feat(backend): bound L1 backfill by the server's remaining freshness (LAB-557) - #268
feat(backend): bound L1 backfill by the server's remaining freshness (LAB-557)#26827Bslash6 wants to merge 1 commit into
Conversation
…(LAB-557) The read response now carries X-CacheKit-Fresh-For (protocol spec/saas-api.md#remaining-freshness). CachekitIO reads parse it (absent = None/legacy; unparseable/negative = 0, the conservative action) and thread (bytes, is_stale, fresh_for) through the freshness chain; L1 backfill uses min(ttl, fresh_for) so an entry read late in its server-side freshness window is never served fresh from L1 past the server's fresh_until. The freshness read path now gates on backend capability, not just configured SWR — the unbounded backfill predates SWR and applied to every CachekitIO read. Revalidation scheduling stays gated on an actually-configured stale window. Post-lock double-check reads share the same bound and stale-exclusion via _l2_double_check.
|
Warning Review limit reachedNext included review available in 13 minutes. View limit detailsLimit details: You’ve used all 6 included reviews currently available. Your 45 included PR review attempts over the past 7 days set your current allowance at 6 reviews per hour. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Bounds L1 backfill by the server's remaining freshness (LAB-557): CachekitIO reads parse the new
X-CacheKit-Fresh-Forresponse header (protocol#51, emitted by saas#325) and L1 backfill usesmin(ttl, fresh_for)— an entry read late in its server-side freshness window is never served fresh from L1 past the server'sfresh_until. Origin: CodeRabbit outside-diff finding on #233 (LAB-506), deferred there because it wasn't fixable SDK-side alone.What ships
CachekitIOBackend.get_with_freshness→(bytes, is_stale, fresh_for); absent header =None(pre-signal server, legacy behavior); unparseable/negative =0(conservative, mirrors unrecognized-freshness → stale; debug-logged so a garbage-emitting proxy is diagnosable). Threaded through the handler/operation-handler chain; a third-party backend still returning the released 2-tuple degrades tofresh_for=Nonevia a length-tolerant unpack instead of a swallowed unpack error turning every hit into a miss.supports_swr— instancehasattrread Mock/__getattr__proxies as capable), not just configured SWR: the unbounded backfill predates SWR and applied to every CachekitIO read. Revalidation scheduling stays gated on an actually-configured stale window._l1_backfill_from_l2holds both invariants at all three backfill sites in lockstep (stale never recorded; fresh bounded); the post-lock double-checks use a freshness-aware read (_l2_double_check) so an L2-read-error + still-live-old-entry double fault can't sneak an unbounded backfill through a side door.ttl=Nonethe bound clamps to L1's ownDEFAULT_L1_TTL_SECONDS(300s) — a long server remainder must never extend local service toward the 30-day cap (DELETE-as-revocation relies on the ≤300s ageout).Tests: regression per the ticket AC (fresh hit with 0s remaining is not L1-recorded; next read reaches L2), bound/legacy/no-SWR/mixed-reader-stale cases, clamp-never-extend, 2-tuple compat, header-parse vectors.
tests/unit/1960 passed; ruff + basedpyright clean; full-suite failure set identical to main modulo timing-flaky perf benchmarks.Expert-panel review (4 agents, high stakes — crypto/protocol gate): FIX-FIRST → applied: ttl=None clamp (CWE-613 — the bound had become an extension), 2-tuple tolerance, backfill-guard dedup, garbage-header debug log, honest
_l2_double_checkdocstring. Rejected: scheduling revalidation from the double-check (spec-permitted asymmetry on a double-fault rarity — documented instead).Docs:
docs/configuration.mdSWR section documents the bound; protocol matrix row stays 🚧 until this ships in a release (matrix verifies released artifacts). Ticket: LAB-557.