Storage Layers
Hot Cache
The hot cache is a transient, in-memory key-value store. It owns nothing — every entry is rebuildable. The platform treats every cache call as best-effort: if the cache is down, traffic still flows.
What the cache actually stores
| Entry | Key prefix | Default TTL |
|---|---|---|
| Query embedding | emb:{sha256_digest[:24]} | 1 hour |
| Recall result | query:{hash}:{user_id}:{project_id} | 5 minutes |
| Project metadata | proj:{project_id} | 5 minutes |
| Tenant principal | tenant:{tenant_id} | 5 minutes |
| Generic key/value | caller-supplied | 300 s default, overrideable |
The fast paths it protects
- Repeat queries embed once per hour instead of every call.
- Popular recall results return without touching the index or the durable store.
- Project-scope and tenant-principal lookups stay sub-millisecond on the hot path.
How a miss and a hit differ
On a hit, the cached value is returned in well under 10 ms and no downstream call happens. On a miss, the platform performs the full path (embedding API, index call, datastore read) and writes the result back with the configured TTL — but only if the call succeeded. Failed work is not cached.
What happens when the cache is down
- The cache client logs a single warning at INFO (deliberately not ERROR — alert spam is worse than the outage itself).
- The client disables itself in-process.
- Reads return
None, writes are silently dropped. - A lazy reconnect attempt runs on the next cache call — not on a timer, to avoid thundering herd on a restarting server.
- Throughput drops; correctness does not.
Explicit invalidation rules
- Adding, updating, or deleting a memory invalidates the recall result keys for that user.
- Updating a project invalidates
proj:{project_id}. - Rotating a tenant key invalidates
tenant:{tenant_id}. - Embedding cache entries are not actively purged; old ones expire on TTL.
Configuration knobs
- Connection pool size 100, socket timeout 0.5 s, connection timeout 0.5 s — chosen so a slow cache cannot stall a request loop.
- Cache URL is read from an environment variable; if it is empty, caching is disabled at boot and every call becomes a no-op.
- Custom TTLs are supported per write — pass
ttl_secondsonsetto override the default.
What the cache is not good for
- Anything that needs to survive a process restart on the cache server.
- Anything that must be transactional with the durable store — there is no two-phase commit between them.
- Anything larger than tens of kilobytes — cache entries are sized for hot paths, not bulk payloads.