fallow 3.22.0 → 3.24.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.
@@ -24,7 +24,7 @@
24
24
 
25
25
 
26
26
  /**
27
- * Schemas for the JSON output of fallow commands. Object-shaped envelopes covered by the `FallowOutput` contract carry a top-level `kind` discriminator. Current kind values: `audit`, `explain`, `inspect_target`, `trace`, `review-envelope`, `review-reconcile`, `coverage-setup`, `coverage-analyze`, `list-boundaries`, `list-workspaces`, `health`, `dupes`, `dead-code-grouped`, `impact`, `impact-cross-repo`, `security`, `security-survivors`, `security-blind-spots`, `dead-code`, `combined`, `feature-flags`, `audit-brief`, `decision-surface`, `review-walkthrough-guide`, `review-walkthrough-validation`, `suppression-inventory`, `type-aware-status`, `similar-code`, `similar-code-inspect`, `similar-code-review`. Consumers should branch on `kind` instead of probing for unique field presence. `CodeClimateOutput` is a bare JSON array (per the Code Climate / GitLab Code Quality spec) and stays a sibling root branch discriminated by checking whether the document root is an array. `ErrorOutput` is the `--format json` failure document, emitted on stdout with a non-zero exit; it carries no `kind` and is discriminated by the `error: true` field.
27
+ * Schemas for the JSON output of fallow commands. Object-shaped envelopes covered by the `FallowOutput` contract carry a top-level `kind` discriminator. Current kind values: `audit`, `explain`, `inspect_target`, `trace`, `trace-error`, `review-envelope`, `review-reconcile`, `coverage-setup`, `coverage-analyze`, `list-boundaries`, `list-workspaces`, `health`, `dupes`, `dead-code-grouped`, `impact`, `impact-cross-repo`, `security`, `security-survivors`, `security-blind-spots`, `dead-code`, `combined`, `feature-flags`, `audit-brief`, `decision-surface`, `review-walkthrough-guide`, `review-walkthrough-validation`, `suppression-inventory`, `doctor`, `type-aware-status`, `similar-code`, `similar-code-inspect`, `similar-code-review`. Consumers should branch on `kind` instead of probing for unique field presence. `CodeClimateOutput` is a bare JSON array (per the Code Climate / GitLab Code Quality spec) and stays a sibling root branch discriminated by checking whether the document root is an array. `ErrorOutput` is the `--format json` failure document, emitted on stdout with a non-zero exit; it carries no `kind` and is discriminated by the `error: true` field.
28
28
  */
29
29
  export type FallowJsonOutput = (FallowOutput | CodeClimateOutput | ErrorOutput)
30
30
  /**
@@ -50,8 +50,10 @@ kind: "audit"
50
50
  kind: "explain"
51
51
  }) | (InspectOutput & {
52
52
  kind: "inspect_target"
53
- }) | ((ExportTrace | ClassMemberTrace | FileTrace | DependencyTrace | CloneTrace | ImpactClosureTrace | SymbolChainTrace | SemanticSymbolTrace) & {
53
+ }) | ((ExportTrace | ClassMemberTrace | FileTrace | DependencyTrace | CloneTrace | ImpactClosureTrace | ImportPathTrace | SymbolChainTrace | SemanticSymbolTrace) & {
54
54
  kind: "trace"
55
+ }) | (ErrorTrace & {
56
+ kind: "trace-error"
55
57
  }) | (ReviewEnvelopeOutput & {
56
58
  kind: "review-envelope"
57
59
  }) | (ReviewReconcileOutput & {
@@ -96,6 +98,8 @@ kind: "review-walkthrough-guide"
96
98
  kind: "review-walkthrough-validation"
97
99
  }) | (SuppressionInventoryOutput & {
98
100
  kind: "suppression-inventory"
101
+ }) | (DoctorOutput & {
102
+ kind: "doctor"
99
103
  }) | (TypeAwareStatusOutput & {
100
104
  kind: "type-aware-status"
101
105
  }) | (SimilarCodeOutput & {
@@ -108,7 +112,7 @@ kind: "similar-code-review"
108
112
  /**
109
113
  * Schema projection for the audit envelope's exact version.
110
114
  */
111
- export type AuditSchemaVersion = 10
115
+ export type AuditSchemaVersion = 11
112
116
  /**
113
117
  * Fallow CLI version that produced this envelope. Renders to the JSON wire as
114
118
  * a bare string (e.g. `"2.74.0"`).
@@ -287,6 +291,30 @@ export type AddToConfigValue = (string | IgnoreExportsRule[] | {
287
291
  * hold `Option<AuditIntroduced>`. Renders to the JSON wire as a bare boolean.
288
292
  */
289
293
  export type AuditIntroduced = boolean
294
+ /**
295
+ * A per-finding caveat on a dead-code verdict that a file this run never
296
+ * fully analyzed can distort.
297
+ *
298
+ * Advisory provenance, in the same spirit as the fix path's
299
+ * `low_confidence_off_graph` / `low_confidence_unresolved_imports` skip
300
+ * reasons: a caveat NEVER withholds, reorders, downgrades, or re-severities
301
+ * the finding, and never changes an exit code. It records that the verdict
302
+ * was computed over an import graph fallow already knows is incomplete, so a
303
+ * reader who sees the finding also sees the caveat instead of having to
304
+ * notice a diagnostic at the other end of the envelope.
305
+ *
306
+ * Deliberately NOT named `confidence`: `health --targets` already emits a
307
+ * `confidence` key holding an enum string, and a shared consumer helper that
308
+ * met both would see the same key change type. Emitted on every finding type
309
+ * that registers it: the reachability arrays (`unused_files[]`,
310
+ * `unused_exports[]`, `unused_types[]`), the member arrays
311
+ * (`unused_enum_members[]`, `unused_class_members[]`, `unused_store_members[]`),
312
+ * and the three dependency arrays. Sorted and deduplicated, absent from the
313
+ * wire when empty. The set is open in the same sense
314
+ * `workspace_diagnostics[].kind` is: treat an unrecognised value as "some
315
+ * caveat" rather than as an error.
316
+ */
317
+ export type ReachabilityCaveat = ("incomplete-file-analysis" | "incomplete-import-graph")
290
318
  /**
291
319
  * Where in package.json a dependency is listed.
292
320
  *
@@ -450,11 +478,28 @@ kind: "skipped-source-dotdir"
450
478
  error: string
451
479
  kind: "source-read-failure"
452
480
  } | {
481
+ /**
482
+ * Number of parser diagnostics reported for the file.
483
+ */
484
+ error_count: number
485
+ /**
486
+ * `true` when the parser abandoned the file instead of recovering, so
487
+ * the extracted module is a fragment at best.
488
+ */
489
+ panicked: boolean
490
+ kind: "source-parse-degraded"
491
+ } | {
453
492
  kind: "bun-lockb-override-resolution-skipped"
454
493
  } | {
455
494
  kind: "bun-lock-override-resolution-skipped"
456
495
  } | {
457
496
  kind: "bun-resolutions-shadowed-by-overrides"
497
+ } | {
498
+ kind: "node-modules-missing"
499
+ } | {
500
+ kind: "boundaries-not-configured"
501
+ } | {
502
+ kind: "rule-packs-not-configured"
458
503
  })
459
504
  /**
460
505
  * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types
@@ -575,6 +620,14 @@ export type HotspotActionType = ("refactor-file" | "add-tests" | "low-bus-factor
575
620
  * an `unowned-hotspot` action.
576
621
  */
