@hominis/fireforge 0.49.2 → 0.51.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 (400) hide show
  1. package/CHANGELOG.md +87 -1
  2. package/README.md +1 -1
  3. package/dist/bin/fireforge.js +6 -0
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/commands/build-prelock.d.ts +20 -0
  6. package/dist/src/commands/build-prelock.js +50 -0
  7. package/dist/src/commands/build.d.ts +3 -1
  8. package/dist/src/commands/build.js +13 -6
  9. package/dist/src/commands/check-report.d.ts +41 -0
  10. package/dist/src/commands/check-report.js +91 -0
  11. package/dist/src/commands/check-run.d.ts +33 -0
  12. package/dist/src/commands/check-run.js +112 -0
  13. package/dist/src/commands/check-steps.d.ts +75 -0
  14. package/dist/src/commands/check-steps.js +200 -0
  15. package/dist/src/commands/check.d.ts +32 -0
  16. package/dist/src/commands/check.js +160 -0
  17. package/dist/src/commands/config.js +5 -6
  18. package/dist/src/commands/declarations-report.d.ts +43 -0
  19. package/dist/src/commands/declarations-report.js +76 -0
  20. package/dist/src/commands/doctor-engine-eslint.js +6 -1
  21. package/dist/src/commands/doctor-source-pin.js +4 -1
  22. package/dist/src/commands/export-adopt-check.d.ts +38 -0
  23. package/dist/src/commands/export-adopt-check.js +98 -0
  24. package/dist/src/commands/export-flow.js +29 -14
  25. package/dist/src/commands/export-placement-gate.d.ts +6 -2
  26. package/dist/src/commands/export-placement-gate.js +8 -0
  27. package/dist/src/commands/export-shared.d.ts +2 -1
  28. package/dist/src/commands/export-staged-registration.d.ts +46 -0
  29. package/dist/src/commands/export-staged-registration.js +91 -0
  30. package/dist/src/commands/forward-import-remedy.d.ts +32 -0
  31. package/dist/src/commands/forward-import-remedy.js +63 -0
  32. package/dist/src/commands/furnace/apply.js +3 -3
  33. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
  34. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  35. package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
  36. package/dist/src/commands/furnace/chrome-doc.js +2 -2
  37. package/dist/src/commands/furnace/create.js +2 -2
  38. package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
  39. package/dist/src/commands/furnace/deploy-named.js +107 -0
  40. package/dist/src/commands/furnace/deploy.d.ts +3 -2
  41. package/dist/src/commands/furnace/deploy.js +50 -86
  42. package/dist/src/commands/furnace/diff.js +26 -3
  43. package/dist/src/commands/furnace/index.js +66 -41
  44. package/dist/src/commands/furnace/init.js +13 -6
  45. package/dist/src/commands/furnace/override.js +4 -2
  46. package/dist/src/commands/furnace/preview.js +4 -3
  47. package/dist/src/commands/furnace/refresh.js +2 -2
  48. package/dist/src/commands/furnace/remove.js +4 -3
  49. package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
  50. package/dist/src/commands/furnace/rename-dry-run.js +127 -0
  51. package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
  52. package/dist/src/commands/furnace/rename-helpers.js +15 -1
  53. package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
  54. package/dist/src/commands/furnace/rename-registrations.js +98 -0
  55. package/dist/src/commands/furnace/rename.d.ts +2 -1
  56. package/dist/src/commands/furnace/rename.js +28 -66
  57. package/dist/src/commands/furnace/scan.d.ts +9 -4
  58. package/dist/src/commands/furnace/scan.js +11 -9
  59. package/dist/src/commands/furnace/sync.js +3 -2
  60. package/dist/src/commands/furnace/validate-report.d.ts +45 -0
  61. package/dist/src/commands/furnace/validate-report.js +91 -0
  62. package/dist/src/commands/furnace/validate.d.ts +1 -1
  63. package/dist/src/commands/furnace/validate.js +151 -113
  64. package/dist/src/commands/furnace/validation-output.js +14 -3
  65. package/dist/src/commands/lint-per-patch.js +36 -61
  66. package/dist/src/commands/lint-per-run-checkjs.js +2 -2
  67. package/dist/src/commands/lint-report.d.ts +8 -4
  68. package/dist/src/commands/lint-report.js +20 -5
  69. package/dist/src/commands/lint.js +15 -34
  70. package/dist/src/commands/manifest.js +4 -0
  71. package/dist/src/commands/park.d.ts +22 -0
  72. package/dist/src/commands/park.js +232 -0
  73. package/dist/src/commands/patch/delete-gap-notice.js +3 -1
  74. package/dist/src/commands/patch/delete.d.ts +1 -1
  75. package/dist/src/commands/patch/delete.js +24 -104
  76. package/dist/src/commands/patch/index.d.ts +3 -3
  77. package/dist/src/commands/patch/index.js +10 -4
  78. package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
  79. package/dist/src/commands/patch/lint-ignore-from.js +142 -0
  80. package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
  81. package/dist/src/commands/patch/lint-ignore.js +78 -31
  82. package/dist/src/commands/patch/move-files-create.js +34 -18
  83. package/dist/src/commands/patch/move-files-into.js +15 -7
  84. package/dist/src/commands/patch/move-files.js +6 -2
  85. package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
  86. package/dist/src/commands/patch/removal-created-files.js +83 -0
  87. package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
  88. package/dist/src/commands/patch/removal-dependents.js +133 -0
  89. package/dist/src/commands/patch/rename.js +20 -1
  90. package/dist/src/commands/patch/reserve.d.ts +33 -0
  91. package/dist/src/commands/patch/reserve.js +152 -0
  92. package/dist/src/commands/patch/retire.d.ts +34 -0
  93. package/dist/src/commands/patch/retire.js +133 -0
  94. package/dist/src/commands/patch/split-plan.d.ts +17 -8
  95. package/dist/src/commands/patch/split-plan.js +60 -28
  96. package/dist/src/commands/patch/split-staged.d.ts +108 -0
  97. package/dist/src/commands/patch/split-staged.js +202 -0
  98. package/dist/src/commands/patch/split.d.ts +5 -0
  99. package/dist/src/commands/patch/split.js +62 -17
  100. package/dist/src/commands/patch/stage.d.ts +34 -0
  101. package/dist/src/commands/patch/stage.js +153 -0
  102. package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
  103. package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
  104. package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
  105. package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
  106. package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
  107. package/dist/src/commands/patch/staged-dependency-from.js +108 -0
  108. package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
  109. package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
  110. package/dist/src/commands/patch/staged-dependency.js +54 -139
  111. package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
  112. package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
  113. package/dist/src/commands/re-export-adjacent.d.ts +50 -2
  114. package/dist/src/commands/re-export-adjacent.js +160 -40
  115. package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
  116. package/dist/src/commands/re-export-bulk-scan.js +22 -7
  117. package/dist/src/commands/re-export-drift.d.ts +36 -8
  118. package/dist/src/commands/re-export-drift.js +73 -49
  119. package/dist/src/commands/re-export-files.js +11 -8
  120. package/dist/src/commands/re-export-hunks.d.ts +35 -0
  121. package/dist/src/commands/re-export-hunks.js +220 -0
  122. package/dist/src/commands/re-export-lint.d.ts +2 -1
  123. package/dist/src/commands/re-export-lint.js +23 -10
  124. package/dist/src/commands/re-export-options.js +74 -6
  125. package/dist/src/commands/re-export-preflight.d.ts +23 -0
  126. package/dist/src/commands/re-export-preflight.js +160 -0
  127. package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
  128. package/dist/src/commands/re-export-purity-scope.js +131 -0
  129. package/dist/src/commands/re-export-register.js +56 -17
  130. package/dist/src/commands/re-export-removed.d.ts +13 -2
  131. package/dist/src/commands/re-export-removed.js +57 -12
  132. package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
  133. package/dist/src/commands/re-export-scan-owner.js +116 -0
  134. package/dist/src/commands/re-export-scan.d.ts +19 -9
  135. package/dist/src/commands/re-export-scan.js +60 -24
  136. package/dist/src/commands/re-export-single.js +122 -46
  137. package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
  138. package/dist/src/commands/re-export-stale-registrations.js +62 -0
  139. package/dist/src/commands/re-export-summary.d.ts +28 -0
  140. package/dist/src/commands/re-export-summary.js +36 -0
  141. package/dist/src/commands/re-export.js +71 -57
  142. package/dist/src/commands/rebase/index.js +17 -17
  143. package/dist/src/commands/run.js +16 -2
  144. package/dist/src/commands/status-check.d.ts +55 -16
  145. package/dist/src/commands/status-check.js +92 -37
  146. package/dist/src/commands/status-json.d.ts +22 -9
  147. package/dist/src/commands/status-json.js +47 -32
  148. package/dist/src/commands/status-output.js +3 -1
  149. package/dist/src/commands/status-scope.d.ts +37 -0
  150. package/dist/src/commands/status-scope.js +54 -0
  151. package/dist/src/commands/status.js +66 -23
  152. package/dist/src/commands/test-browser-preflight.js +19 -3
  153. package/dist/src/commands/test-build-furnace.d.ts +22 -0
  154. package/dist/src/commands/test-build-furnace.js +54 -0
  155. package/dist/src/commands/test-build-phase.js +64 -41
  156. package/dist/src/commands/test-checkjs.js +10 -2
  157. package/dist/src/commands/test-diagnose.js +7 -0
  158. package/dist/src/commands/test-dispatch.d.ts +39 -0
  159. package/dist/src/commands/test-dispatch.js +211 -0
  160. package/dist/src/commands/test-furnace-reach.d.ts +37 -0
  161. package/dist/src/commands/test-furnace-reach.js +132 -0
  162. package/dist/src/commands/test-modes.d.ts +16 -1
  163. package/dist/src/commands/test-modes.js +24 -1
  164. package/dist/src/commands/test-multi-verdict.d.ts +61 -0
  165. package/dist/src/commands/test-multi-verdict.js +111 -0
  166. package/dist/src/commands/test-orchestrate.d.ts +52 -0
  167. package/dist/src/commands/test-orchestrate.js +240 -0
  168. package/dist/src/commands/test-perf-scope.d.ts +50 -0
  169. package/dist/src/commands/test-perf-scope.js +138 -0
  170. package/dist/src/commands/test-prelock.d.ts +51 -0
  171. package/dist/src/commands/test-prelock.js +273 -0
  172. package/dist/src/commands/test-register.js +69 -10
  173. package/dist/src/commands/test-results.d.ts +62 -0
  174. package/dist/src/commands/test-results.js +62 -0
  175. package/dist/src/commands/test-run.d.ts +13 -55
  176. package/dist/src/commands/test-run.js +74 -99
  177. package/dist/src/commands/test-shards.d.ts +110 -0
  178. package/dist/src/commands/test-shards.js +255 -0
  179. package/dist/src/commands/test-stale-gate.d.ts +5 -1
  180. package/dist/src/commands/test-stale-gate.js +60 -28
  181. package/dist/src/commands/test-verdict.d.ts +11 -1
  182. package/dist/src/commands/test-verdict.js +28 -1
  183. package/dist/src/commands/test.d.ts +6 -1
  184. package/dist/src/commands/test.js +120 -124
  185. package/dist/src/commands/token-lint.d.ts +14 -0
  186. package/dist/src/commands/token-lint.js +151 -0
  187. package/dist/src/commands/token.js +10 -0
  188. package/dist/src/commands/verify-scope.d.ts +28 -0
  189. package/dist/src/commands/verify-scope.js +67 -0
  190. package/dist/src/commands/verify.d.ts +10 -2
  191. package/dist/src/commands/verify.js +67 -36
  192. package/dist/src/core/build-baseline-types.d.ts +46 -0
  193. package/dist/src/core/build-baseline-validate.js +19 -0
  194. package/dist/src/core/build-baseline.d.ts +5 -1
  195. package/dist/src/core/build-baseline.js +3 -1
  196. package/dist/src/core/build-overwrite-guard.d.ts +50 -0
  197. package/dist/src/core/build-overwrite-guard.js +84 -4
  198. package/dist/src/core/build-prepare.d.ts +13 -0
  199. package/dist/src/core/build-prepare.js +42 -10
  200. package/dist/src/core/build-run-record.d.ts +74 -0
  201. package/dist/src/core/build-run-record.js +136 -0
  202. package/dist/src/core/checkjs-support-heads.d.ts +41 -0
  203. package/dist/src/core/checkjs-support-heads.js +104 -0
  204. package/dist/src/core/config-paths.d.ts +2 -2
  205. package/dist/src/core/config-paths.js +10 -0
  206. package/dist/src/core/config-validate-check.d.ts +8 -0
  207. package/dist/src/core/config-validate-check.js +219 -0
  208. package/dist/src/core/config-validate-file-size.d.ts +9 -6
  209. package/dist/src/core/config-validate-file-size.js +91 -2
  210. package/dist/src/core/config-validate-history.d.ts +11 -0
  211. package/dist/src/core/config-validate-history.js +38 -0
  212. package/dist/src/core/config-validate-patch-policy.js +100 -0
  213. package/dist/src/core/config-validate-test-toolchains.js +21 -0
  214. package/dist/src/core/config-validate-token-scales.d.ts +9 -0
  215. package/dist/src/core/config-validate-token-scales.js +92 -0
  216. package/dist/src/core/config-validate.js +20 -5
  217. package/dist/src/core/config.d.ts +5 -0
  218. package/dist/src/core/config.js +16 -0
  219. package/dist/src/core/coverage-dispatch.d.ts +24 -0
  220. package/dist/src/core/coverage-dispatch.js +44 -0
  221. package/dist/src/core/coverage-extend.d.ts +70 -45
  222. package/dist/src/core/coverage-extend.js +199 -144
  223. package/dist/src/core/coverage-records.d.ts +108 -0
  224. package/dist/src/core/coverage-records.js +384 -0
  225. package/dist/src/core/destructive.d.ts +7 -4
  226. package/dist/src/core/destructive.js +10 -10
  227. package/dist/src/core/engine-session-lock.d.ts +16 -1
  228. package/dist/src/core/engine-session-lock.js +38 -10
  229. package/dist/src/core/export-moved-code-shape.d.ts +49 -11
  230. package/dist/src/core/export-moved-code-shape.js +135 -44
  231. package/dist/src/core/file-lock-queue.d.ts +67 -0
  232. package/dist/src/core/file-lock-queue.js +221 -0
  233. package/dist/src/core/file-lock-shared.d.ts +57 -0
  234. package/dist/src/core/file-lock-shared.js +117 -0
  235. package/dist/src/core/file-lock.d.ts +13 -25
  236. package/dist/src/core/file-lock.js +163 -140
  237. package/dist/src/core/furnace-apply-output.d.ts +10 -0
  238. package/dist/src/core/furnace-apply-output.js +31 -1
  239. package/dist/src/core/furnace-apply.js +22 -12
  240. package/dist/src/core/furnace-composed-source.d.ts +76 -0
  241. package/dist/src/core/furnace-composed-source.js +167 -0
  242. package/dist/src/core/furnace-config-validate-exceptions.d.ts +16 -0
  243. package/dist/src/core/furnace-config-validate-exceptions.js +102 -0
  244. package/dist/src/core/furnace-config-validate.js +14 -0
  245. package/dist/src/core/furnace-css-fragments.d.ts +10 -0
  246. package/dist/src/core/furnace-css-fragments.js +26 -0
  247. package/dist/src/core/furnace-operation.d.ts +3 -3
  248. package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
  249. package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
  250. package/dist/src/core/furnace-registration-remove.d.ts +22 -1
  251. package/dist/src/core/furnace-registration-remove.js +53 -17
  252. package/dist/src/core/furnace-registration-rename.d.ts +26 -0
  253. package/dist/src/core/furnace-registration-rename.js +77 -0
  254. package/dist/src/core/furnace-registration.d.ts +14 -4
  255. package/dist/src/core/furnace-registration.js +44 -10
  256. package/dist/src/core/furnace-staleness.d.ts +7 -0
  257. package/dist/src/core/furnace-staleness.js +34 -24
  258. package/dist/src/core/furnace-validate-accessibility.d.ts +8 -4
  259. package/dist/src/core/furnace-validate-accessibility.js +71 -28
  260. package/dist/src/core/furnace-validate-exceptions.d.ts +48 -0
  261. package/dist/src/core/furnace-validate-exceptions.js +80 -0
  262. package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
  263. package/dist/src/core/furnace-validate-icon-button.js +78 -0
  264. package/dist/src/core/furnace-validate.js +1 -1
  265. package/dist/src/core/harness-port-fallback.d.ts +60 -0
  266. package/dist/src/core/harness-port-fallback.js +96 -0
  267. package/dist/src/core/history-log-file.d.ts +61 -0
  268. package/dist/src/core/history-log-file.js +164 -0
  269. package/dist/src/core/history-log.d.ts +2 -1
  270. package/dist/src/core/history-log.js +2 -1
  271. package/dist/src/core/json-preserving-edit.d.ts +22 -0
  272. package/dist/src/core/json-preserving-edit.js +199 -0
  273. package/dist/src/core/line-prefixer.d.ts +18 -0
  274. package/dist/src/core/line-prefixer.js +34 -0
  275. package/dist/src/core/mach.d.ts +7 -0
  276. package/dist/src/core/mach.js +32 -10
  277. package/dist/src/core/module-resolution-preflight.d.ts +19 -3
  278. package/dist/src/core/module-resolution-preflight.js +24 -6
  279. package/dist/src/core/negative-control-compiled.d.ts +27 -0
  280. package/dist/src/core/negative-control-compiled.js +73 -0
  281. package/dist/src/core/negative-control-diff.d.ts +51 -0
  282. package/dist/src/core/negative-control-diff.js +179 -0
  283. package/dist/src/core/negative-control.d.ts +150 -0
  284. package/dist/src/core/negative-control.js +399 -0
  285. package/dist/src/core/objdir-install-manifests.d.ts +73 -0
  286. package/dist/src/core/objdir-install-manifests.js +226 -0
  287. package/dist/src/core/park-store.d.ts +63 -0
  288. package/dist/src/core/park-store.js +216 -0
  289. package/dist/src/core/patch-export-update.d.ts +6 -0
  290. package/dist/src/core/patch-export-update.js +13 -3
  291. package/dist/src/core/patch-export.d.ts +3 -2
  292. package/dist/src/core/patch-export.js +22 -16
  293. package/dist/src/core/patch-files.js +26 -8
  294. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +39 -0
  295. package/dist/src/core/patch-lint-checkjs-any-import.js +63 -0
  296. package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
  297. package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
  298. package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
  299. package/dist/src/core/patch-lint-checkjs.js +20 -13
  300. package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
  301. package/dist/src/core/patch-lint-code-lines.js +105 -0
  302. package/dist/src/core/patch-lint-cross.d.ts +3 -1
  303. package/dist/src/core/patch-lint-cross.js +17 -4
  304. package/dist/src/core/patch-lint-css.d.ts +8 -2
  305. package/dist/src/core/patch-lint-css.js +24 -14
  306. package/dist/src/core/patch-lint-file-size.d.ts +12 -5
  307. package/dist/src/core/patch-lint-file-size.js +22 -11
  308. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +23 -0
  309. package/dist/src/core/patch-lint-forward-registration-extended.js +36 -11
  310. package/dist/src/core/patch-lint-forward-registration.js +10 -0
  311. package/dist/src/core/patch-lint-ignore.d.ts +196 -0
  312. package/dist/src/core/patch-lint-ignore.js +429 -0
  313. package/dist/src/core/patch-lint-ownership.d.ts +10 -0
  314. package/dist/src/core/patch-lint-ownership.js +26 -0
  315. package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
  316. package/dist/src/core/patch-lint-size-thresholds.js +110 -0
  317. package/dist/src/core/patch-lint-size.d.ts +117 -0
  318. package/dist/src/core/patch-lint-size.js +331 -0
  319. package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
  320. package/dist/src/core/patch-lint-staged-registration.js +20 -0
  321. package/dist/src/core/patch-lint-token-scale.d.ts +57 -0
  322. package/dist/src/core/patch-lint-token-scale.js +286 -0
  323. package/dist/src/core/patch-lint.d.ts +11 -83
  324. package/dist/src/core/patch-lint.js +66 -288
  325. package/dist/src/core/patch-lock.js +7 -6
  326. package/dist/src/core/patch-manifest-consistency.js +7 -6
  327. package/dist/src/core/patch-manifest-io.d.ts +6 -3
  328. package/dist/src/core/patch-manifest-io.js +27 -9
  329. package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
  330. package/dist/src/core/patch-manifest-key-order.js +61 -0
  331. package/dist/src/core/patch-manifest-stage.d.ts +46 -0
  332. package/dist/src/core/patch-manifest-stage.js +96 -0
  333. package/dist/src/core/patch-manifest-validate.js +61 -3
  334. package/dist/src/core/patch-order-legal.d.ts +26 -0
  335. package/dist/src/core/patch-order-legal.js +88 -0
  336. package/dist/src/core/patch-policy-content.d.ts +40 -0
  337. package/dist/src/core/patch-policy-content.js +216 -0
  338. package/dist/src/core/patch-policy.d.ts +22 -5
  339. package/dist/src/core/patch-policy.js +26 -12
  340. package/dist/src/core/patch-retired.d.ts +57 -0
  341. package/dist/src/core/patch-retired.js +92 -0
  342. package/dist/src/core/patch-subset.d.ts +16 -0
  343. package/dist/src/core/patch-subset.js +66 -0
  344. package/dist/src/core/preflight-wait.d.ts +20 -0
  345. package/dist/src/core/preflight-wait.js +38 -0
  346. package/dist/src/core/rebase-from-version.d.ts +46 -0
  347. package/dist/src/core/rebase-from-version.js +71 -0
  348. package/dist/src/core/run-log.d.ts +26 -0
  349. package/dist/src/core/run-log.js +106 -4
  350. package/dist/src/core/run-profile.d.ts +7 -0
  351. package/dist/src/core/run-profile.js +7 -1
  352. package/dist/src/core/smoke-patterns.d.ts +5 -0
  353. package/dist/src/core/smoke-patterns.js +13 -0
  354. package/dist/src/core/test-harness-crash.d.ts +19 -1
  355. package/dist/src/core/test-harness-crash.js +8 -9
  356. package/dist/src/core/test-harness-signature.d.ts +33 -0
  357. package/dist/src/core/test-harness-signature.js +23 -1
  358. package/dist/src/core/test-raw-log.d.ts +66 -0
  359. package/dist/src/core/test-raw-log.js +122 -0
  360. package/dist/src/core/test-run-completeness.d.ts +90 -0
  361. package/dist/src/core/test-run-completeness.js +184 -0
  362. package/dist/src/core/test-stale-check.d.ts +27 -1
  363. package/dist/src/core/test-stale-check.js +39 -49
  364. package/dist/src/core/test-stale-exempt.d.ts +40 -0
  365. package/dist/src/core/test-stale-exempt.js +70 -0
  366. package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
  367. package/dist/src/core/test-xpcshell-retry.js +2 -1
  368. package/dist/src/core/token-lint.d.ts +53 -0
  369. package/dist/src/core/token-lint.js +131 -0
  370. package/dist/src/core/token-sibling-sheets.d.ts +46 -0
  371. package/dist/src/core/token-sibling-sheets.js +119 -0
  372. package/dist/src/core/tree-guard.js +5 -0
  373. package/dist/src/core/typecheck-shim.d.ts +6 -2
  374. package/dist/src/core/typecheck-shim.js +205 -4
  375. package/dist/src/core/typecheck.js +3 -1
  376. package/dist/src/index.d.ts +14 -3
  377. package/dist/src/index.js +6 -1
  378. package/dist/src/types/commands/index.d.ts +2 -2
  379. package/dist/src/types/commands/options.d.ts +212 -24
  380. package/dist/src/types/commands/patches.d.ts +118 -1
  381. package/dist/src/types/config.d.ts +264 -0
  382. package/dist/src/types/config.js +9 -0
  383. package/dist/src/types/furnace.d.ts +63 -1
  384. package/dist/src/types/furnace.js +7 -0
  385. package/dist/src/types/index.d.ts +1 -1
  386. package/dist/src/utils/options.d.ts +36 -7
  387. package/dist/src/utils/options.js +94 -8
  388. package/dist/src/utils/path-glob.d.ts +15 -0
  389. package/dist/src/utils/path-glob.js +47 -0
  390. package/dist/src/utils/regex.d.ts +15 -3
  391. package/dist/src/utils/regex.js +37 -16
  392. package/docs/configuration.md +369 -11
  393. package/docs/exit-codes.md +18 -1
  394. package/docs/furnace.md +139 -3
  395. package/docs/lifecycle-invariants.md +65 -30
  396. package/docs/machine-output.md +120 -12
  397. package/docs/patch-workflow.md +458 -22
  398. package/docs/run-logs.md +20 -1
  399. package/docs/testing.md +346 -21
  400. package/package.json +3 -3
