audit-tools 0.32.43 → 0.32.45

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 (197) hide show
  1. package/dist/audit/cli/args.d.ts.map +1 -1
  2. package/dist/audit/cli/args.js +2 -4
  3. package/dist/audit/cli/args.js.map +1 -1
  4. package/dist/audit/cli/auditStep.d.ts +1 -1
  5. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  6. package/dist/audit/cli/nextStepCommand.js +3 -3
  7. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  8. package/dist/audit/cli/nextStepHelpers.d.ts +23 -38
  9. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  10. package/dist/audit/cli/nextStepHelpers.js +130 -89
  11. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  12. package/dist/audit/cli/resynthesizeCommand.d.ts.map +1 -1
  13. package/dist/audit/cli/resynthesizeCommand.js +8 -10
  14. package/dist/audit/cli/resynthesizeCommand.js.map +1 -1
  15. package/dist/audit/cli/rollingAuditDispatch.d.ts.map +1 -1
  16. package/dist/audit/cli/rollingAuditDispatch.js +9 -22
  17. package/dist/audit/cli/rollingAuditDispatch.js.map +1 -1
  18. package/dist/audit/contracts/wrapperResponse.d.ts +6 -6
  19. package/dist/audit/extractors/gitHistory.d.ts.map +1 -1
  20. package/dist/audit/extractors/gitHistory.js +3 -0
  21. package/dist/audit/extractors/gitHistory.js.map +1 -1
  22. package/dist/audit/orchestrator/advance.d.ts +4 -1
  23. package/dist/audit/orchestrator/advance.d.ts.map +1 -1
  24. package/dist/audit/orchestrator/advance.js +185 -36
  25. package/dist/audit/orchestrator/advance.js.map +1 -1
  26. package/dist/audit/orchestrator/fileIntegrity.d.ts.map +1 -1
  27. package/dist/audit/orchestrator/fileIntegrity.js +21 -32
  28. package/dist/audit/orchestrator/fileIntegrity.js.map +1 -1
  29. package/dist/audit/orchestrator/reviewPackets.d.ts.map +1 -1
  30. package/dist/audit/orchestrator/reviewPackets.js +31 -36
  31. package/dist/audit/orchestrator/reviewPackets.js.map +1 -1
  32. package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -1
  33. package/dist/audit/orchestrator/taskBuilder.js +12 -24
  34. package/dist/audit/orchestrator/taskBuilder.js.map +1 -1
  35. package/dist/audit/providers/opencodeProvider.d.ts +1 -4
  36. package/dist/audit/providers/opencodeProvider.d.ts.map +1 -1
  37. package/dist/audit/providers/opencodeProvider.js +6 -9
  38. package/dist/audit/providers/opencodeProvider.js.map +1 -1
  39. package/dist/audit/reporting/mergeFindings.d.ts.map +1 -1
  40. package/dist/audit/reporting/mergeFindings.js +1 -32
  41. package/dist/audit/reporting/mergeFindings.js.map +1 -1
  42. package/dist/audit/reporting/synthesis.d.ts.map +1 -1
  43. package/dist/audit/reporting/synthesis.js +1 -12
  44. package/dist/audit/reporting/synthesis.js.map +1 -1
  45. package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -1
  46. package/dist/audit/supervisor/operatorHandoff.js +9 -12
  47. package/dist/audit/supervisor/operatorHandoff.js.map +1 -1
  48. package/dist/audit/supervisor/sessionConfig.d.ts.map +1 -1
  49. package/dist/audit/supervisor/sessionConfig.js +25 -35
  50. package/dist/audit/supervisor/sessionConfig.js.map +1 -1
  51. package/dist/audit/types/auditState.d.ts +6 -6
  52. package/dist/remediate/dedup/crossLensDedup.d.ts +2 -1
  53. package/dist/remediate/dedup/crossLensDedup.d.ts.map +1 -1
  54. package/dist/remediate/dedup/crossLensDedup.js +4 -33
  55. package/dist/remediate/dedup/crossLensDedup.js.map +1 -1
  56. package/dist/remediate/index.d.ts +2 -2
  57. package/dist/remediate/index.d.ts.map +1 -1
  58. package/dist/remediate/index.js +5 -8
  59. package/dist/remediate/index.js.map +1 -1
  60. package/dist/remediate/intake.d.ts.map +1 -1
  61. package/dist/remediate/intake.js +9 -5
  62. package/dist/remediate/intake.js.map +1 -1
  63. package/dist/remediate/phases/close.d.ts +59 -1
  64. package/dist/remediate/phases/close.d.ts.map +1 -1
  65. package/dist/remediate/phases/close.js +294 -29
  66. package/dist/remediate/phases/close.js.map +1 -1
  67. package/dist/remediate/phases/plan.d.ts +2 -2
  68. package/dist/remediate/phases/plan.d.ts.map +1 -1
  69. package/dist/remediate/phases/plan.js +31 -23
  70. package/dist/remediate/phases/plan.js.map +1 -1
  71. package/dist/remediate/providers/opencodeProvider.d.ts +1 -4
  72. package/dist/remediate/providers/opencodeProvider.d.ts.map +1 -1
  73. package/dist/remediate/providers/opencodeProvider.js +6 -9
  74. package/dist/remediate/providers/opencodeProvider.js.map +1 -1
  75. package/dist/remediate/riskSignal.d.ts +30 -0
  76. package/dist/remediate/riskSignal.d.ts.map +1 -1
  77. package/dist/remediate/riskSignal.js +87 -1
  78. package/dist/remediate/riskSignal.js.map +1 -1
  79. package/dist/remediate/state/store.d.ts +54 -11
  80. package/dist/remediate/state/store.d.ts.map +1 -1
  81. package/dist/remediate/state/store.js +37 -64
  82. package/dist/remediate/state/store.js.map +1 -1
  83. package/dist/remediate/state/types.d.ts +22 -0
  84. package/dist/remediate/state/types.d.ts.map +1 -1
  85. package/dist/remediate/state/types.js +8 -0
  86. package/dist/remediate/state/types.js.map +1 -1
  87. package/dist/remediate/steps/dispatch/acceptNode.d.ts +23 -0
  88. package/dist/remediate/steps/dispatch/acceptNode.d.ts.map +1 -1
  89. package/dist/remediate/steps/dispatch/acceptNode.js +61 -7
  90. package/dist/remediate/steps/dispatch/acceptNode.js.map +1 -1
  91. package/dist/remediate/steps/dispatch/marshal.d.ts.map +1 -1
  92. package/dist/remediate/steps/dispatch/marshal.js +30 -0
  93. package/dist/remediate/steps/dispatch/marshal.js.map +1 -1
  94. package/dist/remediate/steps/dispatch/worktreeLifecycle.d.ts.map +1 -1
  95. package/dist/remediate/steps/dispatch/worktreeLifecycle.js +12 -6
  96. package/dist/remediate/steps/dispatch/worktreeLifecycle.js.map +1 -1
  97. package/dist/remediate/steps/finalGate.d.ts +2 -2
  98. package/dist/remediate/steps/finalGate.d.ts.map +1 -1
  99. package/dist/remediate/steps/finalGate.js +8 -9
  100. package/dist/remediate/steps/finalGate.js.map +1 -1
  101. package/dist/remediate/steps/gateCommands.d.ts +17 -0
  102. package/dist/remediate/steps/gateCommands.d.ts.map +1 -1
  103. package/dist/remediate/steps/gateCommands.js +19 -0
  104. package/dist/remediate/steps/gateCommands.js.map +1 -1
  105. package/dist/remediate/steps/leanFastPath.d.ts +0 -31
  106. package/dist/remediate/steps/leanFastPath.d.ts.map +1 -1
  107. package/dist/remediate/steps/leanFastPath.js +27 -127
  108. package/dist/remediate/steps/leanFastPath.js.map +1 -1
  109. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  110. package/dist/remediate/steps/nextStep.js +81 -57
  111. package/dist/remediate/steps/nextStep.js.map +1 -1
  112. package/dist/remediate/utils/fileIntegrity.d.ts.map +1 -1
  113. package/dist/remediate/utils/fileIntegrity.js +29 -33
  114. package/dist/remediate/utils/fileIntegrity.js.map +1 -1
  115. package/dist/remediate/utils/hostAssets.d.ts +4 -1
  116. package/dist/remediate/utils/hostAssets.d.ts.map +1 -1
  117. package/dist/remediate/utils/hostAssets.js +4 -1
  118. package/dist/remediate/utils/hostAssets.js.map +1 -1
  119. package/dist/remediate/validation/artifacts.d.ts.map +1 -1
  120. package/dist/remediate/validation/artifacts.js +3 -2
  121. package/dist/remediate/validation/artifacts.js.map +1 -1
  122. package/dist/remediate/validation/contractPipeline.d.ts.map +1 -1
  123. package/dist/remediate/validation/contractPipeline.js +3 -1
  124. package/dist/remediate/validation/contractPipeline.js.map +1 -1
  125. package/dist/shared/chunkByBudget.d.ts +58 -0
  126. package/dist/shared/chunkByBudget.d.ts.map +1 -0
  127. package/dist/shared/chunkByBudget.js +31 -0
  128. package/dist/shared/chunkByBudget.js.map +1 -0
  129. package/dist/shared/countBy.d.ts +19 -0
  130. package/dist/shared/countBy.d.ts.map +1 -0
  131. package/dist/shared/countBy.js +29 -0
  132. package/dist/shared/countBy.js.map +1 -0
  133. package/dist/shared/engine/obligationEngine.d.ts +2 -2
  134. package/dist/shared/fileIntegrity.d.ts +55 -0
  135. package/dist/shared/fileIntegrity.d.ts.map +1 -0
  136. package/dist/shared/fileIntegrity.js +50 -0
  137. package/dist/shared/fileIntegrity.js.map +1 -0
  138. package/dist/shared/findingSimilarity.d.ts +26 -0
  139. package/dist/shared/findingSimilarity.d.ts.map +1 -0
  140. package/dist/shared/findingSimilarity.js +54 -0
  141. package/dist/shared/findingSimilarity.js.map +1 -0
  142. package/dist/shared/friction/stepBoundaryCapture.d.ts +17 -0
  143. package/dist/shared/friction/stepBoundaryCapture.d.ts.map +1 -1
  144. package/dist/shared/friction/stepBoundaryCapture.js +21 -0
  145. package/dist/shared/friction/stepBoundaryCapture.js.map +1 -1
  146. package/dist/shared/git.d.ts +23 -0
  147. package/dist/shared/git.d.ts.map +1 -1
  148. package/dist/shared/git.js +26 -0
  149. package/dist/shared/git.js.map +1 -1
  150. package/dist/shared/index.d.ts +12 -4
  151. package/dist/shared/index.d.ts.map +1 -1
  152. package/dist/shared/index.js +23 -3
  153. package/dist/shared/index.js.map +1 -1
  154. package/dist/shared/io/auditToolsPaths.d.ts +7 -0
  155. package/dist/shared/io/auditToolsPaths.d.ts.map +1 -1
  156. package/dist/shared/io/auditToolsPaths.js +10 -0
  157. package/dist/shared/io/auditToolsPaths.js.map +1 -1
  158. package/dist/shared/io/lockedJsonStore.d.ts +66 -0
  159. package/dist/shared/io/lockedJsonStore.d.ts.map +1 -0
  160. package/dist/shared/io/lockedJsonStore.js +59 -0
  161. package/dist/shared/io/lockedJsonStore.js.map +1 -0
  162. package/dist/shared/loopCorePaths.d.ts +12 -0
  163. package/dist/shared/loopCorePaths.d.ts.map +1 -0
  164. package/dist/shared/loopCorePaths.js +67 -0
  165. package/dist/shared/loopCorePaths.js.map +1 -0
  166. package/dist/shared/providers/openAiCompatibleProvider.d.ts.map +1 -1
  167. package/dist/shared/providers/openAiCompatibleProvider.js +2 -1
  168. package/dist/shared/providers/openAiCompatibleProvider.js.map +1 -1
  169. package/dist/shared/providers/opencodeProvider.d.ts +8 -0
  170. package/dist/shared/providers/opencodeProvider.d.ts.map +1 -1
  171. package/dist/shared/providers/opencodeProvider.js +10 -0
  172. package/dist/shared/providers/opencodeProvider.js.map +1 -1
  173. package/dist/shared/reporting/auditDeliverable.d.ts.map +1 -1
  174. package/dist/shared/reporting/auditDeliverable.js +14 -9
  175. package/dist/shared/reporting/auditDeliverable.js.map +1 -1
  176. package/dist/shared/tooling/exec.d.ts +42 -4
  177. package/dist/shared/tooling/exec.d.ts.map +1 -1
  178. package/dist/shared/tooling/exec.js +90 -12
  179. package/dist/shared/tooling/exec.js.map +1 -1
  180. package/dist/shared/types/contractPipeline/verification.d.ts +17 -3
  181. package/dist/shared/types/contractPipeline/verification.d.ts.map +1 -1
  182. package/dist/shared/types/sessionConfig.d.ts +28 -0
  183. package/dist/shared/types/sessionConfig.d.ts.map +1 -1
  184. package/dist/shared/types/sessionConfig.js +35 -0
  185. package/dist/shared/types/sessionConfig.js.map +1 -1
  186. package/opencode.json +2 -11
  187. package/package.json +3 -1
  188. package/scripts/audit/postinstall.mjs +57 -137
  189. package/scripts/remediate/postinstall.mjs +41 -169
  190. package/scripts/shared/install-host-assets.mjs +188 -0
  191. package/wrapper/audit-code-wrapper-lib.mjs +32 -4
  192. package/wrapper/audit-code-wrapper-opencode.mjs +41 -25
  193. package/wrapper/remediate-code-wrapper-opencode.mjs +43 -21
  194. package/dist/remediate/utils/commands.d.ts +0 -17
  195. package/dist/remediate/utils/commands.d.ts.map +0 -1
  196. package/dist/remediate/utils/commands.js +0 -29
  197. package/dist/remediate/utils/commands.js.map +0 -1
