Skip to content

Three PR collisions merged cleanly today: nothing asks what the merged tree contains #16155

Open

Description

@mrveiss

Three collisions in one session, none detectable

Every collision check we have is textual — git merge-tree, the mergeable flag, path-filtered workflows. All three of today's collisions merged with zero conflicts:

PRs mechanism what merged cleanly
referential #16144 / #16149 one PR deletes a directory the other cites three times and argues its design by analogy to no file in common at all
arithmetic #16151 / #16141 one declares reach floor=6000, growth=400; the other adds 29 files to the sweep shared file, disjoint hunks, 6406 > 6400
resurrection #16130 / #16149 a branch that merged base between a file being added and deleted re-adds it new file mode 100644, deletion silently reverted

The third is the sharpest: a deletion is where the textual check is weakest, because re-adding a file conflicts with nothing. #16130 was green, reviewed, both its own bugs fixed — and merging it would have undone a completed site separation, with the only signal being two new file lines in a diff nobody re-reads once it is green.

The question none of them asks

A textual merge check answers can these combine. It never answers should the result hold.

All three would have been caught by asking what does the merged tree contain — cheaply, without running the suite:

referential   does any path this PR cites still exist in the merged tree?
arithmetic    do the declared counts still match the merged population?
resurrection  does the merged tree contain a path base deleted?

The mechanisms differ enough that one detector probably will not cover all three, but they share that question, and today nothing asks it.

The resurrection case is mechanical and worth doing first

It is fully decidable from refs, needs no checkout, and has an exact criterion:

files added by the branch relative to merge-base   ∩   files deleted on base since merge-base   ≠  ∅

Where merge-base and head agree, git sees one side deleted, one unchanged and the deletion wins — safe. Only a branch that added the path fights the deletion.

This distinction is load-bearing and easy to get wrong. The obvious proxy — does the branch contain the deleted path — flagged 6 of 7 open PRs today, including the one unblocking every session's pushes, where the true criterion flags exactly one. A proxy validated on the case it was derived from can disagree everywhere else, and this one fails toward alarm.

Acceptance criteria

  • A check reports when a PR's merged result would re-add a path deleted on base since the branch's merge-base, using the add-relative-to-merge-base criterion — not "the branch contains the path"
  • The check names the paths and states which side introduced them, so the reader can tell a resurrection from a legitimate re-add
  • A test proves the false-positive case: a branch that merely carries a file unchanged since its merge-base is not flagged, with a fixture built from the fix(guards): bind the hooksPath guard to what it examined (#16150) #16151 shape
  • A test proves the true-positive case, built from the fix(kb): the summary evaluator must see more than the opening 200 characters (#16110) #16130 shape — merge-base 0, head 2, base 0
  • The check distinguishes no resurrection found from could not compare (shallow clone, missing merge-base) and never reports the second as the first
  • Whether the referential and arithmetic cases fold into the same check, or need their own, is decided and written down rather than left open

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions