@graphrefly/graphrefly 0.47.1 → 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 +28 -19
- 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 +9 -9
- package/dist/base/index.cjs +294 -164
- 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 +77 -72
- package/dist/base/io/index.cjs +145 -85
- 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 +5 -5
- 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 +18 -12
- 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 +18 -12
- package/dist/base/sources/browser/index.js.map +1 -1
- package/dist/base/sources/event/index.cjs +29 -1
- 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 +5 -2
- package/dist/base/sources/index.cjs +96 -50
- 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 +7 -4
- package/dist/base/sources/node/index.cjs +43 -37
- package/dist/base/sources/node/index.cjs.map +1 -1
- package/dist/base/sources/node/index.js +43 -37
- package/dist/base/sources/node/index.js.map +1 -1
- package/dist/{chunk-J5WFUEO4.js → chunk-23MAWVOJ.js} +3 -3
- package/dist/{chunk-YXCPV26R.js → chunk-3REMCHSS.js} +39 -27
- 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-EVYY4X5A.js → chunk-46X2EFQH.js} +16 -5
- 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-RGMTUZCL.js → chunk-65OM4XLQ.js} +50 -4
- 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-7EGRP2VX.js → chunk-7BULJTL6.js} +2 -2
- package/dist/{chunk-7EGRP2VX.js.map → chunk-7BULJTL6.js.map} +1 -1
- package/dist/{chunk-VLAGJZSL.js → chunk-7T7WLEPM.js} +25 -4
- 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-2OB3CEJS.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-MTTRCEJT.js → chunk-DVTDF5OI.js} +2 -2
- package/dist/{chunk-SOOKUYVM.js → chunk-F7EKHR32.js} +13 -9
- package/dist/chunk-F7EKHR32.js.map +1 -0
- package/dist/{chunk-A7KV5UK4.js → chunk-G7H6PN7P.js} +2 -2
- package/dist/{chunk-OCUDSN63.js → chunk-GGKHHG5Y.js} +110 -64
- package/dist/chunk-GGKHHG5Y.js.map +1 -0
- package/dist/{chunk-RAGGHLCV.js → chunk-GUNIRPEJ.js} +8 -6
- package/dist/{chunk-RAGGHLCV.js.map → chunk-GUNIRPEJ.js.map} +1 -1
- package/dist/{chunk-YJ4U2D2C.js → chunk-J5TBZFBD.js} +9 -7
- package/dist/chunk-J5TBZFBD.js.map +1 -0
- package/dist/{chunk-Y52CS6YA.js → chunk-JA67ZQG2.js} +2 -2
- package/dist/{chunk-Y52CS6YA.js.map → chunk-JA67ZQG2.js.map} +1 -1
- package/dist/{chunk-U225SKB4.js → chunk-K4ZYJ4EM.js} +569 -424
- package/dist/chunk-K4ZYJ4EM.js.map +1 -0
- package/dist/{chunk-Z4YXAUDN.js → chunk-KUFXLAEY.js} +11 -7
- package/dist/{chunk-Z4YXAUDN.js.map → chunk-KUFXLAEY.js.map} +1 -1
- package/dist/{chunk-IHTWQEDR.js → chunk-LTSI7ULC.js} +3 -3
- package/dist/{chunk-IHTWQEDR.js.map → chunk-LTSI7ULC.js.map} +1 -1
- package/dist/{chunk-DKNHAICT.js → chunk-MMHGYX44.js} +25 -9
- package/dist/chunk-MMHGYX44.js.map +1 -0
- package/dist/{chunk-K7PDZYQE.js → chunk-MQMTRKY3.js} +129 -50
- 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-O3MT7DYI.js → chunk-N6MNJNHB.js} +2 -2
- 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-DM4OMPWK.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-PZWISPIQ.js → chunk-S7HN5FHL.js} +17 -11
- package/dist/chunk-S7HN5FHL.js.map +1 -0
- package/dist/{chunk-4S53H2KR.js → chunk-SUNCHMML.js} +2 -2
- package/dist/{chunk-4GYMCUDZ.js → chunk-T2U6N3FV.js} +7 -7
- package/dist/{chunk-RJOG4IJU.js → chunk-T5URUIIY.js} +50 -35
- package/dist/chunk-T5URUIIY.js.map +1 -0
- package/dist/{chunk-B4AKFXGE.js → chunk-TPTZZV25.js} +6 -6
- package/dist/chunk-TPTZZV25.js.map +1 -0
- package/dist/{chunk-BU3SEFA5.js → chunk-V46JWFGV.js} +7 -6
- package/dist/chunk-V46JWFGV.js.map +1 -0
- package/dist/{chunk-IJRR6YAI.js → chunk-VLDRAMP7.js} +18 -12
- package/dist/chunk-VLDRAMP7.js.map +1 -0
- package/dist/{chunk-6XZYT4SW.js → chunk-X6ESZDR6.js} +8 -9
- package/dist/chunk-X6ESZDR6.js.map +1 -0
- package/dist/{chunk-E5OZPDIW.js → chunk-X7BA5PWG.js} +7 -5
- package/dist/chunk-X7BA5PWG.js.map +1 -0
- package/dist/{chunk-CXANAIZU.js → chunk-XEWV254I.js} +3 -3
- package/dist/{chunk-CXANAIZU.js.map → chunk-XEWV254I.js.map} +1 -1
- package/dist/{chunk-V4Y3TM7U.js → chunk-YBJVKMTM.js} +38 -16
- package/dist/chunk-YBJVKMTM.js.map +1 -0
- package/dist/{chunk-7ADWWI2T.js → chunk-ZW32BPXV.js} +17 -6
- package/dist/chunk-ZW32BPXV.js.map +1 -0
- package/dist/compat/index.cjs +52 -5
- 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 +7 -7
- package/dist/compat/nestjs/index.cjs +52 -5
- 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 +4 -4
- 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 +2387 -1707
- 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 +173 -150
- package/dist/index.js.map +1 -1
- package/dist/presets/ai/index.cjs +88 -26
- package/dist/presets/ai/index.cjs.map +1 -1
- package/dist/presets/ai/index.js +14 -14
- package/dist/presets/harness/index.cjs +183 -51
- 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 +26 -26
- package/dist/presets/index.cjs +298 -101
- 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 +49 -49
- 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 +64 -44
- 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 +6 -6
- 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 +239 -92
- 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 +32 -32
- 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/{timeout-U5O4ESK3.js → timeout-BEABACRP.js} +2 -2
- 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 +10 -10
- package/dist/utils/ai/browser.js.map +1 -1
- package/dist/utils/ai/index.cjs +291 -191
- 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 +23 -21
- 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 +3 -3
- 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 +1 -1
- 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 +1 -1
- package/dist/utils/graphspec/index.cjs.map +1 -1
- package/dist/utils/graphspec/index.js +3 -3
- package/dist/utils/harness/index.cjs +16 -10
- package/dist/utils/harness/index.cjs.map +1 -1
- package/dist/utils/harness/index.js +1 -1
- package/dist/utils/index.cjs +1692 -1192
- 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 +77 -59
- 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 +570 -425
- package/dist/utils/memory/index.cjs.map +1 -1
- package/dist/utils/memory/index.d.cts +261 -33
- package/dist/utils/memory/index.d.ts +261 -33
- 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 +14 -3
- 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 +3 -3
- 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 +1 -1
- package/dist/utils/reduction/index.cjs.map +1 -1
- package/dist/utils/reduction/index.js +2 -2
- package/dist/utils/resilience/index.cjs +64 -43
- 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 +5 -5
- package/dist/utils/surface/index.cjs +1 -1
- 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-3PSLNJDU.js.map +0 -1
- package/dist/chunk-42FQ27MQ.js.map +0 -1
- package/dist/chunk-4XCHZRUJ.js.map +0 -1
- package/dist/chunk-6XZYT4SW.js.map +0 -1
- package/dist/chunk-7ADWWI2T.js.map +0 -1
- package/dist/chunk-B4AKFXGE.js.map +0 -1
- package/dist/chunk-BU3SEFA5.js.map +0 -1
- package/dist/chunk-BXGZFGZ4.js.map +0 -1
- package/dist/chunk-DKNHAICT.js.map +0 -1
- package/dist/chunk-E5OZPDIW.js.map +0 -1
- package/dist/chunk-EVYY4X5A.js.map +0 -1
- package/dist/chunk-IJRR6YAI.js.map +0 -1
- package/dist/chunk-K7PDZYQE.js.map +0 -1
- package/dist/chunk-NPRP3MCV.js.map +0 -1
- package/dist/chunk-NY2PYHNC.js.map +0 -1
- package/dist/chunk-OCUDSN63.js.map +0 -1
- package/dist/chunk-PKPO3JTZ.js.map +0 -1
- package/dist/chunk-PZWISPIQ.js.map +0 -1
- package/dist/chunk-RGMTUZCL.js.map +0 -1
- package/dist/chunk-RJOG4IJU.js.map +0 -1
- package/dist/chunk-SOOKUYVM.js.map +0 -1
- package/dist/chunk-U225SKB4.js.map +0 -1
- package/dist/chunk-V4Y3TM7U.js.map +0 -1
- package/dist/chunk-VLAGJZSL.js.map +0 -1
- package/dist/chunk-W2BOPXTI.js +0 -1
- package/dist/chunk-YJ4U2D2C.js.map +0 -1
- package/dist/chunk-YXCPV26R.js.map +0 -1
- package/dist/timeout-U5O4ESK3.js.map +0 -1
- /package/dist/{chunk-J5WFUEO4.js.map → chunk-23MAWVOJ.js.map} +0 -0
- /package/dist/{chunk-2OB3CEJS.js.map → chunk-B5Y5GPD5.js.map} +0 -0
- /package/dist/{chunk-MTTRCEJT.js.map → chunk-DVTDF5OI.js.map} +0 -0
- /package/dist/{chunk-A7KV5UK4.js.map → chunk-G7H6PN7P.js.map} +0 -0
- /package/dist/{chunk-O3MT7DYI.js.map → chunk-N6MNJNHB.js.map} +0 -0
- /package/dist/{chunk-DM4OMPWK.js.map → chunk-NSA5K5G2.js.map} +0 -0
- /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
- /package/dist/{chunk-4S53H2KR.js.map → chunk-SUNCHMML.js.map} +0 -0
- /package/dist/{chunk-4GYMCUDZ.js.map → chunk-T2U6N3FV.js.map} +0 -0
- /package/dist/{chunk-W2BOPXTI.js.map → timeout-BEABACRP.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/orchestration/human-input.ts","../src/utils/orchestration/pipeline-graph.ts","../src/utils/orchestration/tracker.ts"],"sourcesContent":["/**\n * Phase 13.F — `humanInput<T>` sibling preset.\n *\n * Source: `archive/docs/SESSION-human-llm-intervention-primitives.md` §5\n * \"Sibling presets on the substrate\" + §9 Phase 2.\n *\n * **Role.** LLM↔human runtime Q&A channel. The agent (or any consumer)\n * reactively asks for human input by emitting a prompt; humanInput\n * publishes a {@link Message} envelope to the well-known\n * {@link PROMPTS_TOPIC} on the hub and watches {@link RESPONSES_TOPIC} for\n * the matching `correlationId`. When the response arrives, humanInput's\n * output Node emits the typed payload `T`.\n *\n * **Sibling to `approvalGate`** ([pipeline-graph.ts](pipeline-graph.ts)):\n * approvalGate is design-time veto on a topology edge; humanInput is a\n * runtime Q&A channel. They share substrate (hub + envelope) but differ\n * in role and initiator.\n *\n * **No imperative `.run()` / `.ask()`** — caller writes to `prompt` (any\n * `NodeInput<string>`) and reads `humanInput()`'s output Node.\n *\n * **Multi-prompt.** Each new `prompt` DATA mints a fresh correlationId\n * and a new pending request. The output Node's emission tracks the latest\n * correlationId — earlier in-flight requests are abandoned (switchMap\n * semantics). To run parallel requests, instantiate two humanInput nodes.\n */\n\nimport { COMPLETE, DATA, type Node, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport {\n\ttype JsonSchema,\n\ttype MessagingHubGraph,\n\tPROMPTS_TOPIC,\n\tRESPONSES_TOPIC,\n\ttype TopicMessage,\n} from \"../messaging/index.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Outbound prompt envelope payload. */\nexport interface HumanPromptPayload {\n\treadonly prompt: string;\n\treadonly schema?: JsonSchema;\n}\n\n/**\n * Options for {@link humanInput}.\n */\nexport interface HumanInputOpts {\n\t/**\n\t * Messaging hub. {@link PROMPTS_TOPIC} is created lazily for outbound\n\t * prompts; {@link RESPONSES_TOPIC} is read for incoming responses.\n\t */\n\treadonly hub: MessagingHubGraph;\n\t/**\n\t * Reactive prompt source. Any `NodeInput<string>` is accepted (Node,\n\t * Promise, AsyncIterable, scalar) — coerced via `fromAny`. Each new\n\t * DATA on this input mints a fresh request.\n\t */\n\treadonly prompt: NodeInput<string>;\n\t/**\n\t * Optional response-shape schema. Carried in the prompt envelope for\n\t * UI / consumer-side validation. Caller-supplied validators (ajv,\n\t * zod, valibot) consume this field; the substrate doesn't validate.\n\t */\n\treadonly schema?: JsonSchema;\n\t/**\n\t * Optional ID generator for the per-prompt correlationId. Default is\n\t * a monotonic counter derived from a tight closure (sufficient for\n\t * in-process correlation; cross-process consumers should supply UUID\n\t * / ULID generation).\n\t */\n\treadonly idGenerator?: () => string;\n}\n\n// ---------------------------------------------------------------------------\n// humanInput\n// ---------------------------------------------------------------------------\n\n/**\n * Constructs a reactive human-input request channel. Each DATA on\n * `prompt` mints a fresh request:\n *\n * 1. Mints a fresh `correlationId` (via `opts.idGenerator` if provided).\n * 2. Publishes `TopicMessage<HumanPromptPayload>` to {@link PROMPTS_TOPIC}\n * (`{ id, schema?, correlationId, payload: { prompt, schema? } }`).\n * 3. Watches {@link RESPONSES_TOPIC} for an envelope whose\n * `correlationId` matches.\n * 4. When matched, emits the response payload as the output Node's DATA.\n *\n * **Switchmap semantics.** A new prompt arriving before the prior\n * response abandons the prior wait. Output Node emits the response for\n * the latest in-flight request only.\n *\n * **Output type `T`** is the response payload type. Caller is responsible\n * for ensuring the response producer (UI / human-side) sends the right\n * shape — `schema` is the wire-level convention for validation.\n *\n * @example\n * ```ts\n * import {\n * humanInput,\n * messagingHub,\n * PROMPTS_TOPIC,\n * RESPONSES_TOPIC,\n * } from \"@graphrefly/graphrefly-ts\";\n *\n * const hub = messagingHub(\"hub\");\n * const promptN = state<string>(\"prompt\");\n * const reply = humanInput<{ ok: boolean; reason: string }>({\n * hub,\n * prompt: promptN,\n * schema: { type: \"object\", required: [\"ok\", \"reason\"] },\n * });\n *\n * // UI / human side: subscribe to PROMPTS_TOPIC, present, then publish to\n * // RESPONSES_TOPIC with the matching correlationId.\n * promptN.emit(\"Approve change?\");\n * const decision = await awaitSettled(reply); // resolves when human responds\n * ```\n *\n * @category patterns\n */\nexport function humanInput<T>(opts: HumanInputOpts): Node<T> {\n\tconst { hub, prompt, schema, idGenerator } = opts;\n\tconst promptNode = fromAny<string>(prompt);\n\tconst promptsTopic = hub.topic<TopicMessage<HumanPromptPayload>>(PROMPTS_TOPIC);\n\tconst responsesTopic = hub.topic<TopicMessage<T>>(RESPONSES_TOPIC);\n\n\tconst nextId = idGenerator ?? defaultIdGenerator();\n\n\treturn node<T>(\n\t\t(_data, a) => {\n\t\t\tlet activeCorrelationId: string | undefined;\n\t\t\tlet respUnsub: (() => void) | undefined;\n\n\t\t\tconst promptUnsub = promptNode.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\t\trespUnsub?.();\n\t\t\t\t\t\trespUnsub = undefined;\n\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (m[0] !== DATA) continue;\n\t\t\t\t\tconst promptStr = m[1] as string;\n\t\t\t\t\t// Switch-map semantics: drop the prior in-flight watcher.\n\t\t\t\t\trespUnsub?.();\n\t\t\t\t\trespUnsub = undefined;\n\t\t\t\t\t// Mint new correlationId.\n\t\t\t\t\tconst correlationId = nextId();\n\t\t\t\t\tactiveCorrelationId = correlationId;\n\n\t\t\t\t\t// Snapshot the responses topic length BEFORE publishing so\n\t\t\t\t\t// we only consider envelopes that arrive AFTER this\n\t\t\t\t\t// subscription. Eliminates the stale-replay-on-subscribe\n\t\t\t\t\t// hazard (push-on-subscribe of `events` delivers the full\n\t\t\t\t\t// retained log, which could include an unrelated old\n\t\t\t\t\t// envelope whose `correlationId` happens to match if the\n\t\t\t\t\t// caller's id-generator is non-unique).\n\t\t\t\t\tconst responseCursorAtSubscribe =\n\t\t\t\t\t\t(responsesTopic.events.cache as readonly TopicMessage<T>[] | undefined)?.length ?? 0;\n\n\t\t\t\t\t// Publish the prompt envelope. Schema is carried at\n\t\t\t\t\t// envelope-level only (Phase 13.B TopicMessage<T> contract);\n\t\t\t\t\t// the payload itself is `HumanPromptPayload` and stays\n\t\t\t\t\t// schema-free.\n\t\t\t\t\tconst envelope: TopicMessage<HumanPromptPayload> = {\n\t\t\t\t\t\tid: correlationId,\n\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\tpayload: { prompt: promptStr },\n\t\t\t\t\t\t...(schema != null && { schema }),\n\t\t\t\t\t};\n\t\t\t\t\tpromptsTopic.publish(envelope);\n\n\t\t\t\t\t// Watch responses topic for matching correlationId, but\n\t\t\t\t\t// skip the retained log (only consider envelopes at index\n\t\t\t\t\t// >= responseCursorAtSubscribe).\n\t\t\t\t\trespUnsub = responsesTopic.events.subscribe((rspMsgs) => {\n\t\t\t\t\t\tfor (const rm of rspMsgs) {\n\t\t\t\t\t\t\tif (rm[0] !== DATA) continue;\n\t\t\t\t\t\t\tconst arr = rm[1] as readonly TopicMessage<T>[];\n\t\t\t\t\t\t\tfor (let i = responseCursorAtSubscribe; i < arr.length; i++) {\n\t\t\t\t\t\t\t\tconst env = arr[i] as TopicMessage<T>;\n\t\t\t\t\t\t\t\tif (env.correlationId === activeCorrelationId) {\n\t\t\t\t\t\t\t\t\ta.emit(env.payload);\n\t\t\t\t\t\t\t\t\t// One-shot per prompt — next prompt re-arms the watcher.\n\t\t\t\t\t\t\t\t\trespUnsub?.();\n\t\t\t\t\t\t\t\t\trespUnsub = undefined;\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}\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\treturn () => {\n\t\t\t\tpromptUnsub();\n\t\t\t\trespUnsub?.();\n\t\t\t};\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\tname: \"humanInput\",\n\t\t\t// Each new prompt may produce a structurally-equal response (e.g.\n\t\t\t// from a deterministic UI mock) — disable framework dedup so\n\t\t\t// repeat emissions propagate. Same precedent as `agent.out`.\n\t\t\tequals: () => false,\n\t\t},\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Default ID generator\n// ---------------------------------------------------------------------------\n\nfunction defaultIdGenerator(): () => string {\n\tlet n = 0;\n\t// `wallClockNs()` routes through the central clock per CLAUDE.md \"Time\n\t// utility rule\" — testing harnesses that monkey-patch the clock can pin\n\t// id generation deterministically.\n\tconst base = wallClockNs().toString(36);\n\treturn () => {\n\t\tn += 1;\n\t\treturn `humanInput-${base}-${n.toString(36)}`;\n\t};\n}\n","/**\n * PipelineGraph subclass (Wave A.1 Unit 1 — locked 2026-04-24).\n *\n * Specialized {@link Graph} that hosts workflow-DAG sugar methods:\n * `task` / `classify` / `combine` / `approval` / `approvalGate` / `catch`.\n * The legacy `pipeline` / `task` / `branch` / `join` / `subPipeline` /\n * `approval` / `loop` / `onFailure` factories from {@link ./index} continue\n * to work for migration ease; new code should prefer methods on this class.\n *\n * **Tier 2.3 rename:** the prior `gate(...)` method is now `approvalGate(...)`,\n * disambiguating it from the other gate-family primitives (`budgetGate` for\n * numeric constraints, `valve` for boolean switching, `policyGate` for ABAC\n * rules). The \"gating dimension\" here is **human judgment**.\n *\n * Construction: `pipelineGraph(name, opts?)` or `new PipelineGraph(name, opts)`.\n */\n\nimport type { NodeActions } from \"@graphrefly/pure-ts/core\";\nimport {\n\tbatch,\n\tCOMPLETE,\n\tDATA,\n\tERROR,\n\tfactoryTag,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\tplaceholderArgs,\n\tRESOLVED,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport type { ReactiveLogBundle } from \"@graphrefly/pure-ts/extra\";\nimport { Graph, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { domainMeta } from \"../../base/meta/domain-meta.js\";\nimport { type BaseAuditRecord, createAuditLog, mutate } from \"../../base/mutation/index.js\";\n\nexport type StepRef = string | Node<unknown>;\n\nfunction meta(kind: string, extra?: Record<string, unknown>): Record<string, unknown> {\n\treturn domainMeta(\"orchestration\", kind, extra);\n}\n\n// ── Decision audit record (Audit 2 + Wave A.2 Unit 8) ─────────────────────\n\nexport type DecisionAction =\n\t| \"approve\"\n\t| \"reject\"\n\t| \"modify\"\n\t| \"drop\"\n\t| \"open\"\n\t| \"close\"\n\t| \"teardown\";\n\nexport interface Decision<T = unknown> extends BaseAuditRecord {\n\treadonly action: DecisionAction;\n\treadonly count?: number;\n\treadonly items?: readonly T[];\n\treadonly unflushed?: number;\n}\n\n/** Recommended `keyOf` for keyed-storage adapters (Audit 2 #7). */\nexport const decisionKeyOf = <T>(d: Decision<T>): string => d.action;\n\n// ── Gate ─────────────────────────────────────────────────────────────────\n\nexport interface GateOptions<_T = unknown> {\n\t/** Bounded default 1000 (Audit 2 cross-cutting). `Infinity` is opt-in. */\n\tmaxPending?: number;\n\tstartOpen?: boolean;\n\t/**\n\t * Reactive auto-approve: gate's `latestIsOpen` mirrors this node's truthy\n\t * value. False→true transition drains the pending queue.\n\t *\n\t * **`COMPLETE` / `ERROR` on the approver are silently ignored** — the gate\n\t * stays in its current state. For permanent-open latching, use\n\t * `onceOnly: true` (the first truthy approval latches; subsequent falsy\n\t * values are ignored). The gate has no graceful terminal-state behavior\n\t * for the approver itself.\n\t */\n\tapprover?: Node<unknown>;\n\t/** Latch — first truthy approval opens permanently; `close()` becomes no-op. */\n\tonceOnly?: boolean;\n\tmeta?: Record<string, unknown>;\n\thandlerVersion?: { id: string; version: string | number };\n}\n\nexport interface GateController<T> {\n\t/**\n\t * The post-gate output node. Renamed from `node` (Tier 5.2 / EC6,\n\t * 2026-04-29) to avoid shadowing `Graph.node(name)` when a gate is\n\t * accessed off a `PipelineGraph` instance.\n\t */\n\treadonly output: Node<T>;\n\treadonly pending: Node<readonly T[]>;\n\treadonly count: Node<number>;\n\treadonly isOpen: Node<boolean>;\n\treadonly droppedCount: Node<number>;\n\treadonly decisions: ReactiveLogBundle<Decision<T>>;\n\treadonly audit: ReactiveLogBundle<Decision<T>>;\n\tapprove(count?: number): void;\n\treject(count?: number): void;\n\tmodify(fn: (value: T, index: number, pending: readonly T[]) => T, count?: number): void;\n\topen(): void;\n\tclose(): void;\n}\n\n// ── catch (rename of onFailure; Wave A.2 Unit 10) ─────────────────────────\n\n/**\n * Terminal-cause discriminator for the {@link PipelineGraph.catch} recovery\n * handler. Tier 1.6.3 status-enum migration: was `{ kind: \"complete\" | \"error\" }`\n * pre-1.0; aligned with the canonical lifecycle enum\n * (`status: \"running\" | \"completed\" | \"errored\" | \"cancelled\"`). The variant\n * structure is preserved — `errored` still carries `error: unknown` and\n * `completed` carries no payload.\n */\nexport type TerminalCause = { kind: \"errored\"; error: unknown } | { kind: \"completed\" };\n\nexport interface CatchOptions<_T> {\n\t/**\n\t * Which terminal cause to recover. Default `\"errored\"` (Tier 1.6.3 rename\n\t * of `\"error\"`). `\"completed\"` recovers COMPLETE; `\"terminal\"` recovers\n\t * either. Aligns with the canonical lifecycle enum that\n\t * {@link TerminalCause.kind} now uses.\n\t */\n\ton?: \"errored\" | \"completed\" | \"terminal\";\n\tcompleteWhenDepsComplete?: boolean;\n\tmeta?: Record<string, unknown>;\n\thandlerVersion?: { id: string; version: string | number };\n}\n\n// ── classify result envelope (Wave A.1 Unit 3) ───────────────────────────\n\nexport interface ClassifyResult<TTag extends string, T> {\n\treadonly tag: TTag | \"error\";\n\treadonly value: T;\n\treadonly error?: unknown;\n}\n\n// ── PipelineGraph ────────────────────────────────────────────────────────\n\nexport class PipelineGraph extends Graph {\n\t// -- task -----------------------------------------------------------------\n\n\t/**\n\t * Register a workflow task (`node` + auto-add). String deps resolve via\n\t * `this.resolve(path)`; Node deps via {@link Graph.nameOf} O(1) lookup.\n\t *\n\t * `run` receives `(data: readonly unknown[], ctx)` — the snapshot of latest\n\t * values per dep (same shape as the old `DerivedFn` sugar).\n\t */\n\ttask<T>(\n\t\tname: string,\n\t\trun: (data: readonly unknown[], ctx: { prevData: readonly unknown[] }) => T | undefined | null,\n\t\topts: { deps?: ReadonlyArray<StepRef>; meta?: Record<string, unknown> } = {},\n\t): Node<T> {\n\t\tconst deps = (opts.deps ?? []).map((d) => this._resolveStep(d));\n\t\tconst step = node<T>(\n\t\t\tdeps,\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 result = run(data, ctx);\n\t\t\t\tif (result !== undefined && result !== null) actions.emit(result);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"task\", opts.meta),\n\t\t\t} as NodeOptions<T>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- classify (n-way; replaces binary `branch`) --------------------------\n\n\tclassify<TTag extends string, T>(\n\t\tname: string,\n\t\tsource: StepRef,\n\t\ttagger: (value: T) => TTag,\n\t\topts: { meta?: Record<string, unknown> } = {},\n\t): Node<ClassifyResult<TTag, T>> {\n\t\tconst src = this._resolveStep(source);\n\t\tconst step = node<ClassifyResult<TTag, T>>(\n\t\t\t[src],\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 value = data[0];\n\t\t\t\ttry {\n\t\t\t\t\tactions.emit({ tag: tagger(value as T), value: value as T });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tactions.emit({ tag: \"error\" as const, value: value as T, error });\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"classify\", opts.meta),\n\t\t\t} as NodeOptions<ClassifyResult<TTag, T>>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- combine (keyed-record fan-in; replaces positional `join`) -----------\n\n\tcombine<R extends Record<string, StepRef>>(\n\t\tname: string,\n\t\tdeps: R,\n\t\topts: { meta?: Record<string, unknown> } = {},\n\t): Node<{ [K in keyof R]: unknown }> {\n\t\tconst keys = Object.keys(deps) as Array<keyof R & string>;\n\t\tconst nodes = keys.map((k) => this._resolveStep(deps[k] as StepRef));\n\t\tconst step = node<{ [K in keyof R]: unknown }>(\n\t\t\tnodes,\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 = {} as { [K in keyof R]: unknown };\n\t\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\t\t(out as Record<string, unknown>)[keys[i] as string] = values[i];\n\t\t\t\t}\n\t\t\t\tactions.emit(out);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"combine\", opts.meta),\n\t\t\t} as NodeOptions<{ [K in keyof R]: unknown }>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- approvalGate ---------------------------------------------------------\n\n\tapprovalGate<T>(name: string, source: StepRef, opts: GateOptions<T> = {}): GateController<T> {\n\t\tconst maxPending = opts.maxPending ?? 1000;\n\t\tif (maxPending < 1 && maxPending !== Number.POSITIVE_INFINITY) {\n\t\t\tthrow new RangeError(\"approvalGate: maxPending must be >= 1\");\n\t\t}\n\t\tconst startOpen = opts.startOpen ?? false;\n\n\t\t// C3 — wrap a foreign Node source in a local proxy derived. The proxy\n\t\t// is owned by THIS graph; downstream wiring uses the proxy (not the\n\t\t// foreign Node) so the cross-graph ownership invariant holds. Causal\n\t\t// chain is preserved via the dep edge — `describe()` still surfaces\n\t\t// the foreign Node's path through the proxy.\n\t\tlet src: Node<unknown>;\n\t\tif (typeof source === \"string\") {\n\t\t\tsrc = this._resolveStep(source);\n\t\t} else if (this.nameOf(source) !== undefined) {\n\t\t\tsrc = source;\n\t\t} else {\n\t\t\tconst proxy = node<unknown>(\n\t\t\t\t[source],\n\t\t\t\t(batchData, actions) => {\n\t\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\t\tif (batch0 == null || batch0.length === 0) return;\n\t\t\t\t\tfor (const v of batch0) actions.emit(v);\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\t\tmeta: factoryTag(\"proxy\"),\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.add(proxy, { name: `${name}/source` });\n\t\t\tsrc = proxy;\n\t\t}\n\n\t\t// State subgraph\n\t\tconst internal = new Graph(`${name}-state`);\n\t\tconst pendingNode = internal.state<readonly T[]>(\"pending\", [], {\n\t\t\tequals: () => false,\n\t\t});\n\t\tconst isOpenNode = internal.state<boolean>(\"isOpen\", startOpen);\n\t\tconst countNode = internal.derived<number>(\"count\", [\"pending\"], (batchData, 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\treturn [(data[0] as readonly T[]).length];\n\t\t});\n\t\tconst droppedCountNode = internal.state<number>(\"droppedCount\", 0);\n\t\tconst decisions = createAuditLog<Decision<T>>({\n\t\t\tname: \"decisions\",\n\t\t\tretainedLimit: 1024,\n\t\t\tgraph: internal,\n\t\t});\n\t\tthis.mount(`${name}-state`, internal);\n\n\t\tlet queue: T[] = [];\n\t\tlet torn = false;\n\t\tlet latched = false;\n\t\t// Closure-mirror per COMPOSITION-GUIDE §28 factory-time seed pattern.\n\t\t// `output` samples `latestIsOpen` inside its fn body when deciding\n\t\t// emit-vs-enqueue; reading a closure variable is NOT a P3 violation\n\t\t// (§28). An in-session Phase 9 plan would have relocated the value to\n\t\t// `internal.derived(\"latestIsOpen\", ...)` + `.cache` reads (which IS\n\t\t// a P3 violation); plan was reverted at the design level after\n\t\t// re-reading §28 — pattern preserved here. See `archive/docs/SESSION-\n\t\t// graph-narrow-waist.md` § \"Status of existing modifications\".\n\t\tlet latestIsOpen = startOpen;\n\t\tconst isOpenUnsub = isOpenNode.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === DATA) latestIsOpen = m[1] as boolean;\n\t\t\t}\n\t\t});\n\t\tthis.addDisposer(isOpenUnsub);\n\n\t\tfunction syncPending(): void {\n\t\t\tpendingNode.emit([...queue]);\n\t\t}\n\n\t\tfunction recordDecision(\n\t\t\taction: DecisionAction,\n\t\t\titems?: readonly T[],\n\t\t\tunflushed?: number,\n\t\t): void {\n\t\t\tdecisions.append({\n\t\t\t\taction,\n\t\t\t\tt_ns: wallClockNs(),\n\t\t\t\t...(items !== undefined ? { items, count: items.length } : {}),\n\t\t\t\t...(unflushed !== undefined ? { unflushed } : {}),\n\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t} as Decision<T>);\n\t\t}\n\n\t\tfunction enqueue(value: T): void {\n\t\t\tqueue.push(value);\n\t\t\tif (queue.length > maxPending) {\n\t\t\t\tconst dropped = queue.shift() as T;\n\t\t\t\tdroppedCountNode.emit((droppedCountNode.cache as number) + 1);\n\t\t\t\trecordDecision(\"drop\", [dropped]);\n\t\t\t}\n\t\t\tsyncPending();\n\t\t}\n\n\t\tfunction dequeue(n: number): T[] {\n\t\t\tconst items = queue.splice(0, n);\n\t\t\tsyncPending();\n\t\t\treturn items;\n\t\t}\n\n\t\tconst output = node<T>(\n\t\t\t[src],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst terminal = ctx.terminalDeps[0];\n\t\t\t\tif (terminal !== undefined) {\n\t\t\t\t\ttorn = true;\n\t\t\t\t\tconst unflushed = queue.length;\n\t\t\t\t\tqueue = [];\n\t\t\t\t\tsyncPending();\n\t\t\t\t\trecordDecision(\"teardown\", undefined, unflushed);\n\t\t\t\t\tactions.down(terminal === true ? [[COMPLETE]] : [[ERROR, terminal]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tif (batch0 == null || batch0.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\tfor (const v of batch0 as T[]) {\n\t\t\t\t\tif (latestIsOpen) {\n\t\t\t\t\t\tactions.emit(v);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tenqueue(v);\n\t\t\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tmeta: meta(\"approval_gate\", opts.meta),\n\t\t\t},\n\t\t);\n\t\tthis.add(output, { name });\n\n\t\t// Reactive approver mode: mirror latestIsOpen to the approver's value.\n\t\t// **m1:** approver `COMPLETE` / `ERROR` are silently ignored — gate stays\n\t\t// in current state. For latching behavior, use `onceOnly: true`.\n\t\tif (opts.approver != null) {\n\t\t\tconst initialApproved = Boolean(opts.approver.cache);\n\t\t\tif (initialApproved) {\n\t\t\t\tisOpenNode.emit(true);\n\t\t\t\tlatestIsOpen = true;\n\t\t\t\tif (opts.onceOnly) latched = true;\n\t\t\t}\n\t\t\tconst approverSub = opts.approver.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 truthy = Boolean(m[1]);\n\t\t\t\t\tif (truthy && !latestIsOpen) {\n\t\t\t\t\t\t// false → true transition\n\t\t\t\t\t\tif (opts.onceOnly) {\n\t\t\t\t\t\t\tif (latched) continue;\n\t\t\t\t\t\t\tlatched = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tisOpenNode.emit(true);\n\t\t\t\t\t\t\tconst items = dequeue(queue.length);\n\t\t\t\t\t\t\t// M11: include items count in approver-driven open decisions\n\t\t\t\t\t\t\t// so audit consumers see how many items were flushed.\n\t\t\t\t\t\t\trecordDecision(\"open\", items);\n\t\t\t\t\t\t\tfor (const item of items) {\n\t\t\t\t\t\t\t\tif (torn) break;\n\t\t\t\t\t\t\t\toutput.emit(item);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (!truthy && latestIsOpen) {\n\t\t\t\t\t\tif (opts.onceOnly && latched) continue;\n\t\t\t\t\t\tbatch(() => {\n\t\t\t\t\t\t\tisOpenNode.emit(false);\n\t\t\t\t\t\t\trecordDecision(\"close\");\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(approverSub);\n\t\t}\n\n\t\tconst guardTorn = (method: string): void => {\n\t\t\tif (torn) throw new Error(`approvalGate: ${method}() called after the gate was torn down`);\n\t\t};\n\n\t\tconst approveImpl = (count = 1): void => {\n\t\t\tguardTorn(\"approve\");\n\t\t\tconst items = dequeue(count);\n\t\t\tfor (const item of items) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.emit(item);\n\t\t\t}\n\t\t};\n\t\tconst rejectImpl = (count = 1): void => {\n\t\t\tguardTorn(\"reject\");\n\t\t\tdequeue(count);\n\t\t};\n\t\tconst modifyImpl = (\n\t\t\tfn: (value: T, index: number, pending: readonly T[]) => T,\n\t\t\tcount = 1,\n\t\t): void => {\n\t\t\tguardTorn(\"modify\");\n\t\t\tconst snapshot = [...queue] as readonly T[];\n\t\t\tconst items = dequeue(count);\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.emit(fn(items[i], i, snapshot));\n\t\t\t}\n\t\t};\n\t\tconst openImpl = (): void => {\n\t\t\tguardTorn(\"open\");\n\t\t\tisOpenNode.emit(true);\n\t\t\tconst items = dequeue(queue.length);\n\t\t\tfor (const item of items) {\n\t\t\t\tif (torn) break;\n\t\t\t\toutput.emit(item);\n\t\t\t}\n\t\t};\n\t\tconst closeImpl = (): void => {\n\t\t\tguardTorn(\"close\");\n\t\t\tif (opts.onceOnly && latched) return;\n\t\t\tisOpenNode.emit(false);\n\t\t};\n\n\t\tconst approve = mutate(approveImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (args, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"approve\",\n\t\t\t\t\tcount: (args[0] as number | undefined) ?? 1,\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst reject = mutate(rejectImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (args, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"reject\",\n\t\t\t\t\tcount: (args[0] as number | undefined) ?? 1,\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst modify = mutate(modifyImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (args, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"modify\",\n\t\t\t\t\tcount: (args[1] as number | undefined) ?? 1,\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst open = mutate(openImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (_a, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"open\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\t\tconst close = mutate(closeImpl, {\n\t\t\tframe: \"transactional\",\n\t\t\tlog: decisions,\n\t\t\tfreeze: false,\n\t\t\tonSuccessRecord: (_a, _r, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"close\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t\tonFailureRecord: (_a, _e, m) =>\n\t\t\t\t({\n\t\t\t\t\taction: \"drop\",\n\t\t\t\t\tt_ns: m.t_ns,\n\t\t\t\t\terrorType: m.errorType,\n\t\t\t\t\t...(opts.handlerVersion != null ? { handlerVersion: opts.handlerVersion } : {}),\n\t\t\t\t}) as Decision<T>,\n\t\t});\n\n\t\tthis.addDisposer(countNode.subscribe(() => undefined));\n\n\t\tconst controller: GateController<T> = {\n\t\t\toutput,\n\t\t\tpending: pendingNode,\n\t\t\tcount: countNode,\n\t\t\tisOpen: isOpenNode,\n\t\t\tdroppedCount: droppedCountNode,\n\t\t\tdecisions,\n\t\t\taudit: decisions,\n\t\t\tapprove,\n\t\t\treject,\n\t\t\tmodify,\n\t\t\topen,\n\t\t\tclose,\n\t\t};\n\t\treturn controller;\n\t}\n\n\t// -- approval (thin alias over approvalGate({ approver, maxPending: 1 })) -\n\n\t/**\n\t * Reactive approval step: passes items through when `approver` is truthy;\n\t * holds at most one pending item (maxPending: 1) when falsy. A thin alias\n\t * over `approvalGate({ approver, maxPending: 1 })` — use `approvalGate()`\n\t * directly for finer control (maxPending, onceOnly, manual approve/reject).\n\t */\n\tapproval<T>(\n\t\tname: string,\n\t\tsource: StepRef,\n\t\tapprover: Node<unknown>,\n\t\topts: Omit<GateOptions<T>, \"approver\" | \"maxPending\"> = {},\n\t): GateController<T> {\n\t\treturn this.approvalGate<T>(name, source, { ...opts, approver, maxPending: 1 });\n\t}\n\n\t// -- catch (renamed onFailure; dep-channel intercept) -------------------\n\n\tcatch<T>(\n\t\tname: string,\n\t\tsource: StepRef,\n\t\trecover: (cause: TerminalCause, actions: NodeActions) => T,\n\t\topts: CatchOptions<T> = {},\n\t): Node<T> {\n\t\tconst src = this._resolveStep(source);\n\t\tconst mode = opts.on ?? \"errored\";\n\t\tconst step = node<T>(\n\t\t\t[src],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst terminal = ctx.terminalDeps[0];\n\t\t\t\tif (terminal !== undefined) {\n\t\t\t\t\tconst cause: TerminalCause =\n\t\t\t\t\t\tterminal === true ? { kind: \"completed\" } : { kind: \"errored\", error: terminal };\n\t\t\t\t\tif (mode === \"terminal\" || mode === cause.kind) {\n\t\t\t\t\t\tactions.emit(recover(cause, actions));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tactions.down(cause.kind === \"completed\" ? [[COMPLETE]] : [[ERROR, cause.error]]);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tif (batch0 == null || batch0.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\tfor (const v of batch0 as T[]) actions.emit(v);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tdescribeKind: \"derived\",\n\t\t\t\tcompleteWhenDepsComplete:\n\t\t\t\t\topts.completeWhenDepsComplete ?? !(mode === \"completed\" || mode === \"terminal\"),\n\t\t\t\terrorWhenDepsError: !(mode === \"errored\" || mode === \"terminal\"),\n\t\t\t\tmeta: meta(\"catch\", opts.meta),\n\t\t\t} as NodeOptions<T>,\n\t\t);\n\t\tthis.add(step, { name });\n\t\treturn step;\n\t}\n\n\t// -- internals ----------------------------------------------------------\n\n\tprivate _resolveStep(dep: StepRef): Node<unknown> {\n\t\tif (typeof dep === \"string\") return this.resolve(dep);\n\t\tconst existing = this.nameOf(dep);\n\t\tif (existing === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`PipelineGraph \"${this.name}\": Node dep is not registered. Pass a string path or call graph.add(node) first.`,\n\t\t\t);\n\t\t}\n\t\treturn dep;\n\t}\n}\n\n/** Factory wrapper — `pipelineGraph(name, opts?)`. Equivalent to `new PipelineGraph(name, opts)`. */\nexport function pipelineGraph(name: string, opts?: GraphOptions): PipelineGraph {\n\tconst g = new PipelineGraph(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. `factoryArgs` is the\n\t// constructor opts (sans the `factory`/`factoryArgs` keys themselves to\n\t// avoid recursive nesting). QA F13: route through `placeholderArgs` for\n\t// consistency with sibling factories — `GraphOptions[key: string]: unknown`\n\t// is open-ended, so user-extension keys may carry non-JSON content.\n\tconst { factory: _f, factoryArgs: _fa, ...tagArgs } = (opts ?? {}) as Record<string, unknown>;\n\tg.tagFactory(\"pipelineGraph\", placeholderArgs(tagArgs));\n\treturn g;\n}\n","/**\n * Phase 13.F — `tracker` sibling preset.\n *\n * Source: `archive/docs/SESSION-human-llm-intervention-primitives.md` §5\n * \"Sibling presets on the substrate\" + `archive/docs/SKETCH-reactive-tracker-factory.md`\n * + `project_reactive_tracker` memory.\n *\n * **Role.** Park-as-deferred queue consumer. The tracker is the\n * cursor-based read surface over the well-known {@link DEFERRED_TOPIC}\n * — items the harness (or any consumer) defers for later attention.\n * Sibling to `humanInput` and `approvalGate`; all three share substrate\n * (hub + envelope + reactive cursor) but differ in role.\n *\n * **Cursor handle.** Per the SESSION's \"Cursor handle\" return — tracker\n * exposes the cursor-based pull / ack surface so the consumer (a\n * dashboard, a post-run review, an LLM watcher) can iterate over\n * unconsumed items in order.\n *\n * **Naming locked (open question §11 #3 resolved):** `tracker`. The\n * SESSION mentioned `tracker` vs `parkedQueue` vs `deferredTracker`;\n * `tracker` is the simplest and most general — the deferred-queue\n * semantic is a recipe, not a name overload. Other use cases (issue\n * tracker, todo tracker, retrospective tracker per\n * `project_reactive_tracker`) reuse the same primitive.\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport {\n\tDEFERRED_TOPIC,\n\ttype MessagingHubGraph,\n\ttype SubscriptionGraph,\n\tsubscription,\n\ttype TopicGraph,\n} from \"../messaging/index.js\";\n\n// ---------------------------------------------------------------------------\n// Bundle\n// ---------------------------------------------------------------------------\n\n/**\n * Bundle returned by {@link tracker}. Wraps a topic + cursor-based\n * subscription with imperative `add` / `ack` helpers.\n */\nexport interface TrackerBundle<T> {\n\t/**\n\t * The underlying topic. Either freshly minted on the hub at\n\t * `topicName` (default {@link DEFERRED_TOPIC}) or reused if the topic\n\t * already exists.\n\t */\n\treadonly topic: TopicGraph<T>;\n\t/** Cursor-based subscription view over `topic.events`. */\n\treadonly subscription: SubscriptionGraph<T>;\n\t/**\n\t * Items beyond the current cursor — i.e. the deferred queue's\n\t * \"pending\" head. Reactive `Node<readonly T[]>`.\n\t */\n\treadonly pending: Node<readonly T[]>;\n\t/** Current cursor position (number of items already acked). */\n\treadonly cursor: Node<number>;\n\t/**\n\t * Reactive total count of items added since construction (matches the\n\t * topic's retained-events length until the topic's retention cap is\n\t * reached).\n\t */\n\treadonly total: Node<number>;\n\t/** Append an item to the deferred queue. */\n\tadd(item: T): void;\n\t/**\n\t * Advance the cursor past `n` items (default 1). Acks the next batch\n\t * of pending items; subsequent reads of `pending` exclude them.\n\t */\n\tack(n?: number): void;\n\t/**\n\t * Pull-and-ack at most `limit` items in one shot. Returns the items\n\t * + the new cursor position (matches `subscription.pullAndAck`).\n\t */\n\tpullAndAck(limit?: number): { items: readonly T[]; cursor: number };\n}\n\n// ---------------------------------------------------------------------------\n// tracker()\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link tracker}.\n */\nexport interface TrackerOpts {\n\t/**\n\t * Messaging hub. The tracker creates / reuses a topic on this hub\n\t * named `topicName` (default {@link DEFERRED_TOPIC}).\n\t */\n\treadonly hub: MessagingHubGraph;\n\t/**\n\t * Topic name on the hub. Default {@link DEFERRED_TOPIC}. Override to\n\t * use a non-deferred topic (e.g. a custom domain queue).\n\t */\n\treadonly topicName?: string;\n\t/**\n\t * Subscription graph name. Default `\"tracker\"`. Multiple trackers on\n\t * the same hub topic must use distinct names.\n\t */\n\treadonly name?: string;\n\t/**\n\t * Initial cursor. Forwarded to the underlying subscription. See\n\t * {@link SubscriptionOptions.from}.\n\t */\n\treadonly from?: \"now\" | \"retained\" | number;\n}\n\n/**\n * Mints a tracker bundle over a hub topic.\n *\n * @example\n * ```ts\n * import { messagingHub, tracker } from \"@graphrefly/graphrefly-ts\";\n *\n * const hub = messagingHub(\"hub\");\n * const issues = tracker<{ summary: string }>({ hub });\n *\n * issues.add({ summary: \"investigate flaky test\" });\n * issues.add({ summary: \"follow up on auth refactor\" });\n *\n * // Subscribe to the pending queue (for a dashboard, watcher, etc.)\n * issues.pending.subscribe((msgs) => { ... });\n *\n * // Imperative pull + ack\n * const next = issues.pullAndAck(1);\n * console.log(next.items[0]?.summary);\n * ```\n *\n * @category patterns\n */\nexport function tracker<T>(opts: TrackerOpts): TrackerBundle<T> {\n\tconst { hub, topicName, name, from } = opts;\n\tconst effectiveTopicName = topicName ?? DEFERRED_TOPIC;\n\tconst effectiveName = name ?? \"tracker\";\n\n\t// Reuse existing topic on the hub or lazy-create.\n\tconst topicGraph = hub.topic<T>(effectiveTopicName);\n\n\t// Cursor-based subscription. The subscription is owned by the tracker\n\t// (not mounted on the hub) — multiple trackers can share the topic with\n\t// independent cursors.\n\tconst sub: SubscriptionGraph<T> = subscription<T>(effectiveName, topicGraph, {\n\t\t...(from != null && { from }),\n\t});\n\n\t// `total` derives from topic.events.length. Use a derived node owned by\n\t// the subscription for a self-contained surface. `keepAlive: true` so\n\t// `total.cache` stays current even without external subscribers.\n\tconst total = sub.derived<number>(\n\t\t\"tracker-total\",\n\t\t[topicGraph.events],\n\t\t(data, ctx) => {\n\t\t\tconst b0 = data[0];\n\t\t\tconst arr =\n\t\t\t\tb0 != null && b0.length > 0\n\t\t\t\t\t? (b0.at(-1) as readonly T[])\n\t\t\t\t\t: ((ctx.prevData[0] as readonly T[] | undefined) ?? []);\n\t\t\treturn [arr.length];\n\t\t},\n\t\t{ keepAlive: true },\n\t);\n\n\treturn {\n\t\ttopic: topicGraph,\n\t\tsubscription: sub,\n\t\tpending: sub.available,\n\t\tcursor: sub.cursor,\n\t\ttotal,\n\t\tadd: (item) => topicGraph.publish(item),\n\t\tack: (n) => sub.ack(n ?? 1),\n\t\tpullAndAck: (limit) => sub.pullAndAck(limit),\n\t};\n}\n"],"mappings":"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","names":["COMPLETE","DATA","node","wallClockNs","node","batch","DATA","wallClockNs","COMPLETE"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/presets/harness/actor-pool.ts","../src/presets/harness/eval-verifier.ts","../src/presets/harness/refine-executor.ts","../src/presets/harness/ownership-controller.ts","../src/presets/harness/profile.ts","../src/presets/harness/trace.ts"],"sourcesContent":["/**\n * DS-14.6.A U-B — `actorPool()` (Phase 14.5).\n *\n * The dynamic-track complement to `spawnable()` (SESSION-DS-14.6-A L7/L8 +\n * 9Q walk). An actor is **identity + cursor + tool closure, NOT a subgraph**\n * (D-B1): no per-actor mount, so `describe()` shows only the pool / todo /\n * context-hub collections and the actor count drifts inside a single\n * reactive `active` map node. `depthCap` is enforced via the depth carried\n * on the attach request (D-B2); `release()` cascades teardown to the\n * actor's context view + todo cursor subscriptions (§3i — free).\n *\n * Contrast `spawnable()`: agent IS a subgraph, topology reflects the agent\n * set, `describe()`-visible — use it when agent identities are pre-known.\n * Use `actorPool()` for runtime recursive fan-out where agent count drifts.\n *\n * @module\n */\n\nimport { type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { type ReactiveLogBundle, reactiveLog } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype ContextEntry,\n\ttype ContextView,\n\ttype RenderedEntry,\n\trenderContextView,\n\ttype TaggedContextPoolBundle,\n\ttaggedContextPool,\n} from \"../ai/context/index.js\";\n\nexport type ActorId = string;\n\nexport interface Todo {\n\treadonly id: string;\n\treadonly assignee?: ActorId;\n\treadonly payload: unknown;\n}\n\nexport type ActorStatus = \"idle\" | \"running\" | \"blocked\" | \"done\";\n\nexport interface ActorState {\n\treadonly id: ActorId;\n\treadonly depth: number;\n\treadonly status: ActorStatus;\n}\n\nexport interface ActorSpec<T> {\n\treadonly id?: ActorId;\n\t/** Recursion depth — gated against `depthCap` (D-B2). Default 0 (root). */\n\treadonly depth?: number;\n\t/** Per-actor compression view over the shared context pool. */\n\treadonly view: Omit<ContextView<T>, \"pressure\"> & { readonly pressure: Node<number> };\n}\n\nexport interface ActorHandle<T> {\n\treadonly id: ActorId;\n\t/** This actor's compressed context slice. */\n\treadonly context: Node<readonly RenderedEntry<T>[]>;\n\t/** Todos currently assigned to this actor (or unassigned). */\n\treadonly todoCursor: Node<readonly Todo[]>;\n\t/** Write an entry into the shared pool, stamped with this actor's id tag. */\n\tpublish(entry: Omit<ContextEntry<T>, \"id\" | \"t_ns\"> & { id?: string }): string;\n\tenqueueTodo(t: Todo): void;\n\treadonly status: Node<ActorStatus>;\n\tsetStatus(s: ActorStatus): void;\n\t/** Idempotent. Tears the actor's subscriptions + removes it from `active`. */\n\trelease(): void;\n}\n\nexport interface ActorPoolOptions<T> {\n\treadonly name?: string;\n\t/** Max recursion depth; `attachActor` with `depth > depthCap` throws. */\n\treadonly depthCap?: number;\n\t/** Forwarded to the backing context pool. */\n\treadonly contextTopic?: string;\n\treadonly llmCompress?: TaggedContextPoolBundle<T>[\"_opts\"][\"llmCompress\"];\n}\n\nexport interface ActorPoolBundle<T> {\n\tattachActor(spec: ActorSpec<T>): ActorHandle<T>;\n\treadonly contextPool: TaggedContextPoolBundle<T>;\n\treadonly todos: ReactiveLogBundle<Todo>;\n\t/** Single reactive map of live actors — `describe()`-coherent (D-B1). */\n\treadonly active: Node<ReadonlyMap<ActorId, ActorState>>;\n\treadonly graph: Graph;\n\tdispose(): void;\n}\n\n/** Process-wide sequence for collision-safe default mount names (QA P6). */\nlet _actorPoolSeq = 0;\n\nexport function actorPool<T = unknown>(\n\tparent: Graph,\n\topts: ActorPoolOptions<T> = {},\n): ActorPoolBundle<T> {\n\t// QA P6: collision-safe default — recursive fan-out spins nested pools\n\t// under one parent; static \"actorPool\" would collide on `parent.mount`.\n\tconst name = opts.name ?? `actorPool-${++_actorPoolSeq}`;\n\tconst graph = new Graph(name);\n\tparent.mount(name, graph);\n\tconst depthCap = opts.depthCap ?? Number.POSITIVE_INFINITY;\n\t// QA P5: per-pool actor counter (was module-global → test-pollution).\n\tlet autoActor = 0;\n\t// QA P7: track live handles so dispose() can release them all.\n\tconst liveHandles = new Set<ActorHandle<T>>();\n\n\tconst contextPool = taggedContextPool<T>(graph, {\n\t\ttopic: opts.contextTopic ?? \"context\",\n\t\tllmCompress: opts.llmCompress,\n\t\tname: `${name}.ctx`,\n\t});\n\tconst todos: ReactiveLogBundle<Todo> = reactiveLog<Todo>(undefined, { name: `${name}.todos` });\n\n\t// Single reactive `active` map node — actor count drifts inside it; no\n\t// per-actor subgraph mount (D-B1, describe-coherent).\n\tconst stateMap = new Map<ActorId, ActorState>();\n\tconst active = node<ReadonlyMap<ActorId, ActorState>>([], {\n\t\tname: `${name}.active`,\n\t\tinitial: new Map(),\n\t});\n\tfunction pushActive(): void {\n\t\tactive.emit(new Map(stateMap));\n\t}\n\n\tfunction attachActor(spec: ActorSpec<T>): ActorHandle<T> {\n\t\tconst depth = spec.depth ?? 0;\n\t\tif (depth > depthCap) {\n\t\t\tthrow new RangeError(`actorPool: depth ${depth} exceeds depthCap ${depthCap}`);\n\t\t}\n\t\tconst id = spec.id ?? `actor-${++autoActor}`;\n\n\t\tconst context = renderContextView(contextPool, spec.view as ContextView<T>);\n\t\t// Per-actor todo cursor — assigned-to-me or unassigned.\n\t\tconst todoCursor = node<readonly Todo[]>(\n\t\t\t[todos.entries as Node],\n\t\t\t(data, actions, ctx) => {\n\t\t\t\tconst all = (data[0] != null && data[0].length > 0 ? data[0].at(-1) : ctx.prevData[0]) as\n\t\t\t\t\t| readonly Todo[]\n\t\t\t\t\t| undefined;\n\t\t\t\tactions.emit((all ?? []).filter((t) => t.assignee === id || t.assignee === undefined));\n\t\t\t},\n\t\t\t{ describeKind: \"derived\" },\n\t\t);\n\t\tconst status = node<ActorStatus>([], { name: `${name}.${id}.status`, initial: \"idle\" });\n\n\t\tstateMap.set(id, { id, depth, status: \"idle\" });\n\t\tpushActive();\n\n\t\t// Keepalive subs so `.cache` stays warm; torn on release (cascade-cancel).\n\t\tconst subs = [\n\t\t\tcontext.subscribe(() => {}),\n\t\t\ttodoCursor.subscribe(() => {}),\n\t\t\tstatus.subscribe(() => {}),\n\t\t];\n\t\tlet released = false;\n\n\t\tconst handle: ActorHandle<T> = {\n\t\t\tid,\n\t\t\tcontext,\n\t\t\ttodoCursor,\n\t\t\tstatus,\n\t\t\tpublish(entry) {\n\t\t\t\tconst tags = [...(entry.tags ?? []), `actor:${id}`];\n\t\t\t\treturn contextPool.add({ ...entry, tags });\n\t\t\t},\n\t\t\tenqueueTodo(t) {\n\t\t\t\ttodos.append(t);\n\t\t\t},\n\t\t\tsetStatus(s) {\n\t\t\t\tstatus.emit(s);\n\t\t\t\tconst prev = stateMap.get(id);\n\t\t\t\tif (prev) {\n\t\t\t\t\tstateMap.set(id, { ...prev, status: s });\n\t\t\t\t\tpushActive();\n\t\t\t\t}\n\t\t\t},\n\t\t\trelease() {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\t// Cascade-cancel: tearing the keepalive subs deactivates the\n\t\t\t\t// per-actor derived nodes (lazy-deactivation — COMPOSITION-GUIDE\n\t\t\t\t// §1), detaching `context`/`todoCursor`/`status` from the shared\n\t\t\t\t// pool/todos logs once no other subscriber remains.\n\t\t\t\tfor (const u of subs) u();\n\t\t\t\tstateMap.delete(id);\n\t\t\t\tliveHandles.delete(handle);\n\t\t\t\tpushActive();\n\t\t\t},\n\t\t};\n\t\tliveHandles.add(handle);\n\t\treturn handle;\n\t}\n\n\treturn {\n\t\tattachActor,\n\t\tcontextPool,\n\t\ttodos,\n\t\tactive,\n\t\tgraph,\n\t\tdispose(): void {\n\t\t\t// QA P7: release outstanding actors first (tears their keepalive\n\t\t\t// subs / deactivates per-actor derived nodes) before disposing the\n\t\t\t// shared pool + todo log.\n\t\t\tfor (const h of [...liveHandles]) h.release();\n\t\t\tcontextPool.dispose();\n\t\t\ttodos.dispose();\n\t\t},\n\t};\n}\n","/**\n * evalVerifier — re-run the affected eval tasks against the execute-stage\n * artifact instead of asking an LLM to opine on the fix.\n *\n * Pairs naturally with {@link refineExecutor}: refineExecutor emits an\n * `ExecuteOutput<T>.artifact` holding the converged candidate; evalVerifier\n * pulls it out via `extractArtifact` and feeds a single-candidate batch\n * into the same `Evaluator<T>` shape that `refineLoop` used. Consistent\n * scoring between EXECUTE and VERIFY — no \"LLM said it looks fine\" gap.\n *\n * **C2 lifecycle (Tier 6.5).** The work fn is invoked once per claimed\n * verify-stage job. A fresh single-candidate eval subgraph is mounted\n * inside the work fn and tears down when the JobFlow pump ack/unsubs.\n *\n * @module\n */\n\nimport { batch, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport { filter } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport type {\n\tExecuteOutput,\n\tHarnessExecutor,\n\tHarnessJobPayload,\n\tHarnessVerifier,\n\tTriagedItem,\n\tVerifyOutput,\n} from \"../../utils/harness/types.js\";\nimport type { JobEnvelope } from \"../../utils/job-queue/index.js\";\nimport { refineExecutor } from \"./refine-executor.js\";\nimport type {\n\tDatasetItem,\n\tEvalResult,\n\tEvaluator,\n\tRefineLoopOptions,\n\tRefineStrategy,\n} from \"./refine-loop.js\";\n\n/** Summary of the re-eval wave passed to a custom `toOutput` mapper. */\nexport interface EvalVerifierSummary {\n\treadonly scores: readonly EvalResult[];\n\treadonly meanScore: number;\n\treadonly passCount: number;\n\treadonly total: number;\n\treadonly threshold: number;\n\t/**\n\t * True when the EXECUTE stage did not produce an artifact (i.e.\n\t * `extractArtifact` returned `null` / `undefined`). Downstream mappers\n\t * can distinguish this from \"evaluator ran but everything scored zero\".\n\t */\n\treadonly missingArtifact?: boolean;\n}\n\n/** Configuration for {@link evalVerifier}. */\nexport interface EvalVerifierConfig<T> {\n\t/**\n\t * Pull the artifact that should be re-evaluated out of the execute-stage\n\t * output. Default: `(exec) => exec.artifact as T` — works out-of-the-box\n\t * with `refineExecutor` (which populates `artifact` by default).\n\t */\n\textractArtifact?: (exec: ExecuteOutput<T>, item: TriagedItem) => T | null | undefined;\n\n\t/**\n\t * Reactive evaluator — same contract as `refineLoop`'s `Evaluator<T>`.\n\t */\n\tevaluator: Evaluator<T>;\n\n\t/**\n\t * Resolve which dataset rows to score this verification against.\n\t */\n\tdatasetFor: (item: TriagedItem) => readonly DatasetItem[];\n\n\t/** Mean score required to pass verification. Default `0.5`. */\n\tthreshold?: number;\n\n\t/** Optional output mapper — override the default findings / errorClass shape. */\n\ttoOutput?: (summary: EvalVerifierSummary) => VerifyOutput;\n\n\t/** Node name prefix for introspection. */\n\tname?: string;\n\n\t/**\n\t * Optional parent graph on which per-claim eval subgraphs mount at\n\t * `eval/${claimId}` (DS-13.5.D.4, locked 2026-05-01). When provided,\n\t * each claim creates a fresh `Graph(\\`eval_${claimId}\\`)` subgraph\n\t * carrying `candidates` / `dataset` / `output` and mounts it at\n\t * `eval/${claimId}` on this parent — `describe()` walks the parent\n\t * see the per-claim topology while the claim is in flight, and the\n\t * subgraph is removed via `parent.remove(\"eval/${claimId}\")` on the\n\t * output node's `deactivate` cleanup (fires when JobFlow's pump\n\t * unsubscribes after ack/nack).\n\t *\n\t * **claimId source.** `JobEnvelope.id` (assigned at enqueue time);\n\t * unique within a JobFlow lifetime — uniqueness within a single pump\n\t * cycle is the JobFlow's contract.\n\t *\n\t * When omitted, internal nodes float (pre-DS-13.5.D.4 behavior).\n\t */\n\tgraph?: Graph;\n}\n\nfunction meanScore(scores: readonly EvalResult[]): number {\n\tif (scores.length === 0) return Number.NEGATIVE_INFINITY;\n\tlet sum = 0;\n\tfor (const s of scores) sum += s.score;\n\treturn sum / scores.length;\n}\n\nfunction defaultToOutput(summary: EvalVerifierSummary): VerifyOutput {\n\tconst { passCount, total, meanScore: mean, threshold, missingArtifact } = summary;\n\tconst meanStr = Number.isFinite(mean) ? mean.toFixed(3) : String(mean);\n\tconst verified = !missingArtifact && total > 0 && mean >= threshold;\n\tconst findings = missingArtifact\n\t\t? [\"EXECUTE stage did not emit an artifact; cannot verify reactively\"]\n\t\t: verified\n\t\t\t? [`${passCount}/${total} eval tasks passed; mean score ${meanStr} ≥ ${threshold}`]\n\t\t\t: total === 0\n\t\t\t\t? [\"No eval tasks were selected for this item — cannot verify\"]\n\t\t\t\t: [\n\t\t\t\t\t\t`${passCount}/${total} eval tasks passed; mean score ${meanStr} < threshold ${threshold}`,\n\t\t\t\t\t];\n\treturn verified\n\t\t? { verified: true, findings }\n\t\t: { verified: false, findings, errorClass: \"structural\" };\n}\n\nfunction defaultExtractArtifact<T>(exec: ExecuteOutput<T>): T | null | undefined {\n\treturn exec.artifact ?? null;\n}\n\n/**\n * Build a {@link HarnessVerifier} that re-runs the eval suite against the\n * artifact produced by EXECUTE.\n *\n * Reads `job.payload.execution` (filled by the upstream execute work fn)\n * and runs the evaluator against `extractArtifact(execution, item)`.\n * Returns the same payload with `verify` filled in.\n *\n * @example Pair with refineExecutor for end-to-end eval consistency.\n * ```ts\n * const evaluator: Evaluator<CatalogEntry> = (cands, ds) => runEval(cands, ds);\n * const harness = harnessLoop(\"repair\", {\n * adapter,\n * executor: refineExecutor({ ..., evaluator, ...strategyConfig }),\n * verifier: evalVerifier({ evaluator, datasetFor, threshold: 0.8 }),\n * });\n * ```\n */\nexport function evalVerifier<T>(config: EvalVerifierConfig<T>): HarnessVerifier<T> {\n\tconst name = config.name ?? \"eval-verifier\";\n\tconst threshold = config.threshold ?? 0.5;\n\tconst toOutput = config.toOutput ?? defaultToOutput;\n\tconst extract = config.extractArtifact ?? defaultExtractArtifact<T>;\n\tconst parentGraph = config.graph;\n\t// DS-13.5.B QA A7 (2026-05-03): per-claimId collision counter.\n\t// Reingest paths preserve identity per DS-13.5.D.3 so the same\n\t// claimId can land on the verifier while a prior cycle is still\n\t// in-flight. Without disambiguation, `parentGraph.mount(\n\t// \"eval/${id}\", sub)` would either silently overwrite the prior\n\t// mount or throw \"mount already exists\". The counter is keyed by\n\t// claimId so DISTINCT ids start at seq=0 (`eval/${id}`) and only\n\t// REPEAT ids get a `_${seq}` suffix.\n\tconst mountSeqByClaimId = new Map<string, number>();\n\n\treturn (job: JobEnvelope<HarnessJobPayload<T>>) => {\n\t\tconst { item, execution } = job.payload;\n\t\t// Defensive: verify stage should always run AFTER execute stage with\n\t\t// `execution` populated. If it isn't, surface that as a structural\n\t\t// failure so the dispatch effect can route the item.\n\t\tif (execution == null) {\n\t\t\treturn {\n\t\t\t\t...job.payload,\n\t\t\t\tverify: {\n\t\t\t\t\tverified: false,\n\t\t\t\t\tfindings: [\"evalVerifier: prior execute stage produced no execution\"],\n\t\t\t\t\terrorClass: \"structural\" as const,\n\t\t\t\t},\n\t\t\t} satisfies HarnessJobPayload<T>;\n\t\t}\n\t\tconst artifact = extract(execution, item);\n\t\tif (artifact == null) {\n\t\t\treturn {\n\t\t\t\t...job.payload,\n\t\t\t\tverify: toOutput({\n\t\t\t\t\tscores: [],\n\t\t\t\t\tmeanScore: Number.NEGATIVE_INFINITY,\n\t\t\t\t\tpassCount: 0,\n\t\t\t\t\ttotal: 0,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tmissingArtifact: true,\n\t\t\t\t}),\n\t\t\t} satisfies HarnessJobPayload<T>;\n\t\t}\n\n\t\t// Per-claim eval subgraph. State seeds with the single candidate +\n\t\t// resolved dataset; the evaluator returns a Node<readonly EvalResult[]>.\n\t\t// The terminal payload emits when the evaluator settles; intermediate\n\t\t// nulls are filtered.\n\t\t//\n\t\t// **Batch-coalescing for synchronous-emit-during-subscribe evaluators\n\t\t// (COMPOSITION-GUIDE §9a).** This `batch()` wrap is load-bearing for a\n\t\t// SPECIFIC evaluator pattern: evaluators that, during the\n\t\t// `evaluator(candidates, dataset)` constructor call, synchronously\n\t\t// `subscribe()` to BOTH inputs and emit on each subscribe-callback\n\t\t// firing. Each subscribe pushes the cached value to its callback, the\n\t\t// callback runs `out.emit(...)`, and that emit becomes its own wave\n\t\t// when not inside a batch — leaving multiple DATA messages visible to\n\t\t// the downstream `derived` once it activates. The JobFlow pump's\n\t\t// \"first DATA wins\" capture would then fire on the FIRST intermediate\n\t\t// emit (e.g. empty scores from a pre-dataset recompute) instead of\n\t\t// the final settled value.\n\t\t//\n\t\t// Wrapping the constructor call in `batch()` coalesces those internal\n\t\t// emits into one multi-message delivery (§9a); sugar `derived`\n\t\t// auto-unwraps to the LAST value per its snapshot/combine semantics\n\t\t// (sugar.ts), so the downstream sees only the final settled scores.\n\t\t//\n\t\t// **Async evaluators are NOT covered by this fix.** Evaluators that\n\t\t// subscribe via microtask / Promise.then() / setTimeout don't see the\n\t\t// §9a hazard at all — their emits land in separate waves regardless\n\t\t// of whether the constructor call is batched. The fix is strictly\n\t\t// for the synchronous-emit-during-subscribe pattern (today's tests:\n\t\t// `presenceEvaluator` in actuator-executor.test.ts; `keywordEvaluator`\n\t\t// in refine-executor.test.ts uses `derived` and is naturally\n\t\t// single-emit). See `harness-default-bridges.test.ts` regression test\n\t\t// \"evalVerifier coalesces synchronous-emit-during-subscribe\n\t\t// evaluators\" for the locked contract.\n\t\t// DS-13.5.D.4 (locked 2026-05-01): when `parentGraph` is configured,\n\t\t// each claim creates its own subgraph `eval_${claimId}` and mounts\n\t\t// it at `eval/${claimId}` on the parent. Internal node names use\n\t\t// the simple shape (`candidates`, `dataset`, `output`) since each\n\t\t// subgraph is a fresh namespace. Cleanup attaches to `raw`'s\n\t\t// deactivate hook so the segment is removed when JobFlow\n\t\t// unsubscribes after ack/nack (canonical \"last unsubscribe\"\n\t\t// signal via the existing NodeFnCleanup.onDeactivation protocol).\n\t\tconst claimId = job.id;\n\t\t// QA A7: only append a `_${seq}` suffix when this claimId has\n\t\t// already been mounted (collision case). Distinct claimIds\n\t\t// resolve to `eval/${claimId}` as before.\n\t\tconst seq = mountSeqByClaimId.get(claimId) ?? 0;\n\t\tmountSeqByClaimId.set(claimId, seq + 1);\n\t\tconst segmentSuffix = seq === 0 ? \"\" : `_${seq}`;\n\t\tconst segmentPath = `eval/${claimId}${segmentSuffix}`;\n\t\tconst sub = parentGraph != null ? new Graph(`eval_${claimId}${segmentSuffix}`) : null;\n\t\tconst candidatesName = sub != null ? \"candidates\" : `${name}/candidates`;\n\t\tconst datasetName = sub != null ? \"dataset\" : `${name}/dataset`;\n\t\tconst outputName = sub != null ? \"output\" : `${name}/output`;\n\t\tconst gateName = sub != null ? \"gate-out\" : `${name}/gate-out`;\n\n\t\tconst candidates = node<readonly T[]>([], {\n\t\t\tinitial: [artifact as T],\n\t\t\tname: candidatesName,\n\t\t});\n\t\tconst dataset = node<readonly DatasetItem[]>([], {\n\t\t\tinitial: config.datasetFor(item),\n\t\t\tname: datasetName,\n\t\t});\n\t\tif (sub != null) {\n\t\t\tsub.add(candidates, { name: \"candidates\" });\n\t\t\tsub.add(dataset, { name: \"dataset\" });\n\t\t}\n\t\tlet scoresNode!: ReturnType<Evaluator<T>>;\n\t\tbatch(() => {\n\t\t\tscoresNode = config.evaluator(candidates, dataset);\n\t\t});\n\t\t// DS-13.5.B QA A1 (2026-05-03): the deactivate cleanup hook MUST\n\t\t// be returned on every fn run, including the early-return path\n\t\t// where `arr == null` (evaluator emits a placeholder before\n\t\t// settling). Cleanup capture happens at the END of fn execution\n\t\t// (NodeFnCleanup contract), so a fn that returned early without\n\t\t// the cleanup object would leak `eval/${claimId}` if its first\n\t\t// run produced null and the consumer unsubscribed before\n\t\t// scoresNode emits non-null.\n\t\tconst cleanup =\n\t\t\tparentGraph != null\n\t\t\t\t? () => ({\n\t\t\t\t\t\tonDeactivation: () => {\n\t\t\t\t\t\t\t// Auto-unmount on JobFlow's pump unsubscribe after\n\t\t\t\t\t\t\t// ack/nack (DS-13.5.D.4). Idempotent: try/catch\n\t\t\t\t\t\t\t// covers the case where the segment was already\n\t\t\t\t\t\t\t// removed (e.g. parent destroy cascade ran first).\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparentGraph.remove(segmentPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t/* best-effort cleanup */\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: () => undefined;\n\t\tconst raw = node<HarnessJobPayload<T> | null>(\n\t\t\t[scoresNode as Node<unknown>],\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 EvalResult[] | null | undefined;\n\t\t\t\tif (arr == null) {\n\t\t\t\t\tactions.emit(null);\n\t\t\t\t\treturn cleanup();\n\t\t\t\t}\n\t\t\t\tconst mean = meanScore(arr);\n\t\t\t\tconst passCount = arr.filter((s) => s.score >= threshold).length;\n\t\t\t\tactions.emit({\n\t\t\t\t\t...job.payload,\n\t\t\t\t\tverify: toOutput({\n\t\t\t\t\t\tscores: arr,\n\t\t\t\t\t\tmeanScore: mean,\n\t\t\t\t\t\tpassCount,\n\t\t\t\t\t\ttotal: arr.length,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn cleanup();\n\t\t\t},\n\t\t\t{ name: outputName, describeKind: \"derived\" },\n\t\t);\n\t\tconst gateOut = filter(raw, (v) => v != null, { name: gateName }) as ReturnType<\n\t\t\tHarnessVerifier<T>\n\t\t>;\n\t\tif (sub != null) {\n\t\t\tsub.add(raw, { name: \"output\" });\n\t\t\t// QA A6: register the gate-out filter on the per-claim\n\t\t\t// subgraph so describe() walks see the consumer-facing node\n\t\t\t// alongside candidates/dataset/output. Without this, the\n\t\t\t// returned filter floats and the subgraph's external surface\n\t\t\t// is incomplete in topology snapshots.\n\t\t\tsub.add(gateOut as Node<unknown>, { name: \"gate-out\" });\n\t\t\t(parentGraph as Graph).mount(segmentPath, sub);\n\t\t}\n\t\treturn gateOut;\n\t};\n}\n\n/**\n * Config for {@link harnessEvalPair} — the typed bundle that produces a\n * matched `refineExecutor<T>` + `evalVerifier<T>` pair sharing one\n * {@link Evaluator} and one `datasetFor` resolver.\n */\nexport interface HarnessEvalPairConfig<T> {\n\t/** Map a triaged item to the seed candidate. */\n\tseedFrom: (item: TriagedItem) => T;\n\t/** The reactive evaluator used by BOTH executor and verifier. */\n\tevaluator: Evaluator<T>;\n\t/** The refinement strategy (e.g. `errorCritique(teacher)`). */\n\tstrategy: RefineStrategy<T>;\n\t/** Resolve dataset rows per triaged item. */\n\tdatasetFor: (item: TriagedItem) => readonly DatasetItem[];\n\t/** Pass-threshold for the verifier. Default `0.5`. */\n\tthreshold?: number;\n\t/** Convergence / budget options forwarded to each inner `refineLoop`. */\n\trefine?: Omit<RefineLoopOptions, \"dataset\" | \"name\">;\n\t/**\n\t * Shared node-name prefix — the executor becomes `${name}-exec` and the\n\t * verifier `${name}-verify` for distinct but related describe() paths.\n\t * Default `\"harness-pair\"`.\n\t */\n\tname?: string;\n}\n\n/**\n * Typed factory that returns a matched `{ executor, verifier }` pair.\n *\n * Prevents the \"executor wrote `A`, verifier expected `B`\" class of runtime\n * cast errors — `T` is threaded through both sides, so mixing up the\n * configuration is a compile error instead of a silent `as T` in\n * `extractArtifact`. Shares the evaluator so EXECUTE and VERIFY score with\n * identical semantics (the whole point of `evalVerifier`).\n */\nexport function harnessEvalPair<T>(config: HarnessEvalPairConfig<T>): {\n\texecutor: HarnessExecutor<T>;\n\tverifier: HarnessVerifier<T>;\n} {\n\tconst baseName = config.name ?? \"harness-pair\";\n\tconst executor = refineExecutor<T>({\n\t\tname: `${baseName}-exec`,\n\t\tseedFrom: config.seedFrom,\n\t\tevaluator: config.evaluator,\n\t\tstrategy: config.strategy,\n\t\tdatasetFor: config.datasetFor,\n\t\trefine: config.refine,\n\t});\n\tconst verifier = evalVerifier<T>({\n\t\tname: `${baseName}-verify`,\n\t\tevaluator: config.evaluator,\n\t\tdatasetFor: config.datasetFor,\n\t\tthreshold: config.threshold,\n\t});\n\treturn { executor, verifier };\n}\n","/**\n * refineExecutor — bridge a `refineLoop` into the harness EXECUTE work fn.\n *\n * Each claimed job mounts a fresh `refineLoop`; when the loop reaches a\n * terminal status (`converged` / `budget` / `errored`), the work fn emits a\n * single {@link HarnessJobPayload} with `execution` filled in. The JobFlow\n * pump subscribes once, takes the first DATA, then unsubscribes — so the\n * inner loop tears down cleanly when the harness acks the job.\n *\n * **C2 lifecycle (Tier 6.5).** The work fn is invoked once per claim, so\n * no internal `switchMap` is needed (the prior pre-C2 shape used switchMap\n * to handle a stream of items). The pump owns the per-claim lifecycle:\n * activation when the work fn returns, teardown when the result Node is\n * unsubscribed.\n *\n * **Cross-item learning:** a fresh refineLoop per item means\n * `errorCritique`-style failure sampling does NOT accumulate across items\n * sharing a `rootCause`. A persistent-loop + re-seed surface is filed in\n * `docs/optimizations.md` as a long-term follow-up.\n *\n * @module\n */\n\nimport { node } from \"@graphrefly/pure-ts/core\";\nimport { filter } from \"@graphrefly/pure-ts/extra\";\nimport type {\n\tExecuteOutput,\n\tHarnessExecutor,\n\tHarnessJobPayload,\n\tTriagedItem,\n} from \"../../utils/harness/types.js\";\nimport type { JobEnvelope } from \"../../utils/job-queue/index.js\";\nimport {\n\ttype DatasetItem,\n\ttype Evaluator,\n\ttype RefineLoopOptions,\n\ttype RefineStatus,\n\ttype RefineStrategy,\n\trefineLoop,\n} from \"./refine-loop.js\";\n\n/** Terminal-run snapshot passed to a custom `toOutput` mapper. */\nexport interface RefineExecutorResult<T> {\n\t/** Best candidate the inner loop converged on. `null` if no candidates were scored. */\n\treadonly best: T | null;\n\t/** Aggregate score at termination. `-Infinity` if the batch was empty. */\n\treadonly score: number;\n\t/** Reason the loop terminated. */\n\treadonly status: RefineStatus;\n}\n\n/** Configuration for {@link refineExecutor}. */\nexport interface RefineExecutorConfig<T> {\n\t/** Map a triaged item to the seed candidate (e.g. a catalog entry, prompt, patch). */\n\tseedFrom: (item: TriagedItem) => T;\n\n\t/** Reactive evaluator — same shape as passed to `refineLoop`. */\n\tevaluator: Evaluator<T>;\n\n\t/** Strategy (e.g. `errorCritique(teacher)`). Applied to every item's inner loop. */\n\tstrategy: RefineStrategy<T>;\n\n\t/** Map a triaged item to the dataset rows the evaluator should score against. */\n\tdatasetFor: (item: TriagedItem) => readonly DatasetItem[];\n\n\t/**\n\t * Optional mapper from the inner loop's terminal snapshot to an\n\t * `ExecuteOutput<T>`. Default: converged→success, budget→partial,\n\t * errored→failure.\n\t */\n\ttoOutput?: (result: RefineExecutorResult<T>) => ExecuteOutput<T>;\n\n\t/** Convergence / budget options forwarded to each inner `refineLoop`. */\n\trefine?: Omit<RefineLoopOptions, \"dataset\" | \"name\">;\n\n\t/** Node name prefix for introspection. Default `\"refine-executor\"`. */\n\tname?: string;\n}\n\nfunction defaultToOutput<T>(result: RefineExecutorResult<T>): ExecuteOutput<T> {\n\tconst { best, score, status } = result;\n\tconst scoreStr = Number.isFinite(score) ? score.toFixed(3) : String(score);\n\tconst artifact = (best ?? undefined) as T | undefined;\n\tif (status === \"converged\") {\n\t\treturn {\n\t\t\toutcome: \"success\",\n\t\t\tdetail: `refineLoop converged at score ${scoreStr}`,\n\t\t\tartifact,\n\t\t};\n\t}\n\tif (status === \"budget\") {\n\t\treturn {\n\t\t\toutcome: \"partial\",\n\t\t\tdetail: `refineLoop hit budget at score ${scoreStr}`,\n\t\t\tartifact,\n\t\t};\n\t}\n\treturn {\n\t\toutcome: \"failure\",\n\t\tdetail: `refineLoop errored (status=${status})`,\n\t\tartifact,\n\t};\n}\n\n/**\n * Build a {@link HarnessExecutor} backed by a `refineLoop` per claimed\n * job.\n *\n * @example Eval-driven repair loop in the harness EXECUTE slot.\n * ```ts\n * const harness = harnessLoop(\"repair\", {\n * adapter,\n * executor: refineExecutor({\n * seedFrom: (item) => initialCatalogEntry(item),\n * datasetFor: (item) => pickAffectedTasks(item, allTasks),\n * evaluator: (cands, tasks) => runEvalBatch(cands, tasks),\n * strategy: errorCritique({ teacher, width: 3 }),\n * refine: { maxIterations: 5, minScore: 0.9 },\n * }),\n * });\n * ```\n */\nexport function refineExecutor<T>(config: RefineExecutorConfig<T>): HarnessExecutor<T> {\n\tconst name = config.name ?? \"refine-executor\";\n\tconst toOutput = config.toOutput ?? defaultToOutput<T>;\n\n\treturn (job: JobEnvelope<HarnessJobPayload<T>>) => {\n\t\tconst item = job.payload.item;\n\t\tconst loop = refineLoop<T>(config.seedFrom(item), config.evaluator, config.strategy, {\n\t\t\t...config.refine,\n\t\t\tdataset: config.datasetFor(item),\n\t\t\tname: `${name}/inner`,\n\t\t});\n\t\t// Terminal-allowlist guard — emit non-null only on `converged` / `budget` /\n\t\t// `errored`; intermediate `running` waves emit `null` (deduped via the\n\t\t// node's default Object.is). The trailing `filter(v != null)` strips\n\t\t// the null DATA so the JobFlow pump's first-DATA capture sees the\n\t\t// terminal payload, not the intermediate null.\n\t\tconst raw = node<HarnessJobPayload<T> | null>(\n\t\t\t[loop.status, loop.best, loop._score],\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 s = data[0] as RefineStatus;\n\t\t\t\tif (s !== \"converged\" && s !== \"budget\" && s !== \"errored\") {\n\t\t\t\t\tactions.emit(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst exec = toOutput({\n\t\t\t\t\tbest: data[1] as T | null,\n\t\t\t\t\tscore: data[2] as number,\n\t\t\t\t\tstatus: s,\n\t\t\t\t});\n\t\t\t\tactions.emit({\n\t\t\t\t\t...job.payload,\n\t\t\t\t\texecution: { item, ...exec },\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ name: `${name}/output`, describeKind: \"derived\" },\n\t\t);\n\t\treturn filter(raw, (v) => v != null, { name: `${name}/gate-out` }) as ReturnType<\n\t\t\tHarnessExecutor<T>\n\t\t>;\n\t};\n}\n","/**\n * `ownershipController()` — multi-agent subgraph ownership preset\n * (DS-14.5.A delta #8; L5/L6 + Q1–Q10).\n *\n * **Placement (documented choice).** Lives in `presets/harness/` alongside\n * the other multi-agent coordination presets (`spawnable()`, `actorPool()`).\n * Per the 4-layer rubric this is a ≥3-utils composition (messaging `topic` +\n * `derived` arbitration + Guard ABAC) wiring multi-agent coordination — the\n * same charter as `harness/`'s existing `spawnable`/`actorPool`. A separate\n * `presets/multi-agent/` directory was rejected to avoid fragmenting the\n * multi-agent presets across two folders for a single factory (L6: \"recipe +\n * preset, NO new primitive\").\n *\n * **What it is.** A `Graph` that owns a shared ownership `topic` (Q3 — one\n * topic carries claim / release / override; subscribers narrow by `kind`),\n * a reactive `current` derivation that folds the ownership log applying the\n * L0–L3 staircase, and a `guard` (`policyAllowing` — the Q7 reactive-options\n * Guard widening) the caller mounts on the owned subgraph. It **consumes the\n * existing DS-14 {@link OwnershipChange}** envelope — it does NOT redefine it.\n *\n * **Staircase (Q10 — `level` is a priority axis, NOT a mechanism enum):**\n * - **L1 TTL** — a `claim` carries a level; the controller's `ttl` (ms)\n * bounds the live window. L1 honors TTL strictly (Q4): a crash inside the\n * window does NOT early-release; recommend `ttl ≤ 60s`.\n * - **L2 heartbeat** — `heartbeat?: NodeInput<unknown>` (Q2). Any reactive\n * trigger Node; each emission resets the countdown (\"max tolerance since\n * last sign of life\", unified across L1/L2). No library timer is shipped\n * and no `claim.heartbeat()` method exists (`feedback_no_imperative` +\n * `feedback_no_imperative_wrap_as_primitive`).\n * - **L3 supervisor** — a `kind:\"override\"` change wins by `level` priority\n * regardless of expiry/heartbeat (priority axis independent of the expiry\n * axis). Supervisor publishes to the SAME topic (Q3).\n *\n * **No polling / no timer (spec §5.8/§5.9/§5.10).** Expiry is evaluated\n * reactively: `current` recomputes whenever the ownership topic OR the\n * heartbeat OR the optional `clock` trigger emits, folding the whole log\n * from scratch (idempotent — no carried mutable cursor). Auto-release on\n * wall-clock TTL requires the caller to wire a reactive `clock` tick\n * (`fromTimer({ ms })` or an activity-derived Node) — the library does not\n * own a timer (L6 / Q2). Without `clock`, expiry still resolves at the next\n * topic/heartbeat emission and on any read that recomputes the derivation.\n *\n * @module\n */\n\nimport { type Node, type NodeGuard, policyAllowing, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport type { NodeInput, OwnershipChange, OwnershipChangePayload } from \"@graphrefly/pure-ts/extra\";\nimport { fromAny } from \"@graphrefly/pure-ts/extra\";\nimport { Graph } from \"@graphrefly/pure-ts/graph\";\nimport { type TopicGraph, topic } from \"../../utils/messaging/index.js\";\n\n/** Ownership level — priority axis (Q10). Higher rank = higher priority. */\nconst LEVEL_RANK = { L0: 0, L1: 1, L2: 2, L3: 3 } as const;\ntype OwnershipLevel = keyof typeof LEVEL_RANK;\n\n/** Options for {@link ownershipController}. */\nexport type OwnershipControllerOptions = {\n\t/**\n\t * TTL (milliseconds) bounding the live window of a claim. Honored\n\t * strictly (Q4) — a crash inside the window does not early-release.\n\t * Recommend ≤ 60_000 for L1 holds; wire `heartbeat` (L2) for longer.\n\t */\n\treadonly ttl: number;\n\t/**\n\t * L2 heartbeat (Q2). Any reactive trigger Node — each emission resets the\n\t * TTL countdown. Simple: `fromTimer({ ms: ttl / 3 })`. Activity-based:\n\t * `derived([toolCalls.events], …)`. Omitted → pure L1 TTL semantics.\n\t */\n\treadonly heartbeat?: NodeInput<unknown>;\n\t/**\n\t * L3 supervisor id. A `kind:\"override\"` change whose `actor` equals this\n\t * id wins by `level` priority regardless of expiry/heartbeat. Override\n\t * delivery is the shared topic with the `kind:\"override\"` discriminant\n\t * (Q3) — not a separate priority topic.\n\t */\n\treadonly supervisor?: string;\n\t/**\n\t * Optional reactive clock trigger used ONLY to re-evaluate TTL expiry\n\t * (e.g. `fromTimer({ ms: 1_000 })`). The library ships no timer (L6/Q2);\n\t * wire this for wall-clock-driven auto-release without an intervening\n\t * claim/heartbeat. Without it, expiry resolves lazily on the next\n\t * topic/heartbeat emission.\n\t */\n\treadonly clock?: NodeInput<unknown>;\n\t/** Bounded retention for the ownership topic (default 256). */\n\treadonly retainedLimit?: number;\n};\n\n/**\n * Resolved ownership state emitted by {@link OwnershipControllerGraph.current}.\n * `owner` is `null` when unclaimed or the live claim has expired.\n */\nexport type OwnershipState = {\n\treadonly owner: string | null;\n\treadonly level: OwnershipLevel | null;\n\t/** Allow-set fed to the Guard. `[]` (deny-all) when `owner === null`. */\n\treadonly allowed: readonly string[];\n\t/**\n\t * Internal (F3/F4) — last sign-of-life (wall-clock ns) for the *current*\n\t * claim: `max(claim.sinceNs, last in-window heartbeat)`. Carried in the\n\t * derivation's OWN emitted state (read back via `ctx.prevData`) so the\n\t * fold is pure — same (folded log, beat-this-wave, now, prevState) →\n\t * same output. NEVER an instance field. `null` when unclaimed. Scoped to\n\t * the active claim: a value older than the active claim's `sinceNs` (a\n\t * prior owner's beat) is discarded so it cannot extend a new owner.\n\t */\n\treadonly signOfLifeNs: number | null;\n};\n\nconst EMPTY_STATE: OwnershipState = {\n\towner: null,\n\tlevel: null,\n\tallowed: [],\n\tsignOfLifeNs: null,\n};\n\ntype ActiveOwner = { owner: string; level: OwnershipLevel; sinceNs: number };\n\n/**\n * Multi-agent subgraph ownership controller. See module docs.\n *\n * Public surface:\n * - `topic` — the shared ownership `TopicGraph<OwnershipChange>` (Q3).\n * Agents publish claim/release/override here (use the `claim`/`release`/\n * `override` helpers — thin reactive wrappers over `topic.publish`, i.e.\n * message flow, NOT imperative triggers).\n * - `current` — `Node<OwnershipState>`: the reactively-resolved owner after\n * applying L1 TTL + L2 heartbeat + L3 supervisor arbitration.\n * - `allowed` — `Node<readonly string[]>`: the Guard allow-set (derived from\n * `current`); re-points on claim/release/override with no rewire.\n * - `guard` — `NodeGuard` from `policyAllowing(this.allowed)`. Mount on the\n * owned subgraph's nodes (`node({ guard })`) for the Q7 hard-block.\n */\nexport class OwnershipControllerGraph extends Graph {\n\treadonly topic: TopicGraph<OwnershipChange>;\n\treadonly current: Node<OwnershipState>;\n\treadonly allowed: Node<readonly string[]>;\n\treadonly guard: NodeGuard;\n\n\tprivate readonly _ttlNs: number;\n\tprivate readonly _supervisor: string | undefined;\n\t/**\n\t * Whether a heartbeat `NodeInput` was supplied at construction (F14 —\n\t * `claim()`'s `level` default is `\"L2\"` when wired, else `\"L1\"`). NOT a\n\t * mutable accumulator — set once in the constructor, read-only after.\n\t */\n\tprivate readonly _hasHeartbeat: boolean;\n\n\tconstructor(name: string, opts: OwnershipControllerOptions) {\n\t\tsuper(name);\n\t\tthis._ttlNs = Math.max(0, opts.ttl) * 1_000_000;\n\t\tthis._supervisor = opts.supervisor;\n\t\tthis._hasHeartbeat = opts.heartbeat != null;\n\n\t\tthis.topic = topic<OwnershipChange>(`${name}__ownership`, {\n\t\t\tretainedLimit: opts.retainedLimit ?? 256,\n\t\t});\n\t\t// The topic is its own TopicGraph; tear it down with this controller.\n\t\t// (Not mounted — `topic.events` already belongs to the TopicGraph; a\n\t\t// re-`add` would violate single-graph node ownership. Consumers\n\t\t// inspect ownership via `current` / `allowed`, not via a mount.)\n\t\tthis.addDisposer(() => {\n\t\t\tthis.topic.destroy();\n\t\t});\n\n\t\t// `current` recomputes whenever the ownership stream changes, the\n\t\t// heartbeat fires, or the optional clock ticks — the only sources\n\t\t// that can change the resolved owner. ALL deps wired BEFORE any claim\n\t\t// can be published (observers before emitters — §47 rule 2).\n\t\tconst deps: Node<unknown>[] = [this.topic.events as Node<unknown>];\n\t\tconst heartbeatIdx = opts.heartbeat != null ? deps.push(fromAny(opts.heartbeat)) - 1 : -1;\n\t\tif (opts.clock != null) deps.push(fromAny(opts.clock) as Node<unknown>);\n\n\t\tthis.current = this.derived<OwnershipState>(\n\t\t\t\"currentOwner\",\n\t\t\tdeps,\n\t\t\t(batchData, ctx) => {\n\t\t\t\t// Wall-clock (F2) — must match `makeChange`'s `t_ns` stamp so\n\t\t\t\t// `nowNs - active.sinceNs` compares like-for-like. Mixing\n\t\t\t\t// monotonic + wall clocks (the prior bug) made TTL math\n\t\t\t\t// nonsense once the two clocks diverged.\n\t\t\t\tconst nowNs = wallClockNs();\n\t\t\t\t// Did the heartbeat dep emit this wave? `batchData[i]` is the\n\t\t\t\t// array of values dep `i` emitted THIS wave; a non-empty\n\t\t\t\t// heartbeat batch is one or more beats.\n\t\t\t\tconst beatThisWave =\n\t\t\t\t\theartbeatIdx >= 0 &&\n\t\t\t\t\t(() => {\n\t\t\t\t\t\tconst hb = batchData[heartbeatIdx] as readonly unknown[] | null | undefined;\n\t\t\t\t\t\treturn hb != null && hb.length > 0;\n\t\t\t\t\t})();\n\n\t\t\t\t// Fold the WHOLE ownership log from scratch (idempotent — the\n\t\t\t\t// topic emits the full retained array, so a cursor would be a\n\t\t\t\t// bug surface; pure reduction is correct and simple, §47).\n\t\t\t\t// `batchData[0]` is `(readonly OwnershipChange[])[]` — the\n\t\t\t\t// snapshots emitted this wave; take the latest (mirrors\n\t\t\t\t// `topic.latest`'s `batch.at(-1)` pattern). On a SENTINEL\n\t\t\t\t// first-activation wave fall back to `ctx.prevData[0]`.\n\t\t\t\tconst topoBatch = batchData[0] as\n\t\t\t\t\t| readonly (readonly OwnershipChange[])[]\n\t\t\t\t\t| null\n\t\t\t\t\t| undefined;\n\t\t\t\tconst log = (\n\t\t\t\t\ttopoBatch != null && topoBatch.length > 0\n\t\t\t\t\t\t? topoBatch[topoBatch.length - 1]\n\t\t\t\t\t\t: (ctx.prevData[0] as readonly OwnershipChange[] | undefined)\n\t\t\t\t) as readonly OwnershipChange[] | undefined;\n\t\t\t\tlet active: ActiveOwner | null = null;\n\t\t\t\tif (log != null) {\n\t\t\t\t\tfor (const ch of log) {\n\t\t\t\t\t\tif (ch?.change == null) continue;\n\t\t\t\t\t\tactive = applyChange(active, ch, this._supervisor);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// F3/F4 — PURE sign-of-life. Read the prior `signOfLifeNs`\n\t\t\t\t// from THIS derivation's own previously-emitted state\n\t\t\t\t// (`ctx.prevData[0]` for the `current` node is unavailable —\n\t\t\t\t// `prevData[0]` is the topic dep — so we read `ctx.cache`,\n\t\t\t\t// the node's own last emit). No instance field anywhere.\n\t\t\t\tconst prevState = (ctx.cache ?? undefined) as OwnershipState | undefined;\n\n\t\t\t\tlet nextActive: ActiveOwner | null = active;\n\t\t\t\tlet signOfLifeNs: number | null = null;\n\n\t\t\t\tif (active != null && this._ttlNs > 0) {\n\t\t\t\t\t// Carry the prior sign-of-life ONLY if it belongs to THIS\n\t\t\t\t\t// claim (>= the active claim's `sinceNs`). A value from a\n\t\t\t\t\t// prior owner (older than `sinceNs`) is discarded so a\n\t\t\t\t\t// stale beat cannot extend a freshly-claimed window. A new\n\t\t\t\t\t// owner therefore starts from its own claim time.\n\t\t\t\t\tconst carried =\n\t\t\t\t\t\tprevState?.signOfLifeNs != null && prevState.signOfLifeNs >= active.sinceNs\n\t\t\t\t\t\t\t? prevState.signOfLifeNs\n\t\t\t\t\t\t\t: active.sinceNs;\n\t\t\t\t\t// Expire FIRST against the carried sign-of-life (Q4 strict —\n\t\t\t\t\t// a late beat must NOT resurrect an already-lapsed claim),\n\t\t\t\t\t// THEN accept a still-timely beat THIS wave. `signOfLifeNs`\n\t\t\t\t\t// only ever advances on an actual beat-this-wave, so a\n\t\t\t\t\t// recompute storm with no beat cannot renew a dead claim\n\t\t\t\t\t// (idempotent re-fold).\n\t\t\t\t\tconst lapsed = nowNs - carried >= this._ttlNs;\n\t\t\t\t\tif (lapsed) {\n\t\t\t\t\t\tnextActive = null;\n\t\t\t\t\t\tsignOfLifeNs = null;\n\t\t\t\t\t} else if (beatThisWave) {\n\t\t\t\t\t\tsignOfLifeNs = nowNs; // timely beat → renew\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsignOfLifeNs = carried; // unchanged — carry forward\n\t\t\t\t\t}\n\t\t\t\t} else if (active != null) {\n\t\t\t\t\t// No TTL configured — never expires; sign-of-life still\n\t\t\t\t\t// tracked (owner-scoped) for completeness/observability.\n\t\t\t\t\tconst carried =\n\t\t\t\t\t\tprevState?.signOfLifeNs != null && prevState.signOfLifeNs >= active.sinceNs\n\t\t\t\t\t\t\t? prevState.signOfLifeNs\n\t\t\t\t\t\t\t: active.sinceNs;\n\t\t\t\t\tsignOfLifeNs = beatThisWave ? nowNs : carried;\n\t\t\t\t}\n\n\t\t\t\treturn [\n\t\t\t\t\tnextActive == null\n\t\t\t\t\t\t? EMPTY_STATE\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\towner: nextActive.owner,\n\t\t\t\t\t\t\t\tlevel: nextActive.level,\n\t\t\t\t\t\t\t\tallowed: [nextActive.owner],\n\t\t\t\t\t\t\t\tsignOfLifeNs,\n\t\t\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t},\n\t\t\t{ keepAlive: true },\n\t\t);\n\n\t\tthis.allowed = this.derived<readonly string[]>(\n\t\t\t\"allowed\",\n\t\t\t[this.current],\n\t\t\t(batchData, ctx) => {\n\t\t\t\tconst batch = batchData[0] as readonly OwnershipState[] | null | undefined;\n\t\t\t\tconst s = (batch != null && batch.length > 0 ? batch[batch.length - 1] : ctx.prevData[0]) as\n\t\t\t\t\t| OwnershipState\n\t\t\t\t\t| undefined;\n\t\t\t\treturn [s?.allowed ?? []];\n\t\t\t},\n\t\t\t{ keepAlive: true },\n\t\t);\n\t\t// F12 — `keepAlive: true` above already installs a self-pruning\n\t\t// keepalive subscription (same as `current`); a second\n\t\t// `keepalive(this.allowed)` disposer was redundant double-subscription.\n\n\t\t// Q7 — the reactive-options Guard. `policyAllowing` reads\n\t\t// `this.allowed.cache` synchronously at write-check time, so\n\t\t// claim/release/override re-point the allow-set with NO rewire.\n\t\tthis.guard = policyAllowing(this.allowed);\n\t}\n\n\t/**\n\t * Publish a `claim`. Thin reactive wrapper over `topic.publish` (message\n\t * flow per §29 — NOT an imperative trigger). `level` defaults to `\"L2\"`\n\t * when this controller has a heartbeat wired, else `\"L1\"`.\n\t */\n\tclaim(actor: string, level?: OwnershipLevel): void {\n\t\t// F14 — documented default (JSDoc + §47): L2 when a heartbeat\n\t\t// NodeInput was wired at construction, else L1.\n\t\tconst lvl = level ?? (this._hasHeartbeat ? \"L2\" : \"L1\");\n\t\tthis.topic.publish(makeChange({ kind: \"claim\", subgraphId: this.name, actor, level: lvl }));\n\t}\n\n\t/** Publish a `release`. Clears ownership iff `actor` is the current owner. */\n\trelease(actor: string): void {\n\t\tthis.topic.publish(makeChange({ kind: \"release\", subgraphId: this.name, actor }));\n\t}\n\n\t/**\n\t * Publish a supervisor `override` (L3). Wins by `level` priority\n\t * regardless of expiry (Q10). `actor` should be this controller's\n\t * `supervisor` id for the override to take precedence.\n\t */\n\toverride(actor: string, previousActor: string, reason: string): void {\n\t\tthis.topic.publish(\n\t\t\tmakeChange({ kind: \"override\", subgraphId: this.name, actor, previousActor, reason }),\n\t\t);\n\t}\n}\n\n/** Wrap an {@link OwnershipChangePayload} in the DS-14 {@link OwnershipChange} envelope. */\nfunction makeChange(payload: OwnershipChangePayload): OwnershipChange {\n\t// F2 — `BaseChange.t_ns` is contractually wall-clock (`wallClockNs()`,\n\t// see change.ts). The fold compares `nowNs (wallClockNs)` against\n\t// `ch.t_ns` for TTL/expiry, so stamp + compare MUST use the same clock.\n\tconst t = wallClockNs();\n\treturn { structure: \"ownership\", version: t, t_ns: t, lifecycle: \"ownership\", change: payload };\n}\n\n/**\n * Fold one ownership change into the resolved-owner state.\n *\n * - `claim` — sets the active owner (records claim time for L1 TTL). A\n * lower-priority claim cannot displace a higher-`level` live owner (Q10 —\n * override arbitration is pure level comparison).\n * - `release` — clears ownership iff the releasing actor is the owner.\n * - `override` — supervisor override: wins by `level` priority. Carries\n * `previousActor` + `reason` per DS-14 (Q3); modeled as an L3 hand-off to\n * `p.actor`.\n */\nfunction applyChange(\n\tactive: ActiveOwner | null,\n\tch: OwnershipChange,\n\tsupervisor: string | undefined,\n): ActiveOwner | null {\n\tconst p = ch.change;\n\t// Use the change's publish timestamp (`t_ns` — wall-clock, stamped in\n\t// `makeChange`) as the claim time — NOT the fold time. The log is re-folded\n\t// from scratch on every recompute (§47), so stamping a fresh clock read\n\t// here would re-baseline the TTL window every recompute and the claim would\n\t// never expire. The fold compares against `wallClockNs()` (F2 — same clock).\n\tif (p.kind === \"claim\") {\n\t\tif (active != null && LEVEL_RANK[active.level] > LEVEL_RANK[p.level]) return active;\n\t\treturn { owner: p.actor, level: p.level, sinceNs: ch.t_ns };\n\t}\n\tif (p.kind === \"release\") {\n\t\tif (active != null && active.owner === p.actor) return null;\n\t\treturn active;\n\t}\n\t// override (F5) — a `kind:\"override\"` only seizes ownership when the\n\t// publishing actor IS the configured supervisor. The prior disjunction\n\t// `|| LEVEL_RANK.L3 >= LEVEL_RANK[active.level]` was a tautology (L3 is the\n\t// max rank ⇒ always true), so ANY actor's override took over. If no\n\t// supervisor is configured, overrides are explicitly disabled (a non-null\n\t// `supervisor` is the gate, not an accidental fall-through).\n\tconst isSupervisor = supervisor != null && p.actor === supervisor;\n\tif (isSupervisor) {\n\t\treturn { owner: p.actor, level: \"L3\", sinceNs: ch.t_ns };\n\t}\n\treturn active;\n}\n\n/**\n * Create a multi-agent subgraph ownership controller (DS-14.5.A #8).\n *\n * @example\n * ```ts\n * const oc = ownershipController(\"payments\", { ttl: 30_000, supervisor: \"lead\" });\n * // Mount the Guard on the owned subgraph:\n * const n = node([], { initial: 0, guard: oc.guard });\n * oc.claim(\"agent-a\"); // agent-a now owns; non-owner writes throw\n * oc.override(\"lead\", \"agent-a\", \"rebalance\"); // supervisor takes over\n * ```\n */\nexport function ownershipController(\n\tname: string,\n\topts: OwnershipControllerOptions,\n): OwnershipControllerGraph {\n\treturn new OwnershipControllerGraph(name, opts);\n}\n","/**\n * Harness-specific graph profiling (roadmap §9.0).\n *\n * Extends {@link graphProfile} with harness domain counters:\n * queue depths, strategy entries, retry/reingestion tracker sizes.\n *\n * @module\n */\n\nimport {\n\ttype GraphProfileOptions,\n\ttype GraphProfileResult,\n\tgraphProfile,\n} from \"@graphrefly/pure-ts/graph\";\nimport { QUEUE_NAMES } from \"../../utils/harness/defaults.js\";\nimport type { QueueRoute, TriagedItem } from \"../../utils/harness/types.js\";\nimport type { HarnessGraph } from \"./harness-loop.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Harness-specific profile extending the base graph profile. */\nexport interface HarnessProfileResult extends GraphProfileResult {\n\t/** Per-queue retained item counts. */\n\tqueueDepths: Record<QueueRoute, number>;\n\t/** Number of rootCause→intervention entries in the strategy model. */\n\tstrategyEntries: number;\n\t/** Global retry count across all items. */\n\ttotalRetries: number;\n\t/** Global reingestion count across all items. */\n\ttotalReingestions: number;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Profile a harness graph with domain-specific counters.\n *\n * **Snapshot caveat (Unit 22 B).** Reads `.cache` values from the\n * strategy / retry / reingestion nodes + each queue topic's `.retained()`\n * view. These are point-in-time reads and are not transactional — if you\n * invoke this during an in-flight reactive wave the values may reflect\n * a partially-settled frame. For end-of-wave accuracy, call from outside\n * any batch boundary.\n *\n * @param harness - The HarnessGraph to profile.\n * @param opts - Optional base profile options.\n * @returns Harness profile with queue depths, strategy stats, and tracker sizes.\n */\nexport function harnessProfile(\n\tharness: HarnessGraph,\n\topts?: GraphProfileOptions,\n): HarnessProfileResult {\n\tconst base = graphProfile(harness, opts);\n\n\t// Unit 22 B: iterate the hub's topic registry instead of a raw Map so\n\t// queue topics added post-construction (dead-letter `__unrouted`, etc.)\n\t// don't get silently ignored.\n\tconst queueDepths: Record<string, number> = {};\n\tfor (const route of QUEUE_NAMES) {\n\t\tconst t = harness.queues.has(route) ? harness.queues.topic<TriagedItem>(route) : null;\n\t\tqueueDepths[route] = t?.retained().length ?? 0;\n\t}\n\n\treturn {\n\t\t...base,\n\t\tqueueDepths: queueDepths as Record<QueueRoute, number>,\n\t\tstrategyEntries: harness.strategy.entries.cache?.size ?? 0,\n\t\ttotalRetries: harness.totalRetries.cache ?? 0,\n\t\ttotalReingestions: harness.totalReingestions.cache ?? 0,\n\t};\n}\n","/**\n * Harness pipeline trace — thin sugar over `graph.observe({ format: \"stage-log\" })`.\n *\n * Since 2026-04-22 (D2), stage-labeled tracing is a first-class observe format\n * on {@link Graph}. `harnessTrace` wires that format over the 7 pipeline stages\n * (INTAKE → TRIAGE → QUEUE → GATE → EXECUTE → VERIFY → STRATEGY) with sensible\n * defaults so harness consumers don't need to restate the stage map.\n *\n * For non-harness graphs, call `graph.observe({ format: \"stage-log\", stageLabels })`\n * directly — the format is domain-agnostic.\n *\n * @module\n */\n\nimport { monotonicNs } from \"@graphrefly/pure-ts/core\";\nimport type { ObserveEvent, ObserveResult } from \"@graphrefly/pure-ts/graph\";\nimport type { HarnessGraph } from \"./harness-loop.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Event type captured by structured trace. */\nexport type TraceEventType = \"data\" | \"error\" | \"complete\";\n\n/** A single structured trace event. */\nexport interface TraceEvent {\n\t/** Elapsed seconds since trace was created. */\n\telapsed: number;\n\t/** Pipeline stage label (INTAKE, TRIAGE, QUEUE, GATE, EXECUTE, VERIFY, STRATEGY). */\n\tstage: string;\n\t/** Event type. */\n\ttype: TraceEventType;\n\t/** Data payload (present for \"data\" and \"error\" events). Omitted at \"summary\" detail. */\n\tdata?: unknown;\n\t/** Human-readable summary of the data. Present at \"standard\" and \"full\" detail. */\n\tsummary?: string;\n}\n\n/** Detail level for trace output. */\nexport type TraceDetail =\n\t/** Stage + elapsed only. No data preview. Lowest overhead. */\n\t| \"summary\"\n\t/** Stage + elapsed + truncated data preview. Default. */\n\t| \"standard\"\n\t/** Stage + elapsed + full raw data. Use for debugging, not production. */\n\t| \"full\";\n\n/** Handle returned by {@link harnessTrace}. Call `dispose()` to stop tracing. */\nexport interface HarnessTraceHandle {\n\t/** Stop tracing and detach all observers. Safe to call multiple times. */\n\tdispose(): void;\n\t/**\n\t * Structured trace events collected since creation. Plain array — no\n\t * subscription needed (COMPOSITION-GUIDE §1: avoid lazy-activation\n\t * friction for inspection tools). Populated reactively via observe().\n\t */\n\treadonly events: readonly TraceEvent[];\n}\n\n/** Options for {@link harnessTrace}. */\nexport interface HarnessTraceOptions {\n\t/** Sink for rendered trace lines. Default: `console.log`. Pass `null` for structured-only. */\n\tlogger?: ((line: string) => void) | null;\n\t/** Detail level for both string and structured output. Default: `\"summary\"`. */\n\tdetail?: TraceDetail;\n}\n\n// ---------------------------------------------------------------------------\n// Stage labels\n// ---------------------------------------------------------------------------\n\n/**\n * Observe paths → stage labels for the 7 harness stages. Path set is\n * sourced from {@link HarnessGraph.stageNodes} so inspection tools stay\n * decoupled from mount-structure changes (Unit 22 C).\n */\nfunction buildStageLabels(harness: HarnessGraph): Record<string, string> {\n\tconst labels: Record<string, string> = {};\n\tfor (const { label, paths } of harness.stageNodes()) {\n\t\tfor (const p of paths) labels[p] = label;\n\t}\n\treturn labels;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Attach a stage-log trace over the harness pipeline. Delegates to\n * `harness.observe({ format: \"stage-log\", ... })` for each stage path —\n * every event is captured in `handle.events` (structured) AND rendered via\n * the `logger` (string output).\n *\n * **Detail levels:**\n * - `\"summary\"` — stage + elapsed only. Minimal overhead.\n * - `\"standard\"` (default) — stage + elapsed + truncated data preview.\n * - `\"full\"` — stage + elapsed + full raw data object in events.\n *\n * Elapsed timestamps are relative to the `harnessTrace()` invocation time,\n * not the first event.\n */\nexport function harnessTrace(\n\tharness: HarnessGraph,\n\topts?: HarnessTraceOptions,\n): HarnessTraceHandle {\n\tconst logger: ((line: string) => void) | null =\n\t\topts?.logger === null ? null : (opts?.logger ?? console.log);\n\tconst detail: TraceDetail = opts?.detail ?? \"summary\";\n\tconst startNs = monotonicNs();\n\tconst observations: ObserveResult[] = [];\n\tconst events: TraceEvent[] = [];\n\tconst stageLabels = buildStageLabels(harness);\n\n\tfunction elapsedSecs(): number {\n\t\treturn (monotonicNs() - startNs) / 1e9;\n\t}\n\n\tfunction recordEvent(stage: string, type: TraceEventType, rawData: unknown): void {\n\t\tconst ev: TraceEvent = { elapsed: elapsedSecs(), stage, type };\n\t\tif (detail !== \"summary\") ev.summary = summarize(rawData);\n\t\tif (detail === \"full\") ev.data = rawData;\n\t\tevents.push(ev);\n\t}\n\n\t// One observe call per path — keeps per-stage elapsed offsets anchored to\n\t// this invocation (the shared stage-log format uses its own elapsed clock\n\t// per observation, which matches the legacy behavior). We also intercept\n\t// each event through `onEvent` so structured `events[]` stays populated\n\t// regardless of `logger`.\n\tfor (const [path, stage] of Object.entries(stageLabels)) {\n\t\ttry {\n\t\t\tconst obs = harness.observe(path, {\n\t\t\t\tformat: \"stage-log\",\n\t\t\t\tstageLabels,\n\t\t\t\tlogger: logger ? (line: string) => logger(line) : () => {},\n\t\t\t\tincludeTypes: [\"data\", \"error\", \"complete\"],\n\t\t\t});\n\t\t\tobs.onEvent((event: ObserveEvent) => {\n\t\t\t\tif (event.type === \"data\") recordEvent(stage, \"data\", (event as { data: unknown }).data);\n\t\t\t\telse if (event.type === \"error\")\n\t\t\t\t\trecordEvent(stage, \"error\", (event as { data: unknown }).data);\n\t\t\t\telse if (event.type === \"complete\") recordEvent(stage, \"complete\", undefined);\n\t\t\t});\n\t\t\tobservations.push(obs);\n\t\t} catch (err) {\n\t\t\t// Node may not exist yet (e.g., a gated-queue route that hasn't been\n\t\t\t// mounted on this harness). Record a synthetic error trace event so\n\t\t\t// consumers see WHICH stage dropped out and why — silent swallow\n\t\t\t// breaks dry-run equivalence (a regression in stage wiring would\n\t\t\t// not surface in the trace).\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\trecordEvent(stage, \"error\", `observe-unavailable: ${path} — ${msg}`);\n\t\t\tif (logger) {\n\t\t\t\tlogger(`[${elapsedSecs().toFixed(3)}s] ${stage.padEnd(9)} ✗ observe-unavailable: ${msg}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tget events(): readonly TraceEvent[] {\n\t\t\treturn events;\n\t\t},\n\t\tdispose() {\n\t\t\tfor (const obs of observations) obs.dispose();\n\t\t\tobservations.length = 0;\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — kept here because `observe({ format: \"stage-log\" })` emits short\n// one-line previews; the structured `events[]` is free to carry richer\n// summaries with different truncation bounds (120 for JSON, 80 for strings).\n// ---------------------------------------------------------------------------\n\nfunction summarize(value: unknown): string {\n\tif (value == null) return \"null\";\n\tif (typeof value === \"string\") return truncate(value, 80);\n\tif (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n\tif (typeof value === \"bigint\") return String(value);\n\ttry {\n\t\tconst json = JSON.stringify(value);\n\t\treturn truncate(json, 120);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length > max ? `${s.slice(0, max - 1)}…` : s;\n}\n"],"mappings":"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","names":["node","filter","Graph","node","node","batch","defaultToOutput","Graph","node","batch","filter","Graph","Graph","batch"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base/composition/single-from-any.ts"],"sourcesContent":["/**\n * `singleFromAny` — keyed promise/Node de-duplication (\"singleflight\").\n *\n * Given a `factory: (key) => NodeInput<T>`, returns a callable that dedupes\n * concurrent invocations sharing the same key — all callers with the same\n * key while a request is in-flight receive the same `Promise<T>`. Once the\n * underlying source settles (DATA, ERROR, or COMPLETE), the cache entry is\n * cleared so the next call re-invokes the factory.\n *\n * This is the classic \"singleflight\" pattern from Go, generalised over the\n * library's `NodeInput<T>` bridge so callers can pass Promise-returning\n * factories, Node-returning factories, or plain value factories with\n * identical semantics.\n *\n * Use cases:\n * - `withReplayCache` cache-miss thundering-herd dedup\n * - Shared HTTP fetches keyed by URL\n * - Expensive compute keyed by request fingerprint\n *\n * @example\n * ```ts\n * const fetchUser = singleFromAny<string, User>((id) => fetch(`/users/${id}`).then(r => r.json()));\n * // Two concurrent callers with id=\"42\" → one underlying fetch, two Promises resolving to the same User.\n * const [a, b] = await Promise.all([fetchUser(\"42\"), fetchUser(\"42\")]);\n * ```\n *\n * @category extra\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport { COMPLETE, ERROR } from \"@graphrefly/pure-ts/core\";\n// Import directly from the source sub-files (rather than the `./sources.js`\n// barrel) so the `single-from-any` module is NOT part of any cycle that runs\n// through `extra/sources/index.ts` — eager re-exports through the barrel were\n// observed to leave `firstValueFrom` / `keepalive` unresolved during nested\n// import chains under vite-node.\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../sources/settled.js\";\n\nexport interface SingleFromAnyOptions<K> {\n\t/**\n\t * Convert a typed key into a cache-string. Defaults to `String(key)`, which\n\t * works for primitive keys; callers with object keys should provide a\n\t * stable serializer (e.g., canonical JSON).\n\t */\n\tkeyFn?: (key: K) => string;\n}\n\n/**\n * Dedupe concurrent `factory(key)` invocations. Returns a bound callable.\n *\n * @param factory - Produces a `NodeInput<T>` for each unique key.\n * @param opts - Optional key-stringification.\n * @returns A function `(key: K) => Promise<T>` whose inflight results are shared per key.\n */\nexport function singleFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Promise<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Promise<T>>();\n\n\treturn (key: K): Promise<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst input = factory(key);\n\n\t\t// Resolve the NodeInput to a Promise<T>. Different input shapes need\n\t\t// different bridges — Promise/Node/AsyncIterable/Iterable/plain value.\n\t\tlet rawPromise: Promise<T>;\n\t\tif (input != null && typeof (input as PromiseLike<T>).then === \"function\") {\n\t\t\trawPromise = Promise.resolve(input as PromiseLike<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\t\"subscribe\" in (input as object) &&\n\t\t\t\"cache\" in (input as object)\n\t\t) {\n\t\t\t// Node: bridge via firstValueFrom.\n\t\t\trawPromise = firstValueFrom(input as Node<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\tSymbol.asyncIterator in (input as object)\n\t\t) {\n\t\t\t// AsyncIterable — take the first value, then close the iterator so\n\t\t\t// any owned resources (HTTP body, subscription, timer) are released.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as AsyncIterable<T>)[Symbol.asyncIterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = await iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty async iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\tawait iter.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else if (input != null && typeof input === \"object\" && Symbol.iterator in (input as object)) {\n\t\t\t// Iterable — take the first value, close the iterator.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as Iterable<T>)[Symbol.iterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\titer.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else {\n\t\t\t// Plain value.\n\t\t\trawPromise = Promise.resolve(input as T);\n\t\t}\n\n\t\t// Install the cache entry BEFORE attaching `.finally`. Otherwise a\n\t\t// sync-resolved Promise's finally microtask could run before the\n\t\t// `inFlight.set` below, leaving a stale entry installed afterwards.\n\t\t// We wrap in a holder whose reference we capture *before* chaining.\n\t\tlet tracked!: Promise<T>;\n\t\tconst cleanup = (): void => {\n\t\t\tif (inFlight.get(k) === tracked) inFlight.delete(k);\n\t\t};\n\t\ttracked = rawPromise.then(\n\t\t\t(v) => {\n\t\t\t\tcleanup();\n\t\t\t\treturn v;\n\t\t\t},\n\t\t\t(e) => {\n\t\t\t\tcleanup();\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\t\tinFlight.set(k, tracked);\n\t\treturn tracked;\n\t};\n}\n\n/**\n * Reactive variant: returns a bound callable that hands out `Node<T>` values.\n * All concurrent callers with the same key during an in-flight source share\n * the same Node. When the underlying source **terminally** settles (ERROR\n * or COMPLETE), the Node is removed from the cache so the next call\n * re-invokes `factory`. DATA is NOT terminal — callers subscribing after\n * the first DATA still receive the shared Node (and push-on-subscribe per\n * the spec's cached-DATA contract).\n *\n * Use when downstream wants reactive subscription (not a one-shot Promise).\n *\n * @category extra\n */\nexport function singleNodeFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Node<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Node<T>>();\n\n\treturn (key: K): Node<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst node = fromAny(factory(key));\n\t\tinFlight.set(k, node);\n\n\t\t// Evict on terminal settle only — ERROR or COMPLETE. DATA is a value\n\t\t// emission, not a lifecycle transition; multi-emitting Nodes should\n\t\t// continue to share across subscribers after the first value.\n\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === ERROR || m[0] === COMPLETE) {\n\t\t\t\t\tif (inFlight.get(k) === node) inFlight.delete(k);\n\t\t\t\t\tunsub();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn node;\n\t};\n}\n"],"mappings":";;;;;AA8BA,SAAS,UAAU,aAAa;AAMhC,SAAS,eAA+B;AAmBjC,SAAS,cACf,SACA,OAAgC,CAAC,GACR;AACzB,QAAM,QAAQ,KAAK,UAAU,CAAC,MAAS,OAAO,CAAC;AAC/C,QAAM,WAAW,oBAAI,IAAwB;AAE7C,SAAO,CAAC,QAAuB;AAC9B,UAAM,IAAI,MAAM,GAAG;AACnB,UAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,QAAI,SAAU,QAAO;AAErB,UAAM,QAAQ,QAAQ,GAAG;AAIzB,QAAI;AACJ,QAAI,SAAS,QAAQ,OAAQ,MAAyB,SAAS,YAAY;AAC1E,mBAAa,QAAQ,QAAQ,KAAuB;AAAA,IACrD,WACC,SAAS,QACT,OAAO,UAAU,YACjB,eAAgB,SAChB,WAAY,OACX;AAED,mBAAa,eAAe,KAAgB;AAAA,IAC7C,WACC,SAAS,QACT,OAAO,UAAU,YACjB,OAAO,iBAAkB,OACxB;AAGD,oBAAc,YAAY;AACzB,cAAM,OAAQ,MAA2B,OAAO,aAAa,EAAE;AAC/D,YAAI;AACH,gBAAM,EAAE,OAAO,KAAK,IAAI,MAAM,KAAK,KAAK;AACxC,cAAI,KAAM,OAAM,IAAI,MAAM,sDAAsD;AAChF,iBAAO;AAAA,QACR,UAAE;AACD,gBAAM,KAAK,SAAS;AAAA,QACrB;AAAA,MACD,GAAG;AAAA,IACJ,WAAW,SAAS,QAAQ,OAAO,UAAU,YAAY,OAAO,YAAa,OAAkB;AAE9F,oBAAc,YAAY;AACzB,cAAM,OAAQ,MAAsB,OAAO,QAAQ,EAAE;AACrD,YAAI;AACH,gBAAM,EAAE,OAAO,KAAK,IAAI,KAAK,KAAK;AAClC,cAAI,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC1E,iBAAO;AAAA,QACR,UAAE;AACD,eAAK,SAAS;AAAA,QACf;AAAA,MACD,GAAG;AAAA,IACJ,OAAO;AAEN,mBAAa,QAAQ,QAAQ,KAAU;AAAA,IACxC;AAMA,QAAI;AACJ,UAAM,UAAU,MAAY;AAC3B,UAAI,SAAS,IAAI,CAAC,MAAM,QAAS,UAAS,OAAO,CAAC;AAAA,IACnD;AACA,cAAU,WAAW;AAAA,MACpB,CAAC,MAAM;AACN,gBAAQ;AACR,eAAO;AAAA,MACR;AAAA,MACA,CAAC,MAAM;AACN,gBAAQ;AACR,cAAM;AAAA,MACP;AAAA,IACD;AACA,aAAS,IAAI,GAAG,OAAO;AACvB,WAAO;AAAA,EACR;AACD;AAeO,SAAS,kBACf,SACA,OAAgC,CAAC,GACX;AACtB,QAAM,QAAQ,KAAK,UAAU,CAAC,MAAS,OAAO,CAAC;AAC/C,QAAM,WAAW,oBAAI,IAAqB;AAE1C,SAAO,CAAC,QAAoB;AAC3B,UAAM,IAAI,MAAM,GAAG;AACnB,UAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,QAAI,SAAU,QAAO;AAErB,UAAM,OAAO,QAAQ,QAAQ,GAAG,CAAC;AACjC,aAAS,IAAI,GAAG,IAAI;AAKpB,UAAM,QAAQ,KAAK,UAAU,CAAC,SAAS;AACtC,iBAAW,KAAK,MAAM;AACrB,YAAI,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,MAAM,UAAU;AACxC,cAAI,SAAS,IAAI,CAAC,MAAM,KAAM,UAAS,OAAO,CAAC;AAC/C,gBAAM;AACN;AAAA,QACD;AAAA,MACD;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base/mutation/index.ts"],"sourcesContent":["/**\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"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/base/sources/async.ts"],"sourcesContent":["/**\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\tstopped = true;\n\t\t\tunsub?.();\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\tsource.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\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\tsource.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\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"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/presets/ai/debate/index.ts"],"sourcesContent":["/**\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\tcancelled = true;\n\t\t\t\t\t\tac.abort();\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":[]}
|