This is the staff-only portal walkthrough — onboarding a client’s ML model. If you’re
looking for tenant setup (organization + workspace + owner account), see
Client Provisioning instead; the two are separate
systems with separate identifiers (this guide’s
client_id is not an organization_id).01 — Create the client profile
Requires
staff:fde or higher, feature internal.provisioning.primary_format must be one of xlsx_csv, json, parquet, hl7_fhir. This call is
idempotent on tenant_slug: a repeat call with the same slug returns 200 with the
existing profile rather than creating a second one; a genuinely new client returns 201. Under
the hood this also provisions a bare workspace (no users/memberships yet — the portal collects
no owner email at this stage) that every later stage writes into.client_profiles.status starts at draft.02 — Register and upload historical data
Register a data source, then upload the file:
kind is one of upload, s3, database. For database, the request accepts
credential_ref only — any field that looks like password/secret/token/api_key is
rejected with a 422; raw credentials are never stored on this row. Uploads are capped at
UPLOAD_MAX_BYTES (50 MB default); a larger file returns 413.Then validate — this is where the corpus actually becomes usable:schema_map maps your file’s column headers to issue-envelope@1 fields; unmapped columns
survive as attributes. Validation does four real things in sequence: parses the uploaded
xlsx/csv, materializes issue-envelope@1 objects, writes envelopes.jsonl to the upload store
— and then ingests and forges each envelope into a real issues row in the client’s
workspace (bounded concurrency, best-effort — a row-level failure doesn’t fail the whole
request). This last step is what makes training in stage 04 actually have a corpus to train
on; without it, an uploaded 250-row file would train on zero issues. client_profiles.status
flips to data_validated only after this succeeds.03 — Choose training configuration
{"data": [...]}), each optionally carrying param_ranges for a bounded-slider UI. Pick a
preset — this stage is a read; nothing is submitted yet.04 — Train the model
Requires Or poll
staff:ml_eng or higher.kind is initial or retrain. This freezes the submitted params (with a hash) and launches
training in the background; client_profiles.status flips to training. Watch it live:GET /v1/provisioning/training-runs/{run_id}/events without the SSE header for a
cursor-paginated log. On success, client_profiles.status becomes trained and the training
run’s manifest carries the wm@2 artifact reference (if WM2_ARTIFACTS=true).05 — Evaluate
/evaluate while an eval already exists is idempotent — it returns the existing row
(200) rather than starting a duplicate. Once eval_run.status is passed:As of the 2026-07 calibration, a genuinely good clustering passes on real data — the
e_sil/e_hold floors were recalibrated against a real qwen3-embedding corpus and E-AGR
(the Leiden↔DSU agreement gate) is now advisory, because the union-find crosscheck it reads
single-linkage-chains real text into one blob and carries no signal about partition quality
(see Evaluation Gates → The calibration
gap). The remaining hard gates
(E-SIL, E-HOLD, E-COV, E-DEG, E-DET, E-PROBE, and E-GOLD when a golden set is
uploaded) can still legitimately fail on genuinely sparse or low-quality pilot data.06 — Host an inference service
Requires Refuses with
staff:ml_eng or higher, feature internal.host_manage (plan="pro" additionally
requires staff:admin).409 if the artifact isn’t eval_passed/approved/overridden (the
EVAL_REQUIRED guard). On the default FREE inference profile this registers routing to the
shared cluster-inference service — no Render API call is made; see
Inference & Queue for exactly what FREE vs. PROD does
and does not do.07 — Go live
client_profiles.status to live. Check the go-live
summary:content_hash, eval.overridden, and real flow.{ingest, assigned,outliers} counts — honest zeros if nothing has flowed through yet, never fabricated.Promoting a later version (shadow → canary → active)
A version doesn’t have to go straight toactive. For a retrain, or a candidate you want to
compare against live traffic first:
promote is distinct from activate (step 07 above) — it flips which model version is the
workspace’s registered active model, not which service receives traffic. See
Model Lifecycle for the full state machine.
Related pages
- Provisioning Portal — the RBAC model behind every step above
- Model Lifecycle — the state machines these calls drive
- Evaluation Gates — what stage 05 actually checks, and the calibration gap
- Inference & Queue — what “hosting” means on FREE vs. PROD