spec-controller 0.1.0-alpha.45 → 0.1.0-alpha.46

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 (116) hide show
  1. package/dist/cli-allocate/cli.d.ts.map +1 -1
  2. package/dist/cli-allocate/cli.js +0 -5
  3. package/dist/cli-allocate/cli.js.map +1 -1
  4. package/dist/cli-allocate/readHistory.d.ts +0 -13
  5. package/dist/cli-allocate/readHistory.d.ts.map +1 -1
  6. package/dist/cli-allocate/readHistory.js +0 -33
  7. package/dist/cli-allocate/readHistory.js.map +1 -1
  8. package/dist/cli-allocate/readParts.d.ts +0 -1
  9. package/dist/cli-allocate/readParts.d.ts.map +1 -1
  10. package/dist/cli-allocate/readParts.js +0 -6
  11. package/dist/cli-allocate/readParts.js.map +1 -1
  12. package/dist/cli-allocate/readTree.d.ts +0 -11
  13. package/dist/cli-allocate/readTree.d.ts.map +1 -1
  14. package/dist/cli-allocate/readTree.js +0 -32
  15. package/dist/cli-allocate/readTree.js.map +1 -1
  16. package/dist/cli-allocate/refStore.d.ts +0 -1
  17. package/dist/cli-allocate/refStore.d.ts.map +1 -1
  18. package/dist/cli-allocate/refStore.js +0 -13
  19. package/dist/cli-allocate/refStore.js.map +1 -1
  20. package/dist/cli-allocate/request.d.ts +0 -2
  21. package/dist/cli-allocate/request.d.ts.map +1 -1
  22. package/dist/cli-allocate/request.js +0 -7
  23. package/dist/cli-allocate/request.js.map +1 -1
  24. package/dist/cli-allocate/stderr.d.ts +0 -7
  25. package/dist/cli-allocate/stderr.d.ts.map +1 -1
  26. package/dist/cli-allocate/stderr.js +0 -7
  27. package/dist/cli-allocate/stderr.js.map +1 -1
  28. package/dist/cli-allocate/unreadable.d.ts +0 -13
  29. package/dist/cli-allocate/unreadable.d.ts.map +1 -1
  30. package/dist/cli-allocate/unreadable.js +0 -13
  31. package/dist/cli-allocate/unreadable.js.map +1 -1
  32. package/dist/cli-args.d.ts +0 -113
  33. package/dist/cli-args.d.ts.map +1 -1
  34. package/dist/cli-args.js +0 -145
  35. package/dist/cli-args.js.map +1 -1
  36. package/dist/cli-balance/cli.d.ts +0 -85
  37. package/dist/cli-balance/cli.d.ts.map +1 -1
  38. package/dist/cli-balance/cli.js +0 -230
  39. package/dist/cli-balance/cli.js.map +1 -1
  40. package/dist/cli-balance/emit/format.d.ts +0 -52
  41. package/dist/cli-balance/emit/format.d.ts.map +1 -1
  42. package/dist/cli-balance/emit/format.js +0 -70
  43. package/dist/cli-balance/emit/format.js.map +1 -1
  44. package/dist/cli-balance/emit/writer.d.ts +0 -17
  45. package/dist/cli-balance/emit/writer.d.ts.map +1 -1
  46. package/dist/cli-balance/emit/writer.js +0 -13
  47. package/dist/cli-balance/emit/writer.js.map +1 -1
  48. package/dist/cli-balance/exitStatus.d.ts +0 -1
  49. package/dist/cli-balance/exitStatus.d.ts.map +1 -1
  50. package/dist/cli-balance/exitStatus.js +0 -7
  51. package/dist/cli-balance/exitStatus.js.map +1 -1
  52. package/dist/cli-balance/inputsRead.d.ts +0 -12
  53. package/dist/cli-balance/inputsRead.d.ts.map +1 -1
  54. package/dist/cli-balance/inputsRead.js +0 -12
  55. package/dist/cli-balance/inputsRead.js.map +1 -1
  56. package/dist/cli-balance/reRender.d.ts +0 -14
  57. package/dist/cli-balance/reRender.d.ts.map +1 -1
  58. package/dist/cli-balance/reRender.js +0 -15
  59. package/dist/cli-balance/reRender.js.map +1 -1
  60. package/dist/cli-balance/unreadableInputs.d.ts +0 -21
  61. package/dist/cli-balance/unreadableInputs.d.ts.map +1 -1
  62. package/dist/cli-balance/unreadableInputs.js +0 -21
  63. package/dist/cli-balance/unreadableInputs.js.map +1 -1
  64. package/dist/cli-registry.d.ts +0 -86
  65. package/dist/cli-registry.d.ts.map +1 -1
  66. package/dist/cli-registry.js +0 -70
  67. package/dist/cli-registry.js.map +1 -1
  68. package/dist/cli.d.ts +0 -20
  69. package/dist/cli.d.ts.map +1 -1
  70. package/dist/cli.js +0 -21
  71. package/dist/cli.js.map +1 -1
  72. package/dist/deferralTags.d.ts +0 -14
  73. package/dist/deferralTags.d.ts.map +1 -1
  74. package/dist/deferralTags.js +0 -14
  75. package/dist/deferralTags.js.map +1 -1
  76. package/dist/host.d.ts +0 -61
  77. package/dist/host.d.ts.map +1 -1
  78. package/dist/host.js +1 -84
  79. package/dist/host.js.map +1 -1
  80. package/dist/ingest/ciSourcePaths.d.ts +0 -38
  81. package/dist/ingest/ciSourcePaths.d.ts.map +1 -1
  82. package/dist/ingest/ciSourcePaths.js +0 -38
  83. package/dist/ingest/ciSourcePaths.js.map +1 -1
  84. package/dist/ingest/gherkinValidation.d.ts +0 -76
  85. package/dist/ingest/gherkinValidation.d.ts.map +1 -1
  86. package/dist/ingest/gherkinValidation.js +0 -76
  87. package/dist/ingest/gherkinValidation.js.map +1 -1
  88. package/dist/ingest/ingestQualityChecks.d.ts +0 -81
  89. package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
  90. package/dist/ingest/ingestQualityChecks.js +0 -194
  91. package/dist/ingest/ingestQualityChecks.js.map +1 -1
  92. package/dist/ingest/ingestScenarios.d.ts +0 -39
  93. package/dist/ingest/ingestScenarios.d.ts.map +1 -1
  94. package/dist/ingest/ingestScenarios.js +0 -70
  95. package/dist/ingest/ingestScenarios.js.map +1 -1
  96. package/dist/ingest/inputShapes.d.ts +0 -31
  97. package/dist/ingest/inputShapes.d.ts.map +1 -1
  98. package/dist/ingest/inputShapes.js +0 -30
  99. package/dist/ingest/inputShapes.js.map +1 -1
  100. package/dist/outputLocation.d.ts +0 -48
  101. package/dist/outputLocation.d.ts.map +1 -1
  102. package/dist/outputLocation.js +0 -48
  103. package/dist/outputLocation.js.map +1 -1
  104. package/dist/run-management/keptRun.d.ts +0 -107
  105. package/dist/run-management/keptRun.d.ts.map +1 -1
  106. package/dist/run-management/keptRun.js +0 -75
  107. package/dist/run-management/keptRun.js.map +1 -1
  108. package/dist/run-management/resolveRunInputs.d.ts +0 -67
  109. package/dist/run-management/resolveRunInputs.d.ts.map +1 -1
  110. package/dist/run-management/resolveRunInputs.js +0 -88
  111. package/dist/run-management/resolveRunInputs.js.map +1 -1
  112. package/dist/storedRun.d.ts +0 -21
  113. package/dist/storedRun.d.ts.map +1 -1
  114. package/dist/storedRun.js +0 -21
  115. package/dist/storedRun.js.map +1 -1
  116. package/package.json +2 -2
