@tea-agent/loop-agent 0.41.1-beta.0 → 0.41.1

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 (206) hide show
  1. package/CHANGELOG.md +47 -267
  2. package/dist/application/dag/generate-task-dag.js +19 -75
  3. package/dist/application/task-lifecycle/advance.js +5 -24
  4. package/dist/application/task-lifecycle/observe.js +17 -171
  5. package/dist/application/task-lifecycle/plan-transitions.js +7 -42
  6. package/dist/application/task-lifecycle/recommendations.js +2 -13
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/cli/command-definitions.js +0 -7
  9. package/dist/cli/program.js +0 -5
  10. package/dist/commands/client-recovery.js +0 -3
  11. package/dist/commands/init.js +1 -27
  12. package/dist/commands/task-advance.js +0 -19
  13. package/dist/executors/dag-pi-executor.js +231 -3784
  14. package/dist/executors/pi-executor.js +4 -15
  15. package/dist/executors/shell-executor.js +217 -945
  16. package/dist/executors/shell-write-guard.js +0 -7
  17. package/dist/shared/dag-failure-category.js +0 -12
  18. package/dist/shared/openspec-spec.js +4 -70
  19. package/dist/shared/operator/capabilities.js +0 -7
  20. package/dist/task/config-types.js +7 -34
  21. package/dist/task/contract/adopt.js +0 -4
  22. package/dist/task/contract/import-revision.js +0 -4
  23. package/dist/task/contract/project.js +0 -3
  24. package/dist/task/contract/schema.js +1 -2
  25. package/dist/task/frontend-project-capability.js +20 -203
  26. package/dist/task/runtime.js +2 -5
  27. package/dist/task/source-prepare/build-draft.js +3 -3
  28. package/dist/task/source-prepare/fragment-inventory.js +9 -15
  29. package/dist/task/source-prepare/prepare.js +1 -89
  30. package/dist/task/source-prepare/semantic-intake.js +2 -6
  31. package/dist/task/source-references.js +1 -22
  32. package/dist/worker/console/chat/chat-ui-policy.js +4 -2
  33. package/dist/worker/console/chat/pi-runtime.js +176 -9
  34. package/dist/worker/console/chat/repo-browser.js +10 -3
  35. package/dist/worker/console/chat/routes.js +42 -22
  36. package/dist/worker/console/chat/semantic-activity.js +12 -11
  37. package/dist/worker/console/chat/session-stats.js +96 -0
  38. package/dist/worker/console/chat/session-store.js +117 -70
  39. package/dist/worker/console/chat/shortcuts.js +1 -1
  40. package/dist/worker/console/chat/turn-process.js +139 -60
  41. package/dist/worker/console/index.js +0 -3
  42. package/dist/worker/console/operation-store.js +6 -226
  43. package/dist/worker/console/operator-actions.js +7 -169
  44. package/dist/worker/console/pi-plugins.js +3 -1
  45. package/dist/worker/console/server.js +0 -3
  46. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-D7oU983t.js} +1 -1
  47. package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-BrKSRdFS.js} +1 -1
  48. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-CiXV7L56.js} +1 -1
  49. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-D_Hs_gIG.js} +1 -1
  50. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-DbM-Lqqh.js} +1 -1
  51. package/dist/worker/console/static/assets/channel-D1xajGpe.js +1 -0
  52. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-D1M8uqJw.js} +1 -1
  53. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-4D3RFHT6.js} +1 -1
  54. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CdwpY_n9.js} +1 -1
  55. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-BLeLZ9PG.js} +1 -1
  56. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-CeRNEMvc.js} +1 -1
  57. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-CjkHP8Vy.js} +1 -1
  58. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-B54ZUQY-.js} +1 -1
  59. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-4bKaMVmx.js} +1 -1
  60. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-Cyjfznu_.js} +1 -1
  61. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CDN-zGFV.js} +1 -1
  62. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BmuGTfRr.js +1 -0
  63. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BmuGTfRr.js +1 -0
  64. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-HxJmz411.js} +1 -1
  65. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-DtSt5K2w.js} +1 -1
  66. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-VtkSpRmG.js} +1 -1
  67. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-Bj4DT4du.js} +1 -1
  68. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-Bpuk6BmP.js} +1 -1
  69. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-BHYGv_yO.js} +1 -1
  70. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-DEx3WwnT.js} +1 -1
  71. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-Cj0dS5e8.js} +1 -1
  72. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-B97h8l21.js} +1 -1
  73. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-DMSFAhBd.js} +1 -1
  74. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-DhVOCbt6.js} +1 -1
  75. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-GlakITWL.js} +1 -1
  76. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-VxPpu9eQ.js} +1 -1
  77. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bs_e5DRT.js} +1 -1
  78. package/dist/worker/console/static/assets/index-BLzcAykx.js +451 -0
  79. package/dist/worker/console/static/assets/index-Cs9JUSPs.css +1 -0
  80. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-BXYuU4Uw.js} +1 -1
  81. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-C34erCbU.js} +1 -1
  82. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-DZCAiOU3.js} +1 -1
  83. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-C9gaTdUm.js} +1 -1
  84. package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CvI0Z17U.js} +1 -1
  85. package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-DMMSIx7j.js} +5 -5
  86. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-BKKP0EO6.js} +1 -1
  87. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-C3LiFbl5.js} +1 -1
  88. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-Bb3Om2Dz.js} +1 -1
  89. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-DNthMjzc.js} +1 -1
  90. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-miFsr4Tv.js} +1 -1
  91. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-yXUncmn6.js} +1 -1
  92. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-DLeWKLak.js} +1 -1
  93. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-CI3he1R3.js} +1 -1
  94. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-B7jfDkS5.js} +1 -1
  95. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-BmrZod7J.js} +1 -1
  96. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-D9ykKEWP.js +1 -0
  97. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-CDOlHVSY.js} +2 -2
  98. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BvPOXALT.js +8 -0
  99. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-Cz-XX1gy.js} +1 -1
  100. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-caV4cI8C.js} +1 -1
  101. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-dImPlnIO.js} +1 -1
  102. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CtRYVJcn.js} +1 -1
  103. package/dist/worker/console/static/index.html +2 -2
  104. package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
  105. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +19 -8
  106. package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
  107. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +15 -7
  108. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
  109. package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
  110. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
  111. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
  112. package/dist/worker/console/workspace-context.js +1 -111
  113. package/dist/worker/observability/read-model.js +4 -0
  114. package/dist/worker/observe/static/dag-node-purpose.js +0 -5
  115. package/dist/worker/observe/static/views/dag-inspector.js +2 -7
  116. package/dist/worker/observe/static/views/session-timeline.js +46 -15
  117. package/dist/workflows/dag/backend-test-result-contract.js +1 -1
  118. package/dist/workflows/dag/contract-validator-registrations.js +2 -1
  119. package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
  120. package/dist/workflows/dag/frontend-plan-render.js +1 -2
  121. package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
  122. package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
  123. package/dist/workflows/dag/frontend-recovery-run.js +20 -33
  124. package/dist/workflows/dag/frontend-repair.js +432 -1
  125. package/dist/workflows/dag/frontend-review-context.js +15 -261
  126. package/dist/workflows/dag/frontend-verification-trace.js +24 -249
  127. package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
  128. package/dist/workflows/dag/init-hybrid.js +494 -685
  129. package/dist/workflows/dag/interrupt-request.js +0 -7
  130. package/dist/workflows/dag/node-execution.js +4 -732
  131. package/dist/workflows/dag/prompt.js +1 -34
  132. package/dist/workflows/dag/report.js +1 -37
  133. package/dist/workflows/dag/rerun-feedback.js +1 -256
  134. package/dist/workflows/dag/rerun-plan.js +2 -10
  135. package/dist/workflows/dag/rerun-run.js +0 -23
  136. package/dist/workflows/dag/rerun-task.js +0 -29
  137. package/dist/workflows/dag/retry-policy.js +104 -214
  138. package/dist/workflows/dag/runner.js +122 -429
  139. package/dist/workflows/dag/scheduler.js +16 -114
  140. package/dist/workflows/dag/types.js +12 -239
  141. package/dist/workflows/dag/validate.js +12 -28
  142. package/docs/init-surface.manifest.json +12 -30
  143. package/docs/skills/vetted-skill-registry.md +2 -4
  144. package/docs/templates/README.md +0 -2
  145. package/docs/templates/agent-dag-report.schema.json +2 -8
  146. package/docs/templates/agent-dag.schema.json +1 -1
  147. package/docs/templates/frontend-implementation-contract.schema.json +1 -4
  148. package/harness.json +3 -3
  149. package/package.json +1 -1
  150. package/skills/frontend-bounded-implement/SKILL.md +14 -15
  151. package/skills/frontend-design-review/SKILL.md +41 -22
  152. package/skills/frontend-implementation/SKILL.md +52 -0
  153. package/skills/frontend-implementation/references/code-standards.md +33 -0
  154. package/skills/frontend-implementation/references/design-spec.md +56 -0
  155. package/skills/frontend-implementation/references/node-contracts.md +31 -0
  156. package/skills/frontend-review/SKILL.md +15 -20
  157. package/skills/frontend-review/references/review-findings.md +7 -6
  158. package/skills/frontend-verification/SKILL.md +1 -1
  159. package/skills/loop-agent/references/command-reference.md +0 -1
  160. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  161. package/dist/commands/dag-follow-up.js +0 -138
  162. package/dist/executors/pi-read-budget-policy.js +0 -239
  163. package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
  164. package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
  165. package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
  166. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
  167. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
  168. package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
  169. package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
  170. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
  171. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
  172. package/dist/worker/console/static-src/active-run-badge.js +0 -17
  173. package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
  174. package/dist/workflows/dag/dag-retry-schema.js +0 -138
  175. package/dist/workflows/dag/frontend-closeout.js +0 -221
  176. package/dist/workflows/dag/frontend-design-policy.js +0 -400
  177. package/dist/workflows/dag/frontend-human-decision.js +0 -182
  178. package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
  179. package/dist/workflows/dag/frontend-read-budgets.js +0 -12
  180. package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
  181. package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
  182. package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
  183. package/dist/workflows/dag/frontend-review-findings.js +0 -270
  184. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
  185. package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
  186. package/dist/workflows/dag/frontend-shape-facts.js +0 -409
  187. package/dist/workflows/dag/frontend-shape.js +0 -427
  188. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
  189. package/dist/workflows/dag/frontend-split-application-service.js +0 -203
  190. package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
  191. package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
  192. package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
  193. package/dist/workflows/dag/frontend-writer-admission.js +0 -285
  194. package/dist/workflows/dag/frontend-writer-status.js +0 -256
  195. package/dist/workflows/dag/recovery-lease.js +0 -80
  196. package/docs/templates/frontend-implementation-dag.json +0 -89
  197. package/docs/templates/spec-registry.schema.json +0 -45
  198. package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
  199. package/skills/frontend-contract/SKILL.md +0 -23
  200. package/skills/frontend-contract/references/contract-protocol.md +0 -34
  201. package/skills/frontend-plan/SKILL.md +0 -26
  202. package/skills/frontend-plan/references/decision-contract.md +0 -37
  203. package/skills/frontend-plan/references/design-decisions.md +0 -17
  204. package/skills/frontend-scout/SKILL.md +0 -25
  205. package/skills/frontend-scout/references/design-evidence.md +0 -16
  206. package/skills/frontend-scout/references/scout-evidence.md +0 -23
@@ -260,10 +260,6 @@ async function monitorRun(input) {
260
260
  failureCategory: "monitor-timeout",
261
261
  });
262
262
  }
263
- function isStartupGateEligible(snapshot) {
264
- const status = snapshot.source?.sourceFidelityStartup?.status;
265
- return status === undefined || status === "complete" || status === "not-applicable";
266
- }
267
263
  function nextMutationAction(actions) {
268
264
  for (const action of actions) {
269
265
  if (action.type !== "stop")
@@ -383,10 +379,7 @@ export async function advanceTaskLifecycle(input) {
383
379
  };
384
380
  }
385
381
  const token = parseGateToken(input.rejectGateToken);
386
- const currentGate = snapshot.gate ??
387
- (isStartupGateEligible(snapshot)
388
- ? await buildCurrentGate(input.repoRoot, input.taskId)
389
- : null);
382
+ const currentGate = snapshot.gate ?? (await buildCurrentGate(input.repoRoot, input.taskId));
390
383
  if (!currentGate || !gateMatches(currentGate, token)) {
391
384
  return {
392
385
  taskId: input.taskId,
@@ -450,12 +443,11 @@ export async function advanceTaskLifecycle(input) {
450
443
  dryRun,
451
444
  skipFinalize: Boolean(input.skipFinalize),
452
445
  forcePrepareContract: Boolean(input.fromDraftPath) && !preparedContractThisCall,
453
- startupRepairAttempted: preparedContractThisCall,
454
446
  });
455
447
  if (dryRun) {
456
448
  const plan = planOnce(snapshot);
457
449
  const plannedGate = snapshot.gate ??
458
- (isStartupGateEligible(snapshot) && snapshot.dagDraft?.exists
450
+ (snapshot.dagDraft?.exists
459
451
  ? await buildCurrentGate(input.repoRoot, input.taskId)
460
452
  : null);
461
453
  return {
@@ -507,10 +499,7 @@ export async function advanceTaskLifecycle(input) {
507
499
  }
508
500
  if (action.type === "create-task") {
509
501
  if (!snapshot.exists) {
510
- await createTask(input.repoRoot, input.taskId, input.title, {
511
- taskKind: input.taskKind,
512
- taskKindExplicit: input.taskKindExplicit,
513
- });
502
+ await createTask(input.repoRoot, input.taskId, input.title);
514
503
  record = appendTransition(record, "task-created");
515
504
  completed.push("task-created");
516
505
  await saveLifecycleRecord(input.repoRoot, record);
@@ -597,10 +586,6 @@ export async function advanceTaskLifecycle(input) {
597
586
  continue;
598
587
  }
599
588
  if (action.type === "prepare-contract") {
600
- const startupStatus = snapshot.source?.sourceFidelityStartup?.status;
601
- const startupRepairAction = startupStatus === "missing" ||
602
- startupStatus === "invalid" ||
603
- startupStatus === "coverage-incomplete";
604
589
  // 生产 source fidelity Pi 接线(AC-PROD-001/005):仅 frontend-implementation
605
590
  // 任务注入 reconcile executor + 独立 reviewer;ineligible 返回 undefined 不接线。
606
591
  // 主路径与 semantic-intake retry 路径共用同一接线,保证任意一条生产路径都实际
@@ -746,9 +731,7 @@ export async function advanceTaskLifecycle(input) {
746
731
  message: "structured requirement draft via semantic intake; projected managed source",
747
732
  });
748
733
  preparedContractThisCall = true;
749
- if (startupRepairAction ||
750
- refreshManagedContractThisCall ||
751
- input.fromDraftPath) {
734
+ if (refreshManagedContractThisCall || input.fromDraftPath) {
752
735
  refreshManagedContractThisCall = false;
753
736
  regenerateDagThisCall = true;
754
737
  }
@@ -842,9 +825,7 @@ export async function advanceTaskLifecycle(input) {
842
825
  break;
843
826
  }
844
827
  preparedContractThisCall = true;
845
- if (startupRepairAction ||
846
- refreshManagedContractThisCall ||
847
- input.fromDraftPath) {
828
+ if (refreshManagedContractThisCall || input.fromDraftPath) {
848
829
  // The old DAG and gate were bound to the pre-mutation contract.
849
830
  refreshManagedContractThisCall = false;
850
831
  regenerateDagThisCall = true;
@@ -1,11 +1,9 @@
1
- import { access, readFile, readdir } from "node:fs/promises";
1
+ import { access, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { getTaskDir, getTaskPaths, getTaskStatus, loadTaskConfig, } from "../../task/runtime.js";
4
4
  import { logicalRevisionForState, observeTaskContractState, } from "../../task/contract/index.js";
5
5
  import { assessDagRunLiveness, listAllDagRunEntries, readDagRunSpec, readDagRunState, } from "../../workflows/dag/lifecycle.js";
6
6
  import { resolveRunningControllerIdentity } from "../../shared/package-metadata.js";
7
- import { parseLedgerJson, validateRequirementLedger, } from "../../task/source-prepare/ledger.js";
8
- import { REQUIREMENT_LEDGER_FILE_NAME } from "../../task/source-prepare/types.js";
9
7
  import { loadLifecycleRecord } from "./record.js";
10
8
  import { buildGateBinding, buildWriteSetGate, buildWriteSetGateDelta, controllerIdentityAnchor, hashCanonicalPayload, normalizeWriteSet, sha256Hex, } from "./gates.js";
11
9
  async function exists(filePath) {
@@ -49,140 +47,6 @@ async function taskExists(repoRoot, taskId) {
49
47
  const paths = getTaskPaths(repoRoot, taskId);
50
48
  return exists(paths.taskConfigPath);
51
49
  }
52
- async function assessReferenceEvidence(referencesDir) {
53
- try {
54
- const entries = await readdir(referencesDir);
55
- const importedPrdCount = entries.filter((name) => name.endsWith(".md")).length;
56
- return importedPrdCount > 0
57
- ? { status: "present", importedPrdCount }
58
- : { status: "absent-or-empty", importedPrdCount: 0 };
59
- }
60
- catch (error) {
61
- if (error &&
62
- typeof error === "object" &&
63
- "code" in error &&
64
- error.code === "ENOENT") {
65
- return { status: "absent-or-empty", importedPrdCount: 0 };
66
- }
67
- return {
68
- status: "unknown",
69
- importedPrdCount: 0,
70
- error: error instanceof Error ? error.message : String(error),
71
- };
72
- }
73
- }
74
- function hasLedgerStructure(value) {
75
- if (!value || typeof value !== "object")
76
- return false;
77
- const ledger = value;
78
- return (typeof ledger.taskId === "string" &&
79
- typeof ledger.inputDigest === "string" &&
80
- typeof ledger.requirementSha256 === "string" &&
81
- Array.isArray(ledger.sourcePaths) &&
82
- Array.isArray(ledger.fragments) &&
83
- Array.isArray(ledger.canonicalRequirements) &&
84
- Boolean(ledger.stats && typeof ledger.stats === "object") &&
85
- Array.isArray(ledger.unresolved) &&
86
- Array.isArray(ledger.conflicts) &&
87
- Array.isArray(ledger.sourceResolutions) &&
88
- typeof ledger.schemaReconcilerVersion === "string" &&
89
- typeof ledger.builtAt === "string");
90
- }
91
- async function assessSourceFidelityStartup(input) {
92
- if (!input.applicable) {
93
- return {
94
- status: "not-applicable",
95
- ledgerPath: input.ledgerPath,
96
- diagnostics: [],
97
- };
98
- }
99
- if (input.referenceEvidenceError) {
100
- return {
101
- status: "invalid",
102
- ledgerPath: input.ledgerPath,
103
- diagnostics: [
104
- {
105
- code: "SOURCE_FIDELITY_LEDGER_STALE",
106
- message: `imported PRD reference evidence is unreadable: ${input.referenceEvidenceError}`,
107
- },
108
- ],
109
- };
110
- }
111
- let raw;
112
- try {
113
- raw = await readFile(input.ledgerPath, "utf-8");
114
- }
115
- catch (error) {
116
- const missing = !(await exists(input.ledgerPath));
117
- return {
118
- status: missing ? "missing" : "invalid",
119
- ledgerPath: input.ledgerPath,
120
- diagnostics: [
121
- {
122
- code: missing
123
- ? "SOURCE_FIDELITY_LEDGER_MISSING"
124
- : "SOURCE_FIDELITY_LEDGER_STALE",
125
- message: missing
126
- ? "managed frontend task has no requirement-ledger.json"
127
- : `requirement ledger is unreadable: ${error instanceof Error ? error.message : String(error)}`,
128
- },
129
- ],
130
- };
131
- }
132
- try {
133
- const ledger = parseLedgerJson(raw);
134
- if (!hasLedgerStructure(ledger)) {
135
- return {
136
- status: "invalid",
137
- ledgerPath: input.ledgerPath,
138
- diagnostics: [
139
- {
140
- code: "SOURCE_FIDELITY_LEDGER_STALE",
141
- message: "requirement ledger is missing required structural fields",
142
- },
143
- ],
144
- };
145
- }
146
- const nonDecisionErrors = validateRequirementLedger(ledger, {
147
- allowedUnresolved: true,
148
- allowedConflicts: true,
149
- });
150
- if (nonDecisionErrors.length > 0) {
151
- const coverageCodes = new Set([
152
- "SOURCE_FIDELITY_HIGH_RISK_UNCOVERED",
153
- "SOURCE_FIDELITY_REQUIREMENT_NOT_COVERED",
154
- ]);
155
- return {
156
- status: nonDecisionErrors.every((error) => coverageCodes.has(error.code))
157
- ? "coverage-incomplete"
158
- : "invalid",
159
- ledgerPath: input.ledgerPath,
160
- diagnostics: nonDecisionErrors,
161
- };
162
- }
163
- const decisionErrors = validateRequirementLedger(ledger);
164
- if (decisionErrors.length > 0) {
165
- return {
166
- status: "human-decision-blocked",
167
- ledgerPath: input.ledgerPath,
168
- diagnostics: decisionErrors,
169
- };
170
- }
171
- return { status: "complete", ledgerPath: input.ledgerPath, diagnostics: [] };
172
- }
173
- catch (error) {
174
- return {
175
- status: "invalid",
176
- ledgerPath: input.ledgerPath,
177
- diagnostics: [
178
- {
179
- code: "SOURCE_FIDELITY_LEDGER_STALE",
180
- message: error instanceof Error ? error.message : String(error),
181
- },
182
- ],
183
- };
184
- }
185
- }
186
50
  /**
187
51
  * Explicit Task↔DAG association only:
188
52
  * - lifecycle.json recorded runAssociations
@@ -318,12 +182,10 @@ export async function observeTaskLifecycle(repoRoot, taskId) {
318
182
  const record = await loadLifecycleRecord(repoRoot, taskId);
319
183
  const contractState = await observeTaskContractState(repoRoot, taskId);
320
184
  let title;
321
- let taskKind;
322
185
  let taskConfigAllowed = [];
323
186
  try {
324
187
  const config = await loadTaskConfig(repoRoot, taskId);
325
188
  title = config.title;
326
- taskKind = config.taskKind;
327
189
  taskConfigAllowed = config.allowedPaths ?? [];
328
190
  }
329
191
  catch {
@@ -337,22 +199,19 @@ export async function observeTaskLifecycle(repoRoot, taskId) {
337
199
  ...(requirementReady ? [] : [requirementPath]),
338
200
  ...(constraintsReady ? [] : [constraintsPath]),
339
201
  ];
340
- const contractManaged = contractState.effectiveStatus === "managed" || Boolean(contractState.ref);
202
+ let importedPrdCount = 0;
341
203
  const referencesDir = path.join(paths.sourceDir, "references");
342
- const referenceEvidence = await assessReferenceEvidence(referencesDir);
343
- const importedPrdCount = referenceEvidence.importedPrdCount;
344
- const ledgerPath = path.join(paths.sourceDir, REQUIREMENT_LEDGER_FILE_NAME);
345
- const sourceFidelityStartup = await assessSourceFidelityStartup({
346
- ledgerPath,
347
- applicable: contractManaged &&
348
- taskKind === "frontend-implementation" &&
349
- referenceEvidence.status !== "absent-or-empty",
350
- referenceEvidenceError: referenceEvidence.status === "unknown"
351
- ? referenceEvidence.error
352
- : undefined,
353
- });
354
- const sourceFidelityReady = sourceFidelityStartup.status === "complete" ||
355
- sourceFidelityStartup.status === "not-applicable";
204
+ if (await exists(referencesDir)) {
205
+ // Count is best-effort; absence is fine.
206
+ try {
207
+ const { readdir } = await import("node:fs/promises");
208
+ const entries = await readdir(referencesDir);
209
+ importedPrdCount = entries.filter((name) => name.endsWith(".md")).length;
210
+ }
211
+ catch {
212
+ importedPrdCount = 0;
213
+ }
214
+ }
356
215
  const dagDraftPath = paths.dagDraftPath;
357
216
  const dagDraftExists = await exists(dagDraftPath);
358
217
  let specHash = null;
@@ -426,11 +285,7 @@ export async function observeTaskLifecycle(repoRoot, taskId) {
426
285
  // Open gate only when draft is strict-validated and the current binding is
427
286
  // not already approved/rejected. Rejected same-digest gates stay closed
428
287
  // until contract/source/DAG/writeSet/controller binding changes.
429
- const gate = gateBound &&
430
- strictValidated &&
431
- sourceFidelityReady &&
432
- !approvedCurrent &&
433
- !rejectedCurrent
288
+ const gate = gateBound && strictValidated && !approvedCurrent && !rejectedCurrent
434
289
  ? buildWriteSetGate({ taskId, bound: gateBound, delta: gateDelta })
435
290
  : null;
436
291
  const gateOpen = Boolean(gate);
@@ -455,10 +310,11 @@ export async function observeTaskLifecycle(repoRoot, taskId) {
455
310
  activeRun.failureCategory === "needs-attention" ||
456
311
  activeRun.failureCategory === "suspected-stall" ||
457
312
  activeRun.failureCategory === "monitor-timeout"));
313
+ const contractManaged = contractState.effectiveStatus === "managed" || Boolean(contractState.ref);
458
314
  const lifecycleState = deriveLifecycleState({
459
315
  exists: true,
460
316
  contractManaged,
461
- sourceReady: requirementReady && sourceFidelityReady,
317
+ sourceReady: requirementReady,
462
318
  dagValidated: strictValidated,
463
319
  gateOpen: Boolean(gate),
464
320
  activeRun,
@@ -496,7 +352,6 @@ export async function observeTaskLifecycle(repoRoot, taskId) {
496
352
  constraintsReady,
497
353
  importedPrdCount,
498
354
  missing,
499
- sourceFidelityStartup,
500
355
  },
501
356
  dagDraft: {
502
357
  path: dagDraftPath,
@@ -520,16 +375,7 @@ export async function observeTaskLifecycle(repoRoot, taskId) {
520
375
  exists: closeoutExists || Boolean(record?.closeout),
521
376
  },
522
377
  completedTransitions: record?.completedTransitions ?? [],
523
- blockers: sourceFidelityReady
524
- ? []
525
- : sourceFidelityStartup.diagnostics.map((diagnostic) => ({
526
- code: diagnostic.code,
527
- message: diagnostic.message,
528
- details: {
529
- startupStatus: sourceFidelityStartup.status,
530
- ledgerPath: sourceFidelityStartup.ledgerPath,
531
- },
532
- })),
378
+ blockers: [],
533
379
  warnings: [],
534
380
  next,
535
381
  };
@@ -46,37 +46,6 @@ export function planTransitions(input) {
46
46
  actions.push({ type: "recover-contract" });
47
47
  expectedTransitions.push("contract-recovered");
48
48
  }
49
- const startupStatus = snapshot.source?.sourceFidelityStartup?.status;
50
- const startupRepairDetected = startupStatus === "missing" ||
51
- startupStatus === "invalid" ||
52
- startupStatus === "coverage-incomplete";
53
- if (startupRepairDetected && input.startupRepairAttempted) {
54
- actions.push({ type: "stop", reason: "blocker" });
55
- return {
56
- actions,
57
- gate: null,
58
- blockers,
59
- next: {
60
- kind: "advance",
61
- command: `loop-agent task advance ${snapshot.taskId} --json`,
62
- },
63
- expectedTransitions,
64
- };
65
- }
66
- const startupRepairRequired = startupRepairDetected;
67
- if (startupStatus === "human-decision-blocked") {
68
- actions.push({ type: "stop", reason: "blocker" });
69
- return {
70
- actions,
71
- gate: null,
72
- blockers,
73
- next: {
74
- kind: "external-action",
75
- description: "Requirement ledger requires an existing human source decision; preserve sourceResolutions, resolve the blocker, then advance again.",
76
- },
77
- expectedTransitions,
78
- };
79
- }
80
49
  const sourceReady = snapshot.source?.requirementReady === true;
81
50
  const contractManaged = snapshot.contract?.effectiveStatus === "managed" ||
82
51
  Boolean(snapshot.contract?.revision && snapshot.contract.revision > 0);
@@ -84,9 +53,7 @@ export function planTransitions(input) {
84
53
  // Prefer prepare once PRDs are on disk; re-import only when caller still
85
54
  // signals hasPrdInput (advance.ts latches this after one import per call).
86
55
  const shouldImportPrd = input.hasPrdInput;
87
- if (input.forcePrepareContract ||
88
- input.refreshManagedContract ||
89
- startupRepairRequired) {
56
+ if (input.forcePrepareContract || input.refreshManagedContract) {
90
57
  if (shouldImportPrd) {
91
58
  actions.push({ type: "import-prd" });
92
59
  expectedTransitions.push("prd-imported");
@@ -157,8 +124,7 @@ export function planTransitions(input) {
157
124
  const strictValidated = snapshot.dagDraft?.strictValidated === true;
158
125
  const dagRefreshRequired = Boolean(input.forceDagRefresh ||
159
126
  input.refreshManagedContract ||
160
- input.forcePrepareContract ||
161
- startupRepairRequired);
127
+ input.forcePrepareContract);
162
128
  if (!dagExists || dagRefreshRequired) {
163
129
  actions.push({ type: "generate-dag" });
164
130
  expectedTransitions.push("dag-generated");
@@ -179,11 +145,10 @@ export function planTransitions(input) {
179
145
  snapshot.lifecycleState === "evidence-closed" ||
180
146
  snapshot.lifecycleState === "needs-attention" ||
181
147
  snapshot.lifecycleState === "awaiting-decision";
182
- const approveCurrentGate = input.approveGate && !dagRefreshRequired;
183
- const approvedForCurrent = postRunState || (approveCurrentGate && gate !== null);
148
+ const approvedForCurrent = postRunState || (input.approveGate && gate !== null);
184
149
  if (!approvedForCurrent && (strictValidated || !dagExists || dagRefreshRequired)) {
185
150
  // Gate opens after generate+validate in the advance loop; plan includes open.
186
- if (!approveCurrentGate) {
151
+ if (!input.approveGate) {
187
152
  actions.push({ type: "open-write-set-gate" });
188
153
  expectedTransitions.push("write-set-gate-opened");
189
154
  if (input.dryRun) {
@@ -212,14 +177,14 @@ export function planTransitions(input) {
212
177
  (snapshot.lifecycleState === "run-failed" && !failedRecoverable) ||
213
178
  snapshot.lifecycleState === "evidence-closed";
214
179
  if (!alreadyTerminalRun) {
215
- if (approveCurrentGate && !postRunState) {
180
+ if (input.approveGate && !postRunState) {
216
181
  expectedTransitions.push("write-set-approved");
217
182
  actions.push({ type: "start-or-monitor-run" });
218
183
  expectedTransitions.push("dag-run-started", "dag-run-monitored");
219
184
  }
220
185
  else if (snapshot.lifecycleState === "running" ||
221
186
  snapshot.activeRun ||
222
- (approveCurrentGate && Boolean(snapshot.activeRun))) {
187
+ (input.approveGate && Boolean(snapshot.activeRun))) {
223
188
  actions.push({ type: "start-or-monitor-run" });
224
189
  expectedTransitions.push("dag-run-monitored");
225
190
  }
@@ -253,7 +218,7 @@ export function planTransitions(input) {
253
218
  actions,
254
219
  gate,
255
220
  blockers,
256
- next: deriveNext(snapshot, gate, approveCurrentGate),
221
+ next: deriveNext(snapshot, gate, input.approveGate),
257
222
  expectedTransitions,
258
223
  };
259
224
  }
@@ -42,7 +42,6 @@ export async function buildTaskLifecycleRecommendations(input) {
42
42
  const allowedPaths = [];
43
43
  const verifyCommands = [];
44
44
  // 1) managed task config
45
- let hasDeclaredManagedVerify = false;
46
45
  try {
47
46
  const config = await loadTaskConfig(input.repoRoot, input.taskId);
48
47
  for (const glob of config.allowedPaths ?? []) {
@@ -54,9 +53,7 @@ export async function buildTaskLifecycleRecommendations(input) {
54
53
  source: "managed-task-config",
55
54
  });
56
55
  }
57
- const managedVerify = (config.verifyCommands ?? []).filter((cmd) => Boolean(cmd.command?.trim()));
58
- hasDeclaredManagedVerify = managedVerify.length > 0;
59
- for (const cmd of managedVerify) {
56
+ for (const cmd of config.verifyCommands ?? []) {
60
57
  const label = cmd.label?.trim() || "verify";
61
58
  const command = cmd.command?.trim();
62
59
  if (!command)
@@ -73,22 +70,14 @@ export async function buildTaskLifecycleRecommendations(input) {
73
70
  // task may not exist yet
74
71
  }
75
72
  // 2) package.json scripts (only if not already covered by managed config)
76
- // The full-suite `test` script is recommended only when the task declares
77
- // NO managed verifyCommands at all. Once a task configures a targeted
78
- // verify set (e.g. per-change typecheck + a scoped vitest run), the full
79
- // `npm run test` must never be auto-added: it validates the whole repo,
80
- // costs far more than the change under review, and can fail on unrelated
81
- // pre-existing breakage, turning a targeted verify green into a hard fail.
82
73
  const scripts = await readPackageScripts(input.repoRoot);
83
74
  const hasVerifyLabel = (label) => verifyCommands.some((entry) => entry.label === label);
84
75
  const scriptCandidates = [
85
76
  { label: "typecheck", script: "typecheck" },
77
+ { label: "test", script: "test" },
86
78
  { label: "check-repo", script: "check:repo" },
87
79
  { label: "check-repo", script: "check-repo" },
88
80
  ];
89
- if (!hasDeclaredManagedVerify) {
90
- scriptCandidates.push({ label: "test", script: "test" });
91
- }
92
81
  for (const candidate of scriptCandidates) {
93
82
  const scriptBody = scripts[candidate.script];
94
83
  if (!scriptBody)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.41.1-beta.0",
4
- "gitSha": "fbc12f26a410e65b74cb259639de202885609c15",
5
- "builtAt": "2026-08-31T10:40:48.916Z"
3
+ "version": "0.41.1",
4
+ "gitSha": "d5dec271d8ae9c579c423d9ea7b98fb0270baa5a",
5
+ "builtAt": "2026-09-02T04:40:44.741Z"
6
6
  }
@@ -36,7 +36,6 @@ import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
36
36
  import { runDagReconcileRun } from "../commands/dag-reconcile-run.js";
37
37
  import { runDagRequestInterrupt } from "../commands/dag-request-interrupt.js";
38
38
  import { runDagRerunTask } from "../commands/dag-rerun-task.js";
39
- import { runDagFollowUp } from "../commands/dag-follow-up.js";
40
39
  import { runDagRerun } from "../commands/dag-rerun.js";
41
40
  import { runDagResume } from "../commands/dag-resume.js";
42
41
  import { runDagDecisionInspect, runDagDecisionValidate, } from "../workflows/dag/decision-envelope.js";
@@ -136,7 +135,6 @@ const DAG_SUBCOMMANDS = [
136
135
  "request-interrupt",
137
136
  "rerun",
138
137
  "rerun-task",
139
- "follow-up",
140
138
  "reconcile-tasks",
141
139
  "final-verification",
142
140
  "decision",
@@ -583,11 +581,6 @@ export const COMMAND_DEFINITIONS = [
583
581
  await runDagRerunTask(repoRoot, rerunTaskArgs);
584
582
  return;
585
583
  }
586
- if (subcommand === "follow-up") {
587
- const followUpArgs = rest.filter((arg) => Boolean(arg));
588
- await runDagFollowUp(repoRoot, followUpArgs);
589
- return;
590
- }
591
584
  if (subcommand === "reconcile-tasks") {
592
585
  const reconcileArgs = rest.filter((arg) => Boolean(arg));
593
586
  await runDagReconcileTasks(repoRoot, reconcileArgs);
@@ -13,7 +13,6 @@ import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
13
13
  import { runDagReconcileRun } from "../commands/dag-reconcile-run.js";
14
14
  import { runDagRequestInterrupt } from "../commands/dag-request-interrupt.js";
15
15
  import { runDagRerunTask } from "../commands/dag-rerun-task.js";
16
- import { runDagFollowUp } from "../commands/dag-follow-up.js";
17
16
  import { runDagRerun } from "../commands/dag-rerun.js";
18
17
  import { runDagReject } from "../commands/dag-reject.js";
19
18
  import { runDagCloseoutDraft, runDagReport } from "../commands/dag-report.js";
@@ -358,9 +357,6 @@ async function runDagAction(repoRoot, subcommand, rest) {
358
357
  case "rerun-task":
359
358
  await runDagRerunTask(repoRoot, args);
360
359
  return;
361
- case "follow-up":
362
- await runDagFollowUp(repoRoot, args);
363
- return;
364
360
  case "reconcile-tasks":
365
361
  await runDagReconcileTasks(repoRoot, args);
366
362
  return;
@@ -549,7 +545,6 @@ function addDagCommand(program, defaultRepoRoot) {
549
545
  "request-interrupt",
550
546
  "rerun",
551
547
  "rerun-task",
552
- "follow-up",
553
548
  "reconcile-tasks",
554
549
  "final-verification",
555
550
  ], defaultRepoRoot);
@@ -1328,15 +1328,12 @@ export async function runClientRecovery(input) {
1328
1328
  }
1329
1329
  const plugin = await installProjectOpenCodePlugin({
1330
1330
  repoRoot: input.repoRoot,
1331
- onlyIfMissing: true,
1332
1331
  });
1333
1332
  const overflowPlugin = await installProjectOpenCodeOverflowCompactPlugin({
1334
1333
  repoRoot: input.repoRoot,
1335
- onlyIfMissing: true,
1336
1334
  });
1337
1335
  const piExtension = await installProjectPiContextOverflowExtension({
1338
1336
  repoRoot: input.repoRoot,
1339
- onlyIfMissing: true,
1340
1337
  });
1341
1338
  const pi = await applyProjectPiSettingsMerge({ repoRoot: input.repoRoot });
1342
1339
  if (mode !== "user") {
@@ -14,19 +14,6 @@ const GITIGNORE_BLOCK_START = "# LOOP_AGENT_INIT_START";
14
14
  const GITIGNORE_BLOCK_END = "# LOOP_AGENT_INIT_END";
15
15
  const INIT_SURFACE_STATE_PATH = ".harness/init-surface.json";
16
16
  const DEFAULT_GOVERNANCE_ROOT = "ai_workspace/loop-agent";
17
- function buildSpecRegistry() {
18
- return `${JSON.stringify({
19
- version: 1,
20
- roots: [],
21
- discovery: {
22
- enabled: true,
23
- maxDepth: 3,
24
- maxFiles: 100,
25
- maxBytes: 1048576,
26
- timeoutMs: 2000,
27
- },
28
- }, null, 2)}\n`;
29
- }
30
17
  const CORE_DOC_FILES = [
31
18
  { source: "README.md", target: "README.md" },
32
19
  {
@@ -623,7 +610,7 @@ if (
623
610
  (assessment.status === "passed" && assessment.currentExitCode !== 0) ||
624
611
  (assessment.status === "baseline-debt" && assessment.currentExitCode === 0)
625
612
  ) fail();
626
- if (!assessment.baselineRef || assessment.baselineRef.nodeId !== "frontend-writer-admission-shell") fail();
613
+ if (!assessment.baselineRef || assessment.baselineRef.nodeId !== "frontend-lint-baseline-shell") fail();
627
614
  const baselineRaw = readContained(assessment.baselineRef.path);
628
615
  if (sha256(baselineRaw) !== assessment.baselineRef.sha256) fail();
629
616
  let baseline;
@@ -1325,9 +1312,6 @@ async function buildDesiredSurfaceContent(input) {
1325
1312
  }), null, 2)}\n`,
1326
1313
  };
1327
1314
  }
1328
- if (manifestPath === "docs/spec-registry.json") {
1329
- return { content: buildSpecRegistry() };
1330
- }
1331
1315
  if (manifestPath === OPENCODE_TRANSIENT_RETRY_PLUGIN_PATH) {
1332
1316
  return { content: buildOpenCodeTransientRetryPluginSource() };
1333
1317
  }
@@ -1725,8 +1709,6 @@ async function listRelativeFiles(rootPath) {
1725
1709
  async function expectedLegacyInitFileSha(input) {
1726
1710
  if (input.legacyPath.startsWith("docs/")) {
1727
1711
  const doc = input.legacyPath.slice("docs/".length);
1728
- if (doc === "spec-registry.json")
1729
- return sha256Text(buildSpecRegistry());
1730
1712
  const generated = buildGeneratedCoreDoc({
1731
1713
  doc,
1732
1714
  projectName: input.projectName,
@@ -2725,14 +2707,6 @@ export async function initializeLoopAgentProject(options) {
2725
2707
  targetRelativePath: path.join(governanceRoot, "templates"),
2726
2708
  written,
2727
2709
  });
2728
- await writeTextIfMissing({
2729
- repoRoot,
2730
- relativePath: path.join(governanceRoot, "spec-registry.json"),
2731
- content: buildSpecRegistry(),
2732
- merge,
2733
- written,
2734
- skipped,
2735
- });
2736
2710
  if (profile === "full") {
2737
2711
  // Project repo-local skills live only under `.agents/skills/`.
2738
2712
  // The package still ships `skills/` as the built-in fallback source.
@@ -377,25 +377,6 @@ export async function runTaskAdvance(repoRoot, args) {
377
377
  intervalMs: options.progressIntervalMs,
378
378
  });
379
379
  }
380
- // Idempotent client-recovery surface install before any DAG run: the Pi
381
- // context-overflow extension / OpenCode plugins / project .pi settings
382
- // are normally installed by `loop-agent init`, but an upgraded or
383
- // non-init-created project may lack them. Installing here (missing-only)
384
- // ensures the overflow compact+retry recovery path is always present,
385
- // independent of how the project was created. Best-effort: a failure to
386
- // install never blocks the run.
387
- if (options.approveGate && !options.dryRun) {
388
- try {
389
- const { runClientRecovery } = await import("./client-recovery.js");
390
- // mode "project" installs only project-owned surfaces
391
- // (.pi/extensions + .opencode/plugins + .pi/settings.json),
392
- // never the user home; installs are missing-only.
393
- await runClientRecovery({ repoRoot, mode: "project" });
394
- }
395
- catch {
396
- // best-effort; do not fail the run over a recovery-surface install
397
- }
398
- }
399
380
  const result = await advanceTaskLifecycle(toUseCaseInput(repoRoot, taskId, options, progress?.observer));
400
381
  const outcome = mapOutcome(result);
401
382
  const gateStop = result.lifecycleState === "awaiting-write-set-approval" &&