---
license: apache-2.0
library_name: transformers
pipeline_tag: feature-extraction
tags:
- surprise
- regime-change
- model-monitoring
- calibrated-uncertainty
- abstention
- time-series
- multi-domain
---
# Zeno Divergent
**A learned representation of *model-relative surprise* — the probability that
an observable departure happens next, calibrated, with an explicit option to
abstain.**
[](https://huggingface.co/mbarbosa1/zeno-divergent-v1/tree/v0.7.0)
[](https://huggingface.co/mbarbosa1/zeno-divergent-v1/tree/v0.7.0)
[](#architecture)
[](#training-data)
[](#the-promotion-gate)
[](https://zenodivergent.dev)
---
## What is published here
| revision | model | corpus | promoted domains | loader |
| --- | --- | --- | --- | --- |
| **`v0.7.0`** | multi-domain, 1,874,220 params — **latest and recommended** | 8 corpora, 7 real | hydrology, climate | explicit revision (safetensors + config) |
| `v0.6.0` | multi-domain, 1,874,220 params — multi-scale windows + robust normalisation | 8 corpora, 7 real | hydrology, markets, climate | explicit revision |
| `v0.5.0` | multi-domain, 1,677,870 params — pin this for seismic / space weather | 8 corpora, 7 real | seismic, hydrology, markets, spaceweather | explicit revision |
| `v0.3.1` | single-domain, 30,859 params — `transformers`-native custom pipeline | seismic only | seismic | pinned revision, `trust_remote_code=False` |
| `v0.2.3` | frozen v0.2 prototype | synthetic | — | remote-code loader |
**Read this before picking a revision.** v0.7.0 promotes **fewer** domains than
v0.6.0 — two instead of three — because the gate got harder, not because the
model got worse. From v0.7.0 onward a domain cannot be promoted unless it
**beats a plain logistic regression fitted on the same features**, with a
bootstrap CI excluding zero, and unless **no head sits within 0.005 AUROC of
chance**. Under v0.6.0's rules none of its promoted domains passed that bar.
Under v0.7.0's rules, hydrology and climate do — that is the headline.
Markets promoted in v0.6.0 and does not in v0.7.0: it never beat the logistic
baseline, and now that is disqualifying. Seismic and space weather still have
collapsed rare-event heads; if you need those domains, pin `v0.5.0`.
`main` now serves the **v0.7.0** multi-domain weights, so the repository
metadata reflects the real model (1,874,220 params) rather than the 30,859-param
v0.3.1 seismic checkpoint it used to carry. The `transformers`-native custom
pipeline stays available at revision `v0.3.1`. Revisions are immutable: nothing
published is ever overwritten in place.
**v0.7.0 closed the gap it was built for.** It adds per-target loss
normalisation, bounded heteroscedastic attenuation, raised rare-event class
weighting, a collapse guard, exclusion of targets with fewer than 25 test
positives, and a hard gate requiring a win over the logistic baseline. Two
domains now clear that bar. Six do not, and each one is published with its
blocking reason attached.
---
## Why this matters
Every deployed forecaster carries an invisible assumption: *tomorrow looks
enough like the data I was fitted on*. When that assumption dies, the model does
not raise its hand. Accuracy degrades, uncertainty stays flat, and the failure
is only discovered downstream.
The usual answers are partial:
| Approach | What it tells you | What it misses |
| --- | --- | --- |
| Predictive uncertainty (`σ`, ensembles) | how noisy *this* prediction is | stays low right up to a regime break |
| Drift / OOD detectors | the inputs moved | fires on harmless movement, silent on harmful stable-looking shifts |
| Change-point detection | something changed **already** | it is a post-mortem, not a lead time |
| **Zeno Divergent** | **the calibrated probability that an observable departure happens in the next window, with an option to abstain** | it is not a hazard forecast — see [limits](#limits) |
**The falsifiable claim this model exists to test:**
> A learned representation of model-relative surprise contains information about
> future regime change and model failure that is **not** captured by predictive
> uncertainty or rule baselines alone — and that representation is **shared
> across domains**.
The harness is built to *reject* that claim. Every target is scored against a
phase-0 rule baseline with entity-level bootstrap confidence intervals, and a
pre-declared promotion gate refuses to publish a domain unless the corpus is
real and the lifts hold.
---
## How it works
```
observations ──▶ schema contract ──▶ past-only features ──▶ per-domain adapter
│
▼
shared dilated causal trunk
│
▼
surprise state z^S
│
┌──────────────────────────────────────┼───────────────┐
▼ ▼ ▼
calibrated p_k(t+Δ) uncertainty σ_k abstain gate
```
1. **Declare a schema.** Categories, numeric channels, targets, horizon. The
schema is a contract, not a guess — it is hashed into the config.
2. **Build past-only features.** Row `i` is a function of observations `0..i`
and nothing after it. Leakage is re-derived from the raw stream, not asserted.
3. **Adapt, then share.** A small per-domain adapter maps each schema into one
**shared** dilated causal trunk. 1,349,417 of the 1,677,870 parameters (80%)
are shared across all eight domains — that sharing is the claim under test.
4. **Encode the surprise state `z^S`.** A representation of *how* expectation is
failing, common to every head.
5. **Predict observable departures.** One head per target: category-regime
transitions, cadence shifts, magnitude-regime shifts, compound transitions.
6. **Calibrate, then gate.** Probabilities are fitted on a held-out validation
split; low-evidence rows are marked `abstained` rather than scored.
### What comes back
| Field | How to read it |
| --- | --- |
| `probabilities` | calibrated probability of each observable transition inside the horizon |
| `uncertainty` | heteroscedastic spread — large means *poorly determined*, not *safe* |
| `abstained` | admission control. **"Not enough evidence", never "nothing to see"** |
| `surprise_index` | max over targets — a ranking, not a probability of harm |
| `latent` | `z^S` itself, for probing and transfer studies |
---
## Results
Held-out chronological test split with a horizon buffer, entity-level bootstrap
CIs, one row per domain showing its strongest scored target.
### v0.7.0 — latest revision
**Promoted — cleared the pre-declared gate, *including* a win over a logistic
regression fitted on the same features**
| domain | corpus | entities | rows | best target | AUROC (95% CI) | ECE | beats logistic on |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Climate** | NOAA GHCN-Daily | 179 | 739,220 | `heat_extreme_ahead` | **0.890** [0.869, 0.910] | 0.010 | `weather_regime_transition`, `diurnal_collapse`, `compound_climate_stress` |
| **Hydrology** | USGS daily water services | 320 | 419,840 | `flow_regime_transition` | **0.786** [0.774, 0.798] | 0.017 | `discharge_regime_shift`, `volatility_regime_shift` |
**Not promoted — published with the blocking reason, not hidden**
| domain | best AUROC | why it did not promote |
| --- | --- | --- |
| Seismic | 0.644 | does not beat the logistic baseline on any target; 3 heads still collapsed to chance; worst ECE 0.79 |
| Space weather | 0.664 | no logistic win; 4 collapsed heads; worst ECE 0.11 |
| Markets | 0.664 | no logistic win; worst ECE 0.101, just over the 0.10 bound |
| Macro (FRED) | 0.922 | no logistic win; 2 collapsed heads; 80 entities, below the 100 minimum |
| Wildfire (NASA FIRMS) | 0.528 | beats neither the rule nor the logistic baseline; all 6 heads at chance; ECE 0.95 |
| Chaos (Lorenz-96 / Kuramoto) | 0.998 | **synthetic corpus.** A deterministic control that proves the pipeline runs. Never evidence about real data. |
**External-corpus transfer (evidence only, never gating).** The trunk and `z^S`
are frozen and only fresh adapters and heads are fitted on corpora the model
never trained on:
| corpus | entities | rows | best target | AUROC |
| --- | --- | --- | --- | --- |
| `Salesforce/lotsa_data` | 240 | 337,140 | regime transition | ~0.92 |
| `Salesforce/GiftEvalPretrain` | 240 | 338,832 | `regime_transition` | 0.786 |
Several proxy targets on both external corpora sit at 0.5 — the shared
representation transfers for transition detection and not, so far, for the
magnitude-shift proxies.
### v0.6.0 — previous revision
**Promoted (cleared the pre-declared gate)**
| domain | corpus | entities | rows | best target | AUROC (95% CI) | ECE | abstention gain |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Climate** | NOAA GHCN-Daily | 182 | 739,220 | `heat_extreme_ahead` | **0.883** [0.860, 0.903] | 0.011 | +0.045 @ 0.77 coverage |
| **Hydrology** | USGS daily water services | 320 | 419,840 | `flow_regime_transition` | **0.770** [0.757, 0.782] | 0.015 | +0.021 @ 0.79 coverage |
| **Markets** | Coinbase public market data | 357 | 258,570 | `dislocation_ahead` | **0.691** [0.672, 0.712] | 0.092 | +0.034 @ 0.89 coverage |
**Not promoted — published with the blocking reason, not hidden**
| domain | entities | best AUROC | why it did not promote |
| --- | --- | --- | --- |
| Seismic | 224 | 0.640 | **regression against v0.5.0.** Four of five heads collapsed to a constant 0.500 while a logistic regression on the same features reaches 0.887. Rare-positive training defect. |
| Space weather | 293 | 0.644 | **regression against v0.5.0.** Four heads collapsed to 0.500 against a 0.78–0.84 logistic baseline. Same defect. |
| Macro (FRED) | 80 | 0.731 | below the 100-entity minimum and below the AUROC floor on every target. |
| Wildfire (NASA FIRMS) | 250 | 0.692 | below the floor; calibration still the weakest of the real corpora. |
| Chaos (Lorenz-96 / Kuramoto) | 240 | 0.998 | **synthetic corpus.** A deterministic control that proves the pipeline runs. Never evidence about real data. |
**The honest headline:** no promoted domain in v0.6.0 yet beats a logistic
regression fitted on the same features. Multi-scale windows and robust
median/IQR normalisation bought climate and cost seismic. Closing that gap is
the entire purpose of v0.7.0.
### v0.5.0 — recommended for seismic and space weather
| domain | corpus | entities | rows | best target | AUROC (95% CI) | ECE | abstention gain |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Seismic** | USGS FDSN events | 224 | 44,470 | `significant_event_ahead` | **0.911** [0.878, 0.933] | 0.071 | +0.092 @ 0.69 coverage |
| **Space weather** | GFZ Potsdam Kp/ap/F10.7 | 293 | 63,224 | `activity_transition` | **0.823** [0.804, 0.839] | 0.044 | +0.091 @ 0.51 coverage |
| **Hydrology** | USGS daily water services | 320 | 419,840 | `flow_regime_transition` | **0.781** [0.771, 0.791] | 0.017 | +0.021 @ 0.83 coverage |
| **Markets** | Coinbase public market data | 357 | 258,570 | `dislocation_ahead` | **0.709** [0.691, 0.731] | 0.084 | +0.037 @ 0.81 coverage |
### Cross-domain transfer (leave-one-domain-out)
The trunk and `z^S` are trained on the *other* domains, then frozen; only the
held-out domain's adapter and heads are fitted. If the shared representation
were domain-specific bookkeeping, transfer would collapse. It does not — five
domains (seismic, hydrology, markets, space weather, climate) clear the gate
under leave-one-domain-out transfer in v0.6.0. That result is **reported, not
required**: the gate rule is discrimination and calibration on each domain's own
corpus.
### The promotion gate
Declared before the run, applied without discretion:
```
real corpus required · ≥ 2 targets significant vs phase-0 rules
paired lift vs phase-0 ≥ 0.03 · worst-target ECE ≤ 0.10
selective-accuracy gain ≥ 0.02 · ≥ 100 entities
leakage tests must pass
```
v0.7.0 adds two rules that v0.6.0 would have failed: **beat a logistic
regression on the same features**, and **block any head sitting within 0.005 of
chance**.
**Verdict for v0.7.0: `promoted`** — two real-corpus domains cleared the gate,
and for the first time both of them beat a logistic regression on the same
features. Six domains did not clear it and ship as candidates with their
blocking reasons attached. v0.4.0 is a
documented gate failure and was never published as a model. Full run report in
`report.json`, digests in `SHA256SUMS`. If those digests do not match your
rebuild, you are not looking at the same artifact.
---
## Quick start
**The current model (`main`, v0.7.0)** loads through the standard Auto classes,
no `trust_remote_code`:
```bash
pip install "zeno-divergent>=0.7.0" transformers torch
```
```python
from transformers import AutoModel
import zeno_divergent # registers config + model with the Auto classes
model = AutoModel.from_pretrained("mbarbosa1/zeno-divergent-v1")
model.describe()
# {'model_version': '0.7.0', 'parameters': 1874220,
# 'promoted_domains': ['climate', 'hydrology'], 'steps': 12, ...}
events = [
{"timestamp": 1717171717.0,
"category": "elevated_flow",
"values": {"discharge_cfs": 812.0,
"abs_daily_change_cfs": 41.0,
"rise_ratio": 1.2}},
# ... chronological, one entity
]
rows = model.score_events(events, domain="hydrology", entity_id="usgs-01646500")
last = rows[-1]
last.probabilities # calibrated, one per declared target
last.uncertainty, last.risk, last.abstained
last.promoted # False => this domain did not clear the release gate
```
Discover a domain's contract instead of hardcoding it:
```python
info = model.domain_info("hydrology")
info["schema"]["categories"], info["schema"]["channels"], info["targets"]
info["promoted"], info["blocking_reasons"], info["abstention_threshold"]
# refuse exploratory output outright
model.score_events(events, domain="seismic", entity_id="x", allow_unpromoted=False)
# ValueError: 'seismic' did not clear the release gate (...)
```
Standardisation statistics, degenerate-column masks, per-target calibration and
the abstention threshold all travel in **`inference.json`** in this revision, and
are applied in the run's own order (standardise and clamp, *then* zero degenerate
columns). That is the same chain the exported browser ONNX graphs run, so a
Python score and an in-browser score of the same window agree to ~1e-7.
Six of the eight domains did not clear the v0.7.0 gate. They still carry weights
and still return numbers, but every row comes back `promoted=False`. Do not
present those as validated results; for seismic or space weather, pin
`revision="v0.5.0"`.
Older APIs stay pinned and unchanged: `revision="v0.3.1"` for the single-domain
`transformers` pipeline, `revision="v0.2.3"` for the frozen synthetic prototype.
No GPU, no network calls at inference time.
---
## Architecture
| | |
| --- | --- |
| architecture | per-domain input adapters → shared dilated causal trunk → shared surprise latent `z^S` → per-domain calibrated heads |
| parameters | **1,874,220** total (v0.7.0), **1,349,417 shared** (72%) across 8 domains; v0.5.0 is 1,677,870 |
| domains | 8 schemas, 7 real corpora, 2 promoted in v0.7.0 under a stricter gate (3 in v0.6.0, 4 in v0.5.0) |
| features | 72 per step, multi-scale windows (5 / 20 / 100 events) + calendar features, robust median/IQR normalisation |
| training | 14 epochs, seed 7, batch 512, lr 1.5e-3, single NVIDIA L4 |
| auxiliary objectives | counter-expectation head, domain-adversarial head, contrastive surprise objective, per-target loss normalisation, bounded log-variance |
| precision | float32, safetensors |
| runtime | CPU, sub-millisecond per row |
Why did the parameter count move around across versions?
Capacity is set by what the corpus supports, not by what looks impressive.
v0.2.x was a wide multi-reference encoder over a *synthetic* ten-mechanism
generator (large, but fitted to a simulator). v0.3 replaced it with a
domain-neutral schema contract over one real corpus, and capacity dropped to
~31k accordingly. v0.5.0 trains one shared trunk across eight real schemas at
once, so capacity is back up to 1.68M, and v0.6.0 to 1.87M with the multi-scale
feature set — this time earned by real data breadth, not by a generator. Nothing
was ever pruned or quantised; every version stays loadable at its own revision.
---
## Training data
Public, credential-free sources. No personal data, no identity, no intent, no
ownership fields — the input contract rejects them.
| domain | source |
| --- | --- |
| seismic | USGS FDSN event web service |
| hydrology | USGS Water Services daily values |
| markets | Coinbase Exchange public market data API |
| spaceweather | GFZ Potsdam Kp/ap/F10.7 (definitive, CC BY 4.0) |
| climate | NOAA GHCN-Daily station access files |
| macro | FRED (Federal Reserve Bank of St. Louis) |
| wildfire | NASA FIRMS active fire detections (VIIRS) |
| chaos | in-repo Lorenz-96 / Kuramoto integrator (deterministic control) |
Splits are chronological with a horizon buffer between them.
---
## Intended use
**In scope**
- Research on model-validity forecasting and surprise representations
- Advisory decision support with a named human owner
- Prioritising which observation to collect next
- Benchmarking change-point and surprise detectors against a locked protocol
- Reproducing — or falsifying — the claim above on your own corpus
**Out of scope**
- Automated or safety-critical actuation
- Reading the output as the probability of a *physical* event (it predicts model failure, not hazard)
- A single cross-domain risk number
- Scoring people. Entities are models, sensors, regions, instruments, processes — never individuals.
---
## Limits
- **Two domains are promoted in v0.7.0, not eight.** Those numbers are
published so they can be checked, not because they are trusted.
- Hydrology and climate beat a logistic regression on the same features. **The
other six do not** — on those domains a linear baseline is still the honest
choice, and the model says so rather than hiding it.
- Seismic, space weather, macro and wildfire still contain heads collapsed at
chance. The collapse guard now blocks them from promotion instead of
averaging them away.
- Leave-one-domain-out transfer promoted nothing in this revision.
- Probabilities are calibrated on the validation split; recalibrate before using
them as decision thresholds in a new deployment.
- Abstention must be surfaced next to the score. Hiding it turns "not observed"
into "not at risk" — that is a misuse.
- The model predicts *observable* transitions in a public descriptive stream. It
makes no claim about identity, intent, ownership or causation.
- `main` serves v0.7.0. Pin `revision="v0.5.0"` for seismic and space weather,
or `revision="v0.3.1"` for the `transformers`-native single-domain pipeline.
---
## Citation
```bibtex
@software{zeno_divergent_0_7_0,
title = {Zeno Divergent: a shared representation of model-relative surprise},
author = {Barbosa, M.},
year = {2026},
url = {https://huggingface.co/mbarbosa1/zeno-divergent-v1},
version = {v0.7.0}
}
```
**[zenodivergent.dev](https://zenodivergent.dev)** — live workspace, interactive benchmarks, full documentation.