@tea-agent/loop-agent 0.39.0-beta.1 → 0.39.0-beta.10

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 (331) hide show
  1. package/AGENTS.md +4 -1
  2. package/CHANGELOG.md +248 -95
  3. package/README.md +9 -5
  4. package/bin/loop-agent.js +7 -3
  5. package/dist/application/task-lifecycle/advance.js +12 -0
  6. package/dist/application/task-lifecycle/recommendations.js +13 -2
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/cli/command-definitions.js +23 -5
  9. package/dist/cli/program.js +21 -2
  10. package/dist/cli/update/notifier.js +2 -2
  11. package/dist/cli/update/runtime-activity.js +1 -29
  12. package/dist/cli.js +2 -1
  13. package/dist/commands/client-recovery.js +3 -0
  14. package/dist/commands/dag-follow-up.js +138 -0
  15. package/dist/commands/dag-rerun.js +55 -1
  16. package/dist/commands/init-model-catalog.js +464 -0
  17. package/dist/commands/init-upgrade.js +265 -97
  18. package/dist/commands/init.js +455 -28
  19. package/dist/commands/inspect-next.js +8 -0
  20. package/dist/commands/task-advance.js +19 -0
  21. package/dist/executors/dag-pi-executor.js +2306 -61
  22. package/dist/executors/pi-executor.js +7 -0
  23. package/dist/executors/pi-extension-resolver.js +233 -0
  24. package/dist/executors/pi-playwright-cli-tool.js +74 -28
  25. package/dist/executors/pi-read-budget-policy.js +239 -0
  26. package/dist/executors/pi-sdk-executor.js +180 -33
  27. package/dist/executors/shell-executor.js +1249 -224
  28. package/dist/executors/shell-write-guard.js +14 -0
  29. package/dist/executors/workspace-write-snapshot.js +68 -0
  30. package/dist/infrastructure/harness/atomic-write.js +23 -0
  31. package/dist/shared/dag-failure-category.js +150 -0
  32. package/dist/shared/dag-prompt-override.js +27 -0
  33. package/dist/shared/openspec-spec.js +70 -4
  34. package/dist/shared/operator/capabilities.js +39 -0
  35. package/dist/shared/playwright-cli-command-policy.js +15 -0
  36. package/dist/shared/update/console-notifier.js +100 -0
  37. package/dist/{cli → shared}/update/npm-client.js +70 -15
  38. package/dist/{cli → shared}/update/state.js +41 -13
  39. package/dist/task/config-types.js +50 -5
  40. package/dist/task/contract/apply.js +11 -1
  41. package/dist/task/contract/constants.js +2 -0
  42. package/dist/task/contract/hash.js +3 -0
  43. package/dist/task/contract/observe.js +25 -4
  44. package/dist/task/contract/paths.js +2 -1
  45. package/dist/task/contract/project.js +18 -1
  46. package/dist/task/contract/schema.js +4 -1
  47. package/dist/task/contract/transaction.js +12 -0
  48. package/dist/task/frontend-project-capability.js +199 -18
  49. package/dist/task/source-prepare/completeness.js +188 -0
  50. package/dist/task/source-prepare/fragment-inventory.js +477 -0
  51. package/dist/task/source-prepare/index.js +3 -0
  52. package/dist/task/source-prepare/ledger-reconciliation.js +127 -0
  53. package/dist/task/source-prepare/ledger-review.js +214 -0
  54. package/dist/task/source-prepare/ledger.js +545 -0
  55. package/dist/task/source-prepare/parse-intent.js +24 -4
  56. package/dist/task/source-prepare/prepare.js +298 -1
  57. package/dist/task/source-prepare/semantic-intake.js +25 -5
  58. package/dist/task/source-prepare/source-fidelity-pi.js +384 -0
  59. package/dist/task/source-prepare/types.js +22 -0
  60. package/dist/task/source-references.js +22 -1
  61. package/dist/worker/cli.js +18 -2
  62. package/dist/worker/console/chat/chat-event-store.js +62 -4
  63. package/dist/worker/console/chat/context-panel.js +7 -0
  64. package/dist/worker/console/chat/deferred-turn.js +12 -0
  65. package/dist/worker/console/chat/operation-card.js +8 -1
  66. package/dist/worker/console/chat/pi-console-config.js +81 -10
  67. package/dist/worker/console/chat/pi-runtime.js +264 -16
  68. package/dist/worker/console/chat/provider-error.js +98 -0
  69. package/dist/worker/console/chat/routes.js +298 -32
  70. package/dist/worker/console/chat/session-stats.js +179 -0
  71. package/dist/worker/console/chat/session-store.js +93 -63
  72. package/dist/worker/console/chat/todos.js +115 -0
  73. package/dist/worker/console/chat/tool-preview.js +42 -0
  74. package/dist/worker/console/chat/turn-process.js +20 -55
  75. package/dist/worker/console/chat/user-questions.js +266 -0
  76. package/dist/worker/console/chat/workspace-landing.js +14 -0
  77. package/dist/worker/console/console-handoff.js +82 -0
  78. package/dist/worker/console/console-update-and-init.js +115 -0
  79. package/dist/worker/console/console-update-runtime.js +84 -0
  80. package/dist/worker/console/dag-execution-receipt.js +33 -0
  81. package/dist/worker/console/draft-store.js +49 -0
  82. package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
  83. package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
  84. package/dist/worker/console/index.js +3 -0
  85. package/dist/worker/console/inspect-split.js +18 -0
  86. package/dist/worker/console/native-directory-picker.js +13 -0
  87. package/dist/worker/console/operation-run-facts.js +19 -3
  88. package/dist/worker/console/operation-store.js +227 -7
  89. package/dist/worker/console/operator-actions.js +388 -0
  90. package/dist/worker/console/operator-surface-health.js +1 -0
  91. package/dist/worker/console/operator-user-error.js +2 -2
  92. package/dist/worker/console/prd-intake-bridge.js +13 -0
  93. package/dist/worker/console/routes.js +355 -3
  94. package/dist/worker/console/security.js +67 -13
  95. package/dist/worker/console/server.js +609 -164
  96. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4kVYweA.js → abnfDiagram-N423BO3Z-BAsjg7ew.js} +1 -1
  97. package/dist/worker/console/static/assets/{arc-Bj2M8iO5.js → arc-CyIlrwZw.js} +1 -1
  98. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CLlXe4-6.js → architectureDiagram-T3A2C74G-Bo4tobhH.js} +1 -1
  99. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-psEp5xH0.js → blockDiagram-VBNYF7ZC-Dfpow9gu.js} +1 -1
  100. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DeKcOCGJ.js → c4Diagram-5PPSVZJV-DPmzG_B4.js} +1 -1
  101. package/dist/worker/console/static/assets/channel-DSrJAn0-.js +1 -0
  102. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-K0C744p1.js → chunk-2GRJ4B5K-pKQpB1UW.js} +1 -1
  103. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-xbNw4J9-.js → chunk-2Q5K7J3B-5n9YYquZ.js} +1 -1
  104. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLaSDUO.js → chunk-5RXB4S5H-DP3CtA2a.js} +1 -1
  105. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CtiPlKel.js → chunk-5VM5RSS4-DYxMJPUy.js} +1 -1
  106. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DZtolir7.js → chunk-6Q2QTUOP-CS3D50Io.js} +1 -1
  107. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CPcdNeew.js → chunk-GF5L2VYU-gSdDfo5_.js} +1 -1
  108. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-NgHc6V37.js → chunk-JWPE2WC7-A48q0ZNt.js} +1 -1
  109. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DQ_T-hg8.js → chunk-KBJHAD2P-ow8Mm3DY.js} +1 -1
  110. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DgLsxcVP.js → chunk-RYQCIY6F-CMKfLWYE.js} +1 -1
  111. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-UrVoM9z1.js → chunk-XXDRQBXY-BiTBdQPX.js} +1 -1
  112. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DeMmPl0_.js +1 -0
  113. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DeMmPl0_.js +1 -0
  114. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CLkYvTb3.js → cose-bilkent-JH36ORCC-Cm7exRz_.js} +1 -1
  115. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BwT_xKrE.js → cynefin-VYW2F7L2-D9O5qGOu.js} +1 -1
  116. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bi9tuzif.js → cynefinDiagram-MW4NZA55-CkvQnako.js} +1 -1
  117. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BCIqkWBV.js → dagre-VZM6K2ZE-B1rzp7CB.js} +1 -1
  118. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dip6l9_Z.js → diagram-7IWD3JNH-BP07Ipcc.js} +1 -1
  119. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B-xkh_wK.js → diagram-B4RE2ZJO-BlPzweQb.js} +1 -1
  120. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DZO0kTt_.js → diagram-LBJQPF4R-CxPa7n0S.js} +1 -1
  121. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D6ZplNbZ.js → diagram-Q27KOJAE-CMTZs53A.js} +1 -1
  122. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPekbhoS.js → diagram-UB23O5K3-CxG_X52r.js} +1 -1
  123. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BtmaJpK5.js → ebnfDiagram-BXEA7PRR-D8axtJM0.js} +1 -1
  124. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-6DS0Xc44.js → erDiagram-JOGREHBK-DIsGzn7b.js} +1 -1
  125. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CihnROSm.js → flowDiagram-UKHOOZJN-CU9zkDG0.js} +1 -1
  126. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CZC4zOE2.js → ganttDiagram-PKOTCBZU-DCjTmz5P.js} +1 -1
  127. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js → gitGraphDiagram-DS77QQ5N-BksdmFzg.js} +1 -1
  128. package/dist/worker/console/static/assets/index-B-O5ChYq.css +1 -0
  129. package/dist/worker/console/static/assets/index-CfnY8AQx.js +407 -0
  130. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DlSl4BGx.js → infoDiagram-6WML65LV-CGzzzJtL.js} +1 -1
  131. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-snnzFl_U.js → ishikawaDiagram-WSZJBQD7-BdseB80N.js} +1 -1
  132. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BDE7qpMx.js → journeyDiagram-NVQOT4AX-DM9gsgha.js} +1 -1
  133. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CD2Ci04G.js → kanban-definition-27J2QSJJ-3q-_9R2b.js} +1 -1
  134. package/dist/worker/console/static/assets/{linear-DdnapKIH.js → linear-B8N-Mxsd.js} +1 -1
  135. package/dist/worker/console/static/assets/{mermaid.core-BVjAT9b8.js → mermaid.core-EPIHUUsu.js} +5 -5
  136. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-D0yJk-zA.js → mindmap-definition-FAOFIHXS-CxwO12aa.js} +1 -1
  137. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVo9tFP-.js → pegDiagram-VL7TDLO6-bPqbVX6Y.js} +1 -1
  138. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DnOV-mZ_.js → pieDiagram-7S7Q4E2Y-KzqIvzeX.js} +1 -1
  139. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CzUJo58i.js → quadrantDiagram-CIZ2JOQS-CyofpWiV.js} +1 -1
  140. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Bvikrolh.js → railroadDiagram-AXF67PYL-cTWJvLTP.js} +1 -1
  141. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DtaSVCap.js → requirementDiagram-LRYGKXZP-BK--q27B.js} +1 -1
  142. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C2c9A0wW.js → sankeyDiagram-W5VNT64P-C0SDOHXK.js} +1 -1
  143. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DmXJcU7r.js → sequenceDiagram-SI44F4Z6-Cong6YIo.js} +1 -1
  144. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B4GUFW92.js → sizeCapture-X5ZJPWSS-DUVkgZx8.js} +1 -1
  145. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Dsad2MXf.js → stateDiagram-OKZ733FA-C7XgxuZg.js} +1 -1
  146. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Dzbnd5oX.js +1 -0
  147. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DGq48Fbi.js → swimlanes-SLNWSIFB-D9Ayvwcy.js} +2 -2
  148. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BY0hHk6G.js +8 -0
  149. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CSSi6OFf.js → timeline-definition-Z64GVDOM-Byb000cH.js} +1 -1
  150. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BqyzPrWv.js → vennDiagram-T6HMQDX7-DMLegPt4.js} +1 -1
  151. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DlznVb6S.js → wardleyDiagram-T6FBY63Y-ChMMeOsP.js} +1 -1
  152. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CfBcgJ_K.js → xychartDiagram-ELKLHX3M-bEMEPisW.js} +1 -1
  153. package/dist/worker/console/static/index.html +2 -2
  154. package/dist/worker/console/static-src/active-run-badge.js +17 -0
  155. package/dist/worker/console/static-src/app/console-types.js +68 -4
  156. package/dist/worker/console/static-src/app/useConsoleShell.js +30 -12
  157. package/dist/worker/console/static-src/app/useOperatorActions.js +41 -6
  158. package/dist/worker/console/static-src/app/useRecoveryConsole.js +45 -10
  159. package/dist/worker/console/static-src/app/useRunProgress.js +47 -0
  160. package/dist/worker/console/static-src/app/useTaskWizard.js +74 -2
  161. package/dist/worker/console/static-src/night/useNightBoard.js +8 -5
  162. package/dist/worker/console/static-src/operator-chat/cards/failure-category-advice.js +25 -0
  163. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +140 -8
  164. package/dist/worker/console/static-src/operator-chat/details-dag-actions.js +122 -0
  165. package/dist/worker/console/static-src/operator-chat/input-history.js +76 -0
  166. package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
  167. package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
  168. package/dist/worker/console/static-src/operator-chat/runtime-selection-labels.js +27 -0
  169. package/dist/worker/console/static-src/operator-chat/turn-submission.js +16 -3
  170. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +168 -72
  171. package/dist/worker/console/static-src/operator-chat/useChatStream.js +102 -21
  172. package/dist/worker/console/static-src/operator-chat/useChatThread.js +184 -4
  173. package/dist/worker/console/static-src/operator-chat/useComposer.js +32 -0
  174. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +63 -9
  175. package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
  176. package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -3
  177. package/dist/worker/console/static-src/pages/tasks/run-id-resolution.js +79 -0
  178. package/dist/worker/console/static-src/pages/tasks/run-ownership-verify.js +23 -0
  179. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +110 -0
  180. package/dist/worker/console/static-src/shell/useWorkspaces.js +299 -0
  181. package/dist/worker/console/static-src/shell/workspace-route.js +337 -0
  182. package/dist/worker/console/workspace-context.js +344 -0
  183. package/dist/worker/console/workspace-registry.js +214 -0
  184. package/dist/worker/loop-agent/loop-agent-client.js +7 -3
  185. package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
  186. package/dist/worker/materialize/harness-task-lineage.js +5 -2
  187. package/dist/worker/observability/init-runtime-activity.js +26 -0
  188. package/dist/worker/observability/read-model.js +22 -0
  189. package/dist/worker/observe/node-input.js +160 -3
  190. package/dist/worker/observe/node-process.js +377 -0
  191. package/dist/worker/observe/routes.js +224 -3
  192. package/dist/worker/observe/server.js +4 -0
  193. package/dist/worker/observe/shell-handler-keys.js +34 -0
  194. package/dist/worker/observe/static/api.js +90 -4
  195. package/dist/worker/observe/static/app.js +18 -70
  196. package/dist/worker/observe/static/constants.js +8 -1
  197. package/dist/worker/observe/static/dag-history-labels.js +4 -0
  198. package/dist/worker/observe/static/dag-node-purpose.d.ts +6 -0
  199. package/dist/worker/observe/static/dag-node-purpose.js +208 -0
  200. package/dist/worker/observe/static/format.js +60 -0
  201. package/dist/worker/observe/static/index.html +6 -1
  202. package/dist/worker/observe/static/inspect-workspace.js +307 -0
  203. package/dist/worker/observe/static/markdown-render.js +20 -1
  204. package/dist/worker/observe/static/operator-chrome.css +145 -20
  205. package/dist/worker/observe/static/operator-chrome.d.ts +20 -3
  206. package/dist/worker/observe/static/operator-chrome.js +330 -96
  207. package/dist/worker/observe/static/prompt-restart-candidates.d.ts +18 -0
  208. package/dist/worker/observe/static/prompt-restart-candidates.js +36 -0
  209. package/dist/worker/observe/static/router.d.ts +46 -0
  210. package/dist/worker/observe/static/router.js +25 -1
  211. package/dist/worker/observe/static/state.d.ts +50 -0
  212. package/dist/worker/observe/static/state.js +184 -1
  213. package/dist/worker/observe/static/styles.css +395 -0
  214. package/dist/worker/observe/static/views/dag-graph.js +4 -2
  215. package/dist/worker/observe/static/views/dag-inspector.js +1067 -9
  216. package/dist/worker/observe/static/views/dag.d.ts +13 -0
  217. package/dist/worker/observe/static/views/dag.js +14 -5
  218. package/dist/worker/observe/static/views/dashboard.js +6 -4
  219. package/dist/worker/observe/static/views/failures.js +5 -2
  220. package/dist/worker/observe/static/views/night.js +2 -2
  221. package/dist/worker/observe/static/views/pool.js +1 -0
  222. package/dist/worker/observe/static/views/run.js +3 -1
  223. package/dist/worker/observe/static/views/session-timeline.js +78 -9
  224. package/dist/worker/observe/static/views/task.js +56 -1
  225. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +49 -3
  226. package/dist/workflows/dag/backend-test-markdown-workflow.js +176 -1
  227. package/dist/workflows/dag/backend-test-pytest-collection.js +98 -14
  228. package/dist/workflows/dag/backend-test-writer-completeness.js +10 -5
  229. package/dist/workflows/dag/contract-output-registry.js +15 -0
  230. package/dist/workflows/dag/contract-validator-registrations.js +1 -2
  231. package/dist/workflows/dag/dynamic-runtime/loop-until.js +1 -1
  232. package/dist/workflows/dag/dynamic-runtime/map.js +1 -1
  233. package/dist/workflows/dag/failure-category.js +7 -116
  234. package/dist/workflows/dag/frontend-closeout.js +221 -0
  235. package/dist/workflows/dag/frontend-design-policy.js +400 -0
  236. package/dist/workflows/dag/frontend-human-decision.js +182 -0
  237. package/dist/workflows/dag/frontend-implementation-contract.js +538 -166
  238. package/dist/workflows/dag/frontend-plan-render.js +24 -0
  239. package/dist/workflows/dag/frontend-prewrite-gate.js +388 -392
  240. package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
  241. package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
  242. package/dist/workflows/dag/frontend-recovery-controller.js +202 -0
  243. package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
  244. package/dist/workflows/dag/frontend-recovery-plan.js +17 -10
  245. package/dist/workflows/dag/frontend-recovery-run.js +33 -20
  246. package/dist/workflows/dag/frontend-repair.js +7 -424
  247. package/dist/workflows/dag/frontend-review-context.js +288 -14
  248. package/dist/workflows/dag/frontend-review-findings.js +270 -0
  249. package/dist/workflows/dag/frontend-risk.js +15 -2
  250. package/dist/workflows/dag/frontend-shadow-dual-write.js +814 -0
  251. package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
  252. package/dist/workflows/dag/frontend-shape-facts.js +409 -0
  253. package/dist/workflows/dag/frontend-shape.js +427 -0
  254. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
  255. package/dist/workflows/dag/frontend-split-application-service.js +203 -0
  256. package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
  257. package/dist/workflows/dag/frontend-test-case-checklist.js +30 -4
  258. package/dist/workflows/dag/frontend-test-case-manifest.js +11 -4
  259. package/dist/workflows/dag/frontend-test-case-quality.js +11 -16
  260. package/dist/workflows/dag/frontend-test-environment-probe.js +230 -0
  261. package/dist/workflows/dag/frontend-test-html-report.js +3 -1
  262. package/dist/workflows/dag/frontend-test-l5-report.js +3 -1
  263. package/dist/workflows/dag/frontend-test-layout.js +159 -0
  264. package/dist/workflows/dag/frontend-test-markdown.js +61 -0
  265. package/dist/workflows/dag/frontend-test-result-contract.js +188 -42
  266. package/dist/workflows/dag/frontend-test-standard-scenarios.js +70 -0
  267. package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
  268. package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
  269. package/dist/workflows/dag/frontend-verification-trace.js +52 -17
  270. package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
  271. package/dist/workflows/dag/frontend-writer-admission.js +272 -0
  272. package/dist/workflows/dag/frontend-writer-status.js +244 -0
  273. package/dist/workflows/dag/init-hybrid.js +984 -613
  274. package/dist/workflows/dag/interrupt-request.js +10 -3
  275. package/dist/workflows/dag/lifecycle.js +3 -3
  276. package/dist/workflows/dag/node-execution.js +468 -58
  277. package/dist/workflows/dag/prompt.js +44 -19
  278. package/dist/workflows/dag/recovery-lease.js +80 -0
  279. package/dist/workflows/dag/report.js +37 -1
  280. package/dist/workflows/dag/rerun-feedback.js +124 -1
  281. package/dist/workflows/dag/rerun-plan.js +144 -5
  282. package/dist/workflows/dag/rerun-run.js +81 -6
  283. package/dist/workflows/dag/rerun-task.js +29 -0
  284. package/dist/workflows/dag/retry-policy.js +318 -8
  285. package/dist/workflows/dag/runner.js +429 -122
  286. package/dist/workflows/dag/scheduler.js +114 -16
  287. package/dist/workflows/dag/structured-output-repair.js +712 -0
  288. package/dist/workflows/dag/types.js +321 -31
  289. package/dist/workflows/dag/upstream-artifacts.js +0 -4
  290. package/dist/workflows/dag/validate.js +92 -32
  291. package/docs/README.md +2 -0
  292. package/docs/architecture/evolution.md +45 -0
  293. package/docs/init-surface.manifest.json +9 -0
  294. package/docs/operations/README.md +1 -1
  295. package/docs/operations/local-development-environment.md +21 -0
  296. package/docs/templates/README.md +2 -1
  297. package/docs/templates/agent-dag-report.schema.json +8 -2
  298. package/docs/templates/agent-dag.schema.json +45 -1
  299. package/docs/templates/frontend-implementation-contract.schema.json +684 -24
  300. package/docs/templates/frontend-test-case-checklist.md +2 -2
  301. package/docs/templates/frontend-test-dag.json +8 -10
  302. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
  303. package/docs/templates/init-managed-agents.md +13 -3
  304. package/docs/templates/spec-registry.schema.json +45 -0
  305. package/harness.json +3 -3
  306. package/package.json +7 -1
  307. package/scripts/next-info.mjs +356 -0
  308. package/scripts/next-publish-gate.mjs +238 -0
  309. package/scripts/release-source-binding.mjs +251 -0
  310. package/skills/codebase-scout/SKILL.md +1 -1
  311. package/skills/fe-test-ui-scout/SKILL.md +65 -0
  312. package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
  313. package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
  314. package/skills/frontend-bounded-implement/SKILL.md +8 -14
  315. package/skills/frontend-design-review/SKILL.md +20 -41
  316. package/skills/frontend-implementation/SKILL.md +3 -4
  317. package/skills/frontend-implementation/references/design-spec.md +15 -10
  318. package/skills/frontend-implementation/references/node-contracts.md +23 -13
  319. package/skills/frontend-review/SKILL.md +22 -14
  320. package/skills/frontend-review/references/review-findings.md +6 -7
  321. package/skills/loop-agent/references/command-reference.md +12 -4
  322. package/skills/loop-agent/references/hybrid-dag.md +8 -1
  323. package/skills/playwright-cli/SKILL.md +23 -1
  324. package/skills/playwright-cli-case-generator/SKILL.md +29 -8
  325. package/dist/worker/console/static/assets/channel-CPF4N7pf.js +0 -1
  326. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +0 -1
  327. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +0 -1
  328. package/dist/worker/console/static/assets/index-DTZOKgAn.js +0 -404
  329. package/dist/worker/console/static/assets/index-Ya5FE7cD.css +0 -1
  330. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +0 -1
  331. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +0 -8
