Activate and batch score
Three objects separate a trained model from served scores, and each exists for a reason:
- A promotion bundle packages the model with the fingerprint of every input that shaped it — contract version, leakage policy, encoders, tokenizer, dataset, eval report. Creation requires no blocking gate and, when a quality gate failed, an exact reasoned acknowledgement permitted by the project's promotion policy.
- A deployment slot is the stable address (
quickstart) your integrations read from while bundles rotate underneath. - Activation re-verifies every pinned fingerprint against storage — mismatch means refuse to serve.
Then a batch refresh scores every user as of a cutoff:
Step 7 refuses blocking or unavailable promotion decisions. If the model needs
an advisory acknowledgement, it also refuses by default: review the evaluation
from Step 6 and the current model's promotion.advisory gate IDs first. To accept
that specific tradeoff, set TESSERA_QUICKSTART_ACKNOWLEDGEMENT to a JSON object
with the exact gate IDs and your non-empty decision reason before running either
example. For example, after reviewing a calibration warning, the value could be
{"gates":["G2"],"reason":"Reviewed calibration diagnostics; accepted for this test"}.
Unset the variable afterwards. Never copy an acknowledgement to an unreviewed
model. If the current verdict is already promotable, the examples send no
acknowledgement. The server rechecks the latest report and policy inside bundle
creation, so a changed gate set or a blocking gate still refuses promotion.
The local docs and Phase 1 test harnesses explicitly configure a G2-only acknowledgement for the reduced CPU tutorial fixture, with a recorded lifecycle verification reason. This does not establish production model quality, change gate thresholds, or apply to any run outside these local harnesses.
- curl
- Python SDK (planned)
#!/usr/bin/env bash
# Quickstart step 7 — bundle the model, create a slot, activate, batch score.
set -euo pipefail
: "${TESSERA_API_BASE:?e.g. https://api.staging.tessera.zone/v1}"
: "${TESSERA_API_KEY:?your tsk_test_… key}"
: "${TESSERA_STATE_DIR:=.}"
AUTH=(-H "Authorization: Bearer $TESSERA_API_KEY")
MODEL_ID="$(cat "$TESSERA_STATE_DIR/model_id")"
# --- 1. promotion bundle: pins every artifact by fingerprint ------------------
# Optional, explicit acknowledgement after reviewing this model's evaluation.
# The registry still refuses blocking gates and rechecks the exact advisory set.
MODEL="$(curl -sS "$TESSERA_API_BASE/models/$MODEL_ID" "${AUTH[@]}")"
BODY="$(printf '%s' "$MODEL" | python3 -c '
import json, os, sys
model = json.load(sys.stdin)
promotion = model.get("promotion") or {}
verdict = promotion.get("verdict")
raw = os.environ.get("TESSERA_QUICKSTART_ACKNOWLEDGEMENT", "")
ack = json.loads(raw) if raw else None
if raw and (
not isinstance(ack, dict) or set(ack) != {"gates", "reason"}
or not isinstance(ack["gates"], list) or not ack["gates"]
or not all(isinstance(gate, str) for gate in ack["gates"])
or not isinstance(ack["reason"], str) or not ack["reason"].strip()
):
raise SystemExit("Acknowledgement must contain gate IDs and a non-empty reason")
if verdict == "promotable":
print("{}")
elif verdict == "needs_acknowledgement":
# No input means no consent: let the API return its refusal and request ID.
# The operator names the advisory gates they accept; the bundle acknowledges
# those that are failing now, and the API refuses any failing gate left out.
gates = [gate for gate in (ack or {}).get("gates", []) if gate in promotion.get("advisory", [])]
print(json.dumps({"acknowledge_gates": {"gates": gates, "reason": ack["reason"]}} if gates else {}))
else:
raise SystemExit("Promotion is blocked or unavailable; inspect the model and evaluation")
')"
BUNDLE="$(curl -sS -X POST "$TESSERA_API_BASE/models/$MODEL_ID/bundles" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-bundle" -d "$BODY")"
BUNDLE_ID="$(printf '%s' "$BUNDLE" | python3 -c '
import json, sys
bundle = json.load(sys.stdin)
if not bundle.get("bundle_id"):
raise SystemExit("Bundle creation failed: " + json.dumps(bundle, sort_keys=True))
print(bundle["bundle_id"])
')"
printf '%s' "$BUNDLE" | python3 -c '
import json, sys
bundle = json.load(sys.stdin)
print("bundle %s pins contract v%s" % (bundle["bundle_id"], bundle["pins"]["contract_version"]))
'
# --- 2. a deployment slot: the stable name scores are served under ------------
SLOT="$(curl -sS -X POST "$TESSERA_API_BASE/slots" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-slot" \
-d '{
"environment": "test",
"name": "quickstart",
"entity_type": "user",
"mode": "live",
"scoring": "batch_only"
}')"
SLOT_ID="$(printf '%s' "$SLOT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["slot_id"])')"
# --- 3. activate: re-verifies every pinned fingerprint before serving ---------
ACTIVATED="$(curl -sS -X POST "$TESSERA_API_BASE/slots/$SLOT_ID:activate" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{"bundle_id": "'"$BUNDLE_ID"'"}')"
printf '%s' "$ACTIVATED" | python3 -c '
import json, sys
slot = json.load(sys.stdin)
print("slot %s: active_bundle_id=%s" % (slot["name"], slot["active_bundle_id"]))
'
# --- 4. batch score every user as of the sample window's end ------------------
REFRESH="$(curl -sS -X POST "$TESSERA_API_BASE/slots/quickstart/refreshes" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-refresh" \
-d '{"cutoff": "2025-07-01T00:00:00Z"}')"
REFRESH_ID="$(printf '%s' "$REFRESH" | python3 -c 'import json,sys; print(json.load(sys.stdin)["refresh_id"])')"
for _ in $(seq 1 600); do
REFRESH="$(curl -sS "$TESSERA_API_BASE/slots/quickstart/refreshes/$REFRESH_ID" "${AUTH[@]}")"
STATUS="$(printf '%s' "$REFRESH" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')"
case "$STATUS" in succeeded|failed) break ;; esac
sleep 2
done
printf '%s' "$REFRESH" | python3 -c '
import json, sys
refresh = json.load(sys.stdin)
print(json.dumps({k: refresh[k] for k in ("refresh_id", "status", "entities_scored", "cutoff")}, indent=2))
'
Download quickstart/07-activate-and-score.sh — this exact file runs in CI on every change (hosts shown are for this environment).
"""Quickstart step 7 (planned Python SDK) — bundle, slot, activate, batch score."""
import json
import os
import time
from pathlib import Path
from tessera import Tessera
from tessera._generated import models
client = Tessera(base_url=os.environ["TESSERA_API_BASE"])
state_dir = Path(os.environ.get("TESSERA_STATE_DIR", "."))
model_id = (state_dir / "model_id").read_text().strip()
# Optional, explicit acknowledgement after reviewing this model's evaluation.
# The registry still refuses blocking gates and rechecks the exact advisory set.
model = client.api.get_model(model_id)
raw_ack = os.environ.get("TESSERA_QUICKSTART_ACKNOWLEDGEMENT", "")
ack = models.AcknowledgeGates.model_validate(json.loads(raw_ack)) if raw_ack else None
if ack is not None and not ack.reason.strip():
raise SystemExit("Acknowledgement must contain gate IDs and a non-empty reason")
promotion = model.promotion
body = None
if promotion is None or promotion.verdict == models.Verdict.blocked:
raise SystemExit("Promotion is blocked or unavailable; inspect the model and evaluation")
if promotion.verdict == models.Verdict.needs_acknowledgement and ack is not None:
# The operator names the advisory gates they accept; the bundle acknowledges
# those that are failing now, and the API refuses any failing gate left out.
failing = {getattr(gate, "value", gate) for gate in promotion.advisory}
accepted = [gate for gate in ack.gates if getattr(gate, "value", gate) in failing]
if accepted:
body = models.CreateBundleRequest(
acknowledge_gates=models.AcknowledgeGates(gates=accepted, reason=ack.reason)
)
bundle = client.api.create_model_bundle(model_id, body)
print(f"bundle pins contract v{bundle.pins['contract_version']}")
slot = client.api.create_slot(
models.SlotCreateRequest(
environment="test",
name="quickstart",
entity_type="user",
mode="live",
scoring="batch_only",
)
)
# Activation re-verifies every pinned fingerprint before serving.
activated = client.api.activate_slot(
slot.slot_id, models.SlotActivateRequest(bundle_id=bundle.bundle_id)
)
print(f"slot {activated.name} activated: {activated.active_bundle_id == bundle.bundle_id}")
refresh = client.api.create_slot_refresh(
"quickstart", models.RefreshCreateRequest(cutoff="2025-07-01T00:00:00Z")
)
for _ in range(600):
refresh = client.api.get_slot_refresh(refresh.refresh_id, "quickstart")
if refresh.status.value in ("succeeded", "failed"):
break
time.sleep(2)
print(f"refresh: {refresh.status.value} entities_scored={refresh.entities_scored}")
client.close()
Download quickstart-sdk/07-activate-and-score.py — this exact file runs in CI on every change (hosts shown are for this environment).
The refresh walks the event store per entity, rebuilds each user's window
as of the cutoff (only events with timestamp <= cutoff may influence a
state), runs the model forward, and writes one state row per user —
1,700 of them here. Refreshes are resumable, partition-checkpointed jobs;
re-running one can never regress a fresher state row (writes are fenced on
the event cursor).
This slot was created scoring: batch_only — the Phase 1 mode where state
is refreshed on your schedule. The same slot surface serves realtime
scoring when streaming scoring is enabled for a project.
Next: read the state.