@graphrefly/graphrefly 0.47.2 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base/composition/index.cjs +4 -3
- package/dist/base/composition/index.cjs.map +1 -1
- package/dist/base/composition/index.d.cts +14 -5
- package/dist/base/composition/index.d.ts +14 -5
- package/dist/base/composition/index.js +8 -8
- package/dist/base/index.cjs +152 -78
- package/dist/base/index.cjs.map +1 -1
- package/dist/base/index.d.cts +2 -2
- package/dist/base/index.d.ts +2 -2
- package/dist/base/index.js +75 -70
- package/dist/base/io/index.cjs +31 -17
- package/dist/base/io/index.cjs.map +1 -1
- package/dist/base/io/index.d.cts +32 -5
- package/dist/base/io/index.d.ts +32 -5
- package/dist/base/io/index.js +1 -1
- package/dist/base/mutation/index.cjs +21 -0
- package/dist/base/mutation/index.cjs.map +1 -1
- package/dist/base/mutation/index.d.cts +23 -1
- package/dist/base/mutation/index.d.ts +23 -1
- package/dist/base/mutation/index.js +3 -1
- package/dist/base/sources/browser/index.cjs +5 -3
- package/dist/base/sources/browser/index.cjs.map +1 -1
- package/dist/base/sources/browser/index.d.cts +20 -2
- package/dist/base/sources/browser/index.d.ts +20 -2
- package/dist/base/sources/browser/index.js +5 -3
- package/dist/base/sources/browser/index.js.map +1 -1
- package/dist/base/sources/event/index.cjs +28 -0
- package/dist/base/sources/event/index.cjs.map +1 -1
- package/dist/base/sources/event/index.d.cts +67 -3
- package/dist/base/sources/event/index.d.ts +67 -3
- package/dist/base/sources/event/index.js +4 -1
- package/dist/base/sources/index.cjs +75 -37
- package/dist/base/sources/index.cjs.map +1 -1
- package/dist/base/sources/index.d.cts +1 -1
- package/dist/base/sources/index.d.ts +1 -1
- package/dist/base/sources/index.js +5 -2
- package/dist/{chunk-R6ZCSXKX.js → chunk-23MAWVOJ.js} +3 -3
- package/dist/{chunk-MS3WPRJR.js → chunk-3REMCHSS.js} +6 -6
- package/dist/chunk-3REMCHSS.js.map +1 -0
- package/dist/{chunk-CEVNQ74M.js → chunk-3YGXPUHW.js} +2 -2
- package/dist/{chunk-CEVNQ74M.js.map → chunk-3YGXPUHW.js.map} +1 -1
- package/dist/{chunk-6ZLCPUXS.js → chunk-46X2EFQH.js} +15 -4
- package/dist/chunk-46X2EFQH.js.map +1 -0
- package/dist/{chunk-NY2PYHNC.js → chunk-5UY3PNFY.js} +12 -5
- package/dist/chunk-5UY3PNFY.js.map +1 -0
- package/dist/{chunk-FQSQONOU.js → chunk-65OM4XLQ.js} +49 -3
- package/dist/chunk-65OM4XLQ.js.map +1 -0
- package/dist/{chunk-3PSLNJDU.js → chunk-6DQYBIHW.js} +314 -49
- package/dist/chunk-6DQYBIHW.js.map +1 -0
- package/dist/{chunk-LDCSZ72P.js → chunk-6YBER5UP.js} +3 -3
- package/dist/{chunk-LDCSZ72P.js.map → chunk-6YBER5UP.js.map} +1 -1
- package/dist/{chunk-3O3NKZJW.js → chunk-7T7WLEPM.js} +24 -3
- package/dist/chunk-7T7WLEPM.js.map +1 -0
- package/dist/{chunk-PKPO3JTZ.js → chunk-AQAKDE7F.js} +29 -11
- package/dist/chunk-AQAKDE7F.js.map +1 -0
- package/dist/{chunk-6MRSX3YK.js → chunk-B5Y5GPD5.js} +2 -2
- package/dist/{chunk-BXGZFGZ4.js → chunk-C5QD5DQX.js} +22 -1
- package/dist/chunk-C5QD5DQX.js.map +1 -0
- package/dist/{chunk-4XCHZRUJ.js → chunk-D5YGR4TP.js} +58 -7
- package/dist/chunk-D5YGR4TP.js.map +1 -0
- package/dist/{chunk-NPRP3MCV.js → chunk-DHDCOOJU.js} +2 -2
- package/dist/chunk-DHDCOOJU.js.map +1 -0
- package/dist/{chunk-VP3TIUDF.js → chunk-DVTDF5OI.js} +2 -2
- package/dist/{chunk-OXD5LFQP.js → chunk-G7H6PN7P.js} +2 -2
- package/dist/{chunk-EL5VHUGK.js → chunk-GGKHHG5Y.js} +32 -18
- package/dist/chunk-GGKHHG5Y.js.map +1 -0
- package/dist/{chunk-446I4EGD.js → chunk-J5TBZFBD.js} +2 -2
- package/dist/{chunk-7AVQIGF6.js → chunk-K4ZYJ4EM.js} +554 -460
- package/dist/chunk-K4ZYJ4EM.js.map +1 -0
- package/dist/{chunk-QFE5BQH7.js → chunk-LTSI7ULC.js} +2 -2
- package/dist/{chunk-5GVURVIG.js → chunk-MMHGYX44.js} +12 -2
- package/dist/{chunk-5GVURVIG.js.map → chunk-MMHGYX44.js.map} +1 -1
- package/dist/{chunk-KRFGO5QH.js → chunk-MQMTRKY3.js} +118 -43
- package/dist/chunk-MQMTRKY3.js.map +1 -0
- package/dist/{chunk-42FQ27MQ.js → chunk-MTODGQBR.js} +44 -179
- package/dist/chunk-MTODGQBR.js.map +1 -0
- package/dist/{chunk-FVINAAKA.js → chunk-NBK6QQMG.js} +14 -13
- package/dist/{chunk-FVINAAKA.js.map → chunk-NBK6QQMG.js.map} +1 -1
- package/dist/{chunk-KNU73RZW.js → chunk-NSA5K5G2.js} +2 -2
- package/dist/{chunk-MLTPJMH6.js → chunk-QQYULEZL.js} +2 -2
- package/dist/chunk-QSW4DFKE.js +31 -0
- package/dist/chunk-QSW4DFKE.js.map +1 -0
- package/dist/{chunk-VAZXUK6G.js → chunk-SUNCHMML.js} +2 -2
- package/dist/{chunk-EP4WVQLX.js → chunk-T2U6N3FV.js} +6 -6
- package/dist/{chunk-T7SP3EYR.js → chunk-T5URUIIY.js} +33 -24
- package/dist/chunk-T5URUIIY.js.map +1 -0
- package/dist/{chunk-VNXAF2KE.js → chunk-TPTZZV25.js} +6 -6
- package/dist/chunk-TPTZZV25.js.map +1 -0
- package/dist/{chunk-IOJDYUA7.js → chunk-V46JWFGV.js} +6 -5
- package/dist/chunk-V46JWFGV.js.map +1 -0
- package/dist/{chunk-WGDEBIP4.js → chunk-X6ESZDR6.js} +5 -6
- package/dist/chunk-X6ESZDR6.js.map +1 -0
- package/dist/{chunk-N65E26UL.js → chunk-XEWV254I.js} +2 -2
- package/dist/{chunk-N65E26UL.js.map → chunk-XEWV254I.js.map} +1 -1
- package/dist/{chunk-PTWADEH3.js → chunk-YBJVKMTM.js} +34 -14
- package/dist/chunk-YBJVKMTM.js.map +1 -0
- package/dist/{chunk-DDTS7F5O.js → chunk-ZW32BPXV.js} +12 -3
- package/dist/chunk-ZW32BPXV.js.map +1 -0
- package/dist/compat/index.cjs +51 -4
- package/dist/compat/index.cjs.map +1 -1
- package/dist/compat/index.d.cts +1 -1
- package/dist/compat/index.d.ts +1 -1
- package/dist/compat/index.js +6 -6
- package/dist/compat/nestjs/index.cjs +51 -4
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +1 -1
- package/dist/compat/nestjs/index.d.ts +1 -1
- package/dist/compat/nestjs/index.js +3 -3
- package/dist/{fallback-Bx46zqky.d.cts → fallback-BROR6ZhO.d.cts} +1 -1
- package/dist/{fallback-pIWW8A2d.d.ts → fallback-DO80aM_3.d.ts} +1 -1
- package/dist/{index-B_p8tnvf.d.cts → index-D1z3XcF9.d.cts} +1 -0
- package/dist/{index-_HDSmPyp.d.ts → index-DZ6yua0Q.d.ts} +1 -0
- package/dist/index.cjs +2215 -1676
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +169 -146
- package/dist/index.js.map +1 -1
- package/dist/presets/ai/index.cjs +46 -0
- package/dist/presets/ai/index.cjs.map +1 -1
- package/dist/presets/ai/index.js +12 -12
- package/dist/presets/harness/index.cjs +130 -18
- package/dist/presets/harness/index.cjs.map +1 -1
- package/dist/presets/harness/index.d.cts +15 -5
- package/dist/presets/harness/index.d.ts +15 -5
- package/dist/presets/harness/index.js +22 -22
- package/dist/presets/index.cjs +222 -53
- package/dist/presets/index.cjs.map +1 -1
- package/dist/presets/index.d.cts +2 -2
- package/dist/presets/index.d.ts +2 -2
- package/dist/presets/index.js +45 -45
- package/dist/presets/inspect/index.cjs +63 -14
- package/dist/presets/inspect/index.cjs.map +1 -1
- package/dist/presets/inspect/index.d.cts +1 -1
- package/dist/presets/inspect/index.d.ts +1 -1
- package/dist/presets/inspect/index.js +6 -6
- package/dist/presets/resilience/index.cjs +29 -21
- package/dist/presets/resilience/index.cjs.map +1 -1
- package/dist/presets/resilience/index.d.cts +12 -8
- package/dist/presets/resilience/index.d.ts +12 -8
- package/dist/presets/resilience/index.js +3 -3
- package/dist/{rate-limiter-DpVbSYdH.d.cts → rate-limiter-DC26FM8J.d.cts} +10 -1
- package/dist/{rate-limiter-CEALq4N1.d.ts → rate-limiter-DyWpwpQP.d.ts} +10 -1
- package/dist/{reactive-layout-fswlBUvX.d.ts → reactive-layout-BBBWH0V_.d.cts} +85 -4
- package/dist/{reactive-layout-fswlBUvX.d.cts → reactive-layout-BBBWH0V_.d.ts} +85 -4
- package/dist/solutions/index.cjs +168 -47
- package/dist/solutions/index.cjs.map +1 -1
- package/dist/solutions/index.d.cts +2 -2
- package/dist/solutions/index.d.ts +2 -2
- package/dist/solutions/index.js +28 -28
- package/dist/{spawnable-5mDY501F.d.cts → spawnable-B2IlW60f.d.cts} +23 -2
- package/dist/{spawnable-D3lR0oQu.d.ts → spawnable-tttFz2Nh.d.ts} +23 -2
- package/dist/testing/index.cjs +94 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +59 -0
- package/dist/testing/index.d.ts +59 -0
- package/dist/testing/index.js +73 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/utils/ai/browser.cjs.map +1 -1
- package/dist/utils/ai/browser.d.cts +2 -2
- package/dist/utils/ai/browser.d.ts +2 -2
- package/dist/utils/ai/browser.js +6 -6
- package/dist/utils/ai/browser.js.map +1 -1
- package/dist/utils/ai/index.cjs +250 -166
- package/dist/utils/ai/index.cjs.map +1 -1
- package/dist/utils/ai/index.d.cts +108 -12
- package/dist/utils/ai/index.d.ts +108 -12
- package/dist/utils/ai/index.js +21 -19
- package/dist/utils/ai/node.cjs.map +1 -1
- package/dist/utils/ai/node.d.cts +5 -5
- package/dist/utils/ai/node.d.ts +5 -5
- package/dist/utils/ai/node.js +2 -2
- package/dist/utils/ai/node.js.map +1 -1
- package/dist/utils/cqrs/index.cjs +29 -3
- package/dist/utils/cqrs/index.cjs.map +1 -1
- package/dist/utils/cqrs/index.d.cts +12 -7
- package/dist/utils/cqrs/index.d.ts +12 -7
- package/dist/utils/cqrs/index.js +2 -2
- package/dist/utils/demo-shell/index.cjs +45 -19
- package/dist/utils/demo-shell/index.cjs.map +1 -1
- package/dist/utils/demo-shell/index.d.cts +1 -1
- package/dist/utils/demo-shell/index.d.ts +1 -1
- package/dist/utils/demo-shell/index.js +2 -2
- package/dist/utils/domain-templates/index.cjs.map +1 -1
- package/dist/utils/domain-templates/index.js +3 -3
- package/dist/utils/graphspec/index.cjs.map +1 -1
- package/dist/utils/graphspec/index.js +3 -3
- package/dist/utils/index.cjs +1642 -1225
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +7 -7
- package/dist/utils/index.d.ts +7 -7
- package/dist/utils/index.js +72 -54
- package/dist/utils/inspect/index.cjs +52 -4
- package/dist/utils/inspect/index.cjs.map +1 -1
- package/dist/utils/inspect/index.d.cts +32 -3
- package/dist/utils/inspect/index.d.ts +32 -3
- package/dist/utils/inspect/index.js +4 -4
- package/dist/utils/job-queue/index.cjs +46 -9
- package/dist/utils/job-queue/index.cjs.map +1 -1
- package/dist/utils/job-queue/index.d.cts +33 -3
- package/dist/utils/job-queue/index.d.ts +33 -3
- package/dist/utils/job-queue/index.js +2 -2
- package/dist/utils/memory/index.cjs +556 -462
- package/dist/utils/memory/index.cjs.map +1 -1
- package/dist/utils/memory/index.d.cts +203 -24
- package/dist/utils/memory/index.d.ts +203 -24
- package/dist/utils/memory/index.js +10 -2
- package/dist/utils/messaging/index.cjs.map +1 -1
- package/dist/utils/messaging/index.d.cts +4 -3
- package/dist/utils/messaging/index.d.ts +4 -3
- package/dist/utils/messaging/index.js +2 -2
- package/dist/utils/orchestration/index.cjs +9 -0
- package/dist/utils/orchestration/index.cjs.map +1 -1
- package/dist/utils/orchestration/index.js +3 -3
- package/dist/utils/process/index.cjs +32 -2
- package/dist/utils/process/index.cjs.map +1 -1
- package/dist/utils/process/index.d.cts +4 -3
- package/dist/utils/process/index.d.ts +4 -3
- package/dist/utils/process/index.js +2 -2
- package/dist/utils/reactive-layout/index.cjs +184 -55
- package/dist/utils/reactive-layout/index.cjs.map +1 -1
- package/dist/utils/reactive-layout/index.d.cts +128 -3
- package/dist/utils/reactive-layout/index.d.ts +128 -3
- package/dist/utils/reactive-layout/index.js +16 -8
- package/dist/utils/reduction/index.cjs.map +1 -1
- package/dist/utils/reduction/index.js +2 -2
- package/dist/utils/resilience/index.cjs +29 -20
- package/dist/utils/resilience/index.cjs.map +1 -1
- package/dist/utils/resilience/index.d.cts +1 -1
- package/dist/utils/resilience/index.d.ts +1 -1
- package/dist/utils/resilience/index.js +2 -2
- package/dist/utils/surface/index.cjs.map +1 -1
- package/dist/utils/surface/index.js +4 -4
- package/package.json +15 -3
- package/dist/chunk-3O3NKZJW.js.map +0 -1
- package/dist/chunk-3PSLNJDU.js.map +0 -1
- package/dist/chunk-42FQ27MQ.js.map +0 -1
- package/dist/chunk-4XCHZRUJ.js.map +0 -1
- package/dist/chunk-6ZLCPUXS.js.map +0 -1
- package/dist/chunk-7AVQIGF6.js.map +0 -1
- package/dist/chunk-BXGZFGZ4.js.map +0 -1
- package/dist/chunk-DDTS7F5O.js.map +0 -1
- package/dist/chunk-EL5VHUGK.js.map +0 -1
- package/dist/chunk-FQSQONOU.js.map +0 -1
- package/dist/chunk-IOJDYUA7.js.map +0 -1
- package/dist/chunk-KRFGO5QH.js.map +0 -1
- package/dist/chunk-MS3WPRJR.js.map +0 -1
- package/dist/chunk-NPRP3MCV.js.map +0 -1
- package/dist/chunk-NY2PYHNC.js.map +0 -1
- package/dist/chunk-PKPO3JTZ.js.map +0 -1
- package/dist/chunk-PTWADEH3.js.map +0 -1
- package/dist/chunk-T7SP3EYR.js.map +0 -1
- package/dist/chunk-VNXAF2KE.js.map +0 -1
- package/dist/chunk-W2BOPXTI.js +0 -1
- package/dist/chunk-W2BOPXTI.js.map +0 -1
- package/dist/chunk-WGDEBIP4.js.map +0 -1
- /package/dist/{chunk-R6ZCSXKX.js.map → chunk-23MAWVOJ.js.map} +0 -0
- /package/dist/{chunk-6MRSX3YK.js.map → chunk-B5Y5GPD5.js.map} +0 -0
- /package/dist/{chunk-VP3TIUDF.js.map → chunk-DVTDF5OI.js.map} +0 -0
- /package/dist/{chunk-OXD5LFQP.js.map → chunk-G7H6PN7P.js.map} +0 -0
- /package/dist/{chunk-446I4EGD.js.map → chunk-J5TBZFBD.js.map} +0 -0
- /package/dist/{chunk-QFE5BQH7.js.map → chunk-LTSI7ULC.js.map} +0 -0
- /package/dist/{chunk-KNU73RZW.js.map → chunk-NSA5K5G2.js.map} +0 -0
- /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
- /package/dist/{chunk-VAZXUK6G.js.map → chunk-SUNCHMML.js.map} +0 -0
- /package/dist/{chunk-EP4WVQLX.js.map → chunk-T2U6N3FV.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/base/resilience/_internal.ts","../../../src/base/resilience/backoff.ts","../../../src/base/resilience/timeout.ts","../../../src/presets/ai/index.ts","../../../src/presets/ai/agent.ts","../../../src/utils/ai/_internal.ts","../../../src/base/meta/domain-meta.ts","../../../src/utils/messaging/index.ts","../../../src/base/mutation/index.ts","../../../src/presets/ai/agent-loop.ts","../../../src/base/sources/settled.ts","../../../src/utils/ai/agents/chat-stream.ts","../../../src/utils/ai/agents/tool-execution.ts","../../../src/base/resilience/retry.ts","../../../src/utils/ai/agents/tool-registry.ts","../../../src/presets/ai/agent-memory.ts","../../../src/base/composition/distill.ts","../../../src/base/sources/async.ts","../../../src/utils/ai/memory/memory-composers.ts","../../../src/base/utils/decay.ts","../../../src/utils/memory/index.ts","../../../src/utils/ai/prompts/prompt-call.ts","../../../src/utils/ai/prompts/prompt-node.ts","../../../src/presets/ai/agents.ts","../../../src/presets/ai/context/index.ts","../../../src/presets/ai/debate/index.ts"],"sourcesContent":["/**\n * Internal helpers shared by resilience sub-files.\n *\n * Not part of the public surface. The base-layer resilience operators\n * co-located here (`retry.ts`, `status.ts`, `timeout.ts`) import what they\n * need from this file directly; the utils-layer resilience primitives that\n * stayed in `utils/resilience/` (`breaker.ts`, `rate-limiter.ts`,\n * `fallback.ts`) import it top-down via `../../base/resilience/_internal.js`.\n *\n * `NodeOrValue<T>` is the only export re-surfaced publicly — there is no\n * `base/resilience/index.ts`; it ships through `utils/resilience/index.ts`\n * (and `utils/memory/index.ts`). Every resilience primitive that accepts\n * reactive options uses it as the option-arg shape.\n */\n\nimport type { Node, NodeOptions } from \"@graphrefly/pure-ts/core\";\nimport { DATA, type Message } from \"@graphrefly/pure-ts/core\";\n\nexport type ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\nexport function operatorOpts<T>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"derived\", ...opts } as NodeOptions<T>;\n}\n\nexport function clampNonNegative(value: number): number {\n\treturn value < 0 ? 0 : value;\n}\n\nexport function msgVal(m: Message): unknown {\n\treturn m[1];\n}\n\nexport function coerceDelayNs(raw: number): number {\n\tif (typeof raw !== \"number\" || !Number.isFinite(raw)) {\n\t\tthrow new TypeError(\"backoff strategy must return a finite number\");\n\t}\n\treturn raw < 0 ? 0 : raw;\n}\n\nexport function isNode(x: unknown): x is Node {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\t\"cache\" in x &&\n\t\ttypeof (x as Node).subscribe === \"function\"\n\t);\n}\n\n/**\n * Either a literal value or a reactive Node carrying it. Mirrors\n * {@link FallbackInput}'s precedent for \"options that may be reactive.\"\n *\n * Used by {@link timeout} / {@link retry} / {@link rateLimiter} /\n * {@link circuitBreaker} / {@link budgetGate} to accept reactive option\n * configurations (Tier 6.5 3.2, 2026-04-29). Each primitive subscribes\n * to the option Node via {@link resolveReactiveOption} and rebinds\n * internal state per its locked swap-semantic rule (see each primitive's\n * JSDoc for the rule).\n *\n * @category extra\n */\nexport type NodeOrValue<T> = T | Node<T>;\n\n/**\n * Closure-mirror helper for `NodeOrValue<T>` options\n * (COMPOSITION-GUIDE §28). Returns:\n * - `current()` — read the latest value (cached at construction; updated\n * on each Node DATA emission).\n * - `unsub()` — release the subscription. Static-form arg never\n * subscribes; `unsub` is a no-op there.\n *\n * `onChange` fires on each DATA after the initial value (skips the\n * cache-seed read). Use to rebind primitive-internal state per the\n * primitive's locked swap-semantic rule.\n *\n * @internal\n */\nexport function resolveReactiveOption<T>(\n\targ: NodeOrValue<T>,\n\tonChange?: (next: T) => void,\n): { current: () => T; unsub: () => void } {\n\tif (!isNode(arg)) {\n\t\treturn { current: () => arg, unsub: () => undefined };\n\t}\n\tconst node = arg as Node<T>;\n\tlet latest: T = node.cache as T;\n\tconst unsub = node.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA) {\n\t\t\t\tlatest = m[1] as T;\n\t\t\t\tif (onChange) onChange(latest);\n\t\t\t}\n\t\t}\n\t});\n\treturn {\n\t\tcurrent: () => latest,\n\t\tunsub,\n\t};\n}\n\nexport function isThenable(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nexport function isAsyncIterable(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n","/**\n * Backoff strategies for {@link retry} (roadmap §3.1). Delays are in **nanoseconds**.\n *\n * Convention: all graphrefly-ts timestamps and durations use nanoseconds (`_ns` suffix).\n * 1 second = 1_000_000_000 ns, 1 ms = 1_000_000 ns.\n */\n\nexport const NS_PER_MS = 1_000_000;\nexport const NS_PER_SEC = 1_000_000_000;\n\nexport type JitterMode = \"none\" | \"full\" | \"equal\";\n\nexport type BackoffPreset =\n\t| \"constant\"\n\t| \"linear\"\n\t| \"exponential\"\n\t| \"fibonacci\"\n\t| \"decorrelatedJitter\";\n\n/** `(attempt, error?, previousDelayNs?) => delayNs | null` — `null` means zero delay. */\nexport type BackoffStrategy = (\n\tattempt: number,\n\terror?: unknown,\n\tprevDelayNs?: number | null,\n) => number | null;\n\nfunction clampNonNegative(value: number): number {\n\treturn value < 0 ? 0 : value;\n}\n\nfunction applyJitter(delay: number, jitter: JitterMode): number {\n\tif (jitter === \"none\") return delay;\n\tif (jitter === \"full\") return Math.random() * delay;\n\treturn delay / 2 + Math.random() * (delay / 2);\n}\n\nfunction randomBetween(min: number, max: number): number {\n\treturn min + Math.random() * (max - min);\n}\n\n/**\n * Builds a strategy that always returns the same delay in nanoseconds.\n *\n * @param delayNs - Non-negative delay in nanoseconds; values below zero are clamped to zero.\n * @returns `BackoffStrategy` for use with {@link retry} or custom timers.\n *\n * @example\n * ```ts\n * import { constant, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, { count: 3, backoff: constant(0.25 * NS_PER_SEC) });\n * ```\n *\n * @category extra\n */\nexport function constant(delayNs: number): BackoffStrategy {\n\tconst safe = clampNonNegative(delayNs);\n\treturn () => safe;\n}\n\n/**\n * Builds linear backoff: `baseNs + stepNs * attempt` (`stepNs` defaults to `baseNs`).\n *\n * @param baseNs - Base delay in nanoseconds (clamped non-negative).\n * @param stepNs - Added per retry attempt in nanoseconds (clamped non-negative).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { linear, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * // Attempt 0 → 1 s, attempt 1 → 2 s, attempt 2 → 3 s …\n * const out = retry(source, { count: 4, backoff: linear(NS_PER_SEC) });\n * ```\n *\n * @category extra\n */\nexport function linear(baseNs: number, stepNs?: number): BackoffStrategy {\n\tconst safeBase = clampNonNegative(baseNs);\n\tconst safeStep = stepNs === undefined ? safeBase : clampNonNegative(stepNs);\n\treturn (attempt: number) => safeBase + safeStep * Math.max(0, attempt);\n}\n\nexport type ExponentialBackoffOptions = {\n\tbaseNs?: number;\n\tfactor?: number;\n\tmaxDelayNs?: number;\n\tjitter?: JitterMode;\n};\n\n/**\n * Builds exponential backoff in nanoseconds, capped by `maxDelayNs`, with optional jitter.\n *\n * @param options - Base, factor, cap, and jitter mode.\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @remarks\n * **Jitter:** `\"full\"` spreads delay across `[0, delay]`; `\"equal\"` uses `[delay/2, delay]`.\n *\n * @example\n * ```ts\n * import { exponential, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * // 100 ms → 200 ms → 400 ms … capped at 30 s, with full jitter\n * const out = retry(source, {\n * count: 5,\n * backoff: exponential({ baseNs: 100 * NS_PER_SEC / 1000, jitter: \"full\" }),\n * });\n * ```\n *\n * @category extra\n */\nexport function exponential(options?: ExponentialBackoffOptions): BackoffStrategy {\n\tconst baseNs = clampNonNegative(options?.baseNs ?? 100 * NS_PER_MS);\n\tconst factor = options?.factor !== undefined && options.factor < 1 ? 1 : (options?.factor ?? 2);\n\tconst maxDelayNs = clampNonNegative(options?.maxDelayNs ?? 30 * NS_PER_SEC);\n\tconst jitter = options?.jitter ?? \"none\";\n\n\treturn (attempt: number) => {\n\t\tlet delay: number;\n\t\tif (baseNs === 0) {\n\t\t\tdelay = 0;\n\t\t} else if (factor === 1) {\n\t\t\tdelay = baseNs;\n\t\t} else {\n\t\t\tconst capRatio = maxDelayNs / baseNs;\n\t\t\tlet growth = 1;\n\t\t\tfor (let i = 0; i < Math.max(0, attempt); i++) {\n\t\t\t\tif (growth >= capRatio) {\n\t\t\t\t\tgrowth = capRatio;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tgrowth *= factor;\n\t\t\t}\n\t\t\tdelay = baseNs * growth;\n\t\t\tif (delay > maxDelayNs) delay = maxDelayNs;\n\t\t}\n\t\treturn applyJitter(delay, jitter);\n\t};\n}\n\n/**\n * Builds Fibonacci-scaled delays: `1, 2, 3, 5, … × baseNs`, capped at `maxDelayNs`.\n *\n * @param baseNs - Multiplier applied to the Fibonacci unit (default `100ms` in nanoseconds).\n * @param maxDelayNs - Upper bound in nanoseconds (default `30s`).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { fibonacci, retry, NS_PER_MS } from \"@graphrefly/graphrefly-ts\";\n *\n * // Delays: 100 ms, 200 ms, 300 ms, 500 ms, 800 ms … (× 100 ms base)\n * const out = retry(source, { count: 5, backoff: fibonacci(100 * NS_PER_MS) });\n * ```\n *\n * @category extra\n */\nexport function fibonacci(baseNs = 100 * NS_PER_MS, maxDelayNs = 30 * NS_PER_SEC): BackoffStrategy {\n\tconst safeBase = clampNonNegative(baseNs);\n\tconst safeMax = clampNonNegative(maxDelayNs);\n\n\tfunction fibUnit(attempt: number): number {\n\t\tif (attempt <= 0) return 1;\n\t\tlet prev = 1;\n\t\tlet cur = 2;\n\t\tfor (let i = 1; i < attempt; i++) {\n\t\t\tconst next = prev + cur;\n\t\t\tprev = cur;\n\t\t\tcur = next;\n\t\t}\n\t\treturn cur;\n\t}\n\n\treturn (attempt: number) => {\n\t\tconst raw = fibUnit(attempt) * safeBase;\n\t\treturn raw <= safeMax ? raw : safeMax;\n\t};\n}\n\n/**\n * Decorrelated jitter (AWS-recommended): `random(baseNs, min(maxNs, lastDelay * 3))`.\n *\n * Stateless — uses `prevDelayNs` (passed by the consumer) instead of closure state.\n * Safe to share across concurrent retry sequences.\n *\n * @param baseNs - Floor of the random range (default `100ms` in nanoseconds).\n * @param maxNs - Ceiling cap (default `30s` in nanoseconds).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { decorrelatedJitter, retry, NS_PER_MS, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, {\n * count: 6,\n * backoff: decorrelatedJitter(100 * NS_PER_MS, 10 * NS_PER_SEC),\n * });\n * ```\n *\n * @category extra\n */\nexport function decorrelatedJitter(\n\tbaseNs = 100 * NS_PER_MS,\n\tmaxNs = 30 * NS_PER_SEC,\n): BackoffStrategy {\n\treturn (_attempt, _error, prevDelayNs) => {\n\t\tconst last = prevDelayNs ?? baseNs;\n\t\tconst ceiling = Math.min(maxNs, last * 3);\n\t\treturn randomBetween(baseNs, ceiling);\n\t};\n}\n\n/**\n * Decorator that caps any strategy at `maxAttempts`. Returns `null` (stop retrying) after the cap.\n *\n * @param strategy - Inner strategy to wrap.\n * @param maxAttempts - Maximum number of attempts (inclusive).\n * @returns Wrapped `BackoffStrategy`.\n *\n * @example\n * ```ts\n * import { withMaxAttempts, exponential } from \"@graphrefly/graphrefly-ts\";\n *\n * const capped = withMaxAttempts(exponential(), 3);\n * capped(3); // null — no more retries beyond attempt 3\n * ```\n *\n * @category extra\n */\nexport function withMaxAttempts(strategy: BackoffStrategy, maxAttempts: number): BackoffStrategy {\n\treturn (attempt, error, prevDelayNs) => {\n\t\tif (attempt >= maxAttempts) return null;\n\t\treturn strategy(attempt, error, prevDelayNs);\n\t};\n}\n\n/**\n * Maps a preset name to a concrete {@link BackoffStrategy} with library-default parameters.\n *\n * @param name - One of `constant`, `linear`, `exponential`, `fibonacci`, or `decorrelatedJitter`.\n * @returns Configured strategy with default parameters.\n * @throws Error when `name` is not a known preset.\n *\n * @example\n * ```ts\n * import { resolveBackoffPreset, retry } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, { count: 3, backoff: resolveBackoffPreset(\"exponential\") });\n * // Equivalent to retry(source, { count: 3, backoff: exponential() })\n * ```\n *\n * @category extra\n */\nexport function resolveBackoffPreset(name: BackoffPreset): BackoffStrategy {\n\tif (name === \"constant\") return constant(1 * NS_PER_SEC);\n\tif (name === \"linear\") return linear(1 * NS_PER_SEC);\n\tif (name === \"exponential\") return exponential();\n\tif (name === \"fibonacci\") return fibonacci();\n\tif (name === \"decorrelatedJitter\") return decorrelatedJitter();\n\tthrow new Error(\n\t\t`Unknown backoff preset: \"${String(name)}\". Use one of: constant, linear, exponential, fibonacci, decorrelatedJitter`,\n\t);\n}\n","/**\n * Timeout — emits `ERROR` with `TimeoutError` if no `DATA` arrives within the deadline.\n *\n * §3.1c — caching, fallback & composition sugar. Uses\n * `core/clock.js`-style nanoseconds and a `ResettableTimer` so the deadline\n * resets on each DATA. Distinct from the `operators/control.ts` timeout\n * (which forwards a caller-supplied error/value) — this one is the\n * resilience family's \"deadline → ERROR\" primitive.\n *\n * **DS-13.5.B (locked 2026-05-01).** Pre-1.0 break: returns\n * {@link TimeoutBundle} with `node` + `timeoutState` companion. Opts\n * accept `Partial<TimeoutOptions>` or `Node<Partial<TimeoutOptions>>`\n * (object-shape, replacing the old `NodeOrValue<number>` flat shape).\n * State preservation across rebind: `ns` change does NOT reset the\n * in-flight deadline — new `ns` applies to next attempt only.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\tmonotonicNs,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n\tResettableTimer,\n\tTEARDOWN,\n} from \"@graphrefly/pure-ts/core\";\nimport { isNode, operatorOpts } from \"./_internal.js\";\nimport { NS_PER_MS } from \"./backoff.js\";\n\n/**\n * Thrown by {@link withTimeout} when no `DATA` arrives within the deadline.\n *\n * @category extra\n */\nexport class TimeoutError extends Error {\n\toverride name = \"TimeoutError\";\n\tconstructor(ns: number) {\n\t\tsuper(`Timed out after ${ns / NS_PER_MS}ms`);\n\t}\n}\n\n/**\n * Options accepted by {@link withTimeout}.\n *\n * - `ns` — deadline in nanoseconds (must be `> 0`). Required at the\n * first opts settle; missing / non-positive values throw at\n * construction.\n * - `meta` — optional metadata merged onto the result node's `meta`\n * for describe()/explain() introspection. Reactive `meta` updates\n * are picked up on the next attempt's emission.\n *\n * @category extra/resilience\n */\nexport interface TimeoutOptions {\n\tns: number;\n\tmeta?: Record<string, unknown>;\n}\n\n/**\n * Lifecycle-shaped state companion emitted by {@link withTimeout}.\n *\n * Default `equals` dedups on the `status` field — subscribers don't\n * re-fire on identical-shape transitions, but DO fire on every state\n * transition AND on payload changes within the same status (e.g. when\n * `running.startedAt_ns` advances on a fresh attempt).\n *\n * @category extra/resilience\n */\nexport type TimeoutState =\n\t| { status: \"pending\" }\n\t| { status: \"running\"; startedAt_ns: number; deadline_ns: number }\n\t| { status: \"completed\"; settledAt_ns: number }\n\t| { status: \"errored\"; firedAt_ns: number; deadline_ns: number };\n\n/**\n * Bundle returned by {@link withTimeout}: the timeout-wrapped output node and\n * its lifecycle-shaped state companion.\n *\n * **Single-subscriber / pipeline-only contract (DS-13.5.B QA, N1, 2026-05-03).**\n * The `timeoutState` companion is allocated once at factory time and shared\n * across all subscribers to `node`. With one subscriber (the typical use\n * case — wire `node` into your downstream chain, optionally observe\n * `timeoutState` separately) the companion reflects a coherent timeline.\n * With **two or more subscribers** to `node`, each subscriber re-runs the\n * producer body and writes into the same `timeoutState`, which can flip\n * between states from different in-flight machines. Don't fan out\n * `node` to multiple subscribers and rely on `timeoutState` accuracy\n * unless you use {@link keepalive} / {@link share}-style consolidation.\n *\n * @category extra/resilience\n */\nexport interface TimeoutBundle<T> {\n\tnode: Node<T>;\n\ttimeoutState: Node<TimeoutState>;\n}\n\ninterface TimeoutExtraOpts {\n\tmeta?: Record<string, unknown>;\n}\n\n/**\n * Wrap `source` with a deadline. If no `DATA` arrives within `opts.ns`\n * nanoseconds, the result node emits `[[ERROR, TimeoutError]]` and\n * transitions `timeoutState` to `\"errored\"`.\n *\n * The timer starts on subscription and resets on each `DATA`. `DIRTY`\n * does NOT reset the timer. Terminal messages (`COMPLETE` / `ERROR`)\n * cancel the timer.\n *\n * **Reactive opts (DS-13.5.B, locked 2026-05-01).**\n *\n * - Static-form callers pass `Partial<TimeoutOptions>` (today's path).\n * `ns` is validated at construction; missing / non-positive throws\n * `RangeError`.\n * - Reactive-form callers pass `Node<Partial<TimeoutOptions>>` — each\n * emission shallow-merges over the prior opts. Empty `{}` emissions\n * are no-ops (no rebind, no companion fire). Mid-flight opts swap\n * does NOT reset the in-flight deadline; new `ns` applies to the\n * next `startTimer()` call.\n * - When the opts Node has `cache === undefined` (SENTINEL: no opts\n * emitted yet), the source is paused until the first valid opts\n * settle. The first valid settle must carry `ns > 0` or the timer\n * layer emits an ERROR (downstream observable) — distinct from the\n * construction-time `RangeError` thrown for static / cache-defined\n * invalid values.\n *\n * @param source - Upstream node.\n * @param opts - `Partial<TimeoutOptions>` (static) or\n * `Node<Partial<TimeoutOptions>>` (reactive).\n * @param extraOpts - Forwarded factory metadata (meta field merged\n * onto the result node).\n * @returns {@link TimeoutBundle} with `node` and `timeoutState`.\n *\n * @throws {RangeError} when the first opts settle is missing or has\n * non-positive `ns`.\n *\n * @category extra\n */\nexport function withTimeout<T>(\n\tsource: Node<T>,\n\topts: Partial<TimeoutOptions> | Node<Partial<TimeoutOptions>>,\n\textraOpts?: TimeoutExtraOpts,\n): TimeoutBundle<T> {\n\tconst isReactive = isNode(opts);\n\n\t// Construction-time validation:\n\t// - Static form: validate the supplied object eagerly.\n\t// - Node form with defined cache: validate the cache value eagerly.\n\t// - Node form with `cache === undefined`: defer validation to first\n\t// DATA emission; source is paused in the meantime.\n\tlet latestOpts: TimeoutOptions | null = null;\n\tif (!isReactive) {\n\t\tconst staticOpts = opts as Partial<TimeoutOptions>;\n\t\tif (\n\t\t\tstaticOpts.ns === undefined ||\n\t\t\ttypeof staticOpts.ns !== \"number\" ||\n\t\t\t!Number.isFinite(staticOpts.ns) ||\n\t\t\tstaticOpts.ns <= 0\n\t\t) {\n\t\t\tthrow new RangeError(\"withTimeout: opts.ns must be a positive finite number\");\n\t\t}\n\t\tlatestOpts = {\n\t\t\tns: staticOpts.ns,\n\t\t\t...(staticOpts.meta != null ? { meta: staticOpts.meta } : {}),\n\t\t};\n\t} else {\n\t\tconst cached = (opts as Node<Partial<TimeoutOptions>>).cache as\n\t\t\t| Partial<TimeoutOptions>\n\t\t\t| undefined;\n\t\tif (cached !== undefined) {\n\t\t\tif (\n\t\t\t\tcached.ns === undefined ||\n\t\t\t\ttypeof cached.ns !== \"number\" ||\n\t\t\t\t!Number.isFinite(cached.ns) ||\n\t\t\t\tcached.ns <= 0\n\t\t\t) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t\"withTimeout: opts.ns must be a positive finite number on first settle\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tlatestOpts = {\n\t\t\t\tns: cached.ns,\n\t\t\t\t...(cached.meta != null ? { meta: cached.meta } : {}),\n\t\t\t};\n\t\t}\n\t}\n\n\tconst callerMeta = extraOpts?.meta;\n\tconst factoryArgs: Record<string, unknown> = isReactive\n\t\t? { ns: \"Node<Partial<TimeoutOptions>>\" }\n\t\t: { ns: latestOpts!.ns };\n\n\t// Companion state node — lifecycle-shaped. Default Object.is-on-status\n\t// dedup so identical-shape transitions don't re-fire downstream.\n\tconst timeoutState = node<TimeoutState>([], {\n\t\tname: \"timeoutState\",\n\t\tdescribeKind: \"state\",\n\t\tinitial: { status: \"pending\" },\n\t\tequals: (a, b) =>\n\t\t\ta === b ||\n\t\t\t(a != null &&\n\t\t\t\tb != null &&\n\t\t\t\ttypeof a === \"object\" &&\n\t\t\t\ttypeof b === \"object\" &&\n\t\t\t\t(a as { status: string }).status === (b as { status: string }).status &&\n\t\t\t\tJSON.stringify(a) === JSON.stringify(b)),\n\t});\n\n\tconst out = node<T>(\n\t\t(_data, a) => {\n\t\t\tlet stopped = false;\n\t\t\tlet lastDeadlineNs = 0;\n\t\t\tconst timer = new ResettableTimer();\n\t\t\tlet optsUnsub: (() => void) | null = null;\n\t\t\tlet srcUnsub: (() => void) | null = null;\n\n\t\t\tfunction emitState(next: TimeoutState): void {\n\t\t\t\ttimeoutState.down([[DIRTY], [DATA, next]]);\n\t\t\t}\n\n\t\t\tfunction startTimer(): void {\n\t\t\t\tif (stopped) return;\n\t\t\t\t// QA A4 (2026-05-03): defensive guard — `latestOpts.ns`\n\t\t\t\t// reaching `undefined` / `NaN` / non-finite is a Class-of-\n\t\t\t\t// bugs source: an explicit `{ ns: undefined }` emit would\n\t\t\t\t// pass the per-key validation (which only checks\n\t\t\t\t// `next.ns !== undefined`) and shallow-merge over a valid\n\t\t\t\t// prior `ns`. Without this guard, `delayMs = NaN`, which\n\t\t\t\t// `setTimeout` treats as `0` → spurious immediate timeout.\n\t\t\t\tif (\n\t\t\t\t\tlatestOpts == null ||\n\t\t\t\t\ttypeof latestOpts.ns !== \"number\" ||\n\t\t\t\t\t!Number.isFinite(latestOpts.ns) ||\n\t\t\t\t\tlatestOpts.ns <= 0\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst ns = latestOpts.ns;\n\t\t\t\tlastDeadlineNs = ns;\n\t\t\t\tconst startedAt = monotonicNs();\n\t\t\t\tconst delayMs = ns / NS_PER_MS;\n\t\t\t\temitState({\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t\tstartedAt_ns: startedAt,\n\t\t\t\t\tdeadline_ns: ns,\n\t\t\t\t});\n\t\t\t\ttimer.start(delayMs, () => {\n\t\t\t\t\tif (stopped) return;\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tsrcUnsub?.();\n\t\t\t\t\temitState({\n\t\t\t\t\t\tstatus: \"errored\",\n\t\t\t\t\t\tfiredAt_ns: monotonicNs(),\n\t\t\t\t\t\tdeadline_ns: ns,\n\t\t\t\t\t});\n\t\t\t\t\ta.down([[ERROR, new TimeoutError(ns)]]);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tfunction attachSource(): void {\n\t\t\t\tif (srcUnsub != null || stopped) return;\n\t\t\t\tsrcUnsub = source.subscribe((msgs) => {\n\t\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\t\tif (stopped) return;\n\t\t\t\t\t\tconst t = m[0];\n\t\t\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\t\t\telse if (t === DATA) {\n\t\t\t\t\t\t\tstartTimer();\n\t\t\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t\t\ttimer.cancel();\n\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\temitState({\n\t\t\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\t\t\tsettledAt_ns: monotonicNs(),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\t\ttimer.cancel();\n\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\temitState({\n\t\t\t\t\t\t\t\tstatus: \"errored\",\n\t\t\t\t\t\t\t\tfiredAt_ns: monotonicNs(),\n\t\t\t\t\t\t\t\tdeadline_ns: lastDeadlineNs,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} else if (t === TEARDOWN) {\n\t\t\t\t\t\t\ttimer.cancel();\n\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} else a.down([m]);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\t// Kick the initial timer if we already have valid opts.\n\t\t\t\tif (latestOpts != null && latestOpts.ns > 0) {\n\t\t\t\t\tstartTimer();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isReactive) {\n\t\t\t\tconst optsNode = opts as Node<Partial<TimeoutOptions>>;\n\t\t\t\toptsUnsub = optsNode.subscribe((msgs) => {\n\t\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\t\t\tconst next = m[1] as Partial<TimeoutOptions>;\n\t\t\t\t\t\tif (next == null || typeof next !== \"object\") continue;\n\t\t\t\t\t\t// Empty `{}` emit is a no-op (lock spec).\n\t\t\t\t\t\tconst keys = Object.keys(next);\n\t\t\t\t\t\tif (keys.length === 0) continue;\n\t\t\t\t\t\t// QA A4 (2026-05-03): validate ns whenever it APPEARS\n\t\t\t\t\t\t// in the emit's keys — including `{ ns: undefined }`,\n\t\t\t\t\t\t// which would otherwise skip validation and shallow-\n\t\t\t\t\t\t// merge over a valid prior `ns` with `undefined`,\n\t\t\t\t\t\t// producing `delayMs = NaN` ≈ 0 ms in startTimer().\n\t\t\t\t\t\t// `'ns' in next` covers both \"explicitly undefined\"\n\t\t\t\t\t\t// and \"explicitly invalid\" forms.\n\t\t\t\t\t\tif (\"ns\" in next) {\n\t\t\t\t\t\t\tif (typeof next.ns !== \"number\" || !Number.isFinite(next.ns) || next.ns <= 0) {\n\t\t\t\t\t\t\t\tif (latestOpts == null) {\n\t\t\t\t\t\t\t\t\t// First settle invalid — emit ERROR rather\n\t\t\t\t\t\t\t\t\t// than throw (mid-subscribe; sync throw\n\t\t\t\t\t\t\t\t\t// would corrupt the host scheduler).\n\t\t\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\t\t\ta.down([\n\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\tERROR,\n\t\t\t\t\t\t\t\t\t\t\tnew RangeError(\n\t\t\t\t\t\t\t\t\t\t\t\t\"withTimeout: opts.ns must be a positive finite number on first settle\",\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Ignore invalid mid-flight ns updates; keep\n\t\t\t\t\t\t\t\t// prior latestOpts.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst wasNull = latestOpts == null;\n\t\t\t\t\t\tlatestOpts = {\n\t\t\t\t\t\t\t...(latestOpts ?? { ns: 0 }),\n\t\t\t\t\t\t\t...next,\n\t\t\t\t\t\t} as TimeoutOptions;\n\t\t\t\t\t\t// First valid settle activates the source attach.\n\t\t\t\t\t\tif (wasNull && latestOpts.ns > 0) {\n\t\t\t\t\t\t\tattachSource();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Static form: attach immediately. Reactive form with defined\n\t\t\t// cache also attaches immediately (latestOpts pre-populated).\n\t\t\tif (latestOpts != null) {\n\t\t\t\tattachSource();\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tstopped = true;\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tif (srcUnsub) srcUnsub();\n\t\t\t\t\tif (optsUnsub) optsUnsub();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: source.cache,\n\t\t\tmeta: { ...(callerMeta ?? {}), ...factoryTag(\"withTimeout\", factoryArgs) },\n\t\t},\n\t);\n\n\treturn { node: out, timeoutState };\n}\n","/**\n * AI presets — opinionated compositions of ai utils.\n *\n * @module\n */\n\nexport * from \"./agent.js\";\nexport * from \"./agent-loop.js\";\nexport * from \"./agent-memory.js\";\nexport * from \"./agents.js\";\nexport * from \"./context/index.js\";\nexport * from \"./debate/index.js\";\n","/**\n * Phase 13.G — `AgentBundle<TIn, TOut>` interface + `class AgentGraph extends Graph`.\n *\n * Source: `archive/docs/SESSION-multi-agent-gap-analysis.md` G1 lock B.\n *\n * Composes the existing substrate (`agentLoop`, `toolRegistry`,\n * `agentMemory`) into a typed inbox/outbox subgraph that other parts of a\n * multi-agent system can wire to. Sibling preset `agent()` (in\n * `./agents.ts`) is the ergonomic factory; this file is the contract.\n *\n * **Cross-cut #1 lock (no `agent.run()`):** caller-side runtime entry is\n * `bundle.in.emit(input)` + `awaitSettled(bundle.out)`. The legacy\n * `agentLoop.run()` is still available on `bundle.graph.loop` for\n * single-shot Promise-bridge use cases, but `agent()` does NOT expose a\n * `run()` method on the bundle.\n *\n * **Memory partition default:** private memory per agent (each `agent(...)`\n * call creates its own `AgentMemoryGraph` if none passed). Pass an explicit\n * shared instance for §29 handoff context-transfer.\n */\n\nimport { batch, DATA, INVALIDATE, type Node, node, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { keepalive } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../../utils/ai/_internal.js\";\nimport type {\n\tInputTokens,\n\tLLMAdapter,\n\tLLMResponse,\n\tOutputTokens,\n\tTokenUsage,\n\tToolDefinition,\n} from \"../../utils/ai/adapters/core/types.js\";\nimport {\n\ttype SubscriptionGraph,\n\tsubscription,\n\ttype TopicGraph,\n\ttopic,\n} from \"../../utils/messaging/index.js\";\nimport { type AgentLoopGraph, agentLoop } from \"./agent-loop.js\";\nimport type { AgentMemoryGraph } from \"./agent-memory.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Lifecycle status of an {@link AgentGraph}.\n *\n * - `idle` — no input has been received since construction or last reset.\n * - `running` — inputs are flowing through the underlying agentLoop\n * (collapses the loop's `thinking` + `acting` substates so consumers\n * don't have to model the tool-call inner loop).\n * - `verifying` — verifier subgraph is in flight (reserved; lights up when\n * the verifier slot is added in a future wave per G7 recipe).\n * - `done` — the most recent input has settled with a verified response.\n * - `error` — the loop or verifier produced a terminal error.\n *\n * **Note (Phase 13.G, 2026-05-01):** v1 of `agent()` has no built-in\n * verifier slot — `verifying` is reserved but never produced. When a\n * verifier consumer surfaces, this enum widens (non-breaking type\n * widening; existing consumers see the same `idle | running | done | error`\n * subset).\n */\nexport type AgentStatus = \"idle\" | \"running\" | \"verifying\" | \"done\" | \"error\";\n\n/**\n * Aggregated cost for an agent's run, surfaced as a `Node<CostState>` on\n * the bundle. **Wraps the canonical {@link TokenUsage}** so consumers get\n * the full provider-disaggregated token classes (cache-read /\n * cache-write-5m / cache-write-1h / audio / image / video / tool-use /\n * reasoning / prediction-accepted / prediction-rejected / extensions /\n * auxiliary non-token costs / raw escape-hatch) without losing fidelity\n * for downstream pricing. USD conversion is a downstream `derived` over\n * `usage`.\n *\n * - `usage` — accumulated {@link TokenUsage} across all turns of the\n * current input.\n * - `turns` — number of completed agentLoop iterations (LLM invocations).\n *\n * **Counter scope:** resets to {@link ZERO_COST} on each new `bundle.in`\n * emit (per-input cost rather than per-agent-lifetime). Sum across multiple\n * inputs by snapshotting `cost` at `done` and accumulating externally —\n * a per-lifetime cost is a downstream `scan` over this.\n *\n * **Helpers.** Use `sumInputTokens(usage)` / `sumOutputTokens(usage)` from\n * `@graphrefly/graphrefly-ts` to flatten to scalars when the caller wants\n * a single number.\n */\nexport interface CostState {\n\treadonly usage: TokenUsage;\n\treadonly turns: number;\n}\n\nconst EMPTY_INPUT: InputTokens = Object.freeze({ regular: 0 });\nconst EMPTY_OUTPUT: OutputTokens = Object.freeze({ regular: 0 });\nconst EMPTY_USAGE: TokenUsage = Object.freeze({ input: EMPTY_INPUT, output: EMPTY_OUTPUT });\n\n/** Empty cost. Used as the initial value and the per-input reset baseline. */\nexport const ZERO_COST: CostState = Object.freeze({ usage: EMPTY_USAGE, turns: 0 });\n\n// ---------------------------------------------------------------------------\n// TokenUsage accumulator\n// ---------------------------------------------------------------------------\n\nfunction addOptional(a: number | undefined, b: number | undefined): number | undefined {\n\tif (a == null && b == null) return undefined;\n\treturn (a ?? 0) + (b ?? 0);\n}\n\nfunction addExtensions(\n\ta: Record<string, number> | undefined,\n\tb: Record<string, number> | undefined,\n): Record<string, number> | undefined {\n\tif (a == null && b == null) return undefined;\n\tconst out: Record<string, number> = { ...(a ?? {}) };\n\tfor (const [k, v] of Object.entries(b ?? {})) {\n\t\tout[k] = (out[k] ?? 0) + v;\n\t}\n\treturn out;\n}\n\n/**\n * Accumulates two {@link TokenUsage} snapshots. All field classes are\n * summed; optional fields propagate as `undefined` when absent from both\n * sides, otherwise treated as 0 for the missing side. `auxiliary` and\n * `extensions` merge by key. `raw` is dropped — it's a per-call escape\n * hatch, not summable.\n *\n * @category extra\n */\nexport function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage {\n\tconst out: TokenUsage = {\n\t\tinput: {\n\t\t\tregular: a.input.regular + b.input.regular,\n\t\t\t...(addOptional(a.input.cacheRead, b.input.cacheRead) !== undefined && {\n\t\t\t\tcacheRead: addOptional(a.input.cacheRead, b.input.cacheRead) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) !== undefined && {\n\t\t\t\tcacheWrite5m: addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) !== undefined && {\n\t\t\t\tcacheWrite1h: addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) !== undefined && {\n\t\t\t\tcacheWriteOther: addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.audio, b.input.audio) !== undefined && {\n\t\t\t\taudio: addOptional(a.input.audio, b.input.audio) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.image, b.input.image) !== undefined && {\n\t\t\t\timage: addOptional(a.input.image, b.input.image) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.video, b.input.video) !== undefined && {\n\t\t\t\tvideo: addOptional(a.input.video, b.input.video) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.toolUse, b.input.toolUse) !== undefined && {\n\t\t\t\ttoolUse: addOptional(a.input.toolUse, b.input.toolUse) as number,\n\t\t\t}),\n\t\t\t...(addExtensions(a.input.extensions, b.input.extensions) !== undefined && {\n\t\t\t\textensions: addExtensions(a.input.extensions, b.input.extensions) as Record<string, number>,\n\t\t\t}),\n\t\t},\n\t\toutput: {\n\t\t\tregular: a.output.regular + b.output.regular,\n\t\t\t...(addOptional(a.output.reasoning, b.output.reasoning) !== undefined && {\n\t\t\t\treasoning: addOptional(a.output.reasoning, b.output.reasoning) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.audio, b.output.audio) !== undefined && {\n\t\t\t\taudio: addOptional(a.output.audio, b.output.audio) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.predictionAccepted, b.output.predictionAccepted) !== undefined && {\n\t\t\t\tpredictionAccepted: addOptional(\n\t\t\t\t\ta.output.predictionAccepted,\n\t\t\t\t\tb.output.predictionAccepted,\n\t\t\t\t) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.predictionRejected, b.output.predictionRejected) !== undefined && {\n\t\t\t\tpredictionRejected: addOptional(\n\t\t\t\t\ta.output.predictionRejected,\n\t\t\t\t\tb.output.predictionRejected,\n\t\t\t\t) as number,\n\t\t\t}),\n\t\t\t...(addExtensions(a.output.extensions, b.output.extensions) !== undefined && {\n\t\t\t\textensions: addExtensions(a.output.extensions, b.output.extensions) as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\tnumber\n\t\t\t\t>,\n\t\t\t}),\n\t\t},\n\t\t...(addExtensions(a.auxiliary, b.auxiliary) !== undefined && {\n\t\t\tauxiliary: addExtensions(a.auxiliary, b.auxiliary) as Record<string, number>,\n\t\t}),\n\t};\n\treturn out;\n}\n\n/**\n * Spec for {@link agent} (in `./agents.ts`). Required fields are minimal —\n * `name` and `adapter` cover the common case where the input is a string\n * and the output is the raw `LLMResponse`. Optional fields shape the\n * agent's behavior:\n *\n * - **Mappers** (`inMapper` / `outMapper`) translate between caller-typed\n * `TIn` / `TOut` and the loop's internal `string` / `LLMResponse`. Default\n * identity mappers are wired automatically when `TIn` extends `string`\n * and `TOut` extends `LLMResponse`.\n * - **`tools`** is a reactive `NodeInput<readonly ToolDefinition[]>` —\n * `agent()` subscribes and reconciles the underlying `toolRegistry`'s\n * registrations on each emit. Static-array form is also accepted.\n * - **`memory`** is an explicit `AgentMemoryGraph` instance for shared\n * memory across agents (§29 handoff context transfer). Default: private\n * memory per agent (each `agent()` call mints its own).\n * - **`maxIterations`** caps the underlying agentLoop's tool-call inner\n * loop. Default 10 (matches `agentLoop`).\n * - **Verifier slot** is intentionally not in v1 — G7 reframe locks it as\n * a caller-composed recipe. When a real consumer surfaces, a\n * `verifier?: (out: Node<TOut>) => NodeInput<VerifierResult>` field\n * lands here additively.\n */\nexport interface AgentSpec<TIn, TOut> {\n\t/** Local mount name when wired to a parent graph. Required. */\n\treadonly name: string;\n\t/** LLM adapter for the underlying agentLoop. Required. */\n\treadonly adapter: LLMAdapter;\n\t/** Optional system prompt. Static today; reactive widening pending. */\n\treadonly systemPrompt?: string;\n\t/**\n\t * Optional reactive tool list. When a Node, the agent subscribes and\n\t * reconciles the underlying `toolRegistry` registrations on each emit\n\t * (additions registered, removals unregistered). When a static array,\n\t * tools are registered once at construction.\n\t */\n\treadonly tools?: Node<readonly ToolDefinition[]> | readonly ToolDefinition[];\n\t/**\n\t * Optional shared memory. Default: private (agent mints its own\n\t * `AgentMemoryGraph` if needed; not yet wired into the loop's chat —\n\t * that wiring is a separate follow-up). Pass an explicit instance to\n\t * share memory across agents for §29 handoff context transfer.\n\t */\n\treadonly memory?: AgentMemoryGraph<unknown>;\n\t/**\n\t * Maps caller-typed input → string for the underlying chat. Defaults to\n\t * identity when `TIn extends string`; required otherwise.\n\t */\n\treadonly inMapper?: (input: TIn) => string;\n\t/**\n\t * Maps the agentLoop's `LLMResponse` → caller-typed output. Defaults to\n\t * identity when `TOut extends LLMResponse`; required otherwise.\n\t */\n\treadonly outMapper?: (response: LLMResponse) => TOut;\n\t/** Caps tool-call inner-loop iterations. Default 10. */\n\treadonly maxIterations?: number;\n\t/** Escape hatch for non-core fields. Surfaced in `describe()` via meta. */\n\treadonly meta?: Record<string, unknown>;\n}\n\n/**\n * Public contract for an agent — typed inbox/outbox + lifecycle / cost\n * observables + the underlying graph for inspection / mounting.\n *\n * **Reactive entry:** caller writes to `in` (e.g. `bundle.in.emit(input)`).\n * The agent reactively kicks the underlying loop and produces `out`.\n *\n * **Reactive exit:** caller reads `out` via `subscribe` (continuous) or\n * `awaitSettled(out)` (single-shot). Both `in` and `out` stay SENTINEL\n * (`cache === undefined`) until the first real emission — no `null`\n * push-on-subscribe trap (per `feedback_use_prevdata_for_sentinel`).\n *\n * **Cross-graph wiring:** the bundle's `graph` is mountable under any\n * parent via `parent.mount(name, bundle.graph)`. After mount, the bundle's\n * Nodes are reachable through both the bundle reference (direct) and via\n * `parent.node(\"<name>::out\")` etc. (qualified path).\n */\nexport interface AgentBundle<TIn, TOut> {\n\treadonly in: Node<TIn>;\n\treadonly out: Node<TOut>;\n\treadonly status: Node<AgentStatus>;\n\treadonly cost: Node<CostState>;\n\treadonly graph: AgentGraph<TIn, TOut>;\n}\n\n// ---------------------------------------------------------------------------\n// AgentGraph\n// ---------------------------------------------------------------------------\n\nconst TERMINAL_STATUSES = new Set<AgentStatus>([\"done\", \"error\"]);\n\n/**\n * Graph subclass implementing {@link AgentBundle}. Mounts an inner\n * {@link AgentLoopGraph} at `loop/`; `in` / `out` / `status` / `cost`\n * surface the bundle contract as top-level nodes.\n *\n * Construction is internal — use the {@link agent} factory in\n * `./agents.ts` for normal use. Direct `new AgentGraph(name, spec)` is\n * supported for callers that want full control over mount order.\n *\n * **Topology:**\n * ```\n * <name>\n * ├── loop (AgentLoopGraph subgraph)\n * │ ├── chat\n * │ ├── tools\n * │ ├── status / turn / aborted / lastResponse / ...\n * ├── in (Node<TIn>, SENTINEL until first emit)\n * ├── out (Node<TOut>, SENTINEL until first response)\n * ├── status (Node<AgentStatus>, mirror of loop.status)\n * └── cost (Node<CostState>)\n * ```\n *\n * **Lifecycle:**\n * - On `in` emit: `inMapper` projects to `string`; appended to\n * `loop.chat`; loop status reset (`turn=0`, `aborted=false`,\n * `status=\"thinking\"`); per-input cost counters reset to zero.\n * - On `loop.lastResponse` emit: cost rolls forward; `out` emits\n * `outMapper(response)`.\n * - On `loop.status=\"done\"`: agent's status emits `\"done\"`.\n * - On `loop.status=\"error\"` (or any ERROR propagation): agent's status\n * emits `\"error\"`.\n */\nexport class AgentGraph<TIn, TOut> extends Graph {\n\t/** The agent's typed inbox. Writable; `in.emit(value)` kicks the loop. */\n\treadonly in: Node<TIn>;\n\t/** The agent's typed outbox. SENTINEL until first response. */\n\treadonly out: Node<TOut>;\n\t/** Lifecycle status (translated from the underlying loop's substates). */\n\treadonly status: Node<AgentStatus>;\n\t/** Cumulative cost for the current / most-recent input. */\n\treadonly cost: Node<CostState>;\n\t/** The underlying agentLoop — exposed for inspection / advanced wiring. */\n\treadonly loop: AgentLoopGraph;\n\t/** Optional shared memory subgraph (mounted at `memory/` if provided). */\n\treadonly memory: AgentMemoryGraph<unknown> | null;\n\n\tconstructor(spec: AgentSpec<TIn, TOut>, opts?: GraphOptions) {\n\t\tsuper(spec.name, opts);\n\n\t\t// --- 1. Mount the agentLoop subgraph. ------------------------------\n\t\tconst initialTools = Array.isArray(spec.tools)\n\t\t\t? (spec.tools as readonly ToolDefinition[])\n\t\t\t: undefined;\n\t\tthis.loop = agentLoop(`${spec.name}-loop`, {\n\t\t\tadapter: spec.adapter,\n\t\t\t...(spec.systemPrompt != null ? { systemPrompt: spec.systemPrompt } : {}),\n\t\t\t...(initialTools != null ? { tools: initialTools } : {}),\n\t\t\t...(spec.maxIterations != null ? { maxTurns: spec.maxIterations } : {}),\n\t\t});\n\t\tthis.mount(\"loop\", this.loop);\n\n\t\t// --- 2. Reactive tools subscription (if Node-form). ----------------\n\t\t// agentLoop's tools are static-array at construction; we reconcile\n\t\t// dynamically by subscribing to the user's reactive Node and\n\t\t// register/unregister against the inner toolRegistry.\n\t\tif (spec.tools != null && !Array.isArray(spec.tools)) {\n\t\t\tconst toolsNode = spec.tools as Node<readonly ToolDefinition[]>;\n\t\t\tconst registered = new Set<string>();\n\t\t\tconst unsubTools = toolsNode.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\t\tconst next = m[1] as readonly ToolDefinition[];\n\t\t\t\t\tconst nextNames = new Set(next.map((t) => t.name));\n\t\t\t\t\t// Unregister missing.\n\t\t\t\t\tfor (const name of registered) {\n\t\t\t\t\t\tif (!nextNames.has(name)) {\n\t\t\t\t\t\t\tthis.loop.tools.unregister(name);\n\t\t\t\t\t\t\tregistered.delete(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Register new (idempotent guard via local tracking).\n\t\t\t\t\tfor (const tool of next) {\n\t\t\t\t\t\tif (!registered.has(tool.name)) {\n\t\t\t\t\t\t\tthis.loop.tools.register(tool);\n\t\t\t\t\t\t\tregistered.add(tool.name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.addDisposer(unsubTools);\n\t\t}\n\n\t\t// --- 3. Optional shared memory subgraph (passed through). ----------\n\t\t// v1: memory is mounted but NOT yet wired into the loop's chat — the\n\t\t// chat-context-from-memory glue is a separate follow-up. Mounting it\n\t\t// here gives the bundle a stable surface for §29 handoff (callers\n\t\t// can pass the SAME instance to multiple agents for shared memory).\n\t\tthis.memory = spec.memory ?? null;\n\t\tif (this.memory != null) {\n\t\t\tthis.mount(\"memory\", this.memory);\n\t\t}\n\n\t\t// --- 4. `in` — the typed inbox. ------------------------------------\n\t\t// SENTINEL until first emit; `equals: () => false` so re-emitting the\n\t\t// same value still kicks (no spurious dedup of repeat inputs).\n\t\tthis.in = node<TIn>([], {\n\t\t\tname: \"in\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_in\"),\n\t\t\tequals: () => false,\n\t\t});\n\t\tthis.add(this.in, { name: \"in\" });\n\n\t\t// --- 5. `cost` — per-input token counters. -------------------------\n\t\tconst costNode = node<CostState>([], {\n\t\t\tname: \"cost\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_cost\"),\n\t\t\tinitial: ZERO_COST,\n\t\t});\n\t\tthis.add(costNode, { name: \"cost\" });\n\t\tthis.cost = costNode;\n\n\t\t// --- 6. `out` — the typed outbox. ----------------------------------\n\t\t// Derived from `loop.lastResponse`. SENTINEL while `loop.lastResponse`\n\t\t// has never emitted a real response (F9 fix: the loop now stays\n\t\t// SENTINEL too — no more eager `null` placeholder), so the SENTINEL\n\t\t// detector inside the fn is `prevData[0] === undefined`. Between\n\t\t// runs, `loop.lastResponse.down([[INVALIDATE]])` clears that\n\t\t// `prevData` slot back to undefined, so this derived correctly gates\n\t\t// to RESOLVED on the next status=\"idle\" wave.\n\t\tconst outMapper = spec.outMapper ?? defaultOutMapper<TOut>();\n\t\tconst outNode = node<TOut>(\n\t\t\t[this.loop.lastResponse],\n\t\t\t(data, a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst resp =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as LLMResponse | undefined)\n\t\t\t\t\t\t: (ctx.prevData[0] as LLMResponse | undefined);\n\t\t\t\tif (resp === undefined) {\n\t\t\t\t\ta.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ta.emit(outMapper(resp));\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"out\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_out\"),\n\t\t\t\t// Each in.emit may produce a structurally-equal response (e.g.\n\t\t\t\t// from a deterministic adapter) — disable framework dedup so\n\t\t\t\t// repeat emits propagate and `awaitSettled({skipCurrent:true})`\n\t\t\t\t// sees them. Callers can wrap with `distinctUntilChanged` if\n\t\t\t\t// they want change-only semantics.\n\t\t\t\tequals: () => false,\n\t\t\t},\n\t\t);\n\t\tthis.add(outNode, { name: \"out\" });\n\t\tthis.out = outNode;\n\n\t\t// --- 7. `status` — translated from loop.status. --------------------\n\t\t// Mirror via §32 pattern: a state node downstream consumers depend on,\n\t\t// reset and updated by an effect listening to loop.status.\n\t\tconst statusNode = node<AgentStatus>([], {\n\t\t\tname: \"status\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t\tinitial: \"idle\",\n\t\t});\n\t\tthis.add(statusNode, { name: \"status\" });\n\t\tthis.status = statusNode;\n\n\t\tconst statusMirrorEff = node(\n\t\t\t[this.loop.status],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst loopStatus =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as string)\n\t\t\t\t\t\t: ((ctx.prevData[0] as string | undefined) ?? \"idle\");\n\t\t\t\tconst next: AgentStatus =\n\t\t\t\t\tloopStatus === \"idle\"\n\t\t\t\t\t\t? \"idle\"\n\t\t\t\t\t\t: loopStatus === \"thinking\" || loopStatus === \"acting\"\n\t\t\t\t\t\t\t? \"running\"\n\t\t\t\t\t\t\t: loopStatus === \"done\"\n\t\t\t\t\t\t\t\t? \"done\"\n\t\t\t\t\t\t\t\t: loopStatus === \"error\"\n\t\t\t\t\t\t\t\t\t? \"error\"\n\t\t\t\t\t\t\t\t\t: \"idle\";\n\t\t\t\tif (statusNode.cache !== next) statusNode.emit(next);\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_status_mirror\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(statusMirrorEff));\n\n\t\t// --- 8. Cost-rollup effect. ---------------------------------------\n\t\t// Rolls forward on each loop.lastResponse emission. Reads\n\t\t// loop.turn.cache for the iteration count (sole-owner-reactive-reader\n\t\t// per Phase 12 D1 lock — loop is mounted as a subgraph of this Graph).\n\t\t// SENTINEL gate: `prevData[0] === undefined` means no response has\n\t\t// ever been delivered for this run (post-INVALIDATE reset between\n\t\t// runs), so the rollup short-circuits.\n\t\tconst costEff = node(\n\t\t\t[this.loop.lastResponse],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst resp =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as LLMResponse | undefined)\n\t\t\t\t\t\t: (ctx.prevData[0] as LLMResponse | undefined);\n\t\t\t\tif (resp === undefined) return;\n\t\t\t\tconst prev = (costNode.cache as CostState | undefined) ?? ZERO_COST;\n\t\t\t\tconst turns = (this.loop.turn.cache as number | undefined) ?? prev.turns;\n\t\t\t\tconst next: CostState = {\n\t\t\t\t\tusage: resp.usage != null ? addUsage(prev.usage, resp.usage) : prev.usage,\n\t\t\t\t\tturns,\n\t\t\t\t};\n\t\t\t\tcostNode.emit(next);\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_cost_rollup\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(costEff));\n\n\t\t// --- 9. `in` → input queue → drain → kick the loop. ----------------\n\t\t// Phase 13.G/H + /qa N1(b) lock (2026-05-01): bundle.in is a\n\t\t// writable surface, but kicks are queued through an internal\n\t\t// hub-style topic + cursor subscription. Out-of-the-box queueing —\n\t\t// caller fires `in.emit(x)` while the agent is mid-run; the input\n\t\t// is parked on the queue and picked up when the loop returns to\n\t\t// `idle` / `done` / `error`. No mid-run reset / cost-leak hazard\n\t\t// (which the prior raw `in.subscribe → kick` path had).\n\t\t//\n\t\t// Topology:\n\t\t// `in` (state Node, writable) → `inputBridge` (subscribe →\n\t\t// publish) → `inputTopic` (TopicGraph<TIn>) → `inputSub`\n\t\t// (SubscriptionGraph<TIn>) → `drainEffect` (effect on\n\t\t// [inputSub.available, loop.status]) → loop kick.\n\t\tconst inMapper = spec.inMapper ?? defaultInMapper<TIn>();\n\t\tconst inputTopic: TopicGraph<TIn> = topic<TIn>(\"input-topic\");\n\t\tthis.mount(\"input-topic\", inputTopic);\n\t\tconst inputSub: SubscriptionGraph<TIn> = subscription<TIn>(\"input-sub\", inputTopic, {\n\t\t\tfrom: \"now\",\n\t\t});\n\t\tthis.mount(\"input-sub\", inputSub);\n\n\t\t// Bridge: `in.emit(x)` publishes to the topic. Validates the\n\t\t// caller-supplied input via `inMapper` at the boundary so the\n\t\t// type error surfaces in the caller's stack frame (not later\n\t\t// during drain). Per the F9 SENTINEL trap, `in` cache is\n\t\t// `undefined` until the first emit; push-on-subscribe delivers\n\t\t// nothing.\n\t\tconst inputBridge = this.in.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst input = m[1] as TIn;\n\t\t\t\t// Boundary type-check: throws if TIn is not string and no\n\t\t\t\t// inMapper supplied. Better here than at drain time so the\n\t\t\t\t// caller's `in.emit(...)` raises synchronously.\n\t\t\t\tinMapper(input);\n\t\t\t\tinputTopic.publish(input);\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(inputBridge);\n\n\t\t// Drain effect: when an input is pending AND the loop is ready\n\t\t// (`idle` / `done` / `error`), pull one and kick. Re-entrancy\n\t\t// guard via `loop.status` — `thinking` / `acting` skip.\n\t\tconst drainEffect = node(\n\t\t\t[inputSub.available, this.loop.status],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst availBatch = data[0];\n\t\t\t\tconst statusBatch = data[1];\n\t\t\t\tconst avail =\n\t\t\t\t\t(availBatch != null && availBatch.length > 0\n\t\t\t\t\t\t? (availBatch.at(-1) as readonly TIn[])\n\t\t\t\t\t\t: ((ctx.prevData[0] as readonly TIn[] | undefined) ?? [])) ?? [];\n\t\t\t\tconst stat =\n\t\t\t\t\t(statusBatch != null && statusBatch.length > 0\n\t\t\t\t\t\t? (statusBatch.at(-1) as string)\n\t\t\t\t\t\t: ((ctx.prevData[1] as string | undefined) ?? \"idle\")) ?? \"idle\";\n\t\t\t\tif (avail.length === 0) return;\n\t\t\t\tif (stat === \"thinking\" || stat === \"acting\") return;\n\t\t\t\tconst result = inputSub.pullAndAck(1);\n\t\t\t\tif (result.items.length === 0) return;\n\t\t\t\tconst input = result.items[0] as TIn;\n\t\t\t\tconst userMsg = inMapper(input);\n\t\t\t\tbatch(() => {\n\t\t\t\t\t// Reset per-input accumulators so cost/turns don't include\n\t\t\t\t\t// the previous input. `lastResponse` is reset via plain\n\t\t\t\t\t// `[[INVALIDATE]]` — under DS-13.5.A INVALIDATE both clears\n\t\t\t\t\t// `_cached` AND settles the consuming wave (decrements\n\t\t\t\t\t// `_dirtyDepCount` like RESOLVED), so dependents like\n\t\t\t\t\t// `out` / `costEff` fire on the next status transition\n\t\t\t\t\t// without staying wedged in DIRTY. Pre-DS-13.5.A this used\n\t\t\t\t\t// the `[[INVALIDATE], [RESOLVED]]` paired-reset workaround.\n\t\t\t\t\tthis.loop.lastResponse.down([[INVALIDATE]]);\n\t\t\t\t\tthis.loop.turn.emit(0);\n\t\t\t\t\tthis.loop.aborted.emit(false);\n\t\t\t\t\tcostNode.emit(ZERO_COST);\n\t\t\t\t\tthis.loop.chat.append(\"user\", userMsg);\n\t\t\t\t\tthis.loop.status.emit(\"thinking\");\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_input_drain\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(drainEffect));\n\n\t\t// `out` and `status` keepalives are unnecessary because the cost /\n\t\t// status effects above already activate `loop.lastResponse` and\n\t\t// `loop.status` — the derived `out` reads from a kept-alive source.\n\t\t// We do keep `out` alive explicitly so `awaitSettled(bundle.out,\n\t\t// { skipCurrent: true })` works even when no other consumer\n\t\t// subscribes between input and response.\n\t\tthis.addDisposer(keepalive(this.out));\n\n\t\t// Surface in describe.\n\t\tvoid TERMINAL_STATUSES;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Default mappers\n// ---------------------------------------------------------------------------\n\n/**\n * Default `inMapper` for `TIn extends string`. Asserts the runtime type at\n * the boundary so callers who omit `inMapper` for a non-string `TIn` get a\n * clear error rather than a silent passthrough.\n */\nfunction defaultInMapper<TIn>(): (input: TIn) => string {\n\treturn (input) => {\n\t\tif (typeof input !== \"string\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`agent: inMapper is required when TIn is not a string (got ${typeof input}). Pass spec.inMapper.`,\n\t\t\t);\n\t\t}\n\t\treturn input;\n\t};\n}\n\n/**\n * Default `outMapper` for `TOut extends LLMResponse`. Asserts the response\n * shape at the boundary; callers with a non-LLMResponse `TOut` must\n * provide `outMapper`.\n */\nfunction defaultOutMapper<TOut>(): (response: LLMResponse) => TOut {\n\treturn (response) => response as unknown as TOut;\n}\n","/**\n * @internal — shared helpers for the AI pattern modules.\n *\n * NOT part of the public API. Consumers reach public symbols through\n * `@graphrefly/graphrefly/patterns/ai` (the barrel).\n *\n * @module\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n\tResettableTimer,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n} from \"./adapters/core/types.js\";\n\nexport function aiMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"ai\", kind, extra);\n}\n\nexport function isPromiseLike(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nexport function isNodeLike(x: unknown): x is Node<unknown> {\n\treturn (\n\t\ttypeof x === \"object\" &&\n\t\tx !== null &&\n\t\t\"subscribe\" in x &&\n\t\ttypeof (x as Node<unknown>).subscribe === \"function\" &&\n\t\t\"cache\" in x\n\t);\n}\n\nexport function isAsyncIterableLike(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\tSymbol.asyncIterator in x &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** First settled `DATA` from a `Node` (do not pass plain strings — `fromAny` would iterate chars). */\nexport function firstDataFromNode(\n\tresolved: Node<unknown>,\n\topts?: { timeoutMs?: number },\n): Promise<unknown> {\n\tif ((resolved as { status?: string }).status === \"settled\") {\n\t\tconst immediate = resolved.cache;\n\t\tif (immediate !== undefined) {\n\t\t\treturn Promise.resolve(immediate);\n\t\t}\n\t}\n\tconst timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tconst unsub = resolved.subscribe((messages) => {\n\t\t\tfor (const msg of messages) {\n\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\tresolve(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === ERROR) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === COMPLETE) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(new Error(\"firstDataFromNode: completed without producing a value\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttimer.start(timeoutMs, () => {\n\t\t\tunsub();\n\t\t\treject(new Error(`firstDataFromNode: timed out after ${timeoutMs}ms`));\n\t\t});\n\t});\n}\n\n/** Await Promise-likes, then resolve `Node` / async-iterable inputs via `fromAny` + first `DATA`. */\nexport async function resolveToolHandlerResult(value: unknown): Promise<unknown> {\n\tif (isPromiseLike(value)) {\n\t\treturn resolveToolHandlerResult(await value);\n\t}\n\tif (isNodeLike(value)) {\n\t\treturn firstDataFromNode(value);\n\t}\n\tif (isAsyncIterableLike(value)) {\n\t\treturn firstDataFromNode(fromAny(value as NodeInput<unknown>));\n\t}\n\treturn value;\n}\n\n/** Strip markdown code fences, handling trailing commentary after closing fence. */\nexport function stripFences(text: string): string {\n\tconst match = text.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```[\\s\\S]*$/);\n\treturn match ? match[1]! : text;\n}\n\n/**\n * Bridge-layer failure kind reported to {@link OneShotLlmCallConfig.onFailure}.\n *\n * - `\"throw\"` — synchronous throw from `adapter.invoke()`.\n * - `\"error\"` — `[ERROR, value]` message on the bridged Node.\n * - `\"complete\"` — the bridged Node closed without emitting DATA.\n * - `\"onSuccess-threw\"` — `onSuccess(resp)` itself threw (uncaught parse /\n * builder error). Caller's `onFailure` decides the failure-payload shape.\n */\nexport type OneShotLlmFailureKind = \"throw\" | \"error\" | \"complete\" | \"onSuccess-threw\";\n\n/** Configuration for {@link _oneShotLlmCall}. */\nexport interface OneShotLlmCallConfig<T> {\n\t/**\n\t * Build the success payload from the adapter's first DATA message.\n\t * MAY throw — the helper catches and routes through `onFailure(kind:\n\t * \"onSuccess-threw\", err)` so callers don't need their own try/catch.\n\t */\n\tonSuccess: (resp: LLMResponse) => T;\n\t/**\n\t * Build a failure payload when the bridge layer reports any of the\n\t * {@link OneShotLlmFailureKind} categories. Caller chooses the detail\n\t * string format and any error-class metadata.\n\t */\n\tonFailure: (kind: OneShotLlmFailureKind, err: unknown) => T;\n\t/**\n\t * Forwarded to `adapter.invoke(messages, opts)` — `signal` is set\n\t * by the helper from the producer's AbortController and CANNOT be\n\t * overridden here (cancellation is a hard contract of this helper).\n\t */\n\tinvokeOpts?: Omit<LLMInvokeOptions, \"signal\">;\n\t/**\n\t * Optional parent abort signal (e.g. JobFlow pump's per-claim signal).\n\t * When the parent aborts, the helper aborts its inner AbortController —\n\t * so `adapter.invoke({ signal })` and `fromAny({ signal })` see the\n\t * cascade and cancel in-flight work. Pump-driven harness teardown\n\t * (`harness.destroy()`) propagates through this hook (Tier 6.5 2.5b).\n\t */\n\tparentSignal?: AbortSignal;\n}\n\n/**\n * Internal — one-shot bridge from `adapter.invoke()` (a `NodeInput<LLMResponse>`)\n * into a producer that emits exactly one DATA + COMPLETE.\n *\n * **Why this exists.** The harness's `defaultLlmExecutor` and\n * `defaultLlmVerifier` (Tier 6.5 C2) both call `adapter.invoke()` once\n * per claimed JobFlow job and need to:\n * 1. Subscribe to the bridged Node, capture the first DATA, parse, emit\n * a domain payload.\n * 2. Map adapter throws / ERROR / COMPLETE-without-DATA to a domain\n * failure payload (rather than nack the JobFlow claim).\n * 3. Thread `signal: ac.signal` into BOTH `adapter.invoke()` (via\n * `LLMInvokeOptions.signal`) and `fromAny()` (covers Node-shaped\n * invokeResults) so teardown actually aborts in-flight HTTP work.\n * 4. Tear down the inner subscription cleanly when DATA captures or\n * when the producer is unsubscribed.\n *\n * Pre-extraction this body was duplicated ~80 LOC across the two default\n * bridges; symmetric fixes had to land twice (qa F1 / F2 / F5). This\n * helper centralizes the producer body so future bridge-layer fixes apply\n * once.\n *\n * **Not part of the public API.** Callers in `patterns/ai/_internal.ts`'s\n * import surface (the harness defaults today) use this; user code should\n * use `promptNode` for cross-wave reactive transforms or call\n * `adapter.invoke()` directly.\n */\nexport function _oneShotLlmCall<T>(\n\tadapter: LLMAdapter,\n\tmessages: readonly ChatMessage[],\n\tconfig: OneShotLlmCallConfig<T>,\n): NodeInput<T> {\n\treturn node<T>(\n\t\t(_data, actions) => {\n\t\t\tconst ac = new AbortController();\n\t\t\t// Link parent signal (e.g. pump per-claim signal) so cascading\n\t\t\t// teardown propagates: parent abort → inner ac.abort → adapter +\n\t\t\t// fromAny cancel.\n\t\t\tconst parentSignal = config.parentSignal;\n\t\t\tlet unlinkParent: () => void = () => undefined;\n\t\t\tif (parentSignal) {\n\t\t\t\tif (parentSignal.aborted) {\n\t\t\t\t\tac.abort();\n\t\t\t\t} else {\n\t\t\t\t\tconst onParentAbort = (): void => ac.abort();\n\t\t\t\t\tparentSignal.addEventListener(\"abort\", onParentAbort, { once: true });\n\t\t\t\t\tunlinkParent = () => parentSignal.removeEventListener(\"abort\", onParentAbort);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet captured = false;\n\t\t\tlet unsub: (() => void) | null = null;\n\t\t\tconst emitOnce = (value: T): void => {\n\t\t\t\tif (captured) return;\n\t\t\t\tcaptured = true;\n\t\t\t\tactions.down([[DATA, value], [COMPLETE]] satisfies Messages);\n\t\t\t\tunsub?.();\n\t\t\t\tunsub = null;\n\t\t\t};\n\t\t\tlet invokeResult: NodeInput<LLMResponse>;\n\t\t\ttry {\n\t\t\t\tinvokeResult = adapter.invoke(messages, { ...config.invokeOpts, signal: ac.signal });\n\t\t\t} catch (err) {\n\t\t\t\temitOnce(config.onFailure(\"throw\", err));\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tunlinkParent();\n\t\t\t\t\t\tac.abort();\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst callNode = fromAny<LLMResponse>(invokeResult, { signal: ac.signal });\n\t\t\tunsub = callNode.subscribe((batch) => {\n\t\t\t\tfor (const m of batch) {\n\t\t\t\t\tif (captured) return;\n\t\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\temitOnce(config.onSuccess(m[1] as LLMResponse));\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\temitOnce(config.onFailure(\"onSuccess-threw\", err));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\t\temitOnce(config.onFailure(\"error\", m[1]));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t\t// COMPLETE without prior DATA — without this arm the JobFlow\n\t\t\t\t\t\t// pump's claim would stall (qa F1 regression). Helper handles\n\t\t\t\t\t\t// for ALL callers; defaults can't regress.\n\t\t\t\t\t\temitOnce(config.onFailure(\"complete\", undefined));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t// Sync DATA delivery (cached state / `fromAny` over a sync value):\n\t\t\t// the callback ran reentrantly before `unsub` was assigned, so the\n\t\t\t// `unsub?.()` call inside `emitOnce` was a no-op. Drop the upstream\n\t\t\t// subscription now that we have the handle.\n\t\t\tif (captured && unsub) {\n\t\t\t\tunsub();\n\t\t\t\tunsub = null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tunlinkParent();\n\t\t\t\t\tac.abort();\n\t\t\t\t\tunsub?.();\n\t\t\t\t\tunsub = null;\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{ describeKind: \"producer\" },\n\t);\n}\n","/**\n * Metadata helpers for pattern-layer nodes (Tier 2.2 promotion from\n * `patterns/_internal/`).\n *\n * Each domain (orchestration, messaging, reduction, ai, cqrs, domain_template,\n * memory, lens, audit, harness) shares the same metadata convention. Promoted\n * to `extra/` so non-patterns code (and downstream consumers building their\n * own domain primitives) can use the same shape.\n *\n * @module\n */\n\n/**\n * Build a domain metadata object for pattern-layer nodes.\n *\n * Each domain follows the same shape: `{ [domain]: true, [domain]_type: kind, ...extra }`.\n *\n * @param domain - The domain tag (e.g. `\"orchestration\"`, `\"ai\"`, `\"cqrs\"`).\n * @param kind - The specific type within the domain (e.g. `\"gate\"`, `\"prompt\"`).\n * @param extra - Additional metadata to merge.\n * @returns Metadata object.\n */\nexport function domainMeta(\n\tdomain: string,\n\tkind: string,\n\textra?: Record<string, unknown>,\n): Record<string, unknown> {\n\treturn {\n\t\t[domain]: true,\n\t\t[`${domain}_type`]: kind,\n\t\t...(extra ?? {}),\n\t};\n}\n","/**\n * Messaging patterns (roadmap §4.2).\n *\n * Pulsar-inspired messaging primitives modeled as graph factories:\n * - `topic()` for append-only topic streams with a retained window.\n * - `subscription()` for cursor-based consumers.\n * - `topicBridge()` for autonomous topic-to-topic relay.\n * - `messagingHub()` for a lazy topic registry.\n *\n * Plus the Phase 13.B standard `Message<T>` envelope and well-known topic\n * name constants ({@link PROMPTS_TOPIC} / {@link RESPONSES_TOPIC} /\n * {@link INJECTIONS_TOPIC} / {@link DEFERRED_TOPIC} / {@link SPAWNS_TOPIC})\n * — recommended (not enforced) wire shape for cross-graph topic payloads.\n *\n * Job queue / job flow primitives live in `patterns/job-queue` — they are a\n * distinct domain that happens to share reactive-log / reactive-map\n * infrastructure with topics.\n */\n\nexport {\n\ttype HubRemoveTopicRecord,\n\thubRemoveTopicKeyOf,\n\ttype MessagingAuditRecord,\n\ttype SubscriptionAckRecord,\n\ttype SubscriptionPullAndAckRecord,\n\tsubscriptionAckKeyOf,\n\tsubscriptionPullAndAckKeyOf,\n\ttype TopicPublishRecord,\n\ttopicPublishKeyOf,\n} from \"./audit-records.js\";\nexport {\n\tCONTEXT_TOPIC,\n\tDEFERRED_TOPIC,\n\tINJECTIONS_TOPIC,\n\ttype JsonSchema,\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tSPAWNS_TOPIC,\n\tSTANDARD_TOPICS,\n\ttype StandardTopic,\n\tTODOS_TOPIC,\n\ttype TopicMessage,\n} from \"./message.js\";\n\nimport { batch, COMPLETE, DATA, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { mutate } from \"../../base/mutation/index.js\";\n\nconst DEFAULT_MAX_PER_PUMP = 256;\n\nfunction requireNonNegativeInt(value: number, label: string): number {\n\tif (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative integer`);\n\t}\n\treturn value;\n}\n\nfunction messagingMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"messaging\", kind, extra);\n}\n\nexport type TopicOptions = {\n\tgraph?: GraphOptions;\n\t/** Bounded retention; default 1024 per cross-cutting policy (Audit 2/4). */\n\tretainedLimit?: number;\n};\n\nconst DEFAULT_TOPIC_RETAINED_LIMIT = 1024;\n\nexport class TopicGraph<T> extends Graph {\n\tprivate readonly _log;\n\tprivate readonly _publishImpl: (value: T) => void;\n\treadonly events: Node<readonly T[]>;\n\t/**\n\t * Most recently published value. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first publish, then\n\t * tracks the latest entry. Spec §5.12 reserves `undefined` as the\n\t * \"never sent DATA\" sentinel — and `TopicGraph.publish(undefined)` is\n\t * rejected — so `cache === undefined` unambiguously signals \"empty topic\"\n\t * even when `T` itself includes `null` (i.e., `topic<number | null>`).\n\t *\n\t * **Within a reactive fn:** detect the empty-topic case via\n\t * `ctx.prevData[i] === undefined` for the dep slot holding `topic.latest`,\n\t * or check `latest.cache === undefined` outside reactive code. No\n\t * separate `hasLatest` companion needed — the SENTINEL is the answer.\n\t */\n\treadonly latest: Node<T>;\n\n\tconstructor(name: string, opts: TopicOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis._log = reactiveLog<T>([], {\n\t\t\tname: \"events\",\n\t\t\tmaxSize: opts.retainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.events = this._log.entries;\n\t\tthis.add(this.events, { name: \"events\" });\n\t\t// `this.derived(\"latest\", [\"events\"], …)` is expressible after the\n\t\t// 2026-04-30 self-resolve fix in `Graph._resolveFromSegments` — a\n\t\t// single-segment path matching the graph's own name (e.g.\n\t\t// `topic(\"events\").resolve(\"events\")`) no longer collapses to empty\n\t\t// and falls through to local-node lookup. Replaces the prior\n\t\t// `node([events], …) + this.add(...)` workaround.\n\t\t//\n\t\t// SENTINEL on empty: returning `[]` here yields a RESOLVED-only wave\n\t\t// (no DATA), so `latest.cache` stays `undefined` until the first\n\t\t// publish. `TopicGraph.publish(undefined)` is rejected (line below),\n\t\t// so `undefined` cache is unambiguously \"empty topic\" even when `T`\n\t\t// itself includes `null`. Drops the prior `hasLatest` companion as\n\t\t// redundant.\n\t\tthis.latest = this.derived<T>(\n\t\t\t\"latest\",\n\t\t\t[\"events\"],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly T[];\n\t\t\t\treturn entries.length === 0 ? [] : [entries[entries.length - 1] as T];\n\t\t\t},\n\t\t\t{ meta: messagingMeta(\"topic_latest\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\t// D1(a): on teardown, propagate COMPLETE on `events` so downstream\n\t\t// derived chains (including any externally-held SubscriptionGraph\n\t\t// sources) see the termination via their `terminalDeps` and can stop\n\t\t// serving stale caches. Tier-3 terminal per spec §2.2.\n\t\t//\n\t\t// EC16 (verified 2026-04-30): the COMPLETE-then-disposeAllViews order\n\t\t// is intentional. COMPLETE propagates SYNCHRONOUSLY through every\n\t\t// subscriber (cursor views, derived chains) so they self-unsubscribe\n\t\t// in their terminal handler before `disposeAllViews` runs. Swapping\n\t\t// the order would clear view caches before subscribers receive the\n\t\t// terminal — strictly worse. Reading `.cache` outside a reactive fn\n\t\t// across teardown is an anti-pattern (spec §5.12) and not a use case\n\t\t// this ordering needs to preserve.\n\t\tthis.addDisposer(() => {\n\t\t\tthis.events.down([[COMPLETE]]);\n\t\t});\n\t\t// P9: release any memoized tail/slice view keepalives held by the log.\n\t\t// TopicGraph itself doesn't call log.tail/slice, but plugins may have\n\t\t// attached views via `_log` — defensive (typical reactive subscribers\n\t\t// have already unsubscribed in their COMPLETE handler above).\n\t\tthis.addDisposer(() => this._log.disposeAllViews());\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route publish through `mutate`\n\t\t// for centralized freeze + re-throw semantics. No audit log surface\n\t\t// (per Tier 8 γ-0): the topic's `events` log already records every\n\t\t// successful publish, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because topic payloads can be large and per-publish\n\t\t// cost matters on hot paths.\n\t\tthis._publishImpl = mutate<[T], void, never>(\n\t\t\t(value): void => {\n\t\t\t\tthis._log.append(value);\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tpublish(value: T): void {\n\t\t// SENTINEL alignment (Wave B.1 Unit 11 lock): `undefined` is the\n\t\t// protocol-level \"never sent DATA\" sentinel — refusing it here\n\t\t// preserves `lastValue: Node<T | undefined>` semantics.\n\t\tif (value === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`TopicGraph \"${this.name}\": publish(undefined) is not allowed (spec §5.12 SENTINEL).`,\n\t\t\t);\n\t\t}\n\t\tthis._publishImpl(value);\n\t}\n\n\t/**\n\t * Wire one or more append-log storage tiers (Audit 4). Each tier receives\n\t * appended events per wave; rollback honors the wave-as-transaction model.\n\t *\n\t * Named `attachEventStorage` (not `attachStorage`) to avoid colliding with\n\t * the inherited {@link Graph.attachSnapshotStorage} which takes the\n\t * paired `AttachSnapshotTierPair[]` shape (Phase 14.6) — distinct\n\t * concerns, distinct surfaces.\n\t *\n\t * @returns Disposer.\n\t */\n\tattachEventStorage(\n\t\ttiers: readonly import(\"@graphrefly/pure-ts/extra\").AppendLogStorageTier<T>[],\n\t): () => void {\n\t\treturn this._log.attachStorage(tiers);\n\t}\n\n\tretained(): readonly T[] {\n\t\treturn this.events.cache as readonly T[];\n\t}\n\n\t/** Internal log bundle — used by TopicBridgeGraph for `attach`. */\n\tget _logBundle() {\n\t\treturn this._log;\n\t}\n}\n\nexport type SubscriptionOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Starting cursor position.\n\t * @deprecated Use `from` instead.\n\t */\n\tcursor?: number;\n\t/**\n\t * Starting position for the subscription.\n\t * - `\"retained\"` (default) — cursor starts at 0; consumer sees all retained history.\n\t * - `\"now\"` — cursor starts at current topic length; consumer ignores history.\n\t * - `number` — explicit cursor position.\n\t */\n\tfrom?: \"now\" | \"retained\" | number;\n\t/**\n\t * When this signal node emits DATA, the subscription auto-advances cursor\n\t * to current `available.length`. Useful for \"ack everything when X happens\"\n\t * patterns. The reactive edge `advanceOn → cursor` is visible in `explain()`.\n\t */\n\tadvanceOn?: Node<unknown>;\n};\n\n/** Result of {@link SubscriptionGraph.pullAndAck}. */\nexport type PullAndAckResult<T> = {\n\titems: readonly T[];\n\tcursor: number;\n};\n\nexport class SubscriptionGraph<T> extends Graph {\n\treadonly cursor: Node<number>;\n\treadonly available: Node<readonly T[]>;\n\t/**\n\t * Reference to the upstream topic graph. Intentionally NOT mounted\n\t * under this subscription: a subscription is a VIEW over an\n\t * externally-owned topic. Double-mounting (e.g. hub-owned topic +\n\t * sub-mount here) would make either-side teardown leave the other\n\t * holding a dead reference. Node-level `derived([topicEvents], …)`\n\t * still wires the data dependency across graph boundaries. D1(e).\n\t */\n\treadonly topic: TopicGraph<T>;\n\n\tprivate _disposed = false;\n\tprivate readonly _ackImpl: (count: number | undefined) => number;\n\tprivate readonly _pullAndAckImpl: (limit: number | undefined) => PullAndAckResult<T>;\n\n\tconstructor(name: string, topicGraph: TopicGraph<T>, opts: SubscriptionOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis.topic = topicGraph;\n\n\t\t// Resolve initial cursor from `from` option, falling back to legacy `cursor` option.\n\t\tlet initialCursor: number;\n\t\tif (opts.from !== undefined) {\n\t\t\tif (opts.from === \"retained\") {\n\t\t\t\tinitialCursor = 0;\n\t\t\t} else if (opts.from === \"now\") {\n\t\t\t\t// §28 sanctioned factory-time boundary read.\n\t\t\t\tinitialCursor = (topicGraph.events.cache as readonly T[]).length;\n\t\t\t} else {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"subscription from\");\n\t\t\t}\n\t\t} else {\n\t\t\tinitialCursor = requireNonNegativeInt(opts.cursor ?? 0, \"subscription cursor\");\n\t\t}\n\n\t\tthis.cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\tmeta: messagingMeta(\"subscription_cursor\"),\n\t\t});\n\n\t\t// B.1 Unit 12 lock: `available` depends directly on topic.events + cursor\n\t\t// via `view({ kind: \"fromCursor\" })`. No `source` passthrough node —\n\t\t// describe shows `topic::events → available` (cross-graph edge) and\n\t\t// `cursor → available` (local edge). One fewer node per subscription.\n\t\tthis.available = topicGraph._logBundle.view({ kind: \"fromCursor\", cursor: this.cursor });\n\t\tthis.add(this.available, { name: \"available\" });\n\t\tthis.addDisposer(keepalive(this.available));\n\n\t\t// Optional reactive auto-advance: when `advanceOn` emits a NEW DATA\n\t\t// (after construction), cursor advances by `available.length` atomically.\n\t\t// Edge visible in describe: advancePump depends on advanceOn.\n\t\t// `_advanceInitialized` guards against the initial push-on-subscribe fire\n\t\t// that would advance cursor before the user has a chance to read.\n\t\tif (opts.advanceOn !== undefined) {\n\t\t\tconst advanceOn = opts.advanceOn;\n\t\t\tlet advanceInitialized = false;\n\t\t\tconst advancePump = node<unknown>(\n\t\t\t\t[advanceOn],\n\t\t\t\t() => {\n\t\t\t\t\t// Skip the initial push-on-subscribe wave.\n\t\t\t\t\tif (!advanceInitialized) {\n\t\t\t\t\t\tadvanceInitialized = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._disposed) return;\n\t\t\t\t\tconst avail = this.available.cache as readonly T[];\n\t\t\t\t\tif (avail.length === 0) return;\n\t\t\t\t\tconst next = (this.cursor.cache as number) + avail.length;\n\t\t\t\t\tthis.cursor.emit(next);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"advancePump\",\n\t\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\t\tmeta: messagingMeta(\"subscription_advance_pump\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(advancePump, { name: \"advancePump\" });\n\t\t\tthis.addDisposer(keepalive(advancePump));\n\t\t}\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route ack + pullAndAck through\n\t\t// `mutate` for centralized freeze + re-throw semantics. No audit\n\t\t// log surface (per Tier 8 γ-0): the cursor's own emission stream already\n\t\t// records every advance, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because count/limit are simple numbers; freezing is\n\t\t// pointless overhead. Disposed-checks stay outside the wrapper so a\n\t\t// no-op call doesn't unnecessarily run the wrapper.\n\t\tthis._ackImpl = mutate<[number | undefined], number, never>(\n\t\t\t(count): number => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst requested =\n\t\t\t\t\tcount === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(count, \"subscription ack count\");\n\t\t\t\tconst step = Math.min(requested, available.length);\n\t\t\t\tif (step <= 0) return this.cursor.cache as number;\n\t\t\t\tconst next = (this.cursor.cache as number) + step;\n\t\t\t\t// F8: use emit() so the pipeline auto-prefixes DIRTY, runs equals\n\t\t\t\t// substitution, and produces a proper two-phase wave (the raw\n\t\t\t\t// `down([[DATA, next]])` path bypassed those contracts).\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn next;\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\n\t\tthis._pullAndAckImpl = mutate<[number | undefined], PullAndAckResult<T>, never>(\n\t\t\t(limit): PullAndAckResult<T> => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst max =\n\t\t\t\t\tlimit === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(limit, \"subscription pullAndAck limit\");\n\t\t\t\tconst items = available.slice(0, max);\n\t\t\t\tif (items.length === 0) return { items, cursor: this.cursor.cache as number };\n\t\t\t\tconst next = (this.cursor.cache as number) + items.length;\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn { items, cursor: next };\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tack(count?: number): number {\n\t\tif (this._disposed) return this.cursor.cache as number;\n\t\treturn this._ackImpl(count);\n\t}\n\n\tpull(limit?: number): readonly T[] {\n\t\tif (this._disposed) return [];\n\t\tconst available = this.available.cache as readonly T[];\n\t\tconst max =\n\t\t\tlimit === undefined\n\t\t\t\t? available.length\n\t\t\t\t: requireNonNegativeInt(limit, \"subscription pull limit\");\n\t\treturn available.slice(0, max);\n\t}\n\n\t/**\n\t * Atomic pull-and-acknowledge. Returns `{ items, cursor }` where `cursor`\n\t * is the new cursor position after advancing. Under single-threaded JS the\n\t * snapshot and advance are atomic; PY callers use a per-subscription Lock.\n\t *\n\t * Replaces `pull(limit, { ack: true })`.\n\t */\n\tpullAndAck(limit?: number): PullAndAckResult<T> {\n\t\tif (this._disposed) return { items: [], cursor: this.cursor.cache as number };\n\t\treturn this._pullAndAckImpl(limit);\n\t}\n\n\t/**\n\t * Release internal subscriptions and mark the subscription torn-down.\n\t * Subsequent `pull`, `pullAndAck`, `ack` return empty / current cursor.\n\t * Emits COMPLETE on `cursor` so derived consumers (e.g. `available`) see\n\t * the termination signal. Also drains `addDisposer` callbacks (including\n\t * the `keepalive(advancePump)` subscription) so no keepalive leak occurs.\n\t */\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\t\tthis._disposed = true;\n\t\tthis.cursor.down([[COMPLETE]]);\n\t\t// m4: drain addDisposer callbacks to release the keepalive subscription.\n\t\tthis.destroy();\n\t}\n}\n\nexport type TopicBridgeOptions<TIn, TOut> = {\n\tgraph?: GraphOptions;\n\tcursor?: number;\n\tmaxPerPump?: number;\n\t/**\n\t * Optional transform/filter applied to each item before republishing.\n\t *\n\t * **At-most-once with silent drop:** when `map` returns `undefined`, the\n\t * input is consumed from the source cursor but NOT republished. Filtered\n\t * items are not retained for retry. If you need filter-with-retry\n\t * semantics, do the filtering in a downstream subscription on the bridged\n\t * output rather than in the `map` function.\n\t */\n\tmap?: (value: TIn) => TOut | undefined;\n};\n\nexport class TopicBridgeGraph<TIn, TOut = TIn> extends Graph {\n\tprivate readonly _sourceSub;\n\treadonly bridgedCount: Node<number>;\n\t/**\n\t * Emits each mapped batch as DATA — gives downstream observers a reactive\n\t * stream of bridged values. Also the link target for `target._log.attach`.\n\t */\n\treadonly output: Node<readonly TOut[]>;\n\n\tconstructor(\n\t\tname: string,\n\t\tsourceTopic: TopicGraph<TIn>,\n\t\ttargetTopic: TopicGraph<TOut>,\n\t\topts: TopicBridgeOptions<TIn, TOut> = {},\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tthis._sourceSub = subscription<TIn>(`${name}-subscription`, sourceTopic, {\n\t\t\tcursor: opts.cursor,\n\t\t});\n\t\tthis.mount(\"subscription\", this._sourceSub);\n\n\t\tconst maxPerPump = Math.max(\n\t\t\t1,\n\t\t\trequireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, \"topic bridge maxPerPump\"),\n\t\t);\n\t\tconst mapValue = opts.map ?? ((value: TIn) => value as unknown as TOut);\n\n\t\t// Reactive output node: derives a mapped batch from `available`.\n\t\t// §24 compliant — output is a real derived edge, visible in describe.\n\t\t// Replaces imperative publish loop. Items where mapValue returns undefined\n\t\t// are filtered out (opt-out / filter).\n\t\tthis.output = node<readonly TOut[]>(\n\t\t\t[this._sourceSub.available],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst arr = data[0] as readonly TIn[];\n\t\t\t\tconst outBatch: TOut[] = [];\n\t\t\t\tconst take = Math.min(arr.length, maxPerPump);\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tconst mapped = mapValue(arr[i] as TIn);\n\t\t\t\t\tif (mapped !== undefined) outBatch.push(mapped);\n\t\t\t\t}\n\t\t\t\tactions.emit(outBatch);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"output\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_output\", { targetRef: targetTopic.name }),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.addDisposer(keepalive(this.output));\n\n\t\t// bridgedCount: state node accumulating total bridged items.\n\t\t// Updated by ackPump after each batch — edge visible via ackPump dep on output.\n\t\tthis.bridgedCount = this.state<number>(\"bridgedCount\", 0, {\n\t\t\tmeta: messagingMeta(\"topic_bridge_count\"),\n\t\t});\n\t\tthis.addDisposer(keepalive(this.bridgedCount));\n\n\t\t// ackPump: effect that advances the subscription cursor and updates\n\t\t// bridgedCount after each batch. Runs after `output` settles.\n\t\t// Captures refs to `this.output`, `this._sourceSub`, `this.bridgedCount`\n\t\t// to avoid `this` inside the fn body.\n\t\tconst outputRef = this.output;\n\t\tconst subRef = this._sourceSub;\n\t\tconst countRef = this.bridgedCount;\n\t\tconst ackPump = this.effect(\n\t\t\t\"ackPump\",\n\t\t\t[\"output\"],\n\t\t\t() => {\n\t\t\t\tconst outBatch = outputRef.cache as readonly TOut[];\n\t\t\t\tif (outBatch.length === 0) return;\n\t\t\t\tconst availLen = (subRef.available.cache as readonly TIn[]).length;\n\t\t\t\tconst toAck = Math.min(availLen, maxPerPump);\n\t\t\t\tif (toAck > 0) {\n\t\t\t\t\tsubRef.ack(toAck);\n\t\t\t\t\tconst prev = (countRef.cache as number) ?? 0;\n\t\t\t\t\tcountRef.emit(prev + outBatch.length);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_ack_pump\"),\n\t\t\t},\n\t\t);\n\t\tthis.addDisposer(keepalive(ackPump));\n\n\t\t// Wire output into target topic's log reactively.\n\t\t// _attachArrayToLog subscribes to output and publishes each item to targetTopic.\n\t\t// Teardown: disposer runs before mount teardown.\n\t\tconst detach = _attachArrayToLog(this.output, targetTopic);\n\t\tthis.addDisposer(detach);\n\t}\n}\n\n/**\n * Attaches each element of an array-valued Node to a TopicGraph's log.\n * Every DATA emission on `source` appends all items in the array to `targetTopic`.\n * Returns a disposer.\n */\nfunction _attachArrayToLog<T>(source: Node<readonly T[]>, targetTopic: TopicGraph<T>): () => void {\n\treturn source.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst arr = m[1] as readonly T[];\n\t\t\tif (arr.length === 0) continue;\n\t\t\tbatch(() => {\n\t\t\t\tfor (const v of arr) targetTopic.publish(v);\n\t\t\t});\n\t\t}\n\t});\n}\n\n// ── TopicRegistry ─────────────────────────────────────────────────────────\n\n/**\n * Private pure data structure managing a named set of {@link TopicGraph}\n * instances. Extracted from {@link MessagingHubGraph} for separation of\n * concerns (B.2 Unit 14 lock: D — split into TopicRegistry + facade).\n *\n * Reusable if other domain consumers (e.g. cqrs.eventLogs) want a shared\n * topic registry later.\n *\n * @internal\n */\nexport class TopicRegistry {\n\tprivate readonly _map = new Map<string, TopicGraph<unknown>>();\n\t/** Reactive monotonic version counter. Advances on topic create/remove. */\n\treadonly version: Node<number>;\n\n\tconstructor(versionNode: Node<number>) {\n\t\tthis.version = versionNode;\n\t}\n\n\tget size(): number {\n\t\treturn this._map.size;\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this._map.has(name);\n\t}\n\n\tget<T>(name: string): TopicGraph<T> | undefined {\n\t\treturn this._map.get(name) as TopicGraph<T> | undefined;\n\t}\n\n\tset<T>(name: string, t: TopicGraph<T>): void {\n\t\tthis._map.set(name, t as TopicGraph<unknown>);\n\t}\n\n\tdelete(name: string): boolean {\n\t\treturn this._map.delete(name);\n\t}\n\n\tkeys(): IterableIterator<string> {\n\t\treturn this._map.keys();\n\t}\n}\n\n// ── MessagingHubGraph ─────────────────────────────────────────────────────\n\nexport type MessagingHubOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Default `TopicOptions` applied to every topic created via `topic(name)`\n\t * without explicit options. Per-call opts override. Default: `{}`\n\t * (unbounded retention per topic unless `retainedLimit` is set per call).\n\t */\n\tdefaultTopicOptions?: TopicOptions;\n};\n\n/**\n * Lazy Pulsar-inspired topic registry. Manages a named set of {@link TopicGraph}\n * instances with retention + cursor semantics. Topics are created on first\n * access; `removeTopic(name)` unmounts and tears down via {@link Graph.remove}.\n *\n * Internally delegates to {@link TopicRegistry} for topic map management\n * (B.2 Unit 14 lock: D facade split).\n *\n * **Relationship to `pubsub()` in `src/extra/pubsub.ts`:** `pubsub` is a\n * lightweight last-value state hub (no retention, no cursors). `MessagingHubGraph`\n * is the full messaging hub — retained message logs, cursor-based subscriptions,\n * and pattern-layer lifecycle management.\n *\n * @category patterns\n */\nexport class MessagingHubGraph extends Graph {\n\tprivate readonly _registry: TopicRegistry;\n\t/** Reactive monotonic version counter — advances on topic create/remove. */\n\treadonly version: Node<number>;\n\tprivate readonly _defaultTopicOptions: TopicOptions;\n\tprivate readonly _removeTopicImpl: (name: string) => void;\n\n\tconstructor(name: string, opts: MessagingHubOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\t// B.2 Unit 14 lock: promote _version → version: Node<number>.\n\t\tconst versionNode = this.state<number>(\"version\", 0, {\n\t\t\tmeta: messagingMeta(\"hub_version\"),\n\t\t});\n\t\tthis.version = versionNode;\n\t\tthis._registry = new TopicRegistry(versionNode);\n\t\t// P8: shallow-copy caller-provided defaults so post-construction\n\t\t// mutations by the caller don't leak into every future `topic()` call.\n\t\tthis._defaultTopicOptions = { ...(opts.defaultTopicOptions ?? {}) };\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route the registry-delete branch of\n\t\t// `removeTopic` through `mutate` for centralized re-throw\n\t\t// semantics. No audit log surface (per Tier 8 γ-0).\n\t\t// `freeze: false` because the only arg is a string name (freeze pointless).\n\t\t// **Closure-state caveat (γ-4):** the inner `try/finally` mutates\n\t\t// `_registry` (a `Map`) and emits the version bump. mutate has no\n\t\t// `batch()` frame, so reactive emissions are NOT rolled back on throw —\n\t\t// and even if it did, `Map.delete` on closure state is invisible to the\n\t\t// batch and can't be unwound. The pre-existing try/finally on\n\t\t// `Graph.remove` is what guarantees registry/version converge to a\n\t\t// consistent state when `remove()` throws; `mutate` adds nothing\n\t\t// to that contract beyond the re-throw.\n\t\tthis._removeTopicImpl = mutate<[string], void, never>(\n\t\t\t(topicName): void => {\n\t\t\t\ttry {\n\t\t\t\t\tthis.remove(topicName); // unmounts, drops edges, tears down\n\t\t\t\t} finally {\n\t\t\t\t\tthis._registry.delete(topicName);\n\t\t\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\t\t\tthis.version.emit(cur + 1);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\t/** Number of topics currently in the hub. */\n\tget size(): number {\n\t\treturn this._registry.size;\n\t}\n\n\t/** Checks topic existence without creating. */\n\thas(name: string): boolean {\n\t\treturn this._registry.has(name);\n\t}\n\n\t/** Iterator over topic names. */\n\ttopicNames(): IterableIterator<string> {\n\t\treturn this._registry.keys();\n\t}\n\n\t/**\n\t * Returns the {@link TopicGraph} for `name`, creating lazily on first call.\n\t * Subsequent calls with the same name return the same instance (options on\n\t * repeat calls are ignored — the topic is already configured).\n\t */\n\ttopic<T = unknown>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\t\tlet t = this._registry.get<T>(name);\n\t\tif (t === undefined) {\n\t\t\tconst effective: TopicOptions = { ...this._defaultTopicOptions, ...(opts ?? {}) };\n\t\t\tt = new TopicGraph<T>(name, effective);\n\t\t\tthis._registry.set(name, t);\n\t\t\tthis.mount(name, t);\n\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\tthis.version.emit(cur + 1);\n\t\t}\n\t\treturn t;\n\t}\n\n\t/**\n\t * Publishes a value to the topic, lazily creating it on first publish.\n\t *\n\t * **Late-subscriber caveat:** the topic is created lazily, so subscribers\n\t * that attach AFTER a publish only see the retained window (governed by\n\t * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If\n\t * `retainedLimit === 0` is set explicitly, early publishes are\n\t * effectively dropped — prefer an unset `retainedLimit` (unbounded\n\t * retention) or subscribe before publishing when late-subscribers matter.\n\t */\n\tpublish<T = unknown>(name: string, value: T): void {\n\t\tthis.topic<T>(name).publish(value);\n\t}\n\n\t/**\n\t * Bulk publish — issues all publishes inside one outer batch. New topics\n\t * are created on demand. No-op if `entries` yields nothing.\n\t *\n\t * **Iterable consumption (F6):** `entries` is consumed once (single-pass)\n\t * INSIDE the batch frame. If the iterator throws mid-way, the batch is\n\t * discarded and NO publishes are visible to subscribers (all-or-nothing).\n\t * Pass an array or `Set` for multi-shot callers.\n\t */\n\tpublishMany(entries: Iterable<[string, unknown]>): void {\n\t\t// P2: iterate inside batch — no `[...entries]` materialization so large\n\t\t// / infinite iterables don't OOM, and iterator throws are contained.\n\t\tbatch(() => {\n\t\t\tfor (const [name, value] of entries) {\n\t\t\t\tthis.topic(name).publish(value);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Creates a {@link SubscriptionGraph} over a named topic. The topic is\n\t * lazily created if missing. Subscription lifecycle is owned by the caller —\n\t * the hub does NOT mount the subscription.\n\t *\n\t * @param subName - Local name for the subscription graph.\n\t * @param topicName - Hub topic to subscribe to.\n\t * @param opts - `SubscriptionOptions` (initial cursor, etc.).\n\t */\n\tsubscribe<T = unknown>(\n\t\tsubName: string,\n\t\ttopicName: string,\n\t\topts?: SubscriptionOptions,\n\t): SubscriptionGraph<T> {\n\t\tconst t = this.topic<T>(topicName);\n\t\treturn new SubscriptionGraph<T>(subName, t, opts);\n\t}\n\n\t/**\n\t * Unmounts and tears down the topic's graph. Returns `true` if the topic\n\t * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.\n\t *\n\t * **Closure-state caveat:** the registry mutation (`_registry.delete`) and\n\t * version bump happen in a `try/finally`, so registry/version converge to\n\t * a consistent state even when {@link Graph.remove} throws. `mutate`\n\t * does not roll back this mutation on throw — `Map.delete` on closure\n\t * state is invisible to any batch frame. The pre-existing try/finally is\n\t * load-bearing for that invariant.\n\t */\n\tremoveTopic(name: string): boolean {\n\t\tif (!this._registry.has(name)) return false;\n\t\t// P1 / P3: Graph.remove first — if it throws, `_registry` must NOT still\n\t\t// hold the broken half-disposed topic (otherwise the next\n\t\t// `hub.topic(name)` returns the corrupted reference). The `try/finally`\n\t\t// inside `_removeTopicImpl`'s action body preserves that invariant.\n\t\tthis._removeTopicImpl(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * Creates a Pulsar-inspired topic graph (append-only retained stream + latest value).\n */\nexport function topic<T>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\treturn new TopicGraph<T>(name, opts);\n}\n\n/**\n * Creates a lazy Pulsar-inspired messaging hub. Topics are created on first access\n * via `hub.topic(name)`; `hub.publish(name, value)` shortcuts through the registry.\n *\n * @example\n * ```ts\n * import { messagingHub } from \"@graphrefly/graphrefly/patterns/messaging\";\n *\n * const hub = messagingHub(\"main\", { defaultTopicOptions: { retainedLimit: 256 } });\n * hub.publish(\"orders\", { id: 1 });\n * hub.publishMany([[\"shipments\", { id: 1 }], [\"orders\", { id: 2 }]]);\n * const sub = hub.subscribe(\"orders-worker\", \"orders\", { cursor: 0 });\n * ```\n */\nexport function messagingHub(name: string, opts?: MessagingHubOptions): MessagingHubGraph {\n\treturn new MessagingHubGraph(name, opts);\n}\n\n/**\n * Creates a cursor-based subscription graph over a topic.\n */\nexport function subscription<T>(\n\tname: string,\n\ttopicGraph: TopicGraph<T>,\n\topts?: SubscriptionOptions,\n): SubscriptionGraph<T> {\n\treturn new SubscriptionGraph<T>(name, topicGraph, opts);\n}\n\n/**\n * Creates an autonomous cursor-based topic relay graph.\n *\n * When `opts.map` is provided, items where `map` returns `undefined` are\n * consumed from the source cursor but NOT republished (at-most-once with\n * silent drop). For filter-with-retry semantics, apply the filter in a\n * downstream subscription on the bridge's `output` node instead.\n */\nexport function topicBridge<TIn, TOut = TIn>(\n\tname: string,\n\tsourceTopic: TopicGraph<TIn>,\n\ttargetTopic: TopicGraph<TOut>,\n\topts?: TopicBridgeOptions<TIn, TOut>,\n): TopicBridgeGraph<TIn, TOut> {\n\treturn new TopicBridgeGraph<TIn, TOut>(name, sourceTopic, targetTopic, opts);\n}\n\n// ── LogProjector ──────────────────────────────────────────────────────────\n//\n// Promotion 2 (memo:Re Story 6.4 back-derivation, design-review-locked\n// 2026-05-16). A cursor-driven projector over a log/topic where a per-item\n// sink can poison-fail. memo:Re hand-rolled `createProjectorCursor` and got\n// the failure mode wrong: a bare `catch { break; }` conflated a *transient*\n// condition (a native feature not yet available → retry later) with a\n// *poison* entry (will never project) → a permanent head-of-line block of\n// every newer entry. The fix is a real, observable, subscribable dead-letter\n// topic + a typed failure policy.\n//\n// Built ON `subscription()` (TopicGraph source) / the bundle's `fromCursor`\n// view (ReactiveLogBundle source) — the same hardened cursor machinery\n// `SubscriptionGraph` itself uses — so the consumer never hand-rolls cursor\n// persistence/durability (the Med \"durability skew\" + parse-leniency findings\n// dissolve). Scope is deliberately bounded: `halt | deadLetter` only, NO\n// programmatic retry/backoff (compose a downstream subscription on\n// `deadLetter` for that — avoids the §44 wrap-imperative-as-primitive trap).\n\nexport type ProjectorPoisonPolicy = \"halt\" | \"deadLetter\";\n\n/** A poison entry routed to {@link LogProjectorGraph.deadLetter}. */\nexport type DeadLetterEntry<T> = {\n\treadonly item: T;\n\t/** `Error.message` (or `String(thrown)`) from the failing `sink`. */\n\treadonly error: string;\n\t/** Absolute 0-based log position of the poisoned item. */\n\treadonly cursorPos: number;\n};\n\nexport type LogProjectorOptions<T> = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Per-item side-effecting projection.\n\t *\n\t * **Transient-vs-poison contract (read this).** The projector cannot tell\n\t * \"this will project later\" from \"this will never project\" — only the sink\n\t * knows. So the contract is:\n\t * - **Return normally** (sync return, or a resolved Promise) → the item is\n\t * *handled*; the cursor advances. Use this for the success path AND for\n\t * any transient/skip condition the sink wants to no-op (e.g. an optional\n\t * native feature not yet available — return without throwing; the entry\n\t * is simply considered done for this projector).\n\t * - **Throw / reject** → the item is *poison*; the {@link onPoison} policy\n\t * applies. Do NOT throw for transient conditions or the item is\n\t * dead-lettered (or halts the stream).\n\t */\n\treadonly sink: (item: T) => void | Promise<void>;\n\t/**\n\t * Behaviour when `sink` throws/rejects on an item (poison):\n\t * - `\"halt\"` (default) — stop projecting at the poison item; the cursor\n\t * does NOT advance past it (head-of-line stop). `position` stalls — that\n\t * is the observable signal. No retry/backoff is built in.\n\t * - `\"deadLetter\"` — publish `{ item, error, cursorPos }` to the\n\t * {@link LogProjectorGraph.deadLetter} topic and advance past it, so\n\t * newer entries still project.\n\t */\n\treadonly onPoison?: ProjectorPoisonPolicy;\n\t/**\n\t * Initial cursor position. `\"retained\"` (default) projects all history;\n\t * `\"now\"` skips existing entries (project only future appends); a number\n\t * starts at that absolute index.\n\t */\n\treadonly from?: \"retained\" | \"now\" | number;\n\t/** Retained window for the `deadLetter` topic. Default 1024. */\n\treadonly deadLetterRetainedLimit?: number;\n};\n\n/**\n * Cursor-driven projector over a {@link TopicGraph} or {@link ReactiveLogBundle}.\n *\n * Topology (mounted on the returned graph):\n * - `subscription` (TopicGraph source only) — the hardened\n * {@link SubscriptionGraph} cursor; or a local `cursor` state + the\n * bundle's `fromCursor` view (ReactiveLogBundle source).\n * - `drain` — an `effect` that, on every not-yet-projected wave, schedules a\n * serialized async pass that calls `sink` per item (mirrors the\n * `SubscriptionGraph.ackPump` / `TopicBridge.ackPump` effect precedent +\n * memo:Re's `inFlight` chain — one wave processed at a time).\n * - `deadLetter` — a real {@link TopicGraph} (NOT a callback): poison entries\n * are observable in `describe()` and subscribable, instead of memo:Re's\n * silent `break`.\n *\n * **No imperative reads.** Observe `position` (cursor) / subscribe to\n * `deadLetter`. `idle()` is a test-only await convenience.\n *\n * @category patterns\n */\nexport class LogProjectorGraph<T> extends Graph {\n\t/** Reactive count of fully-projected entries (the cursor; read-only). */\n\treadonly position: Node<number>;\n\t/**\n\t * Poison entries (populated when `onPoison: \"deadLetter\"`). A real topic —\n\t * subscribable + visible in `describe()`.\n\t */\n\treadonly deadLetter: TopicGraph<DeadLetterEntry<T>>;\n\tprivate _inFlight: Promise<void> = Promise.resolve();\n\n\tconstructor(\n\t\tname: string,\n\t\tsource: TopicGraph<T> | ReactiveLogBundle<T>,\n\t\topts: LogProjectorOptions<T>,\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tconst onPoison: ProjectorPoisonPolicy = opts.onPoison ?? \"halt\";\n\t\tconst sink = opts.sink;\n\n\t\tconst dl = new TopicGraph<DeadLetterEntry<T>>(`${name}_dead_letter`, {\n\t\t\tretainedLimit: opts.deadLetterRetainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.mount(\"deadLetter\", dl);\n\t\tthis.deadLetter = dl;\n\n\t\t// Uniform cursor surface over either source kind. A TopicGraph reuses\n\t\t// the hardened SubscriptionGraph cursor; a ReactiveLogBundle uses a\n\t\t// local state cursor + the bundle's `fromCursor` view — the very\n\t\t// machinery SubscriptionGraph is itself built on.\n\t\tlet available: Node<readonly T[]>;\n\t\tlet cursorBase: () => number;\n\t\tlet advance: (n: number) => void;\n\n\t\tif (source instanceof TopicGraph) {\n\t\t\tconst sub = new SubscriptionGraph<T>(`${name}_subscription`, source, {\n\t\t\t\tfrom: opts.from ?? \"retained\",\n\t\t\t});\n\t\t\tthis.mount(\"subscription\", sub);\n\t\t\tavailable = sub.available;\n\t\t\tthis.position = sub.cursor;\n\t\t\tcursorBase = () => sub.cursor.cache as number;\n\t\t\tadvance = (n) => {\n\t\t\t\tif (n > 0) sub.ack(n);\n\t\t\t};\n\t\t} else {\n\t\t\tconst log = source;\n\t\t\tlet initialCursor: number;\n\t\t\tif (opts.from === \"now\") {\n\t\t\t\tinitialCursor = log.size;\n\t\t\t} else if (typeof opts.from === \"number\") {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"logProjector from\");\n\t\t\t} else {\n\t\t\t\tinitialCursor = 0; // \"retained\"\n\t\t\t}\n\t\t\tconst cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\t\tmeta: messagingMeta(\"log_projector_cursor\"),\n\t\t\t});\n\t\t\tthis.position = cursor;\n\t\t\tcursorBase = () => cursor.cache as number;\n\t\t\tavailable = log.view({ kind: \"fromCursor\", cursor });\n\t\t\tadvance = (n) => {\n\t\t\t\tif (n > 0) cursor.emit((cursor.cache as number) + n);\n\t\t\t};\n\t\t}\n\n\t\t// `halt` is a HARD LATCH (QA-C): on the first poison under `onPoison:\n\t\t// \"halt\"`, `sink` has been invoked exactly once on the poison item;\n\t\t// the projector then freezes — no further `sink` calls, no rescheduled\n\t\t// drains — so a later unrelated append cannot re-invoke the (possibly\n\t\t// side-effecting, non-idempotent) sink on the poison. The stalled\n\t\t// `position` + frozen stream IS the observable signal. v1 has no retry\n\t\t// (compose downstream of `deadLetter` if you need that).\n\t\tlet halted = false;\n\n\t\t// Serialized async drain. One wave processed at a time (the inFlight\n\t\t// chain) so an async `sink` cannot interleave; the cursor is advanced\n\t\t// ONCE per pass after the captured snapshot is processed (mirrors\n\t\t// memo:Re's `runPump` + the ackPump effect precedent).\n\t\tconst runDrain = async (): Promise<void> => {\n\t\t\tif (halted) return;\n\t\t\tconst snapshot = (available.cache as readonly T[] | undefined) ?? [];\n\t\t\tif (snapshot.length === 0) return;\n\t\t\tlet consumed = 0;\n\t\t\tfor (let i = 0; i < snapshot.length; i += 1) {\n\t\t\t\tconst item = snapshot[i] as T;\n\t\t\t\ttry {\n\t\t\t\t\tawait sink(item);\n\t\t\t\t\tconsumed += 1;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconst error = e instanceof Error ? e.message : String(e);\n\t\t\t\t\tif (onPoison === \"deadLetter\") {\n\t\t\t\t\t\tdl.publish({ item, error, cursorPos: cursorBase() + consumed });\n\t\t\t\t\t\tconsumed += 1; // advance past the poison\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// \"halt\" — latch and stop here; do NOT advance past the\n\t\t\t\t\t// poison, do NOT re-invoke `sink` on any later wave.\n\t\t\t\t\thalted = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (consumed > 0) advance(consumed);\n\t\t};\n\t\tconst schedule = (): void => {\n\t\t\tif (halted) return; // latched — no further drains\n\t\t\tthis._inFlight = this._inFlight.then(runDrain, runDrain);\n\t\t};\n\n\t\t// Effect: every wave that exposes not-yet-projected entries schedules a\n\t\t// drain. Side-effecting (sink / cursor advance / dead-letter publish) →\n\t\t// an `effect` node, not a pure derived (COMPOSITION-GUIDE §35; exact\n\t\t// `SubscriptionGraph.advancePump` precedent — never calls `emit` on its\n\t\t// own node, kept warm via `keepalive`).\n\t\tconst drain = node<unknown>(\n\t\t\t[available],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst b = batchData[0];\n\t\t\t\tconst snap = (b != null && b.length > 0 ? b.at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly T[]\n\t\t\t\t\t| undefined;\n\t\t\t\tif (snap && snap.length > 0) schedule();\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"drain\",\n\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\tmeta: messagingMeta(\"log_projector_drain\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(drain, { name: \"drain\" });\n\t\tthis.addDisposer(keepalive(drain));\n\t}\n\n\t/**\n\t * Await any in-flight drain pass. **Test convenience only** — the canonical\n\t * reactive observable is {@link LogProjectorGraph.position}.\n\t */\n\tidle(): Promise<void> {\n\t\treturn this._inFlight;\n\t}\n}\n\n/**\n * Creates a cursor-driven log/topic projector with a typed poison-failure\n * policy and an observable dead-letter topic.\n *\n * @example\n * ```ts\n * import { logProjector, topic } from \"@graphrefly/graphrefly\";\n *\n * const events = topic<Doc>(\"docs\");\n * const proj = logProjector(\"indexer\", events, {\n * sink: async (doc) => { await index(doc); }, // throw ⇒ poison\n * onPoison: \"deadLetter\",\n * });\n * proj.deadLetter.events.subscribe(/* observe poison */);\n * ```\n *\n * @remarks\n * **Use an UNBOUNDED source for durable / long-lived projection.** The cursor\n * is an absolute index; the underlying `fromCursor` view slices the source's\n * *current* entries array. A `TopicGraph` with a `retainedLimit` (or a\n * `ReactiveLogBundle` with `maxSize`) trims its head, so an absolute cursor\n * past the retained window reads the wrong offset (skips entries or stalls).\n * This is inherited `subscription()` / `fromCursor` behaviour, not specific to\n * `logProjector` — but it matters here because projection is typically\n * long-lived. For unbounded projection pass a source with NO `retainedLimit` /\n * `maxSize` (memo:Re's `changesetLog` is unbounded ✓).\n *\n * @category patterns\n */\nexport function logProjector<T>(\n\tname: string,\n\tsource: TopicGraph<T> | ReactiveLogBundle<T>,\n\topts: LogProjectorOptions<T>,\n): LogProjectorGraph<T> {\n\treturn new LogProjectorGraph<T>(name, source, opts);\n}\n","/**\n * Universal mutation framework (Phase 14 — DS-14 locked 2026-05-05).\n *\n * Single `mutate(act, opts)` factory replaces the prior `lightMutation` +\n * `wrapMutation` two-tier split (pre-1.0 break per Q-O2).\n *\n * Two frames:\n * - `\"inline\"` — no batch; up() runs raw. Seq bumps before action; persists\n * on throw. Hot-path-friendly for atomic single-write mutations.\n * - `\"transactional\"` — opens `batch(() => up(...))`. On throw: batch discards\n * deferred deliveries, then `down()` runs (if provided), then failure record.\n *\n * Phase-4 primitives share the same shape: imperative mutation methods +\n * closure state + reactive audit log + freeze-at-entry + rollback-on-throw.\n * This module factors out the common machinery so each primitive becomes\n * declarative wiring over typed audit records.\n */\n\nimport {\n\tbatch,\n\tDATA,\n\tDIRTY,\n\ttype Node,\n\ttype NodeGuard,\n\tnode,\n\tpolicy,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport {\n\ttype ReactiveLogBundle,\n\ttype ReactiveLogOptions,\n\treactiveLog,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\n\n// ── tryIncrementBounded ──────────────────────────────────────────────────\n\n/**\n * Bounded increment for a self-owned counter state node.\n *\n * Reads `counter.cache`, bumps by `by` (default 1) if `cur + by <= cap`,\n * writes back. Returns `false` when the cap would be exceeded (no-op write).\n * Documented P3 exception: the counter is not a declared dep of the caller —\n * it's a private budget read+written from a single call site. This helper\n * keeps the `.cache` access in one named place so caller bodies (which may\n * be inside reactive fn execution paths) stay free of cross-node `.cache`\n * reads.\n *\n * **Safety today:**\n * 1. Single-threaded JS runner never invokes the caller concurrently.\n * 2. `counter.down` writes the cache synchronously before returning, so\n * synchronous re-entry through a downstream publish reads the\n * freshly-incremented value — no double-count.\n *\n * **Future risk:** under a free-threaded runner (PY no-GIL or hypothetical\n * concurrent TS runner), two concurrent firings could still race. Revisit\n * when that surfaces.\n *\n * @param counter - Self-owned counter Node. Caller is the sole writer.\n * @param cap - Upper bound (inclusive). Pass `Number.MAX_SAFE_INTEGER` for\n * \"effectively unbounded\" use cases (e.g. token meters).\n * @param by - Delta to add (default `1`). Must be a finite non-negative\n * number; callers should pre-validate. Overflow-safe via\n * `by > cap - cur` check rather than `cur + by >= cap`.\n */\nexport function tryIncrementBounded(counter: Node<number>, cap: number, by = 1): boolean {\n\tconst cur = (counter.cache as number | undefined) ?? 0;\n\tif (by > cap - cur) return false;\n\tcounter.down([[DIRTY], [DATA, cur + by]]);\n\treturn true;\n}\n\n// ── Audit record schema ──────────────────────────────────────────────────\n\n/** Shared base shape for every audit record. Per-primitive types extend this. */\nexport interface BaseAuditRecord {\n\treadonly t_ns: number;\n\treadonly seq?: number;\n\treadonly handlerVersion?: { id: string; version: string | number };\n}\n\n// ── Default audit guard ──────────────────────────────────────────────────\n\n/**\n * Allow `observe` and `signal`; deny external `write` on the audit log so\n * consumers can subscribe + signal-bridge but cannot inject fake records.\n */\nexport const DEFAULT_AUDIT_GUARD: NodeGuard = policy((allow, deny) => {\n\tallow(\"observe\");\n\tallow(\"signal\");\n\tdeny(\"write\");\n});\n\n// ── createAuditLog ───────────────────────────────────────────────────────\n\nexport type AuditLogOpts<R extends BaseAuditRecord> = {\n\tname: string;\n\t/** Bounded retention; default 1024 per Audit 2 / cross-cutting bounded-default policy. */\n\tretainedLimit?: number;\n\t/** Override the default audit guard. */\n\tguard?: NodeGuard;\n\t/** Mount the audit `entries` Node under this graph (and activate withLatest). */\n\tgraph?: Graph;\n\t/** Pass-through to {@link reactiveLog}. */\n\tversioning?: ReactiveLogOptions<R>[\"versioning\"];\n};\n\n/**\n * Build a reactive audit log with sane defaults: bounded retention, deny-write\n * guard, `withLatest()` companions activated. Returns the {@link ReactiveLogBundle}\n * directly — primitives expose this as `<primitive>.events` / `.decisions` /\n * `.dispatches` / `.invocations` and alias it as `.audit`.\n *\n * @category internal\n */\nexport function createAuditLog<R extends BaseAuditRecord>(\n\topts: AuditLogOpts<R>,\n): ReactiveLogBundle<R> {\n\tconst log = reactiveLog<R>([], {\n\t\tname: opts.name,\n\t\tmaxSize: opts.retainedLimit ?? 1024,\n\t\tguard: opts.guard ?? DEFAULT_AUDIT_GUARD,\n\t\t...(opts.versioning != null ? { versioning: opts.versioning } : {}),\n\t});\n\t// Lazy companion activation up-front so `bundle.lastValue` / `hasLatest`\n\t// are queryable without an explicit `withLatest()` call.\n\tlog.withLatest();\n\tif (opts.graph) {\n\t\topts.graph.add(log.entries, { name: opts.name });\n\t}\n\treturn log;\n}\n\n// ── Universal mutation factory (Phase 14 — DS-14 lock Q-O2/Q-O3) ────────\n//\n// Single `mutate(act, opts)` factory. Two frames:\n//\n// - `\"inline\"` — no batch frame; up() runs raw. Seq bumps before action;\n// persists on throw. Hot-path-friendly for atomic single-write mutations.\n//\n// - `\"transactional\"` — opens `batch(() => up(...))`. On throw: batch discards\n// deferred deliveries, then `down()` runs, then failure record persists.\n//\n// **Heuristic:** if your imperative method's body is one or two lines (mutate\n// state, emit), use `frame: \"inline\"`. If it runs a user-supplied handler or\n// has multiple steps that could leave inconsistent state mid-throw, use\n// `frame: \"transactional\"`.\n\nexport type FailureMeta = {\n\tt_ns: number;\n\tseq?: number;\n\terrorType: string;\n};\n\nexport type SuccessMeta = {\n\tt_ns: number;\n\tseq?: number;\n};\n\n/**\n * Mutation action shape. Plain function shorthand auto-wraps as `{ up: fn }`.\n *\n * - `up` — the mutation action (the \"up migration\").\n * - `down` — optional rollback for closure mutations that `batch()` can't\n * reach. Receives the SAME frozen args as `up`. Runs AFTER batch reactive\n * rollback, BEFORE the failure record. Throws inside `down` are\n * console.error'd without masking the original error. Only meaningful\n * with `frame: \"transactional\"`.\n */\nexport type MutationAct<TArgs extends readonly unknown[], TResult> = {\n\tup: (...args: TArgs) => TResult;\n\tdown?: (...args: TArgs) => void;\n};\n\nexport type MutationFrame = \"inline\" | \"transactional\";\n\nexport type MutateOpts<TArgs extends readonly unknown[], TResult, R extends BaseAuditRecord> = {\n\t/** Frame mode. `\"inline\"` = no batch; `\"transactional\"` = batch + rollback. */\n\tframe: MutationFrame;\n\t/**\n\t * Optional log to append records to. When omitted, the wrapper still\n\t * provides freeze / seq-advance / rollback-on-throw but skips record\n\t * emission — useful for primitives that want centralized mutation\n\t * semantics without a dedicated log surface (e.g. `Topic.publish`).\n\t */\n\tlog?: ReactiveLogBundle<R>;\n\t/** Build the success record from the action's args + result + meta. */\n\tonSuccessRecord?: (args: TArgs, result: TResult, meta: SuccessMeta) => R | undefined;\n\t/** Build the failure record from the args + error + meta. */\n\tonFailureRecord?: (args: TArgs, error: unknown, meta: FailureMeta) => R | undefined;\n\t/** Deep-freeze args at entry (default `true`). Opt out for hot paths. */\n\tfreeze?: boolean;\n\t/** Optional sequence cursor — auto-advanced and stamped onto records. */\n\tseq?: Node<number>;\n\t/** Optional handler version — stamped per Audit 5. */\n\thandlerVersion?: { id: string; version: string | number };\n};\n\nfunction deepFreeze<T>(value: T): T {\n\tif (value === null || typeof value !== \"object\" || Object.isFrozen(value)) return value;\n\tfor (const k of Object.keys(value as Record<string, unknown>)) {\n\t\tdeepFreeze((value as Record<string, unknown>)[k]);\n\t}\n\treturn Object.freeze(value);\n}\n\n/**\n * Universal mutation factory (Phase 14 — DS-14 Q-O2).\n *\n * Replaces the prior `lightMutation` + `wrapMutation` two-tier split.\n * Single factory with `frame: \"inline\" | \"transactional\"` discriminant.\n *\n * @param act - The mutation action. Either a plain function (auto-wrapped as\n * `{ up: fn }`) or a `{ up, down? }` object for explicit rollback.\n * @param opts - Configuration: frame, log, record builders, freeze, seq.\n * @returns A typed wrapper function with the same signature as `act.up`.\n */\nexport function mutate<TArgs extends readonly unknown[], TResult, R extends BaseAuditRecord>(\n\tact: MutationAct<TArgs, TResult> | ((...args: TArgs) => TResult),\n\topts: MutateOpts<TArgs, TResult, R>,\n): (...args: TArgs) => TResult {\n\tconst { up, down } = typeof act === \"function\" ? { up: act, down: undefined } : act;\n\tconst freeze = opts.freeze ?? true;\n\n\tif (opts.frame === \"inline\") {\n\t\treturn function wrapped(...args: TArgs): TResult {\n\t\t\tconst sealed = freeze ? (args.map(deepFreeze) as unknown as TArgs) : args;\n\t\t\tconst t_ns = wallClockNs();\n\t\t\tconst seq = opts.seq ? bumpCursor(opts.seq) : undefined;\n\t\t\ttry {\n\t\t\t\tconst result = up(...sealed);\n\t\t\t\tif (opts.log && opts.onSuccessRecord) {\n\t\t\t\t\tappendAudit<TArgs, TResult, R, SuccessMeta>(\n\t\t\t\t\t\topts.log,\n\t\t\t\t\t\topts.onSuccessRecord,\n\t\t\t\t\t\tsealed,\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t{ t_ns, seq },\n\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tif (opts.log && opts.onFailureRecord) {\n\t\t\t\t\tconst errorType = err instanceof Error ? err.name : typeof err;\n\t\t\t\t\tappendAudit<TArgs, unknown, R, FailureMeta>(\n\t\t\t\t\t\topts.log,\n\t\t\t\t\t\topts.onFailureRecord,\n\t\t\t\t\t\tsealed,\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t{ t_ns, seq, errorType },\n\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t};\n\t}\n\n\t// frame === \"transactional\"\n\treturn function wrapped(...args: TArgs): TResult {\n\t\tconst sealed = freeze ? (args.map(deepFreeze) as unknown as TArgs) : args;\n\t\tconst t_ns = wallClockNs();\n\t\tlet result: TResult;\n\t\tlet captured: unknown;\n\t\tlet captureSet = false;\n\t\tlet seq: number | undefined;\n\t\ttry {\n\t\t\tbatch(() => {\n\t\t\t\tif (opts.seq) seq = bumpCursor(opts.seq);\n\t\t\t\ttry {\n\t\t\t\t\tresult = up(...sealed);\n\t\t\t\t\tif (opts.log && opts.onSuccessRecord) {\n\t\t\t\t\t\tappendAudit<TArgs, TResult, R, SuccessMeta>(\n\t\t\t\t\t\t\topts.log,\n\t\t\t\t\t\t\topts.onSuccessRecord,\n\t\t\t\t\t\t\tsealed,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\t{ t_ns, seq },\n\t\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tcaptured = err;\n\t\t\t\t\tcaptureSet = true;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (outerErr) {\n\t\t\t// Fire `down` AFTER batch's reactive rollback, BEFORE failure record.\n\t\t\t// Gate on `captureSet` — if the throw came from outside the inner try\n\t\t\t// (framework-level batch error before action ran), don't fire down.\n\t\t\tif (captureSet && down) {\n\t\t\t\ttry {\n\t\t\t\t\tdown(...sealed);\n\t\t\t\t} catch (downErr) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`mutate: down hook threw — original action error preserved (${\n\t\t\t\t\t\t\tcaptured instanceof Error ? captured.name : typeof captured\n\t\t\t\t\t\t}). Down error:`,\n\t\t\t\t\t\tdownErr,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (captureSet && opts.log && opts.onFailureRecord) {\n\t\t\t\tconst errorType = captured instanceof Error ? captured.name : typeof captured;\n\t\t\t\tappendAudit<TArgs, unknown, R, FailureMeta>(\n\t\t\t\t\topts.log,\n\t\t\t\t\topts.onFailureRecord,\n\t\t\t\t\tsealed,\n\t\t\t\t\tcaptured,\n\t\t\t\t\t{ t_ns, seq, errorType },\n\t\t\t\t\topts.handlerVersion,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow captureSet ? captured : outerErr;\n\t\t}\n\t\treturn result!;\n\t};\n}\n\n/**\n * Advance a cursor node and return the new value. Emits `[DIRTY], [DATA, next]`\n * directly on the cursor — atomic outside a batch, rollback-discardable inside.\n *\n * Resets to `0` if the cursor cache is missing, non-numeric, `NaN`, or\n * non-finite (e.g. corrupted by `restore()` from a malformed snapshot, or\n * by a misbehaving codec). `??` alone would let `NaN` and `\"\"` pass through\n * and silently corrupt audit ordering downstream.\n *\n * **Silent reset diagnostic (EH-12).** When the cache holds a non-numeric\n * value at bump time, the cursor restarts at 0 and the next bump returns 1\n * — colliding with the seq stamped on the very first record after construct.\n * To make seq-monotonicity violations after a restore visible to operators,\n * the helper emits a one-shot `console.warn` per cursor instance describing\n * the offending value. The cursor is identified by a `WeakSet<Node<number>>`\n * so the warning fires exactly once per node — repeat malformed bumps stay\n * quiet to avoid log spam. Production callers wanting to suppress can swap\n * the global `console` (universal-safe code path; no Node-only API used).\n *\n * Works whether or not the cursor has any subscribers — `down` updates the\n * cache regardless, so primitives that bump before consumers attach (e.g.\n * `JobQueueGraph.enqueue`) still see a coherent sequence.\n *\n * @category internal\n */\nconst _bumpCursorWarned = new WeakSet<Node<number>>();\nexport function bumpCursor(seq: Node<number>): number {\n\tconst raw = seq.cache;\n\tconst valid = typeof raw === \"number\" && Number.isFinite(raw);\n\tif (!valid && raw !== undefined && !_bumpCursorWarned.has(seq)) {\n\t\t_bumpCursorWarned.add(seq);\n\t\tconsole.warn(\n\t\t\t`bumpCursor: cursor cache held a non-numeric value (${String(raw)}); resetting to 0. ` +\n\t\t\t\t\"Causes include: a snapshot codec round-tripping the cursor as a string / null / NaN, \" +\n\t\t\t\t\"OR a malformed initial seed (e.g. state<number>(NaN)). \" +\n\t\t\t\t\"Audit consumers may see colliding seq values after this point.\",\n\t\t);\n\t}\n\tconst cur = valid ? raw : 0;\n\tconst next = cur + 1;\n\tseq.down([[DIRTY], [DATA, next]]);\n\treturn next;\n}\n\n/**\n * Build a record via the supplied builder, stamp `handlerVersion` if present,\n * and append it to the audit log. `undefined` records are skipped (callers\n * pass an `onSuccess` / `onFailure` that returns `undefined` to opt out per\n * call).\n *\n * @category internal\n */\nexport function appendAudit<\n\tTArgs extends readonly unknown[],\n\tTValue,\n\tR extends BaseAuditRecord,\n\tM extends SuccessMeta | FailureMeta,\n>(\n\taudit: ReactiveLogBundle<R>,\n\tbuilder: (args: TArgs, value: TValue, meta: M) => R | undefined,\n\targs: TArgs,\n\tvalue: TValue,\n\tmeta: M,\n\thandlerVersion?: { id: string; version: string | number },\n): void {\n\tconst record = builder(args, value, meta);\n\tif (record === undefined) return;\n\tconst stamped = handlerVersion != null ? ({ ...record, handlerVersion } as R) : record;\n\taudit.append(stamped);\n}\n\n// ── registerCursor / registerCursorMap ───────────────────────────────────\n\n/**\n * Promote a closure counter to a state node mounted under `graph`.\n * Replaces ad-hoc `let _seq = 0` patterns with a node observable in\n * `describe()` and persistable via storage tiers.\n *\n * @category internal\n */\nexport function registerCursor(graph: Graph, name: string, initial = 0): Node<number> {\n\tconst cursor = node<number>([], { initial, name, describeKind: \"state\" });\n\tgraph.add(cursor, { name });\n\treturn cursor;\n}\n\n/**\n * Promote a closure `Map<K, number>` to N state nodes (one per key) mounted\n * under `<graph>::<name>::<key>`. Used by saga (per-event-type cursor).\n *\n * @category internal\n */\nexport function registerCursorMap<K extends string>(\n\tgraph: Graph,\n\tname: string,\n\tkeys: readonly K[],\n\tinitial = 0,\n): { readonly [P in K]: Node<number> } {\n\tconst out = {} as { [P in K]: Node<number> };\n\t// Mount cursors under a child plain-Graph so per-key node names stay flat\n\t// (path-separator `::` is reserved by Graph.add). Using `Graph` directly\n\t// rather than `graph.constructor` avoids spawning a typed subclass with\n\t// an incompatible constructor signature (e.g., CqrsGraph(name, opts)).\n\tconst sub = new Graph(name);\n\tfor (const k of keys) {\n\t\tconst cursor = node<number>([], {\n\t\t\tinitial,\n\t\t\tname: k,\n\t\t\tdescribeKind: \"state\",\n\t\t});\n\t\tsub.add(cursor, { name: k });\n\t\tout[k] = cursor;\n\t}\n\tgraph.mount(name, sub);\n\treturn out;\n}\n","/**\n * Reactive agent loop — autonomous multi-turn LLM agent with tool execution.\n */\n\nexport type AgentLoopStatus = \"idle\" | \"thinking\" | \"acting\" | \"done\" | \"error\";\n\nimport {\n\tbatch,\n\tDATA,\n\tERROR,\n\tINVALIDATE,\n\ttype Node,\n\tnode,\n\tnode as nodeFactory,\n\tplaceholderArgs,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, keepalive, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { awaitSettled } from \"../../base/sources/settled.js\";\nimport { aiMeta } from \"../../utils/ai/_internal.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMResponse,\n\tToolCall,\n\tToolDefinition,\n} from \"../../utils/ai/adapters/core/types.js\";\nimport { type ChatStreamGraph, chatStream } from \"../../utils/ai/agents/chat-stream.js\";\nimport { type ToolResult, toolExecution } from \"../../utils/ai/agents/tool-execution.js\";\nimport { type ToolRegistryGraph, toolRegistry } from \"../../utils/ai/agents/tool-registry.js\";\n\nexport type { ToolResult } from \"../../utils/ai/agents/tool-execution.js\";\n\n// ---------------------------------------------------------------------------\n// agentLoop\n// ---------------------------------------------------------------------------\n\nexport type AgentLoopOptions = {\n\tgraph?: GraphOptions;\n\tadapter: LLMAdapter;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n\tmaxTurns?: number;\n\tstopWhen?: (response: LLMResponse) => boolean;\n\tonToolCall?: (call: ToolCall) => void;\n\tmaxMessages?: number;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Reactive tool-call splice (COMPOSITION-GUIDE §31 \"interception is security\").\n\t * When set, the raw `toolCalls` node is piped through this transform before\n\t * reaching the executor. The transform is a pure reactive composition —\n\t * `(calls: Node<readonly ToolCall[]>) => Node<readonly ToolCall[]>` — so the\n\t * gate is visible in `describe()` / `explain()` as a real edge (no hidden\n\t * imperative wraps; §24).\n\t *\n\t * Typical uses:\n\t * - **Filter / block** — `derived([calls, policy], ([raw, p]) => raw.filter(p))`\n\t * - **Throttle / debounce** — `throttle(calls, windowMs)`\n\t * - **Human-in-the-loop approval** — pipe through a `gate` controller so\n\t * calls wait for human approval before reaching the executor.\n\t *\n\t * The public `agent.toolCalls` node surfaces the POST-intercept stream, so\n\t * audit / telemetry consumers see what the executor actually runs. The raw\n\t * pre-intercept stream is not exposed — tests that need it should run\n\t * without `interceptToolCalls` set (the identity case).\n\t */\n\tinterceptToolCalls?: (calls: Node<readonly ToolCall[]>) => Node<readonly ToolCall[]>;\n};\n\n/**\n * Reactive agent loop.\n *\n * The loop is a reactive state machine wired entirely from graph primitives:\n * `chat.messages` + `tools.schemas` + gating state feed a `promptInput`\n * derived; `switchMap` turns non-null inputs into an LLM invocation via\n * `fromAny(adapter.invoke(...))`. The LLM response drives chat writes and\n * status transitions via effects. Tool calls flow through a reactive\n * executor (`retrySource` + `rescue`) that retries once on error and\n * surfaces terminal errors as JSON-shaped `ToolResult` payloads for the\n * LLM to react to.\n *\n * **No imperative control flow inside the reactive layer** (spec §5.8-5.12):\n * no `while` loops, no manual `await adapter.invoke`, no polling.\n * `agent.run()` is a thin `awaitSettled` bridge so callers can still `await`\n * the loop if they want a Promise.\n *\n * Public surface:\n * - `chat` / `tools` — subgraphs (imperative `append` at boundary, reactive `executeReactive` for tool invocation)\n * - `status` / `turn` / `aborted` — state nodes with explicit initials\n * - `lastResponse` / `toolCalls` / `toolResults` — reactive outputs (SENTINEL until first emission; callers use `awaitSettled` / `subscribe`)\n * - `run(userMessage?, signal?)` — optional user append + Promise bridge\n * - `abort()` — imperative abort shim; flips `aborted` state\n *\n * **Lifecycle: single-mount.** `AgentLoopGraph` instances expect to be\n * constructed once and used until `destroy()`. The internal closure mirrors\n * (`latestTurn` / `latestAborted` / `latestStatus`) are wired by\n * subscribe-and-capture at construction time; their `addDisposer`-registered\n * subscriptions are torn down on subgraph unmount or `destroy()`. After\n * teardown the mirrors freeze at their last value, so re-using a destroyed\n * instance — calling `run()` again, or remounting under a new parent —\n * would silently feed stale mirror data into reactive fn bodies. If you\n * need to \"reset\" an agent, build a fresh `AgentLoopGraph` instance instead\n * of recycling.\n */\nexport class AgentLoopGraph extends Graph {\n\treadonly chat: ChatStreamGraph;\n\treadonly tools: ToolRegistryGraph;\n\n\t/** Current agent status. `initial: \"idle\"` — always has a real value. */\n\treadonly status: Node<AgentLoopStatus>;\n\t/** Turn count (completed LLM invocations this run). `initial: 0`. */\n\treadonly turn: Node<number>;\n\t/** Aborted flag; flipped by `abort()` or external `AbortSignal`. `initial: false`. */\n\treadonly aborted: Node<boolean>;\n\n\t/**\n\t * Most recent LLM response. State-backed mirror driven by the response\n\t * effect. **Stays SENTINEL** (`cache === undefined`, no DATA emitted)\n\t * until the first real response — bridge subscribers see no spurious\n\t * push-on-subscribe DATA. After a real response, holds the latest\n\t * `LLMResponse`. Reset between `run()` calls via `[[INVALIDATE]]` (clears\n\t * cache back to SENTINEL) so a second run with a pre-aborted signal\n\t * cannot leak the prior run's response. Bridge with\n\t * `awaitSettled(lastResponse)` for the first DATA as a Promise; consumers\n\t * inside reactive fns gate on `ctx.prevData[i] === undefined`.\n\t */\n\treadonly lastResponse: Node<LLMResponse>;\n\t/** Tool-call batch emitted by the most recent LLM response. SENTINEL. */\n\treadonly toolCalls: Node<readonly ToolCall[]>;\n\t/** Tool-result batch (one entry per call) after reactive execution. SENTINEL. */\n\treadonly toolResults: Node<readonly ToolResult[]>;\n\n\tprivate readonly _terminalResult: Node<LLMResponse>;\n\tprivate readonly _disposeRunWiring: () => void;\n\t/** Guards against overlapping `run()` calls. */\n\tprivate _running = false;\n\t/**\n\t * Abort controller for the currently-running `adapter.invoke`. Minted per\n\t * switchMap project; aborted when the reactive `aborted` node flips true\n\t * OR when the caller's external `AbortSignal` fires. Threaded into\n\t * `adapter.invoke({ signal })` AND `fromAny(promise, { signal })`, so the\n\t * reactive layer sees ERROR when the wire call is cancelled.\n\t */\n\tprivate _currentAbortController: AbortController | null = null;\n\n\tconstructor(name: string, opts: AgentLoopOptions) {\n\t\tsuper(name, opts.graph);\n\n\t\t// Mount chat subgraph\n\t\tthis.chat = chatStream(`${name}-chat`, { maxMessages: opts.maxMessages });\n\t\tthis.mount(\"chat\", this.chat);\n\n\t\t// Mount tool registry subgraph\n\t\tthis.tools = toolRegistry(`${name}-tools`);\n\t\tthis.mount(\"tools\", this.tools);\n\n\t\tif (opts.tools) {\n\t\t\tfor (const tool of opts.tools) {\n\t\t\t\tthis.tools.register(tool);\n\t\t\t}\n\t\t}\n\n\t\t// --- State nodes (always have a real value; explicit initials) ---\n\t\tthis.status = node<AgentLoopStatus>([], {\n\t\t\t...{\n\t\t\t\tname: \"status\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t\t},\n\t\t\tinitial: \"idle\",\n\t\t});\n\t\tthis.add(this.status, { name: \"status\" });\n\n\t\tthis.turn = node<number>([], {\n\t\t\t...{\n\t\t\t\tname: \"turn\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_turn_count\"),\n\t\t\t},\n\t\t\tinitial: 0,\n\t\t});\n\t\tthis.add(this.turn, { name: \"turn\" });\n\n\t\tthis.aborted = node<boolean>([], {\n\t\t\t...{\n\t\t\t\tname: \"aborted\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_aborted\"),\n\t\t\t},\n\t\t\tinitial: false,\n\t\t});\n\t\tthis.add(this.aborted, { name: \"aborted\" });\n\n\t\t// --- Reactive pipeline ---\n\t\t//\n\t\t// **Read pattern (Phase 12 D1 lock + F2 fix 2026-05-01).** State\n\t\t// scratchpad held on this `AgentLoopGraph` (turn / aborted / chat /\n\t\t// tools) is read inside reactive fn bodies via either:\n\t\t// (a) `data[i]` / `ctx.prevData[i]` for declared deps, OR\n\t\t// (b) sole-owner `.cache` reads on subgraph-mounted state Nodes\n\t\t// (chat / tools mounted as subgraphs of this Graph; the agent\n\t\t// is the sole owner; promptInput / effResponse / effResults\n\t\t// live in the same enclosing constructor scope — sanctioned\n\t\t// form per Phase 12 D1 read-pattern lock).\n\t\t//\n\t\t// Closure mirrors (`latestTurn` / `latestAborted` / `latestStatus`)\n\t\t// are kept ONLY for fields where (b) doesn't simplify the call site\n\t\t// — turn / aborted / status are state Nodes registered on `this`\n\t\t// directly (not subgraphs), and the closure form keeps\n\t\t// effResponse's batch logic readable. They are CORRECT but are NOT\n\t\t// safe under nested drains (the subscribe handler may not have run\n\t\t// yet when a downstream fn reads the closure). For nested-drain-\n\t\t// reachable reads (promptInput, called via `agentLoop.run` from\n\t\t// inside another graph's reactive subscribe handler), prefer (a) or\n\t\t// (b) over the closure mirror. F2 root cause: chat.messages.cache\n\t\t// is updated DURING the DATA-settle phase (before subscribers\n\t\t// run), so `.cache` reads are always at least as fresh as closure\n\t\t// mirrors. See `optimizations.md` \"Phase 13 design-session inputs\n\t\t// from §13.M lock-test\" F2.\n\t\t//\n\t\t// **Pattern note on `latestTurn` staleness under in-batch reads.**\n\t\t// Effect 1 emits `turnNode.emit(next)` inside its batch; Effect 2\n\t\t// reads `latestTurn` on the following wave (after toolResults\n\t\t// settle). Because batch drain is FIFO, `turnSub`'s handler runs\n\t\t// before Effect 2's next wave fires, so `latestTurn` is up-to-date\n\t\t// by the time Effect 2 reads it. This invariant is stable as long\n\t\t// as `turnNode.emit` remains inside Effect 1's batch — a future\n\t\t// refactor that un-batches the emit would regress silently.\n\t\tlet latestTurn = 0;\n\t\tconst turnSub = this.turn.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestTurn = m[1] as number;\n\t\t});\n\t\tlet latestAborted = false;\n\t\tconst abortedSub = this.aborted.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestAborted = m[1] as boolean;\n\t\t});\n\n\t\tconst adapter = opts.adapter;\n\t\tconst systemPrompt = opts.systemPrompt;\n\t\tconst model = opts.model;\n\t\tconst temperature = opts.temperature;\n\t\tconst maxTokens = opts.maxTokens;\n\t\tconst maxTurns = opts.maxTurns ?? 10;\n\t\tconst stopWhen = opts.stopWhen;\n\n\t\t// Capture `this` for closures that don't bind `this`.\n\t\tconst chat = this.chat;\n\t\tconst tools = this.tools;\n\t\tconst statusNode = this.status;\n\t\tconst turnNode = this.turn;\n\t\tconst abortedNode = this.aborted;\n\n\t\t// promptInput: STATUS is the only reactive trigger — chat.messages,\n\t\t// tools.schemas, turn, aborted are sampled via closure-held mirrors\n\t\t// (all populated by subscribe-and-capture above). This prevents the\n\t\t// classic feedback cycle (COMPOSITION-GUIDE §7): if chat.messageCount\n\t\t// were a reactive dep here, effect 1's `chat.append` would trigger a\n\t\t// promptInput wave, which under effect-1's batch would see status\n\t\t// STILL \"thinking\" (pre-drain) and fire a spurious LLM invocation.\n\t\t// By gating only on status, chat writes don't re-trigger — only\n\t\t// explicit status transitions do.\n\t\tconst promptInput: Node<InvokeInput> = nodeFactory<InvokeInput>(\n\t\t\t[statusNode],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 0, \"idle\");\n\t\t\t\tif (stat !== \"thinking\" || latestAborted || latestTurn >= maxTurns) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// F2 fix (2026-05-01): under nested drains, the closure mirrors\n\t\t\t\t// `latestMessages` / `latestSchemas` lag the actual node state —\n\t\t\t\t// messagesSub / schemasSub subscribers may not have run yet when\n\t\t\t\t// promptInput fires (the drain processes status's downstream\n\t\t\t\t// before chat.messages's subscribers fire, even though\n\t\t\t\t// chat.messages.cache is already settled). Read `.cache`\n\t\t\t\t// directly per Phase 12 D1 read-pattern lock: chat / tools are\n\t\t\t\t// mounted as subgraphs of this AgentLoopGraph (sole owner) and\n\t\t\t\t// promptInput is a reactive reader in the same enclosing\n\t\t\t\t// constructor scope — sanctioned `.cache` form. See\n\t\t\t\t// `optimizations.md` \"Phase 13 design-session inputs from §13.M\n\t\t\t\t// lock-test\" F2.\n\t\t\t\tconst messages = (this.chat.messages.cache as readonly ChatMessage[] | undefined) ?? [];\n\t\t\t\tif (messages.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst schemas = (this.tools.schemas.cache as readonly ToolDefinition[] | undefined) ?? [];\n\t\t\t\tactions.emit({ messages, tools: schemas });\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"promptInput\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_prompt_input\", {\n\t\t\t\t\t// State this fn body samples beyond its declared `statusNode`\n\t\t\t\t\t// dep. `aborted` / `turn` come from §28 closure mirrors\n\t\t\t\t\t// (`latestAborted` / `latestTurn`); `chat.messages` /\n\t\t\t\t\t// `tools.schemas` come from sole-owner `.cache` reads\n\t\t\t\t\t// (Phase 12 D1 lock + F2 fix; see comment block above).\n\t\t\t\t\t// Listed here so inspection tooling can surface fold-in\n\t\t\t\t\t// state without grepping source.\n\t\t\t\t\tclosureReads: [\"aborted\", \"turn\", \"chat.messages\", \"tools.schemas\"],\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tconst llmResponse: Node<LLMResponse> = switchMap(\n\t\t\tpromptInput,\n\t\t\t(input) => {\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tthis._currentAbortController = controller;\n\t\t\t\tif (latestAborted) {\n\t\t\t\t\tcontroller.abort(new Error(\"agentLoop: aborted\"));\n\t\t\t\t}\n\t\t\t\t// Wave A Unit B-CC fix: drop the `Promise.resolve(adapter.invoke(...))`\n\t\t\t\t// wrapper. `adapter.invoke` returns a `NodeInput<LLMResponse>`\n\t\t\t\t// (Promise | Node | raw). `fromAny` already handles all three\n\t\t\t\t// shapes; the manual `Promise.resolve` wrapper would force a\n\t\t\t\t// Node-returning adapter into an extra microtask hop and lose\n\t\t\t\t// reactivity (see Unit 11 + Unit 1 for the parallel cleanup).\n\t\t\t\treturn fromAny(\n\t\t\t\t\tadapter.invoke(input.messages, {\n\t\t\t\t\t\ttools: input.tools.length > 0 ? input.tools : undefined,\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\ttemperature,\n\t\t\t\t\t\tmaxTokens,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t}),\n\t\t\t\t\t{ signal: controller.signal },\n\t\t\t\t);\n\t\t\t},\n\t\t\t{ equals: () => false },\n\t\t);\n\n\t\t// State mirror for `lastResponse` — exists for **cross-run reset\n\t\t// semantics**, NOT the §32 mid-wave hazard.\n\t\t//\n\t\t// Why: `llmResponse` is a switchMap output; its cache persists across\n\t\t// `run()` calls (switchMap's output node has no built-in reset path —\n\t\t// the cache stays at the last DATA the inner emitted). A second\n\t\t// `run()` with a pre-aborted signal would otherwise have\n\t\t// `_terminalResult` evaluate `stat=done` (driven by `effAbort`) +\n\t\t// `resp=<prior run's response>` (cached on `llmResponse`) and resolve\n\t\t// the Promise with stale data instead of rejecting with AbortError.\n\t\t// The mirror is **reset via `[[INVALIDATE]]`** in `run()`'s reset\n\t\t// batch — INVALIDATE clears `_cached` back to `undefined` (SENTINEL)\n\t\t// AND clears the `prevData` slot on every dependent (`_terminalResult`,\n\t\t// `toolCallsRaw`), so the abort path correctly emits\n\t\t// `[[ERROR, AbortError]]` from terminalResult's `stat=\"done\" &&\n\t\t// prevData[lastResponse] === undefined → ERROR` guard.\n\t\t//\n\t\t// **No `T | null` placeholder.** Per `feedback_use_prevdata_for_sentinel`\n\t\t// + COMPOSITION-GUIDE §1a, the SENTINEL state IS the \"never sent\n\t\t// real DATA yet\" signal. An eager `initial: null` would push `[null]`\n\t\t// to every fresh subscriber — a footgun for bridge subscribers that\n\t\t// would otherwise need `if (resp == null) continue` guards. Stay\n\t\t// SENTINEL; consumers detect \"no response yet\" via\n\t\t// `ctx.prevData[i] === undefined` (or `cache === undefined` outside\n\t\t// reactive fns). F9 lock-test (`multi-agent-example.test.ts` test 5)\n\t\t// pins this invariant.\n\t\t//\n\t\t// What this does NOT solve: the §32 mid-wave \"stale peer-read\"\n\t\t// hazard. Investigation (2026-04-25) confirmed `_dirtyDepCount`\n\t\t// gating in `_maybeRunFnOnSettlement` already prevents that — when\n\t\t// `effResponse`'s nested batch fires `status=\"done\"` mid-iteration,\n\t\t// terminal's status dep settles but its `llmResponse` (or mirror)\n\t\t// dep is still DIRTY from Phase 1, so the fn does not run until\n\t\t// Phase 2 visits both deps. Verified by fast-check invariant `#12b\n\t\t// nested-drain-peer-consistency-compound` and by the multi-turn\n\t\t// `executes tool calls and loops` test passing under either dep\n\t\t// shape (`[statusNode, llmResponse]` or `[statusNode, lastResponseState]`).\n\t\t//\n\t\t// Verified by: QA C3 regression tests (`run() with pre-aborted\n\t\t// signal rejects AbortError` and `second run() with pre-aborted\n\t\t// signal rejects AbortError (no stale response leak)`) — both\n\t\t// fail when `_terminalResult` is rewired to depend on `llmResponse`\n\t\t// directly. See COMPOSITION-GUIDE §32 (cross-wave reset reframe).\n\t\tconst lastResponseState = node<LLMResponse>([], {\n\t\t\tname: \"lastResponse\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_last_response\"),\n\t\t});\n\t\tthis.lastResponse = lastResponseState;\n\n\t\t// toolCalls: raw node that emits DATA only when status === \"acting\" and\n\t\t// the current response has tool calls. Otherwise emits RESOLVED. Using\n\t\t// DATA([]) for the idle case would cause switchMap(toolCalls) to\n\t\t// re-dispatch its inner (creating a fresh node([], { initial: [] }) source whose\n\t\t// emissions re-trigger effects downstream). RESOLVED keeps the inner\n\t\t// alive and lets upstream waves pass through without re-dispatch.\n\t\t// Inner raw tool-call stream — name `toolCallsRaw` so the post-intercept\n\t\t// public surface (`this.toolCalls`) is unambiguous in `describe()`.\n\t\t// QA-fix: previously the inner was named `\"toolCalls\"`, which collided\n\t\t// with `this.toolCalls` if the user-supplied interceptor returned a\n\t\t// wrapper that internally retained a reference to this raw node —\n\t\t// `describe()` would render two distinct nodes both labeled `\"toolCalls\"`.\n\t\tconst toolCallsRaw = nodeFactory<readonly ToolCall[]>(\n\t\t\t[lastResponseState, statusNode],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\t// SENTINEL guard: `lastResponseState` stays `undefined` (cache\n\t\t\t\t// + prevData) until the first real response. `readLatest`'s\n\t\t\t\t// fallback returns `undefined` here so the no-DATA branch is\n\t\t\t\t// indistinguishable from the protocol SENTINEL — both gate to\n\t\t\t\t// RESOLVED. Per `feedback_use_prevdata_for_sentinel`.\n\t\t\t\tconst resp = readLatest<LLMResponse | undefined>(data, ctx.prevData, 0, undefined);\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 1, \"idle\");\n\t\t\t\tif (stat !== \"acting\") {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst calls = resp?.toolCalls;\n\t\t\t\tif (calls == null || calls.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.emit(calls);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"toolCallsRaw\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_tool_calls_raw\"),\n\t\t\t},\n\t\t);\n\t\t// Reactive splice (D9 / COMPOSITION-GUIDE §31). When `interceptToolCalls`\n\t\t// is set, the raw tool-call stream is transformed in the graph — the\n\t\t// executor sees the gated stream, and `agent.toolCalls` surfaces the\n\t\t// post-intercept view so audit / telemetry match reality.\n\t\tconst gatedToolCallsNode = opts.interceptToolCalls\n\t\t\t? opts.interceptToolCalls(toolCallsRaw)\n\t\t\t: toolCallsRaw;\n\t\tthis.toolCalls = gatedToolCallsNode;\n\n\t\t// Delegate per-call fan-out + retry + rescue to the `toolExecution`\n\t\t// primitive. `toolCallsRaw` already gates empty batches to RESOLVED,\n\t\t// so `toolExecution`'s \"non-empty batch only\" contract is satisfied\n\t\t// upstream. `retryCount: 1` matches the pre-extraction behaviour\n\t\t// (one retry after first failure = 2 attempts total).\n\t\tconst toolResultsNode: Node<readonly ToolResult[]> = toolExecution({\n\t\t\ttoolCalls: gatedToolCallsNode,\n\t\t\ttools,\n\t\t\tretryCount: 1,\n\t\t});\n\t\tthis.toolResults = toolResultsNode;\n\n\t\t// --- State-machine effects ---\n\t\t// Effect 1: LLM response landed → write lastResponse mirror + chat,\n\t\t// transition status, increment turn. Emission ORDER inside the batch\n\t\t// matters (drain is FIFO under any outer-batch depth):\n\t\t// 1. `lastResponseState.emit(response)` FIRST — so when the drain\n\t\t// fires the status=done wave later in the queue, `_terminalResult`'s\n\t\t// dep on `lastResponseState` has already been updated.\n\t\t// 2. `statusNode.emit(nextStatus)` — drives state machine.\n\t\t// 3. `turnNode.emit(next)` — counter.\n\t\t// 4. `chat.append(...)` LAST — chat.messageCount wave now sees the\n\t\t// new status (so `promptInput` gates correctly).\n\t\t// Without (1) first, `_terminalResult` reads stale `prevData` for\n\t\t// lastResponse when status transitions synchronously during drain.\n\t\t//\n\t\t// **Invariant independence from outer batch depth.** `downWithBatch`\n\t\t// preserves FIFO drain order regardless of nesting — whether the\n\t\t// outer batch is at depth 0 (common: Promise microtask) or depth >0\n\t\t// (user-composed `batch()` scope around `agent.run()`), the emissions\n\t\t// above drain in the order they were enqueued. The state-mirror\n\t\t// pattern holds in both cases.\n\t\t//\n\t\t// **Abort guard (C2 defense-in-depth).** If the `aborted` state has\n\t\t// flipped true between `adapter.invoke`'s Promise resolution and this\n\t\t// effect firing (micro-race), bail out so we don't append to chat or\n\t\t// execute tool calls for an abandoned run. The controller.abort() in\n\t\t// effAbort also fires the signal, which causes `fromAny` to emit\n\t\t// ERROR — but that ERROR propagation arrives in a separate wave, so\n\t\t// this guard covers the \"Promise already resolved before abort hit\n\t\t// the controller\" case.\n\t\tconst effResponse = node(\n\t\t\t[llmResponse],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tif (latestAborted) return;\n\t\t\t\tconst response = data[0] as LLMResponse;\n\t\t\t\tconst next = latestTurn + 1;\n\t\t\t\tconst hasToolCalls = response.toolCalls != null && response.toolCalls.length > 0;\n\t\t\t\tconst naturalStop =\n\t\t\t\t\tresponse.finishReason === \"end_turn\" &&\n\t\t\t\t\t(!response.toolCalls || response.toolCalls.length === 0);\n\t\t\t\tconst customStop = stopWhen?.(response) === true;\n\t\t\t\tconst capReached = next >= maxTurns;\n\t\t\t\tconst nextStatus: AgentLoopStatus =\n\t\t\t\t\tcustomStop || naturalStop || !hasToolCalls || capReached ? \"done\" : \"acting\";\n\t\t\t\tbatch(() => {\n\t\t\t\t\tlastResponseState.emit(response);\n\t\t\t\t\tstatusNode.emit(nextStatus);\n\t\t\t\t\tturnNode.emit(next);\n\t\t\t\t\tchat.append(\"assistant\", response.content, {\n\t\t\t\t\t\ttoolCalls: response.toolCalls,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Effect 2: Tool results landed → append to chat, transition to\n\t\t// thinking (or done if turn cap reached). Same ordering discipline —\n\t\t// status emits before chat mutations. Abort guard mirrors effResponse.\n\t\tconst effResults = node(\n\t\t\t[toolResultsNode],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tif (latestAborted) return;\n\t\t\t\tconst arr = data[0] as readonly ToolResult[];\n\t\t\t\tif (arr.length === 0) return;\n\t\t\t\tconst nextStatus: AgentLoopStatus = latestTurn >= maxTurns ? \"done\" : \"thinking\";\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusNode.emit(nextStatus);\n\t\t\t\t\tfor (const r of arr) chat.appendToolResult(r.id, r.content);\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Effect 3: external abort → cancel in-flight wire call + terminal status.\n\t\t// Aborting the controller causes the switchMap inner's `fromAny` to\n\t\t// emit ERROR (signal-bound), which tears down the subscription. The\n\t\t// `status=\"done\"` emit drives `_terminalResult` to resolve `run()`'s\n\t\t// Promise (via AbortError when `resp == null`, see C3).\n\t\t//\n\t\t// Unit 4 Q5: status guard — if status is already \"done\" (the natural-\n\t\t// completion path raced the abort), skip the redundant emit so the\n\t\t// status-node event log isn't polluted with a trailing duplicate.\n\t\t// Closure-mirror `latestStatus` keeps the comparison synchronous and\n\t\t// P3-compliant (closure read, not `.cache` read — see §28). Seeded\n\t\t// from `statusNode.cache` to match the §28 factory-time-seed pattern\n\t\t// that `latestTurn` / `latestAborted` use — the literal `\"idle\"` would\n\t\t// silently drift if the constructor initial value ever changed.\n\t\tlet latestStatus: AgentLoopStatus = (statusNode.cache as AgentLoopStatus | undefined) ?? \"idle\";\n\t\tconst statusSub = statusNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestStatus = m[1] as AgentLoopStatus;\n\t\t});\n\t\tconst effAbort = node(\n\t\t\t[abortedNode],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tif (data[0] === true) {\n\t\t\t\t\tthis._currentAbortController?.abort(new Error(\"agentLoop: aborted\"));\n\t\t\t\t\tif (latestStatus !== \"done\") statusNode.emit(\"done\");\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Keepalive so the pipeline stays activated even without external\n\t\t// subscribers. Callers don't need to subscribe to `llmResponse` /\n\t\t// `toolResults` for the loop to run.\n\t\tconst kaResponse = keepalive(effResponse);\n\t\tconst kaResults = keepalive(effResults);\n\t\tconst kaAbort = keepalive(effAbort);\n\n\t\t// terminalResult emits the final `LLMResponse` on each \"done\"\n\t\t// transition. The old compound `{response, runVersion}` shape existed\n\t\t// to let a re-entrant caller's `awaitSettled` predicate filter out\n\t\t// the PREVIOUS run's cached DATA; that job now belongs to\n\t\t// `awaitSettled({skipCurrent: true})` (extra/sources.ts) which\n\t\t// ignores the initial push-on-subscribe DATA and resolves only on\n\t\t// fresh post-subscribe emissions. Retiring the stamp removes a\n\t\t// closure-held counter and a per-emission object allocation from\n\t\t// the hot path.\n\t\t//\n\t\t// C3 (abort-before-response) post-SENTINEL: when `stat === \"done\"` but\n\t\t// `lastResponseState` is SENTINEL (no DATA ever delivered for this\n\t\t// run — `prevData[1] === undefined`, equivalently `resp === undefined`\n\t\t// after `readLatest`'s fallback), emit `ERROR(AbortError)` so the\n\t\t// awaiting Promise rejects instead of hanging on a RESOLVED. The\n\t\t// SENTINEL state is restored at every `run()` boundary by\n\t\t// `lastResponse.down([[INVALIDATE]])` (clears `_cached` AND clears\n\t\t// each dependent's `prevData` slot for this dep), so a second run\n\t\t// after a successful first run still detects the abort cleanly —\n\t\t// no stale `prevData` leak.\n\t\tthis._terminalResult = nodeFactory<LLMResponse>(\n\t\t\t[statusNode, lastResponseState],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 0, \"idle\");\n\t\t\t\tconst resp = readLatest<LLMResponse | undefined>(data, ctx.prevData, 1, undefined);\n\t\t\t\tif (stat === \"done\") {\n\t\t\t\t\tif (resp !== undefined) {\n\t\t\t\t\t\tactions.emit(resp);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst err = new Error(\"agentLoop: aborted\") as Error & { name: string };\n\t\t\t\t\terr.name = \"AbortError\";\n\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (stat === \"error\") {\n\t\t\t\t\tactions.down([[ERROR, new Error(\"agentLoop: errored\")]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"terminalResult\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_terminal_result\"),\n\t\t\t\t// `lastResponseState` is SENTINEL until the first real response\n\t\t\t\t// arrives — without `partial: true`, the spec §2.7 first-run\n\t\t\t\t// gate would block this fn from ever firing on the abort-\n\t\t\t\t// before-response path (`status → \"done\"` while `lastResponse`\n\t\t\t\t// has never delivered DATA). The fn explicitly handles the\n\t\t\t\t// SENTINEL case (`resp === undefined → ERROR(AbortError)`),\n\t\t\t\t// so partial-fire is safe by design.\n\t\t\t\tpartial: true,\n\t\t\t},\n\t\t);\n\t\t// Wave B-CC Q2/C: register intermediate pipeline nodes so consumers\n\t\t// can `observe(path)` them by name (e.g. `agent.observe(\"promptInput\")`).\n\t\t// They were already visible in `describe()` via dep traversal, but not\n\t\t// path-addressable. Tools using the `observe`-by-path API now work.\n\t\t//\n\t\t// QA-fix (#5 stability): registrations live AFTER ALL dependent nodes\n\t\t// are constructed (`promptInput → llmResponse → effResponse →\n\t\t// lastResponseState → toolCallsRaw → toolResultsNode → effResults →\n\t\t// effAbort → _terminalResult`). Topology event-stream consumers\n\t\t// subscribed at construction time now see registrations in an order\n\t\t// where every edge between two registered nodes is already valid —\n\t\t// no transient partial graph slipping through to live mermaid / d2\n\t\t// renderers.\n\t\tthis.add(promptInput as Node<unknown>, { name: \"promptInput\" });\n\t\tthis.add(llmResponse as Node<unknown>, { name: \"llmResponse\" });\n\t\tthis.add(this.lastResponse as Node<unknown>, { name: \"lastResponse\" });\n\t\t// When no interceptor is configured, `this.toolCalls === toolCallsRaw` —\n\t\t// registering the same instance under two names trips the per-graph\n\t\t// `_nodeToName` collision check. Register the raw under `toolCalls`\n\t\t// directly in that case; otherwise register both (raw + post-intercept).\n\t\tif (this.toolCalls === toolCallsRaw) {\n\t\t\tthis.add(this.toolCalls as Node<unknown>, { name: \"toolCalls\" });\n\t\t} else {\n\t\t\tthis.add(toolCallsRaw as Node<unknown>, { name: \"toolCallsRaw\" });\n\t\t\tthis.add(this.toolCalls as Node<unknown>, { name: \"toolCalls\" });\n\t\t}\n\t\tthis.add(toolResultsNode as Node<unknown>, { name: \"toolResults\" });\n\t\tthis.add(this._terminalResult as Node<unknown>, { name: \"terminalResult\" });\n\n\t\t// Register subscriptions via `addDisposer` so they tear down on\n\t\t// subgraph unmount (not just explicit `destroy()`). A caller that\n\t\t// unmounts the AgentLoopGraph from its parent via `graph.remove(...)`\n\t\t// would otherwise keep `turnSub` / `abortedSub` live against dead state.\n\t\tthis.addDisposer(turnSub);\n\t\tthis.addDisposer(abortedSub);\n\t\tthis.addDisposer(statusSub);\n\t\tthis.addDisposer(kaResponse);\n\t\tthis.addDisposer(kaResults);\n\t\tthis.addDisposer(kaAbort);\n\t\tthis._disposeRunWiring = (): void => {\n\t\t\t// addDisposer takes care of teardown; this shim stays for the\n\t\t\t// `destroy()` override's idempotency contract (safe no-op if the\n\t\t\t// disposers already fired).\n\t\t};\n\t}\n\n\t/**\n\t * Bridge to `Promise<LLMResponse>` over the reactive pipeline.\n\t *\n\t * - If `userMessage` is provided, appends it as a user message and\n\t * transitions status to `\"thinking\"` to kick the loop.\n\t * - If `signal` is provided, binds it to the reactive `aborted` node\n\t * AND threads into `adapter.invoke({ signal })` so the wire call can\n\t * cancel mid-flight. The reactive `aborted` state + effect 3 guarantee\n\t * that even an adapter that ignores `signal` will stop emitting into\n\t * the agent graph.\n\t * - Resolves when `status === \"done\"` with the final LLM response.\n\t * Rejects with `AbortError` when the abort signal fires pre-response.\n\t * Rejects with the stage error when `status === \"error\"`.\n\t *\n\t * **Concurrency:** `run()` refuses to overlap with a pending call on the\n\t * same agent. Attempting to call `run()` while a previous `run()` is\n\t * still in-flight throws a `RangeError` immediately. Stale-resolution\n\t * safety is provided by `awaitSettled({skipCurrent: true})`, which\n\t * ignores the cached initial DATA from any previous run and resolves\n\t * only on a fresh post-subscribe emission of `_terminalResult`.\n\t */\n\tasync run(userMessage?: string, signal?: AbortSignal): Promise<LLMResponse | null> {\n\t\tif (this._running) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`agentLoop \"${this.name}\": run() called while a previous run() is still pending — await the previous run before starting another, or call abort() first`,\n\t\t\t);\n\t\t}\n\t\tthis._running = true;\n\n\t\tlet offAbort: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Reset per-run state. `lastResponse` MUST be cleared here —\n\t\t\t// without it, `_terminalResult` would read the prior run's\n\t\t\t// cached response during a second `run()` with a pre-aborted\n\t\t\t// signal: `effAbort` drives `status → \"done\"`, `_terminalResult`\n\t\t\t// evaluates `stat=\"done\"` + `resp=<prior respA>` and emits DATA\n\t\t\t// as a fresh post-subscribe signal → `awaitSettled` resolves\n\t\t\t// with the stale response instead of rejecting with AbortError.\n\t\t\t// The C3 `stat=done && resp===undefined → ERROR` guard in\n\t\t\t// `_terminalResult` is only correct once the reset clears the\n\t\t\t// cache.\n\t\t\t//\n\t\t\t// **SENTINEL reset via plain `[[INVALIDATE]]`** (DS-13.5.A,\n\t\t\t// 2026-05-01). Pre-DS-13.5.A this required a paired\n\t\t\t// `[[INVALIDATE], [RESOLVED]]` because INVALIDATE alone left\n\t\t\t// dependents wedged in DIRTY. With INVALIDATE settling the wave\n\t\t\t// (decrementing `_dirtyDepCount` like RESOLVED) and clearing\n\t\t\t// `_cached` + each dependent's `prevData[lastResponse]` slot\n\t\t\t// back to `undefined`, a single emission restores SENTINEL state\n\t\t\t// AND lets dependents fire on the next status transition.\n\t\t\t// `lastResponse` is a `Node<LLMResponse>` with no `initial` —\n\t\t\t// it stays SENTINEL until the first real response; resetting\n\t\t\t// via `emit(null)` would push a `null` DATA placeholder (the\n\t\t\t// F9 trap), which is why INVALIDATE rather than emit is used.\n\t\t\tbatch(() => {\n\t\t\t\tthis.lastResponse.down([[INVALIDATE]]);\n\t\t\t\tthis.turn.emit(0);\n\t\t\t\tthis.aborted.emit(false);\n\t\t\t\tthis.status.emit(\"idle\");\n\t\t\t});\n\t\t\tif (userMessage != null) this.chat.append(\"user\", userMessage);\n\n\t\t\t// Subscribe to `_terminalResult` BEFORE transitioning to\n\t\t\t// \"thinking\" — otherwise a synchronous adapter (mock tests,\n\t\t\t// offline stubs) would drain status → done → DATA on\n\t\t\t// `_terminalResult` before `awaitSettled` had a chance to\n\t\t\t// subscribe, and `skipCurrent: true` would swallow the only\n\t\t\t// DATA this run will produce. `awaitSettled` / `firstWhere`\n\t\t\t// subscribes synchronously during the `async` function's\n\t\t\t// initial execution slice, so calling it before the kick\n\t\t\t// guarantees the subscription is in place when the pipeline\n\t\t\t// starts draining.\n\t\t\t//\n\t\t\t// `skipCurrent: true` still matters: on the second `run()`\n\t\t\t// call `_terminalResult` holds cached DATA from the prior run,\n\t\t\t// and push-on-subscribe would resolve immediately with that\n\t\t\t// stale value without the skip.\n\t\t\tconst resultPromise = awaitSettled(this._terminalResult, { skipCurrent: true });\n\n\t\t\tif (signal != null) {\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis.aborted.emit(true);\n\t\t\t\t} else {\n\t\t\t\t\tconst listener = (): void => this.aborted.emit(true);\n\t\t\t\t\tsignal.addEventListener(\"abort\", listener, { once: true });\n\t\t\t\t\toffAbort = (): void => signal.removeEventListener(\"abort\", listener);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Kick — transition to \"thinking\" fires promptInput → llmResponse.\n\t\t\t// Skip the kick when the signal was already aborted: `effAbort`\n\t\t\t// has driven `status → \"done\"` above, and a trailing\n\t\t\t// `thinking` emit would produce a non-monotonic `idle → done →\n\t\t\t// thinking` sequence in the status-event log for no reactive\n\t\t\t// benefit (promptInput gates on `!latestAborted` anyway).\n\t\t\tif (signal?.aborted !== true) {\n\t\t\t\tthis.status.emit(\"thinking\");\n\t\t\t}\n\n\t\t\treturn await resultPromise;\n\t\t} finally {\n\t\t\toffAbort?.();\n\t\t\tthis._running = false;\n\t\t\tthis._currentAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Flip the reactive `aborted` state. Equivalent to setting an external\n\t * `AbortSignal` — the pipeline observes and transitions to `\"done\"`.\n\t */\n\tabort(): void {\n\t\tthis.aborted.emit(true);\n\t}\n\n\toverride destroy(): void {\n\t\ttry {\n\t\t\tthis._disposeRunWiring();\n\t\t} catch {\n\t\t\t/* best-effort: disposing keepalives shouldn't block destroy */\n\t\t}\n\t\tsuper.destroy();\n\t}\n}\n\n/**\n * Read the latest value for dep `i` inside a raw-`node()` fn body.\n *\n * Checks `batchData[i]` first (this-wave DATA from the dep), falls back to\n * `ctx.prevData[i]` (last DATA from prior waves), and finally to `fallback`\n * when the dep has never emitted (SENTINEL). Matches the unwrap semantics\n * `derived`'s sugar applies, so raw nodes can read deps uniformly.\n *\n * @internal\n */\nfunction readLatest<T>(\n\tbatchData: readonly (readonly unknown[] | undefined)[],\n\tprevData: readonly unknown[],\n\tindex: number,\n\tfallback: T,\n): T {\n\tconst batch = batchData[index];\n\tif (batch != null && batch.length > 0) return batch[batch.length - 1] as T;\n\tconst prev = prevData[index];\n\treturn (prev !== undefined ? prev : fallback) as T;\n}\n\n/** @internal Shape of the LLM invocation input — constructed inside `promptInput`. */\ninterface InvokeInput {\n\treadonly messages: readonly ChatMessage[];\n\treadonly tools: readonly ToolDefinition[];\n}\n\nexport function agentLoop(name: string, opts: AgentLoopOptions): AgentLoopGraph {\n\tconst g = new AgentLoopGraph(name, opts);\n\t// Tier 1.5.3 Phase 2.5 (DG1=B): tag the Graph with its constructing\n\t// factory so `describe()` exposes provenance. Opts include non-JSON\n\t// fields (`adapter`, `tools`, `stopWhen`, `onToolCall`,\n\t// `interceptToolCalls`, etc.) so route through `placeholderArgs`\n\t// (DG2=ii).\n\tg.tagFactory(\"agentLoop\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\treturn g;\n}\n","/**\n * Settled/signal helpers.\n *\n * Moved from extra/sources/settled.ts during cleave A2.\n * `keepalive` is substrate — it lives at `@graphrefly/pure-ts`\n * (`packages/pure-ts/src/extra/sources/_keepalive.ts`), not here.\n */\n\n/**\n * Settled / signal helpers — boundary primitives for converting reactive\n * sources into Promise/AbortSignal endpoints.\n *\n * - {@link firstValueFrom} / {@link firstWhere} — Promise of the first\n * matching DATA.\n * - {@link awaitSettled} — composition over `firstWhere` + reactive\n * `timeout` from `extra/resilience` (lazy import to avoid a\n * resilience → sources cycle).\n * - {@link nodeSignal} — `Node<boolean>` → `AbortSignal` bridge.\n * - {@link reactiveCounter} — capped counter exposed as a `Node<number>`.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n} from \"@graphrefly/pure-ts/core\";\n\n/**\n * Converts the first `DATA` on `source` into a Promise; rejects on `ERROR` or `COMPLETE` without data.\n *\n * **Important:** This subscribes and waits for a **future** emission. Data that\n * has already flowed is gone and will not be seen. Call this *before* the upstream\n * emits, or use `source.cache` / `source.status` for already-cached state.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * @param source - Node to read once.\n * @returns Promise of the first value.\n *\n * @example\n * ```ts\n * import { firstValueFrom, of } from \"@graphrefly/graphrefly-ts\";\n *\n * await firstValueFrom(of(42));\n * ```\n *\n * @category extra\n */\nexport function firstValueFrom<T>(source: Node<T>): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet shouldUnsub = false;\n\t\tlet unsub: (() => void) | undefined;\n\t\tunsub = source.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tresolve(m[1] as T);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(m[1]);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(new Error(\"completed without DATA\"));\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (shouldUnsub) {\n\t\t\tunsub?.();\n\t\t\tunsub = undefined;\n\t\t}\n\t});\n}\n\n/**\n * Wait for the first DATA value from `source` that satisfies `predicate`.\n *\n * Subscribes directly and resolves on the first DATA value where\n * `predicate` returns true. Reactive, no polling. Use in tests and\n * bridging code where you need a single matching value as a Promise.\n *\n * **Important:** This only captures **future** emissions — data that has\n * already flowed through the node is gone. Call this *before* the upstream\n * emits. For already-cached values, use `source.cache` / `source.status`.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * ```ts\n * const val = await firstWhere(strategy.snapshot, snap => snap.size > 0);\n * ```\n *\n * @param source - Upstream node to observe.\n * @param predicate - Returns `true` for the value to resolve on.\n * @param opts - `{ skipCurrent?: boolean }`. When `skipCurrent: true`, any DATA\n * delivered during the synchronous `subscribe()` call (push-on-subscribe §2.2\n * replay of the cached value) is ignored — the promise resolves only on the\n * next future emission. Useful when the caller wants to await the next\n * settlement event after an imperative action (e.g. `run()` minting a new\n * runVersion, where the currently-cached value belongs to the previous run).\n *\n * @category extra\n */\nexport function firstWhere<T>(\n\tsource: Node<T>,\n\tpredicate: (value: T) => boolean,\n\topts?: { skipCurrent?: boolean; kick?: () => void },\n): Promise<T> {\n\t// Lock 3.A (Phase 13.6.B): subscribe synchronously inside the function\n\t// body — NOT inside the Promise executor. Subscribing inside the\n\t// executor would defer the subscription past any synchronous `kick()`\n\t// the caller fires after the call returns, race-losing the very wave\n\t// the caller wants to observe.\n\t//\n\t// To bridge sync-subscribe with the async Promise contract, we record\n\t// any settlement that fires *before* the Promise constructor runs, and\n\t// the executor immediately resolves/rejects with the recorded value.\n\t// Settlements after the executor runs go straight through resolve/reject.\n\ttype Pending =\n\t\t| { kind: \"data\"; value: T }\n\t\t| { kind: \"error\"; err: unknown }\n\t\t| { kind: \"complete\" };\n\tlet pending: Pending | undefined;\n\tlet resolveFn: ((value: T) => void) | undefined;\n\tlet rejectFn: ((err: unknown) => void) | undefined;\n\tlet settled = false;\n\tlet shouldUnsub = false;\n\tlet unsub: (() => void) | undefined;\n\tlet inInitialSyncPhase = opts?.skipCurrent === true;\n\n\t// QA P1: every settler short-circuits when `settled === true` so a\n\t// later settle attempt (e.g. `kick()` throwing AFTER it synchronously\n\t// fired matching DATA, OR a `[DATA matched, ERROR]` wave during\n\t// push-on-subscribe) cannot overwrite an earlier `pending` outcome.\n\t// Without this gate, a kick that races sink-callback settlement could\n\t// reject a Promise the user already has resolved-DATA for.\n\tconst settleData = (v: T): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (resolveFn != null) resolveFn(v);\n\t\telse pending = { kind: \"data\", value: v };\n\t};\n\tconst settleError = (err: unknown): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (rejectFn != null) rejectFn(err);\n\t\telse pending = { kind: \"error\", err };\n\t};\n\tconst settleComplete = (): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tconst err = new Error(\"completed without matching value\");\n\t\tif (rejectFn != null) rejectFn(err);\n\t\telse pending = { kind: \"complete\" };\n\t};\n\tconst detach = (): void => {\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tunsub = undefined;\n\t\t} else shouldUnsub = true;\n\t};\n\n\tconst sink: (msgs: Messages) => void = (msgs) => {\n\t\tif (settled) return;\n\t\tfor (const m of msgs) {\n\t\t\tif (settled) return;\n\t\t\t// During the initial sync phase, swallow only cached DATA\n\t\t\t// (push-on-subscribe §2.2). Terminal ERROR / COMPLETE must\n\t\t\t// still reject the promise — otherwise an already-terminated\n\t\t\t// source synchronously delivering `[[ERROR, ...]]` or\n\t\t\t// `[[COMPLETE]]` during `subscribe()` would hang forever\n\t\t\t// under `skipCurrent: true`.\n\t\t\tif (inInitialSyncPhase && m[0] === DATA) continue;\n\t\t\tif (m[0] === DATA) {\n\t\t\t\tconst v = m[1] as T;\n\t\t\t\tif (predicate(v)) {\n\t\t\t\t\tsettleData(v);\n\t\t\t\t\tdetach();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (m[0] === ERROR) {\n\t\t\t\tsettleError(m[1]);\n\t\t\t\tdetach();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\tsettleComplete();\n\t\t\t\tdetach();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\tunsub = source.subscribe(sink);\n\tinInitialSyncPhase = false;\n\t// Lock 3.A: fire `kick` AFTER subscribe is in place. With sync\n\t// subscribe + sync kick, the resulting wave reaches `sink` before\n\t// control returns — making subscribe-before-kick ordering structurally\n\t// impossible to misuse.\n\tif (opts?.kick != null && !settled) {\n\t\ttry {\n\t\t\topts.kick();\n\t\t} catch (err) {\n\t\t\tsettleError(err);\n\t\t\tdetach();\n\t\t}\n\t}\n\tif (shouldUnsub) {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\t// If a settlement landed synchronously before the executor runs,\n\t\t// flush it through immediately.\n\t\tif (pending != null) {\n\t\t\tif (pending.kind === \"data\") resolve(pending.value);\n\t\t\telse if (pending.kind === \"error\") reject(pending.err);\n\t\t\telse reject(new Error(\"completed without matching value\"));\n\t\t\treturn;\n\t\t}\n\t\tresolveFn = resolve;\n\t\trejectFn = reject;\n\t});\n}\n\n/**\n * Await the first non-nullish DATA value from `source`, with optional\n * timeout. Composition sugar over `firstWhere` + reactive timeout.\n *\n * Designed as the CLI/boundary sink for reactive pipelines that end in a\n * nullable node (e.g. `promptNode` — per COMPOSITION-GUIDE §8, it emits\n * `null` before it settles with a real value). Replaces the common pattern\n * `firstValueFrom(filter(source, v => v != null))` with a deadline.\n *\n * - Rejects with `TimeoutError` (from `extra/resilience`) if no matching\n * value arrives within `timeoutMs`. Omit `timeoutMs` for unbounded wait.\n * - `predicate` defaults to `v => v != null`. Pass a custom predicate to\n * gate on a stronger condition (e.g. `v => typeof v === \"string\"`).\n * - Pass `skipCurrent: true` to ignore the currently-cached value delivered\n * synchronously via push-on-subscribe and resolve only on the *next*\n * matching emission. Useful after an imperative action that should produce\n * a fresh settlement (e.g. `run()` minting a new version — the stale\n * cached value from the previous run must not resolve the new caller).\n *\n * ```ts\n * const brief = await awaitSettled(briefNode, { timeoutMs: 120_000 });\n * // or with a predicate:\n * const rich = await awaitSettled(node, {\n * predicate: (v): v is MyShape => typeof v === \"object\" && v != null && \"key\" in v,\n * timeoutMs: 60_000,\n * });\n * // or after kicking off a fresh run:\n * kickOff();\n * const fresh = await awaitSettled(resultNode, { skipCurrent: true });\n * ```\n *\n * Reactive inside, sync propagation — the one async boundary is the\n * returned `Promise<T>` (spec §5.10: async belongs at sources and\n * boundaries, not in the graph).\n *\n * @param source - Upstream node to observe.\n * @param opts - `{ predicate?, timeoutMs?, skipCurrent? }`.\n * @returns Promise that resolves with the first matching value, or rejects on timeout / ERROR / COMPLETE-without-DATA.\n *\n * @category extra\n */\n// Lazy module-cache for the `withTimeout` resilience operator. The dynamic\n// import keeps `settled` free of an eager edge into the resilience family;\n// first call pays the one-shot import, subsequent calls hit cached refs.\nlet _timeoutOp: typeof import(\"../resilience/timeout.js\").withTimeout | undefined;\nlet _nsPerMs: number | undefined;\n\nexport async function awaitSettled<T>(\n\tsource: Node<T>,\n\topts?: {\n\t\tpredicate?: (value: T) => boolean;\n\t\ttimeoutMs?: number;\n\t\tskipCurrent?: boolean;\n\t\t/**\n\t\t * Lock 3.A (Phase 13.6.B): fired AFTER subscribe is in place but\n\t\t * BEFORE the helper's async boundary is exposed to the caller.\n\t\t * Subscribe-before-kick is structurally enforced — the kick's\n\t\t * synchronous wave reaches `sink` before control returns. Replaces\n\t\t * the prior load-bearing-comment pattern (M.20-load-bearing) with\n\t\t * a misuse-impossible API shape.\n\t\t *\n\t\t * Common pattern:\n\t\t * await awaitSettled(node, {\n\t\t * skipCurrent: true,\n\t\t * kick: () => producer.emit(value),\n\t\t * });\n\t\t *\n\t\t * Omit `kick` for external-trigger cases where the wave is fired\n\t\t * by code outside the helper's caller; subscribe still lands\n\t\t * synchronously inside the helper body so the next external wave\n\t\t * is not lost.\n\t\t */\n\t\tkick?: () => void;\n\t},\n): Promise<NonNullable<T>> {\n\tconst predicate = opts?.predicate ?? ((v: T) => v != null);\n\tconst skipCurrent = opts?.skipCurrent;\n\tconst kick = opts?.kick;\n\tif (opts?.timeoutMs == null || opts.timeoutMs <= 0) {\n\t\treturn (await firstWhere(source, predicate, { skipCurrent, kick })) as NonNullable<T>;\n\t}\n\t// Reactive composition: `timeout()` wraps the source as a Node that\n\t// emits ERROR(TimeoutError) on deadline. `firstWhere` then resolves on\n\t// the first matching DATA or rejects on that ERROR. One async boundary\n\t// (the returned Promise), everything inside is sync reactive.\n\tif (_timeoutOp === undefined) {\n\t\tconst [timeoutMod, backoff] = await Promise.all([\n\t\t\timport(\"../resilience/timeout.js\"),\n\t\t\timport(\"../resilience/backoff.js\"),\n\t\t]);\n\t\t_timeoutOp = timeoutMod.withTimeout;\n\t\t_nsPerMs = backoff.NS_PER_MS;\n\t}\n\tconst guarded = _timeoutOp(source, { ns: opts.timeoutMs * (_nsPerMs as number) }).node;\n\treturn (await firstWhere(guarded, predicate, { skipCurrent, kick })) as NonNullable<T>;\n}\n\n/**\n * Converts a reactive `Node<boolean>` into a browser-standard `AbortSignal`\n * that fires when the node settles on `true`. Useful for threading a reactive\n * \"cancel\" flag into any async boundary that accepts a signal (fetch, LLM SDK\n * calls, child-process APIs, timers).\n *\n * **Contract.**\n * - `signal.abort(reason)` fires exactly once, on the first DATA emission with\n * a truthy value. Subsequent emissions are ignored (AbortSignal is\n * single-shot).\n * - Null / `false` / sentinel values are ignored. Push-on-subscribe will\n * check the currently-cached value on subscribe and abort immediately if\n * it's already `true`.\n * - `reason` defaults to `\"cancelled via nodeSignal\"`; pass `opts.reason` to\n * override (`DOMException`, `Error`, or any value accepted by\n * `AbortController.abort`).\n *\n * **Lifecycle.**\n * - Returns a `{signal, dispose}` bundle. Call `dispose()` when you're done\n * with the signal (e.g. in a `finally` after the async operation completes).\n * `dispose()` unsubscribes from the node and is a no-op once the signal has\n * fired.\n * - **Memory note:** without `dispose()` the subscription keeps the reactive\n * node alive for the lifetime of the process. For bridge calls inside a\n * `switchMap` project fn, the switchMap supersede tears the inner subgraph\n * down, which is usually the right lifetime — but still call `dispose()`\n * from the caller's `finally` for clarity.\n *\n * @example\n * ```ts\n * const aborted = state(false);\n * const { signal, dispose } = nodeSignal(aborted);\n * try {\n * const resp = await adapter.invoke(msgs, { signal });\n * return resp;\n * } finally {\n * dispose();\n * }\n * ```\n *\n * @category extra\n */\nexport function nodeSignal(\n\tsource: Node<boolean>,\n\topts?: { reason?: unknown },\n): { signal: AbortSignal; dispose: () => void } {\n\tconst ctrl = new AbortController();\n\tconst reason = opts?.reason ?? new Error(\"cancelled via nodeSignal\");\n\tlet unsub: (() => void) | undefined;\n\tlet shouldUnsub = false;\n\tconst done = () => {\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tunsub = undefined;\n\t\t} else shouldUnsub = true;\n\t};\n\tunsub = source.subscribe((msgs) => {\n\t\tif (ctrl.signal.aborted) return;\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA && m[1] === true) {\n\t\t\t\tctrl.abort(reason);\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === ERROR) {\n\t\t\t\t// Treat an ERROR on the abort source as a cancel signal too —\n\t\t\t\t// a broken control channel should fail closed, not leak the\n\t\t\t\t// in-flight call. Use the error as the abort reason.\n\t\t\t\tctrl.abort(m[1]);\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t// Source completed without aborting — no-op. `done()` already\n\t\t\t\t// released the subscription here, so a later `dispose()` call\n\t\t\t\t// from the caller is a no-op (safe / idempotent).\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t});\n\tif (shouldUnsub) {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\treturn {\n\t\tsignal: ctrl.signal,\n\t\tdispose: () => {\n\t\t\tif (unsub) {\n\t\t\t\tunsub();\n\t\t\t\tunsub = undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// reactiveCounter\n// ---------------------------------------------------------------------------\n\n/** Bundle returned by {@link reactiveCounter}. */\nexport type ReactiveCounterBundle = {\n\t/** Reactive node holding the current count. */\n\treadonly node: Node<number>;\n\t/** Increment by 1. Returns `false` if cap would be exceeded. */\n\tincrement(): boolean;\n\t/** Current count (synchronous read). */\n\tget(): number;\n\t/** Whether the counter has reached its cap. */\n\tatCap(): boolean;\n};\n\n/**\n * Reactive counter with a cap — the building block for circuit breakers.\n *\n * Wraps a `state(0)` node with `increment()` that respects a maximum.\n * The `node` is subscribable and composable like any reactive node. When\n * the cap is reached, `increment()` returns `false`.\n *\n * ```ts\n * const retries = reactiveCounter(10);\n * retries.increment(); // true — count is now 1\n * retries.node.subscribe(...); // reactive updates\n * retries.atCap(); // false\n * ```\n *\n * @param cap - Maximum value (inclusive). 0 = no increments allowed.\n * @category extra\n */\nexport function reactiveCounter(cap: number): ReactiveCounterBundle {\n\tconst counter = node([], { initial: 0 });\n\treturn {\n\t\tnode: counter,\n\t\tincrement() {\n\t\t\tconst current = counter.cache ?? 0;\n\t\t\tif (current >= cap) return false;\n\t\t\tcounter.down([[DIRTY], [DATA, current + 1]]);\n\t\t\treturn true;\n\t\t},\n\t\tget() {\n\t\t\treturn counter.cache ?? 0;\n\t\t},\n\t\tatCap() {\n\t\t\treturn (counter.cache ?? 0) >= cap;\n\t\t},\n\t};\n}\n","import { type Node, node, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { ChatMessage } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// chatStream\n// ---------------------------------------------------------------------------\n\nexport type ChatStreamOptions = {\n\tgraph?: GraphOptions;\n\tmaxMessages?: number;\n};\n\nexport class ChatStreamGraph extends Graph {\n\tprivate readonly _log: ReactiveLogBundle<ChatMessage>;\n\treadonly messages: Node<readonly ChatMessage[]>;\n\t/**\n\t * Most recently appended message. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first append, then\n\t * tracks the latest entry. Per COMPOSITION-GUIDE §1a, the SENTINEL is\n\t * the canonical \"no value yet\" signal — consumers detect empty via\n\t * `data[i] === undefined` inside reactive fns or `latest.cache === undefined`\n\t * outside. No `T | null` placeholder, no `hasLatest` companion.\n\t */\n\treadonly latest: Node<ChatMessage>;\n\treadonly messageCount: Node<number>;\n\n\tconstructor(name: string, opts: ChatStreamOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._log = reactiveLog<ChatMessage>([], {\n\t\t\tname: \"messages\",\n\t\t\tmaxSize: opts.maxMessages,\n\t\t});\n\t\tthis.messages = this._log.entries;\n\t\tthis.add(this.messages, { name: \"messages\" });\n\n\t\t// SENTINEL on empty (COMPOSITION-GUIDE §1a): return `[]` for\n\t\t// RESOLVED-only on empty stream, `[T]` to emit DATA. `latest.cache`\n\t\t// stays `undefined` until the first append.\n\t\tthis.latest = node<ChatMessage>(\n\t\t\t[this.messages],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly ChatMessage[];\n\t\t\t\tif (entries.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.emit(entries[entries.length - 1] as ChatMessage);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"latest\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_latest\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(this.latest, { name: \"latest\" });\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\tthis.messageCount = node<number>(\n\t\t\t[this.messages],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit((data[0] as readonly ChatMessage[]).length);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"messageCount\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_message_count\"),\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t);\n\t\tthis.add(this.messageCount, { name: \"messageCount\" });\n\t\tthis.addDisposer(keepalive(this.messageCount));\n\t}\n\n\tappend(role: ChatMessage[\"role\"], content: string, extra?: Partial<ChatMessage>): void {\n\t\tthis._log.append({ role, content, ...extra });\n\t}\n\n\tappendToolResult(callId: string, content: string): void {\n\t\tthis._log.append({ role: \"tool\", content, toolCallId: callId });\n\t}\n\n\tclear(): void {\n\t\tthis._log.clear();\n\t}\n\n\tallMessages(): readonly ChatMessage[] {\n\t\treturn this.messages.cache as readonly ChatMessage[];\n\t}\n}\n\nexport function chatStream(name: string, opts?: ChatStreamOptions): ChatStreamGraph {\n\treturn new ChatStreamGraph(name, opts);\n}\n","/**\n * `toolExecution` — reactive per-tool-call executor with retry + rescue.\n *\n * Lifted from the inlined `executeToolReactively` helper inside `agent-loop.ts`\n * so it can be consumed standalone by any caller with a reactive `toolCalls`\n * batch — not just `agentLoop`. The shape is: one input `Node<readonly\n * ToolCall[]>` + a `ToolRegistryGraph` → one output `Node<readonly\n * ToolResult[]>`. Each call maps to a per-call `retrySource(executeReactive)`\n * → optional `rescue` chain that emits the handler result on success, or a\n * JSON-wrapped `{ error }` payload on terminal failure so the LLM can see the\n * error as tool output and decide whether to try again via another tool call.\n *\n * **Cancellation.** `executeReactive` mints a per-call `AbortController` and\n * threads its signal into the handler call. When `switchMap` supersedes the\n * inner (a fresh `toolCalls` batch arrives) or the outer graph tears down,\n * the per-call node unsubscribes and `ac.abort()` fires. Signal-aware\n * handlers (`fetch(url, {signal})`, child-process kill, DB cancel) actually\n * stop in-flight work; handlers that ignore the signal still complete to\n * their original termination, but their result is discarded.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { rescue, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { retry } from \"../../../base/resilience/retry.js\";\nimport type { ToolCall } from \"../adapters/core/types.js\";\nimport type { ToolRegistryGraph } from \"./tool-registry.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single tool execution outcome: `{id, content}` where content is a JSON string. */\nexport interface ToolResult {\n\treadonly id: string;\n\treadonly content: string;\n}\n\nexport type ToolExecutionOptions = {\n\t/**\n\t * Reactive tool-call batch. Each non-empty emission triggers a fresh\n\t * per-call execution fan-out; superseding emissions cancel the prior fan.\n\t */\n\ttoolCalls: Node<readonly ToolCall[]>;\n\t/** Registry that resolves tool name → handler. */\n\ttools: ToolRegistryGraph;\n\t/**\n\t * Retry count per individual tool call. `retrySource({count: N})` retries\n\t * up to N times on error (N retries = N+1 total attempts). Default: 1.\n\t */\n\tretryCount?: number;\n\t/**\n\t * How to surface a terminal error after retries are exhausted.\n\t * - `\"rescue\"` (default): emit `{id, content: JSON.stringify({error})}`\n\t * so the LLM sees the failure as structured tool output and can decide\n\t * how to react. Sibling calls in the same batch continue to their own\n\t * completion; one call's failure does not affect the others.\n\t * - `\"propagate\"`: let the ERROR propagate downstream. **Blast radius:**\n\t * the per-batch `derived` join auto-errors when any per-call node\n\t * terminates with ERROR, so one call's failure discards every sibling's\n\t * DATA (even ones that already settled with a valid ToolResult). Use\n\t * `\"propagate\"` only when a single tool failure should be fatal for the\n\t * whole batch; prefer `\"rescue\"` when you want the LLM to see partial\n\t * results plus per-call error markers.\n\t */\n\tonError?: \"rescue\" | \"propagate\";\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Reactive executor for a batch of LLM tool calls.\n *\n * Each DATA emission on `toolCalls` dispatches a fresh per-call fan-out: for\n * every call in the batch, construct a `retrySource(fromAny(tools.execute(\n * name, args)))` node, optionally `rescue` it into a JSON error shape, and\n * join the results via a `derived` whose first-run gate waits for every call\n * to settle before emitting the batch. Empty batches (`calls.length === 0`)\n * are a caller-side invariant violation (the upstream gate should emit\n * RESOLVED for empty batches, not DATA) and trigger a loud error — callers\n * that want to accept empty batches should upstream-filter them first.\n *\n * Reference-equality + content-equality dedup is applied to the output batch\n * so duplicate re-emissions from a completing retrySource don't propagate.\n *\n * @param opts - `{ toolCalls, tools, retryCount?, onError? }`.\n * @returns `Node<readonly ToolResult[]>` — one ToolResult per input ToolCall.\n */\nexport function toolExecution(opts: ToolExecutionOptions): Node<readonly ToolResult[]> {\n\tconst { toolCalls, tools } = opts;\n\tconst retryCount = opts.retryCount ?? 1;\n\tconst onError = opts.onError ?? \"rescue\";\n\n\tconst batchEquals = (a: readonly ToolResult[], b: readonly ToolResult[]): boolean => {\n\t\tif (a === b) return true;\n\t\tif (a.length !== b.length) return false;\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tconst ai = a[i];\n\t\t\tconst bi = b[i];\n\t\t\tif (ai?.id !== bi?.id) return false;\n\t\t\tif (ai?.content !== bi?.content) return false;\n\t\t}\n\t\treturn true;\n\t};\n\n\treturn switchMap<readonly ToolCall[], readonly ToolResult[]>(toolCalls, (calls) => {\n\t\tif (calls == null || calls.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"toolExecution: received an empty tool-call batch as DATA — callers must upstream-filter empty batches (emit RESOLVED) so switchMap is only dispatched for non-empty batches.\",\n\t\t\t);\n\t\t}\n\t\tconst perCall = calls.map((call) => executeOne(call, tools, retryCount, onError));\n\t\t// `executeOne` returns `Node<ToolResult>` in both \"rescue\" and\n\t\t// \"propagate\" modes (the rescue handler builds a `ToolResult`\n\t\t// shape; the success `derived` builds one directly). The join\n\t\t// just forwards the per-call values — no shape coercion needed.\n\t\treturn node(\n\t\t\tperCall,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit(data as readonly ToolResult[]);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\", name: \"toolExecution::batch\", equals: batchEquals },\n\t\t);\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\n/**\n * Per-call reactive executor. `retrySource` re-invokes the factory on ERROR\n * (each attempt mints a fresh `executeReactive` node, which in turn mints a\n * fresh `AbortController` and handler invocation). `executeReactive` itself\n * handles synchronous handler throws — they surface as `[[ERROR, err]]`\n * inside the producer, so `retrySource`'s reactive ERROR path fires\n * consistently regardless of handler shape. No `Promise.resolve().then(...)`\n * thunk needed — the reactive path is end-to-end.\n *\n * Handlers that return a plain string are surfaced as-is; anything else is\n * `JSON.stringify`'d so LLMs that parse tool results can roundtrip\n * structured data without surprise quoting.\n */\nfunction executeOne(\n\tcall: ToolCall,\n\ttools: ToolRegistryGraph,\n\tretryCount: number,\n\tonError: \"rescue\" | \"propagate\",\n): Node<ToolResult> {\n\tconst attempted: Node<unknown> = retry(() => tools.executeReactive(call.name, call.arguments), {\n\t\tcount: retryCount,\n\t}).node;\n\tconst onSuccess = node<ToolResult>(\n\t\t[attempted],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst val = data[0];\n\t\t\tactions.emit({\n\t\t\t\tid: call.id,\n\t\t\t\tcontent: typeof val === \"string\" ? val : JSON.stringify(val),\n\t\t\t});\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tif (onError === \"propagate\") return onSuccess;\n\treturn rescue(onSuccess, (err) => ({\n\t\tid: call.id,\n\t\tcontent: JSON.stringify({ error: String(err) }),\n\t}));\n}\n","/**\n * Retry — re-attempt a node on terminal failure.\n *\n * Two modes selected by the type of `input`:\n * - **Source mode** (`Node<T>`): resubscribes the same node after each ERROR.\n * Upstream must be `resubscribable: true` or retries are silent no-ops.\n * - **Factory mode** (`() => Node<T>`): builds a fresh node per attempt.\n *\n * Shared with `circuitBreaker` / `rateLimiter`: `NodeOrValue<RetryOptions>`\n * lets callers swap retry config reactively (re-validates on each attempt).\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\ttype Message,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n\tResettableTimer,\n} from \"@graphrefly/pure-ts/core\";\nimport { coerceDelayNs, isNode, msgVal, type NodeOrValue, operatorOpts } from \"./_internal.js\";\nimport {\n\ttype BackoffPreset,\n\ttype BackoffStrategy,\n\tNS_PER_MS,\n\tresolveBackoffPreset,\n} from \"./backoff.js\";\nimport type { StatusValue } from \"./status.js\";\n\n/**\n * Lifecycle-shaped state companion emitted by {@link retry} (DS-13.5.B,\n * locked 2026-05-01). Tracks the retry state machine's current status,\n * the attempt counter, and the last scheduled delay (null before the\n * first retry).\n *\n * @category extra/resilience\n */\nexport interface RetryState {\n\tstatus: StatusValue;\n\tattempt: number;\n\tlastDelay_ns: number | null;\n}\n\n/**\n * Bundle returned by {@link retry}: the retry-wrapped output node and its\n * lifecycle state companion. Pre-1.0 break vs the prior `Node<T>` return.\n *\n * **Single-subscriber / pipeline-only contract (DS-13.5.B QA, N1, 2026-05-03).**\n * The `retryState` companion is allocated once at factory time and shared\n * across all subscribers to `node`. With one subscriber (the typical use\n * case — wire `node` into your downstream chain, optionally observe\n * `retryState` separately) the companion reflects a coherent timeline.\n * With **two or more subscribers** to `node`, each subscriber re-runs the\n * producer body and writes into the same `retryState`, including\n * `publish(\"pending\")` resets that can clobber an in-flight machine's\n * `running`/`paused` state. Don't fan out `node` to multiple subscribers\n * and rely on `retryState` accuracy unless you use\n * {@link keepalive} / `share`-style consolidation.\n *\n * @category extra/resilience\n */\nexport interface RetryBundle<T> {\n\tnode: Node<T>;\n\tretryState: Node<RetryState>;\n}\n\nexport type RetryOptions = {\n\t/**\n\t * Max retry attempts after each terminal `ERROR` (not counting the first failure).\n\t *\n\t * **Required when `backoff` is set.** Pass `Infinity` to opt in to unbounded retries\n\t * — the explicit value rules out the silent-infinite-budget footgun (a flaky provider\n\t * + exponential backoff + omitted `count` would previously default to ~2.1B retries).\n\t */\n\tcount?: number;\n\t/** Delay between attempts; strategies use **nanoseconds**. */\n\tbackoff?: BackoffStrategy | BackoffPreset;\n\t/**\n\t * Caller-supplied metadata merged into the produced node's `meta` (Tier 5.2\n\t * D8 widening). Use {@link domainMeta} to tag the layer for `describe()`\n\t * grouping. The primitive's `factoryTag(\"retry\", …)` always wins against\n\t * caller keys.\n\t */\n\tmeta?: Record<string, unknown>;\n};\n\n/** Factory-mode-only options. `initial` seeds the outer node's cache before the first attempt. */\nexport type RetryFactoryOptions<T> = RetryOptions & {\n\t/** Initial cache value for the outer node before the factory runs the first time. */\n\tinitial?: T;\n};\n\n/**\n * Resolved retry config shared by source-mode and factory-mode wrappers.\n * Centralises the unbounded-retry footgun guard and strategy resolution.\n */\ntype ResolvedRetryConfig = {\n\tmaxRetries: number;\n\tstrategy: BackoffStrategy | null;\n};\n\nfunction resolveRetryConfig(opts?: RetryOptions): ResolvedRetryConfig {\n\tconst count = opts?.count;\n\tconst backoffOpt = opts?.backoff;\n\n\t// Unbounded-retry footgun fix: if `backoff` is set without explicit `count`,\n\t// throw at construction time. Caller must opt in to `Infinity` for unbounded.\n\tif (backoffOpt !== undefined && count === undefined) {\n\t\tthrow new RangeError(\n\t\t\t\"retry({ backoff }) requires explicit count to prevent unbounded retries; pass { count: <n>, backoff: ... }\",\n\t\t);\n\t}\n\n\tconst maxRetries = count !== undefined ? count : 0;\n\tif (maxRetries < 0) throw new RangeError(\"retry count must be >= 0\");\n\n\tconst strategy: BackoffStrategy | null =\n\t\tbackoffOpt === undefined\n\t\t\t? null\n\t\t\t: typeof backoffOpt === \"string\"\n\t\t\t\t? resolveBackoffPreset(backoffOpt)\n\t\t\t\t: backoffOpt;\n\n\treturn { maxRetries, strategy };\n}\n\nfunction retryFactoryArgs(opts?: RetryOptions): Record<string, unknown> | undefined {\n\tconst args: Record<string, unknown> = {};\n\tif (opts?.count !== undefined) args.count = opts.count;\n\tif (typeof opts?.backoff === \"string\") args.backoff = opts.backoff;\n\treturn Object.keys(args).length > 0 ? args : undefined;\n}\n\n/**\n * Shared retry state machine. Both `_retrySource` and `_retryFactory` thin-wrap this:\n * the only per-mode logic is supplied via `acquireSource` (returns a fresh `Node<T>`\n * per attempt — for source-mode it just returns the captured `Node`; for factory-mode\n * it calls the user factory and forwards synchronous throws into the same retry path).\n *\n * **Reactive cfg (Tier 6.5 3.2.2, 2026-04-29).** `getCfg` is invoked at\n * every decision point (`scheduleRetryOrFinish` count + strategy reads)\n * so option swaps mid-flight take effect at the next attempt boundary\n * per the locked semantic rule: \"next attempt fails immediately if\n * already exhausted under new count; `backoff` swap takes effect at next\n * retry's delay calculation.\"\n */\nfunction _runRetryStateMachine<T>(\n\tgetCfg: () => ResolvedRetryConfig,\n\tacquireSource: () => Node<T>,\n\ta: { emit: (v: T) => void; down: (msgs: Message[]) => void },\n\temitState?: (next: RetryState) => void,\n): () => void {\n\tlet attempt = 0;\n\tlet stopped = false;\n\tlet prevDelay: number | null = null;\n\tlet unsub: (() => void) | undefined;\n\tconst timer = new ResettableTimer();\n\tconst publish = (status: StatusValue): void => {\n\t\temitState?.({ status, attempt, lastDelay_ns: prevDelay });\n\t};\n\tpublish(\"pending\");\n\n\tfunction disconnectUpstream(): void {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\n\tfunction scheduleRetryOrFinish(err: unknown): void {\n\t\tif (stopped) return;\n\t\tconst cfg = getCfg();\n\t\tif (attempt >= cfg.maxRetries) {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\tconst raw = cfg.strategy === null ? 0 : cfg.strategy(attempt, err, prevDelay);\n\t\t// null from strategy = \"stop retrying\" (e.g. withMaxAttempts cap reached)\n\t\tif (raw === null || raw === undefined) {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\t// A misbehaving strategy (returns NaN / non-finite / negative) MUST NOT\n\t\t// escape into the upstream drain. Treat it like `strategy === null`\n\t\t// (stop retrying) and emit the original error — the strategy bug is a\n\t\t// separate concern the user can inspect via the emitted error's stack.\n\t\tlet delayNs: number;\n\t\ttry {\n\t\t\tdelayNs = coerceDelayNs(raw);\n\t\t} catch {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\tprevDelay = delayNs;\n\t\tattempt += 1;\n\t\tdisconnectUpstream();\n\t\tpublish(\"paused\");\n\t\t// `Math.max(1, …)` floor: every backoff schedule floors at 1ms even when\n\t\t// the strategy returns 0ns. Avoids 0-delay re-entrancy on the active\n\t\t// stack frame (which would risk stack overflow on a tight ERROR loop).\n\t\tconst delayMs = delayNs > 0 ? delayNs / NS_PER_MS : 1;\n\t\t// §5.10: setTimeout (not fromTimer) — retry delay needs clearTimeout/setTimeout;\n\t\t// fromTimer creates a new Node per reset, adding lifecycle overhead per retry.\n\t\ttimer.start(delayMs, () => {\n\t\t\tif (stopped) return;\n\t\t\tconnect();\n\t\t});\n\t}\n\n\tfunction connect(): void {\n\t\ttimer.cancel();\n\t\tdisconnectUpstream();\n\t\tlet src: Node<T>;\n\t\ttry {\n\t\t\tsrc = acquireSource();\n\t\t} catch (err) {\n\t\t\tscheduleRetryOrFinish(err);\n\t\t\treturn;\n\t\t}\n\t\tpublish(\"running\");\n\t\tunsub = src.subscribe((msgs) => {\n\t\t\tif (stopped) return;\n\t\t\tfor (const m of msgs) {\n\t\t\t\tconst t = m[0];\n\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\telse if (t === DATA) {\n\t\t\t\t\tattempt = 0;\n\t\t\t\t\tprevDelay = null;\n\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\tpublish(\"running\");\n\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t// DF2 (2026-04-29): set `stopped = true` BEFORE\n\t\t\t\t\t// `disconnectUpstream()` so a re-entrant ERROR delivered\n\t\t\t\t\t// in the same wave (after disconnect runs but before the\n\t\t\t\t\t// teardown closure fires `stopped = true`) hits the\n\t\t\t\t\t// `if (stopped) return` guard at line 159 and cannot\n\t\t\t\t\t// schedule a new retry timer.\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tdisconnectUpstream();\n\t\t\t\t\tpublish(\"completed\");\n\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\tscheduleRetryOrFinish(msgVal(m));\n\t\t\t\t\treturn;\n\t\t\t\t} else a.down([m]);\n\t\t\t}\n\t\t});\n\t}\n\n\tconnect();\n\n\treturn () => {\n\t\tconst wasStopped = stopped;\n\t\tstopped = true;\n\t\ttimer.cancel();\n\t\tdisconnectUpstream();\n\t\tif (!wasStopped) publish(\"cancelled\");\n\t};\n}\n\n/**\n * Retry operator — two modes selected by the type of `input`:\n *\n * **Source mode** (`input: Node<T>`): resubscribes to the same node after each terminal\n * `ERROR`. The upstream should use `resubscribable: true` if it must emit again after `ERROR`.\n *\n * **Factory mode** (`input: () => Node<T>`): invokes the factory to build a fresh `Node<T>`\n * on every connect / reconnect. Ideal for producers that capture per-attempt resources\n * (sockets, clients, file handles) that become unusable after an error. Synchronous\n * exceptions thrown by the factory are treated as terminal ERROR and run through the\n * same retry pipeline as inner-node ERROR.\n *\n * @param input - Upstream node or factory that returns a fresh node per attempt.\n * @param opts - `count` caps attempts (**required when `backoff` is set**; pass `Infinity` to opt in to unbounded); `backoff` supplies delay in **nanoseconds** (or a preset name); `initial` seeds the outer node cache (factory mode only).\n * @returns Node that retries on error.\n *\n * @throws {RangeError} when `backoff` is provided without an explicit `count` (unbounded-retry footgun guard) or when `count < 0`.\n *\n * @remarks\n * **Protocol:** Forwards unknown message tuples unchanged; handles `DIRTY`, `DATA`, `RESOLVED`, `COMPLETE`, `ERROR`.\n *\n * **Backoff floor:** every scheduled delay is floored at 1ms via `Math.max(1, delayNs / NS_PER_MS)` even when the strategy returns 0ns. This avoids 0-delay re-entrancy on the active stack frame on a tight ERROR loop. Strategies that return `null`/`undefined` stop retrying immediately and forward the original error.\n *\n * @example\n * ```ts\n * // Source mode — resubscribe the same node:\n * import { ERROR, NS_PER_SEC, producer, retry, constant } from \"@graphrefly/graphrefly-ts\";\n *\n * const src = producer(\n * (a) => { a.down([[ERROR, new Error(\"x\")]]); },\n * { resubscribable: true },\n * );\n * const out = retry(src, { count: 2, backoff: constant(0.25 * NS_PER_SEC) });\n *\n * // Factory mode — fresh node per attempt (e.g. reconnecting WebSocket):\n * import { NS_PER_SEC, exponential, retry, fromWebSocket } from \"@graphrefly/graphrefly-ts\";\n *\n * const connected$ = retry(\n * () => fromWebSocket(new WebSocket(\"wss://example/stream\")),\n * { count: 10, backoff: exponential({ baseNs: 1 * NS_PER_SEC }) },\n * );\n * ```\n *\n * @category extra\n */\nexport function retry<T>(input: Node<T>, opts?: NodeOrValue<RetryOptions>): RetryBundle<T>;\nexport function retry<T>(\n\tinput: () => Node<T>,\n\topts?: NodeOrValue<RetryFactoryOptions<T>>,\n): RetryBundle<T>;\nexport function retry<T>(\n\tinput: Node<T> | (() => Node<T>),\n\topts?: NodeOrValue<RetryOptions | RetryFactoryOptions<T>>,\n): RetryBundle<T> {\n\tconst retryState = node<RetryState>([], {\n\t\tname: \"retryState\",\n\t\tdescribeKind: \"state\",\n\t\tinitial: { status: \"pending\", attempt: 0, lastDelay_ns: null },\n\t\tequals: (a, b) =>\n\t\t\ta === b ||\n\t\t\t(a != null &&\n\t\t\t\tb != null &&\n\t\t\t\ttypeof a === \"object\" &&\n\t\t\t\ttypeof b === \"object\" &&\n\t\t\t\tJSON.stringify(a) === JSON.stringify(b)),\n\t});\n\tconst emit = (s: RetryState): void => {\n\t\tretryState.down([[DIRTY], [DATA, s]]);\n\t};\n\tif (typeof input === \"function\") {\n\t\treturn {\n\t\t\tnode: _retryFactory(input, opts as NodeOrValue<RetryFactoryOptions<T>> | undefined, emit),\n\t\t\tretryState,\n\t\t};\n\t}\n\treturn {\n\t\tnode: _retrySource(input, opts as NodeOrValue<RetryOptions> | undefined, emit),\n\t\tretryState,\n\t};\n}\n\n// DS-13.5.B helper: like `resolveReactiveOption` but shallow-merges each\n// reactive emit over the prior opts and treats empty `{}` as a no-op\n// (per the locked cross-cutting rule). Static-form arg returns the value\n// as-is and never subscribes.\nfunction makeMergedOptsMirror<R extends Record<string, unknown>>(\n\targ: NodeOrValue<R> | undefined,\n): { current: () => R | undefined; unsub: () => void } {\n\tif (arg === undefined) {\n\t\treturn { current: () => undefined, unsub: () => undefined };\n\t}\n\tif (!isNode(arg)) {\n\t\treturn { current: () => arg as R, unsub: () => undefined };\n\t}\n\tconst optsNode = arg as Node<R>;\n\tlet merged: R | undefined = (optsNode.cache as R | undefined) ?? undefined;\n\tconst unsub = optsNode.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst next = m[1] as R | undefined;\n\t\t\tif (next == null || typeof next !== \"object\") continue;\n\t\t\tif (Object.keys(next).length === 0) continue; // empty {} no-op\n\t\t\tmerged = { ...(merged ?? ({} as R)), ...next } as R;\n\t\t}\n\t});\n\treturn { current: () => merged, unsub };\n}\n\n// DF6 (2026-04-29): once-per-source dedup for the source-mode-retry warn.\n// Mirrors the `_bumpCursorWarned` pattern in `extra/mutation/index.ts`.\nconst _retrySourceNonResubscribableWarned = new WeakSet<Node<unknown>>();\n\nfunction _retrySource<T>(\n\tsource: Node<T>,\n\topts?: NodeOrValue<RetryOptions>,\n\temitState?: (s: RetryState) => void,\n): Node<T> {\n\t// Source-mode retry re-subscribes to the SAME source node after each\n\t// terminal ERROR. If the upstream was constructed with the default\n\t// `resubscribable: false`, the second subscribe-after-terminal is a\n\t// silent no-op and retries effectively never re-deliver. Surface\n\t// once-per-source so misconfigurations fail loud without log spam.\n\tconst sourceWithFlag = source as unknown as { _resubscribable?: boolean };\n\tif (\n\t\tsourceWithFlag._resubscribable === false &&\n\t\t!_retrySourceNonResubscribableWarned.has(source)\n\t) {\n\t\t_retrySourceNonResubscribableWarned.add(source);\n\t\tconsole.warn(\n\t\t\t\"retry(source, opts): source-mode requires `resubscribable: true` on the upstream \" +\n\t\t\t\t\"node. Retries will be silent no-ops after the first ERROR. Either pass \" +\n\t\t\t\t\"`resubscribable: true` to the source factory, OR use factory-mode retry \" +\n\t\t\t\t\"`retry(() => buildSource(), opts)` so each attempt builds a fresh node.\",\n\t\t);\n\t}\n\tconst staticOpts = isNode(opts) ? undefined : (opts as RetryOptions | undefined);\n\t// Eager validation for static-form opts (preserves construction-time\n\t// \"backoff without count\" RangeError). Reactive-form opts re-validate\n\t// per `getCfg()` call inside the state machine.\n\tif (!isNode(opts)) resolveRetryConfig(staticOpts);\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tconst merged = makeMergedOptsMirror<RetryOptions>(opts);\n\t\t\tconst getCfg = (): ResolvedRetryConfig => resolveRetryConfig(merged.current());\n\t\t\tconst inner = _runRetryStateMachine(getCfg, () => source, a, emitState);\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tinner();\n\t\t\t\t\tmerged.unsub();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: source.cache,\n\t\t\tmeta: {\n\t\t\t\t...(staticOpts?.meta ?? {}),\n\t\t\t\t...factoryTag(\n\t\t\t\t\t\"retry\",\n\t\t\t\t\tisNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction _retryFactory<T>(\n\tfactory: () => Node<T>,\n\topts?: NodeOrValue<RetryFactoryOptions<T>>,\n\temitState?: (s: RetryState) => void,\n): Node<T> {\n\tconst staticOpts = isNode(opts) ? undefined : (opts as RetryFactoryOptions<T> | undefined);\n\t// Eager validation for static-form opts (Tier 3.1 footgun preservation).\n\tif (!isNode(opts)) resolveRetryConfig(staticOpts);\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tconst merged = makeMergedOptsMirror<RetryFactoryOptions<T>>(opts);\n\t\t\tconst getCfg = (): ResolvedRetryConfig => resolveRetryConfig(merged.current());\n\t\t\tconst inner = _runRetryStateMachine(getCfg, factory, a, emitState);\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tinner();\n\t\t\t\t\tmerged.unsub();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: staticOpts?.initial as T | undefined,\n\t\t\tmeta: {\n\t\t\t\t...(staticOpts?.meta ?? {}),\n\t\t\t\t...factoryTag(\n\t\t\t\t\t\"retry\",\n\t\t\t\t\tisNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t);\n}\n","import { ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAsyncIter, fromPromise, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta, isNodeLike } from \"../_internal.js\";\nimport type { ToolDefinition } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// toolRegistry\n// ---------------------------------------------------------------------------\n\nexport type ToolRegistryOptions = {\n\tgraph?: GraphOptions;\n};\n\n/**\n * `ToolRegistryGraph` — name-keyed registry of {@link ToolDefinition}s.\n *\n * **Reactive-only execution.** The only execution path is\n * {@link executeReactive}, which returns a `Node<unknown>` for the handler\n * result. Composing factories (`toolExecution`, `agentLoop`) consume it\n * directly inside `retrySource` / `switchMap` chains. There is intentionally\n * no imperative `execute()` Promise method — the registry was originally a\n * dual-boundary class (imperative + reactive) and the imperative path was\n * the only thing in the codebase bridging through `Promise.resolve().then()`\n * to feed `fromAny`. Removing it left every consumer on a single\n * reactive-all-the-way path with real abort propagation.\n *\n * For non-reactive callers (debug scripts, one-shot tests), bridge with\n * `awaitSettled(toolRegistry.executeReactive(name, args))`.\n *\n * **Wave A Unit 6 refactor:** internal storage migrated from `state<Map>`\n * (O(N) Map-copy per mutation) to `ReactiveMapBundle<string, ToolDefinition>`\n * (O(1) mutations + version counter).\n */\nexport class ToolRegistryGraph extends Graph {\n\treadonly definitions: Node<ReadonlyMap<string, ToolDefinition>>;\n\treadonly schemas: Node<readonly ToolDefinition[]>;\n\tprivate readonly _bundle: ReturnType<typeof reactiveMap<string, ToolDefinition>>;\n\n\tconstructor(name: string, opts: ToolRegistryOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._bundle = reactiveMap<string, ToolDefinition>({\n\t\t\tname: \"definitions\",\n\t\t});\n\t\tthis.definitions = this._bundle.entries;\n\t\tthis.add(this.definitions, { name: \"definitions\" });\n\n\t\tthis.schemas = node<readonly ToolDefinition[]>(\n\t\t\t[this.definitions],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst defs = data[0];\n\t\t\t\tactions.emit([...((defs ?? new Map()) as ReadonlyMap<string, ToolDefinition>).values()]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"schemas\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"tool_schemas\"),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.schemas, { name: \"schemas\" });\n\t\tthis.addDisposer(keepalive(this.schemas));\n\t}\n\n\tregister(tool: ToolDefinition): void {\n\t\tthis._bundle.set(tool.name, tool);\n\t}\n\n\tunregister(name: string): void {\n\t\tthis._bundle.delete(name);\n\t}\n\n\t/**\n\t * Reactive execution — returns a `Node<unknown>` that emits the handler\n\t * result. The returned node is a `producer` that:\n\t *\n\t * 1. Mints a per-call `AbortController` whose `signal` is threaded into\n\t * the handler call AND into `fromAny` (so a `fromPromise` /\n\t * `fromAsyncIter` inner abandons cleanly when the consumer\n\t * unsubscribes).\n\t * 2. Runs `tool.handler(args, {signal})` inside a try/catch — a\n\t * synchronous throw surfaces as `[[ERROR, err]]` downstream instead\n\t * of escaping the producer.\n\t * 3. Forwards every message from the inner `fromAny` chain to the\n\t * producer's outputs.\n\t * 4. On teardown (subscriber count drops to zero, e.g. `switchMap`\n\t * supersede) calls `ac.abort()` and unsubscribes the inner.\n\t * Signal-aware handlers (e.g. `fetch(url, {signal})`) actually stop.\n\t *\n\t * Each call mints a fresh node tied to a fresh `handler(args, ...)`\n\t * invocation — call `executeReactive` again for repeated invocations.\n\t *\n\t * @throws `Error` synchronously when `name` is not registered (no node is\n\t * constructed — the caller gets a pre-wiring failure rather than a\n\t * silent ERROR wave on an empty graph).\n\t */\n\texecuteReactive(name: string, args: Record<string, unknown>): Node<unknown> {\n\t\tconst tool = this._bundle.get(name);\n\t\tif (!tool) throw new Error(`toolRegistry: unknown tool \"${name}\"`);\n\t\treturn node<unknown>(\n\t\t\t[],\n\t\t\t(_data, actions) => {\n\t\t\t\tconst ac = new AbortController();\n\t\t\t\tlet inner: Node<unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = tool.handler(args, { signal: ac.signal });\n\t\t\t\t\tinner = handlerResultToNode(raw, ac.signal);\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// Synchronous throw from handler → ERROR. Producer cleanup\n\t\t\t\t\t// still aborts the controller for symmetry (no-op if no\n\t\t\t\t\t// signal listeners attached).\n\t\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst unsub = inner.subscribe((batch) => {\n\t\t\t\t\tactions.down(batch as Messages);\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: `executeReactive::${name}`,\n\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\tmeta: aiMeta(\"tool_execute_reactive\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tgetDefinition(name: string): ToolDefinition | undefined {\n\t\t// Pure read via the snapshot cache — avoids the bundle's\n\t\t// `wrapMutation` path (which would run the version-bump check and\n\t\t// any configured retention eviction on every lookup). Safe because\n\t\t// `getDefinition` is a boundary API, not a reactive fn body.\n\t\treturn this._bundle.entries.cache?.get(name);\n\t}\n}\n\nexport function toolRegistry(name: string, opts?: ToolRegistryOptions): ToolRegistryGraph {\n\treturn new ToolRegistryGraph(name, opts);\n}\n\n/**\n * Coerce a tool handler return value into a `Node<unknown>`.\n *\n * Differs from `fromAny` by treating **strings, arrays, plain iterables, and\n * scalar objects as single DATA values** rather than iterating them. A tool\n * handler that returns `\"hello world\"` should surface as one `DATA(\"hello\n * world\")`, not 11 `DATA` events of single characters; an array `[1, 2, 3]`\n * should surface as `DATA([1, 2, 3])`, not three separate emissions.\n *\n * Reactive shapes (Node, Promise, AsyncIterable) are unwrapped as expected.\n *\n * @internal\n */\nfunction handlerResultToNode(raw: unknown, signal: AbortSignal): Node<unknown> {\n\tif (isNodeLike(raw)) {\n\t\treturn raw as Node<unknown>;\n\t}\n\tif (raw != null && typeof (raw as PromiseLike<unknown>).then === \"function\") {\n\t\treturn fromPromise(raw as PromiseLike<unknown>, { signal });\n\t}\n\tif (raw != null && typeof raw === \"object\" && Symbol.asyncIterator in (raw as object)) {\n\t\treturn fromAsyncIter(raw as AsyncIterable<unknown>, { signal });\n\t}\n\t// String, number, boolean, null, undefined, plain object, array,\n\t// sync iterable — treat as a single DATA value via a resolved Promise so\n\t// `fromPromise`'s scalar-DATA-emit + COMPLETE semantics match the\n\t// pre-refactor `tools.execute` behavior (which always wrapped via async).\n\treturn fromPromise(Promise.resolve(raw), { signal });\n}\n","// ---------------------------------------------------------------------------\n// agentMemory — sugar over the memoryWith* composers (Unit 7 B).\n//\n// Thin wiring: distill() builds the core store (when no tiers configured);\n// optional capabilities delegate to the composer Graph subclasses in\n// `memory-composers.ts`. Each composer is a self-contained\n// `MemoryWithXxxGraph` that AgentMemoryGraph mounts on itself (Class B\n// audit, 2026-04-30) — teardown cascades via `Graph.destroy()`.\n//\n// **Phase 12.D (2026-04-30):** Migrated from the `Object.assign(graph, ...)`\n// factory pattern to `class extends Graph` (mirrors the\n// `MemoryWith*Graph` precedent). Required by Phase 13.G `agent(spec)` —\n// `AgentBundle.graph: AgentGraph<TIn, TOut>` consumers want `instanceof`\n// narrowing on agent-memory subgraphs.\n// ---------------------------------------------------------------------------\n\nimport { DATA, type Node, node, placeholderArgs, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, fromTimer, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype DistillBundle,\n\ttype DistillOptions,\n\tdistill,\n\ttype Extraction,\n} from \"../../base/composition/distill.js\";\nimport type { LLMAdapter } from \"../../utils/ai/adapters/core/types.js\";\nimport {\n\ttype MemoryWithTiersGraph,\n\tmemoryRetrieval,\n\tmemoryWithKG,\n\tmemoryWithTiers,\n\tmemoryWithVectors,\n} from \"../../utils/ai/memory/memory-composers.js\";\nimport type { RetrievalEntry, RetrievalQuery } from \"../../utils/ai/memory/retrieval.js\";\nimport type { MemoryTiersBundle, MemoryTiersOptions } from \"../../utils/ai/memory/tiers.js\";\nimport { llmConsolidator, llmExtractor } from \"../../utils/ai/prompts/prompt-call.js\";\nimport type { KnowledgeGraph, VectorIndexGraph } from \"../../utils/memory/index.js\";\n\nexport type AgentMemoryOptions<TMem = unknown> = {\n\tgraph?: GraphOptions;\n\t/** LLM adapter for extraction and consolidation. */\n\tadapter?: LLMAdapter;\n\t/** System prompt for the extractor LLM. */\n\textractPrompt?: string;\n\t/** Custom extractFn (overrides adapter + extractPrompt). */\n\textractFn?: (raw: unknown, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\t/** System prompt for the consolidation LLM. */\n\tconsolidatePrompt?: string;\n\t/** Custom consolidateFn (overrides adapter + consolidatePrompt). */\n\tconsolidateFn?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\t/** Reactive trigger for consolidation (caller supplies e.g. `fromTimer`). */\n\tconsolidateTrigger?: NodeInput<unknown>;\n\t/** Score function for budget packing (required). */\n\tscore: (mem: TMem, context: unknown) => number;\n\t/** Cost function for budget packing (required). */\n\tcost: (mem: TMem) => number;\n\t/** Token budget for compact view (default 2000). */\n\tbudget?: number;\n\t/** Context node for scoring. */\n\tcontext?: NodeInput<unknown>;\n\t/** Admission filter (default: admit all). */\n\tadmissionFilter?: (candidate: unknown) => boolean;\n\t/** Vector index dimensions (> 0 enables vector index for retrieval). */\n\tvectorDimensions?: number;\n\t/**\n\t * B12: optional accessor for an entry's hierarchical context breadcrumb\n\t * (e.g. `[\"projects\", \"auth\", \"tokens\"]`). When supplied alongside\n\t * `contextWeight > 0`, retrieval applies a score boost for entries whose\n\t * context shares a prefix with the query's `context`. Entries without\n\t * a breadcrumb are scored flatly.\n\t */\n\tcontextOf?: (mem: TMem) => readonly string[] | undefined;\n\t/**\n\t * B12: hierarchical context boost multiplier. Score is scaled by\n\t * `(1 + contextWeight * sharedDepth / queryDepth)` when both the query\n\t * and entry supply a `context`. Default: 0.\n\t */\n\tcontextWeight?: number;\n\n\t// --- In-factory composition (new) ---\n\n\t/** Extract embedding vector from a memory entry (enables vector index). */\n\tembedFn?: (mem: TMem) => readonly number[] | undefined;\n\t/** Enable knowledge graph for entity/relation tracking. */\n\tenableKnowledgeGraph?: boolean;\n\t/** Extract entities and relations from a memory entry. */\n\tentityFn?: (\n\t\tkey: string,\n\t\tmem: TMem,\n\t) =>\n\t\t| {\n\t\t\t\tentities?: Array<{ id: string; value: unknown }>;\n\t\t\t\trelations?: Array<{ from: string; to: string; relation: string; weight?: number }>;\n\t\t }\n\t\t| undefined;\n\n\t/** 3-tier storage configuration. Omit to use single-tier (existing behavior). */\n\ttiers?: MemoryTiersOptions<TMem>;\n\n\t/** Retrieval pipeline configuration. Requires vector index or knowledge graph. */\n\tretrieval?: {\n\t\t/** Max candidates from vector search (default 20). */\n\t\ttopK?: number;\n\t\t/** KG expansion depth in hops (default 1). */\n\t\tgraphDepth?: number;\n\t};\n\n\t/** Periodic reflection/consolidation configuration. */\n\treflection?: {\n\t\t/** Interval in ms between consolidation runs (default 300_000 = 5 min). */\n\t\tinterval?: number;\n\t\t/** Enable/disable periodic reflection (default true when consolidateFn is available). */\n\t\tenabled?: boolean;\n\t};\n};\n\n/**\n * Pre-wired agentic memory graph. Sugar over `distill` plus the\n * `memoryWithVectors` / `memoryWithKG` / `memoryWithTiers` / `memoryRetrieval`\n * composers. Power users who want a subset of capabilities can call those\n * composers directly; this class bundles them into one ergonomic Graph subclass.\n *\n * Mounts:\n * - `tiers/*` — present when `opts.tiers` configured (replaces the\n * default distill bundle).\n * - `vectors/*` — present when `opts.vectorDimensions > 0 && opts.embedFn`.\n * - `knowledge/*` — present when `opts.enableKnowledgeGraph`.\n * - `retrieval/*` — present when vectors or kg configured.\n *\n * When `opts.tiers` is omitted, `store` / `compact` / `size` are added as\n * top-level nodes on this graph (visible in `describe()` / `explain()`).\n */\nexport class AgentMemoryGraph<TMem = unknown> extends Graph {\n\treadonly distillBundle: DistillBundle<TMem>;\n\treadonly compact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\treadonly size: Node<number>;\n\t/** Vector index bundle (null if not enabled). */\n\treadonly vectors: VectorIndexGraph<TMem> | null;\n\t/** Knowledge graph (null if not enabled). */\n\treadonly kg: KnowledgeGraph<unknown, string> | null;\n\t/** Memory tiers bundle (null if not configured). */\n\treadonly memoryTiers: MemoryTiersBundle<TMem> | null;\n\t/**\n\t * The mounted `MemoryWithTiersGraph` subgraph (null when `opts.tiers` was\n\t * omitted). Surfaces the inner graph for `describe()` / `explain()` walks\n\t * and for callers that need direct access to the tiers subgraph (e.g.\n\t * to register additional disposers or attach storage). Companion to\n\t * `memoryTiers`, which carries only the bundle's reactive surface (B5e).\n\t */\n\treadonly tiers: MemoryWithTiersGraph<unknown, TMem> | null;\n\t/**\n\t * Reactive consumer API. Given a reactive `RetrievalQuery | null` source,\n\t * returns a `Node` emitting the packed retrieval results. Composable with\n\t * graph topology — subscribe it, chain it into `promptNode`, or switchMap\n\t * over a user-input node.\n\t *\n\t * Each call mounts its own per-input subgraph at\n\t * `retrieval::retrieve_${id}` (via `MemoryRetrievalGraph`); concurrent\n\t * calls don't share state mirrors. One-shot consumers wrap with\n\t * `awaitSettled(retrieveReactive(query))`.\n\t *\n\t * Null when no retrieval pipeline is configured.\n\t *\n\t * **QA F-9 (2026-04-30):** the prior `retrieval` / `retrievalTrace`\n\t * shared state-node mirrors have been dropped. Use `retrieveReactive`\n\t * for per-call reactive results; one-shot trace consumers should\n\t * subscribe to the projection's upstream `result` derived directly\n\t * via `view.target.resolve(\"retrieval::retrieve_${id}::result\")`.\n\t */\n\treadonly retrieveReactive:\n\t\t| ((queryInput: NodeInput<RetrievalQuery | null>) => Node<ReadonlyArray<RetrievalEntry<TMem>>>)\n\t\t| null;\n\n\tconstructor(name: string, source: NodeInput<unknown>, opts: AgentMemoryOptions<TMem>) {\n\t\tsuper(name, opts.graph);\n\n\t\t// --- Extract function resolution ---\n\t\t// /qa A3 (2026-04-30): validate BEFORE tagFactory so an invalid-opts\n\t\t// throw doesn't leave a tagged-but-empty Graph instance behind.\n\t\tlet rawExtractFn: (\n\t\t\traw: unknown,\n\t\t\texisting: ReadonlyMap<string, TMem>,\n\t\t) => NodeInput<Extraction<TMem>>;\n\t\tif (opts.extractFn) {\n\t\t\trawExtractFn = opts.extractFn;\n\t\t} else if (opts.adapter && opts.extractPrompt) {\n\t\t\trawExtractFn = llmExtractor<unknown, TMem>(opts.extractPrompt, { adapter: opts.adapter });\n\t\t} else {\n\t\t\tthrow new Error(\"agentMemory: provide either extractFn or adapter + extractPrompt\");\n\t\t}\n\n\t\t// Tier 1.5.3 Phase 2.5 (DG1=B): tag the Graph with its constructing\n\t\t// factory so `describe()` exposes provenance. Opts contain non-JSON\n\t\t// fields (`adapter`, `extractFn`, `embedFn`, `score`, `cost`, `evict`,\n\t\t// callbacks, etc.) so route through `placeholderArgs` (DG2=ii).\n\t\tthis.tagFactory(\"agentMemory\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\t\t// Tier 1.5.4 — distill's `extractFn` is now reactive (called once with\n\t\t// nodes). Adapt the AgentMemoryOptions callback shape via switchMap +\n\t\t// closure-mirror for `existing` (COMPOSITION-GUIDE §40 recipe).\n\t\t// QA F9: register the closure-mirror's unsub with the host graph so\n\t\t// `graph.destroy()` reclaims it — was previously leaked.\n\t\t//\n\t\t// **Phase 16 attempt (2026-04-29) reverted.** Tried `withLatestFrom(\n\t\t// rawNode, existingNode) + switchMap`; this is the WRONG migration per\n\t\t// COMPOSITION-GUIDE §28. **Phase 10.5 (same-day partial-flag flip on\n\t\t// `withLatestFrom`)** removes the initial-pair drop, but this site stays\n\t\t// on closure-mirror form pending Phase 11 restricted signatures. See\n\t\t// `archive/docs/SESSION-graph-narrow-waist.md` § \"Status of existing\n\t\t// modifications\" + § \"Phase 10.5\".\n\t\tconst extractFn = (\n\t\t\trawNode: Node<unknown>,\n\t\t\texistingNode: Node<ReadonlyMap<string, TMem>>,\n\t\t): NodeInput<Extraction<TMem>> => {\n\t\t\tlet latestExisting: ReadonlyMap<string, TMem> =\n\t\t\t\t(existingNode.cache as ReadonlyMap<string, TMem> | undefined) ?? new Map();\n\t\t\tconst unsubExisting = existingNode.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] === DATA) latestExisting = m[1] as ReadonlyMap<string, TMem>;\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.addDisposer(unsubExisting);\n\t\t\treturn switchMap(rawNode, (raw) => {\n\t\t\t\tif (raw == null) return { upsert: [] };\n\t\t\t\treturn rawExtractFn(raw, latestExisting);\n\t\t\t});\n\t\t};\n\n\t\t// --- Admission filter ---\n\t\tlet filteredSource = source;\n\t\tif (opts.admissionFilter) {\n\t\t\tconst srcNode = fromAny(source);\n\t\t\tconst filter = opts.admissionFilter;\n\t\t\tfilteredSource = node(\n\t\t\t\t[srcNode],\n\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t\t);\n\t\t\t\t\tconst raw = data[0];\n\t\t\t\t\tif (filter(raw)) {\n\t\t\t\t\t\tactions.emit(raw);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// EC1 (qa 2026-04-30): emitting `undefined` would violate spec §5.12\n\t\t\t\t\t\t// (undefined is the protocol SENTINEL — TopicGraph.publish even\n\t\t\t\t\t\t// throws on it). Downstream `batch.at(-1) : ctx.prevData[i]`\n\t\t\t\t\t\t// would also resolve `undefined` back to the prior accepted\n\t\t\t\t\t\t// value, leaking past-the-filter. Emit a tier-3 RESOLVED so the\n\t\t\t\t\t\t// wave settles cleanly without surfacing a stale DATA.\n\t\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ name: \"admissionFilter\", describeKind: \"derived\" },\n\t\t\t);\n\t\t}\n\n\t\t// --- Consolidation ---\n\t\tlet consolidateFn:\n\t\t\t| ((entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>)\n\t\t\t| undefined;\n\t\tif (opts.consolidateFn) {\n\t\t\tconsolidateFn = opts.consolidateFn;\n\t\t} else if (opts.adapter && opts.consolidatePrompt) {\n\t\t\tconsolidateFn = llmConsolidator<TMem>(opts.consolidatePrompt, { adapter: opts.adapter });\n\t\t}\n\n\t\t// --- Reflection: default consolidateTrigger from fromTimer ---\n\t\tlet consolidateTrigger = opts.consolidateTrigger;\n\t\tif (!consolidateTrigger && consolidateFn && opts.reflection?.enabled !== false) {\n\t\t\tconst interval = opts.reflection?.interval ?? 300_000;\n\t\t\tconsolidateTrigger = fromTimer(interval, { period: interval });\n\t\t}\n\n\t\t// --- Build distill bundle (the core) ---\n\t\t// Tier 4.1 B (2026-04-29): when tiers are configured, `memoryWithTiers`\n\t\t// is the construction site for the distill bundle so it can wire\n\t\t// `reactiveMap.retention` into the store at construction (no §7 cycle).\n\t\t// When tiers are NOT configured, agentMemory calls `distill` directly.\n\t\tconst distillOpts: DistillOptions<TMem> = {\n\t\t\tscore: opts.score,\n\t\t\tcost: opts.cost,\n\t\t\tbudget: opts.budget ?? 2000,\n\t\t\tcontext: opts.context,\n\t\t\tconsolidate: consolidateFn,\n\t\t\tconsolidateTrigger,\n\t\t};\n\n\t\tlet distillBundle: DistillBundle<TMem>;\n\t\tlet memoryTiersBundle: MemoryTiersBundle<TMem> | null = null;\n\t\tlet tiersSubgraph: MemoryWithTiersGraph<unknown, TMem> | null = null;\n\t\tif (opts.tiers) {\n\t\t\tconst tiersGraph = memoryWithTiers<unknown, TMem>({\n\t\t\t\t// User customization first; canonical agent-memory-level overrides\n\t\t\t\t// last so they always win even if `MemoryTiersOptions` later adds\n\t\t\t\t// any of the same keys.\n\t\t\t\t...opts.tiers,\n\t\t\t\tname: \"tiers\",\n\t\t\t\tsource: filteredSource,\n\t\t\t\textractFn,\n\t\t\t\tscore: opts.score,\n\t\t\t\tcost: opts.cost,\n\t\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : { budget: 2000 }),\n\t\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\t\t...(consolidateFn !== undefined ? { consolidate: consolidateFn } : {}),\n\t\t\t\t...(consolidateTrigger !== undefined ? { consolidateTrigger } : {}),\n\t\t\t});\n\t\t\tthis.mount(\"tiers\", tiersGraph);\n\t\t\tdistillBundle = tiersGraph.store;\n\t\t\tmemoryTiersBundle = tiersGraph.tiers;\n\t\t\ttiersSubgraph = tiersGraph;\n\t\t} else {\n\t\t\tdistillBundle = distill<unknown, TMem>(filteredSource, extractFn, distillOpts);\n\t\t\tthis.add(distillBundle.store.entries, { name: \"store\" });\n\t\t\tthis.add(distillBundle.compact, { name: \"compact\" });\n\t\t\tthis.add(distillBundle.size, { name: \"size\" });\n\t\t}\n\n\t\t// --- Vector index (composer) ---\n\t\tlet vectors: VectorIndexGraph<TMem> | null = null;\n\t\tif (opts.vectorDimensions && opts.vectorDimensions > 0 && opts.embedFn) {\n\t\t\tconst vectorsGraph = memoryWithVectors<TMem>({\n\t\t\t\tname: \"vectors\",\n\t\t\t\tstore: distillBundle,\n\t\t\t\tdimension: opts.vectorDimensions,\n\t\t\t\tembedFn: opts.embedFn,\n\t\t\t});\n\t\t\tthis.mount(\"vectors\", vectorsGraph);\n\t\t\tvectors = vectorsGraph.vectors;\n\t\t}\n\n\t\t// --- Knowledge graph (composer) ---\n\t\tlet kg: KnowledgeGraph<unknown, string> | null = null;\n\t\tif (opts.enableKnowledgeGraph) {\n\t\t\tconst kgGraph = memoryWithKG<TMem>({\n\t\t\t\tname: \"knowledge\",\n\t\t\t\tstore: distillBundle,\n\t\t\t\tkgName: `${name}-kg`,\n\t\t\t\tmountPath: \"knowledge-kg\",\n\t\t\t\t...(opts.entityFn !== undefined ? { entityFn: opts.entityFn } : {}),\n\t\t\t});\n\t\t\tthis.mount(\"knowledge\", kgGraph);\n\t\t\tkg = kgGraph.kg;\n\t\t}\n\n\t\t// --- Retrieval pipeline (composer) ---\n\t\tlet retrieveReactive:\n\t\t\t| ((\n\t\t\t\t\tqueryInput: NodeInput<RetrievalQuery | null>,\n\t\t\t ) => Node<ReadonlyArray<RetrievalEntry<TMem>>>)\n\t\t\t| null = null;\n\n\t\tif (vectors || kg) {\n\t\t\tconst retrievalGraph = memoryRetrieval<TMem>({\n\t\t\t\tname: \"retrieval\",\n\t\t\t\tstore: distillBundle,\n\t\t\t\tvectors,\n\t\t\t\tkg,\n\t\t\t\tscore: opts.score,\n\t\t\t\tcost: opts.cost,\n\t\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : {}),\n\t\t\t\t...(opts.retrieval?.topK !== undefined ? { topK: opts.retrieval.topK } : {}),\n\t\t\t\t...(opts.retrieval?.graphDepth !== undefined\n\t\t\t\t\t? { graphDepth: opts.retrieval.graphDepth }\n\t\t\t\t\t: {}),\n\t\t\t\t...(opts.contextOf !== undefined ? { contextOf: opts.contextOf } : {}),\n\t\t\t\t...(opts.contextWeight !== undefined ? { contextWeight: opts.contextWeight } : {}),\n\t\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\t});\n\t\t\tthis.mount(\"retrieval\", retrievalGraph);\n\t\t\tretrieveReactive = retrievalGraph.retrieveReactive.bind(retrievalGraph);\n\t\t}\n\n\t\tthis.distillBundle = distillBundle;\n\t\tthis.compact = distillBundle.compact;\n\t\tthis.size = distillBundle.size;\n\t\tthis.vectors = vectors;\n\t\tthis.kg = kg;\n\t\tthis.memoryTiers = memoryTiersBundle;\n\t\tthis.tiers = tiersSubgraph;\n\t\tthis.retrieveReactive = retrieveReactive;\n\t}\n}\n\n/**\n * Pre-wired agentic memory graph. Sugar over `distill` plus the\n * `memoryWithVectors` / `memoryWithKG` / `memoryWithTiers` / `memoryRetrieval`\n * composers. Power users who want a subset of capabilities can call those\n * composers directly; this factory bundles them into one ergonomic call.\n *\n * Returns an {@link AgentMemoryGraph} subclass instance — `instanceof\n * AgentMemoryGraph` narrows in callers (e.g. Phase 13.G `agent(spec)`).\n */\nexport function agentMemory<TMem = unknown>(\n\tname: string,\n\tsource: NodeInput<unknown>,\n\topts: AgentMemoryOptions<TMem>,\n): AgentMemoryGraph<TMem> {\n\treturn new AgentMemoryGraph<TMem>(name, source, opts);\n}\n","/**\n * Budget-constrained reactive memory composition (roadmap §3.2b).\n *\n * Moved to base/composition/distill.ts during cleave A2.\n */\n\nimport { batch, factoryTag, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport {\n\tfromAny,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapOptions,\n\treactiveMap,\n\tswitchMap,\n\twithLatestFrom,\n} from \"@graphrefly/pure-ts/extra\";\nimport { forEach } from \"../sources/async.js\";\n\nfunction isNodeLike<T>(value: unknown): value is Node<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"cache\" in (value as Node<T>) &&\n\t\ttypeof (value as Node<T>).subscribe === \"function\"\n\t);\n}\n\nexport type Extraction<TMem> = {\n\tupsert: Array<{ key: string; value: TMem }>;\n\tremove?: string[];\n};\n\nexport type DistillOptions<TMem> = {\n\tscore: (mem: TMem, context: unknown) => number;\n\tcost: (mem: TMem) => number;\n\tbudget?: number;\n\tevict?: (key: string, mem: TMem) => boolean | Node<boolean>;\n\tconsolidate?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\tconsolidateTrigger?: NodeInput<unknown>;\n\tcontext?: NodeInput<unknown>;\n\tmapOptions?: ReactiveMapOptions<string, TMem>;\n};\n\nexport type DistillBundle<TMem> = {\n\tstore: ReactiveMapBundle<string, TMem>;\n\tcompact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\tsize: Node<number>;\n};\n\nfunction keepalive(node: Node): void {\n\tnode.subscribe(() => undefined);\n}\n\n/**\n * Defensive snapshot → ReadonlyMap coercion (D2 /qa lock, Tier 9.1).\n *\n * `ReactiveMapBundle.entries` always emits a real `Map` on the live emit\n * path. The non-Map case happens on snapshot **restore**: the default\n * `JsonGraphCodec` serializes a `Map` to `null`/`{}`/`[]` depending on the\n * codec configuration, and `Graph.restore` writes that decoded value back\n * to the cache. A naive `(snapshot as ReadonlyMap) ?? new Map()` would\n * pass a plain object through and then `.entries()` / `.size` access would\n * silently yield wrong results (or throw). The runtime `instanceof Map`\n * check below restores the safety net the previous `mapFromSnapshot` helper\n * provided before its initial deletion in Tier 10.1.\n */\nfunction mapFromSnapshot<TMem>(snapshot: unknown): ReadonlyMap<string, TMem> {\n\tif (snapshot instanceof Map) return snapshot as ReadonlyMap<string, TMem>;\n\treturn new Map<string, TMem>();\n}\n\nfunction applyExtraction<TMem>(\n\tstore: ReactiveMapBundle<string, TMem>,\n\textraction: Extraction<TMem>,\n): void {\n\tif (!Array.isArray(extraction.upsert)) {\n\t\tthrow new TypeError(\"distill extraction requires upsert: Array<{ key, value }>\");\n\t}\n\tbatch(() => {\n\t\tfor (const { key, value } of extraction.upsert) {\n\t\t\tstore.set(key, value);\n\t\t}\n\t\tfor (const key of extraction.remove ?? []) {\n\t\t\tstore.delete(key);\n\t\t}\n\t});\n}\n\n/**\n * Budget-constrained reactive memory composition.\n *\n * **Tier 1.5.4 (Session A.5 lock, 2026-04-27):** `extractFn` receives the\n * source and existing-store as `Node`s. Distill calls `extractFn` ONCE at\n * wiring time and consumes the returned stream of extractions. The user\n * controls reactive composition — wrap with `switchMap` for cancel-on-new-input,\n * `mergeMap` for parallel, `derived` for sync transforms. See COMPOSITION-GUIDE\n * §40 for the recipe.\n */\nexport function distill<TRaw, TMem>(\n\tsource: NodeInput<TRaw>,\n\textractFn: (\n\t\traw: Node<TRaw>,\n\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t) => NodeInput<Extraction<TMem>>,\n\topts: DistillOptions<TMem>,\n): DistillBundle<TMem> {\n\tconst sourceNode = fromAny(source);\n\tconst store = reactiveMap<string, TMem>(opts.mapOptions ?? {});\n\tconst budget = opts.budget ?? 2000;\n\tconst hasContext = opts.context !== undefined && opts.context !== null;\n\tconst contextNode = hasContext ? fromAny(opts.context) : node<unknown>([], { initial: null });\n\n\t// `latestStore` (formerly a §28 closure-mirror) is no longer needed —\n\t// Phase 10.5 (`withLatestFrom` flipped to `partial: false`) fixed the\n\t// W1 initial-pair drop. `consolidate` now uses\n\t// `withLatestFrom(trigger, store.entries)` below to pair each trigger\n\t// with the latest store snapshot via a real reactive edge (visible in\n\t// `describe()`). The `mapFromSnapshot` transform runs inside the\n\t// switchMap fn body.\n\n\t// Tier 1.5.4: one-shot wire. User's `extractFn` returns the reactive\n\t// extraction stream — distill just `forEach`s and applies. No internal\n\t// switchMap; user picks the cancellation / queueing semantics.\n\tconst extractionStream = fromAny(\n\t\textractFn(sourceNode, store.entries as Node<ReadonlyMap<string, TMem>>),\n\t);\n\tforEach(extractionStream, (extraction) => {\n\t\tapplyExtraction(store, extraction);\n\t});\n\n\tif (opts.evict) {\n\t\t// Track active verdict-node subscriptions so we can react to Node<boolean> changes.\n\t\tconst verdictUnsubs = new Map<string, () => void>();\n\n\t\tconst evictionKeys = node<string[]>(\n\t\t\t[store.entries],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\t\tconst out: string[] = [];\n\t\t\t\tconst entries = mapFromSnapshot<TMem>(snapshot);\n\t\t\t\t// Clean up verdict subscriptions for removed keys.\n\t\t\t\tfor (const key of verdictUnsubs.keys()) {\n\t\t\t\t\tif (!entries.has(key)) {\n\t\t\t\t\t\tverdictUnsubs.get(key)!();\n\t\t\t\t\t\tverdictUnsubs.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, mem] of entries) {\n\t\t\t\t\tconst verdict = opts.evict!(key, mem);\n\t\t\t\t\tif (isNodeLike<boolean>(verdict)) {\n\t\t\t\t\t\t// Subscribe if not already — push-on-subscribe fires with\n\t\t\t\t\t\t// the verdict's current value on first subscribe, so an\n\t\t\t\t\t\t// already-true verdict deletes via the callback without\n\t\t\t\t\t\t// needing a `verdict.cache` read (closes P3 audit #3).\n\t\t\t\t\t\t// Future transitions to `true` flow through the same path.\n\t\t\t\t\t\tif (!verdictUnsubs.has(key)) {\n\t\t\t\t\t\t\tconst unsub = forEach(verdict, (val) => {\n\t\t\t\t\t\t\t\tif (val === true && store.has(key)) {\n\t\t\t\t\t\t\t\t\tstore.delete(key);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tverdictUnsubs.set(key, unsub);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof verdict === \"boolean\") {\n\t\t\t\t\t\tif (verdict) out.push(key);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthrow new TypeError(\"distill evict() must return boolean or Node<boolean>\");\n\t\t\t\t}\n\t\t\t\tactions.emit(out);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\" },\n\t\t);\n\t\tforEach(evictionKeys, (keys) => {\n\t\t\tfor (const key of keys) store.delete(key);\n\t\t});\n\t}\n\n\tconst hasConsolidateTrigger =\n\t\topts.consolidateTrigger !== undefined && opts.consolidateTrigger !== null;\n\tif (opts.consolidate && hasConsolidateTrigger) {\n\t\tconst consolidateTriggerNode = fromAny(opts.consolidateTrigger);\n\t\tconst consolidatePaired = withLatestFrom(\n\t\t\tconsolidateTriggerNode,\n\t\t\tstore.entries as Node<unknown>,\n\t\t);\n\t\tconst consolidationStream = switchMap(consolidatePaired, ([, entries]) =>\n\t\t\topts.consolidate!(mapFromSnapshot<TMem>(entries)),\n\t\t);\n\t\tforEach(consolidationStream, (extraction) => {\n\t\t\tapplyExtraction(store, extraction);\n\t\t});\n\t}\n\n\tconst compact = node<Array<{ key: string; value: TMem; score: number }>>(\n\t\t[store.entries, contextNode],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0];\n\t\t\tconst context = data[1];\n\t\t\tconst map = mapFromSnapshot<TMem>(snapshot);\n\t\t\tconst entries = [...map.entries()].map(([key, value]) => ({\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t\tscore: opts.score(value, context),\n\t\t\t\tcost: opts.cost(value),\n\t\t\t}));\n\t\t\tentries.sort((a, b) => b.score - a.score);\n\n\t\t\tconst packed: Array<{ key: string; value: TMem; score: number }> = [];\n\t\t\tlet remaining = budget;\n\t\t\tfor (const item of entries) {\n\t\t\t\tif (item.cost <= remaining) {\n\t\t\t\t\tpacked.push({ key: item.key, value: item.value, score: item.score });\n\t\t\t\t\tremaining -= item.cost;\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(packed);\n\t\t},\n\t\t{ describeKind: \"derived\", meta: { ...factoryTag(\"distill\", { budget }) } },\n\t);\n\n\tconst size = node<number>(\n\t\t[store.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst batch0 = batchData[0];\n\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\tactions.emit(mapFromSnapshot<TMem>(snapshot).size);\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tkeepalive(compact);\n\tkeepalive(size);\n\n\treturn { store, compact, size };\n}\n","/**\n * Async sources, sinks, and multicast — presentation layer.\n *\n * `fromPromise`, `fromAsyncIter`, `fromAny` are substrate primitives; they are\n * re-exported here from `@graphrefly/pure-ts` for ergonomic single-import use.\n * This file owns the presentation-only async utilities: `defer`, `forEach`,\n * `toArray`, `share`, `replay`, `cached`, `shareReplay`.\n *\n * `singleFromAny` and `singleNodeFromAny` (keyed singleflight) live in\n * `base/composition/single-from-any.ts`.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\tRESOLVED,\n\tSTART,\n} from \"@graphrefly/pure-ts/core\";\nimport { type AsyncSourceOpts, type NodeInput, sourceOpts } from \"@graphrefly/pure-ts/extra\";\n\n/** Options for presentation-layer async operators: NodeOptions without `describeKind`. */\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n// Import fromAny from substrate — used internally by defer. The three async\n// substrate sources (fromAny, fromAsyncIter, fromPromise) are already\n// re-exported from @graphrefly/pure-ts; do NOT re-export here to avoid\n// duplicate-export conflicts at the root barrel level.\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\n\n/**\n * Lazily constructs a {@link Node} from a thunk that runs at **activation\n * time** (first subscriber after a teardown to zero sinks), not factory time.\n *\n * **Resubscribable by default.** Diverges from `fromPromise` / `fromIter` /\n * `fromAsyncIter` (which are single-shot — second subscriber sees the cached\n * terminal value). `defer`'s contract matches RxJS `defer`: every fresh\n * activation cycle re-runs the thunk. To opt out and get one-shot semantics,\n * pass `{ resubscribable: false }`.\n *\n * **Sharing across overlapping subscribers.** The thunk only re-runs on a\n * fresh activation cycle (zero → one sink). Overlapping subscribers share\n * the single activation; the thunk does NOT re-run for each subscriber. If\n * the thunk returns an existing `Node`, that Node is shared across activations\n * — `defer` will subscribe to it on each activation but does not isolate state\n * across subscribers. For per-subscriber isolation, the thunk must construct\n * a fresh source (`state(...)`, `fromPromise(fetch(...))`, etc.) on each call.\n *\n * **Use cases:**\n * - Lazy upstream construction (avoid eager evaluation of expensive factories\n * at module load — the thunk runs only when something subscribes).\n * - Per-activation resource construction (open a connection / file handle on\n * subscribe, when paired with full teardown between sessions).\n * - Bridging non-Node inputs (Promise, AsyncIterable, Iterable, scalar) into\n * the graph behind a lazy boundary.\n *\n * The thunk's return value is bridged via {@link fromAny}. Errors thrown by\n * the thunk surface as a single `[[ERROR, err]]` on the output (with `err`\n * coerced to a non-`undefined` value to satisfy spec §1.3 — bare `throw` and\n * `throw undefined` are wrapped in a `defer: thunk threw undefined` Error).\n *\n * Upstream messages are forwarded transparently (DIRTY / DATA / RESOLVED /\n * COMPLETE / ERROR / INVALIDATE / PAUSE / RESUME / TEARDOWN), preserving\n * batch boundaries. The producer's own `START` handshake is delivered to\n * subscribers automatically; the upstream's `START` is filtered.\n *\n * @param thunk - Called on each activation; returns the upstream input.\n * @param opts - Forwarded to `fromAny` (e.g. `signal` for async inputs).\n * `signal` is only consumed by `fromAny` for async input shapes (Promise,\n * AsyncIterable); it does NOT abort a Node-input or scalar-input defer.\n * @returns `Node<T>` — lazy upstream-on-activation.\n *\n * @example\n * ```ts\n * import { defer } from \"@graphrefly/graphrefly-ts\";\n *\n * // Lazy fetch — runs on the first activation, NOT at factory time.\n * // Each fresh activation cycle (after teardown) re-runs the thunk →\n * // a new fetch. Overlapping subscribers share the single activation.\n * const live = defer(() => fetch(\"/api/feed\").then((r) => r.json()));\n * ```\n *\n * @category extra\n */\nexport function defer<T>(thunk: () => NodeInput<T>, opts?: AsyncSourceOpts): Node<T> {\n\t// A4: strip `signal` before forwarding to NodeOptions — sibling sources\n\t// (fromTimer / fromPromise / fromAsyncIter) destructure first; signal\n\t// continues to flow into fromAny(input, opts) for async input shapes.\n\tconst { signal: _sig, ...nodeOpts } = (opts ?? {}) as AsyncSourceOpts;\n\tconst sOpts = sourceOpts<T>(nodeOpts);\n\tconst merged = sOpts.resubscribable === undefined ? { ...sOpts, resubscribable: true } : sOpts;\n\treturn node<T>((_data, a) => {\n\t\tlet unsub: (() => void) | undefined;\n\t\tlet stopped = false;\n\t\ttry {\n\t\t\tconst input = thunk();\n\t\t\t// `iter: true` preserves defer's RxJS-aligned per-element\n\t\t\t// streaming for sync iterable thunk returns (post DS-13.5\n\t\t\t// fromAny default flip; defer's documented contract is\n\t\t\t// \"forwards iterable values\" per-element).\n\t\t\tconst src = fromAny(input, { ...opts, iter: true });\n\t\t\tunsub = src.subscribe((msgs) => {\n\t\t\t\tif (stopped) return;\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tconst t = m[0];\n\t\t\t\t\tif (t === START) continue; // producer's own START is delivered separately\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\t} else if (t === COMPLETE) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\tbreak; // A2: don't forward post-terminal messages in the same batch\n\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\ta.down([[ERROR, m[1]]]);\n\t\t\t\t\t\tbreak; // A2\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Forward DIRTY / RESOLVED / INVALIDATE / PAUSE / RESUME /\n\t\t\t\t\t\t// TEARDOWN, plus any unknown types (spec §1.3.6 forward-compat).\n\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// A5: spec §1.3 — ERROR payload must not be undefined. Wrap a\n\t\t\t// `throw` or `throw undefined` so dispatch doesn't reject the emit.\n\t\t\tconst safe = err === undefined ? new Error(\"defer: thunk threw undefined\") : err;\n\t\t\ta.down([[ERROR, safe]]);\n\t\t}\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tstopped = true;\n\t\t\t\tunsub?.();\n\t\t\t},\n\t\t};\n\t}, merged);\n}\n\n/**\n * Subscribes immediately and runs `fn` for each upstream `DATA`; returns unsubscribe.\n *\n * @param source - Upstream node.\n * @param fn - Side effect per value.\n * @param opts - Effect node options.\n * @returns Unsubscribe function (idempotent).\n *\n * @example\n * ```ts\n * import { forEach, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const u = forEach(state(1), (v) => console.log(v));\n * u();\n * ```\n *\n * @category extra\n */\nexport function forEach<T>(source: Node<T>, fn: (value: T) => void, opts?: ExtraOpts): () => void {\n\tconst inner = node(\n\t\t[source as Node],\n\t\t(data, _actions) => {\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) fn(v as T);\n\t\t\t}\n\t\t},\n\t\t{ describeKind: \"effect\", ...opts } as NodeOptions,\n\t);\n\treturn inner.subscribe(() => {});\n}\n\n/**\n * Buffers every `DATA`; on upstream `COMPLETE` emits one `DATA` with the full array then `COMPLETE`.\n *\n * @param source - Upstream node.\n * @param opts - Optional node options (derived describe kind).\n * @returns `Node<T[]>` — single array emission before completion.\n *\n * @example\n * ```ts\n * import { of, toArray } from \"@graphrefly/graphrefly-ts\";\n *\n * toArray(of(1, 2, 3));\n * ```\n *\n * @category extra\n */\nexport function toArray<T>(source: Node<T>, opts?: ExtraOpts): Node<T[]> {\n\t// Lock 6.D (Phase 13.6.B): clear the accumulator buffer on\n\t// deactivation so a resubscribable toArray restarts with an empty\n\t// array on the next cycle — pre-flip this came for free via\n\t// `_deactivate`'s store wipe.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<T[]>(\n\t\t[source as Node],\n\t\t(data, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.buf;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!ctx.store.buf) ctx.store.buf = [];\n\t\t\tconst buf = ctx.store.buf as T[];\n\t\t\t// Accumulate DATA first — must happen before the COMPLETE check so\n\t\t\t// that a same-wave DATA+COMPLETE batch (e.g. fromTimer one-shot,\n\t\t\t// fromIter last item) is included in the emitted array.\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) buf.push(v as T);\n\t\t\t}\n\t\t\t// COMPLETE: emit accumulated array then complete.\n\t\t\t// ERROR: autoError propagates; do NOT emit the partial buffer.\n\t\t\tif (ctx.terminalDeps[0] === true) {\n\t\t\t\tactions.emit([...buf]);\n\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\t// RESOLVED wave: propagate RESOLVED. Covers first-wave case; after first\n\t\t\t// call the pre-fn skip handles this automatically.\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t}\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\t...opts,\n\t\t} as NodeOptions<T[]>,\n\t);\n}\n\n/**\n * Multicasts upstream: one subscription to `source` while this wrapper has subscribers (via {@link producer}).\n *\n * @param source - Upstream node to share.\n * @param opts - Producer options; `initial` seeds from `source.cache` when set by factory.\n * @returns `Node<T>` — hot ref-counted bridge.\n *\n * @example\n * ```ts\n * import { share, state } from \"@graphrefly/graphrefly-ts\";\n *\n * share(state(0));\n * ```\n *\n * @category extra\n */\nexport function share<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn node<T>(\n\t\t(_data, a) => ({\n\t\t\tonDeactivation: source.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache },\n\t);\n}\n\n/**\n * Like {@link share} with a bounded replay buffer: new subscribers receive the last `bufferSize`\n * `DATA` payloads (as separate batches) before live updates.\n *\n * @param source - Upstream node.\n * @param bufferSize - Maximum past values to replay (≥ 1).\n * @param opts - Producer options.\n * @returns `Node<T>` — multicast with replay on subscribe.\n *\n * @example\n * ```ts\n * import { replay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * replay(state(0), 3);\n * ```\n *\n * @category extra\n */\nexport function replay<T>(source: Node<T>, bufferSize: number, opts?: ExtraOpts): Node<T> {\n\tif (bufferSize < 1) throw new RangeError(\"replay expects bufferSize >= 1\");\n\t// Spec §2.5 / Lock 6.G: the built-in `replayBuffer` NodeOption retains the\n\t// last-N outgoing DATA and `defaultOnSubscribe` delivers them to a late\n\t// subscriber INSTEAD of the cache-DATA push — so there is no double-deliver\n\t// of the most-recent value. Supersedes the old `wrapSubscribeHook` +\n\t// manual-buffer pattern (which flushed the buffer AND then push-on-\n\t// subscribed the cache, double-delivering the last value).\n\treturn node<T>(\n\t\t(_data, a) => ({\n\t\t\tonDeactivation: source.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache, replayBuffer: bufferSize },\n\t);\n}\n\n/**\n * {@link replay} with `bufferSize === 1` — replays the latest `DATA` to new subscribers.\n *\n * @param source - Upstream node.\n * @param opts - Producer options.\n * @returns `Node<T>` — share + last-value replay.\n *\n * @example\n * ```ts\n * import { cached, state } from \"@graphrefly/graphrefly-ts\";\n *\n * cached(state(0));\n * ```\n *\n * @category extra\n */\nexport function cached<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn replay(source, 1, opts);\n}\n\n// ——————————————————————————————————————————————————————————————\n// RxJS-compatible aliases\n// ——————————————————————————————————————————————————————————————\n\n/**\n * RxJS-named alias for {@link replay} — multicast with a replay buffer of size `bufferSize`.\n *\n * @param source - Upstream node.\n * @param bufferSize - Replay depth (≥ 1).\n * @param opts - Producer options.\n * @returns Same behavior as `replay`.\n *\n * @example\n * ```ts\n * import { shareReplay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * shareReplay(state(0), 5);\n * ```\n *\n * @category extra\n */\nexport const shareReplay = replay;\n","// ---------------------------------------------------------------------------\n// memory composers — Unit 7 C-factoring (2026-04-23 doc decision).\n//\n// Each composer attaches one capability (vectors, KG, tiers, retrieval) to a\n// `DistillBundle`. `agentMemory` continues to ship as the ergonomic sugar\n// over the full pipeline; power users who want a subset call these factories\n// directly.\n//\n// Class B audit (2026-04-30): the composers were migrated from\n// bundle-returning factories to **Graph subclasses** so they participate in\n// `describe()` / `destroy()` like every other Phase 4+ Graph (mirrors\n// `AuditTrailGraph`, `PolicyGateGraph`, `CqrsGraph`). The factory functions\n// remain as ergonomic constructors (`memoryWithVectors(opts) → MemoryWithVectorsGraph`).\n//\n// Tier 4.1 B + 4.3 B (2026-04-29): `memoryWithTiers` is the construction site\n// for the distill bundle when tiers are configured (`reactiveMap.retention`\n// wired at construction eliminates the §7 feedback cycle the prior\n// `tierClassifier` effect carried). `permanentKeys` and `entryCreatedAtNs`\n// are reactive maps mounted on the graph (not closure state) so\n// `describe()`/`explain()` can walk to the inputs that fed an archival\n// decision.\n// ---------------------------------------------------------------------------\n\nimport { batch, DATA, monotonicNs, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport type { StorageHandle } from \"@graphrefly/pure-ts/extra\";\nimport {\n\tfromAny,\n\tkeepalive,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapRetention,\n\treactiveMap,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype DistillBundle,\n\ttype DistillOptions,\n\tdistill,\n\ttype Extraction,\n} from \"../../../base/composition/distill.js\";\nimport { decay } from \"../../../base/utils/decay.js\";\nimport {\n\tcollection,\n\tcosineSimilarity,\n\ttype KnowledgeEdge,\n\ttype KnowledgeGraph,\n\tknowledgeGraph,\n\ttype VectorIndexGraph,\n\ttype VectorRecord,\n\ttype VectorSearchResult,\n\tvectorIndex,\n} from \"../../memory/index.js\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { RetrievalEntry, RetrievalQuery, RetrievalTrace } from \"./retrieval.js\";\nimport {\n\tDEFAULT_DECAY_RATE,\n\ttype MemoryTier,\n\ttype MemoryTiersBundle,\n\ttype MemoryTiersOptions,\n} from \"./tiers.js\";\n\n// Tier 4.7 (Wave AM Unit 5 carry): the pre-rebuild defensive `extractStoreMap`\n// helper (runtime `instanceof Map` check before casting) was deleted in favor\n// of a typed `as` cast at each callsite. The upstream `ReactiveMapBundle`\n// always emits a real Map on the live emit path; non-Map snapshots only\n// surface on `Graph.restore` from a codec that round-tripped Map → JSON →\n// plain object (handled in `extra/composite.ts:mapFromSnapshot` for distill\n// internals). Empty map is the canonical \"no entries yet\" value —\n// `node([], { initial: undefined })` would stall a derived/effect's first-run gate.\n//\n// qa F3 (deferred): the typed cast lies if upstream contract ever breaks\n// (e.g. `entries` emits a non-Map non-undefined value). Failure mode is a\n// TypeError at iteration instead of a silent empty-map fallback —\n// deliberate trade-off, surfacing real upstream-contract violations beats\n// hiding them. Upstream-narrowing follow-up filed in `docs/optimizations.md`\n// under \"Tier 4.7 follow-up — narrow `ReactiveMapBundle.entries` callback typing\".\n\n// ---------------------------------------------------------------------------\n// memoryWithVectors\n// ---------------------------------------------------------------------------\n\nexport interface MemoryWithVectorsOptions<TMem> {\n\t/** Optional Graph identity — passed through to the underlying `Graph` ctor. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-vectors\"`. */\n\tname?: string;\n\t/** The substrate distill store to index. */\n\tstore: DistillBundle<TMem>;\n\t/** Embedding dimension. Must match the `embedFn` output length. */\n\tdimension: number;\n\t/** Extract an embedding vector for a memory entry. */\n\tembedFn: (mem: TMem) => readonly number[] | undefined;\n}\n\n/**\n * Graph subclass that attaches a vector index to a `DistillBundle`. The inner\n * `VectorIndexGraph` is mounted at `\"vectorIndex\"`; an internal effect\n * subscribes to the substrate store and re-indexes on every change.\n *\n * Mirrors `AuditTrailGraph` / `PolicyGateGraph` shape — fully self-contained,\n * teardown via the Graph's `destroy()` cascade.\n */\nexport class MemoryWithVectorsGraph<TMem> extends Graph {\n\treadonly vectors: VectorIndexGraph<TMem>;\n\n\tconstructor(opts: MemoryWithVectorsOptions<TMem>) {\n\t\tsuper(opts.name ?? \"memory-vectors\", opts.graph);\n\t\tthis.vectors = vectorIndex<TMem>({ dimension: opts.dimension });\n\t\tthis.mount(\"vectorIndex\", this.vectors);\n\n\t\tconst embedFn = opts.embedFn;\n\t\tconst vectorsRef = this.vectors;\n\n\t\t// Indexer effect — subscribes to the substrate's store entries, upserts\n\t\t// vectors. Pure side-effect; restricted `effect` fn (no emit/down).\n\t\t// Cross-graph dep on `opts.store.store.entries` is fine — the substrate\n\t\t// is the upstream wired in by the parent factory.\n\t\tconst indexer = node(\n\t\t\t[opts.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t\tconst vec = embedFn(mem);\n\t\t\t\t\tif (vec) vectorsRef.upsert(key, vec, mem);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"indexer\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(indexer, { name: \"indexer\" });\n\t\tthis.addDisposer(keepalive(indexer));\n\t}\n}\n\n/**\n * Attach a vector index to a `DistillBundle`. Indexes every entry in the\n * store as it changes. Returns the `MemoryWithVectorsGraph` whose `vectors`\n * field exposes the underlying `VectorIndexGraph`.\n *\n * Teardown is handled by `Graph.destroy()` — typically inherited via\n * mounting the result on a parent graph (see `agentMemory`).\n */\nexport function memoryWithVectors<TMem>(\n\topts: MemoryWithVectorsOptions<TMem>,\n): MemoryWithVectorsGraph<TMem> {\n\treturn new MemoryWithVectorsGraph<TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryWithKG\n// ---------------------------------------------------------------------------\n\nexport interface MemoryWithKGOptions<TMem> {\n\t/** Optional Graph identity. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-kg\"`. */\n\tname?: string;\n\t/** The substrate distill store to index. */\n\tstore: DistillBundle<TMem>;\n\t/** Inner KnowledgeGraph name. Default: `${name}-kg`. */\n\tkgName?: string;\n\t/**\n\t * Mount path within this Graph for the KnowledgeGraph. Default:\n\t * `\"knowledge-kg\"` (B5c — symmetric with the outer `knowledge` mount so\n\t * describe paths render `knowledge::knowledge-kg::*`).\n\t */\n\tmountPath?: string;\n\t/**\n\t * Extract entities + relations for a memory entry. Omit to mount an empty\n\t * KG without an indexer effect — caller upserts entities / relations\n\t * directly on the `kg` field.\n\t */\n\tentityFn?: (\n\t\tkey: string,\n\t\tmem: TMem,\n\t) =>\n\t\t| {\n\t\t\t\tentities?: Array<{ id: string; value: unknown }>;\n\t\t\t\trelations?: Array<{ from: string; to: string; relation: string; weight?: number }>;\n\t\t }\n\t\t| undefined;\n}\n\n/**\n * Graph subclass that attaches a knowledge graph alongside a `DistillBundle`.\n * Mounts the inner `KnowledgeGraph` at `mountPath` (default `\"knowledge-kg\"`); when\n * `entityFn` is provided, an indexer effect populates entities/relations on\n * every store change.\n */\nexport class MemoryWithKGGraph<TMem> extends Graph {\n\treadonly kg: KnowledgeGraph<unknown, string>;\n\n\tconstructor(opts: MemoryWithKGOptions<TMem>) {\n\t\tconst name = opts.name ?? \"memory-kg\";\n\t\tsuper(name, opts.graph);\n\t\tconst kgName = opts.kgName ?? `${name}-kg`;\n\t\tconst mountPath = opts.mountPath ?? \"knowledge-kg\";\n\t\tthis.kg = knowledgeGraph<unknown, string>(kgName);\n\t\tthis.mount(mountPath, this.kg);\n\n\t\tif (!opts.entityFn) return;\n\t\tconst entityFn = opts.entityFn;\n\t\tconst kgRef = this.kg;\n\t\tconst indexer = node(\n\t\t\t[opts.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t\tconst extracted = entityFn(key, mem);\n\t\t\t\t\tif (!extracted) continue;\n\t\t\t\t\tfor (const ent of extracted.entities ?? []) {\n\t\t\t\t\t\tkgRef.upsertEntity(ent.id, ent.value);\n\t\t\t\t\t}\n\t\t\t\t\tfor (const rel of extracted.relations ?? []) {\n\t\t\t\t\t\tkgRef.link(rel.from, rel.to, rel.relation, rel.weight);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"indexer\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(indexer, { name: \"indexer\" });\n\t\tthis.addDisposer(keepalive(indexer));\n\t}\n}\n\n/**\n * Attach a knowledge graph alongside a `DistillBundle`. Returns the\n * `MemoryWithKGGraph` whose `kg` field exposes the inner `KnowledgeGraph`.\n */\nexport function memoryWithKG<TMem>(opts: MemoryWithKGOptions<TMem>): MemoryWithKGGraph<TMem> {\n\treturn new MemoryWithKGGraph<TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryWithTiers\n// ---------------------------------------------------------------------------\n\n/**\n * Full options for {@link memoryWithTiers} (Tier 4.1 B + 4.3 B refactor,\n * 2026-04-29). Combines tier-policy options with the distill-side options\n * needed to construct the underlying store — `memoryWithTiers` is the\n * **construction site** for the distill bundle so it can wire\n * `reactiveMap.retention` into the store at construction (eliminating the\n * §7 feedback cycle the previous `tierClassifier` effect carried).\n */\nexport type MemoryWithTiersOptions<TRaw, TMem> = MemoryTiersOptions<TMem> &\n\tOmit<DistillOptions<TMem>, \"mapOptions\" | \"score\" | \"context\"> & {\n\t\t/** Optional Graph identity. */\n\t\tgraph?: GraphOptions;\n\t\t/** Subgraph name. Default: `\"memory-tiers\"`. */\n\t\tname?: string;\n\t\t/** Raw source feeding distill. */\n\t\tsource: NodeInput<TRaw>;\n\t\t/** Reactive extraction wiring (same shape as `distill`). */\n\t\textractFn: (\n\t\t\traw: Node<TRaw>,\n\t\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t\t) => NodeInput<Extraction<TMem>>;\n\t\t/** Score function — same signature as `agentMemory.score`. */\n\t\tscore: (mem: TMem, context: unknown) => number;\n\t\t/** Optional reactive context node (passed to `score`). */\n\t\tcontext?: NodeInput<unknown>;\n\t};\n\n/**\n * Graph subclass attaching 3-tier storage (active / archived / permanent) to\n * a fresh distill store, wiring `reactiveMap.retention` at construction so\n * archival happens synchronously inside the substrate's mutation pipeline\n * (no §7 feedback cycle). Promotes `permanentKeys` and `entryCreatedAtNs` to\n * reactive maps registered on this graph (Tier 4.3 B — Unit 7 Q3) so\n * `describe()` / `explain()` can walk to \"why was X archived?\".\n *\n * Public-face fields:\n * - `store` — the distill bundle (construction site, exposed for downstream\n * composers).\n * - `tiers` — tier classification + permanent promotion handles.\n * - `compact`, `size` — alias for `store.compact` / `store.size` (registered\n * under their canonical names so `describe()` keys match `agentMemory`'s\n * pre-migration layout).\n */\nexport class MemoryWithTiersGraph<TRaw, TMem> extends Graph {\n\treadonly store: DistillBundle<TMem>;\n\treadonly tiers: MemoryTiersBundle<TMem>;\n\treadonly compact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\treadonly size: Node<number>;\n\treadonly permanent: ReturnType<typeof collection<TMem>>;\n\treadonly permanentKeys: ReactiveMapBundle<string, true>;\n\treadonly entryCreatedAtNs: ReactiveMapBundle<string, number>;\n\n\tconstructor(opts: MemoryWithTiersOptions<TRaw, TMem>) {\n\t\tsuper(opts.name ?? \"memory-tiers\", opts.graph);\n\n\t\tconst decayRate = opts.decayRate ?? DEFAULT_DECAY_RATE;\n\t\tconst maxActive = opts.maxActive ?? 1000;\n\t\tconst archiveThreshold = opts.archiveThreshold ?? 0.1;\n\t\tconst permanentFilter = opts.permanentFilter ?? (() => false);\n\n\t\t// Tier 2.3 fold: `lightCollection` was merged into\n\t\t// `collection({ranked: false})`. The unified factory returns a Graph (not\n\t\t// a detached bundle), so it's mounted as a subgraph for `describe()`.\n\t\tthis.permanent = collection<TMem>(\"permanent\", { ranked: false });\n\t\tthis.mount(\"permanent\", this.permanent);\n\n\t\t// 4.3 B (Unit 7 Q3, 2026-04-29): closure-state promotion. `permanentKeys`\n\t\t// and `entryCreatedAtNs` are reactive maps registered on this graph so\n\t\t// `describe()` can walk to them and `explain()` can trace the inputs\n\t\t// that fed an archival decision.\n\t\tthis.permanentKeys = reactiveMap<string, true>({ name: \"permanentKeys\" });\n\t\tthis.add(this.permanentKeys.entries, { name: \"permanentKeys\" });\n\t\tthis.entryCreatedAtNs = reactiveMap<string, number>({ name: \"entryCreatedAtNs\" });\n\t\tthis.add(this.entryCreatedAtNs.entries, { name: \"entryCreatedAtNs\" });\n\n\t\t// Closure-mirror for ctx (§28 factory-time seed). `score(mem, ctx)` runs\n\t\t// inside `retention.score` which is invoked synchronously from store\n\t\t// mutations — no reactive dep on contextNode there. The mirror keeps\n\t\t// `latestCtx` current via subscribe.\n\t\t//\n\t\t// Topology visibility: the local-default branch registers the context\n\t\t// state node so it appears in `describe()`. The user-supplied-Node\n\t\t// branch deliberately leaves the node unregistered — `fromAny` returns\n\t\t// the caller's owned Node, which is owned by their graph; mounting it\n\t\t// here would corrupt cross-graph ownership.\n\t\tlet contextNode: Node<unknown>;\n\t\tif (opts.context) {\n\t\t\tcontextNode = fromAny(opts.context);\n\t\t} else {\n\t\t\tcontextNode = node<unknown>([], { initial: null });\n\t\t\tthis.add(contextNode, { name: \"context\" });\n\t\t}\n\t\tlet latestCtx: unknown = contextNode.cache;\n\t\tconst ctxUnsub = contextNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestCtx = m[1];\n\t\t});\n\t\tthis.addDisposer(ctxUnsub);\n\n\t\tconst permanentKeysRef = this.permanentKeys;\n\t\tconst entryCreatedAtNsRef = this.entryCreatedAtNs;\n\t\tconst score = opts.score;\n\n\t\t// Build retention. `score` runs synchronously inside store mutations.\n\t\t// Permanent matches return Infinity to bypass eviction.\n\t\t//\n\t\t// DS-13.5.F (2026-05-01): `score` is read-only against\n\t\t// `entryCreatedAtNs` — the first-write side-effect was extracted into\n\t\t// the `entryCreatedAtNs/sync` effect below. Race window for the very\n\t\t// first call on a new key is mitigated by the `?? nowNs` fallback\n\t\t// (yields ageSeconds = 0, i.e. fresh-decay), and the sync effect\n\t\t// populates the map after the wave settles so subsequent score calls\n\t\t// see the persisted timestamp.\n\t\tconst retention: ReactiveMapRetention<string, TMem> = {\n\t\t\tscore: (key, value) => {\n\t\t\t\tif (permanentFilter(key, value)) return Number.POSITIVE_INFINITY;\n\t\t\t\tif (permanentKeysRef.has(key)) return Number.POSITIVE_INFINITY;\n\t\t\t\tconst nowNs = monotonicNs();\n\t\t\t\tconst createdNs = entryCreatedAtNsRef.get(key) ?? nowNs;\n\t\t\t\tconst ageSeconds = Number(nowNs - createdNs) / 1e9;\n\t\t\t\treturn decay(score(value, latestCtx), ageSeconds, decayRate);\n\t\t\t},\n\t\t\tarchiveThreshold,\n\t\t\tmaxSize: maxActive,\n\t\t};\n\n\t\t// Construct distill with retention wired into mapOptions.\n\t\tthis.store = distill<TRaw, TMem>(opts.source, opts.extractFn, {\n\t\t\tscore: opts.score,\n\t\t\tcost: opts.cost,\n\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : {}),\n\t\t\t...(opts.evict !== undefined ? { evict: opts.evict } : {}),\n\t\t\t...(opts.consolidate !== undefined ? { consolidate: opts.consolidate } : {}),\n\t\t\t...(opts.consolidateTrigger !== undefined\n\t\t\t\t? { consolidateTrigger: opts.consolidateTrigger }\n\t\t\t\t: {}),\n\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\tmapOptions: { retention },\n\t\t});\n\n\t\t// Register the distill bundle's exposed nodes under their canonical\n\t\t// names so consumers (and `describe()`) see the same shape as the\n\t\t// pre-migration top-level surface on `agentMemory`.\n\t\tthis.add(this.store.store.entries, { name: \"store\" });\n\t\tthis.compact = this.store.compact;\n\t\tthis.add(this.compact, { name: \"compact\" });\n\t\tthis.size = this.store.size;\n\t\tthis.add(this.size, { name: \"size\" });\n\n\t\tconst storeRef = this.store;\n\t\tconst tierOf = (key: string): MemoryTier => {\n\t\t\tif (permanentKeysRef.has(key)) return \"permanent\";\n\t\t\tconst m =\n\t\t\t\t(storeRef.store.entries.cache as ReadonlyMap<string, TMem> | undefined) ??\n\t\t\t\tnew Map<string, TMem>();\n\t\t\tif (m.has(key)) return \"active\";\n\t\t\treturn \"archived\";\n\t\t};\n\t\tconst permanentRef = this.permanent;\n\t\tconst markPermanent = (key: string, value: TMem): void => {\n\t\t\tpermanentKeysRef.set(key, true);\n\t\t\tpermanentRef.upsert(key, value);\n\t\t};\n\n\t\t// DS-13.5.F (2026-05-01): first-write of `entryCreatedAtNs[key]` runs\n\t\t// here (extracted from `retention.score` to keep score pure). Reads\n\t\t// `store.store.entries`, writes `entryCreatedAtNs` — distinct nodes,\n\t\t// no §7 feedback cycle. Idempotent: re-emissions for already-tracked\n\t\t// keys skip via `entryCreatedAtNsRef.has(key)`.\n\t\tconst syncCreatedAt = node(\n\t\t\t[this.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = (data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tconst nowNs = monotonicNs();\n\t\t\t\tconst toAdd: string[] = [];\n\t\t\t\tfor (const key of map.keys()) {\n\t\t\t\t\tif (!entryCreatedAtNsRef.has(key)) toAdd.push(key);\n\t\t\t\t}\n\t\t\t\tif (toAdd.length > 0) {\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tfor (const key of toAdd) entryCreatedAtNsRef.set(key, nowNs);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"entryCreatedAtNs/sync\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(syncCreatedAt, { name: \"entryCreatedAtNs/sync\" });\n\t\tthis.addDisposer(keepalive(syncCreatedAt));\n\n\t\t// GC entryCreatedAtNs entries that no longer exist in the active store.\n\t\t// (Adds happen via the syncCreatedAt effect above; removals piggyback\n\t\t// on the store-snapshot subscriber here so the map stays in sync.)\n\t\tconst entriesUnsub = this.store.store.entries.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst map = m[1] as ReadonlyMap<string, TMem>;\n\t\t\t\tconst created = entryCreatedAtNsRef.entries.cache as\n\t\t\t\t\t| ReadonlyMap<string, number>\n\t\t\t\t\t| undefined;\n\t\t\t\tif (created == null) continue;\n\t\t\t\tconst toDelete: string[] = [];\n\t\t\t\tfor (const key of created.keys()) {\n\t\t\t\t\tif (!map.has(key)) toDelete.push(key);\n\t\t\t\t}\n\t\t\t\tif (toDelete.length > 0) {\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tfor (const key of toDelete) entryCreatedAtNsRef.delete(key);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(entriesUnsub);\n\n\t\t// Permanent-promotion effect. Writes to `permanent` collection +\n\t\t// `permanentKeys` (NOT to the active store), so no §7 cycle: the effect's\n\t\t// dep is `store.store.entries`, but it doesn't write back to that node.\n\t\tconst promoter = node(\n\t\t\t[this.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = (data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of map) {\n\t\t\t\t\tif (permanentKeysRef.has(key)) continue;\n\t\t\t\t\tif (permanentFilter(key, mem)) {\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tmarkPermanent(key, mem);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"promoter\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(promoter, { name: \"promoter\" });\n\t\tthis.addDisposer(keepalive(promoter));\n\n\t\tlet archiveHandle: StorageHandle | null = null;\n\t\tif (opts.archiveTier) {\n\t\t\tarchiveHandle = this.attachSnapshotStorage(\n\t\t\t\t[{ snapshot: opts.archiveTier }],\n\t\t\t\topts.archiveStorageOptions ?? {},\n\t\t\t);\n\t\t\tthis.addDisposer(() => archiveHandle?.dispose());\n\t\t}\n\n\t\tthis.tiers = {\n\t\t\tpermanent: this.permanent,\n\t\t\tactiveEntries: this.store.store.entries,\n\t\t\tarchiveHandle,\n\t\t\ttierOf,\n\t\t\tmarkPermanent,\n\t\t};\n\t}\n}\n\n/**\n * Attach 3-tier storage (active / archived / permanent) over a fresh distill\n * store. Returns a `MemoryWithTiersGraph` whose `store` and `tiers` fields\n * mirror the previous bundle shape.\n *\n * **API shape** (Class B audit, 2026-04-30 — breaking change vs.\n * pre-migration): the factory takes a single opts bag including `source`\n * and `extractFn`. The bundle is exposed as `result.store` for downstream\n * composers (vectors / KG / retrieval).\n *\n * - `permanentFilter`-matching entries score `Infinity` in retention →\n * never archived. Independent permanent-promotion effect upserts them\n * into the `permanent` collection.\n * - Below-threshold entries → retention archives synchronously.\n * - Over-`maxActive` entries → retention's `maxSize` evicts lowest-scored.\n */\nexport function memoryWithTiers<TRaw, TMem>(\n\topts: MemoryWithTiersOptions<TRaw, TMem>,\n): MemoryWithTiersGraph<TRaw, TMem> {\n\treturn new MemoryWithTiersGraph<TRaw, TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryRetrieval\n// ---------------------------------------------------------------------------\n\nexport interface MemoryRetrievalOptions<TMem> {\n\t/** Optional Graph identity. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-retrieval\"`. */\n\tname?: string;\n\t/** The substrate distill store. */\n\tstore: DistillBundle<TMem>;\n\t/** Optional vector index for similarity search. */\n\tvectors?: VectorIndexGraph<TMem> | null;\n\t/** Optional knowledge graph for entity-relation expansion. */\n\tkg?: KnowledgeGraph<unknown, string> | null;\n\t/** Score function (same shape as `agentMemory.score`). */\n\tscore: (mem: TMem, context: unknown) => number;\n\t/** Cost function for budget packing. */\n\tcost: (mem: TMem) => number;\n\t/** Token / cost budget. Default 2000. */\n\tbudget?: number;\n\t/** Top-K vector candidates. Default 20. */\n\ttopK?: number;\n\t/** KG expansion depth in hops. Default 1. */\n\tgraphDepth?: number;\n\t/** Hierarchical-context boost weight. Default 0. */\n\tcontextWeight?: number;\n\t/** Hierarchical-context accessor for entries. */\n\tcontextOf?: (mem: TMem) => readonly string[] | undefined;\n\t/** Optional reactive context node (passed to `score`). */\n\tcontext?: NodeInput<unknown>;\n}\n\nfunction sharedPrefixDepth(\n\tq: readonly string[] | undefined,\n\te: readonly string[] | undefined,\n): number {\n\tif (!q || !e) return 0;\n\tconst n = Math.min(q.length, e.length);\n\tlet i = 0;\n\twhile (i < n && q[i] === e[i]) i++;\n\treturn i;\n}\n\n// QA-fix: element-wise reference-equality dedup so subscribers don't wake\n// up when an identical packed array lands (runRetrieval allocates a new\n// outer array reference every call).\nconst packedEquals = <T>(a: readonly T[], b: readonly T[]): boolean => {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n\treturn true;\n};\n\n/**\n * Graph subclass that builds the retrieval pipeline (vector + KG + budget\n * packing) over a `DistillBundle` and optional vectors / kg substrates.\n *\n * **C1 rework (2026-04-30):** retrieval is reactive-only. Each\n * `retrieveReactive(input)` call constructs its own per-input subgraph\n * mounted at `retrieve_${id}` with named nodes `context`, `result`, and\n * `projection`. Subgraphs register their own scoped disposers so teardown\n * is local to the per-call mount.\n *\n * **QA F-9 (2026-04-30):** the shared `retrieval` / `retrievalTrace`\n * state-node mirrors are dropped — they were last-writer-wins under\n * concurrent `retrieveReactive(...)` calls. Consumers must subscribe to\n * the per-call `projection` node directly. One-shot consumers use\n * `awaitSettled(retrieveReactive(input))`.\n *\n * **QA F-6 (2026-04-30):** the per-call `result` derived declares\n * `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps when\n * configured, so a vector upsert / KG mutation re-runs retrieval even\n * when the query / context / store-snapshot are unchanged. Resolves the\n * §28 closure-mirror gap where these `.cache` reads were undeclared.\n */\nexport class MemoryRetrievalGraph<TMem> extends Graph {\n\tprivate readonly _store: DistillBundle<TMem>;\n\tprivate readonly _vectors: VectorIndexGraph<TMem> | null;\n\tprivate readonly _kg: KnowledgeGraph<unknown, string> | null;\n\tprivate readonly _opts: MemoryRetrievalOptions<TMem>;\n\tprivate readonly _contextNode: Node<unknown>;\n\tprivate readonly _topK: number;\n\tprivate readonly _graphDepth: number;\n\tprivate readonly _budget: number;\n\tprivate readonly _contextWeight: number;\n\tprivate _retrieveSeq = 0;\n\n\tconstructor(opts: MemoryRetrievalOptions<TMem>) {\n\t\tsuper(opts.name ?? \"memory-retrieval\", opts.graph);\n\n\t\tthis._store = opts.store;\n\t\tthis._vectors = opts.vectors ?? null;\n\t\tthis._kg = opts.kg ?? null;\n\t\tthis._opts = opts;\n\t\tthis._topK = opts.topK ?? 20;\n\t\tthis._graphDepth = opts.graphDepth ?? 1;\n\t\tthis._budget = opts.budget ?? 2000;\n\t\tthis._contextWeight = opts.contextWeight ?? 0;\n\t\t// DS-13.5.C: synthesized branch (no `opts.context` supplied) registers\n\t\t// on this graph as `_context` so describe()/explain() can walk to it.\n\t\t// User-supplied branch stays unregistered — `fromAny` returns the\n\t\t// caller's owned Node, which is owned by their graph; mounting it\n\t\t// here would corrupt cross-graph ownership (mirrors MemoryWithTiers's\n\t\t// context-branch policy).\n\t\tif (opts.context) {\n\t\t\tthis._contextNode = fromAny(opts.context);\n\t\t} else {\n\t\t\tthis._contextNode = this.state<unknown>(\"_context\", null);\n\t\t}\n\t}\n\n\tprivate _runRetrieval(\n\t\tstoreMap: ReadonlyMap<string, TMem>,\n\t\tctx: unknown,\n\t\tquery: RetrievalQuery,\n\t): { packed: RetrievalEntry<TMem>[]; trace: RetrievalTrace<TMem> } {\n\t\tconst opts = this._opts;\n\t\tconst candidateMap = new Map<\n\t\t\tstring,\n\t\t\t{ value: TMem; sources: Set<\"vector\" | \"graph\" | \"store\"> }\n\t\t>();\n\n\t\tlet vectorCandidates: VectorSearchResult<TMem>[] = [];\n\t\tif (this._vectors && query.vector) {\n\t\t\t// Wave A migrated `vectorIndex` to a reactive-only read API\n\t\t\t// (`searchNode`); inline the equivalent flat-cosine snapshot scan\n\t\t\t// here since `_runRetrieval` is sync and `searchNode` is async-shaped.\n\t\t\t// `patterns/ai/memory/` is queued for its own audit per the Wave A\n\t\t\t// session doc § D.1.\n\t\t\tconst q = query.vector;\n\t\t\tconst snapshot = this._vectors.entries.cache as\n\t\t\t\t| ReadonlyMap<string, VectorRecord<TMem>>\n\t\t\t\t| undefined;\n\t\t\tif (snapshot && snapshot.size > 0 && this._topK > 0) {\n\t\t\t\tconst scored = [...snapshot.values()]\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(row): VectorSearchResult<TMem> => ({\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, this._topK);\n\t\t\t\tvectorCandidates = scored;\n\t\t\t\tfor (const vc of vectorCandidates) {\n\t\t\t\t\tconst mem = storeMap.get(vc.id);\n\t\t\t\t\tif (mem) candidateMap.set(vc.id, { value: mem, sources: new Set([\"vector\"]) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst graphExpanded: string[] = [];\n\t\tif (this._kg) {\n\t\t\t// Wave A migrated `knowledgeGraph` to a reactive-only `relatedNode`\n\t\t\t// API; inline the equivalent adjacency-snapshot scan here for the\n\t\t\t// sync expansion. `adjacencyOut` / `adjacencyIn` are kept warm by\n\t\t\t// the kg's own internal keepalive disposers, so `.cache` is always\n\t\t\t// populated post-construction.\n\t\t\tconst adjOut = this._kg.adjacencyOut.cache as\n\t\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<string>[]>\n\t\t\t\t| undefined;\n\t\t\tconst adjIn = this._kg.adjacencyIn.cache as\n\t\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<string>[]>\n\t\t\t\t| undefined;\n\t\t\tconst seedIds = [...(query.entityIds ?? []), ...[...candidateMap.keys()]];\n\t\t\tconst visited = new Set<string>();\n\t\t\tlet frontier = seedIds;\n\t\t\tfor (let depth = 0; depth < this._graphDepth; depth++) {\n\t\t\t\tconst nextFrontier: string[] = [];\n\t\t\t\tfor (const id of frontier) {\n\t\t\t\t\tif (visited.has(id)) continue;\n\t\t\t\t\tvisited.add(id);\n\t\t\t\t\tconst outEdges = adjOut?.get(id) ?? [];\n\t\t\t\t\tconst inEdges = adjIn?.get(id) ?? [];\n\t\t\t\t\tfor (const edge of outEdges) {\n\t\t\t\t\t\tconst targetId = edge.to;\n\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\tif (existing) existing.sources.add(\"graph\");\n\t\t\t\t\t\t\t\telse candidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Inbound edges: traverse to the `from` side. Match the\n\t\t\t\t\t// previous `kg.related(id)` semantics, which returned both\n\t\t\t\t\t// `from === id` and `to === id` matches.\n\t\t\t\t\tfor (const edge of inEdges) {\n\t\t\t\t\t\tconst targetId = edge.from;\n\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\tif (existing) existing.sources.add(\"graph\");\n\t\t\t\t\t\t\t\telse candidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfrontier = nextFrontier;\n\t\t\t}\n\t\t}\n\t\tfor (const [key, mem] of storeMap) {\n\t\t\tif (!candidateMap.has(key)) {\n\t\t\t\tcandidateMap.set(key, { value: mem, sources: new Set([\"store\"]) });\n\t\t\t}\n\t\t}\n\n\t\tconst qDepth = query.context?.length ?? 0;\n\t\tconst ranked: RetrievalEntry<TMem>[] = [];\n\t\tfor (const [key, { value, sources }] of candidateMap) {\n\t\t\tconst entryContext = opts.contextOf ? opts.contextOf(value) : undefined;\n\t\t\tlet score = opts.score(value, ctx);\n\t\t\tif (this._contextWeight > 0 && qDepth > 0) {\n\t\t\t\tconst shared = sharedPrefixDepth(query.context, entryContext);\n\t\t\t\tif (shared > 0) score = score * (1 + (this._contextWeight * shared) / qDepth);\n\t\t\t}\n\t\t\tconst entry: RetrievalEntry<TMem> = entryContext\n\t\t\t\t? { key, value, score, sources: [...sources], context: entryContext }\n\t\t\t\t: { key, value, score, sources: [...sources] };\n\t\t\tranked.push(entry);\n\t\t}\n\t\tranked.sort((a, b) => b.score - a.score);\n\n\t\tconst packed: RetrievalEntry<TMem>[] = [];\n\t\tlet usedBudget = 0;\n\t\tfor (const entry of ranked) {\n\t\t\tconst c = opts.cost(entry.value);\n\t\t\tif (usedBudget + c > this._budget && packed.length > 0) break;\n\t\t\tpacked.push(entry);\n\t\t\tusedBudget += c;\n\t\t}\n\n\t\treturn { packed, trace: { vectorCandidates, graphExpanded, ranked, packed } };\n\t}\n\n\t/**\n\t * Reactive consumer API — chain into the graph.\n\t *\n\t * Each call constructs its own per-input subgraph mounted at\n\t * `retrieve_${id}` (auto-incrementing within this MemoryRetrievalGraph\n\t * instance) with named nodes:\n\t *\n\t * - `context` — `fromAny(queryInput)` projection (so the input node is\n\t * visible to `describe()` even when callers pass a raw value).\n\t * - `result` — pure derived `{ packed, trace }`.\n\t * - `projection` — the packed-array node returned to the caller.\n\t *\n\t * `result` declares the substrate's `store.entries`, the optional\n\t * `context` Node, the local `context` projection, and (when configured)\n\t * `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps —\n\t * so vector upserts and KG mutations re-trigger retrieval even when\n\t * the input is unchanged.\n\t *\n\t * **Lifecycle contract (DS-13.5.C, 2026-05-01).** The per-call subgraph\n\t * stays mounted while the returned `projection` has at least one\n\t * subscriber. When the last subscriber unsubscribes, projection's\n\t * `deactivate` cleanup hook fires (canonical \"last unsubscribe\" signal\n\t * via the existing `NodeFnCleanup.onDeactivation` protocol), which calls\n\t * `parent.remove(retrieve_${id})` and tears the per-call topology\n\t * down via TEARDOWN cascade (post-DS-13.5.A Q16, COMPLETE auto-precedes).\n\t *\n\t * **Single-shot lifecycle.** This auto-unmount is keyed to the FIRST\n\t * last-unsubscribe event — projection is non-resubscribable from the\n\t * caller's perspective. Callers who need to subscribe / unsubscribe /\n\t * re-subscribe should hold a long-lived subscription externally (e.g.\n\t * `keepalive(projection)`) or call `retrieveReactive(...)` again to\n\t * mount a fresh per-call subgraph.\n\t *\n\t * **Caller obligation.** Either subscribe to `projection` (and\n\t * eventually unsubscribe to trigger cleanup) OR drop the returned\n\t * reference without subscribing — in the no-subscribe case the\n\t * subgraph is dormant (no compute fires) and a parent `destroy()`\n\t * cascade reclaims it. Holding `projection` without subscribing AND\n\t * without ever destroying the parent is the leak case the JSDoc above\n\t * the C1 rework covers.\n\t *\n\t * One-shot callers use `awaitSettled(retrieveReactive(input))`.\n\t */\n\tretrieveReactive(\n\t\tqueryInput: NodeInput<RetrievalQuery | null>,\n\t): Node<ReadonlyArray<RetrievalEntry<TMem>>> {\n\t\tconst id = ++this._retrieveSeq;\n\t\tconst segment = `retrieve_${id}`;\n\n\t\t// Per-call subgraph — owns the wiring, the keepalive, and the\n\t\t// teardown. Mounted on `this` so it's visible in `describe()` and\n\t\t// reachable via `${parent}::retrieve_${id}::result` etc.\n\t\tconst sub = new Graph(segment);\n\n\t\t// Wrap the input as a local pass-through so the per-call subgraph\n\t\t// shows the query source in `describe()` regardless of where the\n\t\t// caller's node lives in the broader topology. `fromAny` returns\n\t\t// the original Node when given a Node, otherwise wraps a\n\t\t// value/promise into a producer.\n\t\t//\n\t\t// DS-13.5.C: registered via `sub.derived(...)` (Graph helper) for\n\t\t// equals plumbing + automatic registration; replaces the prior raw\n\t\t// `node([inputNode], fn) + sub.add(...)` shape.\n\t\tconst inputNode = fromAny(queryInput);\n\t\tconst localContext = sub.derived<RetrievalQuery | null>(\n\t\t\t\"context\",\n\t\t\t[inputNode],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\treturn [(data[0] as RetrievalQuery | null) ?? null];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: aiMeta(\"retrieval_query_input\"),\n\t\t\t\tinitial: null,\n\t\t\t},\n\t\t);\n\n\t\t// /qa F-6 (2026-04-30): declare vectors / kg substrate Node refs as\n\t\t// deps so vector upserts / KG mutations re-trigger retrieval even\n\t\t// when query / context / store snapshots are unchanged. The\n\t\t// `_runRetrieval` body reads `.cache` from these substrates; before\n\t\t// this fix those reads were undeclared §28 closure-mirrors.\n\t\tconst resultDeps: (string | Node<unknown>)[] = [\n\t\t\tthis._store.store.entries,\n\t\t\tthis._contextNode,\n\t\t\tlocalContext,\n\t\t];\n\t\tif (this._vectors) resultDeps.push(this._vectors.entries as Node<unknown>);\n\t\tif (this._kg) {\n\t\t\tresultDeps.push(this._kg.adjacencyOut as Node<unknown>);\n\t\t\tresultDeps.push(this._kg.adjacencyIn as Node<unknown>);\n\t\t}\n\n\t\t// DS-13.5.C: migrated to `sub.derived(...)` for equals plumbing +\n\t\t// automatic registration.\n\t\tconst result = sub.derived<{\n\t\t\tpacked: ReadonlyArray<RetrievalEntry<TMem>>;\n\t\t\ttrace: RetrievalTrace<TMem> | null;\n\t\t}>(\n\t\t\t\"result\",\n\t\t\tresultDeps,\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst query = data[2];\n\t\t\t\tif (query == null) {\n\t\t\t\t\treturn [{ packed: [] as ReadonlyArray<RetrievalEntry<TMem>>, trace: null }];\n\t\t\t\t}\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tconst { packed, trace } = this._runRetrieval(storeMap, data[1], query as RetrievalQuery);\n\t\t\t\treturn [{ packed, trace }];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: aiMeta(\"retrieval_reactive_result\"),\n\t\t\t\tinitial: { packed: [] as ReadonlyArray<RetrievalEntry<TMem>>, trace: null },\n\t\t\t},\n\t\t);\n\n\t\t// DS-13.5.C: projection stays as raw `node()` (not `sub.derived`)\n\t\t// because the keepalive disposer is wired via the fn's\n\t\t// `NodeFnCleanup.onDeactivation` hook — projection's cleanup-on-last-\n\t\t// unsubscribe is what drives `parent.remove(segment)`. The Graph\n\t\t// `.derived()` helper drops the cleanup return, so the raw form\n\t\t// is required here. `equals: packedEquals` is preserved verbatim.\n\t\tconst projection = node<ReadonlyArray<RetrievalEntry<TMem>>>(\n\t\t\t[result],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit((data[0] as { packed: ReadonlyArray<RetrievalEntry<TMem>> }).packed);\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t// Auto-unmount on last unsubscribe (DS-13.5.C).\n\t\t\t\t\t\t// Idempotent: try/catch covers the case where the\n\t\t\t\t\t\t// segment was already removed (e.g. parent destroy\n\t\t\t\t\t\t// cascade ran first, or the caller called remove()\n\t\t\t\t\t\t// manually).\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tthis.remove(segment);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* best-effort cleanup */\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"projection\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"retrieval_reactive\"),\n\t\t\t\tinitial: [] as ReadonlyArray<RetrievalEntry<TMem>>,\n\t\t\t\tequals: packedEquals,\n\t\t\t},\n\t\t);\n\t\tsub.add(projection, { name: \"projection\" });\n\n\t\tthis.mount(segment, sub);\n\t\treturn projection;\n\t}\n}\n\n/**\n * Build the retrieval pipeline (vector + KG + budget packing) over a\n * `DistillBundle` and optional `vectors` / `kg` substrates. Returns a\n * `MemoryRetrievalGraph` exposing `retrieval` / `retrievalTrace` reactive\n * state and the `retrieveReactive(input)` consumer method.\n */\nexport function memoryRetrieval<TMem>(\n\topts: MemoryRetrievalOptions<TMem>,\n): MemoryRetrievalGraph<TMem> {\n\treturn new MemoryRetrievalGraph<TMem>(opts);\n}\n","/**\n * Pure exponential-decay utility (Tier 2.2 promotion from `patterns/memory/`).\n *\n * Used by `collection`, `agentMemory`, harness `strategy.ts`, and any\n * downstream consumer that needs decay-with-floor scoring. Promoted to\n * `extra/utils/` because the math has zero domain semantics and is reusable\n * by non-memory primitives (e.g. routing weight decay, retry-attempt aging).\n *\n * @module\n */\n\n/**\n * Default exponential-decay rate corresponding to a 7-day half-life.\n *\n * `Math.LN2 / (7 × 86_400)` ≈ `1.146e-6`. Imported by memory tiers + any\n * consumer that wants the same default cadence as `agentMemory`'s active\n * tier. Tier 4.4 (Wave AM Unit 1) — promoted from\n * `patterns/ai/memory/tiers.ts` so non-memory consumers can share the\n * canonical default without reaching across domains.\n */\nexport const DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86_400);\n\n/**\n * Exponential decay with floor: `score = max(minScore, baseScore * exp(-ratePerSecond * ageSeconds))`.\n *\n * Tolerant fallbacks (deliberate for use inside reactive derived fns):\n * - non-finite `baseScore` → `minScore`\n * - non-positive `ageSeconds` (incl. clock skew) → `max(minScore, baseScore)` (no decay)\n * - non-positive `ratePerSecond` → `max(minScore, baseScore)` (no decay; rate=0 disables)\n *\n * Underflow boundary: `Math.exp(-745) === 0`. For very long ages × rates the\n * result clamps to `minScore`; if you need slow decay over years, choose a\n * smaller `ratePerSecond` rather than relying on graceful underflow.\n *\n * Half-life conversion: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n */\nexport function decay(\n\tbaseScore: number,\n\tageSeconds: number,\n\tratePerSecond: number,\n\tminScore = 0,\n): number {\n\tif (!Number.isFinite(baseScore)) return minScore;\n\tif (!Number.isFinite(ageSeconds) || ageSeconds <= 0) return Math.max(minScore, baseScore);\n\tif (!Number.isFinite(ratePerSecond) || ratePerSecond <= 0) return Math.max(minScore, baseScore);\n\tconst decayed = baseScore * Math.exp(-ratePerSecond * ageSeconds);\n\treturn Math.max(minScore, decayed);\n}\n","/**\n * Memory patterns (roadmap §4.3) — public-face Phase-4 primitives audited under\n * `archive/docs/SESSION-public-face-blocks-review.md` (Wave A, locked 2026-04-25).\n *\n * Three primitives (the pure `decay` helper was promoted to `extra/utils/decay.ts`\n * per Tier 2.2 and is no longer re-exported here; `lightCollection` was folded\n * into `collection({ranked:false})` per Tier 2.3 and is no longer a separate\n * factory):\n * - {@link collection} / {@link CollectionGraph} — keyed memory store with\n * optional decay-aware ranking. Pass `{ ranked: false }` for the previous\n * `lightCollection` shape (Map + LRU + audit, no scoring).\n * - {@link vectorIndex} / {@link VectorIndexGraph} — reactive vector store with\n * optional HNSW backend, retention, and reactive {@link VectorIndexGraph.searchNode}.\n * - {@link knowledgeGraph} / {@link KnowledgeGraph} — entities + typed edges with\n * symmetric adjacency indexes and reactive {@link KnowledgeGraph.relatedNode}.\n *\n * **No imperative reads.** Per the API-style policy locked 2026-04-25, public-face\n * primitives expose reactive reads only — `itemNode` / `hasNode` / `searchNode` /\n * `relatedNode`. One-shot snapshots use `node.cache` after `awaitSettled`, or\n * `firstValueFrom(node)`.\n *\n * **Audit logs.** Every imperative mutation (`upsert / remove / clear / link /\n * unlink / rescore / reindex`) is wrapped via {@link mutate} and appends a\n * typed record to a public `events` log on the bundle / graph.\n *\n * @module\n */\n\nimport { monotonicNs, type Node, NodeImpl, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { fromTimer, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport {\n\ttype BaseAuditRecord,\n\tbumpCursor,\n\tcreateAuditLog,\n\tmutate,\n\tregisterCursor,\n} from \"../../base/mutation/index.js\";\nimport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\nimport { decay } from \"../../base/utils/decay.js\";\n\n// ── Shared helpers ───────────────────────────────────────────────────────\n\nconst NS_PER_SEC = 1_000_000_000;\n\nfunction memoryMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"memory\", kind, extra);\n}\n\n/**\n * Coerce a value-or-Node argument into a `Node<T>`. Pass-through if already a\n * Node; otherwise wraps in `state(value, {name})`. Used by reactive read\n * factories (`itemNode` / `searchNode` / `relatedNode`) so callers can supply\n * a static value without manually creating a state node.\n *\n * Heuristic: anything that is a `NodeImpl` instance is a Node; everything else\n * is treated as a raw value to wrap.\n */\nfunction toNode<T>(v: T | Node<T>, name?: string): Node<T> {\n\tif (v instanceof NodeImpl) return v as Node<T>;\n\treturn node<T>([], { initial: v as T, ...(name ? { name } : undefined) });\n}\n\nfunction ageSeconds(now: number, lastNs: number): number {\n\treturn (now - lastNs) / NS_PER_SEC;\n}\n\n// `decay` was promoted to `extra/utils/decay.ts` per Tier 2.2 — it is no longer\n// re-exported from this module. Import from `@graphrefly/graphrefly/extra` (or\n// `../../extra/utils/decay.js` internally) instead.\n\n/**\n * Cosine similarity over `(a, b)`. When lengths differ, the shorter is\n * implicitly zero-padded to the longer length. Returns `0` if either vector\n * has zero norm. Public utility — used by {@link VectorIndexGraph.searchNode}\n * and exposed for downstream consumers (e.g. `patterns/ai/memory/`) that need\n * the same scoring at the boundary.\n *\n * **Numeric guards.** Returns `0` for non-finite results (overflow producing\n * `Infinity`/`NaN` from very-large vectors, or `NaN` propagating from any\n * `NaN`/`Infinity` component). Without this guard, downstream sort\n * comparators would order NaN-scored rows arbitrarily.\n *\n * **Depth.** This is a per-call computation; no internal caching. For very\n * large indexes (>10k) consider precomputing norms or using HNSW.\n *\n * @category memory\n */\nexport function cosineSimilarity(a: readonly number[], b: readonly number[]): number {\n\tconst n = Math.max(a.length, b.length);\n\tlet dot = 0;\n\tlet na = 0;\n\tlet nb = 0;\n\tfor (let i = 0; i < n; i += 1) {\n\t\tconst av = a[i] ?? 0;\n\t\tconst bv = b[i] ?? 0;\n\t\tdot += av * bv;\n\t\tna += av * av;\n\t\tnb += bv * bv;\n\t}\n\tif (na === 0 || nb === 0) return 0;\n\tconst score = dot / Math.sqrt(na * nb);\n\treturn Number.isFinite(score) ? score : 0;\n}\n\n/**\n * Equality predicate for {@link VectorIndexGraph.searchNode} results. Compares\n * `id` AND `score` AND `meta` reference per position so that score-only changes\n * (re-upsert with new vector keeping the same top-K order) propagate to\n * downstream subscribers. The previous id-only comparator silently dropped\n * those updates.\n */\nfunction searchResultsEqual<TMeta>(\n\ta: readonly VectorSearchResult<TMeta>[] | undefined,\n\tb: readonly VectorSearchResult<TMeta>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\tif (x.id !== y.id || x.score !== y.score || x.meta !== y.meta) return false;\n\t}\n\treturn true;\n}\n\n// ── Common types ─────────────────────────────────────────────────────────\n\n/** Public alias for the `Node | value` shape accepted by reactive read factories. */\nexport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\n\n// ── Unit 2 (Tier 2.3 fold): collection (formerly lightCollection + collection)\n//\n// Pre-Tier-2.3 the module shipped `lightCollection` (no Graph, no ranking,\n// just LRU + audit) alongside `collection` (Graph-mounted with timer-driven\n// decay-aware ranking). Per the consolidation plan §1 Rule 4, the two are\n// folded into a single `collection({ranked: true|false})` factory: when\n// `ranked: false`, no `ranked` derived / refresh tick / scoring is wired.\n// `LightCollectionEntry` is gone — `CollectionEntry<T>` is the unified entry\n// shape (`baseScore` reads `0` in unranked mode).\n\nexport type CollectionEntry<T> = {\n\treadonly id: string;\n\treadonly value: T;\n\treadonly createdAtNs: number;\n\treadonly lastAccessNs: number;\n\treadonly baseScore: number;\n};\n\nexport type RankedCollectionEntry<T> = CollectionEntry<T> & {\n\treadonly score: number;\n};\n\nexport type CollectionScoreFn<T> = (value: T) => number;\n\nexport type CollectionOptions<T> = {\n\tmaxSize?: number;\n\t/**\n\t * Whether to expose a live decay-aware `ranked` node + `rescore` mutator.\n\t * Default `true`. Pass `false` to fold in the previous `lightCollection`\n\t * shape — entries are still keyed/audited/LRU-evicted, but the timer-driven\n\t * `ranked` + scoring machinery is skipped. `ranked` then resolves to a\n\t * static empty array Node and `rescore()` is a no-op (so callers writing\n\t * type-generic code don't need to special-case the unranked path).\n\t */\n\tranked?: boolean;\n\t/**\n\t * Produces a base score at insert/update time. Static fn or a reactive\n\t * `Node<(value: T) => number>` — when supplied as a Node, `ranked` re-derives\n\t * whenever the score fn changes, but `baseScore` on each entry is only\n\t * recomputed via {@link CollectionGraph.rescore}. Default `() => 1`.\n\t *\n\t * Ignored when `ranked: false` (entries record `baseScore: 0`).\n\t */\n\tscore?: CollectionScoreFn<T> | Node<CollectionScoreFn<T>>;\n\t/**\n\t * Exponential decay rate per second. `0` disables decay (default). When\n\t * positive, `ranked` becomes fully reactive on time via a `fromTimer` source\n\t * (cadence auto-derived from `decayRate` unless overridden via\n\t * `refreshIntervalMs`). Half-life: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n\t *\n\t * Ignored when `ranked: false`.\n\t */\n\tdecayRate?: number;\n\t/** Minimum score floor after decay. Default `0`. */\n\tminScore?: number;\n\t/**\n\t * Override for the `ranked` refresh tick cadence (milliseconds). When\n\t * unset and `decayRate > 0`, defaults to `1000 * Math.LN2 / (10 * decayRate)`\n\t * — roughly one tick per 10% of the half-life (~10% staleness budget).\n\t */\n\trefreshIntervalMs?: number;\n};\n\nexport interface CollectionAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"rescore\";\n\treadonly id?: string;\n}\n\nexport type CollectionGraph<T> = Graph & {\n\treadonly events: ReactiveLogBundle<CollectionAuditRecord>;\n\treadonly items: Node<ReadonlyMap<string, CollectionEntry<T>>>;\n\t/**\n\t * Live decay-aware ranking, sorted by score descending. When the\n\t * collection was constructed with `ranked: false`, this is a static\n\t * empty-array Node (kept for type uniformity).\n\t */\n\treadonly ranked: Node<readonly RankedCollectionEntry<T>[]>;\n\treadonly size: Node<number>;\n\tupsert: (id: string, value: T, opts?: { score?: number }) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/**\n\t * Recompute every entry's `baseScore` via the latest score fn. O(N). Useful\n\t * when a reactive `score` Node has emitted a new fn and the caller wants\n\t * existing entries re-scored without an explicit re-upsert.\n\t *\n\t * No-op (still records an audit entry) when constructed with\n\t * `ranked: false`.\n\t */\n\trescore: () => void;\n\titemNode: (id: NodeOrValue<string>) => Node<CollectionEntry<T> | undefined>;\n\t/** Reactive `true` once the entry exists; tracks upsert / remove. */\n\thasNode: (id: NodeOrValue<string>) => Node<boolean>;\n};\n\nfunction rankedEqual<T>(\n\ta: readonly RankedCollectionEntry<T>[] | undefined,\n\tb: readonly RankedCollectionEntry<T>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\t// Compare value reference too — if `upsert(id, newValue)` runs and\n\t\t// `score(newValue) === score(oldValue)` AND timestamps coincide\n\t\t// (rare on platforms where consecutive `monotonicNs()` calls in the\n\t\t// same microtask collide), the prior comparator suppressed the\n\t\t// emission and consumers reading `entry.value` saw stale data.\n\t\t// Value identity catches it cheaply (`value !== value` only on NaN\n\t\t// payloads, which behave correctly here).\n\t\tif (\n\t\t\tx.id !== y.id ||\n\t\t\tx.score !== y.score ||\n\t\t\tx.lastAccessNs !== y.lastAccessNs ||\n\t\t\tx.value !== y.value\n\t\t)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Scored memory store with live decay-aware ranking.\n *\n * Topology (mounted on the returned graph):\n * - `items` — `reactiveMap<id, CollectionEntry<T>>` (with `retention` configured\n * for score-based eviction when `maxSize` is set).\n * - `ranked` — `Node<readonly RankedCollectionEntry<T>[]>`, sorted by live\n * decayed score. **Lazy** — does NOT compute until subscribed (no internal\n * keepalive). Use `keepalive(coll.ranked)` for eager activation.\n * - `size` — `Node<number>`, count of entries.\n * - `_refreshTick` — `fromTimer`-driven `monotonicNs()` source, mounted only\n * when `decayRate > 0`. Drives `ranked`'s time-dependent re-derivation.\n * - `_seq` — sequence cursor for the audit log.\n * - `events` — bounded reactive log of every mutation.\n *\n * **Time as a reactive dep.** When `decayRate > 0`, `ranked`'s deps are\n * `[items, refreshTick]` — the tick payload IS `monotonicNs()`, so the fn is\n * pure of deps and dry-run-reproducible with a mocked clock.\n *\n * **Lazy timer.** With no subscriber to `ranked`, the timer source does not\n * fire — the activation chain is downstream-driven. To keep the timer warm\n * without consuming results, register `graph.addDisposer(keepalive(coll.ranked))`.\n *\n * **Eviction at write-time.** Score-based retention runs on every successful\n * `upsert / remove / clear` (it is mutation-driven, not tick-driven). The\n * retention scorer reads `monotonicNs()` to compute decayed scores at eviction\n * time — this is a deliberate impurity vs. `ReactiveMapRetention.score`'s\n * \"pure of `(key, value)`\" docstring: write-time is the right moment to evict\n * stale-by-decay entries.\n *\n * **No imperative reads.** Subscribe to `items` / `ranked` for live snapshots,\n * or use `itemNode(id)` for single-key reactive reads.\n *\n * **`rescore` ordering caveat.** `rescore()` reads `items.entries.cache`\n * (the post-emission snapshot) and writes via `setMany`. When called\n * stand-alone it sees the latest committed state. When wrapped inside a\n * user-level `batch(() => { coll.upsert(...); coll.rescore(); })`, the\n * `cache` snapshot reflects state BEFORE the batch — so a just-staged\n * upsert is invisible to the rescore scan. If you need rescore to include\n * the staged upsert, either call `rescore()` after the batch settles or\n * pass the new `baseScore` directly via `upsert(id, value, { score })`.\n *\n * **Audit no-op records.** Like `lightCollection`, mutations record audit\n * entries even when the impl was a no-op (e.g., `rescore()` on an empty\n * store). Intentional — the framework records attempts.\n *\n * @category memory\n */\nexport function collection<T>(name: string, opts: CollectionOptions<T> = {}): CollectionGraph<T> {\n\tconst maxSize = opts.maxSize;\n\tconst ranked = opts.ranked ?? true;\n\t// `decayRate` / `score` / `refreshIntervalMs` are no-ops when ranked is off\n\t// (they only feed the `ranked` derived). The audit + LRU paths still run.\n\tconst decayRate = ranked ? (opts.decayRate ?? 0) : 0;\n\tconst minScore = opts.minScore ?? 0;\n\tif (maxSize !== undefined && maxSize < 1) {\n\t\tthrow new RangeError(\"collection: maxSize must be >= 1\");\n\t}\n\n\t// Resolve score fn — supports static fn or reactive Node<fn>. When\n\t// `ranked: false` the score is constant `0` and `readScoreFn` is unused\n\t// (the upsert path takes the `_opts.score ?? readScoreFn()(value)` branch\n\t// only when ranking is requested).\n\tconst scoreFnDefault: CollectionScoreFn<T> = () => (ranked ? 1 : 0);\n\tconst scoreInput = opts.score ?? scoreFnDefault;\n\tconst scoreNode: Node<CollectionScoreFn<T>> | undefined =\n\t\tranked && scoreInput instanceof NodeImpl\n\t\t\t? (scoreInput as Node<CollectionScoreFn<T>>)\n\t\t\t: undefined;\n\tconst readScoreFn = (): CollectionScoreFn<T> => {\n\t\tif (scoreNode) return scoreNode.cache ?? scoreFnDefault;\n\t\treturn scoreInput as CollectionScoreFn<T>;\n\t};\n\n\tconst graph = new Graph(name);\n\n\t// Score-based retention scorer for `reactiveMap`. When unranked the base\n\t// score is `0`, so retention falls back to LRU-by-`lastAccessNs` (the\n\t// older the access, the lower the decayed score → first to evict).\n\tconst retentionScore = (_k: string, v: CollectionEntry<T>): number =>\n\t\tranked\n\t\t\t? decay(v.baseScore, ageSeconds(monotonicNs(), v.lastAccessNs), decayRate, minScore)\n\t\t\t: v.lastAccessNs;\n\n\tconst items = reactiveMap<string, CollectionEntry<T>>({\n\t\tname: \"items\",\n\t\t...(maxSize !== undefined ? { retention: { score: retentionScore, maxSize } } : {}),\n\t});\n\n\tgraph.add(items.entries, { name: \"items\" });\n\n\t// Refresh tick — only mounted when ranking + decay are configured. Tick\n\t// payload is `monotonicNs()`, so `rankedNode`'s fn is pure-of-deps and\n\t// dry-run-reproducible.\n\tlet refreshTick: Node<number> | undefined;\n\tif (ranked && decayRate > 0) {\n\t\tconst intervalMs = opts.refreshIntervalMs ?? Math.max(1, (1000 * Math.LN2) / (10 * decayRate));\n\t\tconst tickCounter = fromTimer(intervalMs, { period: intervalMs });\n\t\t// Map each tick to the wall-clock `monotonicNs` — the tick payload IS\n\t\t// the time stamp downstream consumers use. Reading the central clock\n\t\t// inside this fn is sanctioned: this derived's purpose is to publish\n\t\t// \"now\" reactively (cf. spec §5.11 — central timer), and downstream\n\t\t// `rankedNode` reads it from its dep array, never from the clock\n\t\t// directly.\n\t\t//\n\t\t// `initial: monotonicNs()` seeds the cache with construction-time\n\t\t// `now` so push-on-subscribe delivers DATA to `rankedNode` before the\n\t\t// first tick fires — without this, `rankedNode` would stall in pending\n\t\t// status until ~`refreshIntervalMs` after first activation, and a\n\t\t// caller reading `rankedNode.cache` immediately after `upsert` would\n\t\t// see `undefined`.\n\t\trefreshTick = node(\n\t\t\t[tickCounter],\n\t\t\t(_batchData, actions) => {\n\t\t\t\tactions.emit(monotonicNs());\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"refresh_tick_ns\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tinitial: monotonicNs(),\n\t\t\t\tmeta: memoryMeta(\"clock\"),\n\t\t\t},\n\t\t);\n\t\tgraph.add(refreshTick, { name: \"refresh_tick_ns\" });\n\t}\n\n\t// `rankedNode` derived — pure of (items, refreshTick?, scoreNode?). When\n\t// `ranked: false`, `rankedNode` is a static empty-array node so the\n\t// public type stays uniform without re-running the sort.\n\tlet rankedNode: Node<readonly RankedCollectionEntry<T>[]>;\n\tif (ranked) {\n\t\tconst rankedDeps: Node<unknown>[] = [items.entries];\n\t\tif (refreshTick) rankedDeps.push(refreshTick);\n\t\tif (scoreNode) rankedDeps.push(scoreNode);\n\t\trankedNode = node(\n\t\t\trankedDeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tlet now: number;\n\t\t\t\tif (refreshTick) {\n\t\t\t\t\tconst tickValue = values[1] as number | undefined;\n\t\t\t\t\tnow = typeof tickValue === \"number\" ? tickValue : monotonicNs();\n\t\t\t\t} else {\n\t\t\t\t\tnow = monotonicNs();\n\t\t\t\t}\n\t\t\t\tif (!snapshot || snapshot.size === 0) {\n\t\t\t\t\tactions.emit([] as readonly RankedCollectionEntry<T>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst out: RankedCollectionEntry<T>[] = [];\n\t\t\t\tfor (const entry of snapshot.values()) {\n\t\t\t\t\tout.push({\n\t\t\t\t\t\t...entry,\n\t\t\t\t\t\tscore: decay(entry.baseScore, ageSeconds(now, entry.lastAccessNs), decayRate, minScore),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tout.sort((a, b) => b.score - a.score || b.lastAccessNs - a.lastAccessNs);\n\t\t\t\tactions.emit(out as readonly RankedCollectionEntry<T>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ranked\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: rankedEqual,\n\t\t\t\tmeta: memoryMeta(\"ranked\"),\n\t\t\t},\n\t\t) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t} else {\n\t\trankedNode = node<readonly RankedCollectionEntry<T>[]>([], {\n\t\t\tinitial: [] as readonly RankedCollectionEntry<T>[],\n\t\t\tname: \"ranked\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: memoryMeta(\"ranked_disabled\"),\n\t\t}) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t}\n\n\tconst size = node(\n\t\t[items.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\tactions.emit(((snapshot ?? new Map()) as ReadonlyMap<string, CollectionEntry<T>>).size);\n\t\t},\n\t\t{\n\t\t\tname: \"size\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: 0,\n\t\t\tmeta: memoryMeta(\"size\"),\n\t\t},\n\t);\n\tgraph.add(size, { name: \"size\" });\n\t// Keepalive only on `size` (cheap; pure of items). `ranked` is intentionally\n\t// lazy so the refresh timer doesn't fire when nothing consumes the ranking.\n\tgraph.addDisposer(keepalive(size));\n\n\t// Audit log + seq cursor.\n\tconst events = createAuditLog<CollectionAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst upsertImpl = (id: string, value: T, _opts?: { score?: number }): void => {\n\t\tconst now = monotonicNs();\n\t\tconst prev = items.get(id);\n\t\tconst baseScore = _opts?.score ?? readScoreFn()(value);\n\t\titems.set(id, {\n\t\t\tid,\n\t\t\tvalue,\n\t\t\tbaseScore,\n\t\t\tcreatedAtNs: prev?.createdAtNs ?? now,\n\t\t\tlastAccessNs: now,\n\t\t});\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!items.has(id)) return;\n\t\titems.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (items.size === 0) return;\n\t\titems.clear();\n\t};\n\tconst rescoreImpl = (): void => {\n\t\t// `ranked: false` short-circuit — there's no live `ranked` node to\n\t\t// re-derive and `baseScore` is held at its insertion-time value, so\n\t\t// rescore is a no-op. The audit record is still emitted so consumers\n\t\t// see the attempt.\n\t\tif (!ranked) return;\n\t\tconst fn = readScoreFn();\n\t\tconst snapshot = items.entries.cache as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\tif (!snapshot || snapshot.size === 0) return;\n\t\tconst updates: Array<[string, CollectionEntry<T>]> = [];\n\t\tfor (const entry of snapshot.values()) {\n\t\t\tupdates.push([entry.id, { ...entry, baseScore: fn(entry.value) }]);\n\t\t}\n\t\titems.setMany(updates);\n\t};\n\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst rescore = mutate(rescoreImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"rescore\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction itemNode(id: NodeOrValue<string>): Node<CollectionEntry<T> | undefined> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.get(key));\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_item\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tfunction hasNode(id: NodeOrValue<string>): Node<boolean> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.has(key) ?? false);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_has\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\titems: items.entries,\n\t\tranked: rankedNode,\n\t\tsize,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\trescore,\n\t\titemNode,\n\t\thasNode,\n\t}) as CollectionGraph<T>;\n\treturn out;\n}\n\n// ── Unit 4: vectorIndex ──────────────────────────────────────────────────\n\nexport type VectorBackend = \"flat\" | \"hnsw\";\n\nexport type VectorRecord<TMeta> = {\n\treadonly id: string;\n\treadonly vector: readonly number[];\n\treadonly meta?: TMeta;\n\t/** Wall-clock-monotonic timestamp at last upsert; used for the default LRU retention. */\n\treadonly upsertedAtNs: number;\n};\n\nexport type VectorSearchResult<TMeta> = {\n\treadonly id: string;\n\treadonly score: number;\n\treadonly meta?: TMeta;\n};\n\nexport type HnswAdapter<TMeta> = {\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\tsearch: (query: readonly number[], k: number) => ReadonlyArray<VectorSearchResult<TMeta>>;\n\t/** Optional adapter teardown. Called from `graph.destroy()` via `addDisposer`. */\n\tdispose?: () => void;\n};\n\nexport type VectorIndexOptions<TMeta> = {\n\tname?: string;\n\tbackend?: VectorBackend;\n\tdimension?: number;\n\t/**\n\t * Strict-dimension default. When `true` (default) AND `dimension` is unset,\n\t * mixed-length upserts throw `RangeError`. Set `false` to opt into the\n\t * lenient zero-padding behavior of {@link VectorIndexGraph.searchNode}.\n\t */\n\tstrictDimension?: boolean;\n\t/** Optional dependency seam for HNSW. */\n\thnswFactory?: () => HnswAdapter<TMeta>;\n\t/** Maximum live entries (LRU-by-upsert-time when set; user-overridable via `retentionScore`). */\n\tmaxSize?: number;\n\t/** Custom retention scorer. Higher score = kept. Defaults to `r => r.upsertedAtNs`. */\n\tretentionScore?: (record: VectorRecord<TMeta>) => number;\n};\n\nexport interface VectorIndexAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"reindex\" | \"evict\";\n\treadonly id?: string;\n}\n\nexport type VectorIndexGraph<TMeta> = Graph & {\n\treadonly backend: VectorBackend;\n\treadonly events: ReactiveLogBundle<VectorIndexAuditRecord>;\n\treadonly entries: Node<ReadonlyMap<string, VectorRecord<TMeta>>>;\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/** Re-push every live entry into the optional HNSW adapter. No-op for `flat`. */\n\treindex: () => void;\n\t/**\n\t * Reactive top-K search. Re-derives whenever entries / query / k change.\n\t * Lazy. Use `firstValueFrom(searchNode(...))` for one-shot reads.\n\t */\n\tsearchNode: (\n\t\tquery: Node<readonly number[]>,\n\t\tk?: NodeOrValue<number>,\n\t) => Node<readonly VectorSearchResult<TMeta>[]>;\n};\n\n/**\n * Reactive vector store with optional HNSW backend.\n *\n * **Storage on `reactiveMap`.** `entries` is a `reactiveMap<id, VectorRecord<TMeta>>`\n * with optional score-based retention (`maxSize` + LRU-by-`upsertedAtNs` by\n * default; user can supply a custom `retentionScore`). On retention eviction,\n * the HNSW adapter (if configured) is also notified via `adapter.remove(id)`.\n *\n * **Reactive search.** `searchNode(queryNode, k)` returns a `Node<readonly\n * VectorSearchResult<TMeta>[]>` that re-derives on entries / query / k change.\n * Lazy — only computes when subscribed. Imperative `search()` is intentionally\n * not exposed (no-imperative-reads policy). Use `firstValueFrom(searchNode(...))`\n * for one-shot reads.\n *\n * **Strict dimension.** Default `strictDimension: true` — if `dimension` is\n * unset and an upsert produces a vector of a different length than the first\n * upserted, throws `RangeError`. Pass `strictDimension: false` to opt into\n * the lenient zero-padding fallback (the previous default).\n *\n * **Adapter lifecycle.** When the HNSW adapter exposes a `dispose()` method,\n * it is bound to the graph's teardown via `addDisposer`. When retention\n * evicts an entry, `adapter.remove(id)` is invoked synchronously inside the\n * retention `onArchive` callback.\n *\n * **Cosine zero-pad.** The flat backend uses cosine similarity over the\n * pairwise max-length zero-pad. Mixing dimensions silently degrades scores\n * unless strict mode catches it at upsert time. For embedding-model vectors,\n * L2-normalize at the source — `vectorIndex` does not normalize.\n *\n * @category memory\n */\nexport function vectorIndex<TMeta>(opts: VectorIndexOptions<TMeta> = {}): VectorIndexGraph<TMeta> {\n\tconst backend = opts.backend ?? \"flat\";\n\tconst dimension = opts.dimension;\n\tconst strictDimension = opts.strictDimension ?? true;\n\tconst maxSize = opts.maxSize;\n\tconst userRetentionScore = opts.retentionScore;\n\n\tlet hnsw: HnswAdapter<TMeta> | undefined;\n\tif (backend === \"hnsw\") {\n\t\thnsw = opts.hnswFactory?.();\n\t\tif (!hnsw) {\n\t\t\tthrow new Error(\n\t\t\t\t'vectorIndex backend \"hnsw\" requires an optional dependency adapter; install your HNSW package and provide `hnswFactory`.',\n\t\t\t);\n\t\t}\n\t}\n\n\tconst graph = new Graph(opts.name ?? \"vector_index\");\n\n\t// Track an inferred dimension when the user didn't lock it but strict mode\n\t// is on — first upsert sets it; subsequent mismatches throw.\n\tlet inferredDimension: number | undefined;\n\tfunction assertDimension(vector: readonly number[]): void {\n\t\tif (dimension !== undefined) {\n\t\t\tif (vector.length !== dimension) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`vector dimension mismatch: expected ${dimension}, got ${vector.length}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!strictDimension) return;\n\t\tif (inferredDimension === undefined) {\n\t\t\tinferredDimension = vector.length;\n\t\t\treturn;\n\t\t}\n\t\tif (vector.length !== inferredDimension) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`vector dimension mismatch: inferred ${inferredDimension} from first upsert, got ${vector.length}. ` +\n\t\t\t\t\t`Pass \\`strictDimension: false\\` to opt into zero-pad behavior, or set an explicit \\`dimension\\`.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst baseRetentionScore = userRetentionScore ?? ((r: VectorRecord<TMeta>) => r.upsertedAtNs);\n\t// `clearInProgress` lets us short-circuit the per-entry `onArchive` →\n\t// `hnsw.remove(id)` cascade when the user calls `clearImpl()`. Retention\n\t// fires `onArchive` for every evicted entry; followed by an explicit\n\t// `hnsw.clear()` we'd double-touch the adapter. Inside `clearImpl` we\n\t// flip this flag, then call `hnsw.clear()` once at the end. (G fix.)\n\tlet clearInProgress = false;\n\n\t// `clearAuditPending` defers the per-entry `evict` audit emission when a\n\t// `clear()` is in flight — those evictions are reported as a single\n\t// `clear` action, not a flurry of `evict` records.\n\tconst events = createAuditLog<VectorIndexAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst entries = reactiveMap<string, VectorRecord<TMeta>>({\n\t\tname: \"entries\",\n\t\t...(maxSize !== undefined\n\t\t\t? {\n\t\t\t\t\tretention: {\n\t\t\t\t\t\tscore: (_k, v) => baseRetentionScore(v),\n\t\t\t\t\t\tmaxSize,\n\t\t\t\t\t\tonArchive: (key) => {\n\t\t\t\t\t\t\tif (clearInProgress) return;\n\t\t\t\t\t\t\tif (backend === \"hnsw\") hnsw!.remove(key);\n\t\t\t\t\t\t\t// E1: surface retention-driven evictions in the audit log\n\t\t\t\t\t\t\t// so replay consumers can reconstruct the live snapshot\n\t\t\t\t\t\t\t// from `events` alone. `seq` is bumped via the cursor;\n\t\t\t\t\t\t\t// the `t_ns` matches `wallClockNs()` for consistency\n\t\t\t\t\t\t\t// with `lightMutation`'s record stamping.\n\t\t\t\t\t\t\tevents.append({\n\t\t\t\t\t\t\t\taction: \"evict\" as const,\n\t\t\t\t\t\t\t\tid: key,\n\t\t\t\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n\tgraph.add(entries.entries, { name: \"entries\" });\n\t// F1: keep `entries` warm so downstream consumers reading\n\t// `vectors.entries.cache` (e.g. `patterns/ai/memory/runRetrieval`) don't\n\t// rely on an external subscriber to activate the node. State nodes are\n\t// ROM and retain `.cache` regardless of subscribers — this `keepalive`\n\t// is defense-in-depth and matches the kg's adjacency keepalive pattern.\n\tgraph.addDisposer(keepalive(entries.entries));\n\n\t// HNSW dispose runs BEFORE state-node teardown via standard disposer\n\t// ordering (disposers drain first, then `[[TEARDOWN]]` propagates per\n\t// `Graph.destroy()`). This is the right ordering: free the adapter's\n\t// native resources before the reactive layer tears down.\n\tif (hnsw?.dispose) {\n\t\tconst disposeAdapter = hnsw.dispose.bind(hnsw);\n\t\tgraph.addDisposer(() => disposeAdapter());\n\t}\n\n\tconst upsertImpl = (id: string, vector: readonly number[], meta?: TMeta): void => {\n\t\tassertDimension(vector);\n\t\t// B1: mutate HNSW first so a throw aborts the reactive write. With\n\t\t// the prior order (entries.set then hnsw.upsert), an adapter throw\n\t\t// would leave entries holding a row HNSW didn't index. Now: HNSW\n\t\t// commits first; if it throws, entries is untouched and audit log\n\t\t// records the failure.\n\t\tif (backend === \"hnsw\") hnsw!.upsert(id, vector, meta);\n\t\t// Defensive copies: vector via `[...vector]`; meta via shallow spread\n\t\t// when it's a non-null object (Array.isArray covered first since arrays\n\t\t// are objects). Primitives, `null`, functions etc. pass through\n\t\t// unchanged. Documented depth limitation: nested objects in `meta` are\n\t\t// shared by reference.\n\t\tconst copiedMeta: TMeta | undefined = (() => {\n\t\t\tif (meta === undefined) return undefined;\n\t\t\tif (meta === null || typeof meta !== \"object\") return meta;\n\t\t\treturn Array.isArray(meta) ? ([...meta] as unknown as TMeta) : ({ ...meta } as TMeta);\n\t\t})();\n\t\tconst record: VectorRecord<TMeta> = {\n\t\t\tid,\n\t\t\tvector: [...vector],\n\t\t\t...(copiedMeta !== undefined ? { meta: copiedMeta } : {}),\n\t\t\tupsertedAtNs: monotonicNs(),\n\t\t};\n\t\tentries.set(id, record);\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!entries.has(id)) return;\n\t\t// B1: HNSW first, then entries.\n\t\tif (backend === \"hnsw\") hnsw!.remove(id);\n\t\tentries.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (entries.size === 0) return;\n\t\t// B1 + G: mark the clear-in-progress flag so retention `onArchive`\n\t\t// suppresses per-entry HNSW removes AND per-entry `evict` audit\n\t\t// records. Then call `entries.clear()` (drains the backend through\n\t\t// retention archival without side effects), and finally call\n\t\t// `hnsw.clear()` once. Reset `inferredDimension` so a fresh start\n\t\t// re-infers from the next upsert.\n\t\tclearInProgress = true;\n\t\ttry {\n\t\t\tentries.clear();\n\t\t\tif (backend === \"hnsw\") hnsw!.clear();\n\t\t} finally {\n\t\t\tclearInProgress = false;\n\t\t}\n\t\tinferredDimension = undefined;\n\t};\n\tconst reindexImpl = (): void => {\n\t\tif (backend !== \"hnsw\") return;\n\t\tconst snapshot = entries.entries.cache as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\tif (!snapshot) return;\n\t\thnsw!.clear();\n\t\tfor (const r of snapshot.values()) {\n\t\t\thnsw!.upsert(r.id, r.vector, r.meta);\n\t\t}\n\t};\n\n\t// `freeze: false` for `upsert` — deep-freezing a 768-dim vector is a\n\t// measurable hot-path tax, and the wrapper does its own defensive copy\n\t// (`vector: [...vector]`) before persisting. See §B.2 of the audit lock.\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tfreeze: false,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst reindex = mutate(reindexImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"reindex\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction searchNode(\n\t\tquery: Node<readonly number[]>,\n\t\tk: NodeOrValue<number> = 5,\n\t): Node<readonly VectorSearchResult<TMeta>[]> {\n\t\tconst kN = toNode<number>(k, \"k\");\n\t\treturn node(\n\t\t\t[entries.entries, query, kN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\t\t\tconst q = values[1] as readonly number[] | undefined;\n\t\t\t\tconst kRaw = values[2] as number;\n\t\t\t\t// Auto-fix: `Math.max(0, Math.floor(k))` — `| 0` is a 32-bit\n\t\t\t\t// signed truncation that collapses Infinity to 0 and wraps\n\t\t\t\t// values > 2^31. Use a proper floor with a non-negative floor.\n\t\t\t\tconst kVal = Number.isFinite(kRaw) ? Math.max(0, Math.floor(kRaw)) : 0;\n\t\t\t\tif (!snapshot || snapshot.size === 0 || kVal <= 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Auto-fix: defensive guard for unset / empty query — earlier\n\t\t\t\t// the fn would TypeError on `q.length` reading `undefined`,\n\t\t\t\t// or compute meaningless all-zero scores against an empty\n\t\t\t\t// vector. With strict-dimension OR an explicit `dimension`,\n\t\t\t\t// also reject mismatched-length queries (the imperative path\n\t\t\t\t// used to throw; reactive deriveds shouldn't throw, so\n\t\t\t\t// degrade to empty results).\n\t\t\t\tif (q == null || q.length === 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst expectedDim = dimension ?? (strictDimension ? inferredDimension : undefined);\n\t\t\t\tif (expectedDim !== undefined && q.length !== expectedDim) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (backend === \"hnsw\") {\n\t\t\t\t\t// Defensive copy of the adapter's return — HNSW libs\n\t\t\t\t\t// sometimes hand back internal buffers; downstream\n\t\t\t\t\t// subscribers must not be able to corrupt adapter state.\n\t\t\t\t\tconst adapterResults = hnsw!.search(q, kVal);\n\t\t\t\t\tactions.emit([...adapterResults] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst ranked = [...snapshot.values()]\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst result: VectorSearchResult<TMeta> = {\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t})\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, kVal);\n\t\t\t\tactions.emit(ranked as readonly VectorSearchResult<TMeta>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t// A1: include `score` in equality. The previous id-only\n\t\t\t\t// comparator suppressed re-emissions when the same set of\n\t\t\t\t// IDs/order had different scores (re-upsert with new\n\t\t\t\t// vector; query change preserving ranking order).\n\t\t\t\tequals: (a, b) => searchResultsEqual(a, b),\n\t\t\t\tmeta: memoryMeta(\"vector_search\"),\n\t\t\t},\n\t\t) as Node<readonly VectorSearchResult<TMeta>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tbackend,\n\t\tevents,\n\t\tentries: entries.entries,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\treindex,\n\t\tsearchNode,\n\t}) as VectorIndexGraph<TMeta>;\n\treturn out;\n}\n\n// ── Unit 5: knowledgeGraph ───────────────────────────────────────────────\n\nexport type KnowledgeEdge<TRelation extends string = string> = {\n\treadonly from: string;\n\treadonly to: string;\n\treadonly relation: TRelation;\n\treadonly weight: number;\n};\n\nexport type KnowledgeGraphOptions = {\n\t/** Cap on entity count (LRU-by-upsert-time when set). */\n\tentitiesMaxSize?: number;\n\t/** Cap on edge count (LRU-by-upsert-time when set). */\n\tedgesMaxSize?: number;\n\t/**\n\t * Orphan-entity garbage collection. `\"keep\"` (default) leaves entities\n\t * untouched when their last edge is unlinked; `\"remove\"` deletes the\n\t * entity post-`unlink` if no edges reference it.\n\t */\n\torphanGC?: \"keep\" | \"remove\";\n};\n\nexport interface KnowledgeGraphAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsertEntity\" | \"removeEntity\" | \"link\" | \"unlink\" | \"orphanRemove\";\n\treadonly id?: string;\n\treadonly from?: string;\n\treadonly to?: string;\n\treadonly relation?: string;\n\t/** Edge weight at the time of the `link`. Omitted for non-edge actions. */\n\treadonly weight?: number;\n}\n\nexport type KnowledgeGraph<TEntity, TRelation extends string = string> = Graph & {\n\treadonly events: ReactiveLogBundle<KnowledgeGraphAuditRecord>;\n\treadonly entities: Node<ReadonlyMap<string, TEntity>>;\n\treadonly edges: Node<ReadonlyMap<string, KnowledgeEdge<TRelation>>>;\n\treadonly adjacencyOut: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly adjacencyIn: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly entityCount: Node<number>;\n\treadonly edgeCount: Node<number>;\n\tupsertEntity: (id: string, value: TEntity) => void;\n\tremoveEntity: (id: string) => void;\n\tlink: (from: string, to: string, relation: TRelation, weight?: number) => void;\n\tunlink: (from: string, to: string, relation?: TRelation) => void;\n\trelatedNode: (\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t) => Node<readonly KnowledgeEdge<TRelation>[]>;\n};\n\nconst TRIPLE_SEP = \"\u0000\";\nfunction tripleKey(from: string, to: string, relation: string): string {\n\treturn `${from}${TRIPLE_SEP}${to}${TRIPLE_SEP}${relation}`;\n}\n\nfunction buildAdjacency<TRelation extends string>(\n\tedges: ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined,\n\tside: \"from\" | \"to\",\n): ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> {\n\tif (!edges || edges.size === 0) return new Map();\n\tconst buckets = new Map<string, KnowledgeEdge<TRelation>[]>();\n\tfor (const edge of edges.values()) {\n\t\tconst key = side === \"from\" ? edge.from : edge.to;\n\t\tlet bucket = buckets.get(key);\n\t\tif (!bucket) {\n\t\t\tbucket = [];\n\t\t\tbuckets.set(key, bucket);\n\t\t}\n\t\tbucket.push(edge);\n\t}\n\tconst out = new Map<string, readonly KnowledgeEdge<TRelation>[]>();\n\tfor (const [key, bucket] of buckets) out.set(key, Object.freeze(bucket));\n\treturn out;\n}\n\nfunction adjacencyEqual<TRelation extends string>(\n\ta: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n\tb: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.size !== b.size) return false;\n\tfor (const [k, av] of a) {\n\t\tconst bv = b.get(k);\n\t\tif (!bv || av.length !== bv.length) return false;\n\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\tconst ae = av[i]!;\n\t\t\tconst be = bv[i]!;\n\t\t\tif (\n\t\t\t\tae.from !== be.from ||\n\t\t\t\tae.to !== be.to ||\n\t\t\t\tae.relation !== be.relation ||\n\t\t\t\tae.weight !== be.weight\n\t\t\t)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Reactive knowledge graph: entities + typed edges + symmetric adjacency.\n *\n * Topology (mounted on the returned graph):\n * - `entities` — `reactiveMap<id, TEntity>` (optional `entitiesMaxSize` LRU).\n * - `edges` — `reactiveMap<tripleKey, KnowledgeEdge<TRelation>>` keyed by\n * `${from}\u0000${to}\u0000${relation}` (optional `edgesMaxSize` LRU).\n * Entity IDs / relations must NOT contain `\u0000`.\n * - `adjacencyOut` — `Node<ReadonlyMap<from, readonly edge[]>>`. **Full O(E)\n * rebuild on every `link` / `unlink` mutation.** (Prior JSDoc claim of\n * \"O(E) build\" referred to a single rebuild — the per-mutation cost is\n * O(E), not O(1) amortized. For very large graphs with frequent edge\n * churn, consider batching via `reactiveMap.setMany`.)\n * - `adjacencyIn` — `Node<ReadonlyMap<to, readonly edge[]>>`. Same O(E) per\n * mutation rebuild characteristic.\n * - `entityCount` / `edgeCount` — observability deriveds.\n * - `events` — bounded reactive audit log.\n *\n * **`link()` semantics.** Calling `link(a, b, rel, w)` twice with different\n * weights replaces the weight on the existing edge (keyed by the triple).\n * `unlink` then `link` re-creates the edge (and bumps `lastUpsertNs` for\n * retention purposes).\n *\n * **Edge weight convention.** Higher weight = stronger relation. Default `1`.\n *\n * **Orphan GC.** `orphanGC: \"remove\"` deletes an entity from `entities` after\n * an `unlink` that empties its adjacency on both sides. Default `\"keep\"`.\n *\n * **No imperative reads.** Use `relatedNode(id, relation?)` for reactive reads.\n *\n * @category memory\n */\nexport function knowledgeGraph<TEntity, TRelation extends string = string>(\n\tname: string,\n\topts: KnowledgeGraphOptions = {},\n): KnowledgeGraph<TEntity, TRelation> {\n\tconst orphanGC = opts.orphanGC ?? \"keep\";\n\tif (opts.entitiesMaxSize !== undefined && opts.entitiesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: entitiesMaxSize must be >= 1\");\n\t}\n\tif (opts.edgesMaxSize !== undefined && opts.edgesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: edgesMaxSize must be >= 1\");\n\t}\n\n\tconst graph = new Graph(name);\n\n\tconst entitiesMap = reactiveMap<string, TEntity>({\n\t\tname: \"entities\",\n\t\t...(opts.entitiesMaxSize !== undefined ? { maxSize: opts.entitiesMaxSize } : {}),\n\t});\n\tconst edgesMap = reactiveMap<string, KnowledgeEdge<TRelation>>({\n\t\tname: \"edges\",\n\t\t...(opts.edgesMaxSize !== undefined ? { maxSize: opts.edgesMaxSize } : {}),\n\t});\n\tgraph.add(entitiesMap.entries, { name: \"entities\" });\n\tgraph.add(edgesMap.entries, { name: \"edges\" });\n\n\tconst adjacencyOut = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"from\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyOut\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_out\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tconst adjacencyIn = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"to\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyIn\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_in\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tgraph.add(adjacencyOut, { name: \"adjacencyOut\" });\n\tgraph.add(adjacencyIn, { name: \"adjacencyIn\" });\n\tgraph.addDisposer(keepalive(adjacencyOut));\n\tgraph.addDisposer(keepalive(adjacencyIn));\n\n\tconst entityCount = node(\n\t\t[entitiesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, TEntity> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, TEntity>).size);\n\t\t},\n\t\t{ name: \"entityCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"entity_count\") },\n\t);\n\tconst edgeCount = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, KnowledgeEdge<TRelation>>).size);\n\t\t},\n\t\t{ name: \"edgeCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"edge_count\") },\n\t);\n\tgraph.add(entityCount, { name: \"entityCount\" });\n\tgraph.add(edgeCount, { name: \"edgeCount\" });\n\tgraph.addDisposer(keepalive(entityCount));\n\tgraph.addDisposer(keepalive(edgeCount));\n\n\tconst events = createAuditLog<KnowledgeGraphAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\t/**\n\t * O(1) orphan check via the kept-warm `adjacency*` deriveds. Reading\n\t * `adjacencyOut.cache` / `adjacencyIn.cache` is safe here because both\n\t * are activated via `addDisposer(keepalive(...))` at construction time\n\t * (a derived's RAM cache only persists with at least one subscriber, and\n\t * the keepalive registers exactly that). The previous implementation\n\t * scanned `edgesMap.entries.cache` post-`deleteMany`, which depended on\n\t * the (sync) snapshot-emit timing of `reactiveMap` — fragile. The\n\t * `adjacency*.cache` approach is both faster (O(1) vs O(E) per check)\n\t * and timing-robust because the reactiveMap snapshot has already\n\t * propagated through the derived chain by the time we read.\n\t */\n\tfunction entityHasReferences(id: string): boolean {\n\t\tconst out = adjacencyOut.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tconst inb = adjacencyIn.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tif ((out?.get(id)?.length ?? 0) > 0) return true;\n\t\tif ((inb?.get(id)?.length ?? 0) > 0) return true;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Apply orphan GC to a list of candidate entity ids. Used by both\n\t * {@link unlinkImpl} (post-edge-removal) and {@link removeEntityImpl}\n\t * (post-cascade) so semantics are consistent. Each removed entity\n\t * records a separate `orphanRemove` audit entry with its own monotonic\n\t * `seq` value (D1 fix — the previous bare `events.append(...)` skipped\n\t * the cursor advance, leaving gaps in the audit replay sequence).\n\t */\n\tfunction applyOrphanGC(candidates: readonly string[]): void {\n\t\tif (orphanGC !== \"remove\") return;\n\t\tfor (const candidate of candidates) {\n\t\t\tif (!entitiesMap.has(candidate)) continue;\n\t\t\tif (entityHasReferences(candidate)) continue;\n\t\t\tentitiesMap.delete(candidate);\n\t\t\tevents.append({\n\t\t\t\taction: \"orphanRemove\" as const,\n\t\t\t\tid: candidate,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst upsertEntityImpl = (id: string, value: TEntity): void => {\n\t\tentitiesMap.set(id, value);\n\t};\n\tconst removeEntityImpl = (id: string): void => {\n\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t| undefined;\n\t\t// Collect both the edge-keys to drop AND the entity ids those edges\n\t\t// reference (other than `id` itself) — the latter become orphan-GC\n\t\t// candidates after the cascade. (C1 fix — the previous impl only\n\t\t// applied orphan GC inside `unlink`, so cascading entity removal\n\t\t// could leave dangling orphans.)\n\t\tconst cascadedNeighbors = new Set<string>();\n\t\tif (snapshot) {\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === id || edge.to === id) {\n\t\t\t\t\ttoDrop.push(key);\n\t\t\t\t\tif (edge.from !== id) cascadedNeighbors.add(edge.from);\n\t\t\t\t\tif (edge.to !== id) cascadedNeighbors.add(edge.to);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tif (entitiesMap.has(id)) entitiesMap.delete(id);\n\t\tapplyOrphanGC([...cascadedNeighbors]);\n\t};\n\tconst linkImpl = (from: string, to: string, relation: TRelation, weight = 1): void => {\n\t\tedgesMap.set(tripleKey(from, to, relation), { from, to, relation, weight });\n\t};\n\tconst unlinkImpl = (from: string, to: string, relation?: TRelation): void => {\n\t\tif (relation !== undefined) {\n\t\t\tedgesMap.delete(tripleKey(from, to, relation));\n\t\t} else {\n\t\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t\t| undefined;\n\t\t\tif (!snapshot) return;\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === from && edge.to === to) toDrop.push(key);\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tapplyOrphanGC([from, to]);\n\t};\n\n\tconst upsertEntity = mutate(upsertEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"upsertEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst removeEntity = mutate(removeEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"removeEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst link = mutate(linkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation, weight], _r, m) => ({\n\t\t\taction: \"link\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\trelation: relation as string,\n\t\t\tweight: weight ?? 1,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst unlink = mutate(unlinkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation], _r, m) => ({\n\t\t\taction: \"unlink\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\t...(relation !== undefined ? { relation: relation as string } : {}),\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\n\tfunction relatedNode(\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t): Node<readonly KnowledgeEdge<TRelation>[]> {\n\t\tconst idN = toNode(id, \"id\");\n\t\t// `relation` is OPTIONAL. We deliberately do NOT include it as a dep\n\t\t// when omitted — `state(undefined)` would be a SENTINEL and the\n\t\t// derived's first-run gate would never open. Callers pass a Node\n\t\t// when they want reactive filtering; pass a value to lock the\n\t\t// filter; omit to disable filtering.\n\t\tconst relN = relation !== undefined ? toNode(relation, \"relation\") : undefined;\n\t\tconst deps: Node<unknown>[] = relN\n\t\t\t? [adjacencyOut, adjacencyIn, idN, relN]\n\t\t\t: [adjacencyOut, adjacencyIn, idN];\n\t\treturn node(\n\t\t\tdeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst out = values[0] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst inb = values[1] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst key = values[2] as string;\n\t\t\t\tconst rel = relN ? (values[3] as TRelation | undefined) : undefined;\n\t\t\t\tconst outE = out?.get(key) ?? [];\n\t\t\t\tconst inE = inb?.get(key) ?? [];\n\t\t\t\t// Concatenate, then dedupe by triple key (a self-loop would appear in both).\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst acc: KnowledgeEdge<TRelation>[] = [];\n\t\t\t\tfor (const edge of outE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tfor (const edge of inE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tactions.emit(acc as readonly KnowledgeEdge<TRelation>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: (a, b) => {\n\t\t\t\t\tconst av = a as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tconst bv = b as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tif (av === bv) return true;\n\t\t\t\t\tif (av == null || bv == null) return false;\n\t\t\t\t\tif (av.length !== bv.length) return false;\n\t\t\t\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\t\t\t\tconst x = av[i]!;\n\t\t\t\t\t\tconst y = bv[i]!;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tx.from !== y.from ||\n\t\t\t\t\t\t\tx.to !== y.to ||\n\t\t\t\t\t\t\tx.relation !== y.relation ||\n\t\t\t\t\t\t\tx.weight !== y.weight\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tmeta: memoryMeta(\"related\"),\n\t\t\t},\n\t\t) as Node<readonly KnowledgeEdge<TRelation>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\tentities: entitiesMap.entries,\n\t\tedges: edgesMap.entries,\n\t\tadjacencyOut,\n\t\tadjacencyIn,\n\t\tentityCount,\n\t\tedgeCount,\n\t\tupsertEntity,\n\t\tremoveEntity,\n\t\tlink,\n\t\tunlink,\n\t\trelatedNode,\n\t}) as KnowledgeGraph<TEntity, TRelation>;\n\treturn out;\n}\n\n// ── DS-14.7: reactiveFactStore (static-topology MEME L2/L3 substrate) ─────\n// Lives in its own file (`fact-store.ts`) — re-exported here so the\n// `utils/memory` barrel stays the single import surface alongside\n// collection / vectorIndex / knowledgeGraph.\nexport {\n\ttype AdmissionFilter,\n\ttype CascadeEvent,\n\ttype CascadeOverflow,\n\ttype CascadeReason,\n\ttype DecayPolicy,\n\ttype DependentsIndex,\n\ttype FactId,\n\ttype FactStore,\n\ttype FactStoreAuditRecord,\n\ttype MemoryAnswer,\n\ttype MemoryFragment,\n\ttype MemoryQuery,\n\ttype OutcomeSignal,\n\ttype ReactiveFactStoreConfig,\n\ttype ReactiveFactStoreGraph,\n\ttype ReviewRequest,\n\treactiveFactStore,\n\ttype ScoringPolicy,\n\ttype ShardKey,\n\ttype StoreReadHandle,\n} from \"./fact-store.js\";\n// DS-14.7 follow-up #2 (persistence half) — durable, event-sourced fact store\n// with substrate-owned replay/dedup (memo:Re Story 6.4 back-derivation).\nexport {\n\ttype PersistentReactiveFactStoreConfig,\n\ttype PersistentReactiveFactStoreGraph,\n\tpersistentReactiveFactStore,\n} from \"./persistent-fact-store.js\";\n// DS-14.7 follow-up #1: recipe library — 8 shipped compositions over the\n// four extension faces. Re-exported here so `utils/memory` stays the single\n// import surface.\nexport * from \"./recipes/index.js\";\n","// ---------------------------------------------------------------------------\n// promptCall — public single-shot LLM JSON helper (Tier 4.6 Wave AM Unit 4\n// promotion from the previously-internal `llmJsonCall` in\n// `patterns/ai/memory/llm-memory.ts`).\n//\n// Wraps {@link promptNode} for the common \"one-shot LLM JSON call per input\"\n// shape: a per-call `node([], { initial: input })` is wrapped, the prompt builder runs against\n// it, and the returned `NodeInput<TOut>` slots into reactive callbacks like\n// `distill`'s `extractFn` / `consolidateFn`. Inherits markdown-fence stripping\n// and content-preview parse errors from `promptNode({format: \"json\"})`.\n//\n// `llmExtractor` / `llmConsolidator` are now thin wrappers over `promptCall`.\n// ---------------------------------------------------------------------------\n\nimport { node } from \"@graphrefly/pure-ts/core\";\nimport type { NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport type { Extraction } from \"../../../base/composition/distill.js\";\nimport type { LLMAdapter } from \"../adapters/core/types.js\";\nimport { promptNode } from \"./prompt-node.js\";\n\n/** Options accepted by {@link promptCall}, {@link llmExtractor}, and {@link llmConsolidator}. */\nexport type PromptCallOptions = {\n\tadapter: LLMAdapter;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Optional name forwarded to the underlying `promptNode` (used as the\n\t * `<name>::messages` / `<name>::response` / `<name>::output` path prefix).\n\t * Defaults differ per call site so multiple `promptCall`s wired into the\n\t * same graph don't collide on `prompt_node::output`.\n\t */\n\tname?: string;\n};\n\n/**\n * Build a one-shot LLM JSON-call factory: each invocation wraps `input` in a\n * fresh `node([], { initial: input })`, delegates to `promptNode({format: \"json\"})`, and\n * returns a `NodeInput<TOut>` that the caller plugs into `distill` /\n * `agentLoop` / any reactive composition that accepts `NodeInput`.\n *\n * **Per-call lifecycle.** The returned `NodeInput<TOut>` is a producer that\n * emits exactly one `DATA` per upstream input (per Tier 1.2 Session C lock —\n * `promptNode` guarantees one DATA per wave). When the consumer's switchMap\n * supersedes it, the per-call `node([], { initial: input })` and the inner `prompt_node::response`\n * tear down together.\n *\n * @param systemPrompt - System message sent on every call.\n * @param buildUserContent - Per-input user-content builder (must be JSON-stringifiable).\n * @param opts - Adapter + model/temperature/maxTokens + optional name prefix.\n * @param defaultName - Path-prefix fallback when `opts.name` is omitted.\n * @returns Factory `(input: TIn) => NodeInput<TOut>`.\n *\n * @category patterns\n */\nexport function promptCall<TIn, TOut>(\n\tsystemPrompt: string,\n\tbuildUserContent: (input: TIn) => string,\n\topts: PromptCallOptions,\n\tdefaultName: string,\n): (input: TIn) => NodeInput<TOut> {\n\tconst name = opts.name ?? defaultName;\n\treturn (input: TIn) => {\n\t\t// One-shot node([], { initial: input }) per call — switchMap teardown inside the\n\t\t// consumer (e.g. distill) reclaims the node when the next upstream\n\t\t// arrives or the bundle disposes.\n\t\tconst inputState = node<TIn>([], { initial: input });\n\t\treturn promptNode<TOut>(\n\t\t\topts.adapter,\n\t\t\t[inputState as never],\n\t\t\t(value: unknown) => buildUserContent(value as TIn),\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tformat: \"json\",\n\t\t\t\tsystemPrompt,\n\t\t\t\tmodel: opts.model,\n\t\t\t\ttemperature: opts.temperature ?? 0,\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t},\n\t\t) as NodeInput<TOut>;\n\t};\n}\n\n/** Options accepted by {@link llmExtractor} and {@link llmConsolidator}. */\nexport type LLMExtractorOptions = PromptCallOptions & {\n\t/**\n\t * Cap the dedup-hint slice of `existingKeys` passed to the LLM. Larger\n\t * stores ship more keys (better dedup recall) at the cost of prompt size.\n\t * Default 100. Set to `Infinity` to forward every key.\n\t */\n\tmaxExistingKeys?: number;\n};\n\n/** Alias for backward compatibility. */\nexport type LLMConsolidatorOptions = LLMExtractorOptions;\n\n/**\n * Returns an `extractFn` callback for `distill()` that invokes an LLM to\n * extract structured memories from raw input.\n *\n * The system prompt should instruct the LLM to return JSON matching\n * `Extraction<TMem>` shape: `{ upsert: [{ key, value }], remove?: [key] }`.\n *\n * Built on `promptNode({format: \"json\"})` — inherits markdown-fence stripping\n * and content-preview parse errors. Stack `withRetry` on the adapter for\n * transient-error tolerance (see `patterns/ai/adapters/middleware/retry.ts`).\n */\nexport function llmExtractor<TRaw, TMem>(\n\tsystemPrompt: string,\n\topts: LLMExtractorOptions,\n): (raw: TRaw, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\tconst cap = opts.maxExistingKeys ?? 100;\n\tconst call = promptCall<{ raw: TRaw; existingKeys: string[] }, Extraction<TMem>>(\n\t\tsystemPrompt,\n\t\t(input) => JSON.stringify({ input: input.raw, existingKeys: input.existingKeys }),\n\t\topts,\n\t\t\"llmExtractor\",\n\t);\n\treturn (raw: TRaw, existing: ReadonlyMap<string, TMem>) => {\n\t\tconst existingKeys =\n\t\t\tcap === Number.POSITIVE_INFINITY ? [...existing.keys()] : [...existing.keys()].slice(0, cap);\n\t\treturn call({ raw, existingKeys });\n\t};\n}\n\n/**\n * Returns a `consolidateFn` callback for `distill()` that invokes an LLM to\n * cluster and merge related memories.\n */\nexport function llmConsolidator<TMem>(\n\tsystemPrompt: string,\n\topts: LLMConsolidatorOptions,\n): (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\tconst call = promptCall<readonly { key: string; value: TMem }[], Extraction<TMem>>(\n\t\tsystemPrompt,\n\t\t(memories) => JSON.stringify({ memories }),\n\t\topts,\n\t\t\"llmConsolidator\",\n\t);\n\treturn (entries: ReadonlyMap<string, TMem>) => {\n\t\tconst memories = [...entries.entries()].map(([key, value]) => ({ key, value }));\n\t\treturn call(memories);\n\t};\n}\n","/**\n * `promptNode` — universal LLM transform as a reactive derived node.\n *\n * The shape: `deps → messagesNode (derived) → switchMap → response (producer) → output`.\n * Each upstream wave is one LLM call; superseding waves cancel the in-flight\n * call via the abort signal threaded through `nodeSignal(opts.abort)`.\n *\n * The producer-shape on the inner is load-bearing: it emits exactly one DATA\n * + COMPLETE per wave, so the outer switchMap sees one DATA per wave (matches\n * the `HarnessExecutor` contract). A `node([response], (batchData, actions, ctx) => {\n * const data = ...; actions.emit(parse(data[0]));\n * }, { describeKind: \"derived\" })` would have its\n * own first-run / push-on-subscribe semantics that can leak a transient null\n * before the real response arrives — observed and reverted in an earlier\n * attempt; see SESSION-ai-harness-module-review.md line 3654 for context.\n * Locked as path (b) producer-based by Session C (2026-04-27); inner-node\n * naming aligned to `prompt_node::response` per the C+D widening (2026-04-30).\n *\n * **Retry / replay-cache.** Stack middleware on the adapter:\n *\n * ```ts\n * import { withRetry, withReplayCache } from \"@graphrefly/graphrefly/patterns/ai\";\n *\n * const adapter = withRetry(\n * withReplayCache(baseAdapter, { keyFn: (ctx) => ctx.messages[0].content }),\n * { count: 3, backoff: 200 },\n * );\n * const result = promptNode(adapter, [input], (q) => q);\n * ```\n *\n * `promptNode` no longer ships `retries` / `cache` options — they duplicated\n * middleware already at the adapter layer.\n *\n * **Cross-wave cache (COMPOSITION-GUIDE §32).** The switchMap output cache\n * survives across new outer DATAs — `promptNode`'s cached value persists\n * until the next wave fully resolves. Consumers that need to distinguish\n * \"fresh value for THIS session\" from \"stale cache from a prior session\"\n * (e.g. `agentLoop` resetting on new `run()`) must add a `node([])` mirror\n * at their session boundary and depend on the mirror, not the `promptNode`\n * output directly. `promptNode` itself stays primitive — it does not\n * embed a state-mirror.\n *\n * @module\n */\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { nodeSignal } from \"../../../base/sources/settled.js\";\nimport { aiMeta, stripFences } from \"../_internal.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tToolDefinition,\n} from \"../adapters/core/types.js\";\n\nexport type PromptNodeOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Output format:\n\t * - `\"text\"` (default) — emit the response content as a string.\n\t * - `\"json\"` — `JSON.parse` the content (markdown fences stripped).\n\t * - `\"raw\"` — emit the full {@link LLMResponse} object (subsumes the\n\t * pre-Tier-2.3 `fromLLM` shape; use this when you need `usage` /\n\t * `toolCalls` / `finishReason` alongside `content`).\n\t */\n\tformat?: \"text\" | \"json\" | \"raw\";\n\t/**\n\t * Reactive tool definitions forwarded to the adapter. Pair with\n\t * `format: \"raw\"` (or read `toolCalls` from a downstream parser) when\n\t * tool-calling is in scope.\n\t *\n\t * **Reactive declared edge** (DF12, Tier 7): `tools` is a `Node` so the\n\t * tools list participates in `describe()` topology and `explain()` causal\n\t * chains. The tools Node is added to `messagesNode`'s declared deps —\n\t * tools changes re-invoke the LLM (treated as a new call envelope).\n\t * Wrap with `distinctUntilChanged` upstream if your tool selector emits\n\t * noisy duplicates that would otherwise spam the adapter. See\n\t * COMPOSITION-GUIDE §31 (Dynamic tool selection) for the canonical\n\t * `toolSelector` pattern that produces this Node.\n\t *\n\t * **Activation note:** since `tools` is a real declared dep, `messagesNode`\n\t * waits for the tools Node to DATA at least once before firing\n\t * (push-on-subscribe SENTINEL gate). Pass a `node<ToolDefinition[]>([], { initial: [] })`\n\t * if you want immediate activation with no tools, or the latest published\n\t * `toolSelector.tools` Node.\n\t */\n\ttools?: Node<readonly ToolDefinition[]>;\n\t/**\n\t * Optional system prompt. Forwarded via `opts.systemPrompt` to the adapter\n\t * only — never pushed as a `{role:\"system\"}` message (avoiding the\n\t * double-send class of bug where adapters that normalize both shapes end\n\t * up with two system entries).\n\t */\n\tsystemPrompt?: string;\n\t/**\n\t * Optional reactive abort signal. When the node emits `true`, the in-flight\n\t * `adapter.invoke()` call is cancelled via `AbortController.abort()`.\n\t * Threaded through `nodeSignal(abort)` — a one-shot bridge. Useful inside\n\t * agent state machines where a separate `aborted` state should cancel the\n\t * current LLM call without superseding via switchMap.\n\t */\n\tabort?: Node<boolean>;\n\tmeta?: Record<string, unknown>;\n};\n\n/** Extract text content from an LLM response, handling various response shapes. */\nfunction extractContent(resp: unknown): string {\n\tif (resp != null && typeof resp === \"object\" && \"content\" in resp) {\n\t\treturn String((resp as LLMResponse).content);\n\t}\n\tif (typeof resp === \"string\") return resp;\n\treturn String(resp);\n}\n\nfunction previewContent(text: string, max = 200): string {\n\tif (text.length <= max) return text;\n\treturn `${text.slice(0, max)}…`;\n}\n\n/**\n * Universal LLM transform: wraps a prompt template + model adapter into a reactive derived node.\n * Re-invokes the LLM whenever any dep changes. Suitable for triage, QA, hypothesis, parity, etc.\n *\n * **Topology** (visible in `describe()`):\n * ```\n * <deps...>, [tools?] → <name>::messages (derived, meta.ai = prompt_node::messages)\n * <name>::messages → <name>::output (switchMap product, meta.ai = prompt_node::output)\n * per-wave inner: <name>::response (producer, meta.ai = prompt_node::response)\n * ```\n * When `opts.tools` is supplied, the tools `Node` is appended to\n * `messagesNode`'s declared deps so it appears as a real edge in `describe()`\n * / `explain()` (DF12, Tier 7).\n *\n * **No-input semantics** (matches the codebase-wide SENTINEL convention):\n * - **Initial no-input** (no real input has ever arrived) — emits nothing.\n * Outer cache stays `undefined`; `subscribe` consumers see no DATA event.\n * Use this to keep downstream gating clean: a `withLatestFrom`-paired\n * trigger won't fire until the LLM has actually produced something.\n * - **Mid-flow no-input** (input dropped to nullish after at least one\n * real LLM call) — emits `null` as a domain \"input went away\" signal.\n * Downstream consumers can distinguish \"haven't started\" from \"input\n * gone.\"\n *\n * **Retries / caching:** stack `withRetry` / `withReplayCache` middleware on the\n * `adapter` argument — `promptNode` no longer ships its own duplicated retry /\n * cache loops (pre-1.0 cleanup, see review session 1).\n *\n * @param adapter - LLM adapter (provider-agnostic). Wrap with `withRetry` /\n * `withReplayCache` middleware for transient-error tolerance\n * or replay caching.\n * @param deps - Input nodes whose values feed the prompt.\n * @param prompt - Static string or template function receiving dep values.\n * @param opts - Optional configuration.\n * @returns `Node` emitting LLM responses (string or parsed JSON).\n */\n// Overload 1: `format: \"raw\"` constrains the emit type to `LLMResponse | null`\n// (the full adapter response, with `usage` / `toolCalls` / `finishReason`).\n// Subsumes the pre-Tier-2.3 `fromLLM` shape.\nexport function promptNode(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts: PromptNodeOptions & { format: \"raw\" },\n): Node<LLMResponse | null>;\n// Overload 2: `format: \"text\" | \"json\"` (default text) — emit-type is the\n// caller's `T` (defaults to `string`). For `\"json\"` callers typically pass\n// the parsed shape (e.g. `promptNode<MyShape>(...)`).\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: Omit<PromptNodeOptions, \"format\"> & { format?: \"text\" | \"json\" },\n): Node<T | null>;\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: PromptNodeOptions,\n): Node<T | null> {\n\tconst format = opts?.format ?? \"text\";\n\tconst baseName = opts?.name ?? \"prompt_node\";\n\n\t// qa A8: tools without `format: \"raw\"` is a footgun — adapter receives\n\t// the tool definitions and may produce `toolCalls`, but the emit path\n\t// only extracts `content`. Warn at construction; downstream parsers\n\t// reading `toolCalls` from a custom `format: \"raw\"` consumer pattern\n\t// can ignore by setting `format: \"raw\"` (intent now matches behavior).\n\tif (opts?.tools !== undefined && format !== \"raw\") {\n\t\tconsole.warn(\n\t\t\t\"promptNode: `tools` is set but `format !== 'raw'`. \" +\n\t\t\t\t\"Tool calls in the response will be silently dropped — set \" +\n\t\t\t\t\"`format: 'raw'` to receive the full LLMResponse with `toolCalls`.\",\n\t\t);\n\t}\n\n\t// SENTINEL semantics rely on the universal first-run gate + standard\n\t// prevData semantics (undefined = SENTINEL, any other value = DATA seen):\n\t// - **Initial no-input** (no dep has ever DATA'd, so prevData is\n\t// undefined across the board): the `derived`'s first-run gate blocks\n\t// `messagesNode`'s fn entirely. It never emits, switchMap never\n\t// fires, outer cache stays `undefined`.\n\t// - **Mid-flow no-input** (deps previously DATA'd then went nullish):\n\t// fn runs, returns `[]`, switchMap dispatches the `node([], { initial: null })`\n\t// branch → outer emits `null` as the domain \"input went away\" signal.\n\t// No `initial: []` and no closure flag — `prevData === undefined` is\n\t// already the sentinel marker, and the gate already enforces \"don't fire\n\t// fn until every dep has DATA'd at least once.\"\n\t//\n\t// DF12: when `opts.tools` is a Node, it's appended to `messagesNode`'s\n\t// declared deps. The fn slices values into user-deps + tools, and emits\n\t// an envelope `{ messages, tools }` so switchMap's per-wave inner can\n\t// read the latest tools via the reactive edge instead of a closure.\n\ttype Envelope = {\n\t\tmessages: readonly ChatMessage[];\n\t\ttools: readonly ToolDefinition[] | undefined;\n\t};\n\tconst userDepsLength = deps.length;\n\tconst allDeps: readonly Node<unknown>[] =\n\t\topts?.tools !== undefined ? [...deps, opts.tools as Node<unknown>] : deps;\n\tconst messagesNode = node<Envelope>(\n\t\tallDeps as Node<unknown>[],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst userValues = data.slice(0, userDepsLength);\n\t\t\tconst toolsValue =\n\t\t\t\topts?.tools !== undefined\n\t\t\t\t\t? (data[userDepsLength] as readonly ToolDefinition[] | undefined)\n\t\t\t\t\t: undefined;\n\t\t\t// Dep-level null guard (composition guide §8): if any USER dep is\n\t\t\t// nullish, emit empty messages → switchMap emits null (mid-flow\n\t\t\t// drop-out). The tools dep can legitimately be empty `[]`; only\n\t\t\t// user deps gate the call.\n\t\t\tif (userValues.some((v) => v == null)) {\n\t\t\t\tactions.emit({ messages: [], tools: toolsValue });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...userValues);\n\t\t\tif (!text) {\n\t\t\t\tactions.emit({ messages: [], tools: toolsValue });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// systemPrompt forwarded through invoke opts only (no double-send).\n\t\t\tactions.emit({\n\t\t\t\tmessages: [{ role: \"user\" as const, content: text }],\n\t\t\t\ttools: toolsValue,\n\t\t\t});\n\t\t},\n\t\t{\n\t\t\tname: `${baseName}::messages`,\n\t\t\tmeta: aiMeta(\"prompt_node::messages\"),\n\t\t},\n\t);\n\n\tconst result = switchMap<Envelope, T | null>(\n\t\tmessagesNode,\n\t\t(envelope) => {\n\t\t\tconst { messages: msgs, tools } = envelope;\n\t\t\tif (!msgs || msgs.length === 0) {\n\t\t\t\treturn node<T | null>([], { initial: null }) as NodeInput<T | null>;\n\t\t\t}\n\n\t\t\t// Producer ensures exactly one DATA + COMPLETE per wave; switchMap\n\t\t\t// sees one DATA, the harness's \"one emission per wave\" contract is\n\t\t\t// honored. Earlier attempts using a derived node leaked\n\t\t\t// transient nulls via the derived's first-run gate.\n\t\t\treturn node<T | null>(\n\t\t\t\t(_data, actions) => {\n\t\t\t\t\tlet done = false;\n\t\t\t\t\tlet cancelled = false;\n\t\t\t\t\tlet abortDispose: (() => void) | undefined;\n\n\t\t\t\t\tconst invokeOpts: LLMInvokeOptions = {\n\t\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\t\t...(tools !== undefined ? { tools } : {}),\n\t\t\t\t\t};\n\t\t\t\t\tif (opts?.abort) {\n\t\t\t\t\t\tconst sig = nodeSignal(opts.abort);\n\t\t\t\t\t\tinvokeOpts.signal = sig.signal;\n\t\t\t\t\t\tabortDispose = sig.dispose;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet invokeResult: NodeInput<LLMResponse>;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinvokeResult = adapter.invoke(msgs, invokeOpts);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst callNode = fromAny(invokeResult);\n\n\t\t\t\t\tconst sub = callNode.subscribe((batch) => {\n\t\t\t\t\t\tif (cancelled || done) return;\n\t\t\t\t\t\tfor (const msg of batch) {\n\t\t\t\t\t\t\t// F-11: re-check `cancelled` (and `done`) at the top of\n\t\t\t\t\t\t\t// each per-message iteration so a teardown / abort that\n\t\t\t\t\t\t\t// fires synchronously between messages stops processing\n\t\t\t\t\t\t\t// further batched messages immediately.\n\t\t\t\t\t\t\tif (cancelled || done) return;\n\t\t\t\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\t\t\t\tconst resp = msg[1] as LLMResponse;\n\t\t\t\t\t\t\t\t// `format: \"raw\"` bypasses parsing — emit the full\n\t\t\t\t\t\t\t\t// LLMResponse object (subsumes the pre-Tier-2.3 `fromLLM`\n\t\t\t\t\t\t\t\t// output shape).\n\t\t\t\t\t\t\t\tif (format === \"raw\") {\n\t\t\t\t\t\t\t\t\tactions.emit(resp as unknown as T);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// F-12: cache the extracted content once on the\n\t\t\t\t\t\t\t\t\t// parse-failure path so we don't call\n\t\t\t\t\t\t\t\t\t// `extractContent(resp)` twice (once for parsing,\n\t\t\t\t\t\t\t\t\t// once for the error-message preview).\n\t\t\t\t\t\t\t\t\tlet content: string;\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tcontent = extractContent(resp);\n\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\t// extractContent itself failed — propagate as\n\t\t\t\t\t\t\t\t\t\t// an ERROR with a generic raw-extraction message.\n\t\t\t\t\t\t\t\t\t\tconst wrapped = new Error(\n\t\t\t\t\t\t\t\t\t\t\t`promptNode: failed to extract content from LLM response: ${\n\t\t\t\t\t\t\t\t\t\t\t\t(err as Error).message\n\t\t\t\t\t\t\t\t\t\t\t}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal-error\n\t\t\t\t\t\t\t\t\t\t// branches so we don't retain the AbortController\n\t\t\t\t\t\t\t\t\t\t// after the wave terminates. Idempotent.\n\t\t\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tactions.down([[ERROR, wrapped]]);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst parsed: T =\n\t\t\t\t\t\t\t\t\t\t\tformat === \"json\"\n\t\t\t\t\t\t\t\t\t\t\t\t? (JSON.parse(stripFences(content)) as T)\n\t\t\t\t\t\t\t\t\t\t\t\t: (content as unknown as T);\n\t\t\t\t\t\t\t\t\t\tactions.emit(parsed);\n\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\tconst wrapped = new Error(\n\t\t\t\t\t\t\t\t\t\t\t`promptNode: failed to parse LLM response as JSON: ${\n\t\t\t\t\t\t\t\t\t\t\t\t(err as Error).message\n\t\t\t\t\t\t\t\t\t\t\t}\\n Raw content (first 200 chars): ${previewContent(content)}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// F-7: dispose abort hook on parse-error\n\t\t\t\t\t\t\t\t\t\t// terminal branch.\n\t\t\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tactions.down([[ERROR, wrapped]]);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (msg[0] === ERROR) {\n\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal ERROR branch.\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\tactions.down([[ERROR, msg[1]]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} else if (msg[0] === COMPLETE) {\n\t\t\t\t\t\t\t\t// Adapter completed — propagate. emit() above already\n\t\t\t\t\t\t\t\t// queued the parsed value so the wave carries DATA + COMPLETE.\n\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal COMPLETE branch.\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Spec §1.3.6 forward-unknown — DIRTY/RESOLVED/INVALIDATE/\n\t\t\t\t\t\t\t\t// PAUSE/RESUME etc. should propagate so downstream caches /\n\t\t\t\t\t\t\t\t// flow-control hooks aren't starved. Re-typed `as never`\n\t\t\t\t\t\t\t\t// because the call's NodeInput<LLMResponse> message tuple\n\t\t\t\t\t\t\t\t// is wider than the unbound `T` projection.\n\t\t\t\t\t\t\t\tactions.down([msg as never]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t\t\tsub();\n\t\t\t\t\t\t\t// F-7: cleanup callback's abortDispose call is idempotent —\n\t\t\t\t\t\t\t// the terminal-branch dispose above sets `abortDispose =\n\t\t\t\t\t\t\t// undefined` so this is a no-op when terminal-fired.\n\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\t\tname: `${baseName}::response`,\n\t\t\t\t\tmeta: aiMeta(\"prompt_node::response\"),\n\t\t\t\t},\n\t\t\t) as NodeInput<T | null>;\n\t\t},\n\t\t{\n\t\t\tname: `${baseName}::output`,\n\t\t\tmeta: opts?.meta\n\t\t\t\t? { ...aiMeta(\"prompt_node::output\"), ...opts.meta }\n\t\t\t\t: aiMeta(\"prompt_node::output\"),\n\t\t},\n\t);\n\n\treturn result;\n}\n","/**\n * Phase 13.H — `agent(spec)` preset + `presetRegistry` sugar.\n *\n * Source: `archive/docs/SESSION-multi-agent-gap-analysis.md` G1 + G2.\n *\n * `agent()` is the ergonomic factory — given a parent Graph and an\n * `AgentSpec`, mints an `AgentGraph`, mounts it under the parent at\n * `spec.name`, and returns the `AgentBundle` contract.\n *\n * `presetRegistry()` is thin sugar over `reactiveMap` — a typed reactive\n * map of `<id, preset>`. Pairs with `materialize` (Phase 13.C) for\n * dynamic preset selection: callers store specs / factories / configs in\n * the registry and `materialize` mounts the matching one based on a\n * routing key.\n *\n * **Cross-cut #1 lock:** no `agent.run()` imperative sugar — caller-side\n * runtime is `bundle.in.emit(input)` + `awaitSettled(bundle.out)`.\n */\n\nimport { type ReactiveMapBundle, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport type { LLMResponse } from \"../../utils/ai/adapters/core/types.js\";\nimport { type AgentBundle, AgentGraph, type AgentSpec } from \"./agent.js\";\n\n// ---------------------------------------------------------------------------\n// agent() factory\n// ---------------------------------------------------------------------------\n\n/**\n * Mints an {@link AgentGraph} from `spec`, mounts it under `parent` at\n * `spec.name`, and returns the {@link AgentBundle} contract.\n *\n * **Default type parameters.** When called without explicit type params,\n * `TIn` defaults to `string` and `TOut` to `LLMResponse` — the common\n * case where the caller writes a user message and reads the raw response.\n * Custom types require both `inMapper` and `outMapper` in the spec; the\n * default mappers throw at runtime if `TIn` / `TOut` aren't string /\n * LLMResponse.\n *\n * **Memory partition default.** Each `agent()` call mints its own\n * `AgentMemoryGraph` if `spec.memory` is omitted (private memory; the\n * common case). Pass an explicit shared instance — e.g.\n * `agent(parent, { ..., memory: sharedMemory })` for two agents — to\n * implement §29 handoff context transfer.\n *\n * **Reactive entry / exit:**\n * - `bundle.in.emit(input)` kicks the loop reactively (no imperative\n * `.run()` per cross-cut #1 lock).\n * - `awaitSettled(bundle.out, { skipCurrent: true })` resolves on the\n * first response after the kick. `skipCurrent` matters for the second\n * call onward — `out` caches the prior response.\n *\n * **Mounting.** The factory mounts under `parent.mount(spec.name, ...)`.\n * The slot name must be free on `parent` at construction time. To keep\n * the agent unmounted, construct `new AgentGraph(spec)` directly.\n *\n * @example\n * ```ts\n * import { agent, awaitSettled, Graph } from \"@graphrefly/graphrefly-ts\";\n *\n * const parent = new Graph(\"parent\");\n * const a = agent(parent, {\n * name: \"researcher\",\n * adapter: openaiAdapter,\n * systemPrompt: \"Research the user's question carefully.\",\n * });\n * a.in.emit(\"What's the capital of France?\");\n * const resp = await awaitSettled(a.out, { skipCurrent: true });\n * ```\n *\n * @category patterns\n */\nexport function agent<TIn = string, TOut = LLMResponse>(\n\tparent: Graph,\n\tspec: AgentSpec<TIn, TOut>,\n): AgentBundle<TIn, TOut> {\n\tconst graph = new AgentGraph<TIn, TOut>(spec);\n\tparent.mount(spec.name, graph);\n\treturn {\n\t\tin: graph.in,\n\t\tout: graph.out,\n\t\tstatus: graph.status,\n\t\tcost: graph.cost,\n\t\tgraph,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// presetRegistry()\n// ---------------------------------------------------------------------------\n\n/**\n * The bundle returned by {@link presetRegistry}. Wraps a `reactiveMap`\n * with imperative `put` / `remove` shortcuts and exposes the underlying\n * `registry` for direct reactive consumption (`.entries` is a\n * `Node<ReadonlyMap<string, TPreset>>`).\n *\n * Use the `registry.entries` Node directly with {@link materialize} (Phase\n * 13.C) — pass it as the `factories` argument when `TPreset` is itself\n * a `() => Graph` factory thunk, or transform via `derived` when\n * `TPreset` is a richer spec type that needs a `spec → factory` adapter.\n */\nexport interface PresetRegistryBundle<TPreset> {\n\t/**\n\t * The underlying reactive map. `registry.entries` is the\n\t * `Node<ReadonlyMap<string, TPreset>>` — pass directly to\n\t * {@link materialize} when preset shape matches the factories arg.\n\t */\n\treadonly registry: ReactiveMapBundle<string, TPreset>;\n\t/** Imperative add / replace. Always emits a fresh snapshot. */\n\tput(id: string, preset: TPreset): void;\n\t/** Imperative remove. Returns `true` if the id was present. */\n\tremove(id: string): boolean;\n}\n\n/**\n * Thin sugar over `reactiveMap` — a typed registry of `<id, preset>` for\n * agent / strategy / persona / skill catalogs.\n *\n * **Generic over preset shape.** `TPreset` is open — could be an\n * {@link AgentSpec}, a `() => Graph` factory thunk, a static config\n * object, or anything else. Decoupled from `agent()` so the same primitive\n * powers harnessLoop strategy registries, pipelineGraph stage catalogs,\n * etc.\n *\n * **Composes with `materialize`.** When `TPreset` is a `() => Graph`\n * factory, pass `registry.entries` directly to\n * {@link materialize} as the `factories` argument. When `TPreset` is a\n * spec, transform via `derived` to build a `Map<id, () => Graph>` adapter:\n *\n * ```ts\n * const presets = presetRegistry<AgentSpec<string, LLMResponse>>();\n * presets.put(\"researcher\", { name: \"researcher\", adapter, systemPrompt: \"...\" });\n *\n * // Adapter: spec → factory.\n * const factories = derived(\n * [presets.registry.entries],\n * ([m]) => new Map(\n * [...m].map(([id, spec]) => [id, () => new AgentGraph(spec)]),\n * ),\n * );\n * const slot = materialize(activeKey, factories, parent);\n * ```\n *\n * @param initial - Optional initial entries.\n * @returns {@link PresetRegistryBundle}.\n *\n * @category patterns\n */\nexport function presetRegistry<TPreset>(\n\tinitial?: ReadonlyMap<string, TPreset>,\n): PresetRegistryBundle<TPreset> {\n\tconst registry = reactiveMap<string, TPreset>({ name: \"presetRegistry\" });\n\tif (initial != null) {\n\t\tfor (const [id, preset] of initial) {\n\t\t\tregistry.set(id, preset);\n\t\t}\n\t}\n\treturn {\n\t\tregistry,\n\t\tput(id, preset) {\n\t\t\tregistry.set(id, preset);\n\t\t},\n\t\tremove(id) {\n\t\t\tif (!registry.has(id)) return false;\n\t\t\tregistry.delete(id);\n\t\t\treturn true;\n\t\t},\n\t};\n}\n","/**\n * DS-14.6.A U-A — tagged context substrate (Phase 14.5).\n *\n * Per-view tagged context (SESSION-DS-14.6-A L3–L6 + SESSION-DS-14.6-A-9Q\n * implementation walk). Pool stores immutable tier-0 originals on an\n * **append-only `reactiveLog`** (D-A4 — structural tier-0 immutability, free\n * `LogChange` mutations, side-steps the DS14R1 TTL/LRU prune-fidelity bug).\n * Each consumer holds a `ContextView` that materialises its own filtered +\n * compressed slice (`Node<readonly RenderedEntry[]>`). Routing is mechanical\n * tag comparison (zero LLM); only `llm-summary` rules cross to an injected\n * `llmCompress` (D-A3). Compression cache is one shared `(id, tier)` map in\n * the pool bundle, bounded LRU (D-A5). Schema is pure data, presentation\n * layer (D-A1) — no `@graphrefly/pure-ts` consumer.\n *\n * @module\n */\n\nimport { type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../../../utils/ai/_internal.js\";\n\n// ── Schema (pure data — D-A1) ────────────────────────────────────────────────\n\nexport type Tag = string;\n\n/** Compression tier. 0 = original; higher = more compressed. */\nexport type Tier = 0 | 1 | 2 | 3;\n\nexport interface ContextEntry<T> {\n\t/** Stable id — cache key component `(id, tier)`. Auto-assigned if omitted. */\n\treadonly id: string;\n\treadonly payload: T;\n\treadonly tags: readonly Tag[];\n\t/** 0..1. Budget/GC ordering. */\n\treadonly importance: number;\n\treadonly compressible: boolean;\n\treadonly topic: string;\n\t/** Wall-clock at add (ns) — used by `poolGC({ olderThanNs })`. */\n\treadonly t_ns: number;\n}\n\nexport interface RuleMatch {\n\treadonly topic?: string | RegExp;\n\treadonly tagsAny?: readonly Tag[];\n\treadonly importanceMin?: number;\n\treadonly importanceMax?: number;\n\treadonly compressible?: boolean;\n}\n\nexport type CompressionRule =\n\t| { readonly match: RuleMatch; readonly action: \"evict\" }\n\t| { readonly match: RuleMatch; readonly action: \"truncate\"; readonly maxChars: number }\n\t| { readonly match: RuleMatch; readonly action: \"reference\" }\n\t| { readonly match: RuleMatch; readonly action: \"llm-summary\"; readonly toTier: Tier };\n\nexport interface RenderedEntry<T> {\n\treadonly id: string;\n\treadonly topic: string;\n\treadonly tags: readonly Tag[];\n\treadonly tier: Tier;\n\t/** Original payload at tier 0; compressed `string` otherwise. */\n\treadonly payload: T | string;\n\treadonly compressed: boolean;\n}\n\nexport interface ContextView<T> {\n\treadonly filter: (e: ContextEntry<T>) => boolean;\n\t/** 0..1. A rule fires when `pressure > 0` and the entry matches. */\n\treadonly pressure: Node<number>;\n\treadonly budgetTokens: number;\n\treadonly rules: readonly CompressionRule[];\n\t/** Default `s => Math.ceil(s.length / 4)`. */\n\treadonly tokenizer?: (s: string) => number;\n}\n\nexport interface PoolGCPolicy {\n\t/** Drop entries with `t_ns < (now - olderThanNs)`. */\n\treadonly olderThanNs?: number;\n\t/** Drop entries with `importance < importanceBelow`. */\n\treadonly importanceBelow?: number;\n\t/**\n\t * **Scope**, not a match-to-evict rule: when set, GC only considers\n\t * entries whose `topic === this`; entries of other topics always survive.\n\t * `olderThanNs` / `importanceBelow` are ANDed *within* this scope.\n\t */\n\treadonly topic?: string;\n\t/** Keep at most this many most-recent entries. */\n\treadonly max?: number;\n}\n\n/** `(entry, toTier) => compressedText`. Injected; required iff a view uses `llm-summary`. */\nexport type LlmCompress<T> = (entry: ContextEntry<T>, toTier: Tier) => string;\n\nexport interface TaggedContextPoolOptions<T> {\n\treadonly topic: string;\n\t/** Forwarded to the backing append-only `reactiveLog` (poolGC ceiling). */\n\treadonly maxEntries?: number;\n\t/** Required iff any rendered view uses an `llm-summary` rule (D-A3). */\n\treadonly llmCompress?: LlmCompress<T>;\n\t/** Shared `(id, tier)` compression cache cap (D-A5). Default 512. */\n\treadonly cacheMax?: number;\n\treadonly name?: string;\n}\n\nexport interface TaggedContextPoolBundle<T> {\n\t/**\n\t * Append an entry (immutable tier-0). Returns its id (auto-assigned\n\t * `ctx-N` per-pool if omitted).\n\t *\n\t * **Caller-supplied ids must be unique within the pool.** The log is\n\t * append-only and does NOT dedupe; the compression cache is keyed by\n\t * `(id, tier)`, so appending two different entries with the same explicit\n\t * `id` makes the second render the first's cached summary (QA P11).\n\t */\n\tadd(entry: Omit<ContextEntry<T>, \"id\" | \"t_ns\"> & { id?: string }): string;\n\t/** All live tier-0 entries. */\n\treadonly entries: Node<readonly ContextEntry<T>[]>;\n\t/** Entries carrying `tag`. */\n\tbyTag(tag: Tag): Node<readonly ContextEntry<T>[]>;\n\t/** Pool-global retention (L6 — distinct from per-view filtering). Returns removed count. */\n\tpoolGC(policy: PoolGCPolicy): number;\n\treadonly graph: Graph;\n\t/** Internal — shared compression cache (one per pool, D-A5). */\n\treadonly _cache: CompressionCache;\n\treadonly _opts: TaggedContextPoolOptions<T>;\n\tdispose(): void;\n}\n\n// ── Shared bounded (id,tier) compression cache (D-A5) ────────────────────────\n\n/**\n * Bounded LRU cache keyed by `(id, tier)`. Uses a nested `Map<id, Map<tier,\n * value>>` (NOT a `${id}::${tier}` string key) so a caller-supplied `id`\n * containing the separator cannot collide (QA P5). LRU is tracked at the\n * (id,tier) leaf via a flat insertion-order key list.\n */\nexport class CompressionCache {\n\tprivate readonly _m = new Map<string, Map<Tier, string>>();\n\t/** Insertion-order list of `id` keys for LRU eviction at the id granularity. */\n\tprivate readonly _order: string[] = [];\n\tconstructor(private readonly _max: number) {}\n\tget(id: string, tier: Tier): string | undefined {\n\t\tconst inner = this._m.get(id);\n\t\tconst v = inner?.get(tier);\n\t\tif (v !== undefined) {\n\t\t\tconst i = this._order.indexOf(id);\n\t\t\tif (i >= 0) this._order.splice(i, 1);\n\t\t\tthis._order.push(id);\n\t\t}\n\t\treturn v;\n\t}\n\tset(id: string, tier: Tier, value: string): void {\n\t\tlet inner = this._m.get(id);\n\t\tif (inner === undefined) {\n\t\t\tinner = new Map<Tier, string>();\n\t\t\tthis._m.set(id, inner);\n\t\t}\n\t\tinner.set(tier, value);\n\t\tconst i = this._order.indexOf(id);\n\t\tif (i >= 0) this._order.splice(i, 1);\n\t\tthis._order.push(id);\n\t\twhile (this._m.size > this._max) {\n\t\t\tconst evict = this._order.shift();\n\t\t\tif (evict === undefined) break;\n\t\t\tthis._m.delete(evict);\n\t\t}\n\t}\n}\n\n// ── Pool ─────────────────────────────────────────────────────────────────────\n\n/** Process-wide sequence for collision-safe default mount names (QA P6). */\nlet _poolSeq = 0;\n\n/**\n * Append-only tagged context pool (D-A4). The pool is a `reactiveLog` of\n * immutable tier-0 entries plus a derived `entries` node; `byTag` derives a\n * filtered view; `poolGC` is the explicit pool-global retention (L6).\n */\nexport function taggedContextPool<T>(\n\tparent: Graph,\n\topts: TaggedContextPoolOptions<T>,\n): TaggedContextPoolBundle<T> {\n\t// QA P6: collision-safe default mount name — two pools with the same\n\t// `topic` under one parent must not collide on `parent.mount`. Explicit\n\t// `opts.name` is respected verbatim (caller owns uniqueness then).\n\tconst mountName = opts.name ?? `ctxpool-${opts.topic}-${++_poolSeq}`;\n\tconst graph = new Graph(mountName);\n\tparent.mount(mountName, graph);\n\n\tconst log: ReactiveLogBundle<ContextEntry<T>> = reactiveLog<ContextEntry<T>>(undefined, {\n\t\tname: `${mountName}.log`,\n\t\tmaxSize: opts.maxEntries,\n\t});\n\tconst cache = new CompressionCache(opts.cacheMax ?? 512);\n\t// QA P5: per-pool id counter (was module-global → test-pollution +\n\t// cross-pool cache-key cross-talk).\n\tlet autoId = 0;\n\n\tconst entries: Node<readonly ContextEntry<T>[]> = log.entries;\n\n\tfunction add(e: Omit<ContextEntry<T>, \"id\" | \"t_ns\"> & { id?: string }): string {\n\t\tconst id = e.id ?? `ctx-${++autoId}`;\n\t\tlog.append({\n\t\t\tid,\n\t\t\tpayload: e.payload,\n\t\t\ttags: e.tags,\n\t\t\timportance: e.importance,\n\t\t\tcompressible: e.compressible,\n\t\t\ttopic: e.topic,\n\t\t\tt_ns: wallClockNs(), // QA P2 — clock.ts invariant (was Date.now()*1e6)\n\t\t});\n\t\treturn id;\n\t}\n\n\tfunction byTag(tag: Tag): Node<readonly ContextEntry<T>[]> {\n\t\treturn node<readonly ContextEntry<T>[]>(\n\t\t\t[entries as Node],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst cur = (data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly ContextEntry<T>[]\n\t\t\t\t\t| undefined;\n\t\t\t\tactions.emit((cur ?? []).filter((x) => x.tags.includes(tag)));\n\t\t\t},\n\t\t\t{ describeKind: \"derived\", meta: aiMeta(\"contextPool.byTag\", { tag }) },\n\t\t);\n\t}\n\n\tfunction poolGC(policy: PoolGCPolicy): number {\n\t\tconst all = log.entries.cache ?? [];\n\t\tconst nowNs = wallClockNs();\n\t\tlet survivors = all.filter((e) => {\n\t\t\t// QA P1: `topic` is a SCOPE, not a match-to-evict rule — entries\n\t\t\t// outside the topic are never GC'd by this call; eviction criteria\n\t\t\t// (olderThanNs / importanceBelow) are ANDed within the scope.\n\t\t\tif (policy.topic != null && e.topic !== policy.topic) return true;\n\t\t\tif (policy.olderThanNs != null && nowNs - e.t_ns >= policy.olderThanNs) return false;\n\t\t\tif (policy.importanceBelow != null && e.importance < policy.importanceBelow) return false;\n\t\t\treturn true;\n\t\t});\n\t\tif (policy.max != null && survivors.length > policy.max) {\n\t\t\tsurvivors = survivors.slice(survivors.length - policy.max);\n\t\t}\n\t\tconst removed = all.length - survivors.length;\n\t\tif (removed > 0) {\n\t\t\tlog.clear();\n\t\t\tlog.appendMany(survivors);\n\t\t}\n\t\treturn removed;\n\t}\n\n\treturn {\n\t\tadd,\n\t\tentries,\n\t\tbyTag,\n\t\tpoolGC,\n\t\tgraph,\n\t\t_cache: cache,\n\t\t_opts: opts,\n\t\tdispose(): void {\n\t\t\tlog.dispose();\n\t\t},\n\t};\n}\n\n// ── tierCompress + renderContextView ─────────────────────────────────────────\n\nconst DEFAULT_TOKENIZER = (s: string): number => Math.ceil(s.length / 4);\n\nfunction matches(e: ContextEntry<unknown>, m: RuleMatch): boolean {\n\tif (m.topic != null) {\n\t\tif (typeof m.topic === \"string\" ? e.topic !== m.topic : !m.topic.test(e.topic)) return false;\n\t}\n\tif (m.tagsAny != null && !m.tagsAny.some((t) => e.tags.includes(t))) return false;\n\tif (m.importanceMin != null && e.importance < m.importanceMin) return false;\n\tif (m.importanceMax != null && e.importance > m.importanceMax) return false;\n\tif (m.compressible != null && e.compressible !== m.compressible) return false;\n\treturn true;\n}\n\n/**\n * Apply the first matching rule to one entry under `pressure`. Non-LLM\n * strategies (truncate / evict / reference) are pure data; `llm-summary`\n * calls the injected `llmCompress`, caching by `(id, toTier)` (D-A5).\n * Returns `undefined` for evicted / pressure-filtered entries.\n */\nexport function tierCompress<T>(\n\te: ContextEntry<T>,\n\trules: readonly CompressionRule[],\n\tpressure: number,\n\tcache: CompressionCache,\n\tllmCompress?: LlmCompress<T>,\n): RenderedEntry<T> | undefined {\n\tconst base: RenderedEntry<T> = {\n\t\tid: e.id,\n\t\ttopic: e.topic,\n\t\ttags: e.tags,\n\t\ttier: 0,\n\t\tpayload: e.payload,\n\t\tcompressed: false,\n\t};\n\tif (pressure <= 0) return base;\n\tfor (const rule of rules) {\n\t\tif (!matches(e, rule.match)) continue;\n\t\tswitch (rule.action) {\n\t\t\tcase \"evict\":\n\t\t\t\treturn undefined;\n\t\t\tcase \"reference\":\n\t\t\t\treturn { ...base, tier: 1, payload: `[ref:${e.id}]`, compressed: true };\n\t\t\tcase \"truncate\": {\n\t\t\t\tconst s = typeof e.payload === \"string\" ? e.payload : JSON.stringify(e.payload);\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttier: 1,\n\t\t\t\t\tpayload: s.length > rule.maxChars ? s.slice(0, rule.maxChars) : s,\n\t\t\t\t\tcompressed: s.length > rule.maxChars,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"llm-summary\": {\n\t\t\t\tif (!llmCompress) {\n\t\t\t\t\t// Defence-in-depth — construction guard should have thrown.\n\t\t\t\t\tthrow new Error(\"tierCompress: 'llm-summary' rule requires `llmCompress`\");\n\t\t\t\t}\n\t\t\t\tconst cached = cache.get(e.id, rule.toTier);\n\t\t\t\tconst text = cached ?? llmCompress(e, rule.toTier);\n\t\t\t\tif (cached === undefined) cache.set(e.id, rule.toTier, text);\n\t\t\t\treturn { ...base, tier: rule.toTier, payload: text, compressed: true };\n\t\t\t}\n\t\t}\n\t}\n\treturn base;\n}\n\n/**\n * Per-consumer reactive rendering (D-A2). Materialises a\n * `Node<readonly RenderedEntry[]>` over the pool: filter → per-entry rule\n * application under `pressure` → token-budget trim (lowest-importance first).\n *\n * Recomputes the slice per `(entries | pressure)` wave (O(n) — behaviourally\n * identical to the incremental closure-mirror; incremental is a perf\n * follow-up, not a correctness gap).\n *\n * @throws if any rule is `llm-summary` and the pool has no `llmCompress`\n * (D-A3 construction guard).\n */\nexport function renderContextView<T>(\n\tpool: TaggedContextPoolBundle<T>,\n\tview: ContextView<T>,\n): Node<readonly RenderedEntry<T>[]> {\n\tconst usesLlm = view.rules.some((r) => r.action === \"llm-summary\");\n\tif (usesLlm && !pool._opts.llmCompress) {\n\t\tthrow new Error(\n\t\t\t\"renderContextView: view has an 'llm-summary' rule but the pool was created without `llmCompress` (DS-14.6.A D-A3).\",\n\t\t);\n\t}\n\tconst tokenize = view.tokenizer ?? DEFAULT_TOKENIZER;\n\tconst llmCompress = pool._opts.llmCompress;\n\n\treturn node<readonly RenderedEntry<T>[]>(\n\t\t[pool.entries as Node, view.pressure as Node],\n\t\t(data, actions, ctx) => {\n\t\t\tconst entries = (data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0]) as\n\t\t\t\t| readonly ContextEntry<T>[]\n\t\t\t\t| undefined;\n\t\t\tconst pressure = (data[1] != null && data[1].length > 0 ? data[1].at(-1) : ctx.prevData[1]) as\n\t\t\t\t| number\n\t\t\t\t| undefined;\n\t\t\tif (entries === undefined) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst p = pressure ?? 0;\n\t\t\tconst rendered: RenderedEntry<T>[] = [];\n\t\t\tfor (const e of entries) {\n\t\t\t\tif (!view.filter(e)) continue;\n\t\t\t\tconst r = tierCompress(e, view.rules, p, pool._cache, llmCompress);\n\t\t\t\tif (r !== undefined) rendered.push(r);\n\t\t\t}\n\t\t\t// Token-budget trim: drop lowest-importance entries until under budget.\n\t\t\tconst cost = (r: RenderedEntry<T>): number =>\n\t\t\t\ttokenize(typeof r.payload === \"string\" ? r.payload : JSON.stringify(r.payload));\n\t\t\tlet total = 0;\n\t\t\tfor (const r of rendered) total += cost(r);\n\t\t\tif (total > view.budgetTokens) {\n\t\t\t\tconst byImp = entries.reduce<Map<string, number>>(\n\t\t\t\t\t(acc, e) => acc.set(e.id, e.importance),\n\t\t\t\t\tnew Map(),\n\t\t\t\t);\n\t\t\t\trendered.sort((a, b) => (byImp.get(a.id) ?? 0) - (byImp.get(b.id) ?? 0));\n\t\t\t\twhile (total > view.budgetTokens && rendered.length > 0) {\n\t\t\t\t\ttotal -= cost(rendered.shift() as RenderedEntry<T>);\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(rendered);\n\t\t},\n\t\t{ describeKind: \"derived\", meta: aiMeta(\"contextView\", { topic: pool._opts.topic }) },\n\t);\n}\n","/**\n * DS-14.6.A U-C — `heterogeneousDebate()` (Phase 14.5).\n *\n * Stanford-MAD heterogeneity thesis (SESSION-DS-14.6-A L9): participants get\n * **different model adapters + different role prompts**. Closed reasoning\n * loop — no tools / side effects / persistent state beyond the transcript.\n *\n * **Reactive topology (QA M1→b, 2026-05-15).** The round loop is NOT a\n * top-level `async while` driver. It mirrors `refineLoop`'s §7 feedback\n * shape so `describe()` / `explain()` / dry-run see the structure:\n *\n * ```\n * roundTrigger(state) ──▶ roundWork(switchMap→producer, per-round\n * sequential adapter.invoke) ──▶ transcript(scan)\n * └─▶ converged(derived) │\n * ▲ │\n * └──────────── decideEffect (feedback + trigger) ◀─────┘\n * ```\n *\n * The per-round participant calls are an async **source boundary** inside\n * the switchMap producer (spec §5.10 — async belongs in sources), with an\n * abort-on-deactivate `AbortController` (COMPOSITION-GUIDE §45) so a\n * superseded / torn-down round cancels its in-flight LLM calls. `decideEffect`\n * is the sole feedback authority (computes termination inline from the round\n * envelope + closure history, §28); `converged` is a parallel derived purely\n * for external `status` observability. Termination: `fixedRounds |\n * \"until-converge\" | { until: Node<boolean> }` — `until` is a real reactive\n * dep, not a `.cache` poll. `\"until-converge\"` uses a pluggable `converge?`\n * fn, default = no participant changed stance across the last 2 rounds\n * (D-C1, zero extra LLM cost). `output:\"synthesizer-final\"` with no\n * synthesizer-role participant throws at construction (D-C2).\n *\n * @module\n */\n\nimport {\n\tbatch,\n\tnode as createNode,\n\tERROR,\n\tINVALIDATE,\n\ttype Node,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { awaitSettled, firstValueFrom } from \"../../../base/sources/settled.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMResponse,\n\tNodeInput,\n} from \"../../../utils/ai/adapters/core/types.js\";\n\nexport interface Turn {\n\treadonly round: number;\n\treadonly role: string;\n\treadonly content: string;\n}\n\nexport interface DebateParticipant {\n\treadonly adapter: LLMAdapter;\n\t/** e.g. \"advocate\" | \"skeptic\" | \"synthesizer\" | custom. */\n\treadonly role: string;\n\treadonly systemPrompt: string;\n}\n\nexport type DebateTermination = number | \"until-converge\" | { readonly until: Node<boolean> };\n\nexport type DebateOutput =\n\t| \"transcript\"\n\t| \"synthesizer-final\"\n\t| { readonly project: (transcript: readonly Turn[]) => unknown };\n\nexport type DebateStatus = \"running\" | \"converged\" | \"max-rounds\" | \"error\";\n\nexport interface HeterogeneousDebateOptions {\n\treadonly question: string;\n\treadonly participants: readonly DebateParticipant[];\n\t/** Default `3`. */\n\treadonly rounds?: DebateTermination;\n\t/** Default `\"transcript\"`. */\n\treadonly output?: DebateOutput;\n\t/**\n\t * D-C1 — `\"until-converge\"` detector. Default: no participant's latest\n\t * content changed vs the previous round (structural compare, no LLM).\n\t */\n\treadonly converge?: (transcript: readonly Turn[]) => boolean;\n\treadonly name?: string;\n\t/** Hard ceiling for `\"until-converge\"` / `{ until }` (default 12). */\n\treadonly maxRounds?: number;\n}\n\nexport interface HeterogeneousDebateBundle {\n\treadonly transcript: Node<readonly Turn[]>;\n\treadonly result: Node<unknown>;\n\treadonly status: Node<DebateStatus>;\n\treadonly graph: DebateGraph;\n\t/**\n\t * Thin `awaitSettled` bridge (mirrors `agentLoop.run()`): kicks the\n\t * reactive round loop and resolves the final `result`. Throws\n\t * `RangeError` if a prior `run()` is still pending (QA P4 re-entrancy).\n\t */\n\trun(): Promise<unknown>;\n}\n\nexport class DebateGraph extends Graph {}\n\nconst SYNTH_RE = /synth/i;\n\n/** Default converge: every role's latest two rounds are identical. */\nfunction defaultConverge(transcript: readonly Turn[]): boolean {\n\tconst rounds = transcript.reduce((m, t) => Math.max(m, t.round), 0);\n\tif (rounds < 2) return false;\n\tconst at = (r: number): Map<string, string> => {\n\t\tconst m = new Map<string, string>();\n\t\tfor (const t of transcript) if (t.round === r) m.set(t.role, t.content);\n\t\treturn m;\n\t};\n\tconst prev = at(rounds - 1);\n\tconst cur = at(rounds);\n\tif (prev.size === 0 || prev.size !== cur.size) return false;\n\tfor (const [role, content] of cur) if (prev.get(role) !== content) return false;\n\treturn true;\n}\n\n/** Process-wide sequence for collision-safe default mount names (QA P6). */\nlet _debateSeq = 0;\n\ninterface RoundEnvelope {\n\treadonly round: number;\n\treadonly turns: readonly Turn[];\n}\n\nexport function heterogeneousDebate(\n\tparent: Graph,\n\topts: HeterogeneousDebateOptions,\n): HeterogeneousDebateBundle {\n\tconst output = opts.output ?? \"transcript\";\n\tif (output === \"synthesizer-final\" && !opts.participants.some((p) => SYNTH_RE.test(p.role))) {\n\t\tthrow new Error(\n\t\t\t\"heterogeneousDebate: output 'synthesizer-final' requires a participant whose role matches /synth/i (DS-14.6.A D-C2).\",\n\t\t);\n\t}\n\tif (opts.participants.length === 0) {\n\t\tthrow new Error(\"heterogeneousDebate: at least one participant is required\");\n\t}\n\n\tconst name = opts.name ?? `debate-${++_debateSeq}`;\n\tconst graph = new DebateGraph(name);\n\tparent.mount(name, graph);\n\n\tconst term = opts.rounds ?? 3;\n\tconst maxRounds = opts.maxRounds ?? 12;\n\tconst converge = opts.converge ?? defaultConverge;\n\t// `{ until }` becomes a real reactive dep (QA P10 — no `.cache` poll);\n\t// non-until modes use a constant-false node for stable dep arity.\n\tconst untilNode: Node<boolean> =\n\t\ttypeof term === \"object\" ? term.until : createNode<boolean>([], { initial: false });\n\n\t// --- state / output nodes -------------------------------------------------\n\tconst roundTrigger = createNode<number>([], { name: `${name}.round`, initial: 0 });\n\tconst statusState = createNode<DebateStatus>([], { name: `${name}.status`, initial: \"running\" });\n\tconst resultState = createNode<unknown>([], { name: `${name}.result`, initial: undefined });\n\n\t// Closure history (§28 factory-time mirror) — the feedback authority's\n\t// view of the transcript without a declared dep cycle.\n\tlet history: Turn[] = [];\n\n\tfunction buildMessages(p: DebateParticipant): ChatMessage[] {\n\t\tconst msgs: ChatMessage[] = [\n\t\t\t{ role: \"system\", content: p.systemPrompt },\n\t\t\t{ role: \"user\", content: opts.question },\n\t\t];\n\t\tfor (const t of history) {\n\t\t\tmsgs.push({ role: \"assistant\", content: `[${t.role} r${t.round}] ${t.content}` });\n\t\t}\n\t\treturn msgs;\n\t}\n\n\t// --- GENERATE: roundTrigger → per-round sequential participant calls -------\n\t// switchMap producer = async source boundary (spec §5.10). The producer's\n\t// deactivate cleanup aborts in-flight calls (COMPOSITION-GUIDE §45 + the\n\t// switchMap supersede path), so a torn-down round burns no extra tokens.\n\tconst roundWork = switchMap<number, RoundEnvelope>(\n\t\troundTrigger,\n\t\t(r) =>\n\t\t\tcreateNode<RoundEnvelope>(\n\t\t\t\t[],\n\t\t\t\t(_data, actions) => {\n\t\t\t\t\tif (r < 1) {\n\t\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tconst ac = new AbortController();\n\t\t\t\t\tlet cancelled = false;\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\tconst turns: Turn[] = [];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tfor (const p of opts.participants) {\n\t\t\t\t\t\t\t\tconst res = await firstValueFrom(\n\t\t\t\t\t\t\t\t\tfromAny<LLMResponse>(\n\t\t\t\t\t\t\t\t\t\tp.adapter.invoke(buildMessages(p), {\n\t\t\t\t\t\t\t\t\t\t\tsignal: ac.signal,\n\t\t\t\t\t\t\t\t\t\t}) as NodeInput<LLMResponse>,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\t\t\t\tturns.push({ round: r, role: p.role, content: res.content });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!cancelled) actions.emit({ round: r, turns });\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (!cancelled) actions.down([[ERROR, err]]);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{ describeKind: \"producer\", name: `${name}.round-work` },\n\t\t\t),\n\t\t{ name: `${name}.rounds` },\n\t);\n\tgraph.add(roundWork, { name: \"rounds\" });\n\n\t// --- transcript: scan-accumulate (external observability) -----------------\n\tconst transcript = createNode<readonly Turn[]>(\n\t\t[roundWork],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst env = (\n\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0]\n\t\t\t) as RoundEnvelope | undefined;\n\t\t\tif (env === undefined) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit(history.slice());\n\t\t},\n\t\t{ name: `${name}.transcript`, describeKind: \"derived\" },\n\t);\n\tgraph.add(transcript, { name: \"transcript\" });\n\n\t// --- converged: parallel derived for external `status` (NOT authority) ----\n\tconst converged = createNode<{ done: boolean; reason: DebateStatus }>(\n\t\t[transcript as Node, untilNode as Node],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst tr = (\n\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0]\n\t\t\t) as readonly Turn[] | undefined;\n\t\t\tconst untilV = (\n\t\t\t\tbatchData[1] != null && batchData[1].length > 0 ? batchData[1].at(-1) : ctx.prevData[1]\n\t\t\t) as boolean | undefined;\n\t\t\tconst rounds = (tr ?? []).reduce((m, t) => Math.max(m, t.round), 0);\n\t\t\tif (typeof term === \"number\") {\n\t\t\t\tactions.emit({ done: rounds >= term, reason: \"max-rounds\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (term === \"until-converge\") {\n\t\t\t\tif (converge(tr ?? [])) actions.emit({ done: true, reason: \"converged\" });\n\t\t\t\telse actions.emit({ done: rounds >= maxRounds, reason: \"max-rounds\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit({ done: untilV === true || rounds >= maxRounds, reason: \"max-rounds\" });\n\t\t},\n\t\t{ name: `${name}.converged`, describeKind: \"derived\" },\n\t);\n\tgraph.add(converged, { name: \"converged\" });\n\n\t// --- decideEffect: SOLE feedback authority (§7 single-trigger) ------------\n\t// Computes termination INLINE (round envelope + closure history + the\n\t// reactive `untilNode` dep) — does NOT read `converged.cache` (avoids the\n\t// same-wave drain-order hazard refineLoop documents). `converged` above is\n\t// purely for external observation.\n\tconst decideEffect = createNode(\n\t\t[roundWork as Node, untilNode as Node],\n\t\t(batchData, _actions, ctx) => {\n\t\t\tconst env = (\n\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : undefined\n\t\t\t) as RoundEnvelope | undefined;\n\t\t\tconst untilV = (\n\t\t\t\tbatchData[1] != null && batchData[1].length > 0 ? batchData[1].at(-1) : ctx.prevData[1]\n\t\t\t) as boolean | undefined;\n\t\t\tif (env === undefined) {\n\t\t\t\t// `until` flipped with no new round — finalize if it went true.\n\t\t\t\tif (typeof term === \"object\" && untilV === true && statusState.cache === \"running\") {\n\t\t\t\t\tfinalize(\"max-rounds\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// New round settled — fold into the closure history first.\n\t\t\thistory = [...history, ...env.turns];\n\t\t\tconst r = env.round;\n\t\t\tlet done = false;\n\t\t\tlet reason: DebateStatus = \"max-rounds\";\n\t\t\tif (typeof term === \"number\") done = r >= term;\n\t\t\telse if (term === \"until-converge\") {\n\t\t\t\tif (converge(history)) {\n\t\t\t\t\tdone = true;\n\t\t\t\t\treason = \"converged\";\n\t\t\t\t} else done = r >= maxRounds;\n\t\t\t} else done = untilV === true || r >= maxRounds;\n\n\t\t\tif (done) finalize(reason);\n\t\t\telse roundTrigger.emit(r + 1); // §7 feedback edge\n\t\t},\n\t\t{ name: `${name}.decide`, describeKind: \"effect\", errorWhenDepsError: false },\n\t);\n\tgraph.add(decideEffect, { name: \"decide\" });\n\n\tfunction finalize(reason: DebateStatus): void {\n\t\tlet out: unknown;\n\t\tif (output === \"transcript\") out = history.slice();\n\t\telse if (output === \"synthesizer-final\") {\n\t\t\tconst synth = [...history].reverse().find((t) => SYNTH_RE.test(t.role));\n\t\t\tout = synth?.content ?? null;\n\t\t} else out = output.project(history.slice());\n\t\tbatch(() => {\n\t\t\tstatusState.emit(reason);\n\t\t\tresultState.emit(out);\n\t\t});\n\t}\n\n\t// Error watcher — adapter throw surfaces as ERROR on roundWork.\n\tconst errorWatcher = createNode(\n\t\t[roundWork as Node],\n\t\t(_b, _a, ec) => {\n\t\t\tconst t = ec.terminalDeps[0];\n\t\t\tif (t !== undefined && t !== true && statusState.cache === \"running\") {\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusState.emit(\"error\");\n\t\t\t\t\tresultState.emit(new Error(\"heterogeneousDebate: a participant adapter errored\"));\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t{ name: `${name}.error-watcher`, describeKind: \"effect\", errorWhenDepsError: false },\n\t);\n\tgraph.add(errorWatcher, { name: \"error-watcher\" });\n\n\t// Keepalive: activate the feedback + observability nodes so the loop runs\n\t// and `.cache` stays warm without an external subscriber. These live for\n\t// the graph's lifetime (torn down on parent-graph destroy).\n\tdecideEffect.subscribe(() => undefined);\n\terrorWatcher.subscribe(() => undefined);\n\ttranscript.subscribe(() => undefined);\n\tconverged.subscribe(() => undefined);\n\n\tlet running = false;\n\n\treturn {\n\t\ttranscript,\n\t\tresult: resultState,\n\t\tstatus: statusState,\n\t\tgraph,\n\t\tasync run(): Promise<unknown> {\n\t\t\tif (running) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`heterogeneousDebate \"${name}\": run() called while a previous run() is still pending`,\n\t\t\t\t);\n\t\t\t}\n\t\t\trunning = true;\n\t\t\ttry {\n\t\t\t\thistory = [];\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusState.emit(\"running\");\n\t\t\t\t\tresultState.down([[INVALIDATE]]);\n\t\t\t\t});\n\t\t\t\t// Subscribe BEFORE the kick (sync adapters would otherwise drain\n\t\t\t\t// the terminal before awaitSettled subscribes).\n\t\t\t\tconst settled = awaitSettled(resultState, { skipCurrent: true });\n\t\t\t\troundTrigger.emit(1); // kick\n\t\t\t\treturn await settled;\n\t\t\t} finally {\n\t\t\t\trunning = false;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBO,SAAS,aAAgB,MAAkC;AACjE,SAAO,EAAE,cAAc,WAAW,GAAG,KAAK;AAC3C;AAMO,SAAS,OAAO,GAAqB;AAC3C,SAAO,EAAE,CAAC;AACX;AAEO,SAAS,cAAc,KAAqB;AAClD,MAAI,OAAO,QAAQ,YAAY,CAAC,OAAO,SAAS,GAAG,GAAG;AACrD,UAAM,IAAI,UAAU,8CAA8C;AAAA,EACnE;AACA,SAAO,MAAM,IAAI,IAAI;AACtB;AAEO,SAAS,OAAO,GAAuB;AAC7C,SACC,KAAK,QACL,OAAO,MAAM,YACb,WAAW,KACX,OAAQ,EAAW,cAAc;AAEnC;AA9CA,IAgBAA;AAhBA;AAAA;AAAA;AAgBA,IAAAA,eAAmC;AAAA;AAAA;;;AChBnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BA,SAAS,iBAAiB,OAAuB;AAChD,SAAO,QAAQ,IAAI,IAAI;AACxB;AAEA,SAAS,YAAY,OAAe,QAA4B;AAC/D,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,OAAQ,QAAO,KAAK,OAAO,IAAI;AAC9C,SAAO,QAAQ,IAAI,KAAK,OAAO,KAAK,QAAQ;AAC7C;AAEA,SAAS,cAAc,KAAa,KAAqB;AACxD,SAAO,MAAM,KAAK,OAAO,KAAK,MAAM;AACrC;AAiBO,SAAS,SAAS,SAAkC;AAC1D,QAAM,OAAO,iBAAiB,OAAO;AACrC,SAAO,MAAM;AACd;AAmBO,SAAS,OAAO,QAAgB,QAAkC;AACxE,QAAM,WAAW,iBAAiB,MAAM;AACxC,QAAM,WAAW,WAAW,SAAY,WAAW,iBAAiB,MAAM;AAC1E,SAAO,CAAC,YAAoB,WAAW,WAAW,KAAK,IAAI,GAAG,OAAO;AACtE;AA+BO,SAAS,YAAY,SAAsD;AACjF,QAAM,SAAS,iBAAiB,SAAS,UAAU,MAAM,SAAS;AAClE,QAAM,SAAS,SAAS,WAAW,UAAa,QAAQ,SAAS,IAAI,IAAK,SAAS,UAAU;AAC7F,QAAM,aAAa,iBAAiB,SAAS,cAAc,KAAK,UAAU;AAC1E,QAAM,SAAS,SAAS,UAAU;AAElC,SAAO,CAAC,YAAoB;AAC3B,QAAI;AACJ,QAAI,WAAW,GAAG;AACjB,cAAQ;AAAA,IACT,WAAW,WAAW,GAAG;AACxB,cAAQ;AAAA,IACT,OAAO;AACN,YAAM,WAAW,aAAa;AAC9B,UAAI,SAAS;AACb,eAAS,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,OAAO,GAAG,KAAK;AAC9C,YAAI,UAAU,UAAU;AACvB,mBAAS;AACT;AAAA,QACD;AACA,kBAAU;AAAA,MACX;AACA,cAAQ,SAAS;AACjB,UAAI,QAAQ,WAAY,SAAQ;AAAA,IACjC;AACA,WAAO,YAAY,OAAO,MAAM;AAAA,EACjC;AACD;AAmBO,SAAS,UAAU,SAAS,MAAM,WAAW,aAAa,KAAK,YAA6B;AAClG,QAAM,WAAW,iBAAiB,MAAM;AACxC,QAAM,UAAU,iBAAiB,UAAU;AAE3C,WAAS,QAAQ,SAAyB;AACzC,QAAI,WAAW,EAAG,QAAO;AACzB,QAAI,OAAO;AACX,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AACjC,YAAM,OAAO,OAAO;AACpB,aAAO;AACP,YAAM;AAAA,IACP;AACA,WAAO;AAAA,EACR;AAEA,SAAO,CAAC,YAAoB;AAC3B,UAAM,MAAM,QAAQ,OAAO,IAAI;AAC/B,WAAO,OAAO,UAAU,MAAM;AAAA,EAC/B;AACD;AAwBO,SAAS,mBACf,SAAS,MAAM,WACf,QAAQ,KAAK,YACK;AAClB,SAAO,CAAC,UAAU,QAAQ,gBAAgB;AACzC,UAAM,OAAO,eAAe;AAC5B,UAAM,UAAU,KAAK,IAAI,OAAO,OAAO,CAAC;AACxC,WAAO,cAAc,QAAQ,OAAO;AAAA,EACrC;AACD;AAmBO,SAAS,gBAAgB,UAA2B,aAAsC;AAChG,SAAO,CAAC,SAAS,OAAO,gBAAgB;AACvC,QAAI,WAAW,YAAa,QAAO;AACnC,WAAO,SAAS,SAAS,OAAO,WAAW;AAAA,EAC5C;AACD;AAmBO,SAAS,qBAAqB,MAAsC;AAC1E,MAAI,SAAS,WAAY,QAAO,SAAS,IAAI,UAAU;AACvD,MAAI,SAAS,SAAU,QAAO,OAAO,IAAI,UAAU;AACnD,MAAI,SAAS,cAAe,QAAO,YAAY;AAC/C,MAAI,SAAS,YAAa,QAAO,UAAU;AAC3C,MAAI,SAAS,qBAAsB,QAAO,mBAAmB;AAC7D,QAAM,IAAI;AAAA,IACT,4BAA4B,OAAO,IAAI,CAAC;AAAA,EACzC;AACD;AAvQA,IAOa,WACA;AARb;AAAA;AAAA;AAOO,IAAM,YAAY;AAClB,IAAM,aAAa;AAAA;AAAA;;;ACR1B;AAAA;AAAA;AAAA;AAAA;AA8IO,SAAS,YACf,QACA,MACA,WACmB;AACnB,QAAM,aAAa,OAAO,IAAI;AAO9B,MAAI,aAAoC;AACxC,MAAI,CAAC,YAAY;AAChB,UAAM,aAAa;AACnB,QACC,WAAW,OAAO,UAClB,OAAO,WAAW,OAAO,YACzB,CAAC,OAAO,SAAS,WAAW,EAAE,KAC9B,WAAW,MAAM,GAChB;AACD,YAAM,IAAI,WAAW,uDAAuD;AAAA,IAC7E;AACA,iBAAa;AAAA,MACZ,IAAI,WAAW;AAAA,MACf,GAAI,WAAW,QAAQ,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,IAC5D;AAAA,EACD,OAAO;AACN,UAAM,SAAU,KAAuC;AAGvD,QAAI,WAAW,QAAW;AACzB,UACC,OAAO,OAAO,UACd,OAAO,OAAO,OAAO,YACrB,CAAC,OAAO,SAAS,OAAO,EAAE,KAC1B,OAAO,MAAM,GACZ;AACD,cAAM,IAAI;AAAA,UACT;AAAA,QACD;AAAA,MACD;AACA,mBAAa;AAAA,QACZ,IAAI,OAAO;AAAA,QACX,GAAI,OAAO,QAAQ,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,MACpD;AAAA,IACD;AAAA,EACD;AAEA,QAAM,aAAa,WAAW;AAC9B,QAAM,cAAuC,aAC1C,EAAE,IAAI,gCAAgC,IACtC,EAAE,IAAI,WAAY,GAAG;AAIxB,QAAM,mBAAe,mBAAmB,CAAC,GAAG;AAAA,IAC3C,MAAM;AAAA,IACN,cAAc;AAAA,IACd,SAAS,EAAE,QAAQ,UAAU;AAAA,IAC7B,QAAQ,CAAC,GAAG,MACX,MAAM,KACL,KAAK,QACL,KAAK,QACL,OAAO,MAAM,YACb,OAAO,MAAM,YACZ,EAAyB,WAAY,EAAyB,UAC/D,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;AAAA,EACzC,CAAC;AAED,QAAM,UAAM;AAAA,IACX,CAAC,OAAO,MAAM;AACb,UAAI,UAAU;AACd,UAAI,iBAAiB;AACrB,YAAM,QAAQ,IAAI,6BAAgB;AAClC,UAAI,YAAiC;AACrC,UAAI,WAAgC;AAEpC,eAAS,UAAU,MAA0B;AAC5C,qBAAa,KAAK,CAAC,CAAC,kBAAK,GAAG,CAAC,mBAAM,IAAI,CAAC,CAAC;AAAA,MAC1C;AAEA,eAAS,aAAmB;AAC3B,YAAI,QAAS;AAQb,YACC,cAAc,QACd,OAAO,WAAW,OAAO,YACzB,CAAC,OAAO,SAAS,WAAW,EAAE,KAC9B,WAAW,MAAM,GAChB;AACD;AAAA,QACD;AACA,cAAM,KAAK,WAAW;AACtB,yBAAiB;AACjB,cAAM,gBAAY,0BAAY;AAC9B,cAAM,UAAU,KAAK;AACrB,kBAAU;AAAA,UACT,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,aAAa;AAAA,QACd,CAAC;AACD,cAAM,MAAM,SAAS,MAAM;AAC1B,cAAI,QAAS;AACb,oBAAU;AACV,qBAAW;AACX,oBAAU;AAAA,YACT,QAAQ;AAAA,YACR,gBAAY,0BAAY;AAAA,YACxB,aAAa;AAAA,UACd,CAAC;AACD,YAAE,KAAK,CAAC,CAAC,oBAAO,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;AAAA,QACvC,CAAC;AAAA,MACF;AAEA,eAAS,eAAqB;AAC7B,YAAI,YAAY,QAAQ,QAAS;AACjC,mBAAW,OAAO,UAAU,CAAC,SAAS;AACrC,qBAAW,KAAK,MAAM;AACrB,gBAAI,QAAS;AACb,kBAAM,IAAI,EAAE,CAAC;AACb,gBAAI,MAAM,mBAAO,GAAE,KAAK,CAAC,CAAC,kBAAK,CAAC,CAAC;AAAA,qBACxB,MAAM,mBAAM;AACpB,yBAAW;AACX,gBAAE,KAAK,EAAE,CAAC,CAAM;AAAA,YACjB,WAAW,MAAM,sBAAU,GAAE,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AAAA,qBACrC,MAAM,uBAAU;AACxB,oBAAM,OAAO;AACb,wBAAU;AACV,wBAAU;AAAA,gBACT,QAAQ;AAAA,gBACR,kBAAc,0BAAY;AAAA,cAC3B,CAAC;AACD,gBAAE,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AACnB;AAAA,YACD,WAAW,MAAM,oBAAO;AACvB,oBAAM,OAAO;AACb,wBAAU;AACV,wBAAU;AAAA,gBACT,QAAQ;AAAA,gBACR,gBAAY,0BAAY;AAAA,gBACxB,aAAa;AAAA,cACd,CAAC;AACD,gBAAE,KAAK,CAAC,CAAC,CAAC;AACV;AAAA,YACD,WAAW,MAAM,uBAAU;AAC1B,oBAAM,OAAO;AACb,wBAAU;AACV,gBAAE,KAAK,CAAC,CAAC,CAAC;AACV;AAAA,YACD,MAAO,GAAE,KAAK,CAAC,CAAC,CAAC;AAAA,UAClB;AAAA,QACD,CAAC;AAED,YAAI,cAAc,QAAQ,WAAW,KAAK,GAAG;AAC5C,qBAAW;AAAA,QACZ;AAAA,MACD;AAEA,UAAI,YAAY;AACf,cAAM,WAAW;AACjB,oBAAY,SAAS,UAAU,CAAC,SAAS;AACxC,qBAAW,KAAK,MAAM;AACrB,gBAAI,EAAE,CAAC,MAAM,kBAAM;AACnB,kBAAM,OAAO,EAAE,CAAC;AAChB,gBAAI,QAAQ,QAAQ,OAAO,SAAS,SAAU;AAE9C,kBAAM,OAAO,OAAO,KAAK,IAAI;AAC7B,gBAAI,KAAK,WAAW,EAAG;AAQvB,gBAAI,QAAQ,MAAM;AACjB,kBAAI,OAAO,KAAK,OAAO,YAAY,CAAC,OAAO,SAAS,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG;AAC7E,oBAAI,cAAc,MAAM;AAIvB,4BAAU;AACV,oBAAE,KAAK;AAAA,oBACN;AAAA,sBACC;AAAA,sBACA,IAAI;AAAA,wBACH;AAAA,sBACD;AAAA,oBACD;AAAA,kBACD,CAAC;AACD;AAAA,gBACD;AAGA;AAAA,cACD;AAAA,YACD;AACA,kBAAM,UAAU,cAAc;AAC9B,yBAAa;AAAA,cACZ,GAAI,cAAc,EAAE,IAAI,EAAE;AAAA,cAC1B,GAAG;AAAA,YACJ;AAEA,gBAAI,WAAW,WAAW,KAAK,GAAG;AACjC,2BAAa;AAAA,YACd;AAAA,UACD;AAAA,QACD,CAAC;AAAA,MACF;AAIA,UAAI,cAAc,MAAM;AACvB,qBAAa;AAAA,MACd;AAEA,aAAO;AAAA,QACN,gBAAgB,MAAM;AACrB,oBAAU;AACV,gBAAM,OAAO;AACb,cAAI,SAAU,UAAS;AACvB,cAAI,UAAW,WAAU;AAAA,QAC1B;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,GAAG,aAAa;AAAA,MAChB,SAAS,OAAO;AAAA,MAChB,MAAM,EAAE,GAAI,cAAc,CAAC,GAAI,OAAG,yBAAW,eAAe,WAAW,EAAE;AAAA,IAC1E;AAAA,EACD;AAEA,SAAO,EAAE,MAAM,KAAK,aAAa;AAClC;AA9XA,IAiBAC,cAqBa;AAtCb;AAAA;AAAA;AAiBA,IAAAA,eAYO;AACP;AACA;AAOO,IAAM,eAAN,cAA2B,MAAM;AAAA,MAC9B,OAAO;AAAA,MAChB,YAAY,IAAY;AACvB,cAAM,mBAAmB,KAAK,SAAS,IAAI;AAAA,MAC5C;AAAA,IACD;AAAA;AAAA;;;AC3CA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqBA,IAAAC,gBAAmE;AACnE,IAAAC,gBAA0B;AAC1B,IAAAC,gBAAyC;;;ACdzC,kBAQO;AACP,mBAAwC;;;ACIjC,SAAS,WACf,QACA,MACA,OAC0B;AAC1B,SAAO;AAAA,IACN,CAAC,MAAM,GAAG;AAAA,IACV,CAAC,GAAG,MAAM,OAAO,GAAG;AAAA,IACpB,GAAI,SAAS,CAAC;AAAA,EACf;AACD;;;ADLO,SAAS,OAAO,MAAc,OAA0D;AAC9F,SAAO,WAAW,MAAM,MAAM,KAAK;AACpC;AAMO,SAAS,WAAW,GAAgC;AAC1D,SACC,OAAO,MAAM,YACb,MAAM,QACN,eAAe,KACf,OAAQ,EAAoB,cAAc,cAC1C,WAAW;AAEb;AAuEO,SAAS,YAAY,MAAsB;AACjD,QAAM,QAAQ,KAAK,MAAM,0CAA0C;AACnE,SAAO,QAAQ,MAAM,CAAC,IAAK;AAC5B;;;AEzEA,IAAAC,eAAuD;AACvD,IAAAC,gBAA+D;AAC/D,IAAAC,gBAAyC;;;AC5BzC,IAAAC,eASO;AACP,IAAAC,gBAIO;AACP,mBAAsB;AAsDf,IAAM,0BAAiC,qBAAO,CAAC,OAAO,SAAS;AACrE,QAAM,SAAS;AACf,QAAM,QAAQ;AACd,OAAK,OAAO;AACb,CAAC;AAwBM,SAAS,eACf,MACuB;AACvB,QAAM,UAAM,2BAAe,CAAC,GAAG;AAAA,IAC9B,MAAM,KAAK;AAAA,IACX,SAAS,KAAK,iBAAiB;AAAA,IAC/B,OAAO,KAAK,SAAS;AAAA,IACrB,GAAI,KAAK,cAAc,OAAO,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,EAClE,CAAC;AAGD,MAAI,WAAW;AACf,MAAI,KAAK,OAAO;AACf,SAAK,MAAM,IAAI,IAAI,SAAS,EAAE,MAAM,KAAK,KAAK,CAAC;AAAA,EAChD;AACA,SAAO;AACR;AAmEA,SAAS,WAAc,OAAa;AACnC,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAClF,aAAW,KAAK,OAAO,KAAK,KAAgC,GAAG;AAC9D,eAAY,MAAkC,CAAC,CAAC;AAAA,EACjD;AACA,SAAO,OAAO,OAAO,KAAK;AAC3B;AAaO,SAAS,OACf,KACA,MAC8B;AAC9B,QAAM,EAAE,IAAI,KAAK,IAAI,OAAO,QAAQ,aAAa,EAAE,IAAI,KAAK,MAAM,OAAU,IAAI;AAChF,QAAM,SAAS,KAAK,UAAU;AAE9B,MAAI,KAAK,UAAU,UAAU;AAC5B,WAAO,SAAS,WAAW,MAAsB;AAChD,YAAM,SAAS,SAAU,KAAK,IAAI,UAAU,IAAyB;AACrE,YAAM,WAAO,0BAAY;AACzB,YAAM,MAAM,KAAK,MAAM,WAAW,KAAK,GAAG,IAAI;AAC9C,UAAI;AACH,cAAM,SAAS,GAAG,GAAG,MAAM;AAC3B,YAAI,KAAK,OAAO,KAAK,iBAAiB;AACrC;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL;AAAA,YACA;AAAA,YACA,EAAE,MAAM,IAAI;AAAA,YACZ,KAAK;AAAA,UACN;AAAA,QACD;AACA,eAAO;AAAA,MACR,SAAS,KAAK;AACb,YAAI,KAAK,OAAO,KAAK,iBAAiB;AACrC,gBAAM,YAAY,eAAe,QAAQ,IAAI,OAAO,OAAO;AAC3D;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL;AAAA,YACA;AAAA,YACA,EAAE,MAAM,KAAK,UAAU;AAAA,YACvB,KAAK;AAAA,UACN;AAAA,QACD;AACA,cAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AAGA,SAAO,SAAS,WAAW,MAAsB;AAChD,UAAM,SAAS,SAAU,KAAK,IAAI,UAAU,IAAyB;AACrE,UAAM,WAAO,0BAAY;AACzB,QAAI;AACJ,QAAI;AACJ,QAAI,aAAa;AACjB,QAAI;AACJ,QAAI;AACH,8BAAM,MAAM;AACX,YAAI,KAAK,IAAK,OAAM,WAAW,KAAK,GAAG;AACvC,YAAI;AACH,mBAAS,GAAG,GAAG,MAAM;AACrB,cAAI,KAAK,OAAO,KAAK,iBAAiB;AACrC;AAAA,cACC,KAAK;AAAA,cACL,KAAK;AAAA,cACL;AAAA,cACA;AAAA,cACA,EAAE,MAAM,IAAI;AAAA,cACZ,KAAK;AAAA,YACN;AAAA,UACD;AAAA,QACD,SAAS,KAAK;AACb,qBAAW;AACX,uBAAa;AACb,gBAAM;AAAA,QACP;AAAA,MACD,CAAC;AAAA,IACF,SAAS,UAAU;AAIlB,UAAI,cAAc,MAAM;AACvB,YAAI;AACH,eAAK,GAAG,MAAM;AAAA,QACf,SAAS,SAAS;AACjB,kBAAQ;AAAA,YACP,mEACC,oBAAoB,QAAQ,SAAS,OAAO,OAAO,QACpD;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD;AACA,UAAI,cAAc,KAAK,OAAO,KAAK,iBAAiB;AACnD,cAAM,YAAY,oBAAoB,QAAQ,SAAS,OAAO,OAAO;AACrE;AAAA,UACC,KAAK;AAAA,UACL,KAAK;AAAA,UACL;AAAA,UACA;AAAA,UACA,EAAE,MAAM,KAAK,UAAU;AAAA,UACvB,KAAK;AAAA,QACN;AAAA,MACD;AACA,YAAM,aAAa,WAAW;AAAA,IAC/B;AACA,WAAO;AAAA,EACR;AACD;AA2BA,IAAM,oBAAoB,oBAAI,QAAsB;AAC7C,SAAS,WAAW,KAA2B;AACrD,QAAM,MAAM,IAAI;AAChB,QAAM,QAAQ,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG;AAC5D,MAAI,CAAC,SAAS,QAAQ,UAAa,CAAC,kBAAkB,IAAI,GAAG,GAAG;AAC/D,sBAAkB,IAAI,GAAG;AACzB,YAAQ;AAAA,MACP,sDAAsD,OAAO,GAAG,CAAC;AAAA,IAIlE;AAAA,EACD;AACA,QAAM,MAAM,QAAQ,MAAM;AAC1B,QAAM,OAAO,MAAM;AACnB,MAAI,KAAK,CAAC,CAAC,kBAAK,GAAG,CAAC,mBAAM,IAAI,CAAC,CAAC;AAChC,SAAO;AACR;AAUO,SAAS,YAMf,OACA,SACA,MACA,OACA,MACA,gBACO;AACP,QAAM,SAAS,QAAQ,MAAM,OAAO,IAAI;AACxC,MAAI,WAAW,OAAW;AAC1B,QAAM,UAAU,kBAAkB,OAAQ,EAAE,GAAG,QAAQ,eAAe,IAAU;AAChF,QAAM,OAAO,OAAO;AACrB;AAWO,SAAS,eAAe,OAAc,MAAc,UAAU,GAAiB;AACrF,QAAM,aAAS,mBAAa,CAAC,GAAG,EAAE,SAAS,MAAM,cAAc,QAAQ,CAAC;AACxE,QAAM,IAAI,QAAQ,EAAE,KAAK,CAAC;AAC1B,SAAO;AACR;;;ADjWA,SAAS,sBAAsB,OAAe,OAAuB;AACpE,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACrE,UAAM,IAAI,MAAM,GAAG,KAAK,iCAAiC;AAAA,EAC1D;AACA,SAAO;AACR;AAEA,SAAS,cAAc,MAAc,OAA0D;AAC9F,SAAO,WAAW,aAAa,MAAM,KAAK;AAC3C;AAQA,IAAM,+BAA+B;AAE9B,IAAM,aAAN,cAA4B,oBAAM;AAAA,EACvB;AAAA,EACA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA;AAAA,EAET,YAAY,MAAc,OAAqB,CAAC,GAAG;AAClD,UAAM,MAAM,KAAK,KAAK;AACtB,SAAK,WAAO,2BAAe,CAAC,GAAG;AAAA,MAC9B,MAAM;AAAA,MACN,SAAS,KAAK,iBAAiB;AAAA,IAChC,CAAC;AACD,SAAK,SAAS,KAAK,KAAK;AACxB,SAAK,IAAI,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAcxC,SAAK,SAAS,KAAK;AAAA,MAClB;AAAA,MACA,CAAC,QAAQ;AAAA,MACT,CAAC,WAAW,QAAQ;AACnB,cAAM,OAAO,UAAU;AAAA,UAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,UAAU,KAAK,CAAC;AACtB,eAAO,QAAQ,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,QAAQ,SAAS,CAAC,CAAM;AAAA,MACrE;AAAA,MACA,EAAE,MAAM,cAAc,cAAc,EAAE;AAAA,IACvC;AACA,SAAK,gBAAY,yBAAU,KAAK,MAAM,CAAC;AAevC,SAAK,YAAY,MAAM;AACtB,WAAK,OAAO,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AAAA,IAC9B,CAAC;AAKD,SAAK,YAAY,MAAM,KAAK,KAAK,gBAAgB,CAAC;AAQlD,SAAK,eAAe;AAAA,MACnB,CAAC,UAAgB;AAChB,aAAK,KAAK,OAAO,KAAK;AAAA,MACvB;AAAA,MACA,EAAE,OAAO,UAAU,QAAQ,MAAM;AAAA,IAClC;AAAA,EACD;AAAA,EAEA,QAAQ,OAAgB;AAIvB,QAAI,UAAU,QAAW;AACxB,YAAM,IAAI;AAAA,QACT,eAAe,KAAK,IAAI;AAAA,MACzB;AAAA,IACD;AACA,SAAK,aAAa,KAAK;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,mBACC,OACa;AACb,WAAO,KAAK,KAAK,cAAc,KAAK;AAAA,EACrC;AAAA,EAEA,WAAyB;AACxB,WAAO,KAAK,OAAO;AAAA,EACpB;AAAA;AAAA,EAGA,IAAI,aAAa;AAChB,WAAO,KAAK;AAAA,EACb;AACD;AA8BO,IAAM,oBAAN,cAAmC,oBAAM;AAAA,EACtC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA;AAAA,EAED,YAAY;AAAA,EACH;AAAA,EACA;AAAA,EAEjB,YAAY,MAAc,YAA2B,OAA4B,CAAC,GAAG;AACpF,UAAM,MAAM,KAAK,KAAK;AACtB,SAAK,QAAQ;AAGb,QAAI;AACJ,QAAI,KAAK,SAAS,QAAW;AAC5B,UAAI,KAAK,SAAS,YAAY;AAC7B,wBAAgB;AAAA,MACjB,WAAW,KAAK,SAAS,OAAO;AAE/B,wBAAiB,WAAW,OAAO,MAAuB;AAAA,MAC3D,OAAO;AACN,wBAAgB,sBAAsB,KAAK,MAAM,mBAAmB;AAAA,MACrE;AAAA,IACD,OAAO;AACN,sBAAgB,sBAAsB,KAAK,UAAU,GAAG,qBAAqB;AAAA,IAC9E;AAEA,SAAK,SAAS,KAAK,MAAc,UAAU,eAAe;AAAA,MACzD,MAAM,cAAc,qBAAqB;AAAA,IAC1C,CAAC;AAMD,SAAK,YAAY,WAAW,WAAW,KAAK,EAAE,MAAM,cAAc,QAAQ,KAAK,OAAO,CAAC;AACvF,SAAK,IAAI,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,SAAK,gBAAY,yBAAU,KAAK,SAAS,CAAC;AAO1C,QAAI,KAAK,cAAc,QAAW;AACjC,YAAM,YAAY,KAAK;AACvB,UAAI,qBAAqB;AACzB,YAAM,kBAAc;AAAA,QACnB,CAAC,SAAS;AAAA,QACV,MAAM;AAEL,cAAI,CAAC,oBAAoB;AACxB,iCAAqB;AACrB;AAAA,UACD;AACA,cAAI,KAAK,UAAW;AACpB,gBAAM,QAAQ,KAAK,UAAU;AAC7B,cAAI,MAAM,WAAW,EAAG;AACxB,gBAAM,OAAQ,KAAK,OAAO,QAAmB,MAAM;AACnD,eAAK,OAAO,KAAK,IAAI;AAAA,QACtB;AAAA,QACA;AAAA,UACC,MAAM;AAAA,UACN,cAAc;AAAA,UACd,MAAM,cAAc,2BAA2B;AAAA,QAChD;AAAA,MACD;AACA,WAAK,IAAI,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,WAAK,gBAAY,yBAAU,WAAW,CAAC;AAAA,IACxC;AASA,SAAK,WAAW;AAAA,MACf,CAAC,UAAkB;AAClB,cAAM,YAAY,KAAK,UAAU;AACjC,cAAM,YACL,UAAU,SACP,UAAU,SACV,sBAAsB,OAAO,wBAAwB;AACzD,cAAM,OAAO,KAAK,IAAI,WAAW,UAAU,MAAM;AACjD,YAAI,QAAQ,EAAG,QAAO,KAAK,OAAO;AAClC,cAAM,OAAQ,KAAK,OAAO,QAAmB;AAI7C,aAAK,OAAO,KAAK,IAAI;AACrB,eAAO;AAAA,MACR;AAAA,MACA,EAAE,OAAO,UAAU,QAAQ,MAAM;AAAA,IAClC;AAEA,SAAK,kBAAkB;AAAA,MACtB,CAAC,UAA+B;AAC/B,cAAM,YAAY,KAAK,UAAU;AACjC,cAAM,MACL,UAAU,SACP,UAAU,SACV,sBAAsB,OAAO,+BAA+B;AAChE,cAAM,QAAQ,UAAU,MAAM,GAAG,GAAG;AACpC,YAAI,MAAM,WAAW,EAAG,QAAO,EAAE,OAAO,QAAQ,KAAK,OAAO,MAAgB;AAC5E,cAAM,OAAQ,KAAK,OAAO,QAAmB,MAAM;AACnD,aAAK,OAAO,KAAK,IAAI;AACrB,eAAO,EAAE,OAAO,QAAQ,KAAK;AAAA,MAC9B;AAAA,MACA,EAAE,OAAO,UAAU,QAAQ,MAAM;AAAA,IAClC;AAAA,EACD;AAAA,EAEA,IAAI,OAAwB;AAC3B,QAAI,KAAK,UAAW,QAAO,KAAK,OAAO;AACvC,WAAO,KAAK,SAAS,KAAK;AAAA,EAC3B;AAAA,EAEA,KAAK,OAA8B;AAClC,QAAI,KAAK,UAAW,QAAO,CAAC;AAC5B,UAAM,YAAY,KAAK,UAAU;AACjC,UAAM,MACL,UAAU,SACP,UAAU,SACV,sBAAsB,OAAO,yBAAyB;AAC1D,WAAO,UAAU,MAAM,GAAG,GAAG;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,OAAqC;AAC/C,QAAI,KAAK,UAAW,QAAO,EAAE,OAAO,CAAC,GAAG,QAAQ,KAAK,OAAO,MAAgB;AAC5E,WAAO,KAAK,gBAAgB,KAAK;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAgB;AACf,QAAI,KAAK,UAAW;AACpB,SAAK,YAAY;AACjB,SAAK,OAAO,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AAE7B,SAAK,QAAQ;AAAA,EACd;AACD;AAyWO,SAAS,MAAS,MAAc,MAAoC;AAC1E,SAAO,IAAI,WAAc,MAAM,IAAI;AACpC;AAuBO,SAAS,aACf,MACA,YACA,MACuB;AACvB,SAAO,IAAI,kBAAqB,MAAM,YAAY,IAAI;AACvD;;;AE1wBA,IAAAC,gBAUO;AACP,IAAAC,gBAA8C;AAC9C,IAAAC,gBAAyC;;;ACGzC,IAAAC,eAQO;AAsBA,SAAS,eAAkB,QAA6B;AAC9D,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AAC1C,QAAI,UAAU;AACd,QAAI,cAAc;AAClB,QAAI;AACJ,YAAQ,OAAO,UAAU,CAAC,SAAS;AAClC,iBAAW,KAAK,MAAM;AACrB,YAAI,QAAS;AACb,YAAI,EAAE,CAAC,MAAM,mBAAM;AAClB,oBAAU;AACV,kBAAQ,EAAE,CAAC,CAAM;AACjB,cAAI,OAAO;AACV,kBAAM;AACN,oBAAQ;AAAA,UACT,MAAO,eAAc;AACrB;AAAA,QACD;AACA,YAAI,EAAE,CAAC,MAAM,oBAAO;AACnB,oBAAU;AACV,iBAAO,EAAE,CAAC,CAAC;AACX,cAAI,OAAO;AACV,kBAAM;AACN,oBAAQ;AAAA,UACT,MAAO,eAAc;AACrB;AAAA,QACD;AACA,YAAI,EAAE,CAAC,MAAM,uBAAU;AACtB,oBAAU;AACV,iBAAO,IAAI,MAAM,wBAAwB,CAAC;AAC1C,cAAI,OAAO;AACV,kBAAM;AACN,oBAAQ;AAAA,UACT,MAAO,eAAc;AACrB;AAAA,QACD;AAAA,MACD;AAAA,IACD,CAAC;AACD,QAAI,aAAa;AAChB,cAAQ;AACR,cAAQ;AAAA,IACT;AAAA,EACD,CAAC;AACF;AA6BO,SAAS,WACf,QACA,WACA,MACa;AAeb,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI,UAAU;AACd,MAAI,cAAc;AAClB,MAAI;AACJ,MAAI,qBAAqB,MAAM,gBAAgB;AAQ/C,QAAM,aAAa,CAAC,MAAe;AAClC,QAAI,QAAS;AACb,cAAU;AACV,QAAI,aAAa,KAAM,WAAU,CAAC;AAAA,QAC7B,WAAU,EAAE,MAAM,QAAQ,OAAO,EAAE;AAAA,EACzC;AACA,QAAM,cAAc,CAAC,QAAuB;AAC3C,QAAI,QAAS;AACb,cAAU;AACV,QAAI,YAAY,KAAM,UAAS,GAAG;AAAA,QAC7B,WAAU,EAAE,MAAM,SAAS,IAAI;AAAA,EACrC;AACA,QAAM,iBAAiB,MAAY;AAClC,QAAI,QAAS;AACb,cAAU;AACV,UAAM,MAAM,IAAI,MAAM,kCAAkC;AACxD,QAAI,YAAY,KAAM,UAAS,GAAG;AAAA,QAC7B,WAAU,EAAE,MAAM,WAAW;AAAA,EACnC;AACA,QAAM,SAAS,MAAY;AAC1B,QAAI,OAAO;AACV,YAAM;AACN,cAAQ;AAAA,IACT,MAAO,eAAc;AAAA,EACtB;AAEA,QAAM,OAAiC,CAAC,SAAS;AAChD,QAAI,QAAS;AACb,eAAW,KAAK,MAAM;AACrB,UAAI,QAAS;AAOb,UAAI,sBAAsB,EAAE,CAAC,MAAM,kBAAM;AACzC,UAAI,EAAE,CAAC,MAAM,mBAAM;AAClB,cAAM,IAAI,EAAE,CAAC;AACb,YAAI,UAAU,CAAC,GAAG;AACjB,qBAAW,CAAC;AACZ,iBAAO;AACP;AAAA,QACD;AAAA,MACD;AACA,UAAI,EAAE,CAAC,MAAM,oBAAO;AACnB,oBAAY,EAAE,CAAC,CAAC;AAChB,eAAO;AACP;AAAA,MACD;AACA,UAAI,EAAE,CAAC,MAAM,uBAAU;AACtB,uBAAe;AACf,eAAO;AACP;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,UAAQ,OAAO,UAAU,IAAI;AAC7B,uBAAqB;AAKrB,MAAI,MAAM,QAAQ,QAAQ,CAAC,SAAS;AACnC,QAAI;AACH,WAAK,KAAK;AAAA,IACX,SAAS,KAAK;AACb,kBAAY,GAAG;AACf,aAAO;AAAA,IACR;AAAA,EACD;AACA,MAAI,aAAa;AAChB,YAAQ;AACR,YAAQ;AAAA,EACT;AAEA,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AAG1C,QAAI,WAAW,MAAM;AACpB,UAAI,QAAQ,SAAS,OAAQ,SAAQ,QAAQ,KAAK;AAAA,eACzC,QAAQ,SAAS,QAAS,QAAO,QAAQ,GAAG;AAAA,UAChD,QAAO,IAAI,MAAM,kCAAkC,CAAC;AACzD;AAAA,IACD;AACA,gBAAY;AACZ,eAAW;AAAA,EACZ,CAAC;AACF;AA8CA,IAAI;AACJ,IAAI;AAEJ,eAAsB,aACrB,QACA,MAyB0B;AAC1B,QAAM,YAAY,MAAM,cAAc,CAAC,MAAS,KAAK;AACrD,QAAM,cAAc,MAAM;AAC1B,QAAM,OAAO,MAAM;AACnB,MAAI,MAAM,aAAa,QAAQ,KAAK,aAAa,GAAG;AACnD,WAAQ,MAAM,WAAW,QAAQ,WAAW,EAAE,aAAa,KAAK,CAAC;AAAA,EAClE;AAKA,MAAI,eAAe,QAAW;AAC7B,UAAM,CAAC,YAAY,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC/C;AAAA,MACA;AAAA,IACD,CAAC;AACD,iBAAa,WAAW;AACxB,eAAW,QAAQ;AAAA,EACpB;AACA,QAAM,UAAU,WAAW,QAAQ,EAAE,IAAI,KAAK,YAAa,SAAoB,CAAC,EAAE;AAClF,SAAQ,MAAM,WAAW,SAAS,WAAW,EAAE,aAAa,KAAK,CAAC;AACnE;AA4CO,SAAS,WACf,QACA,MAC+C;AAC/C,QAAM,OAAO,IAAI,gBAAgB;AACjC,QAAM,SAAS,MAAM,UAAU,IAAI,MAAM,0BAA0B;AACnE,MAAI;AACJ,MAAI,cAAc;AAClB,QAAM,OAAO,MAAM;AAClB,QAAI,OAAO;AACV,YAAM;AACN,cAAQ;AAAA,IACT,MAAO,eAAc;AAAA,EACtB;AACA,UAAQ,OAAO,UAAU,CAAC,SAAS;AAClC,QAAI,KAAK,OAAO,QAAS;AACzB,eAAW,KAAK,MAAM;AACrB,UAAI,EAAE,CAAC,MAAM,qBAAQ,EAAE,CAAC,MAAM,MAAM;AACnC,aAAK,MAAM,MAAM;AACjB,aAAK;AACL;AAAA,MACD;AACA,UAAI,EAAE,CAAC,MAAM,oBAAO;AAInB,aAAK,MAAM,EAAE,CAAC,CAAC;AACf,aAAK;AACL;AAAA,MACD;AACA,UAAI,EAAE,CAAC,MAAM,uBAAU;AAItB,aAAK;AACL;AAAA,MACD;AAAA,IACD;AAAA,EACD,CAAC;AACD,MAAI,aAAa;AAChB,YAAQ;AACR,YAAQ;AAAA,EACT;AACA,SAAO;AAAA,IACN,QAAQ,KAAK;AAAA,IACb,SAAS,MAAM;AACd,UAAI,OAAO;AACV,cAAM;AACN,gBAAQ;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACD;;;ACpbA,IAAAC,eAA0C;AAC1C,IAAAC,gBAA+D;AAC/D,IAAAC,gBAAyC;AAalC,IAAM,kBAAN,cAA8B,oBAAM;AAAA,EACzB;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA;AAAA,EACA;AAAA,EAET,YAAY,MAAc,OAA0B,CAAC,GAAG;AACvD,UAAM,MAAM,KAAK,KAAK;AAEtB,SAAK,WAAO,2BAAyB,CAAC,GAAG;AAAA,MACxC,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,IACf,CAAC;AACD,SAAK,WAAW,KAAK,KAAK;AAC1B,SAAK,IAAI,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAK5C,SAAK,aAAS;AAAA,MACb,CAAC,KAAK,QAAQ;AAAA,MACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,UAAU,KAAK,CAAC;AACtB,YAAI,QAAQ,WAAW,GAAG;AACzB,kBAAQ,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AACzB;AAAA,QACD;AACA,gBAAQ,KAAK,QAAQ,QAAQ,SAAS,CAAC,CAAgB;AAAA,MACxD;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,aAAa;AAAA,MAC3B;AAAA,IACD;AACA,SAAK,IAAI,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,SAAK,gBAAY,yBAAU,KAAK,MAAM,CAAC;AAEvC,SAAK,mBAAe;AAAA,MACnB,CAAC,KAAK,QAAQ;AAAA,MACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,gBAAQ,KAAM,KAAK,CAAC,EAA6B,MAAM;AAAA,MACxD;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,oBAAoB;AAAA,QACjC,SAAS;AAAA,MACV;AAAA,IACD;AACA,SAAK,IAAI,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,SAAK,gBAAY,yBAAU,KAAK,YAAY,CAAC;AAAA,EAC9C;AAAA,EAEA,OAAO,MAA2B,SAAiB,OAAoC;AACtF,SAAK,KAAK,OAAO,EAAE,MAAM,SAAS,GAAG,MAAM,CAAC;AAAA,EAC7C;AAAA,EAEA,iBAAiB,QAAgB,SAAuB;AACvD,SAAK,KAAK,OAAO,EAAE,MAAM,QAAQ,SAAS,YAAY,OAAO,CAAC;AAAA,EAC/D;AAAA,EAEA,QAAc;AACb,SAAK,KAAK,MAAM;AAAA,EACjB;AAAA,EAEA,cAAsC;AACrC,WAAO,KAAK,SAAS;AAAA,EACtB;AACD;AAEO,SAAS,WAAW,MAAc,MAA2C;AACnF,SAAO,IAAI,gBAAgB,MAAM,IAAI;AACtC;;;AC/EA,IAAAC,eAAgC;AAChC,IAAAC,gBAAkC;;;ACZlC,IAAAC,eAWO;AACP;AACA;AAgFA,SAAS,mBAAmB,MAA0C;AACrE,QAAM,QAAQ,MAAM;AACpB,QAAM,aAAa,MAAM;AAIzB,MAAI,eAAe,UAAa,UAAU,QAAW;AACpD,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AAEA,QAAM,aAAa,UAAU,SAAY,QAAQ;AACjD,MAAI,aAAa,EAAG,OAAM,IAAI,WAAW,0BAA0B;AAEnE,QAAM,WACL,eAAe,SACZ,OACA,OAAO,eAAe,WACrB,qBAAqB,UAAU,IAC/B;AAEL,SAAO,EAAE,YAAY,SAAS;AAC/B;AAEA,SAAS,iBAAiB,MAA0D;AACnF,QAAM,OAAgC,CAAC;AACvC,MAAI,MAAM,UAAU,OAAW,MAAK,QAAQ,KAAK;AACjD,MAAI,OAAO,MAAM,YAAY,SAAU,MAAK,UAAU,KAAK;AAC3D,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,OAAO;AAC9C;AAeA,SAAS,sBACR,QACA,eACA,GACA,WACa;AACb,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,YAA2B;AAC/B,MAAI;AACJ,QAAM,QAAQ,IAAI,6BAAgB;AAClC,QAAM,UAAU,CAAC,WAA8B;AAC9C,gBAAY,EAAE,QAAQ,SAAS,cAAc,UAAU,CAAC;AAAA,EACzD;AACA,UAAQ,SAAS;AAEjB,WAAS,qBAA2B;AACnC,YAAQ;AACR,YAAQ;AAAA,EACT;AAEA,WAAS,sBAAsB,KAAoB;AAClD,QAAI,QAAS;AACb,UAAM,MAAM,OAAO;AACnB,QAAI,WAAW,IAAI,YAAY;AAC9B,yBAAmB;AACnB,cAAQ,SAAS;AACjB,QAAE,KAAK,CAAC,CAAC,oBAAO,GAAG,CAAC,CAAC;AACrB;AAAA,IACD;AACA,UAAM,MAAM,IAAI,aAAa,OAAO,IAAI,IAAI,SAAS,SAAS,KAAK,SAAS;AAE5E,QAAI,QAAQ,QAAQ,QAAQ,QAAW;AACtC,yBAAmB;AACnB,cAAQ,SAAS;AACjB,QAAE,KAAK,CAAC,CAAC,oBAAO,GAAG,CAAC,CAAC;AACrB;AAAA,IACD;AAKA,QAAI;AACJ,QAAI;AACH,gBAAU,cAAc,GAAG;AAAA,IAC5B,QAAQ;AACP,yBAAmB;AACnB,cAAQ,SAAS;AACjB,QAAE,KAAK,CAAC,CAAC,oBAAO,GAAG,CAAC,CAAC;AACrB;AAAA,IACD;AACA,gBAAY;AACZ,eAAW;AACX,uBAAmB;AACnB,YAAQ,QAAQ;AAIhB,UAAM,UAAU,UAAU,IAAI,UAAU,YAAY;AAGpD,UAAM,MAAM,SAAS,MAAM;AAC1B,UAAI,QAAS;AACb,cAAQ;AAAA,IACT,CAAC;AAAA,EACF;AAEA,WAAS,UAAgB;AACxB,UAAM,OAAO;AACb,uBAAmB;AACnB,QAAI;AACJ,QAAI;AACH,YAAM,cAAc;AAAA,IACrB,SAAS,KAAK;AACb,4BAAsB,GAAG;AACzB;AAAA,IACD;AACA,YAAQ,SAAS;AACjB,YAAQ,IAAI,UAAU,CAAC,SAAS;AAC/B,UAAI,QAAS;AACb,iBAAW,KAAK,MAAM;AACrB,cAAM,IAAI,EAAE,CAAC;AACb,YAAI,MAAM,mBAAO,GAAE,KAAK,CAAC,CAAC,kBAAK,CAAC,CAAC;AAAA,iBACxB,MAAM,mBAAM;AACpB,oBAAU;AACV,sBAAY;AACZ,YAAE,KAAK,EAAE,CAAC,CAAM;AAChB,kBAAQ,SAAS;AAAA,QAClB,WAAW,MAAM,sBAAU,GAAE,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AAAA,iBACrC,MAAM,uBAAU;AAOxB,oBAAU;AACV,6BAAmB;AACnB,kBAAQ,WAAW;AACnB,YAAE,KAAK,CAAC,CAAC,qBAAQ,CAAC,CAAC;AAAA,QACpB,WAAW,MAAM,oBAAO;AACvB,gCAAsB,OAAO,CAAC,CAAC;AAC/B;AAAA,QACD,MAAO,GAAE,KAAK,CAAC,CAAC,CAAC;AAAA,MAClB;AAAA,IACD,CAAC;AAAA,EACF;AAEA,UAAQ;AAER,SAAO,MAAM;AACZ,UAAM,aAAa;AACnB,cAAU;AACV,UAAM,OAAO;AACb,uBAAmB;AACnB,QAAI,CAAC,WAAY,SAAQ,WAAW;AAAA,EACrC;AACD;AAoDO,SAAS,MACf,OACA,MACiB;AACjB,QAAM,iBAAa,mBAAiB,CAAC,GAAG;AAAA,IACvC,MAAM;AAAA,IACN,cAAc;AAAA,IACd,SAAS,EAAE,QAAQ,WAAW,SAAS,GAAG,cAAc,KAAK;AAAA,IAC7D,QAAQ,CAAC,GAAG,MACX,MAAM,KACL,KAAK,QACL,KAAK,QACL,OAAO,MAAM,YACb,OAAO,MAAM,YACb,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;AAAA,EACzC,CAAC;AACD,QAAM,OAAO,CAAC,MAAwB;AACrC,eAAW,KAAK,CAAC,CAAC,kBAAK,GAAG,CAAC,mBAAM,CAAC,CAAC,CAAC;AAAA,EACrC;AACA,MAAI,OAAO,UAAU,YAAY;AAChC,WAAO;AAAA,MACN,MAAM,cAAc,OAAO,MAAyD,IAAI;AAAA,MACxF;AAAA,IACD;AAAA,EACD;AACA,SAAO;AAAA,IACN,MAAM,aAAa,OAAO,MAA+C,IAAI;AAAA,IAC7E;AAAA,EACD;AACD;AAMA,SAAS,qBACR,KACsD;AACtD,MAAI,QAAQ,QAAW;AACtB,WAAO,EAAE,SAAS,MAAM,QAAW,OAAO,MAAM,OAAU;AAAA,EAC3D;AACA,MAAI,CAAC,OAAO,GAAG,GAAG;AACjB,WAAO,EAAE,SAAS,MAAM,KAAU,OAAO,MAAM,OAAU;AAAA,EAC1D;AACA,QAAM,WAAW;AACjB,MAAI,SAAyB,SAAS,SAA2B;AACjE,QAAM,QAAQ,SAAS,UAAU,CAAC,SAAS;AAC1C,eAAW,KAAK,MAAM;AACrB,UAAI,EAAE,CAAC,MAAM,kBAAM;AACnB,YAAM,OAAO,EAAE,CAAC;AAChB,UAAI,QAAQ,QAAQ,OAAO,SAAS,SAAU;AAC9C,UAAI,OAAO,KAAK,IAAI,EAAE,WAAW,EAAG;AACpC,eAAS,EAAE,GAAI,UAAW,CAAC,GAAU,GAAG,KAAK;AAAA,IAC9C;AAAA,EACD,CAAC;AACD,SAAO,EAAE,SAAS,MAAM,QAAQ,MAAM;AACvC;AAIA,IAAM,sCAAsC,oBAAI,QAAuB;AAEvE,SAAS,aACR,QACA,MACA,WACU;AAMV,QAAM,iBAAiB;AACvB,MACC,eAAe,oBAAoB,SACnC,CAAC,oCAAoC,IAAI,MAAM,GAC9C;AACD,wCAAoC,IAAI,MAAM;AAC9C,YAAQ;AAAA,MACP;AAAA,IAID;AAAA,EACD;AACA,QAAM,aAAa,OAAO,IAAI,IAAI,SAAa;AAI/C,MAAI,CAAC,OAAO,IAAI,EAAG,oBAAmB,UAAU;AAChD,aAAO;AAAA,IACN,CAAC,OAAO,MAAM;AACb,YAAM,SAAS,qBAAmC,IAAI;AACtD,YAAM,SAAS,MAA2B,mBAAmB,OAAO,QAAQ,CAAC;AAC7E,YAAM,QAAQ,sBAAsB,QAAQ,MAAM,QAAQ,GAAG,SAAS;AACtE,aAAO;AAAA,QACN,gBAAgB,MAAM;AACrB,gBAAM;AACN,iBAAO,MAAM;AAAA,QACd;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,GAAG,aAAa;AAAA,MAChB,SAAS,OAAO;AAAA,MAChB,MAAM;AAAA,QACL,GAAI,YAAY,QAAQ,CAAC;AAAA,QACzB,OAAG;AAAA,UACF;AAAA,UACA,OAAO,IAAI,IAAI,EAAE,cAAc,KAAK,IAAI,iBAAiB,UAAU;AAAA,QACpE;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAEA,SAAS,cACR,SACA,MACA,WACU;AACV,QAAM,aAAa,OAAO,IAAI,IAAI,SAAa;AAE/C,MAAI,CAAC,OAAO,IAAI,EAAG,oBAAmB,UAAU;AAChD,aAAO;AAAA,IACN,CAAC,OAAO,MAAM;AACb,YAAM,SAAS,qBAA6C,IAAI;AAChE,YAAM,SAAS,MAA2B,mBAAmB,OAAO,QAAQ,CAAC;AAC7E,YAAM,QAAQ,sBAAsB,QAAQ,SAAS,GAAG,SAAS;AACjE,aAAO;AAAA,QACN,gBAAgB,MAAM;AACrB,gBAAM;AACN,iBAAO,MAAM;AAAA,QACd;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,GAAG,aAAa;AAAA,MAChB,SAAS,YAAY;AAAA,MACrB,MAAM;AAAA,QACL,GAAI,YAAY,QAAQ,CAAC;AAAA,QACzB,OAAG;AAAA,UACF;AAAA,UACA,OAAO,IAAI,IAAI,EAAE,cAAc,KAAK,IAAI,iBAAiB,UAAU;AAAA,QACpE;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;;;ADxXO,SAAS,cAAc,MAAyD;AACtF,QAAM,EAAE,WAAW,MAAM,IAAI;AAC7B,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,cAAc,CAAC,GAA0B,MAAsC;AACpF,QAAI,MAAM,EAAG,QAAO;AACpB,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,aAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AAClC,YAAM,KAAK,EAAE,CAAC;AACd,YAAM,KAAK,EAAE,CAAC;AACd,UAAI,IAAI,OAAO,IAAI,GAAI,QAAO;AAC9B,UAAI,IAAI,YAAY,IAAI,QAAS,QAAO;AAAA,IACzC;AACA,WAAO;AAAA,EACR;AAEA,aAAO,yBAAsD,WAAW,CAAC,UAAU;AAClF,QAAI,SAAS,QAAQ,MAAM,WAAW,GAAG;AACxC,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AACA,UAAM,UAAU,MAAM,IAAI,CAAC,SAAS,WAAW,MAAM,OAAO,YAAY,OAAO,CAAC;AAKhF,eAAO;AAAA,MACN;AAAA,MACA,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,gBAAQ,KAAK,IAA6B;AAAA,MAC3C;AAAA,MACA,EAAE,cAAc,WAAW,MAAM,wBAAwB,QAAQ,YAAY;AAAA,IAC9E;AAAA,EACD,CAAC;AACF;AAmBA,SAAS,WACR,MACA,OACA,YACA,SACmB;AACnB,QAAM,YAA2B,MAAM,MAAM,MAAM,gBAAgB,KAAK,MAAM,KAAK,SAAS,GAAG;AAAA,IAC9F,OAAO;AAAA,EACR,CAAC,EAAE;AACH,QAAM,gBAAY;AAAA,IACjB,CAAC,SAAS;AAAA,IACV,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,MAAM,KAAK,CAAC;AAClB,cAAQ,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,SAAS,OAAO,QAAQ,WAAW,MAAM,KAAK,UAAU,GAAG;AAAA,MAC5D,CAAC;AAAA,IACF;AAAA,IACA,EAAE,cAAc,UAAU;AAAA,EAC3B;AACA,MAAI,YAAY,YAAa,QAAO;AACpC,aAAO,sBAAO,WAAW,CAAC,SAAS;AAAA,IAClC,IAAI,KAAK;AAAA,IACT,SAAS,KAAK,UAAU,EAAE,OAAO,OAAO,GAAG,EAAE,CAAC;AAAA,EAC/C,EAAE;AACH;;;AEjLA,IAAAC,gBAAsD;AACtD,IAAAC,gBAAmE;AACnE,IAAAC,gBAAyC;AAgClC,IAAM,oBAAN,cAAgC,oBAAM;AAAA,EACnC;AAAA,EACA;AAAA,EACQ;AAAA,EAEjB,YAAY,MAAc,OAA4B,CAAC,GAAG;AACzD,UAAM,MAAM,KAAK,KAAK;AAEtB,SAAK,cAAU,2BAAoC;AAAA,MAClD,MAAM;AAAA,IACP,CAAC;AACD,SAAK,cAAc,KAAK,QAAQ;AAChC,SAAK,IAAI,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,SAAK,cAAU;AAAA,MACd,CAAC,KAAK,WAAW;AAAA,MACjB,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,OAAO,KAAK,CAAC;AACnB,gBAAQ,KAAK,CAAC,IAAK,QAAQ,oBAAI,IAAI,GAA2C,OAAO,CAAC,CAAC;AAAA,MACxF;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,cAAc;AAAA,QAC3B,SAAS,CAAC;AAAA,MACX;AAAA,IACD;AACA,SAAK,IAAI,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,SAAK,gBAAY,yBAAU,KAAK,OAAO,CAAC;AAAA,EACzC;AAAA,EAEA,SAAS,MAA4B;AACpC,SAAK,QAAQ,IAAI,KAAK,MAAM,IAAI;AAAA,EACjC;AAAA,EAEA,WAAW,MAAoB;AAC9B,SAAK,QAAQ,OAAO,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BA,gBAAgB,MAAc,MAA8C;AAC3E,UAAM,OAAO,KAAK,QAAQ,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,+BAA+B,IAAI,GAAG;AACjE,eAAO;AAAA,MACN,CAAC;AAAA,MACD,CAAC,OAAO,YAAY;AACnB,cAAM,KAAK,IAAI,gBAAgB;AAC/B,YAAI;AACJ,YAAI;AACH,gBAAM,MAAM,KAAK,QAAQ,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;AACpD,kBAAQ,oBAAoB,KAAK,GAAG,MAAM;AAAA,QAC3C,SAAS,KAAK;AAIb,kBAAQ,KAAK,CAAC,CAAC,qBAAO,GAAG,CAAC,CAAoB;AAC9C,iBAAO;AAAA,YACN,gBAAgB,MAAM;AACrB,iBAAG,MAAM;AAAA,YACV;AAAA,UACD;AAAA,QACD;AACA,cAAM,QAAQ,MAAM,UAAU,CAACA,WAAU;AACxC,kBAAQ,KAAKA,MAAiB;AAAA,QAC/B,CAAC;AACD,eAAO;AAAA,UACN,gBAAgB,MAAM;AACrB,eAAG,MAAM;AACT,kBAAM;AAAA,UACP;AAAA,QACD;AAAA,MACD;AAAA,MACA;AAAA,QACC,MAAM,oBAAoB,IAAI;AAAA,QAC9B,cAAc;AAAA,QACd,MAAM,OAAO,uBAAuB;AAAA,MACrC;AAAA,IACD;AAAA,EACD;AAAA,EAEA,cAAc,MAA0C;AAKvD,WAAO,KAAK,QAAQ,QAAQ,OAAO,IAAI,IAAI;AAAA,EAC5C;AACD;AAEO,SAAS,aAAa,MAAc,MAA+C;AACzF,SAAO,IAAI,kBAAkB,MAAM,IAAI;AACxC;AAeA,SAAS,oBAAoB,KAAc,QAAoC;AAC9E,MAAI,WAAW,GAAG,GAAG;AACpB,WAAO;AAAA,EACR;AACA,MAAI,OAAO,QAAQ,OAAQ,IAA6B,SAAS,YAAY;AAC5E,eAAO,2BAAY,KAA6B,EAAE,OAAO,CAAC;AAAA,EAC3D;AACA,MAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,OAAO,iBAAkB,KAAgB;AACtF,eAAO,6BAAc,KAA+B,EAAE,OAAO,CAAC;AAAA,EAC/D;AAKA,aAAO,2BAAY,QAAQ,QAAQ,GAAG,GAAG,EAAE,OAAO,CAAC;AACpD;;;AL1EO,IAAM,iBAAN,cAA6B,oBAAM;AAAA,EAChC;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAEQ;AAAA,EACA;AAAA;AAAA,EAET,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQX,0BAAkD;AAAA,EAE1D,YAAY,MAAc,MAAwB;AACjD,UAAM,MAAM,KAAK,KAAK;AAGtB,SAAK,OAAO,WAAW,GAAG,IAAI,SAAS,EAAE,aAAa,KAAK,YAAY,CAAC;AACxE,SAAK,MAAM,QAAQ,KAAK,IAAI;AAG5B,SAAK,QAAQ,aAAa,GAAG,IAAI,QAAQ;AACzC,SAAK,MAAM,SAAS,KAAK,KAAK;AAE9B,QAAI,KAAK,OAAO;AACf,iBAAW,QAAQ,KAAK,OAAO;AAC9B,aAAK,MAAM,SAAS,IAAI;AAAA,MACzB;AAAA,IACD;AAGA,SAAK,aAAS,oBAAsB,CAAC,GAAG;AAAA,MACvC,GAAG;AAAA,QACF,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,cAAc;AAAA,MAC5B;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AACD,SAAK,IAAI,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,SAAK,WAAO,oBAAa,CAAC,GAAG;AAAA,MAC5B,GAAG;AAAA,QACF,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,kBAAkB;AAAA,MAChC;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AACD,SAAK,IAAI,KAAK,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpC,SAAK,cAAU,oBAAc,CAAC,GAAG;AAAA,MAChC,GAAG;AAAA,QACF,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,eAAe;AAAA,MAC7B;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AACD,SAAK,IAAI,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAqC1C,QAAI,aAAa;AACjB,UAAM,UAAU,KAAK,KAAK,UAAU,CAAC,SAAS;AAC7C,iBAAW,KAAK,KAAM,KAAI,EAAE,CAAC,MAAM,mBAAM,cAAa,EAAE,CAAC;AAAA,IAC1D,CAAC;AACD,QAAI,gBAAgB;AACpB,UAAM,aAAa,KAAK,QAAQ,UAAU,CAAC,SAAS;AACnD,iBAAW,KAAK,KAAM,KAAI,EAAE,CAAC,MAAM,mBAAM,iBAAgB,EAAE,CAAC;AAAA,IAC7D,CAAC;AAED,UAAM,UAAU,KAAK;AACrB,UAAM,eAAe,KAAK;AAC1B,UAAM,QAAQ,KAAK;AACnB,UAAM,cAAc,KAAK;AACzB,UAAM,YAAY,KAAK;AACvB,UAAM,WAAW,KAAK,YAAY;AAClC,UAAM,WAAW,KAAK;AAGtB,UAAM,OAAO,KAAK;AAClB,UAAM,QAAQ,KAAK;AACnB,UAAM,aAAa,KAAK;AACxB,UAAM,WAAW,KAAK;AACtB,UAAM,cAAc,KAAK;AAWzB,UAAM,kBAAiC,cAAAC;AAAA,MACtC,CAAC,UAAU;AAAA,MACX,CAAC,MAAM,SAAS,QAAQ;AACvB,cAAM,OAAO,WAA4B,MAAM,IAAI,UAAU,GAAG,MAAM;AACtE,YAAI,SAAS,cAAc,iBAAiB,cAAc,UAAU;AACnE,kBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB;AAAA,QACD;AAaA,cAAM,WAAY,KAAK,KAAK,SAAS,SAAgD,CAAC;AACtF,YAAI,SAAS,WAAW,GAAG;AAC1B,kBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB;AAAA,QACD;AACA,cAAM,UAAW,KAAK,MAAM,QAAQ,SAAmD,CAAC;AACxF,gBAAQ,KAAK,EAAE,UAAU,OAAO,QAAQ,CAAC;AAAA,MAC1C;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAQlC,cAAc,CAAC,WAAW,QAAQ,iBAAiB,eAAe;AAAA,QACnE,CAAC;AAAA,MACF;AAAA,IACD;AAEA,UAAM,kBAAiC;AAAA,MACtC;AAAA,MACA,CAAC,UAAU;AACV,cAAM,aAAa,IAAI,gBAAgB;AACvC,aAAK,0BAA0B;AAC/B,YAAI,eAAe;AAClB,qBAAW,MAAM,IAAI,MAAM,oBAAoB,CAAC;AAAA,QACjD;AAOA,mBAAO;AAAA,UACN,QAAQ,OAAO,MAAM,UAAU;AAAA,YAC9B,OAAO,MAAM,MAAM,SAAS,IAAI,MAAM,QAAQ;AAAA,YAC9C;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ,WAAW;AAAA,UACpB,CAAC;AAAA,UACD,EAAE,QAAQ,WAAW,OAAO;AAAA,QAC7B;AAAA,MACD;AAAA,MACA,EAAE,QAAQ,MAAM,MAAM;AAAA,IACvB;AA6CA,UAAM,wBAAoB,oBAAkB,CAAC,GAAG;AAAA,MAC/C,MAAM;AAAA,MACN,cAAc;AAAA,MACd,MAAM,OAAO,qBAAqB;AAAA,IACnC,CAAC;AACD,SAAK,eAAe;AAcpB,UAAM,mBAAe,cAAAA;AAAA,MACpB,CAAC,mBAAmB,UAAU;AAAA,MAC9B,CAAC,MAAM,SAAS,QAAQ;AAMvB,cAAM,OAAO,WAAoC,MAAM,IAAI,UAAU,GAAG,MAAS;AACjF,cAAM,OAAO,WAA4B,MAAM,IAAI,UAAU,GAAG,MAAM;AACtE,YAAI,SAAS,UAAU;AACtB,kBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB;AAAA,QACD;AACA,cAAM,QAAQ,MAAM;AACpB,YAAI,SAAS,QAAQ,MAAM,WAAW,GAAG;AACxC,kBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB;AAAA,QACD;AACA,gBAAQ,KAAK,KAAK;AAAA,MACnB;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,sBAAsB;AAAA,MACpC;AAAA,IACD;AAKA,UAAM,qBAAqB,KAAK,qBAC7B,KAAK,mBAAmB,YAAY,IACpC;AACH,SAAK,YAAY;AAOjB,UAAM,kBAA+C,cAAc;AAAA,MAClE,WAAW;AAAA,MACX;AAAA,MACA,YAAY;AAAA,IACb,CAAC;AACD,SAAK,cAAc;AA+BnB,UAAM,kBAAc;AAAA,MACnB,CAAC,WAAW;AAAA,MACZ,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,YAAI,cAAe;AACnB,cAAM,WAAW,KAAK,CAAC;AACvB,cAAM,OAAO,aAAa;AAC1B,cAAM,eAAe,SAAS,aAAa,QAAQ,SAAS,UAAU,SAAS;AAC/E,cAAM,cACL,SAAS,iBAAiB,eACzB,CAAC,SAAS,aAAa,SAAS,UAAU,WAAW;AACvD,cAAM,aAAa,WAAW,QAAQ,MAAM;AAC5C,cAAM,aAAa,QAAQ;AAC3B,cAAM,aACL,cAAc,eAAe,CAAC,gBAAgB,aAAa,SAAS;AACrE,iCAAM,MAAM;AACX,4BAAkB,KAAK,QAAQ;AAC/B,qBAAW,KAAK,UAAU;AAC1B,mBAAS,KAAK,IAAI;AAClB,eAAK,OAAO,aAAa,SAAS,SAAS;AAAA,YAC1C,WAAW,SAAS;AAAA,UACrB,CAAC;AAAA,QACF,CAAC;AAAA,MACF;AAAA,MACA,EAAE,cAAc,SAAS;AAAA,IAC1B;AAKA,UAAM,iBAAa;AAAA,MAClB,CAAC,eAAe;AAAA,MAChB,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,YAAI,cAAe;AACnB,cAAM,MAAM,KAAK,CAAC;AAClB,YAAI,IAAI,WAAW,EAAG;AACtB,cAAM,aAA8B,cAAc,WAAW,SAAS;AACtE,iCAAM,MAAM;AACX,qBAAW,KAAK,UAAU;AAC1B,qBAAW,KAAK,IAAK,MAAK,iBAAiB,EAAE,IAAI,EAAE,OAAO;AAAA,QAC3D,CAAC;AAAA,MACF;AAAA,MACA,EAAE,cAAc,SAAS;AAAA,IAC1B;AAgBA,QAAI,eAAiC,WAAW,SAAyC;AACzF,UAAM,YAAY,WAAW,UAAU,CAAC,SAAS;AAChD,iBAAW,KAAK,KAAM,KAAI,EAAE,CAAC,MAAM,mBAAM,gBAAe,EAAE,CAAC;AAAA,IAC5D,CAAC;AACD,UAAM,eAAW;AAAA,MAChB,CAAC,WAAW;AAAA,MACZ,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,YAAI,KAAK,CAAC,MAAM,MAAM;AACrB,eAAK,yBAAyB,MAAM,IAAI,MAAM,oBAAoB,CAAC;AACnE,cAAI,iBAAiB,OAAQ,YAAW,KAAK,MAAM;AAAA,QACpD;AAAA,MACD;AAAA,MACA,EAAE,cAAc,SAAS;AAAA,IAC1B;AAKA,UAAM,iBAAa,yBAAU,WAAW;AACxC,UAAM,gBAAY,yBAAU,UAAU;AACtC,UAAM,cAAU,yBAAU,QAAQ;AAsBlC,SAAK,sBAAkB,cAAAD;AAAA,MACtB,CAAC,YAAY,iBAAiB;AAAA,MAC9B,CAAC,MAAM,SAAS,QAAQ;AACvB,cAAM,OAAO,WAA4B,MAAM,IAAI,UAAU,GAAG,MAAM;AACtE,cAAM,OAAO,WAAoC,MAAM,IAAI,UAAU,GAAG,MAAS;AACjF,YAAI,SAAS,QAAQ;AACpB,cAAI,SAAS,QAAW;AACvB,oBAAQ,KAAK,IAAI;AACjB;AAAA,UACD;AACA,gBAAM,MAAM,IAAI,MAAM,oBAAoB;AAC1C,cAAI,OAAO;AACX,kBAAQ,KAAK,CAAC,CAAC,qBAAO,GAAG,CAAC,CAAC;AAC3B;AAAA,QACD;AACA,YAAI,SAAS,SAAS;AACrB,kBAAQ,KAAK,CAAC,CAAC,qBAAO,IAAI,MAAM,oBAAoB,CAAC,CAAC,CAAC;AACvD;AAAA,QACD;AACA,gBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AAAA,MAC1B;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQpC,SAAS;AAAA,MACV;AAAA,IACD;AAcA,SAAK,IAAI,aAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,SAAK,IAAI,aAA8B,EAAE,MAAM,cAAc,CAAC;AAC9D,SAAK,IAAI,KAAK,cAA+B,EAAE,MAAM,eAAe,CAAC;AAKrE,QAAI,KAAK,cAAc,cAAc;AACpC,WAAK,IAAI,KAAK,WAA4B,EAAE,MAAM,YAAY,CAAC;AAAA,IAChE,OAAO;AACN,WAAK,IAAI,cAA+B,EAAE,MAAM,eAAe,CAAC;AAChE,WAAK,IAAI,KAAK,WAA4B,EAAE,MAAM,YAAY,CAAC;AAAA,IAChE;AACA,SAAK,IAAI,iBAAkC,EAAE,MAAM,cAAc,CAAC;AAClE,SAAK,IAAI,KAAK,iBAAkC,EAAE,MAAM,iBAAiB,CAAC;AAM1E,SAAK,YAAY,OAAO;AACxB,SAAK,YAAY,UAAU;AAC3B,SAAK,YAAY,SAAS;AAC1B,SAAK,YAAY,UAAU;AAC3B,SAAK,YAAY,SAAS;AAC1B,SAAK,YAAY,OAAO;AACxB,SAAK,oBAAoB,MAAY;AAAA,IAIrC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,MAAM,IAAI,aAAsB,QAAmD;AAClF,QAAI,KAAK,UAAU;AAClB,YAAM,IAAI;AAAA,QACT,cAAc,KAAK,IAAI;AAAA,MACxB;AAAA,IACD;AACA,SAAK,WAAW;AAEhB,QAAI;AACJ,QAAI;AAwBH,+BAAM,MAAM;AACX,aAAK,aAAa,KAAK,CAAC,CAAC,wBAAU,CAAC,CAAC;AACrC,aAAK,KAAK,KAAK,CAAC;AAChB,aAAK,QAAQ,KAAK,KAAK;AACvB,aAAK,OAAO,KAAK,MAAM;AAAA,MACxB,CAAC;AACD,UAAI,eAAe,KAAM,MAAK,KAAK,OAAO,QAAQ,WAAW;AAiB7D,YAAM,gBAAgB,aAAa,KAAK,iBAAiB,EAAE,aAAa,KAAK,CAAC;AAE9E,UAAI,UAAU,MAAM;AACnB,YAAI,OAAO,SAAS;AACnB,eAAK,QAAQ,KAAK,IAAI;AAAA,QACvB,OAAO;AACN,gBAAM,WAAW,MAAY,KAAK,QAAQ,KAAK,IAAI;AACnD,iBAAO,iBAAiB,SAAS,UAAU,EAAE,MAAM,KAAK,CAAC;AACzD,qBAAW,MAAY,OAAO,oBAAoB,SAAS,QAAQ;AAAA,QACpE;AAAA,MACD;AAQA,UAAI,QAAQ,YAAY,MAAM;AAC7B,aAAK,OAAO,KAAK,UAAU;AAAA,MAC5B;AAEA,aAAO,MAAM;AAAA,IACd,UAAE;AACD,iBAAW;AACX,WAAK,WAAW;AAChB,WAAK,0BAA0B;AAAA,IAChC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AACb,SAAK,QAAQ,KAAK,IAAI;AAAA,EACvB;AAAA,EAES,UAAgB;AACxB,QAAI;AACH,WAAK,kBAAkB;AAAA,IACxB,QAAQ;AAAA,IAER;AACA,UAAM,QAAQ;AAAA,EACf;AACD;AAYA,SAAS,WACR,WACA,UACA,OACA,UACI;AACJ,QAAMC,SAAQ,UAAU,KAAK;AAC7B,MAAIA,UAAS,QAAQA,OAAM,SAAS,EAAG,QAAOA,OAAMA,OAAM,SAAS,CAAC;AACpE,QAAM,OAAO,SAAS,KAAK;AAC3B,SAAQ,SAAS,SAAY,OAAO;AACrC;AAQO,SAAS,UAAU,MAAc,MAAwC;AAC/E,QAAM,IAAI,IAAI,eAAe,MAAM,IAAI;AAMvC,IAAE,WAAW,iBAAa,+BAAgB,IAA0C,CAAC;AACrF,SAAO;AACR;;;AL9tBA,IAAM,cAA2B,OAAO,OAAO,EAAE,SAAS,EAAE,CAAC;AAC7D,IAAM,eAA6B,OAAO,OAAO,EAAE,SAAS,EAAE,CAAC;AAC/D,IAAM,cAA0B,OAAO,OAAO,EAAE,OAAO,aAAa,QAAQ,aAAa,CAAC;AAGnF,IAAM,YAAuB,OAAO,OAAO,EAAE,OAAO,aAAa,OAAO,EAAE,CAAC;AAMlF,SAAS,YAAY,GAAuB,GAA2C;AACtF,MAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,UAAQ,KAAK,MAAM,KAAK;AACzB;AAEA,SAAS,cACR,GACA,GACqC;AACrC,MAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,QAAM,MAA8B,EAAE,GAAI,KAAK,CAAC,EAAG;AACnD,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,CAAC,CAAC,GAAG;AAC7C,QAAI,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK;AAAA,EAC1B;AACA,SAAO;AACR;AAWO,SAAS,SAAS,GAAe,GAA2B;AAClE,QAAM,MAAkB;AAAA,IACvB,OAAO;AAAA,MACN,SAAS,EAAE,MAAM,UAAU,EAAE,MAAM;AAAA,MACnC,GAAI,YAAY,EAAE,MAAM,WAAW,EAAE,MAAM,SAAS,MAAM,UAAa;AAAA,QACtE,WAAW,YAAY,EAAE,MAAM,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5D;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,cAAc,EAAE,MAAM,YAAY,MAAM,UAAa;AAAA,QAC5E,cAAc,YAAY,EAAE,MAAM,cAAc,EAAE,MAAM,YAAY;AAAA,MACrE;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,cAAc,EAAE,MAAM,YAAY,MAAM,UAAa;AAAA,QAC5E,cAAc,YAAY,EAAE,MAAM,cAAc,EAAE,MAAM,YAAY;AAAA,MACrE;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,iBAAiB,EAAE,MAAM,eAAe,MAAM,UAAa;AAAA,QAClF,iBAAiB,YAAY,EAAE,MAAM,iBAAiB,EAAE,MAAM,eAAe;AAAA,MAC9E;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK,MAAM,UAAa;AAAA,QAC9D,OAAO,YAAY,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK;AAAA,MAChD;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK,MAAM,UAAa;AAAA,QAC9D,OAAO,YAAY,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK;AAAA,MAChD;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK,MAAM,UAAa;AAAA,QAC9D,OAAO,YAAY,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK;AAAA,MAChD;AAAA,MACA,GAAI,YAAY,EAAE,MAAM,SAAS,EAAE,MAAM,OAAO,MAAM,UAAa;AAAA,QAClE,SAAS,YAAY,EAAE,MAAM,SAAS,EAAE,MAAM,OAAO;AAAA,MACtD;AAAA,MACA,GAAI,cAAc,EAAE,MAAM,YAAY,EAAE,MAAM,UAAU,MAAM,UAAa;AAAA,QAC1E,YAAY,cAAc,EAAE,MAAM,YAAY,EAAE,MAAM,UAAU;AAAA,MACjE;AAAA,IACD;AAAA,IACA,QAAQ;AAAA,MACP,SAAS,EAAE,OAAO,UAAU,EAAE,OAAO;AAAA,MACrC,GAAI,YAAY,EAAE,OAAO,WAAW,EAAE,OAAO,SAAS,MAAM,UAAa;AAAA,QACxE,WAAW,YAAY,EAAE,OAAO,WAAW,EAAE,OAAO,SAAS;AAAA,MAC9D;AAAA,MACA,GAAI,YAAY,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,MAAM,UAAa;AAAA,QAChE,OAAO,YAAY,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,MAClD;AAAA,MACA,GAAI,YAAY,EAAE,OAAO,oBAAoB,EAAE,OAAO,kBAAkB,MAAM,UAAa;AAAA,QAC1F,oBAAoB;AAAA,UACnB,EAAE,OAAO;AAAA,UACT,EAAE,OAAO;AAAA,QACV;AAAA,MACD;AAAA,MACA,GAAI,YAAY,EAAE,OAAO,oBAAoB,EAAE,OAAO,kBAAkB,MAAM,UAAa;AAAA,QAC1F,oBAAoB;AAAA,UACnB,EAAE,OAAO;AAAA,UACT,EAAE,OAAO;AAAA,QACV;AAAA,MACD;AAAA,MACA,GAAI,cAAc,EAAE,OAAO,YAAY,EAAE,OAAO,UAAU,MAAM,UAAa;AAAA,QAC5E,YAAY,cAAc,EAAE,OAAO,YAAY,EAAE,OAAO,UAAU;AAAA,MAInE;AAAA,IACD;AAAA,IACA,GAAI,cAAc,EAAE,WAAW,EAAE,SAAS,MAAM,UAAa;AAAA,MAC5D,WAAW,cAAc,EAAE,WAAW,EAAE,SAAS;AAAA,IAClD;AAAA,EACD;AACA,SAAO;AACR;AA2FA,IAAM,oBAAoB,oBAAI,IAAiB,CAAC,QAAQ,OAAO,CAAC;AAkCzD,IAAM,aAAN,cAAoC,oBAAM;AAAA;AAAA,EAEvC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,MAA4B,MAAqB;AAC5D,UAAM,KAAK,MAAM,IAAI;AAGrB,UAAM,eAAe,MAAM,QAAQ,KAAK,KAAK,IACzC,KAAK,QACN;AACH,SAAK,OAAO,UAAU,GAAG,KAAK,IAAI,SAAS;AAAA,MAC1C,SAAS,KAAK;AAAA,MACd,GAAI,KAAK,gBAAgB,OAAO,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;AAAA,MACvE,GAAI,gBAAgB,OAAO,EAAE,OAAO,aAAa,IAAI,CAAC;AAAA,MACtD,GAAI,KAAK,iBAAiB,OAAO,EAAE,UAAU,KAAK,cAAc,IAAI,CAAC;AAAA,IACtE,CAAC;AACD,SAAK,MAAM,QAAQ,KAAK,IAAI;AAM5B,QAAI,KAAK,SAAS,QAAQ,CAAC,MAAM,QAAQ,KAAK,KAAK,GAAG;AACrD,YAAM,YAAY,KAAK;AACvB,YAAM,aAAa,oBAAI,IAAY;AACnC,YAAM,aAAa,UAAU,UAAU,CAAC,SAAS;AAChD,mBAAW,KAAK,MAAM;AACrB,cAAI,EAAE,CAAC,MAAM,mBAAM;AACnB,gBAAM,OAAO,EAAE,CAAC;AAChB,gBAAM,YAAY,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAEjD,qBAAW,QAAQ,YAAY;AAC9B,gBAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACzB,mBAAK,KAAK,MAAM,WAAW,IAAI;AAC/B,yBAAW,OAAO,IAAI;AAAA,YACvB;AAAA,UACD;AAEA,qBAAW,QAAQ,MAAM;AACxB,gBAAI,CAAC,WAAW,IAAI,KAAK,IAAI,GAAG;AAC/B,mBAAK,KAAK,MAAM,SAAS,IAAI;AAC7B,yBAAW,IAAI,KAAK,IAAI;AAAA,YACzB;AAAA,UACD;AAAA,QACD;AAAA,MACD,CAAC;AACD,WAAK,YAAY,UAAU;AAAA,IAC5B;AAOA,SAAK,SAAS,KAAK,UAAU;AAC7B,QAAI,KAAK,UAAU,MAAM;AACxB,WAAK,MAAM,UAAU,KAAK,MAAM;AAAA,IACjC;AAKA,SAAK,SAAK,oBAAU,CAAC,GAAG;AAAA,MACvB,MAAM;AAAA,MACN,cAAc;AAAA,MACd,MAAM,OAAO,UAAU;AAAA,MACvB,QAAQ,MAAM;AAAA,IACf,CAAC;AACD,SAAK,IAAI,KAAK,IAAI,EAAE,MAAM,KAAK,CAAC;AAGhC,UAAM,eAAW,oBAAgB,CAAC,GAAG;AAAA,MACpC,MAAM;AAAA,MACN,cAAc;AAAA,MACd,MAAM,OAAO,YAAY;AAAA,MACzB,SAAS;AAAA,IACV,CAAC;AACD,SAAK,IAAI,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,SAAK,OAAO;AAUZ,UAAM,YAAY,KAAK,aAAa,iBAAuB;AAC3D,UAAM,cAAU;AAAA,MACf,CAAC,KAAK,KAAK,YAAY;AAAA,MACvB,CAAC,MAAM,GAAG,QAAQ;AACjB,cAAM,SAAS,KAAK,CAAC;AACrB,cAAM,OACL,UAAU,QAAQ,OAAO,SAAS,IAC9B,OAAO,GAAG,EAAE,IACZ,IAAI,SAAS,CAAC;AACnB,YAAI,SAAS,QAAW;AACvB,YAAE,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACnB;AAAA,QACD;AACA,UAAE,KAAK,UAAU,IAAI,CAAC;AAAA,MACvB;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMxB,QAAQ,MAAM;AAAA,MACf;AAAA,IACD;AACA,SAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,SAAK,MAAM;AAKX,UAAM,iBAAa,oBAAkB,CAAC,GAAG;AAAA,MACxC,MAAM;AAAA,MACN,cAAc;AAAA,MACd,MAAM,OAAO,cAAc;AAAA,MAC3B,SAAS;AAAA,IACV,CAAC;AACD,SAAK,IAAI,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,SAAK,SAAS;AAEd,UAAM,sBAAkB;AAAA,MACvB,CAAC,KAAK,KAAK,MAAM;AAAA,MACjB,CAAC,MAAM,IAAI,QAAQ;AAClB,cAAM,SAAS,KAAK,CAAC;AACrB,cAAM,aACL,UAAU,QAAQ,OAAO,SAAS,IAC9B,OAAO,GAAG,EAAE,IACX,IAAI,SAAS,CAAC,KAA4B;AAChD,cAAM,OACL,eAAe,SACZ,SACA,eAAe,cAAc,eAAe,WAC3C,YACA,eAAe,SACd,SACA,eAAe,UACd,UACA;AACP,YAAI,WAAW,UAAU,KAAM,YAAW,KAAK,IAAI;AAAA,MACpD;AAAA,MACA,EAAE,cAAc,UAAU,MAAM,OAAO,qBAAqB,EAAE;AAAA,IAC/D;AACA,SAAK,gBAAY,yBAAU,eAAe,CAAC;AAS3C,UAAM,cAAU;AAAA,MACf,CAAC,KAAK,KAAK,YAAY;AAAA,MACvB,CAAC,MAAM,IAAI,QAAQ;AAClB,cAAM,SAAS,KAAK,CAAC;AACrB,cAAM,OACL,UAAU,QAAQ,OAAO,SAAS,IAC9B,OAAO,GAAG,EAAE,IACZ,IAAI,SAAS,CAAC;AACnB,YAAI,SAAS,OAAW;AACxB,cAAM,OAAQ,SAAS,SAAmC;AAC1D,cAAM,QAAS,KAAK,KAAK,KAAK,SAAgC,KAAK;AACnE,cAAM,OAAkB;AAAA,UACvB,OAAO,KAAK,SAAS,OAAO,SAAS,KAAK,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,UACpE;AAAA,QACD;AACA,iBAAS,KAAK,IAAI;AAAA,MACnB;AAAA,MACA,EAAE,cAAc,UAAU,MAAM,OAAO,mBAAmB,EAAE;AAAA,IAC7D;AACA,SAAK,gBAAY,yBAAU,OAAO,CAAC;AAgBnC,UAAM,WAAW,KAAK,YAAY,gBAAqB;AACvD,UAAM,aAA8B,MAAW,aAAa;AAC5D,SAAK,MAAM,eAAe,UAAU;AACpC,UAAM,WAAmC,aAAkB,aAAa,YAAY;AAAA,MACnF,MAAM;AAAA,IACP,CAAC;AACD,SAAK,MAAM,aAAa,QAAQ;AAQhC,UAAM,cAAc,KAAK,GAAG,UAAU,CAAC,SAAS;AAC/C,iBAAW,KAAK,MAAM;AACrB,YAAI,EAAE,CAAC,MAAM,mBAAM;AACnB,cAAM,QAAQ,EAAE,CAAC;AAIjB,iBAAS,KAAK;AACd,mBAAW,QAAQ,KAAK;AAAA,MACzB;AAAA,IACD,CAAC;AACD,SAAK,YAAY,WAAW;AAK5B,UAAM,kBAAc;AAAA,MACnB,CAAC,SAAS,WAAW,KAAK,KAAK,MAAM;AAAA,MACrC,CAAC,MAAM,IAAI,QAAQ;AAClB,cAAM,aAAa,KAAK,CAAC;AACzB,cAAM,cAAc,KAAK,CAAC;AAC1B,cAAM,SACJ,cAAc,QAAQ,WAAW,SAAS,IACvC,WAAW,GAAG,EAAE,IACf,IAAI,SAAS,CAAC,KAAoC,CAAC,MAAO,CAAC;AACjE,cAAM,QACJ,eAAe,QAAQ,YAAY,SAAS,IACzC,YAAY,GAAG,EAAE,IAChB,IAAI,SAAS,CAAC,KAA4B,WAAY;AAC5D,YAAI,MAAM,WAAW,EAAG;AACxB,YAAI,SAAS,cAAc,SAAS,SAAU;AAC9C,cAAM,SAAS,SAAS,WAAW,CAAC;AACpC,YAAI,OAAO,MAAM,WAAW,EAAG;AAC/B,cAAM,QAAQ,OAAO,MAAM,CAAC;AAC5B,cAAM,UAAU,SAAS,KAAK;AAC9B,iCAAM,MAAM;AASX,eAAK,KAAK,aAAa,KAAK,CAAC,CAAC,wBAAU,CAAC,CAAC;AAC1C,eAAK,KAAK,KAAK,KAAK,CAAC;AACrB,eAAK,KAAK,QAAQ,KAAK,KAAK;AAC5B,mBAAS,KAAK,SAAS;AACvB,eAAK,KAAK,KAAK,OAAO,QAAQ,OAAO;AACrC,eAAK,KAAK,OAAO,KAAK,UAAU;AAAA,QACjC,CAAC;AAAA,MACF;AAAA,MACA,EAAE,cAAc,UAAU,MAAM,OAAO,mBAAmB,EAAE;AAAA,IAC7D;AACA,SAAK,gBAAY,yBAAU,WAAW,CAAC;AAQvC,SAAK,gBAAY,yBAAU,KAAK,GAAG,CAAC;AAGpC,SAAK;AAAA,EACN;AACD;AAWA,SAAS,kBAA+C;AACvD,SAAO,CAAC,UAAU;AACjB,QAAI,OAAO,UAAU,UAAU;AAC9B,YAAM,IAAI;AAAA,QACT,6DAA6D,OAAO,KAAK;AAAA,MAC1E;AAAA,IACD;AACA,WAAO;AAAA,EACR;AACD;AAOA,SAAS,mBAA0D;AAClE,SAAO,CAAC,aAAa;AACtB;;;AW7mBA,IAAAC,gBAAiE;AACjE,IAAAC,iBAA8D;AAC9D,IAAAC,gBAAyC;;;ACZzC,IAAAC,gBAAmD;AACnD,IAAAC,iBAQO;;;ACHP,IAAAC,gBASO;AACP,IAAAC,gBAAiE;AASjE,IAAAA,iBAAwB;AAgIjB,SAAS,QAAW,QAAiB,IAAwB,MAA8B;AACjG,QAAM,YAAQ;AAAA,IACb,CAAC,MAAc;AAAA,IACf,CAAC,MAAM,aAAa;AACnB,YAAM,SAAS,KAAK,CAAC;AACrB,UAAI,UAAU,QAAQ,OAAO,SAAS,GAAG;AACxC,mBAAW,KAAK,OAAQ,IAAG,CAAM;AAAA,MAClC;AAAA,IACD;AAAA,IACA,EAAE,cAAc,UAAU,GAAG,KAAK;AAAA,EACnC;AACA,SAAO,MAAM,UAAU,MAAM;AAAA,EAAC,CAAC;AAChC;;;ADzJA,SAASC,YAAc,OAAkC;AACxD,SACC,OAAO,UAAU,YACjB,UAAU,QACV,WAAY,SACZ,OAAQ,MAAkB,cAAc;AAE1C;AAwBA,SAASC,WAAUC,QAAkB;AACpC,EAAAA,OAAK,UAAU,MAAM,MAAS;AAC/B;AAeA,SAAS,gBAAsB,UAA8C;AAC5E,MAAI,oBAAoB,IAAK,QAAO;AACpC,SAAO,oBAAI,IAAkB;AAC9B;AAEA,SAAS,gBACR,OACA,YACO;AACP,MAAI,CAAC,MAAM,QAAQ,WAAW,MAAM,GAAG;AACtC,UAAM,IAAI,UAAU,2DAA2D;AAAA,EAChF;AACA,2BAAM,MAAM;AACX,eAAW,EAAE,KAAK,MAAM,KAAK,WAAW,QAAQ;AAC/C,YAAM,IAAI,KAAK,KAAK;AAAA,IACrB;AACA,eAAW,OAAO,WAAW,UAAU,CAAC,GAAG;AAC1C,YAAM,OAAO,GAAG;AAAA,IACjB;AAAA,EACD,CAAC;AACF;AAYO,SAAS,QACf,QACA,WAIA,MACsB;AACtB,QAAM,iBAAa,wBAAQ,MAAM;AACjC,QAAM,YAAQ,4BAA0B,KAAK,cAAc,CAAC,CAAC;AAC7D,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,aAAa,KAAK,YAAY,UAAa,KAAK,YAAY;AAClE,QAAM,cAAc,iBAAa,wBAAQ,KAAK,OAAO,QAAI,oBAAc,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC;AAa5F,QAAM,uBAAmB;AAAA,IACxB,UAAU,YAAY,MAAM,OAA0C;AAAA,EACvE;AACA,UAAQ,kBAAkB,CAAC,eAAe;AACzC,oBAAgB,OAAO,UAAU;AAAA,EAClC,CAAC;AAED,MAAI,KAAK,OAAO;AAEf,UAAM,gBAAgB,oBAAI,IAAwB;AAElD,UAAM,mBAAe;AAAA,MACpB,CAAC,MAAM,OAAO;AAAA,MACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,SAAS,UAAU,CAAC;AAC1B,cAAM,WAAW,UAAU,QAAQ,OAAO,SAAS,IAAI,OAAO,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AACrF,cAAM,MAAgB,CAAC;AACvB,cAAM,UAAU,gBAAsB,QAAQ;AAE9C,mBAAW,OAAO,cAAc,KAAK,GAAG;AACvC,cAAI,CAAC,QAAQ,IAAI,GAAG,GAAG;AACtB,0BAAc,IAAI,GAAG,EAAG;AACxB,0BAAc,OAAO,GAAG;AAAA,UACzB;AAAA,QACD;AACA,mBAAW,CAAC,KAAK,GAAG,KAAK,SAAS;AACjC,gBAAM,UAAU,KAAK,MAAO,KAAK,GAAG;AACpC,cAAIF,YAAoB,OAAO,GAAG;AAMjC,gBAAI,CAAC,cAAc,IAAI,GAAG,GAAG;AAC5B,oBAAM,QAAQ,QAAQ,SAAS,CAAC,QAAQ;AACvC,oBAAI,QAAQ,QAAQ,MAAM,IAAI,GAAG,GAAG;AACnC,wBAAM,OAAO,GAAG;AAAA,gBACjB;AAAA,cACD,CAAC;AACD,4BAAc,IAAI,KAAK,KAAK;AAAA,YAC7B;AACA;AAAA,UACD;AACA,cAAI,OAAO,YAAY,WAAW;AACjC,gBAAI,QAAS,KAAI,KAAK,GAAG;AACzB;AAAA,UACD;AACA,gBAAM,IAAI,UAAU,sDAAsD;AAAA,QAC3E;AACA,gBAAQ,KAAK,GAAG;AAAA,MACjB;AAAA,MACA,EAAE,cAAc,UAAU;AAAA,IAC3B;AACA,YAAQ,cAAc,CAAC,SAAS;AAC/B,iBAAW,OAAO,KAAM,OAAM,OAAO,GAAG;AAAA,IACzC,CAAC;AAAA,EACF;AAEA,QAAM,wBACL,KAAK,uBAAuB,UAAa,KAAK,uBAAuB;AACtE,MAAI,KAAK,eAAe,uBAAuB;AAC9C,UAAM,6BAAyB,wBAAQ,KAAK,kBAAkB;AAC9D,UAAM,wBAAoB;AAAA,MACzB;AAAA,MACA,MAAM;AAAA,IACP;AACA,UAAM,0BAAsB;AAAA,MAAU;AAAA,MAAmB,CAAC,CAAC,EAAE,OAAO,MACnE,KAAK,YAAa,gBAAsB,OAAO,CAAC;AAAA,IACjD;AACA,YAAQ,qBAAqB,CAAC,eAAe;AAC5C,sBAAgB,OAAO,UAAU;AAAA,IAClC,CAAC;AAAA,EACF;AAEA,QAAM,cAAU;AAAA,IACf,CAAC,MAAM,SAAS,WAAW;AAAA,IAC3B,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACG,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,WAAW,KAAK,CAAC;AACvB,YAAM,UAAU,KAAK,CAAC;AACtB,YAAM,MAAM,gBAAsB,QAAQ;AAC1C,YAAM,UAAU,CAAC,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;AAAA,QACzD;AAAA,QACA;AAAA,QACA,OAAO,KAAK,MAAM,OAAO,OAAO;AAAA,QAChC,MAAM,KAAK,KAAK,KAAK;AAAA,MACtB,EAAE;AACF,cAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAExC,YAAM,SAA6D,CAAC;AACpE,UAAI,YAAY;AAChB,iBAAW,QAAQ,SAAS;AAC3B,YAAI,KAAK,QAAQ,WAAW;AAC3B,iBAAO,KAAK,EAAE,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO,OAAO,KAAK,MAAM,CAAC;AACnE,uBAAa,KAAK;AAAA,QACnB;AAAA,MACD;AACA,cAAQ,KAAK,MAAM;AAAA,IACpB;AAAA,IACA,EAAE,cAAc,WAAW,MAAM,EAAE,OAAG,0BAAW,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAC3E;AAEA,QAAM,WAAO;AAAA,IACZ,CAAC,MAAM,OAAO;AAAA,IACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,SAAS,UAAU,CAAC;AAC1B,YAAM,WAAW,UAAU,QAAQ,OAAO,SAAS,IAAI,OAAO,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AACrF,cAAQ,KAAK,gBAAsB,QAAQ,EAAE,IAAI;AAAA,IAClD;AAAA,IACA,EAAE,cAAc,UAAU;AAAA,EAC3B;AACA,EAAAF,WAAU,OAAO;AACjB,EAAAA,WAAU,IAAI;AAEd,SAAO,EAAE,OAAO,SAAS,KAAK;AAC/B;;;AEzNA,IAAAG,gBAA0D;AAE1D,IAAAC,iBAOO;AACP,IAAAC,gBAAyC;;;ACblC,IAAM,qBAAqB,KAAK,OAAO,IAAI;AAgB3C,SAAS,MACf,WACAC,aACA,eACA,WAAW,GACF;AACT,MAAI,CAAC,OAAO,SAAS,SAAS,EAAG,QAAO;AACxC,MAAI,CAAC,OAAO,SAASA,WAAU,KAAKA,eAAc,EAAG,QAAO,KAAK,IAAI,UAAU,SAAS;AACxF,MAAI,CAAC,OAAO,SAAS,aAAa,KAAK,iBAAiB,EAAG,QAAO,KAAK,IAAI,UAAU,SAAS;AAC9F,QAAM,UAAU,YAAY,KAAK,IAAI,CAAC,gBAAgBA,WAAU;AAChE,SAAO,KAAK,IAAI,UAAU,OAAO;AAClC;;;ACnBA,IAAAC,gBAAoE;AAEpE,IAAAC,iBAAkD;AAClD,IAAAC,gBAAsB;AActB,IAAMC,cAAa;AAEnB,SAAS,WAAW,MAAc,OAA0D;AAC3F,SAAO,WAAW,UAAU,MAAM,KAAK;AACxC;AAWA,SAAS,OAAU,GAAgB,MAAwB;AAC1D,MAAI,aAAa,uBAAU,QAAO;AAClC,aAAO,oBAAQ,CAAC,GAAG,EAAE,SAAS,GAAQ,GAAI,OAAO,EAAE,KAAK,IAAI,OAAW,CAAC;AACzE;AAEA,SAAS,WAAW,KAAa,QAAwB;AACxD,UAAQ,MAAM,UAAUA;AACzB;AAuBO,SAAS,iBAAiB,GAAsB,GAA8B;AACpF,QAAM,IAAI,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AACrC,MAAI,MAAM;AACV,MAAI,KAAK;AACT,MAAI,KAAK;AACT,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG;AAC9B,UAAM,KAAK,EAAE,CAAC,KAAK;AACnB,UAAM,KAAK,EAAE,CAAC,KAAK;AACnB,WAAO,KAAK;AACZ,UAAM,KAAK;AACX,UAAM,KAAK;AAAA,EACZ;AACA,MAAI,OAAO,KAAK,OAAO,EAAG,QAAO;AACjC,QAAM,QAAQ,MAAM,KAAK,KAAK,KAAK,EAAE;AACrC,SAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AACzC;AASA,SAAS,mBACR,GACA,GACU;AACV,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,GAAG;AACrC,UAAM,IAAI,EAAE,CAAC;AACb,UAAM,IAAI,EAAE,CAAC;AACb,QAAI,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,KAAM,QAAO;AAAA,EACvE;AACA,SAAO;AACR;AAsGA,SAAS,YACR,GACA,GACU;AACV,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,GAAG;AACrC,UAAM,IAAI,EAAE,CAAC;AACb,UAAM,IAAI,EAAE,CAAC;AAQb,QACC,EAAE,OAAO,EAAE,MACX,EAAE,UAAU,EAAE,SACd,EAAE,iBAAiB,EAAE,gBACrB,EAAE,UAAU,EAAE;AAEd,aAAO;AAAA,EACT;AACA,SAAO;AACR;AAkDO,SAAS,WAAc,MAAc,OAA6B,CAAC,GAAuB;AAChG,QAAM,UAAU,KAAK;AACrB,QAAM,SAAS,KAAK,UAAU;AAG9B,QAAM,YAAY,SAAU,KAAK,aAAa,IAAK;AACnD,QAAM,WAAW,KAAK,YAAY;AAClC,MAAI,YAAY,UAAa,UAAU,GAAG;AACzC,UAAM,IAAI,WAAW,kCAAkC;AAAA,EACxD;AAMA,QAAM,iBAAuC,MAAO,SAAS,IAAI;AACjE,QAAM,aAAa,KAAK,SAAS;AACjC,QAAM,YACL,UAAU,sBAAsB,yBAC5B,aACD;AACJ,QAAM,cAAc,MAA4B;AAC/C,QAAI,UAAW,QAAO,UAAU,SAAS;AACzC,WAAO;AAAA,EACR;AAEA,QAAM,QAAQ,IAAI,oBAAM,IAAI;AAK5B,QAAM,iBAAiB,CAAC,IAAY,MACnC,SACG,MAAM,EAAE,WAAW,eAAW,2BAAY,GAAG,EAAE,YAAY,GAAG,WAAW,QAAQ,IACjF,EAAE;AAEN,QAAM,YAAQ,4BAAwC;AAAA,IACrD,MAAM;AAAA,IACN,GAAI,YAAY,SAAY,EAAE,WAAW,EAAE,OAAO,gBAAgB,QAAQ,EAAE,IAAI,CAAC;AAAA,EAClF,CAAC;AAED,QAAM,IAAI,MAAM,SAAS,EAAE,MAAM,QAAQ,CAAC;AAK1C,MAAI;AACJ,MAAI,UAAU,YAAY,GAAG;AAC5B,UAAM,aAAa,KAAK,qBAAqB,KAAK,IAAI,GAAI,MAAO,KAAK,OAAQ,KAAK,UAAU;AAC7F,UAAM,kBAAc,0BAAU,YAAY,EAAE,QAAQ,WAAW,CAAC;AAchE,sBAAc;AAAA,MACb,CAAC,WAAW;AAAA,MACZ,CAAC,YAAY,YAAY;AACxB,gBAAQ,SAAK,2BAAY,CAAC;AAAA,MAC3B;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAS,2BAAY;AAAA,QACrB,MAAM,WAAW,OAAO;AAAA,MACzB;AAAA,IACD;AACA,UAAM,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAAA,EACnD;AAKA,MAAI;AACJ,MAAI,QAAQ;AACX,UAAM,aAA8B,CAAC,MAAM,OAAO;AAClD,QAAI,YAAa,YAAW,KAAK,WAAW;AAC5C,QAAI,UAAW,YAAW,KAAK,SAAS;AACxC,qBAAa;AAAA,MACZ;AAAA,MACA,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,SAAS,UAAU;AAAA,UAAI,CAACC,QAAO,MACpCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,WAAW,OAAO,CAAC;AACzB,YAAI;AACJ,YAAI,aAAa;AAChB,gBAAM,YAAY,OAAO,CAAC;AAC1B,gBAAM,OAAO,cAAc,WAAW,gBAAY,2BAAY;AAAA,QAC/D,OAAO;AACN,oBAAM,2BAAY;AAAA,QACnB;AACA,YAAI,CAAC,YAAY,SAAS,SAAS,GAAG;AACrC,kBAAQ,KAAK,CAAC,CAAwC;AACtD;AAAA,QACD;AACA,cAAMC,OAAkC,CAAC;AACzC,mBAAW,SAAS,SAAS,OAAO,GAAG;AACtC,UAAAA,KAAI,KAAK;AAAA,YACR,GAAG;AAAA,YACH,OAAO,MAAM,MAAM,WAAW,WAAW,KAAK,MAAM,YAAY,GAAG,WAAW,QAAQ;AAAA,UACvF,CAAC;AAAA,QACF;AACA,QAAAA,KAAI,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY;AACvE,gBAAQ,KAAKA,IAA0C;AAAA,MACxD;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,QAAQ;AAAA,QACR,MAAM,WAAW,QAAQ;AAAA,MAC1B;AAAA,IACD;AACA,UAAM,IAAI,YAAY,EAAE,MAAM,SAAS,CAAC;AAAA,EACzC,OAAO;AACN,qBAAa,oBAA0C,CAAC,GAAG;AAAA,MAC1D,SAAS,CAAC;AAAA,MACV,MAAM;AAAA,MACN,cAAc;AAAA,MACd,MAAM,WAAW,iBAAiB;AAAA,IACnC,CAAC;AACD,UAAM,IAAI,YAAY,EAAE,MAAM,SAAS,CAAC;AAAA,EACzC;AAEA,QAAM,WAAO;AAAA,IACZ,CAAC,MAAM,OAAO;AAAA,IACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACD,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,WAAW,KAAK,CAAC;AACvB,cAAQ,MAAO,YAAY,oBAAI,IAAI,GAA+C,IAAI;AAAA,IACvF;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS;AAAA,MACT,MAAM,WAAW,MAAM;AAAA,IACxB;AAAA,EACD;AACA,QAAM,IAAI,MAAM,EAAE,MAAM,OAAO,CAAC;AAGhC,QAAM,gBAAY,0BAAU,IAAI,CAAC;AAGjC,QAAM,SAAS,eAAsC;AAAA,IACpD,MAAM;AAAA,IACN,eAAe;AAAA,IACf;AAAA,EACD,CAAC;AACD,QAAM,YAAY,eAAe,OAAO,OAAO,CAAC;AAEhD,QAAM,aAAa,CAAC,IAAY,OAAU,UAAqC;AAC9E,UAAM,UAAM,2BAAY;AACxB,UAAM,OAAO,MAAM,IAAI,EAAE;AACzB,UAAM,YAAY,OAAO,SAAS,YAAY,EAAE,KAAK;AACrD,UAAM,IAAI,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,MAAM,eAAe;AAAA,MAClC,cAAc;AAAA,IACf,CAAC;AAAA,EACF;AACA,QAAM,aAAa,CAAC,OAAqB;AACxC,QAAI,CAAC,MAAM,IAAI,EAAE,EAAG;AACpB,UAAM,OAAO,EAAE;AAAA,EAChB;AACA,QAAM,YAAY,MAAY;AAC7B,QAAI,MAAM,SAAS,EAAG;AACtB,UAAM,MAAM;AAAA,EACb;AACA,QAAM,cAAc,MAAY;AAK/B,QAAI,CAAC,OAAQ;AACb,UAAM,KAAK,YAAY;AACvB,UAAM,WAAW,MAAM,QAAQ;AAC/B,QAAI,CAAC,YAAY,SAAS,SAAS,EAAG;AACtC,UAAM,UAA+C,CAAC;AACtD,eAAW,SAAS,SAAS,OAAO,GAAG;AACtC,cAAQ,KAAK,CAAC,MAAM,IAAI,EAAE,GAAG,OAAO,WAAW,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC;AAAA,IAClE;AACA,UAAM,QAAQ,OAAO;AAAA,EACtB;AAEA,QAAM,SAAS,OAAO,YAAY;AAAA,IACjC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,EAAE,GAAG,IAAI,OAAO,EAAE,QAAQ,UAAmB,IAAI,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC9F,CAAC;AACD,QAAM,SAAS,OAAO,YAAY;AAAA,IACjC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,EAAE,GAAG,IAAI,OAAO,EAAE,QAAQ,UAAmB,IAAI,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC9F,CAAC;AACD,QAAM,QAAQ,OAAO,WAAW;AAAA,IAC/B,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,OAAO,IAAI,OAAO,EAAE,QAAQ,SAAkB,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC1F,CAAC;AACD,QAAM,UAAU,OAAO,aAAa;AAAA,IACnC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,OAAO,IAAI,OAAO,EAAE,QAAQ,WAAoB,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC5F,CAAC;AAED,WAAS,SAAS,IAA+D;AAChF,UAAM,MAAM,OAAO,IAAI,IAAI;AAC3B,eAAO;AAAA,MACN,CAAC,MAAM,SAAS,GAAG;AAAA,MACnB,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,MAAM,KAAK,CAAC;AAClB,cAAM,MAAM,KAAK,CAAC;AAClB,gBAAQ,KAAK,KAAK,IAAI,GAAG,CAAC;AAAA,MAC3B;AAAA,MACA;AAAA,QACC,cAAc;AAAA,QACd,MAAM,WAAW,iBAAiB;AAAA,MACnC;AAAA,IACD;AAAA,EACD;AAEA,WAAS,QAAQ,IAAwC;AACxD,UAAM,MAAM,OAAO,IAAI,IAAI;AAC3B,eAAO;AAAA,MACN,CAAC,MAAM,SAAS,GAAG;AAAA,MACnB,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,MAAM,KAAK,CAAC;AAClB,cAAM,MAAM,KAAK,CAAC;AAClB,gBAAQ,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK;AAAA,MACpC;AAAA,MACA;AAAA,QACC,cAAc;AAAA,QACd,MAAM,WAAW,gBAAgB;AAAA,MAClC;AAAA,IACD;AAAA,EACD;AAEA,QAAM,MAAM,OAAO,OAAO,OAAO;AAAA,IAChC;AAAA,IACA,OAAO,MAAM;AAAA,IACb,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACD,SAAO;AACR;AAsGO,SAAS,YAAmB,OAAkC,CAAC,GAA4B;AACjG,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,YAAY,KAAK;AACvB,QAAM,kBAAkB,KAAK,mBAAmB;AAChD,QAAM,UAAU,KAAK;AACrB,QAAM,qBAAqB,KAAK;AAEhC,MAAI;AACJ,MAAI,YAAY,QAAQ;AACvB,WAAO,KAAK,cAAc;AAC1B,QAAI,CAAC,MAAM;AACV,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,QAAM,QAAQ,IAAI,oBAAM,KAAK,QAAQ,cAAc;AAInD,MAAI;AACJ,WAAS,gBAAgB,QAAiC;AACzD,QAAI,cAAc,QAAW;AAC5B,UAAI,OAAO,WAAW,WAAW;AAChC,cAAM,IAAI;AAAA,UACT,uCAAuC,SAAS,SAAS,OAAO,MAAM;AAAA,QACvE;AAAA,MACD;AACA;AAAA,IACD;AACA,QAAI,CAAC,gBAAiB;AACtB,QAAI,sBAAsB,QAAW;AACpC,0BAAoB,OAAO;AAC3B;AAAA,IACD;AACA,QAAI,OAAO,WAAW,mBAAmB;AACxC,YAAM,IAAI;AAAA,QACT,uCAAuC,iBAAiB,2BAA2B,OAAO,MAAM;AAAA,MAEjG;AAAA,IACD;AAAA,EACD;AAEA,QAAM,qBAAqB,uBAAuB,CAAC,MAA2B,EAAE;AAMhF,MAAI,kBAAkB;AAKtB,QAAM,SAAS,eAAuC;AAAA,IACrD,MAAM;AAAA,IACN,eAAe;AAAA,IACf;AAAA,EACD,CAAC;AACD,QAAM,YAAY,eAAe,OAAO,OAAO,CAAC;AAEhD,QAAM,cAAU,4BAAyC;AAAA,IACxD,MAAM;AAAA,IACN,GAAI,YAAY,SACb;AAAA,MACA,WAAW;AAAA,QACV,OAAO,CAAC,IAAI,MAAM,mBAAmB,CAAC;AAAA,QACtC;AAAA,QACA,WAAW,CAAC,QAAQ;AACnB,cAAI,gBAAiB;AACrB,cAAI,YAAY,OAAQ,MAAM,OAAO,GAAG;AAMxC,iBAAO,OAAO;AAAA,YACb,QAAQ;AAAA,YACR,IAAI;AAAA,YACJ,UAAM,2BAAY;AAAA,YAClB,KAAK,WAAW,SAAS;AAAA,UAC1B,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD,IACC,CAAC;AAAA,EACL,CAAC;AACD,QAAM,IAAI,QAAQ,SAAS,EAAE,MAAM,UAAU,CAAC;AAM9C,QAAM,gBAAY,0BAAU,QAAQ,OAAO,CAAC;AAM5C,MAAI,MAAM,SAAS;AAClB,UAAM,iBAAiB,KAAK,QAAQ,KAAK,IAAI;AAC7C,UAAM,YAAY,MAAM,eAAe,CAAC;AAAA,EACzC;AAEA,QAAM,aAAa,CAAC,IAAY,QAA2B,SAAuB;AACjF,oBAAgB,MAAM;AAMtB,QAAI,YAAY,OAAQ,MAAM,OAAO,IAAI,QAAQ,IAAI;AAMrD,UAAM,cAAiC,MAAM;AAC5C,UAAI,SAAS,OAAW,QAAO;AAC/B,UAAI,SAAS,QAAQ,OAAO,SAAS,SAAU,QAAO;AACtD,aAAO,MAAM,QAAQ,IAAI,IAAK,CAAC,GAAG,IAAI,IAA0B,EAAE,GAAG,KAAK;AAAA,IAC3E,GAAG;AACH,UAAM,SAA8B;AAAA,MACnC;AAAA,MACA,QAAQ,CAAC,GAAG,MAAM;AAAA,MAClB,GAAI,eAAe,SAAY,EAAE,MAAM,WAAW,IAAI,CAAC;AAAA,MACvD,kBAAc,2BAAY;AAAA,IAC3B;AACA,YAAQ,IAAI,IAAI,MAAM;AAAA,EACvB;AACA,QAAM,aAAa,CAAC,OAAqB;AACxC,QAAI,CAAC,QAAQ,IAAI,EAAE,EAAG;AAEtB,QAAI,YAAY,OAAQ,MAAM,OAAO,EAAE;AACvC,YAAQ,OAAO,EAAE;AAAA,EAClB;AACA,QAAM,YAAY,MAAY;AAC7B,QAAI,QAAQ,SAAS,EAAG;AAOxB,sBAAkB;AAClB,QAAI;AACH,cAAQ,MAAM;AACd,UAAI,YAAY,OAAQ,MAAM,MAAM;AAAA,IACrC,UAAE;AACD,wBAAkB;AAAA,IACnB;AACA,wBAAoB;AAAA,EACrB;AACA,QAAM,cAAc,MAAY;AAC/B,QAAI,YAAY,OAAQ;AACxB,UAAM,WAAW,QAAQ,QAAQ;AACjC,QAAI,CAAC,SAAU;AACf,SAAM,MAAM;AACZ,eAAW,KAAK,SAAS,OAAO,GAAG;AAClC,WAAM,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI;AAAA,IACpC;AAAA,EACD;AAKA,QAAM,SAAS,OAAO,YAAY;AAAA,IACjC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,EAAE,GAAG,IAAI,OAAO,EAAE,QAAQ,UAAmB,IAAI,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC9F,CAAC;AACD,QAAM,SAAS,OAAO,YAAY;AAAA,IACjC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,EAAE,GAAG,IAAI,OAAO,EAAE,QAAQ,UAAmB,IAAI,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC9F,CAAC;AACD,QAAM,QAAQ,OAAO,WAAW;AAAA,IAC/B,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,OAAO,IAAI,OAAO,EAAE,QAAQ,SAAkB,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC1F,CAAC;AACD,QAAM,UAAU,OAAO,aAAa;AAAA,IACnC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,OAAO,IAAI,OAAO,EAAE,QAAQ,WAAoB,MAAM,EAAE,MAAM,KAAK,EAAE,IAAI;AAAA,EAC5F,CAAC;AAED,WAAS,WACR,OACA,IAAyB,GACoB;AAC7C,UAAM,KAAK,OAAe,GAAG,GAAG;AAChC,eAAO;AAAA,MACN,CAAC,QAAQ,SAAS,OAAO,EAAE;AAAA,MAC3B,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,SAAS,UAAU;AAAA,UAAI,CAACA,QAAO,MACpCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAM,WAAW,OAAO,CAAC;AACzB,cAAM,IAAI,OAAO,CAAC;AAClB,cAAM,OAAO,OAAO,CAAC;AAIrB,cAAM,OAAO,OAAO,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,IAAI;AACrE,YAAI,CAAC,YAAY,SAAS,SAAS,KAAK,QAAQ,GAAG;AAClD,kBAAQ,KAAK,CAAC,CAAyC;AACvD;AAAA,QACD;AAQA,YAAI,KAAK,QAAQ,EAAE,WAAW,GAAG;AAChC,kBAAQ,KAAK,CAAC,CAAyC;AACvD;AAAA,QACD;AACA,cAAM,cAAc,cAAc,kBAAkB,oBAAoB;AACxE,YAAI,gBAAgB,UAAa,EAAE,WAAW,aAAa;AAC1D,kBAAQ,KAAK,CAAC,CAAyC;AACvD;AAAA,QACD;AACA,YAAI,YAAY,QAAQ;AAIvB,gBAAM,iBAAiB,KAAM,OAAO,GAAG,IAAI;AAC3C,kBAAQ,KAAK,CAAC,GAAG,cAAc,CAAyC;AACxE;AAAA,QACD;AACA,cAAM,SAAS,CAAC,GAAG,SAAS,OAAO,CAAC,EAClC,IAAI,CAAC,QAAQ;AACb,gBAAM,SAAoC;AAAA,YACzC,IAAI,IAAI;AAAA,YACR,OAAO,iBAAiB,GAAG,IAAI,MAAM;AAAA,YACrC,GAAI,IAAI,SAAS,SAAY,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAAA,UACpD;AACA,iBAAO;AAAA,QACR,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,IAAI;AACf,gBAAQ,KAAK,MAA8C;AAAA,MAC5D;AAAA,MACA;AAAA,QACC,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,QAKd,QAAQ,CAAC,GAAG,MAAM,mBAAmB,GAAG,CAAC;AAAA,QACzC,MAAM,WAAW,eAAe;AAAA,MACjC;AAAA,IACD;AAAA,EACD;AAEA,QAAM,MAAM,OAAO,OAAO,OAAO;AAAA,IAChC;AAAA,IACA;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACD,SAAO;AACR;AAoDA,IAAM,aAAa;AACnB,SAAS,UAAU,MAAc,IAAY,UAA0B;AACtE,SAAO,GAAG,IAAI,GAAG,UAAU,GAAG,EAAE,GAAG,UAAU,GAAG,QAAQ;AACzD;AAEA,SAAS,eACR,OACA,MAC2D;AAC3D,MAAI,CAAC,SAAS,MAAM,SAAS,EAAG,QAAO,oBAAI,IAAI;AAC/C,QAAM,UAAU,oBAAI,IAAwC;AAC5D,aAAW,QAAQ,MAAM,OAAO,GAAG;AAClC,UAAM,MAAM,SAAS,SAAS,KAAK,OAAO,KAAK;AAC/C,QAAI,SAAS,QAAQ,IAAI,GAAG;AAC5B,QAAI,CAAC,QAAQ;AACZ,eAAS,CAAC;AACV,cAAQ,IAAI,KAAK,MAAM;AAAA,IACxB;AACA,WAAO,KAAK,IAAI;AAAA,EACjB;AACA,QAAM,MAAM,oBAAI,IAAiD;AACjE,aAAW,CAAC,KAAK,MAAM,KAAK,QAAS,KAAI,IAAI,KAAK,OAAO,OAAO,MAAM,CAAC;AACvE,SAAO;AACR;AAEA,SAAS,eACR,GACA,GACU;AACV,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,aAAW,CAAC,GAAG,EAAE,KAAK,GAAG;AACxB,UAAM,KAAK,EAAE,IAAI,CAAC;AAClB,QAAI,CAAC,MAAM,GAAG,WAAW,GAAG,OAAQ,QAAO;AAC3C,aAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK,GAAG;AACtC,YAAM,KAAK,GAAG,CAAC;AACf,YAAM,KAAK,GAAG,CAAC;AACf,UACC,GAAG,SAAS,GAAG,QACf,GAAG,OAAO,GAAG,MACb,GAAG,aAAa,GAAG,YACnB,GAAG,WAAW,GAAG;AAEjB,eAAO;AAAA,IACT;AAAA,EACD;AACA,SAAO;AACR;AAkCO,SAAS,eACf,MACA,OAA8B,CAAC,GACM;AACrC,QAAM,WAAW,KAAK,YAAY;AAClC,MAAI,KAAK,oBAAoB,UAAa,KAAK,kBAAkB,GAAG;AACnE,UAAM,IAAI,WAAW,8CAA8C;AAAA,EACpE;AACA,MAAI,KAAK,iBAAiB,UAAa,KAAK,eAAe,GAAG;AAC7D,UAAM,IAAI,WAAW,2CAA2C;AAAA,EACjE;AAEA,QAAM,QAAQ,IAAI,oBAAM,IAAI;AAE5B,QAAM,kBAAc,4BAA6B;AAAA,IAChD,MAAM;AAAA,IACN,GAAI,KAAK,oBAAoB,SAAY,EAAE,SAAS,KAAK,gBAAgB,IAAI,CAAC;AAAA,EAC/E,CAAC;AACD,QAAM,eAAW,4BAA8C;AAAA,IAC9D,MAAM;AAAA,IACN,GAAI,KAAK,iBAAiB,SAAY,EAAE,SAAS,KAAK,aAAa,IAAI,CAAC;AAAA,EACzE,CAAC;AACD,QAAM,IAAI,YAAY,SAAS,EAAE,MAAM,WAAW,CAAC;AACnD,QAAM,IAAI,SAAS,SAAS,EAAE,MAAM,QAAQ,CAAC;AAE7C,QAAM,mBAAe;AAAA,IACpB,CAAC,SAAS,OAAO;AAAA,IACjB,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,WAAW,KAAK,CAAC;AACvB,cAAQ,KAAK,eAA0B,UAAU,MAAM,CAAC;AAAA,IACzD;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS,oBAAI,IAAI;AAAA,MACjB,QAAQ;AAAA,MACR,MAAM,WAAW,eAAe;AAAA,IACjC;AAAA,EACD;AACA,QAAM,kBAAc;AAAA,IACnB,CAAC,SAAS,OAAO;AAAA,IACjB,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,WAAW,KAAK,CAAC;AACvB,cAAQ,KAAK,eAA0B,UAAU,IAAI,CAAC;AAAA,IACvD;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS,oBAAI,IAAI;AAAA,MACjB,QAAQ;AAAA,MACR,MAAM,WAAW,cAAc;AAAA,IAChC;AAAA,EACD;AACA,QAAM,IAAI,cAAc,EAAE,MAAM,eAAe,CAAC;AAChD,QAAM,IAAI,aAAa,EAAE,MAAM,cAAc,CAAC;AAC9C,QAAM,gBAAY,0BAAU,YAAY,CAAC;AACzC,QAAM,gBAAY,0BAAU,WAAW,CAAC;AAExC,QAAM,kBAAc;AAAA,IACnB,CAAC,YAAY,OAAO;AAAA,IACpB,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,IAAI,KAAK,CAAC;AAChB,cAAQ,MAAO,KAAK,oBAAI,IAAI,GAAoC,IAAI;AAAA,IACrE;AAAA,IACA,EAAE,MAAM,eAAe,cAAc,WAAW,SAAS,GAAG,MAAM,WAAW,cAAc,EAAE;AAAA,EAC9F;AACA,QAAM,gBAAY;AAAA,IACjB,CAAC,SAAS,OAAO;AAAA,IACjB,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACA,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,IAAI,KAAK,CAAC;AAChB,cAAQ,MAAO,KAAK,oBAAI,IAAI,GAAqD,IAAI;AAAA,IACtF;AAAA,IACA,EAAE,MAAM,aAAa,cAAc,WAAW,SAAS,GAAG,MAAM,WAAW,YAAY,EAAE;AAAA,EAC1F;AACA,QAAM,IAAI,aAAa,EAAE,MAAM,cAAc,CAAC;AAC9C,QAAM,IAAI,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1C,QAAM,gBAAY,0BAAU,WAAW,CAAC;AACxC,QAAM,gBAAY,0BAAU,SAAS,CAAC;AAEtC,QAAM,SAAS,eAA0C;AAAA,IACxD,MAAM;AAAA,IACN,eAAe;AAAA,IACf;AAAA,EACD,CAAC;AACD,QAAM,YAAY,eAAe,OAAO,OAAO,CAAC;AAchD,WAAS,oBAAoB,IAAqB;AACjD,UAAMC,OAAM,aAAa;AAGzB,UAAM,MAAM,YAAY;AAGxB,SAAKA,MAAK,IAAI,EAAE,GAAG,UAAU,KAAK,EAAG,QAAO;AAC5C,SAAK,KAAK,IAAI,EAAE,GAAG,UAAU,KAAK,EAAG,QAAO;AAC5C,WAAO;AAAA,EACR;AAUA,WAAS,cAAc,YAAqC;AAC3D,QAAI,aAAa,SAAU;AAC3B,eAAW,aAAa,YAAY;AACnC,UAAI,CAAC,YAAY,IAAI,SAAS,EAAG;AACjC,UAAI,oBAAoB,SAAS,EAAG;AACpC,kBAAY,OAAO,SAAS;AAC5B,aAAO,OAAO;AAAA,QACb,QAAQ;AAAA,QACR,IAAI;AAAA,QACJ,UAAM,2BAAY;AAAA,QAClB,KAAK,WAAW,SAAS;AAAA,MAC1B,CAAC;AAAA,IACF;AAAA,EACD;AAEA,QAAM,mBAAmB,CAAC,IAAY,UAAyB;AAC9D,gBAAY,IAAI,IAAI,KAAK;AAAA,EAC1B;AACA,QAAM,mBAAmB,CAAC,OAAqB;AAC9C,UAAM,WAAW,SAAS,QAAQ;AAQlC,UAAM,oBAAoB,oBAAI,IAAY;AAC1C,QAAI,UAAU;AACb,YAAM,SAAmB,CAAC;AAC1B,iBAAW,CAAC,KAAK,IAAI,KAAK,UAAU;AACnC,YAAI,KAAK,SAAS,MAAM,KAAK,OAAO,IAAI;AACvC,iBAAO,KAAK,GAAG;AACf,cAAI,KAAK,SAAS,GAAI,mBAAkB,IAAI,KAAK,IAAI;AACrD,cAAI,KAAK,OAAO,GAAI,mBAAkB,IAAI,KAAK,EAAE;AAAA,QAClD;AAAA,MACD;AACA,UAAI,OAAO,SAAS,EAAG,UAAS,WAAW,MAAM;AAAA,IAClD;AACA,QAAI,YAAY,IAAI,EAAE,EAAG,aAAY,OAAO,EAAE;AAC9C,kBAAc,CAAC,GAAG,iBAAiB,CAAC;AAAA,EACrC;AACA,QAAM,WAAW,CAAC,MAAc,IAAY,UAAqB,SAAS,MAAY;AACrF,aAAS,IAAI,UAAU,MAAM,IAAI,QAAQ,GAAG,EAAE,MAAM,IAAI,UAAU,OAAO,CAAC;AAAA,EAC3E;AACA,QAAM,aAAa,CAAC,MAAc,IAAY,aAA+B;AAC5E,QAAI,aAAa,QAAW;AAC3B,eAAS,OAAO,UAAU,MAAM,IAAI,QAAQ,CAAC;AAAA,IAC9C,OAAO;AACN,YAAM,WAAW,SAAS,QAAQ;AAGlC,UAAI,CAAC,SAAU;AACf,YAAM,SAAmB,CAAC;AAC1B,iBAAW,CAAC,KAAK,IAAI,KAAK,UAAU;AACnC,YAAI,KAAK,SAAS,QAAQ,KAAK,OAAO,GAAI,QAAO,KAAK,GAAG;AAAA,MAC1D;AACA,UAAI,OAAO,SAAS,EAAG,UAAS,WAAW,MAAM;AAAA,IAClD;AACA,kBAAc,CAAC,MAAM,EAAE,CAAC;AAAA,EACzB;AAEA,QAAM,eAAe,OAAO,kBAAkB;AAAA,IAC7C,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,EAAE,GAAG,IAAI,OAAO;AAAA,MAClC,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,EAAE;AAAA,MACR,KAAK,EAAE;AAAA,IACR;AAAA,EACD,CAAC;AACD,QAAM,eAAe,OAAO,kBAAkB;AAAA,IAC7C,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,EAAE,GAAG,IAAI,OAAO;AAAA,MAClC,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,EAAE;AAAA,MACR,KAAK,EAAE;AAAA,IACR;AAAA,EACD,CAAC;AACD,QAAM,OAAO,OAAO,UAAU;AAAA,IAC7B,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,MAAM,IAAI,UAAU,MAAM,GAAG,IAAI,OAAO;AAAA,MAC1D,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,UAAU;AAAA,MAClB,MAAM,EAAE;AAAA,MACR,KAAK,EAAE;AAAA,IACR;AAAA,EACD,CAAC;AACD,QAAM,SAAS,OAAO,YAAY;AAAA,IACjC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,KAAK;AAAA,IACL,iBAAiB,CAAC,CAAC,MAAM,IAAI,QAAQ,GAAG,IAAI,OAAO;AAAA,MAClD,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,GAAI,aAAa,SAAY,EAAE,SAA6B,IAAI,CAAC;AAAA,MACjE,MAAM,EAAE;AAAA,MACR,KAAK,EAAE;AAAA,IACR;AAAA,EACD,CAAC;AAED,WAAS,YACR,IACA,UAC4C;AAC5C,UAAM,MAAM,OAAO,IAAI,IAAI;AAM3B,UAAM,OAAO,aAAa,SAAY,OAAO,UAAU,UAAU,IAAI;AACrE,UAAM,OAAwB,OAC3B,CAAC,cAAc,aAAa,KAAK,IAAI,IACrC,CAAC,cAAc,aAAa,GAAG;AAClC,eAAO;AAAA,MACN;AAAA,MACA,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,SAAS,UAAU;AAAA,UAAI,CAACD,QAAO,MACpCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QAClE;AACA,cAAMC,OAAM,OAAO,CAAC;AACpB,cAAM,MAAM,OAAO,CAAC;AACpB,cAAM,MAAM,OAAO,CAAC;AACpB,cAAM,MAAM,OAAQ,OAAO,CAAC,IAA8B;AAC1D,cAAM,OAAOA,MAAK,IAAI,GAAG,KAAK,CAAC;AAC/B,cAAM,MAAM,KAAK,IAAI,GAAG,KAAK,CAAC;AAE9B,cAAM,OAAO,oBAAI,IAAY;AAC7B,cAAM,MAAkC,CAAC;AACzC,mBAAW,QAAQ,MAAM;AACxB,gBAAM,IAAI,UAAU,KAAK,MAAM,KAAK,IAAI,KAAK,QAAQ;AACrD,cAAI,KAAK,IAAI,CAAC,EAAG;AACjB,cAAI,QAAQ,UAAa,KAAK,aAAa,IAAK;AAChD,eAAK,IAAI,CAAC;AACV,cAAI,KAAK,IAAI;AAAA,QACd;AACA,mBAAW,QAAQ,KAAK;AACvB,gBAAM,IAAI,UAAU,KAAK,MAAM,KAAK,IAAI,KAAK,QAAQ;AACrD,cAAI,KAAK,IAAI,CAAC,EAAG;AACjB,cAAI,QAAQ,UAAa,KAAK,aAAa,IAAK;AAChD,eAAK,IAAI,CAAC;AACV,cAAI,KAAK,IAAI;AAAA,QACd;AACA,gBAAQ,KAAK,GAA0C;AAAA,MACxD;AAAA,MACA;AAAA,QACC,cAAc;AAAA,QACd,QAAQ,CAAC,GAAG,MAAM;AACjB,gBAAM,KAAK;AACX,gBAAM,KAAK;AACX,cAAI,OAAO,GAAI,QAAO;AACtB,cAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AACrC,cAAI,GAAG,WAAW,GAAG,OAAQ,QAAO;AACpC,mBAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK,GAAG;AACtC,kBAAM,IAAI,GAAG,CAAC;AACd,kBAAM,IAAI,GAAG,CAAC;AACd,gBACC,EAAE,SAAS,EAAE,QACb,EAAE,OAAO,EAAE,MACX,EAAE,aAAa,EAAE,YACjB,EAAE,WAAW,EAAE;AAEf,qBAAO;AAAA,UACT;AACA,iBAAO;AAAA,QACR;AAAA,QACA,MAAM,WAAW,SAAS;AAAA,MAC3B;AAAA,IACD;AAAA,EACD;AAEA,QAAM,MAAM,OAAO,OAAO,OAAO;AAAA,IAChC;AAAA,IACA,UAAU,YAAY;AAAA,IACtB,OAAO,SAAS;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACD,SAAO;AACR;;;AFnyCO,IAAM,yBAAN,cAA2C,oBAAM;AAAA,EAC9C;AAAA,EAET,YAAY,MAAsC;AACjD,UAAM,KAAK,QAAQ,kBAAkB,KAAK,KAAK;AAC/C,SAAK,UAAU,YAAkB,EAAE,WAAW,KAAK,UAAU,CAAC;AAC9D,SAAK,MAAM,eAAe,KAAK,OAAO;AAEtC,UAAM,UAAU,KAAK;AACrB,UAAM,aAAa,KAAK;AAMxB,UAAM,cAAU;AAAA,MACf,CAAC,KAAK,MAAM,MAAM,OAAO;AAAA,MACzB,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,cAAM,WACJ,KAAK,CAAC,KAA+C,oBAAI,IAAkB;AAC7E,mBAAW,CAAC,KAAK,GAAG,KAAK,UAAU;AAClC,gBAAM,MAAM,QAAQ,GAAG;AACvB,cAAI,IAAK,YAAW,OAAO,KAAK,KAAK,GAAG;AAAA,QACzC;AAAA,MACD;AAAA,MACA,EAAE,MAAM,WAAW,cAAc,SAAS;AAAA,IAC3C;AACA,SAAK,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,SAAK,gBAAY,0BAAU,OAAO,CAAC;AAAA,EACpC;AACD;AAUO,SAAS,kBACf,MAC+B;AAC/B,SAAO,IAAI,uBAA6B,IAAI;AAC7C;AA2CO,IAAM,oBAAN,cAAsC,oBAAM;AAAA,EACzC;AAAA,EAET,YAAY,MAAiC;AAC5C,UAAM,OAAO,KAAK,QAAQ;AAC1B,UAAM,MAAM,KAAK,KAAK;AACtB,UAAM,SAAS,KAAK,UAAU,GAAG,IAAI;AACrC,UAAM,YAAY,KAAK,aAAa;AACpC,SAAK,KAAK,eAAgC,MAAM;AAChD,SAAK,MAAM,WAAW,KAAK,EAAE;AAE7B,QAAI,CAAC,KAAK,SAAU;AACpB,UAAM,WAAW,KAAK;AACtB,UAAM,QAAQ,KAAK;AACnB,UAAM,cAAU;AAAA,MACf,CAAC,KAAK,MAAM,MAAM,OAAO;AAAA,MACzB,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,cAAM,WACJ,KAAK,CAAC,KAA+C,oBAAI,IAAkB;AAC7E,mBAAW,CAAC,KAAK,GAAG,KAAK,UAAU;AAClC,gBAAM,YAAY,SAAS,KAAK,GAAG;AACnC,cAAI,CAAC,UAAW;AAChB,qBAAW,OAAO,UAAU,YAAY,CAAC,GAAG;AAC3C,kBAAM,aAAa,IAAI,IAAI,IAAI,KAAK;AAAA,UACrC;AACA,qBAAW,OAAO,UAAU,aAAa,CAAC,GAAG;AAC5C,kBAAM,KAAK,IAAI,MAAM,IAAI,IAAI,IAAI,UAAU,IAAI,MAAM;AAAA,UACtD;AAAA,QACD;AAAA,MACD;AAAA,MACA,EAAE,MAAM,WAAW,cAAc,SAAS;AAAA,IAC3C;AACA,SAAK,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,SAAK,gBAAY,0BAAU,OAAO,CAAC;AAAA,EACpC;AACD;AAMO,SAAS,aAAmB,MAA0D;AAC5F,SAAO,IAAI,kBAAwB,IAAI;AACxC;AAiDO,IAAM,uBAAN,cAA+C,oBAAM;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAA0C;AACrD,UAAM,KAAK,QAAQ,gBAAgB,KAAK,KAAK;AAE7C,UAAM,YAAY,KAAK,aAAa;AACpC,UAAM,YAAY,KAAK,aAAa;AACpC,UAAM,mBAAmB,KAAK,oBAAoB;AAClD,UAAM,kBAAkB,KAAK,oBAAoB,MAAM;AAKvD,SAAK,YAAY,WAAiB,aAAa,EAAE,QAAQ,MAAM,CAAC;AAChE,SAAK,MAAM,aAAa,KAAK,SAAS;AAMtC,SAAK,oBAAgB,4BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACxE,SAAK,IAAI,KAAK,cAAc,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC9D,SAAK,uBAAmB,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAChF,SAAK,IAAI,KAAK,iBAAiB,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAYpE,QAAI;AACJ,QAAI,KAAK,SAAS;AACjB,wBAAc,wBAAQ,KAAK,OAAO;AAAA,IACnC,OAAO;AACN,wBAAc,oBAAc,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC;AACjD,WAAK,IAAI,aAAa,EAAE,MAAM,UAAU,CAAC;AAAA,IAC1C;AACA,QAAI,YAAqB,YAAY;AACrC,UAAM,WAAW,YAAY,UAAU,CAAC,SAAS;AAChD,iBAAW,KAAK,KAAM,KAAI,EAAE,CAAC,MAAM,mBAAM,aAAY,EAAE,CAAC;AAAA,IACzD,CAAC;AACD,SAAK,YAAY,QAAQ;AAEzB,UAAM,mBAAmB,KAAK;AAC9B,UAAM,sBAAsB,KAAK;AACjC,UAAM,QAAQ,KAAK;AAYnB,UAAM,YAAgD;AAAA,MACrD,OAAO,CAAC,KAAK,UAAU;AACtB,YAAI,gBAAgB,KAAK,KAAK,EAAG,QAAO,OAAO;AAC/C,YAAI,iBAAiB,IAAI,GAAG,EAAG,QAAO,OAAO;AAC7C,cAAM,YAAQ,2BAAY;AAC1B,cAAM,YAAY,oBAAoB,IAAI,GAAG,KAAK;AAClD,cAAMC,cAAa,OAAO,QAAQ,SAAS,IAAI;AAC/C,eAAO,MAAM,MAAM,OAAO,SAAS,GAAGA,aAAY,SAAS;AAAA,MAC5D;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACV;AAGA,SAAK,QAAQ,QAAoB,KAAK,QAAQ,KAAK,WAAW;AAAA,MAC7D,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,MAC3D,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,MACxD,GAAI,KAAK,gBAAgB,SAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,MAC1E,GAAI,KAAK,uBAAuB,SAC7B,EAAE,oBAAoB,KAAK,mBAAmB,IAC9C,CAAC;AAAA,MACJ,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;AAAA,MAC9D,YAAY,EAAE,UAAU;AAAA,IACzB,CAAC;AAKD,SAAK,IAAI,KAAK,MAAM,MAAM,SAAS,EAAE,MAAM,QAAQ,CAAC;AACpD,SAAK,UAAU,KAAK,MAAM;AAC1B,SAAK,IAAI,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,SAAK,OAAO,KAAK,MAAM;AACvB,SAAK,IAAI,KAAK,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpC,UAAM,WAAW,KAAK;AACtB,UAAM,SAAS,CAAC,QAA4B;AAC3C,UAAI,iBAAiB,IAAI,GAAG,EAAG,QAAO;AACtC,YAAM,IACJ,SAAS,MAAM,QAAQ,SACxB,oBAAI,IAAkB;AACvB,UAAI,EAAE,IAAI,GAAG,EAAG,QAAO;AACvB,aAAO;AAAA,IACR;AACA,UAAM,eAAe,KAAK;AAC1B,UAAM,gBAAgB,CAAC,KAAa,UAAsB;AACzD,uBAAiB,IAAI,KAAK,IAAI;AAC9B,mBAAa,OAAO,KAAK,KAAK;AAAA,IAC/B;AAOA,UAAM,oBAAgB;AAAA,MACrB,CAAC,KAAK,MAAM,MAAM,OAAO;AAAA,MACzB,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,cAAM,MAAO,KAAK,CAAC,KAA+C,oBAAI,IAAkB;AACxF,cAAM,YAAQ,2BAAY;AAC1B,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,IAAI,KAAK,GAAG;AAC7B,cAAI,CAAC,oBAAoB,IAAI,GAAG,EAAG,OAAM,KAAK,GAAG;AAAA,QAClD;AACA,YAAI,MAAM,SAAS,GAAG;AACrB,mCAAM,MAAM;AACX,uBAAW,OAAO,MAAO,qBAAoB,IAAI,KAAK,KAAK;AAAA,UAC5D,CAAC;AAAA,QACF;AAAA,MACD;AAAA,MACA,EAAE,MAAM,yBAAyB,cAAc,SAAS;AAAA,IACzD;AACA,SAAK,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,SAAK,gBAAY,0BAAU,aAAa,CAAC;AAKzC,UAAM,eAAe,KAAK,MAAM,MAAM,QAAQ,UAAU,CAAC,SAAS;AACjE,iBAAW,KAAK,MAAM;AACrB,YAAI,EAAE,CAAC,MAAM,mBAAM;AACnB,cAAM,MAAM,EAAE,CAAC;AACf,cAAM,UAAU,oBAAoB,QAAQ;AAG5C,YAAI,WAAW,KAAM;AACrB,cAAM,WAAqB,CAAC;AAC5B,mBAAW,OAAO,QAAQ,KAAK,GAAG;AACjC,cAAI,CAAC,IAAI,IAAI,GAAG,EAAG,UAAS,KAAK,GAAG;AAAA,QACrC;AACA,YAAI,SAAS,SAAS,GAAG;AACxB,mCAAM,MAAM;AACX,uBAAW,OAAO,SAAU,qBAAoB,OAAO,GAAG;AAAA,UAC3D,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD,CAAC;AACD,SAAK,YAAY,YAAY;AAK7B,UAAM,eAAW;AAAA,MAChB,CAAC,KAAK,MAAM,MAAM,OAAO;AAAA,MACzB,CAAC,WAAW,UAAU,QAAQ;AAC7B,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,cAAM,MAAO,KAAK,CAAC,KAA+C,oBAAI,IAAkB;AACxF,mBAAW,CAAC,KAAK,GAAG,KAAK,KAAK;AAC7B,cAAI,iBAAiB,IAAI,GAAG,EAAG;AAC/B,cAAI,gBAAgB,KAAK,GAAG,GAAG;AAC9B,qCAAM,MAAM;AACX,4BAAc,KAAK,GAAG;AAAA,YACvB,CAAC;AAAA,UACF;AAAA,QACD;AAAA,MACD;AAAA,MACA,EAAE,MAAM,YAAY,cAAc,SAAS;AAAA,IAC5C;AACA,SAAK,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,SAAK,gBAAY,0BAAU,QAAQ,CAAC;AAEpC,QAAI,gBAAsC;AAC1C,QAAI,KAAK,aAAa;AACrB,sBAAgB,KAAK;AAAA,QACpB,CAAC,EAAE,UAAU,KAAK,YAAY,CAAC;AAAA,QAC/B,KAAK,yBAAyB,CAAC;AAAA,MAChC;AACA,WAAK,YAAY,MAAM,eAAe,QAAQ,CAAC;AAAA,IAChD;AAEA,SAAK,QAAQ;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,eAAe,KAAK,MAAM,MAAM;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;AAkBO,SAAS,gBACf,MACmC;AACnC,SAAO,IAAI,qBAAiC,IAAI;AACjD;AAmCA,SAAS,kBACR,GACA,GACS;AACT,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,QAAM,IAAI,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AACrC,MAAI,IAAI;AACR,SAAO,IAAI,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG;AAC/B,SAAO;AACR;AAKA,IAAM,eAAe,CAAI,GAAiB,MAA6B;AACtE,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO;AAC7D,SAAO;AACR;AAwBO,IAAM,uBAAN,cAAyC,oBAAM;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,eAAe;AAAA,EAEvB,YAAY,MAAoC;AAC/C,UAAM,KAAK,QAAQ,oBAAoB,KAAK,KAAK;AAEjD,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK,WAAW;AAChC,SAAK,MAAM,KAAK,MAAM;AACtB,SAAK,QAAQ;AACb,SAAK,QAAQ,KAAK,QAAQ;AAC1B,SAAK,cAAc,KAAK,cAAc;AACtC,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,iBAAiB,KAAK,iBAAiB;AAO5C,QAAI,KAAK,SAAS;AACjB,WAAK,mBAAe,wBAAQ,KAAK,OAAO;AAAA,IACzC,OAAO;AACN,WAAK,eAAe,KAAK,MAAe,YAAY,IAAI;AAAA,IACzD;AAAA,EACD;AAAA,EAEQ,cACP,UACA,KACA,OACkE;AAClE,UAAM,OAAO,KAAK;AAClB,UAAM,eAAe,oBAAI,IAGvB;AAEF,QAAI,mBAA+C,CAAC;AACpD,QAAI,KAAK,YAAY,MAAM,QAAQ;AAMlC,YAAM,IAAI,MAAM;AAChB,YAAM,WAAW,KAAK,SAAS,QAAQ;AAGvC,UAAI,YAAY,SAAS,OAAO,KAAK,KAAK,QAAQ,GAAG;AACpD,cAAM,SAAS,CAAC,GAAG,SAAS,OAAO,CAAC,EAClC;AAAA,UACA,CAAC,SAAmC;AAAA,YACnC,IAAI,IAAI;AAAA,YACR,OAAO,iBAAiB,GAAG,IAAI,MAAM;AAAA,YACrC,GAAI,IAAI,SAAS,SAAY,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAAA,UACpD;AAAA,QACD,EACC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,KAAK,KAAK;AACrB,2BAAmB;AACnB,mBAAW,MAAM,kBAAkB;AAClC,gBAAM,MAAM,SAAS,IAAI,GAAG,EAAE;AAC9B,cAAI,IAAK,cAAa,IAAI,GAAG,IAAI,EAAE,OAAO,KAAK,SAAS,oBAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;AAAA,QAC9E;AAAA,MACD;AAAA,IACD;AAEA,UAAM,gBAA0B,CAAC;AACjC,QAAI,KAAK,KAAK;AAMb,YAAM,SAAS,KAAK,IAAI,aAAa;AAGrC,YAAM,QAAQ,KAAK,IAAI,YAAY;AAGnC,YAAM,UAAU,CAAC,GAAI,MAAM,aAAa,CAAC,GAAI,GAAG,CAAC,GAAG,aAAa,KAAK,CAAC,CAAC;AACxE,YAAM,UAAU,oBAAI,IAAY;AAChC,UAAI,WAAW;AACf,eAAS,QAAQ,GAAG,QAAQ,KAAK,aAAa,SAAS;AACtD,cAAM,eAAyB,CAAC;AAChC,mBAAW,MAAM,UAAU;AAC1B,cAAI,QAAQ,IAAI,EAAE,EAAG;AACrB,kBAAQ,IAAI,EAAE;AACd,gBAAM,WAAW,QAAQ,IAAI,EAAE,KAAK,CAAC;AACrC,gBAAM,UAAU,OAAO,IAAI,EAAE,KAAK,CAAC;AACnC,qBAAW,QAAQ,UAAU;AAC5B,kBAAM,WAAW,KAAK;AACtB,gBAAI,CAAC,QAAQ,IAAI,QAAQ,GAAG;AAC3B,2BAAa,KAAK,QAAQ;AAC1B,oBAAM,MAAM,SAAS,IAAI,QAAQ;AACjC,kBAAI,KAAK;AACR,sBAAM,WAAW,aAAa,IAAI,QAAQ;AAC1C,oBAAI,SAAU,UAAS,QAAQ,IAAI,OAAO;AAAA,oBACrC,cAAa,IAAI,UAAU,EAAE,OAAO,KAAK,SAAS,oBAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3E,8BAAc,KAAK,QAAQ;AAAA,cAC5B;AAAA,YACD;AAAA,UACD;AAIA,qBAAW,QAAQ,SAAS;AAC3B,kBAAM,WAAW,KAAK;AACtB,gBAAI,CAAC,QAAQ,IAAI,QAAQ,GAAG;AAC3B,2BAAa,KAAK,QAAQ;AAC1B,oBAAM,MAAM,SAAS,IAAI,QAAQ;AACjC,kBAAI,KAAK;AACR,sBAAM,WAAW,aAAa,IAAI,QAAQ;AAC1C,oBAAI,SAAU,UAAS,QAAQ,IAAI,OAAO;AAAA,oBACrC,cAAa,IAAI,UAAU,EAAE,OAAO,KAAK,SAAS,oBAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3E,8BAAc,KAAK,QAAQ;AAAA,cAC5B;AAAA,YACD;AAAA,UACD;AAAA,QACD;AACA,mBAAW;AAAA,MACZ;AAAA,IACD;AACA,eAAW,CAAC,KAAK,GAAG,KAAK,UAAU;AAClC,UAAI,CAAC,aAAa,IAAI,GAAG,GAAG;AAC3B,qBAAa,IAAI,KAAK,EAAE,OAAO,KAAK,SAAS,oBAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AAAA,MAClE;AAAA,IACD;AAEA,UAAM,SAAS,MAAM,SAAS,UAAU;AACxC,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,KAAK,EAAE,OAAO,QAAQ,CAAC,KAAK,cAAc;AACrD,YAAM,eAAe,KAAK,YAAY,KAAK,UAAU,KAAK,IAAI;AAC9D,UAAI,QAAQ,KAAK,MAAM,OAAO,GAAG;AACjC,UAAI,KAAK,iBAAiB,KAAK,SAAS,GAAG;AAC1C,cAAM,SAAS,kBAAkB,MAAM,SAAS,YAAY;AAC5D,YAAI,SAAS,EAAG,SAAQ,SAAS,IAAK,KAAK,iBAAiB,SAAU;AAAA,MACvE;AACA,YAAM,QAA8B,eACjC,EAAE,KAAK,OAAO,OAAO,SAAS,CAAC,GAAG,OAAO,GAAG,SAAS,aAAa,IAClE,EAAE,KAAK,OAAO,OAAO,SAAS,CAAC,GAAG,OAAO,EAAE;AAC9C,aAAO,KAAK,KAAK;AAAA,IAClB;AACA,WAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAEvC,UAAM,SAAiC,CAAC;AACxC,QAAI,aAAa;AACjB,eAAW,SAAS,QAAQ;AAC3B,YAAM,IAAI,KAAK,KAAK,MAAM,KAAK;AAC/B,UAAI,aAAa,IAAI,KAAK,WAAW,OAAO,SAAS,EAAG;AACxD,aAAO,KAAK,KAAK;AACjB,oBAAc;AAAA,IACf;AAEA,WAAO,EAAE,QAAQ,OAAO,EAAE,kBAAkB,eAAe,QAAQ,OAAO,EAAE;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6CA,iBACC,YAC4C;AAC5C,UAAM,KAAK,EAAE,KAAK;AAClB,UAAM,UAAU,YAAY,EAAE;AAK9B,UAAM,MAAM,IAAI,oBAAM,OAAO;AAW7B,UAAM,gBAAY,wBAAQ,UAAU;AACpC,UAAM,eAAe,IAAI;AAAA,MACxB;AAAA,MACA,CAAC,SAAS;AAAA,MACV,CAAC,WAAW,QAAQ;AACnB,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,eAAO,CAAE,KAAK,CAAC,KAA+B,IAAI;AAAA,MACnD;AAAA,MACA;AAAA,QACC,MAAM,OAAO,uBAAuB;AAAA,QACpC,SAAS;AAAA,MACV;AAAA,IACD;AAOA,UAAM,aAAyC;AAAA,MAC9C,KAAK,OAAO,MAAM;AAAA,MAClB,KAAK;AAAA,MACL;AAAA,IACD;AACA,QAAI,KAAK,SAAU,YAAW,KAAK,KAAK,SAAS,OAAwB;AACzE,QAAI,KAAK,KAAK;AACb,iBAAW,KAAK,KAAK,IAAI,YAA6B;AACtD,iBAAW,KAAK,KAAK,IAAI,WAA4B;AAAA,IACtD;AAIA,UAAM,SAAS,IAAI;AAAA,MAIlB;AAAA,MACA;AAAA,MACA,CAAC,WAAW,QAAQ;AACnB,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,cAAM,QAAQ,KAAK,CAAC;AACpB,YAAI,SAAS,MAAM;AAClB,iBAAO,CAAC,EAAE,QAAQ,CAAC,GAA0C,OAAO,KAAK,CAAC;AAAA,QAC3E;AACA,cAAM,WACJ,KAAK,CAAC,KAA+C,oBAAI,IAAkB;AAC7E,cAAM,EAAE,QAAQ,MAAM,IAAI,KAAK,cAAc,UAAU,KAAK,CAAC,GAAG,KAAuB;AACvF,eAAO,CAAC,EAAE,QAAQ,MAAM,CAAC;AAAA,MAC1B;AAAA,MACA;AAAA,QACC,MAAM,OAAO,2BAA2B;AAAA,QACxC,SAAS,EAAE,QAAQ,CAAC,GAA0C,OAAO,KAAK;AAAA,MAC3E;AAAA,IACD;AAQA,UAAM,iBAAa;AAAA,MAClB,CAAC,MAAM;AAAA,MACP,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,OAAO,UAAU;AAAA,UAAI,CAAC,GAAG,MAC9B,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,gBAAQ,KAAM,KAAK,CAAC,EAAsD,MAAM;AAChF,eAAO;AAAA,UACN,gBAAgB,MAAM;AAMrB,gBAAI;AACH,mBAAK,OAAO,OAAO;AAAA,YACpB,QAAQ;AAAA,YAER;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,MACA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,MAAM,OAAO,oBAAoB;AAAA,QACjC,SAAS,CAAC;AAAA,QACV,QAAQ;AAAA,MACT;AAAA,IACD;AACA,QAAI,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAE1C,SAAK,MAAM,SAAS,GAAG;AACvB,WAAO;AAAA,EACR;AACD;AAQO,SAAS,gBACf,MAC6B;AAC7B,SAAO,IAAI,qBAA2B,IAAI;AAC3C;;;AGh6BA,IAAAC,gBAAqB;;;AC+BrB,IAAAC,gBAAuD;AACvD,IAAAC,iBAAmD;AAiEnD,SAAS,eAAe,MAAuB;AAC9C,MAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,aAAa,MAAM;AAClE,WAAO,OAAQ,KAAqB,OAAO;AAAA,EAC5C;AACA,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,SAAO,OAAO,IAAI;AACnB;AAEA,SAAS,eAAe,MAAc,MAAM,KAAa;AACxD,MAAI,KAAK,UAAU,IAAK,QAAO;AAC/B,SAAO,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC;AAC7B;AAwDO,SAAS,WACf,SACA,MACA,QACA,MACiB;AACjB,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,WAAW,MAAM,QAAQ;AAO/B,MAAI,MAAM,UAAU,UAAa,WAAW,OAAO;AAClD,YAAQ;AAAA,MACP;AAAA,IAGD;AAAA,EACD;AAuBA,QAAM,iBAAiB,KAAK;AAC5B,QAAM,UACL,MAAM,UAAU,SAAY,CAAC,GAAG,MAAM,KAAK,KAAsB,IAAI;AACtE,QAAM,mBAAe;AAAA,IACpB;AAAA,IACA,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,aAAa,KAAK,MAAM,GAAG,cAAc;AAC/C,YAAM,aACL,MAAM,UAAU,SACZ,KAAK,cAAc,IACpB;AAKJ,UAAI,WAAW,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG;AACtC,gBAAQ,KAAK,EAAE,UAAU,CAAC,GAAG,OAAO,WAAW,CAAC;AAChD;AAAA,MACD;AACA,YAAM,OAAO,OAAO,WAAW,WAAW,SAAS,OAAO,GAAG,UAAU;AACvE,UAAI,CAAC,MAAM;AACV,gBAAQ,KAAK,EAAE,UAAU,CAAC,GAAG,OAAO,WAAW,CAAC;AAChD;AAAA,MACD;AAEA,cAAQ,KAAK;AAAA,QACZ,UAAU,CAAC,EAAE,MAAM,QAAiB,SAAS,KAAK,CAAC;AAAA,QACnD,OAAO;AAAA,MACR,CAAC;AAAA,IACF;AAAA,IACA;AAAA,MACC,MAAM,GAAG,QAAQ;AAAA,MACjB,MAAM,OAAO,uBAAuB;AAAA,IACrC;AAAA,EACD;AAEA,QAAM,aAAS;AAAA,IACd;AAAA,IACA,CAAC,aAAa;AACb,YAAM,EAAE,UAAU,MAAM,MAAM,IAAI;AAClC,UAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC/B,mBAAO,oBAAe,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC;AAAA,MAC5C;AAMA,iBAAO;AAAA,QACN,CAAC,OAAO,YAAY;AACnB,cAAI,OAAO;AACX,cAAI,YAAY;AAChB,cAAI;AAEJ,gBAAM,aAA+B;AAAA,YACpC,OAAO,MAAM;AAAA,YACb,aAAa,MAAM;AAAA,YACnB,WAAW,MAAM;AAAA,YACjB,cAAc,MAAM;AAAA,YACpB,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,UACxC;AACA,cAAI,MAAM,OAAO;AAChB,kBAAM,MAAM,WAAW,KAAK,KAAK;AACjC,uBAAW,SAAS,IAAI;AACxB,2BAAe,IAAI;AAAA,UACpB;AAEA,cAAI;AACJ,cAAI;AACH,2BAAe,QAAQ,OAAO,MAAM,UAAU;AAAA,UAC/C,SAAS,KAAK;AACb,mBAAO;AACP,oBAAQ,KAAK,CAAC,CAAC,qBAAO,GAAG,CAAC,CAAC;AAC3B,mBAAO;AAAA,cACN,gBAAgB,MAAM;AACrB,+BAAe;AAAA,cAChB;AAAA,YACD;AAAA,UACD;AAEA,gBAAM,eAAW,wBAAQ,YAAY;AAErC,gBAAM,MAAM,SAAS,UAAU,CAACA,WAAU;AACzC,gBAAI,aAAa,KAAM;AACvB,uBAAW,OAAOA,QAAO;AAKxB,kBAAI,aAAa,KAAM;AACvB,kBAAI,IAAI,CAAC,MAAM,oBAAM;AACpB,sBAAM,OAAO,IAAI,CAAC;AAIlB,oBAAI,WAAW,OAAO;AACrB,0BAAQ,KAAK,IAAoB;AAAA,gBAClC,OAAO;AAKN,sBAAI;AACJ,sBAAI;AACH,8BAAU,eAAe,IAAI;AAAA,kBAC9B,SAAS,KAAK;AAGb,0BAAM,UAAU,IAAI;AAAA,sBACnB,4DACE,IAAc,OAChB;AAAA,oBACD;AAIA,mCAAe;AACf,mCAAe;AACf,2BAAO;AACP,4BAAQ,KAAK,CAAC,CAAC,qBAAO,OAAO,CAAC,CAAC;AAC/B;AAAA,kBACD;AACA,sBAAI;AACH,0BAAM,SACL,WAAW,SACP,KAAK,MAAM,YAAY,OAAO,CAAC,IAC/B;AACL,4BAAQ,KAAK,MAAM;AAAA,kBACpB,SAAS,KAAK;AACb,0BAAM,UAAU,IAAI;AAAA,sBACnB,qDACE,IAAc,OAChB;AAAA,mCAAsC,eAAe,OAAO,CAAC;AAAA,oBAC9D;AAGA,mCAAe;AACf,mCAAe;AACf,2BAAO;AACP,4BAAQ,KAAK,CAAC,CAAC,qBAAO,OAAO,CAAC,CAAC;AAC/B;AAAA,kBACD;AAAA,gBACD;AAAA,cACD,WAAW,IAAI,CAAC,MAAM,qBAAO;AAE5B,+BAAe;AACf,+BAAe;AACf,uBAAO;AACP,wBAAQ,KAAK,CAAC,CAAC,qBAAO,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9B;AAAA,cACD,WAAW,IAAI,CAAC,MAAM,wBAAU;AAI/B,+BAAe;AACf,+BAAe;AACf,uBAAO;AACP,wBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB;AAAA,cACD,OAAO;AAMN,wBAAQ,KAAK,CAAC,GAAY,CAAC;AAAA,cAC5B;AAAA,YACD;AAAA,UACD,CAAC;AAED,iBAAO;AAAA,YACN,gBAAgB,MAAM;AACrB,0BAAY;AACZ,kBAAI;AAIJ,6BAAe;AACf,6BAAe;AAAA,YAChB;AAAA,UACD;AAAA,QACD;AAAA,QACA;AAAA,UACC,cAAc;AAAA,UACd,MAAM,GAAG,QAAQ;AAAA,UACjB,MAAM,OAAO,uBAAuB;AAAA,QACrC;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,MAAM,GAAG,QAAQ;AAAA,MACjB,MAAM,MAAM,OACT,EAAE,GAAG,OAAO,qBAAqB,GAAG,GAAG,KAAK,KAAK,IACjD,OAAO,qBAAqB;AAAA,IAChC;AAAA,EACD;AAEA,SAAO;AACR;;;AD/WO,SAAS,WACf,cACA,kBACA,MACA,aACkC;AAClC,QAAM,OAAO,KAAK,QAAQ;AAC1B,SAAO,CAAC,UAAe;AAItB,UAAM,iBAAa,oBAAU,CAAC,GAAG,EAAE,SAAS,MAAM,CAAC;AACnD,WAAO;AAAA,MACN,KAAK;AAAA,MACL,CAAC,UAAmB;AAAA,MACpB,CAAC,UAAmB,iBAAiB,KAAY;AAAA,MACjD;AAAA,QACC;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,aAAa,KAAK,eAAe;AAAA,QACjC,WAAW,KAAK;AAAA,MACjB;AAAA,IACD;AAAA,EACD;AACD;AA0BO,SAAS,aACf,cACA,MACkF;AAClF,QAAM,MAAM,KAAK,mBAAmB;AACpC,QAAM,OAAO;AAAA,IACZ;AAAA,IACA,CAAC,UAAU,KAAK,UAAU,EAAE,OAAO,MAAM,KAAK,cAAc,MAAM,aAAa,CAAC;AAAA,IAChF;AAAA,IACA;AAAA,EACD;AACA,SAAO,CAAC,KAAW,aAAwC;AAC1D,UAAM,eACL,QAAQ,OAAO,oBAAoB,CAAC,GAAG,SAAS,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG;AAC5F,WAAO,KAAK,EAAE,KAAK,aAAa,CAAC;AAAA,EAClC;AACD;AAMO,SAAS,gBACf,cACA,MACsE;AACtE,QAAM,OAAO;AAAA,IACZ;AAAA,IACA,CAAC,aAAa,KAAK,UAAU,EAAE,SAAS,CAAC;AAAA,IACzC;AAAA,IACA;AAAA,EACD;AACA,SAAO,CAAC,YAAuC;AAC9C,UAAM,WAAW,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE;AAC9E,WAAO,KAAK,QAAQ;AAAA,EACrB;AACD;;;ANXO,IAAM,mBAAN,cAA+C,oBAAM;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA;AAAA,EAIT,YAAY,MAAc,QAA4B,MAAgC;AACrF,UAAM,MAAM,KAAK,KAAK;AAKtB,QAAI;AAIJ,QAAI,KAAK,WAAW;AACnB,qBAAe,KAAK;AAAA,IACrB,WAAW,KAAK,WAAW,KAAK,eAAe;AAC9C,qBAAe,aAA4B,KAAK,eAAe,EAAE,SAAS,KAAK,QAAQ,CAAC;AAAA,IACzF,OAAO;AACN,YAAM,IAAI,MAAM,kEAAkE;AAAA,IACnF;AAMA,SAAK,WAAW,mBAAe,+BAAgB,IAA0C,CAAC;AAc1F,UAAM,YAAY,CACjB,SACA,iBACiC;AACjC,UAAI,iBACF,aAAa,SAAmD,oBAAI,IAAI;AAC1E,YAAM,gBAAgB,aAAa,UAAU,CAAC,SAAS;AACtD,mBAAW,KAAK,MAAM;AACrB,cAAI,EAAE,CAAC,MAAM,mBAAM,kBAAiB,EAAE,CAAC;AAAA,QACxC;AAAA,MACD,CAAC;AACD,WAAK,YAAY,aAAa;AAC9B,iBAAO,0BAAU,SAAS,CAAC,QAAQ;AAClC,YAAI,OAAO,KAAM,QAAO,EAAE,QAAQ,CAAC,EAAE;AACrC,eAAO,aAAa,KAAK,cAAc;AAAA,MACxC,CAAC;AAAA,IACF;AAGA,QAAI,iBAAiB;AACrB,QAAI,KAAK,iBAAiB;AACzB,YAAM,cAAU,wBAAQ,MAAM;AAC9B,YAAM,SAAS,KAAK;AACpB,2BAAiB;AAAA,QAChB,CAAC,OAAO;AAAA,QACR,CAAC,WAAW,SAAS,QAAQ;AAC5B,gBAAM,OAAO,UAAU;AAAA,YAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,UAClE;AACA,gBAAM,MAAM,KAAK,CAAC;AAClB,cAAI,OAAO,GAAG,GAAG;AAChB,oBAAQ,KAAK,GAAG;AAAA,UACjB,OAAO;AAON,oBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AAAA,UAC1B;AAAA,QACD;AAAA,QACA,EAAE,MAAM,mBAAmB,cAAc,UAAU;AAAA,MACpD;AAAA,IACD;AAGA,QAAI;AAGJ,QAAI,KAAK,eAAe;AACvB,sBAAgB,KAAK;AAAA,IACtB,WAAW,KAAK,WAAW,KAAK,mBAAmB;AAClD,sBAAgB,gBAAsB,KAAK,mBAAmB,EAAE,SAAS,KAAK,QAAQ,CAAC;AAAA,IACxF;AAGA,QAAI,qBAAqB,KAAK;AAC9B,QAAI,CAAC,sBAAsB,iBAAiB,KAAK,YAAY,YAAY,OAAO;AAC/E,YAAM,WAAW,KAAK,YAAY,YAAY;AAC9C,+BAAqB,0BAAU,UAAU,EAAE,QAAQ,SAAS,CAAC;AAAA,IAC9D;AAOA,UAAM,cAAoC;AAAA,MACzC,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK,UAAU;AAAA,MACvB,SAAS,KAAK;AAAA,MACd,aAAa;AAAA,MACb;AAAA,IACD;AAEA,QAAI;AACJ,QAAI,oBAAoD;AACxD,QAAI,gBAA4D;AAChE,QAAI,KAAK,OAAO;AACf,YAAM,aAAa,gBAA+B;AAAA;AAAA;AAAA;AAAA,QAIjD,GAAG,KAAK;AAAA,QACR,MAAM;AAAA,QACN,QAAQ;AAAA,QACR;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,EAAE,QAAQ,IAAK;AAAA,QACzE,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;AAAA,QAC9D,GAAI,kBAAkB,SAAY,EAAE,aAAa,cAAc,IAAI,CAAC;AAAA,QACpE,GAAI,uBAAuB,SAAY,EAAE,mBAAmB,IAAI,CAAC;AAAA,MAClE,CAAC;AACD,WAAK,MAAM,SAAS,UAAU;AAC9B,sBAAgB,WAAW;AAC3B,0BAAoB,WAAW;AAC/B,sBAAgB;AAAA,IACjB,OAAO;AACN,sBAAgB,QAAuB,gBAAgB,WAAW,WAAW;AAC7E,WAAK,IAAI,cAAc,MAAM,SAAS,EAAE,MAAM,QAAQ,CAAC;AACvD,WAAK,IAAI,cAAc,SAAS,EAAE,MAAM,UAAU,CAAC;AACnD,WAAK,IAAI,cAAc,MAAM,EAAE,MAAM,OAAO,CAAC;AAAA,IAC9C;AAGA,QAAI,UAAyC;AAC7C,QAAI,KAAK,oBAAoB,KAAK,mBAAmB,KAAK,KAAK,SAAS;AACvE,YAAM,eAAe,kBAAwB;AAAA,QAC5C,MAAM;AAAA,QACN,OAAO;AAAA,QACP,WAAW,KAAK;AAAA,QAChB,SAAS,KAAK;AAAA,MACf,CAAC;AACD,WAAK,MAAM,WAAW,YAAY;AAClC,gBAAU,aAAa;AAAA,IACxB;AAGA,QAAI,KAA6C;AACjD,QAAI,KAAK,sBAAsB;AAC9B,YAAM,UAAU,aAAmB;AAAA,QAClC,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,GAAG,IAAI;AAAA,QACf,WAAW;AAAA,QACX,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,MAClE,CAAC;AACD,WAAK,MAAM,aAAa,OAAO;AAC/B,WAAK,QAAQ;AAAA,IACd;AAGA,QAAI,mBAIM;AAEV,QAAI,WAAW,IAAI;AAClB,YAAM,iBAAiB,gBAAsB;AAAA,QAC5C,MAAM;AAAA,QACN,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,QAC3D,GAAI,KAAK,WAAW,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,KAAK,IAAI,CAAC;AAAA,QAC1E,GAAI,KAAK,WAAW,eAAe,SAChC,EAAE,YAAY,KAAK,UAAU,WAAW,IACxC,CAAC;AAAA,QACJ,GAAI,KAAK,cAAc,SAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,QACpE,GAAI,KAAK,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,QAChF,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;AAAA,MAC/D,CAAC;AACD,WAAK,MAAM,aAAa,cAAc;AACtC,yBAAmB,eAAe,iBAAiB,KAAK,cAAc;AAAA,IACvE;AAEA,SAAK,gBAAgB;AACrB,SAAK,UAAU,cAAc;AAC7B,SAAK,OAAO,cAAc;AAC1B,SAAK,UAAU;AACf,SAAK,KAAK;AACV,SAAK,cAAc;AACnB,SAAK,QAAQ;AACb,SAAK,mBAAmB;AAAA,EACzB;AACD;AAWO,SAAS,YACf,MACA,QACA,MACyB;AACzB,SAAO,IAAI,iBAAuB,MAAM,QAAQ,IAAI;AACrD;;;AQ1XA,IAAAC,iBAAoD;AAqD7C,SAAS,MACf,QACA,MACyB;AACzB,QAAM,QAAQ,IAAI,WAAsB,IAAI;AAC5C,SAAO,MAAM,KAAK,MAAM,KAAK;AAC7B,SAAO;AAAA,IACN,IAAI,MAAM;AAAA,IACV,KAAK,MAAM;AAAA,IACX,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM;AAAA,IACZ;AAAA,EACD;AACD;AAgEO,SAAS,eACf,SACgC;AAChC,QAAM,eAAW,4BAA6B,EAAE,MAAM,iBAAiB,CAAC;AACxE,MAAI,WAAW,MAAM;AACpB,eAAW,CAAC,IAAI,MAAM,KAAK,SAAS;AACnC,eAAS,IAAI,IAAI,MAAM;AAAA,IACxB;AAAA,EACD;AACA,SAAO;AAAA,IACN;AAAA,IACA,IAAI,IAAI,QAAQ;AACf,eAAS,IAAI,IAAI,MAAM;AAAA,IACxB;AAAA,IACA,OAAO,IAAI;AACV,UAAI,CAAC,SAAS,IAAI,EAAE,EAAG,QAAO;AAC9B,eAAS,OAAO,EAAE;AAClB,aAAO;AAAA,IACR;AAAA,EACD;AACD;;;ACxJA,IAAAC,gBAA6C;AAC7C,IAAAC,iBAAoD;AACpD,IAAAC,iBAAsB;AAsHf,IAAM,mBAAN,MAAuB;AAAA,EAI7B,YAA6B,MAAc;AAAd;AAAA,EAAe;AAAA,EAH3B,KAAK,oBAAI,IAA+B;AAAA;AAAA,EAExC,SAAmB,CAAC;AAAA,EAErC,IAAI,IAAY,MAAgC;AAC/C,UAAM,QAAQ,KAAK,GAAG,IAAI,EAAE;AAC5B,UAAM,IAAI,OAAO,IAAI,IAAI;AACzB,QAAI,MAAM,QAAW;AACpB,YAAM,IAAI,KAAK,OAAO,QAAQ,EAAE;AAChC,UAAI,KAAK,EAAG,MAAK,OAAO,OAAO,GAAG,CAAC;AACnC,WAAK,OAAO,KAAK,EAAE;AAAA,IACpB;AACA,WAAO;AAAA,EACR;AAAA,EACA,IAAI,IAAY,MAAY,OAAqB;AAChD,QAAI,QAAQ,KAAK,GAAG,IAAI,EAAE;AAC1B,QAAI,UAAU,QAAW;AACxB,cAAQ,oBAAI,IAAkB;AAC9B,WAAK,GAAG,IAAI,IAAI,KAAK;AAAA,IACtB;AACA,UAAM,IAAI,MAAM,KAAK;AACrB,UAAM,IAAI,KAAK,OAAO,QAAQ,EAAE;AAChC,QAAI,KAAK,EAAG,MAAK,OAAO,OAAO,GAAG,CAAC;AACnC,SAAK,OAAO,KAAK,EAAE;AACnB,WAAO,KAAK,GAAG,OAAO,KAAK,MAAM;AAChC,YAAM,QAAQ,KAAK,OAAO,MAAM;AAChC,UAAI,UAAU,OAAW;AACzB,WAAK,GAAG,OAAO,KAAK;AAAA,IACrB;AAAA,EACD;AACD;AAKA,IAAI,WAAW;AAOR,SAAS,kBACf,QACA,MAC6B;AAI7B,QAAM,YAAY,KAAK,QAAQ,WAAW,KAAK,KAAK,IAAI,EAAE,QAAQ;AAClE,QAAM,QAAQ,IAAI,qBAAM,SAAS;AACjC,SAAO,MAAM,WAAW,KAAK;AAE7B,QAAM,UAA0C,4BAA6B,QAAW;AAAA,IACvF,MAAM,GAAG,SAAS;AAAA,IAClB,SAAS,KAAK;AAAA,EACf,CAAC;AACD,QAAM,QAAQ,IAAI,iBAAiB,KAAK,YAAY,GAAG;AAGvD,MAAI,SAAS;AAEb,QAAM,UAA4C,IAAI;AAEtD,WAAS,IAAI,GAAmE;AAC/E,UAAM,KAAK,EAAE,MAAM,OAAO,EAAE,MAAM;AAClC,QAAI,OAAO;AAAA,MACV;AAAA,MACA,SAAS,EAAE;AAAA,MACX,MAAM,EAAE;AAAA,MACR,YAAY,EAAE;AAAA,MACd,cAAc,EAAE;AAAA,MAChB,OAAO,EAAE;AAAA,MACT,UAAM,2BAAY;AAAA;AAAA,IACnB,CAAC;AACD,WAAO;AAAA,EACR;AAEA,WAAS,MAAM,KAA4C;AAC1D,eAAO;AAAA,MACN,CAAC,OAAe;AAAA,MAChB,CAAC,MAAM,SAAS,QAAQ;AACvB,cAAM,MAAO,KAAK,CAAC,KAAK,QAAQ,KAAK,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAGpF,gBAAQ,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,SAAS,GAAG,CAAC,CAAC;AAAA,MAC7D;AAAA,MACA,EAAE,cAAc,WAAW,MAAM,OAAO,qBAAqB,EAAE,IAAI,CAAC,EAAE;AAAA,IACvE;AAAA,EACD;AAEA,WAAS,OAAOC,SAA8B;AAC7C,UAAM,MAAM,IAAI,QAAQ,SAAS,CAAC;AAClC,UAAM,YAAQ,2BAAY;AAC1B,QAAI,YAAY,IAAI,OAAO,CAAC,MAAM;AAIjC,UAAIA,QAAO,SAAS,QAAQ,EAAE,UAAUA,QAAO,MAAO,QAAO;AAC7D,UAAIA,QAAO,eAAe,QAAQ,QAAQ,EAAE,QAAQA,QAAO,YAAa,QAAO;AAC/E,UAAIA,QAAO,mBAAmB,QAAQ,EAAE,aAAaA,QAAO,gBAAiB,QAAO;AACpF,aAAO;AAAA,IACR,CAAC;AACD,QAAIA,QAAO,OAAO,QAAQ,UAAU,SAASA,QAAO,KAAK;AACxD,kBAAY,UAAU,MAAM,UAAU,SAASA,QAAO,GAAG;AAAA,IAC1D;AACA,UAAM,UAAU,IAAI,SAAS,UAAU;AACvC,QAAI,UAAU,GAAG;AAChB,UAAI,MAAM;AACV,UAAI,WAAW,SAAS;AAAA,IACzB;AACA,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,UAAgB;AACf,UAAI,QAAQ;AAAA,IACb;AAAA,EACD;AACD;AAIA,IAAM,oBAAoB,CAAC,MAAsB,KAAK,KAAK,EAAE,SAAS,CAAC;AAEvE,SAAS,QAAQ,GAA0B,GAAuB;AACjE,MAAI,EAAE,SAAS,MAAM;AACpB,QAAI,OAAO,EAAE,UAAU,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,EAAE,KAAK,EAAG,QAAO;AAAA,EACxF;AACA,MAAI,EAAE,WAAW,QAAQ,CAAC,EAAE,QAAQ,KAAK,CAAC,MAAM,EAAE,KAAK,SAAS,CAAC,CAAC,EAAG,QAAO;AAC5E,MAAI,EAAE,iBAAiB,QAAQ,EAAE,aAAa,EAAE,cAAe,QAAO;AACtE,MAAI,EAAE,iBAAiB,QAAQ,EAAE,aAAa,EAAE,cAAe,QAAO;AACtE,MAAI,EAAE,gBAAgB,QAAQ,EAAE,iBAAiB,EAAE,aAAc,QAAO;AACxE,SAAO;AACR;AAQO,SAAS,aACf,GACA,OACA,UACA,OACA,aAC+B;AAC/B,QAAM,OAAyB;AAAA,IAC9B,IAAI,EAAE;AAAA,IACN,OAAO,EAAE;AAAA,IACT,MAAM,EAAE;AAAA,IACR,MAAM;AAAA,IACN,SAAS,EAAE;AAAA,IACX,YAAY;AAAA,EACb;AACA,MAAI,YAAY,EAAG,QAAO;AAC1B,aAAW,QAAQ,OAAO;AACzB,QAAI,CAAC,QAAQ,GAAG,KAAK,KAAK,EAAG;AAC7B,YAAQ,KAAK,QAAQ;AAAA,MACpB,KAAK;AACJ,eAAO;AAAA,MACR,KAAK;AACJ,eAAO,EAAE,GAAG,MAAM,MAAM,GAAG,SAAS,QAAQ,EAAE,EAAE,KAAK,YAAY,KAAK;AAAA,MACvE,KAAK,YAAY;AAChB,cAAM,IAAI,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,KAAK,UAAU,EAAE,OAAO;AAC9E,eAAO;AAAA,UACN,GAAG;AAAA,UACH,MAAM;AAAA,UACN,SAAS,EAAE,SAAS,KAAK,WAAW,EAAE,MAAM,GAAG,KAAK,QAAQ,IAAI;AAAA,UAChE,YAAY,EAAE,SAAS,KAAK;AAAA,QAC7B;AAAA,MACD;AAAA,MACA,KAAK,eAAe;AACnB,YAAI,CAAC,aAAa;AAEjB,gBAAM,IAAI,MAAM,yDAAyD;AAAA,QAC1E;AACA,cAAM,SAAS,MAAM,IAAI,EAAE,IAAI,KAAK,MAAM;AAC1C,cAAM,OAAO,UAAU,YAAY,GAAG,KAAK,MAAM;AACjD,YAAI,WAAW,OAAW,OAAM,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI;AAC3D,eAAO,EAAE,GAAG,MAAM,MAAM,KAAK,QAAQ,SAAS,MAAM,YAAY,KAAK;AAAA,MACtE;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAcO,SAAS,kBACf,MACA,MACoC;AACpC,QAAM,UAAU,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,aAAa;AACjE,MAAI,WAAW,CAAC,KAAK,MAAM,aAAa;AACvC,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,QAAM,WAAW,KAAK,aAAa;AACnC,QAAM,cAAc,KAAK,MAAM;AAE/B,aAAO;AAAA,IACN,CAAC,KAAK,SAAiB,KAAK,QAAgB;AAAA,IAC5C,CAAC,MAAM,SAAS,QAAQ;AACvB,YAAM,UAAW,KAAK,CAAC,KAAK,QAAQ,KAAK,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAGxF,YAAM,WAAY,KAAK,CAAC,KAAK,QAAQ,KAAK,CAAC,EAAE,SAAS,IAAI,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAGzF,UAAI,YAAY,QAAW;AAC1B,gBAAQ,KAAK,CAAC,CAAC;AACf;AAAA,MACD;AACA,YAAM,IAAI,YAAY;AACtB,YAAM,WAA+B,CAAC;AACtC,iBAAW,KAAK,SAAS;AACxB,YAAI,CAAC,KAAK,OAAO,CAAC,EAAG;AACrB,cAAM,IAAI,aAAa,GAAG,KAAK,OAAO,GAAG,KAAK,QAAQ,WAAW;AACjE,YAAI,MAAM,OAAW,UAAS,KAAK,CAAC;AAAA,MACrC;AAEA,YAAM,OAAO,CAAC,MACb,SAAS,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,KAAK,UAAU,EAAE,OAAO,CAAC;AAC/E,UAAI,QAAQ;AACZ,iBAAW,KAAK,SAAU,UAAS,KAAK,CAAC;AACzC,UAAI,QAAQ,KAAK,cAAc;AAC9B,cAAM,QAAQ,QAAQ;AAAA,UACrB,CAAC,KAAK,MAAM,IAAI,IAAI,EAAE,IAAI,EAAE,UAAU;AAAA,UACtC,oBAAI,IAAI;AAAA,QACT;AACA,iBAAS,KAAK,CAAC,GAAG,OAAO,MAAM,IAAI,EAAE,EAAE,KAAK,MAAM,MAAM,IAAI,EAAE,EAAE,KAAK,EAAE;AACvE,eAAO,QAAQ,KAAK,gBAAgB,SAAS,SAAS,GAAG;AACxD,mBAAS,KAAK,SAAS,MAAM,CAAqB;AAAA,QACnD;AAAA,MACD;AACA,cAAQ,KAAK,QAAQ;AAAA,IACtB;AAAA,IACA,EAAE,cAAc,WAAW,MAAM,OAAO,eAAe,EAAE,OAAO,KAAK,MAAM,MAAM,CAAC,EAAE;AAAA,EACrF;AACD;;;AC3WA,IAAAC,gBAOO;AACP,IAAAC,iBAAmC;AACnC,IAAAC,iBAAsB;AA6Df,IAAM,cAAN,cAA0B,qBAAM;AAAC;AAExC,IAAM,WAAW;AAGjB,SAAS,gBAAgB,YAAsC;AAC9D,QAAM,SAAS,WAAW,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,KAAK,GAAG,CAAC;AAClE,MAAI,SAAS,EAAG,QAAO;AACvB,QAAM,KAAK,CAAC,MAAmC;AAC9C,UAAM,IAAI,oBAAI,IAAoB;AAClC,eAAW,KAAK,WAAY,KAAI,EAAE,UAAU,EAAG,GAAE,IAAI,EAAE,MAAM,EAAE,OAAO;AACtE,WAAO;AAAA,EACR;AACA,QAAM,OAAO,GAAG,SAAS,CAAC;AAC1B,QAAM,MAAM,GAAG,MAAM;AACrB,MAAI,KAAK,SAAS,KAAK,KAAK,SAAS,IAAI,KAAM,QAAO;AACtD,aAAW,CAAC,MAAM,OAAO,KAAK,IAAK,KAAI,KAAK,IAAI,IAAI,MAAM,QAAS,QAAO;AAC1E,SAAO;AACR;AAGA,IAAI,aAAa;AAOV,SAAS,oBACf,QACA,MAC4B;AAC5B,QAAM,SAAS,KAAK,UAAU;AAC9B,MAAI,WAAW,uBAAuB,CAAC,KAAK,aAAa,KAAK,CAAC,MAAM,SAAS,KAAK,EAAE,IAAI,CAAC,GAAG;AAC5F,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,MAAI,KAAK,aAAa,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC5E;AAEA,QAAM,OAAO,KAAK,QAAQ,UAAU,EAAE,UAAU;AAChD,QAAM,QAAQ,IAAI,YAAY,IAAI;AAClC,SAAO,MAAM,MAAM,KAAK;AAExB,QAAM,OAAO,KAAK,UAAU;AAC5B,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,WAAW,KAAK,YAAY;AAGlC,QAAM,YACL,OAAO,SAAS,WAAW,KAAK,YAAQ,cAAAC,MAAoB,CAAC,GAAG,EAAE,SAAS,MAAM,CAAC;AAGnF,QAAM,mBAAe,cAAAA,MAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,UAAU,SAAS,EAAE,CAAC;AACjF,QAAM,kBAAc,cAAAA,MAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,WAAW,SAAS,UAAU,CAAC;AAC/F,QAAM,kBAAc,cAAAA,MAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,WAAW,SAAS,OAAU,CAAC;AAI1F,MAAI,UAAkB,CAAC;AAEvB,WAAS,cAAc,GAAqC;AAC3D,UAAM,OAAsB;AAAA,MAC3B,EAAE,MAAM,UAAU,SAAS,EAAE,aAAa;AAAA,MAC1C,EAAE,MAAM,QAAQ,SAAS,KAAK,SAAS;AAAA,IACxC;AACA,eAAW,KAAK,SAAS;AACxB,WAAK,KAAK,EAAE,MAAM,aAAa,SAAS,IAAI,EAAE,IAAI,KAAK,EAAE,KAAK,KAAK,EAAE,OAAO,GAAG,CAAC;AAAA,IACjF;AACA,WAAO;AAAA,EACR;AAMA,QAAM,gBAAY;AAAA,IACjB;AAAA,IACA,CAAC,UACA,cAAAA;AAAA,MACC,CAAC;AAAA,MACD,CAAC,OAAO,YAAY;AACnB,YAAI,IAAI,GAAG;AACV,kBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB,iBAAO;AAAA,QACR;AACA,cAAM,KAAK,IAAI,gBAAgB;AAC/B,YAAI,YAAY;AAChB,SAAC,YAAY;AACZ,gBAAM,QAAgB,CAAC;AACvB,cAAI;AACH,uBAAW,KAAK,KAAK,cAAc;AAClC,oBAAM,MAAM,MAAM;AAAA,oBACjB;AAAA,kBACC,EAAE,QAAQ,OAAO,cAAc,CAAC,GAAG;AAAA,oBAClC,QAAQ,GAAG;AAAA,kBACZ,CAAC;AAAA,gBACF;AAAA,cACD;AACA,kBAAI,UAAW;AACf,oBAAM,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,SAAS,IAAI,QAAQ,CAAC;AAAA,YAC5D;AACA,gBAAI,CAAC,UAAW,SAAQ,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;AAAA,UACjD,SAAS,KAAK;AACb,gBAAI,CAAC,UAAW,SAAQ,KAAK,CAAC,CAAC,qBAAO,GAAG,CAAC,CAAC;AAAA,UAC5C;AAAA,QACD,GAAG;AACH,eAAO;AAAA,UACN,gBAAgB,MAAM;AACrB,wBAAY;AACZ,eAAG,MAAM;AAAA,UACV;AAAA,QACD;AAAA,MACD;AAAA,MACA,EAAE,cAAc,YAAY,MAAM,GAAG,IAAI,cAAc;AAAA,IACxD;AAAA,IACD,EAAE,MAAM,GAAG,IAAI,UAAU;AAAA,EAC1B;AACA,QAAM,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;AAGvC,QAAM,iBAAa,cAAAA;AAAA,IAClB,CAAC,SAAS;AAAA,IACV,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,MACL,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC,EAAE,SAAS,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAEvF,UAAI,QAAQ,QAAW;AACtB,gBAAQ,KAAK,CAAC,CAAC,sBAAQ,CAAC,CAAC;AACzB;AAAA,MACD;AACA,cAAQ,KAAK,QAAQ,MAAM,CAAC;AAAA,IAC7B;AAAA,IACA,EAAE,MAAM,GAAG,IAAI,eAAe,cAAc,UAAU;AAAA,EACvD;AACA,QAAM,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAG5C,QAAM,gBAAY,cAAAA;AAAA,IACjB,CAAC,YAAoB,SAAiB;AAAA,IACtC,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,KACL,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC,EAAE,SAAS,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAEvF,YAAM,SACL,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC,EAAE,SAAS,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAEvF,YAAM,UAAU,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,KAAK,GAAG,CAAC;AAClE,UAAI,OAAO,SAAS,UAAU;AAC7B,gBAAQ,KAAK,EAAE,MAAM,UAAU,MAAM,QAAQ,aAAa,CAAC;AAC3D;AAAA,MACD;AACA,UAAI,SAAS,kBAAkB;AAC9B,YAAI,SAAS,MAAM,CAAC,CAAC,EAAG,SAAQ,KAAK,EAAE,MAAM,MAAM,QAAQ,YAAY,CAAC;AAAA,YACnE,SAAQ,KAAK,EAAE,MAAM,UAAU,WAAW,QAAQ,aAAa,CAAC;AACrE;AAAA,MACD;AACA,cAAQ,KAAK,EAAE,MAAM,WAAW,QAAQ,UAAU,WAAW,QAAQ,aAAa,CAAC;AAAA,IACpF;AAAA,IACA,EAAE,MAAM,GAAG,IAAI,cAAc,cAAc,UAAU;AAAA,EACtD;AACA,QAAM,IAAI,WAAW,EAAE,MAAM,YAAY,CAAC;AAO1C,QAAM,mBAAe,cAAAA;AAAA,IACpB,CAAC,WAAmB,SAAiB;AAAA,IACrC,CAAC,WAAW,UAAU,QAAQ;AAC7B,YAAM,MACL,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC,EAAE,SAAS,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI;AAEzE,YAAM,SACL,UAAU,CAAC,KAAK,QAAQ,UAAU,CAAC,EAAE,SAAS,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAEvF,UAAI,QAAQ,QAAW;AAEtB,YAAI,OAAO,SAAS,YAAY,WAAW,QAAQ,YAAY,UAAU,WAAW;AACnF,mBAAS,YAAY;AAAA,QACtB;AACA;AAAA,MACD;AAEA,gBAAU,CAAC,GAAG,SAAS,GAAG,IAAI,KAAK;AACnC,YAAM,IAAI,IAAI;AACd,UAAI,OAAO;AACX,UAAI,SAAuB;AAC3B,UAAI,OAAO,SAAS,SAAU,QAAO,KAAK;AAAA,eACjC,SAAS,kBAAkB;AACnC,YAAI,SAAS,OAAO,GAAG;AACtB,iBAAO;AACP,mBAAS;AAAA,QACV,MAAO,QAAO,KAAK;AAAA,MACpB,MAAO,QAAO,WAAW,QAAQ,KAAK;AAEtC,UAAI,KAAM,UAAS,MAAM;AAAA,UACpB,cAAa,KAAK,IAAI,CAAC;AAAA,IAC7B;AAAA,IACA,EAAE,MAAM,GAAG,IAAI,WAAW,cAAc,UAAU,oBAAoB,MAAM;AAAA,EAC7E;AACA,QAAM,IAAI,cAAc,EAAE,MAAM,SAAS,CAAC;AAE1C,WAAS,SAAS,QAA4B;AAC7C,QAAI;AACJ,QAAI,WAAW,aAAc,OAAM,QAAQ,MAAM;AAAA,aACxC,WAAW,qBAAqB;AACxC,YAAM,QAAQ,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,SAAS,KAAK,EAAE,IAAI,CAAC;AACtE,YAAM,OAAO,WAAW;AAAA,IACzB,MAAO,OAAM,OAAO,QAAQ,QAAQ,MAAM,CAAC;AAC3C,6BAAM,MAAM;AACX,kBAAY,KAAK,MAAM;AACvB,kBAAY,KAAK,GAAG;AAAA,IACrB,CAAC;AAAA,EACF;AAGA,QAAM,mBAAe,cAAAA;AAAA,IACpB,CAAC,SAAiB;AAAA,IAClB,CAAC,IAAI,IAAI,OAAO;AACf,YAAM,IAAI,GAAG,aAAa,CAAC;AAC3B,UAAI,MAAM,UAAa,MAAM,QAAQ,YAAY,UAAU,WAAW;AACrE,iCAAM,MAAM;AACX,sBAAY,KAAK,OAAO;AACxB,sBAAY,KAAK,IAAI,MAAM,oDAAoD,CAAC;AAAA,QACjF,CAAC;AAAA,MACF;AAAA,IACD;AAAA,IACA,EAAE,MAAM,GAAG,IAAI,kBAAkB,cAAc,UAAU,oBAAoB,MAAM;AAAA,EACpF;AACA,QAAM,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKjD,eAAa,UAAU,MAAM,MAAS;AACtC,eAAa,UAAU,MAAM,MAAS;AACtC,aAAW,UAAU,MAAM,MAAS;AACpC,YAAU,UAAU,MAAM,MAAS;AAEnC,MAAI,UAAU;AAEd,SAAO;AAAA,IACN;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,IACA,MAAM,MAAwB;AAC7B,UAAI,SAAS;AACZ,cAAM,IAAI;AAAA,UACT,wBAAwB,IAAI;AAAA,QAC7B;AAAA,MACD;AACA,gBAAU;AACV,UAAI;AACH,kBAAU,CAAC;AACX,iCAAM,MAAM;AACX,sBAAY,KAAK,SAAS;AAC1B,sBAAY,KAAK,CAAC,CAAC,wBAAU,CAAC,CAAC;AAAA,QAChC,CAAC;AAGD,cAAM,UAAU,aAAa,aAAa,EAAE,aAAa,KAAK,CAAC;AAC/D,qBAAa,KAAK,CAAC;AACnB,eAAO,MAAM;AAAA,MACd,UAAE;AACD,kBAAU;AAAA,MACX;AAAA,IACD;AAAA,EACD;AACD;","names":["import_core","import_core","import_core","import_extra","import_graph","import_core","import_extra","import_graph","import_core","import_extra","batch","import_core","import_extra","import_graph","import_core","import_core","import_extra","import_graph","batch","import_core","import_extra","import_core","batch","import_core","import_extra","import_graph","batch","nodeFactory","batch","import_core","import_extra","import_graph","import_core","import_extra","import_core","import_extra","isNodeLike","keepalive","node","batch","import_core","import_extra","import_graph","ageSeconds","import_core","import_extra","import_graph","NS_PER_SEC","batch","out","ageSeconds","import_core","import_core","import_extra","batch","batch","import_extra","import_core","import_extra","import_graph","policy","import_core","import_extra","import_graph","createNode"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/base/resilience/_internal.ts","../../../src/base/resilience/backoff.ts","../../../src/base/resilience/timeout.ts","../../../src/presets/ai/index.ts","../../../src/presets/ai/agent.ts","../../../src/utils/ai/_internal.ts","../../../src/base/meta/domain-meta.ts","../../../src/utils/messaging/index.ts","../../../src/base/mutation/index.ts","../../../src/presets/ai/agent-loop.ts","../../../src/base/sources/settled.ts","../../../src/utils/ai/agents/chat-stream.ts","../../../src/utils/ai/agents/tool-execution.ts","../../../src/base/resilience/retry.ts","../../../src/utils/ai/agents/tool-registry.ts","../../../src/presets/ai/agent-memory.ts","../../../src/base/composition/distill.ts","../../../src/base/sources/async.ts","../../../src/utils/ai/memory/memory-composers.ts","../../../src/base/utils/decay.ts","../../../src/utils/memory/index.ts","../../../src/utils/ai/prompts/prompt-call.ts","../../../src/utils/ai/prompts/prompt-node.ts","../../../src/presets/ai/agents.ts","../../../src/presets/ai/context/index.ts","../../../src/presets/ai/debate/index.ts"],"sourcesContent":["/**\n * Internal helpers shared by resilience sub-files.\n *\n * Not part of the public surface. The base-layer resilience operators\n * co-located here (`retry.ts`, `status.ts`, `timeout.ts`) import what they\n * need from this file directly; the utils-layer resilience primitives that\n * stayed in `utils/resilience/` (`breaker.ts`, `rate-limiter.ts`,\n * `fallback.ts`) import it top-down via `../../base/resilience/_internal.js`.\n *\n * `NodeOrValue<T>` is the only export re-surfaced publicly — there is no\n * `base/resilience/index.ts`; it ships through `utils/resilience/index.ts`\n * (and `utils/memory/index.ts`). Every resilience primitive that accepts\n * reactive options uses it as the option-arg shape.\n */\n\nimport type { Node, NodeOptions } from \"@graphrefly/pure-ts/core\";\nimport { DATA, type Message } from \"@graphrefly/pure-ts/core\";\n\nexport type ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\nexport function operatorOpts<T>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"derived\", ...opts } as NodeOptions<T>;\n}\n\nexport function clampNonNegative(value: number): number {\n\treturn value < 0 ? 0 : value;\n}\n\nexport function msgVal(m: Message): unknown {\n\treturn m[1];\n}\n\nexport function coerceDelayNs(raw: number): number {\n\tif (typeof raw !== \"number\" || !Number.isFinite(raw)) {\n\t\tthrow new TypeError(\"backoff strategy must return a finite number\");\n\t}\n\treturn raw < 0 ? 0 : raw;\n}\n\nexport function isNode(x: unknown): x is Node {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\t\"cache\" in x &&\n\t\ttypeof (x as Node).subscribe === \"function\"\n\t);\n}\n\n/**\n * Either a literal value or a reactive Node carrying it. Mirrors\n * {@link FallbackInput}'s precedent for \"options that may be reactive.\"\n *\n * Used by {@link timeout} / {@link retry} / {@link rateLimiter} /\n * {@link circuitBreaker} / {@link budgetGate} to accept reactive option\n * configurations (Tier 6.5 3.2, 2026-04-29). Each primitive subscribes\n * to the option Node via {@link resolveReactiveOption} and rebinds\n * internal state per its locked swap-semantic rule (see each primitive's\n * JSDoc for the rule).\n *\n * @category extra\n */\nexport type NodeOrValue<T> = T | Node<T>;\n\n/**\n * Closure-mirror helper for `NodeOrValue<T>` options\n * (COMPOSITION-GUIDE §28). Returns:\n * - `current()` — read the latest value (cached at construction; updated\n * on each Node DATA emission).\n * - `unsub()` — release the subscription. Static-form arg never\n * subscribes; `unsub` is a no-op there.\n *\n * `onChange` fires on each DATA after the initial value (skips the\n * cache-seed read). Use to rebind primitive-internal state per the\n * primitive's locked swap-semantic rule.\n *\n * @internal\n */\nexport function resolveReactiveOption<T>(\n\targ: NodeOrValue<T>,\n\tonChange?: (next: T) => void,\n): { current: () => T; unsub: () => void } {\n\tif (!isNode(arg)) {\n\t\treturn { current: () => arg, unsub: () => undefined };\n\t}\n\tconst node = arg as Node<T>;\n\tlet latest: T = node.cache as T;\n\tconst unsub = node.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA) {\n\t\t\t\tlatest = m[1] as T;\n\t\t\t\tif (onChange) onChange(latest);\n\t\t\t}\n\t\t}\n\t});\n\treturn {\n\t\tcurrent: () => latest,\n\t\tunsub,\n\t};\n}\n\nexport function isThenable(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nexport function isAsyncIterable(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n","/**\n * Backoff strategies for {@link retry} (roadmap §3.1). Delays are in **nanoseconds**.\n *\n * Convention: all graphrefly-ts timestamps and durations use nanoseconds (`_ns` suffix).\n * 1 second = 1_000_000_000 ns, 1 ms = 1_000_000 ns.\n */\n\nexport const NS_PER_MS = 1_000_000;\nexport const NS_PER_SEC = 1_000_000_000;\n\nexport type JitterMode = \"none\" | \"full\" | \"equal\";\n\nexport type BackoffPreset =\n\t| \"constant\"\n\t| \"linear\"\n\t| \"exponential\"\n\t| \"fibonacci\"\n\t| \"decorrelatedJitter\";\n\n/** `(attempt, error?, previousDelayNs?) => delayNs | null` — `null` means zero delay. */\nexport type BackoffStrategy = (\n\tattempt: number,\n\terror?: unknown,\n\tprevDelayNs?: number | null,\n) => number | null;\n\nfunction clampNonNegative(value: number): number {\n\treturn value < 0 ? 0 : value;\n}\n\nfunction applyJitter(delay: number, jitter: JitterMode): number {\n\tif (jitter === \"none\") return delay;\n\tif (jitter === \"full\") return Math.random() * delay;\n\treturn delay / 2 + Math.random() * (delay / 2);\n}\n\nfunction randomBetween(min: number, max: number): number {\n\treturn min + Math.random() * (max - min);\n}\n\n/**\n * Builds a strategy that always returns the same delay in nanoseconds.\n *\n * @param delayNs - Non-negative delay in nanoseconds; values below zero are clamped to zero.\n * @returns `BackoffStrategy` for use with {@link retry} or custom timers.\n *\n * @example\n * ```ts\n * import { constant, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, { count: 3, backoff: constant(0.25 * NS_PER_SEC) });\n * ```\n *\n * @category extra\n */\nexport function constant(delayNs: number): BackoffStrategy {\n\tconst safe = clampNonNegative(delayNs);\n\treturn () => safe;\n}\n\n/**\n * Builds linear backoff: `baseNs + stepNs * attempt` (`stepNs` defaults to `baseNs`).\n *\n * @param baseNs - Base delay in nanoseconds (clamped non-negative).\n * @param stepNs - Added per retry attempt in nanoseconds (clamped non-negative).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { linear, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * // Attempt 0 → 1 s, attempt 1 → 2 s, attempt 2 → 3 s …\n * const out = retry(source, { count: 4, backoff: linear(NS_PER_SEC) });\n * ```\n *\n * @category extra\n */\nexport function linear(baseNs: number, stepNs?: number): BackoffStrategy {\n\tconst safeBase = clampNonNegative(baseNs);\n\tconst safeStep = stepNs === undefined ? safeBase : clampNonNegative(stepNs);\n\treturn (attempt: number) => safeBase + safeStep * Math.max(0, attempt);\n}\n\nexport type ExponentialBackoffOptions = {\n\tbaseNs?: number;\n\tfactor?: number;\n\tmaxDelayNs?: number;\n\tjitter?: JitterMode;\n};\n\n/**\n * Builds exponential backoff in nanoseconds, capped by `maxDelayNs`, with optional jitter.\n *\n * @param options - Base, factor, cap, and jitter mode.\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @remarks\n * **Jitter:** `\"full\"` spreads delay across `[0, delay]`; `\"equal\"` uses `[delay/2, delay]`.\n *\n * @example\n * ```ts\n * import { exponential, retry, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * // 100 ms → 200 ms → 400 ms … capped at 30 s, with full jitter\n * const out = retry(source, {\n * count: 5,\n * backoff: exponential({ baseNs: 100 * NS_PER_SEC / 1000, jitter: \"full\" }),\n * });\n * ```\n *\n * @category extra\n */\nexport function exponential(options?: ExponentialBackoffOptions): BackoffStrategy {\n\tconst baseNs = clampNonNegative(options?.baseNs ?? 100 * NS_PER_MS);\n\tconst factor = options?.factor !== undefined && options.factor < 1 ? 1 : (options?.factor ?? 2);\n\tconst maxDelayNs = clampNonNegative(options?.maxDelayNs ?? 30 * NS_PER_SEC);\n\tconst jitter = options?.jitter ?? \"none\";\n\n\treturn (attempt: number) => {\n\t\tlet delay: number;\n\t\tif (baseNs === 0) {\n\t\t\tdelay = 0;\n\t\t} else if (factor === 1) {\n\t\t\tdelay = baseNs;\n\t\t} else {\n\t\t\tconst capRatio = maxDelayNs / baseNs;\n\t\t\tlet growth = 1;\n\t\t\tfor (let i = 0; i < Math.max(0, attempt); i++) {\n\t\t\t\tif (growth >= capRatio) {\n\t\t\t\t\tgrowth = capRatio;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tgrowth *= factor;\n\t\t\t}\n\t\t\tdelay = baseNs * growth;\n\t\t\tif (delay > maxDelayNs) delay = maxDelayNs;\n\t\t}\n\t\treturn applyJitter(delay, jitter);\n\t};\n}\n\n/**\n * Builds Fibonacci-scaled delays: `1, 2, 3, 5, … × baseNs`, capped at `maxDelayNs`.\n *\n * @param baseNs - Multiplier applied to the Fibonacci unit (default `100ms` in nanoseconds).\n * @param maxDelayNs - Upper bound in nanoseconds (default `30s`).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { fibonacci, retry, NS_PER_MS } from \"@graphrefly/graphrefly-ts\";\n *\n * // Delays: 100 ms, 200 ms, 300 ms, 500 ms, 800 ms … (× 100 ms base)\n * const out = retry(source, { count: 5, backoff: fibonacci(100 * NS_PER_MS) });\n * ```\n *\n * @category extra\n */\nexport function fibonacci(baseNs = 100 * NS_PER_MS, maxDelayNs = 30 * NS_PER_SEC): BackoffStrategy {\n\tconst safeBase = clampNonNegative(baseNs);\n\tconst safeMax = clampNonNegative(maxDelayNs);\n\n\tfunction fibUnit(attempt: number): number {\n\t\tif (attempt <= 0) return 1;\n\t\tlet prev = 1;\n\t\tlet cur = 2;\n\t\tfor (let i = 1; i < attempt; i++) {\n\t\t\tconst next = prev + cur;\n\t\t\tprev = cur;\n\t\t\tcur = next;\n\t\t}\n\t\treturn cur;\n\t}\n\n\treturn (attempt: number) => {\n\t\tconst raw = fibUnit(attempt) * safeBase;\n\t\treturn raw <= safeMax ? raw : safeMax;\n\t};\n}\n\n/**\n * Decorrelated jitter (AWS-recommended): `random(baseNs, min(maxNs, lastDelay * 3))`.\n *\n * Stateless — uses `prevDelayNs` (passed by the consumer) instead of closure state.\n * Safe to share across concurrent retry sequences.\n *\n * @param baseNs - Floor of the random range (default `100ms` in nanoseconds).\n * @param maxNs - Ceiling cap (default `30s` in nanoseconds).\n * @returns `BackoffStrategy` for {@link retry}.\n *\n * @example\n * ```ts\n * import { decorrelatedJitter, retry, NS_PER_MS, NS_PER_SEC } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, {\n * count: 6,\n * backoff: decorrelatedJitter(100 * NS_PER_MS, 10 * NS_PER_SEC),\n * });\n * ```\n *\n * @category extra\n */\nexport function decorrelatedJitter(\n\tbaseNs = 100 * NS_PER_MS,\n\tmaxNs = 30 * NS_PER_SEC,\n): BackoffStrategy {\n\treturn (_attempt, _error, prevDelayNs) => {\n\t\tconst last = prevDelayNs ?? baseNs;\n\t\tconst ceiling = Math.min(maxNs, last * 3);\n\t\treturn randomBetween(baseNs, ceiling);\n\t};\n}\n\n/**\n * Decorator that caps any strategy at `maxAttempts`. Returns `null` (stop retrying) after the cap.\n *\n * @param strategy - Inner strategy to wrap.\n * @param maxAttempts - Maximum number of attempts (inclusive).\n * @returns Wrapped `BackoffStrategy`.\n *\n * @example\n * ```ts\n * import { withMaxAttempts, exponential } from \"@graphrefly/graphrefly-ts\";\n *\n * const capped = withMaxAttempts(exponential(), 3);\n * capped(3); // null — no more retries beyond attempt 3\n * ```\n *\n * @category extra\n */\nexport function withMaxAttempts(strategy: BackoffStrategy, maxAttempts: number): BackoffStrategy {\n\treturn (attempt, error, prevDelayNs) => {\n\t\tif (attempt >= maxAttempts) return null;\n\t\treturn strategy(attempt, error, prevDelayNs);\n\t};\n}\n\n/**\n * Maps a preset name to a concrete {@link BackoffStrategy} with library-default parameters.\n *\n * @param name - One of `constant`, `linear`, `exponential`, `fibonacci`, or `decorrelatedJitter`.\n * @returns Configured strategy with default parameters.\n * @throws Error when `name` is not a known preset.\n *\n * @example\n * ```ts\n * import { resolveBackoffPreset, retry } from \"@graphrefly/graphrefly-ts\";\n *\n * const out = retry(source, { count: 3, backoff: resolveBackoffPreset(\"exponential\") });\n * // Equivalent to retry(source, { count: 3, backoff: exponential() })\n * ```\n *\n * @category extra\n */\nexport function resolveBackoffPreset(name: BackoffPreset): BackoffStrategy {\n\tif (name === \"constant\") return constant(1 * NS_PER_SEC);\n\tif (name === \"linear\") return linear(1 * NS_PER_SEC);\n\tif (name === \"exponential\") return exponential();\n\tif (name === \"fibonacci\") return fibonacci();\n\tif (name === \"decorrelatedJitter\") return decorrelatedJitter();\n\tthrow new Error(\n\t\t`Unknown backoff preset: \"${String(name)}\". Use one of: constant, linear, exponential, fibonacci, decorrelatedJitter`,\n\t);\n}\n","/**\n * Timeout — emits `ERROR` with `TimeoutError` if no `DATA` arrives within the deadline.\n *\n * §3.1c — caching, fallback & composition sugar. Uses\n * `core/clock.js`-style nanoseconds and a `ResettableTimer` so the deadline\n * resets on each DATA. Distinct from the `operators/control.ts` timeout\n * (which forwards a caller-supplied error/value) — this one is the\n * resilience family's \"deadline → ERROR\" primitive.\n *\n * **DS-13.5.B (locked 2026-05-01).** Pre-1.0 break: returns\n * {@link TimeoutBundle} with `node` + `timeoutState` companion. Opts\n * accept `Partial<TimeoutOptions>` or `Node<Partial<TimeoutOptions>>`\n * (object-shape, replacing the old `NodeOrValue<number>` flat shape).\n * State preservation across rebind: `ns` change does NOT reset the\n * in-flight deadline — new `ns` applies to next attempt only.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\tmonotonicNs,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n\tResettableTimer,\n\tTEARDOWN,\n} from \"@graphrefly/pure-ts/core\";\nimport { isNode, operatorOpts } from \"./_internal.js\";\nimport { NS_PER_MS } from \"./backoff.js\";\n\n/**\n * Thrown by {@link withTimeout} when no `DATA` arrives within the deadline.\n *\n * @category extra\n */\nexport class TimeoutError extends Error {\n\toverride name = \"TimeoutError\";\n\tconstructor(ns: number) {\n\t\tsuper(`Timed out after ${ns / NS_PER_MS}ms`);\n\t}\n}\n\n/**\n * Options accepted by {@link withTimeout}.\n *\n * - `ns` — deadline in nanoseconds (must be `> 0`). Required at the\n * first opts settle; missing / non-positive values throw at\n * construction.\n * - `meta` — optional metadata merged onto the result node's `meta`\n * for describe()/explain() introspection. Reactive `meta` updates\n * are picked up on the next attempt's emission.\n *\n * @category extra/resilience\n */\nexport interface TimeoutOptions {\n\tns: number;\n\tmeta?: Record<string, unknown>;\n}\n\n/**\n * Lifecycle-shaped state companion emitted by {@link withTimeout}.\n *\n * Default `equals` dedups on the `status` field — subscribers don't\n * re-fire on identical-shape transitions, but DO fire on every state\n * transition AND on payload changes within the same status (e.g. when\n * `running.startedAt_ns` advances on a fresh attempt).\n *\n * @category extra/resilience\n */\nexport type TimeoutState =\n\t| { status: \"pending\" }\n\t| { status: \"running\"; startedAt_ns: number; deadline_ns: number }\n\t| { status: \"completed\"; settledAt_ns: number }\n\t| { status: \"errored\"; firedAt_ns: number; deadline_ns: number };\n\n/**\n * Bundle returned by {@link withTimeout}: the timeout-wrapped output node and\n * its lifecycle-shaped state companion.\n *\n * **Single-subscriber / pipeline-only contract (DS-13.5.B QA, N1, 2026-05-03).**\n * The `timeoutState` companion is allocated once at factory time and shared\n * across all subscribers to `node`. With one subscriber (the typical use\n * case — wire `node` into your downstream chain, optionally observe\n * `timeoutState` separately) the companion reflects a coherent timeline.\n * With **two or more subscribers** to `node`, each subscriber re-runs the\n * producer body and writes into the same `timeoutState`, which can flip\n * between states from different in-flight machines. Don't fan out\n * `node` to multiple subscribers and rely on `timeoutState` accuracy\n * unless you use {@link keepalive} / {@link share}-style consolidation.\n *\n * @category extra/resilience\n */\nexport interface TimeoutBundle<T> {\n\tnode: Node<T>;\n\ttimeoutState: Node<TimeoutState>;\n}\n\ninterface TimeoutExtraOpts {\n\tmeta?: Record<string, unknown>;\n}\n\n/**\n * Wrap `source` with a deadline. If no `DATA` arrives within `opts.ns`\n * nanoseconds, the result node emits `[[ERROR, TimeoutError]]` and\n * transitions `timeoutState` to `\"errored\"`.\n *\n * The timer starts on subscription and resets on each `DATA`. `DIRTY`\n * does NOT reset the timer. Terminal messages (`COMPLETE` / `ERROR`)\n * cancel the timer.\n *\n * **Reactive opts (DS-13.5.B, locked 2026-05-01).**\n *\n * - Static-form callers pass `Partial<TimeoutOptions>` (today's path).\n * `ns` is validated at construction; missing / non-positive throws\n * `RangeError`.\n * - Reactive-form callers pass `Node<Partial<TimeoutOptions>>` — each\n * emission shallow-merges over the prior opts. Empty `{}` emissions\n * are no-ops (no rebind, no companion fire). Mid-flight opts swap\n * does NOT reset the in-flight deadline; new `ns` applies to the\n * next `startTimer()` call.\n * - When the opts Node has `cache === undefined` (SENTINEL: no opts\n * emitted yet), the source is paused until the first valid opts\n * settle. The first valid settle must carry `ns > 0` or the timer\n * layer emits an ERROR (downstream observable) — distinct from the\n * construction-time `RangeError` thrown for static / cache-defined\n * invalid values.\n *\n * @param source - Upstream node.\n * @param opts - `Partial<TimeoutOptions>` (static) or\n * `Node<Partial<TimeoutOptions>>` (reactive).\n * @param extraOpts - Forwarded factory metadata (meta field merged\n * onto the result node).\n * @returns {@link TimeoutBundle} with `node` and `timeoutState`.\n *\n * @throws {RangeError} when the first opts settle is missing or has\n * non-positive `ns`.\n *\n * @category extra\n */\nexport function withTimeout<T>(\n\tsource: Node<T>,\n\topts: Partial<TimeoutOptions> | Node<Partial<TimeoutOptions>>,\n\textraOpts?: TimeoutExtraOpts,\n): TimeoutBundle<T> {\n\tconst isReactive = isNode(opts);\n\n\t// Construction-time validation:\n\t// - Static form: validate the supplied object eagerly.\n\t// - Node form with defined cache: validate the cache value eagerly.\n\t// - Node form with `cache === undefined`: defer validation to first\n\t// DATA emission; source is paused in the meantime.\n\tlet latestOpts: TimeoutOptions | null = null;\n\tif (!isReactive) {\n\t\tconst staticOpts = opts as Partial<TimeoutOptions>;\n\t\tif (\n\t\t\tstaticOpts.ns === undefined ||\n\t\t\ttypeof staticOpts.ns !== \"number\" ||\n\t\t\t!Number.isFinite(staticOpts.ns) ||\n\t\t\tstaticOpts.ns <= 0\n\t\t) {\n\t\t\tthrow new RangeError(\"withTimeout: opts.ns must be a positive finite number\");\n\t\t}\n\t\tlatestOpts = {\n\t\t\tns: staticOpts.ns,\n\t\t\t...(staticOpts.meta != null ? { meta: staticOpts.meta } : {}),\n\t\t};\n\t} else {\n\t\tconst cached = (opts as Node<Partial<TimeoutOptions>>).cache as\n\t\t\t| Partial<TimeoutOptions>\n\t\t\t| undefined;\n\t\tif (cached !== undefined) {\n\t\t\tif (\n\t\t\t\tcached.ns === undefined ||\n\t\t\t\ttypeof cached.ns !== \"number\" ||\n\t\t\t\t!Number.isFinite(cached.ns) ||\n\t\t\t\tcached.ns <= 0\n\t\t\t) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t\"withTimeout: opts.ns must be a positive finite number on first settle\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tlatestOpts = {\n\t\t\t\tns: cached.ns,\n\t\t\t\t...(cached.meta != null ? { meta: cached.meta } : {}),\n\t\t\t};\n\t\t}\n\t}\n\n\tconst callerMeta = extraOpts?.meta;\n\tconst factoryArgs: Record<string, unknown> = isReactive\n\t\t? { ns: \"Node<Partial<TimeoutOptions>>\" }\n\t\t: { ns: latestOpts!.ns };\n\n\t// Companion state node — lifecycle-shaped. Default Object.is-on-status\n\t// dedup so identical-shape transitions don't re-fire downstream.\n\tconst timeoutState = node<TimeoutState>([], {\n\t\tname: \"timeoutState\",\n\t\tdescribeKind: \"state\",\n\t\tinitial: { status: \"pending\" },\n\t\tequals: (a, b) =>\n\t\t\ta === b ||\n\t\t\t(a != null &&\n\t\t\t\tb != null &&\n\t\t\t\ttypeof a === \"object\" &&\n\t\t\t\ttypeof b === \"object\" &&\n\t\t\t\t(a as { status: string }).status === (b as { status: string }).status &&\n\t\t\t\tJSON.stringify(a) === JSON.stringify(b)),\n\t});\n\n\tconst out = node<T>(\n\t\t(_data, a) => {\n\t\t\tlet stopped = false;\n\t\t\tlet lastDeadlineNs = 0;\n\t\t\tconst timer = new ResettableTimer();\n\t\t\tlet optsUnsub: (() => void) | null = null;\n\t\t\tlet srcUnsub: (() => void) | null = null;\n\n\t\t\tfunction emitState(next: TimeoutState): void {\n\t\t\t\ttimeoutState.down([[DIRTY], [DATA, next]]);\n\t\t\t}\n\n\t\t\tfunction startTimer(): void {\n\t\t\t\tif (stopped) return;\n\t\t\t\t// QA A4 (2026-05-03): defensive guard — `latestOpts.ns`\n\t\t\t\t// reaching `undefined` / `NaN` / non-finite is a Class-of-\n\t\t\t\t// bugs source: an explicit `{ ns: undefined }` emit would\n\t\t\t\t// pass the per-key validation (which only checks\n\t\t\t\t// `next.ns !== undefined`) and shallow-merge over a valid\n\t\t\t\t// prior `ns`. Without this guard, `delayMs = NaN`, which\n\t\t\t\t// `setTimeout` treats as `0` → spurious immediate timeout.\n\t\t\t\tif (\n\t\t\t\t\tlatestOpts == null ||\n\t\t\t\t\ttypeof latestOpts.ns !== \"number\" ||\n\t\t\t\t\t!Number.isFinite(latestOpts.ns) ||\n\t\t\t\t\tlatestOpts.ns <= 0\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst ns = latestOpts.ns;\n\t\t\t\tlastDeadlineNs = ns;\n\t\t\t\tconst startedAt = monotonicNs();\n\t\t\t\tconst delayMs = ns / NS_PER_MS;\n\t\t\t\temitState({\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t\tstartedAt_ns: startedAt,\n\t\t\t\t\tdeadline_ns: ns,\n\t\t\t\t});\n\t\t\t\ttimer.start(delayMs, () => {\n\t\t\t\t\tif (stopped) return;\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tsrcUnsub?.();\n\t\t\t\t\temitState({\n\t\t\t\t\t\tstatus: \"errored\",\n\t\t\t\t\t\tfiredAt_ns: monotonicNs(),\n\t\t\t\t\t\tdeadline_ns: ns,\n\t\t\t\t\t});\n\t\t\t\t\ta.down([[ERROR, new TimeoutError(ns)]]);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tfunction attachSource(): void {\n\t\t\t\tif (srcUnsub != null || stopped) return;\n\t\t\t\tsrcUnsub = source.subscribe((msgs) => {\n\t\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\t\tif (stopped) return;\n\t\t\t\t\t\tconst t = m[0];\n\t\t\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\t\t\telse if (t === DATA) {\n\t\t\t\t\t\t\tstartTimer();\n\t\t\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t\t\ttimer.cancel();\n\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\temitState({\n\t\t\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\t\t\tsettledAt_ns: monotonicNs(),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\t\ttimer.cancel();\n\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\temitState({\n\t\t\t\t\t\t\t\tstatus: \"errored\",\n\t\t\t\t\t\t\t\tfiredAt_ns: monotonicNs(),\n\t\t\t\t\t\t\t\tdeadline_ns: lastDeadlineNs,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} else if (t === TEARDOWN) {\n\t\t\t\t\t\t\ttimer.cancel();\n\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t} else a.down([m]);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\t// Kick the initial timer if we already have valid opts.\n\t\t\t\tif (latestOpts != null && latestOpts.ns > 0) {\n\t\t\t\t\tstartTimer();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isReactive) {\n\t\t\t\tconst optsNode = opts as Node<Partial<TimeoutOptions>>;\n\t\t\t\toptsUnsub = optsNode.subscribe((msgs) => {\n\t\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\t\t\tconst next = m[1] as Partial<TimeoutOptions>;\n\t\t\t\t\t\tif (next == null || typeof next !== \"object\") continue;\n\t\t\t\t\t\t// Empty `{}` emit is a no-op (lock spec).\n\t\t\t\t\t\tconst keys = Object.keys(next);\n\t\t\t\t\t\tif (keys.length === 0) continue;\n\t\t\t\t\t\t// QA A4 (2026-05-03): validate ns whenever it APPEARS\n\t\t\t\t\t\t// in the emit's keys — including `{ ns: undefined }`,\n\t\t\t\t\t\t// which would otherwise skip validation and shallow-\n\t\t\t\t\t\t// merge over a valid prior `ns` with `undefined`,\n\t\t\t\t\t\t// producing `delayMs = NaN` ≈ 0 ms in startTimer().\n\t\t\t\t\t\t// `'ns' in next` covers both \"explicitly undefined\"\n\t\t\t\t\t\t// and \"explicitly invalid\" forms.\n\t\t\t\t\t\tif (\"ns\" in next) {\n\t\t\t\t\t\t\tif (typeof next.ns !== \"number\" || !Number.isFinite(next.ns) || next.ns <= 0) {\n\t\t\t\t\t\t\t\tif (latestOpts == null) {\n\t\t\t\t\t\t\t\t\t// First settle invalid — emit ERROR rather\n\t\t\t\t\t\t\t\t\t// than throw (mid-subscribe; sync throw\n\t\t\t\t\t\t\t\t\t// would corrupt the host scheduler).\n\t\t\t\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\t\t\ta.down([\n\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\tERROR,\n\t\t\t\t\t\t\t\t\t\t\tnew RangeError(\n\t\t\t\t\t\t\t\t\t\t\t\t\"withTimeout: opts.ns must be a positive finite number on first settle\",\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Ignore invalid mid-flight ns updates; keep\n\t\t\t\t\t\t\t\t// prior latestOpts.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst wasNull = latestOpts == null;\n\t\t\t\t\t\tlatestOpts = {\n\t\t\t\t\t\t\t...(latestOpts ?? { ns: 0 }),\n\t\t\t\t\t\t\t...next,\n\t\t\t\t\t\t} as TimeoutOptions;\n\t\t\t\t\t\t// First valid settle activates the source attach.\n\t\t\t\t\t\tif (wasNull && latestOpts.ns > 0) {\n\t\t\t\t\t\t\tattachSource();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Static form: attach immediately. Reactive form with defined\n\t\t\t// cache also attaches immediately (latestOpts pre-populated).\n\t\t\tif (latestOpts != null) {\n\t\t\t\tattachSource();\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tstopped = true;\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tif (srcUnsub) srcUnsub();\n\t\t\t\t\tif (optsUnsub) optsUnsub();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: source.cache,\n\t\t\tmeta: { ...(callerMeta ?? {}), ...factoryTag(\"withTimeout\", factoryArgs) },\n\t\t},\n\t);\n\n\treturn { node: out, timeoutState };\n}\n","/**\n * AI presets — opinionated compositions of ai utils.\n *\n * @module\n */\n\nexport * from \"./agent.js\";\nexport * from \"./agent-loop.js\";\nexport * from \"./agent-memory.js\";\nexport * from \"./agents.js\";\nexport * from \"./context/index.js\";\nexport * from \"./debate/index.js\";\n","/**\n * Phase 13.G — `AgentBundle<TIn, TOut>` interface + `class AgentGraph extends Graph`.\n *\n * Source: `archive/docs/SESSION-multi-agent-gap-analysis.md` G1 lock B.\n *\n * Composes the existing substrate (`agentLoop`, `toolRegistry`,\n * `agentMemory`) into a typed inbox/outbox subgraph that other parts of a\n * multi-agent system can wire to. Sibling preset `agent()` (in\n * `./agents.ts`) is the ergonomic factory; this file is the contract.\n *\n * **Cross-cut #1 lock (no `agent.run()`):** caller-side runtime entry is\n * `bundle.in.emit(input)` + `awaitSettled(bundle.out)`. The legacy\n * `agentLoop.run()` is still available on `bundle.graph.loop` for\n * single-shot Promise-bridge use cases, but `agent()` does NOT expose a\n * `run()` method on the bundle.\n *\n * **Memory partition default:** private memory per agent (each `agent(...)`\n * call creates its own `AgentMemoryGraph` if none passed). Pass an explicit\n * shared instance for §29 handoff context-transfer.\n */\n\nimport { batch, DATA, INVALIDATE, type Node, node, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { keepalive } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../../utils/ai/_internal.js\";\nimport type {\n\tInputTokens,\n\tLLMAdapter,\n\tLLMResponse,\n\tOutputTokens,\n\tTokenUsage,\n\tToolDefinition,\n} from \"../../utils/ai/adapters/core/types.js\";\nimport {\n\ttype SubscriptionGraph,\n\tsubscription,\n\ttype TopicGraph,\n\ttopic,\n} from \"../../utils/messaging/index.js\";\nimport { type AgentLoopGraph, agentLoop } from \"./agent-loop.js\";\nimport type { AgentMemoryGraph } from \"./agent-memory.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Lifecycle status of an {@link AgentGraph}.\n *\n * - `idle` — no input has been received since construction or last reset.\n * - `running` — inputs are flowing through the underlying agentLoop\n * (collapses the loop's `thinking` + `acting` substates so consumers\n * don't have to model the tool-call inner loop).\n * - `verifying` — verifier subgraph is in flight (reserved; lights up when\n * the verifier slot is added in a future wave per G7 recipe).\n * - `done` — the most recent input has settled with a verified response.\n * - `error` — the loop or verifier produced a terminal error.\n *\n * **Note (Phase 13.G, 2026-05-01):** v1 of `agent()` has no built-in\n * verifier slot — `verifying` is reserved but never produced. When a\n * verifier consumer surfaces, this enum widens (non-breaking type\n * widening; existing consumers see the same `idle | running | done | error`\n * subset).\n */\nexport type AgentStatus = \"idle\" | \"running\" | \"verifying\" | \"done\" | \"error\";\n\n/**\n * Aggregated cost for an agent's run, surfaced as a `Node<CostState>` on\n * the bundle. **Wraps the canonical {@link TokenUsage}** so consumers get\n * the full provider-disaggregated token classes (cache-read /\n * cache-write-5m / cache-write-1h / audio / image / video / tool-use /\n * reasoning / prediction-accepted / prediction-rejected / extensions /\n * auxiliary non-token costs / raw escape-hatch) without losing fidelity\n * for downstream pricing. USD conversion is a downstream `derived` over\n * `usage`.\n *\n * - `usage` — accumulated {@link TokenUsage} across all turns of the\n * current input.\n * - `turns` — number of completed agentLoop iterations (LLM invocations).\n *\n * **Counter scope:** resets to {@link ZERO_COST} on each new `bundle.in`\n * emit (per-input cost rather than per-agent-lifetime). Sum across multiple\n * inputs by snapshotting `cost` at `done` and accumulating externally —\n * a per-lifetime cost is a downstream `scan` over this.\n *\n * **Helpers.** Use `sumInputTokens(usage)` / `sumOutputTokens(usage)` from\n * `@graphrefly/graphrefly-ts` to flatten to scalars when the caller wants\n * a single number.\n */\nexport interface CostState {\n\treadonly usage: TokenUsage;\n\treadonly turns: number;\n}\n\nconst EMPTY_INPUT: InputTokens = Object.freeze({ regular: 0 });\nconst EMPTY_OUTPUT: OutputTokens = Object.freeze({ regular: 0 });\nconst EMPTY_USAGE: TokenUsage = Object.freeze({ input: EMPTY_INPUT, output: EMPTY_OUTPUT });\n\n/** Empty cost. Used as the initial value and the per-input reset baseline. */\nexport const ZERO_COST: CostState = Object.freeze({ usage: EMPTY_USAGE, turns: 0 });\n\n// ---------------------------------------------------------------------------\n// TokenUsage accumulator\n// ---------------------------------------------------------------------------\n\nfunction addOptional(a: number | undefined, b: number | undefined): number | undefined {\n\tif (a == null && b == null) return undefined;\n\treturn (a ?? 0) + (b ?? 0);\n}\n\nfunction addExtensions(\n\ta: Record<string, number> | undefined,\n\tb: Record<string, number> | undefined,\n): Record<string, number> | undefined {\n\tif (a == null && b == null) return undefined;\n\tconst out: Record<string, number> = { ...(a ?? {}) };\n\tfor (const [k, v] of Object.entries(b ?? {})) {\n\t\tout[k] = (out[k] ?? 0) + v;\n\t}\n\treturn out;\n}\n\n/**\n * Accumulates two {@link TokenUsage} snapshots. All field classes are\n * summed; optional fields propagate as `undefined` when absent from both\n * sides, otherwise treated as 0 for the missing side. `auxiliary` and\n * `extensions` merge by key. `raw` is dropped — it's a per-call escape\n * hatch, not summable.\n *\n * @category extra\n */\nexport function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage {\n\tconst out: TokenUsage = {\n\t\tinput: {\n\t\t\tregular: a.input.regular + b.input.regular,\n\t\t\t...(addOptional(a.input.cacheRead, b.input.cacheRead) !== undefined && {\n\t\t\t\tcacheRead: addOptional(a.input.cacheRead, b.input.cacheRead) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) !== undefined && {\n\t\t\t\tcacheWrite5m: addOptional(a.input.cacheWrite5m, b.input.cacheWrite5m) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) !== undefined && {\n\t\t\t\tcacheWrite1h: addOptional(a.input.cacheWrite1h, b.input.cacheWrite1h) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) !== undefined && {\n\t\t\t\tcacheWriteOther: addOptional(a.input.cacheWriteOther, b.input.cacheWriteOther) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.audio, b.input.audio) !== undefined && {\n\t\t\t\taudio: addOptional(a.input.audio, b.input.audio) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.image, b.input.image) !== undefined && {\n\t\t\t\timage: addOptional(a.input.image, b.input.image) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.video, b.input.video) !== undefined && {\n\t\t\t\tvideo: addOptional(a.input.video, b.input.video) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.input.toolUse, b.input.toolUse) !== undefined && {\n\t\t\t\ttoolUse: addOptional(a.input.toolUse, b.input.toolUse) as number,\n\t\t\t}),\n\t\t\t...(addExtensions(a.input.extensions, b.input.extensions) !== undefined && {\n\t\t\t\textensions: addExtensions(a.input.extensions, b.input.extensions) as Record<string, number>,\n\t\t\t}),\n\t\t},\n\t\toutput: {\n\t\t\tregular: a.output.regular + b.output.regular,\n\t\t\t...(addOptional(a.output.reasoning, b.output.reasoning) !== undefined && {\n\t\t\t\treasoning: addOptional(a.output.reasoning, b.output.reasoning) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.audio, b.output.audio) !== undefined && {\n\t\t\t\taudio: addOptional(a.output.audio, b.output.audio) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.predictionAccepted, b.output.predictionAccepted) !== undefined && {\n\t\t\t\tpredictionAccepted: addOptional(\n\t\t\t\t\ta.output.predictionAccepted,\n\t\t\t\t\tb.output.predictionAccepted,\n\t\t\t\t) as number,\n\t\t\t}),\n\t\t\t...(addOptional(a.output.predictionRejected, b.output.predictionRejected) !== undefined && {\n\t\t\t\tpredictionRejected: addOptional(\n\t\t\t\t\ta.output.predictionRejected,\n\t\t\t\t\tb.output.predictionRejected,\n\t\t\t\t) as number,\n\t\t\t}),\n\t\t\t...(addExtensions(a.output.extensions, b.output.extensions) !== undefined && {\n\t\t\t\textensions: addExtensions(a.output.extensions, b.output.extensions) as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\tnumber\n\t\t\t\t>,\n\t\t\t}),\n\t\t},\n\t\t...(addExtensions(a.auxiliary, b.auxiliary) !== undefined && {\n\t\t\tauxiliary: addExtensions(a.auxiliary, b.auxiliary) as Record<string, number>,\n\t\t}),\n\t};\n\treturn out;\n}\n\n/**\n * Spec for {@link agent} (in `./agents.ts`). Required fields are minimal —\n * `name` and `adapter` cover the common case where the input is a string\n * and the output is the raw `LLMResponse`. Optional fields shape the\n * agent's behavior:\n *\n * - **Mappers** (`inMapper` / `outMapper`) translate between caller-typed\n * `TIn` / `TOut` and the loop's internal `string` / `LLMResponse`. Default\n * identity mappers are wired automatically when `TIn` extends `string`\n * and `TOut` extends `LLMResponse`.\n * - **`tools`** is a reactive `NodeInput<readonly ToolDefinition[]>` —\n * `agent()` subscribes and reconciles the underlying `toolRegistry`'s\n * registrations on each emit. Static-array form is also accepted.\n * - **`memory`** is an explicit `AgentMemoryGraph` instance for shared\n * memory across agents (§29 handoff context transfer). Default: private\n * memory per agent (each `agent()` call mints its own).\n * - **`maxIterations`** caps the underlying agentLoop's tool-call inner\n * loop. Default 10 (matches `agentLoop`).\n * - **Verifier slot** is intentionally not in v1 — G7 reframe locks it as\n * a caller-composed recipe. When a real consumer surfaces, a\n * `verifier?: (out: Node<TOut>) => NodeInput<VerifierResult>` field\n * lands here additively.\n */\nexport interface AgentSpec<TIn, TOut> {\n\t/** Local mount name when wired to a parent graph. Required. */\n\treadonly name: string;\n\t/** LLM adapter for the underlying agentLoop. Required. */\n\treadonly adapter: LLMAdapter;\n\t/** Optional system prompt. Static today; reactive widening pending. */\n\treadonly systemPrompt?: string;\n\t/**\n\t * Optional reactive tool list. When a Node, the agent subscribes and\n\t * reconciles the underlying `toolRegistry` registrations on each emit\n\t * (additions registered, removals unregistered). When a static array,\n\t * tools are registered once at construction.\n\t */\n\treadonly tools?: Node<readonly ToolDefinition[]> | readonly ToolDefinition[];\n\t/**\n\t * Optional shared memory. Default: private (agent mints its own\n\t * `AgentMemoryGraph` if needed; not yet wired into the loop's chat —\n\t * that wiring is a separate follow-up). Pass an explicit instance to\n\t * share memory across agents for §29 handoff context transfer.\n\t */\n\treadonly memory?: AgentMemoryGraph<unknown>;\n\t/**\n\t * Maps caller-typed input → string for the underlying chat. Defaults to\n\t * identity when `TIn extends string`; required otherwise.\n\t */\n\treadonly inMapper?: (input: TIn) => string;\n\t/**\n\t * Maps the agentLoop's `LLMResponse` → caller-typed output. Defaults to\n\t * identity when `TOut extends LLMResponse`; required otherwise.\n\t */\n\treadonly outMapper?: (response: LLMResponse) => TOut;\n\t/** Caps tool-call inner-loop iterations. Default 10. */\n\treadonly maxIterations?: number;\n\t/** Escape hatch for non-core fields. Surfaced in `describe()` via meta. */\n\treadonly meta?: Record<string, unknown>;\n}\n\n/**\n * Public contract for an agent — typed inbox/outbox + lifecycle / cost\n * observables + the underlying graph for inspection / mounting.\n *\n * **Reactive entry:** caller writes to `in` (e.g. `bundle.in.emit(input)`).\n * The agent reactively kicks the underlying loop and produces `out`.\n *\n * **Reactive exit:** caller reads `out` via `subscribe` (continuous) or\n * `awaitSettled(out)` (single-shot). Both `in` and `out` stay SENTINEL\n * (`cache === undefined`) until the first real emission — no `null`\n * push-on-subscribe trap (per `feedback_use_prevdata_for_sentinel`).\n *\n * **Cross-graph wiring:** the bundle's `graph` is mountable under any\n * parent via `parent.mount(name, bundle.graph)`. After mount, the bundle's\n * Nodes are reachable through both the bundle reference (direct) and via\n * `parent.node(\"<name>::out\")` etc. (qualified path).\n */\nexport interface AgentBundle<TIn, TOut> {\n\treadonly in: Node<TIn>;\n\treadonly out: Node<TOut>;\n\treadonly status: Node<AgentStatus>;\n\treadonly cost: Node<CostState>;\n\treadonly graph: AgentGraph<TIn, TOut>;\n}\n\n// ---------------------------------------------------------------------------\n// AgentGraph\n// ---------------------------------------------------------------------------\n\nconst TERMINAL_STATUSES = new Set<AgentStatus>([\"done\", \"error\"]);\n\n/**\n * Graph subclass implementing {@link AgentBundle}. Mounts an inner\n * {@link AgentLoopGraph} at `loop/`; `in` / `out` / `status` / `cost`\n * surface the bundle contract as top-level nodes.\n *\n * Construction is internal — use the {@link agent} factory in\n * `./agents.ts` for normal use. Direct `new AgentGraph(name, spec)` is\n * supported for callers that want full control over mount order.\n *\n * **Topology:**\n * ```\n * <name>\n * ├── loop (AgentLoopGraph subgraph)\n * │ ├── chat\n * │ ├── tools\n * │ ├── status / turn / aborted / lastResponse / ...\n * ├── in (Node<TIn>, SENTINEL until first emit)\n * ├── out (Node<TOut>, SENTINEL until first response)\n * ├── status (Node<AgentStatus>, mirror of loop.status)\n * └── cost (Node<CostState>)\n * ```\n *\n * **Lifecycle:**\n * - On `in` emit: `inMapper` projects to `string`; appended to\n * `loop.chat`; loop status reset (`turn=0`, `aborted=false`,\n * `status=\"thinking\"`); per-input cost counters reset to zero.\n * - On `loop.lastResponse` emit: cost rolls forward; `out` emits\n * `outMapper(response)`.\n * - On `loop.status=\"done\"`: agent's status emits `\"done\"`.\n * - On `loop.status=\"error\"` (or any ERROR propagation): agent's status\n * emits `\"error\"`.\n */\nexport class AgentGraph<TIn, TOut> extends Graph {\n\t/** The agent's typed inbox. Writable; `in.emit(value)` kicks the loop. */\n\treadonly in: Node<TIn>;\n\t/** The agent's typed outbox. SENTINEL until first response. */\n\treadonly out: Node<TOut>;\n\t/** Lifecycle status (translated from the underlying loop's substates). */\n\treadonly status: Node<AgentStatus>;\n\t/** Cumulative cost for the current / most-recent input. */\n\treadonly cost: Node<CostState>;\n\t/** The underlying agentLoop — exposed for inspection / advanced wiring. */\n\treadonly loop: AgentLoopGraph;\n\t/** Optional shared memory subgraph (mounted at `memory/` if provided). */\n\treadonly memory: AgentMemoryGraph<unknown> | null;\n\n\tconstructor(spec: AgentSpec<TIn, TOut>, opts?: GraphOptions) {\n\t\tsuper(spec.name, opts);\n\n\t\t// --- 1. Mount the agentLoop subgraph. ------------------------------\n\t\tconst initialTools = Array.isArray(spec.tools)\n\t\t\t? (spec.tools as readonly ToolDefinition[])\n\t\t\t: undefined;\n\t\tthis.loop = agentLoop(`${spec.name}-loop`, {\n\t\t\tadapter: spec.adapter,\n\t\t\t...(spec.systemPrompt != null ? { systemPrompt: spec.systemPrompt } : {}),\n\t\t\t...(initialTools != null ? { tools: initialTools } : {}),\n\t\t\t...(spec.maxIterations != null ? { maxTurns: spec.maxIterations } : {}),\n\t\t});\n\t\tthis.mount(\"loop\", this.loop);\n\n\t\t// --- 2. Reactive tools subscription (if Node-form). ----------------\n\t\t// agentLoop's tools are static-array at construction; we reconcile\n\t\t// dynamically by subscribing to the user's reactive Node and\n\t\t// register/unregister against the inner toolRegistry.\n\t\tif (spec.tools != null && !Array.isArray(spec.tools)) {\n\t\t\tconst toolsNode = spec.tools as Node<readonly ToolDefinition[]>;\n\t\t\tconst registered = new Set<string>();\n\t\t\tconst unsubTools = toolsNode.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\t\tconst next = m[1] as readonly ToolDefinition[];\n\t\t\t\t\tconst nextNames = new Set(next.map((t) => t.name));\n\t\t\t\t\t// Unregister missing.\n\t\t\t\t\tfor (const name of registered) {\n\t\t\t\t\t\tif (!nextNames.has(name)) {\n\t\t\t\t\t\t\tthis.loop.tools.unregister(name);\n\t\t\t\t\t\t\tregistered.delete(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Register new (idempotent guard via local tracking).\n\t\t\t\t\tfor (const tool of next) {\n\t\t\t\t\t\tif (!registered.has(tool.name)) {\n\t\t\t\t\t\t\tthis.loop.tools.register(tool);\n\t\t\t\t\t\t\tregistered.add(tool.name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.addDisposer(unsubTools);\n\t\t}\n\n\t\t// --- 3. Optional shared memory subgraph (passed through). ----------\n\t\t// v1: memory is mounted but NOT yet wired into the loop's chat — the\n\t\t// chat-context-from-memory glue is a separate follow-up. Mounting it\n\t\t// here gives the bundle a stable surface for §29 handoff (callers\n\t\t// can pass the SAME instance to multiple agents for shared memory).\n\t\tthis.memory = spec.memory ?? null;\n\t\tif (this.memory != null) {\n\t\t\tthis.mount(\"memory\", this.memory);\n\t\t}\n\n\t\t// --- 4. `in` — the typed inbox. ------------------------------------\n\t\t// SENTINEL until first emit; `equals: () => false` so re-emitting the\n\t\t// same value still kicks (no spurious dedup of repeat inputs).\n\t\tthis.in = node<TIn>([], {\n\t\t\tname: \"in\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_in\"),\n\t\t\tequals: () => false,\n\t\t});\n\t\tthis.add(this.in, { name: \"in\" });\n\n\t\t// --- 5. `cost` — per-input token counters. -------------------------\n\t\tconst costNode = node<CostState>([], {\n\t\t\tname: \"cost\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_cost\"),\n\t\t\tinitial: ZERO_COST,\n\t\t});\n\t\tthis.add(costNode, { name: \"cost\" });\n\t\tthis.cost = costNode;\n\n\t\t// --- 6. `out` — the typed outbox. ----------------------------------\n\t\t// Derived from `loop.lastResponse`. SENTINEL while `loop.lastResponse`\n\t\t// has never emitted a real response (F9 fix: the loop now stays\n\t\t// SENTINEL too — no more eager `null` placeholder), so the SENTINEL\n\t\t// detector inside the fn is `prevData[0] === undefined`. Between\n\t\t// runs, `loop.lastResponse.down([[INVALIDATE]])` clears that\n\t\t// `prevData` slot back to undefined, so this derived correctly gates\n\t\t// to RESOLVED on the next status=\"idle\" wave.\n\t\tconst outMapper = spec.outMapper ?? defaultOutMapper<TOut>();\n\t\tconst outNode = node<TOut>(\n\t\t\t[this.loop.lastResponse],\n\t\t\t(data, a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst resp =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as LLMResponse | undefined)\n\t\t\t\t\t\t: (ctx.prevData[0] as LLMResponse | undefined);\n\t\t\t\tif (resp === undefined) {\n\t\t\t\t\ta.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ta.emit(outMapper(resp));\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"out\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_out\"),\n\t\t\t\t// Each in.emit may produce a structurally-equal response (e.g.\n\t\t\t\t// from a deterministic adapter) — disable framework dedup so\n\t\t\t\t// repeat emits propagate and `awaitSettled({skipCurrent:true})`\n\t\t\t\t// sees them. Callers can wrap with `distinctUntilChanged` if\n\t\t\t\t// they want change-only semantics.\n\t\t\t\tequals: () => false,\n\t\t\t},\n\t\t);\n\t\tthis.add(outNode, { name: \"out\" });\n\t\tthis.out = outNode;\n\n\t\t// --- 7. `status` — translated from loop.status. --------------------\n\t\t// Mirror via §32 pattern: a state node downstream consumers depend on,\n\t\t// reset and updated by an effect listening to loop.status.\n\t\tconst statusNode = node<AgentStatus>([], {\n\t\t\tname: \"status\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t\tinitial: \"idle\",\n\t\t});\n\t\tthis.add(statusNode, { name: \"status\" });\n\t\tthis.status = statusNode;\n\n\t\tconst statusMirrorEff = node(\n\t\t\t[this.loop.status],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst loopStatus =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as string)\n\t\t\t\t\t\t: ((ctx.prevData[0] as string | undefined) ?? \"idle\");\n\t\t\t\tconst next: AgentStatus =\n\t\t\t\t\tloopStatus === \"idle\"\n\t\t\t\t\t\t? \"idle\"\n\t\t\t\t\t\t: loopStatus === \"thinking\" || loopStatus === \"acting\"\n\t\t\t\t\t\t\t? \"running\"\n\t\t\t\t\t\t\t: loopStatus === \"done\"\n\t\t\t\t\t\t\t\t? \"done\"\n\t\t\t\t\t\t\t\t: loopStatus === \"error\"\n\t\t\t\t\t\t\t\t\t? \"error\"\n\t\t\t\t\t\t\t\t\t: \"idle\";\n\t\t\t\tif (statusNode.cache !== next) statusNode.emit(next);\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_status_mirror\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(statusMirrorEff));\n\n\t\t// --- 8. Cost-rollup effect. ---------------------------------------\n\t\t// Rolls forward on each loop.lastResponse emission. Reads\n\t\t// loop.turn.cache for the iteration count (sole-owner-reactive-reader\n\t\t// per Phase 12 D1 lock — loop is mounted as a subgraph of this Graph).\n\t\t// SENTINEL gate: `prevData[0] === undefined` means no response has\n\t\t// ever been delivered for this run (post-INVALIDATE reset between\n\t\t// runs), so the rollup short-circuits.\n\t\tconst costEff = node(\n\t\t\t[this.loop.lastResponse],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tconst resp =\n\t\t\t\t\tbatch0 != null && batch0.length > 0\n\t\t\t\t\t\t? (batch0.at(-1) as LLMResponse | undefined)\n\t\t\t\t\t\t: (ctx.prevData[0] as LLMResponse | undefined);\n\t\t\t\tif (resp === undefined) return;\n\t\t\t\tconst prev = (costNode.cache as CostState | undefined) ?? ZERO_COST;\n\t\t\t\tconst turns = (this.loop.turn.cache as number | undefined) ?? prev.turns;\n\t\t\t\tconst next: CostState = {\n\t\t\t\t\tusage: resp.usage != null ? addUsage(prev.usage, resp.usage) : prev.usage,\n\t\t\t\t\tturns,\n\t\t\t\t};\n\t\t\t\tcostNode.emit(next);\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_cost_rollup\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(costEff));\n\n\t\t// --- 9. `in` → input queue → drain → kick the loop. ----------------\n\t\t// Phase 13.G/H + /qa N1(b) lock (2026-05-01): bundle.in is a\n\t\t// writable surface, but kicks are queued through an internal\n\t\t// hub-style topic + cursor subscription. Out-of-the-box queueing —\n\t\t// caller fires `in.emit(x)` while the agent is mid-run; the input\n\t\t// is parked on the queue and picked up when the loop returns to\n\t\t// `idle` / `done` / `error`. No mid-run reset / cost-leak hazard\n\t\t// (which the prior raw `in.subscribe → kick` path had).\n\t\t//\n\t\t// Topology:\n\t\t// `in` (state Node, writable) → `inputBridge` (subscribe →\n\t\t// publish) → `inputTopic` (TopicGraph<TIn>) → `inputSub`\n\t\t// (SubscriptionGraph<TIn>) → `drainEffect` (effect on\n\t\t// [inputSub.available, loop.status]) → loop kick.\n\t\tconst inMapper = spec.inMapper ?? defaultInMapper<TIn>();\n\t\tconst inputTopic: TopicGraph<TIn> = topic<TIn>(\"input-topic\");\n\t\tthis.mount(\"input-topic\", inputTopic);\n\t\tconst inputSub: SubscriptionGraph<TIn> = subscription<TIn>(\"input-sub\", inputTopic, {\n\t\t\tfrom: \"now\",\n\t\t});\n\t\tthis.mount(\"input-sub\", inputSub);\n\n\t\t// Bridge: `in.emit(x)` publishes to the topic. Validates the\n\t\t// caller-supplied input via `inMapper` at the boundary so the\n\t\t// type error surfaces in the caller's stack frame (not later\n\t\t// during drain). Per the F9 SENTINEL trap, `in` cache is\n\t\t// `undefined` until the first emit; push-on-subscribe delivers\n\t\t// nothing.\n\t\tconst inputBridge = this.in.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst input = m[1] as TIn;\n\t\t\t\t// Boundary type-check: throws if TIn is not string and no\n\t\t\t\t// inMapper supplied. Better here than at drain time so the\n\t\t\t\t// caller's `in.emit(...)` raises synchronously.\n\t\t\t\tinMapper(input);\n\t\t\t\tinputTopic.publish(input);\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(inputBridge);\n\n\t\t// Drain effect: when an input is pending AND the loop is ready\n\t\t// (`idle` / `done` / `error`), pull one and kick. Re-entrancy\n\t\t// guard via `loop.status` — `thinking` / `acting` skip.\n\t\tconst drainEffect = node(\n\t\t\t[inputSub.available, this.loop.status],\n\t\t\t(data, _a, ctx) => {\n\t\t\t\tconst availBatch = data[0];\n\t\t\t\tconst statusBatch = data[1];\n\t\t\t\tconst avail =\n\t\t\t\t\t(availBatch != null && availBatch.length > 0\n\t\t\t\t\t\t? (availBatch.at(-1) as readonly TIn[])\n\t\t\t\t\t\t: ((ctx.prevData[0] as readonly TIn[] | undefined) ?? [])) ?? [];\n\t\t\t\tconst stat =\n\t\t\t\t\t(statusBatch != null && statusBatch.length > 0\n\t\t\t\t\t\t? (statusBatch.at(-1) as string)\n\t\t\t\t\t\t: ((ctx.prevData[1] as string | undefined) ?? \"idle\")) ?? \"idle\";\n\t\t\t\tif (avail.length === 0) return;\n\t\t\t\tif (stat === \"thinking\" || stat === \"acting\") return;\n\t\t\t\tconst result = inputSub.pullAndAck(1);\n\t\t\t\tif (result.items.length === 0) return;\n\t\t\t\tconst input = result.items[0] as TIn;\n\t\t\t\tconst userMsg = inMapper(input);\n\t\t\t\tbatch(() => {\n\t\t\t\t\t// Reset per-input accumulators so cost/turns don't include\n\t\t\t\t\t// the previous input. `lastResponse` is reset via plain\n\t\t\t\t\t// `[[INVALIDATE]]` — under DS-13.5.A INVALIDATE both clears\n\t\t\t\t\t// `_cached` AND settles the consuming wave (decrements\n\t\t\t\t\t// `_dirtyDepCount` like RESOLVED), so dependents like\n\t\t\t\t\t// `out` / `costEff` fire on the next status transition\n\t\t\t\t\t// without staying wedged in DIRTY. Pre-DS-13.5.A this used\n\t\t\t\t\t// the `[[INVALIDATE], [RESOLVED]]` paired-reset workaround.\n\t\t\t\t\tthis.loop.lastResponse.down([[INVALIDATE]]);\n\t\t\t\t\tthis.loop.turn.emit(0);\n\t\t\t\t\tthis.loop.aborted.emit(false);\n\t\t\t\t\tcostNode.emit(ZERO_COST);\n\t\t\t\t\tthis.loop.chat.append(\"user\", userMsg);\n\t\t\t\t\tthis.loop.status.emit(\"thinking\");\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\", meta: aiMeta(\"agent_input_drain\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(drainEffect));\n\n\t\t// `out` and `status` keepalives are unnecessary because the cost /\n\t\t// status effects above already activate `loop.lastResponse` and\n\t\t// `loop.status` — the derived `out` reads from a kept-alive source.\n\t\t// We do keep `out` alive explicitly so `awaitSettled(bundle.out,\n\t\t// { skipCurrent: true })` works even when no other consumer\n\t\t// subscribes between input and response.\n\t\tthis.addDisposer(keepalive(this.out));\n\n\t\t// Surface in describe.\n\t\tvoid TERMINAL_STATUSES;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Default mappers\n// ---------------------------------------------------------------------------\n\n/**\n * Default `inMapper` for `TIn extends string`. Asserts the runtime type at\n * the boundary so callers who omit `inMapper` for a non-string `TIn` get a\n * clear error rather than a silent passthrough.\n */\nfunction defaultInMapper<TIn>(): (input: TIn) => string {\n\treturn (input) => {\n\t\tif (typeof input !== \"string\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`agent: inMapper is required when TIn is not a string (got ${typeof input}). Pass spec.inMapper.`,\n\t\t\t);\n\t\t}\n\t\treturn input;\n\t};\n}\n\n/**\n * Default `outMapper` for `TOut extends LLMResponse`. Asserts the response\n * shape at the boundary; callers with a non-LLMResponse `TOut` must\n * provide `outMapper`.\n */\nfunction defaultOutMapper<TOut>(): (response: LLMResponse) => TOut {\n\treturn (response) => response as unknown as TOut;\n}\n","/**\n * @internal — shared helpers for the AI pattern modules.\n *\n * NOT part of the public API. Consumers reach public symbols through\n * `@graphrefly/graphrefly/utils/ai` (the barrel).\n *\n * @module\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n\tResettableTimer,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n} from \"./adapters/core/types.js\";\n\nexport function aiMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"ai\", kind, extra);\n}\n\nexport function isPromiseLike(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\nexport function isNodeLike(x: unknown): x is Node<unknown> {\n\treturn (\n\t\ttypeof x === \"object\" &&\n\t\tx !== null &&\n\t\t\"subscribe\" in x &&\n\t\ttypeof (x as Node<unknown>).subscribe === \"function\" &&\n\t\t\"cache\" in x\n\t);\n}\n\nexport function isAsyncIterableLike(x: unknown): x is AsyncIterable<unknown> {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\tSymbol.asyncIterator in x &&\n\t\ttypeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n\t);\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** First settled `DATA` from a `Node` (do not pass plain strings — `fromAny` would iterate chars). */\nexport function firstDataFromNode(\n\tresolved: Node<unknown>,\n\topts?: { timeoutMs?: number },\n): Promise<unknown> {\n\tif ((resolved as { status?: string }).status === \"settled\") {\n\t\tconst immediate = resolved.cache;\n\t\tif (immediate !== undefined) {\n\t\t\treturn Promise.resolve(immediate);\n\t\t}\n\t}\n\tconst timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\treturn new Promise((resolve, reject) => {\n\t\tconst timer = new ResettableTimer();\n\t\tconst unsub = resolved.subscribe((messages) => {\n\t\t\tfor (const msg of messages) {\n\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\tresolve(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === ERROR) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(msg[1]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (msg[0] === COMPLETE) {\n\t\t\t\t\ttimer.cancel();\n\t\t\t\t\tunsub();\n\t\t\t\t\treject(new Error(\"firstDataFromNode: completed without producing a value\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttimer.start(timeoutMs, () => {\n\t\t\tunsub();\n\t\t\treject(new Error(`firstDataFromNode: timed out after ${timeoutMs}ms`));\n\t\t});\n\t});\n}\n\n/** Await Promise-likes, then resolve `Node` / async-iterable inputs via `fromAny` + first `DATA`. */\nexport async function resolveToolHandlerResult(value: unknown): Promise<unknown> {\n\tif (isPromiseLike(value)) {\n\t\treturn resolveToolHandlerResult(await value);\n\t}\n\tif (isNodeLike(value)) {\n\t\treturn firstDataFromNode(value);\n\t}\n\tif (isAsyncIterableLike(value)) {\n\t\treturn firstDataFromNode(fromAny(value as NodeInput<unknown>));\n\t}\n\treturn value;\n}\n\n/** Strip markdown code fences, handling trailing commentary after closing fence. */\nexport function stripFences(text: string): string {\n\tconst match = text.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```[\\s\\S]*$/);\n\treturn match ? match[1]! : text;\n}\n\n/**\n * Bridge-layer failure kind reported to {@link OneShotLlmCallConfig.onFailure}.\n *\n * - `\"throw\"` — synchronous throw from `adapter.invoke()`.\n * - `\"error\"` — `[ERROR, value]` message on the bridged Node.\n * - `\"complete\"` — the bridged Node closed without emitting DATA.\n * - `\"onSuccess-threw\"` — `onSuccess(resp)` itself threw (uncaught parse /\n * builder error). Caller's `onFailure` decides the failure-payload shape.\n */\nexport type OneShotLlmFailureKind = \"throw\" | \"error\" | \"complete\" | \"onSuccess-threw\";\n\n/** Configuration for {@link _oneShotLlmCall}. */\nexport interface OneShotLlmCallConfig<T> {\n\t/**\n\t * Build the success payload from the adapter's first DATA message.\n\t * MAY throw — the helper catches and routes through `onFailure(kind:\n\t * \"onSuccess-threw\", err)` so callers don't need their own try/catch.\n\t */\n\tonSuccess: (resp: LLMResponse) => T;\n\t/**\n\t * Build a failure payload when the bridge layer reports any of the\n\t * {@link OneShotLlmFailureKind} categories. Caller chooses the detail\n\t * string format and any error-class metadata.\n\t */\n\tonFailure: (kind: OneShotLlmFailureKind, err: unknown) => T;\n\t/**\n\t * Forwarded to `adapter.invoke(messages, opts)` — `signal` is set\n\t * by the helper from the producer's AbortController and CANNOT be\n\t * overridden here (cancellation is a hard contract of this helper).\n\t */\n\tinvokeOpts?: Omit<LLMInvokeOptions, \"signal\">;\n\t/**\n\t * Optional parent abort signal (e.g. JobFlow pump's per-claim signal).\n\t * When the parent aborts, the helper aborts its inner AbortController —\n\t * so `adapter.invoke({ signal })` and `fromAny({ signal })` see the\n\t * cascade and cancel in-flight work. Pump-driven harness teardown\n\t * (`harness.destroy()`) propagates through this hook (Tier 6.5 2.5b).\n\t */\n\tparentSignal?: AbortSignal;\n}\n\n/**\n * Internal — one-shot bridge from `adapter.invoke()` (a `NodeInput<LLMResponse>`)\n * into a producer that emits exactly one DATA + COMPLETE.\n *\n * **Why this exists.** The harness's `defaultLlmExecutor` and\n * `defaultLlmVerifier` (Tier 6.5 C2) both call `adapter.invoke()` once\n * per claimed JobFlow job and need to:\n * 1. Subscribe to the bridged Node, capture the first DATA, parse, emit\n * a domain payload.\n * 2. Map adapter throws / ERROR / COMPLETE-without-DATA to a domain\n * failure payload (rather than nack the JobFlow claim).\n * 3. Thread `signal: ac.signal` into BOTH `adapter.invoke()` (via\n * `LLMInvokeOptions.signal`) and `fromAny()` (covers Node-shaped\n * invokeResults) so teardown actually aborts in-flight HTTP work.\n * 4. Tear down the inner subscription cleanly when DATA captures or\n * when the producer is unsubscribed.\n *\n * Pre-extraction this body was duplicated ~80 LOC across the two default\n * bridges; symmetric fixes had to land twice (qa F1 / F2 / F5). This\n * helper centralizes the producer body so future bridge-layer fixes apply\n * once.\n *\n * **Not part of the public API.** Callers in `patterns/ai/_internal.ts`'s\n * import surface (the harness defaults today) use this; user code should\n * use `promptNode` for cross-wave reactive transforms or call\n * `adapter.invoke()` directly.\n */\nexport function _oneShotLlmCall<T>(\n\tadapter: LLMAdapter,\n\tmessages: readonly ChatMessage[],\n\tconfig: OneShotLlmCallConfig<T>,\n): NodeInput<T> {\n\treturn node<T>(\n\t\t(_data, actions) => {\n\t\t\tconst ac = new AbortController();\n\t\t\t// Link parent signal (e.g. pump per-claim signal) so cascading\n\t\t\t// teardown propagates: parent abort → inner ac.abort → adapter +\n\t\t\t// fromAny cancel.\n\t\t\tconst parentSignal = config.parentSignal;\n\t\t\tlet unlinkParent: () => void = () => undefined;\n\t\t\tif (parentSignal) {\n\t\t\t\tif (parentSignal.aborted) {\n\t\t\t\t\tac.abort();\n\t\t\t\t} else {\n\t\t\t\t\tconst onParentAbort = (): void => ac.abort();\n\t\t\t\t\tparentSignal.addEventListener(\"abort\", onParentAbort, { once: true });\n\t\t\t\t\tunlinkParent = () => parentSignal.removeEventListener(\"abort\", onParentAbort);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet captured = false;\n\t\t\tlet unsub: (() => void) | null = null;\n\t\t\tconst emitOnce = (value: T): void => {\n\t\t\t\tif (captured) return;\n\t\t\t\tcaptured = true;\n\t\t\t\tactions.down([[DATA, value], [COMPLETE]] satisfies Messages);\n\t\t\t\tunsub?.();\n\t\t\t\tunsub = null;\n\t\t\t};\n\t\t\tlet invokeResult: NodeInput<LLMResponse>;\n\t\t\ttry {\n\t\t\t\tinvokeResult = adapter.invoke(messages, { ...config.invokeOpts, signal: ac.signal });\n\t\t\t} catch (err) {\n\t\t\t\temitOnce(config.onFailure(\"throw\", err));\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tunlinkParent();\n\t\t\t\t\t\tac.abort();\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst callNode = fromAny<LLMResponse>(invokeResult, { signal: ac.signal });\n\t\t\tunsub = callNode.subscribe((batch) => {\n\t\t\t\tfor (const m of batch) {\n\t\t\t\t\tif (captured) return;\n\t\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\temitOnce(config.onSuccess(m[1] as LLMResponse));\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\temitOnce(config.onFailure(\"onSuccess-threw\", err));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\t\temitOnce(config.onFailure(\"error\", m[1]));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t\t// COMPLETE without prior DATA — without this arm the JobFlow\n\t\t\t\t\t\t// pump's claim would stall (qa F1 regression). Helper handles\n\t\t\t\t\t\t// for ALL callers; defaults can't regress.\n\t\t\t\t\t\temitOnce(config.onFailure(\"complete\", undefined));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t// Sync DATA delivery (cached state / `fromAny` over a sync value):\n\t\t\t// the callback ran reentrantly before `unsub` was assigned, so the\n\t\t\t// `unsub?.()` call inside `emitOnce` was a no-op. Drop the upstream\n\t\t\t// subscription now that we have the handle.\n\t\t\tif (captured && unsub) {\n\t\t\t\tunsub();\n\t\t\t\tunsub = null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tunlinkParent();\n\t\t\t\t\tac.abort();\n\t\t\t\t\tunsub?.();\n\t\t\t\t\tunsub = null;\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{ describeKind: \"producer\" },\n\t);\n}\n","/**\n * Metadata helpers for pattern-layer nodes (Tier 2.2 promotion from\n * `patterns/_internal/`).\n *\n * Each domain (orchestration, messaging, reduction, ai, cqrs, domain_template,\n * memory, lens, audit, harness) shares the same metadata convention. Promoted\n * to `extra/` so non-patterns code (and downstream consumers building their\n * own domain primitives) can use the same shape.\n *\n * @module\n */\n\n/**\n * Build a domain metadata object for pattern-layer nodes.\n *\n * Each domain follows the same shape: `{ [domain]: true, [domain]_type: kind, ...extra }`.\n *\n * @param domain - The domain tag (e.g. `\"orchestration\"`, `\"ai\"`, `\"cqrs\"`).\n * @param kind - The specific type within the domain (e.g. `\"gate\"`, `\"prompt\"`).\n * @param extra - Additional metadata to merge.\n * @returns Metadata object.\n */\nexport function domainMeta(\n\tdomain: string,\n\tkind: string,\n\textra?: Record<string, unknown>,\n): Record<string, unknown> {\n\treturn {\n\t\t[domain]: true,\n\t\t[`${domain}_type`]: kind,\n\t\t...(extra ?? {}),\n\t};\n}\n","/**\n * Messaging patterns (roadmap §4.2).\n *\n * Pulsar-inspired messaging primitives modeled as graph factories:\n * - `topic()` for append-only topic streams with a retained window.\n * - `subscription()` for cursor-based consumers.\n * - `topicBridge()` for autonomous topic-to-topic relay.\n * - `messagingHub()` for a lazy topic registry.\n *\n * Plus the Phase 13.B standard `Message<T>` envelope and well-known topic\n * name constants ({@link PROMPTS_TOPIC} / {@link RESPONSES_TOPIC} /\n * {@link INJECTIONS_TOPIC} / {@link DEFERRED_TOPIC} / {@link SPAWNS_TOPIC})\n * — recommended (not enforced) wire shape for cross-graph topic payloads.\n *\n * Job queue / job flow primitives live in `patterns/job-queue` — they are a\n * distinct domain that happens to share reactive-log / reactive-map\n * infrastructure with topics.\n */\n\nexport {\n\ttype HubRemoveTopicRecord,\n\thubRemoveTopicKeyOf,\n\ttype MessagingAuditRecord,\n\ttype SubscriptionAckRecord,\n\ttype SubscriptionPullAndAckRecord,\n\tsubscriptionAckKeyOf,\n\tsubscriptionPullAndAckKeyOf,\n\ttype TopicPublishRecord,\n\ttopicPublishKeyOf,\n} from \"./audit-records.js\";\nexport {\n\tCONTEXT_TOPIC,\n\tDEFERRED_TOPIC,\n\tINJECTIONS_TOPIC,\n\ttype JsonSchema,\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\tSPAWNS_TOPIC,\n\tSTANDARD_TOPICS,\n\ttype StandardTopic,\n\tTODOS_TOPIC,\n\ttype TopicMessage,\n} from \"./message.js\";\n\nimport { batch, COMPLETE, DATA, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { mutate } from \"../../base/mutation/index.js\";\n\nconst DEFAULT_MAX_PER_PUMP = 256;\n\nfunction requireNonNegativeInt(value: number, label: string): number {\n\tif (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {\n\t\tthrow new Error(`${label} must be a non-negative integer`);\n\t}\n\treturn value;\n}\n\nfunction messagingMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"messaging\", kind, extra);\n}\n\nexport type TopicOptions = {\n\tgraph?: GraphOptions;\n\t/** Bounded retention; default 1024 per cross-cutting policy (Audit 2/4). */\n\tretainedLimit?: number;\n};\n\nconst DEFAULT_TOPIC_RETAINED_LIMIT = 1024;\n\nexport class TopicGraph<T> extends Graph {\n\tprivate readonly _log;\n\tprivate readonly _publishImpl: (value: T) => void;\n\treadonly events: Node<readonly T[]>;\n\t/**\n\t * Most recently published value. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first publish, then\n\t * tracks the latest entry. Spec §5.12 reserves `undefined` as the\n\t * \"never sent DATA\" sentinel — and `TopicGraph.publish(undefined)` is\n\t * rejected — so `cache === undefined` unambiguously signals \"empty topic\"\n\t * even when `T` itself includes `null` (i.e., `topic<number | null>`).\n\t *\n\t * **Within a reactive fn:** detect the empty-topic case via\n\t * `ctx.prevData[i] === undefined` for the dep slot holding `topic.latest`,\n\t * or check `latest.cache === undefined` outside reactive code. No\n\t * separate `hasLatest` companion needed — the SENTINEL is the answer.\n\t */\n\treadonly latest: Node<T>;\n\n\tconstructor(name: string, opts: TopicOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis._log = reactiveLog<T>([], {\n\t\t\tname: \"events\",\n\t\t\tmaxSize: opts.retainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.events = this._log.entries;\n\t\tthis.add(this.events, { name: \"events\" });\n\t\t// `this.derived(\"latest\", [\"events\"], …)` is expressible after the\n\t\t// 2026-04-30 self-resolve fix in `Graph._resolveFromSegments` — a\n\t\t// single-segment path matching the graph's own name (e.g.\n\t\t// `topic(\"events\").resolve(\"events\")`) no longer collapses to empty\n\t\t// and falls through to local-node lookup. Replaces the prior\n\t\t// `node([events], …) + this.add(...)` workaround.\n\t\t//\n\t\t// SENTINEL on empty: returning `[]` here yields a RESOLVED-only wave\n\t\t// (no DATA), so `latest.cache` stays `undefined` until the first\n\t\t// publish. `TopicGraph.publish(undefined)` is rejected (line below),\n\t\t// so `undefined` cache is unambiguously \"empty topic\" even when `T`\n\t\t// itself includes `null`. Drops the prior `hasLatest` companion as\n\t\t// redundant.\n\t\tthis.latest = this.derived<T>(\n\t\t\t\"latest\",\n\t\t\t[\"events\"],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly T[];\n\t\t\t\treturn entries.length === 0 ? [] : [entries[entries.length - 1] as T];\n\t\t\t},\n\t\t\t{ meta: messagingMeta(\"topic_latest\") },\n\t\t);\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\t// D1(a): on teardown, propagate COMPLETE on `events` so downstream\n\t\t// derived chains (including any externally-held SubscriptionGraph\n\t\t// sources) see the termination via their `terminalDeps` and can stop\n\t\t// serving stale caches. Tier-3 terminal per spec §2.2.\n\t\t//\n\t\t// EC16 (verified 2026-04-30): the COMPLETE-then-disposeAllViews order\n\t\t// is intentional. COMPLETE propagates SYNCHRONOUSLY through every\n\t\t// subscriber (cursor views, derived chains) so they self-unsubscribe\n\t\t// in their terminal handler before `disposeAllViews` runs. Swapping\n\t\t// the order would clear view caches before subscribers receive the\n\t\t// terminal — strictly worse. Reading `.cache` outside a reactive fn\n\t\t// across teardown is an anti-pattern (spec §5.12) and not a use case\n\t\t// this ordering needs to preserve.\n\t\tthis.addDisposer(() => {\n\t\t\tthis.events.down([[COMPLETE]]);\n\t\t});\n\t\t// P9: release any memoized tail/slice view keepalives held by the log.\n\t\t// TopicGraph itself doesn't call log.tail/slice, but plugins may have\n\t\t// attached views via `_log` — defensive (typical reactive subscribers\n\t\t// have already unsubscribed in their COMPLETE handler above).\n\t\tthis.addDisposer(() => this._log.disposeAllViews());\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route publish through `mutate`\n\t\t// for centralized freeze + re-throw semantics. No audit log surface\n\t\t// (per Tier 8 γ-0): the topic's `events` log already records every\n\t\t// successful publish, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because topic payloads can be large and per-publish\n\t\t// cost matters on hot paths.\n\t\tthis._publishImpl = mutate<[T], void, never>(\n\t\t\t(value): void => {\n\t\t\t\tthis._log.append(value);\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tpublish(value: T): void {\n\t\t// SENTINEL alignment (Wave B.1 Unit 11 lock): `undefined` is the\n\t\t// protocol-level \"never sent DATA\" sentinel — refusing it here\n\t\t// preserves `lastValue: Node<T | undefined>` semantics.\n\t\tif (value === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`TopicGraph \"${this.name}\": publish(undefined) is not allowed (spec §5.12 SENTINEL).`,\n\t\t\t);\n\t\t}\n\t\tthis._publishImpl(value);\n\t}\n\n\t/**\n\t * Wire one or more append-log storage tiers (Audit 4). Each tier receives\n\t * appended events per wave; rollback honors the wave-as-transaction model.\n\t *\n\t * Named `attachEventStorage` (not `attachStorage`) to avoid colliding with\n\t * the inherited {@link Graph.attachSnapshotStorage} which takes the\n\t * paired `AttachSnapshotTierPair[]` shape (Phase 14.6) — distinct\n\t * concerns, distinct surfaces.\n\t *\n\t * @returns Disposer.\n\t */\n\tattachEventStorage(\n\t\ttiers: readonly import(\"@graphrefly/pure-ts/extra\").AppendLogStorageTier<T>[],\n\t): () => void {\n\t\treturn this._log.attachStorage(tiers);\n\t}\n\n\tretained(): readonly T[] {\n\t\treturn this.events.cache as readonly T[];\n\t}\n\n\t/** Internal log bundle — used by TopicBridgeGraph for `attach`. */\n\tget _logBundle() {\n\t\treturn this._log;\n\t}\n}\n\nexport type SubscriptionOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Starting cursor position.\n\t * @deprecated Use `from` instead.\n\t */\n\tcursor?: number;\n\t/**\n\t * Starting position for the subscription.\n\t * - `\"retained\"` (default) — cursor starts at 0; consumer sees all retained history.\n\t * - `\"now\"` — cursor starts at current topic length; consumer ignores history.\n\t * - `number` — explicit cursor position.\n\t */\n\tfrom?: \"now\" | \"retained\" | number;\n\t/**\n\t * When this signal node emits DATA, the subscription auto-advances cursor\n\t * to current `available.length`. Useful for \"ack everything when X happens\"\n\t * patterns. The reactive edge `advanceOn → cursor` is visible in `explain()`.\n\t */\n\tadvanceOn?: Node<unknown>;\n};\n\n/** Result of {@link SubscriptionGraph.pullAndAck}. */\nexport type PullAndAckResult<T> = {\n\titems: readonly T[];\n\tcursor: number;\n};\n\nexport class SubscriptionGraph<T> extends Graph {\n\treadonly cursor: Node<number>;\n\treadonly available: Node<readonly T[]>;\n\t/**\n\t * Reference to the upstream topic graph. Intentionally NOT mounted\n\t * under this subscription: a subscription is a VIEW over an\n\t * externally-owned topic. Double-mounting (e.g. hub-owned topic +\n\t * sub-mount here) would make either-side teardown leave the other\n\t * holding a dead reference. Node-level `derived([topicEvents], …)`\n\t * still wires the data dependency across graph boundaries. D1(e).\n\t */\n\treadonly topic: TopicGraph<T>;\n\n\tprivate _disposed = false;\n\tprivate readonly _ackImpl: (count: number | undefined) => number;\n\tprivate readonly _pullAndAckImpl: (limit: number | undefined) => PullAndAckResult<T>;\n\n\tconstructor(name: string, topicGraph: TopicGraph<T>, opts: SubscriptionOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\tthis.topic = topicGraph;\n\n\t\t// Resolve initial cursor from `from` option, falling back to legacy `cursor` option.\n\t\tlet initialCursor: number;\n\t\tif (opts.from !== undefined) {\n\t\t\tif (opts.from === \"retained\") {\n\t\t\t\tinitialCursor = 0;\n\t\t\t} else if (opts.from === \"now\") {\n\t\t\t\t// §28 sanctioned factory-time boundary read.\n\t\t\t\tinitialCursor = (topicGraph.events.cache as readonly T[]).length;\n\t\t\t} else {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"subscription from\");\n\t\t\t}\n\t\t} else {\n\t\t\tinitialCursor = requireNonNegativeInt(opts.cursor ?? 0, \"subscription cursor\");\n\t\t}\n\n\t\tthis.cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\tmeta: messagingMeta(\"subscription_cursor\"),\n\t\t});\n\n\t\t// B.1 Unit 12 lock: `available` depends directly on topic.events + cursor\n\t\t// via `view({ kind: \"fromCursor\" })`. No `source` passthrough node —\n\t\t// describe shows `topic::events → available` (cross-graph edge) and\n\t\t// `cursor → available` (local edge). One fewer node per subscription.\n\t\tthis.available = topicGraph._logBundle.view({ kind: \"fromCursor\", cursor: this.cursor });\n\t\tthis.add(this.available, { name: \"available\" });\n\t\tthis.addDisposer(keepalive(this.available));\n\n\t\t// Optional reactive auto-advance: when `advanceOn` emits a NEW DATA\n\t\t// (after construction), cursor advances by `available.length` atomically.\n\t\t// Edge visible in describe: advancePump depends on advanceOn.\n\t\t// `_advanceInitialized` guards against the initial push-on-subscribe fire\n\t\t// that would advance cursor before the user has a chance to read.\n\t\tif (opts.advanceOn !== undefined) {\n\t\t\tconst advanceOn = opts.advanceOn;\n\t\t\tlet advanceInitialized = false;\n\t\t\tconst advancePump = node<unknown>(\n\t\t\t\t[advanceOn],\n\t\t\t\t() => {\n\t\t\t\t\t// Skip the initial push-on-subscribe wave.\n\t\t\t\t\tif (!advanceInitialized) {\n\t\t\t\t\t\tadvanceInitialized = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._disposed) return;\n\t\t\t\t\tconst avail = this.available.cache as readonly T[];\n\t\t\t\t\tif (avail.length === 0) return;\n\t\t\t\t\tconst next = (this.cursor.cache as number) + avail.length;\n\t\t\t\t\tthis.cursor.emit(next);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"advancePump\",\n\t\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\t\tmeta: messagingMeta(\"subscription_advance_pump\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(advancePump, { name: \"advancePump\" });\n\t\t\tthis.addDisposer(keepalive(advancePump));\n\t\t}\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route ack + pullAndAck through\n\t\t// `mutate` for centralized freeze + re-throw semantics. No audit\n\t\t// log surface (per Tier 8 γ-0): the cursor's own emission stream already\n\t\t// records every advance, so a separate audit Node would be redundant.\n\t\t// `freeze: false` because count/limit are simple numbers; freezing is\n\t\t// pointless overhead. Disposed-checks stay outside the wrapper so a\n\t\t// no-op call doesn't unnecessarily run the wrapper.\n\t\tthis._ackImpl = mutate<[number | undefined], number, never>(\n\t\t\t(count): number => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst requested =\n\t\t\t\t\tcount === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(count, \"subscription ack count\");\n\t\t\t\tconst step = Math.min(requested, available.length);\n\t\t\t\tif (step <= 0) return this.cursor.cache as number;\n\t\t\t\tconst next = (this.cursor.cache as number) + step;\n\t\t\t\t// F8: use emit() so the pipeline auto-prefixes DIRTY, runs equals\n\t\t\t\t// substitution, and produces a proper two-phase wave (the raw\n\t\t\t\t// `down([[DATA, next]])` path bypassed those contracts).\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn next;\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\n\t\tthis._pullAndAckImpl = mutate<[number | undefined], PullAndAckResult<T>, never>(\n\t\t\t(limit): PullAndAckResult<T> => {\n\t\t\t\tconst available = this.available.cache as readonly T[];\n\t\t\t\tconst max =\n\t\t\t\t\tlimit === undefined\n\t\t\t\t\t\t? available.length\n\t\t\t\t\t\t: requireNonNegativeInt(limit, \"subscription pullAndAck limit\");\n\t\t\t\tconst items = available.slice(0, max);\n\t\t\t\tif (items.length === 0) return { items, cursor: this.cursor.cache as number };\n\t\t\t\tconst next = (this.cursor.cache as number) + items.length;\n\t\t\t\tthis.cursor.emit(next);\n\t\t\t\treturn { items, cursor: next };\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\tack(count?: number): number {\n\t\tif (this._disposed) return this.cursor.cache as number;\n\t\treturn this._ackImpl(count);\n\t}\n\n\tpull(limit?: number): readonly T[] {\n\t\tif (this._disposed) return [];\n\t\tconst available = this.available.cache as readonly T[];\n\t\tconst max =\n\t\t\tlimit === undefined\n\t\t\t\t? available.length\n\t\t\t\t: requireNonNegativeInt(limit, \"subscription pull limit\");\n\t\treturn available.slice(0, max);\n\t}\n\n\t/**\n\t * Atomic pull-and-acknowledge. Returns `{ items, cursor }` where `cursor`\n\t * is the new cursor position after advancing. Under single-threaded JS the\n\t * snapshot and advance are atomic; PY callers use a per-subscription Lock.\n\t *\n\t * Replaces `pull(limit, { ack: true })`.\n\t */\n\tpullAndAck(limit?: number): PullAndAckResult<T> {\n\t\tif (this._disposed) return { items: [], cursor: this.cursor.cache as number };\n\t\treturn this._pullAndAckImpl(limit);\n\t}\n\n\t/**\n\t * Release internal subscriptions and mark the subscription torn-down.\n\t * Subsequent `pull`, `pullAndAck`, `ack` return empty / current cursor.\n\t * Emits COMPLETE on `cursor` so derived consumers (e.g. `available`) see\n\t * the termination signal. Also drains `addDisposer` callbacks (including\n\t * the `keepalive(advancePump)` subscription) so no keepalive leak occurs.\n\t */\n\tdispose(): void {\n\t\tif (this._disposed) return;\n\t\tthis._disposed = true;\n\t\tthis.cursor.down([[COMPLETE]]);\n\t\t// m4: drain addDisposer callbacks to release the keepalive subscription.\n\t\tthis.destroy();\n\t}\n}\n\nexport type TopicBridgeOptions<TIn, TOut> = {\n\tgraph?: GraphOptions;\n\tcursor?: number;\n\tmaxPerPump?: number;\n\t/**\n\t * Optional transform/filter applied to each item before republishing.\n\t *\n\t * **At-most-once with silent drop:** when `map` returns `undefined`, the\n\t * input is consumed from the source cursor but NOT republished. Filtered\n\t * items are not retained for retry. If you need filter-with-retry\n\t * semantics, do the filtering in a downstream subscription on the bridged\n\t * output rather than in the `map` function.\n\t */\n\tmap?: (value: TIn) => TOut | undefined;\n};\n\nexport class TopicBridgeGraph<TIn, TOut = TIn> extends Graph {\n\tprivate readonly _sourceSub;\n\treadonly bridgedCount: Node<number>;\n\t/**\n\t * Emits each mapped batch as DATA — gives downstream observers a reactive\n\t * stream of bridged values. Also the link target for `target._log.attach`.\n\t */\n\treadonly output: Node<readonly TOut[]>;\n\n\tconstructor(\n\t\tname: string,\n\t\tsourceTopic: TopicGraph<TIn>,\n\t\ttargetTopic: TopicGraph<TOut>,\n\t\topts: TopicBridgeOptions<TIn, TOut> = {},\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tthis._sourceSub = subscription<TIn>(`${name}-subscription`, sourceTopic, {\n\t\t\tcursor: opts.cursor,\n\t\t});\n\t\tthis.mount(\"subscription\", this._sourceSub);\n\n\t\tconst maxPerPump = Math.max(\n\t\t\t1,\n\t\t\trequireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, \"topic bridge maxPerPump\"),\n\t\t);\n\t\tconst mapValue = opts.map ?? ((value: TIn) => value as unknown as TOut);\n\n\t\t// Reactive output node: derives a mapped batch from `available`.\n\t\t// §24 compliant — output is a real derived edge, visible in describe.\n\t\t// Replaces imperative publish loop. Items where mapValue returns undefined\n\t\t// are filtered out (opt-out / filter).\n\t\tthis.output = node<readonly TOut[]>(\n\t\t\t[this._sourceSub.available],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst arr = data[0] as readonly TIn[];\n\t\t\t\tconst outBatch: TOut[] = [];\n\t\t\t\tconst take = Math.min(arr.length, maxPerPump);\n\t\t\t\tfor (let i = 0; i < take; i++) {\n\t\t\t\t\tconst mapped = mapValue(arr[i] as TIn);\n\t\t\t\t\tif (mapped !== undefined) outBatch.push(mapped);\n\t\t\t\t}\n\t\t\t\tactions.emit(outBatch);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"output\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_output\", { targetRef: targetTopic.name }),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.output, { name: \"output\" });\n\t\tthis.addDisposer(keepalive(this.output));\n\n\t\t// bridgedCount: state node accumulating total bridged items.\n\t\t// Updated by ackPump after each batch — edge visible via ackPump dep on output.\n\t\tthis.bridgedCount = this.state<number>(\"bridgedCount\", 0, {\n\t\t\tmeta: messagingMeta(\"topic_bridge_count\"),\n\t\t});\n\t\tthis.addDisposer(keepalive(this.bridgedCount));\n\n\t\t// ackPump: effect that advances the subscription cursor and updates\n\t\t// bridgedCount after each batch. Runs after `output` settles.\n\t\t// Captures refs to `this.output`, `this._sourceSub`, `this.bridgedCount`\n\t\t// to avoid `this` inside the fn body.\n\t\tconst outputRef = this.output;\n\t\tconst subRef = this._sourceSub;\n\t\tconst countRef = this.bridgedCount;\n\t\tconst ackPump = this.effect(\n\t\t\t\"ackPump\",\n\t\t\t[\"output\"],\n\t\t\t() => {\n\t\t\t\tconst outBatch = outputRef.cache as readonly TOut[];\n\t\t\t\tif (outBatch.length === 0) return;\n\t\t\t\tconst availLen = (subRef.available.cache as readonly TIn[]).length;\n\t\t\t\tconst toAck = Math.min(availLen, maxPerPump);\n\t\t\t\tif (toAck > 0) {\n\t\t\t\t\tsubRef.ack(toAck);\n\t\t\t\t\tconst prev = (countRef.cache as number) ?? 0;\n\t\t\t\t\tcountRef.emit(prev + outBatch.length);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: messagingMeta(\"topic_bridge_ack_pump\"),\n\t\t\t},\n\t\t);\n\t\tthis.addDisposer(keepalive(ackPump));\n\n\t\t// Wire output into target topic's log reactively.\n\t\t// _attachArrayToLog subscribes to output and publishes each item to targetTopic.\n\t\t// Teardown: disposer runs before mount teardown.\n\t\tconst detach = _attachArrayToLog(this.output, targetTopic);\n\t\tthis.addDisposer(detach);\n\t}\n}\n\n/**\n * Attaches each element of an array-valued Node to a TopicGraph's log.\n * Every DATA emission on `source` appends all items in the array to `targetTopic`.\n * Returns a disposer.\n */\nfunction _attachArrayToLog<T>(source: Node<readonly T[]>, targetTopic: TopicGraph<T>): () => void {\n\treturn source.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst arr = m[1] as readonly T[];\n\t\t\tif (arr.length === 0) continue;\n\t\t\tbatch(() => {\n\t\t\t\tfor (const v of arr) targetTopic.publish(v);\n\t\t\t});\n\t\t}\n\t});\n}\n\n// ── TopicRegistry ─────────────────────────────────────────────────────────\n\n/**\n * Private pure data structure managing a named set of {@link TopicGraph}\n * instances. Extracted from {@link MessagingHubGraph} for separation of\n * concerns (B.2 Unit 14 lock: D — split into TopicRegistry + facade).\n *\n * Reusable if other domain consumers (e.g. cqrs.eventLogs) want a shared\n * topic registry later.\n *\n * @internal\n */\nexport class TopicRegistry {\n\tprivate readonly _map = new Map<string, TopicGraph<unknown>>();\n\t/** Reactive monotonic version counter. Advances on topic create/remove. */\n\treadonly version: Node<number>;\n\n\tconstructor(versionNode: Node<number>) {\n\t\tthis.version = versionNode;\n\t}\n\n\tget size(): number {\n\t\treturn this._map.size;\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this._map.has(name);\n\t}\n\n\tget<T>(name: string): TopicGraph<T> | undefined {\n\t\treturn this._map.get(name) as TopicGraph<T> | undefined;\n\t}\n\n\tset<T>(name: string, t: TopicGraph<T>): void {\n\t\tthis._map.set(name, t as TopicGraph<unknown>);\n\t}\n\n\tdelete(name: string): boolean {\n\t\treturn this._map.delete(name);\n\t}\n\n\tkeys(): IterableIterator<string> {\n\t\treturn this._map.keys();\n\t}\n}\n\n// ── MessagingHubGraph ─────────────────────────────────────────────────────\n\nexport type MessagingHubOptions = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Default `TopicOptions` applied to every topic created via `topic(name)`\n\t * without explicit options. Per-call opts override. Default: `{}`\n\t * (unbounded retention per topic unless `retainedLimit` is set per call).\n\t */\n\tdefaultTopicOptions?: TopicOptions;\n};\n\n/**\n * Lazy Pulsar-inspired topic registry. Manages a named set of {@link TopicGraph}\n * instances with retention + cursor semantics. Topics are created on first\n * access; `removeTopic(name)` unmounts and tears down via {@link Graph.remove}.\n *\n * Internally delegates to {@link TopicRegistry} for topic map management\n * (B.2 Unit 14 lock: D facade split).\n *\n * **Relationship to `pubsub()` in `src/extra/pubsub.ts`:** `pubsub` is a\n * lightweight last-value state hub (no retention, no cursors). `MessagingHubGraph`\n * is the full messaging hub — retained message logs, cursor-based subscriptions,\n * and pattern-layer lifecycle management.\n *\n * @category patterns\n */\nexport class MessagingHubGraph extends Graph {\n\tprivate readonly _registry: TopicRegistry;\n\t/** Reactive monotonic version counter — advances on topic create/remove. */\n\treadonly version: Node<number>;\n\tprivate readonly _defaultTopicOptions: TopicOptions;\n\tprivate readonly _removeTopicImpl: (name: string) => void;\n\n\tconstructor(name: string, opts: MessagingHubOptions = {}) {\n\t\tsuper(name, opts.graph);\n\t\t// B.2 Unit 14 lock: promote _version → version: Node<number>.\n\t\tconst versionNode = this.state<number>(\"version\", 0, {\n\t\t\tmeta: messagingMeta(\"hub_version\"),\n\t\t});\n\t\tthis.version = versionNode;\n\t\tthis._registry = new TopicRegistry(versionNode);\n\t\t// P8: shallow-copy caller-provided defaults so post-construction\n\t\t// mutations by the caller don't leak into every future `topic()` call.\n\t\tthis._defaultTopicOptions = { ...(opts.defaultTopicOptions ?? {}) };\n\n\t\t// Tier 8 / COMPOSITION-GUIDE §35: route the registry-delete branch of\n\t\t// `removeTopic` through `mutate` for centralized re-throw\n\t\t// semantics. No audit log surface (per Tier 8 γ-0).\n\t\t// `freeze: false` because the only arg is a string name (freeze pointless).\n\t\t// **Closure-state caveat (γ-4):** the inner `try/finally` mutates\n\t\t// `_registry` (a `Map`) and emits the version bump. mutate has no\n\t\t// `batch()` frame, so reactive emissions are NOT rolled back on throw —\n\t\t// and even if it did, `Map.delete` on closure state is invisible to the\n\t\t// batch and can't be unwound. The pre-existing try/finally on\n\t\t// `Graph.remove` is what guarantees registry/version converge to a\n\t\t// consistent state when `remove()` throws; `mutate` adds nothing\n\t\t// to that contract beyond the re-throw.\n\t\tthis._removeTopicImpl = mutate<[string], void, never>(\n\t\t\t(topicName): void => {\n\t\t\t\ttry {\n\t\t\t\t\tthis.remove(topicName); // unmounts, drops edges, tears down\n\t\t\t\t} finally {\n\t\t\t\t\tthis._registry.delete(topicName);\n\t\t\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\t\t\tthis.version.emit(cur + 1);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ frame: \"inline\", freeze: false },\n\t\t);\n\t}\n\n\t/** Number of topics currently in the hub. */\n\tget size(): number {\n\t\treturn this._registry.size;\n\t}\n\n\t/** Checks topic existence without creating. */\n\thas(name: string): boolean {\n\t\treturn this._registry.has(name);\n\t}\n\n\t/** Iterator over topic names. */\n\ttopicNames(): IterableIterator<string> {\n\t\treturn this._registry.keys();\n\t}\n\n\t/**\n\t * Returns the {@link TopicGraph} for `name`, creating lazily on first call.\n\t * Subsequent calls with the same name return the same instance (options on\n\t * repeat calls are ignored — the topic is already configured).\n\t */\n\ttopic<T = unknown>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\t\tlet t = this._registry.get<T>(name);\n\t\tif (t === undefined) {\n\t\t\tconst effective: TopicOptions = { ...this._defaultTopicOptions, ...(opts ?? {}) };\n\t\t\tt = new TopicGraph<T>(name, effective);\n\t\t\tthis._registry.set(name, t);\n\t\t\tthis.mount(name, t);\n\t\t\tconst cur = (this.version.cache as number) ?? 0;\n\t\t\tthis.version.emit(cur + 1);\n\t\t}\n\t\treturn t;\n\t}\n\n\t/**\n\t * Publishes a value to the topic, lazily creating it on first publish.\n\t *\n\t * **Late-subscriber caveat:** the topic is created lazily, so subscribers\n\t * that attach AFTER a publish only see the retained window (governed by\n\t * `retainedLimit` on `TopicOptions` / `defaultTopicOptions`). If\n\t * `retainedLimit === 0` is set explicitly, early publishes are\n\t * effectively dropped — prefer an unset `retainedLimit` (unbounded\n\t * retention) or subscribe before publishing when late-subscribers matter.\n\t */\n\tpublish<T = unknown>(name: string, value: T): void {\n\t\tthis.topic<T>(name).publish(value);\n\t}\n\n\t/**\n\t * Bulk publish — issues all publishes inside one outer batch. New topics\n\t * are created on demand. No-op if `entries` yields nothing.\n\t *\n\t * **Iterable consumption (F6):** `entries` is consumed once (single-pass)\n\t * INSIDE the batch frame. If the iterator throws mid-way, the batch is\n\t * discarded and NO publishes are visible to subscribers (all-or-nothing).\n\t * Pass an array or `Set` for multi-shot callers.\n\t */\n\tpublishMany(entries: Iterable<[string, unknown]>): void {\n\t\t// P2: iterate inside batch — no `[...entries]` materialization so large\n\t\t// / infinite iterables don't OOM, and iterator throws are contained.\n\t\tbatch(() => {\n\t\t\tfor (const [name, value] of entries) {\n\t\t\t\tthis.topic(name).publish(value);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Creates a {@link SubscriptionGraph} over a named topic. The topic is\n\t * lazily created if missing. Subscription lifecycle is owned by the caller —\n\t * the hub does NOT mount the subscription.\n\t *\n\t * @param subName - Local name for the subscription graph.\n\t * @param topicName - Hub topic to subscribe to.\n\t * @param opts - `SubscriptionOptions` (initial cursor, etc.).\n\t */\n\tsubscribe<T = unknown>(\n\t\tsubName: string,\n\t\ttopicName: string,\n\t\topts?: SubscriptionOptions,\n\t): SubscriptionGraph<T> {\n\t\tconst t = this.topic<T>(topicName);\n\t\treturn new SubscriptionGraph<T>(subName, t, opts);\n\t}\n\n\t/**\n\t * Unmounts and tears down the topic's graph. Returns `true` if the topic\n\t * existed. Subscribers receive `TEARDOWN` via {@link Graph.remove}.\n\t *\n\t * **Closure-state caveat:** the registry mutation (`_registry.delete`) and\n\t * version bump happen in a `try/finally`, so registry/version converge to\n\t * a consistent state even when {@link Graph.remove} throws. `mutate`\n\t * does not roll back this mutation on throw — `Map.delete` on closure\n\t * state is invisible to any batch frame. The pre-existing try/finally is\n\t * load-bearing for that invariant.\n\t */\n\tremoveTopic(name: string): boolean {\n\t\tif (!this._registry.has(name)) return false;\n\t\t// P1 / P3: Graph.remove first — if it throws, `_registry` must NOT still\n\t\t// hold the broken half-disposed topic (otherwise the next\n\t\t// `hub.topic(name)` returns the corrupted reference). The `try/finally`\n\t\t// inside `_removeTopicImpl`'s action body preserves that invariant.\n\t\tthis._removeTopicImpl(name);\n\t\treturn true;\n\t}\n}\n\n/**\n * Creates a Pulsar-inspired topic graph (append-only retained stream + latest value).\n */\nexport function topic<T>(name: string, opts?: TopicOptions): TopicGraph<T> {\n\treturn new TopicGraph<T>(name, opts);\n}\n\n/**\n * Creates a lazy Pulsar-inspired messaging hub. Topics are created on first access\n * via `hub.topic(name)`; `hub.publish(name, value)` shortcuts through the registry.\n *\n * @example\n * ```ts\n * import { messagingHub } from \"@graphrefly/graphrefly\";\n *\n * const hub = messagingHub(\"main\", { defaultTopicOptions: { retainedLimit: 256 } });\n * hub.publish(\"orders\", { id: 1 });\n * hub.publishMany([[\"shipments\", { id: 1 }], [\"orders\", { id: 2 }]]);\n * const sub = hub.subscribe(\"orders-worker\", \"orders\", { cursor: 0 });\n * ```\n */\nexport function messagingHub(name: string, opts?: MessagingHubOptions): MessagingHubGraph {\n\treturn new MessagingHubGraph(name, opts);\n}\n\n/**\n * Creates a cursor-based subscription graph over a topic.\n */\nexport function subscription<T>(\n\tname: string,\n\ttopicGraph: TopicGraph<T>,\n\topts?: SubscriptionOptions,\n): SubscriptionGraph<T> {\n\treturn new SubscriptionGraph<T>(name, topicGraph, opts);\n}\n\n/**\n * Creates an autonomous cursor-based topic relay graph.\n *\n * When `opts.map` is provided, items where `map` returns `undefined` are\n * consumed from the source cursor but NOT republished (at-most-once with\n * silent drop). For filter-with-retry semantics, apply the filter in a\n * downstream subscription on the bridge's `output` node instead.\n */\nexport function topicBridge<TIn, TOut = TIn>(\n\tname: string,\n\tsourceTopic: TopicGraph<TIn>,\n\ttargetTopic: TopicGraph<TOut>,\n\topts?: TopicBridgeOptions<TIn, TOut>,\n): TopicBridgeGraph<TIn, TOut> {\n\treturn new TopicBridgeGraph<TIn, TOut>(name, sourceTopic, targetTopic, opts);\n}\n\n// ── LogProjector ──────────────────────────────────────────────────────────\n//\n// Promotion 2 (memo:Re Story 6.4 back-derivation, design-review-locked\n// 2026-05-16). A cursor-driven projector over a log/topic where a per-item\n// sink can poison-fail. memo:Re hand-rolled `createProjectorCursor` and got\n// the failure mode wrong: a bare `catch { break; }` conflated a *transient*\n// condition (a native feature not yet available → retry later) with a\n// *poison* entry (will never project) → a permanent head-of-line block of\n// every newer entry. The fix is a real, observable, subscribable dead-letter\n// topic + a typed failure policy.\n//\n// Built ON `subscription()` (TopicGraph source) / the bundle's `fromCursor`\n// view (ReactiveLogBundle source) — the same hardened cursor machinery\n// `SubscriptionGraph` itself uses — so the consumer never hand-rolls cursor\n// persistence/durability (the Med \"durability skew\" + parse-leniency findings\n// dissolve). Scope is deliberately bounded: `halt | deadLetter` only, NO\n// programmatic retry/backoff (compose a downstream subscription on\n// `deadLetter` for that — avoids the §44 wrap-imperative-as-primitive trap).\n\nexport type ProjectorPoisonPolicy = \"halt\" | \"deadLetter\";\n\n/** A poison entry routed to {@link LogProjectorGraph.deadLetter}. */\nexport type DeadLetterEntry<T> = {\n\treadonly item: T;\n\t/** `Error.message` (or `String(thrown)`) from the failing `sink`. */\n\treadonly error: string;\n\t/** Absolute 0-based log position of the poisoned item. */\n\treadonly cursorPos: number;\n};\n\nexport type LogProjectorOptions<T> = {\n\tgraph?: GraphOptions;\n\t/**\n\t * Per-item side-effecting projection.\n\t *\n\t * **Transient-vs-poison contract (read this).** The projector cannot tell\n\t * \"this will project later\" from \"this will never project\" — only the sink\n\t * knows. So the contract is:\n\t * - **Return normally** (sync return, or a resolved Promise) → the item is\n\t * *handled*; the cursor advances. Use this for the success path AND for\n\t * any transient/skip condition the sink wants to no-op (e.g. an optional\n\t * native feature not yet available — return without throwing; the entry\n\t * is simply considered done for this projector).\n\t * - **Throw / reject** → the item is *poison*; the {@link onPoison} policy\n\t * applies. Do NOT throw for transient conditions or the item is\n\t * dead-lettered (or halts the stream).\n\t */\n\treadonly sink: (item: T) => void | Promise<void>;\n\t/**\n\t * Behaviour when `sink` throws/rejects on an item (poison):\n\t * - `\"halt\"` (default) — stop projecting at the poison item; the cursor\n\t * does NOT advance past it (head-of-line stop). `position` stalls — that\n\t * is the observable signal. No retry/backoff is built in.\n\t * - `\"deadLetter\"` — publish `{ item, error, cursorPos }` to the\n\t * {@link LogProjectorGraph.deadLetter} topic and advance past it, so\n\t * newer entries still project.\n\t */\n\treadonly onPoison?: ProjectorPoisonPolicy;\n\t/**\n\t * Initial cursor position. `\"retained\"` (default) projects all history;\n\t * `\"now\"` skips existing entries (project only future appends); a number\n\t * starts at that absolute index.\n\t */\n\treadonly from?: \"retained\" | \"now\" | number;\n\t/** Retained window for the `deadLetter` topic. Default 1024. */\n\treadonly deadLetterRetainedLimit?: number;\n};\n\n/**\n * Cursor-driven projector over a {@link TopicGraph} or {@link ReactiveLogBundle}.\n *\n * Topology (mounted on the returned graph):\n * - `subscription` (TopicGraph source only) — the hardened\n * {@link SubscriptionGraph} cursor; or a local `cursor` state + the\n * bundle's `fromCursor` view (ReactiveLogBundle source).\n * - `drain` — an `effect` that, on every not-yet-projected wave, schedules a\n * serialized async pass that calls `sink` per item (mirrors the\n * `SubscriptionGraph.ackPump` / `TopicBridge.ackPump` effect precedent +\n * memo:Re's `inFlight` chain — one wave processed at a time).\n * - `deadLetter` — a real {@link TopicGraph} (NOT a callback): poison entries\n * are observable in `describe()` and subscribable, instead of memo:Re's\n * silent `break`.\n *\n * **No imperative reads.** Observe `position` (cursor) / subscribe to\n * `deadLetter`. `idle()` is a test-only await convenience.\n *\n * @category patterns\n */\nexport class LogProjectorGraph<T> extends Graph {\n\t/** Reactive count of fully-projected entries (the cursor; read-only). */\n\treadonly position: Node<number>;\n\t/**\n\t * Poison entries (populated when `onPoison: \"deadLetter\"`). A real topic —\n\t * subscribable + visible in `describe()`.\n\t */\n\treadonly deadLetter: TopicGraph<DeadLetterEntry<T>>;\n\tprivate _inFlight: Promise<void> = Promise.resolve();\n\n\tconstructor(\n\t\tname: string,\n\t\tsource: TopicGraph<T> | ReactiveLogBundle<T>,\n\t\topts: LogProjectorOptions<T>,\n\t) {\n\t\tsuper(name, opts.graph);\n\t\tconst onPoison: ProjectorPoisonPolicy = opts.onPoison ?? \"halt\";\n\t\tconst sink = opts.sink;\n\n\t\tconst dl = new TopicGraph<DeadLetterEntry<T>>(`${name}_dead_letter`, {\n\t\t\tretainedLimit: opts.deadLetterRetainedLimit ?? DEFAULT_TOPIC_RETAINED_LIMIT,\n\t\t});\n\t\tthis.mount(\"deadLetter\", dl);\n\t\tthis.deadLetter = dl;\n\n\t\t// Uniform cursor surface over either source kind. A TopicGraph reuses\n\t\t// the hardened SubscriptionGraph cursor; a ReactiveLogBundle uses a\n\t\t// local state cursor + the bundle's `fromCursor` view — the very\n\t\t// machinery SubscriptionGraph is itself built on.\n\t\tlet available: Node<readonly T[]>;\n\t\tlet cursorBase: () => number;\n\t\tlet advance: (n: number) => void;\n\n\t\tif (source instanceof TopicGraph) {\n\t\t\tconst sub = new SubscriptionGraph<T>(`${name}_subscription`, source, {\n\t\t\t\tfrom: opts.from ?? \"retained\",\n\t\t\t});\n\t\t\tthis.mount(\"subscription\", sub);\n\t\t\tavailable = sub.available;\n\t\t\tthis.position = sub.cursor;\n\t\t\tcursorBase = () => sub.cursor.cache as number;\n\t\t\tadvance = (n) => {\n\t\t\t\tif (n > 0) sub.ack(n);\n\t\t\t};\n\t\t} else {\n\t\t\tconst log = source;\n\t\t\tlet initialCursor: number;\n\t\t\tif (opts.from === \"now\") {\n\t\t\t\tinitialCursor = log.size;\n\t\t\t} else if (typeof opts.from === \"number\") {\n\t\t\t\tinitialCursor = requireNonNegativeInt(opts.from, \"logProjector from\");\n\t\t\t} else {\n\t\t\t\tinitialCursor = 0; // \"retained\"\n\t\t\t}\n\t\t\tconst cursor = this.state<number>(\"cursor\", initialCursor, {\n\t\t\t\tmeta: messagingMeta(\"log_projector_cursor\"),\n\t\t\t});\n\t\t\tthis.position = cursor;\n\t\t\tcursorBase = () => cursor.cache as number;\n\t\t\tavailable = log.view({ kind: \"fromCursor\", cursor });\n\t\t\tadvance = (n) => {\n\t\t\t\tif (n > 0) cursor.emit((cursor.cache as number) + n);\n\t\t\t};\n\t\t}\n\n\t\t// `halt` is a HARD LATCH (QA-C): on the first poison under `onPoison:\n\t\t// \"halt\"`, `sink` has been invoked exactly once on the poison item;\n\t\t// the projector then freezes — no further `sink` calls, no rescheduled\n\t\t// drains — so a later unrelated append cannot re-invoke the (possibly\n\t\t// side-effecting, non-idempotent) sink on the poison. The stalled\n\t\t// `position` + frozen stream IS the observable signal. v1 has no retry\n\t\t// (compose downstream of `deadLetter` if you need that).\n\t\tlet halted = false;\n\n\t\t// Serialized async drain. One wave processed at a time (the inFlight\n\t\t// chain) so an async `sink` cannot interleave; the cursor is advanced\n\t\t// ONCE per pass after the captured snapshot is processed (mirrors\n\t\t// memo:Re's `runPump` + the ackPump effect precedent).\n\t\tconst runDrain = async (): Promise<void> => {\n\t\t\tif (halted) return;\n\t\t\tconst snapshot = (available.cache as readonly T[] | undefined) ?? [];\n\t\t\tif (snapshot.length === 0) return;\n\t\t\tlet consumed = 0;\n\t\t\tfor (let i = 0; i < snapshot.length; i += 1) {\n\t\t\t\tconst item = snapshot[i] as T;\n\t\t\t\ttry {\n\t\t\t\t\tawait sink(item);\n\t\t\t\t\tconsumed += 1;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconst error = e instanceof Error ? e.message : String(e);\n\t\t\t\t\tif (onPoison === \"deadLetter\") {\n\t\t\t\t\t\tdl.publish({ item, error, cursorPos: cursorBase() + consumed });\n\t\t\t\t\t\tconsumed += 1; // advance past the poison\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// \"halt\" — latch and stop here; do NOT advance past the\n\t\t\t\t\t// poison, do NOT re-invoke `sink` on any later wave.\n\t\t\t\t\thalted = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (consumed > 0) advance(consumed);\n\t\t};\n\t\tconst schedule = (): void => {\n\t\t\tif (halted) return; // latched — no further drains\n\t\t\tthis._inFlight = this._inFlight.then(runDrain, runDrain);\n\t\t};\n\n\t\t// Effect: every wave that exposes not-yet-projected entries schedules a\n\t\t// drain. Side-effecting (sink / cursor advance / dead-letter publish) →\n\t\t// an `effect` node, not a pure derived (COMPOSITION-GUIDE §35; exact\n\t\t// `SubscriptionGraph.advancePump` precedent — never calls `emit` on its\n\t\t// own node, kept warm via `keepalive`).\n\t\tconst drain = node<unknown>(\n\t\t\t[available],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst b = batchData[0];\n\t\t\t\tconst snap = (b != null && b.length > 0 ? b.at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly T[]\n\t\t\t\t\t| undefined;\n\t\t\t\tif (snap && snap.length > 0) schedule();\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"drain\",\n\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\tmeta: messagingMeta(\"log_projector_drain\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(drain, { name: \"drain\" });\n\t\tthis.addDisposer(keepalive(drain));\n\t}\n\n\t/**\n\t * Await any in-flight drain pass. **Test convenience only** — the canonical\n\t * reactive observable is {@link LogProjectorGraph.position}.\n\t */\n\tidle(): Promise<void> {\n\t\treturn this._inFlight;\n\t}\n}\n\n/**\n * Creates a cursor-driven log/topic projector with a typed poison-failure\n * policy and an observable dead-letter topic.\n *\n * @example\n * ```ts\n * import { logProjector, topic } from \"@graphrefly/graphrefly\";\n *\n * const events = topic<Doc>(\"docs\");\n * const proj = logProjector(\"indexer\", events, {\n * sink: async (doc) => { await index(doc); }, // throw ⇒ poison\n * onPoison: \"deadLetter\",\n * });\n * proj.deadLetter.events.subscribe(/* observe poison */);\n * ```\n *\n * @remarks\n * **Use an UNBOUNDED source for durable / long-lived projection.** The cursor\n * is an absolute index; the underlying `fromCursor` view slices the source's\n * *current* entries array. A `TopicGraph` with a `retainedLimit` (or a\n * `ReactiveLogBundle` with `maxSize`) trims its head, so an absolute cursor\n * past the retained window reads the wrong offset (skips entries or stalls).\n * This is inherited `subscription()` / `fromCursor` behaviour, not specific to\n * `logProjector` — but it matters here because projection is typically\n * long-lived. For unbounded projection pass a source with NO `retainedLimit` /\n * `maxSize` (memo:Re's `changesetLog` is unbounded ✓).\n *\n * @category patterns\n */\nexport function logProjector<T>(\n\tname: string,\n\tsource: TopicGraph<T> | ReactiveLogBundle<T>,\n\topts: LogProjectorOptions<T>,\n): LogProjectorGraph<T> {\n\treturn new LogProjectorGraph<T>(name, source, opts);\n}\n","/**\n * Universal mutation framework (Phase 14 — DS-14 locked 2026-05-05).\n *\n * Single `mutate(act, opts)` factory replaces the prior `lightMutation` +\n * `wrapMutation` two-tier split (pre-1.0 break per Q-O2).\n *\n * Two frames:\n * - `\"inline\"` — no batch; up() runs raw. Seq bumps before action; persists\n * on throw. Hot-path-friendly for atomic single-write mutations.\n * - `\"transactional\"` — opens `batch(() => up(...))`. On throw: batch discards\n * deferred deliveries, then `down()` runs (if provided), then failure record.\n *\n * Phase-4 primitives share the same shape: imperative mutation methods +\n * closure state + reactive audit log + freeze-at-entry + rollback-on-throw.\n * This module factors out the common machinery so each primitive becomes\n * declarative wiring over typed audit records.\n */\n\nimport {\n\tbatch,\n\tDATA,\n\tDIRTY,\n\ttype Node,\n\ttype NodeGuard,\n\tnode,\n\tpolicy,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport {\n\ttype ReactiveLogBundle,\n\ttype ReactiveLogOptions,\n\treactiveLog,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\n\n// ── tryIncrementBounded ──────────────────────────────────────────────────\n\n/**\n * Bounded increment for a self-owned counter state node.\n *\n * Reads `counter.cache`, bumps by `by` (default 1) if `cur + by <= cap`,\n * writes back. Returns `false` when the cap would be exceeded (no-op write).\n * Documented P3 exception: the counter is not a declared dep of the caller —\n * it's a private budget read+written from a single call site. This helper\n * keeps the `.cache` access in one named place so caller bodies (which may\n * be inside reactive fn execution paths) stay free of cross-node `.cache`\n * reads.\n *\n * **Safety today:**\n * 1. Single-threaded JS runner never invokes the caller concurrently.\n * 2. `counter.down` writes the cache synchronously before returning, so\n * synchronous re-entry through a downstream publish reads the\n * freshly-incremented value — no double-count.\n *\n * **Future risk:** under a free-threaded runner (PY no-GIL or hypothetical\n * concurrent TS runner), two concurrent firings could still race. Revisit\n * when that surfaces.\n *\n * @param counter - Self-owned counter Node. Caller is the sole writer.\n * @param cap - Upper bound (inclusive). Pass `Number.MAX_SAFE_INTEGER` for\n * \"effectively unbounded\" use cases (e.g. token meters).\n * @param by - Delta to add (default `1`). Must be a finite non-negative\n * number; callers should pre-validate. Overflow-safe via\n * `by > cap - cur` check rather than `cur + by >= cap`.\n */\nexport function tryIncrementBounded(counter: Node<number>, cap: number, by = 1): boolean {\n\tconst cur = (counter.cache as number | undefined) ?? 0;\n\tif (by > cap - cur) return false;\n\tcounter.down([[DIRTY], [DATA, cur + by]]);\n\treturn true;\n}\n\n// ── Audit record schema ──────────────────────────────────────────────────\n\n/** Shared base shape for every audit record. Per-primitive types extend this. */\nexport interface BaseAuditRecord {\n\treadonly t_ns: number;\n\treadonly seq?: number;\n\treadonly handlerVersion?: { id: string; version: string | number };\n}\n\n// ── Default audit guard ──────────────────────────────────────────────────\n\n/**\n * Allow `observe` and `signal`; deny external `write` on the audit log so\n * consumers can subscribe + signal-bridge but cannot inject fake records.\n */\nexport const DEFAULT_AUDIT_GUARD: NodeGuard = policy((allow, deny) => {\n\tallow(\"observe\");\n\tallow(\"signal\");\n\tdeny(\"write\");\n});\n\n// ── createAuditLog ───────────────────────────────────────────────────────\n\nexport type AuditLogOpts<R extends BaseAuditRecord> = {\n\tname: string;\n\t/** Bounded retention; default 1024 per Audit 2 / cross-cutting bounded-default policy. */\n\tretainedLimit?: number;\n\t/** Override the default audit guard. */\n\tguard?: NodeGuard;\n\t/** Mount the audit `entries` Node under this graph (and activate withLatest). */\n\tgraph?: Graph;\n\t/** Pass-through to {@link reactiveLog}. */\n\tversioning?: ReactiveLogOptions<R>[\"versioning\"];\n};\n\n/**\n * Build a reactive audit log with sane defaults: bounded retention, deny-write\n * guard, `withLatest()` companions activated. Returns the {@link ReactiveLogBundle}\n * directly — primitives expose this as `<primitive>.events` / `.decisions` /\n * `.dispatches` / `.invocations` and alias it as `.audit`.\n *\n * @category internal\n */\nexport function createAuditLog<R extends BaseAuditRecord>(\n\topts: AuditLogOpts<R>,\n): ReactiveLogBundle<R> {\n\tconst log = reactiveLog<R>([], {\n\t\tname: opts.name,\n\t\tmaxSize: opts.retainedLimit ?? 1024,\n\t\tguard: opts.guard ?? DEFAULT_AUDIT_GUARD,\n\t\t...(opts.versioning != null ? { versioning: opts.versioning } : {}),\n\t});\n\t// Lazy companion activation up-front so `bundle.lastValue` / `hasLatest`\n\t// are queryable without an explicit `withLatest()` call.\n\tlog.withLatest();\n\tif (opts.graph) {\n\t\topts.graph.add(log.entries, { name: opts.name });\n\t}\n\treturn log;\n}\n\n/**\n * Read-only projection of a {@link ReactiveLogBundle}. Exposes only the\n * observation surface (`entries` / `size` / `at` / `withLatest` / `lastValue`\n * / `view` / `scan` / `mutationLog`) — the mutators (`append` / `appendMany`\n * / `clear` / `trimHead` / `attach` / `attachStorage`) and the lifecycle\n * disposers are intentionally absent.\n */\nexport type ReadonlyAuditLog<R> = Pick<\n\tReactiveLogBundle<R>,\n\t\"entries\" | \"size\" | \"at\" | \"withLatest\" | \"lastValue\" | \"view\" | \"scan\" | \"mutationLog\"\n>;\n\n/**\n * Wrap an audit log so the `.audit` alias a primitive exposes (the Audit-2\n * `.audit` duplication convention — `saga.audit` / `cqrs.audit` /\n * `jobQueue.audit` / `processManager.audit`) is a **stable read-only view**,\n * not the live mutable bundle. Closes M7: a consumer calling\n * `someGraph.audit.append(...)` would otherwise silently mutate the owning\n * primitive's canonical log. The returned object is frozen and shares the\n * underlying log's nodes (zero copy) — reads are byte-identical to the live\n * bundle; mutators are simply not present (compile-time) and the object is\n * frozen (run-time defense for JS callers).\n *\n * @category internal\n */\nexport function readonlyAuditLog<R>(log: ReactiveLogBundle<R>): ReadonlyAuditLog<R> {\n\treturn Object.freeze({\n\t\tget entries() {\n\t\t\treturn log.entries;\n\t\t},\n\t\tget size() {\n\t\t\treturn log.size;\n\t\t},\n\t\tget lastValue() {\n\t\t\treturn log.lastValue;\n\t\t},\n\t\tget mutationLog() {\n\t\t\treturn log.mutationLog;\n\t\t},\n\t\tat: log.at.bind(log),\n\t\twithLatest: log.withLatest.bind(log),\n\t\tview: log.view.bind(log),\n\t\tscan: log.scan.bind(log),\n\t}) satisfies ReadonlyAuditLog<R>;\n}\n\n// ── Universal mutation factory (Phase 14 — DS-14 lock Q-O2/Q-O3) ────────\n//\n// Single `mutate(act, opts)` factory. Two frames:\n//\n// - `\"inline\"` — no batch frame; up() runs raw. Seq bumps before action;\n// persists on throw. Hot-path-friendly for atomic single-write mutations.\n//\n// - `\"transactional\"` — opens `batch(() => up(...))`. On throw: batch discards\n// deferred deliveries, then `down()` runs, then failure record persists.\n//\n// **Heuristic:** if your imperative method's body is one or two lines (mutate\n// state, emit), use `frame: \"inline\"`. If it runs a user-supplied handler or\n// has multiple steps that could leave inconsistent state mid-throw, use\n// `frame: \"transactional\"`.\n\nexport type FailureMeta = {\n\tt_ns: number;\n\tseq?: number;\n\terrorType: string;\n};\n\nexport type SuccessMeta = {\n\tt_ns: number;\n\tseq?: number;\n};\n\n/**\n * Mutation action shape. Plain function shorthand auto-wraps as `{ up: fn }`.\n *\n * - `up` — the mutation action (the \"up migration\").\n * - `down` — optional rollback for closure mutations that `batch()` can't\n * reach. Receives the SAME frozen args as `up`. Runs AFTER batch reactive\n * rollback, BEFORE the failure record. Throws inside `down` are\n * console.error'd without masking the original error. Only meaningful\n * with `frame: \"transactional\"`.\n */\nexport type MutationAct<TArgs extends readonly unknown[], TResult> = {\n\tup: (...args: TArgs) => TResult;\n\tdown?: (...args: TArgs) => void;\n};\n\nexport type MutationFrame = \"inline\" | \"transactional\";\n\nexport type MutateOpts<TArgs extends readonly unknown[], TResult, R extends BaseAuditRecord> = {\n\t/** Frame mode. `\"inline\"` = no batch; `\"transactional\"` = batch + rollback. */\n\tframe: MutationFrame;\n\t/**\n\t * Optional log to append records to. When omitted, the wrapper still\n\t * provides freeze / seq-advance / rollback-on-throw but skips record\n\t * emission — useful for primitives that want centralized mutation\n\t * semantics without a dedicated log surface (e.g. `Topic.publish`).\n\t */\n\tlog?: ReactiveLogBundle<R>;\n\t/** Build the success record from the action's args + result + meta. */\n\tonSuccessRecord?: (args: TArgs, result: TResult, meta: SuccessMeta) => R | undefined;\n\t/** Build the failure record from the args + error + meta. */\n\tonFailureRecord?: (args: TArgs, error: unknown, meta: FailureMeta) => R | undefined;\n\t/** Deep-freeze args at entry (default `true`). Opt out for hot paths. */\n\tfreeze?: boolean;\n\t/** Optional sequence cursor — auto-advanced and stamped onto records. */\n\tseq?: Node<number>;\n\t/** Optional handler version — stamped per Audit 5. */\n\thandlerVersion?: { id: string; version: string | number };\n};\n\nfunction deepFreeze<T>(value: T): T {\n\tif (value === null || typeof value !== \"object\" || Object.isFrozen(value)) return value;\n\tfor (const k of Object.keys(value as Record<string, unknown>)) {\n\t\tdeepFreeze((value as Record<string, unknown>)[k]);\n\t}\n\treturn Object.freeze(value);\n}\n\n/**\n * Universal mutation factory (Phase 14 — DS-14 Q-O2).\n *\n * Replaces the prior `lightMutation` + `wrapMutation` two-tier split.\n * Single factory with `frame: \"inline\" | \"transactional\"` discriminant.\n *\n * @param act - The mutation action. Either a plain function (auto-wrapped as\n * `{ up: fn }`) or a `{ up, down? }` object for explicit rollback.\n * @param opts - Configuration: frame, log, record builders, freeze, seq.\n * @returns A typed wrapper function with the same signature as `act.up`.\n */\nexport function mutate<TArgs extends readonly unknown[], TResult, R extends BaseAuditRecord>(\n\tact: MutationAct<TArgs, TResult> | ((...args: TArgs) => TResult),\n\topts: MutateOpts<TArgs, TResult, R>,\n): (...args: TArgs) => TResult {\n\tconst { up, down } = typeof act === \"function\" ? { up: act, down: undefined } : act;\n\tconst freeze = opts.freeze ?? true;\n\n\tif (opts.frame === \"inline\") {\n\t\treturn function wrapped(...args: TArgs): TResult {\n\t\t\tconst sealed = freeze ? (args.map(deepFreeze) as unknown as TArgs) : args;\n\t\t\tconst t_ns = wallClockNs();\n\t\t\tconst seq = opts.seq ? bumpCursor(opts.seq) : undefined;\n\t\t\ttry {\n\t\t\t\tconst result = up(...sealed);\n\t\t\t\tif (opts.log && opts.onSuccessRecord) {\n\t\t\t\t\tappendAudit<TArgs, TResult, R, SuccessMeta>(\n\t\t\t\t\t\topts.log,\n\t\t\t\t\t\topts.onSuccessRecord,\n\t\t\t\t\t\tsealed,\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t{ t_ns, seq },\n\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (err) {\n\t\t\t\tif (opts.log && opts.onFailureRecord) {\n\t\t\t\t\tconst errorType = err instanceof Error ? err.name : typeof err;\n\t\t\t\t\tappendAudit<TArgs, unknown, R, FailureMeta>(\n\t\t\t\t\t\topts.log,\n\t\t\t\t\t\topts.onFailureRecord,\n\t\t\t\t\t\tsealed,\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t{ t_ns, seq, errorType },\n\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t};\n\t}\n\n\t// frame === \"transactional\"\n\treturn function wrapped(...args: TArgs): TResult {\n\t\tconst sealed = freeze ? (args.map(deepFreeze) as unknown as TArgs) : args;\n\t\tconst t_ns = wallClockNs();\n\t\tlet result: TResult;\n\t\tlet captured: unknown;\n\t\tlet captureSet = false;\n\t\tlet seq: number | undefined;\n\t\ttry {\n\t\t\tbatch(() => {\n\t\t\t\tif (opts.seq) seq = bumpCursor(opts.seq);\n\t\t\t\ttry {\n\t\t\t\t\tresult = up(...sealed);\n\t\t\t\t\tif (opts.log && opts.onSuccessRecord) {\n\t\t\t\t\t\tappendAudit<TArgs, TResult, R, SuccessMeta>(\n\t\t\t\t\t\t\topts.log,\n\t\t\t\t\t\t\topts.onSuccessRecord,\n\t\t\t\t\t\t\tsealed,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\t{ t_ns, seq },\n\t\t\t\t\t\t\topts.handlerVersion,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tcaptured = err;\n\t\t\t\t\tcaptureSet = true;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (outerErr) {\n\t\t\t// Fire `down` AFTER batch's reactive rollback, BEFORE failure record.\n\t\t\t// Gate on `captureSet` — if the throw came from outside the inner try\n\t\t\t// (framework-level batch error before action ran), don't fire down.\n\t\t\tif (captureSet && down) {\n\t\t\t\ttry {\n\t\t\t\t\tdown(...sealed);\n\t\t\t\t} catch (downErr) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`mutate: down hook threw — original action error preserved (${\n\t\t\t\t\t\t\tcaptured instanceof Error ? captured.name : typeof captured\n\t\t\t\t\t\t}). Down error:`,\n\t\t\t\t\t\tdownErr,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (captureSet && opts.log && opts.onFailureRecord) {\n\t\t\t\tconst errorType = captured instanceof Error ? captured.name : typeof captured;\n\t\t\t\tappendAudit<TArgs, unknown, R, FailureMeta>(\n\t\t\t\t\topts.log,\n\t\t\t\t\topts.onFailureRecord,\n\t\t\t\t\tsealed,\n\t\t\t\t\tcaptured,\n\t\t\t\t\t{ t_ns, seq, errorType },\n\t\t\t\t\topts.handlerVersion,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow captureSet ? captured : outerErr;\n\t\t}\n\t\treturn result!;\n\t};\n}\n\n/**\n * Advance a cursor node and return the new value. Emits `[DIRTY], [DATA, next]`\n * directly on the cursor — atomic outside a batch, rollback-discardable inside.\n *\n * Resets to `0` if the cursor cache is missing, non-numeric, `NaN`, or\n * non-finite (e.g. corrupted by `restore()` from a malformed snapshot, or\n * by a misbehaving codec). `??` alone would let `NaN` and `\"\"` pass through\n * and silently corrupt audit ordering downstream.\n *\n * **Silent reset diagnostic (EH-12).** When the cache holds a non-numeric\n * value at bump time, the cursor restarts at 0 and the next bump returns 1\n * — colliding with the seq stamped on the very first record after construct.\n * To make seq-monotonicity violations after a restore visible to operators,\n * the helper emits a one-shot `console.warn` per cursor instance describing\n * the offending value. The cursor is identified by a `WeakSet<Node<number>>`\n * so the warning fires exactly once per node — repeat malformed bumps stay\n * quiet to avoid log spam. Production callers wanting to suppress can swap\n * the global `console` (universal-safe code path; no Node-only API used).\n *\n * Works whether or not the cursor has any subscribers — `down` updates the\n * cache regardless, so primitives that bump before consumers attach (e.g.\n * `JobQueueGraph.enqueue`) still see a coherent sequence.\n *\n * @category internal\n */\nconst _bumpCursorWarned = new WeakSet<Node<number>>();\nexport function bumpCursor(seq: Node<number>): number {\n\tconst raw = seq.cache;\n\tconst valid = typeof raw === \"number\" && Number.isFinite(raw);\n\tif (!valid && raw !== undefined && !_bumpCursorWarned.has(seq)) {\n\t\t_bumpCursorWarned.add(seq);\n\t\tconsole.warn(\n\t\t\t`bumpCursor: cursor cache held a non-numeric value (${String(raw)}); resetting to 0. ` +\n\t\t\t\t\"Causes include: a snapshot codec round-tripping the cursor as a string / null / NaN, \" +\n\t\t\t\t\"OR a malformed initial seed (e.g. state<number>(NaN)). \" +\n\t\t\t\t\"Audit consumers may see colliding seq values after this point.\",\n\t\t);\n\t}\n\tconst cur = valid ? raw : 0;\n\tconst next = cur + 1;\n\tseq.down([[DIRTY], [DATA, next]]);\n\treturn next;\n}\n\n/**\n * Build a record via the supplied builder, stamp `handlerVersion` if present,\n * and append it to the audit log. `undefined` records are skipped (callers\n * pass an `onSuccess` / `onFailure` that returns `undefined` to opt out per\n * call).\n *\n * @category internal\n */\nexport function appendAudit<\n\tTArgs extends readonly unknown[],\n\tTValue,\n\tR extends BaseAuditRecord,\n\tM extends SuccessMeta | FailureMeta,\n>(\n\taudit: ReactiveLogBundle<R>,\n\tbuilder: (args: TArgs, value: TValue, meta: M) => R | undefined,\n\targs: TArgs,\n\tvalue: TValue,\n\tmeta: M,\n\thandlerVersion?: { id: string; version: string | number },\n): void {\n\tconst record = builder(args, value, meta);\n\tif (record === undefined) return;\n\tconst stamped = handlerVersion != null ? ({ ...record, handlerVersion } as R) : record;\n\taudit.append(stamped);\n}\n\n// ── registerCursor / registerCursorMap ───────────────────────────────────\n\n/**\n * Promote a closure counter to a state node mounted under `graph`.\n * Replaces ad-hoc `let _seq = 0` patterns with a node observable in\n * `describe()` and persistable via storage tiers.\n *\n * @category internal\n */\nexport function registerCursor(graph: Graph, name: string, initial = 0): Node<number> {\n\tconst cursor = node<number>([], { initial, name, describeKind: \"state\" });\n\tgraph.add(cursor, { name });\n\treturn cursor;\n}\n\n/**\n * Promote a closure `Map<K, number>` to N state nodes (one per key) mounted\n * under `<graph>::<name>::<key>`. Used by saga (per-event-type cursor).\n *\n * @category internal\n */\nexport function registerCursorMap<K extends string>(\n\tgraph: Graph,\n\tname: string,\n\tkeys: readonly K[],\n\tinitial = 0,\n): { readonly [P in K]: Node<number> } {\n\tconst out = {} as { [P in K]: Node<number> };\n\t// Mount cursors under a child plain-Graph so per-key node names stay flat\n\t// (path-separator `::` is reserved by Graph.add). Using `Graph` directly\n\t// rather than `graph.constructor` avoids spawning a typed subclass with\n\t// an incompatible constructor signature (e.g., CqrsGraph(name, opts)).\n\tconst sub = new Graph(name);\n\tfor (const k of keys) {\n\t\tconst cursor = node<number>([], {\n\t\t\tinitial,\n\t\t\tname: k,\n\t\t\tdescribeKind: \"state\",\n\t\t});\n\t\tsub.add(cursor, { name: k });\n\t\tout[k] = cursor;\n\t}\n\tgraph.mount(name, sub);\n\treturn out;\n}\n","/**\n * Reactive agent loop — autonomous multi-turn LLM agent with tool execution.\n */\n\nexport type AgentLoopStatus = \"idle\" | \"thinking\" | \"acting\" | \"done\" | \"error\";\n\nimport {\n\tbatch,\n\tDATA,\n\tERROR,\n\tINVALIDATE,\n\ttype Node,\n\tnode,\n\tnode as nodeFactory,\n\tplaceholderArgs,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, keepalive, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { awaitSettled } from \"../../base/sources/settled.js\";\nimport { aiMeta } from \"../../utils/ai/_internal.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMResponse,\n\tToolCall,\n\tToolDefinition,\n} from \"../../utils/ai/adapters/core/types.js\";\nimport { type ChatStreamGraph, chatStream } from \"../../utils/ai/agents/chat-stream.js\";\nimport { type ToolResult, toolExecution } from \"../../utils/ai/agents/tool-execution.js\";\nimport { type ToolRegistryGraph, toolRegistry } from \"../../utils/ai/agents/tool-registry.js\";\n\nexport type { ToolResult } from \"../../utils/ai/agents/tool-execution.js\";\n\n// ---------------------------------------------------------------------------\n// agentLoop\n// ---------------------------------------------------------------------------\n\nexport type AgentLoopOptions = {\n\tgraph?: GraphOptions;\n\tadapter: LLMAdapter;\n\ttools?: readonly ToolDefinition[];\n\tsystemPrompt?: string;\n\tmaxTurns?: number;\n\tstopWhen?: (response: LLMResponse) => boolean;\n\tonToolCall?: (call: ToolCall) => void;\n\tmaxMessages?: number;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Reactive tool-call splice (COMPOSITION-GUIDE §31 \"interception is security\").\n\t * When set, the raw `toolCalls` node is piped through this transform before\n\t * reaching the executor. The transform is a pure reactive composition —\n\t * `(calls: Node<readonly ToolCall[]>) => Node<readonly ToolCall[]>` — so the\n\t * gate is visible in `describe()` / `explain()` as a real edge (no hidden\n\t * imperative wraps; §24).\n\t *\n\t * Typical uses:\n\t * - **Filter / block** — `derived([calls, policy], ([raw, p]) => raw.filter(p))`\n\t * - **Throttle / debounce** — `throttle(calls, windowMs)`\n\t * - **Human-in-the-loop approval** — pipe through a `gate` controller so\n\t * calls wait for human approval before reaching the executor.\n\t *\n\t * The public `agent.toolCalls` node surfaces the POST-intercept stream, so\n\t * audit / telemetry consumers see what the executor actually runs. The raw\n\t * pre-intercept stream is not exposed — tests that need it should run\n\t * without `interceptToolCalls` set (the identity case).\n\t */\n\tinterceptToolCalls?: (calls: Node<readonly ToolCall[]>) => Node<readonly ToolCall[]>;\n};\n\n/**\n * Reactive agent loop.\n *\n * The loop is a reactive state machine wired entirely from graph primitives:\n * `chat.messages` + `tools.schemas` + gating state feed a `promptInput`\n * derived; `switchMap` turns non-null inputs into an LLM invocation via\n * `fromAny(adapter.invoke(...))`. The LLM response drives chat writes and\n * status transitions via effects. Tool calls flow through a reactive\n * executor (`retrySource` + `rescue`) that retries once on error and\n * surfaces terminal errors as JSON-shaped `ToolResult` payloads for the\n * LLM to react to.\n *\n * **No imperative control flow inside the reactive layer** (spec §5.8-5.12):\n * no `while` loops, no manual `await adapter.invoke`, no polling.\n * `agent.run()` is a thin `awaitSettled` bridge so callers can still `await`\n * the loop if they want a Promise.\n *\n * Public surface:\n * - `chat` / `tools` — subgraphs (imperative `append` at boundary, reactive `executeReactive` for tool invocation)\n * - `status` / `turn` / `aborted` — state nodes with explicit initials\n * - `lastResponse` / `toolCalls` / `toolResults` — reactive outputs (SENTINEL until first emission; callers use `awaitSettled` / `subscribe`)\n * - `run(userMessage?, signal?)` — optional user append + Promise bridge\n * - `abort()` — imperative abort shim; flips `aborted` state\n *\n * **Lifecycle: single-mount.** `AgentLoopGraph` instances expect to be\n * constructed once and used until `destroy()`. The internal closure mirrors\n * (`latestTurn` / `latestAborted` / `latestStatus`) are wired by\n * subscribe-and-capture at construction time; their `addDisposer`-registered\n * subscriptions are torn down on subgraph unmount or `destroy()`. After\n * teardown the mirrors freeze at their last value, so re-using a destroyed\n * instance — calling `run()` again, or remounting under a new parent —\n * would silently feed stale mirror data into reactive fn bodies. If you\n * need to \"reset\" an agent, build a fresh `AgentLoopGraph` instance instead\n * of recycling.\n */\nexport class AgentLoopGraph extends Graph {\n\treadonly chat: ChatStreamGraph;\n\treadonly tools: ToolRegistryGraph;\n\n\t/** Current agent status. `initial: \"idle\"` — always has a real value. */\n\treadonly status: Node<AgentLoopStatus>;\n\t/** Turn count (completed LLM invocations this run). `initial: 0`. */\n\treadonly turn: Node<number>;\n\t/** Aborted flag; flipped by `abort()` or external `AbortSignal`. `initial: false`. */\n\treadonly aborted: Node<boolean>;\n\n\t/**\n\t * Most recent LLM response. State-backed mirror driven by the response\n\t * effect. **Stays SENTINEL** (`cache === undefined`, no DATA emitted)\n\t * until the first real response — bridge subscribers see no spurious\n\t * push-on-subscribe DATA. After a real response, holds the latest\n\t * `LLMResponse`. Reset between `run()` calls via `[[INVALIDATE]]` (clears\n\t * cache back to SENTINEL) so a second run with a pre-aborted signal\n\t * cannot leak the prior run's response. Bridge with\n\t * `awaitSettled(lastResponse)` for the first DATA as a Promise; consumers\n\t * inside reactive fns gate on `ctx.prevData[i] === undefined`.\n\t */\n\treadonly lastResponse: Node<LLMResponse>;\n\t/** Tool-call batch emitted by the most recent LLM response. SENTINEL. */\n\treadonly toolCalls: Node<readonly ToolCall[]>;\n\t/** Tool-result batch (one entry per call) after reactive execution. SENTINEL. */\n\treadonly toolResults: Node<readonly ToolResult[]>;\n\n\tprivate readonly _terminalResult: Node<LLMResponse>;\n\tprivate readonly _disposeRunWiring: () => void;\n\t/** Guards against overlapping `run()` calls. */\n\tprivate _running = false;\n\t/**\n\t * Abort controller for the currently-running `adapter.invoke`. Minted per\n\t * switchMap project; aborted when the reactive `aborted` node flips true\n\t * OR when the caller's external `AbortSignal` fires. Threaded into\n\t * `adapter.invoke({ signal })` AND `fromAny(promise, { signal })`, so the\n\t * reactive layer sees ERROR when the wire call is cancelled.\n\t */\n\tprivate _currentAbortController: AbortController | null = null;\n\n\tconstructor(name: string, opts: AgentLoopOptions) {\n\t\tsuper(name, opts.graph);\n\n\t\t// Mount chat subgraph\n\t\tthis.chat = chatStream(`${name}-chat`, { maxMessages: opts.maxMessages });\n\t\tthis.mount(\"chat\", this.chat);\n\n\t\t// Mount tool registry subgraph\n\t\tthis.tools = toolRegistry(`${name}-tools`);\n\t\tthis.mount(\"tools\", this.tools);\n\n\t\tif (opts.tools) {\n\t\t\tfor (const tool of opts.tools) {\n\t\t\t\tthis.tools.register(tool);\n\t\t\t}\n\t\t}\n\n\t\t// --- State nodes (always have a real value; explicit initials) ---\n\t\tthis.status = node<AgentLoopStatus>([], {\n\t\t\t...{\n\t\t\t\tname: \"status\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_status\"),\n\t\t\t},\n\t\t\tinitial: \"idle\",\n\t\t});\n\t\tthis.add(this.status, { name: \"status\" });\n\n\t\tthis.turn = node<number>([], {\n\t\t\t...{\n\t\t\t\tname: \"turn\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_turn_count\"),\n\t\t\t},\n\t\t\tinitial: 0,\n\t\t});\n\t\tthis.add(this.turn, { name: \"turn\" });\n\n\t\tthis.aborted = node<boolean>([], {\n\t\t\t...{\n\t\t\t\tname: \"aborted\",\n\t\t\t\tdescribeKind: \"state\",\n\t\t\t\tmeta: aiMeta(\"agent_aborted\"),\n\t\t\t},\n\t\t\tinitial: false,\n\t\t});\n\t\tthis.add(this.aborted, { name: \"aborted\" });\n\n\t\t// --- Reactive pipeline ---\n\t\t//\n\t\t// **Read pattern (Phase 12 D1 lock + F2 fix 2026-05-01).** State\n\t\t// scratchpad held on this `AgentLoopGraph` (turn / aborted / chat /\n\t\t// tools) is read inside reactive fn bodies via either:\n\t\t// (a) `data[i]` / `ctx.prevData[i]` for declared deps, OR\n\t\t// (b) sole-owner `.cache` reads on subgraph-mounted state Nodes\n\t\t// (chat / tools mounted as subgraphs of this Graph; the agent\n\t\t// is the sole owner; promptInput / effResponse / effResults\n\t\t// live in the same enclosing constructor scope — sanctioned\n\t\t// form per Phase 12 D1 read-pattern lock).\n\t\t//\n\t\t// Closure mirrors (`latestTurn` / `latestAborted` / `latestStatus`)\n\t\t// are kept ONLY for fields where (b) doesn't simplify the call site\n\t\t// — turn / aborted / status are state Nodes registered on `this`\n\t\t// directly (not subgraphs), and the closure form keeps\n\t\t// effResponse's batch logic readable. They are CORRECT but are NOT\n\t\t// safe under nested drains (the subscribe handler may not have run\n\t\t// yet when a downstream fn reads the closure). For nested-drain-\n\t\t// reachable reads (promptInput, called via `agentLoop.run` from\n\t\t// inside another graph's reactive subscribe handler), prefer (a) or\n\t\t// (b) over the closure mirror. F2 root cause: chat.messages.cache\n\t\t// is updated DURING the DATA-settle phase (before subscribers\n\t\t// run), so `.cache` reads are always at least as fresh as closure\n\t\t// mirrors. See `optimizations.md` \"Phase 13 design-session inputs\n\t\t// from §13.M lock-test\" F2.\n\t\t//\n\t\t// **Pattern note on `latestTurn` staleness under in-batch reads.**\n\t\t// Effect 1 emits `turnNode.emit(next)` inside its batch; Effect 2\n\t\t// reads `latestTurn` on the following wave (after toolResults\n\t\t// settle). Because batch drain is FIFO, `turnSub`'s handler runs\n\t\t// before Effect 2's next wave fires, so `latestTurn` is up-to-date\n\t\t// by the time Effect 2 reads it. This invariant is stable as long\n\t\t// as `turnNode.emit` remains inside Effect 1's batch — a future\n\t\t// refactor that un-batches the emit would regress silently.\n\t\tlet latestTurn = 0;\n\t\tconst turnSub = this.turn.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestTurn = m[1] as number;\n\t\t});\n\t\tlet latestAborted = false;\n\t\tconst abortedSub = this.aborted.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestAborted = m[1] as boolean;\n\t\t});\n\n\t\tconst adapter = opts.adapter;\n\t\tconst systemPrompt = opts.systemPrompt;\n\t\tconst model = opts.model;\n\t\tconst temperature = opts.temperature;\n\t\tconst maxTokens = opts.maxTokens;\n\t\tconst maxTurns = opts.maxTurns ?? 10;\n\t\tconst stopWhen = opts.stopWhen;\n\n\t\t// Capture `this` for closures that don't bind `this`.\n\t\tconst chat = this.chat;\n\t\tconst tools = this.tools;\n\t\tconst statusNode = this.status;\n\t\tconst turnNode = this.turn;\n\t\tconst abortedNode = this.aborted;\n\n\t\t// promptInput: STATUS is the only reactive trigger — chat.messages,\n\t\t// tools.schemas, turn, aborted are sampled via closure-held mirrors\n\t\t// (all populated by subscribe-and-capture above). This prevents the\n\t\t// classic feedback cycle (COMPOSITION-GUIDE §7): if chat.messageCount\n\t\t// were a reactive dep here, effect 1's `chat.append` would trigger a\n\t\t// promptInput wave, which under effect-1's batch would see status\n\t\t// STILL \"thinking\" (pre-drain) and fire a spurious LLM invocation.\n\t\t// By gating only on status, chat writes don't re-trigger — only\n\t\t// explicit status transitions do.\n\t\tconst promptInput: Node<InvokeInput> = nodeFactory<InvokeInput>(\n\t\t\t[statusNode],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 0, \"idle\");\n\t\t\t\tif (stat !== \"thinking\" || latestAborted || latestTurn >= maxTurns) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// F2 fix (2026-05-01): under nested drains, the closure mirrors\n\t\t\t\t// `latestMessages` / `latestSchemas` lag the actual node state —\n\t\t\t\t// messagesSub / schemasSub subscribers may not have run yet when\n\t\t\t\t// promptInput fires (the drain processes status's downstream\n\t\t\t\t// before chat.messages's subscribers fire, even though\n\t\t\t\t// chat.messages.cache is already settled). Read `.cache`\n\t\t\t\t// directly per Phase 12 D1 read-pattern lock: chat / tools are\n\t\t\t\t// mounted as subgraphs of this AgentLoopGraph (sole owner) and\n\t\t\t\t// promptInput is a reactive reader in the same enclosing\n\t\t\t\t// constructor scope — sanctioned `.cache` form. See\n\t\t\t\t// `optimizations.md` \"Phase 13 design-session inputs from §13.M\n\t\t\t\t// lock-test\" F2.\n\t\t\t\tconst messages = (this.chat.messages.cache as readonly ChatMessage[] | undefined) ?? [];\n\t\t\t\tif (messages.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst schemas = (this.tools.schemas.cache as readonly ToolDefinition[] | undefined) ?? [];\n\t\t\t\tactions.emit({ messages, tools: schemas });\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"promptInput\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_prompt_input\", {\n\t\t\t\t\t// State this fn body samples beyond its declared `statusNode`\n\t\t\t\t\t// dep. `aborted` / `turn` come from §28 closure mirrors\n\t\t\t\t\t// (`latestAborted` / `latestTurn`); `chat.messages` /\n\t\t\t\t\t// `tools.schemas` come from sole-owner `.cache` reads\n\t\t\t\t\t// (Phase 12 D1 lock + F2 fix; see comment block above).\n\t\t\t\t\t// Listed here so inspection tooling can surface fold-in\n\t\t\t\t\t// state without grepping source.\n\t\t\t\t\tclosureReads: [\"aborted\", \"turn\", \"chat.messages\", \"tools.schemas\"],\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tconst llmResponse: Node<LLMResponse> = switchMap(\n\t\t\tpromptInput,\n\t\t\t(input) => {\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tthis._currentAbortController = controller;\n\t\t\t\tif (latestAborted) {\n\t\t\t\t\tcontroller.abort(new Error(\"agentLoop: aborted\"));\n\t\t\t\t}\n\t\t\t\t// Wave A Unit B-CC fix: drop the `Promise.resolve(adapter.invoke(...))`\n\t\t\t\t// wrapper. `adapter.invoke` returns a `NodeInput<LLMResponse>`\n\t\t\t\t// (Promise | Node | raw). `fromAny` already handles all three\n\t\t\t\t// shapes; the manual `Promise.resolve` wrapper would force a\n\t\t\t\t// Node-returning adapter into an extra microtask hop and lose\n\t\t\t\t// reactivity (see Unit 11 + Unit 1 for the parallel cleanup).\n\t\t\t\treturn fromAny(\n\t\t\t\t\tadapter.invoke(input.messages, {\n\t\t\t\t\t\ttools: input.tools.length > 0 ? input.tools : undefined,\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\ttemperature,\n\t\t\t\t\t\tmaxTokens,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t}),\n\t\t\t\t\t{ signal: controller.signal },\n\t\t\t\t);\n\t\t\t},\n\t\t\t{ equals: () => false },\n\t\t);\n\n\t\t// State mirror for `lastResponse` — exists for **cross-run reset\n\t\t// semantics**, NOT the §32 mid-wave hazard.\n\t\t//\n\t\t// Why: `llmResponse` is a switchMap output; its cache persists across\n\t\t// `run()` calls (switchMap's output node has no built-in reset path —\n\t\t// the cache stays at the last DATA the inner emitted). A second\n\t\t// `run()` with a pre-aborted signal would otherwise have\n\t\t// `_terminalResult` evaluate `stat=done` (driven by `effAbort`) +\n\t\t// `resp=<prior run's response>` (cached on `llmResponse`) and resolve\n\t\t// the Promise with stale data instead of rejecting with AbortError.\n\t\t// The mirror is **reset via `[[INVALIDATE]]`** in `run()`'s reset\n\t\t// batch — INVALIDATE clears `_cached` back to `undefined` (SENTINEL)\n\t\t// AND clears the `prevData` slot on every dependent (`_terminalResult`,\n\t\t// `toolCallsRaw`), so the abort path correctly emits\n\t\t// `[[ERROR, AbortError]]` from terminalResult's `stat=\"done\" &&\n\t\t// prevData[lastResponse] === undefined → ERROR` guard.\n\t\t//\n\t\t// **No `T | null` placeholder.** Per `feedback_use_prevdata_for_sentinel`\n\t\t// + COMPOSITION-GUIDE §1a, the SENTINEL state IS the \"never sent\n\t\t// real DATA yet\" signal. An eager `initial: null` would push `[null]`\n\t\t// to every fresh subscriber — a footgun for bridge subscribers that\n\t\t// would otherwise need `if (resp == null) continue` guards. Stay\n\t\t// SENTINEL; consumers detect \"no response yet\" via\n\t\t// `ctx.prevData[i] === undefined` (or `cache === undefined` outside\n\t\t// reactive fns). F9 lock-test (`multi-agent-example.test.ts` test 5)\n\t\t// pins this invariant.\n\t\t//\n\t\t// What this does NOT solve: the §32 mid-wave \"stale peer-read\"\n\t\t// hazard. Investigation (2026-04-25) confirmed `_dirtyDepCount`\n\t\t// gating in `_maybeRunFnOnSettlement` already prevents that — when\n\t\t// `effResponse`'s nested batch fires `status=\"done\"` mid-iteration,\n\t\t// terminal's status dep settles but its `llmResponse` (or mirror)\n\t\t// dep is still DIRTY from Phase 1, so the fn does not run until\n\t\t// Phase 2 visits both deps. Verified by fast-check invariant `#12b\n\t\t// nested-drain-peer-consistency-compound` and by the multi-turn\n\t\t// `executes tool calls and loops` test passing under either dep\n\t\t// shape (`[statusNode, llmResponse]` or `[statusNode, lastResponseState]`).\n\t\t//\n\t\t// Verified by: QA C3 regression tests (`run() with pre-aborted\n\t\t// signal rejects AbortError` and `second run() with pre-aborted\n\t\t// signal rejects AbortError (no stale response leak)`) — both\n\t\t// fail when `_terminalResult` is rewired to depend on `llmResponse`\n\t\t// directly. See COMPOSITION-GUIDE §32 (cross-wave reset reframe).\n\t\tconst lastResponseState = node<LLMResponse>([], {\n\t\t\tname: \"lastResponse\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: aiMeta(\"agent_last_response\"),\n\t\t});\n\t\tthis.lastResponse = lastResponseState;\n\n\t\t// toolCalls: raw node that emits DATA only when status === \"acting\" and\n\t\t// the current response has tool calls. Otherwise emits RESOLVED. Using\n\t\t// DATA([]) for the idle case would cause switchMap(toolCalls) to\n\t\t// re-dispatch its inner (creating a fresh node([], { initial: [] }) source whose\n\t\t// emissions re-trigger effects downstream). RESOLVED keeps the inner\n\t\t// alive and lets upstream waves pass through without re-dispatch.\n\t\t// Inner raw tool-call stream — name `toolCallsRaw` so the post-intercept\n\t\t// public surface (`this.toolCalls`) is unambiguous in `describe()`.\n\t\t// QA-fix: previously the inner was named `\"toolCalls\"`, which collided\n\t\t// with `this.toolCalls` if the user-supplied interceptor returned a\n\t\t// wrapper that internally retained a reference to this raw node —\n\t\t// `describe()` would render two distinct nodes both labeled `\"toolCalls\"`.\n\t\tconst toolCallsRaw = nodeFactory<readonly ToolCall[]>(\n\t\t\t[lastResponseState, statusNode],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\t// SENTINEL guard: `lastResponseState` stays `undefined` (cache\n\t\t\t\t// + prevData) until the first real response. `readLatest`'s\n\t\t\t\t// fallback returns `undefined` here so the no-DATA branch is\n\t\t\t\t// indistinguishable from the protocol SENTINEL — both gate to\n\t\t\t\t// RESOLVED. Per `feedback_use_prevdata_for_sentinel`.\n\t\t\t\tconst resp = readLatest<LLMResponse | undefined>(data, ctx.prevData, 0, undefined);\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 1, \"idle\");\n\t\t\t\tif (stat !== \"acting\") {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst calls = resp?.toolCalls;\n\t\t\t\tif (calls == null || calls.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.emit(calls);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"toolCallsRaw\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_tool_calls_raw\"),\n\t\t\t},\n\t\t);\n\t\t// Reactive splice (D9 / COMPOSITION-GUIDE §31). When `interceptToolCalls`\n\t\t// is set, the raw tool-call stream is transformed in the graph — the\n\t\t// executor sees the gated stream, and `agent.toolCalls` surfaces the\n\t\t// post-intercept view so audit / telemetry match reality.\n\t\tconst gatedToolCallsNode = opts.interceptToolCalls\n\t\t\t? opts.interceptToolCalls(toolCallsRaw)\n\t\t\t: toolCallsRaw;\n\t\tthis.toolCalls = gatedToolCallsNode;\n\n\t\t// Delegate per-call fan-out + retry + rescue to the `toolExecution`\n\t\t// primitive. `toolCallsRaw` already gates empty batches to RESOLVED,\n\t\t// so `toolExecution`'s \"non-empty batch only\" contract is satisfied\n\t\t// upstream. `retryCount: 1` matches the pre-extraction behaviour\n\t\t// (one retry after first failure = 2 attempts total).\n\t\tconst toolResultsNode: Node<readonly ToolResult[]> = toolExecution({\n\t\t\ttoolCalls: gatedToolCallsNode,\n\t\t\ttools,\n\t\t\tretryCount: 1,\n\t\t});\n\t\tthis.toolResults = toolResultsNode;\n\n\t\t// --- State-machine effects ---\n\t\t// Effect 1: LLM response landed → write lastResponse mirror + chat,\n\t\t// transition status, increment turn. Emission ORDER inside the batch\n\t\t// matters (drain is FIFO under any outer-batch depth):\n\t\t// 1. `lastResponseState.emit(response)` FIRST — so when the drain\n\t\t// fires the status=done wave later in the queue, `_terminalResult`'s\n\t\t// dep on `lastResponseState` has already been updated.\n\t\t// 2. `statusNode.emit(nextStatus)` — drives state machine.\n\t\t// 3. `turnNode.emit(next)` — counter.\n\t\t// 4. `chat.append(...)` LAST — chat.messageCount wave now sees the\n\t\t// new status (so `promptInput` gates correctly).\n\t\t// Without (1) first, `_terminalResult` reads stale `prevData` for\n\t\t// lastResponse when status transitions synchronously during drain.\n\t\t//\n\t\t// **Invariant independence from outer batch depth.** `downWithBatch`\n\t\t// preserves FIFO drain order regardless of nesting — whether the\n\t\t// outer batch is at depth 0 (common: Promise microtask) or depth >0\n\t\t// (user-composed `batch()` scope around `agent.run()`), the emissions\n\t\t// above drain in the order they were enqueued. The state-mirror\n\t\t// pattern holds in both cases.\n\t\t//\n\t\t// **Abort guard (C2 defense-in-depth).** If the `aborted` state has\n\t\t// flipped true between `adapter.invoke`'s Promise resolution and this\n\t\t// effect firing (micro-race), bail out so we don't append to chat or\n\t\t// execute tool calls for an abandoned run. The controller.abort() in\n\t\t// effAbort also fires the signal, which causes `fromAny` to emit\n\t\t// ERROR — but that ERROR propagation arrives in a separate wave, so\n\t\t// this guard covers the \"Promise already resolved before abort hit\n\t\t// the controller\" case.\n\t\tconst effResponse = node(\n\t\t\t[llmResponse],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tif (latestAborted) return;\n\t\t\t\tconst response = data[0] as LLMResponse;\n\t\t\t\tconst next = latestTurn + 1;\n\t\t\t\tconst hasToolCalls = response.toolCalls != null && response.toolCalls.length > 0;\n\t\t\t\tconst naturalStop =\n\t\t\t\t\tresponse.finishReason === \"end_turn\" &&\n\t\t\t\t\t(!response.toolCalls || response.toolCalls.length === 0);\n\t\t\t\tconst customStop = stopWhen?.(response) === true;\n\t\t\t\tconst capReached = next >= maxTurns;\n\t\t\t\tconst nextStatus: AgentLoopStatus =\n\t\t\t\t\tcustomStop || naturalStop || !hasToolCalls || capReached ? \"done\" : \"acting\";\n\t\t\t\tbatch(() => {\n\t\t\t\t\tlastResponseState.emit(response);\n\t\t\t\t\tstatusNode.emit(nextStatus);\n\t\t\t\t\tturnNode.emit(next);\n\t\t\t\t\tchat.append(\"assistant\", response.content, {\n\t\t\t\t\t\ttoolCalls: response.toolCalls,\n\t\t\t\t\t});\n\t\t\t\t\t// EC-2 (DS-2.7.A /qa carry, resolved 2026-05-21):\n\t\t\t\t\t// cap-reached with pending `tool_use` blocks needs synthetic\n\t\t\t\t\t// `tool_result`s — every `tool_use` requires a paired\n\t\t\t\t\t// `tool_result` per Anthropic/OpenAI tool-use schemas, else\n\t\t\t\t\t// audit/replay consumers replaying `loop.chat.allMessages()`\n\t\t\t\t\t// into a fresh `adapter.invoke` see an invalid transcript.\n\t\t\t\t\t// `effFullDeny` (when wired) CANNOT help here: status flips\n\t\t\t\t\t// to `\"done\"` in this same batch, so `toolCallsRaw` gates\n\t\t\t\t\t// RESOLVED on the next wave (its `stat === \"acting\"` guard)\n\t\t\t\t\t// and `effFullDeny`'s diamond never delivers DATA. Mirrors\n\t\t\t\t\t// `effFullDeny`'s `\"[tool call denied by interceptor]\"`\n\t\t\t\t\t// pattern with a maxTurns-specific reason string.\n\t\t\t\t\tif (capReached && hasToolCalls) {\n\t\t\t\t\t\tfor (const tc of response.toolCalls as readonly ToolCall[]) {\n\t\t\t\t\t\t\tchat.appendToolResult(tc.id, \"[tool call denied: maxTurns reached]\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Effect 2: Tool results landed → append to chat, transition to\n\t\t// thinking (or done if turn cap reached). Same ordering discipline —\n\t\t// status emits before chat mutations. Abort guard mirrors effResponse.\n\t\tconst effResults = node(\n\t\t\t[toolResultsNode],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tif (latestAborted) return;\n\t\t\t\tconst arr = data[0] as readonly ToolResult[];\n\t\t\t\tif (arr.length === 0) return;\n\t\t\t\tconst nextStatus: AgentLoopStatus = latestTurn >= maxTurns ? \"done\" : \"thinking\";\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusNode.emit(nextStatus);\n\t\t\t\t\tfor (const r of arr) chat.appendToolResult(r.id, r.content);\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Effect 2b: interceptor-denial recovery. `effResponse` commits\n\t\t// `status=\"acting\"` from the LLM's *pre-intercept* `response.toolCalls`.\n\t\t// When an interceptor denies EVERY call, the post-intercept stream emits\n\t\t// RESOLVED (no DATA) — `toolExecution` no-ops, `effResults` never fires,\n\t\t// and `status` is stranded at \"acting\" forever (`run()` never resolves;\n\t\t// the original liveness bug). On partial deny, `effResults` advances\n\t\t// status correctly for the allowed subset, but the *denied* subset has\n\t\t// no matching `tool_result` — every assistant `tool_use` block needs\n\t\t// one for the next `adapter.invoke` to see a valid transcript per the\n\t\t// LLM-vendor schemas. This effect handles both: it synthesizes\n\t\t// `\"[tool call denied by interceptor]\"` `tool_result`s for whichever\n\t\t// calls were dropped (the full set on full deny, the dropped subset on\n\t\t// partial deny) so the LLM can adapt under the policy (user-locked:\n\t\t// continue, not terminate).\n\t\t//\n\t\t// **Why a [raw, gated] diamond with explicit `partial: true` and NO\n\t\t// `ctx.latestData[1]` fallback.** `gatedToolCallsNode` derives from\n\t\t// `toolCallsRaw`, so the two deps form a diamond — the fn recomputes\n\t\t// once after both settle (spec §1.4 / §2.7), with `batchData[0]` = the\n\t\t// raw requested calls and `batchData[1]` = the gate's emission *this\n\t\t// wave*. The core `node()` default is `partial: false` (node.ts\n\t\t// `opts.partial ?? false`); under that default, an R2.7.0 first-run\n\t\t// gate would hold this fn forever once the gate hits a RESOLVED-only\n\t\t// dep (the gate releases only on real DATA per R2.7.0). Explicit\n\t\t// `partial: true` opts into spec R2.7.2 (DS-2.7.A, 2026-05-19): the\n\t\t// gate is OFF and the fn-body is contractually responsible for\n\t\t// guarding SENTINEL slots. We DELIBERATELY do not fall back to\n\t\t// `ctx.latestData[1]` (the public name for `DepRecord.prevData`):\n\t\t// the signal IS \"the gate delivered no DATA this wave\" (RESOLVED on\n\t\t// the full-deny branch). A fallback would read a *prior allowed\n\t\t// turn*'s calls and mask the deny.\n\t\t//\n\t\t// Only wired when an interceptor is configured (`gatedToolCallsNode\n\t\t// !== toolCallsRaw`): without one there is no deny path, and a\n\t\t// `[toolCallsRaw, toolCallsRaw]` duplicate-dep node would be pointless.\n\t\t//\n\t\t// **Closure-mirror staleness** — the `latestTurn` read below relies on\n\t\t// the same FIFO drain ordering invariant the existing block at lines\n\t\t// ~224–231 documents for `effResults`. `turnNode.emit` lives inside\n\t\t// `effResponse`'s outer batch; `turnSub` drains BEFORE the diamond\n\t\t// settles `effFullDeny`. A future refactor that un-batches that emit\n\t\t// would regress all three effects together — keep the discipline.\n\t\t//\n\t\t// **Belt-and-suspenders maxTurns guard.** On normal flow `effResponse`\n\t\t// already sets `status=\"done\"` when `next >= maxTurns`, so by the time\n\t\t// `toolCallsRaw` would fire (status===\"acting\" gate) we're past the\n\t\t// cap-reaching turn and `effFullDeny` doesn't run. The\n\t\t// `latestTurn >= maxTurns ? \"done\" : \"thinking\"` check below is\n\t\t// defense-in-depth in case a future refactor inverts the ordering\n\t\t// (cheap, no path to a runtime bug).\n\t\tconst effFullDeny =\n\t\t\tgatedToolCallsNode !== toolCallsRaw\n\t\t\t\t? node(\n\t\t\t\t\t\t[toolCallsRaw, gatedToolCallsNode],\n\t\t\t\t\t\t(batchData) => {\n\t\t\t\t\t\t\tif (latestAborted) return;\n\t\t\t\t\t\t\tconst rawBatch = batchData[0];\n\t\t\t\t\t\t\tconst gatedBatch = batchData[1];\n\t\t\t\t\t\t\tconst rawCalls =\n\t\t\t\t\t\t\t\trawBatch != null && rawBatch.length > 0\n\t\t\t\t\t\t\t\t\t? (rawBatch.at(-1) as readonly ToolCall[])\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t// No real request this wave (RESOLVED upstream) — nothing to recover.\n\t\t\t\t\t\t\tif (rawCalls == null || rawCalls.length === 0) return;\n\t\t\t\t\t\t\t// Gate's emission this wave — null/empty when the interceptor\n\t\t\t\t\t\t\t// produced RESOLVED (full deny); non-empty array of the allowed\n\t\t\t\t\t\t\t// subset on partial deny / full allow.\n\t\t\t\t\t\t\tconst gatedCalls =\n\t\t\t\t\t\t\t\tgatedBatch != null && gatedBatch.length > 0\n\t\t\t\t\t\t\t\t\t? (gatedBatch.at(-1) as readonly ToolCall[])\n\t\t\t\t\t\t\t\t\t: null;\n\t\t\t\t\t\t\t// Denied subset = calls in raw not present in gated (by id).\n\t\t\t\t\t\t\t// Full deny → all rawCalls. Partial deny → subtraction.\n\t\t\t\t\t\t\t// Full allow → empty array (no recovery needed).\n\t\t\t\t\t\t\tconst allowedIds = gatedCalls === null ? null : new Set(gatedCalls.map((c) => c.id));\n\t\t\t\t\t\t\tconst denied =\n\t\t\t\t\t\t\t\tallowedIds === null ? rawCalls : rawCalls.filter((c) => !allowedIds.has(c.id));\n\t\t\t\t\t\t\tif (denied.length === 0) return; // full allow — effResults owns it\n\t\t\t\t\t\t\tconst isFullDeny = gatedCalls === null;\n\t\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\t\t// Full deny → advance status here (effResults never fires).\n\t\t\t\t\t\t\t\t// Partial deny → DON'T touch status; effResults will transition\n\t\t\t\t\t\t\t\t// after the allowed subset's tool-execution completes, so we\n\t\t\t\t\t\t\t\t// only fill in the missing tool_results for the denied subset.\n\t\t\t\t\t\t\t\tif (isFullDeny) {\n\t\t\t\t\t\t\t\t\tstatusNode.emit(latestTurn >= maxTurns ? \"done\" : \"thinking\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (const c of denied)\n\t\t\t\t\t\t\t\t\tchat.appendToolResult(c.id, \"[tool call denied by interceptor]\");\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: \"fullDenyRecovery\",\n\t\t\t\t\t\t\tdescribeKind: \"effect\",\n\t\t\t\t\t\t\tmeta: aiMeta(\"agent_full_deny_recovery\"),\n\t\t\t\t\t\t\t// MUST be explicit: the core `node()` default is\n\t\t\t\t\t\t\t// `partial: false` (node.ts `opts.partial ?? false`),\n\t\t\t\t\t\t\t// and `gatedToolCallsNode` only ever emits RESOLVED on the\n\t\t\t\t\t\t\t// full-deny path (never DATA/terminal). Spec R2.7.0\n\t\t\t\t\t\t\t// (DS-2.7.A, 2026-05-19) holds the `partial: false`\n\t\t\t\t\t\t\t// first-run gate until every dep has contributed real\n\t\t\t\t\t\t\t// DATA, so a `partial: false` effFullDeny would hold the\n\t\t\t\t\t\t\t// fn FOREVER. Spec R2.7.2 = `partial: true` disables the\n\t\t\t\t\t\t\t// gate; the fn body's `denied`-subtraction guard above\n\t\t\t\t\t\t\t// covers the SENTINEL slot per the R2.7.2 author\n\t\t\t\t\t\t\t// contract.\n\t\t\t\t\t\t\tpartial: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t: null;\n\n\t\t// Effect 3: external abort → cancel in-flight wire call + terminal status.\n\t\t// Aborting the controller causes the switchMap inner's `fromAny` to\n\t\t// emit ERROR (signal-bound), which tears down the subscription. The\n\t\t// `status=\"done\"` emit drives `_terminalResult` to resolve `run()`'s\n\t\t// Promise (via AbortError when `resp == null`, see C3).\n\t\t//\n\t\t// Unit 4 Q5: status guard — if status is already \"done\" (the natural-\n\t\t// completion path raced the abort), skip the redundant emit so the\n\t\t// status-node event log isn't polluted with a trailing duplicate.\n\t\t// Closure-mirror `latestStatus` keeps the comparison synchronous and\n\t\t// P3-compliant (closure read, not `.cache` read — see §28). Seeded\n\t\t// from `statusNode.cache` to match the §28 factory-time-seed pattern\n\t\t// that `latestTurn` / `latestAborted` use — the literal `\"idle\"` would\n\t\t// silently drift if the constructor initial value ever changed.\n\t\tlet latestStatus: AgentLoopStatus = (statusNode.cache as AgentLoopStatus | undefined) ?? \"idle\";\n\t\tconst statusSub = statusNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestStatus = m[1] as AgentLoopStatus;\n\t\t});\n\t\tconst effAbort = node(\n\t\t\t[abortedNode],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tif (data[0] === true) {\n\t\t\t\t\tthis._currentAbortController?.abort(new Error(\"agentLoop: aborted\"));\n\t\t\t\t\tif (latestStatus !== \"done\") statusNode.emit(\"done\");\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ describeKind: \"effect\" },\n\t\t);\n\n\t\t// Keepalive so the pipeline stays activated even without external\n\t\t// subscribers. Callers don't need to subscribe to `llmResponse` /\n\t\t// `toolResults` for the loop to run.\n\t\tconst kaResponse = keepalive(effResponse);\n\t\tconst kaResults = keepalive(effResults);\n\t\tconst kaFullDeny = effFullDeny ? keepalive(effFullDeny) : null;\n\t\tconst kaAbort = keepalive(effAbort);\n\n\t\t// terminalResult emits the final `LLMResponse` on each \"done\"\n\t\t// transition. The old compound `{response, runVersion}` shape existed\n\t\t// to let a re-entrant caller's `awaitSettled` predicate filter out\n\t\t// the PREVIOUS run's cached DATA; that job now belongs to\n\t\t// `awaitSettled({skipCurrent: true})` (extra/sources.ts) which\n\t\t// ignores the initial push-on-subscribe DATA and resolves only on\n\t\t// fresh post-subscribe emissions. Retiring the stamp removes a\n\t\t// closure-held counter and a per-emission object allocation from\n\t\t// the hot path.\n\t\t//\n\t\t// C3 (abort-before-response) post-SENTINEL: when `stat === \"done\"` but\n\t\t// `lastResponseState` is SENTINEL (no DATA ever delivered for this\n\t\t// run — `prevData[1] === undefined`, equivalently `resp === undefined`\n\t\t// after `readLatest`'s fallback), emit `ERROR(AbortError)` so the\n\t\t// awaiting Promise rejects instead of hanging on a RESOLVED. The\n\t\t// SENTINEL state is restored at every `run()` boundary by\n\t\t// `lastResponse.down([[INVALIDATE]])` (clears `_cached` AND clears\n\t\t// each dependent's `prevData` slot for this dep), so a second run\n\t\t// after a successful first run still detects the abort cleanly —\n\t\t// no stale `prevData` leak.\n\t\tthis._terminalResult = nodeFactory<LLMResponse>(\n\t\t\t[statusNode, lastResponseState],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst stat = readLatest<AgentLoopStatus>(data, ctx.prevData, 0, \"idle\");\n\t\t\t\tconst resp = readLatest<LLMResponse | undefined>(data, ctx.prevData, 1, undefined);\n\t\t\t\tif (stat === \"done\") {\n\t\t\t\t\tif (resp !== undefined) {\n\t\t\t\t\t\tactions.emit(resp);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst err = new Error(\"agentLoop: aborted\") as Error & { name: string };\n\t\t\t\t\terr.name = \"AbortError\";\n\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (stat === \"error\") {\n\t\t\t\t\tactions.down([[ERROR, new Error(\"agentLoop: errored\")]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"terminalResult\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"agent_terminal_result\"),\n\t\t\t\t// `lastResponseState` is SENTINEL until the first real response\n\t\t\t\t// arrives — without `partial: true`, the spec §2.7 first-run\n\t\t\t\t// gate would block this fn from ever firing on the abort-\n\t\t\t\t// before-response path (`status → \"done\"` while `lastResponse`\n\t\t\t\t// has never delivered DATA). The fn explicitly handles the\n\t\t\t\t// SENTINEL case (`resp === undefined → ERROR(AbortError)`),\n\t\t\t\t// so partial-fire is safe by design.\n\t\t\t\tpartial: true,\n\t\t\t},\n\t\t);\n\t\t// Wave B-CC Q2/C: register intermediate pipeline nodes so consumers\n\t\t// can `observe(path)` them by name (e.g. `agent.observe(\"promptInput\")`).\n\t\t// They were already visible in `describe()` via dep traversal, but not\n\t\t// path-addressable. Tools using the `observe`-by-path API now work.\n\t\t//\n\t\t// QA-fix (#5 stability): registrations live AFTER ALL dependent nodes\n\t\t// are constructed (`promptInput → llmResponse → effResponse →\n\t\t// lastResponseState → toolCallsRaw → toolResultsNode → effResults →\n\t\t// effAbort → _terminalResult`). Topology event-stream consumers\n\t\t// subscribed at construction time now see registrations in an order\n\t\t// where every edge between two registered nodes is already valid —\n\t\t// no transient partial graph slipping through to live mermaid / d2\n\t\t// renderers.\n\t\tthis.add(promptInput as Node<unknown>, { name: \"promptInput\" });\n\t\tthis.add(llmResponse as Node<unknown>, { name: \"llmResponse\" });\n\t\tthis.add(this.lastResponse as Node<unknown>, { name: \"lastResponse\" });\n\t\t// When no interceptor is configured, `this.toolCalls === toolCallsRaw` —\n\t\t// registering the same instance under two names trips the per-graph\n\t\t// `_nodeToName` collision check. Register the raw under `toolCalls`\n\t\t// directly in that case; otherwise register both (raw + post-intercept).\n\t\tif (this.toolCalls === toolCallsRaw) {\n\t\t\tthis.add(this.toolCalls as Node<unknown>, { name: \"toolCalls\" });\n\t\t} else {\n\t\t\tthis.add(toolCallsRaw as Node<unknown>, { name: \"toolCallsRaw\" });\n\t\t\tthis.add(this.toolCalls as Node<unknown>, { name: \"toolCalls\" });\n\t\t}\n\t\tthis.add(toolResultsNode as Node<unknown>, { name: \"toolResults\" });\n\t\tthis.add(this._terminalResult as Node<unknown>, { name: \"terminalResult\" });\n\n\t\t// Register subscriptions via `addDisposer` so they tear down on\n\t\t// subgraph unmount (not just explicit `destroy()`). A caller that\n\t\t// unmounts the AgentLoopGraph from its parent via `graph.remove(...)`\n\t\t// would otherwise keep `turnSub` / `abortedSub` live against dead state.\n\t\tthis.addDisposer(turnSub);\n\t\tthis.addDisposer(abortedSub);\n\t\tthis.addDisposer(statusSub);\n\t\tthis.addDisposer(kaResponse);\n\t\tthis.addDisposer(kaResults);\n\t\tif (kaFullDeny) this.addDisposer(kaFullDeny);\n\t\tthis.addDisposer(kaAbort);\n\t\tthis._disposeRunWiring = (): void => {\n\t\t\t// addDisposer takes care of teardown; this shim stays for the\n\t\t\t// `destroy()` override's idempotency contract (safe no-op if the\n\t\t\t// disposers already fired).\n\t\t};\n\t}\n\n\t/**\n\t * Bridge to `Promise<LLMResponse>` over the reactive pipeline.\n\t *\n\t * - If `userMessage` is provided, appends it as a user message and\n\t * transitions status to `\"thinking\"` to kick the loop.\n\t * - If `signal` is provided, binds it to the reactive `aborted` node\n\t * AND threads into `adapter.invoke({ signal })` so the wire call can\n\t * cancel mid-flight. The reactive `aborted` state + effect 3 guarantee\n\t * that even an adapter that ignores `signal` will stop emitting into\n\t * the agent graph.\n\t * - Resolves when `status === \"done\"` with the final LLM response.\n\t * Rejects with `AbortError` when the abort signal fires pre-response.\n\t * Rejects with the stage error when `status === \"error\"`.\n\t *\n\t * **Concurrency:** `run()` refuses to overlap with a pending call on the\n\t * same agent. Attempting to call `run()` while a previous `run()` is\n\t * still in-flight throws a `RangeError` immediately. Stale-resolution\n\t * safety is provided by `awaitSettled({skipCurrent: true})`, which\n\t * ignores the cached initial DATA from any previous run and resolves\n\t * only on a fresh post-subscribe emission of `_terminalResult`.\n\t */\n\tasync run(userMessage?: string, signal?: AbortSignal): Promise<LLMResponse | null> {\n\t\tif (this._running) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`agentLoop \"${this.name}\": run() called while a previous run() is still pending — await the previous run before starting another, or call abort() first`,\n\t\t\t);\n\t\t}\n\t\tthis._running = true;\n\n\t\tlet offAbort: (() => void) | undefined;\n\t\ttry {\n\t\t\t// Reset per-run state. `lastResponse` MUST be cleared here —\n\t\t\t// without it, `_terminalResult` would read the prior run's\n\t\t\t// cached response during a second `run()` with a pre-aborted\n\t\t\t// signal: `effAbort` drives `status → \"done\"`, `_terminalResult`\n\t\t\t// evaluates `stat=\"done\"` + `resp=<prior respA>` and emits DATA\n\t\t\t// as a fresh post-subscribe signal → `awaitSettled` resolves\n\t\t\t// with the stale response instead of rejecting with AbortError.\n\t\t\t// The C3 `stat=done && resp===undefined → ERROR` guard in\n\t\t\t// `_terminalResult` is only correct once the reset clears the\n\t\t\t// cache.\n\t\t\t//\n\t\t\t// **SENTINEL reset via plain `[[INVALIDATE]]`** (DS-13.5.A,\n\t\t\t// 2026-05-01). Pre-DS-13.5.A this required a paired\n\t\t\t// `[[INVALIDATE], [RESOLVED]]` because INVALIDATE alone left\n\t\t\t// dependents wedged in DIRTY. With INVALIDATE settling the wave\n\t\t\t// (decrementing `_dirtyDepCount` like RESOLVED) and clearing\n\t\t\t// `_cached` + each dependent's `prevData[lastResponse]` slot\n\t\t\t// back to `undefined`, a single emission restores SENTINEL state\n\t\t\t// AND lets dependents fire on the next status transition.\n\t\t\t// `lastResponse` is a `Node<LLMResponse>` with no `initial` —\n\t\t\t// it stays SENTINEL until the first real response; resetting\n\t\t\t// via `emit(null)` would push a `null` DATA placeholder (the\n\t\t\t// F9 trap), which is why INVALIDATE rather than emit is used.\n\t\t\tbatch(() => {\n\t\t\t\tthis.lastResponse.down([[INVALIDATE]]);\n\t\t\t\tthis.turn.emit(0);\n\t\t\t\tthis.aborted.emit(false);\n\t\t\t\tthis.status.emit(\"idle\");\n\t\t\t});\n\t\t\tif (userMessage != null) this.chat.append(\"user\", userMessage);\n\n\t\t\t// Subscribe to `_terminalResult` BEFORE transitioning to\n\t\t\t// \"thinking\" — otherwise a synchronous adapter (mock tests,\n\t\t\t// offline stubs) would drain status → done → DATA on\n\t\t\t// `_terminalResult` before `awaitSettled` had a chance to\n\t\t\t// subscribe, and `skipCurrent: true` would swallow the only\n\t\t\t// DATA this run will produce. `awaitSettled` / `firstWhere`\n\t\t\t// subscribes synchronously during the `async` function's\n\t\t\t// initial execution slice, so calling it before the kick\n\t\t\t// guarantees the subscription is in place when the pipeline\n\t\t\t// starts draining.\n\t\t\t//\n\t\t\t// `skipCurrent: true` still matters: on the second `run()`\n\t\t\t// call `_terminalResult` holds cached DATA from the prior run,\n\t\t\t// and push-on-subscribe would resolve immediately with that\n\t\t\t// stale value without the skip.\n\t\t\tconst resultPromise = awaitSettled(this._terminalResult, { skipCurrent: true });\n\n\t\t\tif (signal != null) {\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis.aborted.emit(true);\n\t\t\t\t} else {\n\t\t\t\t\tconst listener = (): void => this.aborted.emit(true);\n\t\t\t\t\tsignal.addEventListener(\"abort\", listener, { once: true });\n\t\t\t\t\toffAbort = (): void => signal.removeEventListener(\"abort\", listener);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Kick — transition to \"thinking\" fires promptInput → llmResponse.\n\t\t\t// Skip the kick when the signal was already aborted: `effAbort`\n\t\t\t// has driven `status → \"done\"` above, and a trailing\n\t\t\t// `thinking` emit would produce a non-monotonic `idle → done →\n\t\t\t// thinking` sequence in the status-event log for no reactive\n\t\t\t// benefit (promptInput gates on `!latestAborted` anyway).\n\t\t\tif (signal?.aborted !== true) {\n\t\t\t\tthis.status.emit(\"thinking\");\n\t\t\t}\n\n\t\t\treturn await resultPromise;\n\t\t} finally {\n\t\t\toffAbort?.();\n\t\t\tthis._running = false;\n\t\t\tthis._currentAbortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Flip the reactive `aborted` state. Equivalent to setting an external\n\t * `AbortSignal` — the pipeline observes and transitions to `\"done\"`.\n\t */\n\tabort(): void {\n\t\tthis.aborted.emit(true);\n\t}\n\n\toverride destroy(): void {\n\t\ttry {\n\t\t\tthis._disposeRunWiring();\n\t\t} catch {\n\t\t\t/* best-effort: disposing keepalives shouldn't block destroy */\n\t\t}\n\t\tsuper.destroy();\n\t}\n}\n\n/**\n * Read the latest value for dep `i` inside a raw-`node()` fn body.\n *\n * Checks `batchData[i]` first (this-wave DATA from the dep), falls back to\n * `ctx.prevData[i]` (last DATA from prior waves), and finally to `fallback`\n * when the dep has never emitted (SENTINEL). Matches the unwrap semantics\n * `derived`'s sugar applies, so raw nodes can read deps uniformly.\n *\n * @internal\n */\nfunction readLatest<T>(\n\tbatchData: readonly (readonly unknown[] | undefined)[],\n\tprevData: readonly unknown[],\n\tindex: number,\n\tfallback: T,\n): T {\n\tconst batch = batchData[index];\n\tif (batch != null && batch.length > 0) return batch[batch.length - 1] as T;\n\tconst prev = prevData[index];\n\treturn (prev !== undefined ? prev : fallback) as T;\n}\n\n/** @internal Shape of the LLM invocation input — constructed inside `promptInput`. */\ninterface InvokeInput {\n\treadonly messages: readonly ChatMessage[];\n\treadonly tools: readonly ToolDefinition[];\n}\n\nexport function agentLoop(name: string, opts: AgentLoopOptions): AgentLoopGraph {\n\tconst g = new AgentLoopGraph(name, opts);\n\t// Tier 1.5.3 Phase 2.5 (DG1=B): tag the Graph with its constructing\n\t// factory so `describe()` exposes provenance. Opts include non-JSON\n\t// fields (`adapter`, `tools`, `stopWhen`, `onToolCall`,\n\t// `interceptToolCalls`, etc.) so route through `placeholderArgs`\n\t// (DG2=ii).\n\tg.tagFactory(\"agentLoop\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\treturn g;\n}\n","/**\n * Settled/signal helpers.\n *\n * Moved from extra/sources/settled.ts during cleave A2.\n * `keepalive` is substrate — it lives at `@graphrefly/pure-ts`\n * (`packages/pure-ts/src/extra/sources/_keepalive.ts`), not here.\n */\n\n/**\n * Settled / signal helpers — boundary primitives for converting reactive\n * sources into Promise/AbortSignal endpoints.\n *\n * - {@link firstValueFrom} / {@link firstWhere} — Promise of the first\n * matching DATA.\n * - {@link awaitSettled} — composition over `firstWhere` + reactive\n * `timeout` from `extra/resilience` (lazy import to avoid a\n * resilience → sources cycle).\n * - {@link nodeSignal} — `Node<boolean>` → `AbortSignal` bridge.\n * - {@link reactiveCounter} — capped counter exposed as a `Node<number>`.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\ttype Messages,\n\ttype Node,\n\tnode,\n} from \"@graphrefly/pure-ts/core\";\n\n/**\n * Converts the first `DATA` on `source` into a Promise; rejects on `ERROR` or `COMPLETE` without data.\n *\n * **Important:** This subscribes and waits for a **future** emission. Data that\n * has already flowed is gone and will not be seen. Call this *before* the upstream\n * emits, or use `source.cache` / `source.status` for already-cached state.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * @param source - Node to read once.\n * @returns Promise of the first value.\n *\n * @example\n * ```ts\n * import { firstValueFrom, of } from \"@graphrefly/graphrefly-ts\";\n *\n * await firstValueFrom(of(42));\n * ```\n *\n * @category extra\n */\nexport function firstValueFrom<T>(source: Node<T>): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet shouldUnsub = false;\n\t\tlet unsub: (() => void) | undefined;\n\t\tunsub = source.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tresolve(m[1] as T);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(m[1]);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(new Error(\"completed without DATA\"));\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (shouldUnsub) {\n\t\t\tunsub?.();\n\t\t\tunsub = undefined;\n\t\t}\n\t});\n}\n\n/**\n * Wait for the first DATA value from `source` that satisfies `predicate`.\n *\n * Subscribes directly and resolves on the first DATA value where\n * `predicate` returns true. Reactive, no polling. Use in tests and\n * bridging code where you need a single matching value as a Promise.\n *\n * **Important:** This only captures **future** emissions — data that has\n * already flowed through the node is gone. Call this *before* the upstream\n * emits. For already-cached values, use `source.cache` / `source.status`.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * ```ts\n * const val = await firstWhere(strategy.snapshot, snap => snap.size > 0);\n * ```\n *\n * @param source - Upstream node to observe.\n * @param predicate - Returns `true` for the value to resolve on.\n * @param opts - `{ skipCurrent?: boolean }`. When `skipCurrent: true`, any DATA\n * delivered during the synchronous `subscribe()` call (push-on-subscribe §2.2\n * replay of the cached value) is ignored — the promise resolves only on the\n * next future emission. Useful when the caller wants to await the next\n * settlement event after an imperative action (e.g. `run()` minting a new\n * runVersion, where the currently-cached value belongs to the previous run).\n *\n * @category extra\n */\nexport function firstWhere<T>(\n\tsource: Node<T>,\n\tpredicate: (value: T) => boolean,\n\topts?: { skipCurrent?: boolean; kick?: () => void },\n): Promise<T> {\n\t// Lock 3.A (Phase 13.6.B): subscribe synchronously inside the function\n\t// body — NOT inside the Promise executor. Subscribing inside the\n\t// executor would defer the subscription past any synchronous `kick()`\n\t// the caller fires after the call returns, race-losing the very wave\n\t// the caller wants to observe.\n\t//\n\t// To bridge sync-subscribe with the async Promise contract, we record\n\t// any settlement that fires *before* the Promise constructor runs, and\n\t// the executor immediately resolves/rejects with the recorded value.\n\t// Settlements after the executor runs go straight through resolve/reject.\n\ttype Pending =\n\t\t| { kind: \"data\"; value: T }\n\t\t| { kind: \"error\"; err: unknown }\n\t\t| { kind: \"complete\" };\n\tlet pending: Pending | undefined;\n\tlet resolveFn: ((value: T) => void) | undefined;\n\tlet rejectFn: ((err: unknown) => void) | undefined;\n\tlet settled = false;\n\tlet shouldUnsub = false;\n\tlet unsub: (() => void) | undefined;\n\tlet inInitialSyncPhase = opts?.skipCurrent === true;\n\n\t// QA P1: every settler short-circuits when `settled === true` so a\n\t// later settle attempt (e.g. `kick()` throwing AFTER it synchronously\n\t// fired matching DATA, OR a `[DATA matched, ERROR]` wave during\n\t// push-on-subscribe) cannot overwrite an earlier `pending` outcome.\n\t// Without this gate, a kick that races sink-callback settlement could\n\t// reject a Promise the user already has resolved-DATA for.\n\tconst settleData = (v: T): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (resolveFn != null) resolveFn(v);\n\t\telse pending = { kind: \"data\", value: v };\n\t};\n\tconst settleError = (err: unknown): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (rejectFn != null) rejectFn(err);\n\t\telse pending = { kind: \"error\", err };\n\t};\n\tconst settleComplete = (): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tconst err = new Error(\"completed without matching value\");\n\t\tif (rejectFn != null) rejectFn(err);\n\t\telse pending = { kind: \"complete\" };\n\t};\n\tconst detach = (): void => {\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tunsub = undefined;\n\t\t} else shouldUnsub = true;\n\t};\n\n\tconst sink: (msgs: Messages) => void = (msgs) => {\n\t\tif (settled) return;\n\t\tfor (const m of msgs) {\n\t\t\tif (settled) return;\n\t\t\t// During the initial sync phase, swallow only cached DATA\n\t\t\t// (push-on-subscribe §2.2). Terminal ERROR / COMPLETE must\n\t\t\t// still reject the promise — otherwise an already-terminated\n\t\t\t// source synchronously delivering `[[ERROR, ...]]` or\n\t\t\t// `[[COMPLETE]]` during `subscribe()` would hang forever\n\t\t\t// under `skipCurrent: true`.\n\t\t\tif (inInitialSyncPhase && m[0] === DATA) continue;\n\t\t\tif (m[0] === DATA) {\n\t\t\t\tconst v = m[1] as T;\n\t\t\t\tif (predicate(v)) {\n\t\t\t\t\tsettleData(v);\n\t\t\t\t\tdetach();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (m[0] === ERROR) {\n\t\t\t\tsettleError(m[1]);\n\t\t\t\tdetach();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\tsettleComplete();\n\t\t\t\tdetach();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\tunsub = source.subscribe(sink);\n\tinInitialSyncPhase = false;\n\t// Lock 3.A: fire `kick` AFTER subscribe is in place. With sync\n\t// subscribe + sync kick, the resulting wave reaches `sink` before\n\t// control returns — making subscribe-before-kick ordering structurally\n\t// impossible to misuse.\n\tif (opts?.kick != null && !settled) {\n\t\ttry {\n\t\t\topts.kick();\n\t\t} catch (err) {\n\t\t\tsettleError(err);\n\t\t\tdetach();\n\t\t}\n\t}\n\tif (shouldUnsub) {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\t// If a settlement landed synchronously before the executor runs,\n\t\t// flush it through immediately.\n\t\tif (pending != null) {\n\t\t\tif (pending.kind === \"data\") resolve(pending.value);\n\t\t\telse if (pending.kind === \"error\") reject(pending.err);\n\t\t\telse reject(new Error(\"completed without matching value\"));\n\t\t\treturn;\n\t\t}\n\t\tresolveFn = resolve;\n\t\trejectFn = reject;\n\t});\n}\n\n/**\n * Await the first non-nullish DATA value from `source`, with optional\n * timeout. Composition sugar over `firstWhere` + reactive timeout.\n *\n * Designed as the CLI/boundary sink for reactive pipelines that end in a\n * nullable node (e.g. `promptNode` — per COMPOSITION-GUIDE §8, it emits\n * `null` before it settles with a real value). Replaces the common pattern\n * `firstValueFrom(filter(source, v => v != null))` with a deadline.\n *\n * - Rejects with `TimeoutError` (from `extra/resilience`) if no matching\n * value arrives within `timeoutMs`. Omit `timeoutMs` for unbounded wait.\n * - `predicate` defaults to `v => v != null`. Pass a custom predicate to\n * gate on a stronger condition (e.g. `v => typeof v === \"string\"`).\n * - Pass `skipCurrent: true` to ignore the currently-cached value delivered\n * synchronously via push-on-subscribe and resolve only on the *next*\n * matching emission. Useful after an imperative action that should produce\n * a fresh settlement (e.g. `run()` minting a new version — the stale\n * cached value from the previous run must not resolve the new caller).\n *\n * ```ts\n * const brief = await awaitSettled(briefNode, { timeoutMs: 120_000 });\n * // or with a predicate:\n * const rich = await awaitSettled(node, {\n * predicate: (v): v is MyShape => typeof v === \"object\" && v != null && \"key\" in v,\n * timeoutMs: 60_000,\n * });\n * // or after kicking off a fresh run:\n * kickOff();\n * const fresh = await awaitSettled(resultNode, { skipCurrent: true });\n * ```\n *\n * Reactive inside, sync propagation — the one async boundary is the\n * returned `Promise<T>` (spec §5.10: async belongs at sources and\n * boundaries, not in the graph).\n *\n * @param source - Upstream node to observe.\n * @param opts - `{ predicate?, timeoutMs?, skipCurrent? }`.\n * @returns Promise that resolves with the first matching value, or rejects on timeout / ERROR / COMPLETE-without-DATA.\n *\n * @category extra\n */\n// Lazy module-cache for the `withTimeout` resilience operator. The dynamic\n// import keeps `settled` free of an eager edge into the resilience family;\n// first call pays the one-shot import, subsequent calls hit cached refs.\nlet _timeoutOp: typeof import(\"../resilience/timeout.js\").withTimeout | undefined;\nlet _nsPerMs: number | undefined;\n\nexport async function awaitSettled<T>(\n\tsource: Node<T>,\n\topts?: {\n\t\tpredicate?: (value: T) => boolean;\n\t\ttimeoutMs?: number;\n\t\tskipCurrent?: boolean;\n\t\t/**\n\t\t * Lock 3.A (Phase 13.6.B): fired AFTER subscribe is in place but\n\t\t * BEFORE the helper's async boundary is exposed to the caller.\n\t\t * Subscribe-before-kick is structurally enforced — the kick's\n\t\t * synchronous wave reaches `sink` before control returns. Replaces\n\t\t * the prior load-bearing-comment pattern (M.20-load-bearing) with\n\t\t * a misuse-impossible API shape.\n\t\t *\n\t\t * Common pattern:\n\t\t * await awaitSettled(node, {\n\t\t * skipCurrent: true,\n\t\t * kick: () => producer.emit(value),\n\t\t * });\n\t\t *\n\t\t * Omit `kick` for external-trigger cases where the wave is fired\n\t\t * by code outside the helper's caller; subscribe still lands\n\t\t * synchronously inside the helper body so the next external wave\n\t\t * is not lost.\n\t\t */\n\t\tkick?: () => void;\n\t},\n): Promise<NonNullable<T>> {\n\tconst predicate = opts?.predicate ?? ((v: T) => v != null);\n\tconst skipCurrent = opts?.skipCurrent;\n\tconst kick = opts?.kick;\n\tif (opts?.timeoutMs == null || opts.timeoutMs <= 0) {\n\t\treturn (await firstWhere(source, predicate, { skipCurrent, kick })) as NonNullable<T>;\n\t}\n\t// Reactive composition: `timeout()` wraps the source as a Node that\n\t// emits ERROR(TimeoutError) on deadline. `firstWhere` then resolves on\n\t// the first matching DATA or rejects on that ERROR. One async boundary\n\t// (the returned Promise), everything inside is sync reactive.\n\tif (_timeoutOp === undefined) {\n\t\tconst [timeoutMod, backoff] = await Promise.all([\n\t\t\timport(\"../resilience/timeout.js\"),\n\t\t\timport(\"../resilience/backoff.js\"),\n\t\t]);\n\t\t_timeoutOp = timeoutMod.withTimeout;\n\t\t_nsPerMs = backoff.NS_PER_MS;\n\t}\n\tconst guarded = _timeoutOp(source, { ns: opts.timeoutMs * (_nsPerMs as number) }).node;\n\treturn (await firstWhere(guarded, predicate, { skipCurrent, kick })) as NonNullable<T>;\n}\n\n/**\n * Converts a reactive `Node<boolean>` into a browser-standard `AbortSignal`\n * that fires when the node settles on `true`. Useful for threading a reactive\n * \"cancel\" flag into any async boundary that accepts a signal (fetch, LLM SDK\n * calls, child-process APIs, timers).\n *\n * **Contract.**\n * - `signal.abort(reason)` fires exactly once, on the first DATA emission with\n * a truthy value. Subsequent emissions are ignored (AbortSignal is\n * single-shot).\n * - Null / `false` / sentinel values are ignored. Push-on-subscribe will\n * check the currently-cached value on subscribe and abort immediately if\n * it's already `true`.\n * - `reason` defaults to `\"cancelled via nodeSignal\"`; pass `opts.reason` to\n * override (`DOMException`, `Error`, or any value accepted by\n * `AbortController.abort`).\n *\n * **Lifecycle.**\n * - Returns a `{signal, dispose}` bundle. Call `dispose()` when you're done\n * with the signal (e.g. in a `finally` after the async operation completes).\n * `dispose()` unsubscribes from the node and is a no-op once the signal has\n * fired.\n * - **Memory note:** without `dispose()` the subscription keeps the reactive\n * node alive for the lifetime of the process. For bridge calls inside a\n * `switchMap` project fn, the switchMap supersede tears the inner subgraph\n * down, which is usually the right lifetime — but still call `dispose()`\n * from the caller's `finally` for clarity.\n *\n * @example\n * ```ts\n * const aborted = state(false);\n * const { signal, dispose } = nodeSignal(aborted);\n * try {\n * const resp = await adapter.invoke(msgs, { signal });\n * return resp;\n * } finally {\n * dispose();\n * }\n * ```\n *\n * @category extra\n */\nexport function nodeSignal(\n\tsource: Node<boolean>,\n\topts?: { reason?: unknown },\n): { signal: AbortSignal; dispose: () => void } {\n\tconst ctrl = new AbortController();\n\tconst reason = opts?.reason ?? new Error(\"cancelled via nodeSignal\");\n\tlet unsub: (() => void) | undefined;\n\tlet shouldUnsub = false;\n\tconst done = () => {\n\t\tif (unsub) {\n\t\t\tunsub();\n\t\t\tunsub = undefined;\n\t\t} else shouldUnsub = true;\n\t};\n\tunsub = source.subscribe((msgs) => {\n\t\tif (ctrl.signal.aborted) return;\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] === DATA && m[1] === true) {\n\t\t\t\tctrl.abort(reason);\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === ERROR) {\n\t\t\t\t// Treat an ERROR on the abort source as a cancel signal too —\n\t\t\t\t// a broken control channel should fail closed, not leak the\n\t\t\t\t// in-flight call. Use the error as the abort reason.\n\t\t\t\tctrl.abort(m[1]);\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t// Source completed without aborting — no-op. `done()` already\n\t\t\t\t// released the subscription here, so a later `dispose()` call\n\t\t\t\t// from the caller is a no-op (safe / idempotent).\n\t\t\t\tdone();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t});\n\tif (shouldUnsub) {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\treturn {\n\t\tsignal: ctrl.signal,\n\t\tdispose: () => {\n\t\t\tif (unsub) {\n\t\t\t\tunsub();\n\t\t\t\tunsub = undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// reactiveCounter\n// ---------------------------------------------------------------------------\n\n/** Bundle returned by {@link reactiveCounter}. */\nexport type ReactiveCounterBundle = {\n\t/** Reactive node holding the current count. */\n\treadonly node: Node<number>;\n\t/** Increment by 1. Returns `false` if cap would be exceeded. */\n\tincrement(): boolean;\n\t/** Current count (synchronous read). */\n\tget(): number;\n\t/** Whether the counter has reached its cap. */\n\tatCap(): boolean;\n};\n\n/**\n * Reactive counter with a cap — the building block for circuit breakers.\n *\n * Wraps a `state(0)` node with `increment()` that respects a maximum.\n * The `node` is subscribable and composable like any reactive node. When\n * the cap is reached, `increment()` returns `false`.\n *\n * ```ts\n * const retries = reactiveCounter(10);\n * retries.increment(); // true — count is now 1\n * retries.node.subscribe(...); // reactive updates\n * retries.atCap(); // false\n * ```\n *\n * @param cap - Maximum value (inclusive). 0 = no increments allowed.\n * @category extra\n */\nexport function reactiveCounter(cap: number): ReactiveCounterBundle {\n\tconst counter = node([], { initial: 0 });\n\treturn {\n\t\tnode: counter,\n\t\tincrement() {\n\t\t\tconst current = counter.cache ?? 0;\n\t\t\tif (current >= cap) return false;\n\t\t\tcounter.down([[DIRTY], [DATA, current + 1]]);\n\t\t\treturn true;\n\t\t},\n\t\tget() {\n\t\t\treturn counter.cache ?? 0;\n\t\t},\n\t\tatCap() {\n\t\t\treturn (counter.cache ?? 0) >= cap;\n\t\t},\n\t};\n}\n","import { type Node, node, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { keepalive, type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { ChatMessage } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// chatStream\n// ---------------------------------------------------------------------------\n\nexport type ChatStreamOptions = {\n\tgraph?: GraphOptions;\n\tmaxMessages?: number;\n};\n\nexport class ChatStreamGraph extends Graph {\n\tprivate readonly _log: ReactiveLogBundle<ChatMessage>;\n\treadonly messages: Node<readonly ChatMessage[]>;\n\t/**\n\t * Most recently appended message. Stays in the protocol SENTINEL state\n\t * (`cache === undefined`, no DATA emitted) until the first append, then\n\t * tracks the latest entry. Per COMPOSITION-GUIDE §1a, the SENTINEL is\n\t * the canonical \"no value yet\" signal — consumers detect empty via\n\t * `data[i] === undefined` inside reactive fns or `latest.cache === undefined`\n\t * outside. No `T | null` placeholder, no `hasLatest` companion.\n\t */\n\treadonly latest: Node<ChatMessage>;\n\treadonly messageCount: Node<number>;\n\n\tconstructor(name: string, opts: ChatStreamOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._log = reactiveLog<ChatMessage>([], {\n\t\t\tname: \"messages\",\n\t\t\tmaxSize: opts.maxMessages,\n\t\t});\n\t\tthis.messages = this._log.entries;\n\t\tthis.add(this.messages, { name: \"messages\" });\n\n\t\t// SENTINEL on empty (COMPOSITION-GUIDE §1a): return `[]` for\n\t\t// RESOLVED-only on empty stream, `[T]` to emit DATA. `latest.cache`\n\t\t// stays `undefined` until the first append.\n\t\tthis.latest = node<ChatMessage>(\n\t\t\t[this.messages],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst entries = data[0] as readonly ChatMessage[];\n\t\t\t\tif (entries.length === 0) {\n\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactions.emit(entries[entries.length - 1] as ChatMessage);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"latest\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_latest\"),\n\t\t\t},\n\t\t);\n\t\tthis.add(this.latest, { name: \"latest\" });\n\t\tthis.addDisposer(keepalive(this.latest));\n\n\t\tthis.messageCount = node<number>(\n\t\t\t[this.messages],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit((data[0] as readonly ChatMessage[]).length);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"messageCount\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"chat_message_count\"),\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t);\n\t\tthis.add(this.messageCount, { name: \"messageCount\" });\n\t\tthis.addDisposer(keepalive(this.messageCount));\n\t}\n\n\tappend(role: ChatMessage[\"role\"], content: string, extra?: Partial<ChatMessage>): void {\n\t\tthis._log.append({ role, content, ...extra });\n\t}\n\n\tappendToolResult(callId: string, content: string): void {\n\t\tthis._log.append({ role: \"tool\", content, toolCallId: callId });\n\t}\n\n\tclear(): void {\n\t\tthis._log.clear();\n\t}\n\n\tallMessages(): readonly ChatMessage[] {\n\t\treturn this.messages.cache as readonly ChatMessage[];\n\t}\n}\n\nexport function chatStream(name: string, opts?: ChatStreamOptions): ChatStreamGraph {\n\treturn new ChatStreamGraph(name, opts);\n}\n","/**\n * `toolExecution` — reactive per-tool-call executor with retry + rescue.\n *\n * Lifted from the inlined `executeToolReactively` helper inside `agent-loop.ts`\n * so it can be consumed standalone by any caller with a reactive `toolCalls`\n * batch — not just `agentLoop`. The shape is: one input `Node<readonly\n * ToolCall[]>` + a `ToolRegistryGraph` → one output `Node<readonly\n * ToolResult[]>`. Each call maps to a per-call `retrySource(executeReactive)`\n * → optional `rescue` chain that emits the handler result on success, or a\n * JSON-wrapped `{ error }` payload on terminal failure so the LLM can see the\n * error as tool output and decide whether to try again via another tool call.\n *\n * **Cancellation.** `executeReactive` mints a per-call `AbortController` and\n * threads its signal into the handler call. When `switchMap` supersedes the\n * inner (a fresh `toolCalls` batch arrives) or the outer graph tears down,\n * the per-call node unsubscribes and `ac.abort()` fires. Signal-aware\n * handlers (`fetch(url, {signal})`, child-process kill, DB cancel) actually\n * stop in-flight work; handlers that ignore the signal still complete to\n * their original termination, but their result is discarded.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { rescue, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { retry } from \"../../../base/resilience/retry.js\";\nimport type { ToolCall } from \"../adapters/core/types.js\";\nimport type { ToolRegistryGraph } from \"./tool-registry.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single tool execution outcome: `{id, content}` where content is a JSON string. */\nexport interface ToolResult {\n\treadonly id: string;\n\treadonly content: string;\n}\n\nexport type ToolExecutionOptions = {\n\t/**\n\t * Reactive tool-call batch. Each non-empty emission triggers a fresh\n\t * per-call execution fan-out; superseding emissions cancel the prior fan.\n\t */\n\ttoolCalls: Node<readonly ToolCall[]>;\n\t/** Registry that resolves tool name → handler. */\n\ttools: ToolRegistryGraph;\n\t/**\n\t * Retry count per individual tool call. `retrySource({count: N})` retries\n\t * up to N times on error (N retries = N+1 total attempts). Default: 1.\n\t */\n\tretryCount?: number;\n\t/**\n\t * How to surface a terminal error after retries are exhausted.\n\t * - `\"rescue\"` (default): emit `{id, content: JSON.stringify({error})}`\n\t * so the LLM sees the failure as structured tool output and can decide\n\t * how to react. Sibling calls in the same batch continue to their own\n\t * completion; one call's failure does not affect the others.\n\t * - `\"propagate\"`: let the ERROR propagate downstream. **Blast radius:**\n\t * the per-batch `derived` join auto-errors when any per-call node\n\t * terminates with ERROR, so one call's failure discards every sibling's\n\t * DATA (even ones that already settled with a valid ToolResult). Use\n\t * `\"propagate\"` only when a single tool failure should be fatal for the\n\t * whole batch; prefer `\"rescue\"` when you want the LLM to see partial\n\t * results plus per-call error markers.\n\t */\n\tonError?: \"rescue\" | \"propagate\";\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Reactive executor for a batch of LLM tool calls.\n *\n * Each DATA emission on `toolCalls` dispatches a fresh per-call fan-out: for\n * every call in the batch, construct a `retrySource(fromAny(tools.execute(\n * name, args)))` node, optionally `rescue` it into a JSON error shape, and\n * join the results via a `derived` whose first-run gate waits for every call\n * to settle before emitting the batch. Empty batches (`calls.length === 0`)\n * are a caller-side invariant violation (the upstream gate should emit\n * RESOLVED for empty batches, not DATA) and trigger a loud error — callers\n * that want to accept empty batches should upstream-filter them first.\n *\n * Reference-equality + content-equality dedup is applied to the output batch\n * so duplicate re-emissions from a completing retrySource don't propagate.\n *\n * @param opts - `{ toolCalls, tools, retryCount?, onError? }`.\n * @returns `Node<readonly ToolResult[]>` — one ToolResult per input ToolCall.\n */\nexport function toolExecution(opts: ToolExecutionOptions): Node<readonly ToolResult[]> {\n\tconst { toolCalls, tools } = opts;\n\tconst retryCount = opts.retryCount ?? 1;\n\tconst onError = opts.onError ?? \"rescue\";\n\n\tconst batchEquals = (a: readonly ToolResult[], b: readonly ToolResult[]): boolean => {\n\t\tif (a === b) return true;\n\t\tif (a.length !== b.length) return false;\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tconst ai = a[i];\n\t\t\tconst bi = b[i];\n\t\t\tif (ai?.id !== bi?.id) return false;\n\t\t\tif (ai?.content !== bi?.content) return false;\n\t\t}\n\t\treturn true;\n\t};\n\n\treturn switchMap<readonly ToolCall[], readonly ToolResult[]>(toolCalls, (calls) => {\n\t\tif (calls == null || calls.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"toolExecution: received an empty tool-call batch as DATA — callers must upstream-filter empty batches (emit RESOLVED) so switchMap is only dispatched for non-empty batches.\",\n\t\t\t);\n\t\t}\n\t\tconst perCall = calls.map((call) => executeOne(call, tools, retryCount, onError));\n\t\t// `executeOne` returns `Node<ToolResult>` in both \"rescue\" and\n\t\t// \"propagate\" modes (the rescue handler builds a `ToolResult`\n\t\t// shape; the success `derived` builds one directly). The join\n\t\t// just forwards the per-call values — no shape coercion needed.\n\t\treturn node(\n\t\t\tperCall,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit(data as readonly ToolResult[]);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\", name: \"toolExecution::batch\", equals: batchEquals },\n\t\t);\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\n/**\n * Per-call reactive executor. `retrySource` re-invokes the factory on ERROR\n * (each attempt mints a fresh `executeReactive` node, which in turn mints a\n * fresh `AbortController` and handler invocation). `executeReactive` itself\n * handles synchronous handler throws — they surface as `[[ERROR, err]]`\n * inside the producer, so `retrySource`'s reactive ERROR path fires\n * consistently regardless of handler shape. No `Promise.resolve().then(...)`\n * thunk needed — the reactive path is end-to-end.\n *\n * Handlers that return a plain string are surfaced as-is; anything else is\n * `JSON.stringify`'d so LLMs that parse tool results can roundtrip\n * structured data without surprise quoting.\n */\nfunction executeOne(\n\tcall: ToolCall,\n\ttools: ToolRegistryGraph,\n\tretryCount: number,\n\tonError: \"rescue\" | \"propagate\",\n): Node<ToolResult> {\n\tconst attempted: Node<unknown> = retry(() => tools.executeReactive(call.name, call.arguments), {\n\t\tcount: retryCount,\n\t}).node;\n\tconst onSuccess = node<ToolResult>(\n\t\t[attempted],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst val = data[0];\n\t\t\tactions.emit({\n\t\t\t\tid: call.id,\n\t\t\t\tcontent: typeof val === \"string\" ? val : JSON.stringify(val),\n\t\t\t});\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tif (onError === \"propagate\") return onSuccess;\n\treturn rescue(onSuccess, (err) => ({\n\t\tid: call.id,\n\t\tcontent: JSON.stringify({ error: String(err) }),\n\t}));\n}\n","/**\n * Retry — re-attempt a node on terminal failure.\n *\n * Two modes selected by the type of `input`:\n * - **Source mode** (`Node<T>`): resubscribes the same node after each ERROR.\n * Upstream must be `resubscribable: true` or retries are silent no-ops.\n * - **Factory mode** (`() => Node<T>`): builds a fresh node per attempt.\n *\n * Shared with `circuitBreaker` / `rateLimiter`: `NodeOrValue<RetryOptions>`\n * lets callers swap retry config reactively (re-validates on each attempt).\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tDIRTY,\n\tERROR,\n\tfactoryTag,\n\ttype Message,\n\ttype Node,\n\tnode,\n\tRESOLVED,\n\tResettableTimer,\n} from \"@graphrefly/pure-ts/core\";\nimport { coerceDelayNs, isNode, msgVal, type NodeOrValue, operatorOpts } from \"./_internal.js\";\nimport {\n\ttype BackoffPreset,\n\ttype BackoffStrategy,\n\tNS_PER_MS,\n\tresolveBackoffPreset,\n} from \"./backoff.js\";\nimport type { StatusValue } from \"./status.js\";\n\n/**\n * Lifecycle-shaped state companion emitted by {@link retry} (DS-13.5.B,\n * locked 2026-05-01). Tracks the retry state machine's current status,\n * the attempt counter, and the last scheduled delay (null before the\n * first retry).\n *\n * @category extra/resilience\n */\nexport interface RetryState {\n\tstatus: StatusValue;\n\tattempt: number;\n\tlastDelay_ns: number | null;\n}\n\n/**\n * Bundle returned by {@link retry}: the retry-wrapped output node and its\n * lifecycle state companion. Pre-1.0 break vs the prior `Node<T>` return.\n *\n * **Single-subscriber / pipeline-only contract (DS-13.5.B QA, N1, 2026-05-03).**\n * The `retryState` companion is allocated once at factory time and shared\n * across all subscribers to `node`. With one subscriber (the typical use\n * case — wire `node` into your downstream chain, optionally observe\n * `retryState` separately) the companion reflects a coherent timeline.\n * With **two or more subscribers** to `node`, each subscriber re-runs the\n * producer body and writes into the same `retryState`, including\n * `publish(\"pending\")` resets that can clobber an in-flight machine's\n * `running`/`paused` state. Don't fan out `node` to multiple subscribers\n * and rely on `retryState` accuracy unless you use\n * {@link keepalive} / `share`-style consolidation.\n *\n * @category extra/resilience\n */\nexport interface RetryBundle<T> {\n\tnode: Node<T>;\n\tretryState: Node<RetryState>;\n}\n\nexport type RetryOptions = {\n\t/**\n\t * Max retry attempts after each terminal `ERROR` (not counting the first failure).\n\t *\n\t * **Required when `backoff` is set.** Pass `Infinity` to opt in to unbounded retries\n\t * — the explicit value rules out the silent-infinite-budget footgun (a flaky provider\n\t * + exponential backoff + omitted `count` would previously default to ~2.1B retries).\n\t */\n\tcount?: number;\n\t/** Delay between attempts; strategies use **nanoseconds**. */\n\tbackoff?: BackoffStrategy | BackoffPreset;\n\t/**\n\t * Caller-supplied metadata merged into the produced node's `meta` (Tier 5.2\n\t * D8 widening). Use {@link domainMeta} to tag the layer for `describe()`\n\t * grouping. The primitive's `factoryTag(\"retry\", …)` always wins against\n\t * caller keys.\n\t */\n\tmeta?: Record<string, unknown>;\n};\n\n/** Factory-mode-only options. `initial` seeds the outer node's cache before the first attempt. */\nexport type RetryFactoryOptions<T> = RetryOptions & {\n\t/** Initial cache value for the outer node before the factory runs the first time. */\n\tinitial?: T;\n};\n\n/**\n * Resolved retry config shared by source-mode and factory-mode wrappers.\n * Centralises the unbounded-retry footgun guard and strategy resolution.\n */\ntype ResolvedRetryConfig = {\n\tmaxRetries: number;\n\tstrategy: BackoffStrategy | null;\n};\n\nfunction resolveRetryConfig(opts?: RetryOptions): ResolvedRetryConfig {\n\tconst count = opts?.count;\n\tconst backoffOpt = opts?.backoff;\n\n\t// Unbounded-retry footgun fix: if `backoff` is set without explicit `count`,\n\t// throw at construction time. Caller must opt in to `Infinity` for unbounded.\n\tif (backoffOpt !== undefined && count === undefined) {\n\t\tthrow new RangeError(\n\t\t\t\"retry({ backoff }) requires explicit count to prevent unbounded retries; pass { count: <n>, backoff: ... }\",\n\t\t);\n\t}\n\n\tconst maxRetries = count !== undefined ? count : 0;\n\tif (maxRetries < 0) throw new RangeError(\"retry count must be >= 0\");\n\n\tconst strategy: BackoffStrategy | null =\n\t\tbackoffOpt === undefined\n\t\t\t? null\n\t\t\t: typeof backoffOpt === \"string\"\n\t\t\t\t? resolveBackoffPreset(backoffOpt)\n\t\t\t\t: backoffOpt;\n\n\treturn { maxRetries, strategy };\n}\n\nfunction retryFactoryArgs(opts?: RetryOptions): Record<string, unknown> | undefined {\n\tconst args: Record<string, unknown> = {};\n\tif (opts?.count !== undefined) args.count = opts.count;\n\tif (typeof opts?.backoff === \"string\") args.backoff = opts.backoff;\n\treturn Object.keys(args).length > 0 ? args : undefined;\n}\n\n/**\n * Shared retry state machine. Both `_retrySource` and `_retryFactory` thin-wrap this:\n * the only per-mode logic is supplied via `acquireSource` (returns a fresh `Node<T>`\n * per attempt — for source-mode it just returns the captured `Node`; for factory-mode\n * it calls the user factory and forwards synchronous throws into the same retry path).\n *\n * **Reactive cfg (Tier 6.5 3.2.2, 2026-04-29).** `getCfg` is invoked at\n * every decision point (`scheduleRetryOrFinish` count + strategy reads)\n * so option swaps mid-flight take effect at the next attempt boundary\n * per the locked semantic rule: \"next attempt fails immediately if\n * already exhausted under new count; `backoff` swap takes effect at next\n * retry's delay calculation.\"\n */\nfunction _runRetryStateMachine<T>(\n\tgetCfg: () => ResolvedRetryConfig,\n\tacquireSource: () => Node<T>,\n\ta: { emit: (v: T) => void; down: (msgs: Message[]) => void },\n\temitState?: (next: RetryState) => void,\n): () => void {\n\tlet attempt = 0;\n\tlet stopped = false;\n\tlet prevDelay: number | null = null;\n\tlet unsub: (() => void) | undefined;\n\tconst timer = new ResettableTimer();\n\tconst publish = (status: StatusValue): void => {\n\t\temitState?.({ status, attempt, lastDelay_ns: prevDelay });\n\t};\n\tpublish(\"pending\");\n\n\tfunction disconnectUpstream(): void {\n\t\tunsub?.();\n\t\tunsub = undefined;\n\t}\n\n\tfunction scheduleRetryOrFinish(err: unknown): void {\n\t\tif (stopped) return;\n\t\tconst cfg = getCfg();\n\t\tif (attempt >= cfg.maxRetries) {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\tconst raw = cfg.strategy === null ? 0 : cfg.strategy(attempt, err, prevDelay);\n\t\t// null from strategy = \"stop retrying\" (e.g. withMaxAttempts cap reached)\n\t\tif (raw === null || raw === undefined) {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\t// A misbehaving strategy (returns NaN / non-finite / negative) MUST NOT\n\t\t// escape into the upstream drain. Treat it like `strategy === null`\n\t\t// (stop retrying) and emit the original error — the strategy bug is a\n\t\t// separate concern the user can inspect via the emitted error's stack.\n\t\tlet delayNs: number;\n\t\ttry {\n\t\t\tdelayNs = coerceDelayNs(raw);\n\t\t} catch {\n\t\t\tdisconnectUpstream();\n\t\t\tpublish(\"errored\");\n\t\t\ta.down([[ERROR, err]]);\n\t\t\treturn;\n\t\t}\n\t\tprevDelay = delayNs;\n\t\tattempt += 1;\n\t\tdisconnectUpstream();\n\t\tpublish(\"paused\");\n\t\t// `Math.max(1, …)` floor: every backoff schedule floors at 1ms even when\n\t\t// the strategy returns 0ns. Avoids 0-delay re-entrancy on the active\n\t\t// stack frame (which would risk stack overflow on a tight ERROR loop).\n\t\tconst delayMs = delayNs > 0 ? delayNs / NS_PER_MS : 1;\n\t\t// §5.10: setTimeout (not fromTimer) — retry delay needs clearTimeout/setTimeout;\n\t\t// fromTimer creates a new Node per reset, adding lifecycle overhead per retry.\n\t\ttimer.start(delayMs, () => {\n\t\t\tif (stopped) return;\n\t\t\tconnect();\n\t\t});\n\t}\n\n\tfunction connect(): void {\n\t\ttimer.cancel();\n\t\tdisconnectUpstream();\n\t\tlet src: Node<T>;\n\t\ttry {\n\t\t\tsrc = acquireSource();\n\t\t} catch (err) {\n\t\t\tscheduleRetryOrFinish(err);\n\t\t\treturn;\n\t\t}\n\t\tpublish(\"running\");\n\t\tunsub = src.subscribe((msgs) => {\n\t\t\tif (stopped) return;\n\t\t\tfor (const m of msgs) {\n\t\t\t\tconst t = m[0];\n\t\t\t\tif (t === DIRTY) a.down([[DIRTY]]);\n\t\t\t\telse if (t === DATA) {\n\t\t\t\t\tattempt = 0;\n\t\t\t\t\tprevDelay = null;\n\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\tpublish(\"running\");\n\t\t\t\t} else if (t === RESOLVED) a.down([[RESOLVED]]);\n\t\t\t\telse if (t === COMPLETE) {\n\t\t\t\t\t// DF2 (2026-04-29): set `stopped = true` BEFORE\n\t\t\t\t\t// `disconnectUpstream()` so a re-entrant ERROR delivered\n\t\t\t\t\t// in the same wave (after disconnect runs but before the\n\t\t\t\t\t// teardown closure fires `stopped = true`) hits the\n\t\t\t\t\t// `if (stopped) return` guard at line 159 and cannot\n\t\t\t\t\t// schedule a new retry timer.\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tdisconnectUpstream();\n\t\t\t\t\tpublish(\"completed\");\n\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\tscheduleRetryOrFinish(msgVal(m));\n\t\t\t\t\treturn;\n\t\t\t\t} else a.down([m]);\n\t\t\t}\n\t\t});\n\t}\n\n\tconnect();\n\n\treturn () => {\n\t\tconst wasStopped = stopped;\n\t\tstopped = true;\n\t\ttimer.cancel();\n\t\tdisconnectUpstream();\n\t\tif (!wasStopped) publish(\"cancelled\");\n\t};\n}\n\n/**\n * Retry operator — two modes selected by the type of `input`:\n *\n * **Source mode** (`input: Node<T>`): resubscribes to the same node after each terminal\n * `ERROR`. The upstream should use `resubscribable: true` if it must emit again after `ERROR`.\n *\n * **Factory mode** (`input: () => Node<T>`): invokes the factory to build a fresh `Node<T>`\n * on every connect / reconnect. Ideal for producers that capture per-attempt resources\n * (sockets, clients, file handles) that become unusable after an error. Synchronous\n * exceptions thrown by the factory are treated as terminal ERROR and run through the\n * same retry pipeline as inner-node ERROR.\n *\n * @param input - Upstream node or factory that returns a fresh node per attempt.\n * @param opts - `count` caps attempts (**required when `backoff` is set**; pass `Infinity` to opt in to unbounded); `backoff` supplies delay in **nanoseconds** (or a preset name); `initial` seeds the outer node cache (factory mode only).\n * @returns Node that retries on error.\n *\n * @throws {RangeError} when `backoff` is provided without an explicit `count` (unbounded-retry footgun guard) or when `count < 0`.\n *\n * @remarks\n * **Protocol:** Forwards unknown message tuples unchanged; handles `DIRTY`, `DATA`, `RESOLVED`, `COMPLETE`, `ERROR`.\n *\n * **Backoff floor:** every scheduled delay is floored at 1ms via `Math.max(1, delayNs / NS_PER_MS)` even when the strategy returns 0ns. This avoids 0-delay re-entrancy on the active stack frame on a tight ERROR loop. Strategies that return `null`/`undefined` stop retrying immediately and forward the original error.\n *\n * @example\n * ```ts\n * // Source mode — resubscribe the same node:\n * import { ERROR, NS_PER_SEC, producer, retry, constant } from \"@graphrefly/graphrefly-ts\";\n *\n * const src = producer(\n * (a) => { a.down([[ERROR, new Error(\"x\")]]); },\n * { resubscribable: true },\n * );\n * const out = retry(src, { count: 2, backoff: constant(0.25 * NS_PER_SEC) });\n *\n * // Factory mode — fresh node per attempt (e.g. reconnecting WebSocket):\n * import { NS_PER_SEC, exponential, retry, fromWebSocket } from \"@graphrefly/graphrefly-ts\";\n *\n * const connected$ = retry(\n * () => fromWebSocket(new WebSocket(\"wss://example/stream\")),\n * { count: 10, backoff: exponential({ baseNs: 1 * NS_PER_SEC }) },\n * );\n * ```\n *\n * @category extra\n */\nexport function retry<T>(input: Node<T>, opts?: NodeOrValue<RetryOptions>): RetryBundle<T>;\nexport function retry<T>(\n\tinput: () => Node<T>,\n\topts?: NodeOrValue<RetryFactoryOptions<T>>,\n): RetryBundle<T>;\nexport function retry<T>(\n\tinput: Node<T> | (() => Node<T>),\n\topts?: NodeOrValue<RetryOptions | RetryFactoryOptions<T>>,\n): RetryBundle<T> {\n\tconst retryState = node<RetryState>([], {\n\t\tname: \"retryState\",\n\t\tdescribeKind: \"state\",\n\t\tinitial: { status: \"pending\", attempt: 0, lastDelay_ns: null },\n\t\tequals: (a, b) =>\n\t\t\ta === b ||\n\t\t\t(a != null &&\n\t\t\t\tb != null &&\n\t\t\t\ttypeof a === \"object\" &&\n\t\t\t\ttypeof b === \"object\" &&\n\t\t\t\tJSON.stringify(a) === JSON.stringify(b)),\n\t});\n\tconst emit = (s: RetryState): void => {\n\t\tretryState.down([[DIRTY], [DATA, s]]);\n\t};\n\tif (typeof input === \"function\") {\n\t\treturn {\n\t\t\tnode: _retryFactory(input, opts as NodeOrValue<RetryFactoryOptions<T>> | undefined, emit),\n\t\t\tretryState,\n\t\t};\n\t}\n\treturn {\n\t\tnode: _retrySource(input, opts as NodeOrValue<RetryOptions> | undefined, emit),\n\t\tretryState,\n\t};\n}\n\n// DS-13.5.B helper: like `resolveReactiveOption` but shallow-merges each\n// reactive emit over the prior opts and treats empty `{}` as a no-op\n// (per the locked cross-cutting rule). Static-form arg returns the value\n// as-is and never subscribes.\nfunction makeMergedOptsMirror<R extends Record<string, unknown>>(\n\targ: NodeOrValue<R> | undefined,\n): { current: () => R | undefined; unsub: () => void } {\n\tif (arg === undefined) {\n\t\treturn { current: () => undefined, unsub: () => undefined };\n\t}\n\tif (!isNode(arg)) {\n\t\treturn { current: () => arg as R, unsub: () => undefined };\n\t}\n\tconst optsNode = arg as Node<R>;\n\tlet merged: R | undefined = (optsNode.cache as R | undefined) ?? undefined;\n\tconst unsub = optsNode.subscribe((msgs) => {\n\t\tfor (const m of msgs) {\n\t\t\tif (m[0] !== DATA) continue;\n\t\t\tconst next = m[1] as R | undefined;\n\t\t\tif (next == null || typeof next !== \"object\") continue;\n\t\t\tif (Object.keys(next).length === 0) continue; // empty {} no-op\n\t\t\tmerged = { ...(merged ?? ({} as R)), ...next } as R;\n\t\t}\n\t});\n\treturn { current: () => merged, unsub };\n}\n\n// DF6 (2026-04-29): once-per-source dedup for the source-mode-retry warn.\n// Mirrors the `_bumpCursorWarned` pattern in `extra/mutation/index.ts`.\nconst _retrySourceNonResubscribableWarned = new WeakSet<Node<unknown>>();\n\nfunction _retrySource<T>(\n\tsource: Node<T>,\n\topts?: NodeOrValue<RetryOptions>,\n\temitState?: (s: RetryState) => void,\n): Node<T> {\n\t// Source-mode retry re-subscribes to the SAME source node after each\n\t// terminal ERROR. If the upstream was constructed with the default\n\t// `resubscribable: false`, the second subscribe-after-terminal is a\n\t// silent no-op and retries effectively never re-deliver. Surface\n\t// once-per-source so misconfigurations fail loud without log spam.\n\tconst sourceWithFlag = source as unknown as { _resubscribable?: boolean };\n\tif (\n\t\tsourceWithFlag._resubscribable === false &&\n\t\t!_retrySourceNonResubscribableWarned.has(source)\n\t) {\n\t\t_retrySourceNonResubscribableWarned.add(source);\n\t\tconsole.warn(\n\t\t\t\"retry(source, opts): source-mode requires `resubscribable: true` on the upstream \" +\n\t\t\t\t\"node. Retries will be silent no-ops after the first ERROR. Either pass \" +\n\t\t\t\t\"`resubscribable: true` to the source factory, OR use factory-mode retry \" +\n\t\t\t\t\"`retry(() => buildSource(), opts)` so each attempt builds a fresh node.\",\n\t\t);\n\t}\n\tconst staticOpts = isNode(opts) ? undefined : (opts as RetryOptions | undefined);\n\t// Eager validation for static-form opts (preserves construction-time\n\t// \"backoff without count\" RangeError). Reactive-form opts re-validate\n\t// per `getCfg()` call inside the state machine.\n\tif (!isNode(opts)) resolveRetryConfig(staticOpts);\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tconst merged = makeMergedOptsMirror<RetryOptions>(opts);\n\t\t\tconst getCfg = (): ResolvedRetryConfig => resolveRetryConfig(merged.current());\n\t\t\tconst inner = _runRetryStateMachine(getCfg, () => source, a, emitState);\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tinner();\n\t\t\t\t\tmerged.unsub();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: source.cache,\n\t\t\tmeta: {\n\t\t\t\t...(staticOpts?.meta ?? {}),\n\t\t\t\t...factoryTag(\n\t\t\t\t\t\"retry\",\n\t\t\t\t\tisNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t);\n}\n\nfunction _retryFactory<T>(\n\tfactory: () => Node<T>,\n\topts?: NodeOrValue<RetryFactoryOptions<T>>,\n\temitState?: (s: RetryState) => void,\n): Node<T> {\n\tconst staticOpts = isNode(opts) ? undefined : (opts as RetryFactoryOptions<T> | undefined);\n\t// Eager validation for static-form opts (Tier 3.1 footgun preservation).\n\tif (!isNode(opts)) resolveRetryConfig(staticOpts);\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tconst merged = makeMergedOptsMirror<RetryFactoryOptions<T>>(opts);\n\t\t\tconst getCfg = (): ResolvedRetryConfig => resolveRetryConfig(merged.current());\n\t\t\tconst inner = _runRetryStateMachine(getCfg, factory, a, emitState);\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tinner();\n\t\t\t\t\tmerged.unsub();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\t...operatorOpts(),\n\t\t\tinitial: staticOpts?.initial as T | undefined,\n\t\t\tmeta: {\n\t\t\t\t...(staticOpts?.meta ?? {}),\n\t\t\t\t...factoryTag(\n\t\t\t\t\t\"retry\",\n\t\t\t\t\tisNode(opts) ? { reactiveOpts: true } : retryFactoryArgs(staticOpts),\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t);\n}\n","import { ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAsyncIter, fromPromise, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta, isNodeLike } from \"../_internal.js\";\nimport type { ToolDefinition } from \"../adapters/core/types.js\";\n\n// ---------------------------------------------------------------------------\n// toolRegistry\n// ---------------------------------------------------------------------------\n\nexport type ToolRegistryOptions = {\n\tgraph?: GraphOptions;\n};\n\n/**\n * `ToolRegistryGraph` — name-keyed registry of {@link ToolDefinition}s.\n *\n * **Reactive-only execution.** The only execution path is\n * {@link executeReactive}, which returns a `Node<unknown>` for the handler\n * result. Composing factories (`toolExecution`, `agentLoop`) consume it\n * directly inside `retrySource` / `switchMap` chains. There is intentionally\n * no imperative `execute()` Promise method — the registry was originally a\n * dual-boundary class (imperative + reactive) and the imperative path was\n * the only thing in the codebase bridging through `Promise.resolve().then()`\n * to feed `fromAny`. Removing it left every consumer on a single\n * reactive-all-the-way path with real abort propagation.\n *\n * For non-reactive callers (debug scripts, one-shot tests), bridge with\n * `awaitSettled(toolRegistry.executeReactive(name, args))`.\n *\n * **Wave A Unit 6 refactor:** internal storage migrated from `state<Map>`\n * (O(N) Map-copy per mutation) to `ReactiveMapBundle<string, ToolDefinition>`\n * (O(1) mutations + version counter).\n */\nexport class ToolRegistryGraph extends Graph {\n\treadonly definitions: Node<ReadonlyMap<string, ToolDefinition>>;\n\treadonly schemas: Node<readonly ToolDefinition[]>;\n\tprivate readonly _bundle: ReturnType<typeof reactiveMap<string, ToolDefinition>>;\n\n\tconstructor(name: string, opts: ToolRegistryOptions = {}) {\n\t\tsuper(name, opts.graph);\n\n\t\tthis._bundle = reactiveMap<string, ToolDefinition>({\n\t\t\tname: \"definitions\",\n\t\t});\n\t\tthis.definitions = this._bundle.entries;\n\t\tthis.add(this.definitions, { name: \"definitions\" });\n\n\t\tthis.schemas = node<readonly ToolDefinition[]>(\n\t\t\t[this.definitions],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst defs = data[0];\n\t\t\t\tactions.emit([...((defs ?? new Map()) as ReadonlyMap<string, ToolDefinition>).values()]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"schemas\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"tool_schemas\"),\n\t\t\t\tinitial: [],\n\t\t\t},\n\t\t);\n\t\tthis.add(this.schemas, { name: \"schemas\" });\n\t\tthis.addDisposer(keepalive(this.schemas));\n\t}\n\n\tregister(tool: ToolDefinition): void {\n\t\tthis._bundle.set(tool.name, tool);\n\t}\n\n\tunregister(name: string): void {\n\t\tthis._bundle.delete(name);\n\t}\n\n\t/**\n\t * Reactive execution — returns a `Node<unknown>` that emits the handler\n\t * result. The returned node is a `producer` that:\n\t *\n\t * 1. Mints a per-call `AbortController` whose `signal` is threaded into\n\t * the handler call AND into `fromAny` (so a `fromPromise` /\n\t * `fromAsyncIter` inner abandons cleanly when the consumer\n\t * unsubscribes).\n\t * 2. Runs `tool.handler(args, {signal})` inside a try/catch — a\n\t * synchronous throw surfaces as `[[ERROR, err]]` downstream instead\n\t * of escaping the producer.\n\t * 3. Forwards every message from the inner `fromAny` chain to the\n\t * producer's outputs.\n\t * 4. On teardown (subscriber count drops to zero, e.g. `switchMap`\n\t * supersede) calls `ac.abort()` and unsubscribes the inner.\n\t * Signal-aware handlers (e.g. `fetch(url, {signal})`) actually stop.\n\t *\n\t * Each call mints a fresh node tied to a fresh `handler(args, ...)`\n\t * invocation — call `executeReactive` again for repeated invocations.\n\t *\n\t * @throws `Error` synchronously when `name` is not registered (no node is\n\t * constructed — the caller gets a pre-wiring failure rather than a\n\t * silent ERROR wave on an empty graph).\n\t */\n\texecuteReactive(name: string, args: Record<string, unknown>): Node<unknown> {\n\t\tconst tool = this._bundle.get(name);\n\t\tif (!tool) throw new Error(`toolRegistry: unknown tool \"${name}\"`);\n\t\treturn node<unknown>(\n\t\t\t[],\n\t\t\t(_data, actions) => {\n\t\t\t\tconst ac = new AbortController();\n\t\t\t\tlet inner: Node<unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = tool.handler(args, { signal: ac.signal });\n\t\t\t\t\tinner = handlerResultToNode(raw, ac.signal);\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// Synchronous throw from handler → ERROR. Producer cleanup\n\t\t\t\t\t// still aborts the controller for symmetry (no-op if no\n\t\t\t\t\t// signal listeners attached).\n\t\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst unsub = inner.subscribe((batch) => {\n\t\t\t\t\tactions.down(batch as Messages);\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: `executeReactive::${name}`,\n\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\tmeta: aiMeta(\"tool_execute_reactive\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tgetDefinition(name: string): ToolDefinition | undefined {\n\t\t// Pure read via the snapshot cache — avoids the bundle's\n\t\t// `wrapMutation` path (which would run the version-bump check and\n\t\t// any configured retention eviction on every lookup). Safe because\n\t\t// `getDefinition` is a boundary API, not a reactive fn body.\n\t\treturn this._bundle.entries.cache?.get(name);\n\t}\n}\n\nexport function toolRegistry(name: string, opts?: ToolRegistryOptions): ToolRegistryGraph {\n\treturn new ToolRegistryGraph(name, opts);\n}\n\n/**\n * Coerce a tool handler return value into a `Node<unknown>`.\n *\n * Differs from `fromAny` by treating **strings, arrays, plain iterables, and\n * scalar objects as single DATA values** rather than iterating them. A tool\n * handler that returns `\"hello world\"` should surface as one `DATA(\"hello\n * world\")`, not 11 `DATA` events of single characters; an array `[1, 2, 3]`\n * should surface as `DATA([1, 2, 3])`, not three separate emissions.\n *\n * Reactive shapes (Node, Promise, AsyncIterable) are unwrapped as expected.\n *\n * @internal\n */\nfunction handlerResultToNode(raw: unknown, signal: AbortSignal): Node<unknown> {\n\tif (isNodeLike(raw)) {\n\t\treturn raw as Node<unknown>;\n\t}\n\tif (raw != null && typeof (raw as PromiseLike<unknown>).then === \"function\") {\n\t\treturn fromPromise(raw as PromiseLike<unknown>, { signal });\n\t}\n\tif (raw != null && typeof raw === \"object\" && Symbol.asyncIterator in (raw as object)) {\n\t\treturn fromAsyncIter(raw as AsyncIterable<unknown>, { signal });\n\t}\n\t// String, number, boolean, null, undefined, plain object, array,\n\t// sync iterable — treat as a single DATA value via a resolved Promise so\n\t// `fromPromise`'s scalar-DATA-emit + COMPLETE semantics match the\n\t// pre-refactor `tools.execute` behavior (which always wrapped via async).\n\treturn fromPromise(Promise.resolve(raw), { signal });\n}\n","// ---------------------------------------------------------------------------\n// agentMemory — sugar over the memoryWith* composers (Unit 7 B).\n//\n// Thin wiring: distill() builds the core store (when no tiers configured);\n// optional capabilities delegate to the composer Graph subclasses in\n// `memory-composers.ts`. Each composer is a self-contained\n// `MemoryWithXxxGraph` that AgentMemoryGraph mounts on itself (Class B\n// audit, 2026-04-30) — teardown cascades via `Graph.destroy()`.\n//\n// **Phase 12.D (2026-04-30):** Migrated from the `Object.assign(graph, ...)`\n// factory pattern to `class extends Graph` (mirrors the\n// `MemoryWith*Graph` precedent). Required by Phase 13.G `agent(spec)` —\n// `AgentBundle.graph: AgentGraph<TIn, TOut>` consumers want `instanceof`\n// narrowing on agent-memory subgraphs.\n// ---------------------------------------------------------------------------\n\nimport { DATA, type Node, node, placeholderArgs, RESOLVED } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, fromTimer, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype DistillBundle,\n\ttype DistillOptions,\n\tdistill,\n\ttype Extraction,\n} from \"../../base/composition/distill.js\";\nimport type { LLMAdapter } from \"../../utils/ai/adapters/core/types.js\";\nimport {\n\ttype MemoryWithTiersGraph,\n\tmemoryRetrieval,\n\tmemoryWithKG,\n\tmemoryWithTiers,\n\tmemoryWithVectors,\n} from \"../../utils/ai/memory/memory-composers.js\";\nimport type { RetrievalEntry, RetrievalQuery } from \"../../utils/ai/memory/retrieval.js\";\nimport type { MemoryTiersBundle, MemoryTiersOptions } from \"../../utils/ai/memory/tiers.js\";\nimport { llmConsolidator, llmExtractor } from \"../../utils/ai/prompts/prompt-call.js\";\nimport type { KnowledgeGraph, VectorIndexGraph } from \"../../utils/memory/index.js\";\n\nexport type AgentMemoryOptions<TMem = unknown> = {\n\tgraph?: GraphOptions;\n\t/** LLM adapter for extraction and consolidation. */\n\tadapter?: LLMAdapter;\n\t/** System prompt for the extractor LLM. */\n\textractPrompt?: string;\n\t/** Custom extractFn (overrides adapter + extractPrompt). */\n\textractFn?: (raw: unknown, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\t/** System prompt for the consolidation LLM. */\n\tconsolidatePrompt?: string;\n\t/** Custom consolidateFn (overrides adapter + consolidatePrompt). */\n\tconsolidateFn?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\t/** Reactive trigger for consolidation (caller supplies e.g. `fromTimer`). */\n\tconsolidateTrigger?: NodeInput<unknown>;\n\t/** Score function for budget packing (required). */\n\tscore: (mem: TMem, context: unknown) => number;\n\t/** Cost function for budget packing (required). */\n\tcost: (mem: TMem) => number;\n\t/** Token budget for compact view (default 2000). */\n\tbudget?: number;\n\t/** Context node for scoring. */\n\tcontext?: NodeInput<unknown>;\n\t/** Admission filter (default: admit all). */\n\tadmissionFilter?: (candidate: unknown) => boolean;\n\t/** Vector index dimensions (> 0 enables vector index for retrieval). */\n\tvectorDimensions?: number;\n\t/**\n\t * B12: optional accessor for an entry's hierarchical context breadcrumb\n\t * (e.g. `[\"projects\", \"auth\", \"tokens\"]`). When supplied alongside\n\t * `contextWeight > 0`, retrieval applies a score boost for entries whose\n\t * context shares a prefix with the query's `context`. Entries without\n\t * a breadcrumb are scored flatly.\n\t */\n\tcontextOf?: (mem: TMem) => readonly string[] | undefined;\n\t/**\n\t * B12: hierarchical context boost multiplier. Score is scaled by\n\t * `(1 + contextWeight * sharedDepth / queryDepth)` when both the query\n\t * and entry supply a `context`. Default: 0.\n\t */\n\tcontextWeight?: number;\n\n\t// --- In-factory composition (new) ---\n\n\t/** Extract embedding vector from a memory entry (enables vector index). */\n\tembedFn?: (mem: TMem) => readonly number[] | undefined;\n\t/** Enable knowledge graph for entity/relation tracking. */\n\tenableKnowledgeGraph?: boolean;\n\t/** Extract entities and relations from a memory entry. */\n\tentityFn?: (\n\t\tkey: string,\n\t\tmem: TMem,\n\t) =>\n\t\t| {\n\t\t\t\tentities?: Array<{ id: string; value: unknown }>;\n\t\t\t\trelations?: Array<{ from: string; to: string; relation: string; weight?: number }>;\n\t\t }\n\t\t| undefined;\n\n\t/** 3-tier storage configuration. Omit to use single-tier (existing behavior). */\n\ttiers?: MemoryTiersOptions<TMem>;\n\n\t/** Retrieval pipeline configuration. Requires vector index or knowledge graph. */\n\tretrieval?: {\n\t\t/** Max candidates from vector search (default 20). */\n\t\ttopK?: number;\n\t\t/** KG expansion depth in hops (default 1). */\n\t\tgraphDepth?: number;\n\t};\n\n\t/** Periodic reflection/consolidation configuration. */\n\treflection?: {\n\t\t/** Interval in ms between consolidation runs (default 300_000 = 5 min). */\n\t\tinterval?: number;\n\t\t/** Enable/disable periodic reflection (default true when consolidateFn is available). */\n\t\tenabled?: boolean;\n\t};\n};\n\n/**\n * Pre-wired agentic memory graph. Sugar over `distill` plus the\n * `memoryWithVectors` / `memoryWithKG` / `memoryWithTiers` / `memoryRetrieval`\n * composers. Power users who want a subset of capabilities can call those\n * composers directly; this class bundles them into one ergonomic Graph subclass.\n *\n * Mounts:\n * - `tiers/*` — present when `opts.tiers` configured (replaces the\n * default distill bundle).\n * - `vectors/*` — present when `opts.vectorDimensions > 0 && opts.embedFn`.\n * - `knowledge/*` — present when `opts.enableKnowledgeGraph`.\n * - `retrieval/*` — present when vectors or kg configured.\n *\n * When `opts.tiers` is omitted, `store` / `compact` / `size` are added as\n * top-level nodes on this graph (visible in `describe()` / `explain()`).\n */\nexport class AgentMemoryGraph<TMem = unknown> extends Graph {\n\treadonly distillBundle: DistillBundle<TMem>;\n\treadonly compact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\treadonly size: Node<number>;\n\t/** Vector index bundle (null if not enabled). */\n\treadonly vectors: VectorIndexGraph<TMem> | null;\n\t/** Knowledge graph (null if not enabled). */\n\treadonly kg: KnowledgeGraph<unknown, string> | null;\n\t/** Memory tiers bundle (null if not configured). */\n\treadonly memoryTiers: MemoryTiersBundle<TMem> | null;\n\t/**\n\t * The mounted `MemoryWithTiersGraph` subgraph (null when `opts.tiers` was\n\t * omitted). Surfaces the inner graph for `describe()` / `explain()` walks\n\t * and for callers that need direct access to the tiers subgraph (e.g.\n\t * to register additional disposers or attach storage). Companion to\n\t * `memoryTiers`, which carries only the bundle's reactive surface (B5e).\n\t */\n\treadonly tiers: MemoryWithTiersGraph<unknown, TMem> | null;\n\t/**\n\t * Reactive consumer API. Given a reactive `RetrievalQuery | null` source,\n\t * returns a `Node` emitting the packed retrieval results. Composable with\n\t * graph topology — subscribe it, chain it into `promptNode`, or switchMap\n\t * over a user-input node.\n\t *\n\t * Each call mounts its own per-input subgraph at\n\t * `retrieval::retrieve_${id}` (via `MemoryRetrievalGraph`); concurrent\n\t * calls don't share state mirrors. One-shot consumers wrap with\n\t * `awaitSettled(retrieveReactive(query))`.\n\t *\n\t * Null when no retrieval pipeline is configured.\n\t *\n\t * **QA F-9 (2026-04-30):** the prior `retrieval` / `retrievalTrace`\n\t * shared state-node mirrors have been dropped. Use `retrieveReactive`\n\t * for per-call reactive results; one-shot trace consumers should\n\t * subscribe to the projection's upstream `result` derived directly\n\t * via `view.target.resolve(\"retrieval::retrieve_${id}::result\")`.\n\t */\n\treadonly retrieveReactive:\n\t\t| ((queryInput: NodeInput<RetrievalQuery | null>) => Node<ReadonlyArray<RetrievalEntry<TMem>>>)\n\t\t| null;\n\n\tconstructor(name: string, source: NodeInput<unknown>, opts: AgentMemoryOptions<TMem>) {\n\t\tsuper(name, opts.graph);\n\n\t\t// --- Extract function resolution ---\n\t\t// /qa A3 (2026-04-30): validate BEFORE tagFactory so an invalid-opts\n\t\t// throw doesn't leave a tagged-but-empty Graph instance behind.\n\t\tlet rawExtractFn: (\n\t\t\traw: unknown,\n\t\t\texisting: ReadonlyMap<string, TMem>,\n\t\t) => NodeInput<Extraction<TMem>>;\n\t\tif (opts.extractFn) {\n\t\t\trawExtractFn = opts.extractFn;\n\t\t} else if (opts.adapter && opts.extractPrompt) {\n\t\t\trawExtractFn = llmExtractor<unknown, TMem>(opts.extractPrompt, { adapter: opts.adapter });\n\t\t} else {\n\t\t\tthrow new Error(\"agentMemory: provide either extractFn or adapter + extractPrompt\");\n\t\t}\n\n\t\t// Tier 1.5.3 Phase 2.5 (DG1=B): tag the Graph with its constructing\n\t\t// factory so `describe()` exposes provenance. Opts contain non-JSON\n\t\t// fields (`adapter`, `extractFn`, `embedFn`, `score`, `cost`, `evict`,\n\t\t// callbacks, etc.) so route through `placeholderArgs` (DG2=ii).\n\t\tthis.tagFactory(\"agentMemory\", placeholderArgs(opts as unknown as Record<string, unknown>));\n\t\t// Tier 1.5.4 — distill's `extractFn` is now reactive (called once with\n\t\t// nodes). Adapt the AgentMemoryOptions callback shape via switchMap +\n\t\t// closure-mirror for `existing` (COMPOSITION-GUIDE §40 recipe).\n\t\t// QA F9: register the closure-mirror's unsub with the host graph so\n\t\t// `graph.destroy()` reclaims it — was previously leaked.\n\t\t//\n\t\t// **Phase 16 attempt (2026-04-29) reverted.** Tried `withLatestFrom(\n\t\t// rawNode, existingNode) + switchMap`; this is the WRONG migration per\n\t\t// COMPOSITION-GUIDE §28. **Phase 10.5 (same-day partial-flag flip on\n\t\t// `withLatestFrom`)** removes the initial-pair drop, but this site stays\n\t\t// on closure-mirror form pending Phase 11 restricted signatures. See\n\t\t// `archive/docs/SESSION-graph-narrow-waist.md` § \"Status of existing\n\t\t// modifications\" + § \"Phase 10.5\".\n\t\tconst extractFn = (\n\t\t\trawNode: Node<unknown>,\n\t\t\texistingNode: Node<ReadonlyMap<string, TMem>>,\n\t\t): NodeInput<Extraction<TMem>> => {\n\t\t\tlet latestExisting: ReadonlyMap<string, TMem> =\n\t\t\t\t(existingNode.cache as ReadonlyMap<string, TMem> | undefined) ?? new Map();\n\t\t\tconst unsubExisting = existingNode.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] === DATA) latestExisting = m[1] as ReadonlyMap<string, TMem>;\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.addDisposer(unsubExisting);\n\t\t\treturn switchMap(rawNode, (raw) => {\n\t\t\t\tif (raw == null) return { upsert: [] };\n\t\t\t\treturn rawExtractFn(raw, latestExisting);\n\t\t\t});\n\t\t};\n\n\t\t// --- Admission filter ---\n\t\tlet filteredSource = source;\n\t\tif (opts.admissionFilter) {\n\t\t\tconst srcNode = fromAny(source);\n\t\t\tconst filter = opts.admissionFilter;\n\t\t\tfilteredSource = node(\n\t\t\t\t[srcNode],\n\t\t\t\t(batchData, actions, ctx) => {\n\t\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t\t);\n\t\t\t\t\tconst raw = data[0];\n\t\t\t\t\tif (filter(raw)) {\n\t\t\t\t\t\tactions.emit(raw);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// EC1 (qa 2026-04-30): emitting `undefined` would violate spec §5.12\n\t\t\t\t\t\t// (undefined is the protocol SENTINEL — TopicGraph.publish even\n\t\t\t\t\t\t// throws on it). Downstream `batch.at(-1) : ctx.prevData[i]`\n\t\t\t\t\t\t// would also resolve `undefined` back to the prior accepted\n\t\t\t\t\t\t// value, leaking past-the-filter. Emit a tier-3 RESOLVED so the\n\t\t\t\t\t\t// wave settles cleanly without surfacing a stale DATA.\n\t\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ name: \"admissionFilter\", describeKind: \"derived\" },\n\t\t\t);\n\t\t}\n\n\t\t// --- Consolidation ---\n\t\tlet consolidateFn:\n\t\t\t| ((entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>)\n\t\t\t| undefined;\n\t\tif (opts.consolidateFn) {\n\t\t\tconsolidateFn = opts.consolidateFn;\n\t\t} else if (opts.adapter && opts.consolidatePrompt) {\n\t\t\tconsolidateFn = llmConsolidator<TMem>(opts.consolidatePrompt, { adapter: opts.adapter });\n\t\t}\n\n\t\t// --- Reflection: default consolidateTrigger from fromTimer ---\n\t\tlet consolidateTrigger = opts.consolidateTrigger;\n\t\tif (!consolidateTrigger && consolidateFn && opts.reflection?.enabled !== false) {\n\t\t\tconst interval = opts.reflection?.interval ?? 300_000;\n\t\t\tconsolidateTrigger = fromTimer(interval, { period: interval });\n\t\t}\n\n\t\t// --- Build distill bundle (the core) ---\n\t\t// Tier 4.1 B (2026-04-29): when tiers are configured, `memoryWithTiers`\n\t\t// is the construction site for the distill bundle so it can wire\n\t\t// `reactiveMap.retention` into the store at construction (no §7 cycle).\n\t\t// When tiers are NOT configured, agentMemory calls `distill` directly.\n\t\tconst distillOpts: DistillOptions<TMem> = {\n\t\t\tscore: opts.score,\n\t\t\tcost: opts.cost,\n\t\t\tbudget: opts.budget ?? 2000,\n\t\t\tcontext: opts.context,\n\t\t\tconsolidate: consolidateFn,\n\t\t\tconsolidateTrigger,\n\t\t};\n\n\t\tlet distillBundle: DistillBundle<TMem>;\n\t\tlet memoryTiersBundle: MemoryTiersBundle<TMem> | null = null;\n\t\tlet tiersSubgraph: MemoryWithTiersGraph<unknown, TMem> | null = null;\n\t\tif (opts.tiers) {\n\t\t\tconst tiersGraph = memoryWithTiers<unknown, TMem>({\n\t\t\t\t// User customization first; canonical agent-memory-level overrides\n\t\t\t\t// last so they always win even if `MemoryTiersOptions` later adds\n\t\t\t\t// any of the same keys.\n\t\t\t\t...opts.tiers,\n\t\t\t\tname: \"tiers\",\n\t\t\t\tsource: filteredSource,\n\t\t\t\textractFn,\n\t\t\t\tscore: opts.score,\n\t\t\t\tcost: opts.cost,\n\t\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : { budget: 2000 }),\n\t\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\t\t...(consolidateFn !== undefined ? { consolidate: consolidateFn } : {}),\n\t\t\t\t...(consolidateTrigger !== undefined ? { consolidateTrigger } : {}),\n\t\t\t});\n\t\t\tthis.mount(\"tiers\", tiersGraph);\n\t\t\tdistillBundle = tiersGraph.store;\n\t\t\tmemoryTiersBundle = tiersGraph.tiers;\n\t\t\ttiersSubgraph = tiersGraph;\n\t\t} else {\n\t\t\tdistillBundle = distill<unknown, TMem>(filteredSource, extractFn, distillOpts);\n\t\t\tthis.add(distillBundle.store.entries, { name: \"store\" });\n\t\t\tthis.add(distillBundle.compact, { name: \"compact\" });\n\t\t\tthis.add(distillBundle.size, { name: \"size\" });\n\t\t}\n\n\t\t// --- Vector index (composer) ---\n\t\tlet vectors: VectorIndexGraph<TMem> | null = null;\n\t\tif (opts.vectorDimensions && opts.vectorDimensions > 0 && opts.embedFn) {\n\t\t\tconst vectorsGraph = memoryWithVectors<TMem>({\n\t\t\t\tname: \"vectors\",\n\t\t\t\tstore: distillBundle,\n\t\t\t\tdimension: opts.vectorDimensions,\n\t\t\t\tembedFn: opts.embedFn,\n\t\t\t});\n\t\t\tthis.mount(\"vectors\", vectorsGraph);\n\t\t\tvectors = vectorsGraph.vectors;\n\t\t}\n\n\t\t// --- Knowledge graph (composer) ---\n\t\tlet kg: KnowledgeGraph<unknown, string> | null = null;\n\t\tif (opts.enableKnowledgeGraph) {\n\t\t\tconst kgGraph = memoryWithKG<TMem>({\n\t\t\t\tname: \"knowledge\",\n\t\t\t\tstore: distillBundle,\n\t\t\t\tkgName: `${name}-kg`,\n\t\t\t\tmountPath: \"knowledge-kg\",\n\t\t\t\t...(opts.entityFn !== undefined ? { entityFn: opts.entityFn } : {}),\n\t\t\t});\n\t\t\tthis.mount(\"knowledge\", kgGraph);\n\t\t\tkg = kgGraph.kg;\n\t\t}\n\n\t\t// --- Retrieval pipeline (composer) ---\n\t\tlet retrieveReactive:\n\t\t\t| ((\n\t\t\t\t\tqueryInput: NodeInput<RetrievalQuery | null>,\n\t\t\t ) => Node<ReadonlyArray<RetrievalEntry<TMem>>>)\n\t\t\t| null = null;\n\n\t\tif (vectors || kg) {\n\t\t\tconst retrievalGraph = memoryRetrieval<TMem>({\n\t\t\t\tname: \"retrieval\",\n\t\t\t\tstore: distillBundle,\n\t\t\t\tvectors,\n\t\t\t\tkg,\n\t\t\t\tscore: opts.score,\n\t\t\t\tcost: opts.cost,\n\t\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : {}),\n\t\t\t\t...(opts.retrieval?.topK !== undefined ? { topK: opts.retrieval.topK } : {}),\n\t\t\t\t...(opts.retrieval?.graphDepth !== undefined\n\t\t\t\t\t? { graphDepth: opts.retrieval.graphDepth }\n\t\t\t\t\t: {}),\n\t\t\t\t...(opts.contextOf !== undefined ? { contextOf: opts.contextOf } : {}),\n\t\t\t\t...(opts.contextWeight !== undefined ? { contextWeight: opts.contextWeight } : {}),\n\t\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\t});\n\t\t\tthis.mount(\"retrieval\", retrievalGraph);\n\t\t\tretrieveReactive = retrievalGraph.retrieveReactive.bind(retrievalGraph);\n\t\t}\n\n\t\tthis.distillBundle = distillBundle;\n\t\tthis.compact = distillBundle.compact;\n\t\tthis.size = distillBundle.size;\n\t\tthis.vectors = vectors;\n\t\tthis.kg = kg;\n\t\tthis.memoryTiers = memoryTiersBundle;\n\t\tthis.tiers = tiersSubgraph;\n\t\tthis.retrieveReactive = retrieveReactive;\n\t}\n}\n\n/**\n * Pre-wired agentic memory graph. Sugar over `distill` plus the\n * `memoryWithVectors` / `memoryWithKG` / `memoryWithTiers` / `memoryRetrieval`\n * composers. Power users who want a subset of capabilities can call those\n * composers directly; this factory bundles them into one ergonomic call.\n *\n * Returns an {@link AgentMemoryGraph} subclass instance — `instanceof\n * AgentMemoryGraph` narrows in callers (e.g. Phase 13.G `agent(spec)`).\n */\nexport function agentMemory<TMem = unknown>(\n\tname: string,\n\tsource: NodeInput<unknown>,\n\topts: AgentMemoryOptions<TMem>,\n): AgentMemoryGraph<TMem> {\n\treturn new AgentMemoryGraph<TMem>(name, source, opts);\n}\n","/**\n * Budget-constrained reactive memory composition (roadmap §3.2b).\n *\n * Moved to base/composition/distill.ts during cleave A2.\n */\n\nimport { batch, factoryTag, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport {\n\tfromAny,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapOptions,\n\treactiveMap,\n\tswitchMap,\n\twithLatestFrom,\n} from \"@graphrefly/pure-ts/extra\";\nimport { forEach } from \"../sources/async.js\";\n\nfunction isNodeLike<T>(value: unknown): value is Node<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"cache\" in (value as Node<T>) &&\n\t\ttypeof (value as Node<T>).subscribe === \"function\"\n\t);\n}\n\nexport type Extraction<TMem> = {\n\tupsert: Array<{ key: string; value: TMem }>;\n\tremove?: string[];\n};\n\nexport type DistillOptions<TMem> = {\n\tscore: (mem: TMem, context: unknown) => number;\n\tcost: (mem: TMem) => number;\n\tbudget?: number;\n\tevict?: (key: string, mem: TMem) => boolean | Node<boolean>;\n\tconsolidate?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\tconsolidateTrigger?: NodeInput<unknown>;\n\tcontext?: NodeInput<unknown>;\n\tmapOptions?: ReactiveMapOptions<string, TMem>;\n};\n\nexport type DistillBundle<TMem> = {\n\tstore: ReactiveMapBundle<string, TMem>;\n\tcompact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\tsize: Node<number>;\n};\n\nfunction keepalive(node: Node): void {\n\tnode.subscribe(() => undefined);\n}\n\n/**\n * Defensive snapshot → ReadonlyMap coercion (D2 /qa lock, Tier 9.1).\n *\n * `ReactiveMapBundle.entries` always emits a real `Map` on the live emit\n * path. The non-Map case happens on snapshot **restore**: the default\n * `JsonGraphCodec` serializes a `Map` to `null`/`{}`/`[]` depending on the\n * codec configuration, and `Graph.restore` writes that decoded value back\n * to the cache. A naive `(snapshot as ReadonlyMap) ?? new Map()` would\n * pass a plain object through and then `.entries()` / `.size` access would\n * silently yield wrong results (or throw). The runtime `instanceof Map`\n * check below restores the safety net the previous `mapFromSnapshot` helper\n * provided before its initial deletion in Tier 10.1.\n */\nfunction mapFromSnapshot<TMem>(snapshot: unknown): ReadonlyMap<string, TMem> {\n\tif (snapshot instanceof Map) return snapshot as ReadonlyMap<string, TMem>;\n\treturn new Map<string, TMem>();\n}\n\nfunction applyExtraction<TMem>(\n\tstore: ReactiveMapBundle<string, TMem>,\n\textraction: Extraction<TMem>,\n): void {\n\tif (!Array.isArray(extraction.upsert)) {\n\t\tthrow new TypeError(\"distill extraction requires upsert: Array<{ key, value }>\");\n\t}\n\tbatch(() => {\n\t\tfor (const { key, value } of extraction.upsert) {\n\t\t\tstore.set(key, value);\n\t\t}\n\t\tfor (const key of extraction.remove ?? []) {\n\t\t\tstore.delete(key);\n\t\t}\n\t});\n}\n\n/**\n * Budget-constrained reactive memory composition.\n *\n * **Tier 1.5.4 (Session A.5 lock, 2026-04-27):** `extractFn` receives the\n * source and existing-store as `Node`s. Distill calls `extractFn` ONCE at\n * wiring time and consumes the returned stream of extractions. The user\n * controls reactive composition — wrap with `switchMap` for cancel-on-new-input,\n * `mergeMap` for parallel, `derived` for sync transforms. See COMPOSITION-GUIDE\n * §40 for the recipe.\n */\nexport function distill<TRaw, TMem>(\n\tsource: NodeInput<TRaw>,\n\textractFn: (\n\t\traw: Node<TRaw>,\n\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t) => NodeInput<Extraction<TMem>>,\n\topts: DistillOptions<TMem>,\n): DistillBundle<TMem> {\n\tconst sourceNode = fromAny(source);\n\tconst store = reactiveMap<string, TMem>(opts.mapOptions ?? {});\n\tconst budget = opts.budget ?? 2000;\n\tconst hasContext = opts.context !== undefined && opts.context !== null;\n\tconst contextNode = hasContext ? fromAny(opts.context) : node<unknown>([], { initial: null });\n\n\t// `latestStore` (formerly a §28 closure-mirror) is no longer needed —\n\t// Phase 10.5 (`withLatestFrom` flipped to `partial: false`) fixed the\n\t// W1 initial-pair drop. `consolidate` now uses\n\t// `withLatestFrom(trigger, store.entries)` below to pair each trigger\n\t// with the latest store snapshot via a real reactive edge (visible in\n\t// `describe()`). The `mapFromSnapshot` transform runs inside the\n\t// switchMap fn body.\n\n\t// Tier 1.5.4: one-shot wire. User's `extractFn` returns the reactive\n\t// extraction stream — distill just `forEach`s and applies. No internal\n\t// switchMap; user picks the cancellation / queueing semantics.\n\tconst extractionStream = fromAny(\n\t\textractFn(sourceNode, store.entries as Node<ReadonlyMap<string, TMem>>),\n\t);\n\tforEach(extractionStream, (extraction) => {\n\t\tapplyExtraction(store, extraction);\n\t});\n\n\tif (opts.evict) {\n\t\t// Track active verdict-node subscriptions so we can react to Node<boolean> changes.\n\t\tconst verdictUnsubs = new Map<string, () => void>();\n\n\t\tconst evictionKeys = node<string[]>(\n\t\t\t[store.entries],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\t\tconst out: string[] = [];\n\t\t\t\tconst entries = mapFromSnapshot<TMem>(snapshot);\n\t\t\t\t// Clean up verdict subscriptions for removed keys.\n\t\t\t\tfor (const key of verdictUnsubs.keys()) {\n\t\t\t\t\tif (!entries.has(key)) {\n\t\t\t\t\t\tverdictUnsubs.get(key)!();\n\t\t\t\t\t\tverdictUnsubs.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, mem] of entries) {\n\t\t\t\t\tconst verdict = opts.evict!(key, mem);\n\t\t\t\t\tif (isNodeLike<boolean>(verdict)) {\n\t\t\t\t\t\t// Subscribe if not already — push-on-subscribe fires with\n\t\t\t\t\t\t// the verdict's current value on first subscribe, so an\n\t\t\t\t\t\t// already-true verdict deletes via the callback without\n\t\t\t\t\t\t// needing a `verdict.cache` read (closes P3 audit #3).\n\t\t\t\t\t\t// Future transitions to `true` flow through the same path.\n\t\t\t\t\t\tif (!verdictUnsubs.has(key)) {\n\t\t\t\t\t\t\tconst unsub = forEach(verdict, (val) => {\n\t\t\t\t\t\t\t\tif (val === true && store.has(key)) {\n\t\t\t\t\t\t\t\t\tstore.delete(key);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tverdictUnsubs.set(key, unsub);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof verdict === \"boolean\") {\n\t\t\t\t\t\tif (verdict) out.push(key);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthrow new TypeError(\"distill evict() must return boolean or Node<boolean>\");\n\t\t\t\t}\n\t\t\t\tactions.emit(out);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\" },\n\t\t);\n\t\tforEach(evictionKeys, (keys) => {\n\t\t\tfor (const key of keys) store.delete(key);\n\t\t});\n\t}\n\n\tconst hasConsolidateTrigger =\n\t\topts.consolidateTrigger !== undefined && opts.consolidateTrigger !== null;\n\tif (opts.consolidate && hasConsolidateTrigger) {\n\t\tconst consolidateTriggerNode = fromAny(opts.consolidateTrigger);\n\t\tconst consolidatePaired = withLatestFrom(\n\t\t\tconsolidateTriggerNode,\n\t\t\tstore.entries as Node<unknown>,\n\t\t);\n\t\tconst consolidationStream = switchMap(consolidatePaired, ([, entries]) =>\n\t\t\topts.consolidate!(mapFromSnapshot<TMem>(entries)),\n\t\t);\n\t\tforEach(consolidationStream, (extraction) => {\n\t\t\tapplyExtraction(store, extraction);\n\t\t});\n\t}\n\n\tconst compact = node<Array<{ key: string; value: TMem; score: number }>>(\n\t\t[store.entries, contextNode],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0];\n\t\t\tconst context = data[1];\n\t\t\tconst map = mapFromSnapshot<TMem>(snapshot);\n\t\t\tconst entries = [...map.entries()].map(([key, value]) => ({\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t\tscore: opts.score(value, context),\n\t\t\t\tcost: opts.cost(value),\n\t\t\t}));\n\t\t\tentries.sort((a, b) => b.score - a.score);\n\n\t\t\tconst packed: Array<{ key: string; value: TMem; score: number }> = [];\n\t\t\tlet remaining = budget;\n\t\t\tfor (const item of entries) {\n\t\t\t\tif (item.cost <= remaining) {\n\t\t\t\t\tpacked.push({ key: item.key, value: item.value, score: item.score });\n\t\t\t\t\tremaining -= item.cost;\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(packed);\n\t\t},\n\t\t{ describeKind: \"derived\", meta: { ...factoryTag(\"distill\", { budget }) } },\n\t);\n\n\tconst size = node<number>(\n\t\t[store.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst batch0 = batchData[0];\n\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\tactions.emit(mapFromSnapshot<TMem>(snapshot).size);\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tkeepalive(compact);\n\tkeepalive(size);\n\n\treturn { store, compact, size };\n}\n","/**\n * Async sources, sinks, and multicast — presentation layer.\n *\n * `fromPromise`, `fromAsyncIter`, `fromAny` are substrate primitives; they are\n * re-exported here from `@graphrefly/pure-ts` for ergonomic single-import use.\n * This file owns the presentation-only async utilities: `defer`, `forEach`,\n * `toArray`, `share`, `replay`, `cached`, `shareReplay`.\n *\n * `singleFromAny` and `singleNodeFromAny` (keyed singleflight) live in\n * `base/composition/single-from-any.ts`.\n */\n\nimport {\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\tRESOLVED,\n\tSTART,\n} from \"@graphrefly/pure-ts/core\";\nimport { type AsyncSourceOpts, type NodeInput, sourceOpts } from \"@graphrefly/pure-ts/extra\";\n\n/** Options for presentation-layer async operators: NodeOptions without `describeKind`. */\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n// Import fromAny from substrate — used internally by defer. The three async\n// substrate sources (fromAny, fromAsyncIter, fromPromise) are already\n// re-exported from @graphrefly/pure-ts; do NOT re-export here to avoid\n// duplicate-export conflicts at the root barrel level.\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\n\n/**\n * Lazily constructs a {@link Node} from a thunk that runs at **activation\n * time** (first subscriber after a teardown to zero sinks), not factory time.\n *\n * **Resubscribable by default.** Diverges from `fromPromise` / `fromIter` /\n * `fromAsyncIter` (which are single-shot — second subscriber sees the cached\n * terminal value). `defer`'s contract matches RxJS `defer`: every fresh\n * activation cycle re-runs the thunk. To opt out and get one-shot semantics,\n * pass `{ resubscribable: false }`.\n *\n * **Sharing across overlapping subscribers.** The thunk only re-runs on a\n * fresh activation cycle (zero → one sink). Overlapping subscribers share\n * the single activation; the thunk does NOT re-run for each subscriber. If\n * the thunk returns an existing `Node`, that Node is shared across activations\n * — `defer` will subscribe to it on each activation but does not isolate state\n * across subscribers. For per-subscriber isolation, the thunk must construct\n * a fresh source (`state(...)`, `fromPromise(fetch(...))`, etc.) on each call.\n *\n * **Use cases:**\n * - Lazy upstream construction (avoid eager evaluation of expensive factories\n * at module load — the thunk runs only when something subscribes).\n * - Per-activation resource construction (open a connection / file handle on\n * subscribe, when paired with full teardown between sessions).\n * - Bridging non-Node inputs (Promise, AsyncIterable, Iterable, scalar) into\n * the graph behind a lazy boundary.\n *\n * The thunk's return value is bridged via {@link fromAny}. Errors thrown by\n * the thunk surface as a single `[[ERROR, err]]` on the output (with `err`\n * coerced to a non-`undefined` value to satisfy spec §1.3 — bare `throw` and\n * `throw undefined` are wrapped in a `defer: thunk threw undefined` Error).\n *\n * Upstream messages are forwarded transparently (DIRTY / DATA / RESOLVED /\n * COMPLETE / ERROR / INVALIDATE / PAUSE / RESUME / TEARDOWN), preserving\n * batch boundaries. The producer's own `START` handshake is delivered to\n * subscribers automatically; the upstream's `START` is filtered.\n *\n * @param thunk - Called on each activation; returns the upstream input.\n * @param opts - Forwarded to `fromAny` (e.g. `signal` for async inputs).\n * `signal` is only consumed by `fromAny` for async input shapes (Promise,\n * AsyncIterable); it does NOT abort a Node-input or scalar-input defer.\n * @returns `Node<T>` — lazy upstream-on-activation.\n *\n * @example\n * ```ts\n * import { defer } from \"@graphrefly/graphrefly-ts\";\n *\n * // Lazy fetch — runs on the first activation, NOT at factory time.\n * // Each fresh activation cycle (after teardown) re-runs the thunk →\n * // a new fetch. Overlapping subscribers share the single activation.\n * const live = defer(() => fetch(\"/api/feed\").then((r) => r.json()));\n * ```\n *\n * @category extra\n */\nexport function defer<T>(thunk: () => NodeInput<T>, opts?: AsyncSourceOpts): Node<T> {\n\t// A4: strip `signal` before forwarding to NodeOptions — sibling sources\n\t// (fromTimer / fromPromise / fromAsyncIter) destructure first; signal\n\t// continues to flow into fromAny(input, opts) for async input shapes.\n\tconst { signal: _sig, ...nodeOpts } = (opts ?? {}) as AsyncSourceOpts;\n\tconst sOpts = sourceOpts<T>(nodeOpts);\n\tconst merged = sOpts.resubscribable === undefined ? { ...sOpts, resubscribable: true } : sOpts;\n\treturn node<T>((_data, a) => {\n\t\tlet unsub: (() => void) | undefined;\n\t\tlet stopped = false;\n\t\ttry {\n\t\t\tconst input = thunk();\n\t\t\t// `iter: true` preserves defer's RxJS-aligned per-element\n\t\t\t// streaming for sync iterable thunk returns (post DS-13.5\n\t\t\t// fromAny default flip; defer's documented contract is\n\t\t\t// \"forwards iterable values\" per-element).\n\t\t\tconst src = fromAny(input, { ...opts, iter: true });\n\t\t\tunsub = src.subscribe((msgs) => {\n\t\t\t\tif (stopped) return;\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tconst t = m[0];\n\t\t\t\t\tif (t === START) continue; // producer's own START is delivered separately\n\t\t\t\t\tif (t === DATA) {\n\t\t\t\t\t\ta.emit(m[1] as T);\n\t\t\t\t\t} else if (t === COMPLETE) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\tbreak; // A2: don't forward post-terminal messages in the same batch\n\t\t\t\t\t} else if (t === ERROR) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\ta.down([[ERROR, m[1]]]);\n\t\t\t\t\t\tbreak; // A2\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Forward DIRTY / RESOLVED / INVALIDATE / PAUSE / RESUME /\n\t\t\t\t\t\t// TEARDOWN, plus any unknown types (spec §1.3.6 forward-compat).\n\t\t\t\t\t\ta.down([m]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// A5: spec §1.3 — ERROR payload must not be undefined. Wrap a\n\t\t\t// `throw` or `throw undefined` so dispatch doesn't reject the emit.\n\t\t\tconst safe = err === undefined ? new Error(\"defer: thunk threw undefined\") : err;\n\t\t\ta.down([[ERROR, safe]]);\n\t\t}\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tstopped = true;\n\t\t\t\tunsub?.();\n\t\t\t},\n\t\t};\n\t}, merged);\n}\n\n/**\n * Subscribes immediately and runs `fn` for each upstream `DATA`; returns unsubscribe.\n *\n * @param source - Upstream node.\n * @param fn - Side effect per value.\n * @param opts - Effect node options.\n * @returns Unsubscribe function (idempotent).\n *\n * @example\n * ```ts\n * import { forEach, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const u = forEach(state(1), (v) => console.log(v));\n * u();\n * ```\n *\n * @category extra\n */\nexport function forEach<T>(source: Node<T>, fn: (value: T) => void, opts?: ExtraOpts): () => void {\n\tconst inner = node(\n\t\t[source as Node],\n\t\t(data, _actions) => {\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) fn(v as T);\n\t\t\t}\n\t\t},\n\t\t{ describeKind: \"effect\", ...opts } as NodeOptions,\n\t);\n\treturn inner.subscribe(() => {});\n}\n\n/**\n * Buffers every `DATA`; on upstream `COMPLETE` emits one `DATA` with the full array then `COMPLETE`.\n *\n * @param source - Upstream node.\n * @param opts - Optional node options (derived describe kind).\n * @returns `Node<T[]>` — single array emission before completion.\n *\n * @example\n * ```ts\n * import { of, toArray } from \"@graphrefly/graphrefly-ts\";\n *\n * toArray(of(1, 2, 3));\n * ```\n *\n * @category extra\n */\nexport function toArray<T>(source: Node<T>, opts?: ExtraOpts): Node<T[]> {\n\t// Lock 6.D (Phase 13.6.B): clear the accumulator buffer on\n\t// deactivation so a resubscribable toArray restarts with an empty\n\t// array on the next cycle — pre-flip this came for free via\n\t// `_deactivate`'s store wipe.\n\tlet cleanup: { onDeactivation: () => void } | undefined;\n\treturn node<T[]>(\n\t\t[source as Node],\n\t\t(data, actions, ctx) => {\n\t\t\tif (cleanup === undefined) {\n\t\t\t\tconst store = ctx.store;\n\t\t\t\tcleanup = {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\tdelete store.buf;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!ctx.store.buf) ctx.store.buf = [];\n\t\t\tconst buf = ctx.store.buf as T[];\n\t\t\t// Accumulate DATA first — must happen before the COMPLETE check so\n\t\t\t// that a same-wave DATA+COMPLETE batch (e.g. fromTimer one-shot,\n\t\t\t// fromIter last item) is included in the emitted array.\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) buf.push(v as T);\n\t\t\t}\n\t\t\t// COMPLETE: emit accumulated array then complete.\n\t\t\t// ERROR: autoError propagates; do NOT emit the partial buffer.\n\t\t\tif (ctx.terminalDeps[0] === true) {\n\t\t\t\tactions.emit([...buf]);\n\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\treturn cleanup;\n\t\t\t}\n\t\t\t// RESOLVED wave: propagate RESOLVED. Covers first-wave case; after first\n\t\t\t// call the pre-fn skip handles this automatically.\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t}\n\t\t\treturn cleanup;\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\t...opts,\n\t\t\t// Operator-required flags spread AFTER user `opts` so a caller\n\t\t\t// cannot accidentally override them (QA F2 spread-order fix,\n\t\t\t// DS-2.7.A `/qa` 2026-05-20 — matches the\n\t\t\t// `reduce`/`scan`/`take`/`last` substrate pattern). Spec §2.7\n\t\t\t// R2.7.1 (DS-2.7.A): Reduce-class shape — fn must fire on\n\t\t\t// upstream COMPLETE to emit the accumulated array (or `[]` for an\n\t\t\t// empty source) followed by its own `[[COMPLETE]]`. Required\n\t\t\t// because `completeWhenDepsComplete: false` means auto-COMPLETE\n\t\t\t// is OFF; without the opt-in `toArray(empty())` never completes.\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\tterminalAsRealInput: true,\n\t\t} as NodeOptions<T[]>,\n\t);\n}\n\n/**\n * Multicasts upstream: one subscription to `source` while this wrapper has subscribers (via {@link producer}).\n *\n * @param source - Upstream node to share.\n * @param opts - Producer options; `initial` seeds from `source.cache` when set by factory.\n * @returns `Node<T>` — hot ref-counted bridge.\n *\n * @example\n * ```ts\n * import { share, state } from \"@graphrefly/graphrefly-ts\";\n *\n * share(state(0));\n * ```\n *\n * @category extra\n */\nexport function share<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn node<T>(\n\t\t(_data, a) => ({\n\t\t\tonDeactivation: source.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache },\n\t);\n}\n\n/**\n * Like {@link share} with a bounded replay buffer: new subscribers receive the last `bufferSize`\n * `DATA` payloads (as separate batches) before live updates.\n *\n * @param source - Upstream node.\n * @param bufferSize - Maximum past values to replay (≥ 1).\n * @param opts - Producer options.\n * @returns `Node<T>` — multicast with replay on subscribe.\n *\n * @example\n * ```ts\n * import { replay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * replay(state(0), 3);\n * ```\n *\n * @category extra\n */\nexport function replay<T>(source: Node<T>, bufferSize: number, opts?: ExtraOpts): Node<T> {\n\tif (bufferSize < 1) throw new RangeError(\"replay expects bufferSize >= 1\");\n\t// Spec §2.5 / Lock 6.G: the built-in `replayBuffer` NodeOption retains the\n\t// last-N outgoing DATA and `defaultOnSubscribe` delivers them to a late\n\t// subscriber INSTEAD of the cache-DATA push — so there is no double-deliver\n\t// of the most-recent value. Supersedes the old `wrapSubscribeHook` +\n\t// manual-buffer pattern (which flushed the buffer AND then push-on-\n\t// subscribed the cache, double-delivering the last value).\n\treturn node<T>(\n\t\t(_data, a) => ({\n\t\t\tonDeactivation: source.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache, replayBuffer: bufferSize },\n\t);\n}\n\n/**\n * {@link replay} with `bufferSize === 1` — replays the latest `DATA` to new subscribers.\n *\n * @param source - Upstream node.\n * @param opts - Producer options.\n * @returns `Node<T>` — share + last-value replay.\n *\n * @example\n * ```ts\n * import { cached, state } from \"@graphrefly/graphrefly-ts\";\n *\n * cached(state(0));\n * ```\n *\n * @category extra\n */\nexport function cached<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn replay(source, 1, opts);\n}\n\n// ——————————————————————————————————————————————————————————————\n// RxJS-compatible aliases\n// ——————————————————————————————————————————————————————————————\n\n/**\n * RxJS-named alias for {@link replay} — multicast with a replay buffer of size `bufferSize`.\n *\n * @param source - Upstream node.\n * @param bufferSize - Replay depth (≥ 1).\n * @param opts - Producer options.\n * @returns Same behavior as `replay`.\n *\n * @example\n * ```ts\n * import { shareReplay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * shareReplay(state(0), 5);\n * ```\n *\n * @category extra\n */\nexport const shareReplay = replay;\n","// ---------------------------------------------------------------------------\n// memory composers — Unit 7 C-factoring (2026-04-23 doc decision).\n//\n// Each composer attaches one capability (vectors, KG, tiers, retrieval) to a\n// `DistillBundle`. `agentMemory` continues to ship as the ergonomic sugar\n// over the full pipeline; power users who want a subset call these factories\n// directly.\n//\n// Class B audit (2026-04-30): the composers were migrated from\n// bundle-returning factories to **Graph subclasses** so they participate in\n// `describe()` / `destroy()` like every other Phase 4+ Graph (mirrors\n// `AuditTrailGraph`, `PolicyGateGraph`, `CqrsGraph`). The factory functions\n// remain as ergonomic constructors (`memoryWithVectors(opts) → MemoryWithVectorsGraph`).\n//\n// Tier 4.1 B + 4.3 B (2026-04-29): `memoryWithTiers` is the construction site\n// for the distill bundle when tiers are configured (`reactiveMap.retention`\n// wired at construction eliminates the §7 feedback cycle the prior\n// `tierClassifier` effect carried). `permanentKeys` and `entryCreatedAtNs`\n// are reactive maps mounted on the graph (not closure state) so\n// `describe()`/`explain()` can walk to the inputs that fed an archival\n// decision.\n// ---------------------------------------------------------------------------\n\nimport { batch, DATA, monotonicNs, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport type { StorageHandle } from \"@graphrefly/pure-ts/extra\";\nimport {\n\tfromAny,\n\tkeepalive,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapRetention,\n\treactiveMap,\n} from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype DistillBundle,\n\ttype DistillOptions,\n\tdistill,\n\ttype Extraction,\n} from \"../../../base/composition/distill.js\";\nimport { decay } from \"../../../base/utils/decay.js\";\nimport {\n\tcollection,\n\tcosineSimilarity,\n\ttype KnowledgeEdge,\n\ttype KnowledgeGraph,\n\tknowledgeGraph,\n\ttype VectorIndexGraph,\n\ttype VectorRecord,\n\ttype VectorSearchResult,\n\tvectorIndex,\n} from \"../../memory/index.js\";\nimport { aiMeta } from \"../_internal.js\";\nimport type { RetrievalEntry, RetrievalQuery, RetrievalTrace } from \"./retrieval.js\";\nimport {\n\tDEFAULT_DECAY_RATE,\n\ttype MemoryTier,\n\ttype MemoryTiersBundle,\n\ttype MemoryTiersOptions,\n} from \"./tiers.js\";\n\n// Tier 4.7 (Wave AM Unit 5 carry): the pre-rebuild defensive `extractStoreMap`\n// helper (runtime `instanceof Map` check before casting) was deleted in favor\n// of a typed `as` cast at each callsite. The upstream `ReactiveMapBundle`\n// always emits a real Map on the live emit path; non-Map snapshots only\n// surface on `Graph.restore` from a codec that round-tripped Map → JSON →\n// plain object (handled in `extra/composite.ts:mapFromSnapshot` for distill\n// internals). Empty map is the canonical \"no entries yet\" value —\n// `node([], { initial: undefined })` would stall a derived/effect's first-run gate.\n//\n// qa F3 (deferred): the typed cast lies if upstream contract ever breaks\n// (e.g. `entries` emits a non-Map non-undefined value). Failure mode is a\n// TypeError at iteration instead of a silent empty-map fallback —\n// deliberate trade-off, surfacing real upstream-contract violations beats\n// hiding them. Upstream-narrowing follow-up filed in `docs/optimizations.md`\n// under \"Tier 4.7 follow-up — narrow `ReactiveMapBundle.entries` callback typing\".\n\n// ---------------------------------------------------------------------------\n// memoryWithVectors\n// ---------------------------------------------------------------------------\n\nexport interface MemoryWithVectorsOptions<TMem> {\n\t/** Optional Graph identity — passed through to the underlying `Graph` ctor. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-vectors\"`. */\n\tname?: string;\n\t/** The substrate distill store to index. */\n\tstore: DistillBundle<TMem>;\n\t/** Embedding dimension. Must match the `embedFn` output length. */\n\tdimension: number;\n\t/** Extract an embedding vector for a memory entry. */\n\tembedFn: (mem: TMem) => readonly number[] | undefined;\n}\n\n/**\n * Graph subclass that attaches a vector index to a `DistillBundle`. The inner\n * `VectorIndexGraph` is mounted at `\"vectorIndex\"`; an internal effect\n * subscribes to the substrate store and re-indexes on every change.\n *\n * Mirrors `AuditTrailGraph` / `PolicyGateGraph` shape — fully self-contained,\n * teardown via the Graph's `destroy()` cascade.\n */\nexport class MemoryWithVectorsGraph<TMem> extends Graph {\n\treadonly vectors: VectorIndexGraph<TMem>;\n\n\tconstructor(opts: MemoryWithVectorsOptions<TMem>) {\n\t\tsuper(opts.name ?? \"memory-vectors\", opts.graph);\n\t\tthis.vectors = vectorIndex<TMem>({ dimension: opts.dimension });\n\t\tthis.mount(\"vectorIndex\", this.vectors);\n\n\t\tconst embedFn = opts.embedFn;\n\t\tconst vectorsRef = this.vectors;\n\n\t\t// Indexer effect — subscribes to the substrate's store entries, upserts\n\t\t// vectors. Pure side-effect; restricted `effect` fn (no emit/down).\n\t\t// Cross-graph dep on `opts.store.store.entries` is fine — the substrate\n\t\t// is the upstream wired in by the parent factory.\n\t\tconst indexer = node(\n\t\t\t[opts.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t\tconst vec = embedFn(mem);\n\t\t\t\t\tif (vec) vectorsRef.upsert(key, vec, mem);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"indexer\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(indexer, { name: \"indexer\" });\n\t\tthis.addDisposer(keepalive(indexer));\n\t}\n}\n\n/**\n * Attach a vector index to a `DistillBundle`. Indexes every entry in the\n * store as it changes. Returns the `MemoryWithVectorsGraph` whose `vectors`\n * field exposes the underlying `VectorIndexGraph`.\n *\n * Teardown is handled by `Graph.destroy()` — typically inherited via\n * mounting the result on a parent graph (see `agentMemory`).\n */\nexport function memoryWithVectors<TMem>(\n\topts: MemoryWithVectorsOptions<TMem>,\n): MemoryWithVectorsGraph<TMem> {\n\treturn new MemoryWithVectorsGraph<TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryWithKG\n// ---------------------------------------------------------------------------\n\nexport interface MemoryWithKGOptions<TMem> {\n\t/** Optional Graph identity. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-kg\"`. */\n\tname?: string;\n\t/** The substrate distill store to index. */\n\tstore: DistillBundle<TMem>;\n\t/** Inner KnowledgeGraph name. Default: `${name}-kg`. */\n\tkgName?: string;\n\t/**\n\t * Mount path within this Graph for the KnowledgeGraph. Default:\n\t * `\"knowledge-kg\"` (B5c — symmetric with the outer `knowledge` mount so\n\t * describe paths render `knowledge::knowledge-kg::*`).\n\t */\n\tmountPath?: string;\n\t/**\n\t * Extract entities + relations for a memory entry. Omit to mount an empty\n\t * KG without an indexer effect — caller upserts entities / relations\n\t * directly on the `kg` field.\n\t */\n\tentityFn?: (\n\t\tkey: string,\n\t\tmem: TMem,\n\t) =>\n\t\t| {\n\t\t\t\tentities?: Array<{ id: string; value: unknown }>;\n\t\t\t\trelations?: Array<{ from: string; to: string; relation: string; weight?: number }>;\n\t\t }\n\t\t| undefined;\n}\n\n/**\n * Graph subclass that attaches a knowledge graph alongside a `DistillBundle`.\n * Mounts the inner `KnowledgeGraph` at `mountPath` (default `\"knowledge-kg\"`); when\n * `entityFn` is provided, an indexer effect populates entities/relations on\n * every store change.\n */\nexport class MemoryWithKGGraph<TMem> extends Graph {\n\treadonly kg: KnowledgeGraph<unknown, string>;\n\n\tconstructor(opts: MemoryWithKGOptions<TMem>) {\n\t\tconst name = opts.name ?? \"memory-kg\";\n\t\tsuper(name, opts.graph);\n\t\tconst kgName = opts.kgName ?? `${name}-kg`;\n\t\tconst mountPath = opts.mountPath ?? \"knowledge-kg\";\n\t\tthis.kg = knowledgeGraph<unknown, string>(kgName);\n\t\tthis.mount(mountPath, this.kg);\n\n\t\tif (!opts.entityFn) return;\n\t\tconst entityFn = opts.entityFn;\n\t\tconst kgRef = this.kg;\n\t\tconst indexer = node(\n\t\t\t[opts.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of storeMap) {\n\t\t\t\t\tconst extracted = entityFn(key, mem);\n\t\t\t\t\tif (!extracted) continue;\n\t\t\t\t\tfor (const ent of extracted.entities ?? []) {\n\t\t\t\t\t\tkgRef.upsertEntity(ent.id, ent.value);\n\t\t\t\t\t}\n\t\t\t\t\tfor (const rel of extracted.relations ?? []) {\n\t\t\t\t\t\tkgRef.link(rel.from, rel.to, rel.relation, rel.weight);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"indexer\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(indexer, { name: \"indexer\" });\n\t\tthis.addDisposer(keepalive(indexer));\n\t}\n}\n\n/**\n * Attach a knowledge graph alongside a `DistillBundle`. Returns the\n * `MemoryWithKGGraph` whose `kg` field exposes the inner `KnowledgeGraph`.\n */\nexport function memoryWithKG<TMem>(opts: MemoryWithKGOptions<TMem>): MemoryWithKGGraph<TMem> {\n\treturn new MemoryWithKGGraph<TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryWithTiers\n// ---------------------------------------------------------------------------\n\n/**\n * Full options for {@link memoryWithTiers} (Tier 4.1 B + 4.3 B refactor,\n * 2026-04-29). Combines tier-policy options with the distill-side options\n * needed to construct the underlying store — `memoryWithTiers` is the\n * **construction site** for the distill bundle so it can wire\n * `reactiveMap.retention` into the store at construction (eliminating the\n * §7 feedback cycle the previous `tierClassifier` effect carried).\n */\nexport type MemoryWithTiersOptions<TRaw, TMem> = MemoryTiersOptions<TMem> &\n\tOmit<DistillOptions<TMem>, \"mapOptions\" | \"score\" | \"context\"> & {\n\t\t/** Optional Graph identity. */\n\t\tgraph?: GraphOptions;\n\t\t/** Subgraph name. Default: `\"memory-tiers\"`. */\n\t\tname?: string;\n\t\t/** Raw source feeding distill. */\n\t\tsource: NodeInput<TRaw>;\n\t\t/** Reactive extraction wiring (same shape as `distill`). */\n\t\textractFn: (\n\t\t\traw: Node<TRaw>,\n\t\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t\t) => NodeInput<Extraction<TMem>>;\n\t\t/** Score function — same signature as `agentMemory.score`. */\n\t\tscore: (mem: TMem, context: unknown) => number;\n\t\t/** Optional reactive context node (passed to `score`). */\n\t\tcontext?: NodeInput<unknown>;\n\t};\n\n/**\n * Graph subclass attaching 3-tier storage (active / archived / permanent) to\n * a fresh distill store, wiring `reactiveMap.retention` at construction so\n * archival happens synchronously inside the substrate's mutation pipeline\n * (no §7 feedback cycle). Promotes `permanentKeys` and `entryCreatedAtNs` to\n * reactive maps registered on this graph (Tier 4.3 B — Unit 7 Q3) so\n * `describe()` / `explain()` can walk to \"why was X archived?\".\n *\n * Public-face fields:\n * - `store` — the distill bundle (construction site, exposed for downstream\n * composers).\n * - `tiers` — tier classification + permanent promotion handles.\n * - `compact`, `size` — alias for `store.compact` / `store.size` (registered\n * under their canonical names so `describe()` keys match `agentMemory`'s\n * pre-migration layout).\n */\nexport class MemoryWithTiersGraph<TRaw, TMem> extends Graph {\n\treadonly store: DistillBundle<TMem>;\n\treadonly tiers: MemoryTiersBundle<TMem>;\n\treadonly compact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\treadonly size: Node<number>;\n\treadonly permanent: ReturnType<typeof collection<TMem>>;\n\treadonly permanentKeys: ReactiveMapBundle<string, true>;\n\treadonly entryCreatedAtNs: ReactiveMapBundle<string, number>;\n\n\tconstructor(opts: MemoryWithTiersOptions<TRaw, TMem>) {\n\t\tsuper(opts.name ?? \"memory-tiers\", opts.graph);\n\n\t\tconst decayRate = opts.decayRate ?? DEFAULT_DECAY_RATE;\n\t\tconst maxActive = opts.maxActive ?? 1000;\n\t\tconst archiveThreshold = opts.archiveThreshold ?? 0.1;\n\t\tconst permanentFilter = opts.permanentFilter ?? (() => false);\n\n\t\t// Tier 2.3 fold: `lightCollection` was merged into\n\t\t// `collection({ranked: false})`. The unified factory returns a Graph (not\n\t\t// a detached bundle), so it's mounted as a subgraph for `describe()`.\n\t\tthis.permanent = collection<TMem>(\"permanent\", { ranked: false });\n\t\tthis.mount(\"permanent\", this.permanent);\n\n\t\t// 4.3 B (Unit 7 Q3, 2026-04-29): closure-state promotion. `permanentKeys`\n\t\t// and `entryCreatedAtNs` are reactive maps registered on this graph so\n\t\t// `describe()` can walk to them and `explain()` can trace the inputs\n\t\t// that fed an archival decision.\n\t\tthis.permanentKeys = reactiveMap<string, true>({ name: \"permanentKeys\" });\n\t\tthis.add(this.permanentKeys.entries, { name: \"permanentKeys\" });\n\t\tthis.entryCreatedAtNs = reactiveMap<string, number>({ name: \"entryCreatedAtNs\" });\n\t\tthis.add(this.entryCreatedAtNs.entries, { name: \"entryCreatedAtNs\" });\n\n\t\t// Closure-mirror for ctx (§28 factory-time seed). `score(mem, ctx)` runs\n\t\t// inside `retention.score` which is invoked synchronously from store\n\t\t// mutations — no reactive dep on contextNode there. The mirror keeps\n\t\t// `latestCtx` current via subscribe.\n\t\t//\n\t\t// Topology visibility: the local-default branch registers the context\n\t\t// state node so it appears in `describe()`. The user-supplied-Node\n\t\t// branch deliberately leaves the node unregistered — `fromAny` returns\n\t\t// the caller's owned Node, which is owned by their graph; mounting it\n\t\t// here would corrupt cross-graph ownership.\n\t\tlet contextNode: Node<unknown>;\n\t\tif (opts.context) {\n\t\t\tcontextNode = fromAny(opts.context);\n\t\t} else {\n\t\t\tcontextNode = node<unknown>([], { initial: null });\n\t\t\tthis.add(contextNode, { name: \"context\" });\n\t\t}\n\t\tlet latestCtx: unknown = contextNode.cache;\n\t\tconst ctxUnsub = contextNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) if (m[0] === DATA) latestCtx = m[1];\n\t\t});\n\t\tthis.addDisposer(ctxUnsub);\n\n\t\tconst permanentKeysRef = this.permanentKeys;\n\t\tconst entryCreatedAtNsRef = this.entryCreatedAtNs;\n\t\tconst score = opts.score;\n\n\t\t// Build retention. `score` runs synchronously inside store mutations.\n\t\t// Permanent matches return Infinity to bypass eviction.\n\t\t//\n\t\t// DS-13.5.F (2026-05-01): `score` is read-only against\n\t\t// `entryCreatedAtNs` — the first-write side-effect was extracted into\n\t\t// the `entryCreatedAtNs/sync` effect below. Race window for the very\n\t\t// first call on a new key is mitigated by the `?? nowNs` fallback\n\t\t// (yields ageSeconds = 0, i.e. fresh-decay), and the sync effect\n\t\t// populates the map after the wave settles so subsequent score calls\n\t\t// see the persisted timestamp.\n\t\tconst retention: ReactiveMapRetention<string, TMem> = {\n\t\t\tscore: (key, value) => {\n\t\t\t\tif (permanentFilter(key, value)) return Number.POSITIVE_INFINITY;\n\t\t\t\tif (permanentKeysRef.has(key)) return Number.POSITIVE_INFINITY;\n\t\t\t\tconst nowNs = monotonicNs();\n\t\t\t\tconst createdNs = entryCreatedAtNsRef.get(key) ?? nowNs;\n\t\t\t\tconst ageSeconds = Number(nowNs - createdNs) / 1e9;\n\t\t\t\treturn decay(score(value, latestCtx), ageSeconds, decayRate);\n\t\t\t},\n\t\t\tarchiveThreshold,\n\t\t\tmaxSize: maxActive,\n\t\t};\n\n\t\t// Construct distill with retention wired into mapOptions.\n\t\tthis.store = distill<TRaw, TMem>(opts.source, opts.extractFn, {\n\t\t\tscore: opts.score,\n\t\t\tcost: opts.cost,\n\t\t\t...(opts.budget !== undefined ? { budget: opts.budget } : {}),\n\t\t\t...(opts.evict !== undefined ? { evict: opts.evict } : {}),\n\t\t\t...(opts.consolidate !== undefined ? { consolidate: opts.consolidate } : {}),\n\t\t\t...(opts.consolidateTrigger !== undefined\n\t\t\t\t? { consolidateTrigger: opts.consolidateTrigger }\n\t\t\t\t: {}),\n\t\t\t...(opts.context !== undefined ? { context: opts.context } : {}),\n\t\t\tmapOptions: { retention },\n\t\t});\n\n\t\t// Register the distill bundle's exposed nodes under their canonical\n\t\t// names so consumers (and `describe()`) see the same shape as the\n\t\t// pre-migration top-level surface on `agentMemory`.\n\t\tthis.add(this.store.store.entries, { name: \"store\" });\n\t\tthis.compact = this.store.compact;\n\t\tthis.add(this.compact, { name: \"compact\" });\n\t\tthis.size = this.store.size;\n\t\tthis.add(this.size, { name: \"size\" });\n\n\t\tconst storeRef = this.store;\n\t\tconst tierOf = (key: string): MemoryTier => {\n\t\t\tif (permanentKeysRef.has(key)) return \"permanent\";\n\t\t\tconst m =\n\t\t\t\t(storeRef.store.entries.cache as ReadonlyMap<string, TMem> | undefined) ??\n\t\t\t\tnew Map<string, TMem>();\n\t\t\tif (m.has(key)) return \"active\";\n\t\t\treturn \"archived\";\n\t\t};\n\t\tconst permanentRef = this.permanent;\n\t\tconst markPermanent = (key: string, value: TMem): void => {\n\t\t\tpermanentKeysRef.set(key, true);\n\t\t\tpermanentRef.upsert(key, value);\n\t\t};\n\n\t\t// DS-13.5.F (2026-05-01): first-write of `entryCreatedAtNs[key]` runs\n\t\t// here (extracted from `retention.score` to keep score pure). Reads\n\t\t// `store.store.entries`, writes `entryCreatedAtNs` — distinct nodes,\n\t\t// no §7 feedback cycle. Idempotent: re-emissions for already-tracked\n\t\t// keys skip via `entryCreatedAtNsRef.has(key)`.\n\t\tconst syncCreatedAt = node(\n\t\t\t[this.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = (data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tconst nowNs = monotonicNs();\n\t\t\t\tconst toAdd: string[] = [];\n\t\t\t\tfor (const key of map.keys()) {\n\t\t\t\t\tif (!entryCreatedAtNsRef.has(key)) toAdd.push(key);\n\t\t\t\t}\n\t\t\t\tif (toAdd.length > 0) {\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tfor (const key of toAdd) entryCreatedAtNsRef.set(key, nowNs);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"entryCreatedAtNs/sync\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(syncCreatedAt, { name: \"entryCreatedAtNs/sync\" });\n\t\tthis.addDisposer(keepalive(syncCreatedAt));\n\n\t\t// GC entryCreatedAtNs entries that no longer exist in the active store.\n\t\t// (Adds happen via the syncCreatedAt effect above; removals piggyback\n\t\t// on the store-snapshot subscriber here so the map stays in sync.)\n\t\tconst entriesUnsub = this.store.store.entries.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\tconst map = m[1] as ReadonlyMap<string, TMem>;\n\t\t\t\tconst created = entryCreatedAtNsRef.entries.cache as\n\t\t\t\t\t| ReadonlyMap<string, number>\n\t\t\t\t\t| undefined;\n\t\t\t\tif (created == null) continue;\n\t\t\t\tconst toDelete: string[] = [];\n\t\t\t\tfor (const key of created.keys()) {\n\t\t\t\t\tif (!map.has(key)) toDelete.push(key);\n\t\t\t\t}\n\t\t\t\tif (toDelete.length > 0) {\n\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\tfor (const key of toDelete) entryCreatedAtNsRef.delete(key);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(entriesUnsub);\n\n\t\t// Permanent-promotion effect. Writes to `permanent` collection +\n\t\t// `permanentKeys` (NOT to the active store), so no §7 cycle: the effect's\n\t\t// dep is `store.store.entries`, but it doesn't write back to that node.\n\t\tconst promoter = node(\n\t\t\t[this.store.store.entries],\n\t\t\t(batchData, _actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = (data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tfor (const [key, mem] of map) {\n\t\t\t\t\tif (permanentKeysRef.has(key)) continue;\n\t\t\t\t\tif (permanentFilter(key, mem)) {\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tmarkPermanent(key, mem);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ name: \"promoter\", describeKind: \"effect\" },\n\t\t);\n\t\tthis.add(promoter, { name: \"promoter\" });\n\t\tthis.addDisposer(keepalive(promoter));\n\n\t\tlet archiveHandle: StorageHandle | null = null;\n\t\tif (opts.archiveTier) {\n\t\t\tarchiveHandle = this.attachSnapshotStorage(\n\t\t\t\t[{ snapshot: opts.archiveTier }],\n\t\t\t\topts.archiveStorageOptions ?? {},\n\t\t\t);\n\t\t\tthis.addDisposer(() => archiveHandle?.dispose());\n\t\t}\n\n\t\tthis.tiers = {\n\t\t\tpermanent: this.permanent,\n\t\t\tactiveEntries: this.store.store.entries,\n\t\t\tarchiveHandle,\n\t\t\ttierOf,\n\t\t\tmarkPermanent,\n\t\t};\n\t}\n}\n\n/**\n * Attach 3-tier storage (active / archived / permanent) over a fresh distill\n * store. Returns a `MemoryWithTiersGraph` whose `store` and `tiers` fields\n * mirror the previous bundle shape.\n *\n * **API shape** (Class B audit, 2026-04-30 — breaking change vs.\n * pre-migration): the factory takes a single opts bag including `source`\n * and `extractFn`. The bundle is exposed as `result.store` for downstream\n * composers (vectors / KG / retrieval).\n *\n * - `permanentFilter`-matching entries score `Infinity` in retention →\n * never archived. Independent permanent-promotion effect upserts them\n * into the `permanent` collection.\n * - Below-threshold entries → retention archives synchronously.\n * - Over-`maxActive` entries → retention's `maxSize` evicts lowest-scored.\n */\nexport function memoryWithTiers<TRaw, TMem>(\n\topts: MemoryWithTiersOptions<TRaw, TMem>,\n): MemoryWithTiersGraph<TRaw, TMem> {\n\treturn new MemoryWithTiersGraph<TRaw, TMem>(opts);\n}\n\n// ---------------------------------------------------------------------------\n// memoryRetrieval\n// ---------------------------------------------------------------------------\n\nexport interface MemoryRetrievalOptions<TMem> {\n\t/** Optional Graph identity. */\n\tgraph?: GraphOptions;\n\t/** Subgraph name. Default: `\"memory-retrieval\"`. */\n\tname?: string;\n\t/** The substrate distill store. */\n\tstore: DistillBundle<TMem>;\n\t/** Optional vector index for similarity search. */\n\tvectors?: VectorIndexGraph<TMem> | null;\n\t/** Optional knowledge graph for entity-relation expansion. */\n\tkg?: KnowledgeGraph<unknown, string> | null;\n\t/** Score function (same shape as `agentMemory.score`). */\n\tscore: (mem: TMem, context: unknown) => number;\n\t/** Cost function for budget packing. */\n\tcost: (mem: TMem) => number;\n\t/** Token / cost budget. Default 2000. */\n\tbudget?: number;\n\t/** Top-K vector candidates. Default 20. */\n\ttopK?: number;\n\t/** KG expansion depth in hops. Default 1. */\n\tgraphDepth?: number;\n\t/** Hierarchical-context boost weight. Default 0. */\n\tcontextWeight?: number;\n\t/** Hierarchical-context accessor for entries. */\n\tcontextOf?: (mem: TMem) => readonly string[] | undefined;\n\t/** Optional reactive context node (passed to `score`). */\n\tcontext?: NodeInput<unknown>;\n}\n\nfunction sharedPrefixDepth(\n\tq: readonly string[] | undefined,\n\te: readonly string[] | undefined,\n): number {\n\tif (!q || !e) return 0;\n\tconst n = Math.min(q.length, e.length);\n\tlet i = 0;\n\twhile (i < n && q[i] === e[i]) i++;\n\treturn i;\n}\n\n// QA-fix: element-wise reference-equality dedup so subscribers don't wake\n// up when an identical packed array lands (runRetrieval allocates a new\n// outer array reference every call).\nconst packedEquals = <T>(a: readonly T[], b: readonly T[]): boolean => {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n\treturn true;\n};\n\n/**\n * Graph subclass that builds the retrieval pipeline (vector + KG + budget\n * packing) over a `DistillBundle` and optional vectors / kg substrates.\n *\n * **C1 rework (2026-04-30):** retrieval is reactive-only. Each\n * `retrieveReactive(input)` call constructs its own per-input subgraph\n * mounted at `retrieve_${id}` with named nodes `context`, `result`, and\n * `projection`. Subgraphs register their own scoped disposers so teardown\n * is local to the per-call mount.\n *\n * **QA F-9 (2026-04-30):** the shared `retrieval` / `retrievalTrace`\n * state-node mirrors are dropped — they were last-writer-wins under\n * concurrent `retrieveReactive(...)` calls. Consumers must subscribe to\n * the per-call `projection` node directly. One-shot consumers use\n * `awaitSettled(retrieveReactive(input))`.\n *\n * **QA F-6 (2026-04-30):** the per-call `result` derived declares\n * `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps when\n * configured, so a vector upsert / KG mutation re-runs retrieval even\n * when the query / context / store-snapshot are unchanged. Resolves the\n * §28 closure-mirror gap where these `.cache` reads were undeclared.\n */\nexport class MemoryRetrievalGraph<TMem> extends Graph {\n\tprivate readonly _store: DistillBundle<TMem>;\n\tprivate readonly _vectors: VectorIndexGraph<TMem> | null;\n\tprivate readonly _kg: KnowledgeGraph<unknown, string> | null;\n\tprivate readonly _opts: MemoryRetrievalOptions<TMem>;\n\tprivate readonly _contextNode: Node<unknown>;\n\tprivate readonly _topK: number;\n\tprivate readonly _graphDepth: number;\n\tprivate readonly _budget: number;\n\tprivate readonly _contextWeight: number;\n\tprivate _retrieveSeq = 0;\n\n\tconstructor(opts: MemoryRetrievalOptions<TMem>) {\n\t\tsuper(opts.name ?? \"memory-retrieval\", opts.graph);\n\n\t\tthis._store = opts.store;\n\t\tthis._vectors = opts.vectors ?? null;\n\t\tthis._kg = opts.kg ?? null;\n\t\tthis._opts = opts;\n\t\tthis._topK = opts.topK ?? 20;\n\t\tthis._graphDepth = opts.graphDepth ?? 1;\n\t\tthis._budget = opts.budget ?? 2000;\n\t\tthis._contextWeight = opts.contextWeight ?? 0;\n\t\t// DS-13.5.C: synthesized branch (no `opts.context` supplied) registers\n\t\t// on this graph as `_context` so describe()/explain() can walk to it.\n\t\t// User-supplied branch stays unregistered — `fromAny` returns the\n\t\t// caller's owned Node, which is owned by their graph; mounting it\n\t\t// here would corrupt cross-graph ownership (mirrors MemoryWithTiers's\n\t\t// context-branch policy).\n\t\tif (opts.context) {\n\t\t\tthis._contextNode = fromAny(opts.context);\n\t\t} else {\n\t\t\tthis._contextNode = this.state<unknown>(\"_context\", null);\n\t\t}\n\t}\n\n\tprivate _runRetrieval(\n\t\tstoreMap: ReadonlyMap<string, TMem>,\n\t\tctx: unknown,\n\t\tquery: RetrievalQuery,\n\t): { packed: RetrievalEntry<TMem>[]; trace: RetrievalTrace<TMem> } {\n\t\tconst opts = this._opts;\n\t\tconst candidateMap = new Map<\n\t\t\tstring,\n\t\t\t{ value: TMem; sources: Set<\"vector\" | \"graph\" | \"store\"> }\n\t\t>();\n\n\t\tlet vectorCandidates: VectorSearchResult<TMem>[] = [];\n\t\tif (this._vectors && query.vector) {\n\t\t\t// Wave A migrated `vectorIndex` to a reactive-only read API\n\t\t\t// (`searchNode`); inline the equivalent flat-cosine snapshot scan\n\t\t\t// here since `_runRetrieval` is sync and `searchNode` is async-shaped.\n\t\t\t// `patterns/ai/memory/` is queued for its own audit per the Wave A\n\t\t\t// session doc § D.1.\n\t\t\tconst q = query.vector;\n\t\t\tconst snapshot = this._vectors.entries.cache as\n\t\t\t\t| ReadonlyMap<string, VectorRecord<TMem>>\n\t\t\t\t| undefined;\n\t\t\tif (snapshot && snapshot.size > 0 && this._topK > 0) {\n\t\t\t\tconst scored = [...snapshot.values()]\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(row): VectorSearchResult<TMem> => ({\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, this._topK);\n\t\t\t\tvectorCandidates = scored;\n\t\t\t\tfor (const vc of vectorCandidates) {\n\t\t\t\t\tconst mem = storeMap.get(vc.id);\n\t\t\t\t\tif (mem) candidateMap.set(vc.id, { value: mem, sources: new Set([\"vector\"]) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst graphExpanded: string[] = [];\n\t\tif (this._kg) {\n\t\t\t// Wave A migrated `knowledgeGraph` to a reactive-only `relatedNode`\n\t\t\t// API; inline the equivalent adjacency-snapshot scan here for the\n\t\t\t// sync expansion. `adjacencyOut` / `adjacencyIn` are kept warm by\n\t\t\t// the kg's own internal keepalive disposers, so `.cache` is always\n\t\t\t// populated post-construction.\n\t\t\tconst adjOut = this._kg.adjacencyOut.cache as\n\t\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<string>[]>\n\t\t\t\t| undefined;\n\t\t\tconst adjIn = this._kg.adjacencyIn.cache as\n\t\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<string>[]>\n\t\t\t\t| undefined;\n\t\t\tconst seedIds = [...(query.entityIds ?? []), ...[...candidateMap.keys()]];\n\t\t\tconst visited = new Set<string>();\n\t\t\tlet frontier = seedIds;\n\t\t\tfor (let depth = 0; depth < this._graphDepth; depth++) {\n\t\t\t\tconst nextFrontier: string[] = [];\n\t\t\t\tfor (const id of frontier) {\n\t\t\t\t\tif (visited.has(id)) continue;\n\t\t\t\t\tvisited.add(id);\n\t\t\t\t\tconst outEdges = adjOut?.get(id) ?? [];\n\t\t\t\t\tconst inEdges = adjIn?.get(id) ?? [];\n\t\t\t\t\tfor (const edge of outEdges) {\n\t\t\t\t\t\tconst targetId = edge.to;\n\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\tif (existing) existing.sources.add(\"graph\");\n\t\t\t\t\t\t\t\telse candidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Inbound edges: traverse to the `from` side. Match the\n\t\t\t\t\t// previous `kg.related(id)` semantics, which returned both\n\t\t\t\t\t// `from === id` and `to === id` matches.\n\t\t\t\t\tfor (const edge of inEdges) {\n\t\t\t\t\t\tconst targetId = edge.from;\n\t\t\t\t\t\tif (!visited.has(targetId)) {\n\t\t\t\t\t\t\tnextFrontier.push(targetId);\n\t\t\t\t\t\t\tconst mem = storeMap.get(targetId);\n\t\t\t\t\t\t\tif (mem) {\n\t\t\t\t\t\t\t\tconst existing = candidateMap.get(targetId);\n\t\t\t\t\t\t\t\tif (existing) existing.sources.add(\"graph\");\n\t\t\t\t\t\t\t\telse candidateMap.set(targetId, { value: mem, sources: new Set([\"graph\"]) });\n\t\t\t\t\t\t\t\tgraphExpanded.push(targetId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfrontier = nextFrontier;\n\t\t\t}\n\t\t}\n\t\tfor (const [key, mem] of storeMap) {\n\t\t\tif (!candidateMap.has(key)) {\n\t\t\t\tcandidateMap.set(key, { value: mem, sources: new Set([\"store\"]) });\n\t\t\t}\n\t\t}\n\n\t\tconst qDepth = query.context?.length ?? 0;\n\t\tconst ranked: RetrievalEntry<TMem>[] = [];\n\t\tfor (const [key, { value, sources }] of candidateMap) {\n\t\t\tconst entryContext = opts.contextOf ? opts.contextOf(value) : undefined;\n\t\t\tlet score = opts.score(value, ctx);\n\t\t\tif (this._contextWeight > 0 && qDepth > 0) {\n\t\t\t\tconst shared = sharedPrefixDepth(query.context, entryContext);\n\t\t\t\tif (shared > 0) score = score * (1 + (this._contextWeight * shared) / qDepth);\n\t\t\t}\n\t\t\tconst entry: RetrievalEntry<TMem> = entryContext\n\t\t\t\t? { key, value, score, sources: [...sources], context: entryContext }\n\t\t\t\t: { key, value, score, sources: [...sources] };\n\t\t\tranked.push(entry);\n\t\t}\n\t\tranked.sort((a, b) => b.score - a.score);\n\n\t\tconst packed: RetrievalEntry<TMem>[] = [];\n\t\tlet usedBudget = 0;\n\t\tfor (const entry of ranked) {\n\t\t\tconst c = opts.cost(entry.value);\n\t\t\tif (usedBudget + c > this._budget && packed.length > 0) break;\n\t\t\tpacked.push(entry);\n\t\t\tusedBudget += c;\n\t\t}\n\n\t\treturn { packed, trace: { vectorCandidates, graphExpanded, ranked, packed } };\n\t}\n\n\t/**\n\t * Reactive consumer API — chain into the graph.\n\t *\n\t * Each call constructs its own per-input subgraph mounted at\n\t * `retrieve_${id}` (auto-incrementing within this MemoryRetrievalGraph\n\t * instance) with named nodes:\n\t *\n\t * - `context` — `fromAny(queryInput)` projection (so the input node is\n\t * visible to `describe()` even when callers pass a raw value).\n\t * - `result` — pure derived `{ packed, trace }`.\n\t * - `projection` — the packed-array node returned to the caller.\n\t *\n\t * `result` declares the substrate's `store.entries`, the optional\n\t * `context` Node, the local `context` projection, and (when configured)\n\t * `vectors.entries` / `kg.adjacencyOut` / `kg.adjacencyIn` as deps —\n\t * so vector upserts and KG mutations re-trigger retrieval even when\n\t * the input is unchanged.\n\t *\n\t * **Lifecycle contract (DS-13.5.C, 2026-05-01).** The per-call subgraph\n\t * stays mounted while the returned `projection` has at least one\n\t * subscriber. When the last subscriber unsubscribes, projection's\n\t * `deactivate` cleanup hook fires (canonical \"last unsubscribe\" signal\n\t * via the existing `NodeFnCleanup.onDeactivation` protocol), which calls\n\t * `parent.remove(retrieve_${id})` and tears the per-call topology\n\t * down via TEARDOWN cascade (post-DS-13.5.A Q16, COMPLETE auto-precedes).\n\t *\n\t * **Single-shot lifecycle.** This auto-unmount is keyed to the FIRST\n\t * last-unsubscribe event — projection is non-resubscribable from the\n\t * caller's perspective. Callers who need to subscribe / unsubscribe /\n\t * re-subscribe should hold a long-lived subscription externally (e.g.\n\t * `keepalive(projection)`) or call `retrieveReactive(...)` again to\n\t * mount a fresh per-call subgraph.\n\t *\n\t * **Caller obligation.** Either subscribe to `projection` (and\n\t * eventually unsubscribe to trigger cleanup) OR drop the returned\n\t * reference without subscribing — in the no-subscribe case the\n\t * subgraph is dormant (no compute fires) and a parent `destroy()`\n\t * cascade reclaims it. Holding `projection` without subscribing AND\n\t * without ever destroying the parent is the leak case the JSDoc above\n\t * the C1 rework covers.\n\t *\n\t * One-shot callers use `awaitSettled(retrieveReactive(input))`.\n\t */\n\tretrieveReactive(\n\t\tqueryInput: NodeInput<RetrievalQuery | null>,\n\t): Node<ReadonlyArray<RetrievalEntry<TMem>>> {\n\t\tconst id = ++this._retrieveSeq;\n\t\tconst segment = `retrieve_${id}`;\n\n\t\t// Per-call subgraph — owns the wiring, the keepalive, and the\n\t\t// teardown. Mounted on `this` so it's visible in `describe()` and\n\t\t// reachable via `${parent}::retrieve_${id}::result` etc.\n\t\tconst sub = new Graph(segment);\n\n\t\t// Wrap the input as a local pass-through so the per-call subgraph\n\t\t// shows the query source in `describe()` regardless of where the\n\t\t// caller's node lives in the broader topology. `fromAny` returns\n\t\t// the original Node when given a Node, otherwise wraps a\n\t\t// value/promise into a producer.\n\t\t//\n\t\t// DS-13.5.C: registered via `sub.derived(...)` (Graph helper) for\n\t\t// equals plumbing + automatic registration; replaces the prior raw\n\t\t// `node([inputNode], fn) + sub.add(...)` shape.\n\t\tconst inputNode = fromAny(queryInput);\n\t\tconst localContext = sub.derived<RetrievalQuery | null>(\n\t\t\t\"context\",\n\t\t\t[inputNode],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\treturn [(data[0] as RetrievalQuery | null) ?? null];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: aiMeta(\"retrieval_query_input\"),\n\t\t\t\tinitial: null,\n\t\t\t},\n\t\t);\n\n\t\t// /qa F-6 (2026-04-30): declare vectors / kg substrate Node refs as\n\t\t// deps so vector upserts / KG mutations re-trigger retrieval even\n\t\t// when query / context / store snapshots are unchanged. The\n\t\t// `_runRetrieval` body reads `.cache` from these substrates; before\n\t\t// this fix those reads were undeclared §28 closure-mirrors.\n\t\tconst resultDeps: (string | Node<unknown>)[] = [\n\t\t\tthis._store.store.entries,\n\t\t\tthis._contextNode,\n\t\t\tlocalContext,\n\t\t];\n\t\tif (this._vectors) resultDeps.push(this._vectors.entries as Node<unknown>);\n\t\tif (this._kg) {\n\t\t\tresultDeps.push(this._kg.adjacencyOut as Node<unknown>);\n\t\t\tresultDeps.push(this._kg.adjacencyIn as Node<unknown>);\n\t\t}\n\n\t\t// DS-13.5.C: migrated to `sub.derived(...)` for equals plumbing +\n\t\t// automatic registration.\n\t\tconst result = sub.derived<{\n\t\t\tpacked: ReadonlyArray<RetrievalEntry<TMem>>;\n\t\t\ttrace: RetrievalTrace<TMem> | null;\n\t\t}>(\n\t\t\t\"result\",\n\t\t\tresultDeps,\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst query = data[2];\n\t\t\t\tif (query == null) {\n\t\t\t\t\treturn [{ packed: [] as ReadonlyArray<RetrievalEntry<TMem>>, trace: null }];\n\t\t\t\t}\n\t\t\t\tconst storeMap =\n\t\t\t\t\t(data[0] as ReadonlyMap<string, TMem> | undefined) ?? new Map<string, TMem>();\n\t\t\t\tconst { packed, trace } = this._runRetrieval(storeMap, data[1], query as RetrievalQuery);\n\t\t\t\treturn [{ packed, trace }];\n\t\t\t},\n\t\t\t{\n\t\t\t\tmeta: aiMeta(\"retrieval_reactive_result\"),\n\t\t\t\tinitial: { packed: [] as ReadonlyArray<RetrievalEntry<TMem>>, trace: null },\n\t\t\t},\n\t\t);\n\n\t\t// DS-13.5.C: projection stays as raw `node()` (not `sub.derived`)\n\t\t// because the keepalive disposer is wired via the fn's\n\t\t// `NodeFnCleanup.onDeactivation` hook — projection's cleanup-on-last-\n\t\t// unsubscribe is what drives `parent.remove(segment)`. The Graph\n\t\t// `.derived()` helper drops the cleanup return, so the raw form\n\t\t// is required here. `equals: packedEquals` is preserved verbatim.\n\t\tconst projection = node<ReadonlyArray<RetrievalEntry<TMem>>>(\n\t\t\t[result],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((b, i) =>\n\t\t\t\t\tb != null && b.length > 0 ? b.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tactions.emit((data[0] as { packed: ReadonlyArray<RetrievalEntry<TMem>> }).packed);\n\t\t\t\treturn {\n\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t// Auto-unmount on last unsubscribe (DS-13.5.C).\n\t\t\t\t\t\t// Idempotent: try/catch covers the case where the\n\t\t\t\t\t\t// segment was already removed (e.g. parent destroy\n\t\t\t\t\t\t// cascade ran first, or the caller called remove()\n\t\t\t\t\t\t// manually).\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tthis.remove(segment);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* best-effort cleanup */\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"projection\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: aiMeta(\"retrieval_reactive\"),\n\t\t\t\tinitial: [] as ReadonlyArray<RetrievalEntry<TMem>>,\n\t\t\t\tequals: packedEquals,\n\t\t\t},\n\t\t);\n\t\tsub.add(projection, { name: \"projection\" });\n\n\t\tthis.mount(segment, sub);\n\t\treturn projection;\n\t}\n}\n\n/**\n * Build the retrieval pipeline (vector + KG + budget packing) over a\n * `DistillBundle` and optional `vectors` / `kg` substrates. Returns a\n * `MemoryRetrievalGraph` exposing `retrieval` / `retrievalTrace` reactive\n * state and the `retrieveReactive(input)` consumer method.\n */\nexport function memoryRetrieval<TMem>(\n\topts: MemoryRetrievalOptions<TMem>,\n): MemoryRetrievalGraph<TMem> {\n\treturn new MemoryRetrievalGraph<TMem>(opts);\n}\n","/**\n * Pure exponential-decay utility (Tier 2.2 promotion from `patterns/memory/`).\n *\n * Used by `collection`, `agentMemory`, harness `strategy.ts`, and any\n * downstream consumer that needs decay-with-floor scoring. Promoted to\n * `extra/utils/` because the math has zero domain semantics and is reusable\n * by non-memory primitives (e.g. routing weight decay, retry-attempt aging).\n *\n * @module\n */\n\n/**\n * Default exponential-decay rate corresponding to a 7-day half-life.\n *\n * `Math.LN2 / (7 × 86_400)` ≈ `1.146e-6`. Imported by memory tiers + any\n * consumer that wants the same default cadence as `agentMemory`'s active\n * tier. Tier 4.4 (Wave AM Unit 1) — promoted from\n * `patterns/ai/memory/tiers.ts` so non-memory consumers can share the\n * canonical default without reaching across domains.\n */\nexport const DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86_400);\n\n/**\n * Exponential decay with floor: `score = max(minScore, baseScore * exp(-ratePerSecond * ageSeconds))`.\n *\n * Tolerant fallbacks (deliberate for use inside reactive derived fns):\n * - non-finite `baseScore` → `minScore`\n * - non-positive `ageSeconds` (incl. clock skew) → `max(minScore, baseScore)` (no decay)\n * - non-positive `ratePerSecond` → `max(minScore, baseScore)` (no decay; rate=0 disables)\n *\n * Underflow boundary: `Math.exp(-745) === 0`. For very long ages × rates the\n * result clamps to `minScore`; if you need slow decay over years, choose a\n * smaller `ratePerSecond` rather than relying on graceful underflow.\n *\n * Half-life conversion: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n */\nexport function decay(\n\tbaseScore: number,\n\tageSeconds: number,\n\tratePerSecond: number,\n\tminScore = 0,\n): number {\n\tif (!Number.isFinite(baseScore)) return minScore;\n\tif (!Number.isFinite(ageSeconds) || ageSeconds <= 0) return Math.max(minScore, baseScore);\n\tif (!Number.isFinite(ratePerSecond) || ratePerSecond <= 0) return Math.max(minScore, baseScore);\n\tconst decayed = baseScore * Math.exp(-ratePerSecond * ageSeconds);\n\treturn Math.max(minScore, decayed);\n}\n","/**\n * Memory patterns (roadmap §4.3) — public-face Phase-4 primitives audited under\n * `archive/docs/SESSION-public-face-blocks-review.md` (Wave A, locked 2026-04-25).\n *\n * Three primitives (the pure `decay` helper was promoted to `extra/utils/decay.ts`\n * per Tier 2.2 and is no longer re-exported here; `lightCollection` was folded\n * into `collection({ranked:false})` per Tier 2.3 and is no longer a separate\n * factory):\n * - {@link collection} / {@link CollectionGraph} — keyed memory store with\n * optional decay-aware ranking. Pass `{ ranked: false }` for the previous\n * `lightCollection` shape (Map + LRU + audit, no scoring).\n * - {@link vectorIndex} / {@link VectorIndexGraph} — reactive vector store with\n * optional HNSW backend, retention, and reactive {@link VectorIndexGraph.searchNode}.\n * - {@link knowledgeGraph} / {@link KnowledgeGraph} — entities + typed edges with\n * symmetric adjacency indexes and reactive {@link KnowledgeGraph.relatedNode}.\n *\n * **No imperative reads.** Per the API-style policy locked 2026-04-25, public-face\n * primitives expose reactive reads only — `itemNode` / `hasNode` / `searchNode` /\n * `relatedNode`. One-shot snapshots use `node.cache` after `awaitSettled`, or\n * `firstValueFrom(node)`.\n *\n * **Audit logs.** Every imperative mutation (`upsert / remove / clear / link /\n * unlink / rescore / reindex`) is wrapped via {@link mutate} and appends a\n * typed record to a public `events` log on the bundle / graph.\n *\n * @module\n */\n\nimport { monotonicNs, type Node, NodeImpl, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { fromTimer, keepalive, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport {\n\ttype BaseAuditRecord,\n\tbumpCursor,\n\tcreateAuditLog,\n\tmutate,\n\tregisterCursor,\n} from \"../../base/mutation/index.js\";\nimport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\nimport { decay } from \"../../base/utils/decay.js\";\n\n// ── Shared helpers ───────────────────────────────────────────────────────\n\nconst NS_PER_SEC = 1_000_000_000;\n\nfunction memoryMeta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"memory\", kind, extra);\n}\n\n/**\n * Coerce a value-or-Node argument into a `Node<T>`. Pass-through if already a\n * Node; otherwise wraps in `state(value, {name})`. Used by reactive read\n * factories (`itemNode` / `searchNode` / `relatedNode`) so callers can supply\n * a static value without manually creating a state node.\n *\n * Heuristic: anything that is a `NodeImpl` instance is a Node; everything else\n * is treated as a raw value to wrap.\n */\nfunction toNode<T>(v: T | Node<T>, name?: string): Node<T> {\n\tif (v instanceof NodeImpl) return v as Node<T>;\n\treturn node<T>([], { initial: v as T, ...(name ? { name } : undefined) });\n}\n\nfunction ageSeconds(now: number, lastNs: number): number {\n\treturn (now - lastNs) / NS_PER_SEC;\n}\n\n// `decay` was promoted to `extra/utils/decay.ts` per Tier 2.2 — it is no longer\n// re-exported from this module. Import from `@graphrefly/graphrefly/extra` (or\n// `../../extra/utils/decay.js` internally) instead.\n\n/**\n * Cosine similarity over `(a, b)`. When lengths differ, the shorter is\n * implicitly zero-padded to the longer length. Returns `0` if either vector\n * has zero norm. Public utility — used by {@link VectorIndexGraph.searchNode}\n * and exposed for downstream consumers (e.g. `patterns/ai/memory/`) that need\n * the same scoring at the boundary.\n *\n * **Numeric guards.** Returns `0` for non-finite results (overflow producing\n * `Infinity`/`NaN` from very-large vectors, or `NaN` propagating from any\n * `NaN`/`Infinity` component). Without this guard, downstream sort\n * comparators would order NaN-scored rows arbitrarily.\n *\n * **Depth.** This is a per-call computation; no internal caching. For very\n * large indexes (>10k) consider precomputing norms or using HNSW.\n *\n * @category memory\n */\nexport function cosineSimilarity(a: readonly number[], b: readonly number[]): number {\n\tconst n = Math.max(a.length, b.length);\n\tlet dot = 0;\n\tlet na = 0;\n\tlet nb = 0;\n\tfor (let i = 0; i < n; i += 1) {\n\t\tconst av = a[i] ?? 0;\n\t\tconst bv = b[i] ?? 0;\n\t\tdot += av * bv;\n\t\tna += av * av;\n\t\tnb += bv * bv;\n\t}\n\tif (na === 0 || nb === 0) return 0;\n\tconst score = dot / Math.sqrt(na * nb);\n\treturn Number.isFinite(score) ? score : 0;\n}\n\n/**\n * Equality predicate for {@link VectorIndexGraph.searchNode} results. Compares\n * `id` AND `score` AND `meta` reference per position so that score-only changes\n * (re-upsert with new vector keeping the same top-K order) propagate to\n * downstream subscribers. The previous id-only comparator silently dropped\n * those updates.\n */\nfunction searchResultsEqual<TMeta>(\n\ta: readonly VectorSearchResult<TMeta>[] | undefined,\n\tb: readonly VectorSearchResult<TMeta>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\tif (x.id !== y.id || x.score !== y.score || x.meta !== y.meta) return false;\n\t}\n\treturn true;\n}\n\n// ── Common types ─────────────────────────────────────────────────────────\n\n/** Public alias for the `Node | value` shape accepted by reactive read factories. */\nexport type { NodeOrValue } from \"../../base/resilience/_internal.js\";\n\n// ── Unit 2 (Tier 2.3 fold): collection (formerly lightCollection + collection)\n//\n// Pre-Tier-2.3 the module shipped `lightCollection` (no Graph, no ranking,\n// just LRU + audit) alongside `collection` (Graph-mounted with timer-driven\n// decay-aware ranking). Per the consolidation plan §1 Rule 4, the two are\n// folded into a single `collection({ranked: true|false})` factory: when\n// `ranked: false`, no `ranked` derived / refresh tick / scoring is wired.\n// `LightCollectionEntry` is gone — `CollectionEntry<T>` is the unified entry\n// shape (`baseScore` reads `0` in unranked mode).\n\nexport type CollectionEntry<T> = {\n\treadonly id: string;\n\treadonly value: T;\n\treadonly createdAtNs: number;\n\treadonly lastAccessNs: number;\n\treadonly baseScore: number;\n};\n\nexport type RankedCollectionEntry<T> = CollectionEntry<T> & {\n\treadonly score: number;\n};\n\nexport type CollectionScoreFn<T> = (value: T) => number;\n\nexport type CollectionOptions<T> = {\n\tmaxSize?: number;\n\t/**\n\t * Whether to expose a live decay-aware `ranked` node + `rescore` mutator.\n\t * Default `true`. Pass `false` to fold in the previous `lightCollection`\n\t * shape — entries are still keyed/audited/LRU-evicted, but the timer-driven\n\t * `ranked` + scoring machinery is skipped. `ranked` then resolves to a\n\t * static empty array Node and `rescore()` is a no-op (so callers writing\n\t * type-generic code don't need to special-case the unranked path).\n\t */\n\tranked?: boolean;\n\t/**\n\t * Produces a base score at insert/update time. Static fn or a reactive\n\t * `Node<(value: T) => number>` — when supplied as a Node, `ranked` re-derives\n\t * whenever the score fn changes, but `baseScore` on each entry is only\n\t * recomputed via {@link CollectionGraph.rescore}. Default `() => 1`.\n\t *\n\t * Ignored when `ranked: false` (entries record `baseScore: 0`).\n\t */\n\tscore?: CollectionScoreFn<T> | Node<CollectionScoreFn<T>>;\n\t/**\n\t * Exponential decay rate per second. `0` disables decay (default). When\n\t * positive, `ranked` becomes fully reactive on time via a `fromTimer` source\n\t * (cadence auto-derived from `decayRate` unless overridden via\n\t * `refreshIntervalMs`). Half-life: `ratePerSecond = Math.LN2 / halfLifeSeconds`.\n\t *\n\t * Ignored when `ranked: false`.\n\t */\n\tdecayRate?: number;\n\t/** Minimum score floor after decay. Default `0`. */\n\tminScore?: number;\n\t/**\n\t * Override for the `ranked` refresh tick cadence (milliseconds). When\n\t * unset and `decayRate > 0`, defaults to `1000 * Math.LN2 / (10 * decayRate)`\n\t * — roughly one tick per 10% of the half-life (~10% staleness budget).\n\t */\n\trefreshIntervalMs?: number;\n};\n\nexport interface CollectionAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"rescore\";\n\treadonly id?: string;\n}\n\nexport type CollectionGraph<T> = Graph & {\n\treadonly events: ReactiveLogBundle<CollectionAuditRecord>;\n\treadonly items: Node<ReadonlyMap<string, CollectionEntry<T>>>;\n\t/**\n\t * Live decay-aware ranking, sorted by score descending. When the\n\t * collection was constructed with `ranked: false`, this is a static\n\t * empty-array Node (kept for type uniformity).\n\t */\n\treadonly ranked: Node<readonly RankedCollectionEntry<T>[]>;\n\treadonly size: Node<number>;\n\tupsert: (id: string, value: T, opts?: { score?: number }) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/**\n\t * Recompute every entry's `baseScore` via the latest score fn. O(N). Useful\n\t * when a reactive `score` Node has emitted a new fn and the caller wants\n\t * existing entries re-scored without an explicit re-upsert.\n\t *\n\t * No-op (still records an audit entry) when constructed with\n\t * `ranked: false`.\n\t */\n\trescore: () => void;\n\titemNode: (id: NodeOrValue<string>) => Node<CollectionEntry<T> | undefined>;\n\t/** Reactive `true` once the entry exists; tracks upsert / remove. */\n\thasNode: (id: NodeOrValue<string>) => Node<boolean>;\n};\n\nfunction rankedEqual<T>(\n\ta: readonly RankedCollectionEntry<T>[] | undefined,\n\tb: readonly RankedCollectionEntry<T>[] | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tconst x = a[i]!;\n\t\tconst y = b[i]!;\n\t\t// Compare value reference too — if `upsert(id, newValue)` runs and\n\t\t// `score(newValue) === score(oldValue)` AND timestamps coincide\n\t\t// (rare on platforms where consecutive `monotonicNs()` calls in the\n\t\t// same microtask collide), the prior comparator suppressed the\n\t\t// emission and consumers reading `entry.value` saw stale data.\n\t\t// Value identity catches it cheaply (`value !== value` only on NaN\n\t\t// payloads, which behave correctly here).\n\t\tif (\n\t\t\tx.id !== y.id ||\n\t\t\tx.score !== y.score ||\n\t\t\tx.lastAccessNs !== y.lastAccessNs ||\n\t\t\tx.value !== y.value\n\t\t)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Scored memory store with live decay-aware ranking.\n *\n * Topology (mounted on the returned graph):\n * - `items` — `reactiveMap<id, CollectionEntry<T>>` (with `retention` configured\n * for score-based eviction when `maxSize` is set).\n * - `ranked` — `Node<readonly RankedCollectionEntry<T>[]>`, sorted by live\n * decayed score. **Lazy** — does NOT compute until subscribed (no internal\n * keepalive). Use `keepalive(coll.ranked)` for eager activation.\n * - `size` — `Node<number>`, count of entries.\n * - `_refreshTick` — `fromTimer`-driven `monotonicNs()` source, mounted only\n * when `decayRate > 0`. Drives `ranked`'s time-dependent re-derivation.\n * - `_seq` — sequence cursor for the audit log.\n * - `events` — bounded reactive log of every mutation.\n *\n * **Time as a reactive dep.** When `decayRate > 0`, `ranked`'s deps are\n * `[items, refreshTick]` — the tick payload IS `monotonicNs()`, so the fn is\n * pure of deps and dry-run-reproducible with a mocked clock.\n *\n * **Lazy timer.** With no subscriber to `ranked`, the timer source does not\n * fire — the activation chain is downstream-driven. To keep the timer warm\n * without consuming results, register `graph.addDisposer(keepalive(coll.ranked))`.\n *\n * **Eviction at write-time.** Score-based retention runs on every successful\n * `upsert / remove / clear` (it is mutation-driven, not tick-driven). The\n * retention scorer reads `monotonicNs()` to compute decayed scores at eviction\n * time — this is a deliberate impurity vs. `ReactiveMapRetention.score`'s\n * \"pure of `(key, value)`\" docstring: write-time is the right moment to evict\n * stale-by-decay entries.\n *\n * **No imperative reads.** Subscribe to `items` / `ranked` for live snapshots,\n * or use `itemNode(id)` for single-key reactive reads.\n *\n * **`rescore` ordering caveat.** `rescore()` reads `items.entries.cache`\n * (the post-emission snapshot) and writes via `setMany`. When called\n * stand-alone it sees the latest committed state. When wrapped inside a\n * user-level `batch(() => { coll.upsert(...); coll.rescore(); })`, the\n * `cache` snapshot reflects state BEFORE the batch — so a just-staged\n * upsert is invisible to the rescore scan. If you need rescore to include\n * the staged upsert, either call `rescore()` after the batch settles or\n * pass the new `baseScore` directly via `upsert(id, value, { score })`.\n *\n * **Audit no-op records.** Like `lightCollection`, mutations record audit\n * entries even when the impl was a no-op (e.g., `rescore()` on an empty\n * store). Intentional — the framework records attempts.\n *\n * @category memory\n */\nexport function collection<T>(name: string, opts: CollectionOptions<T> = {}): CollectionGraph<T> {\n\tconst maxSize = opts.maxSize;\n\tconst ranked = opts.ranked ?? true;\n\t// `decayRate` / `score` / `refreshIntervalMs` are no-ops when ranked is off\n\t// (they only feed the `ranked` derived). The audit + LRU paths still run.\n\tconst decayRate = ranked ? (opts.decayRate ?? 0) : 0;\n\tconst minScore = opts.minScore ?? 0;\n\tif (maxSize !== undefined && maxSize < 1) {\n\t\tthrow new RangeError(\"collection: maxSize must be >= 1\");\n\t}\n\n\t// Resolve score fn — supports static fn or reactive Node<fn>. When\n\t// `ranked: false` the score is constant `0` and `readScoreFn` is unused\n\t// (the upsert path takes the `_opts.score ?? readScoreFn()(value)` branch\n\t// only when ranking is requested).\n\tconst scoreFnDefault: CollectionScoreFn<T> = () => (ranked ? 1 : 0);\n\tconst scoreInput = opts.score ?? scoreFnDefault;\n\tconst scoreNode: Node<CollectionScoreFn<T>> | undefined =\n\t\tranked && scoreInput instanceof NodeImpl\n\t\t\t? (scoreInput as Node<CollectionScoreFn<T>>)\n\t\t\t: undefined;\n\tconst readScoreFn = (): CollectionScoreFn<T> => {\n\t\tif (scoreNode) return scoreNode.cache ?? scoreFnDefault;\n\t\treturn scoreInput as CollectionScoreFn<T>;\n\t};\n\n\tconst graph = new Graph(name);\n\n\t// Score-based retention scorer for `reactiveMap`. When unranked the base\n\t// score is `0`, so retention falls back to LRU-by-`lastAccessNs` (the\n\t// older the access, the lower the decayed score → first to evict).\n\tconst retentionScore = (_k: string, v: CollectionEntry<T>): number =>\n\t\tranked\n\t\t\t? decay(v.baseScore, ageSeconds(monotonicNs(), v.lastAccessNs), decayRate, minScore)\n\t\t\t: v.lastAccessNs;\n\n\tconst items = reactiveMap<string, CollectionEntry<T>>({\n\t\tname: \"items\",\n\t\t...(maxSize !== undefined ? { retention: { score: retentionScore, maxSize } } : {}),\n\t});\n\n\tgraph.add(items.entries, { name: \"items\" });\n\n\t// Refresh tick — only mounted when ranking + decay are configured. Tick\n\t// payload is `monotonicNs()`, so `rankedNode`'s fn is pure-of-deps and\n\t// dry-run-reproducible.\n\tlet refreshTick: Node<number> | undefined;\n\tif (ranked && decayRate > 0) {\n\t\tconst intervalMs = opts.refreshIntervalMs ?? Math.max(1, (1000 * Math.LN2) / (10 * decayRate));\n\t\tconst tickCounter = fromTimer(intervalMs, { period: intervalMs });\n\t\t// Map each tick to the wall-clock `monotonicNs` — the tick payload IS\n\t\t// the time stamp downstream consumers use. Reading the central clock\n\t\t// inside this fn is sanctioned: this derived's purpose is to publish\n\t\t// \"now\" reactively (cf. spec §5.11 — central timer), and downstream\n\t\t// `rankedNode` reads it from its dep array, never from the clock\n\t\t// directly.\n\t\t//\n\t\t// `initial: monotonicNs()` seeds the cache with construction-time\n\t\t// `now` so push-on-subscribe delivers DATA to `rankedNode` before the\n\t\t// first tick fires — without this, `rankedNode` would stall in pending\n\t\t// status until ~`refreshIntervalMs` after first activation, and a\n\t\t// caller reading `rankedNode.cache` immediately after `upsert` would\n\t\t// see `undefined`.\n\t\trefreshTick = node(\n\t\t\t[tickCounter],\n\t\t\t(_batchData, actions) => {\n\t\t\t\tactions.emit(monotonicNs());\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"refresh_tick_ns\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tinitial: monotonicNs(),\n\t\t\t\tmeta: memoryMeta(\"clock\"),\n\t\t\t},\n\t\t);\n\t\tgraph.add(refreshTick, { name: \"refresh_tick_ns\" });\n\t}\n\n\t// `rankedNode` derived — pure of (items, refreshTick?, scoreNode?). When\n\t// `ranked: false`, `rankedNode` is a static empty-array node so the\n\t// public type stays uniform without re-running the sort.\n\tlet rankedNode: Node<readonly RankedCollectionEntry<T>[]>;\n\tif (ranked) {\n\t\tconst rankedDeps: Node<unknown>[] = [items.entries];\n\t\tif (refreshTick) rankedDeps.push(refreshTick);\n\t\tif (scoreNode) rankedDeps.push(scoreNode);\n\t\trankedNode = node(\n\t\t\trankedDeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tlet now: number;\n\t\t\t\tif (refreshTick) {\n\t\t\t\t\tconst tickValue = values[1] as number | undefined;\n\t\t\t\t\tnow = typeof tickValue === \"number\" ? tickValue : monotonicNs();\n\t\t\t\t} else {\n\t\t\t\t\tnow = monotonicNs();\n\t\t\t\t}\n\t\t\t\tif (!snapshot || snapshot.size === 0) {\n\t\t\t\t\tactions.emit([] as readonly RankedCollectionEntry<T>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst out: RankedCollectionEntry<T>[] = [];\n\t\t\t\tfor (const entry of snapshot.values()) {\n\t\t\t\t\tout.push({\n\t\t\t\t\t\t...entry,\n\t\t\t\t\t\tscore: decay(entry.baseScore, ageSeconds(now, entry.lastAccessNs), decayRate, minScore),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tout.sort((a, b) => b.score - a.score || b.lastAccessNs - a.lastAccessNs);\n\t\t\t\tactions.emit(out as readonly RankedCollectionEntry<T>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"ranked\",\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: rankedEqual,\n\t\t\t\tmeta: memoryMeta(\"ranked\"),\n\t\t\t},\n\t\t) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t} else {\n\t\trankedNode = node<readonly RankedCollectionEntry<T>[]>([], {\n\t\t\tinitial: [] as readonly RankedCollectionEntry<T>[],\n\t\t\tname: \"ranked\",\n\t\t\tdescribeKind: \"state\",\n\t\t\tmeta: memoryMeta(\"ranked_disabled\"),\n\t\t}) as Node<readonly RankedCollectionEntry<T>[]>;\n\t\tgraph.add(rankedNode, { name: \"ranked\" });\n\t}\n\n\tconst size = node(\n\t\t[items.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\tactions.emit(((snapshot ?? new Map()) as ReadonlyMap<string, CollectionEntry<T>>).size);\n\t\t},\n\t\t{\n\t\t\tname: \"size\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: 0,\n\t\t\tmeta: memoryMeta(\"size\"),\n\t\t},\n\t);\n\tgraph.add(size, { name: \"size\" });\n\t// Keepalive only on `size` (cheap; pure of items). `ranked` is intentionally\n\t// lazy so the refresh timer doesn't fire when nothing consumes the ranking.\n\tgraph.addDisposer(keepalive(size));\n\n\t// Audit log + seq cursor.\n\tconst events = createAuditLog<CollectionAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst upsertImpl = (id: string, value: T, _opts?: { score?: number }): void => {\n\t\tconst now = monotonicNs();\n\t\tconst prev = items.get(id);\n\t\tconst baseScore = _opts?.score ?? readScoreFn()(value);\n\t\titems.set(id, {\n\t\t\tid,\n\t\t\tvalue,\n\t\t\tbaseScore,\n\t\t\tcreatedAtNs: prev?.createdAtNs ?? now,\n\t\t\tlastAccessNs: now,\n\t\t});\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!items.has(id)) return;\n\t\titems.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (items.size === 0) return;\n\t\titems.clear();\n\t};\n\tconst rescoreImpl = (): void => {\n\t\t// `ranked: false` short-circuit — there's no live `ranked` node to\n\t\t// re-derive and `baseScore` is held at its insertion-time value, so\n\t\t// rescore is a no-op. The audit record is still emitted so consumers\n\t\t// see the attempt.\n\t\tif (!ranked) return;\n\t\tconst fn = readScoreFn();\n\t\tconst snapshot = items.entries.cache as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\tif (!snapshot || snapshot.size === 0) return;\n\t\tconst updates: Array<[string, CollectionEntry<T>]> = [];\n\t\tfor (const entry of snapshot.values()) {\n\t\t\tupdates.push([entry.id, { ...entry, baseScore: fn(entry.value) }]);\n\t\t}\n\t\titems.setMany(updates);\n\t};\n\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst rescore = mutate(rescoreImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"rescore\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction itemNode(id: NodeOrValue<string>): Node<CollectionEntry<T> | undefined> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.get(key));\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_item\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tfunction hasNode(id: NodeOrValue<string>): Node<boolean> {\n\t\tconst idN = toNode(id, \"id\");\n\t\treturn node(\n\t\t\t[items.entries, idN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst map = data[0] as ReadonlyMap<string, CollectionEntry<T>> | undefined;\n\t\t\t\tconst key = data[1] as string;\n\t\t\t\tactions.emit(map?.has(key) ?? false);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: memoryMeta(\"collection_has\"),\n\t\t\t},\n\t\t);\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\titems: items.entries,\n\t\tranked: rankedNode,\n\t\tsize,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\trescore,\n\t\titemNode,\n\t\thasNode,\n\t}) as CollectionGraph<T>;\n\treturn out;\n}\n\n// ── Unit 4: vectorIndex ──────────────────────────────────────────────────\n\nexport type VectorBackend = \"flat\" | \"hnsw\";\n\nexport type VectorRecord<TMeta> = {\n\treadonly id: string;\n\treadonly vector: readonly number[];\n\treadonly meta?: TMeta;\n\t/** Wall-clock-monotonic timestamp at last upsert; used for the default LRU retention. */\n\treadonly upsertedAtNs: number;\n};\n\nexport type VectorSearchResult<TMeta> = {\n\treadonly id: string;\n\treadonly score: number;\n\treadonly meta?: TMeta;\n};\n\nexport type HnswAdapter<TMeta> = {\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\tsearch: (query: readonly number[], k: number) => ReadonlyArray<VectorSearchResult<TMeta>>;\n\t/** Optional adapter teardown. Called from `graph.destroy()` via `addDisposer`. */\n\tdispose?: () => void;\n};\n\nexport type VectorIndexOptions<TMeta> = {\n\tname?: string;\n\tbackend?: VectorBackend;\n\tdimension?: number;\n\t/**\n\t * Strict-dimension default. When `true` (default) AND `dimension` is unset,\n\t * mixed-length upserts throw `RangeError`. Set `false` to opt into the\n\t * lenient zero-padding behavior of {@link VectorIndexGraph.searchNode}.\n\t */\n\tstrictDimension?: boolean;\n\t/** Optional dependency seam for HNSW. */\n\thnswFactory?: () => HnswAdapter<TMeta>;\n\t/** Maximum live entries (LRU-by-upsert-time when set; user-overridable via `retentionScore`). */\n\tmaxSize?: number;\n\t/** Custom retention scorer. Higher score = kept. Defaults to `r => r.upsertedAtNs`. */\n\tretentionScore?: (record: VectorRecord<TMeta>) => number;\n};\n\nexport interface VectorIndexAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsert\" | \"remove\" | \"clear\" | \"reindex\" | \"evict\";\n\treadonly id?: string;\n}\n\nexport type VectorIndexGraph<TMeta> = Graph & {\n\treadonly backend: VectorBackend;\n\treadonly events: ReactiveLogBundle<VectorIndexAuditRecord>;\n\treadonly entries: Node<ReadonlyMap<string, VectorRecord<TMeta>>>;\n\tupsert: (id: string, vector: readonly number[], meta?: TMeta) => void;\n\tremove: (id: string) => void;\n\tclear: () => void;\n\t/** Re-push every live entry into the optional HNSW adapter. No-op for `flat`. */\n\treindex: () => void;\n\t/**\n\t * Reactive top-K search. Re-derives whenever entries / query / k change.\n\t * Lazy. Use `firstValueFrom(searchNode(...))` for one-shot reads.\n\t */\n\tsearchNode: (\n\t\tquery: Node<readonly number[]>,\n\t\tk?: NodeOrValue<number>,\n\t) => Node<readonly VectorSearchResult<TMeta>[]>;\n};\n\n/**\n * Reactive vector store with optional HNSW backend.\n *\n * **Storage on `reactiveMap`.** `entries` is a `reactiveMap<id, VectorRecord<TMeta>>`\n * with optional score-based retention (`maxSize` + LRU-by-`upsertedAtNs` by\n * default; user can supply a custom `retentionScore`). On retention eviction,\n * the HNSW adapter (if configured) is also notified via `adapter.remove(id)`.\n *\n * **Reactive search.** `searchNode(queryNode, k)` returns a `Node<readonly\n * VectorSearchResult<TMeta>[]>` that re-derives on entries / query / k change.\n * Lazy — only computes when subscribed. Imperative `search()` is intentionally\n * not exposed (no-imperative-reads policy). Use `firstValueFrom(searchNode(...))`\n * for one-shot reads.\n *\n * **Strict dimension.** Default `strictDimension: true` — if `dimension` is\n * unset and an upsert produces a vector of a different length than the first\n * upserted, throws `RangeError`. Pass `strictDimension: false` to opt into\n * the lenient zero-padding fallback (the previous default).\n *\n * **Adapter lifecycle.** When the HNSW adapter exposes a `dispose()` method,\n * it is bound to the graph's teardown via `addDisposer`. When retention\n * evicts an entry, `adapter.remove(id)` is invoked synchronously inside the\n * retention `onArchive` callback.\n *\n * **Cosine zero-pad.** The flat backend uses cosine similarity over the\n * pairwise max-length zero-pad. Mixing dimensions silently degrades scores\n * unless strict mode catches it at upsert time. For embedding-model vectors,\n * L2-normalize at the source — `vectorIndex` does not normalize.\n *\n * @category memory\n */\nexport function vectorIndex<TMeta>(opts: VectorIndexOptions<TMeta> = {}): VectorIndexGraph<TMeta> {\n\tconst backend = opts.backend ?? \"flat\";\n\tconst dimension = opts.dimension;\n\tconst strictDimension = opts.strictDimension ?? true;\n\tconst maxSize = opts.maxSize;\n\tconst userRetentionScore = opts.retentionScore;\n\n\tlet hnsw: HnswAdapter<TMeta> | undefined;\n\tif (backend === \"hnsw\") {\n\t\thnsw = opts.hnswFactory?.();\n\t\tif (!hnsw) {\n\t\t\tthrow new Error(\n\t\t\t\t'vectorIndex backend \"hnsw\" requires an optional dependency adapter; install your HNSW package and provide `hnswFactory`.',\n\t\t\t);\n\t\t}\n\t}\n\n\tconst graph = new Graph(opts.name ?? \"vector_index\");\n\n\t// Track an inferred dimension when the user didn't lock it but strict mode\n\t// is on — first upsert sets it; subsequent mismatches throw.\n\tlet inferredDimension: number | undefined;\n\tfunction assertDimension(vector: readonly number[]): void {\n\t\tif (dimension !== undefined) {\n\t\t\tif (vector.length !== dimension) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`vector dimension mismatch: expected ${dimension}, got ${vector.length}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!strictDimension) return;\n\t\tif (inferredDimension === undefined) {\n\t\t\tinferredDimension = vector.length;\n\t\t\treturn;\n\t\t}\n\t\tif (vector.length !== inferredDimension) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`vector dimension mismatch: inferred ${inferredDimension} from first upsert, got ${vector.length}. ` +\n\t\t\t\t\t`Pass \\`strictDimension: false\\` to opt into zero-pad behavior, or set an explicit \\`dimension\\`.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst baseRetentionScore = userRetentionScore ?? ((r: VectorRecord<TMeta>) => r.upsertedAtNs);\n\t// `clearInProgress` lets us short-circuit the per-entry `onArchive` →\n\t// `hnsw.remove(id)` cascade when the user calls `clearImpl()`. Retention\n\t// fires `onArchive` for every evicted entry; followed by an explicit\n\t// `hnsw.clear()` we'd double-touch the adapter. Inside `clearImpl` we\n\t// flip this flag, then call `hnsw.clear()` once at the end. (G fix.)\n\tlet clearInProgress = false;\n\n\t// `clearAuditPending` defers the per-entry `evict` audit emission when a\n\t// `clear()` is in flight — those evictions are reported as a single\n\t// `clear` action, not a flurry of `evict` records.\n\tconst events = createAuditLog<VectorIndexAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\tconst entries = reactiveMap<string, VectorRecord<TMeta>>({\n\t\tname: \"entries\",\n\t\t...(maxSize !== undefined\n\t\t\t? {\n\t\t\t\t\tretention: {\n\t\t\t\t\t\tscore: (_k, v) => baseRetentionScore(v),\n\t\t\t\t\t\tmaxSize,\n\t\t\t\t\t\tonArchive: (key) => {\n\t\t\t\t\t\t\tif (clearInProgress) return;\n\t\t\t\t\t\t\tif (backend === \"hnsw\") hnsw!.remove(key);\n\t\t\t\t\t\t\t// E1: surface retention-driven evictions in the audit log\n\t\t\t\t\t\t\t// so replay consumers can reconstruct the live snapshot\n\t\t\t\t\t\t\t// from `events` alone. `seq` is bumped via the cursor;\n\t\t\t\t\t\t\t// the `t_ns` matches `wallClockNs()` for consistency\n\t\t\t\t\t\t\t// with `lightMutation`'s record stamping.\n\t\t\t\t\t\t\tevents.append({\n\t\t\t\t\t\t\t\taction: \"evict\" as const,\n\t\t\t\t\t\t\t\tid: key,\n\t\t\t\t\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n\tgraph.add(entries.entries, { name: \"entries\" });\n\t// F1: keep `entries` warm so downstream consumers reading\n\t// `vectors.entries.cache` (e.g. `patterns/ai/memory/runRetrieval`) don't\n\t// rely on an external subscriber to activate the node. State nodes are\n\t// ROM and retain `.cache` regardless of subscribers — this `keepalive`\n\t// is defense-in-depth and matches the kg's adjacency keepalive pattern.\n\tgraph.addDisposer(keepalive(entries.entries));\n\n\t// HNSW dispose runs BEFORE state-node teardown via standard disposer\n\t// ordering (disposers drain first, then `[[TEARDOWN]]` propagates per\n\t// `Graph.destroy()`). This is the right ordering: free the adapter's\n\t// native resources before the reactive layer tears down.\n\tif (hnsw?.dispose) {\n\t\tconst disposeAdapter = hnsw.dispose.bind(hnsw);\n\t\tgraph.addDisposer(() => disposeAdapter());\n\t}\n\n\tconst upsertImpl = (id: string, vector: readonly number[], meta?: TMeta): void => {\n\t\tassertDimension(vector);\n\t\t// B1: mutate HNSW first so a throw aborts the reactive write. With\n\t\t// the prior order (entries.set then hnsw.upsert), an adapter throw\n\t\t// would leave entries holding a row HNSW didn't index. Now: HNSW\n\t\t// commits first; if it throws, entries is untouched and audit log\n\t\t// records the failure.\n\t\tif (backend === \"hnsw\") hnsw!.upsert(id, vector, meta);\n\t\t// Defensive copies: vector via `[...vector]`; meta via shallow spread\n\t\t// when it's a non-null object (Array.isArray covered first since arrays\n\t\t// are objects). Primitives, `null`, functions etc. pass through\n\t\t// unchanged. Documented depth limitation: nested objects in `meta` are\n\t\t// shared by reference.\n\t\tconst copiedMeta: TMeta | undefined = (() => {\n\t\t\tif (meta === undefined) return undefined;\n\t\t\tif (meta === null || typeof meta !== \"object\") return meta;\n\t\t\treturn Array.isArray(meta) ? ([...meta] as unknown as TMeta) : ({ ...meta } as TMeta);\n\t\t})();\n\t\tconst record: VectorRecord<TMeta> = {\n\t\t\tid,\n\t\t\tvector: [...vector],\n\t\t\t...(copiedMeta !== undefined ? { meta: copiedMeta } : {}),\n\t\t\tupsertedAtNs: monotonicNs(),\n\t\t};\n\t\tentries.set(id, record);\n\t};\n\tconst removeImpl = (id: string): void => {\n\t\tif (!entries.has(id)) return;\n\t\t// B1: HNSW first, then entries.\n\t\tif (backend === \"hnsw\") hnsw!.remove(id);\n\t\tentries.delete(id);\n\t};\n\tconst clearImpl = (): void => {\n\t\tif (entries.size === 0) return;\n\t\t// B1 + G: mark the clear-in-progress flag so retention `onArchive`\n\t\t// suppresses per-entry HNSW removes AND per-entry `evict` audit\n\t\t// records. Then call `entries.clear()` (drains the backend through\n\t\t// retention archival without side effects), and finally call\n\t\t// `hnsw.clear()` once. Reset `inferredDimension` so a fresh start\n\t\t// re-infers from the next upsert.\n\t\tclearInProgress = true;\n\t\ttry {\n\t\t\tentries.clear();\n\t\t\tif (backend === \"hnsw\") hnsw!.clear();\n\t\t} finally {\n\t\t\tclearInProgress = false;\n\t\t}\n\t\tinferredDimension = undefined;\n\t};\n\tconst reindexImpl = (): void => {\n\t\tif (backend !== \"hnsw\") return;\n\t\tconst snapshot = entries.entries.cache as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\tif (!snapshot) return;\n\t\thnsw!.clear();\n\t\tfor (const r of snapshot.values()) {\n\t\t\thnsw!.upsert(r.id, r.vector, r.meta);\n\t\t}\n\t};\n\n\t// `freeze: false` for `upsert` — deep-freezing a 768-dim vector is a\n\t// measurable hot-path tax, and the wrapper does its own defensive copy\n\t// (`vector: [...vector]`) before persisting. See §B.2 of the audit lock.\n\tconst upsert = mutate(upsertImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tfreeze: false,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"upsert\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst remove = mutate(removeImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({ action: \"remove\" as const, id, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst clear = mutate(clearImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"clear\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\tconst reindex = mutate(reindexImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: (_args, _r, m) => ({ action: \"reindex\" as const, t_ns: m.t_ns, seq: m.seq }),\n\t});\n\n\tfunction searchNode(\n\t\tquery: Node<readonly number[]>,\n\t\tk: NodeOrValue<number> = 5,\n\t): Node<readonly VectorSearchResult<TMeta>[]> {\n\t\tconst kN = toNode<number>(k, \"k\");\n\t\treturn node(\n\t\t\t[entries.entries, query, kN],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst snapshot = values[0] as ReadonlyMap<string, VectorRecord<TMeta>> | undefined;\n\t\t\t\tconst q = values[1] as readonly number[] | undefined;\n\t\t\t\tconst kRaw = values[2] as number;\n\t\t\t\t// Auto-fix: `Math.max(0, Math.floor(k))` — `| 0` is a 32-bit\n\t\t\t\t// signed truncation that collapses Infinity to 0 and wraps\n\t\t\t\t// values > 2^31. Use a proper floor with a non-negative floor.\n\t\t\t\tconst kVal = Number.isFinite(kRaw) ? Math.max(0, Math.floor(kRaw)) : 0;\n\t\t\t\tif (!snapshot || snapshot.size === 0 || kVal <= 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Auto-fix: defensive guard for unset / empty query — earlier\n\t\t\t\t// the fn would TypeError on `q.length` reading `undefined`,\n\t\t\t\t// or compute meaningless all-zero scores against an empty\n\t\t\t\t// vector. With strict-dimension OR an explicit `dimension`,\n\t\t\t\t// also reject mismatched-length queries (the imperative path\n\t\t\t\t// used to throw; reactive deriveds shouldn't throw, so\n\t\t\t\t// degrade to empty results).\n\t\t\t\tif (q == null || q.length === 0) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst expectedDim = dimension ?? (strictDimension ? inferredDimension : undefined);\n\t\t\t\tif (expectedDim !== undefined && q.length !== expectedDim) {\n\t\t\t\t\tactions.emit([] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (backend === \"hnsw\") {\n\t\t\t\t\t// Defensive copy of the adapter's return — HNSW libs\n\t\t\t\t\t// sometimes hand back internal buffers; downstream\n\t\t\t\t\t// subscribers must not be able to corrupt adapter state.\n\t\t\t\t\tconst adapterResults = hnsw!.search(q, kVal);\n\t\t\t\t\tactions.emit([...adapterResults] as readonly VectorSearchResult<TMeta>[]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst ranked = [...snapshot.values()]\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst result: VectorSearchResult<TMeta> = {\n\t\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\t\tscore: cosineSimilarity(q, row.vector),\n\t\t\t\t\t\t\t...(row.meta !== undefined ? { meta: row.meta } : {}),\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t})\n\t\t\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t\t\t.slice(0, kVal);\n\t\t\t\tactions.emit(ranked as readonly VectorSearchResult<TMeta>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t// A1: include `score` in equality. The previous id-only\n\t\t\t\t// comparator suppressed re-emissions when the same set of\n\t\t\t\t// IDs/order had different scores (re-upsert with new\n\t\t\t\t// vector; query change preserving ranking order).\n\t\t\t\tequals: (a, b) => searchResultsEqual(a, b),\n\t\t\t\tmeta: memoryMeta(\"vector_search\"),\n\t\t\t},\n\t\t) as Node<readonly VectorSearchResult<TMeta>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tbackend,\n\t\tevents,\n\t\tentries: entries.entries,\n\t\tupsert,\n\t\tremove,\n\t\tclear,\n\t\treindex,\n\t\tsearchNode,\n\t}) as VectorIndexGraph<TMeta>;\n\treturn out;\n}\n\n// ── Unit 5: knowledgeGraph ───────────────────────────────────────────────\n\nexport type KnowledgeEdge<TRelation extends string = string> = {\n\treadonly from: string;\n\treadonly to: string;\n\treadonly relation: TRelation;\n\treadonly weight: number;\n};\n\nexport type KnowledgeGraphOptions = {\n\t/** Cap on entity count (LRU-by-upsert-time when set). */\n\tentitiesMaxSize?: number;\n\t/** Cap on edge count (LRU-by-upsert-time when set). */\n\tedgesMaxSize?: number;\n\t/**\n\t * Orphan-entity garbage collection. `\"keep\"` (default) leaves entities\n\t * untouched when their last edge is unlinked; `\"remove\"` deletes the\n\t * entity post-`unlink` if no edges reference it.\n\t */\n\torphanGC?: \"keep\" | \"remove\";\n};\n\nexport interface KnowledgeGraphAuditRecord extends BaseAuditRecord {\n\treadonly action: \"upsertEntity\" | \"removeEntity\" | \"link\" | \"unlink\" | \"orphanRemove\";\n\treadonly id?: string;\n\treadonly from?: string;\n\treadonly to?: string;\n\treadonly relation?: string;\n\t/** Edge weight at the time of the `link`. Omitted for non-edge actions. */\n\treadonly weight?: number;\n}\n\nexport type KnowledgeGraph<TEntity, TRelation extends string = string> = Graph & {\n\treadonly events: ReactiveLogBundle<KnowledgeGraphAuditRecord>;\n\treadonly entities: Node<ReadonlyMap<string, TEntity>>;\n\treadonly edges: Node<ReadonlyMap<string, KnowledgeEdge<TRelation>>>;\n\treadonly adjacencyOut: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly adjacencyIn: Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\treadonly entityCount: Node<number>;\n\treadonly edgeCount: Node<number>;\n\tupsertEntity: (id: string, value: TEntity) => void;\n\tremoveEntity: (id: string) => void;\n\tlink: (from: string, to: string, relation: TRelation, weight?: number) => void;\n\tunlink: (from: string, to: string, relation?: TRelation) => void;\n\trelatedNode: (\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t) => Node<readonly KnowledgeEdge<TRelation>[]>;\n};\n\nconst TRIPLE_SEP = \"\u0000\";\nfunction tripleKey(from: string, to: string, relation: string): string {\n\treturn `${from}${TRIPLE_SEP}${to}${TRIPLE_SEP}${relation}`;\n}\n\nfunction buildAdjacency<TRelation extends string>(\n\tedges: ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined,\n\tside: \"from\" | \"to\",\n): ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> {\n\tif (!edges || edges.size === 0) return new Map();\n\tconst buckets = new Map<string, KnowledgeEdge<TRelation>[]>();\n\tfor (const edge of edges.values()) {\n\t\tconst key = side === \"from\" ? edge.from : edge.to;\n\t\tlet bucket = buckets.get(key);\n\t\tif (!bucket) {\n\t\t\tbucket = [];\n\t\t\tbuckets.set(key, bucket);\n\t\t}\n\t\tbucket.push(edge);\n\t}\n\tconst out = new Map<string, readonly KnowledgeEdge<TRelation>[]>();\n\tfor (const [key, bucket] of buckets) out.set(key, Object.freeze(bucket));\n\treturn out;\n}\n\nfunction adjacencyEqual<TRelation extends string>(\n\ta: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n\tb: ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]> | undefined,\n): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\tif (a.size !== b.size) return false;\n\tfor (const [k, av] of a) {\n\t\tconst bv = b.get(k);\n\t\tif (!bv || av.length !== bv.length) return false;\n\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\tconst ae = av[i]!;\n\t\t\tconst be = bv[i]!;\n\t\t\tif (\n\t\t\t\tae.from !== be.from ||\n\t\t\t\tae.to !== be.to ||\n\t\t\t\tae.relation !== be.relation ||\n\t\t\t\tae.weight !== be.weight\n\t\t\t)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Reactive knowledge graph: entities + typed edges + symmetric adjacency.\n *\n * Topology (mounted on the returned graph):\n * - `entities` — `reactiveMap<id, TEntity>` (optional `entitiesMaxSize` LRU).\n * - `edges` — `reactiveMap<tripleKey, KnowledgeEdge<TRelation>>` keyed by\n * `${from}\u0000${to}\u0000${relation}` (optional `edgesMaxSize` LRU).\n * Entity IDs / relations must NOT contain `\u0000`.\n * - `adjacencyOut` — `Node<ReadonlyMap<from, readonly edge[]>>`. **Full O(E)\n * rebuild on every `link` / `unlink` mutation.** (Prior JSDoc claim of\n * \"O(E) build\" referred to a single rebuild — the per-mutation cost is\n * O(E), not O(1) amortized. For very large graphs with frequent edge\n * churn, consider batching via `reactiveMap.setMany`.)\n * - `adjacencyIn` — `Node<ReadonlyMap<to, readonly edge[]>>`. Same O(E) per\n * mutation rebuild characteristic.\n * - `entityCount` / `edgeCount` — observability deriveds.\n * - `events` — bounded reactive audit log.\n *\n * **`link()` semantics.** Calling `link(a, b, rel, w)` twice with different\n * weights replaces the weight on the existing edge (keyed by the triple).\n * `unlink` then `link` re-creates the edge (and bumps `lastUpsertNs` for\n * retention purposes).\n *\n * **Edge weight convention.** Higher weight = stronger relation. Default `1`.\n *\n * **Orphan GC.** `orphanGC: \"remove\"` deletes an entity from `entities` after\n * an `unlink` that empties its adjacency on both sides. Default `\"keep\"`.\n *\n * **No imperative reads.** Use `relatedNode(id, relation?)` for reactive reads.\n *\n * @category memory\n */\nexport function knowledgeGraph<TEntity, TRelation extends string = string>(\n\tname: string,\n\topts: KnowledgeGraphOptions = {},\n): KnowledgeGraph<TEntity, TRelation> {\n\tconst orphanGC = opts.orphanGC ?? \"keep\";\n\tif (opts.entitiesMaxSize !== undefined && opts.entitiesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: entitiesMaxSize must be >= 1\");\n\t}\n\tif (opts.edgesMaxSize !== undefined && opts.edgesMaxSize < 1) {\n\t\tthrow new RangeError(\"knowledgeGraph: edgesMaxSize must be >= 1\");\n\t}\n\n\tconst graph = new Graph(name);\n\n\tconst entitiesMap = reactiveMap<string, TEntity>({\n\t\tname: \"entities\",\n\t\t...(opts.entitiesMaxSize !== undefined ? { maxSize: opts.entitiesMaxSize } : {}),\n\t});\n\tconst edgesMap = reactiveMap<string, KnowledgeEdge<TRelation>>({\n\t\tname: \"edges\",\n\t\t...(opts.edgesMaxSize !== undefined ? { maxSize: opts.edgesMaxSize } : {}),\n\t});\n\tgraph.add(entitiesMap.entries, { name: \"entities\" });\n\tgraph.add(edgesMap.entries, { name: \"edges\" });\n\n\tconst adjacencyOut = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"from\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyOut\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_out\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tconst adjacencyIn = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(buildAdjacency<TRelation>(snapshot, \"to\"));\n\t\t},\n\t\t{\n\t\t\tname: \"adjacencyIn\",\n\t\t\tdescribeKind: \"derived\",\n\t\t\tinitial: new Map() as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>,\n\t\t\tequals: adjacencyEqual,\n\t\t\tmeta: memoryMeta(\"adjacency_in\"),\n\t\t},\n\t) as Node<ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>>;\n\tgraph.add(adjacencyOut, { name: \"adjacencyOut\" });\n\tgraph.add(adjacencyIn, { name: \"adjacencyIn\" });\n\tgraph.addDisposer(keepalive(adjacencyOut));\n\tgraph.addDisposer(keepalive(adjacencyIn));\n\n\tconst entityCount = node(\n\t\t[entitiesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, TEntity> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, TEntity>).size);\n\t\t},\n\t\t{ name: \"entityCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"entity_count\") },\n\t);\n\tconst edgeCount = node(\n\t\t[edgesMap.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst m = data[0] as ReadonlyMap<string, KnowledgeEdge<TRelation>> | undefined;\n\t\t\tactions.emit(((m ?? new Map()) as ReadonlyMap<string, KnowledgeEdge<TRelation>>).size);\n\t\t},\n\t\t{ name: \"edgeCount\", describeKind: \"derived\", initial: 0, meta: memoryMeta(\"edge_count\") },\n\t);\n\tgraph.add(entityCount, { name: \"entityCount\" });\n\tgraph.add(edgeCount, { name: \"edgeCount\" });\n\tgraph.addDisposer(keepalive(entityCount));\n\tgraph.addDisposer(keepalive(edgeCount));\n\n\tconst events = createAuditLog<KnowledgeGraphAuditRecord>({\n\t\tname: \"events\",\n\t\tretainedLimit: 1024,\n\t\tgraph,\n\t});\n\tconst seqCursor = registerCursor(graph, \"seq\", 0);\n\n\t/**\n\t * O(1) orphan check via the kept-warm `adjacency*` deriveds. Reading\n\t * `adjacencyOut.cache` / `adjacencyIn.cache` is safe here because both\n\t * are activated via `addDisposer(keepalive(...))` at construction time\n\t * (a derived's RAM cache only persists with at least one subscriber, and\n\t * the keepalive registers exactly that). The previous implementation\n\t * scanned `edgesMap.entries.cache` post-`deleteMany`, which depended on\n\t * the (sync) snapshot-emit timing of `reactiveMap` — fragile. The\n\t * `adjacency*.cache` approach is both faster (O(1) vs O(E) per check)\n\t * and timing-robust because the reactiveMap snapshot has already\n\t * propagated through the derived chain by the time we read.\n\t */\n\tfunction entityHasReferences(id: string): boolean {\n\t\tconst out = adjacencyOut.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tconst inb = adjacencyIn.cache as\n\t\t\t| ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>\n\t\t\t| undefined;\n\t\tif ((out?.get(id)?.length ?? 0) > 0) return true;\n\t\tif ((inb?.get(id)?.length ?? 0) > 0) return true;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Apply orphan GC to a list of candidate entity ids. Used by both\n\t * {@link unlinkImpl} (post-edge-removal) and {@link removeEntityImpl}\n\t * (post-cascade) so semantics are consistent. Each removed entity\n\t * records a separate `orphanRemove` audit entry with its own monotonic\n\t * `seq` value (D1 fix — the previous bare `events.append(...)` skipped\n\t * the cursor advance, leaving gaps in the audit replay sequence).\n\t */\n\tfunction applyOrphanGC(candidates: readonly string[]): void {\n\t\tif (orphanGC !== \"remove\") return;\n\t\tfor (const candidate of candidates) {\n\t\t\tif (!entitiesMap.has(candidate)) continue;\n\t\t\tif (entityHasReferences(candidate)) continue;\n\t\t\tentitiesMap.delete(candidate);\n\t\t\tevents.append({\n\t\t\t\taction: \"orphanRemove\" as const,\n\t\t\t\tid: candidate,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\tseq: bumpCursor(seqCursor),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst upsertEntityImpl = (id: string, value: TEntity): void => {\n\t\tentitiesMap.set(id, value);\n\t};\n\tconst removeEntityImpl = (id: string): void => {\n\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t| undefined;\n\t\t// Collect both the edge-keys to drop AND the entity ids those edges\n\t\t// reference (other than `id` itself) — the latter become orphan-GC\n\t\t// candidates after the cascade. (C1 fix — the previous impl only\n\t\t// applied orphan GC inside `unlink`, so cascading entity removal\n\t\t// could leave dangling orphans.)\n\t\tconst cascadedNeighbors = new Set<string>();\n\t\tif (snapshot) {\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === id || edge.to === id) {\n\t\t\t\t\ttoDrop.push(key);\n\t\t\t\t\tif (edge.from !== id) cascadedNeighbors.add(edge.from);\n\t\t\t\t\tif (edge.to !== id) cascadedNeighbors.add(edge.to);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tif (entitiesMap.has(id)) entitiesMap.delete(id);\n\t\tapplyOrphanGC([...cascadedNeighbors]);\n\t};\n\tconst linkImpl = (from: string, to: string, relation: TRelation, weight = 1): void => {\n\t\tedgesMap.set(tripleKey(from, to, relation), { from, to, relation, weight });\n\t};\n\tconst unlinkImpl = (from: string, to: string, relation?: TRelation): void => {\n\t\tif (relation !== undefined) {\n\t\t\tedgesMap.delete(tripleKey(from, to, relation));\n\t\t} else {\n\t\t\tconst snapshot = edgesMap.entries.cache as\n\t\t\t\t| ReadonlyMap<string, KnowledgeEdge<TRelation>>\n\t\t\t\t| undefined;\n\t\t\tif (!snapshot) return;\n\t\t\tconst toDrop: string[] = [];\n\t\t\tfor (const [key, edge] of snapshot) {\n\t\t\t\tif (edge.from === from && edge.to === to) toDrop.push(key);\n\t\t\t}\n\t\t\tif (toDrop.length > 0) edgesMap.deleteMany(toDrop);\n\t\t}\n\t\tapplyOrphanGC([from, to]);\n\t};\n\n\tconst upsertEntity = mutate(upsertEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"upsertEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst removeEntity = mutate(removeEntityImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([id], _r, m) => ({\n\t\t\taction: \"removeEntity\" as const,\n\t\t\tid,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst link = mutate(linkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation, weight], _r, m) => ({\n\t\t\taction: \"link\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\trelation: relation as string,\n\t\t\tweight: weight ?? 1,\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\tconst unlink = mutate(unlinkImpl, {\n\t\tframe: \"inline\",\n\t\tlog: events,\n\t\tseq: seqCursor,\n\t\tonSuccessRecord: ([from, to, relation], _r, m) => ({\n\t\t\taction: \"unlink\" as const,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\t...(relation !== undefined ? { relation: relation as string } : {}),\n\t\t\tt_ns: m.t_ns,\n\t\t\tseq: m.seq,\n\t\t}),\n\t});\n\n\tfunction relatedNode(\n\t\tid: NodeOrValue<string>,\n\t\trelation?: NodeOrValue<TRelation>,\n\t): Node<readonly KnowledgeEdge<TRelation>[]> {\n\t\tconst idN = toNode(id, \"id\");\n\t\t// `relation` is OPTIONAL. We deliberately do NOT include it as a dep\n\t\t// when omitted — `state(undefined)` would be a SENTINEL and the\n\t\t// derived's first-run gate would never open. Callers pass a Node\n\t\t// when they want reactive filtering; pass a value to lock the\n\t\t// filter; omit to disable filtering.\n\t\tconst relN = relation !== undefined ? toNode(relation, \"relation\") : undefined;\n\t\tconst deps: Node<unknown>[] = relN\n\t\t\t? [adjacencyOut, adjacencyIn, idN, relN]\n\t\t\t: [adjacencyOut, adjacencyIn, idN];\n\t\treturn node(\n\t\t\tdeps,\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst values = batchData.map((batch, i) =>\n\t\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t\t);\n\t\t\t\tconst out = values[0] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst inb = values[1] as ReadonlyMap<string, readonly KnowledgeEdge<TRelation>[]>;\n\t\t\t\tconst key = values[2] as string;\n\t\t\t\tconst rel = relN ? (values[3] as TRelation | undefined) : undefined;\n\t\t\t\tconst outE = out?.get(key) ?? [];\n\t\t\t\tconst inE = inb?.get(key) ?? [];\n\t\t\t\t// Concatenate, then dedupe by triple key (a self-loop would appear in both).\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst acc: KnowledgeEdge<TRelation>[] = [];\n\t\t\t\tfor (const edge of outE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tfor (const edge of inE) {\n\t\t\t\t\tconst k = tripleKey(edge.from, edge.to, edge.relation);\n\t\t\t\t\tif (seen.has(k)) continue;\n\t\t\t\t\tif (rel !== undefined && edge.relation !== rel) continue;\n\t\t\t\t\tseen.add(k);\n\t\t\t\t\tacc.push(edge);\n\t\t\t\t}\n\t\t\t\tactions.emit(acc as readonly KnowledgeEdge<TRelation>[]);\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tequals: (a, b) => {\n\t\t\t\t\tconst av = a as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tconst bv = b as readonly KnowledgeEdge<TRelation>[] | undefined;\n\t\t\t\t\tif (av === bv) return true;\n\t\t\t\t\tif (av == null || bv == null) return false;\n\t\t\t\t\tif (av.length !== bv.length) return false;\n\t\t\t\t\tfor (let i = 0; i < av.length; i += 1) {\n\t\t\t\t\t\tconst x = av[i]!;\n\t\t\t\t\t\tconst y = bv[i]!;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tx.from !== y.from ||\n\t\t\t\t\t\t\tx.to !== y.to ||\n\t\t\t\t\t\t\tx.relation !== y.relation ||\n\t\t\t\t\t\t\tx.weight !== y.weight\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tmeta: memoryMeta(\"related\"),\n\t\t\t},\n\t\t) as Node<readonly KnowledgeEdge<TRelation>[]>;\n\t}\n\n\tconst out = Object.assign(graph, {\n\t\tevents,\n\t\tentities: entitiesMap.entries,\n\t\tedges: edgesMap.entries,\n\t\tadjacencyOut,\n\t\tadjacencyIn,\n\t\tentityCount,\n\t\tedgeCount,\n\t\tupsertEntity,\n\t\tremoveEntity,\n\t\tlink,\n\t\tunlink,\n\t\trelatedNode,\n\t}) as KnowledgeGraph<TEntity, TRelation>;\n\treturn out;\n}\n\n// ── DS-14.7: reactiveFactStore (static-topology MEME L2/L3 substrate) ─────\n// Lives in its own file (`fact-store.ts`) — re-exported here so the\n// `utils/memory` barrel stays the single import surface alongside\n// collection / vectorIndex / knowledgeGraph.\nexport {\n\ttype AdmissionFilter,\n\ttype CascadeEvent,\n\ttype CascadeOverflow,\n\ttype CascadeReason,\n\ttype DecayPolicy,\n\ttype DependentsIndex,\n\ttype FactId,\n\ttype FactStore,\n\ttype FactStoreAuditRecord,\n\ttype MemoryAnswer,\n\ttype MemoryFragment,\n\ttype MemoryQuery,\n\ttype OutcomeSignal,\n\ttype ReactiveFactStoreConfig,\n\tReactiveFactStoreGraph,\n\ttype ReviewRequest,\n\treactiveFactStore,\n\ttype ScoringPolicy,\n\ttype ShardKey,\n\ttype StoreReadHandle,\n} from \"./fact-store.js\";\n// DS-14.7 follow-up #2 (persistence half) — durable, event-sourced fact store\n// with substrate-owned replay/dedup (memo:Re Story 6.4 back-derivation).\nexport {\n\ttype PersistentReactiveFactStoreConfig,\n\ttype PersistentReactiveFactStoreGraph,\n\tpersistentReactiveFactStore,\n} from \"./persistent-fact-store.js\";\n// DS-14.7 follow-up #1: recipe library — 8 shipped compositions over the\n// four extension faces. Re-exported here so `utils/memory` stays the single\n// import surface.\nexport * from \"./recipes/index.js\";\n// DS-14.7 follow-up #2 — `simpleFactStore()` 80%-case ergonomic wrapper:\n// one-call `remember`, optional storage, decay-on-by-default.\nexport {\n\tDEFAULT_DECAY_HALF_LIFE_NS,\n\tDEFAULT_DECAY_PERIOD_MS,\n\ttype RememberOptions,\n\ttype SimpleFactStoreGraph,\n\ttype SimpleFactStoreOptions,\n\tsimpleFactStore,\n} from \"./simple-fact-store.js\";\n","// ---------------------------------------------------------------------------\n// promptCall — public single-shot LLM JSON helper (Tier 4.6 Wave AM Unit 4\n// promotion from the previously-internal `llmJsonCall` in\n// `patterns/ai/memory/llm-memory.ts`).\n//\n// Wraps {@link promptNode} for the common \"one-shot LLM JSON call per input\"\n// shape: a per-call `node([], { initial: input })` is wrapped, the prompt builder runs against\n// it, and the returned `NodeInput<TOut>` slots into reactive callbacks like\n// `distill`'s `extractFn` / `consolidateFn`. Inherits markdown-fence stripping\n// and content-preview parse errors from `promptNode({format: \"json\"})`.\n//\n// `llmExtractor` / `llmConsolidator` are now thin wrappers over `promptCall`.\n// ---------------------------------------------------------------------------\n\nimport { node } from \"@graphrefly/pure-ts/core\";\nimport type { NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport type { Extraction } from \"../../../base/composition/distill.js\";\nimport type { LLMAdapter } from \"../adapters/core/types.js\";\nimport { promptNode } from \"./prompt-node.js\";\n\n/** Options accepted by {@link promptCall}, {@link llmExtractor}, and {@link llmConsolidator}. */\nexport type PromptCallOptions = {\n\tadapter: LLMAdapter;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Optional name forwarded to the underlying `promptNode` (used as the\n\t * `<name>::messages` / `<name>::response` / `<name>::output` path prefix).\n\t * Defaults differ per call site so multiple `promptCall`s wired into the\n\t * same graph don't collide on `prompt_node::output`.\n\t */\n\tname?: string;\n};\n\n/**\n * Build a one-shot LLM JSON-call factory: each invocation wraps `input` in a\n * fresh `node([], { initial: input })`, delegates to `promptNode({format: \"json\"})`, and\n * returns a `NodeInput<TOut>` that the caller plugs into `distill` /\n * `agentLoop` / any reactive composition that accepts `NodeInput`.\n *\n * **Per-call lifecycle.** The returned `NodeInput<TOut>` is a producer that\n * emits exactly one `DATA` per upstream input (per Tier 1.2 Session C lock —\n * `promptNode` guarantees one DATA per wave). When the consumer's switchMap\n * supersedes it, the per-call `node([], { initial: input })` and the inner `prompt_node::response`\n * tear down together.\n *\n * @param systemPrompt - System message sent on every call.\n * @param buildUserContent - Per-input user-content builder (must be JSON-stringifiable).\n * @param opts - Adapter + model/temperature/maxTokens + optional name prefix.\n * @param defaultName - Path-prefix fallback when `opts.name` is omitted.\n * @returns Factory `(input: TIn) => NodeInput<TOut>`.\n *\n * @category patterns\n */\nexport function promptCall<TIn, TOut>(\n\tsystemPrompt: string,\n\tbuildUserContent: (input: TIn) => string,\n\topts: PromptCallOptions,\n\tdefaultName: string,\n): (input: TIn) => NodeInput<TOut> {\n\tconst name = opts.name ?? defaultName;\n\treturn (input: TIn) => {\n\t\t// One-shot node([], { initial: input }) per call — switchMap teardown inside the\n\t\t// consumer (e.g. distill) reclaims the node when the next upstream\n\t\t// arrives or the bundle disposes.\n\t\tconst inputState = node<TIn>([], { initial: input });\n\t\treturn promptNode<TOut>(\n\t\t\topts.adapter,\n\t\t\t[inputState as never],\n\t\t\t(value: unknown) => buildUserContent(value as TIn),\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tformat: \"json\",\n\t\t\t\tsystemPrompt,\n\t\t\t\tmodel: opts.model,\n\t\t\t\ttemperature: opts.temperature ?? 0,\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t},\n\t\t) as NodeInput<TOut>;\n\t};\n}\n\n/** Options accepted by {@link llmExtractor} and {@link llmConsolidator}. */\nexport type LLMExtractorOptions = PromptCallOptions & {\n\t/**\n\t * Cap the dedup-hint slice of `existingKeys` passed to the LLM. Larger\n\t * stores ship more keys (better dedup recall) at the cost of prompt size.\n\t * Default 100. Set to `Infinity` to forward every key.\n\t */\n\tmaxExistingKeys?: number;\n};\n\n/** Alias for backward compatibility. */\nexport type LLMConsolidatorOptions = LLMExtractorOptions;\n\n/**\n * Returns an `extractFn` callback for `distill()` that invokes an LLM to\n * extract structured memories from raw input.\n *\n * The system prompt should instruct the LLM to return JSON matching\n * `Extraction<TMem>` shape: `{ upsert: [{ key, value }], remove?: [key] }`.\n *\n * Built on `promptNode({format: \"json\"})` — inherits markdown-fence stripping\n * and content-preview parse errors. Stack `withRetry` on the adapter for\n * transient-error tolerance (see `patterns/ai/adapters/middleware/retry.ts`).\n */\nexport function llmExtractor<TRaw, TMem>(\n\tsystemPrompt: string,\n\topts: LLMExtractorOptions,\n): (raw: TRaw, existing: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\tconst cap = opts.maxExistingKeys ?? 100;\n\tconst call = promptCall<{ raw: TRaw; existingKeys: string[] }, Extraction<TMem>>(\n\t\tsystemPrompt,\n\t\t(input) => JSON.stringify({ input: input.raw, existingKeys: input.existingKeys }),\n\t\topts,\n\t\t\"llmExtractor\",\n\t);\n\treturn (raw: TRaw, existing: ReadonlyMap<string, TMem>) => {\n\t\tconst existingKeys =\n\t\t\tcap === Number.POSITIVE_INFINITY ? [...existing.keys()] : [...existing.keys()].slice(0, cap);\n\t\treturn call({ raw, existingKeys });\n\t};\n}\n\n/**\n * Returns a `consolidateFn` callback for `distill()` that invokes an LLM to\n * cluster and merge related memories.\n */\nexport function llmConsolidator<TMem>(\n\tsystemPrompt: string,\n\topts: LLMConsolidatorOptions,\n): (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>> {\n\tconst call = promptCall<readonly { key: string; value: TMem }[], Extraction<TMem>>(\n\t\tsystemPrompt,\n\t\t(memories) => JSON.stringify({ memories }),\n\t\topts,\n\t\t\"llmConsolidator\",\n\t);\n\treturn (entries: ReadonlyMap<string, TMem>) => {\n\t\tconst memories = [...entries.entries()].map(([key, value]) => ({ key, value }));\n\t\treturn call(memories);\n\t};\n}\n","/**\n * `promptNode` — universal LLM transform as a reactive derived node.\n *\n * The shape: `deps → messagesNode (derived) → switchMap → response (producer) → output`.\n * Each upstream wave is one LLM call; superseding waves cancel the in-flight\n * call via the abort signal threaded through `nodeSignal(opts.abort)`.\n *\n * The producer-shape on the inner is load-bearing: it emits exactly one DATA\n * + COMPLETE per wave, so the outer switchMap sees one DATA per wave (matches\n * the `HarnessExecutor` contract). A `node([response], (batchData, actions, ctx) => {\n * const data = ...; actions.emit(parse(data[0]));\n * }, { describeKind: \"derived\" })` would have its\n * own first-run / push-on-subscribe semantics that can leak a transient null\n * before the real response arrives — observed and reverted in an earlier\n * attempt; see SESSION-ai-harness-module-review.md line 3654 for context.\n * Locked as path (b) producer-based by Session C (2026-04-27); inner-node\n * naming aligned to `prompt_node::response` per the C+D widening (2026-04-30).\n *\n * **Retry / replay-cache.** Stack middleware on the adapter:\n *\n * ```ts\n * import { withRetry, withReplayCache } from \"@graphrefly/graphrefly/utils/ai\";\n *\n * const adapter = withRetry(\n * withReplayCache(baseAdapter, { keyFn: (ctx) => ctx.messages[0].content }),\n * { count: 3, backoff: 200 },\n * );\n * const result = promptNode(adapter, [input], (q) => q);\n * ```\n *\n * `promptNode` no longer ships `retries` / `cache` options — they duplicated\n * middleware already at the adapter layer.\n *\n * **Cross-wave cache (COMPOSITION-GUIDE §32).** The switchMap output cache\n * survives across new outer DATAs — `promptNode`'s cached value persists\n * until the next wave fully resolves. Consumers that need to distinguish\n * \"fresh value for THIS session\" from \"stale cache from a prior session\"\n * (e.g. `agentLoop` resetting on new `run()`) must add a `node([])` mirror\n * at their session boundary and depend on the mirror, not the `promptNode`\n * output directly. `promptNode` itself stays primitive — it does not\n * embed a state-mirror.\n *\n * @module\n */\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { nodeSignal } from \"../../../base/sources/settled.js\";\nimport { aiMeta, stripFences } from \"../_internal.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMInvokeOptions,\n\tLLMResponse,\n\tToolDefinition,\n} from \"../adapters/core/types.js\";\n\nexport type PromptNodeOptions = {\n\tname?: string;\n\tmodel?: string;\n\ttemperature?: number;\n\tmaxTokens?: number;\n\t/**\n\t * Output format:\n\t * - `\"text\"` (default) — emit the response content as a string.\n\t * - `\"json\"` — `JSON.parse` the content (markdown fences stripped).\n\t * - `\"raw\"` — emit the full {@link LLMResponse} object (subsumes the\n\t * pre-Tier-2.3 `fromLLM` shape; use this when you need `usage` /\n\t * `toolCalls` / `finishReason` alongside `content`).\n\t */\n\tformat?: \"text\" | \"json\" | \"raw\";\n\t/**\n\t * Reactive tool definitions forwarded to the adapter. Pair with\n\t * `format: \"raw\"` (or read `toolCalls` from a downstream parser) when\n\t * tool-calling is in scope.\n\t *\n\t * **Reactive declared edge** (DF12, Tier 7): `tools` is a `Node` so the\n\t * tools list participates in `describe()` topology and `explain()` causal\n\t * chains. The tools Node is added to `messagesNode`'s declared deps —\n\t * tools changes re-invoke the LLM (treated as a new call envelope).\n\t * Wrap with `distinctUntilChanged` upstream if your tool selector emits\n\t * noisy duplicates that would otherwise spam the adapter. See\n\t * COMPOSITION-GUIDE §31 (Dynamic tool selection) for the canonical\n\t * `toolSelector` pattern that produces this Node.\n\t *\n\t * **Activation note:** since `tools` is a real declared dep, `messagesNode`\n\t * waits for the tools Node to DATA at least once before firing\n\t * (push-on-subscribe SENTINEL gate). Pass a `node<ToolDefinition[]>([], { initial: [] })`\n\t * if you want immediate activation with no tools, or the latest published\n\t * `toolSelector.tools` Node.\n\t */\n\ttools?: Node<readonly ToolDefinition[]>;\n\t/**\n\t * Optional system prompt. Forwarded via `opts.systemPrompt` to the adapter\n\t * only — never pushed as a `{role:\"system\"}` message (avoiding the\n\t * double-send class of bug where adapters that normalize both shapes end\n\t * up with two system entries).\n\t */\n\tsystemPrompt?: string;\n\t/**\n\t * Optional reactive abort signal. When the node emits `true`, the in-flight\n\t * `adapter.invoke()` call is cancelled via `AbortController.abort()`.\n\t * Threaded through `nodeSignal(abort)` — a one-shot bridge. Useful inside\n\t * agent state machines where a separate `aborted` state should cancel the\n\t * current LLM call without superseding via switchMap.\n\t */\n\tabort?: Node<boolean>;\n\tmeta?: Record<string, unknown>;\n};\n\n/** Extract text content from an LLM response, handling various response shapes. */\nfunction extractContent(resp: unknown): string {\n\tif (resp != null && typeof resp === \"object\" && \"content\" in resp) {\n\t\treturn String((resp as LLMResponse).content);\n\t}\n\tif (typeof resp === \"string\") return resp;\n\treturn String(resp);\n}\n\nfunction previewContent(text: string, max = 200): string {\n\tif (text.length <= max) return text;\n\treturn `${text.slice(0, max)}…`;\n}\n\n/**\n * Universal LLM transform: wraps a prompt template + model adapter into a reactive derived node.\n * Re-invokes the LLM whenever any dep changes. Suitable for triage, QA, hypothesis, parity, etc.\n *\n * **Topology** (visible in `describe()`):\n * ```\n * <deps...>, [tools?] → <name>::messages (derived, meta.ai = prompt_node::messages)\n * <name>::messages → <name>::output (switchMap product, meta.ai = prompt_node::output)\n * per-wave inner: <name>::response (producer, meta.ai = prompt_node::response)\n * ```\n * When `opts.tools` is supplied, the tools `Node` is appended to\n * `messagesNode`'s declared deps so it appears as a real edge in `describe()`\n * / `explain()` (DF12, Tier 7).\n *\n * **No-input semantics** (matches the codebase-wide SENTINEL convention):\n * - **Initial no-input** (no real input has ever arrived) — emits nothing.\n * Outer cache stays `undefined`; `subscribe` consumers see no DATA event.\n * Use this to keep downstream gating clean: a `withLatestFrom`-paired\n * trigger won't fire until the LLM has actually produced something.\n * - **Mid-flow no-input** (input dropped to nullish after at least one\n * real LLM call) — emits `null` as a domain \"input went away\" signal.\n * Downstream consumers can distinguish \"haven't started\" from \"input\n * gone.\"\n *\n * **Retries / caching:** stack `withRetry` / `withReplayCache` middleware on the\n * `adapter` argument — `promptNode` no longer ships its own duplicated retry /\n * cache loops (pre-1.0 cleanup, see review session 1).\n *\n * @param adapter - LLM adapter (provider-agnostic). Wrap with `withRetry` /\n * `withReplayCache` middleware for transient-error tolerance\n * or replay caching.\n * @param deps - Input nodes whose values feed the prompt.\n * @param prompt - Static string or template function receiving dep values.\n * @param opts - Optional configuration.\n * @returns `Node` emitting LLM responses (string or parsed JSON).\n */\n// Overload 1: `format: \"raw\"` constrains the emit type to `LLMResponse | null`\n// (the full adapter response, with `usage` / `toolCalls` / `finishReason`).\n// Subsumes the pre-Tier-2.3 `fromLLM` shape.\nexport function promptNode(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts: PromptNodeOptions & { format: \"raw\" },\n): Node<LLMResponse | null>;\n// Overload 2: `format: \"text\" | \"json\"` (default text) — emit-type is the\n// caller's `T` (defaults to `string`). For `\"json\"` callers typically pass\n// the parsed shape (e.g. `promptNode<MyShape>(...)`).\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: Omit<PromptNodeOptions, \"format\"> & { format?: \"text\" | \"json\" },\n): Node<T | null>;\nexport function promptNode<T = string>(\n\tadapter: LLMAdapter,\n\tdeps: readonly Node<unknown>[],\n\tprompt: string | ((...depValues: unknown[]) => string),\n\topts?: PromptNodeOptions,\n): Node<T | null> {\n\tconst format = opts?.format ?? \"text\";\n\tconst baseName = opts?.name ?? \"prompt_node\";\n\n\t// qa A8: tools without `format: \"raw\"` is a footgun — adapter receives\n\t// the tool definitions and may produce `toolCalls`, but the emit path\n\t// only extracts `content`. Warn at construction; downstream parsers\n\t// reading `toolCalls` from a custom `format: \"raw\"` consumer pattern\n\t// can ignore by setting `format: \"raw\"` (intent now matches behavior).\n\tif (opts?.tools !== undefined && format !== \"raw\") {\n\t\tconsole.warn(\n\t\t\t\"promptNode: `tools` is set but `format !== 'raw'`. \" +\n\t\t\t\t\"Tool calls in the response will be silently dropped — set \" +\n\t\t\t\t\"`format: 'raw'` to receive the full LLMResponse with `toolCalls`.\",\n\t\t);\n\t}\n\n\t// SENTINEL semantics rely on the universal first-run gate + standard\n\t// prevData semantics (undefined = SENTINEL, any other value = DATA seen):\n\t// - **Initial no-input** (no dep has ever DATA'd, so prevData is\n\t// undefined across the board): the `derived`'s first-run gate blocks\n\t// `messagesNode`'s fn entirely. It never emits, switchMap never\n\t// fires, outer cache stays `undefined`.\n\t// - **Mid-flow no-input** (deps previously DATA'd then went nullish):\n\t// fn runs, returns `[]`, switchMap dispatches the `node([], { initial: null })`\n\t// branch → outer emits `null` as the domain \"input went away\" signal.\n\t// No `initial: []` and no closure flag — `prevData === undefined` is\n\t// already the sentinel marker, and the gate already enforces \"don't fire\n\t// fn until every dep has DATA'd at least once.\"\n\t//\n\t// DF12: when `opts.tools` is a Node, it's appended to `messagesNode`'s\n\t// declared deps. The fn slices values into user-deps + tools, and emits\n\t// an envelope `{ messages, tools }` so switchMap's per-wave inner can\n\t// read the latest tools via the reactive edge instead of a closure.\n\ttype Envelope = {\n\t\tmessages: readonly ChatMessage[];\n\t\ttools: readonly ToolDefinition[] | undefined;\n\t};\n\tconst userDepsLength = deps.length;\n\tconst allDeps: readonly Node<unknown>[] =\n\t\topts?.tools !== undefined ? [...deps, opts.tools as Node<unknown>] : deps;\n\tconst messagesNode = node<Envelope>(\n\t\tallDeps as Node<unknown>[],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst userValues = data.slice(0, userDepsLength);\n\t\t\tconst toolsValue =\n\t\t\t\topts?.tools !== undefined\n\t\t\t\t\t? (data[userDepsLength] as readonly ToolDefinition[] | undefined)\n\t\t\t\t\t: undefined;\n\t\t\t// Dep-level null guard (composition guide §8): if any USER dep is\n\t\t\t// nullish, emit empty messages → switchMap emits null (mid-flow\n\t\t\t// drop-out). The tools dep can legitimately be empty `[]`; only\n\t\t\t// user deps gate the call.\n\t\t\tif (userValues.some((v) => v == null)) {\n\t\t\t\tactions.emit({ messages: [], tools: toolsValue });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst text = typeof prompt === \"string\" ? prompt : prompt(...userValues);\n\t\t\tif (!text) {\n\t\t\t\tactions.emit({ messages: [], tools: toolsValue });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// systemPrompt forwarded through invoke opts only (no double-send).\n\t\t\tactions.emit({\n\t\t\t\tmessages: [{ role: \"user\" as const, content: text }],\n\t\t\t\ttools: toolsValue,\n\t\t\t});\n\t\t},\n\t\t{\n\t\t\tname: `${baseName}::messages`,\n\t\t\tmeta: aiMeta(\"prompt_node::messages\"),\n\t\t},\n\t);\n\n\tconst result = switchMap<Envelope, T | null>(\n\t\tmessagesNode,\n\t\t(envelope) => {\n\t\t\tconst { messages: msgs, tools } = envelope;\n\t\t\tif (!msgs || msgs.length === 0) {\n\t\t\t\treturn node<T | null>([], { initial: null }) as NodeInput<T | null>;\n\t\t\t}\n\n\t\t\t// Producer ensures exactly one DATA + COMPLETE per wave; switchMap\n\t\t\t// sees one DATA, the harness's \"one emission per wave\" contract is\n\t\t\t// honored. Earlier attempts using a derived node leaked\n\t\t\t// transient nulls via the derived's first-run gate.\n\t\t\treturn node<T | null>(\n\t\t\t\t(_data, actions) => {\n\t\t\t\t\tlet done = false;\n\t\t\t\t\tlet cancelled = false;\n\t\t\t\t\tlet abortDispose: (() => void) | undefined;\n\n\t\t\t\t\tconst invokeOpts: LLMInvokeOptions = {\n\t\t\t\t\t\tmodel: opts?.model,\n\t\t\t\t\t\ttemperature: opts?.temperature,\n\t\t\t\t\t\tmaxTokens: opts?.maxTokens,\n\t\t\t\t\t\tsystemPrompt: opts?.systemPrompt,\n\t\t\t\t\t\t...(tools !== undefined ? { tools } : {}),\n\t\t\t\t\t};\n\t\t\t\t\tif (opts?.abort) {\n\t\t\t\t\t\tconst sig = nodeSignal(opts.abort);\n\t\t\t\t\t\tinvokeOpts.signal = sig.signal;\n\t\t\t\t\t\tabortDispose = sig.dispose;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet invokeResult: NodeInput<LLMResponse>;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinvokeResult = adapter.invoke(msgs, invokeOpts);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\tactions.down([[ERROR, err]]);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tconst callNode = fromAny(invokeResult);\n\n\t\t\t\t\tconst sub = callNode.subscribe((batch) => {\n\t\t\t\t\t\tif (cancelled || done) return;\n\t\t\t\t\t\tfor (const msg of batch) {\n\t\t\t\t\t\t\t// F-11: re-check `cancelled` (and `done`) at the top of\n\t\t\t\t\t\t\t// each per-message iteration so a teardown / abort that\n\t\t\t\t\t\t\t// fires synchronously between messages stops processing\n\t\t\t\t\t\t\t// further batched messages immediately.\n\t\t\t\t\t\t\tif (cancelled || done) return;\n\t\t\t\t\t\t\tif (msg[0] === DATA) {\n\t\t\t\t\t\t\t\tconst resp = msg[1] as LLMResponse;\n\t\t\t\t\t\t\t\t// `format: \"raw\"` bypasses parsing — emit the full\n\t\t\t\t\t\t\t\t// LLMResponse object (subsumes the pre-Tier-2.3 `fromLLM`\n\t\t\t\t\t\t\t\t// output shape).\n\t\t\t\t\t\t\t\tif (format === \"raw\") {\n\t\t\t\t\t\t\t\t\tactions.emit(resp as unknown as T);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// F-12: cache the extracted content once on the\n\t\t\t\t\t\t\t\t\t// parse-failure path so we don't call\n\t\t\t\t\t\t\t\t\t// `extractContent(resp)` twice (once for parsing,\n\t\t\t\t\t\t\t\t\t// once for the error-message preview).\n\t\t\t\t\t\t\t\t\tlet content: string;\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tcontent = extractContent(resp);\n\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\t// extractContent itself failed — propagate as\n\t\t\t\t\t\t\t\t\t\t// an ERROR with a generic raw-extraction message.\n\t\t\t\t\t\t\t\t\t\tconst wrapped = new Error(\n\t\t\t\t\t\t\t\t\t\t\t`promptNode: failed to extract content from LLM response: ${\n\t\t\t\t\t\t\t\t\t\t\t\t(err as Error).message\n\t\t\t\t\t\t\t\t\t\t\t}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal-error\n\t\t\t\t\t\t\t\t\t\t// branches so we don't retain the AbortController\n\t\t\t\t\t\t\t\t\t\t// after the wave terminates. Idempotent.\n\t\t\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tactions.down([[ERROR, wrapped]]);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst parsed: T =\n\t\t\t\t\t\t\t\t\t\t\tformat === \"json\"\n\t\t\t\t\t\t\t\t\t\t\t\t? (JSON.parse(stripFences(content)) as T)\n\t\t\t\t\t\t\t\t\t\t\t\t: (content as unknown as T);\n\t\t\t\t\t\t\t\t\t\tactions.emit(parsed);\n\t\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\t\tconst wrapped = new Error(\n\t\t\t\t\t\t\t\t\t\t\t`promptNode: failed to parse LLM response as JSON: ${\n\t\t\t\t\t\t\t\t\t\t\t\t(err as Error).message\n\t\t\t\t\t\t\t\t\t\t\t}\\n Raw content (first 200 chars): ${previewContent(content)}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t// F-7: dispose abort hook on parse-error\n\t\t\t\t\t\t\t\t\t\t// terminal branch.\n\t\t\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tactions.down([[ERROR, wrapped]]);\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (msg[0] === ERROR) {\n\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal ERROR branch.\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\tactions.down([[ERROR, msg[1]]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} else if (msg[0] === COMPLETE) {\n\t\t\t\t\t\t\t\t// Adapter completed — propagate. emit() above already\n\t\t\t\t\t\t\t\t// queued the parsed value so the wave carries DATA + COMPLETE.\n\t\t\t\t\t\t\t\t// F-7: dispose abort hook on terminal COMPLETE branch.\n\t\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Spec §1.3.6 forward-unknown — DIRTY/RESOLVED/INVALIDATE/\n\t\t\t\t\t\t\t\t// PAUSE/RESUME etc. should propagate so downstream caches /\n\t\t\t\t\t\t\t\t// flow-control hooks aren't starved. Re-typed `as never`\n\t\t\t\t\t\t\t\t// because the call's NodeInput<LLMResponse> message tuple\n\t\t\t\t\t\t\t\t// is wider than the unbound `T` projection.\n\t\t\t\t\t\t\t\tactions.down([msg as never]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t\t\tsub();\n\t\t\t\t\t\t\t// F-7: cleanup callback's abortDispose call is idempotent —\n\t\t\t\t\t\t\t// the terminal-branch dispose above sets `abortDispose =\n\t\t\t\t\t\t\t// undefined` so this is a no-op when terminal-fired.\n\t\t\t\t\t\t\tabortDispose?.();\n\t\t\t\t\t\t\tabortDispose = undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"producer\",\n\t\t\t\t\tname: `${baseName}::response`,\n\t\t\t\t\tmeta: aiMeta(\"prompt_node::response\"),\n\t\t\t\t},\n\t\t\t) as NodeInput<T | null>;\n\t\t},\n\t\t{\n\t\t\tname: `${baseName}::output`,\n\t\t\tmeta: opts?.meta\n\t\t\t\t? { ...aiMeta(\"prompt_node::output\"), ...opts.meta }\n\t\t\t\t: aiMeta(\"prompt_node::output\"),\n\t\t},\n\t);\n\n\treturn result;\n}\n","/**\n * Phase 13.H — `agent(spec)` preset + `presetRegistry` sugar.\n *\n * Source: `archive/docs/SESSION-multi-agent-gap-analysis.md` G1 + G2.\n *\n * `agent()` is the ergonomic factory — given a parent Graph and an\n * `AgentSpec`, mints an `AgentGraph`, mounts it under the parent at\n * `spec.name`, and returns the `AgentBundle` contract.\n *\n * `presetRegistry()` is thin sugar over `reactiveMap` — a typed reactive\n * map of `<id, preset>`. Pairs with `materialize` (Phase 13.C) for\n * dynamic preset selection: callers store specs / factories / configs in\n * the registry and `materialize` mounts the matching one based on a\n * routing key.\n *\n * **Cross-cut #1 lock:** no `agent.run()` imperative sugar — caller-side\n * runtime is `bundle.in.emit(input)` + `awaitSettled(bundle.out)`.\n */\n\nimport { type ReactiveMapBundle, reactiveMap } from \"@graphrefly/pure-ts/extra\";\nimport type { Graph } from \"@graphrefly/pure-ts/graph\";\nimport type { LLMResponse } from \"../../utils/ai/adapters/core/types.js\";\nimport { type AgentBundle, AgentGraph, type AgentSpec } from \"./agent.js\";\n\n// ---------------------------------------------------------------------------\n// agent() factory\n// ---------------------------------------------------------------------------\n\n/**\n * Mints an {@link AgentGraph} from `spec`, mounts it under `parent` at\n * `spec.name`, and returns the {@link AgentBundle} contract.\n *\n * **Default type parameters.** When called without explicit type params,\n * `TIn` defaults to `string` and `TOut` to `LLMResponse` — the common\n * case where the caller writes a user message and reads the raw response.\n * Custom types require both `inMapper` and `outMapper` in the spec; the\n * default mappers throw at runtime if `TIn` / `TOut` aren't string /\n * LLMResponse.\n *\n * **Memory partition default.** Each `agent()` call mints its own\n * `AgentMemoryGraph` if `spec.memory` is omitted (private memory; the\n * common case). Pass an explicit shared instance — e.g.\n * `agent(parent, { ..., memory: sharedMemory })` for two agents — to\n * implement §29 handoff context transfer.\n *\n * **Reactive entry / exit:**\n * - `bundle.in.emit(input)` kicks the loop reactively (no imperative\n * `.run()` per cross-cut #1 lock).\n * - `awaitSettled(bundle.out, { skipCurrent: true })` resolves on the\n * first response after the kick. `skipCurrent` matters for the second\n * call onward — `out` caches the prior response.\n *\n * **Mounting.** The factory mounts under `parent.mount(spec.name, ...)`.\n * The slot name must be free on `parent` at construction time. To keep\n * the agent unmounted, construct `new AgentGraph(spec)` directly.\n *\n * @example\n * ```ts\n * import { agent, awaitSettled, Graph } from \"@graphrefly/graphrefly-ts\";\n *\n * const parent = new Graph(\"parent\");\n * const a = agent(parent, {\n * name: \"researcher\",\n * adapter: openaiAdapter,\n * systemPrompt: \"Research the user's question carefully.\",\n * });\n * a.in.emit(\"What's the capital of France?\");\n * const resp = await awaitSettled(a.out, { skipCurrent: true });\n * ```\n *\n * @category patterns\n */\nexport function agent<TIn = string, TOut = LLMResponse>(\n\tparent: Graph,\n\tspec: AgentSpec<TIn, TOut>,\n): AgentBundle<TIn, TOut> {\n\tconst graph = new AgentGraph<TIn, TOut>(spec);\n\tparent.mount(spec.name, graph);\n\treturn {\n\t\tin: graph.in,\n\t\tout: graph.out,\n\t\tstatus: graph.status,\n\t\tcost: graph.cost,\n\t\tgraph,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// presetRegistry()\n// ---------------------------------------------------------------------------\n\n/**\n * The bundle returned by {@link presetRegistry}. Wraps a `reactiveMap`\n * with imperative `put` / `remove` shortcuts and exposes the underlying\n * `registry` for direct reactive consumption (`.entries` is a\n * `Node<ReadonlyMap<string, TPreset>>`).\n *\n * Use the `registry.entries` Node directly with {@link materialize} (Phase\n * 13.C) — pass it as the `factories` argument when `TPreset` is itself\n * a `() => Graph` factory thunk, or transform via `derived` when\n * `TPreset` is a richer spec type that needs a `spec → factory` adapter.\n */\nexport interface PresetRegistryBundle<TPreset> {\n\t/**\n\t * The underlying reactive map. `registry.entries` is the\n\t * `Node<ReadonlyMap<string, TPreset>>` — pass directly to\n\t * {@link materialize} when preset shape matches the factories arg.\n\t */\n\treadonly registry: ReactiveMapBundle<string, TPreset>;\n\t/** Imperative add / replace. Always emits a fresh snapshot. */\n\tput(id: string, preset: TPreset): void;\n\t/** Imperative remove. Returns `true` if the id was present. */\n\tremove(id: string): boolean;\n}\n\n/**\n * Thin sugar over `reactiveMap` — a typed registry of `<id, preset>` for\n * agent / strategy / persona / skill catalogs.\n *\n * **Generic over preset shape.** `TPreset` is open — could be an\n * {@link AgentSpec}, a `() => Graph` factory thunk, a static config\n * object, or anything else. Decoupled from `agent()` so the same primitive\n * powers harnessLoop strategy registries, pipelineGraph stage catalogs,\n * etc.\n *\n * **Composes with `materialize`.** When `TPreset` is a `() => Graph`\n * factory, pass `registry.entries` directly to\n * {@link materialize} as the `factories` argument. When `TPreset` is a\n * spec, transform via `derived` to build a `Map<id, () => Graph>` adapter:\n *\n * ```ts\n * const presets = presetRegistry<AgentSpec<string, LLMResponse>>();\n * presets.put(\"researcher\", { name: \"researcher\", adapter, systemPrompt: \"...\" });\n *\n * // Adapter: spec → factory.\n * const factories = derived(\n * [presets.registry.entries],\n * ([m]) => new Map(\n * [...m].map(([id, spec]) => [id, () => new AgentGraph(spec)]),\n * ),\n * );\n * const slot = materialize(activeKey, factories, parent);\n * ```\n *\n * @param initial - Optional initial entries.\n * @returns {@link PresetRegistryBundle}.\n *\n * @category patterns\n */\nexport function presetRegistry<TPreset>(\n\tinitial?: ReadonlyMap<string, TPreset>,\n): PresetRegistryBundle<TPreset> {\n\tconst registry = reactiveMap<string, TPreset>({ name: \"presetRegistry\" });\n\tif (initial != null) {\n\t\tfor (const [id, preset] of initial) {\n\t\t\tregistry.set(id, preset);\n\t\t}\n\t}\n\treturn {\n\t\tregistry,\n\t\tput(id, preset) {\n\t\t\tregistry.set(id, preset);\n\t\t},\n\t\tremove(id) {\n\t\t\tif (!registry.has(id)) return false;\n\t\t\tregistry.delete(id);\n\t\t\treturn true;\n\t\t},\n\t};\n}\n","/**\n * DS-14.6.A U-A — tagged context substrate (Phase 14.5).\n *\n * Per-view tagged context (SESSION-DS-14.6-A L3–L6 + SESSION-DS-14.6-A-9Q\n * implementation walk). Pool stores immutable tier-0 originals on an\n * **append-only `reactiveLog`** (D-A4 — structural tier-0 immutability, free\n * `LogChange` mutations, side-steps the DS14R1 TTL/LRU prune-fidelity bug).\n * Each consumer holds a `ContextView` that materialises its own filtered +\n * compressed slice (`Node<readonly RenderedEntry[]>`). Routing is mechanical\n * tag comparison (zero LLM); only `llm-summary` rules cross to an injected\n * `llmCompress` (D-A3). Compression cache is one shared `(id, tier)` map in\n * the pool bundle, bounded LRU (D-A5). Schema is pure data, presentation\n * layer (D-A1) — no `@graphrefly/pure-ts` consumer.\n *\n * @module\n */\n\nimport { type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { aiMeta } from \"../../../utils/ai/_internal.js\";\n\n// ── Schema (pure data — D-A1) ────────────────────────────────────────────────\n\nexport type Tag = string;\n\n/** Compression tier. 0 = original; higher = more compressed. */\nexport type Tier = 0 | 1 | 2 | 3;\n\nexport interface ContextEntry<T> {\n\t/** Stable id — cache key component `(id, tier)`. Auto-assigned if omitted. */\n\treadonly id: string;\n\treadonly payload: T;\n\treadonly tags: readonly Tag[];\n\t/** 0..1. Budget/GC ordering. */\n\treadonly importance: number;\n\treadonly compressible: boolean;\n\treadonly topic: string;\n\t/** Wall-clock at add (ns) — used by `poolGC({ olderThanNs })`. */\n\treadonly t_ns: number;\n}\n\nexport interface RuleMatch {\n\treadonly topic?: string | RegExp;\n\treadonly tagsAny?: readonly Tag[];\n\treadonly importanceMin?: number;\n\treadonly importanceMax?: number;\n\treadonly compressible?: boolean;\n}\n\nexport type CompressionRule =\n\t| { readonly match: RuleMatch; readonly action: \"evict\" }\n\t| { readonly match: RuleMatch; readonly action: \"truncate\"; readonly maxChars: number }\n\t| { readonly match: RuleMatch; readonly action: \"reference\" }\n\t| { readonly match: RuleMatch; readonly action: \"llm-summary\"; readonly toTier: Tier };\n\nexport interface RenderedEntry<T> {\n\treadonly id: string;\n\treadonly topic: string;\n\treadonly tags: readonly Tag[];\n\treadonly tier: Tier;\n\t/** Original payload at tier 0; compressed `string` otherwise. */\n\treadonly payload: T | string;\n\treadonly compressed: boolean;\n}\n\nexport interface ContextView<T> {\n\treadonly filter: (e: ContextEntry<T>) => boolean;\n\t/** 0..1. A rule fires when `pressure > 0` and the entry matches. */\n\treadonly pressure: Node<number>;\n\treadonly budgetTokens: number;\n\treadonly rules: readonly CompressionRule[];\n\t/** Default `s => Math.ceil(s.length / 4)`. */\n\treadonly tokenizer?: (s: string) => number;\n}\n\nexport interface PoolGCPolicy {\n\t/** Drop entries with `t_ns < (now - olderThanNs)`. */\n\treadonly olderThanNs?: number;\n\t/** Drop entries with `importance < importanceBelow`. */\n\treadonly importanceBelow?: number;\n\t/**\n\t * **Scope**, not a match-to-evict rule: when set, GC only considers\n\t * entries whose `topic === this`; entries of other topics always survive.\n\t * `olderThanNs` / `importanceBelow` are ANDed *within* this scope.\n\t */\n\treadonly topic?: string;\n\t/** Keep at most this many most-recent entries. */\n\treadonly max?: number;\n}\n\n/** `(entry, toTier) => compressedText`. Injected; required iff a view uses `llm-summary`. */\nexport type LlmCompress<T> = (entry: ContextEntry<T>, toTier: Tier) => string;\n\nexport interface TaggedContextPoolOptions<T> {\n\treadonly topic: string;\n\t/** Forwarded to the backing append-only `reactiveLog` (poolGC ceiling). */\n\treadonly maxEntries?: number;\n\t/** Required iff any rendered view uses an `llm-summary` rule (D-A3). */\n\treadonly llmCompress?: LlmCompress<T>;\n\t/** Shared `(id, tier)` compression cache cap (D-A5). Default 512. */\n\treadonly cacheMax?: number;\n\treadonly name?: string;\n}\n\nexport interface TaggedContextPoolBundle<T> {\n\t/**\n\t * Append an entry (immutable tier-0). Returns its id (auto-assigned\n\t * `ctx-N` per-pool if omitted).\n\t *\n\t * **Caller-supplied ids must be unique within the pool.** The log is\n\t * append-only and does NOT dedupe; the compression cache is keyed by\n\t * `(id, tier)`, so appending two different entries with the same explicit\n\t * `id` makes the second render the first's cached summary (QA P11).\n\t */\n\tadd(entry: Omit<ContextEntry<T>, \"id\" | \"t_ns\"> & { id?: string }): string;\n\t/** All live tier-0 entries. */\n\treadonly entries: Node<readonly ContextEntry<T>[]>;\n\t/** Entries carrying `tag`. */\n\tbyTag(tag: Tag): Node<readonly ContextEntry<T>[]>;\n\t/** Pool-global retention (L6 — distinct from per-view filtering). Returns removed count. */\n\tpoolGC(policy: PoolGCPolicy): number;\n\treadonly graph: Graph;\n\t/** Internal — shared compression cache (one per pool, D-A5). */\n\treadonly _cache: CompressionCache;\n\treadonly _opts: TaggedContextPoolOptions<T>;\n\tdispose(): void;\n}\n\n// ── Shared bounded (id,tier) compression cache (D-A5) ────────────────────────\n\n/**\n * Bounded LRU cache keyed by `(id, tier)`. Uses a nested `Map<id, Map<tier,\n * value>>` (NOT a `${id}::${tier}` string key) so a caller-supplied `id`\n * containing the separator cannot collide (QA P5). LRU is tracked at the\n * (id,tier) leaf via a flat insertion-order key list.\n */\nexport class CompressionCache {\n\tprivate readonly _m = new Map<string, Map<Tier, string>>();\n\t/** Insertion-order list of `id` keys for LRU eviction at the id granularity. */\n\tprivate readonly _order: string[] = [];\n\tconstructor(private readonly _max: number) {}\n\tget(id: string, tier: Tier): string | undefined {\n\t\tconst inner = this._m.get(id);\n\t\tconst v = inner?.get(tier);\n\t\tif (v !== undefined) {\n\t\t\tconst i = this._order.indexOf(id);\n\t\t\tif (i >= 0) this._order.splice(i, 1);\n\t\t\tthis._order.push(id);\n\t\t}\n\t\treturn v;\n\t}\n\tset(id: string, tier: Tier, value: string): void {\n\t\tlet inner = this._m.get(id);\n\t\tif (inner === undefined) {\n\t\t\tinner = new Map<Tier, string>();\n\t\t\tthis._m.set(id, inner);\n\t\t}\n\t\tinner.set(tier, value);\n\t\tconst i = this._order.indexOf(id);\n\t\tif (i >= 0) this._order.splice(i, 1);\n\t\tthis._order.push(id);\n\t\twhile (this._m.size > this._max) {\n\t\t\tconst evict = this._order.shift();\n\t\t\tif (evict === undefined) break;\n\t\t\tthis._m.delete(evict);\n\t\t}\n\t}\n}\n\n// ── Pool ─────────────────────────────────────────────────────────────────────\n\n/** Process-wide sequence for collision-safe default mount names (QA P6). */\nlet _poolSeq = 0;\n\n/**\n * Append-only tagged context pool (D-A4). The pool is a `reactiveLog` of\n * immutable tier-0 entries plus a derived `entries` node; `byTag` derives a\n * filtered view; `poolGC` is the explicit pool-global retention (L6).\n */\nexport function taggedContextPool<T>(\n\tparent: Graph,\n\topts: TaggedContextPoolOptions<T>,\n): TaggedContextPoolBundle<T> {\n\t// QA P6: collision-safe default mount name — two pools with the same\n\t// `topic` under one parent must not collide on `parent.mount`. Explicit\n\t// `opts.name` is respected verbatim (caller owns uniqueness then).\n\tconst mountName = opts.name ?? `ctxpool-${opts.topic}-${++_poolSeq}`;\n\tconst graph = new Graph(mountName);\n\tparent.mount(mountName, graph);\n\n\tconst log: ReactiveLogBundle<ContextEntry<T>> = reactiveLog<ContextEntry<T>>(undefined, {\n\t\tname: `${mountName}.log`,\n\t\tmaxSize: opts.maxEntries,\n\t});\n\tconst cache = new CompressionCache(opts.cacheMax ?? 512);\n\t// QA P5: per-pool id counter (was module-global → test-pollution +\n\t// cross-pool cache-key cross-talk).\n\tlet autoId = 0;\n\n\tconst entries: Node<readonly ContextEntry<T>[]> = log.entries;\n\n\tfunction add(e: Omit<ContextEntry<T>, \"id\" | \"t_ns\"> & { id?: string }): string {\n\t\tconst id = e.id ?? `ctx-${++autoId}`;\n\t\tlog.append({\n\t\t\tid,\n\t\t\tpayload: e.payload,\n\t\t\ttags: e.tags,\n\t\t\timportance: e.importance,\n\t\t\tcompressible: e.compressible,\n\t\t\ttopic: e.topic,\n\t\t\tt_ns: wallClockNs(), // QA P2 — clock.ts invariant (was Date.now()*1e6)\n\t\t});\n\t\treturn id;\n\t}\n\n\tfunction byTag(tag: Tag): Node<readonly ContextEntry<T>[]> {\n\t\treturn node<readonly ContextEntry<T>[]>(\n\t\t\t[entries as Node],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst cur = (data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly ContextEntry<T>[]\n\t\t\t\t\t| undefined;\n\t\t\t\tactions.emit((cur ?? []).filter((x) => x.tags.includes(tag)));\n\t\t\t},\n\t\t\t{ describeKind: \"derived\", meta: aiMeta(\"contextPool.byTag\", { tag }) },\n\t\t);\n\t}\n\n\tfunction poolGC(policy: PoolGCPolicy): number {\n\t\tconst all = log.entries.cache ?? [];\n\t\tconst nowNs = wallClockNs();\n\t\tlet survivors = all.filter((e) => {\n\t\t\t// QA P1: `topic` is a SCOPE, not a match-to-evict rule — entries\n\t\t\t// outside the topic are never GC'd by this call; eviction criteria\n\t\t\t// (olderThanNs / importanceBelow) are ANDed within the scope.\n\t\t\tif (policy.topic != null && e.topic !== policy.topic) return true;\n\t\t\tif (policy.olderThanNs != null && nowNs - e.t_ns >= policy.olderThanNs) return false;\n\t\t\tif (policy.importanceBelow != null && e.importance < policy.importanceBelow) return false;\n\t\t\treturn true;\n\t\t});\n\t\tif (policy.max != null && survivors.length > policy.max) {\n\t\t\tsurvivors = survivors.slice(survivors.length - policy.max);\n\t\t}\n\t\tconst removed = all.length - survivors.length;\n\t\tif (removed > 0) {\n\t\t\tlog.clear();\n\t\t\tlog.appendMany(survivors);\n\t\t}\n\t\treturn removed;\n\t}\n\n\treturn {\n\t\tadd,\n\t\tentries,\n\t\tbyTag,\n\t\tpoolGC,\n\t\tgraph,\n\t\t_cache: cache,\n\t\t_opts: opts,\n\t\tdispose(): void {\n\t\t\tlog.dispose();\n\t\t},\n\t};\n}\n\n// ── tierCompress + renderContextView ─────────────────────────────────────────\n\nconst DEFAULT_TOKENIZER = (s: string): number => Math.ceil(s.length / 4);\n\nfunction matches(e: ContextEntry<unknown>, m: RuleMatch): boolean {\n\tif (m.topic != null) {\n\t\tif (typeof m.topic === \"string\" ? e.topic !== m.topic : !m.topic.test(e.topic)) return false;\n\t}\n\tif (m.tagsAny != null && !m.tagsAny.some((t) => e.tags.includes(t))) return false;\n\tif (m.importanceMin != null && e.importance < m.importanceMin) return false;\n\tif (m.importanceMax != null && e.importance > m.importanceMax) return false;\n\tif (m.compressible != null && e.compressible !== m.compressible) return false;\n\treturn true;\n}\n\n/**\n * Apply the first matching rule to one entry under `pressure`. Non-LLM\n * strategies (truncate / evict / reference) are pure data; `llm-summary`\n * calls the injected `llmCompress`, caching by `(id, toTier)` (D-A5).\n * Returns `undefined` for evicted / pressure-filtered entries.\n */\nexport function tierCompress<T>(\n\te: ContextEntry<T>,\n\trules: readonly CompressionRule[],\n\tpressure: number,\n\tcache: CompressionCache,\n\tllmCompress?: LlmCompress<T>,\n): RenderedEntry<T> | undefined {\n\tconst base: RenderedEntry<T> = {\n\t\tid: e.id,\n\t\ttopic: e.topic,\n\t\ttags: e.tags,\n\t\ttier: 0,\n\t\tpayload: e.payload,\n\t\tcompressed: false,\n\t};\n\tif (pressure <= 0) return base;\n\tfor (const rule of rules) {\n\t\tif (!matches(e, rule.match)) continue;\n\t\tswitch (rule.action) {\n\t\t\tcase \"evict\":\n\t\t\t\treturn undefined;\n\t\t\tcase \"reference\":\n\t\t\t\treturn { ...base, tier: 1, payload: `[ref:${e.id}]`, compressed: true };\n\t\t\tcase \"truncate\": {\n\t\t\t\tconst s = typeof e.payload === \"string\" ? e.payload : JSON.stringify(e.payload);\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttier: 1,\n\t\t\t\t\tpayload: s.length > rule.maxChars ? s.slice(0, rule.maxChars) : s,\n\t\t\t\t\tcompressed: s.length > rule.maxChars,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"llm-summary\": {\n\t\t\t\tif (!llmCompress) {\n\t\t\t\t\t// Defence-in-depth — construction guard should have thrown.\n\t\t\t\t\tthrow new Error(\"tierCompress: 'llm-summary' rule requires `llmCompress`\");\n\t\t\t\t}\n\t\t\t\tconst cached = cache.get(e.id, rule.toTier);\n\t\t\t\tconst text = cached ?? llmCompress(e, rule.toTier);\n\t\t\t\tif (cached === undefined) cache.set(e.id, rule.toTier, text);\n\t\t\t\treturn { ...base, tier: rule.toTier, payload: text, compressed: true };\n\t\t\t}\n\t\t}\n\t}\n\treturn base;\n}\n\n/**\n * Per-consumer reactive rendering (D-A2). Materialises a\n * `Node<readonly RenderedEntry[]>` over the pool: filter → per-entry rule\n * application under `pressure` → token-budget trim (lowest-importance first).\n *\n * Recomputes the slice per `(entries | pressure)` wave (O(n) — behaviourally\n * identical to the incremental closure-mirror; incremental is a perf\n * follow-up, not a correctness gap).\n *\n * @throws if any rule is `llm-summary` and the pool has no `llmCompress`\n * (D-A3 construction guard).\n */\nexport function renderContextView<T>(\n\tpool: TaggedContextPoolBundle<T>,\n\tview: ContextView<T>,\n): Node<readonly RenderedEntry<T>[]> {\n\tconst usesLlm = view.rules.some((r) => r.action === \"llm-summary\");\n\tif (usesLlm && !pool._opts.llmCompress) {\n\t\tthrow new Error(\n\t\t\t\"renderContextView: view has an 'llm-summary' rule but the pool was created without `llmCompress` (DS-14.6.A D-A3).\",\n\t\t);\n\t}\n\tconst tokenize = view.tokenizer ?? DEFAULT_TOKENIZER;\n\tconst llmCompress = pool._opts.llmCompress;\n\n\treturn node<readonly RenderedEntry<T>[]>(\n\t\t[pool.entries as Node, view.pressure as Node],\n\t\t(data, actions, ctx) => {\n\t\t\tconst entries = (data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0]) as\n\t\t\t\t| readonly ContextEntry<T>[]\n\t\t\t\t| undefined;\n\t\t\tconst pressure = (data[1] != null && data[1].length > 0 ? data[1].at(-1) : ctx.prevData[1]) as\n\t\t\t\t| number\n\t\t\t\t| undefined;\n\t\t\tif (entries === undefined) {\n\t\t\t\tactions.emit([]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst p = pressure ?? 0;\n\t\t\tconst rendered: RenderedEntry<T>[] = [];\n\t\t\tfor (const e of entries) {\n\t\t\t\tif (!view.filter(e)) continue;\n\t\t\t\tconst r = tierCompress(e, view.rules, p, pool._cache, llmCompress);\n\t\t\t\tif (r !== undefined) rendered.push(r);\n\t\t\t}\n\t\t\t// Token-budget trim: drop lowest-importance entries until under budget.\n\t\t\tconst cost = (r: RenderedEntry<T>): number =>\n\t\t\t\ttokenize(typeof r.payload === \"string\" ? r.payload : JSON.stringify(r.payload));\n\t\t\tlet total = 0;\n\t\t\tfor (const r of rendered) total += cost(r);\n\t\t\tif (total > view.budgetTokens) {\n\t\t\t\tconst byImp = entries.reduce<Map<string, number>>(\n\t\t\t\t\t(acc, e) => acc.set(e.id, e.importance),\n\t\t\t\t\tnew Map(),\n\t\t\t\t);\n\t\t\t\trendered.sort((a, b) => (byImp.get(a.id) ?? 0) - (byImp.get(b.id) ?? 0));\n\t\t\t\twhile (total > view.budgetTokens && rendered.length > 0) {\n\t\t\t\t\ttotal -= cost(rendered.shift() as RenderedEntry<T>);\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(rendered);\n\t\t},\n\t\t{ describeKind: \"derived\", meta: aiMeta(\"contextView\", { topic: pool._opts.topic }) },\n\t);\n}\n","/**\n * DS-14.6.A U-C — `heterogeneousDebate()` (Phase 14.5).\n *\n * Stanford-MAD heterogeneity thesis (SESSION-DS-14.6-A L9): participants get\n * **different model adapters + different role prompts**. Closed reasoning\n * loop — no tools / side effects / persistent state beyond the transcript.\n *\n * **Reactive topology (QA M1→b, 2026-05-15).** The round loop is NOT a\n * top-level `async while` driver. It mirrors `refineLoop`'s §7 feedback\n * shape so `describe()` / `explain()` / dry-run see the structure:\n *\n * ```\n * roundTrigger(state) ──▶ roundWork(switchMap→producer, per-round\n * sequential adapter.invoke) ──▶ transcript(scan)\n * └─▶ converged(derived) │\n * ▲ │\n * └──────────── decideEffect (feedback + trigger) ◀─────┘\n * ```\n *\n * The per-round participant calls are an async **source boundary** inside\n * the switchMap producer (spec §5.10 — async belongs in sources), with an\n * abort-on-deactivate `AbortController` (COMPOSITION-GUIDE §45) so a\n * superseded / torn-down round cancels its in-flight LLM calls. `decideEffect`\n * is the sole feedback authority (computes termination inline from the round\n * envelope + closure history, §28); `converged` is a parallel derived purely\n * for external `status` observability. Termination: `fixedRounds |\n * \"until-converge\" | { until: Node<boolean> }` — `until` is a real reactive\n * dep, not a `.cache` poll. `\"until-converge\"` uses a pluggable `converge?`\n * fn, default = no participant changed stance across the last 2 rounds\n * (D-C1, zero extra LLM cost). `output:\"synthesizer-final\"` with no\n * synthesizer-role participant throws at construction (D-C2).\n *\n * @module\n */\n\nimport {\n\tbatch,\n\tnode as createNode,\n\tERROR,\n\tINVALIDATE,\n\ttype Node,\n\tRESOLVED,\n} from \"@graphrefly/pure-ts/core\";\nimport { fromAny, switchMap } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { awaitSettled, firstValueFrom } from \"../../../base/sources/settled.js\";\nimport type {\n\tChatMessage,\n\tLLMAdapter,\n\tLLMResponse,\n\tNodeInput,\n} from \"../../../utils/ai/adapters/core/types.js\";\n\nexport interface Turn {\n\treadonly round: number;\n\treadonly role: string;\n\treadonly content: string;\n}\n\nexport interface DebateParticipant {\n\treadonly adapter: LLMAdapter;\n\t/** e.g. \"advocate\" | \"skeptic\" | \"synthesizer\" | custom. */\n\treadonly role: string;\n\treadonly systemPrompt: string;\n}\n\nexport type DebateTermination = number | \"until-converge\" | { readonly until: Node<boolean> };\n\nexport type DebateOutput =\n\t| \"transcript\"\n\t| \"synthesizer-final\"\n\t| { readonly project: (transcript: readonly Turn[]) => unknown };\n\nexport type DebateStatus = \"running\" | \"converged\" | \"max-rounds\" | \"error\";\n\nexport interface HeterogeneousDebateOptions {\n\treadonly question: string;\n\treadonly participants: readonly DebateParticipant[];\n\t/** Default `3`. */\n\treadonly rounds?: DebateTermination;\n\t/** Default `\"transcript\"`. */\n\treadonly output?: DebateOutput;\n\t/**\n\t * D-C1 — `\"until-converge\"` detector. Default: no participant's latest\n\t * content changed vs the previous round (structural compare, no LLM).\n\t */\n\treadonly converge?: (transcript: readonly Turn[]) => boolean;\n\treadonly name?: string;\n\t/** Hard ceiling for `\"until-converge\"` / `{ until }` (default 12). */\n\treadonly maxRounds?: number;\n}\n\nexport interface HeterogeneousDebateBundle {\n\treadonly transcript: Node<readonly Turn[]>;\n\treadonly result: Node<unknown>;\n\treadonly status: Node<DebateStatus>;\n\treadonly graph: DebateGraph;\n\t/**\n\t * Thin `awaitSettled` bridge (mirrors `agentLoop.run()`): kicks the\n\t * reactive round loop and resolves the final `result`. Throws\n\t * `RangeError` if a prior `run()` is still pending (QA P4 re-entrancy).\n\t */\n\trun(): Promise<unknown>;\n}\n\nexport class DebateGraph extends Graph {}\n\nconst SYNTH_RE = /synth/i;\n\n/** Default converge: every role's latest two rounds are identical. */\nfunction defaultConverge(transcript: readonly Turn[]): boolean {\n\tconst rounds = transcript.reduce((m, t) => Math.max(m, t.round), 0);\n\tif (rounds < 2) return false;\n\tconst at = (r: number): Map<string, string> => {\n\t\tconst m = new Map<string, string>();\n\t\tfor (const t of transcript) if (t.round === r) m.set(t.role, t.content);\n\t\treturn m;\n\t};\n\tconst prev = at(rounds - 1);\n\tconst cur = at(rounds);\n\tif (prev.size === 0 || prev.size !== cur.size) return false;\n\tfor (const [role, content] of cur) if (prev.get(role) !== content) return false;\n\treturn true;\n}\n\n/** Process-wide sequence for collision-safe default mount names (QA P6). */\nlet _debateSeq = 0;\n\ninterface RoundEnvelope {\n\treadonly round: number;\n\treadonly turns: readonly Turn[];\n}\n\nexport function heterogeneousDebate(\n\tparent: Graph,\n\topts: HeterogeneousDebateOptions,\n): HeterogeneousDebateBundle {\n\tconst output = opts.output ?? \"transcript\";\n\tif (output === \"synthesizer-final\" && !opts.participants.some((p) => SYNTH_RE.test(p.role))) {\n\t\tthrow new Error(\n\t\t\t\"heterogeneousDebate: output 'synthesizer-final' requires a participant whose role matches /synth/i (DS-14.6.A D-C2).\",\n\t\t);\n\t}\n\tif (opts.participants.length === 0) {\n\t\tthrow new Error(\"heterogeneousDebate: at least one participant is required\");\n\t}\n\n\tconst name = opts.name ?? `debate-${++_debateSeq}`;\n\tconst graph = new DebateGraph(name);\n\tparent.mount(name, graph);\n\n\tconst term = opts.rounds ?? 3;\n\tconst maxRounds = opts.maxRounds ?? 12;\n\tconst converge = opts.converge ?? defaultConverge;\n\t// `{ until }` becomes a real reactive dep (QA P10 — no `.cache` poll);\n\t// non-until modes use a constant-false node for stable dep arity.\n\tconst untilNode: Node<boolean> =\n\t\ttypeof term === \"object\" ? term.until : createNode<boolean>([], { initial: false });\n\n\t// --- state / output nodes -------------------------------------------------\n\tconst roundTrigger = createNode<number>([], { name: `${name}.round`, initial: 0 });\n\tconst statusState = createNode<DebateStatus>([], { name: `${name}.status`, initial: \"running\" });\n\tconst resultState = createNode<unknown>([], { name: `${name}.result`, initial: undefined });\n\n\t// Closure history (§28 factory-time mirror) — the feedback authority's\n\t// view of the transcript without a declared dep cycle.\n\tlet history: Turn[] = [];\n\n\tfunction buildMessages(p: DebateParticipant): ChatMessage[] {\n\t\tconst msgs: ChatMessage[] = [\n\t\t\t{ role: \"system\", content: p.systemPrompt },\n\t\t\t{ role: \"user\", content: opts.question },\n\t\t];\n\t\tfor (const t of history) {\n\t\t\tmsgs.push({ role: \"assistant\", content: `[${t.role} r${t.round}] ${t.content}` });\n\t\t}\n\t\treturn msgs;\n\t}\n\n\t// --- GENERATE: roundTrigger → per-round sequential participant calls -------\n\t// switchMap producer = async source boundary (spec §5.10). The producer's\n\t// deactivate cleanup aborts in-flight calls (COMPOSITION-GUIDE §45 + the\n\t// switchMap supersede path), so a torn-down round burns no extra tokens.\n\tconst roundWork = switchMap<number, RoundEnvelope>(\n\t\troundTrigger,\n\t\t(r) =>\n\t\t\tcreateNode<RoundEnvelope>(\n\t\t\t\t[],\n\t\t\t\t(_data, actions) => {\n\t\t\t\t\tif (r < 1) {\n\t\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tconst ac = new AbortController();\n\t\t\t\t\tlet cancelled = false;\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\tconst turns: Turn[] = [];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tfor (const p of opts.participants) {\n\t\t\t\t\t\t\t\tconst res = await firstValueFrom(\n\t\t\t\t\t\t\t\t\tfromAny<LLMResponse>(\n\t\t\t\t\t\t\t\t\t\tp.adapter.invoke(buildMessages(p), {\n\t\t\t\t\t\t\t\t\t\t\tsignal: ac.signal,\n\t\t\t\t\t\t\t\t\t\t}) as NodeInput<LLMResponse>,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (cancelled) return;\n\t\t\t\t\t\t\t\tturns.push({ round: r, role: p.role, content: res.content });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!cancelled) actions.emit({ round: r, turns });\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tif (!cancelled) actions.down([[ERROR, err]]);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t\t\tac.abort();\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{ describeKind: \"producer\", name: `${name}.round-work` },\n\t\t\t),\n\t\t{ name: `${name}.rounds` },\n\t);\n\tgraph.add(roundWork, { name: \"rounds\" });\n\n\t// --- transcript: scan-accumulate (external observability) -----------------\n\tconst transcript = createNode<readonly Turn[]>(\n\t\t[roundWork],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst env = (\n\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0]\n\t\t\t) as RoundEnvelope | undefined;\n\t\t\tif (env === undefined) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit(history.slice());\n\t\t},\n\t\t{ name: `${name}.transcript`, describeKind: \"derived\" },\n\t);\n\tgraph.add(transcript, { name: \"transcript\" });\n\n\t// --- converged: parallel derived for external `status` (NOT authority) ----\n\tconst converged = createNode<{ done: boolean; reason: DebateStatus }>(\n\t\t[transcript as Node, untilNode as Node],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst tr = (\n\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : ctx.prevData[0]\n\t\t\t) as readonly Turn[] | undefined;\n\t\t\tconst untilV = (\n\t\t\t\tbatchData[1] != null && batchData[1].length > 0 ? batchData[1].at(-1) : ctx.prevData[1]\n\t\t\t) as boolean | undefined;\n\t\t\tconst rounds = (tr ?? []).reduce((m, t) => Math.max(m, t.round), 0);\n\t\t\tif (typeof term === \"number\") {\n\t\t\t\tactions.emit({ done: rounds >= term, reason: \"max-rounds\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (term === \"until-converge\") {\n\t\t\t\tif (converge(tr ?? [])) actions.emit({ done: true, reason: \"converged\" });\n\t\t\t\telse actions.emit({ done: rounds >= maxRounds, reason: \"max-rounds\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tactions.emit({ done: untilV === true || rounds >= maxRounds, reason: \"max-rounds\" });\n\t\t},\n\t\t{ name: `${name}.converged`, describeKind: \"derived\" },\n\t);\n\tgraph.add(converged, { name: \"converged\" });\n\n\t// --- decideEffect: SOLE feedback authority (§7 single-trigger) ------------\n\t// Computes termination INLINE (round envelope + closure history + the\n\t// reactive `untilNode` dep) — does NOT read `converged.cache` (avoids the\n\t// same-wave drain-order hazard refineLoop documents). `converged` above is\n\t// purely for external observation.\n\tconst decideEffect = createNode(\n\t\t[roundWork as Node, untilNode as Node],\n\t\t(batchData, _actions, ctx) => {\n\t\t\tconst env = (\n\t\t\t\tbatchData[0] != null && batchData[0].length > 0 ? batchData[0].at(-1) : undefined\n\t\t\t) as RoundEnvelope | undefined;\n\t\t\tconst untilV = (\n\t\t\t\tbatchData[1] != null && batchData[1].length > 0 ? batchData[1].at(-1) : ctx.prevData[1]\n\t\t\t) as boolean | undefined;\n\t\t\tif (env === undefined) {\n\t\t\t\t// `until` flipped with no new round — finalize if it went true.\n\t\t\t\tif (typeof term === \"object\" && untilV === true && statusState.cache === \"running\") {\n\t\t\t\t\tfinalize(\"max-rounds\");\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// New round settled — fold into the closure history first.\n\t\t\thistory = [...history, ...env.turns];\n\t\t\tconst r = env.round;\n\t\t\tlet done = false;\n\t\t\tlet reason: DebateStatus = \"max-rounds\";\n\t\t\tif (typeof term === \"number\") done = r >= term;\n\t\t\telse if (term === \"until-converge\") {\n\t\t\t\tif (converge(history)) {\n\t\t\t\t\tdone = true;\n\t\t\t\t\treason = \"converged\";\n\t\t\t\t} else done = r >= maxRounds;\n\t\t\t} else done = untilV === true || r >= maxRounds;\n\n\t\t\tif (done) finalize(reason);\n\t\t\telse roundTrigger.emit(r + 1); // §7 feedback edge\n\t\t},\n\t\t{ name: `${name}.decide`, describeKind: \"effect\", errorWhenDepsError: false },\n\t);\n\tgraph.add(decideEffect, { name: \"decide\" });\n\n\tfunction finalize(reason: DebateStatus): void {\n\t\tlet out: unknown;\n\t\tif (output === \"transcript\") out = history.slice();\n\t\telse if (output === \"synthesizer-final\") {\n\t\t\tconst synth = [...history].reverse().find((t) => SYNTH_RE.test(t.role));\n\t\t\tout = synth?.content ?? null;\n\t\t} else out = output.project(history.slice());\n\t\tbatch(() => {\n\t\t\tstatusState.emit(reason);\n\t\t\tresultState.emit(out);\n\t\t});\n\t}\n\n\t// Error watcher — adapter throw surfaces as ERROR on roundWork.\n\tconst errorWatcher = createNode(\n\t\t[roundWork as Node],\n\t\t(_b, _a, ec) => {\n\t\t\tconst t = ec.terminalDeps[0];\n\t\t\tif (t !== undefined && t !== true && statusState.cache === \"running\") {\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusState.emit(\"error\");\n\t\t\t\t\tresultState.emit(new Error(\"heterogeneousDebate: a participant adapter errored\"));\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t{ name: `${name}.error-watcher`, describeKind: \"effect\", errorWhenDepsError: false },\n\t);\n\tgraph.add(errorWatcher, { name: \"error-watcher\" });\n\n\t// Keepalive: activate the feedback + observability nodes so the loop runs\n\t// and `.cache` stays warm without an external subscriber. These live for\n\t// the graph's lifetime (torn down on parent-graph destroy).\n\tdecideEffect.subscribe(() => undefined);\n\terrorWatcher.subscribe(() => undefined);\n\ttranscript.subscribe(() => undefined);\n\tconverged.subscribe(() => undefined);\n\n\tlet running = false;\n\n\treturn {\n\t\ttranscript,\n\t\tresult: resultState,\n\t\tstatus: statusState,\n\t\tgraph,\n\t\tasync run(): Promise<unknown> {\n\t\t\tif (running) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`heterogeneousDebate \"${name}\": run() called while a previous run() is still pending`,\n\t\t\t\t);\n\t\t\t}\n\t\t\trunning = true;\n\t\t\ttry {\n\t\t\t\thistory = [];\n\t\t\t\tbatch(() => {\n\t\t\t\t\tstatusState.emit(\"running\");\n\t\t\t\t\tresultState.down([[INVALIDATE]]);\n\t\t\t\t});\n\t\t\t\t// Subscribe BEFORE the kick (sync adapters would otherwise drain\n\t\t\t\t// the terminal before awaitSettled subscribes).\n\t\t\t\tconst settled = awaitSettled(resultState, { skipCurrent: true });\n\t\t\t\troundTrigger.emit(1); // kick\n\t\t\t\treturn await settled;\n\t\t\t} finally {\n\t\t\t\trunning = false;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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","names":["import_core","import_core","import_core","import_extra","import_graph","import_core","import_extra","import_graph","import_core","import_extra","batch","import_core","import_extra","import_graph","import_core","import_core","import_extra","import_graph","batch","import_core","import_extra","import_core","batch","import_core","import_extra","import_graph","batch","nodeFactory","batch","import_core","import_extra","import_graph","import_core","import_extra","import_core","import_extra","isNodeLike","keepalive","node","batch","import_core","import_extra","import_graph","ageSeconds","import_core","import_extra","import_graph","NS_PER_SEC","batch","out","ageSeconds","import_core","import_core","import_extra","batch","batch","import_extra","import_core","import_extra","import_graph","policy","import_core","import_extra","import_graph","createNode"]}
|