@iowarp/clio-coder 0.3.7 → 0.3.9

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 (400) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +13 -4
  3. package/dist/{acp-SK4MD6MM.js → acp-7LOELQFP.js} +13 -13
  4. package/dist/{agents-2FN2K6ME.js → agents-FIBG2SHA.js} +41 -37
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-QIYZWM5I.js → auth-OI4LIH2I.js} +31 -24
  7. package/dist/builtins-AD25UL3C.js +17 -0
  8. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  9. package/dist/chunk-3DPEIQKN.js +113 -0
  10. package/dist/{chunk-EOOQZZDE.js → chunk-3DUR4WUA.js} +19 -19
  11. package/dist/{chunk-WHJYKASB.js → chunk-3MRC2YSQ.js} +2 -2
  12. package/dist/{chunk-EBEFWSGL.js → chunk-3UUY7R3Z.js} +14 -10
  13. package/dist/{chunk-LADCF22A.js → chunk-3V5AYSEQ.js} +113 -54
  14. package/dist/{chunk-BMWK7ZIZ.js → chunk-465CC7FK.js} +16 -13
  15. package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
  16. package/dist/{chunk-CEYBNUGC.js → chunk-4H6ULJ3H.js} +378 -36
  17. package/dist/{chunk-YTYFXUI3.js → chunk-4LJX2PUC.js} +9 -9
  18. package/dist/{chunk-DOOEX22V.js → chunk-56KB5IJP.js} +5 -5
  19. package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
  20. package/dist/{chunk-TSHXZTOQ.js → chunk-5HFBWUMU.js} +23 -11
  21. package/dist/{chunk-5UJ6ECTS.js → chunk-5PVQ4SRS.js} +80 -8
  22. package/dist/{chunk-ZWLZP4ZT.js → chunk-5QKCQQ3E.js} +359 -17
  23. package/dist/{chunk-6M7VS3J3.js → chunk-5T7RBWN2.js} +111 -5
  24. package/dist/chunk-774ILSRL.js +172 -0
  25. package/dist/chunk-7C6RYZGQ.js +391 -0
  26. package/dist/{chunk-GH5622CP.js → chunk-A2NJGIB3.js} +2 -2
  27. package/dist/{chunk-C4JBQ5SR.js → chunk-AD7Y7STJ.js} +6 -6
  28. package/dist/{chunk-GEYXPTRF.js → chunk-AEYBF3TB.js} +33 -12
  29. package/dist/{chunk-2SFS6XQE.js → chunk-AMKHQW3C.js} +3 -2
  30. package/dist/{chunk-D4MDIG46.js → chunk-B5CSFE7B.js} +7 -7
  31. package/dist/{chunk-MXI6J5JF.js → chunk-B5XRQOLB.js} +10 -10
  32. package/dist/{chunk-X2KV5FXT.js → chunk-BVDVID7E.js} +2 -2
  33. package/dist/{chunk-JNXPYBB4.js → chunk-CA42X6KT.js} +3 -3
  34. package/dist/{chunk-VREKEFLL.js → chunk-D73KXYPF.js} +3 -3
  35. package/dist/{chunk-JTSEDYVQ.js → chunk-DG4M6ZUE.js} +7 -7
  36. package/dist/{chunk-DQA7QLMD.js → chunk-EBOC7MT3.js} +10 -25
  37. package/dist/{chunk-KZ2H5X4G.js → chunk-ECUO3KDP.js} +129 -14
  38. package/dist/{chunk-JRIO5UD2.js → chunk-EQ63NRB7.js} +5 -5
  39. package/dist/{chunk-YD734TPH.js → chunk-FALJGAWU.js} +2 -2
  40. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  41. package/dist/{chunk-XEGB6BCN.js → chunk-GAYUJ7LE.js} +68 -14
  42. package/dist/{chunk-UND3GU2L.js → chunk-H7IXIC72.js} +2 -2
  43. package/dist/{chunk-IR4CFBFN.js → chunk-HAY4ZE2P.js} +12 -12
  44. package/dist/{chunk-UVDSQ6LW.js → chunk-HCBCAYZU.js} +74 -147
  45. package/dist/{chunk-4DWFMQDR.js → chunk-HJB5IUKP.js} +89 -145
  46. package/dist/{chunk-M4AKACEO.js → chunk-HKO36JWF.js} +33 -5
  47. package/dist/{chunk-KCMKRQX4.js → chunk-HPCTNZM2.js} +45 -82
  48. package/dist/{chunk-465YSENW.js → chunk-IFBNV6H6.js} +3 -3
  49. package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
  50. package/dist/chunk-JEQQR47K.js +3025 -0
  51. package/dist/{chunk-FO5ZOVUY.js → chunk-KV2AOLDF.js} +27 -7
  52. package/dist/chunk-LU7P4LHA.js +33 -0
  53. package/dist/{chunk-6TUKSZVF.js → chunk-LXPJXFM5.js} +11 -11
  54. package/dist/{chunk-VQNODYQ4.js → chunk-MIX5N5AC.js} +488 -3668
  55. package/dist/chunk-MLOK6ZOS.js +2888 -0
  56. package/dist/{chunk-ZZMN5OM4.js → chunk-MV2VUEJC.js} +2 -2
  57. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  58. package/dist/{chunk-OBMAI2DP.js → chunk-N3PBVRTZ.js} +12 -388
  59. package/dist/{chunk-WJHBC77E.js → chunk-N5XKWMDW.js} +17 -7
  60. package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
  61. package/dist/{chunk-UFQ3F4FW.js → chunk-NQ6UCCOD.js} +4 -4
  62. package/dist/chunk-NUGM5KR6.js +165 -0
  63. package/dist/{chunk-DMD2AGVS.js → chunk-NZU6YDNV.js} +20 -18
  64. package/dist/{chunk-WHGPSPT5.js → chunk-O6I4CIEU.js} +151 -13
  65. package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
  66. package/dist/{chunk-PD3MESLB.js → chunk-P3JGPQFL.js} +4 -4
  67. package/dist/{chunk-UHXRNZ2J.js → chunk-PNY46YEY.js} +23 -6
  68. package/dist/{chunk-THKY7CD7.js → chunk-PZ4I4JE2.js} +134 -29
  69. package/dist/{chunk-SROCI7ZU.js → chunk-QQ7EKM72.js} +5 -5
  70. package/dist/{chunk-QCTRSGHQ.js → chunk-R7LNVMCS.js} +91 -53
  71. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  72. package/dist/chunk-RKKLTLYB.js +45 -0
  73. package/dist/{chunk-OB5HIGJY.js → chunk-RKRLDWD3.js} +4 -1
  74. package/dist/{chunk-DJNLUABN.js → chunk-S4COXYBG.js} +588 -32
  75. package/dist/{chunk-3HAPLH5M.js → chunk-T3Z6VAAF.js} +172 -11
  76. package/dist/{chunk-FOT2FX5J.js → chunk-TD7UE2L5.js} +12 -10
  77. package/dist/{chunk-UUANF5CR.js → chunk-TEO2TLVN.js} +856 -967
  78. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  79. package/dist/{chunk-EELBMBT6.js → chunk-VKBMFOYV.js} +74 -15
  80. package/dist/chunk-VO2LKSTM.js +165 -0
  81. package/dist/{chunk-5C77SEEY.js → chunk-VPTUJU4P.js} +3 -3
  82. package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
  83. package/dist/{chunk-J7PIKKWC.js → chunk-WXCJ7VME.js} +8 -8
  84. package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
  85. package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
  86. package/dist/{chunk-AB4XIIVB.js → chunk-YKOFT37S.js} +6 -6
  87. package/dist/chunk-YSEHGPCT.js +127 -0
  88. package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
  89. package/dist/cli/index.js +32 -32
  90. package/dist/{clio-WBVQEBKO.js → clio-LT5V7SSZ.js} +9 -9
  91. package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +5 -5
  92. package/dist/codewiki/build-worker.js +4 -4
  93. package/dist/{components-F7OEATSO.js → components-ZFA3SAER.js} +8 -8
  94. package/dist/{config-TRBL3RCF.js → config-RXS5T3JT.js} +98 -65
  95. package/dist/{configure-OLCVPHNM.js → configure-2WYWSCSD.js} +26 -22
  96. package/dist/{context-MJIJ6GOX.js → context-I3BTOTCS.js} +12 -12
  97. package/dist/{context-XEWE3MOJ.js → context-MVOORGMF.js} +54 -47
  98. package/dist/{context-WFPKQSM6.js → context-PALKKQYL.js} +28 -28
  99. package/dist/{context-clear-KNOS2JPB.js → context-clear-N2WOYZ2K.js} +53 -46
  100. package/dist/{context-index-SSR5ECNE.js → context-index-HNG3MOME.js} +6 -6
  101. package/dist/{context-working-set-EUXAZI6N.js → context-working-set-MIEVECVZ.js} +17 -18
  102. package/dist/{dispatch-runner-B7MTOVKL.js → dispatch-runner-VVA4SRRH.js} +90 -61
  103. package/dist/{docs-FLJTIDSE.js → docs-7LQ23DLM.js} +8 -8
  104. package/dist/doctor-TWBWFK5V.js +165 -0
  105. package/dist/eval-IJ5VEZDJ.js +4483 -0
  106. package/dist/{evidence-JZNBUOQZ.js → evidence-L5APPXNV.js} +68 -61
  107. package/dist/{evolve-FJVC4KKI.js → evolve-RGNKFJ52.js} +47 -40
  108. package/dist/{extensions-IQL36S7K.js → extensions-7WYWUX5A.js} +13 -7
  109. package/dist/{fleet-BDKYJFCP.js → fleet-6CNVBZZP.js} +113 -76
  110. package/dist/{fleet-commands-ZFIWZSB3.js → fleet-commands-L2SXSYEI.js} +10 -10
  111. package/dist/{fleet-graph-Y6HPXIVF.js → fleet-graph-2J3OOIPO.js} +17 -15
  112. package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-CZRJ4JP5.js} +5 -6
  113. package/dist/{fleet-validate-BIYREGIK.js → fleet-validate-C5RI6DP7.js} +20 -19
  114. package/dist/{init-LQUB5COQ.js → init-VBN2ACVA.js} +70 -63
  115. package/dist/{library-NJAHIGG4.js → library-JHGUMLY2.js} +22 -20
  116. package/dist/{memory-OG6HOYKM.js → memory-K4OQIYWG.js} +49 -42
  117. package/dist/{models-5ZG5XY7J.js → models-2NCZUWDD.js} +35 -29
  118. package/dist/{monitor-TJ7AMTGB.js → monitor-MMVTJABD.js} +64 -45
  119. package/dist/{orchestrator-WZYB54DM.js → orchestrator-ZKBPCHW6.js} +1971 -520
  120. package/dist/{paths-XUC7GS6E.js → paths-DBXMZMDU.js} +5 -5
  121. package/dist/registry-LG64LTF4.js +11 -0
  122. package/dist/{reset-PXQT45IY.js → reset-DD5JGOY3.js} +11 -11
  123. package/dist/{run-FQ74YF62.js → run-QEGNX7FL.js} +89 -83
  124. package/dist/{share-FW7SVCL3.js → share-JKD3BQMW.js} +20 -18
  125. package/dist/{skills-7E7IRB3R.js → skills-LMQIKDOZ.js} +23 -21
  126. package/dist/{skills-eval-LI75W6OK.js → skills-eval-I7X2774U.js} +59 -52
  127. package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
  128. package/dist/support-I7LOJLIF.js +38 -0
  129. package/dist/{targets-4CIFKCTW.js → targets-RUSR6B5Z.js} +77 -42
  130. package/dist/{terminal-lease-WUZY7ZV5.js → terminal-lease-QYVORFR4.js} +6 -4
  131. package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
  132. package/dist/{uninstall-7FV7IP4E.js → uninstall-ZJF5H5ZN.js} +8 -8
  133. package/dist/{upgrade-K2HVIVMQ.js → upgrade-XANW3FXB.js} +29 -26
  134. package/dist/{usage-GTZELZQX.js → usage-4H7ZRXQT.js} +110 -61
  135. package/dist/{verifiers-RLAHT27O.js → verifiers-UZXNBZEB.js} +13 -13
  136. package/dist/{verify-BX3BRKH5.js → verify-BVKWTNDL.js} +9 -9
  137. package/dist/{wiki-generate-ASIFASCN.js → wiki-generate-MY7WV2QI.js} +76 -69
  138. package/dist/worker/entry.js +69 -66
  139. package/docs/alcf-provider.md +1 -1
  140. package/docs/architecture.md +1 -1
  141. package/docs/artifact-versions.md +11 -5
  142. package/docs/built-in-agents.md +1 -1
  143. package/docs/capacity-and-scheduling.md +23 -2
  144. package/docs/commands-and-modes.md +2 -2
  145. package/docs/configuration-and-targets.md +37 -5
  146. package/docs/context-engine.md +63 -4
  147. package/docs/documentation-coverage.md +3 -3
  148. package/docs/documentation-guide.md +1 -1
  149. package/docs/environment-variables.md +2 -0
  150. package/docs/eval-runner.md +262 -11
  151. package/docs/evals-internal.md +72 -2
  152. package/docs/evidence-and-memory.md +77 -12
  153. package/docs/evolution.md +1 -1
  154. package/docs/extensions-and-sharing.md +3 -1
  155. package/docs/fleet-dispatch.md +34 -9
  156. package/docs/glossary.md +21 -1
  157. package/docs/installation-and-lifecycle.md +1 -1
  158. package/docs/middleware-and-components.md +1 -1
  159. package/docs/model-catalog.md +1 -1
  160. package/docs/observability.md +54 -3
  161. package/docs/proactive-memory.md +127 -14
  162. package/docs/prompt-envelope-and-tools.md +22 -2
  163. package/docs/provider-adapter-cookbook.md +1 -1
  164. package/docs/release-cut-checklist.md +60 -41
  165. package/docs/safety-model.md +1 -1
  166. package/docs/scientific-validation.md +1 -1
  167. package/docs/skills-marketplace.md +1 -1
  168. package/docs/tool-usage.md +1 -1
  169. package/docs/trace-store.md +1 -1
  170. package/docs/troubleshooting.md +87 -0
  171. package/docs/tui-design.md +1 -1
  172. package/docs/worker-dispatch-mechanics.md +1 -1
  173. package/package.json +2 -2
  174. package/src/cli/agents.ts +1 -1
  175. package/src/cli/argv.ts +5 -0
  176. package/src/cli/config-inspect.ts +33 -6
  177. package/src/cli/config.ts +1 -1
  178. package/src/cli/configure.ts +107 -23
  179. package/src/cli/doctor-state-size.ts +82 -0
  180. package/src/cli/doctor.ts +7 -1
  181. package/src/cli/eval.ts +80 -16
  182. package/src/cli/evidence.ts +30 -25
  183. package/src/cli/extensions.ts +5 -1
  184. package/src/cli/fleet-preflight.ts +2 -12
  185. package/src/cli/fleet.ts +32 -3
  186. package/src/cli/shared.ts +1 -0
  187. package/src/cli/targets.ts +45 -11
  188. package/src/cli/trace.ts +63 -4
  189. package/src/cli/usage.ts +63 -14
  190. package/src/cli/validate-model.ts +60 -5
  191. package/src/core/bus-events.ts +54 -1
  192. package/src/core/cache-telemetry.ts +42 -0
  193. package/src/core/commit-attribution.ts +4 -4
  194. package/src/core/config.ts +18 -0
  195. package/src/core/defaults.ts +36 -6
  196. package/src/core/endpoint-key.ts +27 -0
  197. package/src/core/path-boundary.ts +100 -0
  198. package/src/core/residency-target-key.ts +25 -0
  199. package/src/core/response-schema.ts +36 -2
  200. package/src/domains/agents/extension.ts +2 -11
  201. package/src/domains/agents/fleet-contract.ts +30 -12
  202. package/src/domains/agents/recipe.ts +7 -1
  203. package/src/domains/agents/registry.ts +73 -5
  204. package/src/domains/agents/result-contract.ts +128 -17
  205. package/src/domains/agents/write-boundary.ts +15 -50
  206. package/src/domains/config/classify.ts +3 -0
  207. package/src/domains/context/codewiki/coordinator.ts +12 -4
  208. package/src/domains/context/project-rules.ts +51 -1
  209. package/src/domains/dispatch/admission.ts +40 -3
  210. package/src/domains/dispatch/assignment-reconcile.ts +22 -5
  211. package/src/domains/dispatch/assignment-store.ts +151 -14
  212. package/src/domains/dispatch/capacity-lease.ts +98 -9
  213. package/src/domains/dispatch/contract.ts +26 -1
  214. package/src/domains/dispatch/delegation-plan.ts +2 -5
  215. package/src/domains/dispatch/execution-plan.ts +44 -4
  216. package/src/domains/dispatch/execution-role.ts +9 -1
  217. package/src/domains/dispatch/extension.ts +309 -96
  218. package/src/domains/dispatch/fleet-run.ts +78 -4
  219. package/src/domains/dispatch/gate-role-prompts.ts +38 -0
  220. package/src/domains/dispatch/heartbeat.ts +32 -8
  221. package/src/domains/dispatch/index.ts +6 -1
  222. package/src/domains/dispatch/intent-requirements.ts +40 -0
  223. package/src/domains/dispatch/intent.ts +84 -8
  224. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  225. package/src/domains/dispatch/path-scope.ts +370 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +2 -1
  227. package/src/domains/dispatch/reservation-store.ts +116 -8
  228. package/src/domains/dispatch/state.ts +4 -0
  229. package/src/domains/dispatch/types.ts +14 -7
  230. package/src/domains/dispatch/validation.ts +6 -3
  231. package/src/domains/dispatch/worker-spawn.ts +25 -11
  232. package/src/domains/dispatch/write-boundary-enforcer.ts +62 -0
  233. package/src/domains/dispatch/write-boundary.ts +262 -22
  234. package/src/domains/eval/artifacts/store.ts +62 -0
  235. package/src/domains/eval/compare/behavioral.ts +224 -0
  236. package/src/domains/eval/compare/compare.ts +355 -2
  237. package/src/domains/eval/compare/envelope.ts +128 -0
  238. package/src/domains/eval/compare/gates.ts +24 -6
  239. package/src/domains/eval/compare/thresholds.ts +30 -3
  240. package/src/domains/eval/execution-provenance.ts +240 -0
  241. package/src/domains/eval/metrics/aggregate.ts +136 -0
  242. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  243. package/src/domains/eval/metrics/evidence.ts +79 -2
  244. package/src/domains/eval/metrics/tracked.ts +413 -0
  245. package/src/domains/eval/provenance.ts +117 -0
  246. package/src/domains/eval/reports/comparison.ts +128 -0
  247. package/src/domains/eval/reports/junit.ts +17 -3
  248. package/src/domains/eval/reports/markdown.ts +3 -3
  249. package/src/domains/eval/reports/text.ts +14 -0
  250. package/src/domains/eval/run-compare.ts +20 -0
  251. package/src/domains/eval/runners/clio-run.ts +139 -2
  252. package/src/domains/eval/runners/external-command.ts +28 -3
  253. package/src/domains/eval/schema/adapter.ts +111 -0
  254. package/src/domains/eval/schema/artifact.ts +20 -0
  255. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  256. package/src/domains/eval/schema/behavioral.ts +520 -0
  257. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  258. package/src/domains/eval/schema/serving.ts +74 -0
  259. package/src/domains/eval/schema/suite.ts +38 -8
  260. package/src/domains/eval/schema/validate.ts +58 -3
  261. package/src/domains/eval/schema/verdict.ts +237 -0
  262. package/src/domains/eval/suites/resolve.ts +2 -0
  263. package/src/domains/eval/suites/run.ts +264 -33
  264. package/src/domains/eval/verifiers/command.ts +2 -1
  265. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  266. package/src/domains/evidence/build.ts +68 -21
  267. package/src/domains/evidence/eval.ts +2 -12
  268. package/src/domains/evidence/findings-markdown.ts +33 -0
  269. package/src/domains/evidence/index.ts +21 -0
  270. package/src/domains/evidence/provenance.ts +46 -11
  271. package/src/domains/evidence/run-trust.ts +7 -113
  272. package/src/domains/evidence/trust-projection.ts +274 -0
  273. package/src/domains/evidence/trust-status.ts +145 -17
  274. package/src/domains/evidence/types.ts +4 -0
  275. package/src/domains/extensions/compatibility.ts +285 -0
  276. package/src/domains/extensions/discovery.ts +126 -4
  277. package/src/domains/extensions/resources.ts +21 -9
  278. package/src/domains/extensions/state.ts +18 -5
  279. package/src/domains/extensions/types.ts +6 -1
  280. package/src/domains/lifecycle/doctor.ts +209 -2
  281. package/src/domains/memory/index.ts +14 -0
  282. package/src/domains/memory/task-bank-promotion.ts +64 -0
  283. package/src/domains/memory/task-memory-policy.ts +77 -8
  284. package/src/domains/memory/task-memory-spend.ts +131 -0
  285. package/src/domains/memory/task-memory-status.ts +7 -0
  286. package/src/domains/memory/task-memory-telemetry.ts +2 -0
  287. package/src/domains/middleware/index.ts +1 -0
  288. package/src/domains/middleware/memory-intervention.ts +69 -5
  289. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  290. package/src/domains/observability/background-memory-usage.ts +140 -0
  291. package/src/domains/observability/cost.ts +1 -1
  292. package/src/domains/observability/index.ts +7 -0
  293. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  294. package/src/domains/observability/trace-store.ts +192 -2
  295. package/src/domains/prompts/compiler.ts +100 -13
  296. package/src/domains/prompts/contract.ts +3 -5
  297. package/src/domains/providers/endpoint-capacity.ts +96 -0
  298. package/src/domains/providers/extension.ts +30 -2
  299. package/src/domains/providers/index.ts +10 -0
  300. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  301. package/src/domains/providers/runtime-resolution.ts +8 -1
  302. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  303. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  304. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  305. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  306. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  307. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  308. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  309. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  310. package/src/domains/providers/types/capability-flags.ts +2 -0
  311. package/src/domains/providers/types/target-descriptor.ts +2 -0
  312. package/src/domains/resources/common-loader.ts +3 -0
  313. package/src/domains/resources/prompts/loader.ts +184 -17
  314. package/src/domains/safety/call-target.ts +52 -0
  315. package/src/domains/safety/policy-engine.ts +5 -5
  316. package/src/domains/safety/run-effects.ts +96 -2
  317. package/src/domains/safety/scope.ts +7 -12
  318. package/src/domains/session/context-accounting.ts +52 -1
  319. package/src/domains/session/context-ledger.ts +37 -13
  320. package/src/domains/session/index.ts +6 -0
  321. package/src/domains/session/prompt-cache.ts +140 -0
  322. package/src/domains/session/prompt-manifest.ts +42 -0
  323. package/src/engine/acp/adapter.ts +18 -3
  324. package/src/engine/acp/server.ts +4 -1
  325. package/src/engine/ai.ts +35 -0
  326. package/src/engine/apis/llamacpp-residency.ts +55 -3
  327. package/src/engine/apis/lmstudio.ts +25 -5
  328. package/src/engine/apis/ollama-native.ts +2 -1
  329. package/src/engine/apis/openai-completions.ts +80 -17
  330. package/src/engine/apis/residency-lock.ts +3 -1
  331. package/src/engine/apis/residency.ts +34 -1
  332. package/src/engine/prompt-templates.ts +18 -1
  333. package/src/engine/provider-payload.ts +29 -1
  334. package/src/engine/worker-runtime.ts +6 -3
  335. package/src/entry/orchestrator.ts +176 -30
  336. package/src/interactive/chat-loop-messages.ts +26 -7
  337. package/src/interactive/chat-loop.ts +318 -41
  338. package/src/interactive/chat-panel.ts +62 -8
  339. package/src/interactive/clio-editor.ts +45 -8
  340. package/src/interactive/context-activity.ts +5 -1
  341. package/src/interactive/context-meter.ts +1 -1
  342. package/src/interactive/context-overlay.ts +40 -10
  343. package/src/interactive/cost-overlay.ts +64 -6
  344. package/src/interactive/dispatch-board.ts +127 -5
  345. package/src/interactive/fleet-run-preview.ts +41 -15
  346. package/src/interactive/handoff-round.ts +41 -2
  347. package/src/interactive/interactive-application.ts +24 -1
  348. package/src/interactive/interactive-event-projection.ts +14 -0
  349. package/src/interactive/interactive-input-runtime.ts +8 -0
  350. package/src/interactive/interactive-presentation.ts +4 -0
  351. package/src/interactive/interactive-shell.ts +20 -17
  352. package/src/interactive/interactive-slash-runtime.ts +27 -4
  353. package/src/interactive/memory-overlay.ts +8 -0
  354. package/src/interactive/mutation-preview.ts +295 -0
  355. package/src/interactive/overlay-general-openers.ts +16 -0
  356. package/src/interactive/overlay-key-routing.ts +38 -0
  357. package/src/interactive/overlay-lifecycle.ts +38 -5
  358. package/src/interactive/overlay-permission-lifecycle.ts +22 -2
  359. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  360. package/src/interactive/overlays/ask-user.ts +91 -19
  361. package/src/interactive/overlays/help-reference.ts +4 -0
  362. package/src/interactive/overlays/prompts.ts +11 -1
  363. package/src/interactive/overlays/settings.ts +176 -48
  364. package/src/interactive/permission-hint.ts +34 -2
  365. package/src/interactive/permission-overlay.ts +159 -9
  366. package/src/interactive/prewarm.ts +197 -0
  367. package/src/interactive/render-trace.ts +162 -15
  368. package/src/interactive/renderers/tool-execution.ts +4 -0
  369. package/src/interactive/side-question.ts +58 -1
  370. package/src/interactive/slash-commands.ts +7 -2
  371. package/src/interactive/status/controller.ts +11 -0
  372. package/src/interactive/status/state-machine.ts +54 -2
  373. package/src/interactive/status/types.ts +7 -0
  374. package/src/interactive/terminal-lease.ts +2 -0
  375. package/src/interactive/turn-context.ts +299 -31
  376. package/src/interactive/turn-persistence.ts +14 -4
  377. package/src/interactive/turn-prewarm.ts +364 -0
  378. package/src/interactive/turn-queues.ts +7 -4
  379. package/src/interactive/turn-runtime.ts +8 -1
  380. package/src/interactive/turn-state.ts +23 -0
  381. package/src/interactive/view/artifacts.ts +42 -9
  382. package/src/interactive/view/view-overlay.ts +43 -6
  383. package/src/interactive/worker-receipts.ts +14 -2
  384. package/src/interactive/worker-stream.ts +8 -0
  385. package/src/tools/ask-user.ts +43 -2
  386. package/src/tools/dispatch-admission.ts +12 -13
  387. package/src/tools/dispatch-arguments.ts +27 -0
  388. package/src/tools/dispatch-plan.ts +46 -9
  389. package/src/tools/dispatch-runner.ts +48 -13
  390. package/src/tools/dispatch-scout.ts +1 -1
  391. package/src/tools/monitor.ts +13 -0
  392. package/src/tools/registry.ts +16 -0
  393. package/src/tools/worker-evidence.ts +19 -13
  394. package/src/worker/spec-contract.ts +2 -1
  395. package/dist/chunk-AOCYTWAV.js +0 -449
  396. package/dist/chunk-HWUFFB6L.js +0 -83
  397. package/dist/chunk-R346GLFC.js +0 -31
  398. package/dist/chunk-ZGH7FGS5.js +0 -1079
  399. package/dist/doctor-RN4YKO2X.js +0 -87
  400. package/dist/eval-RUBJVSNQ.js +0 -2557
