Files
parking_solution/wiki/decisions/vision-service.md
T
julian ee28b7302f docs(wiki): decide vision service packaging — apps/vision/ in the monorepo
Settle WHERE the host-side ANPR service lives and how it joins the build: in this
monorepo at apps/vision/ (not a separate repo), still a separate OS process called
over localhost HTTP, wired into the Turbo graph via a thin package.json shim whose
scripts shell to Python tooling (uv/uvicorn/ruff/pytest). Co-located source honors the
vision-service runtime+license isolation decision (AGPL reach is a linking boundary,
not a folder); the fast-alpr MIT baseline removes most of the split-repo pressure
anyway. New page vision-service-packaging; updates vision-service, opencv-anpr-service,
the CLAUDE.md layout, index, log. Not built yet — packaging decision only.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
2026-06-19 14:25:31 +02:00

70 lines
4.2 KiB
Markdown

---
type: decision
tags: [parking, decisions, vision, anpr, anti-fraud]
sources: []
updated: 2026-06-15
status: open
---
# Decision: Host-side Vision Service (ANPR + vehicle verification)
Taken 2026-06-15, as part of the business-layer build ([[session-model]]).
## Decisions
1. **Build a host-side vision service** ([[opencv-anpr-service]]) that does ANPR (plate → identity)
**and** vehicle-attribute verification (anti-spoofing witness) on snapshots from ordinary
Hikvision/Dahua cameras.
2. **It replaces the dedicated edge-AI [[lpr-camera]]** as the recognition path: ordinary IP cam →
snapshot (`Snapshot.bytes`, already pulled by the camera driver) → vision service → plate +
vehicle. Removes the special LPR camera from the [[bom]] as a requirement (still allowed as an
option).
3. **Deployment: a separate local Python/OpenCV microservice** on the appliance, called over
**localhost HTTP** by the Node backend. Fully offline ([[offline-first]]); its own process and
failure domain; the host falls back to the ticket path if it's unavailable. **Source lives in THIS
monorepo at `apps/vision/`, wired into Turbo via a thin `package.json` shim** — separate *process*,
co-located *source*; see [[vision-service-packaging]].
4. **Licensing exception:** AGPL components (e.g. YOLO plate/vehicle models, OpenALPR) are
**permitted inside this service only**, because it's a separate process not linked into the app —
the app stays strictly MIT/Apache/BSD. Amends [[standing-decisions]].
5. **Recognition is advisory, evidence is authoritative.** A read never single-handedly authorizes
a paid/access barrier open; it flags for [[reconciliation]] and attaches (with the source image)
to the signed [[append-only-event-chain]] entry. Low confidence → fallback, never strand a car
([[fail-state-safety]]).
## Why
- **Replace vs. edge-AI camera:** host-side recognition on cheap IP cams shifts cost from per-lane
smart cameras to one compute box + our software; gives us the raw image for the second job below.
- **Vehicle verification is the real prize (user-driven, 2026-06-15):** plate-only ANPR can't catch
a **printed/spoofed plate on a different car**. Extracting vehicle attributes/fingerprint lets the
system reconcile *the car*, not just the number — directly filling the independent-witness gap the
[[append-only-event-chain]] calls out as unbuilt.
- **Separate-process + AGPL-scoped** keeps the app's permissive-license guarantee intact while not
crippling accuracy (the strict permissive-only ANPR path is markedly weaker — that tradeoff was
weighed and the scoped exception chosen).
## Rejected / alternatives
- **Strict permissive-only ANPR in-app** — license-clean but weaker accuracy and more build; the
separate-process AGPL exception was chosen instead.
- **Keep the edge-AI LPR camera as primary** — viable fallback if host-side accuracy disappoints;
not chosen now, kept on the table in [[opencv-anpr-service]].
- **Embed OpenCV in Node** (opencv4nodejs/WASM) — rejected: native-build pain, weaker model
ecosystem, no process isolation, shares the app's failure + license surface.
## Open / next
- Recognizer selection: **fast-alpr (MIT, YOLOv9 detector + CCT OCR on ONNX Runtime) is the evaluated
baseline** as of 2026-06-19 — fits this decision's shape (separate offline localhost process,
swappable) and is permissive end-to-end, so the ANPR path may not need the AGPL exception (pending a
model-**weight-provenance** check). Plate-only: it does NOT cover the vehicle-verification job. Open:
the provenance check + an accuracy benchmark on real Albanian plates (default global vs. the 40+
country EU model). See [[opencv-anpr-service]] "Recognizer evaluation".
- Vehicle-model selection + fingerprint method + anomaly threshold (the Job-2 anti-spoofing stage,
still ours to build on the same ONNX runtime) ([[opencv-anpr-service]]).
- Appliance compute footprint (CPU vs. small GPU/NPU) — [[bom]] / [[open-questions]].
- Service API + the Node-side adapter; per-camera opt-in wiring.
- Reconciliation logic that consumes plate+vehicle witness vs. commanded opens (still unbuilt — see
[[append-only-event-chain]], [[reconciliation]]).