@hominis/fireforge 0.49.2 → 0.50.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 (334) hide show
  1. package/CHANGELOG.md +40 -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 +28 -0
  10. package/dist/src/commands/check-report.js +78 -0
  11. package/dist/src/commands/check-run.d.ts +28 -0
  12. package/dist/src/commands/check-run.js +104 -0
  13. package/dist/src/commands/check-steps.d.ts +67 -0
  14. package/dist/src/commands/check-steps.js +175 -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/doctor-engine-eslint.js +6 -1
  19. package/dist/src/commands/doctor-source-pin.js +4 -1
  20. package/dist/src/commands/export-adopt-check.d.ts +38 -0
  21. package/dist/src/commands/export-adopt-check.js +98 -0
  22. package/dist/src/commands/export-flow.js +29 -14
  23. package/dist/src/commands/export-placement-gate.d.ts +6 -2
  24. package/dist/src/commands/export-shared.d.ts +2 -1
  25. package/dist/src/commands/export-staged-registration.d.ts +46 -0
  26. package/dist/src/commands/export-staged-registration.js +91 -0
  27. package/dist/src/commands/forward-import-remedy.d.ts +32 -0
  28. package/dist/src/commands/forward-import-remedy.js +63 -0
  29. package/dist/src/commands/furnace/apply.js +3 -3
  30. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
  31. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  32. package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
  33. package/dist/src/commands/furnace/chrome-doc.js +2 -2
  34. package/dist/src/commands/furnace/create.js +2 -2
  35. package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
  36. package/dist/src/commands/furnace/deploy-named.js +107 -0
  37. package/dist/src/commands/furnace/deploy.d.ts +3 -2
  38. package/dist/src/commands/furnace/deploy.js +50 -86
  39. package/dist/src/commands/furnace/diff.js +26 -3
  40. package/dist/src/commands/furnace/index.js +66 -41
  41. package/dist/src/commands/furnace/init.js +13 -6
  42. package/dist/src/commands/furnace/override.js +4 -2
  43. package/dist/src/commands/furnace/preview.js +4 -3
  44. package/dist/src/commands/furnace/refresh.js +2 -2
  45. package/dist/src/commands/furnace/remove.js +4 -3
  46. package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
  47. package/dist/src/commands/furnace/rename-dry-run.js +127 -0
  48. package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
  49. package/dist/src/commands/furnace/rename-helpers.js +15 -1
  50. package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
  51. package/dist/src/commands/furnace/rename-registrations.js +93 -0
  52. package/dist/src/commands/furnace/rename.d.ts +2 -1
  53. package/dist/src/commands/furnace/rename.js +28 -66
  54. package/dist/src/commands/furnace/scan.d.ts +9 -4
  55. package/dist/src/commands/furnace/scan.js +11 -9
  56. package/dist/src/commands/furnace/sync.js +3 -2
  57. package/dist/src/commands/furnace/validate-report.d.ts +45 -0
  58. package/dist/src/commands/furnace/validate-report.js +91 -0
  59. package/dist/src/commands/furnace/validate.d.ts +1 -1
  60. package/dist/src/commands/furnace/validate.js +127 -114
  61. package/dist/src/commands/furnace/validation-output.js +14 -3
  62. package/dist/src/commands/lint-per-patch.js +31 -60
  63. package/dist/src/commands/lint-report.d.ts +8 -4
  64. package/dist/src/commands/lint-report.js +15 -5
  65. package/dist/src/commands/lint.js +15 -34
  66. package/dist/src/commands/manifest.js +2 -0
  67. package/dist/src/commands/patch/delete-gap-notice.js +3 -1
  68. package/dist/src/commands/patch/delete.d.ts +1 -1
  69. package/dist/src/commands/patch/delete.js +13 -98
  70. package/dist/src/commands/patch/index.d.ts +1 -1
  71. package/dist/src/commands/patch/index.js +4 -2
  72. package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
  73. package/dist/src/commands/patch/lint-ignore.js +65 -28
  74. package/dist/src/commands/patch/move-files-create.js +26 -17
  75. package/dist/src/commands/patch/move-files-into.js +5 -3
  76. package/dist/src/commands/patch/move-files.js +3 -1
  77. package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
  78. package/dist/src/commands/patch/removal-dependents.js +133 -0
  79. package/dist/src/commands/patch/rename.js +7 -0
  80. package/dist/src/commands/patch/retire.d.ts +34 -0
  81. package/dist/src/commands/patch/retire.js +128 -0
  82. package/dist/src/commands/patch/split-plan.d.ts +7 -7
  83. package/dist/src/commands/patch/split-plan.js +45 -28
  84. package/dist/src/commands/patch/split-staged.d.ts +108 -0
  85. package/dist/src/commands/patch/split-staged.js +202 -0
  86. package/dist/src/commands/patch/split.d.ts +5 -0
  87. package/dist/src/commands/patch/split.js +51 -15
  88. package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
  89. package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
  90. package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
  91. package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
  92. package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
  93. package/dist/src/commands/patch/staged-dependency-from.js +108 -0
  94. package/dist/src/commands/patch/staged-dependency.js +14 -41
  95. package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
  96. package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
  97. package/dist/src/commands/re-export-adjacent.d.ts +45 -2
  98. package/dist/src/commands/re-export-adjacent.js +156 -37
  99. package/dist/src/commands/re-export-drift.d.ts +36 -8
  100. package/dist/src/commands/re-export-drift.js +73 -49
  101. package/dist/src/commands/re-export-files.js +11 -8
  102. package/dist/src/commands/re-export-lint.d.ts +2 -1
  103. package/dist/src/commands/re-export-lint.js +23 -10
  104. package/dist/src/commands/re-export-options.js +45 -4
  105. package/dist/src/commands/re-export-preflight.d.ts +23 -0
  106. package/dist/src/commands/re-export-preflight.js +160 -0
  107. package/dist/src/commands/re-export-register.js +42 -17
  108. package/dist/src/commands/re-export-removed.d.ts +12 -1
  109. package/dist/src/commands/re-export-removed.js +41 -11
  110. package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
  111. package/dist/src/commands/re-export-scan-owner.js +116 -0
  112. package/dist/src/commands/re-export-scan.d.ts +17 -9
  113. package/dist/src/commands/re-export-scan.js +56 -23
  114. package/dist/src/commands/re-export-single.js +22 -6
  115. package/dist/src/commands/re-export-summary.d.ts +28 -0
  116. package/dist/src/commands/re-export-summary.js +36 -0
  117. package/dist/src/commands/re-export.js +37 -24
  118. package/dist/src/commands/rebase/index.js +17 -17
  119. package/dist/src/commands/run.js +16 -2
  120. package/dist/src/commands/status-check.d.ts +55 -16
  121. package/dist/src/commands/status-check.js +92 -37
  122. package/dist/src/commands/status-json.d.ts +22 -9
  123. package/dist/src/commands/status-json.js +47 -32
  124. package/dist/src/commands/status-output.js +3 -1
  125. package/dist/src/commands/status-scope.d.ts +37 -0
  126. package/dist/src/commands/status-scope.js +54 -0
  127. package/dist/src/commands/status.js +66 -23
  128. package/dist/src/commands/test-browser-preflight.js +19 -3
  129. package/dist/src/commands/test-build-furnace.d.ts +21 -0
  130. package/dist/src/commands/test-build-furnace.js +48 -0
  131. package/dist/src/commands/test-build-phase.js +47 -41
  132. package/dist/src/commands/test-checkjs.js +7 -0
  133. package/dist/src/commands/test-diagnose.js +7 -0
  134. package/dist/src/commands/test-modes.d.ts +16 -1
  135. package/dist/src/commands/test-modes.js +24 -1
  136. package/dist/src/commands/test-multi-verdict.d.ts +61 -0
  137. package/dist/src/commands/test-multi-verdict.js +111 -0
  138. package/dist/src/commands/test-orchestrate.d.ts +43 -0
  139. package/dist/src/commands/test-orchestrate.js +222 -0
  140. package/dist/src/commands/test-perf-scope.d.ts +29 -0
  141. package/dist/src/commands/test-perf-scope.js +83 -0
  142. package/dist/src/commands/test-prelock.d.ts +51 -0
  143. package/dist/src/commands/test-prelock.js +177 -0
  144. package/dist/src/commands/test-register.js +54 -10
  145. package/dist/src/commands/test-run.js +4 -1
  146. package/dist/src/commands/test-stale-gate.js +57 -27
  147. package/dist/src/commands/test-verdict.d.ts +10 -1
  148. package/dist/src/commands/test-verdict.js +28 -1
  149. package/dist/src/commands/test.d.ts +6 -1
  150. package/dist/src/commands/test.js +66 -60
  151. package/dist/src/commands/token-lint.d.ts +14 -0
  152. package/dist/src/commands/token-lint.js +111 -0
  153. package/dist/src/commands/token.js +10 -0
  154. package/dist/src/commands/verify-scope.d.ts +28 -0
  155. package/dist/src/commands/verify-scope.js +67 -0
  156. package/dist/src/commands/verify.d.ts +10 -2
  157. package/dist/src/commands/verify.js +59 -35
  158. package/dist/src/core/build-baseline-types.d.ts +46 -0
  159. package/dist/src/core/build-baseline-validate.js +19 -0
  160. package/dist/src/core/build-baseline.d.ts +5 -1
  161. package/dist/src/core/build-baseline.js +3 -1
  162. package/dist/src/core/build-overwrite-guard.d.ts +50 -0
  163. package/dist/src/core/build-overwrite-guard.js +84 -4
  164. package/dist/src/core/build-prepare.d.ts +7 -0
  165. package/dist/src/core/build-prepare.js +14 -8
  166. package/dist/src/core/build-run-record.d.ts +74 -0
  167. package/dist/src/core/build-run-record.js +136 -0
  168. package/dist/src/core/checkjs-support-heads.d.ts +41 -0
  169. package/dist/src/core/checkjs-support-heads.js +104 -0
  170. package/dist/src/core/config-paths.d.ts +2 -2
  171. package/dist/src/core/config-paths.js +8 -0
  172. package/dist/src/core/config-validate-check.d.ts +8 -0
  173. package/dist/src/core/config-validate-check.js +143 -0
  174. package/dist/src/core/config-validate-file-size.d.ts +9 -6
  175. package/dist/src/core/config-validate-file-size.js +91 -2
  176. package/dist/src/core/config-validate-history.d.ts +11 -0
  177. package/dist/src/core/config-validate-history.js +38 -0
  178. package/dist/src/core/config-validate-patch-policy.js +100 -0
  179. package/dist/src/core/config-validate-test-toolchains.js +7 -0
  180. package/dist/src/core/config-validate-token-scales.d.ts +6 -0
  181. package/dist/src/core/config-validate-token-scales.js +50 -0
  182. package/dist/src/core/config-validate.js +14 -5
  183. package/dist/src/core/config.d.ts +5 -0
  184. package/dist/src/core/config.js +16 -0
  185. package/dist/src/core/coverage-dispatch.d.ts +24 -0
  186. package/dist/src/core/coverage-dispatch.js +44 -0
  187. package/dist/src/core/coverage-extend.d.ts +70 -45
  188. package/dist/src/core/coverage-extend.js +199 -144
  189. package/dist/src/core/coverage-records.d.ts +97 -0
  190. package/dist/src/core/coverage-records.js +350 -0
  191. package/dist/src/core/destructive.d.ts +7 -4
  192. package/dist/src/core/destructive.js +10 -10
  193. package/dist/src/core/engine-session-lock.d.ts +10 -1
  194. package/dist/src/core/engine-session-lock.js +28 -8
  195. package/dist/src/core/export-moved-code-shape.d.ts +49 -11
  196. package/dist/src/core/export-moved-code-shape.js +135 -44
  197. package/dist/src/core/file-lock-queue.d.ts +67 -0
  198. package/dist/src/core/file-lock-queue.js +221 -0
  199. package/dist/src/core/file-lock.d.ts +4 -25
  200. package/dist/src/core/file-lock.js +105 -138
  201. package/dist/src/core/furnace-apply-output.d.ts +10 -0
  202. package/dist/src/core/furnace-apply-output.js +31 -1
  203. package/dist/src/core/furnace-apply.js +12 -2
  204. package/dist/src/core/furnace-composed-source.d.ts +76 -0
  205. package/dist/src/core/furnace-composed-source.js +167 -0
  206. package/dist/src/core/furnace-config-validate-exceptions.d.ts +9 -0
  207. package/dist/src/core/furnace-config-validate-exceptions.js +71 -0
  208. package/dist/src/core/furnace-config-validate.js +8 -0
  209. package/dist/src/core/furnace-css-fragments.d.ts +10 -0
  210. package/dist/src/core/furnace-css-fragments.js +26 -0
  211. package/dist/src/core/furnace-operation.d.ts +3 -3
  212. package/dist/src/core/furnace-registration-remove.d.ts +22 -1
  213. package/dist/src/core/furnace-registration-remove.js +53 -17
  214. package/dist/src/core/furnace-registration-rename.d.ts +26 -0
  215. package/dist/src/core/furnace-registration-rename.js +77 -0
  216. package/dist/src/core/furnace-registration.d.ts +14 -4
  217. package/dist/src/core/furnace-registration.js +44 -10
  218. package/dist/src/core/furnace-staleness.d.ts +7 -0
  219. package/dist/src/core/furnace-staleness.js +34 -24
  220. package/dist/src/core/furnace-validate-accessibility.d.ts +4 -2
  221. package/dist/src/core/furnace-validate-accessibility.js +10 -1
  222. package/dist/src/core/furnace-validate-exceptions.d.ts +40 -0
  223. package/dist/src/core/furnace-validate-exceptions.js +43 -0
  224. package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
  225. package/dist/src/core/furnace-validate-icon-button.js +49 -0
  226. package/dist/src/core/furnace-validate.js +1 -1
  227. package/dist/src/core/harness-port-fallback.d.ts +60 -0
  228. package/dist/src/core/harness-port-fallback.js +96 -0
  229. package/dist/src/core/history-log-file.d.ts +61 -0
  230. package/dist/src/core/history-log-file.js +157 -0
  231. package/dist/src/core/history-log.d.ts +2 -1
  232. package/dist/src/core/history-log.js +2 -1
  233. package/dist/src/core/json-preserving-edit.d.ts +22 -0
  234. package/dist/src/core/json-preserving-edit.js +199 -0
  235. package/dist/src/core/mach.js +8 -1
  236. package/dist/src/core/negative-control-diff.d.ts +39 -0
  237. package/dist/src/core/negative-control-diff.js +136 -0
  238. package/dist/src/core/negative-control.d.ts +138 -0
  239. package/dist/src/core/negative-control.js +356 -0
  240. package/dist/src/core/objdir-install-manifests.d.ts +73 -0
  241. package/dist/src/core/objdir-install-manifests.js +226 -0
  242. package/dist/src/core/patch-export-update.d.ts +2 -0
  243. package/dist/src/core/patch-export-update.js +1 -0
  244. package/dist/src/core/patch-export.js +3 -4
  245. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +37 -0
  246. package/dist/src/core/patch-lint-checkjs-any-import.js +61 -0
  247. package/dist/src/core/patch-lint-checkjs.js +8 -11
  248. package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
  249. package/dist/src/core/patch-lint-code-lines.js +105 -0
  250. package/dist/src/core/patch-lint-cross.js +12 -4
  251. package/dist/src/core/patch-lint-css.d.ts +8 -2
  252. package/dist/src/core/patch-lint-css.js +10 -4
  253. package/dist/src/core/patch-lint-file-size.d.ts +12 -5
  254. package/dist/src/core/patch-lint-file-size.js +22 -11
  255. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +18 -0
  256. package/dist/src/core/patch-lint-forward-registration-extended.js +35 -10
  257. package/dist/src/core/patch-lint-forward-registration.js +10 -0
  258. package/dist/src/core/patch-lint-ignore.d.ts +152 -0
  259. package/dist/src/core/patch-lint-ignore.js +299 -0
  260. package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
  261. package/dist/src/core/patch-lint-size-thresholds.js +110 -0
  262. package/dist/src/core/patch-lint-size.d.ts +117 -0
  263. package/dist/src/core/patch-lint-size.js +323 -0
  264. package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
  265. package/dist/src/core/patch-lint-staged-registration.js +20 -0
  266. package/dist/src/core/patch-lint-token-scale.d.ts +39 -0
  267. package/dist/src/core/patch-lint-token-scale.js +109 -0
  268. package/dist/src/core/patch-lint.d.ts +11 -83
  269. package/dist/src/core/patch-lint.js +64 -286
  270. package/dist/src/core/patch-lock.js +7 -6
  271. package/dist/src/core/patch-manifest-consistency.js +7 -6
  272. package/dist/src/core/patch-manifest-io.d.ts +6 -3
  273. package/dist/src/core/patch-manifest-io.js +19 -8
  274. package/dist/src/core/patch-manifest-validate.js +34 -2
  275. package/dist/src/core/patch-order-legal.d.ts +25 -0
  276. package/dist/src/core/patch-order-legal.js +83 -0
  277. package/dist/src/core/patch-policy-content.d.ts +40 -0
  278. package/dist/src/core/patch-policy-content.js +216 -0
  279. package/dist/src/core/patch-policy.d.ts +16 -3
  280. package/dist/src/core/patch-policy.js +16 -9
  281. package/dist/src/core/patch-retired.d.ts +35 -0
  282. package/dist/src/core/patch-retired.js +54 -0
  283. package/dist/src/core/patch-subset.d.ts +16 -0
  284. package/dist/src/core/patch-subset.js +66 -0
  285. package/dist/src/core/preflight-wait.d.ts +20 -0
  286. package/dist/src/core/preflight-wait.js +38 -0
  287. package/dist/src/core/rebase-from-version.d.ts +46 -0
  288. package/dist/src/core/rebase-from-version.js +71 -0
  289. package/dist/src/core/run-log.d.ts +20 -0
  290. package/dist/src/core/run-log.js +89 -3
  291. package/dist/src/core/run-profile.d.ts +7 -0
  292. package/dist/src/core/run-profile.js +7 -1
  293. package/dist/src/core/smoke-patterns.d.ts +5 -0
  294. package/dist/src/core/smoke-patterns.js +13 -0
  295. package/dist/src/core/test-harness-crash.d.ts +18 -1
  296. package/dist/src/core/test-harness-crash.js +6 -4
  297. package/dist/src/core/test-harness-signature.d.ts +17 -0
  298. package/dist/src/core/test-harness-signature.js +4 -0
  299. package/dist/src/core/test-run-completeness.d.ts +57 -0
  300. package/dist/src/core/test-run-completeness.js +144 -0
  301. package/dist/src/core/test-stale-check.d.ts +27 -1
  302. package/dist/src/core/test-stale-check.js +39 -49
  303. package/dist/src/core/test-stale-exempt.d.ts +40 -0
  304. package/dist/src/core/test-stale-exempt.js +70 -0
  305. package/dist/src/core/token-lint.d.ts +50 -0
  306. package/dist/src/core/token-lint.js +126 -0
  307. package/dist/src/core/tree-guard.js +3 -0
  308. package/dist/src/core/typecheck-shim.d.ts +1 -1
  309. package/dist/src/core/typecheck-shim.js +90 -2
  310. package/dist/src/index.d.ts +8 -3
  311. package/dist/src/index.js +3 -1
  312. package/dist/src/types/commands/index.d.ts +2 -2
  313. package/dist/src/types/commands/options.d.ts +148 -21
  314. package/dist/src/types/commands/patches.d.ts +75 -1
  315. package/dist/src/types/config.d.ts +192 -0
  316. package/dist/src/types/config.js +9 -0
  317. package/dist/src/types/furnace.d.ts +43 -1
  318. package/dist/src/types/furnace.js +7 -0
  319. package/dist/src/types/index.d.ts +1 -1
  320. package/dist/src/utils/options.d.ts +34 -6
  321. package/dist/src/utils/options.js +86 -5
  322. package/dist/src/utils/path-glob.d.ts +15 -0
  323. package/dist/src/utils/path-glob.js +47 -0
  324. package/dist/src/utils/regex.d.ts +15 -3
  325. package/dist/src/utils/regex.js +37 -16
  326. package/docs/configuration.md +282 -9
  327. package/docs/exit-codes.md +18 -1
  328. package/docs/furnace.md +97 -3
  329. package/docs/lifecycle-invariants.md +52 -19
  330. package/docs/machine-output.md +74 -12
  331. package/docs/patch-workflow.md +297 -22
  332. package/docs/run-logs.md +20 -1
  333. package/docs/testing.md +276 -20
  334. package/package.json +1 -1
