fallow 3.25.0 → 3.27.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.25.0",
3
+ "version": "3.27.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": [
@@ -255,7 +255,7 @@
255
255
  "name": "--explain-skipped",
256
256
  "type": "bool",
257
257
  "required": false,
258
- "description": "Show a per-pattern breakdown for default duplicate ignores",
258
+ "description": "Show per-pattern counts for skipped files: default duplicate ignores on dupes and audit, built-in discovery ignores on check, dead-code, audit and the default run",
259
259
  "possible_values": [
260
260
  "true",
261
261
  "false"
@@ -320,6 +320,16 @@
320
320
  "false"
321
321
  ]
322
322
  },
323
+ {
324
+ "name": "--fail-on-stale-baseline",
325
+ "type": "bool",
326
+ "required": false,
327
+ "description": "Exit with code 1 if a loaded --baseline has entries that match nothing in this run",
328
+ "possible_values": [
329
+ "true",
330
+ "false"
331
+ ]
332
+ },
323
333
  {
324
334
  "name": "--tolerance",
325
335
  "type": "string",
@@ -7252,7 +7262,7 @@
7252
7262
  ]
7253
7263
  },
7254
7264
  "plugins": {
7255
- "count": 125,
7265
+ "count": 126,
7256
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",
7257
7267
  "names": [
7258
7268
  "nextjs",
@@ -7326,6 +7336,7 @@
7326
7336
  "biome",
7327
7337
  "stylelint",
7328
7338
  "prettier",
7339
+ "oxfmt",
7329
7340
  "oxlint",
7330
7341
  "markdownlint",
7331
7342
  "cspell",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.25.0",
3
+ "version": "3.27.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.25.0",
92
- "@fallow-cli/darwin-x64": "3.25.0",
93
- "@fallow-cli/linux-x64-gnu": "3.25.0",
94
- "@fallow-cli/linux-arm64-gnu": "3.25.0",
95
- "@fallow-cli/linux-x64-musl": "3.25.0",
96
- "@fallow-cli/linux-arm64-musl": "3.25.0",
97
- "@fallow-cli/win32-arm64-msvc": "3.25.0",
98
- "@fallow-cli/win32-x64-msvc": "3.25.0",
99
- "fallow-type-aware": "3.25.0"
91
+ "@fallow-cli/darwin-arm64": "3.27.0",
92
+ "@fallow-cli/darwin-x64": "3.27.0",
93
+ "@fallow-cli/linux-x64-gnu": "3.27.0",
94
+ "@fallow-cli/linux-arm64-gnu": "3.27.0",
95
+ "@fallow-cli/linux-x64-musl": "3.27.0",
96
+ "@fallow-cli/linux-arm64-musl": "3.27.0",
97
+ "@fallow-cli/win32-arm64-msvc": "3.27.0",
98
+ "@fallow-cli/win32-x64-msvc": "3.27.0",
99
+ "fallow-type-aware": "3.27.0"
100
100
  }
101
101
  }
package/schema.json CHANGED
@@ -36,7 +36,7 @@
36
36
  "default": []
37
37
  },
38
38
  "ignorePatterns": {
39
- "description": "An array of project-root-relative glob patterns for files to exclude from analysis entirely; entries are unioned with fallow's built-in defaults (**/node_modules/**, **/dist/**, build/**, **/.git/**, **/coverage/**, **/*.min.js, **/*.min.mjs, **/*.min.cjs, **/*.bundle.js), so custom globs add to rather than replace them. Set it (e.g. `[\"generated/**\"]`) to drop generated or vendored trees from every detector; patterns are validated at load.",
39
+ "description": "An array of project-root-relative glob patterns for files to exclude from analysis entirely; entries are unioned with fallow's built-in defaults (**/node_modules/**, **/dist/**, **/build/**, **/.git/**, **/coverage/**, **/*.min.js, **/*.min.mjs, **/*.min.cjs, **/*.bundle.js), so custom globs add to rather than replace them. Set it (e.g. `[\"generated/**\"]`) to drop generated or vendored trees from every detector; patterns are validated at load.",
40
40
  "type": "array",
41
41
  "items": {
42
42
  "type": "string"
@@ -373,6 +373,8 @@
373
373
  }
374
374
  },
375
375
  "additionalProperties": false,
376
+ "allowComments": true,
377
+ "allowTrailingCommas": true,
376
378
  "$defs": {
377
379
  "ExternalPluginDef": {
378
380
  "description": "A declarative plugin definition loaded from a standalone file or inline config.\n\nExternal plugins provide the same static pattern capabilities as built-in\nplugins (entry points, always-used files, used exports, tooling dependencies),\nbut are defined in standalone files or inline in the fallow config rather than\ncompiled Rust code.\n\nThey cannot do AST-based config parsing (`resolve_config()`), but cover the\nvast majority of framework integration use cases.\n\nSupports JSONC, JSON, and TOML formats. All use camelCase field names.\n\n```json\n{\n \"$schema\": \"https://raw.githubusercontent.com/fallow-rs/fallow/main/plugin-schema.json\",\n \"name\": \"my-framework\",\n \"enablers\": [\"my-framework\", \"@my-framework/core\"],\n \"entryPoints\": [\"src/routes/**/*.{ts,tsx}\"],\n \"configPatterns\": [\"my-framework.config.{ts,js}\"],\n \"alwaysUsed\": [\"src/setup.ts\"],\n \"toolingDependencies\": [\"my-framework-cli\"],\n \"usedExports\": [\n { \"pattern\": \"src/routes/**/*.{ts,tsx}\", \"exports\": [\"default\", \"loader\", \"action\"] }\n ]\n}\n```",
@@ -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.24.1",
449
+ "fallow_version": "3.27.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.25.0",
653
+ "version": "3.27.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.25.0",
1056
+ "version": "3.27.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.25.0",
1133
+ "version": "3.27.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.25.0",
1234
+ "version": "3.27.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.25.0",
1263
+ "version": "3.27.0",
1264
1264
  "elapsed_ms": 42,
1265
1265
  "config": {
1266
1266
  "rules": {
@@ -1836,7 +1836,7 @@ Available on all commands:
1836
1836
  | `--group-by` | `owner\|directory\|package\|section` | - | Group output by CODEOWNERS ownership (`owner`), first path component (`directory`), workspace package (`package`, aliases: `workspace`, `pkg`), or GitLab CODEOWNERS `[Section]` headers (`section`, alias: `gl-section`). All output formats partition issues into labeled groups. `section` mode attaches an `owners` array to each group in JSON output |
1837
1837
  | `--performance` | `bool` | `false` | Show pipeline timing breakdown |
1838
1838
  | `--explain` | `bool` | `false` | JSON: include metric definitions in `_meta`. Human: print a `Description:` line under each section header. Always on for MCP. |
1839
- | `--explain-skipped` | `bool` | `false` | Show a per-pattern breakdown for default duplicate ignores |
1839
+ | `--explain-skipped` | `bool` | `false` | Human/markdown only: show per-pattern counts for files skipped by the default duplicates ignores. `dupes` prints only that breakdown; on `check`, `dead-code`, `audit` and the default run the same flag reports source files the built-in discovery ignores removed |
1840
1840
  | `--summary` | `bool` | `false` | Show only category counts without individual items. Useful for dashboards and quick overviews |
1841
1841
  | `--ci` | `bool` | `false` | CI mode: `--format sarif --fail-on-issues --quiet` |
1842
1842
  | `--fail-on-issues` | `bool` | `false` | Exit 1 if any issues found (promotes `warn` to `error`) |
@@ -1844,6 +1844,7 @@ Available on all commands:
1844
1844
  | `-o, --output-file` | `string` | - | Write the report to a file instead of stdout, for any --format (no ANSI codes). Useful on large projects where the terminal scrollback truncates the top. Progress and the confirmation stay on stderr |
1845
1845
  | `--report-path-prefix` | `string` | - | Prefix prepended to every path in the CI-facing formats (`github-annotations`, `github-summary`, `codeclimate`, `review-github`, `review-gitlab`). CI platforms address files by repository-root-relative path, so when the analyzed project lives in a subdirectory (e.g. `packages/app/`), paths need that offset. fallow detects the offset via the git toplevel automatically; this flag overrides the detection. Pass an empty string to disable rebasing and emit paths relative to `--root` |
1846
1846
  | `--fail-on-regression` | `bool` | `false` | Fail if issue count increased beyond tolerance vs a regression baseline |
1847
+ | `--fail-on-stale-baseline` | `bool` | `false` | Exit with code 1 if a loaded --baseline has entries that match nothing in this run |
1847
1848
  | `--tolerance` | `string` | `0` | Allowed increase: `"2%"` (percentage) or `"5"` (absolute). Default: `"0"` |
1848
1849
  | `--regression-baseline` | `string` | - | Path to a standalone regression baseline file. Without it, fallow uses `regression.baseline` from the config |
1849
1850
  | `--save-regression-baseline` | `string` | - | Save current issue counts. With no path, update `regression.baseline` in the discovered fallow config or create `.fallowrc.json`; with a path, write a standalone baseline file |
@@ -2029,7 +2030,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
2029
2030
  {
2030
2031
  "kind": "dead-code",
2031
2032
  "schema_version": 7,
2032
- "version": "3.25.0",
2033
+ "version": "3.27.0",
2033
2034
  "elapsed_ms": 45,
2034
2035
  "total_issues": 12,
2035
2036
  "entry_points": {
@@ -2189,7 +2190,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
2189
2190
  {
2190
2191
  "kind": "dupes",
2191
2192
  "schema_version": 7,
2192
- "version": "3.25.0",
2193
+ "version": "3.27.0",
2193
2194
  "elapsed_ms": 82,
2194
2195
  "total_clones": 15,
2195
2196
  "total_lines_duplicated": 230,
@@ -2233,11 +2234,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
2233
2234
  {
2234
2235
  "kind": "combined",
2235
2236
  "schema_version": 7,
2236
- "version": "3.25.0",
2237
+ "version": "3.27.0",
2237
2238
  "elapsed_ms": 159,
2238
2239
  "check": {
2239
2240
  "schema_version": 7,
2240
- "version": "3.25.0",
2241
+ "version": "3.27.0",
2241
2242
  "elapsed_ms": 45,
2242
2243
  "total_issues": 12,
2243
2244
  "unused_files": [],
@@ -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,14 @@ 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")
405
423
  /**
406
424
  * Status of a regression-check pass.
407
425
  */
@@ -428,6 +446,25 @@ path: string
428
446
  * with a next-step hint.
429
447
  */
430
448
  message: string
449
+ /**
450
+ * True when this diagnostic reports a run whose RESULTS are degraded:
451
+ * something the user installed, wrote, or expected did not reach the
452
+ * analysis. Projected from [`WorkspaceDiagnosticKind::warns_on_stderr`],
453
+ * which is the same classification that decides whether the CLI prints a
454
+ * stderr line, so a CI log built from this field and a local non-quiet run
455
+ * say the same thing.
456
+ *
457
+ * Omitted when false, which is what keeps every clean run byte-identical.
458
+ * The two unconfigured-check kinds answer false on purpose: they fire in
459
+ * the product's default state on every project that never opted into
460
+ * boundaries or rule packs, so warning on them would warn forever. So does
461
+ * `excluded-by-default-ignore`, which is designed behavior on generated
462
+ * output; the alarm for that case is `no-source-files-analyzed`.
463
+ *
464
+ * Read this instead of hardcoding a kind allowlist: a degrading kind added
465
+ * in a later release then reaches an unchanged consumer.
466
+ */
467
+ degrades_analysis?: boolean
431
468
  } & WorkspaceDiagnostic1)
432
469
  export type WorkspaceDiagnostic1 = ({
433
470
  kind: "undeclared-workspace"
@@ -500,6 +537,39 @@ kind: "node-modules-missing"
500
537
  kind: "boundaries-not-configured"
501
538
  } | {
502
539
  kind: "rule-packs-not-configured"
540
+ } | {
541
+ /**
542
+ * The built-in glob that matched, verbatim (for example
543
+ * `** /build/**`).
544
+ */
545
+ pattern: string
546
+ /**
547
+ * Candidate source files this pattern excluded in this walk, across
548
+ * every directory it matched, not just the one `path` anchors at.
549
+ * Exact: the walk counts each excluded candidate once.
550
+ */
551
+ file_count: number
552
+ /**
553
+ * Distinct directories this pattern matched at, `path` included, and
554
+ * not the number of directories that held the files. A
555
+ * directory-shaped pattern (`** /dist/**`) matches at the directory it
556
+ * names, so an excluded subtree counts once however many nested
557
+ * directories inside it held source: a `dist/` holding files in three
558
+ * sub-directories reports `1`. A file-shaped pattern (`** /*.min.js`)
559
+ * has no directory to collapse to and counts each matched file's own
560
+ * parent. Exact either way, and anything above `1` says `path` names
561
+ * one matched location out of several.
562
+ */
563
+ directory_count: number
564
+ kind: "excluded-by-default-ignore"
565
+ } | {
566
+ /**
567
+ * Candidate source files the built-in ignore patterns removed from
568
+ * this walk, summed across every pattern. `0` when the walk found no
569
+ * candidate to exclude in the first place.
570
+ */
571
+ excluded_file_count: number
572
+ kind: "no-source-files-analyzed"
503
573
  })
504
574
  /**
505
575
  * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types
@@ -1286,6 +1356,16 @@ elapsed_ms: ElapsedMs
1286
1356
  base_snapshot_skipped?: (boolean | null)
1287
1357
  summary: AuditSummary
1288
1358
  attribution: AuditAttribution
1359
+ /**
1360
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
1361
+ * Each entry is the same rule that decides the exit code, so a CI
1362
+ * integration reads the verdict instead of guessing from a process status
1363
+ * it usually cannot see. A gate fails the build when `status` is `fail`
1364
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
1365
+ * rules fail a run with no flag at all, so an absent object means "no gate
1366
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
1367
+ */
1368
+ gate_outcomes?: (GateOutcomes | null)
1289
1369
  /**
1290
1370
  * `_meta` block with metric / rule definitions, when `--explain` was
1291
1371
  * passed.
@@ -1368,6 +1448,78 @@ styling_introduced: number
1368
1448
  styling_inherited: number
1369
1449
  duplication_demoted: number
1370
1450
  }
1451
+ /**
1452
+ * Every gate a run ARMED, keyed by name.
1453
+ *
1454
+ * Armed, not evaluated: a gate is armed by a flag or by config, never merely
1455
+ * because the rule behind it exists. Fallow's default severity rules fail a
1456
+ * run with no flag at all, so a `dead-code` run can exit 1 carrying no object
1457
+ * whatsoever. Read an absent object as "no gate was asked for", never as
1458
+ * "nothing failed".
1459
+ *
1460
+ * Absent from an envelope whenever it is empty, so a run that armed no gate is
1461
+ * byte-identical to one produced before this object existed. An empty object
1462
+ * is never emitted: it would assert that gates were armed and none tripped,
1463
+ * which is a different and false claim.
1464
+ *
1465
+ * The names this build can emit are `error-severity-findings`, `regression`,
1466
+ * `stale-baseline`, `duplication-threshold`, `health-min-score`,
1467
+ * `health-min-severity`, `health-findings`, `health-coverage-gaps`,
1468
+ * `health-runtime-coverage`, `security`, `security-advisory`, `audit-verdict`
1469
+ * and `type-aware-require`. The set is OPEN: a name a consumer does not
1470
+ * recognise means "some gate", not an error.
1471
+ */
1472
+ export interface GateOutcomes {
1473
+ [k: string]: GateOutcome
1474
+ }
1475
+ /**
1476
+ * One gate's verdict on one run.
1477
+ *
1478
+ * `status` and `enforced` answer different questions and legitimately
1479
+ * disagree. `status` is what the rule concluded; `enforced` is whether a
1480
+ * `fail` from this gate would make the run exit non-zero. A
1481
+ * `health --report-only` run is an explicit request never to fail, so a
1482
+ * failing gate there reports `status: fail` with `enforced: false`, and a
1483
+ * stale-baseline verdict published without `--fail-on-stale-baseline` reports
1484
+ * the same pair.
1485
+ *
1486
+ * **A gate fails the build when `status` is `fail` AND `enforced` is true.**
1487
+ * Neither member decides it alone: `enforced` is true on every armed gate,
1488
+ * including the ones that passed, so gating on it by itself fails every run
1489
+ * that armed anything. Read `status` on its own to decide what to say, and
1490
+ * remember that `warn` and `skipped` are neither a pass nor a failure.
1491
+ */
1492
+ export interface GateOutcome {
1493
+ status: GateStatus
1494
+ /**
1495
+ * True when a `fail` from this gate makes the run exit non-zero. False
1496
+ * when the verdict is published for information only, because the gate was
1497
+ * never armed or because the run was told never to fail.
1498
+ */
1499
+ enforced: boolean
1500
+ /**
1501
+ * The measured value the gate compared, when there is one: the duplication
1502
+ * percentage, the health score, or the number of findings at or above the
1503
+ * severity floor. Whole numbers are carried as JSON numbers, so a count of
1504
+ * three reads as `3.0`. Absent for gates that compare no number.
1505
+ */
1506
+ observed?: (number | null)
1507
+ /**
1508
+ * The configured limit `observed` was compared against, when there is one.
1509
+ * Absent for gates that compare no number.
1510
+ */
1511
+ threshold?: (number | null)
1512
+ /**
1513
+ * How the limit was spelled, for a gate whose `threshold` number does not
1514
+ * carry its own unit. `health-min-severity` sets it to the severity floor
1515
+ * (`moderate`, `high` or `critical`); `regression` sets it to the
1516
+ * tolerance as the user wrote it (`"50%"` or `"5"`), because `threshold`
1517
+ * there is the allowance in issues and the percentage would otherwise be
1518
+ * unrecoverable on the grouped envelope, which carries no `regression`
1519
+ * object. Absent for gates whose numbers speak for themselves.
1520
+ */
1521
+ threshold_label?: (string | null)
1522
+ }
1371
1523
  /**
1372
1524
  * Metric and rule definitions emitted under `_meta` when `--explain` is
1373
1525
  * passed (always present in MCP responses). Helps AI agents and CI systems
@@ -2645,10 +2797,29 @@ baseline_deltas?: (BaselineDeltas | null)
2645
2797
  * Which baseline snapshot was matched, in baseline runs.
2646
2798
  */
2647
2799
  baseline?: (BaselineMatch | null)
2800
+ /**
2801
+ * This run's view of the loaded baseline, present only in baseline runs.
2802
+ * Carries the staleness counts, the advisory verdict and `gate_trips`, the
2803
+ * same boolean `--fail-on-stale-baseline` exits on, so a CI integration
2804
+ * reads one field instead of restating the rule. Read `change_scoped`
2805
+ * before dividing `matched_entries` by `baseline_entries`: a narrowed run
2806
+ * can report `matched_entries: 0` on a healthy baseline.
2807
+ */
2808
+ baseline_staleness?: (BaselineStaleness | null)
2648
2809
  /**
2649
2810
  * Regression verdict against the baseline, in `--fail-on-regression` runs.
2650
2811
  */
2651
2812
  regression?: (RegressionResult | null)
2813
+ /**
2814
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
2815
+ * Each entry is the same rule that decides the exit code, so a CI
2816
+ * integration reads the verdict instead of guessing from a process status
2817
+ * it usually cannot see. A gate fails the build when `status` is `fail`
2818
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
2819
+ * rules fail a run with no flag at all, so an absent object means "no gate
2820
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
2821
+ */
2822
+ gate_outcomes?: (GateOutcomes | null)
2652
2823
  /**
2653
2824
  * `_meta` block with docs and rule definitions, when `--explain` was
2654
2825
  * passed.
@@ -2663,7 +2834,8 @@ _meta?: (Meta | null)
2663
2834
  * `malformed-tsconfig`, `tsconfig-reference-dir-missing`;
2664
2835
  * - source discovery, during the file walk: `skipped-large-file`,
2665
2836
  * `skipped-minified-file`, `skipped-source-dotdir`,
2666
- * `source-read-failure`, `source-parse-degraded`;
2837
+ * `excluded-by-default-ignore`, `source-read-failure`,
2838
+ * `source-parse-degraded`;
2667
2839
  * - dead-code analysis, from the dependency-catalog and override
2668
2840
  * detectors: `malformed-pnpm-workspace-yaml`,
2669
2841
  * `bun-lockb-override-resolution-skipped`.
@@ -2684,6 +2856,18 @@ _meta?: (Meta | null)
2684
2856
  * optional `reachability_caveats[]` array, and a reader who never scrolls
2685
2857
  * back up to this list still sees it. `fallow fix` reads the same array
2686
2858
  * and withholds the removal while a caveat stands.
2859
+ *
2860
+ * `excluded-by-default-ignore` is the one source-discovery kind that
2861
+ * reports unseen files WITHOUT raising a caveat. It names a built-in
2862
+ * ignore pattern (`** /dist/**`, `** /build/**`, `** /coverage/**`, or one
2863
+ * of the four minified-bundle globs) that removed candidate source files
2864
+ * from the walk, which is designed behavior on generated output rather
2865
+ * than a degraded run, so it is advisory only and no finding inherits it.
2866
+ * One entry per pattern, never per file, so the array stays bounded on a
2867
+ * project of any size. Gitignored trees are pruned before the walk sees
2868
+ * them and count zero, and `** /node_modules/**` is never reported:
2869
+ * installed dependencies are not the first-party source the kind is
2870
+ * about.
2687
2871
  */
2688
2872
  workspace_diagnostics?: WorkspaceDiagnostic[]
2689
2873
  /**
@@ -5054,6 +5238,86 @@ entries: number
5054
5238
  */
5055
5239
  matched: number
5056
5240
  }
5241
+ /**
5242
+ * One run's machine-readable view of a loaded baseline.
5243
+ *
5244
+ * `stale` and `gate_trips` answer different questions and legitimately
5245
+ * disagree. `stale` mirrors the unasked-for stderr advisory, which stays silent
5246
+ * below a quarter of the baseline and on a run that produced no findings at
5247
+ * all, because a cleaned project and a rotted baseline look identical from
5248
+ * there. `gate_trips` mirrors the opt-in `--fail-on-stale-baseline` rule, which
5249
+ * a repository asks for precisely to catch those cases, so it fires on any
5250
+ * stale entry. A rotted baseline on a cleaned project reports
5251
+ * `stale: false` with `gate_trips: true`; that is the contract, not a defect.
5252
+ *
5253
+ * `change_scoped` is the member a consumer must read before dividing
5254
+ * `matched_entries` by `baseline_entries`. A run narrowed to part of the
5255
+ * project compares a whole-project baseline against a slice of it and can
5256
+ * report `matched_entries: 0` while the baseline is perfectly healthy, so both
5257
+ * `stale` and `gate_trips` are false there by construction. The remedy for a
5258
+ * tripped gate is always the same: re-save the baseline from a whole-project
5259
+ * run with `--save-baseline`.
5260
+ */
5261
+ export interface BaselineStaleness {
5262
+ /**
5263
+ * Entries carried by the loaded baseline file. On health these are the
5264
+ * complexity and CRAP finding entries; runtime-coverage suppressions and
5265
+ * refactoring target keys carried by the same file are not counted.
5266
+ */
5267
+ baseline_entries: number
5268
+ /**
5269
+ * Entries that matched a current finding on this run and were filtered out
5270
+ * of the report. On health this includes entries matched through a
5271
+ * followed file move.
5272
+ */
5273
+ matched_entries: number
5274
+ /**
5275
+ * Entries that matched no current finding on this run:
5276
+ * `baseline_entries - matched_entries`.
5277
+ */
5278
+ stale_entries: number
5279
+ /**
5280
+ * Findings this run produced before the baseline filtered them. Zero means
5281
+ * there was nothing to compare, either because the project is clean or
5282
+ * because the scope was empty, which is why `stale` stays false there even
5283
+ * when every entry went unmatched.
5284
+ */
5285
+ current_findings: number
5286
+ /**
5287
+ * True when this run analyzed only part of the project, so a whole-project
5288
+ * baseline matches less of it for reasons that are not rot. The channels
5289
+ * differ per command and include a diff, a base ref, `--changed-since`,
5290
+ * `--workspace`, `--changed-workspaces`, `--scope`, `--file`, an
5291
+ * issue-type filter, and production mode. Both `stale` and `gate_trips`
5292
+ * are false whenever this is true.
5293
+ */
5294
+ change_scoped: boolean
5295
+ /**
5296
+ * True exactly when the advisory stderr warning fired: not change-scoped,
5297
+ * at least one current finding before baseline filtering, and either
5298
+ * nothing matched or `stale_entries` reached a quarter of
5299
+ * `baseline_entries`.
5300
+ */
5301
+ stale: boolean
5302
+ warning: BaselineStalenessAdvisory
5303
+ /**
5304
+ * True exactly when
5305
+ * `!change_scoped && baseline_entries > 0 && matched_entries < baseline_entries`,
5306
+ * which is the rule `--fail-on-stale-baseline` applies. Deliberately
5307
+ * stricter than `stale`: any unmatched entry counts. It describes the
5308
+ * baseline, not the run's exit code: `health --report-only` is an explicit
5309
+ * request never to fail, so that run exits 0 and says so on stderr while
5310
+ * still reporting `gate_trips: true` here.
5311
+ */
5312
+ gate_trips: boolean
5313
+ /**
5314
+ * Entries that matched only by following a file move. Only `health` can
5315
+ * follow one, in its identity baseline mode; `dead-code` and `dupes` match
5316
+ * entries by fingerprint and never classify one as moved, so they report
5317
+ * `0`. Always `0` in health's count mode too.
5318
+ */
5319
+ moved_entries: number
5320
+ }
5057
5321
  /**
5058
5322
  * Result of regression detection (`--fail-on-regression`). Compares current
5059
5323
  * issue counts against a baseline from config or an explicit file.
@@ -6002,50 +6266,7 @@ severity_moderate_count: number
6002
6266
  /**
6003
6267
  * Baseline staleness data, present only when a baseline was loaded.
6004
6268
  */
6005
- baseline_staleness?: (HealthBaselineStaleness | null)
6006
- }
6007
- /**
6008
- * Staleness of a loaded health baseline.
6009
- *
6010
- * Reports how many saved complexity and CRAP finding entries still matched a
6011
- * current finding on this run, so consumers can see a rotting baseline before
6012
- * it degrades to zero overlap. Runtime-coverage suppressions and refactoring
6013
- * target keys carried by the same baseline are not counted here. Present in
6014
- * the summary only when a baseline was loaded.
6015
- */
6016
- export interface HealthBaselineStaleness {
6017
- /**
6018
- * Complexity and CRAP finding entries carried by the loaded baseline.
6019
- */
6020
- baseline_entries: number
6021
- /**
6022
- * Entries that matched a current finding in the active baseline mode,
6023
- * including entries matched through a followed file move.
6024
- */
6025
- matched_entries: number
6026
- /**
6027
- * Entries that matched no current finding on this run.
6028
- */
6029
- stale_entries: number
6030
- /**
6031
- * Entries that matched only by following a file move in identity mode.
6032
- * Always zero in count mode.
6033
- */
6034
- moved_entries: number
6035
- /**
6036
- * True when this run analyzed a subset of the project (changed-file,
6037
- * diff, or workspace scoping), so the baseline was compared against a
6038
- * narrowed finding set and staleness cannot be judged. `stale` is always
6039
- * false on scoped runs.
6040
- */
6041
- change_scoped: boolean
6042
- /**
6043
- * True exactly when the run was not change-scoped, at least one current
6044
- * finding existed before baseline filtering, and `stale_entries` reached
6045
- * a quarter of `baseline_entries`. Mirrors the human warning so machine
6046
- * consumers do not have to reimplement the threshold.
6047
- */
6048
- stale: boolean
6269
+ baseline_staleness?: (BaselineStaleness | null)
6049
6270
  }
6050
6271
  /**
6051
6272
  * Report entry describing whether a threshold override is active, stale, or
@@ -10796,6 +11017,16 @@ grouped_by?: (GroupByMode | null)
10796
11017
  * Per-bucket recomputed metrics; present only in grouped output.
10797
11018
  */
10798
11019
  groups?: (HealthGroup[] | null)
11020
+ /**
11021
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
11022
+ * Each entry is the same rule that decides the exit code, so a CI
11023
+ * integration reads the verdict instead of guessing from a process status
11024
+ * it usually cannot see. A gate fails the build when `status` is `fail`
11025
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
11026
+ * rules fail a run with no flag at all, so an absent object means "no gate
11027
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
11028
+ */
11029
+ gate_outcomes?: (GateOutcomes | null)
10799
11030
  /**
10800
11031
  * `_meta` block with metric definitions, when `--explain` was passed.
10801
11032
  */
@@ -10970,6 +11201,25 @@ total_issues?: (number | null)
10970
11201
  * Grouped findings; present only in grouped output.
10971
11202
  */
10972
11203
  groups?: (DuplicationGroup[] | null)
11204
+ /**
11205
+ * This run's view of the loaded baseline, present only in baseline runs.
11206
+ * Carries the staleness counts, the advisory verdict and `gate_trips`, the
11207
+ * same boolean `--fail-on-stale-baseline` exits on, so a CI integration
11208
+ * reads one field instead of restating the rule. Read `change_scoped`
11209
+ * before dividing `matched_entries` by `baseline_entries`: a narrowed run
11210
+ * can report `matched_entries: 0` on a healthy baseline.
11211
+ */
11212
+ baseline_staleness?: (BaselineStaleness | null)
11213
+ /**
11214
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
11215
+ * Each entry is the same rule that decides the exit code, so a CI
11216
+ * integration reads the verdict instead of guessing from a process status
11217
+ * it usually cannot see. A gate fails the build when `status` is `fail`
11218
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
11219
+ * rules fail a run with no flag at all, so an absent object means "no gate
11220
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
11221
+ */
11222
+ gate_outcomes?: (GateOutcomes | null)
10973
11223
  /**
10974
11224
  * `_meta` block with metric / rule definitions, emitted when `--explain`
10975
11225
  * is passed (always present in MCP responses).
@@ -11128,6 +11378,25 @@ total_issues: number
11128
11378
  * One bucket per resolver key.
11129
11379
  */
11130
11380
  groups: CheckGroupedEntry[]
11381
+ /**
11382
+ * This run's view of the loaded baseline, present only in baseline runs.
11383
+ * Carries the staleness counts, the advisory verdict and `gate_trips`, the
11384
+ * same boolean `--fail-on-stale-baseline` exits on, so a CI integration
11385
+ * reads one field instead of restating the rule. Read `change_scoped`
11386
+ * before dividing `matched_entries` by `baseline_entries`: a narrowed run
11387
+ * can report `matched_entries: 0` on a healthy baseline.
11388
+ */
11389
+ baseline_staleness?: (BaselineStaleness | null)
11390
+ /**
11391
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
11392
+ * Each entry is the same rule that decides the exit code, so a CI
11393
+ * integration reads the verdict instead of guessing from a process status
11394
+ * it usually cannot see. A gate fails the build when `status` is `fail`
11395
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
11396
+ * rules fail a run with no flag at all, so an absent object means "no gate
11397
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
11398
+ */
11399
+ gate_outcomes?: (GateOutcomes | null)
11131
11400
  /**
11132
11401
  * `_meta` block with docs and rule definitions, when `--explain` was
11133
11402
  * passed.
@@ -11797,6 +12066,16 @@ schema_version: SecuritySchemaVersion
11797
12066
  version: ToolVersion
11798
12067
  elapsed_ms: ElapsedMs
11799
12068
  config: SecurityOutputConfig
12069
+ /**
12070
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
12071
+ * Each entry is the same rule that decides the exit code, so a CI
12072
+ * integration reads the verdict instead of guessing from a process status
12073
+ * it usually cannot see. A gate fails the build when `status` is `fail`
12074
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
12075
+ * rules fail a run with no flag at all, so an absent object means "no gate
12076
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
12077
+ */
12078
+ gate_outcomes?: (GateOutcomes | null)
11800
12079
  /**
11801
12080
  * Security-specific rule and field metadata, emitted with `--explain`.
11802
12081
  */
@@ -12420,6 +12699,16 @@ schema_version: SecuritySchemaVersion
12420
12699
  version: ToolVersion
12421
12700
  elapsed_ms: ElapsedMs
12422
12701
  config: SecurityOutputConfig
12702
+ /**
12703
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
12704
+ * Each entry is the same rule that decides the exit code, so a CI
12705
+ * integration reads the verdict instead of guessing from a process status
12706
+ * it usually cannot see. A gate fails the build when `status` is `fail`
12707
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
12708
+ * rules fail a run with no flag at all, so an absent object means "no gate
12709
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
12710
+ */
12711
+ gate_outcomes?: (GateOutcomes | null)
12423
12712
  /**
12424
12713
  * Security-specific rule and field metadata, emitted with `--explain`.
12425
12714
  */
@@ -12703,6 +12992,16 @@ export interface CombinedOutput {
12703
12992
  schema_version: CombinedSchemaVersion
12704
12993
  version: ToolVersion
12705
12994
  elapsed_ms: ElapsedMs
12995
+ /**
12996
+ * Every gate this run ARMED, keyed by name, absent when it armed none.
12997
+ * Each entry is the same rule that decides the exit code, so a CI
12998
+ * integration reads the verdict instead of guessing from a process status
12999
+ * it usually cannot see. A gate fails the build when `status` is `fail`
13000
+ * AND `enforced` is true. Armed, not evaluated: fallow's default severity
13001
+ * rules fail a run with no flag at all, so an absent object means "no gate
13002
+ * was asked for", never "nothing failed". See [`crate::GateOutcomes`].
13003
+ */
13004
+ gate_outcomes?: (GateOutcomes | null)
12706
13005
  /**
12707
13006
  * Per-section `_meta` blocks, when `--explain` was passed.
12708
13007
  */
@@ -15244,3 +15543,8 @@ export type UnusedDependency = UnusedDependencyFinding | UnusedDevDependencyFind
15244
15543
  * this alias; new code should narrow on the specific wrapper variant.
15245
15544
  */
15246
15545
  export type UnusedMember = UnusedClassMemberFinding | UnusedEnumMemberFinding | UnusedStoreMemberFinding;
15546
+
15547
+ /**
15548
+ * @deprecated Renamed to BaselineStaleness in 3.27.0, when dead-code and dupes started carrying the same shape. The members are unchanged.
15549
+ */
15550
+ export type HealthBaselineStaleness = BaselineStaleness;