fallow 3.23.0 → 3.24.1

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`, `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.
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 & {
@@ -110,7 +112,7 @@ kind: "similar-code-review"
110
112
  /**
111
113
  * Schema projection for the audit envelope's exact version.
112
114
  */
113
- export type AuditSchemaVersion = 10
115
+ export type AuditSchemaVersion = 11
114
116
  /**
115
117
  * Fallow CLI version that produced this envelope. Renders to the JSON wire as
116
118
  * a bare string (e.g. `"2.74.0"`).
@@ -289,6 +291,30 @@ export type AddToConfigValue = (string | IgnoreExportsRule[] | {
289
291
  * hold `Option<AuditIntroduced>`. Renders to the JSON wire as a bare boolean.
290
292
  */
291
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")
292
318
  /**
293
319
  * Where in package.json a dependency is listed.
294
320
  *
@@ -452,11 +478,28 @@ kind: "skipped-source-dotdir"
452
478
  error: string
453
479
  kind: "source-read-failure"
454
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
+ } | {
455
492
  kind: "bun-lockb-override-resolution-skipped"
456
493
  } | {
457
494
  kind: "bun-lock-override-resolution-skipped"
458
495
  } | {
459
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"
460
503
  })
461
504
  /**
462
505
  * Discriminant for [`CloneGroupAction::kind`]. Mirrors the action types
@@ -577,6 +620,14 @@ export type HotspotActionType = ("refactor-file" | "add-tests" | "low-bus-factor
577
620
  * an `unowned-hotspot` action.
578
621
  */
579
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")
580
631
  /**
581
632
  * Runtime coverage JSON contract version. This is scoped to the
582
633
  * `runtime_coverage` block and is independent of the top-level fallow
@@ -773,10 +824,37 @@ export type InspectSectionStatus = ("ok" | "partial" | "unavailable" | "error")
773
824
  * Granularity an [`InspectEvidenceSection`] payload covers.
774
825
  */
775
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"
776
834
  /**
777
835
  * Best-effort classification of why a callee did not resolve to an edge.
778
836
  */
779
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")
780
858
  /**
781
859
  * Singleton GitHub review-event marker.
782
860
  */
@@ -859,7 +937,7 @@ export type GroupByMode = ("owner" | "directory" | "package" | "section")
859
937
  * Schema projection for the duplication envelope's CLI and programmatic
860
938
  * version lineages.
861
939
  */
862
- export type DupesSchemaVersion = (3 | 9)
940
+ export type DupesSchemaVersion = (4 | 10)
863
941
  /**
864
942
  * Wire-version discriminator for [`ImpactReport`]. Independent from the global
865
943
  * `SchemaVersion` (the impact report versions on its own cadence) and from the
@@ -971,7 +1049,7 @@ export type SecurityBlindSpotsSchemaVersion = "1"
971
1049
  /**
972
1050
  * Schema projection for the combined envelope's exact version.
973
1051
  */
974
- export type CombinedSchemaVersion = 11
1052
+ export type CombinedSchemaVersion = 12
975
1053
  /**
976
1054
  * Schema projection for the feature-flags envelope's exact version.
977
1055
  */
@@ -992,7 +1070,7 @@ export type FeatureFlagActionType = ("investigate-flag" | "suppress-line")
992
1070
  * Independently-versioned wire-version newtype for the brief envelope.
993
1071
  * Serializes as the integer `REVIEW_BRIEF_SCHEMA_VERSION`.
994
1072
  */
995
- export type ReviewBriefSchemaVersion = 8
1073
+ export type ReviewBriefSchemaVersion = 10
996
1074
  /**
997
1075
  * The exactly-three shippable decision categories (the SOLID-3). No cut category
998
1076
  * (abstraction / deletion / convention / irreversibility) is representable: this
@@ -1064,7 +1142,7 @@ export type SuppressionInventoryOrigin = "comment"
1064
1142
  /**
1065
1143
  * Schema projection for the exact doctor envelope version.
1066
1144
  */
1067
- export type DoctorSchemaVersion = 1
1145
+ export type DoctorSchemaVersion = 2
1068
1146
  /**
1069
1147
  * Schema projection for `.` as the privacy-safe diagnosed project root.
1070
1148
  */
@@ -1076,11 +1154,11 @@ export type DoctorStatus = ("pass" | "warn" | "fail")
1076
1154
  /**
1077
1155
  * Stable identifier for a doctor check. Declaration order is output order.
1078
1156
  */
1079
- export type DoctorCheckId = ("root" | "config" | "workspaces" | "plugins" | "type-aware")
1157
+ export type DoctorCheckId = ("root" | "config" | "workspaces" | "plugins" | "type-aware" | "dependencies" | "cache" | "graph-cache")
1080
1158
  /**
1081
1159
  * Stable category for a doctor check.
1082
1160
  */
1083
- export type DoctorCheckCategory = ("project" | "configuration" | "workspace" | "plugin" | "companion")
1161
+ export type DoctorCheckCategory = ("project" | "configuration" | "workspace" | "plugin" | "companion" | "cache")
1084
1162
  /**
1085
1163
  * Per-check readiness outcome.
1086
1164
  */
@@ -2585,7 +2663,7 @@ _meta?: (Meta | null)
2585
2663
  * `malformed-tsconfig`, `tsconfig-reference-dir-missing`;
2586
2664
  * - source discovery, during the file walk: `skipped-large-file`,
2587
2665
  * `skipped-minified-file`, `skipped-source-dotdir`,
2588
- * `source-read-failure`;
2666
+ * `source-read-failure`, `source-parse-degraded`;
2589
2667
  * - dead-code analysis, from the dependency-catalog and override
2590
2668
  * detectors: `malformed-pnpm-workspace-yaml`,
2591
2669
  * `bun-lockb-override-resolution-skipped`.
@@ -2596,6 +2674,16 @@ _meta?: (Meta | null)
2596
2674
  * forward slashes; the array is omitted when empty. The same list is
2597
2675
  * repeated on each top-level command's envelope so single-command
2598
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.
2599
2687
  */
2600
2688
  workspace_diagnostics?: WorkspaceDiagnostic[]
2601
2689
  /**
@@ -2833,6 +2921,14 @@ actions: IssueAction[]
2833
2921
  * the merge-base. `None` when serialized directly from Rust.
2834
2922
  */
2835
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[]
2836
2932
  }
