@tangle-network/agent-eval 1.0.21 → 1.0.23

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 (167) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/adapters/http.d.ts +2 -2
  3. package/dist/{agent-profile-Dngk3LZ0.js → agent-profile-4j6f2n-x.js} +4 -4
  4. package/dist/agent-profile-4j6f2n-x.js.map +1 -0
  5. package/dist/{agent-profile-BO8ruI6R.d.ts → agent-profile-C80hNPYb.d.ts} +5 -5
  6. package/dist/{agent-profile-BO8ruI6R.d.ts.map → agent-profile-C80hNPYb.d.ts.map} +1 -1
  7. package/dist/analyst/index.d.ts +11 -11
  8. package/dist/analyst/index.js +1 -1
  9. package/dist/{analyze-runs-jLTRKuoK.js → analyze-runs-BCSHzqna.js} +2 -2
  10. package/dist/{analyze-runs-jLTRKuoK.js.map → analyze-runs-BCSHzqna.js.map} +1 -1
  11. package/dist/{analyze-runs-DYYe18Gw.d.ts → analyze-runs-DbHQHvDC.d.ts} +4 -4
  12. package/dist/{analyze-runs-DYYe18Gw.d.ts.map → analyze-runs-DbHQHvDC.d.ts.map} +1 -1
  13. package/dist/app-grade/index.d.ts +3 -3
  14. package/dist/{benchmark-command-CoNndRCk.js → benchmark-command-DkUpd9Q6.js} +2 -2
  15. package/dist/{benchmark-command-CoNndRCk.js.map → benchmark-command-DkUpd9Q6.js.map} +1 -1
  16. package/dist/benchmarks/index.d.ts +5 -5
  17. package/dist/benchmarks/index.js +2 -2
  18. package/dist/campaign/index.d.ts +6 -6
  19. package/dist/campaign/index.js +7 -7
  20. package/dist/{campaign-Bl07uIaf.js → campaign-D00Tbey-.js} +10 -10
  21. package/dist/{campaign-Bl07uIaf.js.map → campaign-D00Tbey-.js.map} +1 -1
  22. package/dist/{campaign-evidence-NtH29ctt.js → campaign-evidence-CVNKiK0q.js} +2 -2
  23. package/dist/{campaign-evidence-NtH29ctt.js.map → campaign-evidence-CVNKiK0q.js.map} +1 -1
  24. package/dist/cli.js +6 -6
  25. package/dist/contract/index.d.ts +10 -10
  26. package/dist/contract/index.js +7 -8
  27. package/dist/contract/index.js.map +1 -1
  28. package/dist/{default-registry-aPvwtzEM.d.ts → default-registry-CjgRr-l7.d.ts} +7 -7
  29. package/dist/{default-registry-aPvwtzEM.d.ts.map → default-registry-CjgRr-l7.d.ts.map} +1 -1
  30. package/dist/{define-agent-eval-Bx3b9B01.d.ts → define-agent-eval-BQBwKHwF.d.ts} +7 -7
  31. package/dist/{define-agent-eval-Bx3b9B01.d.ts.map → define-agent-eval-BQBwKHwF.d.ts.map} +1 -1
  32. package/dist/{define-agent-eval-BROmIwn1.js → define-agent-eval-BV16x8C0.js} +7 -7
  33. package/dist/{define-agent-eval-BROmIwn1.js.map → define-agent-eval-BV16x8C0.js.map} +1 -1
  34. package/dist/diagnosis/index.d.ts +2 -2
  35. package/dist/diagnosis/index.js +1 -1
  36. package/dist/{engine-BF8naBn7.d.ts → engine-s3t6uYH9.d.ts} +2 -2
  37. package/dist/{engine-BF8naBn7.d.ts.map → engine-s3t6uYH9.d.ts.map} +1 -1
  38. package/dist/{eval-campaign-Dq8DEKmy.js → eval-campaign-DpkToY_w.js} +2 -2
  39. package/dist/eval-campaign-DpkToY_w.js.map +1 -0
  40. package/dist/{evaluation-CFKj_IlJ.d.ts → evaluation-DRgHKEVV.d.ts} +4 -4
  41. package/dist/{evaluation-CFKj_IlJ.d.ts.map → evaluation-DRgHKEVV.d.ts.map} +1 -1
  42. package/dist/evaluation.d.ts +1 -1
  43. package/dist/{exact-types-VAFjtOQN.d.ts → exact-types-DTlZSygs.d.ts} +2 -2
  44. package/dist/{exact-types-VAFjtOQN.d.ts.map → exact-types-DTlZSygs.d.ts.map} +1 -1
  45. package/dist/experiment/index.d.ts +2 -2
  46. package/dist/experiment/index.js +2 -2
  47. package/dist/{feedback-trajectory-DTj8eVTR.d.ts → feedback-trajectory-DrKk79NU.d.ts} +3 -3
  48. package/dist/{feedback-trajectory-DTj8eVTR.d.ts.map → feedback-trajectory-DrKk79NU.d.ts.map} +1 -1
  49. package/dist/hosted/index.js +1 -1
  50. package/dist/{index-BlTbxHlY.d.ts → index-DAnkXnwF.d.ts} +3 -3
  51. package/dist/{index-BlTbxHlY.d.ts.map → index-DAnkXnwF.d.ts.map} +1 -1
  52. package/dist/{index-DfqAy8ct.d.ts → index-DLZp90hM.d.ts} +8 -8
  53. package/dist/{index-DfqAy8ct.d.ts.map → index-DLZp90hM.d.ts.map} +1 -1
  54. package/dist/{index-7tWvC0aW.d.ts → index-DZ_aqB7v.d.ts} +23 -179
  55. package/dist/index-DZ_aqB7v.d.ts.map +1 -0
  56. package/dist/{index-DFso1b2W.d.ts → index-DjrXBogW.d.ts} +9 -9
  57. package/dist/{index-DFso1b2W.d.ts.map → index-DjrXBogW.d.ts.map} +1 -1
  58. package/dist/{index-CM12lr9E.d.ts → index-DtX456kD.d.ts} +6 -6
  59. package/dist/{index-CM12lr9E.d.ts.map → index-DtX456kD.d.ts.map} +1 -1
  60. package/dist/{index-B62BaRzH.d.ts → index-DwscLCQX.d.ts} +2 -2
  61. package/dist/{index-B62BaRzH.d.ts.map → index-DwscLCQX.d.ts.map} +1 -1
  62. package/dist/index.d.ts +25 -25
  63. package/dist/index.js +14 -13
  64. package/dist/index.js.map +1 -1
  65. package/dist/{llm-judge-C813vmpc.js → llm-judge-Cbh7OHaO.js} +7 -7
  66. package/dist/{llm-judge-C813vmpc.js.map → llm-judge-Cbh7OHaO.js.map} +1 -1
  67. package/dist/{matrix-C-GxIgeJ.d.ts → matrix-8NhGDcmi.d.ts} +2 -2
  68. package/dist/{matrix-C-GxIgeJ.d.ts.map → matrix-8NhGDcmi.d.ts.map} +1 -1
  69. package/dist/meta-eval/index.d.ts +2 -2
  70. package/dist/{mint-yF51iBgY.js → mint-Ck92efNo.js} +2 -2
  71. package/dist/{mint-yF51iBgY.js.map → mint-Ck92efNo.js.map} +1 -1
  72. package/dist/multishot/golden/index.d.ts +1 -1
  73. package/dist/multishot/index.d.ts +2 -2
  74. package/dist/openapi.json +1 -1
  75. package/dist/paired-promotion-power-D03cUj9E.js +289 -0
  76. package/dist/paired-promotion-power-D03cUj9E.js.map +1 -0
  77. package/dist/{pareto-fJZg8pXm.js → pareto-UzjB3ZBk.js} +5 -288
  78. package/dist/pareto-UzjB3ZBk.js.map +1 -0
  79. package/dist/{prime-protocol-D1NkJRuD.d.ts → prime-protocol-CKxq_-cx.d.ts} +2 -2
  80. package/dist/{prime-protocol-D1NkJRuD.d.ts.map → prime-protocol-CKxq_-cx.d.ts.map} +1 -1
  81. package/dist/{promotion-gate-Da0xV4sa.d.ts → promotion-gate-HDtliGsh.d.ts} +3 -3
  82. package/dist/{promotion-gate-Da0xV4sa.d.ts.map → promotion-gate-HDtliGsh.d.ts.map} +1 -1
  83. package/dist/{registry-BAcEbzKm.d.ts → registry-BnenKvxM.d.ts} +3 -3
  84. package/dist/{registry-BAcEbzKm.d.ts.map → registry-BnenKvxM.d.ts.map} +1 -1
  85. package/dist/{release-confidence-DGtuPDxJ.js → release-confidence-B4Xxdpmn.js} +2 -2
  86. package/dist/{release-confidence-DGtuPDxJ.js.map → release-confidence-B4Xxdpmn.js.map} +1 -1
  87. package/dist/reporting.d.ts +4 -4
  88. package/dist/reporting.js +2 -2
  89. package/dist/{researcher-CSlc84Bp.d.ts → researcher-DEpedkOZ.d.ts} +4 -4
  90. package/dist/{researcher-CSlc84Bp.d.ts.map → researcher-DEpedkOZ.d.ts.map} +1 -1
  91. package/dist/{reward-ST4PXNXF.d.ts → reward-ap_R9mCH.d.ts} +2 -2
  92. package/dist/{reward-ST4PXNXF.d.ts.map → reward-ap_R9mCH.d.ts.map} +1 -1
  93. package/dist/{reward-hacking-C9hPVT0Q.d.ts → reward-hacking-CIdVwVe4.d.ts} +2 -2
  94. package/dist/{reward-hacking-C9hPVT0Q.d.ts.map → reward-hacking-CIdVwVe4.d.ts.map} +1 -1
  95. package/dist/rl.d.ts +8 -8
  96. package/dist/rl.js +5 -5
  97. package/dist/rollout/index.d.ts +3 -3
  98. package/dist/rollout/index.js +2 -2
  99. package/dist/{rollout-DKa54qer.js → rollout-DWl3Gg6A.js} +2 -2
  100. package/dist/{rollout-DKa54qer.js.map → rollout-DWl3Gg6A.js.map} +1 -1
  101. package/dist/{rubric-predictive-validity-B3RzbwOx.d.ts → rubric-predictive-validity-Bbi88Aut.d.ts} +2 -2
  102. package/dist/{rubric-predictive-validity-B3RzbwOx.d.ts.map → rubric-predictive-validity-Bbi88Aut.d.ts.map} +1 -1
  103. package/dist/{run-record-CFbnkE1K.js → run-record-DTTx9Ktr.js} +2 -2
  104. package/dist/{run-record-CFbnkE1K.js.map → run-record-DTTx9Ktr.js.map} +1 -1
  105. package/dist/{run-record-CpLS4Uid.js → run-record-DmX_ESC5.js} +7 -5
  106. package/dist/run-record-DmX_ESC5.js.map +1 -0
  107. package/dist/{run-record-D2BFMPGl.d.ts → run-record-pBlhZizT.d.ts} +8 -8
  108. package/dist/{run-record-D2BFMPGl.d.ts.map → run-record-pBlhZizT.d.ts.map} +1 -1
  109. package/dist/search/index.d.ts +2 -2
  110. package/dist/search/index.d.ts.map +1 -1
  111. package/dist/search/index.js +2 -2
  112. package/dist/{search-kernel-CQGLbmgn.d.ts → search-kernel-CoDJ21q9.d.ts} +3 -3
  113. package/dist/{search-kernel-CQGLbmgn.d.ts.map → search-kernel-CoDJ21q9.d.ts.map} +1 -1
  114. package/dist/{search-ledger-Dk-yk5Li.js → search-ledger-9liYyZf5.js} +2 -2
  115. package/dist/{search-ledger-Dk-yk5Li.js.map → search-ledger-9liYyZf5.js.map} +1 -1
  116. package/dist/{search-shipper-Dm-_Dtvy.js → search-shipper-B6tMNx1I.js} +2 -2
  117. package/dist/{search-shipper-Dm-_Dtvy.js.map → search-shipper-B6tMNx1I.js.map} +1 -1
  118. package/dist/{search-summary-sPWiYtSl.js → search-summary-CISbbxyr.js} +2 -2
  119. package/dist/{search-summary-sPWiYtSl.js.map → search-summary-CISbbxyr.js.map} +1 -1
  120. package/dist/sequential-BCzXKQab.d.ts +246 -0
  121. package/dist/sequential-BCzXKQab.d.ts.map +1 -0
  122. package/dist/{sequential-CAksw6EU.js → sequential-Ko7T-zvu.js} +65 -28
  123. package/dist/sequential-Ko7T-zvu.js.map +1 -0
  124. package/dist/{skillopt-optimization-method-QO1nU8Kz.js → skillopt-optimization-method-B1Hkfexf.js} +4 -4
  125. package/dist/{skillopt-optimization-method-QO1nU8Kz.js.map → skillopt-optimization-method-B1Hkfexf.js.map} +1 -1
  126. package/dist/{statistical-heldout-CvOwNqt9.d.ts → statistical-heldout-e2hbqDui.d.ts} +4 -4
  127. package/dist/{statistical-heldout-CvOwNqt9.d.ts.map → statistical-heldout-e2hbqDui.d.ts.map} +1 -1
  128. package/dist/{store-tool-spans-B3z_Qb5u.d.ts → store-tool-spans-mlmGj6n3.d.ts} +5 -5
  129. package/dist/{store-tool-spans-B3z_Qb5u.d.ts.map → store-tool-spans-mlmGj6n3.d.ts.map} +1 -1
  130. package/dist/{summary-report-DyZquTaH.d.ts → summary-report-DsiORzPc.d.ts} +3 -3
  131. package/dist/{summary-report-DyZquTaH.d.ts.map → summary-report-DsiORzPc.d.ts.map} +1 -1
  132. package/dist/{systemone-DVk-Crtu.d.ts → systemone-B93onE_a.d.ts} +7 -7
  133. package/dist/{systemone-DVk-Crtu.d.ts.map → systemone-B93onE_a.d.ts.map} +1 -1
  134. package/dist/{systemone-review-CToBl1oa.d.ts → systemone-review-BIggseLt.d.ts} +2 -2
  135. package/dist/{systemone-review-CToBl1oa.d.ts.map → systemone-review-BIggseLt.d.ts.map} +1 -1
  136. package/dist/systemone.d.ts +3 -3
  137. package/dist/{tool-groups-R5RO9OHn.d.ts → tool-groups-CCiATVZw.d.ts} +3 -3
  138. package/dist/tool-groups-CCiATVZw.d.ts.map +1 -0
  139. package/dist/{trace-questions-BY6taxnl.d.ts → trace-questions-B7lkyOlo.d.ts} +3 -3
  140. package/dist/{trace-questions-BY6taxnl.d.ts.map → trace-questions-B7lkyOlo.d.ts.map} +1 -1
  141. package/dist/trace-repair/index.d.ts +2 -2
  142. package/dist/traces.d.ts +4 -4
  143. package/dist/traces.js +2 -8
  144. package/dist/traces.js.map +1 -1
  145. package/dist/{tree-C-N2kP-8.js → tree-D2cNtu9m.js} +10 -10
  146. package/dist/tree-D2cNtu9m.js.map +1 -0
  147. package/dist/{types-BsdcSWnf.d.ts → types-3uX8odDK.d.ts} +3 -3
  148. package/dist/{types-BsdcSWnf.d.ts.map → types-3uX8odDK.d.ts.map} +1 -1
  149. package/dist/{types-kBMNdo1X.d.ts → types-Ob1blgI2.d.ts} +2 -2
  150. package/dist/{types-kBMNdo1X.d.ts.map → types-Ob1blgI2.d.ts.map} +1 -1
  151. package/dist/{types-ip2D3-Ib.d.ts → types-efIQ03Uo.d.ts} +4 -4
  152. package/dist/{types-ip2D3-Ib.d.ts.map → types-efIQ03Uo.d.ts.map} +1 -1
  153. package/dist/wire/index.d.ts +3 -3
  154. package/docs/adopt-stack.md +9 -0
  155. package/docs/eval-fixtures.md +2 -2
  156. package/docs/search-ledger.md +1 -0
  157. package/package.json +5 -5
  158. package/dist/agent-profile-Dngk3LZ0.js.map +0 -1
  159. package/dist/eval-campaign-Dq8DEKmy.js.map +0 -1
  160. package/dist/index-7tWvC0aW.d.ts.map +0 -1
  161. package/dist/pareto-fJZg8pXm.js.map +0 -1
  162. package/dist/run-record-CpLS4Uid.js.map +0 -1
  163. package/dist/sequential-B9p6uoV8.d.ts +0 -168
  164. package/dist/sequential-B9p6uoV8.d.ts.map +0 -1
  165. package/dist/sequential-CAksw6EU.js.map +0 -1
  166. package/dist/tool-groups-R5RO9OHn.d.ts.map +0 -1
  167. package/dist/tree-C-N2kP-8.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rollout-DKa54qer.js","names":[],"sources":["../src/rollout/harbor-task.ts","../src/rollout/interchange/harbor.ts","../src/rollout/readers/claude-jsonl.ts","../src/rollout/readers/codex-rollout.ts","../src/rollout/readers/opencode-sqlite.ts","../src/rollout/tinker.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport {\n link,\n lstat,\n mkdir,\n readdir,\n readFile,\n realpath,\n unlink,\n writeFile,\n} from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\n\nimport { assertCodeSurfaceIdentity } from '../campaign/surface-identity'\nimport type { CodeSurface } from '../campaign/types'\nimport { type CompletionVerdict, completionVerdict } from '../completion-verifier'\nimport { canonicalString } from '../ledger-core/canonical'\nimport { deepFreezeCanonicalJson } from '../ledger-core/deep-freeze'\nimport { assertMinted, type MintedRolloutLine } from './schema'\n\n/** Existing completion checks required to admit a verified episode as a runnable task. */\nexport const HARBOR_TASK_CHECKS = [\n 'base-bundle',\n 'acceptance',\n 'production-delta',\n 'dangling-references',\n 'merge-followup',\n] as const\n\nexport interface HarborTaskFile {\n /** Relative path in the published task. */\n readonly path: string\n /** Actual staged path; task.toml is not published until verification succeeds. */\n readonly stagedPath: string\n readonly sha256: string\n readonly byteLength: number\n}\n\nexport interface HarborTaskVerification {\n /** Digest binding this episode, immutable source identity, merge and every task file. */\n readonly taskId: string\n readonly rolloutId: string\n readonly episodeSha256: string\n readonly task: MintedRolloutLine['task']\n readonly source: Omit<CodeSurface, 'worktreeRef' | 'summary' | 'baseRef'>\n readonly mergeCommit: string\n readonly files: readonly HarborTaskFile[]\n}\n\nexport interface WriteHarborTaskOptions {\n /** Fresh task directory, normally <dataset>/tasks/<task>. Existing paths are refused. */\n readonly directory: string\n readonly episode: MintedRolloutLine\n readonly surface: CodeSurface\n readonly mergeCommit: string\n /** Harbor's org/name task name. */\n readonly name: string\n readonly instruction: string\n /** Caller image with Git/dependencies and a configured user able to clone into /workspace. */\n readonly image: string\n /** Git bundle containing the base and its ancestors only, never the answer/head/merge. */\n readonly baseBundle: Uint8Array\n readonly commands: {\n readonly acceptance: string\n readonly productionDelta: string\n readonly danglingReferences: string\n }\n readonly agentTimeoutSec: number\n readonly verifierTimeoutSec: number\n /**\n * Trusted caller execution boundary. Inspect the actual staged bundle and file hashes.\n * base-bundle proves exact base/tree, base-only closure and no answer material; the\n * three verifier checks prove the supplied commands actually passed on this candidate\n * (strict production-line decrease, zero dangling refs); merge-followup proves this\n * candidate merged with base=merge^1 and a closed, explicitly checked no-fix-forward\n * followup window. Every check must cite receipts bound to taskId, not a title/keyword.\n * Unknown, absent, open followup and provider eligibility are not affirmative evidence.\n */\n readonly verify: (\n request: HarborTaskVerification,\n signal?: AbortSignal,\n ) => Promise<CompletionVerdict>\n readonly signal?: AbortSignal\n}\n\nconst digest = (bytes: Uint8Array | string): string =>\n `sha256:${createHash('sha256').update(bytes).digest('hex')}`\n\nfunction admitted(verdict: CompletionVerdict, taskId: string): void {\n if (verdict.taskId !== taskId) throw new Error('Harbor task verification identity mismatch')\n if (!Array.isArray(verdict.requirements))\n throw new Error('Harbor task requires completion checks')\n for (const row of verdict.requirements) {\n if (\n !row ||\n typeof row.reqId !== 'string' ||\n !row.reqId.trim() ||\n row.correct !== true ||\n row.structurallyPresent !== true ||\n row.satisfied !== true ||\n row.unmeasured !== undefined ||\n !Array.isArray(row.evidence) ||\n !row.evidence.some((value) => typeof value === 'string' && value.trim().length > 0)\n ) {\n throw new Error(`Harbor task requires measured passing ${row?.reqId ?? 'invalid'} evidence`)\n }\n }\n for (const id of HARBOR_TASK_CHECKS) {\n if (verdict.requirements.filter((row) => row.reqId === id).length !== 1) {\n throw new Error(`Harbor task requires exactly one ${id} check`)\n }\n }\n const derived = completionVerdict({ taskId, requirements: verdict.requirements })\n if (\n derived.fullyComplete !== true ||\n verdict.fullyComplete !== true ||\n verdict.valid !== true ||\n verdict.score !== 1 ||\n verdict.completionRate !== 1 ||\n verdict.unmeasuredCount !== 0\n ) {\n throw new Error('Harbor task verification is incomplete')\n }\n}\n\n/**\n * Write a Harbor directory from an admitted canonical episode, without executing it.\n * Failed admission leaves diagnostic files but no task.toml, so the directory is not\n * loadable as a task. The caller owns execution, receipt truth and artifact retention.\n */\nexport async function writeHarborTask(options: WriteHarborTaskOptions): Promise<string> {\n // Capture inputs before the first await; the callback cannot retarget caller-owned data.\n const episode = assertMinted(JSON.parse(canonicalString(options.episode)), 'Harbor task episode')\n const surface = JSON.parse(canonicalString(options.surface)) as CodeSurface\n assertCodeSurfaceIdentity(surface)\n const { kind, baseCommit, baseTree, candidateCommit, candidateTree, patch } = surface\n const source = { kind, baseCommit, baseTree, candidateCommit, candidateTree, patch }\n const {\n directory: inputDirectory,\n name,\n instruction,\n image,\n mergeCommit,\n agentTimeoutSec,\n verifierTimeoutSec,\n verify,\n signal,\n } = options\n const commands = { ...options.commands }\n const bundle = Uint8Array.from(options.baseBundle)\n if (\n episode.outcome.reward !== 1 ||\n !episode.outcome.is_completed ||\n episode.outcome.is_truncated ||\n episode.outcome.error !== null ||\n episode.outcome.realness_screened !== true ||\n episode.outcome.realness_gated === true\n ) {\n throw new Error('Harbor task requires a completed, screened, passing episode')\n }\n if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(mergeCommit)) {\n throw new Error('Harbor task requires a full merge commit identity')\n }\n if (\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]*\\/[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name) ||\n !instruction.trim() ||\n !bundle.length\n )\n throw new Error('Invalid Harbor task input')\n if (!/^[a-zA-Z0-9][a-zA-Z0-9./:_-]*@sha256:[a-f0-9]{64}$/.test(image)) {\n throw new Error('Harbor task image must be pinned by sha256 digest')\n }\n for (const timeout of [agentTimeoutSec, verifierTimeoutSec]) {\n if (!Number.isSafeInteger(timeout) || timeout <= 0) throw new Error('Invalid Harbor timeout')\n }\n if (Object.values(commands).some((command) => typeof command !== 'string' || !command.trim())) {\n throw new Error('All three Harbor verifier commands are required')\n }\n const config =\n `schema_version = \"1.3\"\\n[task]\\nname = \"${name}\"\\n` +\n `[agent]\\ntimeout_sec = ${agentTimeoutSec}\\n[verifier]\\ntimeout_sec = ${verifierTimeoutSec}\\n`\n const files: Record<string, string | Uint8Array> = {\n 'task.toml': config,\n 'instruction.md': instruction,\n 'environment/base.bundle': bundle,\n 'environment/Dockerfile':\n `FROM ${image}\\nCOPY --chmod=0444 base.bundle /tmp/base.bundle\\n` +\n `RUN git clone --no-checkout /tmp/base.bundle /workspace/repo \\\\\\n && git -C /workspace/repo checkout --detach ${baseCommit} \\\\\\n && test \"$(git -C /workspace/repo rev-parse HEAD)\" = \"${baseCommit}\"\\nWORKDIR /workspace/repo\\n`,\n 'tests/acceptance.sh': commands.acceptance,\n 'tests/production-delta.sh': commands.productionDelta,\n 'tests/dangling-references.sh': commands.danglingReferences,\n 'tests/test.sh':\n '#!/bin/sh\\nset -eu\\nproject=${1:-/workspace/repo}\\n' +\n 'tests=${2:-/tests}\\nrewards=${3:-/logs/verifier}\\nmkdir -p \"$rewards\"\\n' +\n 'printf \"0\\\\n\" > \"$rewards/reward.txt\"\\ncd \"$project\"\\n' +\n `git cat-file -e ${baseCommit}^{commit}\\ngit merge-base --is-ancestor ${baseCommit} HEAD\\n` +\n 'sh \"$tests/acceptance.sh\"\\nsh \"$tests/production-delta.sh\"\\nsh \"$tests/dangling-references.sh\"\\n' +\n 'printf \"1\\\\n\" > \"$rewards/reward.txt\"\\n',\n }\n const directory = resolve(inputDirectory)\n signal?.throwIfAborted()\n if ((await realpath(dirname(directory))) !== dirname(directory)) {\n throw new Error('Harbor task parent must not traverse symlinks')\n }\n await mkdir(directory, { mode: 0o700 })\n await mkdir(join(directory, 'environment'))\n await mkdir(join(directory, 'tests'))\n const staged: HarborTaskFile[] = []\n for (const [path, bytes] of Object.entries(files)) {\n const stagedPath = join(directory, path === 'task.toml' ? '.task.toml.pending' : path)\n await writeFile(stagedPath, bytes, { flag: 'wx', mode: path.endsWith('.sh') ? 0o700 : 0o600 })\n staged.push(\n Object.freeze({\n path,\n stagedPath,\n sha256: digest(bytes),\n byteLength: typeof bytes === 'string' ? Buffer.byteLength(bytes) : bytes.byteLength,\n }),\n )\n }\n const identity = {\n rolloutId: episode.rollout_id,\n episodeSha256: digest(canonicalString(episode)),\n task: episode.task,\n source,\n mergeCommit,\n files: staged.map(({ path, sha256, byteLength }) => ({ path, sha256, byteLength })),\n }\n const taskId = digest(canonicalString(identity))\n const request = deepFreezeCanonicalJson({ ...identity, taskId, files: staged })\n signal?.throwIfAborted()\n const verdict = JSON.parse(canonicalString(await verify(request, signal))) as CompletionVerdict\n signal?.throwIfAborted()\n admitted(verdict, taskId)\n // No callback may add answer material to the build context or redirect a parent directory.\n for (const folder of ['', 'environment', 'tests']) {\n const path = join(directory, folder)\n if (!(await lstat(path)).isDirectory() || (await realpath(path)) !== path) {\n throw new Error('Harbor task directory changed during verification')\n }\n const expected =\n folder === ''\n ? ['.task.toml.pending', 'environment', 'instruction.md', 'tests']\n : Object.keys(files)\n .filter((file) => file.startsWith(`${folder}/`))\n .map((file) => file.slice(folder.length + 1))\n if (canonicalString((await readdir(path)).sort()) !== canonicalString(expected.sort())) {\n throw new Error('Harbor task contains unexpected files')\n }\n }\n for (const file of staged) {\n const info = await lstat(file.stagedPath)\n if (\n !info.isFile() ||\n info.isSymbolicLink() ||\n digest(await readFile(file.stagedPath)) !== file.sha256\n ) {\n throw new Error(`Harbor task file changed during verification: ${file.path}`)\n }\n }\n await writeFile(\n join(directory, 'tests/verification.json'),\n canonicalString({ identity, taskId, verdict }),\n { flag: 'wx', mode: 0o600 },\n )\n signal?.throwIfAborted()\n await link(join(directory, '.task.toml.pending'), join(directory, 'task.toml'))\n await unlink(join(directory, '.task.toml.pending'))\n return directory\n}\n","/**\n * Harbor ATIF-v1.7 interchange — `tangle.rollout.v1` ⇄ Agent Trajectory\n * Interchange Format.\n *\n * ATIF is the portability format (spec:\n * https://www.harborframework.com/docs/agents/trajectory-format, normative\n * RFC: harbor-framework/harbor `rfcs/0001-trajectory-format.md`). It sits\n * BELOW the waist of the rollout hourglass in both directions — export reads\n * `RolloutLine[]`, import writes `RolloutLine[]` — and it is never a source\n * of training labels:\n *\n * ATIF models NO reward, NO judge verdict, NO task/split coordinates.\n *\n * Consequences, both deliberate:\n * - EXPORT drops `outcome.reward`, `outcome.reward_source` and\n * `outcome.verdict` entirely. They are not smuggled into `extra`: a\n * third-party reading our ATIF file must not be able to mistake an\n * agent-eval judge score for something ATIF sanctioned.\n * - IMPORT therefore mints UNLABELED lines: `reward: null` (the existing\n * \"null reward is a labeled gap, never 0\" semantics), `verdict: null`,\n * and a `provenance.gap` naming the missing label. An imported\n * trajectory is not a training example until a judge scores it.\n *\n * Everything else we own that ATIF has no field for travels in a namespaced\n * escrow at `extra.tangle.*`, so our own round-trip is exact while a foreign\n * reader can ignore it. Fields that neither ATIF nor the escrow can carry\n * come back explicitly null / fail-closed, never invented.\n *\n * THE ESCROW IS NAMESPACED, NOT AUTHENTICATED. Anyone can write\n * `extra.tangle.*` into a file. So the escrow may restore what a value IS, but\n * never what a line is ALLOWED to do: `task.split` is forced to `holdout` on\n * every import regardless of what the document claims, and promoting an\n * imported trajectory to a trainable split is an explicit, greppable act\n * (`relabelImportedSplit`) rather than a property of the file. The document\n * keeps its claim — the claim just is not authority.\n *\n * Multi-agent shape differs on purpose. ATIF EMBEDS children in\n * `subagent_trajectories`; we keep a flat ledger with a normalized\n * `parent_rollout_id` edge. Export assembles the tree, import flattens it.\n * `session_id` is RUN-scoped in ATIF, so it carries `run_id` — the coordinate\n * that is shared by every invocation of one run — not `rollout_id`, which\n * identifies a single invocation and would split one run across session ids.\n *\n * ROUND-TRIPPING IS IDEMPOTENT: `import(export(import(export(x))))` is\n * byte-identical to `import(export(x))`. Import composes `provenance.gap` as a\n * de-duplicated ordered set rather than appending, and it emits every\n * `ChatMessage` with keys in the canonical schema order (role, content,\n * reasoning_content, tool_calls, tool_call_id, name, is_copied_context), so a\n * ledger hashed on serialized bytes sees no diff across further passes. The\n * FIRST import may re-order a producer's keys — that is the canonicalization.\n *\n * NOT building a Letta converter. Letta's trajectory-v1 is a strict subset of\n * what we need from ATIF here — no per-step or aggregate cost, no\n * multi-agent/subagent structure, no token-id or logprob channel — so a Letta\n * sink would carry less than this one and add a second format to keep\n * correct. Decision recorded in docs/rollout.md; do not re-litigate without a\n * concrete consumer that reads Letta and cannot read ATIF.\n */\n\nimport {\n assertRolloutLine,\n type ChatMessage,\n type ChatRole,\n type ChatToolCall,\n type GatedEvidence,\n ROLLOUT_CAPTURES,\n ROLLOUT_ROLES,\n ROLLOUT_SCHEMA,\n ROLLOUT_SPLITS,\n type RolloutArtifacts,\n type RolloutCapture,\n type RolloutCostBlock,\n type RolloutLine,\n type RolloutPolicy,\n type RolloutRole,\n type RolloutSplit,\n type RolloutStep,\n type RolloutTask,\n type ToolDef,\n} from '../schema'\n\nimport { isRecord } from '../../llm-client/json'\nconst ATIF_SCHEMA_VERSION = 'ATIF-v1.7'\n\n/** Gap note on every imported line — ATIF carries no verdict, so nothing is scored. */\nconst HARBOR_IMPORT_GAP = 'imported from Harbor ATIF; no verdict'\n\n/** Namespaced escrow key for everything ATIF does not model but we must not lose. */\nconst ESCROW = 'tangle'\n\n/**\n * Marks a step we synthesized purely to hold tool results that answered no\n * assistant turn IN THIS DOCUMENT. ATIF has no `tool` source, so such results\n * need a carrier step; the marker lets import drop the carrier instead of\n * inventing a turn.\n *\n * A carrier's results carry NO `source_call_id`. RFC 0001 rule 2 requires every\n * `source_call_id` to match a `tool_call_id` in the same step's `tool_calls`,\n * and a carrier declares no calls (a `system` step cannot legally make one), so\n * emitting the id there would produce an invalid document. The id is escrowed\n * instead and restored verbatim on import — the link survives without the\n * document lying about who made the call.\n */\nconst TOOL_RESULTS_ONLY = 'tool-results-only'\n\n// ---------------------------------------------------------------------------\n// ATIF-v1.7 wire types (RFC 0001). Optional fields are optional here too.\n// ---------------------------------------------------------------------------\n\nexport type HarborStepSource = 'system' | 'user' | 'agent'\n\nexport interface HarborImageSource {\n media_type: string\n path: string\n}\n\nexport interface HarborContentPart {\n type: 'text' | 'image'\n text?: string\n source?: HarborImageSource\n}\n\nexport interface HarborToolCall {\n tool_call_id: string\n function_name: string\n /** ATIF requires a decoded JSON object here, unlike our raw argument string. */\n arguments: Record<string, unknown>\n extra?: Record<string, unknown>\n}\n\nexport interface HarborSubagentTrajectoryRef {\n trajectory_id?: string\n trajectory_path?: string\n /** Informational only since v1.7 — never a resolution key. */\n session_id?: string\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservationResult {\n source_call_id?: string\n content?: string | HarborContentPart[]\n subagent_trajectory_ref?: HarborSubagentTrajectoryRef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservation {\n results: HarborObservationResult[]\n}\n\nexport interface HarborMetrics {\n prompt_tokens?: number\n completion_tokens?: number\n cached_tokens?: number\n cost_usd?: number\n prompt_token_ids?: number[]\n completion_token_ids?: number[]\n logprobs?: number[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborStep {\n /** Ordinal, sequential from 1. */\n step_id: number\n timestamp?: string\n source: HarborStepSource\n model_name?: string\n reasoning_effort?: string | number\n message: string | HarborContentPart[]\n reasoning_content?: string\n tool_calls?: HarborToolCall[]\n observation?: HarborObservation\n metrics?: HarborMetrics\n llm_call_count?: number\n is_copied_context?: boolean\n extra?: Record<string, unknown>\n}\n\nexport interface HarborAgent {\n name: string\n version: string\n model_name?: string\n /** OpenAI function-calling schema — byte-identical to our `ToolDef`. */\n tool_definitions?: ToolDef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborFinalMetrics {\n total_prompt_tokens?: number\n total_completion_tokens?: number\n total_cached_tokens?: number\n total_cost_usd?: number\n total_steps?: number\n extra?: Record<string, unknown>\n}\n\nexport interface HarborTrajectory {\n schema_version: string\n session_id?: string\n /** Required on embedded subagents; we always set it so lines stay joinable. */\n trajectory_id?: string\n agent: HarborAgent\n steps: HarborStep[]\n notes?: string\n final_metrics?: HarborFinalMetrics\n continued_trajectory_ref?: string\n subagent_trajectories?: HarborTrajectory[]\n extra?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined)\n\nconst asNumberOrNull = (v: unknown): number | null =>\n typeof v === 'number' && Number.isFinite(v) ? v : null\n\nconst asIntegerOrUndefined = (v: unknown): number | undefined =>\n Number.isInteger(v) ? (v as number) : undefined\n\nconst asNumberArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n ? (v as number[])\n : undefined\n\nconst asIntegerArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => Number.isInteger(n)) ? (v as number[]) : undefined\n\n/**\n * Builds a `ChatMessage` with keys in the schema's declaration order.\n *\n * Object key order is insertion order in JS, so a message assembled\n * conditionally field-by-field serializes differently depending on which\n * optional fields were present — which makes a byte-hashed ledger see a diff\n * across an import that changed nothing. One builder, one order, stable bytes.\n */\nfunction canonicalChatMessage(parts: {\n role: ChatRole\n content: string | null\n reasoning_content?: string\n tool_calls?: ChatToolCall[]\n tool_call_id?: string\n name?: string\n is_copied_context?: boolean\n}): ChatMessage {\n const message: ChatMessage = { role: parts.role, content: parts.content }\n if (parts.reasoning_content !== undefined) message.reasoning_content = parts.reasoning_content\n if (parts.tool_calls !== undefined) message.tool_calls = parts.tool_calls\n if (parts.tool_call_id !== undefined) message.tool_call_id = parts.tool_call_id\n if (parts.name !== undefined) message.name = parts.name\n if (parts.is_copied_context === true) message.is_copied_context = true\n return message\n}\n\n/** Reads the `extra.tangle` escrow, tolerating a foreign file that has none. */\nfunction escrowOf(extra: Record<string, unknown> | undefined): Record<string, unknown> | undefined {\n if (!isRecord(extra)) return undefined\n const value = extra[ESCROW]\n return isRecord(value) ? value : undefined\n}\n\nfunction escrowSection(\n escrow: Record<string, unknown> | undefined,\n key: string,\n): Record<string, unknown> | undefined {\n if (escrow === undefined) return undefined\n const value = escrow[key]\n return isRecord(value) ? value : undefined\n}\n\n// ---------------------------------------------------------------------------\n// Export: RolloutLine[] → ATIF trajectory tree\n// ---------------------------------------------------------------------------\n\nfunction toHarborToolCall(call: ChatToolCall): HarborToolCall {\n // ATIF requires `arguments` to be a JSON object; ours is the raw\n // JSON-encoded string the model emitted, and models really do emit\n // malformed ones. Keep the exact bytes in `extra` so import restores the\n // string verbatim instead of re-serializing a normalized parse.\n let parsed: Record<string, unknown> | undefined\n try {\n const decoded: unknown = JSON.parse(call.function.arguments)\n if (isRecord(decoded)) parsed = decoded\n } catch {\n parsed = undefined\n }\n return {\n tool_call_id: call.id,\n function_name: call.function.name,\n arguments: parsed ?? {},\n extra: { [ESCROW]: { arguments_raw: call.function.arguments } },\n }\n}\n\n/**\n * `linked` = this result is attached to the step that actually declared the\n * call, so `source_call_id` is legal (RFC 0001 rule 2). When it is not, the id\n * goes to escrow instead of onto the wire.\n */\nfunction toObservationResult(message: ChatMessage, linked: boolean): HarborObservationResult {\n const result: HarborObservationResult = {}\n if (linked && message.tool_call_id !== undefined) result.source_call_id = message.tool_call_id\n if (message.content !== null) result.content = message.content\n const escrow: Record<string, unknown> = {}\n if (!linked && message.tool_call_id !== undefined) escrow.source_call_id = message.tool_call_id\n if (message.name !== undefined) escrow.name = message.name\n // `content: null` on a tool turn is meaningful (a tool that returned\n // nothing) and is not the same as the empty string ATIF would round-trip it to.\n if (message.content === null) escrow.content_null = true\n if (message.reasoning_content !== undefined) escrow.reasoning_content = message.reasoning_content\n if (message.is_copied_context === true) escrow.is_copied_context = true\n if (Object.keys(escrow).length > 0) result.extra = { [ESCROW]: escrow }\n return result\n}\n\n/** True when `step` is the agent turn that declared `callId` — the rule-2 test. */\nfunction declaresCall(step: HarborStep, callId: string | undefined): boolean {\n if (callId === undefined) return false\n return step.tool_calls?.some((call) => call.tool_call_id === callId) === true\n}\n\n/**\n * Attaches the four RL fields lifted from ATIF onto the agent step the span\n * describes. They are ALSO escrowed with the whole span under `extra.tangle`,\n * on purpose: the escrow is how our own round-trip stays exact, and these\n * native fields are how a foreign consumer — which never reads our escrow —\n * gets the logprobs and token ids at all. A field carried only in the escrow is\n * not an interchange field.\n */\nfunction applySpanMetrics(step: HarborStep, span: RolloutStep | undefined): void {\n if (span === undefined) return\n if (span.llm_call_count !== undefined) step.llm_call_count = span.llm_call_count\n const metrics: HarborMetrics = {}\n if (span.prompt_token_ids !== undefined) metrics.prompt_token_ids = span.prompt_token_ids\n if (span.completion_token_ids !== undefined) {\n metrics.completion_token_ids = span.completion_token_ids\n }\n if (span.logprobs !== undefined) metrics.logprobs = span.logprobs\n if (Object.keys(metrics).length > 0) step.metrics = metrics\n}\n\n/**\n * Coalescing fold, not a 1:1 map: ATIF has no `tool` source, so a tool result\n * becomes an `observation.results[]` entry on the agent step THAT DECLARED ITS\n * `tool_call_id`.\n *\n * Linking by id, not by adjacency. Adjacency emitted invalid documents in three\n * shapes the RFC forbids — an assistant turn with no `tool_calls` swallowing the\n * results that followed it, a result whose id matched none of the preceding\n * step's calls, and an unanswered result riding a `system` step that carried a\n * `source_call_id` it could never declare. Attaching only to the step that owns\n * the id also preserves message order exactly: a result either joins the step\n * immediately before it or becomes its own carrier at its own position.\n *\n * `line.steps` span projections are matched to agent steps in order (k-th llm\n * span → k-th agent step) purely to fill ATIF's native per-step `metrics`;\n * extra spans on either side are simply not matched, never invented.\n */\nfunction messagesToSteps(line: RolloutLine): HarborStep[] {\n const steps: HarborStep[] = []\n const llmSpans = (line.steps ?? []).filter((span) => span.kind === 'llm')\n let nextSpan = 0\n for (const message of line.messages) {\n if (message.role === 'tool') {\n const previous = steps[steps.length - 1]\n if (previous !== undefined && declaresCall(previous, message.tool_call_id)) {\n if (previous.observation === undefined) previous.observation = { results: [] }\n previous.observation.results.push(toObservationResult(message, true))\n continue\n }\n // A tool result answering no assistant turn in this document (truncated or\n // reconstructed transcript). It still has to survive, so it rides a marked\n // carrier step whose observation states no call id.\n const carrier: HarborStep = {\n step_id: steps.length + 1,\n source: 'system',\n message: '',\n observation: { results: [toObservationResult(message, false)] },\n extra: { [ESCROW]: { synthetic: TOOL_RESULTS_ONLY } },\n }\n if (message.is_copied_context === true) carrier.is_copied_context = true\n steps.push(carrier)\n continue\n }\n const step: HarborStep = {\n step_id: steps.length + 1,\n source: message.role === 'assistant' ? 'agent' : message.role,\n message: message.content ?? '',\n }\n const escrow: Record<string, unknown> = {}\n if (message.content === null) escrow.content_null = true\n if (message.name !== undefined) escrow.name = message.name\n if (message.role === 'assistant') {\n if (line.policy.model !== null) step.model_name = line.policy.model\n if (message.reasoning_content !== undefined) {\n step.reasoning_content = message.reasoning_content\n }\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n step.tool_calls = message.tool_calls.map(toHarborToolCall)\n }\n applySpanMetrics(step, llmSpans[nextSpan])\n nextSpan += 1\n } else if (message.reasoning_content !== undefined) {\n // ATIF confines `reasoning_content` to agent steps; ours is not confined.\n escrow.reasoning_content = message.reasoning_content\n }\n // RFC 0001 rule 7: a copied-context turn was not authored by this agent, and\n // an SFT pipeline MUST exclude it. Native ATIF field, both directions.\n if (message.is_copied_context === true) step.is_copied_context = true\n if (Object.keys(escrow).length > 0) step.extra = { [ESCROW]: escrow }\n steps.push(step)\n }\n return steps\n}\n\nfunction finalMetricsOf(line: RolloutLine, stepCount: number): HarborFinalMetrics {\n const metrics: HarborFinalMetrics = {}\n if (line.cost.tokens_in !== null) metrics.total_prompt_tokens = line.cost.tokens_in\n if (line.cost.tokens_out !== null) metrics.total_completion_tokens = line.cost.tokens_out\n if (line.cost.cache_read !== null) metrics.total_cached_tokens = line.cost.cache_read\n // Omitted, never 0, when cost was not captured — a fake 0 is a lie about spend.\n if (line.cost.usd !== null) metrics.total_cost_usd = line.cost.usd\n metrics.total_steps = stepCount\n // ATIF has no aggregate field for these three; `reasoning_tokens` under\n // `extra` is the key the RFC's own worked example uses.\n const extra: Record<string, unknown> = {}\n if (line.cost.tokens_reasoning !== null) extra.reasoning_tokens = line.cost.tokens_reasoning\n if (line.cost.cache_write !== null) extra.cache_write_tokens = line.cost.cache_write\n if (line.cost.wall_s !== null) extra.wall_s = line.cost.wall_s\n if (line.cost.llm_call_count !== undefined && line.cost.llm_call_count !== null) {\n extra.llm_call_count = line.cost.llm_call_count\n }\n if (Object.keys(extra).length > 0) metrics.extra = extra\n return metrics\n}\n\nfunction notesOf(line: RolloutLine): string | undefined {\n const parts: string[] = []\n if (line.provenance.gap !== undefined) parts.push(line.provenance.gap)\n if (line.outcome.realness_gated === true) {\n // ATIF has no gate field. A third-party consumer that ignores `extra`\n // would otherwise see a gamed trajectory with nothing marking it, so the\n // flag is stated in prose as well. This export carries no reward at all,\n // so it is not a training-data door — but it is an audit record.\n parts.push('realness-gated: this run faked its success signal (anti-Goodhart gate fired)')\n }\n return parts.length > 0 ? parts.join(' | ') : undefined\n}\n\nfunction toTrajectoryNode(line: RolloutLine): HarborTrajectory {\n const steps = messagesToSteps(line)\n const trajectory: HarborTrajectory = {\n schema_version: ATIF_SCHEMA_VERSION,\n // RUN-scoped, per the spec — so it is `run_id`, the coordinate every\n // invocation of one run shares. `rollout_id` identifies a single\n // invocation: using it gave two roots of the same run different session\n // ids, and foreign tooling that groups by session_id would split the run.\n session_id: line.run_id,\n trajectory_id: line.rollout_id,\n agent: {\n // ATIF requires both; ours are nullable, so a null is substituted here\n // and restored on import from the escrowed policy — never guessed back.\n name: line.policy.harness ?? 'unknown',\n version: line.policy.harness_version ?? '0.0.0',\n ...(line.policy.model !== null ? { model_name: line.policy.model } : {}),\n ...(line.tool_defs.length > 0 ? { tool_definitions: line.tool_defs } : {}),\n },\n steps,\n final_metrics: finalMetricsOf(line, steps.length),\n extra: {\n [ESCROW]: {\n schema: line.schema,\n rollout_id: line.rollout_id,\n parent_rollout_id: line.parent_rollout_id,\n run_id: line.run_id,\n ...(line.experiment_id !== undefined ? { experiment_id: line.experiment_id } : {}),\n ...(line.candidate_id !== undefined ? { candidate_id: line.candidate_id } : {}),\n generation: line.generation,\n candidate_index: line.candidate_index,\n role: line.role,\n task: line.task,\n policy: line.policy,\n // Span projections overlap the same turns as `steps[]`; folding them\n // into ATIF steps would double-count the run, so they stay escrowed.\n ...(line.steps !== undefined ? { spans: line.steps } : {}),\n outcome: {\n // reward / reward_source / verdict are deliberately absent — see the\n // module header. Only the non-scalar outcome fields travel.\n metrics: line.outcome.metrics,\n is_completed: line.outcome.is_completed,\n is_truncated: line.outcome.is_truncated,\n error: line.outcome.error,\n ...(line.outcome.realness_gated !== undefined\n ? { realness_gated: line.outcome.realness_gated }\n : {}),\n },\n artifacts: line.artifacts,\n provenance: line.provenance,\n },\n },\n }\n const notes = notesOf(line)\n if (notes !== undefined) trajectory.notes = notes\n return trajectory\n}\n\ninterface Forest {\n roots: RolloutLine[]\n childrenOf: Map<string, RolloutLine[]>\n}\n\nfunction buildForest(lines: RolloutLine[]): Forest {\n const byId = new Map<string, RolloutLine>()\n for (const line of lines) {\n if (byId.has(line.rollout_id)) {\n throw new Error(`duplicate rollout_id in input: ${line.rollout_id}`)\n }\n byId.set(line.rollout_id, line)\n }\n const roots: RolloutLine[] = []\n const childrenOf = new Map<string, RolloutLine[]>()\n for (const line of lines) {\n const parent = line.parent_rollout_id\n // A parent outside this set is a root OF WHAT WE HAVE: the edge is kept in\n // escrow so a later import restores the dangling pointer instead of nulling it.\n if (parent === null || !byId.has(parent)) {\n roots.push(line)\n continue\n }\n const siblings = childrenOf.get(parent)\n if (siblings === undefined) childrenOf.set(parent, [line])\n else siblings.push(line)\n }\n // Every line has a parent inside the set: the edges form a cycle with no\n // root. Returning zero documents would drop the whole episode silently.\n if (lines.length > 0 && roots.length === 0) {\n throw new Error(\n `parent_rollout_id cycle: no root among ${lines.length} lines (${lines.map((l) => l.rollout_id).join(', ')})`,\n )\n }\n return { roots, childrenOf }\n}\n\nfunction assemble(line: RolloutLine, forest: Forest, onPath: Set<string>): HarborTrajectory {\n if (onPath.has(line.rollout_id)) {\n throw new Error(`parent_rollout_id cycle through rollout_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n const node = toTrajectoryNode(line)\n const children = forest.childrenOf.get(line.rollout_id)\n if (children !== undefined && children.length > 0) {\n node.subagent_trajectories = children.map((child) => assemble(child, forest, onPath))\n }\n onPath.delete(line.rollout_id)\n return node\n}\n\n/**\n * Assemble one episode's flat lines into a single ATIF trajectory tree,\n * linked by `parent_rollout_id`.\n *\n * Reward, verdict and split are NOT emitted (ATIF models none of them); the\n * split and the rest of the task coordinates survive only in `extra.tangle`.\n *\n * We deliberately do NOT synthesize an `observation.subagent_trajectory_ref`\n * pointing at each child: our ledger records WHICH invocation spawned a\n * worker, not which STEP did, and attaching the ref to a guessed step would\n * fabricate a causal claim. Children are embedded in `subagent_trajectories`\n * (each with the `trajectory_id` the spec requires) and the edge is stated in\n * the child's escrowed `parent_rollout_id`.\n *\n * Throws when the lines are not one tree — use `toHarborTrajectories` for a forest.\n */\nexport function toHarborTrajectory(lines: RolloutLine[]): HarborTrajectory {\n const trees = toHarborTrajectories(lines)\n if (trees.length === 0) throw new Error('toHarborTrajectory: no lines')\n if (trees.length > 1) {\n const ids = trees.map((t) => t.trajectory_id ?? '?').join(', ')\n throw new Error(\n `toHarborTrajectory: ${trees.length} roots (${ids}) — ATIF is one tree per document; use toHarborTrajectories`,\n )\n }\n return trees[0]!\n}\n\n/** Every independent tree in the input, one ATIF document each. */\nexport function toHarborTrajectories(lines: RolloutLine[]): HarborTrajectory[] {\n const forest = buildForest(lines)\n return forest.roots.map((root) => assemble(root, forest, new Set()))\n}\n\n// ---------------------------------------------------------------------------\n// Import: ATIF trajectory tree → RolloutLine[]\n// ---------------------------------------------------------------------------\n\nfunction contentToString(message: string | HarborContentPart[]): string {\n if (typeof message === 'string') return message\n return message\n .map((part) =>\n part.type === 'image'\n ? // Our chat content is text-only. Describing the image is honest about\n // what the source held; dropping it silently would not be.\n `[image ${part.source?.media_type ?? 'unknown'} ${part.source?.path ?? ''}]`.trim()\n : (part.text ?? ''),\n )\n .join('\\n')\n}\n\nfunction fromHarborToolCall(call: HarborToolCall): ChatToolCall {\n const raw = asString(escrowOf(call.extra)?.arguments_raw)\n return {\n id: call.tool_call_id,\n type: 'function',\n function: { name: call.function_name, arguments: raw ?? JSON.stringify(call.arguments ?? {}) },\n }\n}\n\nfunction fromObservationResult(\n result: HarborObservationResult,\n callId: string | undefined,\n): ChatMessage {\n const escrow = escrowOf(result.extra)\n return canonicalChatMessage({\n role: 'tool',\n content:\n escrow?.content_null === true\n ? null\n : result.content === undefined\n ? ''\n : contentToString(result.content),\n reasoning_content: asString(escrow?.reasoning_content),\n tool_call_id: callId,\n name: asString(escrow?.name),\n is_copied_context: escrow?.is_copied_context === true,\n })\n}\n\nfunction stepsToMessages(steps: HarborStep[]): ChatMessage[] {\n const messages: ChatMessage[] = []\n for (const step of steps) {\n const escrow = escrowOf(step.extra)\n const carrierOnly = escrow?.synthetic === TOOL_RESULTS_ONLY\n if (!carrierOnly) {\n messages.push(\n canonicalChatMessage({\n role: step.source === 'agent' ? 'assistant' : step.source,\n content: escrow?.content_null === true ? null : contentToString(step.message),\n reasoning_content: step.reasoning_content ?? asString(escrow?.reasoning_content),\n tool_calls:\n step.tool_calls !== undefined && step.tool_calls.length > 0\n ? step.tool_calls.map(fromHarborToolCall)\n : undefined,\n name: asString(escrow?.name),\n is_copied_context: step.is_copied_context === true,\n }),\n )\n }\n for (const result of step.observation?.results ?? []) {\n const resultEscrow = escrowOf(result.extra)\n const callId = result.source_call_id ?? asString(resultEscrow?.source_call_id)\n if (carrierOnly) {\n // Our own carrier: every result on it was a tool turn, and its call id\n // (if the transcript had one) is in escrow, not on the wire.\n messages.push(fromObservationResult(result, callId))\n continue\n }\n if (typeof callId === 'string') {\n messages.push(fromObservationResult(result, callId))\n continue\n }\n // ATIF allows a result from a non-tool-calling action. Our chat schema\n // requires `tool_call_id` on a tool turn, so inventing one would forge a\n // link; the text is preserved as a system observation instead.\n if (result.content !== undefined) {\n messages.push(\n canonicalChatMessage({ role: 'system', content: contentToString(result.content) }),\n )\n }\n }\n }\n return messages\n}\n\nfunction taskFrom(escrow: Record<string, unknown> | undefined, fallbackId: string): RolloutTask {\n const task = escrowSection(escrow, 'task')\n return {\n suite: asString(task?.suite) ?? 'harbor-atif-import',\n instance_id: asString(task?.instance_id) ?? fallbackId,\n // ALWAYS holdout — the escrowed claim is read for nothing here.\n //\n // `extra.tangle.task.split` is a namespaced key, not an authenticated one:\n // a hand-written or third-party document can set `split: 'search'` as\n // easily as our own exporter can, and honouring it made \"this file says so\"\n // sufficient to walk into a training export. Trainability is a decision\n // about a file, so it is made by an operator through\n // `relabelImportedSplit`, never by the file about itself. The claim is not\n // destroyed — it stays readable in the source document.\n split: 'holdout',\n seed: asNumberOrNull(task?.seed),\n rep: asIntegerOrUndefined(task?.rep) ?? 0,\n }\n}\n\nfunction policyFrom(\n escrow: Record<string, unknown> | undefined,\n agent: HarborAgent,\n): RolloutPolicy {\n const escrowed = escrowSection(escrow, 'policy')\n if (escrowed !== undefined) {\n // Our own export: restore verbatim, including the nulls ATIF forced us to\n // substitute placeholders for in `agent.name` / `agent.version`.\n return {\n harness: asString(escrowed.harness) ?? null,\n harness_version: asString(escrowed.harness_version) ?? null,\n model: asString(escrowed.model) ?? null,\n provider: asString(escrowed.provider) ?? null,\n profile_commit: asString(escrowed.profile_commit) ?? null,\n ...(escrowed.prompt_hash !== undefined\n ? { prompt_hash: asString(escrowed.prompt_hash) ?? null }\n : {}),\n ...(escrowed.config_hash !== undefined\n ? { config_hash: asString(escrowed.config_hash) ?? null }\n : {}),\n ...(escrowed.agent_profile_cell_id !== undefined\n ? { agent_profile_cell_id: asString(escrowed.agent_profile_cell_id) ?? null }\n : {}),\n sampling: isRecord(escrowed.sampling) ? escrowed.sampling : null,\n }\n }\n return {\n harness: agent.name,\n harness_version: agent.version,\n model: agent.model_name ?? null,\n provider: null,\n profile_commit: null,\n sampling: null,\n }\n}\n\nfunction artifactsFrom(escrow: Record<string, unknown> | undefined): RolloutArtifacts {\n const artifacts = escrowSection(escrow, 'artifacts')\n return {\n patch_path: asString(artifacts?.patch_path) ?? null,\n run_dir: asString(artifacts?.run_dir) ?? null,\n transcript_ref: asString(artifacts?.transcript_ref) ?? null,\n }\n}\n\nfunction costFrom(final: HarborFinalMetrics | undefined): RolloutCostBlock {\n const rawExtra = final?.extra\n const extra = isRecord(rawExtra) ? rawExtra : undefined\n const calls = asIntegerOrUndefined(extra?.llm_call_count)\n return {\n usd: asNumberOrNull(final?.total_cost_usd),\n tokens_in: asNumberOrNull(final?.total_prompt_tokens),\n tokens_out: asNumberOrNull(final?.total_completion_tokens),\n tokens_reasoning: asNumberOrNull(extra?.reasoning_tokens),\n cache_read: asNumberOrNull(final?.total_cached_tokens),\n cache_write: asNumberOrNull(extra?.cache_write_tokens),\n wall_s: asNumberOrNull(extra?.wall_s),\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n }\n}\n\n/**\n * Recovers span projections from ATIF's NATIVE per-step channel, for documents\n * with no `extra.tangle.spans` escrow — i.e. everything a foreign producer\n * writes. Without this the logprobs and token ids a Harbor-native trainer\n * records would be read, validated, and then dropped on the floor.\n *\n * Only steps that actually carry one of the four fields produce a span: an\n * agent step with no metrics means \"not captured\", and inventing an empty span\n * for it would claim the run had a shape we did not observe.\n */\nfunction spansFromSteps(steps: HarborStep[]): RolloutStep[] {\n const spans: RolloutStep[] = []\n for (const step of steps) {\n if (step.source !== 'agent') continue\n const calls = asIntegerOrUndefined(step.llm_call_count)\n const promptIds = asIntegerArray(step.metrics?.prompt_token_ids)\n const completionIds = asIntegerArray(step.metrics?.completion_token_ids)\n const logprobs = asNumberArray(step.metrics?.logprobs)\n if (\n calls === undefined &&\n promptIds === undefined &&\n completionIds === undefined &&\n logprobs === undefined\n ) {\n continue\n }\n spans.push({\n kind: 'llm',\n name: step.model_name ?? 'chat',\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n ...(promptIds !== undefined ? { prompt_token_ids: promptIds } : {}),\n ...(completionIds !== undefined ? { completion_token_ids: completionIds } : {}),\n ...(logprobs !== undefined ? { logprobs } : {}),\n })\n }\n return spans\n}\n\n/**\n * Composes `provenance.gap` as an ordered SET of reasons.\n *\n * Appending made the note accrete on every pass (\"…no verdict | …no verdict\"),\n * which both grows without bound and breaks byte-level idempotency for a ledger\n * hashed on its serialized lines.\n */\nfunction composeGap(escrowedGap: string | undefined, added: readonly string[]): string {\n const parts: string[] = []\n const seen = new Set<string>()\n for (const raw of [...(escrowedGap?.split(' | ') ?? []), ...added]) {\n const reason = raw.trim()\n if (reason.length === 0 || seen.has(reason)) continue\n seen.add(reason)\n parts.push(reason)\n }\n return parts.join(' | ')\n}\n\nexport interface FromHarborOptions {\n /** Injected clock for deterministic output when the source carries no capture time. */\n now?: () => Date\n}\n\nfunction nodeToLine(\n trajectory: HarborTrajectory,\n parentId: string | null,\n capturedAt: string,\n): RolloutLine {\n const escrow = escrowOf(trajectory.extra)\n const rolloutId =\n asString(escrow?.rollout_id) ?? trajectory.trajectory_id ?? trajectory.session_id\n if (rolloutId === undefined || rolloutId.length === 0) {\n throw new Error(\n 'fromHarborTrajectory: trajectory has no trajectory_id or session_id — cannot mint a joinable rollout_id without inventing one',\n )\n }\n const outcome = escrowSection(escrow, 'outcome')\n const provenance = escrowSection(escrow, 'provenance')\n const capture = provenance?.capture\n const escrowedGap = asString(provenance?.gap)\n const role = escrow?.role\n const escrowedSpans = escrow?.spans\n // The escrow wins when it exists (our own export: exact, including an empty\n // array, which claims \"captured, none\" rather than \"not captured\"), and the\n // native per-step channel is the fallback (a foreign export: still signal).\n const nativeSpans = spansFromSteps(trajectory.steps)\n const spans: RolloutStep[] | undefined = Array.isArray(escrowedSpans)\n ? (escrowedSpans as RolloutStep[])\n : nativeSpans.length > 0\n ? nativeSpans\n : undefined\n const messages = stepsToMessages(trajectory.steps)\n const line: RolloutLine = {\n schema: ROLLOUT_SCHEMA,\n rollout_id: rolloutId,\n // The tree edge wins for embedded children; for a root, the escrowed\n // pointer may reference a line outside this document and is preserved.\n parent_rollout_id: parentId ?? asString(escrow?.parent_rollout_id) ?? null,\n run_id: asString(escrow?.run_id) ?? trajectory.session_id ?? rolloutId,\n // Required keys on the wire (0.127.0): a foreign document that never\n // stated them imports as explicit `null`, not as an absent field.\n experiment_id: asString(escrow?.experiment_id) ?? null,\n candidate_id: asString(escrow?.candidate_id) ?? null,\n generation: asIntegerOrUndefined(escrow?.generation) ?? null,\n candidate_index: asIntegerOrUndefined(escrow?.candidate_index) ?? null,\n role: ROLLOUT_ROLES.includes(role as RolloutRole) ? (role as RolloutRole) : 'agent',\n task: taskFrom(escrow, rolloutId),\n policy: policyFrom(escrow, trajectory.agent),\n messages,\n tool_defs: trajectory.agent.tool_definitions ?? [],\n ...(spans !== undefined ? { steps: spans } : {}),\n outcome: {\n // ATIF carries no label. Null is the labeled gap; a 0 here would be a\n // fabricated failure and a 1 a fabricated success.\n reward: null,\n reward_source: null,\n verdict: null,\n metrics: isRecord(outcome?.metrics) ? outcome.metrics : {},\n is_completed: typeof outcome?.is_completed === 'boolean' ? outcome.is_completed : true,\n is_truncated:\n typeof outcome?.is_truncated === 'boolean'\n ? outcome.is_truncated\n : trajectory.continued_trajectory_ref !== undefined,\n error: asString(outcome?.error) ?? null,\n // The anti-Goodhart flag is restored when the source document stated\n // it; the wire schema requires the field, so a document that never did\n // imports as `false`. That is safe here because the reward is already\n // forced to `null` (not trainable) and `realness_screened` stays\n // absent = unknown rather than claiming a screen ran.\n realness_gated: outcome?.realness_gated === true,\n },\n cost: costFrom(trajectory.final_metrics),\n artifacts: artifactsFrom(escrow),\n provenance: {\n captured_at: asString(provenance?.captured_at) ?? capturedAt,\n capture: ROLLOUT_CAPTURES.includes(capture as RolloutCapture)\n ? (capture as RolloutCapture)\n : 'backfill',\n gap: composeGap(escrowedGap, [HARBOR_IMPORT_GAP]),\n // Restored for the same reason `realness_gated` is, and with the opposite\n // risk profile from the reward: this is the gated run's own measurement\n // bag, moved off `outcome` by `gateGamedOutcome` so no exporter reads it\n // as training input. Dropping it here would silently destroy the audit\n // trail that says WHY the run was flagged and what it claimed, on the one\n // population an auditor most wants to inspect. It cannot be fail-open —\n // nothing projects `provenance` into a training row.\n ...(isRecord(provenance?.gated_evidence)\n ? { gated_evidence: provenance.gated_evidence as GatedEvidence }\n : {}),\n },\n }\n assertRolloutLine(line, `rollout line imported from ATIF trajectory ${rolloutId}`)\n return line\n}\n\n/**\n * Flatten an ATIF trajectory tree back into `tangle.rollout.v1` lines, parent\n * first, each child carrying `parent_rollout_id`.\n *\n * Every line comes back UNLABELED: `reward`, `reward_source` and `verdict` are\n * null and `provenance.gap` says why. ATIF models no verdict, so scoring an\n * imported trajectory is a judge's job, not this function's. Every line lands\n * on `holdout` whatever the document claims — see `relabelImportedSplit`.\n */\nexport function fromHarborTrajectory(\n trajectory: HarborTrajectory,\n options: FromHarborOptions = {},\n): RolloutLine[] {\n const capturedAt = (options.now?.() ?? new Date()).toISOString()\n const lines: RolloutLine[] = []\n const walk = (node: HarborTrajectory, parentId: string | null, onPath: Set<string>): void => {\n const line = nodeToLine(node, parentId, capturedAt)\n if (onPath.has(line.rollout_id)) {\n throw new Error(`subagent_trajectories cycle through trajectory_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n lines.push(line)\n for (const child of node.subagent_trajectories ?? []) {\n walk(child, line.rollout_id, onPath)\n }\n onPath.delete(line.rollout_id)\n }\n walk(trajectory, null, new Set())\n return lines\n}\n\n/**\n * THE explicit door out of `holdout` for imported lines.\n *\n * Import forces `holdout` because a document's own claim about its split is not\n * evidence — anyone can write `extra.tangle.task.split`. Promoting a file to a\n * trainable split is an operator's decision about provenance they verified, so\n * it is a separate, greppable call: `grep relabelImportedSplit` enumerates\n * every place foreign data was declared trainable, which is exactly the audit\n * the trusted-escrow version made impossible.\n *\n * Returns plain `RolloutLine`s. They still have to pass `assertMinted` (and its\n * anti-Goodhart check) to reach an exporter — re-labeling a split is not\n * minting a reward.\n */\nexport function relabelImportedSplit(\n lines: readonly RolloutLine[],\n split: RolloutSplit,\n): RolloutLine[] {\n if (!ROLLOUT_SPLITS.includes(split)) {\n throw new Error(`relabelImportedSplit: unknown split ${String(split)}`)\n }\n return lines.map((line) => ({ ...line, task: { ...line.task, split } }))\n}\n","/**\n * Claude Code project transcripts (~/.claude/projects/<cwd-slug>/<sessionId>.jsonl) as canonical\n * chat-with-tools messages plus per-session token usage.\n *\n * The transcript is read by @tangle-network/harness-sessions, the one reader of harness sessions\n * shared with Discovery, agent-record, traces and the blog: one model call per API response\n * (`message.id`, its usage counted once), the served model from the response, tool calls with\n * their results. This module only projects that session. Sidechain lines (subagent threads in the\n * main file) are separate invocations and are excluded unless `includeSidechain` asks for a\n * subagent's own transcript.\n */\n\nimport { readdir } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport {\n claudeCodeReader,\n claudeCodeRefForFile,\n type HarnessSession,\n readSessionInput,\n toChatMessages,\n} from '@tangle-network/harness-sessions'\nimport type { ChatMessage } from '../schema'\n\nexport const DEFAULT_CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects')\n\n/** Claude Code's project-directory slug for a working directory. */\nfunction claudeProjectSlug(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9-]/g, '-')\n}\n\nexport interface ClaudeTranscriptRef {\n sessionId: string\n path: string\n}\n\n/** Transcript files recorded for sessions launched from `cwd`. */\nexport async function findClaudeTranscripts(\n cwd: string,\n projectsDir: string = DEFAULT_CLAUDE_PROJECTS_DIR,\n): Promise<ClaudeTranscriptRef[]> {\n const dir = join(projectsDir, claudeProjectSlug(cwd))\n const names = await readdir(dir).catch(() => [])\n return names\n .filter((n) => n.endsWith('.jsonl'))\n .sort()\n .map((n) => ({ sessionId: n.replace(/\\.jsonl$/, ''), path: join(dir, n) }))\n}\n\nexport interface ClaudeUsageTotals {\n tokensIn: number | null\n tokensOut: number | null\n cacheRead: number | null\n cacheWrite: number | null\n}\n\nexport interface ClaudeTranscript {\n messages: ChatMessage[]\n usage: ClaudeUsageTotals\n /** Timestamp of the first conversation record; null = empty transcript. */\n startedAt: string | null\n endedAt: string | null\n /** The model that answered the last response (never Claude Code's `<synthetic>` error turn). */\n model: string | null\n /** Every parse or usage gap retained beside this semantic projection. */\n gaps: string[]\n}\n\nexport interface ReadClaudeTranscriptOptions {\n /**\n * Read a subagent's own transcript (`<session>/subagents/agent-<id>.jsonl`), whose records are\n * sidechain end to end, instead of skipping sidechain records.\n */\n readonly includeSidechain?: boolean\n}\n\nconst USAGE_FIELDS = [\n ['tokensIn', 'input'],\n ['tokensOut', 'output'],\n ['cacheRead', 'cacheRead'],\n ['cacheWrite', 'cacheWrite'],\n] as const\n\n/**\n * The messages+usage projection of a normalized session. A usage field is null when any answered\n * model call did not report it, so a partial sum is never mistaken for the session's usage.\n */\nfunction transcriptFromSession(session: HarnessSession): ClaudeTranscript {\n const gaps = session.integrity.gaps.filter((gap) =>\n /is not a JSON record|still being written/u.test(gap),\n )\n const answered = session.modelCalls.filter((call) => call.error === null)\n const usage: ClaudeUsageTotals = {\n tokensIn: null,\n tokensOut: null,\n cacheRead: null,\n cacheWrite: null,\n }\n if (answered.length > 0) {\n for (const [target, field] of USAGE_FIELDS) {\n let total: number | null = 0\n for (const call of answered) {\n const value = call.usage?.[field] ?? null\n if (value === null) {\n total = null\n gaps.push(`model call ${call.id}: ${field} usage unavailable`)\n break\n }\n total += value\n }\n usage[target] = total\n }\n }\n const model =\n [...answered].reverse().find((call) => call.servedModel !== null)?.servedModel ?? null\n return {\n messages: toChatMessages(session),\n usage,\n startedAt: session.startedAt,\n endedAt: session.endedAt,\n model,\n gaps,\n }\n}\n\n/** Read one transcript file. */\nexport async function readClaudeTranscript(\n path: string,\n options: ReadClaudeTranscriptOptions = {},\n): Promise<ClaudeTranscript> {\n const session = await claudeCodeReader.read(\n claudeCodeRefForFile(path, options.includeSidechain === true ? 'parent' : null),\n )\n return transcriptFromSession(session)\n}\n\n/** Parse retained JSONL text without another file or store; source gaps remain explicit. */\nexport function parseClaudeTranscript(\n raw: string,\n options: ReadClaudeTranscriptOptions = {},\n): ClaudeTranscript {\n const session = readSessionInput(\n 'claude-code',\n { text: raw },\n {\n parentNativeSessionId: options.includeSidechain === true ? 'parent' : null,\n label: 'retained transcript',\n },\n )\n return transcriptFromSession(session)\n}\n","/**\n * Codex rollout JSONL through the shared native-session reader. This module\n * projects its result onto rollout messages; it never parses native records,\n * discovers stores, judges an outcome, or makes an imported capture trainable.\n */\nimport {\n codexReader,\n codexRefForFile,\n type HarnessSession,\n type ReadOptions,\n readSessionInput,\n type SessionInputInit,\n toChatMessages,\n} from '@tangle-network/harness-sessions'\nimport type { ChatMessage } from '../schema'\n\n/** Normalized source evidence, with the existing canonical message projection. */\nexport type CodexRollout = Pick<\n HarnessSession,\n | 'nativeSessionId'\n | 'parentNativeSessionId'\n | 'startedAt'\n | 'endedAt'\n | 'usage'\n | 'ending'\n | 'integrity'\n | 'modelSource'\n> & {\n messages: ChatMessage[]\n /** Null when only turn_context names a model; that is configuration, not a response. */\n model: string | null\n requestedModel: string | null\n}\n\nfunction rolloutFromSession(session: HarnessSession): CodexRollout {\n const answered = session.modelCalls.filter((call) => call.error === null)\n const trustedModel =\n session.modelSource === 'provider-response' || session.modelSource === 'session-record'\n return {\n nativeSessionId: session.nativeSessionId,\n parentNativeSessionId: session.parentNativeSessionId,\n messages: toChatMessages(session),\n usage: session.usage,\n startedAt: session.startedAt,\n endedAt: session.endedAt,\n model: trustedModel\n ? ([...answered].reverse().find((call) => call.servedModel !== null)?.servedModel ?? null)\n : null,\n requestedModel:\n [...session.modelCalls].reverse().find((call) => call.requestedModel !== null)\n ?.requestedModel ?? null,\n modelSource: session.modelSource,\n ending: session.ending,\n integrity: session.integrity,\n }\n}\n\n/** Read one already-resolved native file; strict/recover behavior belongs to the SDK. */\nexport async function readCodexRollout(\n path: string,\n options: ReadOptions = {},\n): Promise<CodexRollout> {\n return rolloutFromSession(await codexReader.read(codexRefForFile(path), options))\n}\n\n/** Parse retained text through the same SDK fold, retaining source hashes and gaps. */\nexport function parseCodexRollout(\n raw: string,\n source: SessionInputInit = {},\n options: Pick<ReadOptions, 'corruption'> = {},\n): CodexRollout {\n return rolloutFromSession(readSessionInput('codex', { text: raw }, source, options))\n}\n","/**\n * OpenCode's SQLite store (~/.local/share/opencode/opencode.db) as canonical chat-with-tools\n * messages, through @tangle-network/harness-sessions: the one reader of harness sessions shared\n * with Discovery, agent-record, traces and the blog. The store is read from a private copy, never\n * in place, and a tool part that errored or never finished is read as what it is rather than\n * refused.\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport {\n type HarnessSession,\n opencodeReader,\n opencodeSessionsInStore,\n toChatMessages,\n} from '@tangle-network/harness-sessions'\nimport type { ChatMessage } from '../schema'\n\nexport const DEFAULT_OPENCODE_DB = join(homedir(), '.local', 'share', 'opencode', 'opencode.db')\n\n\n\n/** One session, normalized. */\nasync function readOpencodeSession(\n sessionId: string,\n db: string = DEFAULT_OPENCODE_DB,\n): Promise<HarnessSession> {\n const [ref] = await opencodeSessionsInStore(db, null, { nativeSessionId: sessionId })\n if (ref === undefined) throw new Error(`OpenCode session ${sessionId} is not in ${db}`)\n return opencodeReader.read(ref)\n}\n\n/** One session's canonical messages: each model step, then the results of its tool calls. */\nexport async function readOpencodeSessionMessages(\n sessionId: string,\n db: string = DEFAULT_OPENCODE_DB,\n): Promise<ChatMessage[]> {\n return toChatMessages(await readOpencodeSession(sessionId, db))\n}\n","/** Tinker RL Datum projection of the canonical rollout waist; no client or training loop. */\nimport { assessShareSafety, shareAllowed } from '../trace/redact'\nimport { isSplitEligible, type TrainingExportOptions } from './exporters'\nimport { defaultRolloutScrubber } from './release/scrub'\nimport { assertMinted, assertRewardGate, type MintedRolloutLine, type RolloutStep } from './schema'\n\n/** JSON wire projection of Tinker's text-only Datum; the consumer constructs SDK objects. */\nexport interface TinkerDatum {\n model_input: { chunks: Array<{ type: 'encoded_text'; tokens: number[] }> }\n loss_fn_inputs: {\n target_tokens: { data: number[]; dtype: 'int64'; shape: [number] }\n logprobs: { data: number[]; dtype: 'float32'; shape: [number] }\n advantages: { data: number[]; dtype: 'float32'; shape: [number] }\n }\n}\n\nexport interface TinkerDatumRow {\n /** Only this object goes to the Tinker SDK. Attribution stays with the caller. */\n datum: TinkerDatum\n rollout_id: string\n run_id: string\n instance_id: string\n step_index: number\n reward: number\n realness_gated: false\n realness_screened: boolean | null\n}\n\nexport interface TinkerExportOptions\n extends Pick<TrainingExportOptions, 'allowHeldOutTrainingData'> {\n /** Exact model identity of the captured tokenizer/sampling policy. */\n model: string\n /** Offline decoder for that model. Never re-tokenize or fabricate missing sampling data. */\n decodeTokens: (tokens: readonly number[]) => string\n /** Caller owns group baselines; a reward is not silently treated as an advantage. */\n advantageOf: (line: MintedRolloutLine, stepIndex: number) => number\n}\n\nfunction safeText(text: string, context: string): void {\n // Scrubbing text while retaining its original token ids would transmit the very bytes removed.\n if (\n defaultRolloutScrubber(text) !== text ||\n !shareAllowed(assessShareSafety(text, { profile: 'share' }))\n ) {\n throw new Error(`Tinker export: ${context} needs scrubbing; recapture approved token data`)\n }\n}\n\nfunction tokenIds(tokens: number[] | undefined, context: string): number[] {\n if (!tokens?.length || tokens.some((id) => !Number.isSafeInteger(id) || id < 0)) {\n throw new Error(`Tinker export: ${context} requires captured nonempty token ids`)\n }\n return [...tokens]\n}\n\nfunction projectStep(\n step: RolloutStep,\n line: MintedRolloutLine,\n stepIndex: number,\n options: TinkerExportOptions,\n): TinkerDatumRow {\n if (step.llm_call_count !== 1) {\n throw new Error(\n `Tinker export: ${line.rollout_id} step ${stepIndex} must name one captured model call`,\n )\n }\n const prompt = tokenIds(step.prompt_token_ids, 'prompt')\n const completion = tokenIds(step.completion_token_ids, 'completion')\n const logprobs = step.logprobs === undefined ? undefined : [...step.logprobs]\n if (\n !logprobs ||\n logprobs.length !== completion.length ||\n logprobs.some((p) => !Number.isFinite(Math.fround(p)) || p > 0)\n ) {\n throw new Error(\n `Tinker export: ${line.rollout_id} step ${stepIndex} needs aligned sampling logprobs`,\n )\n }\n safeText(options.decodeTokens(prompt), 'decoded prompt')\n safeText(options.decodeTokens(completion), 'decoded completion')\n const advantage = options.advantageOf(line, stepIndex)\n if (\n typeof advantage !== 'number' ||\n !Number.isFinite(advantage) ||\n !Number.isFinite(Math.fround(advantage))\n ) {\n throw new Error('Tinker export: advantage must be a finite number that fits float32')\n }\n const full = [...prompt, ...completion]\n safeText(options.decodeTokens(full), 'decoded sequence')\n const prefix = Array<number>(prompt.length - 1).fill(0)\n const length = full.length - 1\n return {\n datum: {\n model_input: { chunks: [{ type: 'encoded_text', tokens: full.slice(0, -1) }] },\n loss_fn_inputs: {\n target_tokens: { data: full.slice(1), dtype: 'int64', shape: [length] },\n logprobs: { data: [...prefix, ...logprobs], dtype: 'float32', shape: [length] },\n advantages: {\n data: [...prefix, ...completion.map(() => advantage)],\n dtype: 'float32',\n shape: [length],\n },\n },\n },\n rollout_id: line.rollout_id,\n run_id: line.run_id,\n instance_id: line.task.instance_id,\n step_index: stepIndex,\n reward: line.outcome.reward!,\n realness_gated: false,\n realness_screened: line.outcome.realness_screened ?? null,\n }\n}\n\n/**\n * Project known-reward completed search rollouts, including honest zero/negative rewards.\n * Unknown rewards, gated/lossy/incomplete runs and ineligible splits do not become training data.\n * Missing capture on an otherwise eligible model call refuses the batch, never invents tokens.\n * The caller retains the canonical ledger and owns Tinker sampling/forward_backward/optim_step.\n */\nexport function toTinkerDatumRows(\n lines: readonly MintedRolloutLine[],\n options: TinkerExportOptions,\n): TinkerDatumRow[] {\n if (!options.model) throw new Error('Tinker export: captured model identity is required')\n const rows: TinkerDatumRow[] = []\n const identities = new Set<string>()\n for (const supplied of lines) {\n const line = assertMinted(supplied, 'Tinker rollout')\n assertRewardGate(line, 'Tinker export')\n if (identities.has(line.rollout_id))\n throw new Error(`Tinker export: duplicate rollout ${line.rollout_id}`)\n identities.add(line.rollout_id)\n if (\n !isSplitEligible(line, { allowHeldOutTrainingData: options.allowHeldOutTrainingData }) ||\n line.outcome.reward === null ||\n line.outcome.realness_gated ||\n !line.outcome.is_completed ||\n line.outcome.is_truncated ||\n line.outcome.error !== null ||\n line.provenance.lossy_projection === true\n )\n continue\n if (!Number.isFinite(line.outcome.reward))\n throw new Error('Tinker export: reward must be finite')\n if (line.policy.model !== options.model)\n throw new Error('Tinker export: captured model identity differs')\n if (line.messages.some((message) => message.is_copied_context)) {\n throw new Error('Tinker export: copied context has no captured token mask')\n }\n const steps = line.steps\n if (!steps?.some((step) => step.kind === 'llm'))\n throw new Error('Tinker export: no captured model steps')\n safeText(\n JSON.stringify({ messages: line.messages, steps, tool_defs: line.tool_defs }),\n 'rollout content',\n )\n for (const [index, step] of steps.entries()) {\n if (step.kind === 'llm') rows.push(projectStep(step, line, index, options))\n }\n }\n return rows\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rollout-DWl3Gg6A.js","names":[],"sources":["../src/rollout/harbor-task.ts","../src/rollout/interchange/harbor.ts","../src/rollout/readers/claude-jsonl.ts","../src/rollout/readers/codex-rollout.ts","../src/rollout/readers/opencode-sqlite.ts","../src/rollout/tinker.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\nimport {\n link,\n lstat,\n mkdir,\n readdir,\n readFile,\n realpath,\n unlink,\n writeFile,\n} from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\n\nimport { assertCodeSurfaceIdentity } from '../campaign/surface-identity'\nimport type { CodeSurface } from '../campaign/types'\nimport { type CompletionVerdict, completionVerdict } from '../completion-verifier'\nimport { canonicalString } from '../ledger-core/canonical'\nimport { deepFreezeCanonicalJson } from '../ledger-core/deep-freeze'\nimport { assertMinted, type MintedRolloutLine } from './schema'\n\n/** Existing completion checks required to admit a verified episode as a runnable task. */\nexport const HARBOR_TASK_CHECKS = [\n 'base-bundle',\n 'acceptance',\n 'production-delta',\n 'dangling-references',\n 'merge-followup',\n] as const\n\nexport interface HarborTaskFile {\n /** Relative path in the published task. */\n readonly path: string\n /** Actual staged path; task.toml is not published until verification succeeds. */\n readonly stagedPath: string\n readonly sha256: string\n readonly byteLength: number\n}\n\nexport interface HarborTaskVerification {\n /** Digest binding this episode, immutable source identity, merge and every task file. */\n readonly taskId: string\n readonly rolloutId: string\n readonly episodeSha256: string\n readonly task: MintedRolloutLine['task']\n readonly source: Omit<CodeSurface, 'worktreeRef' | 'summary' | 'baseRef'>\n readonly mergeCommit: string\n readonly files: readonly HarborTaskFile[]\n}\n\nexport interface WriteHarborTaskOptions {\n /** Fresh task directory, normally <dataset>/tasks/<task>. Existing paths are refused. */\n readonly directory: string\n readonly episode: MintedRolloutLine\n readonly surface: CodeSurface\n readonly mergeCommit: string\n /** Harbor's org/name task name. */\n readonly name: string\n readonly instruction: string\n /** Caller image with Git/dependencies and a configured user able to clone into /workspace. */\n readonly image: string\n /** Git bundle containing the base and its ancestors only, never the answer/head/merge. */\n readonly baseBundle: Uint8Array\n readonly commands: {\n readonly acceptance: string\n readonly productionDelta: string\n readonly danglingReferences: string\n }\n readonly agentTimeoutSec: number\n readonly verifierTimeoutSec: number\n /**\n * Trusted caller execution boundary. Inspect the actual staged bundle and file hashes.\n * base-bundle proves exact base/tree, base-only closure and no answer material; the\n * three verifier checks prove the supplied commands actually passed on this candidate\n * (strict production-line decrease, zero dangling refs); merge-followup proves this\n * candidate merged with base=merge^1 and a closed, explicitly checked no-fix-forward\n * followup window. Every check must cite receipts bound to taskId, not a title/keyword.\n * Unknown, absent, open followup and provider eligibility are not affirmative evidence.\n */\n readonly verify: (\n request: HarborTaskVerification,\n signal?: AbortSignal,\n ) => Promise<CompletionVerdict>\n readonly signal?: AbortSignal\n}\n\nconst digest = (bytes: Uint8Array | string): string =>\n `sha256:${createHash('sha256').update(bytes).digest('hex')}`\n\nfunction admitted(verdict: CompletionVerdict, taskId: string): void {\n if (verdict.taskId !== taskId) throw new Error('Harbor task verification identity mismatch')\n if (!Array.isArray(verdict.requirements))\n throw new Error('Harbor task requires completion checks')\n for (const row of verdict.requirements) {\n if (\n !row ||\n typeof row.reqId !== 'string' ||\n !row.reqId.trim() ||\n row.correct !== true ||\n row.structurallyPresent !== true ||\n row.satisfied !== true ||\n row.unmeasured !== undefined ||\n !Array.isArray(row.evidence) ||\n !row.evidence.some((value) => typeof value === 'string' && value.trim().length > 0)\n ) {\n throw new Error(`Harbor task requires measured passing ${row?.reqId ?? 'invalid'} evidence`)\n }\n }\n for (const id of HARBOR_TASK_CHECKS) {\n if (verdict.requirements.filter((row) => row.reqId === id).length !== 1) {\n throw new Error(`Harbor task requires exactly one ${id} check`)\n }\n }\n const derived = completionVerdict({ taskId, requirements: verdict.requirements })\n if (\n derived.fullyComplete !== true ||\n verdict.fullyComplete !== true ||\n verdict.valid !== true ||\n verdict.score !== 1 ||\n verdict.completionRate !== 1 ||\n verdict.unmeasuredCount !== 0\n ) {\n throw new Error('Harbor task verification is incomplete')\n }\n}\n\n/**\n * Write a Harbor directory from an admitted canonical episode, without executing it.\n * Failed admission leaves diagnostic files but no task.toml, so the directory is not\n * loadable as a task. The caller owns execution, receipt truth and artifact retention.\n */\nexport async function writeHarborTask(options: WriteHarborTaskOptions): Promise<string> {\n // Capture inputs before the first await; the callback cannot retarget caller-owned data.\n const episode = assertMinted(JSON.parse(canonicalString(options.episode)), 'Harbor task episode')\n const surface = JSON.parse(canonicalString(options.surface)) as CodeSurface\n assertCodeSurfaceIdentity(surface)\n const { kind, baseCommit, baseTree, candidateCommit, candidateTree, patch } = surface\n const source = { kind, baseCommit, baseTree, candidateCommit, candidateTree, patch }\n const {\n directory: inputDirectory,\n name,\n instruction,\n image,\n mergeCommit,\n agentTimeoutSec,\n verifierTimeoutSec,\n verify,\n signal,\n } = options\n const commands = { ...options.commands }\n const bundle = Uint8Array.from(options.baseBundle)\n if (\n episode.outcome.reward !== 1 ||\n !episode.outcome.is_completed ||\n episode.outcome.is_truncated ||\n episode.outcome.error !== null ||\n episode.outcome.realness_screened !== true ||\n episode.outcome.realness_gated === true\n ) {\n throw new Error('Harbor task requires a completed, screened, passing episode')\n }\n if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(mergeCommit)) {\n throw new Error('Harbor task requires a full merge commit identity')\n }\n if (\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]*\\/[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name) ||\n !instruction.trim() ||\n !bundle.length\n )\n throw new Error('Invalid Harbor task input')\n if (!/^[a-zA-Z0-9][a-zA-Z0-9./:_-]*@sha256:[a-f0-9]{64}$/.test(image)) {\n throw new Error('Harbor task image must be pinned by sha256 digest')\n }\n for (const timeout of [agentTimeoutSec, verifierTimeoutSec]) {\n if (!Number.isSafeInteger(timeout) || timeout <= 0) throw new Error('Invalid Harbor timeout')\n }\n if (Object.values(commands).some((command) => typeof command !== 'string' || !command.trim())) {\n throw new Error('All three Harbor verifier commands are required')\n }\n const config =\n `schema_version = \"1.3\"\\n[task]\\nname = \"${name}\"\\n` +\n `[agent]\\ntimeout_sec = ${agentTimeoutSec}\\n[verifier]\\ntimeout_sec = ${verifierTimeoutSec}\\n`\n const files: Record<string, string | Uint8Array> = {\n 'task.toml': config,\n 'instruction.md': instruction,\n 'environment/base.bundle': bundle,\n 'environment/Dockerfile':\n `FROM ${image}\\nCOPY --chmod=0444 base.bundle /tmp/base.bundle\\n` +\n `RUN git clone --no-checkout /tmp/base.bundle /workspace/repo \\\\\\n && git -C /workspace/repo checkout --detach ${baseCommit} \\\\\\n && test \"$(git -C /workspace/repo rev-parse HEAD)\" = \"${baseCommit}\"\\nWORKDIR /workspace/repo\\n`,\n 'tests/acceptance.sh': commands.acceptance,\n 'tests/production-delta.sh': commands.productionDelta,\n 'tests/dangling-references.sh': commands.danglingReferences,\n 'tests/test.sh':\n '#!/bin/sh\\nset -eu\\nproject=${1:-/workspace/repo}\\n' +\n 'tests=${2:-/tests}\\nrewards=${3:-/logs/verifier}\\nmkdir -p \"$rewards\"\\n' +\n 'printf \"0\\\\n\" > \"$rewards/reward.txt\"\\ncd \"$project\"\\n' +\n `git cat-file -e ${baseCommit}^{commit}\\ngit merge-base --is-ancestor ${baseCommit} HEAD\\n` +\n 'sh \"$tests/acceptance.sh\"\\nsh \"$tests/production-delta.sh\"\\nsh \"$tests/dangling-references.sh\"\\n' +\n 'printf \"1\\\\n\" > \"$rewards/reward.txt\"\\n',\n }\n const directory = resolve(inputDirectory)\n signal?.throwIfAborted()\n if ((await realpath(dirname(directory))) !== dirname(directory)) {\n throw new Error('Harbor task parent must not traverse symlinks')\n }\n await mkdir(directory, { mode: 0o700 })\n await mkdir(join(directory, 'environment'))\n await mkdir(join(directory, 'tests'))\n const staged: HarborTaskFile[] = []\n for (const [path, bytes] of Object.entries(files)) {\n const stagedPath = join(directory, path === 'task.toml' ? '.task.toml.pending' : path)\n await writeFile(stagedPath, bytes, { flag: 'wx', mode: path.endsWith('.sh') ? 0o700 : 0o600 })\n staged.push(\n Object.freeze({\n path,\n stagedPath,\n sha256: digest(bytes),\n byteLength: typeof bytes === 'string' ? Buffer.byteLength(bytes) : bytes.byteLength,\n }),\n )\n }\n const identity = {\n rolloutId: episode.rollout_id,\n episodeSha256: digest(canonicalString(episode)),\n task: episode.task,\n source,\n mergeCommit,\n files: staged.map(({ path, sha256, byteLength }) => ({ path, sha256, byteLength })),\n }\n const taskId = digest(canonicalString(identity))\n const request = deepFreezeCanonicalJson({ ...identity, taskId, files: staged })\n signal?.throwIfAborted()\n const verdict = JSON.parse(canonicalString(await verify(request, signal))) as CompletionVerdict\n signal?.throwIfAborted()\n admitted(verdict, taskId)\n // No callback may add answer material to the build context or redirect a parent directory.\n for (const folder of ['', 'environment', 'tests']) {\n const path = join(directory, folder)\n if (!(await lstat(path)).isDirectory() || (await realpath(path)) !== path) {\n throw new Error('Harbor task directory changed during verification')\n }\n const expected =\n folder === ''\n ? ['.task.toml.pending', 'environment', 'instruction.md', 'tests']\n : Object.keys(files)\n .filter((file) => file.startsWith(`${folder}/`))\n .map((file) => file.slice(folder.length + 1))\n if (canonicalString((await readdir(path)).sort()) !== canonicalString(expected.sort())) {\n throw new Error('Harbor task contains unexpected files')\n }\n }\n for (const file of staged) {\n const info = await lstat(file.stagedPath)\n if (\n !info.isFile() ||\n info.isSymbolicLink() ||\n digest(await readFile(file.stagedPath)) !== file.sha256\n ) {\n throw new Error(`Harbor task file changed during verification: ${file.path}`)\n }\n }\n await writeFile(\n join(directory, 'tests/verification.json'),\n canonicalString({ identity, taskId, verdict }),\n { flag: 'wx', mode: 0o600 },\n )\n signal?.throwIfAborted()\n await link(join(directory, '.task.toml.pending'), join(directory, 'task.toml'))\n await unlink(join(directory, '.task.toml.pending'))\n return directory\n}\n","/**\n * Harbor ATIF-v1.7 interchange — `tangle.rollout.v1` ⇄ Agent Trajectory\n * Interchange Format.\n *\n * ATIF is the portability format (spec:\n * https://www.harborframework.com/docs/agents/trajectory-format, normative\n * RFC: harbor-framework/harbor `rfcs/0001-trajectory-format.md`). It sits\n * BELOW the waist of the rollout hourglass in both directions — export reads\n * `RolloutLine[]`, import writes `RolloutLine[]` — and it is never a source\n * of training labels:\n *\n * ATIF models NO reward, NO judge verdict, NO task/split coordinates.\n *\n * Consequences, both deliberate:\n * - EXPORT drops `outcome.reward`, `outcome.reward_source` and\n * `outcome.verdict` entirely. They are not smuggled into `extra`: a\n * third-party reading our ATIF file must not be able to mistake an\n * agent-eval judge score for something ATIF sanctioned.\n * - IMPORT therefore mints UNLABELED lines: `reward: null` (the existing\n * \"null reward is a labeled gap, never 0\" semantics), `verdict: null`,\n * and a `provenance.gap` naming the missing label. An imported\n * trajectory is not a training example until a judge scores it.\n *\n * Everything else we own that ATIF has no field for travels in a namespaced\n * escrow at `extra.tangle.*`, so our own round-trip is exact while a foreign\n * reader can ignore it. Fields that neither ATIF nor the escrow can carry\n * come back explicitly null / fail-closed, never invented.\n *\n * THE ESCROW IS NAMESPACED, NOT AUTHENTICATED. Anyone can write\n * `extra.tangle.*` into a file. So the escrow may restore what a value IS, but\n * never what a line is ALLOWED to do: `task.split` is forced to `holdout` on\n * every import regardless of what the document claims, and promoting an\n * imported trajectory to a trainable split is an explicit, greppable act\n * (`relabelImportedSplit`) rather than a property of the file. The document\n * keeps its claim — the claim just is not authority.\n *\n * Multi-agent shape differs on purpose. ATIF EMBEDS children in\n * `subagent_trajectories`; we keep a flat ledger with a normalized\n * `parent_rollout_id` edge. Export assembles the tree, import flattens it.\n * `session_id` is RUN-scoped in ATIF, so it carries `run_id` — the coordinate\n * that is shared by every invocation of one run — not `rollout_id`, which\n * identifies a single invocation and would split one run across session ids.\n *\n * ROUND-TRIPPING IS IDEMPOTENT: `import(export(import(export(x))))` is\n * byte-identical to `import(export(x))`. Import composes `provenance.gap` as a\n * de-duplicated ordered set rather than appending, and it emits every\n * `ChatMessage` with keys in the canonical schema order (role, content,\n * reasoning_content, tool_calls, tool_call_id, name, is_copied_context), so a\n * ledger hashed on serialized bytes sees no diff across further passes. The\n * FIRST import may re-order a producer's keys — that is the canonicalization.\n *\n * NOT building a Letta converter. Letta's trajectory-v1 is a strict subset of\n * what we need from ATIF here — no per-step or aggregate cost, no\n * multi-agent/subagent structure, no token-id or logprob channel — so a Letta\n * sink would carry less than this one and add a second format to keep\n * correct. Decision recorded in docs/rollout.md; do not re-litigate without a\n * concrete consumer that reads Letta and cannot read ATIF.\n */\n\nimport {\n assertRolloutLine,\n type ChatMessage,\n type ChatRole,\n type ChatToolCall,\n type GatedEvidence,\n ROLLOUT_CAPTURES,\n ROLLOUT_ROLES,\n ROLLOUT_SCHEMA,\n ROLLOUT_SPLITS,\n type RolloutArtifacts,\n type RolloutCapture,\n type RolloutCostBlock,\n type RolloutLine,\n type RolloutPolicy,\n type RolloutRole,\n type RolloutSplit,\n type RolloutStep,\n type RolloutTask,\n type ToolDef,\n} from '../schema'\n\nimport { isRecord } from '../../llm-client/json'\nconst ATIF_SCHEMA_VERSION = 'ATIF-v1.7'\n\n/** Gap note on every imported line — ATIF carries no verdict, so nothing is scored. */\nconst HARBOR_IMPORT_GAP = 'imported from Harbor ATIF; no verdict'\n\n/** Namespaced escrow key for everything ATIF does not model but we must not lose. */\nconst ESCROW = 'tangle'\n\n/**\n * Marks a step we synthesized purely to hold tool results that answered no\n * assistant turn IN THIS DOCUMENT. ATIF has no `tool` source, so such results\n * need a carrier step; the marker lets import drop the carrier instead of\n * inventing a turn.\n *\n * A carrier's results carry NO `source_call_id`. RFC 0001 rule 2 requires every\n * `source_call_id` to match a `tool_call_id` in the same step's `tool_calls`,\n * and a carrier declares no calls (a `system` step cannot legally make one), so\n * emitting the id there would produce an invalid document. The id is escrowed\n * instead and restored verbatim on import — the link survives without the\n * document lying about who made the call.\n */\nconst TOOL_RESULTS_ONLY = 'tool-results-only'\n\n// ---------------------------------------------------------------------------\n// ATIF-v1.7 wire types (RFC 0001). Optional fields are optional here too.\n// ---------------------------------------------------------------------------\n\nexport type HarborStepSource = 'system' | 'user' | 'agent'\n\nexport interface HarborImageSource {\n media_type: string\n path: string\n}\n\nexport interface HarborContentPart {\n type: 'text' | 'image'\n text?: string\n source?: HarborImageSource\n}\n\nexport interface HarborToolCall {\n tool_call_id: string\n function_name: string\n /** ATIF requires a decoded JSON object here, unlike our raw argument string. */\n arguments: Record<string, unknown>\n extra?: Record<string, unknown>\n}\n\nexport interface HarborSubagentTrajectoryRef {\n trajectory_id?: string\n trajectory_path?: string\n /** Informational only since v1.7 — never a resolution key. */\n session_id?: string\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservationResult {\n source_call_id?: string\n content?: string | HarborContentPart[]\n subagent_trajectory_ref?: HarborSubagentTrajectoryRef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborObservation {\n results: HarborObservationResult[]\n}\n\nexport interface HarborMetrics {\n prompt_tokens?: number\n completion_tokens?: number\n cached_tokens?: number\n cost_usd?: number\n prompt_token_ids?: number[]\n completion_token_ids?: number[]\n logprobs?: number[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborStep {\n /** Ordinal, sequential from 1. */\n step_id: number\n timestamp?: string\n source: HarborStepSource\n model_name?: string\n reasoning_effort?: string | number\n message: string | HarborContentPart[]\n reasoning_content?: string\n tool_calls?: HarborToolCall[]\n observation?: HarborObservation\n metrics?: HarborMetrics\n llm_call_count?: number\n is_copied_context?: boolean\n extra?: Record<string, unknown>\n}\n\nexport interface HarborAgent {\n name: string\n version: string\n model_name?: string\n /** OpenAI function-calling schema — byte-identical to our `ToolDef`. */\n tool_definitions?: ToolDef[]\n extra?: Record<string, unknown>\n}\n\nexport interface HarborFinalMetrics {\n total_prompt_tokens?: number\n total_completion_tokens?: number\n total_cached_tokens?: number\n total_cost_usd?: number\n total_steps?: number\n extra?: Record<string, unknown>\n}\n\nexport interface HarborTrajectory {\n schema_version: string\n session_id?: string\n /** Required on embedded subagents; we always set it so lines stay joinable. */\n trajectory_id?: string\n agent: HarborAgent\n steps: HarborStep[]\n notes?: string\n final_metrics?: HarborFinalMetrics\n continued_trajectory_ref?: string\n subagent_trajectories?: HarborTrajectory[]\n extra?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined)\n\nconst asNumberOrNull = (v: unknown): number | null =>\n typeof v === 'number' && Number.isFinite(v) ? v : null\n\nconst asIntegerOrUndefined = (v: unknown): number | undefined =>\n Number.isInteger(v) ? (v as number) : undefined\n\nconst asNumberArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n ? (v as number[])\n : undefined\n\nconst asIntegerArray = (v: unknown): number[] | undefined =>\n Array.isArray(v) && v.every((n) => Number.isInteger(n)) ? (v as number[]) : undefined\n\n/**\n * Builds a `ChatMessage` with keys in the schema's declaration order.\n *\n * Object key order is insertion order in JS, so a message assembled\n * conditionally field-by-field serializes differently depending on which\n * optional fields were present — which makes a byte-hashed ledger see a diff\n * across an import that changed nothing. One builder, one order, stable bytes.\n */\nfunction canonicalChatMessage(parts: {\n role: ChatRole\n content: string | null\n reasoning_content?: string\n tool_calls?: ChatToolCall[]\n tool_call_id?: string\n name?: string\n is_copied_context?: boolean\n}): ChatMessage {\n const message: ChatMessage = { role: parts.role, content: parts.content }\n if (parts.reasoning_content !== undefined) message.reasoning_content = parts.reasoning_content\n if (parts.tool_calls !== undefined) message.tool_calls = parts.tool_calls\n if (parts.tool_call_id !== undefined) message.tool_call_id = parts.tool_call_id\n if (parts.name !== undefined) message.name = parts.name\n if (parts.is_copied_context === true) message.is_copied_context = true\n return message\n}\n\n/** Reads the `extra.tangle` escrow, tolerating a foreign file that has none. */\nfunction escrowOf(extra: Record<string, unknown> | undefined): Record<string, unknown> | undefined {\n if (!isRecord(extra)) return undefined\n const value = extra[ESCROW]\n return isRecord(value) ? value : undefined\n}\n\nfunction escrowSection(\n escrow: Record<string, unknown> | undefined,\n key: string,\n): Record<string, unknown> | undefined {\n if (escrow === undefined) return undefined\n const value = escrow[key]\n return isRecord(value) ? value : undefined\n}\n\n// ---------------------------------------------------------------------------\n// Export: RolloutLine[] → ATIF trajectory tree\n// ---------------------------------------------------------------------------\n\nfunction toHarborToolCall(call: ChatToolCall): HarborToolCall {\n // ATIF requires `arguments` to be a JSON object; ours is the raw\n // JSON-encoded string the model emitted, and models really do emit\n // malformed ones. Keep the exact bytes in `extra` so import restores the\n // string verbatim instead of re-serializing a normalized parse.\n let parsed: Record<string, unknown> | undefined\n try {\n const decoded: unknown = JSON.parse(call.function.arguments)\n if (isRecord(decoded)) parsed = decoded\n } catch {\n parsed = undefined\n }\n return {\n tool_call_id: call.id,\n function_name: call.function.name,\n arguments: parsed ?? {},\n extra: { [ESCROW]: { arguments_raw: call.function.arguments } },\n }\n}\n\n/**\n * `linked` = this result is attached to the step that actually declared the\n * call, so `source_call_id` is legal (RFC 0001 rule 2). When it is not, the id\n * goes to escrow instead of onto the wire.\n */\nfunction toObservationResult(message: ChatMessage, linked: boolean): HarborObservationResult {\n const result: HarborObservationResult = {}\n if (linked && message.tool_call_id !== undefined) result.source_call_id = message.tool_call_id\n if (message.content !== null) result.content = message.content\n const escrow: Record<string, unknown> = {}\n if (!linked && message.tool_call_id !== undefined) escrow.source_call_id = message.tool_call_id\n if (message.name !== undefined) escrow.name = message.name\n // `content: null` on a tool turn is meaningful (a tool that returned\n // nothing) and is not the same as the empty string ATIF would round-trip it to.\n if (message.content === null) escrow.content_null = true\n if (message.reasoning_content !== undefined) escrow.reasoning_content = message.reasoning_content\n if (message.is_copied_context === true) escrow.is_copied_context = true\n if (Object.keys(escrow).length > 0) result.extra = { [ESCROW]: escrow }\n return result\n}\n\n/** True when `step` is the agent turn that declared `callId` — the rule-2 test. */\nfunction declaresCall(step: HarborStep, callId: string | undefined): boolean {\n if (callId === undefined) return false\n return step.tool_calls?.some((call) => call.tool_call_id === callId) === true\n}\n\n/**\n * Attaches the four RL fields lifted from ATIF onto the agent step the span\n * describes. They are ALSO escrowed with the whole span under `extra.tangle`,\n * on purpose: the escrow is how our own round-trip stays exact, and these\n * native fields are how a foreign consumer — which never reads our escrow —\n * gets the logprobs and token ids at all. A field carried only in the escrow is\n * not an interchange field.\n */\nfunction applySpanMetrics(step: HarborStep, span: RolloutStep | undefined): void {\n if (span === undefined) return\n if (span.llm_call_count !== undefined) step.llm_call_count = span.llm_call_count\n const metrics: HarborMetrics = {}\n if (span.prompt_token_ids !== undefined) metrics.prompt_token_ids = span.prompt_token_ids\n if (span.completion_token_ids !== undefined) {\n metrics.completion_token_ids = span.completion_token_ids\n }\n if (span.logprobs !== undefined) metrics.logprobs = span.logprobs\n if (Object.keys(metrics).length > 0) step.metrics = metrics\n}\n\n/**\n * Coalescing fold, not a 1:1 map: ATIF has no `tool` source, so a tool result\n * becomes an `observation.results[]` entry on the agent step THAT DECLARED ITS\n * `tool_call_id`.\n *\n * Linking by id, not by adjacency. Adjacency emitted invalid documents in three\n * shapes the RFC forbids — an assistant turn with no `tool_calls` swallowing the\n * results that followed it, a result whose id matched none of the preceding\n * step's calls, and an unanswered result riding a `system` step that carried a\n * `source_call_id` it could never declare. Attaching only to the step that owns\n * the id also preserves message order exactly: a result either joins the step\n * immediately before it or becomes its own carrier at its own position.\n *\n * `line.steps` span projections are matched to agent steps in order (k-th llm\n * span → k-th agent step) purely to fill ATIF's native per-step `metrics`;\n * extra spans on either side are simply not matched, never invented.\n */\nfunction messagesToSteps(line: RolloutLine): HarborStep[] {\n const steps: HarborStep[] = []\n const llmSpans = (line.steps ?? []).filter((span) => span.kind === 'llm')\n let nextSpan = 0\n for (const message of line.messages) {\n if (message.role === 'tool') {\n const previous = steps[steps.length - 1]\n if (previous !== undefined && declaresCall(previous, message.tool_call_id)) {\n if (previous.observation === undefined) previous.observation = { results: [] }\n previous.observation.results.push(toObservationResult(message, true))\n continue\n }\n // A tool result answering no assistant turn in this document (truncated or\n // reconstructed transcript). It still has to survive, so it rides a marked\n // carrier step whose observation states no call id.\n const carrier: HarborStep = {\n step_id: steps.length + 1,\n source: 'system',\n message: '',\n observation: { results: [toObservationResult(message, false)] },\n extra: { [ESCROW]: { synthetic: TOOL_RESULTS_ONLY } },\n }\n if (message.is_copied_context === true) carrier.is_copied_context = true\n steps.push(carrier)\n continue\n }\n const step: HarborStep = {\n step_id: steps.length + 1,\n source: message.role === 'assistant' ? 'agent' : message.role,\n message: message.content ?? '',\n }\n const escrow: Record<string, unknown> = {}\n if (message.content === null) escrow.content_null = true\n if (message.name !== undefined) escrow.name = message.name\n if (message.role === 'assistant') {\n if (line.policy.model !== null) step.model_name = line.policy.model\n if (message.reasoning_content !== undefined) {\n step.reasoning_content = message.reasoning_content\n }\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n step.tool_calls = message.tool_calls.map(toHarborToolCall)\n }\n applySpanMetrics(step, llmSpans[nextSpan])\n nextSpan += 1\n } else if (message.reasoning_content !== undefined) {\n // ATIF confines `reasoning_content` to agent steps; ours is not confined.\n escrow.reasoning_content = message.reasoning_content\n }\n // RFC 0001 rule 7: a copied-context turn was not authored by this agent, and\n // an SFT pipeline MUST exclude it. Native ATIF field, both directions.\n if (message.is_copied_context === true) step.is_copied_context = true\n if (Object.keys(escrow).length > 0) step.extra = { [ESCROW]: escrow }\n steps.push(step)\n }\n return steps\n}\n\nfunction finalMetricsOf(line: RolloutLine, stepCount: number): HarborFinalMetrics {\n const metrics: HarborFinalMetrics = {}\n if (line.cost.tokens_in !== null) metrics.total_prompt_tokens = line.cost.tokens_in\n if (line.cost.tokens_out !== null) metrics.total_completion_tokens = line.cost.tokens_out\n if (line.cost.cache_read !== null) metrics.total_cached_tokens = line.cost.cache_read\n // Omitted, never 0, when cost was not captured — a fake 0 is a lie about spend.\n if (line.cost.usd !== null) metrics.total_cost_usd = line.cost.usd\n metrics.total_steps = stepCount\n // ATIF has no aggregate field for these three; `reasoning_tokens` under\n // `extra` is the key the RFC's own worked example uses.\n const extra: Record<string, unknown> = {}\n if (line.cost.tokens_reasoning !== null) extra.reasoning_tokens = line.cost.tokens_reasoning\n if (line.cost.cache_write !== null) extra.cache_write_tokens = line.cost.cache_write\n if (line.cost.wall_s !== null) extra.wall_s = line.cost.wall_s\n if (line.cost.llm_call_count !== undefined && line.cost.llm_call_count !== null) {\n extra.llm_call_count = line.cost.llm_call_count\n }\n if (Object.keys(extra).length > 0) metrics.extra = extra\n return metrics\n}\n\nfunction notesOf(line: RolloutLine): string | undefined {\n const parts: string[] = []\n if (line.provenance.gap !== undefined) parts.push(line.provenance.gap)\n if (line.outcome.realness_gated === true) {\n // ATIF has no gate field. A third-party consumer that ignores `extra`\n // would otherwise see a gamed trajectory with nothing marking it, so the\n // flag is stated in prose as well. This export carries no reward at all,\n // so it is not a training-data door — but it is an audit record.\n parts.push('realness-gated: this run faked its success signal (anti-Goodhart gate fired)')\n }\n return parts.length > 0 ? parts.join(' | ') : undefined\n}\n\nfunction toTrajectoryNode(line: RolloutLine): HarborTrajectory {\n const steps = messagesToSteps(line)\n const trajectory: HarborTrajectory = {\n schema_version: ATIF_SCHEMA_VERSION,\n // RUN-scoped, per the spec — so it is `run_id`, the coordinate every\n // invocation of one run shares. `rollout_id` identifies a single\n // invocation: using it gave two roots of the same run different session\n // ids, and foreign tooling that groups by session_id would split the run.\n session_id: line.run_id,\n trajectory_id: line.rollout_id,\n agent: {\n // ATIF requires both; ours are nullable, so a null is substituted here\n // and restored on import from the escrowed policy — never guessed back.\n name: line.policy.harness ?? 'unknown',\n version: line.policy.harness_version ?? '0.0.0',\n ...(line.policy.model !== null ? { model_name: line.policy.model } : {}),\n ...(line.tool_defs.length > 0 ? { tool_definitions: line.tool_defs } : {}),\n },\n steps,\n final_metrics: finalMetricsOf(line, steps.length),\n extra: {\n [ESCROW]: {\n schema: line.schema,\n rollout_id: line.rollout_id,\n parent_rollout_id: line.parent_rollout_id,\n run_id: line.run_id,\n ...(line.experiment_id !== undefined ? { experiment_id: line.experiment_id } : {}),\n ...(line.candidate_id !== undefined ? { candidate_id: line.candidate_id } : {}),\n generation: line.generation,\n candidate_index: line.candidate_index,\n role: line.role,\n task: line.task,\n policy: line.policy,\n // Span projections overlap the same turns as `steps[]`; folding them\n // into ATIF steps would double-count the run, so they stay escrowed.\n ...(line.steps !== undefined ? { spans: line.steps } : {}),\n outcome: {\n // reward / reward_source / verdict are deliberately absent — see the\n // module header. Only the non-scalar outcome fields travel.\n metrics: line.outcome.metrics,\n is_completed: line.outcome.is_completed,\n is_truncated: line.outcome.is_truncated,\n error: line.outcome.error,\n ...(line.outcome.realness_gated !== undefined\n ? { realness_gated: line.outcome.realness_gated }\n : {}),\n },\n artifacts: line.artifacts,\n provenance: line.provenance,\n },\n },\n }\n const notes = notesOf(line)\n if (notes !== undefined) trajectory.notes = notes\n return trajectory\n}\n\ninterface Forest {\n roots: RolloutLine[]\n childrenOf: Map<string, RolloutLine[]>\n}\n\nfunction buildForest(lines: RolloutLine[]): Forest {\n const byId = new Map<string, RolloutLine>()\n for (const line of lines) {\n if (byId.has(line.rollout_id)) {\n throw new Error(`duplicate rollout_id in input: ${line.rollout_id}`)\n }\n byId.set(line.rollout_id, line)\n }\n const roots: RolloutLine[] = []\n const childrenOf = new Map<string, RolloutLine[]>()\n for (const line of lines) {\n const parent = line.parent_rollout_id\n // A parent outside this set is a root OF WHAT WE HAVE: the edge is kept in\n // escrow so a later import restores the dangling pointer instead of nulling it.\n if (parent === null || !byId.has(parent)) {\n roots.push(line)\n continue\n }\n const siblings = childrenOf.get(parent)\n if (siblings === undefined) childrenOf.set(parent, [line])\n else siblings.push(line)\n }\n // Every line has a parent inside the set: the edges form a cycle with no\n // root. Returning zero documents would drop the whole episode silently.\n if (lines.length > 0 && roots.length === 0) {\n throw new Error(\n `parent_rollout_id cycle: no root among ${lines.length} lines (${lines.map((l) => l.rollout_id).join(', ')})`,\n )\n }\n return { roots, childrenOf }\n}\n\nfunction assemble(line: RolloutLine, forest: Forest, onPath: Set<string>): HarborTrajectory {\n if (onPath.has(line.rollout_id)) {\n throw new Error(`parent_rollout_id cycle through rollout_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n const node = toTrajectoryNode(line)\n const children = forest.childrenOf.get(line.rollout_id)\n if (children !== undefined && children.length > 0) {\n node.subagent_trajectories = children.map((child) => assemble(child, forest, onPath))\n }\n onPath.delete(line.rollout_id)\n return node\n}\n\n/**\n * Assemble one episode's flat lines into a single ATIF trajectory tree,\n * linked by `parent_rollout_id`.\n *\n * Reward, verdict and split are NOT emitted (ATIF models none of them); the\n * split and the rest of the task coordinates survive only in `extra.tangle`.\n *\n * We deliberately do NOT synthesize an `observation.subagent_trajectory_ref`\n * pointing at each child: our ledger records WHICH invocation spawned a\n * worker, not which STEP did, and attaching the ref to a guessed step would\n * fabricate a causal claim. Children are embedded in `subagent_trajectories`\n * (each with the `trajectory_id` the spec requires) and the edge is stated in\n * the child's escrowed `parent_rollout_id`.\n *\n * Throws when the lines are not one tree — use `toHarborTrajectories` for a forest.\n */\nexport function toHarborTrajectory(lines: RolloutLine[]): HarborTrajectory {\n const trees = toHarborTrajectories(lines)\n if (trees.length === 0) throw new Error('toHarborTrajectory: no lines')\n if (trees.length > 1) {\n const ids = trees.map((t) => t.trajectory_id ?? '?').join(', ')\n throw new Error(\n `toHarborTrajectory: ${trees.length} roots (${ids}) — ATIF is one tree per document; use toHarborTrajectories`,\n )\n }\n return trees[0]!\n}\n\n/** Every independent tree in the input, one ATIF document each. */\nexport function toHarborTrajectories(lines: RolloutLine[]): HarborTrajectory[] {\n const forest = buildForest(lines)\n return forest.roots.map((root) => assemble(root, forest, new Set()))\n}\n\n// ---------------------------------------------------------------------------\n// Import: ATIF trajectory tree → RolloutLine[]\n// ---------------------------------------------------------------------------\n\nfunction contentToString(message: string | HarborContentPart[]): string {\n if (typeof message === 'string') return message\n return message\n .map((part) =>\n part.type === 'image'\n ? // Our chat content is text-only. Describing the image is honest about\n // what the source held; dropping it silently would not be.\n `[image ${part.source?.media_type ?? 'unknown'} ${part.source?.path ?? ''}]`.trim()\n : (part.text ?? ''),\n )\n .join('\\n')\n}\n\nfunction fromHarborToolCall(call: HarborToolCall): ChatToolCall {\n const raw = asString(escrowOf(call.extra)?.arguments_raw)\n return {\n id: call.tool_call_id,\n type: 'function',\n function: { name: call.function_name, arguments: raw ?? JSON.stringify(call.arguments ?? {}) },\n }\n}\n\nfunction fromObservationResult(\n result: HarborObservationResult,\n callId: string | undefined,\n): ChatMessage {\n const escrow = escrowOf(result.extra)\n return canonicalChatMessage({\n role: 'tool',\n content:\n escrow?.content_null === true\n ? null\n : result.content === undefined\n ? ''\n : contentToString(result.content),\n reasoning_content: asString(escrow?.reasoning_content),\n tool_call_id: callId,\n name: asString(escrow?.name),\n is_copied_context: escrow?.is_copied_context === true,\n })\n}\n\nfunction stepsToMessages(steps: HarborStep[]): ChatMessage[] {\n const messages: ChatMessage[] = []\n for (const step of steps) {\n const escrow = escrowOf(step.extra)\n const carrierOnly = escrow?.synthetic === TOOL_RESULTS_ONLY\n if (!carrierOnly) {\n messages.push(\n canonicalChatMessage({\n role: step.source === 'agent' ? 'assistant' : step.source,\n content: escrow?.content_null === true ? null : contentToString(step.message),\n reasoning_content: step.reasoning_content ?? asString(escrow?.reasoning_content),\n tool_calls:\n step.tool_calls !== undefined && step.tool_calls.length > 0\n ? step.tool_calls.map(fromHarborToolCall)\n : undefined,\n name: asString(escrow?.name),\n is_copied_context: step.is_copied_context === true,\n }),\n )\n }\n for (const result of step.observation?.results ?? []) {\n const resultEscrow = escrowOf(result.extra)\n const callId = result.source_call_id ?? asString(resultEscrow?.source_call_id)\n if (carrierOnly) {\n // Our own carrier: every result on it was a tool turn, and its call id\n // (if the transcript had one) is in escrow, not on the wire.\n messages.push(fromObservationResult(result, callId))\n continue\n }\n if (typeof callId === 'string') {\n messages.push(fromObservationResult(result, callId))\n continue\n }\n // ATIF allows a result from a non-tool-calling action. Our chat schema\n // requires `tool_call_id` on a tool turn, so inventing one would forge a\n // link; the text is preserved as a system observation instead.\n if (result.content !== undefined) {\n messages.push(\n canonicalChatMessage({ role: 'system', content: contentToString(result.content) }),\n )\n }\n }\n }\n return messages\n}\n\nfunction taskFrom(escrow: Record<string, unknown> | undefined, fallbackId: string): RolloutTask {\n const task = escrowSection(escrow, 'task')\n return {\n suite: asString(task?.suite) ?? 'harbor-atif-import',\n instance_id: asString(task?.instance_id) ?? fallbackId,\n // ALWAYS holdout — the escrowed claim is read for nothing here.\n //\n // `extra.tangle.task.split` is a namespaced key, not an authenticated one:\n // a hand-written or third-party document can set `split: 'search'` as\n // easily as our own exporter can, and honouring it made \"this file says so\"\n // sufficient to walk into a training export. Trainability is a decision\n // about a file, so it is made by an operator through\n // `relabelImportedSplit`, never by the file about itself. The claim is not\n // destroyed — it stays readable in the source document.\n split: 'holdout',\n seed: asNumberOrNull(task?.seed),\n rep: asIntegerOrUndefined(task?.rep) ?? 0,\n }\n}\n\nfunction policyFrom(\n escrow: Record<string, unknown> | undefined,\n agent: HarborAgent,\n): RolloutPolicy {\n const escrowed = escrowSection(escrow, 'policy')\n if (escrowed !== undefined) {\n // Our own export: restore verbatim, including the nulls ATIF forced us to\n // substitute placeholders for in `agent.name` / `agent.version`.\n return {\n harness: asString(escrowed.harness) ?? null,\n harness_version: asString(escrowed.harness_version) ?? null,\n model: asString(escrowed.model) ?? null,\n provider: asString(escrowed.provider) ?? null,\n profile_commit: asString(escrowed.profile_commit) ?? null,\n ...(escrowed.prompt_hash !== undefined\n ? { prompt_hash: asString(escrowed.prompt_hash) ?? null }\n : {}),\n ...(escrowed.config_hash !== undefined\n ? { config_hash: asString(escrowed.config_hash) ?? null }\n : {}),\n ...(escrowed.agent_profile_cell_id !== undefined\n ? { agent_profile_cell_id: asString(escrowed.agent_profile_cell_id) ?? null }\n : {}),\n sampling: isRecord(escrowed.sampling) ? escrowed.sampling : null,\n }\n }\n return {\n harness: agent.name,\n harness_version: agent.version,\n model: agent.model_name ?? null,\n provider: null,\n profile_commit: null,\n sampling: null,\n }\n}\n\nfunction artifactsFrom(escrow: Record<string, unknown> | undefined): RolloutArtifacts {\n const artifacts = escrowSection(escrow, 'artifacts')\n return {\n patch_path: asString(artifacts?.patch_path) ?? null,\n run_dir: asString(artifacts?.run_dir) ?? null,\n transcript_ref: asString(artifacts?.transcript_ref) ?? null,\n }\n}\n\nfunction costFrom(final: HarborFinalMetrics | undefined): RolloutCostBlock {\n const rawExtra = final?.extra\n const extra = isRecord(rawExtra) ? rawExtra : undefined\n const calls = asIntegerOrUndefined(extra?.llm_call_count)\n return {\n usd: asNumberOrNull(final?.total_cost_usd),\n tokens_in: asNumberOrNull(final?.total_prompt_tokens),\n tokens_out: asNumberOrNull(final?.total_completion_tokens),\n tokens_reasoning: asNumberOrNull(extra?.reasoning_tokens),\n cache_read: asNumberOrNull(final?.total_cached_tokens),\n cache_write: asNumberOrNull(extra?.cache_write_tokens),\n wall_s: asNumberOrNull(extra?.wall_s),\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n }\n}\n\n/**\n * Recovers span projections from ATIF's NATIVE per-step channel, for documents\n * with no `extra.tangle.spans` escrow — i.e. everything a foreign producer\n * writes. Without this the logprobs and token ids a Harbor-native trainer\n * records would be read, validated, and then dropped on the floor.\n *\n * Only steps that actually carry one of the four fields produce a span: an\n * agent step with no metrics means \"not captured\", and inventing an empty span\n * for it would claim the run had a shape we did not observe.\n */\nfunction spansFromSteps(steps: HarborStep[]): RolloutStep[] {\n const spans: RolloutStep[] = []\n for (const step of steps) {\n if (step.source !== 'agent') continue\n const calls = asIntegerOrUndefined(step.llm_call_count)\n const promptIds = asIntegerArray(step.metrics?.prompt_token_ids)\n const completionIds = asIntegerArray(step.metrics?.completion_token_ids)\n const logprobs = asNumberArray(step.metrics?.logprobs)\n if (\n calls === undefined &&\n promptIds === undefined &&\n completionIds === undefined &&\n logprobs === undefined\n ) {\n continue\n }\n spans.push({\n kind: 'llm',\n name: step.model_name ?? 'chat',\n ...(calls !== undefined ? { llm_call_count: calls } : {}),\n ...(promptIds !== undefined ? { prompt_token_ids: promptIds } : {}),\n ...(completionIds !== undefined ? { completion_token_ids: completionIds } : {}),\n ...(logprobs !== undefined ? { logprobs } : {}),\n })\n }\n return spans\n}\n\n/**\n * Composes `provenance.gap` as an ordered SET of reasons.\n *\n * Appending made the note accrete on every pass (\"…no verdict | …no verdict\"),\n * which both grows without bound and breaks byte-level idempotency for a ledger\n * hashed on its serialized lines.\n */\nfunction composeGap(escrowedGap: string | undefined, added: readonly string[]): string {\n const parts: string[] = []\n const seen = new Set<string>()\n for (const raw of [...(escrowedGap?.split(' | ') ?? []), ...added]) {\n const reason = raw.trim()\n if (reason.length === 0 || seen.has(reason)) continue\n seen.add(reason)\n parts.push(reason)\n }\n return parts.join(' | ')\n}\n\nexport interface FromHarborOptions {\n /** Injected clock for deterministic output when the source carries no capture time. */\n now?: () => Date\n}\n\nfunction nodeToLine(\n trajectory: HarborTrajectory,\n parentId: string | null,\n capturedAt: string,\n): RolloutLine {\n const escrow = escrowOf(trajectory.extra)\n const rolloutId =\n asString(escrow?.rollout_id) ?? trajectory.trajectory_id ?? trajectory.session_id\n if (rolloutId === undefined || rolloutId.length === 0) {\n throw new Error(\n 'fromHarborTrajectory: trajectory has no trajectory_id or session_id — cannot mint a joinable rollout_id without inventing one',\n )\n }\n const outcome = escrowSection(escrow, 'outcome')\n const provenance = escrowSection(escrow, 'provenance')\n const capture = provenance?.capture\n const escrowedGap = asString(provenance?.gap)\n const role = escrow?.role\n const escrowedSpans = escrow?.spans\n // The escrow wins when it exists (our own export: exact, including an empty\n // array, which claims \"captured, none\" rather than \"not captured\"), and the\n // native per-step channel is the fallback (a foreign export: still signal).\n const nativeSpans = spansFromSteps(trajectory.steps)\n const spans: RolloutStep[] | undefined = Array.isArray(escrowedSpans)\n ? (escrowedSpans as RolloutStep[])\n : nativeSpans.length > 0\n ? nativeSpans\n : undefined\n const messages = stepsToMessages(trajectory.steps)\n const line: RolloutLine = {\n schema: ROLLOUT_SCHEMA,\n rollout_id: rolloutId,\n // The tree edge wins for embedded children; for a root, the escrowed\n // pointer may reference a line outside this document and is preserved.\n parent_rollout_id: parentId ?? asString(escrow?.parent_rollout_id) ?? null,\n run_id: asString(escrow?.run_id) ?? trajectory.session_id ?? rolloutId,\n // Required keys on the wire (0.127.0): a foreign document that never\n // stated them imports as explicit `null`, not as an absent field.\n experiment_id: asString(escrow?.experiment_id) ?? null,\n candidate_id: asString(escrow?.candidate_id) ?? null,\n generation: asIntegerOrUndefined(escrow?.generation) ?? null,\n candidate_index: asIntegerOrUndefined(escrow?.candidate_index) ?? null,\n role: ROLLOUT_ROLES.includes(role as RolloutRole) ? (role as RolloutRole) : 'agent',\n task: taskFrom(escrow, rolloutId),\n policy: policyFrom(escrow, trajectory.agent),\n messages,\n tool_defs: trajectory.agent.tool_definitions ?? [],\n ...(spans !== undefined ? { steps: spans } : {}),\n outcome: {\n // ATIF carries no label. Null is the labeled gap; a 0 here would be a\n // fabricated failure and a 1 a fabricated success.\n reward: null,\n reward_source: null,\n verdict: null,\n metrics: isRecord(outcome?.metrics) ? outcome.metrics : {},\n is_completed: typeof outcome?.is_completed === 'boolean' ? outcome.is_completed : true,\n is_truncated:\n typeof outcome?.is_truncated === 'boolean'\n ? outcome.is_truncated\n : trajectory.continued_trajectory_ref !== undefined,\n error: asString(outcome?.error) ?? null,\n // The anti-Goodhart flag is restored when the source document stated\n // it; the wire schema requires the field, so a document that never did\n // imports as `false`. That is safe here because the reward is already\n // forced to `null` (not trainable) and `realness_screened` stays\n // absent = unknown rather than claiming a screen ran.\n realness_gated: outcome?.realness_gated === true,\n },\n cost: costFrom(trajectory.final_metrics),\n artifacts: artifactsFrom(escrow),\n provenance: {\n captured_at: asString(provenance?.captured_at) ?? capturedAt,\n capture: ROLLOUT_CAPTURES.includes(capture as RolloutCapture)\n ? (capture as RolloutCapture)\n : 'backfill',\n gap: composeGap(escrowedGap, [HARBOR_IMPORT_GAP]),\n // Restored for the same reason `realness_gated` is, and with the opposite\n // risk profile from the reward: this is the gated run's own measurement\n // bag, moved off `outcome` by `gateGamedOutcome` so no exporter reads it\n // as training input. Dropping it here would silently destroy the audit\n // trail that says WHY the run was flagged and what it claimed, on the one\n // population an auditor most wants to inspect. It cannot be fail-open —\n // nothing projects `provenance` into a training row.\n ...(isRecord(provenance?.gated_evidence)\n ? { gated_evidence: provenance.gated_evidence as GatedEvidence }\n : {}),\n },\n }\n assertRolloutLine(line, `rollout line imported from ATIF trajectory ${rolloutId}`)\n return line\n}\n\n/**\n * Flatten an ATIF trajectory tree back into `tangle.rollout.v1` lines, parent\n * first, each child carrying `parent_rollout_id`.\n *\n * Every line comes back UNLABELED: `reward`, `reward_source` and `verdict` are\n * null and `provenance.gap` says why. ATIF models no verdict, so scoring an\n * imported trajectory is a judge's job, not this function's. Every line lands\n * on `holdout` whatever the document claims — see `relabelImportedSplit`.\n */\nexport function fromHarborTrajectory(\n trajectory: HarborTrajectory,\n options: FromHarborOptions = {},\n): RolloutLine[] {\n const capturedAt = (options.now?.() ?? new Date()).toISOString()\n const lines: RolloutLine[] = []\n const walk = (node: HarborTrajectory, parentId: string | null, onPath: Set<string>): void => {\n const line = nodeToLine(node, parentId, capturedAt)\n if (onPath.has(line.rollout_id)) {\n throw new Error(`subagent_trajectories cycle through trajectory_id ${line.rollout_id}`)\n }\n onPath.add(line.rollout_id)\n lines.push(line)\n for (const child of node.subagent_trajectories ?? []) {\n walk(child, line.rollout_id, onPath)\n }\n onPath.delete(line.rollout_id)\n }\n walk(trajectory, null, new Set())\n return lines\n}\n\n/**\n * THE explicit door out of `holdout` for imported lines.\n *\n * Import forces `holdout` because a document's own claim about its split is not\n * evidence — anyone can write `extra.tangle.task.split`. Promoting a file to a\n * trainable split is an operator's decision about provenance they verified, so\n * it is a separate, greppable call: `grep relabelImportedSplit` enumerates\n * every place foreign data was declared trainable, which is exactly the audit\n * the trusted-escrow version made impossible.\n *\n * Returns plain `RolloutLine`s. They still have to pass `assertMinted` (and its\n * anti-Goodhart check) to reach an exporter — re-labeling a split is not\n * minting a reward.\n */\nexport function relabelImportedSplit(\n lines: readonly RolloutLine[],\n split: RolloutSplit,\n): RolloutLine[] {\n if (!ROLLOUT_SPLITS.includes(split)) {\n throw new Error(`relabelImportedSplit: unknown split ${String(split)}`)\n }\n return lines.map((line) => ({ ...line, task: { ...line.task, split } }))\n}\n","/**\n * Claude Code project transcripts (~/.claude/projects/<cwd-slug>/<sessionId>.jsonl) as canonical\n * chat-with-tools messages plus per-session token usage.\n *\n * The transcript is read by @tangle-network/harness-sessions, the one reader of harness sessions\n * shared with Discovery, agent-record, traces and the blog: one model call per API response\n * (`message.id`, its usage counted once), the served model from the response, tool calls with\n * their results. This module only projects that session. Sidechain lines (subagent threads in the\n * main file) are separate invocations and are excluded unless `includeSidechain` asks for a\n * subagent's own transcript.\n */\n\nimport { readdir } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport {\n claudeCodeReader,\n claudeCodeRefForFile,\n type HarnessSession,\n readSessionInput,\n toChatMessages,\n} from '@tangle-network/harness-sessions'\nimport type { ChatMessage } from '../schema'\n\nexport const DEFAULT_CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects')\n\n/** Claude Code's project-directory slug for a working directory. */\nfunction claudeProjectSlug(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9-]/g, '-')\n}\n\nexport interface ClaudeTranscriptRef {\n sessionId: string\n path: string\n}\n\n/** Transcript files recorded for sessions launched from `cwd`. */\nexport async function findClaudeTranscripts(\n cwd: string,\n projectsDir: string = DEFAULT_CLAUDE_PROJECTS_DIR,\n): Promise<ClaudeTranscriptRef[]> {\n const dir = join(projectsDir, claudeProjectSlug(cwd))\n const names = await readdir(dir).catch(() => [])\n return names\n .filter((n) => n.endsWith('.jsonl'))\n .sort()\n .map((n) => ({ sessionId: n.replace(/\\.jsonl$/, ''), path: join(dir, n) }))\n}\n\nexport interface ClaudeUsageTotals {\n tokensIn: number | null\n tokensOut: number | null\n cacheRead: number | null\n cacheWrite: number | null\n}\n\nexport interface ClaudeTranscript {\n messages: ChatMessage[]\n usage: ClaudeUsageTotals\n /** Timestamp of the first conversation record; null = empty transcript. */\n startedAt: string | null\n endedAt: string | null\n /** The model that answered the last response (never Claude Code's `<synthetic>` error turn). */\n model: string | null\n /** Every parse or usage gap retained beside this semantic projection. */\n gaps: string[]\n}\n\nexport interface ReadClaudeTranscriptOptions {\n /**\n * Read a subagent's own transcript (`<session>/subagents/agent-<id>.jsonl`), whose records are\n * sidechain end to end, instead of skipping sidechain records.\n */\n readonly includeSidechain?: boolean\n}\n\nconst USAGE_FIELDS = [\n ['tokensIn', 'input'],\n ['tokensOut', 'output'],\n ['cacheRead', 'cacheRead'],\n ['cacheWrite', 'cacheWrite'],\n] as const\n\n/**\n * The messages+usage projection of a normalized session. A usage field is null when any answered\n * model call did not report it, so a partial sum is never mistaken for the session's usage.\n */\nfunction transcriptFromSession(session: HarnessSession): ClaudeTranscript {\n const gaps = session.integrity.gaps.filter((gap) =>\n /is not a JSON record|still being written/u.test(gap),\n )\n const answered = session.modelCalls.filter((call) => call.error === null)\n const usage: ClaudeUsageTotals = {\n tokensIn: null,\n tokensOut: null,\n cacheRead: null,\n cacheWrite: null,\n }\n if (answered.length > 0) {\n for (const [target, field] of USAGE_FIELDS) {\n let total: number | null = 0\n for (const call of answered) {\n const value = call.usage?.[field] ?? null\n if (value === null) {\n total = null\n gaps.push(`model call ${call.id}: ${field} usage unavailable`)\n break\n }\n total += value\n }\n usage[target] = total\n }\n }\n const model =\n [...answered].reverse().find((call) => call.servedModel !== null)?.servedModel ?? null\n return {\n messages: toChatMessages(session),\n usage,\n startedAt: session.startedAt,\n endedAt: session.endedAt,\n model,\n gaps,\n }\n}\n\n/** Read one transcript file. */\nexport async function readClaudeTranscript(\n path: string,\n options: ReadClaudeTranscriptOptions = {},\n): Promise<ClaudeTranscript> {\n const session = await claudeCodeReader.read(\n claudeCodeRefForFile(path, options.includeSidechain === true ? 'parent' : null),\n )\n return transcriptFromSession(session)\n}\n\n/** Parse retained JSONL text without another file or store; source gaps remain explicit. */\nexport function parseClaudeTranscript(\n raw: string,\n options: ReadClaudeTranscriptOptions = {},\n): ClaudeTranscript {\n const session = readSessionInput(\n 'claude-code',\n { text: raw },\n {\n parentNativeSessionId: options.includeSidechain === true ? 'parent' : null,\n label: 'retained transcript',\n },\n )\n return transcriptFromSession(session)\n}\n","/**\n * Codex rollout JSONL through the shared native-session reader. This module\n * projects its result onto rollout messages; it never parses native records,\n * discovers stores, judges an outcome, or makes an imported capture trainable.\n */\nimport {\n codexReader,\n codexRefForFile,\n type HarnessSession,\n type ReadOptions,\n readSessionInput,\n type SessionInputInit,\n toChatMessages,\n} from '@tangle-network/harness-sessions'\nimport type { ChatMessage } from '../schema'\n\n/** Normalized source evidence, with the existing canonical message projection. */\nexport type CodexRollout = Pick<\n HarnessSession,\n | 'nativeSessionId'\n | 'parentNativeSessionId'\n | 'startedAt'\n | 'endedAt'\n | 'usage'\n | 'ending'\n | 'integrity'\n | 'modelSource'\n> & {\n messages: ChatMessage[]\n /** Null when only turn_context names a model; that is configuration, not a response. */\n model: string | null\n requestedModel: string | null\n}\n\nfunction rolloutFromSession(session: HarnessSession): CodexRollout {\n const answered = session.modelCalls.filter((call) => call.error === null)\n const trustedModel =\n session.modelSource === 'provider-response' || session.modelSource === 'session-record'\n return {\n nativeSessionId: session.nativeSessionId,\n parentNativeSessionId: session.parentNativeSessionId,\n messages: toChatMessages(session),\n usage: session.usage,\n startedAt: session.startedAt,\n endedAt: session.endedAt,\n model: trustedModel\n ? ([...answered].reverse().find((call) => call.servedModel !== null)?.servedModel ?? null)\n : null,\n requestedModel:\n [...session.modelCalls].reverse().find((call) => call.requestedModel !== null)\n ?.requestedModel ?? null,\n modelSource: session.modelSource,\n ending: session.ending,\n integrity: session.integrity,\n }\n}\n\n/** Read one already-resolved native file; strict/recover behavior belongs to the SDK. */\nexport async function readCodexRollout(\n path: string,\n options: ReadOptions = {},\n): Promise<CodexRollout> {\n return rolloutFromSession(await codexReader.read(codexRefForFile(path), options))\n}\n\n/** Parse retained text through the same SDK fold, retaining source hashes and gaps. */\nexport function parseCodexRollout(\n raw: string,\n source: SessionInputInit = {},\n options: Pick<ReadOptions, 'corruption'> = {},\n): CodexRollout {\n return rolloutFromSession(readSessionInput('codex', { text: raw }, source, options))\n}\n","/**\n * OpenCode's SQLite store (~/.local/share/opencode/opencode.db) as canonical chat-with-tools\n * messages, through @tangle-network/harness-sessions: the one reader of harness sessions shared\n * with Discovery, agent-record, traces and the blog. The store is read from a private copy, never\n * in place, and a tool part that errored or never finished is read as what it is rather than\n * refused.\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport {\n type HarnessSession,\n opencodeReader,\n opencodeSessionsInStore,\n toChatMessages,\n} from '@tangle-network/harness-sessions'\nimport type { ChatMessage } from '../schema'\n\nexport const DEFAULT_OPENCODE_DB = join(homedir(), '.local', 'share', 'opencode', 'opencode.db')\n\n\n\n/** One session, normalized. */\nasync function readOpencodeSession(\n sessionId: string,\n db: string = DEFAULT_OPENCODE_DB,\n): Promise<HarnessSession> {\n const [ref] = await opencodeSessionsInStore(db, null, { nativeSessionId: sessionId })\n if (ref === undefined) throw new Error(`OpenCode session ${sessionId} is not in ${db}`)\n return opencodeReader.read(ref)\n}\n\n/** One session's canonical messages: each model step, then the results of its tool calls. */\nexport async function readOpencodeSessionMessages(\n sessionId: string,\n db: string = DEFAULT_OPENCODE_DB,\n): Promise<ChatMessage[]> {\n return toChatMessages(await readOpencodeSession(sessionId, db))\n}\n","/** Tinker RL Datum projection of the canonical rollout waist; no client or training loop. */\nimport { assessShareSafety, shareAllowed } from '../trace/redact'\nimport { isSplitEligible, type TrainingExportOptions } from './exporters'\nimport { defaultRolloutScrubber } from './release/scrub'\nimport { assertMinted, assertRewardGate, type MintedRolloutLine, type RolloutStep } from './schema'\n\n/** JSON wire projection of Tinker's text-only Datum; the consumer constructs SDK objects. */\nexport interface TinkerDatum {\n model_input: { chunks: Array<{ type: 'encoded_text'; tokens: number[] }> }\n loss_fn_inputs: {\n target_tokens: { data: number[]; dtype: 'int64'; shape: [number] }\n logprobs: { data: number[]; dtype: 'float32'; shape: [number] }\n advantages: { data: number[]; dtype: 'float32'; shape: [number] }\n }\n}\n\nexport interface TinkerDatumRow {\n /** Only this object goes to the Tinker SDK. Attribution stays with the caller. */\n datum: TinkerDatum\n rollout_id: string\n run_id: string\n instance_id: string\n step_index: number\n reward: number\n realness_gated: false\n realness_screened: boolean | null\n}\n\nexport interface TinkerExportOptions\n extends Pick<TrainingExportOptions, 'allowHeldOutTrainingData'> {\n /** Exact model identity of the captured tokenizer/sampling policy. */\n model: string\n /** Offline decoder for that model. Never re-tokenize or fabricate missing sampling data. */\n decodeTokens: (tokens: readonly number[]) => string\n /** Caller owns group baselines; a reward is not silently treated as an advantage. */\n advantageOf: (line: MintedRolloutLine, stepIndex: number) => number\n}\n\nfunction safeText(text: string, context: string): void {\n // Scrubbing text while retaining its original token ids would transmit the very bytes removed.\n if (\n defaultRolloutScrubber(text) !== text ||\n !shareAllowed(assessShareSafety(text, { profile: 'share' }))\n ) {\n throw new Error(`Tinker export: ${context} needs scrubbing; recapture approved token data`)\n }\n}\n\nfunction tokenIds(tokens: number[] | undefined, context: string): number[] {\n if (!tokens?.length || tokens.some((id) => !Number.isSafeInteger(id) || id < 0)) {\n throw new Error(`Tinker export: ${context} requires captured nonempty token ids`)\n }\n return [...tokens]\n}\n\nfunction projectStep(\n step: RolloutStep,\n line: MintedRolloutLine,\n stepIndex: number,\n options: TinkerExportOptions,\n): TinkerDatumRow {\n if (step.llm_call_count !== 1) {\n throw new Error(\n `Tinker export: ${line.rollout_id} step ${stepIndex} must name one captured model call`,\n )\n }\n const prompt = tokenIds(step.prompt_token_ids, 'prompt')\n const completion = tokenIds(step.completion_token_ids, 'completion')\n const logprobs = step.logprobs === undefined ? undefined : [...step.logprobs]\n if (\n !logprobs ||\n logprobs.length !== completion.length ||\n logprobs.some((p) => !Number.isFinite(Math.fround(p)) || p > 0)\n ) {\n throw new Error(\n `Tinker export: ${line.rollout_id} step ${stepIndex} needs aligned sampling logprobs`,\n )\n }\n safeText(options.decodeTokens(prompt), 'decoded prompt')\n safeText(options.decodeTokens(completion), 'decoded completion')\n const advantage = options.advantageOf(line, stepIndex)\n if (\n typeof advantage !== 'number' ||\n !Number.isFinite(advantage) ||\n !Number.isFinite(Math.fround(advantage))\n ) {\n throw new Error('Tinker export: advantage must be a finite number that fits float32')\n }\n const full = [...prompt, ...completion]\n safeText(options.decodeTokens(full), 'decoded sequence')\n const prefix = Array<number>(prompt.length - 1).fill(0)\n const length = full.length - 1\n return {\n datum: {\n model_input: { chunks: [{ type: 'encoded_text', tokens: full.slice(0, -1) }] },\n loss_fn_inputs: {\n target_tokens: { data: full.slice(1), dtype: 'int64', shape: [length] },\n logprobs: { data: [...prefix, ...logprobs], dtype: 'float32', shape: [length] },\n advantages: {\n data: [...prefix, ...completion.map(() => advantage)],\n dtype: 'float32',\n shape: [length],\n },\n },\n },\n rollout_id: line.rollout_id,\n run_id: line.run_id,\n instance_id: line.task.instance_id,\n step_index: stepIndex,\n reward: line.outcome.reward!,\n realness_gated: false,\n realness_screened: line.outcome.realness_screened ?? null,\n }\n}\n\n/**\n * Project known-reward completed search rollouts, including honest zero/negative rewards.\n * Unknown rewards, gated/lossy/incomplete runs and ineligible splits do not become training data.\n * Missing capture on an otherwise eligible model call refuses the batch, never invents tokens.\n * The caller retains the canonical ledger and owns Tinker sampling/forward_backward/optim_step.\n */\nexport function toTinkerDatumRows(\n lines: readonly MintedRolloutLine[],\n options: TinkerExportOptions,\n): TinkerDatumRow[] {\n if (!options.model) throw new Error('Tinker export: captured model identity is required')\n const rows: TinkerDatumRow[] = []\n const identities = new Set<string>()\n for (const supplied of lines) {\n const line = assertMinted(supplied, 'Tinker rollout')\n assertRewardGate(line, 'Tinker export')\n if (identities.has(line.rollout_id))\n throw new Error(`Tinker export: duplicate rollout ${line.rollout_id}`)\n identities.add(line.rollout_id)\n if (\n !isSplitEligible(line, { allowHeldOutTrainingData: options.allowHeldOutTrainingData }) ||\n line.outcome.reward === null ||\n line.outcome.realness_gated ||\n !line.outcome.is_completed ||\n line.outcome.is_truncated ||\n line.outcome.error !== null ||\n line.provenance.lossy_projection === true\n )\n continue\n if (!Number.isFinite(line.outcome.reward))\n throw new Error('Tinker export: reward must be finite')\n if (line.policy.model !== options.model)\n throw new Error('Tinker export: captured model identity differs')\n if (line.messages.some((message) => message.is_copied_context)) {\n throw new Error('Tinker export: copied context has no captured token mask')\n }\n const steps = line.steps\n if (!steps?.some((step) => step.kind === 'llm'))\n throw new Error('Tinker export: no captured model steps')\n safeText(\n JSON.stringify({ messages: line.messages, steps, tool_defs: line.tool_defs }),\n 'rollout content',\n )\n for (const [index, step] of steps.entries()) {\n if (step.kind === 'llm') rows.push(projectStep(step, line, index, options))\n }\n }\n return rows\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as RunRecord } from "./run-record-D2BFMPGl.js";
1
+ import { a as RunRecord } from "./run-record-pBlhZizT.js";
2
2
  /** Deployment observations join to evaluation records through their runId. */
3
3
  interface DeploymentOutcome {
4
4
  runId: string;
@@ -125,4 +125,4 @@ interface RubricPredictiveValidityReport {
125
125
  }
126
126
  declare function rubricPredictiveValidity(input: RubricPredictiveValidityInput): Promise<RubricPredictiveValidityReport>;
127
127
  export { RubricPredictiveValidityReport as a, CorrelationInterval as c, FileSystemOutcomeStore as d, FileSystemOutcomeStoreOptions as f, OutcomeStoreError as g, OutcomeStore as h, RubricPredictiveValidityInput as i, OutcomeReduction as l, OutcomeFilter as m, RubricOutcomeExclusion as n, RubricRanking as o, InMemoryOutcomeStore as p, RubricOutcomePair as r, rubricPredictiveValidity as s, OutcomeMetricSpec as t, DeploymentOutcome as u };
128
- //# sourceMappingURL=rubric-predictive-validity-B3RzbwOx.d.ts.map
128
+ //# sourceMappingURL=rubric-predictive-validity-Bbi88Aut.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rubric-predictive-validity-B3RzbwOx.d.ts","names":[],"sources":["../src/meta-eval/outcome-store.ts","../src/meta-eval/outcome-observations.ts","../src/meta-eval/rubric-predictive-validity.ts"],"mappings":";;UAIiB;EACf;EACA;;EAEA,SAAS;EACT,SAAS;;EAET;;UAGe;EACf;EACA;EACA;EACA;IAAU;IAAa;;EACvB;;UAGe;EACf,OAAO,SAAS,oBAAoB;EACpC,OAAO,gBAAgB,QAAQ;EAC/B,KAAK,SAAS,gBAAgB,QAAQ;;cAa3B,gCAAgC;UACnC;EAEF,OAAO,SAAS,oBAAoB;EAIpC,OAAO,gBAAgB,QAAQ;EAI/B,KAAK,SAAQ,gBAAqB,QAAQ;;UAOjC;EACf;;EAEA;;;cAIW,0BAA0B;WAEnB;WACA;WAEA;EAHA,YAAA,wCACA,cAChB,gBACgB;;;cAUP,kCAAkC;mBAC5B;mBACA;UACT;EAEI,YAAA,SAAS;EASf,OAAO,SAAS,oBAAoB;EA8BpC,OAAO,gBAAgB,QAAQ;EAI/B,KAAK,SAAQ,gBAAqB,QAAQ;UAqCxC;;KC/JE;UAEK;EACf;EACA;;UCWe;;EAEf;EACA;;UAGe;;EAEf,MAAM;EACN,UAAU;;EAEV,yBAAyB;;EAEzB;;EAEA;;EAEA;;EAEA;;EAEA;;UAGe;EACf;EACA;EACA,kBAAkB;EAClB;;EAEA;EACA;EACA,aAAa;EACb,cAAc;;EAEd;EACA;EACA,qBAAqB;;EAErB;;UAGe,sBAAsB,KAAK;;EAE1C;;UAGe;EACf;EACA;EACA,kBAAkB;;EAElB;EACA;;UAGe;EACf,gBAAgB;EAChB,OAAO;;EAEP,eAAe;;EAEf,QAAQ;;EAER;;EAEA;;EAEA;;iBAGoB,yBACpB,OAAO,gCACN,QAAQ"}
1
+ {"version":3,"file":"rubric-predictive-validity-Bbi88Aut.d.ts","names":[],"sources":["../src/meta-eval/outcome-store.ts","../src/meta-eval/outcome-observations.ts","../src/meta-eval/rubric-predictive-validity.ts"],"mappings":";;UAIiB;EACf;EACA;;EAEA,SAAS;EACT,SAAS;;EAET;;UAGe;EACf;EACA;EACA;EACA;IAAU;IAAa;;EACvB;;UAGe;EACf,OAAO,SAAS,oBAAoB;EACpC,OAAO,gBAAgB,QAAQ;EAC/B,KAAK,SAAS,gBAAgB,QAAQ;;cAa3B,gCAAgC;UACnC;EAEF,OAAO,SAAS,oBAAoB;EAIpC,OAAO,gBAAgB,QAAQ;EAI/B,KAAK,SAAQ,gBAAqB,QAAQ;;UAOjC;EACf;;EAEA;;;cAIW,0BAA0B;WAEnB;WACA;WAEA;EAHA,YAAA,wCACA,cAChB,gBACgB;;;cAUP,kCAAkC;mBAC5B;mBACA;UACT;EAEI,YAAA,SAAS;EASf,OAAO,SAAS,oBAAoB;EA8BpC,OAAO,gBAAgB,QAAQ;EAI/B,KAAK,SAAQ,gBAAqB,QAAQ;UAqCxC;;KC/JE;UAEK;EACf;EACA;;UCWe;;EAEf;EACA;;UAGe;;EAEf,MAAM;EACN,UAAU;;EAEV,yBAAyB;;EAEzB;;EAEA;;EAEA;;EAEA;;EAEA;;UAGe;EACf;EACA;EACA,kBAAkB;EAClB;;EAEA;EACA;EACA,aAAa;EACb,cAAc;;EAEd;EACA;EACA,qBAAqB;;EAErB;;UAGe,sBAAsB,KAAK;;EAE1C;;UAGe;EACf;EACA;EACA,kBAAkB;;EAElB;EACA;;UAGe;EACf,gBAAgB;EAChB,OAAO;;EAEP,eAAe;;EAEf,QAAQ;;EAER;;EAEA;;EAEA;;iBAGoB,yBACpB,OAAO,gCACN,QAAQ"}
@@ -1,4 +1,4 @@
1
- import { c as validateRunRecord } from "./run-record-CpLS4Uid.js";
1
+ import { c as validateRunRecord } from "./run-record-DmX_ESC5.js";
2
2
  import { ct as mean } from "./statistics-CvvC-MPv.js";
3
3
  // src/campaign/run-record.ts
4
4
  /**
@@ -217,4 +217,4 @@ function finiteMetrics(metrics) {
217
217
  }
218
218
  export { campaignCellToRunRecord as n, projectCampaignCellQuality as r, campaignCellCostProvenance as t };
219
219
 
220
- //# sourceMappingURL=run-record-CFbnkE1K.js.map
220
+ //# sourceMappingURL=run-record-DTTx9Ktr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-record-CFbnkE1K.js","names":[],"sources":["../src/campaign/run-record.ts"],"sourcesContent":["import type { AgentProfileCell } from '../agent-profile-cell'\nimport type { CostProvenance } from '../cost-ledger'\nimport type {\n JudgeScoresRecord,\n RunCostProvenance,\n RunOutcome,\n RunRecord,\n RunSearchCoordinates,\n RunSplitTag,\n RunTerminalOutcome,\n RunTraceRef,\n} from '../run-record'\nimport { validateRunRecord } from '../run-record'\nimport { mean } from '../statistics/mean'\nimport type { CampaignCellResult, JudgeScore } from './types'\n\ninterface CampaignCellRunRecordOptions {\n /** With `search`, this must be `searchCellRunId(search)`. */\n runId: string\n experimentId: string\n candidateId: string\n model: string\n promptHash: string\n configHash: string\n commitSha: string\n splitTag: RunSplitTag\n seed?: number\n scenarioId?: string\n /** Estimated total for a cell that proved no spend at all. A cell that\n * proved part of its spend keeps that floor instead. */\n defaultCostUsd?: number\n agentProfile?: AgentProfileCell\n raw?: Record<string, number>\n search?: RunSearchCoordinates\n traceRef?: RunTraceRef\n}\n\ninterface CampaignCellQualityProjection {\n score?: number\n judgeScores?: JudgeScoresRecord\n successfulJudgeScores: Record<string, JudgeScore>\n failedJudges: string[]\n raw: Record<string, number>\n}\n\n/**\n * A campaign cell carried a judge score without a `dimensions` record.\n *\n * Two exported types share the name `JudgeScore`: the campaign verdict\n * (`{ dimensions, composite, notes }` from `@tangle-network/agent-eval/campaign`)\n * and the root export's flat per-dimension row (`{ judgeName, dimension, score }`\n * from `@tangle-network/agent-eval`). Campaign aggregation accepts only the\n * campaign shape; the flat shape previously crashed here with an opaque\n * TypeError deep inside aggregation.\n */\nexport class CampaignJudgeScoreShapeError extends TypeError {\n constructor(judgeName: string) {\n super(\n `campaign cell judge '${judgeName}' carries a score without a 'dimensions' record. ` +\n `Use the campaign JudgeScore ({ dimensions, composite, notes }) from ` +\n `'@tangle-network/agent-eval/campaign'; the root export's JudgeScore ` +\n `({ judgeName, dimension, score }) is a different type with the same name.`,\n )\n this.name = 'CampaignJudgeScoreShapeError'\n }\n}\n\ninterface CampaignCellExecutionEvidence {\n terminalOutcome: RunTerminalOutcome\n executionErrorCount?: number\n judgeErrorCount?: number\n unclassifiedErrorCount?: number\n terminalFailureReason?: string\n}\n\n/**\n * Project one campaign cell into the canonical run format.\n *\n * A dispatch error establishes terminal execution failure. A judge error only\n * establishes that quality measurement failed after dispatch completed.\n * Failures without a stage remain unknown. No failure becomes a zero-quality\n * label.\n */\nexport function campaignCellToRunRecord<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n options: CampaignCellRunRecordOptions,\n): RunRecord {\n const quality = projectCampaignCellQuality(cell)\n const execution = campaignCellExecutionEvidence(cell)\n const judgeErrorCount = Math.max(\n quality.raw.judge_error_count ?? 0,\n execution.judgeErrorCount ?? 0,\n )\n const costProvenance = campaignCellRunCostProvenance(cell, options.defaultCostUsd)\n const costUsd = costProvenance.usd\n const raw: Record<string, number> = {\n ...finiteMetrics(options.raw),\n ...quality.raw,\n rep: cell.rep,\n duration_ms: cell.durationMs,\n ...(costUsd === null ? {} : { cost_usd: costUsd }),\n tokens_input: cell.tokenUsage.input,\n tokens_output: cell.tokenUsage.output,\n tokens_known: cell.tokenUsage.tokensKnown === false ? 0 : 1,\n latency_ms: cell.durationMs,\n ...(execution.executionErrorCount === undefined\n ? {}\n : { execution_error_count: execution.executionErrorCount }),\n ...(judgeErrorCount > 0 ? { judge_error_count: judgeErrorCount } : {}),\n ...(execution.unclassifiedErrorCount === undefined\n ? {}\n : { unclassified_error_count: execution.unclassifiedErrorCount }),\n }\n if (typeof cell.generation === 'number') raw.generation = cell.generation\n if (cell.tokenUsage.reasoning !== undefined) {\n raw.tokens_reasoning = cell.tokenUsage.reasoning\n }\n if (cell.tokenUsage.cached !== undefined) raw.tokens_cached = cell.tokenUsage.cached\n if (cell.tokenUsage.cacheWrite !== undefined) {\n raw.tokens_cache_write = cell.tokenUsage.cacheWrite\n }\n if (cell.tokenUsage.tokensKnown !== false && costUsd !== null && costUsd > 0) {\n raw.tokens_per_dollar = (cell.tokenUsage.input + cell.tokenUsage.output) / costUsd\n }\n if (costUsd !== null && quality.score !== undefined && quality.score > 0.01) {\n raw.cost_per_quality = costUsd / quality.score\n }\n\n const outcome: RunOutcome = {\n raw,\n ...(quality.judgeScores ? { judgeScores: quality.judgeScores } : {}),\n }\n if (quality.score !== undefined) {\n if (options.splitTag === 'holdout') outcome.holdoutScore = quality.score\n else outcome.searchScore = quality.score\n }\n\n return validateRunRecord({\n runId: options.runId,\n experimentId: options.experimentId,\n candidateId: options.candidateId,\n seed: options.seed ?? cell.seed,\n model: options.model,\n promptHash: options.promptHash,\n configHash: options.configHash,\n commitSha: options.commitSha,\n wallMs: cell.durationMs,\n costUsd,\n costProvenance,\n tokenUsage: { ...cell.tokenUsage },\n terminalOutcome: execution.terminalOutcome,\n ...(execution.terminalFailureReason\n ? { terminalFailureReason: execution.terminalFailureReason }\n : {}),\n outcome,\n splitTag: options.splitTag,\n scenarioId: options.scenarioId ?? cell.scenarioId,\n ...(options.agentProfile ? { agentProfile: options.agentProfile } : {}),\n ...(options.search ? { search: options.search } : {}),\n ...(options.traceRef ? { traceRef: options.traceRef } : {}),\n })\n}\n\n/**\n * A cell's cost as a RunRecord states it. An uncaptured cell's `costUsd` is\n * the spend its receipts proved, so a positive one is the run's floor. The\n * caller's `defaultCostUsd` stands in only when nothing was proved: a proven\n * floor is never replaced by a guess.\n */\nfunction campaignCellRunCostProvenance<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n defaultCostUsd: number | undefined,\n): RunCostProvenance {\n const provenance = campaignCellCostProvenance(cell)\n if (provenance.kind !== 'uncaptured') return provenance\n if (cell.costUsd > 0) return { kind: 'lower-bound', usd: null, knownLowerBoundUsd: cell.costUsd }\n return defaultCostUsd === undefined ? provenance : { kind: 'estimated', usd: defaultCostUsd }\n}\n\n/**\n * Validate the cost fields that cross campaign cache and RunRecord boundaries.\n * `costUsd` is a known subtotal for uncaptured cells, but it must equal the\n * authoritative total whenever that total is observed or estimated.\n */\nexport function campaignCellCostProvenance<TArtifact>(\n cell: Pick<CampaignCellResult<TArtifact>, 'cellId' | 'costUsd' | 'costProvenance'>,\n): CostProvenance {\n if (!Number.isFinite(cell.costUsd) || cell.costUsd < 0) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid costUsd`)\n }\n const provenance = cell.costProvenance\n if (!provenance || typeof provenance !== 'object') {\n throw new Error(`campaign cell '${cell.cellId}' has no costProvenance`)\n }\n if (provenance.kind === 'uncaptured') {\n if (provenance.usd !== null) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid uncaptured costProvenance`)\n }\n return { kind: 'uncaptured', usd: null }\n }\n if (\n (provenance.kind !== 'observed' && provenance.kind !== 'estimated') ||\n !Number.isFinite(provenance.usd) ||\n provenance.usd < 0\n ) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid costProvenance`)\n }\n if (provenance.usd !== cell.costUsd) {\n throw new Error(`campaign cell '${cell.cellId}' has costUsd inconsistent with costProvenance`)\n }\n return { kind: provenance.kind, usd: provenance.usd }\n}\n\nfunction campaignCellExecutionEvidence<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellExecutionEvidence {\n if (cell.errorStage === 'dispatch') {\n return {\n terminalOutcome: 'failed',\n executionErrorCount: 1,\n ...(cell.error ? { terminalFailureReason: cell.error } : {}),\n }\n }\n if (cell.errorStage === 'judge') {\n return {\n terminalOutcome: 'succeeded',\n executionErrorCount: 0,\n judgeErrorCount: 1,\n }\n }\n if (!cell.error) {\n return { terminalOutcome: 'succeeded', executionErrorCount: 0 }\n }\n return {\n terminalOutcome: 'unknown',\n unclassifiedErrorCount: 1,\n }\n}\n\n/**\n * Produce the only task-quality view used by campaign aggregates and exports.\n *\n * Successful judge results remain available for diagnosis after another judge\n * fails, but a task score exists only for an error-free cell whose reported\n * judge values are all finite.\n */\nexport function projectCampaignCellQuality<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellQualityProjection {\n if (cell.errorStage === 'dispatch') {\n return { successfulJudgeScores: {}, failedJudges: [], raw: {} }\n }\n\n const perJudge: Record<string, Record<string, number>> = {}\n const successfulJudgeScores: Record<string, JudgeScore> = {}\n const dimensionValues = new Map<string, number[]>()\n const composites: number[] = []\n const notes: string[] = []\n const failedJudges = new Set<string>(\n cell.errorStage === 'judge' ? [cell.errorJudge ?? 'unknown-judge'] : [],\n )\n const raw: Record<string, number> = {}\n\n for (const [judgeName, score] of Object.entries(cell.judgeScores)) {\n const dimensionsShape = (score as { dimensions?: unknown }).dimensions\n if (\n typeof dimensionsShape !== 'object' ||\n dimensionsShape === null ||\n Array.isArray(dimensionsShape)\n ) {\n throw new CampaignJudgeScoreShapeError(judgeName)\n }\n const finiteDimensions = Object.values(score.dimensions).every(Number.isFinite)\n if (score.failed || !Number.isFinite(score.composite) || !finiteDimensions) {\n failedJudges.add(judgeName)\n continue\n }\n\n composites.push(score.composite)\n successfulJudgeScores[judgeName] = score\n const dimensions = { ...score.dimensions }\n perJudge[judgeName] = dimensions\n for (const [dimension, value] of Object.entries(dimensions)) {\n raw[`${judgeName}.${dimension}`] = value\n const values = dimensionValues.get(dimension) ?? []\n values.push(value)\n dimensionValues.set(dimension, values)\n }\n if (score.notes) notes.push(`${judgeName}: ${score.notes}`)\n for (const failedJudge of score.failedJudges ?? []) {\n failedJudges.add(`${judgeName}/${failedJudge}`)\n }\n }\n\n if (failedJudges.size > 0) raw.judge_error_count = failedJudges.size\n const sortedFailedJudges = [...failedJudges].sort()\n if (composites.length === 0) {\n return {\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n raw,\n }\n }\n\n const composite = mean(composites)\n const perDimMean = Object.fromEntries(\n [...dimensionValues.entries()].map(([dimension, values]) => [dimension, mean(values)]),\n )\n const complete =\n cell.error === undefined && cell.errorStage === undefined && failedJudges.size === 0\n if (complete) raw.composite = composite\n\n return {\n ...(complete ? { score: composite } : {}),\n raw,\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n judgeScores: {\n perJudge,\n perDimMean,\n composite,\n ...(sortedFailedJudges.length > 0 ? { failedJudges: sortedFailedJudges } : {}),\n ...(notes.length > 0 ? { notes: notes.join(' | ') } : {}),\n },\n }\n}\n\nfunction finiteMetrics(metrics: Record<string, number> | undefined): Record<string, number> {\n const finite: Record<string, number> = {}\n for (const [key, value] of Object.entries(metrics ?? {})) {\n if (Number.isFinite(value)) finite[key] = value\n }\n return finite\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-record-DTTx9Ktr.js","names":[],"sources":["../src/campaign/run-record.ts"],"sourcesContent":["import type { AgentProfileCell } from '../agent-profile-cell'\nimport type { CostProvenance } from '../cost-ledger'\nimport type {\n JudgeScoresRecord,\n RunCostProvenance,\n RunOutcome,\n RunRecord,\n RunSearchCoordinates,\n RunSplitTag,\n RunTerminalOutcome,\n RunTraceRef,\n} from '../run-record'\nimport { validateRunRecord } from '../run-record'\nimport { mean } from '../statistics/mean'\nimport type { CampaignCellResult, JudgeScore } from './types'\n\ninterface CampaignCellRunRecordOptions {\n /** With `search`, this must be `searchCellRunId(search)`. */\n runId: string\n experimentId: string\n candidateId: string\n model: string\n promptHash: string\n configHash: string\n commitSha: string\n splitTag: RunSplitTag\n seed?: number\n scenarioId?: string\n /** Estimated total for a cell that proved no spend at all. A cell that\n * proved part of its spend keeps that floor instead. */\n defaultCostUsd?: number\n agentProfile?: AgentProfileCell\n raw?: Record<string, number>\n search?: RunSearchCoordinates\n traceRef?: RunTraceRef\n}\n\ninterface CampaignCellQualityProjection {\n score?: number\n judgeScores?: JudgeScoresRecord\n successfulJudgeScores: Record<string, JudgeScore>\n failedJudges: string[]\n raw: Record<string, number>\n}\n\n/**\n * A campaign cell carried a judge score without a `dimensions` record.\n *\n * Two exported types share the name `JudgeScore`: the campaign verdict\n * (`{ dimensions, composite, notes }` from `@tangle-network/agent-eval/campaign`)\n * and the root export's flat per-dimension row (`{ judgeName, dimension, score }`\n * from `@tangle-network/agent-eval`). Campaign aggregation accepts only the\n * campaign shape; the flat shape previously crashed here with an opaque\n * TypeError deep inside aggregation.\n */\nexport class CampaignJudgeScoreShapeError extends TypeError {\n constructor(judgeName: string) {\n super(\n `campaign cell judge '${judgeName}' carries a score without a 'dimensions' record. ` +\n `Use the campaign JudgeScore ({ dimensions, composite, notes }) from ` +\n `'@tangle-network/agent-eval/campaign'; the root export's JudgeScore ` +\n `({ judgeName, dimension, score }) is a different type with the same name.`,\n )\n this.name = 'CampaignJudgeScoreShapeError'\n }\n}\n\ninterface CampaignCellExecutionEvidence {\n terminalOutcome: RunTerminalOutcome\n executionErrorCount?: number\n judgeErrorCount?: number\n unclassifiedErrorCount?: number\n terminalFailureReason?: string\n}\n\n/**\n * Project one campaign cell into the canonical run format.\n *\n * A dispatch error establishes terminal execution failure. A judge error only\n * establishes that quality measurement failed after dispatch completed.\n * Failures without a stage remain unknown. No failure becomes a zero-quality\n * label.\n */\nexport function campaignCellToRunRecord<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n options: CampaignCellRunRecordOptions,\n): RunRecord {\n const quality = projectCampaignCellQuality(cell)\n const execution = campaignCellExecutionEvidence(cell)\n const judgeErrorCount = Math.max(\n quality.raw.judge_error_count ?? 0,\n execution.judgeErrorCount ?? 0,\n )\n const costProvenance = campaignCellRunCostProvenance(cell, options.defaultCostUsd)\n const costUsd = costProvenance.usd\n const raw: Record<string, number> = {\n ...finiteMetrics(options.raw),\n ...quality.raw,\n rep: cell.rep,\n duration_ms: cell.durationMs,\n ...(costUsd === null ? {} : { cost_usd: costUsd }),\n tokens_input: cell.tokenUsage.input,\n tokens_output: cell.tokenUsage.output,\n tokens_known: cell.tokenUsage.tokensKnown === false ? 0 : 1,\n latency_ms: cell.durationMs,\n ...(execution.executionErrorCount === undefined\n ? {}\n : { execution_error_count: execution.executionErrorCount }),\n ...(judgeErrorCount > 0 ? { judge_error_count: judgeErrorCount } : {}),\n ...(execution.unclassifiedErrorCount === undefined\n ? {}\n : { unclassified_error_count: execution.unclassifiedErrorCount }),\n }\n if (typeof cell.generation === 'number') raw.generation = cell.generation\n if (cell.tokenUsage.reasoning !== undefined) {\n raw.tokens_reasoning = cell.tokenUsage.reasoning\n }\n if (cell.tokenUsage.cached !== undefined) raw.tokens_cached = cell.tokenUsage.cached\n if (cell.tokenUsage.cacheWrite !== undefined) {\n raw.tokens_cache_write = cell.tokenUsage.cacheWrite\n }\n if (cell.tokenUsage.tokensKnown !== false && costUsd !== null && costUsd > 0) {\n raw.tokens_per_dollar = (cell.tokenUsage.input + cell.tokenUsage.output) / costUsd\n }\n if (costUsd !== null && quality.score !== undefined && quality.score > 0.01) {\n raw.cost_per_quality = costUsd / quality.score\n }\n\n const outcome: RunOutcome = {\n raw,\n ...(quality.judgeScores ? { judgeScores: quality.judgeScores } : {}),\n }\n if (quality.score !== undefined) {\n if (options.splitTag === 'holdout') outcome.holdoutScore = quality.score\n else outcome.searchScore = quality.score\n }\n\n return validateRunRecord({\n runId: options.runId,\n experimentId: options.experimentId,\n candidateId: options.candidateId,\n seed: options.seed ?? cell.seed,\n model: options.model,\n promptHash: options.promptHash,\n configHash: options.configHash,\n commitSha: options.commitSha,\n wallMs: cell.durationMs,\n costUsd,\n costProvenance,\n tokenUsage: { ...cell.tokenUsage },\n terminalOutcome: execution.terminalOutcome,\n ...(execution.terminalFailureReason\n ? { terminalFailureReason: execution.terminalFailureReason }\n : {}),\n outcome,\n splitTag: options.splitTag,\n scenarioId: options.scenarioId ?? cell.scenarioId,\n ...(options.agentProfile ? { agentProfile: options.agentProfile } : {}),\n ...(options.search ? { search: options.search } : {}),\n ...(options.traceRef ? { traceRef: options.traceRef } : {}),\n })\n}\n\n/**\n * A cell's cost as a RunRecord states it. An uncaptured cell's `costUsd` is\n * the spend its receipts proved, so a positive one is the run's floor. The\n * caller's `defaultCostUsd` stands in only when nothing was proved: a proven\n * floor is never replaced by a guess.\n */\nfunction campaignCellRunCostProvenance<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n defaultCostUsd: number | undefined,\n): RunCostProvenance {\n const provenance = campaignCellCostProvenance(cell)\n if (provenance.kind !== 'uncaptured') return provenance\n if (cell.costUsd > 0) return { kind: 'lower-bound', usd: null, knownLowerBoundUsd: cell.costUsd }\n return defaultCostUsd === undefined ? provenance : { kind: 'estimated', usd: defaultCostUsd }\n}\n\n/**\n * Validate the cost fields that cross campaign cache and RunRecord boundaries.\n * `costUsd` is a known subtotal for uncaptured cells, but it must equal the\n * authoritative total whenever that total is observed or estimated.\n */\nexport function campaignCellCostProvenance<TArtifact>(\n cell: Pick<CampaignCellResult<TArtifact>, 'cellId' | 'costUsd' | 'costProvenance'>,\n): CostProvenance {\n if (!Number.isFinite(cell.costUsd) || cell.costUsd < 0) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid costUsd`)\n }\n const provenance = cell.costProvenance\n if (!provenance || typeof provenance !== 'object') {\n throw new Error(`campaign cell '${cell.cellId}' has no costProvenance`)\n }\n if (provenance.kind === 'uncaptured') {\n if (provenance.usd !== null) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid uncaptured costProvenance`)\n }\n return { kind: 'uncaptured', usd: null }\n }\n if (\n (provenance.kind !== 'observed' && provenance.kind !== 'estimated') ||\n !Number.isFinite(provenance.usd) ||\n provenance.usd < 0\n ) {\n throw new Error(`campaign cell '${cell.cellId}' has invalid costProvenance`)\n }\n if (provenance.usd !== cell.costUsd) {\n throw new Error(`campaign cell '${cell.cellId}' has costUsd inconsistent with costProvenance`)\n }\n return { kind: provenance.kind, usd: provenance.usd }\n}\n\nfunction campaignCellExecutionEvidence<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellExecutionEvidence {\n if (cell.errorStage === 'dispatch') {\n return {\n terminalOutcome: 'failed',\n executionErrorCount: 1,\n ...(cell.error ? { terminalFailureReason: cell.error } : {}),\n }\n }\n if (cell.errorStage === 'judge') {\n return {\n terminalOutcome: 'succeeded',\n executionErrorCount: 0,\n judgeErrorCount: 1,\n }\n }\n if (!cell.error) {\n return { terminalOutcome: 'succeeded', executionErrorCount: 0 }\n }\n return {\n terminalOutcome: 'unknown',\n unclassifiedErrorCount: 1,\n }\n}\n\n/**\n * Produce the only task-quality view used by campaign aggregates and exports.\n *\n * Successful judge results remain available for diagnosis after another judge\n * fails, but a task score exists only for an error-free cell whose reported\n * judge values are all finite.\n */\nexport function projectCampaignCellQuality<TArtifact>(\n cell: CampaignCellResult<TArtifact>,\n): CampaignCellQualityProjection {\n if (cell.errorStage === 'dispatch') {\n return { successfulJudgeScores: {}, failedJudges: [], raw: {} }\n }\n\n const perJudge: Record<string, Record<string, number>> = {}\n const successfulJudgeScores: Record<string, JudgeScore> = {}\n const dimensionValues = new Map<string, number[]>()\n const composites: number[] = []\n const notes: string[] = []\n const failedJudges = new Set<string>(\n cell.errorStage === 'judge' ? [cell.errorJudge ?? 'unknown-judge'] : [],\n )\n const raw: Record<string, number> = {}\n\n for (const [judgeName, score] of Object.entries(cell.judgeScores)) {\n const dimensionsShape = (score as { dimensions?: unknown }).dimensions\n if (\n typeof dimensionsShape !== 'object' ||\n dimensionsShape === null ||\n Array.isArray(dimensionsShape)\n ) {\n throw new CampaignJudgeScoreShapeError(judgeName)\n }\n const finiteDimensions = Object.values(score.dimensions).every(Number.isFinite)\n if (score.failed || !Number.isFinite(score.composite) || !finiteDimensions) {\n failedJudges.add(judgeName)\n continue\n }\n\n composites.push(score.composite)\n successfulJudgeScores[judgeName] = score\n const dimensions = { ...score.dimensions }\n perJudge[judgeName] = dimensions\n for (const [dimension, value] of Object.entries(dimensions)) {\n raw[`${judgeName}.${dimension}`] = value\n const values = dimensionValues.get(dimension) ?? []\n values.push(value)\n dimensionValues.set(dimension, values)\n }\n if (score.notes) notes.push(`${judgeName}: ${score.notes}`)\n for (const failedJudge of score.failedJudges ?? []) {\n failedJudges.add(`${judgeName}/${failedJudge}`)\n }\n }\n\n if (failedJudges.size > 0) raw.judge_error_count = failedJudges.size\n const sortedFailedJudges = [...failedJudges].sort()\n if (composites.length === 0) {\n return {\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n raw,\n }\n }\n\n const composite = mean(composites)\n const perDimMean = Object.fromEntries(\n [...dimensionValues.entries()].map(([dimension, values]) => [dimension, mean(values)]),\n )\n const complete =\n cell.error === undefined && cell.errorStage === undefined && failedJudges.size === 0\n if (complete) raw.composite = composite\n\n return {\n ...(complete ? { score: composite } : {}),\n raw,\n successfulJudgeScores,\n failedJudges: sortedFailedJudges,\n judgeScores: {\n perJudge,\n perDimMean,\n composite,\n ...(sortedFailedJudges.length > 0 ? { failedJudges: sortedFailedJudges } : {}),\n ...(notes.length > 0 ? { notes: notes.join(' | ') } : {}),\n },\n }\n}\n\nfunction finiteMetrics(metrics: Record<string, number> | undefined): Record<string, number> {\n const finite: Record<string, number> = {}\n for (const [key, value] of Object.entries(metrics ?? {})) {\n if (Number.isFinite(value)) finite[key] = value\n }\n return finite\n}\n"],"mappings":"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"}
@@ -238,10 +238,10 @@ function validateJudgeScores(value, path) {
238
238
  if (rec.notes !== void 0 && typeof rec.notes !== "string") throw new RunRecordValidationError("notes must be a string", `${path}.notes`);
239
239
  }
