Release 0.7.7 — cross-platform fixes + dev-session stall hardening#24
Conversation
Spec-frontmatter status gates compared the raw `status:` value, so a hand-edited spec carrying a stray-cased `Done`/`In-Review` silently failed to advance a story. Add `verify.status_of()` (strip + lower) and route the six spec-frontmatter status reads through it (verify dev/review + bundle gates, engine post-dev sync, sweep bundle). The template and sprint-status tokens are lowercase, so behavior is unchanged for well-formed specs; `devcontract` keeps its own lowercasing (it parses skill prose). Also fix the manual-rollback notice: an empty baseline rendered an invalid `git reset --hard the run's baseline commit` — use a `<baseline_commit>` placeholder instead. Cross-cutting fix surfaced by PR #19; landed independently of the psmux work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The profile- and plugin-manifest "must be project-relative" guards used `Path(value).is_absolute()`, which is platform-dependent (on Windows a POSIX-absolute `/etc/passwd` reads as *not* absolute) and never caught relative `..` escapes — so `../../etc` and cross-OS-absolute paths slipped through. Add `platform_util.is_absolute_path` (absolute in either POSIX or Windows terms) and `has_parent_ref` (a `..` segment in either flavor) and pair them at every guard site in adapters/profile.py and plugins/manifest.py. Hardening surfaced by PR #19; landed independently of the psmux work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A worktree task's `spec_file` (state.json) and the resolve context's `resolution_path` were serialized via `str(Path)`, which emits backslashes on Windows — so a state/context file written on one OS read back with OS-specific separators. Persist both via `as_posix()` so the cross-OS state contract is a single forward-slash string everywhere (a no-op on POSIX). Cross-OS portability surfaced by PR #19; landed independently of the psmux work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The data layer caches a parse while a file's (mtime_ns, size) is unchanged. On a coarse-mtime filesystem (e.g. WSL2 drvfs) a same-size rewrite within one mtime tick is invisible to that signature, so the dashboard serves a stale parse. The engine rewrites state.json atomically (temp + os.replace), so every write lands on a fresh inode — fold st_ino into _stat_sig to catch the change regardless of mtime resolution. Surfaced by PR #19; landed independently. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 34 minutes Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable usage-based reviews in Billing to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). 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 see our Fair Usage Limits Policy for further information, and refer to the rate limits docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughRelease 0.7.7 updates status normalization, project-relative path checks, POSIX path serialization, TUI cache invalidation, dev-session stall nudges, and version metadata. Changes0.7.7 behavioral updates
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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: Release 0.7.7 is a fixes-only patch focused on cross-platform correctness and more reliable dev-session stall handling. Changes:
Technical Notes: The new inactivity-based grace window and wake-nudge budget are bounded by 🤖 Was this summary useful? React with 👍 or 👎 |
| inside the project?" validation.""" | ||
| text = str(value) | ||
| win = PureWindowsPath(text) | ||
| return PurePosixPath(text).is_absolute() or bool(win.drive or win.root) |
There was a problem hiding this comment.
src/automator/platform_util.py:57: is_absolute_path() currently treats Windows drive-relative paths like C:foo as “absolute” because win.drive is truthy even when win.root is empty; that doesn’t match the docstring’s “absolute” definition and could be surprising. If the intent is “reject any drive-qualified path for project-relative guards”, it may be worth clarifying that in the docstring to avoid misuse elsewhere.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/automator/resolve.py (1)
76-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a regression test for
build_context()path normalization.This contract change is cross-OS sensitive, but there is no paired test in the provided suite like the
StoryTask.spec_fileserialization check. A small assertion onresolution_pathincontext.jsonwould lock this fix in.🤖 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/resolve.py` around lines 76 - 78, Add a regression test covering build_context() path normalization so the context contract stays stable across OSes. Update the existing test suite around build_context()/context.json serialization to assert that resolution_path is emitted in POSIX form via resolution_path(...).as_posix(), similar to the StoryTask.spec_file serialization check. Keep the assertion focused on the serialized context value so this cross-platform behavior is locked in.
🤖 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/resolve.py`:
- Around line 76-78: Add a regression test covering build_context() path
normalization so the context contract stays stable across OSes. Update the
existing test suite around build_context()/context.json serialization to assert
that resolution_path is emitted in POSIX form via
resolution_path(...).as_posix(), similar to the StoryTask.spec_file
serialization check. Keep the assertion focused on the serialized context value
so this cross-platform behavior is locked in.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bf304d10-d455-4e0f-8bc8-706a7f125915
⛔ Files ignored due to path filters (11)
docs/images/dashboard.pngis excluded by!**/*.pngdocs/images/dashboard.svgis excluded by!**/*.svgdocs/images/demo.gifis excluded by!**/*.gifdocs/images/settings-scm.pngis excluded by!**/*.pngdocs/images/settings-scm.svgis excluded by!**/*.svgdocs/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 (19)
.claude-plugin/marketplace.jsonCHANGELOG.mdmodule.yamlpyproject.tomlsrc/automator/__init__.pysrc/automator/adapters/profile.pysrc/automator/data/skills/bmad-auto-setup/assets/module.yamlsrc/automator/engine.pysrc/automator/model.pysrc/automator/platform_util.pysrc/automator/plugins/manifest.pysrc/automator/resolve.pysrc/automator/sweep.pysrc/automator/tui/data.pysrc/automator/verify.pytests/test_engine_worktree.pytests/test_platform_util.pytests/test_tui_data.pytests/test_verify.py
- is_absolute_path: reframe the docstring as "rejects any rooted/drive-qualified path" — the helper intentionally rejects a Windows drive-relative `C:foo` (not strictly absolute) because such a path is never a valid in-project relative path. Behavior unchanged; pin the intent with a `C:foo` test row. (augmentcode[bot], PR #24) - resolve.build_context: lock the resolution_path as_posix() serialization with a forward-slash assertion, mirroring the spec_file posix test. (coderabbitai[bot]) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…for dev sessions Dev sessions were mis-stalled two ways: a long productive turn (building a diff, streaming a subagent) was killed because the idle-grace window measured time-since-last-Stop, and a turn ended to await a background process (a Unity PlayMode run) stalled because bmad-auto never re-invokes it. The grace window now measures genuine inactivity — pane-log growth re-arms it — and on real silence the orchestrator wakes the session with up to limits.dev_stall_nudges (new, default 2) nudges before stalling; a fresh Stop restores the budget, session_timeout_min stays the ceiling. New knob wired through policy + settings schema; docs and the [0.7.7] CHANGELOG entry updated. 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/policy.py`:
- Around line 54-60: The `dev_stall_nudges` help text and mirrored
settings/schema copy in `policy.py` currently promise that any response restores
the nudge budget, but `wait_for_completion()` only resets `stall_nudges_left` on
a fresh `Stop` while pane-log growth merely re-arms the grace window. Update the
docstring/help text near `dev_stall_nudges` and the matching text referenced by
`wait_for_completion()`/the settings schema so they describe the actual reset
behavior consistently.
🪄 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: 7dc15b3c-2c72-4b89-92b8-c51d50831cd1
📒 Files selected for processing (9)
CHANGELOG.mdREADME.mddocs/FEATURES.mddocs/game-engine-plugin-guide.mddocs/tui-guide.mdsrc/automator/adapters/generic.pysrc/automator/data/settings/core.tomlsrc/automator/policy.pytests/test_generic_tmux.py
✅ Files skipped from review due to trivial changes (3)
- docs/game-engine-plugin-guide.md
- README.md
- docs/FEATURES.md
|
augment review |
| if event.event == "SessionEnd": | ||
| return self._final(handle, spec, "crashed", session_id, transcript_path) | ||
|
|
||
| def _log_activity_key(self, task_id: str) -> tuple[int, int] | None: |
There was a problem hiding this comment.
src/automator/adapters/generic.py:304: The module docstring says the pane log is “NEVER parsed for control flow”, but _log_activity_key() now uses it to re-arm the stall grace window, which does affect control flow; consider updating that docstring to avoid misleading future readers.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Valid — fixed in f0e639b. The module docstring now scopes "never parsed for control flow" to the log contents and notes that its growth (mtime/size, not the bytes) is read as a liveness signal to re-arm the dev-stall grace window.
Address two valid automated-reviewer findings on PR #24 (both doc-only, from the activity-aware stall detection in 5d06206): - dev_stall_nudges help/schema said "any response restores the budget", but wait_for_completion() restores the nudge budget only on a fresh Stop; pane output merely re-arms the grace window. Fixed the three mirrored copies (policy.py field comment, POLICY_TEMPLATE, core.toml settings schema). - generic.py module docstring claimed the pane log is "NEVER parsed for control flow"; _log_activity_key() now reads its growth (mtime/size, not the bytes) as a liveness signal for stall detection. Scoped the claim to the log contents and noted the metadata liveness signal. The other two findings were already fixed in 72067a1 (platform_util C:foo docstring; resolve.py POSIX resolution_path regression test). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Release 0.7.7
A fixes-only patch release. Most are cross-cutting correctness/hardening fixes
surfaced while reviewing the psmux Windows backend (#19) but independent of it
— landed on their own so the latent-bug fixes ship now, while the psmux work
rebases onto these seams separately. It also folds in a dev-session stall-detection
hardening fix surfaced by a real run, where long PlayMode/multi-subagent stories
were being falsely deferred.
Fixed
verify.status_of) — a hand-edited specwith a stray-cased
Done/In-Reviewsilently failed the dev/review gate and thestory never advanced. Also fixes an invalid
git reset --hard the run's baseline commitrollback hint (now a<baseline_commit>placeholder)...traversal and OS-foreign absolute paths — profile /plugin-manifest "must be project-relative" checks now reject
../escapes andWindows/POSIX cross-absolute paths on every platform (
is_absolute_path/has_parent_ref).as_posix()state serialization — worktreespec_fileand resolveresolution_pathpersist with forward slashes for a single cross-OS contract(no-op on POSIX).
st_inofolded into_stat_sigso anatomic same-size
state.jsonrewrite within one coarse mtime tick (WSL2 drvfs)can't be served stale.
sessions were mis-stalled two ways: a long productive turn (building a diff,
streaming a subagent) was killed because the idle-grace window measured
time-since-last-Stop, and a turn ended to await a background process (a Unity
PlayMode run) stalled because bmad-auto never re-invoked it. The grace window now
measures genuine inactivity — pane-log growth re-arms it — and on real silence the
orchestrator wakes the session with up to
limits.dev_stall_nudges(new, default2) nudges before stalling; a fresh Stop restores the budget,
session_timeout_minstays the ceiling.
Verification
green;
trunk check(no filter) clean.Release commit stamps 0.7.7 across all version files and curates the CHANGELOG; on
merge to
main, the Release workflow auto-creates thev0.7.7tag and GitHubrelease from the
[0.7.7]CHANGELOG section.🤖 Generated with Claude Code
Summary by CodeRabbit
..traversal and OS-foreign/absolute paths in profile and manifest inputs.limits.dev_stall_nudges(default 2) to control wake nudges before marking a dev session stalled.