Comprehensive merge strategy TDD: all --strategy and --history permutations with deliberate conflicts
Goal
Build a load-bearing TDD suite that exercises every permutation of `muse merge` strategy and history options with deliberate, engineered conflicts at all three levels Muse tracks: file, directory, and symbol. This suite is the ground truth for "Muse shines at merges" — if it is green, the claim is proved. If it is red, we know exactly what is broken.
Background
Muse tracks conflicts at the symbol level via `.muse/MERGE_STATE.json` and `muse conflicts --json`. Unlike git's line-level conflict markers, Muse can resolve conflicts at the function/class boundary. This suite must exercise all three levels end-to-end and assert the correct resolution mechanics for each.
Agents have been losing work during merge operations because of a flaw in how `muse commit --allow-empty` stores the merge snapshot (it uses the ours-side snapshot, silently discarding theirs-side changes). This suite will catch that regression and others like it.
Strategy matrix
| `--strategy` | `--history` | Description |
|---|---|---|
| `overlay` | `merge` | Feature branch wins on conflicts, full DAG preserved |
| `overlay` | `squash` | Feature branch wins, single squashed commit |
| `overlay` | `rebase` | Feature branch wins, linear history |
| `state_merge` | `merge` | Three-way merge with conflict detection, full DAG |
| `state_merge` | `squash` | Three-way merge, single squashed commit |
| `state_merge` | `rebase` | Three-way merge, linear history |
Conflict level matrix
| Level | How to engineer | What to assert |
|---|---|---|
| File-level | Both branches edit the same file at non-overlapping regions | File contents merged correctly; neither side's changes lost |
| Directory-level | Both branches add/delete/rename files in the same directory | All additions present, deletions applied, renames resolved |
| Symbol-level | Both branches modify the same function/class body | `muse conflicts --json` lists the symbol; `muse resolve` stages correct merged body |
Test phases
Phase 1 — Fixtures and helpers
TDD-first: write a `conftest.py` or `test_merge_matrix.py` with:
- `make_conflict_repo()` — builds a repo with ours/theirs branches pre-loaded with deliberate conflicts at all three levels
- `assert_no_work_lost()` — verifies that after merge, every change from both sides is present
- `assert_symbol_conflict_listed()` — checks `muse conflicts --json` lists expected symbol paths
- `assert_merge_history()` — verifies parent commit structure matches `--history` option
All helpers must fail before any implementation changes.
Phase 2 — Strategy × History matrix tests
One test per cell in the 6-cell matrix above. Each test:
- Creates a fresh repo with engineered conflicts
- Runs `muse merge <branch> --strategy <s> --history <h>`
- For `state_merge` with conflicts: resolves manually via `muse resolve`
- Commits and asserts:
- All expected files present
- All expected symbols present with correct bodies
- Commit DAG structure matches history option
- `muse verify --json` reports clean
Phase 3 — Regression tests for known failure modes
- `--allow-empty` snapshot regression: after a merge commit with no tracked changes, the working tree must reflect both sides' content (not just ours)
- Symbol-level conflict: after `muse resolve`, the staged file must contain the manually-merged body, not a conflict-marker blob
- Dry-run merge: `muse merge --dry-run` must not mutate any state (working tree, MERGE_STATE, reflog)
Phase 4 — MP GUI smoke tests (optional, separate issue if scope grows)
- `muse hub proposal read <id>` returns `blockedBy` list when predicted conflicts exist
- `muse diff --text <from>..<to>` returns the expected diff text for the proposal view
Acceptance criteria
- All 6 strategy × history combinations have a passing test
- All 3 conflict levels (file, directory, symbol) are exercised
- `--allow-empty` snapshot regression test is red before fix, green after
- `muse verify --json` passes after every merge scenario
- `muse code test --json` runs only these tests on changed files (no full-suite run needed)
- Tests are TDD — written first, implementation fixed to make them pass
Out of scope
- MP GUI conflict surfacing (separate issue)
- `muse diff --text` in proposal view (separate issue)
Notes
- Use `muse merge --dry-run --json` to predict conflicts before asserting
- `muse conflicts --json` returns `[]` when no conflicts are pending
- `muse resolve path/to/file.py --json` stages the resolution; do NOT use `muse code add`
- Harmony autoupdate is on by default; verify it learns from each resolved conflict