@@ -16,6 +16,8 @@
16
16
  import { existsSync, readFileSync } from "node:fs";
17
17
  import { join } from "node:path";
18
18
  import { clioStateDir } from "../core/xdg.js";
19
+ import type { RunEnvelope, RunReceipt } from "../domains/dispatch/types.js";
20
+ import { inspectRunReceiptTrustStatus } from "../domains/evidence/trust-status.js";
19
21
  import { receiptFilePath } from "./view/artifacts.js";
20
22
  import type { WorkerReceiptFacts, WorkerResultContract } from "./worker-stream.js";
21
23
 
@@ -86,12 +88,22 @@ export function workerReceiptFacts(receipt: Record<string, unknown>): WorkerRece
86
88
 
87
89
  /** Read and project `<state>/receipts/<runId>.json` alone; null when it is absent or unreadable. */
88
90
  function readReceiptFileFacts(runId: string, stateDir: string): WorkerReceiptFacts | null {
91
+ let parsed: unknown;
89
92
  try {
90
- const parsed: unknown = JSON.parse(readFileSync(receiptFilePath(stateDir, runId), "utf8"));
91
- return isRecord(parsed) ? workerReceiptFacts(parsed) : null;
93
+ parsed = JSON.parse(readFileSync(receiptFilePath(stateDir, runId), "utf8"));
92
94
  } catch {
93
95
  return null;
94
96
  }
97
+ if (!isRecord(parsed)) return null;
98
+ const facts = workerReceiptFacts(parsed);
99
+ if (facts === null) return null;
100
+ // The trust verdict is an authenticated read-back: the receipt file
101
+ // against the ledger row it was sealed from. Without the row there is no
102
+ // authentication, and no verdict is better than a guessed one.
103
+ const row = findRunRow(runId, stateDir);
104
+ if (row === null) return facts;
105
+ const trust = inspectRunReceiptTrustStatus(parsed as unknown as RunReceipt, row as unknown as RunEnvelope).status;
106
+ return { ...facts, trust };
95
107
  }