@@ -2,7 +2,7 @@ import { existsSync, statSync } from "node:fs";
2
2
  import { mkdir, readFile, rename } from "node:fs/promises";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { StateStore } from "../state/store.js";
5
- import { readOptionalJsonFile, readValidatedSessionConfig, writeJsonFile, writeTextFile, buildAuditDeliverablePair, formatValidationIssues, isRecord, withFsRetry, RunLogger, DISPATCH_PROMPT_HANDOFF_NOTE, renderQuotaCoverageNudge, renderTokenBudgetView, coerceJsonObjectArg, driveRolling, resolveLedgerBudgets, setQuotaStateDir, interpretFreeFormIntent, advance, decideFrictionTriage, buildFrictionTriageBlock, planHybridDispatch, readSettledPools, addSettledPool, sourceByPoolId, classifyProvider, selectDispatchDriver, renderDispatchDriverInstruction, HostSessionQuotaSource, buildProviderModelKey, captureStepBoundaryFriction, LENSES, SEVERITIES, resolveHostProviderName, resolveConversationHostProvider, resolveHostDispatchCapability as sharedResolveHostDispatchCapability, shouldDemotePrimaryInProcess, DEFAULT_CONTEXT_TOKENS } from "audit-tools/shared";
5
+ import { readOptionalJsonFile, readValidatedSessionConfig, stagedAndUntracked, writeJsonFile, writeTextFile, buildAuditDeliverablePair, formatValidationIssues, isRecord, withFsRetry, RunLogger, DISPATCH_PROMPT_HANDOFF_NOTE, renderQuotaCoverageNudge, renderTokenBudgetView, coerceJsonObjectArg, driveRolling, resolveLedgerBudgets, setQuotaStateDir, interpretFreeFormIntent, advance, decideFrictionTriage, buildFrictionTriageBlock, planHybridDispatch, readSettledPools, addSettledPool, sourceByPoolId, classifyProvider, selectDispatchDriver, renderDispatchDriverInstruction, HostSessionQuotaSource, buildProviderModelKey, captureStepBoundaryFriction, captureCostDriftFriction, LENSES, SEVERITIES, resolveHostProviderName, resolveConversationHostProvider, resolveHostDispatchCapability as sharedResolveHostDispatchCapability, resolveRollingEngineFlag, shouldDemotePrimaryInProcess, DEFAULT_CONTEXT_TOKENS } from "audit-tools/shared";
6
6
  import { readRemediationAccessMemory, computeBlockContinuityScores } from "../state/accessMemory.js";