2837
2933
  /**
2838
2934
  * A code-change fix. `type` is one of the kebab-case identifiers in
@@ -2851,6 +2947,14 @@ type: FixActionType
2851
2947
  * Filter on this bool of each individual action, not on `type`. See the
2852
2948
  * [`IssueAction`] enum-level docs for the full list of per-instance
2853
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`].
2854
2958
  */
2855
2959
  auto_fixable: boolean
2856
2960
  /**
@@ -3034,6 +3138,13 @@ semantic?: (SemanticCandidateDecision | null)
3034
3138
  * the merge-base.
3035
3139
  */
3036
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[]
3037
3148
  }
3038
3149
  /**
3039
3150
  * Wire-shape envelope for an [`UnusedExport`] finding consumed under the
@@ -3084,6 +3195,14 @@ semantic?: (SemanticCandidateDecision | null)
3084
3195
  * the merge-base.
3085
3196
  */
3086
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[]
3087
3206
  }
3088
3207
  /**
3089
3208
  * Wire-shape envelope for a [`PrivateTypeLeak`] finding. Mirrors
@@ -3167,6 +3286,15 @@ actions: IssueAction[]
3167
3286
  * the merge-base.
3168
3287
  */
3169
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[]
3170
3298
  }
3171
3299
  /**
3172
3300
  * Wire-shape envelope for an [`UnusedDependency`] finding consumed under
@@ -3204,6 +3332,15 @@ actions: IssueAction[]
3204
3332
  * the merge-base.
3205
3333
  */
3206
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[]
3207
3344
  }
3208
3345
  /**
3209
3346
  * Wire-shape envelope for an [`UnusedDependency`] finding consumed under
@@ -3241,6 +3378,15 @@ actions: IssueAction[]
3241
3378
  * the merge-base.
3242
3379
  */
3243
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[]
3244
3390
  }
3245
3391
  /**
3246
3392
  * Wire-shape envelope for an [`UnusedMember`] finding consumed under the
@@ -3278,6 +3424,15 @@ actions: IssueAction[]
3278
3424
  * the merge-base.
3279
3425
  */
3280
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[]
3281
3436
  }
3282
3437
  /**
3283
3438
  * Wire-shape envelope for an [`UnusedMember`] finding consumed under the
@@ -3321,6 +3476,16 @@ semantic?: (SemanticCandidateDecision | null)
3321
3476
  * the merge-base.
3322
3477
  */
3323
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[]
3324
3489
  }
3325
3490
  /**
3326
3491
  * Wire-shape envelope for an [`UnusedMember`] finding consumed under the
@@ -3364,6 +3529,17 @@ actions: IssueAction[]
3364
3529
  * the merge-base.
3365
3530
  */
3366
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[]
3367
3543
  }
3368
3544
  /**
3369
3545
  * Wire-shape envelope for an [`UnresolvedImport`] finding. Mirrors
@@ -5083,8 +5259,13 @@ start_col: number
5083
5259
  end_col: number
5084
5260
  /**
5085
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.
5086
5267
  */
5087
- fragment: string
5268
+ fragment?: string
5088
5269
  }
5089
5270
  /**
5090
5271
  * Per-action wire shape attached to each `CloneGroupFinding` and
@@ -5249,13 +5430,21 @@ total_tokens: number
5249
5430
  */
5250
5431
  duplicated_tokens: number
5251
5432
  /**
5252
- * Number of clone groups in the reported `clone_groups[]` array after
5253
- * 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.
5254
5436
  */
5255
5437
  clone_groups: number
5256
5438
  /**
5257
- * Total clone instances across all reported groups after filtering and
5258
- * 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.
5259
5448
  */
5260
5449
  clone_instances: number
5261
5450
  /**
@@ -5335,7 +5524,11 @@ prop_drilling_chains?: PropDrillingChainFinding[]
5335
5524
  */
5336
5525
  hotspots?: HotspotFinding[]
5337
5526
  /**
5338
- * 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.
5339
5532
  */
5340
5533
  hotspot_summary?: (HotspotSummary | null)
5341
5534
  /**
@@ -5728,13 +5921,11 @@ export interface HealthSummary {
5728
5921
  */
5729
5922
  files_analyzed: number
5730
5923
  /**
5731
- * Real functions scored across the analyzed files. This counts functions
5732
- * only, so it is smaller than the sum of `file_scores[].function_count`,
5733
- * which also counts the synthetic per-file units (`<module>` for
5734
- * module-scope branching, `<template>` and `<snippet:NAME>` for component
5735
- * templates). The complexity aggregates below, including
5736
- * `average_cyclomatic` and `p90_cyclomatic`, are computed over that larger
5737
- * 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.
5738
5929
  */
5739
5930
  functions_analyzed: number
5740
5931
  /**
@@ -5969,18 +6160,24 @@ dead_file_pct?: (number | null)
5969
6160
  */
5970
6161
  dead_export_pct?: (number | null)
5971
6162
  /**
5972
- * 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.
5973
6165
  */
5974
6166
  avg_cyclomatic: number
5975
6167
  /**
5976
- * Percentage of functions at or above the critical cyclomatic threshold.
6168
+ * Percentage of complexity units at or above the critical cyclomatic threshold.
5977
6169
  * Used by the scale-invariant health score.
5978
6170
  */
5979
6171
  critical_complexity_pct?: (number | null)
5980
6172
  /**
5981
- * 90th percentile cyclomatic complexity.
6173
+ * 90th percentile cyclomatic complexity across the same unit population.
5982
6174
  */
5983
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)
5984
6181
  /**
5985
6182
  * Code duplication percentage (None if duplication pipeline was not run).
5986
6183
  */
@@ -6094,6 +6291,33 @@ top_render_fan_in?: RenderFanInTopComponent[]
6094
6291
  */
6095
6292
  total_loc?: number
6096
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
+ }
6097
6321
  /**
6098
6322
  * Raw counts backing the vital signs percentages.
6099
6323
  *
@@ -6310,15 +6534,15 @@ complexity_density: number
6310
6534
  */
6311
6535
  maintainability_index: number
6312
6536
  /**
6313
- * Summed cyclomatic complexity over the file's functions.
6537
+ * Summed cyclomatic complexity over all units, including module and template scope.
6314
6538
  */
6315
6539
  total_cyclomatic: number
6316
6540
  /**
6317
- * Summed cognitive complexity over the file's functions.
6541
+ * Summed cognitive complexity over all units, including module and template scope.
6318
6542
  */
6319
6543
  total_cognitive: number
6320
6544
  /**
6321
- * Functions in the file.
6545
+ * Complexity units in the file, including synthetic module and template units.
6322
6546
  */
6323
6547
  function_count: number
6324
6548
  /**
@@ -6712,6 +6936,32 @@ files_excluded: number
6712
6936
  * truncated.
6713
6937
  */
6714
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
6715
6965
  }
6716
6966
  /**
6717
6967
  * Runtime coverage findings merged into the health report or emitted by
@@ -6941,6 +7191,16 @@ static_status: string
6941
7191
  * `not_covered` otherwise.
6942
7192
  */
6943
7193
  test_coverage: string
7194
+ /**
7195
+ * `true` when the function is unreachable in the production module graph
7196
+ * but still referenced from a file that production mode excludes (test,
7197
+ * spec, story, fixture, or benchmark). Such a function is not dead code:
7198
+ * removing it breaks the referencing test. `false` when the production
7199
+ * graph was compared against the full tree and no such reference exists.
7200
+ * `null` when the report was produced without a production filter, or by
7201
+ * a surface that carries no second reachability answer.
7202
+ */
7203
+ test_only_reference?: (boolean | null)
6944
7204
  /**
6945
7205
  * `tracked` when V8 observed the function, `untracked` otherwise.
6946
7206
  */
@@ -9537,6 +9797,68 @@ consumed_symbols: string[]
9537
9797
  */