96
108
 
97
109
  /** Read and project `<state>/receipts/<runId>.json`; null when it is absent or unreadable. */
@@ -42,6 +42,7 @@ import type {
42
42
  RunAbortedPayload,
43
43
  } from "../core/bus-events.js";
44
44
  import type { RunKind } from "../domains/dispatch/types.js";
45
+ import type { CanonicalTrustStatus } from "../domains/evidence/trust-status.js";
45
46
  import type { WorkerRunOrigin, WorkerRunRuntime, WorkerRunRuntimeKind } from "../domains/session/index.js";
46
47
  import { createWorkerProgressFold, type WorkerProgressFold, type WorkerProgressSnapshot } from "./worker-progress.js";
47
48
 
@@ -88,6 +89,13 @@ export interface WorkerReceiptSummary {
88
89
  /** A receipt's projection: the summary plus the answer it sealed. */
89
90
  export interface WorkerReceiptFacts extends WorkerReceiptSummary {
90
91
  text?: string;
92
+ /**
93
+ * The canonical trust status of the persisted receipt, authenticated
94
+ * against the persisted ledger row it was sealed from. Present only when
95
+ * both could be read back, so a surface that shows it shows an
96
+ * authenticated verdict and never the sealing process's own claim.
97
+ */
98
+ trust?: CanonicalTrustStatus;
91
99
  }
92
100
 
93
101
  /** Reads `receipts/<runId>.json` and projects it; null when it is absent or unreadable. */
@@ -40,13 +40,27 @@ export interface AskUserQuestion {
40
40
 
41
41
  export interface AskUserAnswer {
42
42
  question: string;
43
+ /** The whole answer on one line: the chosen labels, then the typed text. */
43
44
  answer: string;
45
+ /**
46
+ * The option labels the operator chose, in list order. Absent when they only
47
+ * typed. Present with no {@link value} is a label-only answer, which is how a
48
+ * reader tells "they picked the option" from "they picked it and typed a
49
+ * figure" (issue #228).
50
+ */
51
+ options?: string[];
52
+ /** The operator's typed text, exactly as submitted. Absent when they only chose. */
53
+ value?: string;
44
54
  }
45
55
 
46
56
  export interface AskUserDecision {
47
57
  key: string;
48
58
  value: string;
49
59
  label?: string;
60
+ /** The chosen labels behind `value`; derived by the harness, not model-supplied. */
61
+ options?: string[];
62
+ /** The typed text behind `value`; derived by the harness, not model-supplied. */
63
+ text?: string;
50
64
  /** Question that produced this decision; derived by the harness, not model-supplied. */
51
65
  source_question?: string;
52
66
  }
@@ -299,6 +313,13 @@ export function cancelledAskUserResult(): AskUserResult {
299
313
  return { answers: [], cancelled: true };
300
314
  }
301
315
 
316
+ /** The chosen labels, dropped when the surface supplied nothing usable. */
317
+ function normalizeAnswerOptions(value: unknown): string[] | undefined {
318
+ if (!Array.isArray(value)) return undefined;
319
+ const labels = value.filter((entry): entry is string => typeof entry === "string" && entry.trim().length > 0);
320
+ return labels.length > 0 ? labels : undefined;
321
+ }
322
+
302
323
  function normalizeAskUserResult(questions: ReadonlyArray<AskUserQuestion>, result: AskUserResult): AskUserResult {
303
324
  if (result.cancelled === true) return cancelledAskUserResult();
304
325
  const answers: AskUserAnswer[] = [];
@@ -308,7 +329,18 @@ function normalizeAskUserResult(questions: ReadonlyArray<AskUserQuestion>, resul
308
329
  if (!raw) continue;
309
330
  const question = typeof raw.question === "string" && raw.question.trim().length > 0 ? raw.question : fallbackQuestion;
310
331
  const answer = typeof raw.answer === "string" ? raw.answer.trim() : "";
311
- if (question.length > 0 && answer.length > 0) answers.push({ question, answer });
332
+ if (question.length === 0 || answer.length === 0) continue;
333
+ // The typed text keeps every byte the operator submitted. The one-line
334
+ // `answer` is a rendering of the same decision and is trimmed like any
335
+ // other display string; `value` is the record.
336
+ const options = normalizeAnswerOptions(raw.options);
337
+ const value = typeof raw.value === "string" && raw.value.length > 0 ? raw.value : undefined;
338
+ answers.push({
339
+ question,
340
+ answer,
341
+ ...(options ? { options } : {}),
342
+ ...(value !== undefined ? { value } : {}),
343
+ });
312
344
  }
313
345
  return { answers };
314
346
  }
@@ -363,7 +395,12 @@ function transcriptQuestions(questions: ReadonlyArray<AskUserQuestion>): AskUser
363
395
  }
364
396
 
365
397
  function transcriptAnswers(answers: ReadonlyArray<AskUserAnswer>): AskUserTranscriptAnswer[] {
366
- return answers.map((answer) => ({ question: answer.question, answer: answer.answer }));
398
+ return answers.map((answer) => ({
399
+ question: answer.question,
400
+ answer: answer.answer,
401
+ ...(answer.options && answer.options.length > 0 ? { options: [...answer.options] } : {}),
402
+ ...(answer.value !== undefined ? { value: answer.value } : {}),
403
+ }));
367
404
  }
368
405
 
369
406
  function toDecisionKey(value: string): string {
@@ -397,6 +434,8 @@ function decisionFromAnswer(
397
434
  key,
398
435
  value: answer.answer,
399
436
  ...(label ? { label } : {}),
437
+ ...(answer.options && answer.options.length > 0 ? { options: [...answer.options] } : {}),
438
+ ...(answer.value !== undefined ? { text: answer.value } : {}),
400
439
  source_question: answer.question,
401
440
  };
402
441
  }
@@ -406,6 +445,8 @@ function toTranscriptDecision(decision: AskUserDecision): AskUserTranscriptDecis
406
445
  key: toDecisionKey(decision.key),
407
446
  value: decision.value,
408
447
  ...(decision.label ? { label: decision.label } : {}),
448
+ ...(decision.options && decision.options.length > 0 ? { options: [...decision.options] } : {}),
449
+ ...(decision.text !== undefined ? { text: decision.text } : {}),
409
450
  ...(decision.source_question ? { source_question: decision.source_question } : {}),
410
451
  };
