@tea-agent/loop-agent 0.43.0-next.8 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +41 -2312
  3. package/README.md +7 -0
  4. package/dist/application/dag/args.js +8 -0
  5. package/dist/application/task-lifecycle/advance.js +38 -7
  6. package/dist/build-stamp.json +3 -3
  7. package/dist/cli/command-definitions.js +2 -0
  8. package/dist/cli/program.js +3 -1
  9. package/dist/cli/update/init-surface-notifier.js +2 -0
  10. package/dist/cli/update/policy.js +2 -0
  11. package/dist/commands/client-recovery.js +20 -55
  12. package/dist/commands/cursor-prompt.js +2 -0
  13. package/dist/commands/dag-approve.js +2 -0
  14. package/dist/commands/dag-final-verification.js +2 -0
  15. package/dist/commands/dag-init-hybrid.js +2 -0
  16. package/dist/commands/dag-reconcile-tasks.js +2 -0
  17. package/dist/commands/dag-reject.js +2 -0
  18. package/dist/commands/dag-report.js +2 -0
  19. package/dist/commands/dag-rerun.js +2 -0
  20. package/dist/commands/dag-resume.js +2 -0
  21. package/dist/commands/dag-workflow-compile.js +2 -0
  22. package/dist/commands/dag-workflow-plan.js +2 -0
  23. package/dist/commands/dag-workflow-validate.js +2 -0
  24. package/dist/commands/delegate.js +2 -0
  25. package/dist/commands/examples.js +2 -0
  26. package/dist/commands/import-prd.js +2 -0
  27. package/dist/commands/init-model-catalog.js +2 -0
  28. package/dist/commands/init.js +19 -13
  29. package/dist/commands/instructions.js +2 -0
  30. package/dist/commands/knowledge.js +2 -0
  31. package/dist/commands/loop-benchmark.js +2 -0
  32. package/dist/commands/pi-prompt.js +2 -0
  33. package/dist/commands/pi-reuse-benchmark.js +2 -0
  34. package/dist/commands/promote-run.js +2 -0
  35. package/dist/commands/stats.js +1 -1
  36. package/dist/commands/study-init.js +2 -0
  37. package/dist/commands/task-advance.js +34 -0
  38. package/dist/commands/task-source-prepare.js +2 -0
  39. package/dist/commands/worktree-create.js +2 -0
  40. package/dist/commands/worktree-remove.js +2 -0
  41. package/dist/executors/dag-pi-executor.js +1650 -198
  42. package/dist/executors/pi-executor.js +85 -3
  43. package/dist/executors/pi-sdk-executor.js +18 -0
  44. package/dist/executors/shell-executor.js +93 -7
  45. package/dist/executors/shell-verification.js +3 -0
  46. package/dist/executors/shell-write-guard.js +27 -32
  47. package/dist/governance/exec-plans.js +6 -3
  48. package/dist/infrastructure/console/app-data.js +6 -0
  49. package/dist/shared/artifacts-core.js +2 -0
  50. package/dist/shared/backend-dogfood-preflight.js +47 -0
  51. package/dist/shared/dag-failure-category.js +3 -0
  52. package/dist/shared/git-progress.js +2 -0
  53. package/dist/shared/one-shot-prompt-args.js +2 -0
  54. package/dist/shared/operator/capabilities.js +180 -0
  55. package/dist/shared/package-metadata.js +6 -4
  56. package/dist/shared/pi-context-pressure/extension.js +26 -16
  57. package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
  58. package/dist/shared/pi-provider-recovery.js +182 -0
  59. package/dist/shared/pi-retry-settings.js +40 -0
  60. package/dist/shared/reference-context.js +2 -0
  61. package/dist/task/config-types.js +29 -0
  62. package/dist/task/contract/project.js +9 -0
  63. package/dist/task/contract/recover.js +6 -0
  64. package/dist/task/contract/schema.js +17 -0
  65. package/dist/task/source-prepare/artifact-meta.js +9 -2
  66. package/dist/task/source-prepare/build-draft.js +60 -0
  67. package/dist/task/source-prepare/fragment-inventory.js +4 -1
  68. package/dist/task/source-prepare/parse-intent.js +36 -11
  69. package/dist/task/task-demand-routing.js +5 -2
  70. package/dist/worker/console/chat/browser-automation.js +523 -0
  71. package/dist/worker/console/chat/browser-policy.js +6 -36
  72. package/dist/worker/console/chat/browser-routes.js +188 -56
  73. package/dist/worker/console/chat/explore-tools.js +5 -2
  74. package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
  75. package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
  76. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +184 -0
  77. package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
  78. package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +79 -0
  79. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +94 -0
  80. package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
  81. package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
  82. package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
  83. package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
  84. package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
  85. package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
  86. package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
  87. package/dist/worker/console/chat/pi-runtime.js +208 -1138
  88. package/dist/worker/console/chat/routes.js +59 -24
  89. package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
  90. package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
  91. package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
  92. package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
  93. package/dist/worker/console/chat/session-mode-view.js +5 -4
  94. package/dist/worker/console/chat/session-mode.js +18 -12
  95. package/dist/worker/console/chat/session-store.js +42 -9
  96. package/dist/worker/console/chat/terminal-sessions.js +65 -1
  97. package/dist/worker/console/chat/terminal-tools.js +17 -5
  98. package/dist/worker/console/chat/tool-preview.js +115 -0
  99. package/dist/worker/console/chat/tools.js +10 -0
  100. package/dist/worker/console/chat/turn-order.js +13 -0
  101. package/dist/worker/console/chat/turn-process.js +32 -30
  102. package/dist/worker/console/console-update-and-init.js +1 -19
  103. package/dist/worker/console/console-update-runtime.js +5 -20
  104. package/dist/worker/console/operator-actions.js +63 -1
  105. package/dist/worker/console/prd-intake-bridge.js +54 -1
  106. package/dist/worker/console/routes.js +8 -0
  107. package/dist/worker/console/scheduled-goal-host.js +98 -0
  108. package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
  109. package/dist/worker/console/server.js +24 -1
  110. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CwAxHSAM.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
  111. package/dist/worker/console/static/assets/{arc-Bozf-oeF.js → arc-eoQiMvuk.js} +1 -1
  112. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DEypbEQv.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
  113. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-B1BQWCbE.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
  114. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B3u5-yZz.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
  115. package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
  116. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DSUc2NTh.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
  117. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DZouMIvT.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
  118. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-B3bhB5hh.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
  119. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CZFP_BOz.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
  120. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DnE_wb-X.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
  121. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C2OfoiWm.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
  122. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BKUTL8mm.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
  123. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BT5oz0tg.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
  124. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-D8vk-GJi.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
  125. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CkUIm3zu.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
  126. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
  127. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
  128. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CO9QNHmR.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
  129. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-s52EPl2Z.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
  130. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BHaseJfW.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
  131. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CTVhRG_R.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
  132. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B6pYeOMR.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
  133. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CXXRzw5j.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
  134. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BOeJHiLA.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
  135. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DbEg6h_l.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
  136. package/dist/worker/console/static/assets/{diagram-UB23O5K3-CjlEcbX6.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
  137. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BcqMPbD_.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
  138. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DWfRyHe5.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
  139. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Bz7TeIc8.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
  140. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BD-JxYjU.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
  141. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Cv16vMHK.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
  142. package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
  143. package/dist/worker/console/static/assets/index-Cdkvw_H6.js +469 -0
  144. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BlWO0HQQ.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
  145. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C4mbsn97.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
  146. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CBPvVKjw.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
  147. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DPHLp54K.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
  148. package/dist/worker/console/static/assets/{linear-CXx_9o6k.js → linear-BDZ9riWi.js} +1 -1
  149. package/dist/worker/console/static/assets/{mermaid.core-DU3IxMq9.js → mermaid.core-7pKqYtpZ.js} +5 -5
  150. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-COm4a2ud.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
  151. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Cbt7OA5d.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
  152. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BiYV_4Wl.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
  153. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-lg2zhvbp.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
  154. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-cBLvtf0p.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
  155. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BoekU3Bg.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
  156. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-D_DMZYga.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
  157. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-Lzmzn8lz.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
  158. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Cos3HpIe.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
  159. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-D-hFBGsx.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
  160. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
  161. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BY95sCVI.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
  162. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
  163. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-D1iCgWHS.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
  164. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D9IYy4WK.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
  165. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-C9yJwO-R.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
  166. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CC2llyou.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
  167. package/dist/worker/console/static/index.html +2 -2
  168. package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +10 -0
  169. package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +24 -0
  170. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
  171. package/dist/worker/console/static-src/operator-chat/compaction-message.js +10 -17
  172. package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
  173. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
  174. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
  175. package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
  176. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +10 -0
  177. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +105 -44
  178. package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
  179. package/dist/worker/console/static-src/operator-chat/useChatThread.js +38 -57
  180. package/dist/worker/console/static-src/operator-chat/useComposer.js +195 -73
  181. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
  182. package/dist/worker/console/static-src/prd-file-import.js +3 -1
  183. package/dist/worker/console/workspace-context.js +22 -0
  184. package/dist/worker/console/workspace-initialization.js +209 -0
  185. package/dist/worker/delivery/git-transaction.js +2 -0
  186. package/dist/worker/feature/fullstack-validate.js +2 -0
  187. package/dist/worker/loop-agent/loop-agent-client.js +8 -2
  188. package/dist/worker/materialize/harness-task-materializer.js +4 -1
  189. package/dist/worker/metrics/projector.js +1 -1
  190. package/dist/worker/observability/event-store.js +4 -1
  191. package/dist/worker/observability/read-model.js +4 -1
  192. package/dist/worker/observe/node-transparency.js +23 -1
  193. package/dist/worker/observe/routes.js +4 -0
  194. package/dist/worker/observe/static/operator-chrome.js +3 -1
  195. package/dist/worker/observe/static/styles.css +7 -4
  196. package/dist/worker/observe/static/views/dag-inspector.js +5 -19
  197. package/dist/worker/outcomes/declared-artifacts.js +2 -0
  198. package/dist/worker/preflight.js +3 -0
  199. package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
  200. package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
  201. package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
  202. package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
  203. package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
  204. package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
  205. package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
  206. package/dist/worker/task-spec/validate.js +4 -1
  207. package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
  208. package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
  209. package/dist/workflows/dag/dag-retry-schema.js +11 -0
  210. package/dist/workflows/dag/decision-envelope.js +2 -0
  211. package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
  212. package/dist/workflows/dag/frontend-closeout.js +3 -1
  213. package/dist/workflows/dag/frontend-committed-facts.js +461 -0
  214. package/dist/workflows/dag/frontend-durable-tools.js +15 -3
  215. package/dist/workflows/dag/frontend-implementation-contract.js +369 -12
  216. package/dist/workflows/dag/frontend-plan-canary.js +53 -0
  217. package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
  218. package/dist/workflows/dag/frontend-plan-render.js +0 -2
  219. package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
  220. package/dist/workflows/dag/frontend-recovery-run.js +57 -0
  221. package/dist/workflows/dag/frontend-repair.js +55 -76
  222. package/dist/workflows/dag/frontend-review-context.js +42 -68
  223. package/dist/workflows/dag/frontend-review-scopes.js +2 -2
  224. package/dist/workflows/dag/frontend-risk.js +92 -10
  225. package/dist/workflows/dag/frontend-session-budget.js +117 -3
  226. package/dist/workflows/dag/frontend-shape.js +11 -55
  227. package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
  228. package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
  229. package/dist/workflows/dag/frontend-verification-trace.js +33 -54
  230. package/dist/workflows/dag/frontend-writer-admission.js +3 -47
  231. package/dist/workflows/dag/frontend-writer-status.js +0 -23
  232. package/dist/workflows/dag/init-hybrid.js +47 -19
  233. package/dist/workflows/dag/interrupt-request.js +2 -0
  234. package/dist/workflows/dag/lifecycle.js +11 -2
  235. package/dist/workflows/dag/node-execution.js +50 -13
  236. package/dist/workflows/dag/reconcile-run.js +2 -0
  237. package/dist/workflows/dag/repair-artifact.js +3 -1
  238. package/dist/workflows/dag/report.js +2 -0
  239. package/dist/workflows/dag/rerun-plan.js +10 -0
  240. package/dist/workflows/dag/rerun-task.js +79 -1
  241. package/dist/workflows/dag/retry-policy.js +18 -0
  242. package/dist/workflows/dag/scheduler.js +2 -4
  243. package/dist/workflows/dag/types.js +44 -6
  244. package/dist/workflows/dag/validate.js +4 -0
  245. package/docs/README.md +1 -0
  246. package/docs/architecture/runtime-boundaries.md +3 -3
  247. package/docs/governance/README.md +1 -0
  248. package/docs/init-surface.manifest.json +1 -0
  249. package/docs/operations/README.md +2 -0
  250. package/docs/templates/README.md +1 -1
  251. package/docs/templates/agent-dag.schema.json +2 -2
  252. package/docs/templates/backend-test-dag.json +14 -10
  253. package/docs/templates/frontend-implementation-contract.schema.json +0 -7
  254. package/package.json +9 -3
  255. package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
  256. package/skills/frontend-contract/references/contract-protocol.md +3 -1
  257. package/skills/frontend-plan/SKILL.md +8 -6
  258. package/skills/frontend-plan/references/decision-contract.md +3 -3
  259. package/skills/frontend-review/SKILL.md +18 -28
  260. package/skills/frontend-review/references/review-findings.md +8 -3
  261. package/dist/commands/new-task.js +0 -5
  262. package/dist/commands/status.js +0 -57
  263. package/dist/commands/task-contract.js +0 -269
  264. package/dist/shared/prompts.js +0 -26
  265. package/dist/task/config.js +0 -2
  266. package/dist/task/contract/validate-draft.js +0 -106
  267. package/dist/task/goal.js +0 -3
  268. package/dist/task/index.js +0 -12
  269. package/dist/task/lifecycle.js +0 -1
  270. package/dist/task/operator/capabilities.js +0 -6
  271. package/dist/task/operator/envelope.js +0 -2
  272. package/dist/task/operator/index.js +0 -5
  273. package/dist/task/operator/registry.js +0 -2
  274. package/dist/task/operator/types.js +0 -1
  275. package/dist/task/paths.js +0 -1
  276. package/dist/task/source-state.js +0 -1
  277. package/dist/task/subagent-guidance.js +0 -1
  278. package/dist/worker/console/chat/sift-bridge.js +0 -1
  279. package/dist/worker/console/index.js +0 -20
  280. package/dist/worker/console/static/assets/channel-JM-I_b0s.js +0 -1
  281. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DuQQAYEg.js +0 -1
  282. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DuQQAYEg.js +0 -1
  283. package/dist/worker/console/static/assets/index-B5H-giS2.js +0 -468
  284. package/dist/worker/console/static/assets/index-Bf7dxfm-.css +0 -1
  285. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-img0hVJ4.js +0 -1
  286. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B4acZJvk.js +0 -8
  287. package/dist/worker/scheduler/index.js +0 -25
  288. package/dist/workflows/dag/facts.js +0 -4
  289. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
  290. package/dist/workflows/dag/index.js +0 -6
  291. package/dist/workflows/dynamic/index.js +0 -7
@@ -0,0 +1,117 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { readFile, realpath } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { z } from "zod";
5
+ import { getTaskPaths } from "../../task/runtime.js";
6
+ import { computeTaskConfigSha256 } from "../../task/contract/hash.js";
7
+ import { assessAutonomousExecutionEligibility, deriveEligibilityFactsFromDagSpec } from "../console/dag-execution-receipt.js";
8
+ import { scheduledGoalDraftSchema } from "./scheduled-goal-types.js";
9
+ const bindingSchema = z.object({
10
+ taskId: z.string(), revision: z.number().int().positive(), canonicalHash: z.string(),
11
+ taskConfigSha256: z.string(), projectionVersion: z.number(), canonicalizerVersion: z.number(), taskConfigSchemaVersion: z.number(),
12
+ });
13
+ const statusSchema = z.object({
14
+ taskId: z.string(), lifecycleState: z.literal("awaiting-write-set-approval"),
15
+ contract: z.object({ effectiveStatus: z.literal("managed"), revision: z.number().int().positive(),
16
+ canonicalHash: z.string(), observedCanonicalHash: z.string(), transactionIncomplete: z.literal(false),
17
+ taskConfigSha256: z.string(), projectionVersion: z.number(), canonicalizerVersion: z.number(), taskConfigSchemaVersion: z.number(), }),
18
+ dagDraft: z.object({ exists: z.literal(true), strictValidated: z.literal(true), specHash: z.string() }),
19
+ gate: z.object({ id: z.string().min(1), digest: z.string().min(1), type: z.literal("human-approval"),
20
+ bound: z.object({ taskId: z.string(), contractRevision: z.number(), contractCanonicalHash: z.string(), dagSpecHash: z.string() }), }),
21
+ activeRun: z.unknown().nullable().optional(), blockers: z.array(z.unknown()).length(0),
22
+ });
23
+ /** Freeze only a CLI-prepared managed task. This read-only intake never approves or starts a DAG. */
24
+ export async function prepareScheduledGoalDraft(input, client) {
25
+ // Validate caller-controlled identity before using it in CLI arguments or paths.
26
+ const parsed = scheduledGoalDraftSchema.omit({ prepared: true, controllerRef: true }).parse(input);
27
+ const identity = client.getIdentity();
28
+ if (!identity)
29
+ throw new Error("scheduled goal requires a pinned controller");
30
+ const root = await realpath(parsed.worktreeRef);
31
+ const paths = getTaskPaths(root, parsed.managedTaskId);
32
+ const readBound = async (file) => {
33
+ const resolved = await realpath(file);
34
+ const relative = path.relative(root, resolved);
35
+ if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
36
+ throw new Error("scheduled goal prepared artifact escapes worktree");
37
+ return readFile(resolved, "utf8");
38
+ };
39
+ const status = await client.run(["task", "status", parsed.managedTaskId, "--json"], { cwd: root, expectJson: true, artifactName: `scheduled-goal-admission-${parsed.managedTaskId}-${randomUUID()}`, timeoutMs: 30_000 });
40
+ if (!status.ok || status.exitCode !== 0)
41
+ throw new Error("scheduled goal task status failed");
42
+ const envelope = z.object({ ok: z.literal(true), result: statusSchema }).parse(status.json);
43
+ const snapshot = envelope.result;
44
+ if (snapshot.taskId !== parsed.managedTaskId || snapshot.activeRun != null ||
45
+ snapshot.contract.canonicalHash !== snapshot.contract.observedCanonicalHash ||
46
+ snapshot.gate.bound.taskId !== parsed.managedTaskId ||
47
+ snapshot.gate.bound.contractRevision !== snapshot.contract.revision ||
48
+ snapshot.gate.bound.contractCanonicalHash !== snapshot.contract.canonicalHash)
49
+ throw new Error("scheduled goal managed contract binding mismatch");
50
+ const [dagBytes, configBytes] = await Promise.all([readBound(paths.dagDraftPath), readBound(paths.taskConfigPath)]);
51
+ const dagSpecHash = `sha256:${createHash("sha256").update(dagBytes).digest("hex")}`;
52
+ if (snapshot.dagDraft.specHash !== dagSpecHash || snapshot.gate.bound.dagSpecHash !== dagSpecHash)
53
+ throw new Error("scheduled goal validated DAG drift");
54
+ const dag = JSON.parse(dagBytes);
55
+ const binding = bindingSchema.parse(dag.taskContractBinding);
56
+ const expectedBinding = bindingSchema.parse({ ...snapshot.contract, taskId: parsed.managedTaskId });
57
+ if (dag.version !== 4 || JSON.stringify(binding) !== JSON.stringify(expectedBinding))
58
+ throw new Error("scheduled goal DAG contract binding mismatch");
59
+ const configJson = JSON.parse(configBytes);
60
+ if (computeTaskConfigSha256(configJson) !== binding.taskConfigSha256)
61
+ throw new Error("scheduled goal task configuration drift");
62
+ const config = z.object({ taskKind: z.string(), allowedPaths: z.array(z.string()), forbiddenPaths: z.array(z.string()) }).parse(configJson);
63
+ if (config.taskKind !== parsed.workflow || JSON.stringify(config.allowedPaths) !== JSON.stringify(parsed.allowedPaths) ||
64
+ JSON.stringify(config.forbiddenPaths) !== JSON.stringify(parsed.forbiddenPaths))
65
+ throw new Error("scheduled goal task scope or workflow mismatch");
66
+ const assessment = assessAutonomousExecutionEligibility(deriveEligibilityFactsFromDagSpec({
67
+ dagSpec: dag, allowedPaths: parsed.allowedPaths, forbiddenPaths: parsed.forbiddenPaths,
68
+ }));
69
+ if (!assessment.ok)
70
+ throw new Error(`scheduled goal ineligible: ${assessment.reason}`);
71
+ const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
72
+ return scheduledGoalDraftSchema.parse({ ...parsed, controllerRef: identity.packageFingerprint.value,
73
+ prepared: { gateToken: `${snapshot.gate.id}:${snapshot.gate.digest}`,
74
+ dagPath: path.relative(root, paths.dagDraftPath), dagHash: digest(dagBytes),
75
+ contractPath: path.relative(root, paths.taskConfigPath), contractHash: digest(configBytes) }, });
76
+ }
77
+ /** Materialize only contract/runtime inputs; execution remains owned by the operation host. */
78
+ export async function prepareDerivedScheduledGoalTask(goalId, ownerToken, goals, client) {
79
+ const { mkdir, writeFile } = await import("node:fs/promises");
80
+ const goal = await goals.get(goalId);
81
+ const entry = goal.supervisions.at(-1);
82
+ if (goal.state !== "admitted" || !entry || entry.ownerToken !== ownerToken || entry.state !== "preparing" || !entry.proposal)
83
+ throw new Error("derived preparation not authorized");
84
+ if (client.getIdentity()?.packageFingerprint.value !== goal.frozen.controllerRef)
85
+ throw new Error("derived controller drift");
86
+ const directory = path.join(goal.frozen.worktreeRef, ".harness", "scheduled-goal-inputs");
87
+ await mkdir(directory, { recursive: true, mode: 0o700 });
88
+ const prdPath = path.join(directory, `${entry.managedTaskId}.md`);
89
+ const content = ["# Scheduled goal continuation", "## Goal", goal.frozen.originalGoal,
90
+ "## Observed gap", entry.proposal.summary, "## Next task", entry.proposal.instructions,
91
+ "## Acceptance criteria", ...goal.frozen.acceptance.criteria.map((ac) => `- ${ac.acId}: ${ac.description}\n Verification: ${ac.command}`),
92
+ "## Scope", `Workflow: ${goal.frozen.workflow}; acceptance policy: ${goal.frozen.acceptance.policy}.`,
93
+ `Allowed paths: ${JSON.stringify(goal.frozen.allowedPaths)}. Forbidden paths: ${JSON.stringify(goal.frozen.forbiddenPaths)}.`,
94
+ "Preserve the current worktree changes. Do not change acceptance, dependencies, Git history, controller or runtime configuration. Do not push or merge.",
95
+ `Parent evidence: ${entry.parentEvidenceId}; tree: ${entry.treeHash}.`, ""].join("\n\n");
96
+ await writeFile(prdPath, content, { flag: "wx", mode: 0o600 });
97
+ const boundaryArgs = goal.frozen.allowedPaths.flatMap((ref) => ["--allowed-path", ref])
98
+ .concat(goal.frozen.forbiddenPaths.flatMap((ref) => ["--forbidden-path", ref]))
99
+ .concat(goal.frozen.acceptance.criteria.flatMap((ac) => ["--verify", `${ac.acId}:${ac.command}`]));
100
+ for (const [step, args] of [
101
+ ["create", ["task", "advance", entry.managedTaskId, `Scheduled goal continuation ${entry.taskRevision}`, "--prd", prdPath, "--task-kind", goal.frozen.workflow, ...boundaryArgs, "--json"]],
102
+ ["prepare", ["task", "advance", entry.managedTaskId, "--task-kind", goal.frozen.workflow, ...boundaryArgs, "--json"]],
103
+ ]) {
104
+ const current = await goals.get(goalId);
105
+ if (current.state !== "admitted" || current.supervisions.at(-1)?.ownerToken !== ownerToken)
106
+ throw new Error("derived preparation authorization lost");
107
+ const remaining = Math.min(Date.parse(goal.frozen.time.stopAtUtc), Date.parse(goal.frozen.time.expiresAt)) - Date.now();
108
+ if (remaining <= 0)
109
+ throw new Error("derived preparation expired");
110
+ const result = await client.run([...args], { cwd: goal.frozen.worktreeRef, expectJson: true,
111
+ artifactName: `${entry.managedTaskId}-${step}`, timeoutMs: Math.min(remaining, 300000) });
112
+ if (!result.ok || result.exitCode !== 0 || result.timedOut)
113
+ throw new Error(`derived task ${step} failed or unknown`);
114
+ }
115
+ const { prepared: _prepared, controllerRef: _controller, ...input } = goal.frozen;
116
+ return prepareScheduledGoalDraft({ ...input, managedTaskId: entry.managedTaskId }, client);
117
+ }
@@ -0,0 +1,167 @@
1
+ import { createHash } from "node:crypto";
2
+ import { execFile } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ import { lstat, readFile, readlink, realpath } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { pathMatchesPattern } from "../../shared/git-progress.js";
7
+ import { scheduledGoalDraftSchema } from "./scheduled-goal-types.js";
8
+ const execFileAsync = promisify(execFile);
9
+ const sha256 = (value) => createHash("sha256").update(value).digest("hex");
10
+ /** Run only frozen AC commands. A timeout is uncertain execution, never a passing or repairable failure. */
11
+ export async function evaluateScheduledGoalCriteria(frozen, options = {}) {
12
+ frozen = scheduledGoalDraftSchema.pick({ worktreeRef: true, frozenBase: true, allowedPaths: true, forbiddenPaths: true, acceptance: true, time: true }).strip().parse(frozen);
13
+ if (options.commandTimeoutMs !== undefined && (!Number.isFinite(options.commandTimeoutMs) || options.commandTimeoutMs <= 0))
14
+ throw new Error("invalid acceptance command timeout");
15
+ const now = options.now ?? (() => new Date());
16
+ const startedAt = now().toISOString();
17
+ const capture = () => captureScheduledGoalTree(frozen.worktreeRef, frozen.frozenBase, frozen.allowedPaths, frozen.forbiddenPaths);
18
+ const before = await capture();
19
+ const criteria = [];
20
+ let stopped = before.scopeViolations.length ? "scope_violation" : undefined;
21
+ let drift = false;
22
+ let executionUnknown = false;
23
+ for (const criterion of frozen.acceptance.criteria) {
24
+ if (options.mayRun && !await options.mayRun())
25
+ stopped ??= "assessment_cancelled";
26
+ const current = await capture();
27
+ if (current.treeHash !== before.treeHash) {
28
+ drift = true;
29
+ stopped = "tree_changed_during_acceptance";
30
+ }
31
+ const remaining = Math.min(Date.parse(frozen.time.stopAtUtc), Date.parse(frozen.time.expiresAt)) - now().getTime();
32
+ if (remaining <= 0)
33
+ stopped ??= "authorization_expired";
34
+ const result = { acId: criterion.acId, command: criterion.command,
35
+ status: "pending", exitCode: null, stdout: "", stderr: "", outputHash: sha256(JSON.stringify({ stdout: "", stderr: "", exitCode: null })), };
36
+ if (stopped)
37
+ result.reason = stopped;
38
+ else {
39
+ try {
40
+ const output = await execFileAsync("bash", ["-lc", criterion.command], {
41
+ cwd: frozen.worktreeRef, encoding: "utf8", maxBuffer: 1024 * 1024,
42
+ timeout: Math.max(1, Math.min(remaining, options.commandTimeoutMs ?? 120_000)),
43
+ });
44
+ result.stdout = output.stdout;
45
+ result.stderr = output.stderr;
46
+ result.exitCode = 0;
47
+ result.status = "succeeded";
48
+ }
49
+ catch (error) {
50
+ const failure = error;
51
+ result.stdout = failure.stdout ?? "";
52
+ result.stderr = failure.stderr ?? "";
53
+ if (typeof failure.code === "number" && !failure.killed && !failure.signal) {
54
+ result.exitCode = failure.code;
55
+ result.status = "failed";
56
+ }
57
+ else {
58
+ executionUnknown = true;
59
+ result.reason = "command_execution_unknown";
60
+ stopped = result.reason;
61
+ }
62
+ }
63
+ result.outputHash = sha256(JSON.stringify({ stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode }));
64
+ const verifiedTree = await capture();
65
+ if (verifiedTree.treeHash !== before.treeHash) {
66
+ drift = true;
67
+ stopped = "tree_changed_during_acceptance";
68
+ }
69
+ }
70
+ criteria.push(result);
71
+ }
72
+ const after = await capture();
73
+ drift ||= before.treeHash !== after.treeHash;
74
+ if (drift)
75
+ for (const result of criteria) {
76
+ if (result.reason === "command_execution_unknown")
77
+ continue;
78
+ result.status = "stale";
79
+ result.reason = "tree_changed_during_acceptance";
80
+ }
81
+ const finishedAt = now().toISOString();
82
+ const expired = Date.parse(finishedAt) >= Math.min(Date.parse(frozen.time.stopAtUtc), Date.parse(frozen.time.expiresAt));
83
+ const status = executionUnknown ? "pending" : drift ? "stale" : before.scopeViolations.length || after.scopeViolations.length ? "failed"
84
+ : expired ? "pending"
85
+ : criteria.some((result) => result.status === "pending") ? "pending"
86
+ : criteria.every((result) => result.status === "succeeded") ? "succeeded" : "failed";
87
+ return { before, after, criteria, status, executionUnknown, startedAt, finishedAt };
88
+ }
89
+ /** Hash actual delivery bytes, including nonignored untracked files; staging is not a tree change. */
90
+ export async function captureScheduledGoalTree(worktree, base, allowedPaths, forbiddenPaths) {
91
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(base))
92
+ throw new Error("invalid frozen base");
93
+ const root = await realpath(worktree);
94
+ const git = async (...args) => (await execFileAsync("git", ["-C", root, ...args], {
95
+ encoding: "utf8", timeout: 30_000, maxBuffer: 16 * 1024 * 1024,
96
+ })).stdout;
97
+ const [head, top, tracked, untracked, baseline, format] = await Promise.all([
98
+ git("rev-parse", "HEAD"), git("rev-parse", "--show-toplevel"),
99
+ git("ls-files", "-z", "--cached"), git("ls-files", "-z", "--others", "--exclude-standard"),
100
+ git("ls-tree", "-r", "-z", base), git("rev-parse", "--show-object-format"),
101
+ ]);
102
+ if (await realpath(top.trim()) !== root || head.trim() !== base)
103
+ throw new Error("scheduled goal worktree/base drift");
104
+ const entries = (value) => value.split("\0").filter(Boolean);
105
+ const objectFormat = format.trim();
106
+ if (objectFormat !== "sha1" && objectFormat !== "sha256")
107
+ throw new Error("unsupported Git object format");
108
+ const baseEntries = new Map(entries(baseline).map((entry) => {
109
+ const separator = entry.indexOf("\t");
110
+ const [mode, kind, objectId] = entry.slice(0, separator).split(" ");
111
+ if (separator < 0 || !mode || !kind || !objectId)
112
+ throw new Error("invalid Git tree entry");
113
+ return [entry.slice(separator + 1), { mode, kind, objectId }];
114
+ }));
115
+ const blobId = (bytes) => createHash(objectFormat).update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
116
+ const names = [...new Set([...entries(tracked), ...entries(untracked), ...baseEntries.keys()])].sort();
117
+ const deliveryNames = new Set(names);
118
+ const files = [];
119
+ const changedPaths = [];
120
+ for (const name of names) {
121
+ const expected = baseEntries.get(name);
122
+ let actualId;
123
+ let actualMode;
124
+ const target = path.resolve(root, name);
125
+ const relative = path.relative(root, target);
126
+ if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
127
+ throw new Error("tree path escapes worktree");
128
+ try {
129
+ const parent = await realpath(path.dirname(target));
130
+ if (parent !== root && !parent.startsWith(`${root}${path.sep}`))
131
+ throw new Error("tree parent escapes worktree");
132
+ const stat = await lstat(target);
133
+ if (stat.isSymbolicLink()) {
134
+ const link = await readlink(target);
135
+ const resolved = await realpath(target).catch(() => { throw new Error(`unresolved delivery symlink: ${name}`); });
136
+ if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`))
137
+ throw new Error(`delivery symlink escapes worktree: ${name}`);
138
+ if (!deliveryNames.has(path.relative(root, resolved)))
139
+ throw new Error(`delivery symlink target is not fingerprinted: ${name}`);
140
+ files.push({ name, kind: "symlink", hash: sha256(link) });
141
+ actualId = blobId(Buffer.from(link));
142
+ actualMode = "120000";
143
+ }
144
+ else if (stat.isFile()) {
145
+ const bytes = await readFile(target);
146
+ files.push({ name, kind: "file", hash: sha256(bytes), executable: Boolean(stat.mode & 0o111) });
147
+ actualId = blobId(bytes);
148
+ actualMode = stat.mode & 0o111 ? "100755" : "100644";
149
+ }
150
+ else
151
+ throw new Error(`unsupported delivery entry: ${name}`);
152
+ }
153
+ catch (error) {
154
+ if (error.code === "ENOENT") {
155
+ if (expected)
156
+ files.push({ name, kind: "missing" });
157
+ }
158
+ else
159
+ throw error;
160
+ }
161
+ if (expected ? expected.objectId !== actualId || expected.mode !== actualMode : actualId !== undefined)
162
+ changedPaths.push(name);
163
+ }
164
+ const scopeViolations = changedPaths.filter((name) => !allowedPaths.some((pattern) => pathMatchesPattern(name, pattern))
165
+ || forbiddenPaths.some((pattern) => pathMatchesPattern(name, pattern)));
166
+ return { base, head: head.trim(), treeHash: sha256(JSON.stringify(files)), changedPaths, scopeViolations };
167
+ }
@@ -0,0 +1,62 @@
1
+ import { captureScheduledGoalTree } from "./scheduled-goal-evidence.js";
2
+ // ESRCH establishes absence only; permission errors and PID reuse never grant takeover.
3
+ function ownerMissing(pid) {
4
+ if (pid === undefined)
5
+ return true;
6
+ try {
7
+ process.kill(pid, 0);
8
+ return false;
9
+ }
10
+ catch (error) {
11
+ return error.code === "ESRCH";
12
+ }
13
+ }
14
+ /** Read-only result projection. Reopening a result never authorizes another execution. */
15
+ export async function readScheduledGoalResult(goalId, goals) {
16
+ const goal = await goals.get(goalId);
17
+ const evidence = goal.evidence.at(-1);
18
+ let evidenceCurrent = false;
19
+ let treeReadError = false;
20
+ if (evidence) {
21
+ try {
22
+ const tree = await captureScheduledGoalTree(goal.frozen.worktreeRef, goal.frozen.frozenBase, goal.frozen.allowedPaths, goal.frozen.forbiddenPaths);
23
+ evidenceCurrent = evidence.intentId === goal.intents.at(-1)?.intentId && tree.treeHash === evidence.committedTree.treeHash &&
24
+ tree.treeHash === evidence.assessment.after.treeHash && tree.scopeViolations.length === 0;
25
+ }
26
+ catch {
27
+ treeReadError = true;
28
+ }
29
+ }
30
+ const missingOwner = goal.intents.some((intent) => intent.state === "dispatching" && ownerMissing(intent.dispatchOwnerPid)) || Boolean(goal.assessmentAttempt && ownerMissing(goal.assessmentAttempt.ownerPid)) ||
31
+ goal.supervisions.some((entry) => ["requested", "preparing"].includes(entry.state) && ownerMissing(entry.ownerPid));
32
+ const uncertain = missingOwner || goal.state === "unknown" || goal.intents.some((intent) => intent.state === "unknown") ||
33
+ goal.supervisions.some((entry) => entry.state === "unknown") || Boolean(goal.assessmentAttempt && goal.acceptanceState === "pending");
34
+ const acceptance = evidence && !evidenceCurrent && ["accepted", "failed"].includes(goal.acceptanceState) ? "stale" : goal.acceptanceState;
35
+ return {
36
+ goalId, goalRevision: goal.goalRevision, stateVersion: goal.stateVersion,
37
+ state: goal.state, reasonCode: treeReadError ? "tree_unreadable" : acceptance === "stale" ? "evidence_drift" : goal.reasonCode,
38
+ acceptance, delivery: goal.deliveryState, evidenceCurrent,
39
+ budget: { limits: goal.frozen.budget, used: goal.used, tokenUsage: "unknown" },
40
+ supervision: goal.supervisions.map((entry) => ({ state: entry.state, taskRevision: entry.taskRevision, usageTokens: entry.usageTokens ?? null })),
41
+ execution: goal.intents.map((intent) => ({ taskRevision: intent.taskRevision, turnSeq: intent.turnSeq,
42
+ state: intent.state, operationId: intent.operationId, runId: intent.runId })),
43
+ evidence: goal.evidence.map((item) => ({ evidenceId: item.evidenceId, taskRevision: item.taskRevision,
44
+ treeHash: item.committedTree.treeHash, status: item.assessment.status, recordedAt: item.recordedAt,
45
+ criteria: item.assessment.criteria.map((ac) => ({ acId: ac.acId, status: ac.status, exitCode: ac.exitCode,
46
+ outputHash: ac.outputHash, evidenceRef: `${item.evidenceId}#${ac.acId}` })) })),
47
+ reconciliation: uncertain ? {
48
+ required: true,
49
+ reason: missingOwner ? "reservation_owner_missing" : goal.reasonCode ?? "execution_unknown",
50
+ instructions: "Inspect the associated operation/run and all descendant processes. Preserve the ledger and worktree. Do not delete ownership locks or automatically repeat an unknown action; an operator must reconcile execution before resources can be released.",
51
+ } : null,
52
+ };
53
+ }
54
+ /** Resolve a hash-bound output reference without exposing dispatch/owner capabilities. */
55
+ export async function readScheduledGoalEvidence(goalId, evidenceId, acId, goals) {
56
+ const goal = await goals.get(goalId);
57
+ const evidence = goal.evidence.find((entry) => entry.evidenceId === evidenceId);
58
+ const criterion = evidence?.assessment.criteria.find((entry) => entry.acId === acId);
59
+ if (!evidence || !criterion)
60
+ throw new Error("scheduled goal evidence not found");
61
+ return { evidenceId, taskRevision: evidence.taskRevision, treeHash: evidence.committedTree.treeHash, ...criterion };
62
+ }