@hominis/fireforge 0.50.0 → 0.52.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 (212) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/build-info.json +4 -4
  3. package/dist/src/commands/check-report.d.ts +17 -4
  4. package/dist/src/commands/check-report.js +19 -6
  5. package/dist/src/commands/check-run.d.ts +5 -0
  6. package/dist/src/commands/check-run.js +9 -1
  7. package/dist/src/commands/check-steps.d.ts +8 -0
  8. package/dist/src/commands/check-steps.js +31 -6
  9. package/dist/src/commands/check.js +1 -1
  10. package/dist/src/commands/declarations-report.d.ts +43 -0
  11. package/dist/src/commands/declarations-report.js +76 -0
  12. package/dist/src/commands/export-placement-gate.js +8 -0
  13. package/dist/src/commands/furnace/rename-registrations.js +7 -2
  14. package/dist/src/commands/furnace/validate.js +26 -1
  15. package/dist/src/commands/lint-per-patch.js +6 -2
  16. package/dist/src/commands/lint-per-run-checkjs.js +2 -2
  17. package/dist/src/commands/lint-report.js +7 -2
  18. package/dist/src/commands/manifest.js +2 -0
  19. package/dist/src/commands/park.d.ts +22 -0
  20. package/dist/src/commands/park.js +232 -0
  21. package/dist/src/commands/patch/delete.js +11 -6
  22. package/dist/src/commands/patch/index.d.ts +3 -3
  23. package/dist/src/commands/patch/index.js +8 -4
  24. package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
  25. package/dist/src/commands/patch/lint-ignore-from.js +142 -0
  26. package/dist/src/commands/patch/lint-ignore.js +39 -29
  27. package/dist/src/commands/patch/move-files-create.js +11 -4
  28. package/dist/src/commands/patch/move-files-into.js +10 -4
  29. package/dist/src/commands/patch/move-files.js +3 -1
  30. package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
  31. package/dist/src/commands/patch/removal-created-files.js +83 -0
  32. package/dist/src/commands/patch/rename.js +15 -3
  33. package/dist/src/commands/patch/reserve.d.ts +33 -0
  34. package/dist/src/commands/patch/reserve.js +152 -0
  35. package/dist/src/commands/patch/retire.js +11 -6
  36. package/dist/src/commands/patch/split-plan.d.ts +10 -1
  37. package/dist/src/commands/patch/split-plan.js +16 -1
  38. package/dist/src/commands/patch/split.js +14 -5
  39. package/dist/src/commands/patch/stage.d.ts +34 -0
  40. package/dist/src/commands/patch/stage.js +153 -0
  41. package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
  42. package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
  43. package/dist/src/commands/patch/staged-dependency.js +40 -98
  44. package/dist/src/commands/re-export-adjacent.d.ts +5 -0
  45. package/dist/src/commands/re-export-adjacent.js +4 -3
  46. package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
  47. package/dist/src/commands/re-export-bulk-scan.js +22 -7
  48. package/dist/src/commands/re-export-hunks.d.ts +35 -0
  49. package/dist/src/commands/re-export-hunks.js +220 -0
  50. package/dist/src/commands/re-export-options.js +29 -2
  51. package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
  52. package/dist/src/commands/re-export-purity-scope.js +131 -0
  53. package/dist/src/commands/re-export-register.js +15 -1
  54. package/dist/src/commands/re-export-removed.d.ts +1 -1
  55. package/dist/src/commands/re-export-removed.js +17 -2
  56. package/dist/src/commands/re-export-scan.d.ts +2 -0
  57. package/dist/src/commands/re-export-scan.js +4 -1
  58. package/dist/src/commands/re-export-single.js +102 -42
  59. package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
  60. package/dist/src/commands/re-export-stale-registrations.js +62 -0
  61. package/dist/src/commands/re-export.js +35 -34
  62. package/dist/src/commands/status-output.js +5 -1
  63. package/dist/src/commands/test-build-furnace.d.ts +3 -2
  64. package/dist/src/commands/test-build-furnace.js +8 -2
  65. package/dist/src/commands/test-build-phase.d.ts +2 -0
  66. package/dist/src/commands/test-build-phase.js +34 -17
  67. package/dist/src/commands/test-checkjs.js +3 -2
  68. package/dist/src/commands/test-dispatch.d.ts +39 -0
  69. package/dist/src/commands/test-dispatch.js +220 -0
  70. package/dist/src/commands/test-furnace-reach.d.ts +37 -0
  71. package/dist/src/commands/test-furnace-reach.js +132 -0
  72. package/dist/src/commands/test-orchestrate.d.ts +14 -0
  73. package/dist/src/commands/test-orchestrate.js +25 -4
  74. package/dist/src/commands/test-perf-scope.d.ts +21 -0
  75. package/dist/src/commands/test-perf-scope.js +55 -0
  76. package/dist/src/commands/test-prelock.js +100 -4
  77. package/dist/src/commands/test-register.js +18 -3
  78. package/dist/src/commands/test-results.d.ts +62 -0
  79. package/dist/src/commands/test-results.js +62 -0
  80. package/dist/src/commands/test-run.d.ts +13 -55
  81. package/dist/src/commands/test-run.js +73 -101
  82. package/dist/src/commands/test-shards.d.ts +110 -0
  83. package/dist/src/commands/test-shards.js +255 -0
  84. package/dist/src/commands/test-stale-gate.d.ts +5 -1
  85. package/dist/src/commands/test-stale-gate.js +11 -2
  86. package/dist/src/commands/test-verdict.d.ts +2 -1
  87. package/dist/src/commands/test.d.ts +1 -1
  88. package/dist/src/commands/test.js +68 -75
  89. package/dist/src/commands/token-lint.js +48 -8
  90. package/dist/src/commands/verify.js +9 -2
  91. package/dist/src/core/build-baseline-types.d.ts +13 -0
  92. package/dist/src/core/build-baseline-validate.js +9 -0
  93. package/dist/src/core/build-baseline.js +7 -0
  94. package/dist/src/core/build-prepare.d.ts +6 -0
  95. package/dist/src/core/build-prepare.js +29 -3
  96. package/dist/src/core/config-paths.d.ts +1 -1
  97. package/dist/src/core/config-paths.js +2 -0
  98. package/dist/src/core/config-validate-check.js +83 -7
  99. package/dist/src/core/config-validate-test-toolchains.js +14 -0
  100. package/dist/src/core/config-validate-token-scales.d.ts +3 -0
  101. package/dist/src/core/config-validate-token-scales.js +47 -5
  102. package/dist/src/core/config-validate.js +6 -0
  103. package/dist/src/core/coverage-extend.js +2 -2
  104. package/dist/src/core/coverage-records.d.ts +11 -0
  105. package/dist/src/core/coverage-records.js +34 -0
  106. package/dist/src/core/engine-session-lock.d.ts +6 -0
  107. package/dist/src/core/engine-session-lock.js +10 -2
  108. package/dist/src/core/file-lock-shared.d.ts +57 -0
  109. package/dist/src/core/file-lock-shared.js +117 -0
  110. package/dist/src/core/file-lock.d.ts +9 -0
  111. package/dist/src/core/file-lock.js +58 -2
  112. package/dist/src/core/furnace-apply.js +10 -10
  113. package/dist/src/core/furnace-config-validate-exceptions.d.ts +11 -3
  114. package/dist/src/core/furnace-config-validate-exceptions.js +59 -8
  115. package/dist/src/core/furnace-config-validate.js +7 -1
  116. package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
  117. package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
  118. package/dist/src/core/furnace-validate-accessibility.d.ts +5 -3
  119. package/dist/src/core/furnace-validate-accessibility.js +75 -30
  120. package/dist/src/core/furnace-validate-exceptions.d.ts +13 -4
  121. package/dist/src/core/furnace-validate-exceptions.js +59 -4
  122. package/dist/src/core/furnace-validate-icon-button.js +30 -1
  123. package/dist/src/core/history-log-file.js +8 -1
  124. package/dist/src/core/line-prefixer.d.ts +18 -0
  125. package/dist/src/core/line-prefixer.js +34 -0
  126. package/dist/src/core/mach.d.ts +7 -0
  127. package/dist/src/core/mach.js +24 -9
  128. package/dist/src/core/module-resolution-preflight.d.ts +19 -3
  129. package/dist/src/core/module-resolution-preflight.js +24 -6
  130. package/dist/src/core/negative-control-compiled.d.ts +36 -0
  131. package/dist/src/core/negative-control-compiled.js +87 -0
  132. package/dist/src/core/negative-control-diff.d.ts +14 -2
  133. package/dist/src/core/negative-control-diff.js +49 -6
  134. package/dist/src/core/negative-control.d.ts +12 -0
  135. package/dist/src/core/negative-control.js +48 -5
  136. package/dist/src/core/park-store.d.ts +63 -0
  137. package/dist/src/core/park-store.js +216 -0
  138. package/dist/src/core/patch-export-update.d.ts +4 -0
  139. package/dist/src/core/patch-export-update.js +12 -3
  140. package/dist/src/core/patch-export.d.ts +3 -2
  141. package/dist/src/core/patch-export.js +21 -14
  142. package/dist/src/core/patch-files.js +26 -8
  143. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +6 -4
  144. package/dist/src/core/patch-lint-checkjs-any-import.js +9 -7
  145. package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
  146. package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
  147. package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
  148. package/dist/src/core/patch-lint-checkjs.js +13 -3
  149. package/dist/src/core/patch-lint-cross.d.ts +3 -1
  150. package/dist/src/core/patch-lint-cross.js +5 -0
  151. package/dist/src/core/patch-lint-css.js +14 -10
  152. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +5 -0
  153. package/dist/src/core/patch-lint-forward-registration-extended.js +1 -1
  154. package/dist/src/core/patch-lint-ignore.d.ts +56 -12
  155. package/dist/src/core/patch-lint-ignore.js +173 -43
  156. package/dist/src/core/patch-lint-ownership.d.ts +10 -0
  157. package/dist/src/core/patch-lint-ownership.js +26 -0
  158. package/dist/src/core/patch-lint-size.js +9 -1
  159. package/dist/src/core/patch-lint-token-scale.d.ts +26 -8
  160. package/dist/src/core/patch-lint-token-scale.js +206 -29
  161. package/dist/src/core/patch-lint.js +2 -2
  162. package/dist/src/core/patch-manifest-io.js +8 -1
  163. package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
  164. package/dist/src/core/patch-manifest-key-order.js +61 -0
  165. package/dist/src/core/patch-manifest-stage.d.ts +46 -0
  166. package/dist/src/core/patch-manifest-stage.js +96 -0
  167. package/dist/src/core/patch-manifest-validate.js +27 -1
  168. package/dist/src/core/patch-order-legal.d.ts +2 -1
  169. package/dist/src/core/patch-order-legal.js +7 -2
  170. package/dist/src/core/patch-policy.d.ts +6 -2
  171. package/dist/src/core/patch-policy.js +14 -7
  172. package/dist/src/core/patch-retired.d.ts +26 -4
  173. package/dist/src/core/patch-retired.js +40 -2
  174. package/dist/src/core/run-log.d.ts +6 -0
  175. package/dist/src/core/run-log.js +17 -1
  176. package/dist/src/core/test-harness-crash.d.ts +2 -1
  177. package/dist/src/core/test-harness-crash.js +5 -8
  178. package/dist/src/core/test-harness-signature.d.ts +16 -0
  179. package/dist/src/core/test-harness-signature.js +19 -1
  180. package/dist/src/core/test-raw-log.d.ts +66 -0
  181. package/dist/src/core/test-raw-log.js +122 -0
  182. package/dist/src/core/test-run-completeness.d.ts +47 -7
  183. package/dist/src/core/test-run-completeness.js +70 -23
  184. package/dist/src/core/test-stale-check.d.ts +10 -1
  185. package/dist/src/core/test-stale-check.js +15 -1
  186. package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
  187. package/dist/src/core/test-xpcshell-retry.js +2 -1
  188. package/dist/src/core/token-lint.d.ts +5 -2
  189. package/dist/src/core/token-lint.js +8 -3
  190. package/dist/src/core/token-sibling-sheets.d.ts +46 -0
  191. package/dist/src/core/token-sibling-sheets.js +119 -0
  192. package/dist/src/core/tree-guard.js +2 -0
  193. package/dist/src/core/typecheck-shim.d.ts +6 -1
  194. package/dist/src/core/typecheck-shim.js +139 -2
  195. package/dist/src/core/typecheck.js +3 -1
  196. package/dist/src/index.d.ts +9 -3
  197. package/dist/src/index.js +4 -1
  198. package/dist/src/types/commands/index.d.ts +2 -2
  199. package/dist/src/types/commands/options.d.ts +68 -7
  200. package/dist/src/types/commands/patches.d.ts +43 -0
  201. package/dist/src/types/config.d.ts +74 -2
  202. package/dist/src/types/furnace.d.ts +29 -0
  203. package/dist/src/types/index.d.ts +1 -1
  204. package/dist/src/utils/options.d.ts +3 -2
  205. package/dist/src/utils/options.js +9 -4
  206. package/docs/configuration.md +110 -9
  207. package/docs/furnace.md +61 -1
  208. package/docs/lifecycle-invariants.md +13 -11
  209. package/docs/machine-output.md +68 -18
  210. package/docs/patch-workflow.md +174 -13
  211. package/docs/testing.md +89 -5
  212. package/package.json +3 -3
