audit-tools 0.51.7 → 0.51.9

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 (665) hide show
  1. package/dist/audit/clarification/blastRadius.d.ts +17 -16
  2. package/dist/audit/clarification/blastRadius.d.ts.map +1 -1
  3. package/dist/audit/clarification/blastRadius.js +48 -44
  4. package/dist/audit/clarification/blastRadius.js.map +1 -1
  5. package/dist/audit/clarification/dials.d.ts +4 -4
  6. package/dist/audit/clarification/dials.d.ts.map +1 -1
  7. package/dist/audit/clarification/dials.js +1 -0
  8. package/dist/audit/clarification/dials.js.map +1 -1
  9. package/dist/audit/clarification/partition.d.ts +12 -21
  10. package/dist/audit/clarification/partition.d.ts.map +1 -1
  11. package/dist/audit/clarification/partition.js +52 -59
  12. package/dist/audit/clarification/partition.js.map +1 -1
  13. package/dist/audit/clarification/riskGate.d.ts +2 -2
  14. package/dist/audit/clarification/riskGate.d.ts.map +1 -1
  15. package/dist/audit/clarification/riskGate.js +1 -0
  16. package/dist/audit/clarification/riskGate.js.map +1 -1
  17. package/dist/audit/clarification/voiQueue.d.ts +3 -3
  18. package/dist/audit/clarification/voiQueue.d.ts.map +1 -1
  19. package/dist/audit/clarification/voiQueue.js +1 -0
  20. package/dist/audit/clarification/voiQueue.js.map +1 -1
  21. package/dist/audit/cli/auditStep.d.ts +14 -2
  22. package/dist/audit/cli/auditStep.d.ts.map +1 -1
  23. package/dist/audit/cli/auditStep.js +13 -5
  24. package/dist/audit/cli/auditStep.js.map +1 -1
  25. package/dist/audit/cli/charterClarificationPrompt.d.ts +6 -9
  26. package/dist/audit/cli/charterClarificationPrompt.d.ts.map +1 -1
  27. package/dist/audit/cli/charterClarificationPrompt.js +35 -47
  28. package/dist/audit/cli/charterClarificationPrompt.js.map +1 -1
  29. package/dist/audit/cli/charterComparisonPrompt.d.ts +14 -0
  30. package/dist/audit/cli/charterComparisonPrompt.d.ts.map +1 -0
  31. package/dist/audit/cli/charterComparisonPrompt.js +111 -0
  32. package/dist/audit/cli/charterComparisonPrompt.js.map +1 -0
  33. package/dist/audit/cli/charterExtractionPrompt.d.ts +14 -17
  34. package/dist/audit/cli/charterExtractionPrompt.d.ts.map +1 -1
  35. package/dist/audit/cli/charterExtractionPrompt.js +81 -104
  36. package/dist/audit/cli/charterExtractionPrompt.js.map +1 -1
  37. package/dist/audit/cli/charterFidelityPrompt.d.ts +14 -0
  38. package/dist/audit/cli/charterFidelityPrompt.d.ts.map +1 -0
  39. package/dist/audit/cli/charterFidelityPrompt.js +58 -0
  40. package/dist/audit/cli/charterFidelityPrompt.js.map +1 -0
  41. package/dist/audit/cli/conceptualDispatch.d.ts +39 -6
  42. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  43. package/dist/audit/cli/conceptualDispatch.js +59 -12
  44. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  45. package/dist/audit/cli/confirmIntentStep.d.ts.map +1 -1
  46. package/dist/audit/cli/confirmIntentStep.js +46 -2
  47. package/dist/audit/cli/confirmIntentStep.js.map +1 -1
  48. package/dist/audit/cli/dispatch/hostHandoff.d.ts +18 -6
  49. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  50. package/dist/audit/cli/dispatch/hostHandoff.js +525 -67
  51. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  52. package/dist/audit/cli/fanoutLanes.d.ts +24 -0
  53. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
  54. package/dist/audit/cli/fanoutLanes.js +9 -1
  55. package/dist/audit/cli/fanoutLanes.js.map +1 -1
  56. package/dist/audit/cli/foldTransaction.d.ts.map +1 -1
  57. package/dist/audit/cli/foldTransaction.js +14 -3
  58. package/dist/audit/cli/foldTransaction.js.map +1 -1
  59. package/dist/audit/cli/forceSynthesisCommand.d.ts.map +1 -1
  60. package/dist/audit/cli/forceSynthesisCommand.js +4 -1
  61. package/dist/audit/cli/forceSynthesisCommand.js.map +1 -1
  62. package/dist/audit/cli/intakeCommand.d.ts.map +1 -1
  63. package/dist/audit/cli/intakeCommand.js +1 -0
  64. package/dist/audit/cli/intakeCommand.js.map +1 -1
  65. package/dist/audit/cli/laneSubmissions.d.ts +18 -12
  66. package/dist/audit/cli/laneSubmissions.d.ts.map +1 -1
  67. package/dist/audit/cli/laneSubmissions.js +40 -4
  68. package/dist/audit/cli/laneSubmissions.js.map +1 -1
  69. package/dist/audit/cli/laneValidators.d.ts.map +1 -1
  70. package/dist/audit/cli/laneValidators.js +14 -14
  71. package/dist/audit/cli/laneValidators.js.map +1 -1
  72. package/dist/audit/cli/nextStepCommand.d.ts +7 -0
  73. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  74. package/dist/audit/cli/nextStepCommand.js +206 -31
  75. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  76. package/dist/audit/cli/nextStepHelpers.d.ts +92 -28
  77. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  78. package/dist/audit/cli/nextStepHelpers.js +363 -126
  79. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  80. package/dist/audit/cli/prompts.d.ts +10 -0
  81. package/dist/audit/cli/prompts.d.ts.map +1 -1
  82. package/dist/audit/cli/prompts.js +3 -1
  83. package/dist/audit/cli/prompts.js.map +1 -1
  84. package/dist/audit/cli/reviewRun.d.ts +12 -0
  85. package/dist/audit/cli/reviewRun.d.ts.map +1 -1
  86. package/dist/audit/cli/reviewRun.js +242 -29
  87. package/dist/audit/cli/reviewRun.js.map +1 -1
  88. package/dist/audit/cli/sampleRunCommand.d.ts +12 -4
  89. package/dist/audit/cli/sampleRunCommand.d.ts.map +1 -1
  90. package/dist/audit/cli/semanticReviewStep.d.ts +9 -0
  91. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  92. package/dist/audit/cli/semanticReviewStep.js +71 -30
  93. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  94. package/dist/audit/cli/statusCommand.d.ts.map +1 -1
  95. package/dist/audit/cli/statusCommand.js +29 -66
  96. package/dist/audit/cli/statusCommand.js.map +1 -1
  97. package/dist/audit/cli/stepScaffold.d.ts +43 -2
  98. package/dist/audit/cli/stepScaffold.d.ts.map +1 -1
  99. package/dist/audit/cli/stepScaffold.js +24 -10
  100. package/dist/audit/cli/stepScaffold.js.map +1 -1
  101. package/dist/audit/cli/steps.d.ts +52 -29
  102. package/dist/audit/cli/steps.d.ts.map +1 -1
  103. package/dist/audit/cli/steps.js +44 -14
  104. package/dist/audit/cli/steps.js.map +1 -1
  105. package/dist/audit/cli/synthesizeCommand.d.ts.map +1 -1
  106. package/dist/audit/cli/synthesizeCommand.js +4 -1
  107. package/dist/audit/cli/synthesizeCommand.js.map +1 -1
  108. package/dist/audit/contracts/workerSchemas.d.ts +65 -16
  109. package/dist/audit/contracts/workerSchemas.d.ts.map +1 -1
  110. package/dist/audit/contracts/workerSchemas.js +89 -8
  111. package/dist/audit/contracts/workerSchemas.js.map +1 -1
  112. package/dist/audit/contracts/wrapperResponse.d.ts +14 -21
  113. package/dist/audit/contracts/wrapperResponse.d.ts.map +1 -1
  114. package/dist/audit/contracts/wrapperResponse.js +0 -1
  115. package/dist/audit/contracts/wrapperResponse.js.map +1 -1
  116. package/dist/audit/decompose/findings.d.ts.map +1 -1
  117. package/dist/audit/decompose/findings.js +10 -2
  118. package/dist/audit/decompose/findings.js.map +1 -1
  119. package/dist/audit/extractors/designAssessment.d.ts.map +1 -1
  120. package/dist/audit/extractors/designAssessment.js +13 -4
  121. package/dist/audit/extractors/designAssessment.js.map +1 -1
  122. package/dist/audit/extractors/disposition.d.ts.map +1 -1
  123. package/dist/audit/extractors/disposition.js +17 -5
  124. package/dist/audit/extractors/disposition.js.map +1 -1
  125. package/dist/audit/extractors/graph.d.ts +1 -1
  126. package/dist/audit/extractors/graph.js +1 -1
  127. package/dist/audit/extractors/graphRoutes.d.ts.map +1 -1
  128. package/dist/audit/extractors/graphRoutes.js +224 -17
  129. package/dist/audit/extractors/graphRoutes.js.map +1 -1
  130. package/dist/audit/extractors/leadLineage.d.ts +10 -0
  131. package/dist/audit/extractors/leadLineage.d.ts.map +1 -0
  132. package/dist/audit/extractors/leadLineage.js +44 -0
  133. package/dist/audit/extractors/leadLineage.js.map +1 -0
  134. package/dist/audit/io/artifacts.d.ts.map +1 -1
  135. package/dist/audit/io/artifacts.js +25 -8
  136. package/dist/audit/io/artifacts.js.map +1 -1
  137. package/dist/audit/io/runArtifacts.d.ts +76 -1
  138. package/dist/audit/io/runArtifacts.d.ts.map +1 -1
  139. package/dist/audit/io/runArtifacts.js +113 -20
  140. package/dist/audit/io/runArtifacts.js.map +1 -1
  141. package/dist/audit/io/toolingManifest.d.ts +15 -0
  142. package/dist/audit/io/toolingManifest.d.ts.map +1 -1
  143. package/dist/audit/io/toolingManifest.js +158 -11
  144. package/dist/audit/io/toolingManifest.js.map +1 -1
  145. package/dist/audit/orchestrator/advance.d.ts.map +1 -1
  146. package/dist/audit/orchestrator/advance.js +30 -4
  147. package/dist/audit/orchestrator/advance.js.map +1 -1
  148. package/dist/audit/orchestrator/advanceTypes.d.ts +28 -5
  149. package/dist/audit/orchestrator/advanceTypes.d.ts.map +1 -1
  150. package/dist/audit/orchestrator/artifactMetadata.d.ts.map +1 -1
  151. package/dist/audit/orchestrator/artifactMetadata.js +39 -1
  152. package/dist/audit/orchestrator/artifactMetadata.js.map +1 -1
  153. package/dist/audit/orchestrator/auditTaskUtils.d.ts.map +1 -1
  154. package/dist/audit/orchestrator/auditTaskUtils.js +4 -1
  155. package/dist/audit/orchestrator/auditTaskUtils.js.map +1 -1
  156. package/dist/audit/orchestrator/charterClarificationExecutor.d.ts +11 -17
  157. package/dist/audit/orchestrator/charterClarificationExecutor.d.ts.map +1 -1
  158. package/dist/audit/orchestrator/charterClarificationExecutor.js +61 -93
  159. package/dist/audit/orchestrator/charterClarificationExecutor.js.map +1 -1
  160. package/dist/audit/orchestrator/charterComparisonExecutor.d.ts +24 -0
  161. package/dist/audit/orchestrator/charterComparisonExecutor.d.ts.map +1 -0
  162. package/dist/audit/orchestrator/charterComparisonExecutor.js +110 -0
  163. package/dist/audit/orchestrator/charterComparisonExecutor.js.map +1 -0
  164. package/dist/audit/orchestrator/charterExtractionExecutor.d.ts +34 -20
  165. package/dist/audit/orchestrator/charterExtractionExecutor.d.ts.map +1 -1
  166. package/dist/audit/orchestrator/charterExtractionExecutor.js +80 -106
  167. package/dist/audit/orchestrator/charterExtractionExecutor.js.map +1 -1
  168. package/dist/audit/orchestrator/charterFidelityExecutor.d.ts +20 -0
  169. package/dist/audit/orchestrator/charterFidelityExecutor.d.ts.map +1 -0
  170. package/dist/audit/orchestrator/charterFidelityExecutor.js +76 -0
  171. package/dist/audit/orchestrator/charterFidelityExecutor.js.map +1 -0
  172. package/dist/audit/orchestrator/charterFidelityPacket.d.ts +7 -0
  173. package/dist/audit/orchestrator/charterFidelityPacket.d.ts.map +1 -0
  174. package/dist/audit/orchestrator/charterFidelityPacket.js +68 -0
  175. package/dist/audit/orchestrator/charterFidelityPacket.js.map +1 -0
  176. package/dist/audit/orchestrator/dependencyMap.d.ts.map +1 -1
  177. package/dist/audit/orchestrator/dependencyMap.js +9 -8
  178. package/dist/audit/orchestrator/dependencyMap.js.map +1 -1
  179. package/dist/audit/orchestrator/dependencySlices.d.ts.map +1 -1
  180. package/dist/audit/orchestrator/dependencySlices.js +7 -6
  181. package/dist/audit/orchestrator/dependencySlices.js.map +1 -1
  182. package/dist/audit/orchestrator/designReviewProjection.d.ts.map +1 -1
  183. package/dist/audit/orchestrator/designReviewProjection.js +7 -0
  184. package/dist/audit/orchestrator/designReviewProjection.js.map +1 -1
  185. package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -1
  186. package/dist/audit/orchestrator/designReviewPrompt.js +58 -19
  187. package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -1
  188. package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
  189. package/dist/audit/orchestrator/executorRunners.js +6 -2
  190. package/dist/audit/orchestrator/executorRunners.js.map +1 -1
  191. package/dist/audit/orchestrator/executors.d.ts.map +1 -1
  192. package/dist/audit/orchestrator/executors.js +22 -8
  193. package/dist/audit/orchestrator/executors.js.map +1 -1
  194. package/dist/audit/orchestrator/hostInputPause.js +1 -0
  195. package/dist/audit/orchestrator/hostInputPause.js.map +1 -1
  196. package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts +40 -0
  197. package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts.map +1 -1
  198. package/dist/audit/orchestrator/intentCheckpointExecutor.js +32 -2
  199. package/dist/audit/orchestrator/intentCheckpointExecutor.js.map +1 -1
  200. package/dist/audit/orchestrator/intentCheckpointGate.d.ts +5 -3
  201. package/dist/audit/orchestrator/intentCheckpointGate.d.ts.map +1 -1
  202. package/dist/audit/orchestrator/intentCheckpointGate.js +34 -5
  203. package/dist/audit/orchestrator/intentCheckpointGate.js.map +1 -1
  204. package/dist/audit/orchestrator/intentEquivalenceExecutor.d.ts +2 -2
  205. package/dist/audit/orchestrator/intentInterpreter.d.ts +1 -1
  206. package/dist/audit/orchestrator/intentInterpreter.js +1 -1
  207. package/dist/audit/orchestrator/nextStep.d.ts.map +1 -1
  208. package/dist/audit/orchestrator/nextStep.js +3 -1
  209. package/dist/audit/orchestrator/nextStep.js.map +1 -1
  210. package/dist/audit/orchestrator/obligationPolicy.d.ts +2 -1
  211. package/dist/audit/orchestrator/obligationPolicy.d.ts.map +1 -1
  212. package/dist/audit/orchestrator/obligationPolicy.js +19 -7
  213. package/dist/audit/orchestrator/obligationPolicy.js.map +1 -1
  214. package/dist/audit/orchestrator/partitionTaskGraph.d.ts.map +1 -1
  215. package/dist/audit/orchestrator/partitionTaskGraph.js +1 -0
  216. package/dist/audit/orchestrator/partitionTaskGraph.js.map +1 -1
  217. package/dist/audit/orchestrator/resultIngestion.d.ts.map +1 -1
  218. package/dist/audit/orchestrator/resultIngestion.js +3 -1
  219. package/dist/audit/orchestrator/resultIngestion.js.map +1 -1
  220. package/dist/audit/orchestrator/runtimeCommand.d.ts +72 -0
  221. package/dist/audit/orchestrator/runtimeCommand.d.ts.map +1 -1
  222. package/dist/audit/orchestrator/runtimeCommand.js +177 -20
  223. package/dist/audit/orchestrator/runtimeCommand.js.map +1 -1
  224. package/dist/audit/orchestrator/scopeIndexBaseline.d.ts +56 -0
  225. package/dist/audit/orchestrator/scopeIndexBaseline.d.ts.map +1 -0
  226. package/dist/audit/orchestrator/scopeIndexBaseline.js +114 -0
  227. package/dist/audit/orchestrator/scopeIndexBaseline.js.map +1 -0
  228. package/dist/audit/orchestrator/staleness.d.ts +70 -1
  229. package/dist/audit/orchestrator/staleness.d.ts.map +1 -1
  230. package/dist/audit/orchestrator/staleness.js +171 -21
  231. package/dist/audit/orchestrator/staleness.js.map +1 -1
  232. package/dist/audit/orchestrator/state.d.ts.map +1 -1
  233. package/dist/audit/orchestrator/state.js +49 -25
  234. package/dist/audit/orchestrator/state.js.map +1 -1
  235. package/dist/audit/orchestrator/structureExecutors.d.ts.map +1 -1
  236. package/dist/audit/orchestrator/structureExecutors.js +7 -5
  237. package/dist/audit/orchestrator/structureExecutors.js.map +1 -1
  238. package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts.map +1 -1
  239. package/dist/audit/orchestrator/syntaxResolutionExecutor.js +1 -0
  240. package/dist/audit/orchestrator/syntaxResolutionExecutor.js.map +1 -1
  241. package/dist/audit/orchestrator/systemicChallengeExecutor.d.ts +13 -2
  242. package/dist/audit/orchestrator/systemicChallengeExecutor.d.ts.map +1 -1
  243. package/dist/audit/orchestrator/systemicChallengeExecutor.js +166 -12
  244. package/dist/audit/orchestrator/systemicChallengeExecutor.js.map +1 -1
  245. package/dist/audit/reporting/mergeFindings.d.ts.map +1 -1
  246. package/dist/audit/reporting/mergeFindings.js +6 -5
  247. package/dist/audit/reporting/mergeFindings.js.map +1 -1
  248. package/dist/audit/reporting/synthesis.d.ts +117 -0
  249. package/dist/audit/reporting/synthesis.d.ts.map +1 -1
  250. package/dist/audit/reporting/synthesis.js +277 -10
  251. package/dist/audit/reporting/synthesis.js.map +1 -1
  252. package/dist/audit/supervisor/operatorHandoff.d.ts +0 -2
  253. package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -1
  254. package/dist/audit/supervisor/operatorHandoff.js +0 -3
  255. package/dist/audit/supervisor/operatorHandoff.js.map +1 -1
  256. package/dist/audit/systemic/coveredThemes.d.ts +28 -0
  257. package/dist/audit/systemic/coveredThemes.d.ts.map +1 -0
  258. package/dist/audit/systemic/coveredThemes.js +52 -0
  259. package/dist/audit/systemic/coveredThemes.js.map +1 -0
  260. package/dist/audit/systemic/reviewFileMap.d.ts +81 -0
  261. package/dist/audit/systemic/reviewFileMap.d.ts.map +1 -0
  262. package/dist/audit/systemic/reviewFileMap.js +169 -0
  263. package/dist/audit/systemic/reviewFileMap.js.map +1 -0
  264. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts.map +1 -1
  265. package/dist/audit/systemic/secondOrderAdversaryPrompt.js +149 -26
  266. package/dist/audit/systemic/secondOrderAdversaryPrompt.js.map +1 -1
  267. package/dist/audit/systemic/systemicChallengeLoop.d.ts +44 -4
  268. package/dist/audit/systemic/systemicChallengeLoop.d.ts.map +1 -1
  269. package/dist/audit/systemic/systemicChallengeLoop.js +114 -10
  270. package/dist/audit/systemic/systemicChallengeLoop.js.map +1 -1
  271. package/dist/audit/types/auditState.d.ts +6 -6
  272. package/dist/audit/types/charterClarification.d.ts +9 -4
  273. package/dist/audit/types/charterClarification.d.ts.map +1 -1
  274. package/dist/audit/types/charterRegister.d.ts +48 -93
  275. package/dist/audit/types/charterRegister.d.ts.map +1 -1
  276. package/dist/audit/types/charterRegister.js +15 -26
  277. package/dist/audit/types/charterRegister.js.map +1 -1
  278. package/dist/audit/types/conceptualAdjudication.d.ts +88 -18
  279. package/dist/audit/types/conceptualAdjudication.d.ts.map +1 -1
  280. package/dist/audit/types/conceptualAdjudication.js +77 -16
  281. package/dist/audit/types/conceptualAdjudication.js.map +1 -1
  282. package/dist/audit/types/designAssessment.d.ts +8 -6
  283. package/dist/audit/types/designAssessment.d.ts.map +1 -1
  284. package/dist/audit/types/reviewPlanning.d.ts +2 -2
  285. package/dist/audit/types/systemicChallenge.d.ts +43 -7
  286. package/dist/audit/types/systemicChallenge.d.ts.map +1 -1
  287. package/dist/audit/types.d.ts +71 -10
  288. package/dist/audit/types.d.ts.map +1 -1
  289. package/dist/audit/types.js +23 -2
  290. package/dist/audit/types.js.map +1 -1
  291. package/dist/audit/validation/auditResults.d.ts +30 -0
  292. package/dist/audit/validation/auditResults.d.ts.map +1 -1
  293. package/dist/audit/validation/auditResults.js +50 -8
  294. package/dist/audit/validation/auditResults.js.map +1 -1
  295. package/dist/audit/validation/ingestIssueCodes.d.ts +1 -1
  296. package/dist/audit/validation/ingestIssueCodes.d.ts.map +1 -1
  297. package/dist/audit/validation/ingestIssueCodes.js +14 -0
  298. package/dist/audit/validation/ingestIssueCodes.js.map +1 -1
  299. package/dist/remediate/contractPipeline/artifactStore.d.ts +97 -2
  300. package/dist/remediate/contractPipeline/artifactStore.d.ts.map +1 -1
  301. package/dist/remediate/contractPipeline/artifactStore.js +163 -9
  302. package/dist/remediate/contractPipeline/artifactStore.js.map +1 -1
  303. package/dist/remediate/contractPipeline/changeClassification.d.ts.map +1 -1
  304. package/dist/remediate/contractPipeline/changeClassification.js +93 -3
  305. package/dist/remediate/contractPipeline/changeClassification.js.map +1 -1
  306. package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts.map +1 -1
  307. package/dist/remediate/contractPipeline/cyclicSeamResolution.js +31 -0
  308. package/dist/remediate/contractPipeline/cyclicSeamResolution.js.map +1 -1
  309. package/dist/remediate/contractPipeline/derive.d.ts +0 -14
  310. package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
  311. package/dist/remediate/contractPipeline/derive.js +52 -24
  312. package/dist/remediate/contractPipeline/derive.js.map +1 -1
  313. package/dist/remediate/contractPipeline/finalizedContractFields.d.ts +50 -0
  314. package/dist/remediate/contractPipeline/finalizedContractFields.d.ts.map +1 -0
  315. package/dist/remediate/contractPipeline/finalizedContractFields.js +77 -0
  316. package/dist/remediate/contractPipeline/finalizedContractFields.js.map +1 -0
  317. package/dist/remediate/contractPipeline/idRegistry.d.ts +85 -0
  318. package/dist/remediate/contractPipeline/idRegistry.d.ts.map +1 -1
  319. package/dist/remediate/contractPipeline/idRegistry.js +147 -0
  320. package/dist/remediate/contractPipeline/idRegistry.js.map +1 -1
  321. package/dist/remediate/contractPipeline/phaseCut.d.ts +13 -16
  322. package/dist/remediate/contractPipeline/phaseCut.d.ts.map +1 -1
  323. package/dist/remediate/contractPipeline/phaseCut.js +15 -30
  324. package/dist/remediate/contractPipeline/phaseCut.js.map +1 -1
  325. package/dist/remediate/contractPipeline/reviewSnapshot.d.ts +20 -1
  326. package/dist/remediate/contractPipeline/reviewSnapshot.d.ts.map +1 -1
  327. package/dist/remediate/contractPipeline/reviewSnapshot.js +23 -7
  328. package/dist/remediate/contractPipeline/reviewSnapshot.js.map +1 -1
  329. package/dist/remediate/contractPipeline/semanticProjection.d.ts +17 -0
  330. package/dist/remediate/contractPipeline/semanticProjection.d.ts.map +1 -1
  331. package/dist/remediate/contractPipeline/semanticProjection.js +6 -9
  332. package/dist/remediate/contractPipeline/semanticProjection.js.map +1 -1
  333. package/dist/remediate/contractPipeline/sketchSource.d.ts +183 -0
  334. package/dist/remediate/contractPipeline/sketchSource.d.ts.map +1 -0
  335. package/dist/remediate/contractPipeline/sketchSource.js +255 -0
  336. package/dist/remediate/contractPipeline/sketchSource.js.map +1 -0
  337. package/dist/remediate/findingFilter.d.ts.map +1 -1
  338. package/dist/remediate/findingFilter.js +1 -0
  339. package/dist/remediate/findingFilter.js.map +1 -1
  340. package/dist/remediate/index.d.ts +81 -0
  341. package/dist/remediate/index.d.ts.map +1 -1
  342. package/dist/remediate/index.js +162 -53
  343. package/dist/remediate/index.js.map +1 -1
  344. package/dist/remediate/intake.d.ts +43 -0
  345. package/dist/remediate/intake.d.ts.map +1 -1
  346. package/dist/remediate/intake.js +82 -13
  347. package/dist/remediate/intake.js.map +1 -1
  348. package/dist/remediate/phases/close.d.ts +33 -2
  349. package/dist/remediate/phases/close.d.ts.map +1 -1
  350. package/dist/remediate/phases/close.js +227 -13
  351. package/dist/remediate/phases/close.js.map +1 -1
  352. package/dist/remediate/phases/closeVerifyHeadEvidence.d.ts +154 -0
  353. package/dist/remediate/phases/closeVerifyHeadEvidence.d.ts.map +1 -0
  354. package/dist/remediate/phases/closeVerifyHeadEvidence.js +242 -0
  355. package/dist/remediate/phases/closeVerifyHeadEvidence.js.map +1 -0
  356. package/dist/remediate/state/runStatus.d.ts +35 -0
  357. package/dist/remediate/state/runStatus.d.ts.map +1 -0
  358. package/dist/remediate/state/runStatus.js +46 -0
  359. package/dist/remediate/state/runStatus.js.map +1 -0
  360. package/dist/remediate/state/store.d.ts +52 -2
  361. package/dist/remediate/state/store.d.ts.map +1 -1
  362. package/dist/remediate/state/store.js +124 -21
  363. package/dist/remediate/state/store.js.map +1 -1
  364. package/dist/remediate/state/types.d.ts +83 -13
  365. package/dist/remediate/state/types.d.ts.map +1 -1
  366. package/dist/remediate/steps/contractPipeline.d.ts +65 -1
  367. package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
  368. package/dist/remediate/steps/contractPipeline.js +302 -85
  369. package/dist/remediate/steps/contractPipeline.js.map +1 -1
  370. package/dist/remediate/steps/contractPipelinePrompts.d.ts.map +1 -1
  371. package/dist/remediate/steps/contractPipelinePrompts.js +58 -21
  372. package/dist/remediate/steps/contractPipelinePrompts.js.map +1 -1
  373. package/dist/remediate/steps/dispatch/hostHandoff.d.ts +87 -2
  374. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  375. package/dist/remediate/steps/dispatch/hostHandoff.js +344 -44
  376. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  377. package/dist/remediate/steps/finalGate.d.ts +109 -5
  378. package/dist/remediate/steps/finalGate.d.ts.map +1 -1
  379. package/dist/remediate/steps/finalGate.js +135 -27
  380. package/dist/remediate/steps/finalGate.js.map +1 -1
  381. package/dist/remediate/steps/gateCommands.d.ts +167 -0
  382. package/dist/remediate/steps/gateCommands.d.ts.map +1 -1
  383. package/dist/remediate/steps/gateCommands.js +428 -1
  384. package/dist/remediate/steps/gateCommands.js.map +1 -1
  385. package/dist/remediate/steps/intakeResolver.d.ts +2 -13
  386. package/dist/remediate/steps/intakeResolver.d.ts.map +1 -1
  387. package/dist/remediate/steps/intakeResolver.js +22 -4
  388. package/dist/remediate/steps/intakeResolver.js.map +1 -1
  389. package/dist/remediate/steps/nextStep.d.ts +44 -40
  390. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  391. package/dist/remediate/steps/nextStep.js +501 -106
  392. package/dist/remediate/steps/nextStep.js.map +1 -1
  393. package/dist/remediate/steps/stepWriter.d.ts +1 -1
  394. package/dist/remediate/steps/stepWriter.d.ts.map +1 -1
  395. package/dist/remediate/steps/stepWriter.js +1 -0
  396. package/dist/remediate/steps/stepWriter.js.map +1 -1
  397. package/dist/remediate/steps/types.d.ts +32 -1
  398. package/dist/remediate/steps/types.d.ts.map +1 -1
  399. package/dist/remediate/steps/types.js +1 -0
  400. package/dist/remediate/steps/types.js.map +1 -1
  401. package/dist/remediate/types/options.d.ts +8 -0
  402. package/dist/remediate/types/options.d.ts.map +1 -1
  403. package/dist/remediate/utils/fileIntegrity.d.ts +8 -0
  404. package/dist/remediate/utils/fileIntegrity.d.ts.map +1 -1
  405. package/dist/remediate/utils/fileIntegrity.js +12 -1
  406. package/dist/remediate/utils/fileIntegrity.js.map +1 -1
  407. package/dist/remediate/validation/artifacts.d.ts +1 -1
  408. package/dist/remediate/validation/artifacts.d.ts.map +1 -1
  409. package/dist/remediate/validation/artifacts.js +19 -2
  410. package/dist/remediate/validation/artifacts.js.map +1 -1
  411. package/dist/remediate/validation/contractPipeline.d.ts.map +1 -1
  412. package/dist/remediate/validation/contractPipeline.js +26 -39
  413. package/dist/remediate/validation/contractPipeline.js.map +1 -1
  414. package/dist/remediate/validation/contractPipelineGates.d.ts +18 -1
  415. package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -1
  416. package/dist/remediate/validation/contractPipelineGates.js +33 -5
  417. package/dist/remediate/validation/contractPipelineGates.js.map +1 -1
  418. package/dist/shared/analyzers/acquisitionEngine.d.ts +83 -5
  419. package/dist/shared/analyzers/acquisitionEngine.d.ts.map +1 -1
  420. package/dist/shared/analyzers/acquisitionEngine.js +46 -14
  421. package/dist/shared/analyzers/acquisitionEngine.js.map +1 -1
  422. package/dist/shared/analyzers/binaryAcquisition.d.ts +35 -2
  423. package/dist/shared/analyzers/binaryAcquisition.d.ts.map +1 -1
  424. package/dist/shared/analyzers/binaryAcquisition.js +5 -5
  425. package/dist/shared/analyzers/binaryAcquisition.js.map +1 -1
  426. package/dist/shared/analyzers/candidates.d.ts.map +1 -1
  427. package/dist/shared/analyzers/candidates.js +1 -0
  428. package/dist/shared/analyzers/candidates.js.map +1 -1
  429. package/dist/shared/analyzers/clippy.d.ts +9 -1
  430. package/dist/shared/analyzers/clippy.d.ts.map +1 -1
  431. package/dist/shared/analyzers/clippy.js +10 -2
  432. package/dist/shared/analyzers/clippy.js.map +1 -1
  433. package/dist/shared/analyzers/normalizeExternal.d.ts.map +1 -1
  434. package/dist/shared/analyzers/normalizeExternal.js +1 -0
  435. package/dist/shared/analyzers/normalizeExternal.js.map +1 -1
  436. package/dist/shared/analyzers/rubocop.d.ts +7 -1
  437. package/dist/shared/analyzers/rubocop.d.ts.map +1 -1
  438. package/dist/shared/analyzers/rubocop.js +8 -2
  439. package/dist/shared/analyzers/rubocop.js.map +1 -1
  440. package/dist/shared/analyzers/types.d.ts +24 -24
  441. package/dist/shared/analyzers/types.d.ts.map +1 -1
  442. package/dist/shared/analyzers/types.js +15 -0
  443. package/dist/shared/analyzers/types.js.map +1 -1
  444. package/dist/shared/artifactFreshness.d.ts.map +1 -1
  445. package/dist/shared/artifactFreshness.js +42 -7
  446. package/dist/shared/artifactFreshness.js.map +1 -1
  447. package/dist/shared/chunkByBudget.d.ts.map +1 -1
  448. package/dist/shared/chunkByBudget.js.map +1 -1
  449. package/dist/shared/continuityScore.d.ts.map +1 -1
  450. package/dist/shared/continuityScore.js +12 -4
  451. package/dist/shared/continuityScore.js.map +1 -1
  452. package/dist/shared/decompose/charterClarification.d.ts +49 -45
  453. package/dist/shared/decompose/charterClarification.d.ts.map +1 -1
  454. package/dist/shared/decompose/charterClarification.js +50 -57
  455. package/dist/shared/decompose/charterClarification.js.map +1 -1
  456. package/dist/shared/decompose/charterExtraction.d.ts +616 -342
  457. package/dist/shared/decompose/charterExtraction.d.ts.map +1 -1
  458. package/dist/shared/decompose/charterExtraction.js +590 -488
  459. package/dist/shared/decompose/charterExtraction.js.map +1 -1
  460. package/dist/shared/decompose/contentCoherence.d.ts +36 -2
  461. package/dist/shared/decompose/contentCoherence.d.ts.map +1 -1
  462. package/dist/shared/decompose/contentCoherence.js +45 -5
  463. package/dist/shared/decompose/contentCoherence.js.map +1 -1
  464. package/dist/shared/decompose/modularity.d.ts +98 -1
  465. package/dist/shared/decompose/modularity.d.ts.map +1 -1
  466. package/dist/shared/decompose/modularity.js +89 -8
  467. package/dist/shared/decompose/modularity.js.map +1 -1
  468. package/dist/shared/decompose/systemicChallenge.d.ts +111 -0
  469. package/dist/shared/decompose/systemicChallenge.d.ts.map +1 -1
  470. package/dist/shared/decompose/systemicChallenge.js +28 -0
  471. package/dist/shared/decompose/systemicChallenge.js.map +1 -1
  472. package/dist/shared/engine/obligationEngine.d.ts +2 -2
  473. package/dist/shared/engine/obligationEngine.d.ts.map +1 -1
  474. package/dist/shared/engine/obligationEngine.js +8 -2
  475. package/dist/shared/engine/obligationEngine.js.map +1 -1
  476. package/dist/shared/findingSimilarity.d.ts +8 -0
  477. package/dist/shared/findingSimilarity.d.ts.map +1 -1
  478. package/dist/shared/findingSimilarity.js +10 -3
  479. package/dist/shared/findingSimilarity.js.map +1 -1
  480. package/dist/shared/findings/dedupe.d.ts +15 -0
  481. package/dist/shared/findings/dedupe.d.ts.map +1 -1
  482. package/dist/shared/findings/dedupe.js +137 -1
  483. package/dist/shared/findings/dedupe.js.map +1 -1
  484. package/dist/shared/friction/frictionRecord.d.ts.map +1 -1
  485. package/dist/shared/friction/frictionRecord.js +14 -1
  486. package/dist/shared/friction/frictionRecord.js.map +1 -1
  487. package/dist/shared/friction/triage.d.ts +4 -0
  488. package/dist/shared/friction/triage.d.ts.map +1 -1
  489. package/dist/shared/friction/triage.js +41 -29
  490. package/dist/shared/friction/triage.js.map +1 -1
  491. package/dist/shared/git.d.ts +14 -0
  492. package/dist/shared/git.d.ts.map +1 -1
  493. package/dist/shared/git.js +22 -0
  494. package/dist/shared/git.js.map +1 -1
  495. package/dist/shared/index.d.ts +42 -38
  496. package/dist/shared/index.d.ts.map +1 -1
  497. package/dist/shared/index.js +35 -23
  498. package/dist/shared/index.js.map +1 -1
  499. package/dist/shared/intent/clauseBoundaries.d.ts +75 -0
  500. package/dist/shared/intent/clauseBoundaries.d.ts.map +1 -0
  501. package/dist/shared/intent/clauseBoundaries.js +134 -0
  502. package/dist/shared/intent/clauseBoundaries.js.map +1 -0
  503. package/dist/shared/intent/clauseInterpreter.d.ts +11 -5
  504. package/dist/shared/intent/clauseInterpreter.d.ts.map +1 -1
  505. package/dist/shared/intent/clauseInterpreter.js +16 -41
  506. package/dist/shared/intent/clauseInterpreter.js.map +1 -1
  507. package/dist/shared/intent/freeFormIntentInterpreter.d.ts +11 -0
  508. package/dist/shared/intent/freeFormIntentInterpreter.d.ts.map +1 -1
  509. package/dist/shared/intent/freeFormIntentInterpreter.js +31 -17
  510. package/dist/shared/intent/freeFormIntentInterpreter.js.map +1 -1
  511. package/dist/shared/io/fileLock.d.ts.map +1 -1
  512. package/dist/shared/io/fileLock.js +18 -6
  513. package/dist/shared/io/fileLock.js.map +1 -1
  514. package/dist/shared/io/frictionCapture.d.ts +25 -5
  515. package/dist/shared/io/frictionCapture.d.ts.map +1 -1
  516. package/dist/shared/io/frictionCapture.js +30 -9
  517. package/dist/shared/io/frictionCapture.js.map +1 -1
  518. package/dist/shared/io/schemaVersion.d.ts +4 -3
  519. package/dist/shared/io/schemaVersion.d.ts.map +1 -1
  520. package/dist/shared/io/schemaVersion.js +27 -4
  521. package/dist/shared/io/schemaVersion.js.map +1 -1
  522. package/dist/shared/io/stepContractWriter.d.ts +38 -4
  523. package/dist/shared/io/stepContractWriter.d.ts.map +1 -1
  524. package/dist/shared/io/stepContractWriter.js +59 -1
  525. package/dist/shared/io/stepContractWriter.js.map +1 -1
  526. package/dist/shared/loopCorePaths.d.ts.map +1 -1
  527. package/dist/shared/loopCorePaths.js +8 -0
  528. package/dist/shared/loopCorePaths.js.map +1 -1
  529. package/dist/shared/opencodePermissions.d.ts +27 -3
  530. package/dist/shared/opencodePermissions.d.ts.map +1 -1
  531. package/dist/shared/opencodePermissions.js +77 -26
  532. package/dist/shared/opencodePermissions.js.map +1 -1
  533. package/dist/shared/prompts.d.ts +12 -1
  534. package/dist/shared/prompts.d.ts.map +1 -1
  535. package/dist/shared/prompts.js +11 -1
  536. package/dist/shared/prompts.js.map +1 -1
  537. package/dist/shared/reReview/projectionDiff.d.ts +13 -0
  538. package/dist/shared/reReview/projectionDiff.d.ts.map +1 -1
  539. package/dist/shared/reReview/projectionDiff.js +1 -1
  540. package/dist/shared/reReview/projectionDiff.js.map +1 -1
  541. package/dist/shared/reporting/findingDisplay.d.ts +7 -0
  542. package/dist/shared/reporting/findingDisplay.d.ts.map +1 -1
  543. package/dist/shared/reporting/findingDisplay.js +8 -1
  544. package/dist/shared/reporting/findingDisplay.js.map +1 -1
  545. package/dist/shared/steps/stepEmissionScaffold.d.ts +15 -3
  546. package/dist/shared/steps/stepEmissionScaffold.d.ts.map +1 -1
  547. package/dist/shared/steps/stepEmissionScaffold.js +8 -6
  548. package/dist/shared/steps/stepEmissionScaffold.js.map +1 -1
  549. package/dist/shared/submission/hostHandoffCore.d.ts +37 -12
  550. package/dist/shared/submission/hostHandoffCore.d.ts.map +1 -1
  551. package/dist/shared/submission/hostHandoffCore.js +81 -18
  552. package/dist/shared/submission/hostHandoffCore.js.map +1 -1
  553. package/dist/shared/submission/hostResultOutcomes.d.ts +70 -1
  554. package/dist/shared/submission/hostResultOutcomes.d.ts.map +1 -1
  555. package/dist/shared/submission/hostResultOutcomes.js +66 -1
  556. package/dist/shared/submission/hostResultOutcomes.js.map +1 -1
  557. package/dist/shared/submission/submissionLedger.d.ts +86 -1
  558. package/dist/shared/submission/submissionLedger.d.ts.map +1 -1
  559. package/dist/shared/submission/submissionLedger.js +108 -0
  560. package/dist/shared/submission/submissionLedger.js.map +1 -1
  561. package/dist/shared/submission/submissionScan.d.ts.map +1 -1
  562. package/dist/shared/submission/submissionScan.js +1 -0
  563. package/dist/shared/submission/submissionScan.js.map +1 -1
  564. package/dist/shared/tooling/analyzerDeps.d.ts +14 -0
  565. package/dist/shared/tooling/analyzerDeps.d.ts.map +1 -1
  566. package/dist/shared/tooling/analyzerDeps.js +23 -0
  567. package/dist/shared/tooling/analyzerDeps.js.map +1 -1
  568. package/dist/shared/tooling/commandShape.d.ts +35 -1
  569. package/dist/shared/tooling/commandShape.d.ts.map +1 -1
  570. package/dist/shared/tooling/commandShape.js +66 -4
  571. package/dist/shared/tooling/commandShape.js.map +1 -1
  572. package/dist/shared/tooling/exec.d.ts +62 -4
  573. package/dist/shared/tooling/exec.d.ts.map +1 -1
  574. package/dist/shared/tooling/exec.js +127 -8
  575. package/dist/shared/tooling/exec.js.map +1 -1
  576. package/dist/shared/types/charter.d.ts +674 -156
  577. package/dist/shared/types/charter.d.ts.map +1 -1
  578. package/dist/shared/types/charter.js +172 -118
  579. package/dist/shared/types/charter.js.map +1 -1
  580. package/dist/shared/types/closingActions.d.ts +25 -0
  581. package/dist/shared/types/closingActions.d.ts.map +1 -1
  582. package/dist/shared/types/closingActions.js +26 -0
  583. package/dist/shared/types/closingActions.js.map +1 -1
  584. package/dist/shared/types/contractPipeline/obligations.d.ts +63 -2
  585. package/dist/shared/types/contractPipeline/obligations.d.ts.map +1 -1
  586. package/dist/shared/types/contractPipeline/obligations.js +51 -0
  587. package/dist/shared/types/contractPipeline/obligations.js.map +1 -1
  588. package/dist/shared/types/contractPipeline.d.ts +1 -0
  589. package/dist/shared/types/contractPipeline.d.ts.map +1 -1
  590. package/dist/shared/types/contractPipeline.js +1 -0
  591. package/dist/shared/types/contractPipeline.js.map +1 -1
  592. package/dist/shared/types/contractPropertyShapes.d.ts +34 -0
  593. package/dist/shared/types/contractPropertyShapes.d.ts.map +1 -0
  594. package/dist/shared/types/contractPropertyShapes.js +255 -0
  595. package/dist/shared/types/contractPropertyShapes.js.map +1 -0
  596. package/dist/shared/types/finding.d.ts +376 -18
  597. package/dist/shared/types/finding.d.ts.map +1 -1
  598. package/dist/shared/types/finding.js +111 -0
  599. package/dist/shared/types/finding.js.map +1 -1
  600. package/dist/shared/types/intentCheckpoint.d.ts +214 -2
  601. package/dist/shared/types/intentCheckpoint.d.ts.map +1 -1
  602. package/dist/shared/types/intentCheckpoint.js +273 -0
  603. package/dist/shared/types/intentCheckpoint.js.map +1 -1
  604. package/dist/shared/types/intentInterpretation.d.ts +1 -1
  605. package/dist/shared/types/intentInterpretation.js +1 -1
  606. package/dist/shared/types/remediationOutcome.d.ts +294 -30
  607. package/dist/shared/types/remediationOutcome.d.ts.map +1 -1
  608. package/dist/shared/types/remediationOutcome.js +96 -7
  609. package/dist/shared/types/remediationOutcome.js.map +1 -1
  610. package/dist/shared/types/stepContract.d.ts +47 -0
  611. package/dist/shared/types/stepContract.d.ts.map +1 -1
  612. package/dist/shared/types/stepContract.js +113 -0
  613. package/dist/shared/types/stepContract.js.map +1 -1
  614. package/dist/shared/validation/charterGate.d.ts +13 -28
  615. package/dist/shared/validation/charterGate.d.ts.map +1 -1
  616. package/dist/shared/validation/charterGate.js +13 -35
  617. package/dist/shared/validation/charterGate.js.map +1 -1
  618. package/dist/shared/validation/contractConstructionSites.d.ts +116 -0
  619. package/dist/shared/validation/contractConstructionSites.d.ts.map +1 -0
  620. package/dist/shared/validation/contractConstructionSites.js +277 -0
  621. package/dist/shared/validation/contractConstructionSites.js.map +1 -0
  622. package/dist/shared/validation/designFindingGrounding.d.ts +33 -4
  623. package/dist/shared/validation/designFindingGrounding.d.ts.map +1 -1
  624. package/dist/shared/validation/designFindingGrounding.js +40 -6
  625. package/dist/shared/validation/designFindingGrounding.js.map +1 -1
  626. package/dist/shared/validation/findingGrounding.d.ts.map +1 -1
  627. package/dist/shared/validation/findingGrounding.js +11 -1
  628. package/dist/shared/validation/findingGrounding.js.map +1 -1
  629. package/dist/shared/validation/findingsReport.d.ts.map +1 -1
  630. package/dist/shared/validation/findingsReport.js +5 -0
  631. package/dist/shared/validation/findingsReport.js.map +1 -1
  632. package/docs/audit-pkg/contracts.md +8 -2
  633. package/opencode.json +29 -29
  634. package/package.json +16 -3
  635. package/schemas/audit-code-v1alpha1.schema.json +0 -4
  636. package/scripts/audit/postinstall.mjs +81 -96
  637. package/scripts/remediate/postinstall.mjs +43 -83
  638. package/scripts/shared/host-asset-plan.mjs +176 -0
  639. package/scripts/shared/install-host-assets.mjs +44 -1
  640. package/scripts/shared/primitives.mjs +89 -0
  641. package/skills/audit-code/SKILL.md +4 -4
  642. package/skills/audit-code/audit-code.prompt.md +14 -10
  643. package/skills/remediate-code/SKILL.md +9 -5
  644. package/skills/remediate-code/remediate-code.prompt.md +11 -4
  645. package/wrapper/audit-code-wrapper-build.mjs +6 -3
  646. package/dist/audit/cli/charterDeltaPrompt.d.ts +0 -18
  647. package/dist/audit/cli/charterDeltaPrompt.d.ts.map +0 -1
  648. package/dist/audit/cli/charterDeltaPrompt.js +0 -150
  649. package/dist/audit/cli/charterDeltaPrompt.js.map +0 -1
  650. package/dist/audit/orchestrator/charterDeltaExecutor.d.ts +0 -24
  651. package/dist/audit/orchestrator/charterDeltaExecutor.d.ts.map +0 -1
  652. package/dist/audit/orchestrator/charterDeltaExecutor.js +0 -128
  653. package/dist/audit/orchestrator/charterDeltaExecutor.js.map +0 -1
  654. package/dist/audit/supervisor/runLedger.d.ts +0 -3
  655. package/dist/audit/supervisor/runLedger.d.ts.map +0 -1
  656. package/dist/audit/supervisor/runLedger.js +0 -69
  657. package/dist/audit/supervisor/runLedger.js.map +0 -1
  658. package/dist/shared/types/executionRecord.d.ts +0 -58
  659. package/dist/shared/types/executionRecord.d.ts.map +0 -1
  660. package/dist/shared/types/executionRecord.js +0 -26
  661. package/dist/shared/types/executionRecord.js.map +0 -1
  662. package/dist/shared/types/runLedger.d.ts +0 -17
  663. package/dist/shared/types/runLedger.d.ts.map +0 -1
  664. package/dist/shared/types/runLedger.js +0 -7
  665. package/dist/shared/types/runLedger.js.map +0 -1
@@ -1,21 +1,25 @@
1
+ // sites-pinned: tests/remediate/friction-capture-closeout.test.ts, tests/remediate/next-step-lifecycle.test.ts, tests/remediate/next-step-pipeline-dispatch.test.ts, tests/remediate/next-step-outcomes-contract.test.ts, tests/remediate/integration-pipeline.test.ts, tests/remediate/outcomes-roundtrip.test.ts, tests/remediate/phase-close.test.ts, tests/remediate/grounding.test.ts
2
+ // (the free-form branch's write
3
+ // scope is normalized — a backslash-spelled citation no longer wedges prepare)
4
+ import { AUDIT_TOOLS_DIRNAME } from "../../shared/io/auditToolsPaths.js";
1
5
  import { loadRemediateSessionConfig } from "./sessionConfigLoad.js";
2
6
  import { existsSync, readFileSync, statSync } from "node:fs";
3
7
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
4
8
  import { dirname, join, resolve } from "node:path";
5
9
  import { StateStore } from "../state/store.js";
6
10
  // IO / validation / rendering helpers
7
- import { discardOnSchemaVersionMismatch, readOptionalJsonFile, stagedAndUntracked, writeJsonFile, writeTextFile, buildAuditDeliverablePair, formatValidationIssues, isRecord, withFsRetry, RunLogger, coerceJsonObjectArg, renderPromptCommand, headCommit, projectAuditFindingsReportSubset,
11
+ import { discardOnSchemaVersionMismatch, readOptionalJsonFile, stagedAndUntracked, writeJsonFile, writeTextFile, buildAuditDeliverablePair, formatValidationIssues, isMissingObservation, isRecord, withFsRetry, RunLogger, coerceJsonObjectArg, renderPromptCommand, headCommit, projectAuditFindingsReportSubset,
8
12
  // obligation engine + intent
9
13
  interpretFreeFormIntent, interpretIntent, unresolvedFromClauses, advance, describeStoppedFold, decideFrictionTriage, buildFrictionTriageBlock, linkFrictionRunIds,
10
14
  // domain constants
11
- LENSES, SEVERITIES, CLOSING_ACTIONS, detectProjectFacts, isClosingAction, neutralProjectFacts, } from "audit-tools/shared";
15
+ LENSES, SEVERITIES, CLOSING_ACTIONS, SKIP_WRITE, invalidateStepContracts, detectProjectFacts, isClosingAction, neutralProjectFacts, repoRelativePath, } from "audit-tools/shared";
12
16
  import { applyPlanPipeline, buildCoverageLedger } from "../phases/plan.js";
13
17
  import { groundExtractedFindings, } from "../phases/grounding.js";
14
18
  import { runTriagePhase } from "../phases/triage.js";
15
19
  import { runClosePhase } from "../phases/close.js";
16
20
  import { validateRemediationPlan } from "../validation/remediationState.js";
17
21
  import { readExtractedPlanIfPresent, } from "./dispatch/marshal.js";
18
- import { ingestRemediationHostResults, hostDependencyLevels, permanentlyDeadPendingBlocks, precomputeRecoveryTestVerdicts, prepareRemediationHostHandoff, } from "./dispatch/hostHandoff.js";
22
+ import { ingestRemediationHostResults, hostDependencyLevels, permanentlyDeadPendingBlocks, precomputeRecoveryTestVerdicts, prepareRemediationHostHandoff, workloadBindingIdentity, } from "./dispatch/hostHandoff.js";
19
23
  import { FileLockTimeoutError, withFileLock, } from "../../shared/io/fileLock.js";
20
24
  import { AUDIT_FINDINGS_FILENAME, AUDIT_REPORT_FILENAME, auditArtifactsDir, auditFindingsPath, auditReportPath, promotedAuditFindingsPath, promotedAuditReportPath, remediationArtifactsDir, } from "../../shared/io/auditToolsPaths.js";