@@ -1,16 +1,3 @@
1
- /**
2
- * The balance CLI — thin wiring over the reconciler seams. The orchestration half of
3
- * the old cli.ts: arg parsing, the render-from-JSON mode, and the reconcile →
4
- * census → provenance → plan → write sequence. The impure file reads it calls
5
- * (runReconcile + the read* siblings) live in ingest/ingestQualityChecks.ts; the output
6
- * plan/write in ./emit; the git-derived run inputs in run-management/resolveRunInputs.ts.
7
- *
8
- * Usage:
9
- * pnpm reconcile [--features <dir>] [--vitest <report.json>]
10
- * [--cucumber <report.json>] [--ci-steps <record.json>]
11
- * [--ci <ci.yml>]
12
- * [--format <fmt>[:<path>]]
13
- */
14
1
  import { existsSync, readFileSync } from "node:fs";
15
2
  import { dirname } from "node:path";
16
3
  import { runReconcile, readEvidenceObligations, readFeatureNames, featureCorpusParseErrors, } from "../ingest/ingestQualityChecks.js";
@@ -24,16 +11,7 @@ import { statusFor } from "./exitStatus.js";
24
11
  import { verdictCode, } from "@3f-consulting/spec-controller-core";
25
12
  import { resolveSourceSha, resolveTargetRoot, resolveToolIdentity } from "../run-management/resolveRunInputs.js";
26
13
  import { cliRegistry, renderCommandHelp } from "../cli-registry.js";
27
- // THE ARGV READING AND ITS REGISTRY BOUNDING, SHARED WITH EVERY OTHER COMMAND. Both
28
- // lived here while `balance` was the only command; a second command needs them, and a second
29
- // copy of "what did the operator type" is the one thing this tree least wants two of.
30
14
  import { asksForHelp, parseArgs, checkArgvShape, checkUnknownFlags, checkMissingValues, checkMisplacedHostModifiers, } from "../cli-args.js";
