diff --git a/routing/src/data/route-fixtures.json b/routing/src/data/route-fixtures.json new file mode 100644 index 0000000..f761479 --- /dev/null +++ b/routing/src/data/route-fixtures.json @@ -0,0 +1,9 @@ +{ + "_license": "ODbL-1.0", + "_attribution": "© OpenStreetMap contributors", + "_notice": "Route geometry © OpenStreetMap contributors, precomputed from the public OSRM demo server (router.project-osrm.org) at build time between fixed public landmark coordinates. ODbL v1.0 — https://opendatacommons.org/licenses/odbl/1-0/", + "_source": "OSRM demo server (router.project-osrm.org) — build-time fetch, never a runtime dependency", + "version": 1, + "originToleranceM": 200, + "pairs": [] +} diff --git a/routing/src/types.ts b/routing/src/types.ts new file mode 100644 index 0000000..f1340fc --- /dev/null +++ b/routing/src/types.ts @@ -0,0 +1,132 @@ +/* + * types.ts — the routing contracts (D-01, D-03, D-05, D-07, D-11). + * ---------------------------------------------------------------- + * RoutePoint / RouteRequest / RouteResult / RoutingSource are the seam + * every backend implements: the build-time fixture corpus (backend #1, + * "fixture", this phase), the client-side WASM router (backend #2, + * "wasm-router" — OSS track, post-v1; origin+destination never touch a + * server), and Valhalla-on-VPS (backend #3, documented provision path, + * not shipped). The ladder is DOCUMENTED, not switchable: no env read, + * no config read, no dynamic backend registry (T-05-04) — the import + * site constructs the backend in code (plan 05-04). + * + * THE NULL CONTRACT IS LOAD-BEARING (D-03): route() resolving to NULL is + * the honest "router pending" state — an unknown destination, or an + * origin outside the fixture corpus's tolerance. Never a blank map, + * never a fake route, never a thrown error for a normal miss. + * + * No logging, no storage, no network (D-05/D-12/D-15 analog): request + * coordinates never leave the caller's frame. + */ + +/** A WGS84 point. */ +export interface RoutePoint { + lat: number; + lng: number; +} + +/** A routing request. The origin is the live fix (memory only — GEO-03/D-07). */ +export interface RouteRequest { + origin: RoutePoint; + /** The gazetteer id resolved by the Phase 4 destination resolver. */ + destinationId: string; +} + +/** Distance/duration summary. Distances in meters, durations in seconds. */ +export interface RouteSummary { + distanceM: number; + durationS: number; +} + +/** + * A maneuver step — DAY-ONE FIELD (D-07, GUID-05/06 upstream obligation). + * Fixture-world steps are ALWAYS empty arrays (D-10 defers instructions to + * Phase 6): an empty array is honest "not wired"; a fabricated step list + * would not be. Real step geometry arrives with backends #2/#3. + */ +export interface RouteStep { + distanceM?: number; + durationS?: number; + name?: string; + /** polyline6-encoded step geometry (backend #2/#3 populate this). */ + geometry?: string; +} + +/** + * Decoded geometry + the snapped-progress support field — DAY-ONE FIELD + * (D-07, GUID-05/06 upstream obligation): Phase 6's guidance walks a live + * fix along cumulativeDistanceM instead of re-deriving it per fix. + */ +export interface RouteGeometry { + points: RoutePoint[]; + /** Same length as points; [0] === 0; non-decreasing. Meters along the line. */ + cumulativeDistanceM: number[]; +} + +/** One routable alternative. options[0] of a result is the BEST route. */ +export interface RouteOption { + geometry: RouteGeometry; + summary: RouteSummary; + steps: RouteStep[]; +} + +export interface RouteResult { + destinationId: string; + origin: RoutePoint; + /** 1..3 options, index 0 = best (order preserved from the backend). */ + options: RouteOption[]; + /** === the RoutingSource name that produced it. */ + backend: string; +} + +/** + * The pluggable routing seam (D-01). Backends: "fixture" (this phase) → + * "wasm-router" (OSS track, backend #2 — client-side, origin+destination + * never touch a server) → "valhalla" (VPS, backend #3). Backends #2/#3 do + * NOT ship in this phase — the interface exists so they slot in without a + * client rewrite, exactly parallel to SearchSource's ladder (D-03/D-04). + * + * THE NULL CONTRACT IS LOAD-BEARING (D-03): route() resolving to NULL is + * the honest "router pending" state — an unknown destination, or an origin + * outside the fixture corpus's tolerance. Never a blank map, never a fake + * route, never a thrown error for a normal miss. + * + * No logging, no storage, no network (D-05/D-12/D-15 analog): request + * coordinates never leave the caller's frame. + */ +export interface RoutingSource { + readonly name: string; + route(req: RouteRequest): Promise; +} + +/** One committed fixture route — the polyline6 string stored VERBATIM + * from the build-time OSRM demo response (RESEARCH Finding 1). */ +export interface FixtureRoute { + /** polyline6, stored VERBATIM from the OSRM demo response. */ + geometry: string; + distanceM: number; + durationS: number; +} + +/** One golden origin→destination pair of the fixture corpus (D-02). */ +export interface FixturePair { + /** "-to-", slug charset — also the ?fixpair= knob value. */ + pairId: string; + origin: { lat: number; lng: number; label: string }; + destinationId: string; + /** Best-first, 1..3 entries (OSRM demo returns best-first; preserved). */ + routes: FixtureRoute[]; +} + +/** The committed dataset envelope (route-fixtures.json) — the ODbL + * attribution travels INSIDE the file, the gazetteer's three-surfaces + * pattern (T-05-06). Tests inject synthetic values of this shape. */ +export interface RouteFixturesFile { + _license: string; + _attribution: string; + _notice: string; + _source: string; + version: number; + originToleranceM: number; + pairs: FixturePair[]; +}