--- type: decision tags: [parking, decisions, integrity, devices, schema] sources: [] updated: 2026-06-15 status: open --- # Decision: Split the signed business ledger from device telemetry Taken 2026-06-15, at the start of the business-layer schema work. ## The problem The existing `events` table (signed, hash-chained — [[append-only-event-chain]]) had grown to carry **two unrelated concerns**: the financial/accountability ledger *and* raw device telemetry (button pushes recorded as `input_received`). They have opposite requirements — the ledger must be small, signed, and reconciled; telemetry is high-volume, churny, and disposable. ## Decision — two tables - **`ledger_events`** — the signed, hash-chained, [[atecc608]]-signed **business ledger** (rename of `events`). Holds only business/accountability facts: `vehicle_entry`, `vehicle_exit`, `payment`, `void`, `shift_z_report`, and the witness-grade `barrier_open_command` / `barrier_open_observed` / `anomaly`. [[reconciliation]] runs against this; sessions/[[tariff]]/occupancy are projections of it. - **`device_events`** — **unsigned** operational telemetry (see [[device-events]]): relay fired, printer paper-out, camera offline, reader read, raw input edges. May rotate/prune. Never signed, never reconciled. A raw button press is **telemetry** → `device_events`. The entry flow then mints a **signed `vehicle_entry`** in the ledger once a ticket prints + the barrier is commanded. So `input_received`-as-a-signed-event is **dropped** (it was transitional). ## Why - Keeps the **signed ledger small and high-value** — fewer rows to sign, hash, verify, reconcile, and export; signal isn't drowned in device noise. - Right **durability semantics per stream**: the ledger is precious + append-only forever; telemetry can age out. - Clean separation matches the [[device-adapter-pattern]] philosophy — device chatter stays on the device side of the boundary. ## Consequences / migration (no production data yet) - No `.sqlite` with real chain data exists, so renaming + restructuring is safe now (no signatures to invalidate). This is the moment to do it. - Code: rename `events` → `ledger_events`; `EventLog`/`canonicalize`/`verifyChain` and the `/api/events` routes follow the rename; add an unsigned `device_events` writer; move the Dingtian input-push handler to emit `device_events` (+ the entry flow signs `vehicle_entry`). - `ParkingEventType` in `packages/shared` splits into ledger types vs. a device-event type set. ## Open - `device_events` retention/rotation policy. - Which device facts (if any) are witness-grade enough to *also* warrant a signed ledger entry (e.g. `barrier_open_observed` from a loop sensor) — see [[append-only-event-chain]] witness gap.