Skip to content
Research

The models are good. The map is not.

Global flood platforms are excellent where the data is thick: dense gauge networks, LIDAR terrain, decades of insurance claims. Most of the people who drown live where none of that exists. That is the whole company.

01 · The empty quadrant

Nobody is building here.

That is the whole company. Tomorrow.io, Jupiter Intelligence, 7Analytics and Vassar Labs all win on assets we do not have and are not trying to acquire. We do not compete with them on their ground - we operate in the quadrant they skip: real-time decisions, made where the inputs are thin.

The quadrant is empty for a reason. It is unglamorous, and you cannot enter it from a desk in another country.

Positioning schematic. Placement is our own reading of public product scope, not a benchmark.
02 · What data-sparse actually means

We measured it. It is worse than the brochures suggest.

These are not estimates. Each one is a number we hit while building, on real Odisha feeds, and each one is a reason a platform designed for Rotterdam does not transfer.

0 / 12

CWC river stations that were decision-grade on day one

Not one of them could be trusted to move a score on the day we started ingesting.

0.0%

of readings at Kishan Nagar outside physical range

A platform that trusts the feed wholesale would have alerted on noise.

0

conflicting danger-level tables for the same gauge

DoWR's real danger level for Akhuapada is 18.33 m; INDOFLOODS lists 17.83, which is actually the warning level.

0 mm

what the IMD daily grid can read on a peak event day

While OpenWeather reports localised Odisha rain falling hard. No single feed is safe alone.

Three of these four look like data.

Raw gauge feed · before validation
FLATLINE

sensor stuck, months of identical values

STALL

feed frozen 143 days, last good value repeats

IMPOSSIBLE

spike to 1133 m, and minus 834 m at Jenapur

A RIVER RISINGcounts

Akhuapada 18.45 m against a danger level of 18.33

A flatline, a stall and an impossible spike all arrive as valid rows with valid timestamps. Only the fourth is a river rising.

That is why river level is gated: a station only reaches the risk path when it is marked status == live. Otherwise the briefing says the read is rainfall-only, out loud. The moat is not a model - it is the accumulated knowledge of which feed lies, and when.

03 · Decision engine, not predictor

A forecast is not a decision.

Forecasts answer what will happen. A district officer at three in the morning needs an answer to what do I do, and needs to defend that answer at nine. Those are different products.

What a forecast gives you

62%

probability of flooding, next 24 hours

  • Do I evacuate?
  • Which wards?
  • How do I justify it tomorrow?

The officer improvises. The number takes no responsibility.

What a decision engine gives you
LiveHIGHrule_score 0.71 · Cuttack · 04:12 IST

Rain 6 h

78 mm

p95 baseline

41 mm

Antecedent

3 wet d

Forecast 24 h

46 mm

Why this score
78 mm in 6 h against a p95 of 41 mm, on soil already saturated by three wet days. Forecast adds 46 mm in the next 24 h.
Closest past event
Nearest match in 653 labelled historical events, and what happened in the 48 hours after it. Officers reason by precedent, not probability.
Suggested action
Pre-position at Naraj. Alert wards 4 to 9. One line, not a plan.
What we could not see
No live gauge on this reach, so this read is rainfall-only and the score is capped accordingly. The absence is stated, not smoothed over.

Every field is something the engine already computed. None of it needs a bigger model.

04 · One engine, many hazards

The hazard changes. The shape does not.

Flood is the wedge because it is the most expensive and the most tractable. Underneath, the engine is hazard-agnostic: a baseline, an observation, a rule, a decision. Heat already runs on it, in shadow, with no way to alert.

Now · liveLive

Flood, five cities

Mature the alerting set. North Odisha scored in shadow. Close the recession gap with river gauges on the risk path.

Next · shadowShadow

Heat, same engine

Eleven locations scored against ERA5 normals, five surfaced. Stays in shadow until it has an audit a buyer can check.

DiscoveryOpen

One industry vertical

Mining first, and discovery before any build. Ten to fifteen conversations decide whether there is pull, before a line of product code.

Not in the next ninety days: cyclone, drought, ports, extra industries, or a sixth alerting city. Deliberately.

That is the argument. Everything below is the evidence for it, including the parts that went against us.

The evidence

Everything we know, including what broke.

A district cannot audit what it cannot see. Every figure here carries a label saying what kind of number it is, and the failures are given the same weight as the wins.

01 · what we published

One hundred and forty-three validated positives.

Every one of them counted toward a 99.3% detection rate, and that number led every deck we had.

02 · how they were labelled

Each one snapped to the nearest pilot city within 120 km.

In Odisha that radius crosses whole basins. Watch what it swept in.

03 · where they actually were

They belonged to other rivers.

