docs(wiki): activity-log explainability, dates/i18n, KP-300H barcode fix
Record this session's work across the affected pages + three log entries. - ticket-encoding: id 13→11 digits (guess-resistance rationale, legacy-safe validation) + a barcode-geometry rule (symbol dots must fit the narrowest deployed printer's line — the KP-300H 72mm overflow). - rongta-printer: KP-300H raster-garbage root cause (line overflow, not corruption), sendRaw graceful-close fix, Albanian human dates (formatStampSq). - i18n: localized ledger reason codes, relative/human dates + the "browser ICU lacks Albanian" gotcha, toggle stale-router-context fix. - shift: Albanian Z-report, shift-history UI + permission scoping. - booth-console: explainable activity log (inline reasons/badges, event-detail modal with snapshots + audit disclosure, subscriber names, failed-snapshot tiles). - index/log updated; all added wikilinks resolve. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
type: concept
|
||||
tags: [parking, domain, business, devices, entry-flow]
|
||||
sources: []
|
||||
updated: 2026-06-15
|
||||
updated: 2026-06-19
|
||||
status: open
|
||||
---
|
||||
|
||||
@@ -23,11 +23,19 @@ must have:
|
||||
reconciliation aid ([[reconciliation]] pre-numbered stock), not the scan key.
|
||||
- **All-numeric** (as-built 2026-06-17) — so ANY legacy 1D barcode scanner reads it and an operator
|
||||
can hand-key it. Random (not sequential), so "all-numeric" does not weaken the unguessable
|
||||
property. Format: **13 digits = 12 cryptographically-random digits + 1 Luhn check digit**
|
||||
(10^12 space → negligible collisions at lot scale; the Luhn digit lets manual entry reject a typo
|
||||
rather than fail as "session not found"). `newTicketId()` in `apps/server/src/entry-flow.ts`;
|
||||
validate with `validateTicketCode()` (gate MANUAL entry only — a scanned/looked-up id already in
|
||||
the ledger is authoritative regardless of format).
|
||||
property. Format (**shortened 13→11 on 2026-06-19**): **11 digits = 10 cryptographically-random
|
||||
digits + 1 Luhn check digit**. **Length is driven by guess-resistance, not volume** — with 10^10
|
||||
valid ids and the Luhn digit rejecting 9/10 malformed guesses, a blind attempt at a currently-OPEN
|
||||
ticket lands at ~1-in-10^7 even with thousands parked (the [[threat-model|booth-operator]] threat),
|
||||
which is the property that matters; raw count (a billion) was never the constraint. Collisions stay
|
||||
negligible at lot scale. `newTicketId()` in `apps/server/src/entry-flow.ts`; validate with
|
||||
`validateTicketCode()` — now **length-agnostic** (`\d{10,14}` + Luhn) so legacy 13-digit tickets in
|
||||
circulation keep validating. Gate MANUAL entry only — a scanned/looked-up id already in the ledger
|
||||
is authoritative regardless of format.
|
||||
> **Why 11, not the requested 9 (2026-06-19):** 9 digits (10^8 space) against ~1000 live tickets
|
||||
> gives ~1-in-10^5 per blind guess — an operator scripting guesses could find a valid open ticket
|
||||
> in minutes. 11 keeps a strong anti-forgery margin AND was the actual fix for a printer overflow
|
||||
> (below). The shorter id is *why* the width-3 barcode now fits the 72mm Cashino line.
|
||||
- **Format is a property of minting, not the schema** — `identity` / `sessions.id` are free-form
|
||||
`text`, so changing the id format is a code change with **no migration**. Legacy `T-<uuid>` ids
|
||||
(pre-2026-06-17) remain valid keys and coexist with numeric ones.
|
||||
@@ -50,6 +58,20 @@ must have:
|
||||
> uncertain, so the id is carried in two independently-readable forms (1D barcode / printed digits).
|
||||
> The "operator scans with a phone" path reuses the
|
||||
> existing dispatch flow ([[entry-exit-readers]]) and is tracked separately (not yet built).
|
||||
|
||||
> **Barcode GEOMETRY must fit the paper width — root cause of a real garbage-print incident
|
||||
> (2026-06-19).** The Cashino [[rongta-printer|KP-300H]] entry dispenser printed tickets as **raster
|
||||
> garbage** (solid black bars / banding) while the [[rongta-printer|Rongta]] printed the *identical*
|
||||
> byte stream fine. Not data corruption: the **Code128 symbol overflowed the print line.** Math: a
|
||||
> Code128-B symbol is `(11·chars + 35) · moduleWidth` dots. At 203 dpi the KP-300H prints **72mm =
|
||||
> 512 usable dots** (the Rongta runs 80mm = 576). The old **13-digit** id at `GS w 3` = ~534 dots
|
||||
> **overran 72mm**, and the firmware rendered the overflow as pixels; the Rongta's 80mm had just
|
||||
> enough room — which is why only the Cashino failed. The **11-digit** id at width 3 = **~468 dots**,
|
||||
> fits both widths, and scanned the full value at the exit reader (verified on hardware). Lessons:
|
||||
> (1) keep `(11·len+35)·moduleWidth` under the **narrowest** deployed printer's usable dots; (2) a
|
||||
> too-NARROW module (`GS w 2`) is also bad — it scanned but returned **truncated** values (partial
|
||||
> reads logged as `exit.refused.noSession` anomalies). Width 3 + 11 digits is the verified sweet
|
||||
> spot. `code128()` in `packages/devices/src/drivers/printer-escpos.ts`.
|
||||
- **Scan points** (both host-side reads — [[entry-exit-readers]]):
|
||||
- **Pay station** — customer scans the ticket → host finds the session → shows fee → takes
|
||||
payment ([[tariff]], pay-on-foot) → appends `payment`.
|
||||
|
||||
Reference in New Issue
Block a user