Skip to content

fix: make beetroot modes/doctor tell the truth across environments (#179, #191, #164) - #278

Merged
Xiddoc merged 1 commit into
masterfrom
claude/beetroot-sweep-optimize-jp5vdq
Jul 1, 2026
Merged

fix: make beetroot modes/doctor tell the truth across environments (#179, #191, #164)#278
Xiddoc merged 1 commit into
masterfrom
claude/beetroot-sweep-optimize-jp5vdq

Conversation

@Xiddoc

@Xiddoc Xiddoc commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Three diagnostics-truthfulness fixes so beetroot modes / beetroot doctor stop endorsing hosts that can't actually boot the backend they report as healthy. Closes #179, #191, #164.

#179modes reported redroid host/auto "supported" with a stopped daemon

survey() probed Docker with shutil.which(docker_bin) (CLI presence only). A host with kernel binder ready but dockerd stopped (freshly-rebooted runner, rootless without a running user daemon, socket-less container) printed a false supported, and the subsequent up failed at docker compose up.

  • Relocated the docker info probe out of builder.py into capabilities.py as a public, single-sourced docker_daemon_responsive() (builder now reuses it; no capabilitiesbuilder import cycle — capabilities only imports hostcheck/settings/vm.qemu).
  • classify_modes gains a pure docker_daemon: bool; _redroid_host returns supported only when binder is ready and the CLI is present and the daemon responds. CLI-present-but-daemon-down → needs-setup with a "start the Docker daemon" remedy.
  • survey() populates the flag via the shared helper, short-circuiting the probe when the CLI is absent.

#191doctor reported vm.accel: pass with QEMU/artifacts absent

On the canonical binderless setup (before apt-get install qemu-system-x86 + beetroot build --vm-kernel), doctor printed vm.accel: pass while the VM physically couldn't boot — contradicting beetroot modes (needs-setup) and offering no remedy.

  • VmDeviceBackend.health() now emits a vm.qemu row (shutil.which(settings.qemu_bin); the fail reason reuses the shared capabilities._QEMU_INSTALL string so doctor and modes agree) and a vm.artifacts row (resolves kernel + rootfs via the existing _resolve_artifact; the QemuLaunchError message already names the missing artifact and points at beetroot build --vm-kernel). vm.accel is no longer the sole readiness signal.

#164 — vm doctor false-failed a healthy micro-VM

The vm health path inherited the USB-oriented adb.serial row (_check_adb_serial_listed), which needs a serial to already be listed — but a TCP adb target only appears after an explicit adb connect, so doctor false-failed a fully-booted VM from a fresh adb-server lifetime (and exited non-zero, breaking scripts gating on beetroot doctor).

  • health() now issues adb.connect = api._check_adb_connect(self.adb_address) (connect-then-verify, mirroring the redroid path) instead of adb.serial. The Frida/Magisk rows remain intentionally absent (network-isolated guest, plain redroid).

Tests

  • test_capabilities.py: classify_modes for binder-ready × {daemon up, daemon down}; three survey() integration tests proving the daemon probe is threaded into the verdict (live→supported, dead→needs-setup+remedy, CLI-absent→probe skipped); the real-probe docker_daemon_responsive tests moved here from test_builder.py.
  • test_vm_backend.py: happy path (qemu+artifacts+adb all pass, asserting the connect row targets backend.adb_address and that adb.serial is gone); qemu-absent → vm.qemu fail with the install remedy; artifacts-absent → vm.artifacts fail with the build hint; adb-absent → connect row skips.
  • test_builder.py: updated to patch capabilities.docker_daemon_responsive (one patch covers every relocated call site).

Docs (cli.md, sandbox-quickstart, running-in-ci, binder-and-modes, the vm design log) updated to describe the new doctor rows truthfully. Full gate green locally: ruff, mypy --strict (src + tests), pytest 1983 passed at 100% line+branch coverage.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WmChW67jv2BaPk1a8HreHU


Generated by Claude Code

#179, #191, #164)

Three diagnostics-truthfulness fixes so `modes`/`doctor` stop endorsing hosts
that can't actually boot the backend they report as healthy.

#179 — `beetroot modes` reported redroid host/auto as "supported" whenever the
Docker CLI was on PATH, without checking daemon liveness, so a stopped dockerd
(freshly-rebooted runner, rootless w/o a running user daemon) printed a false
"supported" and the subsequent `up` failed at `docker compose up`. The
`docker info` probe (`_docker_daemon_responsive`) is relocated out of builder.py
into capabilities.py as a public `docker_daemon_responsive()` (single-sourced;
builder now reuses it, no capabilities->builder import cycle). `classify_modes`
gains a pure `docker_daemon: bool` and `_redroid_host` returns "supported" only
when binder is ready AND the CLI is present AND the daemon responds; a
CLI-present-but-daemon-down host now reports "needs-setup" with a "start the
Docker daemon" remedy.

#191 — `beetroot doctor` emitted `vm.accel: pass` even when qemu-system-x86_64
was absent from PATH or the guest kernel/rootfs had never been built, endorsing
a doomed config. `VmDeviceBackend.health()` now emits `vm.qemu` (QEMU binary on
PATH — reuses the shared `capabilities._QEMU_INSTALL` remedy) and `vm.artifacts`
(resolves kernel+rootfs via `_resolve_artifact`) rows, so `vm.accel` is no
longer the sole boot-readiness signal.

#164 — the vm health path inherited the USB-oriented `adb.serial` row
(`_check_adb_serial_listed`), which needs a serial to already be listed; a TCP
adb target only appears after an explicit `adb connect`, so doctor false-failed
a healthy micro-VM from a fresh adb-server lifetime (and exited non-zero).
`health()` now issues `adb.connect = _check_adb_connect(self.adb_address)`
(connect-then-verify, mirroring the redroid path) instead of `adb.serial`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmChW67jv2BaPk1a8HreHU
@Xiddoc
Xiddoc merged commit 8fdd91e into master Jul 1, 2026
17 checks passed
@Xiddoc
Xiddoc deleted the claude/beetroot-sweep-optimize-jp5vdq branch July 1, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants