audit-tools 0.55.4 → 0.55.6

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 (262) hide show
  1. package/dist/audit/cli/auditReviewBindings.d.ts +4 -4
  2. package/dist/audit/cli/auditStep.d.ts +15 -1
  3. package/dist/audit/cli/auditStep.d.ts.map +1 -1
  4. package/dist/audit/cli/auditStep.js +24 -11
  5. package/dist/audit/cli/auditStep.js.map +1 -1
  6. package/dist/audit/cli/charterExtractionPrompt.d.ts.map +1 -1
  7. package/dist/audit/cli/charterExtractionPrompt.js +3 -1
  8. package/dist/audit/cli/charterExtractionPrompt.js.map +1 -1
  9. package/dist/audit/cli/cleanup.d.ts.map +1 -1
  10. package/dist/audit/cli/cleanup.js +26 -2
  11. package/dist/audit/cli/cleanup.js.map +1 -1
  12. package/dist/audit/cli/conceptualDispatch.d.ts +2 -0
  13. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  14. package/dist/audit/cli/conceptualDispatch.js +29 -8
  15. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  16. package/dist/audit/cli/dispatch/hostHandoff.d.ts +37 -3
  17. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  18. package/dist/audit/cli/dispatch/hostHandoff.js +185 -16
  19. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  20. package/dist/audit/cli/dispatch/packetFilter.d.ts +1 -1
  21. package/dist/audit/cli/envelope.d.ts +1 -1
  22. package/dist/audit/cli/envelope.d.ts.map +1 -1
  23. package/dist/audit/cli/envelope.js +4 -1
  24. package/dist/audit/cli/envelope.js.map +1 -1
  25. package/dist/audit/cli/fanoutLanes.d.ts +30 -0
  26. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
  27. package/dist/audit/cli/fanoutLanes.js +76 -8
  28. package/dist/audit/cli/fanoutLanes.js.map +1 -1
  29. package/dist/audit/cli/laneValidators.d.ts +9 -6
  30. package/dist/audit/cli/laneValidators.d.ts.map +1 -1
  31. package/dist/audit/cli/laneValidators.js +22 -7
  32. package/dist/audit/cli/laneValidators.js.map +1 -1
  33. package/dist/audit/cli/nextStepCommand.d.ts +3 -0
  34. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  35. package/dist/audit/cli/nextStepCommand.js +104 -66
  36. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  37. package/dist/audit/cli/nextStepHelpers.d.ts +49 -14
  38. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  39. package/dist/audit/cli/nextStepHelpers.js +169 -68
  40. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  41. package/dist/audit/cli/reviewRun.d.ts +10 -0
  42. package/dist/audit/cli/reviewRun.d.ts.map +1 -1
  43. package/dist/audit/cli/reviewRun.js +4 -3
  44. package/dist/audit/cli/reviewRun.js.map +1 -1
  45. package/dist/audit/cli/sampleRunCommand.d.ts +1 -1
  46. package/dist/audit/cli/semanticReviewStep.d.ts +2 -0
  47. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  48. package/dist/audit/cli/semanticReviewStep.js +5 -50
  49. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  50. package/dist/audit/cli/validateResultsCommand.d.ts.map +1 -1
  51. package/dist/audit/cli/validateResultsCommand.js +3 -1
  52. package/dist/audit/cli/validateResultsCommand.js.map +1 -1
  53. package/dist/audit/contracts/workerSchemas.d.ts +14 -14
  54. package/dist/audit/extractors/fsIntake.d.ts +13 -0
  55. package/dist/audit/extractors/fsIntake.d.ts.map +1 -1
  56. package/dist/audit/extractors/fsIntake.js +11 -1
  57. package/dist/audit/extractors/fsIntake.js.map +1 -1
  58. package/dist/audit/io/artifacts.d.ts +35 -9
  59. package/dist/audit/io/artifacts.d.ts.map +1 -1
  60. package/dist/audit/io/artifacts.js +84 -67
  61. package/dist/audit/io/artifacts.js.map +1 -1
  62. package/dist/audit/io/rollover.d.ts +18 -0
  63. package/dist/audit/io/rollover.d.ts.map +1 -0
  64. package/dist/audit/io/rollover.js +152 -0
  65. package/dist/audit/io/rollover.js.map +1 -0
  66. package/dist/audit/io/runSnapshot.d.ts +149 -0
  67. package/dist/audit/io/runSnapshot.d.ts.map +1 -0
  68. package/dist/audit/io/runSnapshot.js +710 -0
  69. package/dist/audit/io/runSnapshot.js.map +1 -0
  70. package/dist/audit/orchestrator/advanceTypes.d.ts +11 -0
  71. package/dist/audit/orchestrator/advanceTypes.d.ts.map +1 -1
  72. package/dist/audit/orchestrator/autoFixExecutor.d.ts +9 -0
  73. package/dist/audit/orchestrator/autoFixExecutor.d.ts.map +1 -1
  74. package/dist/audit/orchestrator/autoFixExecutor.js +22 -2
  75. package/dist/audit/orchestrator/autoFixExecutor.js.map +1 -1
  76. package/dist/audit/orchestrator/charterExtractionExecutor.d.ts.map +1 -1
  77. package/dist/audit/orchestrator/charterExtractionExecutor.js +18 -3
  78. package/dist/audit/orchestrator/charterExtractionExecutor.js.map +1 -1
  79. package/dist/audit/orchestrator/charterPackets.d.ts +11 -1
  80. package/dist/audit/orchestrator/charterPackets.d.ts.map +1 -1
  81. package/dist/audit/orchestrator/charterPackets.js +13 -0
  82. package/dist/audit/orchestrator/charterPackets.js.map +1 -1
  83. package/dist/audit/orchestrator/dependencyMap.d.ts.map +1 -1
  84. package/dist/audit/orchestrator/dependencyMap.js +6 -0
  85. package/dist/audit/orchestrator/dependencyMap.js.map +1 -1
  86. package/dist/audit/orchestrator/dependencySlices.d.ts.map +1 -1
  87. package/dist/audit/orchestrator/dependencySlices.js +35 -11
  88. package/dist/audit/orchestrator/dependencySlices.js.map +1 -1
  89. package/dist/audit/orchestrator/designReviewPrompt.d.ts +9 -0
  90. package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -1
  91. package/dist/audit/orchestrator/designReviewPrompt.js +69 -31
  92. package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -1
  93. package/dist/audit/orchestrator/designReviewSnapshot.d.ts +1 -0
  94. package/dist/audit/orchestrator/designReviewSnapshot.d.ts.map +1 -1
  95. package/dist/audit/orchestrator/designReviewSnapshot.js +2 -1
  96. package/dist/audit/orchestrator/designReviewSnapshot.js.map +1 -1
  97. package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
  98. package/dist/audit/orchestrator/executorRunners.js +13 -4
  99. package/dist/audit/orchestrator/executorRunners.js.map +1 -1
  100. package/dist/audit/orchestrator/hostInputPause.js +1 -1
  101. package/dist/audit/orchestrator/hostInputPause.js.map +1 -1
  102. package/dist/audit/orchestrator/intakeExecutors.d.ts +8 -1
  103. package/dist/audit/orchestrator/intakeExecutors.d.ts.map +1 -1
  104. package/dist/audit/orchestrator/intakeExecutors.js +13 -4
  105. package/dist/audit/orchestrator/intakeExecutors.js.map +1 -1
  106. package/dist/audit/orchestrator/obligationPolicy.d.ts.map +1 -1
  107. package/dist/audit/orchestrator/obligationPolicy.js +4 -1
  108. package/dist/audit/orchestrator/obligationPolicy.js.map +1 -1
  109. package/dist/audit/orchestrator/planningExecutors.d.ts +1 -1
  110. package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
  111. package/dist/audit/orchestrator/planningExecutors.js +40 -6
  112. package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
  113. package/dist/audit/orchestrator/requeueCommand.d.ts +1 -1
  114. package/dist/audit/orchestrator/systemicChallengeExecutor.d.ts.map +1 -1
  115. package/dist/audit/orchestrator/systemicChallengeExecutor.js +4 -1
  116. package/dist/audit/orchestrator/systemicChallengeExecutor.js.map +1 -1
  117. package/dist/audit/orchestrator/taskBuilder.d.ts +20 -0
  118. package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -1
  119. package/dist/audit/orchestrator/taskBuilder.js +80 -18
  120. package/dist/audit/orchestrator/taskBuilder.js.map +1 -1
  121. package/dist/audit/systemic/reviewFileMap.d.ts +72 -21
  122. package/dist/audit/systemic/reviewFileMap.d.ts.map +1 -1
  123. package/dist/audit/systemic/reviewFileMap.js +96 -45
  124. package/dist/audit/systemic/reviewFileMap.js.map +1 -1
  125. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts +7 -0
  126. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts.map +1 -1
  127. package/dist/audit/systemic/secondOrderAdversaryPrompt.js +39 -8
  128. package/dist/audit/systemic/secondOrderAdversaryPrompt.js.map +1 -1
  129. package/dist/audit/types.d.ts +12 -12
  130. package/dist/audit/validation/auditResults.d.ts +1 -0
  131. package/dist/audit/validation/auditResults.d.ts.map +1 -1
  132. package/dist/audit/validation/auditResults.js +1 -0
  133. package/dist/audit/validation/auditResults.js.map +1 -1
  134. package/dist/remediate/findingFilter.js +1 -1
  135. package/dist/remediate/findingFilter.js.map +1 -1
  136. package/dist/remediate/phases/close.d.ts +1 -0
  137. package/dist/remediate/phases/close.d.ts.map +1 -1
  138. package/dist/remediate/phases/close.js +29 -5
  139. package/dist/remediate/phases/close.js.map +1 -1
  140. package/dist/remediate/phases/closeVerifyAnalyzerLeads.d.ts +1 -1
  141. package/dist/remediate/phases/triage.d.ts +2 -1
  142. package/dist/remediate/phases/triage.d.ts.map +1 -1
  143. package/dist/remediate/phases/triage.js +46 -25
  144. package/dist/remediate/phases/triage.js.map +1 -1
  145. package/dist/remediate/phases/triageConformance.d.ts +14 -0
  146. package/dist/remediate/phases/triageConformance.d.ts.map +1 -0
  147. package/dist/remediate/phases/triageConformance.js +189 -0
  148. package/dist/remediate/phases/triageConformance.js.map +1 -0
  149. package/dist/remediate/state/decisionConsumption.d.ts +110 -0
  150. package/dist/remediate/state/decisionConsumption.d.ts.map +1 -0
  151. package/dist/remediate/state/decisionConsumption.js +122 -0
  152. package/dist/remediate/state/decisionConsumption.js.map +1 -0
  153. package/dist/remediate/state/store.d.ts +4 -0
  154. package/dist/remediate/state/store.d.ts.map +1 -1
  155. package/dist/remediate/state/store.js +16 -0
  156. package/dist/remediate/state/store.js.map +1 -1
  157. package/dist/remediate/steps/contractPipeline.d.ts +0 -6
  158. package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
  159. package/dist/remediate/steps/contractPipeline.js +3 -32
  160. package/dist/remediate/steps/contractPipeline.js.map +1 -1
  161. package/dist/remediate/steps/dispatch/contractConformanceReview.d.ts +9 -0
  162. package/dist/remediate/steps/dispatch/contractConformanceReview.d.ts.map +1 -1
  163. package/dist/remediate/steps/dispatch/contractConformanceReview.js +32 -14
  164. package/dist/remediate/steps/dispatch/contractConformanceReview.js.map +1 -1
  165. package/dist/remediate/steps/dispatch/hostContracts.js +1 -1
  166. package/dist/remediate/steps/dispatch/hostContracts.js.map +1 -1
  167. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  168. package/dist/remediate/steps/dispatch/hostHandoff.js +6 -2
  169. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  170. package/dist/remediate/steps/dispatch/requiredTests.js +1 -1
  171. package/dist/remediate/steps/dispatch/requiredTests.js.map +1 -1
  172. package/dist/remediate/steps/gateCommands.d.ts +1 -0
  173. package/dist/remediate/steps/gateCommands.d.ts.map +1 -1
  174. package/dist/remediate/steps/gateCommands.js +8 -52
  175. package/dist/remediate/steps/gateCommands.js.map +1 -1
  176. package/dist/remediate/steps/nextStep.d.ts +7 -0
  177. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  178. package/dist/remediate/steps/nextStep.js +69 -75
  179. package/dist/remediate/steps/nextStep.js.map +1 -1
  180. package/dist/remediate/steps/prompts.d.ts.map +1 -1
  181. package/dist/remediate/steps/prompts.js +6 -9
  182. package/dist/remediate/steps/prompts.js.map +1 -1
  183. package/dist/remediate/steps/recoverIngest.js +1 -1
  184. package/dist/remediate/steps/recoverIngest.js.map +1 -1
  185. package/dist/shared/analyzers/provenance.d.ts +1 -1
  186. package/dist/shared/analyzers/provenance.js +1 -1
  187. package/dist/shared/contentKey.d.ts +3 -2
  188. package/dist/shared/contentKey.d.ts.map +1 -1
  189. package/dist/shared/contentKey.js +3 -2
  190. package/dist/shared/contentKey.js.map +1 -1
  191. package/dist/shared/decompose/charterExtraction.d.ts +200 -13
  192. package/dist/shared/decompose/charterExtraction.d.ts.map +1 -1
  193. package/dist/shared/decompose/charterExtraction.js +34 -6
  194. package/dist/shared/decompose/charterExtraction.js.map +1 -1
  195. package/dist/shared/decompose/systemicChallenge.js +1 -1
  196. package/dist/shared/decompose/systemicChallenge.js.map +1 -1
  197. package/dist/shared/engine/obligationEngine.d.ts +1 -1
  198. package/dist/shared/engine/obligationEngine.js +1 -1
  199. package/dist/shared/findings/dedupe.js +1 -1
  200. package/dist/shared/findings/dedupe.js.map +1 -1
  201. package/dist/shared/git.d.ts +30 -1
  202. package/dist/shared/git.d.ts.map +1 -1
  203. package/dist/shared/git.js +65 -6
  204. package/dist/shared/git.js.map +1 -1
  205. package/dist/shared/index.d.ts +1 -0
  206. package/dist/shared/index.d.ts.map +1 -1
  207. package/dist/shared/index.js +1 -0
  208. package/dist/shared/index.js.map +1 -1
  209. package/dist/shared/intent/clauseBoundaries.d.ts +1 -0
  210. package/dist/shared/intent/clauseBoundaries.d.ts.map +1 -1
  211. package/dist/shared/intent/clauseBoundaries.js +1 -0
  212. package/dist/shared/intent/clauseBoundaries.js.map +1 -1
  213. package/dist/shared/intent/pathScope.d.ts +1 -0
  214. package/dist/shared/intent/pathScope.d.ts.map +1 -1
  215. package/dist/shared/intent/pathScope.js +1 -0
  216. package/dist/shared/intent/pathScope.js.map +1 -1
  217. package/dist/shared/io/nodeWorktreeGuard.d.ts +1 -1
  218. package/dist/shared/io/nodeWorktreeGuard.js +1 -1
  219. package/dist/shared/io/pathIdentity.d.ts.map +1 -1
  220. package/dist/shared/io/pathIdentity.js +1 -0
  221. package/dist/shared/io/pathIdentity.js.map +1 -1
  222. package/dist/shared/io/stepContractWriter.d.ts +1 -0
  223. package/dist/shared/io/stepContractWriter.d.ts.map +1 -1
  224. package/dist/shared/io/stepContractWriter.js +1 -0
  225. package/dist/shared/io/stepContractWriter.js.map +1 -1
  226. package/dist/shared/loopCorePaths.d.ts.map +1 -1
  227. package/dist/shared/loopCorePaths.js +11 -0
  228. package/dist/shared/loopCorePaths.js.map +1 -1
  229. package/dist/shared/prompts.d.ts +2 -0
  230. package/dist/shared/prompts.d.ts.map +1 -1
  231. package/dist/shared/prompts.js +8 -2
  232. package/dist/shared/prompts.js.map +1 -1
  233. package/dist/shared/submission/ingestReport.d.ts.map +1 -1
  234. package/dist/shared/submission/ingestReport.js +19 -1
  235. package/dist/shared/submission/ingestReport.js.map +1 -1
  236. package/dist/shared/submission/submissionLedger.js +2 -2
  237. package/dist/shared/submission/submissionLedger.js.map +1 -1
  238. package/dist/shared/submission/submissionScan.js +1 -1
  239. package/dist/shared/submission/submissionScan.js.map +1 -1
  240. package/dist/shared/tooling/exec.js +2 -2
  241. package/dist/shared/tooling/exec.js.map +1 -1
  242. package/dist/shared/types/charter.d.ts +9 -0
  243. package/dist/shared/types/charter.d.ts.map +1 -1
  244. package/dist/shared/types/charter.js +7 -0
  245. package/dist/shared/types/charter.js.map +1 -1
  246. package/dist/shared/types/closingActions.js +1 -1
  247. package/dist/shared/types/closingActions.js.map +1 -1
  248. package/dist/shared/types/finding.js +2 -2
  249. package/dist/shared/types/finding.js.map +1 -1
  250. package/dist/shared/types/stepContract.js +1 -1
  251. package/dist/shared/types/stepContract.js.map +1 -1
  252. package/dist/shared/validation/findingGrounding.d.ts +1 -0
  253. package/dist/shared/validation/findingGrounding.d.ts.map +1 -1
  254. package/dist/shared/validation/findingGrounding.js +1 -0
  255. package/dist/shared/validation/findingGrounding.js.map +1 -1
  256. package/dist/shared/validation/producerBoundary.d.ts +10 -0
  257. package/dist/shared/validation/producerBoundary.d.ts.map +1 -0
  258. package/dist/shared/validation/producerBoundary.js +26 -0
  259. package/dist/shared/validation/producerBoundary.js.map +1 -0
  260. package/docs/audit-pkg/contracts.md +6 -2
  261. package/docs/audit-pkg/operator-guide.md +13 -4
  262. package/package.json +5 -1
@@ -1,6 +1,6 @@
1
1
  import { designReviewInputRevision } from "../orchestrator/designReviewProjection.js";
2
2
  import { decodeAuditReviewSubmission, readAuditReviewSubmission, currentAuditReviewInputRevision, auditLaneReviewRequirement } from "./reviewSubmission.js";
3
- // sites-pinned: tests/audit/next-step-helpers.test.ts, tests/audit/charter-emit-order.test.ts, tests/audit/executor-registry-sync.test.ts, tests/audit/pipeline-integration.test.ts
3
+ // sites-pinned: tests/audit/next-step-helpers.test.ts, tests/audit/charter-emit-order.test.ts, tests/audit/executor-registry-sync.test.ts, tests/audit/pipeline-integration.test.ts, tests/audit/next-step-integrity-reintake.test.ts
4
4
  /**
5
5
  * Extracted helpers for the next-step command.
6
6
  *
@@ -11,14 +11,16 @@ import { decodeAuditReviewSubmission, readAuditReviewSubmission, currentAuditRev
11
11
  import { AnalyzerRunConsentDecisionSchema, readRunConsentUnlocked, updateRunConsentUnlocked } from "../../shared/analyzerRunConsent.js";
12
12
  import { mkdir, readFile, unlink } from "node:fs/promises";
13
13
  import { join, relative } from "node:path";
14
- import { advance, ANALYZER_SETTINGS, describeStoppedFold, RunLogger, hashContent, isFileMissingError, isJsonParseError, isRecord, readJsonFile, readSubmissionIngestHistory, readTrailingSubmissionRefusals, persistAnalyzerSettings, writeJsonFile, } from "audit-tools/shared";
14
+ import { AUDIT_FINDINGS_FILENAME, auditFindingsPath, promotedAuditFindingsPath, advance, ANALYZER_SETTINGS, describeStoppedFold, RunLogger, hashContent, isFileMissingError, isJsonParseError, isRecord, readJsonFile, readSubmissionIngestHistory, readTrailingSubmissionRefusals, persistAnalyzerSettings, writeJsonFile, writeTextFile, } from "audit-tools/shared";
15
15
  import { loadArtifactBundle, promoteFinalAuditReport, } from "../io/artifacts.js";
16
+ import { ensureRunSourceRoot, removeRunSnapshot, resolveRunSince } from "../io/runSnapshot.js";
17
+ import { markRunEnded } from "../io/rollover.js";
16
18
  import { auditReportPath, groundDesignFindings, repoPathUniverse, systemicChallengeSchema, laneAssetsDir, promotedAuditReportPath, } from "audit-tools/shared";
17
19
  import { charterExtractionKindsForCeiling } from "./charterExtractionPrompt.js";
18
20
  import { archiveCharterPackets } from "../orchestrator/charterPacketArchive.js";
19
21
  import { LANE_SUBMISSION_SCHEMAS, charterLaneSchema, describeSubmissionShapeMismatch, unwrapSubmissionArray, } from "./laneValidators.js";
20
22
  import { ConceptualJudgeSubmissionSchema, buildConceptualReviewAdjudication, deriveConceptualVerificationStatus, loadConceptualPerspectiveFindings, MalformedConceptualPerspectivesError, readConceptualReviewRoundManifest, SubmittedDesignFindingSchema, suppliedToolVerdictIssue, } from "../types/conceptualAdjudication.js";
21
- import { advanceAudit, engineMaxTransitions, findExecutorFailure, runSingleAdvanceStep, startAdvanceHeartbeat, MAX_DRAIN_STEPS, } from "../orchestrator/advance.js";
23
+ import { engineMaxTransitions, findExecutorFailure, runSingleAdvanceStep, startAdvanceHeartbeat, MAX_DRAIN_STEPS, } from "../orchestrator/advance.js";
22
24
  import { buildDesignReviewSnapshot, isDesignReviewStale, } from "../orchestrator/designReviewSnapshot.js";
23
25
  import { computeStaleArtifacts, emitStalenessRecord, isMetadataMigrationStaleness, resetStalenessDedup, } from "../orchestrator/staleness.js";
24
26
  import { commitFold, createFoldTransaction, markSubmissionApplied, describeQuarantineLocation, quarantineLocationPhrase, quarantineSubmissionFile, quarantineSurvivalNote, recoverStagedSubmissions, stageLaneSubmission, } from "./foldTransaction.js";
@@ -39,7 +41,8 @@ import { buildPendingAuditTasks } from "./dispatch/packetFilter.js";
39
41
  import { buildLineIndex } from "./lineIndex.js";
40
42
  import { ingestAuditHostResults, } from "./dispatch/hostHandoff.js";
41
43
  import { auditIngestRemedy, } from "../validation/ingestIssueCodes.js";
42
- import { CHARTER_EXTRACTION_MERGED_FILENAME, AUDIT_GATE_SUBMISSION_SCOPE, GATE_LANES, charterExtractionCoverageFilename, charterExtractionLane, closeDispatchedLaneOutcomes, laneSubmissionPath, laneSubmissionId, recordLaneOutcome, systemicChallengeLane, } from "./laneSubmissions.js";
44
+ import { buildCharterPacketManifest, carriedCharterLane, materializeCharterPacket, } from "../orchestrator/charterPackets.js";
45
+ import { CHARTER_EXTRACTION_MERGED_FILENAME, AUDIT_GATE_SUBMISSION_SCOPE, GATE_LANES, charterExtractionCoverageFilename, charterExtractionLane, charterExtractionPacketFilename, closeDispatchedLaneOutcomes, laneSubmissionPath, laneSubmissionId, recordLaneOutcome, systemicChallengeLane, } from "./laneSubmissions.js";
43
46
  import { recordHostResultOutcomes, renderIngestReportLines } from "audit-tools/shared";
44
47
  /**
45
48
  * Read a lane's submission from the TOOL-COMPUTED path its emission bound —
@@ -90,6 +93,17 @@ export async function tryConsumeSubmission(artifactsDir, lane, tx, currentInputR
90
93
  throw error;
91
94
  }
92
95
  }
96
+ /**
97
+ * The fold's source root. Throws when read before the fold resolved the run's
98
+ * snapshot: a content read against the LIVE root would silently break the
99
+ * frozen-input property, so there is no fallback.
100
+ */
101
+ export function requireSourceRoot(params) {
102
+ if (params.sourceRoot === undefined) {
103
+ throw new Error("next-step: a content read ran before the run's snapshot was resolved");
104
+ }
105
+ return params.sourceRoot;
106
+ }
93
107
  /**
94
108
  * The return-kind set as RUNTIME data, so a drift guard can IMPORT the real set
95
109
  * instead of transcribing it into a literal that silently agrees with a second
@@ -153,14 +167,37 @@ async function promoteCompletedReport(artifactsDir) {
153
167
  readFile(inPlacePath, "utf8").catch(() => null),
154
168
  ]);
155
169
  // A missing in-place render alongside an existing promoted file is the
156
- // legitimate re-entry AFTER promotion (promotion deletes artifactsDir);
170
+ // legitimate re-entry AFTER promotion (the next run's rollover deletes it);
157
171
  // a PRESENT in-place render that differs is precisely the stale-promotion
158
172
  // case and must fall through to promote.
159
173
  const alreadyPromoted = promotedText !== null && (inPlaceText === null || promotedText === inPlaceText);
160
- if (alreadyPromoted)
161
- return promotedPath;
162
- const promoted = await promoteFinalAuditReport({ artifactsDir });
163
- return promoted.promoted ? promotedPath : inPlacePath;
174
+ // The machine contract must be one level up before the run may end: the
175
+ // rollover deletes the in-place copy and re-archives only the append-only
176
+ // diagnostics (INV 1). Identity, not existence, here too — a PREVIOUS
177
+ // audit's promoted contract always exists — so a contract whose earlier copy
178
+ // failed is promoted again rather than taken as archived.
179
+ const [inPlaceFindings, promotedFindings] = await Promise.all([
180
+ readFile(auditFindingsPath(artifactsDir)).catch(() => null),
181
+ readFile(promotedAuditFindingsPath(artifactsDir)).catch(() => null),
182
+ ]);
183
+ const findingsCurrent = inPlaceFindings === null || (promotedFindings !== null && inPlaceFindings.equals(promotedFindings));
184
+ let findingsArchived = true;
185
+ if (!alreadyPromoted || !findingsCurrent) {
186
+ const promoted = await promoteFinalAuditReport({ artifactsDir });
187
+ if (!promoted.promoted)
188
+ return inPlacePath;
189
+ findingsArchived = !(promoted.unarchived ?? []).some((member) => member.startsWith(AUDIT_FINDINGS_FILENAME));
190
+ }
191
+ // A presented, promoted report ENDS the run, whatever its status (a rendered
192
+ // report on a stopped fold included — re-reading the same frozen snapshot
193
+ // would only stop it again): its snapshot goes, and the marker lets the next
194
+ // next-step roll the dir over (`rollOverFinishedRun`).
195
+ for (const problem of await removeRunSnapshot(artifactsDir)) {
196
+ process.stderr.write(`[audit-code] run snapshot cleanup: ${problem}\n`);
197
+ }
198
+ if (findingsArchived)
199
+ await markRunEnded(artifactsDir);
200
+ return promotedPath;
164
201
  }
165
202
  /**
166
203
  * Build the terminal step for a deterministic fold that has stopped advancing
@@ -217,7 +254,7 @@ function applyRunConsent(options, consent) {
217
254
  }
218
255
  export async function handleAnalyzerConsentBranch(params, bundle, state, analyzersRef, tx) {
219
256
  const pending = pendingAnalyzerConsent({
220
- root: params.root,
257
+ root: requireSourceRoot(params),
221
258
  analyzers: analyzersRef.value,
222
259
  externalAcquisitionEnabled: params.externalAcquisition?.enabled,
223
260
  analyzerConsent: params.externalAcquisition?.analyzerConsent,
@@ -259,7 +296,7 @@ export async function handleGraphEnrichmentBranch(params, bundle, state, analyze
259
296
  // plan draw's classifier (`obligationPolicy.ts`) and this fold agree EXACTLY
260
297
  // on when the analyzer-install consent / edge-reasoning turns are owed.
261
298
  const pauseInputs = {
262
- root: params.root,
299
+ root: requireSourceRoot(params),
263
300
  analyzers: analyzersRef.value,
264
301
  graphLlmEdgeReasoning: params.graphLlmEdgeReasoning,
265
302
  };
@@ -341,6 +378,7 @@ export async function handleGraphEnrichmentBranch(params, bundle, state, analyze
341
378
  // and an unforced call would re-enter a drain.
342
379
  const applied = await runStep({
343
380
  root: params.root,
381
+ sourceRoot: requireSourceRoot(params),
344
382
  artifactsDir: params.artifactsDir,
345
383
  analyzers: analyzersRef.value,
346
384
  graphLlmEdgeReasoning: true,
@@ -1024,7 +1062,7 @@ export async function handleDesignReviewBranch(params, bundle, state, tx) {
1024
1062
  * above for the two gates that deviate and are not run through this engine.
1025
1063
  */