577
622
  export type HotspotActionHeuristic = "directory-deepest"
623
+ /**
624
+ * Where the run's reference epoch came from.
625
+ *
626
+ * Churn recency weighting and ownership staleness are measured against one
627
+ * instant. `head_commit` and `environment` resolve to the same value on every
628
+ * run over the same commit; `wall_clock` does not.
629
+ */
630
+ export type ClockSource = ("environment" | "head_commit" | "wall_clock")
578
631
  /**
579
632
  * Runtime coverage JSON contract version. This is scoped to the
580
633
  * `runtime_coverage` block and is independent of the top-level fallow
@@ -771,10 +824,37 @@ export type InspectSectionStatus = ("ok" | "partial" | "unavailable" | "error")
771
824
  * Granularity an [`InspectEvidenceSection`] payload covers.
772
825
  */
773
826
  export type InspectEvidenceScope = ("symbol" | "file" | "project_filtered_to_file")
827
+ /**
828
+ * Wire-version discriminator for [`ImportPathTrace`]. Independent from the
829
+ * global `SchemaVersion`: the import-path payload versions on its own cadence,
830
+ * like the other independently-versioned envelopes. Serializes as a string
831
+ * `const` so JSON consumers can switch on it.
832
+ */
833
+ export type ImportPathTraceSchemaVersion = "1"
774
834
  /**
775
835
  * Best-effort classification of why a callee did not resolve to an edge.
776
836
  */
777
837
  export type UnresolvedReason = ("local-or-global" | "member-or-dynamic")
838
+ /**
839
+ * Wire-version discriminator for [`ErrorTrace`]. Independent from the global
840
+ * `SchemaVersion` and from the other trace payloads, like
841
+ * [`crate::trace::ImportPathTraceSchemaVersion`]. Serializes as a string
842
+ * `const` so JSON consumers can switch on it.
843
+ */
844
+ export type ErrorTraceSchemaVersion = "1"
845
+ /**
846
+ * Where a frame's source location sits relative to the analysed project.
847
+ */
848
+ export type FrameOrigin = ("in_project" | "node_modules" | "out_of_corpus")
849
+ /**
850
+ * What the project graph could say about a frame's identifier.
851
+ *
852
+ * `not_attempted` is not a softer `not_found`: it records that the graph was
853
+ * never consulted, because the frame does not point at project source. Keeping
854
+ * them apart is what lets `resolved + ambiguous + not_found + not_attempted`
855
+ * equal the frame count without any of the four lying about what it measured.
856
+ */
857
+ export type FrameResolution = ("resolved" | "ambiguous" | "not_found" | "not_attempted")
778
858
  /**
779
859
  * Singleton GitHub review-event marker.
780
860
  */
@@ -857,7 +937,7 @@ export type GroupByMode = ("owner" | "directory" | "package" | "section")
857
937
  * Schema projection for the duplication envelope's CLI and programmatic
858
938
  * version lineages.
859
939
  */
860
- export type DupesSchemaVersion = (3 | 9)
940
+ export type DupesSchemaVersion = (4 | 10)
861
941
  /**
862
942
  * Wire-version discriminator for [`ImpactReport`]. Independent from the global
863
943
  * `SchemaVersion` (the impact report versions on its own cadence) and from the
@@ -969,7 +1049,7 @@ export type SecurityBlindSpotsSchemaVersion = "1"
969
1049
  /**
970
1050
  * Schema projection for the combined envelope's exact version.
971
1051
  */
972
- export type CombinedSchemaVersion = 11
1052
+ export type CombinedSchemaVersion = 12
973
1053
  /**
974
1054
  * Schema projection for the feature-flags envelope's exact version.
975
1055
  */
@@ -990,7 +1070,7 @@ export type FeatureFlagActionType = ("investigate-flag" | "suppress-line")
990
1070
  * Independently-versioned wire-version newtype for the brief envelope.
991
1071
  * Serializes as the integer `REVIEW_BRIEF_SCHEMA_VERSION`.
992
1072
  */
993
- export type ReviewBriefSchemaVersion = 8
1073
+ export type ReviewBriefSchemaVersion = 10
994
1074
  /**
995
1075
  * The exactly-three shippable decision categories (the SOLID-3). No cut category
996
1076
  * (abstraction / deletion / convention / irreversibility) is representable: this
@@ -1059,6 +1139,30 @@ export type SuppressionInventoryLevel = ("file" | "line")
1059
1139
  * How a suppression in the inventory was authored.
1060
1140
  */
1061
1141
  export type SuppressionInventoryOrigin = "comment"
1142
+ /**
1143
+ * Schema projection for the exact doctor envelope version.
1144
+ */
1145
+ export type DoctorSchemaVersion = 2
1146
+ /**
1147
+ * Schema projection for `.` as the privacy-safe diagnosed project root.
1148
+ */
1149
+ export type DoctorProjectRoot = "."
1150
+ /**
1151
+ * Aggregate readiness outcome.
1152
+ */
1153
+ export type DoctorStatus = ("pass" | "warn" | "fail")
1154
+ /**
1155
+ * Stable identifier for a doctor check. Declaration order is output order.
1156
+ */
1157
+ export type DoctorCheckId = ("root" | "config" | "workspaces" | "plugins" | "type-aware" | "dependencies" | "cache" | "graph-cache")
1158
+ /**
1159
+ * Stable category for a doctor check.
1160
+ */
1161
+ export type DoctorCheckCategory = ("project" | "configuration" | "workspace" | "plugin" | "companion" | "cache")
1162
+ /**
1163
+ * Per-check readiness outcome.
1164
+ */
1165
+ export type DoctorCheckStatus = ("pass" | "warn" | "fail" | "skipped")
1062
1166
  /**
1063
1167
  * Schema projection for the type-aware status envelope's exact version.
1064
1168
  */
@@ -2559,7 +2663,7 @@ _meta?: (Meta | null)
2559
2663
  * `malformed-tsconfig`, `tsconfig-reference-dir-missing`;
2560
2664
  * - source discovery, during the file walk: `skipped-large-file`,
2561
2665
  * `skipped-minified-file`, `skipped-source-dotdir`,
2562
- * `source-read-failure`;
2666
+ * `source-read-failure`, `source-parse-degraded`;
2563
2667
  * - dead-code analysis, from the dependency-catalog and override
2564
2668
  * detectors: `malformed-pnpm-workspace-yaml`,
2565
2669
  * `bun-lockb-override-resolution-skipped`.
@@ -2570,6 +2674,16 @@ _meta?: (Meta | null)
2570
2674
  * forward slashes; the array is omitted when empty. The same list is
2571
2675
  * repeated on each top-level command's envelope so single-command
2572
2676
  * consumers see it without having to look at a separate top-level field.
2677
+ *
2678
+ * A diagnostic here is advisory and never withholds a finding. Where an
2679
+ * entry reports a source file this run never fully analyzed
2680
+ * (`source-parse-degraded`, `source-read-failure`, `skipped-large-file`,
2681
+ * `skipped-minified-file`, `skipped-source-dotdir`) it can distort a
2682
+ * verdict, so the affected `unused_files[]`, `unused_exports[]`, and
2683
+ * dependency entries additionally carry the caveat themselves in their own
2684
+ * optional `reachability_caveats[]` array, and a reader who never scrolls
2685
+ * back up to this list still sees it. `fallow fix` reads the same array
2686
+ * and withholds the removal while a caveat stands.
2573
2687
  */
