audit-tools 0.45.0 → 0.46.0

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 (227) hide show
  1. package/README.md +15 -2
  2. package/dist/audit/cli/charterExtractionPrompt.d.ts.map +1 -1
  3. package/dist/audit/cli/charterExtractionPrompt.js +11 -1
  4. package/dist/audit/cli/charterExtractionPrompt.js.map +1 -1
  5. package/dist/audit/cli/cleanupCommand.d.ts +25 -0
  6. package/dist/audit/cli/cleanupCommand.d.ts.map +1 -1
  7. package/dist/audit/cli/cleanupCommand.js +69 -0
  8. package/dist/audit/cli/cleanupCommand.js.map +1 -1
  9. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  10. package/dist/audit/cli/dispatch/hostHandoff.js +52 -76
  11. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  12. package/dist/audit/cli/dispatch/packetFilter.d.ts +1 -1
  13. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
  14. package/dist/audit/cli/fanoutLanes.js +6 -1
  15. package/dist/audit/cli/fanoutLanes.js.map +1 -1
  16. package/dist/audit/cli/laneSubmissions.d.ts +13 -0
  17. package/dist/audit/cli/laneSubmissions.d.ts.map +1 -1
  18. package/dist/audit/cli/laneSubmissions.js +38 -27
  19. package/dist/audit/cli/laneSubmissions.js.map +1 -1
  20. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  21. package/dist/audit/cli/nextStepCommand.js +8 -6
  22. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  23. package/dist/audit/cli/nextStepHelpers.d.ts +3 -2
  24. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  25. package/dist/audit/cli/nextStepHelpers.js +37 -35
  26. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  27. package/dist/audit/cli/reviewRun.d.ts +1 -1
  28. package/dist/audit/cli/reviewRun.d.ts.map +1 -1
  29. package/dist/audit/cli/reviewRun.js +2 -9
  30. package/dist/audit/cli/reviewRun.js.map +1 -1
  31. package/dist/audit/cli/sampleRunCommand.d.ts.map +1 -1
  32. package/dist/audit/cli/sampleRunCommand.js +12 -1
  33. package/dist/audit/cli/sampleRunCommand.js.map +1 -1
  34. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  35. package/dist/audit/cli/semanticReviewStep.js +9 -1
  36. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  37. package/dist/audit/cli/steps.d.ts +6 -6
  38. package/dist/audit/contracts/workerSchemas.d.ts +36 -26
  39. package/dist/audit/contracts/workerSchemas.d.ts.map +1 -1
  40. package/dist/audit/contracts/workerSchemas.js +11 -1
  41. package/dist/audit/contracts/workerSchemas.js.map +1 -1
  42. package/dist/audit/contracts/wrapperResponse.d.ts +52 -28
  43. package/dist/audit/contracts/wrapperResponse.d.ts.map +1 -1
  44. package/dist/audit/contracts/wrapperResponse.js +8 -5
  45. package/dist/audit/contracts/wrapperResponse.js.map +1 -1
  46. package/dist/audit/decompose/sources.d.ts.map +1 -1
  47. package/dist/audit/decompose/sources.js +21 -5
  48. package/dist/audit/decompose/sources.js.map +1 -1
  49. package/dist/audit/extractors/analyzers/registry.d.ts +8 -5
  50. package/dist/audit/extractors/analyzers/registry.d.ts.map +1 -1
  51. package/dist/audit/extractors/analyzers/registry.js +28 -7
  52. package/dist/audit/extractors/analyzers/registry.js.map +1 -1
  53. package/dist/audit/extractors/designAssessment.js +1 -1
  54. package/dist/audit/extractors/gitHistory.d.ts +1 -1
  55. package/dist/audit/extractors/gitHistory.js +1 -1
  56. package/dist/audit/extractors/graph.d.ts +1 -1
  57. package/dist/audit/extractors/graph.js +1 -1
  58. package/dist/audit/extractors/risk.d.ts +1 -1
  59. package/dist/audit/extractors/risk.js +1 -1
  60. package/dist/audit/io/artifacts.d.ts.map +1 -1
  61. package/dist/audit/io/artifacts.js +5 -5
  62. package/dist/audit/io/artifacts.js.map +1 -1
  63. package/dist/audit/orchestrator/acquisitionExecutor.d.ts +11 -6
  64. package/dist/audit/orchestrator/acquisitionExecutor.d.ts.map +1 -1
  65. package/dist/audit/orchestrator/acquisitionExecutor.js +1 -1
  66. package/dist/audit/orchestrator/acquisitionExecutor.js.map +1 -1
  67. package/dist/audit/orchestrator/advance.d.ts +14 -10
  68. package/dist/audit/orchestrator/advance.d.ts.map +1 -1
  69. package/dist/audit/orchestrator/advance.js +49 -24
  70. package/dist/audit/orchestrator/advance.js.map +1 -1
  71. package/dist/audit/orchestrator/advanceTypes.d.ts +14 -0
  72. package/dist/audit/orchestrator/advanceTypes.d.ts.map +1 -1
  73. package/dist/audit/orchestrator/autoFixExecutor.d.ts +20 -1
  74. package/dist/audit/orchestrator/autoFixExecutor.d.ts.map +1 -1
  75. package/dist/audit/orchestrator/autoFixExecutor.js +77 -15
  76. package/dist/audit/orchestrator/autoFixExecutor.js.map +1 -1
  77. package/dist/audit/orchestrator/dependencyMap.js +1 -1
  78. package/dist/audit/orchestrator/dependencyMap.js.map +1 -1
  79. package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
  80. package/dist/audit/orchestrator/executorRunners.js +18 -4
  81. package/dist/audit/orchestrator/executorRunners.js.map +1 -1
  82. package/dist/audit/orchestrator/executors.d.ts +54 -0
  83. package/dist/audit/orchestrator/executors.d.ts.map +1 -1
  84. package/dist/audit/orchestrator/executors.js +352 -0
  85. package/dist/audit/orchestrator/executors.js.map +1 -1
  86. package/dist/audit/orchestrator/hostInputPause.d.ts +20 -11
  87. package/dist/audit/orchestrator/hostInputPause.d.ts.map +1 -1
  88. package/dist/audit/orchestrator/hostInputPause.js +17 -11
  89. package/dist/audit/orchestrator/hostInputPause.js.map +1 -1
  90. package/dist/audit/orchestrator/localCommands.d.ts +24 -1
  91. package/dist/audit/orchestrator/localCommands.d.ts.map +1 -1
  92. package/dist/audit/orchestrator/localCommands.js +44 -9
  93. package/dist/audit/orchestrator/localCommands.js.map +1 -1
  94. package/dist/audit/orchestrator/nextStep.d.ts +13 -0
  95. package/dist/audit/orchestrator/nextStep.d.ts.map +1 -1
  96. package/dist/audit/orchestrator/nextStep.js +13 -0
  97. package/dist/audit/orchestrator/nextStep.js.map +1 -1
  98. package/dist/audit/orchestrator/requeueCommand.d.ts +1 -1
  99. package/dist/audit/orchestrator/runtimeCommand.d.ts +32 -1
  100. package/dist/audit/orchestrator/runtimeCommand.d.ts.map +1 -1
  101. package/dist/audit/orchestrator/runtimeCommand.js +90 -3
  102. package/dist/audit/orchestrator/runtimeCommand.js.map +1 -1
  103. package/dist/audit/orchestrator/structureExecutors.js +1 -1
  104. package/dist/audit/orchestrator/structureExecutors.js.map +1 -1
  105. package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts +11 -1
  106. package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts.map +1 -1
  107. package/dist/audit/orchestrator/syntaxResolutionExecutor.js +25 -9
  108. package/dist/audit/orchestrator/syntaxResolutionExecutor.js.map +1 -1
  109. package/dist/audit/supervisor/operatorHandoff.d.ts +0 -1
  110. package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -1
  111. package/dist/audit/supervisor/operatorHandoff.js +2 -1
  112. package/dist/audit/supervisor/operatorHandoff.js.map +1 -1
  113. package/dist/audit/types.d.ts +18 -18
  114. package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
  115. package/dist/remediate/contractPipeline/derive.js +1 -0
  116. package/dist/remediate/contractPipeline/derive.js.map +1 -1
  117. package/dist/remediate/contractPipeline/semanticProjection.d.ts +5 -4
  118. package/dist/remediate/contractPipeline/semanticProjection.d.ts.map +1 -1
  119. package/dist/remediate/contractPipeline/semanticProjection.js +34 -19
  120. package/dist/remediate/contractPipeline/semanticProjection.js.map +1 -1
  121. package/dist/remediate/index.d.ts.map +1 -1
  122. package/dist/remediate/index.js +3 -2
  123. package/dist/remediate/index.js.map +1 -1
  124. package/dist/remediate/phases/close.d.ts +37 -2
  125. package/dist/remediate/phases/close.d.ts.map +1 -1
  126. package/dist/remediate/phases/close.js +100 -31
  127. package/dist/remediate/phases/close.js.map +1 -1
  128. package/dist/remediate/phases/closeVerifyAnalyzerLeads.js +2 -2
  129. package/dist/remediate/phases/closeVerifyAnalyzerLeads.js.map +1 -1
  130. package/dist/remediate/phases/triage.d.ts.map +1 -1
  131. package/dist/remediate/phases/triage.js +61 -19
  132. package/dist/remediate/phases/triage.js.map +1 -1
  133. package/dist/remediate/steps/contractPipeline.d.ts +13 -0
  134. package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
  135. package/dist/remediate/steps/contractPipeline.js +82 -3
  136. package/dist/remediate/steps/contractPipeline.js.map +1 -1
  137. package/dist/remediate/steps/dispatch/hostHandoff.d.ts +1 -1
  138. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  139. package/dist/remediate/steps/dispatch/hostHandoff.js +297 -139
  140. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  141. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  142. package/dist/remediate/steps/nextStep.js +37 -7
  143. package/dist/remediate/steps/nextStep.js.map +1 -1
  144. package/dist/remediate/types/options.d.ts +1 -1
  145. package/dist/shared/analyzers/acquisitionEngine.d.ts +61 -28
  146. package/dist/shared/analyzers/acquisitionEngine.d.ts.map +1 -1
  147. package/dist/shared/analyzers/acquisitionEngine.js +83 -24
  148. package/dist/shared/analyzers/acquisitionEngine.js.map +1 -1
  149. package/dist/shared/analyzers/binaryAcquisition.d.ts +8 -2
  150. package/dist/shared/analyzers/binaryAcquisition.d.ts.map +1 -1
  151. package/dist/shared/analyzers/binaryAcquisition.js +4 -4
  152. package/dist/shared/analyzers/binaryAcquisition.js.map +1 -1
  153. package/dist/shared/constitutionalDocPaths.d.ts.map +1 -1
  154. package/dist/shared/constitutionalDocPaths.js +7 -0
  155. package/dist/shared/constitutionalDocPaths.js.map +1 -1
  156. package/dist/shared/engine/obligationEngine.d.ts +44 -3
  157. package/dist/shared/engine/obligationEngine.d.ts.map +1 -1
  158. package/dist/shared/engine/obligationEngine.js +53 -7
  159. package/dist/shared/engine/obligationEngine.js.map +1 -1
  160. package/dist/shared/findings/dedupe.d.ts.map +1 -1
  161. package/dist/shared/findings/dedupe.js +8 -0
  162. package/dist/shared/findings/dedupe.js.map +1 -1
  163. package/dist/shared/friction/frictionRecord.d.ts +42 -2
  164. package/dist/shared/friction/frictionRecord.d.ts.map +1 -1
  165. package/dist/shared/friction/frictionRecord.js +111 -3
  166. package/dist/shared/friction/frictionRecord.js.map +1 -1
  167. package/dist/shared/friction/triage.d.ts +15 -0
  168. package/dist/shared/friction/triage.d.ts.map +1 -1
  169. package/dist/shared/friction/triage.js +33 -2
  170. package/dist/shared/friction/triage.js.map +1 -1
  171. package/dist/shared/index.d.ts +13 -9
  172. package/dist/shared/index.d.ts.map +1 -1
  173. package/dist/shared/index.js +14 -7
  174. package/dist/shared/index.js.map +1 -1
  175. package/dist/shared/io/fileLock.d.ts.map +1 -1
  176. package/dist/shared/io/fileLock.js +22 -3
  177. package/dist/shared/io/fileLock.js.map +1 -1
  178. package/dist/shared/io/frictionCapture.d.ts +73 -19
  179. package/dist/shared/io/frictionCapture.d.ts.map +1 -1
  180. package/dist/shared/io/frictionCapture.js +21 -30
  181. package/dist/shared/io/frictionCapture.js.map +1 -1
  182. package/dist/shared/io/lockedJsonStore.d.ts +24 -3
  183. package/dist/shared/io/lockedJsonStore.d.ts.map +1 -1
  184. package/dist/shared/io/lockedJsonStore.js +35 -7
  185. package/dist/shared/io/lockedJsonStore.js.map +1 -1
  186. package/dist/shared/io/stepContractWriter.d.ts +3 -3
  187. package/dist/shared/io/stepContractWriter.d.ts.map +1 -1
  188. package/dist/shared/io/stepContractWriter.js +97 -13
  189. package/dist/shared/io/stepContractWriter.js.map +1 -1
  190. package/dist/shared/submission/expectedSubmissions.d.ts +18 -0
  191. package/dist/shared/submission/expectedSubmissions.d.ts.map +1 -1
  192. package/dist/shared/submission/expectedSubmissions.js +17 -0
  193. package/dist/shared/submission/expectedSubmissions.js.map +1 -1
  194. package/dist/shared/submission/handRecovery.d.ts.map +1 -1
  195. package/dist/shared/submission/handRecovery.js +9 -11
  196. package/dist/shared/submission/handRecovery.js.map +1 -1
  197. package/dist/shared/submission/hostHandoffCore.d.ts +155 -0
  198. package/dist/shared/submission/hostHandoffCore.d.ts.map +1 -0
  199. package/dist/shared/submission/hostHandoffCore.js +210 -0
  200. package/dist/shared/submission/hostHandoffCore.js.map +1 -0
  201. package/dist/shared/submission/submissionLedger.d.ts +5 -1
  202. package/dist/shared/submission/submissionLedger.d.ts.map +1 -1
  203. package/dist/shared/submission/submissionLedger.js +33 -3
  204. package/dist/shared/submission/submissionLedger.js.map +1 -1
  205. package/dist/shared/tooling/commandShape.d.ts +29 -0
  206. package/dist/shared/tooling/commandShape.d.ts.map +1 -1
  207. package/dist/shared/tooling/commandShape.js +82 -10
  208. package/dist/shared/tooling/commandShape.js.map +1 -1
  209. package/dist/shared/tooling/exec.d.ts +32 -0
  210. package/dist/shared/tooling/exec.d.ts.map +1 -1
  211. package/dist/shared/tooling/exec.js +189 -0
  212. package/dist/shared/tooling/exec.js.map +1 -1
  213. package/docs/audit-pkg/contracts.md +2 -1
  214. package/docs/audit-pkg/operator-guide.md +5 -2
  215. package/docs/audit-pkg/product.md +22 -6
  216. package/package.json +10 -6
  217. package/schemas/audit-code-v1alpha1.schema.json +297 -0
  218. package/schemas/audit_result.schema.json +4 -0
  219. package/schemas/audit_results.schema.json +4 -0
  220. package/scripts/shared/install-host-assets.mjs +8 -5
  221. package/skills/audit-code/SKILL.md +4 -2
  222. package/skills/audit-code/audit-code.prompt.md +5 -2
  223. package/skills/audit-code/opencode-command-template.txt +1 -1
  224. package/wrapper/audit-code-wrapper-lib.mjs +81 -16
  225. package/wrapper/installer-verb-help.mjs +14 -4
  226. package/docs/audit-pkg/development.md +0 -113
  227. package/docs/audit-pkg/release.md +0 -140
