fallow 2.101.0 → 2.102.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "2.101.0",
3
+ "version": "2.102.0",
4
4
  "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -80,16 +80,16 @@
80
80
  "detect-libc": "2.1.2"
81
81
  },
82
82
  "devDependencies": {
83
- "@tanstack/intent": "0.0.42"
83
+ "@tanstack/intent": "0.1.1"
84
84
  },
85
85
  "optionalDependencies": {
86
- "@fallow-cli/darwin-arm64": "2.101.0",
87
- "@fallow-cli/darwin-x64": "2.101.0",
88
- "@fallow-cli/linux-x64-gnu": "2.101.0",
89
- "@fallow-cli/linux-arm64-gnu": "2.101.0",
90
- "@fallow-cli/linux-x64-musl": "2.101.0",
91
- "@fallow-cli/linux-arm64-musl": "2.101.0",
92
- "@fallow-cli/win32-arm64-msvc": "2.101.0",
93
- "@fallow-cli/win32-x64-msvc": "2.101.0"
86
+ "@fallow-cli/darwin-arm64": "2.102.0",
87
+ "@fallow-cli/darwin-x64": "2.102.0",
88
+ "@fallow-cli/linux-x64-gnu": "2.102.0",
89
+ "@fallow-cli/linux-arm64-gnu": "2.102.0",
90
+ "@fallow-cli/linux-x64-musl": "2.102.0",
91
+ "@fallow-cli/linux-arm64-musl": "2.102.0",
92
+ "@fallow-cli/win32-arm64-msvc": "2.102.0",
93
+ "@fallow-cli/win32-x64-msvc": "2.102.0"
94
94
  }
95
95
  }
@@ -13,7 +13,6 @@ metadata:
13
13
  Codebase intelligence for JavaScript and TypeScript. The free static layer reports quality, changed-code risk, cleanup opportunities, circular dependencies, code duplication, complexity hotspots, architecture boundary violations, feature flag patterns, and opt-in security candidates. Runtime coverage merges production execution data into the same `fallow health` report for hot-path review, cold-path deletion confidence, and stale-flag evidence, with a single local capture available by default and continuous/cloud runtime monitoring available as an optional mode. 122 framework plugins, zero configuration, sub-second static analysis.
14
14
 
15
15
  ## When to Use
16
-
17
16
  - Finding cleanup opportunities (unused files, exports, types, enum/class members)
18
17
  - Finding unused or unlisted dependencies
19
18
  - Detecting code duplication and clones
@@ -32,7 +31,6 @@ Codebase intelligence for JavaScript and TypeScript. The free static layer repor
32
31
  - Reviewing what fallow has surfaced over time (`fallow impact`)
33
32
 
34
33
  ## When NOT to Use
35
-
36
34
  - Runtime error analysis or debugging
37
35
  - Type checking (use `tsc` for that)
38
36
  - Linting style or formatting issues (use ESLint, Biome, Prettier)
@@ -96,6 +94,7 @@ Route by intent before reaching for the big analysis commands. Same matrix as `f
96
94
  | `dead-code` | Dead code analysis (`check` is an alias) | `--unused-exports`, `--changed-since`, `--changed-workspaces`, `--production`, `--file`, `--include-entry-exports`, `--stale-suppressions`, `--ci`, `--group-by`, `--summary`, `--fail-on-regression`, `--tolerance`, `--regression-baseline`, `--save-regression-baseline` |
97
95
  | `watch` | Watch for changes and re-run analysis | `--no-clear` |
98
96
  | `inspect` | Compose one evidence bundle for a file or exported symbol | `--file <path>`, `--symbol <file>:<export>` |
97
+ | `trace` | Trace a symbol's call chain (best-effort, syntactic; OFF the ranked path) | `symbol`, `--callers`, `--callees`, `--depth` |
99
98
  | `fix` | Auto-remove unused exports/deps | `--dry-run`, `--yes` (required in non-TTY) |
100
99
  | `init` | Generate config file, AGENTS.md agent guide, or pre-commit hook | `--toml`, `--agents`, `--hooks`, `--branch` |
101
100
  | `hooks` | Inspect, install, or remove fallow-managed Git and agent hooks | `status`, `install --target git`, `install --target agent`, `uninstall --target git`, `uninstall --target agent` |
@@ -112,6 +111,7 @@ Route by intent before reaching for the big analysis commands. Same matrix as `f
112
111
  | `flags` | Detect feature flag patterns (env vars, SDK calls, config objects) | `--top` |
113
112
  | `explain` | Explain one issue type without running analysis | `<issue-type>`, `--format json` |
114
113
  | `audit` | Combined dead-code + complexity + duplication for changed files | `--base`, `--gate`, `--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`, `--include-entry-exports` |
114
+ | `decision-surface` | Surface the consequential structural DECISIONS a change embeds (the apex of the review brief), each framed as a judgment question with the routed expert to ask | `--max-decisions` |
115
115
  | `impact` | Show what fallow has done for you: how many issues it is surfacing, the trend since the last recorded run, and how many commits it contained at the pre-commit gate | `--all`, `--sort`, `--limit` |
116
116
  | `security` | Surface opt-in local security candidates for agent verification (not confirmed vulnerabilities). Rule families include the graph rule `client-server-leak`, a data-driven `tainted-sink` catalogue, and the include-required `hardcoded-secret` category for provider-prefix credentials and high-entropy literals assigned to secret-shaped identifiers. Most catalogue rows require non-literal input; narrowly literal-aware rows flag deterministic unsafe literals. Rules default off; suppress a file with `// fallow-ignore-file security-sink`; scope categories with `security.categories`. Add project-local request object names with `security.requestReceivers`; it extends the built-in `req` / `request` / `ctx` / `context` / `event` allowlist for HTTP `query`, `params`, and `body` reads. `hardcoded-secret` runs only when listed in `security.categories.include`. | `--format human\|json\|sarif`, `--changed-since`, `--file`, `--diff-file`, `--workspace`, `--changed-workspaces`, `--surface`, `--ci`, `--fail-on-issues`, `--sarif-file`, `--summary` |
