@tangle-network/agent-runtime 0.94.0 → 0.94.1

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.
Files changed (56) hide show
  1. package/dist/agent.js +4 -4
  2. package/dist/{agentic-generator-B8oeE2Yv.d.ts → agentic-generator-D9ZmAuiL.d.ts} +1 -1
  3. package/dist/candidate-execution/index.js +3 -3
  4. package/dist/{chunk-OO4EK3JB.js → chunk-D336OZHK.js} +6 -3
  5. package/dist/chunk-D336OZHK.js.map +1 -0
  6. package/dist/{chunk-4GBT4WQ6.js → chunk-HPCJBBLS.js} +2 -2
  7. package/dist/{chunk-RTVVH2KL.js → chunk-JEP2WM24.js} +2 -2
  8. package/dist/{chunk-55P6V5JT.js → chunk-K7OPNHU4.js} +2 -2
  9. package/dist/{chunk-7I2AOKCI.js → chunk-KHLE3C5G.js} +2 -2
  10. package/dist/{chunk-4E2GM63H.js → chunk-MZH4HORF.js} +2 -2
  11. package/dist/chunk-PJNGPWTA.js +634 -0
  12. package/dist/chunk-PJNGPWTA.js.map +1 -0
  13. package/dist/{chunk-MRYPFDHJ.js → chunk-RTSZNYXM.js} +3 -3
  14. package/dist/{chunk-H2D3DCEB.js → chunk-SJHFJOCY.js} +2 -2
  15. package/dist/{chunk-FHZHADIM.js → chunk-URMJTSXB.js} +52 -10
  16. package/dist/chunk-URMJTSXB.js.map +1 -0
  17. package/dist/{chunk-3D2RHC4K.js → chunk-WIPGQ4GT.js} +1 -1
  18. package/dist/{chunk-3D2RHC4K.js.map → chunk-WIPGQ4GT.js.map} +1 -1
  19. package/dist/{completion-gate-BDkEYB_-.d.ts → completion-gate-BAj3dXeW.d.ts} +14 -2
  20. package/dist/{coordination-EGoRbbsd.d.ts → coordination-B3ZuApR_.d.ts} +5 -3
  21. package/dist/environment-provider.d.ts +1 -1
  22. package/dist/{improve-ZzTEkpF_.d.ts → improve-r8SvIxYv.d.ts} +2 -2
  23. package/dist/index.d.ts +11 -11
  24. package/dist/index.js +11 -11
  25. package/dist/intelligence.d.ts +3 -3
  26. package/dist/intelligence.js +5 -5
  27. package/dist/knowledge.d.ts +5 -5
  28. package/dist/knowledge.js +4 -4
  29. package/dist/lifecycle.d.ts +3 -3
  30. package/dist/lifecycle.js +2 -2
  31. package/dist/{local-harness-dcD5WTTr.d.ts → local-harness-B7bNuNJw.d.ts} +49 -1
  32. package/dist/{loop-runner-bin-BRXC1RwC.d.ts → loop-runner-bin-D4bMIxmB.d.ts} +2 -2
  33. package/dist/loop-runner-bin.d.ts +5 -5
  34. package/dist/loop-runner-bin.js +5 -5
  35. package/dist/loops.d.ts +11 -11
  36. package/dist/loops.js +4 -4
  37. package/dist/mcp/bin.js +3 -3
  38. package/dist/mcp/index.d.ts +7 -7
  39. package/dist/mcp/index.js +7 -5
  40. package/dist/mcp/index.js.map +1 -1
  41. package/dist/{mcp-serve-verifier-Bg4C3p5S.d.ts → mcp-serve-verifier-BuXjaZDE.d.ts} +1 -1
  42. package/dist/{supervise-Gmf709kn.d.ts → supervise-DTNcLDl2.d.ts} +3 -3
  43. package/dist/{types-Cg_teUPO.d.ts → types-Bb-CqxJH.d.ts} +3 -0
  44. package/dist/{worktree-fanout-BrB4att3.d.ts → worktree-fanout-IMKqdV_E.d.ts} +13 -13
  45. package/package.json +1 -1
  46. package/dist/chunk-FHZHADIM.js.map +0 -1
  47. package/dist/chunk-OO4EK3JB.js.map +0 -1
  48. package/dist/chunk-PX6SXX3M.js +0 -146
  49. package/dist/chunk-PX6SXX3M.js.map +0 -1
  50. /package/dist/{chunk-4GBT4WQ6.js.map → chunk-HPCJBBLS.js.map} +0 -0
  51. /package/dist/{chunk-RTVVH2KL.js.map → chunk-JEP2WM24.js.map} +0 -0
  52. /package/dist/{chunk-55P6V5JT.js.map → chunk-K7OPNHU4.js.map} +0 -0
  53. /package/dist/{chunk-7I2AOKCI.js.map → chunk-KHLE3C5G.js.map} +0 -0
  54. /package/dist/{chunk-4E2GM63H.js.map → chunk-MZH4HORF.js.map} +0 -0
  55. /package/dist/{chunk-MRYPFDHJ.js.map → chunk-RTSZNYXM.js.map} +0 -0
  56. /package/dist/{chunk-H2D3DCEB.js.map → chunk-SJHFJOCY.js.map} +0 -0
@@ -70,4 +70,4 @@ export {
70
70
  InMemoryResultBlobStore,
71
71
  InMemorySpawnJournal
72
72
  };
73
- //# sourceMappingURL=chunk-3D2RHC4K.js.map
73
+ //# sourceMappingURL=chunk-WIPGQ4GT.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/durable/spawn-journal.ts"],"sourcesContent":["/**\n *\n * Event-sourced spawn journal for the recursive execution atom (build steps 3 + 7).\n *\n * The supervision tree is journaled as an append-only event log: every `spawned`,\n * `settled`, and `cancelled` is recorded AFTER it is observed-committed (never\n * speculative), mirroring `ConversationJournal`'s begin/append/load shape. The log\n * holds only the THIN decision record — ids, parentage, budget, the spend a decision\n * consumed, and a content-addressed `outRef`. The payloads the driver branched on\n * (the `out` artifacts) live in a separate `ResultBlobStore`, keyed by `outRef`, so\n * the journal stays small (decisions) and replay rehydrates the exact `Settled` from\n * the blob store (evidence). This is the decision/payload split the replay argument\n * rests on (B1/B2).\n *\n * Replay determinism (B2): `seq` is the monotonic cursor order `scope.next()` yielded\n * each settlement — NOT wall-clock. `replaySpawnTree` sorts strictly by `seq` before\n * touching the blob store, so the order in which rehydration `get`s resolve can never\n * reorder the replayed `Settled[]`; the result is identical regardless of blob latency.\n *\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport type {\n NodeId,\n NodeSnapshot,\n NodeStatus,\n ResultBlobStore,\n Runtime,\n Settled,\n SpawnEvent,\n SpawnJournal,\n Spend,\n TreeView,\n} from '../runtime/supervise/types'\nimport { zeroTokenUsage } from '../runtime/util'\n\n// ── Content addressing ──────────────────────────────────────────────────────\n\n/**\n * Mint the content-addressed `outRef` for a result artifact: `sha256:<hex>` over a\n * stable JSON encoding. Producers call this to derive the `outRef` they journal and\n * `put`; the FS/in-mem stores re-derive it on `put` to verify the supplied ref\n * matches (fail loud on a mismatch — a forged ref breaks the replay invariant).\n *\n * Stable encoding: object keys are sorted recursively so two structurally-equal\n * artifacts hash identically regardless of key insertion order.\n */\nexport function contentAddress(artifact: unknown): string {\n const hex = createHash('sha256').update(stableStringify(artifact), 'utf-8').digest('hex')\n return `sha256:${hex}`\n}\n\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null'\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(',')}}`\n}\n\n// ── Result blob store ─────────────────────────────────────────────────────────\n\n/**\n * In-memory `ResultBlobStore`. Content-addressed: `put` verifies the supplied\n * `outRef` matches the artifact's hash so a stale/forged ref fails loud rather than\n * silently rehydrating the wrong payload. Idempotent on an identical re-put.\n */\nexport class InMemoryResultBlobStore implements ResultBlobStore {\n private readonly blobs = new Map<string, unknown>()\n\n async put(outRef: string, artifact: unknown): Promise<void> {\n assertContentAddress(outRef, artifact)\n this.blobs.set(outRef, artifact)\n }\n\n async get(outRef: string): Promise<unknown | undefined> {\n return this.blobs.has(outRef) ? this.blobs.get(outRef) : undefined\n }\n}\n\n/**\n * FS `ResultBlobStore`. One JSON file per artifact under `dir`, named by a\n * filesystem-safe encoding of the `outRef` (`sha256:<hex>` → `sha256-<hex>.json`).\n * `put` fsyncs so a crash between writes never loses an acknowledged blob.\n */\nexport class FileResultBlobStore implements ResultBlobStore {\n constructor(private readonly dir: string) {}\n\n async put(outRef: string, artifact: unknown): Promise<void> {\n assertContentAddress(outRef, artifact)\n const fs = await import('node:fs/promises')\n await fs.mkdir(this.dir, { recursive: true })\n const fh = await fs.open(this.blobPath(outRef), 'w')\n try {\n await fh.write(JSON.stringify(artifact))\n await fh.sync()\n } finally {\n await fh.close()\n }\n }\n\n async get(outRef: string): Promise<unknown | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.blobPath(outRef), 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n return JSON.parse(text)\n }\n\n private blobPath(outRef: string): string {\n return `${this.dir}/${outRef.replace(/:/g, '-')}.json`\n }\n}\n\nfunction assertContentAddress(outRef: string, artifact: unknown): void {\n const expected = contentAddress(artifact)\n if (outRef !== expected) {\n throw new Error(\n `blob outRef '${outRef}' does not match the artifact content hash '${expected}'; ` +\n 'a content-addressed store refuses a mismatched ref (breaks the replay invariant)',\n )\n }\n}\n\n// ── Spawn journal ──────────────────────────────────────────────────────────────\n\n/**\n * In-memory `SpawnJournal`. Appends are observed-committed only; the impl enforces\n * the corruption guards a durable replay rests on:\n * - an event before `beginTree` is a corrupted tree (fail loud),\n * - a duplicate `seq` within a tree is a corrupted cursor (fail loud) — two\n * settlements cannot share the cursor position replay orders by.\n */\nexport class InMemorySpawnJournal implements SpawnJournal {\n private readonly trees = new Map<NodeId, { begunAt: string; events: SpawnEvent[] }>()\n\n async loadTree(root: NodeId): Promise<SpawnEvent[] | undefined> {\n const tree = this.trees.get(root)\n if (!tree) return undefined\n return tree.events.map((ev) => ({ ...ev }))\n }\n\n async beginTree(root: NodeId, at: string): Promise<void> {\n const existing = this.trees.get(root)\n if (existing) {\n if (existing.begunAt !== at) {\n throw new Error(\n `spawn tree '${root}' already begun at ${existing.begunAt}; refusing to overwrite with ${at}`,\n )\n }\n return\n }\n this.trees.set(root, { begunAt: at, events: [] })\n }\n\n async appendEvent(root: NodeId, ev: SpawnEvent): Promise<void> {\n const tree = this.trees.get(root)\n if (!tree) {\n throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`)\n }\n assertSeqUnique(root, tree.events, ev)\n tree.events.push({ ...ev })\n }\n}\n\n/**\n * JSONL on disk. One line per record: the first record is `begin`, subsequent records\n * are `event` envelopes wrapping a `SpawnEvent`. `loadTree` replays the whole file,\n * filtering by `root`, and applies the same begin-precedes-events + unique-seq\n * corruption guards as the in-memory impl. Each append fsyncs so a crash between\n * writes never loses an acknowledged event.\n */\nexport class FileSpawnJournal implements SpawnJournal {\n constructor(private readonly path: string) {}\n\n async loadTree(root: NodeId): Promise<SpawnEvent[] | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.path, 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n const lines = text.split('\\n').filter((line) => line.length > 0)\n let begun = false\n const events: SpawnEvent[] = []\n for (const line of lines) {\n const record = JSON.parse(line) as SpawnJournalRecord\n if (record.root !== root) continue\n if (record.kind === 'begin') {\n begun = true\n } else {\n if (!begun) {\n throw new Error(\n `spawn journal corrupted: event for tree '${root}' precedes its begin record`,\n )\n }\n assertSeqUnique(root, events, record.event)\n events.push(record.event)\n }\n }\n return begun ? events : undefined\n }\n\n async beginTree(root: NodeId, at: string): Promise<void> {\n const existing = await this.loadTreeBegin(root)\n if (existing) {\n if (existing !== at) {\n throw new Error(\n `spawn tree '${root}' already begun in ${this.path} at ${existing}; refusing to overwrite with ${at}`,\n )\n }\n return\n }\n await this.appendRecord({ kind: 'begin', root, at })\n }\n\n async appendEvent(root: NodeId, ev: SpawnEvent): Promise<void> {\n const events = await this.loadTree(root)\n if (events === undefined) {\n throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`)\n }\n assertSeqUnique(root, events, ev)\n await this.appendRecord({ kind: 'event', root, event: ev })\n }\n\n private async loadTreeBegin(root: NodeId): Promise<string | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.path, 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n const lines = text.split('\\n').filter((line) => line.length > 0)\n for (const line of lines) {\n const record = JSON.parse(line) as SpawnJournalRecord\n if (record.root === root && record.kind === 'begin') return record.at\n }\n return undefined\n }\n\n private async appendRecord(record: SpawnJournalRecord): Promise<void> {\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n await fs.mkdir(path.dirname(this.path), { recursive: true })\n const fh = await fs.open(this.path, 'a')\n try {\n await fh.write(`${JSON.stringify(record)}\\n`)\n await fh.sync()\n } finally {\n await fh.close()\n }\n }\n}\n\ntype SpawnJournalRecord =\n | { kind: 'begin'; root: NodeId; at: string }\n | { kind: 'event'; root: NodeId; event: SpawnEvent }\n\n/**\n * Two `seq` namespaces share the journal: a `spawned` event's `seq` is the spawn ordinal\n * (the order children were created), and a `settled`/`cancelled` event's `seq` is the\n * monotonic CURSOR order `scope.next()` yielded that settlement (B2). The uniqueness\n * replay rests on is the cursor namespace — two settlements cannot share the position\n * replay orders by — so the guard checks only settled/cancelled events. A `spawned`\n * ordinal legitimately equals a later `settled` cursor seq and is not a collision.\n */\nfunction assertSeqUnique(root: NodeId, events: SpawnEvent[], ev: SpawnEvent): void {\n // `spawned` (ordinal namespace) and `metered` (informational spend, no settlement order) live\n // outside the cursor-uniqueness namespace replay relies on.\n if (ev.kind === 'spawned' || ev.kind === 'metered') return\n if (events.some((e) => e.kind !== 'spawned' && e.kind !== 'metered' && e.seq === ev.seq)) {\n throw new Error(\n `spawn journal corrupted: duplicate cursor seq ${ev.seq} in tree '${root}'; ` +\n 'the cursor order replay relies on is not unique',\n )\n }\n}\n\n// ── Replay executor (build step 7) ───────────────────────────────────────────────\n\n/**\n * Re-feed a journaled spawn tree in strict `seq` order, rehydrating each settled\n * child's `out` from the blob store by `outRef`, and return the `Settled[]` exactly\n * as `scope.next()` originally delivered them.\n *\n * Determinism (B2): the events are sorted by `seq` BEFORE any blob `get`, so the\n * replay order is the recorded cursor order regardless of how fast each rehydration\n * resolves. `at` (wall-clock) is never a replay input. Fail loud on a tree that was\n * never begun, a settled-done event missing its `outRef`, or a blob the store can't\n * rehydrate — a silent gap would let `act` branch on the wrong evidence.\n */\nexport async function replaySpawnTree(\n journal: SpawnJournal,\n blobs: ResultBlobStore,\n root: NodeId,\n): Promise<Settled<unknown>[]> {\n const events = await journal.loadTree(root)\n if (events === undefined) {\n throw new Error(`replaySpawnTree: no journaled tree for root '${root}'`)\n }\n const ordered = [...events].sort((a, b) => a.seq - b.seq)\n const labels = new Map<NodeId, string>()\n for (const ev of ordered) {\n if (ev.kind === 'spawned') labels.set(ev.id, ev.label)\n }\n const settled: Settled<unknown>[] = []\n for (const ev of ordered) {\n if (ev.kind === 'spawned') continue\n if (ev.kind === 'metered') continue // a spend record, not a settlement — irrelevant to replay\n if (ev.kind === 'cancelled') {\n settled.push({\n kind: 'down',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'cancelled'),\n reason: ev.reason,\n infra: false,\n restartCount: 0,\n seq: ev.seq,\n })\n continue\n }\n if (ev.status === 'down') {\n settled.push({\n kind: 'down',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'failed'),\n reason: ev.verdict?.notes ?? 'child down',\n infra: ev.infra === true,\n restartCount: 0,\n seq: ev.seq,\n })\n continue\n }\n if (ev.outRef === undefined) {\n throw new Error(\n `replaySpawnTree: settled-done event for '${ev.id}' (seq ${ev.seq}) has no outRef; ` +\n 'cannot rehydrate the result the driver branched on',\n )\n }\n const out = await blobs.get(ev.outRef)\n if (out === undefined) {\n throw new Error(\n `replaySpawnTree: blob store has no artifact for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`,\n )\n }\n settled.push({\n kind: 'done',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'done'),\n out,\n outRef: ev.outRef,\n verdict: ev.verdict,\n spent: ev.spent,\n seq: ev.seq,\n })\n }\n return settled\n}\n\nfunction replayHandle(id: NodeId, label: string, status: NodeStatus) {\n return {\n id,\n label,\n status,\n abort() {\n throw new Error(`cannot abort node '${id}': replayed handles are terminal, not live`)\n },\n }\n}\n\n/**\n * Materialize the live tree (`TreeView`) from a journaled event list for resume. Folds\n * `spawned`/`settled`/`cancelled` into a per-node snapshot in `seq` order, then adds each\n * `metered` event's driver-inference spend onto its node in a separate additive pass — so the\n * resumed view matches what `scope.view` showed at the recorded cursor position.\n */\nexport function materializeTreeView(events: SpawnEvent[]): TreeView {\n const nodes = new Map<NodeId, MutableSnapshot>()\n let root: NodeId | undefined\n // `spawned` (ordinal namespace) and `settled`/`cancelled` (cursor namespace) carry\n // overlapping `seq` values, so create every node before any update — process spawns in\n // ordinal order, then settlements/cancellations in cursor order. A settle/cancel for an\n // un-spawned node is a corrupted log (fail loud via requireNode).\n const spawns = events\n .filter((ev): ev is Extract<SpawnEvent, { kind: 'spawned' }> => ev.kind === 'spawned')\n .sort((a, b) => a.seq - b.seq)\n const settlements = events\n .filter((ev) => ev.kind !== 'spawned' && ev.kind !== 'metered')\n .sort((a, b) => a.seq - b.seq)\n for (const ev of spawns) {\n if (ev.parent === undefined && root === undefined) root = ev.id\n nodes.set(ev.id, {\n id: ev.id,\n parent: ev.parent,\n label: ev.label,\n status: 'pending',\n runtime: ev.runtime,\n budget: ev.budget,\n spent: zeroSpend(),\n })\n }\n for (const ev of settlements) {\n if (ev.kind === 'settled') {\n const node = requireNode(nodes, ev.id)\n node.status = ev.status === 'done' ? 'done' : 'failed'\n node.spent = ev.spent\n node.outRef = ev.outRef\n } else {\n const node = requireNode(nodes, ev.id)\n node.status = 'cancelled'\n }\n }\n // Driver inference: a separate pass so it accumulates ONTO the settled child-work base (no\n // dependence on metered-vs-settled seq order) without touching node status.\n for (const ev of events) {\n if (ev.kind !== 'metered') continue\n const node = requireNode(nodes, ev.id)\n node.spent = addJournalSpend(node.spent, ev.spend)\n }\n const snapshots = [...nodes.values()].map(freezeSnapshot)\n return {\n root: root ?? snapshots[0]?.id ?? '',\n nodes: snapshots,\n inFlight: snapshots.filter((n) => n.status === 'running' || n.status === 'acquiring').length,\n }\n}\n\ninterface MutableSnapshot {\n id: NodeId\n parent?: NodeId\n label: string\n status: NodeStatus\n runtime: Runtime\n budget: NodeSnapshot['budget']\n spent: Spend\n outRef?: string\n}\n\nfunction zeroSpend(): Spend {\n return { iterations: 0, tokens: zeroTokenUsage(), usd: 0, ms: 0 }\n}\n\n/** Add a `metered` spend record onto a node's accumulated spend (per channel). */\nfunction addJournalSpend(a: Spend, b: Spend): Spend {\n return {\n iterations: a.iterations + b.iterations,\n tokens: { input: a.tokens.input + b.tokens.input, output: a.tokens.output + b.tokens.output },\n usd: a.usd + b.usd,\n ms: a.ms + b.ms,\n }\n}\n\nfunction requireNode(nodes: Map<NodeId, MutableSnapshot>, id: NodeId): MutableSnapshot {\n const node = nodes.get(id)\n if (!node) {\n throw new Error(`spawn journal corrupted: settle/cancel for node '${id}' with no prior spawn`)\n }\n return node\n}\n\nfunction freezeSnapshot(node: MutableSnapshot): NodeSnapshot {\n return {\n id: node.id,\n parent: node.parent,\n label: node.label,\n status: node.status,\n runtime: node.runtime,\n budget: node.budget,\n spent: node.spent,\n outRef: node.outRef,\n }\n}\n\nfunction isNoEntError(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'code' in err &&\n (err as { code: unknown }).code === 'ENOENT'\n )\n}\n"],"mappings":";AAsBA,SAAS,kBAAkB;AA0BpB,SAAS,eAAe,UAA2B;AACxD,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,gBAAgB,QAAQ,GAAG,OAAO,EAAE,OAAO,KAAK;AACxF,SAAO,UAAU,GAAG;AACtB;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO,KAAK,UAAU,KAAK,KAAK;AACjF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,IAAI,eAAe,EAAE,KAAK,GAAG,CAAC;AACzE,QAAM,UAAU,OAAO,QAAQ,KAAgC,EAC5D,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,EACjC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE;AAClD,SAAO,IAAI,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAC5F;AASO,IAAM,0BAAN,MAAyD;AAAA,EAC7C,QAAQ,oBAAI,IAAqB;AAAA,EAElD,MAAM,IAAI,QAAgB,UAAkC;AAC1D,yBAAqB,QAAQ,QAAQ;AACrC,SAAK,MAAM,IAAI,QAAQ,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,IAAI,QAA8C;AACtD,WAAO,KAAK,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,MAAM,IAAI;AAAA,EAC3D;AACF;AAwCA,SAAS,qBAAqB,QAAgB,UAAyB;AACrE,QAAM,WAAW,eAAe,QAAQ;AACxC,MAAI,WAAW,UAAU;AACvB,UAAM,IAAI;AAAA,MACR,gBAAgB,MAAM,+CAA+C,QAAQ;AAAA,IAE/E;AAAA,EACF;AACF;AAWO,IAAM,uBAAN,MAAmD;AAAA,EACvC,QAAQ,oBAAI,IAAuD;AAAA,EAEpF,MAAM,SAAS,MAAiD;AAC9D,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,KAAK,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAU,MAAc,IAA2B;AACvD,UAAM,WAAW,KAAK,MAAM,IAAI,IAAI;AACpC,QAAI,UAAU;AACZ,UAAI,SAAS,YAAY,IAAI;AAC3B,cAAM,IAAI;AAAA,UACR,eAAe,IAAI,sBAAsB,SAAS,OAAO,gCAAgC,EAAE;AAAA,QAC7F;AAAA,MACF;AACA;AAAA,IACF;AACA,SAAK,MAAM,IAAI,MAAM,EAAE,SAAS,IAAI,QAAQ,CAAC,EAAE,CAAC;AAAA,EAClD;AAAA,EAEA,MAAM,YAAY,MAAc,IAA+B;AAC7D,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,8CAA8C,IAAI,yBAAyB;AAAA,IAC7F;AACA,oBAAgB,MAAM,KAAK,QAAQ,EAAE;AACrC,SAAK,OAAO,KAAK,EAAE,GAAG,GAAG,CAAC;AAAA,EAC5B;AACF;AA2GA,SAAS,gBAAgB,MAAc,QAAsB,IAAsB;AAGjF,MAAI,GAAG,SAAS,aAAa,GAAG,SAAS,UAAW;AACpD,MAAI,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,SAAS,aAAa,EAAE,QAAQ,GAAG,GAAG,GAAG;AACxF,UAAM,IAAI;AAAA,MACR,iDAAiD,GAAG,GAAG,aAAa,IAAI;AAAA,IAE1E;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/durable/spawn-journal.ts"],"sourcesContent":["/**\n *\n * Event-sourced spawn journal for the recursive execution atom (build steps 3 + 7).\n *\n * The supervision tree is journaled as an append-only event log: every `spawned`,\n * `settled`, and `cancelled` is recorded AFTER it is observed-committed (never\n * speculative), mirroring `ConversationJournal`'s begin/append/load shape. The log\n * holds only the THIN decision record — ids, parentage, budget, the spend a decision\n * consumed, and a content-addressed `outRef`. The payloads the driver branched on\n * (the `out` artifacts) live in a separate `ResultBlobStore`, keyed by `outRef`, so\n * the journal stays small (decisions) and replay rehydrates the exact `Settled` from\n * the blob store (evidence). This is the decision/payload split the replay argument\n * rests on (B1/B2).\n *\n * Replay determinism (B2): `seq` is the monotonic cursor order `scope.next()` yielded\n * each settlement — NOT wall-clock. `replaySpawnTree` sorts strictly by `seq` before\n * touching the blob store, so the order in which rehydration `get`s resolve can never\n * reorder the replayed `Settled[]`; the result is identical regardless of blob latency.\n *\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport type {\n NodeId,\n NodeSnapshot,\n NodeStatus,\n ResultBlobStore,\n Runtime,\n Settled,\n SpawnEvent,\n SpawnJournal,\n Spend,\n TreeView,\n} from '../runtime/supervise/types'\nimport { zeroTokenUsage } from '../runtime/util'\n\n// ── Content addressing ──────────────────────────────────────────────────────\n\n/**\n * Mint the content-addressed `outRef` for a result artifact: `sha256:<hex>` over a\n * stable JSON encoding. Producers call this to derive the `outRef` they journal and\n * `put`; the FS/in-mem stores re-derive it on `put` to verify the supplied ref\n * matches (fail loud on a mismatch — a forged ref breaks the replay invariant).\n *\n * Stable encoding: object keys are sorted recursively so two structurally-equal\n * artifacts hash identically regardless of key insertion order.\n */\nexport function contentAddress(artifact: unknown): string {\n const hex = createHash('sha256').update(stableStringify(artifact), 'utf-8').digest('hex')\n return `sha256:${hex}`\n}\n\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null'\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(',')}}`\n}\n\n// ── Result blob store ─────────────────────────────────────────────────────────\n\n/**\n * In-memory `ResultBlobStore`. Content-addressed: `put` verifies the supplied\n * `outRef` matches the artifact's hash so a stale/forged ref fails loud rather than\n * silently rehydrating the wrong payload. Idempotent on an identical re-put.\n */\nexport class InMemoryResultBlobStore implements ResultBlobStore {\n private readonly blobs = new Map<string, unknown>()\n\n async put(outRef: string, artifact: unknown): Promise<void> {\n assertContentAddress(outRef, artifact)\n this.blobs.set(outRef, artifact)\n }\n\n async get(outRef: string): Promise<unknown | undefined> {\n return this.blobs.has(outRef) ? this.blobs.get(outRef) : undefined\n }\n}\n\n/**\n * FS `ResultBlobStore`. One JSON file per artifact under `dir`, named by a\n * filesystem-safe encoding of the `outRef` (`sha256:<hex>` → `sha256-<hex>.json`).\n * `put` fsyncs so a crash between writes never loses an acknowledged blob.\n */\nexport class FileResultBlobStore implements ResultBlobStore {\n constructor(private readonly dir: string) {}\n\n async put(outRef: string, artifact: unknown): Promise<void> {\n assertContentAddress(outRef, artifact)\n const fs = await import('node:fs/promises')\n await fs.mkdir(this.dir, { recursive: true })\n const fh = await fs.open(this.blobPath(outRef), 'w')\n try {\n await fh.write(JSON.stringify(artifact))\n await fh.sync()\n } finally {\n await fh.close()\n }\n }\n\n async get(outRef: string): Promise<unknown | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.blobPath(outRef), 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n return JSON.parse(text)\n }\n\n private blobPath(outRef: string): string {\n return `${this.dir}/${outRef.replace(/:/g, '-')}.json`\n }\n}\n\nfunction assertContentAddress(outRef: string, artifact: unknown): void {\n const expected = contentAddress(artifact)\n if (outRef !== expected) {\n throw new Error(\n `blob outRef '${outRef}' does not match the artifact content hash '${expected}'; ` +\n 'a content-addressed store refuses a mismatched ref (breaks the replay invariant)',\n )\n }\n}\n\n// ── Spawn journal ──────────────────────────────────────────────────────────────\n\n/**\n * In-memory `SpawnJournal`. Appends are observed-committed only; the impl enforces\n * the corruption guards a durable replay rests on:\n * - an event before `beginTree` is a corrupted tree (fail loud),\n * - a duplicate `seq` within a tree is a corrupted cursor (fail loud) — two\n * settlements cannot share the cursor position replay orders by.\n */\nexport class InMemorySpawnJournal implements SpawnJournal {\n private readonly trees = new Map<NodeId, { begunAt: string; events: SpawnEvent[] }>()\n\n async loadTree(root: NodeId): Promise<SpawnEvent[] | undefined> {\n const tree = this.trees.get(root)\n if (!tree) return undefined\n return tree.events.map((ev) => ({ ...ev }))\n }\n\n async beginTree(root: NodeId, at: string): Promise<void> {\n const existing = this.trees.get(root)\n if (existing) {\n if (existing.begunAt !== at) {\n throw new Error(\n `spawn tree '${root}' already begun at ${existing.begunAt}; refusing to overwrite with ${at}`,\n )\n }\n return\n }\n this.trees.set(root, { begunAt: at, events: [] })\n }\n\n async appendEvent(root: NodeId, ev: SpawnEvent): Promise<void> {\n const tree = this.trees.get(root)\n if (!tree) {\n throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`)\n }\n assertSeqUnique(root, tree.events, ev)\n tree.events.push({ ...ev })\n }\n}\n\n/**\n * JSONL on disk. One line per record: the first record is `begin`, subsequent records\n * are `event` envelopes wrapping a `SpawnEvent`. `loadTree` replays the whole file,\n * filtering by `root`, and applies the same begin-precedes-events + unique-seq\n * corruption guards as the in-memory impl. Each append fsyncs so a crash between\n * writes never loses an acknowledged event.\n */\nexport class FileSpawnJournal implements SpawnJournal {\n constructor(private readonly path: string) {}\n\n async loadTree(root: NodeId): Promise<SpawnEvent[] | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.path, 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n const lines = text.split('\\n').filter((line) => line.length > 0)\n let begun = false\n const events: SpawnEvent[] = []\n for (const line of lines) {\n const record = JSON.parse(line) as SpawnJournalRecord\n if (record.root !== root) continue\n if (record.kind === 'begin') {\n begun = true\n } else {\n if (!begun) {\n throw new Error(\n `spawn journal corrupted: event for tree '${root}' precedes its begin record`,\n )\n }\n assertSeqUnique(root, events, record.event)\n events.push(record.event)\n }\n }\n return begun ? events : undefined\n }\n\n async beginTree(root: NodeId, at: string): Promise<void> {\n const existing = await this.loadTreeBegin(root)\n if (existing) {\n if (existing !== at) {\n throw new Error(\n `spawn tree '${root}' already begun in ${this.path} at ${existing}; refusing to overwrite with ${at}`,\n )\n }\n return\n }\n await this.appendRecord({ kind: 'begin', root, at })\n }\n\n async appendEvent(root: NodeId, ev: SpawnEvent): Promise<void> {\n const events = await this.loadTree(root)\n if (events === undefined) {\n throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`)\n }\n assertSeqUnique(root, events, ev)\n await this.appendRecord({ kind: 'event', root, event: ev })\n }\n\n private async loadTreeBegin(root: NodeId): Promise<string | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.path, 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n const lines = text.split('\\n').filter((line) => line.length > 0)\n for (const line of lines) {\n const record = JSON.parse(line) as SpawnJournalRecord\n if (record.root === root && record.kind === 'begin') return record.at\n }\n return undefined\n }\n\n private async appendRecord(record: SpawnJournalRecord): Promise<void> {\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n await fs.mkdir(path.dirname(this.path), { recursive: true })\n const fh = await fs.open(this.path, 'a')\n try {\n await fh.write(`${JSON.stringify(record)}\\n`)\n await fh.sync()\n } finally {\n await fh.close()\n }\n }\n}\n\ntype SpawnJournalRecord =\n | { kind: 'begin'; root: NodeId; at: string }\n | { kind: 'event'; root: NodeId; event: SpawnEvent }\n\n/**\n * Two `seq` namespaces share the journal: a `spawned` event's `seq` is the spawn ordinal\n * (the order children were created), and a `settled`/`cancelled` event's `seq` is the\n * monotonic CURSOR order `scope.next()` yielded that settlement (B2). The uniqueness\n * replay rests on is the cursor namespace — two settlements cannot share the position\n * replay orders by — so the guard checks only settled/cancelled events. A `spawned`\n * ordinal legitimately equals a later `settled` cursor seq and is not a collision.\n */\nfunction assertSeqUnique(root: NodeId, events: SpawnEvent[], ev: SpawnEvent): void {\n // `spawned` (ordinal namespace) and `metered` (informational spend, no settlement order) live\n // outside the cursor-uniqueness namespace replay relies on.\n if (ev.kind === 'spawned' || ev.kind === 'metered') return\n if (events.some((e) => e.kind !== 'spawned' && e.kind !== 'metered' && e.seq === ev.seq)) {\n throw new Error(\n `spawn journal corrupted: duplicate cursor seq ${ev.seq} in tree '${root}'; ` +\n 'the cursor order replay relies on is not unique',\n )\n }\n}\n\n// ── Replay executor (build step 7) ───────────────────────────────────────────────\n\n/**\n * Re-feed a journaled spawn tree in strict `seq` order, rehydrating each settled\n * child's `out` from the blob store by `outRef`, and return the `Settled[]` exactly\n * as `scope.next()` originally delivered them.\n *\n * Determinism (B2): the events are sorted by `seq` BEFORE any blob `get`, so the\n * replay order is the recorded cursor order regardless of how fast each rehydration\n * resolves. `at` (wall-clock) is never a replay input. Fail loud on a tree that was\n * never begun, a settled-done event missing its `outRef`, or a blob the store can't\n * rehydrate — a silent gap would let `act` branch on the wrong evidence.\n */\nexport async function replaySpawnTree(\n journal: SpawnJournal,\n blobs: ResultBlobStore,\n root: NodeId,\n): Promise<Settled<unknown>[]> {\n const events = await journal.loadTree(root)\n if (events === undefined) {\n throw new Error(`replaySpawnTree: no journaled tree for root '${root}'`)\n }\n const ordered = [...events].sort((a, b) => a.seq - b.seq)\n const labels = new Map<NodeId, string>()\n for (const ev of ordered) {\n if (ev.kind === 'spawned') labels.set(ev.id, ev.label)\n }\n const settled: Settled<unknown>[] = []\n for (const ev of ordered) {\n if (ev.kind === 'spawned') continue\n if (ev.kind === 'metered') continue // a spend record, not a settlement — irrelevant to replay\n if (ev.kind === 'cancelled') {\n settled.push({\n kind: 'down',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'cancelled'),\n reason: ev.reason,\n infra: false,\n restartCount: 0,\n seq: ev.seq,\n })\n continue\n }\n if (ev.status === 'down') {\n settled.push({\n kind: 'down',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'failed'),\n reason: ev.verdict?.notes ?? 'child down',\n infra: ev.infra === true,\n restartCount: 0,\n seq: ev.seq,\n })\n continue\n }\n if (ev.outRef === undefined) {\n throw new Error(\n `replaySpawnTree: settled-done event for '${ev.id}' (seq ${ev.seq}) has no outRef; ` +\n 'cannot rehydrate the result the driver branched on',\n )\n }\n const out = await blobs.get(ev.outRef)\n if (out === undefined) {\n throw new Error(\n `replaySpawnTree: blob store has no artifact for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`,\n )\n }\n settled.push({\n kind: 'done',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'done'),\n out,\n outRef: ev.outRef,\n verdict: ev.verdict,\n spent: ev.spent,\n seq: ev.seq,\n })\n }\n return settled\n}\n\nfunction replayHandle(id: NodeId, label: string, status: NodeStatus) {\n return {\n id,\n label,\n status,\n abort() {\n throw new Error(`cannot abort node '${id}': replayed handles are terminal, not live`)\n },\n }\n}\n\n/**\n * Materialize the live tree (`TreeView`) from a journaled event list for resume. Folds\n * `spawned`/`settled`/`cancelled` into a per-node snapshot in `seq` order, then adds each\n * `metered` event's driver-inference spend onto its node in a separate additive pass — so the\n * resumed view matches what `scope.view` showed at the recorded cursor position.\n */\nexport function materializeTreeView(events: SpawnEvent[]): TreeView {\n const nodes = new Map<NodeId, MutableSnapshot>()\n let root: NodeId | undefined\n // `spawned` (ordinal namespace) and `settled`/`cancelled` (cursor namespace) carry\n // overlapping `seq` values, so create every node before any update — process spawns in\n // ordinal order, then settlements/cancellations in cursor order. A settle/cancel for an\n // un-spawned node is a corrupted log (fail loud via requireNode).\n const spawns = events\n .filter((ev): ev is Extract<SpawnEvent, { kind: 'spawned' }> => ev.kind === 'spawned')\n .sort((a, b) => a.seq - b.seq)\n const settlements = events\n .filter((ev) => ev.kind !== 'spawned' && ev.kind !== 'metered')\n .sort((a, b) => a.seq - b.seq)\n for (const ev of spawns) {\n if (ev.parent === undefined && root === undefined) root = ev.id\n nodes.set(ev.id, {\n id: ev.id,\n parent: ev.parent,\n label: ev.label,\n status: 'pending',\n runtime: ev.runtime,\n budget: ev.budget,\n spent: zeroSpend(),\n })\n }\n for (const ev of settlements) {\n if (ev.kind === 'settled') {\n const node = requireNode(nodes, ev.id)\n node.status = ev.status === 'done' ? 'done' : 'failed'\n node.spent = ev.spent\n node.outRef = ev.outRef\n } else {\n const node = requireNode(nodes, ev.id)\n node.status = 'cancelled'\n }\n }\n // Driver inference: a separate pass so it accumulates ONTO the settled child-work base (no\n // dependence on metered-vs-settled seq order) without touching node status.\n for (const ev of events) {\n if (ev.kind !== 'metered') continue\n const node = requireNode(nodes, ev.id)\n node.spent = addJournalSpend(node.spent, ev.spend)\n }\n const snapshots = [...nodes.values()].map(freezeSnapshot)\n return {\n root: root ?? snapshots[0]?.id ?? '',\n nodes: snapshots,\n inFlight: snapshots.filter((n) => n.status === 'running' || n.status === 'acquiring').length,\n }\n}\n\ninterface MutableSnapshot {\n id: NodeId\n parent?: NodeId\n label: string\n status: NodeStatus\n runtime: Runtime\n budget: NodeSnapshot['budget']\n spent: Spend\n outRef?: string\n}\n\nfunction zeroSpend(): Spend {\n return { iterations: 0, tokens: zeroTokenUsage(), usd: 0, ms: 0 }\n}\n\n/** Add a `metered` spend record onto a node's accumulated spend (per channel). */\nfunction addJournalSpend(a: Spend, b: Spend): Spend {\n return {\n iterations: a.iterations + b.iterations,\n tokens: { input: a.tokens.input + b.tokens.input, output: a.tokens.output + b.tokens.output },\n usd: a.usd + b.usd,\n ...(a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {}),\n ms: a.ms + b.ms,\n }\n}\n\nfunction requireNode(nodes: Map<NodeId, MutableSnapshot>, id: NodeId): MutableSnapshot {\n const node = nodes.get(id)\n if (!node) {\n throw new Error(`spawn journal corrupted: settle/cancel for node '${id}' with no prior spawn`)\n }\n return node\n}\n\nfunction freezeSnapshot(node: MutableSnapshot): NodeSnapshot {\n return {\n id: node.id,\n parent: node.parent,\n label: node.label,\n status: node.status,\n runtime: node.runtime,\n budget: node.budget,\n spent: node.spent,\n outRef: node.outRef,\n }\n}\n\nfunction isNoEntError(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'code' in err &&\n (err as { code: unknown }).code === 'ENOENT'\n )\n}\n"],"mappings":";AAsBA,SAAS,kBAAkB;AA0BpB,SAAS,eAAe,UAA2B;AACxD,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,gBAAgB,QAAQ,GAAG,OAAO,EAAE,OAAO,KAAK;AACxF,SAAO,UAAU,GAAG;AACtB;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO,KAAK,UAAU,KAAK,KAAK;AACjF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,IAAI,eAAe,EAAE,KAAK,GAAG,CAAC;AACzE,QAAM,UAAU,OAAO,QAAQ,KAAgC,EAC5D,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,EACjC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE;AAClD,SAAO,IAAI,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAC5F;AASO,IAAM,0BAAN,MAAyD;AAAA,EAC7C,QAAQ,oBAAI,IAAqB;AAAA,EAElD,MAAM,IAAI,QAAgB,UAAkC;AAC1D,yBAAqB,QAAQ,QAAQ;AACrC,SAAK,MAAM,IAAI,QAAQ,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,IAAI,QAA8C;AACtD,WAAO,KAAK,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,MAAM,IAAI;AAAA,EAC3D;AACF;AAwCA,SAAS,qBAAqB,QAAgB,UAAyB;AACrE,QAAM,WAAW,eAAe,QAAQ;AACxC,MAAI,WAAW,UAAU;AACvB,UAAM,IAAI;AAAA,MACR,gBAAgB,MAAM,+CAA+C,QAAQ;AAAA,IAE/E;AAAA,EACF;AACF;AAWO,IAAM,uBAAN,MAAmD;AAAA,EACvC,QAAQ,oBAAI,IAAuD;AAAA,EAEpF,MAAM,SAAS,MAAiD;AAC9D,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,KAAK,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAU,MAAc,IAA2B;AACvD,UAAM,WAAW,KAAK,MAAM,IAAI,IAAI;AACpC,QAAI,UAAU;AACZ,UAAI,SAAS,YAAY,IAAI;AAC3B,cAAM,IAAI;AAAA,UACR,eAAe,IAAI,sBAAsB,SAAS,OAAO,gCAAgC,EAAE;AAAA,QAC7F;AAAA,MACF;AACA;AAAA,IACF;AACA,SAAK,MAAM,IAAI,MAAM,EAAE,SAAS,IAAI,QAAQ,CAAC,EAAE,CAAC;AAAA,EAClD;AAAA,EAEA,MAAM,YAAY,MAAc,IAA+B;AAC7D,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,8CAA8C,IAAI,yBAAyB;AAAA,IAC7F;AACA,oBAAgB,MAAM,KAAK,QAAQ,EAAE;AACrC,SAAK,OAAO,KAAK,EAAE,GAAG,GAAG,CAAC;AAAA,EAC5B;AACF;AA2GA,SAAS,gBAAgB,MAAc,QAAsB,IAAsB;AAGjF,MAAI,GAAG,SAAS,aAAa,GAAG,SAAS,UAAW;AACpD,MAAI,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,SAAS,aAAa,EAAE,QAAQ,GAAG,GAAG,GAAG;AACxF,UAAM,IAAI;AAAA,MACR,iDAAiD,GAAG,GAAG,aAAa,IAAI;AAAA,IAE1E;AAAA,EACF;AACF;","names":[]}
@@ -1,5 +1,5 @@
1
- import { L as LocalHarness } from './local-harness-dcD5WTTr.js';
2
- import { c as Executor } from './types-Cg_teUPO.js';
1
+ import { L as LocalHarness, C as CodexTokenUsage, a as CodexExecutionPolicy } from './local-harness-B7bNuNJw.js';
2
+ import { c as Executor } from './types-Bb-CqxJH.js';
3
3
 
