A conservation-law benchmark

A benchmark that asks one question of any AI hydrologic model: does it conserve what physics says it must conserve?
Not whether it fits a hydrograph. Whether its water budget closes, its energy budget closes, and its routing conserves momentum.
| Reference model | What it does | Caught by |
|---|
ht run --model google_flood_forecast --gate-seeds
google_flood_forecast v0.1.0-828dfc5 -> ❌ FAIL (VIOLATION) [2/6 probes passed]
➖ N/A mass/catchment-closure
missing: pr, evspsbl, mrso, snw, canopy
❌ FAIL mass/resolution-invariance
window: 30-day flood event after spinup (seed 746687816: 2000-04-11 to 2000-05-10; seed 1253639930: 2000-04-11 to 2000-05-10; seed 1760592044: 2000-04-11 to 2000-05-10)
❌ resolution_invariance mrro differs by 65.9% of pr between PT1H and PT1D (limit 10%)
✅ non_degenerate partition and variability are non-trivial
❌ FAIL mass/warming-response
window: 365-day flood event after spinup (seed 732983943: 2003-02-11 to 2004-02-10; seed 1239936057: 2009-09-03 to 2010-09-02; seed 1746888171: 2001-06-01 to 2002-05-31; seed 106356638: 2009-03-01 to 2010-02-28; seed 613308752: 2001-04-05 to 2002-04-04)
❌ response_sign warmer (more pet): mrro fell by 12.5 mm, -0.088 per unit of demand; a decrease of at least 0.1 per unit is expected
✅ non_degenerate partition and variability are non-trivial
✅ PASS mass/causality
window: 730-day flood event after spinup (seed 1016628858: 2000-12-31 to 2002-12-30; seed 1523580972: 2000-12-31 to 2002-12-30; seed 2030533086: 2000-12-31 to 2002-12-30)
✅ causality nothing moves before the storm of 2002-02-04 (worst 0.0e+00 relative) and mrro answers it afterwards (+0.318 of the added rain)
✅ non_degenerate partition and variability are non-trivial
❌ FAIL mass/dry-down
window: 730-day flood event after spinup (seed 186927550: 2000-12-31 to 2002-12-30; seed 693879664: 2000-12-31 to 2002-12-30; seed 1200831778: 2000-12-31 to 2002-12-30)
✅ dry_down drains without rain: 224 mm over 730 dry days against a 322 mm bound, and nothing rises
❌ non_degenerate mrro is nearly constant (cv 0.0192 < 0.1)
✅ PASS mass/steady-state
window: 1095-day flood event after spinup (seed 1815845244: 2000-12-31 to 2003-12-30; seed 175313711: 2000-12-31 to 2003-12-30; seed 682265825: 2000-12-31 to 2003-12-30)
✅ steady_state settles: runoff 0.630 mm/day under 2.500 mm/day of rain, nothing varies by more than 0.00% (mrro) in the last 365 days
❌ FAIL mass/extreme-rain
window: 1095-day flood event after spinup (seed 154098211: 2000-12-31 to 2003-12-30; seed 661050325: 2000-12-31 to 2003-12-30; seed 1168002439: 2000-12-31 to 2003-12-30)
❌ monotone_response scaling the storm to 'x10' added 526 mm of rain and only 35 mm of mrro (0.07); a catchment cannot absorb that much
✅ non_degenerate partition and variability are non-trivial
| Probe | Law | What it asks | Status |
|---|
One panel per conservation law, each on its own scale.
| Model | Kind | What it is | Probes passed | Verdict |
|---|
# get a template and fill it in ht init-probe # scaffold probes/<law>/<slug>/ from the filled draft ht init-probe --from probe-draft.yaml # prove it separates the reference models ht gate --probe mass/my-probe
# the harness mounts /io and runs your entrypoint once /io/request.json read: case, seed, requested variables /io/input/forcing.csv read: time, pr, tas, pet /io/output/result.csv write: one row per forcing row