@mjasnikovs/pi-task 0.38.28 → 0.38.30

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 (370) hide show
  1. package/dist/config/config.d.ts +70 -70
  2. package/dist/config/config.js +26 -35
  3. package/dist/config/extension-list.d.ts +6 -5
  4. package/dist/config/extension-list.js +3 -2
  5. package/dist/config/reasoning-args.d.ts +9 -7
  6. package/dist/config/reasoning-args.js +12 -10
  7. package/dist/config/reasoning.d.ts +44 -105
  8. package/dist/config/reasoning.js +27 -704
  9. package/dist/config/register.d.ts +34 -48
  10. package/dist/config/register.js +41 -51
  11. package/dist/config/tool-list.d.ts +16 -16
  12. package/dist/config/tool-list.js +1 -1
  13. package/dist/remote/bridge.d.ts +19 -10
  14. package/dist/remote/bridge.js +3 -2
  15. package/dist/remote/broadcast.js +3 -1
  16. package/dist/remote/events.js +12 -11
  17. package/dist/remote/history.d.ts +1 -1
  18. package/dist/remote/protocol.d.ts +6 -3
  19. package/dist/remote/protocol.js +2 -1
  20. package/dist/remote/push.d.ts +16 -16
  21. package/dist/remote/push.js +27 -27
  22. package/dist/remote/register.d.ts +3 -3
  23. package/dist/remote/register.js +17 -19
  24. package/dist/remote/server.d.ts +9 -8
  25. package/dist/remote/server.js +15 -14
  26. package/dist/remote/session-state.d.ts +5 -4
  27. package/dist/remote/session-state.js +8 -5
  28. package/dist/remote/sw.d.ts +7 -6
  29. package/dist/remote/sw.js +7 -6
  30. package/dist/remote/tailscale.d.ts +4 -2
  31. package/dist/remote/tailscale.js +4 -2
  32. package/dist/remote/ui-highlight.js +6 -5
  33. package/dist/remote/ui-render.js +4 -4
  34. package/dist/remote/ui-script.js +24 -24
  35. package/dist/remote/ui-styles.d.ts +1 -1
  36. package/dist/remote/ui-styles.js +10 -13
  37. package/dist/remote/ui-tools.js +9 -6
  38. package/dist/shared/child-extensions.d.ts +29 -17
  39. package/dist/shared/child-extensions.js +29 -17
  40. package/dist/shared/child-output.d.ts +30 -24
  41. package/dist/shared/child-output.js +25 -17
  42. package/dist/shared/child-process.d.ts +47 -40
  43. package/dist/shared/child-process.js +50 -59
  44. package/dist/shared/command-watchdog.d.ts +22 -16
  45. package/dist/shared/command-watchdog.js +28 -21
  46. package/dist/shared/fs-text.d.ts +16 -10
  47. package/dist/shared/fs-text.js +16 -10
  48. package/dist/shared/git-runner.d.ts +25 -25
  49. package/dist/shared/git-runner.js +25 -25
  50. package/dist/shared/leaked-tool-call.d.ts +17 -11
  51. package/dist/shared/leaked-tool-call.js +23 -15
  52. package/dist/shared/model-endpoint.d.ts +29 -16
  53. package/dist/shared/model-endpoint.js +33 -21
  54. package/dist/shared/pi-invocation.d.ts +7 -4
  55. package/dist/shared/pi-invocation.js +12 -7
  56. package/dist/shared/pkg-version.d.ts +13 -5
  57. package/dist/shared/pkg-version.js +13 -5
  58. package/dist/shared/reasoning-capability.d.ts +35 -24
  59. package/dist/shared/reasoning-capability.js +35 -24
  60. package/dist/shared/stream-watchdog.d.ts +60 -44
  61. package/dist/shared/stream-watchdog.js +62 -45
  62. package/dist/task/accept-debt.d.ts +41 -43
  63. package/dist/task/accept-debt.js +73 -65
  64. package/dist/task/api-synthesis.d.ts +24 -21
  65. package/dist/task/api-synthesis.js +32 -26
  66. package/dist/task/apis-contract.d.ts +32 -64
  67. package/dist/task/apis-contract.js +32 -64
  68. package/dist/task/artifact-closure.d.ts +27 -13
  69. package/dist/task/artifact-closure.js +95 -67
  70. package/dist/task/auto-commit.d.ts +46 -35
  71. package/dist/task/auto-commit.js +51 -38
  72. package/dist/task/auto-io.d.ts +45 -25
  73. package/dist/task/auto-io.js +57 -29
  74. package/dist/task/auto-orchestrator.d.ts +26 -24
  75. package/dist/task/auto-orchestrator.js +178 -162
  76. package/dist/task/auto-prompts.d.ts +36 -24
  77. package/dist/task/auto-prompts.js +40 -26
  78. package/dist/task/autofix-ledger.d.ts +27 -25
  79. package/dist/task/autofix-ledger.js +29 -26
  80. package/dist/task/batch-test-task.d.ts +20 -12
  81. package/dist/task/batch-test-task.js +67 -60
  82. package/dist/task/boot-probe.d.ts +60 -44
  83. package/dist/task/boot-probe.js +91 -72
  84. package/dist/task/cancel-input.d.ts +30 -16
  85. package/dist/task/cancel-input.js +20 -11
  86. package/dist/task/cancel-points.d.ts +27 -20
  87. package/dist/task/cancel-points.js +30 -22
  88. package/dist/task/child-runner.d.ts +46 -51
  89. package/dist/task/child-runner.js +48 -49
  90. package/dist/task/child-status.d.ts +23 -16
  91. package/dist/task/child-status.js +23 -16
  92. package/dist/task/clamp-output.js +12 -5
  93. package/dist/task/command-run.d.ts +31 -28
  94. package/dist/task/command-run.js +44 -35
  95. package/dist/task/command-shrink.d.ts +25 -18
  96. package/dist/task/command-shrink.js +37 -31
  97. package/dist/task/command-watchdog.d.ts +9 -6
  98. package/dist/task/command-watchdog.js +21 -15
  99. package/dist/task/context-attribution.d.ts +34 -26
  100. package/dist/task/context-attribution.js +34 -26
  101. package/dist/task/context-silence.d.ts +39 -29
  102. package/dist/task/context-silence.js +35 -25
  103. package/dist/task/context-usage.d.ts +25 -7
  104. package/dist/task/context-usage.js +21 -6
  105. package/dist/task/contracts.d.ts +8 -4
  106. package/dist/task/contracts.js +25 -17
  107. package/dist/task/coverage-loop.d.ts +22 -18
  108. package/dist/task/coverage-loop.js +35 -30
  109. package/dist/task/critique-probes.d.ts +13 -14
  110. package/dist/task/critique-probes.js +50 -39
  111. package/dist/task/debug-log.d.ts +13 -5
  112. package/dist/task/debug-log.js +32 -20
  113. package/dist/task/decompose-fidelity.d.ts +11 -9
  114. package/dist/task/decompose-fidelity.js +38 -33
  115. package/dist/task/decompose-granularity.d.ts +41 -38
  116. package/dist/task/decompose-granularity.js +41 -38
  117. package/dist/task/deep-render-check.d.ts +22 -14
  118. package/dist/task/deep-render-check.js +40 -31
  119. package/dist/task/dropped-input.d.ts +12 -7
  120. package/dist/task/dropped-input.js +5 -2
  121. package/dist/task/enforce-attribution.d.ts +38 -47
  122. package/dist/task/enforce-attribution.js +46 -52
  123. package/dist/task/enforce-guidelines.d.ts +31 -20
  124. package/dist/task/enforce-guidelines.js +32 -21
  125. package/dist/task/enrichment.d.ts +7 -2
  126. package/dist/task/enrichment.js +26 -14
  127. package/dist/task/env-notes.d.ts +16 -7
  128. package/dist/task/env-notes.js +48 -31
  129. package/dist/task/env-template-closure.d.ts +4 -4
  130. package/dist/task/env-template-closure.js +42 -34
  131. package/dist/task/external-context.d.ts +28 -21
  132. package/dist/task/external-context.js +17 -12
  133. package/dist/task/failure-classifier.d.ts +4 -5
  134. package/dist/task/failure-classifier.js +6 -7
  135. package/dist/task/file-inventory.d.ts +15 -11
  136. package/dist/task/file-inventory.js +25 -22
  137. package/dist/task/final-gate-fix.d.ts +74 -86
  138. package/dist/task/final-gate-fix.js +97 -116
  139. package/dist/task/final-gate-progress.d.ts +29 -46
  140. package/dist/task/final-gate-progress.js +40 -51
  141. package/dist/task/final-gate.d.ts +64 -97
  142. package/dist/task/final-gate.js +192 -199
  143. package/dist/task/fix-child.d.ts +21 -27
  144. package/dist/task/fix-child.js +21 -27
  145. package/dist/task/foreign-path.d.ts +6 -5
  146. package/dist/task/foreign-path.js +0 -0
  147. package/dist/task/frozen-conflict.d.ts +9 -10
  148. package/dist/task/frozen-conflict.js +61 -64
  149. package/dist/task/frozen-path-guard.d.ts +35 -14
  150. package/dist/task/frozen-path-guard.js +56 -39
  151. package/dist/task/gate-child.d.ts +27 -28
  152. package/dist/task/gate-child.js +37 -35
  153. package/dist/task/gate-deps.d.ts +34 -27
  154. package/dist/task/gate-deps.js +169 -159
  155. package/dist/task/gate-tally.d.ts +77 -80
  156. package/dist/task/gate-tally.js +65 -68
  157. package/dist/task/git-state-guard.d.ts +15 -11
  158. package/dist/task/git-state-guard.js +76 -66
  159. package/dist/task/impl-widget.d.ts +25 -16
  160. package/dist/task/impl-widget.js +27 -17
  161. package/dist/task/implementation-thinking.d.ts +33 -31
  162. package/dist/task/implementation-thinking.js +5 -6
  163. package/dist/task/implementation-turn.d.ts +34 -31
  164. package/dist/task/implementation-turn.js +29 -27
  165. package/dist/task/inline-markdown.d.ts +20 -7
  166. package/dist/task/inline-markdown.js +15 -6
  167. package/dist/task/launch-config-gap.js +25 -39
  168. package/dist/task/launch-contract.d.ts +18 -21
  169. package/dist/task/launch-contract.js +28 -30
  170. package/dist/task/launch-manifest.d.ts +6 -2
  171. package/dist/task/launch-manifest.js +35 -34
  172. package/dist/task/ledger.js +16 -14
  173. package/dist/task/lint-fix.d.ts +6 -8
  174. package/dist/task/lint-fix.js +67 -69
  175. package/dist/task/loop-detector.d.ts +9 -8
  176. package/dist/task/loop-detector.js +16 -12
  177. package/dist/task/mid-run-input.d.ts +17 -15
  178. package/dist/task/mid-run-input.js +17 -15
  179. package/dist/task/orchestrator.d.ts +24 -28
  180. package/dist/task/orchestrator.js +62 -64
  181. package/dist/task/orientation.d.ts +18 -23
  182. package/dist/task/orientation.js +24 -31
  183. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  184. package/dist/task/owned-freeze-conflict.js +52 -85
  185. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  186. package/dist/task/owned-freeze-reassign.js +41 -61
  187. package/dist/task/parsers.d.ts +4 -2
  188. package/dist/task/parsers.js +4 -4
  189. package/dist/task/phases.d.ts +41 -48
  190. package/dist/task/phases.js +180 -248
  191. package/dist/task/plan-io.d.ts +6 -7
  192. package/dist/task/plan-io.js +6 -7
  193. package/dist/task/plan-orchestrator.d.ts +10 -8
  194. package/dist/task/plan-orchestrator.js +14 -10
  195. package/dist/task/plan-prompts.d.ts +6 -5
  196. package/dist/task/plan-prompts.js +6 -5
  197. package/dist/task/plan-readonly.d.ts +4 -5
  198. package/dist/task/plan-readonly.js +4 -5
  199. package/dist/task/plan-rounds.d.ts +17 -29
  200. package/dist/task/plan-rounds.js +21 -34
  201. package/dist/task/plan-session.d.ts +58 -72
  202. package/dist/task/plan-session.js +61 -83
  203. package/dist/task/probe-gaming.d.ts +28 -27
  204. package/dist/task/probe-gaming.js +0 -0
  205. package/dist/task/prohibition-probe.d.ts +14 -16
  206. package/dist/task/prompts.d.ts +3 -4
  207. package/dist/task/prompts.js +17 -26
  208. package/dist/task/qa-transcript.d.ts +15 -22
  209. package/dist/task/qa-transcript.js +15 -21
  210. package/dist/task/question-box.d.ts +17 -13
  211. package/dist/task/question-box.js +19 -15
  212. package/dist/task/question-dedup.d.ts +6 -7
  213. package/dist/task/question-dedup.js +13 -14
  214. package/dist/task/question-dialog.d.ts +22 -32
  215. package/dist/task/question-dialog.js +22 -32
  216. package/dist/task/question-source.d.ts +18 -44
  217. package/dist/task/question-source.js +22 -51
  218. package/dist/task/refuted-constraint.d.ts +11 -31
  219. package/dist/task/refuted-constraint.js +27 -51
  220. package/dist/task/regenerable-artifacts.d.ts +12 -31
  221. package/dist/task/regenerable-artifacts.js +12 -31
  222. package/dist/task/render-check.d.ts +11 -22
  223. package/dist/task/render-check.js +33 -46
  224. package/dist/task/repo-health-check.d.ts +10 -14
  225. package/dist/task/repo-health-check.js +17 -23
  226. package/dist/task/requirements.d.ts +38 -71
  227. package/dist/task/requirements.js +78 -126
  228. package/dist/task/research-fanout-budget.d.ts +51 -88
  229. package/dist/task/research-fanout-budget.js +51 -88
  230. package/dist/task/research-worker.d.ts +33 -36
  231. package/dist/task/research-worker.js +39 -61
  232. package/dist/task/resume-gap.d.ts +14 -15
  233. package/dist/task/root-cause-repair.d.ts +9 -9
  234. package/dist/task/root-cause-repair.js +28 -40
  235. package/dist/task/run-bracket.d.ts +10 -13
  236. package/dist/task/run-end.d.ts +12 -22
  237. package/dist/task/run-end.js +8 -16
  238. package/dist/task/run-final-gate.d.ts +19 -21
  239. package/dist/task/run-final-gate.js +62 -80
  240. package/dist/task/runner-globs.d.ts +12 -13
  241. package/dist/task/runner-globs.js +12 -13
  242. package/dist/task/runner-resolve.d.ts +9 -9
  243. package/dist/task/runner-resolve.js +22 -23
  244. package/dist/task/script-escape.d.ts +10 -12
  245. package/dist/task/script-escape.js +13 -14
  246. package/dist/task/serve-entry.d.ts +1 -1
  247. package/dist/task/serve-entry.js +22 -25
  248. package/dist/task/service-blocks.js +4 -2
  249. package/dist/task/shipped-source.d.ts +11 -29
  250. package/dist/task/shipped-source.js +11 -29
  251. package/dist/task/skip-escape.js +10 -14
  252. package/dist/task/spec-urls.d.ts +26 -65
  253. package/dist/task/spec-urls.js +26 -65
  254. package/dist/task/spec-validation.d.ts +17 -20
  255. package/dist/task/spec-validation.js +17 -20
  256. package/dist/task/stall-detector.d.ts +23 -30
  257. package/dist/task/stall-detector.js +23 -30
  258. package/dist/task/stream-watchdog.d.ts +14 -12
  259. package/dist/task/stream-watchdog.js +14 -12
  260. package/dist/task/substitution-probe.d.ts +17 -20
  261. package/dist/task/substitution-probe.js +17 -20
  262. package/dist/task/task-gates.d.ts +36 -41
  263. package/dist/task/task-gates.js +95 -106
  264. package/dist/task/task-io.d.ts +4 -4
  265. package/dist/task/task-io.js +4 -4
  266. package/dist/task/task-parsers.js +4 -3
  267. package/dist/task/task-provenance.d.ts +2 -2
  268. package/dist/task/task-provenance.js +11 -13
  269. package/dist/task/task-types.d.ts +4 -3
  270. package/dist/task/terminal-outcome.d.ts +14 -16
  271. package/dist/task/terminal-outcome.js +12 -14
  272. package/dist/task/test-assembly.d.ts +13 -20
  273. package/dist/task/test-assembly.js +13 -20
  274. package/dist/task/timings.d.ts +5 -3
  275. package/dist/task/timings.js +5 -3
  276. package/dist/task/title-label.d.ts +9 -4
  277. package/dist/task/title-label.js +9 -4
  278. package/dist/task/type-only-answer.d.ts +44 -52
  279. package/dist/task/type-only-answer.js +44 -52
  280. package/dist/task/unfailable-command.d.ts +18 -24
  281. package/dist/task/unfailable-command.js +21 -27
  282. package/dist/task/unknown-routing.d.ts +10 -4
  283. package/dist/task/unknown-routing.js +10 -4
  284. package/dist/task/user-directives.d.ts +5 -8
  285. package/dist/task/user-directives.js +5 -8
  286. package/dist/task/verify-quality.d.ts +18 -22
  287. package/dist/task/verify-quality.js +45 -46
  288. package/dist/task/verify-reconcile.d.ts +15 -10
  289. package/dist/task/verify-reconcile.js +45 -43
  290. package/dist/task/verify-resolution.d.ts +24 -20
  291. package/dist/task/verify-resolution.js +51 -50
  292. package/dist/task/verify-work.d.ts +59 -66
  293. package/dist/task/verify-work.js +101 -138
  294. package/dist/task/widget.d.ts +15 -14
  295. package/dist/task/widget.js +22 -17
  296. package/dist/task/wiring-claims.d.ts +25 -32
  297. package/dist/task/wiring-claims.js +30 -35
  298. package/dist/task/write-guard.d.ts +39 -39
  299. package/dist/task/write-guard.js +48 -51
  300. package/dist/task/yolo.d.ts +34 -30
  301. package/dist/task/yolo.js +42 -37
  302. package/dist/workers/abstention.d.ts +21 -41
  303. package/dist/workers/abstention.js +27 -48
  304. package/dist/workers/brave-search.d.ts +4 -3
  305. package/dist/workers/brave-search.js +5 -2
  306. package/dist/workers/brave-warning.d.ts +7 -4
  307. package/dist/workers/brave-warning.js +19 -7
  308. package/dist/workers/ddg-search.d.ts +6 -6
  309. package/dist/workers/ddg-search.js +18 -12
  310. package/dist/workers/docs-cache.js +5 -2
  311. package/dist/workers/docs-chunk.d.ts +30 -37
  312. package/dist/workers/docs-chunk.js +37 -41
  313. package/dist/workers/docs-core.d.ts +28 -44
  314. package/dist/workers/docs-core.js +25 -44
  315. package/dist/workers/docs-index.js +4 -3
  316. package/dist/workers/docs-lookup.d.ts +15 -22
  317. package/dist/workers/docs-lookup.js +12 -21
  318. package/dist/workers/docs-project.d.ts +15 -9
  319. package/dist/workers/docs-project.js +17 -10
  320. package/dist/workers/docs-resolve.d.ts +19 -20
  321. package/dist/workers/docs-resolve.js +35 -32
  322. package/dist/workers/docs-retrieve.d.ts +5 -6
  323. package/dist/workers/docs-retrieve.js +18 -15
  324. package/dist/workers/exa-search.d.ts +9 -6
  325. package/dist/workers/exa-search.js +23 -12
  326. package/dist/workers/fetch-core.d.ts +13 -16
  327. package/dist/workers/fetch-core.js +23 -23
  328. package/dist/workers/focused-extractor.d.ts +12 -12
  329. package/dist/workers/focused-extractor.js +16 -19
  330. package/dist/workers/html-clean.js +24 -14
  331. package/dist/workers/http-request.d.ts +28 -20
  332. package/dist/workers/http-request.js +22 -17
  333. package/dist/workers/npm-version.d.ts +28 -11
  334. package/dist/workers/npm-version.js +24 -15
  335. package/dist/workers/phantom-imports.d.ts +15 -12
  336. package/dist/workers/phantom-imports.js +30 -24
  337. package/dist/workers/pi-worker-core.d.ts +86 -54
  338. package/dist/workers/pi-worker-core.js +112 -112
  339. package/dist/workers/pi-worker-docs.d.ts +24 -19
  340. package/dist/workers/pi-worker-docs.js +67 -76
  341. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  342. package/dist/workers/pi-worker-fetch.js +27 -19
  343. package/dist/workers/pi-worker-search.js +12 -8
  344. package/dist/workers/pi-worker.d.ts +9 -4
  345. package/dist/workers/pi-worker.js +23 -10
  346. package/dist/workers/reasoning-warning.d.ts +18 -17
  347. package/dist/workers/reasoning-warning.js +22 -20
  348. package/dist/workers/research-cache.js +50 -78
  349. package/dist/workers/search-core.js +7 -5
  350. package/dist/workers/search-types.d.ts +10 -9
  351. package/dist/workers/search-types.js +9 -8
  352. package/dist/workers/session-hint.d.ts +13 -14
  353. package/dist/workers/session-hint.js +8 -9
  354. package/dist/workers/shared.d.ts +21 -25
  355. package/dist/workers/shared.js +0 -0
  356. package/dist/workers/single-read-extension.d.ts +14 -7
  357. package/dist/workers/single-read-extension.js +14 -7
  358. package/dist/workers/single-read-guard.d.ts +25 -28
  359. package/dist/workers/single-read-guard.js +32 -32
  360. package/dist/workers/typeonly-log.d.ts +12 -9
  361. package/dist/workers/typeonly-log.js +29 -33
  362. package/dist/workers/worker-channels.d.ts +15 -23
  363. package/dist/workers/worker-channels.js +15 -23
  364. package/dist/workers/worker-failure.d.ts +38 -46
  365. package/dist/workers/worker-failure.js +31 -39
  366. package/dist/workers/worker-kill.d.ts +25 -26
  367. package/dist/workers/worker-kill.js +16 -19
  368. package/dist/workers/worker-profiles.d.ts +43 -53
  369. package/dist/workers/worker-profiles.js +30 -38
  370. package/package.json +10 -8
