fallow 3.26.0 → 3.28.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.
package/capabilities.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.26.0",
3
+ "version": "3.28.0",
4
4
  "manifest_version": "1",
5
5
  "description": "Codebase analyzer for TypeScript/JavaScript: unused code, circular dependencies, code duplication, complexity hotspots, and architecture boundary violations",
6
6
  "global_flags": [
@@ -7262,7 +7262,7 @@
7262
7262
  ]
7263
7263
  },
7264
7264
  "plugins": {
7265
- "count": 126,
7265
+ "count": 127,
7266
7266
  "note": "Built-in framework plugins, auto-activated when their enabler dependency is present; run fallow list --plugins for the set active in a specific project",
7267
7267
  "names": [
7268
7268
  "nextjs",
@@ -7314,6 +7314,7 @@
7314
7314
  "rolldown",
7315
7315
  "rspack",
7316
7316
  "rsbuild",
7317
+ "module-federation",
7317
7318
  "tsup",
7318
7319
  "tsdown",
7319
7320
  "pkg-utils",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.26.0",
3
+ "version": "3.28.0",
4
4
  "mcpName": "io.github.fallow-rs/fallow",
5
5
  "description": "Codebase intelligence for TypeScript and JavaScript. Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift for humans, CI, and the agents writing your code. Zero-config framework support.",
6
6
  "license": "MIT",
@@ -85,17 +85,17 @@
85
85
  "detect-libc": "2.1.2"
86
86
  },
87
87
  "devDependencies": {
88
- "@tanstack/intent": "0.3.8"
88
+ "@tanstack/intent": "0.4.0"
89
89
  },
90
90
  "optionalDependencies": {
91
- "@fallow-cli/darwin-arm64": "3.26.0",
92
- "@fallow-cli/darwin-x64": "3.26.0",
93
- "@fallow-cli/linux-x64-gnu": "3.26.0",
94
- "@fallow-cli/linux-arm64-gnu": "3.26.0",
95
- "@fallow-cli/linux-x64-musl": "3.26.0",
96
- "@fallow-cli/linux-arm64-musl": "3.26.0",
97
- "@fallow-cli/win32-arm64-msvc": "3.26.0",
98
- "@fallow-cli/win32-x64-msvc": "3.26.0",
99
- "fallow-type-aware": "3.26.0"
91
+ "@fallow-cli/darwin-arm64": "3.28.0",
92
+ "@fallow-cli/darwin-x64": "3.28.0",
93
+ "@fallow-cli/linux-x64-gnu": "3.28.0",
94
+ "@fallow-cli/linux-arm64-gnu": "3.28.0",
95
+ "@fallow-cli/linux-x64-musl": "3.28.0",
96
+ "@fallow-cli/linux-arm64-musl": "3.28.0",
97
+ "@fallow-cli/win32-arm64-msvc": "3.28.0",
98
+ "@fallow-cli/win32-x64-msvc": "3.28.0",
99
+ "fallow-type-aware": "3.28.0"
100
100
  }
101
101
  }
package/schema.json CHANGED
@@ -363,7 +363,7 @@
363
363
  "default": false
364
364
  },
365
365
  "autoImports": {
366
- "description": "When true, drops Nuxt convention-based entry-pattern fallbacks: component fallbacks are dropped unless nuxt.config declares components:, and composable/util fallbacks are dropped unless it declares imports:, so genuinely-unreferenced convention files surface as unused-file. Boolean, defaults to false; set it for a Nuxt project that has explicitly configured its auto-import directories. Synthesis of auto-import graph edges (resolving `<Card />` or `useUserStore()` to their convention files) happens regardless of this flag.",
366
+ "description": "When true, drops Nuxt convention-based entry-pattern fallbacks so genuinely-unreferenced convention files surface as unused-file. Component fallbacks are kept when nuxt.config customizes components: in a way fallow does not model, and composable/util fallbacks are kept when it customizes imports:; a config that scans no more than the Nuxt defaults (components: false, components: [], components: { dirs: [] }, components: true, imports: { scan: false }, imports: {}, imports: { dirs: [] }) is treated like the default and its fallbacks are dropped; imports: { autoImport: false } on its own is not, because it only switches the injection off while the same directories stay registered behind #imports. A nuxt.config that carries any top-level key fallow cannot read statically, a computed key, an accessor, or a spread such as { ...base, devtools: {} }, keeps both surfaces' fallbacks for that root, because the spread may hold the keys that decide. Each root is classified on its own config, so one custom nuxt.config in a monorepo does not keep every other workspace's fallbacks. Component names follow Nuxt: a component under components/global or components/islands is named after its own directory (components/global/Foo.vue is `<Foo>`), and .client, .server, .global and .island suffixes are stripped. A name imported or re-exported by hand from #components or #imports credits its convention file just like a template tag or a bare call; a namespace import names nothing and credits nothing. Boolean, defaults to false; set it for a Nuxt project that has explicitly configured its auto-import directories. Synthesis of auto-import graph edges (resolving `<Card />` or `useUserStore()` to their convention files) happens regardless of this flag.",
367
367
  "type": "boolean",
368
368
  "default": false
369
369
  },