240
240
  /**
241
- * Snapshot check for provider model identifiers. Accepts ISO and compact
242
- * dates, Router's `-MMDD` snapshots, one opaque `@token`, and Vertex-style
243
- * `:date-token` suffixes. Routing selectors such as `@preset/name` are not
244
- * immutable model identities.
241
+ * Snapshot check for provider model identifiers. Accepts ISO and compact dates, Router's `-MMDD`
242
+ * snapshots, one opaque `@token`, Vertex-style `:date-token` suffixes, and Claude ids from 4.6 on,
243
+ * which Anthropic serves under one fixed id with no dated form (`claude-sonnet-5-5`). Routing
244
+ * selectors such as `@preset/name` and older Claude aliases (`claude-sonnet-4-5`) are not pinned.
245
245
  */
246
246
  function modelHasSnapshot(model) {
247
247
  if (model.length === 0 || model.trim() !== model) return false;
@@ -257,6 +257,8 @@ function modelHasSnapshot(model) {
257
257
  if (compactDate && validSnapshotDate(compactDate[1], compactDate[2], compactDate[3])) return true;
258
258
  const routerDate = model.match(/-(\d{2})(\d{2})$/u);
259
259
  if (routerDate && validSnapshotDate(void 0, routerDate[1], routerDate[2])) return true;
260
+ const claude = /(?:^|\/)claude-[a-z]+-(\d{1,2})(?:-(\d{1,2}))?$/u.exec(model);
261
+ if (claude && Number(claude[1]) * 100 + Number(claude[2] ?? 0) >= 406) return true;
260
262
  return /:date-[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/u.test(model);
261
263
  }
262
264
  function validSnapshotDate(year, month, day) {
@@ -282,4 +284,4 @@ function validSnapshotDate(year, month, day) {
282
284
  }
283
285
  export { parseRunRecordSafe as a, validateRunRecord as c, modelHasSnapshot as i, UNKNOWN_MODEL as n, runTaskScore as o, isRunRecord as r, searchCellRunId as s, RunRecordValidationError as t };
284
286
 
285
- //# sourceMappingURL=run-record-CpLS4Uid.js.map
287
+ //# sourceMappingURL=run-record-DmX_ESC5.js.map