1
Problem
2
Challenge
3
Solution
4
Implementation
5
Summary

When the label rule changes

Policy shock on day 70

The Problem

On day 70 of the synthetic stream, finance enables a stricter review policy. Categories that auto-cleared now require human eyes. Input features look similar; the correct label changes.

That is concept drift: P(Y|X) moves. Retraining on pre-shock labels teaches the old world. Mixing pre- and post-policy rows in one loss without a version bit looks like noise instead of a regime change.

Day 70
Policy shock (concept shift)
0.008 → 0.12
Expected calibration error (pre vs post)
↑ accuracy
Hold-out accuracy can rise while calibration breaks

Where accuracy misleads

Calibration vs queue volume

The Challenge

Accuracy and calibration diverge

In this run, hold-out accuracy is slightly higher after the shock (~0.91 vs ~0.78 pre) while expected calibration error rises from about 0.008 to about 0.12. A team watching only accuracy would miss that predicted probabilities no longer mean “probability of review under current policy.”

Thresholds tuned on old score-to-outcome curves send the wrong volume to reviewers: too few after a tightening, too many after a loosening. Prior shift—class balance changes without semantic change—needs threshold tuning, not necessarily a full retrain.

Label semantics changed; features did not
Same features X
Old policy Y
New policy Y′
Scores miscalibrated

What breaks in production

Stale thresholds: Fixed cutoffs assume stable meaning of score 0.8.
Mixed training windows: One model learns incompatible label rules.
Accuracy-only gates: Release checks pass while reviewer queue is wrong-sized.
Unversioned policies: You cannot slice metrics by label_policy.

Our approach

Version labels like schema

The Solution

Version the label rule like a schema migration

Store label_policy with every label. Monitor calibration and queue depth by policy version. Schedule relabel or retrain on post-shock data; during transition, route borderline scores to rules or humans with an explicit flag.

Concept drift response
Policy release
Versioned labels
Calibration by version
Threshold / retrain

Policy version field

Treat like feature_schema—required on every label.

ECE dashboards

Page on calibration before accuracy moves.

Transition week

Shadow thresholds; do not auto-apply old cuts.

Prior vs concept

Balance-only change → thresholds; semantic change → labels.

What changes in operations

0.12 ECE
Post-shock calibration (this run)
Queue volume
First business symptom
Versioned eval
Required before redeploy

Code for calibration by policy

ECE and rolling accuracy

Implementation

ece_by_policy.py
def expected_calibration_error(y_true, y_prob, n_bins=10):
    bins = np.linspace(0, 1, n_bins + 1)
    ece = 0.0
    for lo, hi in zip(bins[:-1], bins[1:]):
        mask = (y_prob >= lo) & (y_prob < hi)
        if mask.sum() == 0:
            continue
        acc = y_true[mask].mean()
        conf = y_prob[mask].mean()
        ece += mask.mean() * abs(acc - conf)
    return ece

Key points

  • Shift day 70: Marked in stream metadata and figure JSON sidecar.
  • Rolling accuracy: Can look healthy while ECE jumps—plot both.
  • Retrain data: Post-shock labels only, or weighted by policy version.

Notebook: 03_concept_drift.ipynb

Summary

Semantics and thresholds

What this run shows

Concept drift is a semantics problem. The model may rank rows consistently while the mapping from score to action is wrong for the new policy.

Rolling accuracy around concept shift
Rolling accuracy around the day-70 policy shock. Compare with ECE pre/post in the notebook export JSON.

Calibration broke first

ECE 0.008 → 0.12 while accuracy moved the other way.

Policy as schema

label_policy must ride with every label row.

Thresholds are not universal

Recalibrate per policy version, not per model file only.

Questions answered

Version the label definition with the model artifact? Yes—two fields: model_version and label_policy. Release checks must pass for the pair, not the pickle alone.
Can calibration dashboards page before accuracy moves? They should. Set ECE and queue-volume alerts per policy version.
How to score during transition week? Shadow new thresholds, dual-write labels with policy version, and do not train on mixed policies without sample weights.
Prior shift without semantic change? If only class balance moved, adjust thresholds and class weights before a full retrain.

Production insights

Finance releases

Click to reveal

Put policy launches on the same calendar as schema migrations—with rollback owners.

Reviewer queue

Click to reveal

Queue depth is often the first human-visible symptom of concept drift.

Relabel budget

Click to reveal

Plan relabel hours when policy tightens; old labels are actively harmful.

Accuracy trap

Click to reveal

Higher accuracy after a tightening can mean more true positives under a stricter rule—not a better score scale.

Continue this saga

Next chapter: Shift, drift, and noise.

← Previous StoryBack to saga overviewNext Story →