Repository navigation
docs(serializers): scope cache_clear's pre-upgrade claim, pin the hashed legacy key (LAB-6361) - #452
Conversation
…hed legacy key (LAB-6361) The retention warning said cache_clear() never reaches a pre-upgrade key. That is false on a zero-parameter function, where it takes the single-key path and deletes the twin, and for a twin whose delete failed, which stays tracked and is retried. No test pinned the legacy key for raw keys over 250 characters: _pre_020_key swaps the current key's suffix, which a hashed key does not have. The new sync and async tests seed the literal key cachekit 0.19.0 wrote and fail if get_legacy_cache_key ever derives it some other way. The _resolve_cache_key comments now describe the branch order the code runs. Comment-only change; the module's AST is unchanged.
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 59 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configurationConfiguration used: Repository: cachekit-io/cachekit-py/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
Kody Code Review — 1 suggested fix. 🛠️ Open Agent Prompt |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The re-track after a failed twin delete lives in process memory only, so a restart
or another process's no-argument call does not retry it. Scope the exception to the
`:{integrity_flag}s` twin rather than to every tracked key, which on the default
serializer includes the pre-upgrade key itself, and state the zero-parameter case
as a fact rather than an aside.
The hashed-key tests drop the call counter and recompute: with L1 off, an empty
store already proves the next call misses.
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
On the tenant-scoped Redis backend the key registry is named per function and namespace, not per serializer, so a default-serializer decorator's registered key is drained by an `"auto"` decorator's cache_clear() too: a second way a parameterized function's pre-upgrade twin is reached. And on an async function with a backend cache_clear() raises TypeError, so the zero-parameter guarantee is the sync one; `await fn.ainvalidate_cache()` is the async equivalent.
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
_pin_identity returns the function it is given, but its Any -> Any annotation typed every decorated test function as Any, so a bad call or a misused return went unflagged. A Callable-bound TypeVar passes the signature through.
|
@kody start-review |
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
Three follow-ups to the v0.20.0 legacy-key work. One README sentence is corrected. A test now pins the hashed legacy key to cachekit 0.19.0's exact bytes. Two stale comments are fixed. No runtime line changes.
Changes
docs/serializers/README.md, the retention warning. It saidcache_clear()"reaches only keys this release tracked, never a pre-upgrade one". That is false in two cases. On a function with no parameters,cache_clear()takes the single-key path and deletes the:{ic}stwin. And a twin whoseinvalidate_cache(args)delete failed is re-tracked in that process's memory, so that process's next no-argument call retries it; a restart or another process does not. The sentence is now scoped to the:{integrity_flag}stwin on "a function that takes parameters", matching the "What still needs a backend flush" paragraph above it, and it states both cases. It also names a second way a parameterized function's twin is reached: on the tenant-scoped Redis backend the key registry is named per function and namespace, not per serializer, so a key a v0.20.0 default-serializer decorator registered is drained by an"auto"decorator'scache_clear(). The zero-parameter guarantee is the sync one: on an async function with a backendcache_clear()raisesTypeError, andawait fn.ainvalidate_cache()deletes both keys. I checked the zero-parameter case by hand: seed:1aand:1s, callcache_clear(), and the backend is empty. The retry case is already covered bytest_failed_legacy_delete_is_retried_by_no_args_invalidation.tests/unit/test_key_serializer_suffix.py, new classTestHashedLegacyKeyMatchesV019._pre_020_keyderives the legacy key by swapping the current key's suffix. A raw key over 250 characters is stored as a prefix plus a hash of the whole key, so it has no suffix to swap. As a result, aget_legacy_cache_keyrewritten as a suffix swap passed every existing test. The new sync and async tests use a 300-character namespace andserializer="auto". They fix the function's__module__and__qualname__so the key does not depend on how pytest imports the file. Each test seeds the backend with a hard-coded key that cachekit 0.19.0 wrote, then asserts thatinvalidate_cache(1)/ainvalidate_cache(1)deletes it. The default serializer cannot exercise this: on it the legacy key equals the current key and no twin is computed. Both tests disable L1, because they share one pinned key and the second would otherwise hit the first test's process-wide L1 entry.src/cachekit/decorators/wrapper.py,_resolve_cache_keycomments. "Interop mode takes priority" sat below the generated-key branch, which runs first. The comment now says that decoration rejects interop together withkey=orfast_mode. The finalfast_modereturn is commented as the only mode_generated_key_modeleaves. This is a comment-only change:ast.dump(ast.parse(...))of the file is identical before and after.Re-deriving the 0.19.0 literal
From a directory outside the repo, using the PyPI 0.19.0 wheel:
0.19.0's
generate_keyand its decorator write path agree. At this head,get_legacy_cache_keyreturns the same string, and the current key is…:bcc66513af19ec921928b20ad2f12a40.Mutation run
I rewrote
get_legacy_cache_keyas the suffix swap the test exists to catch, then restored it:Only the two new tests fail. The 30 existing ones pass under the mutation, which is exactly the gap this closes.
Verification
uv run ruff check src/ tests/: all checks passeduv run ruff format --check src/ tests/: 309 files already formatteduv run pytest tests/unit tests/critical -m "not slow": 4049 passed, 25 skippeduv run pytest --markdown-docs README.md docs/: 130 passedCloses LAB-6361