117
117
  | `schema` | Dump CLI definition as JSON | |
@@ -211,6 +211,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
211
211
  | `get_importance` | runtime-coverage | freemium | `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. |
212
212
  | `get_cleanup_candidates` | runtime-coverage | freemium | `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`. |
213
213
  | `audit` | analysis | free | `gate`, `base`, `max_crap`, `coverage`, `runtime_coverage` | Combined dead-code + complexity + duplication for changed files, returns verdict. Set `gate` to `"new-only"` or `"all"`. 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. |
214
+ | `decision_surface` | analysis | free | `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 |
214
215
  | `fallow_explain` | introspection | free | `issue_type` | Explain one issue type without running analysis. Required `issue_type`; returns rationale, examples, fix guidance, and docs URL |
215
216
  | `fix_preview` | fix | free | `no_create_config` | Dry-run auto-fix preview |
216
217
  | `fix_apply` | fix | free | `no_create_config` | Apply auto-fixes (destructive) |
@@ -45,6 +45,7 @@ Analyzes the project for unused files, exports, dependencies, types, members, an
45
45
  | `--trace` | `string` | - | Trace export usage chain |
46
46
  | `--trace-file` | `string` | - | Show all edges for a file |
47
47
  | `--trace-dependency` | `string` | - | Trace where a dependency is used |
48
+ | `--impact-closure` | `string` | - | Compute the impact closure for a file (the transitive affected-but-not-in-diff set + coordination gap). Walks reverse-deps and re-export chains; powers the `inspect_target` MCP tool |
48
49
  | `--top` | `string` | - | Show only the top N items per category |
49
50
  | `--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 |
50
51
 
@@ -505,7 +506,7 @@ fallow health --format json --quiet --trend
505
506
  {
506
507
  "kind": "health",
507
508
  "schema_version": 7,
508
- "version": "2.101.0",
509
+ "version": "2.102.0",
509
510
  "elapsed_ms": 32,
510
511
  "summary": {
511
512
  "files_analyzed": 482,
@@ -828,6 +829,11 @@ Audits changed files for dead code, complexity, and duplication. Returns a verdi
828
829
  | `--runtime-coverage` | `string` | - | Paid runtime-coverage sidecar input. Accepts a V8 directory, a single V8 JSON file, or an Istanbul coverage map JSON. Spawns the `fallow-cov` sidecar as part of the audit pipeline so the `hot-path-touched` verdict surfaces alongside dead-code and complexity findings without requiring a second `fallow health` invocation in CI. License-gated; the verdict is informational (no exit code change) until a future `--gate hot-path-touched` knob lands |
829
830
  | `--min-invocations-hot` | `string` | `100` | Threshold for hot-path classification, forwarded to the sidecar when `--runtime-coverage` is set |
830
831
  | `--gate-marker` | `string` | - | Internal marker identifying a gate run (e.g. `pre-commit`), set by the generated git hook so Fallow Impact can record a containment event when the gate blocks then clears. Hidden; never changes the verdict, exit code, or output |
832
+ | `--brief` | `bool` | `false` | Render the deterministic review brief instead of the gating audit report. The brief answers "where do I look?" rather than "will CI block this?", runs the same analysis, and ALWAYS exits 0 (the verdict is carried informationally). Implied by `fallow review`. Orthogonal to `--format` |
833
+ | `--max-decisions` | `string` | `4` | Cap on the number of consequential structural decisions surfaced in the review brief's decision surface (the working-memory limit). Default 4; clamped to the 3-5 band (4 plus or minus 1). Only consulted on the brief path |
834
+ | `--walkthrough-guide` | `bool` | `false` | Emit the agent-contract WALKTHROUGH GUIDE: the current digest (brief + decision surface), the review direction, the JSON schema the agent must return, and a deterministic graph-snapshot hash pinned into the digest. The digest is built from the graph only (PR prose is never folded in, so it is injection-resistant). Implies the brief; always exits 0. A thin agent skill calls this to fetch the current guide, produces judgment JSON, then reopens with `--walkthrough-file` |
835
+ | `--walkthrough-file` | `string` | - | Ingest an agent's judgment JSON and POST-VALIDATE it against the LIVE graph. Rejects any judgment whose `signal_id` fallow did not emit (anti-hallucination); refuses the whole payload as stale when the echoed graph-snapshot hash no longer matches (the tree moved). The verifier is the graph, not a second model. Implies the brief; always exits 0. The agent's free-text framing is fenced as non-deterministic and never gates or auto-posts |
836
+ | `--show-deprioritized` | `bool` | `false` | Expand the de-prioritized units in the review brief's weighted focus map ("show me what you de-prioritized"). The `deprioritized` escape-hatch list is ALWAYS present in `--format json` regardless; this flag only re-expands the collapse-by-default human focus render. Only consulted on the brief path |
831
837
 
832
838
  Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#global-flags), [`--changed-since`](#global-flags), [`--diff-file`](#global-flags), [`--diff-stdin`](#global-flags), [`--workspace`](#global-flags), [`--changed-workspaces`](#global-flags), [`--group-by`](#global-flags), [`--output-file`](#global-flags).
833
839
  <!-- generated:flags:audit:end -->
@@ -892,7 +898,7 @@ fallow audit \
892
898
  {
893
899
  "kind": "audit",
894
900
  "schema_version": 7,
895
- "version": "2.101.0",
901
+ "version": "2.102.0",
896
902
  "command": "audit",
897
903
  "verdict": "fail",
898
904
  "changed_files_count": 12,
@@ -967,7 +973,7 @@ fallow flags --format json --quiet --workspace my-package
967
973
  ```json