2574
2688
  workspace_diagnostics?: WorkspaceDiagnostic[]
2575
2689
  /**
@@ -2807,6 +2921,14 @@ actions: IssueAction[]
2807
2921
  * the merge-base. `None` when serialized directly from Rust.
2808
2922
  */
2809
2923
  introduced?: (AuditIntroduced | null)
2924
+ /**
2925
+ * Advisory caveats on the reachability verdict behind this finding.
2926
+ * Sorted, deduplicated, and omitted from the wire when empty, so a run
2927
+ * that analyzed every discovered file is byte-identical. Never gates the
2928
+ * finding or the `delete-file` action, though `fallow fix` does withhold
2929
+ * the removal of a caveated finding as low confidence.
2930
+ */
2931
+ reachability_caveats?: ReachabilityCaveat[]
2810
2932
  }
2811
2933
  /**
2812
2934
  * A code-change fix. `type` is one of the kebab-case identifiers in
@@ -2825,6 +2947,14 @@ type: FixActionType
2825
2947
  * Filter on this bool of each individual action, not on `type`. See the
2826
2948
  * [`IssueAction`] enum-level docs for the full list of per-instance
2827
2949
  * flips.
2950
+ *
2951
+ * One flip is RUN-level rather than finding-level: a dead-code finding
2952
+ * carrying `reachability_caveats` reports `false` here, because a file
2953
+ * this run never fully read may hold the reference that credits it. Every
2954
+ * mutation surface honours the same gate, so a plan built from this flag
2955
+ * never expects a write `fallow fix`, the MCP fix tools, or the LSP quick
2956
+ * fix will refuse. The action stays in the array at the same position and
2957
+ * names the reason in [`Self::note`].
2828
2958
  */
2829
2959
  auto_fixable: boolean
2830
2960
  /**
@@ -3008,6 +3138,13 @@ semantic?: (SemanticCandidateDecision | null)
3008
3138
  * the merge-base.
3009
3139
  */
3010
3140
  introduced?: (AuditIntroduced | null)
3141
+ /**
3142
+ * Advisory caveats on the reachability verdict behind this finding.
3143
+ * Sorted, deduplicated, and omitted from the wire when empty. Never gates
3144
+ * the finding or the `remove-export` action, though `fallow fix` does
3145
+ * withhold the removal of a caveated export as low confidence.
3146
+ */
3147
+ reachability_caveats?: ReachabilityCaveat[]
3011
3148
  }
3012
3149
  /**
3013
3150
  * Wire-shape envelope for an [`UnusedExport`] finding consumed under the
@@ -3058,6 +3195,14 @@ semantic?: (SemanticCandidateDecision | null)
3058
3195
  * the merge-base.
3059
3196
  */
3060
3197
  introduced?: (AuditIntroduced | null)
3198
+ /**
3199
+ * Advisory caveats on the reachability verdict behind this finding.
3200
+ * A type export rests on exactly the reachability test an
3201
+ * `unused_exports[]` entry does, and the LSP offers the same
3202
+ * remove-the-`export`-keyword quick fix for both, so the two must render
3203
+ * with the same confidence. Sorted, deduplicated, omitted when empty.
3204
+ */
3205
+ reachability_caveats?: ReachabilityCaveat[]
3061
3206
  }
3062
3207
  /**
3063
3208
  * Wire-shape envelope for a [`PrivateTypeLeak`] finding. Mirrors
@@ -3141,6 +3286,15 @@ actions: IssueAction[]
3141
3286
  * the merge-base.
3142
3287
  */
3143
3288
  introduced?: (AuditIntroduced | null)
3289
+ /**
3290
+ * Advisory caveats on the verdict behind this finding. A dependency is
3291
+ * reported unused when NO module in the project imports its specifier,
3292
+ * so a module that parsed with errors can hide the import that would
3293
+ * have credited the package. Sorted, deduplicated, and omitted from the
3294
+ * wire when empty. Never gates the finding, though `fallow fix`
3295
+ * withholds the `remove-dependency` write while a caveat stands.
3296
+ */
3297
+ reachability_caveats?: ReachabilityCaveat[]
3144
3298
  }
3145
3299
  /**
3146
3300
  * Wire-shape envelope for an [`UnusedDependency`] finding consumed under
@@ -3178,6 +3332,15 @@ actions: IssueAction[]
3178
3332
  * the merge-base.
3179
3333
  */
3180
3334
  introduced?: (AuditIntroduced | null)
3335
+ /**
3336
+ * Advisory caveats on the verdict behind this finding. A dependency is
3337
+ * reported unused when NO module in the project imports its specifier,
3338
+ * so a module that parsed with errors can hide the import that would
3339
+ * have credited the package. Sorted, deduplicated, and omitted from the
3340
+ * wire when empty. Never gates the finding, though `fallow fix`
3341
+ * withholds the `remove-dependency` write while a caveat stands.
3342
+ */
3343
+ reachability_caveats?: ReachabilityCaveat[]
3181
3344
  }
3182
3345
  /**
3183
3346
  * Wire-shape envelope for an [`UnusedDependency`] finding consumed under
@@ -3215,6 +3378,15 @@ actions: IssueAction[]
3215
3378
  * the merge-base.
3216
3379
  */
3217
3380
  introduced?: (AuditIntroduced | null)
3381
+ /**
3382
+ * Advisory caveats on the verdict behind this finding. A dependency is
3383
+ * reported unused when NO module in the project imports its specifier,
3384
+ * so a module that parsed with errors can hide the import that would
3385
+ * have credited the package. Sorted, deduplicated, and omitted from the
3386
+ * wire when empty. Never gates the finding, though `fallow fix`
3387
+ * withholds the `remove-dependency` write while a caveat stands.
3388
+ */
3389
+ reachability_caveats?: ReachabilityCaveat[]
3218
3390
  }
3219
3391
  /**
3220
3392
  * Wire-shape envelope for an [`UnusedMember`] finding consumed under the
@@ -3252,6 +3424,15 @@ actions: IssueAction[]
3252
3424
  * the merge-base.
3253
3425
  */
3254
3426
  introduced?: (AuditIntroduced | null)
3427
+ /**
3428
+ * Advisory caveats on the verdict behind this finding. A member's usage
3429
+ * is collected by walking the member accesses of every module the run
3430
+ * parsed, so a member whose only reference lives in a file the run never
3431
+ * read reads as unused exactly like an export does. Sorted,
3432
+ * deduplicated, and omitted from the wire when empty. Never gates the
3433
+ * finding; it does withhold the `remove-enum-member` mutation.
3434
+ */
3435
+ reachability_caveats?: ReachabilityCaveat[]
3255
3436
  }
3256
3437
  /**
3257
3438
  * Wire-shape envelope for an [`UnusedMember`] finding consumed under the
@@ -3295,6 +3476,16 @@ semantic?: (SemanticCandidateDecision | null)
3295
3476
  * the merge-base.
3296
3477
  */
3297
3478
  introduced?: (AuditIntroduced | null)
3479
+ /**
3480
+ * Advisory caveats on the verdict behind this finding. A class member's
3481
+ * usage is collected by the same reachability-free member-access walk an
3482
+ * enum member's is, so it takes the enum-member rule unchanged: any module
3483
+ * this run analyzed incompletely can hold the access that credits it.
3484
+ * Sorted, deduplicated, and omitted from the wire when empty. Never gates
3485
+ * the finding; it does withhold the `remove-class-member` mutation that
3486
+ * the type-aware pass would otherwise open.
3487
+ */
3488
+ reachability_caveats?: ReachabilityCaveat[]
3298
3489
  }
