Function: readPolicyBag()
function readPolicyBag(policy: unknown, schemaVersion: number): {
capacityModel?: "exclusive" | "shared" | "seated";
formSchemaId?: string;
holdTtlSeconds?: number;
maxCapacityUnits?: number;
minEnrollment?: number;
noShowGraceMinutes?: number;
payloadSchemaId?: string;
pendingTtlSeconds?: number;
pricingScopes?: string[];
requiresApproval?: boolean;
requiresCheckOut?: boolean;
ruleModule?: string;
};Defined in: server/bookings/policy-bag.ts:64
Discriminated policy-bag reader: dispatch on the row's
policySchemaVersion, parse with that version's schema.
Evolving the bag: a future schema version ADDS a .with(n, …) branch that
parses the old shape and UPCASTS it to the current PolicyBag — never
rename or repurpose a field in place. An in-flight booking pinned to an old
version keeps parsing even after the live schema moves on (§6.2 note).
Parameters
| Parameter | Type |
|---|---|
policy | unknown |
schemaVersion | number |
Returns
capacityModel?
optional capacityModel?: "exclusive" | "shared" | "seated";formSchemaId?
optional formSchemaId?: string;holdTtlSeconds?
optional holdTtlSeconds?: number;maxCapacityUnits?
optional maxCapacityUnits?: number;minEnrollment?
optional minEnrollment?: number;Minimum confirmed enrollment for a program offering to RUN (§6.10/Phase 2).
A run-decision check (WaitlistService.decideRun) auto-cancels an offering
whose confirmed SUM(capacity_units) falls below this at decision time
(the class didn't make it). Absent = no minimum; the offering always runs.
noShowGraceMinutes?
optional noShowGraceMinutes?: number;Grace window (in minutes) after startsAt before the no-show sweeper
marks a confirmed booking as no_show. When absent/zero, the sweeper
treats the grace as 0 minutes (marks immediately after startsAt).
The sweeper call-site may also supply an override via noShowGraceMinutes
on the sweep options — the per-booking pinned bag value is the default.
payloadSchemaId?
optional payloadSchemaId?: string;pendingTtlSeconds?
optional pendingTtlSeconds?: number;pricingScopes?
optional pricingScopes?: string[];Scope-key SELECTOR for the pricing glue (§8.3): when non-empty, the
pricing-rule scope mapping is FILTERED to these scope-type keys (e.g.
["booking_type"] makes resource-scoped price rules unmatched for
bookings of this type); when empty/absent, the full merged mapping
applies. These are keys into the mapping — NOT context paths; the
path wiring lives in pricing-glue.ts / deps.pricing.scopeMapping.
requiresApproval?
optional requiresApproval?: boolean;requiresCheckOut?
optional requiresCheckOut?: boolean;ruleModule?
optional ruleModule?: string;