symfonic.services.switching.ports¶
ports ¶
DMC-1 — the one binding port, declared once (CON-P, CON-S-3).
BindingSource is the entire seam between "which generation governs this
invocation?" and the machinery that answers it. The facade compiler and the
admission controller consume this protocol; neither ever learns whether a
control plane or a compiled-in static vector is behind it, which is what makes
DMC-8's "no third mode" enforceable — a new deployment shape is a new
implementation of this protocol or it is an ADR.
TA8.54 declares the second name here, and it is the same seam asked in the
other direction: :func:~symfonic.services.switching.invocation_profile.resolve_legacy_pin
answers "which generation governs this build?" with a frozen value object and
tells the caller nothing about how it was decided. It is re-exported from this
module rather than imported directly because dependency-matrix.md gives
facade-compiler -> runtime-service the cell port, and
symfonic.agent.cutover.legacy_pin — the composition root that builds the
switchboard's pin — sits on the facade side. A narrow function over value
objects is what that cell licenses; reaching into invocation_profile
directly is what it forbids.
BindingSource ¶
Bases: Protocol
Resolve a route bundle's binding. Async-first, read-only, fail-closed.
describe ¶
resolve
async
¶
resolve_epoch
async
¶
CUT-SS-7 — the binding an earlier admission ran under.
Resume paths need it: a pin names an epoch, and placing the resumed work back on that epoch's vector is the only way a switch that landed while the work was paused does not silently follow it.
Source code in src/symfonic/services/switching/ports.py
LegacyPin
dataclass
¶
LegacyPin(capabilities: frozenset[str] = frozenset(), package_version: str = '', vector_hash: str = GenerationVector().vector_hash, source: str = 'release-static', binding: str = 'binding[static,unbuilt] (no profile was constructed)')
Which capabilities a build holds on their legacy bodies, and on whose say.
source is StaticBindingSource's own CUT-PIN-3 vocabulary:
release-static when the line's published contract is what put a
capability on legacy, local-override when the adopter pinned it. The
two are not interchangeable and an operator reading describe() at 03:00
is owed the difference.
resolve_legacy_pin ¶
resolve_legacy_pin(capabilities: Sequence[str] | None, *, package_version: str, legacy_defaults: frozenset[str] = frozenset()) -> LegacyPin
Build the release profile and the binding source, and read the pin back.
This is the construction site. Both objects are built here, on every call, including the call an unpinned build makes — a construction reachable only when somebody opts in would be the original finding wearing a number.
Refusals propagate rather than degrade, and each keeps its own name:
- an empty or unrecognised pin — :class:
ConfigurationErrorfrom :func:legacy_pin_vector; - a pin on a release at or past
FIRST_REJECTING_RETIREMENT_VERSION—LegacyPinRetiredErrorfromStaticBindingSource._apply_override, carrying the migration procedure; - an undocumented combination, or one the constraint set rejects — the
ConfigurationError/ConstraintViolationErrorthat source already raises.
Nothing here answers "unpinned" to a bad pin.