test: comprehensive merge strategy x history x conflict-level TDD suite (muse#29)
New tests/test_merge_matrix.py — ground-truth suite for "Muse shines at merges" per the ticket's own framing: if it's green, the claim is proved; if red, we know exactly what's broken. Per the user's explicit ask, corrects the ticket's own stale strategy matrix and adds octopus:
- The ticket's matrix named a "state_merge" strategy that doesn't exist — the real three-way conflict-detecting strategy is "recursive" (`muse merge --help`: recursive, overlay, snapshot, replay, ours, theirs). Phase 2 exercises recursive x {merge,squash,rebase} and overlay x {merge,squash,rebase} — the two strategies whose behavior meaningfully differs under real conflicts. snapshot/replay/ours/theirs and the full scenario grid (untouched/convergent/divergent/add-add/ delete-modify) are already covered per-strategy by the pre-existing tests/test_phase3_strategy_matrix.py (SM_01-24) — not duplicated. - Octopus (N-way) merge (muse#105), which the ticket predates entirely, is added as its own section: a different code path that ignores --strategy/--history/--on-conflict completely and refuses outright on any path collision (no resolution, matching git). Engine-level depth already exists in tests/test_octopus_merge.py; this file adds the "no work lost" / "ref doesn't move on refusal" / "verify clean" checks the matrix ticket asks for.
make_conflict_repo() builds ONE repo with all three conflict levels the ticket's matrix asks for simultaneously: a genuine symbol-level conflict (calc.py::add, both sides diverge), file-level non-overlapping edits to the same file (shared.py — must auto-merge cleanly, neither side lost), and directory-level additions + a deletion in the same directory (dir_a/ — must auto-merge cleanly, every addition present, deletion applied).
Three real bugs found and fixed while building this TDD-first (per the ticket's own acceptance criterion — "implementation fixed to make tests pass"):
1. muse/cli/commands/merge.py — Case 3 (the auto-resolve path used by overlay/ours/theirs strategies) always wrote a two-parent commit, completely ignoring --history. `muse merge feat --strategy overlay --history squash` reported `"history": "squash"` in its own JSON output while silently writing a two-parent commit anyway. Added the same squash/rebase single-parent branch Case 4 (recursive) already had.
2. muse/core/merge_engine.py + muse/cli/commands/commit.py — completing a conflicted merge via `muse resolve` + `muse commit` always produced a two-parent commit, even when `--history squash`/`--history rebase` was requested on the original `muse merge` — the history mode was silently dropped the moment a conflict forced completion through `muse commit` instead of `muse merge`'s own clean-path commit-writing. Fixed by threading `history` through MERGE_STATE.json (new field, preserved across `muse resolve` calls same as `original_conflict_paths`) and gating commit.py's merge_parent2 logic on it.
3. muse/cli/commands/commit.py — the ticket's own named regression, confirmed reproducible and WORSE than described: if a resolved conflict's content happened to exactly match HEAD's current snapshot (e.g. resolving by keeping "ours"), `muse commit` took the "nothing to commit, working tree clean" early return — exit 0, looks completely benign — but never created the merge commit, never recorded the second parent, and never cleared MERGE_STATE.json. The repo was left PERMANENTLY STUCK: every subsequent `muse merge` re-surfaced the identical already-resolved conflict forever, silently discarding the entire merge rather than just "ours-side only" as the ticket described. Fixed by skipping that early return whenever a merge is actually being completed, regardless of --allow-empty — agents no longer need to know to pass --allow-empty in this case at all.
Also covers (Phase 3): --dry-run mutates nothing (ref, working tree, MERGE_STATE.json, reflog all untouched); muse resolve stages the merged body, not conflict-marker text; Harmony records a resolution after manual resolve (resolution_count == 1); muse verify --json reports all_ok after every scenario.
Confirmed genuine RED for all three fixes by reverting them together and re-running: 7 of 13 tests failed, each landing exactly on one of the three bugs (squash/rebase-after-conflict x2, overlay Case-3 history x2, the stuck-merge regression, and its two parametrized history variants). Restored fixes — all 13 green.
Known gaps, flagged rather than silently worked around: - tests/test_phase3_merge_state_ordering.py::TestCallOrder:: test_apply_manifest_called_before_write_merge_state fails on a clean dev checkout, unrelated to this change (confirmed by shelving these fixes and re-running — identical failure). Pre-existing, not caused or fixed here; left for a separate ticket. - `muse code test --json` reports coverage_fraction: 0.0 / zero selected tests for these changed addresses even after `code index rebuild` — likely requires a committed baseline the coverage mapper can diff against, which doesn't exist for uncommitted changes. Worked around by running the specific targeted test files directly (1352 tests, listed in the regression line below) rather than relying on automatic selection for this verification pass.
Regression (targeted, not full suite per --strategy matrix scope): test_merge_matrix.py, test_cmd_commit*.py, test_cmd_merge*.py, test_phase3_strategy_matrix.py, test_phase6_unified_merge_engine.py, test_core_merge_engine.py, test_merge_data_integrity.py, test_merge_conflict_markers.py, test_merge_supercharge.py, test_phase1_merge_engine.py, test_phase4_harmony_history.py, test_phase7_merge_correctness.py, test_harmony_merge_commit_integrity.py, test_octopus_merge.py, test_addressed_merge_plugin.py, test_comment_only_independence_merge.py, test_merge_base_supercharge.py, test_merge_tree_supercharge.py, test_op_merge.py, test_property_merge_invariants.py, and the full harmony_* suite — 1352 tests, all green, no regressions.
Semantic Changes
37 symbols
Files Changed
+1
~3
1255 in snapshot
0 comments
muse hub commit comment sha256:26088198afa1ef5bf63a4b37349344742d40762144235e27ef26f3e7d9856cae --body "your comment"
No comments yet. Be the first to start the discussion.