@tea-agent/loop-agent 0.42.0-next.1 → 0.42.0-next.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 (238) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +319 -1
  3. package/dist/application/dag/generate-task-dag.js +75 -19
  4. package/dist/application/dag/run-dag.js +41 -0
  5. package/dist/application/task-lifecycle/advance.js +24 -5
  6. package/dist/application/task-lifecycle/observe.js +171 -17
  7. package/dist/application/task-lifecycle/plan-transitions.js +42 -7
  8. package/dist/application/task-lifecycle/recommendations.js +13 -2
  9. package/dist/build-stamp.json +3 -3
  10. package/dist/cli/command-definitions.js +7 -0
  11. package/dist/cli/program.js +6 -1
  12. package/dist/commands/client-recovery.js +3 -0
  13. package/dist/commands/dag-follow-up.js +138 -0
  14. package/dist/commands/dag-rerun-task.js +2 -0
  15. package/dist/commands/init.js +27 -1
  16. package/dist/commands/task-advance.js +19 -0
  17. package/dist/executors/dag-pi-executor.js +3976 -76
  18. package/dist/executors/pi-executor.js +15 -4
  19. package/dist/executors/pi-read-budget-policy.js +239 -0
  20. package/dist/executors/shell-executor.js +978 -188
  21. package/dist/executors/shell-write-guard.js +7 -0
  22. package/dist/infrastructure/console/operation-store.js +226 -6
  23. package/dist/shared/dag-failure-category.js +12 -0
  24. package/dist/shared/openspec-spec.js +70 -4
  25. package/dist/shared/operator/capabilities.js +7 -0
  26. package/dist/task/config-types.js +105 -5
  27. package/dist/task/contract/adopt.js +4 -0
  28. package/dist/task/contract/import-revision.js +4 -0
  29. package/dist/task/contract/project.js +3 -0
  30. package/dist/task/contract/schema.js +2 -1
  31. package/dist/task/frontend-project-capability.js +203 -20
  32. package/dist/task/runtime.js +5 -2
  33. package/dist/task/source-prepare/build-draft.js +3 -3
  34. package/dist/task/source-prepare/fragment-inventory.js +64 -25
  35. package/dist/task/source-prepare/prepare.js +126 -21
  36. package/dist/task/source-prepare/semantic-intake.js +6 -2
  37. package/dist/task/source-references.js +22 -1
  38. package/dist/worker/console/chat/chat-ui-policy.js +4 -2
  39. package/dist/worker/console/chat/model-resolver.js +7 -4
  40. package/dist/worker/console/chat/pi-runtime.js +258 -11
  41. package/dist/worker/console/chat/repo-browser.js +10 -3
  42. package/dist/worker/console/chat/routes.js +165 -71
  43. package/dist/worker/console/chat/sdd-data-alignment.js +222 -0
  44. package/dist/worker/console/chat/session-catalog.js +2 -0
  45. package/dist/worker/console/chat/session-store.js +159 -70
  46. package/dist/worker/console/chat/shortcuts.js +19 -3
  47. package/dist/worker/console/chat/turn-process.js +111 -56
  48. package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
  49. package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
  50. package/dist/worker/console/index.js +3 -0
  51. package/dist/worker/console/operator-actions.js +169 -7
  52. package/dist/worker/console/pi-readiness.js +3 -2
  53. package/dist/worker/console/server.js +23 -1
  54. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DZZ8m3PO.js → abnfDiagram-N423BO3Z-CcS17TBr.js} +1 -1
  55. package/dist/worker/console/static/assets/{arc-D6PvaVd-.js → arc-COptKq2S.js} +1 -1
  56. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-B_OTOiI8.js → architectureDiagram-T3A2C74G-h4LKMHjP.js} +1 -1
  57. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Bv6rqHBg.js → blockDiagram-VBNYF7ZC-COA1MOH0.js} +1 -1
  58. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B8eHr0oz.js → c4Diagram-5PPSVZJV-DJUf0QPm.js} +1 -1
  59. package/dist/worker/console/static/assets/channel-DdBCaOJ6.js +1 -0
  60. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DYwR0im2.js → chunk-2GRJ4B5K-mtWfKrUX.js} +1 -1
  61. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-D2WPGqXt.js → chunk-2Q5K7J3B-B8pXsxDQ.js} +1 -1
  62. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CQISJ_I7.js → chunk-5RXB4S5H-ipKzByl1.js} +1 -1
  63. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C0o2Du1e.js → chunk-5VM5RSS4-DYi3Ald_.js} +1 -1
  64. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-4f8kr-U7.js → chunk-6Q2QTUOP-DQtGYoty.js} +1 -1
  65. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D_OWvXzX.js → chunk-GF5L2VYU-BU0qS2YV.js} +1 -1
  66. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CasdPz5X.js → chunk-JWPE2WC7-DVH9dIGE.js} +1 -1
  67. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Cj8lRrla.js → chunk-KBJHAD2P-Dt60SmgM.js} +1 -1
  68. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CUvD1FSd.js → chunk-RYQCIY6F-BoaUGuEY.js} +1 -1
  69. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CqLw_eqB.js → chunk-XXDRQBXY-_WHFDTp2.js} +1 -1
  70. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DZFra1GO.js +1 -0
  71. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DZFra1GO.js +1 -0
  72. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-ku-WqJPx.js → cose-bilkent-JH36ORCC-BxkbTIRd.js} +1 -1
  73. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-Bq_PYDhl.js → cynefin-VYW2F7L2-Bf2UVnoG.js} +1 -1
  74. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BiGZV641.js → cynefinDiagram-MW4NZA55-Bo23q1J_.js} +1 -1
  75. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C4JRlglF.js → dagre-VZM6K2ZE-Dd_UU49i.js} +1 -1
  76. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B0dNeWYG.js → diagram-7IWD3JNH-ebUa1a9y.js} +1 -1
  77. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Cj35YvYM.js → diagram-B4RE2ZJO-BucthU8r.js} +1 -1
  78. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-uzQoJ2-8.js → diagram-LBJQPF4R-BgqNpAkm.js} +1 -1
  79. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D1a-Buoz.js → diagram-Q27KOJAE-DC4q5NGa.js} +1 -1
  80. package/dist/worker/console/static/assets/{diagram-UB23O5K3-XjRrLRSs.js → diagram-UB23O5K3-CBqCaMeb.js} +1 -1
  81. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Da_O24cW.js → ebnfDiagram-BXEA7PRR-CGtnbQ3-.js} +1 -1
  82. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BLJ8jrYU.js → erDiagram-JOGREHBK-CG3LUao5.js} +1 -1
  83. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-B9GrLjM0.js → flowDiagram-UKHOOZJN-D2ZVgoFS.js} +1 -1
  84. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CeJ0TqiK.js → ganttDiagram-PKOTCBZU-DoYFZiKt.js} +1 -1
  85. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js → gitGraphDiagram-DS77QQ5N-CKoP1s6j.js} +1 -1
  86. package/dist/worker/console/static/assets/index-CAZ2fC_X.css +1 -0
  87. package/dist/worker/console/static/assets/index-vbTcFnFs.js +449 -0
  88. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DB26i3d8.js → infoDiagram-6WML65LV-Duofv8p2.js} +1 -1
  89. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BOGRyeZT.js → ishikawaDiagram-WSZJBQD7-D2nlCkA1.js} +1 -1
  90. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CZRoBO_6.js → journeyDiagram-NVQOT4AX-Dd4IHdus.js} +1 -1
  91. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-qlWhJyoB.js → kanban-definition-27J2QSJJ-Bi20AOdt.js} +1 -1
  92. package/dist/worker/console/static/assets/{linear-CfUiDDB3.js → linear-D59YJ9kB.js} +1 -1
  93. package/dist/worker/console/static/assets/{mermaid.core-BQe6fpqj.js → mermaid.core-Bl13LpNa.js} +5 -5
  94. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-zFzWHw64.js → mindmap-definition-FAOFIHXS-C6DLP5eY.js} +1 -1
  95. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DFGUqjZO.js → pegDiagram-VL7TDLO6-BjO4cy64.js} +1 -1
  96. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BB5i0l8Z.js → pieDiagram-7S7Q4E2Y-D7i2qZTG.js} +1 -1
  97. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-obbVZ_X5.js → quadrantDiagram-CIZ2JOQS-Dx8o_h0y.js} +1 -1
  98. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BwdaNzc1.js → railroadDiagram-AXF67PYL-B55orI_t.js} +1 -1
  99. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CkTJaugh.js → requirementDiagram-LRYGKXZP-zWaehp6f.js} +1 -1
  100. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BwJ-hIgq.js → sankeyDiagram-W5VNT64P-CcA-pjvD.js} +1 -1
  101. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BzSgmm7w.js → sequenceDiagram-SI44F4Z6-BOFbzNHI.js} +1 -1
  102. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Bn3oj5Q1.js → sizeCapture-X5ZJPWSS-BjAejah1.js} +1 -1
  103. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-dxhGtL8K.js → stateDiagram-OKZ733FA-DXYwxJwZ.js} +1 -1
  104. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Clg3V9t1.js +1 -0
  105. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BLpEInya.js → swimlanes-SLNWSIFB-OYiOch8n.js} +2 -2
  106. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DX1dxAAW.js +8 -0
  107. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-ChJGYcXy.js → timeline-definition-Z64GVDOM-cZfH3nmU.js} +1 -1
  108. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DK-qjRer.js → vennDiagram-T6HMQDX7-BDE7b3E1.js} +1 -1
  109. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-3qeaWAg-.js → wardleyDiagram-T6FBY63Y-kyyGy9WJ.js} +1 -1
  110. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CootlyP9.js → xychartDiagram-ELKLHX3M-CJj6VTog.js} +1 -1
  111. package/dist/worker/console/static/index.html +2 -2
  112. package/dist/worker/console/static-src/active-run-badge.js +17 -0
  113. package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -5
  114. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +19 -8
  115. package/dist/worker/console/static-src/operator-chat/input-history.js +8 -6
  116. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +15 -7
  117. package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +10 -0
  118. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +258 -23
  119. package/dist/worker/console/static-src/operator-chat/useChatThread.js +112 -4
  120. package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -4
  121. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +29 -6
  122. package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +8 -2
  123. package/dist/worker/console/static-src/shell/console-update-reload.js +36 -9
  124. package/dist/worker/console/static-src/shell/workspace-route.js +11 -0
  125. package/dist/worker/console/workspace-context.js +115 -1
  126. package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
  127. package/dist/worker/observe/routes.js +4 -0
  128. package/dist/worker/observe/static/dag-helpers.js +4 -2
  129. package/dist/worker/observe/static/dag-node-purpose.js +5 -0
  130. package/dist/worker/observe/static/inspect-workspace.js +23 -0
  131. package/dist/worker/observe/static/kpi.js +2 -2
  132. package/dist/worker/observe/static/operator-chrome.d.ts +10 -2
  133. package/dist/worker/observe/static/operator-chrome.js +37 -23
  134. package/dist/worker/observe/static/relations.js +2 -2
  135. package/dist/worker/observe/static/router.d.ts +12 -1
  136. package/dist/worker/observe/static/router.js +48 -6
  137. package/dist/worker/observe/static/run-processing.js +4 -2
  138. package/dist/worker/observe/static/shell-chrome.js +2 -2
  139. package/dist/worker/observe/static/state.js +5 -0
  140. package/dist/worker/observe/static/styles.css +95 -0
  141. package/dist/worker/observe/static/views/dag-inspector.js +14 -7
  142. package/dist/worker/observe/static/views/dag.js +10 -2
  143. package/dist/worker/observe/static/views/dags.js +3 -1
  144. package/dist/worker/observe/static/views/dashboard.js +14 -6
  145. package/dist/worker/observe/static/views/pool.js +7 -2
  146. package/dist/worker/observe/static/views/run.js +12 -3
  147. package/dist/worker/observe/static/views/session-timeline.js +69 -10
  148. package/dist/worker/observe/static/views/task.js +7 -2
  149. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +215 -28
  150. package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
  151. package/dist/workflows/dag/backend-test-plan-protocol.js +106 -0
  152. package/dist/workflows/dag/backend-test-scenario-param.js +172 -25
  153. package/dist/workflows/dag/backend-test-scenario-partitions.js +62 -1
  154. package/dist/workflows/dag/backend-test-writer-completeness.js +104 -12
  155. package/dist/workflows/dag/contract-validator-registrations.js +1 -2
  156. package/dist/workflows/dag/dag-retry-schema.js +138 -0
  157. package/dist/workflows/dag/frontend-closeout.js +221 -0
  158. package/dist/workflows/dag/frontend-design-policy.js +400 -0
  159. package/dist/workflows/dag/frontend-human-decision.js +182 -0
  160. package/dist/workflows/dag/frontend-implementation-contract.js +1237 -192
  161. package/dist/workflows/dag/frontend-plan-render.js +2 -1
  162. package/dist/workflows/dag/frontend-prewrite-gate.js +256 -350
  163. package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
  164. package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
  165. package/dist/workflows/dag/frontend-recovery-controller.js +226 -0
  166. package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
  167. package/dist/workflows/dag/frontend-recovery-plan.js +21 -10
  168. package/dist/workflows/dag/frontend-recovery-run.js +166 -34
  169. package/dist/workflows/dag/frontend-repair.js +1 -432
  170. package/dist/workflows/dag/frontend-review-context.js +261 -15
  171. package/dist/workflows/dag/frontend-review-findings.js +270 -0
  172. package/dist/workflows/dag/frontend-shadow-dual-write.js +941 -0
  173. package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
  174. package/dist/workflows/dag/frontend-shape-facts.js +419 -0
  175. package/dist/workflows/dag/frontend-shape.js +435 -0
  176. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
  177. package/dist/workflows/dag/frontend-split-application-service.js +203 -0
  178. package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
  179. package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
  180. package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
  181. package/dist/workflows/dag/frontend-verification-trace.js +252 -25
  182. package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
  183. package/dist/workflows/dag/frontend-writer-admission.js +319 -0
  184. package/dist/workflows/dag/frontend-writer-status.js +256 -0
  185. package/dist/workflows/dag/init-hybrid.js +1028 -562
  186. package/dist/workflows/dag/interrupt-request.js +7 -0
  187. package/dist/workflows/dag/node-execution.js +828 -4
  188. package/dist/workflows/dag/prompt.js +70 -3
  189. package/dist/workflows/dag/recovery-lease.js +170 -0
  190. package/dist/workflows/dag/report.js +37 -1
  191. package/dist/workflows/dag/rerun-feedback.js +315 -1
  192. package/dist/workflows/dag/rerun-plan.js +17 -6
  193. package/dist/workflows/dag/rerun-run.js +44 -6
  194. package/dist/workflows/dag/rerun-task.js +251 -13
  195. package/dist/workflows/dag/retry-policy.js +219 -104
  196. package/dist/workflows/dag/runner.js +580 -124
  197. package/dist/workflows/dag/scheduler.js +133 -20
  198. package/dist/workflows/dag/types.js +244 -16
  199. package/dist/workflows/dag/validate.js +28 -12
  200. package/docs/examples/README.md +5 -0
  201. package/docs/init-surface.manifest.json +30 -12
  202. package/docs/skills/vetted-skill-registry.md +4 -2
  203. package/docs/templates/README.md +2 -0
  204. package/docs/templates/agent-dag-report.schema.json +8 -2
  205. package/docs/templates/agent-dag.schema.json +1 -1
  206. package/docs/templates/backend-test-dag.json +23 -20
  207. package/docs/templates/frontend-implementation-contract.schema.json +4 -1
  208. package/docs/templates/frontend-implementation-dag.json +89 -0
  209. package/docs/templates/spec-registry.schema.json +45 -0
  210. package/harness.json +1 -1
  211. package/package.json +4 -3
  212. package/skills/frontend-bounded-implement/SKILL.md +15 -14
  213. package/skills/frontend-bounded-implement/references/code-standards.md +19 -0
  214. package/skills/frontend-contract/SKILL.md +23 -0
  215. package/skills/frontend-contract/references/contract-protocol.md +34 -0
  216. package/skills/frontend-design-review/SKILL.md +22 -41
  217. package/skills/frontend-plan/SKILL.md +26 -0
  218. package/skills/frontend-plan/references/decision-contract.md +37 -0
  219. package/skills/frontend-plan/references/design-decisions.md +17 -0
  220. package/skills/frontend-review/SKILL.md +20 -15
  221. package/skills/frontend-review/references/review-findings.md +6 -7
  222. package/skills/frontend-scout/SKILL.md +25 -0
  223. package/skills/frontend-scout/references/design-evidence.md +16 -0
  224. package/skills/frontend-scout/references/scout-evidence.md +23 -0
  225. package/skills/frontend-verification/SKILL.md +1 -1
  226. package/skills/loop-agent/references/command-reference.md +1 -0
  227. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  228. package/dist/worker/console/static/assets/channel-BU5gOilw.js +0 -1
  229. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +0 -1
  230. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +0 -1
  231. package/dist/worker/console/static/assets/index-H9rFJiGL.css +0 -1
  232. package/dist/worker/console/static/assets/index-xwu9GxEc.js +0 -451
  233. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +0 -1
  234. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +0 -8
  235. package/skills/frontend-implementation/SKILL.md +0 -52
  236. package/skills/frontend-implementation/references/code-standards.md +0 -33
  237. package/skills/frontend-implementation/references/design-spec.md +0 -56
  238. package/skills/frontend-implementation/references/node-contracts.md +0 -31
@@ -1,10 +1,5 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
1
  import { z } from "zod";
4
- import { pathMatchesPattern } from "../../shared/git-progress.js";
5
- import { FRONTEND_IMPLEMENTATION_CONTRACT_SCHEMA_ID, frontendImplementationContractSchema, } from "./frontend-implementation-contract.js";
6
- import { FRONTEND_NO_VERIFICATION_MARKER_TEXT, FRONTEND_VERIFICATION_UNAVAILABLE_MESSAGE, } from "./frontend-verification-trace.js";
7
- export const FRONTEND_REPAIR_ASSESSMENT_SCHEMA_ID = "frontend-repair-assessment-v1";
2
+ import { FRONTEND_NO_VERIFICATION_MARKER_TEXT, } from "./frontend-verification-trace.js";
8
3
  export const frontendRepairFailureClassSchema = z.enum([
9
4
  "typecheck",
10
5
  "build",
@@ -29,55 +24,6 @@ export const frontendCommandCategorySchema = z.enum([
29
24
  "unit-test",
30
25
  "trace",
31
26
  ]);
32
- const REPAIRABLE = new Set([
33
- "typecheck",
34
- "build",
35
- "lint",
36
- "component-test",
37
- "unit-test",
38
- "trace",
39
- ]);
40
- export function isFrontendRepairable(failureClass) {
41
- return REPAIRABLE.has(failureClass);
42
- }
43
- /**
44
- * Deterministic commandLabel → commandCategory mapping (AC-3).
45
- * `targetType` comes from the contract verificationTargets[].type
46
- * (static | unit | component | integration | mock); the literal commandLabel
47
- * wins over type so a `static` typecheck target is never misread as a test.
48
- */
49
- export function mapCommandLabelToCategory(commandLabel, targetType) {
50
- const label = commandLabel.toLowerCase();
51
- if (/(?:typecheck|check-types|type-check|\btsc\b)/.test(label))
52
- return "typecheck";
53
- if (/(?:vite\s+build|next\s+build|webpack|rollup|\bbuild\b)/.test(label))
54
- return "build";
55
- if (/(?:eslint|\blint\b)/.test(label))
56
- return "lint";
57
- if (targetType === "component")
58
- return "component-test";
59
- if (targetType === "unit")
60
- return "unit-test";
61
- if (/(?:component|testing-library|render\()/.test(label))
62
- return "component-test";
63
- return "unit-test";
64
- }
65
- export function isReviewRepairable(finding, implementWriteSet) {
66
- const hasFile = Boolean(finding.file && finding.file.trim().length > 0);
67
- const hasLocation = Boolean((finding.line !== undefined && finding.line > 0) ||
68
- (finding.symbol && finding.symbol.trim().length > 0));
69
- const hasRequirement = Boolean((finding.requirementId && finding.requirementId.trim().length > 0) ||
70
- (finding.acceptanceCriteriaId &&
71
- finding.acceptanceCriteriaId.trim().length > 0));
72
- const fixScope = finding.fixScope ?? (hasFile ? [finding.file] : []);
73
- const fixScopeSubset = fixScope.length > 0 &&
74
- fixScope.every((entry) => isPathWithinWriteSet(entry, implementWriteSet));
75
- return (hasFile &&
76
- hasLocation &&
77
- hasRequirement &&
78
- fixScopeSubset &&
79
- finding.requiresContractReplan !== true);
80
- }
81
27
  export function classifyFrontendFailure(input) {
82
28
  // AC-2: structured evidence takes priority over string-blob heuristics.
83
29
  if (input.failureCategory === "write-guard") {
@@ -176,380 +122,3 @@ export function classifyFrontendFailure(input) {
176
122
  return "path";
177
123
  return "unknown";
178
124
  }
179
- export const frontendRepairAssessmentSchema = z
180
- .object({
181
- schemaVersion: z.literal(1),
182
- schemaId: z.literal(FRONTEND_REPAIR_ASSESSMENT_SCHEMA_ID),
183
- contract: z
184
- .object({
185
- relativePath: z.string().min(1),
186
- schemaId: z.string().min(1),
187
- })
188
- .strict(),
189
- failedNodeIds: z.array(z.string().min(1)),
190
- failureClass: frontendRepairFailureClassSchema,
191
- eligible: z.boolean(),
192
- reason: z.string().min(1),
193
- attempt: z.number().int().min(1).max(2),
194
- maxAttempts: z.literal(1),
195
- allowedRepairWriteSet: z.array(z.string().min(1)),
196
- evidenceRefs: z.array(z.string().min(1)),
197
- browserStatus: z.literal("not-run"),
198
- // AC-5 structured evidence fields (all optional so existing minimal
199
- // fixtures and frontend-review-context safeParse stay compatible).
200
- verificationTargetId: z.string().min(1).optional(),
201
- commandLabel: z.string().min(1).optional(),
202
- exitCode: z.number().int().optional(),
203
- commandCategory: frontendCommandCategorySchema.optional(),
204
- requirementIds: z.array(z.string().min(1)).optional(),
205
- acceptanceCriteriaIds: z.array(z.string().min(1)).optional(),
206
- fixScope: z.array(z.string().min(1)).optional(),
207
- changedPaths: z.array(z.string().min(1)).optional(),
208
- traceRef: z
209
- .object({
210
- relativePath: z.string().min(1),
211
- schemaId: z.string().min(1),
212
- })
213
- .strict()
214
- .optional(),
215
- })
216
- .strict();
217
- function nodeHadFailure(record) {
218
- if (record.status === "ERROR")
219
- return true;
220
- if (recordIndicatesCommandFailure(record))
221
- return true;
222
- const results = record.commandResults ?? [];
223
- if (results.some((item) => item.ok === false))
224
- return true;
225
- return false;
226
- }
227
- function normalize(value) {
228
- return value.replace(/\\/g, "/").replace(/^\.\//, "");
229
- }
230
- /**
231
- * Whether a concrete path or glob entry is contained by the implement writeSet.
232
- * Exact glob equality is the norm (repair writeSet === implement writeSet);
233
- * concrete (non-glob) paths may also be covered by an implement glob.
234
- */
235
- export function isPathWithinWriteSet(entry, implementWriteSet) {
236
- const normalizedEntry = normalize(entry);
237
- const normalizedImplement = implementWriteSet.map(normalize);
238
- if (normalizedImplement.includes(normalizedEntry))
239
- return true;
240
- if (!normalizedEntry.includes("*")) {
241
- return implementWriteSet.some((pattern) => pathMatchesPattern(normalizedEntry, pattern));
242
- }
243
- return false;
244
- }
245
- export function assertWriteSetSubset(repairWriteSet, implementWriteSet) {
246
- for (const entry of repairWriteSet) {
247
- if (!isPathWithinWriteSet(entry, implementWriteSet)) {
248
- throw new Error(`repair writeSet entry "${entry}" is not ⊆ implement writeSet`);
249
- }
250
- }
251
- }
252
- async function loadImplementWriteSet(runDir, fallback) {
253
- if (fallback.length > 0)
254
- return fallback;
255
- const candidates = ["run.json", "dag.json", "spec.json"];
256
- for (const name of candidates) {
257
- try {
258
- const raw = JSON.parse(await readFile(path.join(runDir, name), "utf8"));
259
- const tasks = raw.spec?.tasks ?? raw.tasks ?? [];
260
- const implement = tasks.find((task) => task.id === "frontend-implement-pi");
261
- if (implement?.writeSet?.length)
262
- return implement.writeSet;
263
- }
264
- catch {
265
- // continue
266
- }
267
- }
268
- return fallback;
269
- }
270
- function matchVerificationTarget(contract, commandLabel, command) {
271
- for (const target of contract.verificationTargets) {
272
- if (commandLabel && target.commandLabel === commandLabel)
273
- return target;
274
- if (command &&
275
- (command.includes(target.commandLabel) ||
276
- target.commandLabel.includes(command))) {
277
- return target;
278
- }
279
- }
280
- return undefined;
281
- }
282
- function deriveFailureEvidence(input) {
283
- const evidence = {};
284
- for (const { record } of input.failed) {
285
- const results = record.commandResults ?? [];
286
- const failedResult = results.find((item) => item.ok === false) ?? results[0];
287
- if (failedResult &&
288
- evidence.exitCode === undefined &&
289
- typeof failedResult.exitCode === "number") {
290
- evidence.exitCode = failedResult.exitCode;
291
- }
292
- if (failedResult?.commandLabel && !evidence.commandLabel) {
293
- evidence.commandLabel = failedResult.commandLabel;
294
- }
295
- // Structured trace facts passed by the verification bundle / trace gate.
296
- const failedTraceTarget = (record.traceTargets ?? []).find((target) => target.status === "failed");
297
- if (failedTraceTarget && !evidence.verificationTargetId) {
298
- evidence.verificationTargetId = failedTraceTarget.id;
299
- if (!evidence.commandLabel)
300
- evidence.commandLabel = failedTraceTarget.commandLabel;
301
- evidence.traceTarget = failedTraceTarget;
302
- evidence.traceRef = {
303
- relativePath: "contracts/frontend-verification-trace.json",
304
- schemaId: "frontend-verification-trace-v1",
305
- };
306
- }
307
- if (record.changedPaths?.length && !evidence.changedPaths) {
308
- evidence.changedPaths = [...record.changedPaths];
309
- }
310
- }
311
- // Resolve commandLabel → contract verification target → category + scope.
312
- const target = matchVerificationTarget(input.contract, evidence.commandLabel);
313
- if (target) {
314
- if (!evidence.verificationTargetId)
315
- evidence.verificationTargetId = target.id;
316
- if (!evidence.commandLabel)
317
- evidence.commandLabel = target.commandLabel;
318
- evidence.requirementIds ??= [...target.requirementIds];
319
- evidence.acceptanceCriteriaIds ??= [...target.requirementIds];
320
- evidence.fixScope ??= [target.file];
321
- }
322
- if (evidence.commandLabel) {
323
- evidence.commandCategory ??= mapCommandLabelToCategory(evidence.commandLabel, target?.type);
324
- }
325
- return evidence;
326
- }
327
- export async function runFrontendFailureAssessGate(input) {
328
- const attempt = input.attempt ?? 1;
329
- const implementWriteSet = await loadImplementWriteSet(input.runDir, input.implementWriteSet ?? []);
330
- if (implementWriteSet.length === 0) {
331
- throw new Error("assess: implement writeSet unavailable");
332
- }
333
- const contractRel = "contracts/frontend-implementation-contract.json";
334
- const contractPath = path.join(input.runDir, contractRel);
335
- let contractSchemaId = FRONTEND_IMPLEMENTATION_CONTRACT_SCHEMA_ID;
336
- let contract;
337
- try {
338
- const raw = JSON.parse(await readFile(contractPath, "utf8"));
339
- const parsed = frontendImplementationContractSchema.safeParse(raw);
340
- if (!parsed.success) {
341
- throw new Error("invalid frontend implementation contract");
342
- }
343
- contract = parsed.data;
344
- contractSchemaId = FRONTEND_IMPLEMENTATION_CONTRACT_SCHEMA_ID;
345
- }
346
- catch {
347
- // still allow assessment of failures without contract? fail-closed to contract
348
- throw new Error("assess: missing or invalid contracts/frontend-implementation-contract.json");
349
- }
350
- const candidateNodeIds = [
351
- "frontend-verify-assess-shell",
352
- "frontend-reverify-shell",
353
- "frontend-static-verify-shell",
354
- "frontend-behavior-verify-shell",
355
- "frontend-verification-trace-shell",
356
- "frontend-static-reverify-shell",
357
- "frontend-behavior-reverify-shell",
358
- "frontend-verification-retrace-shell",
359
- ];
360
- const failed = [
361
- ...(input.failureFacts ?? []).filter(({ record }) => nodeHadFailure(record) || recordIndicatesCommandFailure(record)),
362
- ];
363
- for (const nodeId of candidateNodeIds) {
364
- if (failed.some((item) => item.nodeId === nodeId))
365
- continue;
366
- const nodePath = path.join(input.runDir, `${nodeId}.json`);
367
- try {
368
- const record = JSON.parse(await readFile(nodePath, "utf8"));
369
- if (nodeHadFailure(record) || recordIndicatesCommandFailure(record)) {
370
- failed.push({ nodeId, record });
371
- }
372
- }
373
- catch {
374
- // missing optional nodes ok
375
- }
376
- }
377
- if (failed.length === 0) {
378
- const assessment = {
379
- schemaVersion: 1,
380
- schemaId: FRONTEND_REPAIR_ASSESSMENT_SCHEMA_ID,
381
- contract: {
382
- relativePath: contractRel,
383
- schemaId: contractSchemaId,
384
- },
385
- failedNodeIds: [],
386
- failureClass: "unknown",
387
- eligible: false,
388
- reason: "no failed frontend verify/trace nodes in current run",
389
- attempt,
390
- maxAttempts: 1,
391
- allowedRepairWriteSet: [...implementWriteSet],
392
- evidenceRefs: [contractRel],
393
- browserStatus: "not-run",
394
- };
395
- await writeAssessment(input.runDir, assessment);
396
- return assessment;
397
- }
398
- const primary = failed[0];
399
- const evidence = deriveFailureEvidence({ contract, failed });
400
- const failureClass = classifyFrontendFailure({
401
- nodeId: primary.nodeId,
402
- failureCategory: primary.record.failureCategory,
403
- stdout: primary.record.stdout,
404
- stderr: primary.record.stderr,
405
- commandLabel: evidence.commandLabel,
406
- commandCategory: evidence.commandCategory,
407
- exitCode: evidence.exitCode,
408
- traceTarget: evidence.traceTarget ?? null,
409
- changedPaths: evidence.changedPaths,
410
- });
411
- // AC-5: repairable=true requires structured evidence (a resolved exitCode,
412
- // commandCategory, or trace-bound verification target). review has its own
413
- // stricter gate (AC-4) and is never unconditionally repairable.
414
- const baseEligible = isFrontendRepairable(failureClass) && attempt <= 1;
415
- let eligible;
416
- let reason;
417
- if (failureClass === "review") {
418
- const finding = primary.record.reviewFinding ?? {};
419
- eligible = attempt <= 1 && isReviewRepairable(finding, implementWriteSet);
420
- reason = eligible
421
- ? `repairable review finding on ${primary.nodeId}`
422
- : `review finding lacks file/line-symbol/requirement evidence or is outside writeSet on ${primary.nodeId}`;
423
- }
424
- else {
425
- const hasStructuredEvidence = evidence.exitCode !== undefined ||
426
- evidence.commandCategory !== undefined ||
427
- Boolean(evidence.verificationTargetId);
428
- eligible = baseEligible && hasStructuredEvidence;
429
- reason = eligible
430
- ? `repairable failureClass=${failureClass} on ${primary.nodeId}`
431
- : !baseEligible
432
- ? `non-repairable or ineligible: failureClass=${failureClass} attempt=${attempt}`
433
- : `missing structured evidence for failureClass=${failureClass} on ${primary.nodeId}`;
434
- if (!eligible &&
435
- `${primary.record.stderr ?? ""}`.includes(FRONTEND_NO_VERIFICATION_MARKER_TEXT)) {
436
- // Surface the actionable unavailable-verification reason in the
437
- // assessment (and the non-repairable gate error) instead of a
438
- // generic class label.
439
- reason = FRONTEND_VERIFICATION_UNAVAILABLE_MESSAGE;
440
- }
441
- }
442
- // fixScope and changedPaths must stay inside the implement writeSet.
443
- if (evidence.fixScope?.length) {
444
- assertWriteSetSubset(evidence.fixScope, implementWriteSet);
445
- }
446
- if (evidence.changedPaths?.length) {
447
- assertWriteSetSubset(evidence.changedPaths, implementWriteSet);
448
- }
449
- const assessment = {
450
- schemaVersion: 1,
451
- schemaId: FRONTEND_REPAIR_ASSESSMENT_SCHEMA_ID,
452
- contract: {
453
- relativePath: contractRel,
454
- schemaId: contractSchemaId,
455
- },
456
- failedNodeIds: failed.map((item) => item.nodeId),
457
- failureClass,
458
- eligible,
459
- reason,
460
- attempt,
461
- maxAttempts: 1,
462
- allowedRepairWriteSet: [...implementWriteSet],
463
- evidenceRefs: [contractRel, ...failed.map((item) => `${item.nodeId}.json`)],
464
- browserStatus: "not-run",
465
- ...(evidence.verificationTargetId
466
- ? { verificationTargetId: evidence.verificationTargetId }
467
- : {}),
468
- ...(evidence.commandLabel ? { commandLabel: evidence.commandLabel } : {}),
469
- ...(evidence.exitCode !== undefined ? { exitCode: evidence.exitCode } : {}),
470
- ...(evidence.commandCategory
471
- ? { commandCategory: evidence.commandCategory }
472
- : {}),
473
- ...(evidence.requirementIds?.length
474
- ? { requirementIds: evidence.requirementIds }
475
- : {}),
476
- ...(evidence.acceptanceCriteriaIds?.length
477
- ? { acceptanceCriteriaIds: evidence.acceptanceCriteriaIds }
478
- : {}),
479
- ...(evidence.fixScope?.length ? { fixScope: evidence.fixScope } : {}),
480
- ...(evidence.changedPaths?.length
481
- ? { changedPaths: evidence.changedPaths }
482
- : {}),
483
- ...(evidence.traceRef ? { traceRef: evidence.traceRef } : {}),
484
- };
485
- await writeAssessment(input.runDir, assessment);
486
- return assessment;
487
- }
488
- function recordIndicatesCommandFailure(record) {
489
- // Prefer explicit commandResults when present
490
- if (record.commandResults?.some((item) => item.ok === false))
491
- return true;
492
- // Node may be FINISHED with nonZeroExitPolicy=record; look for harness markers
493
- const stdout = record.stdout ?? "";
494
- if (/nonZeroExitPolicy=record/.test(stdout) &&
495
- /exitCode=[1-9]/.test(stdout)) {
496
- return true;
497
- }
498
- if (record.failureCategory && record.failureCategory !== "success") {
499
- // recorded failures may still be FINISHED
500
- if (record.status === "FINISHED") {
501
- return (record.failureCategory === "nonzero-exit" ||
502
- record.failureCategory === "invalid-output" ||
503
- record.failureCategory === "timeout");
504
- }
505
- }
506
- return false;
507
- }
508
- async function writeAssessment(runDir, assessment) {
509
- const relative = "contracts/frontend-repair-assessment.json";
510
- const absolute = path.join(runDir, relative);
511
- await mkdir(path.dirname(absolute), { recursive: true });
512
- await writeFile(absolute, `${JSON.stringify(assessment, null, 2)}\n`, "utf8");
513
- return absolute;
514
- }
515
- export async function runFrontendRepairContractGate(input) {
516
- const relative = "contracts/frontend-repair-assessment.json";
517
- const absolute = path.join(input.runDir, relative);
518
- const raw = JSON.parse(await readFile(absolute, "utf8"));
519
- const parsed = frontendRepairAssessmentSchema.safeParse(raw);
520
- if (!parsed.success) {
521
- throw new Error(`repair-contract: invalid assessment: ${parsed.error.issues
522
- .map((i) => i.message)
523
- .join("; ")}`);
524
- }
525
- const assessment = parsed.data;
526
- const implementWriteSet = await loadImplementWriteSet(input.runDir, input.implementWriteSet ?? []);
527
- assertWriteSetSubset(assessment.allowedRepairWriteSet, implementWriteSet.length
528
- ? implementWriteSet
529
- : assessment.allowedRepairWriteSet);
530
- if (assessment.attempt > assessment.maxAttempts) {
531
- throw new Error("repair-contract: attempt exceeds maxAttempts");
532
- }
533
- if (assessment.failedNodeIds.length === 0) {
534
- return { ok: true, assessment };
535
- }
536
- if (!assessment.eligible) {
537
- throw new Error(`repair-contract: non-repairable failure (${assessment.failureClass}): ${assessment.reason}`);
538
- }
539
- if (!isFrontendRepairable(assessment.failureClass) &&
540
- assessment.failureClass !== "review") {
541
- throw new Error(`repair-contract: failureClass ${assessment.failureClass} is not repairable`);
542
- }
543
- return { ok: true, assessment };
544
- }
545
- export function formatFrontendFailureAssessStdout(assessment) {
546
- return JSON.stringify(assessment);
547
- }
548
- export function formatFrontendRepairContractStdout(assessment) {
549
- return [
550
- "Frontend repair contract: pass",
551
- `eligible=${assessment.eligible}`,
552
- `failureClass=${assessment.failureClass}`,
553
- `writeSetSize=${assessment.allowedRepairWriteSet.length}`,
554
- ].join("\n");
555
- }