7
7
  import { applyPlanPipeline, buildCoverageLedger } from "../phases/plan.js";
8
8
  import { groundExtractedFindings } from "../phases/grounding.js";
@@ -14,7 +14,7 @@ import { makeProviderNodeDispatcher } from "./providerNodeDispatch.js";
14
14
  import { prepareHostRollingDispatch, nodeClaimRegistry, nodeSettledPoolsPath } from "./rollingSession.js";
15
15
  import { ClaimRegistry } from "../../shared/quota/claimRegistry.js";
16
16
  import { claimWithBackoff, withClaimHeartbeat } from "../../shared/quota/claimLease.js";
17
- import { nodeClaimsPath, remediationArtifactsDir } from "../../shared/io/auditToolsPaths.js";
17
+ import { AUDIT_FINDINGS_FILENAME, AUDIT_REPORT_FILENAME, auditArtifactsDir, auditFindingsPath, auditReportPath, auditToolsDir, nodeClaimsPath, promotedAuditFindingsPath, promotedAuditReportPath, remediationArtifactsDir, } from "../../shared/io/auditToolsPaths.js";
18
18
  import { resolveRepoRoot } from "../../shared/io/repoRoot.js";
19
19
  import { writeCurrentStep } from "./stepWriter.js";
20
20
  import { dependencyVerifiedComplete } from "./stepUtils.js";