21
25
  import { callerWorkingDirectory, discoverRepoRoot, resolveRepoRoot, } from "../../shared/io/repoRoot.js";
@@ -25,7 +29,9 @@ import { deduplicateCrossLensFindings, fixupBlocksAfterDedup, } from "../dedup/c
25
29
  import { checkAffectedFileIntegrity } from "../utils/fileIntegrity.js";
26
30
  import { applyIntentOrdering } from "../intent/intentOrdering.js";
27
31
  import { resolveIntakeStep } from "./intakeResolver.js";
28
- import { runToolOwnedFinalGate, writeFinalGateRedRecord, writeFinalGateOutcomeRecord, } from "./finalGate.js";
32
+ import { carriesGateVerdict } from "../../shared/types/remediationOutcome.js";
33
+ import { RUNTIME_RESIDUAL_DECLARATION, readFinalGateVerdict, runToolOwnedFinalGate, writeFinalGateRedRecord, writeFinalGateOutcomeRecord, writeFinalGateVerdict, } from "./finalGate.js";
34
+ import { renderGateAttribution, worktreeContentId, } from "./gateCommands.js";
29
35
  import { buildNextContractPipelineStep, shouldEnterContractPipeline, writePathASeedFromFindings, normalizeBlockTouchedFiles, checkWriteScopePathsAgainstTrackedTree, } from "./contractPipeline.js";
30
36
  import { compareCodeUnits } from "../../shared/compareCodeUnits.js";
31
37
  import { contractArtifactExists, contractPipelineDir, } from "../contractPipeline/artifactStore.js";
@@ -35,6 +41,7 @@ import { runFindingFilterPass } from "../findingFilter.js";
35
41
  import { droppedFindingsRecordPath, renderDroppedFindingsRecord, } from "../droppedFindingsRecord.js";
36
42
  import { intakePaths, isIntakeReady, manifestIsInputBound, readIntakeArtifacts, readProjectFacts, writeProjectFacts, resolveManifestSources, } from "../intake.js";
37
43
  import { ensureIntakeRiskSignal, readIntakeRiskSignal, writeIntakeRiskSignal, escalateRiskSignal, findingRiskEvidence, distinctAffectedFiles, } from "../riskSignal.js";
44
+ import { readIntentCheckpoint, readIntentCheckpointLenient, } from "audit-tools/shared";
38
45
  import { ambiguityReviewPrompt, clarificationPrompt, collectIntakeClarificationsPrompt, collectStartingPointPrompt, extractedPlanDiscardedPrompt, loaderCommand, reviewApprovalPrompt, synthesizeIntakePrompt, triagePrompt, } from "./prompts.js";
39
46
  // Single-sourced prose renders of the canonical lens / severity vocabularies
40
47
  // (`audit-tools/shared` `LENSES` / `SEVERITIES`) for the intent-checkpoint
@@ -74,11 +81,36 @@ function resolveArtifactsDir(root, artifactsDir) {
74
81
  // honored verbatim.
75
82
  return artifactsDir ? resolve(artifactsDir) : remediationArtifactsDir(root);
76
83
  }
84
+ /**
85
+ * The run's friction-record key: the plan id, or `null` when there is no plan.
86
+ *
87
+ * There is DELIBERATELY no fallback key. A fallback ("run") is a path every
88
+ * planless state shares, and `decideFrictionTriage` MATERIALIZES the record it
89
+ * is handed — so a planless caller could MINT a fresh empty record under it,
90
+ * which the close gate then blocks on. That is the 2026-08-24 defect exactly.
91
+ *
92
+ * The key is therefore the plan id or nothing, and a caller handed `null` has
93
+ * no walk to key: the walk ran before the close archived the plan-keyed record,
94
+ * and the plan is where its identity came from.
95
+ */
77
96
  function stateRunId(state) {
78
- // When the plan is absent (fully-green close deleted the state, or complete
79
- // was persisted without a plan), use the stable fallback "run" so the friction
80
- // record path is deterministic across multiple next-step calls on the same run.
81
- return state?.plan?.plan_id ?? "run";
97
+ return state?.plan?.plan_id ?? null;
98
+ }
99
+ /**
100
+ * The run key for a caller holding a LOADED state that must carry a plan id —
101
+ * the host-handoff/ingest paths, whose contracts declare `run_id: string`.
102
+ *
103
+ * It throws rather than inventing a key: an absent plan id there is a
104
+ * reachable-but-unexpected state, and silently falling back would mint a
105
+ * shared path exactly as the fallback key did. Callers that can legitimately
106
+ * hold a planless state use {@link stateRunId} and handle the `null`.
107
+ */
108
+ function requireStateRunId(state) {
109
+ const runId = stateRunId(state);
110
+ if (!runId) {
111
+ throw new Error("remediate: a loaded state with no plan id cannot name a run");
112
+ }
113
+ return runId;
82
114
  }
83
115
  /**
84
116
  * Where an autonomous run's LEFTOVER deliverable pair lands.
@@ -349,14 +381,51 @@ function allItemsTerminal(state) {
349
381
  * return the plan untouched.
350
382
  */
351
383
  async function applyCheckpointIntentOrdering(artifactsDir, plan) {
352
- const checkpoint = await readOptionalJsonFile(join(artifactsDir, "intent_checkpoint.json")).catch(() => undefined);
384
+ // Ordering is an ADVISORY pass: it reorders the plan and nothing depends on
385
+ // it, so an unreadable checkpoint degrades to "no intent" here rather than
386
+ // failing the planning step. (Every other read site is a GATE and lets the
387
+ // throw out — see `readIntentCheckpoint`.)
388
+ const checkpoint = await readIntentCheckpoint(join(artifactsDir, "intent_checkpoint.json")).catch(() => undefined);
353
389
  const freeForm = checkpoint?.free_form_intent;
354
390
  if (typeof freeForm !== "string" || freeForm.trim().length === 0)
355
391
  return plan;
356
392
  const ordered = applyIntentOrdering(plan.findings, plan.blocks, interpretFreeFormIntent(freeForm));
357
393
  return { ...plan, findings: ordered.findings, blocks: ordered.blocks };
358
394
  }
359
- function normalizeExtractedPlan(value, facts) {
395
+ /**
396
+ * The write scope a free-form finding's `affected_files` implies, in the ONE
397
+ * form the block contract accepts.
398
+ *
399
+ * The paths arriving here have been GROUNDED but never normalized: grounding
400
+ * asks whether a path resolves to a real file (`existsSync`), and on Windows
401
+ * `src\a.ts` does — so a Windows-spelled citation survives grounding and, copied
402
+ * verbatim, becomes a `touched_files` entry `assertBlockContract` refuses. The
403
+ * run then wedges at handoff preparation and every retry reproduces the refusal.
404
+ *
405
+ * It normalizes through the SAME shared `repoRelativePath` the handoff boundary
406
+ * resolves declared entries with, so this producer's output is in the form its
407
+ * consumer demands by construction rather than by a second, drifting rule. A
408
+ * path that cannot be contained (`../outside.ts`) is DROPPED rather than
409
+ * resolved: the block contract refuses it later anyway, and dropping it here
410
+ * leaves the finding itself intact — grounding already decided which paths are
411
+ * real, and this decides only how they are SPELLED.
412
+ */
413
+ function normalizedWriteScope(root, finding) {
414
+ const normalized = [];
415
+ for (const affected of finding.affected_files) {
416
+ let path;
417
+ try {
418
+ path = repoRelativePath(root, affected.path, "affected_files[].path");
419
+ }
420
+ catch {
421
+ continue;
422
+ }
423
+ if (path.length > 0 && !normalized.includes(path))
424
+ normalized.push(path);
425
+ }
426
+ return normalized;
427
+ }
428
+ function normalizeExtractedPlan(root, value, facts) {
360
429
  if (!isRecord(value)) {
361
430
  throw new Error("extracted-plan.json must be an object.");
362
431
  }
@@ -390,7 +459,9 @@ function normalizeExtractedPlan(value, facts) {
390
459
  block_id: `B-${String(index + 1).padStart(3, "0")}`,
391
460
  items: [finding.id],
392
461
  parallel_safe: true,
393
- touched_files: finding.affected_files.map((af) => af.path),
462
+ // Normalized, not copied: see normalizedWriteScope — a Windows-spelled
463
+ // citation would otherwise become a write scope the handoff refuses.
464
+ touched_files: normalizedWriteScope(root, finding),
394
465
  }));
395
466
  const dedup = deduplicateCrossLensFindings(findings);
396
467
  const dedupBlocks = fixupBlocksAfterDedup(blocks, dedup.mergeMap);