9538
9798
  note: string
9539
9799
  }
9800
+ /**
9801
+ * Result of asking how one module reaches another: the shortest import path.
9802
+ *
9803
+ * `reachable` is the only field that separates "no route exists" from "the
9804
+ * route is empty because both ends are the same module". Both report
9805
+ * `hops: 0`, so a consumer must read `reachable`, never the hop count.
9806
+ */
9807
+ export interface ImportPathTrace {
9808
+ schema_version: ImportPathTraceSchemaVersion
9809
+ /**
9810
+ * The module the walk started from, root-relative.
9811
+ */
9812
+ from: string
9813
+ /**
9814
+ * The module the walk was looking for, root-relative.
9815
+ */
9816
+ to: string
9817
+ /**
9818
+ * Whether `to` is reachable from `from` by following import edges.
9819
+ */
9820
+ reachable: boolean
9821
+ /**
9822
+ * Number of import edges on the reported route. `0` both when the two ends
9823
+ * are the same module and when there is no route at all.
9824
+ */
9825
+ hops: number
9826
+ /**
9827
+ * The route, in import order. Empty whenever `hops` is `0`.
9828
+ */
9829
+ path: ImportPathHop[]
9830
+ /**
9831
+ * Human-readable summary of the outcome.
9832
+ */
9833
+ reason: string
9834
+ }
9835
+ /**
9836
+ * One import edge on an [`ImportPathTrace`].
9837
+ */
9838
+ export interface ImportPathHop {
9839
+ /**
9840
+ * The importing module, root-relative.
9841
+ */
9842
+ from: string
9843
+ /**
9844
+ * The imported module, root-relative.
9845
+ */
9846
+ to: string
9847
+ /**
9848
+ * Whether every symbol on this edge is type-only, so the hop is erased at
9849
+ * build time. Type-only hops are reported, never skipped: an `import type`
9850
+ * chain is a real compile-time coupling.
9851
+ */
9852
+ type_only: boolean
9853
+ /**
9854
+ * 1-based line in `from` of the imported binding that creates this edge:
9855
+ * the first value-carrying symbol on the import, or the first symbol when
9856
+ * every symbol is type-only. On a multi-line import that is the binding's
9857
+ * own line, not the `import` keyword's. Absent when the edge carries no
9858
+ * span or the source could not be read.
9859
+ */
9860
+ import_line?: (number | null)
9861
+ }
9540
9862
  /**
9541
9863
  * The result of a symbol-level call-chain trace. Its own surface (`kind:
9542
9864
  * "trace"`), NOT folded into the ranked brief.
@@ -9632,6 +9954,195 @@ export interface UnresolvedCallee {
9632
9954
  callee: string
9633
9955
  reason: UnresolvedReason
9634
9956
  }
9957
+ /**
9958
+ * Result of resolving a runtime stack trace against the project graph.
9959
+ */
9960
+ export interface ErrorTrace {
9961
+ schema_version: ErrorTraceSchemaVersion
9962
+ /**
9963
+ * Where the trace was read from: `stdin`, or the path as the caller wrote
9964
+ * it.
9965
+ */
9966
+ source: string
9967
+ /**
9968
+ * The first non-blank input line that preceded any recognised frame,
9969
+ * verbatim. Conventionally the error type and message, but it is reported
9970
+ * as read and NOT parsed into parts. Absent when the input began with a
9971
+ * frame or was empty.
9972
+ */
9973
+ header?: (string | null)
9974
+ /**
9975
+ * Every recognised frame, in input order. Nothing is filtered out: a
9976
+ * dependency or runtime-internal frame stays in the array with its origin
9977
+ * recorded, so hop numbering matches the trace the caller pasted.
9978
+ */
9979
+ frames: ErrorTraceFrame[]
9980
+ counts: ErrorTraceCounts
9981
+ /**
9982
+ * Human-readable summary of the outcome.
9983
+ */
9984
+ reason: string
9985
+ }
9986
+ /**
9987
+ * One frame read from the input stack trace.
9988
+ */
9989
+ export interface ErrorTraceFrame {
9990
+ /**
9991
+ * 0-based position in the input trace, so a caller can quote a frame back
9992
+ * even after filtering the array.
9993
+ */
9994
+ index: number
9995
+ /**
9996
+ * The input line this frame was read from, trimmed of surrounding
9997
+ * whitespace and otherwise verbatim.
9998
+ */
9999
+ raw: string
10000
+ /**
10001
+ * The frame's function identifier as written by the runtime, with the
10002
+ * `async` and `new` markers stripped and recorded separately. Absent for a
10003
+ * frame the runtime emitted without one.
10004
+ */
10005
+ function?: (string | null)
10006
+ /**
10007
+ * Whether the runtime marked this frame as a constructor call (`new X`).
10008
+ */
10009
+ is_constructor?: boolean
10010
+ /**
10011
+ * Whether the runtime marked this frame as an async call.
10012
+ */
10013
+ is_async?: boolean
10014
+ /**
10015
+ * The frame's file as read from the trace, with any `file://` or
10016
+ * `http(s)://` wrapper removed and separators forward-slashed. Reported as
10017
+ * read: it is NOT rewritten to the module path it matched, so a caller can
10018
+ * see what its runtime actually said. Absent for a frame with no location.
10019
+ */
10020
+ file?: (string | null)
10021
+ /**
10022
+ * 1-based line from the frame's location, when the runtime supplied one.
10023
+ */
10024
+ line?: (number | null)
10025
+ /**
10026
+ * 1-based column from the frame's location, when the runtime supplied one.
10027
+ */
10028
+ column?: (number | null)
10029
+ origin: FrameOrigin
10030
+ resolution: FrameResolution
10031
+ /**
10032
+ * Every definition the identifier could name, in deterministic order.
10033
+ * Exactly one entry when `resolution` is `resolved`, more than one when it
10034
+ * is `ambiguous`, and empty otherwise.
10035
+ */
10036
+ candidates: ErrorTraceCandidate[]
10037
+ /**
10038
+ * How many further candidates a presentation cap withheld.
10039
+ * `candidates.len() + candidates_omitted` is the true match count, so an
10040
+ * `ambiguous` frame never understates how ambiguous it is.
10041
+ */
10042
+ candidates_omitted: number
10043
+ /**
10044
+ * Set when this frame's own line disagrees with the definition its
10045
+ * identifier matched: some OTHER definition in the same file is declared
10046
+ * closer above the line the runtime reported.
10047
+ *
10048
+ * The look-up matches on the identifier alone, so a `resolved` frame is
10049
+ * resolved however far its line sits from the match. That is honest about
10050
+ * the question asked and silent about a question a reader would ask next,
10051
+ * which is why the disagreement is published instead of left to be
10052
+ * noticed. The frame is NOT reclassified: the graph does know a
10053
+ * definition under this identifier, and only the caller can say whether
10054
+ * the runtime ran that one or a same-named definition elsewhere.
10055
+ * `reason` names the declaration that sits closer. Only set on a
10056
+ * `resolved` frame that carried a line and matched a definition whose own
10057
+ * line could be read.
10058
+ */
10059
+ line_mismatch?: boolean
10060
+ /**
10061
+ * Human-readable statement of what happened to this frame.
10062
+ */
10063
+ reason: string
10064
+ }
10065
+ /**
10066
+ * One definition a frame's identifier could name.
10067
+ */
10068
+ export interface ErrorTraceCandidate {
10069
+ /**
10070
+ * Root-relative file declaring the definition.
10071
+ */
10072
+ file: string
10073
+ /**
10074
+ * The exported name. For a member match this is the owning export.
10075
+ */
10076
+ symbol: string
10077
+ /**
10078
+ * The member name, when the frame's identifier named a member of
10079
+ * `symbol` rather than `symbol` itself. Absent for a direct export match.
10080
+ */
10081
+ member?: (string | null)
10082
+ /**
10083
+ * What kind of definition this is: `export`, or the member kind
10084
+ * (`class-method`, `class-property`, `enum-member`, `store-member`,
10085
+ * `namespace-member`).
10086
+ */
10087
+ kind: string
10088
+ /**
10089
+ * 1-based declaration line of the definition's identifier. Absent when the
10090
+ * source file could not be read; never guessed.
10091
+ */
10092
+ line?: (number | null)
10093
+ }
10094
+ /**
10095
+ * Per-outcome totals for an [`ErrorTrace`].
10096
+ *
10097
+ * `resolved + ambiguous + not_found + not_attempted == frames`, and
10098
+ * `in_project + node_modules + out_of_corpus == frames`. Both identities hold
10099
+ * on every run, so a caller can verify that nothing was dropped.
10100
+ */
10101
+ export interface ErrorTraceCounts {
10102
+ /**
10103
+ * Frames reported in `frames`.
10104
+ */
10105
+ frames: number
10106
+ /**
10107
+ * Frames a cap withheld from `frames`. Their outcomes are NOT counted in
10108
+ * the fields below, which describe the reported frames only.
10109
+ */
10110
+ frames_omitted: number
10111
+ /**
10112
+ * Frames whose file resolved to project source.
10113
+ */
10114
+ in_project: number
10115
+ /**
10116
+ * Frames whose file lives under an installed dependency tree.
10117
+ */
10118
+ node_modules: number
10119
+ /**
10120
+ * Frames outside the analysed corpus, including frames with no location.
10121
+ */
10122
+ out_of_corpus: number
10123
+ /**
10124
+ * Frames that matched exactly one definition.
10125
+ */
10126
+ resolved: number
10127
+ /**
10128
+ * Frames that matched more than one definition.
10129
+ */
10130
+ ambiguous: number
10131
+ /**
10132
+ * Frames the graph was asked about and could not name.
10133
+ */
10134
+ not_found: number
10135
+ /**
10136
+ * Frames the graph was never asked about.
10137
+ */
10138
+ not_attempted: number
10139
+ /**
10140
+ * Non-blank input lines that were neither recognised as a frame nor taken
10141
+ * as `header`. A trace that is entirely unrecognised reports zero frames
10142
+ * and a non-zero count here, rather than looking like an empty trace.
10143
+ */
10144
+ unparsed_lines: number
10145
+ }
9635
10146
  /**
9636
10147
  * Envelope emitted by `fallow --format review-github` / `review-gitlab`.
9637
10148
  */