3299
3490
  /**
3300
3491
  * Wire-shape envelope for an [`UnusedMember`] finding consumed under the
@@ -3338,6 +3529,17 @@ actions: IssueAction[]
3338
3529
  * the merge-base.
3339
3530
  */
3340
3531
  introduced?: (AuditIntroduced | null)
3532
+ /**
3533
+ * Advisory caveats on the verdict behind this finding. A store member's
3534
+ * usage is collected by the same reachability-free member-access walk a
3535
+ * class member's is, so it takes the member rule unchanged: any module
3536
+ * this run analyzed incompletely can hold the access that credits it.
3537
+ * Sorted, deduplicated, and omitted from the wire when empty. There is no
3538
+ * mutation here to withhold, because a store member offers none on any
3539
+ * surface; this is disclosure only, so a reader deciding by hand is told
3540
+ * what the run did not see.
3541
+ */
3542
+ reachability_caveats?: ReachabilityCaveat[]
3341
3543
  }
3342
3544
  /**
3343
3545
  * Wire-shape envelope for an [`UnresolvedImport`] finding. Mirrors
@@ -5057,8 +5259,13 @@ start_col: number
5057
5259
  end_col: number
5058
5260
  /**
5059
5261
  * The actual source code fragment.
5262
+ *
5263
+ * Omitted from JSON when the caller asked for a location-only payload
5264
+ * (`fallow dupes --no-fragments`, and the MCP `find_dupes` default). The
5265
+ * five location fields above address the same text, so a consumer that
5266
+ * wants the source reads it from the file.
5060
5267
  */
5061
- fragment: string
5268
+ fragment?: string
5062
5269
  }
5063
5270
  /**
5064
5271
  * Per-action wire shape attached to each `CloneGroupFinding` and
@@ -5223,13 +5430,21 @@ total_tokens: number
5223
5430
  */
5224
5431
  duplicated_tokens: number
5225
5432
  /**
5226
- * Number of clone groups in the reported `clone_groups[]` array after
5227
- * filtering and optional `--top` truncation.
5433
+ * Number of clone groups the scoped corpus contains after filtering.
5434
+ * `--top` does not change it; compare it with `clone_groups_shown` on the
5435
+ * envelope to see how much of the corpus the array carries.
5228
5436
  */
5229
5437
  clone_groups: number
5230
5438
  /**
5231
- * Total clone instances across all reported groups after filtering and
5232
- * optional `--top` truncation.
5439
+ * Number of clone families the scoped corpus contains after filtering.
5440
+ * `--top` truncates `clone_families[]` along with `clone_groups[]` but
5441
+ * does not change this counter; compare it with `clone_families_shown` on
5442
+ * the envelope to see how much of the corpus the array carries.
5443
+ */
5444
+ clone_families: number
5445
+ /**
5446
+ * Total clone instances across the scoped corpus after filtering.
5447
+ * `--top` does not change it.
5233
5448
  */
5234
5449
  clone_instances: number
5235
5450
  /**
@@ -5309,7 +5524,11 @@ prop_drilling_chains?: PropDrillingChainFinding[]
5309
5524
  */
5310
5525
  hotspots?: HotspotFinding[]
5311
5526
  /**
5312
- * Hotspot analysis summary (only set with `--hotspots`).
5527
+ * Hotspot analysis summary.
5528
+ *
5529
+ * Set whenever the run measured churn, which needs readable git history;
5530
+ * `--hotspots` adds the per-file [`hotspots`](Self::hotspots) listing
5531
+ * beside it rather than gating this summary.
5313
5532
  */
5314
5533
  hotspot_summary?: (HotspotSummary | null)
5315
5534
  /**
@@ -5702,13 +5921,11 @@ export interface HealthSummary {
5702
5921
  */
5703
5922
  files_analyzed: number
5704
5923
  /**
5705
- * Real functions scored across the analyzed files. This counts functions
5706
- * only, so it is smaller than the sum of `file_scores[].function_count`,
5707
- * which also counts the synthetic per-file units (`<module>` for
5708
- * module-scope branching, `<template>` and `<snippet:NAME>` for component
5709
- * templates). The complexity aggregates below, including
5710
- * `average_cyclomatic` and `p90_cyclomatic`, are computed over that larger
5711
- * population rather than over this count.
5924
+ * Functions and template units checked for threshold findings across the
5925
+ * analyzed files. Synthetic module-scope units are excluded. Cyclomatic
5926
+ * aggregates include module units too; `vital_signs.cyclomatic_population`
5927
+ * reports the disjoint authored-function, module, and template populations
5928
+ * behind those aggregates.
5712
5929
  */
5713
5930
  functions_analyzed: number
5714
5931
  /**
@@ -5943,18 +6160,24 @@ dead_file_pct?: (number | null)
5943
6160
  */
5944
6161
  dead_export_pct?: (number | null)
5945
6162
  /**
5946
- * Average cyclomatic complexity across all functions.
6163
+ * Average cyclomatic complexity across authored functions, module-scope
6164
+ * units, and template units. See `cyclomatic_population` for the denominator.
5947
6165
  */
5948
6166
  avg_cyclomatic: number
5949
6167
  /**
5950
- * Percentage of functions at or above the critical cyclomatic threshold.
6168
+ * Percentage of complexity units at or above the critical cyclomatic threshold.
5951
6169
  * Used by the scale-invariant health score.
5952
6170
  */
5953
6171
  critical_complexity_pct?: (number | null)
5954
6172
  /**
5955
- * 90th percentile cyclomatic complexity.
6173
+ * 90th percentile cyclomatic complexity across the same unit population.
5956
6174
  */
5957
6175
  p90_cyclomatic: number
6176
+ /**
6177
+ * Population behind the cyclomatic mean, percentile, and critical share.
6178
+ * Present on current analyses; absent on older saved snapshots.
6179
+ */
6180
+ cyclomatic_population?: (CyclomaticPopulation | null)
5958
6181
  /**
5959
6182
  * Code duplication percentage (None if duplication pipeline was not run).
5960
6183
  */
@@ -6068,6 +6291,33 @@ top_render_fan_in?: RenderFanInTopComponent[]
6068
6291
  */
6069
6292
  total_loc?: number
6070
6293
  }
6294
+ /**
6295
+ * Disjoint populations feeding the cyclomatic distribution. Counts and sums
6296
+ * across all three groups reconstruct its weighted mean. Module-scope units
6297
+ * contribute to aggregates only and do not produce function findings.
6298
+ */
6299
+ export interface CyclomaticPopulation {
6300
+ functions: CyclomaticUnitPopulation
6301
+ modules: CyclomaticUnitPopulation
6302
+ templates: CyclomaticUnitPopulation
6303
+ }
6304
+ /**
6305
+ * Cyclomatic measurements for one kind of complexity unit.
6306
+ */
6307
+ export interface CyclomaticUnitPopulation {
6308
+ /**
6309
+ * Number of units measured, including those below finding thresholds.
6310
+ */
6311
+ count: number
6312
+ /**
6313
+ * Sum of cyclomatic complexity, before rounding or threshold filtering.
6314
+ */
6315
+ sum: number
6316
+ /**
6317
+ * Highest cyclomatic complexity, or null when this population is empty.
6318
+ */
6319
+ max?: (number | null)
6320
+ }
6071
6321
  /**
6072
6322
  * Raw counts backing the vital signs percentages.
6073
6323
  *
@@ -6284,15 +6534,15 @@ complexity_density: number
6284
6534
  */