@@ -446,7 +446,7 @@ Human output groups paths under "Shared with your team (commit these)" and "Loca
446
446
  {
447
447
  "kind": "agent-install",
448
448
  "schema_version": 1,
449
- "fallow_version": "3.26.0",
449
+ "fallow_version": "3.28.0",
450
450
  "root": "/abs/path",
451
451
  "mode": "install",
452
452
  "dry_run": false,
@@ -650,7 +650,7 @@ fallow health --format json --quiet --trend
650
650
  {
651
651
  "kind": "health",
652
652
  "schema_version": 7,
653
- "version": "3.26.0",
653
+ "version": "3.28.0",
654
654
  "elapsed_ms": 32,
655
655
  "summary": {
656
656
  "files_analyzed": 482,
@@ -1053,7 +1053,7 @@ fallow audit \
1053
1053
  {
1054
1054
  "kind": "audit",
1055
1055
  "schema_version": 7,
1056
- "version": "3.26.0",
1056
+ "version": "3.28.0",
1057
1057
  "command": "audit",
1058
1058
  "verdict": "fail",
1059
1059
  "changed_files_count": 12,
@@ -1130,7 +1130,7 @@ fallow flags --format json --quiet --workspace my-package
1130
1130
  ```json
1131
1131
  {
1132
1132
  "schema_version": 7,
1133
- "version": "3.26.0",
1133
+ "version": "3.28.0",
1134
1134
  "elapsed_ms": 116,
1135
1135
  "feature_flags": [],
1136
1136
  "total_flags": 0
@@ -1231,7 +1231,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1231
1231
  {
1232
1232
  "kind": "security",
1233
1233
  "schema_version": "4",
1234
- "version": "3.26.0",
1234
+ "version": "3.28.0",
1235
1235
  "elapsed_ms": 42,
1236
1236
  "config": {
1237
1237
  "rules": {
@@ -1260,7 +1260,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1260
1260
  {
1261
1261
  "kind": "security",
1262
1262
  "schema_version": "4",
1263
- "version": "3.26.0",
1263
+ "version": "3.28.0",
1264
1264
  "elapsed_ms": 42,
1265
1265
  "config": {
1266
1266
  "rules": {
@@ -2030,7 +2030,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
2030
2030
  {
2031
2031
  "kind": "dead-code",
2032
2032
  "schema_version": 7,
2033
- "version": "3.26.0",
2033
+ "version": "3.28.0",
2034
2034
  "elapsed_ms": 45,
2035
2035
  "total_issues": 12,
2036
2036
  "entry_points": {
@@ -2190,7 +2190,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
2190
2190
  {
2191
2191
  "kind": "dupes",
2192
2192
  "schema_version": 7,
2193
- "version": "3.26.0",
2193
+ "version": "3.28.0",
2194
2194
  "elapsed_ms": 82,
2195
2195
  "total_clones": 15,
2196
2196
  "total_lines_duplicated": 230,
@@ -2234,11 +2234,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
2234
2234
  {
2235
2235
  "kind": "combined",
2236
2236
  "schema_version": 7,
2237
- "version": "3.26.0",
2237
+ "version": "3.28.0",
2238
2238
  "elapsed_ms": 159,
2239
2239
  "check": {
2240
2240
  "schema_version": 7,
2241
- "version": "3.26.0",
2241
+ "version": "3.28.0",
2242
2242
  "elapsed_ms": 45,
2243
2243
  "total_issues": 12,
2244
2244
  "unused_files": [],
@@ -2376,8 +2376,10 @@ Config files are searched in priority order: `.fallowrc.json` > `.fallowrc.jsonc
2376
2376
  // Resolve framework convention auto-imports (Nuxt components) as graph edges.
2377
2377
  // Edges for `<Card001 />`-style template tags are always synthesized; setting
2378
2378
  // this to true also drops the Nuxt component entry patterns so an
2379
- // unreferenced component is reported as unused-file. Kept conservative: a
2380
- // `components:` key in nuxt.config keeps the entry patterns. Default false.
2379
+ // unreferenced component is reported as unused-file. Kept conservative: an
2380
+ // unmodelled `components:` or `imports:` config keeps the entry patterns, but
2381
+ // a config that switches the scan off (`components: { dirs: [] }`,
2382
+ // `imports: { scan: false }`) is treated like the default. Default false.
2381
2383
  "autoImports": false,
2382
2384
 
2383
2385
  // Production mode
@@ -135,6 +135,16 @@ export type ElapsedMs = number
135
135
  * Value of `audit.gate`: which findings drive the `fallow audit` verdict.
136
136
  */
137
137
  export type AuditGate = ("new-only" | "all")
138
+ /**
139
+ * What a gate concluded on this run.
140
+ *
141
+ * Four-valued rather than a boolean because audit's verdict has a warn tier
142
+ * (`crates/cli/src/cli_report.rs` maps it onto three conclusions) and because
143
+ * a gate can stand down without passing. Widening a published boolean later
144
+ * would retype a required field and bump every carrying envelope, so the width
145
+ * is decided here.
146
+ */
147
+ export type GateStatus = ("pass" | "warn" | "fail" | "skipped")
138
148
  /**
139
149
  * Analysis mode stored with baselines, snapshots, audit sides, and impact data.
140
150
  */
@@ -402,6 +412,30 @@ export type DependencyOverrideSource = ("pnpm-workspace.yaml" | "package.json")
402
412
  * surfacing them statically catches the issue first.
403
413
  */
404
414
  export type DependencyOverrideMisconfigReason = ("unparsable-key" | "empty-value")
415
+ /**
416
+ * Which advisory a loaded baseline earned on this run.
417
+ *
418
+ * Mirrors `fallow_engine::baseline::BaselineStalenessWarning` so a consumer can
419
+ * render the same distinction the stderr warning makes, instead of inferring it
420
+ * from counts.
421
+ */
422
+ export type BaselineStalenessAdvisory = ("none" | "zero-overlap" | "partial")
423
+ /**
424
+ * One channel that narrowed a run to part of the project.
425
+ *
426
+ * Serialized as kebab-case inside `scope_reasons` and published as an OPEN
427
+ * set, the same tolerate-unknown contract `gate_outcomes` keys carry: a name
428
+ * this build does not emit means "some narrowing", not an error.
429
+ *
430
+ * Which names a command can emit differs per command, because the three
431
+ * narrowing predicates see different state. `dead-code` reads the flags
432
+ * themselves and can name every channel. `dupes` and `health` see an already
433
+ * resolved changed-file set and report `changed-files`, because at that point
434
+ * the flag that produced it is gone. `health` reports `workspace` for both
435
+ * `--workspace` and `--changed-workspaces` for the same reason. A consumer
436
+ * must therefore not assume a given command emits a given name.
437
+ */
438
+ export type ScopeReason = ("diff" | "changed-since" | "changed-files" | "workspace" | "changed-workspaces" | "scope" | "file" | "issue-type-filter" | "production")
405
439
  /**
406
440
  * Status of a regression-check pass.
407
441
  */
@@ -410,6 +444,29 @@ export type RegressionStatus = ("pass" | "exceeded" | "skipped")
410
444
  * Interpretation of [`RegressionResult::tolerance`].
411
445
  */
412
446
  export type RegressionToleranceKind = ("absolute" | "percentage")
447
+ /**
448
+ * What became of one request on this run.
449
+ *
450
+ * Two-valued today. The value set is OPEN so a later `partial` needs no bump,
451
+ * and it is deliberately not added now: nothing emits it, and a permanently
452
+ * unused value reads as a measurement nobody takes.
453
+ */
454
+ export type RequestStatus = ("applied" | "not-applied")
455
+ /**
456
+ * What a request governs, and therefore what its failure means.
457
+ *
458
+ * Published on every entry so a consumer selects on the class rather than on
459
+ * a name list. Without it the one sentence a consumer can write for the whole
460
+ * object ("the report is wider than requested") is false for any request that
461
+ * does not narrow, which is how a failed `--sarif-file` write came to be
462
+ * reported as an unscoped run. A request name added later carries its own
463
+ * class, so a consumer written today keeps saying the right thing about it.
464
+ *
465
+ * The value set is OPEN, like the names and the statuses: read a class this
466
+ * build does not recognise as "some request", not as an error, and do not read
467
+ * it as `scope`.
468
+ */
469
+ export type RequestEffect = ("scope" | "artifact")
413
470
  /**
414
471
  * A diagnostic about a workspace-discovery candidate.
415
472
  *
@@ -428,6 +485,25 @@ path: string
428
485
  * with a next-step hint.
429
486
  */
430
487
  message: string
488
+ /**
489
+ * True when this diagnostic reports a run whose RESULTS are degraded:
490
+ * something the user installed, wrote, or expected did not reach the
491
+ * analysis. Projected from [`WorkspaceDiagnosticKind::warns_on_stderr`],
492
+ * which is the same classification that decides whether the CLI prints a
493
+ * stderr line, so a CI log built from this field and a local non-quiet run
494
+ * say the same thing.
495
+ *
496
+ * Omitted when false, which is what keeps every clean run byte-identical.
497
+ * The two unconfigured-check kinds answer false on purpose: they fire in
498
+ * the product's default state on every project that never opted into
499
+ * boundaries or rule packs, so warning on them would warn forever. So does
500
+ * `excluded-by-default-ignore`, which is designed behavior on generated
501
+ * output; the alarm for that case is `no-source-files-analyzed`.
502
+ *
503
+ * Read this instead of hardcoding a kind allowlist: a degrading kind added
504
+ * in a later release then reaches an unchanged consumer.
505
+ */
506
+ degrades_analysis?: boolean
431
507
  } & WorkspaceDiagnostic1)
432
508
  export type WorkspaceDiagnostic1 = ({
433
509
  kind: "undeclared-workspace"
@@ -525,6 +601,105 @@ file_count: number
525
601
  */
526
602
  directory_count: number
527
603
  kind: "excluded-by-default-ignore"
604
+ } | {
605
+ /**
606
+ * Candidate source files the built-in ignore patterns removed from
607
+ * this walk, summed across every pattern. `0` when the walk found no
608
+ * candidate to exclude in the first place.
609
+ */
610
+ excluded_file_count: number
611
+ kind: "no-source-files-analyzed"
612
+ } | {
613
+ /**
614
+ * Scoring error text.
615
+ */
616
+ error: string
617
+ kind: "file-scores-unavailable"
618
+ } | {
619
+ /**
620
+ * Which input stopped it, as a kebab-case token: `not-a-repository`,
621
+ * `invalid-since` or `churn-file-unreadable`. The set is open.
622
+ *
623
+ * The cause decides the remedy, which is why it is on the wire: a run
624
+ * outside a repository is fixed by running fallow inside one, a
625
+ * malformed `--since` by respelling the flag, and a churn file that
626
+ * changed under the run by rerunning it. A consumer reading only the
627
+ * kind would offer the first remedy for all three.
628
+ */
629
+ cause: string
630
+ kind: "hotspots-skipped"
631
+ } | {
632
+ /**
633
+ * `true` when the run also asked for ownership attribution, which a
634
+ * shallow clone skews further by inflating single-author dominance.
635
+ */
636
+ ownership_requested: boolean
637
+ kind: "shallow-clone"
638
+ } | {
639
+ kind: "unpinned-clock"
640
+ } | {
641
+ /**
642
+ * Which input failed, as a kebab-case token: `invalid-bot-pattern` or
643
+ * `codeowners-parse-failed`. The set is open.
644
+ */
645
+ cause: string
646
+ /**
647
+ * Underlying error text.
648
+ */
649
+ error: string
650
+ kind: "ownership-unavailable"
651
+ } | {
652
+ /**
653
+ * Filesystem or JSON error text.
654
+ */
655
+ error: string
656
+ kind: "trend-snapshot-unreadable"
657
+ } | {
658
+ /**
659
+ * The plugin that read the config, as it labels itself:
660
+ * `module-federation` for a standalone `module-federation.config.*`,
661
+ * or the bundler plugin (`webpack`, `rspack`, `rsbuild`, `vite`) that
662
+ * read the same options inline from its own config.
663
+ */
664
+ plugin: string
665
+ /**
666
+ * The config key that was present and not fully readable (`exposes`,
667
+ * `remotes`). The set is open.
668
+ */
669
+ key: string
670
+ /**
671
+ * Why it could not be read, as a kebab-case token:
672
+ * `not-object-literal`, `array-form`, `spread` or
673
+ * `unreadable-entries`. The set is open.
674
+ *
675
+ * The reason decides the remedy, which is why it is on the wire: a
676
+ * value that is not an object literal is fixed by writing one, while
677
+ * unreadable entries are fixed by naming those entries in the config
678
+ * option the message points at.
679
+ */
680
+ reason: string
681
+ kind: "plugin-config-unreadable"
682
+ } | {
683
+ /**
684
+ * The plugin that read the config, as it labels itself (`nuxt`).
685
+ */
686
+ plugin: string
687
+ /**
688
+ * The config key whose effect is not modeled (`components`,
689
+ * `imports`). The set is open.
690
+ */
691
+ key: string
692
+ /**
693
+ * Why the effect is not modeled, as a kebab-case token:
694
+ * `key-effect-not-modeled` when the key's own value is the reason,
695
+ * `config-property-unreadable` when a top-level property of the same
696
+ * config file could not be read statically, so no surface in it can
697
+ * be classified at all. The set is open.
698
+ */
699
+ reason: string
700
+ kind: "plugin-effect-not-modeled"
701
+ } | {
702
+ kind: "coverage-auto-detected"
528
703
  })
529
704
  /**
530
705
  * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types
@@ -1311,6 +1486,16 @@ elapsed_ms: ElapsedMs
1311
1486
  base_snapshot_skipped?: (boolean | null)
1312
1487
  summary: AuditSummary
1313
1488
  attribution: AuditAttribution
1489
+ /**
1490
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
1491
+ * Each entry is the same rule that decides the exit code, so a CI
1492
+ * integration reads the verdict instead of guessing from a process status
1493
+ * it usually cannot see. A gate fails the build when `status` is `fail`
1494
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
1495
+ * rules fail a run with no flag at all, so an absent object means "no gate
1496
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
1497
+ */
1498
+ gate_outcomes?: (GateOutcomes | null)
1314
1499
  /**
1315
1500
  * `_meta` block with metric / rule definitions, when `--explain` was
1316
1501
  * passed.
@@ -1393,6 +1578,78 @@ styling_introduced: number
1393
1578
  styling_inherited: number
1394
1579
  duplication_demoted: number
1395
1580
  }
1581
+ /**
1582
+ * Every gate a run ARMED, keyed by name.
1583
+ *
1584
+ * Armed, not evaluated: a gate is armed by a flag or by config, never merely
1585
+ * because the rule behind it exists. Fallow's default severity rules fail a
1586
+ * run with no flag at all, so a `dead-code` run can exit 1 carrying no object
1587
+ * whatsoever. Read an absent object as "no gate was asked for", never as
1588
+ * "nothing failed".
1589
+ *
1590
+ * Absent from an envelope whenever it is empty, so a run that armed no gate is
1591
+ * byte-identical to one produced before this object existed. An empty object
1592
+ * is never emitted: it would assert that gates were armed and none tripped,
1593
+ * which is a different and false claim.
1594
+ *
1595
+ * The names this build can emit are `error-severity-findings`, `regression`,
1596
+ * `stale-baseline`, `duplication-threshold`, `health-min-score`,
1597
+ * `health-min-severity`, `health-findings`, `health-coverage-gaps`,
1598
+ * `health-runtime-coverage`, `security`, `security-advisory`, `audit-verdict`
1599
+ * and `type-aware-require`. The set is OPEN: a name a consumer does not
1600
+ * recognise means "some gate", not an error.
1601
+ */
1602
+ export interface GateOutcomes {
1603
+ [k: string]: GateOutcome
1604
+ }
1605
+ /**
1606
+ * One gate's verdict on one run.
1607
+ *
1608
+ * `status` and `enforced` answer different questions and legitimately
1609
+ * disagree. `status` is what the rule concluded; `enforced` is whether a
1610
+ * `fail` from this gate would make the run exit non-zero. A
1611
+ * `health --report-only` run is an explicit request never to fail, so a
1612
+ * failing gate there reports `status: fail` with `enforced: false`, and a
1613
+ * stale-baseline verdict published without `--fail-on-stale-baseline` reports
1614
+ * the same pair.
1615
+ *
1616
+ * **A gate fails the build when `status` is `fail` AND `enforced` is true.**
1617
+ * Neither member decides it alone: `enforced` is true on every armed gate,
1618
+ * including the ones that passed, so gating on it by itself fails every run
1619
+ * that armed anything. Read `status` on its own to decide what to say, and
1620
+ * remember that `warn` and `skipped` are neither a pass nor a failure.
1621
+ */
1622
+ export interface GateOutcome {
1623
+ status: GateStatus
1624
+ /**
1625
+ * True when a `fail` from this gate makes the run exit non-zero. False
1626
+ * when the verdict is published for information only, because the gate was
1627
+ * never armed or because the run was told never to fail.
1628
+ */
1629
+ enforced: boolean
1630
+ /**
1631
+ * The measured value the gate compared, when there is one: the duplication
1632
+ * percentage, the health score, or the number of findings at or above the
1633
+ * severity floor. Whole numbers are carried as JSON numbers, so a count of
1634
+ * three reads as `3.0`. Absent for gates that compare no number.
1635
+ */
1636
+ observed?: (number | null)
1637
+ /**
1638
+ * The configured limit `observed` was compared against, when there is one.
1639
+ * Absent for gates that compare no number.
1640
+ */
1641
+ threshold?: (number | null)
1642
+ /**
1643
+ * How the limit was spelled, for a gate whose `threshold` number does not
1644
+ * carry its own unit. `health-min-severity` sets it to the severity floor
1645
+ * (`moderate`, `high` or `critical`); `regression` sets it to the
1646
+ * tolerance as the user wrote it (`"50%"` or `"5"`), because `threshold`
1647
+ * there is the allowance in issues and the percentage would otherwise be
1648
+ * unrecoverable on the grouped envelope, which carries no `regression`
1649
+ * object. Absent for gates whose numbers speak for themselves.
1650
+ */
1651
+ threshold_label?: (string | null)
1652
+ }
1396
1653
  /**
1397
1654
  * Metric and rule definitions emitted under `_meta` when `--explain` is
1398
1655
  * passed (always present in MCP responses). Helps AI agents and CI systems
@@ -2670,10 +2927,39 @@ baseline_deltas?: (BaselineDeltas | null)
2670
2927
  * Which baseline snapshot was matched, in baseline runs.
2671
2928
  */
2672
2929
  baseline?: (BaselineMatch | null)
2930
+ /**
2931
+ * This run's view of the loaded baseline, present only in baseline runs.
2932
+ * Carries the staleness counts, the advisory verdict and `gate_trips`, the
2933
+ * same boolean `--fail-on-stale-baseline` exits on, so a CI integration
2934
+ * reads one field instead of restating the rule. Read `change_scoped`
2935
+ * before dividing `matched_entries` by `baseline_entries`: a narrowed run
2936
+ * can report `matched_entries: 0` on a healthy baseline.
2937
+ */
2938
+ baseline_staleness?: (BaselineStaleness | null)
2673
2939
  /**
2674
2940
  * Regression verdict against the baseline, in `--fail-on-regression` runs.
2675
2941
  */
2676
2942
  regression?: (RegressionResult | null)
2943
+ /**
2944
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
2945
+ * Each entry is the same rule that decides the exit code, so a CI
2946
+ * integration reads the verdict instead of guessing from a process status
2947
+ * it usually cannot see. A gate fails the build when `status` is `fail`
2948
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
2949
+ * rules fail a run with no flag at all, so an absent object means "no gate
2950
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
2951
+ */
2952
+ gate_outcomes?: (GateOutcomes | null)
2953
+ /**
2954
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
2955
+ * absent when it was asked for nothing. An entry whose `status` is not
2956
+ * `applied` means the run could not do what it was asked and reported
2957
+ * something WIDER instead, so what follows is a valid report of a scope
2958
+ * nobody requested. Honoured requests are published too, with
2959
+ * `status: "applied"`, so an absent object means "nothing was asked for",
2960
+ * never "nothing failed". See [`crate::RequestOutcomes`].
2961
+ */
2962
+ request_outcomes?: (RequestOutcomes | null)
2677
2963
  /**
2678
2964
  * `_meta` block with docs and rule definitions, when `--explain` was
2679
2965
  * passed.
@@ -2692,10 +2978,12 @@ _meta?: (Meta | null)
2692
2978
  * `source-parse-degraded`;
2693
2979
  * - dead-code analysis, from the dependency-catalog and override
2694
2980
  * detectors: `malformed-pnpm-workspace-yaml`,
2695
- * `bun-lockb-override-resolution-skipped`.
2981
+ * `bun-lockb-override-resolution-skipped`;
2982
+ * - framework plugins, while they read their own build configs:
2983
+ * `plugin-config-unreadable`, `plugin-effect-not-modeled`.
2696
2984
  *
2697
- * Analysis-stage kinds therefore reach only the envelopes whose run
2698
- * includes a dead-code analyze pass, never a standalone
2985
+ * Analysis-stage and plugin-stage kinds therefore reach only the envelopes
2986
+ * whose run includes a dead-code analyze pass, never a standalone
2699
2987
  * `fallow dupes --format json`. `path` is project-root-relative with
2700
2988
  * forward slashes; the array is omitted when empty. The same list is
2701
2989
  * repeated on each top-level command's envelope so single-command
@@ -5092,6 +5380,126 @@ entries: number
5092
5380
  */
5093
5381
  matched: number
5094
5382
  }
5383
+ /**
5384
+ * One run's machine-readable view of a loaded baseline.
5385
+ *
5386
+ * `stale` and `gate_trips` answer different questions and legitimately
5387
+ * disagree. `stale` mirrors the unasked-for stderr advisory, which stays silent
5388
+ * below a quarter of the baseline and on a run that produced no findings at
5389
+ * all, because a cleaned project and a rotted baseline look identical from
5390
+ * there. `gate_trips` mirrors the opt-in `--fail-on-stale-baseline` rule, which
5391
+ * a repository asks for precisely to catch those cases, so it fires on any
5392
+ * stale entry. A rotted baseline on a cleaned project reports
5393
+ * `stale: false` with `gate_trips: true`; that is the contract, not a defect.
5394
+ *
5395
+ * `change_scoped` is the member a consumer must read before dividing
5396
+ * `matched_entries` by `baseline_entries`. A run narrowed to part of the
5397
+ * project compares a whole-project baseline against a slice of it and can
5398
+ * report `matched_entries: 0` while the baseline is perfectly healthy, so both
5399
+ * `stale` and `gate_trips` are false there by construction. The remedy for a
5400
+ * tripped gate is always the same: re-save the baseline from a whole-project
5401
+ * run with `--save-baseline`.
5402
+ */
5403
+ export interface BaselineStaleness {
5404
+ /**
5405
+ * Entries carried by the loaded baseline file. On health these are the
5406
+ * complexity and CRAP finding entries; runtime-coverage suppressions and
5407
+ * refactoring target keys carried by the same file are not counted.
5408
+ */
5409
+ baseline_entries: number
5410
+ /**
5411
+ * Entries that matched a current finding on this run and were filtered out
5412
+ * of the report. On health this includes entries matched through a
5413
+ * followed file move.
5414
+ */
5415
+ matched_entries: number
5416
+ /**
5417
+ * Entries that matched no current finding on this run:
5418
+ * `baseline_entries - matched_entries`.
5419
+ */
5420
+ stale_entries: number
5421
+ /**
5422
+ * Findings this run produced before the baseline filtered them. Zero means
5423
+ * there was nothing to compare, either because the project is clean or
5424
+ * because the scope was empty, which is why `stale` stays false there even
5425
+ * when every entry went unmatched.
5426
+ */
5427
+ current_findings: number
5428
+ /**
5429
+ * True when this run analyzed only part of the project, so a whole-project
5430
+ * baseline matches less of it for reasons that are not rot. The channels
5431
+ * differ per command and include a diff, a base ref, `--changed-since`,
5432
+ * `--workspace`, `--changed-workspaces`, `--scope`, `--file`, an
5433
+ * issue-type filter, and production mode. Both `stale` and `gate_trips`
5434
+ * are false whenever this is true. `scope_reasons` names the channels
5435
+ * that fired.
5436
+ */
5437
+ change_scoped: boolean
5438
+ /**
5439
+ * True exactly when the advisory stderr warning fired: not change-scoped,
5440
+ * at least one current finding before baseline filtering, and either
5441
+ * nothing matched or `stale_entries` reached a quarter of
5442
+ * `baseline_entries`.
5443
+ */
5444
+ stale: boolean
5445
+ warning: BaselineStalenessAdvisory
5446
+ /**
5447
+ * True exactly when `unrecognised_format` is true, or
5448
+ * `!change_scoped && baseline_entries > 0 && matched_entries < baseline_entries`.
5449
+ * That is the rule `--fail-on-stale-baseline` applies. Deliberately
5450
+ * stricter than `stale`: any unmatched entry counts, and so does a file
5451
+ * this command could not read as its own, which protects nothing at all.
5452
+ * The second half is suppressed by `change_scoped` and the first is not:
5453
+ * which command wrote a file does not depend on how much of the project
5454
+ * the run looked at.
5455
+ *
5456
+ * It describes the baseline, not the run's exit code: `health
5457
+ * --report-only` is an explicit request never to fail, so that run exits 0
5458
+ * and says so on stderr while still reporting `gate_trips: true` here, and
5459
+ * `fallow audit` never judges a baseline at all, so its
5460
+ * `gate_outcomes["stale-baseline"]` stands down beside a section that
5461
+ * reports `true`.
5462
+ */
5463
+ gate_trips: boolean
5464
+ /**
5465
+ * Entries that matched only by following a file move. Only `health` can
5466
+ * follow one, in its identity baseline mode; `dead-code` and `dupes` match
5467
+ * entries by fingerprint and never classify one as moved, so they report
5468
+ * `0`. Always `0` in health's count mode too.
5469
+ */
5470
+ moved_entries: number
5471
+ /**
5472
+ * True when the loaded file is not a baseline of the command that read it:
5473
+ * it names another command in its top-level `kind`, or it names none and
5474
+ * carries no key this command's own format writes. Read this, not
5475
+ * `baseline_entries == 0`, before telling anyone their baseline is the
5476
+ * wrong file: a baseline saved from a project that had nothing to record
5477
+ * is legitimately empty and is not a mistake.
5478
+ *
5479
+ * Present only when true, so an envelope from a run that loaded its own
5480
+ * baseline is unchanged. All three commands set it, including `dead-code`,
5481
+ * which classifies the file before its required fields could reject it.
5482
+ * A file with no `kind` is the reading a baseline saved before that member
5483
+ * existed gets, which is why the keys remain the fallback.
5484
+ */
5485
+ unrecognised_format?: boolean
5486
+ /**
5487
+ * Which channels narrowed this run, present and non-empty exactly when
5488
+ * `change_scoped` is true. Both members are derived from one function, so
5489
+ * the boolean and the array cannot disagree.
5490
+ *
5491
+ * Read it to decide whether the narrowing is removable: a run narrowed
5492
+ * only by `diff`, `changed-since`, `changed-files`, `scope`, `file` or
5493
+ * `issue-type-filter` can be repeated unscoped to judge the baseline,
5494
+ * while `production`, `workspace` and `changed-workspaces` are the
5495
+ * caller's own choice about what to analyze and an unscoped repeat would
5496
+ * contradict it.
5497
+ *
5498
+ * The name set is OPEN and the names a command can emit differ per
5499
+ * command; see [`ScopeReason`].
5500
+ */
5501
+ scope_reasons?: ScopeReason[]
5502
+ }
5095
5503
  /**
5096
5504
  * Result of regression detection (`--fail-on-regression`). Compares current
5097
5505
  * issue counts against a baseline from config or an explicit file.
@@ -5128,6 +5536,102 @@ exceeded: boolean
5128
5536
  */
5129
5537
  reason?: (string | null)
5130
5538
  }
