Skip to content

Fix spurious reserved-reformat and enum-alias-removal diffs#115

Merged
ghostdogpr merged 3 commits into
mainfrom
fix/protodiff-reserved-alias
Jul 9, 2026
Merged

Fix spurious reserved-reformat and enum-alias-removal diffs#115
ghostdogpr merged 3 commits into
mainfrom
fix/protodiff-reserved-alias

Conversation

@ghostdogpr

Copy link
Copy Markdown
Owner

Two false-positive classifications in the diff engine, from a fresh bug-hunt pass.

1. Reformatting a reserved range is reported as a removal

diffReserved compared reserved entries structurally (oldRes.toSet -- newRes.toSet). So reserved 2 to 4; and reserved 2, 3, 4; — identical coverage — had an empty intersection and produced a spurious ReservedRemoved(Range(2,4)) plus three ReservedAdded, surfacing a false "reservation removed" warning.

Now it compares the covered number set (as canonical merged intervals — no expansion, so reserved N to max stays cheap) plus the reserved names, and emits nothing when both are unchanged. Genuine changes still fall back to the structural diff, so their reporting is unchanged.

2. Removing an enum alias is flagged wire-breaking

For an allow_alias enum, removing a duplicate value (e.g. C = 1 while B = 1 stays) produced EnumValueRemoved(..., numberReserved = false), which maps to Error in Wire mode — even though number 1 is still assigned to B, so the wire is unaffected. The numberReserved flag was computed only from the new reserved list, ignoring numbers still in use.

The removal is now treated as wire-safe when the number remains present among the new enum values (matching buf's number-level rule). The flag drives severity to Info in Wire mode; its description now reads "(number retained)" to cover both the reserved and still-in-use cases.

Tests

Two tests (red before the fix, green after), plus the full ProtoDiffSpec and the golden IntegrationSpec (24) staying green:

  • reserved 2 to 4;reserved 2, 3, 4; now yields no changes;
  • removing an allow_alias duplicate whose number is still used yields a single EnumValueRemoved that is Info in Wire mode.

- diffReserved compared reserved entries structurally, so rewriting a range
  as the equivalent list of numbers (reserved 2 to 4 vs reserved 2, 3, 4)
  reported a false ReservedRemoved. Compare the covered number set (as merged
  intervals, without expanding, so 'to max' stays cheap) plus reserved names,
  and emit nothing when both are unchanged.

- Removing an enum alias (a duplicate name whose number is still assigned to
  another value) was flagged EnumValueRemoved with numberReserved=false, i.e.
  wire-breaking, even though the number is still live. Treat the removal as
  wire-safe when the number remains present among the new values.
A reserved-name change in the same edit as a numeric range reformat
(reserved 2 to 4 -> reserved 2, 3, 4; reserved "foo") set sameNames to
false, so the whole reserved set fell back to a structural diff and still
reported the range reformat as a spurious ReservedRemoved. Diff the covered
numbers and the reserved names separately so a change to one never resurfaces
reformat noise from the other.
The fallback still diffed raw Reserved entries when numeric coverage changed,
so extending a range while reformatting (reserved 2 to 4 -> reserved 2, 3, 4, 5)
reported ReservedRemoved(2 to 4) even though 2-4 stayed reserved. Compute the
genuinely removed/added coverage as interval-set subtraction and report those
intervals, so only numbers that actually left or entered the reserved set are
reported.
@ghostdogpr ghostdogpr merged commit d733387 into main Jul 9, 2026
3 checks passed
@ghostdogpr ghostdogpr deleted the fix/protodiff-reserved-alias branch July 9, 2026 05:29
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