-
Notifications
You must be signed in to change notification settings - Fork 59
chore(release): 0.6.0 — rollback never wipes non-automator files #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,4 +6,4 @@ | |
| spec files, and the per-run directory under .automator/runs/. | ||
| """ | ||
|
|
||
| __version__ = "0.5.1" | ||
| __version__ = "0.6.0" | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -159,6 +159,17 @@ class ScmPolicy: | |||||||||||||||||||||||||||||||||||
| merge_strategy: str = "merge" # ff | merge | squash | ||||||||||||||||||||||||||||||||||||
| delete_branch: bool = True # delete the unit branch after a successful merge | ||||||||||||||||||||||||||||||||||||
| keep_failed: bool = True # keep a failed unit's worktree+branch for inspection | ||||||||||||||||||||||||||||||||||||
| # rollback_on_failure governs in-place (isolation = "none") recovery after a | ||||||||||||||||||||||||||||||||||||
| # failed attempt / rejected review. Default OFF: the orchestrator never | ||||||||||||||||||||||||||||||||||||
| # touches the working tree — it pauses the run with manual recovery | ||||||||||||||||||||||||||||||||||||
| # instructions, so a half-finished attempt is left for you to inspect. ON: | ||||||||||||||||||||||||||||||||||||
| # the orchestrator auto-reverts the attempt's tracked changes and removes the | ||||||||||||||||||||||||||||||||||||
| # untracked files THIS run created (never a blanket `git clean`; pre-existing | ||||||||||||||||||||||||||||||||||||
| # untracked files and the whole _bmad-output/ are preserved) — convenient but | ||||||||||||||||||||||||||||||||||||
| # it discards the attempt's uncommitted work, so a warning is journalled when | ||||||||||||||||||||||||||||||||||||
| # it fires. Worktree isolation sidesteps this entirely (failed work stays in | ||||||||||||||||||||||||||||||||||||
| # its worktree), so this knob only matters for isolation = "none". | ||||||||||||||||||||||||||||||||||||
| rollback_on_failure: bool = False | ||||||||||||||||||||||||||||||||||||
| # failed_diff_max_mb caps the per-file size (MB) of untracked files captured | ||||||||||||||||||||||||||||||||||||
| # into a kept-failed unit's forensic changes.patch, so a stray build dir or | ||||||||||||||||||||||||||||||||||||
| # huge log can't blow it up; oversized files are skipped with a labelled | ||||||||||||||||||||||||||||||||||||
|
|
@@ -414,6 +425,7 @@ def loads(text: str, plugin_schemas: dict[str, Any] | None = None) -> Policy: | |||||||||||||||||||||||||||||||||||
| merge_strategy=str(scm_d.get("merge_strategy", ScmPolicy.merge_strategy)), | ||||||||||||||||||||||||||||||||||||
| delete_branch=bool(scm_d.get("delete_branch", ScmPolicy.delete_branch)), | ||||||||||||||||||||||||||||||||||||
| keep_failed=bool(scm_d.get("keep_failed", ScmPolicy.keep_failed)), | ||||||||||||||||||||||||||||||||||||
| rollback_on_failure=bool(scm_d.get("rollback_on_failure", ScmPolicy.rollback_on_failure)), | ||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reject non-boolean
Proposed fix+ raw_rollback_on_failure = scm_d.get(
+ "rollback_on_failure", ScmPolicy.rollback_on_failure
+ )
+ if not isinstance(raw_rollback_on_failure, bool):
+ raise PolicyError(
+ "scm.rollback_on_failure must be a boolean: "
+ f"got {raw_rollback_on_failure!r}"
+ )
scm = ScmPolicy(
isolation=str(scm_d.get("isolation", ScmPolicy.isolation)),
branch_per=str(scm_d.get("branch_per", ScmPolicy.branch_per)),
target_branch=str(scm_d.get("target_branch", ScmPolicy.target_branch)),
merge_strategy=str(scm_d.get("merge_strategy", ScmPolicy.merge_strategy)),
delete_branch=bool(scm_d.get("delete_branch", ScmPolicy.delete_branch)),
keep_failed=bool(scm_d.get("keep_failed", ScmPolicy.keep_failed)),
- rollback_on_failure=bool(scm_d.get("rollback_on_failure", ScmPolicy.rollback_on_failure)),
+ rollback_on_failure=raw_rollback_on_failure,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| failed_diff_max_mb=int(scm_d.get("failed_diff_max_mb", ScmPolicy.failed_diff_max_mb)), | ||||||||||||||||||||||||||||||||||||
| failed_diff_unlimited=bool( | ||||||||||||||||||||||||||||||||||||
| scm_d.get("failed_diff_unlimited", ScmPolicy.failed_diff_unlimited) | ||||||||||||||||||||||||||||||||||||
|
|
@@ -600,6 +612,7 @@ def _fold_deprecated_engine( | |||||||||||||||||||||||||||||||||||
| merge_strategy = "merge" # ff | merge | squash (worktree mode merges the unit branch into target locally) | ||||||||||||||||||||||||||||||||||||
| delete_branch = true # delete the unit branch after a successful merge | ||||||||||||||||||||||||||||||||||||
| keep_failed = true # keep a failed unit's worktree+branch for inspection | ||||||||||||||||||||||||||||||||||||
| rollback_on_failure = false # in-place (isolation="none") recovery after a failed attempt. false = never touch the tree; pause with manual recovery steps. true = auto-revert the attempt's tracked changes + remove only the untracked files this run created (WARNING: discards the attempt's uncommitted work; never a blanket git clean). Prefer isolation="worktree" to avoid touching your main checkout. | ||||||||||||||||||||||||||||||||||||
| failed_diff_max_mb = 5 # per-file size cap (MB) for untracked files in a kept-failed unit's changes.patch; oversized files are skipped with a marker | ||||||||||||||||||||||||||||||||||||
| failed_diff_unlimited = false # true = capture the failed-unit diff with no size cap (may produce very large patches; warns when active) | ||||||||||||||||||||||||||||||||||||
| # commit_message_template: when set, the commit message dev sessions use for a | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the manual-rollback pause resumable before continuing.
With rollback disabled,
_pause_for_manual_recovery()saves the current task state. On retry/resume,_finish_inflight()calls_rollback_or_pause()again and pauses unconditionally, even if the operator already reset manually. In_defer(), the task is already terminal before the pause, so a resume can skip recovery entirely and continue on the dirty tree. Add a recovered/acknowledged state check before re-pausing, and avoid marking the task terminal until recovery has been verified or completed.Also applies to: 742-743, 1339-1356
🤖 Prompt for AI Agents