audit-tools 0.42.1 → 0.44.0
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/dispatch/merge-results.mjs +229 -140
- package/dispatch/validate-result.mjs +98 -40
- package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
- package/dist/audit/cli/conceptualDispatch.js +35 -3
- package/dist/audit/cli/conceptualDispatch.js.map +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.d.ts +9 -1
- package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.js +94 -38
- package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
- package/dist/audit/cli/laneSubmissions.d.ts +2 -2
- package/dist/audit/cli/laneSubmissions.js +2 -2
- package/dist/audit/cli/nextStepCommand.d.ts +64 -0
- package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
- package/dist/audit/cli/nextStepCommand.js +877 -783
- package/dist/audit/cli/nextStepCommand.js.map +1 -1
- package/dist/audit/cli/nextStepHelpers.d.ts +12 -36
- package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
- package/dist/audit/cli/nextStepHelpers.js +34 -77
- package/dist/audit/cli/nextStepHelpers.js.map +1 -1
- package/dist/audit/cli/steps.d.ts +2 -2
- package/dist/audit/extractors/graph.d.ts +28 -2
- package/dist/audit/extractors/graph.d.ts.map +1 -1
- package/dist/audit/extractors/graph.js +122 -11
- package/dist/audit/extractors/graph.js.map +1 -1
- package/dist/audit/extractors/graphRoutes.d.ts +8 -0
- package/dist/audit/extractors/graphRoutes.d.ts.map +1 -1
- package/dist/audit/extractors/graphRoutes.js +71 -4
- package/dist/audit/extractors/graphRoutes.js.map +1 -1
- package/dist/audit/io/artifacts.d.ts +55 -0
- package/dist/audit/io/artifacts.d.ts.map +1 -1
- package/dist/audit/io/artifacts.js +189 -12
- package/dist/audit/io/artifacts.js.map +1 -1
- package/dist/audit/io/toolingManifest.d.ts +11 -0
- package/dist/audit/io/toolingManifest.d.ts.map +1 -1
- package/dist/audit/io/toolingManifest.js +13 -3
- package/dist/audit/io/toolingManifest.js.map +1 -1
- package/dist/audit/orchestrator/advance.d.ts +64 -0
- package/dist/audit/orchestrator/advance.d.ts.map +1 -1
- package/dist/audit/orchestrator/advance.js +191 -57
- package/dist/audit/orchestrator/advance.js.map +1 -1
- package/dist/audit/orchestrator/charterClarificationExecutor.d.ts.map +1 -1
- package/dist/audit/orchestrator/charterClarificationExecutor.js +55 -21
- package/dist/audit/orchestrator/charterClarificationExecutor.js.map +1 -1
- package/dist/audit/orchestrator/flowCoverage.d.ts.map +1 -1
- package/dist/audit/orchestrator/flowCoverage.js +7 -10
- package/dist/audit/orchestrator/flowCoverage.js.map +1 -1
- package/dist/audit/orchestrator/flowPlanning.d.ts +54 -1
- package/dist/audit/orchestrator/flowPlanning.d.ts.map +1 -1
- package/dist/audit/orchestrator/flowPlanning.js +77 -18
- package/dist/audit/orchestrator/flowPlanning.js.map +1 -1
- package/dist/audit/orchestrator/flowRequeue.d.ts.map +1 -1
- package/dist/audit/orchestrator/flowRequeue.js +6 -10
- package/dist/audit/orchestrator/flowRequeue.js.map +1 -1
- package/dist/audit/orchestrator/requeueFold.d.ts.map +1 -1
- package/dist/audit/orchestrator/requeueFold.js +18 -5
- package/dist/audit/orchestrator/requeueFold.js.map +1 -1
- package/dist/audit/orchestrator/staleness.d.ts +24 -1
- package/dist/audit/orchestrator/staleness.d.ts.map +1 -1
- package/dist/audit/orchestrator/staleness.js +147 -16
- package/dist/audit/orchestrator/staleness.js.map +1 -1
- package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts +26 -0
- package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts.map +1 -1
- package/dist/audit/orchestrator/syntaxResolutionExecutor.js +97 -12
- package/dist/audit/orchestrator/syntaxResolutionExecutor.js.map +1 -1
- package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -1
- package/dist/audit/orchestrator/taskBuilder.js +111 -21
- package/dist/audit/orchestrator/taskBuilder.js.map +1 -1
- package/dist/audit/orchestrator/trivialAudit.d.ts +17 -1
- package/dist/audit/orchestrator/trivialAudit.d.ts.map +1 -1
- package/dist/audit/orchestrator/trivialAudit.js +31 -4
- package/dist/audit/orchestrator/trivialAudit.js.map +1 -1
- package/dist/audit/types/analyzerCapability.d.ts +6 -6
- package/dist/audit/types/charterRegister.d.ts +30 -12
- package/dist/audit/types/charterRegister.d.ts.map +1 -1
- package/dist/audit/types/charterRegister.js +22 -9
- package/dist/audit/types/charterRegister.js.map +1 -1
- package/dist/audit/validation/anchorGrounding.d.ts.map +1 -1
- package/dist/audit/validation/anchorGrounding.js +17 -0
- package/dist/audit/validation/anchorGrounding.js.map +1 -1
- package/dist/audit/validation/auditResults.d.ts +17 -0
- package/dist/audit/validation/auditResults.d.ts.map +1 -1
- package/dist/audit/validation/auditResults.js +50 -17
- package/dist/audit/validation/auditResults.js.map +1 -1
- package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts +48 -0
- package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts.map +1 -1
- package/dist/remediate/contractPipeline/cyclicSeamResolution.js +128 -0
- package/dist/remediate/contractPipeline/cyclicSeamResolution.js.map +1 -1
- package/dist/remediate/contractPipeline/derive.d.ts +8 -5
- package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
- package/dist/remediate/contractPipeline/derive.js +8 -16
- package/dist/remediate/contractPipeline/derive.js.map +1 -1
- package/dist/remediate/index.d.ts.map +1 -1
- package/dist/remediate/index.js +43 -2
- package/dist/remediate/index.js.map +1 -1
- package/dist/remediate/intent/intentOrdering.d.ts +13 -5
- package/dist/remediate/intent/intentOrdering.d.ts.map +1 -1
- package/dist/remediate/intent/intentOrdering.js +56 -25
- package/dist/remediate/intent/intentOrdering.js.map +1 -1
- package/dist/remediate/phases/close.d.ts +57 -2
- package/dist/remediate/phases/close.d.ts.map +1 -1
- package/dist/remediate/phases/close.js +260 -36
- package/dist/remediate/phases/close.js.map +1 -1
- package/dist/remediate/phases/triage.d.ts.map +1 -1
- package/dist/remediate/phases/triage.js +14 -2
- package/dist/remediate/phases/triage.js.map +1 -1
- package/dist/remediate/state/disposition.d.ts +26 -4
- package/dist/remediate/state/disposition.d.ts.map +1 -1
- package/dist/remediate/state/itemStatus.d.ts +33 -6
- package/dist/remediate/state/itemStatus.d.ts.map +1 -1
- package/dist/remediate/state/itemStatus.js +154 -39
- package/dist/remediate/state/itemStatus.js.map +1 -1
- package/dist/remediate/state/types.d.ts +41 -2
- package/dist/remediate/state/types.d.ts.map +1 -1
- package/dist/remediate/state/types.js.map +1 -1
- package/dist/remediate/steps/contractPipeline.d.ts +296 -15
- package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
- package/dist/remediate/steps/contractPipeline.js +1783 -1001
- package/dist/remediate/steps/contractPipeline.js.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts +137 -2
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.js +657 -59
- package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
- package/dist/remediate/steps/finalGate.d.ts +136 -37
- package/dist/remediate/steps/finalGate.d.ts.map +1 -1
- package/dist/remediate/steps/finalGate.js +120 -86
- package/dist/remediate/steps/finalGate.js.map +1 -1
- package/dist/remediate/steps/gateCommands.d.ts +8 -0
- package/dist/remediate/steps/gateCommands.d.ts.map +1 -1
- package/dist/remediate/steps/gateCommands.js +40 -11
- package/dist/remediate/steps/gateCommands.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts +96 -5
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +668 -147
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/remediate/steps/types.d.ts +4 -3
- package/dist/remediate/steps/types.d.ts.map +1 -1
- package/dist/remediate/steps/types.js +10 -2
- package/dist/remediate/steps/types.js.map +1 -1
- package/dist/remediate/validation/artifacts.d.ts +20 -2
- package/dist/remediate/validation/artifacts.d.ts.map +1 -1
- package/dist/remediate/validation/artifacts.js +224 -130
- package/dist/remediate/validation/artifacts.js.map +1 -1
- package/dist/remediate/validation/contractPipelineGates.d.ts +58 -0
- package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -1
- package/dist/remediate/validation/contractPipelineGates.js +143 -27
- package/dist/remediate/validation/contractPipelineGates.js.map +1 -1
- package/dist/shared/analyzers/acquisitionEngine.d.ts +72 -25
- package/dist/shared/analyzers/acquisitionEngine.d.ts.map +1 -1
- package/dist/shared/analyzers/acquisitionEngine.js +149 -15
- package/dist/shared/analyzers/acquisitionEngine.js.map +1 -1
- package/dist/shared/analyzers/binaryAcquisition.d.ts +27 -2
- package/dist/shared/analyzers/binaryAcquisition.d.ts.map +1 -1
- package/dist/shared/analyzers/binaryAcquisition.js +149 -43
- package/dist/shared/analyzers/binaryAcquisition.js.map +1 -1
- package/dist/shared/analyzers/candidates.d.ts +9 -8
- package/dist/shared/analyzers/candidates.d.ts.map +1 -1
- package/dist/shared/analyzers/candidates.js +96 -64
- package/dist/shared/analyzers/candidates.js.map +1 -1
- package/dist/shared/analyzers/normalizeExternal.d.ts +40 -12
- package/dist/shared/analyzers/normalizeExternal.d.ts.map +1 -1
- package/dist/shared/analyzers/normalizeExternal.js +74 -18
- package/dist/shared/analyzers/normalizeExternal.js.map +1 -1
- package/dist/shared/analyzers/rubocop.d.ts +14 -13
- package/dist/shared/analyzers/rubocop.d.ts.map +1 -1
- package/dist/shared/analyzers/rubocop.js +29 -6
- package/dist/shared/analyzers/rubocop.js.map +1 -1
- package/dist/shared/analyzers/types.d.ts +196 -13
- package/dist/shared/analyzers/types.d.ts.map +1 -1
- package/dist/shared/analyzers/types.js +122 -9
- package/dist/shared/analyzers/types.js.map +1 -1
- package/dist/shared/decompose/charterClarification.d.ts +12 -1
- package/dist/shared/decompose/charterClarification.d.ts.map +1 -1
- package/dist/shared/decompose/charterClarification.js +11 -4
- package/dist/shared/decompose/charterClarification.js.map +1 -1
- package/dist/shared/decompose/charterExtraction.d.ts +20 -10
- package/dist/shared/decompose/charterExtraction.d.ts.map +1 -1
- package/dist/shared/decompose/charterExtraction.js +52 -23
- package/dist/shared/decompose/charterExtraction.js.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +5 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/intent/freeFormIntentInterpreter.d.ts +12 -2
- package/dist/shared/intent/freeFormIntentInterpreter.d.ts.map +1 -1
- package/dist/shared/intent/freeFormIntentInterpreter.js +27 -22
- package/dist/shared/intent/freeFormIntentInterpreter.js.map +1 -1
- package/dist/shared/intent/pathScope.d.ts +12 -1
- package/dist/shared/intent/pathScope.d.ts.map +1 -1
- package/dist/shared/intent/pathScope.js +56 -19
- package/dist/shared/intent/pathScope.js.map +1 -1
- package/dist/shared/intent/sharedIntentData.d.ts +19 -1
- package/dist/shared/intent/sharedIntentData.d.ts.map +1 -1
- package/dist/shared/intent/sharedIntentData.js +33 -8
- package/dist/shared/intent/sharedIntentData.js.map +1 -1
- package/dist/shared/io/fileLock.d.ts +12 -0
- package/dist/shared/io/fileLock.d.ts.map +1 -1
- package/dist/shared/io/fileLock.js +48 -5
- package/dist/shared/io/fileLock.js.map +1 -1
- package/dist/shared/io/json.d.ts +13 -0
- package/dist/shared/io/json.d.ts.map +1 -1
- package/dist/shared/io/json.js +19 -1
- package/dist/shared/io/json.js.map +1 -1
- package/dist/shared/steps/stepEmissionScaffold.d.ts +69 -0
- package/dist/shared/steps/stepEmissionScaffold.d.ts.map +1 -0
- package/dist/shared/steps/stepEmissionScaffold.js +83 -0
- package/dist/shared/steps/stepEmissionScaffold.js.map +1 -0
- package/dist/shared/submission/handRecovery.d.ts.map +1 -1
- package/dist/shared/submission/handRecovery.js +69 -4
- package/dist/shared/submission/handRecovery.js.map +1 -1
- package/dist/shared/submission/submissionIdentity.d.ts +10 -1
- package/dist/shared/submission/submissionIdentity.d.ts.map +1 -1
- package/dist/shared/submission/submissionIdentity.js +12 -3
- package/dist/shared/submission/submissionIdentity.js.map +1 -1
- package/dist/shared/submission/submissionLedger.d.ts +43 -2
- package/dist/shared/submission/submissionLedger.d.ts.map +1 -1
- package/dist/shared/submission/submissionLedger.js +50 -7
- package/dist/shared/submission/submissionLedger.js.map +1 -1
- package/dist/shared/tooling/allowlistedExec.d.ts +9 -0
- package/dist/shared/tooling/allowlistedExec.d.ts.map +1 -1
- package/dist/shared/tooling/allowlistedExec.js +19 -2
- package/dist/shared/tooling/allowlistedExec.js.map +1 -1
- package/dist/shared/tooling/commandShape.d.ts +21 -0
- package/dist/shared/tooling/commandShape.d.ts.map +1 -0
- package/dist/shared/tooling/commandShape.js +120 -0
- package/dist/shared/tooling/commandShape.js.map +1 -0
- package/dist/shared/types/charter.d.ts +24 -0
- package/dist/shared/types/charter.d.ts.map +1 -1
- package/dist/shared/types/charter.js +9 -0
- package/dist/shared/types/charter.js.map +1 -1
- package/dist/shared/types/remediationOutcome.d.ts +282 -9
- package/dist/shared/types/remediationOutcome.d.ts.map +1 -1
- package/dist/shared/types/remediationOutcome.js +174 -1
- package/dist/shared/types/remediationOutcome.js.map +1 -1
- package/package.json +2 -1
- package/remediate-code.mjs +15 -0
- package/wrapper/remediate-code-wrapper-install-hosts.mjs +45 -4
- package/wrapper/remediate-code-wrapper-install-renderers.mjs +12 -2
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { loadAnalyzerPolicy, loadSessionIntent, applyGuidanceFile, runWithBlockedStepBackstop, writeBlockedStepContract, laneAssetsDir, renderFanoutExecutionLines, writeTextFile, } from "audit-tools/shared";
|
|
4
|
+
// The ONE shared table-driven step-emission scaffold. Imported by relative path
|
|
5
|
+
// like every other cross-area shared module this area reaches for.
|
|
6
|
+
import { createStepEmissionScaffold } from "../../shared/steps/stepEmissionScaffold.js";
|
|
4
7
|
import { cleanupStaleArtifactsDir } from "./cleanup.js";
|
|
5
8
|
import { materializeFanoutLanes } from "./fanoutLanes.js";
|
|
6
9
|
import { AUDIT_GATE_SUBMISSION_SCOPE, GATE_LANES, charterExtractionLane, charterExtractionPacketFilename, laneSubmissionPath, mergeLaneShortfalls, recordExpectedLanes, renderLaneShortfallLines, } from "./laneSubmissions.js";
|
|
@@ -182,21 +185,16 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
|
|
|
182
185
|
artifactsDir,
|
|
183
186
|
progressSummary: reason,
|
|
184
187
|
});
|
|
188
|
+
// The ONE emission that is not a table row, and deliberately so: it runs
|
|
189
|
+
// BEFORE dispatch, so no result kind exists to dispatch on. An unreadable
|
|
190
|
+
// or invalid analyzer policy blocks the step rather than degrading to an
|
|
191
|
+
// empty policy (which would silently drop every recorded consent decision)
|
|
192
|
+
// — and it still goes through the scaffold's single emission site, so the
|
|
193
|
+
// "write the step, log it, exactly once" shape is not re-implemented here.
|
|
185
194
|
// Shared blocked-step assembly: the step JSON says WHY on its own via
|
|
186
195
|
// progress.summary — an automated consumer (release smoke, CI) sees only this
|
|
187
196
|
// contract, not the prompt file.
|
|
188
|
-
|
|
189
|
-
tool: "audit-code",
|
|
190
|
-
contractVersion: STEP_CONTRACT_VERSION,
|
|
191
|
-
artifactsDir,
|
|
192
|
-
repoRoot: root,
|
|
193
|
-
runId: null,
|
|
194
|
-
reason,
|
|
195
|
-
artifactPaths: {
|
|
196
|
-
operator_handoff: join(artifactsDir, "operator-handoff.json"),
|
|
197
|
-
},
|
|
198
|
-
});
|
|
199
|
-
console.log(JSON.stringify(step, null, 2));
|
|
197
|
+
await NEXT_STEP_EMISSION.emitPlan(blockedStepPlan(operatorHandoffBlock(root, artifactsDir, reason)));
|
|
200
198
|
return;
|
|
201
199
|
}
|
|
202
200
|
const result = await runDeterministicForNextStep({
|
|
@@ -210,807 +208,903 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
|
|
|
210
208
|
// session config can opt out). The executor builds its own global-`fetch`
|
|
211
209
|
// adapter when no fetcher is injected. The unit/integration suite never reaches
|
|
212
210
|
// here, so acquisition stays a hermetic no-op in tests.
|
|
213
|
-
externalAcquisition:
|
|
214
|
-
enabled: true,
|
|
215
|
-
analyzers: analyzerPolicy.analyzers,
|
|
216
|
-
// Item B: recorded consent decisions ride into admission (granted admits
|
|
217
|
-
// without a token) and into the consent fold's pending computation.
|
|
218
|
-
analyzerConsent: analyzerPolicy.analyzer_consent,
|
|
219
|
-
},
|
|
211
|
+
externalAcquisition: buildExternalAcquisitionOptions(analyzerPolicy),
|
|
220
212
|
since: getFlag(argv, "--since"),
|
|
221
213
|
});
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
214
|
+
// The single dispatch: one table row per result kind, one emission site. A
|
|
215
|
+
// kind the table does not carry is the semantic-review dispatch (the
|
|
216
|
+
// scaffold's fallback), exactly as the old fallthrough branch was.
|
|
217
|
+
await NEXT_STEP_EMISSION.emit(result.kind, {
|
|
218
|
+
argv,
|
|
219
|
+
root,
|
|
220
|
+
artifactsDir,
|
|
221
|
+
analyzerPolicy,
|
|
222
|
+
result,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function currentStepPlan(params) {
|
|
226
|
+
return { via: "current", params };
|
|
227
|
+
}
|
|
228
|
+
function blockedStepPlan(params) {
|
|
229
|
+
return { via: "blocked", params };
|
|
230
|
+
}
|
|
231
|
+
function semanticReviewPlan(params) {
|
|
232
|
+
return { via: "semantic_review", params };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The blocked-step shape both blocked paths share — the pre-dispatch config
|
|
236
|
+
* failure and the `blocked` result kind. Single-sourced so the two cannot drift
|
|
237
|
+
* into two different operator-handoff contracts.
|
|
238
|
+
*/
|
|
239
|
+
function operatorHandoffBlock(root, artifactsDir, reason) {
|
|
240
|
+
return {
|
|
241
|
+
tool: "audit-code",
|
|
242
|
+
contractVersion: STEP_CONTRACT_VERSION,
|
|
243
|
+
artifactsDir,
|
|
244
|
+
repoRoot: root,
|
|
245
|
+
runId: null,
|
|
246
|
+
reason,
|
|
247
|
+
artifactPaths: {
|
|
248
|
+
operator_handoff: join(artifactsDir, "operator-handoff.json"),
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/** The ONE writer dispatch. Each underlying writer is called exactly once here. */
|
|
253
|
+
async function writeAuditStep(plan) {
|
|
254
|
+
switch (plan.via) {
|
|
255
|
+
case "current":
|
|
256
|
+
return await writeCurrentStep(plan.params);
|
|
257
|
+
case "blocked":
|
|
258
|
+
return await writeBlockedStepContract(plan.params);
|
|
259
|
+
case "semantic_review":
|
|
260
|
+
return await renderSemanticReviewStep(plan.params);
|
|
249
261
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Bind one row to its own result variant. The table is keyed BY the result
|
|
265
|
+
* kind, so the row that runs is by construction the row for `ctx.result.kind`;
|
|
266
|
+
* the narrowing is stated once here rather than re-checked in every body.
|
|
267
|
+
*/
|
|
268
|
+
function emissionRow(handle) {
|
|
269
|
+
return (ctx) => handle(ctx, ctx.result);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* The caller-side precondition the analyzer-acquisition chokepoint declares:
|
|
273
|
+
* an acquisition-bearing step is only emitted for a run whose durable analyzer
|
|
274
|
+
* policy actually loaded. Refusing here (the terminal backstop turns the throw
|
|
275
|
+
* into a written blocked step) keeps the alternative — emitting a consent or
|
|
276
|
+
* install step against no policy — impossible: those steps collect decisions
|
|
277
|
+
* that have nothing to merge into, and admission would see no recorded
|
|
278
|
+
* decision at all, making an operator's recorded decline unrepresentable
|
|
279
|
+
* rather than merely unenforced.
|
|
280
|
+
*/
|
|
281
|
+
function requireLoadedAnalyzerPolicy(policy, stepKind) {
|
|
282
|
+
if (policy)
|
|
264
283
|
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
284
|
+
throw new Error(`audit-code next-step: the ${stepKind} step is acquisition-bearing and requires the durable analyzer policy, which was not loaded. Refusing to emit it rather than proceeding with no recorded consent decisions.`);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The acquisition chokepoint's declared caller obligation, discharged in ONE
|
|
288
|
+
* place: BOTH halves of the loaded policy ride every acquisition call — the
|
|
289
|
+
* per-analyzer settings AND the recorded consent decisions. Dropping the
|
|
290
|
+
* decisions leaves a recorded decline unrepresentable at admission (the
|
|
291
|
+
* chokepoint would see `undefined` and read it as "not yet decided"), and no
|
|
292
|
+
* consent token is synthesized here on the operator's behalf: the field is
|
|
293
|
+
* absent, never an empty string.
|
|
294
|
+
*/
|
|
295
|
+
export function buildExternalAcquisitionOptions(policy) {
|
|
296
|
+
return {
|
|
297
|
+
enabled: true,
|
|
298
|
+
analyzers: policy.analyzers,
|
|
299
|
+
// Item B: recorded consent decisions ride into admission (granted admits
|
|
300
|
+
// without a token) and into the consent fold's pending computation.
|
|
301
|
+
analyzerConsent: policy.analyzer_consent,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const emitComplete = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
305
|
+
const triage = result.triage;
|
|
306
|
+
const frictionPending = triage?.action === "dispose";
|
|
307
|
+
return currentStepPlan({
|
|
308
|
+
artifactsDir,
|
|
309
|
+
stepKind: "present_report",
|
|
310
|
+
status: frictionPending ? "ready" : "complete",
|
|
311
|
+
runId: null,
|
|
312
|
+
// INV-READY-STEP-CONTINUATION (COR-f6a36670): a ready step whose
|
|
313
|
+
// stop_condition instructs calling next-step again must carry the
|
|
314
|
+
// executable continuation command — never leave the host to reconstruct
|
|
315
|
+
// the invocation from prose.
|
|
316
|
+
allowedCommands: frictionPending
|
|
317
|
+
? [nextStepCommand(root, artifactsDir)]
|
|
318
|
+
: [],
|
|
319
|
+
stopCondition: frictionPending
|
|
320
|
+
? "Complete friction triage (write open_observations and any dispositions), then call next-step again."
|
|
321
|
+
: "Present the final audit report and stop.",
|
|
322
|
+
repoRoot: root,
|
|
323
|
+
artifactPaths: {
|
|
324
|
+
final_report: result.finalReportPath,
|
|
325
|
+
...(triage ? { friction_record: triage.recordPath } : {}),
|
|
326
|
+
},
|
|
327
|
+
prompt: renderPresentReportPrompt(result.finalReportPath, triage),
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
const emitBlocked = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
331
|
+
// The SAME operator-handoff blocked contract the pre-dispatch config
|
|
332
|
+
// failure emits — built from the one home, never re-typed here.
|
|
333
|
+
return blockedStepPlan(operatorHandoffBlock(root, artifactsDir, result.reason));
|
|
334
|
+
});
|
|
335
|
+
const emitDesignReviewParallel = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
336
|
+
// Both passes are unsatisfied — dispatch the contract pass and the
|
|
337
|
+
// conceptual pass simultaneously. The conceptual pass is shallow (one agent)
|
|
338
|
+
// or deep (N independent perspective subagents + an independent judge),
|
|
339
|
+
// resolved JIT from the user-confirmed checkpoint / session config.
|
|
340
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
341
|
+
const conceptualSettings = resolveConceptualReviewSettings(result.bundle);
|
|
342
|
+
const contract = await prepareContractDispatch({
|
|
343
|
+
artifactsDir,
|
|
344
|
+
bundle: result.bundle,
|
|
345
|
+
maxUnits: conceptualSettings.max_units,
|
|
346
|
+
});
|
|
347
|
+
const conceptual = await prepareConceptualPass(artifactsDir, result.bundle, conceptualSettings);
|
|
348
|
+
const shortfall = mergeLaneShortfalls([
|
|
349
|
+
contract.shortfall,
|
|
350
|
+
conceptual.shortfall,
|
|
351
|
+
]);
|
|
352
|
+
const dispatchPrompt = [
|
|
353
|
+
"# Design review — parallel dispatch",
|
|
354
|
+
"",
|
|
355
|
+
...renderLaneShortfallLines(shortfall),
|
|
356
|
+
"Run the two design-review passes concurrently. Do not wait for one before starting the other.",
|
|
357
|
+
"",
|
|
358
|
+
`1. ${contract.instructionLine}`,
|
|
359
|
+
`2. ${conceptual.instructionLines.join("\n ")}`,
|
|
360
|
+
"",
|
|
361
|
+
"When the contract results and the conceptual results have both been written, run:",
|
|
362
|
+
"",
|
|
363
|
+
` ${continueCommand}`,
|
|
364
|
+
"",
|
|
365
|
+
].join("\n");
|
|
366
|
+
return currentStepPlan({
|
|
367
|
+
artifactsDir,
|
|
368
|
+
stepKind: "design_review_parallel",
|
|
369
|
+
status: "ready",
|
|
370
|
+
runId: null,
|
|
371
|
+
allowedCommands: [continueCommand],
|
|
372
|
+
stopCondition: "Dispatch the contract and conceptual review subagents in parallel, then run next-step once both results are written.",
|
|
373
|
+
repoRoot: root,
|
|
374
|
+
artifactPaths: {
|
|
375
|
+
...contract.artifactPaths,
|
|
376
|
+
...conceptual.artifactPaths,
|
|
377
|
+
},
|
|
378
|
+
prompt: dispatchPrompt,
|
|
379
|
+
access: {
|
|
380
|
+
read_paths: [...contract.readPaths, ...conceptual.readPaths],
|
|
381
|
+
write_paths: [...contract.writePaths, ...conceptual.writePaths],
|
|
382
|
+
},
|
|
383
|
+
submissionShortfall: shortfall,
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
const emitDesignReviewContract = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
387
|
+
// Only the contract pass remains — dispatched exactly as in the parallel
|
|
388
|
+
// branch. This branch is reached whenever the conceptual pass is already
|
|
389
|
+
// done, i.e. late in a run the host itself drove, which is precisely when
|
|
390
|
+
// rendering the adversarial review into the host's own prompt would have it
|
|
391
|
+
// grade its own work (see prepareContractDispatch).
|
|
392
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
393
|
+
const contract = await prepareContractDispatch({
|
|
394
|
+
artifactsDir,
|
|
395
|
+
bundle: result.bundle,
|
|
396
|
+
maxUnits: resolveConceptualReviewSettings(result.bundle).max_units,
|
|
397
|
+
});
|
|
398
|
+
const dispatchPrompt = [
|
|
399
|
+
"# Design review — contract pass",
|
|
400
|
+
"",
|
|
401
|
+
...renderLaneShortfallLines(contract.shortfall),
|
|
402
|
+
contract.instructionLine,
|
|
403
|
+
"",
|
|
404
|
+
"When the contract results have been written, run:",
|
|
405
|
+
"",
|
|
406
|
+
` ${continueCommand}`,
|
|
407
|
+
"",
|
|
408
|
+
].join("\n");
|
|
409
|
+
return currentStepPlan({
|
|
410
|
+
artifactsDir,
|
|
411
|
+
stepKind: "design_review_contract",
|
|
412
|
+
status: "ready",
|
|
413
|
+
runId: null,
|
|
414
|
+
allowedCommands: [continueCommand],
|
|
415
|
+
stopCondition: "Dispatch the contract review subagent, then run next-step once the contract results are written.",
|
|
416
|
+
repoRoot: root,
|
|
417
|
+
artifactPaths: contract.artifactPaths,
|
|
418
|
+
prompt: dispatchPrompt,
|
|
419
|
+
access: {
|
|
420
|
+
read_paths: contract.readPaths,
|
|
421
|
+
write_paths: contract.writePaths,
|
|
422
|
+
},
|
|
423
|
+
submissionShortfall: contract.shortfall,
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
const emitDesignReviewConceptual = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
427
|
+
// Only the conceptual pass remains — shallow (one agent) or deep (N
|
|
428
|
+
// independent perspective subagents + an independent judge), resolved JIT
|
|
429
|
+
// from the user-confirmed checkpoint / session config.
|
|
430
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
431
|
+
const conceptualSettings = resolveConceptualReviewSettings(result.bundle);
|
|
432
|
+
const conceptual = await prepareConceptualPass(artifactsDir, result.bundle, conceptualSettings);
|
|
433
|
+
const prompt = [
|
|
434
|
+
"# Design review — conceptual pass",
|
|
435
|
+
"",
|
|
436
|
+
...renderLaneShortfallLines(conceptual.shortfall),
|
|
437
|
+
conceptual.instructionLines.join("\n"),
|
|
438
|
+
"",
|
|
439
|
+
"When the conceptual results have been written, run:",
|
|
440
|
+
"",
|
|
441
|
+
` ${continueCommand}`,
|
|
442
|
+
"",
|
|
443
|
+
].join("\n");
|
|
444
|
+
return currentStepPlan({
|
|
445
|
+
artifactsDir,
|
|
446
|
+
stepKind: "design_review_conceptual",
|
|
447
|
+
status: "ready",
|
|
448
|
+
runId: null,
|
|
449
|
+
allowedCommands: [continueCommand],
|
|
450
|
+
stopCondition: conceptual.deep
|
|
451
|
+
? "Dispatch the conceptual perspective subagents in parallel, then the independent judge, then run next-step once the merged conceptual results are written."
|
|
452
|
+
: "Write conceptual review findings to the results path, then run next-step.",
|
|
453
|
+
repoRoot: root,
|
|
454
|
+
artifactPaths: {
|
|
455
|
+
design_review_conceptual_results: conceptual.conceptualResultsPath,
|
|
456
|
+
...conceptual.artifactPaths,
|
|
457
|
+
},
|
|
458
|
+
prompt,
|
|
459
|
+
access: {
|
|
460
|
+
read_paths: conceptual.readPaths,
|
|
461
|
+
write_paths: conceptual.writePaths,
|
|
462
|
+
},
|
|
463
|
+
submissionShortfall: conceptual.shortfall,
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
const emitCharterExtraction = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
467
|
+
// Phase C charter layer (conceptual, teleological): one blind, materialized
|
|
468
|
+
// LANE per charter kind (design resolution 2 — independence is the shape of
|
|
469
|
+
// the artifacts, not a merge instruction); the tool merges the per-kind
|
|
470
|
+
// submissions and gates + routes them at ingest. Only reached at a deep+
|
|
471
|
+
// ceiling (shallow omits deterministically without a host turn).
|
|
472
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
473
|
+
const ceiling = resolveCharterCeiling(result.bundle.intent_checkpoint);
|
|
474
|
+
const kinds = charterExtractionKindsForCeiling(ceiling);
|
|
475
|
+
// Channel purity is a property of the INPUT (design resolution 4): each
|
|
476
|
+
// lane gets a tool-materialized evidence packet holding only its channel's
|
|
477
|
+
// material. Packets are (re)written on every emission — they derive from
|
|
478
|
+
// the bundle + disk, so re-materializing is idempotent and keeps a resumed
|
|
479
|
+
// lane's evidence current.
|
|
480
|
+
const packetPaths = [];
|
|
481
|
+
const laneSpecs = await Promise.all(kinds.map(async (kind) => {
|
|
482
|
+
const lane = charterExtractionLane(kind);
|
|
483
|
+
const submissionPath = laneSubmissionPath(artifactsDir, lane);
|
|
484
|
+
const packetPath = join(laneAssetsDir(artifactsDir), charterExtractionPacketFilename(kind));
|
|
485
|
+
await writeTextFile(packetPath, await materializeCharterPacket({ root, bundle: result.bundle, kind }));
|
|
486
|
+
packetPaths.push(packetPath);
|
|
487
|
+
return {
|
|
488
|
+
id: lane,
|
|
489
|
+
label: `Charter ${kind} author (blind lane)`,
|
|
490
|
+
promptFilename: `charter-extraction-${kind}-prompt.md`,
|
|
491
|
+
promptText: renderCharterKindLanePrompt(result.bundle, {
|
|
492
|
+
kind,
|
|
493
|
+
submissionPath,
|
|
494
|
+
packetPath,
|
|
495
|
+
}),
|
|
496
|
+
};
|
|
497
|
+
}));
|
|
498
|
+
const fanout = await materializeFanoutLanes({
|
|
499
|
+
artifactsDir,
|
|
500
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
501
|
+
lanes: laneSpecs,
|
|
502
|
+
});
|
|
503
|
+
const completedLanes = fanout.lanes.filter((lane) => lane.resultExists);
|
|
504
|
+
return currentStepPlan({
|
|
505
|
+
artifactsDir,
|
|
506
|
+
stepKind: "charter_extraction",
|
|
507
|
+
status: "ready",
|
|
508
|
+
runId: null,
|
|
509
|
+
allowedCommands: [continueCommand],
|
|
510
|
+
stopCondition: "Execute each pending charter lane prompt (one blind agent per kind — subagents if available, else sequentially), write each lane's submission to its results path, then run next-step.",
|
|
511
|
+
repoRoot: root,
|
|
512
|
+
artifactPaths: fanout.artifactPaths,
|
|
513
|
+
prompt: [
|
|
514
|
+
"# audit-code charter extraction (per-kind blind lanes)",
|
|
285
515
|
"",
|
|
286
|
-
...renderLaneShortfallLines(shortfall),
|
|
287
|
-
"
|
|
516
|
+
...renderLaneShortfallLines(fanout.shortfall),
|
|
517
|
+
"Each charter kind is authored by its OWN blind lane: a lane must not see another lane's prompt or output, so the later stated↔revealed delta is genuine disagreement rather than one author's self-consistent story. The tool merges the per-kind submissions at ingest.",
|
|
288
518
|
"",
|
|
289
|
-
|
|
290
|
-
|
|
519
|
+
...renderFanoutExecutionLines({
|
|
520
|
+
lanes: fanout.pendingLanes.map((lane) => ({
|
|
521
|
+
label: lane.label,
|
|
522
|
+
promptPath: lane.promptPath,
|
|
523
|
+
resultPath: lane.resultPath,
|
|
524
|
+
})),
|
|
525
|
+
}),
|
|
291
526
|
"",
|
|
292
|
-
|
|
527
|
+
...(completedLanes.length > 0
|
|
528
|
+
? [
|
|
529
|
+
`Already complete (results on disk — do NOT redo these lanes): ${completedLanes
|
|
530
|
+
.map((lane) => lane.label)
|
|
531
|
+
.join(", ")}.`,
|
|
532
|
+
"",
|
|
533
|
+
]
|
|
534
|
+
: []),
|
|
535
|
+
"When every pending lane's result file exists, run:",
|
|
293
536
|
"",
|
|
294
537
|
` ${continueCommand}`,
|
|
295
538
|
"",
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
539
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
540
|
+
"",
|
|
541
|
+
].join("\n"),
|
|
542
|
+
access: {
|
|
543
|
+
// Prompts + packets only: the lanes' whole input is materialized, so no
|
|
544
|
+
// repo/artifact read grant exists to leak another channel's evidence.
|
|
545
|
+
read_paths: [...fanout.readPaths, ...packetPaths],
|
|
546
|
+
write_paths: fanout.writePaths,
|
|
547
|
+
},
|
|
548
|
+
submissionShortfall: fanout.shortfall,
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
const emitCharterDelta = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
552
|
+
// Phase C.2 charter delta-mining (conceptual, teleological): an INDEPENDENT
|
|
553
|
+
// delta-miner reads the assembled charters (authored by a different pass, blind
|
|
554
|
+
// to the gaps) and mines the pairwise deltas + the goal DAG; the tool routes +
|
|
555
|
+
// gates them at ingest. Only reached at a deep+ ceiling whose extraction pass
|
|
556
|
+
// produced ≥1 subsystem (charter_register.deltas_pending).
|
|
557
|
+
// Always-materialized (design resolution 2): the miner prompt is a lane FILE.
|
|
558
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
559
|
+
const submissionPath = laneSubmissionPath(artifactsDir, GATE_LANES.charter_delta);
|
|
560
|
+
const lanePrompt = renderCharterDeltaPrompt(result.bundle, { submissionPath });
|
|
561
|
+
const fanout = await materializeFanoutLanes({
|
|
562
|
+
artifactsDir,
|
|
563
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
564
|
+
lanes: [
|
|
565
|
+
{
|
|
566
|
+
id: GATE_LANES.charter_delta,
|
|
567
|
+
label: "Independent charter delta-miner",
|
|
568
|
+
promptFilename: "charter-delta-prompt.md",
|
|
569
|
+
promptText: lanePrompt,
|
|
313
570
|
},
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
artifactsDir,
|
|
328
|
-
bundle: result.bundle,
|
|
329
|
-
maxUnits: resolveConceptualReviewSettings(result.bundle).max_units,
|
|
330
|
-
});
|
|
331
|
-
const dispatchPrompt = [
|
|
332
|
-
"# Design review — contract pass",
|
|
571
|
+
],
|
|
572
|
+
});
|
|
573
|
+
return currentStepPlan({
|
|
574
|
+
artifactsDir,
|
|
575
|
+
stepKind: "charter_delta",
|
|
576
|
+
status: "ready",
|
|
577
|
+
runId: null,
|
|
578
|
+
allowedCommands: [continueCommand],
|
|
579
|
+
stopCondition: "Execute the delta-miner lane prompt (subagent if available, else yourself), write the mined deltas + goal graph to the results path, then run next-step.",
|
|
580
|
+
repoRoot: root,
|
|
581
|
+
artifactPaths: fanout.artifactPaths,
|
|
582
|
+
prompt: [
|
|
583
|
+
"# audit-code charter delta-mining",
|
|
333
584
|
"",
|
|
334
|
-
...renderLaneShortfallLines(
|
|
335
|
-
|
|
585
|
+
...renderLaneShortfallLines(fanout.shortfall),
|
|
586
|
+
"The assembled charters are ready for the INDEPENDENT delta-miner (it did not author them).",
|
|
336
587
|
"",
|
|
337
|
-
|
|
588
|
+
...renderFanoutExecutionLines({
|
|
589
|
+
lanes: fanout.pendingLanes.map((lane) => ({
|
|
590
|
+
label: lane.label,
|
|
591
|
+
promptPath: lane.promptPath,
|
|
592
|
+
})),
|
|
593
|
+
}),
|
|
594
|
+
"",
|
|
595
|
+
"The executor must write its CharterDeltaSubmission JSON to:",
|
|
596
|
+
"",
|
|
597
|
+
` ${submissionPath}`,
|
|
598
|
+
"",
|
|
599
|
+
"When the result file exists, run:",
|
|
338
600
|
"",
|
|
339
601
|
` ${continueCommand}`,
|
|
340
602
|
"",
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
603
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
604
|
+
"",
|
|
605
|
+
].join("\n"),
|
|
606
|
+
access: {
|
|
607
|
+
read_paths: [
|
|
608
|
+
...fanout.readPaths,
|
|
609
|
+
join(artifactsDir, "charter_register.json"),
|
|
610
|
+
],
|
|
611
|
+
write_paths: fanout.writePaths,
|
|
612
|
+
},
|
|
613
|
+
submissionShortfall: fanout.shortfall,
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
const emitCharterClarification = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
617
|
+
// Phase D triangulation loop: the tool has already run the deterministic loop
|
|
618
|
+
// (partition → VOI-rank → risk-gate → split by attention) and surfaces the
|
|
619
|
+
// interactive queue here. The host relays each SYMMETRIC question and writes the
|
|
620
|
+
// answers back; the executor applies them + re-splits (interruptible: unanswered
|
|
621
|
+
// questions leave-open). Only reached at a deep+ ceiling with attention > 0 and
|
|
622
|
+
// ≥1 open interactive question.
|
|
623
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
624
|
+
const answersPath = laneSubmissionPath(artifactsDir, GATE_LANES.charter_clarification);
|
|
625
|
+
const ceiling = resolveCharterCeiling(result.bundle.intent_checkpoint);
|
|
626
|
+
const clarificationPrompt = renderCharterClarificationPrompt(result.bundle, {
|
|
627
|
+
answersPath,
|
|
628
|
+
continueCommand,
|
|
629
|
+
ceiling,
|
|
630
|
+
});
|
|
631
|
+
const shortfall = await recordExpectedLanes(artifactsDir, AUDIT_GATE_SUBMISSION_SCOPE, [{ lane: GATE_LANES.charter_clarification, promptText: clarificationPrompt }]);
|
|
632
|
+
return currentStepPlan({
|
|
633
|
+
artifactsDir,
|
|
634
|
+
stepKind: "charter_clarification",
|
|
635
|
+
status: "ready",
|
|
636
|
+
runId: null,
|
|
637
|
+
allowedCommands: [continueCommand],
|
|
638
|
+
stopCondition: "Relay each charter-alignment question to the user, write the answers to the answers path, then run next-step.",
|
|
639
|
+
repoRoot: root,
|
|
640
|
+
artifactPaths: {
|
|
641
|
+
charter_clarification_answers: answersPath,
|
|
642
|
+
},
|
|
643
|
+
prompt: [
|
|
644
|
+
...renderLaneShortfallLines(shortfall),
|
|
645
|
+
clarificationPrompt,
|
|
646
|
+
].join("\n"),
|
|
647
|
+
access: {
|
|
648
|
+
read_paths: [join(artifactsDir, "charter_clarification.json")],
|
|
649
|
+
write_paths: [answersPath],
|
|
650
|
+
},
|
|
651
|
+
submissionShortfall: shortfall,
|
|
652
|
+
});
|
|
653
|
+
});
|
|
654
|
+
const emitSystemicChallenge = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
655
|
+
// Phase E second-order adversary (loop-until-dry): the tool has opened the loop
|
|
656
|
+
// and computed the language-neutral aggregate-metrics digest. The host dispatches
|
|
657
|
+
// a SEPARATE adversary agent whose mandate is optimization/better-way; it writes
|
|
658
|
+
// the round's improvement findings (true-lens) back, and the executor folds them
|
|
659
|
+
// + decides convergence. An empty submission converges the loop.
|
|
660
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
661
|
+
const submissionPath = laneSubmissionPath(artifactsDir, GATE_LANES.systemic_challenge);
|
|
662
|
+
const metrics = result.bundle.systemic_challenge?.metrics ?? aggregateMetricsDigest(result.bundle);
|
|
663
|
+
const adversaryPrompt = renderSecondOrderAdversaryPrompt({
|
|
664
|
+
round: (result.bundle.systemic_challenge?.rounds.length ?? 0) + 1,
|
|
665
|
+
priorFindingCount: result.bundle.systemic_challenge?.findings.length ?? 0,
|
|
666
|
+
metrics,
|
|
667
|
+
submissionPath,
|
|
668
|
+
});
|
|
669
|
+
// Always-materialized (design resolution 2): the adversary prompt is a lane
|
|
670
|
+
// FILE — the adversary is a SEPARATE agent by lane class, on every host.
|
|
671
|
+
const fanout = await materializeFanoutLanes({
|
|
672
|
+
artifactsDir,
|
|
673
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
674
|
+
lanes: [
|
|
675
|
+
{
|
|
676
|
+
id: GATE_LANES.systemic_challenge,
|
|
677
|
+
label: "Second-order adversary (improvement-seeking challenge)",
|
|
678
|
+
promptFilename: "systemic-challenge-prompt.md",
|
|
679
|
+
promptText: adversaryPrompt,
|
|
355
680
|
},
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
"
|
|
681
|
+
],
|
|
682
|
+
});
|
|
683
|
+
return currentStepPlan({
|
|
684
|
+
artifactsDir,
|
|
685
|
+
stepKind: "systemic_challenge",
|
|
686
|
+
status: "ready",
|
|
687
|
+
runId: null,
|
|
688
|
+
allowedCommands: [continueCommand],
|
|
689
|
+
stopCondition: "Execute the second-order-adversary lane prompt (a separate agent from the one that drove this audit), write its findings to the results path, then run next-step. An empty findings array converges the loop.",
|
|
690
|
+
repoRoot: root,
|
|
691
|
+
artifactPaths: fanout.artifactPaths,
|
|
692
|
+
prompt: [
|
|
693
|
+
"# audit-code systemic challenge (second-order adversary)",
|
|
694
|
+
"",
|
|
695
|
+
...renderLaneShortfallLines(fanout.shortfall),
|
|
696
|
+
"This round's adversary lane challenges the audit process itself (optimization/better-way mandate). The adversary must NOT be the agent that drove this audit.",
|
|
697
|
+
"",
|
|
698
|
+
...renderFanoutExecutionLines({
|
|
699
|
+
lanes: fanout.pendingLanes.map((lane) => ({
|
|
700
|
+
label: lane.label,
|
|
701
|
+
promptPath: lane.promptPath,
|
|
702
|
+
})),
|
|
703
|
+
}),
|
|
370
704
|
"",
|
|
371
|
-
|
|
372
|
-
conceptual.instructionLines.join("\n"),
|
|
705
|
+
"The executor must write its findings JSON to:",
|
|
373
706
|
"",
|
|
374
|
-
|
|
707
|
+
` ${submissionPath}`,
|
|
708
|
+
"",
|
|
709
|
+
"An EMPTY findings array is the deliberate loop terminator (this round found nothing new).",
|
|
710
|
+
"",
|
|
711
|
+
"When the result file exists, run:",
|
|
375
712
|
"",
|
|
376
713
|
` ${continueCommand}`,
|
|
377
714
|
"",
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
stopCondition: conceptual.deep
|
|
386
|
-
? "Dispatch the conceptual perspective subagents in parallel, then the independent judge, then run next-step once the merged conceptual results are written."
|
|
387
|
-
: "Write conceptual review findings to the results path, then run next-step.",
|
|
388
|
-
repoRoot: root,
|
|
389
|
-
artifactPaths: {
|
|
390
|
-
design_review_conceptual_results: conceptual.conceptualResultsPath,
|
|
391
|
-
...conceptual.artifactPaths,
|
|
392
|
-
},
|
|
393
|
-
prompt,
|
|
394
|
-
access: {
|
|
395
|
-
read_paths: conceptual.readPaths,
|
|
396
|
-
write_paths: conceptual.writePaths,
|
|
397
|
-
},
|
|
398
|
-
submissionShortfall: conceptual.shortfall,
|
|
399
|
-
});
|
|
400
|
-
console.log(JSON.stringify(step, null, 2));
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
if (result.kind === "charter_extraction") {
|
|
404
|
-
// Phase C charter layer (conceptual, teleological): one blind, materialized
|
|
405
|
-
// LANE per charter kind (design resolution 2 — independence is the shape of
|
|
406
|
-
// the artifacts, not a merge instruction); the tool merges the per-kind
|
|
407
|
-
// submissions and gates + routes them at ingest. Only reached at a deep+
|
|
408
|
-
// ceiling (shallow omits deterministically without a host turn).
|
|
409
|
-
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
410
|
-
const ceiling = resolveCharterCeiling(result.bundle.intent_checkpoint);
|
|
411
|
-
const kinds = charterExtractionKindsForCeiling(ceiling);
|
|
412
|
-
// Channel purity is a property of the INPUT (design resolution 4): each
|
|
413
|
-
// lane gets a tool-materialized evidence packet holding only its channel's
|
|
414
|
-
// material. Packets are (re)written on every emission — they derive from
|
|
415
|
-
// the bundle + disk, so re-materializing is idempotent and keeps a resumed
|
|
416
|
-
// lane's evidence current.
|
|
417
|
-
const packetPaths = [];
|
|
418
|
-
const laneSpecs = await Promise.all(kinds.map(async (kind) => {
|
|
419
|
-
const lane = charterExtractionLane(kind);
|
|
420
|
-
const submissionPath = laneSubmissionPath(artifactsDir, lane);
|
|
421
|
-
const packetPath = join(laneAssetsDir(artifactsDir), charterExtractionPacketFilename(kind));
|
|
422
|
-
await writeTextFile(packetPath, await materializeCharterPacket({ root, bundle: result.bundle, kind }));
|
|
423
|
-
packetPaths.push(packetPath);
|
|
424
|
-
return {
|
|
425
|
-
id: lane,
|
|
426
|
-
label: `Charter ${kind} author (blind lane)`,
|
|
427
|
-
promptFilename: `charter-extraction-${kind}-prompt.md`,
|
|
428
|
-
promptText: renderCharterKindLanePrompt(result.bundle, {
|
|
429
|
-
kind,
|
|
430
|
-
submissionPath,
|
|
431
|
-
packetPath,
|
|
432
|
-
}),
|
|
433
|
-
};
|
|
434
|
-
}));
|
|
435
|
-
const fanout = await materializeFanoutLanes({
|
|
436
|
-
artifactsDir,
|
|
437
|
-
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
438
|
-
lanes: laneSpecs,
|
|
439
|
-
});
|
|
440
|
-
const completedLanes = fanout.lanes.filter((lane) => lane.resultExists);
|
|
441
|
-
const step = await writeCurrentStep({
|
|
442
|
-
artifactsDir,
|
|
443
|
-
stepKind: "charter_extraction",
|
|
444
|
-
status: "ready",
|
|
445
|
-
runId: null,
|
|
446
|
-
allowedCommands: [continueCommand],
|
|
447
|
-
stopCondition: "Execute each pending charter lane prompt (one blind agent per kind — subagents if available, else sequentially), write each lane's submission to its results path, then run next-step.",
|
|
448
|
-
repoRoot: root,
|
|
449
|
-
artifactPaths: fanout.artifactPaths,
|
|
450
|
-
prompt: [
|
|
451
|
-
"# audit-code charter extraction (per-kind blind lanes)",
|
|
452
|
-
"",
|
|
453
|
-
...renderLaneShortfallLines(fanout.shortfall),
|
|
454
|
-
"Each charter kind is authored by its OWN blind lane: a lane must not see another lane's prompt or output, so the later stated↔revealed delta is genuine disagreement rather than one author's self-consistent story. The tool merges the per-kind submissions at ingest.",
|
|
455
|
-
"",
|
|
456
|
-
...renderFanoutExecutionLines({
|
|
457
|
-
lanes: fanout.pendingLanes.map((lane) => ({
|
|
458
|
-
label: lane.label,
|
|
459
|
-
promptPath: lane.promptPath,
|
|
460
|
-
resultPath: lane.resultPath,
|
|
461
|
-
})),
|
|
462
|
-
}),
|
|
463
|
-
"",
|
|
464
|
-
...(completedLanes.length > 0
|
|
465
|
-
? [
|
|
466
|
-
`Already complete (results on disk — do NOT redo these lanes): ${completedLanes
|
|
467
|
-
.map((lane) => lane.label)
|
|
468
|
-
.join(", ")}.`,
|
|
469
|
-
"",
|
|
470
|
-
]
|
|
471
|
-
: []),
|
|
472
|
-
"When every pending lane's result file exists, run:",
|
|
473
|
-
"",
|
|
474
|
-
` ${continueCommand}`,
|
|
475
|
-
"",
|
|
476
|
-
"Read and follow only the new step prompt returned by that command.",
|
|
477
|
-
"",
|
|
478
|
-
].join("\n"),
|
|
479
|
-
access: {
|
|
480
|
-
// Prompts + packets only: the lanes' whole input is materialized, so no
|
|
481
|
-
// repo/artifact read grant exists to leak another channel's evidence.
|
|
482
|
-
read_paths: [...fanout.readPaths, ...packetPaths],
|
|
483
|
-
write_paths: fanout.writePaths,
|
|
484
|
-
},
|
|
485
|
-
submissionShortfall: fanout.shortfall,
|
|
486
|
-
});
|
|
487
|
-
console.log(JSON.stringify(step, null, 2));
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
if (result.kind === "charter_delta") {
|
|
491
|
-
// Phase C.2 charter delta-mining (conceptual, teleological): an INDEPENDENT
|
|
492
|
-
// delta-miner reads the assembled charters (authored by a different pass, blind
|
|
493
|
-
// to the gaps) and mines the pairwise deltas + the goal DAG; the tool routes +
|
|
494
|
-
// gates them at ingest. Only reached at a deep+ ceiling whose extraction pass
|
|
495
|
-
// produced ≥1 subsystem (charter_register.deltas_pending).
|
|
496
|
-
// Always-materialized (design resolution 2): the miner prompt is a lane FILE.
|
|
497
|
-
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
498
|
-
const submissionPath = laneSubmissionPath(artifactsDir, GATE_LANES.charter_delta);
|
|
499
|
-
const lanePrompt = renderCharterDeltaPrompt(result.bundle, { submissionPath });
|
|
500
|
-
const fanout = await materializeFanoutLanes({
|
|
501
|
-
artifactsDir,
|
|
502
|
-
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
503
|
-
lanes: [
|
|
504
|
-
{
|
|
505
|
-
id: GATE_LANES.charter_delta,
|
|
506
|
-
label: "Independent charter delta-miner",
|
|
507
|
-
promptFilename: "charter-delta-prompt.md",
|
|
508
|
-
promptText: lanePrompt,
|
|
509
|
-
},
|
|
715
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
716
|
+
"",
|
|
717
|
+
].join("\n"),
|
|
718
|
+
access: {
|
|
719
|
+
read_paths: [
|
|
720
|
+
...fanout.readPaths,
|
|
721
|
+
join(artifactsDir, "systemic_challenge.json"),
|
|
510
722
|
],
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
"",
|
|
534
|
-
"The executor must write its CharterDeltaSubmission JSON to:",
|
|
535
|
-
"",
|
|
536
|
-
` ${submissionPath}`,
|
|
537
|
-
"",
|
|
538
|
-
"When the result file exists, run:",
|
|
539
|
-
"",
|
|
540
|
-
` ${continueCommand}`,
|
|
541
|
-
"",
|
|
542
|
-
"Read and follow only the new step prompt returned by that command.",
|
|
543
|
-
"",
|
|
544
|
-
].join("\n"),
|
|
545
|
-
access: {
|
|
546
|
-
read_paths: [
|
|
547
|
-
...fanout.readPaths,
|
|
548
|
-
join(artifactsDir, "charter_register.json"),
|
|
549
|
-
],
|
|
550
|
-
write_paths: fanout.writePaths,
|
|
551
|
-
},
|
|
552
|
-
submissionShortfall: fanout.shortfall,
|
|
553
|
-
});
|
|
554
|
-
console.log(JSON.stringify(step, null, 2));
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
if (result.kind === "charter_clarification") {
|
|
558
|
-
// Phase D triangulation loop: the tool has already run the deterministic loop
|
|
559
|
-
// (partition → VOI-rank → risk-gate → split by attention) and surfaces the
|
|
560
|
-
// interactive queue here. The host relays each SYMMETRIC question and writes the
|
|
561
|
-
// answers back; the executor applies them + re-splits (interruptible: unanswered
|
|
562
|
-
// questions leave-open). Only reached at a deep+ ceiling with attention > 0 and
|
|
563
|
-
// ≥1 open interactive question.
|
|
564
|
-
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
565
|
-
const answersPath = laneSubmissionPath(artifactsDir, GATE_LANES.charter_clarification);
|
|
566
|
-
const ceiling = resolveCharterCeiling(result.bundle.intent_checkpoint);
|
|
567
|
-
const clarificationPrompt = renderCharterClarificationPrompt(result.bundle, {
|
|
568
|
-
answersPath,
|
|
723
|
+
write_paths: fanout.writePaths,
|
|
724
|
+
},
|
|
725
|
+
submissionShortfall: fanout.shortfall,
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
const emitConfirmIntent = emissionRow(async ({ root, artifactsDir, argv }, result) => {
|
|
729
|
+
const intentCheckpointPath = join(artifactsDir, "intent_checkpoint.json");
|
|
730
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
731
|
+
const preDigest = computeScopePreDigest(result.bundle, root, getFlag(argv, "--since"));
|
|
732
|
+
return currentStepPlan({
|
|
733
|
+
artifactsDir,
|
|
734
|
+
stepKind: "confirm_intent",
|
|
735
|
+
status: "ready",
|
|
736
|
+
runId: null,
|
|
737
|
+
allowedCommands: [continueCommand],
|
|
738
|
+
stopCondition: "Write intent_checkpoint.json with the confirmed scope and intent, then run next-step.",
|
|
739
|
+
repoRoot: root,
|
|
740
|
+
artifactPaths: {
|
|
741
|
+
intent_checkpoint: intentCheckpointPath,
|
|
742
|
+
},
|
|
743
|
+
prompt: renderConfirmIntentPrompt(preDigest, {
|
|
744
|
+
intentCheckpointPath,
|
|
569
745
|
continueCommand,
|
|
570
|
-
|
|
571
|
-
})
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
"",
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
"An EMPTY findings array is the deliberate loop terminator (this round found nothing new).",
|
|
653
|
-
"",
|
|
654
|
-
"When the result file exists, run:",
|
|
655
|
-
"",
|
|
656
|
-
` ${continueCommand}`,
|
|
657
|
-
"",
|
|
658
|
-
"Read and follow only the new step prompt returned by that command.",
|
|
659
|
-
"",
|
|
660
|
-
].join("\n"),
|
|
661
|
-
access: {
|
|
662
|
-
read_paths: [
|
|
663
|
-
...fanout.readPaths,
|
|
664
|
-
join(artifactsDir, "systemic_challenge.json"),
|
|
665
|
-
],
|
|
666
|
-
write_paths: fanout.writePaths,
|
|
667
|
-
},
|
|
668
|
-
submissionShortfall: fanout.shortfall,
|
|
669
|
-
});
|
|
670
|
-
console.log(JSON.stringify(step, null, 2));
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
if (result.kind === "confirm_intent") {
|
|
674
|
-
const intentCheckpointPath = join(artifactsDir, "intent_checkpoint.json");
|
|
675
|
-
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
676
|
-
const preDigest = computeScopePreDigest(result.bundle, root, getFlag(argv, "--since"));
|
|
677
|
-
const step = await writeCurrentStep({
|
|
678
|
-
artifactsDir,
|
|
679
|
-
stepKind: "confirm_intent",
|
|
680
|
-
status: "ready",
|
|
681
|
-
runId: null,
|
|
682
|
-
allowedCommands: [continueCommand],
|
|
683
|
-
stopCondition: "Write intent_checkpoint.json with the confirmed scope and intent, then run next-step.",
|
|
684
|
-
repoRoot: root,
|
|
685
|
-
artifactPaths: {
|
|
686
|
-
intent_checkpoint: intentCheckpointPath,
|
|
746
|
+
unresolvedConstraintClauses: unresolvedConstraintClauses(result.bundle.intent_checkpoint),
|
|
747
|
+
}),
|
|
748
|
+
});
|
|
749
|
+
});
|
|
750
|
+
const emitAnalyzerConsent = emissionRow(async ({ root, artifactsDir, analyzerPolicy }, result) => {
|
|
751
|
+
// Acquisition-bearing row: the durable policy must have loaded.
|
|
752
|
+
requireLoadedAnalyzerPolicy(analyzerPolicy, "analyzer_consent");
|
|
753
|
+
const decisionsPath = laneSubmissionPath(artifactsDir, GATE_LANES.analyzer_consent);
|
|
754
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
755
|
+
const consentPrompt = renderAnalyzerConsentPrompt({
|
|
756
|
+
pending: result.pending,
|
|
757
|
+
decisionsPath,
|
|
758
|
+
continueCommand,
|
|
759
|
+
});
|
|
760
|
+
const shortfall = await recordExpectedLanes(artifactsDir, AUDIT_GATE_SUBMISSION_SCOPE, [{ lane: GATE_LANES.analyzer_consent, promptText: consentPrompt }]);
|
|
761
|
+
return currentStepPlan({
|
|
762
|
+
artifactsDir,
|
|
763
|
+
stepKind: "analyzer_consent",
|
|
764
|
+
status: "ready",
|
|
765
|
+
runId: null,
|
|
766
|
+
allowedCommands: [continueCommand],
|
|
767
|
+
stopCondition: "Present the consent offer to the operator, write their decisions to the decisions path, then run next-step.",
|
|
768
|
+
repoRoot: root,
|
|
769
|
+
artifactPaths: {
|
|
770
|
+
analyzer_consent_decisions: decisionsPath,
|
|
771
|
+
},
|
|
772
|
+
prompt: [...renderLaneShortfallLines(shortfall), consentPrompt].join("\n"),
|
|
773
|
+
submissionShortfall: shortfall,
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
const emitAnalyzerInstall = emissionRow(async ({ root, artifactsDir, analyzerPolicy }, result) => {
|
|
777
|
+
// Acquisition-bearing row: the durable policy must have loaded.
|
|
778
|
+
requireLoadedAnalyzerPolicy(analyzerPolicy, "analyzer_install");
|
|
779
|
+
const decisionsPath = laneSubmissionPath(artifactsDir, GATE_LANES.analyzer_decisions);
|
|
780
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
781
|
+
const installPrompt = renderAnalyzerInstallPrompt({
|
|
782
|
+
unresolved: result.unresolved,
|
|
783
|
+
decisionsPath,
|
|
784
|
+
continueCommand,
|
|
785
|
+
});
|
|
786
|
+
const shortfall = await recordExpectedLanes(artifactsDir, AUDIT_GATE_SUBMISSION_SCOPE, [{ lane: GATE_LANES.analyzer_decisions, promptText: installPrompt }]);
|
|
787
|
+
return currentStepPlan({
|
|
788
|
+
artifactsDir,
|
|
789
|
+
stepKind: "analyzer_install",
|
|
790
|
+
status: "ready",
|
|
791
|
+
runId: null,
|
|
792
|
+
allowedCommands: [continueCommand],
|
|
793
|
+
stopCondition: "Write analyzer install decisions to the results path, then run next-step.",
|
|
794
|
+
repoRoot: root,
|
|
795
|
+
artifactPaths: {
|
|
796
|
+
analyzer_decisions: decisionsPath,
|
|
797
|
+
},
|
|
798
|
+
prompt: [...renderLaneShortfallLines(shortfall), installPrompt].join("\n"),
|
|
799
|
+
submissionShortfall: shortfall,
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
const emitEdgeReasoning = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
803
|
+
const edgeReasoningResultsPath = laneSubmissionPath(artifactsDir, GATE_LANES.edge_reasoning);
|
|
804
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
805
|
+
const basePrompt = buildEdgeReasoningPrompt(result.candidates);
|
|
806
|
+
const contentHash = edgeReasoningContentHash(result.candidates);
|
|
807
|
+
// A prior malformed submission was quarantined (not silently destroyed) —
|
|
808
|
+
// name it and the shape error in the re-emitted prompt so the producer
|
|
809
|
+
// fixes the shape instead of resubmitting the same honest mistake forever.
|
|
810
|
+
const rejectionNotice = await renderEdgeReasoningRejectionNotice(artifactsDir);
|
|
811
|
+
// Always-materialized (design resolution 2): the (potentially large)
|
|
812
|
+
// edge-list prompt lives in a lane file on every host — a subagent-capable
|
|
813
|
+
// host fans it out, any other host reads and follows the same file itself.
|
|
814
|
+
// The retired inline `edge_reasoning` step kind was this branch's other
|
|
815
|
+
// arm. Routed through the same lane materializer as every other fan-out
|
|
816
|
+
// step so the K-of-N/result-exists semantics stay single-sourced.
|
|
817
|
+
const fanout = await materializeFanoutLanes({
|
|
818
|
+
artifactsDir,
|
|
819
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
820
|
+
lanes: [
|
|
821
|
+
{
|
|
822
|
+
id: GATE_LANES.edge_reasoning,
|
|
823
|
+
label: "Edge-reasoning rewrites",
|
|
824
|
+
promptFilename: "edge-reasoning-prompt.md",
|
|
825
|
+
promptText: rejectionNotice
|
|
826
|
+
? `${basePrompt}\n\n${rejectionNotice}`
|
|
827
|
+
: basePrompt,
|
|
687
828
|
},
|
|
688
|
-
|
|
689
|
-
|
|
829
|
+
],
|
|
830
|
+
});
|
|
831
|
+
const edgeReasoningPromptPath = fanout.lanes[0].promptPath;
|
|
832
|
+
const shortfallLines = renderLaneShortfallLines(fanout.shortfall);
|
|
833
|
+
return currentStepPlan({
|
|
834
|
+
artifactsDir,
|
|
835
|
+
stepKind: "edge_reasoning_dispatch",
|
|
836
|
+
status: "ready",
|
|
837
|
+
runId: null,
|
|
838
|
+
allowedCommands: [continueCommand],
|
|
839
|
+
stopCondition: "Execute the edge-reasoning lane prompt (subagent if available, else yourself), write the rewrites to the results path, then run next-step.",
|
|
840
|
+
repoRoot: root,
|
|
841
|
+
artifactPaths: fanout.artifactPaths,
|
|
842
|
+
prompt: [
|
|
843
|
+
...shortfallLines,
|
|
844
|
+
renderEdgeReasoningDispatchPrompt({
|
|
845
|
+
promptPath: edgeReasoningPromptPath,
|
|
846
|
+
resultsPath: edgeReasoningResultsPath,
|
|
690
847
|
continueCommand,
|
|
691
|
-
|
|
848
|
+
contentHash,
|
|
849
|
+
candidateCount: result.candidates.length,
|
|
692
850
|
}),
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
analyzer_decisions: decisionsPath,
|
|
742
|
-
},
|
|
743
|
-
prompt: [...renderLaneShortfallLines(shortfall), installPrompt].join("\n"),
|
|
744
|
-
submissionShortfall: shortfall,
|
|
745
|
-
});
|
|
746
|
-
console.log(JSON.stringify(step, null, 2));
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
if (result.kind === "edge_reasoning") {
|
|
750
|
-
const edgeReasoningResultsPath = laneSubmissionPath(artifactsDir, GATE_LANES.edge_reasoning);
|
|
751
|
-
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
752
|
-
const basePrompt = buildEdgeReasoningPrompt(result.candidates);
|
|
753
|
-
const contentHash = edgeReasoningContentHash(result.candidates);
|
|
754
|
-
// A prior malformed submission was quarantined (not silently destroyed) —
|
|
755
|
-
// name it and the shape error in the re-emitted prompt so the producer
|
|
756
|
-
// fixes the shape instead of resubmitting the same honest mistake forever.
|
|
757
|
-
const rejectionNotice = await renderEdgeReasoningRejectionNotice(artifactsDir);
|
|
758
|
-
// Always-materialized (design resolution 2): the (potentially large)
|
|
759
|
-
// edge-list prompt lives in a lane file on every host — a subagent-capable
|
|
760
|
-
// host fans it out, any other host reads and follows the same file itself.
|
|
761
|
-
// The retired inline `edge_reasoning` step kind was this branch's other
|
|
762
|
-
// arm. Routed through the same lane materializer as every other fan-out
|
|
763
|
-
// step so the K-of-N/result-exists semantics stay single-sourced.
|
|
764
|
-
const fanout = await materializeFanoutLanes({
|
|
765
|
-
artifactsDir,
|
|
766
|
-
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
767
|
-
lanes: [
|
|
768
|
-
{
|
|
769
|
-
id: GATE_LANES.edge_reasoning,
|
|
770
|
-
label: "Edge-reasoning rewrites",
|
|
771
|
-
promptFilename: "edge-reasoning-prompt.md",
|
|
772
|
-
promptText: rejectionNotice
|
|
773
|
-
? `${basePrompt}\n\n${rejectionNotice}`
|
|
774
|
-
: basePrompt,
|
|
775
|
-
},
|
|
776
|
-
],
|
|
777
|
-
});
|
|
778
|
-
const edgeReasoningPromptPath = fanout.lanes[0].promptPath;
|
|
779
|
-
const shortfallLines = renderLaneShortfallLines(fanout.shortfall);
|
|
780
|
-
const step = await writeCurrentStep({
|
|
781
|
-
artifactsDir,
|
|
782
|
-
stepKind: "edge_reasoning_dispatch",
|
|
783
|
-
status: "ready",
|
|
784
|
-
runId: null,
|
|
785
|
-
allowedCommands: [continueCommand],
|
|
786
|
-
stopCondition: "Execute the edge-reasoning lane prompt (subagent if available, else yourself), write the rewrites to the results path, then run next-step.",
|
|
787
|
-
repoRoot: root,
|
|
788
|
-
artifactPaths: fanout.artifactPaths,
|
|
789
|
-
prompt: [
|
|
790
|
-
...shortfallLines,
|
|
791
|
-
renderEdgeReasoningDispatchPrompt({
|
|
792
|
-
promptPath: edgeReasoningPromptPath,
|
|
793
|
-
resultsPath: edgeReasoningResultsPath,
|
|
794
|
-
continueCommand,
|
|
795
|
-
contentHash,
|
|
796
|
-
candidateCount: result.candidates.length,
|
|
797
|
-
}),
|
|
798
|
-
].join("\n"),
|
|
799
|
-
access: {
|
|
800
|
-
read_paths: [edgeReasoningPromptPath],
|
|
801
|
-
write_paths: [edgeReasoningResultsPath],
|
|
802
|
-
},
|
|
803
|
-
submissionShortfall: fanout.shortfall,
|
|
804
|
-
});
|
|
805
|
-
console.log(JSON.stringify(step, null, 2));
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
if (result.kind === "intent_equivalence") {
|
|
809
|
-
const verdictPath = laneSubmissionPath(artifactsDir, GATE_LANES.intent_equivalence);
|
|
810
|
-
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
811
|
-
const status = deriveIntentEquivalenceStatus(result.bundle);
|
|
812
|
-
const pending = status.kind === "prose_judgment_pending" ? status : undefined;
|
|
813
|
-
const fullPrompt = [
|
|
814
|
-
"# Intent-equivalence judgment (bounded)",
|
|
815
|
-
"",
|
|
816
|
-
"The intent checkpoint's PROSE changed since the planning artifacts derived",
|
|
817
|
-
"(structured fields are identical — this is wording only). Judge whether the",
|
|
818
|
-
"two prose forms express the SAME audit intent. Judge STRICTLY: any change",
|
|
819
|
-
"in scope, emphasis, constraint, or goal — however small — is `changed`.",
|
|
820
|
-
"Only pure rephrasing (wording, ordering, formatting) is `equivalent`.",
|
|
821
|
-
"An `equivalent` verdict keeps every planning artifact fresh; `changed`",
|
|
822
|
-
"re-derives the planning cascade against the new intent.",
|
|
823
|
-
"",
|
|
824
|
-
"## Prior prose normal form (what planning derived against)",
|
|
825
|
-
"",
|
|
826
|
-
"```json",
|
|
827
|
-
pending?.prior_prose ?? "(unavailable — re-run next-step)",
|
|
828
|
-
"```",
|
|
829
|
-
"",
|
|
830
|
-
"## Current prose normal form",
|
|
831
|
-
"",
|
|
832
|
-
"```json",
|
|
833
|
-
pending?.current_prose ?? "(unavailable — re-run next-step)",
|
|
834
|
-
"```",
|
|
835
|
-
"",
|
|
836
|
-
"## Verdict contract",
|
|
837
|
-
"",
|
|
838
|
-
"Write EXACTLY this JSON object (no extra fields) to:",
|
|
839
|
-
"",
|
|
840
|
-
` ${verdictPath}`,
|
|
841
|
-
"",
|
|
842
|
-
"```json",
|
|
843
|
-
JSON.stringify({
|
|
844
|
-
verdict: "equivalent | changed",
|
|
845
|
-
judged_pair: {
|
|
846
|
-
prior_hash: pending?.prior_hash ?? "",
|
|
847
|
-
new_hash: pending?.new_hash ?? "",
|
|
848
|
-
},
|
|
849
|
-
}, null, 2),
|
|
850
|
-
"```",
|
|
851
|
-
"",
|
|
852
|
-
"`judged_pair` must carry the two hashes shown above verbatim — they bind",
|
|
853
|
-
"the verdict to this exact pair; a checkpoint edited again mid-judgment is",
|
|
854
|
-
"detected and re-judged.",
|
|
855
|
-
"",
|
|
856
|
-
`Then run: ${continueCommand}`,
|
|
857
|
-
"",
|
|
858
|
-
].join("\n");
|
|
859
|
-
const shortfall = await recordExpectedLanes(artifactsDir, AUDIT_GATE_SUBMISSION_SCOPE, [{ lane: GATE_LANES.intent_equivalence, promptText: fullPrompt }]);
|
|
860
|
-
const step = await writeCurrentStep({
|
|
861
|
-
artifactsDir,
|
|
862
|
-
stepKind: "intent_equivalence",
|
|
863
|
-
status: "ready",
|
|
864
|
-
runId: null,
|
|
865
|
-
allowedCommands: [continueCommand],
|
|
866
|
-
stopCondition: "Write the equivalence verdict to the results path, then run next-step.",
|
|
867
|
-
repoRoot: root,
|
|
868
|
-
artifactPaths: {
|
|
869
|
-
intent_equivalence_verdict: verdictPath,
|
|
870
|
-
},
|
|
871
|
-
prompt: [...renderLaneShortfallLines(shortfall), fullPrompt].join("\n"),
|
|
872
|
-
access: {
|
|
873
|
-
read_paths: [],
|
|
874
|
-
write_paths: [verdictPath],
|
|
851
|
+
].join("\n"),
|
|
852
|
+
access: {
|
|
853
|
+
read_paths: [edgeReasoningPromptPath],
|
|
854
|
+
write_paths: [edgeReasoningResultsPath],
|
|
855
|
+
},
|
|
856
|
+
submissionShortfall: fanout.shortfall,
|
|
857
|
+
});
|
|
858
|
+
});
|
|
859
|
+
const emitIntentEquivalence = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
860
|
+
const verdictPath = laneSubmissionPath(artifactsDir, GATE_LANES.intent_equivalence);
|
|
861
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
862
|
+
const status = deriveIntentEquivalenceStatus(result.bundle);
|
|
863
|
+
const pending = status.kind === "prose_judgment_pending" ? status : undefined;
|
|
864
|
+
const fullPrompt = [
|
|
865
|
+
"# Intent-equivalence judgment (bounded)",
|
|
866
|
+
"",
|
|
867
|
+
"The intent checkpoint's PROSE changed since the planning artifacts derived",
|
|
868
|
+
"(structured fields are identical — this is wording only). Judge whether the",
|
|
869
|
+
"two prose forms express the SAME audit intent. Judge STRICTLY: any change",
|
|
870
|
+
"in scope, emphasis, constraint, or goal — however small — is `changed`.",
|
|
871
|
+
"Only pure rephrasing (wording, ordering, formatting) is `equivalent`.",
|
|
872
|
+
"An `equivalent` verdict keeps every planning artifact fresh; `changed`",
|
|
873
|
+
"re-derives the planning cascade against the new intent.",
|
|
874
|
+
"",
|
|
875
|
+
"## Prior prose normal form (what planning derived against)",
|
|
876
|
+
"",
|
|
877
|
+
"```json",
|
|
878
|
+
pending?.prior_prose ?? "(unavailable — re-run next-step)",
|
|
879
|
+
"```",
|
|
880
|
+
"",
|
|
881
|
+
"## Current prose normal form",
|
|
882
|
+
"",
|
|
883
|
+
"```json",
|
|
884
|
+
pending?.current_prose ?? "(unavailable — re-run next-step)",
|
|
885
|
+
"```",
|
|
886
|
+
"",
|
|
887
|
+
"## Verdict contract",
|
|
888
|
+
"",
|
|
889
|
+
"Write EXACTLY this JSON object (no extra fields) to:",
|
|
890
|
+
"",
|
|
891
|
+
` ${verdictPath}`,
|
|
892
|
+
"",
|
|
893
|
+
"```json",
|
|
894
|
+
JSON.stringify({
|
|
895
|
+
verdict: "equivalent | changed",
|
|
896
|
+
judged_pair: {
|
|
897
|
+
prior_hash: pending?.prior_hash ?? "",
|
|
898
|
+
new_hash: pending?.new_hash ?? "",
|
|
875
899
|
},
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
],
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
"",
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
` ${fallbackResultsPath}`,
|
|
926
|
-
"",
|
|
927
|
-
"When the result file exists, run:",
|
|
928
|
-
"",
|
|
929
|
-
` ${continueCommand}`,
|
|
930
|
-
"",
|
|
931
|
-
"Read and follow only the new step prompt returned by that command.",
|
|
932
|
-
"",
|
|
933
|
-
].join("\n"),
|
|
934
|
-
access: {
|
|
935
|
-
read_paths: fanout.readPaths,
|
|
936
|
-
write_paths: fanout.writePaths,
|
|
900
|
+
}, null, 2),
|
|
901
|
+
"```",
|
|
902
|
+
"",
|
|
903
|
+
"`judged_pair` must carry the two hashes shown above verbatim — they bind",
|
|
904
|
+
"the verdict to this exact pair; a checkpoint edited again mid-judgment is",
|
|
905
|
+
"detected and re-judged.",
|
|
906
|
+
"",
|
|
907
|
+
`Then run: ${continueCommand}`,
|
|
908
|
+
"",
|
|
909
|
+
].join("\n");
|
|
910
|
+
const shortfall = await recordExpectedLanes(artifactsDir, AUDIT_GATE_SUBMISSION_SCOPE, [{ lane: GATE_LANES.intent_equivalence, promptText: fullPrompt }]);
|
|
911
|
+
return currentStepPlan({
|
|
912
|
+
artifactsDir,
|
|
913
|
+
stepKind: "intent_equivalence",
|
|
914
|
+
status: "ready",
|
|
915
|
+
runId: null,
|
|
916
|
+
allowedCommands: [continueCommand],
|
|
917
|
+
stopCondition: "Write the equivalence verdict to the results path, then run next-step.",
|
|
918
|
+
repoRoot: root,
|
|
919
|
+
artifactPaths: {
|
|
920
|
+
intent_equivalence_verdict: verdictPath,
|
|
921
|
+
},
|
|
922
|
+
prompt: [...renderLaneShortfallLines(shortfall), fullPrompt].join("\n"),
|
|
923
|
+
access: {
|
|
924
|
+
read_paths: [],
|
|
925
|
+
write_paths: [verdictPath],
|
|
926
|
+
},
|
|
927
|
+
submissionShortfall: shortfall,
|
|
928
|
+
});
|
|
929
|
+
});
|
|
930
|
+
const emitCriticalFlowFallback = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
931
|
+
const fallbackResultsPath = laneSubmissionPath(artifactsDir, GATE_LANES.critical_flow_fallback);
|
|
932
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
933
|
+
const basePrompt = result.bundle.critical_flows
|
|
934
|
+
? renderCriticalFlowFallbackPrompt(result.bundle.critical_flows)
|
|
935
|
+
: "# Critical-flow fallback\n\nNo critical_flows manifest is available; write an empty flows array.";
|
|
936
|
+
// Always-materialized (design resolution 2): the (potentially ~340-line)
|
|
937
|
+
// flow-stub prompt is a lane FILE, never inlined into the step prompt. The
|
|
938
|
+
// results-path section is the lane materializer's, not this emitter's.
|
|
939
|
+
const lanePrompt = basePrompt;
|
|
940
|
+
const fanout = await materializeFanoutLanes({
|
|
941
|
+
artifactsDir,
|
|
942
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
943
|
+
lanes: [
|
|
944
|
+
{
|
|
945
|
+
id: GATE_LANES.critical_flow_fallback,
|
|
946
|
+
label: "Critical-flow fallback enrichment",
|
|
947
|
+
promptFilename: "critical-flow-fallback-prompt.md",
|
|
948
|
+
promptText: lanePrompt,
|
|
937
949
|
},
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
"",
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
read_paths: fanout.readPaths,
|
|
999
|
-
write_paths: fanout.writePaths,
|
|
950
|
+
],
|
|
951
|
+
});
|
|
952
|
+
return currentStepPlan({
|
|
953
|
+
artifactsDir,
|
|
954
|
+
stepKind: "critical_flow_fallback",
|
|
955
|
+
status: "ready",
|
|
956
|
+
runId: null,
|
|
957
|
+
allowedCommands: [continueCommand],
|
|
958
|
+
stopCondition: "Execute the critical-flow lane prompt (subagent if available, else yourself), write the enrichment to the results path, then run next-step.",
|
|
959
|
+
repoRoot: root,
|
|
960
|
+
artifactPaths: fanout.artifactPaths,
|
|
961
|
+
prompt: [
|
|
962
|
+
"# audit-code critical-flow fallback",
|
|
963
|
+
"",
|
|
964
|
+
...renderLaneShortfallLines(fanout.shortfall),
|
|
965
|
+
...renderFanoutExecutionLines({
|
|
966
|
+
lanes: fanout.pendingLanes.map((lane) => ({
|
|
967
|
+
label: lane.label,
|
|
968
|
+
promptPath: lane.promptPath,
|
|
969
|
+
})),
|
|
970
|
+
}),
|
|
971
|
+
"",
|
|
972
|
+
"The executor must write the CriticalFlowFallbackResult JSON object to:",
|
|
973
|
+
"",
|
|
974
|
+
` ${fallbackResultsPath}`,
|
|
975
|
+
"",
|
|
976
|
+
"When the result file exists, run:",
|
|
977
|
+
"",
|
|
978
|
+
` ${continueCommand}`,
|
|
979
|
+
"",
|
|
980
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
981
|
+
"",
|
|
982
|
+
].join("\n"),
|
|
983
|
+
access: {
|
|
984
|
+
read_paths: fanout.readPaths,
|
|
985
|
+
write_paths: fanout.writePaths,
|
|
986
|
+
},
|
|
987
|
+
submissionShortfall: fanout.shortfall,
|
|
988
|
+
});
|
|
989
|
+
});
|
|
990
|
+
const emitSynthesisNarrative = emissionRow(async ({ root, artifactsDir }, result) => {
|
|
991
|
+
const narrativeResultsPath = laneSubmissionPath(artifactsDir, GATE_LANES.synthesis_narrative);
|
|
992
|
+
const continueCommand = nextStepCommand(root, artifactsDir);
|
|
993
|
+
const basePrompt = result.bundle.audit_findings
|
|
994
|
+
? renderSynthesisNarrativePrompt(result.bundle.audit_findings)
|
|
995
|
+
: "# Synthesis narrative\n\nNo findings report is available; write an empty themes array.";
|
|
996
|
+
// Always-materialized (design resolution 2): the findings digest (up to 120
|
|
997
|
+
// findings) is a lane FILE, never inlined into the step prompt. This step
|
|
998
|
+
// previously carried no access block at all — the lane form declares one.
|
|
999
|
+
// The results-path section is the lane materializer's, not this emitter's.
|
|
1000
|
+
const lanePrompt = basePrompt;
|
|
1001
|
+
const fanout = await materializeFanoutLanes({
|
|
1002
|
+
artifactsDir,
|
|
1003
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
1004
|
+
lanes: [
|
|
1005
|
+
{
|
|
1006
|
+
id: GATE_LANES.synthesis_narrative,
|
|
1007
|
+
label: "Synthesis narrative (themes / exec summary / top risks)",
|
|
1008
|
+
promptFilename: "synthesis-narrative-prompt.md",
|
|
1009
|
+
promptText: lanePrompt,
|
|
1000
1010
|
},
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
const step = await renderSemanticReviewStep({
|
|
1007
|
-
root,
|
|
1011
|
+
],
|
|
1012
|
+
});
|
|
1013
|
+
return currentStepPlan({
|
|
1008
1014
|
artifactsDir,
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1015
|
+
stepKind: "synthesis_narrative",
|
|
1016
|
+
status: "ready",
|
|
1017
|
+
runId: null,
|
|
1018
|
+
allowedCommands: [continueCommand],
|
|
1019
|
+
stopCondition: "Execute the synthesis-narrative lane prompt (subagent if available, else yourself), write the narrative to the results path, then run next-step.",
|
|
1020
|
+
repoRoot: root,
|
|
1021
|
+
artifactPaths: fanout.artifactPaths,
|
|
1022
|
+
prompt: [
|
|
1023
|
+
"# audit-code synthesis narrative",
|
|
1024
|
+
"",
|
|
1025
|
+
...renderLaneShortfallLines(fanout.shortfall),
|
|
1026
|
+
...renderFanoutExecutionLines({
|
|
1027
|
+
lanes: fanout.pendingLanes.map((lane) => ({
|
|
1028
|
+
label: lane.label,
|
|
1029
|
+
promptPath: lane.promptPath,
|
|
1030
|
+
})),
|
|
1031
|
+
}),
|
|
1032
|
+
"",
|
|
1033
|
+
"The executor must write the SynthesisNarrative JSON object to:",
|
|
1034
|
+
"",
|
|
1035
|
+
` ${narrativeResultsPath}`,
|
|
1036
|
+
"",
|
|
1037
|
+
"When the result file exists, run:",
|
|
1038
|
+
"",
|
|
1039
|
+
` ${continueCommand}`,
|
|
1040
|
+
"",
|
|
1041
|
+
"Read and follow only the new step prompt returned by that command.",
|
|
1042
|
+
"",
|
|
1043
|
+
].join("\n"),
|
|
1044
|
+
access: {
|
|
1045
|
+
read_paths: fanout.readPaths,
|
|
1046
|
+
write_paths: fanout.writePaths,
|
|
1047
|
+
},
|
|
1048
|
+
submissionShortfall: fanout.shortfall,
|
|
1013
1049
|
});
|
|
1014
|
-
|
|
1015
|
-
|
|
1050
|
+
});
|
|
1051
|
+
/**
|
|
1052
|
+
* The step-emission dispatch table: exactly one row per host-actionable result
|
|
1053
|
+
* kind. Typed as a TOTAL record over the kind union, so a kind added upstream
|
|
1054
|
+
* with no row here is a compile error rather than a step that silently falls
|
|
1055
|
+
* through to the semantic-review dispatch.
|
|
1056
|
+
*
|
|
1057
|
+
* Exported together with the handled-kinds set below so a drift guard imports
|
|
1058
|
+
* the real thing instead of reconstructing it by reading a branch chain.
|
|
1059
|
+
*/
|
|
1060
|
+
export const NEXT_STEP_EMISSION_TABLE = {
|
|
1061
|
+
complete: emitComplete,
|
|
1062
|
+
blocked: emitBlocked,
|
|
1063
|
+
design_review_parallel: emitDesignReviewParallel,
|
|
1064
|
+
design_review_contract: emitDesignReviewContract,
|
|
1065
|
+
design_review_conceptual: emitDesignReviewConceptual,
|
|
1066
|
+
charter_extraction: emitCharterExtraction,
|
|
1067
|
+
charter_delta: emitCharterDelta,
|
|
1068
|
+
charter_clarification: emitCharterClarification,
|
|
1069
|
+
systemic_challenge: emitSystemicChallenge,
|
|
1070
|
+
confirm_intent: emitConfirmIntent,
|
|
1071
|
+
analyzer_consent: emitAnalyzerConsent,
|
|
1072
|
+
analyzer_install: emitAnalyzerInstall,
|
|
1073
|
+
edge_reasoning: emitEdgeReasoning,
|
|
1074
|
+
intent_equivalence: emitIntentEquivalence,
|
|
1075
|
+
critical_flow_fallback: emitCriticalFlowFallback,
|
|
1076
|
+
synthesis_narrative: emitSynthesisNarrative,
|
|
1077
|
+
};
|
|
1078
|
+
/**
|
|
1079
|
+
* The one emission site for `audit-code next-step`. Rows return plans; this
|
|
1080
|
+
* writes and logs exactly once, whichever row (or the fallback) produced it.
|
|
1081
|
+
*/
|
|
1082
|
+
const NEXT_STEP_EMISSION = createStepEmissionScaffold({
|
|
1083
|
+
table: NEXT_STEP_EMISSION_TABLE,
|
|
1084
|
+
// `semantic_review` is deliberately the FALLBACK rather than a row: the
|
|
1085
|
+
// validation boundary here has always been "anything unmatched is a
|
|
1086
|
+
// semantic-review dispatch", never an error on an unrecognized kind.
|
|
1087
|
+
fallback: (ctx) => {
|
|
1088
|
+
const result = ctx.result;
|
|
1089
|
+
return semanticReviewPlan({
|
|
1090
|
+
root: ctx.root,
|
|
1091
|
+
artifactsDir: ctx.artifactsDir,
|
|
1092
|
+
activeReviewRun: result.activeReviewRun,
|
|
1093
|
+
selectedExecutor: result.selectedExecutor,
|
|
1094
|
+
inProcessMadeProgress: result.inProcessMadeProgress,
|
|
1095
|
+
ingestIssues: result.ingestIssues,
|
|
1096
|
+
});
|
|
1097
|
+
},
|
|
1098
|
+
write: writeAuditStep,
|
|
1099
|
+
// The tool's only externally-observable per-invocation contract.
|
|
1100
|
+
log: (step) => {
|
|
1101
|
+
console.log(JSON.stringify(step, null, 2));
|
|
1102
|
+
},
|
|
1103
|
+
});
|
|
1104
|
+
/**
|
|
1105
|
+
* The handled-kinds set, DERIVED from the table's own keys — never a second,
|
|
1106
|
+
* hand-listed copy that could disagree with the table it describes. A drift
|
|
1107
|
+
* guard consumes this as the real B side of its seam assertion.
|
|
1108
|
+
*/
|
|
1109
|
+
export const NEXT_STEP_EMISSION_KINDS = NEXT_STEP_EMISSION.handledKeys;
|
|
1016
1110
|
//# sourceMappingURL=nextStepCommand.js.map
|