@@ -8,8 +8,25 @@ function compareIds(left, right) {
8
8
  * Build the set one emission owes. Entries are ordered by `submission_id` — a
9
9
  * content-derived key, never emission or filesystem order, so re-recording an
10
10
  * unchanged set produces byte-identical content.
11
+ *
12
+ * A lane declaring `expected: false` is REFUSED here, at the ONE seam every
13
+ * emitter builds its set through: the tool never reads that lane's submission,
14
+ * so an expectation recorded against it can never be satisfied or dropped —
15
+ * it would accumulate as a permanent, false shortfall the run reports forever.
16
+ * Throwing (not filtering) is the fail-closed shape: a caller that routes its
17
+ * un-expected lanes through this builder anyway has misstated what it owes,
18
+ * and a silently narrowed set would hide exactly that. The audit draw's
19
+ * materializer filters at its own boundary first; this is the backstop that
20
+ * makes the filter's omission non-optional.
11
21
  */
12
22
  export function buildExpectedSubmissionSet(params) {
23
+ const unexpected = params.lanes.filter((lane) => lane.expected === false);
24
+ if (unexpected.length > 0) {
25
+ throw new Error(`buildExpectedSubmissionSet refused ${unexpected.length} un-expected lane(s): ` +
26
+ `${unexpected.map((lane) => `'${lane.lane}'`).join(", ")}. The tool never reads ` +
27
+ "a lane whose submission another lane consumes, so recording one would mint an " +
28
+ "expectation no submission can ever satisfy — filter it out before building the set.");
29
+ }
13
30
  const entries = params.lanes.map((lane) => ({
14
31
  submission_id: lane.submissionId,
15
32
  lane: lane.lane,
@@ -1 +1 @@
1
- {"version":3,"file":"expectedSubmissions.js","sourceRoot":"","sources":["../../../src/shared/submission/expectedSubmissions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"expectedSubmissions.js","sourceRoot":"","sources":["../../../src/shared/submission/expectedSubmissions.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"handRecovery.d.ts","sourceRoot":"","sources":["../../../src/shared/submission/handRecovery.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAWjE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC;AA6B5D;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,eAAe,GAAG,IAAI,GACnD,OAAO,CAAC,mBAAmB,CAAC,CAuJ9B"}
1
+ {"version":3,"file":"handRecovery.d.ts","sourceRoot":"","sources":["../../../src/shared/submission/handRecovery.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAWjE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC;AA6B5D;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,eAAe,GAAG,IAAI,GACnD,OAAO,CAAC,mBAAmB,CAAC,CAqJ9B"}
@@ -13,8 +13,8 @@
13
13
  * appends `recovered_by_hand`, so a run repaired by an operator stays
14
14
  * distinguishable from one the host got right.
15
15
  */
16
- import { readFile, unlink, writeFile } from "node:fs/promises";
17
- import { readOptionalJsonFile, writeJsonFile } from "../io/json.js";
16
+ import { readFile, unlink } from "node:fs/promises";
17
+ import { readOptionalJsonFile, writeFileAtomic, writeJsonFile, } from "../io/json.js";
18
18
  import { discardOnSchemaVersionMismatch } from "../io/schemaVersion.js";
19
19
  import { expectedSubmissionsPath, submissionsDir, } from "../io/auditToolsPaths.js";
20
20
  import { EXPECTED_SET_CONTRACT_VERSION } from "./expectedSubmissions.js";
@@ -145,15 +145,13 @@ export async function recoverSubmission(request, validate) {
145
145
  await unlink(landingPath);
146
146
  }
147
147
  else {
148
- // UNCOVERED HALF, stated: this restore is a RAW write while the forward
149
- // write above is atomic (temp + rename). A crash between truncate and
150
- // the last byte therefore leaves a TRUNCATED prior payload worse than
151
- // either outcome this rollback chooses between. Closing it needs
152
- // `writeFileAtomic` to accept `string | Buffer` and be exported, which is
153
- // the io module's node (CP-NODE-3) and named in its dispatch, not a
154
- // change this module may make. Until it lands, the restore is atomic in
155
- // intent and not in mechanism.
156
- await writeFile(landingPath, priorContent);
148
+ // Restored through the SHARED atomic writer with the captured raw bytes,
149
+ // so the rollback is byte-for-byte AND crash-safe: the forward write is
150
+ // temp+rename and the restore must be no weaker, or a crash between
151
+ // truncate and the last byte would leave a TRUNCATED prior payload —
152
+ // worse than either outcome this rollback chooses between. (`writeFile`
153
+ // accepting a Buffer was not enough; only the atomic form closes it.)
154
+ await writeFileAtomic(landingPath, priorContent);
157
155
  }
158
156
  }
159
157
  catch (rollbackError) {
@@ -1 +1 @@
1
- {"version":3,"file":"handRecovery.js","sourceRoot":"","sources":["../../../src/shared/submission/handRecovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"handRecovery.js","sourceRoot":"","sources":["../../../src/shared/submission/handRecovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,155 @@
1
+ /** Code-unit lexical order — the shared comparator for every id sort here. */
2
+ export declare function compareCodeUnits(left: string, right: string): number;
3
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
4
+ /** Exact key set, order-insensitive: a persisted envelope admits no extra keys. */
5
+ export declare function hasExactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean;
6
+ export declare function isSha256(value: unknown): value is string;
7
+ /** Full sha1/sha256 commit id — the only form a baseline may take. */
8
+ export declare function isCommit(value: unknown): value is string;
9
+ export declare function requireNonEmptyString(value: unknown, label: string): string;
10
+ export declare function stringArray(value: unknown): readonly string[] | null;
11
+ /** Element-wise equality of two string arrays (order-significant). */
12
+ export declare function sameStrings(left: readonly string[], right: readonly string[]): boolean;
13
+ /** The dedupe key for an accepted binding: work item × prompt digest. */
14
+ export declare function bindingIdentity(entry: {
15
+ readonly work_item_id: string;
16
+ readonly prompt_sha256: string;
17
+ }): string;
18
+ /**
19
+ * The run-scoped paths one host-handoff boundary lives at.
20
+ *
21
+ * Both twins resolved these with the same three calls (`assertSubmissionRunId`,
22
+ * containment on the artifacts dir, containment on `runs/<runId>`), differing
23
+ * only in whether the run directory carried a sub-segment. The sub-segment is a
24
+ * parameter here, not a fork: remediate's run dir sits under `runs/<id>/implement`
25
+ * because its runs dir also holds triage/closing lanes; audit's sits directly
26
+ * under `runs/<id>`.
27
+ */
28
+ export interface HostHandoffPaths {
29
+ /** Absolute repository root everything is contained beneath. */
30
+ readonly root: string;
31
+ /** Absolute artifacts dir (`.audit-tools/<tool>/`). */
32
+ readonly artifactsDir: string;
33
+ /** Absolute run directory the workload and results live under. */
34
+ readonly runDir: string;
35
+ /** Absolute directory submissions land in. */
36
+ readonly resultDir: string;
37
+ /** Absolute path of the persisted workload document. */
38
+ readonly workloadPath: string;
39
+ }
40
+ /**
41
+ * Resolve the run-scoped boundary paths. Throws when the run id leaves the
42
+ * shared grammar or either declared root escapes containment — before any
43
+ * caller has a path to write to.
44
+ */
45
+ export declare function resolveHostHandoffPaths(params: {
46
+ readonly root: string;
47
+ readonly artifactsDir: string;
48
+ readonly runId: string;
49
+ /**
50
+ * Segments between the RUN DIRECTORY and its lane sub-directory — i.e. AFTER
51
+ * the run id: `runs/<runId>/<segments…>`. Empty for audit's flat
52
+ * `runs/<runId>/`; `["implement"]` for remediate's lane-scoped one. Order is
53
+ * load-bearing: validators join submissions to their run by the FIRST path
54
+ * segment under `runs/`, so the run id must stay that segment.
55
+ */
56
+ readonly runDirSegments?: readonly string[];
57
+ /** Names this draw in the run-id refusal (`Invalid <label>: …`). */
58
+ readonly runIdLabel?: string;
59
+ }): HostHandoffPaths;
60
+ /**
61
+ * The bound path for one work item's submission — the SHARED rule, not a local
62
+ * copy of it. `<resultDir>/<sha256(id)>.json`, repository-relative and
63
+ * forward-slashed. This replaces the byte-equivalent private `resultPathFor`
64
+ * copies both twins carried; a divergence between them would have been silent
65
+ * on both sides.
66
+ */
67
+ export declare function hostHandoffResultPath(paths: HostHandoffPaths, id: string): string;
68
+ /** Absolute form of {@link hostHandoffResultPath}, for readers on disk. */
69
+ export declare function absoluteHostHandoffResultPath(paths: HostHandoffPaths, id: string): string;
70
+ /** Content digest of one prompt text — the binding between ask and answer. */
71
+ export declare function promptSha256(promptText: string): string;
72
+ /** Content digest of one canonical JSON rendering. */
73
+ export declare function contentSha256(value: unknown): string;
74
+ export type WorkloadEnvelopeParse = {
75
+ readonly ok: true;
76
+ readonly rawItems: readonly unknown[];
77
+ } | {
78
+ readonly ok: false;
79
+ };
80
+ /**
81
+ * Validate a persisted workload ENVELOPE against this run: exact keys, the
82
+ * draw's contract version, the run id, and an array of raw items. Item-level
83
+ * shape is the draw's parser ({@link parseAllWorkloadItems}); anything the
84
+ * persisted trusted binding further pins (a digest, a baseline) is the draw's
85
+ * policy layered on top of the `ok` case.
86
+ */
87
+ export declare function parseWorkloadEnvelope(value: unknown, params: {
88
+ readonly contractVersion: string;
89
+ readonly runId: string;
90
+ }): WorkloadEnvelopeParse;
91
+ /** Map raw items through the draw's parser; `null` when ANY item refuses. */
92
+ export declare function parseAllWorkloadItems<T>(rawItems: readonly unknown[], parseItem: (raw: unknown) => T | null): readonly T[] | null;
93
+ /** Every id distinct — the duplicate-work-item refusal. */
94
+ export declare function idsAreUnique(ids: readonly string[]): boolean;
95
+ /**
96
+ * Strictly ascending in code-unit order — which is BOTH "sorted" and
97
+ * "duplicate-free", the two properties every persisted workload's id list must
98
+ * have for a re-derivation to compare equal byte-for-byte.
99
+ */
100
+ export declare function idsAreStrictlyAscending(ids: readonly string[]): boolean;
101
+ /**
102
+ * The identity binding EVERY submitted result carries, identical on both
103
+ * draws: a non-empty `result_id`, this run's id, this work item's id, and the
104
+ * prompt digest of the ask. A refusal here is a REFUSAL, never a repair — the
105
+ * tool cannot know which of the three the host meant.
106
+ */
107
+ export declare function resultIdentityIsBound(value: Record<string, unknown>, params: {
108
+ readonly runId: string;
109
+ readonly workItemId: string;
110
+ readonly promptSha256: string;
111
+ }): boolean;
112
+ /** The minimal view of a parsed work item the result-map check needs. */
113
+ export interface ResultMappedItem {
114
+ readonly id: string;
115
+ readonly prompt: {
116
+ readonly sha256: string;
117
+ };
118
+ readonly result_path: string;
119
+ }
120
+ /** One `host-result-map.json` entry, as both draws persist it. */
121
+ export interface ResultMapEntry {
122
+ readonly work_item_id: string;
123
+ readonly prompt_sha256: string;
124
+ readonly result_path: string;
125
+ }
126
+ /**
127
+ * RESULT-MAP IDENTITY: the map names exactly the workload's items, once each,
128
+ * with each item's own prompt digest and derived bound path. This was the
129
+ * second half of the audit twin's `validateHandoffBinding`, hand-inlined there;
130
+ * the remediate draw pins the same facts through its whole-document digest
131
+ * instead — but the CHECK itself is the draw-independent statement of "the map
132
+ * and the workload agree", so it lives here for whichever draw parses a map.
133
+ *
134
+ * The failure is CLASSIFIED, not collapsed: `coverage` means the map does not
135
+ * name this workload's items exactly once each; `identity` means an entry
136
+ * names the right item but pins another item's prompt digest or a bound path
137
+ * the shared rule does not derive. The two are not interchangeable to the
138
+ * caller — one says the MAP is wrong, the other names the BINDING that broke.
139
+ */
140
+ export type ResultMapIdentity<TItem extends ResultMappedItem> = {
141
+ readonly ok: true;
142
+ readonly byId: ReadonlyMap<string, TItem>;
143
+ } | {
144
+ readonly ok: false;
145
+ readonly reason: "coverage" | "identity";
146
+ readonly workItemId?: string;
147
+ };
148
+ export declare function resultMapIdentity<TItem extends ResultMappedItem>(items: readonly TItem[], entries: readonly ResultMapEntry[]): ResultMapIdentity<TItem>;
149
+ /**
150
+ * First duplicate identity in `entries`, or null. The accepted-results ledger
151
+ * and any other keyed record derives its dedupe refusal from this rather than
152
+ * from a hand-rolled Set walk whose message and predicate can drift apart.
153
+ */
154
+ export declare function firstDuplicateIdentity<T>(entries: readonly T[], identity: (entry: T) => string): T | null;
155
+ //# sourceMappingURL=hostHandoffCore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostHandoffCore.d.ts","sourceRoot":"","sources":["../../../src/shared/submission/hostHandoffCore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * The ONE host-handoff boundary both orchestrators draw from.
3
+ *
4
+ * The audit host handoff (`src/audit/cli/dispatch/hostHandoff.ts`) and the
5
+ * remediation one (`src/remediate/steps/dispatch/hostHandoff.ts`) were two
6
+ * independently evolved bodies that had already converged on the same skeleton:
7
+ * resolve a run-scoped boundary, derive each work item's bound result path
8
+ * through the shared submission-path rule, hash the prompt, validate the
9
+ * workload against its bindings, and refuse a result whose identity, prompt
10
+ * binding, or result-map entry does not match the derivation. Every place they
11
+ * differed in TEXT but not in MEANING is what this core owns now; what remains
12
+ * in each twin is its DRAW — the contract versions and shapes it persists, the
13
+ * domain validation it applies on top, the state it mutates.
14
+ */
15
+ // Sibling modules imported DIRECTLY, never through ../index.js: the barrel
16
+ // re-exports this module, so importing the barrel here would close a cycle
17
+ // (index → hostHandoffCore → index) that check:depgraph refuses.
18
+ import { hashContent } from "../hash.js";
19
+ import { stableStringify } from "../stableStringify.js";
20
+ import { assertSubmissionRunId, resolveContainedPath, submissionPathFor, } from "./submissionIdentity.js";
21
+ import { join, resolve } from "node:path";
22
+ /** Code-unit lexical order — the shared comparator for every id sort here. */
23
+ export function compareCodeUnits(left, right) {
24
+ return left < right ? -1 : left > right ? 1 : 0;
25
+ }
26
+ export function isRecord(value) {
27
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28
+ }
29
+ /** Exact key set, order-insensitive: a persisted envelope admits no extra keys. */
30
+ export function hasExactKeys(value, expected) {
31
+ const actual = Object.keys(value).sort(compareCodeUnits);
32
+ return (actual.length === expected.length &&
33
+ actual.every((key, index) => key === [...expected].sort(compareCodeUnits)[index]));
34
+ }
35
+ export function isSha256(value) {
36
+ return typeof value === "string" && /^[0-9a-f]{64}$/u.test(value);
37
+ }
38
+ /** Full sha1/sha256 commit id — the only form a baseline may take. */
39
+ export function isCommit(value) {
40
+ return (typeof value === "string" &&
41
+ /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/u.test(value));
42
+ }
43
+ export function requireNonEmptyString(value, label) {
44
+ if (typeof value !== "string" || value.length === 0) {
45
+ throw new Error(`${label} must be a non-empty string`);
46
+ }
47
+ return value;
48
+ }
49
+ export function stringArray(value) {
50
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string")
51
+ ? value
52
+ : null;
53
+ }
54
+ /** Element-wise equality of two string arrays (order-significant). */
55
+ export function sameStrings(left, right) {
56
+ return (left.length === right.length &&
57
+ left.every((entry, index) => entry === right[index]));
58
+ }
59
+ /**
60
+ * The dedupe key for an accepted binding: work item × prompt digest, joined by
61
+ * NUL (`String.fromCharCode(0)` in source — never the raw control byte in this
62
+ * file, which git would treat as binary).
63
+ */
64
+ const BINDING_IDENTITY_SEPARATOR = String.fromCharCode(0);
65
+ /** The dedupe key for an accepted binding: work item × prompt digest. */
66
+ export function bindingIdentity(entry) {
67
+ return `${entry.work_item_id}${BINDING_IDENTITY_SEPARATOR}${entry.prompt_sha256}`;
68
+ }
69
+ /**
70
+ * Resolve the run-scoped boundary paths. Throws when the run id leaves the
71
+ * shared grammar or either declared root escapes containment — before any
72
+ * caller has a path to write to.
73
+ */
74
+ export function resolveHostHandoffPaths(params) {
75
+ assertSubmissionRunId(params.runId, params.runIdLabel ?? "host handoff run id");
76
+ const root = resolve(params.root);
77
+ const artifactsDir = resolveContainedPath(root, params.artifactsDir, "artifactsDir");
78
+ const segments = params.runDirSegments ?? [];
79
+ const runDir = resolveContainedPath(artifactsDir, join("runs", params.runId, ...segments), "host handoff run directory");
80
+ return {
81
+ root,
82
+ artifactsDir,
83
+ runDir,
84
+ resultDir: join(runDir, "host-results"),
85
+ workloadPath: join(runDir, "host-workload.json"),
86
+ };
87
+ }
88
+ /**
89
+ * The bound path for one work item's submission — the SHARED rule, not a local
90
+ * copy of it. `<resultDir>/<sha256(id)>.json`, repository-relative and
91
+ * forward-slashed. This replaces the byte-equivalent private `resultPathFor`
92
+ * copies both twins carried; a divergence between them would have been silent
93
+ * on both sides.
94
+ */
95
+ export function hostHandoffResultPath(paths, id) {
96
+ return submissionPathFor({ root: paths.root, submissionDir: paths.resultDir }, id);
97
+ }
98
+ /** Absolute form of {@link hostHandoffResultPath}, for readers on disk. */
99
+ export function absoluteHostHandoffResultPath(paths, id) {
100
+ return resolveContainedPath(paths.root, hostHandoffResultPath(paths, id), `result path for ${id}`);
101
+ }
102
+ /** Content digest of one prompt text — the binding between ask and answer. */
103
+ export function promptSha256(promptText) {
104
+ return hashContent(promptText);
105
+ }
106
+ /** Content digest of one canonical JSON rendering. */
107
+ export function contentSha256(value) {
108
+ return hashContent(stableStringify(value));
109
+ }
110
+ // ── Envelope, item, and binding validation ──────────────────────────────────
111
+ //
112
+ // Both draws parse the SAME document family out of the run directory — a
113
+ // workload envelope carrying `work_items`, per-item trusted bindings keyed by
114
+ // work item, and a result map naming where each answer lands — and both used to
115
+ // re-derive the scaffolding by hand. The shapes below are the shared skeleton;
116
+ // a draw adds only its own contract version, its own item parser, and whatever
117
+ // domain fields its bindings carry.
118
+ /** The `{ contract_version, run_id, work_items }` envelope both workloads use. */
119
+ const WORKLOAD_ENVELOPE_KEYS = ["contract_version", "run_id", "work_items"];
120
+ /**
121
+ * Validate a persisted workload ENVELOPE against this run: exact keys, the
122
+ * draw's contract version, the run id, and an array of raw items. Item-level
123
+ * shape is the draw's parser ({@link parseAllWorkloadItems}); anything the
124
+ * persisted trusted binding further pins (a digest, a baseline) is the draw's
125
+ * policy layered on top of the `ok` case.
126
+ */
127
+ export function parseWorkloadEnvelope(value, params) {
128
+ if (!isRecord(value) ||
129
+ !hasExactKeys(value, WORKLOAD_ENVELOPE_KEYS) ||
130
+ value.contract_version !== params.contractVersion ||
131
+ value.run_id !== params.runId ||
132
+ !Array.isArray(value.work_items)) {
133
+ return { ok: false };
134
+ }
135
+ return { ok: true, rawItems: value.work_items };
136
+ }
137
+ /** Map raw items through the draw's parser; `null` when ANY item refuses. */
138
+ export function parseAllWorkloadItems(rawItems, parseItem) {
139
+ const items = [];
140
+ for (const raw of rawItems) {
141
+ const item = parseItem(raw);
142
+ if (item === null)
143
+ return null;
144
+ items.push(item);
145
+ }
146
+ return items;
147
+ }
148
+ /** Every id distinct — the duplicate-work-item refusal. */
149
+ export function idsAreUnique(ids) {
150
+ return new Set(ids).size === ids.length;
151
+ }
152
+ /**
153
+ * Strictly ascending in code-unit order — which is BOTH "sorted" and
154
+ * "duplicate-free", the two properties every persisted workload's id list must
155
+ * have for a re-derivation to compare equal byte-for-byte.
156
+ */
157
+ export function idsAreStrictlyAscending(ids) {
158
+ return !ids.some((id, index) => index > 0 && compareCodeUnits(ids[index - 1], id) >= 0);
159
+ }
160
+ /**
161
+ * The identity binding EVERY submitted result carries, identical on both
162
+ * draws: a non-empty `result_id`, this run's id, this work item's id, and the
163
+ * prompt digest of the ask. A refusal here is a REFUSAL, never a repair — the
164
+ * tool cannot know which of the three the host meant.
165
+ */
166
+ export function resultIdentityIsBound(value, params) {
167
+ return (typeof value.result_id === "string" &&
168
+ value.result_id.length > 0 &&
169
+ value.run_id === params.runId &&
170
+ value.work_item_id === params.workItemId &&
171
+ value.prompt_sha256 === params.promptSha256);
172
+ }
173
+ export function resultMapIdentity(items, entries) {
174
+ const byId = new Map(items.map((item) => [item.id, item]));
175
+ if (entries.length !== byId.size)
176
+ return { ok: false, reason: "coverage" };
177
+ const seen = new Set();
178
+ for (const entry of entries) {
179
+ const item = byId.get(entry.work_item_id);
180
+ if (item === undefined || seen.has(entry.work_item_id)) {
181
+ return { ok: false, reason: "coverage" };
182
+ }
183
+ if (entry.prompt_sha256 !== item.prompt.sha256 ||
184
+ entry.result_path !== item.result_path) {
185
+ return {
186
+ ok: false,
187
+ reason: "identity",
188
+ workItemId: entry.work_item_id,
189
+ };
190
+ }
191
+ seen.add(entry.work_item_id);
192
+ }
193
+ return { ok: true, byId };
194
+ }
195
+ /**
196
+ * First duplicate identity in `entries`, or null. The accepted-results ledger
197
+ * and any other keyed record derives its dedupe refusal from this rather than
198
+ * from a hand-rolled Set walk whose message and predicate can drift apart.
199
+ */
200
+ export function firstDuplicateIdentity(entries, identity) {
201
+ const seen = new Set();
202
+ for (const entry of entries) {
203
+ const key = identity(entry);
204
+ if (seen.has(key))
205
+ return entry;
206
+ seen.add(key);
207
+ }
208
+ return null;
209
+ }
210
+ //# sourceMappingURL=hostHandoffCore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostHandoffCore.js","sourceRoot":"","sources":["../../../src/shared/submission/hostHandoffCore.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,11 @@ export interface SubmissionLedgerEvent<TIssueCode extends string = SubmissionIss
22
22
  }
23
23
  /** `<artifactsDir>/submissions/submission-ledger.jsonl`. */
24
24
  export declare function submissionLedgerPath(artifactsDir: string): string;
25
- /** Append one event. The parent directory is created on demand. */
25
+ /**
26
+ * Append one event under the shared file lock, so concurrent appends cannot
27
+ * interleave mid-line. The parent directory is created on demand (the lock
28
+ * acquire creates its own parent; `appendNdjsonFile` creates the ledger's).
29
+ */
26
30
  export declare function appendSubmissionEvent<TIssueCode extends string = SubmissionIssueCode>(artifactsDir: string, event: SubmissionLedgerEvent<TIssueCode>): Promise<void>;
27
31
  /** Why one ledger line did not become an event. */
28
32
  export type SubmissionLedgerDropReason =
@@ -1 +1 @@
1
- {"version":3,"file":"submissionLedger.d.ts","sourceRoot":"","sources":["../../../src/shared/submission/submissionLedger.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,eAAO,MAAM,wCAAwC,EACnD,kCAA2C,CAAC;AAE9C,eAAO,MAAM,sBAAsB,oHA0BzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB,CACpC,UAAU,SAAS,MAAM,GAAG,mBAAmB;IAE/C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,wCAAwC,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,mEAAmE;AACnE,wBAAsB,qBAAqB,CACzC,UAAU,SAAS,MAAM,GAAG,mBAAmB,EAC/C,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/E;AAED,mDAAmD;AACnD,MAAM,MAAM,0BAA0B;AACpC,yEAAyE;AACvE,YAAY;AACd,sEAAsE;GACpE,yBAAyB,CAAC;AAE9B,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,oBAAoB,GAAG,SAAS,qBAAqB,EAAE,GAAG;IACpE,QAAQ,CAAC,MAAM,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACnD,CAAC;AAqBF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAkC/B"}
1
+ {"version":3,"file":"submissionLedger.d.ts","sourceRoot":"","sources":["../../../src/shared/submission/submissionLedger.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,eAAO,MAAM,wCAAwC,EACnD,kCAA2C,CAAC;AAE9C,eAAO,MAAM,sBAAsB,oHA0BzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB,CACpC,UAAU,SAAS,MAAM,GAAG,mBAAmB;IAE/C,QAAQ,CAAC,gBAAgB,EAAE,OAAO,wCAAwC,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEjE;AAcD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,SAAS,MAAM,GAAG,mBAAmB,EAC/C,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/E;AAED,mDAAmD;AACnD,MAAM,MAAM,0BAA0B;AACpC,yEAAyE;AACvE,YAAY;AACd,sEAAsE;GACpE,yBAAyB,CAAC;AAE9B,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,oBAAoB,GAAG,SAAS,qBAAqB,EAAE,GAAG;IACpE,QAAQ,CAAC,MAAM,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACnD,CAAC;AAqBF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA4C/B"}
@@ -17,6 +17,8 @@
17
17
  import { join } from "node:path";
18
18
  import { readFile } from "node:fs/promises";
19
19
  import { appendNdjsonFile } from "../io/json.js";
20
+ import { siblingLockPath } from "../io/lockedJsonStore.js";
21
+ import { withFileLock } from "../io/fileLock.js";
20
22
  import { discardOnSchemaVersionMismatch } from "../io/schemaVersion.js";
21
23
  import { submissionsDir } from "../io/auditToolsPaths.js";
22
24
  export const SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION = "submission-ledger-event/v1alpha1";
@@ -51,9 +53,27 @@ export const SUBMISSION_EVENT_KINDS = [
51
53
  export function submissionLedgerPath(artifactsDir) {
52
54
  return join(submissionsDir(artifactsDir), "submission-ledger.jsonl");
53
55
  }
54
- /** Append one event. The parent directory is created on demand. */
56
+ // Sibling lock serializing every append. Two concurrent appends used to be two
57
+ // independent open-append syscalls on one file: on Windows (and wherever O_APPEND
58
+ // is not what the runtime actually performs) they can interleave so one event's
59
+ // line lands INSIDE the other's, and both lines are then torn — the ledger
60
+ // silently loses an event, which is precisely the clean-vs-repaired collapse it
61
+ // exists to prevent. The name is the locked-JSON-store module's OWN derivation
62
+ // (`siblingLockPath`), so the ledger's lock is the same rule the stores use
63
+ // rather than a second spelling of it.
64
+ function ledgerLockPath(ledgerPath) {
65
+ return siblingLockPath(ledgerPath);
66
+ }
67
+ /**
68
+ * Append one event under the shared file lock, so concurrent appends cannot
69
+ * interleave mid-line. The parent directory is created on demand (the lock
70
+ * acquire creates its own parent; `appendNdjsonFile` creates the ledger's).
71
+ */
55
72
  export async function appendSubmissionEvent(artifactsDir, event) {
56
- await appendNdjsonFile(submissionLedgerPath(artifactsDir), event);
73
+ const ledgerPath = submissionLedgerPath(artifactsDir);
74
+ await withFileLock(ledgerLockPath(ledgerPath), async () => {
75
+ await appendNdjsonFile(ledgerPath, event);
76
+ });
57
77
  }
58
78
  function ledgerRead(events, dropped) {
59
79
  Object.defineProperty(events, "events", {
@@ -115,7 +135,17 @@ export async function readSubmissionLedger(artifactsDir) {
115
135
  continue;
116
136
  let parsed;
117
137
  try {
118
- parsed = JSON.parse(line);
138
+ const value = JSON.parse(line);
139
+ // A line that is valid JSON but not an OBJECT is still not an event: the
140
+ // version check below reads properties off it (`in`), which throws on a
141
+ // primitive or array and broke this function's documented never-throw
142
+ // guarantee — one stray line failed the whole call that records drift.
143
+ // Classified exactly like a torn line instead.
144
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
145
+ dropped.push({ line: lineNumber, reason: "unparsable" });
146
+ continue;
147
+ }
148
+ parsed = value;
119
149
  }
120
150
  catch {
121
151
  dropped.push({ line: lineNumber, reason: "unparsable" });
@@ -1 +1 @@
1
- {"version":3,"file":"submissionLedger.js","sourceRoot":"","sources":["../../../src/shared/submission/submissionLedger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"submissionLedger.js","sourceRoot":"","sources":["../../../src/shared/submission/submissionLedger.ts"],"names":[],"mappings":"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"}
@@ -18,4 +18,33 @@ export declare function partitionCommandsByDeclaredShape(commands: readonly stri
18
18
  commands: string[];
19
19
  refusals: string[];
20
20
  };
21
+ /**
22
+ * Split a command string into an argv array, so it can be spawned with
23
+ * `shell: false`.
24
+ *
25
+ * TOTAL, and its guarantee is stated in terms of `shell: false` — not in terms
26
+ * of a precondition a caller has to remember. Exactly two characters are
27
+ * special: an unquoted space ENDS a token, and a double quote toggles grouping
28
+ * and is dropped. EVERY other byte — including `' \ ^ % $` and backtick, and
29
+ * including `& | ; < > ( )` — is copied into the token literally, which under
30
+ * `shell: false` is precisely what the child receives, because no shell ever
31
+ * parses the result. So for any input this produces the argv that a shell-free
32
+ * spawn will actually deliver; it never silently drops meaning.
33
+ *
34
+ * What it does NOT do is decide whether a command was ADMISSIBLE. A string that
35
+ * fails {@link commandLeavesDeclaredShape} still splits — `a && b` becomes
36
+ * `["a", "&&", "b"]`, three literal argv tokens — and that argv is a faithful
37
+ * rendering of what `shell: false` would run, not an execution of the chain the
38
+ * author wrote. That is a declaration the contract cannot honour, so it must be
39
+ * REFUSED by the gate before it reaches a spawn; this function is not the place
40
+ * that decision is made, and it is not a shell parser standing in for one.
41
+ *
42
+ * Windows note: because `\` is an ordinary byte here, an absolute Windows path
43
+ * survives intact through the split (`C:\Program Files\nodejs\node.exe` stays
44
+ * one token when double-quoted). The declared-shape gate refuses `\` in every
45
+ * position, so such a path can only reach this function from a caller that did
46
+ * not gate — see {@link commandLeavesDeclaredShape}'s header for why the
47
+ * refusal is about the declaration rather than the spawn.
48
+ */
49
+ export declare function parseCommandString(command: string): string[];
21
50
  //# sourceMappingURL=commandShape.d.ts.map