@@ -121,6 +121,105 @@ function assertPolicyRangesDoNotOverlap(ranges, label) {
121
121
  }
122
122
  }
123
123
  }
124
+ function parseNonEmptyString(raw, label) {
125
+ if (typeof raw !== 'string' || raw.trim() === '') {
126
+ throw new ConfigError(`Config field "${label}" must be a non-empty string`);
127
+ }
128
+ return raw;
129
+ }
130
+ function parseGlobList(raw, label) {
131
+ if (!Array.isArray(raw) || raw.length === 0) {
132
+ throw new ConfigError(`Config field "${label}" must be a non-empty array of path globs`);
133
+ }
134
+ return raw.map((entry, index) => parseNonEmptyString(entry, `${label}[${index}]`));
135
+ }
136
+ function parseUpstreamAllowEntry(raw, label, defaultMarker) {
137
+ if (typeof raw === 'string')
138
+ return parseNonEmptyString(raw, label);
139
+ let rec;
140
+ try {
141
+ rec = parseObject(raw, label);
142
+ }
143
+ catch {
144
+ throw new ConfigError(`Config field "${label}" must be a path glob or an object`);
145
+ }
146
+ const entry = {
147
+ path: parseNonEmptyString(rec.raw('path'), `${label}.path`),
148
+ };
149
+ const addOnly = rec.raw('addOnly');
150
+ if (addOnly !== undefined) {
151
+ if (typeof addOnly !== 'boolean') {
152
+ throw new ConfigError(`Config field "${label}.addOnly" must be a boolean`);
153
+ }
154
+ entry.addOnly = addOnly;
155
+ }
156
+ const marker = rec.raw('marker');
157
+ if (marker !== undefined)
158
+ entry.marker = parseNonEmptyString(marker, `${label}.marker`);
159
+ if (entry.addOnly === true && entry.marker === undefined && defaultMarker === undefined) {
160
+ throw new ConfigError(`Config field "${label}" sets addOnly but no marker: set "${label}.marker" or "patchPolicy.addOnlyMarker"`);
161
+ }
162
+ return entry;
163
+ }
164
+ function parseScopeRule(raw, label) {
165
+ let rec;
166
+ try {
167
+ rec = parseObject(raw, label);
168
+ }
169
+ catch {
170
+ throw new ConfigError(`Config field "${label}" must be an object`);
171
+ }
172
+ const rule = { files: parseGlobList(rec.raw('files'), `${label}.files`) };
173
+ const category = rec.raw('category');
174
+ if (category !== undefined) {
175
+ rule.category = parsePatchPolicyCategory(category, `${label}.category`);
176
+ }
177
+ const filenamePattern = optionalConfigString(rec, 'filenamePattern', `${label}.filenamePattern`);
178
+ if (filenamePattern !== undefined) {
179
+ try {
180
+ new RegExp(filenamePattern);
181
+ }
182
+ catch (error) {
183
+ throw new ConfigError(`Config field "${label}.filenamePattern" must be a valid regular expression: ${toError(error).message}`);
184
+ }
185
+ rule.filenamePattern = filenamePattern;
186
+ }
187
+ if (rule.category === undefined && rule.filenamePattern === undefined) {
188
+ throw new ConfigError(`Config field "${label}" must set "category" or "filenamePattern" to select the patches it scopes`);
189
+ }
190
+ return rule;
191
+ }
192
+ /**
193
+ * Parses the registration-only policy fields: `upstreamAllowlist`,
194
+ * `addOnlyMarker`, `scopeRules` and `verifyDocumentPaths`. All opt-in.
195
+ */
196
+ function parsePatchPolicyContentRules(rec, out) {
197
+ const addOnlyMarker = rec.raw('addOnlyMarker');
198
+ if (addOnlyMarker !== undefined) {
199
+ out.addOnlyMarker = parseNonEmptyString(addOnlyMarker, 'patchPolicy.addOnlyMarker');
200
+ }
201
+ const allowlist = rec.raw('upstreamAllowlist');
202
+ if (allowlist !== undefined) {
203
+ if (!Array.isArray(allowlist)) {
204
+ throw new ConfigError('Config field "patchPolicy.upstreamAllowlist" must be an array');
205
+ }
206
+ out.upstreamAllowlist = allowlist.map((entry, index) => parseUpstreamAllowEntry(entry, `patchPolicy.upstreamAllowlist[${index}]`, out.addOnlyMarker));
207
+ }
208
+ const scopeRules = rec.raw('scopeRules');
209
+ if (scopeRules !== undefined) {
210
+ if (!Array.isArray(scopeRules)) {
211
+ throw new ConfigError('Config field "patchPolicy.scopeRules" must be an array');
212
+ }
213
+ out.scopeRules = scopeRules.map((entry, index) => parseScopeRule(entry, `patchPolicy.scopeRules[${index}]`));
214
+ }
215
+ const verifyDocumentPaths = rec.raw('verifyDocumentPaths');
216
+ if (verifyDocumentPaths !== undefined) {
217
+ if (typeof verifyDocumentPaths !== 'boolean') {
218
+ throw new ConfigError('Config field "patchPolicy.verifyDocumentPaths" must be a boolean');
219
+ }
220
+ out.verifyDocumentPaths = verifyDocumentPaths;
221
+ }
222
+ }
124
223
  /** Parses and validates the optional patch policy config block. */