@@ -37,8 +37,85 @@ directories. The manifest is JSON:
37
37
  The command can be dry-run, refuses ambiguous ownership, and reports each
38
38
  file-to-patch assignment before refreshing the patch.
39
39
 
40
- `re-export` without a scan previews drift. `--refuse-foreign-drift --expect
41
- <path>` restricts it to the files you intended.
40
+ To adopt files into several patches in one call, name each file's owner
41
+ with `--scan-file <patch>:<path>`. A call with more than one target patch
42
+ requires the prefix on every `--scan-file`. Selected patches that get no
43
+ file refresh scan-less, without a broad directory scan:
44
+
45
+ ```sh
46
+ fireforge re-export 201 200 --scan --scan-file 201:browser/components/hominis/tiles/scroll.mjs --refuse-foreign-drift --expect browser/base/content/hominis.js --expect browser/base/jar.mn
47
+ ```
48
+
49
+ ### Foreign drift
50
+
51
+ Every `re-export` previews drift. For each file a patch already owns, it
52
+ compares the refreshed body with the old one and lists the lines the engine
53
+ file gained or lost since the last export (`+2 added / -1 removed`). Both
54
+ directions count, so an edit that only deletes lines is drift too.
55
+ `--refuse-foreign-drift` turns the preview into a refusal. `--expect <path>`
56
+ admits drift in the files you meant to change. Drift in any other owned
57
+ file, added or removed, still refuses.
58
+
59
+ The belt works beside `--scan`, `--scan-file` and `--scan-files`. It guards
60
+ each patch's existing files, and the files a scan adopts count as expected,
61
+ so the call that adopts a new file can still refuse a peer's edit in the
62
+ patch's other files. It cannot combine with `--files`, which replaces the
63
+ file list outright.
64
+
65
+ The adoption gate and the plain re-export refuse a forward import of a
66
+ module a later patch creates. They also refuse a forward registration
67
+ (`patchLint.forwardRegistration`, for example a `jar.mn` line packaging that
68
+ module), in the same refusal and with the `patch staged-dependency` command
69
+ that declares it, so one declaration pass covers both.
70
+
71
+ ### Re-export belts and arguments
72
+
73
+ `--refuse-adjacent-unmanaged` refuses a patch when an unmanaged file is
74
+ adjacent to it, meaning the re-export would plausibly have to capture it:
75
+
76
+ - a changed file in the same directory as a file the patch owns, or
77
+ - a changed file named by a registration line the patch adds (a jar.mn,
78
+ moz.build or test-manifest line, `*` globs included).
79
+
80
+ A file in a sibling or nested directory is not adjacent, so a peer
81
+ session's unexported test in `test/hominis-tiles/` no longer refuses a
82
+ patch that owns `test/hominis/browser.toml`. The refusal names every file
83
+ with its anchor (`beside engine/<dir>` or `registered by engine/<carrier>`).
84
+
85
+ Three carve-outs keep the belt armed for everything they do not name. Each
86
+ requires `--refuse-adjacent-unmanaged`, and each admitted file is still
87
+ listed:
88
+
89
+ - `--expect-new <path>` names a file this session created and will adopt
90
+ with its next export. The owners of a new module's registration can
91
+ re-export first while a peer's neighbour still refuses. The path must be
92
+ changed in engine/ and owned by no patch. The run ends by naming the
93
+ export still owed, and an unmet path is a warning.
94
+ - `--expect-unmanaged <path>` records a reviewed exception that stays
95
+ unmanaged. An unmet path is a warning.
96
+ - `--adjacent-ignore <path|glob>` is a reviewed ignore list. A `*` stays
97
+ within one path segment and `**` is refused. Unmatched entries are only
98
+ noted, because the same list is reused across runs.
99
+
100
+ ```sh
101
+ fireforge re-export 102 200 --refuse-adjacent-unmanaged --refuse-foreign-drift \
102
+ --expect browser/modules/hominis/moz.build --expect-new browser/modules/hominis/HominisBangs.sys.mjs
103
+ ```
104
+
105
+ `--expect-from <file>` reads `--expect` paths from a file, one per line,
106
+ with blank lines and `#` comments ignored. Under zsh a list held in one
107
+ variable reaches FireForge as a single argument, and splitting it by hand
108
+ left every path after the first as a positional patch name.
109
+
110
+ Arguments are checked before the run queues for the engine lock: an empty
111
+ or unknown patch name, a positional that is an engine file (the refusal
112
+ points at `--expect` and `--expect-from`), a path flag whose value starts
113
+ with `-` (a flag swallowed by a value-less `--expect-unmanaged`), and an
114
+ `--expect`, `--expect-unmanaged`, `--expect-new` or `--scan-file` value that
115
+ names no changed file in engine/. The banner reads `DRY RUN` or `WRITING`.
116
+ A multi-patch run ends with one line naming the patches it wrote and those
117
+ it did not, each with its reason (`failed`, `refused: adjacent unmanaged`,
118
+ `refused: foreign drift`, `skipped`).
42
119
 