1026
1064
  async function runOmittableGate(descriptor, params, bundle, state, tx) {
1027
- const incoming = await tryConsumeSubmission(params.artifactsDir, descriptor.lane, tx, auditLaneReviewRequirement(descriptor.lane) === "ordinary" ? undefined : () => currentAuditReviewInputRevision(params.root, bundle, descriptor.lane));
1065
+ const incoming = await tryConsumeSubmission(params.artifactsDir, descriptor.lane, tx, auditLaneReviewRequirement(descriptor.lane) === "ordinary" ? undefined : () => currentAuditReviewInputRevision(requireSourceRoot(params), bundle, descriptor.lane));
1028
1066
  if (incoming.status === "malformed") {
1029
1067
  // Not-JSON submission: same quarantine-loudly lifecycle as a mis-shaped one.
1030
1068
  await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, descriptor.lane, incoming.reason);
@@ -1067,6 +1105,7 @@ export async function handleSynthesisNarrativeBranch(params, bundle, state, tx)
1067
1105
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.synthesis_narrative],
1068
1106
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1069
1107
  root: p.root,
1108
+ sourceRoot: requireSourceRoot(p),
1070
1109
  artifactsDir: p.artifactsDir,
1071
1110
  preferredExecutor: "synthesis_narrative_executor",
