Every carrier is its own reservations and departure-control system. Three distribution systems sell into them. One switch relays between them. Nothing moves except a real Type B or EDIFACT message over a real socket, and the globe draws only what the messages say.

The whole sky at 21:50 on the synthetic day, once round: 8,500 aircraft over 518 carriers' networks. Every aircraft is a movement message that crossed the switch; the bar at the top is what the aircraft in the air were sold for.
Flight-tracking sites draw positions; airline simulators draw aircraft. wholesky draws nothing it was not told over the industry's own wire. Under the globe is a working airline IT stack, and that changes what the picture means.
An aircraft appears because a Type B movement message crossed the switch and lands because the arrival did. A passenger is on a name list because reservations sent it to the airport. A red halo is a closed airport sized by the real queue items an agent now has to rework. If the message did not happen, neither did the picture.
Every carrier has its own book of record, its own locator space, its own seat inventory and its own console. The distribution systems hold their own copies under their own locators. Nothing is shared but the wire. A region can die and rejoin; the switch cannot tell whether a peer is across a loopback or across a continent.
jetway is not a prop built for the demo. It is a gateway, GDS, DCS and switch with a spool, a lease, retention, rate limits, metrics and a production plan, and everything sim-only stays in wholesky. When the world finds a bug, the fix goes upstream with a test that was watched to fail.
Most airline formats live in paid documents that were not bought. Every package says whether its layer is specified by a public standard, inferred closely from published examples, or inferred. The passengers, aircraft types and fares are synthetic and labelled so; the schedule, tails, delays, cancellations and diversions on the recorded day are not.
The Wednesday before Thanksgiving 2025 is flown from the BTS record: 22,889 flights on their real tails, delayed for their recorded reasons, cancelled and diverted as they were, with 1.4 million pre-sold bookings at a holiday load and a price on every one. It takes a day, because it took a day.
The invariant suite is the release gate: no oversell across selling channels, message conservation at the switch, interline convergence, and a live check any shard can be asked for. Its first run against the recorded day found 88 oversold cabins and a filler that had never looked at the aircraft. The failures are real too, and they are all in the changelog.
The state separation is real: nothing is shared between nodes except a message. Pick a component to see what it does, what it speaks, and how much of it is specified by a public document rather than inferred.
An orthographic globe drawn from the switch's own message bus. An aircraft appears because its carrier's MVT departure message crossed the switch; it lands because the arrival did. Sparks are messages in flight to and from a carrier's home; a red halo is a closed airport, sized by the real queue items an agent now has to rework.
Click any aircraft and you get what its carrier holds: the schedule and, on a recorded day, what really happened to it; departure control's clock, the name list's parts and amendments, seat map by cabin, connections, the load and loadsheet; the operations desk's callsign and flight plan and what the towers said back; the manifest name by name; and the bookings behind the names under the locators the selling channels issued, each with its fare.

One departure as its carrier holds it, from the schedule down to the loadsheet.
Each carrier is a jetway gateway with its own book of record, its own seat inventory, its own locator space and its own console. It answers sells from its cabins, files its schedule changes, and runs its airports: reservations sends the airport the name list at T−180, the counter fills in waves with seat assignments and bag tags to sortation, the ADL goes at T−60, the counter closes, the gate boards, the sortation system reports the hold, the door closes at T−10 -- not over a loaded bag whose passenger is not on board; those are named and pulled first -- and the final sales, transfer, service and load messages and an AHM 560-method loadsheet go out.
The reservations and departure-control halves talk over the network like the separate systems they usually are. A carrier hosted on another machine is asked through federation; the switch cannot tell the difference.

Ryanair's own console, one of 522. Every node has one.
1G, 1S and 1A each run a jetway gateway with queues, an availability cache and its share of demand. A booking is made at the GDS; the sell goes to the carrier as AIRIMP over Type B or PADIS over EDIFACT, the carrier answers KK, US or UC from its inventory, and the record carries every carrier's locator for the same booking. Interline itineraries settle across carriers; tickets are issued and advised; a slice of demand arrives as NDC orders on the GDS's HTTP endpoint.
What the carriers said is what the record shows. A carrier that cannot be reached lands the booking on the divergence queue, each item naming the gap that caused it.

United 2408 Denver to Washington: 65 records under the selling channels' locators, each priced.
A full jetwayd in relay mode: 500-odd TCP listeners, real framing, relay by Type B address line and EDIFACT UNB recipient, a write-ahead spool, an outbox per link that refuses rather than stalls when a peer stops reading, per-peer rate limits with a shared cap, and a lease so a standby takes over. It is the only piece every message crosses, which is why the globe can be drawn from its bus alone.
The sky is loud but not big. Real global reservations traffic is a few thousand messages a second; the switch peaks above 16,000 a second on one 4-vCPU machine during the departure banks. Topology is the interesting part, not throughput.
jetway_outbox_depth · jetway_outbox_congested_total · jetway_ingress_links · jetway_spool_depth
Net mode: who converses with whom, laid out by its own springs.
jetway's pkg/fare is the structure of a filing: fare basis codes, rules for advance purchase, stay, season, change and refund, taxes by kind, passenger types at their discounts, and a pricing step every booking passes through. It carries no fare of its own, because ATPCO's are licensed. wholesky files a synthetic tariff from the schedule's distances, fourteen booking classes to a market, US-shaped taxes, and prices every booking as of its purchase date.
pkg/inventory is leg-based seat control: cabins per leg, serial nested class authorisations, waitlists a tenth of the cabin deep. A full cabin waitlists, a closed class with seats still in the cabin refuses, and the last seats go at the higher fares. The inventory is rebuilt from the book of record at every boot, because anything that remembers sold seats in memory oversells after a restart.
| the recorded day | value |
|---|---|
| whole day, 29,967 legs | $719M |
| average per passenger-leg | $255 |
| median per passenger | $204 |
| full-fare Y · business · deep discount | $341 · $750–785 · $93–160 |
| taxes | 15% |
Synthetic and labelled as such. The shape of a real Thanksgiving Wednesday, not anybody's filing.

The instrument panel. The number that should be zero is labelled as such.
Aircraft report OUT/OFF/ON/IN over a datalink provider (ARINC 620 shapes, from OAG's published tables); operations derives the MVT from the report instead of asserting it. Flight plans go to the towers over the AFTN (ICAO Annex 10) and the towers send DEP and ARR back. A diversion sends its DIV to the field it really landed at.
When a flight is cancelled, every booking on it is queued; the IROPS engine works the queue the way a desk does: the next flights over the same city pair, own metal first, free sale where the availability cache offers it and a request to the carrier where it does not, each request waited on until the carrier answers. A confirmed seat drops the dead leg with a real sell and a real cancel on the wire; a waitlist is kept and named; what nothing can carry stays on the queue for a person, while the airport offloads whoever had checked in and pulls their bags.

522 nodes across six machines, down to the raw telex, and a circuit cut and restored.
The weeks before the day. internal/fill reads the schedule and writes each carrier's book of record before the day runs: parties weighted the way holiday travel is, itineraries that connect on legs that actually connect, booking classes placed in cabins that have room for them on every leg, children and infants, special service requests at their real rates, a ticket per name, the carrier's locator and the selling channel's, purchase dates spread over the months before and priced as of that date. Deterministic from a seed, straight into Postgres with COPY. Southwest's day alone is 260,000 records, written in 24 seconds. One party in three thousand has a cello, and the cello has a seat.
The demand generator then rides on top as what it is on the day of travel: the late trickle, at hundreds of bookings a minute, with connections, interline, ticketing, cancellations, divides and a slice arriving as NDC orders.

The Wednesday before Thanksgiving 2025 at 17:00Z, every aircraft on its real tail.
The invariant suite is the release gate. In process, internal/sim/invariants_test.go proves no oversell across selling channels, message conservation at the switch, interline convergence and that a cancelled flight queues everyone. Live, every shard reports its inventories, the core federates them, and skycheck exits non-zero on a cabin holding more than it has or a shard that did not answer, because a machine being down must not read as a pass.
$ go run ./cmd/skycheck https://wholesky-demo.fly.dev
6 shards, 8074 cabins, 126321 seats sold, 0 oversold
Its first run against the recorded day found 88 oversold cabins, 83 of them business cabins on Hawaii legs holding up to 54 passengers in 32 seats: the filler had drawn booking classes without looking at the aircraft. The gate paid for itself on its first run.
Real: the wire formats and their published rules, the state separation, the failure modes, the schedule on the recorded day, its tails, delays by cause, cancellations and diversions.
Synthetic and labelled: the passengers, the aircraft types inferred from carrier and stage length, seat counts, and the fares. There is no real tariff in this, only the shape of one.
Single-box (-role all, the default and the test bed): one OS process, every jetway instance a library assembly, everything between them crossing real TCP on loopback. Multi-machine (the deployed demo): the same assemblies spread across six machines, dialled together over a private network. The switch cannot tell the difference, which is the point.
Peers register with the core and heartbeat every few seconds. The reply carries the switch's link addresses, the current warp and the closed-airport set, so liveness, time control and chaos propagate on one pulse. The fleet board merges every peer's rows and proxies drill-downs and consoles to whichever machine owns the node. A region can die and restart while the rest of the sky keeps flying; rejoining is registering and dialling back in.
Sells and their answers, availability broadcasts, name lists and their amendments, check-in and bag messages between reservations and the airport, load and passenger lists at door close, movement messages from the datalink provider, flight plans and tower replies over the AFTN, schedule changes, ticket control. Nothing else. Observers are bus taps only.
Everything importable lives in jetway: the codec packages (typeb, edifact, airimp, padis, avs, ssim, ndc, matip, pnr, pnl, baggage, mvt, dcs, aftn, ats, acars, fare) and the application packages (gateway, store, inventory, irops, node, queue, ingress, egress, transport, spool, api). jetway is meant to be usable as a real gateway, DCS or message router; sim-only behaviour stays in wholesky. Each package's doc says whether its format is specified by a public document or inferred from free reproductions, and the roadmap names the paid documents whose absence costs what.
worldc reads one day of BTS on-time data — every US scheduled flight, real tails, real delays by cause, real cancellations and diversions — and skyd flies it at warp 1, so the day before Thanksgiving takes the day before Thanksgiving.
The MVTs carry the record's delay codes. Departure control opens each flight three hours out and closes it at the door; the manifest, load and loadsheet are the day's own. Nothing in the recorded schedule is invented; what is synthetic — passengers, fares, aircraft types where BTS does not say — is labelled in the manifest. At the day's wrap the books are purged by daily partition and refilled deterministically from the seed. It runs at wholesky-thanksgiving.fly.dev.
git clone https://github.com/adamf/wholesky
cd wholesky && go test ./...
# compile a world, then fly it
go run ./cmd/worldc -countries "United Kingdom,France,Germany" -carriers 30 -o europe.json
go run ./cmd/skyd -world europe.json -carriers 12 -demand 8 -warp 240
# console on http://127.0.0.1:8080 · the eye at /eye
worldc compiles a deterministic manifest — airports, carriers, daily flights — from the vendored OpenFlights snapshot; same seed, same world. Pass -bts and -date for a recorded day. skyd boots the switch, the tenants and the distribution systems on loopback and runs the flight day at -warp.
| app | machines | what |
|---|---|---|
| wholesky-demo | core · gds1g · gds1s · gds1a · region0 · region1 | the synthetic world at warp 6, carriers' books in bounded memory |
| wholesky-thanksgiving | one machine, -role all | the recorded day at warp 1, books of record and distribution systems' books in Managed Postgres |
For a carrier's host or a switch carrying real traffic, the SRE plan is its own page: deploy to production — topology, the lease, database provisioning, DR, the alerts, and load testing as the release gate.
Both from fly.toml and fly.thanksgiving.toml. Roles: core, gds, region -shard N -shards M, or all. Peers find the core with -core-url and advertise themselves with -self-url. Stores are memory by default, or Postgres with -tenant-dsn and -gds-dsn; records are partitioned by their retirement day and dropped when the day wraps.
Lessons the deployments taught, all now in the code: a filled 737's name list is three parts; a link's outbox must refuse rather than stall; a seat inventory must be rebuilt from the book at boot; two worlds must not share one small database; and a partition that cannot be created must not stop the write.
Most airline formats are defined in paid IATA documents that were not bought. Every package says which layer it is: specified (ISO 9735, RFC 2351, Annex 10, the Type B whitepaper, the PNRGOV guide, NDC schemas), inferred closely (built and tested against verbatim published examples), or inferred. Never write a doc comment implying conformance you cannot demonstrate. When public sources disagree, implement one, make it advisory, and document the disagreement.
Every time this has been done it paid: the free PNRGOV guide fixed four PADIS bugs whose tests had encoded the same guess as the code; the free EMD guide fixed three coupon statuses; the free Type B whitepaper produced the 4 KB cap and PDM. Look for tables of contents, regulator guides, vendor and airport reproductions, and adjacent free standards. Then state precisely what remains unknown.
JETWAY_TEST_DSN).gofmt and the race detector. Watch the run after every push.IATA's IS-XML for the interline invoices (the proration, billing and agency memos are done), a revenue management forecast learned from history (the ladders, the booking-curve forecaster and the network programme's bid prices are done), Secure Flight-style vetting, WorldTracer's own formats (the AHL, OHD and FWD story of a short-shipped bag runs as a profile), crew, maintenance and rotation, weather and air-traffic flow, airport systems, cargo, and Type B over MQ as some carriers still receive it. The ordered list, with what each would add and exercise, is docs/missing-systems.md; what full load costs is docs/full-throttle.md.