# Cache Keying ## What cache keying is for Mizan's invalidation surface names *which* entries die. Cache keying names *which entry is which*. A key that does not separate User A's content from User B's turns Edge caching into a **security vulnerability** — it serves one user's content to another. ## Why `Vary` is not the mechanism All major CDNs ignore `Vary` for personalized content, and no standardized replacement exists. The key itself carries identity. ## HMAC cache key (JSON-canonical form) ``` ctx:{context}:HMAC-SHA256(secret, json.dumps({ "c": context, "p": sorted_params, // values normalized to JSON-native strings "r": rev, "u": user_id // omitted for public content }, sort_keys=True, separators=(",", ":"))) ``` `derive_cache_key(secret, context, params, user_id=None, rev=0)` → `"ctx:{context}:{hmac_hex}"`. The `ctx:{context}:` prefix lets broad purge SCAN by prefix. Param values are normalized for cross-language consistency (`True`→`"true"`, `None`→`"null"`) before stringification. The derivation lives in `cores/mizan-python/src/mizan_core/cache/keys.py` and `backends/mizan-ts/src/cache/keys.ts` (`deriveCacheKey`); pinned vectors hold the two outputs byte-identical. ### Key derivation rules - **Public content** — URL path + query params (standard CDN). - **User-scoped content** — HMAC key derivation above. - **`@client(auth=...)`** determines whether content is user-scoped. - **`rev` parameter** on `@client` for deploy-time logic invalidation. Bumped by the developer when function logic changes. ## Identity layer MWT (Mizan Web Token) — see [MWT_SPEC.md](MWT_SPEC.md). JWT with Mizan claims on `X-Mizan-Token` header. ## Cache architecture **Not a compiled binary ABI. Not a pluggable Python protocol.** Each backend adapter (Python, TypeScript, PHP, C#, Go) implements the cache protocol in its own language. **Conformance is verified by a shared test suite**, so the implementations cannot drift apart silently. ### Required operations - `cache_get` - `cache_put` - `cache_purge` (scoped recomputes the key; broad SCANs the `ctx:{context}:*` prefix) ### Storage Two backends behind a `CacheBackend` protocol (`mizan_core/cache/backend.py`): - `MemoryCache` — dict-based, for testing. - `RedisCache` — production; persistence, cross-worker sharing, crash recovery. Broad purge via SCAN, delete via UNLINK. ## Deploy invalidation No full context flush. The `rev` parameter on `@client` is part of the HMAC key. When the developer bumps `rev`, old cache entries become **unreachable orphans**. No purge needed; no thundering herd. ## Invariant All cache-related code implements *identical* HMAC key derivation. Cross-language conformance tests enforce this. Any divergence is a security vulnerability.