Skip to content

schema: CloneGroup/CloneFamily require actions but runtime doesn't emit it on fallow dupes / combined output #393

@BartWaardenburg

Description

@BartWaardenburg

Problem

docs/output-schema.json lists actions as a required field on every CloneGroup and CloneFamily (augmented via schema_emit.rs::augment_finding_definition), but the runtime emit paths for fallow dupes --format json and fallow --format json (bare combined) do NOT inject actions: [] on these findings. JSON Schema consumers that strict-validate output against the published schema get 234 validation errors on a standalone fallow dupes --format json of vite (one per clone_families[].groups[]) and 608 errors on the combined output (one per clone_groups[] plus the families).

Repro

cargo build --release --bin fallow
FALLOW_QUIET=1 ./target/release/fallow dupes --format json --root benchmarks/fixtures/real-world/vite \
  | python3 -c "
import json, sys
from jsonschema import Draft7Validator
schema = json.load(open('docs/output-schema.json'))
inst = json.load(sys.stdin)
errs = list(Draft7Validator(schema).iter_errors(inst))
print('errors:', len(errs))
for e in errs[:3]: print(' -', list(e.absolute_path), e.validator, e.message[:80])
"

Output:

errors: 234
 - ['clone_families', 0, 'groups', 0] required 'actions' is a required property
 - ['clone_families', 1, 'groups', 0] required 'actions' is a required property
 - ['clone_families', 2, 'groups', 0] required 'actions' is a required property

Background

The schema-derive pass (#338) introduced augment_finding_definition in crates/cli/src/bin/schema_emit.rs to unconditionally push actions into each finding type's required array, with the rationale (from the schema-emit doc comment) "The runtime always emits actions: [...] (possibly empty) on every finding, so requiring the field on the wire is honest." This contract holds for dead-code findings (UnusedFile, UnusedExport, etc.) where crates/cli/src/report/json.rs::build_actions injects actions on every entry, but NOT for CloneGroup/CloneFamily where inject_dupes_actions only runs under certain code paths (e.g., not in the bare combined path).

Fix options

  1. Wire side (recommended, matches the augmentation contract): make the dupes JSON build paths (build_duplication_json, the combined.dupes sub-builder, the audit duplication block) always inject actions: [] on every CloneGroup and CloneFamily so the wire matches the schema.
  2. Schema side: drop actions from CloneGroup/CloneFamily required in finding_augmentation so the schema documents the field as optional. This contradicts the implement-skill rule about "always emit" but is correct if the runtime contract is genuinely conditional.

Discovered during /fallow-review of #391 (Refs #384 item 6). Pre-existing on origin/main; not introduced by #391.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions