Skip to content

(session-state): one owner per remote row — local-pty while attached, the adapter otherwise - #275

Merged
devsuitup merged 1 commit into
mainfrom
fix/273-remote-row-ownership
Sep 12, 2026
Merged

devsuitup merged 1 commit into
mainfrom
fix/273-remote-row-ownership

Conversation

@devsuitup

Copy link
Copy Markdown
Owner

Closes #273. Measured on v0.0.76 with the activity trace (local note .work-files/switchboard/trace-2026-09-12.md): 53 painted response-ready flickers in 2 min 23 s on an attached remote session, and a 19.96 s / 20.05 s busy tail after the remote process died. Both reproduced on current main by replay tests before the fix (RED quoted in the test file names' first run).

Root cause

Two writers on one row with no arbitration on the attached fact #267 already carried: markRemoteBusy / decayRemoteBusy wrote the shared Maps through setActivity whether or not the row was attached, and projectRemoteState repainted the row from the adapter's private snapshot on every render; setRemoteAttached only toggled a field, so after pty.exit busy could only clear through the 20 s decay.

Fix

  • Ownership rule (documented in session-state.md): attached remote row → local-pty path (OSC busy/idle, response-ready allowed); unattached → the remote adapter (watch, decay, never response-ready). Watch/seed/decay are no-ops while attached; the adapter's projection does not repaint an attached row.
  • Detach handoff: cancel the decay timer, clear busy in the adapter state and the Maps at once, floor the seed window (remoteSeedFloors) so a stale remoteActiveAt cannot re-arm busy.
  • clearUnread(sessionId, via); clearNotifications passes its via (the via: undefined seen in the trace).

Proof

  • test/remote-row-ownership.test.js: symptom 1 (watch must not delete response-ready while attached) and symptom 2 (busy clears at the handoff instant) — both RED before, GREEN after.
  • Mutations: stripping the three attached guards → symptom 1 red; disabling the handoff block → symptom 2 red. Reverted.
  • task check: 1277 + 119 pass, 0 fail, pre-existing skips.

Known side effect, stated in the doc: while a remote row is attached, agentsBusy / is-alive from the adapter are not repainted until detach (the local-pty path owns the row). Not verified live yet — next debug session.

… the adapter otherwise

Closes #273. Measured on v0.0.76: 53 response-ready flickers in 2 min on an
attached remote session, and a 20 s busy tail after the process died. The
remote adapter's watch, seed and decay writers now no-op while the row is
attached, and the adapter's projection does not repaint an attached row; on
detach the adapter takes over from the current state, cancels the decay,
clears busy at once and floors the seed window so a stale remoteActiveAt
cannot re-arm it. clearUnread carries its via.
@devsuitup
devsuitup merged commit c783927 into main Sep 12, 2026
10 checks passed
@devsuitup
devsuitup deleted the fix/273-remote-row-ownership branch September 12, 2026 11:43
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.

(session-state): attached remote row is written by two owners — response-ready flap and a 20 s busy tail after exit

1 participant