Skip to content

feat: report content-duplicate commits instead of silently counting a change twice - #116

Merged
kenjudy merged 3 commits into
mainfrom
fix/dedupe-squash-merge-duplicates
Aug 20, 2026
Merged

kenjudy merged 3 commits into
mainfrom
fix/dedupe-squash-merge-duplicates

Conversation

@kenjudy

@kenjudy kenjudy commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Addresses code-quality-metrics-7ccq (P1). Reports rather than corrects, deliberately; the issue permits either and the reasoning is below.

The defect

local-code-metrics.js dedupes analysed commits by SHA. That does not remove a squash-merge duplicate: the squash commit on the default branch and the feature-branch commits it squashed are different SHAs carrying the same change. When the branch survives the merge, both are analysed.

Reproduced on this repository: 15 groups covering 17 redundant entries out of 531, grouping by normalised subject plus total_additions plus total_deletions. The issue predicted 14 of 528. The gap is window drift, since the run is HEAD-anchored and this session added commits between the issue being written and the reproduction; the extra group is the newest commit duplicated with its own surviving branch. Diagnosed before implementing rather than after.

Measured effect, which is why reasoning about it was not enough

metric before after
large_commits_pct 16.85 16.63
sprawling_commits_pct 7.68 7.54
test_coverage_rate 61.80 61.32
test_isolation_rate 8.80 8.90
uncovered_prod_rate 7.30 7.16
p90_lines_changed 266 260
p95_lines_changed 527 482

No verdict flips on this sample, and the direction is not uniform: test_isolation_rate rose while everything else fell. A duplicate lands in both numerator and denominator, so the bias cannot be predicted from first principles, only measured.

The distortion scales with how many merged branches survive, which is branch hygiene rather than engineering practice. That is the opposite of what these metrics claim to measure.

Report, not correct

findContentDuplicateGroups (lib/git.js) groups by normalised subject, reusing the existing PR_REFERENCE_PATTERN, plus total_additions and total_deletions. The summary gains content_duplicate_group_count, content_duplicate_redundant_entries_count and content_duplicate_groups, and the console prints a line when any are found. total_commits, every rate metric and every distribution are untouched.

The content signature is documented as a floor: it misses a multi-commit branch whose squash net diff differs from the sum of its parts. The reliable alternative is the merged pull request head and base via gh, validated on the deferred code-quality-metrics-76ar and GitHub #107, and it was rejected here for three reasons. It would put network and authentication into local-code-metrics.js, which CLAUDE.md keeps deliberately local-only. Two of the six repositories this tool measures have no API access. And the acceptance criterion asks for a false-negative rate validated across all six, which the sandbox restriction on running the tool outside the worktree made impossible to produce.

Silently deduping a number this central on a heuristic that sometimes misfires would be worse than disclosing it. The issue stays open for the validation the acceptance criteria ask for.

The calibration data is unaffected, and this was checked rather than assumed

Every observation in calibration/observations.json records workflow_type: trunk, with zero occurrences of feature_branch anywhere in the file, consistent with the README mandated --single-branch clone protocol for calibration runs. A single-branch clone never fetches the pre-squash branch, so this duplicate shape cannot occur in that data. No observation needs a reservation.

Verification

720 tests across 43 suites, lint and typecheck clean at every commit. Three cycles with predicted and actual RED quoted in their commit messages; one cycle is disclosed as having passed on arrival because the previous implementation already generalised, rather than being presented as a clean cycle.

🤖 Generated with Claude Code

code-quality-metrics-7ccq: local-code-metrics.js dedupes analyzed commits by
SHA only, which does not catch a squash-merge duplicate -- the squash commit
on the default branch and the feature-branch commits it squashed are
different SHAs carrying the same change, so both get analyzed when the
branch survives the merge.

findContentDuplicateGroups (lib/git.js) groups commits sharing a normalized
subject (trailing "(#N)"/"(GH-N)" stripped, reusing the existing
PR_REFERENCE_PATTERN), total_additions and total_deletions, surfacing any
group with more than one distinct SHA. This is a floor, not an exact test:
it will miss a multi-commit branch whose squash diff differs from the sum
of its parts, and documented as detection-only in its own comment -- not
wired into anything yet.

TDD: wrote a stub returning [] unconditionally (compiles, behaviorally
absent), then a test asserting two same-signature, different-SHA commits
group together. Predicted RED: stub returns [] so the assertion fails
comparing [] against the expected one-group array. Actual RED matched
exactly. Implemented the real grouping and got GREEN.
…dContentDuplicateGroups

