Skip to content

release(v9.0.0)!: default-on flip (uc + parallel) + wave-parallel autopilot - #96

Merged
aimsise merged 10 commits into
mainfrom
impl/parallel-autopilot-v9
Jun 25, 2026
Merged

release(v9.0.0)!: default-on flip (uc + parallel) + wave-parallel autopilot#96
aimsise merged 10 commits into
mainfrom
impl/parallel-autopilot-v9

Conversation

@aimsise

@aimsise aimsise commented Jun 25, 2026

Copy link
Copy Markdown
Owner

TL;DR

BREAKING (v9.0.0). Two run-defaults flip from opt-in to on for a bare invocation: ultracode orchestration (uc) and wave-parallel ticket execution (parallel). A bare /autopilot <slug> (and /brief <idea> under the chain=on default) now runs ultracode-orchestrated, and a multi-ticket run executes wave-by-wave through one ticket-executor subagent per topologically-ready ticket — each in an isolated git worktree, integrated at wave boundaries — instead of the inline serial loop. The safety guarantee inverts to the opt-out path: uc=off / parallel=off (and the SW_PARALLEL_TICKETS_MODE=off / SW_PARALLEL_HOOKS_MODE=off env kill switches) restore the byte-identical v8.7.0 behaviour.

What changed

  • uc default off→on. M+ tickets run their AC evaluation as a parallel multi-verifier panel (Workflow tool). uc=off restores the v8.7.0 single-evaluator Agent path (byte-identical; the cost-revert).
  • parallel default off→on. Multi-ticket runs go wave-parallel via ticket-executor subagents in isolated worktrees. parallel=off (or the env kill switches) restores the byte-identical v8.7.0 inline serial loop (no executor spawn, no wave cursor, no worktree, parallel_mode: state field omitted, every hook firing as before).
  • Unknown-value posture is uniform fail-safe → off (L3/R4). A fat-fingered parallel=<garbage> (and uc=<garbage>) coerces to off (the proven serial path), surfaced via [PARALLEL-MODE] mode=off active=n reason=invocation-unknown-value-failsafe.
  • mode= alias removal DEFERRED. The deprecated /brief mode=auto|manual alias stays functional; every shipped "removed in v9.0.0" reference was corrected to "a future major" (it is NOT removed in this release).

The parallel flip rides on the full Phase 2 rework + the T-005 R-SUBSTOP spike resolving to RELOCATE (the checkpoint guards relocate to SubagentStop, fire on the executor transcript, and enforce there).

Tickets (T-001..T-009)

parallel= plumbing + ticket-executor (T-001) · uc default-on (T-002) · resolve_parallel_mode + wave-cursor schema (T-003) · autopilot-continue wave-aware (T-004) · checkpoint guards → SubagentStop (T-005) · auto-compact wave-unit (T-006) · wave scheduler + parallel_max + H2 cascade-skip fix (T-007) · worktree isolation + cross-wave integration via the shared-tree .simple-workflow symlink (T-008) · default-on flip + v9.0.0 release prep (T-009).

Pre-release multi-angle review (4 cross-cutting criticals found + fixed)

A 25-agent / 6-dimension adversarial whole-branch review (each finding independently re-verified) caught 4 critical bugs the per-ticket reviews missed; all fixed + re-verified clean (commit fix(autopilot): critical pre-release review fixes (C1-C4)):

  • C1 — empty-wave cursor stall. Under parallel default-on, cascading dependency failures that empty later waves left current_wave un-advanced, so autopilot-continue.sh blocked "spawn next wave" until the loop guard fired. Fixed with an all-terminal guard (the serial path already handled it); fixture T-004-4b is negative-control-proven.
  • C2 — SW_PARALLEL_TICKETS_MODE kill switch was unwired. The documented panic button did nothing (the resolver reads SW_PARALLEL_HOOKS_MODE; /autopilot never checked SW_PARALLEL_TICKETS_MODE). Fixed by wiring an env-override (env > arg > default, unknown→off) into Argument Parsing + correcting the false "applied by the resolver" claim in SKILL.md + CLAUDE.md.
  • C3 — test-phase-state-contracts.sh was RED on the branch. A grep guard false-positived on a dense prose line (platformphase-state.yaml). Fixed by anchoring the rm grep to a shell-command boundary (genuine rm phase-state.yaml still caught; positive/negative controls verified).
  • C4 — metric-only routing contradiction (T-001 vs T-007). Resolved by splitting the routing gate into three explicit cases (off / metric-only serial-with-wave-log / on executor-routed) + aligning ticket-executor.md to == on.