package/dist/src/index.js CHANGED
@@ -22,8 +22,11 @@ export { applyAllComponents } from './core/furnace-apply.js';
22
22
  export { ensureFurnaceConfig, loadFurnaceConfig, loadFurnaceState, saveFurnaceState, validateFurnaceConfig, } from './core/furnace-config.js';
23
23
  export { validateAllComponents, validateComponent } from './core/furnace-validate.js';
24
24
  export { countNonBinaryDiffLines, filesMeasuredByFileTooLarge, getPatchSizeThresholds, isTestFile, resolvePatchSizeTier, } from './core/patch-lint.js';
25
- export { countCodeLines } from './core/patch-lint-code-lines.js';
25
+ export { codeLineMask, countCodeLines } from './core/patch-lint-code-lines.js';
26
26
  export { resolveFileSizeThresholds } from './core/patch-lint-file-size.js';
27
+ export { measurePatchSize } from './core/patch-lint-size.js';
28
+ export { isPatchSizeRegistrationFile } from './core/patch-lint-size-thresholds.js';
29
+ export { evaluatePatchPolicyContentForQueue } from './core/patch-policy-content.js';
27
30
  export { addToken, getTokensCssPath, validateTokenAdd } from './core/token-manager.js';
28
31
  export { CancellationError, CommandError, FireForgeError, GeneralError, InvalidArgumentError, ResolutionError, } from './errors/base.js';
