Files

9.6 KiB
Raw Permalink Blame History

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
05-routing-route-display 03 bot
kv
types-only-contract
guidance-sessions
ttl
envelope
privacy
tdd
source-introspection
phase plan provides
05-routing-route-display 01 the polyline6 storage format the snapshot's geometry field cites by name (routing workspace, 05-01) and the RouteResult summary fields (distanceM/durationS) the snapshot headlines
phase provides
03-mini-app-shell-geolocation the SessionClaim field-freeze law (bot/src/kv/sessions.ts "a 5th property means drift") and the location-pin TTL precedent (bot/src/kv/location-pin.ts) D-07 aligns with
GuidanceSessionEnvelope — the frozen Phase 6 contract: EXACTLY [id, chat_id, route_snapshot, created_at]
GuidanceRouteSnapshot — the INLINE route record (D-07): destinationId/Name, distanceM/durationS, polyline6 geometry, startedAtSec
GUIDANCE_SESSION_TTL_SECONDS = 7200 — the ~2h TTL as a documented constant awaiting its Phase 6 consumer
guidance:<id> key-scheme documentation in the module header
GE1–GE7 — seven mechanical gates pinning the types-only boundary (field freeze, inline snapshot, TTL value, no runtime behavior, no new namespace, no Env field, no premature consumer)
phase-6 guidance turn-card service
bot privacy gates
added patterns
Types-only frozen contract: interface + TTL constant + key-scheme doc, with source-introspection gates proving no runtime shadow (extends the privacy.test.mjs grep-gate family)
Negative-space boundary gates: guards over files that must NOT change are green by construction and redden only on drift (05-01 C4/C5/C6 precedent)
created modified
bot/src/kv/guidance-sessions.ts
bot/test/guidance-envelope.test.mjs
Module header says 'No KV binding' instead of naming the KVNamespace type — the plan's own acceptance gate requires that token to appear NOWHERE in the file, comments included (grep -rc = 0); same law, gate-clean wording
GE5–GE7 (no new namespace / no Env field / no consumer) are RED-green-by-construction boundary guards: they scan files that must NOT change, so they pass before and after this plan and redden only on future drift — documented in the suite header per the 05-01 C4/C5/C6 precedent
Contract-freeze gate naming: GE* gates live in the consuming workspace's test dir and lazy-import the contract module so a missing module is a per-case RED, not a suite load failure
Phase-6 handoff note in gate doc-comments: when the service legitimately adds the binding/field/consumer, updating GE4–GE7 is THAT plan's responsibility
5min 2026-10-23

Phase 5 Plan 3: Guidance-Session Contract Freeze (Types-Only) Summary

The guidance_sessions envelope frozen as a types-only Phase 6 contract — 4-field envelope + inline 6-field route snapshot (D-07: one key, one TTL) + the 7200 s TTL constant + guidance:<id> key scheme, with zero runtime behavior and seven GE gates proving the boundary mechanically.

Performance

  • Duration: 5 min
  • Started: 2026-10-23T21:05:12Z
  • Completed: 2026-10-23T21:09:35Z
  • Tasks: 1/1 (TDD RED→GREEN)
  • Files modified: 2 (both created; zero existing files touched)

