Replace the single global session_projcache domain with a per-session
cache file inside the session's own persistence directory, resolved
through sessionPersistence.locate(meta) — the persistence backend owns
the session-directory layout, the cache service keeps every checkpoint
and cold-read responsibility.
- cachedSnapshot(meta) becomes async (one file read per session);
coldSnapshot takes the session header so it can locate the file, with
the stored log header remaining the identity witness.
- Backends without a per-session directory (sqlite) disable the durable
cache: writes no-op and cold reads fall to the full-log rung. An
obsolete global cache is never read — derived data refolds on first
cold read (no migration).
- writeAtomic is exported from dsh-storage-json as the shared atomic
whole-file replace primitive; api-proxy listing and subagent cold
reads await the now-async cachedSnapshot.
- READMEs and a new Agent Note document the per-session medium.