The Scorecard Was Kinder to Late Quakes

Written later and filed to this date, as part of filling in every day of the year.

A forecast that missed by two days and six hours was scored as three days off if the earthquake came early, and as two days off if it came late.

That was the grader in an earthquake dashboard I started in July 2025. Its one-line promise, still at the top of the README, ends “track how close we get”. The model underneath is the simplest thing that can be called a forecast: count the large quakes in a region over the years, treat them as a Poisson process, and quote the expected wait until the next one with a 95% interval. The forecast is not the product. Anyone can draw an exponential. The product is the scorecard, the running record of how far each forecast landed from the quake that resolved it.

The first commit holds a README, a licence and an ignore file. The application itself, a Python backend, a React front end and a compose file, sat untracked beside them for eleven months. In June 2026 an agent brought it under version control as it found it, and the same night wrote the project’s first test and found the grader.

The accuracy code subtracted two timestamps, took the whole days of the difference, and only then took the absolute value. Python floors whole days toward negative infinity. A quake that arrived before its forecast made a negative difference, which floored away from zero and then lost its sign: two and a quarter days became three. A quake that arrived after made a positive difference, which was truncated: two and a quarter became two. The fraction was discarded in both directions and the rounding leaned one way. Every scorecard the dashboard had ever shown was off by up to a day, and kinder to lateness.

The fix is four lines: take the full difference in seconds and divide. The commit that made it also stood up a suite of thirteen tests, because until then there were none, and the first number a test touched in that repository was the one the whole thing existed to report.

Two hundred commits followed that summer, fifty-six of them diary entries recording a session. Among the rest: a free-text search where “magnitude 7” returned the entire catalogue, because the band’s two bounds had been joined with OR; a card that measured whether the Poisson assumption held per region, a second that showed clustered regions forecast worse, and a third that drew the corrected interval beside the official one. The corrected interval never became the forecast. Replacing the model would move every pinned number in the suite, so the question was parked for me to decide, and in September I answered it from the console: not deciding this one, stop asking.

So the dashboard still issues the forecast it has measured to be the wrong shape. Beside it sits the interval it should be issuing, with the ratio of the two widths printed between them, and the scorecard grades the official one to the second.


← all writing