@@ -24,13 +24,13 @@ import { checkAffectedFileIntegrity } from "../utils/fileIntegrity.js";
24
24
  import { resolveIntakeStep } from "./intakeResolver.js";
25
25
  import { runToolOwnedFinalGate, applyCoarseReblock, readFinalGateSidecar, writeFinalGateSidecar, } from "./finalGate.js";
26
26
  import { buildNextContractPipelineStep, shouldEnterContractPipeline, writePathASeedFromFindings, } from "./contractPipeline.js";
27
- import { evaluateFastPath, buildLeanExtractedPlan, distinctAffectedFiles, interpretLeanLightReviewVerdict, LEAN_LIGHT_REVIEW_SCHEMA_VERSION, } from "./leanFastPath.js";
27
+ import { buildLeanExtractedPlan, interpretLeanLightReviewVerdict, LEAN_LIGHT_REVIEW_SCHEMA_VERSION, } from "./leanFastPath.js";
28
28
  import { contractArtifactExists, contractPipelineDir, } from "../contractPipeline/artifactStore.js";
29
29
  import { buildReviewRequest, applyReviewResolution, } 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";
33
- import { ensureIntakeRiskSignal, readIntakeRiskSignal, writeIntakeRiskSignal, escalateRiskSignal, } from "../riskSignal.js";
33
+ import { ensureIntakeRiskSignal, readIntakeRiskSignal, writeIntakeRiskSignal, escalateRiskSignal, findingRiskEvidence, distinctAffectedFiles, } from "../riskSignal.js";
34
34
  import { ambiguityReviewPrompt, clarificationPrompt, collectIntakeClarificationsPrompt, collectStartingPointPrompt, loaderCommand, reviewApprovalPrompt, synthesizeIntakePrompt, triagePrompt, } from "./prompts.js";
35
35
  // Single-sourced prose renders of the canonical lens / severity vocabularies
36
36
  // (`audit-tools/shared` `LENSES` / `SEVERITIES`) for the intent-checkpoint
@@ -81,17 +81,12 @@ export function resolveAutonomousMode(options = {}) {
81
81
  * sessionConfig.dispatch.rolling_engine → REMEDIATE_ROLLING_ENGINE env → true.
82
82
  */
83
83
  export function resolveRollingEngineEnabled(options) {
84
- if (options.rollingEngine !== undefined)
85
- return options.rollingEngine;
86
- const cfg = options.sessionConfig?.dispatch?.rolling_engine;
87
- if (cfg !== undefined)
88
- return cfg;
89
- const envValue = (options.env ?? process.env).REMEDIATE_ROLLING_ENGINE;
90
- if (envValue === "true")
91
- return true;
92
- if (envValue === "false")
93
- return false;
94
- return true;
84
+ return resolveRollingEngineFlag({
85
+ explicit: options.rollingEngine,
86
+ sessionConfig: options.sessionConfig,
87
+ envVarName: "REMEDIATE_ROLLING_ENGINE",
88
+ env: options.env,
89
+ });
95
90
  }
96
91
  /** Conservative context-window floor, applied ONLY at true first contact (nothing persisted). */
97
92
  const HOST_CONTEXT_TOKENS_FLOOR = DEFAULT_CONTEXT_TOKENS;
@@ -189,13 +184,14 @@ function defaultInputCandidates(root) {
189
184
  // both sides of the audit -> remediate pipeline, and feeding it triggers the
190
185
  // lossless structured hand-off in the plan phase instead of a lossy LLM
191
186
  // re-extraction from the markdown render that sits beside it.
187
+ const auditDir = auditArtifactsDir(root);
192
188
  return [
193
- join(root, ".audit-tools", "audit-findings.json"),
194
- join(root, ".audit-tools", "audit", "audit-findings.json"),
195
- join(root, "audit-findings.json"),
196
- join(root, ".audit-tools", "audit-report.md"),
197
- join(root, ".audit-tools", "audit", "audit-report.md"),
198
- join(root, "audit-report.md"),
189
+ promotedAuditFindingsPath(auditDir),
190
+ auditFindingsPath(auditDir),
191
+ join(root, AUDIT_FINDINGS_FILENAME),
192
+ promotedAuditReportPath(auditDir),
193
+ auditReportPath(auditDir),
194
+ join(root, AUDIT_REPORT_FILENAME),
199
195
  ];
200
196
  }
201
197
  function inputValues(input) {
@@ -792,16 +788,8 @@ export async function driveRollingImplementDispatch(options) {
792
788
  // Reactive cost verification: a declared-free source pool observed charging has
793
789
  // been demoted by the engine; surface it as reviewable friction so the operator
794
790
  // reconciles the stale `cost_per_mtok:0` (single step-boundary chokepoint).
795
- onCostDrift: ({ poolId, observedCostUsd, declaredCostPerMtok }) => {
796
- void captureStepBoundaryFriction(artifactsDir, runId, {
797
- eventType: "declared_cost_drift",
798
- discriminator: poolId,
799
- note: `pool "${poolId}" was declared free (cost_per_mtok=${declaredCostPerMtok}) ` +
800
- `but reported cost=${observedCostUsd} — demoted out of free-first ordering; ` +
801
- `reconcile the source's declared cost.`,
802
- severity: "medium",
803
- area: "dispatch/cost",
804
- }, "remediate-code");
791
+ onCostDrift: (info) => {
792
+ captureCostDriftFriction(artifactsDir, runId, info, "remediate-code");
805
793
  },
806
794
  });
807
795
  // Piece D — persist the rolling engine's partial-completion terminal onto state
@@ -1090,6 +1078,18 @@ async function forceReplanFromExistingIntake(root, artifactsDir, previous, store
1090
1078
  status: "pending",
1091
1079
  started_at: previous.started_at,
1092
1080
  step_count: previous.step_count,
1081
+ // Carry the run-lifetime staging-manifest fields across a force-replan.
1082
+ // Dropping run_start_dirty here would make handlePendingExtractedPlan's
1083
+ // capture-once guard re-capture AFTER edits have landed, misclassifying
1084
+ // the run's own hand-applied edits as pre-existing dirt (silently
1085
+ // under-staged at close); applied_edit_surface is git-proven ground truth
1086
+ // that must survive replanning for the same reason.
1087
+ ...(previous.run_start_dirty
1088
+ ? { run_start_dirty: previous.run_start_dirty }
1089
+ : {}),
1090
+ ...(previous.applied_edit_surface
1091
+ ? { applied_edit_surface: previous.applied_edit_surface }
1092
+ : {}),
1093
1093
  };
1094
1094
  const extractedPlan = await readExtractedPlanIfPresent(artifactsDir);
1095
1095
  if (!extractedPlan) {
@@ -1681,6 +1681,17 @@ async function handlePendingExtractedPlan(root, artifactsDir, existing, extracte
1681
1681
  throw new Error("Every extracted finding cited only phantom paths; re-extract with real repo-relative paths.");
1682
1682
  }
1683
1683
  const pipelined = await applyPlanPipeline(plan, { root, artifactsDir });
1684
+ // Run-start dirty snapshot for the V2 staging manifest, capture-once: the
1685
+ // extracted-plan join runs at plan time (before any remediation edit), so
1686
+ // the dirty set here is pre-existing user dirt — the close phase excludes
1687
+ // it from DECLARED-surface staging. runPlanPhase captures the same field on
1688
+ // the structured-audit path; whichever join runs first wins.
1689
+ if (!existing.run_start_dirty) {
1690
+ existing = {
1691
+ ...existing,
1692
+ run_start_dirty: [...stagedAndUntracked(root)].sort(),
1693
+ };
1694
+ }
1684
1695
  const reviewDecision = await readOptionalJsonFile(reviewDecisionPath(artifactsDir));
1685
1696
  // Coverage ledger. Path A (structured_audit): the single filter pass ran at
1686
1697
  // intake over the ORIGINAL findings and persisted its dispositions — build
@@ -2010,12 +2021,12 @@ async function emitAutonomousLeftoverDeliverable(root, artifactsDir, leftovers)
2010
2021
  });
2011
2022
  // Prefer the canonical `.audit-tools/` location (defaultInputCandidates[0]);
2012
2023
  // fall back to the artifacts dir's parent when artifactsDir is non-standard.
2013
- const auditToolsDir = join(root, ".audit-tools");
2014
- const outDir = existsSync(auditToolsDir) ? auditToolsDir : dirname(artifactsDir);
2024
+ const canonicalOutDir = auditToolsDir(root);
2025
+ const outDir = existsSync(canonicalOutDir) ? canonicalOutDir : dirname(artifactsDir);
2015
2026
  await mkdir(outDir, { recursive: true });
2016
2027
  await Promise.all([
2017
- writeJsonFile(join(outDir, "audit-findings.json"), pair.findings_report),
2018
- writeTextFile(join(outDir, "audit-report.md"), pair.report_markdown),
2028
+ writeJsonFile(join(outDir, AUDIT_FINDINGS_FILENAME), pair.findings_report),
2029
+ writeTextFile(join(outDir, AUDIT_REPORT_FILENAME), pair.report_markdown),
2019
2030
  ]);
2020
2031
  }