125
224
  export function parsePatchPolicyBlock(rec) {
126
225
  const out = { ranges: [] };
@@ -170,5 +269,6 @@ export function parsePatchPolicyBlock(rec) {
170
269
  out.reservedRanges = reservedRangesRaw.map((entry, index) => parsePatchPolicyReservedRange(entry, `patchPolicy.reservedRanges[${index}]`));
171
270
  assertPolicyRangesDoNotOverlap(out.reservedRanges, 'patchPolicy.reservedRanges');
172
271
  }
272
+ parsePatchPolicyContentRules(rec, out);
173
273
  return out;
174
274
  }
@@ -52,6 +52,27 @@ export function parseTestBlock(rec, config) {
52
52
  }
53
53
  out.reapOrphans = reapOrphans;
54
54
  }
55
+ const mochitestPorts = testRec.raw('mochitestPorts');
56
+ if (mochitestPorts !== undefined) {
57
+ if (mochitestPorts !== 'fixed' && mochitestPorts !== 'auto') {
58
+ throw new ConfigError('Config field "test.mochitestPorts" must be "fixed" or "auto"');
59
+ }
60
+ out.mochitestPorts = mochitestPorts;
61
+ }
62
+ const lockMode = testRec.raw('lockMode');
63
+ if (lockMode !== undefined) {
64
+ if (lockMode !== 'exclusive' && lockMode !== 'shared') {
65
+ throw new ConfigError('Config field "test.lockMode" must be "exclusive" or "shared"');
66
+ }
67
+ out.lockMode = lockMode;
68
+ }
69
+ const furnaceApply = testRec.raw('furnaceApply');
70
+ if (furnaceApply !== undefined) {
71
+ if (furnaceApply !== 'all' && furnaceApply !== 'reached' && furnaceApply !== 'none') {
72
+ throw new ConfigError('Config field "test.furnaceApply" must be "all", "reached" or "none"');
73
+ }
74
+ out.furnaceApply = furnaceApply;
75
+ }
55
76
  config.test = out;
