Skip to main content

Activate and batch score

Three objects separate a trained model from served scores, and each exists for a reason:

  1. 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.
  2. A deployment slot is the stable address (quickstart) your integrations read from while bundles rotate underneath.
  3. 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.

07-activate-and-score.sh
#!/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).

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.