fallow 3.41.0 → 3.43.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.
@@ -1300,6 +1300,42 @@
1300
1300
  "license_note": null,
1301
1301
  "docs_url": "https://fallow.tools/docs/explanations/dead-code/#absent-component-props"
1302
1302
  },
1303
+ {
1304
+ "id": "constant-parameter",
1305
+ "rule_id": "fallow/constant-parameter",
1306
+ "command": "dead-code",
1307
+ "category": "Dead code",
1308
+ "description": "Each visible call passes a function parameter in the same way",
1309
+ "label": "Constant Parameters",
1310
+ "config_key": "constant-parameters",
1311
+ "registry_index": 35,
1312
+ "aliases": [
1313
+ "constant-parameters"
1314
+ ],
1315
+ "lsp": true,
1316
+ "filter_flag": "--constant-parameters",
1317
+ "result_key": "constant_parameters",
1318
+ "summary_label": "Constant parameters",
1319
+ "summary_docs_anchor": "constant-parameters",
1320
+ "sarif_rule_ids": [
1321
+ "fallow/constant-parameter"
1322
+ ],
1323
+ "codeclimate_check_names": [
1324
+ "fallow/constant-parameter"
1325
+ ],
1326
+ "ts_alias": null,
1327
+ "counts_in_total": true,
1328
+ "fixable": false,
1329
+ "suppressible": true,
1330
+ "suppress_comment": "// fallow-ignore-next-line constant-parameter",
1331
+ "default_severity": "off",
1332
+ "opt_in": true,
1333
+ "frameworks": [],
1334
+ "note": "Opt-in manual review candidate; defaults to off. Inspect the calls and the intent of the parameter before changing the function. No automatic fix.",
1335
+ "license": "free",
1336
+ "license_note": null,
1337
+ "docs_url": "https://fallow.tools/docs/explanations/dead-code/#constant-parameters"
1338
+ },
1303
1339
  {
1304
1340
  "id": "unused-component-emit",
1305
1341
  "rule_id": "fallow/unused-component-emit",
@@ -1308,7 +1344,7 @@
1308
1344
  "description": "A Vue <script setup> defineEmits event is emitted nowhere in its own component",
1309
1345
  "label": "Unused Component Emits",
1310
1346
  "config_key": "unused-component-emits",
1311
- "registry_index": 35,
1347
+ "registry_index": 36,
1312
1348
  "aliases": [
1313
1349
  "unused-component-emits"
1314
1350
  ],
@@ -1344,7 +1380,7 @@
1344
1380
  "description": "An Angular @Input() / signal input() / model() input is read nowhere in its own component",
1345
1381
  "label": "Unused Component Inputs",
1346
1382
  "config_key": "unused-component-inputs",
1347
- "registry_index": 36,
1383
+ "registry_index": 37,
1348
1384
  "aliases": [
1349
1385
  "unused-component-inputs"
1350
1386
  ],
@@ -1380,7 +1416,7 @@
1380
1416
  "description": "An Angular @Output() / signal output() output is emitted nowhere in its own component",
1381
1417
  "label": "Unused Component Outputs",
1382
1418
  "config_key": "unused-component-outputs",
1383
- "registry_index": 37,
1419
+ "registry_index": 38,
1384
1420
  "aliases": [
1385
1421
  "unused-component-outputs"
1386
1422
  ],
@@ -1416,7 +1452,7 @@
1416
1452
  "description": "A Svelte component dispatches a createEventDispatcher event whose name is listened to nowhere in the project",
1417
1453
  "label": "Unused Svelte Events",
1418
1454
  "config_key": "unused-svelte-events",
1419
- "registry_index": 38,
1455
+ "registry_index": 39,
1420
1456
  "aliases": [
1421
1457
  "unused-svelte-events"
1422
1458
  ],
@@ -1452,7 +1488,7 @@
1452
1488
  "description": "A Next.js Server Action exported from a \"use server\" file is referenced by no code in the project",
1453
1489
  "label": "Unused Server Actions",
1454
1490
  "config_key": "unused-server-actions",
1455
- "registry_index": 39,
1491
+ "registry_index": 40,
1456
1492
  "aliases": [
1457
1493
  "unused-server-actions"
1458
1494
  ],
@@ -1488,7 +1524,7 @@
1488
1524
  "description": "A SvelteKit load() return-object key is read by no consumer",
1489
1525
  "label": "Unused Load Data Keys",
1490
1526
  "config_key": "unused-load-data-keys",
1491
- "registry_index": 40,
1527
+ "registry_index": 41,
1492
1528
  "aliases": [
1493
1529
  "unused-load-data-keys"
1494
1530
  ],
@@ -1524,7 +1560,7 @@
1524
1560
  "description": "An Effect layer is composed only into layers that nothing uses",
1525
1561
  "label": "Unused Effect Layers",
1526
1562
  "config_key": "unused-effect-layers",
1527
- "registry_index": 41,
1563
+ "registry_index": 42,
1528
1564
  "aliases": [
1529
1565
  "unused-effect-layers"
1530
1566
  ],
@@ -1560,7 +1596,7 @@
1560
1596
  "description": "An Effect tagged error class is referenced only as a type or a catchTag string, and no code constructs or fails with it",
1561
1597
  "label": "Unused Tagged Errors",
1562
1598
  "config_key": "unused-tagged-errors",
1563
- "registry_index": 42,
1599
+ "registry_index": 43,
1564
1600
  "aliases": [
1565
1601
  "unused-tagged-errors"
1566
1602
  ],
@@ -1596,7 +1632,7 @@
1596
1632
  "description": "A catchTag handler names a project error tag that no code produces",
1597
1633
  "label": "Unproduced Catch Tags",
1598
1634
  "config_key": "unproduced-catch-tags",
1599
- "registry_index": 43,
1635
+ "registry_index": 44,
1600
1636
  "aliases": [
1601
1637
  "unproduced-catch-tags"
1602
1638
  ],
@@ -1632,7 +1668,7 @@
1632
1668
  "description": "Two or more Next.js App Router route files resolve to the same URL",
1633
1669
  "label": "Route Collisions",
1634
1670
  "config_key": "route-collision",
1635
- "registry_index": 44,
1671
+ "registry_index": 45,
1636
1672
  "aliases": [
1637
1673
  "route-collisions"
1638
1674
  ],
@@ -1670,7 +1706,7 @@
1670
1706
  "description": "Sibling Next.js dynamic route segments use different slug names at the same position",
1671
1707
  "label": "Dynamic Segment Conflicts",
1672
1708
  "config_key": "dynamic-segment-name-conflict",
1673
- "registry_index": 45,
1709
+ "registry_index": 46,
1674
1710
  "aliases": [
1675
1711
  "dynamic-segment-name-conflicts"
1676
1712
  ],
@@ -1708,7 +1744,7 @@
1708
1744
  "description": "Suppression comment or tag no longer matches any issue",
1709
1745
  "label": "Stale Suppressions",
1710
1746
  "config_key": "stale-suppressions",
1711
- "registry_index": 46,
1747
+ "registry_index": 47,
1712
1748
  "aliases": [],
1713
1749
  "lsp": true,
1714
1750
  "filter_flag": "--stale-suppressions",
@@ -1744,7 +1780,7 @@
1744
1780
  "description": "Suppression comment omits a required reason",
1745
1781
  "label": "Missing Suppression Reasons",
1746
1782
  "config_key": "require-suppression-reason",
1747
- "registry_index": 47,
1783
+ "registry_index": 48,
1748
1784
  "aliases": [
1749
1785
  "missing-suppression-reasons"
1750
1786
  ],
@@ -1776,7 +1812,7 @@
1776
1812
  "description": "Catalog entry not referenced by any workspace package",
1777
1813
  "label": "Unused Catalog Entries",
1778
1814
  "config_key": "unused-catalog-entries",
1779
- "registry_index": 48,
1815
+ "registry_index": 49,
1780
1816
  "aliases": [
1781
1817
  "catalog",
1782
1818
  "unused-catalog-entries"
@@ -1816,7 +1852,7 @@
1816
1852
  "description": "Named catalog group has no entries",
1817
1853
  "label": "Empty Catalog Groups",
1818
1854
  "config_key": "empty-catalog-groups",
1819
- "registry_index": 49,
1855
+ "registry_index": 50,
1820
1856
  "aliases": [
1821
1857
  "empty-catalog",
1822
1858
  "empty-catalog-groups"
@@ -1856,7 +1892,7 @@
1856
1892
  "description": "package.json references a catalog that does not declare the package",
1857
1893
  "label": "Unresolved Catalog References",
1858
1894
  "config_key": "unresolved-catalog-references",
1859
- "registry_index": 50,
1895
+ "registry_index": 51,
1860
1896
  "aliases": [
1861
1897
  "unresolved-catalog",
1862
1898
  "unresolved-catalog-references"
@@ -1896,7 +1932,7 @@
1896
1932
  "description": "Package-manager override target is not declared or resolved",
1897
1933
  "label": "Unused Dependency Overrides",
1898
1934
  "config_key": "unused-dependency-overrides",
1899
- "registry_index": 51,
1935
+ "registry_index": 52,
1900
1936
  "aliases": [
1901
1937
  "unused-dependency-overrides",
1902
1938
  "unused-override",
@@ -1937,7 +1973,7 @@
1937
1973
  "description": "Package-manager override has an unparsable key or value",
1938
1974
  "label": "Misconfigured Dependency Overrides",
1939
1975
  "config_key": "misconfigured-dependency-overrides",
1940
- "registry_index": 52,
1976
+ "registry_index": 53,
1941
1977
  "aliases": [
1942
1978
  "misconfigured-dependency-overrides",
1943
1979
  "misconfigured-override",
@@ -1978,7 +2014,7 @@
1978
2014
  "description": "Detected feature flag pattern",
1979
2015
  "label": "Feature Flags",
1980
2016
  "config_key": "feature-flags",
1981
- "registry_index": 56,
2017
+ "registry_index": 57,
1982
2018
  "aliases": [],
1983
2019
  "lsp": false,
1984
2020
  "filter_flag": null,
@@ -2008,7 +2044,7 @@
2008
2044
  "description": "A React/Preact prop is forwarded unchanged through 3+ pass-through components to a distant consumer",
2009
2045
  "label": "Prop Drilling",
2010
2046
  "config_key": "prop-drilling",
2011
- "registry_index": 58,
2047
+ "registry_index": 59,
2012
2048
  "aliases": [],
2013
2049
  "lsp": true,
2014
2050
  "filter_flag": null,
@@ -2042,7 +2078,7 @@
2042
2078
  "description": "A React/Preact component whose whole body is a single spread-forwarded child render (a candidate for inlining)",
2043
2079
  "label": "Thin Wrappers",
2044
2080
  "config_key": "thin-wrapper",
2045
- "registry_index": 59,
2081
+ "registry_index": 60,
2046
2082
  "aliases": [
2047
2083
  "thin-wrappers"
2048
2084
  ],
@@ -2078,7 +2114,7 @@
2078
2114
  "description": "Three or more React/Preact components across two or more files declare an identical prop-name set (a missing shared Props type)",
2079
2115
  "label": "Duplicate Prop Shapes",
2080
2116
  "config_key": "duplicate-prop-shape",
2081
- "registry_index": 60,
2117
+ "registry_index": 61,
2082
2118
  "aliases": [
2083
2119
  "duplicate-prop-shapes"
2084
2120
  ],
@@ -2114,7 +2150,7 @@
2114
2150
  "description": "CSS or CSS-in-JS hardcoded styling value bypasses the design token system",
2115
2151
  "label": "CSS Token Drift",
2116
2152
  "config_key": "css-token-drift",
2117
- "registry_index": 61,
2153
+ "registry_index": 62,
2118
2154
  "aliases": [],
2119
2155
  "lsp": false,
2120
2156
  "filter_flag": null,
@@ -2144,7 +2180,7 @@
2144
2180
  "description": "CSS or CSS-in-JS declaration block is duplicated across rules",
2145
2181
  "label": "CSS Duplicate Block",
2146
2182
  "config_key": "css-duplicate-block",
2147
- "registry_index": 62,
2183
+ "registry_index": 63,
2148
2184
  "aliases": [],
2149
2185
  "lsp": false,
2150
2186
  "filter_flag": null,
@@ -2174,7 +2210,7 @@
2174
2210
  "description": "CSS selector, nesting, or important usage is structurally complex",
2175
2211
  "label": "CSS Selector Complexity",
2176
2212
  "config_key": "css-selector-complexity",
2177
- "registry_index": 63,
2213
+ "registry_index": 64,
2178
2214
  "aliases": [],
2179
2215
  "lsp": false,
2180
2216
  "filter_flag": null,
@@ -2204,7 +2240,7 @@
2204
2240
  "description": "CSS or CSS-in-JS surface appears unused",
2205
2241
  "label": "CSS Dead Surface",
2206
2242
  "config_key": "css-dead-surface",
2207
- "registry_index": 64,
2243
+ "registry_index": 65,
2208
2244
  "aliases": [],
2209
2245
  "lsp": false,
2210
2246
  "filter_flag": null,
@@ -2234,7 +2270,7 @@
2234
2270
  "description": "CSS or CSS-in-JS reference resolves to no stylesheet definition",
2235
2271
  "label": "CSS Broken Reference",
2236
2272
  "config_key": "css-broken-reference",
2237
- "registry_index": 65,
2273
+ "registry_index": 66,
2238
2274
  "aliases": [],
2239
2275
  "lsp": false,
2240
2276
  "filter_flag": null,
@@ -2264,7 +2300,7 @@
2264
2300
  "description": "The change weakens tests or a coverage threshold",
2265
2301
  "label": "Weakened Tests",
2266
2302
  "config_key": "weakened-tests",
2267
- "registry_index": 66,
2303
+ "registry_index": 67,
2268
2304
  "aliases": [],
2269
2305
  "lsp": false,
2270
2306
  "filter_flag": null,
@@ -2294,7 +2330,7 @@
2294
2330
  "description": "The change adds a suppression comment",
2295
2331
  "label": "Added Suppressions",
2296
2332
  "config_key": "added-suppression",
2297
- "registry_index": 67,
2333
+ "registry_index": 68,
2298
2334
  "aliases": [],
2299
2335
  "lsp": false,
2300
2336
  "filter_flag": null,
@@ -2324,7 +2360,7 @@
2324
2360
  "description": "The change adds a test-environment branch to source code",
2325
2361
  "label": "Test-Only Branches",
2326
2362
  "config_key": "test-only-branch",
2327
- "registry_index": 68,
2363
+ "registry_index": 69,
2328
2364
  "aliases": [],
2329
2365
  "lsp": false,
2330
2366
  "filter_flag": null,
@@ -2354,7 +2390,7 @@
2354
2390
  "description": "The change edits one copy of duplicated code but not its siblings",
2355
2391
  "label": "Diverged Clone Siblings",
2356
2392
  "config_key": "diverged-clone-sibling",
2357
- "registry_index": 69,
2393
+ "registry_index": 70,
2358
2394
  "aliases": [],
2359
2395
  "lsp": false,
2360
2396
  "filter_flag": null,
@@ -2384,7 +2420,7 @@
2384
2420
  "description": "The change adds a dependency",
2385
2421
  "label": "Added Dependencies",
2386
2422
  "config_key": "added-dependency",
2387
- "registry_index": 70,
2423
+ "registry_index": 71,
2388
2424
  "aliases": [],
2389
2425
  "lsp": false,
2390
2426
  "filter_flag": null,
@@ -3336,6 +3372,36 @@
3336
3372
  "license_note": null,
3337
3373
  "docs_url": "https://fallow.tools/docs/cli/security/"
3338
3374
  },
3375
+ {
3376
+ "id": "mutation-survived",
3377
+ "rule_id": "fallow/mutation-survived",
3378
+ "command": "mutation",
3379
+ "category": "Tests",
3380
+ "description": "A small code change made no test fail",
3381
+ "label": null,
3382
+ "config_key": null,
3383
+ "registry_index": null,
3384
+ "aliases": [],
3385
+ "lsp": false,
3386
+ "filter_flag": null,
3387
+ "result_key": null,
3388
+ "summary_label": null,
3389
+ "summary_docs_anchor": null,
3390
+ "sarif_rule_ids": null,
3391
+ "codeclimate_check_names": null,
3392
+ "ts_alias": null,
3393
+ "counts_in_total": false,
3394
+ "fixable": false,
3395
+ "suppressible": false,
3396
+ "suppress_comment": null,
3397
+ "default_severity": null,
3398
+ "opt_in": null,
3399
+ "frameworks": [],
3400
+ "note": null,
3401
+ "license": "free",
3402
+ "license_note": null,
3403
+ "docs_url": "https://fallow.tools/docs/cli/mutation/"
3404
+ },
3339
3405
  {
3340
3406
  "id": "mysql-multiple-statements",
3341
3407
  "rule_id": "security/mysql-multiple-statements",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "3.41.0",
3
+ "version": "3.43.0",
4
4
  "mcpName": "io.github.fallow-rs/fallow",
5
5
  "description": "Codebase intelligence for TypeScript and JavaScript: health, complexity, duplication, architecture, styling drift, and unused code from one graph. CLI, LSP, and MCP server. Zero config for over 100 frameworks.",
6
6
  "license": "MIT",
@@ -92,14 +92,13 @@
92
92
  "@tanstack/intent": "0.5.6"
93
93
  },
94
94
  "optionalDependencies": {
95
- "@fallow-cli/darwin-arm64": "3.41.0",
96
- "@fallow-cli/darwin-x64": "3.41.0",
97
- "@fallow-cli/linux-x64-gnu": "3.41.0",
98
- "@fallow-cli/linux-arm64-gnu": "3.41.0",
99
- "@fallow-cli/linux-x64-musl": "3.41.0",
100
- "@fallow-cli/linux-arm64-musl": "3.41.0",
101
- "@fallow-cli/win32-arm64-msvc": "3.41.0",
102
- "@fallow-cli/win32-x64-msvc": "3.41.0",
103
- "fallow-type-aware": "3.41.0"
95
+ "@fallow-cli/darwin-arm64": "3.43.0",
96
+ "@fallow-cli/darwin-x64": "3.43.0",
97
+ "@fallow-cli/linux-x64-gnu": "3.43.0",
98
+ "@fallow-cli/linux-arm64-gnu": "3.43.0",
99
+ "@fallow-cli/linux-x64-musl": "3.43.0",
100
+ "@fallow-cli/linux-arm64-musl": "3.43.0",
101
+ "@fallow-cli/win32-arm64-msvc": "3.43.0",
102
+ "@fallow-cli/win32-x64-msvc": "3.43.0"
104
103
  }
105
104
  }
package/schema.json CHANGED
@@ -189,11 +189,11 @@
189
189
  }
190
190
  },
191
191
  "mutation": {
192
- "description": "Configures the explicit `fallow mutation` workflow: `runner` (`auto`\nor `vitest`), `operators` (kebab-case names, default each operator),\n`minScore` (0 to 100; a lower score exits with code 1), and\n`concurrency` (half the logical cores). No key starts a run, and the\nside-effect override is a CLI flag only.",
192
+ "description": "Configures the explicit `fallow mutation` workflow: `runner` (`auto`\nor `vitest`), `operators` (kebab-case names, default the default set),\n`minScore` (0 to 100; a lower score exits with code 1), and\n`concurrency` (half the logical cores). No key starts a run, and the\nside-effect override is a CLI flag only.",
193
193
  "$ref": "#/$defs/MutationConfig"
194
194
  },
195
195
  "health": {
196
- "description": "Sets complexity and health thresholds for `fallow health` (also applied in combined `fallow` and `fallow audit`): `maxCyclomatic` (20), `maxCognitive` (15), `maxCrap` (30.0, findings at or above this are reported), `crapRefactorBand` (5, cyclomatic band below `maxCyclomatic` where a secondary refactor action is added), `maxUnitSize` (max function lines before a large-function finding, 60), `maxFileLines` (max physical lines per file before a file-level finding, 0 means off), `coverage`/`coverageRoot` (Istanbul coverage path and path-prefix strip for accurate CRAP), `ignore` globs (remove files from findings AND the health score), `thresholdOverrides` (per-file/per-function ceilings via `files`/`functions`/`maxCyclomatic`/`maxCognitive`/`maxCrap`/`maxUnitSize`/`maxFileLines`/`reason`), `ownership` (`botPatterns` and `emailMode` for `--ownership`), and `suggestInlineSuppression` (true, emit `suppress-line` action hints in JSON). Raise thresholds to relax which functions are flagged, wire `coverage` for real CRAP scores, or exempt generated/test files via `ignore` (drops them from the score too) or `thresholdOverrides` (keeps them visible under a higher ceiling). The `max*` thresholds govern findings only and never move `health_score`: its penalties use fixed calibration so grades stay comparable across projects, and `ignore` is the lever that removes files from the score.",
196
+ "description": "Sets complexity and health thresholds for `fallow health` (also applied in combined `fallow` and `fallow audit`): `maxCyclomatic` (20), `maxCognitive` (15), `maxCrap` (30.0, findings at or above this are reported), `crapRefactorBand` (5, cyclomatic band below `maxCyclomatic` where a secondary refactor action is added), `maxUnitSize` (max function lines before a large-function finding, 60), `maxFileLines` (max physical lines per file before a file-level finding, 0 means off), `coverage`/`coverageRoot` (Istanbul coverage path and path-prefix strip for accurate CRAP), `ignore` globs (remove files from findings AND the health score), `tailwindIgnorePatterns` (regexes on normalized `prefix-[value]` Tailwind arbitrary-value tokens to exclude from `--css` findings and analytics), `thresholdOverrides` (per-file/per-function ceilings via `files`/`functions`/`maxCyclomatic`/`maxCognitive`/`maxCrap`/`maxUnitSize`/`maxFileLines`/`reason`), `ownership` (`botPatterns` and `emailMode` for `--ownership`), and `suggestInlineSuppression` (true, emit `suppress-line` action hints in JSON). Raise thresholds to relax which functions are flagged, wire `coverage` for real CRAP scores, or exempt generated/test files via `ignore` (drops them from the score too) or `thresholdOverrides` (keeps them visible under a higher ceiling). The `max*` thresholds govern findings only and never move `health_score`: its penalties use fixed calibration so grades stay comparable across projects, and `ignore` is the lever that removes files from the score.",
197
197
  "$ref": "#/$defs/HealthConfig",
198
198
  "default": {
199
199
  "maxCyclomatic": 20,
@@ -248,6 +248,7 @@
248
248
  "unrendered-components": "warn",
249
249
  "unused-component-props": "warn",
250
250
  "absent-component-props": "off",
251
+ "constant-parameters": "off",
251
252
  "unused-component-emits": "warn",
252
253
  "unused-component-inputs": "warn",
253
254
  "unused-component-outputs": "warn",
@@ -332,6 +333,18 @@
332
333
  "configObjectHeuristics": false
333
334
  }
334
335
  },
336
+ "sharedStateAllowlist": {
337
+ "description": "Exact [global root, direct slot] pairs excluded from shared-state inventory.",
338
+ "type": "array",
339
+ "items": {
340
+ "type": "array",
341
+ "items": {
342
+ "type": "string"
343
+ },
344
+ "minItems": 2,
345
+ "maxItems": 2
346
+ }
347
+ },
335
348
  "security": {
336
349
  "description": "Scopes the opt-in `fallow security` catalogue: which candidate categories run and which extra local identifiers count as HTTP request objects. Set when tuning security-candidate detection; the object holds `categories` (an object with `include` and/or `exclude` string arrays of catalogue category ids, where `include` restricts to a whitelist and `exclude` removes from the admitted set, both unset admits all ordinary categories) and `requestReceivers` (a string array of project-local names that extend, not replace, the built-in `*.query`/`*.params`/`*.body` source-receiver allowlist). The `hardcoded-secret` and `secret-to-network` categories are include-required: they fire only when explicitly listed in `categories.include`, even when no include list is otherwise set. The valid category ids are enumerated (with title, CWE, and include-required flag) in the `security_categories` block of `fallow schema`, and also listed by `fallow security --help`; they are not in this config-schema.",
337
350
  "$ref": "#/$defs/SecurityConfig",
@@ -1174,7 +1187,7 @@
1174
1187
  "default": "auto"
1175
1188
  },
1176
1189
  "operators": {
1177
- "description": "The operators to use. Unset uses each operator. `--operators` wins.",
1190
+ "description": "The operators to use. Unset uses the default set. An opt-in operator\nruns only when this list or `--operators` names it. `--operators`\nwins.",
1178
1191
  "type": [
1179
1192
  "array",
1180
1193
  "null"
@@ -1202,8 +1215,24 @@
1202
1215
  "format": "uint",
1203
1216
  "minimum": 1
1204
1217
  },
1218
+ "mutantsPerLine": {
1219
+ "description": "The maximum number of mutants on one source line. The plan keeps the\nmost productive mutants of the line (relational, condition,\narithmetic and logical operators first). The others are `pending`\nwith the reason `sampled-out`. Unset keeps each mutant.\n`--mutants-per-line` wins.",
1220
+ "type": [
1221
+ "integer",
1222
+ "null"
1223
+ ],
1224
+ "format": "uint",
1225
+ "minimum": 1
1226
+ },
1227
+ "functionScope": {
1228
+ "description": "Widen each changed line to the whole function that holds it, so that a\nchange to a parameter or a signature selects the mutants of the\nfunction. Only the changed-code scope uses it. Unset or `false` mutates\nthe changed lines only. `--function-scope` turns it on.",
1229
+ "type": [
1230
+ "boolean",
1231
+ "null"
1232
+ ]
1233
+ },
1205
1234
  "typecheck": {
1206
- "description": "Type-check each survived mutant through the TypeScript-Go companion\nof `--type-aware`. A survivor that does not type-check becomes\n`compile_error` and does not count in the score. Unset or `false`\nchecks no survivor. `--typecheck` turns the check on.",
1235
+ "description": "Type-check each survived mutant through the TypeScript-Go companion\nof `--type-aware`. A survivor that does not type-check becomes\n`compile_error` and does not count in the score. A survivor that\nremoves an optional-chaining link or a nullish fallback from a\nreceiver whose type excludes `null` and `undefined` gets an advisory\n`equivalence_hint`. Its status\nand the score do not change. Unset or `false` checks no survivor.\n`--typecheck` turns the check on.",
1207
1236
  "type": [
1208
1237
  "boolean",
1209
1238
  "null"
@@ -1293,7 +1322,7 @@
1293
1322
  "const": "boolean-literal"
1294
1323
  },
1295
1324
  {
1296
- "description": "A string literal emptied or filled.",
1325
+ "description": "A string or template literal emptied or filled.",
1297
1326
  "type": "string",
1298
1327
  "const": "string-literal"
1299
1328
  },
@@ -1303,7 +1332,7 @@
1303
1332
  "const": "optional-chaining"
1304
1333
  },
1305
1334
  {
1306
- "description": "One token of a regular expression literal changed: an anchor\nremoved, a character class negated, or a class escape with the\nopposite case.",
1335
+ "description": "One token of a regular expression literal changed: an anchor or a\nquantifier removed, a `{n,m}` range shortened to `{n}`, a character\nclass negated, or a class escape with the opposite case.",
1307
1336
  "type": "string",
1308
1337
  "const": "regex-literal"
1309
1338
  },
@@ -1311,6 +1340,56 @@
1311
1340
  "description": "`z.number().int()` to `z.number()` in a module-level `const`\ninitializer: one call link of a fluent chain removed.",
1312
1341
  "type": "string",
1313
1342
  "const": "removed-chain-link"
1343
+ },
1344
+ {
1345
+ "description": "Opt-in. The statements of a block or function body removed.",
1346
+ "type": "string",
1347
+ "const": "block-statement"
1348
+ },
1349
+ {
1350
+ "description": "Opt-in. `[x]` to `[]`, and `[]` to `[\"fallow\"]`.",
1351
+ "type": "string",
1352
+ "const": "array-literal"
1353
+ },
1354
+ {
1355
+ "description": "Opt-in. A non-empty object literal to `{}`.",
1356
+ "type": "string",
1357
+ "const": "object-literal"
1358
+ },
1359
+ {
1360
+ "description": "Opt-in. `startsWith` to `endsWith` and the other method pairs, or\n`s.trim()` to `s`.",
1361
+ "type": "string",
1362
+ "const": "method-expression"
1363
+ },
1364
+ {
1365
+ "description": "Opt-in. The statements of a `case` clause removed.",
1366
+ "type": "string",
1367
+ "const": "switch-case"
1368
+ },
1369
+ {
1370
+ "description": "Opt-in. A call in an expression position to `void 0`.",
1371
+ "type": "string",
1372
+ "const": "call-expression"
1373
+ },
1374
+ {
1375
+ "description": "Opt-in. A `throw new X(...)` statement removed.",
1376
+ "type": "string",
1377
+ "const": "throw-statement"
1378
+ },
1379
+ {
1380
+ "description": "Opt-in. The regex changes applied to a `new RegExp(\"...\")` pattern.",
1381
+ "type": "string",
1382
+ "const": "regex-constructor"
1383
+ },
1384
+ {
1385
+ "description": "Opt-in. A lookaround negated, or `\\b` and `\\B` swapped.",
1386
+ "type": "string",
1387
+ "const": "regex-assertion"
1388
+ },
1389
+ {
1390
+ "description": "Opt-in. `a ?? b` to `a`.",
1391
+ "type": "string",
1392
+ "const": "nullish-fallback"
1314
1393
  }
1315
1394
  ]
1316
1395
  },
