fix(claude-ops): harden lanes launcher refresh — abort on failure, validate targets first#707
Conversation
…lidate targets first Two deferred low-severity follow-ups from PR #616's review of the lanes skill. Item 1: start/restart ran `refresh_repo_and_plugins || rc=1` and launched lanes regardless, seeding background sessions from stale repo/plugin state on a failed `git pull --ff-only` or `claude plugin marketplace update`. The refresh is a documented launch prerequisite, so an unexpected failure now aborts the launch (exit non-zero) with an actionable message. --no-pull/--no-update stay the intentional-skip path: a skipped step leaves the refresh status 0. Item 2: `restart does-not-exist` mutated repo/plugin state before for_each_lane rejected the unknown target. Hoisted the TARGET_LANES existence check into a `validate_target_lanes` function called from main ahead of the refresh step, so a misspelled target fails fast (exit 3) with no mutation — matching stop's DX. Tests: +14 cases (71 -> 85) covering the refresh-failure abort (pull + update, start + restart, bypass still launches) and the pre-refresh target rejection. Closes #639 Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 41s —— View job PR Review — fix(claude-ops): harden lanes launcher refresh
The two fixes are correct and address the right problems. The code is clean, shellcheck-clean per the verification output, and the test structure is solid. A few observations below. CorrectnessItem 1 — refresh abort: The change from Item 2 — validate-before-refresh: Moving the target check from inside Minor observations1. Error message emitted from ((rc)) && err "refresh failed — aborting launch (pass --no-pull/--no-update to skip refresh intentionally)"
return "$rc"The phrase "aborting launch" is stated inside 2. Marketplace-update failure test is missing the message assertion (line 366–372) The assert_contains "start refresh-failure message is actionable" "$out" "refresh failed — aborting launch"
assert_not_contains "no lane launched after a failed pull" "$log" "--bg -n"But the marketplace-update failure test only checks: assert_eq "start aborts when marketplace update fails (exit 1)" 1 "$rc"
assert_not_contains "no lane launched after a failed update" "$log" "--bg -n"The message assertion is missing for the update path. Fix this → 3. Bypass test only covers The CHANGELOG noteThe refresh-abort entry is under Overall this is a clean, well-reasoned hardening pass. The two items are independent, test coverage is comprehensive for the regression cases that matter, and the code is consistent with the existing script conventions. Approve pending the minor observations above (none are blockers). |
Reword the two refresh-guard comment blocks to describe the behaviour under test instead of citing an issue number. Fixes the comment-hygiene CI check (tracker-ref:issue-reference); the substantive what/why is kept.
|
Claude finished @kyle-sexton's task in 1m 53s —— View job PR Review — fix(claude-ops): harden lanes launcher refresh
Latest commit (302c3c3)The synchronize push is purely cosmetic — the two block comments in the test file had their Outstanding from prior reviewThree observations from the prior review remain unaddressed. None are blockers, but two (items 2 and 3) are easy one-line additions that would round out the coverage before merge. 1. Missing message assertion for the marketplace-update failure case (line 369–370) The assert_contains "start refresh-failure message is actionable" "$out" "refresh failed — aborting launch"The marketplace-update failure block does not. The message fires on the same code path ( 2. Bypass test covers The intentional-bypass invariant ( 3. Error message "aborting launch" emitted inside the function that doesn't itself abort (line 391)
CHANGELOG note (editorial)The refresh-abort entry is under OverallThe two commits are correct. The substantive logic is sound, shellcheck-clean, and well-reasoned. Items 2 and 3 above are small, low-effort additions that would give the test suite full coverage of both the failure and bypass paths for both |
- reword refresh-failure message to not claim the function itself aborts (callers abort; the function only returns non-zero) - assert the marketplace-update failure path emits the actionable message - cover the intentional-bypass invariant for restart (_restart_one path), not just start - move the refresh-abort CHANGELOG entry from Changed to Fixed (corrects a silently-swallowed failure) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 7s —— View job PR Review — fix(claude-ops): harden lanes launcher refresh (latest commit: 15d8de6)
All three outstanding observations from the prior review are addressed in this commit. Nothing new introduced. What changed in 15d8de61. Error message wording ( Prior observation: Resolution: 2. Missing message assertion for marketplace-update failure (line 370) Prior observation: the Resolution: 3. Bypass test covered Prior observation: Resolution: matching case added — 4. CHANGELOG Prior observation: the refresh-abort entry belonged under Resolution: both entries consolidated under a single Net test count88 → 91 assertions (+3). All three additions are well-scoped and match the failure/bypass semantics of the code paths they exercise. VerdictClean resolution of all prior observations. The diff is minimal, targeted, and introduces no new issues. The test suite now has symmetric coverage: both |
|
Post-green review pass complete (rule 8). Bot review classification:
All 4 addressed on-branch, no inline threads to resolve, CI fully green (18/18), 91 test assertions passing. Flipping to ready for review; handing off to the babysit lane for merge. |
|
Claude finished @kyle-sexton's task in 1m 40s —— View job PR Review — fix(claude-ops): harden lanes launcher refresh (ready-for-review pass)
This is a final review pass after the PR was flipped to ready-for-review. All four observations from the previous review cycles are confirmed addressed. Nothing new introduced. Prior observations — all resolved1. Error message wording (line 391) The misleading 2. Missing marketplace-update message assertion (line 370)
3. Bypass test covered Matching bypass case added for 4. CHANGELOG section (CHANGELOG.md) Both entries consolidated under Correctness check on the new stubsThe One minor gap (not previously flagged, not blocking)The Net state91 test assertions, shellcheck-clean, version bumped to 0.15.1, CHANGELOG correct. The two hardening items are logically correct and symmetric. The diff is minimal, targeted, and introduces no new issues. Ready to merge. |
Summary
Two deferred low-severity follow-ups from PR #616's review of the
claude-opslanesskill (lane-launcher.sh). Both hardened the pre-launch refresh step so lanes never start from state the user did not sign off on.Fix
Item 1 — abort the launch on a failed refresh.
action_start/action_restartranrefresh_repo_and_plugins || rc=1and proceeded tofor_each_laneregardless, so a failedgit pull --ff-only(divergent/dirty checkout) orclaude plugin marketplace updatestill seeded background lanes from stale repo/plugin state, surfacing non-zero only at the very end. The refresh is a documentedstart/restartprerequisite, so an unexpected failure now hard-stops the launch (refresh_repo_and_plugins || return 1) with an actionable message emitted fromrefresh_repo_and_plugins.--no-pull/--no-updateremain the intentional-skip path: a skipped step leaves the refresh status0, so the abort keys on real failure only, never on an intentional bypass.Item 2 — validate targets before refresh mutations.
restart does-not-existran the full refresh (git pull+ marketplace update) beforefor_each_lanediscovered the target was unknown and exited 3 — inconsistent withstop does-not-exist, which validates before anything happens. TheTARGET_LANESexistence check moved out offor_each_laneinto a newvalidate_target_lanesfunction called frommainahead of action dispatch, so a misspelled target fails fast (exit 3) with no repo/plugin mutation. Single source of truth:for_each_lane's stale "unknown target names are an error" comment was updated to point at the new owner.Verification
lane-launcher.test.shgrew from 71 to 85 cases (+14) covering both fixes: the refresh-failure abort (pull failure and marketplace-update failure, for bothstartandrestart, plus the--no-pull/--no-updatebypass still launching) and the pre-refresh target rejection (nopull/updatein the command log). New stub knobsSTUB_GIT_PULL_RCandSTUB_CLAUDE_UPDATE_RCdrive the failure paths.Closes #639
Related