Migration

See the v9.0.0 migration guide (to be posted under Discussions › Announcements). Reverts: uc=off, parallel=off, or SW_PARALLEL_TICKETS_MODE=off / SW_PARALLEL_HOOKS_MODE=off — each restores the byte-identical v8.7.0 behaviour.

Verification

bash tests/run-all.shALL TEST SUITES PASSED. test-skill-contracts.sh 900/900 (+ CT-PARALLEL-7..12), test-path-consistency.sh 145/145, test-accept-set-verify.sh 32/32, test-phase-state-contracts.sh 14/14, test-autopilot-continue.sh 65/65; ShellCheck clean; DECONTAM 0; plugin.json 9.0.0 == newest CHANGELOG [9.0.0] (CT-MODE-14). Opt-out byte-identity (uc=off parallel=off ≡ v8.7.0) preserved verbatim; agents/ contracts unchanged.

Owed (interactive dogfood, at a live run)

  • AC-6 — bare-invocation default-on behaviour.
  • AC-8 — the impl-guard-under-worktree end-to-end proof (T-005 ⟂ T-008): the SubagentStop checkpoint guard firing under a real worktree via an orchestrator-written main_checkout_root.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe

aimsise and others added 10 commits June 25, 2026 03:27
… (concurrency 1, default off)

T-001 of the parallel-autopilot feature (Wave 0). Adds the run-scoped
`parallel=` argument + `parallel_mode:` state field (a mirror of the
`uc=` / `ultracode_mode:` machinery), a new `ticket-executor` subagent,
wave-list emission, and execution-path routing — all at concurrency 1
(serial-equivalent), default OFF.

- agents/ticket-executor.md (new): runs one ticket's /scout->/impl->/ship
  pipeline as a subagent; `tools:` omitted (full inherit incl Agent);
  MUST NOT write autopilot-state.yaml (main loop is the single writer);
  returns a fixed `[TICKET-EXECUTOR-RESULT]` envelope.
- skills/autopilot/SKILL.md: parallel= parse (default off, unknown->off),
  parallel_mode write/resume, wave-list emit, and per-ticket execution
  routing (off->inline serial; !=off->one executor per ticket, concurrency 1).
- skills/brief/SKILL.md: parallel= parse + chain=off WARNING + forward to
  the chained /autopilot (composes with uc=).
- split-plan-parsing.md: level-synchronous Kahn wave layering (honest
  relationship to the linear Processing order — no false universal-equality).
- state-file.md: parallel_mode field + the envelope / single-writer contract.
- tests/test-skill-contracts.sh: CT-PARALLEL-1..6.
- CLAUDE.md: SW_PARALLEL_TICKETS_MODE kill switch ((B) harness-own).

Byte-identical opt-out (AC-1, meet-or-beat): parallel=off / absent emits
NO [PARALLEL-MODE] line, writes NO parallel_mode state field, spawns no
executor, and enters the unchanged inline loop. This is deliberately
stricter than the uc= peer (which emits its marker + writes its field even
for off) so the parallel=off lane is a truly silent, byte-identical
rollback path.

No version bump / CHANGELOG: this is a continuous build toward a single
v9.0.0 release (T-009 owns the version, CHANGELOG, and migration). README
user-facing docs are deferred to T-009 because parallel only becomes
user-facing-useful (real parallelism + default-on) at v9.0.0; the
dev-facing CLAUDE.md knob is documented here.

Verification: test-skill-contracts 871/871, test-path-consistency 145/145,
test-accept-set-verify 32/32, ShellCheck --severity=warning clean.
Adversarially verified (4 read-only lenses): byte-identity PASS (6/6 sites
gated), mirror-fidelity PASS, executor-contract PASS, governance PASS
(README deferral is intentional + recorded).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
T-002 of the parallel-autopilot feature (Wave 0). Flips the `uc=`
(ultracode orchestration) absent-token default from `off` to `on` across
all four resolution sites + the state-file doc + README. Pure prose /
argument-parsing change — zero hook coupling (no hook reads `uc` /
`ultracode_mode` / `UC_ORCH`; AC-6 verified).

