audit-tools 0.41.1 → 0.42.1

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 (209) hide show
  1. package/dist/audit/cli/args.d.ts +0 -1
  2. package/dist/audit/cli/args.d.ts.map +1 -1
  3. package/dist/audit/cli/args.js +0 -7
  4. package/dist/audit/cli/args.js.map +1 -1
  5. package/dist/audit/cli/auditStep.d.ts +18 -0
  6. package/dist/audit/cli/auditStep.d.ts.map +1 -1
  7. package/dist/audit/cli/auditStep.js +35 -1
  8. package/dist/audit/cli/auditStep.js.map +1 -1
  9. package/dist/audit/cli/cleanup.d.ts +1 -0
  10. package/dist/audit/cli/cleanup.d.ts.map +1 -1
  11. package/dist/audit/cli/cleanup.js +22 -7
  12. package/dist/audit/cli/cleanup.js.map +1 -1
  13. package/dist/audit/cli/confirmIntentStep.d.ts.map +1 -1
  14. package/dist/audit/cli/confirmIntentStep.js +11 -0
  15. package/dist/audit/cli/confirmIntentStep.js.map +1 -1
  16. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  17. package/dist/audit/cli/dispatch/hostHandoff.js +19 -1
  18. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  19. package/dist/audit/cli/envelope.d.ts +0 -24
  20. package/dist/audit/cli/envelope.d.ts.map +1 -1
  21. package/dist/audit/cli/envelope.js +0 -18
  22. package/dist/audit/cli/envelope.js.map +1 -1
  23. package/dist/audit/cli/fanoutLanes.d.ts +24 -0
  24. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
  25. package/dist/audit/cli/fanoutLanes.js +46 -2
  26. package/dist/audit/cli/fanoutLanes.js.map +1 -1
  27. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  28. package/dist/audit/cli/nextStepCommand.js +19 -24
  29. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  30. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  31. package/dist/audit/cli/nextStepHelpers.js +20 -6
  32. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  33. package/dist/audit/cli/workerResult.d.ts +0 -13
  34. package/dist/audit/cli/workerResult.d.ts.map +1 -1
  35. package/dist/audit/cli/workerResult.js +0 -15
  36. package/dist/audit/cli/workerResult.js.map +1 -1
  37. package/dist/audit/contracts/workerSchemas.d.ts +13 -83
  38. package/dist/audit/contracts/workerSchemas.d.ts.map +1 -1
  39. package/dist/audit/contracts/workerSchemas.js +10 -4
  40. package/dist/audit/contracts/workerSchemas.js.map +1 -1
  41. package/dist/audit/orchestrator/advance.d.ts +30 -0
  42. package/dist/audit/orchestrator/advance.d.ts.map +1 -1
  43. package/dist/audit/orchestrator/advance.js +45 -2
  44. package/dist/audit/orchestrator/advance.js.map +1 -1
  45. package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -1
  46. package/dist/audit/orchestrator/designReviewPrompt.js +6 -4
  47. package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -1
  48. package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts +8 -0
  49. package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts.map +1 -1
  50. package/dist/audit/orchestrator/intentCheckpointExecutor.js +2 -0
  51. package/dist/audit/orchestrator/intentCheckpointExecutor.js.map +1 -1
  52. package/dist/audit/orchestrator/partitionTaskGraph.d.ts.map +1 -1
  53. package/dist/audit/orchestrator/partitionTaskGraph.js +2 -2
  54. package/dist/audit/orchestrator/partitionTaskGraph.js.map +1 -1
  55. package/dist/audit/orchestrator/reviewPacketSizing.d.ts +0 -1
  56. package/dist/audit/orchestrator/reviewPacketSizing.d.ts.map +1 -1
  57. package/dist/audit/orchestrator/reviewPacketSizing.js +0 -5
  58. package/dist/audit/orchestrator/reviewPacketSizing.js.map +1 -1
  59. package/dist/audit/orchestrator/reviewPackets.d.ts +8 -2
  60. package/dist/audit/orchestrator/reviewPackets.d.ts.map +1 -1
  61. package/dist/audit/orchestrator/reviewPackets.js +7 -8
  62. package/dist/audit/orchestrator/reviewPackets.js.map +1 -1
  63. package/dist/audit/orchestrator/taskAffinityGraph.d.ts +0 -6
  64. package/dist/audit/orchestrator/taskAffinityGraph.d.ts.map +1 -1
  65. package/dist/audit/orchestrator/taskAffinityGraph.js +0 -16
  66. package/dist/audit/orchestrator/taskAffinityGraph.js.map +1 -1
  67. package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -1
  68. package/dist/audit/orchestrator/taskBuilder.js +1 -2
  69. package/dist/audit/orchestrator/taskBuilder.js.map +1 -1
  70. package/dist/audit/reporting/synthesis.d.ts.map +1 -1
  71. package/dist/audit/reporting/synthesis.js +2 -3
  72. package/dist/audit/reporting/synthesis.js.map +1 -1
  73. package/dist/audit/reporting/workBlocks.d.ts +0 -1
  74. package/dist/audit/reporting/workBlocks.d.ts.map +1 -1
  75. package/dist/audit/reporting/workBlocks.js +4 -41
  76. package/dist/audit/reporting/workBlocks.js.map +1 -1
  77. package/dist/audit/systemic/systemicChallengeLoop.d.ts +0 -8
  78. package/dist/audit/systemic/systemicChallengeLoop.d.ts.map +1 -1
  79. package/dist/audit/systemic/systemicChallengeLoop.js +0 -9
  80. package/dist/audit/systemic/systemicChallengeLoop.js.map +1 -1
  81. package/dist/audit/types.d.ts +4 -4
  82. package/dist/remediate/contractPipeline/artifactStore.d.ts +19 -23
  83. package/dist/remediate/contractPipeline/artifactStore.d.ts.map +1 -1
  84. package/dist/remediate/contractPipeline/artifactStore.js +22 -29
  85. package/dist/remediate/contractPipeline/artifactStore.js.map +1 -1
  86. package/dist/remediate/contractPipeline/changeClassification.d.ts +0 -12
  87. package/dist/remediate/contractPipeline/changeClassification.d.ts.map +1 -1
  88. package/dist/remediate/contractPipeline/changeClassification.js +0 -101
  89. package/dist/remediate/contractPipeline/changeClassification.js.map +1 -1
  90. package/dist/remediate/contractPipeline/derive.d.ts +0 -42
  91. package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
  92. package/dist/remediate/contractPipeline/derive.js +0 -108
  93. package/dist/remediate/contractPipeline/derive.js.map +1 -1
  94. package/dist/remediate/index.d.ts +0 -1
  95. package/dist/remediate/index.d.ts.map +1 -1
  96. package/dist/remediate/index.js +5 -132
  97. package/dist/remediate/index.js.map +1 -1
  98. package/dist/remediate/intake.d.ts +0 -55
  99. package/dist/remediate/intake.d.ts.map +1 -1
  100. package/dist/remediate/intake.js +1 -81
  101. package/dist/remediate/intake.js.map +1 -1
  102. package/dist/remediate/phases/plan.d.ts +0 -1
  103. package/dist/remediate/phases/plan.d.ts.map +1 -1
  104. package/dist/remediate/phases/plan.js +1 -207
  105. package/dist/remediate/phases/plan.js.map +1 -1
  106. package/dist/remediate/state/types.d.ts +4 -4
  107. package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
  108. package/dist/remediate/steps/contractPipeline.js +15 -12
  109. package/dist/remediate/steps/contractPipeline.js.map +1 -1
  110. package/dist/remediate/steps/contractPipelinePrompts.d.ts +9 -9
  111. package/dist/remediate/steps/contractPipelinePrompts.d.ts.map +1 -1
  112. package/dist/remediate/steps/contractPipelinePrompts.js +26 -18
  113. package/dist/remediate/steps/contractPipelinePrompts.js.map +1 -1
  114. package/dist/remediate/steps/dispatch/hostHandoff.d.ts +0 -1
  115. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  116. package/dist/remediate/steps/dispatch/hostHandoff.js +3 -2
  117. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  118. package/dist/remediate/steps/dispatch.d.ts +0 -8
  119. package/dist/remediate/steps/dispatch.d.ts.map +1 -1
  120. package/dist/remediate/steps/dispatch.js +3 -9
  121. package/dist/remediate/steps/dispatch.js.map +1 -1
  122. package/dist/remediate/steps/nextStep.d.ts +0 -1
  123. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  124. package/dist/remediate/steps/nextStep.js +0 -1
  125. package/dist/remediate/steps/nextStep.js.map +1 -1
  126. package/dist/remediate/utils/fileIntegrity.d.ts +0 -8
  127. package/dist/remediate/utils/fileIntegrity.d.ts.map +1 -1
  128. package/dist/remediate/utils/fileIntegrity.js +5 -65
  129. package/dist/remediate/utils/fileIntegrity.js.map +1 -1
  130. package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -1
  131. package/dist/remediate/validation/contractPipelineGates.js +27 -19
  132. package/dist/remediate/validation/contractPipelineGates.js.map +1 -1
  133. package/dist/shared/analyzers/candidates.d.ts +6 -6
  134. package/dist/shared/analyzers/candidates.d.ts.map +1 -1
  135. package/dist/shared/analyzers/candidates.js +6 -6
  136. package/dist/shared/analyzers/candidates.js.map +1 -1
  137. package/dist/shared/chunkByBudget.d.ts +8 -8
  138. package/dist/shared/decompose/contentCoherence.d.ts +43 -273
  139. package/dist/shared/decompose/contentCoherence.d.ts.map +1 -1
  140. package/dist/shared/decompose/contentCoherence.js +120 -63
  141. package/dist/shared/decompose/contentCoherence.js.map +1 -1
  142. package/dist/shared/decompose/modularity.d.ts +17 -0
  143. package/dist/shared/decompose/modularity.d.ts.map +1 -1
  144. package/dist/shared/decompose/modularity.js +78 -3
  145. package/dist/shared/decompose/modularity.js.map +1 -1
  146. package/dist/shared/decompose/systemicChallenge.d.ts +4 -4
  147. package/dist/shared/decompose/workBlockSeams.d.ts +45 -0
  148. package/dist/shared/decompose/workBlockSeams.d.ts.map +1 -0
  149. package/dist/shared/decompose/workBlockSeams.js +82 -0
  150. package/dist/shared/decompose/workBlockSeams.js.map +1 -0
  151. package/dist/shared/index.d.ts +6 -5
  152. package/dist/shared/index.d.ts.map +1 -1
  153. package/dist/shared/index.js +6 -4
  154. package/dist/shared/index.js.map +1 -1
  155. package/dist/shared/io/auditToolsPaths.d.ts +0 -20
  156. package/dist/shared/io/auditToolsPaths.d.ts.map +1 -1
  157. package/dist/shared/io/auditToolsPaths.js +0 -24
  158. package/dist/shared/io/auditToolsPaths.js.map +1 -1
  159. package/dist/shared/loopCorePaths.d.ts.map +1 -1
  160. package/dist/shared/loopCorePaths.js +15 -9
  161. package/dist/shared/loopCorePaths.js.map +1 -1
  162. package/dist/shared/reporting/auditDeliverable.d.ts.map +1 -1
  163. package/dist/shared/reporting/auditDeliverable.js +8 -3
  164. package/dist/shared/reporting/auditDeliverable.js.map +1 -1
  165. package/dist/shared/types/finding.d.ts +119 -317
  166. package/dist/shared/types/finding.d.ts.map +1 -1
  167. package/dist/shared/types/finding.js +38 -11
  168. package/dist/shared/types/finding.js.map +1 -1
  169. package/dist/shared/validation/findingGrounding.d.ts +11 -0
  170. package/dist/shared/validation/findingGrounding.d.ts.map +1 -1
  171. package/dist/shared/validation/findingGrounding.js +21 -0
  172. package/dist/shared/validation/findingGrounding.js.map +1 -1
  173. package/dist/shared/validation/findingsReport.d.ts.map +1 -1
  174. package/dist/shared/validation/findingsReport.js +19 -7
  175. package/dist/shared/validation/findingsReport.js.map +1 -1
  176. package/docs/audit-pkg/contracts.md +2 -2
  177. package/docs/audit-pkg/development.md +1 -1
  178. package/docs/audit-pkg/release.md +20 -114
  179. package/package.json +6 -2
  180. package/schemas/audit_result.schema.json +0 -20
  181. package/schemas/audit_results.schema.json +0 -20
  182. package/schemas/finding.schema.json +0 -20
  183. package/skills/audit-code/SKILL.md +3 -7
  184. package/skills/audit-code/audit-code.prompt.md +5 -9
  185. package/skills/remediate-code/SKILL.md +0 -1
  186. package/dist/remediate/steps/dispatch/common.d.ts +0 -126
  187. package/dist/remediate/steps/dispatch/common.d.ts.map +0 -1
  188. package/dist/remediate/steps/dispatch/common.js +0 -204
  189. package/dist/remediate/steps/dispatch/common.js.map +0 -1
  190. package/dist/remediate/steps/dispatch/dagNodeFields.d.ts +0 -25
  191. package/dist/remediate/steps/dispatch/dagNodeFields.d.ts.map +0 -1
  192. package/dist/remediate/steps/dispatch/dagNodeFields.js +0 -5
  193. package/dist/remediate/steps/dispatch/dagNodeFields.js.map +0 -1
  194. package/dist/remediate/steps/dispatch/implementPrompt.d.ts +0 -47
  195. package/dist/remediate/steps/dispatch/implementPrompt.d.ts.map +0 -1
  196. package/dist/remediate/steps/dispatch/implementPrompt.js +0 -165
  197. package/dist/remediate/steps/dispatch/implementPrompt.js.map +0 -1
  198. package/dist/remediate/steps/dispatch/verifyCommands.d.ts +0 -144
  199. package/dist/remediate/steps/dispatch/verifyCommands.d.ts.map +0 -1
  200. package/dist/remediate/steps/dispatch/verifyCommands.js +0 -331
  201. package/dist/remediate/steps/dispatch/verifyCommands.js.map +0 -1
  202. package/dist/remediate/steps/dispatch/writeScope.d.ts +0 -43
  203. package/dist/remediate/steps/dispatch/writeScope.d.ts.map +0 -1
  204. package/dist/remediate/steps/dispatch/writeScope.js +0 -81
  205. package/dist/remediate/steps/dispatch/writeScope.js.map +0 -1
  206. package/dist/remediate/utils/hostAssets.d.ts +0 -21
  207. package/dist/remediate/utils/hostAssets.d.ts.map +0 -1
  208. package/dist/remediate/utils/hostAssets.js +0 -34
  209. package/dist/remediate/utils/hostAssets.js.map +0 -1
@@ -1,165 +0,0 @@
1
- import { readFileSync, readdirSync } from "node:fs";
2
- import { join, relative } from "node:path";
3
- import { toPromptPathToken, isBareBasename, resolveBasenameToTrackedPath, } from "audit-tools/shared";
4
- const TEST_FILE_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
5
- const WALK_SKIP_DIRS = new Set([
6
- "node_modules", ".git", "dist", "build", "coverage", "out",
7
- ".next", ".turbo", ".audit-tools",
8
- ]);
9
- /** Bounded recursive scan for test files under `root` (skips vendor/build dirs). */
10
- function walkTestFiles(root, max = 400) {
11
- const out = [];
12
- const stack = [root];
13
- let visited = 0;
14
- while (stack.length > 0 && out.length < max) {
15
- const dir = stack.pop();
16
- let entries;
17
- try {
18
- entries = readdirSync(dir, { withFileTypes: true });
19
- }
20
- catch {
21
- continue;
22
- }
23
- for (const entry of entries) {
24
- if (++visited > 20000)
25
- return out;
26
- if (entry.isDirectory()) {
27
- if (WALK_SKIP_DIRS.has(entry.name) || entry.name.startsWith(".test-"))
28
- continue;
29
- stack.push(join(dir, entry.name));
30
- }
31
- else if (TEST_FILE_RE.test(entry.name)) {
32
- out.push(join(dir, entry.name));
33
- if (out.length >= max)
34
- break;
35
- }
36
- }
37
- }
38
- return out;
39
- }
40
- /**
41
- * Walk the repo ONCE and read every test file's content (bounded). Built once per
42
- * dispatch and shared across all blocks so the filesystem walk + reads are not
43
- * repeated per block.
44
- */
45
- export function buildTestFileIndex(root) {
46
- const index = [];
47
- for (const testPath of walkTestFiles(root)) {
48
- let content;
49
- try {
50
- content = readFileSync(testPath, "utf8");
51
- }
52
- catch {
53
- continue;
54
- }
55
- index.push({ rel: relative(root, testPath).replace(/\\/g, "/"), content });
56
- }
57
- return index;
58
- }
59
- /**
60
- * Collect test files from `index` that reference any of `sourceFiles` by
61
- * module basename. When `packageRoot` is supplied (repo-relative prefix, e.g.
62
- * `packages/foo`), only test files under that package are considered —
63
- * otherwise all test files in the index are matched (existing behavior).
64
- */
65
- export function collectReferencingTests(index, sourceFiles, packageRoot) {
66
- if (sourceFiles.length === 0 || index.length === 0)
67
- return [];
68
- const basenames = sourceFiles
69
- .map((f) => (f.split(/[/\\]/).pop() ?? f).replace(/\.[cm]?[jt]sx?$/, ""))
70
- .filter((b) => b.length > 1);
71
- if (basenames.length === 0)
72
- return [];
73
- const needles = basenames.map((b) => new RegExp(`\\b${b.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`));
74
- const sourceSet = new Set(sourceFiles.map((f) => f.replace(/\\/g, "/")));
75
- // Normalize packageRoot to forward slashes and ensure it ends without trailing slash
76
- const pkgPrefix = packageRoot
77
- ? packageRoot.replace(/\\/g, "/").replace(/\/$/, "") + "/"
78
- : null;
79
- const result = [];
80
- for (const { rel, content } of index) {
81
- if (sourceSet.has(rel))
82
- continue;
83
- // If a package scope is set, skip files outside that package
84
- if (pkgPrefix && !rel.startsWith(pkgPrefix))
85
- continue;
86
- if (needles.some((re) => re.test(content)))
87
- result.push(rel);
88
- }
89
- return result;
90
- }
91
- // ---------------------------------------------------------------------------
92
- // Infra-modifying block detection
93
- // ---------------------------------------------------------------------------
94
- /**
95
- * The live dispatch/orchestration modules whose modification can break the
96
- * running engine mid-run. Derived from the REAL post-A12 source layout
97
- * (`src/remediate/...`) — this module IS one of them (`steps/dispatch.ts`), so
98
- * the list is anchored to the actual files on disk, not a hand-typed monorepo
99
- * path that drifts when the tree is reorganised (the pre-A12
100
- * `packages/remediate-code/...` list silently matched NOTHING after the
101
- * collapse, so every infra block rendered as non-infra). Each entry is the
102
- * module's path relative to the `src/remediate` area, forward-slash form.
103
- */
104
- const INFRA_MODULE_SUBPATHS = [
105
- "steps/nextStep.ts",
106
- "steps/dispatch.ts",
107
- "state/store.ts",
108
- "steps/contractPipeline.ts",
109
- "steps/stepWriter.ts",
110
- ];
111
- /**
112
- * The infra module sub-paths anchored under `src/remediate/` — the canonical
113
- * repo-relative form for the current (post-A12) single-package layout. A write
114
- * path matches when its normalised (forward-slash) form ends with one of these
115
- * segments, so an absolute worktree path
116
- * (`.../worktrees/foo/src/remediate/steps/dispatch.ts`), a repo-relative path
117
- * (`src/remediate/steps/dispatch.ts`), or a Windows backslash path all match,
118
- * while a same-basename file in another area (`src/audit/steps/dispatch.ts`)
119
- * does not.
120
- */
121
- const INFRA_FILE_SEGMENTS = INFRA_MODULE_SUBPATHS.map((sub) => `src/remediate/${sub}`);
122
- /**
123
- * Returns true when any path in `writePaths` is one of the live infra modules.
124
- * Paths are normalised to forward-slash form (win32 backslash → `/`) and matched
125
- * by trailing repo-relative segment so absolute/worktree/relative spellings all
126
- * resolve identically. Used to gate the live-surface verification section in the
127
- * implement prompt.
128
- */
129
- export function isInfraModifyingBlock(writePaths) {
130
- for (const p of writePaths) {
131
- const normalized = p.replace(/\\/g, "/");
132
- for (const segment of INFRA_FILE_SEGMENTS) {
133
- if (normalized === segment || normalized.endsWith("/" + segment)) {
134
- return true;
135
- }
136
- }
137
- }
138
- return false;
139
- }
140
- /**
141
- * INV-B3-5: resolve a cited source path to the token the worker should open.
142
- *
143
- * A bare basename (`advance.ts`) that uniquely resolves to one tracked path
144
- * (`src/audit/orchestrator/advance.ts`) is rewritten to that tracked path FIRST,
145
- * so it never surfaces as a broken `<worktreeRoot>/advance.ts` prefix that
146
- * misdirects the worker to a non-existent top-level file. Full / dotfile-dir /
147
- * already-absolute / drive-letter paths pass through unchanged; when a worktree
148
- * root is present, a relative path is prefixed onto it (unchanged behaviour). An
149
- * ambiguous or unresolvable basename is left as-is (monotonic — never a
150
- * regression on paths that already resolved).
151
- */
152
- export function resolveCitationPathForPrompt(rel, worktreeRoot, trackedPaths) {
153
- let target = rel;
154
- if (isBareBasename(rel)) {
155
- const resolved = resolveBasenameToTrackedPath(rel, trackedPaths);
156
- if (resolved)
157
- target = resolved;
158
- }
159
- if (!worktreeRoot)
160
- return target;
161
- if (target.startsWith("/") || /^[A-Za-z]:[/\\]/.test(target))
162
- return target;
163
- return toPromptPathToken(join(worktreeRoot, target));
164
- }
165
- //# sourceMappingURL=implementPrompt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"implementPrompt.js","sourceRoot":"","sources":["../../../../src/remediate/steps/dispatch/implementPrompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,4BAA4B,GAC7B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,YAAY,GAAG,8BAA8B,CAAC;AACpD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK;IAC1D,OAAO,EAAE,QAAQ,EAAE,cAAc;CAClC,CAAC,CAAC;AAEH,oFAAoF;AACpF,SAAS,aAAa,CAAC,IAAY,EAAE,GAAG,GAAG,GAAG;IAC5C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAa,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QACzB,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,EAAE,OAAO,GAAG,KAAK;gBAAE,OAAO,GAAG,CAAC;YAClC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBAChF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAChC,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG;oBAAE,MAAM;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAeD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,KAAK,MAAM,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAsB,EACtB,WAAqB,EACrB,WAAoB;IAEpB,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9D,MAAM,SAAS,GAAG,WAAW;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;SACxE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC,CACvE,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACzE,qFAAqF;IACrF,MAAM,SAAS,GAAG,WAAW;QAC3B,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG;QAC1D,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,KAAK,EAAE,CAAC;QACrC,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,6DAA6D;QAC7D,IAAI,SAAS,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS;QACtD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,qBAAqB,GAAG;IAC5B,mBAAmB;IACnB,mBAAmB;IACnB,gBAAgB;IAChB,2BAA2B;IAC3B,qBAAqB;CACb,CAAC;AAEX;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAsB,qBAAqB,CAAC,GAAG,CACtE,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,GAAG,EAAE,CAChC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAoB;IACxD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACzC,KAAK,MAAM,OAAO,IAAI,mBAAmB,EAAE,CAAC;YAC1C,IAAI,UAAU,KAAK,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC;gBACjE,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,4BAA4B,CAC1C,GAAW,EACX,YAAgC,EAChC,YAAiC;IAEjC,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,4BAA4B,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACjE,IAAI,QAAQ;YAAE,MAAM,GAAG,QAAQ,CAAC;IAClC,CAAC;IACD,IAAI,CAAC,YAAY;QAAE,OAAO,MAAM,CAAC;IACjC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5E,OAAO,iBAAiB,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;AACvD,CAAC"}
@@ -1,144 +0,0 @@
1
- import type { RemediationState } from "../../state/store.js";
2
- /**
3
- * The host manages the build centrally; a per-node verify command that runs
4
- * `npm run build` (or a `npm test` whose package script prepends a build) races
5
- * the central build's dist/ and is therefore forbidden. A command is build-free
6
- * only when it neither builds nor invokes a build-prepending test script.
7
- *
8
- * Forbidden (return false):
9
- * - `npm run build` / `npm run build -w ...` / `tsc` emit (`tsc -b`, `tsc --build`)
10
- * - bare `npm test` / `npm t` / `npm run test` (the package script prepends build)
11
- *
12
- * Allowed (return true):
13
- * - `npm run check` (no emit)
14
- * - `npx vitest run <path>` / `vitest run <path>`
15
- * - `node --test <path>`
16
- */
17
- export declare function isBuildFreeVerifyCommand(cmd: string): boolean;
18
- /**
19
- * Inject the tsx ESM loader into a bare `node --test <file>` command so the `.mjs`
20
- * node:test suites (which import `audit-tools/shared` via tsconfig `paths`, honored
21
- * only by tsx) resolve in a per-node worktree with no built `dist/`. A host- or
22
- * DAG-authored `node --test tests/audit/x.test.mjs` would otherwise fail module
23
- * resolution; the tool normalizes it so correctness can't depend on the host
24
- * remembering to add the loader. Idempotent: a command already carrying
25
- * `--import tsx/esm` or a `--loader` is left untouched. Mirrors the runner the
26
- * derived verify uses ({@link verifyCommandsForEdits}), so the displayed per-node
27
- * command and the in-process verify match.
28
- */
29
- export declare function normalizeNodeTestCommand(cmd: string): string;
30
- /**
31
- * True when `cmd` is a test-runner invocation whose target is a whole directory
32
- * or the entire suite rather than specific test files — e.g. `npx vitest run
33
- * tests/remediate`, `vitest run` (no path), `node --test tests/audit/`. Such a
34
- * command, run as an *additional* per-node verify alongside the scoped derive,
35
- * re-enters the FULL suite inside a per-node worktree. That is the structural
36
- * deadlock proven 2026-06-30: a source node's whole-suite verify fails on a
37
- * stale test owned by a DIFFERENT node, and concurrent worktrees race shared
38
- * test temp dirs. The derived verify already runs this node's OWN touched
39
- * tests, so a host/DAG-authored whole-suite command adds only risk — the tool
40
- * drops it rather than relying on the author to scope it (enforce-in-tooling,
41
- * never host discretion). A command naming at least one concrete `.test.<ext>`
42
- * file is scoped and kept.
43
- */
44
- export declare function isWholeSuiteTestCommand(cmd: string): boolean;
45
- /**
46
- * True when a verify command DEPENDS ON A BUILT `dist/` — either the command
47
- * string itself references a dist path (spawning the built CLI), or, when
48
- * `treeRoot` is supplied, a test FILE the command names imports/spawns dist in
49
- * its content. A per-node worktree has NO dist at all (`dist/` is gitignored
50
- * and only `node_modules` is junction-linked), so such a command false-reds
51
- * DETERMINISTICALLY under the by-design build-free accept gate — three accepts
52
- * in a row failed exactly this way (2026-07-23 dogfood, backlog "build-free
53
- * accept verify false-reds dist-importing targeted commands"). A central build
54
- * cannot fix it (it materializes MAIN's dist, not the worktree's), so the
55
- * remedy is the same as the whole-suite / cross-node families: drop from
56
- * per-node verify and defer to the central close gate, which runs on the
57
- * merged tree with a fresh build.
58
- *
59
- * Detection is deliberately conservative-toward-deferral: a false positive
60
- * (e.g. a comment mentioning `dist/`) only moves that command to the close
61
- * gate — never a lost signal, never a false-red.
62
- */
63
- export declare function isDistDependentVerifyCommand(cmd: string, treeRoot?: string): boolean;
64
- /**
65
- * True when a verify command names a test FILE that is WORKTREE-HOSTILE: its
66
- * content spawns the `audit-code` / `remediate-code` driver CLIs, which the
67
- * worker-context guard (v0.34.19, cwd-discriminated) mechanically refuses from
68
- * inside a node worktree — so the test deterministically fails there and the
69
- * node can NEVER accept (accept/reverify cluster defect 8). Same
70
- * conservative-toward-deferral contract as the dist probe: a false positive
71
- * only moves the command to the close gate (root cwd, where it runs fine).
72
- */
73
- export declare function isWorktreeHostileVerifyCommand(cmd: string, treeRoot: string): boolean;
74
- /**
75
- * Partition verify commands into the per-node-runnable set and the DEFERRED set
76
- * (dist-dependent OR worktree-hostile — both deterministically false-red inside
77
- * a build-free node worktree; the central close gate runs them on the merged
78
- * tree at the repo root). Content-level detection: `treeRoot` should be the
79
- * WORKTREE the verify would run in, so the scanned test files are the node's
80
- * own post-edit versions. The deferred list is DEDUPLICATED — the close gate's
81
- * replay drains it verbatim, so a doubled entry would run twice there.
82
- */
83
- export declare function partitionDeferredVerifyCommands(commands: string[], treeRoot: string): {
84
- kept: string[];
85
- deferred: string[];
86
- };
87
- /**
88
- * cg-1: collapse the per-node DEFERRED verify commands into the close gate's
89
- * single residual run. Exact-duplicate commands collapse to one (first-seen
90
- * order); when the close phase's own full-suite leg ran green
91
- * (`fullSuiteCovers`), any command that leg already covers is SUBSUMED and
92
- * dropped — a whole-suite runner invocation, or a vitest run whose path tokens
93
- * are all test files (the full vitest sweep runs every test file). Everything
94
- * else (e.g. `npm run check`, dist-spawning scripts) survives as the residual
95
- * the close gate must run exactly once. The 2026-08-06 run drained the raw
96
- * per-node lists verbatim — duplicate full `tests/audit` passes, a 2h close.
97
- */
98
- export declare function dedupeDeferredVerifyCommands(deferred: Iterable<string>, opts: {
99
- fullSuiteCovers: boolean;
100
- }): {
101
- residual: string[];
102
- subsumed: string[];
103
- };
104
- /**
105
- * Repo-relative path-like tokens in a shell command — tokens containing a `/` and a
106
- * file extension (e.g. `scripts/remediate/verify-hosts.mjs`, `tests/x.test.ts`).
107
- * Used to decide whether a targeted verify command is self-contained.
108
- */
109
- export declare function pathTokensInCommand(cmd: string): string[];
110
- /**
111
- * Keep only the targeted verify commands that are SELF-CONTAINED for this node:
112
- * every path-like token they reference is either one of the node's own paths (its
113
- * declared write set ∪ the files it actually edited on its branch) or already
114
- * present in the tree. A command referencing a path this node doesn't own and that
115
- * isn't in the tree depends on a SIBLING node's not-yet-created deliverable —
116
- * running it in per-node verify is a guaranteed-fail deadlock (proven 2026-07-03: a
117
- * node's `targeted_command` was `node scripts/remediate/verify-hosts.mjs`, another
118
- * node's pending output). Per-node verify must be self-contained; such a cross-node
119
- * command is dropped here and deferred to the integration/close gate. A command with
120
- * no path tokens (e.g. `npm run check`) is always kept.
121
- */
122
- export declare function selfContainedVerifyCommands(commands: string[], ownPaths: Iterable<string>, treeRoot: string): string[];
123
- /**
124
- * Derive a node's per-node verify commands from the test files it ACTUALLY touched
125
- * on its worktree branch (the git ground truth), instead of trusting host-authored
126
- * `targeted_commands` whose paths/runner can drift from where the worker put the
127
- * test. Always typechecks (`npm run check`, no emit), then runs ONLY this node's
128
- * own touched test files with the repo's runners — never the whole suite (which
129
- * would re-enter worktree-spawning tests inside a nested worktree). Build-free: the
130
- * host owns the central build; a node's own test imports the source it changed via
131
- * the tsx loader. Returns `[]` when there is no git ground truth so the caller can
132
- * skip the gate rather than fabricate a command.
133
- */
134
- /** Pure assembly (git-free) of the verify commands for a set of edited paths —
135
- * the testable core of {@link deriveVerifyCommandsFromBranch}. */
136
- export declare function verifyCommandsForEdits(editedFiles: Iterable<string>): string[];
137
- export declare function deriveVerifyCommandsFromBranch(root: string, branch: string): string[];
138
- /**
139
- * A node's own `targeted_commands` for the per-node verify (task_7d35176d) — the union
140
- * of the block's `targeted_commands` and its findings' `targeted_commands` (the
141
- * auditor-specified, fix-specific verification) bound into the host workload.
142
- */
143
- export declare function targetedCommandsForBlock(state: RemediationState, blockId: string): string[];
144
- //# sourceMappingURL=verifyCommands.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verifyCommands.d.ts","sourceRoot":"","sources":["../../../../src/remediate/steps/dispatch/verifyCommands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAO7D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA4B7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAU5D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAkBpF;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAgBrF;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAWxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC1B,IAAI,EAAE;IAAE,eAAe,EAAE,OAAO,CAAA;CAAE,GACjC;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAe5C;AAaD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAGzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,EAAE,CAUV;AAaD;;;;;;;;;;GAUG;AACH;mEACmE;AACnE,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAW9E;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAS3F"}
@@ -1,331 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { gitEditedFilesForBranch } from "./common.js";
4
- // ---------------------------------------------------------------------------
5
- // Build-free per-node verification commands (residual CE-001)
6
- // ---------------------------------------------------------------------------
7
- /**
8
- * The host manages the build centrally; a per-node verify command that runs
9
- * `npm run build` (or a `npm test` whose package script prepends a build) races
10
- * the central build's dist/ and is therefore forbidden. A command is build-free
11
- * only when it neither builds nor invokes a build-prepending test script.
12
- *
13
- * Forbidden (return false):
14
- * - `npm run build` / `npm run build -w ...` / `tsc` emit (`tsc -b`, `tsc --build`)
15
- * - bare `npm test` / `npm t` / `npm run test` (the package script prepends build)
16
- *
17
- * Allowed (return true):
18
- * - `npm run check` (no emit)
19
- * - `npx vitest run <path>` / `vitest run <path>`
20
- * - `node --test <path>`
21
- */
22
- export function isBuildFreeVerifyCommand(cmd) {
23
- if (cmd.trim().length === 0)
24
- return false;
25
- // INV-RSM-VERIFY-01 (COR-8c497987): judge each shell-chained INVOCATION on its
26
- // own flags, never the whole string — `tsc --noEmit && tsc -p build` must not
27
- // pass because a `--noEmit` appears SOMEWHERE in the command. Split on the
28
- // shell chain separators (&&, ||, ;, |, newline) first, then validate every
29
- // segment independently; one emitting segment forbids the whole command.
30
- const segments = cmd
31
- .replace(/\r\n/g, "\n")
32
- .split(/&&|\|\||[;|\n]/)
33
- .map((s) => s.trim().toLowerCase().replace(/\s+/g, " "))
34
- .filter((s) => s.length > 0);
35
- if (segments.length === 0)
36
- return false;
37
- for (const c of segments) {
38
- // Any explicit build step is forbidden.
39
- if (/\bnpm\s+run\s+build\b/.test(c))
40
- return false;
41
- if (/\btsc\b.*(-b\b|--build\b)/.test(c))
42
- return false;
43
- if (/(^|\s)tsc(\s|$)/.test(c) && !/--noemit\b/.test(c)) {
44
- // A bare `tsc` (or `tsc -p ...`) emits unless --noEmit is set — judged
45
- // per invocation, so a sibling segment's --noEmit cannot vouch for it.
46
- return false;
47
- }
48
- // A build-prepending `npm test` / `npm t` / `npm run test` is forbidden; the
49
- // build-free runner (vitest run / node --test) must be invoked directly.
50
- if (/\bnpm\s+(test|t)\b/.test(c))
51
- return false;
52
- if (/\bnpm\s+run\s+test\b/.test(c))
53
- return false;
54
- }
55
- return true;
56
- }
57
- /**
58
- * Inject the tsx ESM loader into a bare `node --test <file>` command so the `.mjs`
59
- * node:test suites (which import `audit-tools/shared` via tsconfig `paths`, honored
60
- * only by tsx) resolve in a per-node worktree with no built `dist/`. A host- or
61
- * DAG-authored `node --test tests/audit/x.test.mjs` would otherwise fail module
62
- * resolution; the tool normalizes it so correctness can't depend on the host
63
- * remembering to add the loader. Idempotent: a command already carrying
64
- * `--import tsx/esm` or a `--loader` is left untouched. Mirrors the runner the
65
- * derived verify uses ({@link verifyCommandsForEdits}), so the displayed per-node
66
- * command and the in-process verify match.
67
- */
68
- export function normalizeNodeTestCommand(cmd) {
69
- const trimmed = cmd.trim();
70
- if (!/^node\b/.test(trimmed))
71
- return cmd;
72
- if (!/\s--test\b/.test(trimmed))
73
- return cmd;
74
- if (/--import\s+tsx\/esm\b/.test(trimmed) || /--loader\b/.test(trimmed))
75
- return cmd;
76
- return trimmed.replace(/^node\b/, "node --import tsx/esm");
77
- }
78
- /**
79
- * True when `cmd` is a test-runner invocation whose target is a whole directory
80
- * or the entire suite rather than specific test files — e.g. `npx vitest run
81
- * tests/remediate`, `vitest run` (no path), `node --test tests/audit/`. Such a
82
- * command, run as an *additional* per-node verify alongside the scoped derive,
83
- * re-enters the FULL suite inside a per-node worktree. That is the structural
84
- * deadlock proven 2026-06-30: a source node's whole-suite verify fails on a
85
- * stale test owned by a DIFFERENT node, and concurrent worktrees race shared
86
- * test temp dirs. The derived verify already runs this node's OWN touched
87
- * tests, so a host/DAG-authored whole-suite command adds only risk — the tool
88
- * drops it rather than relying on the author to scope it (enforce-in-tooling,
89
- * never host discretion). A command naming at least one concrete `.test.<ext>`
90
- * file is scoped and kept.
91
- */
92
- export function isWholeSuiteTestCommand(cmd) {
93
- const c = cmd.trim();
94
- const isVitest = /\bvitest\b\s+run\b/.test(c) || /\bvitest\b(?!\s+run)/.test(c);
95
- const isNodeTest = /^node\b/.test(c) && /\s--test\b/.test(c);
96
- if (!isVitest && !isNodeTest)
97
- return false;
98
- // Tokenise; a concrete test file makes it scoped. Anything that is a runner
99
- // with no concrete test-file target (bare runner, or a directory/glob target)
100
- // is whole-suite.
101
- const namesConcreteTestFile = /(^|\s)[^\s]*\.test\.(ts|tsx|mjs|cjs|js)(\s|$)/.test(c);
102
- return !namesConcreteTestFile;
103
- }
104
- /**
105
- * True when a verify command DEPENDS ON A BUILT `dist/` — either the command
106
- * string itself references a dist path (spawning the built CLI), or, when
107
- * `treeRoot` is supplied, a test FILE the command names imports/spawns dist in
108
- * its content. A per-node worktree has NO dist at all (`dist/` is gitignored
109
- * and only `node_modules` is junction-linked), so such a command false-reds
110
- * DETERMINISTICALLY under the by-design build-free accept gate — three accepts
111
- * in a row failed exactly this way (2026-07-23 dogfood, backlog "build-free
112
- * accept verify false-reds dist-importing targeted commands"). A central build
113
- * cannot fix it (it materializes MAIN's dist, not the worktree's), so the
114
- * remedy is the same as the whole-suite / cross-node families: drop from
115
- * per-node verify and defer to the central close gate, which runs on the
116
- * merged tree with a fresh build.
117
- *
118
- * Detection is deliberately conservative-toward-deferral: a false positive
119
- * (e.g. a comment mentioning `dist/`) only moves that command to the close
120
- * gate — never a lost signal, never a false-red.
121
- */
122
- export function isDistDependentVerifyCommand(cmd, treeRoot) {
123
- if (/\bdist[\/\\]/.test(cmd))
124
- return true;
125
- if (treeRoot === undefined)
126
- return false;
127
- for (const token of pathTokensInCommand(cmd)) {
128
- if (!/\.test\.(mjs|cjs|js|ts|tsx)$/.test(token))
129
- continue;
130
- const p = join(treeRoot, token);
131
- if (!existsSync(p))
132
- continue;
133
- let content;
134
- try {
135
- content = readFileSync(p, "utf8");
136
- }
137
- catch {
138
- continue;
139
- }
140
- // `dist/`-style path (import/spawn) or a `"dist"` path-segment argument
141
- // (join(root, "dist", ...) — how the wrapper e2es locate the built entry).
142
- if (/\bdist[\/\\]/.test(content) || /["']dist["']/.test(content))
143
- return true;
144
- }
145
- return false;
146
- }
147
- /**
148
- * True when a verify command names a test FILE that is WORKTREE-HOSTILE: its
149
- * content spawns the `audit-code` / `remediate-code` driver CLIs, which the
150
- * worker-context guard (v0.34.19, cwd-discriminated) mechanically refuses from
151
- * inside a node worktree — so the test deterministically fails there and the
152
- * node can NEVER accept (accept/reverify cluster defect 8). Same
153
- * conservative-toward-deferral contract as the dist probe: a false positive
154
- * only moves the command to the close gate (root cwd, where it runs fine).
155
- */
156
- export function isWorktreeHostileVerifyCommand(cmd, treeRoot) {
157
- for (const token of pathTokensInCommand(cmd)) {
158
- if (!/\.test\.(mjs|cjs|js|ts|tsx)$/.test(token))
159
- continue;
160
- const p = join(treeRoot, token);
161
- if (!existsSync(p))
162
- continue;
163
- let content;
164
- try {
165
- content = readFileSync(p, "utf8");
166
- }
167
- catch {
168
- continue;
169
- }
170
- // The driver CLI names (bin or wrapper .mjs) appearing in test content —
171
- // spawn targets the worker-context guard refuses inside a worktree.
172
- if (/\b(?:audit|remediate)-code(?:\.mjs)?\b/.test(content))
173
- return true;
174
- }
175
- return false;
176
- }
177
- /**
178
- * Partition verify commands into the per-node-runnable set and the DEFERRED set
179
- * (dist-dependent OR worktree-hostile — both deterministically false-red inside
180
- * a build-free node worktree; the central close gate runs them on the merged
181
- * tree at the repo root). Content-level detection: `treeRoot` should be the
182
- * WORKTREE the verify would run in, so the scanned test files are the node's
183
- * own post-edit versions. The deferred list is DEDUPLICATED — the close gate's
184
- * replay drains it verbatim, so a doubled entry would run twice there.
185
- */
186
- export function partitionDeferredVerifyCommands(commands, treeRoot) {
187
- const kept = [];
188
- const deferred = new Set();
189
- for (const c of commands) {
190
- if (isDistDependentVerifyCommand(c, treeRoot) || isWorktreeHostileVerifyCommand(c, treeRoot)) {
191
- deferred.add(c);
192
- }
193
- else {
194
- kept.push(c);
195
- }
196
- }
197
- return { kept, deferred: [...deferred] };
198
- }
199
- /**
200
- * cg-1: collapse the per-node DEFERRED verify commands into the close gate's
201
- * single residual run. Exact-duplicate commands collapse to one (first-seen
202
- * order); when the close phase's own full-suite leg ran green
203
- * (`fullSuiteCovers`), any command that leg already covers is SUBSUMED and
204
- * dropped — a whole-suite runner invocation, or a vitest run whose path tokens
205
- * are all test files (the full vitest sweep runs every test file). Everything
206
- * else (e.g. `npm run check`, dist-spawning scripts) survives as the residual
207
- * the close gate must run exactly once. The 2026-08-06 run drained the raw
208
- * per-node lists verbatim — duplicate full `tests/audit` passes, a 2h close.
209
- */
210
- export function dedupeDeferredVerifyCommands(deferred, opts) {
211
- const residual = [];
212
- const subsumed = [];
213
- const seen = new Set();
214
- for (const raw of deferred) {
215
- const cmd = raw.trim();
216
- if (cmd.length === 0 || seen.has(cmd))
217
- continue;
218
- seen.add(cmd);
219
- if (opts.fullSuiteCovers && isSubsumedByFullSuite(cmd)) {
220
- subsumed.push(cmd);
221
- continue;
222
- }
223
- residual.push(cmd);
224
- }
225
- return { residual, subsumed };
226
- }
227
- /** A green full-suite leg covers whole-suite runs and test-file-only vitest runs. */
228
- function isSubsumedByFullSuite(cmd) {
229
- if (isWholeSuiteTestCommand(cmd))
230
- return true;
231
- if (!/\bvitest\b/.test(cmd))
232
- return false;
233
- const tokens = pathTokensInCommand(cmd);
234
- return (tokens.length > 0 &&
235
- tokens.every((t) => /\.test\.(ts|tsx|mts|cts|js|mjs|cjs)$/.test(t)));
236
- }
237
- /**
238
- * Repo-relative path-like tokens in a shell command — tokens containing a `/` and a
239
- * file extension (e.g. `scripts/remediate/verify-hosts.mjs`, `tests/x.test.ts`).
240
- * Used to decide whether a targeted verify command is self-contained.
241
- */
242
- export function pathTokensInCommand(cmd) {
243
- const tokens = cmd.match(/(?:[\w.@-]+[\/\\])+[\w.@-]+\.\w+/g) ?? [];
244
- return [...new Set(tokens.map((t) => t.replace(/\\/g, "/")))];
245
- }
246
- /**
247
- * Keep only the targeted verify commands that are SELF-CONTAINED for this node:
248
- * every path-like token they reference is either one of the node's own paths (its
249
- * declared write set ∪ the files it actually edited on its branch) or already
250
- * present in the tree. A command referencing a path this node doesn't own and that
251
- * isn't in the tree depends on a SIBLING node's not-yet-created deliverable —
252
- * running it in per-node verify is a guaranteed-fail deadlock (proven 2026-07-03: a
253
- * node's `targeted_command` was `node scripts/remediate/verify-hosts.mjs`, another
254
- * node's pending output). Per-node verify must be self-contained; such a cross-node
255
- * command is dropped here and deferred to the integration/close gate. A command with
256
- * no path tokens (e.g. `npm run check`) is always kept.
257
- */
258
- export function selfContainedVerifyCommands(commands, ownPaths, treeRoot) {
259
- const owned = new Set([...ownPaths].map((p) => p.replace(/\\/g, "/")));
260
- return commands.filter((cmd) => {
261
- for (const token of pathTokensInCommand(cmd)) {
262
- if (owned.has(token))
263
- continue;
264
- if (existsSync(join(treeRoot, token)))
265
- continue;
266
- return false;
267
- }
268
- return true;
269
- });
270
- }
271
- /** A repo-relative test path → the runner that executes that file directly. */
272
- function verifyRunnerForTestFile(repoRelPath) {
273
- // ONE vitest runner across all suites (audit / shared / remediate). The node:test
274
- // split was retired 2026-07-02, so every tracked `.test.mjs` / `.test.ts` file is a
275
- // vitest file — running a `.mjs` vitest suite under `node --test` throws "Vitest
276
- // failed to access its internal state". vitest resolves `audit-tools/shared` via its
277
- // config alias, so a per-node worktree needs no prior build (`npx vitest run <file>`).
278
- if (/^tests\/.+\.test\.(mjs|ts|tsx)$/.test(repoRelPath))
279
- return "vitest";
280
- return undefined;
281
- }
282
- /**
283
- * Derive a node's per-node verify commands from the test files it ACTUALLY touched
284
- * on its worktree branch (the git ground truth), instead of trusting host-authored
285
- * `targeted_commands` whose paths/runner can drift from where the worker put the
286
- * test. Always typechecks (`npm run check`, no emit), then runs ONLY this node's
287
- * own touched test files with the repo's runners — never the whole suite (which
288
- * would re-enter worktree-spawning tests inside a nested worktree). Build-free: the
289
- * host owns the central build; a node's own test imports the source it changed via
290
- * the tsx loader. Returns `[]` when there is no git ground truth so the caller can
291
- * skip the gate rather than fabricate a command.
292
- */
293
- /** Pure assembly (git-free) of the verify commands for a set of edited paths —
294
- * the testable core of {@link deriveVerifyCommandsFromBranch}. */
295
- export function verifyCommandsForEdits(editedFiles) {
296
- const vitestTests = [];
297
- for (const f of editedFiles) {
298
- const rel = f.replace(/\\/g, "/");
299
- if (verifyRunnerForTestFile(rel) === "vitest")
300
- vitestTests.push(rel);
301
- }
302
- const cmds = ["npm run check"];
303
- if (vitestTests.length > 0) {
304
- cmds.push(`npx vitest run ${vitestTests.sort().join(" ")}`);
305
- }
306
- return cmds;
307
- }
308
- export function deriveVerifyCommandsFromBranch(root, branch) {
309
- const edited = gitEditedFilesForBranch(root, branch);
310
- if (!edited.available)
311
- return [];
312
- return verifyCommandsForEdits(edited.files);
313
- }
314
- /**
315
- * A node's own `targeted_commands` for the per-node verify (task_7d35176d) — the union
316
- * of the block's `targeted_commands` and its findings' `targeted_commands` (the
317
- * auditor-specified, fix-specific verification) bound into the host workload.
318
- */
319
- export function targetedCommandsForBlock(state, blockId) {
320
- const block = state.plan?.blocks?.find((b) => b.block_id === blockId);
321
- if (!block)
322
- return [];
323
- const out = [...(block.targeted_commands ?? [])];
324
- for (const fid of block.items) {
325
- const finding = state.plan?.findings?.find((f) => f.id === fid);
326
- for (const c of finding?.targeted_commands ?? [])
327
- out.push(c);
328
- }
329
- return [...new Set(out)];
330
- }
331
- //# sourceMappingURL=verifyCommands.js.map