Files
dantotsu-print/PLAN.md
2026-07-02 00:11:05 +02:00

6.5 KiB
Raw Permalink Blame History

Plan: Dantotsu Print — dp CLI (v1)

Phase 2 (Plan) artifact. Implements SPEC.md. Reviewable: read it and say "right approach" or "change X" before we break it into tasks (Phase 3).

Two tracks

  • Track A — dp CLI (Rust, the critical path below).
  • Track B — C4 print service (Python/FastAPI + brother_ql; built here, owned by the project lead — ADR-0004). Runs fully in parallel: Track A is built against a mock POST /print stub that honours the SPEC service interface, so neither track blocks the other. The mock stub is swapped for the real service at the M6 ↔ CB1 integration point — the single sync point.

Guiding principle

Render first, print early. The render is both the hard part and the only physical unknown (small-size 300 dpi legibility, font). So the first slice produces a real PNG you print and eyeball on an actual board — settling Open Q#1 before anything else is built on top of it.

Milestones (Track A) — dependency-ordered

# Milestone Depends on Verification checkpoint
M0 Skeleton — cargo crate, clap surface stubs (dp/config/doctor), DpError (thiserror), CI (test/clippy -D warnings/fmt) cargo build; dp --help lists the three commands
M1 Render slice (core) — read --file/--lines, layout (cell budget + fit math), syntect → mono PNG at 300 dpi / 90×85 mm (JetBrains Mono, no ligatures), --out to disk M0 Print card.png on the QL-1110NWB, read it at the board → settles Q#1 (font/legibility). Golden test: fixture → committed golden PNG
M2 Marking + overflowSpan::parse (L:C-L:C, repeatable, multi-line), emphasis (box/bold/highlight/underline), context window (union of marks ± --context), overflow abort + --force truncation mark + drawn cell boundary M1 Goldens: sub-line box, multi-span, overflow-abort (exit code + "N over" message)
M3 Back-linkgitctx: blame -L → introducing SHA (fallback HEAD), repo slug from remote, footer band owner/repo · path · Lab · @sha, optional --qr M1 On a real repo, footer resolves to the introducing commit; --qr opens the permalink; unit tests parse blame output
M4 Previewviuer inline (Kitty/iTerm/Ghostty/sixel) → text-grid → OS viewer; --preview; confirm [y/N]; -y skips M1 Inline in Ghostty; text-grid fallback; -y non-interactive; piped (no TTY) does not hang
M5 Config + authconfig TOML load/merge, board precedence (--board repo .dantotsu.toml user), dp config set/show; Google OAuth loopback (dp login/logout), token cache (keyring + config fallback), Bearer attach M0 Precedence unit tests; dp login completes OAuth against a test client; token cached + refreshed
M6 Emitemit multipart POST /print (PNG + board + meta JSON), non-zero exit on failure, --dry-run skips M2, M3, M5, mock stub --dry-run; against the mock stub returns printer/job; failure path exits non-zero with an actionable message
M7 Doctor + shims + packagingdoctor (config/service/board→printer/terminal caps/git/font); shim recipes (vim, jetbrains, vscode, xcode); cross-compile binaries (macOS/Linux/Windows), bundle font M4, M6 doctor flags a broken config; each shim fires dp with correct args; binaries run on all three OSes

Milestones (Track B — C4 print service)

# Milestone Depends on Verification checkpoint
CB0 Skeleton + registry — FastAPI app, board→printer registry config (board-id → {printer_ip, model, media}), GET /boards/{id} returning {printer, status} GET /boards/floor3-payments returns the mapped printer
CB1 Print pathPOST /print (multipart PNG + board + meta) → look up printer → PNG → QL raster (102 mm continuous, auto-cut) → brother_ql over the network CB0 End-to-end print of a posted PNG on a real QL-1110NWB (physical gate — needs the printer)
CB2 Auth + status + deploy — Google OIDC validation (audience + hd=theodo.com), label-out / reachability status, containerize & deploy to an internal host CB1 Bad/absent token rejected; unregistered board rejected; container runs on the internal host; dp doctor reads real status

Parallelism

Critical path: M0 → M1 → M2 → M6 → M7. Once M1 lands, M3, M4, M5 are independent and can proceed concurrently (different devs / different sessions). Track B (CB0 → CB1 → CB2) runs alongside the whole thing; Track A uses the mock stub until the M6 ↔ CB1 integration. Shim recipes (M7) can be drafted anytime; they're only tested once M1M6 work.

Risks & mitigations

ID Risk Mitigation
R1 300 dpi small-size legibility (font/size) — the physical unknown M1's early print is a gate; if 8 pt JetBrains Mono isn't legible, swap font / adjust size+budget before goldens bake it in
R2 Rust code→PNG fidelity (mono metrics, no shaping) reuse silicon's approach; pin font + syntect grammar/theme versions for deterministic goldens; ligatures-off sidesteps shaping
R3 Google OAuth loopback across 3 OSes (browser launch, localhost redirect, keychain — esp. Windows) maintained oauth2 crate; device-code fallback if loopback is awkward; keyring with config-file fallback
R4 Terminal graphics detection varies (weakest on older Windows consoles) robust fallback chain inline → text-grid → OS viewer; never hang when stdout isn't a TTY
R5 CLI↔C4 contract drift same owner; keep the mock stub authoritative to the SPEC interface and in the test suite
R6 Overflow abort annoyance if snippets often overflow clear "N over, narrow --lines" message; monitor at pilot (the F1×F3 tension is already logged in DESIGN §8)
R7 Printer IP churn — DHCP reassigns the QL's address, rotting the registry (home test and prod) give each printer a static IP / DHCP reservation; registry keys on it. In prod the service host must also route to each board's printer subnet

Definition of done (v1)

All SPEC success criteria pass; dp builds/runs on macOS+Linux+Windows; a real selection in Vim/JetBrains prints a legible, correctly-marked, back-linked card at the right board via C4; dp doctor is a working first line of support.