fallow 3.23.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`, `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
@@ -9537,6 +9787,68 @@ consumed_symbols: string[]
9537
9787
  */
9538
9788
  note: string
9539
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
+ }
9540
9852
  /**
9541
9853
  * The result of a symbol-level call-chain trace. Its own surface (`kind:
9542
9854
  * "trace"`), NOT folded into the ranked brief.
@@ -9632,6 +9944,195 @@ export interface UnresolvedCallee {
9632
9944
  callee: string
9633
9945
  reason: UnresolvedReason
9634
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
+ }
9635
10136
  /**
9636
10137
  * Envelope emitted by `fallow --format review-github` / `review-gitlab`.
9637
10138
  */
@@ -10205,7 +10706,11 @@ prop_drilling_chains?: PropDrillingChainFinding[]
10205
10706
  */
10206
10707
  hotspots?: HotspotFinding[]
10207
10708
  /**
10208
- * 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.
10209
10714
  */
10210
10715
  hotspot_summary?: (HotspotSummary | null)
10211
10716
  /**
@@ -10420,6 +10925,29 @@ clone_families: CloneFamilyFinding[]
10420
10925
  */
10421
10926
  mirrored_directories?: MirroredDirectory[]
10422
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
10423
10951
  /**
10424
10952
  * Grouping mode when `--group-by` was passed.
10425
10953
  */
@@ -10556,8 +11084,13 @@ start_col: number
10556
11084
  end_col: number
10557
11085
  /**
10558
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.
10559
11092
  */
10560
- fragment: string
11093
+ fragment?: string
10561
11094
  /**
10562
11095
  * Resolver key for this specific instance (per-instance, not the
10563
11096
  * group-level largest-owner).
@@ -11008,6 +11541,13 @@ project_surfacing?: (ImpactCounts | null)
11008
11541
  * `trend`. None until two full `fallow` runs exist. v1.6.
11009
11542
  */
11010
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)
11011
11551
  /**
11012
11552
  * Lifetime count of commit-gate containment events.
11013
11553
  */
@@ -11089,6 +11629,37 @@ previous_total: number
11089
11629
  */
11090
11630
  current_total: number
11091
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
+ }
11092
11663
  /**
11093
11664
  * A commit-gate containment event recorded by `fallow impact`.
11094
11665
  */
@@ -12189,6 +12760,24 @@ feature_flags: FeatureFlagFinding[]
12189
12760
  * Number of entries in `feature_flags`.
12190
12761
  */
12191
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[]
12192
12781
  /**
12193
12782
  * `_meta` block; see [`FeatureFlagsMeta`].
12194
12783
  */
@@ -12530,12 +13119,11 @@ review_effort: ReviewEffort
12530
13119
  /**
12531
13120
  * Stage 1 of the brief: graph-derived orientation facts.
12532
13121
  *
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.
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.
12539
13127
  */
12540
13128
  export interface GraphFacts {
12541
13129
  /**
@@ -12549,12 +13137,6 @@ exports_added: number
12549
13137
  * were added.
12550
13138
  */
12551
13139
  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
13140
  /**
12559
13141
  * Architecture boundary zones touched by the changeset, deduped and sorted.
12560
13142
  * Derived from the run's boundary-violation findings.
@@ -12619,16 +13201,65 @@ files: string[]
12619
13201
  */
12620
13202
  export interface ImpactClosureFacts {
12621
13203
  /**
12622
- * Root-relative paths transitively affected by the changeset (reverse-deps +
12623
- * 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.
12624
13221
  */
12625
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
12626
13240
  /**
12627
13241
  * Coordination gaps: a changed file exports a contract consumed by a module
12628
- * 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.
12629
13245
  */
12630
13246
  coordination_gap: CoordinationGapFact[]
12631
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
+ }
12632
13263
  /**
12633
13264
  * One coordination-gap entry: a changed file exports symbols consumed by a
12634
13265
  * `consumer_file` that is NOT in the diff. Deduped per (changed, consumer) pair
@@ -12708,8 +13339,13 @@ fan_io: number
12708
13339
  /**
12709
13340
  * Security source -> sink taint-touch component (0 until a security pass is
12710
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.
12711
13347
  */
12712
- security_taint: number
13348
+ security_taint?: number
12713
13349
  /**
12714
13350
  * Risk-zone component (boundary / public-API / security-sensitive).
12715
13351
  */
@@ -14277,6 +14913,16 @@ message: string
14277
14913
  * The process exit code the CLI returns alongside this document.
14278
14914
  */
14279
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)
14280
14926
  }
14281
14927
 
14282
14928