-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(flags): add evaluatedAt to /flags response and support displaying $feature_flag_evaluated_at in the event property taxonomy
#41824
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
Conversation
evaluatedAt to /flags response and support displaying $feature_flag_evaluated_at` in the event property taxonomyevaluatedAt to /flags response and support displaying $feature_flag_evaluated_at in the event property taxonomy
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
|
Size Change: +190 B (+0.01%) Total Size: 3.43 MB ℹ️ View Unchanged
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
11 files reviewed, 2 comments
| flags: flags_response.flags, | ||
| quota_limited: None, | ||
| request_id, | ||
| evaluated_at: Utc::now().timestamp_millis(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: timestamp captured after evaluation completes, not when it starts - inconsistent with field's purpose
The evaluated_at timestamp is captured AFTER evaluate_flags_with_overrides() completes and after the timing guard finishes. For debugging purposes, the timestamp should represent when the evaluation began, not ended. Consider capturing the timestamp before line 235 (let eval_timer = ...) and passing it through the evaluation methods.
| evaluated_at: Utc::now().timestamp_millis(), | |
| evaluated_at: eval_start_time, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: rust/feature-flags/src/flags/flag_matching.rs
Line: 277:277
Comment:
**logic:** timestamp captured after evaluation completes, not when it starts - inconsistent with field's purpose
The `evaluated_at` timestamp is captured AFTER `evaluate_flags_with_overrides()` completes and after the timing guard finishes. For debugging purposes, the timestamp should represent when the evaluation began, not ended. Consider capturing the timestamp before line 235 (`let eval_timer = ...`) and passing it through the evaluation methods.
```suggestion
evaluated_at: eval_start_time,
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For debugging purposes, the timestamp should represent when the evaluation began, not ended.
That seems arbitrary. "evaluated" implies past tense. So it should reflect when it was done being evaluated.
| flags: evaluated_flags_map, | ||
| quota_limited: None, | ||
| request_id, | ||
| evaluated_at: Utc::now().timestamp_millis(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: inconsistent timestamp capture points across error paths
The timestamp is captured at different points depending on which code path is taken (lines 277, 482, 498, 529). This creates inconsistent semantics - some timestamps represent when evaluation completed, others when errors occurred. All paths should capture the same logical point in time for consistency.
Prompt To Fix With AI
This is a comment left during a code review.
Path: rust/feature-flags/src/flags/flag_matching.rs
Line: 482:482
Comment:
**logic:** inconsistent timestamp capture points across error paths
The timestamp is captured at different points depending on which code path is taken (lines 277, 482, 498, 529). This creates inconsistent semantics - some timestamps represent when evaluation completed, others when errors occurred. All paths should capture the same logical point in time for consistency.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree. I think the evaluated_at should be captured when the FlagsResponse is created, which is what this PR does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds timestamp tracking to feature flag evaluation responses by introducing an evaluated_at field (in milliseconds since Unix epoch) across all flag response types, and updates taxonomy definitions to support the new $feature_flag_evaluated_at event property.
Key changes:
- Added
evaluated_at: i64field toFlagsResponse,LegacyFlagsResponse,DecideV1Response, andDecideV2Response - Updated taxonomy definitions in Python backend, HogQL AI, and frontend JSON to document the new property
- Added comprehensive tests verifying timestamp presence, serialization, and value validity
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
rust/feature-flags/src/api/types.rs |
Added evaluated_at field to all response structs with documentation, updated constructor and conversion methods |
rust/feature-flags/src/flags/flag_matching.rs |
Set timestamp during flag evaluation at response construction points |
rust/feature-flags/src/handler/mod.rs |
Set timestamp when creating early-exit responses for disabled flags |
rust/feature-flags/src/handler/flags.rs |
Set timestamp for disabled/empty flags scenarios |
rust/feature-flags/src/handler/billing.rs |
Set timestamp for quota-limited responses |
rust/feature-flags/src/handler/config_response_builder.rs |
Added timestamp to test helper response construction |
rust/feature-flags/src/api/endpoint.rs |
Set timestamp for minimal flags response |
rust/feature-flags/tests/test_flags.rs |
Added integration test verifying timestamp in v1/v2 responses and basic validation in existing test |
posthog/taxonomy/taxonomy.py |
Added $feature_flag_evaluated_at property definition for backend taxonomy |
posthog/hogql/ai.py |
Added $feature_flag_evaluated_at property definition for HogQL AI |
frontend/src/taxonomy/core-filter-definitions-by-group.json |
Added $feature_flag_evaluated_at property definition for frontend |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| flags: flags_response.flags, | ||
| quota_limited: None, | ||
| request_id, | ||
| evaluated_at: Utc::now().timestamp_millis(), |
Copilot
AI
Nov 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The evaluated_at timestamp is generated at the end of flag evaluation rather than at the beginning. This means the timestamp represents when the response was constructed, not when the evaluation started. For debugging timing issues, it would be more accurate to capture the timestamp at the start of the evaluation process (before any flag processing occurs).
Consider capturing the timestamp once at the beginning of evaluate_all_feature_flags and passing it through to the FlagsResponse construction, rather than generating it multiple times throughout the evaluation pipeline.
haacked
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice.
The only minor nit would be that we call Utc::now().timestamp_millis() every where we create a FlagResponse.
It seems to me the new method should do this automatically so we don't have to do this everywhere and makes it clear we intend this timestamp to be created when we've created the FlagResponse.
We could add a test helper with_evaluated_at() method for creating a FlagResponse with a specific timestamp for unit test if needed.
But this is not a blocker, just a minor nit.
| flags: flags_response.flags, | ||
| quota_limited: None, | ||
| request_id, | ||
| evaluated_at: Utc::now().timestamp_millis(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For debugging purposes, the timestamp should represent when the evaluation began, not ended.
That seems arbitrary. "evaluated" implies past tense. So it should reflect when it was done being evaluated.
| flags: evaluated_flags_map, | ||
| quota_limited: None, | ||
| request_id, | ||
| evaluated_at: Utc::now().timestamp_millis(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree. I think the evaluated_at should be captured when the FlagsResponse is created, which is what this PR does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
evaluated_at properties in $feature_flag_called events
PostHog/posthog-ruby#82
…PostHog/posthog into feat/add-evaluated-at-to-flags-response
Problem
When debugging feature flag issues or investigating unexpected flag behavior, it's important to know exactly when a flag was evaluated. Currently, feature flag responses include a
request_idfor tracing, but lack timestamp information about when the evaluation occurred.This makes it difficult to:
I gotta update all of the SDKs to use this field and add to as a property to the
$feature_flag_calledevent, but those changes need this change first.Changes
Added
evaluated_atfield to all flag response types:FlagsResponse(v2)LegacyFlagsResponse(v1)DecideV1ResponseDecideV2ResponseUpdated taxonomy definitions to include
$feature_flag_evaluated_atproperty in:core-filter-definitions-by-group.json(frontend)taxonomy.py(backend)ai.py(HogQL AI)Set timestamps at evaluation time using
Utc::now().timestamp_millis()across all response creation pathsAdded comprehensive tests to verify the field is present, serialized correctly, and contains valid timestamps
How did you test this code?
Added new integration test
it_includes_evaluated_at_timestamp_in_response()that:evaluatedAtin JSONAdded unit test
test_evaluated_at_field_is_present()to verify serializationChangelog: (features only) Is this feature complete?
Yes