@@ -2,48 +2,47 @@
2
2
  * final-gate — the run-level integration gate /task-auto runs ONCE, after every
3
3
  * task is checked off and before the run is declared complete.
4
4
  *
5
- * The failure this closes (mx5 runs 3 and 5, validated): every existing gate is
6
- * per-task/per-slice, so a run can finish with each slice individually blessed
7
- * while the ASSEMBLED project is dead statics green yet every protected route
8
- * 500ing, 105/174 tests failing across slices, later tasks breaking files earlier
9
- * tasks verified. Per-task repo-health closes the static half; nothing ever ran
10
- * the project's own test/build commands against the finished whole.
5
+ * Every other gate in this extension is per-task, so a run can finish with each
6
+ * slice individually blessed while the ASSEMBLED project is dead. Per-task
7
+ * repo-health covers the static half; nothing else runs the project's own
8
+ * test/build/start commands against the finished whole.
11
9
  *
12
- * Like repo-health-check (whose discovery style this mirrors), it is deterministic
13
- * no model, no per-file narrowing, no "not my task" gray area. It discovers the
14
- * project's OWN integration commands (the ones a fresh checkout / CI would run)
15
- * and lets their REAL exit codes decide:
10
+ * Like repo-health-check, whose discovery style it mirrors, it is deterministic:
11
+ * no model, no per-file narrowing. It discovers the project's OWN commands and
12
+ * lets their REAL exit codes decide. `runFinalIntegrationGate` runs the sections
13
+ * in this order:
16
14
  *
