Commit Graph
38 Commits
Author SHA1 Message Date
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 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 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 9ae2059432 fix(shell): card body padding — text sat at card edges (device-gate feedback) 2026-10-24 04:12:19 +08:00
araharah-executor 135621f007 feat(04-04): /start carries the araharah logo (static-asset URL, resilient text fallback) + repo icon assets 2026-10-24 02:57:39 +08:00
araharah-executor cbe433fef1 feat(04-04): map tilt (pitch 35) + runtime building extrusion reusing style-owned colors — device-gate feedback 2026-10-24 02:53:39 +08:00
araharah-executor 747eeb7b34 test(04-04): the BA7/BA8 drift gates + the search-tree GEO3 pin + the destination-preload capture leg
- BA7: the shipped JS must carry EVERY committed gazetteer id (the
  web half of bot/web id-set parity, T-04-39) — RED against the
  pre-gazetteer bundle, green after the resolver lands in the build
- BA8: the shipped JS carries NO deep-link crypto (JS assets only —
  the official Telegram SDK is external, D-11/T-04-40)
- no-storage: explicit web/src/search memory-only + no-crypto pin
- capture.mjs: the ARAHARAH-DEST signal race + the 'dest' wait mode
  (state=resolved asserted, then the rendered card's text is waited
  on — the card mounts at live, T-04-42) + the shell-dest-preload
  leg; 8/8 expected captures
2026-10-24 01:38:24 +08:00
araharah-executor c2d78b0c8f feat(04-04): ONBD-03 home-screen hooks + the boot wiring + the ?dest= harness profile
- homescreen.ts: wireHomeScreen behind the BOTH-halves Bot API 8.0
  guard; 'added' hides (no nag), 'unknown' (always iOS) shows the
  neutral prompt — indeterminate, never an error; homeScreenAdded
  hides; a refused addToHomeScreen is caught, the affordance stays;
  .btn-secondary in the existing strip — no new furniture; NO
  beforeinstallprompt/manifest/service worker (T-04-38)
- main.ts: locale derivation moved above the bindings block; stage 13
  reads BOTH destination carriers, seeds the memory-only holder, builds
  the destination/unavailable surface (null when no id — Phase 3 boot
  byte-identical, D-12); the live register shows the destination
  surface; the ARAHARAH-DEST state-token signal fires unconditionally
- index.html: ?dest=<id> harness profile threaded to the mock's
  startParam; the block stays inside __ARAHARAH_HARNESS__
- HS1-HS9 green (54/54), web:typecheck green
2026-10-24 01:36:30 +08:00
araharah-executor 6e421e6b59 test(04-04): RED — the ONBD-03 home-screen gate suite (HS1-HS9)
Capability guard (both halves), the four status branches ('added'
hides, 'unknown' shows with the neutral prompt, 'missed' shows,
'unsupported' nothing), tap → addToHomeScreen, homeScreenAdded →
hidden, and the browser-install-API ban. Suite load fails until
web/src/telegram/homescreen.ts exists (RED verified: 45 passed,
1 failed suite-load).
2026-10-24 01:34:44 +08:00
araharah-executor 4f958411f3 feat(04-04): the destination resolver — two carriers, one validation, memory only
- resolve-destination.ts: reads ?dest= (URL, primary — the inline
  web_app-button carrier) then initData's start_param (the signed
  string, secondary — the direct-link/home-screen carrier), ONE
  slug validation, dest_ prefix stripped; resolves against the
  webview's own build-time @araharah/search copy; honest null for
  unknown ids; module-scope memory-only holder (GEO-03/D-07)
- destination-card.ts: the confirmation + honest-unavailable cards,
  createElement/textContent only, existing theme classes (T-04-32)
- webapp.ts: TelegramWebAppLike gains startParam, addToHomeScreen?,
  checkHomeScreenStatus? + HomeScreenStatus (Bot API 8.0+ members)
- telegram-mock.ts: satisfies the extended contract in the same
  change (startParam initData wiring, homeScreenStatus, __homeScreenAdded)
