Commit Graph
281 Commits
Author SHA1 Message Date
araharah-executor ea9584d163 feat(06-04): R2 upload + A*-CPU measurement gate + the A1 ladder executed to its decision point
- upload-road-graph.mjs: wrangler-shelled maintainer tool (pre-flight 1-80MB,
  round-trip verify hint); bucket araharah-graphs NOT created — R2 is not yet
  enabled on the account (wrangler code 10042) — dashboard one-time activation
  is the phase's user_setup item
- measure-route-cpu.mjs: 25-pair gate (corpus + seeded quadrant spread),
  hrtime around routeAstar, warm-up excluded, unreachable probes reported
  SEPARATELY from the routed p95, exits 1 over the 8ms budget
- Rule 1 (measured): the class set lacked *_link ramps — the graph FRAGMENTED
  (7.7% of nodes in severed motorway islands; corpus pairs 'unreachable').
  5 link classes added -> 311325 nodes / 677068 edges / 14.7 MB, all landmarks
  in one component; enforced floor corrected 1KB -> 1MB (D-01)
- ladder (a) drop tertiary+residential: p95 17.8ms but 12/25 pairs unreachable
  — REJECTED on correctness (D-03), reverted, ladder history recorded
- ladder (b) bidirectional A* (BH, Ikeda potentials, reverse-CSR WeakMap):
  provably optimal (A1 625-pair sweep green), alternation balanced by heap
  size (raw-top comparison starves the backward side 19501:3), reduction
  signs in the standard feasible form. Measured: p95 ~38-93ms — NO GATE PASS.
  The potential split halves each side's steering, cancelling the halved radius
- GATE FAIL is the honest verdict: ladder (c) — Workers Paid vs layout-v2 ALT
  (still $0) vs free-plan-with-degradation — requires maintainer sign-off;
  docs/ROAD-GRAPH.md carries the decision table and the fork contract
2026-10-24 13:56:18 +08:00
araharah-executor 020eb92058 feat(06-04): /api/route engine-A arm + http-source backend #2 — Bearer-gated, honest-null, RP re-pinned (GREEN)
- bot/src/routing/worker-router.ts: module-scope per-env graph memo (1 R2 GET per
  cold isolate, shared with the 06-07 cron arm via loadGraph), snap+A*+deriveSteps,
  claim-gated 401 / 4096-cap 413 / V5 bbox 400, 200-null on every miss class,
  ONE best route (no alternatives), category-only logs
- webhook.ts: /api/route arm delegating to handleRoute (405 non-POST)
- config.ts: ROAD_GRAPH: R2Bucket — first R2 binding (never a KV namespace, GE5)
- wrangler.jsonc: r2_buckets ROAD_GRAPH -> araharah-graphs with the fork law comment
- routing/src/http-source.ts: createHttpRoutingSource — slug-guard-first, fail-honest
  (throw/non-200/malformed/null-body -> null), defensive RouteResult validation;
  exported from index.ts; ladder note: backend #2 LIVE
- A7 re-pinned (06-01 named 06-04 as the owner of createHttpRoutingSource)
- test-side fix during GREEN: the R2 fake hands decodeGraph an exact ArrayBuffer
  (Node Buffers are views; encodeGraph output is already an ArrayBuffer)
- bot 103 passed / routing 65 passed; both typechecks clean
2026-10-24 13:27:02 +08:00
araharah-executor 0abe64e734 test(06-04): failing http-source suite H1-H8 + /api/route block RT1-RT11 + RP1/RP2 re-pin (RED)
- routing/test/http-source.test.mjs: backend #2 client seam — slug-guard-first,
  fail-honest on throw/non-200/malformed/null-body, defensive RouteResult shape
- webhook.test.mjs RT block: 401/413/400 classes, out-of-bbox origin (V5),
  200-null on unknown dest / absent graph / corrupt binary / snap miss / A* miss,
  happy path (engine-a, ONE option, steps) with the 1-GET isolate-memo probe
