Skip to content

fix(flags): fix the way we optimistically send feature flags with capture methods when we have locally evaluated feature flags for a given instance #563

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

dmarticus
Copy link
Contributor

Problem

Closes PostHog/posthog#34188

Changes

TODO

Release info Sub-libraries affected

Bump level

  • Major
  • Minor
  • Patch

Libraries affected

  • All of them
  • posthog-web
  • posthog-node
  • posthog-ai
  • posthog-react-native
  • posthog-nextjs-config

Changelog notes

  • fix: fix the way we optimistically send feature flags with capture methods when we have locally evaluated feature flags for a given instance

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Enhanced feature flag local evaluation in PostHog Node.js client with improved property analysis and stricter controls.

  • Added getRequiredProperties method in posthog-node/src/extensions/feature-flags/feature-flags.ts to analyze properties needed for local evaluation
  • Implemented strictLocalEvaluation option in posthog-node/src/types.ts for stronger control over local evaluation behavior
  • Enhanced sendFeatureFlags configuration in posthog-node/src/client.ts to improve optimistic flag sending with capture methods
  • Added comprehensive test coverage in posthog-node/test/feature-flags.spec.ts for property requirement analysis and strict local evaluation

4 files reviewed, 6 comments
Edit PR Review Bot Settings | Greptile