- strings.ts: 5 new copy fields in en+ms; web depends on @araharah/search
- DP1-DP12 green (45/45 web suite), web:typecheck green
2026-10-24 01:33:56 +08:00
araharah-executor 3e3d1917e6 test(04-04): RED — the ONBD-02 destination-preload gate suite (DP1-DP12)
Two carriers, one validation, memory-only resolution against the
webview's own build-time gazetteer copy. Suite load fails until
web/src/search/resolve-destination.ts exists (RED verified: 33 passed,
1 failed suite-load).
2026-10-24 01:31:56 +08:00
araharah-executor 91ad0c9d93 docs: generate + verify project documentation — canonical docs, per-package READMEs, verified fix pass
- New: docs/ARCHITECTURE.md, docs/GETTING-STARTED.md, docs/DEVELOPMENT.md,
  docs/TESTING.md, docs/CONFIGURATION.md (colored mermaid diagrams, quoted labels)
- Regenerated README.md (arah² / arah2bot naming, canonical clone URL)
- New per-package READMEs: theme/, bot/, web/
- Verified 13 docs against the live codebase (2 fix iterations + 2 residual
  corrections); corrected 56 stale claims across AGENTS/DESIGN/IDEAS/GSD_FIX
2026-10-23 20:56:40 +08:00
araharah-executor af3edefbc6 add sume 2026-10-23 19:18:43 +08:00
araharah-executor 8a5c8b415f fix(03-04): GEO-03 probe platform allowlist — official telegram-web-app.js writes one sessionStorage bookkeeping key; app surfaces stay empty 2026-10-23 18:52:59 +08:00
araharah-executor fc99745672 chore(03-04): remove the device-matrix diagnostic probe — exit obligation, matrix passed 2026-10-23 18:41:41 +08:00
araharah-executor 19a51e5882 fix(03-04): LOCATION SETTINGS CTA version-gated 8.0+ — hides the no-op off-Telegram (Chrome SDK stub reports 6.0) 2026-10-23 01:43:34 +08:00
araharah-executor f4453996ac fix(03-04): on-screen diagnostic probe — WA version/platform, initData char-count, session + location categories 2026-10-23 01:24:52 +08:00
araharah-executor 38ce59b1ca fix(03-04): LOCATION SETTINGS CTA on the denied card (was only on awaiting-pin instance — patch-order bug) 2026-10-23 01:19:10 +08:00
araharah-executor 3793741d2f fix(03-04): load telegram-web-app.js in head — production WebApp was never defined (no initData, no LocationManager, no BackButton) 2026-10-23 01:14:27 +08:00
araharah-executor 9fa4acb319 fix(03-04): Telegram LocationManager deep-link — LOCATION SETTINGS CTA on denied cards + locationManagerUpdated chain re-run 2026-10-23 01:06:52 +08:00
araharah-executor b1d8768866 fix(03-04): web_app menu button on deployed origin + wire CTA actions on both denied-shaped cards 2026-10-23 01:00:27 +08:00
araharah-executor 5c155e393d feat(03-04): Mock-Telegram runner page + Playwright capture harness — 7/7 captures + GEO-03 probe
- runner page: ?mock/?scheme/?pin/?locale profile block wholly inside if (__ARAHARAH_HARNESS__) — installer + /api/session + /api/location + /api/location-fallback fetch stubs dead-code-eliminated from production; main.ts import stays outside the guard
- harness-only ?sessiondelay/?fixdelay boot-stage photograph knobs (localhost resolves the chain in ms — staged BOOT-01/BOOT-02 cards need a hold)
- capture.mjs extends theme/scripts/screenshot.mjs: MIN_BYTES, WR-05 docroot guard, READY-signal race, dist-harness docroot, DENIED_LEG_TIMEOUT_MS=90000 for LINK 3's 60s pre-denial poll, timeout = hard failure with a signal diagnostic
- 7 captures: boot-1/boot-2 stages, live light+dark (theme-slot attribute asserted), Desktop denied card w/ ASK VIA CHAT, chat-pin relay LIVE, DSGN-02 side-by-side vs navigate_map_overview
- GEO-03 runtime probe: localStorage/sessionStorage/cookies/IndexedDB asserted empty after boot-to-live
- mock fixes (Rule 1): LocationManager delivery now uses the Telegram wire shape {latitude,longitude,horizontal_accuracy,course} (authoring shape mapped to undefined → NaN LngLat pageerror); languageCode→initData so localeFromInitData parses the real wire format

