diff --git a/bot/test/guidance-cron.test.mjs b/bot/test/guidance-cron.test.mjs index d94870d..636a530 100644 --- a/bot/test/guidance-cron.test.mjs +++ b/bot/test/guidance-cron.test.mjs @@ -49,6 +49,7 @@ const { strings } = await import("../src/i18n/strings.ts"); const { encodePolyline6 } = await import("@araharah/routing/src/polyline.ts"); const { deriveCumulativeDistanceM, haversineM } = await import("@araharah/routing/src/geo.ts"); const { encodeGraph, decodeGraph } = await import("@araharah/routing/src/graph.ts"); +const { LANDMARK_QUANTUM_S, landmarkTables } = await import("@araharah/routing/src/landmark.ts"); /* ————— geometry helpers (1e-6-grid-exact construction, the codec's grid law) ————— */ @@ -249,15 +250,23 @@ test("GC6b unnamed matched edge → cardStreetUnnamed ('UNNAMED ROAD') — still // A purpose-built unnamed way through the same encodeGraph contract // (names: [] → every edge carries the UNNAMED_NAME_ID sentinel). const meters = haversineM({ lat: 3.15, lng: 101.69 }, { lat: 3.1505, lng: 101.69 }); + const edges = [ + { from: 0, to: 1, seconds: meters / (30 / 3.6) }, + { from: 1, to: 0, seconds: meters / (30 / 3.6) }, + ]; + // A 2-node graph has no degree>=2 farthest-point candidate (the selection + // filter), so the anchor pins directly — the tables still come from the + // ONE integer-Dijkstra core (08-02), through the ONE encode authority. + const landmarkInput = { nodeCount: 2, edges, quantumS: LANDMARK_QUANTUM_S }; + const anchors = Uint32Array.of(0); + const { to, from } = landmarkTables(landmarkInput, anchors); const buf = encodeGraph({ lat: [3.15, 3.1505], lng: [101.69, 101.69], - edges: [ - { from: 0, to: 1, seconds: meters / (30 / 3.6) }, - { from: 1, to: 0, seconds: meters / (30 / 3.6) }, - ], + edges, names: [], maxSpeedKmh: 30, + landmarks: { quantumS: LANDMARK_QUANTUM_S, nodes: anchors, to, from }, }); const graph = decodeGraph(buf); assert.notEqual(graph, null); diff --git a/bot/test/webhook.test.mjs b/bot/test/webhook.test.mjs index 44b3351..178973e 100644 --- a/bot/test/webhook.test.mjs +++ b/bot/test/webhook.test.mjs @@ -472,6 +472,22 @@ test("GW11 PUT /api/guidance → 405", async () => { const { encodeGraph } = await import("../../routing/src/graph.ts"); const { haversineM } = await import("../../routing/src/geo.ts"); +const { LANDMARK_QUANTUM_S, farthestPointAnchors, landmarkTables } = await import( + "../../routing/src/landmark.ts" +); + +/** Tiny REAL landmark block through the ONE preprocessing core (08-02): + * farthest-point anchor + integer ĉ tables — computed, never faked. + * `{ pin }` pins the anchor for graphs with no degree>=2 candidate (the + * selection filter's law — e.g. a single-segment graph); the tables still + * come from the ONE integer-Dijkstra core. */ +function landmarkBlock(nodeCount, edges, { pin } = {}) { + const input = { nodeCount, edges, quantumS: LANDMARK_QUANTUM_S }; + const anchors = pin !== undefined ? Uint32Array.of(pin) : farthestPointAnchors(input, 1); + if (anchors.length !== 1) throw new Error("graph has no degree-2 anchor candidate"); + const { to, from } = landmarkTables(input, anchors); + return { quantumS: LANDMARK_QUANTUM_S, nodes: anchors, to, from }; +} /** The committed 06-01 ground truth (25 nodes around KL center) via fs. */ const MINI_GRAPH = readFileSync(new URL("../../routing/test/fixtures/mini-graph.bin", import.meta.url)); @@ -496,7 +512,14 @@ function corridorGraphBuffer({ gap = false } = {}) { const seconds = meters / (60 / 3.6); edges.push({ from: i, to: i + 1, seconds, nameId: 0 }, { from: i + 1, to: i, seconds, nameId: 0 }); } - return encodeGraph({ lat, lng, edges, names: ["Jalan Koridor Ujian"], maxSpeedKmh: 60 }); + return encodeGraph({ + lat, + lng, + edges, + names: ["Jalan Koridor Ujian"], + maxSpeedKmh: 60, + landmarks: { ...landmarkBlock(n, edges) }, + }); } /** Nodes cluster at two far-apart cells with a nodeless middle: an in-bbox @@ -506,15 +529,17 @@ function sparseGraphBuffer() { const lng = [101.69, 101.6905, 101.7]; const meters = haversineM({ lat: lat[0], lng: lng[0] }, { lat: lat[1], lng: lng[1] }); const seconds = meters / (50 / 3.6); + const edges = [ + { from: 0, to: 1, seconds, nameId: 0 }, + { from: 1, to: 0, seconds, nameId: 0 }, + ]; return encodeGraph({ lat, lng, - edges: [ - { from: 0, to: 1, seconds, nameId: 0 }, - { from: 1, to: 0, seconds, nameId: 0 }, - ], + edges, names: ["Jalan Sparse Ujian"], maxSpeedKmh: 50, + landmarks: { ...landmarkBlock(lat.length, edges, { pin: 0 }) }, }); }