Context

The bus map has four different failure modes that are easy to collapse into one “route data” problem:

  1. A catalog can identify the wrong service or direction.
  2. Ordered stops can be connected with geometry that does not follow roads.
  3. A valid geometry release can fail to reach the browser through the tile API.
  4. Telemetry can drift from a static route without proving that the catalog is wrong.

The R102:AM and R102:PM examples make the first boundary concrete. They are separate ordered services, not two labels on one undirected line. The geometry boundary is equally concrete: a stop sequence can preserve topology while a direct connection between coordinates cuts across blocks. The delivery boundary appeared in the tile fallback work recorded in 9a0533b, while route identity was made explicit in 6556e70.

Decision

The bus data lifecycle has these boundaries:

  • The route catalog and normalized bus stop records define route identity and ordered topology.
  • Build-time OSRM-compatible routing may produce canonical display geometry from that topology.
  • Geometry validation must pass before a bus bundle or tile release is produced.
  • Vector tiles are versioned delivery artifacts. The manifest is published after the versioned objects have been uploaded and verified.
  • The web map may fall back to the loaded bundle after a confirmed tile-manifest failure. Ordered-stop geometry is marked approximate because it preserves topology, not road shape.
  • Telemetry and drift reports are evidence for review. They do not silently rewrite the catalog or canonical geometry.

The source-selection contract is intentionally explicit:

example.ts
1if (input.manifest) return { kind: "tiles", manifest: input.manifest }
2if (input.manifestFailed && input.hasBundle) return { kind: "bundle" }
3return { kind: "pending" }

This prevents two opposite mistakes. A temporary unresolved manifest should not immediately be called a tile outage, and a fallback line should not be presented as though it had the same geometric provenance as the canonical route.

Runtime states

The web map waits for a source decision, then either renders the tile release or falls back to the loaded bundle. The state is about source selection; it does not hide whether the geometry is canonical or approximate.

The state diagram describes the web source decision, not a promise that every map component has already rendered. The API still reports the delivery failure, and the map still needs to mark or otherwise preserve the approximate geometry distinction in its feature properties.

Consequences

This lifecycle keeps route identity stable across GeoJSON, bundles, tiles, and the map. It also leaves room for tile releases to change their zoom range or compression without changing the transit contract. A tile release cannot introduce a new service without failing route-reference validation against canonical geometry.

The fallback has a visible cost. A loaded bundle can keep the map useful, but ordered-stop lines are not road evidence. A stale bundle can also keep displaying an old snapshot, so the static-data warning remains part of the metadata.

The lifecycle does not solve service verification. The current metadata says dataDate: "2026-08-10", reviewStatus: "unreviewed", and validationStatus: "passed". Validation proves that the artifact is internally consistent; it does not prove that an operator has confirmed every stop or fare.

Operational note

The current checkout has no generated tile release under .generated/bus-route-tiles, so no tile version or zoom range is recorded here. Also, the tiles:publish package script currently invokes the tile builder without the explicit zoom arguments that the builder requires. The runbook documents the separate build, validate, and deploy commands until that interface is reconciled.

Implementation references: build-bus-bundle.ts, build-bus-route-tiles.ts, deploy-bus-route-tiles.ts, and bus-route-data.ts.