Repository navigation
fix(crews): Crew groups keep seats without thread facts as unknown - #300
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Repository: Jacksondr5/j5code/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Comment |
c0aef97 to
55a31ee
Compare
The sidebar expander dropped any Crew seat whose thread was not in client state, and the Fleet page grouped a Crew only from placed participants, so a Crew could under-count or vanish while its seats were unknown. The spawned-children read now gives a Captain's row every seat on its live rosters that no parent holds, and the Fleet read emits a thread-less row for a roster seat the ledger never recorded. The sidebar keeps a seat with no thread as an unknown row, and the Fleet tree hangs an unplaced seat under its Captain, so both summaries count every seat. Closes #227 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3912ba5 to
5124a1e
Compare
|
Decision (Jackson, 2026-09-26): keep #300 as is, server part included. The case worth covering is the few seconds between a seat being recorded and its thread appearing during a normal launch. Only the server read knows about a roster seat with no ledger row, so the web change can't cover this alone. A seat whose thread failed to create is handled by #313 (row dropped, and the Captain told "Not created"). Seats left over after a server restart mid-launch are deliberately not covered: after a restart, the person should expect manual repair. This supersedes the panel's "trim to the web part" suggestion. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Jacksondr5
left a comment
There was a problem hiding this comment.
Posted by an AI agent on Jackson's behalf.
Approved as is, server part included, per Jackson's 2026-09-26 decision. Verified live by the review panel (Opus 5.5 + Astra): a reserved seat shows as Unknown in the sidebar and on Fleet.
Merge order: #292, #313, #300, then #315 (after #349 lands). #306 rebases after the stack.
Conflict: #313 rewrote CrewProposalService.resolve; kept main's version and re-applied this branch's stale-preview refusal text naming the roster, a seat's runtime, and the Captain's branch or worktree. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Important
This PR is part of the Crews stack. Merge top to bottom, one at a time, and let each land on
j5/mainbefore the next. #292 isn't in the stack but has to merge before #313.fix(crews): no seat launches into a retired Crew or under a gone Captain #271: No seat launches into a retired Crew or under a gone Captain✅ mergedfix(crews): unit stop and archive finish over a seat that was never created #279: Unit stop and archive finish over a seat that was never created✅ mergedWhy #292 goes first: J5 migrations run in id order, and the migrator skips any id at or below the newest one a database has already applied. If #313's migration 021 ships before #292's 020, 020 never runs on that database.
Problem
A Crew's state is its seats' states from measured facts, but both web surfaces dropped seats the client had no thread facts for (#227). The sidebar expander skipped any seat whose thread wasn't in client state, and the Fleet page built Crew groups only from placed participants. A reserved seat that was never created, or one recorded but not yet placed, simply vanished, so a Crew under-counted or disappeared entirely.
What I changed
apps/server/src/j5/a2a/SpawnedChildrenHttp.ts→projectSpawnedChildren: a Captain's row now also carries every seat on its live rosters that no parent holds (never registered, or registered with no placement). The route looks up Crews the requested rows command (listInvolvingwithparticipantIds) and reads each roster seat's membership and placement in one query.apps/server/src/j5/a2a/FleetReadsHttp.ts→projectFleetSquadron: a live roster seat with no ledger row is emitted as an agent row withthreadId: null, placed under its Captain, named by its seat.apps/web/src/j5/squadron/spawnedChildren.logic.ts→selectSpawnedChildRows: a Crew seat with no thread stays as a row withthread: undefined(sorted last) instead of being dropped; solo peers still wait for their thread.apps/web/src/j5/squadron/SpawnedChildren.tsx: such a seat renders as a plain, non-clickable row: seat name and "Unknown".apps/web/src/j5/fleet/fleet.logic.ts→buildFleetTree: a Crew seat with no placement parent hangs under its Captain, so the group counts it.Sidebar, before → after (the reserved
criticseat was missing; now "2 seats · 1 unknown"):Fleet Crew group, before → after:
Why this shape
The live Fleet read already carries full rosters, and the ledger is the only place that knows whether a seat was ever recorded, so I measure "this seat has no row" once on the server and let both clients render what they're given. I rejected building groups from the roster on each client: the sidebar read doesn't carry the roster, and each client would have to re-derive archived-versus-never-created from partial data.
crewState.tsalready had anunknownstate; nothing could reach it until now.Invariants
unknown, never idle or settled, and an unknown seat keeps its Crew in Active (fleet-page AC31).crewset, sofleetInvolvedThreadRefsnames their Captain and nothing new.Surfaces
packages/contracts)Out of scope
Upgrade and data
None. No migration; older clients just see the extra rows (the sidebar's older logic still drops them, the Fleet's older tree roots them).
Verification
vp test run apps/server/src/j5/a2a: 339 passed, 1 skipped. New cases inSpawnedChildrenHttp.test.tsandFleetReadsHttp.test.ts.vp test run apps/web/src/j5/fleet apps/web/src/j5/squadron apps/web/src/j5/crew/crewState.test.ts: 93 passed. New cases cover a running seat plus an unknown one, a Crew with no placed seat, a thread arriving later, and colliding thread ids across environments.Review focus
projectSpawnedChildren(archived membership or placement under another parent): is there a real state where a live seat is placed elsewhere and should still count under its Captain?listInvolvinglookup by Captain runs on every spawned-children read. It's indexed (j5_agent_crew_instance_captain_idx), but check that it stays cheap for 500 requested rows.Closes #227
Claude Opus 5.5 via Claude Code
🤖 Generated with Claude Code