feat(booth): badge subscriber out-of-window entries in the live feed

A subscriber entering outside their plan's allowed window gets a deferred
transient charge (windowOwedMinor, collected/gated at exit) — but it was
SILENT at the booth: the entry showed as a plain subscriber pass with no hint
money is owed, so the operator only discovers it at exit.

Surface it: add a "out-of-window — owes fee" badge on any entry/exit event
carrying windowOwedMinor > 0, so the operator sees immediately that this
subscriber owes a fee. Also type the window-charge fields on LedgerPayload
(were riding the open-ended index signature).

Behaviour is otherwise unchanged and correct — verified the live "Mon Kukaleshi"
entry: entered 20:29 local (before the 21:00 Mon–Sat window, grace 5m), owes
100 ALL for 18:29–18:55Z, stamped on the signed entry, still owed, gated at
exit. Subscribers get no ticket by design. Build+lint 12/12.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-06-20 20:32:12 +02:00
parent 36f30d39ff
commit eafbc3ddbb
4 changed files with 14 additions and 0 deletions
+3
View File
@@ -112,6 +112,9 @@ function eventBadges(p: LedgerEvent["payload"]): string[] {
if (p.permitRefused) keys.push("booth.badgeSubRefused");
if (p.ticketPrinted === false) keys.push("booth.badgeNoTicket");
if (p.subscriptionSale) keys.push("booth.badgeSubSale");
// Subscriber entered/exited outside their plan's allowed window → owes a deferred
// transient charge, collected (gated) at exit. Flag it so the operator KNOWS now.
if (typeof p.windowOwedMinor === "number" && p.windowOwedMinor > 0) keys.push("booth.badgeWindowCharge");
if (p.source === "manual" && !p.subscriptionSale) keys.push("booth.badgeManualOpen");
return keys;
}