- skills/autopilot/SKILL.md: Argument Parsing absent-token default -> on
  (+ reason=default for the on-by-default path); state-init writes
  ultracode_mode: on by default; the Step-5 resume missing-field fallback
  stays off (legacy-state fidelity — rationale added).
- skills/impl/SKILL.md: Step 1a-uc + Step 3a UC_ORCH resolution default
  -> on; the explicit-`off` "byte-identical to v8.5.0" literal preserved
  verbatim (R-c1/R3 drift guard); Step 15 dispatch unchanged.
- skills/brief/SKILL.md: omitted uc under chain=on -> on; chain=off +
  omitted stays off SILENTLY (no false WARNING; AC-2); explicit uc=on
  under chain=off still warns.
- state-file.md: ultracode_mode default doc off -> on.
- README.md: /brief signature default uc=on; ultracode-on-by-default
  narrative + uc=off as the revert; cost note promoted to by-default.
- tests/test-skill-contracts.sh: CT-UC-ORCH-5 (four-site flip + the
  explicit-off byte-identity literal survives).

The byte-identity guarantee moves to the EXPLICIT opt-out: `uc=off` is
byte-identical to v8.5.0 (Agent path), exactly as the parallel=off lane
in T-001. No version bump / CHANGELOG (single v9.0.0 release at T-009,
which also documents this as a breaking bare-invocation cost change +
migration).

Verification: test-skill-contracts 872/872, test-path-consistency 145/145,
test-accept-set-verify 32/32, ShellCheck clean, no hooks/ touched.
Adversarially verified (2 read-only lenses): flip-completeness PASS
(4/4 sites, leftover hunt clean — one self-caught state-init leftover
fixed pre-commit), preserve-literal + AC-2/3/4 + README PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
…a (T-003)

T-003 of the parallel-autopilot feature (Wave 1). The hook-rework
foundation for T-004/5/6 — ships only the shared resolver, the wave-cursor
schema + orchestrator-write obligation prose, and unit tests. NO hook
behaviour changes yet (the resolver is dormant until T-004/5/6).

- hooks/lib/parse-state-file.sh: + resolve_parallel_mode <state_file>
  (precedence SW_PARALLEL_HOOKS_MODE env > parallel_mode: state scalar >
  off; a SET-but-unknown env value -> off WITHOUT fall-through; absent /
  null / unknown state -> off; missing / unreadable file -> off; prints
  exactly on|metric-only|off, NEVER empty — every ambiguity fails CLOSED to
  off, the proven serial path). Added to the export -f line + header
  contract. Mirrors the get_risk_tolerance case-validator.
- skills/autopilot/references/state-file.md: + the four OPTIONAL wave-cursor
  fields (wave_count / current_wave [-1 before first spawn] / wave_status
  [in_flight|drained] / main_checkout_root) with domains, the single-writer
  rule, and resume semantics (recomputed each entry; a projection of the
  authoritative per-ticket status, never a second source of truth).
- skills/autopilot/SKILL.md: + the single-writer cursor-write obligation
  (main_checkout_root at Phase 2 init; wave_count at wave computation;
  current_wave + wave_status:in_flight before a wave spawn; wave_status:
  drained after the barrier; the ticket-executor NEVER writes the cursor).
- CLAUDE.md: + SW_PARALLEL_HOOKS_MODE (tri-value, default = follow
  parallel_mode, unknown -> off = serial; (B) harness-own; the shared
  hook-side kill switch consumed by the resolver).
- tests/test-hooks-lib.sh: + 12 resolve_parallel_mode unit tests (precedence,
  fail-closed, never-empty, missing-file, env-unknown-no-fall-through).
- tests/test-skill-contracts.sh: + CT-PARALLEL-CURSOR-1/2 (schema + obligation
  + knob + resolver presence/export drift guards).

Known limitation (inherited, safe-degrading): parse_yaml_scalar reads an
UNQUOTED `parallel_mode: on` correctly as the string "on" via yq (tier 1,
YAML 1.2); on a yq-LESS host the python3+PyYAML tier (YAML 1.1) coerces
`on` -> True and the resolver degrades to `off` (serial) — the SAFE
direction. yq is a documented hard dependency; this matches the existing
ultracode_mode reader and is not a T-003 regression.

