Inspiration

On 24 January 2025, Storm Éowyn shut down most of Dublin's flights. For an airline's finance team, a day like that runs on what Hyphenate calls a human runtime: a cancel list coded "weather" at 5 a.m., a spreadsheet, and a week of emailing maintenance to ask "was it really weather?"

That question is worth real money. Under EU261, a passenger on a flight cancelled for the airline's own reasons is owed €250–600; one cancelled by a genuine storm is owed nothing (refunds and care are still due). The cause decides who is owed and what goes on the balance sheet, and nobody checks it.

Hyphenate asked for one corner of a finance team, made autonomous. We picked the seats where an operational fact decides the money: the Passenger Claims Accountant and the Revenue Accountant.

What it does

StormCheck runs Northstar Air, a fictional Dublin airline (about €1.1B revenue), on real weather, real airport traffic and real EU law.

It catches the mistake. Operations coded all 27 Éowyn cancellations "weather". StormCheck reads the real METAR: the storm window closed at 15:00Z, and 11 flights left between 15:30 and 17:30Z. NS31 to Boston was due out at 16:30Z, and its tech log from the night before says hydraulic pump leak, no MEL relief, aircraft on ground. Not weather. A broken plane. It is recoded 71 → 41.

It books the right number. Under IFRS 15, EU261 compensation is variable consideration that reduces passenger revenue, so the liability is the expected value, not €0 and not the maximum:

$$\text{€}34{,}650 = 35\%\ \text{expected claim rate} \times \text{€}99{,}000\ \text{full entitlement}$$

It drafts Dr 4090 / Cr 2140, parked for a person to approve. It never posts or pays on its own.

It asks the right person, once. It escalates three questions to three different people, each with a confidence and a reason: the Claims Lead (a €300 voucher the passenger never signed for), Legal (return flights stranded by the storm) and the Controller (whether to release an old storm's liability). Each answer becomes a scoped rule.

It learns, and it reuses what it learned. On the next storm, Herminia, the Claims Lead's rule settles 31 passengers without asking anyone, with her ruling cited. The one flight her words didn't cover (Boston → Dublin, arriving rather than leaving the EU) asks again instead of stretching her rule. Questions per storm fall from 3 → 1.

It handles something it has never seen. On 28 April 2025 Spain and Portugal lost power at 12:33 CEST: about 500 flights cancelled, 80,000 passengers. We gave StormCheck the real event. It had never seen a blackout, so it didn't guess: it asked Legal one question. With that ruling it settled the 8 flights inside the outage window, caught the 2 cancelled after the power came back (a crew out of duty hours and an aircraft left out of position; the airline's own fault, so they're owed), and booked €136,720 of care that's owed even when the cause is extraordinary.

Every euro traces back. Every fact, decision, rule, ruling, journal entry and LLM call is a hash-chained commit. Click any number and walk it back to the raw METAR line or tech-log entry.

Time saved. By hand, Storm Éowyn is about 500 hours of ops, claims, legal and accounting work (≈ €18,900 at loaded Irish rates). With StormCheck it's about 45 hours of people reviewing and approving. The app computes this live from each run.

Bring your own scenario. On the Judge's Desk, type any airport and date. StormCheck pulls that day's real weather, simulates the airline on it, and runs the same engine.

How we built it

Two Claude roles and one deterministic engine.

  • Reader (Claude): turns messy tech logs, ops notes, CRM records and claim emails into typed facts. Every fact must quote a verbatim span of its source, and code re-parses the value from that span; if they don't match, the fact is dropped.
  • Engine (Python, deterministic): storm and outage windows at both ends of each flight, cause from the aircraft's tech log and rotation, EU261 entitlements, versioned rules with precedence and authority, calibrated confidence, and routing to the right person. It cannot import the Anthropic SDK, read the clock or use randomness; a test enforces that.
  • Books (Python, deterministic): parked journal drafts, the 2140 liability rollforward, claim curves with a Bornhuetter-Ferguson true-up (+€3,990 at the February month-end, with January locked), and invariants checked on every post.
  • Drafter (Claude): corrected rights notices (drafted with zero passenger data), journal memos, "why?" answers, challenge replies and rule drafts. Any number in its prose must appear in the evidence, otherwise a template is used.
  • Trace: an event-sourced, append-only, hash-chained log with blame, time-travel replay and revert. make verify recomputes every hash and replays every decision offline.

Three of us built it overnight, running multiple Claude Code agents in parallel in separate git worktrees. We wrote the contracts first (Pydantic models and an OpenAPI stub) so every lane could start at once. Golden numbers are fixed to the cent and asserted by tests, a checksum stops anyone editing the expected answers, and a pre-commit hook enforces who owns which directory. The final build passes 1,875 tests.

Challenges we ran into

  • Keeping the AI out of the money. The easy version asks the model who is owed. We made that impossible: the LLM never decides who is owed, never computes an amount, and never decides the cause.
  • Getting the accounting right. It isn't a provision. It's IFRS 15 variable consideration (IFRIC, September 2019), and month-end re-estimates are changes in estimate under IAS 8 that never touch a locked period.
  • Facts versus law. A return flight stranded by the storm, or a power cut the system has never seen, isn't settled law. The engine has to stop, ask Legal once, and turn the answer into a rule that doesn't stretch beyond its words.
  • A blackout is not a storm. We generalised "storm windows" into extraordinary-event windows backed by real operator statements. Only the 12:33 start is a published fact; each airport's recovery time is approximate, and we label it that way.
  • Honest proof. Our labels are synthetic, so we separate "settled alone and right" from "safely asked a person" from "settled alone and wrong", and we say on screen that it validates the pipeline, not the world.

Accomplishments that we're proud of

  • It catches the broken plane and defends the decision when challenged ("Decision stands.", with citations).
  • Learning that transfers: one ruling settled 31 cases on the next storm; across held-out days there were 0 repeat questions and 0 rules applied outside their scope.
  • On 95 held-out cancelled flights (17,593 passengers): of the flights it settled alone, 85.5% were right; it caught 9 of 9 miscoded technical faults (€430,125 of entitlement); 8 of 8 prompt-injection attempts were blocked or escalated.
  • Same answer every time. Plain Claude on the same documents gave a different liability for the same storm across runs, and on Storm Herminia overstated it by 37% (€74,052 vs the correct €54,180) every time. StormCheck gave €54,180 exactly, with an identical hash on every run.
  • The books tie to the cent: €34,650 drafted, +€3,990 at the February true-up, and €25,740 tying to the GL:

$$\text{€}25{,}740 = (35\% - 9\%) \times \text{€}99{,}000$$

What we learned

  • The expensive fact is the cause. Once it's right, the compensation band is a lookup; what's left is estimating who will claim.
  • A confidence needs a reason. "39% · sources disagree" tells the Claims Lead what to look at; "39%" doesn't.
  • Rejections teach as much as answers. The Controller's "never release the tail" became a rule.
  • The right question for an AI agent isn't "can it decide?" It's "does it know when not to?"

What's next for StormCheck

  • More disruption types: long arrival delays, ATC, strikes and bird strikes, each settled once by Legal.
  • More regimes: UK261, Canada's APPR, and the EU's 2026 reform.
  • Real airline feeds: Amadeus, NetLine, AMOS and Accelya behind one adapter, still producing only drafts for people to approve.
  • Calibration on a real carrier's history.

What's real: Dublin and Iberian weather and event data, airport traffic, distances and EU law. What's simulated: Northstar's schedule, logs, passengers and claims, with the mess left in.

Built With

Share this project:

Updates

Submission history