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:
2026-06-19 11:41:27 +02:00
parent bbf61c48df
commit 0074e82a2a
7 changed files with 154 additions and 20 deletions
+28 -2
View File
@@ -2,7 +2,7 @@
type: entity
tags: [parking, hardware, printer, device]
sources: []
updated: 2026-06-14
updated: 2026-06-19
---
# Rongta 80mm thermal printer
@@ -14,7 +14,16 @@ many ESC/POS-compatible OEM clones that share its firmware). Driver `rongta` in
## Transport & protocol
- **ESC/POS over a raw TCP socket on port 9100** (the JetDirect/RAW convention). The driver
opens the socket, writes the ESC/POS byte stream, waits for flush, closes.
opens the socket, writes the ESC/POS byte stream, and **closes GRACEFULLY**.
> **Graceful close — fixed 2026-06-19.** `sendRaw()` previously did `write(payload)` then
> `destroy()` on the write callback. But a `Socket.write()` callback fires when bytes reach the
> *local kernel buffer*, NOT when the peer has read them — so `destroy()` could send a TCP **RST**
> that truncates the job mid-stream, leaving the printer a desynced ESC/POS stream (raster garbage).
> Now it `end(payload)` (write + FIN, a clean half-close) and resolves on the socket's `close`
> event — which only fires after the printer has drained the bytes. A timeout *after* the write
> completed is treated as success (some printers never send their own FIN), so a delivered job is
> never spuriously failed. A latent bug found while diagnosing the KP-300H garbage; it was NOT the
> cause of that (see overflow gotcha below) but is a real truncation risk on its own.
- **No authentication** on the print socket — anyone who can reach port 9100 can print. Like
every other field device it must sit on the **isolated device VLAN** ([[network-isolation]]).
There is no real HTTP/control boundary on the device (same posture as [[dingtian-relay]]).
@@ -66,6 +75,23 @@ bytes. A printed voucher surfaced two encoding bugs, both now fixed in `printer-
`line()` now normalises U+00A0/U+202F → a plain space before encoding. Any Intl-formatted value on a
ticket is affected, not just money.
### KP-300H barcode overflow — only the Cashino garbled (2026-06-19)
The Cashino entry dispenser printed **raster garbage** on entry tickets while the booth Rongta printed
the *same* byte stream cleanly. Root cause was **barcode line-overflow, not corruption**: a 13-digit
Code128 at module width 3 (~534 dots) overran the KP-300H's **72mm = 512-dot** line; the Rongta's
80mm (576) had room. Plain-text-only prints were clean, isolating it to the `GS k` barcode. **Fix:
shorten the ticket id 13→11 digits** (~468 dots — fits 72mm) — see [[ticket-encoding]] for the
geometry. Module width must stay 3: a test at width 2 scanned but returned *truncated* values.
**General rule:** size firmware barcodes/QRs to the **narrowest** deployed printer's usable dot width.
### Human dates on printed slips — Albanian (2026-06-19)
`stamp()` now formats timestamps as **`19 Qershor 2026 10:48:25`** (Albanian month, 24h with seconds)
instead of `YYYY-MM-DD HH:MM`. Month names are a hardcoded `SQ_MONTHS` table (the appliance browser's
ICU lacks Albanian locale data — see [[i18n]]). `stamp` is exported as **`formatStampSq`** so the
shift [[shift|Z-report]] shares the one Albanian date format. Applies to ticket issue time, receipt
entry/paid rows, and subscription validity dates (date-only). Consistent with the
"[[i18n|printed paper is always Albanian]]" rule.
## Status
Driver written and compiles; entry-ticket layout is a first pass; live status monitoring is