56
77
  }
57
78
  /** Parses optional project-specific external toolchain doctor probes. */
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Validation for `fireforge.json#patchLint.tokenScales`.
3
+ *
4
+ * Unknown keys are refused: a misspelt `allowInCalc` or `minFiles` would
5
+ * otherwise loosen or drop a scale without a word.
6
+ */
7
+ import type { PatchLintTokenScale } from '../types/config.js';
8
+ /** Parses and validates `patchLint.tokenScales`. */
9
+ export declare function parsePatchLintTokenScales(raw: unknown): PatchLintTokenScale[];
@@ -0,0 +1,92 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Validation for `fireforge.json#patchLint.tokenScales`.
4
+ *
5
+ * Unknown keys are refused: a misspelt `allowInCalc` or `minFiles` would
6
+ * otherwise loosen or drop a scale without a word.
7
+ */
8
+ import { ConfigError } from '../errors/config.js';
9
+ import { parseObject } from '../utils/parse.js';
10
+ const SCALE_KEYS = [
11
+ 'properties',
12
+ 'prefix',
13
+ 'allowLiterals',
14
+ 'allow',
15
+ 'allowInCalc',
16
+ 'offsetCap',
17
+ 'exclude',
18
+ 'minFiles',
19
+ ];
20
+ const PREFIX_PATTERN = /^--[\w-]+$/;
21
+ function parseNames(raw, label, required) {
22
+ if (raw === undefined && !required)
23
+ return undefined;
24
+ if (!Array.isArray(raw) ||
25
+ (required && raw.length === 0) ||
26
+ raw.some((value) => typeof value !== 'string' || value.trim() === '')) {
27
+ throw new ConfigError(`Config field "${label}" must be ${required ? 'a non-empty' : 'an'} array of non-empty strings`);
28
+ }
29
+ return raw;
30
+ }
31
+ function parsePrefix(raw, label) {
32
+ const prefixes = Array.isArray(raw) ? raw : [raw];
33
+ if (prefixes.length === 0 ||
34
+ prefixes.some((prefix) => typeof prefix !== 'string' || !PREFIX_PATTERN.test(prefix))) {
35
+ throw new ConfigError(`Config field "${label}.prefix" must be a custom-property prefix such as "--mybrowser-space-", or a non-empty list of them`);
36
+ }
37
+ return Array.isArray(raw) ? prefixes : raw;
38
+ }
39
+ function parseNumber(raw, label, integer) {
40
+ const valid = typeof raw === 'number' && Number.isFinite(raw) && (integer ? Number.isInteger(raw) : true);
41
+ if (!valid || raw < (integer ? 1 : 0)) {
42
+ throw new ConfigError(`Config field "${label}" must be ${integer ? 'a positive integer' : 'a non-negative number'}`);
43
+ }
44
+ return raw;
45
+ }
46
+ function parseTokenScale(raw, label) {
47
+ let rec;
48
+ try {
49
+ rec = parseObject(raw, label);
50
+ }
51
+ catch {
52
+ throw new ConfigError(`Config field "${label}" must be an object`);
53
+ }
54
+ for (const key of Object.keys(raw)) {
55
+ if (!SCALE_KEYS.includes(key)) {
56
+ throw new ConfigError(`Config field "${label}" has unknown key "${key}"`);
57
+ }
58
+ }
59
+ const properties = parseNames(rec.raw('properties'), `${label}.properties`, true) ?? [];
60
+ const scale = { properties, prefix: parsePrefix(rec.raw('prefix'), label) };
61
+ const allowLiterals = parseNames(rec.raw('allowLiterals'), `${label}.allowLiterals`, false);
62
+ if (allowLiterals !== undefined)
63
+ scale.allowLiterals = allowLiterals;
64
+ const allow = parseNames(rec.raw('allow'), `${label}.allow`, false);
65
+ if (allow !== undefined) {
66
+ const malformed = allow.find((name) => !name.startsWith('--'));
67
+ if (malformed !== undefined) {
68
+ throw new ConfigError(`Config field "${label}.allow" entries must be custom-property names starting with "--" (got "${malformed}")`);
69
+ }
70
+ scale.allow = allow;
71
+ }
72
+ const allowInCalc = parseNames(rec.raw('allowInCalc'), `${label}.allowInCalc`, false);
73
+ if (allowInCalc !== undefined)
74
+ scale.allowInCalc = allowInCalc;
75
+ const offsetCap = rec.raw('offsetCap');
76
+ if (offsetCap !== undefined)
77
+ scale.offsetCap = parseNumber(offsetCap, `${label}.offsetCap`, false);
78
+ const exclude = parseNames(rec.raw('exclude'), `${label}.exclude`, false);
79
+ if (exclude !== undefined)
80
+ scale.exclude = exclude;
81
+ const minFiles = rec.raw('minFiles');
82
+ if (minFiles !== undefined)
83
+ scale.minFiles = parseNumber(minFiles, `${label}.minFiles`, true);
84
+ return scale;
85
+ }
86
+ /** Parses and validates `patchLint.tokenScales`. */
87
+ export function parsePatchLintTokenScales(raw) {
88
+ if (!Array.isArray(raw)) {
89
+ throw new ConfigError('Config field "patchLint.tokenScales" must be an array');
90
+ }
91
+ return raw.map((entry, index) => parseTokenScale(entry, `patchLint.tokenScales[${index}]`));
92
+ }
@@ -9,9 +9,12 @@ import { isContainedRelativePath, isExplicitAbsolutePath } from '../utils/paths.
9
9
  import { describeProductVersionIncompatibility, FIREFOX_PRODUCTS, isObject, isValidAppId, isValidFirefoxCandidate, isValidFirefoxProduct, isValidFirefoxVersion, isValidProjectLicense, PROJECT_LICENSES, } from '../utils/validation.js';
