Scope and terms
This specification defines the rider-facing planner contract. It covers coordinate projection, directed transit services, walking access, transfers, candidate selection, result states, offline behavior, and the boundary between the planner and other services. The planner engine and planner image build explain implementation; they do not replace these behavior requirements.
The planner receives coordinates. Place search resolves human text before this contract begins. A planner query contains an origin, a destination, a requested mode, a query timestamp, a request ID, and optional live-arrival records.
Rider stories
- A rider can request a bus-only, jeepney-only, or either-mode trip between two places.
- A rider can see when the planner found no usable connection instead of receiving a route assembled from guessed transfers.
- A rider can repeat a previously loaded route query without a network request when the static planner image is cached and valid.
- A rider can distinguish a measured live wait from a default, unknown, or unavailable value.
- A rider can use the result without relying on color, animation, or map position alone.
Functional requirements
| ID | Requirement |
|---|---|
| MP-01 | The planner MUST accept an origin and destination coordinate and MUST reject invalid coordinates before search. |
| MP-02 | The planner MUST return samePlace when the endpoints are within 25 m. |
| MP-03 | The planner MUST return outsideServiceArea when the canonical endpoints are outside the compiled service area. |
| MP-04 | The planner MUST support bus, jeepney, and both. Both means either mode is eligible; it MUST NOT imply that every result is mixed-mode. |
| MP-05 | The planner MUST return no more than four selected itineraries. |
| MP-06 | Each itinerary MUST contain access, ride, and egress information sufficient to explain how the result was formed. |
Connectivity and direction
| ID | Requirement |
|---|---|
| MP-10 | A bus connection MUST be grounded in the identity of an official ordered stop. |
| MP-11 | A jeepney service MUST have explicit direction data. The planner MUST NOT infer direction from the rider's pins or silently reverse a geometry without source direction evidence. |
| MP-12 | A same-mode transfer MUST use the mode's canonical transfer identity. Geometric closeness alone MUST NOT create a same-mode edge. |
| MP-13 | A cross-mode transfer MUST involve an official bus stop and a jeepney route point and MUST remain within the current 400 m walking bound. |
| MP-14 | If a reviewed transfer registry is introduced, each entry MUST retain source, review state, effective version, and the two service identities. The current compiler path does not show a separate registry; its current cross-mode rule is the official-bus-node plus jeepney-geometry distance check. |
| MP-15 | The planner MUST preserve service identity and direction through search, materialization, and explanation. |
The 400 m value is a compiler bound, not proof that a crossing is safe or that a sidewalk exists. The product MUST avoid presenting it as a pedestrian route guarantee.
Rider-facing selection
| ID | Requirement |
|---|---|
| MP-20 | An itinerary MUST have one or two ride groups. Three ride groups MUST be rejected. |
| MP-21 | An itinerary MUST NOT board the same service twice. |
| MP-22 | Origin access and destination egress MUST each be at most 1,500 m, and their sum MUST be at most 2,000 m. |
| MP-23 | A post-boarding transfer walk MUST be at most 400 m. |
| MP-24 | Near-duplicate trips with the same first mode, endpoints within 100 m, and scores within two minutes SHOULD collapse to one result. |
| MP-25 | Selection MUST be separate from graph search. A graph-valid candidate MAY be rejected by rider policy. |
The ranking tuple currently uses score, ride count, transfer walking, total walking, longest walking leg, ride distance, first service ID, and path identity. The specification does not make those internal fields a client API. It requires stable selection behavior and an explanation of the chosen legs.
Result states
The planner MUST distinguish at least these outcomes:
| State | Meaning |
|---|---|
| plannerUnavailable | The image could not be loaded, verified, or mounted |
| samePlace | The endpoints are within the same-place threshold |
| outsideServiceArea | One or both endpoints are outside the compiled service area |
| too-far | The query cannot satisfy the planner's access or endpoint policy |
| noConnectingRoute | Search found no candidate that passed topology and rider selection |
| tripFound | At least one selected itinerary was materialized |
The UI MUST explain an unavailable or rejected state without implying that the transit network has no possible route in every circumstance. It should distinguish “the planner is unavailable” from “this query has no connecting route.”
Offline, live data, and fares
| Boundary | Contract |
|---|---|
| Static topology | After a valid image is cached, route search MUST work without a network request. |
| Live arrivals | Live data is optional enrichment. Missing or stale arrivals MUST NOT prevent static route planning. |
| Current web behavior | The web client currently sends an empty live-arrival list, so the first bus wait uses a seven-minute default marked as live time unavailable. |
| Place search | Geocoding and place autocomplete are outside the planner. A failed network resolver MUST not be allowed to invent graph edges. |
| Fares | Planner score is not fare. Fare display MUST identify its source, estimate status, and freshness. The current planner request does not carry fare data. |
| Saved trips | Saved coordinates and route descriptions SHOULD remain local unless a separate sync feature documents its storage and privacy contract. |
The performance requirement is operational rather than an unverified latency number. Query work MUST run in a Web Worker and MUST NOT block map interaction, typing, or pin movement. Release benchmarks MUST name the device, browser, image hash, query set, and whether the image was already mounted. The project MUST NOT publish a universal sub-second claim without that evidence.
Accessibility and privacy
- Every result state MUST be available in text. Map geometry and color alone are insufficient.
- Walking, riding, transfer, wait, and unavailable states MUST have distinct labels.
- The interface MUST preserve keyboard and assistive-technology access to origin, destination, mode, result selection, and retry actions.
- Reduced-motion settings MUST not remove route meaning.
- Coordinates used for planning SHOULD stay in the browser and worker after place resolution. Telemetry and geocoder requests MUST be treated as separate network events.
Acceptance examples
The following examples are contract checks, not fixed route-name fixtures:
| Scenario | Expected result |
|---|---|
| Origin [125.62562, 7.11925], Sampaguita benchmark destination [125.4950106, 7.0201389] | No selected trip may exceed either 1,500 m end cap or the 2,000 m combined access cap. |
| Origin [125.35, 6.75] | outsideServiceArea. |
| Two pins within 25 m | samePlace. |
| Mixed benchmark pins [125.64503318411107, 7.144785528776538] to [125.4894257654426, 7.013155885549239] | The selected result must satisfy access and transfer limits and, when the mixed path is available, preserve both bus and jeepney service identity. |
| bus request on a map with only jeepney candidates | No jeepney ride may appear. |
| both request on a map with only one available mode | The available mode may be returned; both does not require a mixed result. |
The planner tests also cover access boundary values, transfer distance, reboarding, three-ride rejection, near-duplicate suppression, reverse-search equivalence, and invalid transfer paths that must not hide a legal direct ride.
Release and rollback
Before release, the build MUST:
- validate the source bundles and service-area data;
- compile the planner image twice and confirm identical bytes and SHA-256;
- publish the manifest with the matching hash-named artifact;
- run planner image and selection regression tests;
- verify the web build precaches the artifact within the configured 32 MB limit.
The deployment process SHOULD retain the previous manifest and artifact long enough to roll back a bad publication. A rollback MUST restore the pair together. The current compiler's temporary-file rename protects local output, but it is not a deployment transaction.
Open questions remain around pedestrian-safe transfer evidence, route geometry provenance, live wait integration, and a named-device performance budget. Those questions must be resolved with data or tests before they become stronger claims in this specification.