5539
+ /**
5540
+ * Every narrowing or shaping request a run RECEIVED, keyed by name.
5541
+ *
5542
+ * Received, not failed: a request the run honoured is published with
5543
+ * `status: "applied"`, so a consumer can say "scoped to the change"
5544
+ * positively. Read an absent object as "nothing was asked for", never as
5545
+ * "nothing failed".
5546
+ *
5547
+ * Absent from an envelope whenever it is empty, so a run that was asked for
5548
+ * nothing is byte-identical to one produced before this object existed. An
5549
+ * empty object is never emitted: it would assert that something was asked and
5550
+ * all of it applied, which is a different and false claim.
5551
+ *
5552
+ * The names this build can emit are `changed-since`, `diff-filter` and
5553
+ * `sarif-file`. The reasons are `git-missing`, `not-a-repository`,
5554
+ * `git-failed` and `invalid-ref` for `changed-since`, `oversize`,
5555
+ * `unreadable`, `not-utf8`, `foreign-namespace` and `ambiguous-base` for
5556
+ * `diff-filter`, and `directory-create-failed`, `write-failed` and
5557
+ * `serialize-failed` for `sarif-file`. Every set is OPEN: a name a consumer
5558
+ * does not recognise means "some request", not an error.
5559
+ *
5560
+ * `sarif-file` reports a SECONDARY artifact rather than the scope of the
5561
+ * report it travels in, and it is in the same object for the same reason the
5562
+ * others are: the run was asked to do something and did something else, and
5563
+ * nothing in the primary report says so. Which of the two an entry is, every
5564
+ * entry says for itself: `affects` is `scope` for the narrowing requests and
5565
+ * `artifact` for this one. Select on it. A consumer that instead assumes the
5566
+ * whole object narrows the report tells its reader an unwritten SARIF file
5567
+ * widened the analysis, which is what `affects` exists to prevent.
5568
+ *
5569
+ * `scope_size` is emitted for `diff-filter` only today, in added lines. A
5570
+ * consumer reads the unit off the name, so a name that starts measuring its
5571
+ * own scope in a later release needs no change here.
5572
+ *
5573
+ * `invalid-ref` is reachable only through the programmatic API. The
5574
+ * `--changed-since` flag validates its value before a run starts and fails
5575
+ * with exit 2 and an error document, which is the right side to err on: a
5576
+ * malformed ref is invalid input rather than a report of the wrong scope.
5577
+ */
5578
+ export interface RequestOutcomes {
5579
+ [k: string]: RequestOutcome
5580
+ }
5581
+ /**
5582
+ * One request's fate on one run.
5583
+ *
5584
+ * `reason` and `message` are present exactly when `status` is not `applied`,
5585
+ * and absent otherwise, so a consumer that only wants to know whether a
5586
+ * report is scoped reads `status` alone.
5587
+ */
5588
+ export interface RequestOutcome {
5589
+ status: RequestStatus
5590
+ affects: RequestEffect
5591
+ /**
5592
+ * What was asked, as the user spelled it: the git ref for
5593
+ * `changed-since`, the diff source label (`--diff-file pr.diff`,
5594
+ * `--diff-stdin`, `$FALLOW_DIFF_FILE build/pr.diff`) for `diff-filter`,
5595
+ * the target path for `sarif-file`. Echoed rather than normalised, so a
5596
+ * consumer must not join it to the project root the way it joins every
5597
+ * other path-shaped field.
5598
+ */
5599
+ requested: string
5600
+ /**
5601
+ * How much this request left in scope, in the request's own unit, when the
5602
+ * run applied it AND measured that scope. Absent otherwise, including on
5603
+ * every unapplied entry: a request that stood down narrowed nothing, so a
5604
+ * number there would describe a scope nobody applied.
5605
+ *
5606
+ * The unit belongs to the name. `diff-filter` counts added lines, which is
5607
+ * what its filter keeps a finding for. Read the unit off the name the entry
5608
+ * is keyed under, never across names, and read an absent member as "not
5609
+ * measured" rather than as zero.
5610
+ *
5611
+ * The count is what the run INDEXED rather than the true total:
5612
+ * `diff-filter` indexes at most one million added lines and reports that
5613
+ * cap for a larger diff, so read any non-zero value as a lower bound.
5614
+ *
5615
+ * `0` is the case this member exists for: a request that applied over an
5616
+ * EMPTY scope. Every finding then filters out and the report reads clean,
5617
+ * so a consumer that sees no findings beside `scope_size: 0` learns that
5618
+ * nothing was analyzable rather than that the code is clean.
5619
+ */
5620
+ scope_size?: (number | null)
5621
+ /**
5622
+ * Why the request was not applied, as a kebab-case token. Present exactly
5623
+ * when `status` is not `applied`. The set is open per request name; the
5624
+ * names this build can emit are listed on [`RequestOutcomes`].
5625
+ */
5626
+ reason?: (string | null)
5627
+ /**
5628
+ * One sentence naming what was asked, what happened instead, and the next
5629
+ * step. Byte-identical to the stderr line for the same case, so a
5630
+ * consumer that renders this never contradicts a log a human read.
5631
+ * Present exactly when `status` is not `applied`.
5632
+ */
5633
+ message?: (string | null)
5634
+ }
5131
5635
  /**
5132
5636
  * A read-only follow-up command fallow surfaces from the current findings,
5133
5637
  * emitted as the top-level `next_steps` array on each command's JSON envelope.
@@ -6040,51 +6544,7 @@ severity_moderate_count: number
6040
6544
  /**
6041
6545
  * Baseline staleness data, present only when a baseline was loaded.
6042
6546
  */
