Skip to content

fix(server): honor versioned local property matching - #763

Open
marandaneto wants to merge 2 commits into
mainfrom
fix/versioned-boolean-local-evaluation
Open

fix(server): honor versioned local property matching#763
marandaneto wants to merge 2 commits into
mainfrom
fix/versioned-boolean-local-evaluation

Conversation

@marandaneto

@marandaneto marandaneto commented Sep 5, 2026

Copy link
Copy Markdown
Member

💡 Motivation and Context

Server-side local feature flag evaluation needs to honor the property_matching_version returned with flag definitions. This follows the backend change and the shared SDK contract.

  • Missing metadata, version 1, and unsupported versions keep legacy matching. Exactly version 2 uses explicit scalar equality and equality against members of nonempty filter arrays. Empty filters keep recursive truthiness, and is_not complements exact for known properties.
  • Each local evaluation pass keeps one snapshot of definitions, group mappings, cohorts, and its matching version, including recursive flag dependencies.
  • Definition-cache providers retain the version. Version-only refreshes replace the result cache, so an older in-flight remote response cannot repopulate the new cache. A 304 or failed load preserves the previous definitions.
  • In-flight remote evaluations return their own flags, response errors, request ID, and evaluation timestamp even if definitions refresh during the request. Both missing-definition probes and inconclusive local evaluations keep this metadata without reading it back from the replacement cache.

This changes posthog-server plus the shared local-evaluation DTO and API snapshot in posthog. Android mobile matching is unaffected. The existing three-argument Java constructor and Kotlin constructor defaults remain available. The @PostHogInternal data class gains a fourth component and changes its generated copy signatures, so consumers calling that internal generated API must recompile. The existing changeset requests patch releases for posthog and posthog-server.

Optional harness coverage is separate. This PR does not opt an SDK adapter into it.

💚 How did you test it?

On the final source tree, ran:

./gradlew :posthog-server:test --tests 'com.posthog.server.internal.VersionedPropertyMatchingTest' --console=plain
JAVA_TOOL_OPTIONS=-Dnet.bytebuddy.experimental=true ./gradlew :posthog:test :posthog-server:test :posthog:apiCheck :posthog-server:apiCheck --console=plain
make checkFormat
git diff --check

All 942 core tests and 552 server tests passed, along with both API checks and formatting. Coverage includes exact/is_not rows across missing/1/2/3 versions, person/group/cohort/dependency evaluation, version-only refreshes, disk-cache serialization, async hydration, and latch-controlled stale remote responses. HTTP request counts verify local results do not silently fall back remotely.

Four new regressions failed on the previously reviewed code and passed after the repair. They cover delayed successful responses and HTTP failures for both missing definitions and inconclusive local matches. They also verify that an old response cannot populate the new cache, and that a subsequent response retains its own metadata on a cache hit.

The local Java 21 runtime needs the documented Byte Buddy experimental option for existing Mockito tests. No dependencies were upgraded. No mobile/emulator build was run, and local results are not a claim that CI passed.

The required isolated committed-branch autoreview against origin/main reported no actionable findings at c6da08f6c85691016a791d0302d6f01a0d4e93d6. A fresh pi-review found the delayed-response metadata regression at the previous head. This update fixes that finding, and a new fresh review of the pushed head is pending.

📝 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

The existing .changeset/quiet-booleans-match.md was updated to include the delayed-response repair without generating a duplicate. The internal generated API compatibility caveat is noted above.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Pi agents implemented and repaired the server-only matching behavior under human direction. This publication session used Git, GitHub CLI, Gradle, and the isolated Pi autoreview helper to validate and publish the existing implementation. Session reference: sdk-pr-publication/0ee28abf-0f0d-4ec1-bb6e-2ec23145ea0b (local session, no public transcript).

The chosen cache-instance boundary prevents stale remote writes without holding locks across HTTP requests. Returning the complete response entry preserves the caller's metadata independently of cache replacement. Existing constructor compatibility and the API snapshot were preserved. Human review is required before merging.

@marandaneto marandaneto self-assigned this Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

posthog-android Compliance Report

Date: 2026-09-05 15:22:30 UTC
Duration: 117991ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 290ms
Format Validation.Event Has Uuid 26ms
Format Validation.Event Has Lib Properties 29ms
Format Validation.Distinct Id Is String 19ms
Format Validation.Token Is Present 20ms
Format Validation.Custom Properties Preserved 21ms
Format Validation.Event Has Timestamp 18ms
Retry Behavior.Retries On 503 7023ms
Retry Behavior.Does Not Retry On 400 4020ms
Retry Behavior.Does Not Retry On 401 4020ms
Retry Behavior.Respects Retry After Header 7022ms
Retry Behavior.Implements Backoff 17028ms
Retry Behavior.Retries On 500 7016ms
Retry Behavior.Retries On 502 7016ms
Retry Behavior.Retries On 504 7018ms
Retry Behavior.Max Retries Respected 17032ms
Deduplication.Generates Unique Uuids 31ms
Deduplication.Preserves Uuid On Retry 7010ms
Deduplication.Preserves Uuid And Timestamp On Retry 12027ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7016ms
Deduplication.No Duplicate Events In Batch 27ms
Deduplication.Different Events Have Different Uuids 19ms
Compression.Sends Gzip When Enabled 13ms
Batch Format.Uses Proper Batch Structure 15ms
Batch Format.Flush With No Events Sends Nothing 9ms
Batch Format.Multiple Events Batched Together 27ms
Error Handling.Does Not Retry On 403 4015ms
Error Handling.Does Not Retry On 413 4017ms
Error Handling.Retries On 408 5023ms

Feature_Flags Tests

17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 28ms
Request Payload.Flags Request Uses V2 Query Param 16ms
Request Payload.Flags Request Hits Flags Path Not Decide 15ms
Request Payload.Flags Request Omits Authorization Header 29ms
Request Payload.Token In Flags Body Matches Init 16ms
Request Payload.Groups Round Trip 17ms
Request Payload.Groups Default To Empty Object 17ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 19ms
Request Payload.Disable Geoip Omitted Defaults To False 19ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 16ms
Request Lifecycle.No Flags Request On Init Alone 6ms
Request Lifecycle.No Flags Request On Normal Capture 18ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 31ms
Request Lifecycle.Mock Response Value Is Returned To Caller 19ms
Retry Behavior.Retries Flags On 502 319ms
Retry Behavior.Retries Flags On 504 317ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 16ms

@marandaneto
marandaneto marked this pull request as ready for review September 5, 2026 17:29
@marandaneto
marandaneto requested a review from a team as a code owner September 5, 2026 17:29
@greptile-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "fix(server): retain remote response meta..." | Re-trigger Greptile

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.

1 participant