Merge the /dev line to master (#30) - #77
Conversation
Design spec for adding a human-gated planning capability to the manager session (brainstorm → spec → critical review → decompose to stories → existing fleet implements), plus renaming /fix→/dev and /fix-loop→/dev-loop with aliases. Reuses existing skills and the decomposed/subtask convention; adds two backlog-aware behaviors to the manager loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Critical-design-review round 1 approved the planning-pipeline spec as-is: 0 literal-wrongness findings, 0 forced decisions. Empirically confirmed the two load-bearing hand-off facts (subtask is claimable; decomposed parents are excluded from claiming). Recorded the CDR approval in the spec status and carried the three CIR-deferred items forward as notes B8/B9 (+ existing B5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eview-1 to autocoder-planning-pipeline-implementation-plan
Task 1 of docs/plans/2026-07-13-autocoder-planning-pipeline-implementation-plan.md. Edits the in-file self-references in the renamed command/workflow files and adds thin forwarding stubs at the old names. The .claude/fix-loop.local.md state file keeps its name (plan assumption #7). Also adds the /dev mapping-table entry and autonomous gate policy for peters-toolkit:bugfix, so bug work routes through that skill without its in-chat STOP gates stalling the unattended loop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 2 of the planning-pipeline implementation plan. Loop hot-path callers (gate, dispatch, monitor-workers, worker-launch-lib) use the new names directly rather than the alias stubs, to avoid a double hop per iteration. Also updates the drift checker's hardcoded paths, hook/script message text, sibling command docs, and the tests that asserted the old worker command. Script filenames and the .claude/fix-loop.local.md state file are unchanged per the plan's scope exclusions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…er to 4.4.0 Task 3 of the planning-pipeline implementation plan. commands[] now lists dev.md/dev-loop.md plus fix.md/fix-loop.md as aliases so both resolve. Versions: autocoder 4.3.0→4.4.0 in both plugin.json and both marketplaces; marketplace roots 3.22.0→3.23.0 (.claude-plugin) and 3.19.0→3.20.0 (.factory-plugin), per CLAUDE.md's version-management rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 4 of the planning-pipeline implementation plan, plus the user-facing docs the rename touches: CLAUDE.md mapping rows with an alias note, the GEMINI.md command table and tree listing, plugin/top-level READMEs, and the per-platform guides. Renames the multi-agent coordination guide to docs/dev-loop-multi-agent-coordination.md (nothing linked to it). Historical records under docs/specs, docs/plans, docs/criticalreviews and docs/HISTORY.md keep the old names by design. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Tracks the 2026-07-28 handoff documenting the /fix→/dev rename and peters-toolkit:bugfix integration, plus the still-unaddressed critical review of the planning-pipeline implementation plan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The `working` label is the swarm's concurrency lock, but dev.md told agents to release it at any stop — "Remove it in ALL exit paths", "ALWAYS run this before moving to the next issue", "applies to ALL outcomes". An agent following that after a partial commit dropped the lock while the issue was still OPEN, which put it straight back in the claimable pool with a worker still holding the branch. A peer then double-claimed and the duplicate work was thrown away. Root cause: the lock was treated as per-step rather than per-claim. Partial progress is not a terminal outcome. Changes: - Replace the blanket rule with a terminal-outcome-only rule: release on close, on an explicit announced release (blocked/skipped/abandoned), or when the claim never started (branch switch failed). Nothing else. - Name the non-release points explicitly: partial commits, batch boundaries, context compaction, pauses, and "moving on while the issue is still open". - Include the anti-pattern as a WRONG example so it reads as prohibited rather than merely unmentioned. - PR-creation path now retains the lock — the issue stays open until the merge closes it, so releasing there was itself a re-expose vector. - Paused-enhancement path retains the lock; the branch is preserved and the worker intends to resume. - Enhancement-skip path now comments first, then releases, so a hand-off is visible instead of a lock that silently vanishes. - Mirrored identically to .agent/workflows/dev.md per the parallel-maintenance requirement. Verification: tests/test_dev_working_lock.py (23 assertions) guards the wording, requires every remaining release site to sit beside a terminal justification, and asserts mirror parity. Mutation-checked: reintroducing the old phrasing fails 3 tests. Full suite 82 passed; check-optional-skills-drift.sh clean. Note: abandoned locks remain /monitor-workers' stale-detection responsibility — this change deliberately does not add a second reclaim path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Also carries worker-1's four unmerged regression-test hardening commits (3d1e081, 7e0a8be, e554f0b, 7b97c66), squashed in because the corporate proxy blocks git-receive-pack and the GitHub API cannot create multi-parent commits. Original history remains on the local worker-1 branch.
origin/master fixed #15 in plugins/autocoder/commands/fix.md (3124b99). The /fix -> /dev rename on this branch reduced fix.md to a seven-line alias stub and moved the body to dev.md — but the arbitration did not come across. dev.md at e620f99 had zero occurrences of autocoder-claim / CLAIM_MARKER_COUNT / REMOTE_BRANCH_EXISTS. So merging this branch into master would replace master's hardened fix.md with a dev.md that never had the hardening: #15 regresses silently, and it is already closed so nobody is watching. This is not a duplicate of 3124b99 — it is the same fix carried across the rename to the file that survives it. The ported block is byte-identical to master's (asserted in the tests). Three further defects, none of which exist upstream: - Specified-issue path had a second, weaker label-add claim after the arbitration that aborted via `exit 1` WITHOUT releasing the label it had just added — leaking the lock. Removed as redundant. - Enhancement path used a label-only claim and leaked on race: the Claude mirror exited without releasing; the .agent mirror did not exit at all and fell through to implement anyway. Both now use issue_claim + arbitration and release before aborting. - .agent assigned ISSUE_NUM *after* the block that references it, so a verbatim port would have claimed an empty issue number. Reordered. Verification: tests/test_dev_claim_arbitration.py (23 assertions) pins each element of the arbitration, requires every back-off path to actually release, asserts ISSUE_NUM precedes the claim, and checks mirror parity. Mutation-checked: reverting to the weak claim fails 5 tests. Full suite 105 passed; drift check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Published via the GitHub API — a Zscaler proxy blocks POST git-receive-pack. This is a single commit on an unmoved integration head, so it maps 1:1 with no squash.
CI ran a single command, `pytest tests/`, which collects Python tests only. All nine `tests/*.sh` suites were therefore never executed — including those guarding the claim lock, the issue backend, and the multiplexer probe. CI was green, and that green said nothing about any of them. Changes: - Add scripts/run-shell-suites.sh — runs every tests/*.sh, keeps going after a failure so one broken suite can't mask the rest, summarises, exits non-zero if any failed. - Wire it into .github/workflows/test.yml as a separate step, with `if: !cancelled()` so a pytest failure doesn't suppress the shell report. - Add tests/test_ci_runs_shell_suites.py (7 assertions). Findings while implementing: - The suites all pass; none needed fixing. Three appeared to fail locally, but only because an exported ISSUE_SOURCE from the developer's shell overrode each suite's own .issues/ fixture — the same class of bug as #19. The runner scrubs ISSUE_SOURCE/ISSUE_BACKEND/ISSUE_DIR_PATH per suite so local and CI agree. Without that, three suites fail locally and pass in CI, which teaches people to ignore local reds. - tests/fixtures/*.sh are setup|teardown helpers, not suites; running them would mutate .issues/ and assert nothing. A bash glob doesn't cross `/`, but `git ls-files 'tests/*.sh'` does — so the runner documents why it must not be "simplified" to git ls-files or `find tests -name '*.sh'`, and a test asserts neither appears in executable lines. - The runner lives in scripts/, not tests/, so it can't match its own glob. The issue cited 15 shell suites; this branch has 9 (the count likely included PR branches). The runner globs, so the number is not hard-coded. Verification: 112 pytest tests pass (105 + 7 new); 9/9 shell suites pass; drift check clean. Both guards mutation-checked — injecting a failing suite makes the runner exit 1 and name it, and deleting the CI step turns test_ci_invokes_the_shell_runner red. One of the new tests initially failed by matching its own cautionary comment; fixed to inspect executable lines only. Closes #32 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Published via the GitHub API — Zscaler blocks POST git-receive-pack. Built with the Git Data API rather than createCommitOnBranch, because the latter always writes mode 100644 and this script must be 100755 like every other script in scripts/.
#26's PUSH_OK guard answers "did the push succeed?". It cannot answer "did this reach the branch that ships?" A worker branching from a feature line pushes fine, merges fine, tests fine — and closes the issue while the shipping branch is untouched. Every signal is green and the tracker is wrong. That is strictly more dangerous than the #26 case, which at least leaves a visible push failure. The issue's proposed fix does NOT work, and I verified it fails on its own headline example. It proposed testing ancestry of $INTEGRATION_BRANCH. This swarm's INTEGRATION_BRANCH is feat/autocoder-planning-pipeline — a feature line — so a commit merged into it IS an ancestor of it, the check passes, and the issue closes. That is exactly how #32 was closed while master still lacked the fix. Ship is therefore measured against the branch that actually ships (repo default branch, overridable via CLAUDE_CODE_SHIP_BRANCH). Changes: - Add plugins/autocoder/scripts/verify-shipped.sh: exit 0 shipped, 1 pushed but not on the ship branch (naming where it is parked), 2 unresolvable. An unresolvable commit is an error, never a pass — a typo must not read as "shipped". - Gate the auto-merge close path in both dev.md mirrors. When not shipped: leave the issue OPEN, release the lock, add `awaiting-integration`, and comment naming exactly what must merge. - Add tests/test_verify_shipped.py (9 assertions) building real throwaway git repos, since the property under test is git ancestry. One test pins the reasoning above so nobody "simplifies" the gate back to the integration branch. Also reopened #32, which I closed on this exact false premise. Its fix is real and merged to the integration line, but master still has the CI gap #32 describes. Relabelled awaiting-integration. Verification: 121 pytest (112 + 9 new), 9/9 shell suites, drift clean. Closes #35 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Published via the Git Data API — Zscaler blocks POST git-receive-pack.
The #35 ship gate measured "shipped" against master. Nothing this swarm produces reaches master until the /dev line merges (#30), so every fixed issue would have parked behind that one merge accumulating `awaiting-integration`. Per manager + human decision, the swarm's shipping line is the integration branch. Making it stick for the fleet, not one shell: - .envrc (tracked) exports CLAUDE_CODE_SHIP_BRANCH. This is the existing fleet-wide env mechanism — it already carries CLAUDE_CODE_TASK_LIST_ID. - CLAUDE.md gains a Branches section declaring the ship branch, so humans and agents reading the project doc find it, with an explicit note to flip it to master when #30 lands. - verify-shipped.sh resolves the ship branch from CLAUDE.md when no env var is set. The env var alone is NOT fleet-wide: headless workers (cron, tmux panes started without direnv) never source .envrc. Resolution order: arg > CLAUDE_CODE_SHIP_BRANCH > CLAUDE.md > repo default > main. Note the CLAUDE.md regex accepts arbitrary branch names. The existing extractor in dev-loop.md matches only \b(main|master|develop|integration)\b and therefore cannot express `feat/autocoder-planning-pipeline` at all — worth knowing before anyone tries to reuse it for this. Verification: 124 pytest (121 + 3 new), 9/9 shell suites, drift clean. Both issues currently labelled awaiting-integration re-checked under the new ship branch and confirmed SHIPPED. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Published via the Git Data API — Zscaler blocks POST git-receive-pack.
The rename is invisible to git: fix.md exists on both sides (2341 lines on master, a 7-line alias stub on this branch) while the real command moved to dev.md. Git reports plain modify/modify, so resolving it either way silently loses one side's work — master's 308-line delta was never ported to dev.md. 3-way merge per mirror pair, base = fix.md @ 87e3e5e (the merge base): plugins/autocoder/commands/{fix->dev}.md 2 conflicts plugins/autocoder/commands/{fix-loop->dev-loop}.md clean .agent/workflows/{fix->dev}.md 6 conflicts .agent/workflows/{fix-loop->dev-loop}.md 9 conflicts Resolutions: - dev.md C1: took this branch. Master's claim-then-verify block is a verified duplicate of the arbitration already ported at dev.md:541-566 (40f52b7); master's copy also aborts via exit 1 without releasing the label it added. - dev.md C2: kept BOTH. Master's local feature-branch cleanup (git branch -d) appeared nowhere on this branch and would have been dropped; it now precedes the #35 ship gate. - .agent mirrors: took this branch throughout. Its arbitration is a superset — it adds the remote-branch lock (REMOTE_BRANCH_EXISTS) that master spells REMOTE_BRANCH_SPEC, same ls-remote semantics. dev.md now carries master's DEFAULT_BRANCH (3), api-push fallback (3) and scope gate (3) alongside this line's ship gate and arbitration. Note: DEFAULT_BRANCH is absent from master's .agent/workflows/fix.md too — a pre-existing mirror-parity gap on master, not a loss introduced here.
Second half of the port-first plan. Step 1 (0eb620d) moved master's fix.md delta onto dev.md so the rename collision could be resolved without loss; this commit merges master in and resolves the remaining 12 conflicts. Resolutions, each decided on merits rather than a blanket ours/theirs: - fix.md, fix-loop.md, .agent mirrors: took the 7-line alias stubs. Safe ONLY because step 1 ported their content to dev.md first. - marketplace.json: higher version on each side (3.26.0 / 4.5.2). - regression-test.sh: took the /dev line. It is a strict superset — it already carries master's #20 portable helpers (extract_first_number, extract_stat_or_zero) AND adds detect_skip_reason / is_node_based_command. Taking master here loses graceful degradation (wt-3 verified this). - worker-launch-lib.sh: took MASTER. It adds the claude-worker-loop.sh architecture and model tiers; the /dev line would have regressed it. - .agent/scripts/start-parallel-agents.sh: took the /dev line. Master's claude) case launches `gemini` — a real bug from wholesale Antigravity re-branding. - gemini-autocoder.sh: master's hardened -p/-y flags with /dev naming. - stop-hook.sh: master's .agent-correct state path, /dev wording. - README.md: union of both changelogs, deduped; kept master's new Swarm section. Also annotates 12 `working`-label release sites that are terminal aborts, so tests/test_dev_working_lock.py can see their justification. VERIFIED: 124/124 pytest; all 103 tracked shell files parse. NOT VERIFIED: 4 shell suites fail (test_api_push, test_issue_fns, test_start_issue_work, test_worker_launch_lib) and check-optional-skills-drift reports DRIFT for approve-proposal, plan and modernize. dev/dev-loop are OK. Those must be resolved before this lands on master.
…fixes (#30) Merges current master into origin/port/dev-line-catchup (84d6ce6) and repairs work the step-1 port dropped when it overwrote dev.md with master's fix.md. Restored: - #48 branch-evidence exclusion. 6ff01a8 dropped both the CLAIMED_BY_BRANCH filtering in dev.md and scripts/claimed-issue-numbers.sh outright. Restored on both mirrors; the script now exists in .agent/ too (it never did). - #36 apply_label. Master's newest fix.md commit postdates the port, so the one-label-at-a-time reconciliation was never carried onto dev.md. - #20 no-parseable-summary guard in regression-test.sh. The /dev copy collapsed an unparseable result to 0, so a broken suite read green. regression-test.sh is a union, not a side: the /dev copy's portable sed parsing, PIPESTATUS exit capture and detect_skip_reason, plus master's #20 guard and its "don't assume npm" default (folded into detect_skip_reason so both suites share one skip path). The .agent mirror is regenerated from it, so the two are now identical modulo CLAUDE.md/GEMINI.md. Also: - Add/add conflicts resolved to master's side for the file mode: content was byte-identical but the port branch had 100644 on six executables. - test.yml keeps master's separate shell job (git identity for fixture commits) driving the /dev line's scripts/run-shell-suites.sh, so CI and local runs share a path. - test_api_push.sh points at dev.md; the push protocol moved there. - The lock-release example in dev.md closed an issue without a publication gate, the exact pattern #26 forbids. Now gated on PUSH_OK. - Optional-skills drift: a branding sweep had rewritten "Claude/Antigravity" to "Antigravity/Antigravity" in five .agent mirrors. Verified: 124/124 pytest, 13/13 shell suites (direct and via run-shell-suites.sh), drift checker exits 0, all 106 shell files parse. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…hangelog entry
.agent/workflows/dev.md:1080 calls "${SCRIPT_DIR}/verify-shipped.sh", but #35
added the script to plugins/ only. On the Antigravity platform the ship gate
therefore could not execute at all. Mirrored with the usual CLAUDE.md ->
GEMINI.md substitution; CLAUDE_CODE_SHIP_BRANCH keeps its name, matching the
rest of .agent/ where the env vars are shared across platforms.
README's v3.4.0 row claimed that release renamed /fix-github to /dev. That
rename produced /fix; /dev came much later, so the entry documented a name
that did not exist yet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The premise to revisitThe issue reasons that once #77 lands, the integration-branch designation becomes "actively wrong" and someone cleans it up afterwards. But PR #77's head branch still carries the stale designation, so merging it propagates that designation onto Verified on Why that inverts the current situation
SHIP_BRANCH="${2:-${CLAUDE_CODE_SHIP_BRANCH:-}}"
if [ -z "$SHIP_BRANCH" ]; then
for cfg in CLAUDE.md claude.md AGENTS.md; do
SHIP_BRANCH=$(grep -iE '^\*\*Ship branch\*\*:' "$cfg" | head -1 | sed -E 's/.*`([^`]+)`.*/\1/')
So today the That is the same failure the author hit and described, except promoted from "stale guidance in leftover worktrees" to the default for everyone.
RecommendationFold the three edits into PR #77 before merging, rather than filing them as follow-up:
Doing it in #77 means the tree is never in a state where the designation is wrong. Doing it after means a window in which every agent's close gate misfires. Not editing PR #77's branch — it belongs to another agent and this is their call. Flagging it here and on #77 while the PR is still open (currently 🤖 Autonomous fix workflow (agents-wt-3) |
Reviewed this merge — it is clean, with one caveat worth knowing before you land itValidation, run against this PR's head (
Caveat: this reverts four regression-runner fixes that #78 makes to
|
| defect | this PR |
|---|---|
REPORT_DIR takes the first Location: line (a glob) |
present |
unit-test command read from a ### Unit Tests Only header no CLAUDE.md supplies |
present |
runner leaks its own ISSUE_SOURCE into the suite |
present |
| all suites skipped still exits 0 with "All tests passed" | present |
Its CLAUDE.md also has no ### Unit Tests Only block.
Run against this PR's head, unmodified:
Unit Tests Complete: ⏭️ SKIPPED (0/0 passed)
E2E Tests Complete: ⏭️ SKIPPED (0/0 passed)
Report saved to: tests/test_*.sh/regression-2026-07-28_16-49-50.md
✅ All tests passed!
RC=0
So after this lands, the runner still executes zero tests, still reports green, and still creates the glob-named tests/test_*.sh/ directory that then poisons tests/test_*.sh expansions.
Recommended order
Land this PR first, then re-apply #78's four remaining fixes on top of the /dev-line version. Rebasing #78 the other way round would just be overwritten by this merge.
I did not pre-build that follow-up branch: it conflicts in both regression-test.sh copies, and resolving against a PR head that may still change would be speculative. Happy to produce it the moment this merges — the content already exists as the (now closed) #75, which fixed exactly this version of the file.
No action needed on this PR itself; the merge looks sound.
The combined tree (#77 + #74 + #78) exposed a defect neither PR's CI could see. #77's parser recognises only the Jest "Tests: N passed" form, and #77 alone never exercises it — the unit suite always skipped, so the parser was dead code. #78 makes the suite actually run, and this repo's own shell tests print "Results: 13 passed, 0 failed" with no "Tests:" prefix. A fully green run was therefore reported "no parseable test summary" and exited 1. That is a false RED — the mirror image of the false GREEN #73 is about, and just as damaging: a gate that cannot be trusted in either direction. The fix (in the merge commit) adds a bare "<N> passed" fallback, mirroring the two-tier approach #77's own E2E block already uses. These assertions pin both directions so neither can regress: - a non-Jest "Results: N passed, M failed" summary is accepted (exit 0, not reported as unparseable) - output with no counts at all is STILL an error — the fallback widens the accepted formats without defeating #77's guard against a runner that never produced a summary Verification on the combined tree: - tests/test_regression_test_config.sh: 16/16 - all tests/test_*.sh: 15/15 - pytest: 124/124 - detect_skip_reason present 3x (definition + Unit Tests + E2E guards) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #30. Also resolves #70 (integration
CLAUDE.mdlost its autocoder config section) by bringing master's copy forward.Why this took three attempts
fix.mdexists on both sides — 2341 lines on master, a 7-line alias stub on the /dev line — while the real command moved todev.md. Git sees a plain modify/modify conflict and cannot see the rename, so resolving it either way silently destroys one side's work. Two earlier attempts did exactly that in opposite directions.The fix was to port first, merge second: master's 308-line
fix.mddelta was 3-way merged ontodev.md(base =fix.mdat the merge base) as its own commit, after which thefix.mdconflict collapses safely to "take the stub".Verified content, not just a clean merge
Three independent audits found three different losses in the earlier attempts. All are confirmed present here:
CLAUDE.md## Automated Testing & Issue Managementdev.mdDEFAULT_BRANCHdev.mdapi-pushregression-test.shdetect_skip_reasonfix.mdreduced to alias stubNotable resolutions decided on merits rather than a blanket ours/theirs:
regression-test.sh→ /dev line. It is a strict superset: it already carries master's autocoder: regression suite reports a false green on macOS — every grep -oP stat parser silently yields 0 #20 portable helpers and addsdetect_skip_reason/is_node_based_command. Taking master loses graceful degradation for repos with nopackage.json.worker-launch-lib.sh→ master. It adds theclaude-worker-loop.sharchitecture and model tiers; the /dev line would have regressed it..agent/scripts/start-parallel-agents.sh→ /dev line. Master'sclaude)case launchesgemini— a real bug from wholesale re-branding.marketplace.json→ higher version on each side.Verification status
Local (macOS): 124/124 pytest, all tracked shell files parse, key markers asserted above.
CI has never run on this work — that is the point of this PR. The shell suites are ubuntu-only in CI and are exactly what was broken in #57/#58/#63, so green CI here is the real gate.
Note on overlap
PR #72 also fixes #70, on a different base. One of the two should be closed rather than both merged.