server+web: capacity / FULL gate (occupancy fold + transient refuse)
Occupancy is a fold over the signed ledger (entries minus exits per identity);
getOccupancy returns {count, capacity, free, full}. Capacity is a single-row
site_config table (admin-set; null = uncapped; migration 0001, additive).
FULL gate lives in the transient entry flow: when full, refuse (no ticket, no
vehicle_entry, no open) and sign an anomaly. Permit entry is NOT gated --
subscribers are admitted past transient-full (their own maxConcurrent still
applies), so occupancy can read over capacity by design (reserve-for-permits).
Routes: GET /api/occupancy + GET /api/site-config (any role), PUT
/api/site-config (admin; non-negative int or null). Web SiteSettings: live
occupancy + FULL badge (everyone), capacity editor (admin).
Verified: fill to cap -> 3rd transient refused; permit admitted past full; exit
frees a slot; RBAC (operator can't set, -5 -> 400); verifyChain ok. Physical
FULL-sign relay output deferred.
This commit is contained in:
@@ -41,8 +41,27 @@ over, stacked beyond the marked count) instead of refusing. So the FULL gate is
|
||||
(refuse vs. valet-accept), set by the operator per site. Valet is a manned-mode feature with its
|
||||
own custody/session shape — see [[valet-overcapacity]] (deferred).
|
||||
|
||||
## As-built (2026-06-16)
|
||||
|
||||
- **Occupancy** = `occupancyCount` (`apps/server/src/occupancy.ts`): a fold over the ledger —
|
||||
entries minus exits per identity, count those `> 0`. `getOccupancy` returns `{count, capacity,
|
||||
free, full}`.
|
||||
- **Capacity** is a single-row `site_config` table (admin-set; `null` = uncapped). Routes
|
||||
(`routes/site.ts`): `GET /api/occupancy` + `GET /api/site-config` (any role), `PUT /api/site-config`
|
||||
(admin; non-negative int or null).
|
||||
- **FULL gate** is in the **transient entry flow**: `occupancy.full` → refuse (no ticket, no
|
||||
`vehicle_entry`, no open) + signed `anomaly`. **Permit entry is NOT gated** here — subscribers are
|
||||
admitted past transient-full (their own `maxConcurrent` still applies); occupancy can read
|
||||
over-capacity (`free` negative) when permits enter a full lot, as intended.
|
||||
- **UI** `SiteSettings`: live occupancy + FULL badge (everyone); capacity editor (admin).
|
||||
- Verified: fill to cap → 3rd transient refused; permit still admitted past full; exit frees a
|
||||
slot; RBAC (operator can't set capacity); verifyChain ok. Physical FULL-sign relay output is
|
||||
**deferred** (needs a sign device).
|
||||
|
||||
## Open
|
||||
|
||||
- Zone/level granularity at launch vs. single capacity number.
|
||||
- Reserve-for-permits threshold.
|
||||
- Reserve-for-permits **threshold** (a soft transient cap below the hard capacity) — currently
|
||||
permits are simply ungated; a tunable threshold is the richer version.
|
||||
- Physical FULL-sign relay output (a sign-device role).
|
||||
- The valet over-capacity mode + custody model ([[valet-overcapacity]]).
|
||||
|
||||
+15
@@ -592,3 +592,18 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
||||
- VERIFIED: open→double-open 409→payments (cash+card; one dated outside the window excluded)→close
|
||||
totals (cash 500/card 250/3)→close-again 409→re-open ok; readonly 403; verifyChain ok. Full build 5/5.
|
||||
- Updated [[shift]] (as-built).
|
||||
|
||||
## [2026-06-16] build | Capacity / FULL gate (occupancy fold + transient refuse)
|
||||
- Occupancy = fold over the ledger (entries−exits per identity; `apps/server/src/occupancy.ts`),
|
||||
`getOccupancy` → {count, capacity, free, full}. Capacity = single-row `site_config` table (admin,
|
||||
null=uncapped); migration 0001 (additive, no prompt).
|
||||
- FULL gate in the TRANSIENT entry flow: occupancy.full → refuse (no ticket/entry/open) + signed
|
||||
anomaly. Permit entry NOT gated (subscribers admitted past transient-full; their maxConcurrent
|
||||
still applies) — occupancy can read over-capacity by design.
|
||||
- Routes (`routes/site.ts`): GET /api/occupancy + GET /api/site-config (any role), PUT
|
||||
/api/site-config (admin; non-neg int or null). UI `SiteSettings`: live occupancy + FULL badge
|
||||
(all), capacity editor (admin).
|
||||
- VERIFIED: fill to cap=2 → 3rd transient refused (anomaly, no open); permit still admitted (occ 3/2,
|
||||
free −1); exit frees a slot; routes RBAC (op can't set, −5→400, set/clear ok); verifyChain ok.
|
||||
Full build 5/5. Physical FULL-sign relay output deferred.
|
||||
- Updated [[capacity-occupancy]] (as-built).
|
||||
|
||||
Reference in New Issue
Block a user