Caching, post-enforcement.
Two-layer canonical model: foundational cache (raw KV with leases) and entity read cache (typed result projections). Post-enforcement ONLY — every cached read has already passed access evaluation, masking, decryption, and consistency gating. Anti-pattern #60 is absolute: no pre-enforcement entity cache, ever. Protected fields ride AEAD-wrapped envelopes with AAD bound to context.
Foundational + entity read. One canonical bus.
Foundational cache
Raw KV with capability declarations. Two providers shipped: Redis (production, reuses canonical RedisConnectionHardening) and InMemory (opt-in, dev / test only — bootstrap NEVER falls back to InMemory implicitly).
Entity read cache
Typed result projections. Internal to EntityCore. Consumed by ReadCoordinator (hit/store) and WriteCoordinator (invalidate). Every cached read has already passed access evaluation.
AEAD-wrapped protected payloads
Opted-in protected entities ride a CachedPayloadEnvelope with AAD bound to tenant ‖ project ‖ entity ‖ keyFormat ‖ keyVersion. No plaintext fallback — missing key ring → store skipped + invariant metric.
EntityReadCacheGate
Centralized gate. Refuses transaction-scoped reads, non-ReadCommitted consistency, session-scoped reads, internal child reads, protected entities without opt-in. One canonical bypass authority.
4-tier generation composition
platgen + ggen + pgen + egen. O(1) namespace invalidation. Survives dormant providers via durable per-project sequences. The cache key encodes truth-affecting inputs only.
Real singleflight fill
TryAcquireFillLeaseAsync coordinates. Losers poll on capped exponential backoff and consume the winner's value. Lease-less providers degrade honestly to per-caller fill — never a dishonest contract.
Project-scoped bindings
CacheProviderBinding per project. Ancestry inheritance closer-ancestor-wins. Branchable, sandbox-able, scope-chain inherited like every other plane.
Cross-instance coherence
ICacheInvalidationBus. 21 distributed scopes. 13 caches subscribe — runtime compilers, surface compilers, schema cache, webhook endpoint cache, quota enforcement, plus the entity read cache itself.
Genesis-time root seeder
RootCacheBindingSeeder seeds the root project's Redis binding at deployment genesis. Operator opts out via Vadyl:Bootstrap:SeedRootCacheBinding=false. No host-global default cache.
Foundational + entity read
Anti-pattern #60 absolute
AAD-bound to context
Lease-coordinated, not best-effort
Caching that cannot leak.
Post-enforcement only. AEAD-wrapped where it matters. Real singleflight. Project-scoped with ancestry inheritance. Coherent across instances through the canonical bus.