Baitarani 79. Rushikulya 34. Brahmani 29. The engine had been scored on water we were not claiming to watch.

04 · what was left

One of 143 was Mahanadi.

We retired the number, published the audit, and put the precision problem it exposed on the public site.

Schematic. Basin courses are indicative; the event counts and distances are from the relabel audit.

05 · What the engine actually scores
Backtest

14 of 15 river-over-danger spells flagged two days ahead.

The 2026 monsoon on the Baitarani, scored end to end. Fifteen times a river crossed its danger mark on the four reaches we watch. With rainfall forecasts plus the state’s own daily gauge bulletin we flagged 14 of 15 two days ahead, and were HIGH or above on all 27 days a river already stood above danger (a nowcast, not a forecast). n = 15 spells · forecasts as issued, 2 Jun-5 Oct 2026 · unmodified engine.

Miss

What production actually ran, rainfall only: 9 of 15.

And LOW on 6 of those 27 above-danger days: Jajpur on 26-27 September with the river at 1.06× danger. That miss is why the river term now exists.

Backtest

The cost: MEDIUM on about 80% of monsoon days.

Akhuapada sat within 10% of danger for half the season, so Bhadrak and Jajpur read MEDIUM on about 80% of monsoon days. MEDIUM is a river watch; HIGH is the action bar.

Backtest

13 of 13 floods flagged two days before the river crossed its danger level.

Baitarani, 2024 to 2026, on forecasts as they were issued rather than on hindsight rainfall. Precision 27.7%, false alarm rate 21.8%, against a 7.7% base rate: a 3.6 times lift. n = 13.

Thirteen floods is a small sample and we state it as a count, not a percentage. A 13 of 13 result carries a 95% lower bound near 77% recall, so it is not a claim of perfect accuracy and we will not write it as one.

It is also worth being exact about what was measured. Anandapur and Akhuapada are Baitarani gauges on the shadow surface; neither is one of the five cities that actually alert, which sit on the Mahanadi and the Brahmani. This is the engine scored against a gauge record, not the alerting product describing itself.

Backtest

Across all thirteen gauges it is weak, and that is the finding.

51% of floods caught at one day’s lead, at 6.6% precision. Roughly fourteen false alarms for every true flood. Rainfall alone is not a statewide alerting product.

The Baitarani is a slow-response basin, so two days of forecast rain actually reaches the gauge. Rajghat on the Subarnarekha scores 36%, and Purusottampur and Gunupur score zero of two. A single statewide average would hide both the basin that works and the ones that do not, which is why no figure here appears without its basin.

Backtest

Where the labels come from. 497 daily flood bulletins published by Odisha’s Department of Water Resources, 2023 to 2026, archived and parsed into 11,408 gauge readings carrying a danger level. The label is the state’s own operational record: did the river cross its published danger mark. Not our judgement, and not an academic dataset, which is what makes these numbers checkable by the people who published the source.

06 · The audit that cost us our best number
Backtest

We audited our own 99.3% and it did not survive.

Our event labeller snapped each INDOFLOODS gauge to the nearest pilot city within 120 km. In Odisha that distance crosses whole basins. The number was mislabelled, not fabricated - but it was wrong, and we retired it from the site.

We could have quietly fixed it. Instead we published the audit, the replacement number, and the precision problem it exposed underneath.

Where our 143 validated positives actually came from

Baitarani79

Anandapur, 86.8 km from Cuttack

Rushikulya34

Purushottampur, 104.6 km, in Ganjam

Brahmani29

Jenapur, 49.4 km

Mahanadi1

Naraj - one event, out of 143

94.4%

north Odisha onsets, 102 of 108

95.1%

across all 143 events

97.5%

Baitarani

86.2%

Brahmani

What survived the relabel. Hindsight rainfall, not forecast-as-issued; superseded by the forecast numbers above. Rain-only, scored against each gauge’s own ERA5 p95, negatives sampled at the same gauge. No leaked river term.

Miss

The finding nobody publishes: our precision does not exist.

The old “0% false positive rate” was measured on dry days - the one case a rainfall rule separates by construction. On heavy monsoon days at or above the gauge’s own p95 with no recorded flood, the engine fires on every single one: 647 of 647. Sweeping 0.5 to 8 times p95, precision never exceeds 24.2% against a 20% base rate.

And the reason is interesting. North Odisha flood days have a median of 1.94 times p95. Non-flood heavy days have 2.03 - the days without floods had more rain. Either rainfall genuinely cannot discriminate and we need river level as a feature, or the flood record is not exhaustive and we need river level as a label. Both answers point the same way.

