Skip to content

fix(ca): an agent with a pane open is not still "waking" - #1106

Merged
codyde merged 2 commits into
masterfrom
fix/agent-waking-with-open-pane
Aug 15, 2026
Merged

fix(ca): an agent with a pane open is not still "waking"#1106
codyde merged 2 commits into
masterfrom
fix/agent-waking-with-open-pane

Conversation

@codyde

@codyde codyde commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

Create a new cloud agent, land in its session, and the tree still calls it "waking" while you're typing into it.

The row renders the platform's raw status, and sorted_agents already spells out the vocabulary — "running first, waking next, sleeping last" — where the middle rank is literally status == "starting".

That status lags routability by design. #1098 established the gap: the platform routes a shell as soon as the container exists, while RUNNING additionally waits on route publication, a projection hop, and a poll interval. The launcher stopped gating attach on it and started probing the route instead — but the tree kept rendering the value the CLI had already decided not to trust.

Fix

An attached, unfinished pane is direct evidence the agent is up: there's a shell running on it. Believe the pane over the projection.

Where Change
displayed_status Row status and note read running once a pane is open.
sorted_agents Ranks on the displayed status, so the row doesn't sit in the waking band while reading running.
attach_session Clears a settled wake op and its watch — a pane opening proves the wake landed, and it stops the 1.5s watch tick polling that environment for up to WAKE_PATIENCE about an agent already taking keystrokes.

Scoped to starting only. A pane can outlive what it's attached to, and sleeping/crashed/failed/deleting alongside a live pane is news the user needs, not latency to paper over. Sleep and delete ops are untouched — neither is proven by an attach.

Testing

1126 pass, 0 clippy errors. Four new tests:

  • an agent with a pane open reads running (fails with starting if the override is removed — verified)
  • every non-starting status survives an attached pane
  • an ended pane stops counting as evidence
  • an in-flight sleep isn't settled by an attach

Why the override is bounded

An unbounded "pane open ⇒ not starting" rule would hide the case that prompted this: an agent that stays starting, routes SSH fine, and has to be deleted. Painting that green removes the only signal the user has.

So the override only covers the window the lag actually lives in. Benchmarked with 10 × railway code --claude --new (agents cleaned up after):

metric min median max
create returns 1.9s 3.6s 8.9s
status → RUNNING 5.3s 8.4s 14.2s
end-to-end (create → Claude's first reply) 10.3s 13.5s 19.3s

Status reached RUNNING before the harness answered in all 10 runs, worst case 14.2s from create — and a pane opens partway into that. STARTING_GRACE is 45s: generously clear of a slow-but-healthy boot, but bounded, so an agent still starting past it goes back to reporting what the platform says.

The decision is a pure function of (status, pane age), so the boundary is unit-tested directly rather than through a fabricated Session clock.

🤖 Generated with Claude Code

Create a new cloud agent, land in its session, and the tree still calls it
"waking" while you are typing into it. The row renders the platform's raw
status, and `sorted_agents` already documents the vocabulary: "running first,
waking next" — where the middle rank is `starting`.

That status lags routability by design. #1098 established the gap: the
platform routes a shell as soon as the container exists, while RUNNING
additionally waits on route publication, a projection hop, and a poll
interval. The launcher stopped gating attach on it and started probing the
route instead — but the tree kept rendering the value the CLI itself had
already decided not to trust.

An attached, unfinished pane is direct evidence the agent is up: there is a
shell running on it. So believe the pane over the projection.

Scoped to `starting` only. A pane can outlive what it is attached to, and
sleeping/crashed/failed/deleting alongside a live pane is news the user needs
rather than latency to paper over.

Three places, so display and state agree:

- the row's status and note read `running` once a pane is open;
- `sorted_agents` ranks on the displayed status, so the row does not sit in
  the waking band while reading `running`;
- `attach_session` clears a settled wake op and its watch. A pane opening
  proves the wake landed, and it stops the 1.5s watch tick polling that
  environment for up to WAKE_PATIENCE about an agent already taking
  keystrokes. Sleep and delete are untouched — neither is proven by an attach.

Known limitation, measured after the fact: a 10-agent benchmark put the
routine lag at a few seconds, closing before the session is usable (status
reached RUNNING before the harness answered in all 10 runs). The case that
prompted this was an agent that stayed `starting` and had to be deleted — and
this change would render that one `running` too, hiding the only signal
something was wrong. A follow-up should bound the override to a short grace
window after attach and surface a persistent `starting` explicitly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codyde codyde added the release/patch Author patch release label Aug 14, 2026
The override shipped in the previous commit was unbounded: any open pane made
a `starting` agent read `running`, forever. That hides the case that prompted
the fix — an agent that stays `starting`, routes SSH fine, and has to be
deleted. The row would have painted it green and removed the only signal the
user had.

Bound it to the window the lag actually lives in. Measured over ten
`railway code --claude --new` runs, status reached RUNNING 5.3–14.2s after
create, before the harness answered every time. 45s from pane open is
generously past that, so a slow-but-healthy boot never flickers into looking
stuck, while an agent still `starting` past it goes back to reporting what the
platform says.

`agents_with_live_panes` now carries how long each pane has been open rather
than just which agents have one, via a new `Session::open_for`. The decision
stays a pure function of (status, pane age), so the boundary is unit-tested
directly instead of through a fabricated Session clock.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codyde
codyde merged commit 6e8ce66 into master Aug 15, 2026
7 checks passed
@codyde
codyde deleted the fix/agent-waking-with-open-pane branch August 15, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/patch Author patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant