fallow 2.94.0 → 2.95.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "2.94.0",
3
+ "version": "2.95.0",
4
4
  "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -83,13 +83,13 @@
83
83
  "@tanstack/intent": "0.0.41"
84
84
  },
85
85
  "optionalDependencies": {
86
- "@fallow-cli/darwin-arm64": "2.94.0",
87
- "@fallow-cli/darwin-x64": "2.94.0",
88
- "@fallow-cli/linux-x64-gnu": "2.94.0",
89
- "@fallow-cli/linux-arm64-gnu": "2.94.0",
90
- "@fallow-cli/linux-x64-musl": "2.94.0",
91
- "@fallow-cli/linux-arm64-musl": "2.94.0",
92
- "@fallow-cli/win32-arm64-msvc": "2.94.0",
93
- "@fallow-cli/win32-x64-msvc": "2.94.0"
86
+ "@fallow-cli/darwin-arm64": "2.95.0",
87
+ "@fallow-cli/darwin-x64": "2.95.0",
88
+ "@fallow-cli/linux-x64-gnu": "2.95.0",
89
+ "@fallow-cli/linux-arm64-gnu": "2.95.0",
90
+ "@fallow-cli/linux-x64-musl": "2.95.0",
91
+ "@fallow-cli/linux-arm64-musl": "2.95.0",
92
+ "@fallow-cli/win32-arm64-msvc": "2.95.0",
93
+ "@fallow-cli/win32-x64-msvc": "2.95.0"
94
94
  }
95
95
  }
package/schema.json CHANGED
@@ -832,6 +832,13 @@
832
832
  },
833
833
  "default": []
834
834
  },
835
+ "thresholdOverrides": {
836
+ "description": "Per-file or per-function threshold overrides. These keep exceptional\nfunctions visible as configured numeric ceilings instead of hiding them\nbehind binary suppressions.",
837
+ "type": "array",
838
+ "items": {
839
+ "$ref": "#/$defs/HealthThresholdOverride"
840
+ }
841
+ },
835
842
  "ownership": {
836
843
  "description": "Ownership analysis configuration. Controls bot filtering and email\nprivacy mode for `--ownership` output.",
837
844
  "$ref": "#/$defs/OwnershipConfig",
@@ -852,7 +859,67 @@
852
859
  "type": "boolean",
853
860
  "default": true
854
861
  }
855
- }
862
+ },
863
+ "additionalProperties": false
864
+ },
865
+ "HealthThresholdOverride": {
866
+ "description": "Per-file or per-function health threshold override.",
867
+ "type": "object",
868
+ "properties": {
869
+ "files": {
870
+ "description": "Project-root-relative file globs this override applies to.",
871
+ "type": "array",
872
+ "items": {
873
+ "type": "string"
874
+ }
875
+ },
876
+ "functions": {
877
+ "description": "Exact emitted function names this override applies to. Empty means every\nfunction in matching files.",
878
+ "type": "array",
879
+ "items": {
880
+ "type": "string"
881
+ }
882
+ },
883
+ "maxCyclomatic": {
884
+ "description": "Local cyclomatic complexity ceiling.",
885
+ "type": [
886
+ "integer",
887
+ "null"
888
+ ],
889
+ "format": "uint16",
890
+ "minimum": 0,
891
+ "maximum": 65535
892
+ },
893
+ "maxCognitive": {
894
+ "description": "Local cognitive complexity ceiling.",
895
+ "type": [
896
+ "integer",
897
+ "null"
898
+ ],
899
+ "format": "uint16",
900
+ "minimum": 0,
901
+ "maximum": 65535
902
+ },
903
+ "maxCrap": {
904
+ "description": "Local CRAP ceiling.",
905
+ "type": [
906
+ "number",
907
+ "null"
908
+ ],
909
+ "format": "double"
910
+ },
911
+ "reason": {
912
+ "description": "Human-readable rationale for the exception.",
913
+ "type": [
914
+ "string",
915
+ "null"
916
+ ]
917
+ }
918
+ },
919
+ "additionalProperties": false,
920
+ "required": [
921
+ "files"
922
+ ]
856
923
  },
857
924
  "OwnershipConfig": {
858
925
  "description": "Configuration for ownership analysis (`fallow health --hotspots --ownership`).",
@@ -149,7 +149,7 @@ Run `fallow <command> --help` for the full flag list per command (see also refer
149
149
  | `boundary-violation` | `--boundary-violations` | - | `// fallow-ignore-next-line boundary-violation` | Imports crossing architecture zone boundaries. Presets: `layered`, `hexagonal`, `feature-sliced`, `bulletproof`; `autoDiscover` can create one zone per feature directory; per-rule `allowTypeOnly: [zones]` admits `import type` / `export type` crossings while still blocking value imports. Optional sections: `boundaries.coverage.requireAllFiles` reports unzoned source files (`allowUnmatched` globs exempt intentional ones), and `boundaries.calls.forbidden` bans callee patterns per zone (segment-aware and import-resolved, so `child_process.*` covers `node:child_process` named/namespace/default imports; direct callees only, zoned files only). The whole family shares the `boundary-violation` rule and suppression token (`boundary-call-violation` and `boundary-call-violations` accepted as aliases); start the rule at `warn` for a staged rollout |
150
150
  | `boundary-coverage` | - | - | `// fallow-ignore-file boundary-violation` | Source file matches no configured architecture boundary zone; Requires boundaries.coverage.requireAllFiles |
151
151
  | `boundary-call-violation` | - | - | `// fallow-ignore-next-line boundary-call-violation` | Zoned file calls a callee its zone forbids; Requires boundaries.calls.forbidden patterns |
152
- | `policy-violation` | `--policy-violations` | - | `// fallow-ignore-next-line policy-violation` | Calls or imports banned by a declarative rule pack (`rulePacks` config key lists standalone JSON/JSONC files of `banned-call` / `banned-import` rules; pure data, no project code executes). Findings identified as `<pack>/<rule-id>`. Default `warn` master; per-rule `severity` overrides per finding and the exit gate reads the effective severity. Invalid or missing packs fail config load with exit 2. `fallow rule-pack-schema` prints the pack JSON Schema. Suppress with `// fallow-ignore-next-line policy-violation` (one token covers every pack rule on the line). |
152
+ | `policy-violation` | `--policy-violations` | - | `// fallow-ignore-next-line policy-violation` | Calls or imports banned by a declarative rule pack (`rulePacks` config key lists standalone JSON/JSONC files of `banned-call` / `banned-import` rules; pure data, no project code executes). Findings identified as `<pack>/<rule-id>`. Default `warn` master; per-rule `severity` overrides per finding and the exit gate reads the effective severity. Invalid or missing packs fail config load with exit 2. `fallow rule-pack-schema` prints the pack JSON Schema. Use the scoped token to suppress one rule; bare `policy-violation` still covers every pack rule on the line or file. |
153
153
  | `stale-suppression` | `--stale-suppressions` | - | - | `fallow-ignore` comments or `@expected-unused` JSDoc tags that no longer match any issue |
154
154
  | `unused-catalog-entry` | `--unused-catalog-entries` | yes | - | `pnpm-workspace.yaml` entries no workspace package.json references via `catalog:` (default `warn`) |
155
155
  | `empty-catalog-group` | `--empty-catalog-groups` | - | - | Named `catalogs.<name>:` groups in `pnpm-workspace.yaml` with no entries. Top-level `catalog:` placeholders are ignored. Default `warn`. |
@@ -218,14 +218,14 @@ Most tools accept `root`, `config`, `no_cache`, and `threads` params. Exceptions
218
218
 
219
219
  All JSON responses include structured `actions` arrays on every finding (dead code, health, duplication), enabling programmatic fix application or suppression.
220
220
 
221
+ `health.thresholdOverrides[]` lets projects keep known legacy functions visible as configured local ceilings instead of hiding them with suppressions. Each entry has `files` globs, optional exact `functions`, one or more of `maxCyclomatic`, `maxCognitive`, or `maxCrap`, and optional `reason`. Health JSON may include top-level `threshold_overrides[]` entries with `active`, `stale`, or `no_match` status, and complexity findings that use an override carry `effective_thresholds` plus `threshold_source: "override"`.
222
+
221
223
  `dead-code`, `health`, `dupes`, bare `fallow`, and `audit` JSON output also carry a top-level `next_steps` array of read-only follow-up commands computed from the run's findings: each entry is `{ id, command, reason }`. The `command` is runnable as-is (never a placeholder, never `fix` or any other mutating command); the stable kebab-case `id` (`setup`, `impact-report`, `trace-unused-export`, `trace-clone`, `complexity-breakdown`, `scope-workspaces`, `audit-changed`) maps to a verification step you should run BEFORE acting, for example tracing an export before deleting it. A leading `setup` step (command: `fallow schema`) appears only on unconfigured, non-CI projects with findings and doubles as the onboarding trigger below; it disappears after setup or `fallow init --decline`. An at-most-weekly `impact-report` step (command: `fallow impact`) carries the local value digest when impact tracking has non-zero results; it may ride a clean run. When running via MCP, dispatch on the `id` to the matching tool / `code_execute` host call (`trace_export`, `trace_clone`, `check_health` with `complexity_breakdown: true`, `audit`) rather than shelling out the CLI string. The array is deduplicated, capped at three, and omitted when empty; set `FALLOW_SUGGESTIONS=off` to suppress it.
222
224
 
223
225
  ## Node.js Bindings
224
-
225
226
  Embedding fallow in a Node.js process (editor extensions, servers, custom tooling)? Use the `@fallow-cli/fallow-node` NAPI bindings instead of spawning the CLI: six async functions (`detectDeadCode`, `detectCircularDependencies`, `detectBoundaryViolations`, `detectDuplication`, `computeComplexity`, `computeHealth`) returning the same JSON envelopes as `--format json`. Read-only analysis only; use the CLI for write-path commands. Details: [Node Bindings](references/node-bindings.md).
226
227
 
227
228
  ## References
228
-
229
229
  - [CLI Reference](references/cli-reference.md): complete command and flag specifications, plus configuration field details
230
230
  - [Gotchas](references/gotchas.md): common pitfalls, edge cases, and correct usage patterns
231
231
  - [Patterns](references/patterns.md): workflow recipes for CI, monorepos, migration, and incremental adoption
@@ -492,7 +492,7 @@ fallow health --format json --quiet --trend
492
492
  {
493
493
  "kind": "health",
494
494
  "schema_version": 7,
495
- "version": "2.94.0",
495
+ "version": "2.95.0",
496
496
  "elapsed_ms": 32,
497
497
  "summary": {
498
498
  "files_analyzed": 482,
@@ -516,6 +516,8 @@ fallow health --format json --quiet --trend
516
516
  }
517
517
  ```
518
518
 
519
+ `health.thresholdOverrides[]` config entries can raise local cyclomatic, cognitive, or CRAP ceilings for matching files and optional exact function names. When an override affects output, health JSON includes top-level `threshold_overrides[]` state entries (`active`, `stale`, or `no_match`). Complexity findings evaluated with local ceilings include `effective_thresholds` and `threshold_source: "override"` so agents can see which thresholds drove the finding and avoid treating configured exceptions as hidden suppressions.
520
+
519
521
  When the unit size very-high-risk percentage is >= 3%, the JSON output includes a `large_functions` array listing functions exceeding 60 lines of code:
520
522
 
521
523
  ```json
@@ -877,7 +879,7 @@ fallow audit \
877
879
  {
878
880
  "kind": "audit",
879
881
  "schema_version": 7,
880
- "version": "2.94.0",
882
+ "version": "2.95.0",
881
883
  "command": "audit",
882
884
  "verdict": "fail",
883
885
  "changed_files_count": 12,
@@ -952,7 +954,7 @@ fallow flags --format json --quiet --workspace my-package
952
954
  ```json
953
955
  {
954
956
  "schema_version": 7,
955
- "version": "2.94.0",
957
+ "version": "2.95.0",
956
958
  "elapsed_ms": 116,
957
959
  "feature_flags": [],
958
960
  "total_flags": 0
@@ -1052,7 +1054,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1052
1054
  {
1053
1055
  "kind": "security",
1054
1056
  "schema_version": "4",
1055
- "version": "2.94.0",
1057
+ "version": "2.95.0",
1056
1058
  "elapsed_ms": 42,
1057
1059
  "config": {
1058
1060
  "rules": {
@@ -1081,7 +1083,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1081
1083
  {
1082
1084
  "kind": "security",
1083
1085
  "schema_version": "4",
1084
- "version": "2.94.0",
1086
+ "version": "2.95.0",
1085
1087
  "elapsed_ms": 42,
1086
1088
  "config": {
1087
1089
  "rules": {
@@ -1697,7 +1699,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1697
1699
  {
1698
1700
  "kind": "dead-code",
1699
1701
  "schema_version": 7,
1700
- "version": "2.94.0",
1702
+ "version": "2.95.0",
1701
1703
  "elapsed_ms": 45,
1702
1704
  "total_issues": 12,
1703
1705
  "entry_points": {
@@ -1857,7 +1859,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1857
1859
  {
1858
1860
  "kind": "dupes",
1859
1861
  "schema_version": 7,
1860
- "version": "2.94.0",
1862
+ "version": "2.95.0",
1861
1863
  "elapsed_ms": 82,
1862
1864
  "total_clones": 15,
1863
1865
  "total_lines_duplicated": 230,
@@ -1901,11 +1903,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1901
1903
  {
1902
1904
  "kind": "combined",
1903
1905
  "schema_version": 7,
1904
- "version": "2.94.0",
1906
+ "version": "2.95.0",
1905
1907
  "elapsed_ms": 159,
1906
1908
  "check": {
1907
1909
  "schema_version": 7,
1908
- "version": "2.94.0",
1910
+ "version": "2.95.0",
1909
1911
  "elapsed_ms": 45,
1910
1912
  "total_issues": 12,
1911
1913
  "unused_files": [],
@@ -390,6 +390,10 @@ export type ComplexityMetric = ("cyclomatic" | "cognitive")
390
390
  * to cyclomatic complexity and so produces no contribution.
391
391
  */
392
392
  export type ComplexityContributionKind = ("if" | "else" | "else-if" | "ternary" | "logical-and" | "logical-or" | "nullish-coalescing" | "logical-assignment" | "optional-chain" | "for" | "for-in" | "for-of" | "while" | "do-while" | "switch" | "case" | "catch" | "labeled-break" | "labeled-continue")
393
+ /**
394
+ * Source for a finding's effective thresholds.
395
+ */
396
+ export type ThresholdSource = "override"
393
397
  /**
394
398
  * Discriminant for [`HealthFindingAction::kind`]. Mirrors the action types
395
399
  * emitted by `build_health_finding_actions`. A single finding's `actions`
@@ -407,6 +411,10 @@ export type CoverageModel = ("static_binary" | "static_estimated" | "istanbul")
407
411
  * Whether CRAP findings in the report used one coverage-source kind or a mix.
408
412
  */
409
413
  export type CoverageSourceConsistency = ("uniform" | "mixed")
414
+ /**
415
+ * Lifecycle state for a configured threshold override.
416
+ */
417
+ export type ThresholdOverrideStatus = ("active" | "stale" | "no_match")
410
418
  /**
411
419
  * Discriminant for [`UntestedFileAction::kind`]. Mirrors the action types
412
420
  * emitted by `build_untested_file_actions`.
@@ -2080,8 +2088,8 @@ introduced?: (AuditIntroduced | null)
2080
2088
  }
2081
2089
  /**
2082
2090
  * Wire-shape envelope for a [`PolicyViolation`] finding. Carries actions for
2083
- * replacing the banned call or import, or suppressing it with the
2084
- * `policy-violation` token.
2091
+ * replacing the banned call or import, or suppressing it with a scoped
2092
+ * `policy-violation:<pack>/<rule-id>` token.
2085
2093
  */
2086
2094
  export interface PolicyViolationFinding {
2087
2095
  /**
@@ -2816,6 +2824,11 @@ export interface HealthReport {
2816
2824
  */
2817
2825
  findings: HealthFinding[]
2818
2826
  summary: HealthSummary
2827
+ /**
2828
+ * Configured threshold override states. Entries are emitted for active
2829
+ * exceptions, stale exceptions, and full-run no-match cleanup hints.
2830
+ */
2831
+ threshold_overrides?: ThresholdOverrideState[]
2819
2832
  /**
2820
2833
  * Project-wide vital signs (always computed from available data).
2821
2834
  */
@@ -2915,6 +2928,15 @@ component_rollup?: (ComponentRollup | null)
2915
2928
  * otherwise so default and CI output stay lean.
2916
2929
  */
2917
2930
  contributions?: ComplexityContribution[]
2931
+ /**
2932
+ * Resolved thresholds used for this finding when a config override changed
2933
+ * at least one ceiling. Omitted for findings using global thresholds.
2934
+ */
2935
+ effective_thresholds?: (HealthEffectiveThresholds | null)
2936
+ /**
2937
+ * Source of the effective thresholds. Omitted when thresholds are global.
2938
+ */
2939
+ threshold_source?: (ThresholdSource | null)
2918
2940
  /**
2919
2941
  * Machine-actionable fix and suppress hints.
2920
2942
  */
@@ -2964,6 +2986,14 @@ weight: number
2964
2986
  */
2965
2987
  nesting: number
2966
2988
  }
2989
+ /**
2990
+ * Resolved thresholds used to evaluate a health finding.
2991
+ */
2992
+ export interface HealthEffectiveThresholds {
2993
+ max_cyclomatic: number
2994
+ max_cognitive: number
2995
+ max_crap: number
2996
+ }
2967
2997
  /**
2968
2998
  * Suggested action attached to a [`ComplexityViolation`].
2969
2999
  *
@@ -3046,6 +3076,36 @@ severity_critical_count: number
3046
3076
  severity_high_count: number
3047
3077
  severity_moderate_count: number
3048
3078
  }
3079
+ /**
3080
+ * Report entry describing whether a threshold override is active, stale, or
3081
+ * no longer matching any analyzed file or function.
3082
+ */
3083
+ export interface ThresholdOverrideState {
3084
+ status: ThresholdOverrideStatus
3085
+ override_index: number
3086
+ path?: (string | null)
3087
+ function?: (string | null)
3088
+ configured_thresholds: HealthConfiguredThresholds
3089
+ effective_thresholds: HealthEffectiveThresholds
3090
+ metrics?: (ThresholdOverrideMetrics | null)
3091
+ reason?: (string | null)
3092
+ }
3093
+ /**
3094
+ * Threshold values configured by a single override entry.
3095
+ */
3096
+ export interface HealthConfiguredThresholds {
3097
+ max_cyclomatic?: (number | null)
3098
+ max_cognitive?: (number | null)
3099
+ max_crap?: (number | null)
3100
+ }
3101
+ /**
3102
+ * Current complexity metrics for a matched threshold override entry.
3103
+ */
3104
+ export interface ThresholdOverrideMetrics {
3105
+ cyclomatic: number
3106
+ cognitive: number
3107
+ crap?: (number | null)
3108
+ }
3049
3109
  /**
3050
3110
  * Project-wide vital signs , a fixed set of metrics for trend tracking.
3051
3111
  *
@@ -4609,6 +4669,11 @@ elapsed_ms: ElapsedMs
4609
4669
  */
4610
4670
  findings: HealthFinding[]
4611
4671
  summary: HealthSummary
4672
+ /**
4673
+ * Configured threshold override states. Entries are emitted for active
4674
+ * exceptions, stale exceptions, and full-run no-match cleanup hints.
4675
+ */
4676
+ threshold_overrides?: ThresholdOverrideState[]
4612
4677
  /**
4613
4678
  * Project-wide vital signs (always computed from available data).
4614
4679
  */