Comment on lines +605 to +608
if (cohortId in this.cohorts) {
const cohort = this.cohorts[cohortId]
this.analyzeCohortProperties(cohort, personProperties, groupProperties, groupTypes)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: could throw InconclusiveMatchError if cohort not found for consistency with other error handling

Comment on lines +641 to +643
if (!cohort || !cohort.values) {
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: early return should include explanation in debug mode like other similar cases

Suggested change
if (!cohort || !cohort.values) {
return
}
if (!cohort || !cohort.values) {
this.logMsgIfDebug(() => console.debug(`Skipping cohort analysis - cohort or cohort.values is null`))
return
}

Comment on lines 4783 to 4796
describe('getRequiredProperties', () => {
it('should analyze person property requirements', async () => {
await posthog.reloadFeatureFlags()

const requirements = posthog.getRequiredProperties('person-prop-flag')

expect(requirements).toEqual({
personProperties: ['plan'],
groupProperties: {},
canEvaluateLocally: true,
requiresGroups: false,
groupTypes: [],
})
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: good test coverage for analyzing property requirements, but make sure to add test for handling undefined/null person properties

Suggested change
describe('getRequiredProperties', () => {
it('should analyze person property requirements', async () => {
await posthog.reloadFeatureFlags()
const requirements = posthog.getRequiredProperties('person-prop-flag')
expect(requirements).toEqual({
personProperties: ['plan'],
groupProperties: {},
canEvaluateLocally: true,
requiresGroups: false,
groupTypes: [],
})
})
it('should analyze person property requirements', async () => {
await posthog.reloadFeatureFlags()
const requirements = posthog.getRequiredProperties('person-prop-flag')
expect(requirements).toEqual({
personProperties: ['plan'],
groupProperties: {},
canEvaluateLocally: true,
requiresGroups: false,
groupTypes: [],
})
})
it('should handle undefined/null person properties', async () => {
await posthog.reloadFeatureFlags()
const requirements = posthog.getRequiredProperties('person-prop-flag')
const flag = await posthog.getFeatureFlag('person-prop-flag', 'user123', {
onlyEvaluateLocally: true,
personProperties: { plan: undefined }
})
expect(flag).toBe(false)
})

Comment on lines 4935 to 4946
// Just test that the capture method accepts the new structure without throwing
expect(() => {
posthog.capture({
distinctId: 'user123',
event: 'test_event',
sendFeatureFlags: {
personProperties: { plan: 'premium' },
onlyEvaluateLocally: true,
},
})
}).not.toThrow()
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: expand basic capture test to verify the actual feature flag evaluation results

Copy link

github-actions bot commented Jul 8, 2025

Size Change: +9.04 kB (+2.91%)

Total Size: 320 kB

Filename Size Change
posthog-node/lib/edge/index.cjs 34.2 kB +2.26 kB (+7.09%) 🔍
posthog-node/lib/edge/index.mjs 33.9 kB +2.25 kB (+7.11%) 🔍
posthog-node/lib/node/index.cjs 38.6 kB +2.26 kB (+6.23%) 🔍
posthog-node/lib/node/index.mjs 38.3 kB +2.26 kB (+6.26%) 🔍
ℹ️ View Unchanged
Filename Size
posthog-ai/lib/anthropic/index.cjs 2.81 kB
posthog-ai/lib/anthropic/index.mjs 2.66 kB
posthog-ai/lib/gemini/index.cjs 2.46 kB
posthog-ai/lib/gemini/index.mjs 2.4 kB
posthog-ai/lib/index.cjs 14.1 kB
posthog-ai/lib/index.mjs 13.8 kB
posthog-ai/lib/langchain/index.cjs 7.72 kB
posthog-ai/lib/langchain/index.mjs 7.5 kB
posthog-ai/lib/openai/index.cjs 3.16 kB
posthog-ai/lib/openai/index.mjs 3 kB
posthog-ai/lib/vercel/index.cjs 3.95 kB
posthog-ai/lib/vercel/index.mjs 3.9 kB
posthog-nextjs-config/lib/index.cjs 1.94 kB
posthog-nextjs-config/lib/index.mjs 1.78 kB
posthog-react-native/lib/posthog-core/src/eventemitter.js 1.08 kB
posthog-react-native/lib/posthog-core/src/featureFlagUtils.js 1.49 kB
posthog-react-native/lib/posthog-core/src/gzip.js 625 B
posthog-react-native/lib/posthog-core/src/index.js 14.8 kB
posthog-react-native/lib/posthog-core/src/types.js 1.19 kB
posthog-react-native/lib/posthog-core/src/utils.js 1.09 kB
posthog-react-native/lib/posthog-core/src/vendor/uuidv7.js 2.04 kB
posthog-react-native/lib/posthog-react-native/index.js 477 B
posthog-react-native/lib/posthog-react-native/src/autocapture.js 1.8 kB
posthog-react-native/lib/posthog-react-native/src/frameworks/wix-navigation.js 505 B
posthog-react-native/lib/posthog-react-native/src/hooks/useFeatureFlag.js 437 B
posthog-react-native/lib/posthog-react-native/src/hooks/useFeatureFlags.js 362 B
posthog-react-native/lib/posthog-react-native/src/hooks/useNavigationTracker.js 752 B
posthog-react-native/lib/posthog-react-native/src/hooks/usePostHog.js 249 B
posthog-react-native/lib/posthog-react-native/src/legacy.js 810 B
posthog-react-native/lib/posthog-react-native/src/native-deps.js 1.34 kB
posthog-react-native/lib/posthog-react-native/src/optional/OptionalAsyncStorage.js 183 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoApplication.js 215 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoDevice.js 211 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoFileSystem.js 224 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalExpoLocalization.js 216 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeDeviceInfo.js 220 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeLocalize.js 169 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeNavigation.js 218 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeNavigationWix.js 222 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalReactNativeSafeArea.js 312 B
posthog-react-native/lib/posthog-react-native/src/optional/OptionalSessionReplay.js 231 B
posthog-react-native/lib/posthog-react-native/src/posthog-rn.js 5.06 kB
posthog-react-native/lib/posthog-react-native/src/PostHogContext.js 210 B
posthog-react-native/lib/posthog-react-native/src/PostHogProvider.js 1.73 kB
posthog-react-native/lib/posthog-react-native/src/storage.js 1.09 kB
posthog-react-native/lib/posthog-react-native/src/surveys/components/BottomSection.js 652 B
posthog-react-native/lib/posthog-react-native/src/surveys/components/Cancel.js 527 B
posthog-react-native/lib/posthog-react-native/src/surveys/components/ConfirmationMessage.js 738 B
posthog-react-native/lib/posthog-react-native/src/surveys/components/QuestionHeader.js 541 B
posthog-react-native/lib/posthog-react-native/src/surveys/components/QuestionTypes.js 2.81 kB
posthog-react-native/lib/posthog-react-native/src/surveys/components/SurveyModal.js 1.6 kB
posthog-react-native/lib/posthog-react-native/src/surveys/components/Surveys.js 1.85 kB
posthog-react-native/lib/posthog-react-native/src/surveys/getActiveMatchingSurveys.js 902 B
posthog-react-native/lib/posthog-react-native/src/surveys/icons.js 1.86 kB
posthog-react-native/lib/posthog-react-native/src/surveys/index.js 222 B
posthog-react-native/lib/posthog-react-native/src/surveys/PostHogSurveyProvider.js 1.82 kB
posthog-react-native/lib/posthog-react-native/src/surveys/surveys-utils.js 2.33 kB
posthog-react-native/lib/posthog-react-native/src/surveys/useActivatedSurveys.js 1.41 kB
posthog-react-native/lib/posthog-react-native/src/surveys/useSurveyStorage.js 690 B
posthog-react-native/lib/posthog-react-native/src/types.js 90 B
posthog-react-native/lib/posthog-react-native/src/version.js 123 B
posthog-web/lib/index.cjs 23 kB
posthog-web/lib/index.mjs 23 kB

compressed-size-action

@dmarticus dmarticus marked this pull request as draft July 9, 2025 15:28
@dmarticus
Copy link
Contributor Author

closing; did it here: #565

@dmarticus dmarticus closed this Jul 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug report: Feature flag targeting with "Group key" shows 0% match even when group key exists and matches
1 participant