fallow 3.29.0 → 3.31.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/README.md +2 -4
- package/capabilities.json +288 -49
- package/issue-registry.json +106 -37
- package/package.json +12 -11
- package/schema.json +67 -7
- package/skills/fallow/SKILL.md +4 -2
- package/skills/fallow/references/cli-reference.md +54 -18
- package/skills/fallow/references/gotchas.md +24 -0
- package/skills/fallow/references/issue-types.md +3 -1
- package/skills/fallow/references/mcp.md +32 -2
- package/types/output-contract.d.ts +1133 -15
package/skills/fallow/SKILL.md
CHANGED
|
@@ -55,6 +55,7 @@ cargo install fallow-cli # build from source
|
|
|
55
55
|
12. **Use type-aware analysis only for Fallow-owned project questions**. Reach for `--type-aware` to prove exact symbol use, preserve TypeScript class contracts, guard class-member cleanup, find cross-file private type leaks, suggest targeted tests, or inspect public-signature coupling. Keep `tsc --noEmit` responsible for compiler correctness and Oxlint responsible for local typed lint rules. Treat partial or unavailable semantic results as retained findings, never as deletion proof. Unknown external consumers of a published library remain outside checker-visible evidence, so preserve declared public API unless every relevant consumer project is explicitly in scope.
|
|
56
56
|
13. **Use `fallow impact statusline` only for a user-facing status surface**. It intentionally emits one plain-text, path-free line and ignores `--format`. It starts no analysis, never enables Impact, and compares only whole-project scans. Do not parse this line as JSON.
|
|
57
57
|
14. **Treat similar-code output as discovery only**. Never describe its score as a probability, finding, proof of equivalent behavior, or safe-refactor decision. Agents must not authorize setup. Inspect a candidate before judging it: save discovery as `similar-code.json`, inspect with `--candidates similar-code.json`, and pass the unchanged file to `fallow similar-code review`. Over MCP use `find_similar_code` with `paths:` and `inspect_similar_code` with a typed `snapshot`; it fails closed on stale source. Keep `candidate_worthy`, `behaviorally_equivalent`, and `refactor_safe` separate, use `needs-human-review`, and abstain when evidence is incomplete. Only `completion.status: "complete"` makes an empty result conclusive. Follow [the complete workflow to compare semantically similar functions](references/similar-code.md).
|
|
58
|
+
15. **Check production runtime data before an edit or a delete, when Fallow Cloud is connected**. Prefer the scoped reads over the full `get_cloud_runtime_context` pull. Before an edit, run `fallow coverage review-packet --repo <owner/repo>` (MCP `get_cloud_review_packet`) for the changed files and read `hit_count`, `covered_by_test`, and the callers when present. Before a delete, require `period_tracking_state: "never_called"`, not only `tracking_state`, and read `evidence_window.observed_hours`: few observed hours or a low-traffic surface mean "not visited", not "dead". After a deploy, run `fallow coverage deployment-changes --repo <owner/repo>` (MCP `get_cloud_deployment_changes`) and, when `comparable` is `false`, report `reason` and claim no change. Open files by `repo_path`, not `file_path`. Production data is context, never a gate. Details: [references/mcp.md](references/mcp.md#scoped-cloud-reads).
|
|
58
59
|
|
|
59
60
|
## Onboarding And Insight
|
|
60
61
|
Offer setup only after a human-requested analysis shows findings and all signals match: `fallow config --path` exits 3, not CI, not a pipeline format, `fallow impact --format json --quiet` has `onboarding_declined: false`, and no offer happened this session. Ask after showing value. Choices: guard commits and PRs, baseline the existing backlog and clean by category, add AGENTS.md guidance, or keep as-is. On decline, run `fallow init --decline --quiet` and stay silent for this project. Mutate only after consent. For guards, inspect `fallow hooks status --format json --quiet`, then use `fallow hooks install --target agent` and `fallow hooks install --target git`; for large backlogs, pair the gate with `--save-baseline` / new-only guidance. Offer `fallow impact enable` as local-only value tracking, never as telemetry; also offer it once on already-configured projects when `fallow impact status --format json` has `enabled: false` and `explicit_decision: false`, and record a no with `fallow impact disable --quiet`. Surface value on clear events: if the agent gate blocked a commit or push and a later retry succeeded, mention what was contained; when `next_steps` carries id `impact-report`, run its command and relay the non-zero numbers to the user in one line. On request, summarize non-zero Impact counts. Ask about telemetry only after such a win, only if `fallow telemetry status --format json` has `explicit_decision: false`, and never run `fallow telemetry enable`.
|
|
@@ -192,9 +193,10 @@ Reports unused exports in entry files (package.json `main`/`exports`, framework
|
|
|
192
193
|
```bash
|
|
193
194
|
fallow flags --format json --quiet
|
|
194
195
|
fallow flags --format json --quiet --top 20
|
|
196
|
+
fallow flags --retirement --format json --quiet
|
|
195
197
|
```
|
|
196
198
|
|
|
197
|
-
Reports environment-variable gates (`process.env.FEATURE_*`), SDK calls from common flag providers, and config-object patterns, with flag locations, detection confidence, and a cross-reference against dead code.
|
|
199
|
+
Reports environment-variable gates (`process.env.FEATURE_*`), SDK calls from common flag providers, and config-object patterns, with flag locations, detection confidence, and a cross-reference against dead code. `--top N` limits the list. `--retirement` adds a `retirement` object with one row per flag, the reasons it can be retired (`single-read-site`, `test-only`, `literal-constant`, `identical-branches`, `empty-branch`, `guards-dead-code`, `defined-never-read`), and its age from git (`--flag-age blame|pickaxe|off`; blame gives a lower bound). Filter with `--reason <CODE>` and `--min-age <DAYS>`, order with `--sort age|sites|name`. `--flag-state <FILE>` reads an offline vendor export in one vendor-neutral schema and adds `fully-rolled-out`, `archived-in-vendor`, `missing-in-vendor` and `vendor-only`. With `--retirement`, `--save-regression-baseline <PATH>` and `--fail-on-regression --regression-baseline <PATH>` gate on `distinct_flags` (plus each `--reason` count), and the opt-in `--max-flag-age <DAYS>` fails on old flags. Every format works: compact prints `flag-retire:<reason>:<path>:<line>:<name>`, SARIF adds the rule `fallow/flag-retirement-candidate`, CodeClimate adds `fallow/flag-retirement`. The report is advisory: every action has `auto_fixable: false`, and a person decides what to remove.
|
|
198
200
|
|
|
199
201
|
### Surface security candidates for verification
|
|
200
202
|
```bash
|
|
@@ -260,7 +262,7 @@ fallow dead-code --format json --quiet --save-baseline .fallow/snapshot.json
|
|
|
260
262
|
fallow dead-code --format json --quiet --baseline .fallow/snapshot.json
|
|
261
263
|
```
|
|
262
264
|
|
|
263
|
-
`--save-regression-baseline` / `--regression-baseline` / `--fail-on-regression` / `--tolerance` are count-based gates for `dead-code
|
|
265
|
+
`--save-regression-baseline` / `--regression-baseline` / `--fail-on-regression` / `--tolerance` are count-based gates for `dead-code`, bare combined mode, and `flags --retirement` (a flags baseline needs a PATH; without `--retirement` the options have no effect on `flags` and it warns). `--save-baseline` / `--baseline` are identity-based (track finding identity, fail on new). `audit` rejects the global baseline flags and uses `--dead-code-baseline` / `--health-baseline` / `--dupes-baseline` instead.
|
|
264
266
|
|
|
265
267
|
With no path, `--save-regression-baseline` updates `regression.baseline` in the discovered fallow config, or creates `.fallowrc.json` when none exists. Pass a path only when a standalone baseline file is preferred.
|
|
266
268
|
|
|
@@ -52,7 +52,7 @@ Every fallow command with its purpose and key flags. The table is regenerated fr
|
|
|
52
52
|
| `doctor` | Diagnose project readiness without analysis or mutation | |
|
|
53
53
|
| `similar-code` | Find semantically similar functions with a pinned local model (opt-in) | `--threshold`, `--min-lines`, `--top`, `--file` |
|
|
54
54
|
| `inspect` | Compose one evidence bundle for a file or exported symbol | `--file <path>`, `--symbol <file>:<export>` |
|
|
55
|
-
| `trace` | Trace a symbol's call chain (best-effort, syntactic; OFF the ranked path) | `symbol`, `--callers`, `--callees`, `--depth` |
|
|
55
|
+
| `trace` | Trace a symbol's call chain (best-effort, syntactic; OFF the ranked path) | `symbol`, `--callers`, `--callees`, `--depth`, `--path`, `--eager-only` |
|
|
56
56
|
| `trace-error` | Resolve a runtime stack trace's frames to the definitions they name (best-effort, syntactic; OFF the ranked path) | `trace_file` |
|
|
57
57
|
| `fix` | Auto-remove unused exports/deps | `--dry-run`, `--yes` (required in non-TTY) |
|
|
58
58
|
| `init` | Generate config file, AGENTS.md agent guide, or pre-commit hook | `--toml`, `--agents`, `--hooks`, `--branch` |
|
|
@@ -68,11 +68,11 @@ Every fallow command with its purpose and key flags. The table is regenerated fr
|
|
|
68
68
|
| `guard` | Show which architecture rules apply to files before changing them | `files` |
|
|
69
69
|
| `config` | Show the loaded config path and resolved config (verifies which `.fallowrc.json` is in effect) | `--path` |
|
|
70
70
|
| `recommend` | Recommend a project-tailored config for an agent to author | |
|
|
71
|
-
| `list` | Inspect project structure | `--files`, `--entry-points`, `--plugins`, `--boundaries`, `--workspaces` |
|
|
71
|
+
| `list` | Inspect project structure | `--files`, `--entry-points`, `--plugins`, `--boundaries`, `--workspaces`, `--entry-weight` |
|
|
72
72
|
| `workspaces` | Inspect monorepo workspaces + discovery diagnostics (shorthand for `list --workspaces`) | (no flags) |
|
|
73
73
|
| `dupes` | Code duplication detection | `--mode`, `--near`, `--threshold`, `--top`, `--changed-since`, `--workspace`, `--changed-workspaces`, `--skip-local`, `--cross-language`, `--ignore-imports`, `--explain-skipped`, `--fail-on-regression`, `--tolerance`, `--regression-baseline`, `--save-regression-baseline` |
|
|
74
74
|
| `health` | Function complexity analysis (also covers component templates as synthetic `<template>` findings: Angular external `.html` files via `templateUrl` AND inline `@Component({ template: \`...\` })` literals, plus Vue, Svelte and Astro single-file components; suppress an Angular external template with `<!-- fallow-ignore-file complexity -->` at the top of the `.html` file, an Angular inline template with `// fallow-ignore-next-line complexity` directly above the `@Component` decorator, and a `.svelte` / `.vue` / `.astro` template with `<!-- fallow-ignore-next-line complexity -->` on the line immediately above the reported line) | `--complexity`, `--max-cyclomatic`, `--max-cognitive`, `--max-crap`, `--top`, `--sort`, `--file-scores`, `--hotspots`, `--ownership`, `--ownership-emails`, `--targets`, `--effort`, `--score`, `--min-score`, `--since`, `--min-commits`, `--save-snapshot`, `--trend`, `--coverage-gaps`, `--coverage`, `--coverage-root`, `--runtime-coverage`, `--min-invocations-hot`, `--min-observation-volume`, `--low-traffic-threshold`, `--css`, `--complexity-breakdown`, `--min-severity`, `--report-only`, `--workspace`, `--changed-workspaces`, `--baseline`, `--save-baseline` |
|
|
75
|
-
| `flags` | Detect feature flag patterns (env vars, SDK calls, config objects) | `--top` |
|
|
75
|
+
| `flags` | Detect feature flag patterns (env vars, SDK calls, config objects) | `--top`, `--retirement`, `--reason`, `--min-age`, `--flag-state`, `--max-flag-age` |
|
|
76
76
|
| `suppressions` | List active fallow-ignore suppression markers (read-only inventory) | `--file` |
|
|
77
77
|
| `explain` | Explain one issue type without running analysis | `<issue-type>`, `--format json` |
|
|
78
78
|
| `audit` | Combined dead-code + complexity + duplication + styling for changed files, returns a verdict; `fallow review` is an alias for `fallow audit --brief` (advisory orientation brief, always exits 0) | `--base`, `--gate`, `--brief`, `--max-decisions`, `--walkthrough-guide`, `--walkthrough-file`, `--show-deprioritized`, `--production`, `--production-dead-code`, `--production-health`, `--production-dupes`, `--workspace`, `--changed-workspaces`, `--ci`, `--fail-on-issues`, `--explain`, `--explain-skipped`, `--dead-code-baseline`, `--health-baseline`, `--dupes-baseline`, `--max-crap`, `--coverage`, `--coverage-root`, `--no-css`, `--css-deep`, `--no-css-deep`, `--include-entry-exports` |
|
|
@@ -113,6 +113,7 @@ Analyzes the project for unused files, exports, dependencies, types, members, an
|
|
|
113
113
|
| `--symbol-impact` | `string` | - | Compute exact-symbol consumers, affected files, and targeted tests |
|
|
114
114
|
| `--top` | `string` | - | Show only the top N items per category |
|
|
115
115
|
| `--file` | `string` | - | Scope output to specific files. Only issues in the specified files are reported. Project-wide dependency issues are suppressed. Warns on non-existent paths. Useful for lint-staged |
|
|
116
|
+
| `--finding-id` | `string` | - | Only report the findings with these `finding_id` values. Repeat the flag or pass a comma-separated list. Ids stay the same under every filter. The JSON output adds `finding_id_query`: a missing id means "resolved" only when `conclusive` is true |
|
|
116
117
|
|
|
117
118
|
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--output-file`](#global-flags), [`--changed-since`](#global-flags), [`--max-file-size`](#global-flags), [`--production`](#global-flags), [`--no-production`](#global-flags), [`--production-dead-code`](#global-flags), [`--baseline`](#global-flags), [`--save-baseline`](#global-flags), [`--workspace`](#global-flags), [`--changed-workspaces`](#global-flags), [`--include-entry-exports`](#global-flags).
|
|
118
119
|
<!-- generated:flags:dead-code:end -->
|
|
@@ -144,6 +145,7 @@ Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#
|
|
|
144
145
|
| `--duplicate-exports` | Duplicate exports |
|
|
145
146
|
| `--circular-deps` | Circular dependencies |
|
|
146
147
|
| `--re-export-cycles` | Re-export cycles (`kind: multi-node` for barrel files re-exporting from each other in a loop, `kind: self-loop` for a barrel re-exporting from itself). File-scoped finding; chain propagation through the loop is a no-op so imports may silently come up empty. Distinct from `--circular-deps` (runtime cycles). |
|
|
148
|
+
| `--package-cycles` | Two or more workspace packages import each other in a loop |
|
|
147
149
|
| `--boundary-violations` | Boundary violations (imports crossing architecture zone boundaries, unzoned source files when `boundaries.coverage.requireAllFiles` is set, and forbidden calls from `boundaries.calls.forbidden`; suppression token `boundary-violation`, with `boundary-call-violation` and `boundary-call-violations` accepted as aliases for the whole family) |
|
|
148
150
|
| `--policy-violations` | Rule-pack policy violations (banned calls, imports, and catalogue-derived effects declared via the `rulePacks` config key) |
|
|
149
151
|
| `--stale-suppressions` | Stale suppression comments or `@expected-unused` JSDoc tags |
|
|
@@ -347,6 +349,7 @@ Inspect discovered files, entry points, detected frameworks, and architecture bo
|
|
|
347
349
|
| `--plugins` | `bool` | `false` | List active framework plugins |
|
|
348
350
|
| `--boundaries` | `bool` | `false` | Show architecture boundary zones, rules, per-zone file counts, and `logical_groups[]` for `autoDiscover` parents |
|
|
349
351
|
| `--workspaces` | `bool` | `false` | Show discovered monorepo workspaces plus any workspace-discovery diagnostics (malformed `package.json`, unreachable glob matches, missing tsconfig references). Available as the `fallow workspaces` alias too. |
|
|
352
|
+
| `--entry-weight` | `bool` | `false` | Show the startup import weight of each runtime entry point, in source bytes (not bundle size): eager, deferred and out-of-thread modules, eager packages, and the imports that keep the most bytes eager |
|
|
350
353
|
|
|
351
354
|
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags).
|
|
352
355
|
<!-- generated:flags:list:end -->
|
|
@@ -358,9 +361,14 @@ fallow list --entry-points --format json --quiet
|
|
|
358
361
|
fallow list --plugins --format json --quiet
|
|
359
362
|
fallow list --boundaries --format json --quiet
|
|
360
363
|
fallow list --workspaces --format json --quiet
|
|
364
|
+
fallow list --entry-weight --format json --quiet
|
|
361
365
|
fallow workspaces --format json --quiet # alias of `fallow list --workspaces`
|
|
362
366
|
```
|
|
363
367
|
|
|
368
|
+
The `--entry-weight` JSON output carries `entry_weight.entries[]`, one row per runtime entry point, heaviest first. Each row has `eager_modules` and `eager_bytes` (the project modules and source bytes that load before the entry runs; `import type` and a declaration file do not count), `eager_css_bytes`, `deferred_modules` and `deferred_bytes` (reached only through `import()` or a lazy glob), `out_of_thread_modules` and `out_of_thread_bytes` (reached only through a `new URL(..., import.meta.url)` reference such as a worker URL, a webpack worker loader request such as `worker-loader!./work.js`, `child_process.fork`, a pino transport or a `module.register` hook), `eager_packages[]` with the specifiers as written, and `dominating_imports[]`. A dominating import is one import that alone keeps `exclusive_bytes` on the startup path. The unit is `source_bytes`: types and comments count, and tree shaking does not apply, so the value is not a bundle size. An import without the `type` keyword counts as eager, even when it brings in only types that TypeScript removes, so `eager_bytes` can be too high. Treat a dominating import as evidence for a review, not as a fix: a lazy load of code that the first screen needs can make startup slower.
|
|
369
|
+
|
|
370
|
+
To gate eager growth in CI, save a baseline file on the main branch with `fallow list --entry-weight --save-regression-baseline <PATH>`. A later run with `--regression-baseline <PATH>` adds `entry_weight.regression`: per-entry `baseline_eager_bytes`, `current_eager_bytes`, `new_eager_packages` and `exceeded`. The comparison is report-only until you add `--fail-on-regression`; then an entry that grew more than `--tolerance` (bytes, or a percentage such as `5%`) exits 1. A new entry never fails the gate.
|
|
371
|
+
|
|
364
372
|
The `--workspaces` JSON output carries `workspaces[]` (name, project-root-relative path, `is_internal_dependency` bool) plus `workspace_diagnostics[]`. Each diagnostic has a `kind` discriminator (`undeclared-workspace`, `malformed-package-json`, `glob-matched-no-package-json`, `malformed-tsconfig`, `tsconfig-reference-dir-missing`, `malformed-pnpm-workspace-yaml`, `skipped-large-file`, `skipped-minified-file`, `skipped-source-dotdir`, `source-read-failure`, `bun-lockb-override-resolution-skipped`) with a typed payload (`error`, `pattern`, or none), and a `path` that is project-root-relative with forward slashes on every envelope that carries the array. The same `workspace_diagnostics[]` array is also surfaced on the `fallow dead-code --format json`, `fallow dupes --format json`, and `fallow health --format json` envelopes, at the top level of the bare combined `fallow --format json` envelope, on `fallow audit --format json` under `dead_code`, and on the `audit-brief` envelope shared by `fallow review --format json` and `fallow audit --brief --format json`, also under `dead_code` (omitted when empty). The combined carrier is the envelope root, not a section, so `--skip check`, `--only health`, and `--only dupes` all still report what their analyses recorded. The combined root is the union of what every analysis in the run recorded, deduplicated on the whole `kind` (typed payload included) plus `path`, so two overlapping globs still report the same package-less directory once per `pattern` (a declared glob's no-op `./` prefix is normalised away, so one glob written `"./apps/**"` in `package.json` and `apps/**` in `pnpm-workspace.yaml` stays one entry): a combined run walks the project once per analysis, and a per-analysis `production` mode (`production: { deadCode, health, dupes }`, `--production-health`) can give those walks different file sets, so only the union reports what the run as a whole saw. Each analysis contributes the workspace-discovery list its own config load produced, the same list `fallow list --workspaces` reports, so the combined root can carry an `undeclared-workspace` or `glob-matched-no-package-json` entry that the standalone `dead-code`, `check`, `health`, and `dupes` envelopes, which read the process diagnostics registry instead, do not. `fallow audit --format json` and the `audit-brief` envelope are on the same broad side: they fold the dead-code analysis's own list into their `dead_code.workspace_diagnostics[]`, so they too report an `undeclared-workspace` entry the standalone envelopes miss. The CLI and the programmatic route (MCP code mode, NAPI, embedders) agree on everything an analysis records: both folds close with the same process-registry read, which covers what an analysis records after its section captured its list (a `source-read-failure`, or the analysis-stage kinds a health run's own dead-code precompute records) and skips `skipped-large-file`, `skipped-minified-file`, and `skipped-source-dotdir`, since those reach an envelope only from the walk that recorded them. The two analysis-stage kinds (`malformed-pnpm-workspace-yaml`, `bun-lockb-override-resolution-skipped`) are recorded by the dead-code analyze pass, so they only appear on runs that include it: `fallow dupes --format json` and `fallow --only dupes` report the workspace-discovery and source-discovery kinds alone. A malformed ROOT `package.json` exits 2 at config load; everything else warns and continues.
|
|
365
373
|
|
|
366
374
|
The `--boundaries` JSON output carries `boundaries.logical_groups[]` alongside the existing `zones[]` / `rules[]` arrays. Each logical-group entry surfaces a user-authored `autoDiscover` parent zone (which expansion otherwise flattens into per-child zones like `features/auth` / `features/billing`): `name`, `children`, `auto_discover` (verbatim user strings), `status` (`ok` / `empty` / `invalid_path`), `source_zone_index`, summed `file_count`, optional `authored_rule` (the pre-expansion `{ allow, allowTypeOnly }` keyed on the parent), optional `fallback_zone` cross-reference when the parent also kept its own `patterns` (Bulletproof case), optional `merged_from` (parent zone indices when the user declared the same parent name twice; surfaces the duplicate in JSON instead of only in `tracing::warn!`), optional `original_zone_root` (echo of the parent's `root` subtree scope for monorepo patchers), and optional `child_source_indices` (parallel to `children`, attributing each child to a specific `auto_discover` entry when multiple paths were authored). The full shape is documented in `docs/output-schema.json` under `ListBoundariesOutput`.
|
|
@@ -447,7 +455,7 @@ Human output groups paths under "Shared with your team (commit these)" and "Loca
|
|
|
447
455
|
{
|
|
448
456
|
"kind": "agent-install",
|
|
449
457
|
"schema_version": 1,
|
|
450
|
-
"fallow_version": "3.
|
|
458
|
+
"fallow_version": "3.31.0",
|
|
451
459
|
"root": "/abs/path",
|
|
452
460
|
"mode": "install",
|
|
453
461
|
"dry_run": false,
|
|
@@ -651,7 +659,7 @@ fallow health --format json --quiet --trend
|
|
|
651
659
|
{
|
|
652
660
|
"kind": "health",
|
|
653
661
|
"schema_version": 7,
|
|
654
|
-
"version": "3.
|
|
662
|
+
"version": "3.31.0",
|
|
655
663
|
"elapsed_ms": 32,
|
|
656
664
|
"summary": {
|
|
657
665
|
"files_analyzed": 482,
|
|
@@ -1054,7 +1062,7 @@ fallow audit \
|
|
|
1054
1062
|
{
|
|
1055
1063
|
"kind": "audit",
|
|
1056
1064
|
"schema_version": 7,
|
|
1057
|
-
"version": "3.
|
|
1065
|
+
"version": "3.31.0",
|
|
1058
1066
|
"command": "audit",
|
|
1059
1067
|
"verdict": "fail",
|
|
1060
1068
|
"changed_files_count": 12,
|
|
@@ -1110,6 +1118,13 @@ Detects feature flag patterns in the codebase. Identifies environment variable f
|
|
|
1110
1118
|
| Flag | Type | Default | Description |
|
|
1111
1119
|
|---|---|---|---|
|
|
1112
1120
|
| `--top` | `string` | - | Show only the top N flags |
|
|
1121
|
+
| `--retirement` | `bool` | `false` | Add a retirement report: one row per flag, with the reasons the flag can be retired. Advisory only; nothing is removed |
|
|
1122
|
+
| `--reason` | `single-read-site\|test-only\|literal-constant\|identical-branches\|empty-branch\|guards-dead-code\|defined-never-read\|fully-rolled-out\|archived-in-vendor\|missing-in-vendor\|vendor-only` | - | Keep only retirement rows with this reason (repeatable) |
|
|
1123
|
+
| `--sort` | `age\|sites\|name` | `age` | Order of the retirement rows |
|
|
1124
|
+
| `--flag-age` | `blame\|pickaxe\|off` | `blame` | How to measure flag age: blame (lower bound), pickaxe (first commit with the name, slower) or off |
|
|
1125
|
+
| `--min-age` | `string` | - | Keep only retirement rows at least this many days old |
|
|
1126
|
+
| `--flag-state` | `string` | - | Vendor flag export (JSON, read offline) that adds the fully-rolled-out, archived-in-vendor, missing-in-vendor and vendor-only reasons |
|
|
1127
|
+
| `--max-flag-age` | `string` | - | Exit with code 1 when a flag in scope is older than this many days. Opt-in; needs a flag age |
|
|
1113
1128
|
|
|
1114
1129
|
Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--changed-since`](#global-flags), [`--workspace`](#global-flags).
|
|
1115
1130
|
<!-- generated:flags:flags:end -->
|
|
@@ -1122,6 +1137,10 @@ fallow flags --format json --quiet
|
|
|
1122
1137
|
# Top 10 flags
|
|
1123
1138
|
fallow flags --format json --quiet --top 10
|
|
1124
1139
|
|
|
1140
|
+
# Flags at least 90 days old, oldest first. A row with an empty
|
|
1141
|
+
# `reasons` array is not a retirement candidate.
|
|
1142
|
+
fallow flags --retirement --min-age 90 --format json --quiet
|
|
1143
|
+
|
|
1125
1144
|
# Single workspace package
|
|
1126
1145
|
fallow flags --format json --quiet --workspace my-package
|
|
1127
1146
|
```
|
|
@@ -1131,7 +1150,7 @@ fallow flags --format json --quiet --workspace my-package
|
|
|
1131
1150
|
```json
|
|
1132
1151
|
{
|
|
1133
1152
|
"schema_version": 7,
|
|
1134
|
-
"version": "3.
|
|
1153
|
+
"version": "3.31.0",
|
|
1135
1154
|
"elapsed_ms": 116,
|
|
1136
1155
|
"feature_flags": [],
|
|
1137
1156
|
"total_flags": 0
|
|
@@ -1232,7 +1251,7 @@ fallow security --gate newly-reachable --changed-since origin/main
|
|
|
1232
1251
|
{
|
|
1233
1252
|
"kind": "security",
|
|
1234
1253
|
"schema_version": "4",
|
|
1235
|
-
"version": "3.
|
|
1254
|
+
"version": "3.31.0",
|
|
1236
1255
|
"elapsed_ms": 42,
|
|
1237
1256
|
"config": {
|
|
1238
1257
|
"rules": {
|
|
@@ -1261,7 +1280,7 @@ fallow security --gate newly-reachable --changed-since origin/main
|
|
|
1261
1280
|
{
|
|
1262
1281
|
"kind": "security",
|
|
1263
1282
|
"schema_version": "4",
|
|
1264
|
-
"version": "3.
|
|
1283
|
+
"version": "3.31.0",
|
|
1265
1284
|
"elapsed_ms": 42,
|
|
1266
1285
|
"config": {
|
|
1267
1286
|
"rules": {
|
|
@@ -1386,12 +1405,17 @@ The target is a positional argument, formatted as `FILE:SYMBOL` (for example `sr
|
|
|
1386
1405
|
```bash
|
|
1387
1406
|
fallow trace src/utils.ts:formatDate
|
|
1388
1407
|
fallow trace src/utils.ts:formatDate --callers --depth 3
|
|
1408
|
+
fallow trace --path src/main.ts src/chart.ts --format json --quiet
|
|
1409
|
+
fallow trace --path src/main.ts src/chart.ts --eager-only --format json --quiet
|
|
1389
1410
|
```
|
|
1390
1411
|
|
|
1412
|
+
Each `--path` hop carries `type_only` and `dynamic`. A `dynamic` hop loads its target only on demand (`import()`, a lazy glob) or on another thread (a worker, a fork). `--eager-only` follows static value imports only, so its route explains why a module is in the `--entry-weight` eager set of `fallow list`.
|
|
1413
|
+
|
|
1391
1414
|
<!-- generated:flags:trace:start -->
|
|
1392
1415
|
| Flag | Type | Default | Description |
|
|
1393
1416
|
|---|---|---|---|
|
|
1394
1417
|
| `--path` | `string` | - | Shortest import path between two modules, as two file paths (e.g. `--path src/app.ts src/db.ts`). Mutually exclusive with the symbol target and the call-chain flags |
|
|
1418
|
+
| `--eager-only` | `bool` | `false` | With `--path`, follow only static value imports, so the route explains why TO loads before FROM runs. `import()`, lazy globs, worker loads and `import type` do not qualify |
|
|
1395
1419
|
| `--callers` | `bool` | `false` | Walk UP to callers (modules that import the symbol). When neither `--callers` nor `--callees` is set, both directions are walked |
|
|
1396
1420
|
| `--callees` | `bool` | `false` | Walk DOWN to callees (the symbol's module's import-symbol edges plus unresolved call sites). When neither flag is set, both are walked |
|
|
1397
1421
|
| `--depth` | `string` | - | Chain depth bound for both directions (default 2). Symbol-level is best-effort, so a shallow bound keeps the trace legible |
|
|
@@ -1517,7 +1541,7 @@ Pack files can also reference the published schema directly: `"$schema": "https:
|
|
|
1517
1541
|
|
|
1518
1542
|
---
|
|
1519
1543
|
|
|
1520
|
-
## `license`: Manage
|
|
1544
|
+
## `license`: Manage the Fallow Cloud License
|
|
1521
1545
|
|
|
1522
1546
|
Manage the local JWT used to unlock continuous/cloud runtime monitoring. Single-capture local runtime analysis does not require a license. Verification is fully offline against an Ed25519 public key compiled into the binary. Only `--trial` and `refresh` hit the network (`api.fallow.cloud`, 5s connect / 10s total timeout).
|
|
1523
1547
|
|
|
@@ -1656,7 +1680,9 @@ Helper subcommand for runtime coverage setup, focused analysis, and cloud invent
|
|
|
1656
1680
|
|
|
1657
1681
|
- `coverage setup` - resumable state machine that wires sidecar installation, framework-aware coverage recipe writing, optional license activation for continuous monitoring, and automatic handoff into `fallow health --runtime-coverage`.
|
|
1658
1682
|
- `coverage analyze` - focused runtime coverage analysis. Local mode reads `--runtime-coverage <path>`; cloud mode requires explicit `--cloud`, `--runtime-coverage-cloud`, or `FALLOW_RUNTIME_COVERAGE_SOURCE=cloud` and never triggers from `FALLOW_API_KEY` alone.
|
|
1659
|
-
- `coverage upload-inventory` - push a static function inventory to
|
|
1683
|
+
- `coverage upload-inventory` - push a static function inventory to Fallow Cloud so the dashboard can surface `untracked` functions (those in the codebase but never called at runtime).
|
|
1684
|
+
- `coverage review-packet` - read the production facts of changed files or functions from Fallow Cloud as JSON, with no local analysis and no full runtime-context pull. `--file <path>` and `--function <file>:<name>[:<line>]` select the scope; with neither, the source files changed against `--base` (resolved like `fallow audit`) are sent.
|
|
1685
|
+
- `coverage deployment-changes` - read the Fallow Cloud deployment change report for `--sha` (default `HEAD`) against `--base` (default: the previous deployment with production runtime) as JSON.
|
|
1660
1686
|
|
|
1661
1687
|
```bash
|
|
1662
1688
|
fallow coverage setup # interactive
|
|
@@ -1668,6 +1694,10 @@ fallow coverage setup --yes --json --explain # add _meta field docs, enums, war
|
|
|
1668
1694
|
fallow coverage analyze --runtime-coverage ./coverage --format json
|
|
1669
1695
|
fallow coverage analyze --cloud --repo owner/repo --format json
|
|
1670
1696
|
|
|
1697
|
+
fallow coverage review-packet --repo owner/repo # files changed against the merge-base
|
|
1698
|
+
fallow coverage review-packet --repo owner/repo --file src/api.ts
|
|
1699
|
+
fallow coverage deployment-changes --repo owner/repo --sha <sha> --base <sha>
|
|
1700
|
+
|
|
1671
1701
|
fallow coverage upload-inventory # infers project-id, git-sha, API key
|
|
1672
1702
|
fallow coverage upload-inventory --dry-run # print what would be uploaded, exit 0
|
|
1673
1703
|
|
|
@@ -1690,7 +1720,7 @@ fallow coverage upload-source-maps --dry-run # print maps and fileNam
|
|
|
1690
1720
|
|------|------|---------|-------------|
|
|
1691
1721
|
| `--runtime-coverage <PATH>` | path | none | Local V8 directory, V8 JSON file, or Istanbul coverage map. Mutually exclusive with cloud mode. |
|
|
1692
1722
|
| `--cloud`, `--runtime-coverage-cloud` | bool | false | Explicitly fetch cloud runtime facts from `/v1/coverage/:repo/runtime-context`. |
|
|
1693
|
-
| `--api-key <KEY>` | string | `$FALLOW_API_KEY` | Fallow
|
|
1723
|
+
| `--api-key <KEY>` | string | `$FALLOW_API_KEY` | Fallow Cloud bearer token, used only after explicit cloud opt-in. |
|
|
1694
1724
|
| `--api-endpoint <URL>` | string | `$FALLOW_API_URL` or `https://api.fallow.cloud` | Override for staging / on-prem. |
|
|
1695
1725
|
| `--repo <OWNER/REPO>` | string | `$FALLOW_REPO`, then parsed git origin | Repository whose latest cloud runtime facts should be pulled. Slashes are percent-encoded as one route segment. |
|
|
1696
1726
|
| `--coverage-period <DAYS>` | integer | 30 | Cloud observation window, 1 through 90 days. |
|
|
@@ -1716,7 +1746,7 @@ Under `--production` the evidence block also carries `test_only_reference`. It i
|
|
|
1716
1746
|
|
|
1717
1747
|
| Flag | Type | Default | Description |
|
|
1718
1748
|
|------|------|---------|-------------|
|
|
1719
|
-
| `--api-key <KEY>` | string | `$FALLOW_API_KEY` | Fallow
|
|
1749
|
+
| `--api-key <KEY>` | string | `$FALLOW_API_KEY` | Fallow Cloud bearer token. Generate at `https://fallow.cloud/settings#api-keys`. **Prefer `$FALLOW_API_KEY` on shared CI runners**: `--api-key` on the command line may be visible to other processes via `ps`. |
|
|
1720
1750
|
| `--api-endpoint <URL>` | string | `$FALLOW_API_URL` or `https://api.fallow.cloud` | Override for staging / on-prem. |
|
|
1721
1751
|
| `--project-id <OWNER/REPO>` | string | `$GITHUB_REPOSITORY` → `$CI_PROJECT_PATH` → `git remote get-url origin` | Project identifier. |
|
|
1722
1752
|
| `--git-sha <SHA>` | string | `git rev-parse HEAD` | Commit SHA this inventory is keyed to. Max 64 chars; `[A-Za-z0-9._-]` only. |
|
|
@@ -1731,7 +1761,7 @@ Only plain JS/TS/JSX/TSX sources are walked. Declaration files (`*.d.ts`, `*.d.m
|
|
|
1731
1761
|
### Environment
|
|
1732
1762
|
|
|
1733
1763
|
- `FALLOW_COV_BIN` - explicit override for the sidecar binary (for `setup`). Wins over all other discovery paths. Must point to an existing file.
|
|
1734
|
-
- `FALLOW_API_KEY` -
|
|
1764
|
+
- `FALLOW_API_KEY` - Fallow Cloud bearer token (for `upload-inventory` and `upload-source-maps`). Overridden by `--api-key` for `upload-inventory`; `upload-source-maps` reads only the env var so secrets stay out of argv.
|
|
1735
1765
|
- `FALLOW_API_URL` - base URL for cloud calls. Overridden by `--api-endpoint`.
|
|
1736
1766
|
- `FALLOW_CA_BUNDLE` - PEM certificate bundle for cloud calls. Relative paths resolve from the process cwd. The bundle replaces default WebPKI roots, so private-CA runners should pass a complete bundle that includes public roots plus the private CA.
|
|
1737
1767
|
|
|
@@ -1819,6 +1849,7 @@ Available on all commands:
|
|
|
1819
1849
|
| `--no-cache` | `bool` | `false` | Disable incremental caching |
|
|
1820
1850
|
| `--threads` | `string` | - | Number of parser threads |
|
|
1821
1851
|
| `--changed-since` | `string` | - | Only report issues in files changed since this git ref (e.g., main, HEAD~5) |
|
|
1852
|
+
| `--no-package-baselines` | `bool` | `false` | Ignore the per-package refs of `workspaces.changedSince` for this run |
|
|
1822
1853
|
| `--diff-file` | `string` | - | Unified diff for line-level scoping. Use `-` to read from stdin. Project-level findings still bypass this filter. When both this and `--changed-since` are set, the diff filter wins for finding scope while `--changed-since` still drives file discovery |
|
|
1823
1854
|
| `--diff-stdin` | `bool` | `false` | Read the unified diff from stdin. Equivalent to `--diff-file -` |
|
|
1824
1855
|
| `--churn-file` | `string` | - | Import change history from a `fallow-churn/v1` JSON file instead of `git log`, powering hotspots, ownership, and bus-factor on projects with no git repository (Yandex Arc, Mercurial, Perforce). A small wrapper translates your VCS log into the contract. Resolved relative to `--root`. Affects `health --hotspots` / `--ownership` / `--targets` only; `audit`, `impact`, and `--changed-since` still require git |
|
|
@@ -1846,6 +1877,8 @@ Available on all commands:
|
|
|
1846
1877
|
| `--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` |
|
|
1847
1878
|
| `--fail-on-regression` | `bool` | `false` | Fail if issue count increased beyond tolerance vs a regression baseline |
|
|
1848
1879
|
| `--fail-on-stale-baseline` | `bool` | `false` | Exit with code 1 if a loaded --baseline has entries that match nothing in this run |
|
|
1880
|
+
| `--fail-on-baseline-growth` | `bool` | `false` | Exit with code 1 if a loaded baseline has a key that the same file at the base ref does not have |
|
|
1881
|
+
| `--baseline-base` | `string` | - | The git ref that --fail-on-baseline-growth compares the baseline with |
|
|
1849
1882
|
| `--fail-on-parse-error` | `bool` | `false` | Exit with code 1 if fallow could not parse a source file cleanly |
|
|
1850
1883
|
| `--tolerance` | `string` | `0` | Allowed increase: `"2%"` (percentage) or `"5"` (absolute). Default: `"0"` |
|
|
1851
1884
|
| `--regression-baseline` | `string` | - | Path to a standalone regression baseline file. Without it, fallow uses `regression.baseline` from the config |
|
|
@@ -1926,6 +1959,7 @@ These are global flags with behavior specific to bare `fallow` combined mode.
|
|
|
1926
1959
|
| `FALLOW_EXTENDS_TIMEOUT_SECS` | Timeout for fetching remote config inheritance in seconds (default: `5`). Do not raise this for untrusted sources. |
|
|
1927
1960
|
| `FALLOW_CACHE_DIR` | Override the persistent extraction cache directory. Wins over `cache.dir`. Useful for read-only checkouts or CI cache volumes. `--no-cache` disables this knob. |
|
|
1928
1961
|
| `FALLOW_CACHE_MAX_SIZE` | Maximum on-disk extraction cache (`.fallow/cache.bin`) size in megabytes (default: `256`). Triggers LRU eviction when crossed. Wins over `cache.maxSizeMb` config field. Intended for CI runners with disk quotas. `--no-cache` short-circuits this knob. |
|
|
1962
|
+
| `FALLOW_PACKAGE_BASELINES` | Set to `false`, `0`, `no` or `off` to ignore `workspaces.changedSince` for every run of the process, like `--no-package-baselines`. Other values keep the map. |
|
|
1929
1963
|
| `FALLOW_COVERAGE` | Path to Istanbul or raw V8 coverage data for exact CRAP scoring in `health`, `audit`, and bare `fallow`. |
|
|
1930
1964
|
| `FALLOW_COVERAGE_ROOT` | Absolute coverage-data prefix to strip before matching Istanbul paths in `health`, `audit`, and bare `fallow`. |
|
|
1931
1965
|
| `FALLOW_TYPE_AWARE` | Enable or disable TypeScript semantic (type-aware) analysis for the run. Accepts `true`/`false`/`1`/`0`/`yes`/`no`/`on`/`off`; any other value is a hard error. Sits mid-chain in the precedence: the `--type-aware`/`--no-type-aware` CLI flags win over it, and it wins over the `audit.typeAware` config field, which wins over `typeAware.enabled`. |
|
|
@@ -2034,7 +2068,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
|
|
|
2034
2068
|
{
|
|
2035
2069
|
"kind": "dead-code",
|
|
2036
2070
|
"schema_version": 7,
|
|
2037
|
-
"version": "3.
|
|
2071
|
+
"version": "3.31.0",
|
|
2038
2072
|
"elapsed_ms": 45,
|
|
2039
2073
|
"total_issues": 12,
|
|
2040
2074
|
"entry_points": {
|
|
@@ -2194,7 +2228,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
|
|
|
2194
2228
|
{
|
|
2195
2229
|
"kind": "dupes",
|
|
2196
2230
|
"schema_version": 7,
|
|
2197
|
-
"version": "3.
|
|
2231
|
+
"version": "3.31.0",
|
|
2198
2232
|
"elapsed_ms": 82,
|
|
2199
2233
|
"total_clones": 15,
|
|
2200
2234
|
"total_lines_duplicated": 230,
|
|
@@ -2238,11 +2272,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
|
|
|
2238
2272
|
{
|
|
2239
2273
|
"kind": "combined",
|
|
2240
2274
|
"schema_version": 7,
|
|
2241
|
-
"version": "3.
|
|
2275
|
+
"version": "3.31.0",
|
|
2242
2276
|
"elapsed_ms": 159,
|
|
2243
2277
|
"check": {
|
|
2244
2278
|
"schema_version": 7,
|
|
2245
|
-
"version": "3.
|
|
2279
|
+
"version": "3.31.0",
|
|
2246
2280
|
"elapsed_ms": 45,
|
|
2247
2281
|
"total_issues": 12,
|
|
2248
2282
|
"unused_files": [],
|
|
@@ -2454,9 +2488,11 @@ preset = "bulletproof"
|
|
|
2454
2488
|
- `dynamicallyLoaded`: glob patterns for files loaded at runtime (plugin dirs, locale files); treated as always-used
|
|
2455
2489
|
- `cache.dir`: override the persistent extraction cache directory. `FALLOW_CACHE_DIR` wins over this config field, and `--no-cache` disables caching entirely
|
|
2456
2490
|
- `cache.maxSizeMb`: cap the serialized extraction cache size in megabytes. `FALLOW_CACHE_MAX_SIZE` wins over this config field
|
|
2491
|
+
- `workspaces.changedSince`: map exact workspace roots (as `fallow list --workspaces` prints them) to Git refs. `check`, `dead-code` and `dupes` then report the findings of a mapped package only for files changed since its ref; unlisted packages and root files stay in full scope. A global `--changed-since` replaces the map for one run; `--no-package-baselines` or `FALLOW_PACKAGE_BASELINES=false` turns it off. A key that names no workspace, or a ref Git cannot resolve, leaves every package in full scope with a warning and `request_outcomes["package-baselines"]` as `not-applied`. Save a whole-project baseline with `--no-package-baselines`.
|
|
2457
2492
|
- `usedClassMembers`: class method/property names that extend the built-in Angular/React lifecycle allowlist with framework-invoked names. Each entry is a plain string (global suppression) or a scoped object `{ extends?, implements?, members }` matching only classes with the given heritage. Strings can be exact names (`"agInit"`) or glob patterns (`"*"` matches every member, `"enter*"` prefix, `"*Handler"` suffix, `"on*Event"` combined). Use scoped rules for common names like `refresh` or `execute` to avoid false negatives on unrelated classes; global strings for unique names like `agInit`. Example: `["agInit", { "implements": "ICellRendererAngularComp", "members": ["refresh"] }, { "extends": "BaseCommand", "members": ["execute"] }, { "extends": "GrammarBaseListener", "members": ["enter*", "exit*"] }]`. Glob patterns that match zero members emit a `WARN` so dead allowlist entries surface. An unconstrained scoped rule (no `extends` or `implements`) is rejected at load time. Use plugin-level `usedClassMembers` in a `.fallow/plugins/*.jsonc` file for library-specific allowlists
|
|
2458
2493
|
- `resolve.conditions`: additional package.json `exports` / `imports` condition names to honor during module resolution. Baseline conditions (`development`, `import`, `require`, `default`, `types`, `node`, plus `react-native` / `browser` under RN/Expo) are always included; user entries prepend ahead of them. Use for community conditions like `worker`, `edge-light`, `deno`, or custom bundler conditions. Example: `{ "resolve": { "conditions": ["worker", "edge-light"] } }`
|
|
2459
2494
|
- `unusedComponentProps.ignorePattern`: opt-in regex that exempts a component prop from `unused-component-props` when the prop's LOCAL destructure binding name matches (the leading-underscore "accepted-but-intentionally-unused" convention, mirroring TS `noUnusedParameters` + ESLint `varsIgnorePattern` / `argsIgnorePattern`). Applies to Vue, Svelte, Astro, and React/Preact props. The match is on the local alias (`_stage` in `let { stage: _stage } = $props()`), not the public prop name the finding reports (`stage`); matching is unanchored like ESLint's `RegExp.test`, so anchor with `^_`. An invalid regex fails config load. Example: `{ "unusedComponentProps": { "ignorePattern": "^_" } }`
|
|
2495
|
+
- `circularDependencies.ignoreLazyImports`: opt-in boolean, default `false`. When `true`, `circular-dependencies` skips an import edge on which every import loads its target on demand or on another thread: an `import()` inside a function, a template `import()`, a lazy `import.meta.glob`, a worker URL, or a webpack worker loader request such as `worker-loader!./work.js`. A top-level `await import()`, `require()`, an eager `import.meta.glob`, and an edge that also has a static import stay. The filter runs before cycles are counted, so lazy cycles do not use the per-group cycle limit. Example: `{ "circularDependencies": { "ignoreLazyImports": true } }`
|
|
2460
2496
|
|
|
2461
2497
|
---
|
|
2462
2498
|
|
|
@@ -436,6 +436,30 @@ Fallow treats `Config` and `Result` in `./types.ts` as used. Works with `@param`
|
|
|
436
436
|
|
|
437
437
|
---
|
|
438
438
|
|
|
439
|
+
## Command File Arguments Are Entry Points
|
|
440
|
+
|
|
441
|
+
A file that a command names in a `package.json` script, a CI file (GitHub Actions, GitLab CI), a Dockerfile, a Procfile, or `fly.toml` becomes an entry point: `node scripts/seed.ts` keeps `scripts/seed.ts` and its imports reachable.
|
|
442
|
+
|
|
443
|
+
Formatters, linters, and checkers are the exception. They read their file arguments but do not run them, so `eslint src/a.ts`, `prettier --check "**/*.ts"`, `oxlint src/`, `biome check`, `stylelint`, `textlint`, and similar tools make no entry points. This applies to the common package-manager and wrapper forms (`npx`, `pnpm exec`, `pnpm --filter web exec`, `pnpm -r exec`, `yarn run`, `cross-env`, `dotenv -e .env --`, `varlock run --`), and to a call of a script that runs the tool (`npm run lint -- src/a.ts`, `npm run lint src/a.ts`, `yarn lint src/a.ts`). The tool stays a used dependency, its `--config` file stays tracked, and a module that it loads through a flag (`eslint -f ./fmt.js`, `prettier --plugin=./plugin.mjs`) stays reachable.
|
|
444
|
+
|
|
445
|
+
A command in a workspace package that the command selects resolves its file arguments against the directory of that package. `yarn workspace web node scripts/a.ts`, `pnpm --filter web exec tsx scripts/a.ts`, `npm exec -w web -- tsx scripts/a.ts`, and a call of a script of that package (`npm run -w web gen -- scripts/a.ts`) make `scripts/a.ts` of the `web` package an entry point. A pnpm filter can be a name, a name glob (`'@acme/*'`), a directory (`./packages/*`, `{packages/web}`), or an exclusion (`'!web'`). A selection of several packages resolves the file in each package where the file exists. This includes every package: `pnpm -r exec tsx scripts/a.ts`, `yarn workspaces foreach -A exec tsx scripts/a.ts` (narrowed by `--include` and `--exclude`), `yarn workspaces run gen scripts/a.ts`, and `npm --workspaces run gen -- scripts/a.ts`. `yarn workspaces foreach -A` also runs in the root package, as yarn berry does, and its `--include` and `--exclude` match a workspace name or directory (`.` is the root). `pnpm -w` also selects the root package. `--include-workspace-root` adds the root package: in pnpm to `-r` and to a filter that only excludes packages (`--filter '!web'`), and in npm to every workspace selection (`-w web`, `--workspaces`). Without it, `pnpm -r`, `yarn workspaces run`, and `npm --workspaces` leave out the root package. From a workspace package, `npm --workspaces` selects only that package. A `start` script that calls a script in selected packages (`pnpm -r run serve`, `pnpm -C packages/web run serve`) makes that script a runtime script of each package. A script call in the directory of a workspace package (`pnpm -C packages/web run gen scripts/a.ts`, `npm --prefix packages/web run gen -- scripts/a.ts`, `yarn --cwd packages/web gen scripts/a.ts`) runs the script of that package with the forwarded arguments. The formatter and linter rule above still applies in each selected package.
|
|
446
|
+
|
|
447
|
+
A command that runs in workspace packages that Fallow cannot resolve makes no entry points, because those packages resolve the paths against their own directories. This covers the pnpm dependency and changed-package filters (`web...`, `[origin/main]`), the other `yarn workspaces foreach` selections (`--since`, `--recursive`, `--from`, `--worktree`, `--no-private`), and task runners (`turbo run lint -- src/a.ts`, `nx`, `lerna`). The binary stays a used dependency. A command in another directory (`pnpm -C docs exec tsx scripts/a.ts`, `npm --prefix`, `yarn --cwd`) resolves its file arguments against that directory. `yarn node <file>` runs the file with Node.js, also after `yarn --cwd <dir>` and `yarn workspace <name>`.
|
|
448
|
+
|
|
449
|
+
A declared script with the name of a tool runs instead of the tool. With `"eslint": "node tools/check.js"`, `yarn eslint src/a.ts` keeps `src/a.ts` as an entry point.
|
|
450
|
+
|
|
451
|
+
For another command whose file arguments are data, list it in `ignoreCommandEntries`:
|
|
452
|
+
|
|
453
|
+
```jsonc
|
|
454
|
+
{
|
|
455
|
+
"ignoreCommandEntries": ["my-codegen"]
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
`["*"]` turns off entry points from all commands, including modules that a linter loads through a flag (`eslint -f ./fmt.js`); declare the real entries in `entry` instead.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
439
463
|
## JSX `<script src>` and `<link href>` Are Asset References
|
|
440
464
|
|
|
441
465
|
Inside JSX/TSX files, lowercase intrinsic `<script src="...">` and `<link rel="stylesheet|modulepreload" href="...">` are tracked as asset references, same as in plain HTML files. This is needed for SSR frameworks like Hono where layout components emit HTML via JSX.
|
|
@@ -30,7 +30,8 @@ The `generated:issue-types` table below is regenerated from `fallow schema` by s
|
|
|
30
30
|
| `duplicate-export` | `--duplicate-exports` | - | `// fallow-ignore-file duplicate-export` | Same symbol exported from multiple modules |
|
|
31
31
|
| `circular-dependency` | `--circular-deps` | - | `// fallow-ignore-next-line circular-dependency` | Import cycles in the module graph |
|
|
32
32
|
| `re-export-cycle` | `--re-export-cycles` | - | `// fallow-ignore-file re-export-cycle` | Barrel files re-exporting from each other in a loop (`kind: "multi-node"`) or a barrel re-exporting from itself (`kind: "self-loop"`). Chain propagation through the loop is a structural no-op so imports through any member may silently come up empty. Default `warn`. Distinct from `circular-dependencies` (runtime cycles, sometimes intentional). File-scoped suppression only: `// fallow-ignore-file re-export-cycle` on any member breaks the cycle. |
|
|
33
|
-
| `
|
|
33
|
+
| `package-cycle` | `--package-cycles` | - | `// fallow-ignore-next-line package-cycle` | Two or more workspace packages import each other in a loop, so they cannot be built in dependency order. Edges are resolved imports, not declared `package.json` dependencies. Imports from test, spec, story, fixture and tooling config files do not count. Type-only imports count, and each hop in `edges` has a `type_only` flag. Default `warn`. Requires a workspace with two or more packages. A suppression removes one import; the cycle goes away when every import on one hop is suppressed. `group_truncated: true` means the package group has more cycles than listed. `--changed-since` and diff scope use the example import of each hop (`edges[].path`) |
|
|
34
|
+
| `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. Named and default imports through a barrel are judged against the zone of the origin module (`to_path`), and `via_path` names the barrel. 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 |
|
|
34
35
|
| `boundary-coverage` | `--boundary-violations` | - | `// fallow-ignore-file boundary-violation` | Source file matches no configured architecture boundary zone; Requires boundaries.coverage.requireAllFiles |
|
|
35
36
|
| `boundary-call-violation` | `--boundary-violations` | - | `// fallow-ignore-next-line boundary-call-violation` | Zoned file calls a callee its zone forbids; Requires boundaries.calls.forbidden patterns |
|
|
36
37
|
| `policy-violation` | `--policy-violations` | - | `// fallow-ignore-next-line policy-violation` | Calls, imports, or catalogue-derived effects banned by a declarative rule pack (`rulePacks` config key lists standalone JSON/JSONC files of `banned-call`, `banned-import`, and `banned-effect` 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. |
|
|
@@ -72,6 +73,7 @@ The `generated:issue-types` table below is regenerated from `fallow schema` by s
|
|
|
72
73
|
| `untested-export` | `--coverage-gaps` | - | `// fallow-ignore-file coverage-gaps` | Runtime-reachable export has no test dependency path |
|
|
73
74
|
| `code-duplication` | - | - | `// fallow-ignore-next-line code-duplication` | Duplicated code block; Reported by fallow dupes (and bare fallow / fallow audit) |
|
|
74
75
|
| `feature-flag` | - | - | `// fallow-ignore-next-line feature-flag` | Detected feature flag pattern; Reported by fallow flags |
|
|
76
|
+
| `flag-retirement-candidate` | - | - | - | Feature flag is a retirement candidate |
|
|
75
77
|
| `tainted-sink` | - | - | `// fallow-ignore-next-line security-sink` | Syntactic security sink candidates require verification |
|
|
76
78
|
| `client-server-leak` | - | - | `// fallow-ignore-file security-client-server-leak` | Client-bound code reaches a non-public env read |
|
|
77
79
|
| `hardcoded-secret` | - | - | `// fallow-ignore-next-line security-sink` | Provider-prefixed or contextual secret literals require verification; Include-required category: enable via security.categories.include |
|
|
@@ -12,7 +12,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
|
|
|
12
12
|
| Tool | Kind | License | CLI fallback | Key params | Description |
|
|
13
13
|
|---|---|---|---|---|---|
|
|
14
14
|
| `code_execute` | composition | free | - | `code`, `timeout_ms`, `max_output_bytes` | Bounded read-only Code Mode for composing multiple fallow analysis calls in one JavaScript snippet. The snippet receives `{ fallow, root }`, returns JSON-serializable data, and can call read-only helpers such as `fallow.projectInfo`, `fallow.audit`, `fallow.checkHealth`, and `fallow.run(tool, params)` for the same allowlist. `fallow.all(requests)` fans out independent calls in one go: pass `[{ tool, params }, ...]` and get back a positionally aligned array of `{ ok: true, value }` or `{ ok: false, error }`, so one failing element never hides the rest. Host calls are memoized for the duration of one snippet, so repeating the same tool with the same params (key order does not matter) is served from cache, spends no `max_host_calls` slot and no output budget, and is reported in `calls[]` with `cache_hit: true`; a call refused before dispatch (unknown tool, malformed params) spends no slot either, and `limits.max_rejected_host_calls` bounds how many of those the response records. Similar-code is excluded because Code Mode is capped at 30 seconds; use standalone `find_similar_code` and `inspect_similar_code`, which have dedicated 15-minute timeouts. Mutating fix tools are not exposed, and a host call that passes `save_baseline`, `save_regression_baseline` or `save_snapshot` is refused with the name of the standalone tool to call. The sandbox has no filesystem, network, imports, `process`, `require`, `Deno`, `Bun`, or shell access, and no dynamic code compilation: `eval`, `Function`, and the async and generator function constructors are removed, including the `constructor` route reachable through function prototypes. Params: `code`, optional `root`, `timeout_ms` (capped at 30000), and `max_output_bytes` (capped at 4000000). `max_output_bytes` bounds two separate things: the total fallow JSON host calls read, shared across a `fallow.all` fan-out rather than granted per element, and the serialized snippet result. An oversized result is refused with `ok:false`, `truncated:true`, `result_bytes`, and a short `result_preview` in place of the value, never returned whole, so return a projection rather than a whole report. |
|
|
15
|
-
| `analyze` | analysis | free | `fallow dead-code --format json --quiet` | `issue_types`, `production`, `workspace`, `baseline`, `group_by`, `file` | Full dead code analysis (unused files/exports/types/dependencies/members + circular dependencies + re-export cycles (barrel files that form a structural loop, silently breaking re-exports) + boundary violations + rule-pack policy violations (banned calls, imports, and catalogue-derived effects declared via the `rulePacks` config key) + stale suppressions). Private type leaks are an opt-in API hygiene check via `issue_types: ["private-type-leaks"]`. Deprecated exports that still have consumers are an opt-in migration sweep via `issue_types: ["deprecated-exports-in-use"]`. Set `boundary_violations: true` as a convenience alias for `issue_types: ["boundary-violations"]`. Set `group_by` to `"owner"`, `"directory"`, `"package"`, or `"section"` to partition results. The `section` mode reads GitLab CODEOWNERS `[Section]` headers and emits `owners` metadata per group |
|
|
15
|
+
| `analyze` | analysis | free | `fallow dead-code --format json --quiet` | `issue_types`, `production`, `workspace`, `baseline`, `group_by`, `file` | Full dead code analysis (unused files/exports/types/dependencies/members + circular dependencies + re-export cycles (barrel files that form a structural loop, silently breaking re-exports) + package cycles (workspace packages that import each other in a loop) + boundary violations + rule-pack policy violations (banned calls, imports, and catalogue-derived effects declared via the `rulePacks` config key) + stale suppressions). Private type leaks are an opt-in API hygiene check via `issue_types: ["private-type-leaks"]`. Deprecated exports that still have consumers are an opt-in migration sweep via `issue_types: ["deprecated-exports-in-use"]`. Set `boundary_violations: true` as a convenience alias for `issue_types: ["boundary-violations"]`. Set `group_by` to `"owner"`, `"directory"`, `"package"`, or `"section"` to partition results. The `section` mode reads GitLab CODEOWNERS `[Section]` headers and emits `owners` metadata per group |
|
|
16
16
|
| `check_changed` | analysis | free | `fallow dead-code --changed-since <ref> --format json --quiet` | `since`, `baseline`, `fail_on_regression` | Incremental analysis of files changed since a git ref |
|
|
17
17
|
| `security_candidates` | analysis | free | `fallow security --format json --quiet` | `gate`, `surface`, `changed_since`, `paths` | Unverified local security candidates, not confirmed vulnerabilities (`fallow security --format json`). Read `security_findings[]` for category, CWE, severity, evidence, trace, optional `reachability`, blind-spot counters, and optional `unresolved_callee_diagnostics` samples for dynamic callee follow-up. `severity` is a review-priority tier, not a verified vulnerability verdict. Each finding also carries an agent-actionable `candidate` (`source_kind`/`sink`/`boundary`), where URL-category sinks may include `url_shape` (`fixed-origin-dynamic-path` or `dynamic-origin`), an optional `taint_flow` source-to-sink triple, and a stable `finding_id` (equal to the SARIF fingerprint) for cross-run correlation; there is no `impact` field (deciding exploitability is the agent's job). Set `surface: true` to include top-level `attack_surface[]` entries with defensive-boundary prompts for a verifier. Set `gate` to `new` for changed-line candidates or `newly-reachable` for candidates that became reachable from entry points; `newly-reachable` requires `changed_since`. `reachability.untrusted_source_trace` is module-level import context only and does not prove value flow; `reachability.taint_confidence` tiers each reachable candidate as `arg-level` (sink argument traces to a same-module source read, strong) or `module-level` (only the module is import-reachable from a source, weak), so tier from this field instead of the evidence text. Verify trace, reachability context, severity, and evidence before editing code. Supports `root`, `config`, `workspace`, `paths`, `changed_since`, `changed_workspaces`, `surface`, `gate`, `no_cache`, and `threads`; `paths` forwards repeated `fallow security --file` filters for finding anchors, trace hops, untrusted-source reachability trace hops, and unresolved-callee diagnostics. See <https://docs.fallow.tools/cli/security-agent-verification> for the verifier packet and verdict recipe. Inherits `FALLOW_DIFF_FILE` from the server environment for line-level diff scoping; raise `FALLOW_TIMEOUT_SECS` for large repos. |
|
|
18
18
|
| `find_similar_code` | analysis | free | `fallow similar-code --format json --quiet` | `threshold`, `min_lines`, `top`, `changed_since`, `paths` | Find unverified semantically similar function candidates with the exact pinned local model. Discovery is read-only and never authorizes or performs model setup. Scoped output materializes the exact admitted files once in `generation.scope.paths` as provenance. Ask the user to run `fallow similar-code setup --local` when setup is missing. Cold local inference has a dedicated 15-minute subprocess window. |
|
|
@@ -27,6 +27,8 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
|
|
|
27
27
|
| `get_importance` | runtime-coverage | freemium | `fallow health --runtime-coverage <path> --format json --quiet` | `coverage`, `group_by` | Runtime-context slice for production-importance review. Same params as `check_runtime_coverage`; read `runtime_coverage.importance` for stable `fallow:importance:<hash>` IDs, invocations, cyclomatic complexity, owner count, 0-100 score, and templated reason. |
|
|
28
28
|
| `get_cleanup_candidates` | runtime-coverage | freemium | `fallow health --runtime-coverage <path> --format json --quiet` | `coverage`, `group_by` | Runtime-context slice for cleanup review. Same params as `check_runtime_coverage`; read `runtime_coverage.findings` for `safe_to_delete`, `review_required`, `low_traffic`, and `coverage_unavailable`. |
|
|
29
29
|
| `get_cloud_runtime_context` | runtime-coverage | freemium | `fallow coverage analyze --cloud --repo <owner/repo> --format json --quiet` | `repo`, `period_days`, `environment`, `commit_sha`, `top` | Cloud-backed runtime-context slice, and the only MCP tool that makes a network call. Required `repo` (`owner/repo`); `project_id`, `period_days` (1-90, default 30), `environment`, and `commit_sha` narrow the cloud selection, while `production`, `top`, and `min_invocations_hot` behave as on `check_runtime_coverage`. The key is `FALLOW_API_KEY` in the server environment and never a param: without it the call is refused with `code: "cloud_api_key_missing"` before anything runs. Returns the same `runtime_coverage` block as the local tools, joined against the checkout at `root`, so a `root` on a different revision quietly empties `findings` and raises a `cloud_functions_unmatched` warning. Confirm `runtime_coverage.summary.data_source` is `cloud`, and read the source-map confidence table below before acting on file-level signals. |
|
|
30
|
+
| `get_cloud_review_packet` | runtime-coverage | freemium | `fallow coverage review-packet --repo <owner/repo> --file <path> --format json --quiet` | `repo`, `files`, `functions`, `period_days`, `project_id` | Production facts of a few changed files or functions, read from fallow cloud without the full runtime-context pull |
|
|
31
|
+
| `get_cloud_deployment_changes` | runtime-coverage | freemium | `fallow coverage deployment-changes --repo <owner/repo> --sha <sha> --format json --quiet` | `repo`, `sha`, `base`, `change` | How production behavior changed between two deployments, read from the fallow cloud change report |
|
|
30
32
|
| `get_token_blast_radius` | analysis | free | `fallow health --css --format json --quiet` | - | Design-token blast radius for Tailwind v4 @theme tokens and CSS-in-JS token definitions (StyleX, vanilla-extract, PandaCSS): per token, a consumer_count (static lower bound) and a capped located consumers[] sample tagged theme-var/css-var/utility/apply (Tailwind), js-member (member access), or js-call (StyleX theme-group and Panda token calls); descriptive context for sizing a token change, never a deletion gate |
|
|
31
33
|
| `audit` | analysis | free | `fallow audit --format json --quiet` | `gate`, `base`, `css_deep`, `max_crap`, `coverage`, `runtime_coverage` | Combined dead-code + complexity + duplication + styling for changed files, returns verdict. Styling analytics are enabled by default; CSS and CSS-in-JS evidence can add `styling_findings`, `css_analytics`, and `styling_health` under the health sub-result. Set `gate` to `"new-only"` or `"all"`. Set `css_deep: false` to skip project-wide styling reachability while keeping local styling checks, or `css_deep: true` to force it back on when config disables it. Optional `runtime_coverage` (V8 dir / V8 JSON / Istanbul JSON) folds runtime findings into the same call; `min_invocations_hot` tunes the hot-path threshold (default 100). Runtime evidence appears under the audit `complexity` sub-result, including `coverage_intelligence` when combined evidence yields actionable recommendations. |
|
|
32
34
|
| `decision_surface` | analysis | free | `fallow decision-surface --format json --quiet` | `base`, `max_decisions`, `workspace` | Surface the few consequential structural decisions a change embeds (coupling, public API, dependency), each as a judgment question with the routed expert; ranked, capped, and signal_id-anchored |
|
|
@@ -36,7 +38,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
|
|
|
36
38
|
| `project_info` | introspection | free | `fallow list --files --entry-points --plugins --format json --quiet` | `entry_points`, `files`, `plugins`, `boundaries` | Project metadata. Set `entry_points`, `files`, `plugins`, or `boundaries` to `true` to request specific sections |
|
|
37
39
|
| `recommend` | introspection | free | `fallow recommend --format json --quiet` | `root` | Recommend a project-tailored config from framework/workspace/tooling detection: a loader-validated proposed_config and three-valued auto/default/taste decisions for cold-start onboarding |
|
|
38
40
|
| `list_boundaries` | introspection | free | `fallow list --boundaries --format json --quiet` | - | Architecture boundary zones, access rules, and pre-expansion `autoDiscover` `logical_groups[]` (user-authored parent name, verbatim paths, discovered children, `status` enum, summed `file_count`). Returns `{"configured": false}` if no boundaries configured |
|
|
39
|
-
| `feature_flags` | analysis | free | `fallow flags --format json --quiet` | `workspace`, `production` | Detect feature flag patterns (env vars, SDK calls, config objects). Set `top` to limit results |
|
|
41
|
+
| `feature_flags` | analysis | free | `fallow flags --format json --quiet` | `workspace`, `production` | Detect feature flag patterns (env vars, SDK calls, config objects). Set `top` to limit results. `retirement: true` adds the retirement rows; `flag_state` and `flag_age` tune them |
|
|
40
42
|
| `list_suppressions` | analysis | free | `fallow suppressions --format json --quiet` | `workspace`, `changed_since`, `file` | List active fallow-ignore suppression markers grouped per file (line, kind, level, reason, and a stale cross-reference); a read-only governance inventory that always exits 0 |
|
|
41
43
|
| `impact` | introspection | free | `fallow impact --format json --quiet` | `root` | Read the local, opt-in Fallow Impact value report (`fallow impact --format json`). Runs no analysis: current surfacing counts, trend since the last recorded run, pre-commit gate containment, and (on impact v1.5+) resolved/suppressed attribution. History is read from a per-project file in the user's private config dir (never inside the repo). Read-only and `root`-only; the mutating `enable` / `disable` / `default` lifecycle is not exposed. A never-enabled project returns a populated `{"enabled": false, ...}` report (never `{}`); branch on `enabled` and `enabled_source` (`project` / `user` / `default`) then `record_count`, recommending `fallow impact enable` only when `explicit_decision` is `false` (never asked) and staying silent when `true` (deliberately disabled here). Local-developer signal: fallow never records in CI, so empty there and not a CI metric |
|
|
42
44
|
| `impact_all` | introspection | free | `fallow impact --all --format json --quiet` | `sort`, `limit` | Roll every tracked fallow project on this machine into one cross-repo value report (hashed keys plus basename labels, never paths; local-dev only) |
|
|
@@ -95,6 +97,34 @@ ambiguity or reachable references.
|
|
|
95
97
|
|
|
96
98
|
`trace_export` never carries a `semantic` block: it is API-backed in-process and answers from the graph alone.
|
|
97
99
|
|
|
100
|
+
## Scoped cloud reads
|
|
101
|
+
|
|
102
|
+
Use these reads when the project sends production coverage to Fallow Cloud. The CLI reads the key from `--api-key` or `FALLOW_API_KEY`; the MCP tools read `FALLOW_API_KEY` from the server environment only. Prefer the two scoped reads: they return only the functions or the deploy you ask about. `get_cloud_runtime_context` downloads the evidence of every function and runs a full local analysis first, so keep it for whole-project questions.
|
|
103
|
+
|
|
104
|
+
| Question | CLI | MCP tool |
|
|
105
|
+
|:---------|:----|:---------|
|
|
106
|
+
| Is a changed function hot, cold, or tested? | `fallow coverage review-packet --repo <owner/repo>` | `get_cloud_review_packet` |
|
|
107
|
+
| Did the last deploy change what runs? | `fallow coverage deployment-changes --repo <owner/repo>` | `get_cloud_deployment_changes` |
|
|
108
|
+
|
|
109
|
+
**Before an edit.** Without `--file` or `--function`, `review-packet` sends the source files changed against the base (`--base`, then `FALLOW_AUDIT_BASE`, then the merge-base). Narrow it with `--file <path>` or `--function <file>:<name>[:<line>]`, both repeatable; over MCP pass `files[]` or `functions[{file, name, line?}]`. Per function, read:
|
|
110
|
+
|
|
111
|
+
- `hit_count`: the production call count. Rank hot functions by it, not by `prod_hit_count`, which counts tagged traffic only.
|
|
112
|
+
- `tracking_state`: `called`, `never_called`, or `untracked` in the current deployment.
|
|
113
|
+
- `covered_by_test`: `true` or `null`. `null` means no test evidence, not "no test". A hot function with `covered_by_test: null` is a high-risk edit.
|
|
114
|
+
- `blast_radius.caller_count` and `blast_radius.caller_sites`: callers when the data exists; `null` is unknown, not zero.
|
|
115
|
+
|
|
116
|
+
An entry in `not_found` has no cloud data. Absence is not evidence that the code is cold.
|
|
117
|
+
|
|
118
|
+
**Before a delete.** Require both static and runtime evidence:
|
|
119
|
+
|
|
120
|
+
1. `fallow dead-code --trace <file>:<export>` (MCP `trace_export`) confirms the static side.
|
|
121
|
+
2. `period_tracking_state` is `never_called`. It covers the whole period, while `tracking_state` covers only the current deployment. A function with `period_tracking_state: "called"` never gets a `safe_to_delete` verdict.
|
|
122
|
+
3. `evidence_window.observed_hours` is large enough for the traffic of that code. An admin page, a yearly job, an error handler, or a flagged feature can stay unvisited for a long time: "never called" there means "not visited", not "dead". Ask the owner or keep the code.
|
|
123
|
+
|
|
124
|
+
**After a deploy.** `deployment-changes` compares `--sha` (default: git HEAD) with `--base` (default: the previous deployment with production runtime). Each function gets one kind: `stopped`, `new_not_called`, `heated_up`, `cooled_down`, `new_called`, or `unchanged`. Filter with `--change <kind>`, page with `--limit` (1 to 200) and `--cursor`. When `comparable` is `false`, report `reason` and claim no stop and no rate change: `head_warming_up`, `head_short_window`, and `head_insufficient_runtime` mean "try again later"; `no_base_deployment` means there is nothing to compare; `runtime_surfaces_differ`, `runtime_surfaces_unknown`, and `function_set_differs` mean the two deployments do not measure the same code. The report is context and never proves that a function is dead.
|
|
125
|
+
|
|
126
|
+
**Paths.** Open and edit files by `repo_path`. `file_path` is the path the runtime reported (for example `/app/src/x.ts` in a container) and often does not exist in the checkout.
|
|
127
|
+
|
|
98
128
|
## Runtime source-map confidence for cloud runtime tools
|
|
99
129
|
|
|
100
130
|
| Values | Meaning | Agent action |
|