Skip to main content

Behavioral signals

Behavioral signals are label-free per-entity scores computed from the same forward pass that produces the entity embedding — no labels, no extra training, no extra latency budget. They appear in the entity state's signals object when (and only when) the serving bundle enables them:

{
"signals": {
"behavior_surprise": 0.91,
"propensities": {
"session.start": 0.62,
"match.result": 0.31,
"purchase.completed": 0.04
}
}
}

behavior_surprise​

How atypical the entity's recent event sequence is under the model's own next-event objective, as a population-calibrated value in [0, 1].

  • The raw score is the mean next-event-type negative log-likelihood over the last K transitions of the scored window (K is pinned in the bundle, default 64).
  • The raw score is then mapped through a count-stratified population reference built at evaluation time: entities are compared only against test-split entities with a similar history length, so 0.91 reads as "more surprising than 91% of comparable entities" — never as a proxy for how many events the entity has.
  • The key is omitted (never null) when the scored window holds fewer than 2 events: there is no transition to score yet.

A player who suddenly switches from short casual sessions to long ranked ones spikes behavior_surprise; a shopper whose browse-buy rhythm is business-as-usual stays low.

propensities​

Calibrated probabilities that the entity's next event is each of a bundle-configured shortlist of event types (up to 32), keyed by your event type names exactly as you ingest them.

How to read the numbers: the model scores the shortlist by renormalizing its next-event logits over the shortlist only — a P(next = X | next is one of the shortlist)-shaped quantity — and each type's monotone calibration map (fit at evaluation time against the empirical rate of "the next event is X") re-anchors it to the unconditional rate. Read "purchase.completed": 0.04 as "a ~4% chance the next event is a completed purchase". Values are calibrated independently per type and need not sum to 1.

Two shortlist types that collide under the model's hashed event-type vocabulary share their raw score (the collision is recorded in the calibration artifact); their calibrated values may still differ.

Enabling signals​

  1. Evaluate the model — signals evaluation is on by default from Phase 2 and adds a signals block to the eval report (config, the fingerprinted signals_calibration.json artifact, and the non-mandatory S1/S2 quality checks). The default shortlist is the 16 most frequent next-event types on the test split; the evaluation request can override the shortlist and the surprise window K.

  2. Create the bundle with signals enabled:

    curl -X POST "$TESSERA_API_BASE/models/$MODEL_ID/bundles" -H "authorization: Bearer $TESSERA_API_KEY" \
    -H "content-type: application/json" -d '{"signals": {"enabled": true}}'

    This requires the pinned eval report to carry the signals block (else failed_precondition with detail signals_not_evaluated), copies its config verbatim into the bundle's runtime.signals, and pins the calibration artifact — re-verified byte-for-byte at every slot activation, like every other artifact.

  3. Activate the bundle on a slot. Scorers now write signals in the same state update as the embedding; state reads return it as shown above.

An absent signals request field — or enabled: false — leaves signals fully disabled: nothing is loaded, nothing is written.

To attach per-prediction evidence or calibrate surprise against peers, run a signals evaluation first: see Prediction evidence and peer frames.

Quality checks (S1/S2)​

The eval report records two non-mandatory checks under signals.checks — they never gate promotion:

  • S1 — surprise/count invariance: the rank correlation between behavior_surprise and history length must stay low (|ρ| < 0.3); the count-stratified reference is what keeps it low.
  • S2 — propensity calibration: expected calibration error of the calibrated propensities on a held-out half (max ECE ≤ 0.05 over types with enough holdout data).

behavior_surprise is a score, never a label: it is not supervision input and never appears in training.