@iowarp/clio-coder 0.3.3 → 0.3.6

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 (370) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/CONTRIBUTING.md +7 -7
  3. package/README.md +3 -3
  4. package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
  5. package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
  10. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  11. package/dist/chunk-3BPUFZDL.js +37 -0
  12. package/dist/chunk-43AOLP7E.js +375 -0
  13. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  14. package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
  15. package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
  16. package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
  17. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  18. package/dist/chunk-AOCYTWAV.js +449 -0
  19. package/dist/chunk-CFGTUFWB.js +67 -0
  20. package/dist/chunk-CJUB2JJ2.js +1478 -0
  21. package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
  22. package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
  23. package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
  24. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  25. package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
  26. package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
  27. package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
  28. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  29. package/dist/chunk-FYYLNIL5.js +313 -0
  30. package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
  31. package/dist/chunk-GEYXPTRF.js +613 -0
  32. package/dist/chunk-GOXNB3AO.js +261 -0
  33. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  34. package/dist/chunk-HWUFFB6L.js +83 -0
  35. package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
  36. package/dist/chunk-K7VKOLQQ.js +15 -0
  37. package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
  38. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  39. package/dist/chunk-LCGCVYZ4.js +57 -0
  40. package/dist/chunk-LL4KHSZI.js +22 -0
  41. package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
  42. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  43. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  44. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  45. package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
  46. package/dist/chunk-ODFEOB4F.js +1082 -0
  47. package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
  48. package/dist/chunk-OZNBF4L3.js +23 -0
  49. package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
  50. package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
  51. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  52. package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
  53. package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
  54. package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
  55. package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
  56. package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
  57. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  58. package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
  59. package/dist/chunk-TZSKNMZG.js +434 -0
  60. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  61. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  62. package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
  63. package/dist/chunk-W6GROXXM.js +69 -0
  64. package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
  65. package/dist/chunk-WHJYKASB.js +677 -0
  66. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  67. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  68. package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
  69. package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
  70. package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
  71. package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
  72. package/dist/chunk-ZGVHUX3M.js +66 -0
  73. package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
  74. package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
  75. package/dist/chunk-ZZMN5OM4.js +122 -0
  76. package/dist/cli/index.js +34 -30
  77. package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
  78. package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
  79. package/dist/codewiki/build-worker.js +4 -4
  80. package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
  81. package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
  82. package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
  83. package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
  84. package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
  85. package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
  86. package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
  87. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  88. package/dist/context-working-set-UX5KEP4J.js +1553 -0
  89. package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
  90. package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
  91. package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
  92. package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
  93. package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
  94. package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
  95. package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
  96. package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
  97. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
  98. package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
  99. package/dist/memory-7YKKR6UC.js +467 -0
  100. package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
  101. package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
  102. package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
  103. package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
  104. package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
  105. package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
  106. package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
  107. package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
  108. package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
  109. package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
  110. package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
  111. package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
  112. package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
  113. package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
  114. package/dist/verifiers-NCBTHHN2.js +1220 -0
  115. package/dist/verify-X5HDROLA.js +25 -0
  116. package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
  117. package/dist/worker/entry.js +90 -70
  118. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  119. package/docs/README.md +8 -7
  120. package/docs/acp.md +1 -1
  121. package/docs/alcf-provider.md +1 -1
  122. package/docs/architecture.md +2 -2
  123. package/docs/artifact-placement.md +1 -2
  124. package/docs/artifact-versions.md +1 -1
  125. package/docs/built-in-agents.md +1 -1
  126. package/docs/capacity-and-scheduling.md +1 -1
  127. package/docs/commands-and-modes.md +60 -26
  128. package/docs/config-knobs-audit.md +1 -2
  129. package/docs/configuration-and-targets.md +26 -1
  130. package/docs/context-engine.md +67 -13
  131. package/docs/context-working-set.md +194 -0
  132. package/docs/development-pipeline.md +1 -1
  133. package/docs/documentation-coverage.md +6 -6
  134. package/docs/documentation-guide.md +7 -6
  135. package/docs/environment-variables.md +2 -1
  136. package/docs/eval-runner.md +1 -1
  137. package/docs/evals-internal.md +4 -32
  138. package/docs/evidence-and-memory.md +139 -7
  139. package/docs/evolution.md +1 -1
  140. package/docs/exit-codes-and-output.md +1 -1
  141. package/docs/extensions-and-sharing.md +2 -2
  142. package/docs/fleet-dispatch.md +49 -8
  143. package/docs/glossary.md +21 -1
  144. package/docs/installation-and-lifecycle.md +2 -2
  145. package/docs/middleware-and-components.md +19 -2
  146. package/docs/model-catalog.md +7 -9
  147. package/docs/observability.md +4 -4
  148. package/docs/proactive-memory.md +26 -16
  149. package/docs/prompt-envelope-and-tools.md +7 -5
  150. package/docs/provider-adapter-cookbook.md +1 -1
  151. package/docs/release-cut-checklist.md +43 -40
  152. package/docs/safety-model.md +49 -8
  153. package/docs/scientific-validation.md +21 -3
  154. package/docs/session-lifecycle.md +3 -3
  155. package/docs/skills-marketplace.md +1 -1
  156. package/docs/tool-usage.md +79 -12
  157. package/docs/trace-store.md +1 -1
  158. package/docs/troubleshooting.md +1 -1
  159. package/docs/tui-design.md +38 -4
  160. package/docs/worker-dispatch-mechanics.md +11 -1
  161. package/package.json +13 -13
  162. package/skills/meta/clio-test/SKILL.md +20 -17
  163. package/skills/meta/clio-test/evals.md +3 -3
  164. package/skills/meta/clio-test/references/harness.md +35 -6
  165. package/skills/meta/clio-test/references/test-map.md +20 -10
  166. package/skills/registry.yaml +2 -2
  167. package/skills/skill-marketplace.json +1 -1
  168. package/src/cli/agents.ts +2 -3
  169. package/src/cli/argv.ts +14 -1
  170. package/src/cli/context-working-set.ts +513 -0
  171. package/src/cli/context.ts +8 -0
  172. package/src/cli/evidence.ts +20 -2
  173. package/src/cli/fleet.ts +15 -0
  174. package/src/cli/index.ts +5 -1
  175. package/src/cli/memory.ts +272 -10
  176. package/src/cli/modes/json-stream.ts +2 -2
  177. package/src/cli/modes/print.ts +12 -1
  178. package/src/cli/run.ts +22 -2
  179. package/src/cli/targets.ts +12 -3
  180. package/src/cli/usage.ts +55 -7
  181. package/src/cli/verifiers.ts +325 -0
  182. package/src/core/bash-exec.ts +39 -14
  183. package/src/core/bus-events.ts +22 -4
  184. package/src/core/config.ts +54 -0
  185. package/src/core/defaults.ts +50 -3
  186. package/src/core/response-model-id.ts +134 -0
  187. package/src/core/toml.ts +62 -0
  188. package/src/core/verification-scripts.ts +6 -0
  189. package/src/core/workspace-files.ts +0 -1
  190. package/src/domains/agents/builtins/architect.md +1 -1
  191. package/src/domains/agents/builtins/verifier.md +3 -0
  192. package/src/domains/agents/catalog.ts +5 -4
  193. package/src/domains/agents/recipe.ts +54 -14
  194. package/src/domains/agents/result-contract.ts +7 -4
  195. package/src/domains/config/classify.ts +1 -0
  196. package/src/domains/context/bootstrap.ts +36 -27
  197. package/src/domains/context/project-metadata.ts +19 -63
  198. package/src/domains/context/prompt-context.ts +8 -0
  199. package/src/domains/context/working-set/contract.ts +161 -0
  200. package/src/domains/context/working-set/defaults.ts +28 -0
  201. package/src/domains/context/working-set/engine.ts +203 -0
  202. package/src/domains/context/working-set/fold.ts +62 -0
  203. package/src/domains/context/working-set/horizon.ts +38 -0
  204. package/src/domains/context/working-set/marker.ts +103 -0
  205. package/src/domains/context/working-set/path-index.ts +436 -0
  206. package/src/domains/context/working-set/payload.ts +152 -0
  207. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  208. package/src/domains/context/working-set/policies/index.ts +20 -0
  209. package/src/domains/context/working-set/policies/structural.ts +160 -0
  210. package/src/domains/context/working-set/project.ts +132 -0
  211. package/src/domains/context/working-set/protect.ts +109 -0
  212. package/src/domains/context/working-set/recall.ts +177 -0
  213. package/src/domains/context/working-set/replay/controls.ts +112 -0
  214. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  215. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  216. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  217. package/src/domains/context/working-set/replay/report.ts +139 -0
  218. package/src/domains/context/working-set/replay/runner.ts +325 -0
  219. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  220. package/src/domains/context/working-set/replay/trace.ts +21 -0
  221. package/src/domains/context/working-set/visible.ts +54 -0
  222. package/src/domains/dispatch/budget-envelope.ts +396 -0
  223. package/src/domains/dispatch/contract.ts +2 -0
  224. package/src/domains/dispatch/extension.ts +81 -27
  225. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +4 -0
  227. package/src/domains/dispatch/state.ts +1 -0
  228. package/src/domains/dispatch/types.ts +10 -3
  229. package/src/domains/dispatch/validation.ts +14 -0
  230. package/src/domains/dispatch/worker-spawn.ts +14 -3
  231. package/src/domains/eval/metrics/evidence.ts +0 -116
  232. package/src/domains/eval/metrics/invariants.ts +1 -1
  233. package/src/domains/eval/runners/clio-run.ts +1 -10
  234. package/src/domains/eval/runners/external-command.ts +2 -29
  235. package/src/domains/eval/schema/suite.ts +0 -7
  236. package/src/domains/eval/suites/run.ts +1 -7
  237. package/src/domains/evidence/build.ts +112 -45
  238. package/src/domains/evidence/eval.ts +24 -7
  239. package/src/domains/evidence/index.ts +53 -0
  240. package/src/domains/evidence/ordering.ts +12 -0
  241. package/src/domains/evidence/run-trust.ts +221 -0
  242. package/src/domains/evidence/store.ts +46 -6
  243. package/src/domains/evidence/trust-status.ts +854 -0
  244. package/src/domains/evidence/types.ts +26 -0
  245. package/src/domains/memory/index.ts +22 -0
  246. package/src/domains/memory/operations.ts +58 -1
  247. package/src/domains/memory/promotion.ts +281 -0
  248. package/src/domains/memory/prompt-section.ts +25 -5
  249. package/src/domains/memory/proposal.ts +51 -7
  250. package/src/domains/memory/task-bank.ts +3 -2
  251. package/src/domains/memory/task-memory-handoff.ts +181 -24
  252. package/src/domains/memory/task-memory-policy.ts +3 -1
  253. package/src/domains/memory/types.ts +37 -0
  254. package/src/domains/memory/validate.ts +178 -0
  255. package/src/domains/middleware/memory-intervention.ts +38 -25
  256. package/src/domains/middleware/runtime.ts +6 -0
  257. package/src/domains/middleware/skills-reminder.ts +19 -4
  258. package/src/domains/middleware/stalled-turn.ts +208 -5
  259. package/src/domains/middleware/types.ts +10 -0
  260. package/src/domains/observability/contract.ts +6 -1
  261. package/src/domains/observability/cost.ts +20 -4
  262. package/src/domains/observability/extension.ts +2 -2
  263. package/src/domains/providers/index.ts +3 -0
  264. package/src/domains/providers/model-discovery.ts +9 -0
  265. package/src/domains/providers/runtime-resolution.ts +38 -1
  266. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  267. package/src/domains/providers/types/context-window-slots.ts +18 -0
  268. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  269. package/src/domains/safety/autonomy.ts +1 -1
  270. package/src/domains/safety/call-target.ts +211 -14
  271. package/src/domains/safety/decision-presentation.ts +268 -0
  272. package/src/domains/safety/default-path-policy.ts +8 -0
  273. package/src/domains/safety/finish-contract.ts +4 -3
  274. package/src/domains/safety/policy-engine.ts +48 -6
  275. package/src/domains/safety/redaction.ts +73 -0
  276. package/src/domains/session/compaction/compact.ts +23 -1
  277. package/src/domains/session/compaction/cut-point.ts +2 -0
  278. package/src/domains/session/compaction/tokens.ts +16 -1
  279. package/src/domains/session/context-ledger.ts +12 -1
  280. package/src/domains/session/decision-board.ts +4 -0
  281. package/src/domains/session/entries.ts +110 -1
  282. package/src/domains/session/history.ts +68 -19
  283. package/src/domains/session/manager.ts +9 -2
  284. package/src/domains/session/migrations/index.ts +22 -3
  285. package/src/domains/session/usage.ts +24 -7
  286. package/src/engine/acp/event-mapper.ts +7 -0
  287. package/src/engine/acp/server.ts +32 -2
  288. package/src/engine/agent.ts +18 -1
  289. package/src/engine/apis/lmstudio.ts +25 -4
  290. package/src/engine/apis/openai-completions.ts +147 -22
  291. package/src/engine/claude/sdk-runtime.ts +8 -2
  292. package/src/engine/claude/tool-safety.ts +13 -0
  293. package/src/engine/loop-guard.ts +27 -3
  294. package/src/engine/session.ts +9 -3
  295. package/src/engine/worker-events.ts +4 -3
  296. package/src/engine/worker-runtime.ts +59 -54
  297. package/src/entry/orchestrator.ts +34 -5
  298. package/src/interactive/chat-loop-messages.ts +40 -6
  299. package/src/interactive/chat-loop.ts +13 -0
  300. package/src/interactive/chat-panel.ts +17 -1
  301. package/src/interactive/chat-renderer.ts +49 -24
  302. package/src/interactive/clio-editor.ts +44 -7
  303. package/src/interactive/context-meter.ts +10 -0
  304. package/src/interactive/context-overlay.ts +120 -7
  305. package/src/interactive/context-recall-command.ts +110 -0
  306. package/src/interactive/cost-overlay.ts +39 -8
  307. package/src/interactive/dispatch-board.ts +212 -35
  308. package/src/interactive/footer/widgets.ts +13 -0
  309. package/src/interactive/interactive-application.ts +6 -1
  310. package/src/interactive/interactive-input-runtime.ts +11 -1
  311. package/src/interactive/interactive-presentation.ts +11 -1
  312. package/src/interactive/interactive-slash-runtime.ts +37 -1
  313. package/src/interactive/memory-overlay.ts +89 -4
  314. package/src/interactive/model-session-replay.ts +21 -0
  315. package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
  316. package/src/interactive/overlay-frame.ts +5 -2
  317. package/src/interactive/overlay-general-openers.ts +46 -1
  318. package/src/interactive/overlay-key-routing.ts +41 -1
  319. package/src/interactive/overlay-lifecycle.ts +11 -4
  320. package/src/interactive/overlay-permission-lifecycle.ts +23 -8
  321. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  322. package/src/interactive/overlay-transitions.ts +11 -0
  323. package/src/interactive/overlays/ask-user.ts +74 -30
  324. package/src/interactive/overlays/decisions.ts +3 -1
  325. package/src/interactive/permission-hint.ts +35 -0
  326. package/src/interactive/permission-overlay.ts +95 -45
  327. package/src/interactive/renderers/tool-execution.ts +37 -51
  328. package/src/interactive/session-last-turn.ts +8 -1
  329. package/src/interactive/session-transcript.ts +2 -2
  330. package/src/interactive/session-usage-reseed.ts +36 -10
  331. package/src/interactive/slash-commands.ts +31 -4
  332. package/src/interactive/status/summary.ts +5 -0
  333. package/src/interactive/status/types.ts +5 -0
  334. package/src/interactive/terminal-lease.ts +1 -0
  335. package/src/interactive/turn-context.ts +333 -110
  336. package/src/interactive/turn-middleware.ts +7 -6
  337. package/src/interactive/turn-runtime.ts +37 -8
  338. package/src/interactive/turn-state.ts +3 -0
  339. package/src/interactive/worker-progress.ts +440 -0
  340. package/src/interactive/worker-stream.ts +51 -110
  341. package/src/tools/agent-tools.ts +39 -7
  342. package/src/tools/ask-user.ts +21 -1
  343. package/src/tools/bash.ts +144 -82
  344. package/src/tools/builtin-tool-catalog.ts +11 -5
  345. package/src/tools/context/index.ts +107 -5
  346. package/src/tools/context/surface.ts +3 -2
  347. package/src/tools/core-bootstrap.ts +21 -0
  348. package/src/tools/dispatch-arguments.ts +8 -0
  349. package/src/tools/dispatch-event-text.ts +19 -0
  350. package/src/tools/dispatch-runner.ts +9 -7
  351. package/src/tools/dispatch.ts +24 -1
  352. package/src/tools/monitor.ts +43 -20
  353. package/src/tools/registry.ts +72 -10
  354. package/src/tools/result-disposition.ts +706 -0
  355. package/src/tools/result-shaping.ts +321 -20
  356. package/src/tools/safe-exec.ts +2 -0
  357. package/src/tools/verify/authoring.ts +1120 -0
  358. package/src/tools/verify/catalog.ts +346 -0
  359. package/src/tools/verify/index.ts +13 -3
  360. package/src/tools/verify/scripts.ts +135 -37
  361. package/src/tools/verify/surface.ts +9 -5
  362. package/src/tools/worker-evidence.ts +54 -12
  363. package/src/worker/spec-contract.ts +43 -3
  364. package/dist/chunk-J7CWMCQD.js +0 -255
  365. package/dist/chunk-T6YILFSB.js +0 -80
  366. package/dist/chunk-VAKQQHWR.js +0 -434
  367. package/dist/chunk-VPAYEGVX.js +0 -184
  368. package/dist/chunk-XBXAASKX.js +0 -18
  369. package/dist/memory-WFZMGYHX.js +0 -236
  370. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
@@ -1,9 +1,11 @@
1
1
  import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
2
2
  import {
3
- createRedactionTally,
4
- redactSecretsDeep,
5
- redactSecretsText
6
- } from "./chunk-4BJ5BYCE.js";
3
+ protectedArtifactFromSessionEntry,
4
+ protectedArtifactStateFromSessionEntries,
5
+ readAuditRows,
6
+ readSessionEntriesForId,
7
+ responseModelIdObservationFromRecord
8
+ } from "./chunk-CJUB2JJ2.js";
7
9
  import {
8
10
  FLEET_COMMAND_BASE_ENV,
9
11
  describeWriteBoundary,
@@ -23,7 +25,7 @@ import {
23
25
  sumEvalHarnessMetrics,
24
26
  verifyReceiptIntegrity,
25
27
  withReceiptIntegrity
26
- } from "./chunk-AGYYIBLL.js";
28
+ } from "./chunk-OH3TOQTB.js";
27
29
  import {
28
30
  LOCAL_NODE_ID,
29
31
  computeSettingsFingerprint,
@@ -34,10 +36,7 @@ import {
34
36
  receiptAttestationFields,
35
37
  routeFactVerdict,
36
38
  spawnNativeWorker
37
- } from "./chunk-OOJYHWRB.js";
38
- import {
39
- probeWorkspace
40
- } from "./chunk-G4BMMOKF.js";
39
+ } from "./chunk-TSHXZTOQ.js";
41
40
  import {
42
41
  AGENT_LEDGER_PROMPT_MAX_CHARS,
43
42
  RETRYABLE_OUTCOMES,
@@ -59,32 +58,29 @@ import {
59
58
  claudeSubprocessPermissionConfigForAutonomy,
60
59
  competeStanceLiner,
61
60
  createRunEffectsRecorder,
61
+ describeCallAction,
62
62
  isBoundedGateRolePrompt,
63
63
  isClaudeCanonicalTool,
64
64
  isResponseSchemaRejection,
65
65
  isRunOutcomeCode,
66
- isSessionEntry,
67
- isSessionHeader,
68
66
  networkToolsDisabled,
69
67
  projectExecutionHandoffs,
70
68
  renderAgentLedger,
69
+ resolveToolBudgetEnvelope,
71
70
  responseSchemaConflictsWithTools,
72
71
  runKindSupportsLiveSteering,
73
72
  runtimeSpeaksResponseSchemaDialect,
74
73
  serializeWorkerRuntimeDescriptor,
75
74
  toolPromptHintsForNames,
76
75
  validateJobSpec
77
- } from "./chunk-LWLEKMDQ.js";
76
+ } from "./chunk-XXQNGV4M.js";
78
77
  import {
79
- DEFAULT_AUTONOMY_LEVEL,
80
78
  WRITE_ROOT_REFUSED_TOOLS,
81
79
  assessFinishContract,
82
- autonomyDenyRejection,
83
- mapAutonomy,
84
80
  parseJsonObjectPayload,
85
81
  parseVerifierResult,
86
82
  validateRecipeResult
87
- } from "./chunk-STBPMHSX.js";
83
+ } from "./chunk-EKY57CSP.js";
88
84
  import {
89
85
  appliesRecipeResultContract,
90
86
  decideRoute,
@@ -107,31 +103,46 @@ import {
107
103
  sameRouteIdentity,
108
104
  toRouteCandidate,
109
105
  withAttemptRole
110
- } from "./chunk-GGXXDWE4.js";
106
+ } from "./chunk-22NAGB7X.js";
111
107
  import {
112
108
  agentSpecFingerprint,
113
109
  assertAgentSpecPolicy,
114
110
  classify,
115
- detectValidationCommand,
116
111
  isUserVisibleAgent,
117
112
  normalizeAgentSpec,
118
- protectArtifact,
119
113
  resolveAgentToolCompatibility
120
- } from "./chunk-5UUP6MWO.js";
114
+ } from "./chunk-AOCYTWAV.js";
115
+ import {
116
+ detectValidationCommand
117
+ } from "./chunk-MV3K5QF2.js";
121
118
  import {
122
119
  canonicalJson,
123
120
  endpointIdentityHash,
124
121
  parseAgentLedgerBody
125
122
  } from "./chunk-CMZWFGD2.js";
126
123
  import {
124
+ compareCodepoints
125
+ } from "./chunk-FYYLNIL5.js";
126
+ import {
127
+ isProjectVerifierCheckId,
127
128
  isVerificationScriptName
128
- } from "./chunk-7MNJORFF.js";
129
+ } from "./chunk-UL3WSD3F.js";
129
130
  import {
130
131
  canonicalizeExistingPath
131
132
  } from "./chunk-ECH6PKUQ.js";
132
133
  import {
133
134
  isSkillActivation
134
- } from "./chunk-T6YILFSB.js";
135
+ } from "./chunk-GOXNB3AO.js";
136
+ import {
137
+ DEFAULT_AUTONOMY_LEVEL,
138
+ autonomyDenyRejection,
139
+ mapAutonomy
140
+ } from "./chunk-HWUFFB6L.js";
141
+ import {
142
+ createRedactionTally,
143
+ redactSecretsDeep,
144
+ redactSecretsText
145
+ } from "./chunk-4BJ5BYCE.js";
135
146
  import {
136
147
  truncateUtf8
137
148
  } from "./chunk-6XLNIQDB.js";
@@ -141,45 +152,28 @@ import {
141
152
  } from "./chunk-CGKSTWHD.js";
142
153
  import {
143
154
  canonicalizeWireModelId,
144
- ceilChars,
145
155
  firstRuntimeResolutionError,
146
156
  isDispatchEligibleRuntime,
147
157
  resolveEffectivePricing,
148
158
  resolveModelCapabilities,
149
159
  resolveRuntimeTarget,
150
160
  runtimeResolutionWarnings,
151
- runtimeTargetSnapshot,
152
- stripTokenizerSentinels
153
- } from "./chunk-LZSJBIVT.js";
161
+ runtimeTargetSnapshot
162
+ } from "./chunk-DJVECN66.js";
154
163
  import {
155
164
  DEFAULT_DELEGATION_CONNECT_TIMEOUT_MS,
156
165
  DEFAULT_DELEGATION_TURN_TIMEOUT_MS,
157
166
  DEFAULT_SETTINGS,
158
167
  THINKING_LEVELS
159
- } from "./chunk-ZDOOVTXZ.js";
168
+ } from "./chunk-4OC57DA6.js";
160
169
  import {
161
170
  targetRequiresAuth
162
171
  } from "./chunk-4VP4KH3K.js";
