@hominis/fireforge 0.43.0 → 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 +127 -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 +62 -19
  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
@@ -1,6 +1,6 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Harness-crash classification for `fireforge test` (field reports C1/C2).
3
+ * Harness-crash classification for `fireforge test`.
4
4
  *
5
5
  * The wrapped mach harness exhibits flaky non-test failures that an exit
6
6
  * code (or a "did it print a summary" grep) cannot distinguish from real
@@ -11,18 +11,22 @@
11
11
  * 'poll_interval'`, `host_statistics64(HOST_VM_INFO64) syscall failed`,
12
12
  * `(ipc/mig) array not large enough` — a psutil/macOS mismatch) which
13
13
  * abort the run before any test executes;
14
- * - hangs after browser startup that die at the no-output timeout yet
15
- * still emit a `Passed: 0` summary;
16
- * - post-green shutdown re-entry, where a fully green run stalls on
17
- * "must wait for focus" and records "Application shut down (without
18
- * crashing) in the middle of a test!" as the only unexpected failure.
14
+ * - hangs after browser startup that die at the no-output timeout yet still
15
+ * emit a `Passed: 0` summary;
16
+ * - post-green shutdown re-entry, where a fully green run stalls on "must
17
+ * wait for focus" and records "Application shut down (without crashing)
18
+ * in the middle of a test!" as the only unexpected failure.
19
19
  *
20
20
  * Classification therefore keys on `TEST-START` presence — summary lines
21
21
  * never count as proof that tests ran — and recognizes the crash shapes
22
- * above so the command layer can retry them with a bounded budget instead
23
- * of reporting phantom test failures (or phantom passes).
22
+ * above so the command layer can retry them with a bounded budget instead of
23
+ * reporting phantom test failures (or phantom passes).
24
24
  */
25
25
  import { hasKnownTeardownNoise } from './mach-known-noise-filter.js';
26
+ // The no-output-stall triage text lives in `test-stall-triage.ts` (it is
27
+ // operator advice, not classification) and is re-exported here so the
28
+ // command layer keeps importing its harness diagnostics from one module.
29
+ export { headedDisplayAsleepVerdictNote, headedNoOutputTimeoutHint } from './test-stall-triage.js';
26
30
  const TEST_START_PATTERN = /\bTEST-START\b/;
27
31
  /**
28
32
  * Structured-log execution marker (`mach xpcshell-test` mozlog output uses
@@ -40,28 +44,47 @@ const NONZERO_UNEXPECTED_SUMMARY_PATTERN = /\bUnexpected results:\s*[1-9]/;
40
44
  * single-file xpcshell run prints a result-summary block instead
41
45
  * (`TEST_END: Test PASS`, `Ran 16 checks`, `Unexpected results: 0`), so
42
46
  * keying execution purely on `TEST-START` mis-reads a green xpcshell run as
43
- * "no tests started" (field report: a single-file xpcshell pass exited 1).
47
+ * "no tests started".
44
48
  *
45
- * These markers are xpcshell-specific on purpose: the bare
46
- * `Passed: 0` / `Failed: 0` summary that the no-output hang shape prints is
47
- * deliberately NOT matched here — that case must still read as `no-tests`.
49
+ * These markers are xpcshell-specific on purpose: the bare `Passed: 0` /
50
+ * `Failed: 0` summary that the no-output hang shape prints is deliberately
51
+ * NOT matched here — that case must still read as `no-tests`.
48
52
  */
49
53
  const XPCSHELL_RESULT_SUMMARY_PATTERN = /\bTEST_END\b|\bRan \d+ checks?\b|\bResult summary:/i;
50
54
  const UNEXPECTED_LINE_PATTERN = /^.*\bTEST-UNEXPECTED-[A-Z-]+\b.*$/gm;
51
- const FAIL_LINE_PATTERN = /^.*\bFAIL\b.*$/gm;
52
- const ASSERTION_LINE_PATTERN = /^.*\b(?:Assertion failure|MOZ_ASSERT|ASSERTION)\b.*$/gim;
55
+ /**
56
+ * A `FAIL` token that is HARNESS-SHAPED. Deliberately not a bare `\bFAIL\b`
57
+ * word match: that matched any output line containing the ordinary English
58
+ * word, so a test's own passing diagnostic could manufacture a red run (see
59
+ * {@link realUnexpectedFailureLines}). It also matched `TEST-KNOWN-FAIL` —
60
+ * an EXPECTED failure — and counted it as a real one.
61
+ *
62
+ * The `TEST-` prefix is what makes the token the harness's rather than
63
+ * prose, and the negative lookahead is what keeps a known-fail annotation
64
+ * out of the evidence set.
65
+ */
66
+ const FAIL_LINE_PATTERN = /^.*\bTEST-(?!KNOWN-FAIL\b)[A-Z-]*FAIL\b.*$/gm;
67
+ /**
68
+ * The three concrete shapes Gecko prints for a real assertion failure.
69
+ * Case-SENSITIVE and punctuation-anchored on purpose: the previous
70
+ * `/\b(?:Assertion failure|MOZ_ASSERT|ASSERTION)\b/gim` was
71
+ * case-insensitive, so the ordinary English word "assertion" in a passing
72
+ * diagnostic ("If an assertion below times out, this is why") was read as
73
+ * a failure — and the verdict then named that diagnostic as the first real
74
+ * test failure, pointing the reader at the wrong line.
75
+ */
76
+ const ASSERTION_LINE_PATTERN = /^.*(?:Assertion failure:|MOZ_ASSERT\(|###!!! ASSERTION).*$/gm;
53
77
  const SHUTDOWN_REENTRY_PATTERN = /Application shut down \(without crashing\) in the middle of a test/i;
54
78
  const FOCUS_STALL_PATTERN = /must wait for focus/i;
55
79
  const TRACEBACK_PATTERN = /Traceback \(most recent call last\)/;
56
80
  const NO_OUTPUT_TIMEOUT_PATTERN = /timed out after \d+ seconds with no output/i;
57
81
  /**
58
- * Crash-marker lines mozcrash / the mochitest harness print when the
59
- * browser process itself died. Matched against the RAW output (never
60
- * noise-stripped): any of these proves the run was truncated by a crash,
61
- * so an embedded green summary is under-reporting, not a result (field
62
- * report: `Main app process: killed by SIGSEGV` at the second of eight
63
- * files, summary `Passed: 2 / Failed: 0`, mach exit 1 — 0.35.0 accepted
64
- * it as passed and masked a real regression for a whole drill).
82
+ * Crash-marker lines mozcrash / the mochitest harness print when the browser
83
+ * process itself died. Matched against the RAW output (never noise-stripped):
84
+ * any of these proves the run was truncated by a crash, so an embedded green
85
+ * summary is under-reporting, not a result. `Main app process: killed by
86
+ * SIGSEGV` at the second of eight files with a `Passed: 2 / Failed: 0`
87
+ * summary is the shape this exists to catch.
65
88
  */
66
89
  const CRASH_MARKER_PATTERNS = [
67
90
  /Main app process: killed by SIG\w+/,
@@ -77,13 +100,13 @@ const CRASH_MARKER_PATTERNS = [
77
100
  * on macOS. Each is matched per-line so the evidence line in the report is
78
101
  * the concrete failure, not the whole traceback.
79
102
  */
80
- // Downstream report (0.34.0 cycle): a pre-fix _DegradedReading fallback that
81
- // wasn't a real namedtuple duck type crashed mozsystemmonitor on the fallback
82
- // itself (`_build_meta` subscripts the reading; `_collect` unpacks it); a
83
- // startup abort with zero TEST-START lines from this family is a crash, not
84
- // a test failure. The `_collect failed` variant is caught-and-logged, so it
85
- // carries no Traceback header — it gets its own zero-TEST-START check in
86
- // `detectHarnessCrashSignature` besides joining the traceback cluster.
103
+ // A `_DegradedReading` fallback that is not a real namedtuple duck type
104
+ // crashes mozsystemmonitor on the fallback itself (`_build_meta` subscripts
105
+ // the reading; `_collect` unpacks it); a startup abort with zero TEST-START
106
+ // lines from this family is a crash, not a test failure. The `_collect
107
+ // failed` variant is caught-and-logged, so it carries no Traceback header —
108
+ // it gets its own zero-TEST-START check in `detectHarnessCrashSignature`
109
+ // besides joining the traceback cluster.
87
110
  const DEGRADED_READING_CRASH_SIGNALS = [
88
111
  /'_DegradedReading' object is not subscriptable/,
89
112
  /'_DegradedReading' object is not iterable/,
@@ -96,12 +119,12 @@ const STARTUP_TRACEBACK_SIGNALS = [
96
119
  /HOST_VM_INFO64/,
97
120
  /\(ipc\/mig\) array not large enough/,
98
121
  /psutil\.[A-Za-z]*Error/,
99
- // Field report (0.34.1): on a degraded host every collector sample is
100
- // rejected, aggregation has nothing, and mozbuild's log_resource_usage
101
- // dies on usage["io"].read_bytes AFTER a fully successful compile
102
- // ("Error running mach" with complete artifacts). Environmental, not a
103
- // build regression — the protected build retries it (incremental retry
104
- // is cheap and the guard keeps the retry green).
122
+ // On a degraded host every collector sample is rejected, aggregation has
123
+ // nothing, and mozbuild's log_resource_usage dies on
124
+ // usage["io"].read_bytes AFTER a fully successful compile ("Error running
125
+ // mach" with complete artifacts). Environmental, not a build regression —
126
+ // the protected build retries it, since an incremental retry is cheap and
127
+ // the guard keeps the retry green.
105
128
  /AttributeError: 'NoneType' object has no attribute 'read_bytes'/,
106
129
  ...DEGRADED_READING_CRASH_SIGNALS,
107
130
  ];
@@ -113,12 +136,11 @@ function findLine(output, patterns) {
113
136
  return undefined;
114
137
  }
115
138
  /**
116
- * Non-signal noise lines: the resource-monitor degrade path (FireForge's
117
- * own guard plus mozlog's `_collect failed`) prints warnings on runs that
118
- * then complete green. Field report (0.34.0 cycle): every multi-file suite
119
- * was reported CRASH because these lines matched the startup-traceback
120
- * signals even though the embedded summary was fully green. They are
121
- * excluded from crash evidence entirely.
139
+ * Non-signal noise lines: the resource-monitor degrade path (FireForge's own
140
+ * guard plus mozlog's `_collect failed`) prints warnings on runs that then
141
+ * complete green. Without excluding them, every multi-file suite reports
142
+ * CRASH because these lines match the startup-traceback signals even though
143
+ * the embedded summary is fully green.
122
144
  */
123
145
  const NOISE_LINE_PATTERNS = [
124
146
  /\bUserWarning\b/,
@@ -130,10 +152,10 @@ const NOISE_LINE_PATTERNS = [
130
152
  /_collect failed(?!.*_DegradedReading)/i,
131
153
  /FireForge: host resource monitor degraded/i,
132
154
  /warnings\.warn\(/,
133
- // mozsystemmonitor's parent-side drain loop rejecting a malformed sample
134
- // (field report 0.34.1); mach sometimes reprints the warning text without
135
- // the `UserWarning:` token, and a run that completes despite the stream
136
- // must never classify as crash on it.
155
+ // mozsystemmonitor's parent-side drain loop rejecting a malformed sample.
156
+ // mach sometimes reprints the warning text without the `UserWarning:`
157
+ // token, and a run that completes despite the stream must never classify
158
+ // as crash on it.
137
159
  /failed to read the received data/i,
138
160
  ];
139
161
  /** Matches the caught/telemetry context that marks a traceback as benign. */
@@ -209,16 +231,16 @@ function hasGreenShapedSummary(output) {
209
231
  realUnexpectedFailureLines(output).length === 0);
210
232
  }
211
233
  /**
212
- * True when the output embeds a COMPLETED, GREEN suite summary: an
213
- * execution signal, `Unexpected results: 0` (and no non-zero unexpected
214
- * count), a `SUITE_END` marker, no real `TEST-UNEXPECTED-*` lines — and
215
- * NO crash marker. Such a run finished its suite; any startup-traceback-
216
- * shaped noise in the same output is by definition non-fatal, so this
217
- * vetoes signature-based crash classification (field report: fully green
218
- * sharded runs reported `CRASH (N attempts)` because degradation warnings
219
- * matched the psutil signals). A summary printed after a crash marker is
220
- * NOT "completed" — it only covers the files that ran before the crash
221
- * (0.35.0 green-wash field report). Exported for direct unit testing.
234
+ * True when the output embeds a COMPLETED, GREEN suite summary: an execution
235
+ * signal, `Unexpected results: 0` (and no non-zero unexpected count), a
236
+ * `SUITE_END` marker, no real `TEST-UNEXPECTED-*` lines — and NO crash
237
+ * marker. Such a run finished its suite, so any startup-traceback-shaped
238
+ * noise in the same output is by definition non-fatal and this vetoes
239
+ * signature-based crash classification; without the veto, fully green
240
+ * sharded runs report `CRASH (N attempts)` because degradation warnings
241
+ * match the psutil signals. A summary printed after a crash marker is NOT
242
+ * "completed" — it only covers the files that ran before the crash.
243
+ * Exported for direct unit testing.
222
244
  */
223
245
  export function hasCompletedGreenSummary(output) {
224
246
  return hasGreenShapedSummary(output) && findCrashMarkerLine(output) === undefined;
@@ -453,18 +475,18 @@ export function classifyHarnessRun(exitCode, output, requestedPaths) {
453
475
  const firstRealFailure = realFailures[0];
454
476
  const failureBlocks = collectUnexpectedFailureBlocks(output);
455
477
  const secondaryHarnessSignature = firstRealFailure !== undefined ? detectSecondaryHarnessNoise(output) : undefined;
456
- // Checked BEFORE signature detection: a suite that ran clean
457
- // and then died in KNOWN upstream teardown noise is a PASS, not a crash.
458
- // The teardown traceback matches the startup-traceback cluster, and the
459
- // existing green-summary veto over that cluster requires a `SUITE_END`
460
- // marker — which this very traceback is what prevents from printing. So
461
- // a substantively green suite (`Ran N checks` / `Unexpected results: 0`,
462
- // no unexpected lines) was reported CRASH, indistinguishable at the
463
- // summary level from a red run. Every hard-evidence veto still applies:
464
- // a crash marker, a non-zero unexpected count, any real TEST-UNEXPECTED
465
- // line, the shutdown-re-entry shape, or a requested file that never
466
- // started keeps the run failing. Only the missing shutdown marker is
467
- // forgiven, and only when the recognized teardown traceback explains it.
478
+ // Checked BEFORE signature detection: a suite that ran clean and then died
479
+ // in KNOWN upstream teardown noise is a PASS, not a crash. The teardown
480
+ // traceback matches the startup-traceback cluster, and the green-summary
481
+ // veto over that cluster requires a `SUITE_END` marker — which this very
482
+ // traceback is what prevents from printing. Without this check a
483
+ // substantively green suite (`Ran N checks` / `Unexpected results: 0`, no
484
+ // unexpected lines) reports CRASH, indistinguishable at the summary level
485
+ // from a red run. Every hard-evidence veto still applies: a crash marker,
486
+ // a non-zero unexpected count, any real TEST-UNEXPECTED line, the
487
+ // shutdown-re-entry shape, or a requested file that never started keeps
488
+ // the run failing. Only the missing shutdown marker is forgiven, and only
489
+ // when the recognized teardown traceback explains it.
468
490
  if (isGreenSuiteEndedByKnownTeardownNoise(output, counts, realFailures, requestedPaths)) {
469
491
  return { kind: 'tests-ran-ok', note: 'harness teardown noise ignored', ...counts };
470
492
  }
@@ -480,16 +502,14 @@ export function classifyHarnessRun(exitCode, output, requestedPaths) {
480
502
  return { kind: 'tests-ran-ok', ...counts };
481
503
  }
482
504
  // Exit codes follow the corrected verdict: a run whose embedded summary
483
- // completed green is a pass even when the wrapper exit code went
484
- // non-zero on harness noise (field report: a fully green --no-shard run
485
- // exited 1). Real failures always carry a non-zero unexpected count or
486
- // TEST-UNEXPECTED lines, both of which fail the green-summary check.
505
+ // completed green is a pass even when the wrapper exit code went non-zero
506
+ // on harness noise. Real failures always carry a non-zero unexpected count
507
+ // or TEST-UNEXPECTED lines, both of which fail the green-summary check.
487
508
  //
488
- // The override must never win over crash or truncation evidence
489
- // (0.35.0 green-wash field report: a SIGSEGV at the second of eight
490
- // files produced a "green" `Passed: 2 / Failed: 0` summary and mach
491
- // exit 1 — the summary was green only because the crash prevented the
492
- // other six files from producing any results). A crash marker or an
509
+ // The override must never win over crash or truncation evidence: a SIGSEGV
510
+ // at the second of eight files produces a "green" `Passed: 2 / Failed: 0`
511
+ // summary and mach exit 1, green only because the crash prevented the
512
+ // other six files from producing any results. A crash marker or an
493
513
  // unpaired/never-started requested file rejects the override with the
494
514
  // evidence attached, so the caller can say why.
495
515
  if (hasGreenShapedSummary(output)) {
@@ -513,14 +533,40 @@ export function classifyHarnessRun(exitCode, output, requestedPaths) {
513
533
  }
514
534
  return { kind: 'tests-ran-ok', greenSummaryOverride: true, ...counts };
515
535
  }
536
+ const wordMatchNote = unmarkedFailureEvidenceNote(counts, realFailures);
516
537
  return {
517
538
  kind: 'test-failures',
518
539
  ...counts,
519
540
  ...(firstRealFailure !== undefined ? { realFailureLine: firstRealFailure } : {}),
520
541
  ...(failureBlocks.length > 0 ? { realFailureBlocks: failureBlocks } : {}),
521
542
  ...(secondaryHarnessSignature !== undefined ? { secondaryHarnessSignature } : {}),
543
+ ...(wordMatchNote !== undefined ? { note: wordMatchNote } : {}),
522
544
  };
523
545
  }
546
+ /**
547
+ * Belt for the residual case the tightened {@link FAIL_LINE_PATTERN} /
548
+ * {@link ASSERTION_LINE_PATTERN} cannot reach: the summary reported
549
+ * `Unexpected results: 0`, yet the run is still classified `test-failures`
550
+ * on evidence lines that carry NO `TEST-UNEXPECTED-*` marker.
551
+ *
552
+ * `unexpected=0` printed beside `reason=test-failures` is the tell that the
553
+ * verdict rests on pattern matching rather than on a harness result, and a
554
+ * reader who cannot see that spends hours attributing a red run to the
555
+ * change under test. The note says so on the verdict line itself.
556
+ *
557
+ * Deliberately a NOTE and not a reclassification: a non-zero exit with no
558
+ * green-shaped summary is still a failing run, and inventing a new `reason`
559
+ * would break the `FIREFORGE-VERDICT:` contract its consumers parse.
560
+ */
561
+ function unmarkedFailureEvidenceNote(counts, realFailures) {
562
+ if (counts.unexpected !== 0)
563
+ return undefined;
564
+ if (realFailures.length === 0)
565
+ return undefined;
566
+ if (realFailures.some((line) => UNEXPECTED_LINE_SINGLE.test(line)))
567
+ return undefined;
568
+ return 'summary reported 0 unexpected; no TEST-UNEXPECTED marker in the matched evidence';
569
+ }
524
570
  /**
525
571
  * True when the capture shows a substantively GREEN suite whose only
526
572
  * unexplained residue is the recognized mozsystemmonitor teardown
@@ -643,73 +689,6 @@ export function buildHarnessCrashMessage(signature, attempts, commandLabel = 'ma
643
689
  'If it persists across many runs, inspect the mach virtualenv (mach resyncs psutil on its own; ' +
644
690
  'patching it manually does not stick).');
645
691
  }
646
- /**
647
- * The three recorded causes of the `timed out … with no output` / `Ran 0
648
- * checks` signature, ordered so one stall points at the discriminating
649
- * next step. Printed verbatim under the hint.
650
- */
651
- const NO_OUTPUT_STALL_TRIAGE = [
652
- ' 1. A sleeping or locked display on an unattended HEADED run (macOS). The browser never ' +
653
- 'paints and never reaches its first test.',
654
- ' 2. A headless SWGL compositor failure — re-run with --headless to separate this from (1): ' +
655
- 'if --headless passes, the stall was display/compositor-side, not product-side.',
656
- ' 3. A broken `chrome://` image on the startup page, which stalls first paint. Run a ' +
657
- 'known-good control test first; if the control stalls too, the cause is not the test ' +
658
- 'under investigation.',
659
- ];
660
- /**
661
- * Optional hint appended to the harness-crash message when a HEADED run on
662
- * macOS died at the no-output timeout.
663
- *
664
- * When `displayState` names a MEASURED display state, the hint states it
665
- * as fact rather than as one of three possibilities — that is the whole
666
- * point of probing: an operator staring at a bare test failure should not
667
- * have to rediscover that their machine dimmed. `caffeinate` is described
668
- * accurately (it prevents sleep; it cannot wake an already-sleeping
669
- * display), because the previous wording sent operators to a command that
670
- * could not have helped them.
671
- *
672
- * Pure — the platform and the probed state are injected so unit tests need
673
- * no mocking.
674
- *
675
- * @param signature - The recognized crash shape
676
- * @param context - Run mode, platform, and the probed display state
677
- * @returns The hint text, or undefined when the shape does not apply
678
- */
679
- export function headedNoOutputTimeoutHint(signature, context) {
680
- if (context.platform !== 'darwin' || context.headless)
681
- return undefined;
682
- if (!signature.reason.includes('no-output timeout'))
683
- return undefined;
684
- const lead = context.displayState === 'asleep'
685
- ? 'Hint: this was a HEADED run on macOS and the display was MEASURED ASLEEP ' +
686
- '(IODisplayWrangler below its awake power state). A headed browser on a sleeping ' +
687
- 'display never paints and never starts a test, so this stall is environmental — not a ' +
688
- 'product or test failure.'
689
- : context.displayState === 'awake'
690
- ? 'Hint: this was a HEADED run on macOS that died at the no-output timeout. The display ' +
691
- 'was measured AWAKE, so the sleeping-display cause below is ruled out for this run.'
692
- : 'Hint: this was a HEADED run on macOS that died at the no-output timeout. The display ' +
693
- 'state could not be measured, so all three causes below remain open.';
694
- const remedy = 'Note that `caffeinate -disu` PREVENTS sleep; it cannot WAKE a display that is already ' +
695
- 'asleep. Wake the display (or run on an attended machine), or pass --headless.';
696
- return `${lead}\n\nKnown causes of this exact signature:\n${NO_OUTPUT_STALL_TRIAGE.join('\n')}\n\n${remedy}`;
697
- }
698
- /**
699
- * Verdict-line note for a headed no-output stall whose display was
700
- * measured asleep. Returned as the parenthetical the verdict line carries,
701
- * so the one greppable line an automated consumer reads already names the
702
- * environmental cause instead of a bare `FAIL reason=crash`.
703
- */
704
- export function headedDisplayAsleepVerdictNote(signature, context) {
705
- if (context.platform !== 'darwin' || context.headless)
706
- return undefined;
707
- if (context.displayState !== 'asleep')
708
- return undefined;
709
- if (!signature.reason.includes('no-output timeout'))
710
- return undefined;
711
- return 'headed run stalled with the display asleep';
712
- }
713
692
  /**
714
693
  * Exit codes that mean "the child died on SIGSEGV": Node reports a
715
694
  * signal-killed child as the negated signal number, while a shell layer
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The recognized-harness-crash shape, in a module of its own.
3
+ *
4
+ * It lives apart from both of its users to break an import cycle:
5
+ * `test-harness-crash.ts` re-exports the operator advice in
6
+ * `test-stall-triage.ts`, and the triage text is keyed on this signature. A
7
+ * type-only edge is erased at runtime, but the cycle gate reads the import
8
+ * graph rather than the emitted code, and a shared leaf is a truer
9
+ * description of the relationship than either direction of the cycle was:
10
+ * neither module owns this type more than the other.
11
+ */
12
+ /** A recognized harness-crash shape with its evidence line. */
13
+ export interface HarnessCrashSignature {
14
+ /** Stable reason id for the recognized shape. */
15
+ reason: string;
16
+ /** The concrete output line the recognition was based on. */
17
+ line: string;
18
+ }
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * The recognized-harness-crash shape, in a module of its own.
4
+ *
5
+ * It lives apart from both of its users to break an import cycle:
6
+ * `test-harness-crash.ts` re-exports the operator advice in
7
+ * `test-stall-triage.ts`, and the triage text is keyed on this signature. A
8
+ * type-only edge is erased at runtime, but the cycle gate reads the import
9
+ * graph rather than the emitted code, and a shared leaf is a truer
10
+ * description of the relationship than either direction of the cycle was:
11
+ * neither module owns this type more than the other.
12
+ */
13
+ export {};
@@ -1,22 +1,19 @@
1
1
  /**
2
2
  * Directory-argument scope analysis for `fireforge test`.
3
3
  *
4
- * mozbuild's test resolver matches command-line paths by STRING PREFIX,
5
- * so `fireforge test browser/base/content/test/hominis` silently also
6
- * ran the sibling directory `browser/base/content/test/hominis-tiles`
7
- * (152.0b7 → 153.0b8 source-refresh drill: 1224 tests instead of ~200,
8
- * with no indication the scope widened).
4
+ * mozbuild's test resolver matches command-line paths by STRING PREFIX, so
5
+ * `fireforge test browser/base/content/test/hominis` also runs the sibling
6
+ * directory `browser/base/content/test/hominis-tiles` — silently, and with
7
+ * no indication the scope widened.
8
+ *
9
+ * FireForge therefore treats a directory argument as meaning EXACTLY that
10
+ * directory: {@link analyzeTestPathScopes} enumerates the test files of
11
+ * exactly that directory and dispatches THAT explicit file list to mach,
12
+ * because a file list cannot prefix-match anything. Normalizing the
13
+ * directory with a trailing `/` does NOT work — mach still sweeps in the
14
+ * prefix-named sibling. The prefix-matching sibling directories are still
15
+ * reported so the command layer can tell the operator what was excluded.
9
16
  *
10
- * FireForge therefore treats a directory argument as meaning EXACTLY
11
- * that directory: {@link analyzeTestPathScopes} enumerates the test
12
- * files of exactly that directory and dispatches THAT explicit file
13
- * list to mach — a file list cannot prefix-match anything. (0.35.0
14
- * instead normalized the directory with a trailing `/`, assuming the
15
- * separator makes the prefix match exact; field verification on Firefox
16
- * 153 showed mach still swept in the prefix-named sibling, so the
17
- * trailing-slash mechanism was cosmetic and its exclusion echo was
18
- * wrong.) The prefix-matching sibling directories are still reported so
19
- * the command layer can tell the operator what was excluded. Note
20
17
  * FireForge already rejects non-existent paths up front, so raw
21
18
  * prefix-widening was never something an operator could invoke
22
19
  * deliberately — it only ever happened by accident.
@@ -2,22 +2,19 @@
2
2
  /**
3
3
  * Directory-argument scope analysis for `fireforge test`.
4
4
  *
5
- * mozbuild's test resolver matches command-line paths by STRING PREFIX,
6
- * so `fireforge test browser/base/content/test/hominis` silently also
7
- * ran the sibling directory `browser/base/content/test/hominis-tiles`
8
- * (152.0b7 → 153.0b8 source-refresh drill: 1224 tests instead of ~200,
9
- * with no indication the scope widened).
5
+ * mozbuild's test resolver matches command-line paths by STRING PREFIX, so
6
+ * `fireforge test browser/base/content/test/hominis` also runs the sibling
7
+ * directory `browser/base/content/test/hominis-tiles` — silently, and with
8
+ * no indication the scope widened.
9
+ *
10
+ * FireForge therefore treats a directory argument as meaning EXACTLY that
11
+ * directory: {@link analyzeTestPathScopes} enumerates the test files of
12
+ * exactly that directory and dispatches THAT explicit file list to mach,
13
+ * because a file list cannot prefix-match anything. Normalizing the
14
+ * directory with a trailing `/` does NOT work — mach still sweeps in the
15
+ * prefix-named sibling. The prefix-matching sibling directories are still
16
+ * reported so the command layer can tell the operator what was excluded.
10
17
  *
11
- * FireForge therefore treats a directory argument as meaning EXACTLY
12
- * that directory: {@link analyzeTestPathScopes} enumerates the test
13
- * files of exactly that directory and dispatches THAT explicit file
14
- * list to mach — a file list cannot prefix-match anything. (0.35.0
15
- * instead normalized the directory with a trailing `/`, assuming the
16
- * separator makes the prefix match exact; field verification on Firefox
17
- * 153 showed mach still swept in the prefix-named sibling, so the
18
- * trailing-slash mechanism was cosmetic and its exclusion echo was
19
- * wrong.) The prefix-matching sibling directories are still reported so
20
- * the command layer can tell the operator what was excluded. Note
21
18
  * FireForge already rejects non-existent paths up front, so raw
22
19
  * prefix-widening was never something an operator could invoke
23
20
  * deliberately — it only ever happened by accident.
@@ -137,9 +134,9 @@ export function formatScopeNotice(scope) {
137
134
  .map((s) => `${s.path}/ (${s.testFileCount} test file${s.testFileCount === 1 ? '' : 's'})`)
138
135
  .join(', ');
139
136
  if (scope.testFileCount === 0) {
140
- // Fallback dispatch: with nothing to enumerate, the raw directory
141
- // form goes to mach, whose prefix matching CAN sweep the siblings in.
142
- // Claiming exclusion here would repeat the 0.35.0 mistake.
137
+ // Fallback dispatch: with nothing to enumerate, the raw directory form
138
+ // goes to mach, whose prefix matching CAN sweep the siblings in.
139
+ // Claiming exclusion here would be a lie.
143
140
  return (`${requestedDir}/ contains no enumerable test files, so the directory is passed to mach ` +
144
141
  `as-is — mach resolves paths by string prefix, which may also select: ${siblings}.`);
145
142
  }
@@ -53,16 +53,16 @@ export declare const FULL_SUITE_REQUEST = "(entire suite)";
53
53
  * packaging does NOT cover — the runs that would dispatch against missing
54
54
  * `_tests/` support fixtures and hang rather than fail.
55
55
  *
56
- * Coverage semantics: `undefined` (pre-0.37.0 baseline) and `'full'` cover
57
- * everything. A scoped list covers a request path when the request equals a
58
- * covered entry, sits beneath a covered directory entry, or shares a
59
- * manifest granule with a covered entry ({@link toManifestGranule} — a
60
- * scoped `test --build` packages the whole manifest directory, so a
61
- * same-manifest sibling of a covered file is packaged too). Both sides are
62
- * normalized to forward slashes so Windows-style CLI input cannot defeat
63
- * the prefix rule (baseline paths are POSIX by convention). A request with
64
- * no paths is a full-suite run and is never covered by a scoped list — the
65
- * {@link FULL_SUITE_REQUEST} sentinel is returned so the refusal can name it.
56
+ * Coverage semantics: an absent claim and `'full'` cover everything. A
57
+ * scoped list covers a request path when the request equals a covered entry,
58
+ * sits beneath a covered directory entry, or shares a manifest granule with
59
+ * a covered entry ({@link toManifestGranule} — a scoped `test --build`
60
+ * packages the whole manifest directory, so a same-manifest sibling of a
61
+ * covered file is packaged too). Both sides are normalized to forward
62
+ * slashes so Windows-style CLI input cannot defeat the prefix rule (baseline
63
+ * paths are POSIX by convention). A request with no paths is a full-suite
64
+ * run and is never covered by a scoped list — the {@link FULL_SUITE_REQUEST}
65
+ * sentinel is returned so the refusal can name it.
66
66
  */
67
67
  export declare function findUncoveredRequestPaths(coverage: TestPackagingCoverage | undefined, requestedPaths: readonly string[]): string[];
68
68
  /**
@@ -88,17 +88,17 @@ export interface StaticComponentsStaleResult {
88
88
  * Probes whether any `components.conf` changed since the last FULL
89
89
  * `fireforge build` — i.e. since the compiled StaticComponents table was
90
90
  * last regenerated. `components.conf` entries bake into compiled code; a
91
- * scoped `test --build` packages the file but the child process resolves
92
- * the OLD table and fails with `NS_ERROR_MALFORMED_URI` that reads as a
93
- * test bug.
91
+ * scoped `test --build` packages the file but the child process resolves the
92
+ * OLD table and fails with `NS_ERROR_MALFORMED_URI` that reads as a test
93
+ * bug.
94
94
  *
95
95
  * The diff anchors to the baseline's `staticComponentsBaseline` (the last
96
- * full build's engine HEAD SHA), NOT the baseline's own `engineHeadSha`
96
+ * full build's engine HEAD SHA), NOT the baseline's own `engineHeadSha`,
97
97
  * which a scoped `test --build` advances. Dirty candidates are hash-checked
98
98
  * against the anchor's fingerprints so only genuine content divergence
99
- * counts. No baseline / no anchor (pre-0.38.0 marker) → fresh. Never
100
- * throws — the probes it composes degrade to verbose lines and empty
101
- * results on git failure, matching {@link checkStaleBuildForTest}.
99
+ * counts. No baseline or no anchor means fresh. Never throws — the probes it
100
+ * composes degrade to verbose lines and empty results on git failure,
101
+ * matching {@link checkStaleBuildForTest}.
102
102
  */
103
103
  export declare function checkStaticComponentsStale(engineDir: string, baseline: BuildBaseline | undefined): Promise<StaticComponentsStaleResult>;
104
104
  /**