411
452
  }
@@ -6,8 +6,10 @@ import {
6
6
  COUNCIL_JUDGE_PROMPT,
7
7
  JUDGE_GATE_PROMPT,
8
8
  REVIEWER_GATE_PROMPT,
9
+ renderCouncilVoteMemberTask,
9
10
  } from "../domains/dispatch/gate-role-prompts.js";
10
11
  import { normalizeDispatchIntent } from "../domains/dispatch/intent.js";
12
+ import { renderDispatchReviewerTask } from "../domains/dispatch/intent-requirements.js";
11
13
  import { approvedRouteCandidates } from "../domains/dispatch/route-approval.js";
12
14
  import { defaultRoutingIntent } from "../domains/dispatch/routing-intent.js";
13
15
  import type { DispatchFailoverMode } from "../domains/dispatch/validation.js";
@@ -139,15 +141,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
139
141
  return typeof value === "object" && value !== null && !Array.isArray(value);
140
142
  }
141
143
 
142
- function reviewerTask(originalTask: string, builderRunId: string, cycle: number): string {
143
- return [
144
- `Review the work of builder run ${builderRunId} (review cycle ${cycle}).`,
145
- "The builder's final answer is provided as input data; verify it against the workspace, do not trust it blindly.",
146
- "Original task the builder was given:",
147
- originalTask,
148
- ].join("\n\n");
149
- }
150
-
151
144
  function reviewSettingsFromArgs(
152
145
  args: Record<string, unknown>,
153
146
  ): { ok: true; review: DispatchReviewSettings | undefined } | { ok: false; message: string } {
@@ -534,9 +527,6 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
534
527
  if (parsed.requests.length !== 1 || parsed.requests[0] === undefined) {
535
528
  return shapeRejection(args, REVIEW_SINGLE_TASK_MESSAGE);
536
529
  }
537
- if (parsed.requests.some((request) => (request.resolvedVerification?.length ?? 0) > 0)) {
538
- return shapeRejection(args, "verification_unsupported_for_mode: review requests cannot run host verification");
539
- }
540
530
  }
