8a8e74561d
Pivot from the hardware/integrity layer to the parking operation. All wiki-only; no code yet. Core principle throughout: business entities are projections over the signed append-only event log, never mutable tables. New concepts: parking-session, tariff (composable/versioned, FX-ready), shift (manned-only Z-report), capacity-occupancy, validation-discounts, reporting-analytics, clock-integrity, ticket-encoding, anti-passback. New entities: permit, opencv-anpr-service, blocklist. Decisions: session-model, vision-service (host-side ANPR + vehicle verification; scoped AGPL exception for the isolated service). Updates: append-only-event-chain (new event types + vision witness), local-jwt-auth (drop 8h expiry -> until logout; code change pending), lpr-camera (host-side recognition supersedes edge-AI), standing-decisions (AGPL exception), open-questions (+FX, +pay-station money corners, backup). Deferred + flagged: intercom/help-call, receipts/refunds/change, FX engine, lane topology (#1).
86 lines
4.8 KiB
Markdown
86 lines
4.8 KiB
Markdown
---
|
|
type: entity
|
|
tags: [parking, vision, anpr, anti-fraud, service]
|
|
sources: []
|
|
updated: 2026-06-15
|
|
status: open
|
|
---
|
|
|
|
# OpenCV ANPR / Vision Service
|
|
|
|
A **local microservice** that analyses camera snapshots: reads the licence **plate** (ANPR) and
|
|
extracts **vehicle attributes** for verification. Built by us (decision 2026-06-15) to do
|
|
recognition **host-side on ordinary IP-camera snapshots**, replacing the dedicated edge-AI
|
|
[[lpr-camera]]. See decision [[vision-service]].
|
|
|
|
## Two jobs
|
|
|
|
1. **Identity (ANPR).** snapshot → `{ plate, confidence, bbox }`. Feeds the existing
|
|
`IdentitySource = "lpr"` ([[parking-session]]): the plate is a session/identity key and the way
|
|
a plate-bound [[permit]] is matched.
|
|
2. **Verification (anti-fraud witness).** snapshot → vehicle attributes — at minimum
|
|
`{ make?, model?, colour, bodyType }`, ideally a compact **visual fingerprint** (an embedding).
|
|
This is the answer to **plate-spoofing**: *a fraudster prints a registered/paid plate and drives
|
|
in with a different car.* Plate-reading alone can't catch that; comparing the **vehicle** seen at
|
|
entry vs. exit (and vs. the [[permit]]'s known car) can. A plate that entered on a red hatchback
|
|
but exits on a black SUV is a **reconciliation anomaly** — exactly the independent-witness role
|
|
the [[append-only-event-chain]] flags as the unbuilt gap. See [[reconciliation]].
|
|
|
|
> The two jobs are why this is worth building rather than just plate-OCR: the service is both an
|
|
> **identity source** and an **independent witness**, the visual analogue of the whole system's
|
|
> "two records that must reconcile" thesis.
|
|
|
|
## Architecture — separate localhost process
|
|
|
|
- A **Python service** (e.g. FastAPI) running **on the appliance**, called by the Node backend over
|
|
**localhost HTTP** (`POST /analyze` with the JPEG bytes the camera driver already pulls — see
|
|
[[lpr-camera]] "driver/storage boundary": `Snapshot.bytes`).
|
|
- **Fully offline** ([[offline-first]]): all inference is local, no cloud. Model weights ship on the
|
|
appliance.
|
|
- **Process isolation is deliberate** — it keeps a heavy Python/native/AGPL stack out of the
|
|
Node app's process and license surface (see licensing below), and gives it its own failure
|
|
domain. If the service is down/slow, the host falls back (transient ticket path) rather than
|
|
blocking the lane.
|
|
- **Request/response (first cut):**
|
|
- `POST /analyze` → `{ plate: {text, confidence, bbox}|null, vehicle: {colour, bodyType, make?, model?, embedding?}, modelVersion, tookMs }`
|
|
- `GET /health` → readiness + model versions.
|
|
- The Node side wraps it behind an internal interface (like a device adapter) so the recognizer can
|
|
be swapped without touching business logic.
|
|
|
|
## 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
|
|
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]].
|
|
|
|
- OpenCV core itself is **Apache-2.0** (clean either way).
|
|
- AGPL note: if the appliance is ever offered as a network service to third parties, AGPL's
|
|
network-use clause could require offering the service's source — relevant only if productised
|
|
beyond the on-site appliance; flag at that point.
|
|
|
|
## Anti-fraud / threat-model fit
|
|
|
|
- **Plate spoofing** (the motivating case): vehicle-attribute / fingerprint mismatch entry↔exit or
|
|
vs. a [[permit]]'s registered car → anomaly. Doesn't *block* on its own (recognition is
|
|
probabilistic) — it **flags for [[reconciliation]]** and is captured in the signed record.
|
|
- The recognition result and the source image both attach to the signed [[append-only-event-chain]]
|
|
entry, so the *evidence* is tamper-evident even though recognition itself is host-side and
|
|
fallible.
|
|
- Recognition is **advisory, never the sole authority** to open a barrier where money/access is at
|
|
stake — confidence thresholds + fallback to ticket/manual; a low-confidence read must not strand a
|
|
car ([[fail-state-safety]]).
|
|
|
|
## Open
|
|
|
|
- **Recognizer choice** (permissive-only vs. AGPL model) and accuracy targets — see
|
|
[[vision-service]]; AGPL now permitted in-service.
|
|
- **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
|
|
([[bom]], [[open-questions]]).
|
|
- Per-camera **opt-in** ("optionally bound", user's word): which lanes/cameras route snapshots to
|
|
the service.
|