@@ -1,8 +1,8 @@
1
1
  import { z } from "zod";
2
- import { isOpenspecSpecFilePath } from "../../shared/openspec-spec.js";
2
+ import { DEFAULT_FRONTEND_SPEC_ROOTS, isFrontendSpecFilePath, isValidFrontendSpecRoot, OPENSPEC_SPEC_EXT_RE, } from "../../shared/openspec-spec.js";
3
3
  import { campaignBudgetSchema, } from "../../application/evaluation/budget.js";
4
4
  import { assertDagPromptSourceRule } from "./prompt-source.js";
5
- import { dagRetryPolicySchema } from "./retry-policy.js";
5
+ import { dagRetryPolicySchema, TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE, } from "./retry-policy.js";
6
6
  import { dagLivenessPolicySchema, } from "./liveness-policy.js";
7
7
  import { dagOutputProtocolSchema } from "./output-protocol.js";
8
8
  export const dagComplexitySchema = z.enum(["HIGH", "MED", "LOW"]);
@@ -10,6 +10,18 @@ export const dagNodeExecutorSchema = z.enum(["pi", "shell", "static"]);
10
10
  export const CURSOR_DAG_EXECUTOR_REMOVED_ERROR = 'executor "cursor" is no longer supported; regenerate the DAG with Pi-only writers (implement-pi / repair-pi)';
11
11
  export const CURSOR_EXECUTOR_MODELS_REMOVED_ERROR = "executorModels.cursor is no longer supported; use executorModels.pi only";
12
12
  export const dagToolProfileSchema = z.enum(["read-only", "write"]);
13
+ /**
14
+ * Frozen Pi extension short ids for backend implementation DAGs (plan
15
+ * 2026-08-21 D2): the DAG carries only these ids; the executor resolves them
16
+ * against the Pi settings package inventory at run time. Adding a package
17
+ * requires changing this enum and the plan.
18
+ */
19
+ export const dagPiExtensionIdSchema = z.enum(["pi-codegraph", "pi-lens"]);
20
+ /** Node-level explicit Pi extension allowlist (omitted = all off, R8.1). */
21
+ export const dagPiExtensionsSchema = z
22
+ .array(dagPiExtensionIdSchema)
23
+ .min(1)
24
+ .transform((ids) => Array.from(new Set(ids)));
13
25
  /** Static command capabilities only; tasks cannot inject executables or shell prefixes. */
14
26
  export const dagCommandCapabilitySchema = z.enum(["playwright-cli"]);
15
27
  export const dagCommandPolicySchema = z.discriminatedUnion("mode", [
@@ -173,7 +185,16 @@ const dagFrontendNodeIdSchema = z
173
185
  .regex(/^[a-z][a-z0-9-]*$/, "frontend node id must be kebab-case");
174
186
  const openspecCandidatePathSchema = z
175
187
  .string()
176
- .refine((candidate) => !candidate.includes("\\") && isOpenspecSpecFilePath(candidate), "openspec candidate must be a repo-relative supported file under openspec/schemas/, openspec/project-specs/, or ai_workspace/");
188
+ .refine((candidate) => !candidate.includes("\\") &&
189
+ !candidate.startsWith("/") &&
190
+ !candidate.split("/").includes("..") &&
191
+ OPENSPEC_SPEC_EXT_RE.test(candidate), "openspec candidate must be a repo-relative supported specification file");
192
+ const openspecCandidateSnapshotSchema = z
193
+ .object({
194
+ path: openspecCandidatePathSchema,
195
+ sha256: z.string().regex(/^[a-f0-9]{64}$/),
196
+ })
197
+ .strict();
177
198
  export const dagFrontendPrewriteGateSchema = z.object({
178
199
  schemaVersion: z.literal(1),
179
200
  planFromNodeId: dagFrontendNodeIdSchema,
@@ -192,7 +213,24 @@ export const dagFrontendPrewriteGateSchema = z.object({
192
213
  outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
193
214
  requireSourceFreshness: z.literal(true),
194
215
  implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
216
+ /**
217
+ * Generation-frozen roots that bound custom normative directories. Omitted
218
+ * legacy DAGs retain the canonical OpenSpec + ai_workspace roots.
219
+ */
220
+ openspecSpecRoots: z
221
+ .array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
222
+ .optional(),
195
223
  openspecCandidatePaths: z.array(openspecCandidatePathSchema).default([]),
224
+ /** Read-only selector output; omitted for scan-strict and legacy DAGs. */
225
+ openspecSelectionNodeId: dagFrontendNodeIdSchema.optional(),
226
+ /** Contract-declared and source-explicit paths that cannot be downgraded. */
227
+ openspecMandatoryPaths: z.array(openspecCandidatePathSchema).optional(),
228
+ /**
229
+ * Content fingerprints frozen with the generation-time OpenSpec scope. New
230
+ * DAGs use these to reject a plan whose cited specification changed after it
231
+ * was read; legacy DAGs without the field retain existence-only drift checks.
232
+ */
233
+ openspecCandidateSnapshots: z.array(openspecCandidateSnapshotSchema).optional(),
196
234
  /**
197
235
  * Generation-frozen component/theme specification bucket. Derived from
198
236
  * `designEvidence.classified.component ∪ theme ∪ rule.components` at DAG
@@ -237,14 +275,28 @@ export const dagFrontendPrewriteGateSchema = z.object({
237
275
  scanStrict: z.array(openspecCandidatePathSchema).default([]),
238
276
  })
239
277
  .optional(),
278
+ }).superRefine((gate, context) => {
279
+ const roots = gate.openspecSpecRoots ?? DEFAULT_FRONTEND_SPEC_ROOTS;
280
+ const candidateGroups = [
281
+ ["openspecCandidatePaths", gate.openspecCandidatePaths],
282
+ ["openspecMandatoryPaths", gate.openspecMandatoryPaths],
283
+ ["componentSpecCandidatePaths", gate.componentSpecCandidatePaths],
284
+ ["openspecCandidateSources.declared", gate.openspecCandidateSources?.declared],
285
+ ["openspecCandidateSources.taskSourceCited", gate.openspecCandidateSources?.taskSourceCited],
286
+ ["openspecCandidateSources.scanStrict", gate.openspecCandidateSources?.scanStrict],
287
+ ];
288
+ for (const [field, paths] of candidateGroups) {
289
+ for (const [index, candidate] of (paths ?? []).entries()) {
290
+ if (!isFrontendSpecFilePath(candidate, roots)) {
291
+ context.addIssue({
292
+ code: z.ZodIssueCode.custom,
293
+ path: [...field.split("."), index],
294
+ message: "openspec candidate must be a supported file under the generation-frozen openspec spec roots",
295
+ });
296
+ }
297
+ }
298
+ }
240
299
  });
241
- export const dagFrontendLintBaselineSchema = z
242
- .object({
243
- schemaVersion: z.literal(1),
244
- lintCommands: z.array(z.string().min(1)).min(1),
245
- lintEvidence: dagShellVerifyEvidenceSchema,
246
- })
247
- .strict();
248
300
  export const dagFrontendVerificationBundleSchema = z
249
301
  .object({
250
302
  schemaVersion: z.literal(1),
@@ -258,7 +310,9 @@ export const dagFrontendVerificationBundleSchema = z
258
310
  behaviorEvidence: dagShellVerifyEvidenceSchema,
259
311
  lintBaselineNodeId: dagFrontendNodeIdSchema.optional(),
260
312
  writerNodeIds: z.array(dagFrontendNodeIdSchema).optional(),
261
- mode: z.enum(["initial", "repair"]),
313
+ /** M8: verify-shell only ever runs in initial mode; a failure is terminal
314
+ * (routes to recovery) and never selects a same-run repair branch. */
315
+ mode: z.literal("initial"),
262
316
  })
263
317
  .superRefine((bundle, context) => {
264
318
  const groups = [
@@ -333,6 +387,135 @@ export const dagFrontendReviewContextSchema = z.object({
333
387
  schemaVersion: z.literal(1),
334
388
  requireBaseline: z.literal(true),
335
389
  });
390
+ /**
391
+ * Deterministic frontend contract-import shell (micro topology). Re-validates
392
+ * the generation-frozen managed Contract's source/binding/schema freshness and
393
+ * emits a digest. It never invokes a model and never rewrites requirements —
394
+ * micro requires a pre-validated managed Contract, not natural-language intake.
395
+ */
396
+ export const dagFrontendContractImportSchema = z.object({
397
+ schemaVersion: z.literal(1),
398
+ artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
399
+ outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
400
+ requireSourceFreshness: z.literal(true),
401
+ });
402
+ /**
403
+ * Deterministic frontend design-policy shell (M8). Materializes the canonical
404
+ * implementation contract from the plan node and evaluates the design policy
405
+ * (Mock strategy, source freshness, component spec candidates, writeSet
406
+ * patterns, allowed dependencies). Runs BEFORE frontend-design-review-pi, so it
407
+ * never consumes a design verdict; the verdict is enforced by the writer
408
+ * admission shell instead. Replaces the prewrite-gate authorization path.
409
+ */
410
+ export const dagFrontendDesignPolicySchema = z
411
+ .object({
412
+ schemaVersion: z.literal(1),
413
+ planFromNodeId: dagFrontendNodeIdSchema,
414
+ requiredRequirementIds: z
415
+ .array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/))
416
+ .default([]),
417
+ allowedMockStrategies: z
418
+ .array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"]))
419
+ .min(1),
420
+ /** Frozen Mock verification command labels the DAG will actually execute. */
421
+ mockCommandLabels: z.array(z.string()).default([]),
422
+ artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
423
+ outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
424
+ requireSourceFreshness: z.literal(true),
425
+ implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
426
+ /** Generation-frozen roots that bound custom normative directories. */
427
+ openspecSpecRoots: z
428
+ .array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
429
+ .optional(),
430
+ openspecCandidatePaths: z.array(openspecCandidatePathSchema).default([]),
431
+ /** Read-only selector output; omitted for scan-strict and legacy DAGs. */
432
+ openspecSelectionNodeId: dagFrontendNodeIdSchema.optional(),
433
+ /** Contract-declared and source-explicit paths that cannot be downgraded. */
434
+ openspecMandatoryPaths: z.array(openspecCandidatePathSchema).optional(),
435
+ openspecCandidateSnapshots: z
436
+ .array(openspecCandidateSnapshotSchema)
437
+ .optional(),
438
+ /**
439
+ * Generation-frozen component/theme specification bucket. Derived from
440
+ * `designEvidence.classified.component ∪ theme ∪ rule.components` at DAG
441
+ * generation. When non-empty and the canonical contract has UI-visible
442
+ * work, the design policy requires a non-empty `uiComponentChoices` and
443
+ * cross-checks each `specReference.path` against this set + the effective
444
+ * plan openspec-citations block.
445
+ */
446
+ componentSpecCandidatePaths: z.array(openspecCandidatePathSchema).optional(),
447
+ /** OpenSpec gate policy (cited | scan-strict); generation always writes it. */
448
+ openspecPolicy: z.enum(["cited", "scan-strict"]).optional(),
449
+ /** Generation-frozen candidate source metadata (diagnostic). */
450
+ openspecCandidateSources: z
451
+ .object({
452
+ declared: z.array(openspecCandidatePathSchema).default([]),
453
+ taskSourceCited: z.array(openspecCandidatePathSchema).default([]),
454
+ scanStrict: z.array(openspecCandidatePathSchema).default([]),
455
+ })
456
+ .optional(),
457
+ /** Dependency identifiers authorized at generation time (empty = none). */
458
+ allowedDependencies: z.array(z.string()).default([]),
459
+ })
460
+ .superRefine((gate, context) => {
461
+ const roots = gate.openspecSpecRoots ?? DEFAULT_FRONTEND_SPEC_ROOTS;
462
+ const candidateGroups = [
463
+ ["openspecCandidatePaths", gate.openspecCandidatePaths],
464
+ ["openspecMandatoryPaths", gate.openspecMandatoryPaths],
465
+ ["componentSpecCandidatePaths", gate.componentSpecCandidatePaths],
466
+ ["openspecCandidateSources.declared", gate.openspecCandidateSources?.declared],
467
+ ["openspecCandidateSources.taskSourceCited", gate.openspecCandidateSources?.taskSourceCited],
468
+ ["openspecCandidateSources.scanStrict", gate.openspecCandidateSources?.scanStrict],
469
+ ];
470
+ for (const [field, paths] of candidateGroups) {
471
+ for (const [index, candidate] of (paths ?? []).entries()) {
472
+ if (!isFrontendSpecFilePath(candidate, roots)) {
473
+ context.addIssue({
474
+ code: z.ZodIssueCode.custom,
475
+ path: [...field.split("."), index],
476
+ message: "openspec candidate must be a supported file under the generation-frozen openspec spec roots",
477
+ });
478
+ }
479
+ }
480
+ }
481
+ });
482
+ /**
483
+ * Deterministic frontend writer-admission shell (M8). Runs after
484
+ * frontend-design-review-pi: freezes the writer baseline, derives the concrete
485
+ * writeSet, folds the design-policy result + design verdict into admission,
486
+ * and writes contracts/frontend-writer-admission-result.json
487
+ * (schemaId frontend-writer-admission-shell-v1).
488
+ */
489
+ export const dagFrontendWriterAdmissionShellSchema = z
490
+ .object({
491
+ schemaVersion: z.literal(1),
492
+ /** Design verdict source (frontend-design-review-pi); pass is enforced.
493
+ * Omitted in small topology, which has no design review node. */
494
+ designReviewFromNodeId: dagFrontendNodeIdSchema.optional(),
495
+ /** Frozen command labels the verification bundle will execute. */
496
+ frozenCommandLabels: z.array(z.string()).default([]),
497
+ allowedMockStrategies: z
498
+ .array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"]))
499
+ .min(1),
500
+ /** Writer-preceding lint commands; baseline is materialized here (R5). */
501
+ lintCommands: z.array(z.string().min(1)).optional(),
502
+ lintEvidence: dagShellVerifyEvidenceSchema.optional(),
503
+ })
504
+ .superRefine((admission, context) => {
505
+ if ((admission.lintCommands?.length ?? 0) > 0 && !admission.lintEvidence) {
506
+ context.addIssue({
507
+ code: z.ZodIssueCode.custom,
508
+ path: ["lintEvidence"],
509
+ message: "lintEvidence is required when lintCommands are present",
510
+ });
511
+ }
512
+ });
513
+ /** Deterministic frontend closeout shell (M8). Renders the closeout from
514
+ * committed facts only (review context + typed review terminal + trace). */
515
+ export const dagFrontendCloseoutSchema = z.object({
516
+ schemaVersion: z.literal(1),
517
+ reviewFromNodeId: dagFrontendNodeIdSchema,
518
+ });
336
519
  export const ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
337
520
  export const dagVersionSchema = z
338
521
  .union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)])
@@ -370,7 +553,7 @@ export const dagWritePolicySchema = z.enum([
370
553
  "none",
371
554
  ]);
372
555
  /** Git/post-diff write guard intensity for exclusive Pi writers. */
373
- export const dagWriteGuardPolicySchema = z.enum(["full", "tools-only"]);
556
+ export const dagWriteGuardPolicySchema = z.enum(["full", "tools-only", "filesystem-only"]);
374
557
  /**
375
558
  * Fail-closed outcome/diff consistency contract for bounded Pi writers.
376
559
  * The writer must begin with IMPLEMENTATION_OUTCOME: changed,
@@ -380,7 +563,14 @@ export const dagWriteGuardPolicySchema = z.enum(["full", "tools-only"]);
380
563
  */
381
564
  export const dagWriterOutcomePolicySchema = z
382
565
  .object({
383
- type: z.literal("implementation-outcome-v1"),
566
+ /**
567
+ * Protocol face: `implementation-outcome-v1` keeps the legacy
568
+ * IMPLEMENTATION_OUTCOME first-line protocol (backend/README/module
569
+ * writers + frontend-repair-pi); `frontend-facts-v1` derives the status
570
+ * from mechanical facts (write-tool events / run delta / write guard /
571
+ * requirement coverage / focused-check) and never reads the first line.
572
+ */
573
+ type: z.enum(["implementation-outcome-v1", "frontend-facts-v1"]),
384
574
  /** Generation writers may forbid already-satisfied/no-diff completion. */
385
575
  requireChangedFiles: z.boolean().optional(),
386
576
  })
@@ -427,6 +617,8 @@ export const dagBackendTestPipelineSchema = z.enum([
427
617
  "ingest-backend-test-gap",
428
618
  ]);
429
619
  export const dagFrontendBrowserToolPreflightSchema = z.object({}).strict();
620
+ export const dagFrontendTestStandardScenariosSchema = z.object({}).strict();
621
+ export const dagFrontendTestEnvironmentProbeSchema = z.object({}).strict();
430
622
  export const dagFrontendTestEvidenceValidationSchema = z.object({}).strict();
431
623
  export const dagFrontendTestCaseChecklistSchema = z.object({}).strict();
432
624
  export const dagFrontendTestHtmlReportSchema = z.object({}).strict();
@@ -511,12 +703,17 @@ export const dagShellConfigSchema = z.object({
511
703
  .optional(),
512
704
  requirementCoverageGate: dagRequirementCoverageGateSchema.optional(),
513
705
  jsonArtifactGate: dagJsonArtifactGateSchema.optional(),
706
+ frontendDesignPolicy: dagFrontendDesignPolicySchema.optional(),
707
+ frontendWriterAdmission: dagFrontendWriterAdmissionShellSchema.optional(),
514
708
  frontendPrewriteGate: dagFrontendPrewriteGateSchema.optional(),
515
- frontendLintBaseline: dagFrontendLintBaselineSchema.optional(),
516
709
  frontendVerificationBundle: dagFrontendVerificationBundleSchema.optional(),
517
710
  frontendReviewContext: dagFrontendReviewContextSchema.optional(),
711
+ frontendContractImport: dagFrontendContractImportSchema.optional(),
712
+ frontendCloseout: dagFrontendCloseoutSchema.optional(),
518
713
  frontendTestCaseChecklist: dagFrontendTestCaseChecklistSchema.optional(),
519
714
  frontendBrowserToolPreflight: dagFrontendBrowserToolPreflightSchema.optional(),
715
+ frontendTestStandardScenarios: dagFrontendTestStandardScenariosSchema.optional(),
716
+ frontendTestEnvironmentProbe: dagFrontendTestEnvironmentProbeSchema.optional(),
520
717
  frontendTestEvidenceValidation: dagFrontendTestEvidenceValidationSchema.optional(),
521
718
  finalWriteSetApprovalGate: dagFinalWriteSetApprovalGateSchema.optional(),
522
719
  frontendTestL5Report: z.object({}).strict().optional(),
@@ -749,6 +946,26 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
749
946
  role: dagRoleSchema.optional(),
750
947
  skills: z.array(z.string()).optional(),
751
948
  toolProfile: dagToolProfileSchema.optional(),
949
+ /** Bounded read-only discovery budget for nodes that inspect a repository. */
950
+ readBudget: z
951
+ .object({
952
+ maxFiles: z.number().int().positive(),
953
+ maxBytes: z.number().int().positive(),
954
+ maxMs: z.number().int().positive().optional(),
955
+ /** Maximum read/grep/find/ls calls. */
956
+ maxOperations: z.number().int().positive().optional(),
957
+ /** On any read budget exhaustion, return concise completion guidance instead of failing the node. */
958
+ onExhaustion: z.enum(["return-guidance"]).optional(),
959
+ })
960
+ .strict()
961
+ .optional(),
962
+ /**
963
+ * Explicit Pi extension allowlist (backend implementation DAGs only):
964
+ * frozen short ids resolved at run time against the Pi settings package
965
+ * inventory. Omitted = extension discovery stays fully closed (R8.1).
966
+ * Only `executor: "pi"` nodes may declare it (validated fail-closed).
967
+ */
968
+ piExtensions: dagPiExtensionsSchema.optional(),
752
969
  /** Default deny: file write (toolProfile=write) does not grant command execution. */
753
970
  commandPolicy: dagCommandPolicySchema.optional(),
754
971
  writePolicy: dagWritePolicySchema.optional(),
@@ -796,12 +1013,6 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
796
1013
  }
797
1014
  })
798
1015
  .optional(),
799
- /**
800
- * Opt-in upstream context mode for nodes that must consume a validated,
801
- * hash-bound artifact rather than a potentially truncated text preview.
802
- * The default remains preview mode for every existing DAG.
803
- */
804
- artifactFirstUpstreamNodeIds: z.array(z.string()).optional(),
805
1016
  /**
806
1017
  * Fail-closed outcome/diff consistency contract for bounded Pi writers.
807
1018
  * The writer must begin with IMPLEMENTATION_OUTCOME: changed,
@@ -832,6 +1043,14 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
832
1043
  forbiddenPaths: z.array(z.string()).optional().default([]),
833
1044
  decisionGate: dagDecisionGateSchema.optional(),
834
1045
  retryPolicy: dagRetryPolicySchema.optional(),
1046
+ /**
1047
+ * Generation-path stamp for implicit same-run transient retry. Only the
1048
+ * three target templates stamp canonical final verify shells and
1049
+ * exclusive `implement-pi`. Zod-declared so parseDagSpec does not strip it.
1050
+ */
1051
+ transientRetryProfile: z
1052
+ .literal(TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE)
1053
+ .optional(),
835
1054
  /** Optional per-node adaptive liveness override (merged over defaults). */
836
1055
  livenessPolicy: dagLivenessPolicySchema,
837
1056
  dynamicExpansion: dagDynamicExpansionSchema.optional(),
@@ -865,20 +1084,51 @@ export const dagEvaluationBindingSchema = z
865
1084
  .strict();
866
1085
  /** Eval Lab Campaign Budget (W3.4); enforced by runner ledger when mode=hard. */
867
1086
  export const dagBudgetSchema = campaignBudgetSchema;
868
- export const dagSourceBindingSchema = z.object({
1087
+ export const dagSourceBindingSourceSchema = z.object({
1088
+ kind: z.enum(["requirement", "constraint", "reference"]),
1089
+ path: z.string().min(1),
1090
+ sha256: z
1091
+ .string()
1092
+ .regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex"),
1093
+ });
1094
+ /**
1095
+ * DagSourceBinding v1:无 ledger 字段(schemaVersion=1,.strict() 拒绝 ledger
1096
+ * 字段混入,不得以 v1+optional 冒充 v2)。非 frontend task / 无可解析引用时使用。
1097
+ */
1098
+ export const dagSourceBindingV1Schema = z
1099
+ .object({
869
1100
  schemaVersion: z.literal(1),
870
1101
  taskId: z.string().min(1),
871
- sources: z
872
- .array(z.object({
873
- kind: z.enum(["requirement", "constraint", "reference"]),
874
- path: z.string().min(1),
875
- sha256: z
876
- .string()
877
- .regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex"),
878
- }))
879
- .min(1),
1102
+ sources: z.array(dagSourceBindingSourceSchema).min(1),
880
1103
  requirementIds: z.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/)),
881
- });
1104
+ })
1105
+ .strict();
1106
+ /**
1107
+ * DagSourceBinding v2(20260824-frontend-source-fidelity-ledger-v1):仅
1108
+ * frontend-implementation 且存在可解析 requirement/acceptance 引用时产出;
1109
+ * ledgerPath/ledgerSha256/inputDigest/requirementToFragments 全部必填且完整,
1110
+ * 伪造或缺失任一字段被 schema/prewrite 拒绝(AC-002 / AC-FIDELITY-REPAIR-002)。
1111
+ */
1112
+ export const dagSourceBindingV2Schema = z
1113
+ .object({
1114
+ schemaVersion: z.literal(2),
1115
+ taskId: z.string().min(1),
1116
+ sources: z.array(dagSourceBindingSourceSchema).min(1),
1117
+ requirementIds: z.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/)),
1118
+ /** 受管 requirement-ledger.json 的 DAG 可解析路径(.harness/tasks/…/source/…)。 */
1119
+ ledgerPath: z.string().min(1),
1120
+ ledgerSha256: z.string().regex(/^[a-f0-9]{64}$/),
1121
+ inputDigest: z.string().regex(/^[a-f0-9]{64}$/),
1122
+ requirementToFragments: z.record(z.string(), z.array(z.string())),
1123
+ })
1124
+ .strict();
1125
+ export const dagSourceBindingSchema = z.discriminatedUnion("schemaVersion", [
1126
+ dagSourceBindingV1Schema,
1127
+ dagSourceBindingV2Schema,
1128
+ ]);
1129
+ export function isDagSourceBindingV2(binding) {
1130
+ return binding.schemaVersion === 2;
1131
+ }
882
1132
  const dagRerunFeedbackEvidencePathSchema = z