541
531
  if (mode === "compete" && (parsed.requests.length !== 1 || parsed.requests[0] === undefined)) {
542
532
  return shapeRejection(args, COMPETE_SINGLE_TASK_MESSAGE);
@@ -587,7 +577,7 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
587
577
  {
588
578
  agentId: gateDeciderAgentId(reviewResult.review.reviewer),
589
579
  executionRole: "reviewer",
590
- task: reviewerTask(base.task, subject.runId, cycle),
580
+ task: renderDispatchReviewerTask(base.task, subject.runId, cycle, base.intent),
591
581
  systemPrompt: REVIEWER_GATE_PROMPT,
592
582
  autonomy: "read-only",
593
583
  gate: { role: "reviewer", group: "plan-preview", cycle, subjects: [subject] },
@@ -648,6 +638,15 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
648
638
  executionRole: "researcher",
649
639
  autonomy: "read-only",
650
640
  toolProfile: "council-read-only",
641
+ // The runner reuses this composed task from the resolved plan, so
642
+ // the approval artifact the plan hash binds shows the operator the
643
+ // exact ballot the member is asked to cast.
644
+ ...(council.synthesis === "vote"
645
+ ? {
646
+ task: renderCouncilVoteMemberTask(base.task),
647
+ resultContractOverride: { kind: "council-ballot" as const },
648
+ }
649
+ : {}),
651
650
  target: member.target,
652
651
  ...(member.model ? { model: member.model } : {}),
653
652
  ...(member.thinking ? { thinkingLevel: member.thinking as NonNullable<DispatchRequest["thinkingLevel"]> } : {}),
@@ -1,5 +1,6 @@
1
1
  /** Pure model-argument parsing; every returned DispatchRequest has a concrete agent id. */
2
2
 
3
+ import { pathBoundaryCovers } from "../core/path-boundary.js";
3
4
  import type { AgentAutomationAuthority } from "../domains/agents/spec.js";
4
5
  import { type AgentTaskType, classifyAgentTask } from "../domains/dispatch/agent-candidates.js";
5
6
  import { cloneDispatchBudgetRequest } from "../domains/dispatch/budget-envelope.js";
@@ -261,8 +262,34 @@ export function dispatchRequestsFromArgs(
261
262
  for (let index = 0; index < tasks.length; index += 1) {
262
263
  const item = tasks[index];
263
264
  const itemArgs: Record<string, unknown> = isRecord(item) ? { ...shared, ...item } : { ...shared, task: item };
265
+ const sharedIntent = isRecord(shared.intent) ? shared.intent : null;
266
+ const itemIntent = isRecord(item) && Object.hasOwn(item, "intent") && isRecord(item.intent) ? item.intent : null;
267
+ if (sharedIntent !== null && itemIntent !== null) itemArgs.intent = { ...sharedIntent, ...itemIntent };
264
268
  const parsed = dispatchRequestFromArgs(itemArgs, options);
265
269
  if (!parsed.ok) return { ok: false, message: `dispatch: task ${index + 1}: ${parsed.message}` };
270
+ if (sharedIntent !== null && itemIntent !== null) {
271
+ if (options.resolveIntent === undefined) {
272
+ return { ok: false, message: `dispatch: task ${index + 1}: intent resolver is unavailable` };
273
+ }
274
+ const ceiling = options.resolveIntent(sharedIntent, parsed.request.cwd);
275
+ if (!ceiling.ok) return { ok: false, message: `dispatch: task ${index + 1}: ${ceiling.message}` };
276
+ const pathCeilings = {
277
+ readRoots: [...ceiling.intent.readRoots, ...ceiling.intent.writeRoots],
278
+ writeRoots: ceiling.intent.writeRoots,
279
+ relevantPaths: [...ceiling.intent.readRoots, ...ceiling.intent.writeRoots, ...ceiling.intent.relevantPaths],
280
+ };
281
+ for (const field of ["readRoots", "writeRoots", "relevantPaths"] as const) {
282
+ const outside = parsed.request.intent?.[field].find(
283
+ (candidate) => !pathBoundaryCovers(pathCeilings[field], candidate),
284
+ );
285
+ if (outside !== undefined) {
286
+ return {
287
+ ok: false,
288
+ message: `dispatch: task ${index + 1}: intent_scope_widening: ${field} entry '${outside}' is outside the top-level intent ceiling`,
289
+ };
290
+ }
291
+ }
292
+ }
266
293
  requests.push(parsed.request);
267
294
  }
268
295
  return { ok: true, requests };
@@ -21,6 +21,7 @@ import { AGENT_AUTOMATION_AUTHORITIES, type AgentAutomationAuthority } from "../
21
21
  import type { DispatchRequest } from "../domains/dispatch/contract.js";
22
22
  import { type ExecutionRole, isExecutionRole } from "../domains/dispatch/execution-role.js";
23
23
  import { type DispatchIntent, isDispatchIntent } from "../domains/dispatch/intent.js";
24
+ import { resolveDispatchPathScope } from "../domains/dispatch/path-scope.js";
24
25
  import {
25
26
  type ApprovedAssignmentRoute,
26
27
  cloneApprovedAssignmentRoute,
@@ -235,15 +236,46 @@ function str(value: unknown): string | undefined {
235
236
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
236
237
  }
237
238
 
238
- /** Keep terminal control bytes and line breaks out of approval artifacts. */
239
- function safeField(value: string): string {
239
+ /** Keep terminal control bytes and line breaks out of approval artifacts without losing their identity. */
240
+ function safeField(value: string, bindChangedValue = true): string {
240
241
  let result = "";
241
242
  for (const character of value) {
242
243
  const code = character.codePointAt(0) ?? 0;
243
244
  result += code < 32 || (code >= 127 && code <= 159) ? "?" : character;
244
- if (result.length >= 256) return `${result.slice(0, 255)}…`;
245
+ if (result.length >= 256) {
246
+ result = `${result.slice(0, 255)}…`;
247
+ break;
248
+ }
249
+ }
250
+ if (!bindChangedValue || result === value) return result;
251
+ return `${result}{sha256=${createHash("sha256").update(value, "utf8").digest("hex")}}`;
252
+ }
253
+
254
+ function renderLegacyPathScope(task: DispatchPlanTaskView): string[] {
255
+ if (task.intent !== undefined) return [];
256
+ const scope = resolveDispatchPathScope({
257
+ agentId: task.agent,
258
+ executionRole: task.executionRole,
259
+ task: task.task,
260
+ ...(task.briefing !== undefined ? { briefing: task.briefing } : {}),
261
+ });
262
+ const lines = [" scope mode=legacy-inferred"];
263
+ for (const [policy, entries] of [
264
+ ["working_context", scope.provenance.workingContextPaths],
265
+ ["write_boundary", scope.provenance.writeBoundaries],
266
+ ] as const) {
267
+ for (const entry of entries) {
268
+ for (const evidence of entry.evidence) {
269
+ lines.push(
270
+ ` scope ${policy} path=${JSON.stringify(safeField(entry.path))} provenance=${evidence.provenance} source=${evidence.source} confidence=${evidence.confidence} reason=${evidence.reason}`,
271
+ );
272
+ }
273
+ }
274
+ }
275
+ if (scope.provenance.workingContextPaths.length === 0 && scope.provenance.writeBoundaries.length === 0) {
276
+ lines.push(" scope policy_paths=none");
245
277
  }
246
- return result;
278
+ return lines;
247
279
  }
248
280
 
249
281
  function taskViews(args: Record<string, unknown>): DispatchPlanTaskView[] {
@@ -365,7 +397,7 @@ function renderPlanText(
365
397
  ? ""
366
398
  : ` posture=${routing.posture} maxCostUsd=${routing.maxCostUsd ?? "none"} deadlineMs=${routing.deadlineMs ?? "none"} minimumQuality=${routing.minimumQuality ?? "none"} locality=${routing.locality}`;
367
399
  lines.push(
368
- ` ${index + 1}.${role} agent=${safeField(task.agent)}${target}${model}${node}${failover}${routingText} task=${JSON.stringify(safeField(task.task))}`,
400
+ ` ${index + 1}.${role} agent=${safeField(task.agent)}${target}${model}${node}${failover}${routingText} task_bytes=${Buffer.byteLength(task.task, "utf8")} task_sha256=${createHash("sha256").update(task.task, "utf8").digest("hex")} task_preview=${JSON.stringify(safeField(task.task, false))}`,
369
401
  );
370
402
  if (task.council !== undefined) {
371
403
  lines.push(
@@ -392,31 +424,36 @@ function renderPlanText(
392
424
  }
393
425
  if (task.agentSelection !== null) {
394
426
  lines.push(
395
- ` agent-selection=auto baseline=${safeField(task.agentSelection.baselineAgentId)} authority=${task.agentSelection.approvedAuthorities.map(safeField).join(",")} basis=${task.agentSelection.authorityBasis}`,
427
+ ` agent-selection=auto baseline=${safeField(task.agentSelection.baselineAgentId)} authority=${task.agentSelection.approvedAuthorities.map((authority) => safeField(authority)).join(",")} basis=${task.agentSelection.authorityBasis}`,
396
428
  );
397
429
  }
398
430
  if (task.stepId !== null) {
399
431
  lines.push(
400
- ` step=${safeField(task.stepId)} wave=${task.wave ?? "?"} role=${task.executionRole} dependencies=${task.dependencies.map(safeField).join(",") || "none"} result=${task.expectedResultContract ?? "none"} authority=${task.authorityGrant?.requested ?? "none"} basis=${task.authorityGrant?.basis ?? "none"}`,
432
+ ` step=${safeField(task.stepId)} wave=${task.wave ?? "?"} role=${task.executionRole} dependencies=${task.dependencies.map((dependency) => safeField(dependency)).join(",") || "none"} result=${task.expectedResultContract ?? "none"} authority=${task.authorityGrant?.requested ?? "none"} basis=${task.authorityGrant?.basis ?? "none"}`,
401
433
  );
402
434
  const agentReasons = task.agentDecision?.agentSelection.evaluations
403
435
  .filter((evaluation) => evaluation.rejections.length > 0)
404
436
  .slice(0, 8)
405
437
  .map(
406
- (evaluation) => `${safeField(evaluation.agentId)}:${evaluation.rejections.slice(0, 4).map(safeField).join(",")}`,
438
+ (evaluation) =>
439
+ `${safeField(evaluation.agentId)}:${evaluation.rejections
440
+ .slice(0, 4)
441
+ .map((rejection) => safeField(rejection))
442
+ .join(",")}`,
407
443
  );
408
444
  if (agentReasons !== undefined && agentReasons.length > 0)
409
445
  lines.push(` agent-exclusions=${agentReasons.join(";")}`);
410
446
  }
411
447
  if (task.briefing !== undefined) {
412
448
  lines.push(
413
- ` briefing_bytes=${Buffer.byteLength(task.briefing, "utf8")} briefing_sha256=${createHash("sha256").update(task.briefing, "utf8").digest("hex")} briefing_preview=${JSON.stringify(safeField(task.briefing))}`,
449
+ ` briefing_bytes=${Buffer.byteLength(task.briefing, "utf8")} briefing_sha256=${createHash("sha256").update(task.briefing, "utf8").digest("hex")} briefing_preview=${JSON.stringify(safeField(task.briefing, false))}`,
414
450
  );
415
451
  }
416
452
  if (task.intent !== undefined) {
417
453
  const serialized = JSON.stringify(task.intent);
418
454
  lines.push(` intent_sha256=${createHash("sha256").update(serialized, "utf8").digest("hex")}`);
419
455
  }
456
+ lines.push(...renderLegacyPathScope(task));
420
457
  for (const check of task.resolvedVerification ?? []) {
421
458
  lines.push(
422
459
  ` verification check=${safeField(check.check)} argv=${JSON.stringify(check.argv)} cwd=${JSON.stringify(check.cwd)} timeout_ms=${check.timeoutMs}`,
@@ -38,12 +38,15 @@ import {
38
38
  type CompeteStance,
39
39
  JUDGE_GATE_PROMPT,
40
40
  REVIEWER_GATE_PROMPT,
41
+ renderCouncilVoteMemberTask,
41
42
  } from "../domains/dispatch/gate-role-prompts.js";
43
+ import { renderDispatchReviewerTask } from "../domains/dispatch/intent-requirements.js";
42
44
  import { UNVERIFIABLE_RECEIPT_VERIFICATION } from "../domains/dispatch/receipt-findings.js";
43
45
  import { type ReceiptIntegrityResult, verifyReceiptIntegrity } from "../domains/dispatch/receipt-integrity.js";
44
46
  import { explainRouteDecision } from "../domains/dispatch/routing-intent.js";
45
47
  import type { RunGateProvenance, RunGateSubjectRef, RunPlanProvenance, RunReceipt } from "../domains/dispatch/types.js";
46
48
  import { extractRunProvenance, provenanceCompactSuffix } from "../domains/evidence/provenance.js";
49
+ import { summarizeTrustStatus } from "../domains/evidence/trust-projection.js";
47
50
  import { adaptRunReceiptTrustStatus } from "../domains/evidence/trust-status.js";
48
51
  import type { AutonomyLevel } from "../domains/safety/autonomy.js";
49
52
  import {
@@ -580,6 +583,10 @@ function dispatchDetails(
580
583
  hostVerification: integrity.ok ? (receipt.hostVerification ?? null) : null,
581
584
  receiptIntegrity: integrity,
582
585
  trustStatus,
586
+ // The bounded projection sits shallow and flat on purpose: a
587
+ // depth-capped wire (ACP rawOutput) keeps it whole while the
588
+ // canonical status's nested references fall off the end.
589
+ trust: summarizeTrustStatus(trustStatus),
583
590
  ...(receipt.outcome !== undefined && receipt.outcome !== "succeeded"
584
591
  ? { outcome: receipt.outcome, outcomeDetail: receipt.outcomeDetail ?? null }
585
592
  : {}),
@@ -632,15 +639,6 @@ function competeCorrelation(
632
639
  return gateCorrelationOf(subject, decider);
633
640
  }
634
641
 
635
- function reviewerTask(originalTask: string, builderRunId: string, cycle: number): string {
636
- return [
637
- `Review the work of builder run ${builderRunId} (review cycle ${cycle}).`,
638
- "The builder's final answer is provided as input data; verify it against the workspace, do not trust it blindly.",
639
- "Original task the builder was given:",
640
- originalTask,
641
- ].join("\n\n");
642
- }
643
-
644
642
  type ReviewGateSettings = DispatchReviewSettings;
645
643
 
646
644
  const REVIEW_SINGLE_TASK_MESSAGE =
@@ -787,7 +785,7 @@ async function runReviewGated(
787
785
  const reviewerRequest: DispatchRequest = {
788
786
  agentId: gateDeciderAgentId(review.reviewer),
789
787
  executionRole: "reviewer",
790
- task: reviewerTask(base.task, builder.receipt.runId, cycle),
788
+ task: renderDispatchReviewerTask(base.task, builder.receipt.runId, cycle, base.intent),
791
789
  systemPrompt: REVIEWER_GATE_PROMPT,
792
790
  autonomy: "read-only",
793
791
  gate: { role: "reviewer", group, cycle, subjects: [subjectRef(builder.receipt)] },
@@ -1797,10 +1795,19 @@ function competeResult(
1797
1795
  const COUNCIL_BRIEFING_MAX_BYTES = 8 * 1024;
1798
1796
  const COUNCIL_BRIEFING_TRUNCATION = "\n[council peer briefing truncated]";
1799
1797
 
1798
+ /**
1799
+ * The verdict a council answer casts, lower-cased.
1800
+ *
1801
+ * A tally groups by the exact string, so folding case is the difference
1802
+ * between two members who both said yes agreeing and splitting into a
1803
+ * `no_majority` the operator has to read past. Folding happens here, at the one
1804
+ * place a verdict is ever read, so the reported member verdict and the tally
1805
+ * key can never disagree.
1806
+ */
1800
1807
  function councilVerdict(text: string): string | undefined {
1801
1808
  const parsed = parseJsonObjectPayload(text);
1802
1809
  return parsed.ok && typeof parsed.value.verdict === "string" && parsed.value.verdict.trim().length > 0
1803
- ? parsed.value.verdict.trim()
1810
+ ? parsed.value.verdict.trim().toLowerCase()
1804
1811
  : undefined;
1805
1812
  }
1806
1813
 
@@ -1866,11 +1873,32 @@ async function runCouncil(
1866
1873
  }
1867
1874
  const position = (round - 1) * council.members.length + index + 1;
1868
1875
  const pinned = council.resolvedTasks?.find((task) => task.role === "member" && task.position === position);
1876
+ let voteTask = base.task;
1877
+ if (council.synthesis === "vote") {
1878
+ if (pinned !== undefined) voteTask = pinned.task;
1879
+ else if (council.resolvedTasks !== undefined)
1880
+ throw new Error(`dispatch: resolved council plan has no member task at position ${position}`);
1881
+ else voteTask = renderCouncilVoteMemberTask(base.task);
1882
+ }
1869
1883
  const request: DispatchRequest = {
1870
1884
  ...base,
1871
1885
  executionRole: "researcher",
1872
1886
  autonomy: "read-only",
1873
1887
  toolProfile: "council-read-only",
1888
+ // A vote is a majority over the members' verdict fields, so a vote
1889
+ // council asks each member for one and seals the ballot it asked
1890
+ // for. The seated recipe is untouched: the ask is a task suffix and
1891
+ // the postcondition is an override, so the member is still the
1892
+ // agent the operator seated, and any recipe can be voted with.
1893
+ // Admission already composed the suffix into each resolved member
1894
+ // task, so reuse its exact bytes. The fallback supports dispatch
1895
+ // contracts that have no resolved admission artifact.
1896
+ ...(council.synthesis === "vote"
1897
+ ? {
1898
+ task: voteTask,
1899
+ resultContractOverride: { kind: "council-ballot" as const },
1900
+ }
1901
+ : {}),
1874
1902
  target: member.target,
1875
1903
  ...(member.model ? { model: member.model } : {}),
1876
1904
  ...(member.thinking ? { thinkingLevel: member.thinking as NonNullable<DispatchRequest["thinkingLevel"]> } : {}),
@@ -1911,7 +1939,11 @@ async function runCouncil(
1911
1939
  label: run.receipt.council?.label ?? "member",
1912
1940
  runId: run.receipt.runId,
1913
1941
  round: run.receipt.council?.round ?? 1,
1914
- answer: text,
1942
+ // A ballot's prose lives in its `text` field, so the report carries the
1943
+ // member's answer rather than its wire envelope, the same way the judge
1944
+ // line already does. A member answering any other shape has no `text`
1945
+ // key and keeps its whole answer.
1946
+ answer: councilJudgeText(text),
1915
1947
  ...(verdict !== undefined ? { verdict } : {}),
1916
1948
  ...(failed ? { failed: { reason: pipelineFailureReason(run.receipt) } } : {}),
1917
1949
  };
@@ -1967,13 +1999,16 @@ async function runCouncil(
1967
1999
  judgeRunId: judgeRun.receipt.runId,
1968
2000
  };
1969
2001
  }
1970
- if (council.synthesis !== "judge" && prior.size > 0 && deps.dispatch.sealCouncilSynthesis !== undefined) {
2002
+ if (prior.size > 0 && deps.dispatch.sealCouncilSynthesis !== undefined) {
1971
2003
  const finalRuns = [...prior.values()];
1972
2004
  const template = finalRuns[0];
1973
2005
  if (template === undefined) throw new Error("council synthesis has no final member receipt");
1974
2006
  // The sealed text is the whole council-report, not the synthesis alone:
1975
2007
  // /share <synthesis runId> reads this receipt to bring every final
1976
2008
  // member's labelled answer and the synthesis line into the main context.
2009
+ // A judge council seals it on the same terms: the judge run's own
2010
+ // receipt holds only its {"verdict","text"} payload, which carries no
2011
+ // member answers and no roster labels for the main agent to act on.
1977
2012
  const text = JSON.stringify({ members, synthesis } satisfies CouncilReport);
1978
2013
  const receipt = await deps.dispatch.sealCouncilSynthesis({
1979
2014
  group,
@@ -256,7 +256,7 @@ export async function runScoutContinuationPlan<T, S>(input: {
256
256
  };
257
257
  },
258
258
  cancel: (assignmentId) => input.dispatch.abort(assignmentId),
259
- release: (ownerId) => input.dispatch.reservations?.rollbackUnconsumed(ownerId),
259
+ release: (ownerId) => input.dispatch.reservations?.release(ownerId),
260
260
  releaseUnconsumed: (ownerId) => input.dispatch.reservations?.rollbackUnconsumed(ownerId),
261
261
  },
262
262
  input.signal,
@@ -17,6 +17,7 @@ import {
17
17
  type RunReceipt,
18
18
  type RunReceiptVerification,
19
19
  } from "../domains/dispatch/types.js";
20
+ import { summarizeTrustStatus } from "../domains/evidence/trust-projection.js";
20
21
  import {
21
22
  adaptRunReceiptTrustStatus,
22
23
  type CanonicalTrustStatus,
@@ -389,6 +390,7 @@ function runReceipt(deps: MonitorToolDeps, runId: string): ToolResult {
389
390
  receiptPath: run.receiptPath,
390
391
  receiptIntegrity,
391
392
  trustStatus,
393
+ trust: summarizeTrustStatus(trustStatus),
392
394
  ...(receipt !== null && receiptIntegrity.ok
393
395
  ? {
394
396
  evidenceVerification: receipt.verification,
@@ -455,6 +457,17 @@ function durableRunEvidence(run: RunEnvelope | null): DurableRunEvidence {
455
457
  const inspection = inspectRunReceiptTrustStatus(receipt, run);
456
458
  const integrity = inspection.integrity;
457
459
  if (!integrity.ok) {
460
+ // A retired seal is set aside unread, as a missing receipt is. It is
461
+ // not a failed one, so it never reads as tampering here either.
462
+ if (integrity.retired !== undefined) {
463
+ return {
464
+ ...unavailableRunEvidence(
465
+ integrity.reason,
466
+ `${integrity.reason}; worker text is unavailable and validation is unknown.`,
467
+ ),
468
+ trustStatus: inspection.status,
469
+ };
470
+ }
458
471
  return {
459
472
  ...unavailableRunEvidence(
460
473
  integrity.reason,
@@ -234,13 +234,29 @@ export interface AskUserTranscriptQuestion {
234
234
 
235
235
  export interface AskUserTranscriptAnswer {
236
236
  question: string;
237
+ /** The whole answer on one line: the chosen labels, then the typed text. */
237
238
  answer: string;
239
+ /**
240
+ * The option labels the operator chose, in list order. Absent when they only
241
+ * typed. Present with no {@link value} is a label-only answer.
242
+ */
243
+ options?: string[];
244
+ /**
245
+ * The operator's typed text, exactly as submitted. Absent when they only
246
+ * chose. Recording an option label without this is what lost the figures in
247
+ * issue #228.
248
+ */
249
+ value?: string;
238
250
  }
239
251
 
240
252
  export interface AskUserTranscriptDecision {
241
253
  key: string;
242
254
  value: string;
243
255
  label?: string;
256
+ /** The chosen labels behind {@link value}, when the answer had any. Harness-derived. */
257
+ options?: string[];
258
+ /** The typed text behind {@link value}, when the answer had any. Harness-derived. */
259
+ text?: string;
244
260
  source_question?: string;
245
261
  }
246
262
 
@@ -7,6 +7,7 @@ import {
7
7
  } from "../domains/dispatch/budget-envelope.js";
8
8
  import type { ReceiptIntegrityResult } from "../domains/dispatch/receipt-integrity.js";
9
9
  import type { RunReceipt, RunReceiptVerification } from "../domains/dispatch/types.js";
10
+ import { formatTrustAxes, formatTrustSummary } from "../domains/evidence/trust-projection.js";
10
11
  import { adaptRunReceiptTrustStatus, type CanonicalTrustStatus } from "../domains/evidence/trust-status.js";
11
12
  import { receiptResponseModelIdObservationLabel } from "./dispatch-event-text.js";
12
13
 
@@ -128,9 +129,9 @@ export function receiptEvidenceLabels(
128
129
  integrity: ReceiptIntegrityResult,
129
130
  ): string[] {
130
131
  const status = adaptRunReceiptTrustStatus({ ...receipt, verification: verification }, { integrity });
131
- const canonical = canonicalTrustLabel(status);
132
+ const canonical = canonicalTrustLabels(status);
132
133
  if (!integrity.ok) {
133
- return [canonical, `receipt_integrity=FAILED reason=${JSON.stringify(integrity.reason)}`];
134
+ return [...canonical, `receipt_integrity=FAILED reason=${JSON.stringify(integrity.reason)}`];
134
135
  }
135
136
  const briefing =
136
137
  receipt.briefing === undefined
@@ -154,7 +155,7 @@ export function receiptEvidenceLabels(
154
155
  `budget_reason=${JSON.stringify(formatBudgetReasons(receipt.budget))}`,
155
156
  ];
156
157
  return [
157
- canonical,
158
+ ...canonical,
158
159
  `receipt_integrity=verified/v${receipt.integrity.version}/${receipt.integrity.algorithm}`,
159
160
  `evidence_verification=${verification.state}/${verification.basis}`,
160
161
  `host_verification=${receipt.hostVerification?.status ?? "not_requested"}`,
@@ -167,16 +168,13 @@ export function receiptEvidenceLabels(
167
168
  ];
168
169
  }
169
170
 
170
- function canonicalTrustLabel(status: CanonicalTrustStatus): string {
171
- return [
172
- `trust_status=v${status.version}`,
173
- `artifactIntegrity:${status.artifactIntegrity.state}`,
174
- `validationGrounding:${status.validationGrounding.state}`,
175
- `independentReview:${status.independentReview.state}`,
176
- `contextProvenance:${status.contextProvenance.state}`,
177
- `autonomyEnforcement:${status.autonomyEnforcement.state}`,
178
- `completionEvidence:${status.completionEvidence.state}`,
179
- ].join(" ");
171
+ /**
172
+ * The compact projection first, then the canonical axis line, both from the
173
+ * shared projection so the dispatch and monitor text can never spell a state
174
+ * differently from `evidence inspect` or the board.
175
+ */
176
+ function canonicalTrustLabels(status: CanonicalTrustStatus): string[] {
177
+ return [`trust=${JSON.stringify(formatTrustSummary(status))}`, formatTrustAxes(status)];
180
178
  }
181
179
 
182
180
  /**
@@ -192,6 +190,14 @@ export function workerTextLabel(status: CanonicalTrustStatus): string {
192
190
  return "reconnaissance output (advisory leads, not validation evidence):";
193
191
  case "unknown":
194
192
  return "worker claims (validation not observable at this layer):";
193
+ // The three remaining states were one label. The evidence bundle tells
194
+ // a failed check, an inferred claim, and no validation at all apart, so
195
+ // the terminal must too or it hands the operator a coarser verdict than
196
+ // the report for the same run.
197
+ case "failed":
198
+ return "worker claims (validation failed; a check ran and did not pass):";
199
+ case "ungrounded":
200
+ return "worker claims (inferred; validation claimed, none observed):";
195
201
  default:
196
202
  return "worker claims (unverified prose):";
197
203
  }
@@ -162,7 +162,8 @@ interface WorkerSpecFields {
162
162
  */
163
163
  autonomy?: AutonomyLevel;
164
164
  /**
165
- * Absolute directories write-class tool calls are confined to for this run.
165
+ * Absolute path boundaries write-class tool calls are confined to for this run.
166
+ * Exact files omit a trailing slash and subtrees retain one.
166
167
  * Enforced at the shared worker safety seam so a write/edit target outside
167
168
  * every root is a final block. Only set on runtimes that mediate per-tool
168
169
  * calls (native, claude-sdk); dispatch refuses it on subprocess runtimes.