15 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 08-alt-landmark-preprocessing-routing-backend-v2 | 02 | routing |
|
|
|
|
|
|
|
|
|
~17min | 2026-10-25 |
Phase 8 Plan 08-02: Landmark Core + ARG2 Codec Summary
The landmark compute core exists once as a pure typed-array module (deterministic farthest-point anchors + exact integer ĉ-metric Dijkstras with a 65000-quantum loud overflow), graph.ts is version-bumped to ARG2 with one fail-honest decode path whose exact-size law covers the u16 table suffix, and the committed fixture is regenerated as ARG2 through that same encode authority — routing 74/74 + bot 126/126 + both typechecks green, with astar.ts untouched (search behavior provably neutral at this commit).
Performance
- Duration: ~17 min (10:34–10:51 UTC)
- Started: 2026-10-25T10:34:07Z
- Completed: 2026-10-25T10:51:00Z
- Tasks: 3/3 (tasks 1 & 2 with full RED→GREEN gate commits)
- Files modified: 10 (2 created, 8 modified)
Accomplishments
routing/src/landmark.ts— the ONE landmark compute core (zero imports, no I/O):farthestPointAnchors(first degree-≥2 candidate by node id, greedy farthest-point with per-pick forward-pass reuse, lower-id tie-breaks, documented coverageFraction early-stop knob),landmarkTables(forward + reversed integer Dijkstras over floor-quantized weights — the ĉ metric, no stored-distance rounding, no epsilon — binary-heap, lazy deletion, bit0 edges never relaxed in EITHER direction exactly mirroring astar.ts),landmarkCoverage(the build's per-anchor assert feed). 0xFFFF is DATA; any label past 65,000 quanta throws naming the distance and the fix.- ARG2 in
graph.tsin place — no second codec:GRAPH_MAGIC = 0x41524732,GRAPH_VERSION = 2,HEADER_SIZE = 72(f64 alignment kept), landmark header fields @60/@64/@68, append-only suffix (u16 toTable, u16 fromTable, u32 anchors) folded intolayoutFor'stotalarithmetic so the exact-size check rejects monster counts BEFORE any view allocation. Decode refuses ARG1 bytes (the committedmini-graph-arg1.binis the standing rejection vector), version ≠ 2,landmarkCount = 0(no landmark-less ARG2 exists — D-01/A5), hostile quantum, and any size mismatch.GraphInput.landmarksis REQUIRED and loud-validated (9 named-throw classes). - The fixture is ARG2 through the one authority: the builder gained the tiny real landmark stage (L=2 → anchors [0, 18], quantum 0.1 s, coverage 1.00/1.00, fail-loud invariants before write) and is byte-deterministic on re-run;
mini-graph-arg1.binstayed byte-identical to its committed 08-01 bytes (cmp-verified). - The full battery is green at the final commit — routing:test 74/74 (L1–L6 + G1–G11 + untouched A/P/R/S suites), bot 126/126 (RT/H/GC + the updated corridor/cron builders), routing+bot typechecks clean.
routing/src/astar.tshas ZERO changes — A1's 625-pair sweep green over the ARG2 fixture proves the codec change alone is behavior-neutral to search (routeAstar still runs haversine potentials; ALT lands in 08-03).
Task Commits
Each task was committed atomically (TDD tasks carry their RED gates):
- task 1: landmark.ts — the pure landmark compute core —
c3a31ae(test, RED) →1bf413b(test, L5 vector fix) →5b7a130(feat, GREEN) - task 2: ARG2 codec in graph.ts —
34d96b0(test, RED) →32a00b5(feat, GREEN; includes the fixture regen pull-forward) - task 3: bot call sites + full battery seal —
9770867(test)
Files Created/Modified
routing/src/landmark.ts— the pure landmark compute core (created)routing/src/graph.ts— ARG2 codec: 72-byte header, u16 suffix, version-bumped decode laws, required-landmarks encode validationrouting/test/landmark.test.mjs— L1–L6: hand-computed vectors for anchors, quantum exactness, sentinels, asymmetry, overflow, the 5×5 grid (created)routing/test/graph.test.mjs— G-suite re-pinned (G3/G5/G7/G8) + extended (G9 table round-trip, G10 encode validation, G11 decode rejection)routing/test/fixtures/build-mini-graph.mjs— landmark stage + landmark stats in the summary linerouting/test/fixtures/mini-graph.bin— regenerated ARG2 (1884 B; +208-byte table suffix + 4 header bytes + 4-byte alignment)routing/test/astar.test.mjs,routing/test/snap.test.mjs— synthetic encodeGraph call sites carry (inert until 08-03) landmark blocksbot/test/webhook.test.mjs,bot/test/guidance-cron.test.mjs— corridor/sparse/cron builders compute tiny tables viafarthestPointAnchors/landmarkTablesand pass thelandmarksblock
Decisions Made
- Pull the fixture regen forward (Rule 3): task 2's acceptance demands "runner output 0 failed" at its own commit — impossible with a committed ARG1 fixture under ARG2-only decode. The regen joined task 2's commit; task 3 verified the seal (idempotent re-run, byte-stable ARG1 vector) instead.
- Decode-side quantum validation: a non-finite/non-positive
landmarkQuantumSheader decodes null — cheap hostile-header defense so 08-03's potentials can never divide by a corrupt quantum. - Degree filter counts stored out-edges (mirrors included): the blocked mirror still evidences multi-edge road geometry at a node; endpoints/dead-ends stay excluded.
- Test-vector discipline: every pinned integer expectation was verified against an independent brute-force Dijkstra before pinning — which caught my own wrong intuition (below).
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Fixture regeneration pulled forward from task 3 into task 2's commit
- Found during: task 2 (ARG2 codec)
- Issue: task 2's own verification gate (
npm run routing:test→ 0 failed) cannot pass while the committed fixture is ARG1 bytes once decode becomes ARG2-only (G7 + A-suite + snap suite all decode the fixture) - Fix: extended
build-mini-graph.mjswith the landmark stage and regeneratedmini-graph.bininside task 2's commit; task 3 then re-ran the builder (byte-identical output — determinism proven) and sealed ARG1-vector byte-stability - Files modified: routing/test/fixtures/build-mini-graph.mjs, routing/test/fixtures/mini-graph.bin
- Verification: routing:test 74/74 at task-2 commit;
cmpvs committed 08-01 ARG1 bytes passes; regen deterministic - Committed in:
32a00b5
2. [Rule 3 - Blocking] Two encodeGraph call sites missing from the plan's enumeration
- Found during: task 2 (call-site census before implementing)
- Issue: the required-landmarks law makes EVERY encodeGraph call throw — the plan's files list omitted
routing/test/astar.test.mjs(A3's disconnected synthetic) androuting/test/snap.test.mjs(S3's bare 2-node synthetic) - Fix: both synthetics carry small hand-written landmark blocks (inert steering data until 08-03), keeping the cases' original focus
- Files modified: routing/test/astar.test.mjs, routing/test/snap.test.mjs
- Verification: A-suite and S-suite green in the full battery
- Committed in:
32a00b5
3. [Rule 1 - Bug] Two hand-computed L-suite expectations were wrong (implementation was right)
- Found during: task 1 GREEN
- Issue: (a) L4 indexed table rows by anchor NODE ID instead of anchor POSITION (row-major is
[ℓ·N+v], ℓ = position); (b) L6 assumed the ĉ-farthest node from corner 0 is the opposite corner 24 — with interior hops costing 2× perimeter quanta, interior node 18 (297 q) is farther than corner 24 (264 q) - Fix: re-pinned both vectors; node 18's 297-quantum max verified against an independent brute-force Dijkstra before pinning
- Files modified: routing/test/landmark.test.mjs
- Verification: L-suite green; the independent brute force output recorded in-session
- Committed in:
5b7a130
4. [Rule 1 - Bug] Sparse/cron graphs have no degree-≥2 farthest-point candidate
- Found during: task 3 (bot battery)
- Issue: the plan assumed every call site can
farthestPointAnchors(...)— but a single-segment graph's nodes all have out-degree 1, so selection legitimately returns empty and the first battery run failed at suite load - Fix: those call sites pin the anchor explicitly (
Uint32Array.of(0)) and still compute tables throughlandmarkTables— the selection filter is a quality law, not a table law - Files modified: bot/test/webhook.test.mjs, bot/test/guidance-cron.test.mjs
- Verification: bot suite 126/126
- Committed in:
9770867
Total deviations: 4 auto-fixed (2 blocking-call-site/closure, 2 test-vector bugs)
Impact on plan: All four were forced by the plan's own laws (required-landmarks encode, exact gate order) or by verified arithmetic; no scope creep — the 08-04/08-05 boundaries are untouched (build-road-graph.mjs still belongs to 08-04; no search code changed).
TDD Gate Compliance
Both tdd="true" tasks ran full RED→GREEN with separate commits: task 1 c3a31ae(+1bf413b) test gates BEFORE 5b7a130 feat; task 2 34d96b0 test gate BEFORE 32a00b5 feat. RED failures were verified to fail for the RIGHT reason each time (ERR_MODULE_NOT_FOUND for the new module; specific assertion deltas for the re-pinned codec laws). No gate skipped.
Issues Encountered
- A first battery run piped bot tests through
| tail -2withoutpipefail, masking the suite's exit code behind tail's; caught by reading the output (npm error line), re-run withset -o pipefail— all subsequent battery commands use pipefail. - The plan's acceptance grep contains a typo ("landmarms"); the intent (both bot files pass a
landmarks: {block) is satisfied literally.
User Setup Required
None - no external service configuration required.
Next Phase Readiness
- 08-03 (ALT potentials):
RoadGraphnow exposeslandmarkCount/landmarkQuantumS/landmarkTo/landmarkFrom/landmarkNodesas zero-copy views; onlypotential()inrouteAstarchanges. The table values are inert until then (documented coexistence — A-suite green at this commit is the neutrality proof). - 08-04 (build script):
build-road-graph.mjsstill encodes WITHOUT landmarks (line 336) — its planned preprocessing stage joins between edge assembly and the encode call, importing the SAMElandmark.tscore the fixture builder now uses. - 08-05 (campaign): the real KL binary on disk is still ARG1 → decodes null until rebuilt+re-uploaded (the designed router-pending window, D-01); the committed baseline record (08-01) is untouched and its recorder's ARG1-version guard is exactly what makes that safe.
Phase: 08-alt-landmark-preprocessing-routing-backend-v2 Completed: 2026-10-25
Self-Check: PASSED
All 8 claimed files exist on disk; all 6 task commits (c3a31ae, 1bf413b, 5b7a130, 34d96b0, 32a00b5, 9770867) exist in git history. Final battery at 9770867: routing:test 74/74, bot 126/126, routing:typecheck + bot:typecheck clean.