29
32
  export { ExitCode } from './errors/codes.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Re-exports all command-related types from focused sub-modules.
3
3
  */
4
- export type { BuildOptions, DiscardOptions, DoctorOptions, DownloadOptions, ExportOptions, FurnaceApplyOptions, FurnaceCreateOptions, FurnaceDeployOptions, FurnaceLockWaitable, FurnaceOverrideOptions, FurnacePreviewOptions, FurnaceRefreshOptions, FurnaceRemoveOptions, FurnaceRenameOptions, FurnaceSyncOptions, FurnaceValidateOptions, ImportOptions, LintCommandOptions, PackageOptions, PatchCompactOptions, PatchDeleteOptions, PatchLintIgnoreOptions, PatchMoveFilesOptions, PatchRenameOptions, PatchReorderOptions, PatchRetireOptions, PatchSplitOptions, PatchStagedDependencyOptions, PatchTierOptions, RebaseOptions, ReExportOptions, RegisterOptions, ResetOptions, RunOptions, SetupOptions, SourceSetOptions, StatusOptions, TestOptions, TokenAddOptions, WireOptions, } from './options.js';
5
- export type { ImportSummary, LintIgnoreCeiling, LintIgnoreEntry, PatchCategory, PatchesManifest, PatchInfo, PatchLintIssue, PatchLintStagedDeclaration, PatchMetadata, PatchResult, PatchRetiredSlot, PatchStagedDependencies, PatchStagedForwardImport, PatchStagedRegistration, } from './patches.js';
4
+ export type { BuildOptions, DiscardOptions, DoctorOptions, DownloadOptions, ExportOptions, FurnaceApplyOptions, FurnaceCreateOptions, FurnaceDeployOptions, FurnaceLockWaitable, FurnaceOverrideOptions, FurnacePreviewOptions, FurnaceRefreshOptions, FurnaceRemoveOptions, FurnaceRenameOptions, FurnaceSyncOptions, FurnaceValidateOptions, ImportOptions, LintCommandOptions, PackageOptions, PatchCompactOptions, PatchDeleteOptions, PatchLintIgnoreOptions, PatchMoveFilesOptions, PatchRenameOptions, PatchReorderOptions, PatchReserveOptions, PatchRetireOptions, PatchSplitOptions, PatchStagedDependencyOptions, PatchStageOptions, PatchTierOptions, RebaseOptions, ReExportOptions, RegisterOptions, ResetOptions, RunOptions, SetupOptions, SourceSetOptions, StatusOptions, TestOptions, TokenAddOptions, WireOptions, } from './options.js';
5
+ export type { ImportSummary, LintIgnoreCeiling, LintIgnoreEntry, PatchCategory, PatchesManifest, PatchInfo, PatchLintIssue, PatchLintStagedDeclaration, PatchMetadata, PatchReservedSlot, PatchResult, PatchRetiredSlot, PatchSizeShare, PatchStagedDependencies, PatchStagedForwardImport, PatchStagedRegistration, } from './patches.js';
6
6
  export type { DoctorCheck, TokenCoverageFileEntry, TokenCoverageReport } from './project.js';
@@ -2,7 +2,7 @@
2
2
  * Command option types for CLI commands.
3
3
  */
4
4
  import type { FirefoxProduct, ProjectLicense } from '../config.js';
5
- import type { PatchCategory } from './patches.js';
5
+ import type { PatchCategory, PatchSizeShare } from './patches.js';
6
6
  /**
7
7
  * `--dry-run`: print the planned change and exit without writing anything.
8
8
  *
@@ -334,8 +334,8 @@ export interface ReExportOptions extends EngineLockWaitable {
334
334
  * unmanaged files exist adjacent to the patch's ownership, instead of
335
335
  * warning. Gate-driven workflows use this so a freshly created file
336
336
  * beside a patch's owned files cannot be silently left out of the
337
- * refreshed body. Only meaningful on the plain path, and mutually
338
- * exclusive with `--scan` and `--files`, which set filesAffected
337
+ * refreshed body. Beside `--scan` it judges the neighbours the scan did
338
+ * not adopt. Mutually exclusive with `--files`, which sets filesAffected
339
339
  * explicitly.
340
340
  */
341
341
  refuseAdjacentUnmanaged?: boolean;
@@ -397,6 +397,23 @@ export interface ReExportOptions extends EngineLockWaitable {
397
397
  * back at HEAD.
398
398
  */
399
399
  expectRemoved?: string[];
400
+ /**
401
+ * Where a refused `--scan` adoption writes its one `--from`-ready
402
+ * declaration report (`--declarations-out`). Defaults to
403
+ * `.fireforge/declarations/`.
404
+ */
405
+ declarationsOut?: string;
406
+ /**
407
+ * `--hunks-from <diff>`: export each named file as the patch's current
408
+ * body plus only the hunks in this diff, leaving every other session's
409
+ * edits in the file out.
410
+ */
411
+ hunksFrom?: string;
412
+ /**
413
+ * `--exclude-hunks <diff>`: export each named file as the working tree
414
+ * minus the hunks in this diff.
415
+ */
416
+ excludeHunks?: string;
400
417
  }
