fix(08-05): D-03 optimality gate green — fromTable families removed from the ALT potential

Task 1: the D-03 gate script (measure-optimality-gate.mjs) reads the frozen
pre-ALT record, re-routes the same coordinate-pinned pairs on the current
ARG2 binary, and gates on seconds-equality (±0.1%) + verdict-class
preservation — never on node paths (equal-cost ties are documented behavior).

Rule-1 deviation the gate forced on its first run: routeAstar returned
SUBOPTIMAL real-graph routes (x038: 1234.6s vs the 1214.8s Dijkstra optimum;
x045: 1475.5s vs 1460.6s) — the fixture sweep could not see it. Root cause:
the fromTable bound d̂(ℓ,t) − d̂(ℓ,v) is one-directional Lipschitz (its u-side
term needs the REVERSE edge; a oneway does not provide one — the anchor
reached node 264611 126.8s faster than its own 1.49s upstream neighbour
264610), and the shared Ikeda average p = (h_f − h_b)/2 is consistent only
when every family inside h_f/h_b is two-sided. The toTable bound
d̂(v,ℓ) − d̂(t,ℓ) rides stored traversable edges in BOTH directions; it alone
joins the haversine now. Stop rule, reductions, meet probes, reconstruction:
untouched. landmarkTables/build verified EXACT (0 mismatches vs independent
integer Dijkstras, both rows, all 24 anchors).

- measure-optimality-gate.mjs: exported core + CLI guard (route-corpus
  pattern); epsilon mirror + argVersion asserts precede any measurement;
  per-pair rows, extract-drift WARNING (never a re-record), honest exit law
- astar.ts: potential() consults landmarkTo only; doc-comments carry the
  one-directional-Lipschitz law and the x038/x045 evidence
- astar.test.mjs: A11 re-pinned (landmarkFrom must NOT appear in the
  comment-stripped search — re-adding it trips the pin); A12 oneway-ring
  sweep added (directed reach asymmetry stays Dijkstra-equal on every pair)