2021
2032
  // ── Path-A filter dispositions (persisted for the coverage ledger) ──────────────
@@ -2114,21 +2125,37 @@ async function handleReadyIntakeContractPipeline(root, artifactsDir, options) {
2114
2125
  }
2115
2126
  // Persist the filter dispositions so coverage is built over the originals.
2116
2127
  await persistReviewFilterDispositions(artifactsDir, originals, filter);
2117
- // A1 — conservative lean fast path. When the approved set is a handful
2118
- // of grounded, high-confidence, localized, non-cross-cutting findings,
2119
- // the run skips the heavy contract DESIGN loop and synthesizes the
2120
- // extracted plan directly; the plan→implement→close machinery (per-node
2121
- // verify-before-merge + the final whole-repo gate) is the retained safety
2122
- // net. Runs only here — on Path A (structured_audit), the only intake
2123
- // with a pre-existing finding set to judge.
2128
+ // Lean path = the `low` risk tier's realization (D-68 — leanFastPath folded
2129
+ // into the self-scaling dial). A run skips the heavy contract DESIGN loop and
2130
+ // synthesizes the extracted plan directly IFF its effective risk tier is `low`;
2131
+ // the plan→implement→close machinery (per-node verify-before-merge + the final
2132
+ // whole-repo gate) is the retained safety net. Runs only here — on Path A
2133
+ // (structured_audit), the only intake with a pre-existing finding set to judge.
2124
2134
  //