401
418
  /**
402
419
  * Options for the `fireforge patch tier` subcommand. Sets or clears the
@@ -426,8 +443,15 @@ export interface PatchLintIgnoreOptions extends Confirmable, DryRunnable, PatchL
426
443
  * bare IDs. Only the measured size rules accept one. Requires `reason`.
427
444
  */
428
445
  max?: number;
429
- /** Why the ceiling exists. Required with `max`. */
446
+ /** Why the ceiling exists. Required with `max` or a `<rule>=<max>` add. */
430
447
  reason?: string;
448
+ /** With a ceiling on `large-patch-lines`: the share it bounds. */
449
+ share?: PatchSizeShare;
450
+ /**
451
+ * Add every entry in a JSON file under one lock hold: an array of
452
+ * entries, or a lint report whose ceilings for the patch are rebaselined.
453
+ */
454
+ from?: string;
431
455
  }
432
456
  /**
433
457
  * Options for the `fireforge patch staged-dependency` subcommand. Modes are
@@ -490,6 +514,8 @@ export interface PatchSplitOptions extends Confirmable, PatchLockWaitable, Unsaf
490
514
  dryRun?: boolean;
491
515
  /** Skip per-patch lint of the projected bodies. */
492
516
  skipLint?: boolean;
517
+ /** Where a refusal writes its one `--from`-ready declaration report. */
518
+ declarationsOut?: string;
493
519
  }
494
520
  /**
495
521
  * Options for the `fireforge patch move-files` subcommand. Without
@@ -513,6 +539,8 @@ export interface PatchMoveFilesOptions extends Confirmable, PatchLockWaitable, U
513
539
  dryRun?: boolean;
514
540
  /** Skip per-patch lint of the projected bodies. */
515
541
  skipLint?: boolean;
542
+ /** Where a refusal writes its one `--from`-ready declaration report. */
543
+ declarationsOut?: string;
516
544
  }
517
545
  /**
518
546
  * Options for the rebase command.
@@ -650,11 +678,12 @@ export interface TestOptions extends EngineLockWaitable {
650
678
  */
651
679
  refuseUnexportedDrift?: boolean;
652
680
  /**
653
- * `false` under `--no-furnace-apply`: the pre-test build skips the Furnace
654
- * apply and packages engine/ as it stands. Valid only with
681
+ * Which components the pre-test build deploys: `all` (default), `reached`
682
+ * (only those a requested test reaches) or `none`. `false` is
683
+ * `--no-furnace-apply`, the same as `none`. Valid only with
655
684
  * `--build`/`--build-only`.
656
685
  */
657
- furnaceApply?: boolean;
686
+ furnaceApply?: boolean | 'all' | 'reached' | 'none';
658
687
  /** Forward mach's pathless auto-selection mode. Valid only with no explicit paths. */
659
688
  auto?: boolean;
660
689
  /**
@@ -768,6 +797,17 @@ export interface TestOptions extends EngineLockWaitable {
768
797
  * engine harness's busy-port fallback. Same as `test.mochitestPorts: "auto"`.
769
798
  */
770
799
  autoPorts?: boolean;
800
+ /**
801
+ * Hold the engine session lock shared for a build-less run with auto
802
+ * ports, so peers' build-less runs overlap. Same as `test.lockMode: "shared"`.
803
+ */
804
+ sharedLock?: boolean;
805
+ /** Run shards on this many harness instances at once (requires auto ports). */
806
+ jobs?: number;
807
+ /** Dispatch n files per mach invocation, judged per file from the raw log. */
808
+ shardSize?: number;
809
+ /** Write per-file results (mozlog raw log) as JSON to this path. */
810
+ results?: string;
771
811
  }
772
812
  /**
773
813
  * Options for the furnace apply command.
@@ -984,6 +1024,8 @@ export interface RegisterOptions {
984
1024
  export interface PatchDeleteOptions extends Confirmable, DryRunnable, PatchLockWaitable {
985
1025
  /** Bypass the hard refusal when later patches depend on the target. */
986
1026
  forceUnsafe?: boolean;
1027
+ /** Also delete the engine files the patch creates that are still on disk. */
1028
+ deleteCreated?: boolean;
987
1029
  }
988
1030
  /**
989
1031
  * Options for the `fireforge patch retire` subcommand: `patch delete` that
@@ -993,6 +1035,25 @@ export interface PatchRetireOptions extends PatchDeleteOptions {
993
1035
  /** Optional human-readable rationale stored on the retired slot. */
994
1036
  reason?: string;
995
1037
  }
1038
+ /**
1039
+ * Options for the `fireforge patch stage` subcommand: stage the named
1040
+ * patches' files and only their `patches.json` rows in the project index.
1041
+ */
1042
+ export type PatchStageOptions = DryRunnable & PatchLockWaitable;
1043
+ /**
1044
+ * Options for the `fireforge patch reserve` subcommand: hold an order
1045
+ * number for a patch not exported yet, or release the hold.
1046
+ */
1047
+ export interface PatchReserveOptions extends DryRunnable, PatchLockWaitable {
1048
+ /** Category the reserved patch will carry (required to reserve). */
1049
+ category?: string;
1050
+ /** Who holds the reservation (required to reserve). */
1051
+ owner?: string;
1052
+ /** Optional human-readable rationale stored on the reserved slot. */
1053
+ reason?: string;
1054
+ /** Release the reservation at the order instead of creating one. */
1055
+ release?: boolean;
1056
+ }
996
1057
  /**
997
1058
  * Options for the `fireforge patch rename` subcommand. Updates the patch's
998
1059
  * filename, manifest `name`, and (optionally) `description` atomically
@@ -65,7 +65,22 @@ export interface LintIgnoreCeiling {
65
65
  max: number;
66
66
  /** Why the waiver exists. Required so the ceiling is reviewable. */
67
67
  reason: string;
68
+ /**
69
+ * Which share of a split `large-patch-lines` measurement the ceiling
70
+ * bounds: `product` (non-test files) or `test` (test files, held to the
71
+ * test tier). Absent: every finding of the rule. Only valid on
72
+ * `large-patch-lines`, and a rule carries either one share-less ceiling
73
+ * or at most one ceiling per share.
74
+ */
75
+ share?: PatchSizeShare;
76
+ /**
77
+ * Free-form JSON object FireForge preserves and never reads: a place for
78
+ * a project's own waiver bookkeeping (kind, owner, exit condition).
79
+ */
80
+ meta?: Record<string, unknown>;
68
81
  }
82
+ /** The two classes a split `addedCode` line measurement reports. */
83
+ export type PatchSizeShare = 'test' | 'product';
69
84
  /** One `PatchMetadata.lintIgnore` entry: a bare check ID or a ceiling waiver. */
70
85
  export type LintIgnoreEntry = string | LintIgnoreCeiling;
