HOLONOGRAPH / The Guide · Drift attribution v0.23.0 all chapters

Chapter 13

Drift attribution

Reflects Holonograph v0.23.0 · ~6 min read

When a score changes over time, drift attribution tells you which layer of your system the change came from. It answers the question every operator asks after a moved number: is this us, or is this the vendor, or is this our evaluation, or is this just noise?

What it is

A per-surface analysis over a window that returns a timeline of change points. Each change point carries three things: the timestamp of the shift, one of four source labels, and the window over which the analysis is confident about that label.

The four source labels are the same four sources of drift the four-layer snapshot separates at capture time:

  • substrate — your own deployment
  • light source — the vendor moved under you
  • lens — your evaluation configuration changed
  • noise — the model's irreducible non-determinism

Why it matters

Without attribution, a score move is a mystery — the operator has to guess at the cause, and every guess pulls the team in a different direction. With attribution, the same score move is a labeled event with a first suggestion for what to do next. The whole point is to route the response to the layer that can act on it.

How to use it

Point the analysis at a surface and a window:

POST /lens/attribute
Authorization: Bearer <token>
x-holonograph-run-mode: production
Content-Type: application/json

{
  "surfaceId": "classify-intent",
  "since": "2026-06-01T00:00:00Z",
  "until": "2026-07-05T00:00:00Z",
  "bucket": "day",
  "changePointDeltaThreshold": 0.15
}

The response is the timeline plus a couple of companion arrays:

{
  "surfaceId": "classify-intent",
  "eventCount": 12483,
  "changePoints": [
    {
      "timestamp": "2026-06-14T09:20:00Z",
      "source": "light source",
      "window": { "from": "2026-06-12T00:00:00Z", "to": "2026-06-15T00:00:00Z" }
    }
  ],
  "bracketedWindows": [ /* companion windows the analysis wants you to know about before acting */ ]
}

bucket controls the temporal resolution of the timeline. changePointDeltaThreshold is a sensitivity knob: higher = fewer points. Both are optional; the defaults are usually what you want.

Reading the output

Every change point comes with one of the four source labels. Do this with each:

LabelWhat it meansWhat to do
substrate The change tracks something you changed about your deployment. Check your own deployment: recent prompt edits, tool-schema revisions, feature flags, retrieval-index updates. Your substrate columns (Chapter 04) are where you look first.
light source The vendor moved under you — a model was silently re-routed, updated, or its behavior shifted. Check light_source_identifier across the window. If it's stable and the behavior still moved, the vendor changed the model behind an unchanged name.
lens Your evaluation configuration changed. Check the lens version history. A new lens version around the change point means you're seeing the apparatus move, not the system.
noise The model's irreducible non-determinism dominates this window. Gather more data before acting. A noise-labeled change point is a signal to widen the window, not a signal to ship a fix.

The bracketedWindows array holds companion windows the analysis wants you to see before acting on a source label — periods where the timeline is less confident than usual. Read those first when a change point lands adjacent to one.

Working through a report

The usual cadence: run the analysis over a window that ends at "yesterday," then walk the change points in order. Each label sends you to a different place — your deploy log, the vendor's changelog, your lens history — and the labeled window tells you where to look. Once every point has an action (or a decision not to act), the report is done.

Reference

Endpoint

Method & pathPurpose
POST /lens/attributeRun drift attribution over a window.

Request

FieldShapeNotes
surfaceIdstring (req)The surface to analyze.
sinceISO 8601 (opt)Inclusive lower bound on events considered.
untilISO 8601 (opt)Exclusive upper bound.
bucketenum (opt)day, hour, minute. Temporal resolution of the timeline.
changePointDeltaThresholdnumber 0–1 (opt)Sensitivity. Higher = fewer change points.

Response

FieldShapeNotes
surfaceIdstringEcho of the surface.
eventCountnumberHow many events were considered.
changePoints[]arrayTimeline of change points; each has timestamp, source label, and window.
bracketedWindows[]arrayCompanion windows worth reading before acting on nearby change points.