2125
- // T1 slice 3b — the fast path is NOT zero-scrutiny: an eligible run first
2126
- // runs a bounded LIGHT adversarial review over the approved findings (the
2127
- // floor, never off). A clear verdict proceeds to the lean plan; a verdict
2128
- // that surfaces a real concern escalates the risk signal (evidence the
2129
- // work is harder than assessed) and routes to the full pipeline below.
2130
- const fast = evaluateFastPath(gate.approved);
2131
- if (fast.eligible) {
2135
+ // First fold the APPROVED set's finding-level risk (grounding / confidence /
2136
+ // coupling / systemic / architecture / count — the finding-QUALITY dimension the
2137
+ // intake path/breadth/intent signal doesn't see) INTO the shared risk signal as
2138
+ // escalate-on-evidence. This makes the tier the SINGLE classifier: there is no
2139
+ // separate fast-path boolean that can DISAGREE with it (a grounded handful
2140
+ // touching a risk subsystem stays `high` and takes the full pipeline, instead of
2141
+ // bypassing it as the old parallel `evaluateFastPath` allowed).
2142
+ const findingEvidence = findingRiskEvidence(gate.approved);
2143
+ let riskSignal = await readIntakeRiskSignal(artifactsDir);
2144
+ if (findingEvidence && riskSignal) {
2145
+ const raised = escalateRiskSignal(riskSignal, findingEvidence);
2146
+ // escalateRiskSignal returns the SAME reference when the evidence does not
2147
+ // raise the tier — only persist on an actual change (no byte-identical rewrite).
2148
+ if (raised !== riskSignal) {
2149
+ riskSignal = raised;
2150
+ await writeIntakeRiskSignal(artifactsDir, riskSignal);
2151
+ }
2152
+ }
2153
+ // T1 slice 3b — the lean tier is NOT zero-scrutiny: a `low`-tier run first runs
2154
+ // a bounded LIGHT adversarial review over the approved findings (the floor,
2155
+ // never off — `adversarialDepthForTier("low") === "light"`). A clear verdict
2156
+ // proceeds to the lean plan; a verdict that surfaces a real concern escalates
2157
+ // the risk signal and routes to the full pipeline below.
2158
+ if (gate.approved.length > 0 && riskSignal?.tier === "low") {
2132
2159
  const review = await runLeanLightReviewGate(root, artifactsDir, gate.approved);
2133
2160
  if (review.kind === "halt") {
2134
2161
  return review.step;
@@ -2137,20 +2164,17 @@ async function handleReadyIntakeContractPipeline(root, artifactsDir, options) {
2137
2164
  // Escalate-on-evidence: raise the signal to at least `medium` so the
2138
2165
  // full pipeline's adversarial depth is `full` (see slice 3a), then
2139
2166
  // fall through to the full pipeline.
2140
- const current = await readIntakeRiskSignal(artifactsDir);
2141
- if (current) {
2142
- await writeIntakeRiskSignal(artifactsDir, escalateRiskSignal(current, {
2143
- tier: "medium",
2144
- reason: `lean light review surfaced a concern: ${review.concerns.join("; ")}`,
2145
- }));
2146
- }
2167
+ await writeIntakeRiskSignal(artifactsDir, escalateRiskSignal(riskSignal, {
2168
+ tier: "medium",
2169
+ reason: `lean light review surfaced a concern: ${review.concerns.join("; ")}`,
2170
+ }));
2147
2171
  process.stderr.write(`[remediate-code] Lean light review escalated (${review.concerns.join("; ")}); routing to the full contract pipeline.\n`);
2148
2172
  }
2149
2173
  else {
2150
2174
  // Clear verdict → proceed with the lean plan.
2151
2175
  const leanPlan = buildLeanExtractedPlan(gate.approved, randomRunId("LEAN"));
2152
2176
  await writeJsonFile(intakePaths(artifactsDir).extractedPlan, leanPlan);
2153
- process.stderr.write(`[remediate-code] Lean fast path: ${fast.reason}; light review clear. Routing to plan→implement.\n`);
2177
+ process.stderr.write(`[remediate-code] Lean fast path (risk tier low): ${riskSignal.rationale.join("; ")}; light review clear. Routing to plan→implement.\n`);
2154
2178
  const planned = await handlePendingExtractedPlan(root, artifactsDir, { status: "pending" }, leanPlan);
2155
2179
  if (planned) {
2156
2180
  return planned;