feat(05-01): RoutingSource contract + day-one route model + fixture seed schema
- types.ts: the D-01 backend-ladder seam (fixture -> wasm-router -> valhalla), D-03 null contract documented on the interface, D-07 day-one fields (RouteStep typed + RouteGeometry.cumulativeDistanceM, GUID-05/06 obligation) - route-fixtures.json: committed EMPTY seed with the ODbL header (license/attribution/notice, T-05-06) — plan 05-02 populates it
This commit is contained in:
@@ -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<RouteResult | null>;
|
||||
}
|
||||
|
||||
/** 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 {
|
||||
/** "<origin-id>-to-<dest-id>", 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[];
|
||||
}
|
||||
Reference in New Issue
Block a user