17
- * - static analysis first (runRepoHealthCheck — cheap, precise), then
18
- * - lockfile↔manifest consistency (mx5 run 7, validated: the lockfile carried a
19
- * dependency no committed manifest declared, so the tree tested green here
20
- * but a FRESH CHECKOUT could not even install each ecosystem's own offline
21
- * "is the lock in sync" command decides), then
22
- * - the project's own `test` and `build` commands, run verbatim and unaided, then
23
- * - one boot exercise of the project's own start command (mx5 run 7, validated:
24
- * every static and test gate green, yet `bun run start` died in ~1s on a
25
- * self-inflicted EADDRINUSE nothing had ever LAUNCHED the finished project).
26
- * No ports, URLs, or framework knowledge: fast non-zero exit → FAIL, quick
27
- * exit 0 → PASS (CLI-style), still alive after the grace window → PASS and
28
- * the whole process group is killed (scripts spawn children; a leaked child
29
- * server would mask every later boot check with a port collision).
15
+ * - static analysis (runRepoHealthCheck), then
16
+ * - the launch-contract diff and the `pre-discovery` closure scans, which need
17
+ * no runner at all, then
18
+ * - lockfile↔manifest consistency a lockfile can carry a dependency no
19
+ * committed manifest declares, so the tree tests green here while a FRESH
20
+ * CHECKOUT cannot install; each ecosystem's own non-mutating "is the lock in
21
+ * sync" command decides, then
22
+ * - the project's own test and build commands, verbatim and unaided, then
23
+ * - the declared launch scripts, one-shot, then
24
+ * - one boot exercise of the start command. No ports, URLs or framework
25
+ * knowledge: fast non-zero exit → FAIL, quick exit 0 → PASS (CLI-style),
26
+ * still alive after the grace window PASS, and the whole process group is
27
+ * killed, because scripts spawn children and a leaked child server masks
28
+ * every later boot check with a port collision, then
29
+ * - the blindness guard and the `post-boot` closure scans.
30
+ *
31
+ * EVERY section runs and the failures AGGREGATE into one ranked list; nothing
32
+ * early-returns on the first failure.
30
33
  *
