Kaizen
Browse modulesBookingsbookings/serverFunctions

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

ParameterType
policyunknown
schemaVersionnumber

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;

On this page