import { AdmissionPolicy } from "../admission/admission.mjs"; import { MusterContext } from "./common.mjs"; //#region src/domain/ports/admission.bridge.d.ts /** Who is entering where — the question a facts resolver answers about. */ interface AdmissionFactsQuery { readonly subjectRef: string; readonly subjectModel: string; readonly scope: string | undefined; readonly sessionKind: string; /** The decision instant, so a resolver never reads its own clock. */ readonly at: Date; } interface AdmissionBridge { /** * The house rules in force for this scope, right now. * * Called INSIDE the check-in transaction, before the occupancy read, so an * implementation must be a fast read and must not open its own transaction. * It is passed `ctx` so a Mongo-backed registry can enroll in the caller's * session rather than reading outside it. * * Return `null` when the scope has no configured rules. */ resolvePolicy(scope: string | undefined, sessionKind: string, ctx: MusterContext): Promise; /** * SERVER-AUTHORITATIVE facts the rules evaluate against — an entitlement the * subject holds, their membership tier, whether an escort is present. * * ## Why this exists, and why it is not optional in spirit * * Making `resolvePolicy` server-side fixed WHO WRITES THE RULES. It did not * fix who supplies the INPUTS, and a rule is only as trustworthy as its * facts: with `admissionFacts` taken from the request body, a zone rule like * `allowIf hasZoneGrant == true` is defeated by a caller that simply POSTs * `admissionFacts: { hasZoneGrant: true }`. The rule reads as enforcement and * is decoration — the same defect as the policy, one layer down. * * ## Keys returned here WIN * * The engine spreads these AFTER `input.admissionFacts`, so a server-answered * key overrides whatever the caller claimed about it. Caller facts survive * only for keys the server does not answer (genuinely host-local extras a * kiosk knows and the server cannot). * * **So any fact a SECURITY rule reads must be resolved here.** A fact only * the caller supplies is an assertion by the party being policed. * * ## Failing is better than guessing * * If the underlying lookup cannot answer — the entitlement store is * unreachable, a timeout — THROW. Do not return `false`, and do not return * `true`. `false` denies a paying member and reads to them as "your * membership expired", which is wrong information rather than an outage; * `true` opens the door. A throw surfaces as a real error the operator can * see and alert on. Absence of an answer is not a negative answer. */ resolveFacts?(query: AdmissionFactsQuery, ctx: MusterContext): Promise>; } //#endregion export { AdmissionBridge, AdmissionFactsQuery };