6043
- baseline_staleness?: (HealthBaselineStaleness | null)
6044
- }
6045
- /**
6046
- * Staleness of a loaded health baseline.
6047
- *
6048
- * Reports how many saved complexity and CRAP finding entries still matched a
6049
- * current finding on this run, so consumers can see a rotting baseline before
6050
- * it degrades to zero overlap. Runtime-coverage suppressions and refactoring
6051
- * target keys carried by the same baseline are not counted here. Present in
6052
- * the summary only when a baseline was loaded.
6053
- */
6054
- export interface HealthBaselineStaleness {
6055
- /**
6056
- * Complexity and CRAP finding entries carried by the loaded baseline.
6057
- */
6058
- baseline_entries: number
6059
- /**
6060
- * Entries that matched a current finding in the active baseline mode,
6061
- * including entries matched through a followed file move.
6062
- */
6063
- matched_entries: number
6064
- /**
6065
- * Entries that matched no current finding on this run.
6066
- */
6067
- stale_entries: number
6068
- /**
6069
- * Entries that matched only by following a file move in identity mode.
6070
- * Always zero in count mode.
6071
- */
6072
- moved_entries: number
6073
- /**
6074
- * True when this run analyzed a subset of the project (changed-file,
6075
- * diff, or workspace scoping, or production mode, which drops test, story
6076
- * and dev files), so the baseline was compared against a narrowed finding
6077
- * set and staleness cannot be judged. `stale` is always false on scoped
6078
- * runs.
6079
- */
6080
- change_scoped: boolean
6081
- /**
6082
- * True exactly when the run was not change-scoped, at least one current
6083
- * finding existed before baseline filtering, and `stale_entries` reached
6084
- * a quarter of `baseline_entries`. Mirrors the human warning so machine
6085
- * consumers do not have to reimplement the threshold.
6086
- */
6087
- stale: boolean
6547
+ baseline_staleness?: (BaselineStaleness | null)
6088
6548
  }
