An agent plugin caches task context before a system-message transform in a process that hosts multiple root sessions and child sessions. How should the cache be keyed so context cannot leak across sessions, and how should retention be bounded so memory stays finite under concurrent sessions?
Resolution (reasoning only; no executed tests; no repository inspection).
Keying and isolation: never store task context in a process-global singleton or module-level currentContext. Key each entry by the concrete sessionId active at write and at inject. Prefer the composite key sessionId plus authGeneration when credentials can rotate while a root session stays alive. Carry only sessionId in request scope such as AsyncLocalStorage; resolve authGeneration from the live authorization handle at write, read, and inject. Look up by the full key only. Missing or generation mismatch injects empty or default. Never fall back to parent, sibling, last-writer, or a prior generation.
Children: default-isolate. If inheritance is required, copy-on-create a snapshot into the child key; never share a mutable object with the parent. Maintain a parent-to-child or auth-lineage index so dispose and revoke sweep every tied key.
Inject and write races: after a successful fetch and immediately before mutating prompt state, re-validate entry generation against live. Sample generation once at write start; commit only if sampled still equals live inside the revoke critical section or equivalent compare-and-set; on mismatch abort and delete any provisional entry. Never re-resolve live into the key after a bump.
Memory bounds: cap entry count, bytes per entry, and total bytes; prefer delete-on-session-dispose and delete-on-auth-bump; use LRU plus TTL only for orphans; store slim summaries. Do not recycle a sessionId while an orphaned composite entry may remain, or use a process-wide epoch so restarted counters cannot collide.
Treat injected context as prompt data only, never as a network credential. Outbound calls must present a capability bound to the current generation and fail closed on mismatch.
Aligned with existing public skill guidance on session- and auth-bound task context caches. Support is reasoned design analysis, not executed tests.
Changed requirement (reasoning only; no executed tests; no repository inspection): authorization can be revoked or replaced while the plugin process and the same root session stay alive.
Cache binding
- Extend every entry from sessionId alone to the composite key sessionId plus authGeneration.
- Keep authGeneration as a monotonic opaque counter on the live authorization handle for that auth lineage, not only inside cached payloads.
- Carry only sessionId in request scope such as AsyncLocalStorage. Resolve authGeneration from the live handle at write, read, and inject time. Never from a module-level current pointer and never from an ALS-cached generation alone.
- Look up by the full composite key. Missing or generation mismatch injects empty or default. Never fall back to a prior generation, parent, sibling, or last-writer.
Write and inject races
- Sample generation once at write start. Key and tag only with that sampled generation. On commit, inside the revoke critical section or equivalent compare-and-set, require sampled equals live; only then insert or replace. On mismatch, abort and delete any provisional entry under the sampled key. Never re-resolve live into the composite key after a bump.
- After a successful fetch and immediately before mutating prompt state, re-validate that entry.authGeneration equals live.authGeneration. On mismatch, abort to empty or default.
Invalidate on replace
- Compare-and-set live.authGeneration from expected to expected plus one, or hold one critical section for the whole bump, lineage delete or tombstone including indexed children, and credential publish. On CAS failure, retry or abort without publishing.
- Default-isolate children; if inheritance is required, copy-on-create into the child key. Children must read the live parent auth handle for generation checks. Maintain a parent-to-child or auth-lineage index so revoke sweeps every tied key. Treat child entry install and lineage registration as one atomic unit.
Prevent stale context from authorizing network activity
- Treat injected context as prompt data only. Never as a network credential. Do not cache bearer tokens in task context.
- Every outbound network or tool call must present a capability bound to the current generation; mismatch fails closed.
- Cancel work that will take another hop. Do not assume already-gated single-shot I/O is recalled.
- Re-check live generation before applying response side effects because bytes already on the wire cannot be recalled.
Memory: prefer delete-on-bump; keep generation state O of 1 per live session; avoid recycling sessionId while an orphaned composite entry may remain, or use a process-wide epoch so restarted counters cannot collide.
Limits: does not scrub prompt text already injected into an in-flight model turn before a bump; completed single-shot I/O under an old generation is not undone.
Aligned with existing public skill guidance on session- and auth-bound task context caches. Support is reasoned design analysis, not executed tests.