What it cost
31 of 214 sites could not receive commands for 17 minutes. No site lost power and no safety function was affected: protection runs on each site’s own controller, and every site held its last setpoint.
- Sites
- 31 of 214 (14%), every site in the north-fjord region. The other five regions were unaffected.
- Commands
- 121 sent into the gap. 112 waited in the queue and were delivered late, by 09:33. 9 dispatch setpoints expired after their 10-minute limit and were re-issued by hand by 09:40. None were lost silently.
- Dispatch
- NF-12 and NF-19 missed the 09:20 discharge window. 1.4 MWh of scheduled discharge was not delivered.
- Safety
- None. Site protection does not depend on the command path.
- Detection
- 5 minutes, by a person reading the acknowledgement column. No alert fired.
- Resolution
- 12 minutes after detection, 17 minutes in total.
Minute by minute
Every minute of the window, quiet ones included. Left of the spine is what operators were shown; right of it is what the command path was doing.
-
Console showed31 / 31 healthyCommand API answers 202 Accepted.What was trueFallback activatesBundle 0922-1 reaches the router without a north-fjord key. The lookup returns an empty route instead of failing closed; commands to 31 sites are accepted and go nowhere.Waiting6
-
Console showed31 / 31 healthyWhat was trueA setpoint to NF-07 passes its 30-second acknowledgement window. 0 of 31 north-fjord sites are acknowledging.Waiting13
-
Console showed31 / 31 healthyWhat was trueThe fleet acknowledgement rate falls from 99.6% to 85.5%. It is on a chart. It is not on an alert.Waiting20
-
Console showed31 / 31 healthyWhat was trueNothing new. Commands keep queuing.Waiting26
-
Console showed31 / 31 healthy09:20 dispatch schedule marked “sent”.What was trueThe 09:20 schedule for north-fjord sits in the queue with everything else.Waiting33
-
Console showed31 / 31 healthyCommand log: 31 sites “sent”, none “acknowledged”.What was trueOperators see driftThe north-fjord desk operator notices the empty acknowledgement column and calls the shift lead. Five minutes have passed without an alert.Waiting40
-
Console showed31 / 31 healthyWhat was trueThe discharge window opens. NF-12 and NF-19 miss it; 1.4 MWh of scheduled discharge is not delivered.Waiting55
-
Console showed31 / 31 healthyWhat was trueThe shift lead pages platform on-call.Waiting61
-
Console showed31 / 31 healthySite links: 31 / 31 up.What was trueOn-call acknowledges and checks site connectivity. Every site answers, over the telemetry uplink, which is not the path that broke.Waiting68
-
Console showed31 / 31 healthyWhat was trueFalse lead closed: the sites are reachable, so the fault is on our side of the command path.Waiting75
-
Console showed31 / 31 healthyWhat was trueSEV-1 declaredThe duty manager declares SEV-1 and takes incident command. Status goes to the operations channel.Waiting81
-
Console showed31 / 31 healthyWhat was trueThe routing lead joins the call.Waiting88
-
Console showed31 / 31 healthyWhat was trueA traced command shows route=[] for every north-fjord site.Waiting94
-
Console showed31 / 31 healthyWhat was trueMissing key foundA diff of bundles 0922-0 and 0922-1 shows the region split added north-inland and dropped north-fjord.Waiting101
-
Console showed31 / 31 healthyWhat was trueDecision: promote the previous bundle rather than hand-add the key under pressure.Waiting108
-
Console showed31 / 31 healthyWhat was truePromotion of 0922-0 starts, with a two-person check.Waiting114
-
Console showed31 / 31 healthyWhat was trueBundle 0922-0 is live on 3 of 5 router replicas.Waiting121
-
Console showed31 / 31 healthyThe acknowledgement column fills. Health never moved.What was trueRoute restoredThe previous configuration is live on all replicas. NF-07 acknowledges at 09:31:12; all 31 sites by 09:31:48. The queue starts draining.Waiting121
- After the windowQueue empty. 112 commands delivered late, in order.
- The desk re-issues the 9 setpoints that expired in the queue.
- Incident closed after 30 minutes of clean acknowledgements across all regions.
Why the console stayed green
Health and commands travel in opposite directions. We only measured one of them.
Root cause. The router’s lookup for a region key fell back to an empty route when the key was missing. An empty route is a valid answer, so the router accepted every command for north-fjord, queued it and reported nothing wrong.
- The fallback was meant to be temporary. CHG-2291, merged on Wed 16 Sep, let the router tolerate missing region keys so the staged region split could roll out without crashing replicas. It had no removal date, no alert and no owner after the split.
- Health checks measure the other direction. Device health comes from heartbeats the sites send us. It tells us a site can reach us, not that we can reach it.
- Acknowledgements were charted, not alerted. The fleet rate dropped from 99.6% to 85.5% in two minutes. Nobody had set a threshold, so nothing paged.
- Validation checked shape, not completeness. Bundle 0922-1 was valid against the schema. Nothing compared its region keys with the site registry.
- “Accepted” read as “sent”. The API returns 202 when a command is queued. The console labelled those commands “sent”.
router/resolve.py · CHG-2291 · merged Wed 16 Sep41def route_for(key):42− return ROUTES[key]42+ # tolerate keys missing mid-split43+ return ROUTES.get(key, [])
router/resolve.py · CHG-2317 · shipped Mon 28 Sep41def route_for(key):42− return ROUTES.get(key, [])42+ route = ROUTES[key] # raises43+ if not route: raise EmptyRoute(key)44 return route
Durable fixes
Three changes, each with an owner, a date and a test that tells us it worked. Status as of Wed 30 Sep.
| Fix | Owner | Due | Status | How we will know it worked |
|---|---|---|---|---|
| RemoveThe empty-route fallbackThe router fails closed. A bundle with an unresolved region key is rejected at publish, and the command API returns 503 for anything it cannot route. | Platform routing lead | 29 Sep | DoneCHG-2317 · 28 Sep | A test bundle without the north-fjord key is rejected in staging, and the publish job names the missing key. Passing since 28 Sep. |
| AddAn acknowledgement SLO and alert99% of commands acknowledged within 60 seconds, per region. Page the desk and platform on-call when any region stays below 90% for 2 minutes. | Control-room operations manager | 9 Oct | In progressshadow since 25 Sep | Replaying the 22 Sep traffic through the rule pages at 09:16, three minutes before a person noticed. |
| ProveA regional failover drillRemove one region key on purpose, first in staging and then in a production maintenance window, and run the recovery from the runbook. | Reliability programme lead | 23 Oct | Scheduled21 Oct staging · 23 Oct prod | The page arrives within 2 minutes, and a responder who was not on incident 17 restores routes in under 5. |
What held, and what was luck
We keep what worked on purpose. The luck is a list of things to stop relying on.
Held up on purpose
- A person read the right column. The desk operator saw the empty acknowledgement column at 09:19 and escalated at once.
- Rolling back beat patching. Promoting bundle 0922-0 took three minutes and needed no code change.
- The queue kept its order. 112 of 121 commands were delivered late rather than dropped.
- Site protection stayed local. No site needed the command path to stay safe.
Luck not a control
- The hour. At 09:14 on a weekday the north-fjord desk is staffed. Overnight the region is watched from the central console, which hides the acknowledgement column by default.
- A small diff. Bundle 0922-1 changed three keys. A larger bundle would have taken longer to read by eye.
- Two sites, not twelve. Only NF-12 and NF-19 had a discharge due inside the window.
- Low stakes in the queue. The nine expired commands were routine setpoints, not curtailment orders.
Open the prevention checkWhat keeps this fixed after the fixes ship
The durable check is ownership: the recovery path now has a named owner, a tested alert and a scheduled review. If any of the three lapses, this postmortem reopens.
- Owner
- The platform routing lead owns route resolution and the fail-closed rule, recorded in the service catalogue on 28 Sep.
- Alert
- The acknowledgement SLO pages below 90% for 2 minutes. Tested by replaying 22 Sep traffic; it fired at 09:16.
- Review
- First on Fri 6 Nov 2026 with the drill results, then every quarter. The reliability programme lead chairs it.