31
34
  * Environment-gap safety, same contract as repo-health-check: a command that
32
35
  * CANNOT run (ENOENT, exit 127 = command-not-found inside the script chain, or a
33
- * timeout) is an environment problem, not a code fault — it is SKIPPED, never
34
- * failed. Only a command that actually ran and exited non-zero fails the gate,
35
- * and the reason carries the tail of its real output so the user (and a resume
36
- * fix) can act on it. A test suite that needs a database will fail here when the
37
- * database is genuinely reachable-but-mis-wired which is exactly the class the
38
- * per-task gates kept excusing and the caller puts a human on the decision
39
- * (accept / leave failed), so a genuine external gap can still be overridden.
36
+ * timeout) is an environment problem, not a code fault — SKIPPED, never failed.
37
+ * Only a command that actually ran and exited non-zero fails the gate, and the
38
+ * reason carries the tail of its real output so the user and a resume fix can act
39
+ * on it. A test suite that needs a database still fails here when the database is
40
+ * reachable-but-mis-wired, and the caller puts a human on that decision, so a
41
+ * genuine external gap can be overridden.
40
42
  *
41
- * A skip is never silent, though. A DISCOVERED boot command that never ran is its
42
- * own verdict (bootSkipVerdict, mx5 run 18) nothing else the gate observed can
43
- * cancel it. Validation harnesses for that lever:
44
- * scripts/boot-skip-baserate.ts base rate, shipped gate, before the change
45
- * scripts/boot-skip-verdict-ab.ts two-armed deterministic A/B + invariants
46
- * scripts/boot-skip-fp-suite.ts zero-FP arms over every local repo
43
+ * A skip is never silent: a DISCOVERED boot command that never ran is its own
44
+ * verdict, kept outside the tally's dynamic counters so nothing else the gate
45
+ * observed can cancel it.
47
46
  */
48
47
  import { existsSync, readFileSync } from 'node:fs';
49
48
  import * as path from 'node:path';
@@ -69,35 +68,33 @@ import { VERIFY_FAIL_PREFIX } from './verify-work.js';
69
68
  * manifest that exists wins, mirroring discoverHealthCommands. Empty means
70
69
  * "nothing to run" — the static half may still gate.
71
70
  *
72
- * THE MANIFEST ALLOWLIST BELOW IS NARROW, AND THAT IS A KNOWN, MEASURED GAP: a
73
- * C++/CMake project (no package.json) and a package.json whose only script is
74
- * `verify` both discover NOTHING here. That outcome is now reported as UNOBSERVED
75
- * rather than as a PASS (see unobservedVerdict), which makes the blindness loud and
76
- * durable — it does not remove it. The gap itself stands.
71
+ * THE MANIFEST ALLOWLIST BELOW IS NARROW, AND THAT IS A KNOWN GAP: a project with
72
+ * no package.json, Makefile, Cargo.toml, go.mod or pyproject.toml discovers
73
+ * NOTHING here, and so does a package.json whose only script is named something
74
+ * else. That outcome is reported as UNOBSERVED rather than as a PASS (see
75
+ * unobservedVerdict), which makes the blindness loud — it does not remove it.
77
76
  *