6285
6535
  maintainability_index: number
6286
6536
  /**
6287
- * Summed cyclomatic complexity over the file's functions.
6537
+ * Summed cyclomatic complexity over all units, including module and template scope.
6288
6538
  */
6289
6539
  total_cyclomatic: number
6290
6540
  /**
6291
- * Summed cognitive complexity over the file's functions.
6541
+ * Summed cognitive complexity over all units, including module and template scope.
6292
6542
  */
6293
6543
  total_cognitive: number
6294
6544
  /**
6295
- * Functions in the file.
6545
+ * Complexity units in the file, including synthetic module and template units.
6296
6546
  */
6297
6547
  function_count: number
6298
6548
  /**
@@ -6686,6 +6936,32 @@ files_excluded: number
6686
6936
  * truncated.
6687
6937
  */
6688
6938
  shallow_clone: boolean
6939
+ /**
6940
+ * Provenance of the instant every churn and staleness number was measured
6941
+ * against. Absent only when a caller assembled a summary without one.
6942
+ */
6943
+ clock?: (ClockProvenance | null)
6944
+ }
6945
+ /**
6946
+ * The instant a run measured commit ages and staleness against.
6947
+ *
6948
+ * A consumer reading `weighted_commits`, `stale_days`, or anything derived
6949
+ * from them needs to know whether re-running over the same commit yields the
6950
+ * same number. The human report says so in a warning that `--quiet` removes,
6951
+ * which left the JSON consumer, who cannot see stderr at all, with no way to
6952
+ * find out.
6953
+ */
6954
+ export interface ClockProvenance {
6955
+ source: ClockSource
6956
+ /**
6957
+ * The reference epoch itself, in unix seconds. Pass it back as
6958
+ * `FALLOW_CLOCK_EPOCH` to reproduce this run's churn-derived numbers.
6959
+ */
6960
+ epoch_secs: number
6961
+ /**
6962
+ * False only for `wall_clock`, where the numbers drift between runs.
6963
+ */
6964
+ reproducible: boolean
6689
6965
  }
6690
6966
  /**
6691
6967
  * Runtime coverage findings merged into the health report or emitted by
@@ -9511,6 +9787,68 @@ consumed_symbols: string[]
9511
9787
  */
9512
9788
  note: string
9513
9789
  }
