Skip to content

feat: deskwright-doctor -- post-install health check with an action for every finding - #5

Open
timrichardson wants to merge 2 commits into
tristanmuzzu:mainfrom
timrichardson:feat/doctor
Open

timrichardson wants to merge 2 commits into
tristanmuzzu:mainfrom
timrichardson:feat/doctor

Conversation

@timrichardson

@timrichardson timrichardson commented Sep 15, 2026

Copy link
Copy Markdown

Implements #6 (and exists because of #3). Stacks on #4 -- the registry checks are the #3 lesson made executable -- so review after or with it; the diff collapses to just the doctor once #4 lands.

What this changes

Adds deskwright-doctor, a read-only post-install health check of the running stack. deskwright-setup --check proves the machine before anything exists; the doctor proves what is actually installed, registered and live afterwards, and every finding names its fix (install line, gsettings command, logout, restart command). It asks the live system, not the package manager: does anything own org.a11y.atspi.Registry on this session's a11y bus, does the registered command complete a real MCP initialize + tools/list handshake, is each running headless session's registry up. --self-test adds the headless self-test (private virtual monitor, safe unattended). Never changes anything, never sudos; exit 0 healthy / 1 needs action / 2 not a target.

How it was proven

  • ruff check . clean
  • python3 -m pytest -q -- 409 passed (11 new; every external read behind a seam, subprocess booby-trapped in tests)
  • Live on a real session (Ubuntu 26.04, GNOME 50.1), then dogfooded for a day against the pipx install as the daily driver: exactly one finding, and it was true (the logout Wayland still owed); no false positives. It also correctly diagnosed a pre-fix: start the AT-SPI registry on the headless session before the shell #4 headless session (registry down) and printed the exact restart command while testing.
  • DESKWRIGHT_SESSION=headless deskwright --self-test -- 18/18 via the doctor's --self-test flag (with fix: start the AT-SPI registry on the headless session before the shell #4 beneath it; 16/18 without)
  • Extension not changed.

Anything a reviewer should be suspicious of

  • _install_provenance infers version/origin from the install layout (<prefix>/lib/python*/site-packages/deskwright*.dist-info, direct_url.json) rather than asking the running server. Wheels installed by uv/poetry may land in layouts it calls "unrecognized"; the stdio handshake still covers whether the server works.
  • The MCP stdio probe speaks JSON-RPC by hand (initialize, initialized, tools/list) with a watchdog kill at 20 s. Deliberately not mcpdrv, to keep the doctor importable anywhere; if the protocol grows required fields the probe may need updating.
  • The registry probe reuses fix: start the AT-SPI registry on the headless session before the shell #4's _registry_alive shape on purpose: one explanation of that failure mode, not two.

Dog-food window complete: a day of daily-driver use, output above. Out of draft.

… had nothing to talk to

A private dbus-daemon cannot activate at-spi2-registryd: the a11y broker
routes the start through org.freedesktop.systemd1, and on a bus with no
systemd that name is the stub that answers /bin/false. So the headless
a11y bus existed but no registry ever owned org.a11y.atspi.Registry, and
ui_tree/ui_find failed with 'no application named gnome-shell' while the
user's real session, whose bus has real systemd behind it, worked.

headless.py now starts registryd itself, BEFORE the shell: order matters,
because the shell's atk-bridge stops retrying registration when no
registry answers (measured: registry-after-shell = 16/18 self-test,
registry-before-shell = 18/18).

Unit tests for the spawn/liveness/stop paths run anywhere; the live proof
is tests/test_headless_atspi.py, which fails 2/3 checks on main and
passes 3/3 here, and a cold headless self-test at 18/18.
…ix for every finding

setup --check proves the machine before anything exists; the doctor proves
the RUNNING stack after install and registration, and every finding prints
its action. Born from tristanmuzzu#3, where every static check was green and even the
self-test said 16/18 while the a11y registry quietly did not exist: a
doctor has to ask the live system (does anything own
org.a11y.atspi.Registry on this session's a11y bus? does the registered
command answer MCP on stdio?), not the package manager.

Checks: session, deps (setup's probes, same install lines), the a11y flag,
the registry, the extension (files/enabled/live), the server command
(version + provenance + a real initialize/tools/list handshake), and each
running headless session's registry. --self-test adds the headless
self-test (private virtual monitor, safe unattended). Never changes
anything, never sudos; exit 0 healthy / 1 action needed / 2 not a target.

11 in-process tests (seams only, subprocess booby-trapped); verified live
on Ubuntu 26.04: correctly demands the one logout this machine still owes,
spots a pre-fix headless session and prints the restart command.

This branch has not been deployed

No deployments
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.

1 participant