/p/2026-08-31 · explainer
Paper explainer · 2608.26306 · Shraga, Eshel, Gorelik

The check said yes.
By the time it ran, it was wrong.

A guardrail sits in front of an action, reads the current state, and approves. Nothing about that verdict is wrong. But the verdict takes time to compute and time to deliver, and the system keeps moving underneath it — so by the moment the action actually lands, the state it was approved against is gone. This is the oldest bug in systems programming, time-of-check to time-of-use, wearing a language model as a hat. Replaying logged decisions eight steps later across five self-adaptive systems, the reference verdict had flipped on 5.3% to 48.4% of candidates; among approvals that were genuinely correct when checked, 3.4% to 24.7% were inadmissible by the time they ran. The fix does not need a model of the system: divide the action's safety margin by how fast the signal has lately been moving, and refuse to act past that horizon. It took expiry to 0–1.8% in every environment.

01 · The hazard

Correct at check time, inadmissible at use time

Follow one decision through. At some step the monitor reports an observation, the controller proposes an action, and the guardrail approves that action against that observation. Every one of those is right. Then the verdict has to travel: it is computed, returned, queued behind whatever else the loop is doing, and finally actuated some number of steps later.

By then the plant has moved. The action was admissible for the state it was checked against and may not be admissible for the state it arrives in — and nothing in the pipeline notices, because the approval carries no expiry. The paper's name for what is missing is a freshness contract: an approval must be correct when checked and still valid when used, and almost nobody records the second half.

Interactive · slide the delay between check and actpacket loss must stay at or under 0.10
at check time
at use time

02 · The measurement

Five systems, and the churn is nothing alike

Five step-driven simulators were replayed at shifts of one to ten steps: an internet-of-things network gated on packet loss, an edge-cloud tuner on response-time error, a self-healing web application on per-step utility, an adaptive vision pipeline on utility, and a job dispatcher on average delay. Each has a scalar feature and a threshold, so admissibility is a deterministic label rather than an opinion.

At eight steps, verdict-change rates run from 5.3% to 48.4% — roughly a ninefold spread — and the shapes differ as much as the levels. Two environments are already saturated at a single step and barely move after. One climbs steadily with age, 16.5% at one step to 32.7% at eight. One is flat. One barely registers.

Interactive · pick a system, then age the verdictshare of candidates whose verdict had flipped
verdict change
shape

That spread is the practical finding. There is no universal number for how long an approval stays good, so a fixed timeout is either needlessly conservative in one system or dangerous in another. The horizon has to be estimated per decision.

03 · The mechanism

Margin, divided by how fast things are moving

The shield is arithmetic, and that is its best feature. Take the signed distance between the current feature value and its threshold — how much room the action has before it becomes inadmissible. Track how fast that feature has lately been changing with an exponentially weighted average of its step-to-step movement, smoothing at a tenth, fixed across all five environments.

Divide the first by the second and you have an estimated number of steps the approval stays good for. The action passes only if it was approved upstream, the margin is genuinely positive, and the actual delay is inside that horizon. Otherwise it falls back.

Interactive · build the horizon out of two numbersmargin ÷ recent movement per step
020 steps

The reasoning underneath is a bound, not a guess: if the feature moves by at most some amount each step, then over K steps it moves by at most K times that, and keeping K times the recent movement under the margin is enough to avoid crossing the line. The paper is honest that it has swapped an unknown worst-case drift bound for a smoothed recent-change estimate.

Both halves are load-bearingexpiry rate · lower is better

04 · The judges

Every judge stream leaked, and you cannot tell why

Four judge backends were audited — two small open-weight models, one hosted small model, one hosted mid-tier — by asking, inside each judge's own approval set, how many were inadmissible at use time. On the fastest-churning environment at eight steps that ran from 11.5% to 36.8%, and every audited stream was nonzero.

Read that number carefully, because the paper insists on it: it mixes check-time judge error with temporal expiry and cannot separate them. It does not rank judge quality and it does not isolate staleness. What it does establish is that no judge you plug in gets you out of this — the leak is present in all four, so a better judge is not the lever.

What this audit supports, and what it does notread the second column before quoting the first
05 · For your own agent

Put an expiry on the approval illustrative

Map it onto an agent that asks a model to approve a tool call before executing it. The margin is how far the thing you are gating on sits from the line that makes the call unsafe. The volatility is how fast that quantity has been moving. The delay is how long your approval sits between the check and the call actually going out — model latency, queueing, a human in the loop.

The widget above is the whole rule. What is left is knowing that you have those three numbers already, and are almost certainly not writing any of them down next to the approval.

Interactive · the same rule, on an agent tool callillustrative
The numbers

What the paper actually reports

What this does not show

In practice