Skip to content
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

feat(flags): Add feature flag version info, evaluation reason, and id to $feature_flag_called event #427

Merged
merged 18 commits into from
Mar 28, 2025

Conversation

haacked
Copy link
Contributor

@haacked haacked commented Mar 21, 2025

Updates posthog-node to take advantage of /decide?v=4 changes. See PostHog/posthog#29751 for more info.

The end result is $feature_flag_called events will have additional properties:

Property Name Descirption
$feature_flag_version The version of the feature flag. This is visible in the diffs of the feature flag activity log.
$feature_flag_reason The reason the feature flag matched or didn't match.
$feature_flag_id The database id of the feature flag (Just in case a flag was deleted and then recreated with the same key, we can determine the difference.

Problem

Changes

Release info Sub-libraries affected

Bump level

  • Major
  • Minor
  • Patch

Libraries affected

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

Changelog notes

  • Added support for X

@haacked haacked requested a review from marandaneto as a code owner March 21, 2025 18:12
@haacked haacked requested a review from a team March 21, 2025 18:12
Copy link

github-actions bot commented Mar 21, 2025

Size Change: +6.31 kB (+3.92%)

Total Size: 167 kB

Filename Size Change
posthog-node/lib/index.cjs.js 34.7 kB +766 B (+2.26%)
posthog-node/lib/index.esm.js 34.4 kB +772 B (+2.29%)
posthog-react-native/lib/posthog-core/src/index.js 12.6 kB +622 B (+5.21%) 🔍
posthog-react-native/lib/posthog-core/src/types.js 492 B +18 B (+3.8%)
posthog-web/lib/index.cjs.js 21.2 kB +1.31 kB (+6.57%) 🔍
posthog-web/lib/index.esm.js 21.2 kB +1.31 kB (+6.6%) 🔍
posthog-react-native/lib/posthog-core/src/featureFlagUtils.js 1.51 kB +1.51 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size
posthog-react-native/lib/posthog-core/src/eventemitter.js 1.08 kB
posthog-react-native/lib/posthog-core/src/lz-string.js 1.42 kB
posthog-react-native/lib/posthog-core/src/surveys-types.js 702 B
posthog-react-native/lib/posthog-core/src/utils.js 956 B
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 628 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 4.85 kB
posthog-react-native/lib/posthog-react-native/src/PostHogContext.js 210 B
posthog-react-native/lib/posthog-react-native/src/PostHogProvider.js 1.74 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 630 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 742 B
posthog-react-native/lib/posthog-react-native/src/surveys/components/QuestionHeader.js 547 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.5 kB
posthog-react-native/lib/posthog-react-native/src/surveys/components/Surveys.js 1.82 kB
posthog-react-native/lib/posthog-react-native/src/surveys/getActiveMatchingSurveys.js 907 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.35 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 124 B

compressed-size-action

Comment on lines +14 to +15
silent: true,
verbose: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I turned these off because there's a lot of console output when running tests which adds a lot of noise to the test output and makes it hard to find what really went wrong.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, these can be configured at test time through CLI arguments anyway.

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

Here's my review of the pull request:

This PR adds support for version 4 of the /decide endpoint, enhancing feature flag tracking with version info, evaluation reasons, and flag IDs in the $feature_flag_called event.

Key changes:

  • Added new FeatureFlagDetail, FeatureFlagMetadata, and EvaluationReason types in posthog-core/src/types.ts to support additional flag metadata
  • Introduced featureFlagUtils.ts with utility functions for processing feature flags and converting between v3/v4 formats
  • Updated /decide endpoint calls to use v4 by default while maintaining backward compatibility
  • Enhanced $feature_flag_called events with new properties: $feature_flag_version, $feature_flag_reason, and $feature_flag_id
  • Fixed duplicate code in getFeatureFlagPayload where default values were being set twice

The implementation looks solid with good test coverage, though I recommend:

  • Adding tests to verify the new event properties in posthog-web.spec.ts
  • Filling out the PR template's bump level and affected libraries checkboxes for version management

11 file(s) reviewed, 6 comment(s)
Edit PR Review Bot Settings | Greptile

@marandaneto
Copy link
Member

this will affect react native as well so make sure to bump versions/chagelog, etc

@marandaneto marandaneto requested a review from a team March 24, 2025 08:34
@haacked
Copy link
Contributor Author

haacked commented Mar 24, 2025

this will affect react native as well so make sure to bump versions/chagelog, etc

Thanks for the heads up! I moved the PR back to draft because I need to verify the changes with RN.

@haacked haacked force-pushed the haacked/decide-v4-support branch from 99647da to c53e6f1 Compare March 27, 2025 17:12
haacked added 6 commits March 27, 2025 10:19
If the bootstrap.featureFlagPayloads has a key
that's not in bootstrap.featureFlags, we assume
the caller wanted that to be a true flag.
Handle v4 Response from decide
This changes how we load and save flags from persistence to support the new v4 format. However, we have to be careful to honor any flags already in persistence in the legacy format.
Use getFeatureFlagDetails to reimplement it.
haacked added a commit that referenced this pull request Mar 27, 2025
@haacked haacked force-pushed the haacked/decide-v4-support branch from c53e6f1 to fc5f1d4 Compare March 27, 2025 22:28
haacked added a commit that referenced this pull request Mar 28, 2025
@haacked haacked force-pushed the haacked/decide-v4-support branch from fc5f1d4 to fe9d19c Compare March 28, 2025 01:12
The $feature_flag_called event now has additional information such as `feature_flag_id`, `feature_flag_version`, `feature_flag_reason`, and `feature_flag_requestId`

Fixes #427
@haacked haacked marked this pull request as ready for review March 28, 2025 01:18
@haacked haacked requested a review from marandaneto March 28, 2025 01:18
@haacked
Copy link
Contributor Author

haacked commented Mar 28, 2025

I tested posthog-node. I don't have React Native set up yet. I'm going to try and get that set up for testing. However, if anyone already is in a position to test it, that'd be great. All the unit tests pass so I'm pretty confident with the change. I went through great pain to make it backwards compatible.

@haacked haacked added the bump minor Bump minor version when this PR gets merged label Mar 28, 2025
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

This PR enhances feature flag evaluation by upgrading to the /decide?v=4 endpoint and inserting additional metadata into the $feature_flag_called event.

• Introduced new types and utility functions (posthog-core/src/types.ts, posthog-core/src/featureFlagUtils.ts) to support flag versioning, evaluation reason, and ID.
• Updated event processing in posthog-core/src/index.ts and posthog-node/src/posthog-node.ts to include the new properties.
• Modified tests (posthog-node/test/feature-flags.decide.spec.ts, posthog-core/test/posthog.featureflags.spec.ts) to validate decide v4 responses.
• Improved developer experience with jest.config.js and README.md updates.

21 file(s) reviewed, no comment(s)
Edit PR Review Bot Settings | Greptile

@haacked haacked force-pushed the haacked/decide-v4-support branch from fe9d19c to b6955c2 Compare March 28, 2025 01:24
@haacked
Copy link
Contributor Author

haacked commented Mar 28, 2025

I'm going to change this to only deploy posthog-node as it's more urgent to get out there. I'll test react-native separately.

Done!

Copy link
Contributor

@dmarticus dmarticus left a comment

Choose a reason for hiding this comment

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

I think I got all the spots where you might want to prefer undefined to false, but worth a double-check.

Comment on lines +14 to +15
silent: true,
verbose: false,
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, these can be configured at test time through CLI arguments anyway.

}