Battery: routing 80/80, bot 126/126, both typechecks green.
D-03 gate: GATE PASS — 53/53 routed pairs equal within ±0.1% (max |Δ| 0.005%),
verdict classes preserved (6 unreachable + 41 unsnappable, 0 re-snapped).
This commit is contained in:
araharah-executor
2026-10-25 19:54:24 +08:00
parent ab0b465218
commit 149636ce0a
3 changed files with 441 additions and 46 deletions
+302
View File
@@ -0,0 +1,302 @@
#!/usr/bin/env node
/*
* measure-optimality-gate.mjs — the D-03 optimality gate (Phase 8 plan 08-05).
* ------------------------------------------------------------------------------
* A MAINTAINER-TIME REPO TOOL — NOT a runtime dependency; nothing in bot/src,
* web/src, or routing/src imports it (the route-corpus/measure-route-cpu law).
*
* Purpose: prove the ALT preprocessing (ARG2 + landmark steering) did not move
* route OPTIMALITY, by re-routing the SAME coordinate-pinned pairs the frozen
* pre-ALT record (Plan 08-01's routing/test/fixtures/alt-baseline.json)
* measured, and gating on:
* D03A — seconds equality: |post − pre| within ± OPTIMALITY_EPSILON_PCT % of
* pre (equal seconds pass; equal-cost TIES are fine — D-03);
* D03B — verdict-class preservation: reachable/unreachable stays the same
* per pair (unsnappable pairs that now snap are an INFO count, not a
* violation — D-03's letter gates the reachable/unreachable classes).
*
* WHAT THE GATE NEVER DOES: compare NODE PATHS. A different equal-cost path
* (a tie) is documented behavior under bidirectional search + ALT potentials —
* structurally invisible to this gate (no path read exists here; only seconds
* and verdict classes are compared).
*
* Inputs:
* - the COMMITTED record routing/test/fixtures/alt-baseline.json (IMMUTABLE
* — the recorder refuses overwrite; delete by explicit git revert only);
* - the LOCAL rebuilt binary routing/data/kl-roadgraph.v1.bin (ARG2 — the
* storage NAME stays v1; the header version is the format truth).
*
* Constant-mirror law: this script's OPTIMALITY_EPSILON_PCT is asserted EQUAL
* to the record's epsilon block BEFORE any measurement — a record edit alone
* cannot fake a pass. Extract drift (node/edge count deltas vs the record) is
* a printed WARNING, never a violation, and NEVER a reason to re-record
* (Pitfall 1: the record is the anchor; mass failures escalate to the user).
*
* Echo law: pair ids + measurements ONLY (the route-corpus posture) — pair
* coordinates in the record are public bbox-derived values, never user data.
*
* Usage:
* node routing/scripts/measure-optimality-gate.mjs
*
* Exit codes: 0 GATE PASS (zero violations across both checks); 1 any
* violation, a mirror-assert failure, or an absent/undecodable input.
*/
import { existsSync, readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { decodeGraph } from "../src/graph.ts";
import { snapToGraph as snap } from "../src/snap.ts";
import { routeAstar as astar } from "../src/astar.ts";
const here = dirname(fileURLToPath(import.meta.url)); // routing/scripts
/** The frozen pre-ALT record — the D-03 anchor (committed, immutable). */
const RECORD_PATH = resolve(here, "..", "test", "fixtures", "alt-baseline.json");
/** The current binary under test (same path law as measure-route-cpu.mjs). */
const GRAPH_PATH = resolve(here, "..", "data", "kl-roadgraph.v1.bin");
/**
* D-03's named epsilon (±0.1% of the pre-ALT seconds) — the MIRROR of the
* record's epsilon block. The main() assert below refuses to measure when
* the two disagree: the record cannot be edited to fake an epsilon, and this
* constant cannot drift from the record silently.
*/
const OPTIMALITY_EPSILON_PCT = 0.1;
/** The record must be the PRE-ALT baseline (Pitfall 1's guard, mirrored). */
const REQUIRED_BASELINE_ARG_VERSION = 1;
function fail(message) {
console.error(`measure-optimality-gate: ${message}`);
process.exit(1);
}
function toArrayBuffer(buf) {
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
}
/**
* The measurement core — exported so a suite can mirror the SAME numbers this
* CLI prints (one measurement, two reporters — the route-corpus split).
*
* For each record pair: snap both endpoints on the CURRENT graph, route with
* the CURRENT search, and classify:
* "pass" — seconds within epsilon (both routed) or the same null
* verdict class preserved (unreachable/unsnappable);
* "violation" — a D03A seconds break or a D03B reachable/unreachable class
* break;
* "re-snapped" — record-unsnappable that now snaps (INFO; counted, printed
* as a WARNING in the summary when > 0, never a violation);
* "unsnapped" — a record-routed pair whose snap now misses (a D03B class
* break — the pair no longer routes at all).
*
* @param graph decoded RoadGraph (the current ARG2 build)
* @param record parsed alt-baseline.json (the frozen pre-ALT record)
* @param opts { snap, astar } — the live modules (injected like the corpus core)
* @returns {{ checks: { D03A: check, D03B: check }, rows: Array, reSnapped: number, pass: boolean }}
*/
export function measureOptimality(graph, record, { snap, astar }) {
const checks = {
D03A: { id: "D03A", label: "seconds equality (±0.1%)", violations: [] },
D03B: { id: "D03B", label: "verdict class preserved", violations: [] },
};
const rows = [];
let reSnapped = 0;
for (const pair of record.pairs) {
const pre = pair.seconds; // number | null
const verdictPre = pair.verdict; // "reachable" | "unreachable" | "unsnappable"
const origin = snap(graph, pair.origin);
const goal = snap(graph, pair.destination);
let post = null;
let verdictPost = "unsnappable";
if (origin !== null && goal !== null) {
const result = astar(graph, origin.node, goal.node);
if (result === null) verdictPost = "unreachable";
else {
verdictPost = "reachable";
post = result.seconds;
}
}
let cls = "pass";
let deltaPct = null;
if (verdictPre === "unsnappable") {
if (verdictPost === "unsnappable") {
cls = "pass"; // unsnappable preserved — the honest null, stable
} else {
// The pair now snaps (+ routes or honestly reports unreachable):
// an INFO re-snap, counted and summary-WARNED, NOT a violation.
cls = "re-snapped";
reSnapped += 1;
}
} else if (verdictPost === "unsnappable") {
cls = "unsnapped";
checks.D03B.violations.push({
pairId: pair.pairId,
reason: `verdict class break: ${verdictPre} (pre-ALT record) -> unsnappable (post-ALT snap miss)`,
});
} else if (verdictPre !== verdictPost) {
cls = "violation";
checks.D03B.violations.push({
pairId: pair.pairId,
reason: `verdict class break: ${verdictPre} -> ${verdictPost}`,
});
} else if (verdictPost === "reachable") {
// Both sides routed — D03A seconds equality (paths are NEVER compared;
// equal-cost tie differences cannot produce a violation by construction).
deltaPct = ((post - pre) / pre) * 100;
if (Math.abs(deltaPct) > OPTIMALITY_EPSILON_PCT) {
cls = "violation";
checks.D03A.violations.push({
pairId: pair.pairId,
reason: `seconds drift ${pre.toFixed(1)}s -> ${post.toFixed(1)}s (Δ ${deltaPct.toFixed(3)}% beyond ±${OPTIMALITY_EPSILON_PCT}%)`,
});
}
}
// else: unreachable -> unreachable — class preserved, pass.
rows.push({ pairId: pair.pairId, pre, post, deltaPct, verdictPre, verdictPost, class: cls });
}
const pass =
checks.D03A.violations.length === 0 && checks.D03B.violations.length === 0;
return { checks, rows, reSnapped, pass };
}
/* ————— CLI reporter ————— */
function formatSeconds(v) {
return v === null ? "unsnappable" : `${v.toFixed(1)}s`;
}
function report(record, results, drift) {
const routed = results.rows.filter((r) => r.class === "pass" && r.pre !== null && r.post !== null);
const unreachPreserved = results.rows.filter(
(r) => r.verdictPre === "unreachable" && r.verdictPost === "unreachable",
).length;
const unsnapPreserved = results.rows.filter(
(r) => r.verdictPre === "unsnappable" && r.verdictPost === "unsnappable",
).length;
const maxAbsDelta = routed.reduce((m, r) => Math.max(m, Math.abs(r.deltaPct ?? 0)), 0);
console.log(`D-03 optimality gate — ${results.rows.length} record pairs vs the current binary`);
for (const row of results.rows) {
const delta = row.deltaPct === null ? "Δ —" : `Δ ${row.deltaPct >= 0 ? "+" : ""}${row.deltaPct.toFixed(3)}%`;
const tag =
row.class === "re-snapped"
? "re-snapped INFO"
: row.class === "unsnapped" || row.class === "violation"
? "FAIL"
: "pass";
const note = row.class === "re-snapped" ? " (re-snapped — no pre-ALT seconds to compare)" : "";
console.log(` ${row.pairId}: pre ${formatSeconds(row.pre)} post ${formatSeconds(row.post)} (${delta})${note} ${tag}`);
}
console.log(
`summary: ${results.rows.length} record pairs — ${routed.length} routed equal, ` +
`${unreachPreserved} unreachable preserved, ${unsnapPreserved} unsnappable preserved, ` +
`${results.reSnapped} re-snapped`,
);
for (const check of Object.values(results.checks)) {
console.log(` ${check.id} (${check.label}): ${check.violations.length} violation(s)`);
for (const v of check.violations) {
console.log(` ${v.pairId}: ${v.reason}`);
}
}
console.log(` max |Δ%| over routed pairs: ${maxAbsDelta.toFixed(3)}%`);
console.log(
` epsilon: ±${OPTIMALITY_EPSILON_PCT}% (OPTIMALITY_EPSILON_PCT — mirrored to the record's epsilon block: ${record.epsilon.pct}%)`,
);
if (drift !== null) {
console.log(
` extract drift vs the frozen record: nodes ${drift.nodes >= 0 ? "+" : ""}${drift.nodes}, edges ${drift.edges >= 0 ? "+" : ""}${drift.edges} — the seconds gate still applies`,
);
}
if (results.reSnapped > 0) {
console.log(
`WARNING: ${results.reSnapped} record-unsnappable pair(s) now snap on the current graph (re-snapped INFO rows above) — counted, not a D-03 violation`,
);
}
if (!results.pass) {
const a = results.checks.D03A.violations.length;
const b = results.checks.D03B.violations.length;
console.error(
`GATE FAIL: D-03 optimality — ${a} D03A + ${b} D03B violations across ${results.rows.length} record pairs. ` +
`The record is IMMUTABLE (Pitfall 1): suspect extract drift first (the WARNING counts above), then escalate to the user — never edit or re-record the baseline.`,
);
return false;
}
console.log(
`GATE PASS: D-03 optimality — ${routed.length}/${routed.length} routed pairs equal within ±${OPTIMALITY_EPSILON_PCT}%, verdict classes preserved ` +
`(${results.rows.length}/${results.rows.length} record pairs; ${unreachPreserved} unreachable + ${unsnapPreserved} unsnappable preserved, ${results.reSnapped} re-snapped)`,
);
return true;
}
function main() {
// Honest-refusal structure: EVERY guard below precedes any measurement call.
if (!existsSync(RECORD_PATH)) {
fail(`no baseline record at ${RECORD_PATH} — run measure-optimality-baseline first — the record is the D-03 anchor`);
}
if (!existsSync(GRAPH_PATH)) {
fail(`no graph at ${GRAPH_PATH} — build it first: node routing/scripts/build-road-graph.mjs`);
}
const record = JSON.parse(readFileSync(RECORD_PATH, "utf8"));
if (!record || typeof record !== "object" || !Array.isArray(record.pairs) || record.pairs.length === 0) {
fail(`${RECORD_PATH} has no pairs array — the record schema is the gate's input contract`);
}
if (!record.graph || typeof record.graph.argVersion !== "number") {
fail(`${RECORD_PATH} has no graph block — the record schema is the gate's input contract`);
}
// CONSTANT-MIRROR ASSERT (must precede any measurement): the gate's epsilon
// equals the record's epsilon block, by name and by value — a record edit
// alone cannot fake a pass.
if (record.epsilon?.name !== "OPTIMALITY_EPSILON_PCT" || record.epsilon?.pct !== OPTIMALITY_EPSILON_PCT) {
fail(
`epsilon mirror mismatch: the gate's OPTIMALITY_EPSILON_PCT is ${OPTIMALITY_EPSILON_PCT} but the record's epsilon block says ` +
`${JSON.stringify(record.epsilon ?? null)} — align the constant with the record's provenance (or git-revert the record edit); the record itself is immutable`,
);
}
if (record.graph.argVersion !== REQUIRED_BASELINE_ARG_VERSION) {
fail(
`the baseline must be the pre-ALT record (argVersion ${REQUIRED_BASELINE_ARG_VERSION}) — this record says argVersion ${record.graph.argVersion}`,
);
}
const graph = decodeGraph(toArrayBuffer(readFileSync(GRAPH_PATH)));
if (graph === null) {
fail(
`${GRAPH_PATH} does not decode (fail-honest null — still ARG1 or corrupt) — rebuild the ARG2 binary: node routing/scripts/build-road-graph.mjs`,
);
}
console.log(
`record: ${record.pairs.length} pairs recorded ${record.recordedAt} ` +
`(ARG${record.graph.argVersion}: ${record.graph.nodeCount} nodes / ${record.graph.edgeCount} edges, epsilon ±${record.epsilon.pct}%)`,
);
console.log(`current: ${graph.nodeCount} nodes / ${graph.edgeCount} edges (decoded from ${GRAPH_PATH})`);
let drift = null;
const nodeDrift = graph.nodeCount - record.graph.nodeCount;
const edgeDrift = graph.edgeCount - record.graph.edgeCount;
if (nodeDrift !== 0 || edgeDrift !== 0) {
drift = { nodes: nodeDrift, edges: edgeDrift };
console.log(
`WARNING: extract drift vs the frozen record — the seconds gate still applies (NEVER a reason to re-record; Pitfall 1)`,
);
}
const results = measureOptimality(graph, record, { snap, astar });
const pass = report(record, results, drift);
process.exit(pass ? 0 : 1);
}
// Run only when invoked directly — importing this module (an in-process
// mirror of the same numbers) must never execute the CLI (route-corpus law).
const invoked = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : "";
if (invoked === import.meta.url) {
main();
}