@tea-agent/loop-agent 0.44.0-next.1 → 0.44.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/CHANGELOG.md +379 -416
- package/dist/application/evaluation/budget.js +21 -0
- package/dist/application/evaluation/corpus-hash.js +10 -15
- package/dist/application/evaluation/corpus.js +2 -1
- package/dist/application/evaluation/frontend-browser-acceptance.js +77 -0
- package/dist/application/evaluation/frontend-corpus-browser-acceptance.js +175 -0
- package/dist/application/evaluation/frontend-gateway-evidence.js +226 -0
- package/dist/application/evaluation/frontend-pair-registration.js +143 -0
- package/dist/application/evaluation/frontend-paired-summary.js +150 -0
- package/dist/application/evaluation/frontend-run-observation.js +144 -0
- package/dist/application/evaluation/frontend-shared-evidence.js +105 -0
- package/dist/application/evaluation/types.js +45 -12
- package/dist/application/task-lifecycle/observe.js +26 -1
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +11 -0
- package/dist/cli/program.js +4 -0
- package/dist/commands/task-advance.js +3 -5
- package/dist/commands/task-source-prepare.js +13 -1
- package/dist/executors/dag-pi/guards.js +4 -0
- package/dist/executors/dag-pi/model-config.js +30 -0
- package/dist/executors/dag-pi/plan/fact-adoption.js +55 -0
- package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +22 -28
- package/dist/executors/dag-pi/plan/finalize-tools.js +259 -0
- package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
- package/dist/executors/dag-pi/plan/record-tools.js +861 -0
- package/dist/executors/dag-pi/plan/schema.js +129 -0
- package/dist/executors/dag-pi/plan/session.js +1 -0
- package/dist/executors/dag-pi/plan/tool-helpers.js +16 -0
- package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
- package/dist/executors/dag-pi/tools/design-terminal-tools.js +159 -0
- package/dist/executors/dag-pi/tools/plan-decision-tools.js +529 -0
- package/dist/executors/dag-pi/tools/review-terminal-tools.js +159 -0
- package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
- package/dist/executors/dag-pi-executor.js +398 -3384
- package/dist/executors/pi-executor.js +6 -1
- package/dist/executors/pi-sdk-executor.js +112 -19
- package/dist/executors/shell-executor.js +88 -12
- package/dist/executors/shell-presets.js +1 -1
- package/dist/executors/shell-write-guard.js +26 -3
- package/dist/infrastructure/console/operation-store.js +48 -14
- package/dist/infrastructure/evaluation/corpus-store.js +37 -12
- package/dist/shared/file-identity.js +23 -0
- package/dist/shared/git-workspace-status.js +482 -0
- package/dist/shared/operator/capabilities.js +10 -5
- package/dist/shared/path-safety.js +2 -2
- package/dist/shared/wizard-local-telemetry.js +51 -0
- package/dist/task/config-types.js +22 -8
- package/dist/task/contract/project.js +13 -0
- package/dist/task/contract/schema.js +2 -7
- package/dist/task/frontend-preflight.js +1 -1
- package/dist/task/source-prepare/parse-intent.js +124 -5
- package/dist/task/source-prepare/prepare.js +6 -1
- package/dist/task/source-prepare/semantic-intake.js +18 -3
- package/dist/task/source-prepare/source-execution.js +65 -0
- package/dist/task/source-prepare/source-fidelity-pi.js +22 -9
- package/dist/task/source-prepare/source-provider-budget.js +290 -0
- package/dist/worker/console/chat/assistant-content.js +5 -34
- package/dist/worker/console/chat/chat-event-store.js +62 -10
- package/dist/worker/console/chat/context-insights.js +723 -0
- package/dist/worker/console/chat/conversation-nodes.js +383 -0
- package/dist/worker/console/chat/db-connections.js +854 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +1 -1
- package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +655 -0
- package/dist/worker/console/chat/pi-runtime.js +445 -36
- package/dist/worker/console/chat/provider-error.js +0 -12
- package/dist/worker/console/chat/repo-browser.js +52 -4
- package/dist/worker/console/chat/routes.js +577 -72
- package/dist/worker/console/chat/sdd-data-alignment.js +8 -31
- package/dist/worker/console/chat/session-store.js +147 -19
- package/dist/worker/console/chat/shortcuts.js +7 -0
- package/dist/worker/console/chat/timeline-message-order.js +22 -0
- package/dist/worker/console/chat/tools.js +34 -0
- package/dist/worker/console/chat/turn-process.js +237 -66
- package/dist/worker/console/chat/user-turn-outline.js +19 -0
- package/dist/worker/console/console-update-runtime.js +2 -2
- package/dist/worker/console/dag-confirmation.js +3 -0
- package/dist/worker/console/dag-execution-receipt.js +3 -0
- package/dist/worker/console/operator-actions.js +32 -3
- package/dist/worker/console/operator-user-error.js +28 -1
- package/dist/worker/console/pi-readiness.js +4 -4
- package/dist/worker/console/prd-intake-bridge.js +5 -12
- package/dist/worker/console/recovery-cta.js +14 -14
- package/dist/worker/console/server.js +5 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-8-j6y-sd.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
- package/dist/worker/console/static/assets/{arc-eoQiMvuk.js → arc-dT5T4sVL.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C4A3uMcI.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D4zD2F-Q.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-j1RkJziL.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
- package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-YBHmhik1.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-COfWyo9P.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-I99OUkHY.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-XKxoJNJ4.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DLT_cYx1.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CxcKZ9mV.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-V1EqXdjY.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DebTtdFp.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-B-ivNRDf.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DC_Ds11b.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-sWEqKwIb.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BXa_dcu4.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-C-Mle84F.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CXPDBITe.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CC-WJQfa.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CDAV5Vs4.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CmFiAcNz.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DPBZHuyn.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-jUlm_Ds3.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DWhQ3mfY.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Tr2gMqet.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DJjVQHPA.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-D74dQ4u0.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
- package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
- package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-ILCbxJyb.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DeuWBQ89.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CF5ih8Fk.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C7yOSuRO.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
- package/dist/worker/console/static/assets/{linear-BDZ9riWi.js → linear-DGRlieMH.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-7pKqYtpZ.js → mermaid.core-4P9yPC9c.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-LeJDybSU.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BJvT3pMD.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-_rGqpMan.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DPcSv5aA.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Drxx4hkJ.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BCTUdU4z.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B6wzbZmB.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BGt8d3QQ.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-7nlhJKo7.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Cv2stqMA.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-qDAo4Yc1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKbDNKTr.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DI-9EHic.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BrzzRDpX.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BclH5hGh.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -1
- package/dist/worker/console/static-src/operator-chat/animation-frame-batcher.js +38 -0
- package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +186 -5
- package/dist/worker/console/static-src/operator-chat/chat-stream-continuity.js +101 -0
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +18 -3
- package/dist/worker/console/static-src/operator-chat/context-insights-store.js +64 -0
- package/dist/worker/console/static-src/operator-chat/details-rail-surfaces.js +98 -0
- package/dist/worker/console/static-src/operator-chat/file-palette-nav.js +81 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +17 -3
- package/dist/worker/console/static-src/operator-chat/process-label.js +27 -5
- package/dist/worker/console/static-src/operator-chat/tools-catalog.js +16 -7
- package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +4 -1
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
- package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +211 -40
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +124 -27
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +88 -20
- package/dist/worker/console/static-src/operator-chat/useComposer.js +80 -6
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +13 -3
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +36 -17
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +18 -0
- package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
- package/dist/worker/console/static-src/shell/console-update-reload.js +1 -1
- package/dist/worker/console/workspace-context.js +2 -0
- package/dist/worker/console/workspace-initialization.js +3 -3
- package/dist/worker/observability/read-model.js +23 -2
- package/dist/worker/observe/node-context-insights.js +479 -0
- package/dist/worker/observe/static/console-theme.css +174 -0
- package/dist/worker/observe/static/console-theme.js +36 -0
- package/dist/worker/observe/static/operator-chrome.css +85 -0
- package/dist/worker/observe/static/operator-chrome.js +51 -0
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
- package/dist/worker/scheduler/scheduled-goal-evidence.js +66 -3
- package/dist/worker/scheduler/scheduled-goal-store.js +10 -0
- package/dist/workflows/dag/budget-enforcement.js +31 -2
- package/dist/workflows/dag/frontend-closeout.js +3 -1
- package/dist/workflows/dag/frontend-contract-facts.js +11 -8
- package/dist/workflows/dag/frontend-design-policy.js +6 -6
- package/dist/workflows/dag/frontend-durable-tools.js +90 -70
- package/dist/workflows/dag/frontend-implementation-contract.js +146 -57
- package/dist/workflows/dag/frontend-plan-canary.js +66 -16
- package/dist/workflows/dag/frontend-plan-decision-contract.js +13 -21
- package/dist/workflows/dag/frontend-plan-progress.js +92 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +10 -5
- package/dist/workflows/dag/frontend-recovery-run.js +51 -46
- package/dist/workflows/dag/frontend-repair-assertions.js +36 -0
- package/dist/workflows/dag/frontend-review-context.js +29 -1
- package/dist/workflows/dag/frontend-review-scopes.js +92 -2
- package/dist/workflows/dag/frontend-risk.js +8 -3
- package/dist/workflows/dag/frontend-root-observation.js +261 -0
- package/dist/workflows/dag/frontend-session-budget.js +52 -39
- package/dist/workflows/dag/frontend-session-context.js +10 -0
- package/dist/workflows/dag/frontend-test-execution-evidence.js +206 -48
- package/dist/workflows/dag/frontend-typed-event-store.js +11 -1
- package/dist/workflows/dag/frontend-verification-trace.js +6 -0
- package/dist/workflows/dag/frontend-writer-admission.js +3 -1
- package/dist/workflows/dag/init-hybrid.js +108 -37
- package/dist/workflows/dag/node-execution.js +11 -11
- package/dist/workflows/dag/output-protocol.js +1 -0
- package/dist/workflows/dag/rerun-feedback.js +35 -4
- package/dist/workflows/dag/rerun-task.js +62 -66
- package/dist/workflows/dag/runner.js +58 -12
- package/dist/workflows/dag/types.js +15 -8
- package/dist/workflows/loop/benchmark.js +11 -8
- package/docs/README.md +1 -1
- package/docs/architecture/runtime-boundaries.md +1 -1
- package/docs/governance/harness-methodology-verification.md +11 -0
- package/docs/templates/backend-test-dag.json +5 -4
- package/docs/templates/frontend-implementation-contract.schema.json +31 -11
- package/package.json +6 -4
- package/skills/frontend-design-review/SKILL.md +8 -11
- package/skills/frontend-design-review/references/review-checklist.md +3 -4
- package/skills/frontend-review/SKILL.md +5 -1
- package/skills/loop-agent/references/command-reference.md +8 -0
- package/skills/loop-agent/references/hybrid-dag.md +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +0 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +0 -1
- package/dist/worker/console/static/assets/index-Cdkvw_H6.js +0 -469
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +0 -8
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sha256OfCanonicalJson } from "../../task/contract/hash.js";
|
|
1
2
|
import { access, mkdir, readFile } from "node:fs/promises";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import path from "node:path";
|
|
@@ -28,7 +29,7 @@ export function parseDagRerunTaskArgs(args) {
|
|
|
28
29
|
for (let index = 0; index < args.length; index += 1) {
|
|
29
30
|
const arg = args[index];
|
|
30
31
|
if (arg === undefined)
|
|
31
|
-
|
|
32
|
+
throw new Error("dag rerun-task argument is missing");
|
|
32
33
|
if (arg === "--run-id")
|
|
33
34
|
parentRunId = args[++index];
|
|
34
35
|
else if (arg.startsWith("--run-id="))
|
|
@@ -103,6 +104,9 @@ async function readFrontendRecoveryDescriptor(runDir, parentRunId, requestId) {
|
|
|
103
104
|
plan.schemaVersion !== 1 ||
|
|
104
105
|
plan.parentRunId !== parentRunId ||
|
|
105
106
|
plan.requestId !== requestId ||
|
|
107
|
+
plan.failureSource !== raw.failureSource ||
|
|
108
|
+
plan.failureOwner !== raw.failureOwner ||
|
|
109
|
+
plan.resetRootNodeId !== raw.resetRootNodeId ||
|
|
106
110
|
!Array.isArray(plan.resetNodeIds) ||
|
|
107
111
|
!Array.isArray(plan.importedNodeIds)) {
|
|
108
112
|
throw new Error("frontend recovery descriptor is invalid or unbound");
|
|
@@ -126,6 +130,8 @@ function buildFrontendRecoveryIntent(input) {
|
|
|
126
130
|
attemptIndex: input.parentRecovery?.attemptIndex ?? 0,
|
|
127
131
|
continuationCount: input.parentRecovery?.continuationCount ?? 0,
|
|
128
132
|
failureSource: input.failureSource,
|
|
133
|
+
...(input.failureOwner ? { failureOwner: input.failureOwner } : {}),
|
|
134
|
+
...(input.resetRootNodeId ? { resetRootNodeId: input.resetRootNodeId } : {}),
|
|
129
135
|
revision: 0,
|
|
130
136
|
};
|
|
131
137
|
}
|
|
@@ -391,6 +397,8 @@ async function executeFrontendRecoveryContinuation(input) {
|
|
|
391
397
|
parentRunId: input.parentRunId,
|
|
392
398
|
requestId: input.requestId,
|
|
393
399
|
failureSource: descriptor.failureSource,
|
|
400
|
+
failureOwner: descriptor.failureOwner,
|
|
401
|
+
resetRootNodeId: descriptor.resetRootNodeId,
|
|
394
402
|
parentRecovery: parentState.frontendRecoveryState,
|
|
395
403
|
}),
|
|
396
404
|
recoveryPlan: descriptor.plan,
|
|
@@ -404,75 +412,63 @@ async function executeFrontendRecoveryContinuation(input) {
|
|
|
404
412
|
// these through its own durable tools (normal commit entry, child binding)
|
|
405
413
|
// and the model only corrects the rows the design review flagged; the
|
|
406
414
|
// parent ledger is never rewritten and the finalize terminal is not
|
|
407
|
-
// inherited.
|
|
408
|
-
|
|
415
|
+
// inherited. Only an absent parent ledger permits a fresh Plan.
|
|
416
|
+
if (descriptor.plan.resetRootNodeId === "frontend-plan-pi") {
|
|
409
417
|
const parentPlanLedger = path.join(located.runDir, "frontend-plan-pi", "plan-decision-facts.jsonl");
|
|
410
|
-
const parentRaw = await readFile(parentPlanLedger, "utf8")
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
bucket.push(entry);
|
|
426
|
-
byKind.set(kind, bucket);
|
|
427
|
-
}
|
|
428
|
-
let parentCanonicalSha256;
|
|
429
|
-
try {
|
|
430
|
-
const parentCanonical = await readFile(path.join(located.runDir, "contracts", "frontend-implementation-contract.json"), "utf8");
|
|
431
|
-
parentCanonicalSha256 = createHash("sha256").update(parentCanonical).digest("hex");
|
|
432
|
-
}
|
|
433
|
-
catch {
|
|
434
|
-
// Parent canonical unavailable → the identical-plan guard is skipped.
|
|
435
|
-
}
|
|
436
|
-
// Carry the design findings that blocked the parent run: the child's
|
|
437
|
-
// finalize runs a per-finding closure check against them.
|
|
438
|
-
let designFindings = [];
|
|
439
|
-
try {
|
|
440
|
-
const designFacts = await readTypedEventStoreFromJsonl(path.join(located.runDir, "frontend-design-review-pi", "design-typed-facts.jsonl"));
|
|
441
|
-
for (const record of designFacts) {
|
|
442
|
-
const fact = record.fact;
|
|
443
|
-
if (record.phase !== "committed" || fact.kind !== "design-finding")
|
|
418
|
+
const parentRaw = await readFile(parentPlanLedger, "utf8").catch((error) => {
|
|
419
|
+
if (error.code === "ENOENT")
|
|
420
|
+
return undefined;
|
|
421
|
+
throw error;
|
|
422
|
+
});
|
|
423
|
+
if (parentRaw !== undefined) {
|
|
424
|
+
const parentRecords = await readTypedEventStoreFromJsonl(parentPlanLedger);
|
|
425
|
+
// Collapse superseded records first: the parent ledger is append-only
|
|
426
|
+
// (replace:true appends a corrected row), and replaying both the original
|
|
427
|
+
// and its correction would trip FACT_IDENTITY_CONFLICT in the child.
|
|
428
|
+
const { collapseDecisionEntriesByKind } = await import("./frontend-plan-decision-contract.js");
|
|
429
|
+
const byKind = new Map();
|
|
430
|
+
for (const record of parentRecords) {
|
|
431
|
+
const kind = String(record.fact.kind);
|
|
432
|
+
if (record.phase !== "committed" || kind === "finalize_decision")
|
|
444
433
|
continue;
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
434
|
+
const entry = record.fact.entry;
|
|
435
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
436
|
+
continue;
|
|
437
|
+
const bucket = byKind.get(kind) ?? [];
|
|
438
|
+
bucket.push(entry);
|
|
439
|
+
byKind.set(kind, bucket);
|
|
451
440
|
}
|
|
441
|
+
let parentCanonicalSha256;
|
|
442
|
+
try {
|
|
443
|
+
const parentCanonical = await readFile(path.join(located.runDir, "contracts", "frontend-implementation-contract.json"), "utf8");
|
|
444
|
+
parentCanonicalSha256 = createHash("sha256").update(parentCanonical).digest("hex");
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
// Parent canonical unavailable → the identical-plan guard is skipped.
|
|
448
|
+
}
|
|
449
|
+
const { readCurrentFrontendRepairFindings } = await import("./rerun-feedback.js");
|
|
450
|
+
const feedback = await readCurrentFrontendRepairFindings(located.runDir);
|
|
451
|
+
const designFindings = feedback?.verdict === "request" ? feedback.findings : [];
|
|
452
|
+
const parentSpec = await readDagRunSpec(located.runDir);
|
|
453
|
+
const snapshot = {
|
|
454
|
+
schemaVersion: 1,
|
|
455
|
+
schemaId: "frontend-plan-parent-decision-snapshot-v1",
|
|
456
|
+
parentRunId: input.parentRunId,
|
|
457
|
+
parentLedgerSha256: createHash("sha256").update(parentRaw).digest("hex"),
|
|
458
|
+
sourceBindingSha256: sha256OfCanonicalJson(parentSpec.sourceBinding ?? null),
|
|
459
|
+
...(feedback ? { feedbackBinding: { sourceNodeId: feedback.sourceNodeId, ledgerSha256: feedback.ledgerSha256, terminalEventId: feedback.terminalEventId } } : {}),
|
|
460
|
+
...(parentCanonicalSha256 ? { parentCanonicalSha256 } : {}),
|
|
461
|
+
designFindings,
|
|
462
|
+
facts: [...byKind.entries()].flatMap(([kind, entries]) => collapseDecisionEntriesByKind(kind, entries).map((entry) => ({
|
|
463
|
+
kind,
|
|
464
|
+
entry,
|
|
465
|
+
}))),
|
|
466
|
+
};
|
|
467
|
+
await mkdir(path.join(locatedChild.runDir, "frontend-plan-pi"), {
|
|
468
|
+
recursive: true,
|
|
469
|
+
});
|
|
470
|
+
await writeJsonAtomic(path.join(locatedChild.runDir, "frontend-plan-pi", "parent-decision-snapshot.json"), snapshot);
|
|
452
471
|
}
|
|
453
|
-
catch {
|
|
454
|
-
// No readable design findings → the closure check has no assertions.
|
|
455
|
-
}
|
|
456
|
-
const snapshot = {
|
|
457
|
-
schemaVersion: 1,
|
|
458
|
-
schemaId: "frontend-plan-parent-decision-snapshot-v1",
|
|
459
|
-
parentRunId: input.parentRunId,
|
|
460
|
-
parentLedgerSha256: createHash("sha256").update(parentRaw).digest("hex"),
|
|
461
|
-
...(parentCanonicalSha256 ? { parentCanonicalSha256 } : {}),
|
|
462
|
-
designFindings,
|
|
463
|
-
facts: [...byKind.entries()].flatMap(([kind, entries]) => collapseDecisionEntriesByKind(kind, entries).map((entry) => ({
|
|
464
|
-
kind,
|
|
465
|
-
entry,
|
|
466
|
-
}))),
|
|
467
|
-
};
|
|
468
|
-
await mkdir(path.join(locatedChild.runDir, "frontend-plan-pi"), {
|
|
469
|
-
recursive: true,
|
|
470
|
-
});
|
|
471
|
-
await writeJsonAtomic(path.join(locatedChild.runDir, "frontend-plan-pi", "parent-decision-snapshot.json"), snapshot);
|
|
472
|
-
}
|
|
473
|
-
catch {
|
|
474
|
-
// No parent plan ledger (or unreadable) → the child plans fresh,
|
|
475
|
-
// exactly like a run without recovery lineage.
|
|
476
472
|
}
|
|
477
473
|
const childSpec = await readDagRunSpec(locatedChild.runDir);
|
|
478
474
|
const childState = await readDagRunState(locatedChild.runDir);
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { assertFrontendPairExecution } from "../../application/evaluation/frontend-pair-registration.js";
|
|
2
|
+
import { sourceBudgetContractIdentity } from "../../application/evaluation/budget.js";
|
|
3
|
+
import { summarizeFrozenSourceUsage } from "../../task/source-prepare/source-provider-budget.js";
|
|
4
|
+
import { sha256OfCanonicalJson } from "../../task/contract/hash.js";
|
|
1
5
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
6
|
import { createHash } from "node:crypto";
|
|
3
7
|
import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
|
|
@@ -244,6 +248,17 @@ export function createInitialRunState(spec, opts, ranks, runId = opts.runId ?? "
|
|
|
244
248
|
: {}),
|
|
245
249
|
};
|
|
246
250
|
initRunBudgetLedger(state, spec.budget);
|
|
251
|
+
if (spec.sourceProviderBudget) {
|
|
252
|
+
if (sha256OfCanonicalJson(spec.sourceProviderBudget.contract ?? null) !== sha256OfCanonicalJson(sourceBudgetContractIdentity(spec.taskContractBinding) ?? null) || !state.budgetLedger || spec.sourceProviderBudget.ledger.taskId !== spec.sourceBinding?.taskId || spec.sourceProviderBudget.ledger.maxProviderRequests !== state.budgetLedger.limits.maxProviderRequests || spec.sourceProviderBudget.sourceBindingSha256 !== sha256OfCanonicalJson(spec.sourceBinding))
|
|
253
|
+
throw Error("FRONTEND_PROVIDER_BUDGET_INVALID: source snapshot does not match DAG");
|
|
254
|
+
state.sourceProviderBudget = structuredClone(spec.sourceProviderBudget);
|
|
255
|
+
state.budgetLedger.consumed.providerRequests = spec.sourceProviderBudget.ledger.reservedRequests;
|
|
256
|
+
const sourceUsage = summarizeFrozenSourceUsage(spec.sourceProviderBudget);
|
|
257
|
+
if (sourceUsage.complete)
|
|
258
|
+
state.budgetLedger.consumed.tokens = sourceUsage.totalTokens;
|
|
259
|
+
else if (spec.sourceProviderBudget.ledger.reservedRequests > 0)
|
|
260
|
+
state.budgetLedger.consumed.missingTokenNodeIds.push(`task-budget:${spec.sourceProviderBudget.ledger.budgetId}`);
|
|
261
|
+
}
|
|
247
262
|
return state;
|
|
248
263
|
}
|
|
249
264
|
export function assertFrozenEvaluationBinding(spec, state) {
|
|
@@ -280,6 +295,12 @@ export async function runDag(spec, opts) {
|
|
|
280
295
|
if (!runningIdentity) {
|
|
281
296
|
throw new Error("running controller identity could not be resolved; refuse to create an unpinned DAG run");
|
|
282
297
|
}
|
|
298
|
+
if (spec.evaluation?.frontendPair)
|
|
299
|
+
await assertFrontendPairExecution({
|
|
300
|
+
repoRoot: opts.cwd, binding: spec.evaluation,
|
|
301
|
+
controllerFingerprint: runningIdentity.packageFingerprint.value,
|
|
302
|
+
startedAt: new Date().toISOString(),
|
|
303
|
+
});
|
|
283
304
|
assertRuntimeContractCompatible(spec, {
|
|
284
305
|
...DAG_CONTROLLER_CAPABILITIES,
|
|
285
306
|
controllerVersion: runningIdentity.packageVersion,
|
|
@@ -453,6 +474,12 @@ export async function resumeDagRun(opts) {
|
|
|
453
474
|
if (!runningIdentity) {
|
|
454
475
|
throw new Error("running controller identity could not be resolved; refuse to resume an unpinned DAG run");
|
|
455
476
|
}
|
|
477
|
+
if (spec.evaluation?.frontendPair)
|
|
478
|
+
await assertFrontendPairExecution({
|
|
479
|
+
repoRoot: opts.cwd, binding: spec.evaluation,
|
|
480
|
+
controllerFingerprint: runningIdentity.packageFingerprint.value,
|
|
481
|
+
startedAt: state.startedAt,
|
|
482
|
+
});
|
|
456
483
|
assertRuntimeContractCompatible(spec, {
|
|
457
484
|
...DAG_CONTROLLER_CAPABILITIES,
|
|
458
485
|
controllerVersion: runningIdentity.packageVersion,
|
|
@@ -602,8 +629,12 @@ async function executeDagCheckpoint(input) {
|
|
|
602
629
|
};
|
|
603
630
|
const onSigTerm = () => shutdownOnSignal("SIGTERM");
|
|
604
631
|
const onSigInt = () => shutdownOnSignal("SIGINT");
|
|
605
|
-
|
|
606
|
-
|
|
632
|
+
// Keep listeners installed until persistence completes. Pi dependencies use
|
|
633
|
+
// signal-exit, which recounts listeners during signal dispatch and re-sends
|
|
634
|
+
// the signal if a once-listener has already removed itself. terminalSignal
|
|
635
|
+
// above makes repeated signals idempotent; normal cleanup removes listeners.
|
|
636
|
+
process.on("SIGTERM", onSigTerm);
|
|
637
|
+
process.on("SIGINT", onSigInt);
|
|
607
638
|
// Exit-time diagnostics (silent-death forensics): write an `armed` line at
|
|
608
639
|
// checkpoint start and append process-exit / uncaught-exception /
|
|
609
640
|
// unhandled-rejection lines with a live state snapshot so an abnormal death
|
|
@@ -862,7 +893,12 @@ async function executeDagCheckpoint(input) {
|
|
|
862
893
|
trigger: recoveryTrigger,
|
|
863
894
|
deps: input.recovery,
|
|
864
895
|
});
|
|
865
|
-
if (created.kind === "
|
|
896
|
+
if (created.kind === "blocked") {
|
|
897
|
+
state.status = "failed";
|
|
898
|
+
state.terminalReason = created.reason;
|
|
899
|
+
state.frontendRecoveryResult = buildRecoveryResultForTrigger(state, recoveryTrigger, "auto-recovery-blocked");
|
|
900
|
+
}
|
|
901
|
+
else if (created.kind === "conflict") {
|
|
866
902
|
// Same clientRequestId with a different payload → fail closed; never
|
|
867
903
|
// create a second recovery operation (AC-004).
|
|
868
904
|
state.status = "failed";
|
|
@@ -1276,7 +1312,7 @@ export async function finalizeTerminalRunStatus(state, taskCount, runDir, cwd, f
|
|
|
1276
1312
|
// The rejected design is a plan input defect. Reset from the
|
|
1277
1313
|
// planner so the next child can incorporate the committed
|
|
1278
1314
|
// findings before design review runs again.
|
|
1279
|
-
failureSource: "frontend-
|
|
1315
|
+
failureSource: "frontend-design-review-pi",
|
|
1280
1316
|
failureOwner: classifyReviewIssueCategoryFailureOwner(designRequestFact.issueCategory),
|
|
1281
1317
|
protocolFailureReason: `frontend design review request_design_changes (issueCategory=${designRequestFact.issueCategory})`,
|
|
1282
1318
|
recoveryMode: "new-dag",
|
|
@@ -1477,6 +1513,20 @@ export async function finalizeTerminalRunStatus(state, taskCount, runDir, cwd, f
|
|
|
1477
1513
|
*/
|
|
1478
1514
|
async function createRecoveryOperation(input) {
|
|
1479
1515
|
const { cwd, runDir, spec, state, trigger } = input;
|
|
1516
|
+
const { computeFrontendRecoveryPlanForSource } = await import("./frontend-recovery-plan.js");
|
|
1517
|
+
let plan;
|
|
1518
|
+
try {
|
|
1519
|
+
plan = computeFrontendRecoveryPlanForSource({
|
|
1520
|
+
spec,
|
|
1521
|
+
parentRunId: state.runId,
|
|
1522
|
+
requestId: trigger.requestId,
|
|
1523
|
+
failureSource: trigger.failureSource,
|
|
1524
|
+
failureOwner: trigger.failureOwner,
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
catch (error) {
|
|
1528
|
+
return { kind: "blocked", reason: error instanceof Error ? error.message : String(error) };
|
|
1529
|
+
}
|
|
1480
1530
|
const recoveryLease = await acquireDagRecoveryLease({
|
|
1481
1531
|
cwd,
|
|
1482
1532
|
parentRunId: state.runId,
|
|
@@ -1502,13 +1552,6 @@ async function createRecoveryOperation(input) {
|
|
|
1502
1552
|
observeOnly = true;
|
|
1503
1553
|
}
|
|
1504
1554
|
}
|
|
1505
|
-
const { computeFrontendRecoveryPlanForSource } = await import("./frontend-recovery-plan.js");
|
|
1506
|
-
const plan = computeFrontendRecoveryPlanForSource({
|
|
1507
|
-
spec,
|
|
1508
|
-
parentRunId: state.runId,
|
|
1509
|
-
requestId: trigger.requestId,
|
|
1510
|
-
failureSource: trigger.failureSource,
|
|
1511
|
-
});
|
|
1512
1555
|
const planHash = createHash("sha256")
|
|
1513
1556
|
.update(JSON.stringify(plan))
|
|
1514
1557
|
.digest("hex");
|
|
@@ -1518,6 +1561,8 @@ async function createRecoveryOperation(input) {
|
|
|
1518
1561
|
parentRunId: state.runId,
|
|
1519
1562
|
requestId: trigger.requestId,
|
|
1520
1563
|
failureSource: trigger.failureSource,
|
|
1564
|
+
failureOwner: plan.failureOwner,
|
|
1565
|
+
resetRootNodeId: plan.resetRootNodeId,
|
|
1521
1566
|
recoveryMode: trigger.recoveryMode,
|
|
1522
1567
|
planHash,
|
|
1523
1568
|
plan,
|
|
@@ -1529,7 +1574,8 @@ async function createRecoveryOperation(input) {
|
|
|
1529
1574
|
parentRunId: state.runId,
|
|
1530
1575
|
requestId: trigger.requestId,
|
|
1531
1576
|
failureSource: trigger.failureSource,
|
|
1532
|
-
failureOwner:
|
|
1577
|
+
failureOwner: plan.failureOwner,
|
|
1578
|
+
resetRootNodeId: plan.resetRootNodeId,
|
|
1533
1579
|
protocolFailureReason: trigger.protocolFailureReason,
|
|
1534
1580
|
recoveryMode: trigger.recoveryMode,
|
|
1535
1581
|
planHash,
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { frontendPairExecutionBindingSchema } from "../../application/evaluation/frontend-pair-registration.js";
|
|
2
|
+
import { sourceBudgetContractIdentity } from "../../application/evaluation/budget.js";
|
|
3
|
+
import { sha256OfCanonicalJson } from "../../task/contract/hash.js";
|
|
4
|
+
import { frontendTestObservationSchema } from "./frontend-test-execution-evidence.js";
|
|
5
|
+
import { capabilityBoundarySchema } from "../../task/config-types.js";
|
|
1
6
|
import { z } from "zod";
|
|
2
7
|
import { frontendExecutionPolicySchema } from "../../shared/frontend-execution-policy.js";
|
|
3
8
|
import { DEFAULT_FRONTEND_SPEC_ROOTS, isFrontendSpecFilePath, isValidFrontendSpecRoot, OPENSPEC_SPEC_EXT_RE, } from "../../shared/openspec-spec.js";
|
|
4
|
-
import { campaignBudgetSchema, } from "../../application/evaluation/budget.js";
|
|
9
|
+
import { campaignBudgetSchema, sourceProviderBudgetBindingSchema, } from "../../application/evaluation/budget.js";
|
|
5
10
|
import { assertDagPromptSourceRule } from "./prompt-source.js";
|
|
6
11
|
// Leaf-module import: dagRetryPolicySchema must be defined by a module that
|
|
7
12
|
// never transitively reaches types.ts during init (retry-policy does, via
|
|
@@ -89,6 +94,7 @@ export const dagShellVerifyEvidenceSchema = z.object({
|
|
|
89
94
|
.array(z.object({
|
|
90
95
|
label: z.string(),
|
|
91
96
|
status: z.enum(["ok", "future-delivery-script", "future-test-target"]),
|
|
97
|
+
testObservation: frontendTestObservationSchema.optional(),
|
|
92
98
|
}))
|
|
93
99
|
.default([]),
|
|
94
100
|
/** Effective timeout applied independently to each shell command. */
|
|
@@ -463,13 +469,7 @@ export const dagFrontendDesignPolicySchema = z
|
|
|
463
469
|
.optional(),
|
|
464
470
|
/** Generation-frozen test capability boundary composed into the
|
|
465
471
|
* canonical dependencyPolicy by the runtime. */
|
|
466
|
-
capabilityBoundary:
|
|
467
|
-
.object({
|
|
468
|
-
allowed: z.array(z.string().min(1)).optional(),
|
|
469
|
-
forbidden: z.array(z.string().min(1)).optional(),
|
|
470
|
-
})
|
|
471
|
-
.strict()
|
|
472
|
-
.optional(),
|
|
472
|
+
capabilityBoundary: capabilityBoundarySchema.optional(),
|
|
473
473
|
/** Generation-frozen interaction id vocabulary (plan finalize check). */
|
|
474
474
|
interactionIds: z.array(z.string().min(1)).optional(),
|
|
475
475
|
/** Generation-frozen roots that bound custom normative directories. */
|
|
@@ -1320,6 +1320,7 @@ export const dagEvaluationBindingSchema = z
|
|
|
1320
1320
|
seed: z.number().int().nonnegative(),
|
|
1321
1321
|
split: z.enum(["public", "private", "held_out"]).optional(),
|
|
1322
1322
|
taskRef: z.string().min(1).optional(),
|
|
1323
|
+
frontendPair: frontendPairExecutionBindingSchema.optional(),
|
|
1323
1324
|
})
|
|
1324
1325
|
.strict();
|
|
1325
1326
|
/** Eval Lab Campaign Budget (W3.4); enforced by runner ledger when mode=hard. */
|
|
@@ -1424,6 +1425,7 @@ export const dagSpecSchema = z
|
|
|
1424
1425
|
evaluation: dagEvaluationBindingSchema.optional(),
|
|
1425
1426
|
/** Optional hard/record-only budget; requires version 3 or 4. */
|
|
1426
1427
|
budget: dagBudgetSchema.optional(),
|
|
1428
|
+
sourceProviderBudget: sourceProviderBudgetBindingSchema.optional(),
|
|
1427
1429
|
frontendExecutionPolicy: frontendExecutionPolicySchema.optional(),
|
|
1428
1430
|
sourceBinding: dagSourceBindingSchema.optional(),
|
|
1429
1431
|
/** v4 managed Task Contract binding; only valid on version 4. */
|
|
@@ -1494,6 +1496,9 @@ export const dagSpecSchema = z
|
|
|
1494
1496
|
tasks: z.array(dagTaskSchema).min(1),
|
|
1495
1497
|
})
|
|
1496
1498
|
.superRefine((spec, ctx) => {
|
|
1499
|
+
if (spec.sourceProviderBudget && (!spec.sourceBinding || spec.sourceProviderBudget.ledger.taskId !== spec.sourceBinding.taskId || sha256OfCanonicalJson(spec.sourceProviderBudget.contract ?? null) !== sha256OfCanonicalJson(sourceBudgetContractIdentity(spec.taskContractBinding) ?? null) || spec.budget?.mode !== "hard" || spec.sourceProviderBudget.ledger.maxProviderRequests !== spec.budget?.limits.maxProviderRequests || spec.sourceProviderBudget.sourceBindingSha256 !== sha256OfCanonicalJson(spec.sourceBinding))) {
|
|
1500
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["sourceProviderBudget"], message: "source request budget must match the frozen source and request limit" });
|
|
1501
|
+
}
|
|
1497
1502
|
const supportsV3Fields = spec.version === 3 || spec.version === 4;
|
|
1498
1503
|
validateFrozenArtifactBindings(spec.tasks, ctx);
|
|
1499
1504
|
if (spec.evaluation && !supportsV3Fields) {
|
|
@@ -1618,6 +1623,8 @@ export const frontendRecoveryStateSchema = z
|
|
|
1618
1623
|
* frontend-plan-revision-pi / frontend-prewrite-gate-shell /
|
|
1619
1624
|
* frontend-implement-pi (writer partial write). */
|
|
1620
1625
|
failureSource: z.string().min(1).optional(),
|
|
1626
|
+
failureOwner: z.enum(["contract", "scout", "plan", "implementation", "verification-config", "environment", "scope", "unknown"]).optional(),
|
|
1627
|
+
resetRootNodeId: z.string().min(1).optional(),
|
|
1621
1628
|
revision: z.number().int().nonnegative(),
|
|
1622
1629
|
})
|
|
1623
1630
|
.strict()
|
|
@@ -40,7 +40,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
40
40
|
regressionPause: false,
|
|
41
41
|
changedPaths: 2,
|
|
42
42
|
repairPasses: 1,
|
|
43
|
-
}, ["./test/dag-runner.test.ts"], "Single repair exhausts before the third successful hard verification."),
|
|
43
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Single repair exhausts before the third successful hard verification."),
|
|
44
44
|
result("3-pass-convergence", {
|
|
45
45
|
pass: true,
|
|
46
46
|
fullVerifyPass: true,
|
|
@@ -51,7 +51,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
51
51
|
regressionPause: false,
|
|
52
52
|
changedPaths: 2,
|
|
53
53
|
repairPasses: 3,
|
|
54
|
-
}, ["./test/dag-runner.test.ts"], "Convergence re-enters supervisor, repair, and hard verify until pass 3."),
|
|
54
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Convergence re-enters supervisor, repair, and hard verify until pass 3."),
|
|
55
55
|
result("3-pass-convergence+quota", {
|
|
56
56
|
pass: true,
|
|
57
57
|
fullVerifyPass: true,
|
|
@@ -64,6 +64,9 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
64
64
|
repairPasses: 3,
|
|
65
65
|
}, [
|
|
66
66
|
"./test/dag-runner.test.ts",
|
|
67
|
+
"./test/dag-runner-convergence.test.ts",
|
|
68
|
+
"./test/dag-runner-artifacts.test.ts",
|
|
69
|
+
"./test/dag-runner-decisions.test.ts",
|
|
67
70
|
"./test/verify-step.test.ts",
|
|
68
71
|
], "Intermediate verification uses quota while final hard gate remains full."),
|
|
69
72
|
]),
|
|
@@ -78,7 +81,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
78
81
|
regressionPause: false,
|
|
79
82
|
changedPaths: 3,
|
|
80
83
|
repairPasses: 1,
|
|
81
|
-
}, ["./test/dag-runner.test.ts"], "Single repair ends failed without enough evidence to classify regression."),
|
|
84
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Single repair ends failed without enough evidence to classify regression."),
|
|
82
85
|
result("3-pass-convergence", {
|
|
83
86
|
pass: false,
|
|
84
87
|
fullVerifyPass: false,
|
|
@@ -89,7 +92,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
89
92
|
regressionPause: true,
|
|
90
93
|
changedPaths: 3,
|
|
91
94
|
repairPasses: 2,
|
|
92
|
-
}, ["./test/dag-runner.test.ts"], "Convergence pauses instead of retrying blindly after regression signal."),
|
|
95
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Convergence pauses instead of retrying blindly after regression signal."),
|
|
93
96
|
result("3-pass-convergence+quota", {
|
|
94
97
|
pass: false,
|
|
95
98
|
fullVerifyPass: false,
|
|
@@ -100,7 +103,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
100
103
|
regressionPause: true,
|
|
101
104
|
changedPaths: 3,
|
|
102
105
|
repairPasses: 2,
|
|
103
|
-
}, ["./test/dag-runner.test.ts"], "Quota reduces intermediate cost but still pauses on regression."),
|
|
106
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Quota reduces intermediate cost but still pauses on regression."),
|
|
104
107
|
]),
|
|
105
108
|
sample("LB-03", "write guard hard failure must not retry", "dag-runtime", [
|
|
106
109
|
result("single-repair", {
|
|
@@ -113,7 +116,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
113
116
|
regressionPause: false,
|
|
114
117
|
changedPaths: 1,
|
|
115
118
|
repairPasses: 1,
|
|
116
|
-
}, ["./test/dag-runner.test.ts"], "Write-guard failure remains terminal."),
|
|
119
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Write-guard failure remains terminal."),
|
|
117
120
|
result("3-pass-convergence", {
|
|
118
121
|
pass: false,
|
|
119
122
|
fullVerifyPass: false,
|
|
@@ -124,7 +127,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
124
127
|
regressionPause: false,
|
|
125
128
|
changedPaths: 1,
|
|
126
129
|
repairPasses: 1,
|
|
127
|
-
}, ["./test/dag-runner.test.ts"], "Non-retry class is not re-entered."),
|
|
130
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Non-retry class is not re-entered."),
|
|
128
131
|
result("3-pass-convergence+quota", {
|
|
129
132
|
pass: false,
|
|
130
133
|
fullVerifyPass: false,
|
|
@@ -135,7 +138,7 @@ export const LOOP_BENCHMARK_FIXTURE_SAMPLES = [
|
|
|
135
138
|
regressionPause: false,
|
|
136
139
|
changedPaths: 1,
|
|
137
140
|
repairPasses: 1,
|
|
138
|
-
}, ["./test/dag-runner.test.ts"], "Quota strategy does not change write-guard retry policy."),
|
|
141
|
+
}, ["./test/dag-runner.test.ts", "./test/dag-runner-convergence.test.ts", "./test/dag-runner-artifacts.test.ts", "./test/dag-runner-decisions.test.ts"], "Quota strategy does not change write-guard retry policy."),
|
|
139
142
|
]),
|
|
140
143
|
sample("LB-04", "quota final gate must stay full", "loop-runtime", [
|
|
141
144
|
result("single-repair", {
|
package/docs/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`docs/` 是 loop-agent 源仓的治理文档根目录。新读者不需要先浏览所有文件,先按任务选择入口,再由目录 README 或 `docs/document-catalog.json` 判断文档身份。
|
|
4
4
|
|
|
5
|
-
**维护日:2026-
|
|
5
|
+
**维护日:2026-09-16** — 对齐 `@tea-agent/loop-agent@0.41.1-beta.0`。版本事实以根 `CHANGELOG.md` 与 `package.json` 为准;能力短摘要见 `reports/current-capability-summary.md`。
|
|
6
6
|
|
|
7
7
|
## 我现在要做什么?
|
|
8
8
|
|
|
@@ -180,7 +180,7 @@ Runner / Loop ──(迁移中)──> 逐步改为仅经 Store / Appli
|
|
|
180
180
|
| Script | 检查内容 | 失败条件 |
|
|
181
181
|
| -------- | ---------- | ---------- |
|
|
182
182
|
| `scripts/check-architecture-boundaries.sh` | workflow/executor forbidden import,及 Worker → CLI/commands/application import | 新的未 allowlist violation |
|
|
183
|
-
| `scripts/check-command-registry-drift.sh` |
|
|
183
|
+
| `scripts/check-command-registry-drift.sh` | 五处真源的 top-level command 一致性:`src/cli/command-definitions.ts`(权威)、`src/shared/operator/capabilities.ts` 覆盖表、`skills/loop-agent/references/command-reference.md`、`website/docs/reference/cli.md`、`test/cli-contract.test.ts` 的 `LEGACY_SUPPORTED_COMMANDS`(逐项且同序) | 任一真源引用未注册 command、未覆盖已注册 command,或契约测试清单与 registry 不一致 |
|
|
184
184
|
| `scripts/check-exec-plan-index-sync.sh` | `ai_workspace/loop-agent/exec-plans/{active,completed}` 目录文件 vs 对应 `README.md` 索引 | 任一 plan 文件未在索引登记 |
|
|
185
185
|
| `scripts/check-skill-entry.sh` | `loop-agent` / `agent-worker` 的 frontmatter、required references、入口行数与 operator trigger vocabulary | 任一公共 skill 缺失、reference/trigger 漂移或入口超过 hard limit |
|
|
186
186
|
|
|
@@ -19,9 +19,20 @@
|
|
|
19
19
|
| 行为有覆盖 | `npm test` |
|
|
20
20
|
| 完整本地交付有效 | `bash scripts/ci.sh` |
|
|
21
21
|
|
|
22
|
+
## 代理与拦截层:校验状态码分布,不是请求条数
|
|
23
|
+
|
|
24
|
+
当验证经过中间层(网关 shim、mock server、反向代理、录制层)时,「请求到了中间层」不等于「中间层在起作用」:
|
|
25
|
+
|
|
26
|
+
- 只看条数会把 **404/5xx 也算成命中**。真实的失败模式是「流量根本没经过」或「经过了但立刻被拒」,两者都产出请求记录。
|
|
27
|
+
- 必须核对 **状态码分布**(如 `200×99` 而非 `200×1 + 404×42`),以及流量是否落在**目标时间窗口**内。
|
|
28
|
+
- 用一条已知成功的直接调用(curl)建立参照,并确认它的路径形态与被测链路的路径形态**一致**——baseUrl 拼接差异(如 `/v1` 重复)会造成静默 404,而外层 runner 可能仍产出看似完整的产物。
|
|
29
|
+
- 尤其警惕「未触发阈值」这类结论:它既可能是真的余量充足,也可能是**根本没走到阈值判断**。两者的证据形态完全不同,不能只凭「无拦截记录」下结论。
|
|
30
|
+
|
|
22
31
|
## Red Flags
|
|
23
32
|
|
|
24
33
|
- 凭意图声明完成
|
|
25
34
|
- 依赖陈旧命令输出
|
|
26
35
|
- 用窄检查支撑宽声明
|
|
27
36
|
- 跳过失败命令的细节
|
|
37
|
+
- 用计数(请求数/命中数)代替状态码与时间窗口证据
|
|
38
|
+
- 把「没有触发拦截」直接读成「余量充足」,未确认流量确实经过了拦截点
|