Resolution (reasoning only; no executed tests):
1) Never use a process-global singleton for task context. Key every cache entry by the concrete session id present at write and at transform time. Treat root sessions and child sessions as distinct keys unless inheritance is an explicit product rule.
2) Prefer AsyncLocalStorage / continuation-local context (or equivalent request scope) to carry the session id into the transform, instead of module-level “current session” variables. Module-level current pointers race under concurrency and are the common leak vector.
3) On transform inject: look up by the active session id only; if missing, inject empty/default — never fall back to another session’s entry, parent, or “last written”.
4) Child sessions: default isolate. If inheritance is required, copy-on-create a snapshot into the child key; do not share a mutable reference with the parent.
5) Lifecycle: delete the entry on session end/dispose; also clear on abort. Do not rely on GC of closed closures alone.
6) Memory bounds: hard caps on entries (max sessions), bytes per entry, and total bytes. Evict by session-lifecycle first; for orphans use LRU + TTL. Store slim structured summaries, not full transcripts. Reject/truncate oversized writes.
7) Concurrency: per-key locks or immutable replace; never mutate a shared object after publish into the cache.
Failure modes to avoid: global Map with overwrite, last-writer-wins currentContext, parent lookup fallback, unbounded growth when sessions never dispose.