43
120
  ### Deletions
44
121
 
@@ -56,20 +133,59 @@ requested path produces no hunk. That is checked against the full requested
56
133
  list rather than the subset left after filtering, so nothing dropped upstream
57
134
  can pass as a silent success.
58
135
 
59
- An absent file originally created by a selected patch can be retired with
60
- repeatable `--expect-removed <path>` on scan-less re-export:
136
+ A file can be retired from a selected patch with repeatable
137
+ `--expect-removed <path>` on scan-less re-export. This works for an absent
138
+ file the patch created, and for an upstream file the patch modified or
139
+ deleted whose engine copy is back at HEAD:
61
140
 
62
141
  ```sh
63
142
  fireforge re-export 202 --refuse-adjacent-unmanaged --refuse-foreign-drift --expect browser/themes/shared/hominis/widgets.css --expect-removed browser/themes/shared/hominis/stop.svg
64
143
  ```
65
144
 
66
- The removal must have exactly one selected owner, be absent from disk and
67
- engine HEAD, and have a `new file mode` section in that owner's patch.
68
- Every removal is validated before writes, in dry-run too. Other paths keep
145
+ The removal must have exactly one selected owner. A patch-created file must
146
+ be absent from disk and engine HEAD, and have a `new file mode` section in
147
+ that owner's patch. An upstream file must be tracked in HEAD, match it on
148
+ disk, and have a section in that owner's patch. Without the retirement, a
149
+ scan-less re-export keeps the path in `filesAffected`, and with the belt
150
+ armed it refuses because the file's lines left the body. Every removal is
151
+ validated before writes, in dry-run too. Other paths keep
69
152
  both refusal checks; retirement grants no unmanaged or foreign-drift