883
1133
  .string()
884
1134
  .min(1)
@@ -941,6 +1191,24 @@ export const dagSpecSchema = z
941
1191
  taskContractBinding: dagTaskContractBindingSchema.optional(),
942
1192
  /** Optional unresolved parent-run feedback for a full task rerun. */
943
1193
  rerunFeedback: dagRerunFeedbackSchema.optional(),
1194
+ /** Frontend recovery continuation quota (frozen at generation time from
1195
+ * task.json frontendRecovery.maxContinuations). Bounds how many times a
1196
+ * failed frontend run may auto-recover via M6 recovery operations before
1197
+ * the run stays failed and needs human intervention. */
1198
+ frontendRecovery: z
1199
+ .object({
1200
+ maxContinuations: z
1201
+ .number()
1202
+ .int()
1203
+ .min(1)
1204
+ .max(5)
1205
+ .optional()
1206
+ .default(1),
1207
+ })
1208
+ .strict()
1209
+ .optional(),
1210
+ /** Backend-test-only workspace mutation control; absent means Git. */
1211
+ backendTestWorkspaceControl: z.enum(["git", "filesystem-only"]).optional(),
944
1212
  /** Frozen backend-test artifact layout (plan A); absent = historical default testcase/ layout. */
945
1213
  backendTestLayout: z