CAPTURE OK — 7/7 non-blank captures; GEO-03 probe PASSED
2026-10-23 00:37:58 +08:00
araharah-executor 8b39ea70c3 feat(03-04): Worker [assets] binding + one-command deploy + D-14 build-artifact gate
- wrangler.jsonc assets block serves ../web/dist; run_worker_first keeps /api/* + /telegram/* on the Worker (D-13)
- root npm run deploy = build theme → web → bot wrangler deploy + set-webhook (D-15); dev = build + wrangler dev --port 8787 --local (D-12)
- vite.config.ts dual-build: __ARAHARAH_HARNESS__ define keyed on --mode harness, separate dist/dist-harness outDirs
- main.ts guard unchanged; ambient constant declared once in web/src/vite-env.d.ts
- build-artifact.test.mjs BA1..BA6: zero CDN refs, self-hosted fonts, MapLibre worker, inlined style, no mock installer in ANY emitted file (HTML included)
2026-10-23 00:15:26 +08:00
araharah-executor d573acc583 feat(03-03): status strip, state cards, recenter control, boot choreography — map-first, D-09 staged states
- strip.ts: six-state lamp+word left cluster, ±M / FIX Ns AGO telemetry (U+00B1 glyph), elapsed-seconds for acquiring
- cards.ts: boot/denied/lost builders from theme classes, machine-blink gantry (500ms JS duty cycle), GEO/SYS registers from strings.ts, D-06 CTA inversion (chat-fallback=btn-primary, retry=btn-secondary)
- recenter.ts: 40x40 plate w/ >=44 hit slop, orthogonal inline-SVG crosshair, three data-attribute notch states, no inline handlers
- main.ts: boot order map->session->chain (bootMap before acquireFix), null-map guards on every map consumer, ARAHARAH-LIVE emitted outside the guard, data-map=absent fallback, localeFromInitData, ASK VIA CHAT w/ D-03 revalidation, 1s tick re-running the chain at 45s staleness
- map.ts: attribution control moved bottom-left (UI-SPEC flush chip, compact)
- shell.css: attrib chip #map-scoped override (wins cascade over maplibre css), strip left cluster, recenter z-index
- vite.config.ts: define __ARAHARAH_HARNESS__ keyed on --mode harness (bare ambient global would ReferenceError in plain dev; Rule 3)
- session.test.mjs: SESS1-4 memory-token gates
2026-10-23 00:08:34 +08:00
araharah-executor c437d312f6 feat(03-03): Rams shell stylesheet + MapLibre v6 bootstrap, position marker, follow controller
- shell.css: token-only chrome (zero hex, zero transition/animation), dark-slot activation, machined geometry (8px lamp/notch, 40x40 plate, data-map=absent field)
- map.ts: setWorkerUrl + ?worker&url, build-time-inlined liberty-rams.json, GPUInitializationError -> null gate, RAMS-BASEMAP-READY signal
- marker.ts: dot + accuracy circle (100m display cap) + heading cone hidden on null, DOM Marker SVG namespace discipline
- follow.ts: 96px camera padding, 400ms flyTo, user-gesture-only free mode
- UI-SPEC: planner amendments verified (Pitfall 4 present; Open Question 1 appended)
2026-10-22 23:53:18 +08:00
araharah-executor 83985c4a09 feat(03-03): copy module — UI-SPEC table verbatim (en+ms) + COPY1..6 copy gate
- web/src/i18n/strings.ts: 25-key ShellStrings, pickLocale verbatim from bot, localeFromInitData over the raw initData string (RESEARCH §Security V2)
- web/test/copy-gate.test.mjs: parity, content, fallback, no-inline-copy source-introspection (comments stripped), initData locale derivation
2026-10-22 23:51:05 +08:00
araharah-executor 2659b7f352 feat(03-02): D-11 Mock-Telegram harness + the four requirement gates (17 cases green)
- telegram-mock.ts: fake window.Telegram.WebApp injected into the SAME window
  (never an iframe — Bot API 10.2 origin restriction, Pitfall 6); Web-Crypto
  dev signer mirroring bot/src/security/initdata.ts's two-step HMAC (async
  makeDevInitData — node:crypto stays out of the browser bundle path);
  controllable LocationManager stream, themeChanged emitter, BackButton clicks
- location-chain.test.mjs (10 cases): GEO-01 version gate / null-WebApp guard
  / null-denial / hard timeout / stale-detector + one-read nudge; GEO-02 pin
  pickup / bounded 60s poll / Desktop no-geolocation leg ' same denial keys
- no-storage.test.mjs (3 cases): GEO-03 comment-stripped grep gate over
  web/src/**/*.{ts,html}, no-SW invariant, store.ts storage-assignment probe
