Assignments
Assignments are the recommended way for business workflows to run models. An
assignment has a stable key, such as default or forecast, and points to one
active model version in a domain or service scope.
Why assignments exist
Section titled “Why assignments exist”Without assignments, consumers would need to know the exact model_id and
model_version for each workflow. Assignments let the platform change the model
version behind a stable key while callers keep using the same route.
Scopes
Section titled “Scopes”| Scope | Route shape | Use when |
|---|---|---|
| Domain | /v2/clients/{client_id}/domains/{domain_id}/assignments/{assignment_key} | The capability belongs to the domain as a whole. |
| Service | /v2/clients/{client_id}/domains/{domain_id}/service/{service_id}/assignments/{assignment_key} | The capability belongs to one initialized service. |
Active and archived revisions
Section titled “Active and archived revisions”Each assignment key has one active revision. Creating a new revision archives the previous active revision for the same key. Historical jobs remain linked to the revision that launched them.
flowchart LR
Key[assignment key forecast] --> Active[active revision]
Active --> ModelVersion[model version]
NewRevision[new revision] --> Active
Active --> Archived[previous revision archived]
Running jobs
Section titled “Running jobs”Run inference through the assignment job route. The response returns a job_id.
Poll GET /v2/jobs/{job_id} to read status, output, and errors.
Assignments keep the caller insulated from model-version changes, but they do not hide async behavior. Always treat assignment execution as a job lifecycle.
Assignment blocked by service features
Section titled “Assignment blocked by service features”When you create or update a domain assignment (POST or PUT on the domain assignments collection or keyed route), the API checks every non-departed service in the domain. If any service’s provided_features cannot be resolved against the target model version’s frozen feature schema, the request fails with HTTP 422 and a structured body (not the usual { success, message } envelope). Other semantic failures on those routes — for example, an invalid model reference — still use the standard error envelope.
{ "error": "cannot assign model version 3: 2 service(s) have incompatible provided_features", "blocking_services": [ { "service_id": "svc-a", "feature": "cabin_category", "value": "unknown" } ]}| Field | Meaning |
|---|---|
error | Human-readable summary of why assignment was blocked. Do not parse for control flow. |
blocking_services | Services to fix before retrying — each entry names the service, the feature that failed validation, and the stored value. |
Remediation:
Retry the domain default assignment (POST or PUT) with optional service_updates to patch
provided_features for specific services in the same request. Each entry uses static_features
(same field name as service init/PUT); keys are shallow-merged into the stored object and validated
only against the target model version’s frozen feature schema:
{ "model_id": "example-model", "model_version": "2.0.0", "service_updates": [ { "service_id": "svc-001", "static_features": { "route": "route-a" } } ]}The API validates all service_updates, then pre-checks every other non-departed service. If any
still block, you get the same 422 with blocking_services. When none block, it applies the
patches, upserts the assignment, and re-resolves resolved_features for all non-departed services
in one transaction.
service_updates is only allowed on domain default assignment upserts (not service-scoped
routes or other assignment keys).
Depart services whose departure_datetime is in the past when they should no longer participate
in the domain freeze check.
For general maintenance under the current default freeze (not assign-time remediation),
PUT .../service/{service_id} can update stored provided_features on individual services.
Changing features on services does not change an already-frozen model version. If you need a different feature contract on the model itself, register a new model version.
Service-scoped assignment routes do not perform this domain-wide freeze check; only domain
assignment upserts can return blocking_services.
Live domain features vs the frozen schema
Section titled “Live domain features vs the frozen schema”Live domain_features is the next-train draft — the contract the next model version will be
trained against. It is not the contract that currently-deployed services are running under;
that one is the frozen schema on the active default assignment’s model version.
PUT /v2/clients/{client_id}/domains/{domain_id}/features is persist-only. It writes the new
feature definitions and returns { features: [...] }. It does not re-resolve, re-validate, or
re-fire inference for any existing service. Live edits cannot silently change the meaning of
stored provided_features or resolved_features for a deployed model.
To propagate new feature shapes onto deployed services, use one of:
| When | Route |
|---|---|
| Roll a new model version’s contract onto the whole domain | Domain default assignment swap (POST or PUT) — optionally with service_updates to patch incompatible services in the same call. |
Adjust one service’s static_features under the current freeze | PUT /v2/.../service/{service_id}. |
| Re-fire inference per service without changing their stored features | POST /v2/.../services/init — dispatches a fresh assignment-linked inference job per non-departed service using the stored resolved_features, then returns { dispatched_services: [...] }. |
Multiple primary products
Section titled “Multiple primary products”Ferry-style domains may sell several capacity types on one sailing (seats, cabins,
lane metres). Use one service per departure and service-scoped keys named
{primary}_{capability} (e.g. cabin_recommendation). Keys are a tenant naming convention, not
a separate platform type — see Multiple primary products.