diff --git a/wiki/decisions/vision-service.md b/wiki/decisions/vision-service.md index 22d1973..d74f8db 100644 --- a/wiki/decisions/vision-service.md +++ b/wiki/decisions/vision-service.md @@ -53,8 +53,14 @@ Taken 2026-06-15, as part of the business-layer build ([[session-model]]). ## Open / next -- Recognizer + vehicle-model selection and accuracy targets; fingerprint method + anomaly - threshold ([[opencv-anpr-service]]). +- 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 diff --git a/wiki/entities/opencv-anpr-service.md b/wiki/entities/opencv-anpr-service.md index 1cfb5f1..0978858 100644 --- a/wiki/entities/opencv-anpr-service.md +++ b/wiki/entities/opencv-anpr-service.md @@ -50,8 +50,11 @@ recognition **host-side on ordinary IP-camera snapshots**, replacing the dedicat ## Licensing — scoped AGPL exception (amends the standing rule) The app is strictly **MIT/Apache/BSD** ([[technology-stack]], [[standing-decisions]]). Accurate -ANPR/vehicle models are mostly **AGPL** (YOLO/Ultralytics detectors, OpenALPR) or commercial. -Decision (2026-06-15): **allow AGPL inside this service only.** It is a **separate process**, not +ANPR/vehicle models were *assumed* to be mostly **AGPL** (Ultralytics YOLO detectors, OpenALPR) or +commercial — but the **fast-alpr stack (above) is MIT end-to-end**, so a permissive ANPR baseline now +looks achievable (pending the weight-provenance caveat). The exception below still matters for the +*strongest* models (Ultralytics YOLO) and for the vehicle-verification job. Decision (2026-06-15): +**allow AGPL inside this service only.** It is a **separate process**, not linked into the app, so its obligations don't reach the Node/React codebase; the app's permissive guarantee is preserved. Recorded as an explicit exception in [[standing-decisions]] / [[vision-service]]. @@ -61,6 +64,51 @@ guarantee is preserved. Recorded as an explicit exception in [[standing-decision network-use clause could require offering the service's source — relevant only if productised beyond the on-site appliance; flag at that point. +## Recognizer evaluation — fast-alpr is the leading baseline (2026-06-19) + +`YOLO vs OpenCV` is a **category error** — they're different pipeline layers, not competitors. ANPR +is a **pipeline**: (1) plate **detection** (find the box → YOLO-family detector), (2) plate **OCR** +(read the crop → a CRNN/CCT or OCR engine), (3) **glue** (capture/crop/deskew/draw → OpenCV, +Apache-2.0, always present). So the real choice is *which end-to-end recognizer*, and **OpenCV is +used regardless** as the image-handling toolkit. + +**Leading option: [fast-alpr](https://github.com/ankandrew/fast-alpr) (v0.4.0, 15 Mar 2026).** A thin +orchestrator over two **swappable** stages, both on **ONNX Runtime** — which matches THIS service's +decided architecture (separate localhost Python process, offline, swappable behind an interface) +almost exactly: + +| Stage | Default model | Library | License | +| --- | --- | --- | --- | +| Plate detection | `yolo-v9-t-384-license-plate-end2end` | [open-image-models](https://github.com/ankandrew/open-image-models) | MIT | +| Plate OCR | `cct-xs-v2-global-model` | [fast-plate-ocr](https://github.com/ankandrew/fast-plate-ocr) | MIT | + +- **MIT top-to-bottom** (library *and* the published model weights), one maintainer (ankandrew) across + all three repos. **The detector is open-image-models' own YOLOv9 ONNX export — NOT the Ultralytics + AGPL package** — so fast-alpr is a **permissive baseline that may not even need the scoped AGPL + exception** below. ⚠️ **Caveat (verify before relying on it):** a repo's LICENSE covers its *code*; + redistributed model *weights* can carry separate provenance (YOLOv9 upstream is GPL-3.0; Ultralytics + YOLO is AGPL). Confirm the weight training/provenance (model card) before treating "MIT weights" as + settled for compliance — the AGPL-in-service exception is the safety net if it doesn't hold. +- **CPU-only + fully offline.** No runtime ships by default; pick a backend extra — `fast-alpr[onnx]` + (CPU), or `[onnx-gpu]`/`[onnx-openvino]`/`[onnx-directml]`/`[onnx-qnn]` — which maps onto the + "CPU now, small GPU/NPU later" compute question ([[bom]], [[open-questions]]). +- **Albanian/EU plates:** fast-plate-ocr also has a **European model trained on 40+ countries** (newer + than the default global model) — benchmark it against the default for AL accuracy. +- **Modular, no lock-in:** swap either stage via `BaseDetector`/`BaseOCR` (their docs plug in + Tesseract). So fast-alpr is the baseline you keep while replacing one stage if needed. + +**Scope: fast-alpr is plate-only — it does Job 1 (ANPR) but NOT Job 2 (vehicle verification).** The +anti-spoofing vehicle-attribute/fingerprint stage is still ours to build — but since fast-alpr already +standardizes on **ONNX Runtime + a YOLO-family detector**, the vehicle stage shares that runtime (the +coherent outcome). Other options, weaker: **OpenALPR** (permissive but largely unmaintained, the old +"permissive-only, weaker" path); **Ultralytics YOLO + PaddleOCR** (most accurate/tunable, but YOLO is +AGPL → needs the in-service exception; most build effort — the "scale" path if fast-alpr's accuracy +disappoints). + +**Recommendation:** prototype with **fast-alpr** now (permissive, offline, ONNX, fits the decided +shape); plan a YOLO-detector fine-tune + PaddleOCR only if production accuracy demands it. Choice kept +**open** pending the weight-provenance check + an accuracy benchmark on real AL plates. + ## Anti-fraud / threat-model fit - **Plate spoofing** (the motivating case): vehicle-attribute / fingerprint mismatch entry↔exit or @@ -75,8 +123,10 @@ guarantee is preserved. Recorded as an explicit exception in [[standing-decision ## Open -- **Recognizer choice** (permissive-only vs. AGPL model) and accuracy targets — see - [[vision-service]]; AGPL now permitted in-service. +- **Recognizer choice** — **fast-alpr (MIT, YOLOv9+CCT on ONNX) is the evaluated baseline** (see the + Recognizer evaluation section above); remaining open items are the **weight-provenance check** and + an **accuracy benchmark on real AL plates** (default global vs. the 40+country EU model). See + [[vision-service]]; AGPL still permitted in-service for the stronger fallback. - **Vehicle fingerprint**: attribute classifier vs. embedding-similarity; what threshold makes a mismatch an anomaly without false-positiving on lighting/angle. - **Compute footprint** on the appliance (CPU-only vs. a small GPU/NPU) — procurement input diff --git a/wiki/index.md b/wiki/index.md index e1b34a7..a1fcfb5 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -96,7 +96,7 @@ Counts: 4 sources · 19 entities · 44 concepts · 5 decision records. - [[device-events]] — unsigned hardware telemetry (relay/printer/camera/reader/input); separate from the signed ledger. - [[app-logs]] — the third stream: diagnostic logs (backend warn+ pino sink + frontend errors) → app_logs; log:read viewer; pruned by age+row cap. - [[subscription]] — recurring plan (e.g. 10,000 ALL/month); RF/QR or plate identity, car-count + max-concurrent, host-in-loop; short-circuits payment. (Renamed from "permit"; time-of-day windows noted, deferred.) -- [[opencv-anpr-service]] — host-side vision microservice: ANPR (plate identity) + vehicle verification (anti-plate-spoofing witness). +- [[opencv-anpr-service]] — host-side vision microservice: ANPR (plate identity) + vehicle verification (anti-plate-spoofing witness); fast-alpr (MIT, YOLOv9+CCT/ONNX) the evaluated recognizer baseline. - [[blocklist]] — barred plates/cards refused at entry (never at exit); signed, attributed. ## Concepts — frontend / operator UI diff --git a/wiki/log.md b/wiki/log.md index a13556b..f682cec 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -904,3 +904,7 @@ FLAW found: the entry button could be pressed without limit — each press minte ## [2026-06-19] feat | Application logs — backend pino DB sink + frontend error collection (app_logs) Added a THIRD data stream (`app_logs`) alongside the signed ledger and device telemetry — operational/diagnostic logs, since an OFFLINE appliance has no Sentry to ship to. BACKEND: a pino stream tees warn/error/fatal into app_logs (info/debug stay stdout-only — no bloat) with NO call-site change; the DB is now built BEFORE Fastify so the logger stream has its sink. FRONTEND (lib/logger.ts): always ships failed API requests (apiFetch non-OK path, minus 401 pre-login churn), window.onerror, unhandledrejection, and a top-level React ErrorBoundary (render crash → fatal, not a white screen); console.warn/error forwarded ONLY at client debug/trace level (noisy otherwise). Batched/throttled POST, flush via raw fetch + sendBeacon on pagehide. Reliability invariants: never log the /api/logs call itself (loop guard), LogService reentrancy guard, all writes best-effort/swallowed, bounded queue + clamped rows. API: POST /api/logs (any signed-in user, CSRF, tolerant — never 4xx on a bad entry) + GET /api/logs gated by a NEW `log:read` permission (new `log` resource in the RBAC grid; admin holds it). Retention: pruned by age (LOG_RETENTION_DAYS=30) AND row cap (MAX_ROWS=50k), hourly + at startup. UI: a Logs screen under /setup (filter level/source/since, expand to context+stack, 15s poll), sq+en. DB migration 0009_app_logs (+journal idx 9, seeds admin log:read) applied to the live apps/server DB. Verified end-to-end via app.inject: login→POST 204→GET 200 with the record; backend warn/error persisted + info dropped; non-admin GET 403 / POST 204 (the intended split). Build+lint green. New page [[app-logs]]; updated [[event-streams-split]], [[device-events]], index. + +## [2026-06-19] query | ANPR recognizer options — fast-alpr evaluated as the baseline + +Q: LPR/ANPR options — YOLO, OpenCV, both, another framework? Reframed: "YOLO vs OpenCV" is a category error — they're different pipeline LAYERS (YOLO = plate detector; OpenCV = Apache-2.0 image-handling glue, used regardless; plus an OCR stage). The real choice is which end-to-end recognizer. Researched [fast-alpr](https://github.com/ankandrew/fast-alpr) (latest **v0.4.0, 15 Mar 2026, MIT**): a thin orchestrator over two swappable ONNX stages — detection via [open-image-models](https://github.com/ankandrew/open-image-models) (`yolo-v9-t-384-license-plate-end2end`, MIT) + OCR via [fast-plate-ocr](https://github.com/ankandrew/fast-plate-ocr) (`cct-xs-v2-global-model`, MIT; also has a EUROPEAN model trained on 40+ countries — relevant for AL plates). MIT top-to-bottom (code AND published weights), one maintainer across all three repos, CPU-only + fully offline, backend extras for CPU/CUDA/OpenVINO/DirectML/QNN. KEY FINDING: its detector is open-image-models' OWN YOLOv9 ONNX export, NOT the Ultralytics AGPL package — so fast-alpr is a PERMISSIVE baseline that may not even need the scoped AGPL exception from [[vision-service]]. CAVEAT (flagged, not closed): a repo's LICENSE covers code, not necessarily redistributed model WEIGHTS (YOLOv9 upstream is GPL-3.0; Ultralytics YOLO AGPL) — verify weight provenance before relying on "MIT weights". fast-alpr is PLATE-ONLY → Job 2 (vehicle-attribute anti-spoofing) is still ours to build, but shares the same ONNX runtime. Recommendation: prototype fast-alpr now; Ultralytics-YOLO+PaddleOCR fine-tune only if accuracy disappoints. Recorded as an evaluated-options note; decision kept status:open pending the provenance check + an AL-plate accuracy benchmark. Updated [[opencv-anpr-service]] (new "Recognizer evaluation" section + licensing nuance), [[vision-service]] (open/next), index.