9790
+ /**
9791
+ * Result of asking how one module reaches another: the shortest import path.
9792
+ *
9793
+ * `reachable` is the only field that separates "no route exists" from "the
9794
+ * route is empty because both ends are the same module". Both report
9795
+ * `hops: 0`, so a consumer must read `reachable`, never the hop count.
9796
+ */
9797
+ export interface ImportPathTrace {
9798
+ schema_version: ImportPathTraceSchemaVersion
9799
+ /**
9800
+ * The module the walk started from, root-relative.
9801
+ */
9802
+ from: string
9803
+ /**
9804
+ * The module the walk was looking for, root-relative.
9805
+ */
9806
+ to: string
9807
+ /**
9808
+ * Whether `to` is reachable from `from` by following import edges.
9809
+ */
9810
+ reachable: boolean
9811
+ /**
9812
+ * Number of import edges on the reported route. `0` both when the two ends
9813
+ * are the same module and when there is no route at all.
9814
+ */
9815
+ hops: number
9816
+ /**
9817
+ * The route, in import order. Empty whenever `hops` is `0`.
9818
+ */
9819
+ path: ImportPathHop[]
9820
+ /**
9821
+ * Human-readable summary of the outcome.
9822
+ */
9823
+ reason: string
9824
+ }
9825
+ /**
9826
+ * One import edge on an [`ImportPathTrace`].
9827
+ */
9828
+ export interface ImportPathHop {
9829
+ /**
9830
+ * The importing module, root-relative.
9831
+ */
9832
+ from: string
9833
+ /**
9834
+ * The imported module, root-relative.
9835
+ */
9836
+ to: string
9837
+ /**
9838
+ * Whether every symbol on this edge is type-only, so the hop is erased at
9839
+ * build time. Type-only hops are reported, never skipped: an `import type`
9840
+ * chain is a real compile-time coupling.
9841
+ */
9842
+ type_only: boolean
9843
+ /**
9844
+ * 1-based line in `from` of the imported binding that creates this edge:
9845
+ * the first value-carrying symbol on the import, or the first symbol when
9846
+ * every symbol is type-only. On a multi-line import that is the binding's
9847
+ * own line, not the `import` keyword's. Absent when the edge carries no
9848
+ * span or the source could not be read.
9849
+ */
9850
+ import_line?: (number | null)
9851
+ }
9514
9852
  /**
9515
9853
  * The result of a symbol-level call-chain trace. Its own surface (`kind:
9516
9854
  * "trace"`), NOT folded into the ranked brief.
@@ -9606,6 +9944,195 @@ export interface UnresolvedCallee {
9606
9944
  callee: string
9607
9945
  reason: UnresolvedReason
9608
9946
  }
9947
+ /**
9948
+ * Result of resolving a runtime stack trace against the project graph.
9949
+ */
9950
+ export interface ErrorTrace {
9951
+ schema_version: ErrorTraceSchemaVersion
9952
+ /**
9953
+ * Where the trace was read from: `stdin`, or the path as the caller wrote
9954
+ * it.
9955
+ */
9956
+ source: string
9957
+ /**
9958
+ * The first non-blank input line that preceded any recognised frame,
9959
+ * verbatim. Conventionally the error type and message, but it is reported
9960
+ * as read and NOT parsed into parts. Absent when the input began with a
9961
+ * frame or was empty.
9962
+ */
9963
+ header?: (string | null)
9964
+ /**
9965
+ * Every recognised frame, in input order. Nothing is filtered out: a
9966
+ * dependency or runtime-internal frame stays in the array with its origin
9967
+ * recorded, so hop numbering matches the trace the caller pasted.
9968
+ */
9969
+ frames: ErrorTraceFrame[]
9970
+ counts: ErrorTraceCounts
9971
+ /**
9972
+ * Human-readable summary of the outcome.
9973
+ */
9974
+ reason: string
9975
+ }
9976
+ /**
9977
+ * One frame read from the input stack trace.
9978
+ */
9979
+ export interface ErrorTraceFrame {
9980
+ /**
9981
+ * 0-based position in the input trace, so a caller can quote a frame back
9982
+ * even after filtering the array.
9983
+ */
9984
+ index: number
9985
+ /**
9986
+ * The input line this frame was read from, trimmed of surrounding
9987
+ * whitespace and otherwise verbatim.
9988
+ */
9989
+ raw: string
9990
+ /**
9991
+ * The frame's function identifier as written by the runtime, with the
9992
+ * `async` and `new` markers stripped and recorded separately. Absent for a
9993
+ * frame the runtime emitted without one.
9994
+ */
9995
+ function?: (string | null)
9996
+ /**
9997
+ * Whether the runtime marked this frame as a constructor call (`new X`).
9998
+ */
9999
+ is_constructor?: boolean
10000
+ /**
10001
+ * Whether the runtime marked this frame as an async call.
10002
+ */
10003
+ is_async?: boolean
10004
+ /**
10005
+ * The frame's file as read from the trace, with any `file://` or
10006
+ * `http(s)://` wrapper removed and separators forward-slashed. Reported as
10007
+ * read: it is NOT rewritten to the module path it matched, so a caller can
10008
+ * see what its runtime actually said. Absent for a frame with no location.
10009
+ */
10010
+ file?: (string | null)
10011
+ /**
10012
+ * 1-based line from the frame's location, when the runtime supplied one.
10013
+ */
10014
+ line?: (number | null)
10015
+ /**
10016
+ * 1-based column from the frame's location, when the runtime supplied one.
10017
+ */
10018
+ column?: (number | null)
10019
+ origin: FrameOrigin
10020
+ resolution: FrameResolution
10021
+ /**
10022
+ * Every definition the identifier could name, in deterministic order.
10023
+ * Exactly one entry when `resolution` is `resolved`, more than one when it
10024
+ * is `ambiguous`, and empty otherwise.
10025
+ */
10026
+ candidates: ErrorTraceCandidate[]
10027
+ /**
10028
+ * How many further candidates a presentation cap withheld.
10029
+ * `candidates.len() + candidates_omitted` is the true match count, so an
10030
+ * `ambiguous` frame never understates how ambiguous it is.
10031
+ */
10032
+ candidates_omitted: number
10033
+ /**
10034
+ * Set when this frame's own line disagrees with the definition its
10035
+ * identifier matched: some OTHER definition in the same file is declared
10036
+ * closer above the line the runtime reported.
10037
+ *
10038
+ * The look-up matches on the identifier alone, so a `resolved` frame is
10039
+ * resolved however far its line sits from the match. That is honest about
10040
+ * the question asked and silent about a question a reader would ask next,
10041
+ * which is why the disagreement is published instead of left to be
10042
+ * noticed. The frame is NOT reclassified: the graph does know a
10043
+ * definition under this identifier, and only the caller can say whether
10044
+ * the runtime ran that one or a same-named definition elsewhere.
10045
+ * `reason` names the declaration that sits closer. Only set on a
10046
+ * `resolved` frame that carried a line and matched a definition whose own
10047
+ * line could be read.
10048
+ */
10049
+ line_mismatch?: boolean
10050
+ /**
10051
+ * Human-readable statement of what happened to this frame.
10052
+ */
10053
+ reason: string
10054
+ }
10055
+ /**
10056
+ * One definition a frame's identifier could name.
10057
+ */
10058
+ export interface ErrorTraceCandidate {
10059
+ /**
10060
+ * Root-relative file declaring the definition.
10061
+ */
10062
+ file: string
10063
+ /**
10064
+ * The exported name. For a member match this is the owning export.
10065
+ */
10066
+ symbol: string
10067
+ /**
10068
+ * The member name, when the frame's identifier named a member of
10069
+ * `symbol` rather than `symbol` itself. Absent for a direct export match.
10070
+ */
10071
+ member?: (string | null)
10072
+ /**
10073
+ * What kind of definition this is: `export`, or the member kind
10074
+ * (`class-method`, `class-property`, `enum-member`, `store-member`,
10075
+ * `namespace-member`).
10076
+ */
10077
+ kind: string
10078
+ /**
10079
+ * 1-based declaration line of the definition's identifier. Absent when the
10080
+ * source file could not be read; never guessed.
10081
+ */
10082
+ line?: (number | null)
10083
+ }
10084
+ /**
10085
+ * Per-outcome totals for an [`ErrorTrace`].
10086
+ *
10087
+ * `resolved + ambiguous + not_found + not_attempted == frames`, and
10088
+ * `in_project + node_modules + out_of_corpus == frames`. Both identities hold
10089
+ * on every run, so a caller can verify that nothing was dropped.
10090
+ */
10091
+ export interface ErrorTraceCounts {
10092
+ /**
10093
+ * Frames reported in `frames`.
10094
+ */
10095
+ frames: number
10096
+ /**
10097
+ * Frames a cap withheld from `frames`. Their outcomes are NOT counted in
10098
+ * the fields below, which describe the reported frames only.
10099
+ */
10100
+ frames_omitted: number
10101
+ /**
10102
+ * Frames whose file resolved to project source.
10103
+ */
10104
+ in_project: number
10105
+ /**
10106
+ * Frames whose file lives under an installed dependency tree.
10107
+ */
10108
+ node_modules: number
10109
+ /**
10110
+ * Frames outside the analysed corpus, including frames with no location.
10111
+ */
10112
+ out_of_corpus: number
10113
+ /**
10114
+ * Frames that matched exactly one definition.
10115
+ */
10116
+ resolved: number
10117
+ /**
10118
+ * Frames that matched more than one definition.
10119
+ */
10120
+ ambiguous: number
10121
+ /**
10122
+ * Frames the graph was asked about and could not name.
10123
+ */
10124
+ not_found: number
10125
+ /**
10126
+ * Frames the graph was never asked about.
10127
+ */
10128
+ not_attempted: number
10129
+ /**
10130
+ * Non-blank input lines that were neither recognised as a frame nor taken
10131
+ * as `header`. A trace that is entirely unrecognised reports zero frames
10132
+ * and a non-zero count here, rather than looking like an empty trace.
10133
+ */
10134
+ unparsed_lines: number
10135
+ }
9609
10136
  /**
9610
10137
  * Envelope emitted by `fallow --format review-github` / `review-gitlab`.
9611
10138
  */
@@ -10179,7 +10706,11 @@ prop_drilling_chains?: PropDrillingChainFinding[]
10179
10706
  */
10180
10707
  hotspots?: HotspotFinding[]
10181
10708
  /**
10182
- * Hotspot analysis summary (only set with `--hotspots`).
10709
+ * Hotspot analysis summary.
10710
+ *
10711
+ * Set whenever the run measured churn, which needs readable git history;
10712
+ * `--hotspots` adds the per-file [`hotspots`](Self::hotspots) listing
10713
+ * beside it rather than gating this summary.
10183
10714
  */
10184
10715
  hotspot_summary?: (HotspotSummary | null)
10185
10716
  /**
@@ -10394,6 +10925,29 @@ clone_families: CloneFamilyFinding[]
10394
10925
  */
10395
10926
  mirrored_directories?: MirroredDirectory[]
10396
10927
  stats: DuplicationStats
10928
+ /**
10929
+ * Number of clone groups carried in `clone_groups[]`.
10930
+ */
10931
+ clone_groups_shown: number
10932
+ /**
10933
+ * Number of scoped-corpus clone groups withheld from `clone_groups[]` by
10934
+ * a presentation cap such as `--top`. `0` on an untruncated run, so
10935
+ * `clone_groups_shown + clone_groups_omitted == stats.clone_groups`
10936
+ * always holds and `stats` keeps describing the whole measured corpus.
10937
+ */
10938
+ clone_groups_omitted: number
10939
+ /**
10940
+ * Number of clone families carried in `clone_families[]`.
10941
+ */
10942
+ clone_families_shown: number
10943
+ /**
10944
+ * Number of scoped-corpus clone families withheld from `clone_families[]`
10945
+ * by a presentation cap such as `--top`, which rebuilds the families from
10946
+ * the groups that survived the cap. `0` on an untruncated run, so
10947
+ * `clone_families_shown + clone_families_omitted == stats.clone_families`
10948
+ * always holds and `stats` keeps describing the whole measured corpus.
10949
+ */
10950
+ clone_families_omitted: number
10397
10951
  /**
10398
10952
  * Grouping mode when `--group-by` was passed.
10399
10953
  */
@@ -10530,8 +11084,13 @@ start_col: number
10530
11084
  end_col: number
10531
11085
  /**
10532
11086
  * The actual source code fragment.
11087
+ *
11088
+ * Omitted from JSON when the caller asked for a location-only payload
11089
+ * (`fallow dupes --no-fragments`, and the MCP `find_dupes` default). The
11090
+ * five location fields above address the same text, so a consumer that
11091
+ * wants the source reads it from the file.
10533
11092
  */
10534
- fragment: string
11093
+ fragment?: string
10535
11094
  /**
10536
11095
  * Resolver key for this specific instance (per-instance, not the
10537
11096
  * group-level largest-owner).
@@ -10982,6 +11541,13 @@ project_surfacing?: (ImpactCounts | null)
10982
11541
  * `trend`. None until two full `fallow` runs exist. v1.6.
10983
11542
  */
10984
11543
  project_trend?: (TrendSummary | null)
11544
+ /**
11545
+ * Recorded gate runs grouped by source, over the same bounded window of
11546
+ * recorded runs `record_count` reports. A floor, not a lifetime total, and
11547
+ * absent when no run in that window carries a gate source. Local
11548
+ * provenance, never an adoption metric.
11549
+ */
11550
+ gate_runs?: (GateRunCounts | null)
10985
11551
  /**
10986
11552
  * Lifetime count of commit-gate containment events.
10987
11553
  */
@@ -11063,6 +11629,37 @@ previous_total: number
11063
11629
  */
11064
11630
  current_total: number
11065
11631
  }
11632
+ /**
11633
+ * Recorded gate runs grouped by the gate that produced them. Local
11634
+ * provenance only: the store never leaves the machine, so this answers "where
11635
+ * do my gate runs come from", never "how widely is fallow adopted".
11636
+ *
11637
+ * Counted over the recorded runs the store still holds, which is the same
11638
+ * window `record_count` reports. The store keeps a bounded number of runs and
11639
+ * drops the oldest, so on a long-lived project these are the shape of recent
11640
+ * gate activity, not a lifetime total: read them as a floor. Absent when no
11641
+ * run in that window carries a gate source, which is not the same as "no gate
11642
+ * ever ran here".
11643
+ */
11644
+ export interface GateRunCounts {
11645
+ /**
11646
+ * Runs recorded by the agent gate (`--gate-marker agent`).
11647
+ */
11648
+ agent: number
11649
+ /**
11650
+ * Runs recorded by the git pre-commit hook (`--gate-marker pre-commit`).
11651
+ */
11652
+ pre_commit: number
11653
+ /**
11654
+ * Runs recorded by a CI gate (`--gate-marker ci`).
11655
+ */
11656
+ ci: number
11657
+ /**
11658
+ * Gate runs whose marker this build does not recognise, plus every gate
11659
+ * run recorded before the store kept its source (store schema 6 and older).
11660
+ */
11661
+ unknown: number
11662
+ }
11066
11663
  /**
11067
11664
  * A commit-gate containment event recorded by `fallow impact`.
11068
11665
  */
@@ -12163,6 +12760,24 @@ feature_flags: FeatureFlagFinding[]
12163
12760
  * Number of entries in `feature_flags`.
12164
12761
  */
12165
12762
  total_flags: number
12763
+ /**
12764
+ * Workspace-discovery and source-discovery diagnostics for the run. See
12765
+ * `CheckOutput::workspace_diagnostics` for the full contract.
12766
+ *
12767
+ * A flags run walks and parses the project like every other analysis, so
12768
+ * it records the same discovery kinds: a `skipped-large-file`,
12769
+ * `skipped-minified-file`, or `source-read-failure` file was never
12770
+ * scanned for flags, and a `source-parse-degraded` file was scanned from
12771
+ * a partial module. Each is a reason a flag can be missing from
12772
+ * `feature_flags[]`, which is exactly what a consumer reading a
12773
+ * zero-result run needs to know. The analysis-stage kinds appear here
12774
+ * too: the scan correlates flags with dead exports, so it runs the
12775
+ * dead-code analyze pass that records them.
12776
+ *
12777
+ * Omitted when empty, so a project with no discovery noise sees no
12778
+ * change.
12779
+ */
12780
+ workspace_diagnostics?: WorkspaceDiagnostic[]
12166
12781
  /**
12167
12782
  * `_meta` block; see [`FeatureFlagsMeta`].
12168
12783
  */
@@ -12504,12 +13119,11 @@ review_effort: ReviewEffort
12504
13119
  /**
12505
13120
  * Stage 1 of the brief: graph-derived orientation facts.
12506
13121
  *
12507
- * `boundaries_touched` is derived from the run's boundary-violation zones;
12508
- * `reachable_from` is populated by the impact closure (the affected-not-shown
12509
- * set: modules the changed code is reachable from / affects, none in the diff).
12510
- * `exports_added` and `api_width_delta` both report the exports-aware public API
12511
- * widening count. Removed exports are not represented in this widening-only
12512
- * signal.
13122
+ * `boundaries_touched` is derived from the run's boundary-violation zones.
13123
+ * `exports_added` and `api_width_delta` both report the exports-aware public
13124
+ * API widening count. Removed exports are not represented in this
13125
+ * widening-only signal. The set of modules the changed code reaches is Stage
13126
+ * 3's `impact_closure`, which owns both its magnitude and its paths.
12513
13127
  */
