audit-tools 0.55.5 → 0.55.7

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 (266) hide show
  1. package/dist/audit/cli/auditStep.d.ts +15 -1
  2. package/dist/audit/cli/auditStep.d.ts.map +1 -1
  3. package/dist/audit/cli/auditStep.js +24 -11
  4. package/dist/audit/cli/auditStep.js.map +1 -1
  5. package/dist/audit/cli/cleanup.d.ts.map +1 -1
  6. package/dist/audit/cli/cleanup.js +26 -2
  7. package/dist/audit/cli/cleanup.js.map +1 -1
  8. package/dist/audit/cli/conceptualDispatch.d.ts +2 -0
  9. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  10. package/dist/audit/cli/conceptualDispatch.js +29 -8
  11. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  12. package/dist/audit/cli/dispatch/hostHandoff.d.ts +37 -3
  13. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  14. package/dist/audit/cli/dispatch/hostHandoff.js +185 -16
  15. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  16. package/dist/audit/cli/fanoutLanes.d.ts +30 -0
  17. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
  18. package/dist/audit/cli/fanoutLanes.js +76 -8
  19. package/dist/audit/cli/fanoutLanes.js.map +1 -1
  20. package/dist/audit/cli/lineIndex.d.ts.map +1 -1
  21. package/dist/audit/cli/lineIndex.js +19 -41
  22. package/dist/audit/cli/lineIndex.js.map +1 -1
  23. package/dist/audit/cli/nextStepCommand.d.ts +3 -0
  24. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  25. package/dist/audit/cli/nextStepCommand.js +109 -68
  26. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  27. package/dist/audit/cli/nextStepHelpers.d.ts +55 -20
  28. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  29. package/dist/audit/cli/nextStepHelpers.js +215 -196
  30. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  31. package/dist/audit/cli/reviewRun.d.ts +4 -0
  32. package/dist/audit/cli/reviewRun.d.ts.map +1 -1
  33. package/dist/audit/cli/reviewRun.js +1 -1
  34. package/dist/audit/cli/reviewRun.js.map +1 -1
  35. package/dist/audit/cli/semanticReviewStep.d.ts +2 -0
  36. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  37. package/dist/audit/cli/semanticReviewStep.js +5 -50
  38. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  39. package/dist/audit/cli/validateResultsCommand.d.ts.map +1 -1
  40. package/dist/audit/cli/validateResultsCommand.js +3 -1
  41. package/dist/audit/cli/validateResultsCommand.js.map +1 -1
  42. package/dist/audit/extractors/disposition.d.ts.map +1 -1
  43. package/dist/audit/extractors/disposition.js +14 -38
  44. package/dist/audit/extractors/disposition.js.map +1 -1
  45. package/dist/audit/extractors/fsIntake.d.ts +13 -0
  46. package/dist/audit/extractors/fsIntake.d.ts.map +1 -1
  47. package/dist/audit/extractors/fsIntake.js +11 -1
  48. package/dist/audit/extractors/fsIntake.js.map +1 -1
  49. package/dist/audit/extractors/readFileText.d.ts.map +1 -1
  50. package/dist/audit/extractors/readFileText.js +34 -5
  51. package/dist/audit/extractors/readFileText.js.map +1 -1
  52. package/dist/audit/io/artifacts.d.ts +35 -9
  53. package/dist/audit/io/artifacts.d.ts.map +1 -1
  54. package/dist/audit/io/artifacts.js +84 -67
  55. package/dist/audit/io/artifacts.js.map +1 -1
  56. package/dist/audit/io/rollover.d.ts +18 -0
  57. package/dist/audit/io/rollover.d.ts.map +1 -0
  58. package/dist/audit/io/rollover.js +152 -0
  59. package/dist/audit/io/rollover.js.map +1 -0
  60. package/dist/audit/io/runSnapshot.d.ts +149 -0
  61. package/dist/audit/io/runSnapshot.d.ts.map +1 -0
  62. package/dist/audit/io/runSnapshot.js +710 -0
  63. package/dist/audit/io/runSnapshot.js.map +1 -0
  64. package/dist/audit/orchestrator/acquisitionExecutor.d.ts +5 -2
  65. package/dist/audit/orchestrator/acquisitionExecutor.d.ts.map +1 -1
  66. package/dist/audit/orchestrator/acquisitionExecutor.js +28 -22
  67. package/dist/audit/orchestrator/acquisitionExecutor.js.map +1 -1
  68. package/dist/audit/orchestrator/advanceTypes.d.ts +11 -0
  69. package/dist/audit/orchestrator/advanceTypes.d.ts.map +1 -1
  70. package/dist/audit/orchestrator/autoFixExecutor.d.ts +9 -0
  71. package/dist/audit/orchestrator/autoFixExecutor.d.ts.map +1 -1
  72. package/dist/audit/orchestrator/autoFixExecutor.js +22 -2
  73. package/dist/audit/orchestrator/autoFixExecutor.js.map +1 -1
  74. package/dist/audit/orchestrator/charterExtractionExecutor.d.ts.map +1 -1
  75. package/dist/audit/orchestrator/charterExtractionExecutor.js +18 -3
  76. package/dist/audit/orchestrator/charterExtractionExecutor.js.map +1 -1
  77. package/dist/audit/orchestrator/charterPackets.d.ts +11 -1
  78. package/dist/audit/orchestrator/charterPackets.d.ts.map +1 -1
  79. package/dist/audit/orchestrator/charterPackets.js +13 -0
  80. package/dist/audit/orchestrator/charterPackets.js.map +1 -1
  81. package/dist/audit/orchestrator/designReviewPrompt.d.ts +9 -0
  82. package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -1
  83. package/dist/audit/orchestrator/designReviewPrompt.js +69 -31
  84. package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -1
  85. package/dist/audit/orchestrator/designReviewSnapshot.d.ts +1 -0
  86. package/dist/audit/orchestrator/designReviewSnapshot.d.ts.map +1 -1
  87. package/dist/audit/orchestrator/designReviewSnapshot.js +2 -1
  88. package/dist/audit/orchestrator/designReviewSnapshot.js.map +1 -1
  89. package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
  90. package/dist/audit/orchestrator/executorRunners.js +13 -4
  91. package/dist/audit/orchestrator/executorRunners.js.map +1 -1
  92. package/dist/audit/orchestrator/intakeExecutors.d.ts +8 -1
  93. package/dist/audit/orchestrator/intakeExecutors.d.ts.map +1 -1
  94. package/dist/audit/orchestrator/intakeExecutors.js +13 -4
  95. package/dist/audit/orchestrator/intakeExecutors.js.map +1 -1
  96. package/dist/audit/orchestrator/obligationPolicy.d.ts.map +1 -1
  97. package/dist/audit/orchestrator/obligationPolicy.js +4 -1
  98. package/dist/audit/orchestrator/obligationPolicy.js.map +1 -1
  99. package/dist/audit/orchestrator/planningExecutors.d.ts +1 -1
  100. package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
  101. package/dist/audit/orchestrator/planningExecutors.js +40 -6
  102. package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
  103. package/dist/audit/orchestrator/reviewPacketSizing.d.ts +4 -4
  104. package/dist/audit/orchestrator/reviewPacketSizing.d.ts.map +1 -1
  105. package/dist/audit/orchestrator/reviewPacketSizing.js +5 -5
  106. package/dist/audit/orchestrator/reviewPacketSizing.js.map +1 -1
  107. package/dist/audit/orchestrator/reviewPackets.d.ts.map +1 -1
  108. package/dist/audit/orchestrator/reviewPackets.js +10 -5
  109. package/dist/audit/orchestrator/reviewPackets.js.map +1 -1
  110. package/dist/audit/orchestrator/runtimeCommand.d.ts +9 -2
  111. package/dist/audit/orchestrator/runtimeCommand.d.ts.map +1 -1
  112. package/dist/audit/orchestrator/runtimeCommand.js +14 -22
  113. package/dist/audit/orchestrator/runtimeCommand.js.map +1 -1
  114. package/dist/audit/orchestrator/scopeIndexBaseline.d.ts.map +1 -1
  115. package/dist/audit/orchestrator/scopeIndexBaseline.js +7 -29
  116. package/dist/audit/orchestrator/scopeIndexBaseline.js.map +1 -1
  117. package/dist/audit/orchestrator/selectiveDeepening/conflict.d.ts +6 -2
  118. package/dist/audit/orchestrator/selectiveDeepening/conflict.d.ts.map +1 -1
  119. package/dist/audit/orchestrator/selectiveDeepening/conflict.js +45 -4
  120. package/dist/audit/orchestrator/selectiveDeepening/conflict.js.map +1 -1
  121. package/dist/audit/orchestrator/selectiveDeepening/index.d.ts.map +1 -1
  122. package/dist/audit/orchestrator/selectiveDeepening/index.js +4 -4
  123. package/dist/audit/orchestrator/selectiveDeepening/index.js.map +1 -1
  124. package/dist/audit/orchestrator/systemicChallengeExecutor.d.ts.map +1 -1
  125. package/dist/audit/orchestrator/systemicChallengeExecutor.js +4 -1
  126. package/dist/audit/orchestrator/systemicChallengeExecutor.js.map +1 -1
  127. package/dist/audit/orchestrator/taskBuilder.d.ts +20 -0
  128. package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -1
  129. package/dist/audit/orchestrator/taskBuilder.js +80 -18
  130. package/dist/audit/orchestrator/taskBuilder.js.map +1 -1
  131. package/dist/audit/systemic/reviewFileMap.d.ts +72 -21
  132. package/dist/audit/systemic/reviewFileMap.d.ts.map +1 -1
  133. package/dist/audit/systemic/reviewFileMap.js +96 -45
  134. package/dist/audit/systemic/reviewFileMap.js.map +1 -1
  135. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts +7 -0
  136. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts.map +1 -1
  137. package/dist/audit/systemic/secondOrderAdversaryPrompt.js +39 -8
  138. package/dist/audit/systemic/secondOrderAdversaryPrompt.js.map +1 -1
  139. package/dist/remediate/phases/close.d.ts.map +1 -1
  140. package/dist/remediate/phases/close.js +29 -11
  141. package/dist/remediate/phases/close.js.map +1 -1
  142. package/dist/remediate/phases/closeAcceptance.d.ts.map +1 -1
  143. package/dist/remediate/phases/closeAcceptance.js +2 -0
  144. package/dist/remediate/phases/closeAcceptance.js.map +1 -1
  145. package/dist/remediate/phases/closeVerifyAnalyzerLeads.d.ts +2 -1
  146. package/dist/remediate/phases/closeVerifyAnalyzerLeads.d.ts.map +1 -1
  147. package/dist/remediate/phases/closeVerifyAnalyzerLeads.js +10 -9
  148. package/dist/remediate/phases/closeVerifyAnalyzerLeads.js.map +1 -1
  149. package/dist/remediate/phases/triage.d.ts +2 -1
  150. package/dist/remediate/phases/triage.d.ts.map +1 -1
  151. package/dist/remediate/phases/triage.js +46 -25
  152. package/dist/remediate/phases/triage.js.map +1 -1
  153. package/dist/remediate/phases/triageConformance.d.ts +14 -0
  154. package/dist/remediate/phases/triageConformance.d.ts.map +1 -0
  155. package/dist/remediate/phases/triageConformance.js +189 -0
  156. package/dist/remediate/phases/triageConformance.js.map +1 -0
  157. package/dist/remediate/state/decisionConsumption.d.ts +110 -0
  158. package/dist/remediate/state/decisionConsumption.d.ts.map +1 -0
  159. package/dist/remediate/state/decisionConsumption.js +122 -0
  160. package/dist/remediate/state/decisionConsumption.js.map +1 -0
  161. package/dist/remediate/state/dirtyBaseline.d.ts +10 -0
  162. package/dist/remediate/state/dirtyBaseline.d.ts.map +1 -0
  163. package/dist/remediate/state/dirtyBaseline.js +18 -0
  164. package/dist/remediate/state/dirtyBaseline.js.map +1 -0
  165. package/dist/remediate/state/store.d.ts +8 -4
  166. package/dist/remediate/state/store.d.ts.map +1 -1
  167. package/dist/remediate/state/store.js +24 -0
  168. package/dist/remediate/state/store.js.map +1 -1
  169. package/dist/remediate/steps/dispatch/contractConformanceReview.d.ts +9 -0
  170. package/dist/remediate/steps/dispatch/contractConformanceReview.d.ts.map +1 -1
  171. package/dist/remediate/steps/dispatch/contractConformanceReview.js +32 -14
  172. package/dist/remediate/steps/dispatch/contractConformanceReview.js.map +1 -1
  173. package/dist/remediate/steps/dispatch/hostCorroboration.d.ts.map +1 -1
  174. package/dist/remediate/steps/dispatch/hostCorroboration.js +34 -82
  175. package/dist/remediate/steps/dispatch/hostCorroboration.js.map +1 -1
  176. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  177. package/dist/remediate/steps/dispatch/hostHandoff.js +10 -1
  178. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  179. package/dist/remediate/steps/finalGate.d.ts.map +1 -1
  180. package/dist/remediate/steps/finalGate.js +11 -5
  181. package/dist/remediate/steps/finalGate.js.map +1 -1
  182. package/dist/remediate/steps/gateCommands.d.ts +1 -0
  183. package/dist/remediate/steps/gateCommands.d.ts.map +1 -1
  184. package/dist/remediate/steps/gateCommands.js +13 -63
  185. package/dist/remediate/steps/gateCommands.js.map +1 -1
  186. package/dist/remediate/steps/nextStep.d.ts +7 -0
  187. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  188. package/dist/remediate/steps/nextStep.js +93 -33
  189. package/dist/remediate/steps/nextStep.js.map +1 -1
  190. package/dist/shared/analyzers/acquisitionEngine.d.ts +12 -5
  191. package/dist/shared/analyzers/acquisitionEngine.d.ts.map +1 -1
  192. package/dist/shared/analyzers/acquisitionEngine.js +86 -38
  193. package/dist/shared/analyzers/acquisitionEngine.js.map +1 -1
  194. package/dist/shared/analyzers/binaryAcquisition.d.ts +17 -41
  195. package/dist/shared/analyzers/binaryAcquisition.d.ts.map +1 -1
  196. package/dist/shared/analyzers/binaryAcquisition.js +260 -227
  197. package/dist/shared/analyzers/binaryAcquisition.js.map +1 -1
  198. package/dist/shared/analyzers/binaryFetcher.d.ts +4 -0
  199. package/dist/shared/analyzers/binaryFetcher.d.ts.map +1 -0
  200. package/dist/shared/analyzers/binaryFetcher.js +79 -0
  201. package/dist/shared/analyzers/binaryFetcher.js.map +1 -0
  202. package/dist/shared/analyzers/binaryVersions.d.ts +5 -0
  203. package/dist/shared/analyzers/binaryVersions.d.ts.map +1 -0
  204. package/dist/shared/analyzers/binaryVersions.js +31 -0
  205. package/dist/shared/analyzers/binaryVersions.js.map +1 -0
  206. package/dist/shared/analyzers/candidates.d.ts +3 -3
  207. package/dist/shared/analyzers/candidates.d.ts.map +1 -1
  208. package/dist/shared/analyzers/candidates.js +35 -12
  209. package/dist/shared/analyzers/candidates.js.map +1 -1
  210. package/dist/shared/contentKey.d.ts +3 -2
  211. package/dist/shared/contentKey.d.ts.map +1 -1
  212. package/dist/shared/contentKey.js +3 -2
  213. package/dist/shared/contentKey.js.map +1 -1
  214. package/dist/shared/decompose/charterExtraction.d.ts +189 -1
  215. package/dist/shared/decompose/charterExtraction.d.ts.map +1 -1
  216. package/dist/shared/decompose/charterExtraction.js +17 -2
  217. package/dist/shared/decompose/charterExtraction.js.map +1 -1
  218. package/dist/shared/git.d.ts +58 -2
  219. package/dist/shared/git.d.ts.map +1 -1
  220. package/dist/shared/git.js +214 -56
  221. package/dist/shared/git.js.map +1 -1
  222. package/dist/shared/gitTrackedPaths.d.ts +39 -0
  223. package/dist/shared/gitTrackedPaths.d.ts.map +1 -0
  224. package/dist/shared/gitTrackedPaths.js +29 -0
  225. package/dist/shared/gitTrackedPaths.js.map +1 -0
  226. package/dist/shared/index.d.ts +4 -2
  227. package/dist/shared/index.d.ts.map +1 -1
  228. package/dist/shared/index.js +4 -2
  229. package/dist/shared/index.js.map +1 -1
  230. package/dist/shared/io/sourcePath.d.ts +8 -0
  231. package/dist/shared/io/sourcePath.d.ts.map +1 -0
  232. package/dist/shared/io/sourcePath.js +38 -0
  233. package/dist/shared/io/sourcePath.js.map +1 -0
  234. package/dist/shared/loopCorePaths.d.ts.map +1 -1
  235. package/dist/shared/loopCorePaths.js +2 -0
  236. package/dist/shared/loopCorePaths.js.map +1 -1
  237. package/dist/shared/prompts.d.ts +2 -0
  238. package/dist/shared/prompts.d.ts.map +1 -1
  239. package/dist/shared/prompts.js +8 -2
  240. package/dist/shared/prompts.js.map +1 -1
  241. package/dist/shared/submission/ingestReport.d.ts.map +1 -1
  242. package/dist/shared/submission/ingestReport.js +19 -1
  243. package/dist/shared/submission/ingestReport.js.map +1 -1
  244. package/dist/shared/tooling/exec.d.ts +1 -0
  245. package/dist/shared/tooling/exec.d.ts.map +1 -1
  246. package/dist/shared/tooling/exec.js +20 -4
  247. package/dist/shared/tooling/exec.js.map +1 -1
  248. package/dist/shared/tooling/resolveExecutable.d.ts +10 -0
  249. package/dist/shared/tooling/resolveExecutable.d.ts.map +1 -0
  250. package/dist/shared/tooling/resolveExecutable.js +46 -0
  251. package/dist/shared/tooling/resolveExecutable.js.map +1 -0
  252. package/dist/shared/types/charter.d.ts +9 -0
  253. package/dist/shared/types/charter.d.ts.map +1 -1
  254. package/dist/shared/types/charter.js +7 -0
  255. package/dist/shared/types/charter.js.map +1 -1
  256. package/dist/shared/validation/citationGrounding.d.ts +1 -1
  257. package/dist/shared/validation/citationGrounding.d.ts.map +1 -1
  258. package/dist/shared/validation/citationGrounding.js +24 -11
  259. package/dist/shared/validation/citationGrounding.js.map +1 -1
  260. package/dist/shared/validation/findingGrounding.d.ts +1 -1
  261. package/dist/shared/validation/findingGrounding.d.ts.map +1 -1
  262. package/dist/shared/validation/findingGrounding.js +11 -23
  263. package/dist/shared/validation/findingGrounding.js.map +1 -1
  264. package/docs/audit-pkg/contracts.md +6 -2
  265. package/docs/audit-pkg/operator-guide.md +13 -4
  266. package/package.json +2 -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,18 +11,20 @@ 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";
