@hominis/fireforge 0.45.0 → 0.46.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 (662) hide show
  1. package/CHANGELOG.md +409 -446
  2. package/dist/bin/fireforge.d.ts +1 -1
  3. package/dist/bin/fireforge.js +21 -15
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/cli-usage-error.d.ts +46 -0
  6. package/dist/src/cli-usage-error.js +81 -0
  7. package/dist/src/cli.d.ts +7 -2
  8. package/dist/src/cli.js +47 -47
  9. package/dist/src/commands/bootstrap-checks.js +2 -1
  10. package/dist/src/commands/bootstrap.js +3 -4
  11. package/dist/src/commands/build.js +27 -17
  12. package/dist/src/commands/config.js +9 -9
  13. package/dist/src/commands/destructive-decision.d.ts +19 -0
  14. package/dist/src/commands/destructive-decision.js +31 -0
  15. package/dist/src/commands/discard.js +5 -5
  16. package/dist/src/commands/doctor-check-core.d.ts +4 -10
  17. package/dist/src/commands/doctor-check-core.js +0 -8
  18. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  19. package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
  20. package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
  21. package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
  22. package/dist/src/commands/doctor-furnace-jar.js +1 -1
  23. package/dist/src/commands/doctor-furnace.js +22 -22
  24. package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
  25. package/dist/src/commands/doctor-orphaned-harness.js +14 -23
  26. package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
  27. package/dist/src/commands/doctor-patch-manifest.js +7 -6
  28. package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
  29. package/dist/src/commands/doctor-source-pin.d.ts +12 -12
  30. package/dist/src/commands/doctor-source-pin.js +14 -14
  31. package/dist/src/commands/doctor-working-tree.d.ts +3 -3
  32. package/dist/src/commands/doctor-working-tree.js +3 -3
  33. package/dist/src/commands/doctor.d.ts +3 -1
  34. package/dist/src/commands/doctor.js +15 -16
  35. package/dist/src/commands/download.js +50 -37
  36. package/dist/src/commands/export-all.js +29 -12
  37. package/dist/src/commands/export-flow.d.ts +5 -5
  38. package/dist/src/commands/export-flow.js +29 -59
  39. package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
  40. package/dist/src/commands/export-placement-conflicts.js +12 -12
  41. package/dist/src/commands/export-placement-gate.d.ts +2 -2
  42. package/dist/src/commands/export-placement-gate.js +7 -13
  43. package/dist/src/commands/export-placement-policy.d.ts +1 -1
  44. package/dist/src/commands/export-placement-policy.js +4 -6
  45. package/dist/src/commands/export-shared.d.ts +51 -32
  46. package/dist/src/commands/export-shared.js +17 -32
  47. package/dist/src/commands/export.js +14 -5
  48. package/dist/src/commands/furnace/apply.js +16 -16
  49. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  50. package/dist/src/commands/furnace/authoring-config.js +19 -0
  51. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
  52. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  53. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
  54. package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
  55. package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
  56. package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
  57. package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
  58. package/dist/src/commands/furnace/chrome-doc.js +18 -18
  59. package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
  60. package/dist/src/commands/furnace/create-browser-test.js +7 -12
  61. package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
  62. package/dist/src/commands/furnace/create-dry-run.js +6 -9
  63. package/dist/src/commands/furnace/create-features.d.ts +2 -2
  64. package/dist/src/commands/furnace/create-features.js +2 -2
  65. package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
  66. package/dist/src/commands/furnace/create-mochikit.js +7 -7
  67. package/dist/src/commands/furnace/create-templates.d.ts +31 -15
  68. package/dist/src/commands/furnace/create-templates.js +20 -19
  69. package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
  70. package/dist/src/commands/furnace/create-xpcshell.js +8 -8
  71. package/dist/src/commands/furnace/create.d.ts +1 -1
  72. package/dist/src/commands/furnace/create.js +35 -29
  73. package/dist/src/commands/furnace/deploy.js +15 -6
  74. package/dist/src/commands/furnace/diff.js +7 -7
  75. package/dist/src/commands/furnace/index.js +1 -1
  76. package/dist/src/commands/furnace/init.js +17 -16
  77. package/dist/src/commands/furnace/list.js +2 -2
  78. package/dist/src/commands/furnace/override.d.ts +1 -1
  79. package/dist/src/commands/furnace/override.js +43 -34
  80. package/dist/src/commands/furnace/preview.js +17 -17
  81. package/dist/src/commands/furnace/refresh.js +15 -7
  82. package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
  83. package/dist/src/commands/furnace/remove-mutations.js +19 -19
  84. package/dist/src/commands/furnace/remove-state.d.ts +1 -1
  85. package/dist/src/commands/furnace/remove-state.js +1 -1
  86. package/dist/src/commands/furnace/remove.js +4 -8
  87. package/dist/src/commands/furnace/rename-browser-test.js +10 -15
  88. package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
  89. package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
  90. package/dist/src/commands/furnace/rename.js +36 -36
  91. package/dist/src/commands/furnace/scan.js +3 -3
  92. package/dist/src/commands/furnace/status.js +19 -16
  93. package/dist/src/commands/furnace/sync.js +6 -6
  94. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  95. package/dist/src/commands/furnace/test-file-name.js +39 -0
  96. package/dist/src/commands/furnace/validate.js +11 -12
  97. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  98. package/dist/src/commands/furnace/validation-output.js +3 -8
  99. package/dist/src/commands/import.js +22 -29
  100. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  101. package/dist/src/commands/lint-per-patch.js +27 -12
  102. package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
  103. package/dist/src/commands/lint-per-run-checkjs.js +14 -15
  104. package/dist/src/commands/lint-report.d.ts +3 -3
  105. package/dist/src/commands/lint-report.js +4 -4
  106. package/dist/src/commands/lint.d.ts +5 -4
  107. package/dist/src/commands/lint.js +36 -36
  108. package/dist/src/commands/manifest.d.ts +4 -4
  109. package/dist/src/commands/manifest.js +1 -1
  110. package/dist/src/commands/package.js +4 -6
  111. package/dist/src/commands/patch/compact.d.ts +2 -2
  112. package/dist/src/commands/patch/compact.js +19 -20
  113. package/dist/src/commands/patch/delete.d.ts +1 -1
  114. package/dist/src/commands/patch/delete.js +23 -33
  115. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  116. package/dist/src/commands/patch/entry-projection.js +24 -0
  117. package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
  118. package/dist/src/commands/patch/lint-ignore.js +33 -44
  119. package/dist/src/commands/patch/move-files-create.d.ts +2 -2
  120. package/dist/src/commands/patch/move-files-create.js +29 -15
  121. package/dist/src/commands/patch/move-files-into.d.ts +2 -2
  122. package/dist/src/commands/patch/move-files-into.js +41 -37
  123. package/dist/src/commands/patch/move-files.js +5 -14
  124. package/dist/src/commands/patch/patch-context.d.ts +1 -1
  125. package/dist/src/commands/patch/rename.d.ts +4 -4
  126. package/dist/src/commands/patch/rename.js +35 -49
  127. package/dist/src/commands/patch/reorder.js +35 -48
  128. package/dist/src/commands/patch/split-plan.d.ts +7 -8
  129. package/dist/src/commands/patch/split-plan.js +10 -13
  130. package/dist/src/commands/patch/split.d.ts +2 -2
  131. package/dist/src/commands/patch/split.js +50 -48
  132. package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
  133. package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
  134. package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
  135. package/dist/src/commands/patch/staged-dependency.js +22 -28
  136. package/dist/src/commands/patch/tier.d.ts +2 -2
  137. package/dist/src/commands/patch/tier.js +20 -30
  138. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  139. package/dist/src/commands/patch-rename-map.js +36 -0
  140. package/dist/src/commands/pending-resolution.d.ts +15 -0
  141. package/dist/src/commands/pending-resolution.js +25 -0
  142. package/dist/src/commands/re-export-adjacent.d.ts +25 -3
  143. package/dist/src/commands/re-export-adjacent.js +40 -24
  144. package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
  145. package/dist/src/commands/re-export-bulk-scan.js +23 -27
  146. package/dist/src/commands/re-export-drift.d.ts +10 -10
  147. package/dist/src/commands/re-export-drift.js +33 -33
  148. package/dist/src/commands/re-export-files.d.ts +2 -3
  149. package/dist/src/commands/re-export-files.js +52 -44
  150. package/dist/src/commands/re-export-lint.d.ts +29 -30
  151. package/dist/src/commands/re-export-lint.js +36 -29
  152. package/dist/src/commands/re-export-options.d.ts +1 -1
  153. package/dist/src/commands/re-export-options.js +1 -1
  154. package/dist/src/commands/re-export-register.d.ts +1 -1
  155. package/dist/src/commands/re-export-register.js +1 -1
  156. package/dist/src/commands/re-export-scan.d.ts +1 -1
  157. package/dist/src/commands/re-export-scan.js +12 -9
  158. package/dist/src/commands/re-export-single.d.ts +23 -4
  159. package/dist/src/commands/re-export-single.js +39 -31
  160. package/dist/src/commands/re-export.js +35 -17
  161. package/dist/src/commands/rebase/abort.js +9 -14
  162. package/dist/src/commands/rebase/continue.js +20 -19
  163. package/dist/src/commands/rebase/index.d.ts +1 -1
  164. package/dist/src/commands/rebase/index.js +5 -5
  165. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  166. package/dist/src/commands/rebase/patch-loop.js +20 -24
  167. package/dist/src/commands/register.js +5 -5
  168. package/dist/src/commands/reset.js +1 -1
  169. package/dist/src/commands/resolve.d.ts +2 -2
  170. package/dist/src/commands/resolve.js +21 -13
  171. package/dist/src/commands/run.d.ts +0 -13
  172. package/dist/src/commands/run.js +38 -51
  173. package/dist/src/commands/setup-support.d.ts +16 -4
  174. package/dist/src/commands/setup-support.js +20 -20
  175. package/dist/src/commands/setup.js +4 -10
  176. package/dist/src/commands/source.js +9 -2
  177. package/dist/src/commands/status-check.d.ts +3 -3
  178. package/dist/src/commands/status-check.js +6 -6
  179. package/dist/src/commands/status-json.d.ts +14 -13
  180. package/dist/src/commands/status-json.js +9 -8
  181. package/dist/src/commands/status-output.d.ts +3 -3
  182. package/dist/src/commands/status-output.js +5 -5
  183. package/dist/src/commands/status-ownership.d.ts +3 -3
  184. package/dist/src/commands/status-ownership.js +3 -3
  185. package/dist/src/commands/status.js +25 -26
  186. package/dist/src/commands/test-build-phase.d.ts +3 -3
  187. package/dist/src/commands/test-build-phase.js +48 -24
  188. package/dist/src/commands/test-diagnose.d.ts +1 -1
  189. package/dist/src/commands/test-diagnose.js +20 -20
  190. package/dist/src/commands/test-modes.d.ts +4 -4
  191. package/dist/src/commands/test-modes.js +4 -5
  192. package/dist/src/commands/test-register.js +5 -3
  193. package/dist/src/commands/test-run.d.ts +11 -11
  194. package/dist/src/commands/test-run.js +40 -33
  195. package/dist/src/commands/test-stale-gate.d.ts +12 -12
  196. package/dist/src/commands/test-stale-gate.js +17 -17
  197. package/dist/src/commands/test-verdict.d.ts +19 -5
  198. package/dist/src/commands/test-verdict.js +26 -11
  199. package/dist/src/commands/test.d.ts +3 -3
  200. package/dist/src/commands/test.js +73 -36
  201. package/dist/src/commands/token-coverage.js +3 -3
  202. package/dist/src/commands/token-list.d.ts +26 -0
  203. package/dist/src/commands/token-list.js +153 -0
  204. package/dist/src/commands/token.js +26 -10
  205. package/dist/src/commands/tree.js +26 -21
  206. package/dist/src/commands/typecheck.d.ts +6 -6
  207. package/dist/src/commands/typecheck.js +16 -16
  208. package/dist/src/commands/verify.d.ts +3 -3
  209. package/dist/src/commands/verify.js +10 -10
  210. package/dist/src/commands/watch.js +11 -11
  211. package/dist/src/commands/wire.js +17 -16
  212. package/dist/src/core/ast-utils.d.ts +7 -7
  213. package/dist/src/core/ast-utils.js +8 -8
  214. package/dist/src/core/branding.d.ts +5 -12
  215. package/dist/src/core/branding.js +6 -5
  216. package/dist/src/core/browser-wire.d.ts +1 -1
  217. package/dist/src/core/browser-wire.js +10 -7
  218. package/dist/src/core/build-audit-platform.d.ts +32 -3
  219. package/dist/src/core/build-audit-platform.js +153 -13
  220. package/dist/src/core/build-audit-registration.d.ts +5 -5
  221. package/dist/src/core/build-audit-registration.js +10 -9
  222. package/dist/src/core/build-audit-resolve.d.ts +5 -5
  223. package/dist/src/core/build-audit-resolve.js +6 -6
  224. package/dist/src/core/build-audit-skip.d.ts +57 -0
  225. package/dist/src/core/build-audit-skip.js +112 -0
  226. package/dist/src/core/build-audit-transforms.d.ts +2 -2
  227. package/dist/src/core/build-audit-transforms.js +3 -3
  228. package/dist/src/core/build-audit.d.ts +21 -8
  229. package/dist/src/core/build-audit.js +142 -40
  230. package/dist/src/core/build-baseline-types.d.ts +19 -18
  231. package/dist/src/core/build-baseline-types.js +1 -1
  232. package/dist/src/core/build-baseline.d.ts +48 -31
  233. package/dist/src/core/build-baseline.js +20 -43
  234. package/dist/src/core/build-jar-escalation.d.ts +8 -8
  235. package/dist/src/core/build-jar-escalation.js +18 -17
  236. package/dist/src/core/build-overwrite-guard.d.ts +4 -4
  237. package/dist/src/core/build-overwrite-guard.js +14 -14
  238. package/dist/src/core/build-prepare.d.ts +4 -12
  239. package/dist/src/core/build-prepare.js +22 -26
  240. package/dist/src/core/config-mutate.js +4 -4
  241. package/dist/src/core/config-paths.d.ts +2 -6
  242. package/dist/src/core/config-paths.js +4 -2
  243. package/dist/src/core/config-state.d.ts +0 -6
  244. package/dist/src/core/config-state.js +3 -21
  245. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  246. package/dist/src/core/config-validate-build-audit.js +80 -0
  247. package/dist/src/core/config-validate-file-size.d.ts +1 -1
  248. package/dist/src/core/config-validate-file-size.js +3 -3
  249. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  250. package/dist/src/core/config-validate-patch-policy.js +3 -3
  251. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  252. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  253. package/dist/src/core/config-validate.js +22 -12
  254. package/dist/src/core/config.d.ts +12 -12
  255. package/dist/src/core/config.js +21 -25
  256. package/dist/src/core/coverage-extend.d.ts +16 -16
  257. package/dist/src/core/coverage-extend.js +20 -20
  258. package/dist/src/core/destructive.d.ts +14 -14
  259. package/dist/src/core/destructive.js +9 -9
  260. package/dist/src/core/diff-hunks.d.ts +2 -2
  261. package/dist/src/core/diff-hunks.js +7 -7
  262. package/dist/src/core/discard-baseline.d.ts +10 -10
  263. package/dist/src/core/discard-baseline.js +22 -23
  264. package/dist/src/core/display-state.d.ts +11 -11
  265. package/dist/src/core/display-state.js +12 -12
  266. package/dist/src/core/engine-changes.d.ts +2 -2
  267. package/dist/src/core/engine-changes.js +2 -2
  268. package/dist/src/core/engine-precondition.d.ts +5 -13
  269. package/dist/src/core/engine-precondition.js +5 -10
  270. package/dist/src/core/engine-session-lock.d.ts +18 -18
  271. package/dist/src/core/engine-session-lock.js +50 -54
  272. package/dist/src/core/export-moved-code-shape.d.ts +7 -7
  273. package/dist/src/core/export-moved-code-shape.js +10 -10
  274. package/dist/src/core/file-lock-owner.d.ts +103 -0
  275. package/dist/src/core/file-lock-owner.js +259 -0
  276. package/dist/src/core/file-lock.d.ts +14 -19
  277. package/dist/src/core/file-lock.js +90 -128
  278. package/dist/src/core/firefox-cache.d.ts +13 -1
  279. package/dist/src/core/firefox-cache.js +61 -36
  280. package/dist/src/core/firefox-download.d.ts +15 -0
  281. package/dist/src/core/firefox-download.js +38 -22
  282. package/dist/src/core/firefox-extract.d.ts +8 -7
  283. package/dist/src/core/firefox-extract.js +45 -27
  284. package/dist/src/core/firefox.d.ts +34 -36
  285. package/dist/src/core/firefox.js +13 -44
  286. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  287. package/dist/src/core/furnace-apply-dry-run.js +2 -8
  288. package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
  289. package/dist/src/core/furnace-apply-ftl.js +8 -8
  290. package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
  291. package/dist/src/core/furnace-apply-helpers.js +28 -39
  292. package/dist/src/core/furnace-apply-output.js +1 -1
  293. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
  294. package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
  295. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
  296. package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
  297. package/dist/src/core/furnace-apply.d.ts +4 -4
  298. package/dist/src/core/furnace-apply.js +50 -29
  299. package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
  300. package/dist/src/core/furnace-checksum-utils.js +5 -5
  301. package/dist/src/core/furnace-config-custom.d.ts +1 -1
  302. package/dist/src/core/furnace-config-custom.js +2 -2
  303. package/dist/src/core/furnace-config-order.js +1 -1
  304. package/dist/src/core/furnace-config-tokens.d.ts +3 -3
  305. package/dist/src/core/furnace-config-tokens.js +3 -3
  306. package/dist/src/core/furnace-config-validate.js +2 -2
  307. package/dist/src/core/furnace-config.d.ts +5 -5
  308. package/dist/src/core/furnace-config.js +40 -53
  309. package/dist/src/core/furnace-constants.d.ts +6 -6
  310. package/dist/src/core/furnace-constants.js +9 -8
  311. package/dist/src/core/furnace-css-fragments.d.ts +6 -6
  312. package/dist/src/core/furnace-css-fragments.js +11 -11
  313. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  314. package/dist/src/core/furnace-dir-entry.js +21 -0
  315. package/dist/src/core/furnace-jsconfig.d.ts +7 -7
  316. package/dist/src/core/furnace-jsconfig.js +22 -20
  317. package/dist/src/core/furnace-operation.d.ts +22 -19
  318. package/dist/src/core/furnace-operation.js +38 -34
  319. package/dist/src/core/furnace-precondition.d.ts +10 -10
  320. package/dist/src/core/furnace-precondition.js +8 -8
  321. package/dist/src/core/furnace-refresh.d.ts +18 -6
  322. package/dist/src/core/furnace-refresh.js +5 -8
  323. package/dist/src/core/furnace-registration-ast.d.ts +2 -3
  324. package/dist/src/core/furnace-registration-ast.js +9 -12
  325. package/dist/src/core/furnace-registration-remove.d.ts +4 -4
  326. package/dist/src/core/furnace-registration-remove.js +6 -6
  327. package/dist/src/core/furnace-registration-validate.d.ts +2 -2
  328. package/dist/src/core/furnace-registration-validate.js +2 -2
  329. package/dist/src/core/furnace-registration.d.ts +7 -6
  330. package/dist/src/core/furnace-registration.js +29 -36
  331. package/dist/src/core/furnace-rollback.d.ts +1 -1
  332. package/dist/src/core/furnace-rollback.js +5 -5
  333. package/dist/src/core/furnace-scanner.js +3 -6
  334. package/dist/src/core/furnace-stale-export.d.ts +17 -16
  335. package/dist/src/core/furnace-stale-export.js +16 -15
  336. package/dist/src/core/furnace-staleness.d.ts +2 -2
  337. package/dist/src/core/furnace-staleness.js +2 -2
  338. package/dist/src/core/furnace-state-persist.d.ts +12 -12
  339. package/dist/src/core/furnace-state-persist.js +10 -10
  340. package/dist/src/core/furnace-step-errors.d.ts +6 -6
  341. package/dist/src/core/furnace-step-errors.js +6 -6
  342. package/dist/src/core/furnace-validate-accessibility.js +14 -14
  343. package/dist/src/core/furnace-validate-compatibility.js +9 -9
  344. package/dist/src/core/furnace-validate-registration.d.ts +2 -2
  345. package/dist/src/core/furnace-validate-registration.js +18 -20
  346. package/dist/src/core/furnace-validate-structure.d.ts +1 -1
  347. package/dist/src/core/furnace-validate-structure.js +4 -4
  348. package/dist/src/core/furnace-validate.js +9 -9
  349. package/dist/src/core/furnace-version-drift.d.ts +5 -5
  350. package/dist/src/core/furnace-version-drift.js +5 -5
  351. package/dist/src/core/git-base.d.ts +6 -4
  352. package/dist/src/core/git-base.js +29 -7
  353. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  354. package/dist/src/core/git-diff-new-file.js +119 -0
  355. package/dist/src/core/git-diff.d.ts +13 -13
  356. package/dist/src/core/git-diff.js +121 -189
  357. package/dist/src/core/git-file-ops.d.ts +6 -13
  358. package/dist/src/core/git-file-ops.js +11 -35
  359. package/dist/src/core/git-readonly-index.d.ts +12 -14
  360. package/dist/src/core/git-readonly-index.js +12 -16
  361. package/dist/src/core/git-status.d.ts +9 -2
  362. package/dist/src/core/git-status.js +23 -11
  363. package/dist/src/core/git.d.ts +3 -9
  364. package/dist/src/core/git.js +28 -57
  365. package/dist/src/core/harness-orphans.d.ts +17 -17
  366. package/dist/src/core/harness-orphans.js +28 -27
  367. package/dist/src/core/history-log.d.ts +19 -0
  368. package/dist/src/core/history-log.js +29 -0
  369. package/dist/src/core/license-headers.d.ts +19 -18
  370. package/dist/src/core/license-headers.js +29 -28
  371. package/dist/src/core/mach-build-artifacts.d.ts +21 -21
  372. package/dist/src/core/mach-build-artifacts.js +23 -23
  373. package/dist/src/core/mach-error-hints.d.ts +5 -10
  374. package/dist/src/core/mach-error-hints.js +14 -14
  375. package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
  376. package/dist/src/core/mach-known-noise-filter.js +57 -56
  377. package/dist/src/core/mach-mozconfig.d.ts +6 -6
  378. package/dist/src/core/mach-mozconfig.js +17 -16
  379. package/dist/src/core/mach-python.d.ts +3 -0
  380. package/dist/src/core/mach-python.js +13 -7
  381. package/dist/src/core/mach-resource-shim.d.ts +24 -12
  382. package/dist/src/core/mach-resource-shim.js +124 -21
  383. package/dist/src/core/mach.d.ts +59 -73
  384. package/dist/src/core/mach.js +47 -115
  385. package/dist/src/core/marionette-port.d.ts +15 -30
  386. package/dist/src/core/marionette-port.js +46 -89
  387. package/dist/src/core/marionette-preflight.d.ts +6 -6
  388. package/dist/src/core/marionette-preflight.js +32 -50
  389. package/dist/src/core/markdown-table.d.ts +9 -9
  390. package/dist/src/core/markdown-table.js +14 -14
  391. package/dist/src/core/mochitest-server-port.d.ts +8 -8
  392. package/dist/src/core/mochitest-server-port.js +17 -17
  393. package/dist/src/core/module-resolution-preflight.d.ts +8 -8
  394. package/dist/src/core/module-resolution-preflight.js +11 -11
  395. package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
  396. package/dist/src/core/moz-manifest-helpers.js +7 -7
  397. package/dist/src/core/moz-manifest-register.d.ts +1 -1
  398. package/dist/src/core/moz-manifest-register.js +2 -2
  399. package/dist/src/core/moz-manifest-rules.js +46 -42
  400. package/dist/src/core/moz-manifest-tokenizers.js +1 -1
  401. package/dist/src/core/ownership-table.d.ts +5 -5
  402. package/dist/src/core/ownership-table.js +7 -7
  403. package/dist/src/core/parser-fallback.d.ts +3 -3
  404. package/dist/src/core/parser-fallback.js +3 -3
  405. package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
  406. package/dist/src/core/patch-apply-fuzz.js +13 -13
  407. package/dist/src/core/patch-apply.d.ts +13 -14
  408. package/dist/src/core/patch-apply.js +36 -42
  409. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  410. package/dist/src/core/patch-export-coverage.js +1 -30
  411. package/dist/src/core/patch-export-update.d.ts +21 -4
  412. package/dist/src/core/patch-export-update.js +7 -6
  413. package/dist/src/core/patch-export.d.ts +20 -30
  414. package/dist/src/core/patch-export.js +55 -77
  415. package/dist/src/core/patch-files.d.ts +0 -4
  416. package/dist/src/core/patch-files.js +0 -11
  417. package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
  418. package/dist/src/core/patch-identifier-suggest.js +4 -4
  419. package/dist/src/core/patch-lint-binary.d.ts +12 -18
  420. package/dist/src/core/patch-lint-cache.d.ts +18 -2
  421. package/dist/src/core/patch-lint-cache.js +16 -19
  422. package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
  423. package/dist/src/core/patch-lint-checkjs.js +78 -64
  424. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
  425. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
  426. package/dist/src/core/patch-lint-creators.d.ts +5 -9
  427. package/dist/src/core/patch-lint-creators.js +3 -3
  428. package/dist/src/core/patch-lint-cross.d.ts +27 -19
  429. package/dist/src/core/patch-lint-cross.js +67 -110
  430. package/dist/src/core/patch-lint-css.d.ts +1 -1
  431. package/dist/src/core/patch-lint-css.js +15 -11
  432. package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
  433. package/dist/src/core/patch-lint-diff-tag.js +5 -5
  434. package/dist/src/core/patch-lint-diff.d.ts +4 -4
  435. package/dist/src/core/patch-lint-diff.js +4 -4
  436. package/dist/src/core/patch-lint-file-size.d.ts +3 -3
  437. package/dist/src/core/patch-lint-file-size.js +6 -6
  438. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  439. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  440. package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
  441. package/dist/src/core/patch-lint-jsdoc.js +46 -46
  442. package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
  443. package/dist/src/core/patch-lint-module-registration.js +1 -1
  444. package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
  445. package/dist/src/core/patch-lint-mozbuild.js +10 -10
  446. package/dist/src/core/patch-lint-observer.d.ts +3 -3
  447. package/dist/src/core/patch-lint-observer.js +7 -7
  448. package/dist/src/core/patch-lint-ownership.d.ts +6 -6
  449. package/dist/src/core/patch-lint-ownership.js +6 -6
  450. package/dist/src/core/patch-lint-prettier.d.ts +6 -6
  451. package/dist/src/core/patch-lint-prettier.js +7 -7
  452. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  453. package/dist/src/core/patch-lint-queue-types.js +12 -0
  454. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  455. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  456. package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
  457. package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
  458. package/dist/src/core/patch-lint.d.ts +41 -35
  459. package/dist/src/core/patch-lint.js +52 -49
  460. package/dist/src/core/patch-lock.d.ts +1 -1
  461. package/dist/src/core/patch-lock.js +11 -11
  462. package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
  463. package/dist/src/core/patch-manifest-consistency.js +16 -17
  464. package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
  465. package/dist/src/core/patch-manifest-files-affected.js +3 -3
  466. package/dist/src/core/patch-manifest-io.d.ts +14 -14
  467. package/dist/src/core/patch-manifest-io.js +35 -34
  468. package/dist/src/core/patch-manifest-query.d.ts +1 -1
  469. package/dist/src/core/patch-manifest-query.js +4 -4
  470. package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
  471. package/dist/src/core/patch-manifest-resolve.js +7 -7
  472. package/dist/src/core/patch-manifest-validate.js +3 -3
  473. package/dist/src/core/patch-manifest.d.ts +2 -2
  474. package/dist/src/core/patch-manifest.js +2 -2
  475. package/dist/src/core/patch-parse.d.ts +32 -21
  476. package/dist/src/core/patch-parse.js +40 -15
  477. package/dist/src/core/patch-policy.js +15 -27
  478. package/dist/src/core/patch-registration-refs.d.ts +4 -4
  479. package/dist/src/core/patch-registration-refs.js +7 -7
  480. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  481. package/dist/src/core/patch-source-metadata.js +0 -4
  482. package/dist/src/core/patch-transform.d.ts +8 -16
  483. package/dist/src/core/patch-transform.js +13 -23
  484. package/dist/src/core/process-cpu-time.d.ts +1 -1
  485. package/dist/src/core/process-cpu-time.js +6 -6
  486. package/dist/src/core/rebase-session.d.ts +9 -15
  487. package/dist/src/core/rebase-session.js +13 -25
  488. package/dist/src/core/register-browser-content.js +3 -2
  489. package/dist/src/core/register-browser-test.js +2 -1
  490. package/dist/src/core/register-module.js +2 -1
  491. package/dist/src/core/register-result.d.ts +1 -1
  492. package/dist/src/core/register-result.js +1 -1
  493. package/dist/src/core/register-scaffold.d.ts +2 -2
  494. package/dist/src/core/register-scaffold.js +8 -7
  495. package/dist/src/core/register-shared-css.d.ts +3 -3
  496. package/dist/src/core/register-shared-css.js +6 -5
  497. package/dist/src/core/register-xpcshell-test.d.ts +2 -2
  498. package/dist/src/core/register-xpcshell-test.js +2 -2
  499. package/dist/src/core/run-log-redact.d.ts +38 -0
  500. package/dist/src/core/run-log-redact.js +69 -0
  501. package/dist/src/core/run-log.d.ts +21 -10
  502. package/dist/src/core/run-log.js +76 -27
  503. package/dist/src/core/shared-ftl.d.ts +2 -2
  504. package/dist/src/core/shared-ftl.js +6 -6
  505. package/dist/src/core/signal-critical.d.ts +2 -2
  506. package/dist/src/core/signal-critical.js +4 -6
  507. package/dist/src/core/smoke-patterns.d.ts +5 -6
  508. package/dist/src/core/smoke-patterns.js +15 -20
  509. package/dist/src/core/state-file.d.ts +15 -4
  510. package/dist/src/core/state-file.js +14 -1
  511. package/dist/src/core/status-binary.d.ts +8 -8
  512. package/dist/src/core/status-binary.js +12 -12
  513. package/dist/src/core/status-classify.d.ts +17 -17
  514. package/dist/src/core/status-classify.js +13 -12
  515. package/dist/src/core/test-changed-prefs.d.ts +12 -12
  516. package/dist/src/core/test-changed-prefs.js +40 -25
  517. package/dist/src/core/test-harness-crash.d.ts +39 -39
  518. package/dist/src/core/test-harness-crash.js +69 -69
  519. package/dist/src/core/test-harness-output.d.ts +7 -7
  520. package/dist/src/core/test-harness-output.js +7 -7
  521. package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
  522. package/dist/src/core/test-harness-verdict-notes.js +4 -4
  523. package/dist/src/core/test-path-scope.d.ts +8 -8
  524. package/dist/src/core/test-path-scope.js +11 -11
  525. package/dist/src/core/test-stale-check.d.ts +22 -23
  526. package/dist/src/core/test-stale-check.js +31 -30
  527. package/dist/src/core/test-stale-symlink.d.ts +1 -1
  528. package/dist/src/core/test-stale-symlink.js +1 -1
  529. package/dist/src/core/test-stall-triage.d.ts +9 -9
  530. package/dist/src/core/test-stall-triage.js +22 -22
  531. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  532. package/dist/src/core/test-xpcshell-retry.js +14 -11
  533. package/dist/src/core/token-category.d.ts +35 -2
  534. package/dist/src/core/token-category.js +67 -58
  535. package/dist/src/core/token-coverage.js +4 -5
  536. package/dist/src/core/token-dark-mode.d.ts +9 -9
  537. package/dist/src/core/token-dark-mode.js +13 -25
  538. package/dist/src/core/token-docs.d.ts +1 -1
  539. package/dist/src/core/token-inventory.d.ts +56 -0
  540. package/dist/src/core/token-inventory.js +109 -0
  541. package/dist/src/core/token-manager.d.ts +4 -4
  542. package/dist/src/core/token-manager.js +22 -22
  543. package/dist/src/core/token-scaffold.d.ts +4 -4
  544. package/dist/src/core/token-scaffold.js +4 -4
  545. package/dist/src/core/token-variant.d.ts +14 -14
  546. package/dist/src/core/token-variant.js +52 -53
  547. package/dist/src/core/toolchain-preflight.d.ts +15 -15
  548. package/dist/src/core/toolchain-preflight.js +23 -23
  549. package/dist/src/core/tree-cow.d.ts +3 -5
  550. package/dist/src/core/tree-cow.js +8 -8
  551. package/dist/src/core/tree-guard.d.ts +3 -3
  552. package/dist/src/core/tree-guard.js +23 -23
  553. package/dist/src/core/tree-store.d.ts +15 -15
  554. package/dist/src/core/tree-store.js +39 -38
  555. package/dist/src/core/typecheck-shim.d.ts +16 -15
  556. package/dist/src/core/typecheck-shim.js +26 -25
  557. package/dist/src/core/typecheck.d.ts +12 -12
  558. package/dist/src/core/typecheck.js +33 -33
  559. package/dist/src/core/wire-destroy.d.ts +2 -2
  560. package/dist/src/core/wire-destroy.js +5 -5
  561. package/dist/src/core/wire-dom-fragment.d.ts +3 -3
  562. package/dist/src/core/wire-dom-fragment.js +12 -23
  563. package/dist/src/core/wire-init.d.ts +2 -2
  564. package/dist/src/core/wire-init.js +7 -7
  565. package/dist/src/core/wire-subscript.d.ts +1 -1
  566. package/dist/src/core/wire-subscript.js +3 -3
  567. package/dist/src/core/wire-utils.d.ts +9 -9
  568. package/dist/src/core/wire-utils.js +16 -28
  569. package/dist/src/core/xpcshell-appdir.d.ts +20 -20
  570. package/dist/src/core/xpcshell-appdir.js +28 -30
  571. package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
  572. package/dist/src/core/xpcshell-profile-dir.js +7 -7
  573. package/dist/src/errors/base.d.ts +69 -16
  574. package/dist/src/errors/base.js +95 -26
  575. package/dist/src/errors/build.d.ts +6 -6
  576. package/dist/src/errors/build.js +26 -34
  577. package/dist/src/errors/codes.d.ts +10 -10
  578. package/dist/src/errors/codes.js +10 -10
  579. package/dist/src/errors/config.d.ts +0 -14
  580. package/dist/src/errors/config.js +13 -34
  581. package/dist/src/errors/download.d.ts +13 -0
  582. package/dist/src/errors/download.js +53 -24
  583. package/dist/src/errors/furnace.d.ts +2 -2
  584. package/dist/src/errors/furnace.js +8 -9
  585. package/dist/src/errors/git.d.ts +9 -9
  586. package/dist/src/errors/git.js +21 -31
  587. package/dist/src/errors/patch.d.ts +3 -3
  588. package/dist/src/errors/patch.js +11 -13
  589. package/dist/src/errors/rebase.d.ts +1 -1
  590. package/dist/src/errors/rebase.js +8 -8
  591. package/dist/src/errors/run.d.ts +1 -1
  592. package/dist/src/errors/run.js +1 -1
  593. package/dist/src/index.d.ts +4 -4
  594. package/dist/src/index.js +4 -4
  595. package/dist/src/types/commands/options.d.ts +155 -200
  596. package/dist/src/types/commands/patches.d.ts +19 -19
  597. package/dist/src/types/commands/project.d.ts +3 -3
  598. package/dist/src/types/config.d.ts +52 -19
  599. package/dist/src/types/furnace.d.ts +17 -17
  600. package/dist/src/types/index.d.ts +0 -1
  601. package/dist/src/types/json.d.ts +3 -3
  602. package/dist/src/types/json.js +2 -2
  603. package/dist/src/types/typecheck.d.ts +3 -3
  604. package/dist/src/utils/assert.d.ts +4 -16
  605. package/dist/src/utils/assert.js +7 -24
  606. package/dist/src/utils/build-info.d.ts +6 -6
  607. package/dist/src/utils/build-info.js +6 -6
  608. package/dist/src/utils/child-env.d.ts +7 -6
  609. package/dist/src/utils/child-env.js +5 -5
  610. package/dist/src/utils/concurrency.d.ts +2 -2
  611. package/dist/src/utils/concurrency.js +2 -2
  612. package/dist/src/utils/elapsed.js +10 -1
  613. package/dist/src/utils/errors.d.ts +8 -8
  614. package/dist/src/utils/errors.js +8 -8
  615. package/dist/src/utils/fs.d.ts +1 -1
  616. package/dist/src/utils/fs.js +15 -20
  617. package/dist/src/utils/hash.d.ts +12 -0
  618. package/dist/src/utils/hash.js +16 -0
  619. package/dist/src/utils/line-dispatch.d.ts +15 -0
  620. package/dist/src/utils/line-dispatch.js +48 -0
  621. package/dist/src/utils/logger.d.ts +4 -4
  622. package/dist/src/utils/logger.js +11 -11
  623. package/dist/src/utils/machine-output.js +2 -2
  624. package/dist/src/utils/options.d.ts +14 -20
  625. package/dist/src/utils/options.js +26 -27
  626. package/dist/src/utils/package-root.js +5 -14
  627. package/dist/src/utils/paths.d.ts +4 -4
  628. package/dist/src/utils/paths.js +4 -4
  629. package/dist/src/utils/platform.d.ts +0 -4
  630. package/dist/src/utils/process-group.d.ts +10 -9
  631. package/dist/src/utils/process-group.js +37 -36
  632. package/dist/src/utils/process.d.ts +70 -55
  633. package/dist/src/utils/process.js +129 -179
  634. package/dist/src/utils/ps-duration.d.ts +4 -4
  635. package/dist/src/utils/ps-duration.js +9 -9
  636. package/dist/src/utils/regex.d.ts +4 -4
  637. package/dist/src/utils/regex.js +7 -7
  638. package/dist/src/utils/sleep.d.ts +26 -0
  639. package/dist/src/utils/sleep.js +31 -0
  640. package/dist/src/utils/stdio-drain.d.ts +7 -7
  641. package/dist/src/utils/stdio-drain.js +8 -8
  642. package/dist/src/utils/validation.d.ts +12 -49
  643. package/dist/src/utils/validation.js +26 -36
  644. package/docs/README.md +2 -2
  645. package/docs/configuration.md +163 -69
  646. package/docs/exit-codes.md +66 -49
  647. package/docs/furnace.md +20 -19
  648. package/docs/lifecycle-invariants.md +414 -247
  649. package/docs/machine-output.md +58 -34
  650. package/docs/patch-workflow.md +48 -44
  651. package/docs/run-logs.md +72 -28
  652. package/docs/testing.md +105 -98
  653. package/docs/verification-trees.md +23 -22
  654. package/package.json +7 -6
  655. package/dist/src/commands/rebase.d.ts +0 -4
  656. package/dist/src/commands/rebase.js +0 -5
  657. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  658. package/dist/src/core/patch-artifact-normalize.js +0 -24
  659. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  660. package/dist/src/core/patch-lint-reexports.js +0 -8
  661. package/dist/src/core/wire-targets.d.ts +0 -7
  662. package/dist/src/core/wire-targets.js +0 -8