78
- * The obvious fix harvest each task's own `## verified tooling` section, which
79
- * DOES record the missing commands was measured on 2026-07-27 and REFUTED. That
80
- * section is model-authored and, despite its name, unverified: on godot-engine it
81
- * yields 3 commands that exit 0 and 8 that exit non-zero, six of those for purely
82
- * fabricated reasons (recorded without a required argument, pointing at files that
83
- * do not exist, naming a test runner the project does not use) — so harvesting it
84
- * turns that project's PASS into a FAIL citing "No scene path provided", plus ~15
85
- * minutes of hang. Full numbers, the reproduction rig, and why no pre-execution
86
- * filter can separate a fabricated command from a real one:
87
- * scripts/harvest-verified-tooling-step0.ts. DO NOT re-propose the harvest without
88
- * first fixing the PROVENANCE of `## verified tooling` (record cwd + exit code at
89
- * authoring time); widening this allowlist tool-by-tool is not the fix either.
77
+ * DO NOT close the gap by harvesting each task's own `## verified tooling`
78
+ * section. That section is the parsed output of a model child (phases.ts writes
79
+ * it from the verify-tooling worker), and despite its name nothing records the
80
+ * cwd the command was tried in or the code it exited with so a fabricated
81
+ * command is indistinguishable from a real one before it runs, and running it is
82
+ * how the gate would find out. Fix that provenance first. Widening this allowlist
83
+ * tool-by-tool is not the fix either.
90
84
  */
91
85
  export function discoverIntegrationCommands(cwd) {
92
86
  if (existsSync(path.join(cwd, 'package.json'))) {
93
87
  const s = packageScripts(cwd);
94
88
  const cmds = [];
95
- // Every test-shaped script, not just the one literally named `test` (mx5 run
96
- // 10: `test:ct` 89 Playwright component tests, the ONLY client-executing
97
- // suite never ran because the gate looked only for `test`/`build`). Plain
98
- // `test` leads (richer, most common), then `test:*`/`test-*` in declaration
99
- // order, then `build`. Env-gap SKIP still applies per command (a suite whose
100
- // browser/runtime is absent skips, it does not fail see runGateCommand).
89
+ // Every test-shaped script, not just the one literally named `test`: a
90
+ // project's only browser-executing suite is often `test:ct` or similar, and
91
+ // looking for `test` alone never runs it. Plain `test` leads, then every
92
+ // `test:`/`test_`/`test-` prefixed name in declaration order (Array#sort is
93
+ // stable), then `build`. Measured on a manifest declaring test:ct, build,
94
+ // test_unit, test-e2e, test, testing and pretest, the result is exactly
95
+ // test, test:ct, test_unit, test-e2e, build — `testing` and `pretest` do
96
+ // not match. Env-gap SKIP still applies per command: a suite whose browser
97
+ // or runtime is absent skips rather than fails (see runGateCommand).
101
98
  const testNames = Object.keys(s).filter(n => n === 'test' || /^test[:_-]/.test(n));
102
99
  testNames.sort((a, b) => a === 'test' ? -1
103
100
  : b === 'test' ? 1
@@ -141,11 +138,18 @@ export function discoverIntegrationCommands(cwd) {
141
138
  }
142
139
  /**
143
140
  * Per-ecosystem lockfile↔manifest consistency checks. A check applies only when
144
- * BOTH the manifest and its lockfile exist (no lockfile nothing to verify),
145
- * and every command is the ecosystem's own non-mutating "is the lock in sync
146
- * with the manifest" form — validated to exit 0 fast on an in-sync tree and
147
- * non-zero on a genuine desync, without touching the tree or (when in sync)
148
- * the network.
141
+ * BOTH the manifest and its lockfile exist no lockfile means nothing to verify
142
+ * and every command is that ecosystem's own non-mutating "is the lock in sync
143
+ * with the manifest" form.
144
+ *
145
+ * Four of the six were run against real throwaway projects, in sync and then with
146
+ * one dependency added to the manifest only. Each exited 0 in sync and non-zero
147
+ * on the desync, and left the lockfile byte-identical either way:
148
+ * `bun install --frozen-lockfile --dry-run` 0/1, `npm ci --dry-run` 0/1 (and it
149
+ * does not remove node_modules), `cargo metadata --locked` 0/101,
150
+ * `uv lock --check` 0/1. The `go` and `poetry` rows could not be run here — those
151
+ * binaries are not installed on this box — so they are asserted, not measured.
152
+ * A desync does reach the network; only the in-sync path is offline.
149
153
  */
150
154
  const LOCKFILE_CHECKS = [
151
155
  {
@@ -200,11 +204,11 @@ export function discoverGateCommandLabels(cwd) {
200
204
  * The RESOLVED BODY of every discoverable gate command, keyed by the same label
201
205
  * `discoverGateCommandLabels` produces.
202
206
  *
203
- * The label is what the gate CALLS; the body is what actually runs. mx5 run 19's
204
- * autofix changed `scripts.test` from `AGENT=1 bun test` to `AGENT=1 bun test
205
- * ./test` — the label `bun run test` was identical before and after, so the
206
- * label guard saw nothing while the suite stopped covering the repository. The
207
- * shrink guard compares these bodies (see command-shrink.ts).
207
+ * The label is what the gate CALLS; the body is what actually runs. A fix pass
208
+ * can rewrite `scripts.test` to run one subdirectory and leave the label
209
+ * `bun run test` identical, so the label guard sees nothing while the suite stops
210
+ * covering the repository. The shrink guard compares these bodies (see
211
+ * command-shrink.ts).
208
212
  *
209
213
  * A command with no indirection (`cargo test --quiet`, `pytest -q`) resolves to
210
214
  * itself: it cannot be narrowed without changing the label, which the label
@@ -260,7 +264,7 @@ async function runGateCommand(cwd, [bin, args], timeoutMs, extraGapRe,
260
264
  envOverride,
261
265
  /** The spawner. Injected so the gate's own tests can script a verdict. */
262
266
  run = spawnCommand, signal) {
263
- // Runner resolution (mx5 run 16): a login-shell-stripped PATH left `bun`
267
+ // Runner resolution: a login-shell-stripped PATH left `bun`
264
268
  // unspawnable, so every dynamic check skipped and the gate went blind. The
265
269
  // resolved binary is spawned, and its directory rides on the child's PATH so
266
270
  // the SCRIPT CHAIN can re-invoke the runner (`bun run test` runs `bun test`
@@ -280,46 +284,44 @@ run = spawnCommand, signal) {
280
284
  return verdict;
281
285
  }
282
286
  // `runVerifyCommandLine` and its outcome type live in command-run.ts with the
283
- // other command drivers; re-exported so existing importers keep working.
287
+ // other command drivers; re-exported because the gate's own test suite reaches
288
+ // them through this module.
284
289
  export { runVerifyCommandLine } from './command-run.js';
285
- // The two verdict predicates — the run-16 full-blindness FAIL and the third,
290
+ // The two verdict predicates — the full-blindness FAIL and the third,
286
291
  // non-blocking UNOBSERVED verdict — live with the counters they read, in
287
- // gate-tally.ts (GateTally). Re-exported so every existing importer keeps working.
292
+ // gate-tally.ts (GateTally). Re-exported for the gate's own test suite.
288
293
  export { observabilityGapFailure, unobservedVerdict };
289
- // File → introducing-task provenance moved to task-provenance.ts (mx5 run-12
290
- // PROMPT 2 extracted it for the cross-task deletion guards); re-exported so
291
- // existing importers keep working.
294
+ // File → introducing-task provenance lives in task-provenance.ts, next to the
295
+ // cross-task deletion guards that use it; re-exported for the gate's own tests.
292
296
  export { taskThatIntroduced };
293
- // The boot probe moved to boot-probe.ts (its own concern, 0 other importers inside
294
- // src/). Re-exported so the seven validation harnesses under scripts/ which have
295
- // always imported exactly this surface and nothing else from the gate — keep
296
- // working unchanged. Same pattern as taskThatIntroduced above.
297
+ // The boot probe lives in boot-probe.ts. This module is its ONLY importer inside
298
+ // src/, so these re-exports exist for consumers outside it; of them, the gate's
299
+ // own test suite currently reaches only `bootSkipVerdict` through here.
297
300
  export { discoverBootCommand, detectsServedApp, runBootCheck, runBootSection, bootSkipVerdict, nonLaunchScriptReason, rejectedLaunchScript, parseSsListeners, parseNetstatListeners, parseLsofListeners, pickFreePort, preferredDeclaredPort, canEnumerateListeners };
298
301
  // The ACCEPT-debt re-check (`deriveOpenDebts`, `rerunDebtVerifyCommand`) lives in
299
- // accept-debt.ts with the ledger it reads and writes; re-exported so the
300
- // orchestrator and the harnesses under scripts/ keep working unchanged.
302
+ // accept-debt.ts with the ledger it reads and writes; re-exported because
303
+ // auto-orchestrator.ts imports `deriveOpenDebts` through this module.
301
304
  export { deriveOpenDebts, rerunDebtVerifyCommand };
302
305
  /**
303
306
  * The run-level closure scans, in emission order within their stage.
304
307
  *
305
308
  * ONLY checks of this shape belong here. Four other checks in this gate are
306
- * deliberately NOT rows: repo-health returns {ok, reason} and formats inline;
307
- * the launch-contract diff branches on manifest kind and can emit a NOTE instead
308
- * of a failure; the launch config-gap produces neither a failure nor a note but
309
- * UN-COUNTS a dynamic observation; and the boot check is an async, stateful,
310
- * port-binding exercise. Squeezing any of those in would mean a row type with
311
- * more escape hatches than content.
309
+ * deliberately NOT rows: repo-health returns {ok, reason} and formats inline; the
310
+ * launch-contract diff branches on manifest kind and can emit a NOTE instead of a
311
+ * failure; the launch config-gap produces neither a failure nor a note but
312
+ * UN-COUNTS a dynamic observation (`tally.unobserve()`); and the boot check is
313
+ * async, stateful and port-binding. Squeezing any of those in would mean a row
314
+ * type with more escape hatches than content.
312
315
  */
313
316
  const CLOSURE_SCANS = [
314
317
  {
315
- // Serve-entry closure (mx5 run 18, nexttask 2B): the tree builds a server
316
- // app, expects to serve (SPA fallback / static read / a design clause), and
317
- // NOTHING anywhere starts a listener `src/server/index.ts` ended at
318
- // `export {app}`, so the product could not be started at all while every
319
- // dynamic probe went blind on a docker-less box. Static, deterministic,
320
- // milliseconds, and unlike the boot check decidable in exactly the
321
- // environment where the boot skipped. Hence `pre-discovery`: a project with
322
- // no runnable command at all must still fail this, not report UNOBSERVED.
318
+ // Serve-entry closure: the tree builds a server app, expects to serve (SPA
319
+ // fallback, a static read, a design clause), and NOTHING anywhere starts a
320
+ // listener a module that ends at `export {app}` cannot be started at all.
321
+ // Static and synchronous, and unlike the boot check it is decidable in
322
+ // exactly the environment where a boot would skip. Hence `pre-discovery`: a
323
+ // project with no runnable command must still fail this rather than report
324
+ // UNOBSERVED.
323
325
  id: 'serve-entry',
324
326
  stage: 'pre-discovery',
325
327
  rank: 0,
@@ -330,13 +332,12 @@ const CLOSURE_SCANS = [
330
332
  }
331
333
  },
332
334
  {
333
- // Artifact-production closure (mx5 run 13, PROMPT 2): a runtime file
334
- // reference with NO producer anywhere ships silently — the server read
335
- // `Bun.file('dist/index.html')` while the build emitted only app.css +
336
- // main.js, so every non-API GET 404'd behind 32/32 green checkoffs.
337
- // Deterministic scan of the shipped tree (literal refs only, positive
338
- // producer evidence required — see artifact-closure.ts); each dangle names
339
- // referencer + missing path.
335
+ // Artifact-production closure: a runtime file reference with NO producer
336
+ // anywhere ships silently — a server reading `dist/index.html` that no build
337
+ // step emits 404s every request behind a fully green plan. Deterministic
338
+ // scan of the shipped tree: literal references only, positive producer
339
+ // evidence required (artifact-closure.ts). Each dangle names the referencer
340
+ // and the missing path.
340
341
  id: 'dangling-artifact',
341
342
  stage: 'post-boot',
342
343
  rank: 0,
@@ -346,16 +347,15 @@ const CLOSURE_SCANS = [
346
347
  }
347
348
  },
348
349
  {
349
- // Env-template closure (mx5 run 19, nexttask 10): a shipped source file
350
- // requires an env var the shipped template never mentions. `seed.ts` read
351
- // `process.env.ADMIN_PHONE`/`ADMIN_PASSWORD`, `.env.example` declared
352
- // neither, `bun run seed` exited 1, and the autofix "fixed" it by writing
353
- // the GITIGNORED `.env` so the committed tree still cannot seed and
354
- // nothing at run end said why. Same shape and rank as the dangling-artifact
355
- // scan above: naming the ARTIFACT that is wrong, statically, instead of only
356
- // the command that failed. The formatter needs the template set as well as
357
- // the finding, which is why scan and format are folded into one row.
358
- // Inert on any tree with no tracked template (ENOENT = pass).
350
+ // Env-template closure: a shipped source file requires an env var the
351
+ // shipped template never mentions. Without this the only symptom is the
352
+ // script's own non-zero exit, which an autofix can silence by writing the
353
+ // GITIGNORED `.env` leaving a committed tree that still cannot run and
354
+ // nothing at run end saying why. Same shape and rank as the
355
+ // dangling-artifact scan: name the ARTIFACT that is wrong, statically,
356
+ // rather than only the command that failed. The formatter needs the
357
+ // template set as well as the finding, which is why scan and format are one
358
+ // row. Inert on any tree with no tracked template.
359
359
  id: 'env-template',
360
360
  stage: 'post-boot',
361
361
  rank: 0,
@@ -400,17 +400,16 @@ export async function runFinalIntegrationGate(cwd, opts = {}) {
400
400
  return inertClosure();
401
401
  }
402
402
  }, trackedFiles: trackedFilesFn = trackedFiles } = opts;
403
- // ASYNC: the run-end gate no longer blocks the event loop for the project's own
404
- // lint (measured 15s mx5 / 69s aiz-client with zero timer ticks), so a loader can
405
- // paint and a cancel can reach the child.
403
+ // ASYNC so the event loop keeps turning while the project's own lint runs: a
404
+ // loader can paint and a cancel can reach the child.
406
405
  const stat = await runRepoHealthCheck(cwd, {
407
406
  run: runCmd,
408
407
  ...(opts.signal === undefined ? {} : { signal: opts.signal })
409
408
  });
410
- // Debts are derived once, before any section runs, and ride on every verdict
411
- // shape (GateTally.verdict): `reason` stays the mechanical failure because it
412
- // seeds the autofix child's prompt run 11's fix child executed a recorded
413
- // claim as an instruction.
409
+ // Debts are derived ONCE, before any section runs, and ride on every verdict
410
+ // shape (GateTally.verdict). `reason` stays purely mechanical because it seeds
411
+ // the autofix child's prompt, and a write-enabled child reads a recorded claim
412
+ // as an instruction.
414
413
  const debts = await deriveOpenDebts(cwd, stat.ok, runCmd, opts.signal);
415
414
  // Every section below RECORDS into the tally (failures ranked, the four
416
415
  // dynamic counters, the notes) and the verdict is assembled ONCE at the end —
@@ -422,20 +421,20 @@ export async function runFinalIntegrationGate(cwd, opts = {}) {
422
421
  // entered the ledger through EITHER altitude.
423
422
  if (!stat.ok)
424
423
  tally.fail(`${VERIFY_FAIL_PREFIX['static-checks']} ${stat.reason}`);
425
- // Launch-contract diff (mx5 run 10 item 4): the design declared `migrate`/`seed`
426
- // scripts that fell through decompose and shipped missing, unchecked. Diff the
427
- // plan-time-extracted declared scripts against the manifest; a missing one is a
428
- // launch-surface defect. FP-safe: empty declared list (nothing grounded) no check.
424
+ // Launch-contract diff: a design can declare scripts that fall through
425
+ // decompose and ship missing, unchecked. Diff the plan-time-extracted declared
426
+ // scripts against the manifest; a missing one is a launch-surface defect.
427
+ // FP-safe: an empty declared list means nothing was grounded, so no check runs.
429
428
  //
430
- // THE DIFF IS INERT WITHOUT A MANIFEST (nexttask 16A). It used to diff against
431
- // `Object.keys(packageScripts(cwd))`, whose catch returns {} so a project with
432
- // NO package.json was indistinguishable from one with no scripts, and every
433
- // declared script was reported missing in wording naming a file the project was
434
- // never meant to have. Nothing upstream is npm-shaped (the extractor scrapes any
435
- // design that says "script"), and this text seeds the autofix child's prompt, so
436
- // on a CMake/cargo project the likely repair was to write a package.json.
429
+ // THE DIFF MUST NOT RUN WITHOUT A MANIFEST. `packageScripts` catches and
430
+ // returns {}, so diffing against its keys makes a project with NO package.json
431
+ // indistinguishable from one with no scripts every declared script reported
432
+ // missing, naming a file the project was never meant to have. The extractor
433
+ // upstream scrapes any design that says "script", nothing about it is
434
+ // npm-shaped, and this text seeds the autofix child's prompt, so on a
435
+ // CMake/cargo project the repair it invites is to write a package.json.
437
436
  // readLaunchManifest resolves package.json, else a Makefile's targets, else
438
- // nothing — and nothing means no failure plus a note, never a silent pass.
437
+ // nothing — and nothing means a note, never a failure and never a silent pass.
439
438
  const declared = await readDeclaredScripts(cwd);
440
439
  if (declared.length > 0) {
441
440
  const manifest = readLaunchManifest(cwd);
@@ -476,33 +475,31 @@ export async function runFinalIntegrationGate(cwd, opts = {}) {
476
475
  tally.ran(label);
477
476
  }
478
477
  }
479
- // EXECUTE the launch contract (mx5 run 11): every declared script that is
480
- // neither boot-class (the boot check below owns those) nor already covered by
481
- // the integration commands above RUNS as a one-shot, in declared order
482
- // existence is not launchability (`migrate`/`seed` shipped as first-call
483
- // TypeErrors while the gate checked only that they exist). The env-gap
484
- // contract extends to missing external INFRASTRUCTURE (no DB/daemon on this
485
- // box → skip, not fail); a skip whose script also carries a standing EXCUSE
486
- // note (F7) is surfaced as an UNOBSERVED warning the note may be covering a
487
- // real defect the gate could not reach here (run 11's "pre-existing .rows
488
- // bug" note excused the exact scripts that shipped broken).
478
+ // EXECUTE the launch contract: every declared script that is neither
479
+ // boot-class (the boot check below owns those) nor already covered by the
480
+ // integration commands above RUNS as a one-shot, in declared order. Existence
481
+ // is not launchability a script can be present in the manifest and throw on
482
+ // its first call. The env-gap contract extends to missing external
483
+ // INFRASTRUCTURE here (no DB or daemon on this box → skip, not fail), and a
484
+ // skip whose script also carries a standing EXCUSE note is surfaced as an
485
+ // UNOBSERVED warning: the note may be covering a real defect the gate could
486
+ // not reach.
489
487
  if (declared.length > 0) {
490
488
  const covered = cmds.flatMap(([bin, args]) => (bin === 'bun' || bin === 'npm') && args[0] === 'run' && args[1] ? [args[1]] : []);
491
489
  const skippedLaunch = [];
492
- // A declared script the manifest doesn't expose is already a launch-contract
493
- // failure above; executing it too would double-report (pre-aggregation the
494
- // contract diff early-returned, so this loop could assume presence).
495
- // EXECUTION STAYS npm-ONLY. The diff above now also speaks Makefile (16A),
496
- // but the runner below is literally `bun run <name>`; on a Makefile project
497
- // `present` is empty, so every declared target is skipped rather than run
498
- // through the wrong tool. Widening the RUNNER is a separate lever with its
499
- // own A/B, not a free rider on an inertness fix.
490
+ // A declared script the manifest doesn't expose is already a
491
+ // launch-contract failure above; executing it too would double-report.
492
+ // EXECUTION STAYS npm-ONLY: the runner below is literally `bun run <name>`,
493
+ // so on a Makefile project `present` is empty from `packageScripts` and
494
+ // every declared target is skipped rather than run through the wrong tool.
495
+ // The diff above does speak Makefile; widening the RUNNER to match is a
496
+ // separate change.
500
497
  const present = new Set(Object.keys(packageScripts(cwd)).map(s => s.toLowerCase()));
501
498
  const scripts = packageScripts(cwd);
502
- // CONFIG-GAP INPUTS (mx5 run 20), read once: the tracked file list and the
503
- // union of every tracked env template's declared variables. Both empty on a
504
- // non-git tree or a tree with no template, which makes the whole check inert
505
- // — a project with no template gains no excuse. See launch-config-gap.ts.
499
+ // CONFIG-GAP INPUTS, read once: the tracked file list and the union of every
500
+ // tracked env template's declared variables. Both are empty on a non-git tree
501
+ // or one with no template, which makes the whole check inert there — a
502
+ // project with no template gains no excuse. See launch-config-gap.ts.
506
503
  const closure = envClosure(cwd);
507
504
  const trackedForGap = closure.templates.length > 0 ? (trackedFilesFn(cwd) ?? []) : [];
508
505
  const launchTimeout = Math.min(timeoutMs, 180_000);
@@ -521,17 +518,16 @@ export async function runFinalIntegrationGate(cwd, opts = {}) {
521
518
  }
522
519
  tally.observed();
523
520
  if (r.outcome === 'fail') {
524
- // A CONFIG GAP IS NOT A CODE FAULT (mx5 run 20). The run died on
525
- // `bun run seed` exiting 1 because ADMIN_PHONE which the project's
526
- // own `.env.example` DECLARES is absent from this box, and the only
527
- // way to supply it is a gitignored `.env` the commit cannot contain.
528
- // Four static conditions (findLaunchConfigGap) plus one dynamic one:
529
- // re-run with the variables supplied as synthetic placeholders, and
530
- // reclassify ONLY if that exits 0. A script that fails for its own
531
- // reasons fails again with the values present and stays a FAIL an
521
+ // A CONFIG GAP IS NOT A CODE FAULT. A script can exit non-zero only
522
+ // because a variable its own committed template DECLARES is absent
523
+ // from this box, where the only way to supply it is a gitignored
524
+ // `.env` no commit can contain. findLaunchConfigGap decides the
525
+ // static half; the dynamic half is this re-run with the variables
526
+ // supplied as synthetic placeholders, and the reclassification
527
+ // happens ONLY if that exits 0. A script that fails for its own
528
+ // reasons fails again with the values present and stays a FAIL: an
532
529
  // absent variable is not a licence to ignore an exit code the code
533
- // caused. Nothing is parsed from the child's stderr: the wording is
534
- // the project's, not the harness's.
530
+ // caused. Nothing is parsed from the child's stderr.
535
531
  const gap = findLaunchConfigGap({
536
532
  cwd,
537
533
  script: name,
@@ -570,41 +566,38 @@ export async function runFinalIntegrationGate(cwd, opts = {}) {
570
566
  }
571
567
  }
572
568
  }
573
- // Boot + render ALWAYS runs (mx5 run 13): it is independent of test results by
574
- // construction, and it carries the run's most load-bearing signal earlier
575
- // failures no longer shadow it. Its failures rank FIRST in the aggregate.
576
- // A boot that never RAN is its own verdict (mx5 run 18 see bootSkipVerdict);
577
- // it lives outside the tally's dynamic counters on purpose, so the test/build
578
- // commands that did run cannot cancel it.
569
+ // Boot + render ALWAYS runs. It is independent of test results by
570
+ // construction and carries the run's most load-bearing signal, so its failures
571
+ // rank FIRST in the aggregate and earlier failures cannot shadow it. A boot
572
+ // that never RAN is its own verdict, kept outside the tally's dynamic counters
573
+ // on purpose, so the test/build commands that did run cannot cancel it.
579
574
  //
580
- // ZERO DISCOVERY IS UNOBSERVED, NEVER A PASS (see unobservedVerdict, and the
581
- // zero-attempts branch of GateTally.verdict). Nothing was discovered, so nothing
582
- // ran, so the blindness guard below (attempted === 0 → null) does not fire and
583
- // this outcome used to be reported as `PASS no integration command found
584
- // (statics passed)`, i.e. "we never checked" reading identically to "we checked
585
- // and it was fine". IAR1 shipped that verdict TWICE while carrying open
586
- // verify-FAIL debt (its .pi-tasks/TASK_AUTO_0001.md:31 and TASK_AUTO_0002.md:37).
587
- // The outcome stays `ok: true` (non-blocking, justified at unobservedVerdict) but
588
- // is labelled, trailed and carried as debt by the caller. It needs no new command
589
- // source, so unlike the harvest lever refuted at discoverIntegrationCommands it
590
- // cannot inject a fabricated failure. The inert-contract note rides on it too: a
591
- // non-npm project carrying a launch contract usually discovers no command either,
592
- // and that is exactly the run whose silence must not read as "the contract was
593
- // checked and was fine".
575
+ // ZERO DISCOVERY IS UNOBSERVED, NEVER A PASS (see unobservedVerdict and the
576
+ // zero-attempts branch of GateTally.verdict). Nothing discovered means nothing
577
+ // ran, so the blindness guard below cannot fire either
578
+ // `observabilityGapFailure` returns null the moment `attempted === 0`. Calling
579
+ // that a PASS makes "we never checked" read identically to "we checked and it
580
+ // was fine", and a run can ship that verdict while carrying open verify-FAIL
581
+ // debt. The outcome stays `ok: true` and non-blocking, but is labelled,
582
+ // trailed and carried as debt by the caller. It needs no new command source, so
583
+ // unlike the harvest refused at discoverIntegrationCommands it cannot inject a
584
+ // fabricated failure. The inert-contract note rides on it: a non-npm project
585
+ // carrying a launch contract usually discovers no command either, and that is
586
+ // exactly the run whose silence must not read as "the contract was checked and
587
+ // was fine".
594
588
  //
595
- // This return sits AFTER the launch-script loop, not before it: it used to fire
596
- // first, so a DECLARED launch script never ran on a tree with no discoverable
597
- // integration command (found and left unfixed in f5d7110). "Nothing to observe"
598
- // is a fact about the tally no attempt, no failure not about discovery, and
599
- // asking the tally makes the two paths see the same state. It still returns
600
- // before the boot `else` branch and the post-boot closure scans, whose stage is a
601
- // statement about when they are meaningful.
589
+ // This return sits AFTER the launch-script loop, not before it. Firing first, a
590
+ // DECLARED launch script would never run on a tree with no discoverable
591
+ // integration command. The condition asks the TALLY no attempt and no failure
592
+ // rather than asking discovery, so both paths see the same state. It still
593
+ // returns before the boot section and the post-boot closure scans.
602
594
  if (!boot && tally.silent())
603
595
  return tally.verdict(debts);
604
596
  // The boot CONCEPT lives in boot-probe.ts (runBootSection): discovery,
605
597
  // served-app detection, the probe defaults, the boot check, orphan-port
606
598
  // recovery, the port-holder diagnosis, the skip verdict and the
607
- // rejected-launch-script branch. This is the record, and nothing else.
599
+ // rejected-launch-script branch. What is left here is only the recording of
600
+ // its result into the tally.
608
601
  const bootSection = await runBootSection(cwd, {
609
602
  ...(planText === undefined ? {} : { planText }),
610
603
  ...(bootGraceMs === undefined ? {} : { graceMs: bootGraceMs }),
@@ -628,17 +621,17 @@ export async function runFinalIntegrationGate(cwd, opts = {}) {
628
621
  tally.ran(bootSection.ranLabel);
629
622
  for (const w of bootSection.warnings)
630
623
  tally.warn(w);
631
- // Full-skip blindness guard (mx5 run 16): commands were discovered but every
632
- // one skipped → rank-0 failure, never a static-only PASS. Runner resolvability
633
- // is checked through resolveRunner so the failure text can name the missing
634
- // runner when that is the cause (the run-16 shape: login-shell PATH lost bun).
624
+ // Full-skip blindness guard: commands were discovered but every one skipped →
625
+ // rank-0 failure, never a static-only PASS. Runner resolvability is checked
626
+ // through resolveRunner so the failure text can name the missing runner when
627
+ // that is the cause.
635
628
  const gap = tally.blindness(b => resolveRunner(b).ok);
636
629
  if (gap)
637
630
  tally.fail(gap, 0);
638
631
  // The remaining run-level closure scans — "the shipped tree references or
639
- // requires something it does not contain" — after every dynamic section, so
640
- // their failures keep their historical place in the aggregate (CLOSURE_SCANS:
641
- // 'post-boot').
632
+ // requires something it does not contain" — after every dynamic section, which
633
+ // is where their failures sit in the aggregate's within-rank order
634
+ // (CLOSURE_SCANS: 'post-boot').
642
635
  runClosureScans('post-boot', { cwd, planText }, (t, r) => tally.fail(t, r));
643
636
  return tally.verdict(debts);
644
637
  }