Verification: test-hooks-lib 176/176 (incl. the 12 new resolver tests),
test-skill-contracts 874/874, test-path-consistency 145/145, ShellCheck
--severity=warning clean (parse-state-file.sh + both test files). No hooks/
decision logic changed; the resolver has no caller yet (AC-6). Adversarially
verified via an ultracode Workflow (3 read-only Explore lenses:
resolver-correctness, schema-obligation, no-change-governance) — all PASS,
zero defects.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
Wave 2. Inserts one wave-aware branch (gated if PARALLEL_MODE != off) AFTER the policy-gate-stop honour gate + the .auto-compact-pending sentinel check, BEFORE the FILE_COUNT loop guard (R-ORDER-SENTINEL). in_flight->barrier block; drained+remaining->spawn-next block; drained+last+terminal->fall through. metric-only->serial. parallel=off byte-identical.

Verify: test-autopilot-continue 64/64 (incl T-004-9 honour-gate-before-wave fixture added after adversarial-verify), ShellCheck clean. Verified via ultracode Workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
…in-Stop stand-down (T-005)

Wave 2. hooks.json gains a SubagentStop array with TWO separate top-level entries (impl + scout guards; autopilot-continue/session-stop-log NOT added; Stop unchanged). Both guards (symmetric): read .hook_event_name (missing->Stop); under PARALLEL_MODE!=off AND event!=SubagentStop -> stand down (exit 0); metric-only logs+falls through; SubagentStop path adds early is_autopilot_context||exit 0 then enforces verbatim on the executor transcript; prefer main_checkout_root (T-003) over _psf_repo_root (keeps impl-guard alive under a worktree). R-SUBSTOP spike = RELOCATE (gates T-009 flip). parallel=off byte-identical.

