Decisions
The decision-record anatomy (16 fields), deterministic policy replay, and outcome/calibration honesty.
Every engine call produces a DecisionRecord — one row in the append-only decisions ledger,
rendered to customers as: probability P that event obtains within horizon, conditional
on conditions, computed from input_hash, at confidence, with freshness per input
and calibration adequacy stated.
Record anatomy — the 16 fields
The ledger row mirrors the decisions table 1:1 (§1.8 DecisionRecord):
| # | Field | Meaning |
|---|---|---|
| 1 | decision_id | uuid PK — stable identifier across reads and replays |
| 2 | timestamp | when the decision was recorded |
| 3 | asset | BTC | ETH | SOL |
| 4 | chain | base (v1) |
| 5 | input_hash | provenance hash of the journaled inputs (idempotency key) |
| 6 | state_hash | hash of the feature state at decision time |
| 7 | feature_version | feature-engine version |
| 8 | question_version | signal definition version (S01..S11) |
| 9 | jev_version | judgment-engine version |
| 10 | probability | the recorded probability (0 = no claim made) |
| 11 | confidence | the recorded confidence (0 = no claim made) |
| 12 | policy_version | sealed ruleset that produced the verdict |
| 13 | decision | publish | monitor | escalate | suppress | insufficient_confidence | stale_input |
| 14 | action | none | record | alert | webhook | escalate_human — the vocabulary deliberately excludes any execution verb |
| 15 | payment_id | FK to the payments ledger (null on free surfaces) |
| 16 | outcome_id | one-shot link to the realized outcome (nullable) |
The action vocabulary excludes execution verbs by design: Tollbridge renders verdicts, not trades.
Replay semantics
Replay (POST /v1/decisions/{id}/replay, free) is deterministic and policy-only:
- The journaled decision inputs are re-verified against the ledger row's
input_hash, then re-evaluated under the requested sealed ruleset ({"ruleset_version": "1.0.0"}or the recorded default). - The response carries
{ decision_id, original_verdict, replayed_verdict, matched_rules, policy_version, deterministic: true }. - Inputs that cannot be verified →
409 REPLAY_INPUT_LOST— never a fabricated replay.
Model replay is out of scope in v1 — stated honestly. A live model re-run ("replay with the current model") would be a NEW decision, not a replay: model drift and refusal semantics change what jev would have said. Replays are policy-only by construction; a new decision costs a new payment and creates a new ledger row.
Outcome + calibration reporting
Realized outcomes link back to decisions one-shot (outcome_id), and the calibration service
reports bucketed reliability over the ledger:
- Calibration output is never silently self-tuned; every learned change ships as a sealed, published release with its measured proof — see Decision intelligence.
- Any bucket with inadequate sample size renders as "insufficient sample — no calibration claim" (the insufficient-sample honesty rule): a handful of outcomes is not a calibration curve, and Tollbridge will not pretend otherwise.
- Attribution keys (
event_definition_hash,jev_version,question_version,policy_version) keep every number traceable to the methodology that produced it.
Calibration in a served decision body
When a decision's number is reconciled with a frequency counted on the provider's own
market history, the served decision body carries a calibration block describing that
basis in plain terms:
"calibration": {
"basis": "measured_history",
"source": "the venue's own price history",
"observations": 7385,
"assets": ["BTC", "ETH", "SOL", "HYPE", "DOGE"],
"window_days": 208,
"starting_condition": "allow"
}observationsis how many historical outcomes the frequency was counted over.window_daysis the history's span (ornullwhen the source does not record one).starting_conditionappears only for a question whose number is conditioned on the account's state at the moment the decision was made.- The block is present only when a measured frequency was actually applied. A refusal, a question with no measurable frequency, or a disabled control omits it — absence is the honest signal, never a placeholder.
The calibration block reports the basis of the number; it does not change what the number
is. The probability stays the model's forecast, reconciled with measured history.
Honest refusals
Stale/degraded inputs, inadequate baselines and unavailable surfaces are 200 responses with
the refusal recorded as the decision — probability and confidence are 0 ("no claim"; the
decision field carries the truth):
| Recorded decision | Meaning |
|---|---|
stale_input | an input breached its staleness budget or arrived degraded |
insufficient_confidence | jev refused (insufficient_sample) or a degenerate baseline |
suppress | jev refused (out_of_scope / unresolvable_event) or the surface is unavailable |
A provider being down is NOT a decision — it surfaces as a typed error and records nothing.
Where decisions appear
- Deep decisions:
POST /v1/decisions— Decisions API. - Signal decisions: Market signals, Funding, Risk.
- Replay mechanics: Replay semantics.