Skip to content

symfonic.platform.admission

admission

SCOPE-14 — the admission order, as code rather than as a comment.

1. Derive the principal.            Failure → 401/403/400, audited.
2. Subject tombstone check.         A deleted subject does not start a run.
3. Effect-admission lease.          EFX-L-1/L-4, acquired by the invocation.
4. Policy / tool lockdown.          SEC-FCP-3/4.
5. Budget check.                    Fail-closed, evented.
6. Effect.

Steps 3–6 belong to the invocation and are EFX-L-4's ordering consumed unchanged; this gate owns 1, 2 and 5 — the ones that happen before an invocation exists. The order is not arbitrary: each step is cheaper and more definitive than the next, and every one of them is fail-closed, so a failure anywhere denies and the denial is auditable.

AdmissionGate

AdmissionGate(*, resolver: ScopeResolver, guard: SubjectAdmission | None = None, budget: BudgetService | None = None)

The three platform-side gates, composed in the one declared order.

Each collaborator is injected. There is no service locator and no lookup by name: a gate receives the two or three objects it uses, which is what keeps the order auditable — you can read it in the constructor, not chase it through a registry.

Source code in src/symfonic/platform/admission.py
def __init__(
    self,
    *,
    resolver: ScopeResolver,
    guard: SubjectAdmission | None = None,
    budget: BudgetService | None = None,
) -> None:
    self._resolver = resolver
    self._guard = guard
    self._budget = budget

admit async

admit(credentials: RequestCredentials) -> AuthenticatedPrincipal

Run the gates in order and return the principal, or raise the first no.

Source code in src/symfonic/platform/admission.py
async def admit(self, credentials: RequestCredentials) -> AuthenticatedPrincipal:
    """Run the gates in order and return the principal, or raise the first no."""
    principal = await self._resolver.resolve(credentials)
    if self._guard is not None:
        await self._guard.require_admission(principal.scope)
    if self._budget is not None:
        await self._budget.enforce(principal)
    return principal

SubjectAdmission

Bases: Protocol

Whatever can answer "may this subject start a run?" — the inward guard.