test(08-02): bot-suite encodeGraph call sites carry landmark blocks (full battery green)

webhook corridor/sparse builders + guidance-cron unnamed way compute
tiny tables through the ONE preprocessing core (@araharah/routing
farthestPointAnchors + landmarkTables) and pass the landmarks block
into the same single encodeGraph call — call-site updates, not a
second encode function. Graphs with no degree>=2 candidate (sparse,
2-node) pin their anchor explicitly; tables still come from the
integer-Dijkstra core.

FULL BATTERY at this commit: routing:test 74/74, bot 126/126, both
typechecks clean; the regenerated fixture is deterministic (byte-
identical re-run); mini-graph-arg1.bin is byte-stable vs its committed
08-01 bytes.
This commit is contained in:
araharah-executor
2026-10-25 18:50:20 +08:00
parent 32a00b5b0b
commit 9770867fd2
2 changed files with 43 additions and 9 deletions
+13 -4
View File
@@ -49,6 +49,7 @@ const { strings } = await import("../src/i18n/strings.ts");
const { encodePolyline6 } = await import("@araharah/routing/src/polyline.ts"); const { encodePolyline6 } = await import("@araharah/routing/src/polyline.ts");
const { deriveCumulativeDistanceM, haversineM } = await import("@araharah/routing/src/geo.ts"); const { deriveCumulativeDistanceM, haversineM } = await import("@araharah/routing/src/geo.ts");
const { encodeGraph, decodeGraph } = await import("@araharah/routing/src/graph.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) ————— */ /* ————— 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 // A purpose-built unnamed way through the same encodeGraph contract
// (names: [] → every edge carries the UNNAMED_NAME_ID sentinel). // (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 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({ const buf = encodeGraph({
lat: [3.15, 3.1505], lat: [3.15, 3.1505],
lng: [101.69, 101.69], lng: [101.69, 101.69],
edges: [ edges,
{ from: 0, to: 1, seconds: meters / (30 / 3.6) },
{ from: 1, to: 0, seconds: meters / (30 / 3.6) },
],
names: [], names: [],
maxSpeedKmh: 30, maxSpeedKmh: 30,
landmarks: { quantumS: LANDMARK_QUANTUM_S, nodes: anchors, to, from },
}); });
const graph = decodeGraph(buf); const graph = decodeGraph(buf);
assert.notEqual(graph, null); assert.notEqual(graph, null);
+30 -5
View File
@@ -472,6 +472,22 @@ test("GW11 PUT /api/guidance → 405", async () => {
const { encodeGraph } = await import("../../routing/src/graph.ts"); const { encodeGraph } = await import("../../routing/src/graph.ts");
const { haversineM } = await import("../../routing/src/geo.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. */ /** 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)); 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); const seconds = meters / (60 / 3.6);
edges.push({ from: i, to: i + 1, seconds, nameId: 0 }, { from: i + 1, to: i, seconds, nameId: 0 }); 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 /** 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 lng = [101.69, 101.6905, 101.7];
const meters = haversineM({ lat: lat[0], lng: lng[0] }, { lat: lat[1], lng: lng[1] }); const meters = haversineM({ lat: lat[0], lng: lng[0] }, { lat: lat[1], lng: lng[1] });
const seconds = meters / (50 / 3.6); const seconds = meters / (50 / 3.6);
const edges = [
{ from: 0, to: 1, seconds, nameId: 0 },
{ from: 1, to: 0, seconds, nameId: 0 },
];
return encodeGraph({ return encodeGraph({
lat, lat,
lng, lng,
edges: [ edges,
{ from: 0, to: 1, seconds, nameId: 0 },
{ from: 1, to: 0, seconds, nameId: 0 },
],
names: ["Jalan Sparse Ujian"], names: ["Jalan Sparse Ujian"],
maxSpeedKmh: 50, maxSpeedKmh: 50,
landmarks: { ...landmarkBlock(lat.length, edges, { pin: 0 }) },
}); });
} }