@@ -10205,7 +10716,11 @@ prop_drilling_chains?: PropDrillingChainFinding[]
10205
10716
  */
10206
10717
  hotspots?: HotspotFinding[]
10207
10718
  /**
10208
- * Hotspot analysis summary (only set with `--hotspots`).
10719
+ * Hotspot analysis summary.
10720
+ *
10721
+ * Set whenever the run measured churn, which needs readable git history;
10722
+ * `--hotspots` adds the per-file [`hotspots`](Self::hotspots) listing
10723
+ * beside it rather than gating this summary.
10209
10724
  */
10210
10725
  hotspot_summary?: (HotspotSummary | null)
10211
10726
  /**
@@ -10420,6 +10935,29 @@ clone_families: CloneFamilyFinding[]
10420
10935
  */
10421
10936
  mirrored_directories?: MirroredDirectory[]
10422
10937
  stats: DuplicationStats
10938
+ /**
10939
+ * Number of clone groups carried in `clone_groups[]`.
10940
+ */
10941
+ clone_groups_shown: number
10942
+ /**
10943
+ * Number of scoped-corpus clone groups withheld from `clone_groups[]` by
10944
+ * a presentation cap such as `--top`. `0` on an untruncated run, so
10945
+ * `clone_groups_shown + clone_groups_omitted == stats.clone_groups`
10946
+ * always holds and `stats` keeps describing the whole measured corpus.
10947
+ */
10948
+ clone_groups_omitted: number
10949
+ /**
10950
+ * Number of clone families carried in `clone_families[]`.
10951
+ */
10952
+ clone_families_shown: number
10953
+ /**
10954
+ * Number of scoped-corpus clone families withheld from `clone_families[]`
10955
+ * by a presentation cap such as `--top`, which rebuilds the families from
10956
+ * the groups that survived the cap. `0` on an untruncated run, so
10957
+ * `clone_families_shown + clone_families_omitted == stats.clone_families`
10958
+ * always holds and `stats` keeps describing the whole measured corpus.
10959
+ */
10960
+ clone_families_omitted: number
10423
10961
  /**
10424
10962
  * Grouping mode when `--group-by` was passed.
10425
10963
  */