Three more tests for the function added in the prior commit: PR-reference
suffix stripping, a false-positive guard (same subject, different diff size
must not group), and a same-SHA-input guard. All three passed on arrival --
the prior commit implementation already stripped PR_REFERENCE_PATTERN and
already compared additions/deletions as part of the key, so no production
code changed here. Disclosing this rather than presenting it as a red/green
cycle: predicted RED for the PR-suffix test specifically, expecting it to
need production code, ran it, got GREEN immediately, and stopped to
diagnose before writing anything. Diagnosis was that the generalization
already existed, not that the test was wrong.
code-quality-metrics-7ccq: wires findContentDuplicateGroups (lib/git.js)
into collectLocalMetrics. After metrics is built, groups it by content
signature and adds three summary fields: content_duplicate_group_count,
content_duplicate_redundant_entries_count, and the full
content_duplicate_groups detail (subject, total_additions, total_deletions,
shas). A non-empty result also logs a console line pointing at the summary
field.

Deliberately report-only: total_commits, filtered_from and every rate
metric/distribution are untouched. The detection is a floor (documented on
findContentDuplicateGroups itself) that can miss a divergent squash diff
and could in principle coincide on two unrelated commits, so silently
dropping an entry on this signal would trade a visible distortion for an
invisible one. This is the "report rather than correct" branch the issue
explicitly allows.

TDD: added two tests to collectLocalMetrics.test.js -- a two-branch fixture
(a "(#42)"-suffixed squash-style commit and its un-suffixed original, same
diff size, different SHA) asserting content_duplicate_group_count: 1,
content_duplicate_redundant_entries_count: 1, and the group detail; plus a
guard asserting 0/0/[] when no duplicate exists. Predicted RED: both new
summary fields are undefined before this commit, so
expect(summary.content_duplicate_group_count).toBe(1) (and .toBe(0) in the
guard) fail with "Received: undefined". Actual RED matched exactly for
both. Implemented the wiring and got GREEN; total_commits stayed 2 in the
duplicate fixture, confirming no silent correction.

Fixed an accidental extra closing brace introduced while appending this
describe block to the end of collectLocalMetrics.test.js (caught by
node -c before running the suite).
@kenjudy
kenjudy merged commit 79bc4ca into main Aug 20, 2026
1 check passed
@github-actions

Copy link
Copy Markdown

PR Analysis

Size: small (based on production code)
Production Code: 73 lines (2 files)
Test Code: 123 lines (2 files)
Total: 196 lines (4 files)
Test-to-Production Ratio: 1.68:1
No size or quality concerns.

Strengths

  • 1 test-only commits

Commit Analysis

Total Commits: 3
Average Commit Size: 24 production lines
Average Files per Commit: 1.7

Metric Value
Large commits (>100 prod lines) 0/3 (0%)
Sprawling commits (>5 files) 0/3 (0%)
Test/prod co-change rate 2/3 (67%)
Message quality 3/3 (100%)
Median net additions ratio 0.98
Test-only commits 1
Production-only commits 0

Commit Details

a895f5d Ken Judy (8/20/2026)
feat: detect content-duplicate commit groups by subject and diff size
44 prod lines, 2 files [test+prod]

d1a9dd1 Ken Judy (8/20/2026)
test: cover PR-suffix normalization and false-positive guards for findContentDuplicateGroups
0 prod lines, 1 files

acd5d2a Ken Judy (8/20/2026)
feat: surface content-duplicate commit groups in the analysis summary
29 prod lines, 2 files [test+prod]

Test Coverage

Test-to-Production Ratio: 1.68:1 (no calibrated target for this ratio; reported descriptively)

DORA Capability Assessment

Archetype: harmonious-high-achiever
Strong batch discipline, test coverage, and message quality. AI tools likely amplifying positive outcomes.

Capability Metric Value Target
Small Batches Large commit % 0% <18% (no critical band established)
Small Batches Sprawling commit % 0% <18% (no critical band established)
Version Control Test/prod co-change rate 67% >23% (no critical band established)
Version Control Message quality 100% no band, see spec
AI Risk Signal Net additions ratio (median) 0.98 no band, see spec
Sample size (3 commits) is below the 5-commit convention for a rate verdict (code-quality-metrics-w9f): large-commit %, sprawling-commit % and test/prod co-change rate are reported below without a pass/fail judgement.
Automated by Code Metrics Workflow

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.

1 participant