@tea-agent/loop-agent 0.43.0-next.18 → 0.43.0-next.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +60 -2308
- package/README.md +7 -0
- package/dist/application/task-lifecycle/advance.js +38 -7
- package/dist/build-stamp.json +3 -3
- package/dist/commands/init.js +13 -9
- package/dist/commands/task-advance.js +32 -0
- package/dist/executors/dag-pi-executor.js +1615 -188
- package/dist/executors/pi-executor.js +85 -3
- package/dist/executors/pi-sdk-executor.js +18 -0
- package/dist/executors/shell-executor.js +92 -7
- package/dist/shared/backend-dogfood-preflight.js +47 -0
- package/dist/shared/dag-failure-category.js +3 -0
- package/dist/shared/operator/capabilities.js +180 -0
- package/dist/task/config-types.js +29 -0
- package/dist/task/contract/project.js +9 -0
- package/dist/task/contract/schema.js +17 -0
- package/dist/task/source-prepare/build-draft.js +60 -0
- package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +24 -16
- package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
- package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
- package/dist/worker/console/chat/pi-runtime.js +86 -27
- package/dist/worker/console/chat/routes.js +19 -0
- package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
- package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
- package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
- package/dist/worker/console/chat/session-mode.js +7 -3
- package/dist/worker/console/chat/session-store.js +42 -9
- package/dist/worker/console/chat/tool-preview.js +115 -0
- package/dist/worker/console/chat/turn-order.js +13 -0
- package/dist/worker/console/chat/turn-process.js +32 -30
- package/dist/worker/console/operator-actions.js +50 -0
- package/dist/worker/console/prd-intake-bridge.js +54 -1
- package/dist/worker/console/scheduled-goal-host.js +98 -0
- package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
- package/dist/worker/console/server.js +15 -0
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-B_UDknhR.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
- package/dist/worker/console/static/assets/{arc-D6hU0drN.js → arc-eoQiMvuk.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DmVikdRK.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-DydABCRg.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DrXKC2Jl.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D2-qFxr7.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-ChfeF41P.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Drwrz55x.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CAQGErL7.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DHO38w5U.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-EYIN0EOI.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CrFLKqkT.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DMchffoo.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DaSvtKQa.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DcW8W9Qj.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BUirrMEi.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BXzO8iXR.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DAtgaxIn.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C1re9Noh.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-N8Kj08J9.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-D6BpSLs3.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-C2Vlgnl4.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-CMbqtVLS.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-A770Eb-0.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-LV2w_2pT.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-bwqf56ah.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BnVtHhZh.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BGVToEqc.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DL2l7Vne.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
- package/dist/worker/console/static/assets/{index-B_V4wvXs.js → index-Cdkvw_H6.js} +97 -97
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BWIpubOx.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DjYBD8vv.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-C0_mBaHb.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Cy71zbX6.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
- package/dist/worker/console/static/assets/{linear-Dt3_w3Vn.js → linear-BDZ9riWi.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DnNOlfEP.js → mermaid.core-7pKqYtpZ.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DAbTspwq.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-NNiM141p.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CN80Z1Do.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Bxyfh0JU.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BlWnC79M.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BrEu4P_e.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Bt70igBr.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-C8DQR-r9.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DEMinJAT.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-DDdDBzQc.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-G2wcBs3T.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Dzn4g2gJ.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-5v2rP9oO.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-B4EOx7ew.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CQ1v8eYP.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +3 -17
- package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +2 -5
- package/dist/worker/console/workspace-context.js +11 -0
- package/dist/worker/observe/static/operator-chrome.js +3 -1
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
- package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
- package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
- package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
- package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
- package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
- package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
- package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
- package/dist/workflows/dag/dag-retry-schema.js +11 -0
- package/dist/workflows/dag/frontend-closeout.js +4 -2
- package/dist/workflows/dag/frontend-committed-facts.js +461 -0
- package/dist/workflows/dag/frontend-durable-tools.js +15 -3
- package/dist/workflows/dag/frontend-implementation-contract.js +365 -8
- package/dist/workflows/dag/frontend-plan-canary.js +53 -0
- package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
- package/dist/workflows/dag/frontend-plan-render.js +0 -2
- package/dist/workflows/dag/frontend-prewrite-gate.js +3 -3
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
- package/dist/workflows/dag/frontend-recovery-run.js +57 -0
- package/dist/workflows/dag/frontend-review-context.js +43 -70
- package/dist/workflows/dag/frontend-risk.js +92 -10
- package/dist/workflows/dag/frontend-session-budget.js +117 -3
- package/dist/workflows/dag/frontend-shape.js +11 -55
- package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
- package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
- package/dist/workflows/dag/frontend-verification-trace.js +11 -2
- package/dist/workflows/dag/frontend-writer-admission.js +3 -47
- package/dist/workflows/dag/frontend-writer-status.js +0 -23
- package/dist/workflows/dag/init-hybrid.js +182 -185
- package/dist/workflows/dag/lifecycle.js +7 -2
- package/dist/workflows/dag/node-execution.js +48 -13
- package/dist/workflows/dag/rerun-plan.js +10 -0
- package/dist/workflows/dag/rerun-task.js +77 -1
- package/dist/workflows/dag/retry-policy.js +18 -0
- package/dist/workflows/dag/scheduler.js +2 -4
- package/dist/workflows/dag/types.js +23 -0
- package/docs/README.md +1 -0
- package/docs/init-surface.manifest.json +1 -0
- package/docs/operations/README.md +2 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +14 -10
- package/docs/templates/frontend-implementation-contract.schema.json +0 -7
- package/docs/templates/frontend-implementation-dag.json +8 -9
- package/package.json +6 -3
- package/skills/frontend-bounded-implement/SKILL.md +3 -4
- package/skills/frontend-design-review/SKILL.md +7 -12
- package/skills/frontend-design-review/references/review-checklist.md +7 -7
- package/skills/frontend-plan/SKILL.md +8 -18
- package/skills/frontend-plan/references/decision-contract.md +19 -26
- package/skills/frontend-review/SKILL.md +21 -25
- package/skills/frontend-review/references/review-findings.md +48 -24
- package/dist/worker/console/static/assets/channel-Drecd94a.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-8Udu0t8-.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-8Udu0t8-.js +0 -1
- package/dist/worker/console/static/assets/index-DcudonhZ.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CyCiS0Lt.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-U0lhi6N0.js +0 -8
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
|
@@ -712,6 +712,7 @@ export async function runDagStatus(repoRoot, rawArgs) {
|
|
|
712
712
|
export function parseDagDoctorArgs(args) {
|
|
713
713
|
let runId;
|
|
714
714
|
let markdown = false;
|
|
715
|
+
let json = false;
|
|
715
716
|
for (let i = 0; i < args.length; i += 1) {
|
|
716
717
|
const arg = args[i];
|
|
717
718
|
if (arg === undefined)
|
|
@@ -729,6 +730,10 @@ export function parseDagDoctorArgs(args) {
|
|
|
729
730
|
throw new Error("dag doctor --run-id requires a value");
|
|
730
731
|
continue;
|
|
731
732
|
}
|
|
733
|
+
if (arg === "--json") {
|
|
734
|
+
json = true;
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
732
737
|
if (arg === "--markdown") {
|
|
733
738
|
markdown = true;
|
|
734
739
|
continue;
|
|
@@ -738,7 +743,7 @@ export function parseDagDoctorArgs(args) {
|
|
|
738
743
|
}
|
|
739
744
|
throw new Error(`unexpected positional argument: ${arg}`);
|
|
740
745
|
}
|
|
741
|
-
return { runId, markdown };
|
|
746
|
+
return { runId, markdown, json };
|
|
742
747
|
}
|
|
743
748
|
function findDoctorFailureNode(state) {
|
|
744
749
|
if (state.pausedByNodeId) {
|
|
@@ -847,7 +852,7 @@ async function formatDagDoctorMarkdown(repoRoot, runId) {
|
|
|
847
852
|
export async function runDagDoctor(repoRoot, rawArgs) {
|
|
848
853
|
const parsed = parseDagDoctorArgs(rawArgs);
|
|
849
854
|
if (parsed.runId) {
|
|
850
|
-
if (parsed.markdown) {
|
|
855
|
+
if (parsed.markdown && !parsed.json) {
|
|
851
856
|
console.log(await formatDagDoctorMarkdown(repoRoot, parsed.runId));
|
|
852
857
|
return;
|
|
853
858
|
}
|
|
@@ -15,7 +15,7 @@ import { buildDagNodePromptEnvelope, formatConvergenceFeedbackBlock, } from "./p
|
|
|
15
15
|
import { persistLongNodeOutputArtifacts } from "./upstream-artifacts.js";
|
|
16
16
|
import { materializeDeclaredArtifactFacts } from "./artifact-bindings.js";
|
|
17
17
|
import { buildOutputLimitRecoverySection, loadBackendTestWriterProgressForRetry, } from "./backend-test-writer-completeness.js";
|
|
18
|
-
import { computeBackoffDelayMs, isCanonicalFinalVerifyShellRetryCandidate, isRetryablePiFailureCategory, isSafeReadOnlyPiRetryCandidate, isTargetTemplateTransientRetryNode, isWriterEmptyDiffRetryCandidate, isWriterTransportRetryCandidate, OUTPUT_LIMIT_RETRY_CATEGORY, projectFrontendNodeProtocolFailureReason, resolveFrontendPlanBackupRoute, resolveFrontendPlanRetryStep, VERIFY_SHELL_RETRY_POLICY, } from "./retry-policy.js";
|
|
18
|
+
import { computeBackoffDelayMs, isCanonicalFinalVerifyShellRetryCandidate, isProviderAvailabilityFailureCategory, isRetryablePiFailureCategory, isSafeReadOnlyPiRetryCandidate, isTargetTemplateTransientRetryNode, isWriterEmptyDiffRetryCandidate, isWriterTransportRetryCandidate, OUTPUT_LIMIT_RETRY_CATEGORY, projectFrontendNodeProtocolFailureReason, resolveFrontendPlanBackupRoute, resolveFrontendPlanRetryStep, VERIFY_SHELL_RETRY_POLICY, } from "./retry-policy.js";
|
|
19
19
|
import { applyNodeActivity, evaluateNodeLiveness, resolveLivenessPolicy, } from "./liveness-policy.js";
|
|
20
20
|
import { buildProtocolRetryInstruction, normalizeReviewVerdictAfterRetries, parseJsonReviewVerdict, validateOutputProtocol, } from "./output-protocol.js";
|
|
21
21
|
import { getStructuredContractValidator } from "./contract-output-registry.js";
|
|
@@ -568,7 +568,7 @@ export function renderFrontendPlanInputContext(input) {
|
|
|
568
568
|
"Do not read upstream artifacts, task sources, or repository files. If this input cannot support a decision, record a genuine evidence gap.",
|
|
569
569
|
"</frontend_plan_input>",
|
|
570
570
|
"<plan_review_checklist>",
|
|
571
|
-
"
|
|
571
|
+
"Satisfy these checks in the committed facts before the runtime compiles and finalizes the Plan:",
|
|
572
572
|
...checklistLines,
|
|
573
573
|
"</plan_review_checklist>",
|
|
574
574
|
].join("\n");
|
|
@@ -614,6 +614,10 @@ export async function buildFrontendPlanInputContext(runDir, componentSourceCitat
|
|
|
614
614
|
export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCategory, previousProtocolReason, recoveryTargetPaths, recoveryDiagnostics, frontendPlanRetryStep) {
|
|
615
615
|
if (attemptNumber <= 1)
|
|
616
616
|
return basePrompt;
|
|
617
|
+
// Match the executor segmented Plan identity; custom nodes retain their terminal.
|
|
618
|
+
const planCompletion = task.id === FRONTEND_PLAN_NODE_ID
|
|
619
|
+
? "Stop after committing the required facts. The runtime compiles and finalizes the committed ledger automatically; only repair facts reported by its validation."
|
|
620
|
+
: "Then call finalize_plan exactly once.";
|
|
617
621
|
// Context overflow is a transport/session failure, not a plan-protocol
|
|
618
622
|
// failure. It must take precedence over the plan retry ladder so every
|
|
619
623
|
// retry, including a repeated plan overflow, starts from the compact
|
|
@@ -656,8 +660,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
656
660
|
previousProtocolReason) {
|
|
657
661
|
// The frontend plan node's compile authority is the committed typed
|
|
658
662
|
// ledger, not a fenced JSON text artifact: its retry guidance must
|
|
659
|
-
// direct the model to re-commit corrected record_* facts and
|
|
660
|
-
//
|
|
663
|
+
// direct the model to re-commit corrected record_* facts and respect
|
|
664
|
+
// terminal ownership. The full-contract JSON guidance below applies
|
|
661
665
|
// only to nodes whose authority is still a text contract artifact.
|
|
662
666
|
if (task.structuredContractOutput.schemaId ===
|
|
663
667
|
"frontend-implementation-contract-plan-patch-v1") {
|
|
@@ -673,7 +677,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
673
677
|
"<retry_instruction>",
|
|
674
678
|
"Previous plan ledger facts failed canonical contract validation:",
|
|
675
679
|
previousProtocolReason,
|
|
676
|
-
"Fix the reported violations by re-committing corrected record_* facts
|
|
680
|
+
"Fix the reported violations by re-committing corrected record_* facts. The committed typed ledger is the only compile authority.",
|
|
681
|
+
planCompletion,
|
|
677
682
|
"Do not emit a fenced JSON contract, protected skeleton fields, or an openspec-citations block; narrative JSON is not validated and wastes the output budget.",
|
|
678
683
|
...frontendPlanValidationRetryGuidance(previousProtocolReason),
|
|
679
684
|
...splitGuidance,
|
|
@@ -711,7 +716,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
711
716
|
"",
|
|
712
717
|
"<retry_instruction>",
|
|
713
718
|
"Previous attempt was truncated by the provider (stopReason=length) before the plan facts were fully committed.",
|
|
714
|
-
"Re-commit the missing record_* facts
|
|
719
|
+
"Re-commit the missing record_* facts; the committed typed ledger is the only compile authority. Do NOT re-read contract/scout outputs or source files — use the facts already in context. Commit record_* facts one tool call per message.",
|
|
720
|
+
planCompletion,
|
|
715
721
|
"Do not emit a fenced JSON contract, protected skeleton fields, or an openspec-citations block; narrative JSON is not validated and wastes the output budget.",
|
|
716
722
|
"</retry_instruction>",
|
|
717
723
|
].join("\n");
|
|
@@ -732,7 +738,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
732
738
|
"",
|
|
733
739
|
"<retry_instruction>",
|
|
734
740
|
"Frontend plan retry ladder step: compact-terminal-first.",
|
|
735
|
-
"Do NOT rewrite the narrative. Only adopt already staged/quarantined fresh facts
|
|
741
|
+
"Do NOT rewrite the narrative. Only adopt already staged/quarantined fresh facts and fill the missing required facts.",
|
|
742
|
+
planCompletion,
|
|
736
743
|
"Keep the existing committed ledger intact; do not re-derive already committed facts.",
|
|
737
744
|
"</retry_instruction>",
|
|
738
745
|
].join("\n");
|
|
@@ -743,7 +750,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
743
750
|
"",
|
|
744
751
|
"<retry_instruction>",
|
|
745
752
|
"Frontend plan retry ladder step: bounded-tool-only.",
|
|
746
|
-
"Reduce reasoning and wall-clock time. Use only
|
|
753
|
+
"Reduce reasoning and wall-clock time. Use only the tools exposed for this session and only for the necessary missing facts.",
|
|
754
|
+
planCompletion,
|
|
747
755
|
"Do not expand scope or re-derive already committed facts.",
|
|
748
756
|
"</retry_instruction>",
|
|
749
757
|
].join("\n");
|
|
@@ -754,7 +762,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
754
762
|
"",
|
|
755
763
|
"<retry_instruction>",
|
|
756
764
|
"Frontend plan retry ladder step: backup-model.",
|
|
757
|
-
"A backup provider/model route was selected after repeated non-converging failures. Re-derive only the missing committed facts
|
|
765
|
+
"A backup provider/model route was selected after repeated non-converging failures. Re-derive only the missing committed facts; do not repeat the failed strategy.",
|
|
766
|
+
planCompletion,
|
|
758
767
|
"</retry_instruction>",
|
|
759
768
|
].join("\n");
|
|
760
769
|
}
|
|
@@ -793,7 +802,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
793
802
|
"",
|
|
794
803
|
"<retry_instruction>",
|
|
795
804
|
"Previous plan attempt issued too many read-only tool calls (read/grep/ls/find) and blew up the context window. Trust the upstream frontend-contract-pi typed requirement facts and frontend-scout-pi target surface already provided — do NOT re-read contract/scout stdout, PRD/source files, or component sources you already inspected.",
|
|
796
|
-
"Minimize discovery reads: only read what you genuinely need, once. Commit
|
|
805
|
+
"Minimize discovery reads: only read what you genuinely need, once. Commit the required record_* facts directly from the facts already in context (one tool call per message).",
|
|
806
|
+
planCompletion,
|
|
797
807
|
"</retry_instruction>",
|
|
798
808
|
].join("\n");
|
|
799
809
|
}
|
|
@@ -917,7 +927,8 @@ export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFail
|
|
|
917
927
|
"",
|
|
918
928
|
"<retry_instruction>",
|
|
919
929
|
"Previous attempt exceeded the structured output size limit.",
|
|
920
|
-
"Re-commit corrected record_* facts
|
|
930
|
+
"Re-commit corrected record_* facts; the committed typed ledger is the only compile authority.",
|
|
931
|
+
planCompletion,
|
|
921
932
|
"Do not emit a fenced JSON contract, protected skeleton fields, or an openspec-citations block; narrative JSON is not validated and wastes the output budget.",
|
|
922
933
|
"</retry_instruction>",
|
|
923
934
|
].join("\n");
|
|
@@ -1713,6 +1724,20 @@ export async function executeDagNode(input) {
|
|
|
1713
1724
|
? result.stderr.slice(markerIndex, markerIndex + 4_000).trim()
|
|
1714
1725
|
: `backend-test Markdown plan attempt failed with ${result.failureCategory}`;
|
|
1715
1726
|
}
|
|
1727
|
+
// Decision-path Plan bridge failures surface from the executor as
|
|
1728
|
+
// invalid-output (the derived relationship patch failed pre-validation),
|
|
1729
|
+
// NOT through the R1 structured self-check (which only runs when
|
|
1730
|
+
// result.ok). Capture the bridge diagnostics into previousProtocolReason
|
|
1731
|
+
// so the next attempt prompt tells the model exactly which decision facts
|
|
1732
|
+
// to repair instead of replaying the identical under-declared session.
|
|
1733
|
+
if (task.id === FRONTEND_PLAN_NODE_ID &&
|
|
1734
|
+
!result.ok &&
|
|
1735
|
+
result.failureCategory === "invalid-output" &&
|
|
1736
|
+
/frontend decision → relationship patch failed|frontend decision finalize failed/.test(result.stderr ?? "")) {
|
|
1737
|
+
previousProtocolReason = (result.stderr ?? "")
|
|
1738
|
+
.slice(-4_000)
|
|
1739
|
+
.trim();
|
|
1740
|
+
}
|
|
1716
1741
|
if (isFrontendStructuredRepairSchemaId(task.structuredContractOutput?.schemaId)) {
|
|
1717
1742
|
const rawText = canonicalNodeOutput(result);
|
|
1718
1743
|
if (rawText.trim().length > 0) {
|
|
@@ -1905,13 +1930,23 @@ export async function executeDagNode(input) {
|
|
|
1905
1930
|
frontendPriorFingerprints.push(fingerprint);
|
|
1906
1931
|
frontendPlanRetryStep = nextStep;
|
|
1907
1932
|
if (nextStep === "unsupported-provider-capability") {
|
|
1933
|
+
// Reachability first: when the failed attempts never reached model
|
|
1934
|
+
// reasoning (gateway 5xx / rate limit / quota / network), the
|
|
1935
|
+
// ladder's fail-closed category would read as a capability mismatch
|
|
1936
|
+
// and send the diagnosis the wrong way. Keep the outage visible in
|
|
1937
|
+
// the node's category and explain why.
|
|
1938
|
+
const providerOutage = isProviderAvailabilityFailureCategory(result.failureCategory);
|
|
1908
1939
|
result = {
|
|
1909
1940
|
...result,
|
|
1910
1941
|
ok: false,
|
|
1911
|
-
failureCategory:
|
|
1942
|
+
failureCategory: providerOutage
|
|
1943
|
+
? "upstream-unavailable"
|
|
1944
|
+
: "unsupported-provider-capability",
|
|
1912
1945
|
stderr: [
|
|
1913
1946
|
result.stderr,
|
|
1914
|
-
|
|
1947
|
+
providerOutage
|
|
1948
|
+
? "frontend plan retry ladder: attempts failed on provider reachability (5xx / rate limit / quota / network), so this is an upstream outage, not a provider capability mismatch"
|
|
1949
|
+
: "frontend plan retry ladder: no compatible provider capability route for the protocol failure reason",
|
|
1915
1950
|
]
|
|
1916
1951
|
.filter(Boolean)
|
|
1917
1952
|
.join("\n"),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCanonicalFrontendShapeDag } from "./frontend-shape-facts.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { readFile } from "node:fs/promises";
|
|
3
4
|
import { z } from "zod";
|
|
@@ -1348,6 +1349,15 @@ export async function evaluateDagRerunPlan(input) {
|
|
|
1348
1349
|
}
|
|
1349
1350
|
}
|
|
1350
1351
|
const closureSafety = assessResetClosureSafety(input.parentSpec, resetNodeIds, {
|
|
1352
|
+
// The canonical frontend template tails into read-only artifact shells
|
|
1353
|
+
// (review-context, closeout) that carry no commands. Without artifact
|
|
1354
|
+
// continuation admission every from-node restart of that template was
|
|
1355
|
+
// blocked as `restart-subgraph-contains-unsafe-shell`, so a frontend run
|
|
1356
|
+
// could only ever be re-verified by repeating the whole chain (smoke
|
|
1357
|
+
// r27-r36: ~30 min per iteration instead of ~6).
|
|
1358
|
+
...(isCanonicalFrontendShapeDag(new Map(input.parentSpec.tasks.map((task) => [task.id, task])))
|
|
1359
|
+
? { artifactContinuation: true }
|
|
1360
|
+
: {}),
|
|
1351
1361
|
...(transportWriterRestart && effectiveFromNodeId
|
|
1352
1362
|
? { allowedTransportWriterNodeId: effectiveFromNodeId }
|
|
1353
1363
|
: {}),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, readFile } from "node:fs/promises";
|
|
1
|
+
import { access, mkdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { generateTaskDagUseCase } from "../../application/dag/generate-task-dag.js";
|
|
@@ -8,6 +8,7 @@ import { stageRecoveryChild } from "./frontend-recovery-run.js";
|
|
|
8
8
|
import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
|
|
9
9
|
import { DAG_RUNS_DIR, isTerminalDagRunStatus, locateDagRun, readDagRunSpec, readDagRunState, } from "./lifecycle.js";
|
|
10
10
|
import { deriveDagRerunFeedback } from "./rerun-feedback.js";
|
|
11
|
+
import { readTypedEventStoreFromJsonl } from "./frontend-typed-event-store.js";
|
|
11
12
|
import { acquireDagRecoveryLease, bindDagRecoveryLeaseExecution, } from "./recovery-lease.js";
|
|
12
13
|
import { parseDagSpec, } from "./types.js";
|
|
13
14
|
export const RERUN_TASK_LINEAGE_REL_PATH = ".runtime/rerun-task-lineage.json";
|
|
@@ -398,6 +399,81 @@ async function executeFrontendRecoveryContinuation(input) {
|
|
|
398
399
|
if (!locatedChild || locatedChild.runDir !== staged.childRunDir) {
|
|
399
400
|
throw new Error(`frontend recovery child lifecycle drift: ${staged.childRunId}`);
|
|
400
401
|
}
|
|
402
|
+
// D (local design repair): publish a read-only snapshot of the parent's
|
|
403
|
+
// committed decision facts into the child run. The child plan node replays
|
|
404
|
+
// these through its own durable tools (normal commit entry, child binding)
|
|
405
|
+
// and the model only corrects the rows the design review flagged; the
|
|
406
|
+
// parent ledger is never rewritten and the finalize terminal is not
|
|
407
|
+
// inherited. Best-effort: a parent without plan facts plans fresh.
|
|
408
|
+
try {
|
|
409
|
+
const parentPlanLedger = path.join(located.runDir, "frontend-plan-pi", "plan-decision-facts.jsonl");
|
|
410
|
+
const parentRaw = await readFile(parentPlanLedger, "utf8");
|
|
411
|
+
const parentRecords = await readTypedEventStoreFromJsonl(parentPlanLedger);
|
|
412
|
+
// Collapse superseded records first: the parent ledger is append-only
|
|
413
|
+
// (replace:true appends a corrected row), and replaying both the original
|
|
414
|
+
// and its correction would trip FACT_IDENTITY_CONFLICT in the child.
|
|
415
|
+
const { collapseDecisionEntriesByKind } = await import("./frontend-plan-decision-contract.js");
|
|
416
|
+
const byKind = new Map();
|
|
417
|
+
for (const record of parentRecords) {
|
|
418
|
+
const kind = String(record.fact.kind);
|
|
419
|
+
if (record.phase !== "committed" || kind === "finalize_decision")
|
|
420
|
+
continue;
|
|
421
|
+
const entry = record.fact.entry;
|
|
422
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
423
|
+
continue;
|
|
424
|
+
const bucket = byKind.get(kind) ?? [];
|
|
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")
|
|
444
|
+
continue;
|
|
445
|
+
const finding = (fact.finding ?? {});
|
|
446
|
+
designFindings.push({
|
|
447
|
+
severity: typeof finding.severity === "string" ? finding.severity : "Important",
|
|
448
|
+
issue: typeof finding.issue === "string" ? finding.issue : "",
|
|
449
|
+
requiredChange: typeof finding.requiredChange === "string" ? finding.requiredChange : "",
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
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
|
+
}
|
|
401
477
|
const childSpec = await readDagRunSpec(locatedChild.runDir);
|
|
402
478
|
const childState = await readDagRunState(locatedChild.runDir);
|
|
403
479
|
let runSummary;
|
|
@@ -364,6 +364,24 @@ export function computeBackoffDelayMs(attemptNumber, policy) {
|
|
|
364
364
|
const raw = policy.initialDelayMs * 2 ** exponent;
|
|
365
365
|
return Math.min(raw, policy.maxDelayMs);
|
|
366
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Provider-reachability failure categories: the attempt never reached model
|
|
369
|
+
* reasoning, so no capability conclusion may be drawn from it. Used to keep the
|
|
370
|
+
* plan retry ladder from relabelling an upstream outage as
|
|
371
|
+
* `unsupported-provider-capability` (2026-09-11: the gateway returned 503 while
|
|
372
|
+
* r18/r19 reported the vague capability category).
|
|
373
|
+
*/
|
|
374
|
+
export const PROVIDER_AVAILABILITY_FAILURE_CATEGORIES = [
|
|
375
|
+
"unavailable",
|
|
376
|
+
"upstream-unavailable",
|
|
377
|
+
"network",
|
|
378
|
+
"rate-limit",
|
|
379
|
+
"quota",
|
|
380
|
+
];
|
|
381
|
+
export function isProviderAvailabilityFailureCategory(category) {
|
|
382
|
+
return (category !== undefined &&
|
|
383
|
+
PROVIDER_AVAILABILITY_FAILURE_CATEGORIES.includes(category));
|
|
384
|
+
}
|
|
367
385
|
/**
|
|
368
386
|
* A+B (AC-001/AC-005): project raw executor signals to the canonical 7-value
|
|
369
387
|
* protocol failure reason. Specific signals win first, then the existing
|
|
@@ -115,7 +115,7 @@ export const FRONTEND_WRITER_NODE_IDS = [
|
|
|
115
115
|
];
|
|
116
116
|
/**
|
|
117
117
|
* Run-relative artifact location read by the frontend writer admission gate.
|
|
118
|
-
* M8
|
|
118
|
+
* M8 points the admission source at the canonical
|
|
119
119
|
* frontend-writer-admission-result.json artifact (written by the
|
|
120
120
|
* frontend-writer-admission-shell); the exported name is retained because
|
|
121
121
|
* runner.ts / node-execution.ts reference it as the admission evidence source.
|
|
@@ -125,9 +125,7 @@ export { FRONTEND_WRITER_ADMISSION_RESULT_ARTIFACT };
|
|
|
125
125
|
/**
|
|
126
126
|
* Read and validate the writer admission result artifact.
|
|
127
127
|
* Fail-closed: a missing file or invalid payload returns ok:false and never
|
|
128
|
-
* throws. This is the M8 write authorization source
|
|
129
|
-
* frontend-prewrite-result-v1 for dispatch; the legacy artifact remains
|
|
130
|
-
* produced only by the shadow `runFrontendPrewriteGate` library export).
|
|
128
|
+
* throws. This is the M8 write authorization source for dispatch.
|
|
131
129
|
*/
|
|
132
130
|
export async function readFrontendPrewriteResult(runDir) {
|
|
133
131
|
const artifactPath = path.join(runDir, FRONTEND_WRITER_ADMISSION_RESULT_ARTIFACT);
|
|
@@ -449,6 +449,29 @@ export const dagFrontendDesignPolicySchema = z
|
|
|
449
449
|
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
450
450
|
requireSourceFreshness: z.literal(true),
|
|
451
451
|
implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
|
|
452
|
+
/** Generation-frozen requirement→file ownership. Violations are
|
|
453
|
+
* machine-rejected at plan finalize (smoke r35: prose-only ownership
|
|
454
|
+
* rules were ignored by the planner and re-violated by recovery). */
|
|
455
|
+
requirementOwnership: z
|
|
456
|
+
.array(z
|
|
457
|
+
.object({
|
|
458
|
+
requirementIds: z.array(z.string().min(1)).min(1),
|
|
459
|
+
implementationFiles: z.array(z.string().min(1)).optional(),
|
|
460
|
+
verificationFiles: z.array(z.string().min(1)).optional(),
|
|
461
|
+
})
|
|
462
|
+
.strict())
|
|
463
|
+
.optional(),
|
|
464
|
+
/** Generation-frozen test capability boundary composed into the
|
|
465
|
+
* canonical dependencyPolicy by the runtime. */
|
|
466
|
+
capabilityBoundary: z
|
|
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(),
|
|
473
|
+
/** Generation-frozen interaction id vocabulary (plan finalize check). */
|
|
474
|
+
interactionIds: z.array(z.string().min(1)).optional(),
|
|
452
475
|
/** Generation-frozen roots that bound custom normative directories. */
|
|
453
476
|
openspecSpecRoots: z
|
|
454
477
|
.array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
|
package/docs/README.md
CHANGED
|
@@ -80,5 +80,6 @@
|
|
|
80
80
|
| `reports/` | 验证、dogfood、merge、init evolution 与历史 handoff 证据 |
|
|
81
81
|
| `skills/` | repo-local skill registry |
|
|
82
82
|
| `templates/` | 可复用任务、报告、DAG 和 init 模板 |
|
|
83
|
+
| `fixtures/` | 文档与前端 DAG 验收使用的固定输入 |
|
|
83
84
|
|
|
84
85
|
站上使用者文档在 `../website/docs/`;源仓治理事实以本目录、`AGENTS.md`、`harness.json`、`CHANGELOG.md` 和检查脚本为准。
|
|
@@ -364,6 +364,7 @@
|
|
|
364
364
|
"description": "Documentation and user-facing guidance changes that should be considered but should not slow normal iteration.",
|
|
365
365
|
"patterns": [
|
|
366
366
|
"CHANGELOG.md",
|
|
367
|
+
"CHANGELOG/**",
|
|
367
368
|
"website/docs/**",
|
|
368
369
|
"docs/*.md",
|
|
369
370
|
"docs/architecture/**"
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
## 入口
|
|
6
6
|
|
|
7
|
+
- [`scheduled-goal-host.md`](scheduled-goal-host.md):Console Chat 预约宿主、服务环境、状态判读与清理。
|
|
8
|
+
|
|
7
9
|
- [`local-development-environment.md`](local-development-environment.md):本地环境、Windows 差异和常见排障。
|
|
8
10
|
- [`branch-merge-guideline.md`](branch-merge-guideline.md):按风险选择合并模式并留下 source-SHA 证据。
|
|
9
11
|
- [`github-collaboration.md`](github-collaboration.md):仓库内 GitHub 协作约定及发布通道。
|
package/docs/templates/README.md
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
## Backend-test
|
|
32
32
|
|
|
33
|
-
- `backend-test-dag.json` — backend-test DAG
|
|
33
|
+
- `backend-test-dag.json` — backend-test DAG 模板;由 runtime builder 生成,Module Index 的 8 列、separator、单一 resolved Markdown Path 和 Split Reason 集合以 `backend-test-plan-protocol.ts` 为真源并由 drift test 校验;其中 `generate-backend-md-cases-pi` 是唯一允许 `writer-empty-diff` 重试的 writer(总共两次,仅限 post-write-guard attribution 确认的空 diff);N2/N5 合同限定 Scenario Partition 必须有源有限域。
|
|
34
34
|
- `backend-test-dag.classify.prompt.md`、`backend-test-dag.generate-pytest.prompt.md`、`backend-test-dag.review-cases.prompt.md`、`backend-test-dag.retrospect.prompt.md` — 分类、生成、审查和复盘提示。
|
|
35
35
|
- `backend-test-analysis.schema.json`、`backend-test-execution.schema.json`、`backend-test-result.schema.json`、`backend-test-case-manifest.schema.json` — 分析、执行、结果与用例清单 schema。
|
|
36
36
|
|
|
@@ -466,9 +466,9 @@
|
|
|
466
466
|
"retryCategories": {
|
|
467
467
|
"type": "array",
|
|
468
468
|
"items": {
|
|
469
|
-
"enum": ["timeout", "network", "rate-limit", "unavailable", "empty-output", "output-limit", "output-too-large", "protocol-invalid", "invalid-output", "writer-empty-diff", "incomplete-write-set", "writer-clean-timeout", "read-burst", "context-overflow"]
|
|
469
|
+
"enum": ["timeout", "network", "rate-limit", "unavailable", "upstream-unavailable", "empty-output", "output-limit", "output-too-large", "protocol-invalid", "invalid-output", "writer-empty-diff", "incomplete-write-set", "writer-clean-timeout", "read-burst", "context-overflow"]
|
|
470
470
|
},
|
|
471
|
-
"default": ["timeout", "network", "rate-limit", "unavailable", "empty-output", "output-limit"],
|
|
471
|
+
"default": ["timeout", "network", "rate-limit", "unavailable", "upstream-unavailable", "empty-output", "output-limit"],
|
|
472
472
|
"description": "Failure categories eligible for retry. quota/auth/write-guard are never eligible. invalid-output is allowed only on explicit structured/protocol policies; writer-empty-diff and incomplete-write-set are reserved for requireChangedFiles generation/completeness writers; writer-clean-timeout is reserved for standard bounded writers after explicit zero-write-tool-call and empty-diff evidence."
|
|
473
473
|
}
|
|
474
474
|
}
|