fix: call Harmony inside muse rebase's per-commit replay loop (muse#33)
Scope confirmed with the user as standalone `muse rebase` only — the `muse merge --history rebase` flag is a pre-existing squash-equivalent stub (see merge.py's own comment: "rebase full commit-by-commit replay is Phase 4 scope") and is left untouched; it is not a genuine per-commit replay loop, so it is out of scope here and remains a known, documented gap to be addressed separately.
Root cause: `replay_one()` (muse/core/rebase.py), the real per-commit replay loop backing `muse rebase`, performed a three-way merge per commit but never consulted Harmony at all — a conflict always paused the rebase even when Harmony held a saved resolution for the identical pattern. And once a rebase conflict WAS resolved manually via `muse resolve` + `muse rebase --continue`, the resolution was silently discarded: `--continue` wrote the new commit directly, bypassing the `record_resolutions` call that `muse commit` makes for an equivalent `muse merge` conflict (muse/cli/commands/commit.py:772-800). This also left `MERGE_STATE.json` on disk forever, since nothing ever cleared it.
Fix: - `replay_one()` now calls `harmony_auto_apply()` with THIS commit's own ours/theirs manifests (not any squash snapshot) when the merge conflicts, before giving up. Re-keys `harmony_resolved` to the file portion before merging into the manifest (same muse#93 key-mismatch guard already in merge.py). - Added `_record_rebase_resolution()` in the CLI layer, called from `muse rebase --continue` right after the paused commit is finalized — mirrors commit.py's existing merge/squash pattern exactly: builds ours/theirs manifests from MERGE_STATE's commit IDs, calls `record_resolutions()` with `manually_resolved` from MERGE_STATE, then unconditionally clears MERGE_STATE.json.
Three unrelated pre-existing bugs surfaced by writing a real end-to-end test against the actual CLI (rather than synthetic objects) and had to be fixed to make the scenario testable at all: - `_run_replay_loop()` referenced an undefined `elapsed` name when building conflict JSON output — always raised NameError, meaning `muse rebase --json <upstream>` crashed on any conflict instead of reporting one. - Both callers of `_run_replay_loop()` fell through to a bare `return` on conflict with no `SystemExit` — the JSON body correctly reported `"exit_code": 1` but the actual process exit code stayed 0. - The conflict branch in `_run_replay_loop()` re-inserted the commit ID at the front of `state["remaining"]`, duplicating it — it was read via `state["remaining"][0]` but never popped, so re-inserting it produced two copies. The next `--continue` would then replay the already-resolved commit a second time and report a spurious second conflict.
New test file tests/test_harmony_rebase_loop.py (HR_01-HR_04): a mid- replay conflict resolved manually is recorded by Harmony and clears MERGE_STATE.json; an identical conflict pattern on a fresh rebase is auto-resolved without pausing. Confirmed genuine RED by reverting the harmony wiring and re-running (both failures land exactly where the removed logic was supposed to act), then GREEN with the fix restored.
Regression: full harmony + rebase suites (755 tests), plus HA_02/HA_03/ HC_01-04 (tests/test_phase4_harmony_history.py, tests/test_phase7_merge_correctness.py) — all green, no regressions.
Semantic Changes
23 symbols
Files Changed
+1
~2
1254 in snapshot
0 comments
muse hub commit comment sha256:a7991bbc89b2af67cdd97580946aad7500cc737dd0c0d89088df831e198bdf84 --body "your comment"
No comments yet. Be the first to start the discussion.