GitHubBook a demoStart routing
Browse docs

The calibration lifecycle

The audited life of a qcal_ artifact — the four one-way states, the per-segment activation gate, the refit scheduler's five triggers, the recalibration log, and read-time invalidation.

Last updated

On this page

A fit produces a qcal_ artifact, but fitting is only the first event in its life. The artifact moves through a small, one-way lifecycle; exactly one of its states can license a claim; promotion is gated; a background scheduler keeps it fresh; and every move — including every refusal — is written to an append-only log. This page is the lifecycle end to end.

The four states

An artifact is content-addressed: its id is qcal_<compactTS>_<sha8> where the hash is taken over the fit’s own content, so a refit over the same window lands on the same id and a different fit is always a new id. The store keeps one <id>.json per artifact plus a manifest.json naming the active and shadow slots and every versions[]. Each artifact carries a status, and the status moves one way:

candidate → shadow → active → retired
State What it is Can it serve a claim?
candidate A fresh fit, inert. Writing one changes nothing else, which is what makes quality calibrate safe to run on a schedule. No
shadow Fitted and evaluated, but never served — the slot the scheduler populates so a fresh fit can be watched against production. No
active The one status that can license a probability claim. Activating an artifact retires the incumbent atomically. Yes
retired Terminal. A successor is a new content-addressed id, never the same bytes wearing a fresh status. No

Forward skips are legal — candidate → active is the ordinary operator action, and candidate → retired lets you discard superseded evidence — but nothing ever moves backward. The illegal moves are refused by name, each naming the from-state, the to-state, and the legal moves that remain:

  • active → shadow — demoting a serving artifact would leave the store with no active artifact and no record that one was removed. The honest move is to activate its successor, which retires it by name.
  • active → active — “already active” is information, not a no-op; silently succeeding would let an operator believe a promotion happened and write an audit row saying so.
  • retired → anything — a retired artifact is history.
The calibration lifecycle: candidate → shadow → active → retiredA one-way state machine. A fitted candidate moves to shadow, an operator activate moves shadow to active, and activation retires the incumbent so it moves to retired. The refit scheduler, fired as an edge by five named triggers, lands automatic refits in shadow under the PromoteShadow default and never promotes itself into the serving slot. A candidate may also skip straight to active.refit scheduler5 named triggers · edge-firedcandidatefresh fit · inertshadowfitted · never servedactivelicenses the claimretiredterminalPromoteShadowfitoperatoractivateretirecandidate may skip to active

The activation gate

Activation is the one transition that is gated. The rule is per segment: an artifact may be activated if at least one measured segment passed its own B.5 gate. Segments that failed serve nothing — but they do not block the ones that passed.

The strict reading — “every measured segment must pass” — is only ever a disclosure, and the reason is arithmetic. Requiring N independent segments to each clear a per-segment false-refusal rate β makes the artifact-level refusal rate 1 − (1 − β)^N: about 14% over three segments and 99.4% over a hundred. A real fleet is many segments by construction, so a strict gate would refuse a perfectly calibrated deployment essentially always. Nothing is weakened by the per-segment reading, because a segment that failed its own gate licenses nothing whether or not the artifact around it is active — the per-segment gate is where the safety actually lives.

So only two things are refused at activation: an artifact that measured nothing (a fit over an all-synthetic or all-thin window), and one whose every measured segment failed. Both refusals carry the full reliability report.

The refit scheduler

Calibrations go stale as traffic shifts, so a background loop — strictly off the request path, paced by a ticker that checks roughly every five minutes — decides when to refit. Five events can trigger a refit, and each one travels into the log as a named trigger from a closed vocabulary:

Trigger Fires when
drift_finding A registered drift detector reports that a segment’s population moved.
policy_epoch_change The policy fingerprint moved — the artifact was fit under an epoch no longer in force.
staleness The artifact passed the freshness horizon (30 days).
operator_request A human asked, with a reason that becomes the log entry’s detail.
scheduled_interval The configured refit_interval elapsed. (Omit it, or set 0s, and there is no periodic refit — the other four triggers are unaffected.)

Each trigger fires as an edge, not a level: once per (artifact, epoch), never once per tick. A policy-epoch change is a persistent condition; firing on the level would write one log entry per tick forever, and a log that grows without limit is an outage. A refit that failed is retried by the scheduled interval, which is the mechanism that already means “try again later.”

The scheduler’s default promotion mode is shadow. An automatic refit lands its fresh fit in the shadow slot — fitted, evaluated, never served — and stops. Promoting itself into the serving slot would be a routing change nobody approved. An operator promotes from shadow to active with tokentriage quality activate, and that activation is audited.

The recalibration log

Every lifecycle event appends one entry to recalibration.jsonl in the store — a fit, activate, shadow, retire, or invalidate — and so does every refusal of those, each classified applied or refused. A refusal is an entry, not an absence: a scheduler that logged its successes and swallowed its refusals would produce a log in which “the epoch moved and we refitted” and “the epoch moved and the refit failed for eleven days” are the same document, just with fewer lines.

The log is strictly append-only (entries are never rewritten in place) and every entry carries a monotonic Seq seeded from disk, so a restart is invisible and a gap at the head of a read is the honest disclosure that older entries rotated away. Each entry also requires a detail — a refused activation with no text is a refusal nobody can act on — so the trail records not just what happened but why.

Invalidation happens at read time

When a drift finding, the staleness horizon, or a policy-epoch change invalidates a calibration, the artifact’s bytes are never rewritten. They can’t be: the id is a content hash of the fit, so editing an entry and re-saving under the same id is exactly the corruption the store refuses.

Instead the invalidation is applied per segment, at read time. The affected segment’s entry is flipped to an insufficient refusal — drift_invalidated for a detector finding, calibration_stale for a stale or epoch-mismatched fit — carrying its own need, have, and hint, the same emitted-not-omitted shape as every other refusal. The durable record of the decision is the recalibration log; the flip is computed when the artifact is read. So the system says “I cannot prove that any more” about the exact thing you asked about, without ever pretending the original measurement did not happen.

Two calibrations, one chassis

One naming caveat is load-bearing. This page is about tokentriage quality calibrateprobability calibration, stored under <state_dir>/calibrations/quality/, producing qcal_ artifacts. It is not the pre-existing tokentriage calibrate, which is routing-threshold calibration — it decides what share of traffic goes to the frontier tier, stores its artifacts under ~/.tokentriage/calibrations, and is documented in Routing.

You can watch the whole lifecycle in the Calibration studio — its lifecycle board orders cards candidate → shadow → active → retired, and gated activation shows the reliability diff as its confirm surface. See Dashboard.