fallow 2.84.0 → 2.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -9
- package/schema.json +119 -118
- package/skills/fallow/SKILL.md +47 -31
- package/skills/fallow/references/cli-reference.md +198 -38
- package/skills/fallow/references/gotchas.md +1 -1
- package/skills/fallow/references/patterns.md +10 -4
- package/types/output-contract.d.ts +411 -1198
|
@@ -25,33 +25,20 @@
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Schemas for the JSON output of fallow commands.
|
|
28
|
+
* Schemas for the JSON output of fallow commands. Object-shaped envelopes covered by the `FallowOutput` contract carry a top-level `kind` discriminator (for example `dead-code`, `dead-code-grouped`, `health`, `dupes`, `combined`, `audit`, `explain`, `impact`, `security`, `coverage-setup`, `coverage-analyze`, `list-boundaries`, `review-envelope`, and `review-reconcile`). Consumers should branch on `kind` instead of probing for unique field presence. `--legacy-envelope` removes only the document-root `kind` for one compatibility cycle. `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.
|
|
29
29
|
*/
|
|
30
30
|
export type FallowJsonOutput = (FallowOutput | CodeClimateOutput)
|
|
31
31
|
/**
|
|
32
|
-
* Typed root of every fallow
|
|
33
|
-
*
|
|
34
|
-
* the document-root `oneOf` in
|
|
35
|
-
*
|
|
32
|
+
* Typed root of every fallow JSON envelope shape that serializes as a JSON
|
|
33
|
+
* object and participates in the documented `FallowOutput` contract. The
|
|
34
|
+
* schema derived from this enum drives the document-root `oneOf` in
|
|
35
|
+
* `docs/output-schema.json`.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* [`DupesOutput`] flatten their inner body (`HealthReport` /
|
|
43
|
-
* `DuplicationReport`) into top-level fields, so the actual
|
|
44
|
-
* discriminators are nested-body keys such as `health_score` (health) and
|
|
45
|
-
* `clone_groups` (dupes), NOT `report` or `groups`.
|
|
46
|
-
*
|
|
47
|
-
* Variant order is **most-specific first**. Schemars 1 preserves
|
|
48
|
-
* declaration order in the emitted `oneOf`, and validators that enforce
|
|
49
|
-
* strict `oneOf` (and any future migration that adds `Deserialize`) will
|
|
50
|
-
* try branches top-to-bottom. The required-field sets shrink as we move
|
|
51
|
-
* down the list, with [`CombinedOutput`] last because its three required
|
|
52
|
-
* fields (`schema_version`, `version`, `elapsed_ms`) are a strict subset
|
|
53
|
-
* of every other variant's required set; placing it earlier would let a
|
|
54
|
-
* `CheckOutput` payload silently match `CombinedOutput` first.
|
|
37
|
+
* The default wire shape now carries a top-level `kind` discriminator so
|
|
38
|
+
* agents and schema-validating clients can select the variant in O(1) instead
|
|
39
|
+
* of probing for unique field presence. `--legacy-envelope` is a one-cycle
|
|
40
|
+
* compatibility flag that removes only this document-root `kind` field from
|
|
41
|
+
* CLI JSON output; nested report objects are not rewritten.
|
|
55
42
|
*
|
|
56
43
|
* One envelope is intentionally NOT in this enum:
|
|
57
44
|
* - `CodeClimateOutput` serializes as a bare JSON array
|
|
@@ -59,13 +46,36 @@ export type FallowJsonOutput = (FallowOutput | CodeClimateOutput)
|
|
|
59
46
|
* spec; `#[serde(tag = ...)]` cannot internally tag a non-object
|
|
60
47
|
* variant and wrapping the array would break the spec. The root schema
|
|
61
48
|
* carries it as a sibling `oneOf` branch alongside `FallowOutput`.
|
|
62
|
-
*
|
|
63
|
-
* A future major release plans to switch this to
|
|
64
|
-
* `#[serde(tag = "kind")]` for true O(1) discriminability on AI / agent
|
|
65
|
-
* consumers, paired with a one-cycle `--legacy-envelope` opt-out flag.
|
|
66
|
-
* Tracked under issue #384.
|
|
67
49
|
*/
|
|
68
|
-
export type FallowOutput = (AuditOutput
|
|
50
|
+
export type FallowOutput = ((AuditOutput & {
|
|
51
|
+
kind: "audit"
|
|
52
|
+
}) | (ExplainOutput & {
|
|
53
|
+
kind: "explain"
|
|
54
|
+
}) | (ReviewEnvelopeOutput & {
|
|
55
|
+
kind: "review-envelope"
|
|
56
|
+
}) | (ReviewReconcileOutput & {
|
|
57
|
+
kind: "review-reconcile"
|
|
58
|
+
}) | (CoverageSetupOutput & {
|
|
59
|
+
kind: "coverage-setup"
|
|
60
|
+
}) | (CoverageAnalyzeOutput & {
|
|
61
|
+
kind: "coverage-analyze"
|
|
62
|
+
}) | (ListBoundariesOutput & {
|
|
63
|
+
kind: "list-boundaries"
|
|
64
|
+
}) | (HealthOutput & {
|
|
65
|
+
kind: "health"
|
|
66
|
+
}) | (DupesOutput & {
|
|
67
|
+
kind: "dupes"
|
|
68
|
+
}) | (CheckGroupedOutput & {
|
|
69
|
+
kind: "dead-code-grouped"
|
|
70
|
+
}) | (ImpactReport & {
|
|
71
|
+
kind: "impact"
|
|
72
|
+
}) | (SecurityOutput & {
|
|
73
|
+
kind: "security"
|
|
74
|
+
}) | (CheckOutput & {
|
|
75
|
+
kind: "dead-code"
|
|
76
|
+
}) | (CombinedOutput & {
|
|
77
|
+
kind: "combined"
|
|
78
|
+
}))
|
|
69
79
|
/**
|
|
70
80
|
* Schema version for this output format (independent of tool version). Bump
|
|
71
81
|
* policy: ADDITIVE changes (new optional top-level fields, new optional struct
|
|
@@ -87,15 +97,12 @@ export type FallowOutput = (AuditOutput | ExplainOutput | ReviewEnvelopeOutput |
|
|
|
87
97
|
* additive examples: dupes --group-by adds optional grouped_by, total_issues,
|
|
88
98
|
* groups fields without bumping.
|
|
89
99
|
*/
|
|
90
|
-
export type SchemaVersion =
|
|
100
|
+
export type SchemaVersion = 7
|
|
91
101
|
/**
|
|
92
102
|
* Fallow CLI version that produced this envelope. Renders to the JSON wire as
|
|
93
103
|
* a bare string (e.g. `"2.74.0"`).
|
|
94
104
|
*/
|
|
95
105
|
export type ToolVersion = string
|
|
96
|
-
/**
|
|
97
|
-
* Singleton `command` discriminator for [`AuditOutput`].
|
|
98
|
-
*/
|
|
99
106
|
export type AuditCommand = "audit"
|
|
100
107
|
/**
|
|
101
108
|
* Verdict for the audit command.
|
|
@@ -106,9 +113,6 @@ export type AuditVerdict = ("pass" | "warn" | "fail")
|
|
|
106
113
|
* integer.
|
|
107
114
|
*/
|
|
108
115
|
export type ElapsedMs = number
|
|
109
|
-
/**
|
|
110
|
-
* Gating mode for `fallow audit`.
|
|
111
|
-
*/
|
|
112
116
|
export type AuditGate = ("new-only" | "all")
|
|
113
117
|
/**
|
|
114
118
|
* A suggested action attached to a finding in the JSON output. Each finding
|
|
@@ -220,17 +224,6 @@ export type AuditIntroduced = boolean
|
|
|
220
224
|
export type DependencyLocation = ("dependencies" | "devDependencies" | "optionalDependencies")
|
|
221
225
|
/**
|
|
222
226
|
* The kind of member.
|
|
223
|
-
*
|
|
224
|
-
* # Examples
|
|
225
|
-
*
|
|
226
|
-
* ```
|
|
227
|
-
* use fallow_types::extract::MemberKind;
|
|
228
|
-
*
|
|
229
|
-
* let kind = MemberKind::EnumMember;
|
|
230
|
-
* assert_eq!(kind, MemberKind::EnumMember);
|
|
231
|
-
* assert_ne!(kind, MemberKind::ClassMethod);
|
|
232
|
-
* assert_ne!(MemberKind::ClassMethod, MemberKind::ClassProperty);
|
|
233
|
-
* ```
|
|
234
227
|
*/
|
|
235
228
|
export type MemberKind = ("enum_member" | "class_method" | "class_property" | "namespace_member")
|
|
236
229
|
/**
|
|
@@ -354,43 +347,10 @@ export type ExceededThreshold = ("cyclomatic" | "cognitive" | "both" | "crap" |
|
|
|
354
347
|
export type FindingSeverity = ("moderate" | "high" | "critical")
|
|
355
348
|
/**
|
|
356
349
|
* Coverage tier classification for CRAP findings.
|
|
357
|
-
*
|
|
358
|
-
* Bucketed coverage signal that lets action consumers (AI agents, IDE
|
|
359
|
-
* extensions, CI integrations) pick the right remediation without knowing
|
|
360
|
-
* the underlying coverage values:
|
|
361
|
-
* - `None`: file has no test reachability (estimated model 0% band) or
|
|
362
|
-
* Istanbul data shows 0% statement coverage. The right action is
|
|
363
|
-
* "add tests from scratch."
|
|
364
|
-
* - `Partial`: some coverage exists (estimated model 40% band, or
|
|
365
|
-
* Istanbul shows >0% but below the high watermark). The right
|
|
366
|
-
* action is "increase coverage on uncovered branches."
|
|
367
|
-
* - `High`: coverage is at or above the high watermark (estimated model
|
|
368
|
-
* 85% band, or Istanbul shows >= 70%). Action selection still checks
|
|
369
|
-
* the CRAP formula before deciding whether coverage or refactoring is
|
|
370
|
-
* the better remediation.
|
|
371
|
-
*
|
|
372
|
-
* The high watermark default is 70 (matches Istanbul `lines: 70`).
|
|
373
|
-
* Partial is anything in `(0, 70)`. None is `<= 0`.
|
|
374
350
|
*/
|
|
375
351
|
export type CoverageTier = ("none" | "partial" | "high")
|
|
376
352
|
/**
|
|
377
353
|
* Provenance of a CRAP finding's coverage signal.
|
|
378
|
-
*
|
|
379
|
-
* Discriminates whether the `coverage_tier` and `crap` score were derived
|
|
380
|
-
* from real Istanbul data, the graph-based estimated model evaluated against
|
|
381
|
-
* the finding's own file, or the graph-based estimated model evaluated
|
|
382
|
-
* against a different file (today: an Angular component `.ts` reached via
|
|
383
|
-
* the inverse `templateUrl` edge from a synthetic `<template>` finding on
|
|
384
|
-
* the component's `.html` template).
|
|
385
|
-
*
|
|
386
|
-
* Consumers reading this field:
|
|
387
|
-
* - AI agents picking remediation actions ("the score is inherited, the fix
|
|
388
|
-
* may need to land on the component file, not the template").
|
|
389
|
-
* - Dashboards plotting CRAP trends ("the discriminator changed shape;
|
|
390
|
-
* absorb the rollout rather than flagging a step change").
|
|
391
|
-
* - Future tier 2 (AOT source-map back-mapping) will introduce
|
|
392
|
-
* `MeasuredAotSourceMap` so consumers can distinguish measured-AOT from
|
|
393
|
-
* inherited-JIT without parsing the score itself.
|
|
394
354
|
*/
|
|
395
355
|
export type CoverageSource = ("istanbul" | "estimated" | "estimated_component_inherited")
|
|
396
356
|
/**
|
|
@@ -406,6 +366,10 @@ export type HealthFindingActionType = ("refactor-function" | "add-tests" | "incr
|
|
|
406
366
|
* Coverage model used for CRAP score computation.
|
|
407
367
|
*/
|
|
408
368
|
export type CoverageModel = ("static_binary" | "static_estimated" | "istanbul")
|
|
369
|
+
/**
|
|
370
|
+
* Whether CRAP findings in the report used one coverage-source kind or a mix.
|
|
371
|
+
*/
|
|
372
|
+
export type CoverageSourceConsistency = ("uniform" | "mixed")
|
|
409
373
|
/**
|
|
410
374
|
* Discriminant for [`UntestedFileAction::kind`]. Mirrors the action types
|
|
411
375
|
* emitted by `build_untested_file_actions`.
|
|
@@ -420,13 +384,7 @@ export type UntestedExportActionType = ("add-test-import" | "suppress-file")
|
|
|
420
384
|
* Churn trend indicator based on comparing recent vs older halves of the analysis period.
|
|
421
385
|
*/
|
|
422
386
|
export type ChurnTrend = ("accelerating" | "stable" | "cooling")
|
|
423
|
-
/**
|
|
424
|
-
* Format discriminator for [`ContributorEntry::identifier`].
|
|
425
|
-
*/
|
|
426
387
|
export type ContributorIdentifierFormat = ("raw" | "handle" | "anonymized" | "hash")
|
|
427
|
-
/**
|
|
428
|
-
* Machine-readable ownership state for a hotspot.
|
|
429
|
-
*/
|
|
430
388
|
export type OwnershipState = ("active" | "unowned" | "declared_inactive" | "drifting")
|
|
431
389
|
/**
|
|
432
390
|
* Discriminant for [`HotspotAction::kind`].
|
|
@@ -489,6 +447,32 @@ export type RuntimeCoverageRiskBand = ("low" | "medium" | "high")
|
|
|
489
447
|
* License or trial watermark applied to runtime coverage output.
|
|
490
448
|
*/
|
|
491
449
|
export type RuntimeCoverageWatermark = ("trial-expired" | "license-expired-grace" | "unknown")
|
|
450
|
+
/**
|
|
451
|
+
* Coverage-intelligence JSON contract version. Scoped to the
|
|
452
|
+
* `coverage_intelligence` block and independent of the top-level fallow
|
|
453
|
+
* JSON `schema_version`.
|
|
454
|
+
*/
|
|
455
|
+
export type CoverageIntelligenceSchemaVersion = "1"
|
|
456
|
+
/**
|
|
457
|
+
* Headline verdict for the combined coverage-intelligence report.
|
|
458
|
+
*/
|
|
459
|
+
export type CoverageIntelligenceVerdict = ("risky-change-detected" | "high-confidence-delete" | "review-required" | "refactor-carefully" | "clean" | "unknown")
|
|
460
|
+
/**
|
|
461
|
+
* Ordered evidence signals behind a coverage-intelligence finding.
|
|
462
|
+
*/
|
|
463
|
+
export type CoverageIntelligenceSignal = ("changed" | "hot_path" | "low_test_coverage" | "high_crap" | "static_unused" | "runtime_cold" | "no_test_path" | "runtime_reachable" | "ownership_drift" | "test_covered")
|
|
464
|
+
/**
|
|
465
|
+
* Recommended action family for a combined finding.
|
|
466
|
+
*/
|
|
467
|
+
export type CoverageIntelligenceRecommendation = ("add-test-or-split-before-merge" | "delete-after-confirming-owner" | "review-before-changing" | "refactor-carefully-keep-behavior")
|
|
468
|
+
/**
|
|
469
|
+
* Confidence in the joined evidence and resulting recommendation.
|
|
470
|
+
*/
|
|
471
|
+
export type CoverageIntelligenceConfidence = ("high" | "medium" | "low")
|
|
472
|
+
/**
|
|
473
|
+
* Confidence tier for the cross-surface evidence match.
|
|
474
|
+
*/
|
|
475
|
+
export type CoverageIntelligenceMatchConfidence = ("path-function-line" | "path-line" | "direct")
|
|
492
476
|
/**
|
|
493
477
|
* Category of refactoring recommendation.
|
|
494
478
|
*/
|
|
@@ -568,34 +552,13 @@ export type ReviewCheckConclusion = ("success" | "neutral" | "failure")
|
|
|
568
552
|
* Schema-version discriminator for the review reconcile envelope.
|
|
569
553
|
*/
|
|
570
554
|
export type ReviewReconcileSchema = "fallow-review-reconcile/v1"
|
|
571
|
-
/**
|
|
572
|
-
* Singleton schema-version discriminator for [`CoverageSetupOutput`].
|
|
573
|
-
*/
|
|
574
555
|
export type CoverageSetupSchemaVersion = "1"
|
|
575
|
-
/**
|
|
576
|
-
* Framework label inside coverage setup output.
|
|
577
|
-
*/
|
|
578
556
|
export type CoverageSetupFramework = ("nextjs" | "nestjs" | "nuxt" | "sveltekit" | "astro" | "remix" | "vite" | "plain_node" | "unknown")
|
|
579
|
-
/**
|
|
580
|
-
* Package manager label inside coverage setup output.
|
|
581
|
-
*/
|
|
582
557
|
export type CoverageSetupPackageManager = ("npm" | "pnpm" | "yarn" | "bun")
|
|
583
|
-
/**
|
|
584
|
-
* Runtime target inside coverage setup output.
|
|
585
|
-
*/
|
|
586
558
|
export type CoverageSetupRuntimeTarget = ("node" | "browser")
|
|
587
|
-
/**
|
|
588
|
-
* Singleton schema-version discriminator for [`CoverageAnalyzeOutput`].
|
|
589
|
-
* Independent from the global [`SchemaVersion`] because the runtime
|
|
590
|
-
* coverage envelope versions independently from the rest of the
|
|
591
|
-
* JSON contract.
|
|
592
|
-
*/
|
|
593
559
|
export type CoverageAnalyzeSchemaVersion = "1"
|
|
594
560
|
/**
|
|
595
|
-
* Discovery outcome for a [`LogicalGroup`].
|
|
596
|
-
* "the directory exists and is empty" versus "at least one `autoDiscover`
|
|
597
|
-
* path was invalid or unreadable", so consumers can render an actionable
|
|
598
|
-
* hint instead of "0 children, mystery".
|
|
561
|
+
* Discovery outcome for a [`LogicalGroup`].
|
|
599
562
|
*/
|
|
600
563
|
export type LogicalGroupStatus = ("ok" | "empty" | "invalid_path")
|
|
601
564
|
/**
|
|
@@ -606,6 +569,33 @@ export type LogicalGroupStatus = ("ok" | "empty" | "invalid_path")
|
|
|
606
569
|
* groups by GitLab CODEOWNERS `[Section]` header name.
|
|
607
570
|
*/
|
|
608
571
|
export type GroupByMode = ("owner" | "directory" | "package" | "section")
|
|
572
|
+
/**
|
|
573
|
+
* Wire-version discriminator for [`ImpactReport`]. Independent from the global
|
|
574
|
+
* `SchemaVersion` (the impact report versions on its own cadence) and from the
|
|
575
|
+
* on-disk `STORE_SCHEMA_VERSION` (the persisted store shape versions
|
|
576
|
+
* separately). Serializes as a string `const` so JSON consumers can switch on
|
|
577
|
+
* it, matching the other independently-versioned envelopes (e.g.
|
|
578
|
+
* `CoverageAnalyzeSchemaVersion`).
|
|
579
|
+
*/
|
|
580
|
+
export type ImpactReportSchemaVersion = "1"
|
|
581
|
+
/**
|
|
582
|
+
* Direction of a count trend between two recorded runs.
|
|
583
|
+
*/
|
|
584
|
+
export type ImpactTrendDirection = ("improving" | "declining" | "stable")
|
|
585
|
+
/**
|
|
586
|
+
* The `fallow security --format json` schema version. Independently versioned
|
|
587
|
+
* from the main contract, mirroring `ImpactReportSchemaVersion`.
|
|
588
|
+
*/
|
|
589
|
+
export type SecuritySchemaVersion = "1"
|
|
590
|
+
/**
|
|
591
|
+
* The kind of security candidate. Findings are CANDIDATES for downstream agent
|
|
592
|
+
* verification, NOT verified vulnerabilities.
|
|
593
|
+
*/
|
|
594
|
+
export type SecurityFindingKind = ("client-server-leak" | "tainted-sink")
|
|
595
|
+
/**
|
|
596
|
+
* The role a hop plays in a security finding's structural import trace.
|
|
597
|
+
*/
|
|
598
|
+
export type TraceHopRole = ("client-boundary" | "intermediate" | "secret-source" | "sink")
|
|
609
599
|
/**
|
|
610
600
|
* Discriminator value for [`CodeClimateIssue::kind`].
|
|
611
601
|
*/
|
|
@@ -622,69 +612,22 @@ export type CodeClimateSeverity = ("info" | "minor" | "major" | "critical" | "bl
|
|
|
622
612
|
export type CodeClimateOutput = CodeClimateIssue[]
|
|
623
613
|
|
|
624
614
|
/**
|
|
625
|
-
*
|
|
626
|
-
* complexity, and duplication scoped to changed files with a verdict
|
|
627
|
-
* (`pass` / `warn` / `fail`), a per-category summary, optional
|
|
628
|
-
* new-vs-inherited attribution, and full sub-results.
|
|
629
|
-
*
|
|
630
|
-
* Like [`CombinedOutput`], `audit`'s `duplication` and `complexity`
|
|
631
|
-
* sub-keys hold body shapes rather than per-command envelopes:
|
|
632
|
-
* `duplication` is [`DupesReportPayload`] (the typed wrapper payload
|
|
633
|
-
* emitted via `crate::output_dupes::DupesReportPayload::from_report`),
|
|
634
|
-
* `complexity` is [`HealthReport`]. `dead_code` is the full
|
|
635
|
-
* [`CheckOutput`] envelope. The committed schema points `duplication`
|
|
636
|
-
* at `#/definitions/DupesReportPayload` and `complexity` at
|
|
637
|
-
* `#/definitions/HealthReport` so the documented shape matches the
|
|
638
|
-
* wire; the `committed_property_refs_match_derived_property_refs`
|
|
639
|
-
* drift test enforces the alignment.
|
|
615
|
+
* `fallow audit --format json` envelope.
|
|
640
616
|
*/
|
|
641
617
|
export interface AuditOutput {
|
|
642
618
|
schema_version: SchemaVersion
|
|
643
619
|
version: ToolVersion
|
|
644
620
|
command: AuditCommand
|
|
645
621
|
verdict: AuditVerdict
|
|
646
|
-
/**
|
|
647
|
-
* Number of files changed between base ref and HEAD.
|
|
648
|
-
*/
|
|
649
622
|
changed_files_count: number
|
|
650
|
-
/**
|
|
651
|
-
* Git ref used as comparison base (explicit or auto-detected).
|
|
652
|
-
*/
|
|
653
623
|
base_ref: string
|
|
654
|
-
/**
|
|
655
|
-
* Short SHA of HEAD. Omitted when git is unavailable.
|
|
656
|
-
*/
|
|
657
624
|
head_sha?: (string | null)
|
|
658
625
|
elapsed_ms: ElapsedMs
|
|
659
|
-
/**
|
|
660
|
-
* Only emitted when --performance is set. true means audit reused the
|
|
661
|
-
* current run's keys as the base snapshot because every changed file was
|
|
662
|
-
* either a non-behavioral doc or token-equivalent at the base ref (the
|
|
663
|
-
* docs-only-diff fast path); false means the regular base worktree
|
|
664
|
-
* analysis ran.
|
|
665
|
-
*/
|
|
666
626
|
base_snapshot_skipped?: (boolean | null)
|
|
667
627
|
summary: AuditSummary
|
|
668
628
|
attribution: AuditAttribution
|
|
669
|
-
/**
|
|
670
|
-
* Full dead code results (omitted if no changed files). Issue objects
|
|
671
|
-
* include introduced: true/false when audit can compare against the base
|
|
672
|
-
* ref.
|
|
673
|
-
*/
|
|
674
629
|
dead_code?: (CheckOutput | null)
|
|
675
|
-
/**
|
|
676
|
-
* Full duplication results (omitted if no changed files). Clone groups
|
|
677
|
-
* include introduced: true/false when audit can compare against the base
|
|
678
|
-
* ref. Carries typed [`crate::output_dupes::CloneGroupFinding`] and
|
|
679
|
-
* [`crate::output_dupes::CloneFamilyFinding`] wrappers (matches what
|
|
680
|
-
* `crates/cli/src/audit.rs` emits via
|
|
681
|
-
* `crate::output_dupes::DupesReportPayload::from_report`).
|
|
682
|
-
*/
|
|
683
630
|
duplication?: (DupesReportPayload | null)
|
|
684
|
-
/**
|
|
685
|
-
* Full complexity results (omitted if no changed files). Findings include
|
|
686
|
-
* introduced: true/false when audit can compare against the base ref.
|
|
687
|
-
*/
|
|
688
631
|
complexity?: (HealthReport | null)
|
|
689
632
|
}
|
|
690
633
|
/**
|
|
@@ -724,14 +667,7 @@ export interface CheckOutput {
|
|
|
724
667
|
schema_version: SchemaVersion
|
|
725
668
|
version: ToolVersion
|
|
726
669
|
elapsed_ms: ElapsedMs
|
|
727
|
-
/**
|
|
728
|
-
* Total number of issues found across all categories.
|
|
729
|
-
*/
|
|
730
670
|
total_issues: number
|
|
731
|
-
/**
|
|
732
|
-
* Entry-point detection summary. Present when the analysis populated
|
|
733
|
-
* the metadata block; absent in synthesised fixtures.
|
|
734
|
-
*/
|
|
735
671
|
entry_points?: (EntryPoints | null)
|
|
736
672
|
summary: CheckSummary
|
|
737
673
|
/**
|
|
@@ -886,34 +822,10 @@ unused_dependency_overrides?: UnusedDependencyOverrideFinding[]
|
|
|
886
822
|
* error. Wrapped in [`MisconfiguredDependencyOverrideFinding`].
|
|
887
823
|
*/
|
|
888
824
|
misconfigured_dependency_overrides?: MisconfiguredDependencyOverrideFinding[]
|
|
889
|
-
/**
|
|
890
|
-
* Per-category delta comparison against a saved baseline. Only present
|
|
891
|
-
* when `--baseline` is used (today only via the combined invocation).
|
|
892
|
-
*/
|
|
893
825
|
baseline_deltas?: (BaselineDeltas | null)
|
|
894
|
-
/**
|
|
895
|
-
* Baseline match statistics. Only present when `--baseline` is used.
|
|
896
|
-
*/
|
|
897
826
|
baseline?: (BaselineMatch | null)
|
|
898
|
-
/**
|
|
899
|
-
* Regression check result. Only present when `--fail-on-regression` is
|
|
900
|
-
* used.
|
|
901
|
-
*/
|
|
902
827
|
regression?: (RegressionResult | null)
|
|
903
|
-
/**
|
|
904
|
-
* `_meta` block with metric / rule definitions, emitted when `--explain`
|
|
905
|
-
* is passed (always present in MCP responses).
|
|
906
|
-
*/
|
|
907
828
|
_meta?: (Meta | null)
|
|
908
|
-
/**
|
|
909
|
-
* Workspace-discovery diagnostics surfaced by
|
|
910
|
-
* `discover_workspaces_with_diagnostics` (issue #473): malformed
|
|
911
|
-
* declared-workspace `package.json`, glob matches with no `package.json`,
|
|
912
|
-
* malformed `tsconfig.json`, missing tsconfig reference paths. Omitted
|
|
913
|
-
* when empty so consumers on monorepos without discovery noise see no
|
|
914
|
-
* new field. Pairing of `#[serde(default, skip_serializing_if = ...)]`
|
|
915
|
-
* is required for schemars to mark the field non-required.
|
|
916
|
-
*/
|
|
917
829
|
workspace_diagnostics?: WorkspaceDiagnostic[]
|
|
918
830
|
}
|
|
919
831
|
/**
|
|
@@ -2281,6 +2193,13 @@ token_count: number
|
|
|
2281
2193
|
* Number of lines in the duplicated block.
|
|
2282
2194
|
*/
|
|
2283
2195
|
line_count: number
|
|
2196
|
+
/**
|
|
2197
|
+
* Stable content fingerprint, usually `dup:<8hex>` and widened on rare
|
|
2198
|
+
* report collisions. Addressable via `fallow dupes --trace dup:<fp>` (and
|
|
2199
|
+
* the `trace_clone` MCP tool) to deep-dive this group; shown alongside
|
|
2200
|
+
* each group in the human listing.
|
|
2201
|
+
*/
|
|
2202
|
+
fingerprint: string
|
|
2284
2203
|
/**
|
|
2285
2204
|
* Suggested next steps: an `extract-shared` primary and a
|
|
2286
2205
|
* `suppress-line` secondary. Always emitted (possibly empty for
|
|
@@ -2561,6 +2480,10 @@ hotspot_summary?: (HotspotSummary | null)
|
|
|
2561
2480
|
* `--runtime-coverage`).
|
|
2562
2481
|
*/
|
|
2563
2482
|
runtime_coverage?: (RuntimeCoverageReport | null)
|
|
2483
|
+
/**
|
|
2484
|
+
* Combined coverage, runtime, complexity, and change-scope verdicts.
|
|
2485
|
+
*/
|
|
2486
|
+
coverage_intelligence?: (CoverageIntelligenceReport | null)
|
|
2564
2487
|
/**
|
|
2565
2488
|
* Functions exceeding 60 LOC (very high risk). Only present when unit size
|
|
2566
2489
|
* very-high-risk bin >= 3%. Sorted by line count descending.
|
|
@@ -2593,177 +2516,41 @@ actions_meta?: (HealthActionsMeta | null)
|
|
|
2593
2516
|
}
|
|
2594
2517
|
/**
|
|
2595
2518
|
* Wire envelope for a single complexity finding.
|
|
2596
|
-
*
|
|
2597
|
-
* Flattens [`ComplexityViolation`] for wire continuity and adds the typed
|
|
2598
|
-
* `actions` list plus the audit-mode `introduced` flag. The
|
|
2599
|
-
* `#[serde(flatten)]` keeps each `findings[]` item byte-identical to the
|
|
2600
|
-
* pre-wrapper shape: inner fields (`path`, `name`, `line`, `cyclomatic`,
|
|
2601
|
-
* ...) sit at the top level alongside `actions` and optional `introduced`.
|
|
2602
|
-
*
|
|
2603
|
-
* Construct via [`HealthFinding::with_actions`] in the typical health
|
|
2604
|
-
* pipeline (the wrapper computes its own `actions` from a
|
|
2605
|
-
* [`HealthActionContext`]) or via [`HealthFinding::new`] when the caller
|
|
2606
|
-
* already has the action list (e.g., tests, audit cross-attribution).
|
|
2607
2519
|
*/
|
|
2608
2520
|
export interface HealthFinding {
|
|
2609
|
-
/**
|
|
2610
|
-
* Absolute file path.
|
|
2611
|
-
*/
|
|
2612
2521
|
path: string
|
|
2613
|
-
/**
|
|
2614
|
-
* Function name, `"<anonymous>"` for unnamed functions/arrows, or
|
|
2615
|
-
* `"<template>"` for synthetic Angular template findings.
|
|
2616
|
-
*/
|
|
2617
2522
|
name: string
|
|
2618
|
-
/**
|
|
2619
|
-
* 1-based line number.
|
|
2620
|
-
*/
|
|
2621
2523
|
line: number
|
|
2622
|
-
/**
|
|
2623
|
-
* 0-based column.
|
|
2624
|
-
*/
|
|
2625
2524
|
col: number
|
|
2626
|
-
/**
|
|
2627
|
-
* Cyclomatic complexity.
|
|
2628
|
-
*/
|
|
2629
2525
|
cyclomatic: number
|
|
2630
|
-
/**
|
|
2631
|
-
* SonarSource cognitive complexity (structural + nesting penalty).
|
|
2632
|
-
*/
|
|
2633
2526
|
cognitive: number
|
|
2634
|
-
/**
|
|
2635
|
-
* Number of lines in the function.
|
|
2636
|
-
*/
|
|
2637
2527
|
line_count: number
|
|
2638
|
-
/**
|
|
2639
|
-
* Number of parameters (excluding TypeScript's this parameter).
|
|
2640
|
-
*/
|
|
2641
2528
|
param_count: number
|
|
2642
2529
|
exceeded: ExceededThreshold
|
|
2643
2530
|
severity: FindingSeverity
|
|
2644
|
-
/**
|
|
2645
|
-
* CRAP score (`CC^2 * (1 - cov/100)^3 + CC`), rounded to one decimal.
|
|
2646
|
-
* Present when the function also exceeded `--max-crap`, otherwise absent.
|
|
2647
|
-
*/
|
|
2648
2531
|
crap?: (number | null)
|
|
2649
|
-
/**
|
|
2650
|
-
* Per-function statement coverage percentage (0.0 to 100.0) used to
|
|
2651
|
-
* derive `crap`. Present when Istanbul data matched the function,
|
|
2652
|
-
* otherwise absent (estimated model or unmatched functions).
|
|
2653
|
-
*/
|
|
2654
2532
|
coverage_pct?: (number | null)
|
|
2655
|
-
/**
|
|
2656
|
-
* Bucketed coverage tier used to drive action selection. Present whenever
|
|
2657
|
-
* CRAP triggered the finding (Istanbul or estimated), absent otherwise.
|
|
2658
|
-
* `none` = coverage is at most 0% (file not test-reachable, or Istanbul
|
|
2659
|
-
* reports 0); `partial` = coverage is in `(0, 70)`; `high` = coverage is
|
|
2660
|
-
* at or above the high watermark (default `>= 70`, or the estimated 85%
|
|
2661
|
-
* band).
|
|
2662
|
-
*/
|
|
2663
2533
|
coverage_tier?: (CoverageTier | null)
|
|
2664
|
-
/**
|
|
2665
|
-
* Provenance of the coverage signal. Present whenever CRAP triggered the
|
|
2666
|
-
* finding. `istanbul` = direct fnMap match; `estimated` = graph-based
|
|
2667
|
-
* estimate against the finding's own file; `estimated_component_inherited`
|
|
2668
|
-
* = graph-based estimate inherited from an Angular component `.ts`
|
|
2669
|
-
* reached via the inverse `templateUrl` edge (synthetic `<template>`
|
|
2670
|
-
* findings on `.html` files only).
|
|
2671
|
-
*/
|
|
2672
2534
|
coverage_source?: (CoverageSource | null)
|
|
2673
|
-
/**
|
|
2674
|
-
* Owning component file that contributed reachability when
|
|
2675
|
-
* `coverage_source == "estimated_component_inherited"`. Always paired
|
|
2676
|
-
* with that variant of `coverage_source` and absent otherwise. The
|
|
2677
|
-
* value is the `.ts` file fallow walked to via the inverse `templateUrl`
|
|
2678
|
-
* edge (e.g. `permissions.component.ts`); the JSON serializer strips it
|
|
2679
|
-
* to project-relative form just like other path fields. Lets human and
|
|
2680
|
-
* AI consumers explain "the template scored partial because the
|
|
2681
|
-
* component it belongs to is tested" without re-deriving the link.
|
|
2682
|
-
*/
|
|
2683
2535
|
inherited_from?: (string | null)
|
|
2684
|
-
/**
|
|
2685
|
-
* Breakdown of a synthetic `<component>` rollup finding into its
|
|
2686
|
-
* worst-class-function and template contributions. Present only on
|
|
2687
|
-
* findings whose [`name`](Self::name) is the literal string
|
|
2688
|
-
* `"<component>"` (Angular components whose class AND template both
|
|
2689
|
-
* contributed to a per-component complexity rollup); absent on every
|
|
2690
|
-
* other finding kind.
|
|
2691
|
-
*
|
|
2692
|
-
* The owning [`HealthFinding`](crate::health_types::HealthFinding)'s
|
|
2693
|
-
* [`cyclomatic`](Self::cyclomatic) / [`cognitive`](Self::cognitive)
|
|
2694
|
-
* totals are `class_worst_function + template`, so consumers ranking
|
|
2695
|
-
* by complexity see the component as one unit. The breakdown carries
|
|
2696
|
-
* the pre-summation numbers plus the worst class function's name so
|
|
2697
|
-
* consumers can explain "this component ranked high because the
|
|
2698
|
-
* template added 6 cyclomatic on top of the worst class function's 3".
|
|
2699
|
-
*/
|
|
2700
2536
|
component_rollup?: (ComponentRollup | null)
|
|
2701
2537
|
/**
|
|
2702
|
-
* Machine-actionable fix and suppress hints.
|
|
2703
|
-
* empty in the typical pipeline (the action selector emits at least
|
|
2704
|
-
* `suppress-line` or `suppress-file` unless suppressed by the
|
|
2705
|
-
* context).
|
|
2538
|
+
* Machine-actionable fix and suppress hints.
|
|
2706
2539
|
*/
|
|
2707
2540
|
actions: HealthFindingAction[]
|
|
2708
2541
|
/**
|
|
2709
|
-
* Audit-mode flag indicating whether the finding is new versus the
|
|
2710
|
-
*
|
|
2711
|
-
* `Some(false)` when present in both snapshots, `None` outside audit
|
|
2712
|
-
* mode (the field is skipped from the wire).
|
|
2542
|
+
* Audit-mode flag indicating whether the finding is new versus the base
|
|
2543
|
+
* snapshot.
|
|
2713
2544
|
*/
|
|
2714
2545
|
introduced?: (boolean | null)
|
|
2715
2546
|
}
|
|
2716
|
-
/**
|
|
2717
|
-
* Per-component breakdown attached to a synthetic `<component>`
|
|
2718
|
-
* [`HealthFinding`](crate::health_types::HealthFinding). See
|
|
2719
|
-
* [`ComplexityViolation::component_rollup`] for the owning-finding
|
|
2720
|
-
* contract; the wrapper flattens the inner type's
|
|
2721
|
-
* [`component_rollup`](ComplexityViolation::component_rollup) field
|
|
2722
|
-
* onto its own wire shape.
|
|
2723
|
-
*/
|
|
2724
2547
|
export interface ComponentRollup {
|
|
2725
|
-
/**
|
|
2726
|
-
* Angular component class name (e.g. `"HostGameComponent"`). Derived
|
|
2727
|
-
* from the worst class function's `ClassName.methodName` identifier.
|
|
2728
|
-
*/
|
|
2729
2548
|
component: string
|
|
2730
|
-
/**
|
|
2731
|
-
* Name of the worst class function/method whose individual cyclomatic
|
|
2732
|
-
* is the largest among the component's class findings (e.g.
|
|
2733
|
-
* `"ngOnInit"`). When two methods tie on cyclomatic the first by
|
|
2734
|
-
* iteration order wins; consumers should treat the choice as
|
|
2735
|
-
* representative, not authoritative.
|
|
2736
|
-
*/
|
|
2737
2549
|
class_worst_function: string
|
|
2738
|
-
/**
|
|
2739
|
-
* Cyclomatic complexity of the worst class function alone (the
|
|
2740
|
-
* `class_worst_function`).
|
|
2741
|
-
*/
|
|
2742
2550
|
class_cyclomatic: number
|
|
2743
|
-
/**
|
|
2744
|
-
* Cognitive complexity of the worst class function alone.
|
|
2745
|
-
*/
|
|
2746
2551
|
class_cognitive: number
|
|
2747
|
-
/**
|
|
2748
|
-
* Path of the Angular template that contributed to the rollup.
|
|
2749
|
-
* External-template components use the `.html` template file path;
|
|
2750
|
-
* inline-template components use the owning `.ts` itself (since the
|
|
2751
|
-
* `<template>` finding for inline templates is anchored at the
|
|
2752
|
-
* component's `@Component` decorator on the same file). Stored
|
|
2753
|
-
* absolute internally; the JSON output strips it to project-relative
|
|
2754
|
-
* form via the global `strip_root_prefix` post-pass (as with every
|
|
2755
|
-
* other `PathBuf` field in this crate).
|
|
2756
|
-
*/
|
|
2757
2552
|
template_path: string
|
|
2758
|
-
/**
|
|
2759
|
-
* Cyclomatic complexity contributed by the template alone (control
|
|
2760
|
-
* flow on `*ngIf` / `*ngFor` / `@if` / `@for` / `@switch` etc.).
|
|
2761
|
-
*/
|
|
2762
2553
|
template_cyclomatic: number
|
|
2763
|
-
/**
|
|
2764
|
-
* Cognitive complexity contributed by the template alone (nesting +
|
|
2765
|
-
* branching penalty on the same constructs as `template_cyclomatic`).
|
|
2766
|
-
*/
|
|
2767
2554
|
template_cognitive: number
|
|
2768
2555
|
}
|
|
2769
2556
|
/**
|
|
@@ -2832,77 +2619,20 @@ target_path?: (string | null)
|
|
|
2832
2619
|
* Summary statistics for the health report.
|
|
2833
2620
|
*/
|
|
2834
2621
|
export interface HealthSummary {
|
|
2835
|
-
/**
|
|
2836
|
-
* Number of files analyzed.
|
|
2837
|
-
*/
|
|
2838
2622
|
files_analyzed: number
|
|
2839
|
-
/**
|
|
2840
|
-
* Total number of functions found.
|
|
2841
|
-
*/
|
|
2842
2623
|
functions_analyzed: number
|
|
2843
|
-
/**
|
|
2844
|
-
* Number of functions exceeding at least one threshold (before --top
|
|
2845
|
-
* truncation).
|
|
2846
|
-
*/
|
|
2847
2624
|
functions_above_threshold: number
|
|
2848
|
-
/**
|
|
2849
|
-
* Configured cyclomatic threshold.
|
|
2850
|
-
*/
|
|
2851
2625
|
max_cyclomatic_threshold: number
|
|
2852
|
-
/**
|
|
2853
|
-
* Configured cognitive threshold.
|
|
2854
|
-
*/
|
|
2855
2626
|
max_cognitive_threshold: number
|
|
2856
|
-
/**
|
|
2857
|
-
* Configured CRAP (Change Risk Anti-Patterns) score threshold. Functions
|
|
2858
|
-
* meeting or exceeding this score appear as findings with the `crap` and
|
|
2859
|
-
* optional `coverage_pct` fields populated.
|
|
2860
|
-
*/
|
|
2861
2627
|
max_crap_threshold: number
|
|
2862
|
-
/**
|
|
2863
|
-
* Number of files with health scores. Only present when --file-scores is
|
|
2864
|
-
* used. 0 indicates the flag was set but scoring failed.
|
|
2865
|
-
*/
|
|
2866
2628
|
files_scored?: (number | null)
|
|
2867
|
-
/**
|
|
2868
|
-
* Average maintainability index across all scored files (before --top
|
|
2869
|
-
* truncation). Only present when --file-scores is used and at least one
|
|
2870
|
-
* file was scored.
|
|
2871
|
-
*/
|
|
2872
2629
|
average_maintainability?: (number | null)
|
|
2873
|
-
/**
|
|
2874
|
-
* Coverage model used for CRAP score computation. 'static_estimated'
|
|
2875
|
-
* (default) uses per-function graph-based estimation from export
|
|
2876
|
-
* references: directly test-referenced = 85%, indirectly reachable = 40%,
|
|
2877
|
-
* untested = 0%. 'istanbul' uses real per-function statement coverage from
|
|
2878
|
-
* a coverage-final.json file (--coverage flag or auto-detected).
|
|
2879
|
-
* 'static_binary' is the legacy binary model. Only present when file
|
|
2880
|
-
* scores are computed.
|
|
2881
|
-
*/
|
|
2882
2630
|
coverage_model?: (CoverageModel | null)
|
|
2883
|
-
|
|
2884
|
-
* Number of functions matched against Istanbul coverage data.
|
|
2885
|
-
* Only present when `coverage_model` is `istanbul`.
|
|
2886
|
-
*/
|
|
2631
|
+
coverage_source_consistency?: (CoverageSourceConsistency | null)
|
|
2887
2632
|
istanbul_matched?: (number | null)
|
|
2888
|
-
/**
|
|
2889
|
-
* Total functions that could potentially be matched.
|
|
2890
|
-
* Only present when `coverage_model` is `istanbul`.
|
|
2891
|
-
*/
|
|
2892
2633
|
istanbul_total?: (number | null)
|
|
2893
|
-
/**
|
|
2894
|
-
* Number of findings with critical severity (cognitive >= 40 or cyclomatic
|
|
2895
|
-
* >= 50).
|
|
2896
|
-
*/
|
|
2897
2634
|
severity_critical_count: number
|
|
2898
|
-
/**
|
|
2899
|
-
* Number of findings with high severity (cognitive 25-39 or cyclomatic
|
|
2900
|
-
* 30-49).
|
|
2901
|
-
*/
|
|
2902
2635
|
severity_high_count: number
|
|
2903
|
-
/**
|
|
2904
|
-
* Number of findings with moderate severity.
|
|
2905
|
-
*/
|
|
2906
2636
|
severity_moderate_count: number
|
|
2907
2637
|
}
|
|
2908
2638
|
/**
|
|
@@ -3053,173 +2783,43 @@ high_risk: number
|
|
|
3053
2783
|
*/
|
|
3054
2784
|
very_high_risk: number
|
|
3055
2785
|
}
|
|
3056
|
-
/**
|
|
3057
|
-
* Project-level health score. Score = 100 minus available penalties from dead
|
|
3058
|
-
* code, complexity, maintainability, hotspots, unused deps, circular deps,
|
|
3059
|
-
* unit size, coupling, and duplication. Missing metrics do not penalize;
|
|
3060
|
-
* --score computes the score and duplication penalty, while churn-backed
|
|
3061
|
-
* hotspot penalties require hotspot analysis (--hotspots, or --targets with
|
|
3062
|
-
* --score).
|
|
3063
|
-
*/
|
|
3064
2786
|
export interface HealthScore {
|
|
3065
|
-
/**
|
|
3066
|
-
* Health score formula version. Version 2 uses scale-invariant
|
|
3067
|
-
* density/tail metrics for monorepo-safe scoring.
|
|
3068
|
-
*/
|
|
3069
2787
|
formula_version: number
|
|
3070
|
-
/**
|
|
3071
|
-
* Overall score (0-100, higher is better). Reproducible: 100 -
|
|
3072
|
-
* sum(penalties) == score.
|
|
3073
|
-
*/
|
|
3074
2788
|
score: number
|
|
3075
|
-
/**
|
|
3076
|
-
* Letter grade. A: score >= 85, B: 70-84, C: 55-69, D: 40-54, F: below 40.
|
|
3077
|
-
*/
|
|
3078
2789
|
grade: string
|
|
3079
2790
|
penalties: HealthScorePenalties
|
|
3080
2791
|
}
|
|
3081
2792
|
/**
|
|
3082
2793
|
* Per-component penalty breakdown for the health score.
|
|
3083
|
-
*
|
|
3084
|
-
* Each field shows how many points were subtracted for that component.
|
|
3085
|
-
* `None` means the metric was not available (pipeline didn't run).
|
|
3086
2794
|
*/
|
|
3087
2795
|
export interface HealthScorePenalties {
|
|
3088
|
-
/**
|
|
3089
|
-
* Points lost from dead files (max 15). Null if dead code pipeline not
|
|
3090
|
-
* run.
|
|
3091
|
-
*/
|
|
3092
2796
|
dead_files?: (number | null)
|
|
3093
|
-
/**
|
|
3094
|
-
* Points lost from dead exports (max 15). Null if dead code pipeline not
|
|
3095
|
-
* run.
|
|
3096
|
-
*/
|
|
3097
2797
|
dead_exports?: (number | null)
|
|
3098
|
-
/**
|
|
3099
|
-
* Points lost from critical-complexity density (max 20). Older snapshots
|
|
3100
|
-
* without density fields fall back to average cyclomatic complexity above
|
|
3101
|
-
* 1.5.
|
|
3102
|
-
*/
|
|
3103
2798
|
complexity: number
|
|
3104
|
-
/**
|
|
3105
|
-
* Points lost from legacy p90 cyclomatic complexity above 10. Current
|
|
3106
|
-
* scale-invariant runs report 0 because tail complexity is folded into
|
|
3107
|
-
* complexity.
|
|
3108
|
-
*/
|
|
3109
2799
|
p90_complexity: number
|
|
3110
|
-
/**
|
|
3111
|
-
* Points lost from low maintainability index density (max 15).
|
|
3112
|
-
*/
|
|
3113
2800
|
maintainability?: (number | null)
|
|
3114
|
-
/**
|
|
3115
|
-
* Points lost from top-percentile hotspot density (max 10). Null if
|
|
3116
|
-
* hotspots not computed.
|
|
3117
|
-
*/
|
|
3118
2801
|
hotspots?: (number | null)
|
|
3119
|
-
/**
|
|
3120
|
-
* Points lost from unused dependency density (max 25). Null if dead code
|
|
3121
|
-
* pipeline not run.
|
|
3122
|
-
*/
|
|
3123
2802
|
unused_deps?: (number | null)
|
|
3124
|
-
/**
|
|
3125
|
-
* Points lost from circular dependency density (max 25). Null if dead code
|
|
3126
|
-
* pipeline not run.
|
|
3127
|
-
*/
|
|
3128
2803
|
circular_deps?: (number | null)
|
|
3129
|
-
/**
|
|
3130
|
-
* Points lost from oversized-function density (max 10). Null if no
|
|
3131
|
-
* functions analyzed.
|
|
3132
|
-
*/
|
|
3133
2804
|
unit_size?: (number | null)
|
|
3134
|
-
/**
|
|
3135
|
-
* Points lost from coupling concentration density (max 5). Null if file
|
|
3136
|
-
* scores not computed.
|
|
3137
|
-
*/
|
|
3138
2805
|
coupling?: (number | null)
|
|
3139
|
-
/**
|
|
3140
|
-
* Points lost from code duplication (max 10). Penalty = min(max(0,
|
|
3141
|
-
* duplication_pct - 5) * 1, 10). Null if duplication pipeline not run.
|
|
3142
|
-
*/
|
|
3143
2806
|
duplication?: (number | null)
|
|
3144
2807
|
}
|
|
3145
2808
|
/**
|
|
3146
2809
|
* Per-file health score combining complexity, coupling, and dead code metrics.
|
|
3147
|
-
*
|
|
3148
|
-
* Files with zero functions (barrel files, re-export files) are excluded by default.
|
|
3149
|
-
*
|
|
3150
|
-
* ## Maintainability Index Formula
|
|
3151
|
-
*
|
|
3152
|
-
* ```text
|
|
3153
|
-
* dampening = min(lines / 50, 1.0)
|
|
3154
|
-
* fan_out_penalty = min(ln(fan_out + 1) × 4, 15)
|
|
3155
|
-
* maintainability = 100
|
|
3156
|
-
* - (complexity_density × 30 × dampening)
|
|
3157
|
-
* - (dead_code_ratio × 20)
|
|
3158
|
-
* - fan_out_penalty
|
|
3159
|
-
* ```
|
|
3160
|
-
*
|
|
3161
|
-
* Clamped to \[0, 100\]. Higher is better. The dampening factor prevents
|
|
3162
|
-
* complexity density from dominating the score on small files (< 50 lines).
|
|
3163
|
-
*
|
|
3164
|
-
* - **complexity_density**: total cyclomatic complexity / lines of code
|
|
3165
|
-
* - **dead_code_ratio**: fraction of value exports (excluding type-only exports) with zero references (0.0–1.0)
|
|
3166
|
-
* - **fan_out_penalty**: logarithmic scaling with cap at 15 points; reflects diminishing marginal risk of additional imports
|
|
3167
2810
|
*/
|
|
3168
2811
|
export interface FileHealthScore {
|
|
3169
|
-
/**
|
|
3170
|
-
* File path (absolute; stripped to relative in output).
|
|
3171
|
-
*/
|
|
3172
2812
|
path: string
|
|
3173
|
-
/**
|
|
3174
|
-
* Number of files that import this file.
|
|
3175
|
-
*/
|
|
3176
2813
|
fan_in: number
|
|
3177
|
-
/**
|
|
3178
|
-
* Number of files this file imports.
|
|
3179
|
-
*/
|
|
3180
2814
|
fan_out: number
|
|
3181
|
-
/**
|
|
3182
|
-
* Fraction of value exports with zero references (0.0–1.0). Files with no value exports get 0.0.
|
|
3183
|
-
* Type-only exports (interfaces, type aliases) are excluded from both numerator and denominator
|
|
3184
|
-
* to avoid inflating the ratio for well-typed codebases that export props types alongside components.
|
|
3185
|
-
*/
|
|
3186
2815
|
dead_code_ratio: number
|
|
3187
|
-
/**
|
|
3188
|
-
* Total cyclomatic complexity / lines of code.
|
|
3189
|
-
*/
|
|
3190
2816
|
complexity_density: number
|
|
3191
|
-
/**
|
|
3192
|
-
* Weighted composite score (0–100, higher is better).
|
|
3193
|
-
*/
|
|
3194
2817
|
maintainability_index: number
|
|
3195
|
-
/**
|
|
3196
|
-
* Sum of cyclomatic complexity across all functions.
|
|
3197
|
-
*/
|
|
3198
2818
|
total_cyclomatic: number
|
|
3199
|
-
/**
|
|
3200
|
-
* Sum of cognitive complexity across all functions.
|
|
3201
|
-
*/
|
|
3202
2819
|
total_cognitive: number
|
|
3203
|
-
/**
|
|
3204
|
-
* Number of functions in this file.
|
|
3205
|
-
*/
|
|
3206
2820
|
function_count: number
|
|
3207
|
-
/**
|
|
3208
|
-
* Total lines of code (from line_offsets).
|
|
3209
|
-
*/
|
|
3210
2821
|
lines: number
|
|
3211
|
-
/**
|
|
3212
|
-
* Maximum CRAP score among functions in this file. Computed via the active
|
|
3213
|
-
* `coverage_model` per the canonical formula CC^2 * (1 - cov/100)^3 + CC
|
|
3214
|
-
* (Savoia & Evans, 2007). Coverage source: `static_estimated` (default,
|
|
3215
|
-
* graph-based per-function estimate), `istanbul` (real per-function
|
|
3216
|
-
* statement coverage from --coverage), or the legacy `static_binary`
|
|
3217
|
-
* (whole-file 0%/100%, retained for compatibility).
|
|
3218
|
-
*/
|
|
3219
2822
|
crap_max: number
|
|
3220
|
-
/**
|
|
3221
|
-
* Count of functions with CRAP >= 30 (CC >= 5 without test path).
|
|
3222
|
-
*/
|
|
3223
2823
|
crap_above_threshold: number
|
|
3224
2824
|
}
|
|
3225
2825
|
/**
|
|
@@ -3403,51 +3003,16 @@ comment?: (string | null)
|
|
|
3403
3003
|
* test code.
|
|
3404
3004
|
*/
|
|
3405
3005
|
export interface HotspotFinding {
|
|
3406
|
-
/**
|
|
3407
|
-
* File path (absolute; stripped to relative in output).
|
|
3408
|
-
*/
|
|
3409
3006
|
path: string
|
|
3410
|
-
/**
|
|
3411
|
-
* Hotspot score (0–100). Higher means more risk.
|
|
3412
|
-
*/
|
|
3413
3007
|
score: number
|
|
3414
|
-
/**
|
|
3415
|
-
* Number of commits in the analysis window.
|
|
3416
|
-
*/
|
|
3417
3008
|
commits: number
|
|
3418
|
-
/**
|
|
3419
|
-
* Recency-weighted commit count (exponential decay, half-life 90 days).
|
|
3420
|
-
*/
|
|
3421
3009
|
weighted_commits: number
|
|
3422
|
-
/**
|
|
3423
|
-
* Total lines added across all commits.
|
|
3424
|
-
*/
|
|
3425
3010
|
lines_added: number
|
|
3426
|
-
/**
|
|
3427
|
-
* Total lines deleted across all commits.
|
|
3428
|
-
*/
|
|
3429
3011
|
lines_deleted: number
|
|
3430
|
-
/**
|
|
3431
|
-
* Cyclomatic complexity / lines of code.
|
|
3432
|
-
*/
|
|
3433
3012
|
complexity_density: number
|
|
3434
|
-
/**
|
|
3435
|
-
* Number of files that import this file (blast radius).
|
|
3436
|
-
*/
|
|
3437
3013
|
fan_in: number
|
|
3438
3014
|
trend: ChurnTrend
|
|
3439
|
-
/**
|
|
3440
|
-
* Ownership signals (bus factor, contributors, declared owner, drift).
|
|
3441
|
-
* Populated only when `--ownership` is requested.
|
|
3442
|
-
*/
|
|
3443
3015
|
ownership?: (OwnershipMetrics | null)
|
|
3444
|
-
/**
|
|
3445
|
-
* True when the file path matches a test/mock convention (e.g.
|
|
3446
|
-
* `** /__tests__/**`, `** /*.test.*`, `** /*.spec.*`, `** /__mocks__/**`).
|
|
3447
|
-
* Test files are intentionally included in hotspot ranking (test
|
|
3448
|
-
* maintenance IS real work), but tagging them lets consumers decide
|
|
3449
|
-
* whether to weight or filter them downstream.
|
|
3450
|
-
*/
|
|
3451
3016
|
is_test_path?: boolean
|
|
3452
3017
|
/**
|
|
3453
3018
|
* Machine-actionable refactor and review hints. Always populated;
|
|
@@ -3459,89 +3024,23 @@ is_test_path?: boolean
|
|
|
3459
3024
|
*/
|
|
3460
3025
|
actions: HotspotAction[]
|
|
3461
3026
|
}
|
|
3462
|
-
/**
|
|
3463
|
-
* Per-file ownership signals attached to hotspot entries when the user
|
|
3464
|
-
* passes `--ownership`. All fields are derived from git history and the
|
|
3465
|
-
* repository's CODEOWNERS file (if any).
|
|
3466
|
-
*/
|
|
3467
3027
|
export interface OwnershipMetrics {
|
|
3468
|
-
/**
|
|
3469
|
-
* Avelino truck factor: minimum contributors covering at least 50% of
|
|
3470
|
-
* recency-weighted commits in the analysis window. Lower = higher
|
|
3471
|
-
* knowledge-loss risk.
|
|
3472
|
-
*/
|
|
3473
3028
|
bus_factor: number
|
|
3474
|
-
/**
|
|
3475
|
-
* Distinct authors in the analysis window after bot filtering.
|
|
3476
|
-
*/
|
|
3477
3029
|
contributor_count: number
|
|
3478
3030
|
top_contributor: ContributorEntry
|
|
3479
|
-
/**
|
|
3480
|
-
* Up to three additional contributors by share, ordered desc.
|
|
3481
|
-
* Useful for "who else could review this file" routing.
|
|
3482
|
-
*/
|
|
3483
3031
|
recent_contributors?: ContributorEntry[]
|
|
3484
|
-
/**
|
|
3485
|
-
* Contributors whose last touch is within 90 days, ordered by share
|
|
3486
|
-
* descending. First-class field so AI agents do not have to
|
|
3487
|
-
* reconstruct it from [`recent_contributors`](Self::recent_contributors)
|
|
3488
|
-
* filtered by [`ContributorEntry::stale_days`]. Excludes the top
|
|
3489
|
-
* contributor (they are the sole author being flagged); consumers
|
|
3490
|
-
* wanting the full list can union with `top_contributor`.
|
|
3491
|
-
*/
|
|
3492
3032
|
suggested_reviewers?: ContributorEntry[]
|
|
3493
|
-
/**
|
|
3494
|
-
* CODEOWNERS-resolved owner for this file, if a rule matched.
|
|
3495
|
-
* Only the primary (first) owner of the matched rule is reported.
|
|
3496
|
-
*/
|
|
3497
3033
|
declared_owner?: (string | null)
|
|
3498
|
-
/**
|
|
3499
|
-
* Tristate: `Some(true)` = CODEOWNERS file exists but no rule matches
|
|
3500
|
-
* this file; `Some(false)` = a CODEOWNERS rule matches; `None` = no
|
|
3501
|
-
* CODEOWNERS file was discovered for the repository (cannot determine).
|
|
3502
|
-
*/
|
|
3503
3034
|
unowned?: (boolean | null)
|
|
3504
3035
|
ownership_state: OwnershipState
|
|
3505
|
-
/**
|
|
3506
|
-
* True when ownership has drifted from the original author to a new
|
|
3507
|
-
* top contributor. Pairs with [`drift_reason`](Self::drift_reason).
|
|
3508
|
-
*/
|
|
3509
3036
|
drift: boolean
|
|
3510
|
-
/**
|
|
3511
|
-
* Human-readable explanation of the drift, populated only when
|
|
3512
|
-
* [`drift`](Self::drift) is true.
|
|
3513
|
-
*/
|
|
3514
3037
|
drift_reason?: (string | null)
|
|
3515
3038
|
}
|
|
3516
|
-
/**
|
|
3517
|
-
* Per-author contribution summary. The identifier is rendered per the
|
|
3518
|
-
* configured ownership.emailMode (handle, anonymized/hash, or raw); the format field
|
|
3519
|
-
* discriminates the modes so type-aware consumers can branch without
|
|
3520
|
-
* re-parsing.
|
|
3521
|
-
*/
|
|
3522
3039
|
export interface ContributorEntry {
|
|
3523
|
-
/**
|
|
3524
|
-
* Display string per the configured email mode: raw email
|
|
3525
|
-
* (`alice@example.com`), local-part handle (`alice`), or stable anonymized hash
|
|
3526
|
-
* pseudonym (`xxh3:<16hex>`). The format depends on `format`.
|
|
3527
|
-
*
|
|
3528
|
-
* Renamed from `email` because in `handle` and `anonymized`/`hash` modes the value
|
|
3529
|
-
* is no longer an email address; consumers tempted to use it as one
|
|
3530
|
-
* (e.g. `mailto:`) would be wrong.
|
|
3531
|
-
*/
|
|
3532
3040
|
identifier: string
|
|
3533
3041
|
format: ContributorIdentifierFormat
|
|
3534
|
-
/**
|
|
3535
|
-
* Recency-weighted share of total weighted commits (0..1, three decimals).
|
|
3536
|
-
*/
|
|
3537
3042
|
share: number
|
|
3538
|
-
/**
|
|
3539
|
-
* Days since this contributor last touched the file.
|
|
3540
|
-
*/
|
|
3541
3043
|
stale_days: number
|
|
3542
|
-
/**
|
|
3543
|
-
* Total commits by this contributor in the analysis window.
|
|
3544
|
-
*/
|
|
3545
3044
|
commits: number
|
|
3546
3045
|
}
|
|
3547
3046
|
/**
|
|
@@ -3584,29 +3083,11 @@ suggested_pattern?: (string | null)
|
|
|
3584
3083
|
*/
|
|
3585
3084
|
heuristic?: (HotspotActionHeuristic | null)
|
|
3586
3085
|
}
|
|
3587
|
-
/**
|
|
3588
|
-
* Summary statistics for hotspot analysis.
|
|
3589
|
-
*/
|
|
3590
3086
|
export interface HotspotSummary {
|
|
3591
|
-
/**
|
|
3592
|
-
* Analysis window display string (e.g., "6 months").
|
|
3593
|
-
*/
|
|
3594
3087
|
since: string
|
|
3595
|
-
/**
|
|
3596
|
-
* Minimum commits threshold.
|
|
3597
|
-
*/
|
|
3598
3088
|
min_commits: number
|
|
3599
|
-
/**
|
|
3600
|
-
* Number of files with churn data meeting the threshold.
|
|
3601
|
-
*/
|
|
3602
3089
|
files_analyzed: number
|
|
3603
|
-
/**
|
|
3604
|
-
* Number of files excluded (below min_commits).
|
|
3605
|
-
*/
|
|
3606
3090
|
files_excluded: number
|
|
3607
|
-
/**
|
|
3608
|
-
* Whether the repository is a shallow clone.
|
|
3609
|
-
*/
|
|
3610
3091
|
shallow_clone: boolean
|
|
3611
3092
|
}
|
|
3612
3093
|
/**
|
|
@@ -3981,24 +3462,88 @@ code: string
|
|
|
3981
3462
|
message: string
|
|
3982
3463
|
}
|
|
3983
3464
|
/**
|
|
3984
|
-
*
|
|
3465
|
+
* Combined coverage, runtime, complexity, and change-scope verdicts.
|
|
3985
3466
|
*/
|
|
3986
|
-
export interface
|
|
3467
|
+
export interface CoverageIntelligenceReport {
|
|
3468
|
+
schema_version: CoverageIntelligenceSchemaVersion
|
|
3469
|
+
verdict: CoverageIntelligenceVerdict
|
|
3470
|
+
summary: CoverageIntelligenceSummary
|
|
3471
|
+
findings: CoverageIntelligenceFinding[]
|
|
3472
|
+
}
|
|
3987
3473
|
/**
|
|
3988
|
-
*
|
|
3474
|
+
* Aggregate metadata for coverage-intelligence output.
|
|
3475
|
+
*/
|
|
3476
|
+
export interface CoverageIntelligenceSummary {
|
|
3477
|
+
findings: number
|
|
3478
|
+
risky_changes: number
|
|
3479
|
+
high_confidence_deletes: number
|
|
3480
|
+
review_required: number
|
|
3481
|
+
refactor_carefully: number
|
|
3482
|
+
skipped_ambiguous_matches: number
|
|
3483
|
+
}
|
|
3484
|
+
/**
|
|
3485
|
+
* One combined coverage-intelligence finding.
|
|
3486
|
+
*/
|
|
3487
|
+
export interface CoverageIntelligenceFinding {
|
|
3488
|
+
/**
|
|
3489
|
+
* Stable finding ID of the form `fallow:coverage-intel:<hash>`.
|
|
3490
|
+
*/
|
|
3491
|
+
id: string
|
|
3492
|
+
/**
|
|
3493
|
+
* File path relative to the project root.
|
|
3989
3494
|
*/
|
|
3990
3495
|
path: string
|
|
3991
3496
|
/**
|
|
3992
|
-
* Function
|
|
3497
|
+
* Function or export identity when known.
|
|
3993
3498
|
*/
|
|
3994
|
-
|
|
3499
|
+
identity?: (string | null)
|
|
3995
3500
|
/**
|
|
3996
|
-
* 1-
|
|
3501
|
+
* 1-indexed source line.
|
|
3997
3502
|
*/
|
|
3998
3503
|
line: number
|
|
3504
|
+
verdict: CoverageIntelligenceVerdict
|
|
3505
|
+
signals: CoverageIntelligenceSignal[]
|
|
3506
|
+
recommendation: CoverageIntelligenceRecommendation
|
|
3507
|
+
confidence: CoverageIntelligenceConfidence
|
|
3508
|
+
related_ids?: string[]
|
|
3509
|
+
evidence: CoverageIntelligenceEvidence
|
|
3510
|
+
actions: CoverageIntelligenceAction[]
|
|
3511
|
+
}
|
|
3999
3512
|
/**
|
|
4000
|
-
*
|
|
3513
|
+
* Compact evidence values that led to a recommendation.
|
|
4001
3514
|
*/
|
|
3515
|
+
export interface CoverageIntelligenceEvidence {
|
|
3516
|
+
coverage_pct?: (number | null)
|
|
3517
|
+
crap?: (number | null)
|
|
3518
|
+
runtime_verdict?: (string | null)
|
|
3519
|
+
invocations?: (number | null)
|
|
3520
|
+
static_status?: (string | null)
|
|
3521
|
+
test_coverage?: (string | null)
|
|
3522
|
+
changed?: boolean
|
|
3523
|
+
ownership_state?: (string | null)
|
|
3524
|
+
match_confidence: CoverageIntelligenceMatchConfidence
|
|
3525
|
+
}
|
|
3526
|
+
/**
|
|
3527
|
+
* Machine-actionable next step for a coverage-intelligence finding.
|
|
3528
|
+
*/
|
|
3529
|
+
export interface CoverageIntelligenceAction {
|
|
3530
|
+
/**
|
|
3531
|
+
* Action identifier, normalized to `type` in JSON output.
|
|
3532
|
+
*/
|
|
3533
|
+
type: string
|
|
3534
|
+
description: string
|
|
3535
|
+
/**
|
|
3536
|
+
* Whether fallow can apply this action automatically.
|
|
3537
|
+
*/
|
|
3538
|
+
auto_fixable: boolean
|
|
3539
|
+
}
|
|
3540
|
+
/**
|
|
3541
|
+
* A function exceeding the very-high-risk size threshold (>60 LOC).
|
|
3542
|
+
*/
|
|
3543
|
+
export interface LargeFunctionEntry {
|
|
3544
|
+
path: string
|
|
3545
|
+
name: string
|
|
3546
|
+
line: number
|
|
4002
3547
|
line_count: number
|
|
4003
3548
|
}
|
|
4004
3549
|
/**
|
|
@@ -4317,181 +3862,51 @@ scope: string
|
|
|
4317
3862
|
* fallow JSON-producing command.
|
|
4318
3863
|
*/
|
|
4319
3864
|
export interface ExplainOutput {
|
|
4320
|
-
/**
|
|
4321
|
-
* Canonical rule id, for example `fallow/unused-export`.
|
|
4322
|
-
*/
|
|
4323
3865
|
id: string
|
|
4324
|
-
/**
|
|
4325
|
-
* Human-readable rule name.
|
|
4326
|
-
*/
|
|
4327
3866
|
name: string
|
|
4328
|
-
/**
|
|
4329
|
-
* Short one-line explanation of the issue.
|
|
4330
|
-
*/
|
|
4331
3867
|
summary: string
|
|
4332
|
-
/**
|
|
4333
|
-
* Why the issue matters and what fallow checks.
|
|
4334
|
-
*/
|
|
4335
3868
|
rationale: string
|
|
4336
|
-
/**
|
|
4337
|
-
* Concrete example of the finding.
|
|
4338
|
-
*/
|
|
4339
3869
|
example: string
|
|
4340
|
-
/**
|
|
4341
|
-
* Recommended fix or suppression guidance.
|
|
4342
|
-
*/
|
|
4343
3870
|
how_to_fix: string
|
|
4344
|
-
/**
|
|
4345
|
-
* Docs URL for the rule.
|
|
4346
|
-
*/
|
|
4347
3871
|
docs: string
|
|
4348
3872
|
}
|
|
4349
3873
|
/**
|
|
4350
3874
|
* Envelope emitted by `fallow --format review-github` / `review-gitlab`.
|
|
4351
|
-
* Consumed by `action/scripts/review.sh` and `ci/scripts/review.sh` to
|
|
4352
|
-
* post inline PR / MR review comments.
|
|
4353
3875
|
*/
|
|
4354
3876
|
export interface ReviewEnvelopeOutput {
|
|
4355
|
-
/**
|
|
4356
|
-
* GitHub review event. Omitted for GitLab.
|
|
4357
|
-
*/
|
|
4358
3877
|
event?: (ReviewEnvelopeEvent | null)
|
|
4359
|
-
/**
|
|
4360
|
-
* Review summary body (rendered above per-line comments). Deprecated in
|
|
4361
|
-
* v2 envelopes: prefer [`summary.body`](`ReviewEnvelopeSummary::body`),
|
|
4362
|
-
* which is byte-identical to this field but carries a stable
|
|
4363
|
-
* fingerprint for reconciliation. Kept on v2 emit so v1 consumers that
|
|
4364
|
-
* only look at `body` keep working.
|
|
4365
|
-
*/
|
|
4366
3878
|
body: string
|
|
4367
3879
|
summary?: ReviewEnvelopeSummary
|
|
4368
|
-
/**
|
|
4369
|
-
* Per-line comments. Each is either a [`GitHubReviewComment`] or a
|
|
4370
|
-
* [`GitLabReviewComment`] depending on `meta.provider`.
|
|
4371
|
-
*/
|
|
4372
3880
|
comments: ReviewComment[]
|
|
4373
|
-
/**
|
|
4374
|
-
* Regex consumers run against every existing PR/MR comment body to
|
|
4375
|
-
* extract a fallow-emitted fingerprint marker. Capture group 1 is the
|
|
4376
|
-
* fingerprint string (a bare 16-char hex hash for single-finding
|
|
4377
|
-
* comments, or `<kind>:<16-char-hex>` for compositions such as
|
|
4378
|
-
* `merged:` for same-line collapsed comments).
|
|
4379
|
-
*
|
|
4380
|
-
* The pattern is anchored with `^` / `$` and relies on multiline
|
|
4381
|
-
* matching to anchor at line boundaries inside a multi-line comment
|
|
4382
|
-
* body. Multiline is NOT baked into the pattern via `(?m)` (which
|
|
4383
|
-
* JavaScript RegExp rejects as `Invalid group`); instead the consumer
|
|
4384
|
-
* passes [`Self::marker_regex_flags`] as the flags argument to its
|
|
4385
|
-
* regex engine. JavaScript: `new RegExp(env.marker_regex,
|
|
4386
|
-
* env.marker_regex_flags)`. Rust: `regex::RegexBuilder::new(pat)
|
|
4387
|
-
* .multi_line(flags.contains('m')).build()` (or any equivalent).
|
|
4388
|
-
*/
|
|
4389
3881
|
marker_regex?: string
|
|
4390
|
-
/**
|
|
4391
|
-
* Flags consumers pass alongside [`Self::marker_regex`] when
|
|
4392
|
-
* constructing their regex engine. Currently always `"m"` (multiline
|
|
4393
|
-
* so the anchored `^` / `$` match at every line boundary within a
|
|
4394
|
-
* comment body). Emitting flags as a separate field instead of
|
|
4395
|
-
* baking `(?m)` into the pattern keeps the wire compatible with
|
|
4396
|
-
* JavaScript RegExp, which rejects inline flag groups outside a
|
|
4397
|
-
* `(?flags:X)` grouping.
|
|
4398
|
-
*/
|
|
4399
3882
|
marker_regex_flags?: string
|
|
4400
3883
|
meta: ReviewEnvelopeMeta
|
|
4401
3884
|
}
|
|
4402
3885
|
/**
|
|
4403
|
-
* Summary block on [`ReviewEnvelopeOutput`].
|
|
4404
|
-
* `serde(default)` keeps schemars from marking it required so a future
|
|
4405
|
-
* Deserialize derivation against v1 historical input synthesizes an empty
|
|
4406
|
-
* value rather than erroring.
|
|
3886
|
+
* Summary block on [`ReviewEnvelopeOutput`].
|
|
4407
3887
|
*/
|
|
4408
3888
|
export interface ReviewEnvelopeSummary {
|
|
4409
|
-
/**
|
|
4410
|
-
* Markdown body of the summary. Byte-identical to the legacy top-level
|
|
4411
|
-
* [`ReviewEnvelopeOutput::body`] field; the duplication is intentional
|
|
4412
|
-
* so v1 consumers see no behavior change.
|
|
4413
|
-
*/
|
|
4414
3889
|
body: string
|
|
4415
|
-
/**
|
|
4416
|
-
* FNV-1a 64-bit hash (16 lowercase hex chars) of the summary body
|
|
4417
|
-
* BEFORE the trailing fallow-fingerprint marker line is appended.
|
|
4418
|
-
* (Computing the hash from the post-marker body would be circular:
|
|
4419
|
-
* the marker contains the fingerprint, so the fingerprint cannot
|
|
4420
|
-
* depend on the marker.) To reproduce from [`Self::body`], strip the
|
|
4421
|
-
* line matching [`ReviewEnvelopeOutput::marker_regex`] together with
|
|
4422
|
-
* its leading separator newlines and hash the remainder. Stable
|
|
4423
|
-
* across runs that produce the same summary content; consumers
|
|
4424
|
-
* upsert the sticky summary comment by matching this fingerprint
|
|
4425
|
-
* against the marker_regex extraction of every existing comment body.
|
|
4426
|
-
*/
|
|
4427
3890
|
fingerprint: string
|
|
4428
3891
|
}
|
|
4429
3892
|
/**
|
|
4430
3893
|
* GitHub pull-request review comment.
|
|
4431
3894
|
*/
|
|
4432
3895
|
export interface GitHubReviewComment {
|
|
4433
|
-
/**
|
|
4434
|
-
* File path the comment targets, repo-root relative.
|
|
4435
|
-
*/
|
|
4436
3896
|
path: string
|
|
4437
|
-
/**
|
|
4438
|
-
* 1-indexed line number the comment targets.
|
|
4439
|
-
*/
|
|
4440
3897
|
line: number
|
|
4441
3898
|
side: GitHubReviewSide
|
|
4442
|
-
/**
|
|
4443
|
-
* Markdown body of the comment.
|
|
4444
|
-
*/
|
|
4445
3899
|
body: string
|
|
4446
|
-
/**
|
|
4447
|
-
* Stable fingerprint for the comment, used by `fallow ci
|
|
4448
|
-
* reconcile-review` to detect carryover comments across PR revisions.
|
|
4449
|
-
* For single-finding comments the value is a bare 16-char hex FNV-1a
|
|
4450
|
-
* hash. For merged comments (multiple findings on the same path:line)
|
|
4451
|
-
* the value is `merged:<16-char hex>` over the sorted constituent
|
|
4452
|
-
* fingerprints, so the identity shifts whenever constituent findings
|
|
4453
|
-
* change membership. Bundled wrappers and `fallow ci reconcile-review`
|
|
4454
|
-
* dedupe on this primary fingerprint only; consumers wanting
|
|
4455
|
-
* update-in-place reconciliation (preserving reviewer reply threads
|
|
4456
|
-
* across content changes) implement their own identity tracking via
|
|
4457
|
-
* `marker_regex`.
|
|
4458
|
-
*/
|
|
4459
3900
|
fingerprint: string
|
|
4460
|
-
/**
|
|
4461
|
-
* True when [`Self::body`] was truncated to fit a downstream provider's
|
|
4462
|
-
* note-size budget (today: 65,536 bytes). The body retains the closing
|
|
4463
|
-
* fallow-fingerprint marker so reconciliation continues to work after
|
|
4464
|
-
* truncation.
|
|
4465
|
-
*
|
|
4466
|
-
* Co-presence invariant: `truncated == true` always implies the body
|
|
4467
|
-
* contains an inline `<!-- fallow-truncated -->` HTML marker and the
|
|
4468
|
-
* `> Body truncated by fallow.` blockquote breadcrumb, and vice versa.
|
|
4469
|
-
* All three signals are emitted together; consumers may use any one
|
|
4470
|
-
* (the typed boolean is the authoritative machine-readable signal).
|
|
4471
|
-
*/
|
|
4472
3901
|
truncated?: boolean
|
|
4473
3902
|
}
|
|
4474
3903
|
/**
|
|
4475
3904
|
* GitLab merge-request discussion comment.
|
|
4476
3905
|
*/
|
|
4477
3906
|
export interface GitLabReviewComment {
|
|
4478
|
-
/**
|
|
4479
|
-
* Markdown body of the comment.
|
|
4480
|
-
*/
|
|
4481
3907
|
body: string
|
|
4482
3908
|
position: GitLabReviewPosition
|
|
4483
|
-
/**
|
|
4484
|
-
* Stable fingerprint for the comment. See
|
|
4485
|
-
* [`GitHubReviewComment::fingerprint`] for the single vs `merged:`
|
|
4486
|
-
* shape contract; semantics are identical across providers.
|
|
4487
|
-
*/
|
|
4488
3909
|
fingerprint: string
|
|
4489
|
-
/**
|
|
4490
|
-
* True when [`Self::body`] was truncated to fit GitLab's note-size
|
|
4491
|
-
* budget. See [`GitHubReviewComment::truncated`] for the full
|
|
4492
|
-
* co-presence invariant with the inline HTML marker and human
|
|
4493
|
-
* blockquote breadcrumb.
|
|
4494
|
-
*/
|
|
4495
3910
|
truncated?: boolean
|
|
4496
3911
|
}
|
|
4497
3912
|
/**
|
|
@@ -4499,30 +3914,12 @@ truncated?: boolean
|
|
|
4499
3914
|
* merge-request discussion-position API.
|
|
4500
3915
|
*/
|
|
4501
3916
|
export interface GitLabReviewPosition {
|
|
4502
|
-
/**
|
|
4503
|
-
* Merge-request base SHA.
|
|
4504
|
-
*/
|
|
4505
3917
|
base_sha?: (string | null)
|
|
4506
|
-
/**
|
|
4507
|
-
* Merge-request start SHA.
|
|
4508
|
-
*/
|
|
4509
3918
|
start_sha?: (string | null)
|
|
4510
|
-
/**
|
|
4511
|
-
* Merge-request head SHA.
|
|
4512
|
-
*/
|
|
4513
3919
|
head_sha?: (string | null)
|
|
4514
3920
|
position_type: GitLabReviewPositionType
|
|
4515
|
-
/**
|
|
4516
|
-
* File path on the base side.
|
|
4517
|
-
*/
|
|
4518
3921
|
old_path: string
|
|
4519
|
-
/**
|
|
4520
|
-
* File path on the head side.
|
|
4521
|
-
*/
|
|
4522
3922
|
new_path: string
|
|
4523
|
-
/**
|
|
4524
|
-
* 1-indexed line on the head side.
|
|
4525
|
-
*/
|
|
4526
3923
|
new_line: number
|
|
4527
3924
|
}
|
|
4528
3925
|
/**
|
|
@@ -4531,10 +3928,6 @@ new_line: number
|
|
|
4531
3928
|
export interface ReviewEnvelopeMeta {
|
|
4532
3929
|
schema: ReviewEnvelopeSchema
|
|
4533
3930
|
provider: ReviewProvider
|
|
4534
|
-
/**
|
|
4535
|
-
* Check conclusion derived from the underlying findings. Emitted only
|
|
4536
|
-
* for GitHub envelopes today.
|
|
4537
|
-
*/
|
|
4538
3931
|
check_conclusion?: (ReviewCheckConclusion | null)
|
|
4539
3932
|
}
|
|
4540
3933
|
/**
|
|
@@ -4545,240 +3938,66 @@ check_conclusion?: (ReviewCheckConclusion | null)
|
|
|
4545
3938
|
export interface ReviewReconcileOutput {
|
|
4546
3939
|
schema: ReviewReconcileSchema
|
|
4547
3940
|
provider: ReviewProvider
|
|
4548
|
-
/**
|
|
4549
|
-
* PR / MR target identifier supplied to `fallow ci reconcile-review`.
|
|
4550
|
-
* `null` when the command ran without an explicit target.
|
|
4551
|
-
*/
|
|
4552
3941
|
target?: (string | null)
|
|
4553
|
-
/**
|
|
4554
|
-
* Whether the reconcile ran in dry-run mode.
|
|
4555
|
-
*/
|
|
4556
3942
|
dry_run: boolean
|
|
4557
|
-
/**
|
|
4558
|
-
* Number of comments in the supplied review envelope.
|
|
4559
|
-
*/
|
|
4560
3943
|
comments: number
|
|
4561
|
-
/**
|
|
4562
|
-
* Total fingerprints discovered in the supplied envelope.
|
|
4563
|
-
*/
|
|
4564
3944
|
current_fingerprints: number
|
|
4565
|
-
/**
|
|
4566
|
-
* Existing fingerprints already posted on the PR / MR.
|
|
4567
|
-
*/
|
|
4568
3945
|
existing_fingerprints: number
|
|
4569
|
-
/**
|
|
4570
|
-
* Newly-introduced fingerprints (current minus existing).
|
|
4571
|
-
*/
|
|
4572
3946
|
new_fingerprints: number
|
|
4573
|
-
/**
|
|
4574
|
-
* Stale fingerprints (existing minus current).
|
|
4575
|
-
*/
|
|
4576
3947
|
stale_fingerprints: number
|
|
4577
|
-
/**
|
|
4578
|
-
* Identifiers of the new fingerprints (subset of comments).
|
|
4579
|
-
*/
|
|
4580
3948
|
new: string[]
|
|
4581
|
-
/**
|
|
4582
|
-
* Identifiers of the stale fingerprints (subset of existing).
|
|
4583
|
-
*/
|
|
4584
3949
|
stale: string[]
|
|
4585
|
-
/**
|
|
4586
|
-
* Optional warning when the provider API was unreachable or
|
|
4587
|
-
* auth-rejected. `null` on the happy path.
|
|
4588
|
-
*/
|
|
4589
3950
|
provider_warning?: (string | null)
|
|
4590
|
-
/**
|
|
4591
|
-
* Resolution comments actually posted (zero on dry runs).
|
|
4592
|
-
*/
|
|
4593
3951
|
resolution_comments_posted: number
|
|
4594
|
-
/**
|
|
4595
|
-
* Stale review threads actually resolved (zero on dry runs).
|
|
4596
|
-
*/
|
|
4597
3952
|
threads_resolved: number
|
|
4598
|
-
/**
|
|
4599
|
-
* Operator-facing retry hint when apply stopped early.
|
|
4600
|
-
*/
|
|
4601
3953
|
apply_hint?: (string | null)
|
|
4602
|
-
/**
|
|
4603
|
-
* Errors collected during apply, one entry per failure.
|
|
4604
|
-
*/
|
|
4605
3954
|
apply_errors: string[]
|
|
4606
|
-
/**
|
|
4607
|
-
* Stale fingerprints whose provider mutation failed.
|
|
4608
|
-
*/
|
|
4609
3955
|
failed_fingerprints?: string[]
|
|
4610
|
-
/**
|
|
4611
|
-
* Stale fingerprints not fully applied after the fail-fast stop.
|
|
4612
|
-
*/
|
|
4613
3956
|
unapplied_fingerprints?: string[]
|
|
4614
3957
|
}
|
|
4615
3958
|
/**
|
|
4616
|
-
*
|
|
4617
|
-
* agent-readable runtime coverage setup instructions. In workspaces,
|
|
4618
|
-
* `members` carries one entry per detected runtime package; `runtime_targets`
|
|
4619
|
-
* is the union of all member targets.
|
|
4620
|
-
*
|
|
4621
|
-
* Constructed at runtime by
|
|
4622
|
-
* `crates/cli/src/coverage/mod.rs::build_setup_envelope`; the wire is
|
|
4623
|
-
* `serde_json::to_value(&envelope)`. The drift gate keeps this struct
|
|
4624
|
-
* aligned with `docs/output-schema.json`.
|
|
3959
|
+
* `fallow coverage setup --json` envelope.
|
|
4625
3960
|
*/
|
|
4626
3961
|
export interface CoverageSetupOutput {
|
|
4627
3962
|
schema_version: CoverageSetupSchemaVersion
|
|
4628
3963
|
framework_detected: CoverageSetupFramework
|
|
4629
|
-
/**
|
|
4630
|
-
* Detected JavaScript package manager. `null` when none could be
|
|
4631
|
-
* resolved.
|
|
4632
|
-
*/
|
|
4633
3964
|
package_manager?: (CoverageSetupPackageManager | null)
|
|
4634
|
-
/**
|
|
4635
|
-
* Union of runtime targets across emitted members.
|
|
4636
|
-
*/
|
|
4637
3965
|
runtime_targets: CoverageSetupRuntimeTarget[]
|
|
4638
|
-
/**
|
|
4639
|
-
* Per-runtime-workspace setup recipes. Pure aggregator roots and
|
|
4640
|
-
* build-only library packages are omitted.
|
|
4641
|
-
*/
|
|
4642
3966
|
members: CoverageSetupMember[]
|
|
4643
|
-
|
|
4644
|
-
* Always `null` today. Reserved for a future "config has been written
|
|
4645
|
-
* to disk" indicator.
|
|
4646
|
-
*/
|
|
4647
|
-
config_written?: {
|
|
4648
|
-
[k: string]: unknown
|
|
4649
|
-
}
|
|
4650
|
-
/**
|
|
4651
|
-
* Shell commands the agent should run from the workspace root.
|
|
4652
|
-
*/
|
|
3967
|
+
config_written?: unknown
|
|
4653
3968
|
commands: string[]
|
|
4654
|
-
/**
|
|
4655
|
-
* Compatibility copy of the primary member's files, with workspace
|
|
4656
|
-
* prefixes when the primary member is not the root.
|
|
4657
|
-
*/
|
|
4658
3969
|
files_to_edit: CoverageSetupFileToEdit[]
|
|
4659
|
-
/**
|
|
4660
|
-
* Compatibility copy of the primary member's snippets, with workspace
|
|
4661
|
-
* prefixes when the primary member is not the root.
|
|
4662
|
-
*/
|
|
4663
3970
|
snippets: CoverageSetupSnippet[]
|
|
4664
|
-
/**
|
|
4665
|
-
* Optional Dockerfile RUN/COPY snippet to enable the beacon in
|
|
4666
|
-
* containerised deployments.
|
|
4667
|
-
*/
|
|
4668
3971
|
dockerfile_snippet?: (string | null)
|
|
4669
|
-
/**
|
|
4670
|
-
* Ordered next-step instructions for the agent / human operator.
|
|
4671
|
-
*/
|
|
4672
3972
|
next_steps: string[]
|
|
4673
|
-
/**
|
|
4674
|
-
* Non-fatal warnings raised during setup detection.
|
|
4675
|
-
*/
|
|
4676
3973
|
warnings: string[]
|
|
4677
|
-
|
|
4678
|
-
* `_meta` block emitted only when `--explain` is passed.
|
|
4679
|
-
*/
|
|
4680
|
-
_meta?: {
|
|
4681
|
-
[k: string]: unknown
|
|
3974
|
+
_meta?: unknown
|
|
4682
3975
|
}
|
|
4683
|
-
}
|
|
4684
|
-
/**
|
|
4685
|
-
* Per-workspace setup recipe inside [`CoverageSetupOutput::members`].
|
|
4686
|
-
*/
|
|
4687
3976
|
export interface CoverageSetupMember {
|
|
4688
|
-
/**
|
|
4689
|
-
* Workspace package name (or root marker for single-package projects).
|
|
4690
|
-
*/
|
|
4691
3977
|
name: string
|
|
4692
|
-
/**
|
|
4693
|
-
* Workspace path relative to the analysed root, or `.` for the root
|
|
4694
|
-
* member.
|
|
4695
|
-
*/
|
|
4696
3978
|
path: string
|
|
4697
3979
|
framework_detected: CoverageSetupFramework
|
|
4698
|
-
/**
|
|
4699
|
-
* Package manager detected for this member.
|
|
4700
|
-
*/
|
|
4701
3980
|
package_manager?: (CoverageSetupPackageManager | null)
|
|
4702
|
-
/**
|
|
4703
|
-
* Runtime targets supported by this member's framework.
|
|
4704
|
-
*/
|
|
4705
3981
|
runtime_targets: CoverageSetupRuntimeTarget[]
|
|
4706
|
-
/**
|
|
4707
|
-
* Files the agent should edit to wire in the beacon.
|
|
4708
|
-
*/
|
|
4709
3982
|
files_to_edit: CoverageSetupFileToEdit[]
|
|
4710
|
-
/**
|
|
4711
|
-
* Code snippets the agent should paste into the edited files.
|
|
4712
|
-
*/
|
|
4713
3983
|
snippets: CoverageSetupSnippet[]
|
|
4714
|
-
/**
|
|
4715
|
-
* Optional Dockerfile snippet specific to this member.
|
|
4716
|
-
*/
|
|
4717
3984
|
dockerfile_snippet?: (string | null)
|
|
4718
|
-
/**
|
|
4719
|
-
* Member-scoped warnings.
|
|
4720
|
-
*/
|
|
4721
3985
|
warnings: string[]
|
|
4722
3986
|
}
|
|
4723
|
-
/**
|
|
4724
|
-
* Single file to edit inside [`CoverageSetupMember::files_to_edit`] or
|
|
4725
|
-
* [`CoverageSetupOutput::files_to_edit`].
|
|
4726
|
-
*/
|
|
4727
3987
|
export interface CoverageSetupFileToEdit {
|
|
4728
|
-
/**
|
|
4729
|
-
* Workspace-relative path to the file to edit.
|
|
4730
|
-
*/
|
|
4731
3988
|
path: string
|
|
4732
|
-
/**
|
|
4733
|
-
* Why the file needs editing (e.g. `"Mount the beacon middleware"`).
|
|
4734
|
-
*/
|
|
4735
3989
|
reason: string
|
|
4736
3990
|
}
|
|
4737
|
-
/**
|
|
4738
|
-
* Single code snippet inside [`CoverageSetupMember::snippets`] or
|
|
4739
|
-
* [`CoverageSetupOutput::snippets`].
|
|
4740
|
-
*/
|
|
4741
3991
|
export interface CoverageSetupSnippet {
|
|
4742
|
-
/**
|
|
4743
|
-
* Short label identifying the snippet (used by the human renderer).
|
|
4744
|
-
*/
|
|
4745
3992
|
label: string
|
|
4746
|
-
/**
|
|
4747
|
-
* Workspace-relative path the snippet should be pasted into.
|
|
4748
|
-
*/
|
|
4749
3993
|
path: string
|
|
4750
|
-
/**
|
|
4751
|
-
* Snippet content (literal source text).
|
|
4752
|
-
*/
|
|
4753
3994
|
content: string
|
|
4754
3995
|
}
|
|
4755
|
-
/**
|
|
4756
|
-
* Envelope emitted by `fallow coverage analyze --format json`.
|
|
4757
|
-
*
|
|
4758
|
-
* Focused runtime coverage analysis output. Local mode reads
|
|
4759
|
-
* `--runtime-coverage <path>`. Cloud mode requires explicit `--cloud` /
|
|
4760
|
-
* `--runtime-coverage-cloud` or `FALLOW_RUNTIME_COVERAGE_SOURCE=cloud`;
|
|
4761
|
-
* `FALLOW_API_KEY` alone does NOT select cloud mode.
|
|
4762
|
-
*
|
|
4763
|
-
* Constructed at runtime in
|
|
4764
|
-
* `crates/cli/src/coverage/analyze.rs::print_runtime_json`; the wire is
|
|
4765
|
-
* `serde_json::to_value(&envelope)`. The drift gate keeps this struct
|
|
4766
|
-
* aligned with `docs/output-schema.json`. Carries its own schema-version
|
|
4767
|
-
* discriminator ([`CoverageAnalyzeSchemaVersion`]) because runtime
|
|
4768
|
-
* coverage iterates independently of the main JSON contract version.
|
|
4769
|
-
*/
|
|
4770
3996
|
export interface CoverageAnalyzeOutput {
|
|
4771
3997
|
schema_version: CoverageAnalyzeSchemaVersion
|
|
4772
3998
|
version: ToolVersion
|
|
4773
3999
|
elapsed_ms: ElapsedMs
|
|
4774
4000
|
runtime_coverage: RuntimeCoverageReport
|
|
4775
|
-
/**
|
|
4776
|
-
* `_meta` block with metric / rule definitions, emitted when `--explain`
|
|
4777
|
-
* is passed. Populated via the post-pass injection in
|
|
4778
|
-
* `print_runtime_json` (matches the pattern used by every other typed
|
|
4779
|
-
* envelope; the typed struct sets this to `None` and the JSON layer
|
|
4780
|
-
* merges in the `crate::explain::coverage_analyze_meta()` payload).
|
|
4781
|
-
*/
|
|
4782
4001
|
_meta?: (Meta | null)
|
|
4783
4002
|
}
|
|
4784
4003
|
/**
|
|
@@ -4795,38 +4014,12 @@ boundaries: BoundariesListing
|
|
|
4795
4014
|
* `boundaries` block carried by [`ListBoundariesOutput`].
|
|
4796
4015
|
*/
|
|
4797
4016
|
export interface BoundariesListing {
|
|
4798
|
-
/**
|
|
4799
|
-
* `false` when the project has no `boundaries` configured; `true`
|
|
4800
|
-
* otherwise. When `false` every array below is empty and every count
|
|
4801
|
-
* is `0` (parity is enforced so consumers can read the counts without
|
|
4802
|
-
* first branching on this flag).
|
|
4803
|
-
*/
|
|
4804
4017
|
configured: boolean
|
|
4805
|
-
/**
|
|
4806
|
-
* Length of [`Self::zones`]; emitted alongside the array for parity
|
|
4807
|
-
* with `rule_count` / `logical_group_count`.
|
|
4808
|
-
*/
|
|
4809
4018
|
zone_count: number
|
|
4810
|
-
/**
|
|
4811
|
-
* Boundary zones after preset and `autoDiscover` expansion.
|
|
4812
|
-
*/
|
|
4813
4019
|
zones: BoundariesListZone[]
|
|
4814
|
-
/**
|
|
4815
|
-
* Length of [`Self::rules`].
|
|
4816
|
-
*/
|
|
4817
4020
|
rule_count: number
|
|
4818
|
-
/**
|
|
4819
|
-
* Boundary import rules, each `from -> allow[]`.
|
|
4820
|
-
*/
|
|
4821
4021
|
rules: BoundariesListRule[]
|
|
4822
|
-
/**
|
|
4823
|
-
* Length of [`Self::logical_groups`]. Always present (issue #373).
|
|
4824
|
-
*/
|
|
4825
4022
|
logical_group_count: number
|
|
4826
|
-
/**
|
|
4827
|
-
* Pre-expansion `autoDiscover` groups carrying the user-authored parent
|
|
4828
|
-
* name and grouping intent (issue #373).
|
|
4829
|
-
*/
|
|
4830
4023
|
logical_groups: BoundariesListLogicalGroup[]
|
|
4831
4024
|
}
|
|
4832
4025
|
/**
|
|
@@ -4834,18 +4027,8 @@ logical_groups: BoundariesListLogicalGroup[]
|
|
|
4834
4027
|
* classifies files into a single zone via glob patterns.
|
|
4835
4028
|
*/
|
|
4836
4029
|
export interface BoundariesListZone {
|
|
4837
|
-
/**
|
|
4838
|
-
* Zone identifier as referenced in rules (e.g. `app`, `features/auth`).
|
|
4839
|
-
*/
|
|
4840
4030
|
name: string
|
|
4841
|
-
/**
|
|
4842
|
-
* Compiled glob patterns. Children of an `autoDiscover` parent each
|
|
4843
|
-
* carry a single pattern like `src/features/auth/**`.
|
|
4844
|
-
*/
|
|
4845
4031
|
patterns: string[]
|
|
4846
|
-
/**
|
|
4847
|
-
* Number of discovered files classified into this zone.
|
|
4848
|
-
*/
|
|
4849
4032
|
file_count: number
|
|
4850
4033
|
}
|
|
4851
4034
|
/**
|
|
@@ -4855,14 +4038,7 @@ file_count: number
|
|
|
4855
4038
|
* corresponding [`BoundariesListLogicalGroup::authored_rule`].
|
|
4856
4039
|
*/
|
|
4857
4040
|
export interface BoundariesListRule {
|
|
4858
|
-
/**
|
|
4859
|
-
* Source zone the rule applies to.
|
|
4860
|
-
*/
|
|
4861
4041
|
from: string
|
|
4862
|
-
/**
|
|
4863
|
-
* Target zones [`Self::from`] is allowed to import from. Self-imports
|
|
4864
|
-
* are always allowed implicitly.
|
|
4865
|
-
*/
|
|
4866
4042
|
allow: string[]
|
|
4867
4043
|
}
|
|
4868
4044
|
/**
|
|
@@ -4872,75 +4048,28 @@ allow: string[]
|
|
|
4872
4048
|
* would otherwise flatten it out of [`BoundariesListing::zones`].
|
|
4873
4049
|
*/
|
|
4874
4050
|
export interface BoundariesListLogicalGroup {
|
|
4875
|
-
/**
|
|
4876
|
-
* Logical parent zone name as authored by the user.
|
|
4877
|
-
*/
|
|
4878
4051
|
name: string
|
|
4879
|
-
/**
|
|
4880
|
-
* Discovered child zone names in stable directory-sorted order.
|
|
4881
|
-
*/
|
|
4882
4052
|
children: string[]
|
|
4883
|
-
/**
|
|
4884
|
-
* Verbatim `autoDiscover` strings from the user's config (not
|
|
4885
|
-
* normalized) so round-trip tooling can match byte-for-byte.
|
|
4886
|
-
*/
|
|
4887
4053
|
auto_discover: string[]
|
|
4888
4054
|
status: LogicalGroupStatus
|
|
4889
|
-
/**
|
|
4890
|
-
* Position of the parent zone in the user's pre-expansion `zones[]`.
|
|
4891
|
-
*/
|
|
4892
4055
|
source_zone_index: number
|
|
4893
|
-
/**
|
|
4894
|
-
* Sum of `file_count` across [`Self::children`] plus the fallback
|
|
4895
|
-
* zone's `file_count` when present.
|
|
4896
|
-
*/
|
|
4897
4056
|
file_count: number
|
|
4898
|
-
/**
|
|
4899
|
-
* Pre-expansion rule keyed on the parent name, when the user wrote
|
|
4900
|
-
* one.
|
|
4901
|
-
*/
|
|
4902
4057
|
authored_rule?: (AuthoredRule | null)
|
|
4903
|
-
/**
|
|
4904
|
-
* When the parent zone also carried explicit `patterns`, it stayed in
|
|
4905
|
-
* [`BoundariesListing::zones`] as a fallback classifier; this is its
|
|
4906
|
-
* name. Equal to [`Self::name`] when present.
|
|
4907
|
-
*/
|
|
4908
4058
|
fallback_zone?: (string | null)
|
|
4909
|
-
/**
|
|
4910
|
-
* Parent zone indices merged into this group when the user declared
|
|
4911
|
-
* the same parent name multiple times.
|
|
4912
|
-
*/
|
|
4913
4059
|
merged_from?: (number[] | null)
|
|
4914
|
-
/**
|
|
4915
|
-
* Echo of the parent zone's `root` (subtree scope) as the user wrote
|
|
4916
|
-
* it. `None` when the parent had no `root` field.
|
|
4917
|
-
*/
|
|
4918
4060
|
original_zone_root?: (string | null)
|
|
4919
|
-
/**
|
|
4920
|
-
* Parallel to [`Self::children`]: for child at index `i`, the index
|
|
4921
|
-
* into [`Self::auto_discover`] of the path that produced it. Empty
|
|
4922
|
-
* when only one path was authored (every child trivially maps to
|
|
4923
|
-
* index 0). `serde(default)` keeps the schema's `required` array in
|
|
4924
|
-
* step with the runtime's `skip_serializing_if` behavior.
|
|
4925
|
-
*/
|
|
4926
4061
|
child_source_indices?: number[]
|
|
4927
4062
|
}
|
|
4928
4063
|
/**
|
|
4929
|
-
* Pre-expansion
|
|
4930
|
-
* user's original intent (`{ from: "features", allow: ["shared"] }`) even
|
|
4931
|
-
* after `expand_auto_discover` rewrote it into per-child rules
|
|
4932
|
-
* (`features/auth -> shared`, `features/billing -> shared`).
|
|
4064
|
+
* Pre-expansion rule preserved on a [`LogicalGroup`].
|
|
4933
4065
|
*/
|
|
4934
4066
|
export interface AuthoredRule {
|
|
4935
4067
|
/**
|
|
4936
|
-
*
|
|
4068
|
+
* Authored `allow` list.
|
|
4937
4069
|
*/
|
|
4938
4070
|
allow: string[]
|
|
4939
4071
|
/**
|
|
4940
|
-
*
|
|
4941
|
-
* from JSON output when empty; `serde(default)` keeps the derived
|
|
4942
|
-
* schema in lock-step (schemars 1 marks any field with a
|
|
4943
|
-
* `serde(default)` attribute as non-required).
|
|
4072
|
+
* Authored `allowTypeOnly` list.
|
|
4944
4073
|
*/
|
|
4945
4074
|
allow_type_only?: string[]
|
|
4946
4075
|
}
|
|
@@ -5008,6 +4137,10 @@ hotspot_summary?: (HotspotSummary | null)
|
|
|
5008
4137
|
* `--runtime-coverage`).
|
|
5009
4138
|
*/
|
|
5010
4139
|
runtime_coverage?: (RuntimeCoverageReport | null)
|
|
4140
|
+
/**
|
|
4141
|
+
* Combined coverage, runtime, complexity, and change-scope verdicts.
|
|
4142
|
+
*/
|
|
4143
|
+
coverage_intelligence?: (CoverageIntelligenceReport | null)
|
|
5011
4144
|
/**
|
|
5012
4145
|
* Functions exceeding 60 LOC (very high risk). Only present when unit size
|
|
5013
4146
|
* very-high-risk bin >= 3%. Sorted by line count descending.
|
|
@@ -5037,31 +4170,9 @@ health_trend?: (HealthTrend | null)
|
|
|
5037
4170
|
* back to the report root.
|
|
5038
4171
|
*/
|
|
5039
4172
|
actions_meta?: (HealthActionsMeta | null)
|
|
5040
|
-
/**
|
|
5041
|
-
* Resolver mode used when --group-by is active. Present only on grouped
|
|
5042
|
-
* output. The top-level `vital_signs`, `health_score`, and `summary` keep
|
|
5043
|
-
* the active run scope (for example after --workspace); per-group versions
|
|
5044
|
-
* live inside each entry of `groups`.
|
|
5045
|
-
*/
|
|
5046
4173
|
grouped_by?: (GroupByMode | null)
|
|
5047
|
-
/**
|
|
5048
|
-
* Per-group health output, present only when `--group-by` is active.
|
|
5049
|
-
* Each group recomputes its own `vital_signs` and `health_score` from
|
|
5050
|
-
* the files in that group, mirroring how `--workspace` scopes a single
|
|
5051
|
-
* subset.
|
|
5052
|
-
*/
|
|
5053
4174
|
groups?: (HealthGroup[] | null)
|
|
5054
|
-
/**
|
|
5055
|
-
* `_meta` block with metric / rule definitions, emitted when `--explain`
|
|
5056
|
-
* is passed (always present in MCP responses).
|
|
5057
|
-
*/
|
|
5058
4175
|
_meta?: (Meta | null)
|
|
5059
|
-
/**
|
|
5060
|
-
* Workspace-discovery diagnostics surfaced during config load
|
|
5061
|
-
* (issue #473). Mirror of [`CheckOutput::workspace_diagnostics`] so
|
|
5062
|
-
* stand-alone `fallow health --format json` consumers see the same
|
|
5063
|
-
* signal.
|
|
5064
|
-
*/
|
|
5065
4176
|
workspace_diagnostics?: WorkspaceDiagnostic[]
|
|
5066
4177
|
}
|
|
5067
4178
|
/**
|
|
@@ -5103,6 +4214,12 @@ files_analyzed: number
|
|
|
5103
4214
|
* rendered finding count, not the un-truncated total.
|
|
5104
4215
|
*/
|
|
5105
4216
|
functions_above_threshold: number
|
|
4217
|
+
/**
|
|
4218
|
+
* Whether CRAP findings in this group share a single coverage-source kind
|
|
4219
|
+
* (`uniform`) or combine Istanbul / estimated / inherited sources
|
|
4220
|
+
* (`mixed`). Absent when no grouped finding carries CRAP source data.
|
|
4221
|
+
*/
|
|
4222
|
+
coverage_source_consistency?: (CoverageSourceConsistency | null)
|
|
5106
4223
|
/**
|
|
5107
4224
|
* Per-group vital signs recomputed from the files in this group. Absent
|
|
5108
4225
|
* when --score-only suppressed top-level vital signs.
|
|
@@ -5151,19 +4268,15 @@ targets?: RefactoringTargetFinding[]
|
|
|
5151
4268
|
actions_meta?: (HealthActionsMeta | null)
|
|
5152
4269
|
}
|
|
5153
4270
|
/**
|
|
5154
|
-
*
|
|
5155
|
-
*
|
|
4271
|
+
* Wire-shape payload for `fallow dupes --format json` (the body that
|
|
4272
|
+
* flattens into [`crate::output_envelope::DupesOutput`] and is also
|
|
4273
|
+
* emitted under the `dupes` / `duplication` key inside the combined and
|
|
4274
|
+
* audit envelopes).
|
|
5156
4275
|
*
|
|
5157
|
-
*
|
|
5158
|
-
*
|
|
5159
|
-
*
|
|
5160
|
-
*
|
|
5161
|
-
* typed [`crate::output_dupes::CloneGroupFinding`] /
|
|
5162
|
-
* [`crate::output_dupes::CloneFamilyFinding`] wrappers so the `actions[]`
|
|
5163
|
-
* field is part of the schema-derived contract.
|
|
5164
|
-
* `grouped_by` / `groups` / `total_issues` are populated by the grouped
|
|
5165
|
-
* builder; on the ungrouped path they stay `None` and `skip_serializing_if`
|
|
5166
|
-
* drops them.
|
|
4276
|
+
* Mirrors [`DuplicationReport`] field-for-field, except `clone_groups`
|
|
4277
|
+
* and `clone_families` carry the typed wrapper envelopes instead of bare
|
|
4278
|
+
* findings, so the schema (and any TS / agent consumer) sees the typed
|
|
4279
|
+
* `actions[]` natively.
|
|
5167
4280
|
*/
|
|
5168
4281
|
export interface DupesOutput {
|
|
5169
4282
|
schema_version: SchemaVersion
|
|
@@ -5188,29 +4301,8 @@ clone_families: CloneFamilyFinding[]
|
|
|
5188
4301
|
*/
|
|
5189
4302
|
mirrored_directories?: MirroredDirectory[]
|
|
5190
4303
|
stats: DuplicationStats
|
|
5191
|
-
/**
|
|
5192
|
-
* Resolver mode used for partitioning. Present only when `--group-by` is
|
|
5193
|
-
* active.
|
|
5194
|
-
*/
|
|
5195
4304
|
grouped_by?: (GroupByMode | null)
|
|
5196
|
-
/**
|
|
5197
|
-
* Total clone groups across all buckets when `--group-by` is active.
|
|
5198
|
-
* Mirrors the grouped check / health envelopes which expose
|
|
5199
|
-
* `total_issues` so MCP and CI consumers can read the same key across
|
|
5200
|
-
* commands.
|
|
5201
|
-
*/
|
|
5202
4305
|
total_issues?: (number | null)
|
|
5203
|
-
/**
|
|
5204
|
-
* Per-group buckets when `--group-by` is active. Each clone group is
|
|
5205
|
-
* attributed to its largest-owner key (most instances; alphabetical
|
|
5206
|
-
* tiebreak). Sort: most clone groups first, then alphabetical, with
|
|
5207
|
-
* `(unowned)` pinned last.
|
|
5208
|
-
*
|
|
5209
|
-
* Each bucket's `clone_groups` and `clone_families` carry the typed
|
|
5210
|
-
* finding wrappers ([`crate::output_dupes::AttributedCloneGroupFinding`],
|
|
5211
|
-
* [`crate::output_dupes::CloneFamilyFinding`]) so the `actions[]`
|
|
5212
|
-
* augmentation is part of the schema-derived contract.
|
|
5213
|
-
*/
|
|
5214
4306
|
groups?: (DuplicationGroup[] | null)
|
|
5215
4307
|
/**
|
|
5216
4308
|
* `_meta` block with metric / rule definitions, emitted when `--explain`
|
|
@@ -5271,6 +4363,13 @@ line_count: number
|
|
|
5271
4363
|
* CloneInstance shape.
|
|
5272
4364
|
*/
|
|
5273
4365
|
instances: AttributedInstance[]
|
|
4366
|
+
/**
|
|
4367
|
+
* Stable content fingerprint, usually `dup:<8hex>` and widened on rare
|
|
4368
|
+
* report collisions. Addressable via `fallow dupes --trace dup:<fp>`.
|
|
4369
|
+
* Computed from the group's instances, so it matches the top-level
|
|
4370
|
+
* `clone_groups[].fingerprint` for the same clone.
|
|
4371
|
+
*/
|
|
4372
|
+
fingerprint: string
|
|
5274
4373
|
/**
|
|
5275
4374
|
* Suggested next steps. Always emitted.
|
|
5276
4375
|
*/
|
|
@@ -5329,19 +4428,8 @@ schema_version: SchemaVersion
|
|
|
5329
4428
|
version: ToolVersion
|
|
5330
4429
|
elapsed_ms: ElapsedMs
|
|
5331
4430
|
grouped_by: GroupByMode
|
|
5332
|
-
/**
|
|
5333
|
-
* Total number of issues across all groups.
|
|
5334
|
-
*/
|
|
5335
4431
|
total_issues: number
|
|
5336
|
-
/**
|
|
5337
|
-
* One entry per group; each contains the same issue arrays as
|
|
5338
|
-
* `CheckOutput` plus the group key and per-group total.
|
|
5339
|
-
*/
|
|
5340
4432
|
groups: CheckGroupedEntry[]
|
|
5341
|
-
/**
|
|
5342
|
-
* `_meta` block with metric / rule definitions, emitted when `--explain`
|
|
5343
|
-
* is passed.
|
|
5344
|
-
*/
|
|
5345
4433
|
_meta?: (Meta | null)
|
|
5346
4434
|
}
|
|
5347
4435
|
/**
|
|
@@ -5350,23 +4438,8 @@ _meta?: (Meta | null)
|
|
|
5350
4438
|
* `AnalysisResults`.
|
|
5351
4439
|
*/
|
|
5352
4440
|
export interface CheckGroupedEntry {
|
|
5353
|
-
/**
|
|
5354
|
-
* Group identifier produced by the resolver. For `package` grouping:
|
|
5355
|
-
* workspace package name. For `owner` grouping: the CODEOWNERS team.
|
|
5356
|
-
* For `directory` grouping: the top-level directory prefix. For
|
|
5357
|
-
* `section` grouping: the GitLab CODEOWNERS section name (or
|
|
5358
|
-
* `(no section)` / `(unowned)` for unmatched files).
|
|
5359
|
-
*/
|
|
5360
4441
|
key: string
|
|
5361
|
-
/**
|
|
5362
|
-
* Section default owners (GitLab CODEOWNERS `[Section] @owner1
|
|
5363
|
-
* @owner2`). Emitted only when `grouped_by` is `section`. Empty for
|
|
5364
|
-
* the `(no section)` and `(unowned)` buckets.
|
|
5365
|
-
*/
|
|
5366
4442
|
owners?: (string[] | null)
|
|
5367
|
-
/**
|
|
5368
|
-
* Total number of issues in this group.
|
|
5369
|
-
*/
|
|
5370
4443
|
total_issues: number
|
|
5371
4444
|
/**
|
|
5372
4445
|
* Files not reachable from any entry point. Wrapped in
|
|
@@ -5522,89 +4595,229 @@ unused_dependency_overrides?: UnusedDependencyOverrideFinding[]
|
|
|
5522
4595
|
misconfigured_dependency_overrides?: MisconfiguredDependencyOverrideFinding[]
|
|
5523
4596
|
}
|
|
5524
4597
|
/**
|
|
5525
|
-
*
|
|
5526
|
-
* invocation). Wraps the per-analysis sub-results inside a single envelope
|
|
5527
|
-
* with the standard `schema_version` / `version` / `elapsed_ms` header.
|
|
5528
|
-
*
|
|
5529
|
-
* Each sub-result is `Option<...>` so `--only` / `--skip` can suppress a
|
|
5530
|
-
* pass without leaving an empty key on the wire. The `check` sub-result is
|
|
5531
|
-
* the full [`CheckOutput`] envelope (including its own `schema_version` /
|
|
5532
|
-
* `version` / `elapsed_ms`), `dupes` is the typed [`DupesReportPayload`]
|
|
5533
|
-
* emitted via `crate::output_dupes::DupesReportPayload::from_report`, and
|
|
5534
|
-
* `health` is the bare [`HealthReport`] body: the runtime emit calls
|
|
5535
|
-
* `serde_json::to_value(&report)` directly rather than wrapping it in the
|
|
5536
|
-
* per-command envelope. The committed schema points `dupes` at
|
|
5537
|
-
* `#/definitions/DupesReportPayload` and `health` at
|
|
5538
|
-
* `#/definitions/HealthReport` so the documented shape matches the
|
|
5539
|
-
* wire; the `committed_property_refs_match_derived_property_refs`
|
|
5540
|
-
* drift test enforces the alignment.
|
|
4598
|
+
* The rendered impact report, derived purely from the store (no analysis run).
|
|
5541
4599
|
*/
|
|
5542
|
-
export interface
|
|
5543
|
-
schema_version:
|
|
5544
|
-
|
|
5545
|
-
|
|
4600
|
+
export interface ImpactReport {
|
|
4601
|
+
schema_version: ImpactReportSchemaVersion
|
|
4602
|
+
enabled: boolean
|
|
4603
|
+
record_count: number
|
|
4604
|
+
first_recorded?: (string | null)
|
|
5546
4605
|
/**
|
|
5547
|
-
*
|
|
5548
|
-
*
|
|
5549
|
-
*
|
|
4606
|
+
* Git SHA of the most recent recorded run, so a consumer can tell which
|
|
4607
|
+
* commit the `surfacing` counts belong to. This is an ABBREVIATED SHA
|
|
4608
|
+
* (`git rev-parse --short`), so it is for display/correlation only and will
|
|
4609
|
+
* not match a full 40-character SHA from `$GITHUB_SHA` or the git API
|
|
4610
|
+
* without expansion. None when the latest run had no SHA (not a git repo)
|
|
4611
|
+
* or there are no records yet.
|
|
5550
4612
|
*/
|
|
5551
|
-
|
|
4613
|
+
latest_git_sha?: (string | null)
|
|
5552
4614
|
/**
|
|
5553
|
-
*
|
|
4615
|
+
* Counts from the most recent recorded run. These are CHANGED-FILE scoped
|
|
4616
|
+
* (each record comes from a `fallow audit` run, whose default `new-only`
|
|
4617
|
+
* gate counts only findings in the changed files of that run), NOT a
|
|
4618
|
+
* whole-project total.
|
|
5554
4619
|
*/
|
|
5555
|
-
|
|
4620
|
+
surfacing?: (ImpactCounts | null)
|
|
5556
4621
|
/**
|
|
5557
|
-
*
|
|
5558
|
-
* `DupesOutput` envelope). Absent when `--skip dupes`. The payload
|
|
5559
|
-
* wraps each clone group / family with its typed `actions[]` array via
|
|
5560
|
-
* `crate::output_dupes::DupesReportPayload::from_report`.
|
|
4622
|
+
* Trend between the two most recent records. None until two records exist.
|
|
5561
4623
|
*/
|
|
5562
|
-
|
|
4624
|
+
trend?: (TrendSummary | null)
|
|
5563
4625
|
/**
|
|
5564
|
-
*
|
|
5565
|
-
*
|
|
4626
|
+
* Counts from the most recent whole-project `fallow` run. WHOLE-PROJECT
|
|
4627
|
+
* scope (not changed-file), so this is the current issue total across the
|
|
4628
|
+
* whole repo, context next to the actionable changed-file `surfacing`
|
|
4629
|
+
* count. None until a full `fallow` run has been recorded. v1.6.
|
|
5566
4630
|
*/
|
|
5567
|
-
|
|
4631
|
+
project_surfacing?: (ImpactCounts | null)
|
|
4632
|
+
/**
|
|
4633
|
+
* Trend between the two most recent whole-project records. Comparable over
|
|
4634
|
+
* time (same whole-project denominator every run), unlike the changed-file
|
|
4635
|
+
* `trend`. None until two full `fallow` runs exist. v1.6.
|
|
4636
|
+
*/
|
|
4637
|
+
project_trend?: (TrendSummary | null)
|
|
4638
|
+
containment_count: number
|
|
4639
|
+
/**
|
|
4640
|
+
* Most recent containment events (newest last), capped for display.
|
|
4641
|
+
*/
|
|
4642
|
+
recent_containment: ContainmentEvent[]
|
|
4643
|
+
/**
|
|
4644
|
+
* Lifetime count of findings fallow credits as genuinely resolved (code
|
|
4645
|
+
* removed or refactored, never a `fallow-ignore`). v1.5.
|
|
4646
|
+
*/
|
|
4647
|
+
resolved_total: number
|
|
4648
|
+
/**
|
|
4649
|
+
* Lifetime count of findings silenced by a newly-added `fallow-ignore`.
|
|
4650
|
+
* Reported as honest context, never as a win. v1.5.
|
|
4651
|
+
*/
|
|
4652
|
+
suppressed_total: number
|
|
4653
|
+
/**
|
|
4654
|
+
* Most recent resolution events (newest last), capped for display. v1.5.
|
|
4655
|
+
*/
|
|
4656
|
+
recent_resolved: ResolutionEvent[]
|
|
4657
|
+
/**
|
|
4658
|
+
* Whether per-finding attribution has a baseline yet. False on a freshly
|
|
4659
|
+
* upgraded v1 store (no frontier captured), which the renderer uses to show
|
|
4660
|
+
* "resolution tracking starts from your next run" instead of a bare zero.
|
|
4661
|
+
*/
|
|
4662
|
+
attribution_active: boolean
|
|
5568
4663
|
}
|
|
5569
4664
|
/**
|
|
5570
|
-
*
|
|
4665
|
+
* Per-category issue counts captured at a recorded run.
|
|
5571
4666
|
*/
|
|
5572
|
-
export interface
|
|
4667
|
+
export interface ImpactCounts {
|
|
4668
|
+
total_issues: number
|
|
4669
|
+
dead_code: number
|
|
4670
|
+
complexity: number
|
|
4671
|
+
duplication: number
|
|
4672
|
+
}
|
|
5573
4673
|
/**
|
|
5574
|
-
*
|
|
4674
|
+
* A computed trend between the two most recent records.
|
|
5575
4675
|
*/
|
|
5576
|
-
|
|
4676
|
+
export interface TrendSummary {
|
|
4677
|
+
direction: ImpactTrendDirection
|
|
5577
4678
|
/**
|
|
5578
|
-
*
|
|
4679
|
+
* Signed delta in total issues (current minus previous).
|
|
5579
4680
|
*/
|
|
5580
|
-
|
|
4681
|
+
total_delta: number
|
|
4682
|
+
previous_total: number
|
|
4683
|
+
current_total: number
|
|
4684
|
+
}
|
|
4685
|
+
export interface ContainmentEvent {
|
|
4686
|
+
blocked_at: string
|
|
4687
|
+
cleared_at: string
|
|
4688
|
+
git_sha?: (string | null)
|
|
4689
|
+
blocked_counts: ImpactCounts
|
|
4690
|
+
}
|
|
4691
|
+
export interface ResolutionEvent {
|
|
4692
|
+
kind: string
|
|
4693
|
+
path: string
|
|
4694
|
+
symbol?: (string | null)
|
|
4695
|
+
git_sha?: (string | null)
|
|
4696
|
+
timestamp: string
|
|
4697
|
+
}
|
|
5581
4698
|
/**
|
|
5582
|
-
*
|
|
4699
|
+
* The `fallow security --format json` envelope. `security_findings` is the
|
|
4700
|
+
* unique required field used for untagged narrowing in `FallowOutput`.
|
|
5583
4701
|
*/
|
|
5584
|
-
|
|
4702
|
+
export interface SecurityOutput {
|
|
4703
|
+
schema_version: SecuritySchemaVersion
|
|
4704
|
+
/**
|
|
4705
|
+
* Security candidates. Paths are project-root-relative, forward-slash.
|
|
4706
|
+
*/
|
|
4707
|
+
security_findings: SecurityFinding[]
|
|
4708
|
+
/**
|
|
4709
|
+
* In-band blind spot: number of `"use client"` files whose transitive
|
|
4710
|
+
* import cone contains a dynamic `import()` the reachability BFS could not
|
|
4711
|
+
* follow. A leak hidden behind such an edge would not be reported, so a
|
|
4712
|
+
* zero finding count with a non-zero value here is NOT a clean bill.
|
|
4713
|
+
*/
|
|
4714
|
+
unresolved_edge_files: number
|
|
4715
|
+
/**
|
|
4716
|
+
* In-band blind spot: number of sink-shaped nodes the catalogue detector
|
|
4717
|
+
* could not flatten to a static callee path (dynamic dispatch, computed
|
|
4718
|
+
* members, aliased bindings). A zero finding count with a non-zero value
|
|
4719
|
+
* here is NOT a clean bill.
|
|
4720
|
+
*/
|
|
4721
|
+
unresolved_callee_sites: number
|
|
5585
4722
|
}
|
|
5586
4723
|
/**
|
|
5587
|
-
*
|
|
4724
|
+
* A local security CANDIDATE for downstream agent verification, NOT a verified
|
|
4725
|
+
* vulnerability. Emitted only by `fallow security`, never under bare `fallow`
|
|
4726
|
+
* or the `audit` gate. There is deliberately no `confidence` or
|
|
4727
|
+
* `signal_strength` field: fallow does not prove exploitability, so the trace
|
|
4728
|
+
* (its hops and length) is the only honest signal.
|
|
5588
4729
|
*/
|
|
5589
|
-
export interface
|
|
5590
|
-
|
|
4730
|
+
export interface SecurityFinding {
|
|
4731
|
+
kind: SecurityFindingKind
|
|
5591
4732
|
/**
|
|
5592
|
-
*
|
|
4733
|
+
* The catalogue category id (e.g. `"dangerous-html"`). `None` for
|
|
4734
|
+
* `ClientServerLeak`; `Some` for `TaintedSink`.
|
|
5593
4735
|
*/
|
|
5594
|
-
|
|
4736
|
+
category?: (string | null)
|
|
5595
4737
|
/**
|
|
5596
|
-
*
|
|
4738
|
+
* The CWE number declared by the matched catalogue entry. `None` for
|
|
4739
|
+
* `ClientServerLeak`; never fabricated beyond the catalogue's value.
|
|
5597
4740
|
*/
|
|
5598
|
-
|
|
4741
|
+
cwe?: (number | null)
|
|
5599
4742
|
/**
|
|
5600
|
-
*
|
|
4743
|
+
* File the finding is anchored on (the client boundary). Absolute
|
|
4744
|
+
* internally; JSON strips the project root via `serde_path::serialize`.
|
|
5601
4745
|
*/
|
|
5602
|
-
|
|
5603
|
-
|
|
4746
|
+
path: string
|
|
4747
|
+
/**
|
|
4748
|
+
* 1-based line number of the anchor.
|
|
4749
|
+
*/
|
|
4750
|
+
line: number
|
|
4751
|
+
/**
|
|
4752
|
+
* 0-based byte column offset of the anchor.
|
|
4753
|
+
*/
|
|
4754
|
+
col: number
|
|
4755
|
+
/**
|
|
4756
|
+
* Agent/human-readable evidence (e.g. the named env var the chain reaches).
|
|
4757
|
+
*/
|
|
4758
|
+
evidence: string
|
|
5604
4759
|
/**
|
|
5605
|
-
*
|
|
5606
|
-
*
|
|
4760
|
+
* Structural import-hop trace from the client boundary to the secret source.
|
|
4761
|
+
* The hop count is the uncalibrated signal; fallow does not prove the path
|
|
4762
|
+
* is exploitable.
|
|
5607
4763
|
*/
|
|
4764
|
+
trace: TraceHop[]
|
|
4765
|
+
/**
|
|
4766
|
+
* Machine-actionable next steps. Always emitted (possibly empty for
|
|
4767
|
+
* forward-compat). For security candidates this is a single file-level
|
|
4768
|
+
* suppress hint (`auto_fixable: false`); there is no auto-fix because
|
|
4769
|
+
* verification is the agent's job, not fallow's.
|
|
4770
|
+
*/
|
|
4771
|
+
actions: IssueAction[]
|
|
4772
|
+
}
|
|
4773
|
+
/**
|
|
4774
|
+
* One hop in a security finding's structural trace. Stored as an absolute path
|
|
4775
|
+
* internally; JSON serialization strips the project root via
|
|
4776
|
+
* `serde_path::serialize`.
|
|
4777
|
+
*/
|
|
4778
|
+
export interface TraceHop {
|
|
4779
|
+
/**
|
|
4780
|
+
* File on this hop of the import chain.
|
|
4781
|
+
*/
|
|
4782
|
+
path: string
|
|
4783
|
+
/**
|
|
4784
|
+
* 1-based line number. Import-chain hops point at the import site; the
|
|
4785
|
+
* terminal secret-source hop points at the source module when extraction
|
|
4786
|
+
* does not carry a more precise member-access span.
|
|
4787
|
+
*/
|
|
4788
|
+
line: number
|
|
4789
|
+
/**
|
|
4790
|
+
* 0-based byte column offset.
|
|
4791
|
+
*/
|
|
4792
|
+
col: number
|
|
4793
|
+
role: TraceHopRole
|
|
4794
|
+
}
|
|
4795
|
+
/**
|
|
4796
|
+
* Bare `fallow --format json` envelope.
|
|
4797
|
+
*/
|
|
4798
|
+
export interface CombinedOutput {
|
|
4799
|
+
schema_version: SchemaVersion
|
|
4800
|
+
version: ToolVersion
|
|
4801
|
+
elapsed_ms: ElapsedMs
|
|
4802
|
+
_meta?: (CombinedMeta | null)
|
|
4803
|
+
check?: (CheckOutput | null)
|
|
4804
|
+
dupes?: (DupesReportPayload | null)
|
|
4805
|
+
health?: (HealthReport | null)
|
|
4806
|
+
}
|
|
4807
|
+
export interface CombinedMeta {
|
|
4808
|
+
check?: (Meta | null)
|
|
4809
|
+
dupes?: (Meta | null)
|
|
4810
|
+
health?: (Meta | null)
|
|
4811
|
+
}
|
|
4812
|
+
/**
|
|
4813
|
+
* Single CodeClimate-compatible issue inside [`CodeClimateOutput`].
|
|
4814
|
+
*/
|
|
4815
|
+
export interface CodeClimateIssue {
|
|
4816
|
+
type: CodeClimateIssueKind
|
|
4817
|
+
check_name: string
|
|
4818
|
+
description: string
|
|
4819
|
+
categories: string[]
|
|
4820
|
+
severity: CodeClimateSeverity
|
|
5608
4821
|
fingerprint: string
|
|
5609
4822
|
location: CodeClimateLocation
|
|
5610
4823
|
}
|