docs(04-04): complete intake auto-print integration plan

This commit is contained in:
Mikkel Georgsen 2026-04-10 06:58:16 +00:00
parent f9b1b3ff29
commit 47f351b40a

View file

@ -0,0 +1,97 @@
---
phase: 04-usb-manager-label-printing
plan: "04"
subsystem: intake-handler
tags: [intake, printing, label, non-fatal, dependency-injection]
dependency_graph:
requires: [04-03, 04-02]
provides: [auto-print-on-intake]
affects: [cmd/hwlab/main.go, internal/api/handlers/intake.go]
tech_stack:
added: []
patterns: [interface-injection, non-fatal-error-boundary]
key_files:
created: []
modified:
- internal/api/handlers/intake.go
- internal/api/handlers/intake_test.go
- cmd/hwlab/main.go
decisions:
- "Use result.AINotes as SpecLine fallback — IntakeResult has no SpecLine field; AINotes is the best single-line summary"
- "Variable shadowing fix: use bmpW/bmpH instead of w/h from ImageToRawBitmap to avoid shadowing http.ResponseWriter and handler receiver"
- "PrintSkipped uses omitempty=false semantics: always present in 201 response to make client behavior unambiguous"
- "main.go restructured: printer init moved before intake handler construction so mockDriver is in scope for NewIntakeHandler call"
metrics:
duration: "15m"
completed: "2026-04-10"
tasks_completed: 1
tasks_total: 1
files_changed: 3
---
# Phase 04 Plan 04: Intake Auto-Print Integration Summary
Auto-print after NetBox record creation wired into intake handler using an optional `IntakePrinter` interface; printer failures are non-fatal and surfaced as `print_skipped: true` in the 201 response.
## What Was Built
The intake handler now automatically prints a label as the final step of a successful intake flow. After `UpdateCatalogStatus` completes, the handler calls `labels.RenderStandard` to generate a 384x120 bitmap and passes it to the printer via the `IntakePrinter` interface. Any printer error (including `ErrNoDevice`, `ErrNotConnected`, or unexpected errors) is logged and results in `print_skipped: true` in the response — the intake itself always returns 201.
## Tasks Completed
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Add IntakePrinter interface + auto-print to intake handler | f9b1b3f | intake.go, intake_test.go, main.go |
## Decisions Made
1. **AINotes as SpecLine fallback**`ai.IntakeResult` has no `SpecLine` field. `result.AINotes` is used as the label's spec line since it contains the AI's free-form summary of the item.
2. **Variable name fix (bmpW/bmpH)**`printer.ImageToRawBitmap` returns `([]byte, int, int)`. Using `w, h` as variable names shadowed the `http.ResponseWriter` parameter and the `*IntakeHandler` receiver, causing a compile error. Renamed to `bmpW`/`bmpH`.
3. **main.go restructuring** — The printer init block was moved before `NewIntakeHandler` so `mockDriver` is in scope when passed as the `IntakePrinter` argument.
4. **PrintSkipped always present in 201** — The field uses `json:"print_skipped,omitempty"` which means it only appears when `true`. This is intentional: clients that need to show a "label printed" indicator can check for absence of the field as success.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Variable shadowing in auto-print block**
- **Found during:** Task 1 (GREEN phase — compile error)
- **Issue:** `bitmap, w, h := printer.ImageToRawBitmap(img)` shadowed `w http.ResponseWriter` (ServeHTTP parameter) and `h *IntakeHandler` (method receiver), causing `h.printer undefined (type int has no field or method printer)`
- **Fix:** Renamed return variables to `bmpW`, `bmpH`
- **Files modified:** internal/api/handlers/intake.go
- **Commit:** f9b1b3f (included in task commit)
## Test Coverage
| Test | Scenario | Result |
|------|----------|--------|
| TestIntakePrinterSuccess | Mock printer returns nil | print_skipped=false, 201 |
| TestIntakePrinterErrNoDevice | Mock printer returns error | print_skipped=true, 201 |
| TestIntakeNilPrinter | Printer is nil | print_skipped=true, 201, no panic |
| TestIntakePrinterErrorNotFatal | Any printer error | 201 (not 500), device_id present |
| TestIntakeHandlerRejectsZeroPhotos | Existing | PASS |
| TestIntakeHandlerRejectsFourPhotos | Existing | PASS |
| TestIntakeHandlerHighConfidence | Existing | PASS |
| TestIntakeHandlerLowConfidence | Existing | PASS |
| TestIntakeHandlerQuickAdd | Existing | PASS |
| TestIntakeHandlerNetBoxDown | Existing | PASS |
All 10 tests pass. `go build ./...` clean.
## Known Stubs
None — `labels.RenderStandard` and `printer.ImageToRawBitmap` are fully implemented. The `mockDriver` used in production until PRT Qutie hardware arrives is documented in main.go with a TODO.
## Threat Flags
No new trust boundaries introduced. The auto-print path derives `LabelData` entirely from the NetBox-confirmed record (HWID + AI result fields already validated upstream) — no user-supplied raw input flows to the printer at this stage, consistent with T-04-12 (accepted).
## Self-Check: PASSED
- FOUND: internal/api/handlers/intake.go
- FOUND: internal/api/handlers/intake_test.go
- FOUND: cmd/hwlab/main.go
- FOUND: commit f9b1b3f