10
10
  import { SUPPORTED_CONFIG_ROOT_KEYS } from './config-paths.js';
11
11
  import { parseBuildAuditConfig } from './config-validate-build-audit.js';
12
- import { parsePatchLintFileSizeThresholds } from './config-validate-file-size.js';
12
+ import { parseCheckConfig } from './config-validate-check.js';
13
+ import { parsePatchLintSizeFields } from './config-validate-file-size.js';
14
+ import { parseHistoryBlock } from './config-validate-history.js';
13
15
  import { parsePatchPolicyBlock } from './config-validate-patch-policy.js';
14
16
  import { parseExternalToolchainsBlock, parseTestBlock } from './config-validate-test-toolchains.js';
17
+ import { parsePatchLintTokenScales } from './config-validate-token-scales.js';
15
18
  /**
16
19
  * Parses and validates the four required identity fields (`name`,
17
20
  * `vendor`, `appId`, `binaryName`): all non-empty strings, with
@@ -167,6 +170,7 @@ export function validateConfig(data) {
167
170
  config.buildAudit = parseBuildAuditConfig(buildAuditRaw);
168
171
  }
169
172
  parseTestBlock(rec, config);
173
+ parseHistoryBlock(rec, config);
170
174
  parseExternalToolchainsBlock(rec, config);
171
175
  parseWireBlock(rec, config);
172
176
  parseLicenseField(rec, config);
@@ -190,6 +194,11 @@ export function validateConfig(data) {
190
194
  if (typecheckRec) {
191
195
  config.typecheck = parseTypecheckBlock(typecheckRec);
192
196
  }
197
+ // `fireforge check` policy and project steps.
198
+ const checkRaw = rec.raw('check');
199
+ if (checkRaw !== undefined) {
200
+ config.check = parseCheckConfig(checkRaw);
201
+ }
193
202
  // Warn on unknown root keys
194
203
  const knownRootKeys = new Set(SUPPORTED_CONFIG_ROOT_KEYS);
195
204
  for (const key of rec.keys()) {
@@ -372,10 +381,7 @@ function parsePatchLintBlock(rec) {
372
381
  }
373
382
  out.rawColorAllowlist = rawColorAllowlist;
374
383
  }
375
- const fileSizeThresholds = rec.raw('fileSizeThresholds');
376
- if (fileSizeThresholds !== undefined) {
377
- out.fileSizeThresholds = parsePatchLintFileSizeThresholds(fileSizeThresholds);
378
- }
384
+ Object.assign(out, parsePatchLintSizeFields((key) => rec.raw(key)));
379
385
  const forwardRegistration = rec.raw('forwardRegistration');
380
386
  if (forwardRegistration !== undefined) {
381
387
  if (forwardRegistration !== 'support-files' && forwardRegistration !== 'extended') {
@@ -383,6 +389,9 @@ function parsePatchLintBlock(rec) {
383
389
  }
384
390
  out.forwardRegistration = forwardRegistration;
385
391
  }
392
+ const tokenScales = rec.raw('tokenScales');
393
+ if (tokenScales !== undefined)
394
+ out.tokenScales = parsePatchLintTokenScales(tokenScales);
386
395
  for (const key of PATCH_LINT_SEVERITY_GATE_KEYS) {
387
396
  const gate = parseSeverityGate(rec.raw(key), `patchLint.${key}`);
388
397
  if (gate !== undefined)
@@ -462,6 +471,12 @@ function parseTypecheckBlock(rec) {
462
471
  if (undefinedIdentifiers !== undefined) {
463
472
  out.undefinedIdentifiers = undefinedIdentifiers;
464
473
  }
474
+ const litTypes = rec.raw('litTypes');
475
+ if (litTypes !== undefined && typeof litTypes !== 'boolean') {
476
+ throw new ConfigError('Config field "typecheck.litTypes" must be a boolean');
477
+ }
478
+ if (litTypes !== undefined)
479
+ out.litTypes = litTypes;
465
480
  return out;
466
481
  }
467
482
  /**
@@ -54,6 +54,11 @@ export declare function writeConfig(root: string, config: FireForgeConfig): Prom
54
54
  * This is used by CLI `config --force`, where callers may intentionally write
55
55
  * keys or value shapes outside the validated FireForgeConfig schema.
56
56
  *
57
+ * An existing file is edited in place: only the values that differ from the
58
+ * document on disk are rewritten, so a one-key change keeps the file's
59
+ * formatting (compact objects and arrays, indentation, key order) and stays
60
+ * a one-hunk diff. A missing or unparseable file is written in full.
61
+ *
57
62
  * Individual writes are atomic via {@link writeJson} (temp file + rename),
58
63
  * but atomicity alone does not prevent lost updates across concurrent
59
64
  * writers: each writer reads an old copy, mutates its own in-memory view,
@@ -16,6 +16,7 @@ import { isObject } from '../utils/validation.js';
16
16
  import { getProjectPaths } from './config-paths.js';
17
17
  import { validateConfig } from './config-validate.js';
18
18
  import { createSiblingLockPath, withFileLock } from './file-lock.js';
19
+ import { rewriteJsonPreservingFormat } from './json-preserving-edit.js';
19
20
  // ---- re-exports ----
20
21
  export { mutateConfig } from './config-mutate.js';
21
22
  export { FIREFORGE_DIR, getProjectPaths, SUPPORTED_CONFIG_PATHS, SUPPORTED_CONFIG_ROOT_KEYS, } from './config-paths.js';
@@ -109,6 +110,11 @@ export async function writeConfig(root, config) {
109
110
  * This is used by CLI `config --force`, where callers may intentionally write
110
111
  * keys or value shapes outside the validated FireForgeConfig schema.
111
112
  *
113
+ * An existing file is edited in place: only the values that differ from the
114
+ * document on disk are rewritten, so a one-key change keeps the file's
115
+ * formatting (compact objects and arrays, indentation, key order) and stays
116
+ * a one-hunk diff. A missing or unparseable file is written in full.
117
+ *
112
118
  * Individual writes are atomic via {@link writeJson} (temp file + rename),
113
119
  * but atomicity alone does not prevent lost updates across concurrent
114
120
  * writers: each writer reads an old copy, mutates its own in-memory view,
@@ -119,6 +125,16 @@ export async function writeConfig(root, config) {
119
125
  */
120
126
  export async function writeConfigDocument(root, config) {
121
127
  const paths = getProjectPaths(root);
128
+ if (await fsUtils.pathExists(paths.config)) {
129
+ const current = await fsUtils.readText(paths.config);
130
+ // `FireForgeConfig` is plain parsed-config data, so it is a JSON object.
131
+ const edited = rewriteJsonPreservingFormat(current, config);
132
+ if (edited !== undefined) {
133
+ if (edited !== current)
134
+ await fsUtils.writeText(paths.config, edited);
135
+ return;
136
+ }
137
+ }
122
138
  await fsUtils.writeJson(paths.config, config);
123
139
  }
124
140
  /**
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Dispatch-time half of per-path coverage. A scoped build that followed a
3
+ * full build carries the full build's anchor forward instead of collapsing
4
+ * the claim to its own paths. A requested path outside the scoped list is
5
+ * then still covered while its own staging inputs are unchanged against
6
+ * that anchor, and a refusal names the inputs that did change.
7
+ */
8
+ import type { BuildBaseline } from './build-baseline-types.js';
9
+ /** A requested path no recorded claim covers, with the inputs that explain it. */
10
+ export interface UncoveredRequest {
11
+ path: string;
12
+ /** Staging inputs changed since the carried full build. Empty when unknown. */
13
+ changed: string[];
14
+ }
15
+ /**
16
+ * Re-checks the paths the scoped list does not cover against the carried
17
+ * full-build anchor. Returns the paths that stay uncovered.
18
+ *
19
+ * @param engineDir - Path to the engine directory
20
+ * @param baseline - Last successful build's baseline
21
+ * @param uncovered - Request paths outside the scoped list
22
+ * @param fullSuite - The sentinel standing for a path-less (full-suite) request
23
+ */
24
+ export declare function filterByCarriedFullCoverage(engineDir: string, baseline: BuildBaseline | undefined, uncovered: readonly string[], fullSuite: string): Promise<UncoveredRequest[]>;
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Dispatch-time half of per-path coverage. A scoped build that followed a
4
+ * full build carries the full build's anchor forward instead of collapsing
5
+ * the claim to its own paths. A requested path outside the scoped list is
6
+ * then still covered while its own staging inputs are unchanged against
7
+ * that anchor, and a refusal names the inputs that did change.
8
+ */
9
+ import { toError } from '../utils/errors.js';
10
+ import { verbose } from '../utils/logger.js';
11
+ import { collectStagingInputs, findChangedInputs, hashEngineFile, readEngineContentState, } from './coverage-records.js';
12
+ /**
13
+ * Re-checks the paths the scoped list does not cover against the carried
14
+ * full-build anchor. Returns the paths that stay uncovered.
15
+ *
16
+ * @param engineDir - Path to the engine directory
17
+ * @param baseline - Last successful build's baseline
18
+ * @param uncovered - Request paths outside the scoped list
19
+ * @param fullSuite - The sentinel standing for a path-less (full-suite) request
20
+ */
21
+ export async function filterByCarriedFullCoverage(engineDir, baseline, uncovered, fullSuite) {
22
+ const unresolved = uncovered.map((path) => ({ path, changed: [] }));
23
+ const anchor = baseline?.fullCoverageAnchor;
24
+ if (anchor === undefined || uncovered.length === 0)
25
+ return unresolved;
26
+ if ((await hashEngineFile(engineDir, 'mozconfig')) !== anchor.mozconfigHash)
27
+ return unresolved;
28
+ let state;
29
+ try {
30
+ state = await readEngineContentState(engineDir);
31
+ }
32
+ catch (error) {
33
+ verbose(`Coverage check: engine state unreadable — ${toError(error).message}`);
34
+ return unresolved;
35
+ }
36
+ const remaining = [];
37
+ for (const path of uncovered) {
38
+ const inputs = path === fullSuite ? undefined : await collectStagingInputs(engineDir, path);
39
+ const changed = await findChangedInputs(state, anchor, inputs);
40
+ if (changed === undefined || changed.length > 0)
41
+ remaining.push({ path, changed: changed ?? [] });
42
+ }
43
+ return remaining;
44
+ }
@@ -1,62 +1,87 @@
1
1
  /**
2
- * Retains prior test staging only when HEAD, mozconfig and every recorded
3
- * dirty input outside the newly rebuilt scope are unchanged. Complete
4
- * input fingerprints are required: packageable-only legacy records cannot
2
+ * Decides which earlier packaging claims a scoped `fireforge test --build`
3
+ * keeps. Retention is per staged path (see `coverage-records.ts`): an
4
+ * earlier path stays covered while its own staging inputs are unchanged,
5
+ * whatever moved elsewhere in the engine, and a full claim narrows to
6
+ * per-path checks once something outside the new scope changed instead of
7
+ * collapsing to this build's paths. `--extend-coverage` turns any drop into
8
+ * a refusal before the build.
9
+ *
10
+ * Fingerprints must be complete: a legacy packageable-only record cannot
5
11
  * prove that a test fixture or manifest still matches its staged copy.
6
12
  */
