Files
arah2/.planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-CONTEXT.md
T

113 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 8: ALT Landmark Preprocessing (Routing Backend v2) - Context
**Gathered:** 2026-10-25
**Status:** Ready for planning
<domain>
## Phase Boundary
Cross-metro routes route in-budget on the free plan: ALT (A\*, Landmarks, Triangle-inequality) preprocessing over the CSR graph upgrades engine A's worst case while staying $0 — the c2 rung of the measured ladder, executed (committed by Phase 6's post-planning A1 ratification). Concretely: build-time landmark distance tables, a graph-layout v2 binary that carries them, the same R2 hosting + unchanged upload script, a corpus re-run proving optimality is unaffected, the free-plan CPU gate passing with p95 under the ceiling, and the c3 degradation class retiring from KNOWN-LIMITATIONS.
No new product surfaces — the user-visible outcome is unchanged routing behavior that now covers the longest cross-metro KL routes inside the CPU budget.
</domain>
<decisions>
## Implementation Decisions
### Binary layout compatibility (user decision D-01)
- **D-01:** **ARG2-only, fail-honest.** The graph layout version bumps; the landmark-carrying layout is a new version, and old ARG1 binaries decode to null (the existing fail-honest law in `graph.ts`) → the Phase 6 designed **router-pending state** covers them. There is exactly **one decode path and one search path** — no v1 fallback branch, no silent quality regression; a fork (or our own R2 during rollout) routes nothing until the v2 binary is uploaded once. Chosen over dual-version decode to keep the single-authority law: the permanent cost of two search paths (and a silently degraded mode that contradicts fail-honest) outweighs a small, honest, temporary unavailability window. The upload script stays unchanged (roadmap lock) — re-uploading the rebuilt binary is the whole migration.
### Landmark budget (user decision D-02)
- **D-02:** **A scaling rule, not a fixed count.** The selection *approach* is locked — build-time Dijkstra passes over well-spread anchor nodes (farthest-point/hill-climb family over the road graph; anchors are road-network nodes, NOT POIs — restaurants/shops live in the Phase 4 gazetteer). The landmark *count* is a measurement-justified, node-count-proportional quantity: the KL build ships whatever count the CPU-gate measurement justifies (expected in the lean ~16–32 range; the curve flattens fast at metro scale). Rationale locked in discussion: per-landmark bytes scale with node count (~1.2 MB/landmark at KL's 311k nodes), so a fixed "generous" count explodes at future Malaysia scale (~12–24 MB/landmark at country network size) while ALT's advantage itself narrows at that scale (that tier is Contraction Hierarchies' job, still deferred per Phase 6 D-02). A future Malaysia-wide build applies the same scaling rule at its own scale — nothing is over-provisioned now for a graph that doesn't exist.
### Optimality verification definition (user decision D-03)
- **D-03:** **Equal seconds, ties allowed.** The corpus re-run gate asserts: total route **seconds** match the pre-ALT baseline exactly (or within a named tiny epsilon, ~±0.1%) and every pair stays in the same verdict class (reachable/unreachable). ALT changes A\*'s steering, never its cost model — optimal seconds are guaranteed; but bidirectional search + different potentials may legitimately change **tie-breaking** (a different equal-cost path). Tie-path differences are documented behavior, NOT failures. Bit-identical node paths is explicitly NOT the gate (brittle — fails on legitimate ties).
### Measurement sample (user decision D-04)
- **D-04:** **Extend the sample for the ALT verdict.** The existing 25-route seeded gate (`measure-route-cpu.mjs`, seed `0x06d4`) stays as the CI-size snapshot; the ALT verdict additionally runs a maintainer-time extended seeded sample (~100 cross-metro worst-case pairs) for confidence that the longest routes route in-budget. Maintainer-time measurement is free — bigger evidence at zero runtime cost. Same print-the-measurement law.
### Limitations retirement (user decision D-05)
- **D-05:** **Retire the c3 class with evidence.** `docs/KNOWN-LIMITATIONS.md`'s cross-metro CPU degradation section is replaced by a short retirement record: what changed (ALT preprocessing), the measured numbers that retired it (p95 under the ceiling, from D-04's run), and the date. The ALT row in the limitations' roadmap-pointer table flips from "Next-milestone item, not built" to built (Phase 8). The honest audit trail stays in-document (measurements print; limitations never overpromise). Note: because of D-01 there is NO "fallback for landmark-less graphs" to document — an old graph is simply router-pending, which is already a designed, documented degradation.
### OpenCode's Discretion
- Landmark-selection algorithm specifics (farthest-point vs hill-climb vs hybrid), anchor count formula constants, and any quantization of stored distances (e.g., u16-seconds research) within the scaling rule
- Preprocessing build-time cost budget (each landmark = one full graph pass; build script runtime stays sanity-bounded)
- The exact epsilon value and its name (named constant, replay-tested, per phase-6 constant law)
- ARG2 layout byte design (header extensions aligned to the typed-array law; corrupt-binary fail-honest validation carried forward)
- How the committed mini-graph fixture and test suite version-bump (new-ARG2 fixtures; old-v1 fixture kept only as a decode-rejection case)
- KNOWN-LIMITATIONS retirement wording within the honest-engineering tone law
</decisions>
<specifics>
## Specific Ideas
- The user explicitly asked for (and received) the landmark concept explanation: ALT anchors are abstract road-graph reference points, not places. This distinction should survive into research/planning docs so future readers don't confuse it with POI search.
- The whole-malaysia question shaped D-02: the decision is deliberately future-compatible — a Malaysia build should re-derive landmark count from the same rule (and may reasonably graduate to CH per Phase 6's deferral), never inherit a KL-tuned constant.
- "Fail-honest beats silent degradation" was the deciding principle for D-01 — consistent with the repo's designed-degradation philosophy (router-pending is a feature, not an error).
</specifics>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Phase scope + decisions
- `.planning/ROADMAP.md` §Phase 8 — goal, 3 success criteria, "graph-layout v2 with landmark distances precomputed at build time; upload script unchanged"
- `.planning/phases/06-turn-by-turn-guidance-live-driving/06-CONTEXT.md` — engine A pivot (D-01/D-02), the A1 ratification committing c2 (ALT) as this phase and rejecting Workers Paid; Phase 6's CH/turn-restrictions deferral list
- `.planning/phases/06-turn-by-turn-guidance-live-driving/06-04-SUMMARY.md` — the measured ladder history (full graph unidirectional 38.4 ms p95 → drop-classes rejected on correctness → bidirectional BH kept) and the real-graph build facts (311,325 nodes / 677,068 directed edges / 14.7 MB / all landmarks in one strongly-connected component)
- `.planning/phases/07-hardening-private-launch/07-CONTEXT.md` — KNOWN-LIMITATIONS doc shape (07 D-08) and the consolidated budget record (07 D-06) that SC's numbers join
### Codebase
- `routing/src/graph.ts` — the pinned CSR binary layout ("ARG1" v1, version field, fail-honest decode): the codec this phase versions to ARG2; encode remains the single authority
- `routing/src/astar.ts` — the bidirectional A\* (BH) ALT builds on; its traversal law, equilibrate rule, and pure-module law
- `routing/scripts/measure-route-cpu.mjs` — the CPU gate (P95_BUDGET_MS 8, 25-route seeded sample, ladder history in its header): the gate this phase must pass
- `routing/scripts/build-road-graph.mjs` — the build tool where the preprocessing stage joins ( Overpass extract → dedup → encode )
- `routing/scripts/route-corpus.mjs` — the corpus re-run tool the optimality gate (D-03) rides
- `routing/scripts/upload-road-graph.mjs` — the unchanged fork migration path (D-01)
- `docs/KNOWN-LIMITATIONS.md` — the c3 section + ALT roadmap-pointer row that D-05 retires
- `bot/src/routing/worker-router.ts` — the R2-hosted graph consumer (key `kl-roadgraph.v1.bin`) that serves `/api/route`; consumes the v2 layout unchanged at its API
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `graph.ts` encode/decode single authority — the ARG2 layout extends one module, pins one header, keeps zero-copy typed-array laws
- `astar.ts` bidirectional search — ALT potentials slot into the existing lazy-potential mechanism; no new search skeleton
- `measure-route-cpu.mjs` + `route-corpus.mjs` — the gate and corpus harness both re-run as-is (sample extension is a parameter, not a rewrite)
- Committed mini-graph fixture — test corpus basis; version-bumped fixtures derive through the same encode path
- `snap.ts` — unchanged; snapping is orthogonal to ALT (D-05 phase-6 single-authority law holds)
### Established Patterns
- Fail-honest decode → router-pending (designed degradation, never an error)
- Named constants, replay-tested no magic numbers (applies to epsilon + landmark scaling constants)
- Budget gates print their measurement and gate on p95 with margin
- TDD RED→GREEN with hand-rolled runners; pure modules (no I/O in routing/src)
### Integration Points
- `build-road-graph.mjs` gains the preprocessing stage (one Dijkstra pass per landmark at build time)
- R2 `ROAD_GRAPH` binding + `upload-road-graph.mjs` — same key path, new-version binary
- Engine-B (Phase 11) downloads this same asset — the scaling rule + lean KL count keep the future phone payload in the ~30–50 MB class
- `docs/KNOWN-LIMITATIONS.md` and `docs/CONFIGURATION.md` — the record surfaces D-05 touches
</code_context>
<deferred>
## Deferred Ideas
- Contraction Hierarchies — remains the Phase 6 deferral; the noted future tier if routing ever graduates to Malaysia-wide scale (D-02's rationale points there)
- Engine B client-side router consuming the ARG2 asset — Phase 11 (the phone-download payload concern in this phase's discussion feeds its budget documentation)
- Turn restrictions in the graph — Phase 6 deferral stands
- Any traffic/time-dependent weighting — v2 per REQUIREMENTS
</deferred>
---
*Phase: 08-alt-landmark-preprocessing-routing-backend-v2*
*Context gathered: 2026-10-25*