fix(exit): stuck active session — paid ticket with no vehicle_exit
A paid car that left via a manual barrier re-open kept no vehicle_exit, so activeSessions() saw it as permanently open and the grace-expiry eviction (which only ran for exited sessions) never fired — it lingered forever (ticket T-397815c0). - reopenBarrier() now signs a vehicle_exit (source:manual) when the session is still open, closing it; still no second exit when already exited (phantom re-close — no double-count). - activeSessions() ages out a PAID open session past grace even with no exit (unpaid open sessions never age out — a car owing money stays). Pure display filter; the signed log is untouched. Verified both fixes + chain integrity on a fresh DB. A one-off corrective vehicle_exit was appended to the live ledger to clear T-397815c0. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -250,10 +250,20 @@ export class PayStation {
|
||||
? new Date(Date.parse(a.paidAt) + a.graceExitMin * 60_000).toISOString()
|
||||
: null;
|
||||
const withinGrace = graceExpiresAt != null && now <= Date.parse(graceExpiresAt);
|
||||
const paid = a.paidAt != null;
|
||||
|
||||
// ACTIVE = still inside, OR exited but still within the (unconfirmed) grace window.
|
||||
// An exited session past grace is presumed truly gone → omitted.
|
||||
// ACTIVE membership:
|
||||
// - exited + within grace → still shown (barrier unconfirmed, may be present);
|
||||
// - exited + past grace → presumed gone, omitted;
|
||||
// - open + UNPAID → always shown (a car owing money never ages out —
|
||||
// it's genuinely still inside until it pays, however long that takes);
|
||||
// - open + PAID + past grace → AGE-OUT (omit). A paid car whose walk-back grace
|
||||
// lapsed has left; if no vehicle_exit was ever signed (e.g. it left via a
|
||||
// manual barrier re-open before that path closed the session, or a historical
|
||||
// session like T-397815c0) it would otherwise linger forever. The signed log
|
||||
// is unchanged — this is purely a display filter. See booth-exit-flow.md.
|
||||
if (!open && !withinGrace) continue;
|
||||
if (open && paid && graceExpiresAt != null && !withinGrace) continue;
|
||||
|
||||
// Amount owed now: only meaningful for an open + unpaid session.
|
||||
let amountMinor: number | null = null;
|
||||
|
||||
Reference in New Issue
Block a user