Skip to content

sweep: parallel batch of bug/hardening/optimization fixes (#272 #177 #192 #276 #277 #274 #246 #262 #273 #275 #267) - #280

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

sweep: parallel batch of bug/hardening/optimization fixes (#272 #177 #192 #276 #277 #274 #246 #262 #273 #275 #267)#280
Xiddoc merged 4 commits into
masterfrom
claude/beetroot-sweep-optimize-jp5vdq

Conversation

@Xiddoc

@Xiddoc Xiddoc commented Jul 1, 2026

Copy link
Copy Markdown
Owner

A batch of independent, file-disjoint fixes implemented in parallel and integrated together. Each was gated to 100% line+branch coverage in isolation; the combined tree is green (ruff, mypy --strict src+tests, pytest 2052 passed at 100% coverage).

Closes #272
Closes #177
Closes #192
Closes #276
Closes #277
Closes #274
Closes #246
Closes #262
Closes #273
Closes #275
Closes #267

cli / hostcheck

compose

downloads / builder

vm boot-cache

adb

registry / config / snapshot

docs (#267)

  • Corrected the compose.yaml denylist-default comment, the redroid-script clone path (~/.cache/beetroot/redroid-script, not /tmp/redroid), and the AGENTS.md verb list (frida-addr/install-frida/modes).

🤖 Generated with Claude Code

https://claude.ai/code/session_01WmChW67jv2BaPk1a8HreHU


Generated by Claude Code

claude added 4 commits July 1, 2026 10:31
…t, denylist default)

Part of the #267 codebase-audit cleanup (doc/comment subset):
- compose.yaml: the BEETROOT_DENYLIST_PACKAGES comment claimed the default is
  the GMS pair, but the compose default is EMPTY (`:-`) — the GMS pair is
  supplied only by the CLI's render_env, so a bare `docker compose` leaves root
  unhidden. Corrected the comment.
- AGENTS.md / docs/reference/cli.md: `beetroot build` clones redroid-script into
  the per-user cache dir (~/.cache/beetroot/redroid-script), not /tmp/redroid
  (moved in v0.4). (The v0.3→v0.4 migration doc's /tmp/redroid reference is
  historical and left intact.)
- AGENTS.md verb list: replaced the non-existent `frida` verb with the real
  `frida-addr` + `install-frida`, and added the missing `modes` verb.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmChW67jv2BaPk1a8HreHU
…i/compose/downloads/vm/registry

Landed via 7 file-disjoint clusters (each independently gated to 100%):

cli / hostcheck (#272, #177, #192, #267):
- guard every ports.well_known(...)['frida'] banner access so a Frida-less
  instance no longer KeyErrors in create/register/up/restore;
- the `up` banner no longer advertises a Frida endpoint for binder: vm;
- the strict binder: host block remedy now carries the binder: vm hint;
- `ls` shows the instance dir (not "-") for directory-backed vm rows.

compose (#276, #277):
- ps_status skips non-dict JSON lines instead of raising AttributeError;
- lifecycle ComposeError messages include a trimmed stderr tail.

downloads / builder (#274, #246, #262, #267):
- rootfs_download caps zstd output (64 GiB) and validates Content-Length;
- kernel_download streams the bzImage to disk (no full-RAM buffer);
- the default Docker static bundle sha256 is pinned (docker-27.5.1.tgz);
- the kernel source tarball is hashed in 64 KiB chunks;
- a malformed IMAGE_SIZE_MB is a preflight problem, not a crash.

vm boot-cache (#273, #267):
- the warm-boot checkpoint identity folds in the resolved accelerator
  (kvm vs tcg), so an accel flip invalidates the checkpoint;
- a warm-resume failure copies the console log to a .warm-fail sidecar
  before the cold-boot retry truncates it.

adb (#275):
- add_module raises AdbNotInstalledError when adb is absent.

registry / config / snapshot (#267):
- add_allocating bounds the port index by the cap at registration;
- mem_reservation/memswap_limit are validated against mem at load time;
- snapshot restore caps zstd decompression output.

Combined gate green: ruff, ruff format, mypy (src+tests), pytest 2052 passed
at 100% line+branch coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmChW67jv2BaPk1a8HreHU
…d_module guard doesn't depend on ambient adb

The #275 guard makes AdbDevice.add_module raise AdbNotInstalledError when adb is
absent from PATH. test_module_verb_dispatches_to_adb_device drove the real
AdbDevice without stubbing shutil.which, so it passed only where adb happens to
be installed (the dev sandbox) and failed on CI runners with no adb. Stub which
present, mirroring the sibling test_shell_dispatches_to_adb_device.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmChW67jv2BaPk1a8HreHU
…ams (CR fix)

Adversarial CR caught that the initial #276 implementation used
capture_output=True on the lifecycle verbs, which HIDES all output — a real UX
regression: `beetroot logs <name>` (non-follow, the default) printed nothing
because the logs go to stdout, and `docker compose build` ran silently.

Corrected scope:
- up / down / logs (non-follow): capture STDERR ONLY (stderr=PIPE, text=True)
  so its tail is still folded into the ComposeError, while stdout stays
  inherited and streams to the terminal (logs print; compose progress shows).
- build: reverted to inherit stdio (BuildKit progress is on stderr and the
  build log is the deliverable — capturing would run it silently); its error
  is exit-code-only, as before.
- logs -f: unchanged (already inherits stdio).

Tests updated to assert stderr=PIPE (not capture_output) for up/down/logs and
that build neither captures nor folds stderr. Full gate green at 100% coverage,
verified both with adb present and with adb stripped from PATH (CI-like).

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