The calibration lifecycle
The audited life of a qcal_ artifact, from the four one-way states and the per-segment activation gate to the refit triggers and read-time invalidation.
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 the ones
that were turned away, 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 right 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 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) rather than 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 and evaluated and serving nothing, 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 one of those that was turned
away, each classified applied or refused. A turned-away move 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,
one of them with fewer lines.
The log is strictly append-only (no entry is 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
a disclosure that older entries rotated away. Each entry also requires a detail, since a
refused activation with no text is nothing anybody can act on, so the trail records not only
what happened but why.
A second kind of artifact lands in the same store under the same discipline. A judge validation
run writes a jval_ artifact beside the qcal_ ones, whether the run promoted the subject or
declined it, and a declined run is as durable as a promoted one. What is inside a jval_ record,
and the ordered walk that produces it, are
How a judge reaches a measured basis.
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 insufficient, 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 the other refusals take. 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 carries real weight. This page is about tokentriage quality calibrate,
probability 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.