Symptom
codex-clean resume <session-id> does not return to the seat that created the session. It picks a seat by the normal rotation strategy and runs codex resume against whichever seat that turns out to be.
Evidence
Mode::Resume only shapes the child's argv (src/runner.rs:1457-1470); it has no effect on seat selection. orchestrate picks by strategy with no resume special-case.
A session-to-seat mapping does exist, but it is lossy and unused by the runner:
SeatRuntimeState::last_session / last_session_at (src/seat.rs:955-959) hold only the most recent session per seat, overwritten on every run (src/runner.rs:719-720).
- The only consumer is
seat_cmd's cost lookup (src/seat_cmd.rs:1415-1445), which searches seats for a matching last_session and falls back to active_seat.
So the data needed to pin a resume is half-present and thrown away after one run.
What needs verifying first
Whether this actually breaks anything, which I did not test:
- Session rollout files live in the shared
~/.codex/sessions (1492 of them here), so codex resume <id> will find the local file whichever seat is active.
- The open question is server-side: does continuing a thread created by one account work when the request is authenticated as a different account in the same workspace? If it does, seat affinity genuinely does not matter and this issue closes as documentation. If it errors or silently starts a new thread, it needs pinning.
Test: run something on main, note the session id, force CODEX_CLEAN_SEAT=backup1 codex-clean resume <id>, see what happens.
Suggested direction, if it does matter
Record a durable session_id -> seat map in state.json (bounded by count or age) rather than one last_session per seat, and have orchestrate pin the seat for Mode::Resume. Unknown session id falls back to the active seat with a warning.
Note that resume --last is a separate question: it means "the most recent local rollout", which is seat-agnostic today.
Related: #38 is unrelated, but this shares state with the locking work.
Symptom
codex-clean resume <session-id>does not return to the seat that created the session. It picks a seat by the normal rotation strategy and runscodex resumeagainst whichever seat that turns out to be.Evidence
Mode::Resumeonly shapes the child's argv (src/runner.rs:1457-1470); it has no effect on seat selection.orchestratepicks by strategy with no resume special-case.A session-to-seat mapping does exist, but it is lossy and unused by the runner:
SeatRuntimeState::last_session/last_session_at(src/seat.rs:955-959) hold only the most recent session per seat, overwritten on every run (src/runner.rs:719-720).seat_cmd's cost lookup (src/seat_cmd.rs:1415-1445), which searches seats for a matchinglast_sessionand falls back toactive_seat.So the data needed to pin a resume is half-present and thrown away after one run.
What needs verifying first
Whether this actually breaks anything, which I did not test:
~/.codex/sessions(1492 of them here), socodex resume <id>will find the local file whichever seat is active.Test: run something on
main, note the session id, forceCODEX_CLEAN_SEAT=backup1 codex-clean resume <id>, see what happens.Suggested direction, if it does matter
Record a durable
session_id -> seatmap instate.json(bounded by count or age) rather than onelast_sessionper seat, and haveorchestratepin the seat forMode::Resume. Unknown session id falls back to the active seat with a warning.Note that
resume --lastis a separate question: it means "the most recent local rollout", which is seat-agnostic today.Related: #38 is unrelated, but this shares state with the locking work.