@@ -10556,8 +11094,13 @@ start_col: number
10556
11094
  end_col: number
10557
11095
  /**
10558
11096
  * The actual source code fragment.
11097
+ *
11098
+ * Omitted from JSON when the caller asked for a location-only payload
11099
+ * (`fallow dupes --no-fragments`, and the MCP `find_dupes` default). The
11100
+ * five location fields above address the same text, so a consumer that
11101
+ * wants the source reads it from the file.
10559
11102
  */
10560
- fragment: string
11103
+ fragment?: string
10561
11104
  /**
10562
11105
  * Resolver key for this specific instance (per-instance, not the
10563
11106
  * group-level largest-owner).
@@ -11008,6 +11551,13 @@ project_surfacing?: (ImpactCounts | null)
11008
11551
  * `trend`. None until two full `fallow` runs exist. v1.6.
11009
11552
  */
11010
11553
  project_trend?: (TrendSummary | null)
11554
+ /**
11555
+ * Recorded gate runs grouped by source, over the same bounded window of
11556
+ * recorded runs `record_count` reports. A floor, not a lifetime total, and
11557
+ * absent when no run in that window carries a gate source. Local
11558
+ * provenance, never an adoption metric.
11559
+ */
11560
+ gate_runs?: (GateRunCounts | null)
11011
11561
  /**
11012
11562
  * Lifetime count of commit-gate containment events.
11013
11563
  */
@@ -11089,6 +11639,37 @@ previous_total: number
11089
11639
  */
11090
11640
  current_total: number
11091
11641
  }
