fix(flags): honor versioned local property matching - #922
Draft
marandaneto wants to merge 5 commits into
Draft
Conversation
Contributor
posthog-python Compliance ReportDate: 2026-09-05 17:47:21 UTC ✅ All Tests Passed!111/111 tests passed Capture_V1 Tests✅ 94/94 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
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.
💡 Motivation and Context
Local feature flag evaluation needs to honor the
property_matching_versionsupplied with flag definitions. Otherwise Python can return a different result from the service when a project uses version 2 matching.This follows the backend behavior and shared SDK contract.
is_notcomplementsexact.Compatibility
The optional definition-cache field and matcher arguments are additive and included in the public API snapshot.
Clientsupports async definition providers here. The separateAsyncClientremains remote-only. The existing Sampo changeset is a patch forpypi/posthog.Redis keys, TTLs, public cache signatures, and standalone invalidation/clear behavior are unchanged. The new entry metadata is additive and readable by older SDKs. Older or unverifiable entries become cache misses for upgraded Client-managed caches. Older SDK readers do not gain these protections.
Before definitions load, remote results can still serve outage fallback within the same Client. Their private identity is unique to that Client and renewed after fork, so new Clients and workers cannot reuse unverifiable remote-only entries. Authentication or billing resets disable Redis result caching until valid definitions load again. Remote requests use their request-start generation only as a local invalidation boundary, not as proof of the server's definition snapshot.
Redis result writes remain synchronous. This change does not add Redis timeouts or make single-result cache writes nonblocking. Old entries can remain until their existing TTL expires, but upgraded readers only accept matching provenance.
Optional harness coverage is separate. This PR does not opt an SDK adapter into that coverage.
💚 How did you test it?
Using the existing cached virtualenv with
PYTHONDONTWRITEBYTECODE=1andPYTHONPATH=.:ef127fd. Permanent regression tests failed 24 cases on that head and pass with the fix. They cover restart, different worker snapshots, synchronous/asynchronous providers, cohort/group-mapping-only changes, paused writes, old entries without metadata, and delayed remote responses across hydration or reset.806f735. Three regression cases failed before replacing shared remote-only provenance with per-Client identities. Same-Client fallback, matching-definition reuse, and fork controls pass.3dbe088passed isolated committed-branch autoreview againstorigin/mainwith no actionable findings.Targeted mutation CI repair
The targeted job stopped before mutation testing because its CRAP gate selects only
test_utils.pyandtest_size_limited_dict.py. Cache publication tests in other files did not cover the new snapshot paths in that selection. The CRAP calculator also counts non-executable lines, and the Redis read method's complexity of 10 could not satisfy the strict below-10 limit.if/else. Redis writes select the fingerprint once. Publication fences, write locks, Redis I/O ordering, and public signatures are unchanged.utils.py. The maximum CRAP score is 8.66, below the unchanged limit of 10. A fresh actual mutation run killed all 535 mutants, with emptymutmut resultsand no survivors, timeouts, or untested mutants.a5a6dfbpassed isolated committed-branch autoreview againstorigin/mainwith no actionable findings. All GitHub checks fora5a6dfb8e96c4b5cb8ad4e857ab2a18da3e6209ecompleted successfully, with no failed, pending, or skipped checks. The CI run includes Python 3.10 through 3.14 tests. Its targeted mutation job executed mutation testing rather than skipping on a cache hit and killed all 535 mutants. Both capture protocols also passed SDK compliance.Full repository tests and generated mirror packaging were not run locally for this repair. Redis regressions use the repository's deterministic FakeRedis, not a live Redis service.
📝 Checklist
If releasing new changes
sampo addto generate a changeset fileThe existing
.sampo/changesets/versioned-property-matching.mdpatch changeset was updated.sampo addwas not rerun and no duplicate changeset was added.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Pi agents implemented and tested this user-directed SDK contract update using repository inspection, Python/pytest, Ruff, Git, GitHub CLI, and the isolated autoreview helper. Human review is required before merging. No public agent session link is available.
Fresh review found that a process-local generation could allow invalidated Redis entries to revive after restart. The repair adds private snapshot provenance without putting Redis I/O under the publication lock. The user-directed review workflow approved the additive metadata and stricter handling of unverifiable remote-only entries. Legacy matching defaults, public cache APIs, and Redis key formats are preserved.