12514
13128
  export interface GraphFacts {
12515
13129
  /**
@@ -12523,12 +13137,6 @@ exports_added: number
12523
13137
  * were added.
12524
13138
  */
12525
13139
  api_width_delta: number
12526
- /**
12527
- * Root-relative paths of modules the changed code is reachable from / affects
12528
- * (the impact closure's affected-but-not-in-diff set), deduped and sorted.
12529
- * Empty when no graph was retained or nothing depends on the changed files.
12530
- */
12531
- reachable_from: string[]
12532
13140
  /**
12533
13141
  * Architecture boundary zones touched by the changeset, deduped and sorted.
12534
13142
  * Derived from the run's boundary-violation findings.
@@ -12593,16 +13201,65 @@ files: string[]
12593
13201
  */
12594
13202
  export interface ImpactClosureFacts {
12595
13203
  /**
12596
- * Root-relative paths transitively affected by the changeset (reverse-deps +
12597
- * re-export chains) that are NOT in the diff, deduped and sorted.
13204
+ * The FULL number of files transitively affected by the changeset
13205
+ * (reverse-deps + re-export chains) that are NOT in the diff. Computed
13206
+ * BEFORE [`affected_not_shown`](Self::affected_not_shown) is capped to a
13207
+ * sample, so it is always the true magnitude of the blast radius.
13208
+ */
13209
+ affected_count: number
13210
+ /**
13211
+ * A capped, path-sorted sample of the affected root-relative paths (at most
13212
+ * [`AFFECTED_SAMPLE_CAP`]), deduped. The full count lives in
13213
+ * [`affected_count`](Self::affected_count) and the distribution in
13214
+ * [`affected_by_dir`](Self::affected_by_dir); use this list to jump to
13215
+ * representative files, NEVER to enumerate the blast radius or to infer its
13216
+ * shape. Because it is a prefix of the sorted set, it clusters in whichever
13217
+ * directory sorts first. To reconstruct the full set, run
13218
+ * `fallow check --impact-closure <path>` once per changed file and union the
13219
+ * results: that flag seeds from a single file, so no single command
13220
+ * reproduces this changeset-wide union.
12598
13221
  */
12599
13222
  affected_not_shown: string[]
13223
+ /**
13224
+ * The blast radius rolled up by parent directory: how the affected files
13225
+ * distribute, heaviest directory first, ties broken by directory path so the
13226
+ * order is deterministic. This is the SHAPE signal, and unlike
13227
+ * [`affected_not_shown`](Self::affected_not_shown) its counts are exact for
13228
+ * every directory it lists. At most [`AFFECTED_DIR_CAP`] entries.
13229
+ */
13230
+ affected_by_dir: AffectedDirectory[]
13231
+ /**
13232
+ * How many directories did not fit within [`AFFECTED_DIR_CAP`] and are
13233
+ * absent from [`affected_by_dir`](Self::affected_by_dir). They are the
13234
+ * lightest ones; their files are still counted in
13235
+ * [`affected_count`](Self::affected_count). Zero when nothing was omitted.
13236
+ * Add this to `affected_by_dir.len()` for the true number of directories
13237
+ * the change reaches.
13238
+ */
13239
+ affected_by_dir_omitted: number
12600
13240
  /**
12601
13241
  * Coordination gaps: a changed file exports a contract consumed by a module
12602
- * absent from the diff. One entry per (changed file, consumer) pair.
13242
+ * absent from the diff. One entry per (changed file, consumer) pair. NOT a
13243
+ * subset of [`affected_not_shown`](Self::affected_not_shown): the gap
13244
+ * deliberately skips story and test consumers that the affected set counts.
12603
13245
  */
12604
13246
  coordination_gap: CoordinationGapFact[]
12605
13247
  }
13248
+ /**
13249
+ * One directory of the blast radius and how many affected files it holds.
13250
+ */
13251
+ export interface AffectedDirectory {
13252
+ /**
13253
+ * Root-relative parent directory, forward-slashed. The empty string is the
13254
+ * repository root.
13255
+ */
13256
+ dir: string
13257
+ /**
13258
+ * How many affected-but-not-in-diff files live directly in `dir`. Exact,
13259
+ * never sampled.
13260
+ */
13261
+ count: number
13262
+ }
12606
13263
  /**
12607
13264
  * One coordination-gap entry: a changed file exports symbols consumed by a
12608
13265
  * `consumer_file` that is NOT in the diff. Deduped per (changed, consumer) pair
@@ -12682,8 +13339,13 @@ fan_io: number
12682
13339
  /**
12683
13340
  * Security source -> sink taint-touch component (0 until a security pass is
12684
13341
  * threaded onto the brief path; the seam is built and tested).
13342
+ *
13343
+ * Omitted from the wire while it is zero, the same treatment `runtime`
13344
+ * gets. Publishing a permanently-zero component as a required field made
13345
+ * it read as a measurement that found nothing, when nothing measured it.
13346
+ * A consumer that sums components must read an absent component as zero.
12685
13347
  */
12686
- security_taint: number
13348
+ security_taint?: number
12687
13349
  /**
12688
13350
  * Risk-zone component (boundary / public-API / security-sensitive).
12689
13351
  */
@@ -13516,6 +14178,75 @@ reason?: (string | null)
13516
14178
  */
13517
14179
  reason_present: boolean
13518
14180
  }
14181
+ /**
14182
+ * Versioned readiness envelope emitted by `fallow doctor --format json`.
14183
+ */
14184
+ export interface DoctorOutput {
14185
+ schema_version: DoctorSchemaVersion
14186
+ version: ToolVersion
14187
+ root: DoctorProjectRoot
14188
+ status: DoctorStatus
14189
+ summary: DoctorSummary
14190
+ /**
14191
+ * Checks in stable contract order.
14192
+ */
14193
+ checks: DoctorCheck[]
14194
+ }
14195
+ /**
14196
+ * Counts for every per-check status.
14197
+ */
14198
+ export interface DoctorSummary {
14199
+ /**
14200
+ * Successful checks.
14201
+ */
14202
+ pass: number
14203
+ /**
14204
+ * Advisory checks.
14205
+ */
14206
+ warn: number
14207
+ /**
14208
+ * Failed checks.
14209
+ */
14210
+ fail: number
14211
+ /**
14212
+ * Inapplicable or prerequisite-blocked checks.
14213
+ */
14214
+ skipped: number
14215
+ }
14216
+ /**
14217
+ * One deterministic doctor check result.
14218
+ */
14219
+ export interface DoctorCheck {
14220
+ id: DoctorCheckId
14221
+ category: DoctorCheckCategory
14222
+ status: DoctorCheckStatus
14223
+ /**
14224
+ * Whether failure makes the project not ready.
14225
+ */
14226
+ required: boolean
14227
+ /**
14228
+ * Human-readable result with no host-specific absolute paths.
14229
+ */
14230
+ message: string
14231
+ /**
14232
+ * Optional actionable next command.
14233
+ */
14234
+ remediation?: (DoctorRemediation | null)
14235
+ }
14236
+ /**
14237
+ * Actionable remediation attached to a doctor check.
14238
+ */
14239
+ export interface DoctorRemediation {
14240
+ /**
14241
+ * Command the user or agent can choose to run.
14242
+ */
14243
+ command: string
14244
+ cwd: DoctorProjectRoot
14245
+ /**
14246
+ * Whether running the command can modify project files or dependencies.
14247
+ */
14248
+ mutating: boolean
14249
+ }
13519
14250
  /**
13520
14251
  * Envelope emitted by `fallow type-aware status --format json`.
13521
14252
  */
@@ -14121,6 +14852,12 @@ severity: CodeClimateSeverity
14121
14852
  */
14122
14853
  fingerprint: string
14123
14854
  location: CodeClimateLocation
14855
+ /**
14856
+ * Other source locations that provide evidence for the finding. GitLab's
14857
+ * Code Quality widget ignores this standard CodeClimate field, but Fallow
14858
+ * preserves it for review-comment rendering.
14859
+ */
14860
+ other_locations?: CodeClimateLocation[]
14124
14861
  /**
14125
14862
  * Optional owner attribution used by grouped dead-code output.
14126
14863
  */
@@ -14142,13 +14879,17 @@ path: string
14142
14879
  lines: CodeClimateLines
14143
14880
  }
14144
14881
  /**
14145
- * `lines.begin` for [`CodeClimateLocation`].
14882
+ * Inclusive line range for [`CodeClimateLocation`].
14146
14883
  */
14147
14884
  export interface CodeClimateLines {
14148
14885
  /**
14149
14886
  * 1-based start line.
14150
14887
  */
14151
14888
  begin: number
14889
+ /**
14890
+ * Inclusive 1-based end line. Omitted for point findings.
14891
+ */
14892
+ end?: (number | null)
14152
14893
  }
14153
14894
  /**
14154
14895
  * Structured JSON error emitted on stdout when `--format json` is active and a
@@ -14172,6 +14913,16 @@ message: string
14172
14913
  * The process exit code the CLI returns alongside this document.
14173
14914
  */
14174
14915
  exit_code: number
14916
+ /**
14917
+ * Stable machine-readable code such as `FALLOW_INVALID_COVERAGE_PATH`,
14918
+ * when the failure has one. Present so an agent can branch on the reason
14919
+ * without pattern-matching the human message.
14920
+ */
14921
+ code?: (string | null)
14922
+ /**
14923
+ * Remediation hint for the caller, when the failure has one.
14924
+ */
14925
+ help?: (string | null)
14175
14926
  }
14176
14927
 
14177
14928