@tea-agent/loop-agent 0.38.1 → 0.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -13
- package/dist/application/dag/generate-task-dag.js +9 -0
- package/dist/build-stamp.json +3 -3
- package/dist/commands/init.js +2 -14
- package/dist/executors/dag-pi-executor.js +41 -4
- package/dist/executors/shell-executor.js +269 -15
- package/dist/governance/manifest-types.js +0 -2
- package/dist/shared/operator/capabilities.js +87 -22
- package/dist/task/config-types.js +22 -0
- package/dist/worker/console/chat/deferred-turn.js +91 -0
- package/dist/worker/console/chat/pi-runtime.js +10 -5
- package/dist/worker/console/chat/routes.js +458 -47
- package/dist/worker/console/chat/semantic-activity.js +13 -13
- package/dist/worker/console/chat/session-store.js +146 -2
- package/dist/worker/console/harness-pi-model-matrix.js +2 -11
- package/dist/worker/console/operator-actions.js +5 -4
- package/dist/worker/console/pi-readiness.js +1 -0
- package/dist/worker/console/recovery-cta.js +4 -4
- package/dist/worker/console/recovery-error-copy.js +4 -4
- package/dist/worker/console/server.js +6 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Hfsot6rP.js → abnfDiagram-N423BO3Z-C4bmo3iY.js} +1 -1
- package/dist/worker/console/static/assets/{arc-YGwEASin.js → arc-SAD7McOS.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CmOM0F92.js → architectureDiagram-T3A2C74G-DAVLUdK1.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-DDLuaHC5.js → blockDiagram-VBNYF7ZC-CPPdv4vj.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B0Um43W4.js → c4Diagram-5PPSVZJV-D1GRGZax.js} +1 -1
- package/dist/worker/console/static/assets/channel-R6oQIDkw.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DvBN4JZc.js → chunk-2GRJ4B5K-D_Bq2ZqK.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-B1UVgW4E.js → chunk-2Q5K7J3B-CPLVtamK.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Cf0GgXzX.js → chunk-5RXB4S5H-DnaZWcL3.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DbNA24sj.js → chunk-5VM5RSS4-BRTmFgnq.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Bi_0Be06.js → chunk-6Q2QTUOP-BRlfYZoH.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C8pPGvRd.js → chunk-GF5L2VYU-CjNybD4u.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BitQY8Z-.js → chunk-JWPE2WC7-D3e-74fG.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-U67GCiEo.js → chunk-KBJHAD2P-Br3ir6f2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-IoJwXPBA.js → chunk-RYQCIY6F-1NgVuRbh.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-YDZ_UHgE.js → chunk-XXDRQBXY-BTYuvuWN.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BPXlmPWI.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BPXlmPWI.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CUZgsiRC.js → cose-bilkent-JH36ORCC-BC6Bgosf.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-COmCh4pT.js → cynefin-VYW2F7L2-DV-HypfL.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Ta6FSm68.js → cynefinDiagram-MW4NZA55-DhTaddO-.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-UdcR-VW9.js → dagre-VZM6K2ZE-BnEcOmiI.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-DybcO3Et.js → diagram-7IWD3JNH-xphGRVKp.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-wErDFWLw.js → diagram-B4RE2ZJO-CrdD1mRG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DkVHZWqz.js → diagram-LBJQPF4R-D4YdLsaF.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DdqWs7QN.js → diagram-Q27KOJAE-LCKyGZ5U.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-C9dMVmDo.js → diagram-UB23O5K3-BeiTe7t0.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-B2T2WcBK.js → ebnfDiagram-BXEA7PRR-BO2cq8GS.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Bt9rjDFq.js → erDiagram-JOGREHBK-CmWww3Nt.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-U8ic_tvi.js → flowDiagram-UKHOOZJN-C2kkUYg5.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BfQJdQoO.js → ganttDiagram-PKOTCBZU-DY_JZ2iQ.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CpMftH4O.js → gitGraphDiagram-DS77QQ5N-BizhCSw9.js} +1 -1
- package/dist/worker/console/static/assets/index-BXN89VPX.js +325 -0
- package/dist/worker/console/static/assets/index-CuH5CNFu.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DzqWXNO_.js → infoDiagram-6WML65LV-Dlo2eK_d.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-CJmGQ5Yp.js → ishikawaDiagram-WSZJBQD7-3EIlIIuZ.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-ChPtKFLz.js → journeyDiagram-NVQOT4AX-DiMDe5Yh.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-PRe7wB5u.js → kanban-definition-27J2QSJJ-sN553oIN.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DpKX6QNp.js → linear-D9Py31Ld.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Dnl76b7Y.js → mermaid.core-D7Occzk_.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-S9PCXc3J.js → mindmap-definition-FAOFIHXS-DjDRboiR.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Du8e-FSX.js → pegDiagram-VL7TDLO6-Cgc4qlzp.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CY6OmHTc.js → pieDiagram-7S7Q4E2Y-DxZj8pKd.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C65GPhpj.js → quadrantDiagram-CIZ2JOQS-CJ50MngR.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-U6IUiTCL.js → railroadDiagram-AXF67PYL-BY-OD8Tr.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D-I_9Qhi.js → requirementDiagram-LRYGKXZP-CQFButfK.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B57Fhed0.js → sankeyDiagram-W5VNT64P-BB_QUK_b.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CJOtiw21.js → sequenceDiagram-SI44F4Z6-CqhXZjyx.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-FyX8zxSh.js → sizeCapture-X5ZJPWSS-2l1U4rgJ.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-eF-pbs9t.js → stateDiagram-OKZ733FA-BX1FbrhJ.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DJKi0Qel.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CcfkA-Dq.js → swimlanes-SLNWSIFB-DOSnT7hb.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-YYe7EEm5.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DH8FjnOK.js → timeline-definition-Z64GVDOM-DVJQA7AN.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-beoTagJg.js → vennDiagram-T6HMQDX7-74uxl9gx.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CQSfw4cK.js → wardleyDiagram-T6FBY63Y-DsBxlcg_.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CQgzQ6jn.js → xychartDiagram-ELKLHX3M-snuW9Mjw.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +0 -12
- package/dist/worker/console/static-src/app/useOperatorActions.js +1 -1
- package/dist/worker/console/static-src/app/useRecoveryActions.js +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +38 -1
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +8 -1
- package/dist/worker/console/static-src/operator-chat/turn-submission.js +42 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +3 -0
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +204 -11
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +23 -1
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +755 -51
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-execution-contract.js +18 -9
- package/dist/workflows/dag/backend-test-gap-fill.js +205 -0
- package/dist/workflows/dag/backend-test-intake-context.js +32 -0
- package/dist/workflows/dag/backend-test-layout.js +133 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +167 -32
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +368 -33
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/backend-test-scenario-param.js +884 -140
- package/dist/workflows/dag/backend-test-scenario-partitions.js +249 -0
- package/dist/workflows/dag/backend-test-writer-completeness.js +100 -56
- package/dist/workflows/dag/contract-validator-registrations.js +2 -1
- package/dist/workflows/dag/convergence/controller.js +141 -0
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +236 -8
- package/dist/workflows/dag/frontend-prewrite-gate.js +95 -35
- package/dist/workflows/dag/init-hybrid.js +652 -87
- package/dist/workflows/dag/node-execution.js +45 -18
- package/dist/workflows/dag/prompt.js +45 -0
- package/dist/workflows/dag/rerun-feedback.js +212 -0
- package/dist/workflows/dag/rerun-plan.js +93 -27
- package/dist/workflows/dag/rerun-run.js +3 -0
- package/dist/workflows/dag/rerun-task.js +61 -2
- package/dist/workflows/dag/retry-policy.js +18 -0
- package/dist/workflows/dag/types.js +98 -0
- package/docs/templates/backend-test-dag.json +60 -35
- package/docs/templates/harness.schema.json +0 -8
- package/harness.json +1 -8
- package/package.json +1 -1
- package/skills/frontend-implementation/references/node-contracts.md +2 -2
- package/dist/worker/console/static/assets/channel-Dp_2Aqf1.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL--CODy37j.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE--CODy37j.js +0 -1
- package/dist/worker/console/static/assets/index-BA5-N5ER.css +0 -1
- package/dist/worker/console/static/assets/index-DKPXBrdc.js +0 -325
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B-mvnLEc.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-JtpBmIv4.js +0 -8
|
@@ -8,6 +8,7 @@ import { analyzeFrontendImplementationContract, writeFrontendImplementationContr
|
|
|
8
8
|
import { renderFrontendPlanMarkdown } from "./frontend-plan-render.js";
|
|
9
9
|
import { captureFrontendWorktreeBaseline } from "./frontend-worktree-diff.js";
|
|
10
10
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
11
|
+
import { normalizeVerdictCandidateLine } from "./dynamic-runtime/shared.js";
|
|
11
12
|
export const FRONTEND_PREWRITE_RESULT_SCHEMA_ID = "frontend-prewrite-result-v1";
|
|
12
13
|
export const FRONTEND_PREWRITE_RESULT_ARTIFACT_NAME = "frontend-prewrite-result.json";
|
|
13
14
|
/** Canonical contract serialization must stay at or below this byte size. */
|
|
@@ -39,6 +40,7 @@ export const frontendPrewriteFailureCodeSchema = z.enum([
|
|
|
39
40
|
"component-spec-not-cited",
|
|
40
41
|
"component-choices-missing",
|
|
41
42
|
"contract-too-large",
|
|
43
|
+
"revision-patch-unmergeable",
|
|
42
44
|
]);
|
|
43
45
|
export const frontendPrewriteResultV1Schema = z
|
|
44
46
|
.object({
|
|
@@ -160,9 +162,12 @@ async function readNodeText(runDir, nodeId) {
|
|
|
160
162
|
if (record.status !== "FINISHED") {
|
|
161
163
|
throw new Error(`frontend prewrite gate requires FINISHED node ${nodeId} (got ${String(record.status)})`);
|
|
162
164
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
// Pi execution mirrors a successful structured-contract normalization into
|
|
166
|
+
// both assistantText and stdout. Treat node output the same way as the DAG
|
|
167
|
+
// runtime's canonicalNodeOutput(): assistantText is authoritative and stdout
|
|
168
|
+
// is only a fallback. Concatenating the two duplicate fields makes a single
|
|
169
|
+
// canonical plan appear as two complete JSON contracts to the prewrite gate.
|
|
170
|
+
const text = record.assistantText?.trim() || record.stdout?.trim() || "";
|
|
166
171
|
if (!text)
|
|
167
172
|
throw new Error(`frontend prewrite gate empty output from ${nodeId}`);
|
|
168
173
|
return text;
|
|
@@ -171,16 +176,53 @@ async function readNodeRawText(runDir, nodeId) {
|
|
|
171
176
|
const record = JSON.parse(await readFile(path.join(runDir, `${nodeId}.json`), "utf8"));
|
|
172
177
|
return record.assistantText ?? record.stdout ?? "";
|
|
173
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Same shape predicate as the internal `isContract` inside
|
|
181
|
+
* `extractFrontendImplementationJson` (frontend-implementation-contract.ts):
|
|
182
|
+
* schemaVersion 1 + a plain `targets` object + `requirements` and
|
|
183
|
+
* `verificationTargets` arrays. A merge-patch delta does not carry these
|
|
184
|
+
* fields, so this is the deterministic boundary between a full contract and a
|
|
185
|
+
* patch. Keep the two predicates in sync.
|
|
186
|
+
*/
|
|
187
|
+
function isFullContractShape(value) {
|
|
188
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
const record = value;
|
|
192
|
+
const targets = record.targets;
|
|
193
|
+
return (record.schemaVersion === 1 &&
|
|
194
|
+
targets !== null &&
|
|
195
|
+
typeof targets === "object" &&
|
|
196
|
+
!Array.isArray(targets) &&
|
|
197
|
+
Array.isArray(record.requirements) &&
|
|
198
|
+
Array.isArray(record.verificationTargets));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Shared merge pipeline for revisionPatch mode and content-driven
|
|
202
|
+
* compatibility: read the original contract node, extract the original
|
|
203
|
+
* contract and the effective node's patch, apply the RFC 7386 merge-patch, and
|
|
204
|
+
* serialize deterministically. Throws on any failure; callers map the error to
|
|
205
|
+
* their own classification (retryable-invalid for explicit revisionPatch mode,
|
|
206
|
+
* blocked for content-driven fallback).
|
|
207
|
+
*/
|
|
208
|
+
async function mergeRevisionPatch(runDir, planText, originalNodeId) {
|
|
209
|
+
const originalText = await readNodeText(runDir, originalNodeId);
|
|
210
|
+
const originalValue = extractFrontendImplementationJson(originalText);
|
|
211
|
+
const patchValue = extractFrontendImplementationJson(planText);
|
|
212
|
+
const merged = applyFrontendImplementationContractPatch(originalValue, patchValue);
|
|
213
|
+
return serializeDeterministicJson(merged);
|
|
214
|
+
}
|
|
174
215
|
function firstNonEmptyVerdictLine(text) {
|
|
175
216
|
const lines = text
|
|
176
217
|
.split(/\r?\n/)
|
|
177
218
|
.map((line) => line.trim())
|
|
178
219
|
.filter(Boolean);
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
220
|
+
// Emphasis stripping (backtick + asterisk) is shared with the runIf
|
|
221
|
+
// selector and node-level output-protocol validation via
|
|
222
|
+
// normalizeVerdictCandidateLine. The gate keeps its own loose
|
|
223
|
+
// pass/request-revision normalization below (prefix match + trailing
|
|
224
|
+
// prose tolerance) for deterministic fail-closed behavior.
|
|
225
|
+
const normalizedLines = lines.map(normalizeVerdictCandidateLine);
|
|
184
226
|
const first = normalizedLines[0] ?? "";
|
|
185
227
|
// The prompt requires VERDICT to be the first non-empty line, but model
|
|
186
228
|
// output can still prepend a summary. Keep the protocol strict in the
|
|
@@ -459,9 +501,8 @@ export async function runFrontendPrewriteGate(input) {
|
|
|
459
501
|
let effectiveContractText = null;
|
|
460
502
|
if (revisionPatchMode) {
|
|
461
503
|
const originalNodeId = input.config.planFallbackFromNodeIds[0];
|
|
462
|
-
let originalText;
|
|
463
504
|
try {
|
|
464
|
-
|
|
505
|
+
effectiveContractText = await mergeRevisionPatch(input.runDir, planText, originalNodeId);
|
|
465
506
|
}
|
|
466
507
|
catch (error) {
|
|
467
508
|
return finalizePrewrite(input, {
|
|
@@ -472,35 +513,54 @@ export async function runFrontendPrewriteGate(input) {
|
|
|
472
513
|
failureCode: "contract-invalid",
|
|
473
514
|
});
|
|
474
515
|
}
|
|
475
|
-
|
|
476
|
-
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
// Content-driven compatibility (Bug 1): legacy DAGs without
|
|
519
|
+
// revisionPatch can still receive a merge-patch delta from the revision
|
|
520
|
+
// node. Detect the output shape instead of trusting the DAG flag alone.
|
|
521
|
+
// - Full contract shape → keep legacy full-contract semantics unchanged.
|
|
522
|
+
// - Patch shape with a usable original contract node → auto-merge and
|
|
523
|
+
// run the existing analysis/materialization pipeline.
|
|
524
|
+
// - Patch shape but unmergeable → blocked + revision-patch-unmergeable
|
|
525
|
+
// (no retryable loop).
|
|
526
|
+
let planJsonValue = null;
|
|
477
527
|
try {
|
|
478
|
-
|
|
479
|
-
patchValue = extractFrontendImplementationJson(planText);
|
|
528
|
+
planJsonValue = extractFrontendImplementationJson(planText);
|
|
480
529
|
}
|
|
481
|
-
catch
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
classification: "retryable-invalid",
|
|
486
|
-
failureReason: `frontend prewrite gate revisionPatch mode failed to parse contract/patch: ${error instanceof Error ? error.message : String(error)}`,
|
|
487
|
-
failureCode: "contract-invalid",
|
|
488
|
-
});
|
|
530
|
+
catch {
|
|
531
|
+
// Not machine-readable JSON: fall back to the legacy full-contract
|
|
532
|
+
// path where analyzeFrontendImplementationContract surfaces the
|
|
533
|
+
// original diagnostic (fail-closed without a new failure mode).
|
|
489
534
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
535
|
+
if (planJsonValue !== null && !isFullContractShape(planJsonValue)) {
|
|
536
|
+
const originalNodeId = input.config.planFallbackFromNodeIds[0];
|
|
537
|
+
if (!originalNodeId || originalNodeId === planNodeId) {
|
|
538
|
+
return finalizePrewrite(input, {
|
|
539
|
+
...basePending,
|
|
540
|
+
verdict,
|
|
541
|
+
classification: "blocked",
|
|
542
|
+
failureReason: "frontend prewrite gate: the effective plan output is a merge-patch delta but no distinct original contract node is available. Check the DAG revisionPatch/planFallbackFromNodeIds configuration or regenerate the DAG.",
|
|
543
|
+
failureCode: "revision-patch-unmergeable",
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
try {
|
|
547
|
+
const originalText = await readNodeText(input.runDir, originalNodeId);
|
|
548
|
+
const originalValue = extractFrontendImplementationJson(originalText);
|
|
549
|
+
if (!isFullContractShape(originalValue)) {
|
|
550
|
+
throw new Error(`original contract node ${originalNodeId} is not a full frontend implementation contract`);
|
|
551
|
+
}
|
|
552
|
+
effectiveContractText = await mergeRevisionPatch(input.runDir, planText, originalNodeId);
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
return finalizePrewrite(input, {
|
|
556
|
+
...basePending,
|
|
557
|
+
verdict,
|
|
558
|
+
classification: "blocked",
|
|
559
|
+
failureReason: `frontend prewrite gate: the effective plan output is a merge-patch delta but it cannot be merged onto the original contract node ${originalNodeId}: ${error instanceof Error ? error.message : String(error)}. Check the DAG revisionPatch/planFallbackFromNodeIds configuration or regenerate the DAG.`,
|
|
560
|
+
failureCode: "revision-patch-unmergeable",
|
|
561
|
+
});
|
|
562
|
+
}
|
|
502
563
|
}
|
|
503
|
-
effectiveContractText = serializeDeterministicJson(merged);
|
|
504
564
|
}
|
|
505
565
|
const requirementIdSearchText = effectiveContractText ?? planText;
|
|
506
566
|
const missingIds = input.config.requiredRequirementIds.filter((id) => !requirementIdSearchText.includes(id));
|