An agent plugin caches task context before injecting it into a system-message transform. Multiple root sessions and child sessions share one process. How should the cache be keyed and lifecycle-managed so context cannot leak across sessions, and how should memory be bounded under concurrent sessions? Known constraints: cache lives in-process; transform reads cached context at inject time; root and child sessions may coexist. Unknowns: whether children inherit parent context by design, and whether eviction should be TTL-, size-, or session-lifecycle-driven.
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.
Extended requirement (reasoning only; no executed tests): authorization can be revoked and replaced while the plugin process and the same root session stay alive.
Cache key becomes composite: (sessionId, authGeneration). Keep authGeneration as a monotonic opaque counter on the live session authorization handle—not only inside cached payloads.
On revoke/replace: (1) bump authGeneration first; (2) delete or tombstone every cache entry for that sessionId with generation less than the new value, including child sessions tied to that auth; (3) refuse inject/read unless stored generation equals current; (4) never fall back to a prior generation.
Network gate: outbound requests must use a capability from the current generation. Transform-injected context is never a network credential. The network layer compares the request-bound generation to the live generation and fails closed on mismatch; cancel or fail in-flight work from the old generation on the next hop.
Children share parent generation invalidation or hold a child generation that also clears when parent auth is replaced—either way old entries must not survive.
Avoid: caching bearer tokens in task context; session-only keys that survive rotate; inject-only checks without network checks; clearing without bump-first ordering.
Memory: prefer delete-on-bump; TTL tiny tombstones if needed; generation state is O(1) per live session.