70
153
  exception. Removing every file would empty the patch and requires `patch
71
- drop` instead. `--expect-removed` cannot combine with `--scan`, `--files` or
72
- `--all`.
154
+ delete` (or `patch retire`, which keeps the order number) instead.
155
+ `--expect-removed` cannot combine with `--scan`, `--files` or `--all`.
156
+
157
+ ### Forward imports and new modules
158
+
159
+ A re-export (plain or `--scan`) refused because a file imports a module a
160
+ later patch creates names the earliest legal order for exporting those
161
+ files as their own patch (free, inside the category range, and not opening
162
+ a gap under `allowGaps: false`), and prints the exact `patch
163
+ staged-dependency --add` command for each edge, with a `--reason`
164
+ placeholder.
165
+
166
+ An `export --order` (or `--before`/`--after`) refused on a new system
167
+ module that no patch registers in moz.build says "register first". When the
168
+ module's moz.build line is already in the working tree but the patch that
169
+ owns that moz.build has not exported it, the refusal prints three steps:
170
+ declare the line as a staged registration on that patch, re-run the export,
171
+ then re-export that patch. With the declaration in place and the line in the
172
+ working tree, the export is accepted, with a note to re-export the
173
+ registering patch next.
174
+
175
+ The refusal offers the adopt-then-split sequence (`re-export --scan
176
+ --scan-file`, then `patch move-files --create`) only when the new file
177
+ shares a block of at least three consecutive substantive lines with an
178
+ existing patch, quotes the matched lines, and only when adopting the files
179
+ into that patch would itself pass: it names the forward import or the hard
180
+ size limit that would refuse the adopt instead. When the only error is the
181
+ missing registration, adopt-then-split is not offered at all.
182
+
183
+ This is the route for pruning a path from a reserved-range allowlist
184
+ (`patchPolicy.reservedRanges[].allowed[].files`). Remove the path from the
185
+ allowlist, restore its engine copy, and retire it with `--expect-removed`.
186
+ The re-export policy gate checks the `filesAffected` the export will write,
187
+ and only for the patch being written, so one patch's stale row cannot fail
188
+ the other patches in the same call.
73
189
 
74
190
  ## Queue maintenance
75
191
 
@@ -80,8 +196,32 @@ Under `fireforge patch`:
80
196
  - `patch reorder` moves a patch.
81
197
  - `patch split <source> --files <paths...> --name <name>` carves files out of
82
198
  a patch into a new one as a single transaction, including staged-dependency
83
- owner rewrites, and supports `--dry-run`.
199
+ owner rewrites, and supports `--dry-run`. `patch move-files <from> <to>
200
+ --create --order <n>` does the same with the files named by `--file`.
201
+ Both keep the staged declarations in step with the move and list every
202
+ change: owners (of forward imports and registrations alike) that named
203
+ the source for a moved `creates` path are re-pointed at the new patch, a
204
+ declaration whose declaring file moved goes with it, and a declaration the
205
+ move makes unused is dropped. The patch policy, including the gap rule, is
206
+ checked before any lint runs.
84
207
  - `patch rename` also supports `--category` and `--order`.
208
+ - `patch retire <name>` removes a patch like `patch delete` (same dependency
209
+ refusal, `--dry-run` and confirmation) but keeps its order number as a
210
+ retired slot in `patches.json#retired`, so `patchPolicy.allowGaps: false`
211
+ sees no gap and no later patch is renumbered. Use it for a patch emptied by
212
+ a rename. The slot has no `.patch` file and no row in `patches`: apply,
213
+ export, lint and rebase never see it, and only the gap check counts it as
214
+ occupied. A patch that later takes the order (`export --order <n>`, a
215
+ rename or a renumber) fills the slot, which then disappears. `patch
216
+ compact` renumbers through retired slots like any other gap.
217
+ - `patch staged-dependency <name> --add --from <json-file>` adds many
218
+ declarations in one call under one lock hold. The file is a `lint
219
+ --per-patch --report` document (its findings' `stagedDeclarations` for
220
+ that patch) or a JSON array of `{ file, specifier | line, creates, owner?,
221
+ reason?, patch? }` entries; entries naming another patch are skipped, and
222
+ `--reason` fills entries without one. Every `staged-dependency` call logs
223
+ only its delta (`added` / `removed`) in the history; records written
224
+ before 0.50.0 carry the whole `before` / `after` lists instead.
85
225
 
