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.
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.
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 validationsensor stuck, months of identical values
feed frozen 84 days, last good value repeats
spike to 1133 m, and minus 834 m at Jenapur
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.
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.
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.
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.
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.
Flood, five cities
Mature the alerting set. North Odisha scored in shadow. Close the recession gap with river gauges on the risk path.
Heat, same engine
Eleven locations scored against ERA5 normals, five surfaced. Stays in shadow until it has an audit a buyer can check.
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.
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.
Each one snapped to the nearest pilot city within 120 km.
In Odisha that radius crosses whole basins. Watch what it swept in.
They belonged to other rivers.
Baitarani 79. Rushikulya 34. Brahmani 29. The engine had been scored on water we were not claiming to watch.
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.
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
Anandapur, 86.8 km from Cuttack
Purushottampur, 104.6 km, in Ganjam
Jenapur, 49.4 km
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. Rain-only, scored against each gauge’s own ERA5 p95, negatives sampled at the same gauge. No leaked river term.
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 August 2026
- Open
The trust gate is not passed
Fourteen consecutive dry days with zero false HIGH. Minimum streak is currently zero, blocked on Sambalpur and Rourkela. And the gate as written tests only dry days - the one case the engine never fails. It needs rewriting.
- Open
Precision is unmeasurable until rivers land
We cannot separate "the engine over-fires" from "the flood record is incomplete" without river level as a feature or a label. Real telemetry is now in production, so this becomes answerable this season.
- Shadow
The ML model has never driven an alert
XGBoost v2 runs on every cycle and is logged. Offline it reads 91% leave-one-region-out and 96% event holdout. It stays in shadow until monsoon validation - offline metrics are not permission to go live.
- 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.
How to read every number on this site
In production, driving user-facing alerts.
Measured on history. Never quoted as live accuracy.
Computed and published, structurally unable to alert.
The engine was wrong, and here is the write-up.
A known gap we have not closed.
If we cannot label it, we do not make the claim.
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 June84 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 it would have worked
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.
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.
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, August 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.