Context

A route line passing close to another line is weak evidence. It does not identify a shared stop, a legal boarding point, or a place where a rider can cross the road. The problem is sharper for Davao jeepneys because route geometry and direction evidence are not as structured as the bus stop catalog.

The planner also exposed a second version of the same mistake. The Buhangin to Sampaguita case produced a graph-valid itinerary with a historical report of 4.7 kilometres of initial access walking, a 17-kilometre bus ride, and 22.2 kilometres overall. The graph could connect the path. That did not make it reasonable advice. The incident is described in Graph-valid but rider-absurd route.

Decision

The compiler and selector use typed boundaries:

  • A service is directed. Jeepney directions come from explicit input, and the compiler does not create a reverse service only because a LineString can be reversed.
  • Same-mode transfers require a shared transferKey and different service identities.
  • A bus-to-jeepney transfer requires an official bus stop on the bus side and a jeepney node within 400 metres. The edge carries walking cost and the target service's boarding wait.
  • Each access end is capped at 1,500 metres. The two endpoint walks together are capped at 2,000 metres.
  • A selected candidate has one or two rides, does not reboard the same service, and does not exceed 400 metres of transfer walking.

This is a prohibition on arbitrary proximity edges, not a prohibition on every geometric intermodal edge. The current compiler deliberately allows one bounded, mode-aware case.

The following is a partial excerpt from the current compiler. It checks the semantic precondition before the later distance loop:

example.ts
1 if (node.stopOrdinal === NONE_U32) {
2 throw new Error("bus transfer node is not an official stop")
3 }
4 const coordinate = coordinateForNode(node, coordinates)
5 const bucket = Math.floor(coordinate.latE7 / TRANSFER_LATITUDE_BUCKET_E7)
6 const bucketNodes = busNodesByLatitudeBucket.get(bucket)
7 if (bucketNodes === undefined) busNodesByLatitudeBucket.set(bucket, [node])
8 else bucketNodes.push(node)

Source: planner-compile-edges.ts. The same function later skips a candidate when walkMm is greater than TRANSFER_MAX_MM. A 400-metre transfer can compile; the compiler test for 401 metres expects no transfer edge.

The access rule is enforced after query projection by accessWithinCaps in planner-runtime-policy.ts. This placement keeps the base graph reusable. A service is not removed globally because one rider starts too far from it. The incident page shows the function alongside the boundary tests.

Consequences

The planner avoids connecting arbitrary route points merely because their coordinates are close. Official bus stop identity, explicit service direction, transfer keys, and bounded distance all remain visible in the compiled graph. Candidate selection can reject a long access walk without changing the base topology.

The rules do not prove pedestrian safety. Coordinate distance is not a street route, and the current transfer check does not know about medians, fences, private land, or crossing signals. A valid direction file can still describe an imperfect route. These limits belong in the data and product explanation rather than behind an absolute safety claim.

The current checkout has no separate transfer-registry file. Earlier design notes used reviewed transfer provenance, but the active compiler derives intermodal edges from official-stop identity and the distance bound. If a reviewed registry becomes required, it must be added as an input with its own validation and version.

The 1,500-metre rule is also not a minimum transit-ride rule. There is no current MIN_TRANSIT_RIDE_MM constant. The compiler rejects zero-length ride segments, and candidate construction rejects a candidate with zero ride distance. That is a different invariant.

The browser path uses static topology and currently supplies no live bus arrivals to the planner. No telemetry update can repair a false graph edge during this calculation.

Status

Accepted. The current compiler enforces the direction, transfer-key, official-stop, and distance boundaries described above.