audit-tools 0.30.25 → 0.30.27
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/dist/remediate/contractPipeline/artifactStore.d.ts +7 -0
- package/dist/remediate/contractPipeline/artifactStore.d.ts.map +1 -1
- package/dist/remediate/contractPipeline/artifactStore.js +11 -0
- package/dist/remediate/contractPipeline/artifactStore.js.map +1 -1
- package/dist/remediate/contractPipeline/phaseCut.d.ts +80 -0
- package/dist/remediate/contractPipeline/phaseCut.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/phaseCut.js +184 -0
- package/dist/remediate/contractPipeline/phaseCut.js.map +1 -0
- package/dist/remediate/contractPipeline/phaseCutArtifact.d.ts +31 -0
- package/dist/remediate/contractPipeline/phaseCutArtifact.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/phaseCutArtifact.js +48 -0
- package/dist/remediate/contractPipeline/phaseCutArtifact.js.map +1 -0
- package/dist/remediate/riskSignal.d.ts +16 -0
- package/dist/remediate/riskSignal.d.ts.map +1 -1
- package/dist/remediate/riskSignal.js +4 -0
- package/dist/remediate/riskSignal.js.map +1 -1
- package/dist/remediate/state/types.d.ts +24 -0
- package/dist/remediate/state/types.d.ts.map +1 -1
- package/dist/remediate/state/types.js +9 -0
- package/dist/remediate/state/types.js.map +1 -1
- package/dist/remediate/steps/contractPipeline.d.ts +11 -5
- package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
- package/dist/remediate/steps/contractPipeline.js +215 -29
- package/dist/remediate/steps/contractPipeline.js.map +1 -1
- package/dist/remediate/steps/dispatch.d.ts +17 -0
- package/dist/remediate/steps/dispatch.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch.js +46 -2
- package/dist/remediate/steps/dispatch.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +35 -11
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/package.json +1 -1
|
@@ -30,6 +30,15 @@ export const RemediationBlockSchema = z
|
|
|
30
30
|
* declared surface is a producer bug, not an implicit empty.
|
|
31
31
|
*/
|
|
32
32
|
touched_files: z.array(z.string()),
|
|
33
|
+
/**
|
|
34
|
+
* 0-based foundations→consumers phase ordinal (auto-phasing, T3). Derived
|
|
35
|
+
* mechanically at promotion from the persisted phase cut (the module a block's
|
|
36
|
+
* obligations belong to). The rolling scheduler treats it as a hard barrier: a
|
|
37
|
+
* block never dispatches until every lower-ordinal block is verified-complete,
|
|
38
|
+
* giving a per-phase whole-repo green checkpoint. Optional — absent (or all
|
|
39
|
+
* blocks sharing one ordinal) means a single phase, i.e. no barrier.
|
|
40
|
+
*/
|
|
41
|
+
phase_ordinal: z.number().int().nonnegative().optional(),
|
|
33
42
|
})
|
|
34
43
|
.strict();
|
|
35
44
|
export const RemediationPlanSchema = z
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/remediate/state/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAQtD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGvE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;IAC1B;;;;OAIG;IACH,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC5C;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACjD;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/remediate/state/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,18 @@ import { type ValidationIssue, type JudgeReport, type SessionConfig } from "audi
|
|
|
2
2
|
import type { ContractPipelineArtifactName } from "../contractPipeline/artifactStore.js";
|
|
3
3
|
import type { RemediationStep } from "./types.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Runaway backstop for the judge↔repair loop — the LOUD exception path, NOT the
|
|
6
|
+
* normal terminator. The loop normally terminates by *convergence*: it keeps
|
|
7
|
+
* repairing only while each round surfaces a genuinely NEW accepted counterexample
|
|
8
|
+
* (real progress), reaches a fixpoint when the judge approves, and escalates to the
|
|
9
|
+
* user the moment a round re-accepts an already-addressed counterexample without
|
|
10
|
+
* progress (a stall/oscillation). This ceiling exists only so a pathological run
|
|
11
|
+
* that keeps minting brand-new accepted counterexamples forever cannot loop without
|
|
12
|
+
* bound; hitting it is itself an escalation (loud), never a silent proceed. It is
|
|
13
|
+
* deliberately generous — a genuinely deep but converging design (each round a new
|
|
14
|
+
* real defect) must not be cut mid-convergence (the failure mode of the former N=2).
|
|
9
15
|
*/
|
|
10
|
-
export declare const MAX_CONTRACT_REPAIR_ITERATIONS =
|
|
16
|
+
export declare const MAX_CONTRACT_REPAIR_ITERATIONS = 8;
|
|
11
17
|
/** Maximum implementation_dag regenerations after traceability rejections. */
|
|
12
18
|
export declare const MAX_DAG_REGENERATION_ATTEMPTS = 2;
|
|
13
19
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contractPipeline.d.ts","sourceRoot":"","sources":["../../../src/remediate/steps/contractPipeline.ts"],"names":[],"mappings":"AAwBA,OAAO,EAOL,KAAK,eAAe,EACpB,KAAK,WAAW,EAIhB,KAAK,aAAa,EAEnB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"contractPipeline.d.ts","sourceRoot":"","sources":["../../../src/remediate/steps/contractPipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,8 +23,10 @@ import { existsSync } from "node:fs";
|
|
|
23
23
|
import { mkdir, rename } from "node:fs/promises";
|
|
24
24
|
import { join } from "node:path";
|
|
25
25
|
import { writeJsonFile, readOptionalJsonFile, formatValidationIssues, hashContent, isRecord, withFsRetry, captureStepBoundaryFriction, } from "audit-tools/shared";
|
|
26
|
-
import { CP_ARTIFACT_NAMES, contractArtifactExists, contractArtifactFilePath, contractPipelineDir, detectStaleArtifacts, isEnvelope, pathASeedFilePath, readContractArtifact, writeContractArtifact, } from "../contractPipeline/artifactStore.js";
|
|
27
|
-
import { readIntakeRiskSignal, writeIntakeRiskSignal, escalateRiskSignal, decompositionRiskEvidence, adversarialDepthForTier, } from "../riskSignal.js";
|
|
26
|
+
import { CP_ARTIFACT_NAMES, contractArtifactExists, contractArtifactFilePath, contractPipelineDir, detectStaleArtifacts, envelopePayload, isEnvelope, pathASeedFilePath, readContractArtifact, writeContractArtifact, } from "../contractPipeline/artifactStore.js";
|
|
27
|
+
import { readIntakeRiskSignal, writeIntakeRiskSignal, escalateRiskSignal, decompositionRiskEvidence, adversarialDepthForTier, roundTripGranularityForTier, } from "../riskSignal.js";
|
|
28
|
+
import { phaseOrdinalForObligations, moduleSlug, renderPhaseCutSection, } from "../contractPipeline/phaseCut.js";
|
|
29
|
+
import { ensurePhaseCutArtifact, readPhaseCutArtifact } from "../contractPipeline/phaseCutArtifact.js";
|
|
28
30
|
import { detectCyclicSeamObligations, validateCycleBreak, } from "../contractPipeline/cyclicSeamResolution.js";
|
|
29
31
|
import { deriveObligationLedger, buildTestValidatorPlanScaffold, buildImplementationDagScaffold, acceptedCounterexampleIds, } from "../contractPipeline/derive.js";
|
|
30
32
|
import { ensureNodeId, toBlockId } from "../contractPipeline/idRegistry.js";
|
|
@@ -60,14 +62,39 @@ const ARTIFACT_TO_PHASE = {
|
|
|
60
62
|
// ── Phase → step kind mapping ──────────────────────────────────────────────────
|
|
61
63
|
const CONTRACT_STEP_KIND = "contract_pipeline";
|
|
62
64
|
const PRE_IMPLEMENTATION_PHASE_ORDER = CONTRACT_PIPELINE_PHASE_ORDER.filter((phase) => phase !== "closing");
|
|
65
|
+
/**
|
|
66
|
+
* Granularity collapse group (T1 slice 4b). The framing phases — goal, context,
|
|
67
|
+
* decomposition — are ONE coherent act of authoring (scope the change top-down):
|
|
68
|
+
* they carry no adversarial judgment and no deterministic derivation interleaves
|
|
69
|
+
* them, so for low-complexity work they fold into a single round-trip producing
|
|
70
|
+
* all three artifacts instead of three gated steps. The group deliberately STOPS
|
|
71
|
+
* at decomposition (before module_contract_drafting): keeping the decomposition→
|
|
72
|
+
* drafting boundary lets the slice-4a escalate-on-evidence intercept inspect the
|
|
73
|
+
* fresh decomposition and raise the tier — un-collapsing every remaining phase —
|
|
74
|
+
* before any contract is drafted or the per-module wave fans out. Collapse is
|
|
75
|
+
* best-effort: any member artifact the worker omits or writes malformed is
|
|
76
|
+
* re-emitted as its own fine-grained step by `nextMissingContractPhase`, so no
|
|
77
|
+
* work is ever lost. See `roundTripGranularityForTier`.
|
|
78
|
+
*/
|
|
79
|
+
const FRAMING_COLLAPSE_GROUP = [
|
|
80
|
+
"goal_normalization",
|
|
81
|
+
"context_collection",
|
|
82
|
+
"decomposition",
|
|
83
|
+
];
|
|
63
84
|
// ── Bounded-loop caps ─────────────────────────────────────────────────────────
|
|
64
85
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
86
|
+
* Runaway backstop for the judge↔repair loop — the LOUD exception path, NOT the
|
|
87
|
+
* normal terminator. The loop normally terminates by *convergence*: it keeps
|
|
88
|
+
* repairing only while each round surfaces a genuinely NEW accepted counterexample
|
|
89
|
+
* (real progress), reaches a fixpoint when the judge approves, and escalates to the
|
|
90
|
+
* user the moment a round re-accepts an already-addressed counterexample without
|
|
91
|
+
* progress (a stall/oscillation). This ceiling exists only so a pathological run
|
|
92
|
+
* that keeps minting brand-new accepted counterexamples forever cannot loop without
|
|
93
|
+
* bound; hitting it is itself an escalation (loud), never a silent proceed. It is
|
|
94
|
+
* deliberately generous — a genuinely deep but converging design (each round a new
|
|
95
|
+
* real defect) must not be cut mid-convergence (the failure mode of the former N=2).
|
|
69
96
|
*/
|
|
70
|
-
export const MAX_CONTRACT_REPAIR_ITERATIONS =
|
|
97
|
+
export const MAX_CONTRACT_REPAIR_ITERATIONS = 8;
|
|
71
98
|
/** Maximum implementation_dag regenerations after traceability rejections. */
|
|
72
99
|
export const MAX_DAG_REGENERATION_ATTEMPTS = 2;
|
|
73
100
|
/**
|
|
@@ -106,12 +133,6 @@ export async function writeCyclicSeamRepairState(artifactsDir, state) {
|
|
|
106
133
|
await writeJsonFile(cyclicSeamRepairStatePath(artifactsDir), state);
|
|
107
134
|
}
|
|
108
135
|
// ── Envelope handling ─────────────────────────────────────────────────────────
|
|
109
|
-
/** Payload of a stored artifact whether or not it has been enveloped yet. */
|
|
110
|
-
function envelopePayload(envelope) {
|
|
111
|
-
if (!envelope)
|
|
112
|
-
return undefined;
|
|
113
|
-
return isEnvelope(envelope) ? envelope.payload : envelope;
|
|
114
|
-
}
|
|
115
136
|
/**
|
|
116
137
|
* Render a pre-filled skeleton section (S3 scaffold) for the partially-derivable
|
|
117
138
|
* phases. The tool derives the structure/ids/cross-refs from the already-present
|
|
@@ -318,11 +339,26 @@ function inferRepairDirective(judge) {
|
|
|
318
339
|
instruction: "Address every judge-accepted counterexample in the judge report's classifications.",
|
|
319
340
|
};
|
|
320
341
|
}
|
|
342
|
+
/** Judge-accepted counterexample ids from a judge report's classifications. */
|
|
343
|
+
function acceptedCeIdsOf(judge) {
|
|
344
|
+
return (judge?.classifications ?? [])
|
|
345
|
+
.filter((c) => c.classification === "accepted")
|
|
346
|
+
.map((c) => c.counterexample_id);
|
|
347
|
+
}
|
|
321
348
|
/**
|
|
322
|
-
* Decide whether implementation planning may proceed
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
349
|
+
* Decide whether implementation planning may proceed. Convergence-terminated,
|
|
350
|
+
* NOT capped at an arbitrary count:
|
|
351
|
+
* - approved verdict ⇒ proceed (the fixpoint);
|
|
352
|
+
* - a needs_repair verdict that surfaces a NEW accepted counterexample (one not
|
|
353
|
+
* already addressed by a prior repair) ⇒ repair (genuine progress);
|
|
354
|
+
* - a needs_repair verdict whose accepted counterexamples were ALL already
|
|
355
|
+
* addressed ⇒ escalate (stall/oscillation — the repair loop is not converging,
|
|
356
|
+
* surface the outstanding counterexamples to the user instead of silently
|
|
357
|
+
* shipping residual risk or looping);
|
|
358
|
+
* - the runaway backstop (MAX_CONTRACT_REPAIR_ITERATIONS) ⇒ escalate (loud).
|
|
359
|
+
* The former fixed N=2 cap that proceeded-with-residual-risk at an arbitrary count
|
|
360
|
+
* is gone: a deep-but-converging run is no longer cut mid-convergence, and a
|
|
361
|
+
* genuinely non-converging run is surfaced rather than buried.
|
|
326
362
|
*/
|
|
327
363
|
async function evaluateJudgeGate(artifactsDir) {
|
|
328
364
|
const judgeEnvelope = await readContractArtifact(artifactsDir, "judge_report");
|
|
@@ -334,12 +370,6 @@ async function evaluateJudgeGate(artifactsDir) {
|
|
|
334
370
|
const repairState = await readRepairState(artifactsDir);
|
|
335
371
|
const judgeHash = judgeEnvelope.content_hash;
|
|
336
372
|
const alreadyHandled = repairState.repairs.some((repair) => repair.judge_hash === judgeHash);
|
|
337
|
-
if (!alreadyHandled && repairState.repairs.length >= MAX_CONTRACT_REPAIR_ITERATIONS) {
|
|
338
|
-
return {
|
|
339
|
-
kind: "proceed_residual",
|
|
340
|
-
note: `The judge verdict remains "needs_repair" after ${repairState.repairs.length} repair iteration(s) (the cap). Proceed anyway: treat every judge-accepted counterexample that remains unaddressed as a residual risk, and cover each one with an implementation or verification node.`,
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
373
|
// Map judge.repair_directive.target if present; if absent, infer from classifications.
|
|
344
374
|
const rawDirective = judge.repair_directive;
|
|
345
375
|
const directive = rawDirective
|
|
@@ -350,7 +380,36 @@ async function evaluateJudgeGate(artifactsDir) {
|
|
|
350
380
|
instruction: rawDirective.instruction,
|
|
351
381
|
}
|
|
352
382
|
: inferRepairDirective(judge);
|
|
353
|
-
|
|
383
|
+
const acceptedIds = acceptedCeIdsOf(judge);
|
|
384
|
+
const addressed = new Set(repairState.repairs.flatMap((r) => r.accepted_ce_ids ?? []));
|
|
385
|
+
const newAccepted = acceptedIds.filter((id) => !addressed.has(id));
|
|
386
|
+
// Idempotent re-entry: this exact judge report already drove a repair (its hash
|
|
387
|
+
// is recorded). Re-emit the same repair directive; do not re-evaluate convergence
|
|
388
|
+
// (the repair has not yet produced a fresh judge report).
|
|
389
|
+
if (alreadyHandled) {
|
|
390
|
+
return { kind: "repair", directive, judgeHash, acceptedCeIds: newAccepted };
|
|
391
|
+
}
|
|
392
|
+
// Runaway backstop (loud) — the exception path, not the normal terminator.
|
|
393
|
+
if (repairState.repairs.length >= MAX_CONTRACT_REPAIR_ITERATIONS) {
|
|
394
|
+
return {
|
|
395
|
+
kind: "escalate",
|
|
396
|
+
reason: "runaway",
|
|
397
|
+
outstanding: acceptedIds,
|
|
398
|
+
note: `The judge↔repair loop reached its runaway backstop (${repairState.repairs.length} repair rounds) without converging. Each round was still surfacing accepted counterexamples. This is pathological non-convergence — review the outstanding counterexamples and the contract design with the user before proceeding.`,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
// Progress: a new accepted counterexample (or the first round) ⇒ repair.
|
|
402
|
+
if (repairState.repairs.length === 0 || newAccepted.length > 0) {
|
|
403
|
+
return { kind: "repair", directive, judgeHash, acceptedCeIds: newAccepted };
|
|
404
|
+
}
|
|
405
|
+
// Stall: a needs_repair verdict whose every accepted counterexample was already
|
|
406
|
+
// addressed by a prior repair ⇒ the loop is not converging ⇒ escalate.
|
|
407
|
+
return {
|
|
408
|
+
kind: "escalate",
|
|
409
|
+
reason: "stall",
|
|
410
|
+
outstanding: acceptedIds,
|
|
411
|
+
note: `The judge re-accepted counterexample(s) that a prior repair already addressed (${acceptedIds.join(", ") || "none newly accepted"}), with no new accepted counterexample this round. The repair loop is not converging on these items. Resolve them with the user — adjust the contract design or accept the counterexamples as known limitations — before the plan can be promoted.`,
|
|
412
|
+
};
|
|
354
413
|
}
|
|
355
414
|
/**
|
|
356
415
|
* The traceability invariant: no implementation_dag node may exist without
|
|
@@ -777,6 +836,45 @@ After writing the output file, run:
|
|
|
777
836
|
stopCondition: `Stop after writing the contract-pipeline output for phase "${phase}" and running next-step.`,
|
|
778
837
|
});
|
|
779
838
|
};
|
|
839
|
+
// T1 slice 4b: emit ONE round-trip whose prompt concatenates the rendered
|
|
840
|
+
// specs of several consecutive authoring phases. The worker writes every
|
|
841
|
+
// named artifact top-down (each later phase's inputs are the files it wrote in
|
|
842
|
+
// the earlier sections of the same round-trip), then runs next-step once. The
|
|
843
|
+
// group header overrides the per-section "stop after writing" lines so they are
|
|
844
|
+
// not read as three separate stop points.
|
|
845
|
+
const buildCollapsedFramingStep = (phases) => {
|
|
846
|
+
const sections = phases.map((phase) => {
|
|
847
|
+
const rendered = renderContractPipelinePrompt({
|
|
848
|
+
role: phase,
|
|
849
|
+
artifactPaths,
|
|
850
|
+
sourcePaths,
|
|
851
|
+
repoRoot: root,
|
|
852
|
+
pathASeedPath,
|
|
853
|
+
hostCanDispatchSubagents: options.hostCanDispatchSubagents,
|
|
854
|
+
adversarialDepth,
|
|
855
|
+
});
|
|
856
|
+
return { phase, rendered };
|
|
857
|
+
});
|
|
858
|
+
const outputPaths = sections.map((s) => s.rendered.outputPath);
|
|
859
|
+
const header = `# Collapsed Authoring Round-Trip — ${phases.length} Phases
|
|
860
|
+
|
|
861
|
+
This is a low-complexity change, so these ${phases.length} coherent authoring phases are combined into a SINGLE round-trip. Complete EVERY section below — author them top-down, writing each artifact to its named path (each later section's inputs are the files you write in the earlier sections of this same round-trip). Then run next-step ONCE.
|
|
862
|
+
|
|
863
|
+
Treat any per-section "Stop after writing the output file / do not advance" instruction as scoped to that section only — it does NOT mean stop the round-trip. Finish all sections first.
|
|
864
|
+
|
|
865
|
+
If you cannot complete a section (an artifact would be malformed), write the ones you can and run next-step: the pipeline re-emits any missing or invalid artifact as its own fine-grained step, so no work is lost.
|
|
866
|
+
|
|
867
|
+
Artifacts to produce (in order):
|
|
868
|
+
${outputPaths.map((p, i) => `${i + 1}. \`${p}\` (${phases[i]})`).join("\n")}`;
|
|
869
|
+
const body = sections
|
|
870
|
+
.map((s) => `\n---\n\n${s.rendered.prompt}`)
|
|
871
|
+
.join("\n");
|
|
872
|
+
return buildStep({
|
|
873
|
+
prompt: `${header}\n${body}`,
|
|
874
|
+
outputPath: outputPaths[outputPaths.length - 1],
|
|
875
|
+
stopCondition: `Stop after writing all ${phases.length} collapsed-framing artifacts (${phases.join(", ")}) and running next-step once.`,
|
|
876
|
+
});
|
|
877
|
+
};
|
|
780
878
|
const buildParallelModuleWaveStep = async (phase) => {
|
|
781
879
|
// DC-3: fan the phase out to ONE agent per module, concurrency-capped by the
|
|
782
880
|
// shared wave scheduler (the same quota/host machinery implement dispatch
|
|
@@ -1061,8 +1159,10 @@ ${rejectionRewriteInstruction(archived.archivedPath)}`);
|
|
|
1061
1159
|
return buildNextContractPipelineStep(options);
|
|
1062
1160
|
}
|
|
1063
1161
|
}
|
|
1064
|
-
// 3. Judge gate: implementation planning is reachable only through an
|
|
1065
|
-
//
|
|
1162
|
+
// 3. Judge gate: implementation planning is reachable only through an approved
|
|
1163
|
+
// verdict (the fixpoint) or a convergent targeted repair. A stalled /
|
|
1164
|
+
// non-converging repair loop escalates to the user (blocked) instead of
|
|
1165
|
+
// silently proceeding with residual risk.
|
|
1066
1166
|
if (nextPhase === "implementation_planning") {
|
|
1067
1167
|
const gate = await evaluateJudgeGate(artifactsDir);
|
|
1068
1168
|
if (gate.kind === "repair") {
|
|
@@ -1073,6 +1173,7 @@ ${rejectionRewriteInstruction(archived.archivedPath)}`);
|
|
|
1073
1173
|
judge_hash: gate.judgeHash,
|
|
1074
1174
|
target: repairTarget,
|
|
1075
1175
|
at: new Date().toISOString(),
|
|
1176
|
+
accepted_ce_ids: gate.acceptedCeIds,
|
|
1076
1177
|
});
|
|
1077
1178
|
await writeRepairState(artifactsDir, repairState);
|
|
1078
1179
|
}
|
|
@@ -1088,11 +1189,37 @@ ${rejectionRewriteInstruction(archived.archivedPath)}`);
|
|
|
1088
1189
|
stopCondition: `Stop after rewriting "${repairTarget}" per the judge repair directive and running next-step.`,
|
|
1089
1190
|
});
|
|
1090
1191
|
}
|
|
1091
|
-
if (gate.kind === "
|
|
1092
|
-
|
|
1192
|
+
if (gate.kind === "escalate") {
|
|
1193
|
+
// Non-convergence (stall or runaway backstop): surface it to the user
|
|
1194
|
+
// loudly rather than promoting a plan over an un-converged contract. The
|
|
1195
|
+
// outstanding accepted counterexamples are named so the user can resolve
|
|
1196
|
+
// them (revise the contract design or accept them as known limitations).
|
|
1197
|
+
await captureStepBoundaryFriction(artifactsDir, runId, {
|
|
1198
|
+
eventType: "repair_round",
|
|
1199
|
+
discriminator: `judge_nonconvergence:${gate.reason}`,
|
|
1200
|
+
note: `Judge↔repair loop escalated (${gate.reason}): ${gate.note}`,
|
|
1201
|
+
category: "trap",
|
|
1202
|
+
}, "remediate-code");
|
|
1203
|
+
return writeCurrentStep({
|
|
1204
|
+
stepKind: CONTRACT_STEP_KIND,
|
|
1205
|
+
status: "blocked",
|
|
1206
|
+
runId,
|
|
1207
|
+
repoRoot: root,
|
|
1208
|
+
artifactsDir,
|
|
1209
|
+
prompt: `# Judge↔Repair Loop Did Not Converge
|
|
1093
1210
|
|
|
1094
1211
|
${gate.note}
|
|
1095
|
-
|
|
1212
|
+
|
|
1213
|
+
## Outstanding accepted counterexamples
|
|
1214
|
+
|
|
1215
|
+
${gate.outstanding.length > 0
|
|
1216
|
+
? gate.outstanding.map((id) => `- ${id}`).join("\n")
|
|
1217
|
+
: "_(none newly accepted this round)_"}
|
|
1218
|
+
|
|
1219
|
+
Read the judge_report and counterexample artifacts, decide with the user how to resolve each outstanding counterexample (revise the contract design and re-run, or accept it as a known limitation), then re-run next-step.`,
|
|
1220
|
+
allowedCommands: [],
|
|
1221
|
+
stopCondition: "Stop — the contract pipeline is blocked on a non-converging judge↔repair loop pending a user decision.",
|
|
1222
|
+
});
|
|
1096
1223
|
}
|
|
1097
1224
|
// gate.kind === "proceed": fall through to the normal phase step below.
|
|
1098
1225
|
}
|
|
@@ -1601,6 +1728,39 @@ ${preCriticCitationGate.errorLines.join("\n")}
|
|
|
1601
1728
|
}
|
|
1602
1729
|
return buildParallelModuleWaveStep(nextPhase);
|
|
1603
1730
|
}
|
|
1731
|
+
// Auto-phasing (T3): at the conceptual-design critique, hand the critic the
|
|
1732
|
+
// tool-DERIVED phase cut so it assesses design quality WITHIN a mechanically
|
|
1733
|
+
// dependency-ordered foundations→consumers phasing, instead of rejecting an
|
|
1734
|
+
// arbitrary N-goal change as "over-scoped" and forcing the host to re-scope by
|
|
1735
|
+
// hand at intake. The cut is derived deterministically from the finalized module
|
|
1736
|
+
// contracts' directional neighbor_needs edges (present by the critique phase) and
|
|
1737
|
+
// PERSISTED as the `phase_cut.json` sidecar here, so the cut the critic sees and
|
|
1738
|
+
// the cut the implementation-DAG promotion enforces are one source. Only injected
|
|
1739
|
+
// into the prompt when there is a genuine multi-phase cut to communicate.
|
|
1740
|
+
if (nextPhase === "critique") {
|
|
1741
|
+
const cut = await ensurePhaseCutArtifact(artifactsDir);
|
|
1742
|
+
if (cut && cut.phases.length > 1) {
|
|
1743
|
+
const reReview = await buildReReviewSection(nextPhase, artifactsDir);
|
|
1744
|
+
const phaseCutSection = renderPhaseCutSection(cut);
|
|
1745
|
+
return buildPhaseStep("critique", reReview ? `${phaseCutSection}\n${reReview}` : phaseCutSection);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
// Granularity collapse (T1 slice 4b): for low-complexity work, fold the framing
|
|
1749
|
+
// suffix [nextPhase..decomposition] into ONE round-trip producing several
|
|
1750
|
+
// artifacts, instead of one gated step per phase. Reads the POST-escalation
|
|
1751
|
+
// riskSignal (slice 4a may have already raised the tier above), so the dial is
|
|
1752
|
+
// never frozen at run start — `fine` for medium/high keeps full per-phase
|
|
1753
|
+
// isolation. Only collapses a genuine multi-phase suffix; a single trailing
|
|
1754
|
+
// framing phase falls through to the normal per-phase dispatch below.
|
|
1755
|
+
if (nextPhase &&
|
|
1756
|
+
roundTripGranularityForTier(riskSignal?.tier) === "collapsed" &&
|
|
1757
|
+
FRAMING_COLLAPSE_GROUP.includes(nextPhase)) {
|
|
1758
|
+
const startIdx = FRAMING_COLLAPSE_GROUP.indexOf(nextPhase);
|
|
1759
|
+
const suffix = FRAMING_COLLAPSE_GROUP.slice(startIdx);
|
|
1760
|
+
if (suffix.length > 1) {
|
|
1761
|
+
return buildCollapsedFramingStep([...suffix]);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1604
1764
|
// Skeleton-scaffolded phases (S3): the tool pre-fills structure/ids from the
|
|
1605
1765
|
// derived obligation ledger so the worker fills only the judgment slots.
|
|
1606
1766
|
if (nextPhase === "test_validator_plan" || nextPhase === "implementation_planning") {
|
|
@@ -1683,6 +1843,22 @@ export async function promoteImplementationDagToExtractedPlan(artifactsDir) {
|
|
|
1683
1843
|
obligationMap.set(obl.id, obl.kind);
|
|
1684
1844
|
}
|
|
1685
1845
|
}
|
|
1846
|
+
// Auto-phasing (T3): read the persisted phase cut and re-key its module-phase
|
|
1847
|
+
// map by `moduleSlug(name)` — the fragment the obligation ledger encodes into
|
|
1848
|
+
// `OBL-<slug>-…` ids. The block phase ordinal is then derived MECHANICALLY from
|
|
1849
|
+
// each node's obligations (never trusting a worker-carried field, which a node
|
|
1850
|
+
// merge could drop), so a foundation block always sorts below the consumers that
|
|
1851
|
+
// depend on it. Absent cut (single module / no finalized contracts) → no
|
|
1852
|
+
// ordinals, i.e. one phase, no barrier.
|
|
1853
|
+
const phaseCut = await readPhaseCutArtifact(artifactsDir);
|
|
1854
|
+
const slugToOrdinal = new Map();
|
|
1855
|
+
if (phaseCut) {
|
|
1856
|
+
for (const [name, ordinal] of Object.entries(phaseCut.module_phase)) {
|
|
1857
|
+
slugToOrdinal.set(moduleSlug(name), ordinal);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
const lastOrdinal = Math.max(0, ...slugToOrdinal.values());
|
|
1861
|
+
const hasMultiPhase = phaseCut ? phaseCut.phases.length > 1 : false;
|
|
1686
1862
|
const nodes = Array.isArray(dag?.nodes) ? dag.nodes : [];
|
|
1687
1863
|
const findings = nodes.map((node, index) => {
|
|
1688
1864
|
const id = ensureNodeId(node.id, index);
|
|
@@ -1755,6 +1931,15 @@ export async function promoteImplementationDagToExtractedPlan(artifactsDir) {
|
|
|
1755
1931
|
const touchedFiles = [
|
|
1756
1932
|
...new Set(node.output_files ?? node.files_likely_touched ?? []),
|
|
1757
1933
|
];
|
|
1934
|
+
// Phase ordinal from the union of this node's obligations (max → fail-toward-
|
|
1935
|
+
// later). Only stamped when there is a genuine multi-phase cut, so a single-
|
|
1936
|
+
// phase change carries no ordinal and the scheduler runs no barrier.
|
|
1937
|
+
const phaseOrdinal = hasMultiPhase
|
|
1938
|
+
? phaseOrdinalForObligations([
|
|
1939
|
+
...(node.satisfies_obligations ?? []),
|
|
1940
|
+
...(node.verification_obligation_ids ?? []),
|
|
1941
|
+
], slugToOrdinal, lastOrdinal)
|
|
1942
|
+
: undefined;
|
|
1758
1943
|
return {
|
|
1759
1944
|
block_id: toBlockId(nodeId),
|
|
1760
1945
|
items: [nodeId],
|
|
@@ -1765,6 +1950,7 @@ export async function promoteImplementationDagToExtractedPlan(artifactsDir) {
|
|
|
1765
1950
|
// touched_files is REQUIRED on the block contract; promote the node's
|
|
1766
1951
|
// declared write scope so the file-ownership scheduler can read it.
|
|
1767
1952
|
touched_files: touchedFiles,
|
|
1953
|
+
...(phaseOrdinal !== undefined ? { phase_ordinal: phaseOrdinal } : {}),
|
|
1768
1954
|
...(node.targeted_commands && node.targeted_commands.length > 0
|
|
1769
1955
|
? { targeted_commands: [...node.targeted_commands] }
|
|
1770
1956
|
: {}),
|