E-Processes — Anytime-Valid Sequential Testing
What goes wrong with a naive approach
Every frame, the runtime asks: “is this observation a budget violation?” If you run a fixed- test (say, a z-test at ) on every frame, the type-I error explodes. The familiar “don’t peek at your p-value” warning isn’t a polite suggestion — at 60 fps you are peeking 60 times per second, and after one second of unified you have an expected false rejections.
Possible mitigations, all bad:
- Bonferroni across frames — divide by 60 and you’ll miss every real violation.
- Only test every frames — delay the alert and lose responsiveness, the whole point of continuous monitoring.
- Group-sequential tests — need pre-specified looks; TUI alerts are not pre-specified.
The right tool is the e-process: a test martingale whose expected value under stays bounded. You can peek every single frame and the false-alarm probability is still capped by .
Mental model
Picture a betting game against :
- You start with wealth .
- Every frame you bet a fraction of your wealth on the observation having mean greater than .
- If the observation is above , your wealth grows; if below, it shrinks.
- Under , the expected wealth is non-increasing (no strategy beats the null on average).
- Alert when — “you made so much money that either you’re a genius or is wrong”.
Because is a non-negative supermartingale under , Ville’s inequality gives:
— any stopping time, any number of looks, any number of frames.
E-processes are the secret ingredient that makes “principled monitoring at 60 fps” tractable. Conformal prediction gives you calibrated bounds; the e-process gives you calibrated alerts that survive continuous peeking.
The math
Wealth recursion
with (typically to keep the factor positive).
Ville’s bound
for any adapted — you are free to choose the betting fraction from the history as long as it doesn’t peek at the future.
GRAPA (gradient-of-log-wealth adaptive prior)
Fixing is suboptimal: too small and the detector is slow, too large and the wealth crashes on noise. GRAPA adapts:
Intuition: take a gradient step on the log-wealth with respect to . If the current is too conservative under a true alternative, the gradient points up; if too aggressive and wealth is decaying, the gradient points down.
Defaults
| Parameter | Default | Meaning |
|---|---|---|
| 0.05 | Global false-alarm bound. | |
| 0.1 | Null mean (normalised). | |
| 0.5 | Initial betting fraction. | |
| 0.1 | Gradient step size. |
Why fixed- tests fail under peeking
Fixed-α z-test at 60 fps
H0: μ = 0.1, observations i.i.d. ~ N(0.1, σ²)
Per-frame test at α = 0.05.
Expected false rejections per second: 60 * 0.05 = 3.0
→ alert log is unusable.Uses in FrankenTUI
- Throttle / flake detector (
eprocess_throttle.rs) — detects adversarial input bursts or flaky subscriptions. - Allocation budget — paired with CUSUM so a slow leak is detected by one or both.
- Conformal top-layer — the anytime-valid layer sitting above vanilla conformal.
Rust interface
use ftui_runtime::eprocess_throttle::{EProcess, EProcessConfig};
let mut ep = EProcess::new(EProcessConfig {
alpha: 0.05,
mu_0: 0.1,
initial_lambda: 0.5,
grapa_eta: 0.1,
});
// On each observation:
let rejected = ep.observe(x_t);
if rejected {
trigger_alert();
}observe returns true the first time . After a
rejection, the caller typically resets (or the subsystem takes a
compensating action and the wealth drifts back down).
How to debug
Rejections emit eprocess_reject lines:
{"schema":"eprocess_reject","alpha":0.05,
"wealth":24.6,"lambda":0.43,"x_t":0.18,
"mu_0":0.1,"grapa_step":0.03}FTUI_EVIDENCE_SINK=/tmp/ftui.jsonl cargo run -p ftui-demo-showcase
# Lambda trajectory over a session (GRAPA adaptation):
jq -c 'select(.schema=="eprocess_step")
| [.frame, .lambda]' /tmp/ftui.jsonl | tail -40A stuck at 0 means GRAPA has decided the stream is indistinguishable from — not a bug. A stuck at means the stream is far from and you should already have seen rejections.
Pitfalls
The wealth factor can go negative if . That breaks the martingale. Clip for bounded observations, or use the log version .
GRAPA is not a free lunch. If the stream briefly looks adversarial and GRAPA spikes , a subsequent benign shift can obliterate the wealth. Keep small (≤0.1) so adaptation is gradual.
Cross-references
- Alpha-investing — the sequential-FDR layer that budgets multiple e-processes.
- Vanilla conformal — the base for the conformal-over-e-process stack.
- CUSUM — the cheap partner for allocation-budget alerts.