flagDetail = remoteResponse.response
response = getFeatureFlagValue(flagDetail) ?? false
Copy link
Contributor

Choose a reason for hiding this comment

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

this is the change where we should just return a FeatureFlagValue here instead of defaulting to false (i.e. let it be undefined if we couldn't compute it for whatever reason).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I did this because that's the current behavior.

matchValue = await this.getFeatureFlag(key, distinctId, {
...options,
onlyEvaluateLocally: true,
sendFeatureFlagEvents: false, // TODO: Discuss with @dylan.
Copy link
Contributor

Choose a reason for hiding this comment

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

per discussion, we should leave this false. cc @marandaneto does that make sense to you, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I think we should leave sendFeatureFlagEvents false here is this path only applies to local evaluation. It'd be weird for it send feature flag events in this case, but not in the /decide case. If we want both cases to send feature flag events, we can discuss separately and do that as a follow-up.

// If we haven't loaded flags yet, or errored out, we respond with undefined
return {
response: undefined,
requestId: undefined,
}
}

let response = featureFlags[key]
// `/decide` v3 returns all flags
let response = getFeatureFlagValue(flagDetailResponse.response)
Copy link
Contributor

Choose a reason for hiding this comment

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

make sure this can return undefined if we did error out.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you want me to make that change in this PR or is that something you plan to do after this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, we'll do this as a follow-up.

It's now a TODID.
@haacked haacked merged commit 4561cb9 into main Mar 28, 2025
4 checks passed
@haacked haacked deleted the haacked/decide-v4-support branch March 28, 2025 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bump minor Bump minor version when this PR gets merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants