# What a national railway timetable gives back to a late train

One row per **leg class**: an ordered pair of adjacent Swiss stations plus a train category,
over the 50 days **2026-07-25 to 2026-09-12**. 5,824 rows.

A published timetable is the time a train needs plus a supplement, spread along the route so
a train that falls behind can catch up. The railway literature sets norms for the supplement
and argues about where to put it. This is the measurement: for each leg, how much lateness it
actually gives back, computed from Switzerland's own open operational record.

## The one idea worth taking from the method

**Absorbed lateness is a behaviour, not a parameter.** You cannot see how fast a train could
have gone, so an estimate of slack that starts from a technical minimum running time inherits
whatever you assumed. This does not start there. It takes every train that entered a leg
`d` minutes late and asks how much less late it was at the other end. Four published
timestamps, two subtractions, no model.

`absorption_best_s` is that quantity at its largest. `slack_present_s` is the other one,
the older one, the one that does need an assumption, and it is here beside it because the two
disagree in about nine leg classes out of ten and that disagreement is the interesting part.

## Files

- `legs.jsonl` — one JSON object per line, one per leg class.
- `schema.json` — JSON Schema draft 2020-12 for a row, with `x-origin` on every field.
- `sources.json` — where each column came from and the licence position of each source.
- `validate.mjs` — dependency-free; re-checks every row against the schema, plus the
  digests and row count in `manifest.json`.

## What is in it, in one paragraph

Of 5,824 leg classes, 1,260 give back nothing at all: their best
absorption is zero or negative. The median that does give something back gives
39 seconds. Pooled over the whole network the curve rises from
19 s for a barely-late train to a ceiling of
48 s
and then falls, which is why a badly late train never catches up: recovery is bounded per leg,
so what a journey can undo depends on how many stops it has rather than on how much help it
needs. End to end, a train leaving one minute late arrives 10 seconds
late and a train leaving fifteen minutes late arrives 877 seconds late.

## Three things to know before you use a row

**1. `realised_run_p01_s` is an upper bound, not a minimum.** It is the first percentile of
what trains were observed to take. A leg where every train is padded will have a padded first
percentile, so `slack_present_s` is a *lower* bound on the slack that is there.

**2. 153 leg classes carry a non-zero `traversals_impossible`.** Those traversals
had a negative realised run time, meaning the record says the train reached the second stop
before it left the first, which cannot happen. They are excluded from every statistic here and
counted in that column instead of being swept up. Where the count is most of the class, the
cause is usually that two adjacent halts carry the *same* departure timestamp to the second, so
the record cannot say when the train left the first of them. Treat a row with a high
`traversals_impossible` relative to `traversals_measured` as a row about the record rather
than about the railway.

**3. Only measurements are used.** The publisher's status field distinguishes `REAL` (an
effective actual time) from `GESCHAETZT` (a calculated one), `PROGNOSE` (a forecast) and
`UNBEKANNT`. Nothing here uses anything but `REAL`. That is also why coverage,
`traversals_measured` over `traversals_scheduled`, is well short of one on some legs: a
forecast is not an observation and is not counted as one.

## Attribution

Source of the underlying operational data: **opentransportdata.swiss**. The analysis and every
measured column are the Artificial Wasteland's, published under its own name as that platform's
terms require of an analysis, and dedicated to the public domain.