- route-privacy re-pin (06-04's own gate law): RP1 = claim-bound local routing
  (getClaimByToken, no fetch/proxy, arm wired to worker-router, no routing hosts),
  RP2 = workspace allowlist @araharah/{search,routing}/* subpaths only
2026-10-24 13:22:51 +08:00
araharah-executor d51fd8b47b feat(06-04): road-graph build tool — Overpass extract → pinned CSR binary with the D-01 stats gate
- maintainer-time repo tool (nothing in bot/web/routing src imports it): drivable-class
  Overpass extract (Pitfall 1 filter), nodes deduped by rounded coord, oneway/-1/roundabout
  flag law, maxspeed-tag overrides over class defaults, name-pool interning
- bbox derived mechanically from the committed corpus (gazetteer entries + golden pairs
  ± 0.05 deg, printed) — Open Q 4's pinning
- collect-then-write + ENFORCED size gate (>1 MB, <=80 MB, exit 1 outside) + advisory
  30-80 MB band warning; --check mode decodes and re-prints the gate, zero network
- routing/data/.gitignore: *.bin is an ODbL-derived build artifact — forks build their own
- real KL graph built: 277514 nodes / 598396 edges / 21447 names / 13.1 MB (gate PASS,
  band warning printed for review)
2026-10-24 13:19:07 +08:00
araharah-executor c96f186da6 docs(06-03): merge continuation-pass verification into the plan summary
- session-continuation note (late-flush observation + post-flush gate
  re-verification by the continuation agent)
- plan-agnostic phrasing for the future worker-router RP2 widening
2026-10-24 13:10:18 +08:00
araharah-executor 3f06fdc281 docs(06-03): complete the guidance-envelope service + /api/guidance plan 2026-10-24 13:09:20 +08:00
araharah-executor 371b2a0ad7 docs(06-03): complete guidance envelope service + /api/guidance plan
- 2/2 tasks TDD RED->GREEN: envelope service (0cfa0bd/c87dc7d) +
  /api/guidance endpoints (212aa57/7875ed4)
- GE4-GE7 + RP2 re-pinned with their invalidating changes; GE1-GE3 frozen
- 90/90 bot tests green; typecheck clean
2026-10-24 13:08:05 +08:00
araharah-executor 7875ed4d94 feat(06-03): /api/guidance POST/GET/DELETE — Bearer-claim gated, TTL-only service beneath (GREEN)
- POST: WR-01 cap (MAX_GUIDANCE_BODY_CHARS 8192, pre/post-read double check),
  hand-rolled snapshot validation (slug destinationId, bounded name, finite
  metrics, integer startedAtSec, polyline6 geometry >= 2 points via
  decodePolyline6) -> mintGuidanceSession with the CLAIM's chat_id — a body
  chat_id is structurally ignored (T-06-02 injection probe GW4)
- GET/DELETE: resolve then OWN — envelope.chat_id === claim.chat_id else 404,
  foreign and absent indistinguishable (T-06-02b); DELETE actively removes
  the record (D-14's server half); non-POST/GET/DELETE -> 405
- category-only logging: [guidance] rejected: unauthorized|malformed —
  literal strings, no interpolation of body/claim values (D-14)
- RP2 re-pin ships WITH the change (gate re-pin law): the total
  @araharah/routing ban becomes an explicit allowlist — exactly the
  polyline6 codec may enter the Worker (geometry validation); the routing
  stack stays web-side; RP1 unchanged
- bot/package.json + lock: @araharah/routing workspace dep
2026-10-24 13:06:25 +08:00
araharah-executor 212aa57c14 test(06-03): guidance endpoint suite GW1-GW11 — 401/413/400 classes, claim-owned chat (T-06-02 injection probe), own-vs-foreign GET/DELETE, 405 (RED)
- offline undici Request/Response pattern; claims minted through the real
  /api/session path (mintSession) against the Map-fake KV
- GW8 green-by-construction (the catch-all already 404s absent ids);
  ownership teeth live in GW7/GW10
2026-10-24 13:04:17 +08:00
araharah-executor c87dc7dc14 feat(06-03): guidance envelope service — TTL-only mint/get/delete beneath the frozen shape
- mintGuidanceSession: crypto.randomUUID id, claim-derived chat_id arg,
  ONE put at guidance:<id> with same-line expirationTtl (GE1/PG1)
- getGuidanceSession: UUID-shape guard BEFORE any KV touch (V5), exact
  4+6-field + type + finite/range validation (the location-pin defensive
  read law) — corrupt records read as null, never reach the cron
- deleteGuidanceSession: active trip-end sweep (D-14's server half)
- module header: the types-only note becomes the shape-frozen + service-
  owns-every-write law; envelope/snapshot interfaces byte-identical (GE2)
- no new namespace (GE5), no new Env field (GE6) — the chat_sessions
  binding is handed in structurally
2026-10-24 13:03:19 +08:00
araharah-executor 0cfa0bde38 test(06-03): re-pin GE4/GE7 to the live service + behavioral envelope suite + PG1 storage list (RED)
- GE1/GE2/GE3 UNCHANGED in meaning (TTL 7200, 4+6 field freeze, inline snapshot)
- GE4 re-pinned: types-only token ban -> the module must EXPORT mint/get/deleteGuidanceSession
- GE7 re-pinned: total consumer ban -> named-imports-only of the service surface
- GE5/GE6 stand (exactly one kv namespace; no Env guidance field)
- GS1-GS5 behavioral: TTL'd mint, roundtrip, 7-class defensive null read,
  UUID key-guard without KV touch (V5), active delete (D-14 server half)
- PG1 storageModules now covers kv/guidance-sessions.ts (same-line TTL law)
2026-10-24 13:02:28 +08:00
araharah-executor a9041fb527 docs(06-02): complete the guidance-brain plan (replays + ETA + throttle)
- SUMMARY: 3/3 tasks, 5 commits, 100/100 web tests, replay-proven D-04
  machine, honest ETA, D-15 throttle; deviations + self-check recorded
- STATE.md / ROADMAP.md deliberately untouched (orchestrator-owned)
2026-10-24 12:53:16 +08:00
araharah-executor a45f8a507e feat(06-02): D-15 distance-throttled watchPosition wrapper + throttle truth table
- shouldAcceptFix: accept when first fix, >=10 m moved, or >=5 s elapsed
  (whichever first) — the pure accept rule over haversineM
- createGuidanceWatch(geo, onFix): high-accuracy watchPosition
  (maximumAge: 0), six-field Fix normalization (null accuracy/heading,
  source webview), rejected fixes die in the wrapper, idempotent stop()
  clearing the watcher id (T-06-05b's privacy-minimal trip end)
- replay suite T1-T3 + R12b: truth table, recorded-options structural
  gate, feed-only-accepted proof, stop idempotence, module purity scan
2026-10-24 12:50:49 +08:00
araharah-executor 299827a469 feat(06-02): honest ETA — per-axis EMA + independent display deadbands + arrival clock (GREEN)
- updateEta(prev|null, remainingS, remainingM): numbers-only signature
  (D-07 structural — no Fix can enter); first update seeds directly
- EMA alpha 0.25/fix per axis; display refreshes only past its axis
  deadband (+-1 min time / +-5% remaining, axes independent)
- composeEtaClock: 24-hour HH:MM instrument format (local wall clock)
- suite E1-E8 green: seed, jitter-holds-display, real-drop-updates,
  independent axes, deadband symmetry, pinned constants, purity gate
2026-10-24 12:48:29 +08:00
araharah-executor 65852940cc test(06-02): add failing honest-ETA suite E1-E8 — EMA + deadband + arrival clock (RED) 2026-10-24 12:47:13 +08:00
araharah-executor ad1fd3059c feat(06-02): THE pure D-04 guidance state machine + forward-only projection + named constants (GREEN)
- createGuidanceSession + stepGuidance: the thresholds+grace reroute machine
  (idle/on_route/off_route/rerouting/resuming/no_reroute) with accuracy-aware
  threshold max(35, 2xacc) capped 100, 3-consecutive-fixes + grace gates,
  missed-turn shortened grace (3s), storm guard with off_route re-request
  after expiry, honest no_reroute degradation
- projectAlongRoute: forward-only cos(lat)-scaled projection, cumulative
  remaining (D-07), haversineM deviation (one distance authority)
- once-per-edge D-08 effect stream: approach 300 m / maneuver impact /
  arrive + arrival at 25 m (D-14); reroute-applied re-arms, measures against
  the NEW model only (Pitfall 6)
- replay suite R1-R12 green: corridor/excursion/missed-turn/jitter drives,
  storm guard mechanics, self-heal, structural purity gate; 88/88 web tests
2026-10-24 12:46:06 +08:00
araharah-executor b879e56bb1 test(06-02): add failing D-16 drive replay suite R1-R12 + four committed drive fixtures (RED)
- guidance-replay.test.mjs: corridor/excursion/missed-turn/jitter replays,
  storm guard, shortened grace, haptic edges, start gate, projection
- fixtures derived from golden pair central-market-to-merdeka-118
  (ODbL attribution in each _notice; Fix-shaped streams per D-16)
2026-10-24 12:35:32 +08:00
araharah-executor 9456a870fe docs(06-01): complete engine-a data-plane plan
- SUMMARY: CSR codec + snapping + typed-array A* (57/57 routing tests,
  625/625 Dijkstra equivalence), 2 documented deviations (header alignment
  padding, compass turn convention), TDD gate sequence intact
2026-10-24 12:16:37 +08:00
araharah-executor e34c2296f5 feat(06-01): typed-array A* + turn classifier + step derivation + public exports (GREEN)
- routeAstar: allocation-free hot loop — binary heap of node indices over
  preallocated typed arrays (grown by doubling), typed-array g/closed/
  came-from, on-demand cached haversine/maxSpeed heuristic (admissible +
  consistent); oneway-reverse edges never relaxed; unreachable -> null
- A1 proves A* == brute-force Dijkstra on ALL 625 mini-graph pairs
- classifyTurn: the one turn authority (compass convention — negative
  delta = left; plan's (0,40)->slight-left case contradicted its own
  (0,-90)/(0,90) pins, documented deviation); TURN_* constants exported
  for plan 07's cron projection
- deriveSteps: splits at non-straight bearings or name changes; steps
  carry kind/name/distanceM + polyline6; depart-first, arrive-last
- index.ts: engine-A named exports + ladder note updated — backend #2 is
  now 'engine-a' (D-01 supersedes the wasm-router note; Valhalla port
  infeasible + geojson-path-finder rejected, engine B = post-v1
  evolution, D-02); createHttpRoutingSource deliberately absent (plan 04)
2026-10-24 12:14:37 +08:00
araharah-executor 6adfd86ade test(06-01): add failing A* equivalence + step-derivation suite A1-A8 (RED)
- A1: exhaustive 625-pair A*-vs-Dijkstra equivalence (the RESEARCH-mandated
  correctness gate); A2 oneway detour; A3 honest-null unreachable
- A4/A5 deriveSteps: L-path turn kinds + name/distance/polyline6; depart/
  arrive invariants; A6 classifyTurn pins (compass convention, documented)
- A7 index.ts public surface (createHttpRoutingSource deliberately absent);
  A8 no-Map structural gate
2026-10-24 12:13:00 +08:00
araharah-executor 2e73068af5 feat(06-01): point-to-edge GPS-fix snapping with memoized grid index (GREEN)
- snapToGraph: bbox+margin guard first (honest null = router-pending,
  D-03), then 3x3 coarse-grid neighborhood (0.002 deg cells, WeakMap
  memo per RoadGraph — LAW 1 lazy memoize, O(local) not O(n))
- projection in cos(lat)-scaled degree space (Pitfall 8); returned
  distance is haversineM; result carries the best segment's nameId
  (null for the unnamed sentinel) for plan 07's cron street-hop
- oneway-reverse edges stay snap-visible (direction is A*'s law);
  gridBuildCount() instrumentation kept internal to the workspace
2026-10-24 12:10:46 +08:00
araharah-executor 72703d26ec test(06-01): add failing GPS-fix snap suite S1-S6 (RED)
- Exact-node hit, mid-edge closer-endpoint projection, nameId resolution
  (named + unnamed-null halves), bbox-margin honest miss, oneway direction
  ignored, WeakMap grid memoization (build-counter + structural greps)
2026-10-24 12:09:18 +08:00
araharah-executor 1ce35907d5 feat(06-01): CSR graph codec + committed mini-graph fixture + RouteStep.kind (GREEN)
- graph.ts: decodeGraph/encodeGraph over the pinned little-endian CSR
  layout; header magic+version+exact byte-size validation BEFORE any view
  allocation (T-06-03/T-06-03b fail-honest null); zero-copy typed-array
  views; street-name pool with UNNAMED_NAME_ID sentinel
- header padded 60 -> 64 bytes so f64 views are 8-byte aligned — unaligned
  Float64Array throws RangeError, making plan-literal offsets incompatible
  with the plan's own zero-copy law (documented deviation; field
  order/content/endian unchanged; consumers inherit via encodeGraph)
- build-mini-graph.mjs + committed mini-graph.bin: hand-built 5x5 grid,
  25 nodes, 80 directed edges, 3 named streets, exactly ONE oneway pair,
  two speed classes (60/30 km/h) — the A* ground truth (G7 pins it)
- types.ts: RouteStep gains optional kind (8 turn kinds) — Engine A
  populates it (06-01); fixture-world steps stay empty arrays (D-10)
2026-10-24 12:07:17 +08:00
araharah-executor 53740944b8 test(06-01): add failing CSR graph codec suite G1-G8 (RED)
- Pinned-layout gates: round-trip, bad magic/version/truncated -> null,
  zero-copy view mutation, name pool, committed mini-graph fixture pin
- Each case lazy-imports ../src/graph.ts — ERR_MODULE_NOT_FOUND is the
  red state (fixture-source.test.mjs pattern)
2026-10-24 12:05:16 +08:00
araharah-executor 7da7c2019c test(04-04): commit the CR13/CS5 shadow-law gate updates (missed in 54a2b54 staging) 2026-10-24 12:00:09 +08:00
araharah-executor 4212d1acd0 fix(06): revise plans per checker feedback — D-12 street-bearing cards by default, split 06-05 task 2, dep/wording/doc fixes 2026-10-24 08:06:42 +08:00
araharah-executor 7fe8c6aa65 docs(06): create phase plans (8 plans, 4 waves) 2026-10-24 07:46:13 +08:00
araharah-executor 6f747b4cb1 docs(05): phase 5 PASSED — verification + close 2026-10-24 06:06:49 +08:00
araharah-executor efba4d6f4c docs(05-05): complete verification-gates plan
- BA9/BA10 + BA5 sentinel extension, five ?fixpair-raced capture legs
  (13/13), RP1/RP2 Worker privacy gates
- two Rule-1 boot fixes (onLoad wiring + consult-after-load) documented
- STATE.md and ROADMAP.md untouched (orchestrator-owned)
2026-10-24 06:04:52 +08:00
araharah-executor 6302901f82 test(05-05): Worker no-route-proxy gates RP1+RP2 (D-05)
- RP1: zero /api/route + registerRoute/routeProxy tokens in comment-stripped
  bot/src — the Worker gains no route endpoint, even accidentally (T-05-16)
- RP2: zero @araharah/routing specifiers in bot/src — routing lives in the
  webview bundle only; the Worker imports only @araharah/search
- scans grow with the bot/src tree automatically (the PG-gate pattern)
- TDD note: gates target an already-clean tree, so the RED run is a teeth
  proof — a planted violating file fails both gates; removed, both pass
  (74/0 bot suite green)
2026-10-24 06:03:01 +08:00
araharah-executor af744e49c7 feat(05-05): ?fixpair harness knob + pinned-corpus origin lookup (GREEN)
- route-profiles.ts: HARNESS-ONLY module — sentinel ROUTE_PROFILE_HARNESS_ONLY
  + getRouteProfileOrigin wrapping getPairOrigin; D-12 header (pinned PUBLIC
  origin only, no coordinate params) + BA5 exclusion note
- index.html: ?fixpair=<pair-id> knob resolves the pair's pinned public
  origin as the mock's telegramFix (accuracy 12, heading null); unknown
  pairId keeps the default fix; knob documented in the profile comment
- [Rule 1 - Bug] main.ts never passed bootMap's opts.onLoad — route sources
  never existed and setRouteDrawn's setData silently no-op'd (cards rendered,
  the line never painted; invisible to the RS fakes). Wiring added + RS2
  boot-wiring gate pins it
- [Rule 1 - Bug] consult raced the map load: harness session stubs resolve
  the location chain before WebGL/style init, so draw landed on missing
  sources and the post-load empty install discarded it (probe: ROUTE token
  fired before RAMS-BASEMAP-READY). Consult now awaits mapLayersReady,
  resolved in the load handler after installRouteLayers (never wedges —
  finally-resolved; cards-only boots resolve immediately)
- Capture run: CAPTURE OK — 13/13; route line verified painted, alt swap
  renders ROUTE 2/2 +1 MIN VS ROUTE 1, pending card honest, dark PX-02
- npm test -w web: 76 passed (new RS2 boot-wiring gate included)
2026-10-24 06:01:57 +08:00
araharah-executor c9b1128a0f test(05-05): add five route capture legs racing ARAHARAH-ROUTE (RED)
- SIGNALS + seen-map + diagnostics gain ARAHARAH-ROUTE; waitMode 'route'
  races the state token, asserts expectState + expectText DOM text, and
  applies the PX-02 theme-slot honesty check on themed legs
- captureLeg gains an interact(page) pre-shot hook (the alt leg's chip tap)
- five legs data-driven from the committed corpus (demoPair picked at
  runtime — never a hardcoded pair literal): fixture / alt / pending /
  dark / route-gallery-compare (composer refactored into composeCompare)
- expected list grows 8 → 13
- RED by construction: the ?fixpair knob does not exist yet, so the
  default fix sits outside the demo pair's 200m tolerance → the drawn
  legs must fail with state=pending
2026-10-24 05:47:40 +08:00
araharah-executor 29ad451c27 test(05-05): BA9 bundle-budget + BA10 fixture-parity gates + BA5 harness-sentinel extension
- BA9: summed gz size of fixtures dataset + routing/src + web/src/route
  sources <= 204800 bytes, measurement printed every run (D-11, T-05-12)
- BA10: every committed pairId must appear in the shipped JS assets
  (the BA7 analog — a stale fixture-less bundle is unshippable)
- BA5: ROUTE_PROFILE_HARNESS_ONLY joins the harness-leak token scan
  (the 05-05 route-profiles module must be dead-code-eliminated from dist)
- TDD note: gates target artifacts already shipped by 05-02/05-04, so no
  failing RED run exists; mechanism teeth proven (bogus pairId absent)
2026-10-24 05:45:20 +08:00
araharah-executor 7aa1113a57 docs(05-04): complete web route surface plan
- 4/4 tasks, 5 commits (f710913, d0751c1, 01a75f1, 65952fb, 52c9320)
- 73 web tests green incl. RS1-RS10; typecheck + production build + theme audit clean
- deviations: live-branch routePhase guard (spec state-table precedence),
  controller dep growth for Node-testability, pin-tail 3x8/20 synthesis
2026-10-24 05:40:35 +08:00
araharah-executor 52c93203f5 test(05-04): RS1-RS10 structural + fake-map behavioral suite for the route surface
- RS1 paint law: 4 layer ids in bottom-to-top order, verbatim hex,
  square caps, bevel joins, opacity 1
- RS2 map-law: zero setStyle across web/src/route (T-05-09); opts.onLoad
  sits after building-3d and before RAMS-BASEMAP-READY
- RS3 fake-map: install shape + idempotence, setData swap/clear behavior,
  the paint table paired per layer, [lng,lat] coordinate order
- RS4 controller: drawn path (bottom card, camera law 96/320/64/64 @400ms,
  pitch 35 explicit, bearing from getBearing), chip select (swap + rebuild
  + ALWAYS refit), walkBack (clear + destination card + refollow), pending
  (center, no fitBounds), exception fail-honest (T-05-04), state tokens
- RS5 card structure: zero innerHTML, role=group, btn-secondary only
- RS6 D-10: zero btn-primary/progress/maneuver in web/src/route
- RS7 BackButton: overlay walks (never close()), root closes (T-05-11)
- RS8 console discipline: exactly two state tokens, no interpolation
- RS9 strings-only copy; RS10 route family under the storage-gate scan
2026-10-24 05:38:33 +08:00
araharah-executor 65952fbd52 feat(05-04): route controller + cards + boot wiring + two-state BackButton walk
- route-card.ts: buildRouteCard (register ROUTE{n/N}, verbatim-name
  headline, telemetry-num MIN/KM row, difference line, N-1 chips with
  aria labels + data-route-index, ONE btn-secondary) + buildRoutePendingCard
  (register/body/hint/CTA, standard ink, no red) — createElement +
  textContent only, strings-module copy, no padding overrides
- route.ts: createRouteController — idle|route|pending, consult once
  (.catch(() => null) → pending, T-05-04), chip swap + ALWAYS refit,
  walkBack total function (clear + destination card + refollow), camera
  constants beside follow.ts, two ARAHARAH-ROUTE state tokens as the
  module's ONLY console lines (D-15/T-05-13)
- main.ts: routePhase/routeWalkBack assignable closures, .route-stack +
  showRouteCard, controller wired with null-tolerant map/follow/endpoints
  (WebGL2-absent degrades to cards-only), consult-once guard in handleLive,
  stale branch keeps the route card (strip lamp carries the signal)
- backbutton.ts: predicate + handler as ONE change — overlay click walks
  to the root via the injected walkBack, root click keeps Telegram close()
2026-10-24 05:34:47 +08:00
araharah-executor 01a75f1fbe feat(05-04): route paint stack + endpoint markers + load-hook install + shell chrome
- route-layers.ts: 2 empty GeoJSON sources + 4 line layers (route-alt-casing
  5px matte-black / route-alt-line 3px soft-beige / route-casing 9px
  matte-black / route-line 5px signal-orange), opacity 1.0, cap square,
  join bevel, no beforeId — idempotent install, setData-only updates,
  zero setStyle (T-05-09); verbatim tokens.css hex (DSGN-01)
- route-markers.ts: origin ring (24px, 2px matte-black, aria-hidden) +
  destination pin (12px square + 3px×8px tail, white inset rule, never
  orange) + 160px ellipsis name chip; WeakMap-tracked removal
- map.ts: bootMap gains opts.onLoad — invoked inside the existing load
  handler AFTER building-3d, BEFORE the ready log, its own try/catch
- shell.css: .route-stack registers (64px control-clearance composite),
  telemetry/diff/chips rows composing the .card child rules (no padding
  overrides), 28px chips with 44px ::after hit slop + instant :active
  invert + 3px focus bracket, marker chrome — token references only
2026-10-24 05:29:25 +08:00
araharah-executor d0751c1a33 feat(05-04): route strings (10 keys en+ms) + @araharah/routing workspace dep (GREEN)
- 10 ShellStrings keys per the binding UI-SPEC copy table (routeRegister,
  routeDiffFastest/Slower templates, pending card quartet, ctaSearchAgain,
  ariaRouteAlternatives/Chip templates) — verbatim en + ms
- copy gate: COPY1 floor 40 + route-key pins, COPY5 scans web/src/route,
  COPY7 pins the verbatim pending/CTA/template copy
- web depends on @araharah/routing (lockfile settled)
2026-10-24 05:25:37 +08:00
araharah-executor f710913a0b test(05-04): extend copy gate for route copy — COPY7 verbatim + floor 40 + COPY5 src/route scope (RED) 2026-10-24 05:25:03 +08:00
araharah-executor 50f22dcbb7 docs(05-02): complete fixture corpus + offline tolerance gate plan 2026-10-24 05:21:59 +08:00
araharah-executor 6c0880b4db feat(05-02): offline corpus tolerance gate — measurePairs core + CLI + in-suite RT1-RT10 (GREEN)
- routing/scripts/route-corpus.mjs: the shared measurement core (exported
  measurePairs) + CLI reporter in the gazetteer-corpus.mjs shape — one
  measurement, two reporters, no drift
- RT1 corpus size 10..20; RT2 schema + RT2b mechanical D-12 proof (every
  committed origin equals its gazetteer landmark within 1e-4 deg); RT3 route
  shape; RT4 probe exclusion (national-museum never a destination); RT5
  haversine-vs-summary band [0.85, 1.10] + bbox+0.05; RT6 speed [1.0, 30] m/s;
  RT7 codec round-trip per route; RT8 ODbL header surfaces; RT9 gz budget
  (measured 16576 B / 102400 B); RT10 alternatives floor (8 pairs / floor 4)
- fully offline: zero network in the measurement path (T-05-05); pair ids and
  measurements printed, never geometry strings (D-15); fixed escalation
  ladder on failure (--only repair -> regenerate -> re-gate)
- suite: 35 passed, 0 failed; npm run routing:corpus exits 0; typecheck clean
2026-10-24 05:19:55 +08:00
araharah-executor 63ef408197 test(05-02): add failing offline corpus tolerance gate suite RT1-RT10 (RED)
- one test per check, mirroring search/test/corpus.test.mjs: the suite imports
  measurePairs from routing/scripts/route-corpus.mjs IN-PROCESS (never spawns
  the CLI) — one measurement, two reporters, no drift
- RED: the measurement core does not exist yet -> 10 named ERR_MODULE_NOT_FOUND
  failures; the committed dataset itself is already green material (task 1)
- fully offline by construction: zero network in the measurement path (T-05-05)
2026-10-24 05:18:16 +08:00
araharah-executor 4e89cff552 feat(05-02): pinned golden-pair corpus + OSRM-demo fetch tool + populated committed dataset (GREEN)
- routing/test/fixtures/golden-pairs.json: the hand-authored 15-pair pinned
  corpus (D-02/D-12) — origins AND destinations are gazetteer landmarks,
  klBbox + 100 KB gz budget + probe id + alternatives floor pinned
- routing/scripts/fetch-route-fixtures.mjs: the maintainer build tool
  (overpass-topup.mjs pattern) — D-12 boundary in the header, pre-flight
  public-coordinate proof against the gazetteer (1e-4 deg), mandatory
  User-Agent, 1200 ms inter-request delay, one retry on network/5xx,
  collect-then-write, --only=<pairId> single-pair repair merge
- routing/src/data/route-fixtures.json: 15 real OSRM-demo pairs committed
  (1-3 verbatim polyline6 routes each; 8 pairs carry >= 2 alternates),
  ODbL header fields preserved (T-05-06)
- loader-env L3 armed (RED commit 01b0ed6) + C6 re-pinned from the empty-seed
  state to the populated corpus (05-01 documented both as 05-02 handoffs)
- npm delegates: root routing:fixtures; routing fixtures + corpus scripts
2026-10-24 05:17:01 +08:00
araharah-executor 01b0ed6884 test(05-02): tighten loader-env L3 to require pair 1 serving at pinned origin (RED)
- L3 previously pinned the 05-01 empty-seed state (honest null at the pinned origin)
- it now asserts the default fixture source SERVES pair 1 (kl-tower-to-kl-sentral)
  at its pinned public origin and resolves honest null ~300 m away (outside the
  200 m tolerance, D-03)
- RED until plan 05-02 populates the committed fixture dataset
2026-10-24 05:14:15 +08:00
araharah-executor 48627d4102 docs(05-03): complete guidance-session contract freeze plan 2026-10-24 05:10:36 +08:00
araharah-executor d5c2bc0938 feat(05-03): freeze guidance_sessions envelope as types-only contract (GREEN)
- GuidanceSessionEnvelope: EXACTLY id, chat_id, route_snapshot, created_at
  (SessionClaim field-freeze law — a 5th property means drift)
- GuidanceRouteSnapshot INLINE (D-07: one key, one TTL, ~2h): destination
  id/name, distanceM/durationS, polyline6 geometry (05-01 storage format),
  startedAtSec resume anchor
- GUIDANCE_SESSION_TTL_SECONDS = 7200 — every Phase 6 write carries it
- guidance:<id> key-scheme doc header; zero runtime behavior (no binding,
  no function, no import — GE4 pins it)

Note: header says 'No KV binding' rather than naming the KV type because
the acceptance gate requires that token to appear NOWHERE in the file,
comments included — same law, gate-clean wording.
2026-10-24 05:09:27 +08:00
araharah-executor 0b8671e9ca test(05-03): add failing guidance-envelope types-only gates (GE1-GE7) (RED)
- GE1 TTL constant === 7200 (~2h, D-06)
- GE2 field freeze: envelope 4 fields / snapshot 6 fields (SessionClaim law)
- GE3 inline snapshot: typed inline, zero snapshotRef tokens in bot/src (D-07)
- GE4 types-only: zero behavior tokens comment-stripped (T-05-08)
- GE5-GE7 negative-space guards: one kv namespace, no Env field, no consumer
  (green by construction — redden only on drift; 05-01 C4/C5/C6 precedent)
2026-10-24 05:08:52 +08:00
araharah-executor 2ee5e4e38b docs(05-01): complete routing workspace plan
- SUMMARY: 3/3 tasks TDD RED->GREEN, 25/25 cases green, 6 commits
- RoutingSource seam + polyline6 codec + fixture backend + loader proof
2026-10-24 05:04:26 +08:00
araharah-executor 3e0c5e3eb4 feat(05-01): geo math + fixture RoutingSource backend + public API
- geo.ts: haversineM + deriveCumulativeDistanceM (D-07 snapped-progress field)
- fixture-source.ts: backend #1 — ORIGIN_TOLERANCE_M=200 matching law,
  honest-null pending semantics (D-03), defensive pair skip at index build,
  lazy memoized index (LAW 1), static JSON import (LAW 2), zero
  logging/storage/network (LAW 3, D-12)
- index.ts: named-export public surface, subpath-with-extension import law
- loader proven in three environments (bare Node 24, esbuild, Vite-family)
2026-10-24 05:03:07 +08:00
araharah-executor 0599ffe14f test(05-01): add failing fixture-source + loader-env suites (F1-F8, L1-L3)
- synthetic injected datasets only — never the network, never the committed file
- F3 pins the 200 m haversine tolerance boundary; F6 the defensive pair skip
- F7 the lazy-index source gate (LAW 1); L2 the esbuild inline marker
2026-10-24 05:02:08 +08:00