Accomplishments

  • The Phase 6 contract exists in code (D-06): GuidanceSessionEnvelope (EXACTLY id, chat_id, route_snapshot, created_at — the SessionClaim field-freeze law) and GuidanceRouteSnapshot (EXACTLY destinationId, destinationName, distanceM, durationS, geometry, startedAtSec), the guidance:<id> key scheme, and GUIDANCE_SESSION_TTL_SECONDS = 7200 — pinned by GE1/GE2 so drift reddens the suite.
  • D-07 is mechanical, not aspirational: route_snapshot: GuidanceRouteSnapshot is typed INLINE (GE3), the tokens snapshotRef/snapshot_ref are banned across all of bot/src, and the TTL law means one key, one expiry — nothing outlives 2h, nothing is reconstructable after expiry.
  • The types-only boundary cannot leak this phase (T-05-08): GE4 comment-strips the module and bans every behavior token (KV binding type, .put(, .get(, .delete(, function exports, imports); GE5 pins wrangler.jsonc to EXACTLY ONE kv namespace (chat_sessions); GE6 pins Env free of any guidance field; GE7 bans any bot/src import of the module — no runtime shadow, no premature consumer.
  • Zero existing bot files modified: wrangler.jsonc and config.ts are untouched; the full bot suite is green at 72/72 (65 pre-existing + 7 GE gates) and bot:typecheck exits 0 (the module sits inside the bot tsconfig's include: ["src"]).

Task Commits

Each gate of the TDD cycle was committed atomically:

  1. task 1: the frozen envelope types + the types-only gate suite
    • 0b8671e test(05-03): add failing guidance-envelope types-only gates (GE1-GE7) (RED)
    • d5c2bc0 feat(05-03): freeze guidance_sessions envelope as types-only contract (GREEN)

Plan metadata: committed separately (docs, force-added — .planning/ is gitignored)

TDD Gate Compliance

  • RED gate: 0b8671e — GE1–GE4 fail on the absent module (ERR_MODULE_NOT_FOUND / ENOENT, verified as the exact failure modes); GE5–GE7 pass as documented green-by-construction boundary guards.
  • GREEN gate: d5c2bc0 — 72/72 pass, typecheck exit 0.
  • REFACTOR gate: not needed — 58 lines of pure types + one constant; nothing to clean.

Files Created/Modified

  • bot/src/kv/guidance-sessions.ts — the frozen contract: module header (types-only law, D-06/D-07 citations, guidance:<id> key scheme), GUIDANCE_SESSION_TTL_SECONDS = 7200, GuidanceRouteSnapshot (6 fields), GuidanceSessionEnvelope (4 fields). No imports, no functions, no class.
  • bot/test/guidance-envelope.test.mjs — GE1–GE7: TTL constant value; interface-body field-freeze regex (^\s{2}\w+: between interface X { and \n}); inline-snapshot type + repo-wide ref-token ban; comment-stripped behavior-token ban (the routing C4 stripComments pattern); comment-stripped JSON.parse of wrangler.jsonc; config.ts token ban; import-statement ban across the recursive bot/src tree.

Decisions Made

  • Header wording: "No KV binding" instead of the KVNamespace type name — the plan's <interfaces> header template contains that literal token, but the plan's own acceptance criterion requires grep -rc 'KvNamespace' to return 0 with "the word never appears" (comments included). The mechanical gate wins; the law stated is identical.
  • GE5–GE7 declared green-by-construction in the RED commit — they are negative-space guards over files that must NOT change, so they cannot fail while the boundary holds (their RED state is vacuous). Mirrors 05-01's C4/C5/C6 zero-laws precedent; documented in both the suite header and the RED commit message.

Deviations from Plan

None — plan executed exactly as written. The two items above are judgment calls inside the plan's own acceptance gates, documented for the verifier.

Known Stubs

None — the module ships types + one constant by design (D-06); nothing flows to UI, nothing consumes it at runtime (GE7 pins that). Phase 6 builds the service on this frozen shape.

Threat Surface Scan

No new surface beyond the plan's <threat_model>: no endpoints, no auth paths, no file access, no schema at a trust boundary — the module has zero runtime behavior. All three register entries have implemented, gate-covered mitigations: T-05-08 (premature persistence → GE4/GE5/GE6/GE7), T-05-08b (retention → GE1 + GE3 inline snapshot), T-05-08c (contract drift → GE2 exact field sets). No threat flags.

Issues Encountered

  • Pre-existing uncommitted working-tree changes to bot/test/cari.test.mjs and bot/test/commands.test.mjs (a prior session's register-commands scope-shadow fix pins) were present at start. Baseline verified green WITH them (65/65) before any of my commits; they were left untouched and excluded from every commit. Out of scope per the plan-boundary rule.
  • Node lives under nvm in this environment — verification commands sourced ~/.nvm/nvm.sh first (the 05-01 precedent). No project impact.

User Setup Required

None — no external service configuration required. The module ships no behavior; nothing deploys.

Next Phase Readiness

  • Phase 6 (backgrounded turn-card service): consumes GuidanceSessionEnvelope / GuidanceRouteSnapshot / GUIDANCE_SESSION_TTL_SECONDS / the guidance:<id> key scheme verbatim — the shape cannot have drifted (GE1/GE2 pin it). Phase 6's plan owns: the KV namespace binding + Env field (relaxing GE5/GE6), the consumer import (relaxing GE7), and extending the PG1 same-line-expirationTtl grep gate to guidance: writes.
  • Phase 5 remaining plans: none depend on this module (depends_on: [], wave: 1); 05-04/05-05 web-side work is unaffected.

Phase: 05-routing-route-display Completed: 2026-10-23

Self-Check: PASSED

  • All 2 created files verified present on disk (guidance-sessions.ts, guidance-envelope.test.mjs).
  • Both plan commits verified in git log (0b8671e RED, d5c2bc0 GREEN).
  • npm test -w bot: 72 passed, 0 failed (PASS GE1…GE7 + all 65 pre-existing cases). npm run bot:typecheck: exit 0.
  • All seven acceptance greps pass on the module (envelope iface, snapshot iface, TTL const, key scheme, KvNamespace count = 0, inline snapshot).
  • Zero existing files modified by this plan; STATE.md and ROADMAP.md untouched (orchestrator-owned writes).