6089
6549
  /**
6090
6550
  * Report entry describing whether a threshold override is active, stale, or
@@ -10835,6 +11295,26 @@ grouped_by?: (GroupByMode | null)
10835
11295
  * Per-bucket recomputed metrics; present only in grouped output.
10836
11296
  */
10837
11297
  groups?: (HealthGroup[] | null)
11298
+ /**
11299
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
11300
+ * Each entry is the same rule that decides the exit code, so a CI
11301
+ * integration reads the verdict instead of guessing from a process status
11302
+ * it usually cannot see. A gate fails the build when `status` is `fail`
11303
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
11304
+ * rules fail a run with no flag at all, so an absent object means "no gate
11305
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
11306
+ */
11307
+ gate_outcomes?: (GateOutcomes | null)
11308
+ /**
11309
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
11310
+ * absent when it was asked for nothing. An entry whose `status` is not
11311
+ * `applied` means the run could not do what it was asked and reported
11312
+ * something WIDER instead, so what follows is a valid report of a scope
11313
+ * nobody requested. Honoured requests are published too, with
11314
+ * `status: "applied"`, so an absent object means "nothing was asked for",
11315
+ * never "nothing failed". See [`crate::RequestOutcomes`].
11316
+ */
11317
+ request_outcomes?: (RequestOutcomes | null)
10838
11318
  /**
10839
11319
  * `_meta` block with metric definitions, when `--explain` was passed.
10840
11320
  */
@@ -11009,6 +11489,35 @@ total_issues?: (number | null)
11009
11489
  * Grouped findings; present only in grouped output.
11010
11490
  */
11011
11491
  groups?: (DuplicationGroup[] | null)
11492
+ /**
11493
+ * This run's view of the loaded baseline, present only in baseline runs.
11494
+ * Carries the staleness counts, the advisory verdict and `gate_trips`, the
11495
+ * same boolean `--fail-on-stale-baseline` exits on, so a CI integration
11496
+ * reads one field instead of restating the rule. Read `change_scoped`
11497
+ * before dividing `matched_entries` by `baseline_entries`: a narrowed run
11498
+ * can report `matched_entries: 0` on a healthy baseline.
11499
+ */
11500
+ baseline_staleness?: (BaselineStaleness | null)
11501
+ /**
11502
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
11503
+ * Each entry is the same rule that decides the exit code, so a CI
11504
+ * integration reads the verdict instead of guessing from a process status
11505
+ * it usually cannot see. A gate fails the build when `status` is `fail`
11506
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
11507
+ * rules fail a run with no flag at all, so an absent object means "no gate
11508
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
11509
+ */
11510
+ gate_outcomes?: (GateOutcomes | null)
11511
+ /**
11512
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
11513
+ * absent when it was asked for nothing. An entry whose `status` is not
11514
+ * `applied` means the run could not do what it was asked and reported
11515
+ * something WIDER instead, so what follows is a valid report of a scope
11516
+ * nobody requested. Honoured requests are published too, with
11517
+ * `status: "applied"`, so an absent object means "nothing was asked for",
11518
+ * never "nothing failed". See [`crate::RequestOutcomes`].
11519
+ */
11520
+ request_outcomes?: (RequestOutcomes | null)
11012
11521
  /**
11013
11522
  * `_meta` block with metric / rule definitions, emitted when `--explain`
11014
11523
  * is passed (always present in MCP responses).
@@ -11167,6 +11676,35 @@ total_issues: number
11167
11676
  * One bucket per resolver key.
11168
11677
  */
