deriveMessages() no longer re-derives and re-clones the whole surface per call: each node is projected exactly once, when first seen (O(new nodes) per access), through the now-public deriveEventMessage — the per-node pure function external reconstructors and the dev invariant fold over a log prefix, so no two paths can disagree about a request's messages. A surface rewrite (replace, invalidate) rebuilds, signalled by SurfaceManager.replaceGeneration — monotonic, bumped by every folded replace and by invalidate(), never reset. Callers get a fresh array snapshot per call over SHARED deep-frozen messages: isolation of the append-only log moves from per-call cloning to unrepresentability (mutation throws), which the two isolation tests now pin directly.
6.8 KiB
6.8 KiB
Event Producer And Consumer Matrix
This matrix shows which packages dispatch each harness-owned event and which packages listen to it. It is intentionally a table rather than one large graph: events are many-to-many, and dense relation data is easier to review in rows. Dynamic dispatch overrides cover sites that deliberately bypass ctx.emit, such as subagent lifecycle containment.
Maintenance mode: hybrid generated: Cordis event declarations and most producer/listener edges are AST-scanned; dynamic dispatch sites are classified in scripts/gen-doc-graphs.ts.