25
- import { charterClarificationOmits, charterExtractionOmits, intentEquivalenceOmits, synthesisNarrativeOmits, systemicChallengeOmits, } from "../orchestrator/obligationPolicy.js";
27
+ import { charterClarificationOmits, charterComparisonOmits, charterFidelityOmits, charterExtractionOmits, intentEquivalenceOmits, synthesisNarrativeOmits, systemicChallengeOmits, } from "../orchestrator/obligationPolicy.js";
26
28
  import { computeArtifactMetadata, computeArtifactStateSignature } from "../orchestrator/artifactMetadata.js";
27
29
  import { decideNextStep, PRIORITY, } from "../orchestrator/nextStep.js";
28
30
  import { isHostDelegationExecutor } from "../orchestrator/executors.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,
@@ -1019,12 +1057,11 @@ export async function handleDesignReviewBranch(params, bundle, state, tx) {
1019
1057
  }
1020
1058
  /**
1021
1059
  * Drive one "poll the lane → apply+continue, else omit-or-return" gate — the
1022
- * shape common to synthesis_narrative, charter_extraction,
1023
- * charter_clarification, and systemic_challenge. See the section comment
1024
- * above for the two gates that deviate and are not run through this engine.
1060
+ * single-lane lifecycle. Charter extraction, graph enrichment, and design
1061
+ * review retain their custom inner ordering and consumption policies.
1025
1062
  */
1026
1063
  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));
1064
+ const incoming = await tryConsumeSubmission(params.artifactsDir, descriptor.lane, tx, auditLaneReviewRequirement(descriptor.lane) === "ordinary" ? undefined : () => currentAuditReviewInputRevision(requireSourceRoot(params), bundle, descriptor.lane));
1028
1065
  if (incoming.status === "malformed") {
1029
1066
  // Not-JSON submission: same quarantine-loudly lifecycle as a mis-shaped one.
1030
1067
  await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, descriptor.lane, incoming.reason);
@@ -1067,6 +1104,7 @@ export async function handleSynthesisNarrativeBranch(params, bundle, state, tx)
1067
1104
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.synthesis_narrative],
1068
1105
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1069
1106
  root: p.root,
1107
+ sourceRoot: requireSourceRoot(p),
1070
1108
  artifactsDir: p.artifactsDir,
1071
1109
  preferredExecutor: "synthesis_narrative_executor",
1072
1110
  narrativeResultsPath: path,
@@ -1078,11 +1116,8 @@ export async function handleSynthesisNarrativeBranch(params, bundle, state, tx)
1078
1116
  }, params, bundle, state, tx);
1079
1117
  }
1080
1118
  /**
1081
- * Handle the `intent_equivalence_executor` polling block (DD-9). Deviates from
1082
- * `runOmittableGate` in ONE way: the consumed verdict is SCHEMA-validated here
1083
- * and a mis-shaped submission is QUARANTINED with a stderr diagnostic (the
1084
- * quarantine-loudly property) instead of being handed to the executor to crash
1085
- * on. Returns:
1119
+ * Handle the `intent_equivalence_executor` polling block (DD-9), using the
1120
+ * common consume-before-omit lifecycle and schema quarantine. Returns:
1086
1121
  * - `continue` → a valid verdict was consumed + committed; re-scan.
1087
1122
  * - `run_omit` → a deterministic arm owns the resolution (baseline stamp /
1088
1123
  * gate-version-stale / structured delta) — run the executor, stay drainable.
@@ -1090,32 +1125,20 @@ export async function handleSynthesisNarrativeBranch(params, bundle, state, tx)
1090
1125
  */