1072
1111
  narrativeResultsPath: path,
@@ -1100,6 +1139,7 @@ export async function handleIntentEquivalenceBranch(params, bundle, state, tx) {
1100
1139
  if (parsed.success) {
1101
1140
  const applied = await runAuditStepUnlocked({
1102
1141
  root: params.root,
1142
+ sourceRoot: requireSourceRoot(params),
1103
1143
  artifactsDir: params.artifactsDir,
1104
1144
  preferredExecutor: "intent_equivalence_executor",
1105
1145
  intentEquivalenceVerdictPath: incoming.path,
@@ -1136,6 +1176,7 @@ export async function handleCriticalFlowFallbackBranch(params, bundle, state, tx
1136
1176
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.critical_flow_fallback],
1137
1177
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1138
1178
  root: p.root,
1179
+ sourceRoot: requireSourceRoot(p),
1139
1180
  artifactsDir: p.artifactsDir,
1140
1181
  preferredExecutor: "critical_flow_fallback_executor",
1141
1182
  criticalFlowFallbackResultsPath: path,
@@ -1157,6 +1198,21 @@ export async function handleCriticalFlowFallbackBranch(params, bundle, state, tx
1157
1198
  * - a `deep`/`deepest` ceiling with no submission yet → `return` the host step
1158
1199
  * that renders the charter-extraction prompt.
1159
1200
  */
1201
+ /**
1202
+ * Materialize one charter kind's evidence packet and its coverage manifest into
1203
+ * the lane assets and return the packet's digest. The emitter calls it for every
1204
+ * kind (each lane reads its packet), and so does the merge (the executor checks
1205
+ * every lane's citations against its kind's manifest — a CARRIED lane's
1206
+ * included — and folds every kind's coverage into the register). Idempotent:
1207
+ * the packet derives from the bundle and the frozen snapshot.
1208
+ */
1209
+ export async function writeCharterLaneAssets(params) {
1210
+ const packetPath = join(laneAssetsDir(params.artifactsDir), charterExtractionPacketFilename(params.kind));
1211
+ const packet = await materializeCharterPacket({ root: params.sourceRoot, bundle: params.bundle, kind: params.kind });
1212
+ await writeTextFile(packetPath, packet.markdown);
1213
+ await writeJsonFile(join(laneAssetsDir(params.artifactsDir), charterExtractionCoverageFilename(params.kind)), buildCharterPacketManifest(params.kind, packet.excerpts, packet.coverage));
1214
+ return { packetPath, packet, digest: hashContent(packet.markdown) };
1215
+ }
1160
1216
  export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1161
1217
  const ceiling = resolveCharterCeiling(bundle.intent_checkpoint);
1162
1218
  // Shallow ceiling (default): omit deterministically, no host turn, no lanes.
@@ -1176,13 +1232,33 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1176
1232
  const kinds = charterExtractionKindsForCeiling(ceiling);
1177
1233
  const universe = new Set((bundle.repo_manifest?.files ?? []).map((file) => file.path));
1178
1234
  const laneValues = new Map();
1235
+ // A kind whose packet did not change since the previous register's lane was
1236
+ // written is CARRIED (the emitter asked no lane for it); every other kind is
1237
+ // authored from a lane submission. The digest is the one each authored lane
1238
+ // records.
1239
+ const carried = new Map();
1240
+ const digests = new Map();
1241
+ for (const kind of kinds) {
1242
+ const { digest } = await writeCharterLaneAssets({
1243
+ sourceRoot: requireSourceRoot(params),
1244
+ artifactsDir: params.artifactsDir,
1245
+ bundle,
1246
+ kind,
1247
+ });
1248
+ digests.set(kind, digest);
1249
+ const reused = carriedCharterLane(bundle, kind, digest);
1250
+ if (reused !== undefined)
1251
+ carried.set(kind, reused);
1252
+ }
1179
1253
  let quarantinedAny = false;
1180
1254
  for (const kind of kinds) {
1255
+ if (carried.has(kind))
1256
+ continue;
1181
1257
  const lane = charterExtractionLane(kind);
1182
1258
  // Staged per lane; an INCOMPLETE set is restored to its bound paths at
1183
1259
  // commit (un-applied), which is exactly the K-of-N resume the design
1184
1260
  // wants — pending lanes survive on disk until every lane is present.
1185
- const incoming = await tryConsumeSubmission(params.artifactsDir, lane, tx, () => currentAuditReviewInputRevision(params.root, bundle, lane));
1261
+ const incoming = await tryConsumeSubmission(params.artifactsDir, lane, tx, () => currentAuditReviewInputRevision(requireSourceRoot(params), bundle, lane));
1186
1262
  if (incoming.status === "absent")
1187
1263
  continue;
1188
1264
  if (incoming.status === "malformed") {
@@ -1190,7 +1266,7 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1190
1266
  await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, lane, incoming.reason);
1191
1267
  continue;
1192
1268
  }
1193
- const parsed = charterLaneSchema(universe).safeParse(incoming.value);
1269
+ const parsed = charterLaneSchema(universe, kind).safeParse(incoming.value);
1194
1270
  if (parsed.success) {
1195
1271
  laneValues.set(kind, { value: parsed.data, path: incoming.path });
1196
1272
  }
@@ -1199,7 +1275,7 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1199
1275
  await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, lane, parsed.error);
1200
1276
  }
1201
1277
  }
1202
- if (!quarantinedAny && laneValues.size === kinds.length) {
1278
+ if (!quarantinedAny && laneValues.size + carried.size === kinds.length) {
1203
1279
  // Complete + valid: tool-side merge (stable by lane order = canonical kind
1204
1280
  // order), then one executor ingest; unlink lane files only after apply.
1205
1281
  // The post-apply unlink is the standard consumed-submission lifecycle
@@ -1212,7 +1288,12 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1212
1288
  // "which lane is this", and asking the lane to restate it only ever let the
1213
1289
  // lane check itself (owner review of prompt 8, 2026-09-17).
1214
1290
  const merged = {
1215
- lanes: kinds.map((kind) => ({ kind, ...laneValues.get(kind).value })),
1291
+ // `inputs` was checked at the gate; the merged lane carries the DAG only.
1292
+ lanes: kinds.filter((kind) => !carried.has(kind)).map((kind) => {
1293
+ const { inputs: _declared, ...dag } = laneValues.get(kind).value;
1294
+ return { kind, packet_sha256: digests.get(kind), ...dag };
1295
+ }),
1296
+ carried: [...carried.values()],
1216
1297
  };
1217
1298
  // The merged submission is TOOL-written, so it lives with the other lane
1218
1299
  // assets rather than under `submissions/` (which holds only what a host
@@ -1221,6 +1302,7 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1221
1302
  await writeJsonFile(mergedPath, merged);
1222
1303
  const applied = await runAuditStepUnlocked({
1223
1304
  root: params.root,
1305
+ sourceRoot: requireSourceRoot(params),
1224
1306
  artifactsDir: params.artifactsDir,
1225
1307
  preferredExecutor: "charter_extraction_executor",
1226
1308
  charterSubmissionPath: mergedPath,
@@ -1272,6 +1354,7 @@ export async function handleCharterComparisonBranch(params, bundle, state, tx) {
1272
1354
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.charter_comparison],
1273
1355
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1274
1356
  root: p.root,
1357
+ sourceRoot: requireSourceRoot(p),
1275
1358
  artifactsDir: p.artifactsDir,
1276
1359
  preferredExecutor: "charter_comparison_executor",
1277
1360
  charterComparisonSubmissionPath: path,
@@ -1292,6 +1375,7 @@ export async function handleCharterFidelityBranch(params, bundle, state, tx) {
1292
1375
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.charter_fidelity],
1293
1376
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1294
1377
  root: p.root,
1378
+ sourceRoot: requireSourceRoot(p),
1295
1379
  artifactsDir: p.artifactsDir,
1296
1380
  preferredExecutor: "charter_fidelity_executor",
1297
1381
  charterFidelitySubmissionPath: path,
@@ -1321,6 +1405,7 @@ export async function handleCharterClarificationBranch(params, bundle, state, tx
1321
1405
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.charter_clarification],
1322
1406
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1323
1407
  root: p.root,
1408
+ sourceRoot: requireSourceRoot(p),
1324
1409
  artifactsDir: p.artifactsDir,
1325
1410
  preferredExecutor: "charter_clarification_executor",
1326
1411
  clarificationAnswersPath: path,
@@ -1358,6 +1443,7 @@ export async function handleSystemicChallengeBranch(params, bundle, state, tx) {
1358
1443
  schema: systemicChallengeSchema(repoPathUniverse(bundle.repo_manifest)),
1359
1444
  apply: (_value, path, p, foldBundle, staged) => runAuditStepUnlocked({
1360
1445
  root: p.root,
1446
+ sourceRoot: requireSourceRoot(p),
1361
1447
  artifactsDir: p.artifactsDir,
1362
1448
  preferredExecutor: "systemic_challenge_executor",
1363
1449
  systemicChallengePath: path,
@@ -1400,9 +1486,10 @@ export async function executeAndRecord(params, analyzers, decision, index, lastS
1400
1486
  status: "running",
1401
1487
  started_at: startedAt,
1402
1488
  });
1403
- const indexes = await manifestIndexes(params.root, bundle, ctx.manifestIndexCache);
1489
+ const indexes = await manifestIndexes(requireSourceRoot(params), bundle, ctx.manifestIndexCache);
1404
1490
  const result = await runSingleAdvanceStep(bundle, {
1405
- root: params.root,
1491
+ root: requireSourceRoot(params),
1492
+ repositoryRoot: params.root,
1406
1493
  artifactsDir: params.artifactsDir,
1407
1494
  analyzers,
1408
1495
  graphLlmEdgeReasoning: params.graphLlmEdgeReasoning,
@@ -1535,8 +1622,8 @@ export async function checkNoProgressBeforeDispatch(ctx) {
1535
1622
  timestamp: new Date().toISOString(),
1536
1623
  });
1537
1624
  // A terminal INTENT, not the built terminal: `buildTerminalStep` can
1538
- // PROMOTE (which deletes artifactsDir), so it must run after the fold's
1539
- // commit and outside its hold. The marker above is the in-fold record.
1625
+ // PROMOTE (which writes outside the dir and removes a complete run's
1626
+ // snapshot), so it must run after the fold's commit and outside its hold. The marker above is the in-fold record.
1540
1627
  return {
1541
1628
  kind: "terminal_intent",
1542
1629
  bundle: ctx.bundle,
@@ -1987,15 +2074,20 @@ async function ingestAvailableInspectionResults(bundle, ctx) {
1987
2074
  // so the accept decision sees the same disk truth `runAuditStep`'s batch gate
1988
2075
  // validates against; the audit-task manifest comes from the same bundle.
1989
2076
  const lineIndexForIngest = bundle.repo_manifest
1990
- ? await buildLineIndex(ctx.params.root, bundle.repo_manifest)
2077
+ ? await buildLineIndex(requireSourceRoot(ctx.params), bundle.repo_manifest)
1991
2078
  : undefined;
2079
+ // The set replayed below. The ingest validates those entries again against
2080
+ // this same tree, so the batch gate cannot refuse what it is handed.
2081
+ const pendingIds = new Set(buildPendingAuditTasks(bundle).map((task) => task.task_id));
1992
2082
  try {
1993
2083
  const ingested = await ingestAuditHostResults({
1994
2084
  root: ctx.params.root,
2085
+ sourceRoot: requireSourceRoot(ctx.params),
1995
2086
  artifactsDir: ctx.params.artifactsDir,
1996
2087
  runId: currentRun.run_id,
1997
2088
  auditTasks: bundle.audit_tasks ?? [],
1998
2089
  lineIndex: lineIndexForIngest,
2090
+ pendingTaskIds: pendingIds,
1999
2091
  });
2000
2092
  acceptedResults = ingested.accepted_results;
2001
2093
  ingestIssues = ingested.issues;
@@ -2032,13 +2124,13 @@ async function ingestAvailableInspectionResults(bundle, ctx) {
2032
2124
  // Even a refused-only arrival must be visible on the next host step.
2033
2125
  mergeFoldAdvisoriesInto(ctx.foldAdvisoriesRef.value, { issues: ingestIssues, validationWarnings });
2034
2126
  await writePendingAdvisories(ctx.params.artifactsDir, ctx.foldAdvisoriesRef.value);
2035
- const pendingIds = new Set(buildPendingAuditTasks(bundle).map((task) => task.task_id));
2036
2127
  const pendingAccepted = acceptedResults.filter((result) => pendingIds.has(result.task_id));
2037
2128
  if (pendingAccepted.length > 0) {
2038
2129
  // Forced, lock-free, against the CARRIED bundle: the fold owns the one
2039
2130
  // hold and the one persist.
2040
2131
  const ingested = await runAuditStepUnlocked({
2041
2132
  root: ctx.params.root,
2133
+ sourceRoot: requireSourceRoot(ctx.params),
2042
2134
  artifactsDir: ctx.params.artifactsDir,
2043
2135
  preferredExecutor: "result_ingestion_executor",
2044
2136
  auditResultsData: [...pendingAccepted],
@@ -2065,6 +2157,7 @@ async function runHostDelegationObligation(bundle, ctx) {
2065
2157
  // other half).
2066
2158
  const review = await ensureSemanticReviewRunUnlocked({
2067
2159
  root: ctx.params.root,
2160
+ sourceRoot: requireSourceRoot(ctx.params),
2068
2161
  artifactsDir: ctx.params.artifactsDir,
2069
2162
  bundle,
2070
2163
  state,
@@ -2115,7 +2208,12 @@ async function withFoldAdvisories(step, ctx) {
2115
2208
  if (step.kind !== "semantic_review") {
2116
2209
  return {
2117
2210
  ...step,
2118
- advisoryNotice: renderCarriedAdvisoryLines(carried),
2211
+ // An architecture step that carries a ready-inspection run names that
2212
+ // run's workload in its own task, above the carried report (the
2213
+ // `withReadyInspection` section); the pending items are in it.
2214
+ advisoryNotice: renderCarriedAdvisoryLines(carried, step.inspectionRun !== undefined && step.kind !== "blocked"
2215
+ ? "named_above"
2216
+ : "next_call"),
2119
2217
  };
2120
2218
  }
2121
2219
  return {
@@ -2138,14 +2236,15 @@ async function withFoldAdvisories(step, ctx) {
2138
2236
  * the bullet format and the headings, and the copy had already gone stale
2139
2237
  * against the section it claimed to match.
2140
2238
  *
2141
- * The workload is `next_call` here: this report rides a step of another kind,
2142
- * so no workload is published below it.
2239
+ * The report rides a step of another kind and follows its whole task, so the
2240
+ * workload is `named_above` when that task names a ready-inspection workload,
2241
+ * and `next_call` otherwise.
2143
2242
  */
2144
- function renderCarriedAdvisoryLines(carried) {
2243
+ function renderCarriedAdvisoryLines(carried, workload) {
2145
2244
  return renderIngestReportLines({
2146
2245
  issues: carried.ingestIssues,
2147
2246
  remedy: auditIngestRemedy,
2148
- workload: "next_call",
2247
+ workload,
2149
2248
  advisories: carried.validationWarnings,
2150
2249
  });
2151
2250
  }
@@ -2219,8 +2318,8 @@ function foldHeartbeatRecord(obligation, durationMs) {
2219
2318
  * Drive the deterministic fold for one `next-step` call.
2220
2319
  *
2221
2320
  * Structure mirrors remediate-code's `decideNextStepLoop` (the proven engine
2222
- * consumer): a PREAMBLE (the `index===0` file-integrity re-intake, the analog of
2223
- * remediate's `forceReplan`) then the shared `advance` running audit's `PRIORITY`
2321
+ * consumer): source-integrity refresh under the hold, then the shared
2322
+ * `advance` running audit's `PRIORITY`
2224
2323
  * obligations. Each deterministic executor `transition`s (folding the whole chain
2225
2324
  * into one host round-trip); host-delegation / dispatch / terminal obligations
2226
2325
  * `emit` the host-actionable step.
@@ -2241,7 +2340,10 @@ export async function runDeterministicForNextStep(params) {
2241
2340
  // engine directly rather than through `advanceAudit`).
2242
2341
  const heartbeat = startAdvanceHeartbeat();
2243
2342
  try {
2244
- return await runDeterministicFold(params, heartbeat);
2343
+ const result = await runDeterministicFold(params, heartbeat);
2344
+ // The fold resolved the run's snapshot under its hold; the emission renders
2345
+ // every packet and workload from the same tree.
2346
+ return { ...result, sourceRoot: requireSourceRoot(params) };
2245
2347
  }
2246
2348
  finally {
2247
2349
  heartbeat.stop();
@@ -2261,38 +2363,6 @@ async function runDeterministicFold(params, heartbeat) {
2261
2363
  const analyzersRef = {
2262
2364
  value: params.analyzers,
2263
2365
  };
2264
- // PREAMBLE — file-integrity re-intake (runs once, like remediate's
2265
- // forceReplan). When pending audit-task files have changed/vanished since the
2266
- // manifest was built, re-run intake so planning re-grounds. advanceAudit does
2267
- // not persist (only runAuditStep does), so this is the same diagnostic-then-
2268
- // reload the hand loop performed on its first iteration: the warning fires and
2269
- // the fold below starts from the freshly-loaded disk bundle.
2270
- {
2271
- const bundle = await loadArtifactBundle(params.artifactsDir);
2272
- if (bundle.audit_state?.status !== "complete" && bundle.repo_manifest) {
2273
- const pendingTasks = buildPendingAuditTasks(bundle);
2274
- const taskFiles = new Set();
2275
- for (const task of pendingTasks) {
2276
- for (const fp of Object.keys(task.file_line_counts ?? {}))
2277
- taskFiles.add(fp);
2278
- }
2279
- if (taskFiles.size > 0) {
2280
- const integrity = await checkFileIntegrity(params.root, bundle.repo_manifest, [...taskFiles]);
2281
- if (!integrity.is_clean) {
2282
- // Route this diagnostic OFF stdout: cmdNextStep emits the step
2283
- // contract as the sole stdout payload via console.log(JSON.stringify),
2284
- // so a console.log here would corrupt the JSON-on-stdout contract.
2285
- process.stderr.write(`[audit-code] nextStep: integrity check — ${integrity.changed_files.length} changed, ` +
2286
- `${integrity.missing_files.length} missing, ${integrity.io_errors.length} io-error(s); re-running intake.\n`);
2287
- await advanceAudit(bundle, {
2288
- root: params.root,
2289
- artifactsDir: params.artifactsDir,
2290
- preferredExecutor: "intake_executor",
2291
- });
2292
- }
2293
- }
2294
- }
2295
- }
2296
2366
  const ctx = {
2297
2367
  params,
2298
2368
  analyzersRef,
@@ -2326,8 +2396,18 @@ async function runDeterministicFold(params, heartbeat) {
2326
2396
  const holdStartMs = Date.now();
2327
2397
  let chargedExecutions;
2328
2398
  let ingestionExecutions = 0;
2399
+ let intakeExecutions = 0;
2329
2400
  await recoverStagedSubmissions(params.artifactsDir);
2330
2401
  const previousConsent = await readRunConsentUnlocked(params.root, params.artifactsDir);
2402
+ // The run's frozen snapshot, under the same hold as the consent record it
2403
+ // shares a lifetime with: created at run start, re-checked out on resume.
2404
+ // Every content read of this fold uses it (`requireSourceRoot`); the
2405
+ // complete-run rule lives in `ensureRunSourceRoot`, shared with every
2406
+ // standalone step command.
2407
+ params.sourceRoot = await ensureRunSourceRoot(params.root, params.artifactsDir);
2408
+ if (params.since !== undefined) {
2409
+ params.since = await resolveRunSince(params.root, params.artifactsDir, params.since);
2410
+ }
2331
2411
  const consent = params.autoFix?.enabled === undefined && !params.autoFix?.dryRun
2332
2412
  ? previousConsent
2333
2413
  : await updateRunConsentUnlocked(params.root, params.artifactsDir, {}, params.autoFix?.enabled, params.autoFix?.dryRun);
@@ -2348,6 +2428,26 @@ async function runDeterministicFold(params, heartbeat) {
2348
2428
  }
2349
2429
  ctx.currentBundleRef.value = startBundle;
2350
2430
  try {
2431
+ // Observe source integrity against the fresh carried authority, under
2432
+ // the same hold and before any old host submission can be ingested.
2433
+ if (startBundle.audit_state?.status !== "complete" && startBundle.repo_manifest) {
2434
+ const taskFiles = [...new Set(buildPendingAuditTasks(startBundle).flatMap((task) => task.file_paths))];
2435
+ if (taskFiles.length > 0) {
2436
+ const integrity = await checkFileIntegrity(requireSourceRoot(params), startBundle.repo_manifest, taskFiles);
2437
+ if (!integrity.is_clean) {
2438
+ process.stderr.write(`[audit-code] nextStep: integrity check - ${integrity.changed_files.length} changed, ` +
2439
+ `${integrity.missing_files.length} missing, ${integrity.io_errors.length} io-error(s); re-running intake.\n`);
2440
+ intakeExecutions = 1;
2441
+ const refreshed = await runSingleAdvanceStep(startBundle, {
2442
+ root: requireSourceRoot(params), repositoryRoot: params.root, artifactsDir: params.artifactsDir,
2443
+ preferredExecutor: "intake_executor", scopeIndexMemo: params.scopeIndexMemo,
2444
+ runLogger: foldLogger, heartbeat,
2445
+ });
2446
+ startBundle = refreshed.updated_bundle;
2447
+ ctx.currentBundleRef.value = startBundle;
2448
+ }
2449
+ }
2450
+ }
2351
2451
  if (startBundle.audit_tasks && startBundle.audit_state?.status !== "complete" &&
2352
2452
  deriveAuditState(startBundle, { emitStaleness: false }).obligations.find((obligation) => obligation.id === "planning_artifacts")?.state === "satisfied") {
2353
2453
  const beforeIngest = startBundle;
@@ -2360,16 +2460,17 @@ async function runDeterministicFold(params, heartbeat) {
2360
2460
  obligations: trackFoldBundle(buildAuditObligations()),
2361
2461
  }, startBundle, ctx, {
2362
2462
  maxTransitions: engineMaxTransitions(),
2363
- maxExecutions: MAX_DRAIN_STEPS - ingestionExecutions,
2463
+ maxExecutions: MAX_DRAIN_STEPS - ingestionExecutions - intakeExecutions,
2364
2464
  });
2365
- chargedExecutions = engineOutcome.executions + ingestionExecutions;
2465
+ chargedExecutions = engineOutcome.executions + ingestionExecutions + intakeExecutions;
2366
2466
  if (engineOutcome.step && engineOutcome.step.kind !== "terminal_intent" && ARCHITECTURE_WORK_STEPS.has(engineOutcome.step.kind) &&
2367
2467
  buildPendingAuditTasks(engineOutcome.state).length > 0) {
2368
2468
  const inspection = await ensureSemanticReviewRunUnlocked({
2369
- root: params.root, artifactsDir: params.artifactsDir,
2469
+ root: params.root, sourceRoot: requireSourceRoot(params), artifactsDir: params.artifactsDir,
2370
2470
  bundle: engineOutcome.state,
2371
2471
  state: deriveAuditState(engineOutcome.state, { emitStaleness: false }),
2372
2472
  obligationId: "audit_tasks_completed",
2473
+ emittedStepKind: engineOutcome.step.kind,
2373
2474
  });
2374
2475
  engineOutcome.step = { ...engineOutcome.step, inspectionRun: inspection.activeReviewRun };
2375
2476
  }
@@ -2418,14 +2519,14 @@ async function runDeterministicFold(params, heartbeat) {
2418
2519
  // obligation that produces most of it, is what makes "stated on exactly one
2419
2520
  // emitted step, WHICHEVER step that is" true for every kind. A terminal
2420
2521
  // intent is deliberately excluded: it is not a step, and the terminal
2421
- // conversion below promotes and deletes the artifacts dir — the carry has
2422
- // nowhere left to be stated, and the run is over.
2522
+ // conversion below promotes — the carry has nowhere left to be stated, and
2523
+ // the run is over.
2423
2524
  if (outcome.step && outcome.step.kind !== "terminal_intent") {
2424
2525
  return await withFoldAdvisories(outcome.step, ctx);
2425
2526
  }
2426
2527
  if (outcome.step) {
2427
2528
  // Guard terminals convert POST-commit, POST-hold: buildTerminalStep can
2428
- // promote, and promotion deletes artifactsDir.
2529
+ // promote, which writes outside the dir and removes a complete run's snapshot.
2429
2530
  return await buildTerminalStep(params, outcome.step.bundle, outcome.step.state, outcome.step.reason);
2430
2531
  }
2431
2532
  if (outcome.stopped === "budget") {