test(05-01): add failing fixture-source + loader-env suites (F1-F8, L1-L3)

- synthetic injected datasets only — never the network, never the committed file
- F3 pins the 200 m haversine tolerance boundary; F6 the defensive pair skip
- F7 the lazy-index source gate (LAW 1); L2 the esbuild inline marker
This commit is contained in:
araharah-executor
2026-10-24 05:02:08 +08:00
parent 4acb878c33
commit 0599ffe14f
2 changed files with 365 additions and 0 deletions
+275
View File
@@ -0,0 +1,275 @@
#!/usr/bin/env node
/*
* fixture-source.test.mjs — the fixture RoutingSource backend gates (F1–F8).
* --------------------------------------------------------------------------
* RED first (plan 05-01 task 3): every case fails while
* routing/src/fixture-source.ts does not exist.
*
* Datasets are SYNTHETIC and injected via createFixtureRoutingSource(data) —
* never the network, never the committed file (that one is exercised by the
* loader-env suite's L3 against the default source).
*
* F1 empty corpus -> null — the committed seed's state until 05-02
* F2 match serves best-first — backend tag, order, decoded geometry,
* cumulative field, EMPTY steps (T-05-07)
* F3 tolerance boundary — ~111 m serves; ~222 m is honest null
* (the 200 m law, haversine-verified)
* F4 slug guard — non-slug / over-long destinationId ->
* null WITHOUT consulting the index (T-05-03)
* F5 unknown destination — valid slug with no pair -> null (D-03,
* never a nearest-match)
* F6 malformed pair skipped — NaN distance / empty routes / throwing
* geometry are skipped at index build; a
* well-formed sibling still serves
* F7 lazy index — source gate: no `new Map(` and no
* `decodePolyline6(` call at TOP LEVEL
* (gazetteer LAW 1 — Workers 1 s startup)
* F8 getPairOrigin — slug-guarded lookup by pairId; positive
* half is deferred while the committed
* seed is empty (visible SKIP, the
* loader-env L2/L3 precedent)
*
* Run: npm run routing:test (exit 0 = all green)
*/
import { strict as assert } from "node:assert";
import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { test } from "./harness.mjs";
const here = path.dirname(fileURLToPath(import.meta.url)); // routing/test
// Lazy module loads — missing modules => per-case ERR_MODULE_NOT_FOUND (RED).
let polylinePromise = null;
function loadPolyline() {
if (!polylinePromise) polylinePromise = import("../src/polyline.ts");
return polylinePromise;
}
let sourcePromise = null;
function loadSource() {
if (!sourcePromise) sourcePromise = import("../src/fixture-source.ts");
return sourcePromise;
}
/* ————— synthetic dataset builder (public KL coordinates, 1e-6 grid) ————— */
const KL_TOWER = { lat: 3.1528, lng: 101.7038, label: "Kuala Lumpur Tower" };
const KL_SENTRAL = { lat: 3.1343, lng: 101.6869 };
const PATH_A = [
{ lat: 3.1528, lng: 101.7038 },
{ lat: 3.15, lng: 101.7 },
{ lat: 3.14, lng: 101.69 },
{ lat: 3.1343, lng: 101.6869 },
];
const PATH_B = [
{ lat: 3.1528, lng: 101.7038 },
{ lat: 3.148, lng: 101.699 },
{ lat: 3.1343, lng: 101.6869 },
];
async function buildSyntheticDataset() {
const { encodePolyline6 } = await loadPolyline();
return {
version: 1,
originToleranceM: 200,
pairs: [
{
pairId: "kl-tower-to-kl-sentral",
origin: KL_TOWER,
destinationId: "kl-sentral",
routes: [
{ geometry: encodePolyline6(PATH_A), distanceM: 4800, durationS: 600 },
{ geometry: encodePolyline6(PATH_B), distanceM: 5200, durationS: 640 },
],
},
],
};
}
/* ————— F1–F8 ————— */
test("F1 empty corpus -> null — every route() resolves null (the seed's state until 05-02)", async () => {
const { createFixtureRoutingSource } = await loadSource();
const source = createFixtureRoutingSource({ version: 1, originToleranceM: 200, pairs: [] });
assert.equal(source.name, "fixture", "the backend tag is 'fixture'");
const result = await source.route({
origin: { lat: 3.1528, lng: 101.7038 },
destinationId: "kl-sentral",
});
assert.equal(result, null, "an empty corpus is honest-null, never a fabricated route");
});
test("F2 match serves best-first — backend tag, order, decoded geometry, cumulative field, EMPTY steps", async () => {
const { createFixtureRoutingSource } = await loadSource();
const data = await buildSyntheticDataset();
const source = createFixtureRoutingSource(data);
const origin = { lat: 3.1528, lng: 101.7038 };
const result = await source.route({ origin, destinationId: "kl-sentral" });
assert.ok(result, "the pinned origin + matching destinationId must serve");
assert.equal(result.backend, "fixture");
assert.equal(result.destinationId, "kl-sentral");
assert.deepEqual(result.origin, origin);
assert.equal(result.options.length, 2, "both synthetic routes serve, order preserved");
assert.deepEqual(
result.options[0].geometry.points,
PATH_A,
"options[0] is fixture route 1 (best-first order preserved)",
);
assert.equal(result.options[0].summary.distanceM, 4800);
assert.equal(result.options[0].summary.durationS, 600);
assert.equal(result.options[1].summary.distanceM, 5200);
const cum = result.options[0].geometry.cumulativeDistanceM;
assert.equal(cum.length, PATH_A.length, "cumulative is the same length as points");
assert.equal(cum[0], 0, "cumulative starts at 0");
for (let i = 1; i < cum.length; i++) {
assert.ok(cum[i] >= cum[i - 1], "cumulative is non-decreasing");
assert.ok(Number.isFinite(cum[i]), "cumulative entries are finite meters");
}
for (const option of result.options) {
assert.deepEqual(option.steps, [], "fixture-world steps are ALWAYS empty (T-05-07, D-10)");
}
});
test("F3 tolerance boundary — ~111 m from the pinned origin serves; ~222 m is honest null", async () => {
const { createFixtureRoutingSource } = await loadSource();
const data = await buildSyntheticDataset();
const source = createFixtureRoutingSource(data);
// 0.001 deg lat ~= 111 m (haversine) — inside the 200 m tolerance.
const near = await source.route({
origin: { lat: 3.1538, lng: 101.7038 },
destinationId: "kl-sentral",
});
assert.ok(near, "GPS jitter within ~111 m of the pinned origin must still serve");
// 0.002 deg lat ~= 222 m — outside the 200 m tolerance.
const far = await source.route({
origin: { lat: 3.1548, lng: 101.7038 },
destinationId: "kl-sentral",
});
assert.equal(far, null, "beyond the tolerance the backend must NOT fabricate a route (D-03)");
});
test("F4 slug guard — non-slug and over-long destinationIds are refused before the index is touched", async () => {
const { createFixtureRoutingSource } = await loadSource();
const data = await buildSyntheticDataset();
const source = createFixtureRoutingSource(data);
const origin = { lat: 3.1528, lng: 101.7038 };
assert.equal(
await source.route({ origin, destinationId: "not a slug!" }),
null,
"spaces/punctuation are refused by the slug guard (T-05-03)",
);
assert.equal(
await source.route({ origin, destinationId: "a".repeat(65) }),
null,
"a 65-char id exceeds the 1..64 slug charset — refused (hostile-shape DoS bound)",
);
});
test("F5 unknown destination -> null — a valid slug with no pair is the honest pending state (D-03)", async () => {
const { createFixtureRoutingSource } = await loadSource();
const data = await buildSyntheticDataset();
const source = createFixtureRoutingSource(data);
const result = await source.route({
origin: { lat: 3.1528, lng: 101.7038 },
destinationId: "petronas-twin-towers",
});
assert.equal(result, null, "never a nearest-match geometry for an unknown destination");
});
test("F6 malformed pair skipped — NaN distance / empty routes / throwing geometry never throw to the caller", async () => {
const { createFixtureRoutingSource } = await loadSource();
const { encodePolyline6 } = await loadPolyline();
const broken = {
version: 1,
originToleranceM: 200,
pairs: [
{
pairId: "broken-nan",
origin: { lat: 3.1528, lng: 101.7038, label: "broken distance" },
destinationId: "kl-sentral",
routes: [
{
geometry: encodePolyline6([{ lat: 3.1528, lng: 101.7038 }]),
distanceM: Number.NaN,
durationS: 100,
},
],
},
{
pairId: "broken-empty-routes",
origin: { lat: 3.1528, lng: 101.7038, label: "empty routes" },
destinationId: "kl-sentral",
routes: [],
},
{
pairId: "broken-throwing-geometry",
origin: { lat: 3.1528, lng: 101.7038, label: "truncated polyline" },
destinationId: "kl-sentral",
routes: [{ geometry: "A", distanceM: 100, durationS: 10 }],
},
{
pairId: "kl-tower-to-kl-sentral",
origin: KL_TOWER,
destinationId: "kl-sentral",
routes: [
{
geometry: encodePolyline6(PATH_A),
distanceM: 4800,
durationS: 600,
},
],
},
],
};
const source = createFixtureRoutingSource(broken);
const served = await source.route({
origin: { lat: 3.1528, lng: 101.7038 },
destinationId: "kl-sentral",
});
assert.ok(served, "the well-formed sibling pair still serves");
assert.equal(served.options.length, 1, "only the well-formed pair is admitted");
assert.equal(served.options[0].summary.distanceM, 4800);
});
test("F7 lazy index — no `new Map(` and no `decodePolyline6(` call at TOP LEVEL (gazetteer LAW 1)", () => {
const srcPath = path.join(here, "..", "src", "fixture-source.ts");
const src = readFileSync(srcPath, "utf8");
// Strip comments first (the no-storage gate pattern) — prose is not a call site.
const code = src
.replace(/\/\*[\s\S]*?\*\//g, " ")
.replace(/(^|[^:\\])\/\/[^\n]*/g, "$1");
for (const line of code.split("\n")) {
if (line.trim() === "") continue;
if (/^\s/.test(line)) continue; // indented => inside a function — allowed
assert.ok(
!line.includes("new Map("),
`top-level index construction — LAW 1 violated: ${line.trim().slice(0, 60)}`,
);
assert.ok(
!line.includes("decodePolyline6("),
`top-level geometry decode — LAW 1 violated: ${line.trim().slice(0, 60)}`,
);
}
});
test("F8 getPairOrigin — slug-guarded lookup; positive half deferred while the seed is empty", async () => {
const mod = await loadSource();
assert.equal(mod.getPairOrigin("not a slug!"), null, "garbage pairId -> null (slug guard)");
assert.equal(mod.getPairOrigin("a".repeat(65)), null, "over-long pairId -> null");
assert.equal(mod.getPairOrigin("unknown-pair"), null, "unknown pair -> honest null");
const pairs = mod.getPairs();
assert.ok(Array.isArray(pairs), "getPairs returns an array");
if (pairs.length === 0) {
console.log(
"SKIP F8 (positive half) — the committed seed is empty until plan 05-02 populates it; the lookup machinery is proven by F2's injected dataset",
);
return;
}
const first = pairs[0];
const origin = mod.getPairOrigin(first.pairId);
assert.deepEqual(
origin,
{ lat: first.origin.lat, lng: first.origin.lng },
"getPairOrigin resolves the pinned origin for a known pairId",
);
});