1091
1126
  export async function handleIntentEquivalenceBranch(params, bundle, state, tx) {
1092
1127
  const lane = GATE_LANES.intent_equivalence;
1093
- const incoming = await tryConsumeSubmission(params.artifactsDir, lane, tx);
1094
- if (incoming.status === "malformed") {
1095
- await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, lane, incoming.reason);
1096
- // Fall through: no valid submission — re-emit or deterministically resolve.
1097
- }
1098
- else if (incoming.status === "ok") {
1099
- const parsed = LANE_SUBMISSION_SCHEMAS[lane].safeParse(incoming.value);
1100
- if (parsed.success) {
1101
- const applied = await runAuditStepUnlocked({
1102
- root: params.root,
1103
- artifactsDir: params.artifactsDir,
1104
- preferredExecutor: "intent_equivalence_executor",
1105
- intentEquivalenceVerdictPath: incoming.path,
1106
- scopeIndexMemo: params.scopeIndexMemo,
1107
- }, bundle);
1108
- markSubmissionApplied(tx, incoming.path);
1109
- return { action: "continue", bundle: applied.updated_bundle };
1110
- }
1111
- await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, lane, parsed.error);
1112
- // Fall through: no valid submission — re-emit or deterministically resolve.
1113
- }
1114
- // Single-sourced with the plan draw's classifier (obligationPolicy.ts).
1115
- if (intentEquivalenceOmits(bundle)) {
1116
- return { action: "run_omit" };
1117
- }
1118
- return { action: "return", result: { kind: "intent_equivalence", state, bundle } };
1128
+ return runOmittableGate({
1129
+ kind: "intent_equivalence",
1130
+ lane,
1131
+ schema: LANE_SUBMISSION_SCHEMAS[lane],
1132
+ apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1133
+ root: p.root,
1134
+ sourceRoot: requireSourceRoot(p),
1135
+ artifactsDir: p.artifactsDir,
1136
+ preferredExecutor: "intent_equivalence_executor",
1137
+ intentEquivalenceVerdictPath: path,
1138
+ scopeIndexMemo: p.scopeIndexMemo,
1139
+ }, foldBundle),
1140
+ shouldOmit: intentEquivalenceOmits,
1141
+ }, params, bundle, state, tx);
1119
1142
  }
1120
1143
  /**
1121
1144
  * Handle the `critical_flow_fallback_executor` submission-polling block.
@@ -1136,6 +1159,7 @@ export async function handleCriticalFlowFallbackBranch(params, bundle, state, tx
1136
1159
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.critical_flow_fallback],
1137
1160
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1138
1161
  root: p.root,
1162
+ sourceRoot: requireSourceRoot(p),
1139
1163
  artifactsDir: p.artifactsDir,
1140
1164
  preferredExecutor: "critical_flow_fallback_executor",
1141
1165
  criticalFlowFallbackResultsPath: path,
@@ -1157,6 +1181,21 @@ export async function handleCriticalFlowFallbackBranch(params, bundle, state, tx
1157
1181
  * - a `deep`/`deepest` ceiling with no submission yet → `return` the host step
1158
1182
  * that renders the charter-extraction prompt.
1159
1183
  */
1184
+ /**
1185
+ * Materialize one charter kind's evidence packet and its coverage manifest into
1186
+ * the lane assets and return the packet's digest. The emitter calls it for every
1187
+ * kind (each lane reads its packet), and so does the merge (the executor checks
1188
+ * every lane's citations against its kind's manifest — a CARRIED lane's
1189
+ * included — and folds every kind's coverage into the register). Idempotent:
1190
+ * the packet derives from the bundle and the frozen snapshot.
1191
+ */
1192
+ export async function writeCharterLaneAssets(params) {
1193
+ const packetPath = join(laneAssetsDir(params.artifactsDir), charterExtractionPacketFilename(params.kind));
1194
+ const packet = await materializeCharterPacket({ root: params.sourceRoot, bundle: params.bundle, kind: params.kind });
1195
+ await writeTextFile(packetPath, packet.markdown);
1196
+ await writeJsonFile(join(laneAssetsDir(params.artifactsDir), charterExtractionCoverageFilename(params.kind)), buildCharterPacketManifest(params.kind, packet.excerpts, packet.coverage));
1197
+ return { packetPath, packet, digest: hashContent(packet.markdown) };
1198
+ }
1160
1199
  export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1161
1200
  const ceiling = resolveCharterCeiling(bundle.intent_checkpoint);
1162
1201
  // Shallow ceiling (default): omit deterministically, no host turn, no lanes.
@@ -1176,13 +1215,33 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1176
1215
  const kinds = charterExtractionKindsForCeiling(ceiling);
1177
1216
  const universe = new Set((bundle.repo_manifest?.files ?? []).map((file) => file.path));
1178
1217
  const laneValues = new Map();
1218
+ // A kind whose packet did not change since the previous register's lane was
1219
+ // written is CARRIED (the emitter asked no lane for it); every other kind is
1220
+ // authored from a lane submission. The digest is the one each authored lane
1221
+ // records.
1222
+ const carried = new Map();
1223
+ const digests = new Map();
1224
+ for (const kind of kinds) {
1225
+ const { digest } = await writeCharterLaneAssets({
1226
+ sourceRoot: requireSourceRoot(params),
1227
+ artifactsDir: params.artifactsDir,
1228
+ bundle,
1229
+ kind,
1230
+ });
1231
+ digests.set(kind, digest);
1232
+ const reused = carriedCharterLane(bundle, kind, digest);
1233
+ if (reused !== undefined)
1234
+ carried.set(kind, reused);
1235
+ }
1179
1236
  let quarantinedAny = false;
1180
1237
  for (const kind of kinds) {
1238
+ if (carried.has(kind))
1239
+ continue;
1181
1240
  const lane = charterExtractionLane(kind);
1182
1241
  // Staged per lane; an INCOMPLETE set is restored to its bound paths at
1183
1242
  // commit (un-applied), which is exactly the K-of-N resume the design
1184
1243
  // 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));
1244
+ const incoming = await tryConsumeSubmission(params.artifactsDir, lane, tx, () => currentAuditReviewInputRevision(requireSourceRoot(params), bundle, lane));
1186
1245
  if (incoming.status === "absent")
1187
1246
  continue;
1188
1247
  if (incoming.status === "malformed") {
@@ -1199,7 +1258,7 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1199
1258
  await quarantineMisshapedSubmission(params.artifactsDir, incoming.path, lane, parsed.error);
1200
1259
  }
1201
1260
  }
