@tea-agent/loop-agent 0.43.0-next.1 → 0.43.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 +129 -9
- package/dist/application/dag/run-dag.js +5 -0
- package/dist/application/evaluation/budget.js +19 -1
- package/dist/application/task-lifecycle/advance.js +17 -4
- package/dist/application/task-lifecycle/observe.js +43 -29
- package/dist/application/task-lifecycle/plan-transitions.js +5 -4
- package/dist/build-stamp.json +3 -3
- package/dist/executors/dag-pi-executor.js +1214 -584
- package/dist/executors/pi-executor.js +22 -1
- package/dist/executors/pi-sdk-executor.js +140 -39
- package/dist/executors/shell-executor.js +5 -2
- package/dist/shared/frontend-execution-policy.js +23 -0
- package/dist/task/config-types.js +4 -0
- package/dist/task/source-prepare/ledger-reconciliation.js +2 -2
- package/dist/task/source-prepare/ledger-review.js +6 -9
- package/dist/task/source-prepare/semantic-intake.js +16 -26
- package/dist/task/source-prepare/source-fidelity-pi.js +28 -9
- package/dist/task/source-references.js +48 -23
- package/dist/worker/console/chat/assistant-content.js +23 -2
- package/dist/worker/console/chat/browser-policy.js +143 -0
- package/dist/worker/console/chat/browser-routes.js +148 -0
- package/dist/worker/console/chat/explore-tools.js +13 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +78 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +86 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
- package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
- package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
- package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
- package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
- package/dist/worker/console/chat/pi-runtime.js +213 -1181
- package/dist/worker/console/chat/routes.js +212 -71
- package/dist/worker/console/chat/scm-routes.js +217 -0
- package/dist/worker/console/chat/scm-service.js +283 -0
- package/dist/worker/console/chat/scm-tools.js +111 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +65 -9
- package/dist/worker/console/chat/session-catalog.js +32 -0
- package/dist/worker/console/chat/session-mode-view.js +48 -0
- package/dist/worker/console/chat/session-mode.js +218 -0
- package/dist/worker/console/chat/session-store.js +22 -6
- package/dist/worker/console/chat/shortcuts.js +6 -0
- package/dist/worker/console/chat/terminal-routes.js +216 -0
- package/dist/worker/console/chat/terminal-sessions.js +348 -0
- package/dist/worker/console/chat/terminal-tools.js +211 -0
- package/dist/worker/console/chat/tool-preview.js +11 -0
- package/dist/worker/console/chat/tools.js +2 -0
- package/dist/worker/console/server.js +2 -28
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-B0Q0nClf.js → abnfDiagram-N423BO3Z-D_fNbWc_.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DCPjC19G.js → arc-_HuqLW6m.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CP5n9jmG.js → architectureDiagram-T3A2C74G-Djy2qY1m.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CmaWi_Wg.js → blockDiagram-VBNYF7ZC-bB-1TSyY.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-Ct5tcMfZ.js → c4Diagram-5PPSVZJV-C5Hmghrz.js} +1 -1
- package/dist/worker/console/static/assets/channel-C0A6UEIa.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-C0osm1Zf.js → chunk-2GRJ4B5K-Duyl39oy.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CDWviED7.js → chunk-2Q5K7J3B-x6mdnSyf.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-mtSk1-j7.js → chunk-5RXB4S5H-WlBuFj7W.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-D5J9PHC7.js → chunk-5VM5RSS4-CTF429HX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Begg4WAa.js → chunk-6Q2QTUOP-Dwd6r-SF.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-sF1AEy7T.js → chunk-GF5L2VYU-C-Br82D1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BqbsWXZb.js → chunk-JWPE2WC7-CuGp0DeE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BKJrPcJ6.js → chunk-KBJHAD2P-CJhFX6Lh.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CcwNMRho.js → chunk-RYQCIY6F-DpGOa_jT.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BEJi3iIs.js → chunk-XXDRQBXY-DXJaTynd.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DzguNppy.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DzguNppy.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-DRLgTvVu.js → cose-bilkent-JH36ORCC-CRBZWjE4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BoAVG3cs.js → cynefin-VYW2F7L2-BdXcxtlb.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bzol06hR.js → cynefinDiagram-MW4NZA55-07UKsOts.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-UmliJM77.js → dagre-VZM6K2ZE-D38p9__S.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BWLcJkFo.js → diagram-7IWD3JNH-nSiBNNjH.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CgApOm-O.js → diagram-B4RE2ZJO-BFOTot5D.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-Bh3RgTLs.js → diagram-LBJQPF4R-DypKaZ6k.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-Dsh-D5nE.js → diagram-Q27KOJAE-B6yoOQeW.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-Dkbbpcpb.js → diagram-UB23O5K3-BHYS6viX.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-3EBaA3t3.js → ebnfDiagram-BXEA7PRR-D2VD5Snj.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Bq2Dc5ok.js → erDiagram-JOGREHBK-E98mWxN1.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-De7y55ha.js → flowDiagram-UKHOOZJN-CT1zxhqP.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-fLiDbQRh.js → ganttDiagram-PKOTCBZU-6GcngNcy.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Du617mp1.js → gitGraphDiagram-DS77QQ5N-DCL6NvKe.js} +1 -1
- package/dist/worker/console/static/assets/index-24jp3aBh.js +468 -0
- package/dist/worker/console/static/assets/index-CY6y6I8M.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BwmlF-XP.js → infoDiagram-6WML65LV-C0627e-9.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-zsGtS59u.js → ishikawaDiagram-WSZJBQD7-C_u3P6Ik.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DTTPTe3f.js → journeyDiagram-NVQOT4AX-DPDPv9HL.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-BkXg9aP-.js → kanban-definition-27J2QSJJ-D3OHdWiO.js} +1 -1
- package/dist/worker/console/static/assets/{linear-7U2ue5IE.js → linear-DI88zD7n.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BUuGHmWO.js → mermaid.core-p2l8IrWY.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-7q6fX0Sv.js → mindmap-definition-FAOFIHXS-B1bAX-oS.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CkQPJN55.js → pegDiagram-VL7TDLO6-DwOnWxdD.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CCal_tfX.js → pieDiagram-7S7Q4E2Y-xRkTXnJC.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-B7bpxyAZ.js → quadrantDiagram-CIZ2JOQS-_9UC5Zio.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CJmww7D-.js → railroadDiagram-AXF67PYL-CgEUirWJ.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D6ldWJEv.js → requirementDiagram-LRYGKXZP-Czbpwiyz.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-VGh33I9e.js → sankeyDiagram-W5VNT64P-_j7_KiqY.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CCkDrIjU.js → sequenceDiagram-SI44F4Z6-BNJa6Hyi.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-NC8f5Otb.js → sizeCapture-X5ZJPWSS-DedpKtOc.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-_92ezZdF.js → stateDiagram-OKZ733FA-BBvthr7c.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BABVQnfM.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BdUCGtbP.js → swimlanes-SLNWSIFB-Ds7umgEM.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D0qsLaxR.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CdD1H8ia.js → timeline-definition-Z64GVDOM-CKa-p1nF.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-Dkdk3oFo.js → vennDiagram-T6HMQDX7-LoUNR56o.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CKu2uPPY.js → wardleyDiagram-T6FBY63Y-Bqbl6ym7.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-ClqAnuG8.js → xychartDiagram-ELKLHX3M-B8dUg4lf.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +10 -0
- package/dist/worker/console/static-src/operator-chat/chat-link.js +94 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +122 -10
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +7 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +27 -15
- package/dist/worker/console/static-src/operator-chat/process-label.js +41 -0
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +13 -0
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +10 -0
- package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +51 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +44 -24
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +18 -2
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +41 -8
- package/dist/worker/console/static-src/operator-chat/useComposer.js +26 -11
- package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +21 -0
- package/dist/worker/console/workspace-context.js +15 -1
- package/dist/worker/observe/node-transparency.js +81 -72
- package/dist/worker/observe/routes.js +20 -1
- package/dist/worker/observe/static/dag-inspector-humanize.js +3 -0
- package/dist/worker/observe/static/dom.js +20 -1
- package/dist/worker/observe/static/format-pool.d.ts +2 -0
- package/dist/worker/observe/static/format-pool.js +6 -0
- package/dist/worker/observe/static/format.js +7 -0
- package/dist/worker/observe/static/inspect-workspace.js +34 -7
- package/dist/worker/observe/static/inspector-submission.js +32 -0
- package/dist/worker/observe/static/kpi.js +1 -0
- package/dist/worker/observe/static/relations.js +2 -0
- package/dist/worker/observe/static/router.js +13 -0
- package/dist/worker/observe/static/run-processing.js +2 -0
- package/dist/worker/observe/static/shell-chrome.js +36 -3
- package/dist/worker/observe/static/state.js +35 -2
- package/dist/worker/observe/static/styles.css +263 -39
- package/dist/worker/observe/static/task-failure-labels.d.ts +4 -0
- package/dist/worker/observe/static/task-failure-labels.js +67 -0
- package/dist/worker/observe/static/task-history.js +12 -0
- package/dist/worker/observe/static/views/batch.js +6 -13
- package/dist/worker/observe/static/views/dag-graph.js +50 -3
- package/dist/worker/observe/static/views/dag-inspector.js +742 -268
- package/dist/worker/observe/static/views/dag-trajectory.js +3 -0
- package/dist/worker/observe/static/views/dag.d.ts +6 -0
- package/dist/worker/observe/static/views/dag.js +49 -11
- package/dist/worker/observe/static/views/dags.js +2 -0
- package/dist/worker/observe/static/views/dashboard.js +21 -12
- package/dist/worker/observe/static/views/failures.js +21 -11
- package/dist/worker/observe/static/views/feature.js +11 -29
- package/dist/worker/observe/static/views/pool.js +37 -28
- package/dist/worker/observe/static/views/run.js +48 -5
- package/dist/worker/observe/static/views/session-timeline.js +189 -240
- package/dist/worker/observe/static/views/task.js +81 -62
- package/dist/workflows/dag/budget-enforcement.js +53 -3
- package/dist/workflows/dag/frontend-capacity.js +9 -0
- package/dist/workflows/dag/frontend-design-policy.js +2 -1
- package/dist/workflows/dag/frontend-durable-tools.js +193 -0
- package/dist/workflows/dag/frontend-execution-groups.js +24 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +13 -0
- package/dist/workflows/dag/frontend-input-projection.js +76 -0
- package/dist/workflows/dag/frontend-plan-completeness.js +186 -0
- package/dist/workflows/dag/frontend-plan-recovery-policy.js +18 -0
- package/dist/workflows/dag/frontend-plan-render.js +10 -3
- package/dist/workflows/dag/frontend-recovery-controller.js +7 -7
- package/dist/workflows/dag/frontend-recovery-lineage.js +13 -0
- package/dist/workflows/dag/frontend-recovery-run.js +4 -0
- package/dist/workflows/dag/frontend-review-scopes.js +139 -0
- package/dist/workflows/dag/frontend-session-budget.js +249 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +20 -2
- package/dist/workflows/dag/frontend-shape-facts.js +12 -2
- package/dist/workflows/dag/frontend-shape.js +30 -1
- package/dist/workflows/dag/frontend-test-execution-evidence.js +3 -2
- package/dist/workflows/dag/frontend-typed-event-store.js +11 -0
- package/dist/workflows/dag/init-hybrid.js +16 -10
- package/dist/workflows/dag/node-execution.js +38 -155
- package/dist/workflows/dag/prompt.js +4 -0
- package/dist/workflows/dag/rerun-plan.js +7 -1
- package/dist/workflows/dag/runner.js +26 -1
- package/dist/workflows/dag/types.js +6 -0
- package/docs/operations/README.md +1 -0
- package/docs/templates/frontend-design-contract.md +4 -4
- package/docs/templates/frontend-implementation-contract.schema.json +34 -2
- package/docs/templates/frontend-implementation-dag.json +5 -5
- package/package.json +6 -3
- package/skills/frontend-contract/SKILL.md +2 -1
- package/skills/frontend-contract/references/contract-protocol.md +19 -3
- package/skills/frontend-design-review/SKILL.md +12 -11
- package/skills/frontend-plan/SKILL.md +9 -2
- package/skills/frontend-plan/references/decision-contract.md +18 -5
- package/skills/frontend-review/SKILL.md +10 -11
- package/skills/frontend-scout/references/scout-evidence.md +4 -0
- package/dist/worker/console/static/assets/channel-DAS07MdS.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cwk-5jiW.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cwk-5jiW.js +0 -1
- package/dist/worker/console/static/assets/index-C0O48S_P.js +0 -449
- package/dist/worker/console/static/assets/index-CzKf4U8P.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DyJg5gzW.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B1cw_0Uy.js +0 -8
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { collectFrontendExecutionGroups } from "./frontend-execution-groups.js";
|
|
2
|
+
import { reserveDagProviderRequest } from "./budget-enforcement.js";
|
|
1
3
|
import { createHash } from "node:crypto";
|
|
2
4
|
import { existsSync } from "node:fs";
|
|
3
5
|
import { readFile } from "node:fs/promises";
|
|
@@ -297,6 +299,12 @@ export function buildContextOverflowRetryPrompt(task, basePrompt) {
|
|
|
297
299
|
compactRetrySection(basePrompt, "task", COMPACT_RETRY_TASK_MAX_CHARS),
|
|
298
300
|
"</task>",
|
|
299
301
|
].join("\n"),
|
|
302
|
+
// Plan still needs the complete frozen obligations for ledger ownership
|
|
303
|
+
// and scoped projection. Its executor packs this block before dispatch;
|
|
304
|
+
// dropping or character-truncating it prevents safe progress recovery.
|
|
305
|
+
...(isFrontendPlanLadderTask(task)
|
|
306
|
+
? [basePrompt.match(/<frontend_plan_input>[\s\S]*?<\/frontend_plan_input>/)?.[0] ?? ""]
|
|
307
|
+
: []),
|
|
300
308
|
].join("\n\n");
|
|
301
309
|
}
|
|
302
310
|
function isFrontendPlanLadderTask(task) {
|
|
@@ -380,27 +388,14 @@ async function readFrontendPlanCommittedSnapshot(runDir, nodeId) {
|
|
|
380
388
|
function planInputRecord(value) {
|
|
381
389
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
382
390
|
}
|
|
383
|
-
function planInputText(value,
|
|
384
|
-
|
|
385
|
-
return undefined;
|
|
386
|
-
const normalized = value.trim();
|
|
387
|
-
return normalized.length <= maxChars
|
|
388
|
-
? normalized
|
|
389
|
-
: `${normalized.slice(0, maxChars - 1)}…`;
|
|
391
|
+
function planInputText(value, _maxChars) {
|
|
392
|
+
return typeof value === "string" && value.trim().length ? value.trim() : undefined;
|
|
390
393
|
}
|
|
391
394
|
function planInputStrings(value) {
|
|
392
395
|
return Array.isArray(value)
|
|
393
396
|
? value.filter((item) => typeof item === "string")
|
|
394
397
|
: [];
|
|
395
398
|
}
|
|
396
|
-
/** Input bound for the planner evidence block; protects the model input budget. */
|
|
397
|
-
const FRONTEND_PLAN_INPUT_MAX_CHARS = 12_000;
|
|
398
|
-
const FRONTEND_PLAN_INPUT_CAP_LADDER = [
|
|
399
|
-
{ text: 240, array: 40 },
|
|
400
|
-
{ text: 120, array: 20 },
|
|
401
|
-
{ text: 60, array: 10 },
|
|
402
|
-
{ text: 24, array: 4 },
|
|
403
|
-
];
|
|
404
399
|
/**
|
|
405
400
|
* Frozen requirement→PRD citation map for the plan review checklist: lets the
|
|
406
401
|
* model declare sourceRequirementIds whose section/line match the component
|
|
@@ -446,78 +441,19 @@ async function resolveComponentSourceCitations(spec, cwd) {
|
|
|
446
441
|
return new Map();
|
|
447
442
|
}
|
|
448
443
|
}
|
|
449
|
-
/** Input bound for the contract node's compiled ledger block. */
|
|
450
|
-
const FRONTEND_CONTRACT_INPUT_MAX_CHARS = 12_000;
|
|
451
444
|
/**
|
|
452
|
-
* Render the contract node's complete
|
|
445
|
+
* Render the contract node's complete semantic ledger handoff. The
|
|
453
446
|
* source-fidelity ledger already extracted canonical requirements with source
|
|
454
447
|
* spans; the contract node confirms and commits them incrementally through
|
|
455
448
|
* record_requirement instead of re-reading the raw source (extreme-environment:
|
|
456
449
|
* a small output window cannot absorb a full source re-read).
|
|
457
450
|
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
451
|
+
* Whole obligations are retained here; the executor selects complete scopes
|
|
452
|
+
* before dispatch. References and conditions are never clipped.
|
|
460
453
|
*/
|
|
461
454
|
export function renderFrontendContractInputContext(input) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
// sourceFragmentIds entirely, the model (correctly refusing to invent ids)
|
|
465
|
-
// committed empty bindings, and the plan compile failed the ledger-binding
|
|
466
|
-
// gate for every requirement. Bindings therefore bypass the cap ladder and
|
|
467
|
-
// every degradation level; only requirement TEXTS and fragment CONTEXT
|
|
468
|
-
// (path/headingPath) may degrade. Fragment context is rendered only for
|
|
469
|
-
// fragments actually referenced by a requirement and shrinks first.
|
|
470
|
-
const referencedFragmentIds = new Set(input.canonicalRequirements.flatMap((requirement) => planInputStrings(requirement.sourceFragmentIds)));
|
|
471
|
-
const referencedFragments = input.fragments.filter((fragment) => referencedFragmentIds.has(fragment.id));
|
|
472
|
-
const serializeAtCap = (cap) => JSON.stringify({
|
|
473
|
-
requirements: input.canonicalRequirements.map((requirement) => ({
|
|
474
|
-
id: requirement.id,
|
|
475
|
-
text: planInputText(requirement.text, cap.text),
|
|
476
|
-
sourceFragmentIds: planInputStrings(requirement.sourceFragmentIds),
|
|
477
|
-
})),
|
|
478
|
-
fragments: referencedFragments.map((fragment) => ({
|
|
479
|
-
id: fragment.id,
|
|
480
|
-
path: planInputText(fragment.path, 200),
|
|
481
|
-
headingPath: planInputText(fragment.headingPath, 120),
|
|
482
|
-
lineRange: fragment.lineRange,
|
|
483
|
-
})),
|
|
484
|
-
});
|
|
485
|
-
let serialized = serializeAtCap(FRONTEND_PLAN_INPUT_CAP_LADDER[0]);
|
|
486
|
-
for (const cap of FRONTEND_PLAN_INPUT_CAP_LADDER.slice(1)) {
|
|
487
|
-
if (serialized.length <= FRONTEND_CONTRACT_INPUT_MAX_CHARS)
|
|
488
|
-
break;
|
|
489
|
-
serialized = serializeAtCap(cap);
|
|
490
|
-
}
|
|
491
|
-
if (serialized.length > FRONTEND_CONTRACT_INPUT_MAX_CHARS) {
|
|
492
|
-
// Last resort: keep every requirement id AND its fragment bindings,
|
|
493
|
-
// degrade texts, and shrink referenced fragment context first (halve,
|
|
494
|
-
// then drop context fields, then drop the fragment list entirely).
|
|
495
|
-
// Requirement ids and sourceFragmentIds are never dropped.
|
|
496
|
-
let fragments = referencedFragments.map((fragment) => ({
|
|
497
|
-
id: fragment.id,
|
|
498
|
-
path: planInputText(fragment.path, 120),
|
|
499
|
-
}));
|
|
500
|
-
let requirements = input.canonicalRequirements.map((requirement) => {
|
|
501
|
-
const sourceFragmentIds = planInputStrings(requirement.sourceFragmentIds);
|
|
502
|
-
return {
|
|
503
|
-
id: requirement.id,
|
|
504
|
-
text: "(truncated)",
|
|
505
|
-
// Empty bindings carry no information; omit them so the payload
|
|
506
|
-
// stays inside the char bound when no requirement is bound.
|
|
507
|
-
...(sourceFragmentIds.length > 0 ? { sourceFragmentIds } : {}),
|
|
508
|
-
};
|
|
509
|
-
});
|
|
510
|
-
let bounded = JSON.stringify({ degraded: "requirement-texts-truncated", requirements, fragments });
|
|
511
|
-
while (bounded.length > FRONTEND_CONTRACT_INPUT_MAX_CHARS && fragments.length > 0) {
|
|
512
|
-
fragments = fragments.slice(0, Math.floor(fragments.length / 2));
|
|
513
|
-
bounded = JSON.stringify({
|
|
514
|
-
degraded: "requirement-texts-truncated",
|
|
515
|
-
requirements,
|
|
516
|
-
fragments,
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
serialized = bounded;
|
|
520
|
-
}
|
|
455
|
+
const referenced = new Set(input.canonicalRequirements.flatMap(r => r.sourceFragmentIds));
|
|
456
|
+
const serialized = JSON.stringify({ requirements: input.canonicalRequirements, fragments: input.fragments.filter(f => referenced.has(f.id)) });
|
|
521
457
|
return [
|
|
522
458
|
"<frontend_contract_input>",
|
|
523
459
|
"Canonical requirements extracted by the source-fidelity ledger, compiled by the runner. Treat them as the authoritative requirement inventory: confirm and commit each requirement through record_requirement (one per tool call); the ledger already binds source fragments, so do NOT re-read the raw source files.",
|
|
@@ -542,16 +478,13 @@ export async function buildFrontendContractInputContext(input) {
|
|
|
542
478
|
});
|
|
543
479
|
}
|
|
544
480
|
/**
|
|
545
|
-
* Render the planner's complete
|
|
481
|
+
* Render the planner's complete semantic evidence handoff from committed
|
|
546
482
|
* typed facts. It deliberately excludes upstream response prose and artifact
|
|
547
483
|
* paths: Contract and Scout have already established these facts, so Plan
|
|
548
484
|
* should decide and commit rather than spend another model turn reading them.
|
|
549
485
|
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
552
|
-
* fallback keeps every requirement id (with `text: "(truncated)"`) while
|
|
553
|
-
* declaring the degradation, so the planner records targeted evidence gaps
|
|
554
|
-
* instead of receiving a silently corrupted tail.
|
|
486
|
+
* Whole obligations are retained. Session packing and scoped projection happen
|
|
487
|
+
* in the executor before dispatch, without dropping text or source identities.
|
|
555
488
|
*/
|
|
556
489
|
export function renderFrontendPlanInputContext(input) {
|
|
557
490
|
const committedFacts = (records) => records.flatMap((record) => record.phase === "committed" && planInputRecord(record.fact)
|
|
@@ -610,77 +543,12 @@ export function renderFrontendPlanInputContext(input) {
|
|
|
610
543
|
const behaviorRequiredIds = requirementFacts
|
|
611
544
|
.filter((requirement) => requirement.evidence.behavior === "required")
|
|
612
545
|
.map((requirement) => requirement.id);
|
|
613
|
-
const
|
|
614
|
-
requirements
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
})),
|
|
619
|
-
requiredDeliverables,
|
|
620
|
-
targetSurface: targetSurface.map((surface) => ({
|
|
621
|
-
completeness: planInputText(surface.completeness, 32),
|
|
622
|
-
entrypoint: planInputText(surface.entrypoint, cap.text),
|
|
623
|
-
routeOrMount: planInputText(surface.routeOrMount, cap.text),
|
|
624
|
-
implementationPaths: planInputStrings(surface.implementationPaths).slice(0, cap.array),
|
|
625
|
-
testPaths: planInputStrings(surface.testPaths).slice(0, cap.array),
|
|
626
|
-
dataSource: planInputText(surface.dataSource, cap.text),
|
|
627
|
-
allowedPathConflicts: planInputStrings(surface.allowedPathConflicts).slice(0, cap.array),
|
|
628
|
-
unresolvedPaths: planInputStrings(surface.unresolvedPaths).slice(0, cap.array),
|
|
629
|
-
})),
|
|
630
|
-
designEvidence: designEvidence.map((evidence) => ({
|
|
631
|
-
source: planInputText(evidence.source, cap.text),
|
|
632
|
-
paths: planInputStrings(evidence.paths).slice(0, cap.array),
|
|
633
|
-
conflicts: planInputStrings(evidence.conflicts).slice(0, cap.array),
|
|
634
|
-
})),
|
|
635
|
-
declaredUiStates: declaredUiStates.map((state) => ({
|
|
636
|
-
id: state.id,
|
|
637
|
-
trigger: planInputText(state.trigger, cap.text),
|
|
638
|
-
observableOutcome: planInputText(state.observableOutcome, cap.text),
|
|
639
|
-
})),
|
|
640
|
-
committedUx: committedUiStateNames.length > 0 ||
|
|
641
|
-
committedInteractionNames.length > 0
|
|
642
|
-
? {
|
|
643
|
-
uiStateNames: committedUiStateNames,
|
|
644
|
-
interactionNames: committedInteractionNames,
|
|
645
|
-
}
|
|
646
|
-
: undefined,
|
|
546
|
+
const serialized = JSON.stringify({
|
|
547
|
+
requirements, requiredDeliverables, targetSurface, designEvidence, declaredUiStates,
|
|
548
|
+
executionGroups: collectFrontendExecutionGroups(contractFacts.filter(f => f.kind === "requirement").map(f => ({ id: String(f.id), execution: f.execution }))),
|
|
549
|
+
constraints: contractFacts.filter(f => ["constraint", "open-question", "split-proposal", "handoff-intent"].includes(String(f.kind))),
|
|
550
|
+
committedUx: committedUiStateNames.length || committedInteractionNames.length ? { uiStateNames: committedUiStateNames, interactionNames: committedInteractionNames } : undefined,
|
|
647
551
|
});
|
|
648
|
-
let serialized = serializeAtCap(FRONTEND_PLAN_INPUT_CAP_LADDER[0]);
|
|
649
|
-
for (const cap of FRONTEND_PLAN_INPUT_CAP_LADDER.slice(1)) {
|
|
650
|
-
if (serialized.length <= FRONTEND_PLAN_INPUT_MAX_CHARS)
|
|
651
|
-
break;
|
|
652
|
-
serialized = serializeAtCap(cap);
|
|
653
|
-
}
|
|
654
|
-
if (serialized.length > FRONTEND_PLAN_INPUT_MAX_CHARS) {
|
|
655
|
-
// Last resort: keep every requirement id (ids are short and the plan
|
|
656
|
-
// prompt separately lists them) but drop their texts, shrink scout facts
|
|
657
|
-
// to the minimum, and declare the degradation instead of corrupting JSON.
|
|
658
|
-
let fallback = {
|
|
659
|
-
degraded: "requirement-texts-truncated",
|
|
660
|
-
requiredDeliverables,
|
|
661
|
-
requirements: requirements.map((requirement) => ({
|
|
662
|
-
id: requirement.id,
|
|
663
|
-
text: "(truncated)",
|
|
664
|
-
})),
|
|
665
|
-
targetSurface: targetSurface.map((surface) => ({
|
|
666
|
-
completeness: planInputText(surface.completeness, 32),
|
|
667
|
-
implementationPaths: planInputStrings(surface.implementationPaths).slice(0, FRONTEND_PLAN_INPUT_CAP_LADDER[3].array),
|
|
668
|
-
})),
|
|
669
|
-
designEvidence: [],
|
|
670
|
-
};
|
|
671
|
-
let bounded = JSON.stringify(fallback);
|
|
672
|
-
let keep = fallback.requirements.length;
|
|
673
|
-
while (bounded.length > FRONTEND_PLAN_INPUT_MAX_CHARS &&
|
|
674
|
-
keep > 0) {
|
|
675
|
-
keep = Math.max(0, Math.floor(keep / 2));
|
|
676
|
-
fallback = { ...fallback, requirements: fallback.requirements.slice(0, keep) };
|
|
677
|
-
bounded = JSON.stringify({
|
|
678
|
-
...fallback,
|
|
679
|
-
requirementIdsTruncated: keep < requirements.length,
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
serialized = bounded;
|
|
683
|
-
}
|
|
684
552
|
const checklistLines = [
|
|
685
553
|
"1. Record the GLOBAL UX vocabulary with record_state_registry BEFORE any record_state_flow: one stable behavior-domain name per state/interaction (e.g. planner-task-edit), never one name per AC number, and never a rename of an already-recorded concept. Coverage slices by AC; UX does not.",
|
|
686
554
|
"2. Every recorded interaction/uiState name must be in that registry, and uiState names must use the contract's declared authoritative ids (declaredUiStates below) when present.",
|
|
@@ -1583,6 +1451,20 @@ export async function executeDagNode(input) {
|
|
|
1583
1451
|
return;
|
|
1584
1452
|
}
|
|
1585
1453
|
}
|
|
1454
|
+
if (task.id === "frontend-scout-pi") {
|
|
1455
|
+
try {
|
|
1456
|
+
const { readTypedEventStoreFromJsonl } = await import("./frontend-typed-event-store.js");
|
|
1457
|
+
const facts = (await readTypedEventStoreFromJsonl(path.join(runDir, "frontend-contract-pi", "contract-typed-facts.jsonl"))).filter(r => r.phase === "committed").map(r => r.fact);
|
|
1458
|
+
const requirements = [...new Map(facts.filter(f => f.kind === "requirement").map(f => [String(f.id), f])).values()];
|
|
1459
|
+
if (!requirements.length)
|
|
1460
|
+
throw Error("FRONTEND_INPUT_MISSING: Scout needs committed Contract obligations");
|
|
1461
|
+
prompt += `\n<frontend_scout_input>\n${JSON.stringify({ requirements, sharedFacts: facts.filter(f => !["requirement", "contract-scope-completed", "contract-finalized"].includes(String(f.kind))) })}\n</frontend_scout_input>`;
|
|
1462
|
+
}
|
|
1463
|
+
catch (error) {
|
|
1464
|
+
await failBeforePrompt(error, "frontend-scout-input-unavailable");
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1586
1468
|
if (FRONTEND_WRITER_NODE_IDS.includes(nodeId)) {
|
|
1587
1469
|
// Design-review findings are not reliable in the provider's prose output
|
|
1588
1470
|
// (typed terminal nodes commonly return an empty assistant message). Inject
|
|
@@ -1770,6 +1652,7 @@ export async function executeDagNode(input) {
|
|
|
1770
1652
|
attemptPrompt,
|
|
1771
1653
|
});
|
|
1772
1654
|
result = await executeNode({
|
|
1655
|
+
...(state.budgetLedger?.mode === "hard" && state.budgetLedger.limits.maxProviderRequests !== undefined ? { reserveProviderRequest: () => reserveDagProviderRequest({ state, nodeId, attempt: attemptNumber, persist: input.persistState }) } : {}),
|
|
1773
1656
|
task,
|
|
1774
1657
|
cwd,
|
|
1775
1658
|
model,
|
|
@@ -136,6 +136,10 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
|
|
|
136
136
|
const consumedArtifactIds = new Set((task.consumesArtifacts ?? []).map((binding) => binding.artifactId));
|
|
137
137
|
for (const depId of task.depends_on) {
|
|
138
138
|
const record = upstream[depId];
|
|
139
|
+
if (task.id === "frontend-scout-pi" && depId === "frontend-contract-pi" && record?.status === "FINISHED") {
|
|
140
|
+
sections.push(`## Upstream output: ${depId}\nCommitted Contract obligations are supplied in frontend_scout_input. Do not reconstruct them from prose or reread the source.`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
139
143
|
const stdout = record?.stdout?.trim() ? record.stdout : "";
|
|
140
144
|
const assistantText = record?.assistantText?.trim()
|
|
141
145
|
? record.assistantText
|
|
@@ -46,6 +46,7 @@ const highRiskContinuationAuthorityV1Schema = z
|
|
|
46
46
|
tokens: z.number().int().nonnegative().nullable(),
|
|
47
47
|
wallTimeMs: z.number().nonnegative(),
|
|
48
48
|
executorCalls: z.number().int().nonnegative(),
|
|
49
|
+
providerRequests: z.number().int().nonnegative().optional(),
|
|
49
50
|
repairPasses: z.number().int().nonnegative(),
|
|
50
51
|
peakContextChars: z.number().int().nonnegative(),
|
|
51
52
|
missingTokenNodeIds: z.array(z.string()),
|
|
@@ -1300,7 +1301,12 @@ export async function evaluateDagRerunPlan(input) {
|
|
|
1300
1301
|
const task = tasksByIdForPlan.get(nodeId);
|
|
1301
1302
|
return task?.readSet ?? [];
|
|
1302
1303
|
});
|
|
1303
|
-
|
|
1304
|
+
// An omitted or empty readSet is unrestricted, not proof that an
|
|
1305
|
+
// imported node read nothing. Localize drift only when every reused
|
|
1306
|
+
// node has an explicit reading boundary.
|
|
1307
|
+
const importedReadSetsKnown = importedNodeIds.every((nodeId) => (tasksByIdForPlan.get(nodeId)?.readSet?.length ?? 0) > 0);
|
|
1308
|
+
const scopedDrift = importedReadSetsKnown &&
|
|
1309
|
+
driftedPaths !== undefined &&
|
|
1304
1310
|
driftedPaths.length > 0 &&
|
|
1305
1311
|
driftedPaths.every((driftPath) => !importedReadPaths.some((pattern) => pathMatchesWorkspacePattern(driftPath, pattern)) &&
|
|
1306
1312
|
resetNodeIds.some((nodeId) => {
|
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import { isHardBudgetBreached, resolveEffectiveMaxConcurrent, } from "../../application/evaluation/budget.js";
|
|
7
7
|
import { readCandidateRecord } from "../../infrastructure/evaluation/candidate-store.js";
|
|
8
8
|
import { CANONICAL_TASK_ID_PATTERN, formatLocalCompactDate, } from "../../task/runtime.js";
|
|
9
|
-
import { assertFrozenBudget, initRunBudgetLedger, preflightBudgetOrBreach, recordFinishedNodeBudget, writeBudgetLedgerArtifacts, } from "./budget-enforcement.js";
|
|
9
|
+
import { assertFrozenBudget, initRunBudgetLedger, preflightBudgetOrBreach, recordFinishedNodeBudget, validateCumulativeBudgetSuccessor, writeBudgetLedgerArtifacts, } from "./budget-enforcement.js";
|
|
10
10
|
import { getDagRunDir, isTerminalDagRunStatus, locateDagRun, readHumanApprovalArtifact, readDagRunState, requireActiveDagRun, } from "./lifecycle.js";
|
|
11
11
|
import { markInterruptNeedsReconcile, mergeAbortSignals, readInterruptRequest, runnerIdentityFromState, settleDagInterrupt, startInterruptWatcher, } from "./interrupt-request.js";
|
|
12
12
|
import { moveToCompletedRunDir, moveToPausedRunDir, prepareRunDir, writeRunSpec, writeRunState, } from "./run-store.js";
|
|
@@ -887,6 +887,31 @@ async function executeDagCheckpoint(input) {
|
|
|
887
887
|
observeOnly: created.kind === "observed",
|
|
888
888
|
deps: {
|
|
889
889
|
...input.recovery,
|
|
890
|
+
budget: input.recovery.budget ?? state.budget,
|
|
891
|
+
readLedgers: input.recovery.readLedgers ?? (async () => {
|
|
892
|
+
if (!state.budget)
|
|
893
|
+
return [];
|
|
894
|
+
const location = await locateDagRun(cwd, state.runId);
|
|
895
|
+
let current = await readDagRunState(location?.runDir ?? runDir);
|
|
896
|
+
const visited = new Set([current.runId]);
|
|
897
|
+
while (current.frontendRecoveryState?.parentRunId === current.runId && current.frontendRecoveryState.childRunId && current.frontendRecoveryState.childRunId !== current.runId) {
|
|
898
|
+
if (["child-staging", "child-activating"].includes(current.frontendRecoveryState.phase))
|
|
899
|
+
break;
|
|
900
|
+
const childId = current.frontendRecoveryState.childRunId;
|
|
901
|
+
if (visited.has(childId))
|
|
902
|
+
throw Error("FRONTEND_PROVIDER_BUDGET_LINEAGE_INVALID: cyclic recovery");
|
|
903
|
+
visited.add(childId);
|
|
904
|
+
const childLocation = await locateDagRun(cwd, childId);
|
|
905
|
+
if (!childLocation)
|
|
906
|
+
throw Error("FRONTEND_PROVIDER_BUDGET_LINEAGE_INVALID: missing recovery child");
|
|
907
|
+
const child = await readDagRunState(childLocation.runDir);
|
|
908
|
+
validateCumulativeBudgetSuccessor(current, child);
|
|
909
|
+
current = child;
|
|
910
|
+
}
|
|
911
|
+
if (!current.budgetLedger)
|
|
912
|
+
throw Error("FRONTEND_PROVIDER_BUDGET_INVALID: recovery ledger missing");
|
|
913
|
+
return [current.budgetLedger];
|
|
914
|
+
}),
|
|
890
915
|
failureOwner: input.recovery.failureOwner ??
|
|
891
916
|
recoveryTrigger.failureOwner,
|
|
892
917
|
protocolFailureReason: input.recovery.protocolFailureReason ??
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { frontendExecutionPolicySchema } from "../../shared/frontend-execution-policy.js";
|
|
2
3
|
import { DEFAULT_FRONTEND_SPEC_ROOTS, isFrontendSpecFilePath, isValidFrontendSpecRoot, OPENSPEC_SPEC_EXT_RE, } from "../../shared/openspec-spec.js";
|
|
3
4
|
import { campaignBudgetSchema, } from "../../application/evaluation/budget.js";
|
|
4
5
|
import { assertDagPromptSourceRule } from "./prompt-source.js";
|
|
@@ -1385,6 +1386,7 @@ export const dagSpecSchema = z
|
|
|
1385
1386
|
evaluation: dagEvaluationBindingSchema.optional(),
|
|
1386
1387
|
/** Optional hard/record-only budget; requires version 3 or 4. */
|
|
1387
1388
|
budget: dagBudgetSchema.optional(),
|
|
1389
|
+
frontendExecutionPolicy: frontendExecutionPolicySchema.optional(),
|
|
1388
1390
|
sourceBinding: dagSourceBindingSchema.optional(),
|
|
1389
1391
|
/** v4 managed Task Contract binding; only valid on version 4. */
|
|
1390
1392
|
taskContractBinding: dagTaskContractBindingSchema.optional(),
|
|
@@ -1567,6 +1569,10 @@ export const frontendRecoveryStateSchema = z
|
|
|
1567
1569
|
recoveryRootRunId: z.string().min(1),
|
|
1568
1570
|
parentRunId: z.string().min(1),
|
|
1569
1571
|
childRunId: z.string().min(1).optional(),
|
|
1572
|
+
budgetLineage: z.object({
|
|
1573
|
+
parentLedgerSha256: z.string().regex(/^[a-f0-9]{64}$/), inheritedAt: z.string().datetime(),
|
|
1574
|
+
inheritedConsumed: z.object({ tokens: z.number().nonnegative().nullable(), wallTimeMs: z.number().nonnegative(), executorCalls: z.number().int().nonnegative(), providerRequests: z.number().int().nonnegative().optional(), repairPasses: z.number().int().nonnegative(), peakContextChars: z.number().int().nonnegative(), missingTokenNodeIds: z.array(z.string()) }).strict(),
|
|
1575
|
+
}).strict().optional(),
|
|
1570
1576
|
attemptId: z.string().min(1),
|
|
1571
1577
|
attemptIndex: z.number().int().min(0).max(5),
|
|
1572
1578
|
continuationCount: z.number().int().min(0).max(5),
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
- [`github-collaboration.md`](github-collaboration.md):仓库内 GitHub 协作约定及发布通道。
|
|
10
10
|
- [`version-and-release-management.md`](version-and-release-management.md):版本发布管理——next / release-x.y / latest 渠道、移动式 `npm-next` ref、`inspect next` 查询入口、workflow 与 promote 手册。
|
|
11
11
|
- [`production-readiness.md`](production-readiness.md):交付前的生产就绪判断。
|
|
12
|
+
- [`frontend-reliability-canary-runbook.md`](frontend-reliability-canary-runbook.md):frontend 可靠性修复的 live canary 内网执行手册(协议冻结自 exec-plan §17;配对矩阵、证据注册与人工晋升门)。
|
|
12
13
|
- [`agent-worker-production-readiness.md`](agent-worker-production-readiness.md):agent-worker Feature/Task Pool 外层编排的 Production Readiness v1 操作合同。
|
|
13
14
|
- [`backend-test-jacoco-coverage.md`](backend-test-jacoco-coverage.md):Java 被测服务挂载 JaCoCo tcpserver agent 的 Maven、`java -jar` 与 Docker 操作手册。
|
|
14
15
|
- [`console-chat-dogfood-playbook.md`](console-chat-dogfood-playbook.md):Operator Chat(含 Explore 子 Agent)真实模型 dogfood 的 CLI 驱动步骤、mutation 双 token / SSE 超时 / question 应答等已知陷阱与验证方式。
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
- **DAG 如何消费**:进入 `evidenceGaps[]` 与 Non-goals,`frontend-review-pi`/closeout 据它保留风险与后续项。
|
|
62
62
|
- **缺失/冲突时 fail-closed**:范围与需求非目标冲突、或风险被隐藏时阻塞。
|
|
63
63
|
|
|
64
|
-
## OpenSpec
|
|
64
|
+
## OpenSpec 来源与引用
|
|
65
65
|
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
66
|
+
- Contract 用 `record_openspec_selection` 声明实际使用的 required/relevant 来源,未提及候选不自动升级为 required。
|
|
67
|
+
- Plan 通过 typed tools 引用冻结来源;runtime 从绑定来源与真实读取证据物化引用和 canonical JSON。模型不再输出 JSON 契约块或 `openspec-citations` fence。
|
|
68
|
+
- 来源未绑定、引用不可解析或缺少真实读取背书时,由确定性 gate 阻断;不得伪造读取或引用。
|
|
@@ -115,6 +115,32 @@
|
|
|
115
115
|
"items": {
|
|
116
116
|
"$ref": "#/$defs/path"
|
|
117
117
|
}
|
|
118
|
+
},
|
|
119
|
+
"execution": {
|
|
120
|
+
"type": "object",
|
|
121
|
+
"additionalProperties": false,
|
|
122
|
+
"required": [
|
|
123
|
+
"groupId",
|
|
124
|
+
"kind",
|
|
125
|
+
"summary"
|
|
126
|
+
],
|
|
127
|
+
"properties": {
|
|
128
|
+
"groupId": {
|
|
129
|
+
"type": "string",
|
|
130
|
+
"minLength": 1
|
|
131
|
+
},
|
|
132
|
+
"kind": {
|
|
133
|
+
"enum": [
|
|
134
|
+
"behavior",
|
|
135
|
+
"constraint",
|
|
136
|
+
"exclusion"
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
"summary": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"minLength": 1
|
|
142
|
+
}
|
|
143
|
+
}
|
|
118
144
|
}
|
|
119
145
|
}
|
|
120
146
|
}
|
|
@@ -644,10 +670,16 @@
|
|
|
644
670
|
"allOf": [
|
|
645
671
|
{
|
|
646
672
|
"if": {
|
|
647
|
-
"required": [
|
|
673
|
+
"required": [
|
|
674
|
+
"ledgerPath"
|
|
675
|
+
]
|
|
648
676
|
},
|
|
649
677
|
"then": {
|
|
650
|
-
"required": [
|
|
678
|
+
"required": [
|
|
679
|
+
"ledgerSha256",
|
|
680
|
+
"inputDigest",
|
|
681
|
+
"requirementToFragments"
|
|
682
|
+
]
|
|
651
683
|
}
|
|
652
684
|
}
|
|
653
685
|
],
|
|
@@ -27,17 +27,17 @@
|
|
|
27
27
|
"tasks": [
|
|
28
28
|
{
|
|
29
29
|
"id":"frontend-contract-pi", "depends_on":[], "complexity":"MED", "executor":"pi", "role":"planner", "writePolicy":"read-only", "allowedPaths":["**"], "forbiddenPaths":[".harness/**","artifacts/**"],
|
|
30
|
-
"outputContract":"
|
|
30
|
+
"outputContract":"Incremental Contract typed facts from complete input scopes; complete_contract_scope after all decisions, then one successful finalize_contract. Runtime owns canonical text and source bindings. No file writes.",
|
|
31
31
|
"subtask_prompt":"Read the task inputs. Produce a concise frontend contract that maps each required behavior, UI state, and interaction to observable outcomes. Identify missing or conflicting requirements as blockers; do not infer them and do not edit files."
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"id":"frontend-scout-pi", "depends_on":["frontend-contract-pi"], "complexity":"LOW", "executor":"pi", "role":"scout", "writePolicy":"read-only", "allowedPaths":["REPLACE/WITH/FRONTEND/SOURCE/PATH/**","REPLACE/WITH/FRONTEND/TEST/PATH/**"], "forbiddenPaths":[".harness/**","artifacts/**"],
|
|
35
|
-
"outputContract":"
|
|
35
|
+
"outputContract":"Scout typed target-surface and design-evidence facts backed by fresh read evidence; durable receipts only. No file writes.",
|
|
36
36
|
"subtask_prompt":"Inspect only the declared frontend source and test paths. Report reusable component, styling, accessibility, state-management, and verification patterns that satisfy the contract. Do not edit files or broaden the allowed paths."
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"id":"frontend-plan-pi", "depends_on":["frontend-scout-pi"], "complexity":"MED", "executor":"pi", "role":"planner", "writePolicy":"read-only", "allowedPaths":["REPLACE/WITH/FRONTEND/SOURCE/PATH/**","REPLACE/WITH/FRONTEND/TEST/PATH/**"], "forbiddenPaths":[".harness/**","artifacts/**"],
|
|
40
|
-
"outputContract":"
|
|
40
|
+
"outputContract":"Plan record_* tools for scoped coverage, shared execution groups and UX, one mock endpoint per record, then one successful finalize_plan. Runtime derives canonical JSON and Markdown. No file writes.",
|
|
41
41
|
"subtask_prompt":"Turn the contract and reconnaissance into a minimal implementation plan. Every target file and verification step must be concrete. Preserve existing design and accessibility conventions. If any behavior lacks a verifiable target, report it as blocked instead of guessing."
|
|
42
42
|
},
|
|
43
43
|
{
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"id":"frontend-design-review-pi", "depends_on":["frontend-design-policy-shell"], "complexity":"MED", "executor":"pi", "role":"reviewer", "writePolicy":"read-only", "allowedPaths":["REPLACE/WITH/FRONTEND/SOURCE/PATH/**","REPLACE/WITH/FRONTEND/TEST/PATH/**"], "forbiddenPaths":[".harness/**","artifacts/**"],
|
|
51
|
-
"outputContract":"
|
|
51
|
+
"outputContract":"record_design_finding for individual findings; approve_design or request_design_changes provides the sole committed terminal. Independently review execution-group member differences. No file writes.",
|
|
52
52
|
"subtask_prompt":"Review the approved plan against the frontend contract and design-policy result. Reject missing visible states, interaction behavior, accessibility obligations, or unsupported design claims. Do not edit files."
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"id":"frontend-review-pi", "depends_on":["frontend-review-context-shell"], "complexity":"MED", "executor":"pi", "role":"reviewer", "writePolicy":"read-only", "allowedPaths":["REPLACE/WITH/FRONTEND/TARGET/PATH/**"], "forbiddenPaths":[".harness/**","artifacts/**"],
|
|
79
|
-
"outputContract":"
|
|
79
|
+
"outputContract":"record_review_finding for individual findings; approve_review or request_review_changes provides the sole committed terminal. No file writes.",
|
|
80
80
|
"subtask_prompt":"Review the actual diff and archived verification evidence against the frontend contract. Do not treat missing, weak, mock-only, or not-run evidence as passed. Report explicit residual risks; do not edit files."
|
|
81
81
|
},
|
|
82
82
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tea-agent/loop-agent",
|
|
3
|
-
"version": "0.43.0-next.
|
|
3
|
+
"version": "0.43.0-next.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"loop-agent": "bin/loop-agent.js",
|
|
@@ -78,9 +78,12 @@
|
|
|
78
78
|
"@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
|
|
79
79
|
"@earendil-works/pi-ai": "0.83.0",
|
|
80
80
|
"@earendil-works/pi-coding-agent": "0.83.0",
|
|
81
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
82
|
+
"@xterm/xterm": "^6.0.0",
|
|
81
83
|
"commander": "^12.1.0",
|
|
82
84
|
"katex": "^0.16.47",
|
|
83
85
|
"mermaid": "^11.16.1",
|
|
86
|
+
"node-pty": "^1.2.0-beta.15",
|
|
84
87
|
"rehype-highlight": "^7.0.2",
|
|
85
88
|
"rehype-katex": "^7.0.1",
|
|
86
89
|
"remark-math": "^6.0.0",
|
|
@@ -90,8 +93,8 @@
|
|
|
90
93
|
"zod": "^3.25.76"
|
|
91
94
|
},
|
|
92
95
|
"optionalDependencies": {
|
|
93
|
-
"@
|
|
94
|
-
"@
|
|
96
|
+
"@agent-context/sift": "0.0.1-alpha.7",
|
|
97
|
+
"@cursor/sdk": "^1.0.7"
|
|
95
98
|
},
|
|
96
99
|
"devDependencies": {
|
|
97
100
|
"@remixicon/react": "^4.9.0",
|
|
@@ -15,7 +15,8 @@ language. Do not inspect implementation files or choose components, routes, Mock
|
|
|
15
15
|
mechanisms, dependencies, or target code as requirement facts.
|
|
16
16
|
|
|
17
17
|
Submit confirmed facts incrementally with the contract `record_*` tools and finish
|
|
18
|
-
with
|
|
18
|
+
with one successful `finalize_contract`. Complete each input scope with
|
|
19
|
+
`complete_contract_scope` after all its decisions; correct rejected calls and retry. Start recording as soon as a requirement or
|
|
19
20
|
constraint is confirmed; do not accumulate the whole contract in one response.
|
|
20
21
|
|
|
21
22
|
Missing product semantics may be explicit assumptions only when they do not change
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
source-fidelity ledger. Do not infer fragment IDs from prose.
|
|
9
9
|
- Record observable outcomes, applicable UI states, runtime/environment constraints,
|
|
10
10
|
non-goals, risks, and verification expectations without choosing implementation.
|
|
11
|
-
-
|
|
12
|
-
|
|
11
|
+
- Runtime owns requirement text, source binding and disposition. Use typed questions
|
|
12
|
+
and constraints for uncertainties; blocked terminal facts name their owner.
|
|
13
13
|
|
|
14
14
|
## Evidence and handoff
|
|
15
15
|
|
|
@@ -29,6 +29,22 @@ enumerate or downgrade them.
|
|
|
29
29
|
|
|
30
30
|
## Terminal
|
|
31
31
|
|
|
32
|
-
Commit facts
|
|
32
|
+
Commit facts from the complete current scope, then `complete_contract_scope` only
|
|
33
|
+
after its evidence, constraints and source-bound deliverables are recorded. Scope
|
|
34
|
+
checkpoints survive interruption; confirming an ID alone is not completion.
|
|
35
|
+
Call `finalize_contract` with
|
|
33
36
|
`ready`, `ready-with-assumptions`, or `blocked`. If the task is too large for one
|
|
34
37
|
bounded writer, record a split proposal instead of broadening the contract.
|
|
38
|
+
|
|
39
|
+
A successful receipt means the fact was saved durably. Replays are idempotent;
|
|
40
|
+
changed facts require explicit `replace:true`. Correct rejected calls and retry,
|
|
41
|
+
but do not mutate after a successful terminal. Never drop tail conditions to fit.
|
|
42
|
+
|
|
43
|
+
## Execution ownership
|
|
44
|
+
|
|
45
|
+
`record_requirement` may include `execution:{groupId,kind,summary}`. Use `behavior`,
|
|
46
|
+
`constraint`, or `exclusion`; reuse an existing group only when semantics agree.
|
|
47
|
+
Keep permission, threshold and failure-path differences separate. Do not merge
|
|
48
|
+
source IDs or independent acceptance conditions. Unclassified requirements remain
|
|
49
|
+
independent. Later scopes receive the shared group index. A group is a planning
|
|
50
|
+
proposal; independent design review must check every member's complete text.
|
|
@@ -9,26 +9,27 @@ references:
|
|
|
9
9
|
|
|
10
10
|
# Frontend Design Review
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
capacity diagnostic
|
|
14
|
-
|
|
15
|
-
bound Mock strategy, task bounds, and traceable design evidence supplied by the
|
|
16
|
-
upstream context. Do not rediscover task sources, search specification roots, or
|
|
17
|
-
replace frozen evidence with nearby-code conventions. Use only exact, bound evidence
|
|
18
|
-
paths when additional reading is necessary; never invent connector results.
|
|
12
|
+
Audit the canonical contract or its hash-bound indexed sections, guided by the
|
|
13
|
+
capacity diagnostic. Check Mock strategy, task bounds and exact bound evidence.
|
|
14
|
+
Do not rediscover sources, search specification roots or invent connector results.
|
|
19
15
|
|
|
20
16
|
## Authoritative Terminal
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
Submit findings one at a time with `record_design_finding` using stable IDs.
|
|
19
|
+
Use `replace:true` for revisions. The terminal automatically includes saved findings;
|
|
20
|
+
do not repeat their array. Correct rejected calls, then commit one successful terminal:
|
|
23
21
|
|
|
24
22
|
- `approve_design` when no blocking design defect remains;
|
|
25
23
|
- `request_design_changes` when a blocker exists. It must include a typed
|
|
26
|
-
`issueCategory`, at least one `evidenceRef`, and non-empty findings.
|
|
24
|
+
`issueCategory`, at least one `evidenceRef`, and non-empty findings (saved or supplied).
|
|
27
25
|
|
|
28
26
|
The typed terminal is the only authoritative outcome. Do not require or emit a
|
|
29
27
|
`VERDICT:` line, JSON verdict, revision patch, or a second final-design-review
|
|
30
|
-
verdict.
|
|
31
|
-
|
|
28
|
+
verdict. Requested changes end this run; recovery owns the bounded follow-up.
|
|
29
|
+
|
|
30
|
+
Check every execution group against its members' complete outcomes. Permissions,
|
|
31
|
+
thresholds and error paths remain independent ACs; a shared VT must prove them all.
|
|
32
|
+
Constraint/exclusion labels never waive source-required behavior evidence.
|
|
32
33
|
|
|
33
34
|
## Blocking Conditions
|
|
34
35
|
|