@@ -447,7 +518,16 @@ function normalizeExtractedPlan(value, facts) {
447
518
  * so membership is the whole check.
448
519
  */
449
520
  async function confirmedClosingPlan(artifactsDir) {
450
- const checkpoint = await readOptionalJsonFile(join(artifactsDir, "intent_checkpoint.json"));
521
+ // LENIENT, for the same reason the gate is: this runs on the state the gate
522
+ // just handled, and its own contract below says an out-of-vocabulary action
523
+ // "cannot reach here". A strict read would turn a case this function already
524
+ // handles by falling back to `none` into a thrown load error instead.
525
+ //
526
+ // This function only USES validated fields, so it takes the plain lenient read
527
+ // and never touches `readIntentCheckpointLenient`'s raw rejections: the value
528
+ // returned is one the schema accepts, and `isClosingAction` / `customCommandOf`
529
+ // are the point-of-use checks on top of it.
530
+ const checkpoint = await readIntentCheckpoint(join(artifactsDir, "intent_checkpoint.json"), { lenient: true });
451
531
  if (!checkpoint || checkpoint.confirmed_by !== "host")
452
532
  return { action: "none" };
453
533
  const chosen = checkpoint.closing_action;
@@ -555,8 +635,8 @@ function carryForwardMatchingItems(previous, replanned) {
555
635
  // A still-pending item carries no work to preserve, so it is re-minted from
556
636
  // the fresh plan rather than carried forward. (This test used to also admit
557
637
  // a pending item that held an `item_spec`; the document phase that produced
558
- // one was dissolved by N-R13 and the field is gone, so the second condition
559
- // could never be true and is not restated here.)
638
+ // one was dissolved and the field is gone, so the second condition could
639
+ // never be true and is not restated here.)
560
640
  if (!previousFinding || !previousItem) {
561
641
  continue;
562
642
  }
@@ -619,6 +699,29 @@ async function forceReplanFromExistingIntake(root, artifactsDir, previous, store
619
699
  await store.saveState(carried);
620
700
  return carried;
621
701
  }
702
+ /**
703
+ * The BLOCKING friction close-out step for a run whose walk is still owed.
704
+ *
705
+ * Emitted from `handleClosing` BEFORE the close touches disk, so the record the
706
+ * host is told to write (`triage.recordPath`) is the plan-keyed one this very
707
+ * decision just materialized — and so the run's identity in that path is the
708
+ * plan id, not a fallback. The step is a `closing`-phase gate: `next-step`
709
+ * re-decides the same walk on the next call, and only a disposed walk lets the
710
+ * close proceed.
711
+ */
712
+ async function buildFrictionWalkStep(root, artifactsDir, state, triage) {
713
+ return writeCurrentStep({
714
+ stepKind: "close_run",
715
+ status: "ready",
716
+ runId: requireStateRunId(state),
717
+ repoRoot: root,
718
+ artifactsDir,
719
+ prompt: `# Remediation Run Friction Triage\n\nComplete the friction close-out walk before the run may close.\n${buildFrictionTriageBlock(triage)}`,
720
+ allowedCommands: [],
721
+ stopCondition: "Complete friction triage (write dispositions and open_observations), then call next-step again.",
722
+ artifactPaths: { friction_record: triage.recordPath },
723
+ });
724
+ }
622
725
  async function presentReportStep(root, artifactsDir, state) {
623
726
  const reportPath = join(dirname(artifactsDir), "remediation-report.md");
624
727
  // Terminal friction-TRIAGE close-out, folded into present_report (single-sourced in
@@ -626,13 +729,39 @@ async function presentReportStep(root, artifactsDir, state) {
626
729
  // event + reflection is disposed AND ≥1 open observation written. Never trivially
627
730
  // satisfied by an empty event set — the host must actively confirm the friction state.
628
731
  //
629
- // When `artifactsDir` was deleted by a fully-green close (close.ts rm -rf on a
630
- // green run), there is nowhere to persist the friction record and no mechanical
631
- // events to triage — skip the triage entirely and go straight to complete.
632
- const artifactsDirExists = existsSync(artifactsDir);
633
- const triage = artifactsDirExists
634
- ? await decideRemediateFrictionCloseout(artifactsDir, state)
635
- : null;
732
+ // NO FRICTION RECORD IS EVER MINTED HERE. The decision was made — and the
733
+ // record, under the run's plan-keyed path, was walked — before the close
734
+ // archived it: `handleClosing` consults `decideRemediateFrictionCloseout`
735
+ // against the LIVE state and short-circuits the close until the walk is
736
+ // disposed. So ON THE GREEN PATH — the close ran to `complete`, archived the
737
+ // run and removed the artifacts dir — the walk was already completed when the
738
+ // close started, the plan-keyed record left with the other deliverables, and
739
+ // all that is left is to RENDER the already-recorded walk for the host.
740
+ //
741
+ // NOT-GREEN IS THE OTHER HALF, and it is not "mint nothing": a close that
742
+ // returned a non-`complete` state PRESERVES the artifacts dir, so the record
743
+ // this step decides remains where the run wrote it — the caller reaches here
744
+ // with the saved state still carrying its plan id, `decideFrictionTriage`
745
+ // materializes (or re-reads) that same plan-keyed file, and the walk is
746
+ // rendered from the record that is still in place.
747
+ //
748
+ // It is decided — and so materialized — ONLY when the state names a run. The
749
+ // guard is the plan id, not the artifacts dir: the dir is not evidence of
750
+ // anything here, since `decideNextStepLoop` mkdirs it unconditionally on entry,
751
+ // `RunLogger.event` mkdirs it again for `run.log.jsonl`, and `writeJsonFile`
752
+ // mkdirs any parent it is handed. So a dir-existence test is true on every
753
+ // path, including a run whose state the close deleted. Guarding on the dir was
754
+ // the 2026-08-24 defect: the decider ran with a null state, took a fallback
755
+ // key, and because `decideFrictionTriage` MATERIALIZES the record it is given,
756
+ // minted a fresh EMPTY record inside the directory the close had just deleted —
757
+ // re-blocking the run on the record it had created. `stateRunId` now answers
758
+ // `null` for a planless state and this call therefore decides nothing.
759
+ //
760
+ // A `complete` state reaching here is a run that never ran the close walk (a
761
+ // re-delivery of an already-complete run, whose plan the state still carries),
762
+ // so the walk is genuinely still owed and deciding it here is correct — it
763
+ // renders as the blocking step. Only a planless state renders nothing.
764
+ const triage = await decideRemediateFrictionCloseout(artifactsDir, state);
636
765
  const frictionBlock = triage ? buildFrictionTriageBlock(triage) : "";
637
766
  const isBlocked = triage?.action === "dispose";
638
767
  return writeCurrentStep({
@@ -683,32 +812,32 @@ function currentHostBoundaryState(state) {
683
812
  *
684
813
  * So:
685
814
  *
686
- * - **Phase 1, UNLOCKED.** Snapshot the state, capture HEAD, and run every
687
- * distinct required-test command exactly once
688
- * (`precomputeRecoveryTestVerdicts`). HEAD is captured BEFORE the spawns, not
689
- * after, because a host-authored command that MOVES HEAD would otherwise
690
- * produce verdicts of mixed provenance and go undetected. (The guard compares
691
- * commit shas: it sees HEAD movement, not worktree dirt — a command that only
692
- * dirties files is invisible to it, which is acceptable because phase 2's
693
- * corroboration is commit-based.)
694
- * - **Phase 2, LOCKED.** Re-read HEAD and abort the whole recovery if it moved
695
- * (`tree_moved_between_phases`) — the phase-1 verdicts would describe a tree
696
- * that no longer exists, and nothing is accepted or appended. Otherwise ingest
697
- * with the pre-computed verdicts, which the ingest only READS: in recovery
698
- * mode it never spawns, and a command missing from the table fails closed.
815
+ * - **Phase 1, UNLOCKED.** Snapshot the state, capture HEAD and the workload
816
+ * binding, and run every distinct required-test command exactly once
817
+ * (`precomputeRecoveryTestVerdicts`). Both identities are captured BEFORE the
818
+ * spawns, not after, because a host-authored command that MOVES HEAD would
819
+ * otherwise produce verdicts of mixed provenance and go undetected. (The HEAD
820
+ * guard compares commit shas: it sees HEAD movement, not worktree dirt — a
821
+ * command that only dirties files is invisible to it, which is acceptable
822
+ * because phase 2's corroboration is commit-based.)
823
+ * - **Phase 2, LOCKED.** Re-read both identities and abort the whole recovery if
824
+ * either moved — `tree_moved_between_phases` for HEAD,
825
+ * `state_moved_between_phases` for the binding — because the phase-1 verdicts
826
+ * would describe a tree or a frontier that no longer exists, and nothing is
827
+ * accepted or appended. Otherwise ingest with the pre-computed verdicts, which
828
+ * the ingest only READS: in recovery mode it never spawns, and a command
829
+ * missing from the table fails closed.
699
830
  *
700
831
  * What remains inside the lock is git plumbing (ancestry, ref scan, diff-tree),
701
832
  * the ledger append, and the state write — sub-second work, comfortably inside
702
- * heartbeat coverage. The HEAD-unchanged guard closes the gap the phase split
703
- * opens; the operational protocol is still one writer at a time, now enforced by
704
- * a lock that cannot be stolen mid-hold instead of by convention.
833
+ * heartbeat coverage. The two unchanged-identity guards close the gap the phase
834
+ * split opens; the operational protocol is still one writer at a time, now
835
+ * enforced by a lock that cannot be stolen mid-hold instead of by convention.
705
836
  *
706
- * One accepted cost: `StateStore.mutate` always writes, so a recovery run that
707
- * changes nothing rewrites `state.json` with identical content. Expressing a
708
- * true no-op means plumbing the locked store's `SKIP_WRITE` sentinel through
709
- * `StateStore.mutate`, which is a change to the store's API rather than to this
710
- * verb. The `state_changed` flag on the returned summary stays authoritative
711
- * for callers either way.
837
+ * A recovery that changes nothing writes nothing: phase 2 returns the locked
838
+ * store's `SKIP_WRITE` sentinel, which `StateStore.mutate` now honors, so the
839
+ * retry loop of a genuinely-empty recovery no longer replaces `state.json` with
840
+ * byte-identical content on every pass.
712
841
  */
713
842
  export async function recoverIngestHostResults(options) {
714
843
  const root = resolveRoot(options.root);
@@ -720,6 +849,7 @@ export async function recoverIngestHostResults(options) {
720
849
  throw new Error(`No remediation state at ${artifactsDir} — there is nothing to ingest.`);
721
850
  }
722
851
  const headBeforeTests = await headCommit(root);
852
+ const bindingBeforeTests = workloadBindingIdentity(currentHostBoundaryState(snapshot));
723
853
  const requiredTestVerdicts = await precomputeRecoveryTestVerdicts({
724
854
  root,
725
855
  artifactsDir,
@@ -740,23 +870,50 @@ export async function recoverIngestHostResults(options) {
740
870
  throw new Error(`No remediation state at ${artifactsDir} — there is nothing to ingest.`);
741
871
  }
742
872
  const headNow = await headCommit(root);
743
- if (headNow !== headBeforeTests) {
873
+ const bindingNow = workloadBindingIdentity(currentHostBoundaryState(state));
874
+ // TWO identities, because they catch different writers. HEAD moves when the
875
+ // tree does; the workload binding moves when a concurrent state writer
876
+ // settles items or re-mints the workload without committing anything. The
877
+ // verdict table describes the frontier as it was at phase 1, so either
878
+ // change invalidates it — and a stale table is not merely imprecise: the
879
+ // commands it no longer covers read as `required_test_failed`, which
880
+ // attributes a bookkeeping race to the host's work.
881
+ const moved = headNow !== headBeforeTests
882
+ ? "tree"
883
+ : bindingNow !== bindingBeforeTests
884
+ ? "state"
885
+ : null;
886
+ if (moved !== null) {
744
887
  ingested = {
745
888
  accepted_count: 0,
746
889
  completed_work_item_ids: [],
747
890
  pending_work_item_ids: state.host_handoff?.work_item_ids ?? [],
891
+ // This verdict aborts the whole recovery BEFORE any item is read, so
892
+ // there is no per-item observation to report — an empty map is the
893
+ // honest statement of that, not a missing field.
894
+ work_item_outcomes: new Map(),
748
895
  issues: [
749
- {
750
- code: "tree_moved_between_phases",
751
- message: `HEAD moved from ${headBeforeTests ?? "(none)"} to ${headNow ?? "(none)"} ` +
752
- "while the required tests were running, so their verdicts no longer describe " +
753
- "this tree. Nothing was accepted; re-run recover-ingest on a settled tree.",
754
- },
896
+ moved === "tree"
897
+ ? {
898
+ code: "tree_moved_between_phases",
899
+ message: `HEAD moved from ${headBeforeTests ?? "(none)"} to ${headNow ?? "(none)"} ` +
900
+ "while the required tests were running, so their verdicts no longer describe " +
901
+ "this tree. Nothing was accepted; re-run recover-ingest on a settled tree.",
902
+ }
903
+ : {
904
+ code: "state_moved_between_phases",
905
+ message: "the run's workload binding changed while the required tests were running, " +
906
+ "so their verdicts no longer describe the pending frontier. Nothing was " +
907
+ "accepted; re-run recover-ingest once no other writer is advancing this run.",
908
+ },
755
909
  ],
756
910
  state_changed: false,
757
911
  state: currentHostBoundaryState(state),
758
912
  };
759
- return state;
913
+ // The lock was taken to WRITE. Nothing changed, so write nothing: the
914
+ // no-op sentinel is what keeps a settled recovery from replacing
915
+ // state.json with byte-identical content on every retry.
916
+ return SKIP_WRITE;
760
917
  }
761
918
  const outcome = await ingestRemediationHostResults({
762
919
  root,
@@ -769,16 +926,62 @@ export async function recoverIngestHostResults(options) {
769
926
  throw new Error("Remediation state uses a retired dispatch shape and cannot cross the host handoff boundary.");
770
927
  }
771
928
  ingested = outcome;
929
+ // A nothing-to-recover pass returns the sentinel, not the state it read: the
930
+ // mutation is a no-op and must not rewrite the file (see StateStore.mutate).
772
931
  if (!outcome.state_changed)
773
- return state;
774
- const { contract_version: _contractVersion, ...persistableState } = outcome.state;
775
- return persistableState;
932
+ return SKIP_WRITE;
933
+ // No `contract_version` strip. The boundary helper below stamps the version
934
+ // onto the state it hands the host handoff, and this used to peel it back
935
+ // off on the way to disk so `state.json` matched what was written before.
936
+ // The STORE now owns that field end to end — it stamps it on read and the
937
+ // write hook validates it — so peeling it here would persist a state
938
+ // without the identity the store just established, and the next read would
939
+ // have to re-invent it.
940
+ return outcome.state;
776
941
  });
942
+ // The run moved, so the persisted step contract no longer describes it: it
943
+ // names work this ingest just resolved, against a workload binding this ingest
944
+ // may have cleared. Invalidate it — but only when something actually changed,
945
+ // because a no-op recovery must leave the tree byte-identical (which is the
946
+ // same reason the mutation above writes nothing).
947
+ if (ingested.state_changed) {
948
+ await invalidateStepContracts(artifactsDir);
949
+ }
777
950
  return ingested;
778
951
  }
952
+ /**
953
+ * Render the host-facing result status for an ingest, split by outcome.
954
+ *
955
+ * Takes the whole summary rather than just its issues, because the split needs
956
+ * BOTH halves: which items were refused (from the issues) and which landed
957
+ * without a result (from `work_item_outcomes`, where the run's corroborated
958
+ * commit for the item is what separates that case from plain unfinished work).
959
+ */
960
+ function remediationResultDiagnostics(ingested) {
961
+ const describe = (issue) => `- ${issue.work_item_id ? `\`${issue.work_item_id}\`: ` : ""}${issue.message}${issue.result_path ? ` (\`${issue.result_path}\`)` : ""}`;
962
+ const section = (heading, lines) => lines.length === 0 ? "" : `\n${heading}\n\n${lines.join("\n")}\n`;
963
+ const rejected = ingested.issues.filter((issue) => !isMissingObservation(issue));
964
+ const landedWithoutResult = [...ingested.work_item_outcomes]
965
+ .filter(([, outcome]) => outcome === "missing_result_with_commit")
966
+ .map(([id]) => id)
967
+ .sort(compareCodeUnits);
968
+ const notYetWritten = ingested.issues.filter((issue) => isMissingObservation(issue));
969
+ const body = section("## Results already landed, whose result file is missing", landedWithoutResult.map((id) => `- \`${id}\`: this item's edits are IN this repository — a corroborated commit landed ` +
970
+ `for it and its changed files are recorded — but no result file exists at its bound ` +
971
+ `\`result_path\`. This is PARTIAL PROGRESS, not absent work: write the result for the ` +
972
+ `commit that is already there rather than redoing the edit.`)) +
973
+ section("## Result status requiring attention", rejected.map(describe)) +
974
+ section("## Results not yet written", notYetWritten.map(describe));
975
+ if (body === "")
976
+ return "";
977
+ return (body +
978
+ "\nThe workload was restored from its tool-owned digest when necessary. Repair or\n" +
979
+ "complete only the named result files; do not rewrite the workload or its\n" +
980
+ "baseline.\n");
981
+ }
779
982
  async function buildImplementDispatchStep(ctx) {
780
983
  const { root, artifactsDir, state, store, runLogger } = ctx;
781
- const runId = stateRunId(state);
984
+ const runId = requireStateRunId(state);
782
985
  const boundaryState = currentHostBoundaryState(state);
783
986
  const ingested = await ingestRemediationHostResults({
784
987
  root,
@@ -815,9 +1018,10 @@ async function buildImplementDispatchStep(ctx) {
815
1018
  });
816
1019
  }
817
1020
  if (ingested.state_changed) {
818
- const { contract_version: _contractVersion, ...persistableState } = ingested.state;
819
- await store.saveState(persistableState);
820
- return { kind: "transition", state: persistableState };
1021
+ // Same as the recovery verb above: the version is the store's to write,
1022
+ // not a boundary decoration to peel off before persisting.
1023
+ await store.saveState(ingested.state);
1024
+ return { kind: "transition", state: ingested.state };
821
1025
  }
822
1026
  const baselineCommit = await headCommit(root);
823
1027
  if (!baselineCommit) {
@@ -844,23 +1048,21 @@ async function buildImplementDispatchStep(ctx) {
844
1048
  // `FrictionRunLinks`). Each reference is sourced from the envelope that owns it — the
845
1049
  // persisted handoff record for the dispatch run, the step contract's own run id for
846
1050
  // the step — never synthesized from the other.
847
- await linkFrictionRunIds(artifactsDir, stateRunId(state), { step_run_id: runId, dispatch_run_id: handoff.handoff_record.run_id }, "remediate-code");
1051
+ await linkFrictionRunIds(artifactsDir, requireStateRunId(state), { step_run_id: runId, dispatch_run_id: handoff.handoff_record.run_id }, "remediate-code");
848
1052
  // The issues were logged above, before any exit path. What follows is the
849
1053
  // RENDER — a channel that survives exactly as long as the host reads this one
850
1054
  // step, and that is reached only when nothing was accepted.
851
- const resultDiagnostics = ingested.issues.length === 0
852
- ? ""
853
- : `
854
- ## Result status requiring attention
855
-
856
- ${ingested.issues
857
- .map((issue) => `- ${issue.work_item_id ? `\`${issue.work_item_id}\`: ` : ""}${issue.message}${issue.result_path ? ` (\`${issue.result_path}\`)` : ""}`)
858
- .join("\n")}
859
-
860
- The workload was restored from its tool-owned digest when necessary. Repair or
861
- complete only the named result files; do not rewrite the workload or its
862
- baseline.
863
- `;
1055
+ //
1056
+ // THREE STATES, THREE SECTIONS, because they have three different remedies and
1057
+ // a reader must not have to parse prose to tell them apart (the measured
1058
+ // friction: a host parser special-casing "no result file exists"):
1059
+ // rejected — something was written and refused; repair it.
1060
+ // missing + commit — the edits LANDED but no result exists; write the
1061
+ // result FOR THE COMMIT THAT IS ALREADY THERE.
1062
+ // missing, no commit — nothing yet; write it when the work is done.
1063
+ // The classification is on CODES, never message text, so rewording a message
1064
+ // cannot move an item between sections.
1065
+ const diagnostics = remediationResultDiagnostics(ingested);
864
1066
  const nextCommand = loaderCommand("next-step");
865
1067
  return {
866
1068
  kind: "emit",
@@ -881,7 +1083,7 @@ It contains the complete, dependency-safe current frontier. Complete every work
881
1083
  item and write its exact prompt-bound result contract to its \`result_path\`.
882
1084
  The host owns execution choices, grouping, and concurrency; audit-tools performs
883
1085
  no launch, routing, or quota decision. Do not start a later dependency level.
884
- ${resultDiagnostics}
1086
+ ${diagnostics}
885
1087
 
886
1088
  After all completed changes are merged and their result files exist, run:
887
1089
 
@@ -948,9 +1150,18 @@ async function handleComplete(root, artifactsDir, state) {
948
1150
  * event AND every surfaced agent-feedback reflection carries a disposition; an empty
949
1151
  * set (zero events AND zero reflections) is trivially "disposed". Keyed only off
950
1152
  * `(artifactsDir, runId)`; never coupled to any repo's backlog doc.
1153
+ *
1154
+ * A state with NO plan id can name no run, and since the decision MATERIALIZES
1155
+ * the record it keys, guessing a key there would mint one. It returns `null`
1156
+ * instead — "there is no run here to close out", which is the truthful answer
1157
+ * for a state whose plan is gone. Callers that hold the run's plan get a
1158
+ * decision; callers past the run boundary get nothing to render.
951
1159
  */
952
1160
  export async function decideRemediateFrictionCloseout(artifactsDir, state) {
953
- return decideFrictionTriage(artifactsDir, stateRunId(state), "remediate-code");
1161
+ const runId = stateRunId(state);
1162
+ if (!runId)
1163
+ return null;
1164
+ return decideFrictionTriage(artifactsDir, runId, "remediate-code");
954
1165
  }
955
1166
  /**
956
1167
  * Copy an unusable extracted plan somewhere recoverable and PROVE the copy
@@ -1000,6 +1211,7 @@ async function handlePendingExtractedPlan(root, artifactsDir, existing, extracte
1000
1211
  // captured into the artifact dir; before this, the durable tree held no trace
1001
1212
  // that a plan had been destroyed or that findings had been dropped.
1002
1213
  runLogger) {
1214
+ // <!-- comment-symbol-exempt: names deliberately-retired symbols; this block records that history -->
1003
1215
  // The discard-and-re-extract recovery below covers EXACTLY the region whose
1004
1216
  // failures mean the extracted PLAN is unusable: normalization and grounding.
1005
1217
  // It deliberately stops there. Everything after it — sizing, the dirty
@@ -1018,7 +1230,7 @@ runLogger) {
1018
1230
  let mergeMap;
1019
1231
  let grounding;
1020
1232
  try {
1021
- ({ plan, sourceFindings, mergeMap } = normalizeExtractedPlan(extractedPlan,
1233
+ ({ plan, sourceFindings, mergeMap } = normalizeExtractedPlan(root, extractedPlan,
1022
1234
  // Persisted by the confirm step; planning spawns nothing (the
1023
1235
  // backend-independent planning contract), so it never detects here.
1024
1236
  (await readProjectFacts(artifactsDir)) ?? neutralProjectFacts()));
@@ -1553,7 +1765,7 @@ async function handleReadyIntakeContractPipeline(root, artifactsDir, options, ru
1553
1765
  const auditFindings = await readAuditFindingsOnce();
1554
1766
  const originals = extractAuditFindings(auditFindings);
1555
1767
  if (originals.length > 0) {
1556
- const checkpoint = await readOptionalJsonFile(join(artifactsDir, "intent_checkpoint.json"));
1768
+ const checkpoint = await readIntentCheckpoint(join(artifactsDir, "intent_checkpoint.json"));
1557
1769
  const filter = await runFindingFilterPass(originals, {
1558
1770
  root,
1559
1771
  checkpoint: checkpoint ?? undefined,
@@ -2212,8 +2424,8 @@ async function handlePlanning(root, artifactsDir, state, store) {
2212
2424
  if (halt)
2213
2425
  return { kind: "emit", step: halt };
2214
2426
  }
2215
- // Document phase dissolved (N-R13): planning transitions directly to
2216
- // implementing, and the host workload reads finding context directly.
2427
+ // Document phase dissolved: planning transitions directly to implementing,
2428
+ // and the host workload reads finding context directly.
2217
2429
  const implementBlocks = dispatchFrontier(state);
2218
2430
  if (implementBlocks.length > 0) {
2219
2431
  if (state.plan) {
@@ -2331,7 +2543,7 @@ function finalGateDisabledReason(options) {
2331
2543
  * were indistinguishable after the fact.
2332
2544
  */
2333
2545
  async function recordFinalGateOutcome(ctx) {
2334
- const ran = ctx.outcome === "executed";
2546
+ const verdict = carriesGateVerdict(ctx.outcome);
2335
2547
  await writeFinalGateOutcomeRecord(ctx.artifactsDir, {
2336
2548
  scope: ctx.scope,
2337
2549
  outcome: ctx.outcome,
@@ -2346,9 +2558,10 @@ async function recordFinalGateOutcome(ctx) {
2346
2558
  note: `${ctx.gateKey} outcome=${ctx.outcome} ` +
2347
2559
  // "n/a", never "true": a gate that ran nothing has no verdict, and the
2348
2560
  // durable record it is written beside carries `passed: null` for the
2349
- // same reason.
2350
- `passed=${ran ? String(ctx.passed) : "n/a"} ` +
2351
- `commands=${ran ? String(ctx.commandsRun) : "0"}` +
2561
+ // same reason. A `history` outcome DOES carry a verdict — a judge ruled
2562
+ // on this exact tree — so it prints its verdict like an executed one.
2563
+ `passed=${verdict ? String(ctx.passed) : "n/a"} ` +
2564
+ `commands=${verdict ? String(ctx.commandsRun) : "0"}` +
2352
2565
  (ctx.reason === undefined ? "" : ` reason=${ctx.reason}`),
2353
2566
  ...(ctx.durationMs === undefined ? {} : { duration_ms: ctx.durationMs }),
2354
2567
  });
@@ -2372,26 +2585,56 @@ async function recordFinalGateOutcome(ctx) {
2372
2585
  * the captured output, which stays in the artifact where a multi-KB suite log
2373
2586
  * costs nothing.
2374
2587
  *
2375
- * COST OF THE PAUSE, stated in the prompt rather than discovered: there is no
2376
- * cached verdict, so EVERY next-step taken while the suite is red re-runs the
2377
- * whole gate — a full build plus the whole suite, minutes, holding the phase
2378
- * lock throughout. That is the deliberate price of having no counter to strand
2379
- * the run on, and it makes polling expensive: the host should re-run once it has
2380
- * actually fixed something, not on a timer.
2588
+ * COST OF THE PAUSE. The gate's verdict is cached against the TREE CONTENT, so
2589
+ * re-entering a boundary with the tree untouched serves the recorded verdict —
2590
+ * the pause re-emits from cache without spawning a builder or a suite. A green
2591
+ * on a fixed tree, and a re-run on a tree that MOVED, both go to the floor as
2592
+ * before: the cache is an equality check on content, never a counter and never a
2593
+ * reason to skip a tree nobody judged.
2381
2594
  */
2382
2595
  async function emitFinalGateRedStep(ctx) {
2383
2596
  const { root, artifactsDir, state, scope, gate, runLogger } = ctx;
2384
2597
  const failed = gate.results.find((r) => !r.passed);
2385
- const recordPath = await writeFinalGateRedRecord(artifactsDir, scope, failed);
2598
+ const recordPath = await writeFinalGateRedRecord(artifactsDir, scope, failed, {
2599
+ root,
2600
+ state,
2601
+ });
2386
2602
  const failingCommand = failed
2387
2603
  ? `${failed.argv.join(" ")} (exit ${String(failed.exit_code)})`
2388
2604
  : "(the gate reported no failing command)";
2605
+ // Read the attribution back OFF THE RECORD rather than recomputing it: the
2606
+ // record is the durable statement, and a prompt that derived its own answer
2607
+ // from a fresh git read could disagree with the artifact the same step points
2608
+ // at. Absent (the record was written by the no-state path, or attribution
2609
+ // chose not to run) means no verdict is asserted, which is exactly what the
2610
+ // prompt then says.
2611
+ const attribution = (await readOptionalJsonFile(recordPath))?.attribution;
2612
+ const attributionBlock = renderGateAttribution(attribution);
2389
2613
  runLogger.event({
2390
2614
  phase: "next-step",
2391
2615
  kind: "outcome",
2392
2616
  obligation: state.status,
2393
- note: `final_gate_red scope=${scope} command=${failed ? failed.argv.join(" ") : "unknown"}`,
2617
+ note: `final_gate_red scope=${scope} command=${failed ? failed.argv.join(" ") : "unknown"}` +
2618
+ (attribution ? ` attribution=${attribution.verdict}` : ""),
2394
2619
  });
2620
+ // THE BINDING, named in the prompt. The verdict this pause repeats is cached
2621
+ // against the CONTENT of the tree, so an operator who reads "the suite is
2622
+ // still red" and fixes something the run cannot see — or, worse, who assumes
2623
+ // the message will change on its own — is left looping on a red that is being
2624
+ // SERVED, not observed. State the id and state exactly what moves it: any
2625
+ // edit to a non-ignored file outside the run's own artifacts. This is the
2626
+ // same carve-out `worktreeContentId` applies, said in the operator's terms.
2627
+ const bindingBlock = ctx.tree === undefined
2628
+ ? "Binding: this gate re-runs the floor on every arrival here, so this red\n" +
2629
+ "describes the tree as it stands right now."
2630
+ : ctx.tree === null
2631
+ ? "Binding: no tree content id could be taken, so this red is NOT cached —\n" +
2632
+ "the floor will run again on your next next-step whatever you change."
2633
+ : `Binding: this red is bound to tree \`${ctx.tree}\`. Any edit to a file\n` +
2634
+ `outside \`${AUDIT_TOOLS_DIRNAME}/\` — and outside anything git ignores — moves that\n` +
2635
+ "id, which invalidates the cached verdict and makes the next next-step run\n" +
2636
+ "the WHOLE floor again against what you changed. Editing nothing leaves the\n" +
2637
+ "id identical, so the cached red is served back without spawning anything.";
2395
2638
  const nextCommand = loaderCommand("next-step");
2396
2639
  return {
2397
2640
  kind: "emit",
@@ -2420,6 +2663,10 @@ A red here is whole-repo and says nothing about which remediation item caused
2420
2663
  it — it may not be this run's doing at all (a commit landed alongside the run is
2421
2664
  enough). So this is a PAUSE, not a verdict on the work.
2422
2665
 
2666
+ ${attributionBlock}
2667
+
2668
+ ${bindingBlock}
2669
+
2423
2670
  Fix the failing command — or confirm it was already broken independently of this
2424
2671
  run — then run:
2425
2672
 
@@ -2428,10 +2675,11 @@ run — then run:
2428
2675
  The gate re-runs from scratch. The moment it is green the run continues exactly
2429
2676
  where it left off.
2430
2677
 
2431
- Re-run it DELIBERATELY, not on a timer: there is no cached verdict, so every
2432
- next-step taken while the suite is red re-runs the entire gate — a full build
2433
- plus the whole suite, minutes, holding the run's phase lock the whole time.
2434
- Fix something first, then re-run.
2678
+ Re-run it DELIBERATELY, not on a timer. The gate's verdict is cached against the
2679
+ content of the tree, so a re-run with nothing changed serves the recorded verdict
2680
+ without spawning anything — and the moment you fix something the tree moves, the
2681
+ cache misses, and the whole floor (a full build plus the suite, minutes, holding
2682
+ the run's phase lock) runs against your change. Fix something first, then re-run.
2435
2683
  `,
2436
2684
  allowedCommands: [nextCommand],
2437
2685
  stopCondition: "Stop. Make the repository suite green, then re-run next-step to resume the run.",
@@ -2481,19 +2729,87 @@ async function runPhaseBoundaryGate(ctx) {
2481
2729
  });
2482
2730
  return null;
2483
2731
  }
2732
+ // The TREE this verdict will be about. Taken BEFORE the floor runs so the
2733
+ // cached verdict describes the state the floor actually saw; taken ONCE so
2734
+ // the identity written and the identity read back cannot be two derivations
2735
+ // that disagree.
2736
+ //
2737
+ // A boundary that re-dispatches work will get a different id on the next call
2738
+ // and the floor re-runs — which is correct: the tree it certified is gone.
2739
+ const tree = await worktreeContentId(root);
2740
+ const gateKey = `phase_boundary_gate phase=${phase}`;
2741
+ // THE CACHE. The fold re-enters this boundary on every next-step taken before
2742
+ // the next phase dispatches, and the floor is build + typecheck + the whole
2743
+ // suite — minutes, holding the phase lock. Re-running it on a tree that cannot
2744
+ // have changed since the last verdict buys nothing: the answer is already
2745
+ // known and was already recorded. A HIT is therefore a full substitute,
2746
+ // including for a RED one (see {@link readFinalGateVerdict} — the pause is
2747
+ // rebuilt from the cached results rather than re-derived).
2748
+ const cached = await readFinalGateVerdict(artifactsDir, scope, tree);
2749
+ if (cached !== undefined) {
2750
+ // Recorded as a distinct outcome from a real run: the judge is `history`,
2751
+ // not a spawned command, and `commands_run` counts what HISTORY held, never
2752
+ // what this call executed. `passed` is echoed unchanged, so a cached green
2753
+ // still reads green and a cached red still reads red.
2754
+ await recordFinalGateOutcome({
2755
+ artifactsDir,
2756
+ state,
2757
+ scope,
2758
+ gateKey,
2759
+ runLogger,
2760
+ outcome: "history",
2761
+ passed: cached.passed,
2762
+ commandsRun: cached.results.length,
2763
+ reason: `a verdict for this exact tree content is already recorded (scope "${cached.scope}", ` +
2764
+ `recorded_at ${cached.recorded_at}); the floor was NOT re-run because the tree it ` +
2765
+ "would run against has not changed",
2766
+ });
2767
+ if (cached.passed)
2768
+ return null; // cached green (or scope-out) → dispatch
2769
+ // Cached RED. The run has not progressed since that verdict — the pause
2770
+ // mutates nothing — so re-entering it is the same pause, rebuilt from the
2771
+ // cached command results so the record keeps its failing command, exit code
2772
+ // and output tail.
2773
+ return emitFinalGateRedStep({
2774
+ root,
2775
+ artifactsDir,
2776
+ state,
2777
+ scope,
2778
+ gate: {
2779
+ passed: false,
2780
+ results: cached.results,
2781
+ outcome: cached.outcome,
2782
+ scoped_out: cached.scoped_out,
2783
+ runtime_residual: RUNTIME_RESIDUAL_DECLARATION,
2784
+ },
2785
+ // The RECORD's own tree, not the freshly-measured one: the prompt must
2786
+ // name the identity the cached verdict is actually bound to, which is the
2787
+ // one readFinalGateVerdict just matched on.
2788
+ tree: cached.tree,
2789
+ runLogger,
2790
+ });
2791
+ }
2484
2792
  const gateStart = Date.now();
2485
2793
  runLogger.event({
2486
2794
  phase: "next-step",
2487
2795
  kind: "executor_start",
2488
2796
  obligation: state.status,
2489
- note: `phase_boundary_gate phase=${phase}`,
2797
+ note: gateKey,
2490
2798
  });
2491
2799
  const gate = await runToolOwnedFinalGate(root, { runner: options.finalGateRunner });
2800
+ await writeFinalGateVerdict(artifactsDir, {
2801
+ scope,
2802
+ tree,
2803
+ passed: gate.passed,
2804
+ scoped_out: gate.scoped_out,
2805
+ outcome: gate.outcome,
2806
+ results: gate.results,
2807
+ });
2492
2808
  await recordFinalGateOutcome({
2493
2809
  artifactsDir,
2494
2810
  state,
2495
2811
  scope,
2496
- gateKey: `phase_boundary_gate phase=${phase}`,
2812
+ gateKey,
2497
2813
  runLogger,
2498
2814
  outcome: gate.outcome,
2499
2815
  passed: gate.passed,
@@ -2513,6 +2829,9 @@ async function runPhaseBoundaryGate(ctx) {
2513
2829
  state,
2514
2830
  scope,
2515
2831
  gate,
2832
+ // The id taken BEFORE the floor ran, which is what writeFinalGateVerdict
2833
+ // just recorded — so the prompt names the binding the cache will match on.
2834
+ tree,
2516
2835
  runLogger,
2517
2836
  });
2518
2837
  }
@@ -2557,6 +2876,10 @@ async function handleAllTerminalTransition(root, artifactsDir, state, store, opt
2557
2876
  // one at a phase boundary, so it gets the same answer: record and pause.
2558
2877
  // The run does NOT advance to `closing` — closing on a red would write a
2559
2878
  // report claiming an outcome the suite never corroborated.
2879
+ // No `tree` here on purpose: this funnel caches nothing (it runs the floor
2880
+ // on every arrival), so there is no verdict record for a red to be bound
2881
+ // to, and the prompt says exactly that instead of naming an id that would
2882
+ // be re-measured on the next call anyway.
2560
2883
  return emitFinalGateRedStep({
2561
2884
  root,
2562
2885
  artifactsDir,
@@ -2592,6 +2915,23 @@ async function handleAllTerminalTransition(root, artifactsDir, state, store, opt
2592
2915
  async function handleClosing(root, artifactsDir, state, runLogger, store) {
2593
2916
  const closeStart = Date.now();
2594
2917
  runLogger.event({ phase: "next-step", kind: "executor_start", obligation: state.status, note: "close" });
2918
+ // THE FRICTION WALK IS DECIDED HERE, BEFORE THE CLOSE TOUCHES DISK.
2919
+ //
2920
+ // `runClosePhase` ends by archiving the run's friction record into the
2921
+ // promoted deliverables and deleting the artifacts dir. Both the record and
2922
+ // the state's plan id — the key that names it — are gone after that, so this
2923
+ // is the last moment a decision can name the run it is closing out. Deciding
2924
+ // here also MATERIALIZES the plan-keyed record, which is what gives the host
2925
+ // a file to append to during the walk.
2926
+ //
2927
+ // An unsatisfied walk short-circuits the close ENTIRELY: no tests, no closing
2928
+ // action, no archive, no removal. The run stays open on the plan-keyed record
2929
+ // and is emitted as the blocking friction step; once disposed, the next
2930
+ // `next-step` re-decides it as satisfied and falls through to a real close.
2931
+ const frictionTriage = await decideRemediateFrictionCloseout(artifactsDir, state);
2932
+ if (frictionTriage && frictionTriage.action !== "disposed") {
2933
+ return { kind: "emit", step: await buildFrictionWalkStep(root, artifactsDir, state, frictionTriage) };
2934
+ }
2595
2935
  const closed = await runClosePhase(state, { root, artifactsDir }, runLogger);
2596
2936
  runLogger.event({ phase: "next-step", kind: "executor_end", obligation: state.status, note: "close", duration_ms: Date.now() - closeStart });
2597
2937
  if (closed.status !== "complete") {
@@ -2602,10 +2942,10 @@ async function handleClosing(root, artifactsDir, state, runLogger, store) {
2602
2942
  // Close-complete CROSSES the engine boundary: `complete` is a pre-intake
2603
2943
  // obligation, unreachable from a main-engine transition. Emit the durable
2604
2944
  // report directly, passing exactly what the original recursion reloaded — the
2605
- // artifact dir is DELETED on a fully-green close (reload → null → stateRunId
2606
- // falls back to "run") and PRESERVED on a not-green complete (reload → the
2607
- // saved complete state → its plan_id). `store.loadState()` reproduces both, so
2608
- // present_report is identical to the cascade.
2945
+ // artifact dir is DELETED on a fully-green close (reload → null, and a null
2946
+ // state renders no friction block) and PRESERVED on a not-green complete
2947
+ // (reload → the saved complete state → its plan_id). `store.loadState()`
2948
+ // reproduces both, so present_report is identical to the cascade.
2609
2949
  // (Regression-locked in next-step-implement-dispatch.)
2610
2950
  return {
2611
2951
  kind: "emit",
@@ -2846,8 +3186,21 @@ async function buildConfirmIntentStep(ctx) {
2846
3186
  const nextCommand = loaderCommand("next-step");
2847
3187
  const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
2848
3188
  // Read the pre-drafted checkpoint if one exists (confirmed_by: "draft").
2849
- const draft = await readOptionalJsonFile(checkpointPath);
3189
+ //
3190
+ // This is the GATE, and it reads LENIENTLY on purpose: a checkpoint whose
3191
+ // `closing_action` is outside the vocabulary must reach the refusal below,
3192
+ // where the prompt names the offending value and the legal set. A strict read
3193
+ // would replace that affordance with a zod error. Every field consumed here as
3194
+ // a VALUE is still checked by name (`isClosingAction`, `customCommandOf`).
3195
+ //
3196
+ // The REFUSED values come from `rejected`, never from `draft`: the returned
3197
+ // checkpoint is schema-valid, so an out-of-vocabulary key is ABSENT from it
3198
+ // (see `parseIntentCheckpointLenient`). The value the refusal quotes is the one
3199
+ // the host WROTE, which is exactly what `rejected` carries.
3200
+ const draftRead = await readIntentCheckpointLenient(checkpointPath);
3201
+ const draft = draftRead.checkpoint;
2850
3202
  const isDraft = draft?.confirmed_by === "draft";
3203
+ const rejectedClosingAction = draftRead.rejected.find((field) => field.key === "closing_action");
2851
3204
  // Closing action: DETECTED candidates, presented for the host to choose
2852
3205
  // from; the tool never selects one (owner decision 92b0e2dd7cfdc06d).
2853
3206
  const facts = await detectProjectFacts(root);
@@ -2857,7 +3210,9 @@ async function buildConfirmIntentStep(ctx) {
2857
3210
  const closingSection = renderClosingActionSection(facts);
2858
3211
  // A confirmed checkpoint whose closing_action is not in the vocabulary
2859
3212
  // re-enters this step by name — a refusal, never a silent default.
2860
- const rawChoice = draft?.confirmed_by === "host" ? draft.closing_action : undefined;
3213
+ const rawChoice = draft?.confirmed_by === "host"
3214
+ ? (draft.closing_action ?? rejectedClosingAction?.value)
3215
+ : undefined;
2861
3216
  const refusal = rawChoice !== undefined && !isClosingAction(rawChoice)
2862
3217
  ? `> **Refused:** \`closing_action\` ${JSON.stringify(rawChoice)} is not one of ${CLOSING_ACTIONS.map((a) => `\`${a}\``).join(", ")}. Rewrite the checkpoint with a valid value, or omit the field for \`none\`.\n`
2863
3218
  : rawChoice === "custom" && customCommandOf(draft) === null
@@ -3159,10 +3514,12 @@ export const PRE_INTAKE_PRIORITY = [
3159
3514
  */
3160
3515
  export function buildPreIntakeObligations(ctx, snapshot) {
3161
3516
  const { artifactsDir, inputResolution } = ctx;
3162
- const { existingCheckpoint, resumeAck, entryState, suppliedInputUnchanged, guidanceFileSupplied } = snapshot;
3517
+ const { existingCheckpoint, rejectedCheckpointFields, resumeAck, entryState, suppliedInputUnchanged, guidanceFileSupplied } = snapshot;
3163
3518
  const ip = intakePaths(artifactsDir);
3164
3519
  const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
3165
3520
  const ackPath = join(artifactsDir, "confirm_resume_ack.json");
3521
+ /** The refused `closing_action`, if the schema dropped one — see the `fires` note. */
3522
+ const rejectedClosingAction = rejectedCheckpointFields.find((field) => field.key === "closing_action");
3166
3523
  const interpretationPath = join(artifactsDir, INTENT_INTERPRETATION_FILENAME);
3167
3524
  const reportPath = join(dirname(artifactsDir), "remediation-report.md");
3168
3525
  return [
@@ -3230,8 +3587,18 @@ export function buildPreIntakeObligations(ctx, snapshot) {
3230
3587
  // A host-confirmed checkpoint carrying a closing_action outside the
3231
3588
  // vocabulary is not a confirmation: the step re-emits naming the value
3232
3589
  // (owner decision 92b0e2dd7cfdc06d — never a silent default).
3590
+ //
3591
+ // The refused value comes from `rejectedCheckpointFields` as well as from
3592
+ // the parsed checkpoint, and it must: the lenient read DROPS a key the
3593
+ // schema refused, so an out-of-vocabulary `closing_action` is absent from
3594
+ // `existingCheckpoint` and the read of it alone would answer `undefined`
3595
+ // — "no answer given, so no question" — leaving every branch of `fires`
3596
+ // false and advancing on a checkpoint whose action was never accepted.
3597
+ // `confirmed_by` survives the drop, which is exactly what makes that
3598
+ // silent pass possible; reading the rejection back is what closes it.
3233
3599
  const chosenClosingAction = existingCheckpoint?.confirmed_by === "host"
3234
- ? existingCheckpoint.closing_action
3600
+ ? (existingCheckpoint.closing_action ??
3601
+ rejectedClosingAction?.value)
3235
3602
  : undefined;
3236
3603
  const invalidClosingAction = (chosenClosingAction !== undefined && !isClosingAction(chosenClosingAction)) ||
3237
3604
  (chosenClosingAction === "custom" && customCommandOf(existingCheckpoint) === null);
@@ -3501,6 +3868,15 @@ export function buildMainObligations(ctx) {
3501
3868
  execute: async (state) => {
3502
3869
  const s = requireState(state);
3503
3870
  s.status = "waiting_for_clarification";
3871
+ // The binding is scoped to `implementing` (INV-RSM-STATE-COMPLETE: the
3872
+ // load gate rejects a `host_handoff` under any other status, and the
3873
+ // store's write hook enforces the same rule). Leaving the status
3874
+ // without clearing the record produced a state the tool itself could
3875
+ // not read back — a state that only escaped because nothing validated
3876
+ // the write path. Dropping it here is also what the field MEANS: the
3877
+ // pending workload it digests is about to be re-prepared for the
3878
+ // answered item.
3879
+ delete s.host_handoff;
3504
3880
  await store.saveState(s);
3505
3881
  return { kind: "transition", state: s };
3506
3882
  },
@@ -3676,9 +4052,27 @@ async function advanceUnderPhaseLock(deps) {
3676
4052
  // Pre-read the once-async signals the pre-intake derive()s consume
3677
4053
  // synchronously (no transition inside this advance call rewrites either file).
3678
4054
  const checkpointPath = join(artifactsDir, "intent_checkpoint.json");
3679
- const existingCheckpoint = existsSync(checkpointPath)
3680
- ? await readOptionalJsonFile(checkpointPath)
4055
+ // LENIENT: this read feeds the pre-intake derive()s, whose confirmation
4056
+ // obligation is what REFUSES a malformed checkpoint by name and re-asks. A
4057
+ // strict read here would pre-empt that obligation with a thrown load error.
4058
+ //
4059
+ // Every consumer of the VALUE here uses a validated field (as a value, or as a
4060
+ // presence question on a DIFFERENT field), never quotes an offending one — the
4061
+ // prompt that quotes the refused value is `buildConfirmIntentStep`, which reads
4062
+ // the raw rejections itself. So this site takes the plain lenient read, whose
4063
+ // value is schema-valid.
4064
+ //
4065
+ // The REJECTIONS are threaded beside it rather than discarded, because one
4066
+ // consumer is not a value read: `confirm_intent`'s `fires` asks whether the
4067
+ // checkpoint carries an ACCEPTED answer, and a refused `closing_action` is a
4068
+ // key the lenient read DROPPED — so the parsed value cannot answer for it, and
4069
+ // asking only the parsed value reads a refusal as "no answer given, so no
4070
+ // question". Strict is not the alternative: it would replace the gate's named
4071
+ // refusal with a thrown load error.
4072
+ const checkpointRead = existsSync(checkpointPath)
4073
+ ? await readIntentCheckpointLenient(checkpointPath)
3681
4074
  : undefined;
4075
+ const existingCheckpoint = checkpointRead?.checkpoint;
3682
4076
  const resumeAck = await readOptionalJsonFile(join(artifactsDir, "confirm_resume_ack.json"));
3683
4077
  // Whether a supplied `--input` matches the input the existing run was built
3684
4078
  // from — so re-passing the same `--input` (the loader does this each next-step)
@@ -3701,6 +4095,7 @@ async function advanceUnderPhaseLock(deps) {
3701
4095
  priority: PRE_INTAKE_PRIORITY,
3702
4096
  obligations: buildPreIntakeObligations(ctx, {
3703
4097
  existingCheckpoint,
4098
+ rejectedCheckpointFields: checkpointRead?.rejected ?? [],
3704
4099
  resumeAck,
3705
4100
  entryState: state,
3706
4101
  suppliedInputUnchanged,