audit-tools 0.35.1 → 0.35.5
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/audit/cli/nextStepHelpers.d.ts.map +1 -1
- package/dist/audit/cli/nextStepHelpers.js +85 -10
- package/dist/audit/cli/nextStepHelpers.js.map +1 -1
- package/dist/audit/orchestrator/partitionTaskGraph.d.ts +11 -0
- package/dist/audit/orchestrator/partitionTaskGraph.d.ts.map +1 -1
- package/dist/audit/orchestrator/partitionTaskGraph.js +4 -1
- package/dist/audit/orchestrator/partitionTaskGraph.js.map +1 -1
- package/dist/audit/orchestrator/reviewPackets.d.ts +6 -0
- package/dist/audit/orchestrator/reviewPackets.d.ts.map +1 -1
- package/dist/audit/orchestrator/reviewPackets.js +1 -0
- package/dist/audit/orchestrator/reviewPackets.js.map +1 -1
- package/dist/audit/reporting/mergeFindings.d.ts.map +1 -1
- package/dist/audit/reporting/mergeFindings.js +3 -0
- package/dist/audit/reporting/mergeFindings.js.map +1 -1
- package/dist/audit/reporting/synthesis.d.ts +8 -5
- package/dist/audit/reporting/synthesis.d.ts.map +1 -1
- package/dist/audit/reporting/synthesis.js +21 -10
- package/dist/audit/reporting/synthesis.js.map +1 -1
- package/dist/audit/reporting/synthesisNarrativePrompt.js +1 -1
- package/dist/audit/reporting/synthesisNarrativePrompt.js.map +1 -1
- package/dist/remediate/dedup/crossLensDedup.d.ts +12 -0
- package/dist/remediate/dedup/crossLensDedup.d.ts.map +1 -1
- package/dist/remediate/dedup/crossLensDedup.js +29 -4
- package/dist/remediate/dedup/crossLensDedup.js.map +1 -1
- package/dist/remediate/intake.d.ts +1 -1
- package/dist/remediate/intake.d.ts.map +1 -1
- package/dist/remediate/intake.js +11 -1
- package/dist/remediate/intake.js.map +1 -1
- package/dist/remediate/phases/plan.d.ts +8 -4
- package/dist/remediate/phases/plan.d.ts.map +1 -1
- package/dist/remediate/phases/plan.js +10 -6
- package/dist/remediate/phases/plan.js.map +1 -1
- package/dist/remediate/phases/triage.d.ts.map +1 -1
- package/dist/remediate/phases/triage.js +1 -1
- package/dist/remediate/phases/triage.js.map +1 -1
- package/dist/remediate/review/reviewGate.d.ts +14 -0
- package/dist/remediate/review/reviewGate.d.ts.map +1 -1
- package/dist/remediate/review/reviewGate.js +37 -0
- package/dist/remediate/review/reviewGate.js.map +1 -1
- package/dist/remediate/steps/dispatch/implementPrompt.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/implementPrompt.js +3 -1
- package/dist/remediate/steps/dispatch/implementPrompt.js.map +1 -1
- package/dist/remediate/steps/dispatch/marshal.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/marshal.js +65 -31
- package/dist/remediate/steps/dispatch/marshal.js.map +1 -1
- package/dist/remediate/steps/dispatch/writeScope.d.ts +10 -17
- package/dist/remediate/steps/dispatch/writeScope.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/writeScope.js +16 -57
- package/dist/remediate/steps/dispatch/writeScope.js.map +1 -1
- package/dist/remediate/steps/dispatch.d.ts +1 -1
- package/dist/remediate/steps/dispatch.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch.js +1 -1
- package/dist/remediate/steps/dispatch.js.map +1 -1
- package/dist/remediate/steps/intakeResolver.d.ts.map +1 -1
- package/dist/remediate/steps/intakeResolver.js +1 -1
- package/dist/remediate/steps/intakeResolver.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +90 -18
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/remediate/steps/prompts.d.ts +3 -3
- package/dist/remediate/steps/prompts.d.ts.map +1 -1
- package/dist/remediate/steps/prompts.js +43 -9
- package/dist/remediate/steps/prompts.js.map +1 -1
- package/dist/remediate/validation/remediationState.d.ts +1 -1
- package/dist/remediate/validation/remediationState.d.ts.map +1 -1
- package/dist/remediate/validation/remediationState.js +8 -1
- package/dist/remediate/validation/remediationState.js.map +1 -1
- package/dist/shared/decompose/modularity.d.ts.map +1 -1
- package/dist/shared/decompose/modularity.js +101 -37
- package/dist/shared/decompose/modularity.js.map +1 -1
- package/dist/shared/dispatch/providerLaunchFinalize.d.ts.map +1 -1
- package/dist/shared/dispatch/providerLaunchFinalize.js +23 -3
- package/dist/shared/dispatch/providerLaunchFinalize.js.map +1 -1
- package/dist/shared/findings/dedupe.d.ts +29 -0
- package/dist/shared/findings/dedupe.d.ts.map +1 -1
- package/dist/shared/findings/dedupe.js +74 -3
- package/dist/shared/findings/dedupe.js.map +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/validation/findingsReport.d.ts +25 -33
- package/dist/shared/validation/findingsReport.d.ts.map +1 -1
- package/dist/shared/validation/findingsReport.js +237 -57
- package/dist/shared/validation/findingsReport.js.map +1 -1
- package/dist/shared/validation/sessionConfig.d.ts.map +1 -1
- package/dist/shared/validation/sessionConfig.js +4 -1
- package/dist/shared/validation/sessionConfig.js.map +1 -1
- package/package.json +1 -1
|
@@ -37,7 +37,7 @@ import { resolveIntakeStep } from "./intakeResolver.js";
|
|
|
37
37
|
import { runToolOwnedFinalGate, applyCoarseReblock, readFinalGateSidecar, writeFinalGateSidecar, } from "./finalGate.js";
|
|
38
38
|
import { buildNextContractPipelineStep, shouldEnterContractPipeline, writePathASeedFromFindings, buildLeanExtractedPlan, } from "./contractPipeline.js";
|
|
39
39
|
import { contractArtifactExists, contractPipelineDir, } from "../contractPipeline/artifactStore.js";
|
|
40
|
-
import { buildReviewRequest, applyReviewResolution, isResolutionForRequest, REVIEW_REQUEST_SCHEMA_VERSION, } from "../review/reviewGate.js";
|
|
40
|
+
import { buildReviewRequest, applyReviewResolution, isResolutionForRequest, screenResolutionIds, REVIEW_REQUEST_SCHEMA_VERSION, } from "../review/reviewGate.js";
|
|
41
41
|
import { buildAutonomousReviewDecision } from "../review/autonomousGate.js";
|
|
42
42
|
import { runFindingFilterPass } from "../findingFilter.js";
|
|
43
43
|
import { intakePaths, isIntakeReady, readIntakeArtifacts, resolveManifestSources, } from "../intake.js";
|
|
@@ -1074,13 +1074,11 @@ function stripPlanTimeBookkeeping(value) {
|
|
|
1074
1074
|
function findingCarryForwardKey(finding) {
|
|
1075
1075
|
return JSON.stringify(stripPlanTimeBookkeeping(finding));
|
|
1076
1076
|
}
|
|
1077
|
-
//
|
|
1078
|
-
//
|
|
1079
|
-
//
|
|
1080
|
-
//
|
|
1081
|
-
//
|
|
1082
|
-
// whether a finding should ever belong to two blocks at all — is tracked in
|
|
1083
|
-
// docs/backlog/open-bugs.md.
|
|
1077
|
+
// Single-block membership is enforced by `fixupBlocksAfterDedup` (each finding
|
|
1078
|
+
// id appears in exactly one block's items after fixup), so this scan is a plain
|
|
1079
|
+
// projection. First-wins in block order is kept as the tie-break for defense in
|
|
1080
|
+
// depth — it is the same order fixup resolves ownership in, so the two can
|
|
1081
|
+
// never disagree even on a malformed plan.
|
|
1084
1082
|
function blockIdsByFinding(plan) {
|
|
1085
1083
|
const byFinding = new Map();
|
|
1086
1084
|
for (const block of plan.blocks) {
|
|
@@ -2094,14 +2092,14 @@ function extractAuditFindings(parsed) {
|
|
|
2094
2092
|
}
|
|
2095
2093
|
return [];
|
|
2096
2094
|
}
|
|
2097
|
-
async function handleWaitingForReviewApproval(root, artifactsDir, request) {
|
|
2095
|
+
async function handleWaitingForReviewApproval(root, artifactsDir, request, refusal) {
|
|
2098
2096
|
return writeCurrentStep({
|
|
2099
2097
|
stepKind: "collect_review_approval",
|
|
2100
2098
|
status: "blocked",
|
|
2101
2099
|
runId: randomRunId("REVIEW"),
|
|
2102
2100
|
repoRoot: root,
|
|
2103
2101
|
artifactsDir,
|
|
2104
|
-
prompt: reviewApprovalPrompt(request, reviewResolutionPath(artifactsDir)),
|
|
2102
|
+
prompt: reviewApprovalPrompt(request, reviewResolutionPath(artifactsDir), refusal),
|
|
2105
2103
|
allowedCommands: [loaderCommand("next-step")],
|
|
2106
2104
|
stopCondition: "Stop after presenting the findings for approval and collecting the user's approve/disapprove decision, unless the decision is already recorded and the prompt told you to continue.",
|
|
2107
2105
|
artifactPaths: {
|
|
@@ -2110,6 +2108,31 @@ async function handleWaitingForReviewApproval(root, artifactsDir, request) {
|
|
|
2110
2108
|
},
|
|
2111
2109
|
});
|
|
2112
2110
|
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Uniform id-join contract pre-screen for the review gate (both paths): a
|
|
2113
|
+
* resolution naming an unknown finding id or tier is REFUSED whole — archived
|
|
2114
|
+
* (never applied) and the gate re-halts with the refusal and the valid set in
|
|
2115
|
+
* the re-prompt. The gate's default is approve, so the silent-drop alternative
|
|
2116
|
+
* turns a typo'd decline into an approval. Returns the re-halt step, or null
|
|
2117
|
+
* when the resolution's ids are clean. `applyReviewResolution` re-checks as the
|
|
2118
|
+
* mechanical backstop.
|
|
2119
|
+
*/
|
|
2120
|
+
async function refuseUnknownIdResolution(root, artifactsDir, request, resolution, resolutionPath, requestPath) {
|
|
2121
|
+
const screen = screenResolutionIds(request, resolution);
|
|
2122
|
+
if (screen.unknown_finding_ids.length === 0 && screen.unknown_tiers.length === 0) {
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
await withFsRetry(() => rename(resolutionPath, `${resolutionPath}.refused-${Date.now()}`));
|
|
2126
|
+
await writeJsonFile(requestPath, request);
|
|
2127
|
+
const parts = [];
|
|
2128
|
+
if (screen.unknown_finding_ids.length > 0) {
|
|
2129
|
+
parts.push(`finding id(s) not in the request: ${screen.unknown_finding_ids.map((i) => `\`${i}\``).join(", ")}`);
|
|
2130
|
+
}
|
|
2131
|
+
if (screen.unknown_tiers.length > 0) {
|
|
2132
|
+
parts.push(`unknown tier(s): ${screen.unknown_tiers.map((t) => `\`${t}\``).join(", ")}`);
|
|
2133
|
+
}
|
|
2134
|
+
return handleWaitingForReviewApproval(root, artifactsDir, request, parts.join("; "));
|
|
2135
|
+
}
|
|
2113
2136
|
/**
|
|
2114
2137
|
* Run the review-approval gate over the SURVIVOR finding set (already passed
|
|
2115
2138
|
* through the single filter pass: deduped, evidence-bearing, path-grounded,
|
|
@@ -2186,6 +2209,9 @@ async function runReviewApprovalGate(root, artifactsDir, survivors, autonomous =
|
|
|
2186
2209
|
step: await handleWaitingForReviewApproval(root, artifactsDir, request),
|
|
2187
2210
|
};
|
|
2188
2211
|
}
|
|
2212
|
+
const refusalStep = await refuseUnknownIdResolution(root, artifactsDir, request, resolution, resolutionPath, requestPath);
|
|
2213
|
+
if (refusalStep)
|
|
2214
|
+
return { kind: "halt", step: refusalStep };
|
|
2189
2215
|
const decision = applyReviewResolution(request, resolution);
|
|
2190
2216
|
const record = {
|
|
2191
2217
|
schema_version: REVIEW_DECISION_SCHEMA_VERSION,
|
|
@@ -2765,11 +2791,25 @@ function applyClarificationActionToItem(item, res, now) {
|
|
|
2765
2791
|
* Mirrors the triage resolution consume: reject_finding → terminal,
|
|
2766
2792
|
* clarified → re-open (pending) for implement dispatch. Archives the file.
|
|
2767
2793
|
*/
|
|
2768
|
-
async function applyPlanClarificationResolution(artifactsDir, state, store) {
|
|
2794
|
+
async function applyPlanClarificationResolution(root, artifactsDir, state, store) {
|
|
2769
2795
|
if (!state.plan || !state.items)
|
|
2770
|
-
return state;
|
|
2796
|
+
return { kind: "applied", state };
|
|
2771
2797
|
const resolutionPath = join(artifactsDir, "clarification_resolution.json");
|
|
2772
2798
|
const resolutions = normalizePlanClarificationResolutions(await readOptionalJsonFile(resolutionPath));
|
|
2799
|
+
// Uniform id-join contract: an unknown finding_id refuses the WHOLE
|
|
2800
|
+
// resolution (archived, nothing applied) and re-halts with the unknown ids
|
|
2801
|
+
// named — the silent-continue alternative drops the user's answer on a typo'd
|
|
2802
|
+
// id and force-closes its item as abandoned at the fall-through below.
|
|
2803
|
+
const unknownIds = resolutions
|
|
2804
|
+
.map((r) => r.finding_id)
|
|
2805
|
+
.filter((id) => !state.items?.[id]);
|
|
2806
|
+
if (unknownIds.length > 0) {
|
|
2807
|
+
await withFsRetry(() => rename(resolutionPath, `${resolutionPath}.refused-${Date.now()}`));
|
|
2808
|
+
return {
|
|
2809
|
+
kind: "refused",
|
|
2810
|
+
step: await handleWaitingForClarification(root, artifactsDir, state, `finding id(s) not in the plan: ${unknownIds.map((i) => `\`${i}\``).join(", ")}`),
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2773
2813
|
const now = new Date().toISOString();
|
|
2774
2814
|
for (const res of resolutions) {
|
|
2775
2815
|
const item = state.items[res.finding_id];
|
|
@@ -2795,9 +2835,9 @@ async function applyPlanClarificationResolution(artifactsDir, state, store) {
|
|
|
2795
2835
|
state.clarifications = [];
|
|
2796
2836
|
state.closing_plan ??= { action: "none" };
|
|
2797
2837
|
await store.saveState(state);
|
|
2798
|
-
return state;
|
|
2838
|
+
return { kind: "applied", state };
|
|
2799
2839
|
}
|
|
2800
|
-
async function handleWaitingForClarification(root, artifactsDir, state) {
|
|
2840
|
+
async function handleWaitingForClarification(root, artifactsDir, state, refusal) {
|
|
2801
2841
|
const clarifications = state.clarifications ??
|
|
2802
2842
|
(await readOptionalJsonFile(join(artifactsDir, "clarification_request.json"))) ??
|
|
2803
2843
|
[];
|
|
@@ -2808,7 +2848,7 @@ async function handleWaitingForClarification(root, artifactsDir, state) {
|
|
|
2808
2848
|
runId: stateRunId(state),
|
|
2809
2849
|
repoRoot: root,
|
|
2810
2850
|
artifactsDir,
|
|
2811
|
-
prompt: clarificationPrompt(clarifications, resolutionPath),
|
|
2851
|
+
prompt: clarificationPrompt(clarifications, resolutionPath, refusal),
|
|
2812
2852
|
allowedCommands: [loaderCommand("next-step")],
|
|
2813
2853
|
stopCondition: "Stop after asking the user for clarification answers, unless the answers are already available and the prompt told you to continue.",
|
|
2814
2854
|
artifactPaths: {
|
|
@@ -2877,6 +2917,9 @@ async function runPlanningReviewGate(root, artifactsDir, state, store) {
|
|
|
2877
2917
|
await writeJsonFile(requestPath, request);
|
|
2878
2918
|
return handleWaitingForReviewApproval(root, artifactsDir, request);
|
|
2879
2919
|
}
|
|
2920
|
+
const refusalStep = await refuseUnknownIdResolution(root, artifactsDir, request, resolution, resolutionPath, requestPath);
|
|
2921
|
+
if (refusalStep)
|
|
2922
|
+
return refusalStep;
|
|
2880
2923
|
const decision = applyReviewResolution(request, resolution);
|
|
2881
2924
|
const record = {
|
|
2882
2925
|
schema_version: REVIEW_DECISION_SCHEMA_VERSION,
|
|
@@ -2982,7 +3025,7 @@ async function runPlanAmbiguityGate(root, artifactsDir, state, store) {
|
|
|
2982
3025
|
runId: stateRunId(state),
|
|
2983
3026
|
repoRoot: root,
|
|
2984
3027
|
artifactsDir,
|
|
2985
|
-
prompt: ambiguityReviewPrompt(candidates, resolutionPath),
|
|
3028
|
+
prompt: ambiguityReviewPrompt(candidates, resolutionPath, findings.map((f) => f.id)),
|
|
2986
3029
|
allowedCommands: [loaderCommand("next-step")],
|
|
2987
3030
|
stopCondition: "Stop after reviewing the candidate ambiguities (and asking the user any genuine ones), unless the resolution is already written and the prompt told you to continue.",
|
|
2988
3031
|
artifactPaths: {
|
|
@@ -2994,6 +3037,33 @@ async function runPlanAmbiguityGate(root, artifactsDir, state, store) {
|
|
|
2994
3037
|
// Resolution present: apply it to items, mark the gate done, archive inputs so
|
|
2995
3038
|
// it cannot re-halt.
|
|
2996
3039
|
const resolutions = normalizePlanClarificationResolutions(await readOptionalJsonFile(resolutionPath));
|
|
3040
|
+
// Uniform id-join contract: a resolution naming a finding id outside the plan
|
|
3041
|
+
// is REFUSED whole (archived, nothing applied) and the gate re-halts with the
|
|
3042
|
+
// unknown ids named — the silent-continue alternative drops a host answer on a
|
|
3043
|
+
// typo'd id, leaving its item to fall to mid-run triage unexplained.
|
|
3044
|
+
const validIds = new Set(findings.map((f) => f.id));
|
|
3045
|
+
const unknownIds = resolutions
|
|
3046
|
+
.map((r) => r.finding_id)
|
|
3047
|
+
.filter((id) => !validIds.has(id));
|
|
3048
|
+
if (unknownIds.length > 0) {
|
|
3049
|
+
await withFsRetry(() => rename(resolutionPath, `${resolutionPath}.refused-${Date.now()}`));
|
|
3050
|
+
const candidates = (await readOptionalJsonFile(requestPath)) ??
|
|
3051
|
+
detectPlanAmbiguities(findings, state.items);
|
|
3052
|
+
return writeCurrentStep({
|
|
3053
|
+
stepKind: "collect_clarifications",
|
|
3054
|
+
status: "blocked",
|
|
3055
|
+
runId: stateRunId(state),
|
|
3056
|
+
repoRoot: root,
|
|
3057
|
+
artifactsDir,
|
|
3058
|
+
prompt: ambiguityReviewPrompt(candidates, resolutionPath, findings.map((f) => f.id), `finding id(s) not in the plan: ${unknownIds.map((i) => `\`${i}\``).join(", ")}`),
|
|
3059
|
+
allowedCommands: [loaderCommand("next-step")],
|
|
3060
|
+
stopCondition: "Stop after re-submitting a corrected ambiguity resolution, unless it is already written and the prompt told you to continue.",
|
|
3061
|
+
artifactPaths: {
|
|
3062
|
+
ambiguity_request: requestPath,
|
|
3063
|
+
ambiguity_resolution: resolutionPath,
|
|
3064
|
+
},
|
|
3065
|
+
});
|
|
3066
|
+
}
|
|
2997
3067
|
const now = new Date().toISOString();
|
|
2998
3068
|
let changed = false;
|
|
2999
3069
|
for (const res of resolutions) {
|
|
@@ -3861,8 +3931,10 @@ function buildMainObligations(ctx) {
|
|
|
3861
3931
|
execute: async (state) => {
|
|
3862
3932
|
const s = requireState(state);
|
|
3863
3933
|
if (existsSync(clarificationResolutionPath)) {
|
|
3864
|
-
const
|
|
3865
|
-
|
|
3934
|
+
const outcome = await applyPlanClarificationResolution(root, artifactsDir, s, store);
|
|
3935
|
+
if (outcome.kind === "refused")
|
|
3936
|
+
return { kind: "emit", step: outcome.step };
|
|
3937
|
+
return { kind: "transition", state: outcome.state };
|
|
3866
3938
|
}
|
|
3867
3939
|
return {
|
|
3868
3940
|
kind: "emit",
|