Verify: test-scout-checkpoint-guard 27/27, test-impl-checkpoint-guard 21/21 (incl worktree-via-main_checkout_root), ShellCheck clean, hooks.json valid. Verified via ultracode Workflow. (CT-PARALLEL-SUBSTOP-1 lands with T-006 in the shared test-skill-contracts.sh.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
Wave 2. post-ship resolves PARALLEL_MODE BEFORE the ship-detector early-exit and under parallel SUPPLANTS it (if/elif/else: off->ship-detector; metric-only->log+ship; on->_detect_wave_drained) so a drained write WITHOUT ship:completed still injects (M1). Dedup re-keyed to wave-{N}:{ts} (hyphen) so the shared %%:* / ##*: split is untouched. IS_LAST_TICKET generalized to cursor-based IS_LAST_WAVE. pre-next-scout stands down under parallel. parallel=off byte-identical (ship-detector + serial marker verbatim). Gate 5 gets a T-007 done/-move precondition note.

Also lands the SHARED test-skill-contracts.sh CTs for BOTH Wave-2 guards: CT-PARALLEL-SUBSTOP-1 (T-005) + CT-AC-WAVE-1 (T-006, greps the executable G7_CURRENT_WAVE_LW not the comment-only IS_LAST_WAVE, fixing a verify-found vacuous grep).

Verify: test-post-ship-state-auto-compact 41/41 (NEW file; M1 drained-without-ship, 5:1700+wave-2:1700 marker round-trip, AC-4c cursor IS_LAST with shipped<total), test-pre-next-scout 22/22, test-skill-contracts 876/876, ShellCheck clean. 4-lens ultracode adversarial verify: core PASS; the verify-found vacuous-CT + 2 edge-fixture gaps fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
…e-out fix (T-007)

Turn the concurrency-1 executor-routed path (T-001) into real per-wave parallelism. Under PARALLEL_MODE == on the main loop iterates topological waves: build READY_k (resume-skip + per-wave dependency re-eval), pre-wave single-writer state write (in_progress), spawn min(|READY_k|, CONCURRENCY_CAP) ticket-executor subagents in ONE message behind a foreground barrier, post-wave single-writer state write (transcribe envelopes, fold dep-skips, drained) -- exactly two autopilot-state.yaml writes per ACTIVE wave, executors never write state. Oversized waves sub-batch lex-ordered (still two writes/wave). parallel_max= concurrency cap (arg > SW_PARALLEL_MAX_CONCURRENCY env > default 4); parallel_max=1 degenerates to serial. Wave-variant auto-compact exception (do NOT spawn WAVE_{k+1}).

H2 FIX (HIGH): hooks/pre-state-transition.sh cascade-skip carve-out regex dependency_failed|dependency_skipped -> dependency_([^[:space:]]*_)?(failed|skipped). INTELLIGENT DOCUMENTED DEVIATION from the ticket-literal dependency_[^[:space:]]*_(failed|skipped): the literal would NOT match the bare dependency_failed form, breaking back-compat. Shipped form matches the slug-interpolated dependency_002-bar_failed (which a whole-wave in_progress run actively triggers) AND the bare tokens, rejects non-dependency reasons. Verified directly + CT-WAVE-5 drives the hook with a negative control.

parallel=off / absent is byte-identical: the wave loop is added ONLY under PARALLEL_MODE == on; the serial sentences survive verbatim; [PARALLEL-MODE] line + parallel_mode: field + wave cursor are omitted when off.

Adversarial 2-lens verify (PASS_WITH_NITS, no blockers) drove 3 fixes, all in these 6 files: (1) empty-wave resume skip -- a spawn-less wave does ZERO state writes, realising Phase 1 Step 5; (2) parallel_max= coercion WARNING gated to PARALLEL_MODE != off so a global SW_PARALLEL_MAX_CONCURRENCY=garbage cannot leak stderr into a serial rollback; (3) CT-WAVE-3 (B)harness-own sub-check co-located with the new knob line; + CT-WAVE-6 covers (1)+(2). Deferred nit (theoretical, no real autopilot reason triggers it): the H2 regex is unanchored substring-match (matches its original semantics); a ^...$ anchor is a self-documenting follow-up.

Tests: skill-contracts 882/882 (CT-WAVE-1..6), state-transition-guard 16/16, path 145/145, accept-set-verify 32/32, ShellCheck clean, DECONTAM 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
…ed-tree symlink (T-008)

Under PARALLEL_MODE == on, each ticket-executor runs in a per-ticket isolation worktree so concurrent same-wave siblings never collide on the working tree. The main loop (single writer): pre-creates git worktree add -b ap/<parent>/<NNN-slug> <.claude/worktrees/ap-<parent>-<NNN-slug>> <BASE_REF> (explicit ref, NOT EnterWorktree/baseRef -- baseRef is binary fresh|head; H3 pins the path under .claude/worktrees/ so EnterWorktree(path=) is accepted); integrates each completed branch into a local-only ap-integration/<parent> at the wave boundary (--no-ff --no-edit, topo/lex, idempotent via merge-base --is-ancestor, conflict -> ticket failed + integration_conflict_<other-NNN> + cascade-skip, run continues), advancing BASE_REF so wave k>0 sees earlier waves; three-tier cleanup (per-ticket remove --force / integration-worktree post-loop / parent-scoped startup stale-sweep) + SW_PARALLEL_WORKTREE_KEEP. Each ticket still ships its own PR (no merge=true); the integration branch is never pushed. Envelope gains branch + head_sha. ticket-executor keeps tools: omitted (preserves Agent/Skill depth+1 inheritance) with the add/remove/list worktree scope documented to mirror ac-evaluator. parallel=off / metric-only add NO worktree code (byte-identical).

W-3 path-resolution (user-chosen mechanism = symlink): .simple-workflow/ is gitignored and ABSENT in a fresh worktree, so the scheduler creates a <worktree>/.simple-workflow -> <MAIN_REPO>/.simple-workflow symlink at worktree pre-create (step 2a). The WHOLE pipeline (/scout//impl//ship//tune) resolves its relative .simple-workflow/... paths -- incl the /ship Step 5 ticket-move -- through the symlink to the shared main checkout, so NO pipeline skill changes and /ship Step 5 is byte-unchanged (no ARTIFACT_ROOT argument). A symlink shares ONE inode (not a .worktreeinclude copy, W-8), so per-ticket-disjoint writes + the main-loop single-writer of autopilot-state.yaml stay race-free.

Adversarial verify (2 lenses) FAILED on the first pass: the /ship W-3 audit was documentation-only (bare relative paths would strand the move under a worktree). Fixed by the symlink above. Two more fixes from verify + my own review, all confirmed by a clean re-verify (both lenses PASS_WITH_NITS, 0 blockers): (1) wave-boundary integration reordered to step 4a (AFTER the barrier, BEFORE the post-wave write) so an integration-conflict status flip is PERSISTED by step 5 before the next wave's dependency re-eval reads it -- cascade-skip correctness; two-writes-per-active-wave intact; (2) Phase 2 init mid-merge recovery (merge --abort + worktree remove --force a leftover integration worktree before re-create). Nits fixed: state-file.md step-ref + two-writes wording, empty-wave skip names 4a, symlink-removal-vs-target note, Bash(ln -s:*) scoped grant.

Documented limitation (not a correctness bug): /ship Step 6 /tune read-modify-writes the SHARED .simple-workflow/kb/ accumulator, so under concurrency > 1 concurrent /tune calls race to a bounded KB-learning lost-update. Ticket execution + status + autopilot-state.yaml are unaffected; only best-effort learning fidelity drops. The false 'disjoint prevents races' claim was corrected; serializing /tune (skip-in-executor + post-wave-in-main-loop, or a kb/ lock) is the recorded follow-up.

Tests: skill-contracts 894/894 (CT-WORKTREE-1..12, all non-vacuous), path 145/145, accept-set-verify 32/32, state-transition-guard 16/16, ShellCheck clean, DECONTAM 0; ac-evaluator/-hi untouched (twins unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
…opilot

BREAKING: two run-defaults flip from opt-in to on for a bare invocation. uc (ultracode orchestration) default off->on (T-002 prose, reaffirmed here): M+ tickets run their AC evaluation as a parallel multi-verifier panel. parallel (wave-parallel ticket execution) default off->on: a multi-ticket /autopilot (and /brief chain=on) run executes wave-by-wave through one ticket-executor subagent per topologically-ready ticket, each in an isolated git worktree, merged at wave boundaries, instead of the inline serial loop.

The parallel flip is the FINAL hunk, gated on the full Phase 2 rework (T-004/5/6 wave-aware Stop/checkpoint/auto-compact) + the wave scheduler (T-007) + worktree isolation (T-008) ALL landing in this release AND on the T-005 R-SUBSTOP spike resolving to RELOCATE (SubagentStop fires with the executor transcript and the checkpoint guards enforce). uc has no hook dependency and rides v9.0.0 for the breaking-when-in-doubt bundling.

Safety inverts to the OPT-OUT path, byte-identical to v8.7.0: uc=off restores the single-evaluator Agent path; parallel=off (or SW_PARALLEL_TICKETS_MODE=off / SW_PARALLEL_HOOKS_MODE=off) restores the inline serial loop (no ticket-executor spawn, no wave cursor, no worktree machinery, parallel_mode: state field omitted, every hook firing as before). L3/R4: an unknown parallel=<garbage> (and uc=<garbage>) value fails SAFE to off (uniform fail-closed direction), the parallel coercion observable via [PARALLEL-MODE] mode=off active=n reason=invocation-unknown-value-failsafe.

mode= alias removal DEFERRED (decision: defer): the deprecated /brief mode=auto|manual alias stays functional; every shipped reference (the runtime WARNING, README signature, the mode-independence guard note, the agent-spawn-prompts precedence note) was corrected this release from 'removed in v9.0.0' to 'a future major (deferred from v9.0.0)' so no v9.0.0 artifact claims its own removal in the shipping version. CHANGELOG ### Removed records the deferral honestly.

Documented limitation (decision: ship): under concurrency > 1, /ship Step 6 /tune read-modify-writes the shared .simple-workflow/kb/ accumulator, racing to a bounded KB-learning lost-update (best-effort fidelity drop, NOT a correctness bug; ticket execution + status + autopilot-state.yaml unaffected). Serializing /tune is the documented follow-up.

Adversarial verify: a 2-lens pass FAILED on a mode= deferral inconsistency (README falsely claimed the alias was removed in v9.0.0); fixed; a final re-verify is PASS_WITH_NITS (0 blockers). plugin.json 9.0.0 == newest CHANGELOG [9.0.0] (CT-MODE-14); real ISO date 2026-06-25. A GitHub Discussions migration guide is drafted (gitignored .docs/, post at release time). No agent contract or spawn-prompt changed (agents/ untouched).

Tests: skill-contracts 898/898 (+ CT-PARALLEL-7..10: default flip, parallel=off byte-identity, bare-default-on routes to wave-parallel, unknown->off failsafe; CT-UC-ORCH-5 uc=off byte-identity), path 145/145, accept-set-verify 32/32, state-transition-guard 16/16, ShellCheck clean, DECONTAM 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
A 25-agent / 6-dimension adversarial whole-branch review (each finding independently re-verified) before the v9.0.0 publish caught 4 CROSS-CUTTING critical bugs that the per-ticket reviews missed. All fixed + re-verified clean (both lenses PASS_WITH_NITS, 0 blockers/majors).

C1 (empty-wave cursor stall, hooks/autopilot-continue.sh): under parallel default-on, cascading dependency failures that leave later waves EMPTY left current_wave un-advanced (empty waves skip the cursor-advancing step 2), so the Stop hook kept selecting spawn_next ((current_wave+1)<wave_count stays true) and emitted decision:block FOREVER until the FILE_COUNT loop guard fired [AUTOPILOT-STALL]. The serial path already handled this cleanly. FIX: an all-terminal guard in the WAVE_DECISION logic — when spawn_next is selected but parse_active_steps is EMPTY (all tickets terminal), override to terminal_check and fall through to the existing all-terminal exit-0. Guard lives entirely inside the PARALLEL_MODE != off block (serial byte-identity holds). Fixture T-004-4b (drained + current_wave=0 + wave_count=3 + all-terminal) is negative-control-proven (fails if the guard is removed); suite 65/65.

C2 (SW_PARALLEL_TICKETS_MODE kill switch UNWIRED): the documented operator panic button did NOTHING — resolve_parallel_mode reads SW_PARALLEL_HOOKS_MODE (the hook side) and /autopilot Argument Parsing never checked SW_PARALLEL_TICKETS_MODE, so =off still resolved PARALLEL_MODE=on and spawned executors. FIX: wire an explicit env-override into SKILL.md Argument Parsing (precedence env SW_PARALLEL_TICKETS_MODE > parallel= arg > absent-token default on; unknown env -> off fail-safe) + correct the false 'applied by the resolver helper' claim in BOTH skills/autopilot/SKILL.md AND CLAUDE.md (two-knob architecture: TICKETS_MODE = run/skill side, HOOKS_MODE = hook side). CT-PARALLEL-11 (non-vacuous).

C3 (test-phase-state-contracts.sh RED on the branch): the no-rm-of-phase-state.yaml guard pattern rm[[:space:]].*phase-state.yaml false-positive-FAILed on a dense T-008 prose line ('the platfoRM blocks ... phase-state.yaml') — run-all.sh was failing. FIX: anchor rm to a shell-command boundary ((^|[^[:alnum:]_])rm[[:space:]][^|;&]*phase-state.yaml) + the same hardening on the sibling impl-state.yaml guard; positive control (real 'rm phase-state.yaml' / 'rm -f .../phase-state.yaml' still caught) + negative control (platform/transform/confirm prose no longer matches) verified. 14/14; run-all.sh = ALL TEST SUITES PASSED.

C4 (metric-only routing contradiction): SKILL.md:176 (T-001) said 'PARALLEL_MODE != off -> executor-routed' (capturing metric-only) while SKILL.md:249 (T-007) said 'metric-only = serial inline, no executor' — mutually exclusive. FIX: split the routing gate into THREE explicit cases (off = inline serial byte-identical; metric-only = inline serial + wave-plan log, no executor/spawn/cursor/worktree; on = executor-routed), retitle the executor section + wave-cursor obligation + state-file clause to '== on', and align agents/ticket-executor.md (description + body) to 'parallel_mode == on (NOT metric-only)'. CT-PARALLEL-12 (non-vacuous).

Tests: skill-contracts 900/900 (CT-PARALLEL-11/12 added), path 145/145, accept-set 32/32, phase-state-contracts 14/14, autopilot-continue 65/65, run-all.sh ALL PASSED, ShellCheck clean, DECONTAM 0, CT-MODE-14 version sync. Residual minor nits (non-blocking, recorded): C1 redundant parse_active_steps call, C3 theoretical 'NOT rm' prose (no corpus match), C2/C4 implicit single-emission/silence cross-refs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Mw2bH4wbEPeebXsvSG6rWe
@aimsise
aimsise merged commit 7b964a7 into main Jun 25, 2026
2 checks passed
@aimsise
aimsise deleted the impl/parallel-autopilot-v9 branch June 25, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant