docs(04): plan revision 1 — fix wave-1 bundle proof + acceptance-criteria corrections

This commit is contained in:
araharah-executor
2026-10-24 00:02:27 +08:00
parent c0134c7e99
commit 4a83ec6871
5 changed files with 62 additions and 43 deletions
@@ -446,8 +446,8 @@ When `origin` is empty or blank: skip the OPEN button, send the card with the al
- `grep -c '/cari — ' bot/src/i18n/strings.ts | head -1` returns 2 (the /cari helpMenu line in BOTH locales — the " — " marker is load-bearing for `menuEntries` AND `menuFor`)
- `node --input-type=module -e "const {strings}=await import('./bot/src/i18n/strings.ts'); const en=Object.keys(strings.en).sort(), ms=Object.keys(strings.ms).sort(); if(JSON.stringify(en)!==JSON.stringify(ms)) throw new Error('locale key-sets differ'); if(!strings.ms.searchNoMatch||strings.ms.searchNoMatch===strings.en.searchNoMatch) throw new Error('ms refusal copy untranslated'); if(strings.en.osmAttribution!=='© OpenStreetMap contributors') throw new Error('attribution'); console.log('strings OK')"` exits 0 (CS1's locale parity holds with the new fields)
- `grep -q 'export function registerCari' bot/src/bot/commands/cari.ts` exits 0 AND `grep -q 'bot.command("cari"' bot/src/bot/commands/cari.ts` exits 0 AND `grep -q 'bot.command("search"' bot/src/bot/commands/cari.ts` exits 0 (D-01's /cari plus its bilingual twin)
- `grep -c 'pergi_ke' bot/src/bot/commands/cari.ts | head -1` returns 0 (`/pergi_ke` stays reserved for Phase 5 — D-01)
- `grep -q 'replyWithVenue' bot/src/bot/commands/cari.ts` exits 0 AND `grep -c 'ctx.reply(' bot/src/bot/commands/cari.ts | head -1` is <= 2 (exactly ONE venue send for the card; the other `ctx.reply` calls are the refusal/usage lines)
- `grep -c 'bot\.command("pergi_ke"' bot/src/bot/commands/cari.ts | head -1` returns 0 (`/pergi_ke` stays UNREGISTERED — reserved for Phase 5, D-01; the header comment may still document the reservation, so the ban is on the registration shape, not the token)
- `grep -q 'replyWithVenue' bot/src/bot/commands/cari.ts` exits 0 AND `grep -c 'replyWithVenue' bot/src/bot/commands/cari.ts | head -1` returns 1 (exactly ONE venue send builds the card) AND `grep -c 'ctx.reply(' bot/src/bot/commands/cari.ts | head -1` returns 3 (the THREE plain-reply sites: empty-query usage, over-cap, no-match)
- `grep -q 'MAX_QUERY_CHARS = 128' bot/src/bot/commands/cari.ts` exits 0 (V5's length cap)
- `grep -q 'MINI_APP_URL' bot/src/config.ts` exits 0 AND `grep -q 'MINI_APP_URL' bot/wrangler.jsonc` exits 0 AND `grep -q 'MINI_APP_URL' bot/.dev.vars.example` exits 0 AND `grep -q 'MINI_APP_URL' docs/CONFIGURATION.md` exits 0 (the public origin is configured, documented in code, in the example file, and in the configuration docs)
- `grep -q '"vars"' bot/wrangler.jsonc` exits 0 (the origin is a var, NOT a secret)
@@ -531,7 +531,7 @@ Update the file's header comment to name the two new surfaces and D-01/D-02/D-10
**Acceptance:** `npm run bot:typecheck` exits 0. `npm test -w bot` will still FAIL on CS4/CS5/CS6 until task 3 updates them — that is expected and is task 3's job.
</action>
<verify>
<automated>cd /home/C-Fu/araharah && npm run bot:typecheck 2>&1 | tail -10 ; grep -c 'answerCallbackQuery' bot/src/bot/handlers/search-alternate.ts ; grep -c 'registerCari\|registerSearchAlternate' bot/src/bot/bot.ts ; npm test -w bot 2>&1 | tail -6</automated>
<automated>cd /home/C-Fu/araharah && npm run bot:typecheck 2>&1 | tail -10 ; grep -c 'answerCallbackQuery' bot/src/bot/handlers/search-alternate.ts ; grep -c 'registerCari\|registerSearchAlternate' bot/src/bot/bot.ts ; npm test -w bot 2>&1 | tail -6 ; cd bot && npx wrangler deploy --dry-run --outdir /tmp/opencode/araharah-worker-dryrun 2>&1 | tail -3 ; grep -rl 'suria-klcc' /tmp/opencode/araharah-worker-dryrun/ | wc -l</automated>
</verify>
<acceptance_criteria>
- `npm run bot:typecheck` exits 0
@@ -544,6 +544,7 @@ Update the file's header comment to name the two new surfaces and D-01/D-02/D-10
- `grep -q 'export async function sendVenueCard' bot/src/bot/handlers/search-alternate.ts` exits 0 AND `grep -q 'sendVenueCard' bot/src/bot/commands/cari.ts` exits 0 (ONE card builder, two callers — the first card and the swapped card are structurally identical)
- `grep -q 'registerCari' bot/src/bot/bot.ts` exits 0 AND `grep -q 'registerSearchAlternate' bot/src/bot/bot.ts` exits 0 (both surfaces are wired into the factory)
- `grep -c 'createGazetteerSource()' bot/src/bot/bot.ts | head -1` returns 1 (ONE source instance shared by both registrations — a single memoized index)
- `cd bot && npx wrangler deploy --dry-run --outdir /tmp/opencode/araharah-worker-dryrun` exits 0 AND `grep -rl 'suria-klcc' /tmp/opencode/araharah-worker-dryrun/ | wc -l` returns >= 1 (the Worker bundle INLINES the gazetteer now that `bot.ts` imports `createGazetteerSource()` — this completes the L3 bundle-marker half deferred from plan 04-01, where no bot source imported the module yet)
- `grep -q 'replyWithVenue' bot/src/bot/handlers/search-alternate.ts` exits 0 AND `grep -c 'editMessageText' bot/src/bot/handlers/search-alternate.ts | head -1` returns 0 (the swap sends a NEW card; `editMessageText` would destroy the venue payload)
</acceptance_criteria>
<done>The alternates surface is live: a scoped `alt:` callback matcher that answers within 30 s, validates the id before lookup, swaps the card with a new venue message through the ONE shared card builder, and a catch-all that answers every other callback so Telegram never shows a spinner.</done>
@@ -644,7 +645,7 @@ function stripComments(src) {
- `npm test -w web` green (unaffected by this plan)
- `grep -rl 'createHmac\|crypto\.subtle' bot/src/bot/commands/cari.ts bot/src/bot/handlers/search-alternate.ts` returns NOTHING — the deep-link path carries no crypto (D-11)
- `grep -v '^\s*\*\|^\s*//\|^/\*\|^\s*$' bot/src/bot/commands/cari.ts | grep -o 'console\.log("[^"]*"' | grep -v '\[search\] rejected: [a-z-]*"' | wc -l` returns 0 — every log line is a category-only literal (D-15)
- `grep -c 'pergi_ke' bot/src/bot/commands/cari.ts bot/scripts/register-commands.mjs | head -1` returns 0 for both files — the Phase-5 command stays reserved (D-01)
- `grep -c 'bot\.command("pergi_ke"' bot/src/bot/commands/cari.ts | head -1` returns 0 AND `grep -c 'pergi_ke' bot/scripts/register-commands.mjs | head -1` returns 0 — the Phase-5 command stays unregistered (D-01; cari.ts's ban is on the registration shape, since its header comment documents the reservation)
- `grep -q 'MINI_APP_URL' docs/CONFIGURATION.md` exits 0 — the new configuration value is documented where a maintainer looks
</verification>