31
- /**
32
- * Collect the `--format <spec>` values from argv in order (the flag is REPEATABLE, unlike
33
- * the single-valued flags `parseArgs` records) — the raw specs `planOutput` parses. Empty
34
- * when no `--format` was given, which `planOutput` reads as the md→stdout default.
35
- * Several specs route in one invocation.
36
- */
37
15
  function collectFormatSpecs(argv) {
38
16
  const specs = [];
39
17
  for (let i = 0; i < argv.length; i++) {
@@ -47,15 +25,6 @@ function collectFormatSpecs(argv) {
47
25
  }
48
26
  return specs;
49
27
  }
50
- /**
51
- * The legacy-`--json` guard at the CLI edge. The earlier
52
- * `--json <path>` flag is removed; supplying it must fail fast with a migration hint to
53
- * `--format json:<path>`, so the removed flag never silently no-ops and drops output. PURE
54
- * and `@unit`-testable: the removed flag is NOT a `--format` spec (planOutput never sees
55
- * it), so the guard reads the parsed args directly and returns the typed migration-hint
56
- * error message when `--json` is present — routed to stderr + a non-zero exit by main(),
57
- * the same handling planOutput's typed error gets (the shared error surface) — else null.
58
- */
59
28
  export function checkLegacyJson(args) {
60
29
  if (args["json"] !== undefined) {
61
30
  return ("The --json <path> flag has been removed. " +
@@ -64,27 +33,9 @@ export function checkLegacyJson(args) {
64
33
  }
65
34
  return null;
66
35
  }
67
- /**
68
- * Source the provenance "Target repo:" name for a run. The
69
- * operator's `--target` is recorded VERBATIM — no resolution — defaulting to
70
- * `"unknown-target"` when omitted (parallel to `sourceSha`'s `"unknown"`; the facts
71
- * artefact is self-describing, so the line always renders). PURE and `@unit`-testable at
72
- * the CLI edge, like `checkLegacyJson`. It never inspects `--features`: the prior
73
- * `basename(dirname(--features))` resolution (the deleted `resolveTarget`) and its
74
- * degenerate `.` are impossible now — the target is only ever the given value or the
75
- * explicit default.
76
- */
77
36
  export function sourceTarget(args) {
78
37
  return args["target"] ?? "unknown-target";
79
38
  }
80
- /**
81
- * The parsed args, as the reconciler's input paths — the one place a `--flag` name becomes a
82
- * `ReconcileOptions` key.
83
- *
84
- * Its own function rather than an object literal inside `runBalance`, which sits at the
85
- * `max-lines-per-function` standard: a flag is added here, not by growing the orchestration. The
86
- * mapping is also the only thing in that function with nothing to do with orchestration.
87
- */
88
39
  function reconcileInputsOf(args) {
89
40
  return {
90
41
  features: args["features"],
@@ -95,27 +46,7 @@ function reconcileInputsOf(args) {
95
46
  ciSteps: args["ci-steps"],
96
47
  };
97
48
  }
98
- /**
99
- * Guard the supplied input-file/dir flags at the CLI edge. A
100
- * mistyped `--vitest` / `--cucumber` / `--features` / `--ci` / `--package-json`
101
- * pointing at a non-existent path used to reconcile silently against ZERO evidence —
102
- * a terrifying false all-red report meaning "you forgot the reports", not "your code
103
- * is broken" (the dogfooding fault). These flags are Examples of ONE boundary
104
- * rule: a supplied-but-absent input path is a hard error, and a flag added to the set
105
- * inherits it rather than restating it. Scope is existence only
106
- * (readability / file-vs-dir type-correctness out of scope; `exists` covers the dir
107
- * flag and the file flags alike).
108
- *
109
- * PURE and `@unit`-testable like `checkLegacyJson` / `sourceTarget`: reads the parsed
110
- * args + an injected `exists` fn (no fs), returns the FIRST supplied-but-absent
111
- * `(flag, path)` as a typed error naming both — routed to stderr + a non-zero exit by
112
- * `refuseUnreadableInputs` (the shared typed-error surface) — else null. An OMITTED flag is not an
113
- * error (legitimately optional: simply no evidence of that kind).
114
- */
115
49
  export function checkInputsExist(args, exists) {
116
- // The input flags in a fixed order — the FIRST supplied-but-absent one is the
117
- // reported error (deterministic; the operator fixes and re-runs). Keys are the
118
- // parseArgs form (the `--` stripped); the message names the flag WITH its dashes.
119
50
  const flags = [
120
51
  "vitest", "cucumber", "features", "ci", "package-json", "ci-steps",
121
52
  ];
@@ -127,29 +58,9 @@ export function checkInputsExist(args, exists) {
127
58
  }
128
59
  return null;
129
60
  }
130
- /**
131
- * The JSON-BEARING input flags — the ones whose content is `JSON.parse`d. `--features` and `--ci`
132
- * are read as Gherkin and YAML files on disk, and whether they can be read is `checkInputPaths`'s.
133
- */
134
61
  const JSON_INPUT_FLAGS = [
135
62
  "vitest", "cucumber", "package-json", "ci-steps",
136
63
  ];
137
- /**
138
- * Guard the READABILITY of the supplied JSON inputs at the CLI edge.
139
- * `checkInputsExist` already guards their PRESENCE — but a path that is present yet
140
- * UNPARSEABLE fell straight through it: the reader threw mid-parse, nothing caught it, and
141
- * the process hit Node's default exit 1 — the code reserved for a genuine OUT-OF-BALANCE
142
- * verdict. A crashed invocation was therefore indistinguishable, by exit code, from an
143
- * honest disagreement. An input the tool cannot read is a USAGE fault: exit 2,
144
- * sibling to a missing path and an unrecognised flag.
145
- *
146
- * PURE and `@unit`-testable like its sibling guards: reads the parsed args + an injected
147
- * `read` fn (no fs), returns the FIRST supplied-but-unparseable `(flag, path, failure)` as
148
- * a typed error naming all three — routed to stderr + exit 2 by `refuseUnreadableInputs` — else null.
149
- * An omitted flag is not an error, and a file that cannot be read at all (a race after the
150
- * existence check, a permission refused) is refused as one that could not be read, never as JSON
151
- * that did not parse.
152
- */
153
64
  export function checkInputsParse(args, read) {
154
65
  for (const flag of JSON_INPUT_FLAGS) {
155
66
  const path = args[flag];
@@ -166,7 +77,6 @@ export function checkInputsParse(args, read) {
166
77
  JSON.parse(text);
167
78
  }
168
79
  catch (err) {
169
- // Anything that escapes this catch lands on Node's default exit 1 — the collision itself.
170
80
  return `The --${flag} report is not valid JSON: ${path} (${failureOf(err)})`;
171
81
  }
172
82
  }
@@ -175,22 +85,6 @@ export function checkInputsParse(args, read) {
175
85
  function failureOf(err) {
176
86
  return err instanceof Error ? err.message : String(err);
177
87
  }
178
- /**
179
- * Guard the readability of `--render-from-json` at the CLI edge. The
180
- * render-from-saved-JSON branch RETURNS before the input guards ever run, so it honoured
181
- * NEITHER: a missing path crashed to `ENOENT` and a malformed file to `SyntaxError`, both
182
- * landing on Node's default exit 1 — the out-of-balance code.
183
- *
184
- * The missing-path case was a live violation of the missing-input rule's own shipped principle: a
185
- * supplied input path that does not exist is a hard error at exit 2, enforced for the five
186
- * evidence flags and not for this one. The CLI shipped a guard that half-honoured its Rule.
187
- *
188
- * MISSING and UNPARSEABLE are two Examples of one boundary rule — an input the tool cannot
189
- * read is a usage error, never a verdict — so one guard covers both. PURE and
190
- * `@unit`-testable like its siblings: the parsed args + an injected `read` (no fs), which
191
- * throws for an absent/unreadable path exactly as `readFileSync` does. An OMITTED flag is
192
- * not an error (the ordinary reconcile path).
193
- */
194
88
  export function checkRenderFromJson(args, read) {
195
89
  const path = args["render-from-json"];
196
90
  if (path === undefined)
@@ -199,72 +93,36 @@ export function checkRenderFromJson(args, read) {
199
93
  JSON.parse(read(path));
200
94
  }
201
95
  catch (err) {
202
- // MISSING (read throws ENOENT) and UNPARSEABLE (JSON.parse throws) are the same input
203
- // fault, caught in the same place. Anything escaping here lands on Node's default
204
- // exit 1 — the out-of-balance code — which is the collision this closes.
205
96
  const failure = err instanceof Error ? err.message : String(err);
206
97
  return `The --render-from-json saved report could not be read: ${path} (${failure})`;
207
98
  }
208
99
  return null;
209
100
  }
210
- /**
211
- * The `balance` command. A refusal leaves on the usage code and answers that no report was written,
212
- * after everything already written has drained.
213
- */
214
101
  export function runBalance(argv) {
215
102
  return settlingRefusal(() => balance(argv), false);
216
103
  }
217
104
  function balance(argv) {
218
- // Answer `--help`/`-h` from the command/flag registry BEFORE any
219
- // parse or reconcile: render the balance command's per-command scope (a line per
220
- // registered flag — name + arg + description), leave process.exitCode at its default 0,
221
- // and return. This intercepts --help so it never falls through parseArgs as a stray flag
222
- // while balance runs anyway. The registry is the single source, so a flag that exists is
223
- // a flag that appears in help — no hand-kept list to drift.
224
105
  if (asksForHelp(argv)) {
225
106
  process.stdout.write(renderCommandHelp(cliRegistry, "balance") + "\n");
226
107
  return false;
227
108
  }
228
- // Capture the run-start instant up front — the run provenance's UTC timestamp,
229
- // threaded through ctx.runStart to the renderers.
230
109
  const runStart = new Date();
231
110
  const args = parseArgs(argv);
232
- // Legacy-`--json` guard: the earlier `--json <path>` flag is
233
- // removed. Reject it fast — before any reconcile or write — with a migration hint to
234
- // `--format json:<path>`, so the removed flag never silently no-ops and drops output. The
235
- // guard's typed error is routed to stderr + a non-zero exit, exactly as planOutput's error
236
- // is below (the shared typed-error surface).
237
111
  const legacyJsonError = checkLegacyJson(args);
238
112
  if (legacyJsonError)
239
113
  refuse(legacyJsonError);
240
- // A host modifier after the command is out of place, not unknown, so it is
241
- // refused before the drift advice.
242
114
  const misplacedModifierError = checkMisplacedHostModifiers(args, cliRegistry, "balance");
243
115
  if (misplacedModifierError)
244
116
  refuse(misplacedModifierError);
245
- // Every token is a flag or the value of the flag before it, refused before the unknown-flag
246
- // check below.
247
117
  const shapeError = checkArgvShape(argv, cliRegistry, "balance");
248
118
  if (shapeError)
249
119
  refuse(shapeError);
250
- // Registry-bounded flag NAMES: `balance` accepts ONLY the flags its registry
251
- // scope LISTS. An unregistered flag — a typo `--strcit`, a stray `--bogus` — is a USAGE error:
252
- // name it on stderr, set process.exitCode = 2 (the enumerated usage code, the 0/1/2
253
- // taxonomy — never 1, never 0), and RETURN before any reconcile. It bounds names only; that every
254
- // other token is read or refused is the argv-shape check above.
255
- // Runs AFTER the legacy-`--json` guard so `--json` keeps its specific migration hint, after the
256
- // misplaced-modifier refusal, so a `--store` / `--run-id` written after the command is named as
257
- // out of place rather than given pin advice, and after the argv-shape check, so `--format=json` is
258
- // refused as a form and never given pin advice. This is the structural teeth behind "accepted =
259
- // registry = help" — a flag can't affect behaviour without a registry entry.
260
120
  const unknownFlagError = checkUnknownFlags(args, cliRegistry, "balance", resolveToolIdentity().toolVersion);
261
121
  if (unknownFlagError) {
262
122
  process.stderr.write(unknownFlagError + "\n");
263
123
  process.exitCode = 2;
264
124
  return false;
265
125
  }
266
- // A flag that takes a value, given none, refused before anything reads
267
- // the value `parseArgs` made up for it.
268
126
  const missingValueError = checkMissingValues(argv, cliRegistry, "balance");
269
127
  if (missingValueError)
270
128
  refuse(missingValueError);
@@ -272,53 +130,22 @@ function balance(argv) {
272
130
  return false;
273
131
  refuseUnreadableInputs(args);
274
132
  const inputs = reconcileInputsOf(args);
275
- // Reconcile the obligation-vs-observation evidence into the Ledger. The runtime evidence-observation
276
- // views (Test volume, the evidence grid) are FOLDS the renderers derive off this Ledger's posted
277
- // credits (the census is retired), so they cannot drift from the
278
- // reconciler's verdict: they ARE the same rows. `withRuntimeObservations: true` (below) tells the
279
- // renderers the axis is in play.
280
133
  const balance = runReconcile(inputs);
281
- // Read the scenario-corpus census alongside the balance —
282
- // the raw-vs-parsed @SCN-occurrence delta over the same discovered feature corpus.
283
- // A sibling to the balance, threaded to the renderers via writeOutputs like ctx.
284
134
  const evidenceObligations = readEvidenceObligations(args["features"]);
285
- // The static-check kind-counts are a FOLD OVER THE LEDGER — the
286
- // renderers count the balance's own posted static-check credits (`staticObservationTally`), so
287
- // they cannot drift from the reconciler's verdict: they ARE the same rows. The parallel static
288
- // census is RETIRED; `withStaticChecks: true` (below) tells the renderers the axis is in play.
289
- // Read the target's feature-code→slug map alongside the balance
290
- // — the by-feature cut's full-name labels. The 5th sibling, threaded to the MARKDOWN
291
- // renderer via writeOutputs only (markdown-only; the by-feature cut isn't on JSON).
292
135
  const featureNames = readFeatureNames(args["features"]);
293
136
  const ctx = runContextOf(args, inputs, runStart);
294
- // Plan the outputs from the --format specs (no flag → md→stdout) and write them via
295
- // the writer — the pure plan / impure writer split. The plan
296
- // parse+validate is pure; the writer is the only IO for the emitted report. This is
297
- // the SOLE output path: the tool emits via --format and holds no storage opinion — the
298
- // legacy runs/<target>/<ISO>/ auto-archive was removed, the
299
- // caller now routes stored runs (spec-controller's run-management layer).
300
137
  const planResult = planOutput(collectFormatSpecs(argv), namesStdout);
301
138
  if (!planResult.ok)
302
139
  refuse(planResult.error);
303
140
  const payloads = { balance, ctx, evidenceObligations, withRuntimeObservations: true, withStaticChecks: true, featureNames };
304
141
  writeOutputs(planResult.plan, payloads, stdoutIdentity, identifiedInputs(inputsReadBy(args, NODE_INPUT_READER)));
305
- // Set after the report is written in full, never `process.exit`, so the buffered report is
306
- // flushed intact rather than truncated mid-write.
307
142
  const verdict = verdictCode({ ...balance, strict: ctx.strict === true });
308
143
  const code = statusFor(verdict, args["exit-zero"] !== undefined);
309
- // Assigned only when NON-ZERO, so a balanced run still LEAVES process.exitCode at its default
310
- // rather than writing a 0 over it — the distinction the balanced-exit scenarios rest on.
311
144
  if (code !== 0)
312
145
  process.exitCode = code;
313
146
  return true;
314
147
  }
315
- /**
316
- * Render-from-saved-JSON mode: the markdown a banked spec-reconciliation.json renders to, on
317
- * stdout, and the exit its saved verdict names — no reconcile, no live inputs. True when it
318
- * answered the run, so `runBalance` returns before any reconcile.
319
- */
320
148
  function renderSavedReport(args) {
321
- // Here rather than with the live-input guards, because this mode returns before they run.
322
149
  const ignoredFlagError = checkReRenderFlags(args);
323
150
  if (ignoredFlagError)
324
151
  refuse(ignoredFlagError);
@@ -341,57 +168,19 @@ function renderSavedReport(args) {
341
168
  process.exitCode = code;
342
169
  return true;
343
170
  }
344
- /**
345
- * The live-input guards, in the order they run: each halts at exit 2 BEFORE any reconcile,
346
- * because an input the tool cannot read is a usage error, never a verdict.
347
- */
348
171
  function refuseUnreadableInputs(args) {
349
- // Input-existence guard: a supplied input-file/dir flag pointing at a
350
- // non-existent path is a HARD ERROR — halt BEFORE reconciling, with a typed message
351
- // naming the flag + path, never the silent zero-evidence all-red report a mistyped
352
- // path used to produce (the dogfooding fault). Routed to stderr + a non-zero exit,
353
- // exactly as the legacy-`--json` guard (the shared typed-error surface). An
354
- // omitted flag is legitimately optional and passes through untouched.
355
172
  const missingInputError = checkInputsExist(args, existsSync);
356
173
  if (missingInputError)
357
174
  refuse(missingInputError);
358
- // Input-READABILITY guard: existence is not enough. A report that is
359
- // PRESENT but UNPARSEABLE (`--vitest /dev/null`, truncated JSON, non-JSON) used to throw
360
- // mid-parse inside reconcileWithCensus, uncaught — and Node's default exit code is 1, the
361
- // code reserved for a genuine OUT-OF-BALANCE verdict. So a tool that
362
- // CRASHED before reconciling was indistinguishable, by exit code, from an honest
363
- // disagreement. Runs immediately after the existence guard and BEFORE any
364
- // reconcile, routing to the same stderr + exit 2 lane: an input the tool cannot read is a
365
- // usage fault, sibling to a missing path and an unrecognised flag — never a verdict.
366
175
  const unparseableInputError = checkInputsParse(args, (path) => readFileSync(path, "utf8"));
367
176
  if (unparseableInputError)
368
177
  refuse(unparseableInputError);
369
- // A corpus or workflow path that is not the kind its flag reads, or may not be read, cannot be read at all.
370
178
  const unreadablePathError = checkInputPaths(args);
371
179
  if (unreadablePathError)
372
180
  refuse(unreadablePathError);
373
- // Parsing is not reading: a report that parses but is not in the shape its reader expects would
374
- // be read as nothing, or read until it threw, so it is refused here with where its shape is wrong.
375
181
  const misshapenInputError = checkInputShapes(jsonInputsOf(args, existsSync), (path) => readFileSync(path, "utf8"));
376
182
  if (misshapenInputError)
377
183
  refuse(misshapenInputError);
378
- // The FEATURE-CORPUS integrity checkpoint. The feature corpus is an
379
- // input too — the ledger's DEBIT side — and it was read by a hand-rolled TAG-LINE SCAN that
380
- // never consulted a parser. So a malformed tag line simply stopped being a tag line and its
381
- // scenario CEASED TO EXIST: one stray character deleted a failing row and turned an
382
- // out-of-balance run (exit 1) into a clean BALANCED (exit 0). A dropped scenario cannot even
383
- // reconcile `missing`, because it was never RAISED to be missing — the run read cleaner than
384
- // reality, the exact false-green this tool exists to prevent.
385
- //
386
- // Validated with the REAL Gherkin parser (cucumber's own), so a file the tool would reconcile is
387
- // at least a file cucumber would RUN. A file it rejects is an input we CANNOT READ: exit 2,
388
- // halting BEFORE any reconcile, naming the file and the parse failure — the same Rule as
389
- // the unparseable-report and unreadable-saved-report guards ("an input the tool cannot read is a usage error, never a
390
- // verdict"), now on the obligation side. Never a verdict, and never a green.
391
- //
392
- // The corpus is EXTRACTED from the same real AST, so what the tool reconciles is
393
- // what cucumber runs — Feature/Rule tag inheritance included. This guard decides whether the file
394
- // can be read at all; parseScenarios then reads it exactly as cucumber would.
395
184
  const featureParseErrors = featureCorpusParseErrors(args["features"]);
396
185
  if (featureParseErrors.length > 0) {
397
186
  refuse(featureParseErrors
@@ -399,13 +188,6 @@ function refuseUnreadableInputs(args) {
399
188
  .join("\n"));
400
189
  }
401
190
  }
402
- /**
403
- * Build the run provenance ONCE (project design §1) — a sibling RunContext, the
404
- * Ledger staying pure — reusing the existing runStart. The target is the
405
- * operator's --target VERBATIM (unknown-target on omit; Fork A — no
406
- * resolution, no basename guessing). Source SHA via the read-only target read, with
407
- * --source-sha as the override (resolveSourceSha).
408
- */
409
191
  function runContextOf(args, inputs, runStart) {
410
192
  return {
411
193
  target: sourceTarget(args),
@@ -415,23 +197,11 @@ function runContextOf(args, inputs, runStart) {
415
197
  sourceSha: args["source-sha"],
416
198
  targetDir: args["features"] !== undefined ? dirname(args["features"]) : undefined,
417
199
  }),
418
- // The TARGET repo root the recorded input paths are made portable against (fixed to
419
- // the target root, not the run cwd) — the SAME
420
- // root readEvidenceObservations passes to countRuntimeEvidenceObservationKinds, derived from
421
- // --features, so a cross-repo reconcile records inputs relative (`features`) rather
422
- // than leaking the target's absolute path.
423
200
  root: resolveTargetRoot({ features: inputs.features }),
424
- // The TOOL's own identity — which spec-controller produced
425
- // this run, distinct from the target's sourceSha. Read from the tool's OWN dir, never
426
- // cwd (which is the target). One call, spread into the ctx; the same identity feeds
427
- // the run.yaml manifest.
428
201
  ...resolveToolIdentity(),
429
202
  strict: args["strict"] !== undefined,
430
203
  };
431
204
  }
432
- // Only run the balance command when this module is executed directly
433
- // (`tsx cli-balance/cli.ts`), NOT when imported by the top-level `spec-controller`
434
- // bin dispatcher or by a test that exercises the pure edge guards.
435
205
  const invokedDirectly = process.argv[1] !== undefined && import.meta.url === `file://${process.argv[1]}`;
436
206
  if (invokedDirectly)
437
207
  runBalance(process.argv.slice(2));
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli-balance/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli-balance/cli.ts"],"names":[],"mappings":"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"}
@@ -1,47 +1,17 @@
1
- /**
2
- * The output PLAN — the pure app-layer parse+validate of the `--format <fmt>[:<path>]`
3
- * grammar (the three-layer split). Given the raw
4
- * `--format` specs (in argv order; empty when no flag was passed), `planOutput` returns
5
- * either an `OutputPlan` — an ordered list of `{ fmt, dest }` outputs — or a typed error.
6
- *
7
- * PURE: no IO. The plan describes WHAT to emit and WHERE; the writer (`writer.ts`) is the
8
- * only layer that performs the IO. This split lets `planOutput` be proven in isolation
9
- * (`@unit`, no subprocess) while the writer's real stdout/file effect is the `@integration`
10
- * arm — the anti-watermelon rule (each integration arm asserts the real IO, never a
11
- * planOutput re-run).
12
- *
13
- * FMT-001 (`@SCN-FMT-001`) establishes the skeleton: no flag — and an explicit `md` —
14
- * plan a single markdown output bound for stdout. Later sub-issues extend `planOutput`
15
- * with json (FMT-002), file dests (`<fmt>:<path>`, FMT-002/003), the at-most-one-to-stdout
16
- * invariant (FMT-005), the legacy-`--json` rejection (FMT-006), and unknown-format
17
- * rejection (FMT-007) — each landing on the `OutputPlan` type + typed `PlanResult` error
18
- * surface designed here.
19
- *
20
- * Parent: @SCN-FMT-001 — the output-dispatch rework.
21
- */
22
- /** A supported output format. FMT-001 plans `md`; `json` is wired in FMT-002. */
23
1
  export type OutputFormat = "md" | "json";
24
- /** Where a planned output is written — stdout, or a caller-given file path. */
25
2
  export type OutputDest = {
26
3
  readonly kind: "stdout";
27
4
  } | {
28
5
  readonly kind: "file";
29
6
  readonly path: string;
30
7
  };
31
- /** One planned output: a format routed to a destination. */
32
8
  export interface PlannedOutput {
33
9
  readonly fmt: OutputFormat;
34
10
  readonly dest: OutputDest;
35
11
  }
36
- /** The plan: the ordered outputs a single invocation will emit. */
37
12
  export interface OutputPlan {
38
13
  readonly outputs: readonly PlannedOutput[];
39
14
  }
40
- /**
41
- * The result of planning — either the plan, or a typed error carrying the operator-facing
42
- * message (later sub-issues raise these for the stdout-collision, legacy-flag, and
43
- * unknown-format cases). A discriminated union so the CLI branches on `ok`.
44
- */
45
15
  export type PlanResult = {
46
16
  readonly ok: true;
47
17
  readonly plan: OutputPlan;
@@ -49,42 +19,20 @@ export type PlanResult = {
49
19
  readonly ok: false;
50
20
  readonly error: string;
51
21
  };
52
- /**
53
- * Parse + validate the `--format` specs into an `OutputPlan` (or a typed error).
54
- *
55
- * FMT-001: no specs (no `--format` flag) defaults to a single `md`; an explicit `md`
56
- * plans the same. Each planned output is markdown bound for stdout — the default human
57
- * report, like vitest/cucumber.
58
- */
59
22
  export declare function planOutput(formatSpecs: readonly string[], namesStdout?: (path: string) => boolean): PlanResult;
60
- /** The operating system's identity for a regular file: its device and inode, exact beyond 2^53. */
61
23
  export interface FileIdentity {
62
24
  readonly dev: bigint;
63
25
  readonly ino: bigint;
64
26
  }
65
- /** A planned output beside the identity of the regular file it lands on, when it lands on one. */
66
27
  export interface IdentifiedOutput {
67
28
  readonly output: PlannedOutput;
68
29
  readonly identity: FileIdentity | undefined;
69
30
  }
70
- /**
71
- * The refusal for the first two outputs that land on one regular file, or undefined when none do.
72
- * The file is known by its identity rather than its spelling, so a link, a `..`, a case the volume
73
- * folds or the file standard output is redirected into all count. An output with no identity is
74
- * not on a regular file, and writing such a destination twice loses nothing, so it is never compared.
75
- */
76
31
  export declare function sharedFileRefusal(outputs: readonly IdentifiedOutput[]): string | undefined;
77
- /** A file the run reads, as the refusal names it, beside the identity of the regular file it is, when it is one. */
78
32
  export interface IdentifiedInput {
79
33
  readonly subject: string;
80
34
  readonly path: string;
81
35
  readonly identity: FileIdentity | undefined;
82
36
  }
83
- /**
84
- * The refusal for the first output that lands on a regular file the run reads, or undefined when none
85
- * does. The file is known by its identity, as two outputs sharing one are, so a link, a `..`, a case
86
- * the volume folds or standard output appended into an input all count. Something that is not a
87
- * regular file, on either side, is never compared.
88
- */
89
37
  export declare function inputOverwriteRefusal(outputs: readonly IdentifiedOutput[], inputs: readonly IdentifiedInput[]): string | undefined;
90
38
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/cli-balance/emit/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,MAAM,CAAC;AAczC,+EAA+E;AAC/E,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC5C;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,WAAW,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAqB,GACnD,UAAU,CA0DZ;AAED,mGAAmG;AACnG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,kGAAkG;AAClG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,GAAG,SAAS,CAY1F;AAED,oHAAoH;AACpH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,GAAG,SAAS,CAYlI"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/cli-balance/emit/format.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,MAAM,CAAC;AAQzC,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC5C;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,UAAU,CACxB,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,WAAW,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAqB,GACnD,UAAU,CAkCZ;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;CAC7C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,GAAG,SAAS,CAY1F;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;CAC7C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,GAAG,SAAS,CAYlI"}
@@ -1,63 +1,15 @@
1
- /**
2
- * The output PLAN — the pure app-layer parse+validate of the `--format <fmt>[:<path>]`
3
- * grammar (the three-layer split). Given the raw
4
- * `--format` specs (in argv order; empty when no flag was passed), `planOutput` returns
5
- * either an `OutputPlan` — an ordered list of `{ fmt, dest }` outputs — or a typed error.
6
- *
7
- * PURE: no IO. The plan describes WHAT to emit and WHERE; the writer (`writer.ts`) is the
8
- * only layer that performs the IO. This split lets `planOutput` be proven in isolation
9
- * (`@unit`, no subprocess) while the writer's real stdout/file effect is the `@integration`
10
- * arm — the anti-watermelon rule (each integration arm asserts the real IO, never a
11
- * planOutput re-run).
12
- *
13
- * FMT-001 (`@SCN-FMT-001`) establishes the skeleton: no flag — and an explicit `md` —
14
- * plan a single markdown output bound for stdout. Later sub-issues extend `planOutput`
15
- * with json (FMT-002), file dests (`<fmt>:<path>`, FMT-002/003), the at-most-one-to-stdout
16
- * invariant (FMT-005), the legacy-`--json` rejection (FMT-006), and unknown-format
17
- * rejection (FMT-007) — each landing on the `OutputPlan` type + typed `PlanResult` error
18
- * surface designed here.
19
- *
20
- * Parent: @SCN-FMT-001 — the output-dispatch rework.
21
- */
22
- /**
23
- * The formats `planOutput` accepts; any other `--format` token is rejected (FMT-007 /
24
- * @SCN-FMT-007). The single source of truth the unknown-format guard checks against AND
25
- * lists in its hint, so a future format (html, sarif) is added in exactly one place.
26
- */
27
1
  const SUPPORTED_FORMATS = ["md", "json"];
28
- /** Runtime narrowing of a parsed `--format` token to a supported `OutputFormat`. */
29
2
  function isSupportedFormat(fmt) {
30
3
  return SUPPORTED_FORMATS.includes(fmt);
31
4
  }
32
- /**
33
- * Parse + validate the `--format` specs into an `OutputPlan` (or a typed error).
34
- *
35
- * FMT-001: no specs (no `--format` flag) defaults to a single `md`; an explicit `md`
36
- * plans the same. Each planned output is markdown bound for stdout — the default human
37
- * report, like vitest/cucumber.
38
- */
39
5
  export function planOutput(formatSpecs, namesStdout = () => false) {
40
- // No --format flag defaults to a single "md" spec — the default human report.
41
6
  const specs = formatSpecs.length === 0 ? ["md"] : formatSpecs;
42
7
  const outputs = specs.map((spec) => {
43
- // Grammar: "<fmt>[:<path>]". Split on the FIRST colon — the fmt is everything before
44
- // it; a ":<path>" tail routes that format to the file at <path> (FMT-002/003), where
45
- // the path is everything after the first colon (so a path may itself contain colons).
46
- // No colon keeps the bare-fmt → stdout default (FMT-001). The at-most-one-to-stdout /
47
- // unknown-format validation (FMT-005/007) lands on this same parse and the typed
48
- // PlanResult error surface.
49
8
  const colon = spec.indexOf(":");
50
9
  const fmt = (colon === -1 ? spec : spec.slice(0, colon));
51
10
  const dest = colon === -1 ? { kind: "stdout" } : { kind: "file", path: spec.slice(colon + 1) };
52
11
  return { fmt, dest };
53
12
  });
54
- // The unknown-format guard (FMT-007 / @SCN-FMT-007): a
55
- // --format naming an unsupported format (e.g. `xml`, or a typo) is rejected fast on the
56
- // shared typed PlanResult error surface (the same surface FMT-005/006 use) — rather than
57
- // silently rendering as markdown (the writer's default render branch) and exiting 0. The
58
- // error LISTS the supported formats so the operator knows what to use — basic public-CLI
59
- // robustness. Checked BEFORE the stdout-collision count so an unroutable format is
60
- // reported as such (an unknown format can't meaningfully collide on stdout).
61
13
  const unknown = outputs.filter((o) => !isSupportedFormat(o.fmt));
62
14
  if (unknown.length > 0) {
63
15
  const bad = [...new Set(unknown.map((o) => o.fmt))].join(", ");
@@ -67,16 +19,6 @@ export function planOutput(formatSpecs, namesStdout = () => false) {
67
19
  `(e.g. --format md, --format json:report.json).`,
68
20
  };
69
21
  }
70
- // The stdout invariant (FMT-005 / @SCN-FMT-005): AT MOST
71
- // ONE output may route to stdout, so a captured stdout never carries two interleaved
72
- // documents. This is a COUNT check on the stdout-destined outputs (≤ 1) — NOT a
73
- // "distinct formats > 1" check — so `--format md --format md` (the same format twice,
74
- // both stdout) is rejected just as `--format md --format json` is; a distinct-formats
75
- // check would wrongly pass the former. Rejected with a typed error on the shared
76
- // PlanResult surface (the same surface FMT-006/007 raise), carrying the hint to give one
77
- // of the colliding outputs a `:<path>` so it writes to a file instead.
78
- // A path that names standard output itself (/dev/stdout, /dev/fd/1) routes there as surely as a
79
- // bare format does, so it is counted with the outputs bound for stdout.
80
22
  const stdoutBound = outputs.filter((o) => o.dest.kind === "stdout" || namesStdout(o.dest.path));
81
23
  if (stdoutBound.length > 1) {
82
24
  const fmts = stdoutBound.map((o) => o.fmt).join(", ");
@@ -89,12 +31,6 @@ export function planOutput(formatSpecs, namesStdout = () => false) {
89
31
  }
90
32
  return { ok: true, plan: { outputs } };
91
33
  }
92
- /**
93
- * The refusal for the first two outputs that land on one regular file, or undefined when none do.
94
- * The file is known by its identity rather than its spelling, so a link, a `..`, a case the volume
95
- * folds or the file standard output is redirected into all count. An output with no identity is
96
- * not on a regular file, and writing such a destination twice loses nothing, so it is never compared.
97
- */
98
34
  export function sharedFileRefusal(outputs) {
99
35
  const onFiles = outputs.filter((o) => o.identity !== undefined);
100
36
  for (const [index, first] of onFiles.entries()) {
@@ -106,12 +42,6 @@ export function sharedFileRefusal(outputs) {
106
42
  }
107
43
  return undefined;
108
44
  }
109
- /**
110
- * The refusal for the first output that lands on a regular file the run reads, or undefined when none
111
- * does. The file is known by its identity, as two outputs sharing one are, so a link, a `..`, a case
112
- * the volume folds or standard output appended into an input all count. Something that is not a
113
- * regular file, on either side, is never compared.
114
- */
115
45
  export function inputOverwriteRefusal(outputs, inputs) {
116
46
  for (const { output, identity } of outputs) {
117
47
  if (identity === undefined)