Repository navigation
Crew launch retries converge on the final approved roster #220
Description
A Crew launch that fails partway is supposed to hand the gate back and let a retry converge on the same seats. Three retry paths do not converge today, and each one either strands a seat or refuses a seat the person approved.
Where it breaks:
- Addition retries never clean up stale reservations.
CrewLaunchService.addSeats(apps/server/src/j5/a2a/CrewLaunchService.ts:702-766) reserves member rows before spawning but, unlike the initial-roster path (:639-674), never retires a reservation the person renamed or dropped on the retry. Renameold-nametonew-nameafter a failed addition and the Crew ends up with both rows, one never briefed, and the dead row counts against the twelve-seat cap. - A seat dropped on one retry and re-added on the next is refused as retired.
assertReusableSeats(CrewLaunchService.ts:586-596) sees that the deterministic seat thread was archived by the earlier retry cleanup and refuses with "reusing a retired seat". Nothing can ever launch that seat name for that proposal again. The 2026-09-18 worklog left this open; I want it closed. - A persona change on an uncreated seat is silently lost.
AgentCrewInstanceService.ts:202inserts members withINSERT OR IGNORE, so if the person changes a not-yet-spawned seat's persona or reason before retrying, the manifest keeps the old values while the seat launches with the new ones.
What should change:
- Before spawning, reconcile this proposal's reservations against the final approved roster: retire reservations for seats that were dropped or renamed, update persona and reason on reservations whose thread does not exist yet, and never touch a seat whose thread already exists.
- For a re-added seat whose deterministic thread was archived by a previous retry, unarchive that thread and reuse it rather than minting a new id. My call is to keep every id derivable from proposal and seat name; if that turns out to be impossible, say so on this issue before switching to a fresh id.
- Apply the same convergence to roster launches and additions through one code path.
Tests to ship (CrewLaunchService.test.ts, AgentCrewInstanceService.test.ts):
- failed addition, then rename at eleven existing seats, converges without hitting the cap
- drop a seat on one failed launch, re-add it on the next, and the seat is briefed exactly once
- change an uncreated seat's persona before retry and the manifest reflects the new persona
- established seats and their threads are untouched by a retry
Done when a retry after any failed launch or addition lands the exact roster the person approved on the last card, with no orphan rows and no "retired seat" refusal for a seat that is on that roster.
Related criteria: crews.md AC7.
Blocks (soft) #222. The cap counting there is simpler once stale reservations from failed retries are gone. Independent of #221, though both touch the launch recovery path; land whichever is ready and rebase the other.
Activity
bryantderosier commentedon Sep 21, 2026
Fix is up in #235.
One pre-existing thing the review turned up that is out of scope for this issue and worth its own follow-up: the command receipt replays rejected receipts as well as accepted ones. So if the decider ever rejects a seat's deterministic
spawn-createorspawn-brief, every retry of that proposal re-fails on the same id, and the person's only way out is to rename the seat or decline. None of the three paths here hit that, and the ids stay derivable as I asked, but the retry story is not fully closed until a rejected seat can recover too.