@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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +319 -1
- package/dist/application/dag/generate-task-dag.js +75 -19
- package/dist/application/dag/run-dag.js +41 -0
- package/dist/application/task-lifecycle/advance.js +24 -5
- package/dist/application/task-lifecycle/observe.js +171 -17
- package/dist/application/task-lifecycle/plan-transitions.js +42 -7
- package/dist/application/task-lifecycle/recommendations.js +13 -2
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +7 -0
- package/dist/cli/program.js +6 -1
- package/dist/commands/client-recovery.js +3 -0
- package/dist/commands/dag-follow-up.js +138 -0
- package/dist/commands/dag-rerun-task.js +2 -0
- package/dist/commands/init.js +27 -1
- package/dist/commands/task-advance.js +19 -0
- package/dist/executors/dag-pi-executor.js +3976 -76
- package/dist/executors/pi-executor.js +15 -4
- package/dist/executors/pi-read-budget-policy.js +239 -0
- package/dist/executors/shell-executor.js +978 -188
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/infrastructure/console/operation-store.js +226 -6
- package/dist/shared/dag-failure-category.js +12 -0
- package/dist/shared/openspec-spec.js +70 -4
- package/dist/shared/operator/capabilities.js +7 -0
- package/dist/task/config-types.js +105 -5
- package/dist/task/contract/adopt.js +4 -0
- package/dist/task/contract/import-revision.js +4 -0
- package/dist/task/contract/project.js +3 -0
- package/dist/task/contract/schema.js +2 -1
- package/dist/task/frontend-project-capability.js +203 -20
- package/dist/task/runtime.js +5 -2
- package/dist/task/source-prepare/build-draft.js +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +64 -25
- package/dist/task/source-prepare/prepare.js +126 -21
- package/dist/task/source-prepare/semantic-intake.js +6 -2
- package/dist/task/source-references.js +22 -1
- package/dist/worker/console/chat/chat-ui-policy.js +4 -2
- package/dist/worker/console/chat/model-resolver.js +7 -4
- package/dist/worker/console/chat/pi-runtime.js +258 -11
- package/dist/worker/console/chat/repo-browser.js +10 -3
- package/dist/worker/console/chat/routes.js +165 -71
- package/dist/worker/console/chat/sdd-data-alignment.js +222 -0
- package/dist/worker/console/chat/session-catalog.js +2 -0
- package/dist/worker/console/chat/session-store.js +159 -70
- package/dist/worker/console/chat/shortcuts.js +19 -3
- package/dist/worker/console/chat/turn-process.js +111 -56
- package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
- package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
- package/dist/worker/console/index.js +3 -0
- package/dist/worker/console/operator-actions.js +169 -7
- package/dist/worker/console/pi-readiness.js +3 -2
- package/dist/worker/console/server.js +23 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DZZ8m3PO.js → abnfDiagram-N423BO3Z-CcS17TBr.js} +1 -1
- package/dist/worker/console/static/assets/{arc-D6PvaVd-.js → arc-COptKq2S.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-B_OTOiI8.js → architectureDiagram-T3A2C74G-h4LKMHjP.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Bv6rqHBg.js → blockDiagram-VBNYF7ZC-COA1MOH0.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B8eHr0oz.js → c4Diagram-5PPSVZJV-DJUf0QPm.js} +1 -1
- package/dist/worker/console/static/assets/channel-DdBCaOJ6.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DYwR0im2.js → chunk-2GRJ4B5K-mtWfKrUX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-D2WPGqXt.js → chunk-2Q5K7J3B-B8pXsxDQ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CQISJ_I7.js → chunk-5RXB4S5H-ipKzByl1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C0o2Du1e.js → chunk-5VM5RSS4-DYi3Ald_.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-4f8kr-U7.js → chunk-6Q2QTUOP-DQtGYoty.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D_OWvXzX.js → chunk-GF5L2VYU-BU0qS2YV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CasdPz5X.js → chunk-JWPE2WC7-DVH9dIGE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Cj8lRrla.js → chunk-KBJHAD2P-Dt60SmgM.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CUvD1FSd.js → chunk-RYQCIY6F-BoaUGuEY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CqLw_eqB.js → chunk-XXDRQBXY-_WHFDTp2.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DZFra1GO.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DZFra1GO.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-ku-WqJPx.js → cose-bilkent-JH36ORCC-BxkbTIRd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-Bq_PYDhl.js → cynefin-VYW2F7L2-Bf2UVnoG.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BiGZV641.js → cynefinDiagram-MW4NZA55-Bo23q1J_.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C4JRlglF.js → dagre-VZM6K2ZE-Dd_UU49i.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B0dNeWYG.js → diagram-7IWD3JNH-ebUa1a9y.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Cj35YvYM.js → diagram-B4RE2ZJO-BucthU8r.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-uzQoJ2-8.js → diagram-LBJQPF4R-BgqNpAkm.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D1a-Buoz.js → diagram-Q27KOJAE-DC4q5NGa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-XjRrLRSs.js → diagram-UB23O5K3-CBqCaMeb.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Da_O24cW.js → ebnfDiagram-BXEA7PRR-CGtnbQ3-.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BLJ8jrYU.js → erDiagram-JOGREHBK-CG3LUao5.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-B9GrLjM0.js → flowDiagram-UKHOOZJN-D2ZVgoFS.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CeJ0TqiK.js → ganttDiagram-PKOTCBZU-DoYFZiKt.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js → gitGraphDiagram-DS77QQ5N-CKoP1s6j.js} +1 -1
- package/dist/worker/console/static/assets/index-CAZ2fC_X.css +1 -0
- package/dist/worker/console/static/assets/index-vbTcFnFs.js +449 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DB26i3d8.js → infoDiagram-6WML65LV-Duofv8p2.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BOGRyeZT.js → ishikawaDiagram-WSZJBQD7-D2nlCkA1.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CZRoBO_6.js → journeyDiagram-NVQOT4AX-Dd4IHdus.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-qlWhJyoB.js → kanban-definition-27J2QSJJ-Bi20AOdt.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CfUiDDB3.js → linear-D59YJ9kB.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BQe6fpqj.js → mermaid.core-Bl13LpNa.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-zFzWHw64.js → mindmap-definition-FAOFIHXS-C6DLP5eY.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DFGUqjZO.js → pegDiagram-VL7TDLO6-BjO4cy64.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BB5i0l8Z.js → pieDiagram-7S7Q4E2Y-D7i2qZTG.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-obbVZ_X5.js → quadrantDiagram-CIZ2JOQS-Dx8o_h0y.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BwdaNzc1.js → railroadDiagram-AXF67PYL-B55orI_t.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CkTJaugh.js → requirementDiagram-LRYGKXZP-zWaehp6f.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BwJ-hIgq.js → sankeyDiagram-W5VNT64P-CcA-pjvD.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BzSgmm7w.js → sequenceDiagram-SI44F4Z6-BOFbzNHI.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Bn3oj5Q1.js → sizeCapture-X5ZJPWSS-BjAejah1.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-dxhGtL8K.js → stateDiagram-OKZ733FA-DXYwxJwZ.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Clg3V9t1.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BLpEInya.js → swimlanes-SLNWSIFB-OYiOch8n.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DX1dxAAW.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-ChJGYcXy.js → timeline-definition-Z64GVDOM-cZfH3nmU.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DK-qjRer.js → vennDiagram-T6HMQDX7-BDE7b3E1.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-3qeaWAg-.js → wardleyDiagram-T6FBY63Y-kyyGy9WJ.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CootlyP9.js → xychartDiagram-ELKLHX3M-CJj6VTog.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/active-run-badge.js +17 -0
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -5
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +19 -8
- package/dist/worker/console/static-src/operator-chat/input-history.js +8 -6
- package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +15 -7
- package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +10 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +258 -23
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +112 -4
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -4
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +29 -6
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +8 -2
- package/dist/worker/console/static-src/shell/console-update-reload.js +36 -9
- package/dist/worker/console/static-src/shell/workspace-route.js +11 -0
- package/dist/worker/console/workspace-context.js +115 -1
- package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
- package/dist/worker/observe/routes.js +4 -0
- package/dist/worker/observe/static/dag-helpers.js +4 -2
- package/dist/worker/observe/static/dag-node-purpose.js +5 -0
- package/dist/worker/observe/static/inspect-workspace.js +23 -0
- package/dist/worker/observe/static/kpi.js +2 -2
- package/dist/worker/observe/static/operator-chrome.d.ts +10 -2
- package/dist/worker/observe/static/operator-chrome.js +37 -23
- package/dist/worker/observe/static/relations.js +2 -2
- package/dist/worker/observe/static/router.d.ts +12 -1
- package/dist/worker/observe/static/router.js +48 -6
- package/dist/worker/observe/static/run-processing.js +4 -2
- package/dist/worker/observe/static/shell-chrome.js +2 -2
- package/dist/worker/observe/static/state.js +5 -0
- package/dist/worker/observe/static/styles.css +95 -0
- package/dist/worker/observe/static/views/dag-inspector.js +14 -7
- package/dist/worker/observe/static/views/dag.js +10 -2
- package/dist/worker/observe/static/views/dags.js +3 -1
- package/dist/worker/observe/static/views/dashboard.js +14 -6
- package/dist/worker/observe/static/views/pool.js +7 -2
- package/dist/worker/observe/static/views/run.js +12 -3
- package/dist/worker/observe/static/views/session-timeline.js +69 -10
- package/dist/worker/observe/static/views/task.js +7 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +215 -28
- package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
- package/dist/workflows/dag/backend-test-plan-protocol.js +106 -0
- package/dist/workflows/dag/backend-test-scenario-param.js +172 -25
- package/dist/workflows/dag/backend-test-scenario-partitions.js +62 -1
- package/dist/workflows/dag/backend-test-writer-completeness.js +104 -12
- package/dist/workflows/dag/contract-validator-registrations.js +1 -2
- package/dist/workflows/dag/dag-retry-schema.js +138 -0
- package/dist/workflows/dag/frontend-closeout.js +221 -0
- package/dist/workflows/dag/frontend-design-policy.js +400 -0
- package/dist/workflows/dag/frontend-human-decision.js +182 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +1237 -192
- package/dist/workflows/dag/frontend-plan-render.js +2 -1
- package/dist/workflows/dag/frontend-prewrite-gate.js +256 -350
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
- package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
- package/dist/workflows/dag/frontend-recovery-controller.js +226 -0
- package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +21 -10
- package/dist/workflows/dag/frontend-recovery-run.js +166 -34
- package/dist/workflows/dag/frontend-repair.js +1 -432
- package/dist/workflows/dag/frontend-review-context.js +261 -15
- package/dist/workflows/dag/frontend-review-findings.js +270 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +941 -0
- package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
- package/dist/workflows/dag/frontend-shape-facts.js +419 -0
- package/dist/workflows/dag/frontend-shape.js +435 -0
- package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
- package/dist/workflows/dag/frontend-split-application-service.js +203 -0
- package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
- package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
- package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
- package/dist/workflows/dag/frontend-verification-trace.js +252 -25
- package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
- package/dist/workflows/dag/frontend-writer-admission.js +319 -0
- package/dist/workflows/dag/frontend-writer-status.js +256 -0
- package/dist/workflows/dag/init-hybrid.js +1028 -562
- package/dist/workflows/dag/interrupt-request.js +7 -0
- package/dist/workflows/dag/node-execution.js +828 -4
- package/dist/workflows/dag/prompt.js +70 -3
- package/dist/workflows/dag/recovery-lease.js +170 -0
- package/dist/workflows/dag/report.js +37 -1
- package/dist/workflows/dag/rerun-feedback.js +315 -1
- package/dist/workflows/dag/rerun-plan.js +17 -6
- package/dist/workflows/dag/rerun-run.js +44 -6
- package/dist/workflows/dag/rerun-task.js +251 -13
- package/dist/workflows/dag/retry-policy.js +219 -104
- package/dist/workflows/dag/runner.js +580 -124
- package/dist/workflows/dag/scheduler.js +133 -20
- package/dist/workflows/dag/types.js +244 -16
- package/dist/workflows/dag/validate.js +28 -12
- package/docs/examples/README.md +5 -0
- package/docs/init-surface.manifest.json +30 -12
- package/docs/skills/vetted-skill-registry.md +4 -2
- package/docs/templates/README.md +2 -0
- package/docs/templates/agent-dag-report.schema.json +8 -2
- package/docs/templates/agent-dag.schema.json +1 -1
- package/docs/templates/backend-test-dag.json +23 -20
- package/docs/templates/frontend-implementation-contract.schema.json +4 -1
- package/docs/templates/frontend-implementation-dag.json +89 -0
- package/docs/templates/spec-registry.schema.json +45 -0
- package/harness.json +1 -1
- package/package.json +4 -3
- package/skills/frontend-bounded-implement/SKILL.md +15 -14
- package/skills/frontend-bounded-implement/references/code-standards.md +19 -0
- package/skills/frontend-contract/SKILL.md +23 -0
- package/skills/frontend-contract/references/contract-protocol.md +34 -0
- package/skills/frontend-design-review/SKILL.md +22 -41
- package/skills/frontend-plan/SKILL.md +26 -0
- package/skills/frontend-plan/references/decision-contract.md +37 -0
- package/skills/frontend-plan/references/design-decisions.md +17 -0
- package/skills/frontend-review/SKILL.md +20 -15
- package/skills/frontend-review/references/review-findings.md +6 -7
- package/skills/frontend-scout/SKILL.md +25 -0
- package/skills/frontend-scout/references/design-evidence.md +16 -0
- package/skills/frontend-scout/references/scout-evidence.md +23 -0
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/loop-agent/references/command-reference.md +1 -0
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/worker/console/static/assets/channel-BU5gOilw.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +0 -1
- package/dist/worker/console/static/assets/index-H9rFJiGL.css +0 -1
- package/dist/worker/console/static/assets/index-xwu9GxEc.js +0 -451
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +0 -8
- package/skills/frontend-implementation/SKILL.md +0 -52
- package/skills/frontend-implementation/references/code-standards.md +0 -33
- package/skills/frontend-implementation/references/design-spec.md +0 -56
- package/skills/frontend-implementation/references/node-contracts.md +0 -31
|
@@ -415,12 +415,16 @@ function isCanonicalGeneratedVerifyShell(task) {
|
|
|
415
415
|
return false;
|
|
416
416
|
if (shell.projectGovernanceGate)
|
|
417
417
|
return false;
|
|
418
|
-
if (shell.
|
|
418
|
+
if (shell.frontendDesignPolicy)
|
|
419
|
+
return false;
|
|
420
|
+
if (shell.frontendWriterAdmission)
|
|
419
421
|
return false;
|
|
420
422
|
if (shell.frontendVerificationBundle)
|
|
421
423
|
return false;
|
|
422
424
|
if (shell.frontendReviewContext)
|
|
423
425
|
return false;
|
|
426
|
+
if (shell.frontendCloseout)
|
|
427
|
+
return false;
|
|
424
428
|
if (shell.backendTestPipeline)
|
|
425
429
|
return false;
|
|
426
430
|
if (shell.nonZeroExitPolicy === "record")
|
|
@@ -444,15 +448,18 @@ function isCanonicalFrontendArtifactContinuationShell(task) {
|
|
|
444
448
|
switch (task.id) {
|
|
445
449
|
case "frontend-prewrite-gate-shell":
|
|
446
450
|
return Boolean(shell.frontendPrewriteGate) && (shell.commands?.length ?? 0) === 0;
|
|
447
|
-
case "frontend-
|
|
448
|
-
return Boolean(shell.
|
|
449
|
-
|
|
450
|
-
|
|
451
|
+
case "frontend-design-policy-shell":
|
|
452
|
+
return Boolean(shell.frontendDesignPolicy) && (shell.commands?.length ?? 0) === 0;
|
|
453
|
+
case "frontend-writer-admission-shell":
|
|
454
|
+
return Boolean(shell.frontendWriterAdmission) && (shell.commands?.length ?? 0) === 0;
|
|
451
455
|
case "frontend-verify-assess-shell":
|
|
452
456
|
case "frontend-reverify-shell":
|
|
457
|
+
case "frontend-verify-shell":
|
|
453
458
|
return Boolean(shell.frontendVerificationBundle) && (shell.commands?.length ?? 0) === 0;
|
|
454
459
|
case "frontend-review-context-shell":
|
|
455
460
|
return Boolean(shell.frontendReviewContext) && (shell.commands?.length ?? 0) === 0;
|
|
461
|
+
case "frontend-closeout-shell":
|
|
462
|
+
return Boolean(shell.frontendCloseout) && (shell.commands?.length ?? 0) === 0;
|
|
456
463
|
default:
|
|
457
464
|
return false;
|
|
458
465
|
}
|
|
@@ -474,12 +481,16 @@ function isSafeGateOnlyShell(task) {
|
|
|
474
481
|
return false;
|
|
475
482
|
if (shell.preset)
|
|
476
483
|
return false;
|
|
477
|
-
if (shell.
|
|
484
|
+
if (shell.frontendDesignPolicy)
|
|
485
|
+
return false;
|
|
486
|
+
if (shell.frontendWriterAdmission)
|
|
478
487
|
return false;
|
|
479
488
|
if (shell.frontendVerificationBundle)
|
|
480
489
|
return false;
|
|
481
490
|
if (shell.frontendReviewContext)
|
|
482
491
|
return false;
|
|
492
|
+
if (shell.frontendCloseout)
|
|
493
|
+
return false;
|
|
483
494
|
if (shell.backendTestPipeline)
|
|
484
495
|
return false;
|
|
485
496
|
if (shell.verifyEvidence)
|
|
@@ -13,6 +13,7 @@ import { prepareActiveRunDir, writeNodeRecord, writeRunSpec, writeRunState, } fr
|
|
|
13
13
|
import { cloneParentSkillSnapshotForContinuation, readSkillSnapshot, } from "./skill-snapshot.js";
|
|
14
14
|
import { topoSortToRanks } from "./topo.js";
|
|
15
15
|
import { captureWorkspaceCheckpoint, readWorkspaceCheckpoint, WORKSPACE_CHECKPOINT_START_REL, WORKSPACE_CHECKPOINT_TERMINAL_REL, writeWorkspaceCheckpoint, } from "./workspace-checkpoint.js";
|
|
16
|
+
import { acquireDagRecoveryLease, bindDagRecoveryLeaseExecution, } from "./recovery-lease.js";
|
|
16
17
|
import { captureWriterBaseline, readJournalFile, recordWriterAttemptFromCurrent, restoreJournal, writeJournalFile, } from "./frontend-writer-rollback.js";
|
|
17
18
|
export const RERUN_PLAN_REL_PATH = ".runtime/rerun-plan.json";
|
|
18
19
|
export const IMPORT_MANIFEST_REL_PATH = ".runtime/import-manifest.json";
|
|
@@ -87,11 +88,18 @@ const operatorRequestEnvelopeSchema = z
|
|
|
87
88
|
})
|
|
88
89
|
.strict();
|
|
89
90
|
async function readExistingOperatorRequest(cwd, requestId) {
|
|
91
|
+
const requestPath = operatorRequestPath(cwd, requestId);
|
|
90
92
|
try {
|
|
91
|
-
const raw = JSON.parse(await readFile(
|
|
93
|
+
const raw = JSON.parse(await readFile(requestPath, "utf-8"));
|
|
92
94
|
const parsed = operatorRequestEnvelopeSchema.safeParse(raw);
|
|
93
|
-
if (!parsed.success)
|
|
94
|
-
|
|
95
|
+
if (!parsed.success) {
|
|
96
|
+
throw new Error("REQUEST_ID_REUSE_CONFLICT: persisted operator request envelope is invalid or belongs to a different request kind");
|
|
97
|
+
}
|
|
98
|
+
if (parsed.data.requestId !== requestId ||
|
|
99
|
+
parsed.data.parentRunId !== parsed.data.result.plan.parentRunId ||
|
|
100
|
+
parsed.data.newRunId !== parsed.data.result.newRunId) {
|
|
101
|
+
throw new Error("REQUEST_ID_REUSE_CONFLICT: persisted operator request envelope binding mismatch");
|
|
102
|
+
}
|
|
95
103
|
const result = parsed.data.result;
|
|
96
104
|
return {
|
|
97
105
|
...result,
|
|
@@ -99,10 +107,18 @@ async function readExistingOperatorRequest(cwd, requestId) {
|
|
|
99
107
|
idempotentReplay: true,
|
|
100
108
|
};
|
|
101
109
|
}
|
|
102
|
-
catch {
|
|
103
|
-
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error &&
|
|
112
|
+
typeof error === "object" &&
|
|
113
|
+
"code" in error &&
|
|
114
|
+
error.code === "ENOENT") {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
if (error instanceof Error && error.message.startsWith("REQUEST_ID_REUSE_CONFLICT:")) {
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`REQUEST_ID_REUSE_CONFLICT: invalid persisted operator request envelope: ${error instanceof Error ? error.message : String(error)}`);
|
|
104
121
|
}
|
|
105
|
-
return undefined;
|
|
106
122
|
}
|
|
107
123
|
/**
|
|
108
124
|
* Idempotent replay of a previously persisted operator request, if any.
|
|
@@ -970,6 +986,20 @@ export async function executeDagRerun(input) {
|
|
|
970
986
|
}
|
|
971
987
|
const parentSpec = await readDagRunSpec(located.runDir);
|
|
972
988
|
const parentState = await readDagRunState(located.runDir);
|
|
989
|
+
const recoveryLease = await acquireDagRecoveryLease({
|
|
990
|
+
cwd: input.cwd,
|
|
991
|
+
parentRunId: input.parentRunId,
|
|
992
|
+
requestId: input.requestId,
|
|
993
|
+
kind: "rerun-from-node",
|
|
994
|
+
});
|
|
995
|
+
if (recoveryLease.kind === "held") {
|
|
996
|
+
return {
|
|
997
|
+
ok: false,
|
|
998
|
+
plan,
|
|
999
|
+
errorCode: "RECOVERY_LEASE_HELD",
|
|
1000
|
+
message: `parent run recovery is already claimed by ${recoveryLease.lease.kind} request ${recoveryLease.lease.requestId}`,
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
973
1003
|
const staged = await stageContinuationRun({
|
|
974
1004
|
cwd: input.cwd,
|
|
975
1005
|
parentRunDir: located.runDir,
|
|
@@ -981,6 +1011,14 @@ export async function executeDagRerun(input) {
|
|
|
981
1011
|
requestId: input.requestId,
|
|
982
1012
|
promptOverrides: input.promptOverrides,
|
|
983
1013
|
});
|
|
1014
|
+
// Stage is non-executing; bind the child identity immediately before handing
|
|
1015
|
+
// it to the runner so no recovery DAG can start without durable parent
|
|
1016
|
+
// lineage ownership.
|
|
1017
|
+
await bindDagRecoveryLeaseExecution({
|
|
1018
|
+
leasePath: recoveryLease.leasePath,
|
|
1019
|
+
lease: recoveryLease.lease,
|
|
1020
|
+
executionRef: staged.state.runId,
|
|
1021
|
+
});
|
|
984
1022
|
const continuationOptions = {
|
|
985
1023
|
cwd: input.cwd,
|
|
986
1024
|
spec: staged.spec,
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { generateTaskDagUseCase } from "../../application/dag/generate-task-dag.js";
|
|
5
|
+
import { buildDefaultFrontendRecoveryDeps, } from "../../application/dag/run-dag.js";
|
|
6
|
+
import { runDagContinuation, } from "./runner.js";
|
|
7
|
+
import { stageRecoveryChild } from "./frontend-recovery-run.js";
|
|
4
8
|
import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
|
|
5
9
|
import { DAG_RUNS_DIR, isTerminalDagRunStatus, locateDagRun, readDagRunSpec, readDagRunState, } from "./lifecycle.js";
|
|
6
10
|
import { deriveDagRerunFeedback } from "./rerun-feedback.js";
|
|
11
|
+
import { acquireDagRecoveryLease, bindDagRecoveryLeaseExecution, } from "./recovery-lease.js";
|
|
7
12
|
import { parseDagSpec, } from "./types.js";
|
|
8
13
|
export const RERUN_TASK_LINEAGE_REL_PATH = ".runtime/rerun-task-lineage.json";
|
|
9
14
|
export function parseDagRerunTaskArgs(args) {
|
|
10
15
|
if (args.length === 0) {
|
|
11
|
-
throw new Error("usage: dag rerun-task --run-id <id> --reason <text> --request-id <key> [--profile auto|minimal|standard|reviewed|supervised] [--task-id <id>] [--json]");
|
|
16
|
+
throw new Error("usage: dag rerun-task --run-id <id> --reason <text> --request-id <key> [--profile auto|minimal|standard|reviewed|supervised] [--task-id <id>] [--frontend-recovery --recovery-operation-id <id>] [--json]");
|
|
12
17
|
}
|
|
13
18
|
let parentRunId;
|
|
14
19
|
let reason;
|
|
@@ -17,6 +22,8 @@ export function parseDagRerunTaskArgs(args) {
|
|
|
17
22
|
let profileExplicit = false;
|
|
18
23
|
let taskIdOverride;
|
|
19
24
|
let execute = true;
|
|
25
|
+
let frontendRecovery = false;
|
|
26
|
+
let recoveryOperationId;
|
|
20
27
|
for (let index = 0; index < args.length; index += 1) {
|
|
21
28
|
const arg = args[index];
|
|
22
29
|
if (arg === "--run-id")
|
|
@@ -47,6 +54,12 @@ export function parseDagRerunTaskArgs(args) {
|
|
|
47
54
|
continue;
|
|
48
55
|
else if (arg === "--no-execute")
|
|
49
56
|
execute = false;
|
|
57
|
+
else if (arg === "--frontend-recovery")
|
|
58
|
+
frontendRecovery = true;
|
|
59
|
+
else if (arg === "--recovery-operation-id")
|
|
60
|
+
recoveryOperationId = args[++index];
|
|
61
|
+
else if (arg.startsWith("--recovery-operation-id="))
|
|
62
|
+
recoveryOperationId = arg.slice("--recovery-operation-id=".length);
|
|
50
63
|
else if (arg.startsWith("-"))
|
|
51
64
|
throw new Error(`unknown dag rerun-task flag: ${arg}`);
|
|
52
65
|
else
|
|
@@ -69,6 +82,48 @@ export function parseDagRerunTaskArgs(args) {
|
|
|
69
82
|
profileExplicit,
|
|
70
83
|
...(taskIdOverride?.trim() ? { taskIdOverride: taskIdOverride.trim() } : {}),
|
|
71
84
|
execute,
|
|
85
|
+
frontendRecovery,
|
|
86
|
+
...(recoveryOperationId ? { recoveryOperationId } : {}),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const frontendRecoveryDescriptorPath = (runDir, requestId) => path.join(runDir, ".runtime", "frontend-recovery", `${requestId}.json`);
|
|
90
|
+
async function readFrontendRecoveryDescriptor(runDir, parentRunId, requestId) {
|
|
91
|
+
const raw = JSON.parse(await readFile(frontendRecoveryDescriptorPath(runDir, requestId), "utf8"));
|
|
92
|
+
const plan = raw.plan;
|
|
93
|
+
if (raw.schemaVersion !== 1 ||
|
|
94
|
+
raw.parentRunId !== parentRunId ||
|
|
95
|
+
raw.requestId !== requestId ||
|
|
96
|
+
typeof raw.failureSource !== "string" ||
|
|
97
|
+
typeof raw.recoveryMode !== "string" ||
|
|
98
|
+
typeof raw.planHash !== "string" ||
|
|
99
|
+
!plan ||
|
|
100
|
+
plan.schemaVersion !== 1 ||
|
|
101
|
+
plan.parentRunId !== parentRunId ||
|
|
102
|
+
plan.requestId !== requestId ||
|
|
103
|
+
!Array.isArray(plan.resetNodeIds) ||
|
|
104
|
+
!Array.isArray(plan.importedNodeIds)) {
|
|
105
|
+
throw new Error("frontend recovery descriptor is invalid or unbound");
|
|
106
|
+
}
|
|
107
|
+
const expectedHash = createHash("sha256")
|
|
108
|
+
.update(JSON.stringify(plan))
|
|
109
|
+
.digest("hex");
|
|
110
|
+
if (raw.planHash !== expectedHash) {
|
|
111
|
+
throw new Error("frontend recovery descriptor plan hash mismatch");
|
|
112
|
+
}
|
|
113
|
+
return raw;
|
|
114
|
+
}
|
|
115
|
+
function buildFrontendRecoveryIntent(input) {
|
|
116
|
+
return {
|
|
117
|
+
schemaVersion: 1,
|
|
118
|
+
phase: "child-staging",
|
|
119
|
+
requestId: input.requestId,
|
|
120
|
+
recoveryRootRunId: input.parentRecovery?.recoveryRootRunId ?? input.parentRunId,
|
|
121
|
+
parentRunId: input.parentRunId,
|
|
122
|
+
attemptId: input.requestId,
|
|
123
|
+
attemptIndex: input.parentRecovery?.attemptIndex ?? 0,
|
|
124
|
+
continuationCount: input.parentRecovery?.continuationCount ?? 0,
|
|
125
|
+
failureSource: input.failureSource,
|
|
126
|
+
revision: 0,
|
|
72
127
|
};
|
|
73
128
|
}
|
|
74
129
|
function parseDagRerunTaskProfile(value) {
|
|
@@ -135,6 +190,21 @@ function resolveTaskIdForRerun(spec, taskIdOverride) {
|
|
|
135
190
|
function operatorRequestPath(cwd, requestId) {
|
|
136
191
|
return path.join(cwd, DAG_RUNS_DIR, ".operator-requests", `${requestId}.json`);
|
|
137
192
|
}
|
|
193
|
+
function computeRerunTaskRequestHash(input) {
|
|
194
|
+
return createHash("sha256")
|
|
195
|
+
.update(JSON.stringify({
|
|
196
|
+
parentRunId: input.parentRunId,
|
|
197
|
+
reason: input.reason,
|
|
198
|
+
requestId: input.requestId,
|
|
199
|
+
profile: input.profile ?? "auto",
|
|
200
|
+
profileExplicit: input.profileExplicit ?? false,
|
|
201
|
+
taskIdOverride: input.taskIdOverride ?? null,
|
|
202
|
+
execute: input.execute ?? true,
|
|
203
|
+
frontendRecovery: input.frontendRecovery ?? false,
|
|
204
|
+
recoveryOperationId: input.recoveryOperationId ?? null,
|
|
205
|
+
}))
|
|
206
|
+
.digest("hex");
|
|
207
|
+
}
|
|
138
208
|
async function fileExists(filePath) {
|
|
139
209
|
try {
|
|
140
210
|
await access(filePath);
|
|
@@ -184,23 +254,45 @@ export async function assessGeneratedOutputConflict(spec, cwd) {
|
|
|
184
254
|
}
|
|
185
255
|
return conflictPaths;
|
|
186
256
|
}
|
|
187
|
-
async function readExistingOperatorRequest(cwd, requestId) {
|
|
257
|
+
async function readExistingOperatorRequest(cwd, requestId, expected) {
|
|
258
|
+
let raw;
|
|
188
259
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
260
|
+
raw = JSON.parse(await readFile(operatorRequestPath(cwd, requestId), "utf-8"));
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
if (error &&
|
|
264
|
+
typeof error === "object" &&
|
|
265
|
+
"code" in error &&
|
|
266
|
+
error.code === "ENOENT") {
|
|
267
|
+
return undefined;
|
|
192
268
|
}
|
|
269
|
+
throw new Error(`invalid persisted rerun-task operator request: ${error instanceof Error ? error.message : String(error)}`);
|
|
193
270
|
}
|
|
194
|
-
|
|
195
|
-
|
|
271
|
+
if (raw.schemaVersion !== 1 ||
|
|
272
|
+
raw.kind !== "standalone-task-rerun-request" ||
|
|
273
|
+
raw.requestId !== requestId) {
|
|
274
|
+
throw new Error("REQUEST_ID_REUSE_CONFLICT: operator request id belongs to a different request kind");
|
|
275
|
+
}
|
|
276
|
+
if (raw.parentRunId !== expected.parentRunId ||
|
|
277
|
+
raw.requestHash !== expected.requestHash) {
|
|
278
|
+
throw new Error("REQUEST_ID_REUSE_CONFLICT: rerun-task operator request payload drifted");
|
|
196
279
|
}
|
|
197
|
-
|
|
280
|
+
const result = raw.result;
|
|
281
|
+
if (!result ||
|
|
282
|
+
typeof result !== "object" ||
|
|
283
|
+
Array.isArray(result) ||
|
|
284
|
+
result.parentRunId !== expected.parentRunId ||
|
|
285
|
+
result.requestId !== requestId) {
|
|
286
|
+
throw new Error("invalid persisted rerun-task operator request result");
|
|
287
|
+
}
|
|
288
|
+
return { ...result, idempotentReplay: true };
|
|
198
289
|
}
|
|
199
|
-
async function persistOperatorRequest(cwd, result) {
|
|
290
|
+
async function persistOperatorRequest(cwd, result, requestHash) {
|
|
200
291
|
await writeJsonAtomic(operatorRequestPath(cwd, result.requestId), {
|
|
201
292
|
schemaVersion: 1,
|
|
202
293
|
kind: "standalone-task-rerun-request",
|
|
203
294
|
parentRunId: result.parentRunId,
|
|
295
|
+
requestHash,
|
|
204
296
|
newRunId: result.newRunId,
|
|
205
297
|
taskId: result.taskId,
|
|
206
298
|
reason: result.reason,
|
|
@@ -263,8 +355,106 @@ function extractNewRunId(generateResult) {
|
|
|
263
355
|
const runSummary = extractRunSummary(generateResult);
|
|
264
356
|
return runSummary?.runId;
|
|
265
357
|
}
|
|
358
|
+
async function executeFrontendRecoveryContinuation(input) {
|
|
359
|
+
const located = await locateDagRun(input.cwd, input.parentRunId);
|
|
360
|
+
if (!located || located.lifecycle !== "active") {
|
|
361
|
+
throw new Error(`frontend recovery parent run must remain active: ${input.parentRunId}`);
|
|
362
|
+
}
|
|
363
|
+
const lease = await acquireDagRecoveryLease({
|
|
364
|
+
cwd: input.cwd,
|
|
365
|
+
parentRunId: input.parentRunId,
|
|
366
|
+
requestId: input.requestId,
|
|
367
|
+
kind: "standalone-task-rerun",
|
|
368
|
+
});
|
|
369
|
+
if (lease.kind !== "held" ||
|
|
370
|
+
lease.lease.kind !== "auto-frontend-recovery" ||
|
|
371
|
+
lease.lease.requestId !== input.requestId ||
|
|
372
|
+
!input.recoveryOperationId ||
|
|
373
|
+
lease.lease.executionRef !== input.recoveryOperationId) {
|
|
374
|
+
return blockedResult({
|
|
375
|
+
parentRunId: input.parentRunId,
|
|
376
|
+
reason: input.reason,
|
|
377
|
+
requestId: input.requestId,
|
|
378
|
+
blockedReason: "recovery-lease-held",
|
|
379
|
+
note: "frontend recovery operation is not the owner of the parent recovery lease",
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
const descriptor = await readFrontendRecoveryDescriptor(located.runDir, input.parentRunId, input.requestId);
|
|
383
|
+
const parentState = await readDagRunState(located.runDir);
|
|
384
|
+
const staged = await stageRecoveryChild({
|
|
385
|
+
cwd: input.cwd,
|
|
386
|
+
parentRunId: input.parentRunId,
|
|
387
|
+
recoveryIntent: buildFrontendRecoveryIntent({
|
|
388
|
+
parentRunId: input.parentRunId,
|
|
389
|
+
requestId: input.requestId,
|
|
390
|
+
failureSource: descriptor.failureSource,
|
|
391
|
+
parentRecovery: parentState.frontendRecoveryState,
|
|
392
|
+
}),
|
|
393
|
+
recoveryPlan: descriptor.plan,
|
|
394
|
+
});
|
|
395
|
+
const locatedChild = await locateDagRun(input.cwd, staged.childRunId);
|
|
396
|
+
if (!locatedChild || locatedChild.runDir !== staged.childRunDir) {
|
|
397
|
+
throw new Error(`frontend recovery child lifecycle drift: ${staged.childRunId}`);
|
|
398
|
+
}
|
|
399
|
+
const childSpec = await readDagRunSpec(locatedChild.runDir);
|
|
400
|
+
const childState = await readDagRunState(locatedChild.runDir);
|
|
401
|
+
let runSummary;
|
|
402
|
+
if (locatedChild.lifecycle === "completed" ||
|
|
403
|
+
locatedChild.lifecycle === "paused") {
|
|
404
|
+
runSummary = {
|
|
405
|
+
title: childState.title,
|
|
406
|
+
runId: childState.runId,
|
|
407
|
+
status: childState.status,
|
|
408
|
+
ranks: childState.ranks,
|
|
409
|
+
nodes: childState.nodes,
|
|
410
|
+
runDir: locatedChild.runDir,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
const childRecovery = childSpec.tasks.some((task) => task.id === "frontend-implement-pi")
|
|
415
|
+
? input.recovery ?? await buildDefaultFrontendRecoveryDeps(input.cwd)
|
|
416
|
+
: undefined;
|
|
417
|
+
runSummary = await runDagContinuation({
|
|
418
|
+
cwd: input.cwd,
|
|
419
|
+
spec: childSpec,
|
|
420
|
+
state: childState,
|
|
421
|
+
runDir: locatedChild.runDir,
|
|
422
|
+
...(childRecovery ? { recovery: childRecovery } : {}),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
const settledChild = await locateDagRun(input.cwd, staged.childRunId);
|
|
426
|
+
const settledChildState = settledChild
|
|
427
|
+
? await readDagRunState(settledChild.runDir)
|
|
428
|
+
: childState;
|
|
429
|
+
const feedback = summarizeFeedback(childSpec.rerunFeedback, "no-unresolved-verify-review-feedback");
|
|
430
|
+
const result = {
|
|
431
|
+
ok: runSummary.status === "finished" ||
|
|
432
|
+
settledChildState.frontendRecoveryResult?.outcome === "recovered",
|
|
433
|
+
parentRunId: input.parentRunId,
|
|
434
|
+
newRunId: staged.childRunId,
|
|
435
|
+
taskId: childSpec.taskContractBinding?.taskId ??
|
|
436
|
+
childSpec.sourceBinding?.taskId,
|
|
437
|
+
reason: input.reason,
|
|
438
|
+
requestId: input.requestId,
|
|
439
|
+
mode: "generate+validate+execute",
|
|
440
|
+
feedback,
|
|
441
|
+
runSummary,
|
|
442
|
+
};
|
|
443
|
+
await writeRerunTaskLineage(input.cwd, staged.childRunId, {
|
|
444
|
+
parentRunId: input.parentRunId,
|
|
445
|
+
reason: input.reason,
|
|
446
|
+
requestId: input.requestId,
|
|
447
|
+
feedback,
|
|
448
|
+
});
|
|
449
|
+
await persistOperatorRequest(input.cwd, result, input.requestHash);
|
|
450
|
+
return result;
|
|
451
|
+
}
|
|
266
452
|
export async function rerunStandaloneTask(input) {
|
|
267
|
-
const
|
|
453
|
+
const requestHash = computeRerunTaskRequestHash(input);
|
|
454
|
+
const existing = await readExistingOperatorRequest(input.cwd, input.requestId, {
|
|
455
|
+
parentRunId: input.parentRunId,
|
|
456
|
+
requestHash,
|
|
457
|
+
});
|
|
268
458
|
if (existing) {
|
|
269
459
|
return existing;
|
|
270
460
|
}
|
|
@@ -297,6 +487,17 @@ export async function rerunStandaloneTask(input) {
|
|
|
297
487
|
note: eligibility.note,
|
|
298
488
|
});
|
|
299
489
|
}
|
|
490
|
+
if (input.frontendRecovery) {
|
|
491
|
+
return executeFrontendRecoveryContinuation({
|
|
492
|
+
cwd: input.cwd,
|
|
493
|
+
parentRunId: input.parentRunId,
|
|
494
|
+
reason: input.reason,
|
|
495
|
+
requestId: input.requestId,
|
|
496
|
+
requestHash,
|
|
497
|
+
recoveryOperationId: input.recoveryOperationId,
|
|
498
|
+
recovery: input.recovery,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
300
501
|
let parentFeedback;
|
|
301
502
|
let missingFeedbackReason = "no-unresolved-verify-review-feedback";
|
|
302
503
|
try {
|
|
@@ -308,12 +509,18 @@ export async function rerunStandaloneTask(input) {
|
|
|
308
509
|
state,
|
|
309
510
|
});
|
|
310
511
|
}
|
|
311
|
-
catch {
|
|
512
|
+
catch (error) {
|
|
513
|
+
if (state.terminalReason === "design-request-changes") {
|
|
514
|
+
throw new Error(`frontend design recovery feedback unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
515
|
+
}
|
|
312
516
|
// Feedback is additive recovery context. A corrupt/missing historical
|
|
313
517
|
// artifact must be reported honestly but must not block an otherwise
|
|
314
518
|
// eligible full rerun.
|
|
315
519
|
missingFeedbackReason = "feedback-unavailable";
|
|
316
520
|
}
|
|
521
|
+
if (state.terminalReason === "design-request-changes" && !parentFeedback) {
|
|
522
|
+
throw new Error("frontend design recovery feedback unavailable: no typed findings were found");
|
|
523
|
+
}
|
|
317
524
|
const execute = input.execute ?? true;
|
|
318
525
|
let effectiveFeedback;
|
|
319
526
|
let expectedRerunFeedbackDigest;
|
|
@@ -369,6 +576,34 @@ export async function rerunStandaloneTask(input) {
|
|
|
369
576
|
}
|
|
370
577
|
}
|
|
371
578
|
}
|
|
579
|
+
const recoveryLease = execute
|
|
580
|
+
? await acquireDagRecoveryLease({
|
|
581
|
+
cwd: input.cwd,
|
|
582
|
+
parentRunId: input.parentRunId,
|
|
583
|
+
requestId: input.requestId,
|
|
584
|
+
kind: "standalone-task-rerun",
|
|
585
|
+
})
|
|
586
|
+
: undefined;
|
|
587
|
+
if (recoveryLease?.kind === "held") {
|
|
588
|
+
return blockedResult({
|
|
589
|
+
parentRunId: input.parentRunId,
|
|
590
|
+
reason: input.reason,
|
|
591
|
+
requestId: input.requestId,
|
|
592
|
+
blockedReason: "recovery-lease-held",
|
|
593
|
+
note: `parent run recovery is already claimed by ${recoveryLease.lease.kind} request ${recoveryLease.lease.requestId}`,
|
|
594
|
+
taskId: taskResolution.taskId,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
if (recoveryLease?.kind === "acquired") {
|
|
598
|
+
// Persist a non-empty execution identity before generateTaskDagUseCase can
|
|
599
|
+
// execute its new DAG. The generated run id is not available yet, so the
|
|
600
|
+
// request id is the stable lineage handle for this entry point.
|
|
601
|
+
await bindDagRecoveryLeaseExecution({
|
|
602
|
+
leasePath: recoveryLease.leasePath,
|
|
603
|
+
lease: recoveryLease.lease,
|
|
604
|
+
executionRef: `standalone-task-rerun:${input.requestId}`,
|
|
605
|
+
});
|
|
606
|
+
}
|
|
372
607
|
const generateResult = await generateTaskDagUseCase({
|
|
373
608
|
repoRoot: input.cwd,
|
|
374
609
|
taskId: taskResolution.taskId,
|
|
@@ -420,10 +655,13 @@ export async function rerunStandaloneTask(input) {
|
|
|
420
655
|
...(runSummary ? { runSummary } : {}),
|
|
421
656
|
};
|
|
422
657
|
if (await fileExists(operatorRequestPath(input.cwd, input.requestId))) {
|
|
423
|
-
const replay = await readExistingOperatorRequest(input.cwd, input.requestId
|
|
658
|
+
const replay = await readExistingOperatorRequest(input.cwd, input.requestId, {
|
|
659
|
+
parentRunId: input.parentRunId,
|
|
660
|
+
requestHash,
|
|
661
|
+
});
|
|
424
662
|
if (replay)
|
|
425
663
|
return replay;
|
|
426
664
|
}
|
|
427
|
-
await persistOperatorRequest(input.cwd, result);
|
|
665
|
+
await persistOperatorRequest(input.cwd, result, requestHash);
|
|
428
666
|
return result;
|
|
429
667
|
}
|