feat: add evaluateFlags() API for single-call flag evaluation#131
Open
feat: add evaluateFlags() API for single-call flag evaluation#131
Conversation
Phase 1 of the Server SDK Feature Flag Evaluations RFC. Mirrors the Node (posthog-js#3476) and Python (posthog-python#539) implementations. * `Client::evaluateFlags()` returns a `FeatureFlagEvaluations` snapshot. Reads on the snapshot do not trigger additional `/flags` requests; access via `isEnabled` / `getFlag` fires a deduped `$feature_flag_called` event the first time each key is touched. `getFlagPayload` is silent. * `capture()` accepts a `flags` snapshot to attach `$feature/<key>` and `$active_feature_flags` properties without a fresh `/flags` round trip. * The single-flag dedup is extracted to `Client::captureFlagCalledIfNeeded()`, shared by the legacy path and the snapshot. * `flag_keys_to_evaluate` and `geoip_disable` are forwarded on the `/flags` request body when callers pass `flagKeys` or `disableGeoip`. * New `feature_flags_log_warnings` option silences filter warnings emitted from `only()` / `onlyAccessed()`. Also fixes a pre-existing bug in `SizeLimitedHash::contains/add` that caused the per-distinct_id `$feature_flag_called` dedup to never match after the first event. The new snapshot path requires real dedup, and existing tests only ever made a single call so the bug was invisible until now. Generated-By: PostHog Code Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d
4 tasks
The file pairs `require_once 'test/error_log_mock.php'` with class declarations, matching the pattern in FeatureFlagLocalEvaluationTest. The existing tests do the same thing; suppressing the rule per-file is consistent with that precedent. Generated-By: PostHog Code Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
evaluateFlags(), a single-call flag evaluation API that returns aFeatureFlagEvaluationssnapshot for one distinct id:/flagsrequest per call; reads on the snapshot make zero further requests.isEnabled($key)/getFlag($key)fire a deduped$feature_flag_calledevent with full metadata (id, version, reason, request_id) on first access.getFlagPayload($key)is silent.only([...])/onlyAccessed()return filtered clones for scoping which flags attach to a captured event.capture(['flags' => $snapshot, …])attaches$feature/<key>and$active_feature_flagswithout a fresh/flagsround trip.getFeatureFlag/getFeatureFlagResult/getAllFlags/send_feature_flagspaths keep working.RFC · reference SDK PRs: posthog-python#539, posthog-js#3476.
Design decisions
FeatureFlagEvaluationsHostinterface (captureFlagCalledIfNeeded,logWarning) instead of a fullClient, so unit tests can use a fake without spinning up the SDK.recordAccessrather than at every call site, soisEnabled/getFlagstill return sane values without leaking events with empty actors.$feature_flag_request_id(it's per-/flags-response) but emitlocally_evaluated=trueand reason"Evaluated locally"to match the existing single-flag local path.flags=oncapture()takes precedence oversend_feature_flags, letting callers adopt the new path without ripping the old one out.SizeLimitedHash::contains/addwere comparing values to keys and pushing onto the outer map, so the per-distinct_id$feature_flag_calleddedup never matched after the first event. The new snapshot path requires real dedup, so it's fixed here.Phase 2 follow-ups (deliberately out of scope)
getFeatureFlag,isFeatureEnabled,getFeatureFlagResult,getAllFlags, and thesend_feature_flagscapture option.flag_definitions_loaded_atthrough the snapshot — posthog-php doesn't track that timestamp on the local poller today.Created with PostHog Code