22. Dispatcher
Context
A request says what faculty it needs; a model name does not say whether that faculty exists, accepts the necessary material, or is ready now. Local Soulstones and remote Portals change state independently of the request. LychD needs one admission office that can bind semantic demand to a live capability without acquiring the right to move the machine.
Decision
Dispatcher selects a capability and admits a temporary grant. It never starts, stops, loads, or evicts an Animator. Orchestrator owns those transitions; Graph owns whether a wait stays live or becomes durable.
The accepted general-service boundary is deliberately narrow:
typed demand → interface/profile declaration → fresh state → exact WARM grant → registered lease
A capability-bearing Animator is the route; there is no semantic provider-pair abstraction. Dispatcher emits its authoritative dispatch event only after lease admission. The delivered source implements the narrower v1 chat-model and toolset compatibility path described below; the general-service records and discriminated grant union remain Designed.
The live Animator is a capability/runtime handle, not a deployment document. It carries its exact Rune identity, Connector, and typed runtime surfaces while Containers, Bind, and Scribe retain physical compilation authority.
Capability Binding Cartography
The binding keeps five questions explicit: what was requested, what is declared, what was tested, what was observed, and what may be used now.
| Record | Office |
|---|---|
CapabilityDemand@1 |
Exact interface, operation, typed material, feature facts, invocation mode, and policy constraints required now. |
CapabilitySpecV2 |
Immutable declaration of Animator, interface, exact profile, operations, invocation mode, driver, and route shape. |
CapabilityEvidenceRef |
Reference to exact producer-attributed conformance evidence; neither admission nor current readiness by itself. |
CapabilityState |
Latest observation for that exact declared binding and, when required, operation. |
| discriminated capability grant | Temporary, WARM binding exposing only the callable surface for one admitted operation. |
Designed v2 keys are {animator}:{interface_id}:{profile_ref} where profile_ref includes a safe
stable id and exact immutable revision or content digest. They cross registry, Dispatcher,
Orchestrator, events, Workers, and Graph; after a pause a consumer re-fetches this canonical
identity, never a mutable handle. The operation remains explicit in demand and grant rather than
being hidden in profile identity.
Every component uses the closed slug grammar owned by Capabilities; colons, paths, whitespace, controls, and floating revisions are forbidden.
Delivered v1 compatibility projection
Current CapabilitySpec keys are {animator}:{family}:{model_id} and the single
CapabilityGrant class contains either an admitted Pydantic AI chat model with explicitly
declared agent-loop toolsets, or a non-empty tool_execution toolset surface. The closed families
are chat, vision, embedding, stt, tts, tool_execution, and rerank; model_id remains
required. Only chat and non-empty tool_execution can issue this v1 grant. The other family
labels remain routing metadata and fail closed at issue; they do not prove an executable STT/TTS
call, visual or embedding job, rerank call, Scout effect, host tool, or live session merely because
the vocabulary can name one.
Current [[models]] declarations may project into v2 only through an explicit compatibility map
from an exact family/model pair to an exact interface/profile. Persisted v1 keys are never silently
reinterpreted and an unknown family never becomes a generic service.
Interfaces, profiles, and material
An interface is the versioned semantic ABI, such as model.chat@1, echo.transcribe@1,
prism.image@2, or prism.scanner@1. A profile pins the exact model, weights, graph,
workflow, configuration, dependencies, licenses, formats, languages, limits, and conformance
evidence that implement it. Operations name admitted acts such as generate, edit,
transcribe, segment, or search.
A demand matches only its exact interface and operation, typed I/O contract references, every
required material facet and feature fact, invocation mode, and eligible profile. Unknown support
never admits work. Image-capable chat remains chat; speech emitted by a chat model is not thereby
an eligible synthesizer; tool is never a universal effect interface.
Declaration and observation
The v2 declaration holds animator/runtime/source kind, interface/profile, operations, typed I/O,
invocation mode, driver/dialect, feature facts, conformance evidence, resource envelope, dynamic
trait, and concurrency intent. The current v1 declaration retains family/model, input modalities,
tool support, generation, and context fields; connector-local model summaries select Chat or
Responses. The v1 dispatch demand cannot require streaming support or output modalities.
is_dynamic says a running local runtime may load a model; it is not readiness. The observed
phase is COLD, ACTIVATABLE, WARMING, WARM, ERROR, or UNKNOWN.
Soulstone declarations compile from Runes and selected adapters; probes update state and may fill
explicitly open runtime facts. An unknown local runtime stays passive unless an explicit adapter
and dialect profile give it semantics. "OpenAI-compatible" without a named, proved dialect gives
it none. Generic command planning synthesizes no Connector, model catalogue, or readiness.
The supported llama.cpp profile disables engine idle sleep: healthy fixed-runtime inventory can
survive sleep, and router autoload=false does not prevent a sleeping child from waking during
inference. Managed argument vectors begin with --sleep-idle-seconds -1; extra_args cannot
contain another sleep control. Passthrough vectors must begin with that exact pair, either at
the start for an image entrypoint or immediately after a non-option executable token. Later sleep
controls, underscore aliases, and equals spellings are refused. Admitted passthrough bytes remain
unchanged. Arbitrary wrappers that cannot honor this flag are outside this profile. This is command admission,
not attestation of a running engine, external mutation, or a shared endpoint's actual configuration.
Unregistered OpenAI-shaped aliases fail Soulstone capability-coverage validation before Bind or
registry publication. A Portal creates routes only for capabilities declared in its Rune; zero declarations
mean zero routes. Portal routes are non-dynamic and non-dedicated.
Their default probe = false makes no discovery egress, and a readiness probe never authorizes
private transmission. That unprobed route is projected as UNKNOWN and unverified, never fabricated
as WARM, so it cannot receive a grant.
OpenAI-shaped transport construction binds only the declared endpoint and API credential. It does not retain ambient SDK organization, project, webhook, admin credential, or custom-header configuration. Environment headers cannot override the declared credential or reach another endpoint. Model, readiness, and local control-plane HTTP clients ignore ambient proxy configuration and do not follow redirects. Model transport performs one physical transmission per invocation: implicit SDK retries are disabled, including after a lost acknowledgement. Agent validation repair remains an explicit model round under its existing budget; this transport rule authorizes neither another provider nor blind replay of an ambiguous effect. Model-client close and re-entry retain the same transport policy.
Runtime hydration
Soulstone adapter ownership is the adapter's exact declared runtime key; registration cannot claim
another adapter's runtime. Registry hydration is staged and rejects a runtime unless it retains the
exact input Rune and its name equals the Rune name. Every synthesized specification must then
name that Animator, the Rune's canonical runtime, source kind and concurrency intent, and the canonical
{animator}:{family}:{model_id} key before any snapshot is published.
An adapter constructs its runtime catalogue once per hydration. Capability synthesis consumes
that runtime's captured model summaries and generation defaults instead of re-reading a preset or
independently rebuilding the connector's catalogue. Bind uses the same construction boundary to
check capability coverage without probing or activating the runtime.
A model-local request policy is validated against the resolved runtime, exact model and Chat
surface during synthesis, before a registry snapshot is published. Its generation value is frozen
into the specification and grant; issuance must not reopen the Rune or recover settings from model
names. The hydrated model must retain the admitted Chat transport before the policy can become
outbound settings. A v1 Run still pins its capability key, not a durable declaration-generation
fingerprint: this policy grants neither live reconfiguration nor policy continuity across arbitrary
operator changes. Construct and qualify an immutable assembly for fresh admissions.
Endpoint hydration preserves which fields the operator supplied: allocating a port must not turn
omitted managed-command defaults into declarations that conflict with an explicit exec command.
Probe completeness and invalidation
A probe is a total observation of the exact requested capability-key and operation set. Duplicate, missing, or foreign keys are contract failures; a successful result replaces that Animator's cached states as one operation, while an exception, cancellation during the probe, or malformed result invalidates the affected prior observations. A failed full-registry refresh invalidates the full cached observation set rather than preserving stale warmth. Initial hydration probes the complete staged snapshot and publishes neither runtime nor state until every result validates, so a failed first probe leaves the registry retryable. Portal egress probing is selected only by the exact Portal definition's typed strategy.
Resolution
Candidate selection
Designed resolution receives CapabilityDemand@1, run and station-attempt identity, deadline, and
priority. It removes ineligible declarations and orders the rest deterministically under
an admitted selection policy. This is readiness matching, not a judgment of quality, price,
privacy, or correctness.
Current lease_grant retains its narrower family/model/modalities/tools
signature, an optional exact capability_key constraint, and deterministic
open/non-error/active/warm/name/key order. Cached observations rank eligible routes; they are not
permanent denial. The exact key intersects every other demand constraint; it cannot bypass readiness, drain
admission, or Portal quarantine. A model alias alone still denotes an eligible pool. An unknown,
incompatible, or unavailable exact key never substitutes another candidate.
Bridge preference at admission
The bounded revision-2 Bridge preference ranks only
the two configured literal registry keys before a fresh Run is admitted. Validate both complete
declarations before probing: each must have SourceKind.SOULSTONE, family CHAT and
supports_tools = true. Zero-weight routes are disabled, not exempt from declaration validation.
For positive-weight routes, perform one successful direct
refresh_capability_states_for_animator batch per distinct Animator and consume its returned
immutable states. A complete Animator batch may include a zero-weight capability sharing that
Animator; its phase/time are omitted from the retained decision and it remains ineligible. Never
substitute cached observations through a refresh-or-cached helper.
The complete probe batch has one fixed five-second cooperative timeout and no retry.
Timeout, cancellation, malformed observations or operational probe failure abort admission with
content-free public refusal codes; an earlier successful route is not selected after a later
probe fails. Existing adapters retain ownership of probe cancellation and cleanup. Five seconds
does not establish a hard process, network or cleanup containment limit.
After all probe awaits, recheck that the validated declarations are unchanged and read current
lease admission. A changed declaration aborts admission. Capture each Animator's admission
generation before its probe; a changed generation at the final check excludes its routes with
the safe readiness_changed code, even if admission has reopened. Only a positive-weight route
with a successfully observed WARM phase and currently OPEN admission is eligible. Other
successfully observed phases and closed admission are bounded exclusions. Select the greatest
weight among eligible routes, breaking a tie by ascending canonical key; an empty eligible set
refuses admission without activation, grant preparation or model entry.
Retain server-observed times and the bounded observations under Configuration's custody law. The batch is not an atomic cross-Animator readiness snapshot or a reservation. It cannot promise that the selected route will remain ready through persistence, queueing or execution. Existing exact-key Dispatcher issue and generation checks still apply; execution may enter Stasis or refuse, and never substitutes the other preference route. This policy changes neither grant, provider-entry, cleanup nor Bridge call/tool/consent/token-budget semantics.
Refresh the selected route
An invalidated or absent cached observation ranks as UNKNOWN, so the selected
declaration can be freshly observed on a later request. It never recovers cached warmth.
An eligible cached ERROR ranks behind other candidates with the same admission state and is
freshly observed when selected. Recovery therefore needs no unrelated transition or polling
service. A fresh ERROR still refuses the request without grant or hardware transition; v1 does
not retry another candidate after its chosen route fails.
The chosen record is refreshed immediately before issue. Capability specifications, observations, generation profiles, and model summaries are frozen value objects with immutable nested fields. Registry and adapter projections may share those values; ordinary consumer mutation cannot rewrite the canonical declaration. Animator Runes freeze group membership and both explicitly supplied and omitted environment/secret maps. Inventory collections use immutable sequences. These in-process value contracts are not a sandbox for extension code.
| Observation | Result |
|---|---|
WARM, admission open, executable v1 surface admitted |
Issue and register a grant. |
WARM, metadata-only or empty v1 surface |
CapabilityUnavailable. |
COLD/ACTIVATABLE/WARMING, dedicated |
HardwareTransitionRequired. |
| Those phases, shared or non-managed | CapabilityUnavailable. |
ERROR |
Unavailable with observed reason. |
UNKNOWN |
Re-probe; unavailable if still unresolved. |
| Drain closes during issue | Transition required, and only this race is translated. |
Refusal and transition signals
Known metadata-only v1 families are refused before readiness probing or a drain wait: hardware convergence cannot create their missing executable surface. The final registry issue probe can observe a different phase from Dispatcher's earlier probe; its typed readiness failure returns that exact observation to the same phase decision table. Hydration, policy, and malformed-probe failures remain ordinary failures and never become hardware requests merely because issue failed.
The transition signal contains capability key, Animator name, and optional ready estimate—no
connector, model, lease, or service handle. Graph may release its edge, ask Orchestrator to
converge, and dispatch afresh. Dispatcher never calls activate_capability or await_warm.
The Grant Lease Doctrine
Registry issue permits only a WARM record. The designed discriminated union exposes one of:
ModelGrant: a Pydantic AI model and admitted agent-loop toolsets;CallGrant: one typed bounded call driver;JobGrant: typed submit, status, cancellation, result, and reconciliation surfaces; orSessionGrant: one typed, bounded, epoch-fenced live-session driver.
Every variant contains the exact specification, operation, warm observation, lease identity, holder, issue time, scope, and only the live surface it admits.
Current source delivers one frozen
v1 compatibility grant: chat must hydrate its Pydantic AI model and receives agent-loop toolsets
only when supports_tools = true; tool_execution must hydrate at least one toolset and receives
no model. All other v1 families fail closed because no typed executable surface exists. The grant
does not expose its Animator or Connector. Specifications and observations share immutable nested
values; only explicitly admitted model or toolset handles remain live process objects.
The registry creates the identity; Dispatcher registers it in the process-local LeaseLedger.
Its context manager releases on ordinary exit, body failure, and observation failure. Duplicate
ids are defects. A closed drain gate or fresh dedicated COLD/ACTIVATABLE/WARMING
observation turns into Stasis; unknown, erroneous, shared, or non-readiness issue failures do not.
The same scope owns the model's provider context. It closes the provider before releasing the
lease, including caller cancellation and refusal during admission; provider-profile adapters
forward this lifecycle to their transport. A cached, model-free Agent owns no grant client.
Drain truth is absence of ledger leases on an Animator. Admission closes before drain waits, so
new work cannot enter an eviction set. A completed drain and reopen also invalidates grant
preparation that began before that drain. Dispatcher captures the Animator's process-local
admission generation before asynchronous grant issue or provider entry; the ledger checks that
generation and open admission together before registering the lease. A changed generation returns
the same handle-free hardware-wait signal after provider cleanup, without publishing a dispatch
event. Unrelated Animators retain their own admission generations.
A run waiting for its remedy owns no lease. expires_at is
recorded but unenforced: there is no renewal or distributed stale-grant fence. Grants contain
trusted live objects and may not enter Graph state, persistence, or delegated processes.
From a grant to an enduring effect
For a bounded immediate call, the lease ends with that call. Before any local or remote asynchronous
effect is first submitted, execution ownership must transfer to a persisted
ServiceJobAttempt@1; attempts on managed resident or scarce local substrate additionally require
an Orchestrator-visible exact reservation and fence. Live work uses its domain-owned bounded
session record; no common
SessionAttempt is accepted yet. A process-local lease alone cannot
prevent duplicate remote effects or fence local residency. Workers
(14) owns that Designed handoff.
Durable Content and ArtifactRef
The Designed content path requires Runs and checkpoints to name content with ArtifactRef, never
embedded bytes: identity, sha256: digest, media type, byte size, and
public/internal/private/restricted classification. Media-type projection to input modality
for matching remains Designed.
Current code defines this immutable metadata shape and carries references in delegated-job
requests and results. Ordinary Intent and Bridge admission remain text-only; they neither carry
artifact references through the Run ledger nor infer required modalities from media types.
Dispatcher filters explicitly supplied modality requirements. A separate, unregistered
trusted-local custody adapter provides bounded
retention under an injected current authorizer. Bridge artifact admission, credential-backed
authority, and provider materialization remain separate work.
Explicit local embedding compatibility profile
An exact configured embedding family/model pair may additionally declare an immutable
model.embed@1 profile. This does not change lease_grant: unprofiled embedding labels and
embedding requests through the chat/tool grant path still refuse before readiness or host work.
The separate lease_embedding entry requires the canonical capability key, profile digest and
operation (embed_document or embed_query). It admits only local Soulstones, reuses fresh
issue-time readiness, drain generations and lease accounting, and exposes only a bounded driver.
Provider entry precedes lease registration; cleanup completes before release, including cancellation.
A driver cannot execute outside its entered lease or execute another operation than its grant.
The first explicitly selected profile is one fixed Qwen3-Embedding-0.6B Q8_0 artifact and llama.cpp b9445 dialect, with last pooling, 1024 dimensions and L2 normalization. Its immutable manifest binds model/image/build digests, exact query/document rendering, tokenizer options, conformance receipt and input/output/deadline bounds. It accepts one input per call, at most 4096 rendered UTF-8 bytes and 511 runtime tokens. Oversize input refuses; truncation is forbidden. Runtime configuration selects a managed single-model command with no passthrough, router, environment, model or profile overrides. Configuration and a prior conformance receipt establish admission, not fresh attestation of a mutable externally replaced process or artifact.
A source-bearing call requires a current-authority callback immediately before tokenization and embedding transmission. Source eligibility and stale-completion fencing remain the caller's domain obligations; no database lock spans runtime work. The local dialect accepts only a literal loopback HTTP endpoint, disables ambient proxies and redirects, bounds raw response bytes before parsing, and validates indexed output identity, count, dimension, finite numbers, nonzero norm and usage. Returned execution values contain vectors and digests, not original text or raw provider responses. Errors expose safe codes. No Portal, general SpecV2, detached job, semantic recall, ANN or training operation is authorized by this compatibility profile.
The fixed profile requires an explicit port and literal-loopback base_url so it does not
inherit hostname resolution or generic endpoint allocation. For example, a local Soulstone
may select embedding_profile = "qwen3-06b-q8-b9445@1", port = 8080,
base_url = "http://127.0.0.1:8080/v1", model_path = "/models/embedding.gguf", and
quadlet.image = "ghcr.io/ggml-org/llama.cpp@sha256:39f4f2c5fd4537f85208f905e70269b5b691fbc6de00fd916c37a60a710b7d52".
The operator supplies the public artifact through the existing mount configuration. Model path,
image and profile are configured admission evidence: replacing a mounted file is not detected by
health/inventory probes. The retained public manual fixture in
tests/fixtures/embeddings/qwen3-06b-q8-b9445.json
is dialect qualification, not fresh runtime attestation or proof of Orchestrator activation.
Its laboratory RLIMIT and network isolation do not become general deployment resource guarantees.
The output scalar encoding is float32-le: provider numbers are explicitly projected to IEEE754
binary32, then checked for finite values, dimension 1024 and L2 norm within 1e-4, without
renormalization. Vector digests hash the concatenated little-endian binary32 bytes. This same
canonicalizer is required at a durable pgvector handoff and after reload; JSON decimal formatting
is not the storage identity. Receipts bind vector digests and input/rendered digests without raw
source text or duplicate vector coordinates.
A driver closes admission and joins or cancels its outstanding requests before Dispatcher releases the lease. Failing or cancelled driver entry owns its own partial cleanup; the fixed driver entry has no suspension. Safe refusal codes replace provider bodies and transport exception causes.
Policy boundary
Selection is mostly a future enforcement seam, not a complete policy engine. One coarse rule is
delivered now: every SourceKind.PORTAL candidate fails closed before grant, including direct-key
dispatch and direct registry issue, because no typed egress admission path exists. This quarantine
is not privacy-safe Portal operation. Sigil visibility, Portal secure mode, Toll arbitration, Censor/Privacy
Cut/TransformationReceipt/Egress Gate, unsupported-modality planning, A2A, and delegated-agent
choice are unwired. They must compose one typed, fail-closed path before grant; none may create an
alternate route around Dispatcher.
Security requires both admission before a Portal grant and a decision over the exact canonical payload immediately before transmission. Dispatcher will compose those decisions; it does not transform data or currently admit any Portal grant. A future path must not allow retry, fallback, delegated child, or consent to reuse an obsolete verdict.
Declaring and reading capabilities
Use Capabilities for declaration formats and the meaning of observed readiness. The guide relates these records to the capability an operation actually needs and distinguishes the current compatibility surface from the general-service design.
Consequences
Accepted
- Requirements, observed readiness, usable runtime handles, and drain accounting are separate.
- A hardware wait is handle-free and cannot deadlock on its own lease.
- Local and remote routes share typed grant law without sharing lifecycle authority.
Cost
- Registry and lease coordination are process-local.
- Order ignores quality, price, privacy, and Sigil visibility; Portal sources are quarantined and incomplete probes can refuse a viable local route.
- The matcher picks one candidate and does not score or explain alternatives.
Verification
Current Dispatcher unit tests cover v1 matching, deterministic preference, generation settings, and frozen compatibility grants. The current dispatch decision table covers every readiness row, grant/drain race, event ordering, and release on failure; registry, Portal, adapter, and lease tests cover v1 synthesis, fresh pre-issue probing, fail-closed family surfaces, opt-in probes, hydration, and drain accounting. The fixed embedding profile additionally has configured registry/Dispatcher HTTP integration tests for exact wire bytes, bounded responses, stale authority, cancellation and float32 identity, plus a retained manual dialect fixture. General interface/profile catalogs, grant variants, service attempts, and capability-set placement remain Designed. State of Work owns delivery claims.