- theme.test.mjs (4 cases): PX-02 colorScheme + luminance fallback + setStyle
  source-introspection (Pitfall 7) + themeChanged re-apply; document stub
  installed and restored per case
- Rule 1 fix in telegram.ts: looksStale/nudgeAndRetryTelegram accept an
  omitted lastAccepted (undefined normalized to null) ' acquireFix(deps)
  first-call contract
2026-10-22 23:46:17 +08:00
araharah-executor 0a35bce256 feat(03-02): Telegram platform wrappers — theme slot switch, BackButton total wire, safe-area union
- theme.ts: colorScheme → data-tg-theme on <html>; header_bg_color 0-1 luminance fallback
  (T-03-11 — Telegram hex is a signal, never a consumed CSS value); applyTheme's ONLY
  statement is the attribute set (Pitfall 7 / D-10, greppable invariant)
- backbutton.ts: hide() at init (one shell state), onClick is total — close() at the root,
  no dead-ends (UI-SPEC §BackButton)
- safe-area.ts: env(safe-area-inset-*) probe ∪ WebApp.safeAreaInset, per-edge max,
  version-gated at 8.0, applied as --safe-* custom properties on :root
- webapp.ts + backbutton/safe-area never read node_modules types;
  @types/telegram-web-app stays dropped (web/package.json untouched)
2026-10-22 23:40:03 +08:00
araharah-executor faab77a84f feat(03-02): D-04 chain state machine + memory-only session store + /api/session client
- chain.ts: acquireFix tries telegram → webview → chat-pin in locked order; staleness
  routes to the nudge inside link 1, never to success (Pitfall 2); pluggable cadence —
  NO setInterval/watchPosition anywhere (Phase 6 picks, Open Question 2)
- isFixStale (45s = UI-SPEC signal-lost trigger) + fixAgeSeconds for FIX Ns AGO telemetry
- store.ts: module-scope token holder, zero persistence calls (the D-07 invariant);
  SESSION_TTL_SECONDS = 900 mirrors bot/src/kv/sessions.ts by name (D-03)
- client.ts: posts VERBATIM initData as the body, validates token shape, maps 401
  categories exactly (malformed/tampered/stale/network)
2026-10-22 23:39:16 +08:00
araharah-executor 9552e7e4ab feat(03-02): Fix type + three source adapters (telegram/webview/chat-pin) — GEO-01 wrappers
- types.ts: the shared Fix shape + LocationState machine (type-only, D-04/D-05/D-07)
- telegram.ts: version-gated LocationManager init/getLocation, hard 8s timeout (Pitfall 3),
  null-safe telegramLocationSupported (plain browser/Desktop = false, not TypeError),
  looksStale + haversine + the Android nudge (issue #56 navbar read DISCARDED, then retry)
- webview.ts: one-shot geolocation read, maximumAge: 0 (freshness axis), 8s timeout
- chat-pin.ts: bounded 60s poll of GET /api/location (Bearer token) + POST /api/location-fallback
  throw-on-fail so the ASK VIA CHAT handler can revalidate (D-03)
- telegram/webapp.ts created early (Rule 3: task 1 imports TelegramWebAppLike from task 3's
  file; declared the narrow hand-rolled interface now, verbatim per plan)
2026-10-22 23:37:58 +08:00
araharah-executor 9376cabca2 feat(03-01): stand up web/ npm workspace with Wave-0 hand-rolled test runner (D-01, D-02, D-11, D-14)
- web/ workspace: TS + Vite shell (maplibre-gl 6.15.0, vite 8.3.5, TS 5.9.3; no UI framework, no Telegram SDK script tag)
- tsconfig mirrors bot/ strictness byte-for-byte except the three authorized keys (DOM lib, vite/client types, resolveJsonModule)
- test/runner.mjs + harness.mjs copied verbatim from bot/test/ (body-identical past header)
- root package.json: web workspace + web:* delegate scripts
- web/src/main.ts entry module created (tsc include:['src'] needs ≥1 input; 03-02/03-03 mount here)
2026-10-22 23:24:41 +08:00