163
- import {
164
- CURRENT_SESSION_FORMAT_VERSION,
165
- appendSessionFileEntry,
166
- atomicWrite,
167
- createSession,
168
- cwdHash,
169
- openSession,
170
- readSessionFileEntries,
171
- readSessionMeta,
172
- resumeSession,
173
- sessionPaths
174
- } from "./chunk-M6SHUN7Q.js";
175
- import {
176
- assertSafeId
177
- } from "./chunk-R346GLFC.js";
178
172
  import {
179
173
  gitCommitAttributionEnabled,
180
174
  reportCommitAttributionDiagnostic,
181
175
  withManagedGitCommitAttributionEnvironment
182
- } from "./chunk-COU2UHX6.js";
176
+ } from "./chunk-VEZEGCGW.js";
183
177
  import {
184
178
  MAX_TIMER_DELAY_MS,
185
179
  rawDurationMs
@@ -194,6 +188,15 @@ import {
194
188
  processAlive,
195
189
  processBirthToken
196
190
  } from "./chunk-3I7MS7N2.js";
191
+ import {
192
+ ceilChars
193
+ } from "./chunk-GEYXPTRF.js";
194
+ import {
195
+ atomicWrite
196
+ } from "./chunk-FO5ZOVUY.js";
197
+ import {
198
+ assertSafeId
199
+ } from "./chunk-R346GLFC.js";
197
200
  import {
198
201
  GUARDRAIL_DEFAULTS,
199
202
  resolveGuardrail
@@ -208,7 +211,7 @@ import {
208
211
  } from "./chunk-6EJMN2Y3.js";
209
212
  import {
210
213
  BusChannels
211
- } from "./chunk-OQ33BKR3.js";
214
+ } from "./chunk-G7MUEIGA.js";
212
215
  import {
213
216
  readClioVersion,
214
217
  readPiMonoVersion,
@@ -1426,8 +1429,8 @@ init_esm_shims();
1426
1429
 
1427
1430
  // src/domains/evidence/build.ts
1428
1431
  init_esm_shims();
1429
- import { mkdir, readFile as readFile3, writeFile } from "node:fs/promises";
1430
- import { join as join19 } from "node:path";
1432
+ import { mkdir, readFile as readFile2, writeFile } from "node:fs/promises";
1433
+ import { join as join16 } from "node:path";
1431
1434
 
1432
1435
  // src/domains/dispatch/index.ts
1433
1436
  init_esm_shims();
@@ -1540,12 +1543,15 @@ var AcpEventMapper = class {
1540
1543
  if (!this.toolStarts.has(toolCallId) && (status === "pending" || status === "in_progress")) {
1541
1544
  const startedAt = Date.now();
1542
1545
  this.toolStarts.set(toolCallId, performance2.now());
1546
+ const action = describeCallAction(update.kind ?? title, update.rawInput);
1543
1547
  out.push({
1544
1548
  type: "clio_tool_start",
1545
1549
  payload: {
1546
1550
  tool: update.kind ?? title,
1551
+ toolCallId,
1547
1552
  posture: "operating",
1548
- startedAt
1553
+ startedAt,
1554
+ ...action !== null ? { action } : {}
1549
1555
  }
1550
1556
  });
1551
1557
  out.push({
@@ -1571,6 +1577,7 @@ var AcpEventMapper = class {
1571
1577
  type: "clio_tool_finish",
1572
1578
  payload: {
1573
1579
  tool: update.kind ?? title,
1580
+ toolCallId,
1574
1581
  posture: "operating",
1575
1582
  durationMs: Math.round(performance2.now() - startedAtClock),
1576
1583
  outcome: isError ? "error" : "ok",
@@ -4577,6 +4584,7 @@ function envelopeFromReceipt(receipt, status, receiptPath) {
4577
4584
  ...receipt.agentAudience !== void 0 ? { agentAudience: receipt.agentAudience } : {},
4578
4585
  ...receipt.requestOrigin !== void 0 ? { requestOrigin: receipt.requestOrigin } : {},
4579
4586
  task: receipt.task,
4587
+ ...receipt.budget !== void 0 ? { budget: receipt.budget } : {},
4580
4588
  ...receipt.briefing !== void 0 ? { briefing: receipt.briefing } : {},
4581
4589
  ...receipt.steering !== void 0 ? { steering: receipt.steering } : {},
4582
4590
  targetId: receipt.targetId,
@@ -6351,6 +6359,7 @@ function openLedger(opts) {
6351
6359
  ...input.agentAudience !== void 0 ? { agentAudience: input.agentAudience } : {},
6352
6360
  ...input.requestOrigin !== void 0 ? { requestOrigin: input.requestOrigin } : {},
6353
6361
  task: input.task,
6362
+ ...input.budget !== void 0 ? { budget: structuredClone(input.budget) } : {},
6354
6363
  ...input.briefing !== void 0 ? { briefing: structuredClone(input.briefing) } : {},
6355
6364
  ...input.steering !== void 0 ? { steering: structuredClone(input.steering) } : {},
6356
6365
  targetId: input.targetId,
@@ -7135,7 +7144,7 @@ function assertWriteRootsEnforceable(runtime, writeRoots) {
7135
7144
  function assertWorkerBudgetEnforceable(runtime, hasDeclaredBudget) {
7136
7145
  if (!hasDeclaredBudget || runtime.kind !== "subprocess") return;
7137
7146
  throw new Error(
7138
- `dispatch: runtime '${runtime.id}' cannot enforce an explicit agent budget because subprocess workers do not expose per-tool mediation; choose a native or claude-sdk worker`
7147
+ `dispatch: runtime '${runtime.id}' cannot enforce an explicit dispatch budget because subprocess workers do not expose per-tool mediation; choose a native or claude-sdk worker`
7139
7148
  );
7140
7149
  }
7141
7150
  var TOOL_CARRYING_API_FAMILIES = /* @__PURE__ */ new Set([
@@ -7188,18 +7197,27 @@ function assertPostRuntimeToolCompatibility(agentId, spec, effectiveTools, targe
7188
7197
  `dispatch: admission denied: agent '${agentId}' is incompatible with runtime '${target.runtime.id}' after tool narrowing; missing required tools: ${compatibility.missingRequired.join(", ")}`
7189
7198
  );
7190
7199
  }
7191
- function resolveEffectiveWorkerBudget(input) {
7200
+ function workerToolCallHardCap(settings) {
7192
7201
  const rawEnvCap = process.env.CLIO_CODER_WORKER_TOOL_CALL_CAP?.trim();
7193
7202
  const parsedEnvCap = rawEnvCap && /^[1-9]\d*$/.test(rawEnvCap) ? Number(rawEnvCap) : Number.NaN;
7194
- const hardCap = Number.isSafeInteger(parsedEnvCap) ? parsedEnvCap : input.settings?.guardrails.workerToolCallCap ?? GUARDRAIL_DEFAULTS.workerToolCallCap;
7203
+ return Number.isSafeInteger(parsedEnvCap) ? parsedEnvCap : settings?.guardrails.workerToolCallCap ?? GUARDRAIL_DEFAULTS.workerToolCallCap;
7204
+ }
7205
+ function resolveEffectiveWorkerBudget(input) {
7206
+ const hardCap = workerToolCallHardCap(input.settings);
7195
7207
  const declared = input.declared ?? {
7196
7208
  toolCalls: hardCap,
7197
7209
  readReserve: Math.min(5, Math.max(0, hardCap - 1)),
7198
7210
  synthesis: true
7199
7211
  };
7200
- const toolCalls = Math.min(declared.toolCalls, hardCap);
7201
- const readReserve = input.allowedTools.includes(ToolNames.Read) ? Math.min(declared.readReserve, Math.max(0, toolCalls - 1)) : 0;
7202
- return { toolCalls, readReserve, synthesis: declared.synthesis, hardCap };
7212
+ return resolveToolBudgetEnvelope({
7213
+ recipeId: input.recipeId,
7214
+ policy: declared,
7215
+ ...input.req.budget === void 0 ? {} : { request: input.req.budget },
7216
+ hardCap,
7217
+ hasReadTool: input.allowedTools.includes(ToolNames.Read),
7218
+ retry: (input.req.lineage?.attempt ?? 0) > 0,
7219
+ revision: input.req.gate?.role === "builder" && input.req.gate.cycle > 1 && input.req.gate.verdict === "revise"
7220
+ });
7203
7221
  }
7204
7222
  function frozenProtectedArtifactState(state) {
7205
7223
  return {
@@ -8477,7 +8495,7 @@ function createDispatchBundle(context, options) {
8477
8495
  );
8478
8496
  enforceCapabilityGate(target.target.id, target.modelCapabilities, req.requiredCapabilities);
8479
8497
  assertRuntimeCanHonorWorkerPermissionMode(target.runtime, settings?.workers.onPermission ?? "deny");
8480
- assertWorkerBudgetEnforceable(target.runtime, spec.budget !== null);
8498
+ assertWorkerBudgetEnforceable(target.runtime, spec.budget !== null || req.budget !== void 0);
8481
8499
  const cwd = req.cwd ?? process.cwd();
8482
8500
  const sessionAutonomy = settings?.autonomy ?? "auto-edit";
8483
8501
  const effectiveAutonomy = clampWorkerAutonomy(sessionAutonomy, req.autonomy);
@@ -8510,7 +8528,13 @@ function createDispatchBundle(context, options) {
8510
8528
  workingContextPaths: workerWorkingContextPaths(req)
8511
8529
  });
8512
8530
  const systemPrompt = compiledWorkerPrompt.systemPrompt;
8513
- const budget = resolveEffectiveWorkerBudget({ declared: spec.budget, allowedTools: effectiveTools, settings });
8531
+ const budgetEnvelope = resolveEffectiveWorkerBudget({
8532
+ req,
8533
+ recipeId: recipe.id,
8534
+ declared: spec.budget,
8535
+ allowedTools: effectiveTools,
8536
+ settings
8537
+ });
8514
8538
  const tier = spec.projectContextTier;
8515
8539
  const project = projectContext && tier === "bounded" ? projectContext.projectStructuredContext(cwd) : null;
8516
8540
  const dynamicPromptMessages = buildDynamicPromptMessages(req, {
@@ -8560,7 +8584,8 @@ function createDispatchBundle(context, options) {
8560
8584
  operatorProfileApplied: compiledWorkerPrompt.operatorProfileApplied ?? false,
8561
8585
  capabilityMismatch,
8562
8586
  effectiveAutonomy,
8563
- budget,
8587
+ budget: budgetEnvelope.effective,
8588
+ budgetEnvelope,
8564
8589
  ...settings ? { settings } : {}
8565
8590
  };
8566
8591
  }
@@ -8734,12 +8759,16 @@ function createDispatchBundle(context, options) {
8734
8759
  tokenMeter.cacheReadTokens += typeof u.cacheRead === "number" ? u.cacheRead : 0;
8735
8760
  tokenMeter.cacheWriteTokens += typeof u.cacheWrite === "number" ? u.cacheWrite : 0;
8736
8761
  tokenMeter.reasoningTokens += extractReasoningTokenCount(u);
8737
- const model = readStringOrNull(event.message.model);
8738
- const responseModel = readStringOrNull(event.message.responseModel);
8739
- const responseId = readStringOrNull(event.message.responseId);
8740
- if (model !== null || responseModel !== null || responseId !== null) {
8741
- upstreamResponses.push({ model, responseModel, responseId });
8742
- }
8762
+ const requestedModelId = readStringOrNull(event.message.model);
8763
+ const responseModelIdObservation = responseModelIdObservationFromRecord(event.message, "not-observed");
8764
+ const differingResponseModelId = readStringOrNull(event.message.responseModel);
8765
+ const providerResponseId = readStringOrNull(event.message.responseId);
8766
+ upstreamResponses.push({
8767
+ requestedModelId,
8768
+ responseModelIdObservation,
8769
+ differingResponseModelId,
8770
+ providerResponseId
8771
+ });
8743
8772
  if (event.message.stopReason === "error") {
8744
8773
  const message = readStringOrNull(event.message.errorMessage);
8745
8774
  if (message !== null) failureMessage = message;
@@ -9294,6 +9323,11 @@ function createDispatchBundle(context, options) {
9294
9323
  return handle;
9295
9324
  };
9296
9325
  if (req.delegationAgentId) {
9326
+ if (req.budget !== void 0) {
9327
+ throw new Error(
9328
+ "dispatch: budget envelopes cannot be enforced on an ACP delegation target; dispatch to a native or claude-sdk worker"
9329
+ );
9330
+ }
9297
9331
  assertPlannedNodeIdentity(req, { id: "local", kind: "local" });
9298
9332
  assertProtectedArtifactsEnforceable("acp-delegation", false, protectedArtifactState);
9299
9333
  if (req.responseSchema !== void 0) {
@@ -9553,12 +9587,16 @@ function createDispatchBundle(context, options) {
9553
9587
  tokenMeter.cacheReadTokens += typeof u.cacheRead === "number" ? u.cacheRead : 0;
9554
9588
  tokenMeter.cacheWriteTokens += typeof u.cacheWrite === "number" ? u.cacheWrite : 0;
9555
9589
  tokenMeter.reasoningTokens += extractReasoningTokenCount(u);
9556
- const model = readStringOrNull(event.message.model);
9557
- const responseModel = readStringOrNull(event.message.responseModel);
9558
- const responseId = readStringOrNull(event.message.responseId);
9559
- if (model !== null || responseModel !== null || responseId !== null) {
9560
- upstreamResponses.push({ model, responseModel, responseId });
9561
- }
9590
+ const requestedModelId = readStringOrNull(event.message.model);
9591
+ const responseModelIdObservation = responseModelIdObservationFromRecord(event.message, "not-observed");
9592
+ const differingResponseModelId = readStringOrNull(event.message.responseModel);
9593
+ const providerResponseId = readStringOrNull(event.message.responseId);
9594
+ upstreamResponses.push({
9595
+ requestedModelId,
9596
+ responseModelIdObservation,
9597
+ differingResponseModelId,
9598
+ providerResponseId
9599
+ });
9562
9600
  if (event.message.stopReason === "error") {
9563
9601
  const message = readStringOrNull(event.message.errorMessage);
9564
9602
  if (message !== null) failureMessage = message;
@@ -9629,6 +9667,7 @@ function createDispatchBundle(context, options) {
9629
9667
  agentAudience: lifecycle.agentAudience,
9630
9668
  requestOrigin: lifecycle.requestOrigin,
9631
9669
  task: req.task,
9670
+ budget: lifecycle.budgetEnvelope,
9632
9671
  targetId: lifecycle.target.target.id,
9633
9672
  wireModelId: lifecycle.target.wireModelId,
9634
9673
  runtimeId: lifecycle.target.runtime.id,
@@ -9686,6 +9725,7 @@ function createDispatchBundle(context, options) {
9686
9725
  });
9687
9726
  await ledgerRef.persist();
9688
9727
  const fleetIdentity = {
9728
+ budget: lifecycle.budgetEnvelope,
9689
9729
  ...placement !== void 0 && placement !== null ? { node: placement.node.id } : {},
9690
9730
  ...req.gate !== void 0 ? { gate: { role: req.gate.role, cycle: req.gate.cycle } } : {},
9691
9731
  ...req.reroutes !== void 0 && req.reroutes.length > 0 ? { rerouteCount: req.reroutes.length } : {},
@@ -9777,6 +9817,7 @@ function createDispatchBundle(context, options) {
9777
9817
  requestOrigin: lifecycle.requestOrigin,
9778
9818
  agentId: req.agentId,
9779
9819
  task: req.task,
9820
+ budget: lifecycle.budgetEnvelope,
9780
9821
  cwd: lifecycle.cwd,
9781
9822
  node: placement?.node ?? null,
9782
9823
  aborted: false,
@@ -9820,6 +9861,7 @@ function createDispatchBundle(context, options) {
9820
9861
  agentAudience: lifecycle.agentAudience,
9821
9862
  requestOrigin: lifecycle.requestOrigin,
9822
9863
  task: req.task,
9864
+ budget: lifecycle.budgetEnvelope,
9823
9865
  targetId: lifecycle.target.target.id,
9824
9866
  wireModelId: lifecycle.target.wireModelId,
9825
9867
  runtimeId: lifecycle.target.runtime.id,
@@ -10232,6 +10274,11 @@ function createDispatchBundle(context, options) {
10232
10274
  if (!validated.ok) throw new Error(`dispatch: invalid spec: ${validated.errors.join("; ")}`);
10233
10275
  req = validation.restore(validated.spec);
10234
10276
  if (req.delegationAgentId) {
10277
+ if (req.budget !== void 0) {
10278
+ throw new Error(
10279
+ "dispatch: budget envelopes cannot be enforced on an ACP delegation target; dispatch to a native or claude-sdk worker"
10280
+ );
10281
+ }
10235
10282
  const protectedArtifactState = getProtectedArtifactState();
10236
10283
  assertProtectedArtifactsEnforceable("acp-delegation", false, protectedArtifactState);
10237
10284
  if (req.responseSchema !== void 0) {
@@ -10293,6 +10340,7 @@ function createDispatchBundle(context, options) {
10293
10340
  );
10294
10341
  assertPostRuntimeToolCompatibility(req.agentId, agentSpec, effectiveTools, target);
10295
10342
  assertRuntimeCanHonorWorkerPermissionMode(target.runtime, settings?.workers.onPermission ?? "deny");
10343
+ assertWorkerBudgetEnforceable(target.runtime, agentSpec.budget !== null || req.budget !== void 0);
10296
10344
  assertResponseSchemaEnforceable(target.runtime, target.modelCapabilities, req.responseSchema, effectiveTools.length);
10297
10345
  assertWriteRootsEnforceable(target.runtime, req.writeRoots);
10298
10346
  assertProtectedArtifactsEnforceable(
@@ -10300,6 +10348,13 @@ function createDispatchBundle(context, options) {
10300
10348
  target.runtime.kind !== "subprocess",
10301
10349
  getProtectedArtifactState()
10302
10350
  );
10351
+ resolveEffectiveWorkerBudget({
10352
+ req,
10353
+ recipeId: recipe.id,
10354
+ declared: agentSpec.budget,
10355
+ allowedTools: effectiveTools,
10356
+ settings
10357
+ });
10303
10358
  return {
10304
10359
  agentId: req.agentId,
10305
10360
  specFingerprint: agentSpecFingerprint(agentSpec),
@@ -10624,6 +10679,7 @@ function createDispatchBundle(context, options) {
10624
10679
  runId: run.runId,
10625
10680
  agentId: run.agentId,
10626
10681
  task: run.task,
10682
+ ...run.budget !== void 0 ? { budget: run.budget } : {},
10627
10683
  runtimeKind: run.runtimeKind,
10628
10684
  outcomePhase: run.stallKilled ? "terminating" : run.aborted ? "aborting" : "running",
10629
10685
  heartbeat,
@@ -12577,1521 +12633,807 @@ function createDispatchDomainModule(options = {}) {
12577
12633
  };
12578
12634
  }
12579
12635
 
12580
- // src/domains/session/index.ts
12581
- init_esm_shims();
12582
-
12583
- // src/domains/session/extension.ts
12584
- init_esm_shims();
12585
-
12586
- // src/domains/session/checkpoint.ts
12587
- init_esm_shims();
12588
- async function performCheckpoint(state, reason) {
12589
- await state.writer.persistTree();
12590
- if (stateRootRemoved()) return;
12591
- const paths = sessionPaths(state.meta);
12592
- const at = (/* @__PURE__ */ new Date()).toISOString();
12593
- const enriched = {
12594
- ...state.meta,
12595
- lastCheckpointAt: at,
12596
- lastCheckpointReason: reason ?? null
12597
- };
12598
- atomicWrite(paths.meta, JSON.stringify(enriched, null, 2));
12599
- Object.assign(state.meta, enriched);
12600
- }
12601
-
12602
- // src/domains/session/history.ts
12603
- init_esm_shims();
12604
- import { existsSync as existsSync14, readdirSync as readdirSync6, readFileSync as readFileSync12, statSync as statSync2 } from "node:fs";
12605
- import { join as join15 } from "node:path";
12606
-
12607
- // src/domains/session/compaction/session-entries.ts
12636
+ // src/domains/evidence/failure-attribution.ts
12608
12637
  init_esm_shims();
12609
- function collectSessionEntries(turns, filePath) {
12610
- const out = [];
12611
- for (const raw of turns) {
12612
- if (!isSessionEntry(raw)) {
12613
- throw new Error(
12614
- `session ledger contains an unreadable entry (missing kind discriminant): ${filePath}. Remove or compact the session to reset.`
12615
- );
12616
- }
12617
- out.push(raw);
12618
- }
12619
- return out;
12620
- }
12621
-
12622
- // src/domains/session/history.ts
12623
- function listSessionsForCwd(cwd) {
12624
- const hash = cwdHash(cwd);
12625
- const dir = join15(clioStateDir(), "sessions", hash);
12626
- if (!existsSync14(dir)) return [];
12627
- const metas = [];
12628
- for (const entry of readdirSync6(dir, { withFileTypes: true })) {
12629
- if (!entry.isDirectory()) continue;
12630
- const sessionDir = join15(dir, entry.name);
12631
- const metaPath = join15(sessionDir, "meta.json");
12632
- if (!existsSync14(metaPath)) continue;
12633
- let meta;
12634
- try {
12635
- if (!statSync2(metaPath).isFile()) continue;
12636
- const raw = readFileSync12(metaPath, "utf8");
12637
- meta = JSON.parse(raw);
12638
- } catch {
12639
- continue;
12640
- }
12641
- enrichMetaForListing(meta, join15(sessionDir, "current.jsonl"));
12642
- metas.push(meta);
12643
- }
12644
- metas.sort((a, b) => {
12645
- const aKey = a.lastActivityAt ?? a.createdAt ?? "";
12646
- const bKey = b.lastActivityAt ?? b.createdAt ?? "";
12647
- return aKey === bKey ? 0 : aKey > bKey ? -1 : 1;
12648
- });
12649
- return metas;
12650
- }
12651
- var PREVIEW_MAX_CHARS = 240;
12652
- function collapseWhitespace(text) {
12653
- return text.replace(/\s+/g, " ").trim();
12654
- }
12655
- function extractUserText(payload) {
12656
- if (typeof payload === "string") {
12657
- const collapsed = collapseWhitespace(payload);
12658
- return collapsed.length > 0 ? collapsed : null;
12638
+ function attributeEvidenceFailure(facts) {
12639
+ if (facts.outcomeCode === "worker_tool_call_cap_exhausted" || facts.outcomeCode === "loop_guard_tools_disabled_exhausted") {
12640
+ return "tool-loop";
12659
12641
  }
12660
- if (!payload || typeof payload !== "object") return null;
12661
- const obj = payload;
12662
- if (typeof obj.text === "string") {
12663
- const collapsed = collapseWhitespace(obj.text);
12664
- if (collapsed.length > 0) return collapsed;
12642
+ if (facts.outcome === "timed_out" || facts.outcome === "stalled") return "timeout";
12643
+ const diagnostic = [facts.outcomeDetail, facts.failureMessage].filter((value) => value !== null).join("\n").toLowerCase();
12644
+ if (diagnostic.length === 0) return "unknown";
12645
+ if (/\b(?:401|403)\b|unauthorized|forbidden|invalid api key|authentication/.test(diagnostic)) {
12646
+ return "auth-failure";
12665
12647
  }
12666
- if (Array.isArray(obj.content)) {
12667
- const parts = [];
12668
- for (const part of obj.content) {
12669
- if (part && typeof part === "object" && part.type === "text" && typeof part.text === "string") {
12670
- parts.push(part.text);
12671
- }
12672
- }
12673
- const joined = collapseWhitespace(parts.join(" "));
12674
- if (joined.length > 0) return joined;
12648
+ if (/\b429\b|rate[ -]?limit|too many requests|temporar(?:y|ily)|unavailable|\b50[234]\b/.test(diagnostic)) {
12649
+ return "provider-transient";
12675
12650
  }
12676
- return null;
12677
- }
12678
- function scanCurrentJsonl(currentPath) {
12679
- const result = {
12680
- firstUserMessage: null,
12681
- messageCount: 0,
12682
- lastTimestamp: null,
12683
- name: null,
12684
- labels: /* @__PURE__ */ new Map()
12685
- };
12686
- if (!existsSync14(currentPath)) return result;
12687
- const records = readSessionFileEntries(currentPath).filter((entry) => !isSessionHeader(entry));
12688
- for (const parsed of collectSessionEntries(records, currentPath)) {
12689
- if (result.lastTimestamp === null || parsed.timestamp > result.lastTimestamp) {
12690
- result.lastTimestamp = parsed.timestamp;
12691
- }
12692
- if (parsed.kind === "message" && parsed.role === "user") {
12693
- result.messageCount += 1;
12694
- if (result.firstUserMessage === null) {
12695
- const text = extractUserText(parsed.payload);
12696
- if (text !== null) result.firstUserMessage = text;
12697
- }
12698
- }
12699
- if (parsed.kind === "sessionInfo") {
12700
- const info = parsed;
12701
- if (info.name !== void 0) {
12702
- const trimmed = info.name.trim();
12703
- result.name = trimmed.length > 0 ? trimmed : null;
12704
- }
12705
- if (info.targetTurnId && info.label !== void 0) {
12706
- const existing = result.labels.get(info.targetTurnId);
12707
- if (!existing || existing.timestamp <= info.timestamp) {
12708
- result.labels.set(info.targetTurnId, { label: info.label, timestamp: info.timestamp });
12709
- }
12710
- }
12711
- }
12712
- if (parsed.kind === "label") {
12713
- const label = parsed;
12714
- const existing = result.labels.get(label.targetTurnId);
12715
- if (!existing || existing.timestamp <= label.timestamp) {
12716
- result.labels.set(label.targetTurnId, { label: label.label ?? "", timestamp: label.timestamp });
12717
- }
12718
- }
12651
+ if (/context (?:length|window)|context[_ -]?overflow|maximum context|too many tokens/.test(diagnostic)) {
12652
+ return "context-overflow";
12719
12653
  }
12720
- return result;
12721
- }
12722
- function enrichMetaForListing(meta, currentPath) {
12723
- const scan = scanCurrentJsonl(currentPath);
12724
- if (scan.name) meta.name = scan.name;
12725
- const labelValues = [...scan.labels.values()].map((entry) => entry.label.trim()).filter((label) => label.length > 0);
12726
- if (labelValues.length > 0) meta.labels = labelValues;
12727
- if (scan.firstUserMessage) {
12728
- meta.firstMessagePreview = scan.firstUserMessage.length > PREVIEW_MAX_CHARS ? `${scan.firstUserMessage.slice(0, PREVIEW_MAX_CHARS - 1)}\u2026` : scan.firstUserMessage;
12654
+ if (/module not found|cannot find module|missing (?:dependency|package)|dependency .* missing/.test(diagnostic)) {
12655
+ return "missing-dependency";
12729
12656
  }
12730
- if (scan.messageCount > 0) meta.messageCount = scan.messageCount;
12731
- const fallbackMtime = readMtimeIso(currentPath);
12732
- const activity = scan.lastTimestamp ?? fallbackMtime ?? meta.endedAt ?? meta.createdAt ?? null;
12733
- if (activity) meta.lastActivityAt = activity;
12734
- }
12735
- function readMtimeIso(path2) {
12736
- try {
12737
- return statSync2(path2).mtime.toISOString();
12738
- } catch {
12739
- return null;
12657
+ if (/wrong runtime|runtime mismatch|model mismatch|unsupported runtime/.test(diagnostic)) return "wrong-runtime";
12658
+ if (/\b(?:test|tests|pytest|ctest)\b.*(?:fail|error)|(?:fail|error).*\b(?:test|tests|pytest|ctest)\b/.test(diagnostic)) {
12659
+ return "test-failure";
12740
12660
  }
12661
+ if (/\bbuild\b.*(?:fail|error)|(?:fail|error).*\bbuild\b/.test(diagnostic)) return "build-failure";
12662
+ return "unknown";
12741
12663
  }
12742
- function enrichForkMeta(meta, parentSessionId, parentTurnId) {
12743
- Object.assign(meta, { parentSessionId, parentTurnId });
12744
- const paths = sessionPaths(meta);
12745
- atomicWrite(paths.meta, JSON.stringify(meta, null, 2));
12746
- }
12747
-
12748
- // src/domains/session/manager.ts
12749
- init_esm_shims();
12750
-
12751
- // node_modules/uuid/dist-node/index.js
12752
- init_esm_shims();
12753
12664
 
12754
- // node_modules/uuid/dist-node/stringify.js
12665
+ // src/domains/evidence/provenance.ts
12755
12666
  init_esm_shims();
12756
- var byteToHex = [];
12757
- for (let i = 0; i < 256; ++i) {
12758
- byteToHex.push((i + 256).toString(16).slice(1));
12759
- }
12760
- function unsafeStringify(arr, offset = 0) {
12761
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
12667
+ var PERSONA_HASH_PREFIX_CHARS = 12;
12668
+ function extractRunProvenance(receipt) {
12669
+ const view = {};
12670
+ if (receipt.pipeline !== void 0) view.pipeline = receipt.pipeline;
12671
+ if (receipt.personaOverride !== void 0) view.personaOverride = receipt.personaOverride;
12672
+ const escalation = escalationCountsFrom(receipt.safety);
12673
+ if (escalation !== null) view.escalation = escalation;
12674
+ if (receipt.autonomyEnforcement !== void 0) view.autonomyEnforcement = receipt.autonomyEnforcement;
12675
+ return view;
12762
12676
  }
12763
-
12764
- // node_modules/uuid/dist-node/rng.js
12765
- init_esm_shims();
12766
- var rnds8 = new Uint8Array(16);
12767
- function rng() {
12768
- return crypto.getRandomValues(rnds8);
12677
+ function hasRunProvenance(view) {
12678
+ return view.pipeline !== void 0 || view.personaOverride !== void 0 || view.escalation !== void 0 || view.autonomyEnforcement !== void 0;
12769
12679
  }
12770
-
12771
- // node_modules/uuid/dist-node/v7.js
12772
- init_esm_shims();
12773
- var _state = {};
12774
- function v7(options, buf, offset) {
12775
- let bytes;
12776
- if (options) {
12777
- bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);
12778
- } else {
12779
- const now = Date.now();
12780
- const rnds = rng();
12781
- updateV7State(_state, now, rnds);
12782
- bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);
12783
- }
12784
- return buf ?? unsafeStringify(bytes);
12785
- }
12786
- function updateV7State(state, now, rnds) {
12787
- state.msecs ??= -Infinity;
12788
- state.seq ??= 0;
12789
- if (now > state.msecs) {
12790
- state.seq = rnds[6] << 23 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
12791
- state.msecs = now;
12792
- } else {
12793
- state.seq = state.seq + 1 | 0;
12794
- if (state.seq === 0) {
12795
- state.msecs++;
12796
- }
12797
- }
12798
- return state;
12680
+ function runProvenanceFromUnknown(value) {
12681
+ if (!isRecord9(value)) return {};
12682
+ const view = {};
12683
+ const pipeline = pipelineFromUnknown(value.pipeline);
12684
+ if (pipeline !== null) view.pipeline = pipeline;
12685
+ const personaOverride = personaOverrideFromUnknown(value.personaOverride);
12686
+ if (personaOverride !== null) view.personaOverride = personaOverride;
12687
+ const escalation = escalationFromUnknown(value.safety);
12688
+ if (escalation !== null) view.escalation = escalation;
12689
+ const autonomyEnforcement = autonomyEnforcementFromUnknown(value.autonomyEnforcement);
12690
+ if (autonomyEnforcement !== null) view.autonomyEnforcement = autonomyEnforcement;
12691
+ return view;
12799
12692
  }
12800
- function v7Bytes(rnds, msecs, seq, buf, offset = 0) {
12801
- if (rnds.length < 16) {
12802
- throw new Error("Random bytes length must be >= 16");
12803
- }
12804
- if (!buf) {
12805
- buf = new Uint8Array(16);
12806
- offset = 0;
12807
- } else {
12808
- if (offset < 0 || offset + 16 > buf.length) {
12809
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
12810
- }
12811
- }
12812
- msecs ??= Date.now();
12813
- seq ??= rnds[6] * 127 << 24 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
12814
- buf[offset++] = msecs / 1099511627776 & 255;
12815
- buf[offset++] = msecs / 4294967296 & 255;
12816
- buf[offset++] = msecs / 16777216 & 255;
12817
- buf[offset++] = msecs / 65536 & 255;
12818
- buf[offset++] = msecs / 256 & 255;
12819
- buf[offset++] = msecs & 255;
12820
- buf[offset++] = 112 | seq >>> 28 & 15;
12821
- buf[offset++] = seq >>> 20 & 255;
12822
- buf[offset++] = 128 | seq >>> 14 & 63;
12823
- buf[offset++] = seq >>> 6 & 255;
12824
- buf[offset++] = seq << 2 & 255 | rnds[10] & 3;
12825
- buf[offset++] = rnds[11];
12826
- buf[offset++] = rnds[12];
12827
- buf[offset++] = rnds[13];
12828
- buf[offset++] = rnds[14];
12829
- buf[offset++] = rnds[15];
12830
- return buf;
12831
- }
12832
- var v7_default = v7;
12833
-
12834
- // src/domains/session/migrations/index.ts
12835
- init_esm_shims();
12836
- function runMigrations(meta, sessionPath) {
12837
- const from = meta.sessionFormatVersion ?? 1;
12838
- if (from < CURRENT_SESSION_FORMAT_VERSION) {
12839
- throw new Error(
12840
- `session metadata has an unsupported format version (expected version 3, got ${from}): ${sessionPath}. Remove the session directory to start a new session.`
12841
- );
12842
- }
12843
- return { migrated: false, from, to: from };
12693
+ function isRecord9(value) {
12694
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12844
12695
  }
12845
-
12846
- // src/domains/session/manager.ts
12847
- function newTurnId() {
12848
- return v7_default();
12696
+ function finiteNumber(value) {
12697
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
12849
12698
  }
12850
- function startSession(input) {
12851
- const { meta, writer } = createSession({
12852
- cwd: input.cwd,
12853
- model: input.model ?? null,
12854
- target: input.target ?? null,
12855
- ...input.initialEntries !== void 0 ? { initialEntries: input.initialEntries } : {},
12856
- ...input.initialTree !== void 0 ? { initialTree: input.initialTree } : {},
12857
- ...input.parentSession !== void 0 ? { parentSession: input.parentSession } : {},
12858
- ...input.parentTurnId !== void 0 ? { parentTurnId: input.parentTurnId } : {}
12859
- });
12860
- return { meta, writer };
12699
+ function pipelineFromUnknown(value) {
12700
+ if (!isRecord9(value)) return null;
12701
+ const position = finiteNumber(value.position);
12702
+ const inputBytes = finiteNumber(value.inputBytes);
12703
+ if (position === null || inputBytes === null) return null;
12704
+ const fromRunId = typeof value.fromRunId === "string" ? value.fromRunId : null;
12705
+ return { fromRunId, position, inputBytes, inputTruncated: value.inputTruncated === true };
12861
12706
  }
12862
- function persistSessionMeta(state) {
12863
- if (stateRootRemoved()) return;
12864
- atomicWrite(sessionPaths(state.meta).meta, JSON.stringify(state.meta, null, 2));
12707
+ function personaOverrideFromUnknown(value) {
12708
+ if (!isRecord9(value) || typeof value.promptHash !== "string" || value.promptHash.length === 0) return null;
12709
+ return { promptHash: value.promptHash };
12865
12710
  }
12866
- function resumeSessionState(sessionId) {
12867
- const persistedMeta = readSessionMeta(sessionId);
12868
- const paths = sessionPaths(persistedMeta);
12869
- runMigrations(persistedMeta, paths.meta);
12870
- const { meta, writer, tree } = resumeSession(sessionId);
12871
- return { state: { meta, writer }, nodes: tree };
12711
+ function autonomyEnforcementFromUnknown(value) {
12712
+ if (!isRecord9(value)) return null;
12713
+ if (value.grade !== "mediated" && value.grade !== "approximated" && value.grade !== "bypassed") return null;
12714
+ if (typeof value.autonomy !== "string" || value.autonomy.length === 0) return null;
12715
+ const view = { grade: value.grade, autonomy: value.autonomy };
12716
+ if (typeof value.externalMode === "string" && value.externalMode.length > 0) view.externalMode = value.externalMode;
12717
+ if (typeof value.dangerousBypass === "boolean") view.dangerousBypass = value.dangerousBypass;
12718
+ return view;
12872
12719
  }
12873
- function appendTurn(state, input) {
12874
- const record = {
12875
- id: input.id ?? newTurnId(),
12876
- parentId: input.parentId,
12877
- at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
12878
- kind: input.kind,
12879
- payload: input.payload
12720
+ function escalationFromUnknown(safety) {
12721
+ if (!isRecord9(safety)) return null;
12722
+ const decisions = safety.decisions;
12723
+ if (!isRecord9(decisions)) return null;
12724
+ const requested = finiteNumber(decisions.escalationRequested);
12725
+ if (requested === null) return null;
12726
+ return {
12727
+ requested,
12728
+ approved: finiteNumber(decisions.escalationApproved) ?? 0,
12729
+ denied: finiteNumber(decisions.escalationDenied) ?? 0,
12730
+ timedOut: finiteNumber(decisions.escalationTimedOut) ?? 0
12880
12731
  };
12881
- const entry = {
12882
- kind: "message",
12883
- turnId: record.id,
12884
- parentTurnId: record.parentId,
12885
- timestamp: record.at,
12886
- role: record.kind,
12887
- payload: record.payload
12732
+ }
12733
+ function escalationCountsFrom(safety) {
12734
+ const decisions = safety?.decisions;
12735
+ if (decisions === void 0 || decisions.escalationRequested === void 0) return null;
12736
+ return {
12737
+ requested: decisions.escalationRequested,
12738
+ approved: decisions.escalationApproved ?? 0,
12739
+ denied: decisions.escalationDenied ?? 0,
12740
+ timedOut: decisions.escalationTimedOut ?? 0
12888
12741
  };
12889
- state.writer.appendEntry(entry, {
12890
- treeNode: {
12891
- id: record.id,
12892
- parentId: record.parentId,
12893
- at: record.at,
12894
- kind: record.kind
12895
- }
12896
- });
12897
- return record;
12898
12742
  }
12899
- function appendEntry(state, input) {
12900
- const turnId = input.turnId ?? newTurnId();
12901
- const timestamp = input.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
12902
- const entry = { ...input, turnId, timestamp };
12903
- if (!isSessionEntry(entry)) throw new Error(`session.appendEntry: invalid ${String(input.kind)} entry`);
12904
- state.writer.appendEntry(entry);
12905
- return entry;
12743
+ function formatPersonaHashPrefix(promptHash2) {
12744
+ if (promptHash2.length <= PERSONA_HASH_PREFIX_CHARS) return promptHash2;
12745
+ return `${promptHash2.slice(0, PERSONA_HASH_PREFIX_CHARS)}...`;
12906
12746
  }
12907
- function replaceEntries(state, entries) {
12908
- for (const entry of entries) {
12909
- if (!isSessionEntry(entry)) throw new Error("session.replaceEntries: invalid entry");
12747
+ function provenanceTranscriptLines(view) {
12748
+ const lines = [];
12749
+ if (view.pipeline !== void 0) {
12750
+ const { fromRunId, position, inputBytes, inputTruncated } = view.pipeline;
12751
+ const source = fromRunId ?? "unknown";
12752
+ const truncation = inputTruncated ? "input truncated" : "not truncated";
12753
+ lines.push(`pipeline: step ${position}, input ${inputBytes} bytes from ${source} (${truncation})`);
12910
12754
  }
12911
- state.writer.replaceEntries(entries);
12912
- }
12913
-
12914
- // src/domains/session/tree/fork.ts
12915
- init_esm_shims();
12916
-
12917
- // src/domains/session/tree/active-path.ts
12918
- init_esm_shims();
12919
- function filterEntriesToActivePath(entries, leafTurnId) {
12920
- const messages = [];
12921
- const messagesById = /* @__PURE__ */ new Map();
12922
- for (const entry of entries) {
12923
- if (entry.kind !== "message") continue;
12924
- messages.push(entry);
12925
- messagesById.set(entry.turnId, entry);
12926
- }
12927
- const latest2 = messages[messages.length - 1];
12928
- const pinnedLeaf = resolveLeafMessage(entries, messagesById, leafTurnId);
12929
- if (!hasBranch(messages) && (pinnedLeaf === void 0 || pinnedLeaf.turnId === latest2?.turnId)) return [...entries];
12930
- const leaf = pinnedLeaf ?? latest2;
12931
- if (!leaf) return [...entries];
12932
- const pathIds = /* @__PURE__ */ new Set();
12933
- let current = leaf;
12934
- while (current && !pathIds.has(current.turnId)) {
12935
- pathIds.add(current.turnId);
12936
- if (current.parentTurnId === null) break;
12937
- current = messagesById.get(current.parentTurnId);
12938
- }
12939
- const leafIndex = entries.findIndex((entry) => entry.kind === "message" && entry.turnId === leaf.turnId);
12940
- return entries.filter((entry, index) => entryBelongsToPath(entry, pathIds, leafIndex >= 0 && index <= leafIndex));
12941
- }
12942
- function resolveLeafMessage(entries, messagesById, leafTurnId) {
12943
- if (leafTurnId === void 0) return void 0;
12944
- const direct = messagesById.get(leafTurnId);
12945
- if (direct) return direct;
12946
- const sidecar = entries.find((entry) => entry.turnId === leafTurnId);
12947
- if (!sidecar) return void 0;
12948
- const anchor = sidecarAnchorTurnId(sidecar);
12949
- return anchor === null ? void 0 : messagesById.get(anchor);
12950
- }
12951
- function sidecarAnchorTurnId(entry) {
12952
- if (entry.kind === "label") return entry.targetTurnId;
12953
- if (entry.kind === "sessionInfo") return entry.targetTurnId ?? entry.parentTurnId;
12954
- if (entry.kind === "compactionSummary" && entry.firstKeptTurnId.length > 0) return entry.firstKeptTurnId;
12955
- return entry.parentTurnId;
12956
- }
12957
- function hasBranch(messages) {
12958
- const seenParents = /* @__PURE__ */ new Set();
12959
- for (const message of messages) {
12960
- if (message.parentTurnId === null) continue;
12961
- if (seenParents.has(message.parentTurnId)) return true;
12962
- seenParents.add(message.parentTurnId);
12755
+ if (view.personaOverride !== void 0) {
12756
+ lines.push(`persona override: prompt hash ${formatPersonaHashPrefix(view.personaOverride.promptHash)}`);
12963
12757
  }
12964
- return false;
12965
- }
12966
- function entryBelongsToPath(entry, pathIds, atOrBeforeLeaf) {
12967
- if (entry.kind === "message") return pathIds.has(entry.turnId);
12968
- if (entry.kind === "label") return pathIds.has(entry.targetTurnId);
12969
- if (entry.kind === "sessionInfo") return entry.targetTurnId === void 0 || pathIds.has(entry.targetTurnId);
12970
- if (entry.kind === "compactionSummary" && entry.firstKeptTurnId.length > 0 && pathIds.has(entry.firstKeptTurnId)) {
12971
- return true;
12758
+ if (view.escalation !== void 0) {
12759
+ const { requested, approved, denied, timedOut } = view.escalation;
12760
+ lines.push(`escalations: ${requested} requested, ${approved} approved, ${denied} denied, ${timedOut} timed out`);
12972
12761
  }
12973
- return entry.parentTurnId === null ? atOrBeforeLeaf : pathIds.has(entry.parentTurnId);
12974
- }
12975
-
12976
- // src/domains/session/tree/fork.ts
12977
- function linkedRecordFromEntry(entry) {
12978
- return {
12979
- id: entry.turnId,
12980
- parentId: entry.parentTurnId,
12981
- timestamp: entry.timestamp,
12982
- treeKind: entry.kind === "message" ? entry.role : null,
12983
- raw: entry
12984
- };
12985
- }
12986
- function traceAncestry(records, leafTurnId) {
12987
- const byId = /* @__PURE__ */ new Map();
12988
- for (const record of records) byId.set(record.id, record);
12989
- const path2 = [];
12990
- let current = byId.get(leafTurnId);
12991
- if (!current) throw new Error(`session.fork: parent turn not found: ${leafTurnId}`);
12992
- const seen = /* @__PURE__ */ new Set();
12993
- while (current) {
12994
- if (seen.has(current.id)) throw new Error(`session.fork: cycle in parent chain at ${current.id}`);
12995
- seen.add(current.id);
12996
- path2.unshift(current);
12997
- if (current.parentId === null) break;
12998
- const next = byId.get(current.parentId);
12999
- if (!next) throw new Error(`session.fork: broken parent chain at ${current.id}`);
13000
- current = next;
12762
+ if (view.autonomyEnforcement !== void 0) {
12763
+ const { grade, autonomy, externalMode, dangerousBypass } = view.autonomyEnforcement;
12764
+ const mode = externalMode !== void 0 ? ` mode=${externalMode}` : "";
12765
+ const bypass = dangerousBypass === true ? " dangerousBypass=true" : "";
12766
+ lines.push(`autonomy enforcement: ${grade} autonomy=${autonomy}${mode}${bypass}`);
13001
12767
  }
13002
- return path2;
13003
- }
13004
- function treeFromLinearPath(path2) {
13005
- return path2.filter((record) => record.treeKind !== null).map((record) => ({
13006
- id: record.id,
13007
- parentId: record.parentId,
13008
- at: record.timestamp,
13009
- kind: record.treeKind
13010
- }));
12768
+ return lines;
13011
12769
  }
13012
- function sessionEntryBelongsToPath(entry, pathIds, atOrBeforeForkPoint) {
13013
- if (entry.kind === "compactionSummary" && !atOrBeforeForkPoint) return false;
13014
- return entryBelongsToPath(entry, pathIds, atOrBeforeForkPoint);
13015
- }
13016
- function branchEntriesFromParent(parentMeta, leafTurnId) {
13017
- const parentCurrentPath = sessionPaths(parentMeta).current;
13018
- const records = readSessionFileEntries(parentCurrentPath).filter((entry) => !isSessionHeader(entry));
13019
- const parsed = collectSessionEntries(records, parentCurrentPath);
13020
- const linked = parsed.map(linkedRecordFromEntry);
13021
- const path2 = traceAncestry(linked, leafTurnId);
13022
- const pathIds = new Set(path2.map((record) => record.id));
13023
- const forkPointIndex = parsed.findIndex((entry) => linkedRecordFromEntry(entry).id === leafTurnId);
13024
- const entries = parsed.filter(
13025
- (entry, index) => sessionEntryBelongsToPath(entry, pathIds, forkPointIndex >= 0 && index <= forkPointIndex)
13026
- );
13027
- return {
13028
- parentCurrentPath,
13029
- entries,
13030
- tree: treeFromLinearPath(path2)
13031
- };
13032
- }
13033
- function forkFromState(input) {
13034
- const parentMeta = input.from.meta;
13035
- input.from.writer.flushAppends();
13036
- const branch = branchEntriesFromParent(parentMeta, input.parentTurnId);
13037
- const cwd = input.cwd ?? parentMeta.cwd;
13038
- const next = startSession({
13039
- cwd,
13040
- model: parentMeta.model,
13041
- target: parentMeta.target,
13042
- initialEntries: branch.entries,
13043
- initialTree: branch.tree,
13044
- parentSession: branch.parentCurrentPath,
13045
- parentTurnId: input.parentTurnId
13046
- });
13047
- enrichForkMeta(next.meta, parentMeta.id, input.parentTurnId);
13048
- void input.from.writer.close();
13049
- return { next, parentMeta, nodes: branch.tree };
12770
+ function provenanceCompactSuffix(view) {
12771
+ const parts = [];
12772
+ if (view.pipeline !== void 0) {
12773
+ const { fromRunId, position, inputBytes, inputTruncated } = view.pipeline;
12774
+ const from = fromRunId ?? "unknown";
12775
+ parts.push(`pipeline=step${position} from=${from} in=${inputBytes}b${inputTruncated ? " truncated" : ""}`);
12776
+ }
12777
+ if (view.personaOverride !== void 0) {
12778
+ parts.push(`persona=${formatPersonaHashPrefix(view.personaOverride.promptHash)}`);
12779
+ }
12780
+ if (view.escalation !== void 0) {
12781
+ const { requested, approved, denied, timedOut } = view.escalation;
12782
+ parts.push(`escalations=${requested}req/${approved}appr/${denied}deny/${timedOut}timeout`);
12783
+ }
12784
+ if (view.autonomyEnforcement !== void 0) {
12785
+ const { grade, autonomy, externalMode, dangerousBypass } = view.autonomyEnforcement;
12786
+ const mode = externalMode !== void 0 ? `/${externalMode}` : "";
12787
+ const bypass = dangerousBypass === true ? "/bypass" : "";
12788
+ parts.push(`enforcement=${grade}:${autonomy}${mode}${bypass}`);
12789
+ }
12790
+ return parts.length === 0 ? "" : ` ${parts.join(" ")}`;
13050
12791
  }
13051
12792
 
13052
- // src/domains/session/tree/manager.ts
12793
+ // src/domains/evidence/run-trust.ts
13053
12794
  init_esm_shims();
13054
- import { existsSync as existsSync15, renameSync as renameSync5, rmSync as rmSync4 } from "node:fs";
13055
- import { dirname as dirname3, join as join16 } from "node:path";
13056
- function readTreeBundle(sessionId) {
13057
- const reader = openSession(sessionId);
13058
- const meta = reader.meta();
13059
- const paths = sessionPaths(meta);
13060
- const nodes = [...reader.tree()];
13061
- const entries = collectSessionEntries(reader.turns(), paths.current);
13062
- const labels = resolveLabelMap(entries);
13063
- return { sessionId, meta, nodes, entries, labels };
13064
- }
13065
- function resolveLabelMap(entries) {
13066
- const out = /* @__PURE__ */ new Map();
13067
- for (const entry of entries) {
13068
- const info = labelFields(entry);
13069
- if (!info) continue;
13070
- const existing = out.get(info.targetTurnId);
13071
- if (existing && existing.timestamp > info.timestamp) continue;
13072
- if (info.label === void 0 || info.label === "") {
13073
- out.set(info.targetTurnId, { label: "", timestamp: info.timestamp });
13074
- continue;
13075
- }
13076
- out.set(info.targetTurnId, { label: info.label, timestamp: info.timestamp });
13077
- }
13078
- return out;
13079
- }
13080
- function labelFields(entry) {
13081
- if (entry.kind === "label") return entry;
13082
- if (entry.kind !== "sessionInfo") return null;
13083
- const info = entry;
13084
- if (!info.targetTurnId) return null;
13085
- const out = {
13086
- targetTurnId: info.targetTurnId,
13087
- timestamp: info.timestamp
13088
- };
13089
- if (info.label !== void 0) out.label = info.label;
13090
- return out;
13091
- }
13092
- function appendEntryToSessionFile(sessionId, entry) {
13093
- const meta = readSessionMeta(sessionId);
13094
- const paths = sessionPaths(meta);
13095
- appendSessionFileEntry(paths.current, entry);
13096
- }
13097
- function removeSessionDirectory(sessionId) {
13098
- const meta = readSessionMeta(sessionId);
13099
- const paths = sessionPaths(meta);
13100
- const dir = dirname3(paths.meta);
13101
- rmSync4(dir, { recursive: true, force: true });
13102
- }
13103
- function tombstoneSession(sessionId) {
13104
- const meta = readSessionMeta(sessionId);
13105
- const paths = sessionPaths(meta);
13106
- if (!existsSync15(paths.meta)) return;
13107
- const tombstone = join16(dirname3(paths.meta), "meta.deleted.json");
13108
- renameSync5(paths.meta, tombstone);
13109
- }
13110
12795
 
13111
- // src/domains/session/tree/navigator.ts
12796
+ // src/domains/evidence/trust-status.ts
13112
12797
  init_esm_shims();
13113
- function pickMeta(meta) {
13114
- const out = {
13115
- id: meta.id,
13116
- cwd: meta.cwd,
13117
- createdAt: meta.createdAt,
13118
- endedAt: meta.endedAt,
13119
- model: meta.model,
13120
- target: meta.target
13121
- };
13122
- if (meta.parentSessionId !== void 0) out.parentSessionId = meta.parentSessionId;
13123
- if (meta.parentTurnId !== void 0) out.parentTurnId = meta.parentTurnId;
13124
- return out;
12798
+ var TRUST_STATUS_VERSION = 1;
12799
+ var TRUST_STATUS_MAX_ARTIFACT_REFERENCES = 16;
12800
+ var TRUST_STATUS_MAX_IDENTIFIER_LENGTH = 512;
12801
+ var TRUST_STATUS_AXES = [
12802
+ "artifactIntegrity",
12803
+ "validationGrounding",
12804
+ "independentReview",
12805
+ "contextProvenance",
12806
+ "autonomyEnforcement",
12807
+ "completionEvidence"
12808
+ ];
12809
+ var TRUST_STATUS_STATES = {
12810
+ artifactIntegrity: ["verified", "failed", "absent", "unknown", "not_applicable"],
12811
+ validationGrounding: ["validated", "failed", "ungrounded", "absent", "unknown", "not_applicable"],
12812
+ independentReview: ["passed", "failed", "inconclusive", "not_independent", "absent", "unknown", "not_applicable"],
12813
+ contextProvenance: ["recorded", "invalid", "absent", "unknown", "not_applicable"],
12814
+ autonomyEnforcement: ["enforced", "approximated", "bypassed", "absent", "unknown", "not_applicable"],
12815
+ completionEvidence: ["evidenced", "incomplete", "limited", "absent", "unknown", "not_applicable"]
12816
+ };
12817
+ var SELF_REPORTED_ARTIFACT_KINDS = /* @__PURE__ */ new Set([
12818
+ "finish_contract_evidence",
12819
+ "run_receipt"
12820
+ ]);
12821
+ var AXIS_STATES = {
12822
+ artifactIntegrity: new Set(TRUST_STATUS_STATES.artifactIntegrity),
12823
+ validationGrounding: new Set(TRUST_STATUS_STATES.validationGrounding),
12824
+ independentReview: new Set(TRUST_STATUS_STATES.independentReview),
12825
+ contextProvenance: new Set(TRUST_STATUS_STATES.contextProvenance),
12826
+ autonomyEnforcement: new Set(TRUST_STATUS_STATES.autonomyEnforcement),
12827
+ completionEvidence: new Set(TRUST_STATUS_STATES.completionEvidence)
12828
+ };
12829
+ var AXIS_SOURCES = {
12830
+ artifactIntegrity: /* @__PURE__ */ new Set(["receipt_integrity_verification", "compatibility"]),
12831
+ validationGrounding: /* @__PURE__ */ new Set(["run_receipt", "evidence_bundle", "compatibility"]),
12832
+ independentReview: /* @__PURE__ */ new Set(["gate_decision", "compatibility"]),
12833
+ contextProvenance: /* @__PURE__ */ new Set(["run_receipt", "evidence_bundle", "compatibility"]),
12834
+ autonomyEnforcement: /* @__PURE__ */ new Set(["run_receipt", "compatibility"]),
12835
+ completionEvidence: /* @__PURE__ */ new Set(["finish_contract", "compatibility"])
12836
+ };
12837
+ var SOURCE_AUTHORITIES = {
12838
+ receipt_integrity_verification: /* @__PURE__ */ new Set(["clio"]),
12839
+ run_receipt: /* @__PURE__ */ new Set(["clio", "validator", "runtime", "external_system", "unknown"]),
12840
+ gate_decision: /* @__PURE__ */ new Set(["clio", "reviewer", "operator", "unknown"]),
12841
+ evidence_bundle: /* @__PURE__ */ new Set(["clio"]),
12842
+ finish_contract: /* @__PURE__ */ new Set(["clio"]),
12843
+ compatibility: /* @__PURE__ */ new Set(["clio", "unknown"])
12844
+ };
12845
+ var ABSENCE_REASONS = /* @__PURE__ */ new Set([
12846
+ "not_recorded",
12847
+ "not_observed",
12848
+ "artifact_missing",
12849
+ "historical_format"
12850
+ ]);
12851
+ var SOURCE_KINDS = /* @__PURE__ */ new Set([
12852
+ "receipt_integrity_verification",
12853
+ "run_receipt",
12854
+ "gate_decision",
12855
+ "evidence_bundle",
12856
+ "finish_contract",
12857
+ "compatibility"
12858
+ ]);
12859
+ var AUTHORITY_KINDS = /* @__PURE__ */ new Set([
12860
+ "clio",
12861
+ "validator",
12862
+ "reviewer",
12863
+ "operator",
12864
+ "runtime",
12865
+ "external_system",
12866
+ "unknown"
12867
+ ]);
12868
+ var ARTIFACT_KINDS = /* @__PURE__ */ new Set([
12869
+ "run_receipt",
12870
+ "validation_result",
12871
+ "gate_decision",
12872
+ "briefing",
12873
+ "project_context",
12874
+ "autonomy_policy",
12875
+ "finish_contract_evidence",
12876
+ "evidence_bundle",
12877
+ "session_entry"
12878
+ ]);
12879
+ function isRecord10(value) {
12880
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13125
12881
  }
13126
- function computeLeafId(nodes) {
13127
- if (nodes.length === 0) return null;
13128
- const hasChild = /* @__PURE__ */ new Set();
13129
- for (const node of nodes) {
13130
- if (node.parentId) hasChild.add(node.parentId);
13131
- }
13132
- let leaf = null;
13133
- for (const node of nodes) {
13134
- if (hasChild.has(node.id)) continue;
13135
- if (!leaf || node.at >= leaf.at) leaf = node;
13136
- }
13137
- return leaf?.id ?? null;
12882
+ function hasExactKeys(value, keys) {
12883
+ const expected = new Set(keys);
12884
+ return Object.keys(value).length === expected.size && Object.keys(value).every((key) => expected.has(key));
13138
12885
  }
13139
- function buildTreeSnapshot(input) {
13140
- const nodesById = {};
13141
- for (const node of input.nodes) {
13142
- const entry = {
13143
- id: node.id,
13144
- parentId: node.parentId,
13145
- at: node.at,
13146
- kind: node.kind,
13147
- children: []
13148
- };
13149
- const resolved = input.labels.get(node.id);
13150
- if (resolved && resolved.label !== "") entry.label = resolved.label;
13151
- const preview = input.previews?.get(node.id);
13152
- if (preview !== void 0 && preview.length > 0) entry.preview = preview;
13153
- nodesById[node.id] = entry;
13154
- }
13155
- const rootIds = [];
13156
- for (const node of input.nodes) {
13157
- const parent = node.parentId ? nodesById[node.parentId] : void 0;
13158
- if (!parent) {
13159
- rootIds.push(node.id);
13160
- } else {
13161
- parent.children.push(node.id);
13162
- }
12886
+ function isTrustStatusIdentifier(value) {
12887
+ if (typeof value !== "string" || value.trim().length === 0 || value.length > TRUST_STATUS_MAX_IDENTIFIER_LENGTH) {
12888
+ return false;
13163
12889
  }
13164
- const byTime = (a, b) => {
13165
- const na = nodesById[a];
13166
- const nb = nodesById[b];
13167
- if (!na || !nb) return a < b ? -1 : a > b ? 1 : 0;
13168
- if (na.at === nb.at) return na.id < nb.id ? -1 : na.id > nb.id ? 1 : 0;
13169
- return na.at < nb.at ? -1 : 1;
13170
- };
13171
- rootIds.sort(byTime);
13172
- for (const key of Object.keys(nodesById)) {
13173
- const entry = nodesById[key];
13174
- if (entry) entry.children.sort(byTime);
12890
+ for (const character of value) {
12891
+ const codePoint = character.codePointAt(0);
12892
+ if (codePoint !== void 0 && (codePoint < 32 || codePoint === 127)) return false;
13175
12893
  }
13176
- const leafId = input.leafId !== void 0 ? input.leafId : computeLeafId(input.nodes);
13177
- return {
13178
- sessionId: input.meta.id,
13179
- meta: pickMeta(input.meta),
13180
- leafId,
13181
- nodesById,
13182
- rootIds
13183
- };
13184
- }
13185
-
13186
- // src/domains/session/tree/preview.ts
13187
- init_esm_shims();
13188
- var TURN_PREVIEW_MAX_CHARS = 60;
13189
- var ESC = String.fromCharCode(27);
13190
- var ANSI_CSI_RE = new RegExp(`${ESC}\\[[0-9;?]*[ -/]*[@-~]`, "g");
13191
- var ANSI_FALLBACK_RE = new RegExp(`${ESC}[@-_]`, "g");
13192
- function stripAnsi(text) {
13193
- return text.replace(ANSI_CSI_RE, "").replace(ANSI_FALLBACK_RE, "");
13194
- }
13195
- function collapseSingleLine(text) {
13196
- return text.replace(/\s+/g, " ").trim();
13197
- }
13198
- function sanitize(text) {
13199
- return collapseSingleLine(stripTokenizerSentinels(stripAnsi(text)));
12894
+ return true;
13200
12895
  }
13201
- function clamp(text, max) {
13202
- if (text.length <= max) return text;
13203
- if (max <= 1) return text.slice(0, max);
13204
- return `${text.slice(0, max - 1)}\u2026`;
12896
+ function compareArtifactReferences(left, right) {
12897
+ const leftKey = `${left.kind}\0${left.id}\0${left.digest?.value ?? ""}`;
12898
+ const rightKey = `${right.kind}\0${right.id}\0${right.digest?.value ?? ""}`;
12899
+ return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
13205
12900
  }
13206
- function extractPlainText(payload) {
13207
- if (typeof payload === "string") {
13208
- const sanitized = sanitize(payload);
13209
- return sanitized.length > 0 ? sanitized : null;
12901
+ function normalizeArtifactReference(value, path2) {
12902
+ if (!isRecord10(value)) throw new Error(`${path2} must be an object`);
12903
+ if (!hasExactKeys(value, value.digest === void 0 ? ["kind", "id"] : ["kind", "id", "digest"])) {
12904
+ throw new Error(`${path2} has unknown or missing fields`);
13210
12905
  }
13211
- if (!payload || typeof payload !== "object") return null;
13212
- const obj = payload;
13213
- if (typeof obj.text === "string") {
13214
- const sanitized = sanitize(obj.text);
13215
- if (sanitized.length > 0) return sanitized;
12906
+ if (typeof value.kind !== "string" || !ARTIFACT_KINDS.has(value.kind)) {
12907
+ throw new Error(`${path2}.kind is invalid`);
13216
12908
  }
13217
- if (Array.isArray(obj.content)) {
13218
- const parts = [];
13219
- for (const block of obj.content) {
13220
- if (!block || typeof block !== "object") continue;
13221
- const b = block;
13222
- if (b.type === "text" && typeof b.text === "string") parts.push(b.text);
13223
- }
13224
- if (parts.length > 0) {
13225
- const sanitized = sanitize(parts.join(" "));
13226
- if (sanitized.length > 0) return sanitized;
12909
+ if (!isTrustStatusIdentifier(value.id)) throw new Error(`${path2}.id is invalid`);
12910
+ const reference = { kind: value.kind, id: value.id };
12911
+ if (value.digest !== void 0) {
12912
+ if (!isRecord10(value.digest) || !hasExactKeys(value.digest, ["algorithm", "value"]) || value.digest.algorithm !== "sha256" || typeof value.digest.value !== "string" || !/^[a-f0-9]{64}$/u.test(value.digest.value)) {
12913
+ throw new Error(`${path2}.digest is invalid`);
13227
12914
  }
12915
+ reference.digest = { algorithm: "sha256", value: value.digest.value };
13228
12916
  }
13229
- return null;
12917
+ return reference;
13230
12918
  }
13231
- function pickToolArg(toolName, args) {
13232
- if (!args || typeof args !== "object") return "";
13233
- const a = args;
13234
- const preferred = {
13235
- read: ["path"],
13236
- write: ["path"],
13237
- edit: ["path"],
13238
- bash: ["command"],
13239
- code_nav: ["query", "mode"],
13240
- git: ["op"],
13241
- verify: ["check"],
13242
- grep: ["pattern", "query"],
13243
- search: ["query", "pattern"],
13244
- web_fetch: ["url"],
13245
- web_search: ["query"]
13246
- };
13247
- const order = preferred[toolName] ?? [];
13248
- for (const key of order) {
13249
- const value = a[key];
13250
- if (typeof value === "string" && value.length > 0) return sanitize(value);
13251
- if (typeof value === "number") return String(value);
12919
+ function normalizeAttributedStatus(axis, value) {
12920
+ if (!hasExactKeys(value, ["state", "source", "authority", "artifacts"])) {
12921
+ throw new Error(`${axis} has unknown or missing fields`);
13252
12922
  }
13253
- for (const [, value] of Object.entries(a)) {
13254
- if (typeof value === "string" && value.length > 0) return sanitize(value);
13255
- if (typeof value === "number" || typeof value === "boolean") return String(value);
12923
+ if (!isRecord10(value.source) || !hasExactKeys(value.source, ["kind", "id"])) {
12924
+ throw new Error(`${axis}.source is invalid`);
13256
12925
  }
13257
- return "";
13258
- }
13259
- function extractToolCall(payload) {
13260
- if (!payload || typeof payload !== "object") return null;
13261
- const p = payload;
13262
- const toolName = typeof p.name === "string" ? p.name : typeof p.toolName === "string" ? p.toolName : null;
13263
- if (!toolName) return null;
13264
- const args = p.args !== void 0 ? p.args : p.arguments ?? p.input;
13265
- return { toolName, args };
13266
- }
13267
- function extractToolResult(payload) {
13268
- if (!payload || typeof payload !== "object") return null;
13269
- const p = payload;
13270
- if (!("toolCallId" in p) && !("result" in p) && !("isError" in p)) return null;
13271
- const isError = p.isError === true;
13272
- let text = "";
13273
- const result = p.result;
13274
- if (typeof result === "string") text = result;
13275
- else if (result && typeof result === "object") {
13276
- const r = result;
13277
- if (Array.isArray(r.content)) {
13278
- const parts = [];
13279
- for (const block of r.content) {
13280
- if (!block || typeof block !== "object") continue;
13281
- const b = block;
13282
- if (b.type === "text" && typeof b.text === "string") parts.push(b.text);
13283
- }
13284
- text = parts.join(" ");
13285
- } else if (typeof r.text === "string") {
13286
- text = r.text;
13287
- }
12926
+ if (typeof value.source.kind !== "string" || !SOURCE_KINDS.has(value.source.kind) || !AXIS_SOURCES[axis].has(value.source.kind) || !isTrustStatusIdentifier(value.source.id)) {
12927
+ throw new Error(`${axis}.source is invalid`);
13288
12928
  }
13289
- if (text.length === 0 && typeof p.errorMessage === "string") text = p.errorMessage;
13290
- return { isError, text: sanitize(text) };
13291
- }
13292
- function assistantStopMarker(payload) {
13293
- if (!payload || typeof payload !== "object") return null;
13294
- const sr = payload.stopReason;
13295
- if (sr === "aborted") return "(aborted)";
13296
- if (sr === "error") return "(error)";
13297
- return null;
13298
- }
13299
- function buildTurnPreview(turn, max = TURN_PREVIEW_MAX_CHARS) {
13300
- const budget = Math.max(1, max);
13301
- switch (turn.kind) {
13302
- case "user": {
13303
- const text = extractPlainText(turn.payload);
13304
- return text === null ? "(empty)" : clamp(text, budget);
13305
- }
13306
- case "assistant": {
13307
- const stop = assistantStopMarker(turn.payload);
13308
- const text = extractPlainText(turn.payload);
13309
- if (text !== null) return clamp(text, budget);
13310
- if (stop !== null) return stop;
13311
- if (turn.payload && typeof turn.payload === "object" && Array.isArray(turn.payload.content)) {
13312
- const content = turn.payload.content;
13313
- const toolCalls = content.filter(
13314
- (b) => b && typeof b === "object" && b.type === "toolCall"
13315
- );
13316
- if (toolCalls.length > 0) {
13317
- const names = toolCalls.map((b) => b.name).filter((n) => typeof n === "string");
13318
- if (names.length > 0) return clamp(`(tool calls) ${names.join(", ")}`, budget);
13319
- }
13320
- }
13321
- return "(empty)";
13322
- }
13323
- case "tool_call": {
13324
- const call = extractToolCall(turn.payload);
13325
- if (!call) return "(empty)";
13326
- const arg = pickToolArg(call.toolName, call.args);
13327
- const inner = arg.length > 0 ? `"${clamp(arg, Math.max(8, budget - call.toolName.length - 4))}"` : "";
13328
- const composed = `${call.toolName}(${inner})`;
13329
- return clamp(composed, budget);
13330
- }
13331
- case "tool_result": {
13332
- const result = extractToolResult(turn.payload);
13333
- if (!result) return "(empty)";
13334
- const status = result.isError ? "err" : "ok";
13335
- const head = `[${status}]`;
13336
- if (result.text.length === 0) return head;
13337
- const remaining = Math.max(4, budget - head.length - 1);
13338
- return `${head} ${clamp(result.text, remaining)}`;
13339
- }
13340
- case "system": {
13341
- const text = extractPlainText(turn.payload);
13342
- return text === null ? "(system)" : clamp(text, budget);
13343
- }
13344
- case "checkpoint":
13345
- return "(checkpoint)";
13346
- default:
13347
- return `(${String(turn.kind)})`;
12929
+ if (!isRecord10(value.authority) || !hasExactKeys(value.authority, ["kind", "id"])) {
12930
+ throw new Error(`${axis}.authority is invalid`);
13348
12931
  }
13349
- }
13350
-
13351
- // src/domains/session/extension.ts
13352
- function createSessionBundle(context) {
13353
- let state = null;
13354
- let currentTurnId = null;
13355
- function emitPark(sessionId, reason) {
13356
- context.bus.emit(BusChannels.SessionParked, { sessionId, reason, at: Date.now() });
13357
- }
13358
- function emitResume(sessionId, via) {
13359
- context.bus.emit(BusChannels.SessionResumed, { sessionId, via, at: Date.now() });
13360
- }
13361
- function emitTurnSwitched(sessionId, turnId) {
13362
- context.bus.emit(BusChannels.SessionTurnSwitched, { sessionId, turnId, at: Date.now() });
13363
- }
13364
- function resolveLeafOnOpen(resumed) {
13365
- const pinned = resumed.state.meta.pinnedLeafTurnId;
13366
- if (pinned && resumed.nodes.some((node) => node.id === pinned)) return pinned;
13367
- return computeLeafId(resumed.nodes);
13368
- }
13369
- async function closeCurrent(reason = "close") {
13370
- if (!state) return;
13371
- const s = state;
13372
- emitPark(s.meta.id, reason);
13373
- state = null;
13374
- currentTurnId = null;
13375
- await s.writer.close();
13376
- }
13377
- async function flushIfCurrent(sessionId) {
13378
- if (state?.meta.id === sessionId) {
13379
- await state.writer.persistTree();
13380
- }
13381
- }
13382
- function structuralTreeNodes(entries, previews) {
13383
- const nodes = [];
13384
- for (const entry of entries) {
13385
- if (entry.kind === "compactionSummary") {
13386
- nodes.push({ id: entry.turnId, parentId: entry.parentTurnId, at: entry.timestamp, kind: "compaction" });
13387
- const summarized = entry.messagesSummarized === void 0 ? "history" : `${entry.messagesSummarized} entries`;
13388
- const after = entry.tokensAfter === void 0 ? "" : ` -> ~${entry.tokensAfter}`;
13389
- previews.set(entry.turnId, `${summarized} summarized, ~${entry.tokensBefore}${after} tokens`);
13390
- continue;
13391
- }
13392
- if (entry.kind === "branchSummary") {
13393
- nodes.push({ id: entry.turnId, parentId: entry.parentTurnId, at: entry.timestamp, kind: "branch" });
13394
- const text = entry.summary.split("\n", 1)[0] ?? "";
13395
- previews.set(
13396
- entry.turnId,
13397
- text.length > 0 ? `returned from ${entry.fromTurnId}: ${text}` : `returned from ${entry.fromTurnId}`
13398
- );
13399
- }
13400
- }
13401
- return nodes;
12932
+ if (typeof value.authority.kind !== "string" || !AUTHORITY_KINDS.has(value.authority.kind) || !SOURCE_AUTHORITIES[value.source.kind].has(
12933
+ value.authority.kind
12934
+ ) || !isTrustStatusIdentifier(value.authority.id)) {
12935
+ throw new Error(`${axis}.authority is invalid`);
13402
12936
  }
13403
- function snapshotFor(sessionId) {
13404
- const bundle = readTreeBundle(sessionId);
13405
- const meta = state?.meta.id === sessionId ? state.meta : bundle.meta;
13406
- const previews = /* @__PURE__ */ new Map();
13407
- let structural = [];
13408
- try {
13409
- for (const entry of bundle.entries) {
13410
- if (entry.kind !== "message") continue;
13411
- const text = buildTurnPreview({ kind: entry.role, payload: entry.payload });
13412
- if (text.length > 0) previews.set(entry.turnId, text);
13413
- }
13414
- structural = structuralTreeNodes(bundle.entries, previews);
13415
- } catch {
13416
- }
13417
- const persistedLeaf = bundle.meta.pinnedLeafTurnId && bundle.nodes.some((node) => node.id === bundle.meta.pinnedLeafTurnId) ? bundle.meta.pinnedLeafTurnId : computeLeafId(bundle.nodes);
13418
- return buildTreeSnapshot({
13419
- meta,
13420
- nodes: [...bundle.nodes, ...structural],
13421
- labels: bundle.labels,
13422
- previews,
13423
- // The leaf is the next append point, so it is computed over turn nodes
13424
- // only: a structural node marks a moment in the timeline, never a place
13425
- // the session continues from.
13426
- leafId: state?.meta.id === sessionId ? currentTurnId : persistedLeaf
13427
- });
12937
+ if (value.source.kind === "compatibility" && value.state !== "unknown" && value.state !== "not_applicable") {
12938
+ throw new Error(`${axis} compatibility source cannot establish ${value.state}`);
13428
12939
  }
13429
- const contract = {
13430
- current: () => state?.meta ?? null,
13431
- create(input) {
13432
- const cwd = input?.cwd ?? process.cwd();
13433
- const startInput = { cwd };
13434
- if (input?.model !== void 0) startInput.model = input.model;
13435
- if (input?.target !== void 0) startInput.target = input.target;
13436
- if (state) {
13437
- const prior = state;
13438
- emitPark(prior.meta.id, "create_new");
13439
- state = null;
13440
- void prior.writer.close();
13441
- }
13442
- const next = startSession(startInput);
13443
- next.meta.workspace = probeWorkspace(cwd);
13444
- persistSessionMeta(next);
13445
- state = next;
13446
- currentTurnId = null;
13447
- return next.meta;
13448
- },
13449
- append(turn) {
13450
- if (!state) throw new Error("session.append: no current session");
13451
- if (turn.parentId !== currentTurnId) {
13452
- throw new Error(
13453
- `session.append: turn parentId ${turn.parentId ?? "null"} is not this session's current leaf (expected ${currentTurnId ?? "null"}); refusing to parent a turn onto another session's turn`
13454
- );
13455
- }
13456
- const record = appendTurn(state, turn);
13457
- currentTurnId = record.id;
13458
- if (state.meta.pinnedLeafTurnId !== void 0 && state.meta.pinnedLeafTurnId !== null) {
13459
- state.meta.pinnedLeafTurnId = null;
13460
- persistSessionMeta(state);
13461
- }
13462
- return record;
13463
- },
13464
- appendEntry(entry) {
13465
- if (!state) throw new Error("session.appendEntry: no current session");
13466
- return appendEntry(state, entry);
13467
- },
13468
- replaceEntries(entries) {
13469
- if (!state) throw new Error("session.replaceEntries: no current session");
13470
- replaceEntries(state, entries);
13471
- },
13472
- recordSkillActivation(activation) {
13473
- if (!state) throw new Error("session.recordSkillActivation: no current session");
13474
- appendEntry(state, {
13475
- kind: "skillActivation",
13476
- parentTurnId: activation.turnId ?? null,
13477
- activation
13478
- });
13479
- const existing = state.meta.skillActivations ?? [];
13480
- state.meta.skillActivations = [...existing, activation];
13481
- persistSessionMeta(state);
13482
- return activation;
13483
- },
13484
- async checkpoint(reason) {
13485
- if (!state) throw new Error("session.checkpoint: no current session");
13486
- await performCheckpoint(state, reason);
13487
- },
13488
- flushAppends() {
13489
- if (!state) throw new Error("session.flushAppends: no current session");
13490
- state.writer.flushAppends();
13491
- },
13492
- resume(sessionId) {
13493
- if (state && state.meta.id === sessionId) return state.meta;
13494
- const resumed = resumeSessionState(sessionId);
13495
- if (state) {
13496
- const prior = state;
13497
- emitPark(prior.meta.id, "resume_other");
13498
- void prior.writer.close();
13499
- }
13500
- state = resumed.state;
13501
- currentTurnId = resolveLeafOnOpen(resumed);
13502
- emitResume(resumed.state.meta.id, "resume");
13503
- return resumed.state.meta;
13504
- },
13505
- fork(parentTurnId, input) {
13506
- if (!state) throw new Error("session.fork: no current session to fork from");
13507
- const prior = state;
13508
- const { next, nodes } = forkFromState({
13509
- from: prior,
13510
- parentTurnId,
13511
- ...input?.cwd !== void 0 ? { cwd: input.cwd } : {}
13512
- });
13513
- emitPark(prior.meta.id, "fork");
13514
- state = next;
13515
- currentTurnId = computeLeafId(nodes);
13516
- return next.meta;
13517
- },
13518
- tree(sessionId) {
13519
- const id = sessionId ?? state?.meta.id;
13520
- if (!id) throw new Error("session.tree: no sessionId provided and no current session");
13521
- if (state?.meta.id === id) void flushIfCurrent(id);
13522
- return snapshotFor(id);
13523
- },
13524
- switchBranch(sessionId) {
13525
- if (state?.meta.id === sessionId) return state.meta;
13526
- const resumed = resumeSessionState(sessionId);
13527
- if (state) {
13528
- const prior = state;
13529
- emitPark(prior.meta.id, "switch_branch");
13530
- void prior.writer.close();
13531
- }
13532
- state = resumed.state;
13533
- currentTurnId = resolveLeafOnOpen(resumed);
13534
- emitResume(resumed.state.meta.id, "switch_branch");
13535
- return resumed.state.meta;
13536
- },
13537
- switchTurn(turnId) {
13538
- if (!state) throw new Error("session.switchTurn: no current session");
13539
- void flushIfCurrent(state.meta.id);
13540
- const nodes = readTreeBundle(state.meta.id).nodes;
13541
- if (!nodes.some((node) => node.id === turnId)) {
13542
- throw new Error(`session.switchTurn: turn not found: ${turnId}`);
13543
- }
13544
- currentTurnId = turnId;
13545
- state.meta.pinnedLeafTurnId = turnId;
13546
- persistSessionMeta(state);
13547
- emitTurnSwitched(state.meta.id, turnId);
13548
- return state.meta;
13549
- },
13550
- editLabel(turnId, label, sessionId) {
13551
- const targetId = sessionId ?? state?.meta.id;
13552
- if (!targetId) throw new Error("session.editLabel: no sessionId provided and no current session");
13553
- if (state && state.meta.id === targetId) {
13554
- appendEntry(state, {
13555
- kind: "label",
13556
- parentTurnId: null,
13557
- targetTurnId: turnId,
13558
- label
13559
- });
13560
- return;
13561
- }
13562
- const entry = {
13563
- kind: "label",
13564
- turnId: newTurnId(),
13565
- parentTurnId: null,
13566
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
13567
- targetTurnId: turnId,
13568
- label
13569
- };
13570
- appendEntryToSessionFile(targetId, entry);
13571
- },
13572
- setName(name, sessionId) {
13573
- const targetId = sessionId ?? state?.meta.id;
13574
- if (!targetId) throw new Error("session.setName: no sessionId provided and no current session");
13575
- if (state && state.meta.id === targetId) {
13576
- appendEntry(state, {
13577
- kind: "sessionInfo",
13578
- parentTurnId: null,
13579
- name
13580
- });
13581
- return;
13582
- }
13583
- const entry = {
13584
- kind: "sessionInfo",
13585
- turnId: newTurnId(),
13586
- parentTurnId: null,
13587
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
13588
- name
13589
- };
13590
- appendEntryToSessionFile(targetId, entry);
13591
- },
13592
- deleteSession(id, opts) {
13593
- if (state?.meta.id === id) {
13594
- throw new Error("session.deleteSession: refusing to delete the currently open session; close() first");
13595
- }
13596
- const options = opts ?? {};
13597
- if (options.keepFiles) {
13598
- tombstoneSession(id);
13599
- } else {
13600
- removeSessionDirectory(id);
13601
- }
13602
- },
13603
- history() {
13604
- const cwd = state?.meta.cwd ?? process.cwd();
13605
- return listSessionsForCwd(cwd);
13606
- },
13607
- async close() {
13608
- await closeCurrent();
13609
- }
13610
- };
13611
- const extension = {
13612
- async start() {
13613
- },
13614
- async stop() {
13615
- if (!state) return;
13616
- try {
13617
- await performCheckpoint(state, "shutdown");
13618
- } catch (err) {
13619
- process.stderr.write(
13620
- `[clio:session] shutdown checkpoint failed: ${err instanceof Error ? err.message : String(err)}
13621
- `
13622
- );
13623
- }
13624
- await closeCurrent("shutdown");
13625
- }
13626
- };
13627
- return { extension, contract };
13628
- }
13629
-
13630
- // src/domains/session/manifest.ts
13631
- init_esm_shims();
13632
- var SessionManifest = {
13633
- name: "session",
13634
- dependsOn: ["config"]
13635
- };
13636
-
13637
- // src/domains/session/archive-readers.ts
13638
- init_esm_shims();
13639
- import { readdir, readFile } from "node:fs/promises";
13640
- import { join as join17 } from "node:path";
13641
- async function readAuditRows(stateDir) {
13642
- const root = join17(stateDir, "audit");
13643
- let files;
13644
- try {
13645
- files = await readdir(root);
13646
- } catch (error) {
13647
- const err = error;
13648
- if (err.code === "ENOENT") return { rows: [], errors: [] };
13649
- return { rows: [], errors: [`audit root read error: ${err.message ?? String(err)}`] };
12940
+ if (!Array.isArray(value.artifacts) || value.artifacts.length > TRUST_STATUS_MAX_ARTIFACT_REFERENCES) {
12941
+ throw new Error(`${axis}.artifacts exceeds the bounded reference list`);
13650
12942
  }
13651
- const rows = [];
13652
- const errors = [];
13653
- for (const file of files.filter((name) => name.endsWith(".jsonl")).sort(compareStrings2)) {
13654
- const path2 = join17(root, file);
13655
- let raw;
13656
- try {
13657
- raw = await readFile(path2, "utf8");
13658
- } catch (error) {
13659
- const err = error;
13660
- errors.push(`${path2}: ${err.message ?? String(err)}`);
13661
- continue;
13662
- }
13663
- const lines = raw.split("\n");
13664
- for (let index = 0; index < lines.length; index += 1) {
13665
- const line = lines[index];
13666
- if (line === void 0 || line.length === 0) continue;
13667
- let parsed;
13668
- try {
13669
- parsed = JSON.parse(line);
13670
- } catch (error) {
13671
- const message = error instanceof Error ? error.message : String(error);
13672
- errors.push(`${path2}:${index + 1}: invalid JSON: ${message}`);
13673
- continue;
13674
- }
13675
- if (!isRecord9(parsed)) {
13676
- errors.push(`${path2}:${index + 1}: expected object`);
13677
- continue;
13678
- }
13679
- const auditKind = readOptionalString(parsed.kind) ?? "tool_call";
13680
- rows.push({
13681
- file,
13682
- line: index + 1,
13683
- row: parsed,
13684
- ts: readOptionalString(parsed.ts),
13685
- auditKind,
13686
- correlationId: readOptionalString(parsed.correlationId) ?? ""
13687
- });
12943
+ const artifacts = value.artifacts.map(
12944
+ (entry, index) => normalizeArtifactReference(entry, `${axis}.artifacts[${index}]`)
12945
+ );
12946
+ artifacts.sort(compareArtifactReferences);
12947
+ for (let index = 1; index < artifacts.length; index += 1) {
12948
+ if (compareArtifactReferences(
12949
+ artifacts[index - 1],
12950
+ artifacts[index]
12951
+ ) === 0) {
12952
+ throw new Error(`${axis}.artifacts contains a duplicate reference`);
13688
12953
  }
13689
12954
  }
13690
- return { rows, errors };
12955
+ return {
12956
+ state: value.state,
12957
+ source: { kind: value.source.kind, id: value.source.id },
12958
+ authority: { kind: value.authority.kind, id: value.authority.id },
12959
+ artifacts
12960
+ };
13691
12961
  }
13692
- async function readSessionEntriesForId(stateDir, sessionId) {
13693
- const root = join17(stateDir, "sessions");
13694
- let cwdHashes;
13695
- try {
13696
- cwdHashes = await readdir(root);
13697
- } catch (error) {
13698
- const err = error;
13699
- if (err.code === "ENOENT") return { entries: [], missing: true, errors: [] };
13700
- return { entries: [], missing: false, errors: [`session root read error: ${err.message ?? String(err)}`] };
12962
+ function normalizeAxis(axis, value) {
12963
+ if (!isRecord10(value) || typeof value.state !== "string" || !AXIS_STATES[axis].has(value.state)) {
12964
+ throw new Error(`${axis}.state is invalid`);
13701
12965
  }
13702
- for (const cwdHash2 of cwdHashes.sort(compareStrings2)) {
13703
- const currentPath = join17(root, cwdHash2, sessionId, "current.jsonl");
13704
- let raw;
13705
- let source = currentPath;
13706
- try {
13707
- raw = await readFile(currentPath, "utf8");
13708
- } catch (error) {
13709
- const err = error;
13710
- if (err.code === "ENOENT") {
13711
- const tmpPath = `${currentPath}.tmp`;
13712
- try {
13713
- raw = await readFile(tmpPath, "utf8");
13714
- source = tmpPath;
13715
- } catch {
13716
- continue;
13717
- }
13718
- } else if (err.code === "ENOTDIR") {
13719
- continue;
13720
- } else {
13721
- return { entries: [], missing: false, errors: [`${currentPath}: ${err.message ?? String(err)}`] };
13722
- }
12966
+ if (value.state === "absent") {
12967
+ if (!hasExactKeys(value, ["state", "reason"]) || typeof value.reason !== "string" || !ABSENCE_REASONS.has(value.reason)) {
12968
+ throw new Error(`${axis} absent state is invalid`);
13723
12969
  }
13724
- return parseSessionEntries(raw, source);
12970
+ return { state: "absent", reason: value.reason };
13725
12971
  }
13726
- return { entries: [], missing: true, errors: [] };
12972
+ return normalizeAttributedStatus(axis, value);
13727
12973
  }
13728
- function parseSessionEntries(raw, source) {
13729
- const entries = [];
13730
- const errors = [];
13731
- const lines = raw.split("\n");
13732
- for (let index = 0; index < lines.length; index += 1) {
13733
- const line = lines[index];
13734
- if (line === void 0 || line.trim().length === 0) continue;
13735
- let parsed;
13736
- try {
13737
- parsed = JSON.parse(line);
13738
- } catch (error) {
13739
- const message = error instanceof Error ? error.message : String(error);
13740
- errors.push(`${source}:${index + 1}: invalid JSON: ${message}`);
13741
- continue;
13742
- }
13743
- if (isSessionHeader(parsed)) continue;
13744
- if (isSessionEntry(parsed)) {
13745
- entries.push(parsed);
13746
- continue;
13747
- }
13748
- errors.push(
13749
- `session ledger contains an unreadable entry (missing kind discriminant): ${source}. Remove or compact the session to reset.`
12974
+ function normalizeTrustStatus(value) {
12975
+ if (!isRecord10(value) || !hasExactKeys(value, ["version", ...TRUST_STATUS_AXES])) {
12976
+ throw new Error("trust status has unknown or missing fields");
12977
+ }
12978
+ if (value.version !== TRUST_STATUS_VERSION) throw new Error("trust status version is invalid");
12979
+ return {
12980
+ version: TRUST_STATUS_VERSION,
12981
+ artifactIntegrity: normalizeAxis("artifactIntegrity", value.artifactIntegrity),
12982
+ validationGrounding: normalizeAxis("validationGrounding", value.validationGrounding),
12983
+ independentReview: normalizeAxis("independentReview", value.independentReview),
12984
+ contextProvenance: normalizeAxis("contextProvenance", value.contextProvenance),
12985
+ autonomyEnforcement: normalizeAxis("autonomyEnforcement", value.autonomyEnforcement),
12986
+ completionEvidence: normalizeAxis("completionEvidence", value.completionEvidence)
12987
+ };
12988
+ }
12989
+ function absentTrustStatus(reason) {
12990
+ return { state: "absent", reason };
12991
+ }
12992
+ function composeTrustStatus(...projections) {
12993
+ const axes = {
12994
+ artifactIntegrity: absentTrustStatus("not_recorded"),
12995
+ validationGrounding: absentTrustStatus("not_recorded"),
12996
+ independentReview: absentTrustStatus("not_recorded"),
12997
+ contextProvenance: absentTrustStatus("not_recorded"),
12998
+ autonomyEnforcement: absentTrustStatus("not_recorded"),
12999
+ completionEvidence: absentTrustStatus("not_recorded")
13000
+ };
13001
+ for (const projection of projections) {
13002
+ if (projection.artifactIntegrity !== void 0) axes.artifactIntegrity = projection.artifactIntegrity;
13003
+ if (projection.validationGrounding !== void 0) axes.validationGrounding = projection.validationGrounding;
13004
+ if (projection.independentReview !== void 0) axes.independentReview = projection.independentReview;
13005
+ if (projection.contextProvenance !== void 0) axes.contextProvenance = projection.contextProvenance;
13006
+ if (projection.autonomyEnforcement !== void 0) axes.autonomyEnforcement = projection.autonomyEnforcement;
13007
+ if (projection.completionEvidence !== void 0) axes.completionEvidence = projection.completionEvidence;
13008
+ }
13009
+ return normalizeTrustStatus({ version: TRUST_STATUS_VERSION, ...axes });
13010
+ }
13011
+ function sha256Reference(kind, id, digest) {
13012
+ const reference = { kind, id };
13013
+ if (digest !== void 0 && /^[a-f0-9]{64}$/u.test(digest)) {
13014
+ reference.digest = { algorithm: "sha256", value: digest };
13015
+ }
13016
+ return reference;
13017
+ }
13018
+ function receiptReference(receipt) {
13019
+ return sha256Reference("run_receipt", receipt.runId, receipt.integrity?.digest);
13020
+ }
13021
+ function attributed(state, source, authority, artifacts) {
13022
+ return { state, source, authority, artifacts: [...artifacts].sort(compareArtifactReferences) };
13023
+ }
13024
+ function receiptSource(receipt) {
13025
+ return { kind: "run_receipt", id: receipt.runId };
13026
+ }
13027
+ function compatibilitySource(receipt, field) {
13028
+ return { kind: "compatibility", id: `run_receipt:${receipt.runId}:${field}` };
13029
+ }
13030
+ var DISPATCH_AUTHORITY = { kind: "clio", id: "dispatch" };
13031
+ var COMPATIBILITY_AUTHORITY = { kind: "unknown", id: "historical-persisted-format" };
13032
+ function adaptReceiptIntegrityStatus(receipt, verification) {
13033
+ if (receipt === null || receipt === void 0) return absentTrustStatus("artifact_missing");
13034
+ const artifacts = [receiptReference(receipt)];
13035
+ if (verification === void 0 || verification.ok && receipt.integrity === void 0) {
13036
+ return attributed(
13037
+ "unknown",
13038
+ {
13039
+ kind: "compatibility",
13040
+ id: `run_receipt:${receipt.runId}:${receipt.integrity === void 0 ? "integrity-missing" : "integrity-unchecked"}`
13041
+ },
13042
+ COMPATIBILITY_AUTHORITY,
13043
+ artifacts
13750
13044
  );
13751
13045
  }
13752
- return { entries, missing: false, errors };
13046
+ return attributed(
13047
+ verification.ok ? "verified" : "failed",
13048
+ { kind: "receipt_integrity_verification", id: receipt.runId },
13049
+ { kind: "clio", id: "receipt-integrity" },
13050
+ artifacts
13051
+ );
13753
13052
  }
13754
- async function listSessionLedgerRefs(stateDir, onlyCwdHash) {
13755
- const root = join17(stateDir, "sessions");
13756
- let cwdHashes;
13757
- try {
13758
- cwdHashes = await readdir(root);
13759
- } catch {
13760
- return [];
13053
+ function validationArtifacts(receipt) {
13054
+ const artifacts = [receiptReference(receipt)];
13055
+ for (const fact of receipt.quality?.typedValidations ?? []) {
13056
+ artifacts.push(sha256Reference("validation_result", fact.sourceId, fact.validatorDigest));
13761
13057
  }
13762
- const refs = [];
13763
- for (const cwdHash2 of cwdHashes.sort(compareStrings2)) {
13764
- if (onlyCwdHash !== void 0 && cwdHash2 !== onlyCwdHash) continue;
13765
- let sessionIds;
13766
- try {
13767
- sessionIds = await readdir(join17(root, cwdHash2));
13768
- } catch {
13769
- continue;
13770
- }
13771
- for (const sessionId of sessionIds.sort(compareStrings2)) {
13772
- refs.push({ cwdHash: cwdHash2, sessionId, path: join17(root, cwdHash2, sessionId, "current.jsonl") });
13773
- }
13058
+ const resultContract = receipt.quality?.resultContract;
13059
+ if (resultContract !== null && resultContract !== void 0) {
13060
+ artifacts.push(sha256Reference("validation_result", resultContract.sourceId, resultContract.validatorDigest));
13774
13061
  }
13775
- return refs;
13062
+ return uniqueBoundedReferences(artifacts);
13776
13063
  }
13777
- function readOptionalString(value) {
13778
- return typeof value === "string" && value.length > 0 ? value : null;
13064
+ function qualityHasFailure(quality) {
13065
+ if (quality === void 0) return false;
13066
+ if (quality.typedValidations.some((fact) => !fact.passed)) return true;
13067
+ return quality.resultContract?.conformance === "fail" || quality.resultContract?.quality === "fail";
13779
13068
  }
13780
- function isRecord9(value) {
13781
- return typeof value === "object" && value !== null && !Array.isArray(value);
13782
- }
13783
- function compareStrings2(a, b) {
13784
- return a.localeCompare(b);
13069
+ function qualityHasValidation(quality) {
13070
+ if (quality === void 0) return false;
13071
+ if (quality.typedValidations.some((fact) => fact.passed)) return true;
13072
+ return quality.resultContract?.quality === "pass";
13785
13073
  }
13786
-
13787
- // src/domains/session/protected-artifacts.ts
13788
- init_esm_shims();
13789
- function protectedArtifactEntryFromArtifact(artifact, context) {
13790
- const entry = {
13791
- kind: "protectedArtifact",
13792
- parentTurnId: context.parentTurnId,
13793
- action: "protect",
13794
- artifact: artifactSnapshot(artifact)
13795
- };
13796
- if (context.toolName !== void 0) entry.toolName = context.toolName;
13797
- if (context.toolCallId !== void 0) entry.toolCallId = context.toolCallId;
13798
- if (context.runId !== void 0) entry.runId = context.runId;
13799
- if (context.correlationId !== void 0) entry.correlationId = context.correlationId;
13800
- return entry;
13801
- }
13802
- function protectedArtifactFromSessionEntry(entry) {
13803
- return protectedArtifactFromSnapshot(entry.artifact);
13804
- }
13805
- function protectedArtifactStateFromSessionEntries(entries) {
13806
- let state = { artifacts: [] };
13807
- const protectedEntries = entries.map((entry, index) => ({ entry, index })).filter((item) => item.entry.kind === "protectedArtifact").sort(compareProtectedEntryPositions);
13808
- for (const item of protectedEntries) {
13809
- if (item.entry.action !== "protect") continue;
13810
- state = protectArtifact(state, protectedArtifactFromSessionEntry(item.entry));
13811
- }
13812
- return state;
13813
- }
13814
- function artifactSnapshot(artifact) {
13815
- const snapshot = {
13816
- path: artifact.path,
13817
- protectedAt: artifact.protectedAt,
13818
- reason: artifact.reason,
13819
- source: artifact.source
13820
- };
13821
- if (artifact.validationCommand !== void 0) snapshot.validationCommand = artifact.validationCommand;
13822
- if (artifact.validationExitCode !== void 0) snapshot.validationExitCode = artifact.validationExitCode;
13823
- return snapshot;
13824
- }
13825
- function protectedArtifactFromSnapshot(snapshot) {
13826
- const artifact = {
13827
- path: snapshot.path,
13828
- protectedAt: snapshot.protectedAt,
13829
- reason: snapshot.reason,
13830
- source: snapshot.source
13831
- };
13832
- if (snapshot.validationCommand !== void 0) artifact.validationCommand = snapshot.validationCommand;
13833
- if (snapshot.validationExitCode !== void 0) artifact.validationExitCode = snapshot.validationExitCode;
13834
- return artifact;
13835
- }
13836
- function compareProtectedEntryPositions(left, right) {
13837
- return compareStrings3(left.entry.timestamp, right.entry.timestamp) || compareStrings3(left.entry.turnId, right.entry.turnId) || left.index - right.index;
13838
- }
13839
- function compareStrings3(left, right) {
13840
- if (left < right) return -1;
13841
- if (left > right) return 1;
13842
- return 0;
13843
- }
13844
-
13845
- // src/domains/session/usage.ts
13846
- init_esm_shims();
13847
- function numberAt(source, key) {
13848
- const value = source[key];
13849
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
13850
- }
13851
- function reasoningTokensOf(usage) {
13852
- const direct = numberAt(usage, "reasoningTokens");
13853
- if (direct > 0) return direct;
13854
- const details = usage.outputTokensDetails ?? usage.completionTokensDetails;
13855
- if (details && typeof details === "object") return numberAt(details, "reasoningTokens");
13856
- return 0;
13857
- }
13858
- function stringAt(source, ...keys) {
13859
- for (const key of keys) {
13860
- const value = source[key];
13861
- if (typeof value === "string" && value.trim().length > 0) return value;
13074
+ function verificationStatus(verification, receipt, artifacts) {
13075
+ if (verification.state === "verified") {
13076
+ return attributed("validated", receiptSource(receipt), { kind: "validator", id: verification.basis }, artifacts);
13862
13077
  }
13863
- return null;
13864
- }
13865
- function ledgerUsageCalls(entries, defaults = {}) {
13866
- const calls = [];
13867
- let currentTarget = defaults.target ?? null;
13868
- let currentModel = defaults.model ?? null;
13869
- for (const entry of entries) {
13870
- if (entry?.kind === "compactionSummary") {
13871
- const usage2 = entry.usage;
13872
- if (!usage2 || usage2.totalTokens <= 0) continue;
13873
- calls.push({
13874
- providerId: currentTarget ?? "unknown",
13875
- modelId: currentModel ?? "unknown",
13876
- input: usage2.input,
13877
- output: usage2.output,
13878
- cacheRead: usage2.cacheRead,
13879
- cacheWrite: usage2.cacheWrite,
13880
- reasoningTokens: usage2.reasoning,
13881
- totalTokens: usage2.totalTokens,
13882
- costUsd: usage2.cost.total,
13883
- // A split turn runs two summarization streams under one entry; the
13884
- // provider served that many calls even though one row records them.
13885
- apiCalls: Math.max(1, Math.round(usage2.apiCalls))
13886
- });
13887
- continue;
13888
- }
13889
- if (entry?.kind === "modelChange") {
13890
- const change = entry;
13891
- if (typeof change.target === "string" && change.target.length > 0) currentTarget = change.target;
13892
- else if (typeof change.provider === "string" && change.provider.length > 0) currentTarget = change.provider;
13893
- if (typeof change.modelId === "string" && change.modelId.length > 0) currentModel = change.modelId;
13894
- continue;
13895
- }
13896
- if (entry?.kind !== "message" || entry.role !== "assistant") continue;
13897
- const payload = entry.payload;
13898
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) continue;
13899
- const record = payload;
13900
- const stopReason = record.stopReason;
13901
- if (stopReason === "aborted" || stopReason === "error") continue;
13902
- const rawUsage = record.usage;
13903
- if (!rawUsage || typeof rawUsage !== "object" || Array.isArray(rawUsage)) continue;
13904
- const usage = rawUsage;
13905
- const input = numberAt(usage, "input");
13906
- const output = numberAt(usage, "output");
13907
- const cacheRead = numberAt(usage, "cacheRead");
13908
- const cacheWrite = numberAt(usage, "cacheWrite");
13909
- const totalTokens = numberAt(usage, "totalTokens") || input + output + cacheRead + cacheWrite;
13910
- if (totalTokens === 0) continue;
13911
- const cost = usage.cost;
13912
- const costUsd = cost && typeof cost === "object" ? numberAt(cost, "total") : 0;
13913
- calls.push({
13914
- providerId: currentTarget ?? stringAt(record, "provider", "api") ?? "unknown",
13915
- modelId: currentModel ?? stringAt(record, "responseModel", "model") ?? "unknown",
13916
- input,
13917
- output,
13918
- cacheRead,
13919
- cacheWrite,
13920
- reasoningTokens: reasoningTokensOf(usage),
13921
- totalTokens,
13922
- costUsd
13923
- });
13078
+ if (verification.state === "unverified") return absentTrustStatus("not_observed");
13079
+ if (verification.state === "not_applicable") {
13080
+ return attributed("not_applicable", receiptSource(receipt), DISPATCH_AUTHORITY, artifacts);
13924
13081
  }
13925
- return calls;
13082
+ return attributed(
13083
+ "unknown",
13084
+ receiptSource(receipt),
13085
+ verification.basis === "acp-external-unobserved" ? { kind: "external_system", id: "acp-delegation" } : COMPATIBILITY_AUTHORITY,
13086
+ artifacts
13087
+ );
13926
13088
  }
13927
-
13928
- // src/domains/session/index.ts
13929
- var SessionDomainModule = {
13930
- manifest: SessionManifest,
13931
- createExtension: createSessionBundle
13932
- };
13933
-
13934
- // src/domains/evidence/failure-attribution.ts
13935
- init_esm_shims();
13936
- function attributeEvidenceFailure(facts) {
13937
- if (facts.outcomeCode === "worker_tool_call_cap_exhausted" || facts.outcomeCode === "loop_guard_tools_disabled_exhausted") {
13938
- return "tool-loop";
13939
- }
13940
- if (facts.outcome === "timed_out" || facts.outcome === "stalled") return "timeout";
13941
- const diagnostic = [facts.outcomeDetail, facts.failureMessage].filter((value) => value !== null).join("\n").toLowerCase();
13942
- if (diagnostic.length === 0) return "unknown";
13943
- if (/\b(?:401|403)\b|unauthorized|forbidden|invalid api key|authentication/.test(diagnostic)) {
13944
- return "auth-failure";
13945
- }
13946
- if (/\b429\b|rate[ -]?limit|too many requests|temporar(?:y|ily)|unavailable|\b50[234]\b/.test(diagnostic)) {
13947
- return "provider-transient";
13948
- }
13949
- if (/context (?:length|window)|context[_ -]?overflow|maximum context|too many tokens/.test(diagnostic)) {
13950
- return "context-overflow";
13089
+ function adaptRunReceiptValidationStatus(receipt) {
13090
+ if (receipt === null || receipt === void 0) return absentTrustStatus("artifact_missing");
13091
+ const artifacts = validationArtifacts(receipt);
13092
+ if (qualityHasFailure(receipt.quality)) {
13093
+ return attributed("failed", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
13951
13094
  }
13952
- if (/module not found|cannot find module|missing (?:dependency|package)|dependency .* missing/.test(diagnostic)) {
13953
- return "missing-dependency";
13095
+ if ((receipt.validationGrounding?.ungrounded.length ?? 0) > 0 || receipt.validationGrounding !== void 0 && receipt.validationGrounding.claimed > receipt.validationGrounding.grounded) {
13096
+ return attributed("ungrounded", receiptSource(receipt), { kind: "validator", id: "command-grounding" }, artifacts);
13954
13097
  }
13955
- if (/wrong runtime|runtime mismatch|model mismatch|unsupported runtime/.test(diagnostic)) return "wrong-runtime";
13956
- if (/\b(?:test|tests|pytest|ctest)\b.*(?:fail|error)|(?:fail|error).*\b(?:test|tests|pytest|ctest)\b/.test(diagnostic)) {
13957
- return "test-failure";
13098
+ if (qualityHasValidation(receipt.quality)) {
13099
+ return attributed("validated", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
13958
13100
  }
13959
- if (/\bbuild\b.*(?:fail|error)|(?:fail|error).*\bbuild\b/.test(diagnostic)) return "build-failure";
13960
- return "unknown";
13961
- }
13962
-
13963
- // src/domains/evidence/provenance.ts
13964
- init_esm_shims();
13965
- var PERSONA_HASH_PREFIX_CHARS = 12;
13966
- function extractRunProvenance(receipt) {
13967
- const view = {};
13968
- if (receipt.pipeline !== void 0) view.pipeline = receipt.pipeline;
13969
- if (receipt.personaOverride !== void 0) view.personaOverride = receipt.personaOverride;
13970
- const escalation = escalationCountsFrom(receipt.safety);
13971
- if (escalation !== null) view.escalation = escalation;
13972
- if (receipt.autonomyEnforcement !== void 0) view.autonomyEnforcement = receipt.autonomyEnforcement;
13973
- return view;
13101
+ if (receipt.verification !== void 0) return verificationStatus(receipt.verification, receipt, artifacts);
13102
+ return attributed("unknown", compatibilitySource(receipt, "verification"), COMPATIBILITY_AUTHORITY, artifacts);
13974
13103
  }
13975
- function hasRunProvenance(view) {
13976
- return view.pipeline !== void 0 || view.personaOverride !== void 0 || view.escalation !== void 0 || view.autonomyEnforcement !== void 0;
13104
+ function validBriefing(briefing) {
13105
+ return Number.isSafeInteger(briefing.bytes) && briefing.bytes >= 0 && /^[a-f0-9]{64}$/u.test(briefing.contentHash);
13977
13106
  }
13978
- function runProvenanceFromUnknown(value) {
13979
- if (!isRecord10(value)) return {};
13980
- const view = {};
13981
- const pipeline = pipelineFromUnknown(value.pipeline);
13982
- if (pipeline !== null) view.pipeline = pipeline;
13983
- const personaOverride = personaOverrideFromUnknown(value.personaOverride);
13984
- if (personaOverride !== null) view.personaOverride = personaOverride;
13985
- const escalation = escalationFromUnknown(value.safety);
13986
- if (escalation !== null) view.escalation = escalation;
13987
- const autonomyEnforcement = autonomyEnforcementFromUnknown(value.autonomyEnforcement);
13988
- if (autonomyEnforcement !== null) view.autonomyEnforcement = autonomyEnforcement;
13989
- return view;
13107
+ function validBoundedProjectContext(context) {
13108
+ return context.tier === "bounded" && Number.isSafeInteger(context.chars) && (context.chars ?? -1) >= 0 && typeof context.contentHash === "string" && /^[a-f0-9]{64}$/u.test(context.contentHash);
13990
13109
  }
13991
- function isRecord10(value) {
13992
- return typeof value === "object" && value !== null && !Array.isArray(value);
13110
+ function contextArtifacts(receipt) {
13111
+ const artifacts = [receiptReference(receipt)];
13112
+ if (receipt.briefing !== void 0 && validBriefing(receipt.briefing)) {
13113
+ artifacts.push(sha256Reference("briefing", `${receipt.runId}:briefing`, receipt.briefing.contentHash));
13114
+ }
13115
+ if (receipt.projectContext?.tier === "bounded" && validBoundedProjectContext(receipt.projectContext)) {
13116
+ artifacts.push(
13117
+ sha256Reference("project_context", `${receipt.runId}:project-context`, receipt.projectContext.contentHash)
13118
+ );
13119
+ }
13120
+ return uniqueBoundedReferences(artifacts);
13993
13121
  }
13994
- function finiteNumber(value) {
13995
- return typeof value === "number" && Number.isFinite(value) ? value : null;
13122
+ function adaptRunReceiptContextStatus(receipt) {
13123
+ if (receipt === null || receipt === void 0) return absentTrustStatus("artifact_missing");
13124
+ const artifacts = contextArtifacts(receipt);
13125
+ const source = receiptSource(receipt);
13126
+ const briefingInvalid = receipt.briefing !== void 0 && !validBriefing(receipt.briefing);
13127
+ if (briefingInvalid) return attributed("invalid", source, DISPATCH_AUTHORITY, artifacts);
13128
+ const context = receipt.projectContext;
13129
+ if (context === void 0) {
13130
+ if (receipt.briefing !== void 0) return attributed("recorded", source, DISPATCH_AUTHORITY, artifacts);
13131
+ return attributed("unknown", compatibilitySource(receipt, "projectContext"), COMPATIBILITY_AUTHORITY, artifacts);
13132
+ }
13133
+ if (context.tier === "none") {
13134
+ if (context.chars !== void 0 || context.contentHash !== void 0 || context.sections !== void 0) {
13135
+ return attributed("invalid", source, DISPATCH_AUTHORITY, artifacts);
13136
+ }
13137
+ return receipt.briefing === void 0 ? attributed("not_applicable", source, DISPATCH_AUTHORITY, artifacts) : attributed("recorded", source, DISPATCH_AUTHORITY, artifacts);
13138
+ }
13139
+ return attributed(validBoundedProjectContext(context) ? "recorded" : "invalid", source, DISPATCH_AUTHORITY, artifacts);
13996
13140
  }
13997
- function pipelineFromUnknown(value) {
13998
- if (!isRecord10(value)) return null;
13999
- const position = finiteNumber(value.position);
14000
- const inputBytes = finiteNumber(value.inputBytes);
14001
- if (position === null || inputBytes === null) return null;
14002
- const fromRunId = typeof value.fromRunId === "string" ? value.fromRunId : null;
14003
- return { fromRunId, position, inputBytes, inputTruncated: value.inputTruncated === true };
13141
+ function adaptRunReceiptAutonomyStatus(receipt) {
13142
+ if (receipt === null || receipt === void 0) return absentTrustStatus("artifact_missing");
13143
+ const enforcement = receipt.autonomyEnforcement;
13144
+ const artifacts = [receiptReference(receipt)];
13145
+ if (enforcement === void 0) {
13146
+ return attributed("unknown", compatibilitySource(receipt, "autonomyEnforcement"), COMPATIBILITY_AUTHORITY, artifacts);
13147
+ }
13148
+ artifacts.push({ kind: "autonomy_policy", id: `${receipt.runId}:${enforcement.autonomy}` });
13149
+ const authority = enforcement.grade === "mediated" ? { kind: "clio", id: "safety-autonomy" } : { kind: "runtime", id: enforcement.externalMode ?? "external-runtime" };
13150
+ const state = enforcement.dangerousBypass === true || enforcement.grade === "bypassed" ? "bypassed" : enforcement.grade === "approximated" ? "approximated" : "enforced";
13151
+ return attributed(state, receiptSource(receipt), authority, artifacts);
14004
13152
  }
14005
- function personaOverrideFromUnknown(value) {
14006
- if (!isRecord10(value) || typeof value.promptHash !== "string" || value.promptHash.length === 0) return null;
14007
- return { promptHash: value.promptHash };
13153
+ function receiptClaimsAreAuthenticated(receipt, integrity) {
13154
+ return receipt?.integrity !== void 0 && integrity?.ok === true;
14008
13155
  }
14009
- function autonomyEnforcementFromUnknown(value) {
14010
- if (!isRecord10(value)) return null;
14011
- if (value.grade !== "mediated" && value.grade !== "approximated" && value.grade !== "bypassed") return null;
14012
- if (typeof value.autonomy !== "string" || value.autonomy.length === 0) return null;
14013
- const view = { grade: value.grade, autonomy: value.autonomy };
14014
- if (typeof value.externalMode === "string" && value.externalMode.length > 0) view.externalMode = value.externalMode;
14015
- if (typeof value.dangerousBypass === "boolean") view.dangerousBypass = value.dangerousBypass;
14016
- return view;
13156
+ function unauthenticatedReceiptProjection(receipt) {
13157
+ if (receipt === null || receipt === void 0) {
13158
+ return {
13159
+ validationGrounding: absentTrustStatus("artifact_missing"),
13160
+ contextProvenance: absentTrustStatus("artifact_missing"),
13161
+ autonomyEnforcement: absentTrustStatus("artifact_missing")
13162
+ };
13163
+ }
13164
+ if (receipt.integrity === void 0) {
13165
+ const artifacts = [receiptReference(receipt)];
13166
+ return {
13167
+ validationGrounding: attributed(
13168
+ "unknown",
13169
+ compatibilitySource(receipt, "canonical-projection"),
13170
+ COMPATIBILITY_AUTHORITY,
13171
+ artifacts
13172
+ ),
13173
+ contextProvenance: attributed(
13174
+ "unknown",
13175
+ compatibilitySource(receipt, "canonical-projection"),
13176
+ COMPATIBILITY_AUTHORITY,
13177
+ artifacts
13178
+ ),
13179
+ autonomyEnforcement: attributed(
13180
+ "unknown",
13181
+ compatibilitySource(receipt, "canonical-projection"),
13182
+ COMPATIBILITY_AUTHORITY,
13183
+ artifacts
13184
+ )
13185
+ };
13186
+ }
13187
+ return {
13188
+ validationGrounding: absentTrustStatus("not_observed"),
13189
+ contextProvenance: absentTrustStatus("not_observed"),
13190
+ autonomyEnforcement: absentTrustStatus("not_observed")
13191
+ };
13192
+ }
13193
+ function adaptRunReceiptTrustStatus(receipt, options = {}) {
13194
+ const authenticated2 = receiptClaimsAreAuthenticated(receipt, options.integrity);
13195
+ const receiptProjection = authenticated2 ? {
13196
+ validationGrounding: adaptRunReceiptValidationStatus(receipt),
13197
+ contextProvenance: adaptRunReceiptContextStatus(receipt),
13198
+ autonomyEnforcement: adaptRunReceiptAutonomyStatus(receipt)
13199
+ } : unauthenticatedReceiptProjection(receipt);
13200
+ return composeTrustStatus({
13201
+ artifactIntegrity: adaptReceiptIntegrityStatus(receipt, options.integrity),
13202
+ ...receiptProjection,
13203
+ independentReview: absentTrustStatus(receipt === null || receipt === void 0 ? "artifact_missing" : "not_recorded"),
13204
+ completionEvidence: absentTrustStatus(
13205
+ receipt === null || receipt === void 0 ? "artifact_missing" : "not_recorded"
13206
+ )
13207
+ });
14017
13208
  }
14018
- function escalationFromUnknown(safety) {
14019
- if (!isRecord10(safety)) return null;
14020
- const decisions = safety.decisions;
14021
- if (!isRecord10(decisions)) return null;
14022
- const requested = finiteNumber(decisions.escalationRequested);
14023
- if (requested === null) return null;
13209
+ function inspectRunReceiptTrustStatus(receipt, envelope) {
13210
+ let integrity;
13211
+ if (receipt === null || receipt === void 0) {
13212
+ integrity = { ok: false, reason: "receipt unavailable" };
13213
+ } else if (envelope === null || envelope === void 0) {
13214
+ integrity = { ok: false, reason: "run ledger envelope unavailable" };
13215
+ } else {
13216
+ try {
13217
+ integrity = verifyReceiptIntegrity(receipt, envelope);
13218
+ } catch (error) {
13219
+ integrity = {
13220
+ ok: false,
13221
+ reason: `receipt invalid: ${error instanceof Error ? error.message : String(error)}`
13222
+ };
13223
+ }
13224
+ }
14024
13225
  return {
14025
- requested,
14026
- approved: finiteNumber(decisions.escalationApproved) ?? 0,
14027
- denied: finiteNumber(decisions.escalationDenied) ?? 0,
14028
- timedOut: finiteNumber(decisions.escalationTimedOut) ?? 0
14029
- };
13226
+ integrity,
13227
+ status: adaptRunReceiptTrustStatus(receipt, { integrity })
13228
+ };
13229
+ }
13230
+ function gateReference(artifact) {
13231
+ return sha256Reference("gate_decision", artifact.id, artifact.integrity.digest);
13232
+ }
13233
+ function gateAuthority(artifact) {
13234
+ if (artifact.outcome === "operator-confirmed") return { kind: "operator", id: "gate-confirmation" };
13235
+ if (artifact.outcome === "full-auto-applied") return { kind: "clio", id: "full-auto-gate-policy" };
13236
+ return { kind: "reviewer", id: artifact.decider?.runId ?? "unavailable-decider" };
13237
+ }
13238
+ function adaptGateDecisionReviewStatus(artifact, subjectRunId, verification) {
13239
+ if (artifact === null || artifact === void 0) return absentTrustStatus("artifact_missing");
13240
+ const source = { kind: "gate_decision", id: artifact.id };
13241
+ const artifacts = [gateReference(artifact)];
13242
+ const authority = gateAuthority(artifact);
13243
+ if (!artifact.subjects.some((subject) => subject.runId === subjectRunId)) return absentTrustStatus("not_recorded");
13244
+ if (verification === void 0 || !verification.ok) {
13245
+ return attributed(
13246
+ "unknown",
13247
+ source,
13248
+ verification === void 0 ? COMPATIBILITY_AUTHORITY : { kind: "unknown", id: "unauthenticated-gate-artifact" },
13249
+ artifacts
13250
+ );
13251
+ }
13252
+ if (artifact.decider === void 0 || artifact.correlation === void 0) {
13253
+ if (artifact.outcome === "operator-confirmed" || artifact.outcome === "full-auto-applied") {
13254
+ return attributed("not_applicable", source, authority, artifacts);
13255
+ }
13256
+ return attributed("inconclusive", source, authority, artifacts);
13257
+ }
13258
+ if (!artifact.correlation.independent) return attributed("not_independent", source, authority, artifacts);
13259
+ if (artifact.outcome === "pass") return attributed("passed", source, authority, artifacts);
13260
+ if (artifact.outcome === "fail") return attributed("failed", source, authority, artifacts);
13261
+ if (artifact.outcome === "winner") {
13262
+ return attributed(
13263
+ artifact.winner?.subject.runId === subjectRunId ? "passed" : "failed",
13264
+ source,
13265
+ authority,
13266
+ artifacts
13267
+ );
13268
+ }
13269
+ return attributed("inconclusive", source, authority, artifacts);
14030
13270
  }
14031
- function escalationCountsFrom(safety) {
14032
- const decisions = safety?.decisions;
14033
- if (decisions === void 0 || decisions.escalationRequested === void 0) return null;
13271
+ function adaptGroundedEvidenceValidationStatus(input) {
13272
+ const observed = (input.artifacts ?? []).filter((artifact) => !SELF_REPORTED_ARTIFACT_KINDS.has(artifact.kind));
13273
+ if (observed.length === 0) return absentTrustStatus("not_observed");
13274
+ return attributed(
13275
+ "validated",
13276
+ { kind: "evidence_bundle", id: `${input.evidenceId}:${input.runId}` },
13277
+ { kind: "clio", id: "evidence-grounding" },
13278
+ uniqueBoundedReferences([{ kind: "evidence_bundle", id: input.evidenceId }, ...observed])
13279
+ );
13280
+ }
13281
+ function adaptFinishContractCompletionStatus(assessment, options = {}) {
13282
+ const artifacts = uniqueBoundedReferences(
13283
+ options.artifacts ?? assessment.evidence.map((evidence, index) => ({
13284
+ kind: evidence.turnId === void 0 ? "finish_contract_evidence" : "session_entry",
13285
+ id: evidence.turnId ?? `${evidence.kind}:${index + 1}`
13286
+ }))
13287
+ );
13288
+ const source = { kind: "finish_contract", id: options.sourceId ?? assessment.reason };
13289
+ const authority = { kind: "clio", id: "finish-contract" };
13290
+ if (assessment.reason === "no_mutation") return attributed("not_applicable", source, authority, artifacts);
13291
+ if (assessment.reason === "validation_evidence") return attributed("evidenced", source, authority, artifacts);
13292
+ if (assessment.reason === "explicit_limitation") return attributed("limited", source, authority, artifacts);
13293
+ return attributed("incomplete", source, authority, artifacts);
13294
+ }
13295
+ function uniqueBoundedReferences(references) {
13296
+ const sorted = [...references].sort(compareArtifactReferences);
13297
+ const unique = sorted.filter(
13298
+ (reference, index) => index === 0 || compareArtifactReferences(sorted[index - 1], reference) !== 0
13299
+ );
13300
+ return unique.slice(0, TRUST_STATUS_MAX_ARTIFACT_REFERENCES);
13301
+ }
13302
+
13303
+ // src/domains/evidence/types.ts
13304
+ init_esm_shims();
13305
+ var EVIDENCE_VERSION = 1;
13306
+ var FAILURE_CAUSE_TAG_ORDER = [
13307
+ "timeout",
13308
+ "auth-failure",
13309
+ "missing-dependency",
13310
+ "build-failure",
13311
+ "test-failure",
13312
+ "blocked-tool"
13313
+ ];
13314
+ var FAILURE_CAUSE_TAGS = new Set(FAILURE_CAUSE_TAG_ORDER);
13315
+
13316
+ // src/domains/evidence/run-trust.ts
13317
+ function buildEvidenceTrustStatusFile(input) {
14034
13318
  return {
14035
- requested: decisions.escalationRequested,
14036
- approved: decisions.escalationApproved ?? 0,
14037
- denied: decisions.escalationDenied ?? 0,
14038
- timedOut: decisions.escalationTimedOut ?? 0
13319
+ version: EVIDENCE_VERSION,
13320
+ evidenceId: input.evidenceId,
13321
+ projection: "canonical",
13322
+ runs: input.runSources.map((source) => ({
13323
+ runId: source.envelope.id,
13324
+ status: composeEvidenceRunTrustStatus({
13325
+ evidenceId: input.evidenceId,
13326
+ source,
13327
+ gateDecisions: input.gateDecisions,
13328
+ auditRows: input.auditRows,
13329
+ validationEvidence: input.validationEvidence?.get(source.envelope.id) ?? []
13330
+ })
13331
+ }))
14039
13332
  };
14040
13333
  }
14041
- function formatPersonaHashPrefix(promptHash2) {
14042
- if (promptHash2.length <= PERSONA_HASH_PREFIX_CHARS) return promptHash2;
14043
- return `${promptHash2.slice(0, PERSONA_HASH_PREFIX_CHARS)}...`;
14044
- }
14045
- function provenanceTranscriptLines(view) {
14046
- const lines = [];
14047
- if (view.pipeline !== void 0) {
14048
- const { fromRunId, position, inputBytes, inputTruncated } = view.pipeline;
14049
- const source = fromRunId ?? "unknown";
14050
- const truncation = inputTruncated ? "input truncated" : "not truncated";
14051
- lines.push(`pipeline: step ${position}, input ${inputBytes} bytes from ${source} (${truncation})`);
14052
- }
14053
- if (view.personaOverride !== void 0) {
14054
- lines.push(`persona override: prompt hash ${formatPersonaHashPrefix(view.personaOverride.promptHash)}`);
13334
+ function composeEvidenceRunTrustStatus(input) {
13335
+ const inspection = inspectRunReceiptTrustStatus(input.source.receipt, input.source.envelope);
13336
+ const receiptRejected = inspection.status.artifactIntegrity.state === "failed";
13337
+ let status = inspection.status;
13338
+ const grounded = input.validationEvidence.filter((artifact) => isTrustStatusIdentifier(artifact.id));
13339
+ if (grounded.length > 0 && (status.validationGrounding.state === "absent" || status.validationGrounding.state === "unknown")) {
13340
+ status = composeTrustStatus(status, {
13341
+ validationGrounding: adaptGroundedEvidenceValidationStatus({
13342
+ evidenceId: input.evidenceId,
13343
+ runId: input.source.envelope.id,
13344
+ artifacts: grounded
13345
+ })
13346
+ });
14055
13347
  }
14056
- if (view.escalation !== void 0) {
14057
- const { requested, approved, denied, timedOut } = view.escalation;
14058
- lines.push(`escalations: ${requested} requested, ${approved} approved, ${denied} denied, ${timedOut} timed out`);
13348
+ const gate = latestGateDecisionForRun(input.gateDecisions, input.source.envelope.id);
13349
+ if (gate !== null) {
13350
+ const artifactVerification = verifyGateDecisionArtifact(gate);
13351
+ const subject = gate.subjects.find((entry) => entry.runId === input.source.envelope.id);
13352
+ const receipt = inspection.integrity.ok ? input.source.receipt : null;
13353
+ const verification = artifactVerification.ok && subject !== void 0 && receipt?.integrity !== void 0 && subject.digest === receipt.integrity.digest ? { ok: true } : {
13354
+ ok: false,
13355
+ reason: artifactVerification.ok ? "gate subject receipt digest unavailable or mismatched" : artifactVerification.reason
13356
+ };
13357
+ status = composeTrustStatus(status, {
13358
+ independentReview: adaptGateDecisionReviewStatus(gate, input.source.envelope.id, verification)
13359
+ });
14059
13360
  }
14060
- if (view.autonomyEnforcement !== void 0) {
14061
- const { grade, autonomy, externalMode, dangerousBypass } = view.autonomyEnforcement;
14062
- const mode = externalMode !== void 0 ? ` mode=${externalMode}` : "";
14063
- const bypass = dangerousBypass === true ? " dangerousBypass=true" : "";
14064
- lines.push(`autonomy enforcement: ${grade} autonomy=${autonomy}${mode}${bypass}`);
13361
+ const finish = latestFinishContractForRun(input.auditRows, input.source.envelope.id);
13362
+ if (finish !== null) {
13363
+ const completion = adaptFinishContractCompletionStatus(finish.assessment, {
13364
+ sourceId: finish.sourceId,
13365
+ artifacts: finish.artifacts
13366
+ });
13367
+ status = composeTrustStatus(status, {
13368
+ completionEvidence: receiptRejected && completion.state === "evidenced" ? {
13369
+ state: "unknown",
13370
+ source: { kind: "finish_contract", id: finish.sourceId },
13371
+ authority: { kind: "clio", id: "finish-contract" },
13372
+ artifacts: finish.artifacts
13373
+ } : completion
13374
+ });
14065
13375
  }
14066
- return lines;
14067
- }
14068
- function provenanceCompactSuffix(view) {
14069
- const parts = [];
14070
- if (view.pipeline !== void 0) {
14071
- const { fromRunId, position, inputBytes, inputTruncated } = view.pipeline;
14072
- const from = fromRunId ?? "unknown";
14073
- parts.push(`pipeline=step${position} from=${from} in=${inputBytes}b${inputTruncated ? " truncated" : ""}`);
13376
+ return status;
13377
+ }
13378
+ function latestGateDecisionForRun(decisions, runId) {
13379
+ return decisions.filter((decision) => decision.subjects.some((subject) => subject.runId === runId)).sort(
13380
+ (left, right) => compareCodepoints(left.createdAt, right.createdAt) || left.cycle - right.cycle || compareCodepoints(left.id, right.id)
13381
+ ).at(-1) ?? null;
13382
+ }
13383
+ function latestFinishContractForRun(rows, runId) {
13384
+ const candidates = rows.filter((row) => row.auditKind === "completion_contract" && row.runId === runId && row.confidence === "exact").flatMap((row) => {
13385
+ const assessment = finishContractAssessmentFromAudit(row.row);
13386
+ if (assessment === null) return [];
13387
+ const correlationId = readOptionalString(row.row.correlationId) ?? `${runId}:completion-contract`;
13388
+ if (!isTrustStatusIdentifier(correlationId)) return [];
13389
+ const turnId = readOptionalString(row.row.turnId);
13390
+ const artifacts = [
13391
+ { kind: "finish_contract_evidence", id: correlationId },
13392
+ ...turnId === null || !isTrustStatusIdentifier(turnId) ? [] : [{ kind: "session_entry", id: turnId }]
13393
+ ];
13394
+ return [{ sourceId: correlationId, assessment, artifacts, timestamp: row.ts ?? "" }];
13395
+ }).sort(
13396
+ (left, right) => compareCodepoints(left.timestamp, right.timestamp) || compareCodepoints(left.sourceId, right.sourceId)
13397
+ );
13398
+ const latest2 = candidates.at(-1);
13399
+ return latest2 === void 0 ? null : { sourceId: latest2.sourceId, assessment: latest2.assessment, artifacts: latest2.artifacts };
13400
+ }
13401
+ function finishContractAssessmentFromAudit(row) {
13402
+ const reason = readOptionalString(row.reason);
13403
+ const decision = readOptionalString(row.decision);
13404
+ const mutatedPaths = Array.isArray(row.mutatedPaths) ? row.mutatedPaths.filter((entry) => typeof entry === "string") : [];
13405
+ const turnId = readOptionalString(row.turnId);
13406
+ const evidenceKinds = Array.isArray(row.evidenceKinds) ? row.evidenceKinds.filter(isFinishContractEvidenceKind) : [];
13407
+ const evidence = evidenceKinds.map((kind) => ({
13408
+ kind,
13409
+ summary: "recorded by the finish contract",
13410
+ ...turnId === null ? {} : { turnId }
13411
+ }));
13412
+ if (decision === "ok" && reason === "no_mutation") {
13413
+ return { kind: "ok", reason, evidence: [], mutatedPaths };
14074
13414
  }
14075
- if (view.personaOverride !== void 0) {
14076
- parts.push(`persona=${formatPersonaHashPrefix(view.personaOverride.promptHash)}`);
13415
+ if (decision === "ok" && reason === "validation_evidence") {
13416
+ return { kind: "ok", reason, evidence, mutatedPaths };
14077
13417
  }
14078
- if (view.escalation !== void 0) {
14079
- const { requested, approved, denied, timedOut } = view.escalation;
14080
- parts.push(`escalations=${requested}req/${approved}appr/${denied}deny/${timedOut}timeout`);
13418
+ if (decision === "ok" && reason === "explicit_limitation") {
13419
+ return { kind: "ok", reason, evidence: [], mutatedPaths };
14081
13420
  }
14082
- if (view.autonomyEnforcement !== void 0) {
14083
- const { grade, autonomy, externalMode, dangerousBypass } = view.autonomyEnforcement;
14084
- const mode = externalMode !== void 0 ? `/${externalMode}` : "";
14085
- const bypass = dangerousBypass === true ? "/bypass" : "";
14086
- parts.push(`enforcement=${grade}:${autonomy}${mode}${bypass}`);
13421
+ if (decision === "engage" && reason === "unvalidated_mutation") {
13422
+ return { kind: "engage", reason, message: "finish contract engaged", evidence: [], mutatedPaths };
14087
13423
  }
14088
- return parts.length === 0 ? "" : ` ${parts.join(" ")}`;
13424
+ return null;
13425
+ }
13426
+ function isFinishContractEvidenceKind(value) {
13427
+ return value === "validation_command" || value === "protected_artifact" || value === "dispatch_receipt";
13428
+ }
13429
+ function readOptionalString(value) {
13430
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
14089
13431
  }
14090
13432
 
14091
13433
  // src/domains/evidence/store.ts
14092
13434
  init_esm_shims();
14093
- import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
14094
- import { join as join18 } from "node:path";
13435
+ import { readdir, readFile } from "node:fs/promises";
13436
+ import { join as join15 } from "node:path";
14095
13437
  var EVIDENCE_FILES = [
14096
13438
  "overview.json",
14097
13439
  "transcript.md",
@@ -14101,16 +13443,17 @@ var EVIDENCE_FILES = [
14101
13443
  "audit-linked.jsonl",
14102
13444
  "receipt.json",
14103
13445
  "gate-decisions.json",
13446
+ "trust-status.json",
14104
13447
  "protected-artifacts.json",
14105
13448
  "findings.json",
14106
13449
  "findings.md"
14107
13450
  ];
14108
13451
  function evidenceRoot(dataDir) {
14109
- return join18(dataDir, "evidence");
13452
+ return join15(dataDir, "evidence");
14110
13453
  }
14111
13454
  function evidenceDirectory(dataDir, evidenceId) {
14112
13455
  assertSafeId(evidenceId, "evidence");
14113
- return join18(evidenceRoot(dataDir), evidenceId);
13456
+ return join15(evidenceRoot(dataDir), evidenceId);
14114
13457
  }
14115
13458
  var EvidenceNotFoundError = class extends Error {
14116
13459
  constructor(evidenceId) {
@@ -14126,7 +13469,7 @@ function isMissingFile(error) {
14126
13469
  async function loadEvidenceOverview(dataDir, evidenceId) {
14127
13470
  let raw;
14128
13471
  try {
14129
- raw = await readFile2(join18(evidenceDirectory(dataDir, evidenceId), "overview.json"), "utf8");
13472
+ raw = await readFile(join15(evidenceDirectory(dataDir, evidenceId), "overview.json"), "utf8");
14130
13473
  } catch (error) {
14131
13474
  if (isMissingFile(error)) throw new EvidenceNotFoundError(evidenceId);
14132
13475
  throw error;
@@ -14138,19 +13481,52 @@ async function inspectEvidence(dataDir, evidenceId) {
14138
13481
  const overview = await loadEvidenceOverview(dataDir, evidenceId);
14139
13482
  let findingsRaw;
14140
13483
  try {
14141
- findingsRaw = await readFile2(join18(evidenceDirectory(dataDir, evidenceId), "findings.json"), "utf8");
13484
+ findingsRaw = await readFile(join15(evidenceDirectory(dataDir, evidenceId), "findings.json"), "utf8");
14142
13485
  } catch (error) {
14143
13486
  if (isMissingFile(error)) throw new Error(`evidence artifact ${evidenceId} is missing findings.json`);
14144
13487
  throw error;
14145
13488
  }
14146
13489
  const findingsParsed = parseJson(findingsRaw, `${evidenceId}/findings.json`);
14147
13490
  const findings = parseFindingsFile(findingsParsed, `${evidenceId}/findings.json`);
14148
- return { overview, findings };
13491
+ return { overview, findings, trustStatus: await loadEvidenceTrustStatus(dataDir, evidenceId) };
13492
+ }
13493
+ async function loadEvidenceTrustStatus(dataDir, evidenceId) {
13494
+ let raw;
13495
+ try {
13496
+ raw = await readFile(join15(evidenceDirectory(dataDir, evidenceId), "trust-status.json"), "utf8");
13497
+ } catch (error) {
13498
+ if (isMissingFile(error)) {
13499
+ return { version: 1, evidenceId, projection: "historical_format", runs: [] };
13500
+ }
13501
+ throw error;
13502
+ }
13503
+ const source = `${evidenceId}/trust-status.json`;
13504
+ const parsed = parseJson(raw, source);
13505
+ if (!isRecord11(parsed)) throw new Error(`${source}: expected object`);
13506
+ if (parsed.version !== 1) throw new Error(`${source}: expected version 1`);
13507
+ if (readString(parsed, source, "evidenceId") !== evidenceId) {
13508
+ throw new Error(`${source}.evidenceId: expected ${evidenceId}`);
13509
+ }
13510
+ if (parsed.projection !== "canonical") throw new Error(`${source}.projection: expected canonical`);
13511
+ if (!Array.isArray(parsed.runs)) throw new Error(`${source}.runs: expected array`);
13512
+ return {
13513
+ version: 1,
13514
+ evidenceId,
13515
+ projection: "canonical",
13516
+ runs: parsed.runs.map((entry, index) => {
13517
+ const entrySource = `${source}.runs[${index}]`;
13518
+ if (!isRecord11(entry)) throw new Error(`${entrySource}: expected object`);
13519
+ return {
13520
+ runId: readString(entry, entrySource, "runId"),
13521
+ status: normalizeTrustStatus(entry.status)
13522
+ };
13523
+ })
13524
+ };
14149
13525
  }
14150
13526
  async function loadEvidenceRunProvenance(dataDir, evidenceId) {
14151
13527
  let raw;
14152
13528
  try {
14153
- raw = await readFile2(join18(evidenceDirectory(dataDir, evidenceId), "receipt.json"), "utf8");
13529
+ raw = await readFile(join15(evidenceDirectory(dataDir, evidenceId), "receipt.json"), "utf8");
14154
13530
  } catch (error) {
14155
13531
  const err = error;
14156
13532
  if (err.code === "ENOENT") return [];
@@ -14169,14 +13545,14 @@ async function loadEvidenceRunProvenance(dataDir, evidenceId) {
14169
13545
  async function listEvidenceOverviews(dataDir) {
14170
13546
  let entries;
14171
13547
  try {
14172
- entries = await readdir2(evidenceRoot(dataDir));
13548
+ entries = await readdir(evidenceRoot(dataDir));
14173
13549
  } catch (error) {
14174
13550
  const err = error;
14175
13551
  if (err.code === "ENOENT") return [];
14176
13552
  throw error;
14177
13553
  }
14178
13554
  const overviews = [];
14179
- for (const entry of entries.sort(compareStrings4)) {
13555
+ for (const entry of entries.sort(compareCodepoints)) {
14180
13556
  try {
14181
13557
  overviews.push(await loadEvidenceOverview(dataDir, entry));
14182
13558
  } catch {
@@ -14313,26 +13689,10 @@ function parseJson(raw, source) {
14313
13689
  function isRecord11(value) {
14314
13690
  return typeof value === "object" && value !== null && !Array.isArray(value);
14315
13691
  }
14316
- function compareStrings4(a, b) {
14317
- return a.localeCompare(b);
14318
- }
14319
13692
  function findingsFile(evidenceId, findings) {
14320
13693
  return { version: 1, evidenceId, findings };
14321
13694
  }
14322
13695
 
14323
- // src/domains/evidence/types.ts
14324
- init_esm_shims();
14325
- var EVIDENCE_VERSION = 1;
14326
- var FAILURE_CAUSE_TAG_ORDER = [
14327
- "timeout",
14328
- "auth-failure",
14329
- "missing-dependency",
14330
- "build-failure",
14331
- "test-failure",
14332
- "blocked-tool"
14333
- ];
14334
- var FAILURE_CAUSE_TAGS = new Set(FAILURE_CAUSE_TAG_ORDER);
14335
-
14336
13696
  // src/domains/evidence/build.ts
14337
13697
  var MAX_TASK_CHARS = 500;
14338
13698
  var TRANSCRIPT_TEXT_MAX_CHARS = 500;
@@ -14376,7 +13736,15 @@ async function buildEvidence(options) {
14376
13736
  const auditLinks = await linkAuditRows(options.stateDir, source, runSources, sessionLinks);
14377
13737
  const toolEventRows = toolEvents(runSources, sessionLinks, auditLinks);
14378
13738
  const protectedArtifactsRaw = protectedArtifactsFile(sessionLinks);
14379
- const findings = buildFindings(runSources, sessionLinks, auditLinks, protectedArtifactsRaw);
13739
+ const validationEvidence = validationEvidenceByRun(sessionLinks.entries, runSources);
13740
+ const trustStatusRaw = buildEvidenceTrustStatusFile({
13741
+ evidenceId,
13742
+ runSources,
13743
+ gateDecisions: gateDecisions.decisions,
13744
+ auditRows: auditLinks.rows,
13745
+ validationEvidence
13746
+ });
13747
+ const findings = buildFindings(runSources, trustStatusRaw, sessionLinks, auditLinks, protectedArtifactsRaw);
14380
13748
  const tally = createRedactionTally();
14381
13749
  const redactedRunSources = runSources.map((item) => ({
14382
13750
  ...item,
@@ -14393,6 +13761,7 @@ async function buildEvidence(options) {
14393
13761
  readErrors: auditLinks.readErrors
14394
13762
  };
14395
13763
  const protectedArtifacts = redactSecretsDeep(protectedArtifactsRaw, tally);
13764
+ const trustStatus = redactSecretsDeep(trustStatusRaw, tally);
14396
13765
  const overview = buildOverview(
14397
13766
  evidenceId,
14398
13767
  source,
@@ -14414,16 +13783,17 @@ async function buildEvidence(options) {
14414
13783
  redactedAuditLinks,
14415
13784
  redactedToolEvents,
14416
13785
  gateDecisions,
13786
+ trustStatus,
14417
13787
  protectedArtifacts,
14418
13788
  transcript
14419
13789
  );
14420
- return { evidenceId, directory, overview: finalOverview, findings };
13790
+ return { evidenceId, directory, overview: finalOverview, findings, trustStatus };
14421
13791
  }
14422
13792
  function buildOverview(evidenceId, source, runSources, findings, sessionLinks, auditLinks, toolEventRows, protectedArtifacts) {
14423
13793
  const envelopes = runSources.map((item) => item.envelope);
14424
13794
  const receipts = runSources.flatMap((item) => item.receipt === null ? [] : [item.receipt]);
14425
13795
  const toolStats = receipts.flatMap((receipt) => receipt.toolStats);
14426
- const runIds = envelopes.map((envelope) => envelope.id).sort(compareStrings5);
13796
+ const runIds = envelopes.map((envelope) => envelope.id).sort(compareCodepoints);
14427
13797
  const sessionIds = uniqueStrings(
14428
13798
  envelopes.flatMap((envelope) => envelope.sessionId === null ? [] : [envelope.sessionId])
14429
13799
  );
@@ -14468,15 +13838,17 @@ function buildOverview(evidenceId, source, runSources, findings, sessionLinks, a
14468
13838
  files: [...EVIDENCE_FILES]
14469
13839
  };
14470
13840
  }
14471
- function buildFindings(runSources, sessionLinks, auditLinks, protectedArtifacts) {
13841
+ function buildFindings(runSources, trustStatus, sessionLinks, auditLinks, protectedArtifacts) {
14472
13842
  const findings = [];
14473
- const validationRunIds = validationEvidenceRunIds(sessionLinks.entries, runSources, auditLinks.rows);
13843
+ const trustByRun = new Map(trustStatus.runs.map((entry) => [entry.runId, entry.status]));
14474
13844
  for (const source of runSources) {
13845
+ const status = trustByRun.get(source.envelope.id);
13846
+ if (status === void 0) throw new Error(`canonical trust status missing for run ${source.envelope.id}`);
14475
13847
  if (source.receiptError !== null) {
14476
13848
  const tag = source.receiptIntegrityFailed ? "receipt-integrity" : "unknown";
14477
13849
  findings.push(finding(findings.length, "warn", tag, source.envelope.id, source.receiptError));
14478
13850
  }
14479
- if (isSuccessfulRun(source) && !validationRunIds.has(source.envelope.id)) {
13851
+ if (isSuccessfulRun(source) && (status.validationGrounding.state === "absent" || status.validationGrounding.state === "unknown")) {
14480
13852
  findings.push(
14481
13853
  finding(
14482
13854
  findings.length,
@@ -14487,10 +13859,21 @@ function buildFindings(runSources, sessionLinks, auditLinks, protectedArtifacts)
14487
13859
  )
14488
13860
  );
14489
13861
  }
13862
+ if (status.validationGrounding.state === "ungrounded") {
13863
+ findings.push(
13864
+ finding(
13865
+ findings.length,
13866
+ "warn",
13867
+ "proxy-validation",
13868
+ source.envelope.id,
13869
+ "run claimed validation that was not grounded in an observed execution"
13870
+ )
13871
+ );
13872
+ }
14490
13873
  if (source.envelope.cwd.trim().length === 0) {
14491
13874
  findings.push(finding(findings.length, "warn", "cwd-missing", source.envelope.id, "run ledger cwd is empty"));
14492
13875
  }
14493
- const receipt = source.receipt;
13876
+ const receipt = authenticatedReceipt(source);
14494
13877
  const blocked = receipt?.toolStats.reduce((total, stat) => total + stat.blocked, 0) ?? 0;
14495
13878
  if (blocked > 0) {
14496
13879
  findings.push(
@@ -14509,12 +13892,11 @@ function buildFindings(runSources, sessionLinks, auditLinks, protectedArtifacts)
14509
13892
  )
14510
13893
  );
14511
13894
  }
14512
- const autonomyEnforcement = receipt?.autonomyEnforcement;
14513
- if (autonomyEnforcement?.dangerousBypass === true) {
14514
- const message = autonomyEnforcement.externalMode === "agent-managed" ? "run used external agent-managed governance; Clio safety blocks were not enforced" : "run executed with external permission bypass (CLIO_CODER_ALLOW_EXTERNAL_FULL_ACCESS=1); Clio safety blocks were not enforced";
13895
+ if (status.autonomyEnforcement.state === "bypassed") {
13896
+ const message = status.autonomyEnforcement.authority.id === "agent-managed" ? "run used external agent-managed governance; Clio safety blocks were not enforced" : "run executed with external permission bypass (CLIO_CODER_ALLOW_EXTERNAL_FULL_ACCESS=1); Clio safety blocks were not enforced";
14515
13897
  findings.push(finding(findings.length, "warn", "external-bypass", source.envelope.id, message));
14516
- } else if (autonomyEnforcement?.grade === "approximated") {
14517
- const mode = autonomyEnforcement.externalMode ? ` via ${autonomyEnforcement.externalMode}` : "";
13898
+ } else if (status.autonomyEnforcement.state === "approximated") {
13899
+ const mode = status.autonomyEnforcement.authority.id === "external-runtime" ? "" : ` via ${status.autonomyEnforcement.authority.id}`;
14518
13900
  findings.push(
14519
13901
  finding(
14520
13902
  findings.length,
@@ -14601,19 +13983,22 @@ function buildFindings(runSources, sessionLinks, auditLinks, protectedArtifacts)
14601
13983
  }
14602
13984
  return findings;
14603
13985
  }
14604
- function validationEvidenceRunIds(entries, runSources, auditRows) {
14605
- const runIds = /* @__PURE__ */ new Set();
14606
- const sourceRunIds = new Set(runSources.map((source) => source.envelope.id));
13986
+ function validationEvidenceByRun(entries, runSources) {
13987
+ const evidence = /* @__PURE__ */ new Map();
14607
13988
  const calls = /* @__PURE__ */ new Map();
14608
13989
  for (const linked of entries) {
14609
13990
  const runId = validationRunIdFor(linked, runSources);
14610
13991
  const entry = linked.entry;
14611
13992
  if (entry.kind === "bashExecution") {
14612
- if (runId !== null && isSuccessfulValidationBashExecution(entry)) runIds.add(runId);
13993
+ if (runId !== null && isSuccessfulValidationBashExecution(entry)) {
13994
+ addValidationEvidence(evidence, runId, { kind: "session_entry", id: entry.turnId });
13995
+ }
14613
13996
  continue;
14614
13997
  }
14615
13998
  if (entry.kind === "protectedArtifact") {
14616
- if (runId !== null && isValidationProtectedArtifact(entry)) runIds.add(runId);
13999
+ if (runId !== null && isValidationProtectedArtifact(entry)) {
14000
+ addValidationEvidence(evidence, runId, { kind: "session_entry", id: entry.turnId });
14001
+ }
14617
14002
  continue;
14618
14003
  }
14619
14004
  if (entry.kind !== "message") continue;
@@ -14626,16 +14011,16 @@ function validationEvidenceRunIds(entries, runSources, auditRows) {
14626
14011
  const result = extractSessionToolResult(entry, linked);
14627
14012
  if (result.id === null || !isSuccessfulSessionToolResult(result)) continue;
14628
14013
  const candidate = calls.get(result.id);
14629
- if (candidate?.runId !== null && candidate?.runId !== void 0) runIds.add(candidate.runId);
14630
- }
14631
- for (const linked of auditRows) {
14632
- if (linked.auditKind !== "completion_contract") continue;
14633
- if (linked.runId === null || !sourceRunIds.has(linked.runId)) continue;
14634
- if (readOptionalString2(linked.row.decision) !== "ok") continue;
14635
- if (readOptionalString2(linked.row.reason) !== "validation_evidence") continue;
14636
- runIds.add(linked.runId);
14014
+ if (candidate?.runId !== null && candidate?.runId !== void 0) {
14015
+ addValidationEvidence(evidence, candidate.runId, candidate.artifact);
14016
+ }
14637
14017
  }
14638
- return runIds;
14018
+ return evidence;
14019
+ }
14020
+ function addValidationEvidence(evidence, runId, reference) {
14021
+ const current = evidence.get(runId) ?? [];
14022
+ current.push(reference);
14023
+ evidence.set(runId, current);
14639
14024
  }
14640
14025
  function validationRunIdFor(linked, runSources) {
14641
14026
  if (linked.link.runId !== null) return linked.link.runId;
@@ -14643,11 +14028,15 @@ function validationRunIdFor(linked, runSources) {
14643
14028
  return runSources[0]?.envelope.id ?? null;
14644
14029
  }
14645
14030
  function isSuccessfulRun(source) {
14646
- const outcome = source.receipt?.outcome ?? source.envelope.outcome ?? null;
14031
+ const receipt = authenticatedReceipt(source);
14032
+ const outcome = receipt?.outcome ?? source.envelope.outcome ?? null;
14647
14033
  if (outcome !== null) return outcome === "succeeded";
14648
- const exitCode = source.receipt?.exitCode ?? source.envelope.exitCode;
14034
+ const exitCode = receipt?.exitCode ?? source.envelope.exitCode;
14649
14035
  return source.envelope.status === "completed" && exitCode === 0;
14650
14036
  }
14037
+ function authenticatedReceipt(source) {
14038
+ return source.receipt !== null && source.receiptError === null && !source.receiptIntegrityFailed ? source.receipt : null;
14039
+ }
14651
14040
  function isSuccessfulValidationBashExecution(entry) {
14652
14041
  if (entry.cancelled || entry.exitCode !== 0) return false;
14653
14042
  return detectValidationCommand(entry.command).kind === "validation";
@@ -14662,7 +14051,8 @@ function validationToolCallCandidate(entry, linked, runSources) {
14662
14051
  if (validationToolCallSummary(call.tool, call.args) === null) return null;
14663
14052
  return {
14664
14053
  toolCallId: call.id,
14665
- runId: validationRunIdFor(linked, runSources)
14054
+ runId: validationRunIdFor(linked, runSources),
14055
+ artifact: { kind: "session_entry", id: entry.turnId }
14666
14056
  };
14667
14057
  }
14668
14058
  function validationToolCallSummary(toolName, args) {
@@ -14680,8 +14070,10 @@ function validationToolCallSummary(toolName, args) {
14680
14070
  const target = readOptionalString2(argRecord?.path) ?? "artifact";
14681
14071
  return `verify frontend ${target}`;
14682
14072
  }
14683
- if (check === null || !isVerificationScriptName(check)) return null;
14684
- return `npm run ${check}`;
14073
+ if (check === null) return null;
14074
+ if (isVerificationScriptName(check)) return `npm run ${check}`;
14075
+ if (isProjectVerifierCheckId(check)) return `verify ${check}`;
14076
+ return null;
14685
14077
  }
14686
14078
  return null;
14687
14079
  }
@@ -14700,23 +14092,24 @@ function finding(index, severity, tag, runId, message) {
14700
14092
  message
14701
14093
  };
14702
14094
  }
14703
- async function writeEvidenceFiles(directory, overview, runSources, findings, sessionLinks, auditLinks, toolEventRows, gateDecisions, protectedArtifacts, transcript) {
14095
+ async function writeEvidenceFiles(directory, overview, runSources, findings, sessionLinks, auditLinks, toolEventRows, gateDecisions, trustStatus, protectedArtifacts, transcript) {
14704
14096
  await mkdir(directory, { recursive: true });
14705
- await writeJson(join19(directory, "overview.json"), overview);
14097
+ await writeJson(join16(directory, "overview.json"), overview);
14706
14098
  await writeFile(
14707
- join19(directory, "transcript.md"),
14099
+ join16(directory, "transcript.md"),
14708
14100
  transcript ?? renderTranscript(overview, runSources, sessionLinks),
14709
14101
  "utf8"
14710
14102
  );
14711
- await writeJsonl(join19(directory, "trace.raw.jsonl"), rawTraceRows(runSources));
14712
- await writeJsonl(join19(directory, "trace.cleaned.jsonl"), cleanedTraceRows(runSources, findings, toolEventRows));
14713
- await writeJsonl(join19(directory, "tool-events.jsonl"), toolEventRows);
14714
- await writeJsonl(join19(directory, "audit-linked.jsonl"), auditLinks.rows);
14715
- await writeJson(join19(directory, "receipt.json"), receiptsFile(runSources));
14716
- await writeJson(join19(directory, "gate-decisions.json"), gateDecisions);
14717
- await writeJson(join19(directory, "protected-artifacts.json"), protectedArtifacts);
14718
- await writeJson(join19(directory, "findings.json"), findingsFile(overview.evidenceId, [...findings]));
14719
- await writeFile(join19(directory, "findings.md"), renderFindings(findings), "utf8");
14103
+ await writeJsonl(join16(directory, "trace.raw.jsonl"), rawTraceRows(runSources));
14104
+ await writeJsonl(join16(directory, "trace.cleaned.jsonl"), cleanedTraceRows(runSources, findings, toolEventRows));
14105
+ await writeJsonl(join16(directory, "tool-events.jsonl"), toolEventRows);
14106
+ await writeJsonl(join16(directory, "audit-linked.jsonl"), auditLinks.rows);
14107
+ await writeJson(join16(directory, "receipt.json"), receiptsFile(runSources));
14108
+ await writeJson(join16(directory, "gate-decisions.json"), gateDecisions);
14109
+ await writeJson(join16(directory, "trust-status.json"), trustStatus);
14110
+ await writeJson(join16(directory, "protected-artifacts.json"), protectedArtifacts);
14111
+ await writeJson(join16(directory, "findings.json"), findingsFile(overview.evidenceId, [...findings]));
14112
+ await writeFile(join16(directory, "findings.md"), renderFindings(findings), "utf8");
14720
14113
  }
14721
14114
  function rawTraceRows(runSources) {
14722
14115
  const rows = [];
@@ -14835,7 +14228,7 @@ function linkSessionEntry(entry, windows) {
14835
14228
  if (stamped !== null) {
14836
14229
  return { runId: stamped, kind: "entry-run-id", confidence: "exact", candidateRunIds: [stamped] };
14837
14230
  }
14838
- const candidates = windows.filter((window) => timestampInRunWindow(entry.timestamp, window)).map((window) => window.runId).sort(compareStrings5);
14231
+ const candidates = windows.filter((window) => timestampInRunWindow(entry.timestamp, window)).map((window) => window.runId).sort(compareCodepoints);
14839
14232
  const only = candidates.length === 1 ? candidates[0] : void 0;
14840
14233
  if (only !== void 0) {
14841
14234
  return { runId: only, kind: "timestamp-window", confidence: "best-effort", candidateRunIds: candidates };
@@ -14867,7 +14260,7 @@ function attributionWindows(ledger, runSources, sessionIds) {
14867
14260
  if (windows.has(id) || !linkedSessions.has(sessionId)) continue;
14868
14261
  windows.set(id, { runId: id, startedAt, endedAt: readOptionalString2(row.endedAt) });
14869
14262
  }
14870
- return [...windows.values()].sort((left, right) => compareStrings5(left.runId, right.runId));
14263
+ return [...windows.values()].sort((left, right) => compareCodepoints(left.runId, right.runId));
14871
14264
  }
14872
14265
  function evidenceRunLink(link) {
14873
14266
  return {
@@ -14884,11 +14277,11 @@ function timestampInRunWindow(timestamp, envelope) {
14884
14277
  return value >= start && value <= end;
14885
14278
  }
14886
14279
  function compareLinkedSessionEntries(a, b) {
14887
- const byTimestamp = compareStrings5(a.entry.timestamp, b.entry.timestamp);
14280
+ const byTimestamp = compareCodepoints(a.entry.timestamp, b.entry.timestamp);
14888
14281
  if (byTimestamp !== 0) return byTimestamp;
14889
- const bySession = compareStrings5(a.sessionId, b.sessionId);
14282
+ const bySession = compareCodepoints(a.sessionId, b.sessionId);
14890
14283
  if (bySession !== 0) return bySession;
14891
- return compareStrings5(a.entry.turnId, b.entry.turnId);
14284
+ return compareCodepoints(a.entry.turnId, b.entry.turnId);
14892
14285
  }
14893
14286
  function sessionToolEvents(entries) {
14894
14287
  const calls = /* @__PURE__ */ new Map();
@@ -15002,9 +14395,9 @@ function extractSessionToolResult(entry, linked) {
15002
14395
  };
15003
14396
  }
15004
14397
  function compareSessionToolCalls(a, b) {
15005
- const byTimestamp = compareStrings5(a.timestamp, b.timestamp);
14398
+ const byTimestamp = compareCodepoints(a.timestamp, b.timestamp);
15006
14399
  if (byTimestamp !== 0) return byTimestamp;
15007
- return compareStrings5(a.id, b.id);
14400
+ return compareCodepoints(a.id, b.id);
15008
14401
  }
15009
14402
  async function linkAuditRows(stateDir, source, runSources, sessionLinks) {
15010
14403
  const auditRows = await readAuditRows(stateDir);
@@ -15089,7 +14482,7 @@ function bestEffortAuditLink(audit, source, runSources, sessionIds) {
15089
14482
  linkKind: "ambiguous-timestamp-tool",
15090
14483
  confidence: "best-effort",
15091
14484
  reasons: ["audit timestamp and tool matched multiple runs in this session"],
15092
- candidateRunIds: candidates.map((item) => item.envelope.id).sort(compareStrings5)
14485
+ candidateRunIds: candidates.map((item) => item.envelope.id).sort(compareCodepoints)
15093
14486
  };
15094
14487
  }
15095
14488
  if (source.kind === "session" && sessionIds.has(source.sessionId)) {
@@ -15156,12 +14549,12 @@ function auditToolEvents(rows) {
15156
14549
  function compareAuditLinkedRows(a, b) {
15157
14550
  const byTs = compareNullableStrings(a.ts, b.ts);
15158
14551
  if (byTs !== 0) return byTs;
15159
- const byKind = compareStrings5(a.auditKind, b.auditKind);
14552
+ const byKind = compareCodepoints(a.auditKind, b.auditKind);
15160
14553
  if (byKind !== 0) return byKind;
15161
14554
  const aCorrelation = readOptionalString2(a.row.correlationId) ?? "";
15162
14555
  const bCorrelation = readOptionalString2(b.row.correlationId) ?? "";
15163
- if (aCorrelation !== bCorrelation) return compareStrings5(aCorrelation, bCorrelation);
15164
- return JSON.stringify(a.row).localeCompare(JSON.stringify(b.row));
14556
+ if (aCorrelation !== bCorrelation) return compareCodepoints(aCorrelation, bCorrelation);
14557
+ return compareCodepoints(JSON.stringify(a.row), JSON.stringify(b.row));
15165
14558
  }
15166
14559
  function receiptsFile(runSources) {
15167
14560
  return {
@@ -15198,7 +14591,7 @@ function protectedArtifactsFile(sessionLinks) {
15198
14591
  };
15199
14592
  }
15200
14593
  function compareProtectedArtifactEvents(left, right) {
15201
- return compareStrings5(left.timestamp, right.timestamp) || compareStrings5(left.sessionId, right.sessionId) || compareStrings5(left.turnId, right.turnId) || compareStrings5(left.artifact.path, right.artifact.path);
14594
+ return compareCodepoints(left.timestamp, right.timestamp) || compareCodepoints(left.sessionId, right.sessionId) || compareCodepoints(left.turnId, right.turnId) || compareCodepoints(left.artifact.path, right.artifact.path);
15202
14595
  }
15203
14596
  function renderTranscript(overview, runSources, sessionLinks) {
15204
14597
  const lines = [
@@ -15259,7 +14652,7 @@ function renderSessionTranscriptEntry(linked) {
15259
14652
  const error = result.isError ? " error=true" : "";
15260
14653
  return [`${prefix} tool_result ${result.tool}${id}${error}: ${previewUnknown(result.result)}`];
15261
14654
  }
15262
- const text = collapseWhitespace2(extractTextFromPayload(entry.payload));
14655
+ const text = collapseWhitespace(extractTextFromPayload(entry.payload));
15263
14656
  const rendered = text.length > 0 ? truncateText(text, TRANSCRIPT_TEXT_MAX_CHARS) : previewUnknown(entry.payload);
15264
14657
  return [`${prefix} ${entry.role}: ${rendered}`];
15265
14658
  }
@@ -15344,6 +14737,18 @@ function renderSessionTranscriptEntry(linked) {
15344
14737
  ];
15345
14738
  }
15346
14739
  if (entry.kind === "custom") return [`${prefix} custom:${entry.customType} ${previewUnknown(entry.data)}`];
14740
+ if (entry.kind === "contextEviction") {
14741
+ const pressure = entry.pressureBefore === null ? "" : ` pressure=${entry.pressureBefore.toFixed(3)}`;
14742
+ return [
14743
+ `${prefix} contextEviction policy=${entry.policyId} trigger=${entry.trigger} items=${entry.evicted.length} tokens=${entry.tokensBefore}->${entry.tokensAfter}${pressure}`,
14744
+ ...entry.evicted.map(
14745
+ (item) => ` evicted ref=${item.ref.entry} reason=${item.reason}${item.by === void 0 ? "" : ` by=${item.by}`} freed=${item.tokensFreed}`
14746
+ )
14747
+ ];
14748
+ }
14749
+ if (entry.kind === "contextRecall") {
14750
+ return [`${prefix} contextRecall ref=${entry.ref.entry} trigger=${entry.trigger} tokens=${entry.tokensReadmitted}`];
14751
+ }
15347
14752
  const _exhaustive = entry;
15348
14753
  return [`${prefix} ${String(_exhaustive)}`];
15349
14754
  }
@@ -15359,10 +14764,10 @@ function renderFindings(findings) {
15359
14764
  `;
15360
14765
  }
15361
14766
  async function readRunLedger(stateDir) {
15362
- const target = join19(stateDir, "runs.json");
14767
+ const target = join16(stateDir, "runs.json");
15363
14768
  let raw;
15364
14769
  try {
15365
- raw = await readFile3(target, "utf8");
14770
+ raw = await readFile2(target, "utf8");
15366
14771
  } catch (error) {
15367
14772
  const err = error;
15368
14773
  if (err.code === "ENOENT") throw new Error("run ledger not found");
@@ -15380,10 +14785,10 @@ function selectRunEnvelopes(ledger, source) {
15380
14785
  });
15381
14786
  }
15382
14787
  async function readReceipt(stateDir, envelope) {
15383
- const receiptPath = envelope.receiptPath ?? join19(stateDir, "receipts", `${envelope.id}.json`);
14788
+ const receiptPath = envelope.receiptPath ?? join16(stateDir, "receipts", `${envelope.id}.json`);
15384
14789
  let raw;
15385
14790
  try {
15386
- raw = await readFile3(receiptPath, "utf8");
14791
+ raw = await readFile2(receiptPath, "utf8");
15387
14792
  } catch (error) {
15388
14793
  const err = error;
15389
14794
  if (err.code === "ENOENT") {
@@ -15391,9 +14796,18 @@ async function readReceipt(stateDir, envelope) {
15391
14796
  }
15392
14797
  return { receipt: null, error: `receipt read error: ${err.message ?? String(err)}`, integrityFailed: false };
15393
14798
  }
15394
- const parsed = parseJson2(raw, receiptPath);
15395
- const receipt = parseRunReceipt(parsed, receiptPath);
15396
- const integrity = verifyReceiptIntegrity(receipt, envelope);
14799
+ let receipt;
14800
+ try {
14801
+ const parsed = parseJson2(raw, receiptPath);
14802
+ receipt = parseRunReceipt(parsed, receiptPath);
14803
+ } catch (error) {
14804
+ return {
14805
+ receipt: null,
14806
+ error: `receipt invalid: ${error instanceof Error ? error.message : String(error)}`,
14807
+ integrityFailed: true
14808
+ };
14809
+ }
14810
+ const integrity = inspectRunReceiptTrustStatus(receipt, envelope).integrity;
15397
14811
  if (!integrity.ok) {
15398
14812
  return { receipt, error: `receipt integrity: ${integrity.reason}`, integrityFailed: true };
15399
14813
  }
@@ -15582,15 +14996,15 @@ function extractTextFromPayload(payload) {
15582
14996
  }
15583
14997
  function previewUnknown(value) {
15584
14998
  if (value === void 0) return "";
15585
- if (typeof value === "string") return truncateText(collapseWhitespace2(value), TOOL_PREVIEW_MAX_CHARS);
14999
+ if (typeof value === "string") return truncateText(collapseWhitespace(value), TOOL_PREVIEW_MAX_CHARS);
15586
15000
  try {
15587
15001
  const text = JSON.stringify(value);
15588
- return text === void 0 ? "" : truncateText(collapseWhitespace2(text), TOOL_PREVIEW_MAX_CHARS);
15002
+ return text === void 0 ? "" : truncateText(collapseWhitespace(text), TOOL_PREVIEW_MAX_CHARS);
15589
15003
  } catch {
15590
- return truncateText(collapseWhitespace2(String(value)), TOOL_PREVIEW_MAX_CHARS);
15004
+ return truncateText(collapseWhitespace(String(value)), TOOL_PREVIEW_MAX_CHARS);
15591
15005
  }
15592
15006
  }
15593
- function collapseWhitespace2(text) {
15007
+ function collapseWhitespace(text) {
15594
15008
  return text.replace(/\s+/g, " ").trim();
15595
15009
  }
15596
15010
  async function writeJson(path2, value) {
@@ -15609,34 +15023,31 @@ function durationMs(startedAt, endedAt) {
15609
15023
  }
15610
15024
  function earliest(values) {
15611
15025
  if (values.length === 0) return null;
15612
- return [...values].sort(compareStrings5)[0] ?? null;
15026
+ return [...values].sort(compareCodepoints)[0] ?? null;
15613
15027
  }
15614
15028
  function latest(values) {
15615
15029
  if (values.length === 0) return null;
15616
- return [...values].sort(compareStrings5).at(-1) ?? null;
15030
+ return [...values].sort(compareCodepoints).at(-1) ?? null;
15617
15031
  }
15618
15032
  function uniqueStrings(values) {
15619
- return [...new Set(values)].sort(compareStrings5);
15033
+ return [...new Set(values)].sort(compareCodepoints);
15620
15034
  }
15621
15035
  function uniqueTags(values) {
15622
- return [...new Set(values)].sort(compareStrings5);
15623
- }
15624
- function compareStrings5(a, b) {
15625
- return a.localeCompare(b);
15036
+ return [...new Set(values)].sort(compareCodepoints);
15626
15037
  }
15627
15038
  function compareNullableStrings(a, b) {
15628
15039
  if (a === b) return 0;
15629
15040
  if (a === null) return 1;
15630
15041
  if (b === null) return -1;
15631
- return compareStrings5(a, b);
15042
+ return compareCodepoints(a, b);
15632
15043
  }
15633
15044
  function compareRuns(a, b) {
15634
- const byStart = compareStrings5(a.startedAt, b.startedAt);
15045
+ const byStart = compareCodepoints(a.startedAt, b.startedAt);
15635
15046
  if (byStart !== 0) return byStart;
15636
- return compareStrings5(a.id, b.id);
15047
+ return compareCodepoints(a.id, b.id);
15637
15048
  }
15638
15049
  function compareToolStats(a, b) {
15639
- return compareStrings5(a.tool, b.tool);
15050
+ return compareCodepoints(a.tool, b.tool);
15640
15051
  }
15641
15052
  function compareEvidenceToolEvents(a, b) {
15642
15053
  const byTimestamp = compareNullableStrings(a.timestamp ?? null, b.timestamp ?? null);
@@ -15645,7 +15056,7 @@ function compareEvidenceToolEvents(a, b) {
15645
15056
  if (byRun !== 0) return byRun;
15646
15057
  const bySession = compareNullableStrings(a.sessionId, b.sessionId);
15647
15058
  if (bySession !== 0) return bySession;
15648
- const byTool = compareStrings5(a.tool, b.tool);
15059
+ const byTool = compareCodepoints(a.tool, b.tool);
15649
15060
  if (byTool !== 0) return byTool;
15650
15061
  return compareNullableStrings(a.toolCallId ?? null, b.toolCallId ?? null);
15651
15062
  }
@@ -15661,8 +15072,8 @@ function sanitizeEvidenceId(value) {
15661
15072
 
15662
15073
  // src/domains/evidence/eval.ts
15663
15074
  init_esm_shims();
15664
- import { mkdir as mkdir2, readdir as readdir3, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
15665
- import { join as join20 } from "node:path";
15075
+ import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
15076
+ import { join as join17 } from "node:path";
15666
15077
 
15667
15078
  // src/domains/eval/index.ts
15668
15079
  init_esm_shims();
@@ -15712,12 +15123,13 @@ var EVAL_EVIDENCE_FILES = [
15712
15123
  "audit-linked.jsonl",
15713
15124
  "receipt.json",
15714
15125
  "gate-decisions.json",
15126
+ "trust-status.json",
15715
15127
  "protected-artifacts.json",
15716
15128
  "eval-result.json",
15717
15129
  "findings.json",
15718
15130
  "findings.md"
15719
15131
  ];
15720
- var PREVIEW_MAX_CHARS2 = 240;
15132
+ var PREVIEW_MAX_CHARS = 240;
15721
15133
  async function buildEvalEvidence(options) {
15722
15134
  if (options.evalId !== void 0 && options.artifact !== void 0) {
15723
15135
  throw new Error("build eval evidence accepts either evalId or artifact, not both");
@@ -15740,8 +15152,23 @@ async function buildEvalEvidence(options) {
15740
15152
  options.stateDir
15741
15153
  ).map((entry) => entry.artifact)
15742
15154
  };
15743
- await writeEvalEvidenceFiles(directory, artifact, overview, findings, toolEventRows, linkedRuns, gateDecisions);
15744
- return { evidenceId, directory, overview, findings };
15155
+ const trustStatus = buildEvidenceTrustStatusFile({
15156
+ evidenceId,
15157
+ runSources: linkedRuns.runSources,
15158
+ gateDecisions: gateDecisions.decisions,
15159
+ auditRows: linkedRuns.auditRows
15160
+ });
15161
+ await writeEvalEvidenceFiles(
15162
+ directory,
15163
+ artifact,
15164
+ overview,
15165
+ findings,
15166
+ toolEventRows,
15167
+ linkedRuns,
15168
+ gateDecisions,
15169
+ trustStatus
15170
+ );
15171
+ return { evidenceId, directory, overview, findings, trustStatus };
15745
15172
  }
15746
15173
  function evalEvidenceId(evalId) {
15747
15174
  return `eval-${sanitizeEvidenceId2(evalId)}`;
@@ -15756,7 +15183,7 @@ function evalOverview(evidenceId, artifact, findings, toolEventRows, linkedRuns,
15756
15183
  evidenceId,
15757
15184
  source: { kind: "eval", evalId: artifact.evalId },
15758
15185
  generatedAt: artifact.endedAt,
15759
- runIds: envelopes.length > 0 ? uniqueStrings2(envelopes.map((envelope) => envelope.id)) : artifact.results.map((result) => result.runId).sort(compareStrings6),
15186
+ runIds: envelopes.length > 0 ? uniqueStrings2(envelopes.map((envelope) => envelope.id)) : artifact.results.map((result) => result.runId).sort(compareCodepoints),
15760
15187
  sessionId: uniqueStrings2(envelopes.flatMap((envelope) => envelope.sessionId === null ? [] : [envelope.sessionId]))[0] ?? null,
15761
15188
  statuses: envelopes.length > 0 ? uniqueStrings2(envelopes.map((envelope) => envelope.status)) : uniqueStrings2(artifact.results.map((result) => result.pass ? "passed" : "failed")),
15762
15189
  startedAt: artifact.startedAt,
@@ -15843,7 +15270,7 @@ function evalToolEvents(artifact) {
15843
15270
  }
15844
15271
  return events.sort(compareEvidenceToolEvents2);
15845
15272
  }
15846
- async function writeEvalEvidenceFiles(directory, artifact, overview, findings, toolEventRows, linkedRuns, gateDecisions) {
15273
+ async function writeEvalEvidenceFiles(directory, artifact, overview, findings, toolEventRows, linkedRuns, gateDecisions, trustStatus) {
15847
15274
  const emptyProtected = { version: EVIDENCE_VERSION, artifacts: [], events: [] };
15848
15275
  const receiptsFile2 = {
15849
15276
  version: EVIDENCE_VERSION,
@@ -15851,18 +15278,19 @@ async function writeEvalEvidenceFiles(directory, artifact, overview, findings, t
15851
15278
  };
15852
15279
  const redactedArtifact = redactArtifactForStorage(artifact);
15853
15280
  await mkdir2(directory, { recursive: true });
15854
- await writeJson2(join20(directory, "overview.json"), overview);
15855
- await writeFile2(join20(directory, "transcript.md"), renderEvalTranscript(redactedArtifact, overview), "utf8");
15856
- await writeJsonl2(join20(directory, "trace.raw.jsonl"), rawEvalTraceRows(redactedArtifact));
15857
- await writeJsonl2(join20(directory, "trace.cleaned.jsonl"), cleanedEvalTraceRows(redactedArtifact, findings));
15858
- await writeJsonl2(join20(directory, "tool-events.jsonl"), redactArtifactForStorage(toolEventRows));
15859
- await writeJsonl2(join20(directory, "audit-linked.jsonl"), linkedRuns.auditRows);
15860
- await writeJson2(join20(directory, "receipt.json"), receiptsFile2);
15861
- await writeJson2(join20(directory, "gate-decisions.json"), gateDecisions);
15862
- await writeJson2(join20(directory, "protected-artifacts.json"), emptyProtected);
15863
- await writeJson2(join20(directory, "eval-result.json"), redactedArtifact);
15864
- await writeJson2(join20(directory, "findings.json"), findingsFile(overview.evidenceId, [...findings]));
15865
- await writeFile2(join20(directory, "findings.md"), renderFindings2(findings), "utf8");
15281
+ await writeJson2(join17(directory, "overview.json"), overview);
15282
+ await writeFile2(join17(directory, "transcript.md"), renderEvalTranscript(redactedArtifact, overview), "utf8");
15283
+ await writeJsonl2(join17(directory, "trace.raw.jsonl"), rawEvalTraceRows(redactedArtifact));
15284
+ await writeJsonl2(join17(directory, "trace.cleaned.jsonl"), cleanedEvalTraceRows(redactedArtifact, findings));
15285
+ await writeJsonl2(join17(directory, "tool-events.jsonl"), redactArtifactForStorage(toolEventRows));
15286
+ await writeJsonl2(join17(directory, "audit-linked.jsonl"), linkedRuns.auditRows);
15287
+ await writeJson2(join17(directory, "receipt.json"), receiptsFile2);
15288
+ await writeJson2(join17(directory, "gate-decisions.json"), gateDecisions);
15289
+ await writeJson2(join17(directory, "trust-status.json"), trustStatus);
15290
+ await writeJson2(join17(directory, "protected-artifacts.json"), emptyProtected);
15291
+ await writeJson2(join17(directory, "eval-result.json"), redactedArtifact);
15292
+ await writeJson2(join17(directory, "findings.json"), findingsFile(overview.evidenceId, [...findings]));
15293
+ await writeFile2(join17(directory, "findings.md"), renderFindings2(findings), "utf8");
15866
15294
  }
15867
15295
  function rawEvalTraceRows(artifact) {
15868
15296
  return artifact.results.map((result) => ({
@@ -15971,22 +15399,22 @@ async function writeJsonl2(path2, rows) {
15971
15399
  }
15972
15400
  function commandPreview(command) {
15973
15401
  const text = command.stderr.length > 0 ? command.stderr : command.stdout;
15974
- return truncateText2(text, PREVIEW_MAX_CHARS2);
15402
+ return truncateText2(text, PREVIEW_MAX_CHARS);
15975
15403
  }
15976
15404
  function truncateText2(value, maxChars) {
15977
15405
  if (value.length <= maxChars) return value;
15978
15406
  return `${value.slice(0, Math.max(0, maxChars - 1))}\u2026`;
15979
15407
  }
15980
15408
  function uniqueStrings2(values) {
15981
- return [...new Set(values)].sort(compareStrings6);
15409
+ return [...new Set(values)].sort(compareCodepoints);
15982
15410
  }
15983
15411
  function uniqueTags2(values) {
15984
- return [...new Set(values)].sort(compareStrings6);
15412
+ return [...new Set(values)].sort(compareCodepoints);
15985
15413
  }
15986
15414
  function compareEvidenceToolEvents2(a, b) {
15987
15415
  const byRun = compareNullableStrings2(a.runId, b.runId);
15988
15416
  if (byRun !== 0) return byRun;
15989
- const byTool = compareStrings6(a.tool, b.tool);
15417
+ const byTool = compareCodepoints(a.tool, b.tool);
15990
15418
  if (byTool !== 0) return byTool;
15991
15419
  const byArgs = compareNullableStrings2(a.argsPreview ?? null, b.argsPreview ?? null);
15992
15420
  if (byArgs !== 0) return byArgs;
@@ -16013,7 +15441,7 @@ async function linkEvalRuns(stateDir, artifact) {
16013
15441
  }
16014
15442
  async function readRunLedger2(stateDir) {
16015
15443
  try {
16016
- const raw = await readFile4(join20(stateDir, "runs.json"), "utf8");
15444
+ const raw = await readFile3(join17(stateDir, "runs.json"), "utf8");
16017
15445
  const parsed = JSON.parse(raw);
16018
15446
  return Array.isArray(parsed) ? parsed.filter(isRecord13) : [];
16019
15447
  } catch {
@@ -16024,9 +15452,9 @@ function evalRunMatches(artifact, envelope) {
16024
15452
  return artifact.results.some((result) => result.runId === envelope.id);
16025
15453
  }
16026
15454
  async function readReceiptForRun(stateDir, envelope) {
16027
- const path2 = envelope.receiptPath ?? join20(stateDir, "receipts", `${envelope.id}.json`);
15455
+ const path2 = envelope.receiptPath ?? join17(stateDir, "receipts", `${envelope.id}.json`);
16028
15456
  try {
16029
- const parsed = JSON.parse(await readFile4(path2, "utf8"));
15457
+ const parsed = JSON.parse(await readFile3(path2, "utf8"));
16030
15458
  return isRecord13(parsed) ? parsed : null;
16031
15459
  } catch {
16032
15460
  return null;
@@ -16038,7 +15466,7 @@ async function countSessionEntries(stateDir, sessionIds) {
16038
15466
  const path2 = await findSessionLedgerPath(stateDir, sessionId);
16039
15467
  if (path2 === null) continue;
16040
15468
  try {
16041
- const raw = await readFile4(path2, "utf8");
15469
+ const raw = await readFile3(path2, "utf8");
16042
15470
  count += raw.split("\n").filter((line) => line.trim().length > 0).filter((line) => {
16043
15471
  try {
16044
15472
  const parsed = JSON.parse(line);
@@ -16053,17 +15481,17 @@ async function countSessionEntries(stateDir, sessionIds) {
16053
15481
  return count;
16054
15482
  }
16055
15483
  async function findSessionLedgerPath(stateDir, sessionId) {
16056
- const root = join20(stateDir, "sessions");
15484
+ const root = join17(stateDir, "sessions");
16057
15485
  let cwdHashes;
16058
15486
  try {
16059
- cwdHashes = await readdir3(root);
15487
+ cwdHashes = await readdir2(root);
16060
15488
  } catch {
16061
15489
  return null;
16062
15490
  }
16063
- for (const cwdHash2 of cwdHashes) {
16064
- const path2 = join20(root, cwdHash2, sessionId, "current.jsonl");
15491
+ for (const cwdHash of cwdHashes) {
15492
+ const path2 = join17(root, cwdHash, sessionId, "current.jsonl");
16065
15493
  try {
16066
- await readFile4(path2, "utf8");
15494
+ await readFile3(path2, "utf8");
16067
15495
  return path2;
16068
15496
  } catch {
16069
15497
  }
@@ -16071,16 +15499,16 @@ async function findSessionLedgerPath(stateDir, sessionId) {
16071
15499
  return null;
16072
15500
  }
16073
15501
  async function linkedEvalAuditRows(stateDir, runIds, artifact) {
16074
- const root = join20(stateDir, "audit");
15502
+ const root = join17(stateDir, "audit");
16075
15503
  let files;
16076
15504
  try {
16077
- files = await readdir3(root);
15505
+ files = await readdir2(root);
16078
15506
  } catch {
16079
15507
  return [];
16080
15508
  }
16081
15509
  const rows = [];
16082
- for (const file of files.filter((name) => name.endsWith(".jsonl")).sort(compareStrings6)) {
16083
- const raw = await readFile4(join20(root, file), "utf8").catch(() => "");
15510
+ for (const file of files.filter((name) => name.endsWith(".jsonl")).sort(compareCodepoints)) {
15511
+ const raw = await readFile3(join17(root, file), "utf8").catch(() => "");
16084
15512
  const lines = raw.split("\n");
16085
15513
  for (let index = 0; index < lines.length; index += 1) {
16086
15514
  const line = lines[index];
@@ -16144,27 +15572,24 @@ function timestampInEvalWindow(timestamp, artifact) {
16144
15572
  return Number.isFinite(value) && Number.isFinite(start) && Number.isFinite(end) && value >= start && value <= end;
16145
15573
  }
16146
15574
  function compareRunEnvelopes(a, b) {
16147
- return compareStrings6(a.startedAt, b.startedAt) || compareStrings6(a.id, b.id);
15575
+ return compareCodepoints(a.startedAt, b.startedAt) || compareCodepoints(a.id, b.id);
16148
15576
  }
16149
15577
  function compareAuditRows(a, b) {
16150
- return compareNullableStrings2(a.ts, b.ts) || compareNullableStrings2(a.runId, b.runId) || JSON.stringify(a.row).localeCompare(JSON.stringify(b.row));
15578
+ return compareNullableStrings2(a.ts, b.ts) || compareNullableStrings2(a.runId, b.runId) || compareCodepoints(JSON.stringify(a.row), JSON.stringify(b.row));
16151
15579
  }
16152
15580
  function compareToolStats2(a, b) {
16153
- return compareStrings6(a.tool, b.tool);
15581
+ return compareCodepoints(a.tool, b.tool);
16154
15582
  }
16155
15583
  function compareNullableStrings2(a, b) {
16156
15584
  if (a === b) return 0;
16157
15585
  if (a === null) return -1;
16158
15586
  if (b === null) return 1;
16159
- return compareStrings6(a, b);
15587
+ return compareCodepoints(a, b);
16160
15588
  }
16161
15589
  function sanitizeEvidenceId2(value) {
16162
15590
  const sanitized = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
16163
15591
  return sanitized.length === 0 ? "unknown" : sanitized;
16164
15592
  }
16165
- function compareStrings6(a, b) {
16166
- return a.localeCompare(b);
16167
- }
16168
15593
  function isRecord13(value) {
16169
15594
  return typeof value === "object" && value !== null && !Array.isArray(value);
16170
15595
  }
@@ -16380,26 +15805,19 @@ export {
16380
15805
  createWriteBoundaryEnforcer,
16381
15806
  DispatchDomainModule,
16382
15807
  createDispatchDomainModule,
16383
- collectSessionEntries,
16384
- filterEntriesToActivePath,
16385
- readAuditRows,
16386
- parseSessionEntries,
16387
- listSessionLedgerRefs,
16388
- protectedArtifactEntryFromArtifact,
16389
- protectedArtifactStateFromSessionEntries,
16390
- ledgerUsageCalls,
16391
- SessionDomainModule,
16392
15808
  extractRunProvenance,
16393
15809
  provenanceTranscriptLines,
16394
15810
  provenanceCompactSuffix,
15811
+ adaptRunReceiptTrustStatus,
15812
+ inspectRunReceiptTrustStatus,
15813
+ FAILURE_CAUSE_TAGS,
16395
15814
  evidenceDirectory,
16396
15815
  EvidenceNotFoundError,
16397
15816
  inspectEvidence,
16398
15817
  loadEvidenceRunProvenance,
16399
15818
  listEvidenceOverviews,
16400
- FAILURE_CAUSE_TAGS,
16401
15819
  buildEvidence,
16402
15820
  summarizeEvalResults,
16403
15821
  buildEvalEvidence
16404
15822
  };
16405
- //# sourceMappingURL=chunk-SRDMMSEP.js.map
15823
+ //# sourceMappingURL=chunk-QM3F2GKX.js.map