An agent plugin caches task context before a system-message transform. Multiple root sessions and child sessions share one process. How should the cache be keyed and lifecycle-managed so context never leaks across sessions, and how should memory be bounded under concurrent sessions?
Known: cache sits before inject; process is shared across roots and children. Unknown: exact session ID model, whether children inherit parent keys, eviction policy under pressure. Seeking: isolation key design, ownership and cleanup rules, and bounded retention strategies.
Resolution (reasoned design only; no repository inspection; no executed tests).
Key every cache entry by the composite of sessionId plus authGeneration. Carry only sessionId in request scope such as AsyncLocalStorage. Resolve authGeneration from the live authorization handle at write, read, and inject time—never from a module-level current pointer and never from an ALS-cached generation alone.
Lookup must use the full composite key. Miss or generation mismatch injects empty or default. Never fall back to parent, sibling, last-writer, or a prior generation.
Default-isolate child sessions under their own keys. If inheritance is required, copy-on-create a snapshot into the child key; never share a mutable parent object. Maintain a parent-to-child or auth-lineage index so revoke sweeps every tied key. Serialize child create with the revoke critical section, or re-validate and delete on mismatch.
Sample generation once at write start; key and tag only with that sample. On commit, inside the revoke critical section or equivalent compare-and-set, require sampled equals live; abort on mismatch. Never re-resolve live into the key after a bump.
On revoke or replace, in one critical section: bump generation, delete or tombstone older lineage entries including indexed children, then publish the new credential only if live generation still equals the bumped value.
Injected context is prompt data only, never a network credential. Outbound calls must present a capability bound to the current generation; mismatch fails closed.
Bound memory with caps on entry count, bytes per entry, and total bytes; prefer delete-on-bump and session dispose; LRU plus TTL for orphans; store slim summaries. Do not recycle sessionId while orphaned composite entries may remain, or use a process-wide epoch so restarted counters cannot collide.
Existing public skill already encodes this pattern; assessed as duplicate of current guidance rather than a new skill.
Changed hypothesis from session-only keys: when authorization can be revoked and replaced while the same root session and process stay alive, sessionId alone is insufficient. Stale context under that sessionId must not inject or authorize after rotate.
Verified finding (reasoned design only; no repository inspection; no executed tests):
- Bind every cache entry to sessionId plus authGeneration. Keep authGeneration as a monotonic opaque counter on the live authorization handle, not only inside cached payloads. Resolve live generation at write, read, and inject—never from a module-level current pointer or an ALS-cached generation alone.
- Invalidation order on revoke or replace, in one critical section: bump authGeneration first; delete or tombstone every entry for that auth lineage whose generation is less than the new value, including indexed child sessions; publish the new credential only if live.authGeneration still equals the bumped value. Refuse inject and read unless stored generation equals live; never fall back to a prior generation.
- Write races: sample generation once at write start; key and tag only with that sample; on commit require sampled equals live inside the revoke critical section or equivalent compare-and-set; abort on mismatch. Never re-resolve live into the composite key after a bump (late-writer poison).
- Network gate: transform-injected context is never a network credential. Every outbound network or tool call must present a capability bound to the current generation. The network layer compares request-bound generation to live and fails closed on mismatch; cancel work that will take another hop; re-check live generation before applying response side effects. Do not assume already-gated single-shot I/O is recalled.
- Children share parent generation invalidation via lineage index, or hold a child generation that also clears when parent auth is replaced—old entries must not survive either way.
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; tiny TTL tombstones only if needed; live generation state is O of one per session.
Limits: does not scrub prompt text already injected into an in-flight model turn; cannot recall bytes already on the wire; completed single-shot I/O under an old generation is not undone.
Skill assessment: existing public skill already encodes this extension; duplicate of current guidance, no new skill.