Repository navigation
Description
Overview
Three defects, one root cause: the dev-workflow helper scripts resolve paths under $HOME/Code/PyAutoLabs, which does not exist in a cloud, web or CI session. All three were hit in sequence during the PyAutoBrain#224 session on 2026-08-10, and each silently did the wrong thing rather than complaining.
Filed high because #2 is a safety defect, not an inconvenience: a guard that returns "all clear" when it cannot read its input is worse than no guard, because the workflow documents it and skills act on its answer.
Plan
prompt_sync_push— push the current branch, or refuse when the checkout is not onmain. It currently hardcodesgit push origin main.worktree_check_conflict— fail closed when the registry cannot be resolved, naming the path it tried. It currently returns 0, meaning "no conflict".test_skill_install.py— skip with a reason on the web-github installer path instead of failing. It currently fails in any cloud session and passes in real CI.
1. prompt_sync_push hardcodes git push origin main
PyAutoMind scripts/prompt_sync.sh — the helper every Mind-writing skill is told to call. create_issue step 6 and start_dev step 7 both instruct the agent to call it. A branch-scoped session that follows the documented steps verbatim pushes Mind straight to main, bypassing review. In the #224 session this was caught only because the helper was inspected before use; the documented path would have violated the session's branch requirement.
2. worktree_check_conflict fails open — the important one
bin/worktree.sh, in worktree_list_claimed:
if [[ ! -f "$active" ]]; then
return 0
fiNo registry → returns 0 → worktree_check_conflict reports no conflict. The guard cannot distinguish "nothing claims this repo" from "I could not read the registry", and answers the former.
Reproduced: worktree_check_conflict reconcile-upstream-repo-mode PyAutoBrain PyAutoMind returned 0 and was recorded as a clean check. Re-run with PYAUTO_MAIN=/workspace it worked and returned the same verdict — but the first answer was worth nothing, and had a conflict existed the session would have started conflicting work on a green light. This is the guard that serialises two agents wanting the same repo.
3. test_skill_install.py fails locally, passes in CI
Two tests assert on installer output that only appears on the local-dev path (assert "SKIP intake (Codex skill" in result.stdout). bin/install.sh already knows the difference — it prints Environment: local-dev vs Environment: web-github / ci-only — and skips the skill-symlink work on the latter.
Consequence, observed: Heart is unreachable from a cloud session, so ship_library falls back to pytest -x and treats any failure as RED. These two failures made that gate spuriously RED on #224 and cost a human acknowledgement to override. CI on that PR then went green on both legs, confirming the diff was never implicated.
The unifying point
bin/install.sh already detects and prints its execution environment, and WORKFLOW.md already names them (local-dev, web-github, ci-only). The helpers should consult that same notion and either adapt or fail closed. None of the three should silently do the wrong thing.
Test Plan
-
prompt_sync_pushon a non-mainbranch pushes that branch, or refuses; never pushes tomainfrom a branch-scoped checkout. Covered by a test. -
worktree_check_conflictreturns non-zero when it cannot resolveactive.md, naming the path it tried. Covered by a test pointing$PYAUTO_MAINat an empty dir. The "registry present, no claim" case still returns 0. -
test_skill_install.pypasses on both paths — skipping with a reason on web-github, still asserting fully on local-dev. -
pytest tests/green in a cloud session, so theship_libraryfallback gate stops producing false REDs.
Affected Repositories
- PyAutoBrain (primary) —
bin/worktree.sh,tests/test_skill_install.py - PyAutoMind —
scripts/prompt_sync.sh
Suggested branch: feature/dev-workflow-helpers-laptop-paths
Branched from main, independent of #224 (disjoint files), so the two can land in either order.
Original Prompt
Filed at PyAutoMind draft/bug/pyautobrain/dev_workflow_helpers_assume_laptop_paths.md.
Activity
Jammy2211 commentedon Aug 10, 2026
Correction to defect 1, after measuring it
This issue describes defect 1 as "pushes Mind straight to
main, bypassing review". Measuring the old helper against real bare remotes shows that is only half of it, and not the half that fires most often.git push origin mainpushes the localmainref — never the commit just made on a feature branch. So the old behaviour splits by the state of localmain:mainvs remotemainmain, unreviewed, and still leaves the branch work local.The first row is the common one and the quieter danger: in an ephemeral cloud container, "committed, reported synced, never pushed" is silent loss. The second is the review bypass this issue originally described.
Same root cause, and the fix already on PyAutoMind#178 (push
HEAD) addresses both. What changed is the description and the coverage — the two halves now have their own tests, since they are distinct failures:test_committed_work_actually_reaches_the_remotetest_a_branch_push_never_advances_main5 of the 7 new tests now fail against
origin/main's script.Also found in the same audit (already fixed)
Auditing PyAutoBrain#224 against
mainturned up an unrelated regression in that PR: widening the band column to fit the newneeds-reviewlabel had changed the printed output of the default path too, adding six columns of indent to runs that can never emit that band. The suspects were unaffected — verified identical againstmain, 29 of 135, no result keys removed — but the text a human reads had shifted for work unrelated to the feature. Fixed inc7c8b17: the width now follows the widest band actually present, so a default run prints exactly whatmainprinted.Confirmed NOT broken by defect 2's fix
worktree_claim_is_stalein the same file is documented fail-open by design ("anything unknown … returns 1 = not stale and the caller proceeds"). Makingworktree_check_conflictfail closed does not contradict it: that function resolvesactive.mditself and never callsworktree_list_claimed, so its behaviour is untouched. Both functions fail toward safety — for staleness the safe answer is "don't remove", for conflicts it is "don't start".Generated by Claude Code