import { Condition } from "@classytic/primitives/condition"; //#region src/domain/admission/admission.d.ts /** Why admission was granted or refused. Stable codes — safe to switch on. */ type AdmissionReason = 'admitted' | 'capacity_full' | 'companions_exceeded' | 'rule_denied'; /** * One house rule. `denyIf` refuses when it matches; `allowIf` refuses when it * does NOT match (an allow-list). A rule may carry either or both — both must * pass. `code` identifies the rule in the decision + audit trail. */ interface AdmissionRule { /** Stable rule id surfaced in the decision (e.g. `'pool_offpeak_only'`). */ readonly code: string; /** Refuse when this matches the facts. */ readonly denyIf?: Condition | undefined; /** Refuse unless this matches the facts (allow-list form). */ readonly allowIf?: Condition | undefined; /** Operator-facing explanation shown at the turnstile. */ readonly message?: string | undefined; } /** * The house rules for one zone / membership tier / session kind. Every field * is optional — an omitted policy admits everyone (muster stays a recorder * unless a host opts into enforcement). */ interface AdmissionPolicy { /** * Max PEOPLE inside the scope at once (the party counts as * `1 + companionCount`). Omit for unlimited. */ readonly capacity?: number | undefined; /** Max companions on a single visit — the "one guest, or two" rule. */ readonly maxCompanions?: number | undefined; /** Declarative house rules, evaluated in order. */ readonly rules?: readonly AdmissionRule[] | undefined; } /** Live occupancy of the scope being entered. */ interface OccupancySnapshot { /** Open sessions (subjects inside). */ readonly sessions: number; /** Total people inside — subjects PLUS their companions. */ readonly people: number; } /** * Everything a rule may reference. The engine supplies the visit facts; the * host adds domain facts (tier, membershipStatus, escortPresent, roomType…) * via the index signature, and rules address them by dotted path. */ interface AdmissionFacts { readonly subjectRef: string; readonly subjectModel: string; readonly scope?: string | undefined; readonly sessionKind: string; /** Companions arriving with the subject on THIS visit. */ readonly companionCount: number; /** Occupancy BEFORE this party enters. */ readonly occupancy: OccupancySnapshot; /** Decision instant (never read from a clock inside the evaluator). */ readonly at: Date; /** ISO weekday of `at` in the caller's zone — 1=Mon … 7=Sun. */ readonly weekday: number; /** Hour-of-day of `at` (0–23) in the caller's zone. */ readonly hour: number; /** Host-supplied domain facts (tier, plan, escort, …). */ readonly [key: string]: unknown; } interface AdmissionDecision { readonly allowed: boolean; readonly reason: AdmissionReason; /** The rule that refused, when `reason === 'rule_denied'`. */ readonly ruleCode?: string; /** Operator-facing message for a refusal. */ readonly message?: string; /** People inside after admission, when allowed (diagnostics / dashboards). */ readonly occupancyAfter?: number; } /** * Evaluate admission. PURE — no clock, no I/O. * * DENY PRECEDENCE (first match wins, most physical first): * 1. `capacity_full` — the room genuinely cannot hold the party * 2. `companions_exceeded` — more guests than the tier permits * 3. `rule_denied` — a declarative house rule refused * 4. `admitted` * * Capacity is checked against the WHOLE party (`1 + companionCount`), so a * member with two guests is refused when only one slot remains — never * admitted-then-overflowing. */ declare function evaluateAdmission(facts: AdmissionFacts, policy?: AdmissionPolicy): AdmissionDecision; /** Convenience boolean form. */ declare function isAdmitted(facts: AdmissionFacts, policy?: AdmissionPolicy): boolean; /** * Authoring-time validation — call when an admin SAVES a policy, so a * malformed `Condition` fails at configuration time rather than silently * refusing every member at the turnstile. Throws the primitive's * `ConditionError`; also rejects negative caps. */ declare function validateAdmissionPolicy(policy: AdmissionPolicy): void; //#endregion export { AdmissionDecision, AdmissionFacts, AdmissionPolicy, AdmissionReason, AdmissionRule, OccupancySnapshot, evaluateAdmission, isAdmitted, validateAdmissionPolicy };