@tea-agent/loop-agent 0.41.1-beta.0 → 0.42.0-next.2
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/CHANGELOG.md +78 -206
- package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
- package/dist/adapters/context-transfer/pi-session.js +61 -0
- package/dist/application/dag/generate-task-dag.js +19 -75
- package/dist/application/task-lifecycle/advance.js +5 -24
- package/dist/application/task-lifecycle/observe.js +17 -171
- package/dist/application/task-lifecycle/plan-transitions.js +7 -42
- package/dist/application/task-lifecycle/recommendations.js +2 -13
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +12 -7
- package/dist/cli/program.js +23 -6
- package/dist/commands/client-recovery.js +0 -3
- package/dist/commands/dag-artifact.js +284 -0
- package/dist/commands/dag-context.js +184 -0
- package/dist/commands/dag-rerun.js +206 -1
- package/dist/commands/init.js +1 -27
- package/dist/commands/task-advance.js +0 -19
- package/dist/executors/dag-pi-executor.js +266 -3792
- package/dist/executors/pi-executor.js +4 -15
- package/dist/executors/pi-sdk-executor.js +3 -0
- package/dist/executors/shell-executor.js +217 -945
- package/dist/executors/shell-write-guard.js +0 -7
- package/dist/{worker → infrastructure}/console/app-data.js +4 -0
- package/dist/infrastructure/console/artifact-revision-store.js +430 -0
- package/dist/infrastructure/console/context-export-store.js +160 -0
- package/dist/infrastructure/console/dir-lock.js +132 -0
- package/dist/infrastructure/console/operation-store.js +197 -0
- package/dist/infrastructure/harness/artifact-store.js +10 -1
- package/dist/infrastructure/harness/atomic-write.js +12 -2
- package/dist/shared/context-transfer/artifact-revision.js +172 -0
- package/dist/shared/context-transfer.js +418 -0
- package/dist/shared/dag-failure-category.js +0 -12
- package/dist/shared/openspec-spec.js +4 -70
- package/dist/shared/operator/capabilities.js +14 -7
- package/dist/shared/operator/safe-run-summary.js +1 -0
- package/dist/shared/path-safety.js +93 -0
- package/dist/shared/preview.js +28 -4
- package/dist/task/config-types.js +80 -35
- package/dist/task/contract/adopt.js +0 -4
- package/dist/task/contract/import-revision.js +0 -4
- package/dist/task/contract/project.js +0 -3
- package/dist/task/contract/schema.js +1 -2
- package/dist/task/frontend-project-capability.js +20 -203
- package/dist/task/runtime.js +2 -5
- package/dist/task/source-prepare/build-draft.js +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +9 -15
- package/dist/task/source-prepare/prepare.js +1 -89
- package/dist/task/source-prepare/semantic-intake.js +2 -6
- package/dist/task/source-references.js +1 -22
- package/dist/task/task-demand-routing.js +3 -0
- package/dist/worker/console/chat/chat-event-store.js +2 -2
- package/dist/worker/console/chat/pi-runtime.js +3 -2
- package/dist/worker/console/chat/resource-preferences-store.js +1 -1
- package/dist/worker/console/chat/routes.js +13 -4
- package/dist/worker/console/chat/semantic-activity.js +12 -11
- package/dist/worker/console/chat/session-stats.js +96 -0
- package/dist/worker/console/chat/session-store.js +1 -1
- package/dist/worker/console/chat/turn-process.js +28 -4
- package/dist/worker/console/chat/user-questions.js +1 -1
- package/dist/worker/console/console-update-runtime.js +1 -1
- package/dist/worker/console/context-transfer-diagnostics.js +198 -0
- package/dist/worker/console/dag-confirmation.js +1 -1
- package/dist/worker/console/dag-execution-receipt.js +1 -1
- package/dist/worker/console/doctor.js +1 -1
- package/dist/worker/console/draft-store.js +1 -1
- package/dist/worker/console/human-gate-token.js +1 -1
- package/dist/worker/console/index.js +3 -6
- package/dist/worker/console/interview/assessment.js +1 -1
- package/dist/worker/console/interview/session.js +1 -1
- package/dist/worker/console/operation-runner.js +45 -4
- package/dist/worker/console/operation-sse.js +1 -1
- package/dist/worker/console/operation-wait.js +1 -1
- package/dist/worker/console/operator-actions.js +107 -168
- package/dist/worker/console/operator-surface-health.js +1 -1
- package/dist/worker/console/operator-user-error.js +169 -0
- package/dist/worker/console/pi-plugins.js +60 -1
- package/dist/worker/console/routes.js +637 -8
- package/dist/worker/console/security.js +35 -0
- package/dist/worker/console/server.js +6 -6
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-DZZ8m3PO.js} +1 -1
- package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-D6PvaVd-.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-B_OTOiI8.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-Bv6rqHBg.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-B8eHr0oz.js} +1 -1
- package/dist/worker/console/static/assets/channel-BU5gOilw.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-DYwR0im2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-D2WPGqXt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CQISJ_I7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-C0o2Du1e.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-4f8kr-U7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-D_OWvXzX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-CasdPz5X.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-Cj8lRrla.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-CUvD1FSd.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CqLw_eqB.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-ku-WqJPx.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-Bq_PYDhl.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-BiGZV641.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-C4JRlglF.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-B0dNeWYG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-Cj35YvYM.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-uzQoJ2-8.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-D1a-Buoz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-XjRrLRSs.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-Da_O24cW.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-BLJ8jrYU.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-B9GrLjM0.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-CeJ0TqiK.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js} +1 -1
- package/dist/worker/console/static/assets/index-H9rFJiGL.css +1 -0
- package/dist/worker/console/static/assets/index-xwu9GxEc.js +451 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-DB26i3d8.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-BOGRyeZT.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-CZRoBO_6.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-qlWhJyoB.js} +1 -1
- package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CfUiDDB3.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-BQe6fpqj.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-zFzWHw64.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-DFGUqjZO.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-BB5i0l8Z.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-obbVZ_X5.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-BwdaNzc1.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-CkTJaugh.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-BwJ-hIgq.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-BzSgmm7w.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-Bn3oj5Q1.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-dxhGtL8K.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-BLpEInya.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-ChJGYcXy.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-DK-qjRer.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-3qeaWAg-.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CootlyP9.js} +1 -1
- package/dist/worker/console/static/index.html +7 -2
- package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
- package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
- package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
- package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
- package/dist/worker/console/static-src/shell/console-update-reload.js +25 -0
- package/dist/worker/console/workspace-context.js +28 -112
- package/dist/worker/console/workspace-registry.js +2 -2
- package/dist/worker/continuation/worker-continuation.js +278 -0
- package/dist/worker/observability/read-model.js +4 -0
- package/dist/worker/observe/health.js +1 -1
- package/dist/worker/observe/node-transparency.js +572 -0
- package/dist/worker/observe/routes.js +51 -1
- package/dist/worker/observe/static/api.js +69 -5
- package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
- package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
- package/dist/worker/observe/static/dag-node-purpose.js +0 -5
- package/dist/worker/observe/static/state.js +3 -1
- package/dist/worker/observe/static/styles.css +1037 -126
- package/dist/worker/observe/static/views/dag-inspector.js +1217 -65
- package/dist/worker/observe/static/views/session-timeline.js +121 -25
- package/dist/worker/outcomes/adapters.js +19 -0
- package/dist/worker/outcomes/types.js +1 -0
- package/dist/worker/pool/attempt-lease.js +97 -66
- package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
- package/dist/worker/pool/reconcile.js +46 -1
- package/dist/worker/pool/run-store.js +2 -0
- package/dist/worker/pool/state-projection.js +2 -0
- package/dist/worker/task-spec/workflow-routing.js +8 -3
- package/dist/workflows/dag/artifact-bindings.js +149 -0
- package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +99 -4
- package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/backend-test-writer-completeness.js +45 -3
- package/dist/workflows/dag/budget-enforcement.js +10 -0
- package/dist/workflows/dag/context-receipt.js +305 -0
- package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
- package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
- package/dist/workflows/dag/context-transfer/renderers.js +93 -0
- package/dist/workflows/dag/contract-validator-registrations.js +2 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
- package/dist/workflows/dag/frontend-plan-render.js +1 -2
- package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
- package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
- package/dist/workflows/dag/frontend-recovery-run.js +20 -33
- package/dist/workflows/dag/frontend-repair.js +432 -1
- package/dist/workflows/dag/frontend-review-context.js +15 -261
- package/dist/workflows/dag/frontend-verification-trace.js +24 -249
- package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
- package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
- package/dist/workflows/dag/init-hybrid.js +740 -718
- package/dist/workflows/dag/interrupt-request.js +0 -7
- package/dist/workflows/dag/node-execution.js +136 -759
- package/dist/workflows/dag/path-safety.js +1 -0
- package/dist/workflows/dag/prompt.js +30 -38
- package/dist/workflows/dag/report.js +1 -37
- package/dist/workflows/dag/rerun-feedback.js +1 -256
- package/dist/workflows/dag/rerun-plan.js +557 -11
- package/dist/workflows/dag/rerun-run.js +601 -38
- package/dist/workflows/dag/rerun-task.js +0 -29
- package/dist/workflows/dag/retry-policy.js +109 -214
- package/dist/workflows/dag/runner.js +142 -430
- package/dist/workflows/dag/scheduler.js +16 -114
- package/dist/workflows/dag/skill-snapshot.js +17 -0
- package/dist/workflows/dag/types.js +195 -246
- package/dist/workflows/dag/validate.js +12 -28
- package/docs/architecture/runtime-boundaries.md +6 -6
- package/docs/architecture/worker-and-feature.md +1 -1
- package/docs/init-surface.manifest.json +12 -30
- package/docs/skills/vetted-skill-registry.md +2 -4
- package/docs/templates/README.md +0 -2
- package/docs/templates/agent-dag-report.schema.json +2 -8
- package/docs/templates/agent-dag.schema.json +33 -1
- package/docs/templates/backend-test-dag.json +18 -18
- package/docs/templates/frontend-implementation-contract.schema.json +1 -4
- package/docs/templates/product-line/task.yaml +1 -1
- package/harness.json +3 -3
- package/package.json +3 -1
- package/skills/frontend-bounded-implement/SKILL.md +14 -15
- package/skills/frontend-design-review/SKILL.md +41 -22
- package/skills/frontend-implementation/SKILL.md +52 -0
- package/skills/frontend-implementation/references/code-standards.md +33 -0
- package/skills/frontend-implementation/references/design-spec.md +56 -0
- package/skills/frontend-implementation/references/node-contracts.md +31 -0
- package/skills/frontend-review/SKILL.md +15 -20
- package/skills/frontend-review/references/review-findings.md +7 -6
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/loop-agent/references/command-reference.md +6 -1
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/commands/dag-follow-up.js +0 -138
- package/dist/executors/pi-read-budget-policy.js +0 -239
- package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
- package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
- package/dist/worker/console/operation-store.js +0 -389
- package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
- package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
- package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
- package/dist/worker/console/static-src/active-run-badge.js +0 -17
- package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
- package/dist/workflows/dag/dag-retry-schema.js +0 -138
- package/dist/workflows/dag/frontend-closeout.js +0 -221
- package/dist/workflows/dag/frontend-design-policy.js +0 -400
- package/dist/workflows/dag/frontend-human-decision.js +0 -182
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
- package/dist/workflows/dag/frontend-read-budgets.js +0 -12
- package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
- package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
- package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
- package/dist/workflows/dag/frontend-review-findings.js +0 -270
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
- package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
- package/dist/workflows/dag/frontend-shape-facts.js +0 -409
- package/dist/workflows/dag/frontend-shape.js +0 -427
- package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
- package/dist/workflows/dag/frontend-split-application-service.js +0 -203
- package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
- package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
- package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
- package/dist/workflows/dag/frontend-writer-admission.js +0 -285
- package/dist/workflows/dag/frontend-writer-status.js +0 -256
- package/dist/workflows/dag/recovery-lease.js +0 -80
- package/docs/templates/frontend-implementation-dag.json +0 -89
- package/docs/templates/spec-registry.schema.json +0 -45
- package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
- package/skills/frontend-contract/SKILL.md +0 -23
- package/skills/frontend-contract/references/contract-protocol.md +0 -34
- package/skills/frontend-plan/SKILL.md +0 -26
- package/skills/frontend-plan/references/decision-contract.md +0 -37
- package/skills/frontend-plan/references/design-decisions.md +0 -17
- package/skills/frontend-scout/SKILL.md +0 -25
- package/skills/frontend-scout/references/design-evidence.md +0 -16
- package/skills/frontend-scout/references/scout-evidence.md +0 -23
- /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { isOpenspecSpecFilePath } from "../../shared/openspec-spec.js";
|
|
3
3
|
import { campaignBudgetSchema, } from "../../application/evaluation/budget.js";
|
|
4
4
|
import { assertDagPromptSourceRule } from "./prompt-source.js";
|
|
5
|
-
|
|
6
|
-
// never transitively reaches types.ts during init (retry-policy does, via
|
|
7
|
-
// frontend-recovery-capsule → frontend-recovery-lineage →
|
|
8
|
-
// frontend-implementation-contract), or a run whose entry module initializes
|
|
9
|
-
// retry-policy first reads an undefined schema here.
|
|
10
|
-
import { dagRetryPolicySchema, TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE, } from "./dag-retry-schema.js";
|
|
5
|
+
import { dagRetryPolicySchema, TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE, } from "./retry-policy.js";
|
|
11
6
|
import { dagLivenessPolicySchema, } from "./liveness-policy.js";
|
|
12
7
|
import { dagOutputProtocolSchema } from "./output-protocol.js";
|
|
13
8
|
export const dagComplexitySchema = z.enum(["HIGH", "MED", "LOW"]);
|
|
@@ -85,7 +80,10 @@ export const dagShellVerifyEvidenceSchema = z.object({
|
|
|
85
80
|
selectionReasons: z.array(z.string()).default([]),
|
|
86
81
|
/** Non-executing generation-time cwd/local-script validation evidence. */
|
|
87
82
|
preflight: z
|
|
88
|
-
.array(z.object({
|
|
83
|
+
.array(z.object({
|
|
84
|
+
label: z.string(),
|
|
85
|
+
status: z.enum(["ok", "future-delivery-script"]),
|
|
86
|
+
}))
|
|
89
87
|
.default([]),
|
|
90
88
|
/** Effective timeout applied independently to each shell command. */
|
|
91
89
|
commandTimeoutMs: z.number().int().positive().optional(),
|
|
@@ -190,16 +188,7 @@ const dagFrontendNodeIdSchema = z
|
|
|
190
188
|
.regex(/^[a-z][a-z0-9-]*$/, "frontend node id must be kebab-case");
|
|
191
189
|
const openspecCandidatePathSchema = z
|
|
192
190
|
.string()
|
|
193
|
-
.refine((candidate) => !candidate.includes("\\") &&
|
|
194
|
-
!candidate.startsWith("/") &&
|
|
195
|
-
!candidate.split("/").includes("..") &&
|
|
196
|
-
OPENSPEC_SPEC_EXT_RE.test(candidate), "openspec candidate must be a repo-relative supported specification file");
|
|
197
|
-
const openspecCandidateSnapshotSchema = z
|
|
198
|
-
.object({
|
|
199
|
-
path: openspecCandidatePathSchema,
|
|
200
|
-
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
201
|
-
})
|
|
202
|
-
.strict();
|
|
191
|
+
.refine((candidate) => !candidate.includes("\\") && isOpenspecSpecFilePath(candidate), "openspec candidate must be a repo-relative supported file under openspec/schemas/, openspec/project-specs/, or ai_workspace/");
|
|
203
192
|
export const dagFrontendPrewriteGateSchema = z.object({
|
|
204
193
|
schemaVersion: z.literal(1),
|
|
205
194
|
planFromNodeId: dagFrontendNodeIdSchema,
|
|
@@ -218,24 +207,7 @@ export const dagFrontendPrewriteGateSchema = z.object({
|
|
|
218
207
|
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
219
208
|
requireSourceFreshness: z.literal(true),
|
|
220
209
|
implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
|
|
221
|
-
/**
|
|
222
|
-
* Generation-frozen roots that bound custom normative directories. Omitted
|
|
223
|
-
* legacy DAGs retain the canonical OpenSpec + ai_workspace roots.
|
|
224
|
-
*/
|
|
225
|
-
openspecSpecRoots: z
|
|
226
|
-
.array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
|
|
227
|
-
.optional(),
|
|
228
210
|
openspecCandidatePaths: z.array(openspecCandidatePathSchema).default([]),
|
|
229
|
-
/** Read-only selector output; omitted for scan-strict and legacy DAGs. */
|
|
230
|
-
openspecSelectionNodeId: dagFrontendNodeIdSchema.optional(),
|
|
231
|
-
/** Contract-declared and source-explicit paths that cannot be downgraded. */
|
|
232
|
-
openspecMandatoryPaths: z.array(openspecCandidatePathSchema).optional(),
|
|
233
|
-
/**
|
|
234
|
-
* Content fingerprints frozen with the generation-time OpenSpec scope. New
|
|
235
|
-
* DAGs use these to reject a plan whose cited specification changed after it
|
|
236
|
-
* was read; legacy DAGs without the field retain existence-only drift checks.
|
|
237
|
-
*/
|
|
238
|
-
openspecCandidateSnapshots: z.array(openspecCandidateSnapshotSchema).optional(),
|
|
239
211
|
/**
|
|
240
212
|
* Generation-frozen component/theme specification bucket. Derived from
|
|
241
213
|
* `designEvidence.classified.component ∪ theme ∪ rule.components` at DAG
|
|
@@ -280,28 +252,14 @@ export const dagFrontendPrewriteGateSchema = z.object({
|
|
|
280
252
|
scanStrict: z.array(openspecCandidatePathSchema).default([]),
|
|
281
253
|
})
|
|
282
254
|
.optional(),
|
|
283
|
-
}).superRefine((gate, context) => {
|
|
284
|
-
const roots = gate.openspecSpecRoots ?? DEFAULT_FRONTEND_SPEC_ROOTS;
|
|
285
|
-
const candidateGroups = [
|
|
286
|
-
["openspecCandidatePaths", gate.openspecCandidatePaths],
|
|
287
|
-
["openspecMandatoryPaths", gate.openspecMandatoryPaths],
|
|
288
|
-
["componentSpecCandidatePaths", gate.componentSpecCandidatePaths],
|
|
289
|
-
["openspecCandidateSources.declared", gate.openspecCandidateSources?.declared],
|
|
290
|
-
["openspecCandidateSources.taskSourceCited", gate.openspecCandidateSources?.taskSourceCited],
|
|
291
|
-
["openspecCandidateSources.scanStrict", gate.openspecCandidateSources?.scanStrict],
|
|
292
|
-
];
|
|
293
|
-
for (const [field, paths] of candidateGroups) {
|
|
294
|
-
for (const [index, candidate] of (paths ?? []).entries()) {
|
|
295
|
-
if (!isFrontendSpecFilePath(candidate, roots)) {
|
|
296
|
-
context.addIssue({
|
|
297
|
-
code: z.ZodIssueCode.custom,
|
|
298
|
-
path: [...field.split("."), index],
|
|
299
|
-
message: "openspec candidate must be a supported file under the generation-frozen openspec spec roots",
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
255
|
});
|
|
256
|
+
export const dagFrontendLintBaselineSchema = z
|
|
257
|
+
.object({
|
|
258
|
+
schemaVersion: z.literal(1),
|
|
259
|
+
lintCommands: z.array(z.string().min(1)).min(1),
|
|
260
|
+
lintEvidence: dagShellVerifyEvidenceSchema,
|
|
261
|
+
})
|
|
262
|
+
.strict();
|
|
305
263
|
export const dagFrontendVerificationBundleSchema = z
|
|
306
264
|
.object({
|
|
307
265
|
schemaVersion: z.literal(1),
|
|
@@ -315,10 +273,6 @@ export const dagFrontendVerificationBundleSchema = z
|
|
|
315
273
|
behaviorEvidence: dagShellVerifyEvidenceSchema,
|
|
316
274
|
lintBaselineNodeId: dagFrontendNodeIdSchema.optional(),
|
|
317
275
|
writerNodeIds: z.array(dagFrontendNodeIdSchema).optional(),
|
|
318
|
-
/** "initial" = first-pass assess bundle; "repair" = the convergence
|
|
319
|
-
* loop's post-repair reverify, which re-runs the same frozen commands
|
|
320
|
-
* and fails on any failure (still no same-run repair branch inside the
|
|
321
|
-
* node itself). */
|
|
322
276
|
mode: z.enum(["initial", "repair"]),
|
|
323
277
|
})
|
|
324
278
|
.superRefine((bundle, context) => {
|
|
@@ -394,135 +348,6 @@ export const dagFrontendReviewContextSchema = z.object({
|
|
|
394
348
|
schemaVersion: z.literal(1),
|
|
395
349
|
requireBaseline: z.literal(true),
|
|
396
350
|
});
|
|
397
|
-
/**
|
|
398
|
-
* Deterministic frontend contract-import shell (micro topology). Re-validates
|
|
399
|
-
* the generation-frozen managed Contract's source/binding/schema freshness and
|
|
400
|
-
* emits a digest. It never invokes a model and never rewrites requirements —
|
|
401
|
-
* micro requires a pre-validated managed Contract, not natural-language intake.
|
|
402
|
-
*/
|
|
403
|
-
export const dagFrontendContractImportSchema = z.object({
|
|
404
|
-
schemaVersion: z.literal(1),
|
|
405
|
-
artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
|
|
406
|
-
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
407
|
-
requireSourceFreshness: z.literal(true),
|
|
408
|
-
});
|
|
409
|
-
/**
|
|
410
|
-
* Deterministic frontend design-policy shell (M8). Materializes the canonical
|
|
411
|
-
* implementation contract from the plan node and evaluates the design policy
|
|
412
|
-
* (Mock strategy, source freshness, component spec candidates, writeSet
|
|
413
|
-
* patterns, allowed dependencies). Runs BEFORE frontend-design-review-pi, so it
|
|
414
|
-
* never consumes a design verdict; the verdict is enforced by the writer
|
|
415
|
-
* admission shell instead. Replaces the prewrite-gate authorization path.
|
|
416
|
-
*/
|
|
417
|
-
export const dagFrontendDesignPolicySchema = z
|
|
418
|
-
.object({
|
|
419
|
-
schemaVersion: z.literal(1),
|
|
420
|
-
planFromNodeId: dagFrontendNodeIdSchema,
|
|
421
|
-
requiredRequirementIds: z
|
|
422
|
-
.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/))
|
|
423
|
-
.default([]),
|
|
424
|
-
allowedMockStrategies: z
|
|
425
|
-
.array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"]))
|
|
426
|
-
.min(1),
|
|
427
|
-
/** Frozen Mock verification command labels the DAG will actually execute. */
|
|
428
|
-
mockCommandLabels: z.array(z.string()).default([]),
|
|
429
|
-
artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
|
|
430
|
-
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
431
|
-
requireSourceFreshness: z.literal(true),
|
|
432
|
-
implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
|
|
433
|
-
/** Generation-frozen roots that bound custom normative directories. */
|
|
434
|
-
openspecSpecRoots: z
|
|
435
|
-
.array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
|
|
436
|
-
.optional(),
|
|
437
|
-
openspecCandidatePaths: z.array(openspecCandidatePathSchema).default([]),
|
|
438
|
-
/** Read-only selector output; omitted for scan-strict and legacy DAGs. */
|
|
439
|
-
openspecSelectionNodeId: dagFrontendNodeIdSchema.optional(),
|
|
440
|
-
/** Contract-declared and source-explicit paths that cannot be downgraded. */
|
|
441
|
-
openspecMandatoryPaths: z.array(openspecCandidatePathSchema).optional(),
|
|
442
|
-
openspecCandidateSnapshots: z
|
|
443
|
-
.array(openspecCandidateSnapshotSchema)
|
|
444
|
-
.optional(),
|
|
445
|
-
/**
|
|
446
|
-
* Generation-frozen component/theme specification bucket. Derived from
|
|
447
|
-
* `designEvidence.classified.component ∪ theme ∪ rule.components` at DAG
|
|
448
|
-
* generation. When non-empty and the canonical contract has UI-visible
|
|
449
|
-
* work, the design policy requires a non-empty `uiComponentChoices` and
|
|
450
|
-
* cross-checks each `specReference.path` against this set + the effective
|
|
451
|
-
* plan openspec-citations block.
|
|
452
|
-
*/
|
|
453
|
-
componentSpecCandidatePaths: z.array(openspecCandidatePathSchema).optional(),
|
|
454
|
-
/** OpenSpec gate policy (cited | scan-strict); generation always writes it. */
|
|
455
|
-
openspecPolicy: z.enum(["cited", "scan-strict"]).optional(),
|
|
456
|
-
/** Generation-frozen candidate source metadata (diagnostic). */
|
|
457
|
-
openspecCandidateSources: z
|
|
458
|
-
.object({
|
|
459
|
-
declared: z.array(openspecCandidatePathSchema).default([]),
|
|
460
|
-
taskSourceCited: z.array(openspecCandidatePathSchema).default([]),
|
|
461
|
-
scanStrict: z.array(openspecCandidatePathSchema).default([]),
|
|
462
|
-
})
|
|
463
|
-
.optional(),
|
|
464
|
-
/** Dependency identifiers authorized at generation time (empty = none). */
|
|
465
|
-
allowedDependencies: z.array(z.string()).default([]),
|
|
466
|
-
})
|
|
467
|
-
.superRefine((gate, context) => {
|
|
468
|
-
const roots = gate.openspecSpecRoots ?? DEFAULT_FRONTEND_SPEC_ROOTS;
|
|
469
|
-
const candidateGroups = [
|
|
470
|
-
["openspecCandidatePaths", gate.openspecCandidatePaths],
|
|
471
|
-
["openspecMandatoryPaths", gate.openspecMandatoryPaths],
|
|
472
|
-
["componentSpecCandidatePaths", gate.componentSpecCandidatePaths],
|
|
473
|
-
["openspecCandidateSources.declared", gate.openspecCandidateSources?.declared],
|
|
474
|
-
["openspecCandidateSources.taskSourceCited", gate.openspecCandidateSources?.taskSourceCited],
|
|
475
|
-
["openspecCandidateSources.scanStrict", gate.openspecCandidateSources?.scanStrict],
|
|
476
|
-
];
|
|
477
|
-
for (const [field, paths] of candidateGroups) {
|
|
478
|
-
for (const [index, candidate] of (paths ?? []).entries()) {
|
|
479
|
-
if (!isFrontendSpecFilePath(candidate, roots)) {
|
|
480
|
-
context.addIssue({
|
|
481
|
-
code: z.ZodIssueCode.custom,
|
|
482
|
-
path: [...field.split("."), index],
|
|
483
|
-
message: "openspec candidate must be a supported file under the generation-frozen openspec spec roots",
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
/**
|
|
490
|
-
* Deterministic frontend writer-admission shell (M8). Runs after
|
|
491
|
-
* frontend-design-review-pi: freezes the writer baseline, derives the concrete
|
|
492
|
-
* writeSet, folds the design-policy result + design verdict into admission,
|
|
493
|
-
* and writes contracts/frontend-writer-admission-result.json
|
|
494
|
-
* (schemaId frontend-writer-admission-shell-v1).
|
|
495
|
-
*/
|
|
496
|
-
export const dagFrontendWriterAdmissionShellSchema = z
|
|
497
|
-
.object({
|
|
498
|
-
schemaVersion: z.literal(1),
|
|
499
|
-
/** Design verdict source (frontend-design-review-pi); pass is enforced.
|
|
500
|
-
* Omitted in small topology, which has no design review node. */
|
|
501
|
-
designReviewFromNodeId: dagFrontendNodeIdSchema.optional(),
|
|
502
|
-
/** Frozen command labels the verification bundle will execute. */
|
|
503
|
-
frozenCommandLabels: z.array(z.string()).default([]),
|
|
504
|
-
allowedMockStrategies: z
|
|
505
|
-
.array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"]))
|
|
506
|
-
.min(1),
|
|
507
|
-
/** Writer-preceding lint commands; baseline is materialized here (R5). */
|
|
508
|
-
lintCommands: z.array(z.string().min(1)).optional(),
|
|
509
|
-
lintEvidence: dagShellVerifyEvidenceSchema.optional(),
|
|
510
|
-
})
|
|
511
|
-
.superRefine((admission, context) => {
|
|
512
|
-
if ((admission.lintCommands?.length ?? 0) > 0 && !admission.lintEvidence) {
|
|
513
|
-
context.addIssue({
|
|
514
|
-
code: z.ZodIssueCode.custom,
|
|
515
|
-
path: ["lintEvidence"],
|
|
516
|
-
message: "lintEvidence is required when lintCommands are present",
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
/** Deterministic frontend closeout shell (M8). Renders the closeout from
|
|
521
|
-
* committed facts only (review context + typed review terminal + trace). */
|
|
522
|
-
export const dagFrontendCloseoutSchema = z.object({
|
|
523
|
-
schemaVersion: z.literal(1),
|
|
524
|
-
reviewFromNodeId: dagFrontendNodeIdSchema,
|
|
525
|
-
});
|
|
526
351
|
export const ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
527
352
|
export const dagVersionSchema = z
|
|
528
353
|
.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)])
|
|
@@ -570,14 +395,7 @@ export const dagWriteGuardPolicySchema = z.enum(["full", "tools-only", "filesyst
|
|
|
570
395
|
*/
|
|
571
396
|
export const dagWriterOutcomePolicySchema = z
|
|
572
397
|
.object({
|
|
573
|
-
|
|
574
|
-
* Protocol face: `implementation-outcome-v1` keeps the legacy
|
|
575
|
-
* IMPLEMENTATION_OUTCOME first-line protocol (backend/README/module
|
|
576
|
-
* writers + frontend-repair-pi); `frontend-facts-v1` derives the status
|
|
577
|
-
* from mechanical facts (write-tool events / run delta / write guard /
|
|
578
|
-
* requirement coverage / focused-check) and never reads the first line.
|
|
579
|
-
*/
|
|
580
|
-
type: z.enum(["implementation-outcome-v1", "frontend-facts-v1"]),
|
|
398
|
+
type: z.literal("implementation-outcome-v1"),
|
|
581
399
|
/** Generation writers may forbid already-satisfied/no-diff completion. */
|
|
582
400
|
requireChangedFiles: z.boolean().optional(),
|
|
583
401
|
})
|
|
@@ -710,13 +528,10 @@ export const dagShellConfigSchema = z.object({
|
|
|
710
528
|
.optional(),
|
|
711
529
|
requirementCoverageGate: dagRequirementCoverageGateSchema.optional(),
|
|
712
530
|
jsonArtifactGate: dagJsonArtifactGateSchema.optional(),
|
|
713
|
-
frontendDesignPolicy: dagFrontendDesignPolicySchema.optional(),
|
|
714
|
-
frontendWriterAdmission: dagFrontendWriterAdmissionShellSchema.optional(),
|
|
715
531
|
frontendPrewriteGate: dagFrontendPrewriteGateSchema.optional(),
|
|
532
|
+
frontendLintBaseline: dagFrontendLintBaselineSchema.optional(),
|
|
716
533
|
frontendVerificationBundle: dagFrontendVerificationBundleSchema.optional(),
|
|
717
534
|
frontendReviewContext: dagFrontendReviewContextSchema.optional(),
|
|
718
|
-
frontendContractImport: dagFrontendContractImportSchema.optional(),
|
|
719
|
-
frontendCloseout: dagFrontendCloseoutSchema.optional(),
|
|
720
535
|
frontendTestCaseChecklist: dagFrontendTestCaseChecklistSchema.optional(),
|
|
721
536
|
frontendBrowserToolPreflight: dagFrontendBrowserToolPreflightSchema.optional(),
|
|
722
537
|
frontendTestStandardScenarios: dagFrontendTestStandardScenariosSchema.optional(),
|
|
@@ -922,7 +737,58 @@ export const structuredContractOutputSchemaIds = [
|
|
|
922
737
|
"frontend-implementation-contract-plan-patch-v1",
|
|
923
738
|
"frontend-implementation-contract-revision-patch-v1",
|
|
924
739
|
];
|
|
925
|
-
export const
|
|
740
|
+
export const dagArtifactIdentitySchema = z
|
|
741
|
+
.string()
|
|
742
|
+
.regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/, "artifact id must be stable lower-case dot/kebab syntax");
|
|
743
|
+
const dagArtifactRelativePathSchema = z
|
|
744
|
+
.string()
|
|
745
|
+
.min(1)
|
|
746
|
+
.refine((value) => !value.includes("\0"), "artifact path must not contain NUL")
|
|
747
|
+
.refine((value) => !value.includes("\\"), "artifact path must use POSIX separators")
|
|
748
|
+
.refine((value) => !value.startsWith("/") && !/^[A-Za-z]:/.test(value), "artifact path must be run-relative")
|
|
749
|
+
.refine((value) => value.split("/").every((segment) => segment !== "" && segment !== ".."), "artifact path must not escape the run");
|
|
750
|
+
export const dagProducedArtifactSchema = z
|
|
751
|
+
.object({
|
|
752
|
+
artifactId: dagArtifactIdentitySchema,
|
|
753
|
+
kind: z.enum(["structured", "assistant", "stdout"]),
|
|
754
|
+
path: dagArtifactRelativePathSchema,
|
|
755
|
+
mediaType: z.string().min(1),
|
|
756
|
+
schemaId: z.string().min(1).optional(),
|
|
757
|
+
revisionPolicy: z.enum(["immutable", "replace-file"]),
|
|
758
|
+
})
|
|
759
|
+
.strict()
|
|
760
|
+
.superRefine((value, ctx) => {
|
|
761
|
+
if (value.kind === "structured" && !value.schemaId) {
|
|
762
|
+
ctx.addIssue({
|
|
763
|
+
code: z.ZodIssueCode.custom,
|
|
764
|
+
path: ["schemaId"],
|
|
765
|
+
message: "structured artifact requires schemaId",
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
if (value.kind !== "structured" && value.schemaId) {
|
|
769
|
+
ctx.addIssue({
|
|
770
|
+
code: z.ZodIssueCode.custom,
|
|
771
|
+
path: ["schemaId"],
|
|
772
|
+
message: "only structured artifacts may declare schemaId",
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
if (value.revisionPolicy === "replace-file" &&
|
|
776
|
+
value.kind !== "structured") {
|
|
777
|
+
ctx.addIssue({
|
|
778
|
+
code: z.ZodIssueCode.custom,
|
|
779
|
+
path: ["revisionPolicy"],
|
|
780
|
+
message: "MVP revisions are limited to structured artifacts",
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
export const dagConsumedArtifactSchema = z
|
|
785
|
+
.object({
|
|
786
|
+
artifactId: dagArtifactIdentitySchema,
|
|
787
|
+
required: z.boolean().default(true),
|
|
788
|
+
})
|
|
789
|
+
.strict();
|
|
790
|
+
export const dagTaskSchema = z.object({
|
|
791
|
+
id: z.string().regex(/^[a-z][a-z0-9-]*$/, "task id must be kebab-case"),
|
|
926
792
|
depends_on: z.array(z.string()).default([]),
|
|
927
793
|
/**
|
|
928
794
|
* How SKIPPED upstreams affect readiness.
|
|
@@ -955,19 +821,6 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
955
821
|
role: dagRoleSchema.optional(),
|
|
956
822
|
skills: z.array(z.string()).optional(),
|
|
957
823
|
toolProfile: dagToolProfileSchema.optional(),
|
|
958
|
-
/** Bounded read-only discovery budget for nodes that inspect a repository. */
|
|
959
|
-
readBudget: z
|
|
960
|
-
.object({
|
|
961
|
-
maxFiles: z.number().int().positive(),
|
|
962
|
-
maxBytes: z.number().int().positive(),
|
|
963
|
-
maxMs: z.number().int().positive().optional(),
|
|
964
|
-
/** Maximum read/grep/find/ls calls. */
|
|
965
|
-
maxOperations: z.number().int().positive().optional(),
|
|
966
|
-
/** On any read budget exhaustion, return concise completion guidance instead of failing the node. */
|
|
967
|
-
onExhaustion: z.enum(["return-guidance"]).optional(),
|
|
968
|
-
})
|
|
969
|
-
.strict()
|
|
970
|
-
.optional(),
|
|
971
824
|
/**
|
|
972
825
|
* Explicit Pi extension allowlist (backend implementation DAGs only):
|
|
973
826
|
* frozen short ids resolved at run time against the Pi settings package
|
|
@@ -998,6 +851,15 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
998
851
|
shell: dagShellConfigSchema.optional(),
|
|
999
852
|
static: dagStaticConfigSchema.optional(),
|
|
1000
853
|
outputContract: z.string().optional(),
|
|
854
|
+
/**
|
|
855
|
+
* Frozen producer declarations for run-owned artifacts. These declarations,
|
|
856
|
+
* together with consumesArtifacts, are the only authority for artifact
|
|
857
|
+
* lineage and impact analysis. Prompt/outputContract/path heuristics are
|
|
858
|
+
* intentionally forbidden.
|
|
859
|
+
*/
|
|
860
|
+
producesArtifacts: z.array(dagProducedArtifactSchema).optional(),
|
|
861
|
+
/** Frozen logical artifact inputs consumed by this node. */
|
|
862
|
+
consumesArtifacts: z.array(dagConsumedArtifactSchema).optional(),
|
|
1001
863
|
outputMode: dagOutputModeSchema.optional(),
|
|
1002
864
|
firstProtocolLine: z.string().min(1).optional(),
|
|
1003
865
|
/**
|
|
@@ -1026,8 +888,7 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
1026
888
|
})
|
|
1027
889
|
.strict()
|
|
1028
890
|
.superRefine((value, ctx) => {
|
|
1029
|
-
if (value.schemaId ===
|
|
1030
|
-
"frontend-implementation-contract-plan-patch-v1" &&
|
|
891
|
+
if (value.schemaId === "frontend-implementation-contract-plan-patch-v1" &&
|
|
1031
892
|
!value.skeleton) {
|
|
1032
893
|
ctx.addIssue({
|
|
1033
894
|
code: "custom",
|
|
@@ -1082,6 +943,121 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
1082
943
|
dynamicCondition: dagDynamicConditionSchema.optional(),
|
|
1083
944
|
dynamicLoopUntil: dagDynamicLoopUntilSchema.optional(),
|
|
1084
945
|
});
|
|
946
|
+
function hasTransitiveDependency(tasksById, consumerNodeId, producerNodeId) {
|
|
947
|
+
const queue = [...(tasksById.get(consumerNodeId)?.depends_on ?? [])];
|
|
948
|
+
const seen = new Set();
|
|
949
|
+
while (queue.length > 0) {
|
|
950
|
+
const nodeId = queue.shift();
|
|
951
|
+
if (nodeId === producerNodeId)
|
|
952
|
+
return true;
|
|
953
|
+
if (seen.has(nodeId))
|
|
954
|
+
continue;
|
|
955
|
+
seen.add(nodeId);
|
|
956
|
+
queue.push(...(tasksById.get(nodeId)?.depends_on ?? []));
|
|
957
|
+
}
|
|
958
|
+
return false;
|
|
959
|
+
}
|
|
960
|
+
function validateFrozenArtifactBindings(tasks, ctx) {
|
|
961
|
+
const tasksById = new Map(tasks.map((task) => [task.id, task]));
|
|
962
|
+
const producers = new Map();
|
|
963
|
+
const paths = new Map();
|
|
964
|
+
for (const [taskIndex, task] of tasks.entries()) {
|
|
965
|
+
const localIds = new Set();
|
|
966
|
+
for (const [artifactIndex, artifact] of (task.producesArtifacts ?? []).entries()) {
|
|
967
|
+
if (localIds.has(artifact.artifactId) ||
|
|
968
|
+
producers.has(artifact.artifactId)) {
|
|
969
|
+
ctx.addIssue({
|
|
970
|
+
code: z.ZodIssueCode.custom,
|
|
971
|
+
path: [
|
|
972
|
+
"tasks",
|
|
973
|
+
taskIndex,
|
|
974
|
+
"producesArtifacts",
|
|
975
|
+
artifactIndex,
|
|
976
|
+
"artifactId",
|
|
977
|
+
],
|
|
978
|
+
message: `artifact ${artifact.artifactId} must have exactly one producer`,
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
producers.set(artifact.artifactId, {
|
|
983
|
+
nodeId: task.id,
|
|
984
|
+
taskIndex,
|
|
985
|
+
artifactIndex,
|
|
986
|
+
path: artifact.path,
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
localIds.add(artifact.artifactId);
|
|
990
|
+
const foldedPath = artifact.path
|
|
991
|
+
.normalize("NFC")
|
|
992
|
+
.toLocaleLowerCase("en-US");
|
|
993
|
+
const existingArtifactId = paths.get(foldedPath);
|
|
994
|
+
if (existingArtifactId && existingArtifactId !== artifact.artifactId) {
|
|
995
|
+
ctx.addIssue({
|
|
996
|
+
code: z.ZodIssueCode.custom,
|
|
997
|
+
path: [
|
|
998
|
+
"tasks",
|
|
999
|
+
taskIndex,
|
|
1000
|
+
"producesArtifacts",
|
|
1001
|
+
artifactIndex,
|
|
1002
|
+
"path",
|
|
1003
|
+
],
|
|
1004
|
+
message: `artifact path collides with ${existingArtifactId} under case folding`,
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
else {
|
|
1008
|
+
paths.set(foldedPath, artifact.artifactId);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
for (const [taskIndex, task] of tasks.entries()) {
|
|
1013
|
+
const consumed = new Set();
|
|
1014
|
+
for (const [artifactIndex, binding] of (task.consumesArtifacts ?? []).entries()) {
|
|
1015
|
+
if (consumed.has(binding.artifactId)) {
|
|
1016
|
+
ctx.addIssue({
|
|
1017
|
+
code: z.ZodIssueCode.custom,
|
|
1018
|
+
path: [
|
|
1019
|
+
"tasks",
|
|
1020
|
+
taskIndex,
|
|
1021
|
+
"consumesArtifacts",
|
|
1022
|
+
artifactIndex,
|
|
1023
|
+
"artifactId",
|
|
1024
|
+
],
|
|
1025
|
+
message: `artifact ${binding.artifactId} is consumed more than once by ${task.id}`,
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
consumed.add(binding.artifactId);
|
|
1029
|
+
const producer = producers.get(binding.artifactId);
|
|
1030
|
+
if (!producer) {
|
|
1031
|
+
ctx.addIssue({
|
|
1032
|
+
code: z.ZodIssueCode.custom,
|
|
1033
|
+
path: [
|
|
1034
|
+
"tasks",
|
|
1035
|
+
taskIndex,
|
|
1036
|
+
"consumesArtifacts",
|
|
1037
|
+
artifactIndex,
|
|
1038
|
+
"artifactId",
|
|
1039
|
+
],
|
|
1040
|
+
message: `artifact ${binding.artifactId} has no declared producer`,
|
|
1041
|
+
});
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
if (producer.nodeId === task.id ||
|
|
1045
|
+
!hasTransitiveDependency(tasksById, task.id, producer.nodeId)) {
|
|
1046
|
+
ctx.addIssue({
|
|
1047
|
+
code: z.ZodIssueCode.custom,
|
|
1048
|
+
path: [
|
|
1049
|
+
"tasks",
|
|
1050
|
+
taskIndex,
|
|
1051
|
+
"consumesArtifacts",
|
|
1052
|
+
artifactIndex,
|
|
1053
|
+
"artifactId",
|
|
1054
|
+
],
|
|
1055
|
+
message: `consumer ${task.id} must be downstream of producer ${producer.nodeId}`,
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1085
1061
|
export const dagModelsSchema = z
|
|
1086
1062
|
.object({
|
|
1087
1063
|
HIGH: z.string().optional(),
|
|
@@ -1111,9 +1087,7 @@ export const dagBudgetSchema = campaignBudgetSchema;
|
|
|
1111
1087
|
export const dagSourceBindingSourceSchema = z.object({
|
|
1112
1088
|
kind: z.enum(["requirement", "constraint", "reference"]),
|
|
1113
1089
|
path: z.string().min(1),
|
|
1114
|
-
sha256: z
|
|
1115
|
-
.string()
|
|
1116
|
-
.regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex"),
|
|
1090
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex"),
|
|
1117
1091
|
});
|
|
1118
1092
|
/**
|
|
1119
1093
|
* DagSourceBinding v1:无 ledger 字段(schemaVersion=1,.strict() 拒绝 ledger
|
|
@@ -1215,22 +1189,6 @@ export const dagSpecSchema = z
|
|
|
1215
1189
|
taskContractBinding: dagTaskContractBindingSchema.optional(),
|
|
1216
1190
|
/** Optional unresolved parent-run feedback for a full task rerun. */
|
|
1217
1191
|
rerunFeedback: dagRerunFeedbackSchema.optional(),
|
|
1218
|
-
/** Frontend recovery continuation quota (frozen at generation time from
|
|
1219
|
-
* task.json frontendRecovery.maxContinuations). Bounds how many times a
|
|
1220
|
-
* failed frontend run may auto-recover via M6 recovery operations before
|
|
1221
|
-
* the run stays failed and needs human intervention. */
|
|
1222
|
-
frontendRecovery: z
|
|
1223
|
-
.object({
|
|
1224
|
-
maxContinuations: z
|
|
1225
|
-
.number()
|
|
1226
|
-
.int()
|
|
1227
|
-
.min(1)
|
|
1228
|
-
.max(5)
|
|
1229
|
-
.optional()
|
|
1230
|
-
.default(1),
|
|
1231
|
-
})
|
|
1232
|
-
.strict()
|
|
1233
|
-
.optional(),
|
|
1234
1192
|
/** Backend-test-only workspace mutation control; absent means Git. */
|
|
1235
1193
|
backendTestWorkspaceControl: z.enum(["git", "filesystem-only"]).optional(),
|
|
1236
1194
|
/** Frozen backend-test artifact layout (plan A); absent = historical default testcase/ layout. */
|
|
@@ -1280,6 +1238,7 @@ export const dagSpecSchema = z
|
|
|
1280
1238
|
})
|
|
1281
1239
|
.superRefine((spec, ctx) => {
|
|
1282
1240
|
const supportsV3Fields = spec.version === 3 || spec.version === 4;
|
|
1241
|
+
validateFrozenArtifactBindings(spec.tasks, ctx);
|
|
1283
1242
|
if (spec.evaluation && !supportsV3Fields) {
|
|
1284
1243
|
ctx.addIssue({
|
|
1285
1244
|
code: z.ZodIssueCode.custom,
|
|
@@ -1356,9 +1315,6 @@ export const FRONTEND_RECOVERY_RESULT_SCHEMA_VERSION = 1;
|
|
|
1356
1315
|
* Phase 3a parents converge first, so `rollback-pending` is not produced and
|
|
1357
1316
|
* was removed by AC-1; the phase starts at `child-staging` and ends at
|
|
1358
1317
|
* `settled`.
|
|
1359
|
-
*
|
|
1360
|
-
* @deprecated Read-only compatibility only; the M6 operation controller no
|
|
1361
|
-
* longer uses this phase as the authoritative recovery entry point.
|
|
1362
1318
|
*/
|
|
1363
1319
|
export const frontendRecoveryPhaseSchema = z.enum([
|
|
1364
1320
|
"child-staging",
|
|
@@ -1378,9 +1334,6 @@ export const frontendRecoveryPhaseSchema = z.enum([
|
|
|
1378
1334
|
* runner's `(existing?.revision ?? 0) + 1` CAS write (the schema only bounds it
|
|
1379
1335
|
* non-negative). `childRunId` may be absent through `child-activating` and must
|
|
1380
1336
|
* be non-empty from `child-running` onward.
|
|
1381
|
-
*
|
|
1382
|
-
* @deprecated Read-only compatibility only; the runner no longer writes this
|
|
1383
|
-
* intent (the M6 operation controller supervises recovery instead).
|
|
1384
1337
|
*/
|
|
1385
1338
|
export const frontendRecoveryStateSchema = z
|
|
1386
1339
|
.object({
|
|
@@ -1452,10 +1405,6 @@ export const frontendRecoveryEvidenceRefSchema = z
|
|
|
1452
1405
|
* stays permissive (failureClass optional, evidenceRefs may be empty) so it
|
|
1453
1406
|
* accepts the runner's actual phase-3a products, which do not always carry a
|
|
1454
1407
|
* failure class or evidence reference.
|
|
1455
|
-
*
|
|
1456
|
-
* @deprecated Read-only compatibility only; the M6 operation controller writes
|
|
1457
|
-
* `recovered`/`auto-recovery-blocked` results directly and never uses this
|
|
1458
|
-
* schema as the authoritative recovery settlement.
|
|
1459
1408
|
*/
|
|
1460
1409
|
export const frontendRecoveryResultSchema = z
|
|
1461
1410
|
.object({
|
|
@@ -3,7 +3,7 @@ import { resolveShellCommands } from "../../executors/shell-executor.js";
|
|
|
3
3
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
4
4
|
import { resolveRepairTaskForGate } from "./repair-artifact.js";
|
|
5
5
|
import { topoSortToRanks } from "./topo.js";
|
|
6
|
-
import { isSafeReadOnlyPiRetryCandidate, isWriterEmptyDiffRetryCandidate, isWriterTransportRetryCandidate, INCOMPLETE_WRITE_SET_RETRY_CATEGORY, WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY, WRITER_EMPTY_DIFF_RETRY_CATEGORY,
|
|
6
|
+
import { isSafeReadOnlyPiRetryCandidate, isWriterEmptyDiffRetryCandidate, isWriterTransportRetryCandidate, INCOMPLETE_WRITE_SET_RETRY_CATEGORY, WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY, WRITER_EMPTY_DIFF_RETRY_CATEGORY, } from "./retry-policy.js";
|
|
7
7
|
import { isBackendTestCompletenessRetryCandidate } from "./backend-test-writer-completeness.js";
|
|
8
8
|
import { defaultFrontendTestLayout, frontendTestLayoutFromSpec, } from "./frontend-test-layout.js";
|
|
9
9
|
const GOVERNANCE_WARNING_TYPES = new Set([
|
|
@@ -464,9 +464,7 @@ function validateShellTaskConfig(task, spec, issues) {
|
|
|
464
464
|
if (commands.length === 0 &&
|
|
465
465
|
!shell.jsonArtifactGate &&
|
|
466
466
|
!shell.backendTestPipeline &&
|
|
467
|
-
!shell.
|
|
468
|
-
!shell.frontendWriterAdmission &&
|
|
469
|
-
!shell.frontendCloseout &&
|
|
467
|
+
!shell.frontendPrewriteGate &&
|
|
470
468
|
!shell.frontendBrowserToolPreflight &&
|
|
471
469
|
!shell.frontendTestStandardScenarios &&
|
|
472
470
|
!shell.frontendTestEnvironmentProbe &&
|
|
@@ -539,26 +537,18 @@ function validateShellTaskConfig(task, spec, issues) {
|
|
|
539
537
|
}
|
|
540
538
|
}
|
|
541
539
|
}
|
|
542
|
-
if (shell.
|
|
543
|
-
const sourceNodeIds = [
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
if (shell.frontendWriterAdmission) {
|
|
554
|
-
const sourceNodeIds = shell.frontendWriterAdmission.designReviewFromNodeId
|
|
555
|
-
? [shell.frontendWriterAdmission.designReviewFromNodeId]
|
|
556
|
-
: [];
|
|
540
|
+
if (shell.frontendPrewriteGate) {
|
|
541
|
+
const sourceNodeIds = [
|
|
542
|
+
shell.frontendPrewriteGate.planFromNodeId,
|
|
543
|
+
...shell.frontendPrewriteGate.planFallbackFromNodeIds,
|
|
544
|
+
shell.frontendPrewriteGate.reviewFromNodeId,
|
|
545
|
+
...shell.frontendPrewriteGate.reviewFallbackFromNodeIds,
|
|
546
|
+
];
|
|
557
547
|
for (const sourceNodeId of new Set(sourceNodeIds)) {
|
|
558
548
|
if (!task.depends_on.includes(sourceNodeId)) {
|
|
559
549
|
issues.push({
|
|
560
550
|
type: "missing-dependency",
|
|
561
|
-
message: `shell task ${task.id}
|
|
551
|
+
message: `shell task ${task.id} frontendPrewriteGate source ${sourceNodeId} must be a direct dependency`,
|
|
562
552
|
});
|
|
563
553
|
}
|
|
564
554
|
}
|
|
@@ -656,18 +646,12 @@ function validateRetryPolicyTaskConfig(task, issues) {
|
|
|
656
646
|
}
|
|
657
647
|
if (isWriterTransportCandidate) {
|
|
658
648
|
const categories = new Set(task.retryPolicy.retryCategories);
|
|
659
|
-
const allowedWriterTransportCategories = new Set([
|
|
660
|
-
WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY,
|
|
661
|
-
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
662
|
-
]);
|
|
663
|
-
const allAllowed = [...categories].every((category) => allowedWriterTransportCategories.has(category));
|
|
664
649
|
if (task.retryPolicy.maxAttempts !== 2 ||
|
|
665
|
-
categories.size
|
|
666
|
-
!allAllowed ||
|
|
650
|
+
categories.size !== 1 ||
|
|
667
651
|
!categories.has(WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY)) {
|
|
668
652
|
issues.push({
|
|
669
653
|
type: "invalid-retry-policy",
|
|
670
|
-
message: `task ${task.id} writer transport retryPolicy must use exactly two total attempts and only
|
|
654
|
+
message: `task ${task.id} writer transport retryPolicy must use exactly two total attempts and only ${WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY}`,
|
|
671
655
|
});
|
|
672
656
|
}
|
|
673
657
|
}
|