Repository navigation
[compass] Fix: a detached seat can't be reconnected by the button its message names, and agents aren't told capture is down - #42
Conversation
…ames, and agents aren't told capture is down A seat that signed in through Sign in (Windows' credential dialog) lost its viewer (on 10-13, extended reason 17: the seat's display driver failed). Its message said to press Reconnect, but ReconnectAsync reset the prompt to the start option, so every press tried automatic sign-in and failed with 2055, reporting "The seat could not start" while the seat still ran. Agents saw only state detached, and a capture error blaming a hidden or minimized viewer. - The daemon remembers that the running seat signed in with the password; Reconnect then asks for it again, and display reconnects stay refused even after a host recovery reset the prompt. Cleared when the seat stops or disappears. Agent-reachable starts never raise the dialog. - detached carries its message in lastError (seat_status, anode status, anode start), saying what is down and the user's reconnect step; seat_display refuses while the viewer is disconnected. - The seat host's capture error says when its session is disconnected (WTSConnectState). - Extended disconnect reasons 15-18, 23 and 24 are named instead of the control's generic text. - Quick checks: viewer sign-in updated; daemon detached viewer, rdp extended reasons and capture unavailable message added. TROUBLESHOOTING, PROTOCOL and CHANGELOG updated. Implemented by Codex (gpt-6-astra) from the fixer's brief; reviewed and tested by the fixer. Fixes B-038 (C:\DEV\Compass\ANODE-BUGS.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a39612181
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (state is "error" or "logon-error" or "detached") _lastError = message; | ||
| else if (state == "ready") _lastError = string.Empty; |
There was a problem hiding this comment.
Clear the detached error after a successful stop
When a detached seat is stopped successfully, StopSeatAsync transitions through stopping to stopped, but neither state clears _lastError. Because this change now stores every detached message there, subsequent status responses remain state: "stopped" while lastError still claims that the seat and its programs are running and instructs the user to reconnect. Clear the error on a successful stopped transition (or replace it with an appropriate stopped-state value).
Useful? React with 👍 / 👎.
Codex review (P2): the new detached guard in DisplayAsync also refused method reconnect, which is how the seat host returns the viewer to the old display after a failed display reconnect, and how an automatically signed-in seat comes back. While the viewer is disconnected, refuse a live change (it can't work) and any change on a seat that signed in with the password (the user must reconnect it), but let an automatic seat's reconnect through, as before this PR. The detached check now covers both, and two more mutations are caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…6-10-13-detached-seat # Conflicts: # CHANGELOG.md
Codex connector review (P2): a detached seat stopped through Stop kept its detached message in lastError, so status said "stopped" while lastError still said the seat was running and how to reconnect it. Moving from detached to stopping now clears it; a failed stop still records its own error. The detached check stops a detached seat and requires an empty lastError. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review (fresh Claude subagent, P3): a failed display reconnect, or a lost host connection, can set detached after Stop has moved to stopping, so the seat would end stopped with the reconnect advice still in lastError. Stop's success path now clears it when the state it ends is detached. The check also asserts the seat is detached before it stops it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Report
B-038 in
C:\DEV\Compass\ANODE-BUGS.md(filed 2026-10-13 by compass-play-upload): on 0.11.2,seat_statussaiddetached,seat_screenshotandseat_capabilitiesreported "The seat's display is unavailable for capture. RDP may have suspended rendering while its viewer was hidden or minimized...", Chrome's page had no controls inseat_observe, andseat_displayrefused. The Play Console upload stopped there.What happened (from the daemon's own log,
%LOCALAPPDATA%\Packages\OpenAI.Codex_…\LocalCache\Local\Anode\anode.log)--sign-in; automatic sign-in failed (2055, a PIN account); the user pressed Sign in…, entered the password, and the seat came up in session 2.ERRINFO_CLOSE_STACK_ON_DRIVER_FAILURE, "The display driver in the remote session was unable to complete all the tasks required for startup". Anode logged the control's generic text instead ("The administrator has ended the session... A network problem occurred") and "Press Reconnect".state: detached(the message reaches the viewer and log, notlastError) and a capture error pointing at a hidden viewer.Root cause
ReconnectAsyncset_promptForCredentials = promptForCredentials || _options.PromptForCredentials, so the Reconnect button forgot that the running seat could only sign in through the credential dialog.DisplayAsyncalready assumes such a seat needs the password for every new connection, but read the same per-attempt flag, whichStartSeatAsyncalso resets. Thedetachedmessage was the one place that said what to do, and agents never saw it.Fix
_seatSignedInWithPassword, set at login, cleared when the seat stops or disappears). Reconnect asks for the password again for such a seat;DisplayAsynckeeps refusing a viewer reconnect for it even after a host recovery reset the prompt. Only the viewer's buttons callReconnectAsync;StartSeatAsyncand every agent-reachable path are unchanged and never raise the dialog.detachedsays what is down and the next step, inlastErrortoo (soseat_status,anode statusandanode startshow it): screenshots fail, browser pages show no controls, the display can't change, programs and jobs keep running; for a password seat "the user opens the viewer, presses Reconnect and enters their Windows password; an agent can't do this step".seat_displaywhile the viewer is disconnected: a live change is refused with that message, and so is any change on a password seat (before, it advisedanode quit, which closes the seat's programs). A reconnect on an automatically signed-in seat still goes through, since that is how it comes back, including the seat host's return to the old display after a failed one.WTSQuerySessionInformation/WTSConnectStatein the seat host), pointing atseat_status; otherwise today's text is unchanged.quit(15:30:34 "Creating the seat..." thenE_FAIL); [compass] Fix: anode quit leaves Anode running while the sign-in dialog is open #34's_quittingguard covers that.Docs: TROUBLESHOOTING gains "The seat is detached and screenshots fail" (and a pointer from "Hidden viewer capture fails", and a line in "It asks for a password every time"); PROTOCOL notes
detachedfillslastError; CHANGELOG entry.How it was tested
logs/codex/briefs/2026-10-13-anode-fixer-B-038.md); I read the whole diff and rewrote the CHANGELOG entry.selftest --quick107/107 (104 +daemon detached viewer,rdp extended reasons,capture unavailable message;viewer sign-inupdated: its old assertion that a plain Reconnect after Sign in drops the prompt encoded this bug).scratch/compass-anode-fixer/evidence/2026-10-13-b038-mutations*.txt): 12 of 12 caught: Reconnect forgetting the sign-in, login not recording it,detachedwithoutlastError, Stop or a vanished seat keeping it, the display check reading only the attempt's prompt, the detached guard removed, blocking an automatic seat's reconnect, or letting a live change through, the message always saying "press Reconnect", extended reason 17 unexplained, and a stop keeping the detached advice.f636b28; the check covers it.8a7f90bfound nothing; the GitHub Codex connector found one P2: a detached seat stopped through Stop kept the "still running, press Reconnect" advice inlastError. Fixed in59326e0; the check covers it.59326e0found nothing; a fresh Claude subagent found no P1/P2 and one P3 race (a failed display reconnect or lost host connection settingdetachedwhile a stop runs would leave the advice instopped). Fixed in751152a, with an extra assertion in the check; the subagent confirmed the delta (merge log).8a7f90b, final head751152a): FOCUS test command (scripts/build.ps1 -QuickTest -OutputDirectory artifacts\pkg-build) passes, Releaseselftest --quick108/108 (Debug and Release),check-docs.ps1consistent.start,quit, lease oranode-controlcall.Needs a manual check in a real seat
anode statusshows the newlastError;seat_screenshotnames the disconnected viewer; Reconnect opens the credential dialog, and after the password the seat isreadywith its programs still open.WTSDisconnectedwhile its viewer is gone; if Windows reports otherwise, the old message appears (theseat_statuspart still holds).🤖 Generated with Claude Code