Files
mizan/docs/CACHE_KEYING.md
Ryth Azhur e00b3a177e Docs carry the shape of the system, not its status
MIZAN.md's phase-numbered implementation order, PRODUCT_ARCHITECTURE's
"Deferred until Render revenue funds it" and "Shipped in", PSR_VS_EDGE's
current-state section, and the READMEs' passing-test counts were all reporting
where the work stood rather than what the system is. OWED_SURFACE keeps its
subject — surface that is specified but unbuilt — stated as the shape each unit
owes.

The channel sections follow the renamed slots: Params / ClientMessage /
ServerMessage, and Channel as the base class on both backends.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 14:03:29 -04:00

2.7 KiB

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. 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.