@hominis/fireforge 0.43.1 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +10 -1
  3. package/dist/bin/fireforge.d.ts +4 -9
  4. package/dist/bin/fireforge.js +42 -40
  5. package/dist/build-info.json +4 -4
  6. package/dist/src/cli.js +74 -8
  7. package/dist/src/commands/bootstrap.js +17 -20
  8. package/dist/src/commands/build.js +25 -32
  9. package/dist/src/commands/config.js +34 -41
  10. package/dist/src/commands/discard.js +8 -9
  11. package/dist/src/commands/doctor-check-core.d.ts +4 -18
  12. package/dist/src/commands/doctor-check-core.js +8 -35
  13. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  14. package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
  15. package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
  16. package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
  17. package/dist/src/commands/doctor-furnace-jar.js +7 -9
  18. package/dist/src/commands/doctor-furnace.js +21 -24
  19. package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
  20. package/dist/src/commands/doctor-orphaned-harness.js +18 -44
  21. package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
  22. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  23. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  24. package/dist/src/commands/doctor-working-tree.js +11 -18
  25. package/dist/src/commands/doctor.js +35 -53
  26. package/dist/src/commands/download.js +32 -48
  27. package/dist/src/commands/export-all.js +29 -33
  28. package/dist/src/commands/export-flow.js +6 -6
  29. package/dist/src/commands/export-placement-conflicts.js +10 -9
  30. package/dist/src/commands/export-placement-gate.js +5 -5
  31. package/dist/src/commands/export-shared.d.ts +30 -33
  32. package/dist/src/commands/export-shared.js +45 -43
  33. package/dist/src/commands/export.js +21 -27
  34. package/dist/src/commands/furnace/apply.js +14 -23
  35. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  36. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  37. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  38. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  39. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  40. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  41. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  42. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  43. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  44. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  45. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  46. package/dist/src/commands/furnace/create-readback.js +12 -13
  47. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  48. package/dist/src/commands/furnace/create-templates.js +35 -30
  49. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  50. package/dist/src/commands/furnace/create.js +33 -23
  51. package/dist/src/commands/furnace/deploy.js +16 -24
  52. package/dist/src/commands/furnace/diff.js +9 -9
  53. package/dist/src/commands/furnace/init.js +33 -36
  54. package/dist/src/commands/furnace/override.js +23 -25
  55. package/dist/src/commands/furnace/preview.js +47 -67
  56. package/dist/src/commands/furnace/refresh.js +12 -16
  57. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  58. package/dist/src/commands/furnace/remove-mutations.js +9 -16
  59. package/dist/src/commands/furnace/remove-state.js +1 -1
  60. package/dist/src/commands/furnace/remove.js +33 -38
  61. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  62. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  63. package/dist/src/commands/furnace/rename.js +59 -69
  64. package/dist/src/commands/furnace/scan.js +19 -33
  65. package/dist/src/commands/furnace/status.js +12 -9
  66. package/dist/src/commands/furnace/sync.js +9 -16
  67. package/dist/src/commands/furnace/validate.js +20 -20
  68. package/dist/src/commands/import.js +42 -35
  69. package/dist/src/commands/lint-per-patch.js +15 -10
  70. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  71. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  72. package/dist/src/commands/lint-report.js +6 -7
  73. package/dist/src/commands/lint.d.ts +15 -16
  74. package/dist/src/commands/lint.js +86 -102
  75. package/dist/src/commands/package.js +6 -11
  76. package/dist/src/commands/patch/compact.js +1 -1
  77. package/dist/src/commands/patch/delete.js +24 -33
  78. package/dist/src/commands/patch/index.d.ts +5 -6
  79. package/dist/src/commands/patch/index.js +10 -12
  80. package/dist/src/commands/patch/lint-ignore.js +14 -13
  81. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  82. package/dist/src/commands/patch/move-files-create.js +8 -8
  83. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  84. package/dist/src/commands/patch/move-files-into.js +8 -8
  85. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  86. package/dist/src/commands/patch/patch-context.js +2 -3
  87. package/dist/src/commands/patch/rename.d.ts +10 -11
  88. package/dist/src/commands/patch/rename.js +11 -12
  89. package/dist/src/commands/patch/reorder.js +8 -9
  90. package/dist/src/commands/patch/split-plan.js +1 -1
  91. package/dist/src/commands/patch/split.d.ts +8 -10
  92. package/dist/src/commands/patch/split.js +9 -11
  93. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  94. package/dist/src/commands/patch/staged-dependency.js +7 -3
  95. package/dist/src/commands/patch/tier.d.ts +9 -9
  96. package/dist/src/commands/patch/tier.js +18 -15
  97. package/dist/src/commands/re-export-adjacent.js +9 -8
  98. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  99. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  100. package/dist/src/commands/re-export-drift.js +10 -10
  101. package/dist/src/commands/re-export-files.d.ts +6 -7
  102. package/dist/src/commands/re-export-files.js +34 -44
  103. package/dist/src/commands/re-export-lint.d.ts +10 -13
  104. package/dist/src/commands/re-export-lint.js +16 -14
  105. package/dist/src/commands/re-export-options.d.ts +6 -6
  106. package/dist/src/commands/re-export-options.js +6 -6
  107. package/dist/src/commands/re-export-register.d.ts +4 -10
  108. package/dist/src/commands/re-export-register.js +5 -11
  109. package/dist/src/commands/re-export-scan.js +1 -1
  110. package/dist/src/commands/re-export-single.d.ts +3 -3
  111. package/dist/src/commands/re-export-single.js +33 -25
  112. package/dist/src/commands/re-export.js +13 -21
  113. package/dist/src/commands/rebase/abort.js +3 -3
  114. package/dist/src/commands/rebase/confirm.js +2 -1
  115. package/dist/src/commands/rebase/continue.d.ts +1 -1
  116. package/dist/src/commands/rebase/continue.js +14 -9
  117. package/dist/src/commands/rebase/index.js +11 -11
  118. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  119. package/dist/src/commands/rebase/patch-loop.js +60 -39
  120. package/dist/src/commands/rebase/summary.js +1 -1
  121. package/dist/src/commands/register.js +5 -7
  122. package/dist/src/commands/reset.js +2 -1
  123. package/dist/src/commands/resolve.d.ts +16 -13
  124. package/dist/src/commands/resolve.js +30 -33
  125. package/dist/src/commands/run.js +33 -35
  126. package/dist/src/commands/setup-support.js +15 -19
  127. package/dist/src/commands/setup.js +13 -9
  128. package/dist/src/commands/status-check.d.ts +6 -6
  129. package/dist/src/commands/status-json.d.ts +6 -6
  130. package/dist/src/commands/status-json.js +5 -0
  131. package/dist/src/commands/status-output.d.ts +5 -5
  132. package/dist/src/commands/status-output.js +6 -6
  133. package/dist/src/commands/status-ownership.d.ts +16 -14
  134. package/dist/src/commands/status-ownership.js +16 -14
  135. package/dist/src/commands/status.js +42 -34
  136. package/dist/src/commands/test-build-phase.js +26 -13
  137. package/dist/src/commands/test-diagnose.js +44 -44
  138. package/dist/src/commands/test-register.js +1 -0
  139. package/dist/src/commands/test-run.d.ts +14 -16
  140. package/dist/src/commands/test-run.js +21 -13
  141. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  142. package/dist/src/commands/test-stale-gate.js +15 -16
  143. package/dist/src/commands/test-verdict.d.ts +20 -3
  144. package/dist/src/commands/test-verdict.js +30 -0
  145. package/dist/src/commands/test.js +83 -76
  146. package/dist/src/commands/token-coverage.js +3 -4
  147. package/dist/src/commands/token.js +16 -18
  148. package/dist/src/commands/tree.js +47 -31
  149. package/dist/src/commands/typecheck.d.ts +10 -12
  150. package/dist/src/commands/typecheck.js +24 -27
  151. package/dist/src/commands/verify.js +13 -15
  152. package/dist/src/commands/watch.js +21 -23
  153. package/dist/src/commands/wire.js +52 -62
  154. package/dist/src/core/ast-utils.d.ts +8 -7
  155. package/dist/src/core/ast-utils.js +8 -7
  156. package/dist/src/core/branding.d.ts +9 -14
  157. package/dist/src/core/branding.js +7 -11
  158. package/dist/src/core/browser-wire.d.ts +1 -1
  159. package/dist/src/core/browser-wire.js +14 -19
  160. package/dist/src/core/build-audit-platform.js +25 -33
  161. package/dist/src/core/build-audit-registration.js +17 -25
  162. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  163. package/dist/src/core/build-audit-resolve.js +27 -33
  164. package/dist/src/core/build-audit-transforms.js +18 -19
  165. package/dist/src/core/build-audit.js +28 -42
  166. package/dist/src/core/build-baseline-types.d.ts +29 -35
  167. package/dist/src/core/build-baseline.d.ts +5 -4
  168. package/dist/src/core/build-baseline.js +14 -14
  169. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  170. package/dist/src/core/build-overwrite-guard.js +17 -27
  171. package/dist/src/core/build-prepare.d.ts +2 -2
  172. package/dist/src/core/build-prepare.js +8 -9
  173. package/dist/src/core/config-state.js +12 -4
  174. package/dist/src/core/config-validate.js +8 -5
  175. package/dist/src/core/config.d.ts +5 -8
  176. package/dist/src/core/config.js +7 -16
  177. package/dist/src/core/coverage-extend.d.ts +15 -13
  178. package/dist/src/core/coverage-extend.js +15 -13
  179. package/dist/src/core/destructive.d.ts +31 -9
  180. package/dist/src/core/destructive.js +29 -26
  181. package/dist/src/core/diff-hunks.js +10 -12
  182. package/dist/src/core/discard-baseline.d.ts +8 -8
  183. package/dist/src/core/discard-baseline.js +16 -15
  184. package/dist/src/core/display-state.d.ts +12 -14
  185. package/dist/src/core/display-state.js +12 -14
  186. package/dist/src/core/engine-changes.d.ts +2 -4
  187. package/dist/src/core/engine-changes.js +2 -4
  188. package/dist/src/core/engine-precondition.d.ts +28 -13
  189. package/dist/src/core/engine-precondition.js +25 -10
  190. package/dist/src/core/engine-session-lock.d.ts +47 -21
  191. package/dist/src/core/engine-session-lock.js +168 -33
  192. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  193. package/dist/src/core/export-moved-code-shape.js +10 -10
  194. package/dist/src/core/file-lock.d.ts +62 -5
  195. package/dist/src/core/file-lock.js +196 -59
  196. package/dist/src/core/firefox-cache.js +1 -3
  197. package/dist/src/core/firefox-extract.js +10 -14
  198. package/dist/src/core/firefox.d.ts +7 -5
  199. package/dist/src/core/firefox.js +4 -5
  200. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  201. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  202. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  203. package/dist/src/core/furnace-apply-ftl.js +12 -12
  204. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  205. package/dist/src/core/furnace-apply-helpers.js +19 -16
  206. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  207. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  208. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  209. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  210. package/dist/src/core/furnace-apply.d.ts +5 -8
  211. package/dist/src/core/furnace-apply.js +19 -24
  212. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  213. package/dist/src/core/furnace-checksum-utils.js +16 -0
  214. package/dist/src/core/furnace-config.d.ts +21 -30
  215. package/dist/src/core/furnace-config.js +32 -54
  216. package/dist/src/core/furnace-constants.d.ts +8 -0
  217. package/dist/src/core/furnace-constants.js +10 -2
  218. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  219. package/dist/src/core/furnace-css-fragments.js +5 -5
  220. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  221. package/dist/src/core/furnace-jsconfig.js +11 -12
  222. package/dist/src/core/furnace-marker.d.ts +7 -8
  223. package/dist/src/core/furnace-marker.js +7 -8
  224. package/dist/src/core/furnace-operation.d.ts +31 -0
  225. package/dist/src/core/furnace-operation.js +54 -17
  226. package/dist/src/core/furnace-precondition.d.ts +61 -0
  227. package/dist/src/core/furnace-precondition.js +67 -0
  228. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  229. package/dist/src/core/furnace-registration-remove.js +6 -7
  230. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  231. package/dist/src/core/furnace-registration-validate.js +20 -1
  232. package/dist/src/core/furnace-registration.d.ts +5 -6
  233. package/dist/src/core/furnace-registration.js +10 -12
  234. package/dist/src/core/furnace-rollback.js +7 -7
  235. package/dist/src/core/furnace-scanner.d.ts +1 -0
  236. package/dist/src/core/furnace-scanner.js +1 -2
  237. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  238. package/dist/src/core/furnace-stale-export.js +10 -10
  239. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  240. package/dist/src/core/furnace-state-persist.js +6 -8
  241. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  242. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  243. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  244. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  245. package/dist/src/core/furnace-validate-helpers.js +0 -491
  246. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  247. package/dist/src/core/furnace-validate-registration.js +115 -41
  248. package/dist/src/core/furnace-validate.d.ts +16 -0
  249. package/dist/src/core/furnace-validate.js +188 -145
  250. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  251. package/dist/src/core/furnace-version-drift.js +10 -11
  252. package/dist/src/core/git-base.d.ts +7 -9
  253. package/dist/src/core/git-base.js +7 -9
  254. package/dist/src/core/git-diff.d.ts +20 -9
  255. package/dist/src/core/git-diff.js +148 -63
  256. package/dist/src/core/git-file-ops.d.ts +19 -19
  257. package/dist/src/core/git-file-ops.js +19 -19
  258. package/dist/src/core/git-readonly-index.d.ts +53 -19
  259. package/dist/src/core/git-readonly-index.js +75 -31
  260. package/dist/src/core/git-status.d.ts +5 -6
  261. package/dist/src/core/git-status.js +5 -6
  262. package/dist/src/core/git.d.ts +9 -10
  263. package/dist/src/core/git.js +54 -70
  264. package/dist/src/core/license-headers.d.ts +17 -23
  265. package/dist/src/core/license-headers.js +17 -23
  266. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  267. package/dist/src/core/mach-build-artifacts.js +57 -19
  268. package/dist/src/core/mach-error-hints.js +42 -29
  269. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  270. package/dist/src/core/mach-known-noise-filter.js +18 -20
  271. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  272. package/dist/src/core/mach-mozconfig.js +30 -0
  273. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  274. package/dist/src/core/mach-resource-shim.js +50 -67
  275. package/dist/src/core/mach.d.ts +37 -41
  276. package/dist/src/core/mach.js +50 -51
  277. package/dist/src/core/marionette-port.d.ts +36 -1
  278. package/dist/src/core/marionette-port.js +96 -31
  279. package/dist/src/core/marionette-preflight.d.ts +8 -12
  280. package/dist/src/core/marionette-preflight.js +86 -52
  281. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  282. package/dist/src/core/mochitest-server-port.js +119 -0
  283. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  284. package/dist/src/core/module-resolution-preflight.js +9 -11
  285. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  286. package/dist/src/core/moz-manifest-helpers.js +163 -0
  287. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  288. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  289. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  290. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  291. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  292. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  293. package/dist/src/core/ownership-table.d.ts +14 -16
  294. package/dist/src/core/ownership-table.js +14 -16
  295. package/dist/src/core/parser-fallback.d.ts +15 -1
  296. package/dist/src/core/parser-fallback.js +22 -3
  297. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  298. package/dist/src/core/patch-apply-fuzz.js +15 -18
  299. package/dist/src/core/patch-apply.d.ts +13 -34
  300. package/dist/src/core/patch-apply.js +16 -76
  301. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  302. package/dist/src/core/patch-artifact-normalize.js +13 -15
  303. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  304. package/dist/src/core/patch-export-metadata.js +13 -4
  305. package/dist/src/core/patch-export-update.d.ts +13 -1
  306. package/dist/src/core/patch-export-update.js +25 -8
  307. package/dist/src/core/patch-export.d.ts +15 -8
  308. package/dist/src/core/patch-export.js +10 -11
  309. package/dist/src/core/patch-files.d.ts +5 -6
  310. package/dist/src/core/patch-files.js +5 -6
  311. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  312. package/dist/src/core/patch-identifier-suggest.js +14 -19
  313. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  314. package/dist/src/core/patch-lint-binary.js +39 -0
  315. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  316. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  317. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  318. package/dist/src/core/patch-lint-checkjs.js +16 -16
  319. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  320. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  321. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  322. package/dist/src/core/patch-lint-creators.js +8 -8
  323. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  324. package/dist/src/core/patch-lint-cross.js +16 -16
  325. package/dist/src/core/patch-lint-css.d.ts +3 -5
  326. package/dist/src/core/patch-lint-css.js +17 -22
  327. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  328. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  329. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  330. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  331. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  332. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  333. package/dist/src/core/patch-lint-observer.js +7 -7
  334. package/dist/src/core/patch-lint.d.ts +38 -29
  335. package/dist/src/core/patch-lint.js +89 -121
  336. package/dist/src/core/patch-lock.d.ts +1 -1
  337. package/dist/src/core/patch-lock.js +45 -9
  338. package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
  339. package/dist/src/core/patch-manifest-consistency.js +25 -27
  340. package/dist/src/core/patch-manifest-io.js +14 -18
  341. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  342. package/dist/src/core/patch-manifest-resolve.js +9 -12
  343. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  344. package/dist/src/core/patch-manifest-validate.js +25 -13
  345. package/dist/src/core/patch-parse.d.ts +24 -13
  346. package/dist/src/core/patch-parse.js +19 -14
  347. package/dist/src/core/patch-policy.d.ts +2 -2
  348. package/dist/src/core/patch-policy.js +2 -2
  349. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  350. package/dist/src/core/patch-registration-refs.js +9 -9
  351. package/dist/src/core/process-cpu-time.d.ts +12 -0
  352. package/dist/src/core/process-cpu-time.js +52 -0
  353. package/dist/src/core/rebase-session.d.ts +38 -26
  354. package/dist/src/core/rebase-session.js +55 -28
  355. package/dist/src/core/register-browser-content.js +9 -74
  356. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  357. package/dist/src/core/register-module.js +10 -43
  358. package/dist/src/core/register-scaffold.d.ts +8 -8
  359. package/dist/src/core/register-scaffold.js +10 -10
  360. package/dist/src/core/register-shared-css.d.ts +9 -12
  361. package/dist/src/core/register-shared-css.js +17 -87
  362. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  363. package/dist/src/core/register-xpcshell-test.js +7 -8
  364. package/dist/src/core/shared-ftl.js +12 -4
  365. package/dist/src/core/state-file.d.ts +45 -0
  366. package/dist/src/core/state-file.js +34 -0
  367. package/dist/src/core/status-binary.d.ts +18 -11
  368. package/dist/src/core/status-binary.js +19 -12
  369. package/dist/src/core/status-classify.d.ts +30 -36
  370. package/dist/src/core/status-classify.js +21 -26
  371. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  372. package/dist/src/core/test-changed-prefs.js +78 -0
  373. package/dist/src/core/test-harness-crash.d.ts +25 -63
  374. package/dist/src/core/test-harness-crash.js +121 -142
  375. package/dist/src/core/test-harness-signature.d.ts +18 -0
  376. package/dist/src/core/test-harness-signature.js +13 -0
  377. package/dist/src/core/test-path-scope.d.ts +12 -15
  378. package/dist/src/core/test-path-scope.js +15 -18
  379. package/dist/src/core/test-stale-check.d.ts +17 -17
  380. package/dist/src/core/test-stale-check.js +50 -43
  381. package/dist/src/core/test-stall-triage.d.ts +51 -0
  382. package/dist/src/core/test-stall-triage.js +126 -0
  383. package/dist/src/core/token-category.js +5 -7
  384. package/dist/src/core/token-coverage.js +9 -9
  385. package/dist/src/core/token-dark-mode.d.ts +9 -11
  386. package/dist/src/core/token-dark-mode.js +9 -11
  387. package/dist/src/core/token-docs.d.ts +2 -0
  388. package/dist/src/core/token-docs.js +2 -0
  389. package/dist/src/core/token-manager.d.ts +10 -2
  390. package/dist/src/core/token-manager.js +17 -8
  391. package/dist/src/core/token-scaffold.d.ts +7 -7
  392. package/dist/src/core/token-scaffold.js +7 -7
  393. package/dist/src/core/token-variant.d.ts +4 -4
  394. package/dist/src/core/token-variant.js +4 -4
  395. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  396. package/dist/src/core/toolchain-preflight.js +28 -31
  397. package/dist/src/core/tree-guard.js +12 -2
  398. package/dist/src/core/tree-store.d.ts +41 -27
  399. package/dist/src/core/tree-store.js +63 -42
  400. package/dist/src/core/typecheck-shim.d.ts +23 -24
  401. package/dist/src/core/typecheck-shim.js +23 -24
  402. package/dist/src/core/typecheck.js +8 -8
  403. package/dist/src/core/wire-destroy.d.ts +3 -3
  404. package/dist/src/core/wire-destroy.js +7 -15
  405. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  406. package/dist/src/core/wire-dom-fragment.js +11 -44
  407. package/dist/src/core/wire-init.d.ts +2 -3
  408. package/dist/src/core/wire-init.js +8 -19
  409. package/dist/src/core/wire-subscript.d.ts +2 -3
  410. package/dist/src/core/wire-subscript.js +4 -13
  411. package/dist/src/core/wire-utils.d.ts +7 -8
  412. package/dist/src/core/wire-utils.js +7 -8
  413. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  414. package/dist/src/core/xpcshell-appdir.js +38 -45
  415. package/dist/src/errors/base.d.ts +37 -16
  416. package/dist/src/errors/base.js +37 -16
  417. package/dist/src/errors/build.d.ts +13 -1
  418. package/dist/src/errors/build.js +14 -2
  419. package/dist/src/errors/codes.d.ts +16 -0
  420. package/dist/src/errors/codes.js +16 -0
  421. package/dist/src/errors/furnace.d.ts +4 -4
  422. package/dist/src/errors/git.d.ts +6 -10
  423. package/dist/src/errors/git.js +6 -10
  424. package/dist/src/errors/patch.d.ts +7 -7
  425. package/dist/src/errors/patch.js +7 -7
  426. package/dist/src/errors/rebase.d.ts +4 -4
  427. package/dist/src/errors/rebase.js +4 -4
  428. package/dist/src/index.d.ts +7 -1
  429. package/dist/src/index.js +5 -0
  430. package/dist/src/types/commands/index.d.ts +2 -2
  431. package/dist/src/types/commands/options.d.ts +88 -70
  432. package/dist/src/types/commands/patches.d.ts +24 -34
  433. package/dist/src/types/commands/project.d.ts +5 -34
  434. package/dist/src/types/config.d.ts +25 -23
  435. package/dist/src/types/config.js +6 -1
  436. package/dist/src/types/furnace.d.ts +37 -13
  437. package/dist/src/types/furnace.js +19 -1
  438. package/dist/src/types/index.d.ts +3 -3
  439. package/dist/src/utils/build-info.d.ts +7 -8
  440. package/dist/src/utils/build-info.js +12 -11
  441. package/dist/src/utils/errors.d.ts +6 -8
  442. package/dist/src/utils/errors.js +6 -8
  443. package/dist/src/utils/logger.d.ts +27 -10
  444. package/dist/src/utils/logger.js +28 -16
  445. package/dist/src/utils/machine-output.d.ts +12 -0
  446. package/dist/src/utils/machine-output.js +33 -0
  447. package/dist/src/utils/options.d.ts +31 -14
  448. package/dist/src/utils/options.js +86 -30
  449. package/dist/src/utils/paths.d.ts +10 -8
  450. package/dist/src/utils/paths.js +10 -8
  451. package/dist/src/utils/platform.d.ts +0 -25
  452. package/dist/src/utils/platform.js +1 -42
  453. package/dist/src/utils/process-group.d.ts +9 -4
  454. package/dist/src/utils/process-group.js +19 -5
  455. package/dist/src/utils/process.d.ts +42 -7
  456. package/dist/src/utils/process.js +44 -17
  457. package/dist/src/utils/ps-duration.d.ts +31 -0
  458. package/dist/src/utils/ps-duration.js +70 -0
  459. package/dist/src/utils/regex.d.ts +9 -10
  460. package/dist/src/utils/regex.js +9 -10
  461. package/dist/src/utils/validation.d.ts +58 -28
  462. package/dist/src/utils/validation.js +60 -33
  463. package/package.json +2 -2
  464. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  465. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  466. package/dist/src/core/manifest-helpers.d.ts +0 -38
  467. package/dist/src/core/manifest-helpers.js +0 -120
  468. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  469. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  470. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -16,17 +16,17 @@ import { info, notice, spinner, verbose } from '../utils/logger.js';
16
16
  import { reportBuildOnlyCompletion } from './test-modes.js';
17
17
  import { enforceStaleBuildGate, enforceStaticComponentsGate } from './test-stale-gate.js';
18
18
  import { emitPassVerdict } from './test-verdict.js';
19
- async function runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries, testPackagingCoverage, extend) {
19
+ async function runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries, testPackagingCoverage, refuseUnexportedDrift, extend) {
20
20
  await withBuildLock(projectRoot, async () => {
21
21
  // Pass the previous baseline exactly like `fireforge build` does, so
22
22
  // auto-configure runs under the same conditions on both paths. The
23
23
  // pre-test build must never invalidate more of the objdir than a plain
24
- // `mach build faster` would (field incident: a failed pre-test build
25
- // was followed by a ~64-minute full rebuild where an incremental one
26
- // should have sufficed).
24
+ // `mach build faster` would — a failed pre-test build followed by a full
25
+ // rebuild is an hour where an incremental one would have sufficed.
27
26
  const previousBaseline = await readBuildBaseline(projectRoot);
28
27
  const preparation = await prepareBuildEnvironment(projectRoot, paths, projectConfig, {
29
28
  previousBaseline,
29
+ refuseUnexportedDrift,
30
30
  });
31
31
  // The mozconfig half of the --extend-coverage anchor can
32
32
  // only be checked once prepareBuildEnvironment has regenerated
@@ -64,14 +64,13 @@ async function runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries
64
64
  s.stop('Build complete');
65
65
  // Same record, same failure tolerance as `fireforge build` /
66
66
  // `build --ui` (build.ts): a green pre-test build refreshes the
67
- // stale-build baseline so a later plain `fireforge test` over the
68
- // same files — in any invocation shape — is not refused. A failed
69
- // write never fails the run. The coverage claim is scoped to the
70
- // requested test paths, since a file-scoped `test --build` only
71
- // guarantees packaging for those manifests. The previous baseline is
72
- // passed through so a scoped write carries the static-components
73
- // anchor forward (a `mach build faster` does not rebake
74
- // components.conf into the compiled table).
67
+ // stale-build baseline so a later plain `fireforge test` over the same
68
+ // files is not refused. A failed write never fails the run. The
69
+ // coverage claim is scoped to the requested test paths, since a
70
+ // file-scoped `test --build` only guarantees packaging for those
71
+ // manifests. The previous baseline is passed through so a scoped write
72
+ // carries the static-components anchor forward — `mach build faster`
73
+ // does not rebake components.conf into the compiled table.
75
74
  try {
76
75
  // Under --extend-coverage the claim is the UNION of the previous
77
76
  // record and this build's paths, and the static-components anchor
@@ -113,6 +112,19 @@ function assertExtendCoverageUsage(options, normalizedPaths) {
113
112
  throw new InvalidArgumentError('--extend-coverage requires explicit test paths: a path-less build records full coverage, which already covers every path.', '--extend-coverage');
114
113
  }
115
114
  }
115
+ /**
116
+ * Refuses `--refuse-unexported-drift` on a run that dispatches no build.
117
+ * The flag governs the PRE-TEST build only, so accepting it without
118
+ * `--build`/`--build-only` would arm a belt over work that never happens —
119
+ * exactly the silent no-op this release fixes elsewhere.
120
+ */
121
+ function assertRefuseUnexportedDriftUsage(options) {
122
+ if (options.refuseUnexportedDrift !== true)
123
+ return;
124
+ if (options.build === true || options.buildOnly === true)
125
+ return;
126
+ throw new InvalidArgumentError('--refuse-unexported-drift requires --build or --build-only: it guards the pre-test build, and this run dispatches none.', '--refuse-unexported-drift');
127
+ }
116
128
  /** Renders the `recordedBy` invocation string surfaced by `status --test-coverage`. */
117
129
  function describeBuildInvocation(extending, coverage) {
118
130
  const extendFlag = extending ? ' --extend-coverage' : '';
@@ -133,6 +145,7 @@ export async function runTestBuildPhase(projectRoot, paths, projectConfig, harne
133
145
  if (extending) {
134
146
  assertExtendCoverageUsage(options, normalizedPaths);
135
147
  }
148
+ assertRefuseUnexportedDriftUsage(options);
136
149
  if (options.build || options.buildOnly) {
137
150
  // A path-less `test --build` runs (and packages for) the full suite;
138
151
  // a scoped invocation only vouches for the requested paths. A SCOPED
@@ -152,7 +165,7 @@ export async function runTestBuildPhase(projectRoot, paths, projectConfig, harne
152
165
  }
153
166
  }
154
167
  }
155
- await runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries, coverage, extending ? { requestedPaths: normalizedPaths } : undefined);
168
+ await runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries, coverage, options.refuseUnexportedDrift === true, extending ? { requestedPaths: normalizedPaths } : undefined);
156
169
  info('');
157
170
  if (options.buildOnly) {
158
171
  // Union build for mixed harnesses: the coverage claim
@@ -7,6 +7,7 @@
7
7
  * `test-harness-crash.ts` for single and sharded invocations. Split out of
8
8
  * `test.ts` to keep both files within the per-file line budget.
9
9
  */
10
+ import { describeChangedPrefNoise } from '../core/test-changed-prefs.js';
10
11
  import { buildGreenSummaryRejectedMessage, buildHarnessCrashMessage, buildNoTestsRanMessage, buildSilentSegfaultMessage, headedNoOutputTimeoutHint, isSilentSegfault, } from '../core/test-harness-crash.js';
11
12
  import { buildHarnessEarlyExitMessage, classifyHarnessEarlyExit, completePostRebuildFailureContext, prependPostRebuildFailureContext, } from '../core/test-harness-output.js';
12
13
  import { GeneralError } from '../errors/base.js';
@@ -32,35 +33,33 @@ function buildStaleBuildMessage(postRebuild) {
32
33
  'Re-run "fireforge build --ui" or "fireforge test --build" and then retry.');
33
34
  }
34
35
  function hasStaleBuildArtifactsSignal(output) {
35
- // Deliberately narrow: only fire on branding-specific resource paths
36
- // that are always a stale-artifact symptom. The earlier pattern also
37
- // matched `resource:///modules/distribution.sys.mjs`, which surfaced on
38
- // real packaging / module-resolution failures too (e.g. a fork's
39
- // `MyBrowserStore.sys.mjs` missing from the installed app dir after a
40
- // successful build). That false-positive pushed operators toward
41
- // "rebuild" advice for what was actually a module-registration issue.
36
+ // Deliberately narrow: only fire on branding-specific resource paths that
37
+ // are always a stale-artifact symptom. A pattern that also matches
38
+ // `resource:///modules/distribution.sys.mjs` fires on real packaging and
39
+ // module-resolution failures too — a fork's own `.sys.mjs` missing from
40
+ // the installed app dir after a successful build — pushing operators
41
+ // toward "rebuild" advice for a module-registration issue.
42
42
  return (/chrome:\/\/branding\/locale\/brand\.properties/i.test(output) ||
43
43
  /browser\/branding\/[^/\s]+\/moz\.build/i.test(output));
44
44
  }
45
45
  /**
46
- * Fork-module-not-registered signal. 2026-04-21 eval Finding #14:
47
- * a fork's test failed with `Failed to load resource:///modules/mybrowser/
48
- * MyBrowserStore.sys.mjs`. The branding pattern happened to also match
49
- * because the test harness printed a branding warning during its
50
- * teardown, and the stale-build branch won by precedence — telling the
51
- * operator to rebuild when the real fix is to register the module in
52
- * the fork's `browser/modules/<binary>/moz.build`. Match a
53
- * `resource:///modules/<binaryName>/` pattern so fork-owned module
54
- * failures surface the right diagnosis.
46
+ * Fork-module-not-registered signal.
47
+ *
48
+ * A fork's test failing with `Failed to load
49
+ * resource:///modules/<binary>/Store.sys.mjs` can also match the branding
50
+ * pattern, because the harness prints a branding warning during teardown —
51
+ * and the stale-build branch then wins by precedence, telling the operator
52
+ * to rebuild when the real fix is to register the module in the fork's
53
+ * `browser/modules/<binary>/moz.build`. Matching a
54
+ * `resource:///modules/<binaryName>/` pattern surfaces the right diagnosis.
55
55
  */
56
56
  function hasForkModuleSignal(output, binaryName) {
57
- // `binaryName` comes from fireforge.json, and config validation
58
- // (`config-validate.ts:59-70`) bars only `..`, path separators, NUL and
59
- // absolute paths — regex metacharacters get through. The inline escape
60
- // this replaced wrote its character class as `[.*+?^${}()|[\\]\\\\]`,
61
- // which closes early after the escaped backslash, so it escaped nothing:
62
- // `my.browser` matched `myXbrowser`, and an unbalanced `(` or `[` threw a
63
- // SyntaxError out of the failure-diagnosis path, replacing the real test
57
+ // `binaryName` comes from fireforge.json, and config validation bars only
58
+ // `..`, path separators, NUL and absolute paths — regex metacharacters get
59
+ // through. A hand-written character class is easy to get wrong (one that
60
+ // closes early after an escaped backslash escapes nothing), which makes
61
+ // `my.browser` match `myXbrowser` and lets an unbalanced `(` or `[` throw
62
+ // a SyntaxError out of the failure-diagnosis path, replacing the real test
64
63
  // failure with an opaque regex error.
65
64
  const pattern = new RegExp(`Failed to load resource:\\/\\/\\/modules\\/${escapeRegex(binaryName)}\\/`, 'i');
66
65
  return pattern.test(output);
@@ -130,8 +129,8 @@ function buildMochitestHttp3ServerMessage() {
130
129
  * captured output supports, throwing it as a domain error.
131
130
  *
132
131
  * The branch order is load-bearing: narrower signals are checked before
133
- * broader ones so, for example, a fork-owned module failure is not reported as
134
- * a stale build (2026-04-21 eval Finding #14).
132
+ * broader ones, so a fork-owned module failure is not reported as a stale
133
+ * build.
135
134
  */
136
135
  function handleNonZeroTestExit(result, normalizedPaths, appdirInjectionAttempted, binaryName, postRebuildContext) {
137
136
  if (result.exitCode === 0 || result.exitCode === 130)
@@ -158,24 +157,21 @@ function handleNonZeroTestExit(result, normalizedPaths, appdirInjectionAttempted
158
157
  throwGeneral(buildHarnessEarlyExitMessage(earlyExit, normalizedPaths));
159
158
  }
160
159
  // Fork-owned module load failures must beat the branding stale-build
161
- // branch: 2026-04-21 eval (Finding #14) saw a fork's test fail with
162
- // `Failed to load resource:///modules/mybrowser/MyBrowserStore.sys.mjs`
163
- // while the harness teardown printed a branding warning that the old
164
- // stale-build pattern matched, so the operator was told to rebuild
165
- // when the real fix is to register the missing module.
160
+ // branch: a test failing with `Failed to load
161
+ // resource:///modules/<binary>/Store.sys.mjs` while the harness teardown
162
+ // prints a branding warning would otherwise be told to rebuild, when the
163
+ // real fix is to register the missing module.
166
164
  if (hasForkModuleSignal(combinedOutput, binaryName)) {
167
165
  throwGeneral(buildForkModuleMessage(binaryName));
168
166
  }
169
167
  // Branding-specific stale-build signals keep priority over the broader
170
168
  // xpcshell-appdir hint: when `chrome://branding/locale/brand.properties`
171
169
  // fails to resolve, the fix really is "rebuild", not "pass --app-path".
172
- // But the stale-build check is now narrower — it no longer matches
173
- // `resource:///modules/distribution.sys.mjs` alone, which was producing
174
- // false-positive rebuild advice on fork-custom module-load failures
175
- // (the eval saw this for `MyBrowserStore.sys.mjs`). Cases that once
176
- // landed on `distribution.sys.mjs` fall through to xpcshell-appdir,
177
- // which is the more useful diagnosis in practice for `Failed to load
178
- // resource:///modules/…`.
170
+ // The stale-build check is narrow enough not to match
171
+ // `resource:///modules/distribution.sys.mjs` alone, which produced
172
+ // false-positive rebuild advice on fork-custom module-load failures; those
173
+ // cases fall through to xpcshell-appdir, the more useful diagnosis for
174
+ // `Failed to load resource:///modules/…`.
179
175
  if (hasStaleBuildArtifactsSignal(combinedOutput)) {
180
176
  throwGeneral(buildStaleBuildMessage(Boolean(failureContext)));
181
177
  }
@@ -194,7 +190,12 @@ function handleNonZeroTestExit(result, normalizedPaths, appdirInjectionAttempted
194
190
  info('Hint: The test file may not be registered in browser.toml or jar.mn.');
195
191
  info('Run "fireforge register <test-path>" to register it.');
196
192
  }
197
- throw new BuildError(withContext(`Tests failed with exit code ${result.exitCode}. Check the output above for details.`), 'mach test');
193
+ // Last, and additive rather than a branch of its own: the run really did
194
+ // fail (exit code stays 5), so this only says WHICH KIND of failure it is.
195
+ // Every branch above is a different diagnosis and outranks it.
196
+ const changedPrefNoise = describeChangedPrefNoise(combinedOutput);
197
+ throw new BuildError(withContext(`Tests failed with exit code ${result.exitCode}. Check the output above for details.` +
198
+ (changedPrefNoise !== undefined ? `\n\n${changedPrefNoise}` : '')), 'mach test');
198
199
  }
199
200
  /**
200
201
  * Applies the harness-run verdict for a single (non-sharded) invocation:
@@ -225,10 +226,10 @@ function applySingleRunOutcome(outcome, normalizedPaths, binaryName, postRebuild
225
226
  throw new GeneralError(hint ? `${base}\n\n${hint}` : base);
226
227
  }
227
228
  if (outcome.verdict.kind === 'tests-ran-ok') {
228
- // The verdict is authoritative over the raw exit code: a completed
229
- // green embedded summary overrides a non-zero exit caused by harness
230
- // noise (field report: fully green --no-shard runs exited 1, forcing
231
- // operators to parse embedded summaries by hand).
229
+ // The verdict is authoritative over the raw exit code: a completed green
230
+ // embedded summary overrides a non-zero exit caused by harness noise,
231
+ // which would otherwise leave operators parsing embedded summaries by
232
+ // hand.
232
233
  if (outcome.verdict.greenSummaryOverride) {
233
234
  info(`Note: mach exited ${outcome.result.exitCode}, but the embedded suite summary completed ` +
234
235
  'green (Unexpected results: 0). FireForge treats the run as passed; the non-zero exit ' +
@@ -243,8 +244,7 @@ function applySingleRunOutcome(outcome, normalizedPaths, binaryName, postRebuild
243
244
  }
244
245
  // A green-LOOKING summary rejected on crash/truncation evidence gets its
245
246
  // own explanation instead of the generic exit-code message — the operator
246
- // must see WHY the green counts were not trusted (0.35.0 green-wash
247
- // field report: SIGSEGV at file 2 of 8, `Passed: 2 / Failed: 0`).
247
+ // must see WHY the green counts were not trusted.
248
248
  if (outcome.verdict.greenSummaryRejected) {
249
249
  throw new GeneralError(buildGreenSummaryRejectedMessage(outcome.verdict.greenSummaryRejected, outcome.result.exitCode));
250
250
  }
@@ -58,6 +58,7 @@ export function registerTest(program, { getProjectRoot, withErrorHandling }) {
58
58
  .option('--build', 'Run incremental UI build before testing')
59
59
  .option('--build-only', 'Run the scoped pre-test build (packaging exactly [paths...], mixed harnesses allowed) and exit without dispatching tests — one build covers both harness halves, then run each half without --build')
60
60
  .option('--extend-coverage', 'With --build/--build-only and explicit paths, union those paths into the recorded test-packaging coverage instead of replacing it, so an earlier scoped build stays covered. Refused when the build anchor moved (engine HEAD, mozconfig, or a previously fingerprinted packageable file changed).')
61
+ .option('--refuse-unexported-drift', 'With --build/--build-only, refuse (instead of warning) when the pre-test build would overwrite engine content recorded in neither a patch body nor the pristine baseline — the same belt as "fireforge build --refuse-unexported-drift", armable from the scripted "test --build" shape the hazard actually shows up in')
61
62
  .option('--auto', 'Forward mach test --auto. Valid only when no explicit paths are provided.')
62
63
  .option('--allow-stale-build', 'Allow tests to run even when packageable engine files changed since the last successful FireForge build')
63
64
  .option('--allow-stale-components', 'Run tests despite components.conf changes that only a full "fireforge build" compiles in (the packaged child process will resolve the OLD StaticComponents table)')
@@ -1,14 +1,13 @@
1
1
  /**
2
- * Run orchestration for `fireforge test`: bounded harness-crash retries
3
- * (field reports C1/C2) and sequential per-file sharding of multi-path
4
- * invocations (field report C3).
2
+ * Run orchestration for `fireforge test`: bounded harness-crash retries and
3
+ * sequential per-file sharding of multi-path invocations.
5
4
  *
6
- * Sharding exists because passing several browser-chrome files to one
7
- * mach invocation destabilizes later files — cross-file profile/pref
8
- * bleed in the shared mochitest profile made the second file time out at
9
- * window-open while each file passed in isolation. Sequential single-file
10
- * harness runs cost startup time but make results reproducible; the
11
- * combined invocation stays available via `--no-shard`.
5
+ * Sharding exists because passing several browser-chrome files to one mach
6
+ * invocation destabilizes later files — cross-file profile/pref bleed in the
7
+ * shared mochitest profile makes the second file time out at window-open
8
+ * while each file passes in isolation. Sequential single-file harness runs
9
+ * cost startup time but make results reproducible; the combined invocation
10
+ * stays available via `--no-shard`.
12
11
  */
13
12
  import { type DisplaySleepState } from '../core/display-state.js';
14
13
  import { type MachCommandResult } from '../core/mach.js';
@@ -19,8 +18,8 @@ export declare const DEFAULT_HARNESS_RETRIES = 2;
19
18
  * Which mach command a run dispatches to. Single-suite runs use the
20
19
  * suite-specific command (`mach xpcshell-test` / `mach mochitest`), which
21
20
  * skips the mozlog resource monitor that crashes generic `mach test` on a
22
- * broken host (field report E1). `generic` is the historical `mach test`
23
- * path (mixed/all-tests runs, or the `--generic-mach-test` opt-out).
21
+ * broken host. `generic` is the plain `mach test` path (mixed/all-tests runs,
22
+ * or the `--generic-mach-test` opt-out).
24
23
  */
25
24
  export type TestSuite = 'xpcshell' | 'mochitest' | 'generic';
26
25
  /** Inputs shared by every harness invocation in one `fireforge test` run. */
@@ -63,11 +62,10 @@ export interface TestRunOutcome {
63
62
  export declare function runTestsWithRetries(ctx: TestRunContext, paths: string[]): Promise<TestRunOutcome>;
64
63
  /**
65
64
  * One sequential harness invocation of a sharded run: a requested path
66
- * argument and the mach paths dispatched for it. A file argument is a
67
- * group of one; a directory argument groups its enumerated test files so
68
- * the whole directory still runs in ONE browser instance (cross-file
69
- * state carries within a directory run exactly like the pre-enumeration
70
- * behavior).
65
+ * argument and the mach paths dispatched for it. A file argument is a group
66
+ * of one; a directory argument groups its enumerated test files so the whole
67
+ * directory still runs in ONE browser instance, keeping cross-file state
68
+ * behaviour within a directory run.
71
69
  */
72
70
  export interface ShardGroup {
73
71
  /** The path argument as the operator passed it (display label). */
@@ -1,18 +1,18 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Run orchestration for `fireforge test`: bounded harness-crash retries
4
- * (field reports C1/C2) and sequential per-file sharding of multi-path
5
- * invocations (field report C3).
3
+ * Run orchestration for `fireforge test`: bounded harness-crash retries and
4
+ * sequential per-file sharding of multi-path invocations.
6
5
  *
7
- * Sharding exists because passing several browser-chrome files to one
8
- * mach invocation destabilizes later files — cross-file profile/pref
9
- * bleed in the shared mochitest profile made the second file time out at
10
- * window-open while each file passed in isolation. Sequential single-file
11
- * harness runs cost startup time but make results reproducible; the
12
- * combined invocation stays available via `--no-shard`.
6
+ * Sharding exists because passing several browser-chrome files to one mach
7
+ * invocation destabilizes later files — cross-file profile/pref bleed in the
8
+ * shared mochitest profile makes the second file time out at window-open
9
+ * while each file passes in isolation. Sequential single-file harness runs
10
+ * cost startup time but make results reproducible; the combined invocation
11
+ * stays available via `--no-shard`.
13
12
  */
14
13
  import { probeDisplaySleepState } from '../core/display-state.js';
15
14
  import { mochitestWithOutput, testWithOutput, xpcshellTestWithOutput, } from '../core/mach.js';
15
+ import { changedPrefNoiseVerdictNote } from '../core/test-changed-prefs.js';
16
16
  import { buildHarnessCrashMessage, classifyHarnessRun, headedDisplayAsleepVerdictNote, headedNoOutputTimeoutHint, } from '../core/test-harness-crash.js';
17
17
  import { retryAfterXpcshellSymlinkRepair } from '../core/test-xpcshell-retry.js';
18
18
  import { withXpcshellProfileDir } from '../core/xpcshell-profile-dir.js';
@@ -72,6 +72,14 @@ async function runTestsWithRetriesInner(ctx, paths, env) {
72
72
  `${verdict.signature?.line ?? ''}\n` +
73
73
  `Retrying (attempt ${attempts + 1} of ${maxAttempts})...`);
74
74
  }
75
+ // A verdict whose every unexpected result is time-driven pref noise is
76
+ // still a FAIL — only the note changes, so a `unexpected=2` line is not
77
+ // read as two real assertion failures.
78
+ if (verdict.kind === 'test-failures' && verdict.note === undefined) {
79
+ const prefNote = changedPrefNoiseVerdictNote(`${result.stdout}\n${result.stderr}`);
80
+ if (prefNote !== undefined)
81
+ verdict = { ...verdict, note: prefNote };
82
+ }
75
83
  const displayState = await probeDisplayStateForStall(verdict, ctx.headless);
76
84
  if (displayState !== undefined) {
77
85
  const note = headedDisplayAsleepVerdictNote(verdict.signature, {
@@ -85,10 +93,10 @@ async function runTestsWithRetriesInner(ctx, paths, env) {
85
93
  return { result, verdict, attempts, appdirInjectionAttempted, displayState };
86
94
  }
87
95
  /**
88
- * Probes the display's power state for a HEADED no-output stall, and only
89
- * for that shape. Every other outcome — a passing run, a real
90
- * test failure, a headless run, any other crash shape — skips the probe
91
- * entirely, so the common paths spawn nothing.
96
+ * Probes the display's power state for a HEADED no-output stall, and only for
97
+ * that shape. Every other outcome — a passing run, a real test failure, a
98
+ * headless run, any other crash shape — skips the probe entirely, so the
99
+ * common paths spawn nothing.
92
100
  *
93
101
  * @returns The measured state, or undefined when the shape does not apply
94
102
  */
@@ -9,25 +9,24 @@
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
13
- * packageable engine edits since the last successful build and fail
14
- * UP-FRONT unless the operator explicitly accepts the stale package risk.
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
+ * operator explicitly accepts the stale package risk.
15
15
  *
16
16
  * Packaging COVERAGE is checked first, on EVERY non-`--build` run and
17
- * regardless of staleness or `--allow-stale-build`: a runtime packaged by
18
- * a file-scoped `test --build` can lack support fixtures for OTHER
19
- * manifests even when nothing changed since — dispatching such a run
20
- * hangs on missing fixtures rather than failing, so the flag (which only
21
- * accepts stale CONTENT) must not be the trigger. Field incident: a
22
- * three-file scoped rebuild left `file_tiles_audio.html` unpackaged and a
23
- * later run over different files timed out twice at 45s waiting on
24
- * `DOMAudioPlaybackStarted`.
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
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
22
+ * fixture unpackaged makes a later run over different files time out waiting
23
+ * on an event that never fires.
25
24
  *
26
- * Exception: a path-less `test --doctor` stops at the Marionette health
27
- * check (`runDoctorPreflight` returns 'stop' when no test paths were
28
- * given) and never dispatches a test, so it needs no packaging coverage —
29
- * treating it as a full-suite request would refuse a probe that touches
30
- * no fixtures. The stale-content refusal still applies to it unchanged.
25
+ * Exception: a path-less `test --doctor` stops at the Marionette health check
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
28
+ * a full-suite request would refuse a probe that touches no fixtures. The
29
+ * stale-content refusal still applies to it unchanged.
31
30
  */
32
31
  export declare function enforceStaleBuildGate(projectRoot: string, engineDir: string, options: TestOptions, normalizedPaths: readonly string[]): Promise<void>;
33
32
  /**
@@ -11,25 +11,24 @@ import { checkStaleBuildForTest, checkStaticComponentsStale, findUncoveredReques
11
11
  import { GeneralError } from '../errors/base.js';
12
12
  import { warn } from '../utils/logger.js';
13
13
  /**
14
- * Stale-build preflight — when `--build` was NOT requested, detect
15
- * packageable engine edits since the last successful build and fail
16
- * UP-FRONT unless the operator explicitly accepts the stale package risk.
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
+ * operator explicitly accepts the stale package risk.
17
17
  *
18
18
  * Packaging COVERAGE is checked first, on EVERY non-`--build` run and
19
- * regardless of staleness or `--allow-stale-build`: a runtime packaged by
20
- * a file-scoped `test --build` can lack support fixtures for OTHER
21
- * manifests even when nothing changed since — dispatching such a run
22
- * hangs on missing fixtures rather than failing, so the flag (which only
23
- * accepts stale CONTENT) must not be the trigger. Field incident: a
24
- * three-file scoped rebuild left `file_tiles_audio.html` unpackaged and a
25
- * later run over different files timed out twice at 45s waiting on
26
- * `DOMAudioPlaybackStarted`.
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
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
24
+ * fixture unpackaged makes a later run over different files time out waiting
25
+ * on an event that never fires.
27
26
  *
28
- * Exception: a path-less `test --doctor` stops at the Marionette health
29
- * check (`runDoctorPreflight` returns 'stop' when no test paths were
30
- * given) and never dispatches a test, so it needs no packaging coverage —
31
- * treating it as a full-suite request would refuse a probe that touches
32
- * no fixtures. The stale-content refusal still applies to it unchanged.
27
+ * Exception: a path-less `test --doctor` stops at the Marionette health check
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
30
+ * a full-suite request would refuse a probe that touches no fixtures. The
31
+ * stale-content refusal still applies to it unchanged.
33
32
  */
34
33
  export async function enforceStaleBuildGate(projectRoot, engineDir, options, normalizedPaths) {
35
34
  const stale = await checkStaleBuildForTest(projectRoot, engineDir);
@@ -6,10 +6,12 @@ import type { HarnessRunVerdict } from '../core/test-harness-crash.js';
6
6
  * invalid paths, port conflicts, config errors, spawn failures),
7
7
  * `inconclusive` marks a run whose harness result exists but cannot be
8
8
  * trusted because `engine/` changed (or became unprobeable one-sidedly)
9
- * while the tests ran, and `lock-timeout` marks a run that never started
10
- * because the engine session lock stayed contended past the wait budget.
9
+ * while the tests ran, `lock-timeout` marks a run that never started
10
+ * because the engine session lock stayed contended past the wait budget,
11
+ * and `killed` marks a run terminated by a signal before it could reach any
12
+ * of the others.
11
13
  */
12
- export type FireforgeVerdictReason = 'crash' | 'no-tests' | 'test-failures' | 'preflight' | 'inconclusive' | 'lock-timeout';
14
+ export type FireforgeVerdictReason = 'crash' | 'no-tests' | 'test-failures' | 'preflight' | 'inconclusive' | 'lock-timeout' | 'killed';
13
15
  /**
14
16
  * Re-arms the verdict sink for a new run. Called at `testCommand` entry so
15
17
  * repeated programmatic invocations (and tests) each get their own
@@ -30,3 +32,18 @@ export declare function emitHarnessVerdict(verdict: HarnessRunVerdict, shards?:
30
32
  export declare function emitPassVerdict(): void;
31
33
  /** Emits a FAIL verdict carrying an emission-layer reason code. */
32
34
  export declare function emitFailVerdict(reason: FireforgeVerdictReason): void;
35
+ /**
36
+ * Emits the terminal verdict for a run killed by a signal.
37
+ *
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
40
+ * meant checking `ps` and the lock file by hand, at the exact moment (a
41
+ * mass kill under a usage limit, mid-drain) when the tree's state most
42
+ * needs to be readable. A no-op unless a run was actually in flight: the
43
+ * line asserts a test run happened, and an interrupted `status` did not
44
+ * have one.
45
+ *
46
+ * @param signal - The signal that terminated the run
47
+ * @returns True when a line was written
48
+ */
49
+ export declare function emitKilledVerdict(signal: NodeJS.Signals): boolean;
@@ -1,6 +1,15 @@
1
1
  import { formatFireforgeVerdictLine } from '../core/test-harness-crash.js';
2
2
  import { setStdoutSealed } from '../utils/logger.js';
3
3
  let emitted = false;
4
+ /**
5
+ * True once a test run has begun in this process.
6
+ *
7
+ * The signal path needs it: a `FIREFORGE-VERDICT` line claims a test run
8
+ * happened, and a Ctrl+C during `fireforge status` must not print one. Set
9
+ * by {@link resetVerdictEmission}, which `testCommand` already calls at
10
+ * entry, so nothing else has to remember to arm it.
11
+ */
12
+ let armed = false;
4
13
  /**
5
14
  * Re-arms the verdict sink for a new run. Called at `testCommand` entry so
6
15
  * repeated programmatic invocations (and tests) each get their own
@@ -8,6 +17,7 @@ let emitted = false;
8
17
  */
9
18
  export function resetVerdictEmission() {
10
19
  emitted = false;
20
+ armed = true;
11
21
  setStdoutSealed(false);
12
22
  }
13
23
  /** True once this run has written its `FIREFORGE-VERDICT:` line. */
@@ -46,3 +56,23 @@ export function emitPassVerdict() {
46
56
  export function emitFailVerdict(reason) {
47
57
  writeVerdictLine(`FIREFORGE-VERDICT: FAIL reason=${reason}`);
48
58
  }
59
+ /**
60
+ * Emits the terminal verdict for a run killed by a signal.
61
+ *
62
+ * Without it a killed run wrote NO terminal line, so a log tail could not
63
+ * distinguish "killed" from "still running" from "never started" — recovery
64
+ * meant checking `ps` and the lock file by hand, at the exact moment (a
65
+ * mass kill under a usage limit, mid-drain) when the tree's state most
66
+ * needs to be readable. A no-op unless a run was actually in flight: the
67
+ * line asserts a test run happened, and an interrupted `status` did not
68
+ * have one.
69
+ *
70
+ * @param signal - The signal that terminated the run
71
+ * @returns True when a line was written
72
+ */
73
+ export function emitKilledVerdict(signal) {
74
+ if (!armed || emitted)
75
+ return false;
76
+ writeVerdictLine(`FIREFORGE-VERDICT: FAIL reason=killed signal=${signal}`);
77
+ return true;
78
+ }