11642
+ /**
11643
+ * Recorded gate runs grouped by the gate that produced them. Local
11644
+ * provenance only: the store never leaves the machine, so this answers "where
11645
+ * do my gate runs come from", never "how widely is fallow adopted".
11646
+ *
11647
+ * Counted over the recorded runs the store still holds, which is the same
11648
+ * window `record_count` reports. The store keeps a bounded number of runs and
11649
+ * drops the oldest, so on a long-lived project these are the shape of recent
11650
+ * gate activity, not a lifetime total: read them as a floor. Absent when no
11651
+ * run in that window carries a gate source, which is not the same as "no gate
11652
+ * ever ran here".
11653
+ */
11654
+ export interface GateRunCounts {
11655
+ /**
11656
+ * Runs recorded by the agent gate (`--gate-marker agent`).
11657
+ */
11658
+ agent: number
11659
+ /**
11660
+ * Runs recorded by the git pre-commit hook (`--gate-marker pre-commit`).
11661
+ */
11662
+ pre_commit: number
11663
+ /**
11664
+ * Runs recorded by a CI gate (`--gate-marker ci`).
11665
+ */
11666
+ ci: number
11667
+ /**
11668
+ * Gate runs whose marker this build does not recognise, plus every gate
11669
+ * run recorded before the store kept its source (store schema 6 and older).
11670
+ */
11671
+ unknown: number
11672
+ }
11092
11673
  /**
11093
11674
  * A commit-gate containment event recorded by `fallow impact`.
11094
11675
  */
@@ -12189,6 +12770,24 @@ feature_flags: FeatureFlagFinding[]
12189
12770
  * Number of entries in `feature_flags`.
12190
12771
  */
12191
12772
  total_flags: number
12773
+ /**
12774
+ * Workspace-discovery and source-discovery diagnostics for the run. See
12775
+ * `CheckOutput::workspace_diagnostics` for the full contract.
12776
+ *
12777
+ * A flags run walks and parses the project like every other analysis, so
12778
+ * it records the same discovery kinds: a `skipped-large-file`,
12779
+ * `skipped-minified-file`, or `source-read-failure` file was never
12780
+ * scanned for flags, and a `source-parse-degraded` file was scanned from
12781
+ * a partial module. Each is a reason a flag can be missing from
12782
+ * `feature_flags[]`, which is exactly what a consumer reading a
12783
+ * zero-result run needs to know. The analysis-stage kinds appear here
12784
+ * too: the scan correlates flags with dead exports, so it runs the
12785
+ * dead-code analyze pass that records them.
12786
+ *
12787
+ * Omitted when empty, so a project with no discovery noise sees no
12788
+ * change.
12789
+ */
12790
+ workspace_diagnostics?: WorkspaceDiagnostic[]
12192
12791
  /**
12193
12792
  * `_meta` block; see [`FeatureFlagsMeta`].
12194
12793
  */
@@ -12530,12 +13129,11 @@ review_effort: ReviewEffort
12530
13129
  /**
12531
13130
  * Stage 1 of the brief: graph-derived orientation facts.
12532
13131
  *
12533
- * `boundaries_touched` is derived from the run's boundary-violation zones;
12534
- * `reachable_from` is populated by the impact closure (the affected-not-shown
12535
- * set: modules the changed code is reachable from / affects, none in the diff).
12536
- * `exports_added` and `api_width_delta` both report the exports-aware public API
12537
- * widening count. Removed exports are not represented in this widening-only
12538
- * signal.
13132
+ * `boundaries_touched` is derived from the run's boundary-violation zones.
13133
+ * `exports_added` and `api_width_delta` both report the exports-aware public
13134
+ * API widening count. Removed exports are not represented in this
13135
+ * widening-only signal. The set of modules the changed code reaches is Stage
13136
+ * 3's `impact_closure`, which owns both its magnitude and its paths.
12539
13137
  */
