fix(08): WR-04 — quantized weight validated at the i32 boundary before the Int32Array store

- 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
This commit is contained in:
araharah-executor
2026-10-25 22:35:47 +08:00
parent 95399aec8a
commit e77bbe9f72
2 changed files with 76 additions and 1 deletions
+24 -1
View File
@@ -45,6 +45,16 @@ export const LANDMARK_MAX_QUANTA = 65000;
* all-ones u16 pattern 0xffff is every table cell's out-of-domain value;
* consumers check against this constant, never a per-callsite literal. */
export const LANDMARK_SENTINEL = 0xffff;
/** The i32 weight-domain ceiling: qWeight is an Int32Array, so a quantized
* edge at or past 2^31 would WRAP NEGATIVE on store — silently bypassing
* the LANDMARK_MAX_QUANTA throw in dijkstraPass (a negative contribution
* never exceeds it), poisoning the Dijkstras, and at finish() a wrapped
* −1 label would BECOME the 0xFFFF sentinel. Any raw seconds/quantumS
* quotient at or past this ceiling throws at prepare time, BEFORE the
* store — nothing is clamped, ever. (Exactly 2^31−1 already cannot
* survive dijkstraPass's ceiling either, so the strict `>=` loses
* nothing and fails one boundary earlier, at the table-build entry.) */
const LANDMARK_I32_WEIGHT_CEILING = 0x7fffffff;
/** The landmark compute input — the shape build scripts assemble. */
export interface LandmarkInput {
@@ -111,7 +121,20 @@ function prepare(input: LandmarkInput): Prepared {
}
// THE ĉ RULE (Pattern 2): floor keeps the surrogate at or below the
// live edge — the exactness hinge for admissibility downstream.
qWeight[e] = Math.floor(edge.seconds / input.quantumS);
const q = Math.floor(edge.seconds / input.quantumS);
// RANGE LAW at the storage boundary (08-review WR-04): the quotient is
// validated BEFORE the Int32Array store — at or past the i32 ceiling
// the store wraps NEGATIVE, silently bypassing the dijkstraPass ceiling
// (a negative contribution never exceeds LANDMARK_MAX_QUANTA) and
// corrupting the tables. This is a per-edge check at the table-build
// entry: the search hot path stays allocation-free and validation-free.
if (q >= LANDMARK_I32_WEIGHT_CEILING) {
fail(
context,
`edge ${edge.from}->${edge.to} quantizes to ${q} quanta, at or past the i32 weight ceiling ${LANDMARK_I32_WEIGHT_CEILING} (raise landmarkQuantumS)`,
);
}
qWeight[e] = q;
flags[e] = edge.flags & 1;
target[e] = edge.to;
source[e] = edge.from;