4
4
  /**
5
5
  *
@@ -136,6 +136,18 @@ interface WorktreeHarnessResult {
136
136
  durationMs: number;
137
137
  stdout: string;
138
138
  stderr: string;
139
+ /** Exact Codex JSONL usage when reproducible mode is enabled. */
140
+ usage?: CodexTokenUsage;
141
+ /** Installed CLI version captured immediately before execution. */
142
+ cliVersion?: string;
143
+ /** SHA-256 of `codex debug prompt-input` output for the exact isolated prompt. */
144
+ effectivePromptSha256?: string;
145
+ /** SHA-256 of the exact executable + argv with prompt content replaced by `<PROMPT>`. */
146
+ nonPromptArgsSha256?: string;
147
+ /** SHA-256 of the isolated config that fixes permissions and shell environment. */
148
+ controlledConfigSha256?: string;
149
+ /** Explicit isolation claims checked before model execution. */
150
+ executionPolicy?: CodexExecutionPolicy;
139
151
  };
140
152
  /** Verification signals derived in the live worktree (present only when commands were given). */
141
153
  checks?: {
@@ -1,12 +1,12 @@
1
- import { E as ExecutorFactory, e as ExecutorRegistry, i as Spend, A as Agent, S as Scope, a as ResultBlobStore, B as Budget } from './types-Cg_teUPO.js';
1
+ import { E as ExecutorFactory, e as ExecutorRegistry, i as Spend, A as Agent, S as Scope, a as ResultBlobStore, B as Budget } from './types-Bb-CqxJH.js';
2
2
  import { AgentProfile } from '@tangle-network/agent-interface';
3
3
  import { U as UiLens, a as UiFinding, C as CoderTask } from './substrate-DO2GHNg2.js';
4
4
  import { S as SandboxClient, E as ExecCtx, g as LoopTraceEmitter, f as LoopTraceEvent, a as RuntimeStreamEvent, d as AgentRunSpec } from './types-DWA64rbJ.js';
5
5
  import { BackendType, SandboxEvent, SandboxInstance } from '@tangle-network/sandbox';
6
6
  import { AgentEvalError } from '@tangle-network/agent-eval';
7
7
  import { b as ToolSpec, c as RuntimeTelemetryOptions, R as RouterConfig } from './sanitize-C2jicjNf.js';
8
- import { G as GitRunner, a as WorktreeCheckRunner, D as DeliverableSpec } from './completion-gate-BDkEYB_-.js';
9
- import { L as LocalHarness } from './local-harness-dcD5WTTr.js';
8
+ import { G as GitRunner, a as WorktreeCheckRunner, D as DeliverableSpec } from './completion-gate-BAj3dXeW.js';
9
+ import { L as LocalHarness } from './local-harness-B7bNuNJw.js';
10
10
  import { ProviderExecutorOptions, AgentEnvironmentProviderRegistry } from './environment-provider.js';
11
11
  import { AgentEnvironmentProvider } from '@tangle-network/agent-interface/environment-provider';
12
12
 
@@ -87,6 +87,8 @@ interface CliWorktreeSeam {
87
87
  runId?: string;
88
88
  baseRef?: string;
89
89
  harnessTimeoutMs?: number;
90
+ /** Isolated, network-off Codex execution with terminal JSONL usage capture. */
91
+ codexReproducible?: boolean;
90
92
  testCmd?: string;
91
93
  typecheckCmd?: string;
92
94
  checkTimeoutMs?: number;
@@ -2,7 +2,7 @@ import { AgentProfile, AgentProfileValidationResult } from '@tangle-network/agen
2
2
  import { CreateAgentEnvironmentInput, AgentTurnInput, AgentEnvironmentProvider, AgentEnvironmentCapabilities, AgentProfileRef } from '@tangle-network/agent-interface/environment-provider';
3
3
  export { AgentEnvironment, AgentEnvironmentCapabilities, AgentEnvironmentEvent, AgentEnvironmentProvider, AgentEnvironmentQuery, AgentEnvironmentStatus, AgentEnvironmentSummary, AgentProfileRef, AgentSession, AgentSessionRef, AgentSessionStatus, AgentTurnInput, AgentTurnResult, CheckpointRef, CheckpointRequest, CreateAgentEnvironmentInput, ExecRequest, ExecResult, ForkRequest, PlacementInfo, ResourceRequest, WorkspaceRequest } from '@tangle-network/agent-interface/environment-provider';
4
4
  import { CreateSandboxOptions, BackendType } from '@tangle-network/sandbox';
5
- import { R as Runtime, E as ExecutorFactory } from './types-Cg_teUPO.js';
5
+ import { R as Runtime, E as ExecutorFactory } from './types-Bb-CqxJH.js';
6
6
  import { S as SandboxClient } from './types-DWA64rbJ.js';
7
7
  import '@tangle-network/agent-eval';
8
8
 
@@ -1,7 +1,7 @@
1
1
  import { Scenario, SelfImproveOptions, SurfaceProposer, SelfImproveResult, MutableSurface } from '@tangle-network/agent-eval/contract';
2
2
  import { AgentProfile } from '@tangle-network/agent-interface';
3
- import { L as LocalHarness } from './local-harness-dcD5WTTr.js';
4
- import { V as Verifier, C as CandidateGenerator } from './agentic-generator-B8oeE2Yv.js';
3
+ import { L as LocalHarness } from './local-harness-B7bNuNJw.js';
4
+ import { V as Verifier, C as CandidateGenerator } from './agentic-generator-D9ZmAuiL.js';
5
5
 
6
6
  /**
7
7
  *
package/dist/index.d.ts CHANGED
@@ -5,29 +5,29 @@ export { r as AgentAdapter, s as AgentKnowledgeProvider, A as AgentRuntimeEvent,
5
5
  export { AgentCandidateCodeSource, AgentCandidateCodeSurfaceSource, AgentCandidateModelGrantActivateInput, AgentCandidateModelGrantClient, AgentCandidateModelGrantReservation, AgentCandidateModelGrantReserveInput, AgentCandidateModelGrantSettleInput, AgentCandidateProfileSource, BuildAgentCandidateBundleInput, CreateProtectedAgentCandidateModelPortOptions, DisposePreparedAgentCandidateOptions, FileAgentCandidateExecutionClaimStore, FileAgentCandidateExecutionClaimStoreOptions, RecoverExpiredAgentCandidateOptions, applyExactAgentProfileDiff, buildAgentCandidateBundle, candidateExecutionClaim, createProtectedAgentCandidateModelPort, disposePreparedAgentCandidateExecution, parseExactAgentProfile, parseExactAgentProfileDiff, persistCandidateOutputArtifact, recoverExpiredAgentCandidateExecution, verifyAgentCandidateBundle } from './candidate-execution/index.js';
6
6
  export { d as AgentCandidateArtifactPort, e as AgentCandidateBenchmarkGraderIdentity, f as AgentCandidateBenchmarkGraderPort, A as AgentCandidateBundleInput, g as AgentCandidateContainerPort, h as AgentCandidateExecutionAttemptRecord, i as AgentCandidateExecutionAttemptRef, j as AgentCandidateExecutionClaim, k as AgentCandidateExecutionClaimResult, l as AgentCandidateExecutionClaimStore, m as AgentCandidateExecutionCleanupHandles, n as AgentCandidateExecutionFailureClass, o as AgentCandidateExecutionFinishResult, p as AgentCandidateExecutionLease, q as AgentCandidateExecutionPhase, r as AgentCandidateExecutionPhaseResult, b as AgentCandidateExecutionPorts, s as AgentCandidateExecutionRecoveryEvidence, t as AgentCandidateExecutionStageResult, u as AgentCandidateExecutionTerminalRecord, v as AgentCandidateExecutionTerminalResult, w as AgentCandidateExecutionUsage, x as AgentCandidateExecutorFinalCapture, y as AgentCandidateExecutorMemoryCapture, z as AgentCandidateExecutorPort, B as AgentCandidateExecutorProfileFile, C as AgentCandidateExecutorRequest, D as AgentCandidateExecutorStopRequest, F as AgentCandidateExecutorTaskOutcomeCapture, G as AgentCandidateExecutorWorkspaceFile, H as AgentCandidateExecutorWorkspaceInput, I as AgentCandidateMemoryPort, J as AgentCandidateMemoryResetResult, K as AgentCandidateModelLimits, L as AgentCandidateModelPort, M as AgentCandidateOutputArtifactPort, N as AgentCandidateOutputPurpose, O as AgentCandidateProtectedModelActivation, Q as AgentCandidateProtectedModelCall, R as AgentCandidateProtectedModelReservation, S as AgentCandidateProtectedModelSettlement, T as AgentCandidateProtectedRunCapture, U as AgentCandidateRepositoryPort, V as AgentCandidateRetryRejection, c as AgentCandidateRunFinalization, a as AgentCandidateTaskExecution, W as AgentCandidateVerificationPorts, X as AgentCandidateWorkspacePort, Y as CANDIDATE_TRACE_ENV, Z as CANDIDATE_TRACE_TAGS, _ as CanonicalCandidateDocument, E as ExecutePreparedAgentCandidateOptions, $ as InMemoryAgentCandidateExecutionClaimStore, P as PrepareAgentCandidateExecutionOptions, a0 as PreparedAgentCandidateExecution, a1 as PreparedAgentCandidateInstruction, a2 as PreparedAgentCandidateLaunch, a3 as PreparedAgentCandidateTrace, a4 as ResolvedAgentCandidateContainer, a5 as VerifiedAgentCandidate, a6 as VerifiedAgentCandidateTaskOutcome, a7 as executePreparedAgentCandidate, a8 as prepareAgentCandidateExecution, a9 as sealAgentCandidateBundle } from './prepare-BKxAiUcH.js';
7
7
  import { Scenario, ProfileDispatchFn, ProposeContext, SurfaceProposer } from '@tangle-network/agent-eval/campaign';
8
- import { C as CandidateGenerator } from './agentic-generator-B8oeE2Yv.js';
9
- export { A as AgenticGeneratorOptions, I as ImprovementDriverOptions, M as ManagedImprovementDriver, V as Verifier, a as VerifyResult, b as agenticGenerator, c as commandVerifier, i as improvementDriver } from './agentic-generator-B8oeE2Yv.js';
10
- export { c as ImproveCodeOptions, d as ImproveMemoryOptions, a as ImproveOptions, b as ImproveResult, e as ImproveSkillsOptions, I as ImproveSurface, f as applyImprovementWinnerToProfile, i as improve } from './improve-ZzTEkpF_.js';
11
- export { M as McpServeSpec, m as mcpServeVerifier } from './mcp-serve-verifier-Bg4C3p5S.js';
8
+ import { C as CandidateGenerator } from './agentic-generator-D9ZmAuiL.js';
9
+ export { A as AgenticGeneratorOptions, I as ImprovementDriverOptions, M as ManagedImprovementDriver, V as Verifier, a as VerifyResult, b as agenticGenerator, c as commandVerifier, i as improvementDriver } from './agentic-generator-D9ZmAuiL.js';
10
+ export { c as ImproveCodeOptions, d as ImproveMemoryOptions, a as ImproveOptions, b as ImproveResult, e as ImproveSkillsOptions, I as ImproveSurface, f as applyImprovementWinnerToProfile, i as improve } from './improve-r8SvIxYv.js';
11
+ export { M as McpServeSpec, m as mcpServeVerifier } from './mcp-serve-verifier-BuXjaZDE.js';
12
12
  import { AgentProfileDiff, AgentProfile as AgentProfile$1 } from '@tangle-network/agent-interface';
13
13
  import { Scenario as Scenario$1, SelfImproveOptions } from '@tangle-network/agent-eval/contract';
14
14
  import { S as SurfaceImprovementEdit } from './improvement-adapter-BieWeK5J.js';
15
15
  import { I as ImprovementAdapter } from './types-BC3bZpH0.js';
16
16
  export { AgentKnowledgeReadinessCheckOptions, KnowledgeImprovementJobMeasurement, KnowledgeImprovementJobResult, KnowledgeReadinessCheck, KnowledgeReadinessCheckInput, KnowledgeReadinessCheckResult, RESEARCH_SUPERVISOR_SYSTEM_PROMPT, RunKnowledgeImprovementJobOptions, SupervisedKnowledgeUpdateInput, SupervisedKnowledgeUpdateOptions, SupervisedKnowledgeUpdateResult, SupervisedKnowledgeUpdater, createAgentKnowledgeReadinessCheck, createSupervisedKnowledgeUpdater, formatSupervisedKnowledgeTask, knowledgeReadinessDeliverable, runKnowledgeImprovementJob, runSupervisedKnowledgeUpdate } from './knowledge.js';
17
- export { D as DELEGATED_LOOP_MODES, a as DelegatedLoopMode, b as DelegatedLoopRegistry, c as DelegatedLoopResult, d as DelegatedLoopRunner, L as LoopRunnerCliArgs, e as LoopRunnerCliResult, R as ResearchLoopResult, f as ResearchLoopRunnerOptions, g as RunDelegatedLoopOptions, V as VetoedFact, W as WorktreeLoopRunnerOptions, h as auditLoopRunner, i as isDelegatedLoopMode, p as parseLoopRunnerArgv, r as researchLoopRunner, j as runDelegatedLoop, k as runLoopRunnerCli, s as selfImproveLoopRunner, w as worktreeLoopRunner } from './loop-runner-bin-BRXC1RwC.js';
17
+ export { D as DELEGATED_LOOP_MODES, a as DelegatedLoopMode, b as DelegatedLoopRegistry, c as DelegatedLoopResult, d as DelegatedLoopRunner, L as LoopRunnerCliArgs, e as LoopRunnerCliResult, R as ResearchLoopResult, f as ResearchLoopRunnerOptions, g as RunDelegatedLoopOptions, V as VetoedFact, W as WorktreeLoopRunnerOptions, h as auditLoopRunner, i as isDelegatedLoopMode, p as parseLoopRunnerArgv, r as researchLoopRunner, j as runDelegatedLoop, k as runLoopRunnerCli, s as selfImproveLoopRunner, w as worktreeLoopRunner } from './loop-runner-bin-D4bMIxmB.js';
18
18
  export { m as mcpToolsForRuntimeMcp, a as mcpToolsForRuntimeMcpSubset } from './openai-tools-D0ZSRCC6.js';
19
- export { b0 as EvalRunEvent, b1 as EvalRunGeneration, b2 as EvalRunsExportConfig, b3 as EvalRunsExportResult, b4 as INTELLIGENCE_WIRE_VERSION, b5 as LoopSpanNode, b6 as OtelAttribute, b7 as OtelExportConfig, b8 as OtelExporter, b9 as OtelSpan, ba as RuntimeEventOtelOptions, bb as buildLoopOtelSpans, bc as buildLoopSpanNodes, bd as buildRuntimeEventOtelSpans, be as createOtelExporter, bf as exportEvalRuns, bg as loopEventToOtelSpan } from './coordination-EGoRbbsd.js';
19
+ export { b0 as EvalRunEvent, b1 as EvalRunGeneration, b2 as EvalRunsExportConfig, b3 as EvalRunsExportResult, b4 as INTELLIGENCE_WIRE_VERSION, b5 as LoopSpanNode, b6 as OtelAttribute, b7 as OtelExportConfig, b8 as OtelExporter, b9 as OtelSpan, ba as RuntimeEventOtelOptions, bb as buildLoopOtelSpans, bc as buildLoopSpanNodes, bd as buildRuntimeEventOtelSpans, be as createOtelExporter, bf as exportEvalRuns, bg as loopEventToOtelSpan } from './coordination-B3ZuApR_.js';
20
20
  import { c as RuntimeTelemetryOptions } from './sanitize-C2jicjNf.js';
21
21
  export { d as RuntimeEventCollector, e as RuntimeStreamEventCollector, S as SanitizedKnowledgeReadinessReport, f as createRuntimeEventCollector, g as createRuntimeStreamEventCollector, s as sanitizeAgentRuntimeEvent, h as sanitizeKnowledgeReadinessReport, i as sanitizeRuntimeStreamEvent } from './sanitize-C2jicjNf.js';
22
22
  import '@tangle-network/sandbox';
23
- import './local-harness-dcD5WTTr.js';
23
+ import './local-harness-B7bNuNJw.js';
24
24
  import 'node:child_process';
25
25
  import '@tangle-network/agent-knowledge';
26
- import './supervise-Gmf709kn.js';
27
- import './types-Cg_teUPO.js';
28
- import './completion-gate-BDkEYB_-.js';
26
+ import './supervise-DTNcLDl2.js';
27
+ import './types-Bb-CqxJH.js';
28
+ import './completion-gate-BAj3dXeW.js';
29
29
  import './kb-gate-CwHO0vz6.js';
30
- import './worktree-fanout-BrB4att3.js';
30
+ import './worktree-fanout-IMKqdV_E.js';
31
31
  import './substrate-DO2GHNg2.js';
32
32
  import './environment-provider.js';
33
33
  import '@tangle-network/agent-interface/environment-provider';
package/dist/index.js CHANGED
@@ -4,11 +4,11 @@ import {
4
4
  createProtectedAgentCandidateModelPort,
5
5
  disposePreparedAgentCandidateExecution,
6
6
  recoverExpiredAgentCandidateExecution
7
- } from "./chunk-4E2GM63H.js";
7
+ } from "./chunk-MZH4HORF.js";
8
8
  import {
9
9
  mcpToolsForRuntimeMcp,
10
10
  mcpToolsForRuntimeMcpSubset
11
- } from "./chunk-55P6V5JT.js";
11
+ } from "./chunk-K7OPNHU4.js";
12
12
  import {
13
13
  DEFAULT_ROUTER_BASE_URL,
14
14
  cleanModelId,
@@ -27,14 +27,14 @@ import {
27
27
  runLoopRunnerCli,
28
28
  selfImproveLoopRunner,
29
29
  worktreeLoopRunner
30
- } from "./chunk-MRYPFDHJ.js";
30
+ } from "./chunk-RTSZNYXM.js";
31
31
  import "./chunk-SGKPNBXE.js";
32
32
  import {
33
33
  applyImprovementWinnerToProfile,
34
34
  improve,
35
35
  improvementDriver,
36
36
  rawTraceDistiller
37
- } from "./chunk-H2D3DCEB.js";
37
+ } from "./chunk-SJHFJOCY.js";
38
38
  import {
39
39
  CANDIDATE_TRACE_ENV,
40
40
  CANDIDATE_TRACE_TAGS,
@@ -49,7 +49,7 @@ import {
49
49
  prepareAgentCandidateExecution,
50
50
  sealAgentCandidateBundle,
51
51
  verifyAgentCandidateBundle
52
- } from "./chunk-7I2AOKCI.js";
52
+ } from "./chunk-KHLE3C5G.js";
53
53
  import {
54
54
  InMemoryRuntimeSessionStore,
55
55
  createIterableBackend,
@@ -59,7 +59,7 @@ import {
59
59
  normalizeBackendStreamEvent,
60
60
  nowIso,
61
61
  touchSession
62
- } from "./chunk-OO4EK3JB.js";
62
+ } from "./chunk-D336OZHK.js";
63
63
  import "./chunk-ZQZX77MM.js";
64
64
  import {
65
65
  mcpBuildPrompt,
@@ -69,7 +69,7 @@ import {
69
69
  import {
70
70
  agenticGenerator,
71
71
  commandVerifier
72
- } from "./chunk-RTVVH2KL.js";
72
+ } from "./chunk-JEP2WM24.js";
73
73
  import {
74
74
  RESEARCH_SUPERVISOR_SYSTEM_PROMPT,
75
75
  createAgentKnowledgeReadinessCheck,
@@ -78,14 +78,14 @@ import {
78
78
  knowledgeReadinessDeliverable,
79
79
  runKnowledgeImprovementJob,
80
80
  runSupervisedKnowledgeUpdate
81
- } from "./chunk-4GBT4WQ6.js";
81
+ } from "./chunk-HPCJBBLS.js";
82
82
  import "./chunk-5QOB7H74.js";
83
83
  import {
84
84
  composeRuntimeHooks,
85
85
  defineRuntimeHooks,
86
86
  notifyRuntimeDecisionPoint,
87
87
  notifyRuntimeHookEvent
88
- } from "./chunk-FHZHADIM.js";
88
+ } from "./chunk-URMJTSXB.js";
89
89
  import "./chunk-DPEUKJRO.js";
90
90
  import {
91
91
  INTELLIGENCE_WIRE_VERSION,
@@ -101,11 +101,11 @@ import {
101
101
  sanitizeKnowledgeReadinessReport,
102
102
  sanitizeRuntimeStreamEvent
103
103
  } from "./chunk-ISTDY47H.js";
104
- import "./chunk-3D2RHC4K.js";
104
+ import "./chunk-WIPGQ4GT.js";
105
105
  import "./chunk-VSWBYWFK.js";
106
106
  import "./chunk-3MDZX7YU.js";
107
107
  import "./chunk-FVJ7M3DA.js";
108
- import "./chunk-PX6SXX3M.js";
108
+ import "./chunk-PJNGPWTA.js";
109
109
  import {
110
110
  AgentEvalError,
111
111
  BackendTransportError,
@@ -5,12 +5,12 @@ import { AnalystFinding } from '@tangle-network/agent-eval/analyst';
5
5
  import { Scenario, SelfImproveResult } from '@tangle-network/agent-eval/contract';
6
6
  import { R as RunAnalystLoopOpts, a as RunAnalystLoopResult } from './types-BC3bZpH0.js';
7
7
  import { A as AgentCandidateBundleInput, a as AgentCandidateTaskExecution, b as AgentCandidateExecutionPorts, P as PrepareAgentCandidateExecutionOptions, E as ExecutePreparedAgentCandidateOptions, c as AgentCandidateRunFinalization } from './prepare-BKxAiUcH.js';
8
- import { I as ImproveSurface, a as ImproveOptions, b as ImproveResult } from './improve-ZzTEkpF_.js';
8
+ import { I as ImproveSurface, a as ImproveOptions, b as ImproveResult } from './improve-r8SvIxYv.js';
9
9
  import '@tangle-network/agent-eval';
10
10
  import '@tangle-network/sandbox';
11
- import './local-harness-dcD5WTTr.js';
11
+ import './local-harness-B7bNuNJw.js';
12
12
  import 'node:child_process';
13
- import './agentic-generator-B8oeE2Yv.js';
13
+ import './agentic-generator-D9ZmAuiL.js';
14
14
  import '@tangle-network/agent-eval/campaign';
15
15
 
16
16
  /**
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  applyImprovementWinnerToProfile,
3
3
  improve
4
- } from "./chunk-H2D3DCEB.js";
4
+ } from "./chunk-SJHFJOCY.js";
5
5
  import {
6
6
  assertCandidateProfileBinding,
7
7
  canonicalCandidateDigest,
@@ -13,21 +13,21 @@ import {
13
13
  prepareAgentCandidateExecution,
14
14
  sealAgentCandidateBundle,
15
15
  verifyAgentCandidateBundle
16
- } from "./chunk-7I2AOKCI.js";
16
+ } from "./chunk-KHLE3C5G.js";
17
17
  import {
18
18
  runAnalystLoop
19
19
  } from "./chunk-ZQZX77MM.js";
20
- import "./chunk-RTVVH2KL.js";
20
+ import "./chunk-JEP2WM24.js";
21
21
  import {
22
22
  buildLoopOtelSpans,
23
23
  buildRuntimeEventOtelSpans,
24
24
  createOtelExporter,
25
25
  flatOtelSpan
26
26
  } from "./chunk-ISTDY47H.js";
27
- import "./chunk-3D2RHC4K.js";
27
+ import "./chunk-WIPGQ4GT.js";
28
28
  import "./chunk-3MDZX7YU.js";
29
29
  import "./chunk-FVJ7M3DA.js";
30
- import "./chunk-PX6SXX3M.js";
30
+ import "./chunk-PJNGPWTA.js";
31
31
  import "./chunk-YEJR7IXO.js";
32
32
  import "./chunk-DGUM43GV.js";
33
33
 
@@ -1,15 +1,15 @@
1
1
  import { KnowledgeReadinessSpec, BuildEvalKnowledgeBundleOptions, KnowledgeBaseQualityOptions, KnowledgeImprovementResult, KnowledgeImprovementOptions } from '@tangle-network/agent-knowledge';
2
- import { E as ExecutorConfig } from './coordination-EGoRbbsd.js';
3
- import { a as SuperviseOptions, S as SupervisorProfile } from './supervise-Gmf709kn.js';
4
- import { B as Budget, b as SupervisedResult } from './types-Cg_teUPO.js';
5
- import { D as DeliverableSpec } from './completion-gate-BDkEYB_-.js';
2
+ import { E as ExecutorConfig } from './coordination-B3ZuApR_.js';
3
+ import { a as SuperviseOptions, S as SupervisorProfile } from './supervise-DTNcLDl2.js';
4
+ import { B as Budget, b as SupervisedResult } from './types-Bb-CqxJH.js';
5
+ import { D as DeliverableSpec } from './completion-gate-BAj3dXeW.js';
6
6
  import '@tangle-network/agent-interface';
7
7
  import './substrate-DO2GHNg2.js';
8
8
  import './types-DWA64rbJ.js';
9
9
  import '@tangle-network/agent-eval';
10
10
  import '@tangle-network/sandbox';
11
11
  import './sanitize-C2jicjNf.js';
12
- import './local-harness-dcD5WTTr.js';
12
+ import './local-harness-B7bNuNJw.js';
13
13
  import 'node:child_process';
14
14
  import './environment-provider.js';
15
15
  import '@tangle-network/agent-interface/environment-provider';
package/dist/knowledge.js CHANGED
@@ -6,16 +6,16 @@ import {
6
6
  knowledgeReadinessDeliverable,
7
7
  runKnowledgeImprovementJob,
8
8
  runSupervisedKnowledgeUpdate
9
- } from "./chunk-4GBT4WQ6.js";
9
+ } from "./chunk-HPCJBBLS.js";
10
10
  import "./chunk-5QOB7H74.js";
11
- import "./chunk-FHZHADIM.js";
11
+ import "./chunk-URMJTSXB.js";
12
12
  import "./chunk-DPEUKJRO.js";
13
13
  import "./chunk-ISTDY47H.js";
14
- import "./chunk-3D2RHC4K.js";
14
+ import "./chunk-WIPGQ4GT.js";
15
15
  import "./chunk-VSWBYWFK.js";
16
16
  import "./chunk-3MDZX7YU.js";
17
17
  import "./chunk-FVJ7M3DA.js";
18
- import "./chunk-PX6SXX3M.js";
18
+ import "./chunk-PJNGPWTA.js";
19
19
  import "./chunk-YEJR7IXO.js";
20
20
  import "./chunk-DGUM43GV.js";
21
21
  export {
@@ -2,9 +2,9 @@ import { AgentProfile } from '@tangle-network/agent-interface';
2
2
  import { a as ProfileArtifact, A as ArtifactKind, b as ArtifactStatus, c as ArtifactInput, E as EvalRunner, d as EvalResult, G as GenerateContext, C as CandidateGenerator, e as PromotionVerdict, P as PromotionGate } from './generator-YkAQrOoD.js';
3
3
  export { f as ArtifactPayloads, H as HeldOutPromotionGateOptions, M as MarginalLift, g as MeasureMarginalLiftOptions, h as heldOutPromotionGate, m as measureMarginalLift, t as thresholdPromotionGate } from './generator-YkAQrOoD.js';
4
4
  import { LlmClientOptions, AnalystFinding } from '@tangle-network/agent-eval';
5
- import { M as McpServeSpec } from './mcp-serve-verifier-Bg4C3p5S.js';
6
- import { L as LocalHarness } from './local-harness-dcD5WTTr.js';
7
- import './agentic-generator-B8oeE2Yv.js';
5
+ import { M as McpServeSpec } from './mcp-serve-verifier-BuXjaZDE.js';
6
+ import { L as LocalHarness } from './local-harness-B7bNuNJw.js';
7
+ import './agentic-generator-D9ZmAuiL.js';
8
8
  import '@tangle-network/agent-eval/campaign';
9
9
  import 'node:child_process';
10
10
 
package/dist/lifecycle.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  import {
7
7
  agenticGenerator,
8
8
  commandVerifier
9
- } from "./chunk-RTVVH2KL.js";
10
- import "./chunk-PX6SXX3M.js";
9
+ } from "./chunk-JEP2WM24.js";
10
+ import "./chunk-PJNGPWTA.js";
11
11
  import {
12
12
  ValidationError
13
13
  } from "./chunk-YEJR7IXO.js";
@@ -42,6 +42,9 @@ interface RunLocalHarnessOptions {
42
42
  /** Allow autonomous Claude edits without an interactive permission prompt.
43
43
  * Use only when `cwd` is an isolated candidate worktree. */
44
44
  dangerouslySkipPermissions?: boolean;
45
+ /** Isolate Codex from ambient configuration/instructions and require JSONL token usage.
46
+ * The invocation should come from `harnessInvocation(..., { codexReproducible: true })`. */
47
+ codexReproducible?: boolean;
45
48
  /** Wall-clock kill deadline (ms). Default 5 min. Subprocess SIGTERMed on expiry. */
46
49
  timeoutMs?: number;
47
50
  /** Caller cancellation. SIGTERM is sent on abort. */
@@ -58,6 +61,45 @@ interface RunLocalHarnessOptions {
58
61
  stdio: 'pipe';
59
62
  }) => ChildProcess;
60
63
  }