@@ -1,5 +1,4 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { loadConfig } from '../core/config.js';
3
2
  import { findNearestXpcshellManifest } from '../core/xpcshell-appdir.js';
4
3
  import { GeneralError } from '../errors/base.js';
5
4
  import { info, success } from '../utils/logger.js';
@@ -46,7 +45,7 @@ export function canaryTimeoutSeconds(projectConfig) {
46
45
  /** Emits or throws the one-word canary verdict. */
47
46
  export function reportCanaryOutcome(outcome) {
48
47
  // Written raw as the run's last stdout line on green and throw paths
49
- // alike — see the FIREFORGE-VERDICT contract in test-harness-crash.ts.
48
+ // alike. See the FIREFORGE-VERDICT contract in test-harness-crash.ts.
50
49
  try {
51
50
  if (outcome.verdict.kind === 'tests-ran-ok') {
52
51
  success('Canary: green');
@@ -98,16 +97,16 @@ function buildMixedHarnessMessage(classification) {
98
97
  * dispatch, so refusing it before spending minutes in a pre-test build
99
98
  * is strictly better. A nonexistent path classifies as
100
99
  * nonXpcshell (findNearestXpcshellManifest returns null), so classifying
101
- * before assertTestPathsExist is harmless — existence is still asserted
100
+ * before assertTestPathsExist is harmless: existence is still asserted
102
101
  * after the stale/coverage gates, preserving their precedence over
103
102
  * missing-path errors. `xpcshellOnly` (non-empty request, zero
104
103
  * nonXpcshell paths) gates the Marionette preflight and the mochitest
105
- * client flags; pathless runs keep the full-suite behavior.
104
+ * client flags. Pathless runs keep the full-suite behavior.
106
105
  */
107
106
  export async function classifyBeforeDispatch(engineDir, normalizedPaths, options) {
108
107
  const classification = await classifyTestHarnesses(engineDir, normalizedPaths);
109
108
  if (classification.xpcshell.length > 0 && classification.nonXpcshell.length > 0) {
110
- // `--build-only` never dispatches, so a mixed request is legal there —
109
+ // `--build-only` never dispatches, so a mixed request is legal there:
111
110
  // packaging the union is the whole point.
112
111
  if (options?.allowMixed !== true) {
113
112
  throw new GeneralError(buildMixedHarnessMessage(classification));
@@ -28,7 +28,7 @@ const TEST_HELP_TEXT = [
28
28
  'Machine-readable verdict: every run (single, sharded, --canary,',
29
29
  '--doctor) ends with exactly one raw stdout line',
30
30
  ' FIREFORGE-VERDICT: PASS|FAIL [reason=crash|test-failures|',
31
- ' no-tests|preflight|inconclusive|lock-timeout] [checks=<n>]',
31
+ ' no-tests|preflight|inconclusive|lock-timeout|killed] [checks=<n>]',
32
32
  ' [unexpected=<n>] [shards=<p>/<t>] [(<note>)] [log=<path>]',
33
33
  "log=<path> names this run's complete output, written to",
34
34
  '.fireforge/logs/ as the run streams, so a piped or truncated run',
@@ -41,7 +41,9 @@ const TEST_HELP_TEXT = [
41
41
  'errors); reason=inconclusive means engine/ changed while the',
42
42
  'tests ran, so the harness result cannot be trusted;',
43
43
  'reason=lock-timeout means the run never started because another',
44
- 'engine-mutating command held the lock past the wait budget. A sharded',
44
+ 'engine-mutating command held the lock past the wait budget;',
45
+ 'reason=killed means a signal terminated the run before it reached',
46
+ 'any other outcome (written from the signal handler). A sharded',
45
47
  'aggregate reason is the most structural failing shard (crash,',
46
48
  'then no-tests, then test-failures). Count keys are omitted when',
47
49
  'the embedded summary did not print them. A trailing parenthetical',
@@ -71,7 +73,7 @@ export function registerTest(program, { getProjectRoot, withErrorHandling }) {
71
73
  .option('--canary [path]', 'Run one short browser-chrome harness canary. Uses test.canaryPath from fireforge.json when no path is supplied.')
72
74
  .option('--doctor', 'Run a marionette handshake preflight before tests (exit 1 on FAIL). With no paths, runs the preflight only.')
73
75
  .option('--mach-arg <arg>', 'Forward this argument verbatim to `mach test` (repeatable). Escape valve for upstream xpcshell/mochitest flags FireForge does not model.', ...stringListOption())
74
- .option('--harness-retries <n>', `Retry budget for recognized harness crashes (resource-monitor tracebacks, pre-test hangs, post-green shutdown re-entry). 0 disables retries. Default: ${String(DEFAULT_HARNESS_RETRIES)}.`, commanderArgParser((raw) => {
76
+ .option('--harness-retries <n>', `Retry budget for recognized harness crashes (resource-monitor tracebacks, pre-test hangs, post-green shutdown re-entry). 0 disables retries. Default: ${DEFAULT_HARNESS_RETRIES}.`, commanderArgParser((raw) => {
75
77
  const n = Number.parseInt(raw, 10);
76
78
  if (!Number.isFinite(n) || n < 0 || n > 10) {
77
79
  throw new GeneralError(`--harness-retries must be an integer in 0..10 (got "${raw}")`);
@@ -3,10 +3,10 @@
3
3
  * sequential per-file sharding of multi-path invocations.
4
4
  *
5
5
  * Sharding exists because passing several browser-chrome files to one mach
6
- * invocation destabilizes later files — cross-file profile/pref bleed in the
6
+ * invocation destabilizes later files: cross-file profile/pref bleed in the
7
7
  * shared mochitest profile makes the second file time out at window-open
8
8
  * while each file passes in isolation. Sequential single-file harness runs
9
- * cost startup time but make results reproducible; the combined invocation
9
+ * cost startup time but make results reproducible. The combined invocation
10
10
  * stays available via `--no-shard`.
11
11
  */
12
12
  import { type DisplaySleepState } from '../core/display-state.js';
@@ -54,8 +54,8 @@ export interface TestRunOutcome {
54
54
  /** Whether xpcshell appdir injection was attempted for this invocation. */
55
55
  appdirInjectionAttempted: boolean;
56
56
  /**
57
- * Display power state measured for a HEADED no-output stall;
58
- * undefined when the shape did not apply and no probe ran.
57
+ * Display power state measured for a HEADED no-output stall. Undefined
58
+ * when the shape did not apply and no probe ran.
59
59
  */
60
60
  displayState?: DisplaySleepState | undefined;
61
61
  }
@@ -68,7 +68,7 @@ export declare function runTestsWithRetries(ctx: TestRunContext, paths: string[]
68
68
  /**
69
69
  * One sequential harness invocation of a sharded run: a requested path
70
70
  * argument and the mach paths dispatched for it. A file argument is a group
71
- * of one; a directory argument groups its enumerated test files so the whole
71
+ * of one. A directory argument groups its enumerated test files so the whole
72
72
  * directory still runs in ONE browser instance, keeping cross-file state
73
73
  * behaviour within a directory run.
74
74
  */
@@ -88,25 +88,25 @@ export interface ShardedRunSummary {
88
88
  shards: ShardOutcome[];
89
89
  passed: number;
90
90
  total: number;
91
- /** Aggregate classifier verdict — see {@link deriveAggregateShardVerdict}. */
91
+ /** Aggregate classifier verdict. See {@link deriveAggregateShardVerdict}. */
92
92
  aggregate: HarnessRunVerdict;
93
93
  }
94
94
  /**
95
95
  * Derives the aggregate classification for a sharded run: all-green is
96
- * `tests-ran-ok`; otherwise the most structural failure wins — a crashed
96
+ * `tests-ran-ok`. Otherwise the most structural failure wins. A crashed
97
97
  * shard makes the whole run `harness-crash`, then `no-tests`, then plain
98
- * `test-failures` — so the aggregate `reason=` keeps the classifier-driven
98
+ * `test-failures`, so the aggregate `reason=` keeps the classifier-driven
99
99
  * contract instead of collapsing every failure to `test-failures`.
100
100
  */
101
101
  export declare function deriveAggregateShardVerdict(shards: ShardOutcome[]): HarnessRunVerdict;
102
102
  /**
103
103
  * Runs each requested path argument as its own sequential harness
104
104
  * invocation (a directory argument's enumerated files stay together in
105
- * one invocation — see {@link ShardGroup}) and prints an aggregate
105
+ * one invocation, see {@link ShardGroup}) and prints an aggregate
106
106
  * report. Per-shard failures are diagnosed via `diagnoseShardFailure`
107
107
  * (which receives the throwing diagnosis chain from the command layer)
108
108
  * but downgraded to warnings so every shard runs. The aggregate verdict
109
- * line and the aggregate error are NOT produced here — the caller runs
109
+ * line and the aggregate error are not produced here: the caller runs
110
110
  * the engine-generation integrity check first and then calls
111
111
  * {@link finalizeShardedOutcome}, so a run invalidated by a concurrent
112
112
  * `engine/` mutation can never print `PASS` before the check fails.
@@ -114,7 +114,7 @@ export declare function deriveAggregateShardVerdict(shards: ShardOutcome[]): Har
114
114
  export declare function runShardedTests(ctx: TestRunContext, groups: ShardGroup[], diagnoseShardFailure: (outcome: TestRunOutcome, label: string) => string | undefined): Promise<ShardedRunSummary>;
115
115
  /**
116
116
  * Emits the aggregate FIREFORGE-VERDICT line for a sharded run, then
117
- * throws the aggregate error when any shard did not pass — the same
117
+ * throws the aggregate error when any shard did not pass, the same
118
118
  * emit-then-throw shape as `finalizeSingleRunOutcome`. Called only after
119
119
  * the engine-generation check succeeded.
120
120
  */
@@ -4,14 +4,14 @@
4
4
  * sequential per-file sharding of multi-path invocations.
5
5
  *
6
6
  * Sharding exists because passing several browser-chrome files to one mach
7
- * invocation destabilizes later files — cross-file profile/pref bleed in the
7
+ * invocation destabilizes later files: cross-file profile/pref bleed in the
8
8
  * shared mochitest profile makes the second file time out at window-open
9
9
  * while each file passes in isolation. Sequential single-file harness runs
10
- * cost startup time but make results reproducible; the combined invocation
10
+ * cost startup time but make results reproducible. The combined invocation
11
11
  * stays available via `--no-shard`.
12
12
  */
13
13
  import { probeDisplaySleepState } from '../core/display-state.js';
14
- import { mochitestWithOutput, testWithOutput, xpcshellTestWithOutput, } from '../core/mach.js';
14
+ import { runMachTestSuite } from '../core/mach.js';
15
15
  import { getActiveRunLogPath } from '../core/run-log.js';
16
16
  import { changedPrefNoiseVerdictNote } from '../core/test-changed-prefs.js';
17
17
  import { buildHarnessCrashMessage, classifyHarnessRun, headedDisplayAsleepVerdictNote, headedNoOutputTimeoutHint, } from '../core/test-harness-crash.js';
@@ -24,13 +24,13 @@ import { maybeInjectAppdirArg } from './test-appdir.js';
24
24
  import { emitHarnessVerdict } from './test-verdict.js';
25
25
  /** Default bounded retry budget for recognized harness crashes. */
26
26
  export const DEFAULT_HARNESS_RETRIES = 2;
27
- /** Resolves the capturing mach dispatcher for a suite. */
28
- function dispatchForSuite(suite) {
27
+ /** Resolves the mach test command a suite dispatches to. */
28
+ function machKindForSuite(suite) {
29
29
  if (suite === 'xpcshell')
30
- return xpcshellTestWithOutput;
30
+ return 'xpcshell-test';
31
31
  if (suite === 'mochitest')
32
- return mochitestWithOutput;
33
- return testWithOutput;
32
+ return 'mochitest';
33
+ return 'test';
34
34
  }
35
35
  /**
36
36
  * Runs one mach test invocation for `paths`, retrying recognized harness
@@ -38,40 +38,47 @@ function dispatchForSuite(suite) {
38
38
  * stale-xpcshell-symlink repair path the single-run flow already used.
39
39
  */
40
40
  export async function runTestsWithRetries(ctx, paths) {
41
- // Pure mochitest dispatches keep their env byte-identical — the profile
41
+ // Pure mochitest dispatches keep their env byte-identical, since the profile
42
42
  // variable is xpcshell-harness-specific. Generic `mach
43
43
  // test` runs may include xpcshell paths, so they get the isolation too.
44
44
  if (ctx.suite === 'mochitest') {
45
45
  return runTestsWithRetriesInner(ctx, paths, ctx.env);
46
46
  }
47
47
  // Fresh profile dir per harness invocation: shards isolate from each
48
- // other and from concurrent `fireforge test` processes; the crash /
49
- // symlink-repair retries inside one invocation deliberately REUSE the
50
- // same directory (they are the same logical run and the harness
48
+ // other and from concurrent `fireforge test` processes. The crash /
49
+ // symlink-repair retries inside one invocation reuse the same directory
50
+ // on purpose (they are the same logical run and the harness
51
51
  // re-initialises the profile contents itself).
52
52
  return withXpcshellProfileDir(ctx.env, (env) => runTestsWithRetriesInner(ctx, paths, env));
53
53
  }
54
54
  async function runTestsWithRetriesInner(ctx, paths, env) {
55
55
  const extraArgs = [...ctx.baseExtraArgs];
56
56
  const appdirInjectionAttempted = await maybeInjectAppdirArg(ctx.engineDir, paths, ctx.objDir, extraArgs);
57
- const dispatch = dispatchForSuite(ctx.suite);
57
+ const kind = machKindForSuite(ctx.suite);
58
58
  const maxAttempts = Math.max(1, ctx.harnessRetries + 1);
59
59
  let attempts = 0;
60
60
  let result;
61
61
  let verdict;
62
62
  for (;;) {
63
63
  attempts += 1;
64
- // Arity is kept minimal when there is nothing extra to pass: the
65
- // dispatchers' trailing parameters are optional, and appending explicit
66
- // `undefined`s would only make every call site's shape depend on
67
- // features the run is not using.
68
- result =
69
- ctx.fullOutput === true
70
- ? await dispatch(ctx.engineDir, paths, extraArgs, env, true)
71
- : env
72
- ? await dispatch(ctx.engineDir, paths, extraArgs, env)
73
- : await dispatch(ctx.engineDir, paths, extraArgs);
74
- result = await retryAfterXpcshellSymlinkRepair(ctx.engineDir, ctx.objDir, result, ctx.classification, paths, extraArgs, env, dispatch, ctx.fullOutput);
64
+ result = await runMachTestSuite(kind, {
65
+ engineDir: ctx.engineDir,
66
+ testPaths: paths,
67
+ args: extraArgs,
68
+ env,
69
+ fullOutput: ctx.fullOutput,
70
+ });
71
+ result = await retryAfterXpcshellSymlinkRepair({
72
+ engineDir: ctx.engineDir,
73
+ objDir: ctx.objDir,
74
+ result,
75
+ classification: ctx.classification,
76
+ normalizedPaths: paths,
77
+ extraArgs,
78
+ env,
79
+ kind,
80
+ fullOutput: ctx.fullOutput,
81
+ });
75
82
  const combined = `${result.stdout}\n${result.stderr}`;
76
83
  verdict = classifyHarnessRun(result.exitCode, combined, paths);
77
84
  if (verdict.kind !== 'harness-crash' || attempts >= maxAttempts)
@@ -81,7 +88,7 @@ async function runTestsWithRetriesInner(ctx, paths, env) {
81
88
  `Retrying (attempt ${attempts + 1} of ${maxAttempts})...`);
82
89
  }
83
90
  // A verdict whose every unexpected result is time-driven pref noise is
84
- // still a FAIL — only the note changes, so a `unexpected=2` line is not
91
+ // still a FAIL. Only the note changes, so a `unexpected=2` line is not
85
92
  // read as two real assertion failures.
86
93
  if (verdict.kind === 'test-failures' && verdict.note === undefined) {
87
94
  const prefNote = changedPrefNoiseVerdictNote(`${result.stdout}\n${result.stderr}`);
@@ -101,9 +108,9 @@ async function runTestsWithRetriesInner(ctx, paths, env) {
101
108
  return { result, verdict, attempts, appdirInjectionAttempted, displayState };
102
109
  }
103
110
  /**
104
- * Probes the display's power state for a HEADED no-output stall, and only for
105
- * that shape. Every other outcome — a passing run, a real test failure, a
106
- * headless run, any other crash shape — skips the probe entirely, so the
111
+ * Probes the display's power state for a headed no-output stall, and only for
112
+ * that shape. Every other outcome (a passing run, a real test failure, a
113
+ * headless run, any other crash shape) skips the probe entirely, so the
107
114
  * common paths spawn nothing.
108
115
  *
109
116
  * @returns The measured state, or undefined when the shape does not apply
@@ -125,9 +132,9 @@ const SHARD_STATUS_LABEL = {
125
132
  };
126
133
  /**
127
134
  * Derives the aggregate classification for a sharded run: all-green is
128
- * `tests-ran-ok`; otherwise the most structural failure wins — a crashed
135
+ * `tests-ran-ok`. Otherwise the most structural failure wins. A crashed
129
136
  * shard makes the whole run `harness-crash`, then `no-tests`, then plain
130
- * `test-failures` — so the aggregate `reason=` keeps the classifier-driven
137
+ * `test-failures`, so the aggregate `reason=` keeps the classifier-driven
131
138
  * contract instead of collapsing every failure to `test-failures`.
132
139
  */
133
140
  export function deriveAggregateShardVerdict(shards) {
@@ -143,11 +150,11 @@ export function deriveAggregateShardVerdict(shards) {
143
150
  /**
144
151
  * Runs each requested path argument as its own sequential harness
145
152
  * invocation (a directory argument's enumerated files stay together in
146
- * one invocation — see {@link ShardGroup}) and prints an aggregate
153
+ * one invocation, see {@link ShardGroup}) and prints an aggregate
147
154
  * report. Per-shard failures are diagnosed via `diagnoseShardFailure`
148
155
  * (which receives the throwing diagnosis chain from the command layer)
149
156
  * but downgraded to warnings so every shard runs. The aggregate verdict
150
- * line and the aggregate error are NOT produced here — the caller runs
157
+ * line and the aggregate error are not produced here: the caller runs
151
158
  * the engine-generation integrity check first and then calls
152
159
  * {@link finalizeShardedOutcome}, so a run invalidated by a concurrent
153
160
  * `engine/` mutation can never print `PASS` before the check fails.
@@ -186,7 +193,7 @@ export async function runShardedTests(ctx, groups, diagnoseShardFailure) {
186
193
  }
187
194
  /**
188
195
  * Emits the aggregate FIREFORGE-VERDICT line for a sharded run, then
189
- * throws the aggregate error when any shard did not pass — the same
196
+ * throws the aggregate error when any shard did not pass, the same
190
197
  * emit-then-throw shape as `finalizeSingleRunOutcome`. Called only after
191
198
  * the engine-generation check succeeded.
192
199
  */
@@ -3,40 +3,40 @@
3
3
  * and a run against a stale or under-packaged runtime: the packaging
4
4
  * coverage refusal, the stale-content refusal, and the compiled
5
5
  * StaticComponents refusal. Split out of `test.ts` so the command module
6
- * stays wiring; the probes and refusal copy live in
6
+ * stays wiring. The probes and refusal copy live in
7
7
  * `src/core/test-stale-check.ts`.
8
8
  */
9
9
  import type { BuildBaseline } from '../core/build-baseline-types.js';
10
10
  import type { TestOptions } from '../types/commands/index.js';
11
11
  /**
12
- * Stale-build preflight — when `--build` was NOT requested, detect packageable
13
- * engine edits since the last successful build and fail UP-FRONT unless the
12
+ * Stale-build preflight: when `--build` was not requested, detect packageable
13
+ * engine edits since the last successful build and fail up front unless the
14
14
  * operator explicitly accepts the stale package risk.
15
15
  *
16
- * Packaging COVERAGE is checked first, on EVERY non-`--build` run and
16
+ * Packaging coverage is checked first, on every non-`--build` run and
17
17
  * regardless of staleness or `--allow-stale-build`: a runtime packaged by a
18
- * file-scoped `test --build` can lack support fixtures for OTHER manifests
19
- * even when nothing changed since — dispatching such a run hangs on missing
18
+ * file-scoped `test --build` can lack support fixtures for other manifests
19
+ * even when nothing changed since, and dispatching such a run hangs on missing
20
20
  * fixtures rather than failing, so the flag (which only accepts stale
21
- * CONTENT) must not be the trigger. A three-file scoped rebuild leaving one
21
+ * content) must not be the trigger. A three-file scoped rebuild leaving one
22
22
  * fixture unpackaged makes a later run over different files time out waiting
23
23
  * on an event that never fires.
24
24
  *
25
25
  * Exception: a path-less `test --doctor` stops at the Marionette health check
26
26
  * (`runDoctorPreflight` returns 'stop' when no test paths were given) and
27
- * never dispatches a test, so it needs no packaging coverage — treating it as
27
+ * never dispatches a test, so it needs no packaging coverage. Treating it as
28
28
  * a full-suite request would refuse a probe that touches no fixtures. The
29
29
  * stale-content refusal still applies to it unchanged.
30
30
  */
31
31
  export declare function enforceStaleBuildGate(projectRoot: string, engineDir: string, options: TestOptions, normalizedPaths: readonly string[]): Promise<void>;
32
32
  /**
33
- * Compiled-StaticComponents gate — refuses runs whose child process would
33
+ * Compiled-StaticComponents gate: refuses runs whose child process would
34
34
  * resolve a stale compiled component table. `components.conf` entries bake
35
- * into compiled code that only a FULL build regenerates; a scoped
35
+ * into compiled code that only a full build regenerates. A scoped
36
36
  * `test --build` repackages the file but the failure surfaces as
37
37
  * `NS_ERROR_MALFORMED_URI` inside the test. Applies to build-less runs
38
- * (after the coverage refusal) AND to scoped `test --build` runs (before
39
- * the pre-test build — that build cannot fix the table). A path-less
38
+ * (after the coverage refusal) and to scoped `test --build` runs (before
39
+ * the pre-test build, which cannot fix the table). A path-less
40
40
  * `test --build` is exempt: its full build refreshes the anchor itself.
41
41
  * `--allow-stale-components` downgrades the refusal to a warning.
42
42
  */
@@ -4,29 +4,29 @@
4
4
  * and a run against a stale or under-packaged runtime: the packaging
5
5
  * coverage refusal, the stale-content refusal, and the compiled
6
6
  * StaticComponents refusal. Split out of `test.ts` so the command module
7
- * stays wiring; the probes and refusal copy live in
7
+ * stays wiring. The probes and refusal copy live in
8
8
  * `src/core/test-stale-check.ts`.
9
9
  */
10
10
  import { checkStaleBuildForTest, checkStaticComponentsStale, findChangedTestManifestsForPaths, findUncoveredRequestPaths, formatStaleBuildWarning, formatStaticComponentsRefusal, formatTestCoverageRefusal, } from '../core/test-stale-check.js';
11
- import { GeneralError } from '../errors/base.js';
11
+ import { PreflightRefusalError } from '../errors/base.js';
12
12
  import { warn } from '../utils/logger.js';
13
13
  /**
14
- * Stale-build preflight — when `--build` was NOT requested, detect packageable
15
- * engine edits since the last successful build and fail UP-FRONT unless the
14
+ * Stale-build preflight: when `--build` was not requested, detect packageable
15
+ * engine edits since the last successful build and fail up front unless the
16
16
  * operator explicitly accepts the stale package risk.
17
17
  *
18
- * Packaging COVERAGE is checked first, on EVERY non-`--build` run and
18
+ * Packaging coverage is checked first, on every non-`--build` run and
19
19
  * regardless of staleness or `--allow-stale-build`: a runtime packaged by a
20
- * file-scoped `test --build` can lack support fixtures for OTHER manifests
21
- * even when nothing changed since — dispatching such a run hangs on missing
20
+ * file-scoped `test --build` can lack support fixtures for other manifests
21
+ * even when nothing changed since, and dispatching such a run hangs on missing
22
22
  * fixtures rather than failing, so the flag (which only accepts stale
23
- * CONTENT) must not be the trigger. A three-file scoped rebuild leaving one
23
+ * content) must not be the trigger. A three-file scoped rebuild leaving one
24
24
  * fixture unpackaged makes a later run over different files time out waiting
25
25
  * on an event that never fires.
26
26
  *
27
27
  * Exception: a path-less `test --doctor` stops at the Marionette health check
28
28
  * (`runDoctorPreflight` returns 'stop' when no test paths were given) and
29
- * never dispatches a test, so it needs no packaging coverage — treating it as
29
+ * never dispatches a test, so it needs no packaging coverage. Treating it as
30
30
  * a full-suite request would refuse a probe that touches no fixtures. The
31
31
  * stale-content refusal still applies to it unchanged.
32
32
  */
@@ -37,10 +37,10 @@ export async function enforceStaleBuildGate(projectRoot, engineDir, options, nor
37
37
  const recordedCoverage = stale.baseline?.testPackagingCoverage;
38
38
  const uncovered = findUncoveredRequestPaths(recordedCoverage, normalizedPaths);
39
39
  if (uncovered.length > 0) {
40
- // The refusal is correct on its own; naming the manifest that gained
40
+ // The refusal is correct on its own. Naming the manifest that gained
41
41
  // an entry is the triage step it otherwise leaves to the reader.
42
42
  const changedManifests = await findChangedTestManifestsForPaths(engineDir, stale.baseline, uncovered);
43
- throw new GeneralError(formatTestCoverageRefusal(uncovered, Array.isArray(recordedCoverage) ? recordedCoverage : [], changedManifests));
43
+ throw new PreflightRefusalError(formatTestCoverageRefusal(uncovered, Array.isArray(recordedCoverage) ? recordedCoverage : [], changedManifests), 'coverage-replaced');
44
44
  }
45
45
  }
46
46
  await enforceStaticComponentsGate(engineDir, stale.baseline, options);
@@ -59,18 +59,18 @@ export async function enforceStaleBuildGate(projectRoot, engineDir, options, nor
59
59
  warn(staleMessage);
60
60
  }
61
61
  else {
62
- throw new GeneralError(staleMessage);
62
+ throw new PreflightRefusalError(staleMessage, 'stale-build');
63
63
  }
64
64
  }
65
65
  }
66
66
  /**
67
- * Compiled-StaticComponents gate — refuses runs whose child process would
67
+ * Compiled-StaticComponents gate: refuses runs whose child process would
68
68
  * resolve a stale compiled component table. `components.conf` entries bake
69
- * into compiled code that only a FULL build regenerates; a scoped
69
+ * into compiled code that only a full build regenerates. A scoped
70
70
  * `test --build` repackages the file but the failure surfaces as
71
71
  * `NS_ERROR_MALFORMED_URI` inside the test. Applies to build-less runs
72
- * (after the coverage refusal) AND to scoped `test --build` runs (before
73
- * the pre-test build — that build cannot fix the table). A path-less
72
+ * (after the coverage refusal) and to scoped `test --build` runs (before
73
+ * the pre-test build, which cannot fix the table). A path-less
74
74
  * `test --build` is exempt: its full build refreshes the anchor itself.
75
75
  * `--allow-stale-components` downgrades the refusal to a warning.
76
76
  */
@@ -84,5 +84,5 @@ export async function enforceStaticComponentsGate(engineDir, baseline, options)
84
84
  warn(message);
85
85
  return;
86
86
  }
87
- throw new GeneralError(message);
87
+ throw new PreflightRefusalError(message, 'stale-components');
88
88
  }
@@ -1,7 +1,7 @@
1
1
  import type { HarnessRunVerdict } from '../core/test-harness-crash.js';
2
2
  /**
3
3
  * Reason codes the emission layer can put on a `FIREFORGE-VERDICT: FAIL`
4
- * line. The first three mirror the harness classifier; `preflight` covers
4
+ * line. The first three mirror the harness classifier. `preflight` covers
5
5
  * every failure before harness classification (missing/stale builds,
6
6
  * invalid paths, port conflicts, config errors, spawn failures),
7
7
  * `inconclusive` marks a run whose harness result exists but cannot be
@@ -30,13 +30,27 @@ export declare function emitHarnessVerdict(verdict: HarnessRunVerdict, shards?:
30
30
  }): void;
31
31
  /** Emits the pathless `--doctor` PASS verdict. */
32
32
  export declare function emitPassVerdict(): void;
33
- /** Emits a FAIL verdict carrying an emission-layer reason code. */
34
- export declare function emitFailVerdict(reason: FireforgeVerdictReason): void;
33
+ /**
34
+ * Emits a FAIL verdict carrying an emission-layer reason code, and
35
+ * optionally the refusal class that produced it.
36
+ *
37
+ * `note=` is additive, like the `log=`, `signal=` and `shards=` keys already
38
+ * on this line: `reason=` is unchanged and still comes from the closed set
39
+ * in `docs/machine-output.md`, so a consumer that tokenises `key=value`
40
+ * pairs is unaffected. It exists because `reason=preflight` covers every
41
+ * gate before the harness (a missing build, a peer's packaging record, a
42
+ * developer browser holding the objdir), and an unattended reader whose
43
+ * pipe kept only the verdict line could not tell those apart.
44
+ *
45
+ * @param reason - Closed-set verdict reason
46
+ * @param note - Stable refusal class, when the thrower named one
47
+ */
48
+ export declare function emitFailVerdict(reason: FireforgeVerdictReason, note?: string): void;
35
49
  /**
36
50
  * Emits the terminal verdict for a run killed by a signal.
37
51
  *
38
- * Without it a killed run wrote NO terminal line, so a log tail could not
39
- * distinguish "killed" from "still running" from "never started" — recovery
52
+ * Without it a killed run wrote no terminal line, so a log tail could not
53
+ * distinguish "killed" from "still running" from "never started". Recovery
40
54
  * meant checking `ps` and the lock file by hand, at the exact moment (a
41
55
  * mass kill under a usage limit, mid-drain) when the tree's state most
42
56
  * needs to be readable. A no-op unless a run was actually in flight: the
@@ -27,21 +27,21 @@ export function verdictEmitted() {
27
27
  return emitted;
28
28
  }
29
29
  /**
30
- * Writes the run's single verdict line — raw stdout (clack's renderer can
31
- * drop output under non-TTY capture), first write wins. Every later call
30
+ * Writes the run's single verdict line to raw stdout (clack's renderer can
31
+ * drop output under non-TTY capture). First write wins. Every later call
32
32
  * is a no-op: the writer closest to the harness result runs first, so the
33
33
  * fallback layers (the engine-generation guard, the preflight wrapper)
34
34
  * can emit unconditionally without risking a second line. Writing also
35
- * seals stdout: the verdict must stay the run's LAST stdout write, so all
36
- * subsequent logger output — including the CLI-boundary error/cancel
37
- * rendering after an emit-then-throw path — routes to stderr.
35
+ * seals stdout: the verdict must stay the run's last stdout write, so all
36
+ * subsequent logger output, including the CLI-boundary error/cancel
37
+ * rendering after an emit-then-throw path, routes to stderr.
38
38
  */
39
39
  function writeVerdictLine(line) {
40
40
  if (emitted)
41
41
  return;
42
42
  emitted = true;
43
43
  // The run log's path rides the verdict line because the verdict must stay
44
- // the run's LAST stdout write — a separate announcement after it would
44
+ // the run's last stdout write: a separate announcement after it would
45
45
  // break that contract, and one before it is the first thing a `tail` cuts.
46
46
  // Appended as an additive `key=value`, so consumers that tokenize the line
47
47
  // are unaffected and a truncated tail still says where the full output is.
@@ -61,15 +61,30 @@ export function emitHarnessVerdict(verdict, shards) {
61
61
  export function emitPassVerdict() {
62
62
  writeVerdictLine('FIREFORGE-VERDICT: PASS');
63
63
  }
64
- /** Emits a FAIL verdict carrying an emission-layer reason code. */
65
- export function emitFailVerdict(reason) {
66
- writeVerdictLine(`FIREFORGE-VERDICT: FAIL reason=${reason}`);
64
+ /**
65
+ * Emits a FAIL verdict carrying an emission-layer reason code, and
66
+ * optionally the refusal class that produced it.
67
+ *
68
+ * `note=` is additive, like the `log=`, `signal=` and `shards=` keys already
69
+ * on this line: `reason=` is unchanged and still comes from the closed set
70
+ * in `docs/machine-output.md`, so a consumer that tokenises `key=value`
71
+ * pairs is unaffected. It exists because `reason=preflight` covers every
72
+ * gate before the harness (a missing build, a peer's packaging record, a
73
+ * developer browser holding the objdir), and an unattended reader whose
74
+ * pipe kept only the verdict line could not tell those apart.
75
+ *
76
+ * @param reason - Closed-set verdict reason
77
+ * @param note - Stable refusal class, when the thrower named one
78
+ */
79
+ export function emitFailVerdict(reason, note) {
80
+ const suffix = note === undefined ? '' : ` note=${note}`;
81
+ writeVerdictLine(`FIREFORGE-VERDICT: FAIL reason=${reason}${suffix}`);
67
82
  }
68
83
  /**
69
84
  * Emits the terminal verdict for a run killed by a signal.
70
85
  *
71
- * Without it a killed run wrote NO terminal line, so a log tail could not
72
- * distinguish "killed" from "still running" from "never started" — recovery
86
+ * Without it a killed run wrote no terminal line, so a log tail could not
87
+ * distinguish "killed" from "still running" from "never started". Recovery
73
88
  * meant checking `ps` and the lock file by hand, at the exact moment (a
74
89
  * mass kill under a usage limit, mid-drain) when the tree's state most
75
90
  * needs to be readable. A no-op unless a run was actually in flight: the
@@ -4,9 +4,9 @@ import type { TestOptions } from '../types/commands/index.js';
4
4
  *
5
5
  * Owns the run's exactly-one-`FIREFORGE-VERDICT:`-line guarantee: the sink
6
6
  * is re-armed at entry, and any failure that reaches this boundary without
7
- * an inner writer having emitted — the preflight ladder (missing engine or
8
- * build, config errors, stale-build and port gates, missing paths), and a
9
- * harness process that failed to start — emits `FAIL reason=preflight`,
7
+ * an inner writer having emitted (the preflight ladder: missing engine or
8
+ * build, config errors, stale-build and port gates, missing paths, and a
9
+ * harness process that failed to start) emits `FAIL reason=preflight`,
10
10
  * since no harness classification exists for such a run. Writers closer to
11
11
  * the harness (doctor, canary, single, sharded, the engine-generation
12
12
  * guard) emit first and win.