7
- import { type BuildBaseline, type TestPackagingCoverage } from './build-baseline-types.js';
8
- /** Why `--extend-coverage` could not union onto the recorded claim. */
9
- export type ExtendAnchorReason = 'no-baseline' | 'no-fingerprints' | 'no-mozconfig-hash' | 'head-moved' | 'fingerprint-diverged' | 'mozconfig-changed';
10
- /** Outcome of an anchor check: either extend is sound, or it is refused. */
11
- export type ExtendAnchorResult = {
12
- ok: true;
13
- } | {
14
- ok: false;
15
- reason: ExtendAnchorReason;
16
- detail: string[];
17
- };
13
+ import type { BuildBaseline, CoverageAnchor, CoverageRecord, TestPackagingCoverage } from './build-baseline-types.js';
14
+ export { hashEngineFile } from './coverage-records.js';
15
+ /** What a dropped full claim is called in notices and refusals. */
16
+ export declare const FULL_CLAIM_LABEL = "full coverage";
17
+ /** An earlier claim this build cannot keep, and why. */
18
+ export interface DroppedClaim {
19
+ /** Request path, or {@link FULL_CLAIM_LABEL}. */
20
+ path: string;
21
+ /** Staging inputs whose content changed since the claim was staged. */
22
+ changed: string[];
23
+ /** Why the claim cannot be verified at all, when no input list explains it. */
24
+ reason?: string;
25
+ }
26
+ /** What a scoped build keeps of the recorded coverage. */
27
+ export interface CoverageRetentionPlan {
28
+ /** The previous claim was full and nothing outside this build's scope moved. */
29
+ keepFull: boolean;
30
+ /** Earlier per-path records kept, refreshed for this build's paths. */
31
+ retained: Record<string, CoverageRecord>;
32
+ /** Full-build anchor carried for dispatch-time per-path checks. */
33
+ fullAnchor: CoverageAnchor | undefined;
34
+ /** Changed inputs that narrowed a full claim to per-path checks. */
35
+ narrowedBy: string[];
36
+ /** Earlier claims this build cannot keep. */
37
+ dropped: DroppedClaim[];
38
+ }
39
+ /** The baseline-wide anchor a baseline's own fields describe, when complete. */
40
+ export declare function baselineAnchor(baseline: BuildBaseline): CoverageAnchor | undefined;
18
41
  /**
19
- * Verifies the parts of the anchor knowable before the build runs: a usable
20
- * previous baseline, an unchanged engine HEAD, and byte-identical content
21
- * for every path that baseline fingerprinted.
42
+ * Plans which earlier claims a scoped build over `requested` keeps. Runs
43
+ * before the build lock, so a refusal costs neither build time nor the
44
+ * lock. The mozconfig half runs later, via {@link applyMozconfigAnchor}.
45
+ *
22
46
  * @param engineDir - Path to the engine directory
23
- * @param previousBaseline - Baseline recorded by the previous build
47
+ * @param previous - Baseline recorded by the previous build
48
+ * @param requested - Normalized request paths this build packages
24
49
  */
25
- export declare function checkExtendCoverageAnchor(engineDir: string, previousBaseline: BuildBaseline | undefined, rebuiltPaths?: readonly string[]): Promise<ExtendAnchorResult>;
50
+ export declare function planCoverageRetention(engineDir: string, previous: BuildBaseline | undefined, requested: string[]): Promise<CoverageRetentionPlan>;
26
51
  /**
27
- * Verifies the mozconfig half of the anchor. Split from
28
- * {@link checkExtendCoverageAnchor} because it can only run after
29
- * `prepareBuildEnvironment` regenerates `engine/mozconfig` (the file this
30
- * build will configure with), and must still run before mach, so a refusal
31
- * costs no build time.
52
+ * Applies the mozconfig half of the anchor: a claim staged under a different
53
+ * `engine/mozconfig` is dropped. Runs after `prepareBuildEnvironment`
54
+ * regenerated the file this build configures with, and before mach.
55
+ *
32
56
  * @param engineDir - Path to the engine directory
33
- * @param previousBaseline - Baseline recorded by the previous build
57
+ * @param plan - Plan from {@link planCoverageRetention}
34
58
  */
35
- export declare function checkExtendMozconfigAnchor(engineDir: string, previousBaseline: BuildBaseline | undefined): Promise<ExtendAnchorResult>;
59
+ export declare function applyMozconfigAnchor(engineDir: string, plan: CoverageRetentionPlan): Promise<CoverageRetentionPlan>;
60
+ /** Fields a scoped build writes onto its baseline. */
61
+ export interface RecordedCoverage {
62
+ testPackagingCoverage: TestPackagingCoverage;
63
+ testCoverageRecords?: Record<string, CoverageRecord>;
64
+ fullCoverageAnchor?: CoverageAnchor;
65
+ }
36
66
  /**
37
- * Unions the newly built paths onto the recorded claim. A `'full'` claim, or
38
- * an absent one (which means full), stays `'full'`, since it already covers
39
- * everything.
67
+ * The coverage a green scoped build records: `'full'` when the plan kept a
68
+ * full claim, otherwise this build's paths with fresh records plus every
69
+ * retained earlier path, and the carried full anchor.
40
70
  *
41
- * @param previous - Coverage recorded by the previous build
71
+ * @param engineDir - Path to the engine directory
72
+ * @param plan - Plan after {@link applyMozconfigAnchor}
42
73
  * @param requested - Normalized request paths this build packaged
43
74
  */
44
- export declare function unionTestPackagingCoverage(previous: TestPackagingCoverage | undefined, requested: readonly string[]): TestPackagingCoverage;
75
+ export declare function recordScopedCoverage(engineDir: string, plan: CoverageRetentionPlan, requested: string[]): Promise<RecordedCoverage>;
76
+ /** Renders one dropped claim with its cause. */
77
+ export declare function describeDroppedClaim(claim: DroppedClaim): string;
45
78
  /**
46
- * Renders the fail-closed refusal for an anchor check that did not pass.
47
- * Kept separate from the probes so tests can assert the structured result
48
- * without matching copy.
49
- * @param result - Failing result from an anchor check
79
+ * The notice a scoped build prints about earlier coverage, or undefined
80
+ * when nothing was dropped or narrowed.
50
81
  */
51
- export declare function formatExtendCoverageRefusal(result: {
52
- reason: ExtendAnchorReason;
53
- detail: string[];
54
- }): string;
82
+ export declare function formatCoverageRetentionNotice(plan: CoverageRetentionPlan): string | undefined;
55
83
  /**
56
- * Hex-encoded SHA-256 of an engine-relative file, matching the digest the
57
- * baseline writer produces. `undefined` on any IO error, which every caller
58
- * treats as "cannot prove unchanged", i.e. a refusal.
59
- * @param engineDir - Path to the engine directory
60
- * @param relPath - Engine-relative POSIX path
84
+ * The `--extend-coverage` refusal: the flag asks that no earlier claim be
85
+ * dropped, and the plan would drop some.
61
86
  */
62
- export declare function hashEngineFile(engineDir: string, relPath: string): Promise<string | undefined>;
87
+ export declare function formatExtendCoverageRefusal(dropped: readonly DroppedClaim[]): string;