audit-tools 0.50.9 → 0.50.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/remediate/index.d.ts.map +1 -1
- package/dist/remediate/index.js +2 -2
- package/dist/remediate/index.js.map +1 -1
- package/dist/remediate/phases/close.d.ts.map +1 -1
- package/dist/remediate/phases/close.js +13 -0
- package/dist/remediate/phases/close.js.map +1 -1
- package/dist/remediate/phases/grounding.d.ts +6 -5
- package/dist/remediate/phases/grounding.d.ts.map +1 -1
- package/dist/remediate/phases/grounding.js +11 -9
- package/dist/remediate/phases/grounding.js.map +1 -1
- package/dist/remediate/phases/triage.d.ts.map +1 -1
- package/dist/remediate/phases/triage.js +14 -16
- package/dist/remediate/phases/triage.js.map +1 -1
- package/dist/remediate/steps/contractPipeline.js +11 -11
- package/dist/remediate/steps/contractPipeline.js.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts +19 -0
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.js +94 -30
- package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts +1 -1
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +62 -84
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/remediate/steps/stepUtils.d.ts +1 -37
- package/dist/remediate/steps/stepUtils.d.ts.map +1 -1
- package/dist/remediate/steps/stepUtils.js +0 -79
- package/dist/remediate/steps/stepUtils.js.map +1 -1
- package/dist/remediate/validation/artifacts.js +1 -1
- package/dist/remediate/validation/artifacts.js.map +1 -1
- package/dist/remediate/validation/contractPipelineGates.d.ts +14 -6
- package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -1
- package/dist/remediate/validation/contractPipelineGates.js +35 -36
- package/dist/remediate/validation/contractPipelineGates.js.map +1 -1
- package/dist/shared/analyzers/acquisitionEngine.d.ts +0 -29
- package/dist/shared/analyzers/acquisitionEngine.d.ts.map +1 -1
- package/dist/shared/analyzers/acquisitionEngine.js +13 -1
- package/dist/shared/analyzers/acquisitionEngine.js.map +1 -1
- package/dist/shared/analyzers/binaryAcquisition.d.ts.map +1 -1
- package/dist/shared/analyzers/binaryAcquisition.js +6 -2
- package/dist/shared/analyzers/binaryAcquisition.js.map +1 -1
- package/dist/shared/tooling/commandShape.js +5 -5
- package/dist/shared/tooling/exec.d.ts.map +1 -1
- package/dist/shared/tooling/exec.js +14 -0
- package/dist/shared/tooling/exec.js.map +1 -1
- package/dist/shared/validation/findingGrounding.d.ts +7 -2
- package/dist/shared/validation/findingGrounding.d.ts.map +1 -1
- package/dist/shared/validation/findingGrounding.js +15 -18
- package/dist/shared/validation/findingGrounding.js.map +1 -1
- package/package.json +1 -1
|
@@ -15,12 +15,11 @@ import { runTriagePhase } from "../phases/triage.js";
|
|
|
15
15
|
import { runClosePhase } from "../phases/close.js";
|
|
16
16
|
import { validateRemediationPlan } from "../validation/remediationState.js";
|
|
17
17
|
import { readExtractedPlanIfPresent, } from "./dispatch.js";
|
|
18
|
-
import { ingestRemediationHostResults, hostDependencyLevels, precomputeRecoveryTestVerdicts, prepareRemediationHostHandoff, } from "./dispatch/hostHandoff.js";
|
|
18
|
+
import { ingestRemediationHostResults, hostDependencyLevels, permanentlyDeadPendingBlocks, precomputeRecoveryTestVerdicts, prepareRemediationHostHandoff, } from "./dispatch/hostHandoff.js";
|
|
19
19
|
import { FileLockTimeoutError, withFileLock, } from "../../shared/io/fileLock.js";
|
|
20
20
|
import { AUDIT_FINDINGS_FILENAME, AUDIT_REPORT_FILENAME, auditArtifactsDir, auditFindingsPath, auditReportPath, promotedAuditFindingsPath, promotedAuditReportPath, remediationArtifactsDir, } from "../../shared/io/auditToolsPaths.js";
|
|
21
21
|
import { callerWorkingDirectory, discoverRepoRoot, resolveRepoRoot, } from "../../shared/io/repoRoot.js";
|
|
22
22
|
import { writeCurrentStep } from "./stepWriter.js";
|
|
23
|
-
import { dependencyAwaitingClarification, dependencyVerifiedComplete, } from "./stepUtils.js";
|
|
24
23
|
import { isTerminalStatus, isVerifiedCompleteStatus, } from "../state/itemStatus.js";
|
|
25
24
|
import { deduplicateCrossLensFindings, fixupBlocksAfterDedup, } from "../dedup/crossLensDedup.js";
|
|
26
25
|
import { checkAffectedFileIntegrity } from "../utils/fileIntegrity.js";
|
|
@@ -219,7 +218,7 @@ function suppliedInputMatchesRun(inputResolution, manifest) {
|
|
|
219
218
|
return false;
|
|
220
219
|
return true;
|
|
221
220
|
}
|
|
222
|
-
export {
|
|
221
|
+
export { classifyFindingRisk } from "./stepUtils.js";
|
|
223
222
|
export { isTerminalStatus, isVerifiedCompleteStatus };
|
|
224
223
|
export { hostDependencyLevels };
|
|
225
224
|
function documentableFindings(state) {
|
|
@@ -228,41 +227,50 @@ function documentableFindings(state) {
|
|
|
228
227
|
return state.plan.findings.filter((finding) => state.items?.[finding.id]?.status === "pending");
|
|
229
228
|
}
|
|
230
229
|
/**
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
230
|
+
* The dispatch frontier: the level-0 draw of the SAME dependency/phase
|
|
231
|
+
* partition the host workload builder emits from ({@link hostDependencyLevels}).
|
|
232
|
+
* The guard and the builder reading ONE computation is what keeps the
|
|
233
|
+
* "Cannot prepare an empty remediation host workload" throw unreachable from
|
|
234
|
+
* the scheduler: whenever this is non-empty, the builder derives the identical
|
|
235
|
+
* non-empty set (the 2026-08-23 empty-frontier incident — the retired
|
|
236
|
+
* edge-only predicate ignored the phase barrier and dependency existence, so
|
|
237
|
+
* the guard dispatched frontiers the builder refused, and next-step died
|
|
238
|
+
* instead of pausing).
|
|
236
239
|
*/
|
|
237
|
-
function
|
|
238
|
-
|
|
239
|
-
return [];
|
|
240
|
-
return state.plan.blocks.filter((block) => dependencyVerifiedComplete(block, state) &&
|
|
241
|
-
block.items.some((findingId) => {
|
|
242
|
-
const item = state.items?.[findingId];
|
|
243
|
-
return item?.status === "pending";
|
|
244
|
-
}));
|
|
240
|
+
function dispatchFrontier(state) {
|
|
241
|
+
return hostDependencyLevels(state)[0] ?? [];
|
|
245
242
|
}
|
|
246
243
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
* (`dependencyAwaitingClarification`): since the clarification round is deferred
|
|
255
|
-
* to the end of the implement phase, such a node reaches this sweep while its
|
|
256
|
-
* answer is still outstanding, and blocking it would report "upstream failed"
|
|
257
|
-
* for what is really "awaiting an answer". It stays `pending` and is re-decided
|
|
258
|
-
* once the answer lands.
|
|
244
|
+
* The ONE dead-end sweep, shared by the planning→implementing transition and
|
|
245
|
+
* the implementing obligation: marks the pending items of every permanently
|
|
246
|
+
* dead block `blocked` with the INV-RS-01 reason, and reports whether anything
|
|
247
|
+
* changed. Deadness is the workload boundary's own liveness analysis
|
|
248
|
+
* ({@link permanentlyDeadPendingBlocks}), so a node held by an unanswered
|
|
249
|
+
* clarification — or by a lower phase that is merely still working — is NEVER
|
|
250
|
+
* mis-reported as an upstream failure (the 175cfb89 pin).
|
|
259
251
|
*/
|
|
260
|
-
function
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
252
|
+
function sweepPermanentlyDeadBlocks(state) {
|
|
253
|
+
let changed = false;
|
|
254
|
+
const now = new Date().toISOString();
|
|
255
|
+
for (const block of permanentlyDeadPendingBlocks(state)) {
|
|
256
|
+
for (const findingId of block.items) {
|
|
257
|
+
const it = state.items?.[findingId];
|
|
258
|
+
if (!it || it.status !== "pending")
|
|
259
|
+
continue;
|
|
260
|
+
it.status = "blocked";
|
|
261
|
+
it.started_at ??= now;
|
|
262
|
+
it.completed_at = now;
|
|
263
|
+
it.failure_reason =
|
|
264
|
+
it.failure_reason ??
|
|
265
|
+
"A prerequisite can never reach a verified-complete disposition " +
|
|
266
|
+
"(a dependency or lower-phase block was skipped, blocked, or abandoned; " +
|
|
267
|
+
"a declared dependency resolves to no block; or the dependencies are " +
|
|
268
|
+
"cyclic); the host handoff will not expose this node against an " +
|
|
269
|
+
"upstream surface that never landed (INV-RS-01).";
|
|
270
|
+
changed = true;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return changed;
|
|
266
274
|
}
|
|
267
275
|
/**
|
|
268
276
|
* Whether any item is paused on a worker question that has not been answered yet.
|
|
@@ -668,7 +676,11 @@ export async function recoverIngestHostResults(options) {
|
|
|
668
676
|
if (requiredTestVerdicts === "unsupported_retired_state") {
|
|
669
677
|
throw new Error("Remediation state uses a retired dispatch shape and cannot cross the host handoff boundary.");
|
|
670
678
|
}
|
|
671
|
-
// ── Phase 2: locked
|
|
679
|
+
// ── Phase 2: locked; children are async + deadline-bounded only ──────────
|
|
680
|
+
// The long-running required tests were precomputed in Phase 1, outside the
|
|
681
|
+
// lock. What still spawns under the hold is the corroboration git probes —
|
|
682
|
+
// async on the tracked twin with the shared deadline (INV-SSF), so the
|
|
683
|
+
// hold's heartbeat keeps beating through every probe.
|
|
672
684
|
let ingested;
|
|
673
685
|
await store.mutate(async (state) => {
|
|
674
686
|
if (!state) {
|
|
@@ -1985,7 +1997,7 @@ async function handlePlanning(root, artifactsDir, state, store) {
|
|
|
1985
1997
|
}
|
|
1986
1998
|
// Document phase dissolved (N-R13): planning transitions directly to
|
|
1987
1999
|
// implementing, and the host workload reads finding context directly.
|
|
1988
|
-
const implementBlocks =
|
|
2000
|
+
const implementBlocks = dispatchFrontier(state);
|
|
1989
2001
|
if (implementBlocks.length > 0) {
|
|
1990
2002
|
if (state.plan) {
|
|
1991
2003
|
const integrity = await checkAffectedFileIntegrity(root, state.plan.findings);
|
|
@@ -2020,28 +2032,15 @@ async function handlePlanning(root, artifactsDir, state, store) {
|
|
|
2020
2032
|
}
|
|
2021
2033
|
}
|
|
2022
2034
|
// Transition directly to implementing — no separate document round.
|
|
2023
|
-
// Any pending item
|
|
2035
|
+
// Any pending item that can never enter the host dependency frontier is
|
|
2024
2036
|
// dead-ended (INV-RS-01): a prerequisite was skipped/blocked, so its
|
|
2025
2037
|
// verified-complete edge can never be satisfied — never dispatch a dependent
|
|
2026
2038
|
// against an upstream surface that did not land. Mark it blocked so the run
|
|
2027
2039
|
// advances to close rather than looping forever. A node that is merely
|
|
2028
|
-
// waiting on a still-running prerequisite
|
|
2029
|
-
//
|
|
2040
|
+
// waiting on a still-running prerequisite — or on a clarification answer —
|
|
2041
|
+
// is NOT dead; the liveness analysis behind the sweep holds it pending.
|
|
2030
2042
|
if (implementBlocks.length === 0) {
|
|
2031
|
-
|
|
2032
|
-
for (const findingId of block.items) {
|
|
2033
|
-
const it = state.items?.[findingId];
|
|
2034
|
-
if (!it || it.status !== "pending")
|
|
2035
|
-
continue;
|
|
2036
|
-
it.status = "blocked";
|
|
2037
|
-
it.failure_reason =
|
|
2038
|
-
it.failure_reason ??
|
|
2039
|
-
"A dependency node did not reach a verified-complete disposition " +
|
|
2040
|
-
"(a prerequisite was skipped, blocked, or the dependencies are cyclic); " +
|
|
2041
|
-
"the host handoff will not expose this node against an upstream " +
|
|
2042
|
-
"surface that never landed (INV-RS-01).";
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2043
|
+
sweepPermanentlyDeadBlocks(state);
|
|
2045
2044
|
}
|
|
2046
2045
|
state.status = "implementing";
|
|
2047
2046
|
await store.saveState(state);
|
|
@@ -3232,7 +3231,7 @@ export function buildMainObligations(ctx) {
|
|
|
3232
3231
|
derive: (state) => state != null &&
|
|
3233
3232
|
(state.status === "implementing" || state.status === "triage") &&
|
|
3234
3233
|
hasUnansweredClarification(state) &&
|
|
3235
|
-
|
|
3234
|
+
dispatchFrontier(state).length === 0
|
|
3236
3235
|
? "missing"
|
|
3237
3236
|
: "satisfied",
|
|
3238
3237
|
execute: async (state) => {
|
|
@@ -3247,9 +3246,9 @@ export function buildMainObligations(ctx) {
|
|
|
3247
3246
|
derive: (state) => state?.status === "implementing" ? "missing" : "satisfied",
|
|
3248
3247
|
execute: async (state) => {
|
|
3249
3248
|
const s = requireState(state);
|
|
3250
|
-
//
|
|
3251
|
-
// has left "pending".
|
|
3252
|
-
const pendingBlocks =
|
|
3249
|
+
// A non-empty dispatch frontier dispatches; triage only runs once every
|
|
3250
|
+
// item has left "pending".
|
|
3251
|
+
const pendingBlocks = dispatchFrontier(s);
|
|
3253
3252
|
if (pendingBlocks.length > 0) {
|
|
3254
3253
|
// Per-phase boundary gate (T3): before opening a phase P > 0, run the
|
|
3255
3254
|
// whole-repo suite once over the just-landed foundations. A red PAUSES
|
|
@@ -3273,33 +3272,12 @@ export function buildMainObligations(ctx) {
|
|
|
3273
3272
|
runLogger,
|
|
3274
3273
|
});
|
|
3275
3274
|
}
|
|
3276
|
-
// Dead-end pending nodes
|
|
3277
|
-
//
|
|
3278
|
-
//
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
let changed = false;
|
|
3283
|
-
for (const block of deadEnded) {
|
|
3284
|
-
for (const findingId of block.items) {
|
|
3285
|
-
const it = s.items?.[findingId];
|
|
3286
|
-
if (!it || it.status !== "pending")
|
|
3287
|
-
continue;
|
|
3288
|
-
it.status = "blocked";
|
|
3289
|
-
it.started_at ??= now;
|
|
3290
|
-
it.completed_at = now;
|
|
3291
|
-
it.failure_reason =
|
|
3292
|
-
it.failure_reason ??
|
|
3293
|
-
"A dependency node did not reach a verified-complete disposition " +
|
|
3294
|
-
"(a prerequisite was skipped, blocked, or the dependencies are cyclic); " +
|
|
3295
|
-
"the host handoff will not expose this node (INV-RS-01).";
|
|
3296
|
-
changed = true;
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
if (changed) {
|
|
3300
|
-
await store.saveState(s);
|
|
3301
|
-
return { kind: "transition", state: s };
|
|
3302
|
-
}
|
|
3275
|
+
// Dead-end pending nodes that can never enter the frontier (INV-RS-01)
|
|
3276
|
+
// so the implementing→triage loop can't livelock; transition so the
|
|
3277
|
+
// engine re-scans on the updated state.
|
|
3278
|
+
if (sweepPermanentlyDeadBlocks(s)) {
|
|
3279
|
+
await store.saveState(s);
|
|
3280
|
+
return { kind: "transition", state: s };
|
|
3303
3281
|
}
|
|
3304
3282
|
return handleImplementing(root, artifactsDir, s, runLogger, store, options);
|
|
3305
3283
|
},
|