diff --git a/wiki/concepts/i18n.md b/wiki/concepts/i18n.md index 97d975e..0ab700b 100644 --- a/wiki/concepts/i18n.md +++ b/wiki/concepts/i18n.md @@ -71,6 +71,18 @@ Two patterns added on top of the catalog approach: > this box must avoid relying on `Intl` for Albanian or it leaks English. (Printed slips already > solved this with the `SQ_MONTHS` table in [[rongta-printer]].) +## UI-wide date standard — "25 Qer 14:30" (2026-07-06) + +Dates were a mix of catalog-formatted "25 Qershor 20:01" and browser-locale "7/6/2026, 9:34 AM" +(raw `toLocaleString` in ~20 call sites) — operator called it out. The standard now: **short +month from the catalog** (`common.monthsShort`: Jan/Shk/…/Qer/Korr/…/Dhj), **24h clock**, year +only when ≠ current. Helpers in `lib/format.ts`: `formatDate` ("25 Qer"), `formatDateTime` +("25 Qer 14:30", optional seconds — the event-detail modal keeps them), `formatClock` ("HH:mm"); +`formatRelativeDateTime` keeps Sot/Dje and uses the same short months beyond that. Rule for new +code: **never call `toLocale*String` for a DATE** — catalog months exist because the appliance +browser's ICU may lack Albanian data; number formatting (thousand separators on money) still uses +the locale. Swept everywhere 2026-07-06. + ## Open / deferred - **SetupWizard chrome is now translated (2026-06-19)**; the remaining gap is the **backend diff --git a/wiki/concepts/tariff-time-tiers.md b/wiki/concepts/tariff-time-tiers.md index 18f267c..dfe7d40 100644 --- a/wiki/concepts/tariff-time-tiers.md +++ b/wiki/concepts/tariff-time-tiers.md @@ -174,5 +174,6 @@ in `packages/shared/src/index.ts` (+ `tariff.test.ts`, 36 cases incl. the golden holiday calendar (one date list, referenced by cards) is a future nicety, not built. - Per-relay/lane **category capture** at a transient gate (the "bus lane") — seam noted in `entry-flow.ts`; today every transient takes the site default category. -- A composer **price preview** ("at 14:30 Tue a 2h stay costs …") — high-value for operator trust, - deferred. +- ~~A composer **price preview**~~ — largely DELIVERED 2026-07-06 by the Tariff Lab's fee + BREAKDOWN (see [[tariff]] §Tariff Lab): simulate any stay against a draft/version and read the + line items. A live preview inside the composer form itself remains a possible nicety. diff --git a/wiki/concepts/tariff.md b/wiki/concepts/tariff.md index d353005..01bbd1a 100644 --- a/wiki/concepts/tariff.md +++ b/wiki/concepts/tariff.md @@ -201,7 +201,19 @@ The admin authors the rate card at runtime — no hand-seeding: - Ships **blank** — until a version is published, `GET /api/tariff` returns `active: null` and the pay station returns `409 no active tariff`. Verified end to end (publish → pay station prices). -### Tariff Lab (simulator, as-built 2026-06-20; drafts redesign 2026-07-05) +### Tariff Lab (simulator, as-built 2026-06-20; drafts redesign 2026-07-05; fee breakdown 2026-07-06) + +> **Fee breakdown ("how is this sum produced").** The lab's Outcome panel lists the fee's LINE +> ITEMS: banded same-price increment runs (time window · N × unit · tier-card name), window-package +> occurrences, stepped day totals (top-tier repeat flagged), daily-cap clamps as NEGATIVE +> adjustments, entry grace, plus a rounding note (raw min → billed min at the increment). Produced +> by `explainFee` in `@parking/shared` — the SAME computeFee walk with a trace collector, so +> Σ items ≡ the amount by construction (golden V1 regression unchanged). `/api/tariff/simulate` +> returns it as `breakdown` (null when settled). Also the composer grew INCREMENT-UNIT guards +> (2026-07-06): price labels state the real unit live ("Çmimi / orë" at 60, "Çmimi / N min" +> otherwise), an amber warning fires when increment ≠ 60, and each ladder/flat price shows its +> "= X / orë" equivalence — closing the 60→10 ×6-prices trap; example defaults are +> currency-scaled (ALL: 200/100, not the euro-scale 2.00/1.00). The tariff engine is a **pure function of time**, but you could previously only *exercise* it by waiting (the only clock the booth reads is the real wall-clock). The **Tariff Lab** closes that gap: diff --git a/wiki/decisions/fleet-deployment-komodo.md b/wiki/decisions/fleet-deployment-komodo.md index 69bbbb1..86dc054 100644 --- a/wiki/decisions/fleet-deployment-komodo.md +++ b/wiki/decisions/fleet-deployment-komodo.md @@ -2,7 +2,7 @@ type: decision tags: [parking, deployment, fleet, komodo, netbird, offline-first, threat-model] sources: [] -updated: 2026-06-29 +updated: 2026-07-07 status: settled --- @@ -176,3 +176,19 @@ here so it isn't re-litigated. - Companion: the `komodo/` infra-as-code sketch (in the repo, not the wiki), [[appliance-provisioning]] (what runs *before* Periphery), [[disk-os-hardening]] (the appliance's hardening surface). + +## park-lab — the lab bench joins the fleet (2026-07-07) + +Second `[[stack]]` in `komodo/resources.toml`: **`park-lab`** (server = the lab box's Periphery +`connect_as`), the first non-booth member and the proof of the tier model in practice: + +| Stack | compose branch | image tag | secrets | +| --- | --- | --- | --- | +| park-lab | `dev` | **moving `dev`** (a lab may float) | `park_lab_*` | +| park-buzi | `stage` | pinned `stage-` | `park_buzi_*` | + +The three knobs are independent per stack — the ResourceSync's own branch only governs where the +FILE is read from, each stack's `branch` picks its compose files, `TAG` picks the image. Per-box +secrets even in the lab (blast radius). The lab box earned its keep immediately: it caught the +USB close-cancel truncation, the printer/controller wizard gate, and the Periphery v2.2.0 +root_directory default before any of them reached a real booth ([[appliance-provisioning]] §7a). diff --git a/wiki/entities/rongta-printer.md b/wiki/entities/rongta-printer.md index 1621c9b..14be49a 100644 --- a/wiki/entities/rongta-printer.md +++ b/wiki/entities/rongta-printer.md @@ -49,8 +49,9 @@ many ESC/POS-compatible OEM clones that share its firmware). Driver `rongta` in - **Two printers configured (as of 2026-06-18)**, by role — see [[printer-roles-failover]]: - **entry-dispenser** — `10.0.10.9`, outside at the lane; the driver takes the entry ticket. This unit is a **Cashino**, not a Rongta: it prints the same ESC/POS stream but - serves no `/prn_stat.htm` status page, so it runs on the `cashino` driver (reachability - PING only, no paper/cover status) — see [[printer-status-monitoring]]. + serves no `/prn_stat.htm` status page, so it runs on the generic ESC/POS driver + (id `escpos` — renamed from `cashino` 2026-07-06, migration 0023; reachability PING + only, no paper/cover status) — see [[printer-status-monitoring]], [[printer-usb-transport]]. - **booth-receipt** — `10.0.10.10`, inside the booth; receipts, AND the backup that prints the entry ticket if the outside dispenser is offline. This unit is a **Rongta** (`rongta` driver, full status-page monitoring). diff --git a/wiki/log.md b/wiki/log.md index f752ef0..2e4a2ec 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -2516,3 +2516,12 @@ GETs /ISAPI/System/time, and beyond 60s drift PUTs manual time with the site's w offset, echoing the camera's timeZone verbatim; >1h jumps log warn (persisted). digest client generalised GET→GET/PUT/POST with body (the handshake was already method-aware). Capability-guarded (isClockSyncable — hikvision only). 8 new tests (5 devices, 3 tz-offset). + +## [2026-07-07] lint | Wiki catch-up sweep after the lab-bench sprint + +Audit found five pages lagging the log: [[rongta-printer]] still named the `cashino` driver id +(→ escpos + migration note); [[tariff-time-tiers]] still listed the composer price preview as +deferred (→ delivered by the lab fee breakdown); [[tariff]] lab section gained the breakdown + +composer increment-guard paragraph; [[i18n]] now records the "25 Qer 14:30" date standard and the +never-toLocaleString-for-dates rule; [[fleet-deployment-komodo]] gained the park-lab stack + tier +table (also logging the park-lab addition itself, which had slipped the log).