Files

268 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 08-alt-landmark-preprocessing-routing-backend-v2
plan: 05
type: execute
wave: 5
depends_on: ["08-04"]
files_modified:
- routing/scripts/measure-optimality-gate.mjs
- scripts/lib/budget-gates.mjs
- scripts/test/budget-audit.test.mjs
- docs/BUDGETS.md
- docs/KNOWN-LIMITATIONS.md
- docs/ROAD-GRAPH.md
autonomous: true
requirements: [SC3, SC4]
must_haves:
truths:
- "The D-03 optimality gate is a committed, re-runnable script that reads the FROZEN pre-ALT record (08-01), re-routes the SAME coordinate-pinned pairs on the current ARG2 binary, and gates on seconds-equality (± OPTIMALITY_EPSILON_PCT = 0.1) + verdict-class preservation — never on node paths (equal-cost ties are documented behavior, D-03)"
- "The gate's epsilon constant is asserted EQUAL to the record's epsilon block — a record edit alone cannot fake a pass (constant-mirror law from 08-01)"
- "The ALT verdict is MEASURED, never hoped: the 25-route CI gate AND the D-04 extended 100-pair verdict both print their p95 + GATE lines; the c3 retirement (D-05) happens ONLY on passing numbers, quoted verbatim into every record"
- "The remediation ladder is pre-committed: FAIL → rebuild at --landmarks 32 → re-measure; at L=32 still FAIL → STOP and escalate honestly (retirement never fires on failing numbers); astar's stop rule is untouchable (Pitfall 3)"
- "Every record that documented the accepted c3 degradation tells the post-ALT truth: budget-gates.mjs' route-cpu verdict law, docs/BUDGETS.md's CPU row + c3 section, docs/KNOWN-LIMITATIONS.md's c3 section + ALT pointer row, docs/ROAD-GRAPH.md's ladder table + ARG2 layout — no 'next-milestone item' wording survives (Pitfall 6, docs divorce)"
artifacts:
- path: "routing/scripts/measure-optimality-gate.mjs"
provides: "the D-03 gate — exported core + CLI guard (route-corpus pattern); D03A seconds-equality + D03B verdict-class checks with per-pair violations"
- path: "scripts/lib/budget-gates.mjs"
provides: "the route-cpu verdict law re-anchored: ≤8 ms PASS; within the shared-host variance guard → loud re-run warning; beyond → uncharted-regression FAIL; all c3-ACCEPTED wording removed"
- path: "docs/KNOWN-LIMITATIONS.md"
provides: "the c3 section replaced by the retirement record (FIXED shape, /cari precedent); ALT roadmap-pointer row flipped to built"
- path: "docs/ROAD-GRAPH.md"
provides: "ladder table's (c2) rung with measured numbers; the ARG2 layout + landmarkQuantumS knob documented; storage-name-vs-format-truth note"
key_links:
- from: "routing/scripts/measure-optimality-gate.mjs"
to: "routing/test/fixtures/alt-baseline.json"
via: "reads pairs (origin/destination lat-lng + seconds + verdict) + epsilon.pct from the frozen record — never regenerates pairs"
pattern: "alt-baseline\\.json"
- from: "routing/scripts/measure-optimality-gate.mjs OPTIMALITY_EPSILON_PCT"
to: "record.epsilon.pct"
via: "mirror assert before any measurement (mismatch → fail)"
pattern: "OPTIMALITY_EPSILON_PCT"
- from: "docs/KNOWN-LIMITATIONS.md retirement record"
to: "the campaign's printed gate lines (task 2's quoted numbers)"
via: "D-05 evidence law: the record quotes the measured p95s + date, never rounds up or hopes"
pattern: "FIXED 2026-"
---
<objective>
The measurement campaign that turns ALT from code into evidence, and the record retirement that evidence buys: the D-03 optimality gate against the frozen pre-ALT baseline, the SC-1/SC-1′ CPU verdicts (25-route CI + 100-pair extended), then every c3-accepting record — budget gate law, BUDGETS, KNOWN-LIMITATIONS, ROAD-GRAPH — re-written to the measured truth.
Purpose: this plan IS the phase's success criteria. SC-1 (p95 under the ceiling) and SC-2 (optimality unaffected) are measured here; SC-3 (the c3 class retires with evidence) is written here.
Output: green optimality gate, green CPU verdicts (or the honest-FAIL escalation), and four documents + one gate law that no longer accept a degradation that no longer exists.
</objective>
<execution_context>
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
@$HOME/.config/opencode/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/STATE.md
@.planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-CONTEXT.md
@.planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-RESEARCH.md
@.planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-PATTERNS.md
@.planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-VALIDATION.md
<interfaces>
<!-- The instruments and records this plan operates on. Extracted 2026-10-25. -->
The frozen record (Plan 08-01, `routing/test/fixtures/alt-baseline.json`):
```json
{ "recordedAt": "<ISO>", "epsilon": { "name": "OPTIMALITY_EPSILON_PCT", "pct": 0.1 },
"graph": { "path": "routing/data/kl-roadgraph.v1.bin", "byteLength": 15449343, "nodeCount": N, "edgeCount": E, "argVersion": 1 },
"pairRules": { "seed": "0x08a1", "count": 100, "minPairKm": 12 },
"pairs": [ { "pairId": "x000", "origin": {"lat": …, "lng": …}, "destination": {"lat": …, "lng": …}, "straightLineKm": …, "seconds": …, "verdict": "reachable|unreachable|unsnappable" } ] }
```
The record is IMMUTABLE (the recorder refuses overwrite; delete by explicit git revert only). Pairs are pinned by COORDINATES (never node indices — Pitfall 2).
`routing/scripts/route-corpus.mjs` — the gate-script architecture to copy: exported measurement core + CLI guard (`const invoked = process.argv[1] ? pathToFileURL(...) : ""; if (invoked === import.meta.url) main();`, lines 329–334), the checks-registry + violations pattern (lines 74–92), named-constant bands (lines 41–53), the report/exit law (0 only when every check has zero violations).
`routing/scripts/measure-route-cpu.mjs` — the two verdict modes: default (zero args, 25-route CI gate, `P95_BUDGET_MS = 8`, prints `p95: <n> ms (…)` + `GATE PASS|FAIL: …`) and `--extended` (Plan 08-01: ~100 cross-metro coordinate-pinned pairs via generateCrossMetroPairs, seed 0x08a1, its own p95 + gate line naming the D-04 extended verdict). The pre-ALT extended run measured an HONEST GATE FAIL (08-01) — post-ALT PASS is the arc this plan closes.
`scripts/lib/budget-gates.mjs` — the route-cpu verdict law going stale (lines 24–33 doc, 58–61 `ROUTE_CPU_DRIFT_GUARD_MS = 200`, 121–133 verdict strings): current strings call an 8 ms overshoot "the DOCUMENTED, ACCEPTED c3 class" and call ALT "a next-milestone item". `runCpuLadderGate` (lines 78–119) runs measure-route-cpu.mjs with ZERO args and regex-parses `^p95:` / `^GATE (?:FAIL|PASS):` — that CLI contract is pinned (budget-audit 19/19 vectors; scripts/test/budget-audit.test.mjs also source-token-checks the gates). Read that test IN FULL before editing either file — vectors pinning the stale strings co-update in the same task.
docs state to rewrite: `docs/KNOWN-LIMITATIONS.md` c3 section (lines 29–41, ending "…it is a next-milestone item and is **not** in this release."), the /cari FIXED-record precedent (lines 43–57: ROOT CAUSE / what changed / verified date / what REMAINS), ALT pointer row (line 80: "Next-milestone item, not built"). `docs/ROAD-GRAPH.md` CPU-gate section (lines 77–106: ladder table + the open c1/c2/c3 decision paragraph), key-facts row "pinned CSR v1" (line 130). `docs/BUDGETS.md` route-cpu row (line 58) + "Cross-metro CPU degradation (the c3 class)" section (lines 162–186, including the 200 ms DRIFT GUARD paragraph). `docs/CONFIGURATION.md` — verify-only.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>task 1: The D-03 optimality gate script + green run against the frozen record</name>
<files>routing/scripts/measure-optimality-gate.mjs</files>
<read_first>
- routing/test/fixtures/alt-baseline.json (the committed record — its exact schema is the gate's input contract)
- routing/scripts/route-corpus.mjs lines 41–92 + 283–334 (checks/violations pattern, exported-core + CLI-guard, report/exit law — copy this architecture)
- routing/scripts/measure-route-cpu.mjs lines 47–84 (existsSync guard, toArrayBuffer, decodeGraph-null fail, graph print shape)
- .planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-RESEARCH.md (D-03 verbatim; Pitfall 1 — the record is frozen, drift escalates, never re-records; Pitfall 2 — coordinates are the only pin)
- routing/scripts/measure-optimality-baseline.mjs (Plan 08-01 — the immutable-record law and the fail() shape it established)
</read_first>
<behavior>
- epsilon mirror: the script's OPTIMALITY_EPSILON_PCT ≠ record.epsilon.pct → fail() BEFORE any measurement (constant-mirror law; a record edit alone cannot fake equality)
- record.graph.argVersion !== 1 → fail() ("the baseline must be the pre-ALT record")
- current binary decodes null (still ARG1 / corrupt) → fail() with the rebuild hint — never a partial comparison
- D03B verdict class: record reachable + post-ALT null (or the reverse) → violation naming the pairId; record unreachable + post unreachable → pass
- D03A seconds: both routed and |post − pre| > pre × 0.1/100 → violation; within → pass (equal seconds, ties allowed — node paths are NEVER compared)
- record "unsnappable" pairs (seconds null): post also unsnappable → pass; post now snaps and routes → an INFO row ("re-snapped") with its seconds printed, NOT a violation — counted and WARNING-printed in the summary if > 0 (D-03's letter gates the reachable/unreachable classes)
- a tie-path difference (different equal-cost node path, same seconds) CANNOT produce a violation — the gate structurally never looks at paths
</behavior>
<action>
Create `routing/scripts/measure-optimality-gate.mjs` (#!/usr/bin/env node; header contract doc-comment in the route-corpus style: purpose, inputs — the COMMITTED record + the LOCAL rebuilt binary — echoes pair ids + measurements only, exit law).
Constants (named, doc-commented): `OPTIMALITY_EPSILON_PCT = 0.1` (D-03; the mirror of the record's epsilon block), `RECORD_PATH = resolve(here, "..", "test", "fixtures", "alt-baseline.json")`, `GRAPH_PATH = resolve(here, "..", "data", "kl-roadgraph.v1.bin")` (the same path law as measure-route-cpu).
Exported core (the route-corpus split — one measurement, two reporters):
`export function measureOptimality(graph, record, { snap, astar })` → `{ checks: { D03A, D03B }, rows, reSnapped, pass }` — for each record pair: snap both endpoints (snap-miss on the NEW graph → row class "unsnapped", handled per the unsnappable rules above); route with `astar`; compare per the <behavior> rules; per-pair row `{ pairId, pre, post, deltaPct, verdictPre, verdictPost, class: "pass|violation|re-snapped|unsnapped" }`.
CLI main(): existsSync guards (absent record → fail "run measure-optimality-baseline first — the record is the D-03 anchor"; absent binary → fail with the build hint); parse + validate the record; the epsilon + argVersion mirror asserts; decodeGraph (null → fail honest); INFO print comparing record.graph counts vs current (nodeCount/edgeCount drift → WARNING line: "extract drift vs the frozen record — the seconds gate still applies"; NOT a violation, and NEVER a reason to re-record — Pitfall 1); run the core; print per-pair rows (` xNNN: pre 5123.4s post 5123.4s (Δ 0.000%) pass` shape), the summary (violations per check, re-snapped count, max |Δ%|, the epsilon used), and exit 1 on any violation else `GATE PASS: D-03 optimality — N/N pairs equal within ±0.1%, verdict classes preserved`.
Then RUN it — the rebuilt ARG2 binary from 08-04 is on disk: `node routing/scripts/measure-optimality-gate.mjs`. Expected: GATE PASS (ALT is steering-only; A1-class change). A FAIL here is honest and STOPS the plan: report the violating pairs, suspect extract drift first (compare the WARNING counts), and NEVER edit the record — escalation to the user is the only next step (Pitfall 1's immutable law).
</action>
<verify>
<automated>export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH" && node routing/scripts/measure-optimality-gate.mjs 2>&1 | tail -3 && echo "D03-GATE-GREEN"</automated>
</verify>
<acceptance_criteria>
- The script is committed; grep gates: `OPTIMALITY_EPSILON_PCT` ≥ 3 (const + mirror assert + report line); the mirror assert (`record.epsilon`) present; `alt-baseline.json` referenced as RECORD_PATH.
- The real run exits 0 printing per-pair rows for the record's full pair count (100), 0 violations, and the `GATE PASS: D-03 optimality …` line; the run's tail is quoted in the summary.
- Seconds/verdict-only law: the script contains NO node-path comparison (`grep -c "nodes\[0\]\|nodes.length" routing/scripts/measure-optimality-gate.mjs` = 0).
- Honest-refusal structure verified by reading main(): the epsilon + argVersion mirror asserts and the decodeGraph-null branch ALL precede any measurement call (code-order check, quoted in the summary).
</acceptance_criteria>
<done>D-03 is a machine gate and it is GREEN: post-ALT seconds equal the frozen pre-ALT record within ±0.1% with verdict classes preserved.</done>
</task>
<task type="auto">
<name>task 2: The CPU verdict campaign (SC-1 + SC-1′) with the pre-committed ladder</name>
<files></files>
<read_first>
- routing/scripts/measure-route-cpu.mjs IN FULL (185 lines — the two modes whose output you will quote; the GATE lines' exact shapes)
- .planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-RESEARCH.md (D-04; Pitfall 3 — the remediation ladder and the temptation it forecloses; A6 — the verdict is expected but the gate decides)
- .planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-01-PLAN.md (the pre-ALT extended FAIL — the honest before-number this verdict answers)
</read_first>
<action>
Run BOTH verdict modes over the ARG2 binary and quote every gate line in the summary. These numbers are the phase's SC-1 evidence and the raw material for tasks 3–4's records.
1. `node routing/scripts/measure-route-cpu.mjs` — the 25-route CI gate. Expected: `GATE PASS: p95 <X> ms <= 8 ms budget`. Quote the p95 line, the worst 3 per-pair lines, and the routed/unreachable split.
2. `node routing/scripts/measure-route-cpu.mjs --extended` — the D-04 ALT verdict on ~100 coordinate-pinned cross-metro pairs. Expected: its own p95 + `GATE PASS` line naming the D-04 extended verdict. Quote the p95 line + the slowest pairs.
3. THE PRE-COMMITTED LADDER (Pitfall 3) — apply ONLY in this order, only on FAIL:
a. `node routing/scripts/build-road-graph.mjs --landmarks 32` (the measured D-02 knob, top of the rule) → re-run BOTH gates.
b. At L=32 still FAIL → STOP. Record the honest numbers; do NOT proceed to tasks 3–4 as retirements (they re-scope to an honest escalation record instead — D-05's evidence law forbids retiring on failing numbers); report to the user.
NEVER: edit P95_BUDGET_MS, touch routeAstar's stop rule/reductions, drop sample pairs, reseed, or re-run until a lucky box moment and quote only that one (print-the-measurement law gates even a PASS — quote the run you got; a suspiciously loaded box gets a NOTE in the summary, not a re-roll).
</action>
<verify>
<automated>export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH" && node routing/scripts/measure-route-cpu.mjs 2>&1 | tail -1 && node routing/scripts/measure-route-cpu.mjs --extended 2>&1 | tail -1 && echo "CPU-VERDICTS-RECORDED"</automated>
</verify>
<acceptance_criteria>
- The 25-route gate exits 0 with `GATE PASS: p95 … <= 8 ms budget` (or the ladder was exercised to its documented stop).
- The extended verdict exits 0 with its `GATE PASS … D-04 extended verdict` line (or the ladder/escalation path is documented).
- The summary quotes BOTH p95 lines + n values + date, and (if used) the `--landmarks 32` rebuild command and both re-measurements.
- `grep -c "P95_BUDGET_MS = 8" routing/scripts/measure-route-cpu.mjs` = 1 (the budget was never touched).
</acceptance_criteria>
<done>SC-1/SC-1′ are measured with ALT live; the numbers that retire (or honestly keep) the c3 class exist, printed and quoted.</done>
</task>
<task type="auto">
<name>task 3: Budget-record truth-out — the route-cpu gate law + docs/BUDGETS.md</name>
<files>scripts/lib/budget-gates.mjs, scripts/test/budget-audit.test.mjs, docs/BUDGETS.md</files>
<read_first>
- scripts/lib/budget-gates.mjs lines 20–135 IN FULL (the runCpuLadderGate law, ROUTE_CPU_DRIFT_GUARD_MS, the verdict strings citing the ACCEPTED c3 class + "next-milestone item")
- scripts/test/budget-audit.test.mjs IN FULL (the 19/19 vectors — identify which pin the stale strings/exit laws; they co-update here)
- docs/BUDGETS.md lines 50–70 (the route-cpu row) + 155–190 (the c3 section + the DRIFT GUARD paragraph)
- .planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-CONTEXT.md (D-05 — the record retires WITH evidence)
- Task 2's quoted numbers (the new measured p95s)
</read_first>
<action>
Retire the c3 acceptance in the gate law and the budget record — the audit must stop DOCUMENTING a degradation that no longer exists (Pitfall 6):
1. `scripts/lib/budget-gates.mjs` — re-anchor the route-cpu verdict law (the zero-arg CLI contract with measure-route-cpu.mjs and the `^p95:` / `^GATE` regex parsing stay BYTE-COMPATIBLE — that is pinned by budget-audit):
- ≤ P95_BUDGET_MS (8): unchanged PASS path.
- 8 < p95 ≤ ROUTE_CPU_DRIFT_GUARD_MS (200 — the constant STAYS, re-documented): exit 0 with a loud WARNING line: over the product budget within the shared-host variance guard (documented ≈2x box variance; the 06-04 band history cites 38–93 ms on IDENTICAL pre-ALT code) — "re-run on a quiet box before treating as regression; the c3 class was RETIRED in Phase 8 (ALT preprocessing)".
- p95 > 200: exit 1 "UNCHARTED REGRESSION — the c3 degradation class was retired in Phase 8; a p95 here means the ALT binary/graph or the search regressed".
- DELETE the stale strings: "DOCUMENTED, ACCEPTED c3 class", "the ALT landmark lever is a next-milestone item", and the doc-comment lines 24–33's c3-acceptance framing — replaced by the retirement framing with the Phase 8 citation.
2. `scripts/test/budget-audit.test.mjs` — co-update ONLY the vectors that pinned the stale strings/exit law (the suite must return to 19/19 green with the NEW law; the count stays 19 unless a vector was solely a stale-string pin, in which case it becomes the new-law equivalent — never silently dropped; the final line still reports `BUDGET-AUDIT SUITE: 19/19 vectors ok`).
3. `docs/BUDGETS.md` — the route-cpu row: new measured value (task 2's quoted p95 + date + n; keep the "not statically pinnable / re-run the audit" honesty and the shared-host variance note), the headroom cell flips positive, the "accepted c3 class" disposition cell becomes "RETIRED 2026-10-25 (Phase 8, ALT)". The c3 section becomes the retirement record in the same shape (what changed: ALT preprocessing + ARG2; the measured numbers that retired it; the DECIDED posture now: p95 ≤ 8 is the gate, the variance guard is measurement hygiene, NOT an accepted class; the ladder history stays as history). The DRIFT GUARD paragraph re-anchors to the new law (variance guard ≠ accepted degradation).
</action>
<verify>
<automated>export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH" && node scripts/test/budget-audit.test.mjs 2>&1 | tail -1 && grep -rn "next-milestone item" scripts/lib/budget-gates.mjs docs/BUDGETS.md | wc -l && echo "C3-GATE-LAW-REANCHORED"</automated>
</verify>
<acceptance_criteria>
- `node scripts/test/budget-audit.test.mjs` → final line `BUDGET-AUDIT SUITE: 19/19 vectors ok` (co-updated vectors included).
- grep law: zero hits for "next-milestone item" in scripts/lib/budget-gates.mjs and docs/BUDGETS.md; zero hits for "ACCEPTED c3" in budget-gates.mjs.
- ROUTE_CPU_DRIFT_GUARD_MS still exported and used (the constant survives with its new documented meaning).
- docs/BUDGETS.md's route-cpu row carries task 2's measured p95 + date; the c3 section leads with the retirement (grep "RETIRED" ≥ 1 in the file).
- The zero-arg child-process contract is untouched: `runCpuLadderGate` still executes measure-route-cpu.mjs with no args and the same regexes (the audit suite's own pins prove it).
</acceptance_criteria>
<done>The budget record and its gate law state the post-ALT truth: ≤8 ms is the gate, the variance guard is hygiene, c3 is retired with quoted numbers.</done>
</task>
<task type="auto">
<name>task 4: Docs retirement (D-05) — KNOWN-LIMITATIONS + ROAD-GRAPH (+ CONFIGURATION verify)</name>
<files>docs/KNOWN-LIMITATIONS.md, docs/ROAD-GRAPH.md</files>
<read_first>
- docs/KNOWN-LIMITATIONS.md IN FULL (104 lines — the c3 section 29–41; the /cari FIXED-record precedent 43–57, the exact shape to copy; the roadmap-pointer table 77–81)
- docs/ROAD-GRAPH.md IN FULL (130 lines — the CPU-gate section 77–106 incl. the open c1/c2/c3 decision paragraph; the fork contract's build/check steps; the key-facts table 119–130)
- docs/CONFIGURATION.md lines ~24, ~248, ~294 (verify-only: path/script-name claims that could have gone false)
- .planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-RESEARCH.md (D-05; Pitfall 6 — docs divorce; the ROAD-GRAPH.md section of PATTERNS)
- Tasks 1–3's quoted numbers (the retirement record's evidence)
</read_first>
<action>
1. `docs/KNOWN-LIMITATIONS.md`:
- Replace the "Cross-metro routes may not resolve" c3 section with the retirement record, in the /cari record's shape: ROOT CAUSE (BH's weak geographic/max-speed potentials on 20–30 km cross-metro routes — the survey-predicted weak spot), FIXED 2026-10-25 (Phase 8): ALT landmark preprocessing — build-time ĉ-metric distance tables in the ARG2 graph layout + max-combined ALT/haversine A\* steering; the measured numbers that retired it (25-route p95 X ms; extended 100-pair p95 Y ms — quoted from task 2's printed lines; the D-03 optimality gate green vs the frozen pre-ALT record); what REMAINS: equal-cost tie-paths may differ (documented behavior, never a failure), and an old ARG1 binary is router-pending until ONE re-upload — the designed degradation, now the only one. Workers Paid stays rejected ($0 law).
- Flip the roadmap-pointer ALT row: "Next-milestone item, not built" → built (Phase 8) with the measured p95; adjust the surrounding "none in this release" framing accordingly (the WASM-router and Engine-B rows stay as they are).
2. `docs/ROAD-GRAPH.md`:
- CPU-gate section: the ladder table gains the (c2) rung — executed, with the measured p95s + date; the decision paragraph flips from OPEN (c1/c2/c3) to DECIDED: c2 built (this phase), c1 and c3 rejected (c3 retired by measurement). Note the extended 100-pair verdict as the cross-metro evidence.
- New short section "The ARG2 layout": 72-byte header (landmarkCount / landmarkQuantumS / reserved), the u16 dual-family table suffix + u32 anchors, the sentinel 0xFFFF law, and the `landmarkQuantumS` fork knob — 0.1 s default ⇒ ≈6,553 s expressible ceiling, raise-at-rebuild instructions for larger forks (Pitfall 5). The storage-name-vs-format-truth note: the R2 key stays `kl-roadgraph.v1.bin` (D-01 lock); the HEADER version is the format truth — never rename the key.
- Key-facts table: "pinned CSR v1" → ARG2 wording; add the optimality-gate script to the tools list.
- The fork contract's build step text gains the landmark facts (the stage prints them; no new commands — the contract's commands are unchanged).
3. `docs/CONFIGURATION.md`: READ-verify — edit ONLY if a statement became false (paths and script names are unchanged; expected no-op). Note the check in the summary either way.
TONE LAW: honest-engineering voice throughout — quote measured numbers with their date, name what remains, never overpromise ("routes in budget" only as far as the gates measured).
</action>
<verify>
<automated>export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH" && grep -c "Next-milestone item, not built" docs/KNOWN-LIMITATIONS.md; grep -c "FIXED 2026-10-25" docs/KNOWN-LIMITATIONS.md docs/ROAD-GRAPH.md; grep -c "landmarkQuantumS" docs/ROAD-GRAPH.md && echo "DOCS-RETIRED"</automated>
</verify>
<acceptance_criteria>
- KNOWN-LIMITATIONS: `grep -c "Next-milestone item, not built"` = 0; the retirement record present with `FIXED 2026-10-25` + the measured p95 strings from task 2 (grep the exact quoted number ≥ 1); the tie-path and router-pending remainders named.
- ROAD-GRAPH: the (c2) ladder rung present with numbers (`grep -c "(c2)" ≥ 1` in the ladder table region); `landmarkQuantumS` ≥ 2; "ARG2" ≥ 3; the decision paragraph states c2 executed and c1/c3 rejected; the storage-name note present.
- No doc claims ARG1 binaries remain decodeable (grep -ci "arg1" in both docs shows only retirement/router-pending contexts — read the hits).
- CONFIGURATION.md untouched OR the touched lines quoted in the summary.
- Both docs keep the honest tone: no "always"/"never" claims beyond what the gates measured.
</acceptance_criteria>
<done>SC-3 is written: the c3 class is retired with quoted evidence in every record that documented it, and the fork contract teaches ARG2.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| frozen record → optimality gate | the record is the phase's comparison anchor; editing it must never be able to fake a pass |
| campaign verdicts → public docs | the retirement records quote measurements; unmeasured claims are the failure mode D-05 exists to prevent |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-08-13 | Tampering | gaming the optimality gate by editing the record | mitigate | the epsilon constant-mirror assert + the record's refuse-overwrite immutability (08-01) + committed git history make any edit visible; the gate re-snaps the record's COORDINATES and re-measures live, so only a genuine equal-seconds run passes |
| T-08-14 | Repudiation | retirement docs citing numbers never measured | mitigate | D-05's evidence law: tasks 3–4 quote task 2's printed gate lines verbatim; the review leg cross-checks the quotes against the summary |
| T-08-15 | Tampering | extract drift faking a pass/fail | mitigate | the gate prints the counts-diff WARNING; the seconds epsilon + verdict classes are the gates; a mass-failure escalates to the user — the record is never silently re-recorded (Pitfall 1) |
| T-08-16 | DoS | campaign runtime (100 routes + rebuild retries) | accept | maintainer-time; seconds-class measurements; the ladder is capped at one rebuild (L=32) |
</threat_model>
<verification>
- `node routing/scripts/measure-optimality-gate.mjs` → GATE PASS (D-03).
- Both measure-route-cpu modes → GATE PASS (SC-1/SC-1′) or the documented honest-FAIL escalation.
- `node scripts/test/budget-audit.test.mjs` → `BUDGET-AUDIT SUITE: 19/19 vectors ok`.
- `npm run routing:test && npm test -w bot && npm run routing:typecheck && npm run bot:typecheck` — the full battery green one final time at the phase's last code-touching commit (only the new gate script + doc/gate-law edits since 08-04).
- Docs greps (task 4's acceptance) all green; the summary quotes every gate line the records cite.
- MANUAL (maintainer, after this plan): `node routing/scripts/upload-road-graph.mjs` + the roundtrip `--check` — the R2 upload is an account-level act (validation map, manual-only); the plan stops at the local evidence.
</verification>
<success_criteria>
The D-03 optimality gate is green against the frozen pre-ALT record; the 25-route and extended CPU verdicts pass with ALT live (or the honest-FAIL escalation is recorded); every record that accepted the c3 degradation — budget gate law, BUDGETS, KNOWN-LIMITATIONS, ROAD-GRAPH — now states the measured post-ALT truth with dates and quoted numbers; the fork contract teaches ARG2; nothing claims more than the gates measured.
</success_criteria>
<output>
After completion, create `.planning/phases/08-alt-landmark-preprocessing-routing-backend-v2/08-05-SUMMARY.md`
</output>