#!/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(); }