1202
- if (!quarantinedAny && laneValues.size === kinds.length) {
1261
+ if (!quarantinedAny && laneValues.size + carried.size === kinds.length) {
1203
1262
  // Complete + valid: tool-side merge (stable by lane order = canonical kind
1204
1263
  // order), then one executor ingest; unlink lane files only after apply.
1205
1264
  // The post-apply unlink is the standard consumed-submission lifecycle
@@ -1213,10 +1272,11 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1213
1272
  // lane check itself (owner review of prompt 8, 2026-09-17).
1214
1273
  const merged = {
1215
1274
  // `inputs` was checked at the gate; the merged lane carries the DAG only.
1216
- lanes: kinds.map((kind) => {
1275
+ lanes: kinds.filter((kind) => !carried.has(kind)).map((kind) => {
1217
1276
  const { inputs: _declared, ...dag } = laneValues.get(kind).value;
1218
- return { kind, ...dag };
1277
+ return { kind, packet_sha256: digests.get(kind), ...dag };
1219
1278
  }),
1279
+ carried: [...carried.values()],
1220
1280
  };
1221
1281
  // The merged submission is TOOL-written, so it lives with the other lane
1222
1282
  // assets rather than under `submissions/` (which holds only what a host
@@ -1225,6 +1285,7 @@ export async function handleCharterExtractionBranch(params, bundle, state, tx) {
1225
1285
  await writeJsonFile(mergedPath, merged);
1226
1286
  const applied = await runAuditStepUnlocked({
1227
1287
  root: params.root,
1288
+ sourceRoot: requireSourceRoot(params),
1228
1289
  artifactsDir: params.artifactsDir,
1229
1290
  preferredExecutor: "charter_extraction_executor",
1230
1291
  charterSubmissionPath: mergedPath,
@@ -1276,12 +1337,13 @@ export async function handleCharterComparisonBranch(params, bundle, state, tx) {
1276
1337
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.charter_comparison],
1277
1338
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1278
1339
  root: p.root,
1340
+ sourceRoot: requireSourceRoot(p),
1279
1341
  artifactsDir: p.artifactsDir,
1280
1342
  preferredExecutor: "charter_comparison_executor",
1281
1343
  charterComparisonSubmissionPath: path,
1282
1344
  scopeIndexMemo: p.scopeIndexMemo,
1283
1345
  }, foldBundle),
1284
- shouldOmit: (b) => !(b.charter_register?.comparison_pending === true),
1346
+ shouldOmit: charterComparisonOmits,
1285
1347
  }, params, bundle, state, tx);
1286
1348
  }
1287
1349
  /**
@@ -1296,12 +1358,13 @@ export async function handleCharterFidelityBranch(params, bundle, state, tx) {
1296
1358
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.charter_fidelity],
1297
1359
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1298
1360
  root: p.root,
1361
+ sourceRoot: requireSourceRoot(p),
1299
1362
  artifactsDir: p.artifactsDir,
1300
1363
  preferredExecutor: "charter_fidelity_executor",
1301
1364
  charterFidelitySubmissionPath: path,
1302
1365
  scopeIndexMemo: p.scopeIndexMemo,
1303
1366
  }, foldBundle),
1304
- shouldOmit: (b) => !(b.charter_register?.fidelity_pending === true),
1367
+ shouldOmit: charterFidelityOmits,
1305
1368
  }, params, bundle, state, tx);
1306
1369
  }
1307
1370
  /**
@@ -1325,6 +1388,7 @@ export async function handleCharterClarificationBranch(params, bundle, state, tx
1325
1388
  schema: LANE_SUBMISSION_SCHEMAS[GATE_LANES.charter_clarification],
1326
1389
  apply: (_value, path, p, foldBundle) => runAuditStepUnlocked({
1327
1390
  root: p.root,
1391
+ sourceRoot: requireSourceRoot(p),
1328
1392
  artifactsDir: p.artifactsDir,
1329
1393
  preferredExecutor: "charter_clarification_executor",
1330
1394
  clarificationAnswersPath: path,
@@ -1362,6 +1426,7 @@ export async function handleSystemicChallengeBranch(params, bundle, state, tx) {
1362
1426
  schema: systemicChallengeSchema(repoPathUniverse(bundle.repo_manifest)),
1363
1427
  apply: (_value, path, p, foldBundle, staged) => runAuditStepUnlocked({
1364
1428
  root: p.root,
1429
+ sourceRoot: requireSourceRoot(p),
1365
1430
  artifactsDir: p.artifactsDir,
1366
1431
  preferredExecutor: "systemic_challenge_executor",
1367
1432
  systemicChallengePath: path,
@@ -1404,9 +1469,10 @@ export async function executeAndRecord(params, analyzers, decision, index, lastS
1404
1469
  status: "running",
1405
1470
  started_at: startedAt,
1406
1471
  });
1407
- const indexes = await manifestIndexes(params.root, bundle, ctx.manifestIndexCache);
1472
+ const indexes = await manifestIndexes(requireSourceRoot(params), bundle, ctx.manifestIndexCache);
1408
1473
  const result = await runSingleAdvanceStep(bundle, {
1409
- root: params.root,
1474
+ root: requireSourceRoot(params),
1475
+ repositoryRoot: params.root,
1410
1476
  artifactsDir: params.artifactsDir,
1411
1477
  analyzers,
1412
1478
  graphLlmEdgeReasoning: params.graphLlmEdgeReasoning,
@@ -1539,8 +1605,8 @@ export async function checkNoProgressBeforeDispatch(ctx) {
1539
1605
  timestamp: new Date().toISOString(),
1540
1606
  });
1541
1607
  // A terminal INTENT, not the built terminal: `buildTerminalStep` can
1542
- // PROMOTE (which deletes artifactsDir), so it must run after the fold's
1543
- // commit and outside its hold. The marker above is the in-fold record.
1608
+ // PROMOTE (which writes outside the dir and removes a complete run's
1609
+ // snapshot), so it must run after the fold's commit and outside its hold. The marker above is the in-fold record.
1544
1610
  return {
1545
1611
  kind: "terminal_intent",
1546
1612
  bundle: ctx.bundle,
@@ -1764,6 +1830,21 @@ async function runDeterministicExecutor(bundle, ctx) {
1764
1830
  // silently roll back everything the fold has done (persist-once).
1765
1831
  return { kind: "transition", state: result.updated_bundle };
1766
1832
  }
1833
+ /** Adapt only the common outer outcome; handlers retain their lane lifecycle. */
1834
+ function omittableObligation(handler) {
1835
+ return async (bundle, ctx) => {
1836
+ const state = deriveAuditState(bundle, { emitStaleness: false });
1837
+ const branch = await handler(ctx.params, bundle, state, ctx.tx);
1838
+ switch (branch.action) {
1839
+ case "return":
1840
+ return { kind: "emit", step: branch.result, state: bundle };
1841
+ case "continue":
1842
+ return { kind: "transition", state: branch.bundle };
1843
+ case "run_omit":
1844
+ return runDeterministicExecutor(bundle, ctx);
1845
+ }
1846
+ };
1847
+ }
1767
1848
  /**
1768
1849
  * Build the audit obligation definitions in `PRIORITY` order. Each `execute`
1769
1850
  * relocates the corresponding arm of the hand-rolled `for` loop:
@@ -1808,17 +1889,7 @@ export function buildAuditObligations() {
1808
1889
  // confidence bar, apply the host submission against the carried bundle or
1809
1890
  // emit the host step. No autonomous omit — the host is always available to
1810
1891
  // author the enrichment.
1811
- critical_flow_fallback_current: async (bundle, ctx) => {
1812
- const state = deriveAuditState(bundle, { emitStaleness: false });
1813
- const branch = await handleCriticalFlowFallbackBranch(ctx.params, bundle, state, ctx.tx);
1814
- if (branch.action === "return") {
1815
- return { kind: "emit", step: branch.result, state: bundle };
1816
- }
1817
- if (branch.action === "run_omit") {
1818
- return runDeterministicExecutor(bundle, ctx);
1819
- }
1820
- return { kind: "transition", state: branch.bundle };
1821
- },
1892
+ critical_flow_fallback_current: omittableObligation(handleCriticalFlowFallbackBranch),
1822
1893
  // Graph enrichment: poll the analyzer-decision / edge-reasoning lane
1823
1894
  // artifacts first (emit a host step when one is needed), otherwise run the
1824
1895
  // deterministic enrichment executor.
@@ -1848,104 +1919,31 @@ export function buildAuditObligations() {
1848
1919
  // DD-9 intent-equivalence gate: consume a judge verdict (validated +
1849
1920
  // quarantined-loudly), resolve the deterministic arms in-fold, or emit the
1850
1921
  // bounded prose-equivalence judge step.
1851
- intent_equivalence_current: async (bundle, ctx) => {
1852
- const state = deriveAuditState(bundle, { emitStaleness: false });
1853
- const branch = await handleIntentEquivalenceBranch(ctx.params, bundle, state, ctx.tx);
1854
- if (branch.action === "return") {
1855
- return { kind: "emit", step: branch.result, state: bundle };
1856
- }
1857
- if (branch.action === "run_omit") {
1858
- return runDeterministicExecutor(bundle, ctx);
1859
- }
1860
- return { kind: "transition", state: branch.bundle };
1861
- },
1922
+ intent_equivalence_current: omittableObligation(handleIntentEquivalenceBranch),
1862
1923
  // Charter extraction (Phase C): consume the lane submissions (ingest+gate),
1863
1924
  // omit at a shallow ceiling, or emit the host charter-extraction step.
1864
- charter_extraction_current: async (bundle, ctx) => {
1865
- const state = deriveAuditState(bundle, { emitStaleness: false });
1866
- const branch = await handleCharterExtractionBranch(ctx.params, bundle, state, ctx.tx);
1867
- if (branch.action === "return") {
1868
- return { kind: "emit", step: branch.result, state: bundle };
1869
- }
1870
- if (branch.action === "run_omit") {
1871
- return runDeterministicExecutor(bundle, ctx);
1872
- }
1873
- return { kind: "transition", state: branch.bundle };
1874
- },
1925
+ charter_extraction_current: omittableObligation(handleCharterExtractionBranch),
1875
1926
  // Charter comparison (steps 2–3): consume the comparison submission, settle
1876
1927
  // deterministically when the register is not comparison_pending, or emit the
1877
1928
  // comparison reader's host step.
1878
- charter_comparison_current: async (bundle, ctx) => {
1879
- const state = deriveAuditState(bundle, { emitStaleness: false });
1880
- const branch = await handleCharterComparisonBranch(ctx.params, bundle, state, ctx.tx);
1881
- if (branch.action === "return") {
1882
- return { kind: "emit", step: branch.result, state: bundle };
1883
- }
1884
- if (branch.action === "run_omit") {
1885
- return runDeterministicExecutor(bundle, ctx);
1886
- }
1887
- return { kind: "transition", state: branch.bundle };
1888
- },
1929
+ charter_comparison_current: omittableObligation(handleCharterComparisonBranch),
1889
1930
  // Charter fidelity (step 4): the separate lane's verdicts, or the settle.
1890
- charter_fidelity_current: async (bundle, ctx) => {
1891
- const state = deriveAuditState(bundle, { emitStaleness: false });
1892
- const branch = await handleCharterFidelityBranch(ctx.params, bundle, state, ctx.tx);
1893
- if (branch.action === "return") {
1894
- return { kind: "emit", step: branch.result, state: bundle };
1895
- }
1896
- if (branch.action === "run_omit") {
1897
- return runDeterministicExecutor(bundle, ctx);
1898
- }
1899
- return { kind: "transition", state: branch.bundle };
1900
- },
1931
+ charter_fidelity_current: omittableObligation(handleCharterFidelityBranch),
1901
1932
  // The two design-review passes share one submission-poll handler (it
1902
1933
  // resolves which pass remains).
1903
1934
  design_review_contract_completed: (bundle, ctx) => runDesignReviewObligation(bundle, ctx),
1904
1935
  design_review_conceptual_completed: (bundle, ctx) => runDesignReviewObligation(bundle, ctx),
1905
1936
  // Charter clarification (Phase D triangulation loop).
1906
- charter_clarification_current: async (bundle, ctx) => {
1907
- const state = deriveAuditState(bundle, { emitStaleness: false });
1908
- const branch = await handleCharterClarificationBranch(ctx.params, bundle, state, ctx.tx);
1909
- if (branch.action === "return") {
1910
- return { kind: "emit", step: branch.result, state: bundle };
1911
- }
1912
- if (branch.action === "run_omit") {
1913
- return runDeterministicExecutor(bundle, ctx);
1914
- }
1915
- return { kind: "transition", state: branch.bundle };
1916
- },
1937
+ charter_clarification_current: omittableObligation(handleCharterClarificationBranch),
1917
1938
  // Systemic challenge (Phase E loop-until-dry).
1918
- systemic_challenge_current: async (bundle, ctx) => {
1919
- const state = deriveAuditState(bundle, { emitStaleness: false });
1920
- const branch = await handleSystemicChallengeBranch(ctx.params, bundle, state, ctx.tx);
1921
- if (branch.action === "return") {
1922
- return { kind: "emit", step: branch.result, state: bundle };
1923
- }
1924
- if (branch.action === "run_omit") {
1925
- return runDeterministicExecutor(bundle, ctx);
1926
- }
1927
- return { kind: "transition", state: branch.bundle };
1928
- },
1939
+ systemic_challenge_current: omittableObligation(handleSystemicChallengeBranch),
1929
1940
  // The audit-task dispatch obligation maps to the host-delegation
1930
1941
  // semantic_review_executor (no deterministic runner) → host review.
1931
1942
  audit_tasks_completed: (bundle, ctx) => runHostDelegationObligation(bundle, ctx),
1932
1943
  // Synthesis narrative: consume the narrative lane; emit the host step when
1933
1944
  // narrative is enabled and not yet supplied, otherwise the deterministic
1934
1945
  // omit runs (fold on).
1935
- synthesis_narrative_current: async (bundle, ctx) => {
1936
- const state = deriveAuditState(bundle, { emitStaleness: false });
1937
- const branch = await handleSynthesisNarrativeBranch(ctx.params, bundle, state, ctx.tx);
1938
- if (branch.action === "return") {
1939
- return { kind: "emit", step: branch.result, state: bundle };
1940
- }
1941
- if (branch.action === "run_omit") {
1942
- // Narrative disabled: run the deterministic omit executor so the
1943
- // status:omitted marker is written and the obligation is satisfied.
1944
- return runDeterministicExecutor(bundle, ctx);
1945
- }
1946
- // continue: a narrative submission was consumed + applied — re-scan.
1947
- return { kind: "transition", state: branch.bundle };
1948
- },
1946
+ synthesis_narrative_current: omittableObligation(handleSynthesisNarrativeBranch),
1949
1947
  };
1950
1948
  // The registry's membership and order DERIVE from PRIORITY — never a second
1951
1949
  // hand-enumerated list, so an id cannot be in the scan and absent from the
@@ -1991,15 +1989,20 @@ async function ingestAvailableInspectionResults(bundle, ctx) {
1991
1989
  // so the accept decision sees the same disk truth `runAuditStep`'s batch gate
1992
1990
  // validates against; the audit-task manifest comes from the same bundle.
1993
1991
  const lineIndexForIngest = bundle.repo_manifest
1994
- ? await buildLineIndex(ctx.params.root, bundle.repo_manifest)
1992
+ ? await buildLineIndex(requireSourceRoot(ctx.params), bundle.repo_manifest)
1995
1993
  : undefined;
1994
+ // The set replayed below. The ingest validates those entries again against
1995
+ // this same tree, so the batch gate cannot refuse what it is handed.
1996
+ const pendingIds = new Set(buildPendingAuditTasks(bundle).map((task) => task.task_id));
1996
1997
  try {
1997
1998
  const ingested = await ingestAuditHostResults({
1998
1999
  root: ctx.params.root,
2000
+ sourceRoot: requireSourceRoot(ctx.params),
1999
2001
  artifactsDir: ctx.params.artifactsDir,
2000
2002
  runId: currentRun.run_id,
2001
2003
  auditTasks: bundle.audit_tasks ?? [],
2002
2004
  lineIndex: lineIndexForIngest,
2005
+ pendingTaskIds: pendingIds,
2003
2006
  });
2004
2007
  acceptedResults = ingested.accepted_results;
2005
2008
  ingestIssues = ingested.issues;
@@ -2036,13 +2039,13 @@ async function ingestAvailableInspectionResults(bundle, ctx) {
2036
2039
  // Even a refused-only arrival must be visible on the next host step.
2037
2040
  mergeFoldAdvisoriesInto(ctx.foldAdvisoriesRef.value, { issues: ingestIssues, validationWarnings });
2038
2041
  await writePendingAdvisories(ctx.params.artifactsDir, ctx.foldAdvisoriesRef.value);
2039
- const pendingIds = new Set(buildPendingAuditTasks(bundle).map((task) => task.task_id));
2040
2042
  const pendingAccepted = acceptedResults.filter((result) => pendingIds.has(result.task_id));
2041
2043
  if (pendingAccepted.length > 0) {
2042
2044
  // Forced, lock-free, against the CARRIED bundle: the fold owns the one
2043
2045
  // hold and the one persist.
2044
2046
  const ingested = await runAuditStepUnlocked({
2045
2047
  root: ctx.params.root,
2048
+ sourceRoot: requireSourceRoot(ctx.params),
2046
2049
  artifactsDir: ctx.params.artifactsDir,
2047
2050
  preferredExecutor: "result_ingestion_executor",
2048
2051
  auditResultsData: [...pendingAccepted],
@@ -2069,6 +2072,7 @@ async function runHostDelegationObligation(bundle, ctx) {
2069
2072
  // other half).
2070
2073
  const review = await ensureSemanticReviewRunUnlocked({
2071
2074
  root: ctx.params.root,
2075
+ sourceRoot: requireSourceRoot(ctx.params),
2072
2076
  artifactsDir: ctx.params.artifactsDir,
2073
2077
  bundle,
2074
2078
  state,
@@ -2119,7 +2123,12 @@ async function withFoldAdvisories(step, ctx) {
2119
2123
  if (step.kind !== "semantic_review") {
2120
2124
  return {
2121
2125
  ...step,
2122
- advisoryNotice: renderCarriedAdvisoryLines(carried),
2126
+ // An architecture step that carries a ready-inspection run names that
2127
+ // run's workload in its own task, above the carried report (the
2128
+ // `withReadyInspection` section); the pending items are in it.
2129
+ advisoryNotice: renderCarriedAdvisoryLines(carried, step.inspectionRun !== undefined && step.kind !== "blocked"
2130
+ ? "named_above"
2131
+ : "next_call"),
2123
2132
  };
2124
2133
  }
2125
2134
  return {
@@ -2142,14 +2151,15 @@ async function withFoldAdvisories(step, ctx) {
2142
2151
  * the bullet format and the headings, and the copy had already gone stale
2143
2152
  * against the section it claimed to match.
2144
2153
  *
2145
- * The workload is `next_call` here: this report rides a step of another kind,
2146
- * so no workload is published below it.
2154
+ * The report rides a step of another kind and follows its whole task, so the
2155
+ * workload is `named_above` when that task names a ready-inspection workload,
2156
+ * and `next_call` otherwise.
2147
2157
  */
2148
- function renderCarriedAdvisoryLines(carried) {
2158
+ function renderCarriedAdvisoryLines(carried, workload) {
2149
2159
  return renderIngestReportLines({
2150
2160
  issues: carried.ingestIssues,
2151
2161
  remedy: auditIngestRemedy,
2152
- workload: "next_call",
2162
+ workload,
2153
2163
  advisories: carried.validationWarnings,
2154
2164
  });
2155
2165
  }
@@ -2223,8 +2233,8 @@ function foldHeartbeatRecord(obligation, durationMs) {
2223
2233
  * Drive the deterministic fold for one `next-step` call.
2224
2234
  *
2225
2235
  * Structure mirrors remediate-code's `decideNextStepLoop` (the proven engine
2226
- * consumer): a PREAMBLE (the `index===0` file-integrity re-intake, the analog of
2227
- * remediate's `forceReplan`) then the shared `advance` running audit's `PRIORITY`
2236
+ * consumer): source-integrity refresh under the hold, then the shared
2237
+ * `advance` running audit's `PRIORITY`
2228
2238
  * obligations. Each deterministic executor `transition`s (folding the whole chain
2229
2239
  * into one host round-trip); host-delegation / dispatch / terminal obligations
2230
2240
  * `emit` the host-actionable step.
@@ -2239,13 +2249,24 @@ function foldHeartbeatRecord(obligation, durationMs) {
2239
2249
  * terminal step (present_report when a report is rendered, else blocked).
2240
2250
  */
2241
2251
  export async function runDeterministicForNextStep(params) {
2252
+ // Only explicit deadlines survive across calls. A synthesized budget belongs to
2253
+ // this invocation, even when the caller reuses its original options object.
2254
+ const deadline = params.deadline ?? params.externalAcquisition?.deadline ?? { at: Date.now() + params.timeoutMs };
2255
+ params = {
2256
+ ...params,
2257
+ deadline,
2258
+ ...(params.externalAcquisition ? { externalAcquisition: { ...params.externalAcquisition, deadline } } : {}),
2259
+ };
2242
2260
  // The heartbeat wraps the WHOLE call, throw path included: a drain that dies
2243
2261
  // halfway is exactly when a caller most needs to know how far it got, and the
2244
2262
  // interval beat has no other owner on this path (the fold drives the shared
2245
2263
  // engine directly rather than through `advanceAudit`).
2246
2264
  const heartbeat = startAdvanceHeartbeat();
2247
2265
  try {
2248
- return await runDeterministicFold(params, heartbeat);
2266
+ const result = await runDeterministicFold(params, heartbeat);
2267
+ // The fold resolved the run's snapshot under its hold; the emission renders
2268
+ // every packet and workload from the same tree.
2269
+ return { ...result, sourceRoot: requireSourceRoot(params) };
2249
2270
  }
2250
2271
  finally {
2251
2272
  heartbeat.stop();
@@ -2265,38 +2286,6 @@ async function runDeterministicFold(params, heartbeat) {
2265
2286
  const analyzersRef = {
2266
2287
  value: params.analyzers,
2267
2288
  };
2268
- // PREAMBLE — file-integrity re-intake (runs once, like remediate's
2269
- // forceReplan). When pending audit-task files have changed/vanished since the
2270
- // manifest was built, re-run intake so planning re-grounds. advanceAudit does
2271
- // not persist (only runAuditStep does), so this is the same diagnostic-then-
2272
- // reload the hand loop performed on its first iteration: the warning fires and
2273
- // the fold below starts from the freshly-loaded disk bundle.
2274
- {
2275
- const bundle = await loadArtifactBundle(params.artifactsDir);
2276
- if (bundle.audit_state?.status !== "complete" && bundle.repo_manifest) {
2277
- const pendingTasks = buildPendingAuditTasks(bundle);
2278
- const taskFiles = new Set();
2279
- for (const task of pendingTasks) {
2280
- for (const fp of Object.keys(task.file_line_counts ?? {}))
2281
- taskFiles.add(fp);
2282
- }
2283
- if (taskFiles.size > 0) {
2284
- const integrity = await checkFileIntegrity(params.root, bundle.repo_manifest, [...taskFiles]);
2285
- if (!integrity.is_clean) {
2286
- // Route this diagnostic OFF stdout: cmdNextStep emits the step
2287
- // contract as the sole stdout payload via console.log(JSON.stringify),
2288
- // so a console.log here would corrupt the JSON-on-stdout contract.
2289
- process.stderr.write(`[audit-code] nextStep: integrity check — ${integrity.changed_files.length} changed, ` +
2290
- `${integrity.missing_files.length} missing, ${integrity.io_errors.length} io-error(s); re-running intake.\n`);
2291
- await advanceAudit(bundle, {
2292
- root: params.root,
2293
- artifactsDir: params.artifactsDir,
2294
- preferredExecutor: "intake_executor",
2295
- });
2296
- }
2297
- }
2298
- }
2299
- }
2300
2289
  const ctx = {
2301
2290
  params,
2302
2291
  analyzersRef,
@@ -2330,8 +2319,18 @@ async function runDeterministicFold(params, heartbeat) {
2330
2319
  const holdStartMs = Date.now();
2331
2320
  let chargedExecutions;
2332
2321
  let ingestionExecutions = 0;
2322
+ let intakeExecutions = 0;
2333
2323
  await recoverStagedSubmissions(params.artifactsDir);
2334
2324
  const previousConsent = await readRunConsentUnlocked(params.root, params.artifactsDir);
2325
+ // The run's frozen snapshot, under the same hold as the consent record it
2326
+ // shares a lifetime with: created at run start, re-checked out on resume.
2327
+ // Every content read of this fold uses it (`requireSourceRoot`); the
2328
+ // complete-run rule lives in `ensureRunSourceRoot`, shared with every
2329
+ // standalone step command.
2330
+ params.sourceRoot = await ensureRunSourceRoot(params.root, params.artifactsDir);
2331
+ if (params.since !== undefined) {
2332
+ params.since = await resolveRunSince(params.root, params.artifactsDir, params.since);
2333
+ }
2335
2334
  const consent = params.autoFix?.enabled === undefined && !params.autoFix?.dryRun
2336
2335
  ? previousConsent
2337
2336
  : await updateRunConsentUnlocked(params.root, params.artifactsDir, {}, params.autoFix?.enabled, params.autoFix?.dryRun);
@@ -2352,6 +2351,26 @@ async function runDeterministicFold(params, heartbeat) {
2352
2351
  }
2353
2352
  ctx.currentBundleRef.value = startBundle;
2354
2353
  try {
2354
+ // Observe source integrity against the fresh carried authority, under
2355
+ // the same hold and before any old host submission can be ingested.
2356
+ if (startBundle.audit_state?.status !== "complete" && startBundle.repo_manifest) {
2357
+ const taskFiles = [...new Set(buildPendingAuditTasks(startBundle).flatMap((task) => task.file_paths))];
2358
+ if (taskFiles.length > 0) {
2359
+ const integrity = await checkFileIntegrity(requireSourceRoot(params), startBundle.repo_manifest, taskFiles);
2360
+ if (!integrity.is_clean) {
2361
+ process.stderr.write(`[audit-code] nextStep: integrity check - ${integrity.changed_files.length} changed, ` +
2362
+ `${integrity.missing_files.length} missing, ${integrity.io_errors.length} io-error(s); re-running intake.\n`);
2363
+ intakeExecutions = 1;
2364
+ const refreshed = await runSingleAdvanceStep(startBundle, {
2365
+ root: requireSourceRoot(params), repositoryRoot: params.root, artifactsDir: params.artifactsDir,
2366
+ preferredExecutor: "intake_executor", scopeIndexMemo: params.scopeIndexMemo,
2367
+ runLogger: foldLogger, heartbeat,
2368
+ });
2369
+ startBundle = refreshed.updated_bundle;
2370
+ ctx.currentBundleRef.value = startBundle;
2371
+ }
2372
+ }
2373
+ }
2355
2374
  if (startBundle.audit_tasks && startBundle.audit_state?.status !== "complete" &&
2356
2375
  deriveAuditState(startBundle, { emitStaleness: false }).obligations.find((obligation) => obligation.id === "planning_artifacts")?.state === "satisfied") {
2357
2376
  const beforeIngest = startBundle;
@@ -2364,13 +2383,13 @@ async function runDeterministicFold(params, heartbeat) {
2364
2383
  obligations: trackFoldBundle(buildAuditObligations()),
2365
2384
  }, startBundle, ctx, {
2366
2385
  maxTransitions: engineMaxTransitions(),
2367
- maxExecutions: MAX_DRAIN_STEPS - ingestionExecutions,
2386
+ maxExecutions: MAX_DRAIN_STEPS - ingestionExecutions - intakeExecutions,
2368
2387
  });
2369
- chargedExecutions = engineOutcome.executions + ingestionExecutions;
2388
+ chargedExecutions = engineOutcome.executions + ingestionExecutions + intakeExecutions;
2370
2389
  if (engineOutcome.step && engineOutcome.step.kind !== "terminal_intent" && ARCHITECTURE_WORK_STEPS.has(engineOutcome.step.kind) &&
2371
2390
  buildPendingAuditTasks(engineOutcome.state).length > 0) {
2372
2391
  const inspection = await ensureSemanticReviewRunUnlocked({
2373
- root: params.root, artifactsDir: params.artifactsDir,
2392
+ root: params.root, sourceRoot: requireSourceRoot(params), artifactsDir: params.artifactsDir,
2374
2393
  bundle: engineOutcome.state,
2375
2394
  state: deriveAuditState(engineOutcome.state, { emitStaleness: false }),
2376
2395
  obligationId: "audit_tasks_completed",
@@ -2423,14 +2442,14 @@ async function runDeterministicFold(params, heartbeat) {
2423
2442
  // obligation that produces most of it, is what makes "stated on exactly one
2424
2443
  // emitted step, WHICHEVER step that is" true for every kind. A terminal
2425
2444
  // intent is deliberately excluded: it is not a step, and the terminal
2426
- // conversion below promotes and deletes the artifacts dir — the carry has
2427
- // nowhere left to be stated, and the run is over.
2445
+ // conversion below promotes — the carry has nowhere left to be stated, and
2446
+ // the run is over.
2428
2447
  if (outcome.step && outcome.step.kind !== "terminal_intent") {
2429
2448
  return await withFoldAdvisories(outcome.step, ctx);
2430
2449
  }
2431
2450
  if (outcome.step) {
2432
2451
  // Guard terminals convert POST-commit, POST-hold: buildTerminalStep can
2433
- // promote, and promotion deletes artifactsDir.
2452
+ // promote, which writes outside the dir and removes a complete run's snapshot.
2434
2453
  return await buildTerminalStep(params, outcome.step.bundle, outcome.step.state, outcome.step.reason);
2435
2454
  }
2436
2455
  if (outcome.stopped === "budget") {