Files
archy/.planning/phases/09-botfights-platform-upgrade/09-03-SUMMARY.md
T

189 lines
15 KiB
Markdown

---
phase: 09-botfights-platform-upgrade
plan: 03
subsystem: docs
tags: [hono, vue3, markdown, ai-prompt, api-docs]
# Dependency graph
requires: []
provides:
- "One consolidated, self-contained AI bot-setup prompt (frontend/public/docs/BOTFIGHTS.md)"
- "GET /api/docs/prompt serving that prompt as text/markdown with {{ARENA_URL}} resolved"
- "Every in-app setup surface (JoinBoutPage, BotProfilePage, DocsPage) pointed at the one prompt"
affects: [09-04-canonical-arena-deployment, 09-07-demo-verification]
# Tech tracking
tech-stack:
added: []
patterns:
- "{{ARENA_URL}} literal token in canonical markdown, substituted server-side (PUBLIC_ARENA_URL || request origin) or client-side (window.location.origin) — one doc, many resolution points"
- "Dual-path file resolution (server/public/docs/... then ../../../frontend/public/docs/...) mirroring app.ts's publicDir derivation, so the route works from both a built container and a dev checkout"
key-files:
created: []
modified:
- frontend/public/docs/BOTFIGHTS.md
- BOTFIGHTS.md
- server/src/routes/docs.ts
- server/src/routes/docs.test.ts
- frontend/src/pages/JoinBoutPage.vue
- frontend/src/pages/BotProfilePage.vue
- frontend/src/pages/DocsPage.vue
- e2e/signup-bot.spec.ts
key-decisions:
- "Documented the real webhook-vs-poll trash-talk field-name split (trash_talk snake_case for webhook responses per orchestrator.ts's webhookResponseSchema, trashTalk camelCase for /api/fights/poll/respond per validators.ts's respondSchema) instead of picking one and being wrong for the other protocol"
- "Fixed the old bot.js webhook example's signature verification, which hashed BOT_SECRET directly — the real derivation is HMAC-SHA256(key=HMAC-SHA256('botfights-webhook-v1', SHA256(BOT_SECRET)), message=timestamp.body), verified against orchestrator.ts"
- "Did not carry over BOT_SETUP.md's customization API example — POST /api/auth/update requires a nostr-owned publicKey that anonymously-registered (POST /api/bots) bots never have, so including it would document a call the AI-agent flow can never use"
- "BotProfilePage.vue's webhook/polling guide-type selector (two buttons) was removed, not just re-pointed — there is only one document now, so the mode toggle had nothing left to select"
requirements-completed: [BOT-02]
coverage:
- id: D1
description: "One consolidated prompt (frontend/public/docs/BOTFIGHTS.md) contains registration, credentials, both protocols, every endpoint, and every response format — the four superseded docs (BOTFIGHTS-EASY/POLLING/WEBHOOK.md, BOT_SETUP.md) are deleted"
requirement: BOT-02
verification:
- kind: other
ref: "grep acceptance criteria: {{ARENA_URL}} count>=5, YOUR_BOT_ID/YOUR_BOT_SECRET present, api/fights/poll(/respond)/api/queue/join/X-Botfights-Signature present, botfights.io count=0, superseded files absent, wc -l>=452"
status: pass
human_judgment: false
- id: D2
description: "GET /api/docs/prompt serves the prompt as text/markdown with {{ARENA_URL}} resolved to PUBLIC_ARENA_URL or the request origin"
requirement: BOT-02
verification:
- kind: unit
ref: "server/src/routes/docs.test.ts#GET /api/docs/prompt (5 new cases: 200+markdown, no leftover token, PUBLIC_ARENA_URL precedence, origin fallback, YOUR_BOT_ID preserved)"
status: pass
- kind: other
ref: "pnpm exec tsc --noEmit -p server/tsconfig.json"
status: pass
human_judgment: false
- id: D3
description: "Every in-app setup surface (JoinBoutPage, BotProfilePage, DocsPage) points at the single prompt; DocsPage has a copy-to-clipboard 'Give this to your AI' panel plus the literal /api/docs/prompt URL"
requirement: BOT-02
verification:
- kind: other
ref: "pnpm exec vue-tsc --noEmit -p frontend/tsconfig.json && grep -rl (deleted doc names) frontend/src returns nothing"
status: pass
- kind: e2e
ref: "e2e/signup-bot.spec.ts#unified AI bot-setup prompt (BOT-02) — 2 new tests written; NOT executed this session, see Issues Encountered"
status: unknown
human_judgment: true
rationale: "The e2e Playwright run against a local dev server could not execute — port 9100 (the local backend's fixed dev port, hardcoded in frontend/vite.config.ts's proxy target) is occupied by the live archi-dev-box botfights container needed for tomorrow's demo. All static/type-level verification passed; the actual browser-driven click-through and live GET /api/docs/prompt fetch through a running app need a human (or a later session with the port free) to confirm."
# Metrics
duration: 53min
completed: 2026-07-31
status: complete
---
# Phase 9 Plan 3: Unified AI Bot-Setup Prompt Summary
**Consolidated five drifting BOTFIGHTS setup docs into one self-contained AI prompt, served live at `GET /api/docs/prompt` with the arena URL auto-resolved, and wired every in-app surface (JoinBoutPage, BotProfilePage, DocsPage) to it with a copy-to-clipboard "Give this to your AI" panel.**
## Performance
- **Duration:** 53 min
- **Started:** 2026-07-31T01:41:39Z
- **Completed:** 2026-07-31T02:34:21Z
- **Tasks:** 3
- **Files modified:** 12 (botfight repo) + 1 (this SUMMARY, archy repo)
## Accomplishments
- One canonical prompt (`frontend/public/docs/BOTFIGHTS.md`, 621 lines) covers: anonymous `POST /api/bots` registration (previously undocumented anywhere), credentials + both auth forms, full working webhook and polling bot implementations sharing one `ARENA_URL` constant, the exact two-step HMAC webhook signature derivation, an endpoint reference table, challenge payloads/types/scoring reconciled against `docs.ts`, and a troubleshooting table.
- `GET /api/docs/prompt` (new Hono route) serves that file as `text/markdown`, resolving `{{ARENA_URL}}` to `PUBLIC_ARENA_URL` or the request's own origin — so a cloud agent that curls the live arena gets a prompt whose examples already point back at that same arena.
- `frontend/public/docs/BOTFIGHTS-EASY.md`, `BOTFIGHTS-POLLING.md`, `BOTFIGHTS-WEBHOOK.md`, and `BOT_SETUP.md` are deleted; the repo-root `BOTFIGHTS.md` is now a 4-line stub pointing at the canonical copy.
- `JoinBoutPage.vue` and `BotProfilePage.vue` both collapsed their mode-conditional doc paths to the single `/docs/BOTFIGHTS.md`, keeping the `YOUR_BOT_ID`/`YOUR_BOT_SECRET` substitution and adding a new `{{ARENA_URL}} -> window.location.origin` substitution.
- `DocsPage.vue` gained a "GIVE THIS TO YOUR AI" panel above the existing tabs: a copy-URL button, a copy-full-prompt button that fetches `/api/docs/prompt` live, and the literal URL displayed for handing to an agent directly.
## Task Commits
Each task was committed atomically (botfight repo, `git push origin main`):
1. **Task 1: Write the one prompt** - `bbc3c7a` (docs)
2. **Task 2: Serve GET /api/docs/prompt** - `a080956` (feat)
3. **Task 3: Point every in-app surface at the one prompt** - `2dd9947` (feat)
**Plan metadata:** this SUMMARY, committed to the archy repo (`git push gitea-ai main`).
_Note: the botfight repo's working tree is shared with a concurrent agent doing BOT-01 (nostr auth) work throughout this session — every stage/commit above was done by explicit file path, never `git add -A`, and pushes landed as clean fast-forwards on top of their `bf240ce`/`635ee39`/`e824f4c` commits with no conflicts._
## Files Created/Modified
- `frontend/public/docs/BOTFIGHTS.md` - the canonical unified prompt (452 -> 621 lines)
- `BOTFIGHTS.md` (repo root) - reduced to a 4-line stub
- `BOT_SETUP.md`, `frontend/public/docs/BOTFIGHTS-EASY.md`, `BOTFIGHTS-POLLING.md`, `BOTFIGHTS-WEBHOOK.md` - deleted
- `server/src/routes/docs.ts` - new `GET /prompt` handler
- `server/src/routes/docs.test.ts` - 5 new test cases for the prompt route
- `frontend/src/pages/JoinBoutPage.vue` - `setupDocPath()`/`setupDocName()` collapsed, `{{ARENA_URL}}` substitution added
- `frontend/src/pages/BotProfilePage.vue` - same collapse; removed the now-meaningless webhook/polling guide-type selector
- `frontend/src/pages/DocsPage.vue` - new "Give this to your AI" copy panel
- `e2e/signup-bot.spec.ts` - 2 new tests (copy affordance visible, `GET /api/docs/prompt` returns 200 via `page.request`)
## Decisions Made
See `key-decisions` in frontmatter — most notably: fixed a real bug in the old webhook signature example (it hashed the raw secret instead of the two-step `secretHash``signingKey` derivation the server actually uses), and documented the genuine `trash_talk`/`trashTalk` field-naming split between the webhook and poll protocols rather than picking one casing and silently breaking the other.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Webhook signature verification example was wrong**
- **Found during:** Task 1 (writing the consolidated prompt)
- **Issue:** The old `bot.js` webhook example's `verifySignature()` computed `HMAC-SHA256(BOT_SECRET, timestamp.body)` directly. The real server (`orchestrator.ts` lines 183-195) derives the signing key as `HMAC-SHA256('botfights-webhook-v1', SHA256(BOT_SECRET))` first, then HMACs the payload with *that* key. A bot following the old example would always reject valid, correctly-signed requests.
- **Fix:** Rewrote `verifySignature()` in the new webhook example to match the real two-step derivation; documented the exact steps in the new "Webhook verification" section.
- **Files modified:** `frontend/public/docs/BOTFIGHTS.md`
- **Verification:** Manually traced against `server/src/engine/orchestrator.ts` lines 183-195 (read, not modified).
- **Committed in:** `bbc3c7a` (Task 1 commit)
**2. [Rule 1 - Bug] `trash_talk` field-name mismatch between my own poll/webhook examples**
- **Found during:** Task 1 self-review, after drafting a combined prompt that used `trashTalk` everywhere
- **Issue:** `server/src/lib/validators.ts`'s `respondSchema` (used by `POST /api/fights/poll/respond`) requires camelCase `trashTalk`; `server/src/engine/orchestrator.ts`'s `webhookResponseSchema` (used to parse a webhook bot's HTTP response) requires snake_case `trash_talk` and is `.passthrough()`, so the wrong casing doesn't error — it silently drops the trash talk. My first draft used `trashTalk` in both places, which would have shipped the same latent bug that was never previously documented at all.
- **Fix:** Split the webhook bot's response construction to use `trash_talk`, kept the polling bot's to `trashTalk`, and added an explicit "Webhook vs poll: field naming" callout with a payload example for each protocol.
- **Files modified:** `frontend/public/docs/BOTFIGHTS.md`
- **Verification:** Verified against `server/src/lib/validators.ts` (`respondSchema`) and `server/src/engine/orchestrator.ts` (`webhookResponseSchema`) directly.
- **Committed in:** `bbc3c7a` (Task 1 commit)
**3. [Rule 2 - Missing critical] BotProfilePage.vue's dead webhook/polling guide-selector removed, not left dangling**
- **Found during:** Task 3
- **Issue:** The plan called for collapsing to a single doc but the page had a two-button "WEBHOOK / POLLING" selector purely for choosing which of the two now-deleted docs to display. Leaving the buttons in place with both wired to the same content would be confusing dead UI.
- **Fix:** Replaced the two-button selector with a single "LOAD SETUP GUIDE" button; removed the now-unused `guideMode` ref and simplified `loadGuide()` to take no parameter.
- **Files modified:** `frontend/src/pages/BotProfilePage.vue`
- **Verification:** `vue-tsc --noEmit` passes; visually the panel now shows one button instead of two.
- **Committed in:** `2dd9947` (Task 3 commit)
---
**Total deviations:** 3 auto-fixed (2 bug fixes, 1 missing-critical UI cleanup)
**Impact on plan:** All three were necessary for the prompt to actually be correct and usable by an AI agent — the plan's core acceptance bar. No scope creep; no files outside the plan's `files_modified` list were touched.
## Issues Encountered
- **e2e suite not executed this session.** `pnpm test:e2e -- e2e/signup-bot.spec.ts` requires a local dev server; `frontend/vite.config.ts`'s dev proxy hardcodes backend target `http://localhost:9100`, but port 9100 on this machine (archi-dev-box) is occupied by the live, healthy `botfights` podman container (42h uptime) that is needed for tomorrow's demo — confirmed via `podman ps`. I did not stop it. My own orphaned `pnpm dev` frontend-only process (backend half crashed with `EADDRINUSE`) was killed cleanly. Recorded to `.planning/WINDOWS.md` as an `unrun-verify` entry (id 5). Everything I *could* verify locally passed: `vue-tsc --noEmit`, `tsc --noEmit`, the full `pnpm --filter frontend build` (confirmed `frontend/dist/docs/BOTFIGHTS.md` ships in the bundle), and `pnpm vitest run --project server` (5 failures, all pre-existing and unrelated — the exact flaky perf-test set documented in `deferred-items.md`: `answers.test.ts`, `lifecycle.test.ts`, `scoring.test.ts`, `bot-auth.test.ts` constant-time; `docs.test.ts` itself passed 8/8 on every run).
- **Shared working tree with a concurrent agent.** The other agent's BOT-01 work (nostr `GET /api/auth/me`, `migrate.ts` DDL sync) landed mid-session via their own commits (`bf240ce`, `635ee39`, `e824f4c`) with no file overlap with this plan's `files_modified` list. Every `git add`/commit in this plan staged only the exact files this plan owns; both pushes were clean fast-forwards.
## User Setup Required
None - no external service configuration required. (Note: `PUBLIC_ARENA_URL` is an optional env var the route already supports, but setting it on the deployed canonical arena is a deployment/manifest concern for a different plan, not this one.)
## Next Phase Readiness
- The prompt is ready for tomorrow's demo path: any agent that can `curl https://botfights.archipelago-foundation.org/api/docs/prompt` gets a complete, arena-URL-correct instruction set.
- **Before the demo:** a human (or a session with port 9100 free) should run `pnpm test:e2e -- e2e/signup-bot.spec.ts` against a live instance and, ideally, hand the deployed `/api/docs/prompt` output to a real cloud agent once — the plan's own stated acceptance bar ("tomorrow's demo has a cloud-hosted 'openclaw' bot register and fight using ONLY this prompt") is a human/live-system verification this session could not perform.
- No blockers for other 09-* plans — this plan touched only docs/routes/frontend pages already isolated in its own `files_modified` list.
---
*Phase: 09-botfights-platform-upgrade*
*Completed: 2026-07-31*
## Self-Check: PASSED
- FOUND: `frontend/public/docs/BOTFIGHTS.md`
- FOUND: `BOTFIGHTS.md` (repo-root stub)
- FOUND: `server/src/routes/docs.ts`
- FOUND: `server/src/routes/docs.test.ts`
- CONFIRMED DELETED: `frontend/public/docs/BOTFIGHTS-EASY.md`, `BOTFIGHTS-POLLING.md`, `BOTFIGHTS-WEBHOOK.md`, `BOT_SETUP.md`
- Commit `bbc3c7a` (Task 1): FOUND in `git log --oneline --all`
- Commit `a080956` (Task 2): FOUND in `git log --oneline --all`
- Commit `2dd9947` (Task 3): FOUND in `git log --oneline --all`