64
+ /** Exact aggregate usage emitted by Codex's terminal `turn.completed` JSONL event. */
65
+ interface CodexTokenUsage {
66
+ inputTokens: number;
67
+ cachedInputTokens: number;
68
+ outputTokens: number;
69
+ reasoningOutputTokens: number;
70
+ }
71
+ /** Isolation settings asserted before a reproducible Codex run is allowed to start. */
72
+ interface CodexExecutionPolicy {
73
+ sessionPersistence: 'ephemeral';
74
+ userConfig: false;
75
+ rules: false;
76
+ projectInstructions: false;
77
+ skillInstructions: false;
78
+ appInstructions: false;
79
+ toolSuggestions: false;
80
+ multiAgentInstructions: false;
81
+ sandbox: 'workspace-write';
82
+ permissionProfile: 'agent_runtime_reproducible';
83
+ approvalPolicy: 'never';
84
+ shellNetwork: false;
85
+ webSearch: false;
86
+ serviceTier: 'default';
87
+ shellEnvironment: 'core-filtered';
88
+ loginShell: false;
89
+ credentialsReadable: false;
90
+ parentRepoRead: false;
91
+ gitMetadata: false;
92
+ temporaryDirectory: 'workspace-private';
93
+ containerSockets: false;
94
+ }
95
+ /** Zero-model-call evidence for the exact Codex process about to run. */
96
+ interface CodexExecutionEvidence {
97
+ cliVersion: string;
98
+ effectivePromptSha256: string;
99
+ nonPromptArgsSha256: string;
100
+ controlledConfigSha256: string;
101
+ policy: CodexExecutionPolicy;
102
+ }
61
103
  /** @experimental */