What we have not solved, as of October 2026

  • The trust gate is not passed

    Trust gate v2 is defined. v25_dowr passes on the 2026 tape; rain-only fails G1. Still OPEN for the five LIVE cities. Fourteen consecutive dry days with zero false HIGH remains the live-city bar, and Sambalpur and Rourkela still block it.

    Open
  • Precision is measured now, and statewide it is weak

    This sat here as unanswerable until we archived the state’s own gauge record and could ask it properly. It is answered, and the answer is not flattering: 6.6% precision across all thirteen gauges, roughly fourteen false alarms for every true flood, against 27.7% on the Baitarani. Rainfall alone is not a statewide alerting product. That is a finding about where this engine works, not a disclaimer.

    Open
  • The ML model has never driven an alert, and its old numbers are retired

    XGBoost v2 runs on every cycle and is logged, and it has never altered a user-facing score. The offline figures we used to quote, 91% leave-one-region-out and 96% event holdout, are withdrawn: the training set defined water level as 85% of the event peak, so roughly 77% of the feature importance was encoding the label. It has not been re-measured since. Every flood number on this site is the rule engine, not the model.

    Shadow
  • Heat has a dataset, not a model

    About 82k leakage-audited rows under ml/heatwave/, of which roughly 23.7k are forecast-backed. No model has been trained. HeatBench v0 exists; the IMD grid cross-check sits at roughly 62% within 1.5 degrees of ERA5.

    Shadow

How to read every number on this site

Live

In production, driving user-facing alerts.

Backtest

Measured on history. Never quoted as live accuracy.

Shadow

Computed and published, structurally unable to alert.

Miss

The engine was wrong, and here is the write-up.

Open

A known gap we have not closed.

If we cannot label it, we do not make the claim.

Rainfall, river stage, and what the engine saidBacktest · forecast replayed as issued
06 · Fixing it: real river telemetry

We deleted the constants and went to the source.

The engine used to carry hardcoded river levels. They are gone. CWC hourly telemetry now arrives from the NWDP open API (46 gauges across Mahanadi, Brahmani and Baitarani), and the daily DoWR flood bulletin is parsed for 28 more.

What the feed actually looked like

  • Out-of-range at Kishan Nagar, including a spike to 1133 m and minus 834 m at Jenapur34.6%
  • Sensors flatlined: Akhuapada, Champua, Pamposh, Nimapara, Seorinarayan5 stuck
  • Brahmani and Baitarani feed, stalled since 3 June143 days
  • Real but stale: Sambalpur, Hirakud, Basantpur, Khairmal38–79 h

So the ingest ships with a QC layer it turned out to need badly: physical-range filter, stuck-sensor detection over a 500-reading window, and a datum check that strips a published danger level when it does not share the station’s datum. A level counts toward a score only when the gauge is genuinely live, and since Rule v2.5 a live level near its danger mark can raise the call on its own, without waiting for rainfall to agree.

Backtest

It worked, so we shipped it

10 of 12 location-days in the 19–21 August recession window that rainfall scored LOW would have been rescued by the river hold. On 19 August, Akhuapada was literally above its danger level, 18.45 m against 18.33, while the rainfall engine said 0.20 LOW. That measurement is what put river stage into the score in Rule v2.5, where a live gauge near its mark can now raise the call without rainfall’s agreement.

Live

Live in production

Sambalpur now reads 181.68 m from Jamadarpali. Cuttack 131.22 from Kishan Nagar, Puri 3.22 from Nimapara, Rourkela 171.4 from Pamposh, all correctly marked unavailable and contributing nothing. Bhubaneswar has no CWC station at all, so it now shows no river level rather than a frozen constant.

07 · What the engine is built from

Public and academic data, named, and filtered before it counts.

Nothing reaches a score straight from a feed. Every reading passes four gates, and a station that fails any of them contributes nothing rather than contributing noise.

INDOFLOODS

653 labelled historical flood events. Kuntla & Saharia, BAMS 2025.

IFI

India Flood Inventory. Saharia et al.

ERA5

1991–2020 climatology. Each location's own wet-day p95, and the heat baseline.

IMD

Daily gridded rainfall and Odisha district normals.

Odisha AWS

State automatic weather stations, ingested twice daily.

CWC / NWDP

Hourly river telemetry, 46 gauges, open-licensed.

DoWR Odisha

Daily flood bulletin: 28 gauges with danger, warning and historic high, plus reservoir gates and discharge.

NRSC · OpenWeather

Satellite baselines and live forecast. Derived risk product; no raw data resale.

Derived risk product; no raw data resale. Advisory only.

The honest position, October 2026

Every claim above is labelled. If we cannot label it, we do not make it.

The flood engine alerts on five cities. The ML runs in shadow and cannot alter a user-facing score. Heat has no live mode in the code, not a switch we are choosing not to flip. There is no signed MoU and no paying customer.