- 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
- 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
- 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)
- 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)
- commands.test.mjs: commandSources gains commands/cari.ts; CS4 documents
the SECOND inline-keyboard carve (venue card allowed, reply keyboard
still banned in commands/); CS5 menu becomes help/privacy/cari; CS5b's
future-stub ban narrows to /pergi_ke (reserved for Phase 5, D-01); CS6
registers cari+search in the alias set
- cari.test.mjs NEW: CR1-CR15 — payload shapes captured through the real
createBot + fake baseFetch (getMe included), plus source-introspection
gates with the stripComments helper: venue fields, OPEN URL = configured
origin + plain slug id, NO-CRYPTO law (D-11), one-message alternates,
callback_data discipline, honest refusal, 128-char cap, always-answer,
category-only logging (D-15), bilingual copy, registration script, swap
semantics, hostile-id drop
- register-commands.mjs: menu list gains cari (two fetch calls unchanged)
- [Rule 1] location-fallback.ts: the message handler now passes non-location
messages through (next) — it matched EVERY message and silently starved
all downstream message-stage handlers, so /cari never fired through the
real factory; caught by the fake-transport suite
- suites: bot 65/65 (15 CR + 9 CS + all prior), web 33/33, search 57/57,
bot:typecheck green
- kv/location-pin.ts mirrors sessions.ts shape: writePin/getPin/clearPin, key loc:<chat_id> (chat-scoped, claim-derived — never user-id scoped across keys)
- PIN_TTL_SECONDS=300; writePin is the only write path, expirationTtl on the same line referencing the named constant
- getPin is a defensive read: parse guard + shape guard + |lat|<=90 / |lon|<=180 range guard (V5 Input Validation) — corrupt records return null
- privacy.test.mjs: storageModules now scans kv/location-pin.ts, so PG1 (same-line TTL) and PG2 (no persistence-shaped exports) apply automatically
- sessions.ts: mintSession (crypto.randomUUID opaque token, T-02-05), rotate-on-new deletes prior session record via chat pointer (D-07), both puts carry expirationTtl: SESSION_TTL_SECONDS on the call line (PRIV-02)
- SESSION_TTL_SECONDS = 900 pairs the session envelope with the D-13 freshness window
- SessionClaim is exactly D-08: user_id, chat_id, issued_at, language_code — nothing else serializes to storage
- sessions.test.mjs: in-memory KV fake asserting finite expirationTtl on every put; D-08 key-set equality; rotate removes old token; expired-token → null (D-14 class)
- privacy.test.mjs: PG1 same-line expirationTtl source gate (auto-tightens to webhook.ts when plan 03 adds it) + PG2 no persistence-shaped exports
- 18/18 PASS across initdata + sessions + privacy suites; full plan GREEN