Skip to content

Present clone findings as clone groups (#5) - #30

Draft
drogers0 wants to merge 4 commits into
masterfrom
clone-groups-5
Draft

Present clone findings as clone groups (#5)#30
drogers0 wants to merge 4 commits into
masterfrom
clone-groups-5

Conversation

@drogers0

@drogers0 drogers0 commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Closes #5.

Collapses N-way duplicates into first-class clone groups across the JSON and HTML reports, instead of scattering the N·(N−1)/2 pairwise findings. Detection output (findings, scores, pairs) is unchanged — this is a presentation/derivation change — so the frozen detection baseline is not re-frozen.

What changed

  • New grouping primitive. CloneGroup + build_groups (the single grouping source of truth) and a group_stats helper in similarity::clustering. Groups are derived from findings and re-numbered deterministically via a total order over the sorted location-identity vector, so membership/ids are reproducible run-to-run. Without --cluster each finding is its own 2-location singleton group; with it, findings sharing a function merge.
  • JSON (⚠️ BREAKING). Findings now nest under a top-level groups array; the flat findings array is removed. Each group carries its unique locations, max_score/max_duplicated_lines, and its pairwise findings. Consume as for g in groups: for f in g.findings — no clustered-vs-flat branching.
  • HTML. Flat per-finding list by default (unchanged); under --cluster, a summary line (“{group_count} clone groups across {grouped_function_count} functions”) plus one collapsible section per multi-location group. The client-side sort script now reorders only top-level rows, so nested member findings are no longer reparented on first paint.
  • Stats. New group_count + de-duplicated grouped_function_count, populated via group_stats in the pipeline, the sonarqube engine, and diff (recomputed after filtering to changed paths so the report stays internally consistent).
  • SARIF and the in-memory ScanResult.findings model are unchanged.
  • Updated the benchmark harness to read groups[].findings[], regenerated the golden JSON snapshot and all four example reports, and refreshed README / CLAUDE.md / docs.

Validation

cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test (273 lib + 16 integration + 3 golden), and cargo build --release all pass. The detection baseline (benchmark/baseline.json) is untouched.

Collapse N-way duplicates into first-class clone groups across the JSON and
HTML reports instead of scattering the N·(N−1)/2 pairwise findings.

- Add `CloneGroup` + `build_groups` (the single grouping source of truth) and a
  `group_stats` helper in `similarity::clustering`. Groups are derived from
  findings and re-numbered deterministically (total order over the sorted
  location-identity vector), so membership/ids are reproducible run-to-run.
  Without `--cluster` each finding is its own 2-location singleton group; with
  it, findings sharing a function merge. Detection output is unchanged.
- JSON (BREAKING): findings now nest under a top-level `groups` array; the flat
  `findings` array is removed. Each group carries its unique `locations`,
  `max_score`/`max_duplicated_lines`, and its pairwise `findings`.
- HTML: flat per-finding list by default; under `--cluster` a summary line plus
  one collapsible section per multi-location group. Fix the sort script to
  reorder only top-level rows so nested member findings are not reparented.
- Stats: add `group_count` + de-duplicated `grouped_function_count`, populated
  via `group_stats` in the pipeline, sonarqube engine, and `diff` (recomputed
  after filtering to changed paths so the report stays internally consistent).
- Update the benchmark harness to read `groups[].findings[]`, regenerate the
  golden JSON snapshot and the example reports, and refresh README/CLAUDE.md/
  docs. SARIF and the in-memory `ScanResult.findings` model are unchanged, so
  the detection baseline is not re-frozen.
drogers0 added 3 commits July 9, 2026 18:22
Make clone grouping the single, unconditional presentation. Findings
sharing a function identity merge into one family via union-find; the
representative is the most-connected location (identity-min tiebreak).

- HTML: GitHub-style family cards — representative code block plus
  member diffs oriented against the rep (single canonicalization point),
  injective consumed-aware member assignment, self-clones and leftovers
  under "Other matches". Single-finding families render as one open pair
  card; multi-finding families collapse with the first member pre-open.
- Remove --cluster / --cluster-min-size flags, the cluster_findings /
  cluster_min_size config + overrides + validation, and the vestigial
  Finding.metadata field (JSON and SARIF schema change).
- JSON/SARIF flow through the same always-on grouping; SARIF stays
  one-result-per-finding.
- Regenerate golden snapshots (metadata + cluster config removed) and
  examples; refresh docs and CLAUDE.md.

Detection output is unchanged; the frozen baseline is not re-frozen.
…ually

Cut the representative/star model from the HTML family card. A multi-finding
family now lists its member locations and renders every finding as an equal
side-by-side diff card (first pre-open); cross-location and self-clone findings
get identical treatment, with self-clones carrying an "internal duplication"
label. This removes the arbitrary demotion where an in-family self-clone was
buried in a collapsed "Other matches" section while a standalone self-clone
rendered as a full card.

- Remove the `representative` field from CloneGroup and its most-connected
  computation in build_groups (locations stay identity-sorted; finding order
  unchanged).
- Delete the rep source block, member-row consumption/orientation logic, and
  the "Other matches" catch-all from html.rs (render_code_block,
  render_member_rows, orient_finding, and helpers).
- Regenerate the HTML/JSON/SARIF examples; refresh README/CLAUDE/docs.

Detection output is unchanged; the frozen baseline is not re-frozen.
Render the multi-finding family card as `<details open>` so a clone group
shows its findings without a click; its first finding card is already
pre-opened, so the group and its first diff are both visible by default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve clone group presentation for N-way duplicates

1 participant