Skip to content

feat(sweep): extend intent-gap patch-restore re-drive to deferred-work bundles#93

Merged
pbean merged 1 commit into
mainfrom
feat/sweep-intent-gap-patch-restore
Jul 9, 2026
Merged

feat(sweep): extend intent-gap patch-restore re-drive to deferred-work bundles#93
pbean merged 1 commit into
mainfrom
feat/sweep-intent-gap-patch-restore

Conversation

@pbean

@pbean pbean commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Closes #75.

Extends the intent-gap patch-restore re-drive (built for sprint/story runs in #86) to SweepEngine deferred-work bundles. An escalated bundle can now be resolved with bmad-loop resolve <run> --restore-patch <path>, which re-arms the bundle spec to in-review and re-applies the saved patch on the re-drive, so the corrected session resumes review on the restored diff instead of reimplementing from scratch.

Why this was small

Investigation showed almost the whole mechanism was already inherited or pre-wired for sweep — the apply seam (_restore_patch inside the inherited _dev_phase), latch-clear on commit (_commit), the T4 proof-of-work exclusion (verify_dev_bundle), runs.rearm_escalation (run_type-agnostic), and the CLI resolveresume routing (_resume_paused_run builds SweepEngine for run_type=="sweep"). The gap was that SweepEngine overrides _loop wholesale and hand-rolls recovery in _run_bundle, so it never reached the base _finish_inflight re-drive wiring.

The two production changes (src/bmad_loop/sweep.py)

  • _generic_bundle_prompt — a restore re-drive now points at the in-review bundle spec (task.spec_file) instead of the fresh intent.md, so upstream step-01's spec-pointer intent check early-exits before its version-control sanity check would HALT blocked on the restored dirty tree. Mirrors the sprint F1 fix (engine.py:2133-2141).
  • _run_bundle recovery — latches resolved_redrive and passes cause="resolved" for a re-armed task, mirroring _finish_inflight (engine.py:1151-1157). This is a correctness fix: without the latch, a non-critical exhaustion mid-re-drive silently DEFERs the human-resolved escalation (escalation.py:110PAUSE if resolved_redrive else DEFER) — filing it as fresh deferred work and rolling back the correction. It also repairs the pre-existing from-scratch sweep re-drive, which had the same latent bug.

Tests

  • Engine (tests/test_sweep.py) — restore-prompt unit; restore re-drive → done + both latches cleared + prompt-points-at-spec + attempt-restored; pause-not-defer exhaustion for both the restore and from-scratch paths. New escalating-dev helper in conftest.py.
  • E2E scenario 8 (tests/test_stories_e2e.py) — drives the real sweep/resolve --restore-patch/resume binaries through tmux (a triage branch added to the fake CLI; the bundle-dev session reuses the existing sprint branch). This is the only coverage of the sweep-specific CLI resume path.
  • Every new test verified to fail without the fix. Full suite 1695 passed / 1 skipped (Windows-only); trunk check clean.

Residual (out of scope)

If triage.json fails to reload on resume, a re-armed bundle can be orphaned by a fresh triage plan whose bundle names differ — pre-existing sweep fragility, not introduced here. Worth a follow-up issue.

Summary by CodeRabbit

  • New Features

    • Added clearer recovery guidance for interrupted review flows, including restoring from a saved patch and continuing review instead of restarting work.
    • Extended the same recovery flow to deferred-work sweep runs, including resumable re-drive behavior after escalation.
  • Bug Fixes

    • Improved handling of restored runs so recovery now resumes in the correct state and re-applies the saved patch consistently.
    • Refined pause vs. defer behavior for exhausted restore/re-drive scenarios.

…k bundles (#75)

An escalated sweep bundle can now be resolved with
`bmad-loop resolve <run> --restore-patch <path>`, re-arming the bundle spec to
`in-review` and re-applying the saved patch on the re-drive — the same recovery
sprint/story runs got in #86. Bundles lack sprint-status entries and SweepEngine
overrides `_loop` wholesale, so it never reached the base `_finish_inflight`
re-drive wiring; two small deltas close the gap (the apply seam, latch-clear on
commit, proof-of-work exclusion, rearm, and CLI resolve->resume were already
inherited/pre-wired):

- `_generic_bundle_prompt`: point a restore re-drive at the in-review bundle spec
  (task.spec_file) instead of the fresh intent.md, so step-01's spec-pointer
  intent check early-exits before its version-control sanity check HALTs blocked
  on the restored dirty tree (mirrors the sprint F1 fix, engine.py:2133-2141).
- `_run_bundle` recovery: latch `resolved_redrive` and pass `cause="resolved"`
  for a re-armed task, mirroring `_finish_inflight` (engine.py:1151-1157). This
  is a correctness fix — without the latch a non-critical exhaustion mid-re-drive
  silently DEFERs the human-resolved escalation (escalation.py:110). It also
  repairs the pre-existing from-scratch sweep re-drive, which had the same bug.

Tests: 4 engine cases in test_sweep.py (restore prompt, restore re-drive ->
done + latch cleared + prompt-points-at-spec, pause-not-defer exhaustion for the
restore and from-scratch paths) + an escalating-dev conftest helper; E2E
scenario 8 drives the real sweep/resolve/resume binaries through tmux (the only
coverage of the sweep-specific CLI resume path). All new tests fail without the
fix. Full suite 1695 passed / 1 skipped; trunk clean.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab1467b4-f42f-4bb6-931c-7bcc91cf3056

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Extends the intent-gap patch-restore re-drive recovery mechanism from story runs to SweepEngine deferred-work bundles: bundle escalations can now be resolved with --restore-patch, re-arming the bundle spec to in-review and resuming review on the reapplied patch rather than re-implementing. Includes documentation, engine logic, and test updates.

Changes

Sweep patch-restore re-drive

Layer / File(s) Summary
Documentation and changelog updates
CHANGELOG.md, docs/FEATURES.md
Documents restore rejection constraints and extends the intent-gap patch-restore recovery description to deferred-work sweep bundles.
SweepEngine rollback/pause and prompt logic
src/bmad_loop/sweep.py
Updates _run_bundle's rollback/pause handling to latch resolved_redrive and pass a "resolved"/"stopped" cause, and extends _generic_bundle_prompt repair-mode text with patch-restore re-drive ordering constraints.
Test helper for bundle dev escalation
tests/conftest.py
Adds bundle_dev_escalates helper simulating a bundle intent-gap escalation with a blocked spec and CRITICAL result.
Unit tests for restore/re-drive and exhaustion
tests/test_sweep.py
Adds helpers and tests covering restore-aware prompt selection, restore re-drive reaching done with latch clearing, and pause-not-defer exhaustion for both restore and from-scratch re-drives.
End-to-end sweep patch-restore scenario
tests/test_stories_e2e.py
Adds SWEEP scaffolding, fake CLI dispatch branch, and an E2E test validating intent-gap patch save, restore-based resolve, and resume completing the deferred-work entry.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Poem

A patch once torn, then saved with care,
Now bundles too can mend the tear.
Rearm, reapply, resume review—
No fresh rewrite, just carry through.
Hop hop hooray, the sweep's now sound! 🐇🩹

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the sweep deferred-work patch-restore re-drive change.
Linked Issues check ✅ Passed The changes implement restore-patch re-arm, patch reapplication, latch clearing, and sweep resolve/resume behavior requested in #75.
Out of Scope Changes check ✅ Passed The docs, tests, and engine updates stay focused on the sweep patch-restore recovery work and do not add unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sweep-intent-gap-patch-restore

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pbean

pbean commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Filed the out-of-scope residual (triage.json reload failure orphaning a re-armed bundle) as #94.

@pbean

pbean commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review
augment review

@augmentcode

augmentcode Bot commented Jul 8, 2026

Copy link
Copy Markdown

Looks like you're out of credits for this review. Head to your account settings to top up and keep reviews running. https://app.augmentcode.com/account/subscription

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

@pbean Got it — kicking off a review of the latest changes now. Thanks for filing #94 for the triage.json reload residual as a follow-up.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extend intent-gap patch-restore re-drive to the sweep workflow

1 participant