968
974
  {
969
975
  "schema_version": 7,
970
- "version": "2.101.0",
976
+ "version": "2.102.0",
971
977
  "elapsed_ms": 116,
972
978
  "feature_flags": [],
973
979
  "total_flags": 0
@@ -1067,7 +1073,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1067
1073
  {
1068
1074
  "kind": "security",
1069
1075
  "schema_version": "4",
1070
- "version": "2.101.0",
1076
+ "version": "2.102.0",
1071
1077
  "elapsed_ms": 42,
1072
1078
  "config": {
1073
1079
  "rules": {
@@ -1096,7 +1102,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1096
1102
  {
1097
1103
  "kind": "security",
1098
1104
  "schema_version": "4",
1099
- "version": "2.101.0",
1105
+ "version": "2.102.0",
1100
1106
  "elapsed_ms": 42,
1101
1107
  "config": {
1102
1108
  "rules": {
@@ -1762,7 +1768,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1762
1768
  {
1763
1769
  "kind": "dead-code",
1764
1770
  "schema_version": 7,
1765
- "version": "2.101.0",
1771
+ "version": "2.102.0",
1766
1772
  "elapsed_ms": 45,
1767
1773
  "total_issues": 12,
1768
1774
  "entry_points": {
@@ -1922,7 +1928,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1922
1928
  {
1923
1929
  "kind": "dupes",
1924
1930
  "schema_version": 7,
1925
- "version": "2.101.0",
1931
+ "version": "2.102.0",
1926
1932
  "elapsed_ms": 82,
1927
1933
  "total_clones": 15,
1928
1934
  "total_lines_duplicated": 230,
@@ -1966,11 +1972,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1966
1972
  {
1967
1973
  "kind": "combined",
1968
1974
  "schema_version": 7,
1969
- "version": "2.101.0",
1975
+ "version": "2.102.0",
1970
1976
  "elapsed_ms": 159,
1971
1977
  "check": {
1972
1978
  "schema_version": 7,
1973
- "version": "2.101.0",
1979
+ "version": "2.102.0",
1974
1980
  "elapsed_ms": 45,
1975
1981
  "total_issues": 12,
1976
1982
  "unused_files": [],
@@ -85,6 +85,12 @@ kind: "security-blind-spots"
85
85
  kind: "dead-code"
86
86
  }) | (CombinedOutput & {
87
87
  kind: "combined"
88
+ }) | (ReviewBriefOutput & {
89
+ kind: "audit-brief"
90
+ }) | (WalkthroughGuide & {
91
+ kind: "review-walkthrough-guide"
92
+ }) | (WalkthroughValidation & {
93
+ kind: "review-walkthrough-validation"
88
94
  }))
89
95
  /**
90
96
  * Schema version for this output format (independent of tool version). Bump
@@ -763,6 +769,44 @@ export type SecurityVerifierVerdictStatus = ("survivor" | "dismissed" | "needs-h
763
769
  * The `fallow security blind-spots --format json` schema version.
764
770
  */
765
771
  export type SecurityBlindSpotsSchemaVersion = "1"
772
+ /**
773
+ * Independently-versioned wire-version newtype for the brief envelope.
774
+ * Serializes as the integer `REVIEW_BRIEF_SCHEMA_VERSION`.
775
+ */
776
+ export type ReviewBriefSchemaVersion = number
777
+ /**
778
+ * Coarse risk classification for a changeset, a pure function of the change
779
+ * size (file count plus, once threaded, net lines).
780
+ */
781
+ export type RiskClass = ("low" | "medium" | "high")
782
+ /**
783
+ * Suggested reviewer effort, a pure function of [`RiskClass`].
784
+ */
785
+ export type ReviewEffort = ("glance" | "review" | "deep_dive")
786
+ /**
787
+ * The focus label for a review unit. EXACTLY two variants: `Skip` is NOT
788
+ * representable, so the type system is the guarantee that free mode never emits
789
+ * a `skip` label (safe explicit-skip is paid, runtime-backed only). Mirrors
790
+ * the decision surface's "cut category not representable" structural posture.
791
+ */
792
+ export type FocusLabel = ("review-here" | "not-prioritized")
793
+ /**
794
+ * A per-unit confidence flag. The EXACT panel-decided strings: a dynamically-
795
+ * wired or re-export-heavy unit carries one so its static-reachability signal is
796
+ * not trusted as complete (the anti-silent-de-prioritization guard). The flag
797
+ * NEVER lowers the score; it is advisory provenance.
798
+ */
799
+ export type ConfidenceFlag = ("dynamic-dispatch" | "re-export-indirection")
800
+ /**
801
+ * The category of a single weakening signal.
802
+ */
803
+ export type WeakeningKind = ("test-weakened" | "threshold-lowered" | "suppression-added" | "security-check-removed")
804
+ /**
805
+ * The exactly-three shippable decision categories (the SOLID-3). No cut category
806
+ * (abstraction / deletion / convention / irreversibility) is representable: this
807
+ * enum is the structural guarantee that confirmed-noise categories never ship.
808
+ */
809
+ export type DecisionCategory = ("coupling-boundary" | "public-api-contract" | "dependency")
766
810
  /**
767
811
  * Discriminator value for [`CodeClimateIssue::kind`].
768
812
  */
@@ -2882,11 +2926,15 @@ export interface UnrenderedComponentFinding {
2882
2926
  */
2883
2927
  path: string
2884
2928
  /**
2885
- * The component name (the `.vue`/`.svelte` file stem, PascalCase).
2929
+ * The component name. For `"vue"` / `"svelte"` / `"astro"` this is the SFC
2930
+ * file stem (PascalCase); for `"angular"` it is the component class name; for
2931
+ * `"lit"` it is the registered custom-element TAG (e.g. `x-foo`), not a file
2932
+ * stem. Use `path` to anchor the file across all frameworks.
2886
2933
  */
2887
2934
  component_name: string
2888
2935
  /**
2889
- * Which framework this component belongs to: `"vue"` or `"svelte"`.
2936
+ * Which framework this component belongs to: `"vue"`, `"svelte"`, `"astro"`,
2937
+ * `"angular"`, or `"lit"`.
2890
2938
  */
2891
2939
  framework: string
2892
2940
  /**
@@ -6453,6 +6501,14 @@ dead_code: InspectEvidenceSection
6453
6501
  duplication: InspectEvidenceSection
6454
6502
  complexity: InspectEvidenceSection
6455
6503
  security: InspectEvidenceSection
6504
+ impact_closure: InspectEvidenceSection
6505
+ /**
6506
+ * OPT-IN symbol-level call chain. Present only when `--symbol-chain` was
6507
+ * requested AND the target is a SYMBOL (best-effort, syntactic, OFF the
6508
+ * ranked path). `None` (omitted) by default: symbol-level chains are
6509
+ * best-effort and not part of the trusted ranked evidence.
6510
+ */
6511
+ symbol_chain?: (InspectEvidenceSection | null)
6456
6512
  }
6457
6513
  export interface InspectEvidenceSection {
6458
6514
  status: InspectSectionStatus
@@ -8439,6 +8495,659 @@ dupes?: (Meta | null)
8439
8495
  health?: (Meta | null)
8440
8496
  telemetry?: (TelemetryMeta | null)
8441
8497
  }
8498
+ /**
8499
+ * The full `fallow audit --brief --format json` envelope. Carries the
8500
+ * informational verdict, the triage and graph-facts orientation stages, plus
8501
+ * the reused "subtract" section (the same dead-code / duplication / complexity
8502
+ * payload `fallow audit --format json` emits).
8503
+ */
8504
+ export interface ReviewBriefOutput {
8505
+ schema_version: ReviewBriefSchemaVersion
8506
+ /**
8507
+ * Fallow CLI version that produced this output.
8508
+ */
8509
+ version: string
8510
+ /**
8511
+ * Command discriminator singleton: always `"audit-brief"`.
8512
+ */
8513
+ command: string
8514
+ triage: DiffTriage
8515
+ graph_facts: GraphFacts
8516
+ partition: PartitionFacts
8517
+ impact_closure: ImpactClosureFacts
8518
+ focus: FocusMap
8519
+ deltas: ReviewDeltas
8520
+ /**
8521
+ * 6.F, headline: reviewer-private weakening signals (tests
8522
+ * removed/skipped, thresholds lowered, suppressions added, security steps
8523
+ * removed). Advisory, never gates, never auto-posted.
8524
+ */
8525
+ weakening: WeakeningSignal[]
8526
+ routing: RoutingFacts
8527
+ decisions: DecisionSurface
8528
+ }
8529
+ /**
8530
+ * Stage 0 of the brief: triage facts derived purely from the diff size.
8531
+ *
8532
+ * `hunks` and `net_lines` are `None` in v1: the file-level audit does not yet
8533
+ * thread a `DiffIndex` (from `report/ci/diff_filter.rs`). They populate later,
8534
+ * on `--diff-file` / `--diff-stdin`, without a schema bump.
8535
+ */
8536
+ export interface DiffTriage {
8537
+ /**
8538
+ * Number of changed files in the audit scope.
8539
+ */
8540
+ files: number
8541
+ /**
8542
+ * Number of diff hunks. `None` in v1 (no diff index threaded yet).
8543
+ */
8544
+ hunks?: (number | null)
8545
+ /**
8546
+ * Net added-minus-removed lines. `None` in v1 (no diff index threaded yet).
8547
+ */
8548
+ net_lines?: (number | null)
8549
+ risk_class: RiskClass
8550
+ review_effort: ReviewEffort
8551
+ }
8552
+ /**
8553
+ * Stage 1 of the brief: graph-derived orientation facts.
8554
+ *
8555
+ * `boundaries_touched` is derived from the run's boundary-violation zones;
8556
+ * `reachable_from` is populated by the impact closure (the affected-not-shown
8557
+ * set: modules the changed code is reachable from / affects, none in the diff).
8558
+ * `exports_added` / `api_width_delta` stay honestly stubbed (`0`) until the
8559
+ * export-surface delta lands. The fields are present and correctly typed so
8560
+ * values fill in later without a schema bump.
8561
+ */
8562
+ export interface GraphFacts {
8563
+ /**
8564
+ * Number of exports added by the changeset. Stubbed to `0` in v1.
8565
+ */
8566
+ exports_added: number
8567
+ /**
8568
+ * Change in public API width (added minus removed exports). Stubbed to `0`
8569
+ * in v1.
8570
+ */
8571
+ api_width_delta: number
8572
+ /**
8573
+ * Root-relative paths of modules the changed code is reachable from / affects
8574
+ * (the impact closure's affected-but-not-in-diff set), deduped and sorted.
8575
+ * Empty when no graph was retained or nothing depends on the changed files.
8576
+ */
8577
+ reachable_from: string[]
8578
+ /**
8579
+ * Architecture boundary zones touched by the changeset, deduped and sorted.
8580
+ * Derived from the run's boundary-violation findings.
8581
+ */
8582
+ boundaries_touched: string[]
8583
+ }
8584
+ /**
8585
+ * Stage 2 of the brief: the partition + order. The changed files split into
8586
+ * coherent BY-MODULE units (the only byte-identical-deterministic clustering
8587
+ * definition straight from the graph), plus a dependency-sensible review ORDER
8588
+ * over those units (definitions before consumers, mechanical/leaf units last,
8589
+ * ties broken by the path sort). Stage 2 sits UNDER the decision surface as a
8590
+ * drill-down; it is the backbone the directed-review loop hands the agent.
8591
+ *
8592
+ * Feature-cluster and concern partitioning are deferred (they need scoring
8593
+ * heuristics whose tie-breaks are a fresh nondeterminism surface).
8594
+ */
8595
+ export interface PartitionFacts {
8596
+ /**
8597
+ * The by-module units, sorted by module directory. Empty when no graph was
8598
+ * retained or no changed file maps to a known module.
8599
+ */
8600
+ units: ReviewUnitFact[]
8601
+ /**
8602
+ * The dependency-sensible review order: module-directory strings,
8603
+ * definitions before consumers, mechanical/leaf units last. A permutation of
8604
+ * the `units` module directories.
8605
+ */
8606
+ order: string[]
8607
+ }
8608
+ /**
8609
+ * One review unit: a coherent by-module cluster of the changed set.
8610
+ */
8611
+ export interface ReviewUnitFact {
8612
+ /**
8613
+ * The module directory the unit covers (root-relative, forward-slashed).
8614
+ * The empty string is the repository-root group.
8615
+ */
8616
+ module_dir: string
8617
+ /**
8618
+ * The changed files in this unit, path-sorted.
8619
+ */
8620
+ files: string[]
8621
+ }
8622
+ /**
8623
+ * Stage 3 of the brief: the impact closure. The transitive
8624
+ * affected-but-not-in-diff set plus the coordination gap. The differentiator a
8625
+ * diff tool fundamentally cannot do, because it has no graph.
8626
+ *
8627
+ * Honest scope (ADR-001, syntactic): the coordination gap is an attention
8628
+ * pointer at the exact inter-module failure mode, NOT a correctness proof.
8629
+ */
8630
+ export interface ImpactClosureFacts {
8631
+ /**
8632
+ * Root-relative paths transitively affected by the changeset (reverse-deps +
8633
+ * re-export chains) that are NOT in the diff, deduped and sorted.
8634
+ */
8635
+ affected_not_shown: string[]
8636
+ /**
8637
+ * Coordination gaps: a changed file exports a contract consumed by a module
8638
+ * absent from the diff. One entry per (changed file, consumer) pair.
8639
+ */
8640
+ coordination_gap: CoordinationGapFact[]
8641
+ }
8642
+ /**
8643
+ * One coordination-gap entry: a changed file exports symbols consumed by a
8644
+ * `consumer_file` that is NOT in the diff. Deduped per (changed, consumer) pair
8645
+ * (firing-precision rule R2).
8646
+ */
8647
+ export interface CoordinationGapFact {
8648
+ /**
8649
+ * Root-relative path of the changed file whose contract is consumed elsewhere.
8650
+ */
8651
+ changed_file: string
8652
+ /**
8653
+ * Root-relative path of the consumer module that is NOT in the diff.
8654
+ */
8655
+ consumer_file: string
8656
+ /**
8657
+ * The exported symbol names the consumer references, sorted.
8658
+ */
8659
+ consumed_symbols: string[]
8660
+ /**
8661
+ * Honest scope note: this is a syntactic attention pointer, not a proof.
8662
+ */
8663
+ note: string
8664
+ }
8665
+ /**
8666
+ * The weighted focus map: the ranked `review-here` units plus the FULL
8667
+ * `deprioritized` escape-hatch list, so nothing is hidden.
8668
+ *
8669
+ * Completeness invariant (the escape-hatch done-condition): the two lists
8670
+ * partition the unit set, so `review_here.len() + deprioritized.len()` equals
8671
+ * the total unit count by construction.
8672
+ */
8673
+ export interface FocusMap {
8674
+ /**
8675
+ * Units labeled `review-here`, ranked by composite score (descending), ties
8676
+ * broken by path for determinism.
8677
+ */
8678
+ review_here: FocusUnit[]
8679
+ /**
8680
+ * EVERY `not-prioritized` unit (the escape hatch). Always present and fully
8681
+ * enumerated so a reviewer can always "show me what you de-prioritized"; the
8682
+ * human brief collapses it by default and re-expands under
8683
+ * `--show-deprioritized`.
8684
+ */
8685
+ deprioritized: FocusUnit[]
8686
+ }
8687
+ /**
8688
+ * One review unit on the focus map: its file, composite score, label, human
8689
+ * reason, and any confidence flags.
8690
+ */
8691
+ export interface FocusUnit {
8692
+ /**
8693
+ * Root-relative path of the changed file this unit covers.
8694
+ */
8695
+ file: string
8696
+ score: FocusScore
8697
+ label: FocusLabel
8698
+ /**
8699
+ * A human-readable reason for the label, built from the present signals.
8700
+ */
8701
+ reason: string
8702
+ /**
8703
+ * Confidence flags (advisory; never lower the score). Sorted, deduped.
8704
+ */
8705
+ confidence?: ConfidenceFlag[]
8706
+ }
8707
+ /**
8708
+ * The composite attention score, with the four deterministic component
8709
+ * sub-scores kept on the wire so the runtime seam can re-weight `total`
8710
+ * without recomputing the signals.
8711
+ */
8712
+ export interface FocusScore {
8713
+ /**
8714
+ * Fan-in/out blast-radius component.
8715
+ */
8716
+ fan_io: number
8717
+ /**
8718
+ * Security source -> sink taint-touch component (0 until a security pass is
8719
+ * threaded onto the brief path; the seam is built and tested).
8720
+ */
8721
+ security_taint: number
8722
+ /**
8723
+ * Risk-zone component (boundary / public-API / security-sensitive).
8724
+ */
8725
+ risk_zone: number
8726
+ /**
8727
+ * Change-shape component (new/widened export, signature change proxy).
8728
+ */
8729
+ change_shape: number
8730
+ /**
8731
+ * The summed total. The paid runtime layer multiplies a runtime hot/cold weight in here.
8732
+ */
8733
+ total: number
8734
+ }
8735
+ /**
8736
+ * Diff-aware deterministic deltas (6.A), framed new-vs-pre-existing against
8737
+ * the audit base snapshot. Each entry is a brief summary/verdict line.
8738
+ *
8739
+ * `public_api` is batch-consolidated to ONE decision per change (rule R1):
8740
+ * the `added` list carries the introduced public-export keys as evidence, but a
8741
+ * reviewer reads "the public surface widened by N", never one decision per
8742
+ * symbol.
8743
+ */
8744
+ export interface ReviewDeltas {
8745
+ /**
8746
+ * Cross-zone boundary EDGES introduced vs base (R2 first-edge-only: one per
8747
+ * `<from_zone>-><to_zone>` pair, never per import). New-vs-pre-existing.
8748
+ */
8749
+ boundary_introduced: string[]
8750
+ /**
8751
+ * Circular dependencies introduced vs base (canonical file-set keys).
8752
+ */
8753
+ cycle_introduced: string[]
8754
+ /**
8755
+ * Exports-aware public-API surface delta: the public-export keys
8756
+ * (`<rel_path>::<name>`) added vs base, resolved through `package.json`
8757
+ * `exports` + re-export reachability. A symbol re-exported only through an
8758
+ * internal barrel NOT in `exports` is absent here (zero delta); one
8759
+ * reachable through an `exports` path is present (exactly one).
8760
+ */
8761
+ public_api_added: string[]
8762
+ }
8763
+ /**
8764
+ * One weakening signal: a category, the file it was detected in, and a short
8765
+ * human-readable evidence string. Reviewer-private; never gates.
8766
+ */
8767
+ export interface WeakeningSignal {
8768
+ kind: WeakeningKind
8769
+ /**
8770
+ * Root-relative path of the changed file the signal was detected in.
8771
+ */
8772
+ file: string
8773
+ /**
8774
+ * Short evidence string (e.g. the offending token or the threshold delta).
8775
+ */
8776
+ evidence: string
8777
+ }
8778
+ /**
8779
+ * The full routing section: one unit per changed source file with a routable
8780
+ * signal. Files with no ownership signal are omitted (no noise).
8781
+ */
8782
+ export interface RoutingFacts {
8783
+ /**
8784
+ * Per-changed-file routing units, sorted by file path.
8785
+ */
8786
+ units: RoutingUnit[]
8787
+ }
8788
+ /**
8789
+ * One routed unit (a changed file) with its experts and bus-factor flag.
8790
+ */
8791
+ export interface RoutingUnit {
8792
+ /**
8793
+ * Root-relative path of the changed file.
8794
+ */
8795
+ file: string
8796
+ /**
8797
+ * The routed expert(s): the CODEOWNERS declared owner when present, else the
8798
+ * top git-blame / recency contributor; empty when no signal is available.
8799
+ */
8800
+ expert: string[]
8801
+ /**
8802
+ * Whether the only qualified owner is a single contributor (bus-factor-1):
8803
+ * a knowledge-concentration risk worth a second reviewer.
8804
+ */
8805
+ bus_factor_one?: boolean
8806
+ }
8807
+ /**
8808
+ * The ranked, capped decision surface plus the set of signal_ids the
8809
+ * deterministic layer emitted (the anti-hallucination allowlist).
8810
+ */
8811
+ export interface DecisionSurface {
8812
+ /**
8813
+ * Up to `cap` ranked decisions, highest consequence first.
8814
+ */
8815
+ decisions: Decision[]
8816
+ /**
8817
+ * Present when more than `cap` decisions were extracted.
8818
+ */
8819
+ truncated?: (TruncationNote | null)
8820
+ /**
8821
+ * Every signal_id the deterministic layer emitted, INCLUDING those whose
8822
+ * decision was collapsed below the cap or suppressed. The anti-hallucination
8823
+ * allowlist: an agent decision whose id is absent is rejected.
8824
+ */
8825
+ emitted_signal_ids: string[]
8826
+ }
8827
+ /**
8828
+ * One consequential structural decision, framed as a judgment question for a
8829
+ * human with taste, anchored to a fallow-emitted signal.
8830
+ */
8831
+ export interface Decision {
8832
+ /**
8833
+ * Deterministic anchor to the fallow-emitted candidate this decision frames.
8834
+ * `accept_signal_id` rejects any id not in the emitted set.
8835
+ */
8836
+ signal_id: string
8837
+ category: DecisionCategory
8838
+ /**
8839
+ * The decision framed as a judgment question for the human.
8840
+ */
8841
+ question: string
8842
+ /**
8843
+ * Root-relative file the decision is anchored at (for suppression + routing).
8844
+ */
8845
+ anchor_file: string
8846
+ /**
8847
+ * 1-based anchor line, when the underlying signal carries one (0 = file head).
8848
+ */
8849
+ anchor_line: number
8850
+ /**
8851
+ * The raw fallow-emitted candidate key the `signal_id` hashes (the evidence).
8852
+ */
8853
+ signal_key: string
8854
+ /**
8855
+ * The `signal_id` this decision WOULD have had before any rename in this
8856
+ * change (the anchor file's pre-rename path). Present only when the anchor was
8857
+ * renamed. A review-memory layer carries a dismissal across a `git mv`: if
8858
+ * `previous_signal_id` was dismissed in an earlier PR, treat this decision as
8859
+ * dismissed too. Keeps `signal_id` itself exact + deterministic.
8860
+ */
8861
+ previous_signal_id?: (string | null)
8862
+ /**
8863
+ * Blast radius: count of modules affected beyond the diff by this decision.
8864
+ */
8865
+ blast: number
8866
+ /**
8867
+ * `blast * reversibility_weight`: the rank key (sorted descending).
8868
+ */
8869
+ consequence: number
8870
+ /**
8871
+ * The routed expert(s) to ask, from ownership routing. Empty when no
8872
+ * ownership signal is available for the anchor file.
8873
+ */
8874
+ expert: string[]
8875
+ /**
8876
+ * Whether the anchor file's only qualified owner is one person (bus-factor-1).
8877
+ */
8878
+ bus_factor_one?: boolean
8879
+ /**
8880
+ * Honest per-decision count: in-repo modules OUTSIDE the diff that already
8881
+ * depend on this decision's anchor. This is the DISPLAY number (taste
8882
+ * ownership: the human reads reversibility from the count itself), distinct
8883
+ * from `blast` (the project-wide proxy used only for ranking). Never a door
8884
+ * label. Internal-only by construction, so it cannot see a published library's
8885
+ * external consumers; the public-API trade-off clause names that risk in prose.
8886
+ */
8887
+ internal_consumer_count: number
8888
+ /**
8889
+ * The named structural sacrifice this change makes, stated as a fact, never a
8890
+ * recommendation (e.g. "Couples `app` to `infra`; 4 in-repo modules already
8891
+ * depend on this anchor."). A sibling fact to `question`; it never tells the
8892
+ * human what to choose.
8893
+ */
8894
+ tradeoff: string
8895
+ }
8896
+ /**
8897
+ * A note for the decisions collapsed below the cap.
8898
+ */
8899
+ export interface TruncationNote {
8900
+ /**
8901
+ * How many decisions were collapsed below the cap.
8902
+ */
8903
+ collapsed: number
8904
+ /**
8905
+ * Human-readable collapse reason.
8906
+ */
8907
+ reason: string
8908
+ }
8909
+ /**
8910
+ * The `fallow review --walkthrough-guide` envelope: the current digest + schema
8911
+ * the agent fetches. The tool owns this; the skill stays thin (it fetches this
8912
+ * rather than embedding a frozen copy). Always emitted with exit 0.
8913
+ */
8914
+ export interface WalkthroughGuide {
8915
+ schema_version: ReviewBriefSchemaVersion
8916
+ /**
8917
+ * Fallow CLI version that produced this guide.
8918
+ */
8919
+ version: string
8920
+ /**
8921
+ * Command discriminator singleton: always `"review-walkthrough-guide"`.
8922
+ */
8923
+ command: string
8924
+ /**
8925
+ * The deterministic graph-snapshot hash pinned into the digest. The agent
8926
+ * echoes it back; a mismatch on reentry refuses the payload as stale.
8927
+ */
8928
+ graph_snapshot_hash: string
8929
+ digest: ReviewBriefOutput
8930
+ direction: ReviewDirection
8931
+ /**
8932
+ * The per-hunk change anchors: one stable id per changed region. An agent
8933
+ * may cite a `change_anchor` as a judgment anchor in addition to an emitted
8934
+ * `signal_id`, so a trade-off about a changed region with no graph finding
8935
+ * can still anchor (and be post-validated) rather than hallucinate.
8936
+ */
8937
+ change_anchors: ChangeAnchor[]
8938
+ agent_schema: AgentSchema
8939
+ /**
8940
+ * The injection-resistance note (digest is graph-only; PR prose untrusted).
8941
+ */
8942
+ injection_note: string
8943
+ }
8944
+ /**
8945
+ * The review direction artifact: the order to review in, the coherent units,
8946
+ * and per-unit concern lens + out-of-diff + expert. A minimal projection of the
8947
+ * EXISTING graph facts (routing units + impact closure); the full weighted-focus
8948
+ * engine is a later epic. Graph-derived only (injection-resistant).
8949
+ */
8950
+ export interface ReviewDirection {
8951
+ /**
8952
+ * The dependency-sensible review order: unit file paths, units carrying
8953
+ * out-of-diff consumers first (review the load-bearing definitions before
8954
+ * the mechanical units).
8955
+ */
8956
+ order: string[]
8957
+ /**
8958
+ * The coherent review units, in `order`.
8959
+ */
8960
+ units: DirectionUnit[]
8961
+ }
8962
+ /**
8963
+ * One directed review unit projected from the graph: a file the change touches,
8964
+ * the concern to check, the out-of-diff consumers it must account for, and the
8965
+ * routed expert. Graph-derived only (routing + impact closure), NEVER from prose.
8966
+ */
8967
+ export interface DirectionUnit {
8968
+ /**
8969
+ * Root-relative path of the unit to review.
8970
+ */
8971
+ file: string
8972
+ /**
8973
+ * The concern lens the agent should check for this unit, derived from the
8974
+ * unit's risk signals (impact-closure consumers vs a plain touched file).
8975
+ */
8976
+ concern_lens: string
8977
+ /**
8978
+ * Per-unit review-effort budget: the weighted-focus composite score for
8979
+ * this file. A cloud fan-out spends AI passes/verifiers PROPORTIONAL to this
8980
+ * (higher = review harder); a local single-agent loop can ignore it.
8981
+ */
8982
+ scoring_budget: number
8983
+ /**
8984
+ * Root-relative paths of modules affected by this unit but NOT in the diff
8985
+ * (the out-of-diff context the agent must reason about).
8986
+ */
8987
+ out_of_diff: string[]
8988
+ /**
8989
+ * The routed expert(s) to ask, from ownership routing.
8990
+ */
8991
+ expert: string[]
8992
+ }
8993
+ /**
8994
+ * One stable per-hunk CHANGE ANCHOR: a changed region the agent may cite as a
8995
+ * judgment anchor IN ADDITION to a `signal_id`. Where a `signal_id` anchors a
8996
+ * graph FINDING ("fallow emitted this exact finding"), a change_anchor anchors
8997
+ * only a changed REGION ("fallow confirms this region changed") , a strictly
8998
+ * weaker guarantee, surfaced as `anchor_kind` on the accepted judgment so a
8999
+ * consumer can tell the two apart. Graph/diff-derived; NEVER from prose.
9000
+ */
9001
+ export interface ChangeAnchor {
9002
+ /**
9003
+ * Stable, CONTENT-addressed id: `chg:<16-hex>` over the file path + the
9004
+ * normalized added text (line numbers are NOT hashed, so an edit above the
9005
+ * hunk or a whitespace-only change does not move the id).
9006
+ */
9007
+ change_anchor: string
9008
+ /**
9009
+ * Root-relative path of the changed file.
9010
+ */
9011
+ file: string
9012
+ /**
9013
+ * 1-based first line of the hunk in the head file (display/deep-link only;
9014
+ * NOT part of the id).
9015
+ */
9016
+ start_line: number
9017
+ /**
9018
+ * Number of added lines in the hunk (display only; NOT part of the id).
9019
+ */
9020
+ line_count: number
9021
+ /**
9022
+ * Rename-durable anchor: the id this same hunk would have had under the
9023
+ * pre-rename path. `None` unless the file was renamed in this change, so an
9024
+ * agent that cited the anchor before a `git mv` still resolves.
9025
+ */
9026
+ previous_change_anchor?: (string | null)
9027
+ }
9028
+ /**
9029
+ * The shape the agent must return, embedded in the guide so a thin skill needs
9030
+ * no frozen copy. Documents the anchoring + staleness contract in the wire.
9031
+ */
9032
+ export interface AgentSchema {
9033
+ /**
9034
+ * How the agent must structure each judgment: cite an emitted `signal_id`,
9035
+ * add free-text `framing` (non-deterministic, fenced), an optional `concern`.
9036
+ */
9037
+ judgment_shape: string
9038
+ /**
9039
+ * The agent MUST echo this `graph_snapshot_hash` back in its JSON; a
9040
+ * mismatch on reentry REFUSES the payload as stale.
9041
+ */
9042
+ echo_field: string
9043
+ /**
9044
+ * The constant naming the anti-hallucination rule.
9045
+ */
9046
+ anchoring_rule: string
9047
+ }
9048
+ /**
9049
+ * The `fallow review --walkthrough-file` validation envelope: the result of
9050
+ * post-validating the agent's judgment against the live graph. Always exit 0.
9051
+ */
9052
+ export interface WalkthroughValidation {
9053
+ schema_version: ReviewBriefSchemaVersion
9054
+ /**
9055
+ * Fallow CLI version that produced this validation.
9056
+ */
9057
+ version: string
9058
+ /**
9059
+ * Command discriminator singleton: always `"review-walkthrough-validation"`.
9060
+ */
9061
+ command: string
9062
+ /**
9063
+ * The current run's deterministic graph-snapshot hash.
9064
+ */
9065
+ graph_snapshot_hash: string
9066
+ /**
9067
+ * `true` when the agent's echoed hash != the current hash (the tree moved):
9068
+ * the WHOLE payload is refused, `accepted` is empty.
9069
+ */
9070
+ stale: boolean
9071
+ /**
9072
+ * Judgments that cite a real fallow-emitted signal, framing fenced.
9073
+ */
9074
+ accepted: AcceptedJudgment[]
9075
+ /**
9076
+ * Judgments rejected (unanchored signal id, or all-rejected when stale).
9077
+ */
9078
+ rejected: RejectedJudgment[]
9079
+ /**
9080
+ * Count of accepted judgments.
9081
+ */
9082
+ accepted_count: number
9083
+ /**
9084
+ * Count of rejected judgments.
9085
+ */
9086
+ rejected_count: number
9087
+ /**
9088
+ * Count of accepted judgments whose `signal_id` resolved against the live
9089
+ * allowlist. Zero unanchored when this equals `accepted_count` and there are
9090
+ * no rejections (the clean done-condition).
9091
+ */
9092
+ unanchored_count: number
9093
+ }
9094
+ /**
9095
+ * One accepted judgment: the real anchored signal passed through with the
9096
+ * agent's framing FENCED as non-deterministic.
9097
+ */
9098
+ export interface AcceptedJudgment {
9099
+ /**
9100
+ * The fallow-emitted `signal_id` (verified against the allowlist). Empty
9101
+ * when this judgment was anchored by a `change_anchor` instead.
9102
+ */
9103
+ signal_id: string
9104
+ /**
9105
+ * The fallow-emitted `change_anchor` (verified against the allowlist). Empty
9106
+ * when this judgment was anchored by a `signal_id`.
9107
+ */
9108
+ change_anchor: string
9109
+ /**
9110
+ * Which anchor resolved: `"signal"` (a graph FINDING, the strong anchor) or
9111
+ * `"change"` (a changed REGION only, the weaker anchor). Lets a consumer
9112
+ * distinguish a finding-anchored judgment from a region-anchored one rather
9113
+ * than collapsing both into one accepted bucket.
9114
+ */
9115
+ anchor_kind: string
9116
+ /**
9117
+ * The agent's framing, FENCED: this is non-deterministic agent prose.
9118
+ */
9119
+ agent_framing: string
9120
+ /**
9121
+ * The agent's optional concern category (advisory).
9122
+ */
9123
+ concern?: (string | null)
9124
+ /**
9125
+ * Hard fence: always `false`. The framing is agent prose, never a
9126
+ * deterministic fallow result, so it never gates or auto-posts.
9127
+ */
9128
+ deterministic: boolean
9129
+ }
9130
+ /**
9131
+ * One rejected judgment plus the reason it was rejected.
9132
+ */
9133
+ export interface RejectedJudgment {
9134
+ /**
9135
+ * The `signal_id` the agent cited (fallow never emitted it). Empty when the
9136
+ * judgment cited a `change_anchor` instead.
9137
+ */
9138
+ signal_id: string
9139
+ /**
9140
+ * The `change_anchor` the agent cited (fallow never emitted it). Empty when
9141
+ * the judgment cited a `signal_id` instead.
9142
+ */
9143
+ change_anchor: string
9144
+ /**
9145
+ * The rejection reason: `unanchored-signal-id` (cited a signal fallow did
9146
+ * not emit), `unknown-change-anchor` (cited a region fallow did not emit),
9147
+ * or `stale-snapshot` (the tree moved).
9148
+ */
9149
+ reason: string
9150
+ }
8442
9151
  /**
8443
9152
  * Single CodeClimate-compatible issue inside [`CodeClimateOutput`].
8444
9153
  */