71
86
  /**
@@ -227,6 +242,28 @@ export interface PatchesManifest {
227
242
  * slot, and the slot is dropped on that write.
228
243
  */
229
244
  retired?: PatchRetiredSlot[];
245
+ /**
246
+ * Order numbers `patch reserve` holds for a patch a session has agreed to
247
+ * export but has not exported yet. Like a retired slot, a reservation is
248
+ * read only by the `patchPolicy.allowGaps: false` gap check (as an
249
+ * occupied order) and by the earliest-legal-order search (as taken); the
250
+ * export that lands on the order fills it, and the slot is dropped on that
251
+ * write.
252
+ */
253
+ reserved?: PatchReservedSlot[];
254
+ }
255
+ /** One order held by `patch reserve` until its owner exports it. */
256
+ export interface PatchReservedSlot {
257
+ /** The reserved order number. */
258
+ order: number;
259
+ /** Category the reserved patch will carry, so the slot stays in its range. */
260
+ category: PatchCategory;
261
+ /** Who holds the reservation: a session label or the planned filename. */
262
+ owner: string;
263
+ /** ISO timestamp of the reservation. */
264
+ reservedAt: string;
265
+ /** Optional human-readable rationale. */
266
+ reason?: string;
230
267
  }
231
268
  /** One placeholder left by `patch retire`. */
232
269
  export interface PatchRetiredSlot {
@@ -306,4 +343,10 @@ export interface PatchLintIssue {
306
343
  * ceiling compares against it, and `lint --report` carries it.
307
344
  */
308
345
  measurement?: number;
346
+ /**
347
+ * For a `large-patch-lines` finding under `patchSizeMetric: "addedCode"`
348
+ * on a general-tier patch: which share of the patch it measured. A
349
+ * share-scoped lintIgnore ceiling matches only findings of its share.
350
+ */
351
+ share?: PatchSizeShare;
309
352
  }
@@ -62,6 +62,21 @@ export interface TestConfig {
62
62
  * once. `--auto-ports` is the per-invocation equivalent.
63
63
  */
64
64
  mochitestPorts?: 'fixed' | 'auto';
65
+ /**
66
+ * `exclusive` (the default): every `fireforge test` holds the engine
67
+ * session lock alone. `shared`: a build-less run with auto ports holds it
68
+ * shared, so peers' build-less runs on the same objdir overlap while
69
+ * builds and re-exports still wait. `--shared-lock` is the per-invocation
70
+ * equivalent.
71
+ */
72
+ lockMode?: 'exclusive' | 'shared';
73
+ /**
74
+ * Which components `test --build` deploys before building: `all` (the
75
+ * default) every component with undeployed edits, `reached` only those a
76
+ * requested test reaches, `none` nothing. `--furnace-apply` is the
77
+ * per-invocation equivalent.
78
+ */
79
+ furnaceApply?: 'all' | 'reached' | 'none';
65
80
  }
66
81
  /** Patch history log settings stored in fireforge.json. */
67
82
  export interface HistoryConfig {
@@ -243,6 +258,11 @@ export interface CheckExtraStep {
243
258
  cwd?: string;
244
259
  /** Seconds before the step is killed and fails. Unbounded when unset. */
245
260
  timeout?: number;
261
+ /**
262
+ * Steps (built-in or extra) that must finish before this one starts,
263
+ * whatever their outcome: an ordering, not a success dependency.
264
+ */
265
+ after?: string[];
246
266
  }
247
267
  /** Configuration for `fireforge check`. Every field is optional. */
248
268
  export interface CheckConfig {
@@ -264,6 +284,23 @@ export interface CheckConfig {
264
284
  };
265
285
  /** Project commands run as further steps. */
266
286
  extraSteps?: CheckExtraStep[];
287
+ /** Seconds before a built-in step is killed and fails. Unbounded when unset. */
288
+ timeout?: number;
289
+ /** Per-step `timeout` overrides for built-in steps, in seconds. */
290
+ timeouts?: Partial<Record<CheckBuiltinStep, number>>;
291
+ /**
292
+ * Fail the verdict when a built-in step is skipped because it has nothing
293
+ * to run (no `typecheck` block, no furnace.json). A step named in `skip`
294
+ * is a decision, not a gap, and never fails it.
295
+ */
296
+ failOnSkipped?: boolean;
297
+ /**
298
+ * Project-relative path the lint step writes its `lint --per-patch
299
+ * --report` JSON to. Extra steps receive it as
300
+ * `FIREFORGE_CHECK_LINT_REPORT`, so an audit can read the run's lint
301
+ * report instead of linting the queue a second time.
302
+ */
303
+ lintReport?: string;
267
304
  }
268
305
  /**
269
306
  * Configuration for the `fireforge typecheck` command. Distinct from
@@ -308,6 +345,15 @@ export interface TypecheckConfig {
308
345
  * blocking. `'off'` suppresses them.
309
346
  */
310
347
  undefinedIdentifiers?: PatchLintSeverityGate;
348
+ /**
349
+ * Types Lit in the shim: `LitElement` and the template helpers of
350
+ * `chrome://global/content/vendor/lit.all.mjs`, and `MozLitElement` of
351
+ * `chrome://global/content/lit-utils.mjs`, with closed member lists, so a
352
+ * misspelt member of a widget host is an error. Default off: reactive
353
+ * properties declared only through `static properties` or
354
+ * `static queries` then need a JSDoc or constructor declaration.
355
+ */
356
+ litTypes?: boolean;
311
357
  }
312
358
  /**
313
359
  * Wire command configuration.
@@ -564,8 +610,12 @@ export interface PatchLintConfig {
564
610
  export interface PatchLintTokenScale {
565
611
  /** CSS properties governed (exact names, or a `*`-suffixed prefix such as `padding*`). */
566
612
  properties: string[];
567
- /** Custom-property prefix of the scale's tokens, e.g. `--mybrowser-space-`. */
568
- prefix: string;
613
+ /**
614
+ * Custom-property prefix of the scale's tokens, e.g. `--mybrowser-space-`,
615
+ * or a list of them for a scale whose steps are spelled more than one way
616
+ * (`["--mybrowser-space-", "--mybrowser-gap-"]`).
617
+ */
618
+ prefix: string | string[];
569
619
  /**
570
620
  * Literal value atoms accepted without a token (`0`, `auto`, `1px`).
571
621
  * `*` is a wildcard, so `*%` accepts any percentage. CSS-wide keywords
@@ -579,6 +629,28 @@ export interface PatchLintTokenScale {
579
629
  * tokens.
580
630
  */
581
631
  allow?: string[];
632
+ /**
633
+ * Literal atoms accepted only inside a math function (`calc()`, `min()`,
634
+ * `max()`, `clamp()`), with the `allowLiterals` wildcard syntax: a
635
+ * unitless multiplier (`calc(var(--x-space-2) * 2)`) without also
636
+ * accepting a bare `2`.
637
+ */
638
+ allowInCalc?: string[];
639
+ /**
640
+ * Largest total, in px, a declaration may subtract from this scale's
641
+ * tokens inside a math function (`calc(var(--x-space-4) - 1px)`), for a
642
+ * border or hairline inset. Summed over the declaration.
643
+ */
644
+ offsetCap?: number;
645
+ /** Engine-relative globs (`**`, `*`, `?`) of files this scale does not govern. */
646
+ exclude?: string[];
647
+ /**
648
+ * The fewest patch-created CSS files (outside `exclude`) that must carry a
649
+ * declaration of this scale's properties. A queue under it fails
650
+ * `token-scale-vacuous`, so a scale that matches nothing, or a scan set
651
+ * a move emptied, cannot pass by judging nothing.
652
+ */
653
+ minFiles?: number;
582
654
  }