@@ -1389,6 +1468,13 @@
1389
1468
  },
1390
1469
  "default": []
1391
1470
  },
1471
+ "tailwindIgnorePatterns": {
1472
+ "description": "Regular expressions excluding Tailwind arbitrary-value utilities from\ntoken-drift findings and analytics, including CVA variants. Matches the\nnormalized `prefix-[value]` token, without variants, negative signs, or\nsuffix modifiers. Both `-mt-[7px]` and `mt-[7px]` match as `mt-[7px]`;\n`bg-[#abc]/50` matches as `bg-[#abc]`. These spellings cannot be excluded\nindependently. Use `^icon-\\[` to exclude Iconify tokens, including variants.\nDefaults to no exclusions. Invalid regexes fail config loading.",
1473
+ "type": "array",
1474
+ "items": {
1475
+ "type": "string"
1476
+ }
1477
+ },
1392
1478
  "thresholdOverrides": {
1393
1479
  "description": "Per-file or per-function threshold overrides. These keep exceptional\nfunctions visible as configured numeric ceilings instead of hiding them\nbehind binary suppressions.",
1394
1480
  "type": "array",
@@ -1731,6 +1817,11 @@
1731
1817
  "$ref": "#/$defs/Severity",
1732
1818
  "default": "off"
1733
1819
  },
