Skip to content

validate reports every duplicate-id twice, and counts it twice #365

Description

@MongLong0214

Found during post-merge verification of #352. Pre-existing — reproduced identically on c9a83a2 (before the #352 merge) and on ca538a6 (after), so this is not a regression from that change.

Reproduced

A two-block message declaring one Record-Id in both blocks, validated in a full clone with the notes refspec configured:

$ commitlore validate -f dup.txt
shape failed · references failed
4: duplicate-id Record-Id — got "r-dup352z", want "exactly one record per Record-Id"
8: duplicate-id Record-Id — got "r-dup352z", want "exactly one record per Record-Id"
4: duplicate-id Record-Id — got "r-dup352z", want "exactly one record per Record-Id"
8: duplicate-id Record-Id — got "r-dup352z", want "exactly one record per Record-Id"
commitlore: 4 violations (SPEC §6) — the message was not modified
$ echo $?
1

Two duplicates. Four reported. --json carries all four objects, byte-identical in pairs:

{"line":4,...,"rule":"duplicate-id",...},{"line":8,...},{"line":4,...},{"line":8,...}

Cause

Both checks find it independently. The shape check catches a Record-Id repeated inside one message; checkReferences catches the same id colliding across the message's own blocks. Neither knows the other ran, and the violations are concatenated without dedup.

The reference-check half only becomes visible once the unfetched gate is past — in a repository with no notes refspec, references short-circuits to not-checked and only the shape half prints. That is why this survived: the common local case shows two, and the case that shows four needs a configured mirror.

Why it matters

validate output is what a person reads at the moment their commit was just rejected, and the repair loop reads --json. A doubled list makes a two-problem message look like a four-problem one, and the count in the summary line is the number a reader uses to decide how much work they are in for. It also means an automated repair loop is handed two identical instructions for one edit.

Shape of the fix

Dedup violations on (line, rule, key, value) before formatting and counting — or decide which check owns duplicate-id and let the other stay silent on it. The second is cleaner but is a contract decision about what each check class means; the first is safe and local. Whichever is chosen, the summary count must match the number of distinct problems.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions