- guide wait mode: the ARAHARAH-GUIDE state-token race (expectGuide
on_route|rerouting) + DOM text polls + the PX-02 theme-slot honesty
check + the D-15 coordinate-hygiene scan over the WHOLE leg's console
(assertNoCoordinateLines — state tokens only, never coordinates)
- the engine-A-shaped /api/route stub (per-leg Playwright interception,
installed pre-goto): POST #1 = the consult — the drive model built
from the committed fixture corpus + the drive's recorded maneuver
indices + street names snapToGraph'd off the LOCAL road graph (the
road the turn puts you on); later POSTs = reroutes — the merge model
held 5s so the calm REROUTING window is photographable; the REAL
http-source validation still runs on every answer
- legs 14-19 per the UI-SPEC capture table: active (banner slots +
compact strip + card + progressbar + LIST default), list (scripted
banner tap -> CLOSE + NEXT row lamp), rerouting (calm copy + dash +
gantry + NO functional-red computed colors), confirm (bottom register
+ both CTAs + no red), tripend (center card + deletion clause + chrome
cleared + strip returned), dark (matte-black chassis constant)
- leg 20: guidance-gallery-compare.png vs active_route_guidance/screen.png
(the composer generalized with mockup params; legs 8/13 unchanged)
- prior 13 legs unbroken: 20/20 non-blank captures
- ?drive=<name> replaces navigator.geolocation with a replay source
streaming a committed drive fixture (web/test/fixtures/drives/*.json)
through the LIVE shell: the real pump arms the real
createGuidanceWatch against it — no test-only bypass of validation
- the replay clock starts lazily at the first watchPosition arm (the
route draw — nothing emitted before a consumer exists) and plays
REAL-TIME: the machine's grace/storm clocks read wall time
- window.__ARAHARAH_DRIVE = { pause(), resume(), name }: pause freezes
emission mid-stream (the capture legs' freeze for scripted taps and
the REROUTING window), resume continues; the machine's wall clock
keeps running across a pause (documented harness semantics)
- unknown drive name -> one honest token (ARAHARAH-DRIVE
state=unknown) + the default geolocation stays — never a crash,
never arbitrary data (T-06-08 Tampering mitigation); slug guard on
the name, defensive fixture shape check
- import.meta.glob pattern is ROOT-ABSOLUTE (/test/fixtures/drives/*.json
— Vite 8's importGlob matches no relative pattern escaping src/,
verified by the dev-server probe); fixtures inline into the harness
bundle only — production tree-shake verified clean in BOTH directions
- BA5 posture held: production scan clean, harness bundle carries the
replay; 147/147 web tests, typecheck clean
- a fix arriving while the abandon confirm is open rebuilt the guidance
card over it (the ONE PX-03 exit guard evaporating mid-decision); the
pump now re-renders banner/list only and the confirm surface survives
until CONTINUE or YES, ABANDON
- G7b pins it: confirm mounts -> live fix -> confirm still shown,
guidancePhase=confirm holds, YES ABANDON still tears down
- found while building 06-08's scripted END TRIP capture leg; the real
drive's step 6 (END TRIP on a live road) would have hit this within one
watch fix
- routing/scripts/build-glyphs.mjs: maintainer shell (Usage/Exit codes/
collect-then-write — a missing/invalid source exits 1 with the kind named
and nothing written); recolors currentColor → #EB8008 in-memory and
injects a full-bleed #1A1A1A plate (stroke="none" — it must not inherit
the root's orange stroke); the committed SVGs are THE single source and
stay untouched
- sharp 0.35.5 as a routing devDependency (maintainer-only, zero runtime
deps); 'glyphs' script added
- 8× 256×256 PNGs committed (web/public/glyphs/) — the chat turn-card's
sendPhoto URL rides the Worker's static handler; two render bugs fixed
en route: density multiplied the explicit size attrs into 2048² (dropped),
and the plate inherited the root stroke (orange frame — stroke="none")
- SVG sources verified unchanged after the run
- route.ts: onDeactivated POSTs the FROZEN six-field snapshot with
keepalive (the minimize race's belt) and stores the server-minted id;
onActivated DELETEs (the cron pauses — structural) and RETAINS the id;
teardown's deleteEnvelope completes the idempotent pair; a live
envelope is never double-minted; best-effort honesty throughout (D-13)
- resume(trip): the controller computes the projection from
startedAtSec + avg speed (the cron's own math, one formula), renders
GUIDE // RESUMING + gantry + projected card, draws the rebuilt line,
arms the watch, DELETEs immediately (a resumed boot is foregrounded),
and seeds the session mid-route on the first fix through the machine's
own resuming path — synthesized terminal marks keep the arrive mark at
the line's END (a steps-less envelope model would instantly arrive)
- backAction(): the PX-01 resolver's single authority — driving →
confirm, confirm → CONTINUE, ended/route → the walk, root → close
- guidance.ts: resumingView keeps the progress math in guidance/ (RS6)
- main.ts: the COMPOSED LADDER (engine-a first, fixture fallback —
code-constructed, zero env reads), the ?g= UUID-validated reader with
the defensive envelope validation (fail-honest → honest boot), the
capability-guarded activated/deactivated wiring, the recenter
re-lock at the guidance pose, the chain-fix camera skip while driving,
and the no-double-consult resume guard
- merged suite: G9-G12 + the E-family (co-executor tests reconciled:
pre-gate probe, builder-format asserts, terminal-mark fixture)
— 146 passed, typecheck clean
- G9 minimize POST: EXACTLY the frozen six-field snapshot (id/chat_id/
created_at are server-minted), keepalive:true (the minimize race),
the Bearer header; a live envelope is never double-minted
- G10 DELETE with the stored id on activated (the cron pauses —
structural) AND at teardown (the D-14 active sweep, idempotent)
- G11 ?g= resume: GUIDE // RESUMING + gantry + projected numbers, the
watch armed, the line drawn; the first fix flips live ON_ROUTE through
the machine's own resuming path; the ?g= envelope deletes at teardown
- G12 main.ts composition gate: createHttpRoutingSource + the
'?? (await' ladder, the UUID-validated ?g= carrier, the
activated/deactivated wiring, the guidance-aware camera pose, the
no-double-consult guard, zero env reads
- route.ts grows the pump beside the Phase 5 graph: the injected watch arms
with the route draw; the first fix opens the 06-02 session; the start
gate (>= GUIDANCE_START_ALONG_M along) activates the cockpit — PX-03
close protection, [data-guidance=active], banner + card + list, camera
eased to the SNAPPED line, state=on_route token
- effects dispatch: haptics via fireHaptic, reroute-requested through the
injected RoutingSource (fail-honest catch; success = setData snap-in with
NO camera jump + list re-render; failure = calm NO REROUTE + card state
line); arrival -> the D-14 teardown (watch stop, protection release,
chrome clear, trip-end card center)
- END TRIP/BackButton -> the ONE confirm card; YES ABANDON = same teardown;
CONTINUE dismisses with guidance alive; guidancePhase exposes
none/driving/confirm/ended for the PX-01 resolver; walkBack refuses
while the confirm owns the exit and vacates the route stack on the walk
- guidanceView (guidance.ts): banner/card/list view data composed beside
the machine's own maneuver marks — route/ imports and calls it, never
re-derives (the RS6 re-pin's boundary; zero banned tokens in route/)
- G1-G8 green; RS6/RS8 re-pins green; 137 passed, typecheck clean
- G1 activation gate: sub-threshold fix keeps the Phase 5 route state;
a fix >= 30 m along mounts the cockpit (data-guidance, close protection,
banner + card, the locked camera pose, state=on_route token)
- G2 pump updates: banner distance/street from the model, ETA card,
stepping progress bar (pct = alongM/totalM)
- G3 no premature signal during the OFF_ROUTE grace; G4 REROUTING calm
swap + dash + gantry with exactly ONE source.route call under the storm
guard; G5 pending precondition + NO REROUTE fail-honest degradation;
G6 reroute success = setData snap-in, NO camera jump, gantry stop
- G7 END TRIP -> confirm -> YES ABANDON teardown (watch stop, protection
release, trip-end card, state=ended); CONTINUE dismisses, guidance alive
- G8 arrival runs the same teardown from the machine's arrival effect
- RS6 re-pinned: banned tokens only on ../guidance/ import lines (guidance
IMPLEMENTATION lives in web/src/guidance/); RS8 re-pinned: the
ARAHARAH-GUIDE token family joins the console discipline
- guidance/camera.ts: GUIDANCE_CAMERA_PADDING {320,64,64,64} / ZOOM 16 /
EASE_MS 400 / PITCH 35; easeToSnapped rides the follow controller (ONE
easing discipline) and never passes bearing — north-up, recorded call;
onRerouteApplied is the documented camera no-op (setData lives in the
route layer)
- map/follow.ts: follow(point, opts?) pose overrides spread over the
Phase 3/5 defaults — no-opts calls stay byte-identical (RS13); the
re-lock announces the mode (the recenter notch's return signal, RS12);
the originalEvent unlock law untouched
- telegram/backbutton.ts: BackAction resolver ({hidden|close|callback})
consulted per click + wire.sync() visibility re-apply (visible iff
actionable); the legacy (hasOverlay, walkBack) shape composes internally
so Phase 5 call sites and RS7 stay valid; close() only at the true root
- RS7b: the context-aware BackButton resolver walks search → routes →
guidance → (confirm) → routes → search; close() NEVER fires from a
pushed state; the wire exposes sync() for state changes
- RS11: GUIDANCE_CAMERA_PADDING/{ZOOM,EASE_MS,CAMERA_PITCH} pinned at the
UI-SPEC pose; bearing key NEVER present; onRerouteApplied moves nothing
- RS12: programmatic moves never unlock follow; a user movestart
(originalEvent) unlocks — Phase 3 free state returns
- RS13: follow(fix) without opts stays byte-identical (no pitch/zoom keys)
- fakeMap grows flyTo/on/emit recording; suite header documents the RS6/RS8
re-pins landing with the guidance wiring (tasks 2-3)
- buildGuidanceCard: GUIDE register, verbatim headline, live telemetry row (MIN / {km} KM / ETA), 4px progressbar with full aria value set + instant inline width, no-reroute state line only when degrading, ONE btn-secondary END TRIP
- buildConfirmCard: GUIDE // CONFIRM + exact en/ms privacy copy, btn-primary YES ABANDON + btn-secondary CONTINUE, guide-confirm bottom-register hook — the ONE primary CTA in guidance chrome
- buildTripEndCard: GUIDE // END, exact deletion copy, no actions
- shell.css guidance block: banner chassis + 1px separator, CSS-only strip compaction under [data-guidance], list panel + row states + lamp, progress bar — token vars only, zero motion/depth/radius/hex (theme audit clean)
- 8 hand-authored 32x32 SVGs per the UI-SPEC geometry table (3px stroke, square caps, orthogonal/45° only; uturn = machined staple, no arc)
- glyphs.ts: GLYPH_KINDS/GLYPHS via Vite ?raw (committed files are the single source) + svgHost — the ONE sanctioned innerHTML site, a static import value
- strings.ts: 18 ShellStrings keys appended in en + ms, values verbatim from the 06-UI-SPEC copywriting contract
- copy-gate: COPY1 floor 40→58 + COPY8 pins all 18 guidance keys verbatim in both locales
- 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
- 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)
- 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
- 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)
- 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
- 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
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).
- 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
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).