Skip to content

Add comicbox doctor: offline dependency and config health report - #230

Merged
ajslater merged 1 commit into
developfrom
feature/doctor
Oct 4, 2026
Merged

ajslater merged 1 commit into
developfrom
feature/doctor

Conversation

@ajslater

@ajslater ajslater commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Summary

comicbox doctor reports everything outside comicbox's own code that it depends on. Each row says OK, WARN, OFF (optional, not set up), MISSING, WRONG VERSION, MISCONFIGURED or ERROR, with a one-line fix for anything that isn't OK. Any failure exits 1, so comicbox doctor -q (problems only) doubles as a Docker / CI health check.

This is PR 1 of the plan in tasks/doctor-command-plan.md: everything offline. The live --online probe is the stacked PR that follows.

  • Archives: CBZ (zlib, zipremove's remove/repack, zip codecs), CBR (extracts the existing _rar_probe.rar; a tool that passes rarfile's check but can't extract is MISCONFIGURED, no tool is MISSING, with a brew/apt/dnf hint), CB7, CBT, PDF (absent is OFF; installed but broken shows the real import error).
  • Images: a Pillow codec for every page extension (IMAGE_EXTS, derived from comicbox), and an imagehash smoke test.
  • Config: the --config file and the user config, validation exactly as a run does it, unknown keys in files and COMICBOX_* env vars (with "did you mean"), legacy env vars, COMICBOX_GENERAL__CONFIG.
  • Online: per-source credentials, named by the layer that supplied each field (--auth, env var, config file, keyring) and never by value. Also the keyring backend, the cache dir, Comic Vine's hourly budget read from the bucket file, and proxy env vars by name.
  • Python packages: pins from comicbox's own metadata via packaging, which is now a runtime dependency.

doctor is sniffed as argv[1] before the Runner is built, as picopt does, so a broken config is reported rather than raised. Trailing args go through the normal parser (-c, --auth, --cache-dir mean what they mean in a run). doctor --help says comicbox doctor. A comic named doctor is reached as ./doctor.

Where this departs from the plan

  • Unknown keys inside a per_source block are a WARN, not MISCONFIGURED. The plan expected the template to reject them. It doesn't: confuse's MappingTemplate type-checks the keys it knows and silently drops the rest, so a typo there validates and does nothing. The doctor walks each block against _PER_SOURCE_TUNING_TEMPLATE.
  • Credential provenance is worked out in the doctor, not recorded on OnlineSourceCredentials. _build_auth_settings only ever sees the validated AttrDict, not a confuse view. And _add_env mounts env vars as an anonymous source, so the env layer is named from the variable itself.
  • Extras aren't double-counted. The packages section checks base requirements; the PDF row owns comicbox-pdffile's pin.
  • Zero counts are left out of the summary line (✓ 0 problems · 1 warning · 2 off), so a clean -q run prints exactly ✓ 0 problems.

Test plan

  • make fix, make lint (ruff, basedpyright, complexipy, radon, vulture, codespell), make ty
  • make test: 2372 passed, 1 skipped. New tests cover every RAR state, broken py7zr/pdffile/imagehash imports, bad YAML, unknown keys and sources, legacy env vars, every provenance layer, no socket opened, no secret rendered (plus a redaction backstop for crash messages), colored and theme: none rendering, -q, CLI dispatch, ./doctor, and the lazy-import contract.
  • Ran comicbox doctor, -q, -c with good, bad and missing files, and --help by hand.

Pre-existing, not from this PR: a coverage-enabled run shows 12 ResourceWarning: unclosed database warnings on test_metron_id_attribute_fallback / test_write_api. They show up identically with the doctor tests deselected.

🤖 Generated with Claude Code

`comicbox doctor` lists everything outside comicbox's own code that it
depends on and says per item whether it is OK, WARN, OFF (optional, not
set up), MISSING, WRONG VERSION, MISCONFIGURED or ERROR, with a one-line
fix for anything that isn't OK. Any failure exits 1, so `comicbox doctor
-q` (problems only) works as a Docker or CI health check.

Today each of these findings is at most one log line that scrolls past:
a RAR tool that passes rarfile's version check but can't extract, a
broken PDF extra, a skipped user config, a typo'd config key that confuse
silently drops, a legacy env var, a pin a distro package or a --no-deps
install broke.

Sections: Archives (CBZ/CBR/CB7/CBT/PDF, the RAR check extracts the
existing probe fixture), Images (Pillow codecs for every page extension,
an imagehash smoke test), Config (each config file, validation exactly as
a run does it, unknown keys in files and env vars, legacy env vars),
Online (per-source credentials named by the layer that supplied them,
never by value; keyring backend; cache dir; Comic Vine's hourly budget
from the bucket file), and Python packages (pins from comicbox's own
metadata via packaging, now a runtime dependency).

`doctor` is sniffed as argv[1] before the Runner is built, as picopt
does, so a bad config is reported rather than raised. Trailing args go
through the normal parser, so `-c`, `--auth` and `--cache-dir` mean what
they mean in a run. Every probe imports its library lazily, and a check
that crashes becomes one ERROR row without hiding the rest. Rows are
scrubbed of resolved secrets as a backstop.

Two findings while implementing, against the plan's premises:
- confuse's MappingTemplate type-checks a per_source block but drops
  keys it doesn't know, so a typo there validates and does nothing. The
  doctor walks those blocks against the template and warns.
- Credential provenance is worked out in the doctor from a freshly
  layered confuse view: _build_auth_settings only ever sees the
  validated AttrDict, and env vars are mounted as an anonymous source,
  so the env layer is named from the variable itself.

Also: build_parser(prog=...), the folded CLI shorthands move to
parser.FOLDED_DESTS (the drift test uses it), ComicboxPrint's theme
resolution becomes resolve_style_name(), and IMAGE_EXT_RE is built from
a new IMAGE_EXTS tuple.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ajslater
ajslater merged commit aea1042 into develop Oct 4, 2026
7 checks passed
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