Skip to content

fix: include group context in $feature_flag_called dedupe key#150

Merged
gustavohstrassburger merged 3 commits into
mainfrom
posthog-code/fix-flag-called-dedupe-groups
May 27, 2026
Merged

fix: include group context in $feature_flag_called dedupe key#150
gustavohstrassburger merged 3 commits into
mainfrom
posthog-code/fix-flag-called-dedupe-groups

Conversation

@gustavohstrassburger
Copy link
Copy Markdown
Contributor

@gustavohstrassburger gustavohstrassburger commented May 25, 2026

💡 Motivation and Context

In Client::captureFlagCalledIfNeeded (lib/Client.php), the per-distinct_id dedupe element only included the distinct ID under the flag key. For group-scoped flags this meant that when the same user was evaluated under a different group, no new $feature_flag_called event was fired — causing per-group exposure undercount for experiments scoped to a group key.

Mirrors the posthog-node fix in PostHog/posthog-js#3658 (which closes PostHog/posthog-js#3651). Both SDKs share the same dedupe shape, so backend evaluation needs the same change.

💚 How did you test it?

Added three PHPUnit tests in test/FeatureFlagEvaluationsTest.php:

  • testFeatureFlagCalledFiresPerGroupContext — same user, same flag, two different group contexts → two events fired with the expected $groups payloads.
  • testFeatureFlagCalledDedupesAcrossRepeatedCallsUnderSameGroup — repeated access under the same group → one event.
  • testFeatureFlagCalledDedupesAcrossGroupKeyOrder — same groups passed with different array insertion order → still one event (canonicalized via ksort + json_encode).

vendor/bin/phpunit is green (311 tests pass).

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

Created with PostHog Code

In `Client::captureFlagCalledIfNeeded`, the per-`distinct_id` dedupe element only included the distinct ID under the flag key. For group-scoped flags this meant that when the same user was evaluated under a different group, no new `$feature_flag_called` event was fired — causing per-group exposure undercount for experiments scoped to a group key.

Append a canonical JSON of the sorted `groups` map to the dedup element (`$distinctId . canonicalGroupsRepr($groups)`) so the same `(distinct_id, flag)` fires once per distinct group context. Repeated calls under the same group context still dedupe; calls that pass the same array with keys inserted in a different order also dedupe (the array is canonicalized via `ksort` before being JSON-encoded).

Mirrors the posthog-node fix in PostHog/posthog-js#3658 (which closes PostHog/posthog-js#3651). Both SDKs share the same dedupe shape, so backend evaluation needs the same change.

Generated-By: PostHog Code
Task-Id: d94308d9-7655-4bac-8f15-c61478b5fca1
Generated-By: PostHog Code
Task-Id: d94308d9-7655-4bac-8f15-c61478b5fca1
@gustavohstrassburger gustavohstrassburger marked this pull request as ready for review May 25, 2026 21:03
@gustavohstrassburger gustavohstrassburger requested a review from a team as a code owner May 25, 2026 21:03
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 25, 2026

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
lib/Client.php:984-985
`json_encode` returns `false` on encoding failure (e.g., non-UTF-8 bytes in a group value). PHP silently casts `false` to `''`, so every failing encoding produces the suffix `'_'` — all such groups collapse into the same dedup bucket and subsequent `$feature_flag_called` events are silently dropped. Adding a `JSON_THROW_ON_ERROR` flag makes the failure explicit.

```suggestion
        ksort($groups);
        return '_' . json_encode($groups, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
```

### Issue 2 of 2
test/FeatureFlagEvaluationsTest.php:609-655
**Prefer parameterised tests for the two dedup-count cases**

`testFeatureFlagCalledDedupesAcrossRepeatedCallsUnderSameGroup` and `testFeatureFlagCalledDedupesAcrossGroupKeyOrder` both set up a different call pattern, flush, count matching events, and assert exactly 1. Per the team's preference, these share enough structure to be combined under a single `@dataProvider` — each data set would supply the group arrays to pass on each call and the expected event count, keeping the assertion logic in one place.

Reviews (1): Last reviewed commit: "chore: add changeset" | Re-trigger Greptile

Comment thread lib/Client.php Outdated
Comment thread test/FeatureFlagEvaluationsTest.php Outdated
@gustavohstrassburger gustavohstrassburger merged commit 83afee8 into main May 27, 2026
14 checks passed
@gustavohstrassburger gustavohstrassburger deleted the posthog-code/fix-flag-called-dedupe-groups branch May 27, 2026 18:44
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.

$feature_flag_called dedupe does not include group context for group-scoped flags

2 participants