Scopes cache keys by tenant, invalidates on write or uses versioned keys, applies a stampede lock on miss, and never stores responses that skipped authorization.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Read-heavy API responses may be cached only under tenant-scoped keys after authorization succeeds. Writes either delete matching keys or bump a version token embedded in the key. Concurrent misses take a stampede lock so one fill runs. Unauthorized, cross-tenant, or pre-authorization payloads are never stored.
Scope
- Cache key layout, tenant isolation, TTL, write-through invalidation, versioned keys, stampede lock, negative-cache policy, and authorization ordering for read-heavy backend APIs.
- Shared Redis or equivalent used by multiple service replicas.
- Documenting which writes map to which key families.
Outside this block
- CDN edge caching of public marketing pages.
- Client-side HTTP cache headers for anonymous browsers.
Contract
- Every cache key includes tenant identifier and resource family; a lookup that omits tenant is a programming error and is not executed.
- Authorization for the caller and row runs before cache fill; a deny is not cached as a hit body for another caller.
- On a documented write event, either all matching keys are deleted within the invalidation bound or the version token in those keys is incremented so stale entries miss.
- TTL is an upper bound, not a substitute for write invalidation on user-visible correctness fields.
- Miss storms take a per-key lock; waiters retry once the fill completes or the lock TTL expires.
- Negative caches, if used, are tenant-scoped, short-TTL, and never store another tenant's existence probe.
Implementation guidance
- Build keys from a typed helper: tenant, family, resource id, and optional version; ban string concatenation in handlers.
- Prefer version tokens for hot lists where delete fan-out is expensive; prefer delete for single-object correctness.
Failure handling
- Cache store outage serves origin reads; it does not skip authorization to keep latency.
- Partial invalidation (some replicas still hot) is corrected by version bump or TTL, whichever the matrix specifies for that family.
Verification and operations
- Measure hit ratio by family, invalidation lag, stampede lock wait, and cross-tenant key collision tests (must be zero).
- Alert when a family marked invalidate-on-write exceeds the lag bound after a write.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.
References
- Tenant-scoped keys, write invalidation versus version tokens, and stampede locks are project decisions recorded in this package; they are not a public standard.