62
104
  interface LocalHarnessResult {
63
105
  /** OS exit code. `null` when killed before exit. */
@@ -72,6 +114,10 @@ interface LocalHarnessResult {
72
114
  durationMs: number;
73
115
  /** Set when timeoutMs elapsed before exit. */
74
116
  timedOut: boolean;
117
+ /** Present for a reproducible Codex run; parsed from the real terminal JSONL event. */
118
+ usage?: CodexTokenUsage;
119
+ /** Present for reproducible Codex runs; generated and checked before model execution. */
120
+ evidence?: CodexExecutionEvidence;
75
121
  }
76
122
  /**
77
123
  * Spawn a local coding harness CLI as a subprocess + collect its output.
@@ -93,5 +139,7 @@ interface LocalHarnessResult {
93
139
  * @experimental
94
140
  */
95
141
  declare function runLocalHarness(options: RunLocalHarnessOptions): Promise<LocalHarnessResult>;
142
+ /** Parse and validate the one terminal usage event emitted by `codex exec --json`. */
143
+ declare function parseCodexTokenUsage(stdout: string): CodexTokenUsage;
96
144
 
97
- export { type LocalHarness as L, type RunLocalHarnessOptions as R, type LocalHarnessResult as a, runLocalHarness as r };
145
+ export { type CodexTokenUsage as C, type LocalHarness as L, type RunLocalHarnessOptions as R, type CodexExecutionPolicy as a, type CodexExecutionEvidence as b, type LocalHarnessResult as c, parseCodexTokenUsage as p, runLocalHarness as r };
@@ -2,8 +2,8 @@ import { Scenario } from '@tangle-network/agent-eval/campaign';
2
2
  import { SelfImproveOptions, SelfImproveResult } from '@tangle-network/agent-eval/contract';
3
3
  import { R as RunAnalystLoopOpts, a as RunAnalystLoopResult } from './types-BC3bZpH0.js';
4
4
  import { F as FactCandidate, C as CreateKbGateOptions } from './kb-gate-CwHO0vz6.js';
5
- import { B as Budget } from './types-Cg_teUPO.js';
6
- import { A as AuthoredHarness, W as WinnerStrategy, a as WorktreeFanoutOptions, b as WorktreePatchArtifact } from './worktree-fanout-BrB4att3.js';
5
+ import { B as Budget } from './types-Bb-CqxJH.js';
6
+ import { A as AuthoredHarness, W as WinnerStrategy, a as WorktreeFanoutOptions, b as WorktreePatchArtifact } from './worktree-fanout-IMKqdV_E.js';
7
7
 
8
8
  /**
9
9
  *
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- export { L as LoopRunnerCliArgs, e as LoopRunnerCliResult, p as parseLoopRunnerArgv, k as runLoopRunnerCli } from './loop-runner-bin-BRXC1RwC.js';
2
+ export { L as LoopRunnerCliArgs, e as LoopRunnerCliResult, p as parseLoopRunnerArgv, k as runLoopRunnerCli } from './loop-runner-bin-D4bMIxmB.js';
3
3
  import '@tangle-network/agent-eval/campaign';
4
4
  import '@tangle-network/agent-eval/contract';
5
5
  import './types-BC3bZpH0.js';
6
6
  import '@tangle-network/agent-eval';
7
7
  import './kb-gate-CwHO0vz6.js';
8
- import './types-Cg_teUPO.js';
8
+ import './types-Bb-CqxJH.js';
9
9
  import '@tangle-network/agent-interface';
10
10
  import '@tangle-network/sandbox';
11
11
  import './types-DWA64rbJ.js';
12
- import './worktree-fanout-BrB4att3.js';
13
- import './completion-gate-BDkEYB_-.js';
14
- import './local-harness-dcD5WTTr.js';
12
+ import './worktree-fanout-IMKqdV_E.js';
13
+ import './completion-gate-BAj3dXeW.js';
14
+ import './local-harness-B7bNuNJw.js';
15
15
  import 'node:child_process';
@@ -2,18 +2,18 @@
2
2
  import {
3
3
  parseLoopRunnerArgv,
4
4
  runLoopRunnerCli
5
- } from "./chunk-MRYPFDHJ.js";
5
+ } from "./chunk-RTSZNYXM.js";
6
6
  import "./chunk-SGKPNBXE.js";
7
- import "./chunk-OO4EK3JB.js";
7
+ import "./chunk-D336OZHK.js";
8
8
  import "./chunk-ZQZX77MM.js";
9
- import "./chunk-FHZHADIM.js";
9
+ import "./chunk-URMJTSXB.js";
10
10
  import "./chunk-DPEUKJRO.js";
11
11
  import "./chunk-ISTDY47H.js";
12
- import "./chunk-3D2RHC4K.js";
12
+ import "./chunk-WIPGQ4GT.js";
13
13
  import "./chunk-VSWBYWFK.js";
14
14
  import "./chunk-3MDZX7YU.js";
15
15
  import "./chunk-FVJ7M3DA.js";
16
- import "./chunk-PX6SXX3M.js";
16
+ import "./chunk-PJNGPWTA.js";
17
17
  import "./chunk-YEJR7IXO.js";
18
18
  import "./chunk-DGUM43GV.js";
19
19
  export {