12540
13138
  export interface GraphFacts {
12541
13139
  /**
@@ -12549,12 +13147,6 @@ exports_added: number
12549
13147
  * were added.
12550
13148
  */
12551
13149
  api_width_delta: number
12552
- /**
12553
- * Root-relative paths of modules the changed code is reachable from / affects
12554
- * (the impact closure's affected-but-not-in-diff set), deduped and sorted.
12555
- * Empty when no graph was retained or nothing depends on the changed files.
12556
- */
12557
- reachable_from: string[]
12558
13150
  /**
12559
13151
  * Architecture boundary zones touched by the changeset, deduped and sorted.
12560
13152
  * Derived from the run's boundary-violation findings.
@@ -12619,16 +13211,65 @@ files: string[]
12619
13211
  */
12620
13212
  export interface ImpactClosureFacts {
12621
13213
  /**
12622
- * Root-relative paths transitively affected by the changeset (reverse-deps +
12623
- * re-export chains) that are NOT in the diff, deduped and sorted.
13214
+ * The FULL number of files transitively affected by the changeset
13215
+ * (reverse-deps + re-export chains) that are NOT in the diff. Computed
13216
+ * BEFORE [`affected_not_shown`](Self::affected_not_shown) is capped to a
13217
+ * sample, so it is always the true magnitude of the blast radius.
13218
+ */
13219
+ affected_count: number
13220
+ /**
13221
+ * A capped, path-sorted sample of the affected root-relative paths (at most
13222
+ * [`AFFECTED_SAMPLE_CAP`]), deduped. The full count lives in
13223
+ * [`affected_count`](Self::affected_count) and the distribution in
13224
+ * [`affected_by_dir`](Self::affected_by_dir); use this list to jump to
13225
+ * representative files, NEVER to enumerate the blast radius or to infer its
13226
+ * shape. Because it is a prefix of the sorted set, it clusters in whichever
13227
+ * directory sorts first. To reconstruct the full set, run
13228
+ * `fallow check --impact-closure <path>` once per changed file and union the
13229
+ * results: that flag seeds from a single file, so no single command
13230
+ * reproduces this changeset-wide union.
12624
13231
  */
12625
13232
  affected_not_shown: string[]
13233
+ /**
13234
+ * The blast radius rolled up by parent directory: how the affected files
13235
+ * distribute, heaviest directory first, ties broken by directory path so the
13236
+ * order is deterministic. This is the SHAPE signal, and unlike
13237
+ * [`affected_not_shown`](Self::affected_not_shown) its counts are exact for
13238
+ * every directory it lists. At most [`AFFECTED_DIR_CAP`] entries.
13239
+ */
13240
+ affected_by_dir: AffectedDirectory[]
13241
+ /**
13242
+ * How many directories did not fit within [`AFFECTED_DIR_CAP`] and are
13243
+ * absent from [`affected_by_dir`](Self::affected_by_dir). They are the
13244
+ * lightest ones; their files are still counted in
13245
+ * [`affected_count`](Self::affected_count). Zero when nothing was omitted.
13246
+ * Add this to `affected_by_dir.len()` for the true number of directories
13247
+ * the change reaches.
13248
+ */
13249
+ affected_by_dir_omitted: number
12626
13250
  /**
12627
13251
  * Coordination gaps: a changed file exports a contract consumed by a module
12628
- * absent from the diff. One entry per (changed file, consumer) pair.
13252
+ * absent from the diff. One entry per (changed file, consumer) pair. NOT a
13253
+ * subset of [`affected_not_shown`](Self::affected_not_shown): the gap
13254
+ * deliberately skips story and test consumers that the affected set counts.
12629
13255
  */
12630
13256
  coordination_gap: CoordinationGapFact[]
12631
13257
  }
13258
+ /**
13259
+ * One directory of the blast radius and how many affected files it holds.
13260
+ */
13261
+ export interface AffectedDirectory {
13262
+ /**
13263
+ * Root-relative parent directory, forward-slashed. The empty string is the
13264
+ * repository root.
13265
+ */
13266
+ dir: string
13267
+ /**
13268
+ * How many affected-but-not-in-diff files live directly in `dir`. Exact,
13269
+ * never sampled.
13270
+ */
13271
+ count: number
13272
+ }
12632
13273
  /**
12633
13274
  * One coordination-gap entry: a changed file exports symbols consumed by a
12634
13275
  * `consumer_file` that is NOT in the diff. Deduped per (changed, consumer) pair
@@ -12708,8 +13349,13 @@ fan_io: number
12708
13349
  /**
12709
13350
  * Security source -> sink taint-touch component (0 until a security pass is
12710
13351
  * threaded onto the brief path; the seam is built and tested).
13352
+ *
13353
+ * Omitted from the wire while it is zero, the same treatment `runtime`
13354
+ * gets. Publishing a permanently-zero component as a required field made
13355
+ * it read as a measurement that found nothing, when nothing measured it.
13356
+ * A consumer that sums components must read an absent component as zero.
12711
13357
  */
12712
- security_taint: number
13358
+ security_taint?: number
12713
13359
  /**
12714
13360
  * Risk-zone component (boundary / public-API / security-sensitive).
12715
13361
  */
@@ -14277,6 +14923,16 @@ message: string
14277
14923
  * The process exit code the CLI returns alongside this document.
14278
14924
  */
14279
14925
  exit_code: number
14926
+ /**
14927
+ * Stable machine-readable code such as `FALLOW_INVALID_COVERAGE_PATH`,
14928
+ * when the failure has one. Present so an agent can branch on the reason
14929
+ * without pattern-matching the human message.
14930
+ */
14931
+ code?: (string | null)
14932
+ /**
14933
+ * Remediation hint for the caller, when the failure has one.
14934
+ */
14935
+ help?: (string | null)
14280
14936
  }
14281
14937
 
14282
14938