refactor(engine): extract rollback/preserve cluster into RecoveryFlow (#244, PR 2/2)#266
Conversation
…#244) Findings F-3 of the brownfield refactor assessment, PR 2/2 (PR 1 was the worktree cluster, #265). Engine's rollback/preserve cluster is an independent recovery state machine; carve it into a `RecoveryFlow` collaborator built from narrow deps (repo paths, policy, run state, journal, run dir) plus a getter for the engine's swappable active workspace and a few engine callbacks (emit a plugin hook, save state, escalate a task, escalation-pause). The collaborator never receives the whole Engine. Same pattern as WorktreeFlow: Engine keeps same-name delegating private methods (`_rollback_or_pause`, `_safe_reset`, `_restore_patch`, `_prune_preserve_refs`, `_preserve_attempt_*`, `_pause_for_manual_recovery`, `_protected_relpaths`) so test_engine*.py stays byte-untouched and the SweepEngine/StoriesEngine subclasses (which override nothing in this cluster, and call `_rollback_or_pause` /`_safe_reset` through the inherited delegators) are unchanged. `emit` is late-bound so a monkeypatched `Engine._emit` still wins; `RunPaused` is raised via the injected `escalation_pause`/`escalate` callbacks so recovery_flow need not import engine (avoids a runtime<->engine cycle). Behavior-preserving only. New unit tests exercise the collaborator in isolation in tests/test_recovery_flow.py. engine.py shrinks by ~333 lines. The hook-bus cluster is left in place (explicitly out of scope). Closes #244.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughEngine’s rollback, preservation, manual-recovery, and patch-restoration logic is extracted into a new ChangesRecovery flow extraction
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@CodeRabbit review |
✅ Action performedReview finished.
|
Findings F-3 of the brownfield CLI/TUI refactor assessment — PR 2 of 2, completing #244 (PR 1, the worktree cluster, landed in #265). Requires PR 1 merged; verified on
main(951383a).What
Engine's rollback/preserve cluster is an independent recovery state machine. Carve it into a
RecoveryFlowcollaborator (src/bmad_loop/recovery_flow.py) built from narrow deps — repo paths, policy, run state, journal, run dir — plus a getter for the engine's worktree-swappable active workspace and a handful of engine callbacks. The collaborator never receives the wholeEngine.Methods moved (same names, minus the leading
_, on the collaborator):_rollback_or_pause·_safe_reset·_restore_patch·_prune_preserve_refs_preserve_attempt_commits·_preserve_attempt_worktree_pause_for_manual_recovery·_protected_relpathsengine.pyshrinks by ~333 lines (38 insertions, 371 deletions).Same pattern & hard constraints as PR 1 (#265)
test_engine*.pyis byte-untouched and green (339 engine/worktree/plugin/stories tests pass).SweepEngine/StoriesEngineoverride nothing in this cluster and reach_rollback_or_pause/_safe_resetthrough the inherited delegators.emitis injected late-bound (a lambda, not the bound method) so a test's monkeypatchedEngine._emitstill wins onpre_rollback/post_rollback;workspace_getreads the engine's swappable workspace live.RunPausedis raised via the injectedescalation_pause/escalatecallbacks, sorecovery_flownever importsengine.Tests
New
tests/test_recovery_flow.py— 24 tests exercising the collaborator in isolation (narrow deps + stub callbacks, noEngine): protected-path derivation, the auto-recover / pause / worktree / resolved-re-drive / git-fault branches ofrollback_or_pause, recovery-ref preservation (commit + dirty-worktree), the three manual-recovery notice shapes, prune retention + per-family error handling, andrestore_patchapply/escalate.Verification
tests/test_engine.py tests/test_engine_worktree.py tests/test_engine_plugin.py tests/test_stories_engine.py→ 339 passedtests/test_recovery_flow.py→ 24 passedtest_module_skills_sync[...bmad-loop-setup]failures are pre-existing local install-tree drift (a gitignored.agents/.claudeassets/module.yamlout of sync with canonicalsrc); untouched by this PR and not reproduced on a clean CI checkout.uvx pyright@1.1.411→ 0 errors · fulltrunk check→ cleanCloses #244.
Summary by CodeRabbit