chore(release): 0.7.12#35
Conversation
…alations
Two bugs surfaced driving Epic 9 in a real project (document-ordered, not
numeric, sprint board; epic 9 physically last in the file):
1. A story from a human-resolved CRITICAL `blocked` escalation whose re-drive
still couldn't converge was silently downgraded to a plateau-defer (and its
implemented code rolled back). `decide_dev`/`decide_review_session` now
re-escalate (PAUSE) instead of DEFER when `task.resolved_redrive` is latched,
so the blocker resurfaces for the human and `_escalate` preserves the tree.
2. `resume` rebuilt the Engine without the run's `--epic`/`--story`/
`--max-stories`, so a resumed `--epic N` run widened to every epic; combined
with strict file-order selection, deferring/finishing an out-of-file-order
epic's story bounced the pick to an earlier-in-file epic and fired a spurious
"epic N complete" boundary. Fixes:
- persist epic_filter/story_filter/max_stories in RunState and restore them
on resume (also closes the max_stories-dropped-on-resume gap);
- `_pick_next` now exhausts the current epic before advancing (next_actionable
gains an `epic` filter), so an epic-boundary only fires when the current
epic is genuinely out of actionable stories. Document-order epic execution
is preserved (fallback is still file order).
Adds coverage for story index 0, document-order boundaries, resume-scope
restoration, and defer-vs-escalate on resolved_redrive (new test_escalation.py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CHANGELOG entry + version stamp (scripts/sync_version.py) for the resume-scope and resolved-escalation defer fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ack reset A story that escalates before it commits leaves its implementation in the working tree. On resume of a resolved re-drive (or any rollback_on_failure reset), `_rollback_or_pause` runs `git reset --hard baseline` plus its untracked cleanup, discarding that diff — only committed work above baseline was parked (attempt-preserve/). A dev session that stalled mid-implementation therefore restarted from zero every run. Park the uncommitted diff too: `verify.snapshot_worktree` captures tracked edits AND run-created untracked files (which `git stash create` misses) via a throwaway temp index honoring .gitignore, and `_preserve_attempt_worktree` refs it under refs/attempt-preserve-dirty/<slug>-<baseline8> before every auto-rollback reset. No-op on a clean tree; best-effort so it never blocks the reset. Complements _preserve_attempt_commits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dashboard tokens column and run-header summary now show the cost-proportional weighted total (cache reads discounted per the run's cache_read_weight, matching the engine budget check), with the previous unweighted total preserved in a new 'raw' 7th column. The weight is read from the persisted policy snapshot with a 0.1 fallback, so no engine/policy/persistence changes are needed and the TUI stays a pure observer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rtional weighted… Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 44 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThis release bumps version metadata to 0.7.12 and updates run scope persistence, epic-scoped selection, rollback preservation, escalation handling, and weighted/raw token display. ChangesRelease 0.7.12
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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 |
🤖 Augment PR SummarySummary: Releases Changes:
Technical Notes: The TUI reads 🤖 Was this summary useful? React with 👍 or 👎 |
| # Same git-safe, length-bounded slug as _preserve_attempt_commits so an | ||
| # exotic/overlong --run-id can't blow the ref-name limit and drop the ref. | ||
| slug = "".join(c if (c.isalnum() or c in "_-") else "-" for c in self.state.run_id)[:64] | ||
| ref = f"refs/attempt-preserve-dirty/{slug}-{baseline[:8]}" |
There was a problem hiding this comment.
_preserve_attempt_worktree names the recovery ref with {baseline[:8]}; if multiple rollbacks happen for the same run/story baseline, this update-ref will overwrite the previous snapshot and make earlier preserved work unrecoverable (journal entries keep only the ref name).
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Fixed in 632b086. The recovery ref now carries a per-retry discriminator — refs/attempt-preserve-dirty/{slug}-{baseline[:8]}-{task.attempt}. task.attempt only ever increments across a task (never resets), so repeated dirty rollbacks against the same fixed baseline_commit no longer reuse the ref name and orphan an earlier attempt's snapshot. Locked by a new regression test, test_rollback_preserves_distinct_refs_across_repeated_dirty_rollbacks, which drives two dirty→rollback cycles on the same baseline and asserts two distinct, git show-able refs.
|
|
||
| Returns ``ref_name`` on success, or ``None`` when the tree is clean relative | ||
| to HEAD (nothing to preserve — the intended non-destructive uncommitted-revert | ||
| case). Raises :class:`GitError` on any git failure so a caller can never |
There was a problem hiding this comment.
snapshot_worktree’s docstring says raising GitError means callers “can never … reset past unpreserved work”, but Engine._preserve_attempt_worktree catches GitError and proceeds with a destructive reset; this contract mismatch could mislead future callers about the safety semantics.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Fixed in 632b086. The docstring is reworded: the GitError raise surfaces the capture failure so the caller can decide, rather than implying it universally stops a reset past unpreserved work. The commit-preservation caller refuses to reset; the best-effort worktree caller (_preserve_attempt_worktree) journals the failure and proceeds — the recovery ref is a safety net, not a gate.
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
tests/test_escalation.py (1)
34-36: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winConsider asserting the reason on the budget-left RETRY path.
This test only checks
action == Action.RETRY, so it does not catch that_exhaust_reasonis currently rewriting the reason on the retry branch (see the escalation.py comment). Addingassert "re-escalating" not in decision.reasonwould lock in the intended behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_escalation.py` around lines 34 - 36, The budget-left retry test for decide_dev only asserts Action.RETRY, so it can miss the incorrect reason rewrite in the retry path. Update the test to also check the Decision.reason from decide_dev, specifically that it does not contain the re-escalating text on the resolved_redrive/budget-remains path, so the intended behavior in _exhaust_reason is preserved.tests/test_tui_app.py (1)
190-207: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a RunHeader assertion for parity with the sibling test.
This fallback test only checks the tasks-table cells; the sibling test (
test_task_table_shows_weighted_and_raw_tokens) also asserts theRunHeadertext. Without a header check here, a regression inwidgets.py's default-weight accumulation path could go undetected.✅ Proposed addition
assert tasks_table.get_cell("1-1-login", "tokens") == "260" assert tasks_table.get_cell("1-1-login", "raw") == "1,160" + header = str(screen.query_one("`#runheader`", RunHeader).content) + assert "260 tokens (1,160 raw)" in header🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_tui_app.py` around lines 190 - 207, Add a RunHeader assertion to match the sibling token-weight test and cover the same UI path. In test_token_weight_falls_back_to_default, after selecting the run in DashboardScreen, also query the RunHeader and assert its text reflects the weighted total and raw total for the fallback-weight case. This keeps parity with test_task_table_shows_weighted_and_raw_tokens and verifies the default-weight accumulation behavior exercised through widgets.py.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/automator/engine.py`:
- Around line 793-797: The recovery ref created by _preserve_attempt_worktree in
engine.py can collide across retries because it is keyed only on
task.baseline_commit, so later attempts overwrite earlier preserved snapshots.
Update the ref naming in _preserve_attempt_worktree (and any call path that
invokes verify.snapshot_worktree) to include a per-retry discriminator such as
task.attempt, matching the retry loop in _dev_phase so each preservation is
unique and previous worktree snapshots are retained.
In `@src/automator/escalation.py`:
- Around line 71-82: The retry path in decide_dev is building an exhausted-style
reason even when Action.RETRY is returned, which makes the repair feedback and
journal message misleading; update the logic so _exhaust_reason(task, ...) is
only used when the exhausted action is actually selected, and otherwise pass
through the original reason. Apply the same fix in decide_review_session as
well, using the same pattern around the budget_left check and the existing
_exhaust_reason helper so both functions keep retry reasons distinct from
exhausted reasons.
In `@src/automator/verify.py`:
- Around line 277-278: The snapshotting logic in verify.py is too broad because
the current _git_env("add", "-A") call in the restore/snapshot flow records
every untracked file, including pre-existing user files. Update the caller to
pass the baseline untracked snapshot into this path, then change the Git staging
logic to use git add -u for tracked modifications and add only newly created
untracked files relative to that baseline. Keep the fix localized to the restore
helper around _git_env and the code that builds the attempt-preserve-dirty
snapshot.
- Around line 290-292: The snapshot commit in _git(repo, "commit-tree", ...) can
fail when no local/global Git identity is configured, so set synthetic author
and committer identity via _git_env before creating the worktree snapshot.
Update the snapshot path in verify.py around the commit-tree call to pass
GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME, and GIT_COMMITTER_EMAIL
so the recovery flow completes reliably.
In `@tests/test_engine.py`:
- Around line 1118-1147: Add a regression test for repeated rollback on the same
baseline in test_rollback_preserves_uncommitted_attempt_worktree by driving two
consecutive dirty-then-rollback cycles through engine._rollback_or_pause on the
same StoryTask.task.baseline_commit. Verify _preserve_attempt_worktree (and its
attempt-preserve-dirty ref creation) does not overwrite the first preserved
snapshot, and assert both recovered snapshots remain accessible in the journal
after the second rollback.
---
Nitpick comments:
In `@tests/test_escalation.py`:
- Around line 34-36: The budget-left retry test for decide_dev only asserts
Action.RETRY, so it can miss the incorrect reason rewrite in the retry path.
Update the test to also check the Decision.reason from decide_dev, specifically
that it does not contain the re-escalating text on the
resolved_redrive/budget-remains path, so the intended behavior in
_exhaust_reason is preserved.
In `@tests/test_tui_app.py`:
- Around line 190-207: Add a RunHeader assertion to match the sibling
token-weight test and cover the same UI path. In
test_token_weight_falls_back_to_default, after selecting the run in
DashboardScreen, also query the RunHeader and assert its text reflects the
weighted total and raw total for the fallback-weight case. This keeps parity
with test_task_table_shows_weighted_and_raw_tokens and verifies the
default-weight accumulation behavior exercised through widgets.py.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8035db79-d7ee-4b9c-9b5c-d92205b9d2c1
⛔ Files ignored due to path filters (13)
docs/images/dashboard.pngis excluded by!**/*.pngdocs/images/dashboard.svgis excluded by!**/*.svgdocs/images/decision-answer.pngis excluded by!**/*.pngdocs/images/decision-answer.svgis excluded by!**/*.svgdocs/images/deferred-modal.pngis excluded by!**/*.pngdocs/images/deferred-modal.svgis excluded by!**/*.svgdocs/images/demo.gifis excluded by!**/*.gifdocs/images/settings.svgis excluded by!**/*.svgdocs/images/start-run-modal.pngis excluded by!**/*.pngdocs/images/start-run-modal.svgis excluded by!**/*.svgdocs/images/sweep-decision.pngis excluded by!**/*.pngdocs/images/sweep-decision.svgis excluded by!**/*.svguv.lockis excluded by!**/*.lock
📒 Files selected for processing (21)
.claude-plugin/marketplace.jsonCHANGELOG.mdmodule.yamlpyproject.tomlsrc/automator/__init__.pysrc/automator/cli.pysrc/automator/data/skills/bmad-auto-setup/assets/module.yamlsrc/automator/engine.pysrc/automator/escalation.pysrc/automator/model.pysrc/automator/sprintstatus.pysrc/automator/tui/screens/dashboard.pysrc/automator/tui/widgets.pysrc/automator/verify.pytests/test_cli.pytests/test_engine.pytests/test_escalation.pytests/test_model.pytests/test_sprintstatus.pytests/test_tui_app.pytests/test_verify.py
Address CodeRabbit/Augment findings on the auto-rollback safety net added in aedbcf9 — the snapshot could silently lose the very work it exists to protect. - verify.snapshot_worktree: scope the capture to what safe_rollback would destroy — `add -u` for tracked edits/deletions plus only run-created untracked files (untracked_files minus baseline_untracked), never a pre-existing user file; and commit-tree under a synthetic bmad-auto identity so the snapshot succeeds with no git user.name/email configured (else the best-effort caller caught the GitError and reset past the work). Signature gains keyword-only baseline_untracked and the docstring is reworded to match. - engine._preserve_attempt_worktree: key the recovery ref on task.attempt so repeated dirty rollbacks against the same fixed baseline no longer orphan an earlier attempt's snapshot. - escalation: only wrap the reason with the exhausted "re-escalating" wording on the budget-exhausted branch; a plain RETRY keeps its plain reason. - tests: no-identity + untracked-scope snapshot cases, repeated-rollback distinct refs regression, and a budget-left reason assertion. CHANGELOG hardened note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/automator/verify.py`:
- Around line 292-296: Treat missing baseline_untracked as unknown in
verify.py’s snapshot staging logic: in the code path that computes new from
untracked_files(repo), do not coerce baseline_untracked to an empty list when it
is None. Update the handling around the untracked staging block so that when
baseline_untracked is unavailable, the code skips staging untracked files
entirely instead of calling _git_env("add", ...) for them; keep the existing
behavior only when a real baseline snapshot is present. Use the existing
untracked_files, safe_rollback, and _git_env flow to locate and adjust this
decision point.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 23946aa2-7103-497d-b5be-9b5aaf1289d1
📒 Files selected for processing (7)
CHANGELOG.mdsrc/automator/engine.pysrc/automator/escalation.pysrc/automator/verify.pytests/test_engine.pytests/test_escalation.pytests/test_verify.py
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (4)
- src/automator/escalation.py
- tests/test_escalation.py
- src/automator/engine.py
- tests/test_engine.py
Address CodeRabbit round-2 finding on the run-scoped snapshot from 632b086. `snapshot_worktree` coerced `baseline_untracked or []`, so a None baseline (a pre-upgrade/resumed run with no snapshot) treated every current untracked file as run-created and parked it — a scope mismatch with safe_rollback (which deletes no untracked files when baseline_untracked is None) and a privacy leak. Guard on None explicitly, mirroring attempt_dirty/safe_rollback: park no untracked file when the baseline is unknown (tracked edits are still parked via add -u). New test test_snapshot_worktree_unknown_baseline_skips_untracked locks it: a None-baseline snapshot captures the tracked edit but not the untracked file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
augment review |
| def _apply_tasks(self, state: RunState) -> None: | ||
| table = self.query_one("#tasks", DataTable) | ||
| weight = state.cache_read_weight() | ||
| for key, task in state.tasks.items(): |
There was a problem hiding this comment.
src/automator/tui/screens/dashboard.py:546: The tokens cell shows "-" when weighted is 0; if cache_read_weight is 0 and a task only has cache-read tokens, the weighted total can be 0 while raw is nonzero, so this looks like missing data rather than “0 weighted tokens.”
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Good catch — fixed in 7b06edf. The tokens cell now gates on whether the task has any tokens at all, not on the weighted value, mirroring the adjacent raw cell:
tokens = f"{weighted:,}" if task.tokens.total else "-"So with cache_read_weight = 0 a cache-read-only task (weighted 0, raw nonzero) renders tokens = "0" instead of "-"; "-" is now reserved for a task with genuinely no tokens. Locked by test_zero_weighted_tokens_shows_zero_not_dash (cache_read_weight: 0.0, a task with only cache_read_tokens=1000, asserts tokens == "0" and raw == "1,000").
| ) | ||
| except verify.GitError: | ||
| self.journal.append("attempt-worktree-preserve-failed", story_key=task.story_key) | ||
| return |
There was a problem hiding this comment.
src/automator/engine.py:892: Catching verify.GitError here journals only a generic attempt-worktree-preserve-failed entry, dropping the underlying git error output; if the subsequent reset destroys work, this makes diagnosis of the preservation failure much harder.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Fixed in 7b06edf. _preserve_attempt_worktree now binds the exception and journals its message:
except verify.GitError as exc:
self.journal.append(
"attempt-worktree-preserve-failed", story_key=task.story_key, error=str(exc)
)
returnThe GitError messages already carry the underlying git stderr (e.g. git commit-tree (snapshot) failed in <repo>: <output>), so this keeps the diagnosis breadcrumb when a preservation failure is followed by a destructive reset. Covered by test_rollback_worktree_preserve_failure_journals_git_error, which forces a GitError and asserts the journal entry's error field carries the detail while the reset still proceeds.
…tokens Address two low-severity Augment findings on PR #35. - engine._preserve_attempt_worktree: bind the caught verify.GitError and journal its message (`error=str(exc)`) instead of a bare entry, so a preservation failure before a destructive reset leaves a diagnosable breadcrumb (the commit-tree/update-ref stderr) rather than just "it failed". - tui dashboard _apply_tasks: gate the `tokens` cell on `task.tokens.total`, not on the weighted value. With cache_read_weight=0 a cache-read-only task has weighted==0 but nonzero raw; it now shows "0" instead of "-" (which reads as missing data). "-" stays reserved for a task with no tokens at all. Tests: preserve-failure journals the git error; a zero-weighted cache-read-only task renders tokens "0" not "-". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A poll worker delivers its snapshot on the UI thread via call_from_thread; that callback can land after the DashboardScreen has been unmounted (app shutdown) or switched away, when the widgets it queries are gone — raising `NoMatches: No nodes match '#runs' on DashboardScreen()`. Guard `_apply` on `self.is_running`, which flips False on teardown but stays True while the screen is merely backgrounded under a pushed screen, so a stale apply is dropped while a live background one still refreshes. Fixes an intermittent crash (and the corresponding flaky test_tui_settings teardown). Regression test: applying a snapshot to a no-longer-running screen is a no-op instead of a NoMatches crash. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@CodeRabbit review |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/automator/tui/screens/dashboard.py (1)
553-568: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor duplication in the total-gate check.
The
if task.tokens.total else "-"gate is repeated for bothtokensandraw. Could extract into a single boolean, but this is purely cosmetic.♻️ Optional simplification
for key, task in state.tasks.items(): weighted = task.tokens.weighted_total(weight) + has_tokens = bool(task.tokens.total) # Gate on total (any tokens?), not on `weighted`: with cache_read_weight=0 # a cache-read-only task has weighted==0 but nonzero raw — show "0", not "-" # (which reads as missing data). "-" means the task has no tokens at all. - tokens = f"{weighted:,}" if task.tokens.total else "-" - raw = f"{task.tokens.total:,}" if task.tokens.total else "-" + tokens = f"{weighted:,}" if has_tokens else "-" + raw = f"{task.tokens.total:,}" if has_tokens else "-"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/automator/tui/screens/dashboard.py` around lines 553 - 568, The total-token check is duplicated when building the dashboard row in the task loop, so simplify the `tokens`/`raw` formatting in `dashboard.py` by computing a single boolean or helper from `task.tokens.total` and reusing it for both fields. Keep the existing behavior in the `state.tasks.items()` iteration and preserve the current `weighted` vs raw display logic in the same block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/automator/tui/screens/dashboard.py`:
- Around line 553-568: The total-token check is duplicated when building the
dashboard row in the task loop, so simplify the `tokens`/`raw` formatting in
`dashboard.py` by computing a single boolean or helper from `task.tokens.total`
and reusing it for both fields. Keep the existing behavior in the
`state.tasks.items()` iteration and preserve the current `weighted` vs raw
display logic in the same block.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 369ea9e1-7f05-4089-9b3e-be02c567ee05
📒 Files selected for processing (5)
CHANGELOG.mdsrc/automator/engine.pysrc/automator/tui/screens/dashboard.pytests/test_engine.pytests/test_tui_app.py
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
- src/automator/engine.py
- tests/test_engine.py
Address a trivial CodeRabbit nitpick: the `if task.tokens.total` gate was repeated for the `tokens` and `raw` cells in _apply_tasks. Extract it into a single `has_tokens` boolean and reuse. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Applied the token-cell dedupe nitpick in c7a9f11 — extracted |
Release 0.7.12. On merge to
main,.github/workflows/release.ymlauto-creates thev0.7.12tag and GitHub release from the CHANGELOG.Added
tokenscolumn and the run-header summary now show the cost-proportional weighted total (cache-read tokens discounted by the run'scache_read_weight— the same weighting the per-story budget enforces), so the headline number tracks spend rather than context re-reads. The previous unweighted total moves to a newrawcolumn. The weight is read from the run's persisted policy snapshot with a0.1fallback, so no engine/policy changes were needed and the TUI stays a pure observer.Fixed
attempt-preserve/<run_id>-<head8>and the uncommitted working-tree diff (tracked edits and run-created untracked files) underrefs/attempt-preserve-dirty/— both recoverable by name and surviving gc. A rollback that cannot create the ref pauses for manual recovery rather than destroying work.--epic Nrun stays scoped to its epic and no longer declares the epic "done" while stories remain — the selector/cap are persisted and restored on resume.Full notes in
CHANGELOG.md.Verification
release.py check: version fields all agree on0.7.12;[0.7.12]CHANGELOG section present.tests/test_module_skills_sync.pygreen.rawcolumn.trunk check: no issues.🤖 Generated with Claude Code
Summary by CodeRabbit