- 08.1-01 task 2: re-pin graph.test.mjs in-memory G-cases (G1/G3/G8/G9/G10/G11)
and astar.test.mjs in-memory/ALT cases; suspend only committed-fixture G7 and
A1/A2/A4/A5/A6 (the runner auto-discovers all suites and parses no argv, so
task 2's verify could never exit 0 otherwise)
- 08.1-01 task 3: own un-suspension of G7 and A1/A2/A4/A5/A6 after the ARG3
fixture regeneration
- 08.1-01 task 1: drop the cosmetic --test-name-pattern flag (ignored by the
hand-rolled runner; full suite runs instead)
- 08.1-02 task 2: use grep -cF for the rollout decodeGraph call-site gate
(BRE form exited 2 with 'Unmatched ( or \\(')
- 08.1-02 task 1: replace the no-op '|| test $? -eq 1' landmark gate with a
'test "$(...)" -eq 0' count assertion that can actually fail
- new named constant LANDMARK_I32_WEIGHT_CEILING (0x7fffffff) in
landmark.ts: a seconds/quantumS quotient at or past 2^31 would wrap
NEGATIVE on the Int32Array store, silently bypassing the
LANDMARK_MAX_QUANTA throw in dijkstraPass (a negative contribution
never exceeds it) and — at a -1 wrap — becoming the 0xFFFF sentinel;
prepare() now fails loud at the table-build entry, naming the edge,
the ceiling and the fix (raise landmarkQuantumS)
- 'nothing is clamped, ever' now holds at the storage boundary;
validation is per-edge at build entry — the search hot path stays
allocation-free and validation-free
- L5b regression vector: 3e10 s edge (3e11 quanta) throws in both
landmarkTables and farthestPointAnchors; just-under-ceiling
(2147483646) still fails via the documented 65000 law; ordinary
weights untouched
- the graph binary is NOT committed: routing/data/.gitignore ignores
*.bin (git check-ignore verified) — forks rebuild their own
(docs/ROAD-GRAPH.md), so the old assertion message was factually false
- CPU3 now mirrors CPU4's law: absent binary -> honest SKIP (not a
failure); the run-the-ladder assertions fire only when it is present
- reason text aligned with reality: 'gitignored fork-rebuildable artifact'
- sweepOracle: Math.abs(deltaS) > ORACLE_EPSILON_S replaces the one-sided
'seconds > optimal + eps' check — a result FASTER than the Dijkstra
oracle (the traversal-law-break signature, e.g. a oneway relaxed) is
now a violation, stamped ORACLE-MISMATCH, never a pass
- worstDeltaPct tracks MAGNITUDE not sign — a -40% law break moves it
- pass gate: suboptimal === 0 && oracleMismatch === 0 && classBreaks === 0
- header gate description + exit codes updated: the check is |Δ| in both
directions; GATE FAIL names both violation classes; GATE PASS reads
0/N |Δ| violations
- row-level signed Δ printout unchanged (sign/direction reporting kept)
measure-astar-oracle-sweep.mjs (maintainer-time, route-corpus law: exported
core sweepOracle + CLI guard, print-the-measurement, honest exit codes):
- FRESH seeded cross-metro pairs via measure-optimality-baseline.mjs's
exported generateCrossMetroPairs core — seed 0x08f1, deliberately NOT
the D-03 corpus seed 0x08a1, so this sweep never measures the corpus
- compared-pair law: one 3x-oversampled draw, consumed in order until 200
COMPARED pairs (reachable + null-vs-null unreachable both compare;
snap misses counted and printed; same binary + seed => same set) —
random bbox coordinates are ~20% off-road and an unsnappable pair
cannot exercise the search
- brute-force unidirectional Dijkstra oracle (label-setting, heap, the
shared oneway traversal law) on the SAME snapped node pair
- gate: 0 suboptimal (epsilon 1e-6 s — f64 summation-order noise floor,
A1's epsilon); class-breaks (one side routes, other doesn't) violate
- honest skip when the gitignored binary is absent (exit 0, SKIP printed)
First run on the fixed engine: 200 compared (182 routed, 18 unreachable),
0 SUBOPTIMAL, worst delta +0.000% — GATE PASS. The pre-F1 engine measured
1/194 suboptimal on this pair shape (bench7, debug session).
Debug session alt-potential-4x-slowdown, root cause RC-1 (LIVE correctness
bug): bound()'s per-node sentinel skip (tv === 0xffff -> drop landmark l)
varied the active landmark family set PER NODE, so the toTable max lost
cross-edge consistency across edges leaving the 6,285-node disconnected
island (2.02% of cells) — shipped routeAstar returned suboptimal seconds
on 1/194 fresh random real-graph pairs vs the Dijkstra oracle (worst
single-edge family variance 1,026 s). D-03's fixed corpus was green on
sampling luck.
The fix (reverseFor precedent, in-constraint):
- per-graph WeakMap memo cleanColumnsFor: clean[l] = 'to-column l has ZERO
sentinel cells' — O(L*n) sequential row scans once per graph/isolate
- per-search active list activeL = clean columns only; bound() loops the
active list with NO per-node sentinel branch; the constant-table
goal/origin NaN checks are retained (belt)
- on the current binary (0/24 clean columns) potentials degrade to EXACTLY
haversine — the designed sound fallback; the pre-ALT CPU band returns
- ALT stays live and tested on strongly connected fixtures (mini-graph
0/2 dirty columns, A12 ring all-clean, new A13 mixed subset case)
- LANDMARK_SENTINEL_U16 named constant; sentinel compares at setup scope
only; pure-module law untouched
BH stop rule, reductions, balanced alternation, meet probes, real-seconds
reconstruction: UNTOUCHED. F2 (transposed table) explicitly out of scope.
Battery: routing 81/81 (A11 RED pins now green, A13 new), bot 126/126,
routing+bot typecheck clean.
- A9: island fixture re-pinned as ALL-DIRTY (every to-column holds a
B-node sentinel -> every landmark drops search-scoped -> the whole
fixture runs the haversine fallback); the old 'real ALT bounds live in
A' claim is gone — it described the per-node sentinel skip RC-1 removed
- A10: mechanism comment updated to the containment law (active list
empty at search scope, never a per-node l-mask)
- A11: structural pin rewritten to the F1 bound() shape — cleanColumnsFor
memo + activeL list must exist in code; inline '=== 0xffff' sentinel
compares BANNED (RC-1's exact shape); named-constant law pinned —
FAILS ON SHIPPED CODE (the RED gate)
- A12: re-sealed as the ALT-ACTIVE counterpart — all to-columns clean
(strongly connected ring + spur), pinned by table scan
- A13 (new): mixed clean/dirty columns via a one-way-bottleneck twin-ring
fixture — the subset-active-list branch neither A9 nor A12 exercises;
64-pair Dijkstra equivalence + honest nulls
Fails today by design: A11 (4 pins) against the shipped per-node skip.
Task 4, re-scoped per the plan's honest-FAIL branch: the c3 class is NOT
retired — every record now states the measured post-ALT truth.
- KNOWN-LIMITATIONS: the cross-metro section is the /cari-shaped record —
WHAT CHANGED (ALT built, D-03 optimality green quoted) / what REMAINS
(the CPU verdict FAIL lines quoted with date; the one-directional-
Lipschitz wall named; the escalation open); the roadmap-pointer ALT row
flips to Built (Phase 8) with the measured verdict — never 'not built'
again
- ROAD-GRAPH: the ladder table gains the (c2) rung (EXECUTED, measured
FAIL, the L=32 probe quoted); the decision paragraph states c2
executed-verdict-fail and names the real remaining options; new 'The
ARG2 binary layout' section (72-byte header, landmarkCount/
landmarkQuantumS, u16 suffix + sentinels, the quantum knob's ≈6,553 s
ceiling, the storage-name-vs-format-truth law); key facts carry the
optimality gate and the ARG2 wording; the fork contract's build step
teaches the landmark stage (no new commands)
- docs/CONFIGURATION.md: verify-only — all path/script claims still true,
no edit needed
- staged as selective hunks; the tree's pre-existing doc-sync edits
(battery paragraph, 'six maintainer scripts' intro) remain uncommitted
greps: 'Next-milestone item, not built' = 0; the measured p95 strings
quoted; (c2)/landmarkQuantumS/ARG2 all present; ARG1 appears only in
layout/router-pending contexts.
Task 3, re-scoped per the plan's honest-FAIL branch: the CPU verdict FAILED
(the ladder ran to its documented stop), so the c3 class is NOT retired —
the record instead carries the executed-and-measured ALT truth.
- budget-gates.mjs: the verdict law documents the Phase-8 outcome (ALT
EXECUTED, optimality green, CPU verdict FAIL 152.788/185.692 ms quoted
with date; L=32 probe measured worse) — the stale 'next-milestone item'
wording is gone; ROUTE_CPU_DRIFT_GUARD_MS re-anchored 200 → 400 (the
post-ALT documented band outgrew the old guard; ≈2x the worst shipped-
config run 185.692 ms); the guard stays a regression trip-wire, the 8 ms
budget stays and its FAIL still prints every run
- budget-audit.test.mjs: CPU3 pins the new law (evidence must name the
EXECUTED-in-Phase-8 verdict and must NEVER say 'next-milestone');
19/19 vectors ok (the count holds — no vector dropped)
- docs/BUDGETS.md: route-cpu row carries the Phase-8 measured numbers +
date; the c3 section is the honest post-ALT record (what changed, the
quoted gate lines, the one-directional-Lipschitz wall, the open
escalation) — staged as selective hunks; the tree's pre-existing
doc-sync edits in other sections remain uncommitted, untouched
grep law: zero 'next-milestone' hits in budget-gates.mjs + BUDGETS.md;
ROUTE_CPU_DRIFT_GUARD_MS still exported and used.
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).
- The stage between edge compaction and encode feeds the graph's edges to
landmark.ts (farthestPointAnchors + landmarkTables + landmarkCoverage) —
the script quantizes and implements nothing itself (single-authority law)
- D-02 scaling rule L = clamp(round(N/13000), 16, 32) (~24 at KL's 311k
nodes) with a --landmarks <n> measured knob (positive int, hard cap 128,
parsed before --check)
- Honest gates before any write: quantum-ceiling throw -> fail with the
raise-quantum hint (Pitfall 5); per-anchor coverage >= 0.9 (the SAME
fraction for any L — the override cannot lower it, T-08-11); anchor
shortfall fails loud instead of encoding a weaker ALT
- encodeGraph receives landmarks: { quantumS, nodes, to, from } — the one
ARG2 authority; no local fallback encode
- Stats gate prints L/quantum/coverage min-mean/table bytes/sentinel totals
BEFORE the size gates; --check mirrors the facts from the decoded binary
(landmarkCount/quantum/anchors/coverage/sentinels, no network)
- A1 ladder history gains rung (c2): EXECUTED in this preprocessing stage
- RO1 upload-format-agnostic: upload-road-graph.mjs keeps KEY
'kl-roadgraph.v1.bin' + BUCKET 'araharah-graphs'; comment-stripped code
contains ZERO format tokens (landmark/encodeGraph/decodeGraph/ARG1/ARG2
magics/GRAPH_VERSION) — the migration is byte-shipping of the same key,
forever (A8 grep-shape)
- RO2 one decode path: worker-router.ts keeps GRAPH_KEY unchanged, exactly
ONE decodeGraph call in the loadGraph flow, no version-conditional branch
(GRAPH_VERSION / magics / '=== 2' absent) — an undecodable binary flows
to the existing null -> router-pending path (D-01 at the consumer)
- full battery at this commit — the FIRST where routeAstar consults real
landmark tables on the bot suite's ARG2 corridor graphs: routing 79/79
(A1 seal + A9/A10/A11 + RO1/RO2), bot 126/126 (RT trunks + cron),
routing+bot typechecks clean; worker-router.ts and upload-road-graph.mjs
untouched (git diff --stat empty)
- routeAstar's ONLY change: the h_f/h_b bodies become max(ALT triangle
bounds, haversine) — per-search Float64Array(L) constant tables in quanta
(0xFFFF written as NaN = search-scoped landmark drop), lazy per-node
max over the four triangle families with RAW u16 sentinel compares
BEFORE any float conversion, haversine max-fallback on sentinel-flooded
nodes (Pattern 3 containment)
- the (h_f - h_b)/2 combination, reductions, balanced alternation, meet
probes, BH stop rule, and real-seconds reconstruction are byte-identical
(research Pattern 1 — the survey's (pf-pr)/2 is what p_f already is)
- no Map/Object allocations (A8 green), no new imports, one search path
(L >= 1 is the decodeGraph guarantee, D-01)
- A1's 625-pair Dijkstra-equivalence sweep re-pinned under ALT: the
standing optimality proof; A9 island + A10 skip laws sealed; A11
structural pin green
- module header + routeAstar doc gain the ALT paragraph (c-metric
exactness, sentinel laws, Ikeda history intact)
- A9: two-component synthetic (3x3 grid + 4-node path), anchors HAND-PINNED
inside component A only via landmarkTables; full 169-pair sweep asserts
seconds-only Dijkstra equivalence (A-internal with ALT live, B-internal
on the haversine fallback, 72 cross pairs -> null)
- A10: origin AND goal inside the anchorless component — all families drop
at SEARCH scope, the 16 B-internal pairs still route Dijkstra-equal
- A11: comment-stripped astar.ts must reference landmarkTo/landmarkFrom/
landmarkQuantumS in CODE; one sentinel spelling (0xffff, never 65535);
A8's no-Map law unchanged — FAILS now (RED: the potential is still
pure haversine)
- case-index doc-comment extended A1-A8 -> A1-A11; buildIslandFixture
helper routes fixture tables through the ONE landmark module
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.
graph.ts versioned IN PLACE (no second codec): GRAPH_MAGIC 0x41524732,
GRAPH_VERSION 2, HEADER_SIZE 72 (72%8==0 keeps f64 views aligned);
header gains landmarkCount u32 @60 (the old pad), landmarkQuantumS f32
@64, reserved u32 @68; the landmark suffix (u16 toTable, u16 fromTable,
u32 landmarkNodes) extends layoutFor's total arithmetic — exact-size
law covers the variable suffix BEFORE any view allocation (T-08-01).
D-01 fail-honest: ARG1 bytes / version!=2 / landmarkCount=0 / hostile
quantum / size mismatch all decode null (committed mini-graph-arg1.bin
is the standing rejection vector). GraphInput.landmarks REQUIRED and
loud-validated (T-08-04). RoadGraph gains the five landmark fields
(Plan 08-03's ALT potentials consume them).
Fixture regenerated as ARG2 through the SAME encode authority: the
builder gains the tiny real landmark stage (L=2, anchors [0,18],
quantum 0.1s, coverage 1.0 — identical bytes every re-run).
Rule-3 call-site updates forced by the required-landmarks law (missed
by the plan's files list): astar.test A3 + snap.test S3 synthetics
carry inert hand landmark blocks. Fixture regen pulled forward from
task 3 so this commit's own battery is green (74 passed, 0 failed).
farthestPointAnchors + landmarkTables + landmarkCoverage over the
ĉ metric: edge weights floor-quantized once (Math.floor(seconds/q)),
exact integer Dijkstras (Int32 labels, binary heap, lazy deletion),
0xFFFF sentinel, 65000-quantum loud overflow. Traversal law mirrors
astar.ts verbatim: bit0 edges never relaxed in EITHER direction.
Test-vector corrections caught at GREEN (expectations were wrong,
implementation was right):
- L4: rows index by anchor POSITION (row-major [l*N+v]), not node id
- L6: the c-metric farthest node from corner 0 is interior node 18
(297q: interior hops cost 2x perimeter), not corner 24 (264q) —
verified against an independent brute-force Dijkstra
A 2-node graph has no degree>=2 candidates, so farthestPointAnchors
returns empty before any Dijkstra runs and never reaches the overflow
throw. Node 1 on a 3-node path is a candidate, so the selection pass
actually exercises the law.
Hand-computed vectors for the pure landmark compute core: deterministic
degree-filtered farthest-point anchors, exact integer quanta
(floor(2.55/0.1)=25, two edges=50), 0xFFFF sentinel + self-cell laws,
oneway asymmetry, the 65000-quantum overflow throw, and the 5x5-grid
corner-to-corner 264-quanta vector with coverage 1.0.