11169
11678
  groups: CheckGroupedEntry[]
11679
+ /**
11680
+ * This run's view of the loaded baseline, present only in baseline runs.
11681
+ * Carries the staleness counts, the advisory verdict and `gate_trips`, the
11682
+ * same boolean `--fail-on-stale-baseline` exits on, so a CI integration
11683
+ * reads one field instead of restating the rule. Read `change_scoped`
11684
+ * before dividing `matched_entries` by `baseline_entries`: a narrowed run
11685
+ * can report `matched_entries: 0` on a healthy baseline.
11686
+ */
11687
+ baseline_staleness?: (BaselineStaleness | null)
11688
+ /**
11689
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
11690
+ * Each entry is the same rule that decides the exit code, so a CI
11691
+ * integration reads the verdict instead of guessing from a process status
11692
+ * it usually cannot see. A gate fails the build when `status` is `fail`
11693
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
11694
+ * rules fail a run with no flag at all, so an absent object means "no gate
11695
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
11696
+ */
11697
+ gate_outcomes?: (GateOutcomes | null)
11698
+ /**
11699
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
11700
+ * absent when it was asked for nothing. An entry whose `status` is not
11701
+ * `applied` means the run could not do what it was asked and reported
11702
+ * something WIDER instead, so what follows is a valid report of a scope
11703
+ * nobody requested. Honoured requests are published too, with
11704
+ * `status: "applied"`, so an absent object means "nothing was asked for",
11705
+ * never "nothing failed". See [`crate::RequestOutcomes`].
11706
+ */
11707
+ request_outcomes?: (RequestOutcomes | null)
11170
11708
  /**
11171
11709
  * `_meta` block with docs and rule definitions, when `--explain` was
11172
11710
  * passed.
@@ -11836,6 +12374,26 @@ schema_version: SecuritySchemaVersion
11836
12374
  version: ToolVersion
11837
12375
  elapsed_ms: ElapsedMs
11838
12376
  config: SecurityOutputConfig
12377
+ /**
12378
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
12379
+ * Each entry is the same rule that decides the exit code, so a CI
12380
+ * integration reads the verdict instead of guessing from a process status
12381
+ * it usually cannot see. A gate fails the build when `status` is `fail`
12382
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
12383
+ * rules fail a run with no flag at all, so an absent object means "no gate
12384
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
12385
+ */
12386
+ gate_outcomes?: (GateOutcomes | null)
12387
+ /**
12388
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
12389
+ * absent when it was asked for nothing. An entry whose `status` is not
12390
+ * `applied` means the run could not do what it was asked and reported
12391
+ * something WIDER instead, so what follows is a valid report of a scope
12392
+ * nobody requested. Honoured requests are published too, with
12393
+ * `status: "applied"`, so an absent object means "nothing was asked for",
12394
+ * never "nothing failed". See [`crate::RequestOutcomes`].
12395
+ */
12396
+ request_outcomes?: (RequestOutcomes | null)
11839
12397
  /**
11840
12398
  * Security-specific rule and field metadata, emitted with `--explain`.
11841
12399
  */