946
1214
  .object({
@@ -953,6 +1221,18 @@ export const dagSpecSchema = z
953
1221
  isDefault: z.boolean(),
954
1222
  })
955
1223
  .optional(),
1224
+ /** Frozen frontend-test artifact layout; absent = historical testcase/frontend/ layout. */
1225
+ frontendTestLayout: z
1226
+ .object({
1227
+ testRoot: z.string(),
1228
+ ragDir: z.string(),
1229
+ casesDir: z.string(),
1230
+ evidenceDir: z.string(),
1231
+ reportsDir: z.string(),
1232
+ fixturesDir: z.string(),
1233
+ isDefault: z.boolean(),
1234
+ })
1235
+ .optional(),
956
1236
  /** Bound user shared-setup document (plan B); absent = no shared setup references expected. */
957
1237
  backendTestSharedSetup: z
958
1238
  .object({
@@ -1052,6 +1332,9 @@ export const FRONTEND_RECOVERY_RESULT_SCHEMA_VERSION = 1;
1052
1332
  * Phase 3a parents converge first, so `rollback-pending` is not produced and
1053
1333
  * was removed by AC-1; the phase starts at `child-staging` and ends at
1054
1334
  * `settled`.
1335
+ *
1336
+ * @deprecated Read-only compatibility only; the M6 operation controller no
1337
+ * longer uses this phase as the authoritative recovery entry point.
1055
1338
  */
1056
1339
  export const frontendRecoveryPhaseSchema = z.enum([
1057
1340
  "child-staging",
@@ -1071,6 +1354,9 @@ export const frontendRecoveryPhaseSchema = z.enum([
1071
1354
  * runner's `(existing?.revision ?? 0) + 1` CAS write (the schema only bounds it
1072
1355
  * non-negative). `childRunId` may be absent through `child-activating` and must
1073
1356
  * be non-empty from `child-running` onward.
1357
+ *
1358
+ * @deprecated Read-only compatibility only; the runner no longer writes this
1359
+ * intent (the M6 operation controller supervises recovery instead).
1074
1360
  */
1075
1361
  export const frontendRecoveryStateSchema = z
1076
1362
  .object({
@@ -1142,6 +1428,10 @@ export const frontendRecoveryEvidenceRefSchema = z
1142
1428
  * stays permissive (failureClass optional, evidenceRefs may be empty) so it
1143
1429
  * accepts the runner's actual phase-3a products, which do not always carry a
1144
1430
  * failure class or evidence reference.
1431
+ *
1432
+ * @deprecated Read-only compatibility only; the M6 operation controller writes
1433
+ * `recovered`/`auto-recovery-blocked` results directly and never uses this
1434
+ * schema as the authoritative recovery settlement.
1145
1435
  */
1146
1436
  export const frontendRecoveryResultSchema = z
1147
1437
  .object({
@@ -38,10 +38,6 @@ export function relocateNodeArtifactPaths(node, oldRunDir, newRunDir) {
38
38
  node.stdoutArtifactPath = rewrite(node.stdoutArtifactPath);
39
39
  node.assistantArtifactPath = rewrite(node.assistantArtifactPath);
40
40
  node.structuredArtifactPath = rewrite(node.structuredArtifactPath);
41
- if (node.frontendPlanOutput) {
42
- node.frontendPlanOutput.citationsArtifactPath = rewrite(node.frontendPlanOutput.citationsArtifactPath);
43
- node.frontendPlanOutput.rawCandidatePath = rewrite(node.frontendPlanOutput.rawCandidatePath);
44
- }
45
41
  node.nodeRecordPath = rewrite(node.nodeRecordPath);
46
42
  }
47
43
  export function relocateConvergenceArtifactPaths(convergence, oldRunDir, newRunDir) {