Skip to content

fix(flags): align local string matching with the flags service - #735

Open
marandaneto wants to merge 2 commits into
mainfrom
fix/issue-78019-case-folding
Open

fix(flags): align local string matching with the flags service#735
marandaneto wants to merge 2 commits into
mainfrom
fix/issue-78019-case-folding

Conversation

@marandaneto

@marandaneto marandaneto commented Aug 27, 2026

Copy link
Copy Markdown
Member

💡 Motivation and Context

The posthog-server local evaluator could disagree with the released /flags service for exact matching, JSON values, and case-insensitive string operators.

This fixes PostHog/posthog#78019 by matching the current Rust backend contract:

  • exact and is_not apply the backend's boolean-like filter gate before ordinary array membership.
  • Boolean-only and empty filter arrays preserve the backend's aggregate truthiness behavior.
  • Composite values use compact JSON with recursively sorted keys and backend-compatible escaping.
  • Integer values retain their JSON spelling.
  • Floating-point matching falls back to the server because JVM formatting is not identical to serde_json for every finite double.
  • Exact comparisons use full Unicode lowercase, including final sigma and dotted İ.
  • Contains, prefix, and suffix comparisons retain ASCII-only lowercase.

The proposed backend cleanup in PostHog/posthog#90694 is a separate draft. This PR intentionally follows the released backend until that proposal is accepted.

The patch changes only posthog-server and includes a patch changeset.

💚 How did you test it?

Red-green regression evidence:

  • Boolean coercion initially failed for false versus "banana"; the focused evaluator suite now passes.
  • Composite stringification initially failed for "[1,2]" versus [1, 2]; the focused evaluator suite now passes.
  • Review follow-ups reproduced null-member omission, broad long-s boolean matching, and nested non-finite failures before their fixes.

Validation:

  • ./gradlew :posthog-server:test --tests 'com.posthog.server.internal.FlagEvaluatorTest' --no-daemon
  • make checkFormat
  • ./gradlew :posthog-server:animalsnifferMain :posthog-server:animalsnifferTest --no-daemon
  • $HOME/.pi/agent/skills/autoreview/scripts/autoreview --mode local

The full :posthog-server:test suite reached 512 passing tests. Five unrelated Mockito inline-agent tests fail on the local JDK. Required CI remains the authoritative full-suite check.

Autoreview findings about operand direction and whole-array matching were rejected after verification: propertyValue is the filter operand, and the focused 100-test evaluator class passes the cited vectors.

📝 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

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Pi implemented and reviewed the change under human direction using the address-pr-comments, check-pr, autoreview, and karpathy-guidelines skills. The released Rust matcher was the source of truth; the separate backend draft was not adopted.

@marandaneto marandaneto self-assigned this Aug 27, 2026
@marandaneto
marandaneto requested a review from a team August 27, 2026 05:47
@marandaneto
marandaneto marked this pull request as ready for review August 27, 2026 05:51
@marandaneto
marandaneto requested a review from a team as a code owner August 27, 2026 05:51
@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "fix(flags): align local string matching ..." | Re-trigger Greptile

Comment thread posthog-server/src/main/java/com/posthog/server/internal/FlagEvaluator.kt Outdated
@arnohillen

Copy link
Copy Markdown
Contributor

computeExactMatch (posthog-server/src/main/java/com/posthog/server/internal/FlagEvaluator.kt:238) still skips the service's boolean-coercion gate (is_truthy_or_falsy_property_value, rust/feature-flags/src/properties/property_matching.rs:212-220), so exact with filter ["false"] and property "pro" returns false locally and true on /flags (same for filter false vs "banana" and filter [] vs true), while filter ["true","false"] vs "true" returns true locally and false on /flags; pre-existing (identical results on main) and posthog-python's compute_exact_match has the same gap, so follow-up rather than a blocker here.

@marandaneto

Copy link
Copy Markdown
Member Author

Addressed the released-backend parity findings in 41fa02a. A focused red test reproduced false versus "banana" returning false locally before the fix; the evaluator now applies the backend boolean-array gate first, including empty-array truthiness, and the same suite passes. Composite values now use compact recursively sorted JSON, while floating-point values return inconclusive and fall back to /flags because JVM formatting cannot reproduce every serde_json spelling. Strong final-sigma and dotted-I vectors pass without changing Kotlin lowercase. PostHog/posthog#90694 remains the separate proposed backend cleanup.

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.

Case folding and numeric stringification are inconsistent between SDK local evaluation and the flags service

3 participants