fix: make beetroot modes/doctor tell the truth across environments (#179, #191, #164) - #278
Merged
Merged
Conversation
#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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three diagnostics-truthfulness fixes so
beetroot modes/beetroot doctorstop endorsing hosts that can't actually boot the backend they report as healthy. Closes #179, #191, #164.#179 —
modesreported redroid host/auto "supported" with a stopped daemonsurvey()probed Docker withshutil.which(docker_bin)(CLI presence only). A host with kernel binder ready butdockerdstopped (freshly-rebooted runner, rootless without a running user daemon, socket-less container) printed a falsesupported, and the subsequentupfailed atdocker compose up.docker infoprobe out ofbuilder.pyintocapabilities.pyas a public, single-sourceddocker_daemon_responsive()(builder now reuses it; nocapabilities→builderimport cycle —capabilitiesonly importshostcheck/settings/vm.qemu).classify_modesgains a puredocker_daemon: bool;_redroid_hostreturnssupportedonly when binder is ready and the CLI is present and the daemon responds. CLI-present-but-daemon-down →needs-setupwith a "start the Docker daemon" remedy.survey()populates the flag via the shared helper, short-circuiting the probe when the CLI is absent.#191 —
doctorreportedvm.accel: passwith QEMU/artifacts absentOn the canonical binderless setup (before
apt-get install qemu-system-x86+beetroot build --vm-kernel), doctor printedvm.accel: passwhile the VM physically couldn't boot — contradictingbeetroot modes(needs-setup) and offering no remedy.VmDeviceBackend.health()now emits avm.qemurow (shutil.which(settings.qemu_bin); the fail reason reuses the sharedcapabilities._QEMU_INSTALLstring so doctor and modes agree) and avm.artifactsrow (resolves kernel + rootfs via the existing_resolve_artifact; theQemuLaunchErrormessage already names the missing artifact and points atbeetroot build --vm-kernel).vm.accelis no longer the sole readiness signal.#164 — vm
doctorfalse-failed a healthy micro-VMThe vm health path inherited the USB-oriented
adb.serialrow (_check_adb_serial_listed), which needs a serial to already be listed — but a TCP adb target only appears after an explicitadb connect, so doctor false-failed a fully-booted VM from a fresh adb-server lifetime (and exited non-zero, breaking scripts gating onbeetroot doctor).health()now issuesadb.connect = api._check_adb_connect(self.adb_address)(connect-then-verify, mirroring the redroid path) instead ofadb.serial. The Frida/Magisk rows remain intentionally absent (network-isolated guest, plain redroid).Tests
test_capabilities.py:classify_modesfor binder-ready × {daemon up, daemon down}; threesurvey()integration tests proving the daemon probe is threaded into the verdict (live→supported, dead→needs-setup+remedy, CLI-absent→probe skipped); the real-probedocker_daemon_responsivetests moved here fromtest_builder.py.test_vm_backend.py: happy path (qemu+artifacts+adb all pass, asserting the connect row targetsbackend.adb_addressand thatadb.serialis gone); qemu-absent →vm.qemufail with the install remedy; artifacts-absent →vm.artifactsfail with the build hint; adb-absent → connect row skips.test_builder.py: updated to patchcapabilities.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