@@ -12459,6 +13017,26 @@ schema_version: SecuritySchemaVersion
12459
13017
  version: ToolVersion
12460
13018
  elapsed_ms: ElapsedMs
12461
13019
  config: SecurityOutputConfig
13020
+ /**
13021
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
13022
+ * Each entry is the same rule that decides the exit code, so a CI
13023
+ * integration reads the verdict instead of guessing from a process status
13024
+ * it usually cannot see. A gate fails the build when `status` is `fail`
13025
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
13026
+ * rules fail a run with no flag at all, so an absent object means "no gate
13027
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
13028
+ */
13029
+ gate_outcomes?: (GateOutcomes | null)
13030
+ /**
13031
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
13032
+ * absent when it was asked for nothing. An entry whose `status` is not
13033
+ * `applied` means the run could not do what it was asked and reported
13034
+ * something WIDER instead, so what follows is a valid report of a scope
13035
+ * nobody requested. Honoured requests are published too, with
13036
+ * `status: "applied"`, so an absent object means "nothing was asked for",
13037
+ * never "nothing failed". See [`crate::RequestOutcomes`].
13038
+ */
13039
+ request_outcomes?: (RequestOutcomes | null)
12462
13040
  /**
12463
13041
  * Security-specific rule and field metadata, emitted with `--explain`.
12464
13042
  */
@@ -12742,6 +13320,26 @@ export interface CombinedOutput {
12742
13320
  schema_version: CombinedSchemaVersion
12743
13321
  version: ToolVersion
12744
13322
  elapsed_ms: ElapsedMs
13323
+ /**
13324
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
13325
+ * Each entry is the same rule that decides the exit code, so a CI
13326
+ * integration reads the verdict instead of guessing from a process status
13327
+ * it usually cannot see. A gate fails the build when `status` is `fail`
13328
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
13329
+ * rules fail a run with no flag at all, so an absent object means "no gate
13330
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
13331
+ */
13332
+ gate_outcomes?: (GateOutcomes | null)
13333
+ /**
13334
+ * Every narrowing or shaping request this run RECEIVED, keyed by name,
13335
+ * absent when it was asked for nothing. An entry whose `status` is not
13336
+ * `applied` means the run could not do what it was asked and reported
13337
+ * something WIDER instead, so what follows is a valid report of a scope
13338
+ * nobody requested. Honoured requests are published too, with
13339
+ * `status: "applied"`, so an absent object means "nothing was asked for",
13340
+ * never "nothing failed". See [`crate::RequestOutcomes`].
13341
+ */
13342
+ request_outcomes?: (RequestOutcomes | null)
12745
13343
  /**
12746
13344
  * Per-section `_meta` blocks, when `--explain` was passed.
12747
13345
  */
@@ -12801,6 +13399,22 @@ export interface FeatureFlagsOutput {
12801
13399
  schema_version: FeatureFlagsSchemaVersion
12802
13400
  version: ToolVersion
12803
13401
  elapsed_ms: ElapsedMs
13402
+ /**
13403
+ * What the run was asked to narrow and whether it did. See
13404
+ * [`crate::RequestOutcomes`] for the full contract.
13405
+ *
13406
+ * `fallow flags` accepts `--changed-since`, and an unresolvable ref widens
13407
+ * the scan to the whole project rather than failing the run. Until this
13408
+ * member existed the only account of that was a stderr line, which `--quiet`
13409
+ * removes, so a flag inventory read as scoped to the change could silently
13410
+ * be the whole project's (issue #2734).
13411
+ *
13412
+ * The command applies no diff filter, so the object carries the
13413
+ * `changed-since` entry only. Omitted when the run was asked for nothing,
13414
+ * which keeps a scan that passed no narrowing flag byte-identical and moves
13415
+ * no `schema_version`.
13416
+ */
13417
+ request_outcomes?: (RequestOutcomes | null)
12804
13418
  /**
12805
13419
  * Detected feature-flag findings.
12806
13420
  */
@@ -14137,6 +14751,22 @@ invalid_value?: (string | null)
14137
14751
  */
14138
14752
  export interface SuppressionInventoryOutput {
14139
14753
  schema_version: SuppressionInventorySchemaVersion
14754
+ /**
14755
+ * What the run was asked to narrow and whether it did. See
14756
+ * [`crate::RequestOutcomes`] for the full contract.
14757
+ *
14758
+ * `fallow suppressions` accepts `--changed-since`, and an unresolvable ref
14759
+ * widens the inventory to the whole project rather than failing the run.
14760
+ * Until this member existed the only account of that was a stderr line,
14761
+ * which `--quiet` removes, so an inventory read as scoped to the change
14762
+ * could silently be the whole project's (issue #2734).
14763
+ *
14764
+ * The command applies no diff filter, so the object carries the
14765
+ * `changed-since` entry only. Omitted when the run was asked for nothing,
14766
+ * which keeps an inventory that passed no narrowing flag byte-identical and
14767
+ * leaves `schema_version` at `1`.
14768
+ */
14769
+ request_outcomes?: (RequestOutcomes | null)
14140
14770
  summary: SuppressionInventorySummary
14141
14771
  /**
14142
14772
  * Per-file suppression listings, sorted by path then line.
@@ -15283,3 +15913,8 @@ export type UnusedDependency = UnusedDependencyFinding | UnusedDevDependencyFind
15283
15913
  * this alias; new code should narrow on the specific wrapper variant.
15284
15914
  */
15285
15915
  export type UnusedMember = UnusedClassMemberFinding | UnusedEnumMemberFinding | UnusedStoreMemberFinding;
15916
+
15917
+ /**
15918
+ * @deprecated Renamed to BaselineStaleness in 3.27.0, when dead-code and dupes started carrying the same shape. The members are unchanged.
15919
+ */
15920
+ export type HealthBaselineStaleness = BaselineStaleness;