audit-tools 0.34.15 → 0.34.18

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.
Files changed (103) hide show
  1. package/dispatch/merge-results.mjs +84 -24
  2. package/dispatch/validate.mjs +21 -3
  3. package/dist/audit/cli/dispatch/packetFilter.d.ts.map +1 -1
  4. package/dist/audit/cli/dispatch/packetFilter.js +7 -14
  5. package/dist/audit/cli/dispatch/packetFilter.js.map +1 -1
  6. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  7. package/dist/audit/cli/nextStepCommand.js +7 -1
  8. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  9. package/dist/audit/cli/scoreAuditCommand.d.ts.map +1 -1
  10. package/dist/audit/cli/scoreAuditCommand.js +6 -1
  11. package/dist/audit/cli/scoreAuditCommand.js.map +1 -1
  12. package/dist/audit/extractors/graphSignals.d.ts +37 -9
  13. package/dist/audit/extractors/graphSignals.d.ts.map +1 -1
  14. package/dist/audit/extractors/graphSignals.js +69 -9
  15. package/dist/audit/extractors/graphSignals.js.map +1 -1
  16. package/dist/audit/orchestrator/pendingTasks.d.ts +26 -0
  17. package/dist/audit/orchestrator/pendingTasks.d.ts.map +1 -0
  18. package/dist/audit/orchestrator/pendingTasks.js +13 -0
  19. package/dist/audit/orchestrator/pendingTasks.js.map +1 -0
  20. package/dist/audit/orchestrator/planningExecutors.d.ts +12 -1
  21. package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
  22. package/dist/audit/orchestrator/planningExecutors.js +43 -9
  23. package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
  24. package/dist/audit/orchestrator/state.d.ts.map +1 -1
  25. package/dist/audit/orchestrator/state.js +31 -22
  26. package/dist/audit/orchestrator/state.js.map +1 -1
  27. package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -1
  28. package/dist/audit/supervisor/operatorHandoff.js +19 -16
  29. package/dist/audit/supervisor/operatorHandoff.js.map +1 -1
  30. package/dist/remediate/dispatch/ownershipRegistry.d.ts +17 -1
  31. package/dist/remediate/dispatch/ownershipRegistry.d.ts.map +1 -1
  32. package/dist/remediate/dispatch/ownershipRegistry.js +21 -3
  33. package/dist/remediate/dispatch/ownershipRegistry.js.map +1 -1
  34. package/dist/remediate/phases/close.d.ts +49 -1
  35. package/dist/remediate/phases/close.d.ts.map +1 -1
  36. package/dist/remediate/phases/close.js +57 -14
  37. package/dist/remediate/phases/close.js.map +1 -1
  38. package/dist/remediate/phases/plan.d.ts.map +1 -1
  39. package/dist/remediate/phases/plan.js +66 -6
  40. package/dist/remediate/phases/plan.js.map +1 -1
  41. package/dist/remediate/phases/triage.d.ts.map +1 -1
  42. package/dist/remediate/phases/triage.js +52 -5
  43. package/dist/remediate/phases/triage.js.map +1 -1
  44. package/dist/remediate/review/reviewGate.d.ts +14 -0
  45. package/dist/remediate/review/reviewGate.d.ts.map +1 -1
  46. package/dist/remediate/review/reviewGate.js +22 -0
  47. package/dist/remediate/review/reviewGate.js.map +1 -1
  48. package/dist/remediate/state/store.d.ts.map +1 -1
  49. package/dist/remediate/state/store.js +64 -1
  50. package/dist/remediate/state/store.js.map +1 -1
  51. package/dist/remediate/steps/dispatch/acceptNode.d.ts +15 -0
  52. package/dist/remediate/steps/dispatch/acceptNode.d.ts.map +1 -1
  53. package/dist/remediate/steps/dispatch/acceptNode.js +98 -26
  54. package/dist/remediate/steps/dispatch/acceptNode.js.map +1 -1
  55. package/dist/remediate/steps/dispatch/acceptReconcile.d.ts +66 -0
  56. package/dist/remediate/steps/dispatch/acceptReconcile.d.ts.map +1 -0
  57. package/dist/remediate/steps/dispatch/acceptReconcile.js +154 -0
  58. package/dist/remediate/steps/dispatch/acceptReconcile.js.map +1 -0
  59. package/dist/remediate/steps/dispatch/marshal.d.ts.map +1 -1
  60. package/dist/remediate/steps/dispatch/marshal.js +34 -2
  61. package/dist/remediate/steps/dispatch/marshal.js.map +1 -1
  62. package/dist/remediate/steps/dispatch/verifyCommands.d.ts.map +1 -1
  63. package/dist/remediate/steps/dispatch/verifyCommands.js +29 -15
  64. package/dist/remediate/steps/dispatch/verifyCommands.js.map +1 -1
  65. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  66. package/dist/remediate/steps/nextStep.js +70 -26
  67. package/dist/remediate/steps/nextStep.js.map +1 -1
  68. package/dist/remediate/steps/rollingSession.d.ts +22 -3
  69. package/dist/remediate/steps/rollingSession.d.ts.map +1 -1
  70. package/dist/remediate/steps/rollingSession.js +33 -7
  71. package/dist/remediate/steps/rollingSession.js.map +1 -1
  72. package/dist/shared/dispatch/unifiedRolling.d.ts.map +1 -1
  73. package/dist/shared/dispatch/unifiedRolling.js +21 -0
  74. package/dist/shared/dispatch/unifiedRolling.js.map +1 -1
  75. package/dist/shared/findings/dedupe.d.ts +5 -2
  76. package/dist/shared/findings/dedupe.d.ts.map +1 -1
  77. package/dist/shared/findings/dedupe.js +56 -21
  78. package/dist/shared/findings/dedupe.js.map +1 -1
  79. package/dist/shared/friction/triage.d.ts.map +1 -1
  80. package/dist/shared/friction/triage.js +10 -3
  81. package/dist/shared/friction/triage.js.map +1 -1
  82. package/dist/shared/io/frictionCapture.d.ts +0 -14
  83. package/dist/shared/io/frictionCapture.d.ts.map +1 -1
  84. package/dist/shared/io/frictionCapture.js +48 -3
  85. package/dist/shared/io/frictionCapture.js.map +1 -1
  86. package/dist/shared/providers/openAiCompatibleProvider.d.ts.map +1 -1
  87. package/dist/shared/providers/openAiCompatibleProvider.js +51 -16
  88. package/dist/shared/providers/openAiCompatibleProvider.js.map +1 -1
  89. package/dist/shared/providers/providerFactory.d.ts +17 -0
  90. package/dist/shared/providers/providerFactory.d.ts.map +1 -1
  91. package/dist/shared/providers/providerFactory.js +11 -6
  92. package/dist/shared/providers/providerFactory.js.map +1 -1
  93. package/dist/shared/providers/proxyCatalog.d.ts.map +1 -1
  94. package/dist/shared/providers/proxyCatalog.js +20 -5
  95. package/dist/shared/providers/proxyCatalog.js.map +1 -1
  96. package/dist/shared/quota/capacity.d.ts.map +1 -1
  97. package/dist/shared/quota/capacity.js +13 -0
  98. package/dist/shared/quota/capacity.js.map +1 -1
  99. package/dist/shared/quota/fileLock.d.ts +8 -1
  100. package/dist/shared/quota/fileLock.d.ts.map +1 -1
  101. package/dist/shared/quota/fileLock.js +39 -1
  102. package/dist/shared/quota/fileLock.js.map +1 -1
  103. package/package.json +1 -1
@@ -26,7 +26,7 @@ import { resolveIntakeStep } from "./intakeResolver.js";
26
26
  import { runToolOwnedFinalGate, applyCoarseReblock, readFinalGateSidecar, writeFinalGateSidecar, } from "./finalGate.js";
27
27
  import { buildNextContractPipelineStep, shouldEnterContractPipeline, writePathASeedFromFindings, buildLeanExtractedPlan, } from "./contractPipeline.js";
28
28
  import { contractArtifactExists, contractPipelineDir, } from "../contractPipeline/artifactStore.js";
29
- import { buildReviewRequest, applyReviewResolution, } from "../review/reviewGate.js";
29
+ import { buildReviewRequest, applyReviewResolution, isResolutionForRequest, } from "../review/reviewGate.js";
30
30
  import { buildAutonomousReviewDecision } from "../review/autonomousGate.js";
31
31
  import { runFindingFilterPass } from "../findingFilter.js";
32
32
  import { intakePaths, isIntakeReady, readIntakeArtifacts, resolveManifestSources, } from "../intake.js";
@@ -1506,6 +1506,7 @@ async function buildImplementDispatchStep(ctx) {
1506
1506
  const rollMerge = loaderCommand(`merge-implement-results --run-id ${runId}`);
1507
1507
  const rollNext = loaderCommand("next-step");
1508
1508
  const acceptCmd = loaderCommand(`accept-node --id <BLOCK_ID> --run-id ${runId}`);
1509
+ const reverifyCmd = loaderCommand(`reverify-node --id <BLOCK_ID> --run-id ${runId}`);
1509
1510
  const nodeLines = rolling.initial
1510
1511
  .map((n) => `- \`${n.block_id}\` — prompt: \`${n.prompt_path}\` — worktree (subagent cwd): \`${n.worktree_root}\``)
1511
1512
  .join("\n");
@@ -1544,10 +1545,17 @@ As EACH subagent finishes, run (substituting the finished node's block id):
1544
1545
  It runs the commit -> verify -> merge lifecycle for that node and prints a JSON
1545
1546
  directive on stdout:
1546
1547
  - \`{"directive":"wait",...}\` — other granted nodes are still in flight; do not spawn more.
1547
- - \`{"directive":"done",...}\` — every granted node has been accepted. Then run:
1548
+ - \`{"directive":"done",...}\` — every granted node reached a terminal accept. Then run:
1548
1549
 
1549
1550
  \`${rollMerge}\`
1550
1551
 
1552
+ If the directive's \`accept_failed\` array names any node, that node's accept FAILED:
1553
+ its committed work is preserved under a quarantine ref and nothing landed. Do NOT
1554
+ re-run \`accept-node\` for it (that only re-reports the failure). Fix the named cause,
1555
+ then re-drive it with:
1556
+
1557
+ \`${reverifyCmd}\`
1558
+
1551
1559
  Then run:
1552
1560
 
1553
1561
  \`${rollNext}\`
@@ -1560,8 +1568,8 @@ ${DISPATCH_PROMPT_HANDOFF_NOTE}
1560
1568
 
1561
1569
  ${renderHostScratchNote(hostScratchDir(artifactsDir, runId))}
1562
1570
  `,
1563
- allowedCommands: [acceptCmd, rollMerge, rollNext],
1564
- stopCondition: "Stop after every node has been accepted (accept-node returns done), results merged, and next-step has been run.",
1571
+ allowedCommands: [acceptCmd, reverifyCmd, rollMerge, rollNext],
1572
+ stopCondition: "Stop after every node has reached a terminal accept (accept-node returns done), results merged, and next-step has been run.",
1565
1573
  artifactPaths: { dispatch_plan: rolling.planPath, dispatch_quota: rolling.quotaPath },
1566
1574
  }) };
1567
1575
  }
@@ -1945,8 +1953,6 @@ async function handlePendingExtractedPlan(root, artifactsDir, existing, extracte
1945
1953
  // pipeline. File-driven and pre-state (no RemediationState exists at intake yet),
1946
1954
  // mirroring the intake-clarification gate rather than waiting_for_clarification.
1947
1955
  const REVIEW_DECISION_SCHEMA_VERSION = "remediate-code-review-decision/v1";
1948
- /** Stable, informational plan id for the pre-plan review request/decision pair. */
1949
- const REVIEW_GATE_PLAN_ID = "path-a-review";
1950
1956
  function reviewRequestPath(artifactsDir) {
1951
1957
  return join(artifactsDir, "review_request.json");
1952
1958
  }
@@ -2016,11 +2022,12 @@ async function runReviewApprovalGate(root, artifactsDir, survivors, autonomous =
2016
2022
  if (gateOpen && autonomous) {
2017
2023
  const auto = buildAutonomousReviewDecision(survivors);
2018
2024
  const approvedSet = new Set(auto.approved_ids);
2019
- // Leftovers stay LIVE: declined is EMPTY (no durable rejection). The split
2020
- // below excludes nothing, so every leftover remains a live finding.
2025
+ // Leftovers stay LIVE: declined is EMPTY (no durable rejection). The
2026
+ // decision REPLAY keys on approved_ids (COR-227a02ae), so on later calls
2027
+ // exactly the approved subset — never the live leftovers — re-enters.
2021
2028
  const record = {
2022
2029
  schema_version: REVIEW_DECISION_SCHEMA_VERSION,
2023
- plan_id: REVIEW_GATE_PLAN_ID,
2030
+ plan_id: randomRunId("path-a-review"),
2024
2031
  approved_ids: auto.approved_ids,
2025
2032
  declined: [],
2026
2033
  created_at: new Date().toISOString(),
@@ -2042,7 +2049,9 @@ async function runReviewApprovalGate(root, artifactsDir, survivors, autonomous =
2042
2049
  const requestPath = reviewRequestPath(artifactsDir);
2043
2050
  if (!existsSync(resolutionPath)) {
2044
2051
  // Halt: present the tiered survivors and wait for the user's decision.
2045
- const request = buildReviewRequest(survivors, REVIEW_GATE_PLAN_ID);
2052
+ // The request's plan id is minted RUN-UNIQUE so a stale resolution from
2053
+ // another run can never correlate against it (COR-0b906e37).
2054
+ const request = buildReviewRequest(survivors, randomRunId("path-a-review"));
2046
2055
  await writeJsonFile(requestPath, request);
2047
2056
  return {
2048
2057
  kind: "halt",
@@ -2051,12 +2060,22 @@ async function runReviewApprovalGate(root, artifactsDir, survivors, autonomous =
2051
2060
  }
2052
2061
  // Consume the resolution into a durable, reasoned decision record.
2053
2062
  const request = (await readOptionalJsonFile(requestPath)) ??
2054
- buildReviewRequest(survivors, REVIEW_GATE_PLAN_ID);
2063
+ buildReviewRequest(survivors, randomRunId("path-a-review"));
2055
2064
  const resolution = await readOptionalJsonFile(resolutionPath);
2065
+ if (!isResolutionForRequest(request, resolution)) {
2066
+ // Stale cross-run resolution (plan_id mismatch): archive it and RE-HALT
2067
+ // with the live request rather than applying another run's answer.
2068
+ await withFsRetry(() => rename(resolutionPath, `${resolutionPath}.stale-${Date.now()}`));
2069
+ await writeJsonFile(requestPath, request);
2070
+ return {
2071
+ kind: "halt",
2072
+ step: await handleWaitingForReviewApproval(root, artifactsDir, request),
2073
+ };
2074
+ }
2056
2075
  const decision = applyReviewResolution(request, resolution);
2057
2076
  const record = {
2058
2077
  schema_version: REVIEW_DECISION_SCHEMA_VERSION,
2059
- plan_id: REVIEW_GATE_PLAN_ID,
2078
+ plan_id: request.plan_id,
2060
2079
  approved_ids: decision.approved_ids,
2061
2080
  declined: decision.declined,
2062
2081
  created_at: new Date().toISOString(),
@@ -2069,13 +2088,20 @@ async function runReviewApprovalGate(root, artifactsDir, survivors, autonomous =
2069
2088
  }
2070
2089
  }
2071
2090
  }
2072
- // Decision recorded (now or on a prior call): split the survivors.
2091
+ // Decision recorded (now or on a prior call): split the survivors. The
2092
+ // replay honours the recorded approved_ids (COR-227a02ae) — an autonomous
2093
+ // decision approves a SUBSET with declined EMPTY (leftovers live but not
2094
+ // approved), so keying the replay on the declined set alone would silently
2095
+ // re-approve every leftover on the next call.
2073
2096
  const decision = await readOptionalJsonFile(decisionPath);
2074
2097
  const declined = decision?.declined ?? [];
2075
2098
  const declinedIds = new Set(declined.map((d) => d.finding_id));
2099
+ const approvedIds = decision ? new Set(decision.approved_ids ?? []) : undefined;
2076
2100
  return {
2077
2101
  kind: "proceed",
2078
- approved: survivors.filter((f) => !declinedIds.has(f.id)),
2102
+ approved: approvedIds !== undefined
2103
+ ? survivors.filter((f) => approvedIds.has(f.id))
2104
+ : survivors.filter((f) => !declinedIds.has(f.id)),
2079
2105
  declined,
2080
2106
  };
2081
2107
  }
@@ -2279,6 +2305,17 @@ async function handleReadyIntakeContractPipeline(root, artifactsDir, options) {
2279
2305
  if (!pipeline.shouldHandleContractPipeline) {
2280
2306
  return null;
2281
2307
  }
2308
+ // The effective session config is loaded BEFORE the review gate
2309
+ // (COR-5f8fb354): the gate's attended-vs-autonomous resolution must see the
2310
+ // PERSISTED session-config.json (`autonomous_mode`), not only a programmatic
2311
+ // override — resolving from the bare CLI options meant a nightly unattended
2312
+ // run halted for a human at the review gate. The same loaded config feeds
2313
+ // the dispatch-capability resolution further down (single load).
2314
+ const sessionConfigForDispatch = await loadRemediateSessionConfig({
2315
+ root,
2316
+ override: options?.sessionConfig,
2317
+ artifactsFirst: true,
2318
+ });
2282
2319
  // Path A: run the single filter pass over the ORIGINAL findings, present the
2283
2320
  // SURVIVORS at the review gate (deduped / evidence-bearing / path-grounded /
2284
2321
  // checkpoint-kept, tiered by review-necessity), then seed the pipeline with the
@@ -2304,7 +2341,10 @@ async function handleReadyIntakeContractPipeline(root, artifactsDir, options) {
2304
2341
  checkpoint: checkpoint ?? undefined,
2305
2342
  evidenceGrounding: true,
2306
2343
  });
2307
- const gate = await runReviewApprovalGate(root, artifactsDir, filter.survivors, resolveAutonomousMode(options ?? {}));
2344
+ const gate = await runReviewApprovalGate(root, artifactsDir, filter.survivors,
2345
+ // Autonomy resolves from the PERSISTED session config (hoisted load
2346
+ // above) → env → attended default, never from the bare CLI options.
2347
+ resolveAutonomousMode({ sessionConfig: sessionConfigForDispatch }));
2308
2348
  if (gate.kind === "halt") {
2309
2349
  return gate.step;
2310
2350
  }
@@ -2415,12 +2455,8 @@ async function handleReadyIntakeContractPipeline(root, artifactsDir, options) {
2415
2455
  // (`resolveHostDispatchCapability`) implement dispatch uses — never a manual
2416
2456
  // flag. Threaded into the contract pipeline so the adversarial 'critique' /
2417
2457
  // 'critic' prompts MANDATE an independent sub-agent reviewer when the host can
2418
- // dispatch one (fail-safe: mandate by default).
2419
- const sessionConfigForDispatch = await loadRemediateSessionConfig({
2420
- root,
2421
- override: options?.sessionConfig,
2422
- artifactsFirst: true,
2423
- });
2458
+ // dispatch one (fail-safe: mandate by default). The config itself was loaded
2459
+ // once, above the review gate (COR-5f8fb354).
2424
2460
  const hostCanDispatchSubagents = resolveHostDispatchCapability({
2425
2461
  hostCanDispatchSubagents: options?.hostCanDispatchSubagents,
2426
2462
  sessionConfig: sessionConfigForDispatch,
@@ -2665,8 +2701,6 @@ async function handleWaitingForTriage(root, artifactsDir, state) {
2665
2701
  },
2666
2702
  });
2667
2703
  }
2668
- /** Stable, informational plan id for the Path-B (planning-point) review pair. */
2669
- const REVIEW_GATE_PLAN_ID_PATH_B = "path-b-review";
2670
2704
  /**
2671
2705
  * Path-B (document / conversation) review-necessity gate, fired at the PLANNING
2672
2706
  * point over the deduped/grounded node findings. Path A records its review
@@ -2690,20 +2724,30 @@ async function runPlanningReviewGate(root, artifactsDir, state, store) {
2690
2724
  const requestPath = reviewRequestPath(artifactsDir);
2691
2725
  const resolutionPath = reviewResolutionPath(artifactsDir);
2692
2726
  const decisionPath = reviewDecisionPath(artifactsDir);
2727
+ // Path B correlates on the LIVE plan's own id (INV-RSM-RESOLUTION-CORRELATE):
2728
+ // the plan exists at the planning point, so its plan_id is the natural
2729
+ // run-unique key — a stale resolution from an earlier plan can never match.
2730
+ const reviewPlanId = state.plan?.plan_id ?? randomRunId("path-b-review");
2693
2731
  if (!existsSync(resolutionPath)) {
2694
2732
  // Halt: present the tiered node findings and wait for the user's decision.
2695
- const request = buildReviewRequest(findings, REVIEW_GATE_PLAN_ID_PATH_B);
2733
+ const request = buildReviewRequest(findings, reviewPlanId);
2696
2734
  await writeJsonFile(requestPath, request);
2697
2735
  return handleWaitingForReviewApproval(root, artifactsDir, request);
2698
2736
  }
2699
2737
  // Resolution present: consume it into a durable, reasoned decision record.
2700
2738
  const request = (await readOptionalJsonFile(requestPath)) ??
2701
- buildReviewRequest(findings, REVIEW_GATE_PLAN_ID_PATH_B);
2739
+ buildReviewRequest(findings, reviewPlanId);
2702
2740
  const resolution = await readOptionalJsonFile(resolutionPath);
2741
+ if (!isResolutionForRequest(request, resolution)) {
2742
+ // Stale cross-run resolution: archive it and re-halt with the live request.
2743
+ await withFsRetry(() => rename(resolutionPath, `${resolutionPath}.stale-${Date.now()}`));
2744
+ await writeJsonFile(requestPath, request);
2745
+ return handleWaitingForReviewApproval(root, artifactsDir, request);
2746
+ }
2703
2747
  const decision = applyReviewResolution(request, resolution);
2704
2748
  const record = {
2705
2749
  schema_version: REVIEW_DECISION_SCHEMA_VERSION,
2706
- plan_id: REVIEW_GATE_PLAN_ID_PATH_B,
2750
+ plan_id: request.plan_id,
2707
2751
  approved_ids: decision.approved_ids,
2708
2752
  declined: decision.declined,
2709
2753
  created_at: new Date().toISOString(),