1820
+ "constant-parameters": {
1821
+ "description": "Parameters, and option keys of object-pattern parameters, that each\nvisible call passes in one way. Requires manual review; off by\ndefault. A `warn` finding does not change the CLI exit code unless\n`--fail-on-issues` is set. When the rule is on, the dead-code count\ngate of the GitHub Action counts it unless `fail-on-issues` is\n`false`.",
1822
+ "$ref": "#/$defs/Severity",
1823
+ "default": "off"
1824
+ },
1734
1825
  "unused-component-emits": {
1735
1826
  "description": "Vue `<script setup>` `defineEmits` declared event emitted nowhere inside\nits own single-file component (no `emit('<name>')` call). The\nsingle-file dead-input direction. Defaults to `warn`, not `error`: an\nemit can be part of a deliberately-stable public component API, so\nanalyzer confidence is lower. A `warn` finding does not change the CLI\nexit code unless `--fail-on-issues` is set. The dead-code count gate of\nthe GitHub Action counts it unless `fail-on-issues` is `false`.",
1736
1827
  "$ref": "#/$defs/Severity",
@@ -2661,6 +2752,17 @@
2661
2752
  }
2662
2753
  ]
2663
2754
  },
2755
+ "constant-parameters": {
2756
+ "description": "Optional override for constant parameters.",
2757
+ "anyOf": [
2758
+ {
2759
+ "$ref": "#/$defs/Severity"
2760
+ },
2761
+ {
2762
+ "type": "null"
2763
+ }
2764
+ ]
2765
+ },
2664
2766
  "unused-component-emits": {
2665
2767
  "description": "Optional override for [`RulesConfig::unused_component_emits`].",
2666
2768
  "anyOf": [
@@ -3296,6 +3398,12 @@
3296
3398
  "minimum": 0,
3297
3399
  "default": 0
3298
3400
  },
3401
+ "constantParameters": {
3402
+ "description": "Baseline count of constant parameter review candidates. Absent while\nzero, so a baseline without the opt-in rule keeps its shape.",
3403
+ "type": "integer",
3404
+ "format": "uint",
3405
+ "minimum": 0
3406
+ },
3299
3407
  "analysisIdentity": {
3300
3408
  "description": "Compatibility identity for the analysis that produced these counts.\nMissing values in existing configs are treated as syntactic.",
3301
3409
  "$ref": "#/$defs/SemanticAnalysisIdentity",
@@ -3669,7 +3777,7 @@
3669
3777
  "description": "Value of `audit.gate`: which findings drive the `fallow audit` verdict.",
3670
3778
  "oneOf": [
3671
3779
  {
3672
- "description": "Fail only on findings the current changeset introduced, determined by\na base-snapshot attribution pass. The default.",
3780
+ "description": "Fail only on findings the current changeset introduced, determined by\na base-snapshot attribution pass. An unused file or unused export\noutside the changed files counts when the base does not report it.\nThe default.",
3673
3781
  "type": "string",
3674
3782
  "const": "new-only"
3675
3783
  },
@@ -3705,7 +3813,7 @@
3705
3813
  "type": "object",
3706
3814
  "properties": {
3707
3815
  "dir": {
3708
- "description": "Directory for fallow's persistent analysis cache. Relative paths resolve\nfrom the project root.",
3816
+ "description": "Directory for fallow's persistent analysis cache. Relative paths resolve\nfrom the project root. The directory must be inside the project: an\nabsolute path or a path that leaves the root is ignored with a\nwarning. Use `FALLOW_CACHE_DIR` to put the cache outside the project.",
3709
3817
  "type": [
3710
3818
  "string",
3711
3819
  "null"
@@ -32,10 +32,11 @@ const {
32
32
  } = require("./verify-binary");
33
33
 
34
34
  // Bumped to 2 when SHA-256 + platformPkgDir binding landed (closes the
35
- // cross-install reuse gap in the shared $XDG fallback cache), and to 3 when
36
- // the sentinel started tracking fallow-similar-code alongside the multicall
37
- // CLI. Sentinels written under an older schema are invalidated automatically.
38
- const SENTINEL_SCHEMA_VERSION = 3;
35
+ // cross-install reuse gap in the shared $XDG fallback cache), to 3 when the
36
+ // sentinel tracked fallow-similar-code alongside the multicall CLI, and to 4
37
+ // when the platform package went back to the multicall CLI alone. Sentinels
38
+ // written under an older schema are invalidated automatically.
39
+ const SENTINEL_SCHEMA_VERSION = 4;
39
40
  const VERIFY_LOG_ENV = "FALLOW_VERIFY_LOG";
40
41
 
41
42
  // One-shot warning state: each warning class fires once per process,