--- phase: 02-bot-skeleton-initdata-security plan: 01 subsystem: infra tags: [telegram, grammy, cloudflare-workers, wrangler, npm-workspaces, typescript, hmac, tdd] # Dependency graph requires: - phase: 01-design-tokens-rams-foundation provides: npm workspace pattern (root delegate scripts + per-workspace package.json) and hand-rolled zero-dep test runner shape (theme/scripts/audit.test.mjs, D-12 precedent) provides: - `bot/` npm workspace (`@araharah/bot`) with grammy ^1.46.0 + wrangler ^4.151.3 + TypeScript ^5.9.3, registry-verified - `bot/src/config.ts` Env contract (BOT_TOKEN, WEBHOOK_SECRET, chat_sessions KVNamespace) consumed by plans 02/03 - `bot/wrangler.jsonc` Worker config with main src/webhook.ts + chat_sessions KV binding (id placeholder → plan 03) - `bot/test/harness.mjs` + `runner.mjs` — D-12 zero-dependency runner, suite-load failures become FAIL cases - `bot/test/initdata.test.mjs` — RED vector suite T1–T7 (contract for plan 02 GREEN) - Secret hygiene baseline: `.gitignore` (.dev.vars, .wrangler/) + `.dev.vars.example` shipped in first commit affects: [02-02 security core (GREEN against this suite), 02-03 commands+KV+deploy, phase 3 mini app shell, phase 5 session envelope] # Tech tracking tech-stack: added: [grammy ^1.46.0, wrangler ^4.151.3, typescript ^5.9.3, @cloudflare/workers-types ^5.20261022.1, @types/node ^26.6.5] patterns: [npm workspace sibling to theme/ with root delegate scripts, hand-rolled registry/runner test harness (D-12), erasable-only TypeScript under type-stripping, RED-first TDD for security gates, secrets as wrangler secrets + gitignored .dev.vars mirror] key-files: created: - bot/package.json - bot/tsconfig.json - bot/wrangler.jsonc - bot/.gitignore - bot/.dev.vars.example - bot/src/config.ts - bot/test/harness.mjs - bot/test/runner.mjs - bot/test/initdata.test.mjs modified: - package.json (workspaces + bot:* delegate scripts) - package-lock.json (bot workspace deps) key-decisions: - "Lazy per-case dynamic import of ../src/security/initdata.ts in the RED suite: each vector reports its own FAIL (8 named FAILs at RED) instead of losing the whole suite to one load error; the suite-load-failure path survives as the runner's crash guard" - "Test-side HMAC signing helper uses node:crypto (two-step Telegram derivation) so the RED suite is provably independent of the SubtleCrypto implementation path plan 02 writes; T7 pins the primitive against the RFC-4231 case-1 vector" patterns-established: - "D-12 harness: import { test } from './harness.mjs' in any bot/test/*.test.mjs; runner auto-discovers, prints PASS/FAIL per case + '[runner] N passed, M failed', exit 0 only when all green" - "Root delegate scripts: bot:test / bot:typecheck / bot:dev / bot:deploy / bot:commands (mirrors Phase 1 build:* pattern)" - "Erasable-only TS in bot/src (no enums/parameter properties/namespaces); tsconfig: strict + noEmit + allowImportingTsExtensions + workers-types" requirements-completed: [ONBD-01, PRIV-01, PRIV-02] # substrate only — D-15/D-17 secret-hygiene + D-12 verification substrate for these reqs; full req delivery lands in plans 02/03 # Metrics duration: 4min completed: 2026-10-22 --- # Phase 2 Plan 1: Bot Workspace Scaffold + RED initdata Vector Suite Summary **`bot/` npm workspace stood up with grammy/wrangler/TS and the D-12 zero-dep test harness, shipping a RED-demonstrated initdata HMAC vector suite (T1–T7, 8 FAILs / exit 1) that plan 02 goes GREEN against** ## Performance - **Duration:** 4 min - **Started:** 2026-10-22T03:35:10Z - **Completed:** 2026-10-22T03:38:23Z - **Tasks:** 2 - **Files modified:** 11 (9 created, 2 modified) ## Accomplishments - `bot/` workspace installs and typechecks clean: grammy@1.46.0 + wrangler@4.151.3 + typescript@5.9.3 landed exactly in ranges pinned by RESEARCH.md (lockfile-verified) - `Env` interface contract (`BOT_TOKEN`, `WEBHOOK_SECRET`, `chat_sessions: KVNamespace`) committed as the type anchor plans 02/03 implement against - Secret hygiene from the first commit: `.gitignore` (.dev.vars, .wrangler/) ships in the same commit as `.dev.vars.example`; `git check-ignore bot/.dev.vars` verified - Hand-rolled runner (D-12) replicates Phase 1's pattern in a second workspace: zero deps, suite-load failures become FAIL cases (never crashes), `[runner] N passed, M failed` summary, exit 1 on any failure - RED vector suite final-contract: T1 known-good, T2 tampered, T3 stale (3600 s), T4 boundary (899 ok / 901 stale), T5 order-independence, T6a–c malformed, T7 RFC-4231 node:crypto independence pin — demonstrated RED with 8 named FAILs against missing `src/security/initdata.ts` ## task Commits Each task was committed atomically: 1. **task 1: bot workspace scaffold with Env contract (D-09/D-10/D-11/D-15)** — `c9b6ba4` (feat) 2. **task 2: Wave 0 harness + RED initdata vector suite (D-12, TDD RED)** — `fc5001a` (test) _Note: task 2 is TDD RED by plan design; the GREEN commit belongs to plan 02 task 1 (wave 2), which will flip this suite from 8 FAILs to all-pass._ ## Files Created/Modified - `package.json` — workspaces `["theme","bot"]` + `bot:*` delegate scripts (theme scripts untouched) - `bot/package.json` — `@araharah/bot` workspace: test/typecheck/dev/deploy/commands scripts, grammy + wrangler/TS deps - `bot/tsconfig.json` — strict ES2023, noEmit, moduleResolution bundler, workers-types, allowImportingTsExtensions - `bot/wrangler.jsonc` — name araharah-bot, `main: src/webhook.ts`, chat_sessions KV binding (id = KV_ID_PLACEHOLDER until plan 03's `wrangler kv namespace create`) - `bot/.gitignore` — exactly `.dev.vars` + `.wrangler/` (D-15/D-17) - `bot/.dev.vars.example` — shape only (BOT_TOKEN=, WEBHOOK_SECRET=, WEBHOOK_URL=), no values - `bot/src/config.ts` — `export interface Env` + KVNamespace member (contract only, no implementation) - `bot/test/harness.mjs` — zero-dep registry: `test(name, fn)` / `registry` - `bot/test/runner.mjs` — D-12 runner: sorted `*.test.mjs` discovery, suite-load error → stored FAIL case, PASS/FAIL + summary + exit codes - `bot/test/initdata.test.mjs` — vector suite T1–T7; signing helper in-file via node:crypto; fixtures in-process - `package-lock.json` — bot workspace dep tree (grammy 1.46.0, wrangler 4.151.3 pinned) ## Decisions Made - **Lazy per-case validator import in the RED suite:** the plan allowed either "suite load failed" or per-case FAILs; per-case chosen so RED shows each vector's own failure (and plan 02's GREEN progress will be visible per-vector) - **Test-side signing via node:crypto (not SubtleCrypto):** keeps the RED suite's expected-hash path independent of the implementation path under test; T7's RFC-4231 pin makes that independence a guarded invariant ## Deviations from Plan None - plan executed exactly as written. (T6 was split into T6a/T6b/T6c named cases within the plan's single T6 bullet — this stays within the documented contract and yields ≥7 independent FAILs at RED.) ## Issues Encountered - Verified at execution start that Node 24.18.0 dynamic-imports `.ts` modules from `.mjs` natively (probe in /tmp/opencode/) — no `--experimental-strip-types` flag needed, confirming the runner + type-test design works without tooling changes - npm emitted allow-scripts warnings for esbuild/workerd/@parcel/watcher install scripts (self-hosted toolchain hygiene; unrelated to this plan — dev-only tooling, noted for awareness, no action taken per scope boundary) ## User Setup Required None for this plan. (Real secrets — BOT_TOKEN / WEBHOOK_SECRET / Cloudflare account — are only needed at plan 03's deploy checkpoint, per D-15/D-16.) ## Next Phase Readiness - Plans 02/03 can implement against `bot/src/config.ts` Env + `bot/wrangler.jsonc` entry points; `npm test -w bot` and `npm run bot:typecheck` are the wave verification commands - Plan 02 task 1 must make `bot/test/initdata.test.mjs` GREEN (implement `src/security/initdata.ts` per the T1–T7 contract) - Plan 03 task 1 fills the real KV namespace id into `bot/wrangler.jsonc` (replace `KV_ID_PLACEHOLDER`) ## Self-Check: PASSED - All 9 created files verified present on disk (bot/ tree + test files) - Commits verified in history: `c9b6ba4` (feat task 1), `fc5001a` (test task 2 RED) - `git check-ignore bot/.dev.vars` → ignored (secret hygiene confirmed) - STATE.md / ROADMAP.md untouched by this agent (ROADMAP.md's pre-existing modification belongs to the orchestrator) --- *Phase: 02-bot-skeleton-initdata-security* *Completed: 2026-10-22*