# Merge-Conflict Resolution Rubric

audience: AI coding agents first. Imperative, BLUF.

The agent resolves every merge conflict by JUDGMENT, autonomously. NEVER escalate a git conflict to
the user — they cannot help; relying on them fails the project. `finish-branch.sh` hands you the
conflict (`sync-base` leaves it in the worktree); you resolve it with these rules, commit, then let
`land-merge` re-gate. Same rules for both land modes (merge-to-main and open-a-PR).

## Governing principle — deletion needs proof; keeping both is safe

**Discarding a side is the ONLY silently-irreversible move.** Keep-both, when wrong, fails LOUD — a
duplicate definition trips the compiler/linter/tests; disjoint changes simply coexist. So:

> **Default to integrating BOTH sides. Delete a side ONLY after proving it carries zero unique behavior.**

This governs the whole ladder below — every rung is an application of it, not an exception to it.

## Per-conflict ladder — stop at the first rung that holds

First, for EACH conflicted hunk, read BOTH sides AND why each changed (`git log -p <base> -- <file>`
and `git log -p <branch> -- <file>`). Then:

1. **Both sides changed DIFFERENT things in the same place** → **integrate both.** Common case.
   Dropping either is a real regression.
2. **Both did the SAME job two different ways** (accidental double-work) → **keep the better, drop the
   other.** "Better" is defined below.
3. **One side is the other PLUS more** (strict superset / refinement) → **take the superset.**
4. **One side re-breaks something the other fixed** → **keep the fix. ALWAYS.** Never reintroduce a
   known-fixed bug.
5. **Genuinely unsure which is better** → **keep both.** Never guess-delete.

## "Better" — the tie-break for rung 2

Pick the version that, in order: **passes the tests** / **is more complete** / **handles more edge
cases** / **is the one that already fixed a known bug**. Only if still tied, keep the branch side
(active work) — and only after confirming the dropped side has NO unique behavior.

- DO NOT use "**newer**" as the tie-break. Newer ≠ better — a feature branch can be OLDER than a
  hotfix that landed on the base. Recency proves nothing about correctness.

## Tests are necessary, NOT sufficient

After resolving ALL hunks, run the project test command. But:

- A **semantic** conflict produces **NO markers** — two clean edits that disagree. The hunk ladder
  never fires; tests are the only catch. So `land-merge` ALWAYS runs the tests, even on a "clean" sync.
- Green tests over code **nothing exercises** prove nothing. If no test covers the conflicted/affected
  lines, **say "resolved but unverified at `<file>:<line>`"** — do NOT claim the resolution is clean.
  Green cannot launder an unverified resolution.

## Hard NEVERs

- **NEVER blanket `git merge -X theirs` / `git checkout --theirs -- <file>` a whole file** to make a
  conflict go away. That is the silent-loss move this rubric exists to kill. Whole-file pick is allowed
  ONLY after proving that file's other side has zero unique value.
- **NEVER resolve on the base branch (main).** Resolve on the BRANCH (in its worktree); the base only
  ever fast-forwards to your verified result. main never passes through a broken state.
- **NEVER hand the conflict to the user.** The agent owns this call end to end.

## Mode note

- **merge-to-main:** `sync-base` merges base INTO the branch → resolve here → `land-merge` ff's main.
- **open-a-PR:** do NOT pre-merge base into the branch by default (pollutes the PR diff). Resolve
  against base ONLY when the branch is actually unmergeable and you are deliberately making it
  mergeable — then these same rules apply.