86
226
  Every queue-mutating patch command accepts `--wait-lock [seconds]`. See
87
227
  [`configuration.md`](configuration.md#lock-waits) for how the budget
@@ -105,17 +245,37 @@ as before. Errors and warnings always print in full, and the `--report`
105
245
  JSON is the same in both modes.
106
246
 
107
247
  `lint --per-patch --report <path>` writes a machine-readable JSON report with
108
- each patch's line count, tier, active size thresholds, issues, and issues
109
- suppressed by `lintIgnore`. The size metrics (`countNonBinaryDiffLines`,
110
- `resolvePatchSizeTier`, `getPatchSizeThresholds`) are also exported on the
111
- programmatic API. So is `filesMeasuredByFileTooLarge(patchText)`, which
112
- returns the files `file-too-large` measures in a patch: the JS files it
113
- creates, and never a modified file or a new file of another kind. The rule
114
- selects its files through that same function, so an audit that uses it
115
- cannot drift from the rule.
248
+ each patch's line count, the `metric` it was counted in
249
+ (`patchLint.patchSizeMetric`: `diff` or `addedCode`), tier, active size
250
+ thresholds, issues, and issues suppressed by `lintIgnore`, plus the
251
+ cross-patch findings in `queueIssues`. A `forward-import` or
252
+ `forward-registration` finding carries the declarations that discharge it as
253
+ `stagedDeclarations`, which `patch staged-dependency --from` reads. Size-rule
254
+ issues carry the value they measured as `measurement`. The size metrics
255
+ (`countNonBinaryDiffLines`, `resolvePatchSizeTier`,
256
+ `getPatchSizeThresholds(tier, config)`) are also exported on the
257
+ programmatic API, with the file-size helpers `isTestFile`,
258
+ `resolveFileSizeThresholds` and `countCodeLines`. So is
259
+ `filesMeasuredByFileTooLarge(patchText)`, which returns the files
260
+ `file-too-large` measures in a patch: the JS files it creates, and never a
261
+ modified file or a new file of another kind. The rule selects its files
262
+ through that same function, so an audit that uses it cannot drift from the
263
+ rule.
264
+
265
+ `lint --per-patch` measures sizes on the working tree, the way export and
266
+ re-export do: each patch's diff is taken against the engine baseline from
267
+ the files in `engine/`, and `file-too-large` reads the file on disk. A test
268
+ file grown past its tier fails the lint gate while the edit is in progress,
269
+ without a re-export first. See
270
+ [`configuration.md`](configuration.md#patchlint) for the size metrics and
271
+ thresholds.
116
272
 
117
273
  Per-patch lint type-checks plain Firefox JS against a built-in
118
- Firefox-globals shim that tracks upstream WebIDL additions per release. See
274
+ Firefox-globals shim that tracks upstream WebIDL additions per release. A
275
+ `resource://` or `chrome://` import the per-patch program cannot resolve (a
276
+ module another patch creates, outside the file's program) is typed `any`;
277
+ an implicit-`any` finding in a file with such an import names it, since the
278
+ whole-tree `fireforge typecheck` sees the real type. See
119
279
  [`configuration.md`](configuration.md#patchlint) for the project hooks
120
280
  (`checkJsExtraShim`, `checkJsTestFiles`, `checkJsTestShim`).
121
281
 
@@ -123,6 +283,57 @@ For release whitespace checks, use `npm run whitespace:check`. It still
123
283
  checks source diffs while excluding the diff syntax of generated
124
284
  `patches/*.patch` files.
125
285
 
286
+ ### Linting single files
287
+
288
+ `./mach eslint <files>` needs mach's `lint` virtualenv. When that cannot be
289
+ built on the host (a pinned requirement missing from PyPI, or a host Python
290
+ the requirements do not support), no Mozilla-configured ESLint runs, and a
291
+ bare `engine/node_modules/.bin/eslint` lacks the chrome-script globals and
292
+ reports mostly noise. FireForge's own checks cover part of the gap:
293
+
294
+ - `fireforge lint <path>...` lints only the named modified engine files
295
+ (paths relative to `engine/`; a leading `engine/` is accepted, and a
296
+ directory takes its modified and untracked files). It runs the
297
+ patch-quality rules on those files' diff against HEAD, plus the checkJs
298
+ pass when `patchLint.checkJs` is on. It needs no build.
299
+ - `fireforge lint --per-patch --patches <patch>` lints one patch's queued
300
+ diff, the gate an export is held to.
301
+ - `fireforge typecheck` type-checks the configured jsconfig projects.
302
+
303
+ None of these applies Mozilla's ESLint rule set, so a file they pass can
304
+ still fail `./mach eslint` once the virtualenv builds again.
305
+
306
+ ### Size waivers with a ceiling
307
+
308
+ A bare `lintIgnore` entry (`"file-too-large"`) suppresses its rule at any
309
+ size, so a waived file can keep growing. For the measured size rules
310
+ (`file-too-large`, `large-patch-lines`, `large-patch-files`) an entry can
311
+ instead carry a ceiling:
312
+
313
+ ```json
314
+ "lintIgnore": [
315
+ "modified-file-missing-header",
316
+ { "rule": "file-too-large", "max": 1200, "reason": "Controller split tracked in #412" }
317
+ ]
318
+ ```
319
+
320
+ ```sh
321
+ fireforge patch lint-ignore 310-ui-sidebar --add file-too-large --max 1200 --reason "Controller split tracked in #412"
322
+ ```
323
+
324
+ The finding stays suppressed while its measurement (lines for the line
325
+ rules, files for `large-patch-files`) is at or below `max`, and fires at its
326
+ own severity past it, with a message naming the ceiling. Once the rule no
327
+ longer reaches its own warning band, `lint --per-patch` prints a
328
+ `lint-ignore-removable` notice naming the `patch lint-ignore --remove`
329
+ command, and the `--report` JSON carries each ceiling under
330
+ `lintIgnoreCeilings` with its current `measurement` and a `state` of
331
+ `within`, `exceeded` or `removable`. An `--add` for a rule that already has
332
+ an entry replaces it, so the same command moves a ceiling or widens it back
333
+ to a bare waiver. `export` and `re-export --lint-ignore <id>` only append
334
+ bare IDs, and never widen an existing ceiling. The manifest refuses a
335
+ ceiling on any other rule, and a second entry for the same rule.
336
+
126
337
  ## CI enforcement
127
338
 
128
339
  `fireforge status --check` exits non-zero when any unmanaged, drifted, or
@@ -131,6 +342,57 @@ conflicted file exists. `--fail-on <class,...>` tunes the policy set, and
131
342
  name the owning `patch`. `--include-ownership` adds ownership rows to JSON
132
343
  status output.
133
344
 
345
+ `ownership-conflict` is a `--fail-on` class beside the file classifications:
346
+ a path claimed by more than one patch, judged from the same rows as
347
+ `--include-ownership` (so it fails on a clean tree too). It is not in the
348
+ default set. `--allow <class,...>` names classes that never fail and removes
349
+ them from the fail set. `--fail-on-unknown` (which needs `--allow`) fails
350
+ every class present that neither list names, so a gate written today keeps
351
+ failing closed when a later FireForge adds a classification:
352
+
353
+ ```bash
354
+ npx fireforge status --json --summary \
355
+ --fail-on unmanaged,patch-owned-drift,conflict,ownership-conflict \
356
+ --allow patch-backed,branding,furnace,binary-unsupported --fail-on-unknown
357
+ ```
358
+
359
+ The JSON `check` block echoes `allow` and `failOnUnknown` when they are set,
360
+ and marks an offender that failed only through `--fail-on-unknown` with
361
+ `"unnamed": true`. Under `--check` the full `--json` payload carries the
362
+ `check` block too, not only `--summary`.
363
+
364
+ On a shared engine, `--patches <list>` judges only the named patches:
365
+ `status` keeps the files each one owns or claims (and, with `--ownership` or
366
+ the ownership checks, the rows naming it), and `verify` keeps the findings
367
+ that name it. Patches are named the way `lint --per-patch --patches` names
368
+ them (filename, stem, order number, manifest name or slug). A peer's drifted
369
+ patch then no longer turns this session's gate red. The limit is the
370
+ point: an unmanaged file belongs to no patch, so a scoped run never judges
371
+ unexported files, this session's included. Run the unscoped gate before a
372
+ commit that should cover them. `verify --patches` keeps findings about the
373
+ queue as a whole (a `patches.json` that does not parse) whatever the scope.
374
+
375
+ `fireforge check` composes the static gates into one command: `status`
376
+ (as `--json --summary --check`), `verify`, `lint --per-patch`,
377
+ `typecheck`, `furnace validate` and `token coverage`, plus the project's
378
+ `check.extraSteps[]` (see [`configuration.md`](configuration.md#check)). The
379
+ steps run in parallel as child `fireforge` processes, so each behaves exactly
380
+ as it does standalone and takes only its own locks; `check` takes none
381
+ itself. None of the built-in steps takes the engine session lock. The one
382
+ built-in step that writes, `typecheck` (it regenerates a stale Furnace
383
+ jsconfig), runs before `furnace validate`, which reads that file. `--patches`
384
+ is forwarded to status, verify and lint. `--only` and `--skip` narrow the
385
+ step list, and `--jobs <n>` caps how many run at once. The run ends with a
386
+ per-step table and one verdict line:
387
+
388
+ ```
389
+ FIREFORGE-VERDICT: PASS steps=<n> skipped=<n>
390
+ FIREFORGE-VERDICT: FAIL reason=step-failures|lock-timeout failed=<step,...> steps=<n> skipped=<n>
391
+ ```
392
+
393
+ `--json` replaces both with one document. A failed step's last 40 output
394
+ lines are printed under the table.
395
+
134
396
  The JSON shapes are specified in [`machine-output.md`](machine-output.md),
135
397
  and the codes a script should branch on in
136
398
  [`exit-codes.md`](exit-codes.md).
@@ -161,9 +423,22 @@ context` (with the step it needed) or `reject` (with the files git named).
161
423
  It exits 6 when anything rejects. A reject after an earlier one is marked
162
424
  as possibly cascading from it, since the replay continues without the
163
425
  rejected patch. Run it after the download, when HEAD is the new source. The
164
- header names the oldest patch stamp as "from", compared as versions rather
165
- than strings, prints the spread when the queue carries several stamps, and
166
- warns when `engine/` is not yet on the pinned version.
426
+ header names the previous pin as "from": `firefox.version` in the
427
+ `fireforge.json` committed at the project's HEAD, the tree the queue was
428
+ last applied to (since 0.50.0). The patch stamps follow on their own line
429
+ (`Patch stamps: 317 at 153.0esr, 5 at 153.3.0esr`), oldest first and
430
+ compared as versions rather than strings, because patches untouched since an
431
+ older hop keep their older stamp. When no committed pin precedes the target
432
+ (the project is not a repository, or the pin move is already committed), the
433
+ header falls back to the oldest stamp and says so. The header also warns
434
+ when `engine/` is not yet on the pinned version.
435
+
436
+ A source refresh replaces `engine/node_modules`, which an engine-ESLint
437
+ ratchet runs from. `fireforge doctor` warns ("Engine ESLint installed") until
438
+ it is back. Reinstall it with `cd engine && ./mach npm ci --no-audit
439
+ --no-fund`, which installs only the node dependencies. `./mach eslint
440
+ --setup` also builds mach's Python `lint` virtualenv, and that step fails
441
+ whenever a requirement it pins is no longer served by PyPI.
167
442
 
168
443
  If a patch fails, fix the reject inside `engine/`, then run
169
444
  `npx fireforge rebase --continue`. A rebase leaves the engine mutated on
package/docs/run-logs.md CHANGED
@@ -53,7 +53,8 @@ the mistake.
53
53
  - **Opened before any preflight**, so a refusal is logged too. Those are
54
54
  exactly the runs whose only output a `tail` throws away.
55
55
  - **Retained 20 deep per command kind.** Per kind, so that a busy `test` loop
56
- cannot evict the `build` log an operator needs to read beside it. Pruning
56
+ cannot evict the `build` log an operator needs to read beside it. A
57
+ `--keep-log` copy (below) is outside this count. Pruning
57
58
  runs before the new file is opened, and orders by the timestamp in the
58
59
  filename rather than by stat-ing every entry.
59
60
  - **Timestamps are filesystem-safe.** They use the ISO form with `:` and `.`
@@ -67,6 +68,24 @@ the mistake.
67
68
  active log, also best-effort, before exiting, so the held partial line of a
68
69
  killed run reaches disk.
69
70
 
71
+ ## Keeping a log past retention
72
+
73
+ Retention is shared by every session on the checkout, so on a busy shared
74
+ checkout a log a verdict line names can be pruned within the hour.
75
+ `--keep-log <path>` (on `test` and `build`) also writes the run's log to a
76
+ path of the caller's choosing, outside `.fireforge/logs/` and never pruned.
77
+ `FIREFORGE_LOG_KEEP=<path>` sets the same for every run in a session. The
78
+ flag wins over the variable. A value ending in `/` or naming an existing
79
+ directory receives the log under its own `.fireforge/logs/` file name, so a
80
+ session directory collects one file per run; any other value is the file
81
+ itself. Relative values resolve against the working directory.
82
+
83
+ The copy is written live, line for line through the same redaction, rather
84
+ than copied at the end, so a killed run keeps what it had written, exactly
85
+ as the primary log does. `log=` still names the primary. The copy is
86
+ best-effort too: if it cannot be opened, the run proceeds with the primary
87
+ alone, and if the primary cannot be opened, the copy stands in for it.
88
+
70
89
  ## Preflight refusals
71
90
 
72
91
  `fireforge test` opens its run log before any preflight, so a refusal is