583
655
  /**
584
656
  * Build modes for mach.
@@ -109,6 +109,19 @@ export interface FurnaceValidationException {
109
109
  component: string;
110
110
  /** The finding's check name, as `furnace validate` prints it in brackets. */
111
111
  check: string;
112
+ /**
113
+ * Narrows the exception to the findings on this element tag (a finding's
114
+ * `tags`): a `panel-item` menu row can be accepted without muting the
115
+ * check for every other element of the component.
116
+ */
117
+ tag?: string;
118
+ /**
119
+ * Narrows the exception to the findings in this module file of the
120
+ * component (a finding's `files`), by file name: a vendored bundle whose
121
+ * bytes are pinned can be accepted without muting the check for the
122
+ * authored modules beside it.
123
+ */
124
+ file?: string;
112
125
  /** Why the finding is accepted. Required: the entry is the review record. */
113
126
  reason: string;
114
127
  }
@@ -160,6 +173,12 @@ export interface FurnaceConfig {
160
173
  * `['browser/base/content/browser.xhtml']`, the upstream Firefox path.
161
174
  */
162
175
  tokenHostDocuments?: string[];
176
+ /**
177
+ * Stylesheets that load beside others in a document no queue link shows,
178
+ * for `token lint`: `{ "<glob>": ["<path or glob>", …] }`. A sheet the key
179
+ * matches may reference the tokens its partners declare.
180
+ */
181
+ tokenSiblingSheets?: Record<string, string[]>;
163
182
  /**
164
183
  * Override the default Fluent (.ftl) base path within the engine.
165
184
  * Defaults to `toolkit/locales/en-US/toolkit/global` when not set.
@@ -185,6 +204,12 @@ export interface FurnaceConfig {
185
204
  * entry that no longer matches anything as a stale-exception warning.
186
205
  */
187
206
  validationExceptions?: FurnaceValidationException[];
207
+ /**
208
+ * The fewest components a full `furnace validate` must judge. A run under
209
+ * it fails with `component-floor`, so a moved or emptied components tree
210
+ * cannot pass by validating nothing.
211
+ */
212
+ minComponents?: number;
188
213
  /**
189
214
  * Opt-in `furnace validate` checks (see {@link FURNACE_OPT_IN_CHECKS}).
190
215
  * Unset runs only the default checks.
@@ -359,6 +384,10 @@ export interface ValidationIssue {
359
384
  check: string;
360
385
  /** Human-readable description of the issue */
361
386
  message: string;
387
+ /** Element tags the finding is about, when it is about particular elements. */
388
+ tags?: string[];
389
+ /** Component module files the finding is in (`hardcoded-text`), by file name. */
390
+ files?: string[];
362
391
  }
363
392
  /** Resolved test-harness selection for a `furnace create` run. */
364
393
  export type ResolvedTestStyle = 'mochikit' | 'browser-chrome' | 'xpcshell' | 'none';
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Re-exports all type definitions.
3
3
  */
4
- export type { BuildConfig, FireForgeConfig, FirefoxConfig, FirefoxProduct, PatchLintFileSizeThresholds, PatchLintFileSizeTier, ProjectLicense, ProjectPaths, WireConfig, } from './config.js';
4
+ export type { BuildConfig, FireForgeConfig, FirefoxConfig, FirefoxProduct, PatchLintFileSizeThresholds, PatchLintFileSizeTier, PatchLintPatchSizeMetric, ProjectLicense, ProjectPaths, WireConfig, } from './config.js';
5
5
  export type { ApplyResult, ComponentType, CustomComponentConfig, DryRunAction, FurnaceConfig, FurnaceState, OverrideComponentConfig, OverrideType, StepError, ValidationIssue, } from './furnace.js';
@@ -49,13 +49,14 @@ export declare function commanderArgParser<T>(parse: (raw: string) => T): (raw:
49
49
  export declare function stringListOption(): [(value: string, previous: string[]) => string[], string[]];
50
50
  /** Environment variable naming a standing wait budget for the whole session. */
51
51
  export declare const WAIT_LOCK_ENV_VAR = "FIREFORGE_WAIT_LOCK";
52
+ export declare const MAX_WAIT_LOCK_SECONDS = 86400;
52
53
  /**
53
54
  * Resolves the parsed `--wait-lock [seconds]` option value into a wait budget
54
55
  * in seconds for `withEngineSessionLock`:
55
56
  * - absent (`undefined`) → {@link WAIT_LOCK_ENV_VAR} if set, else `undefined`
56
57
  * (the ~1 s fail-fast),
57
58
  * - bare flag (`true`) → {@link DEFAULT_WAIT_LOCK_SECONDS},
58
- * - explicit value → integer validated into 1..3600.
59
+ * - explicit value → integer validated into 1..86400.
59
60
  *
60
61
  * The flag always wins over the environment: the environment expresses a
61
62
  * default for a session, and an invocation that names a budget has said
@@ -125,7 +126,7 @@ export declare function isPathShapedArgument(token: string): boolean;
125
126
  *
126
127
  * Commander binds the next non-dash token to an optional value, so
127
128
  * `fireforge test --build --wait-lock browser_x.js` failed with
128
- * "--wait-lock must be an integer in 1..3600 (got "browser_x.js")": the
129
+ * "--wait-lock must be an integer in 1..86400 (got "browser_x.js")": the
129
130
  * help says the value is optional, and the obvious spelling refused. The
130
131
  * released flag moves to the end of the option section (before any `--`),
131
132
  * where nothing follows it, so commander reads it bare. Operands keep their
@@ -68,9 +68,14 @@ export function stringListOption() {
68
68
  const DEFAULT_WAIT_LOCK_SECONDS = 60;
69
69
  /** Environment variable naming a standing wait budget for the whole session. */
70
70
  export const WAIT_LOCK_ENV_VAR = 'FIREFORGE_WAIT_LOCK';
71
- /** Bounds shared by the flag and the environment variable. */
71
+ /**
72
+ * Bounds shared by the flag and the environment variable. The ceiling is a
73
+ * day: on a shared engine a re-export or `test --build` queued behind a
74
+ * peer's long series can need more than the hour the cap used to be, and a
75
+ * longer wait then had to be a requeue after exit 15.
76
+ */
72
77
  const MIN_WAIT_LOCK_SECONDS = 1;
73
- const MAX_WAIT_LOCK_SECONDS = 3600;
78
+ export const MAX_WAIT_LOCK_SECONDS = 86_400;
74
79
  /**
75
80
  * Parses a wait budget from text, or undefined when it is not an integer in
76
81
  * range. Shared by the flag and {@link WAIT_LOCK_ENV_VAR} so the two cannot
@@ -115,7 +120,7 @@ function waitLockSecondsFromEnv() {
115
120
  * - absent (`undefined`) → {@link WAIT_LOCK_ENV_VAR} if set, else `undefined`
116
121
  * (the ~1 s fail-fast),
117
122
  * - bare flag (`true`) → {@link DEFAULT_WAIT_LOCK_SECONDS},
118
- * - explicit value → integer validated into 1..3600.
123
+ * - explicit value → integer validated into 1..86400.
119
124
  *
120
125
  * The flag always wins over the environment: the environment expresses a
121
126
  * default for a session, and an invocation that names a budget has said
@@ -237,7 +242,7 @@ export function isPathShapedArgument(token) {
237
242
  *
238
243
  * Commander binds the next non-dash token to an optional value, so
239
244
  * `fireforge test --build --wait-lock browser_x.js` failed with
240
- * "--wait-lock must be an integer in 1..3600 (got "browser_x.js")": the
245
+ * "--wait-lock must be an integer in 1..86400 (got "browser_x.js")": the
241
246
  * help says the value is optional, and the obvious spelling refused. The
242
247
  * released flag moves to the end of the option section (before any `--`),
243
248
  * where nothing follows it, so commander reads it bare. Operands keep their
@@ -253,10 +253,34 @@ lint instead of throwing at runtime (since 0.50.0). The same shim backs
253
253
  is a wildcard), or a CSS-wide keyword (`inherit`, `initial`, `unset`,
254
254
  `revert`, `revert-layer`). A `var()` fallback is held to the same scale,
255
255
  so `var(--mybrowser-gap, 7px)` fails on `7px`. `calc()`, `min()`, `max()`
256
- and `clamp()` are transparent, so a unitless multiplier inside one needs
257
- an `allowLiterals` entry. Files the patch modifies rather than creates are
258
- not checked, and a line carrying `fireforge-ignore: token-scale` is
259
- skipped.
256
+ and `clamp()` are transparent. Files the patch modifies rather than
257
+ creates are not checked, and a line carrying
258
+ `fireforge-ignore: token-scale` is skipped. Declarations inside
259
+ descriptor at-rules (`@font-face`, `@counter-style`, `@property`,
260
+ `@font-feature-values`, `@font-palette-values`, `@page` and its margin
261
+ boxes) are descriptors, not properties, and are not judged.
262
+
263
+ Since 0.51.0 a scale also takes:
264
+
265
+ - `prefix` as a list (`["--mybrowser-space-", "--mybrowser-gap-"]`) for a
266
+ scale whose steps are spelled more than one way.
267
+ - `allowInCalc`: literals legal only inside a math function, such as the
268
+ unitless multiplier in `calc(var(--mybrowser-space-2) * 2)`, without
269
+ also passing a bare `2`. Same wildcard syntax as `allowLiterals`.
270
+ - `offsetCap`: the px a declaration may subtract from the scale's tokens
271
+ inside a math function (`calc(var(--mybrowser-space-4) - 1px)`), summed
272
+ over the declaration. A px value anywhere else still fails.
273
+ - `exclude`: engine-relative globs of files the scale does not govern,
274
+ such as a vendored minified sheet, so its patch needs no patch-wide
275
+ waiver.
276
+ - `minFiles`: the fewest patch-created stylesheets (outside `exclude`)
277
+ that must declare one of the scale's properties. Under it the queue
278
+ fails `token-scale-vacuous` (an error on `fireforge.json` in
279
+ `lint --per-patch`), so a scale that matches nothing, or a scan set a
280
+ move emptied, cannot pass by judging nothing. A `--patches` run does
281
+ not judge the floor.
282
+
283
+ An unknown key in a scale is refused.
260
284
 
261
285
  ## `typecheck`
262
286
 
@@ -275,6 +299,42 @@ program: prior incremental diagnostic state is never restored. Cached and
275
299
  also disables build-info writes. A jsconfig's own `incremental` and
276
300
  `tsBuildInfoFile` remain ignored.
277
301
 
302
+ `typecheck.litTypes: true` (since 0.51.0, default off) types Lit in the
303
+ shim: `LitElement` and the helpers of
304
+ `chrome://global/content/vendor/lit.all.mjs`, and `MozLitElement` of
305
+ `chrome://global/content/lit-utils.mjs`. The element classes carry closed
306
+ member lists, as `Cu` does, so a misspelt member of a widget host is an
307
+ error rather than `any`. Template helpers and directives stay loose. It is
308
+ off by default because a reactive property declared only in
309
+ `static properties` or `static queries` then needs a declaration to be
310
+ known. Since 0.52.0 the shim declares the global type
311
+ `MozLitElementWith<Extra>`: a widget casts its base to it, and its
312
+ instances carry `Extra` beside MozLitElement's members. A query getter
313
+ cannot be declared any other way: a class field redefines the getter
314
+ MozLitElement installs and throws, and a constructor declaration reads it
315
+ before `renderRoot` exists.
316
+
317
+ ```js
318
+ const Base = /** @type {MozLitElementWith<{ input: HTMLInputElement }>} */ (MozLitElement);
319
+ export class MozSearch extends Base {
320
+ static queries = { input: 'input' };
321
+ }
322
+ ```
323
+
324
+ Without `litTypes` (and under per-patch checkJs, which does not type Lit)
325
+ `MozLitElementWith<Extra>` is `any`, as the base is, so the same source
326
+ checks in both. A project shim can add members by merging
327
+ `interface LitElementShimMembers`; a jsconfig `paths` entry that maps these
328
+ URLs to real sources takes precedence.
329
+
330
+ Per-patch checkJs gives each test script its own program. Since 0.51.0 a
331
+ test's `resource:///` and `chrome://` imports (including a
332
+ `typeof import("…")` cast) resolve to the modules the queue creates up to
333
+ the test's own patch, so a test of an earlier patch's module is checked
334
+ against its real types. A module a later patch creates, an upstream module
335
+ and a basename two patches create still type as `any`, and an implicit-any
336
+ finding on such an import names it.
337
+
278
338
  Both project and per-patch checkJs provide Gecko DOM constructor
279
339
  `isInstance(value)` predicates with instance narrowing, plus
280
340
  `MouseEvent.MOZ_SOURCE_PEN`. These declarations retain normal DOM member
@@ -288,8 +348,10 @@ gaps does not move a patch out of the band its category owns.
288
348
  With `patchPolicy.allowGaps: false`, orders are contiguous within a range:
289
349
  a new patch must fill an existing gap or take the number right after the
290
350
  range's last patch. A patch that has to leave the queue without opening a
291
- gap is removed with `patch retire`, which keeps its order as a retired slot
292
- (see [`patch-workflow.md`](patch-workflow.md#queue-maintenance)).
351
+ gap is removed with `patch retire`, which keeps its order as a retired slot.
352
+ An order a peer has claimed but not exported yet is held with `patch
353
+ reserve`, so a later order can be exported without a gap in between (see
354
+ [`patch-workflow.md`](patch-workflow.md#queue-maintenance)).
293
355
 
294
356
  ### Registration-only rules
295
357
 
@@ -356,6 +418,18 @@ harness's own busy-port fallback, so sibling checkouts can run browser suites
356
418
  at once. `--auto-ports` does the same for one invocation. See
357
419
  [`testing.md`](testing.md#shared-browsers-ports-and-host-state).
358
420
 
421
+ `test.lockMode` is `"exclusive"` (default) or `"shared"`. `"shared"` lets a
422
+ build-less run that applies no negative control and uses auto ports hold the
423
+ engine-session lock shared, so peers' build-less runs on the same objdir
424
+ overlap while builds, re-exports and every other writer still hold it alone.
425
+ `--shared-lock` does the same for one invocation. See
426
+ [`testing.md`](testing.md#concurrency).
427
+
428
+ `test.furnaceApply` is `"all"` (default), `"reached"` or `"none"`: which
429
+ components a `test --build` deploys before building. `--furnace-apply` does
430
+ the same for one invocation. See
431
+ [`testing.md`](testing.md#furnace-components-in-a-pre-test-build).
432
+
359
433
  ## `history`
360
434
 
361
435
  `history.path` is where FireForge appends its patch history log, relative to
@@ -457,6 +531,24 @@ one that dismissed four unregistered sources.
457
531
  `/bin/sh -c` (`cmd.exe /c` on Windows) from the project root, or from the
458
532
  project-relative `cwd`. `timeout` is in seconds: past it the step's whole
459
533
  process tree is killed and the step fails. A step passes when it exits 0.
534
+ `after` lists steps, built-in or extra, that must finish before it starts
535
+ (whatever their outcome); a name that is not a step, or an ordering cycle,
536
+ is refused.
537
+ - `timeout` bounds every built-in step, in seconds, and `timeouts` sets it
538
+ per step (`{ "typecheck": 600 }`). A step past its budget is killed and
539
+ fails. Unset, built-in steps are unbounded.
540
+ - `failOnSkipped: true` fails the check (`reason=skipped-steps`) when a
541
+ built-in step is skipped because the project has nothing for it to run
542
+ (no `typecheck` block, no `furnace.json`). A step named in `skip` is a
543
+ decision and never fails it.
544
+ - `lintReport` is a project-relative path the lint step writes its
545
+ `lint --per-patch --report` JSON to. Every extra step receives the
546
+ absolute path as `FIREFORGE_CHECK_LINT_REPORT`, so an audit that runs
547
+ `after: ["lint"]` can read the run's lint report instead of linting the
548
+ queue a second time.
549
+
550
+ The verdict line names the skipped steps with an additive
551
+ `skipped-steps=<a,b>` key beside `skipped=<n>`.
460
552
 
461
553
  ## Design tokens
462
554
 
@@ -519,7 +611,16 @@ The dark and variant blocks mirror it and appear in `token show`.
519
611
  - `token-undeclared`: a `var(--<prefix>…)` in the tokens CSS, or in any CSS
520
612
  file a patch in the queue touches, names a token no block of the tokens
521
613
  CSS declares. A property declared in the same file, and the `furnace.json`
522
- `tokenAllowlist` and `runtimeVariables` names, are exempt.
614
+ `tokenAllowlist` and `runtimeVariables` names, are exempt. Since 0.51.0 a
615
+ reference with a fallback (`var(--x, 0)`) is optional and not reported,
616
+ and a token a sibling sheet declares counts as declared. Sheets are
617
+ siblings when one queue document links both (`<link rel="stylesheet">`,
618
+ `<html:link>` or `<?xml-stylesheet?>`, in markup or a Lit template; a
619
+ `chrome://` URL resolves through the queue's jar.mn lines, a relative
620
+ one beside the document), when one `@import`s the other, or when
621
+ `furnace.json` `tokenSiblingSheets` pairs them:
622
+ `{ "browser/themes/**/panel*.css": ["browser/base/content/host.css"] }`
623
+ (a partner is a path or a glob over the queue's sheets).
523
624
 
524
625
  The prefix is `furnace.json` `tokenPrefix`, else `--<binaryName>-`.
525
626
 
@@ -585,7 +686,7 @@ Every FireForge command that mutates the engine takes the engine-session
585
686
  lock, and some take a second subsystem lock as well. Contention fails fast
586
687
  after about a second by default.
587
688
 
588
- `--wait-lock [seconds]` (bare flag means 60, valid range 1 to 3600) replaces
689
+ `--wait-lock [seconds]` (bare flag means 60, valid range 1 to 86400, a day) replaces
589
690
  that with a bounded wait, and the budget covers every lock the command takes.
590
691
  For `furnace apply`, `deploy` and `sync` that means the furnace lock as well
591
692
  as the engine-session lock. The furnace leaves that take only the furnace lock
@@ -614,7 +715,7 @@ instead of blocking it.
614
715
 
615
716
  | Variable | Effect |
616
717
  | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
617
- | `FIREFORGE_WAIT_LOCK` | Session-wide lock wait budget in seconds (1 to 3600). See above. |
718
+ | `FIREFORGE_WAIT_LOCK` | Session-wide lock wait budget in seconds (1 to 86400). See above. |
618
719
  | `FIREFORGE_SESSION_ID` | Recorded as `sessionId` on every patch history log record this process writes. See `history` above. |
619
720
  | `FIREFORGE_LOG_KEEP` | Also write every `test`/`build` run log here, outside retention (a directory collects one file per run). See `run-logs.md`. |
620
721
  | `FIREFORGE_MAX_UNTRACKED_FILES` | Per-directory cap when expanding collapsed untracked directories in `status` (default 5000). A non-positive value warns and is ignored. |