tsc --noEmit (run standalone, not filtered through a shell wrapper that
silently swallowed the real exit code) caught what my own verification
missed the first time: c.req.param('name') is typed possibly-undefined
in this Hono router's inferred route map, and the podman build's own
`pnpm --filter server build` step (which runs the real tsc, unlike a
loosely-configured local check) failed on it — 1.2.10 was never
actually built with the :name/ai-config routes as a result. Added an
explicit guard (matches the 404 semantics of a missing param) to all
three new handlers.
Also bumps docker-compose.arena.yml to the 1.2.11 tag being built next.
Co-Authored-By: Claude <noreply@anthropic.com>
Image tag bumps for 1.2.7/1.2.8/1.2.9 were applied directly on the VPS2
host via SSH+sed during live demo deployment and not consistently mirrored
back to this file each time — this commit brings it back in sync with
what's actually running (confirmed: docker inspect botfights-arena shows
localhost:3000/lfg2025/botfights:1.2.9, healthy).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sets the mint for the planned Cashu fixed-stake entry fee design ("winner
takes all, 21 sats each, only ever" — user-directed). Verified the mint
live before configuring it (not guessed): NUT-4 mint (bolt11/sat), NUT-5
melt, NUT-7 spend-check (needed to reject an already-spent posted token),
NUT-11 P2PK (lets a payout be locked to the winner's own pubkey, no
interactive receive step needed) all present. Mint's own description says
"Do not use with large amounts of ecash" — matches the 21-sat cap
intentionally.
This alone moves no funds: the existing cashu payout branch in
server/src/engine/payments.ts is only reached from ranked-mode fights,
which still requires BOTFIGHTS_NWC_URL (still unset) to even queue an
entry fee. The actual "accept a posted token as a stake, escrow it, refund
on timeout, pay the winner" capability does not exist in the codebase yet
— this commit is config-only prep, tracked as a properly-scoped follow-up
(see archy's 09-botfights-platform-upgrade/deferred-items.md for the
threat register worked through before configuring this).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"Connect NWC" was 500ing — server/src/engine/crypto.ts's getKey() throws
immediately under NODE_ENV=production when this var is unset. Generated a
random 32-byte key directly on the VPS2 host into /opt/botfights-arena/.env
(0600, never committed — same pattern as JWT_SECRET), wired the reference
into the deployed docker-compose.yml, and restarted. Only enables storing
per-user NWC connection strings encrypted at rest — does not enable any
actual money movement (BOTFIGHTS_NWC_URL, the arena's own wallet, is still
unset and deliberately not touched here).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1. server/src/app.ts: CSP img-src only allowed 'self'/data:/blob: — nostr
profile pictures come from kind:0 metadata, a URL the user sets via their
own client, hosted on whatever domain they picked. There's no central
image host for a decentralized identity system, so every external
profile pic was CSP-blocked and rendered as a broken image. Added
https: (broad) — safe here since images can't execute script even from
an untrusted origin, unlike script-src which stays locked to 'self'.
2. frontend/src/pages/JoinBoutPage.vue: the new AI-answer option (1.2.7)
was reported as invisible — it was gated behind picking POLLING (not the
default WEBHOOK) AND behind a collapsed toggle within that. Changed:
POLLING is now the default mode (also the documented default in
BOTFIGHTS.md), the AI section is expanded by default instead of
collapsed, and the POLLING button's own description now mentions the
option so it's visible without any extra click.
3. docker-compose.arena.yml: image tag 1.2.1 -> 1.2.7, matching what's
actually deployed on the canonical arena (rolled live via
ssh+docker compose pull/up this session — this commit just brings the
repo's copy of the compose file back in sync with reality).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The first cloud AI agent given the prompt refused it as a suspected prompt
injection: 'nothing else needs to be read' framing, raw-IP fallback, and
being told to wire its own ANTHROPIC_API_KEY into a persistent script. All
three patterns removed; brains are now an operator-supplied optional
OpenAI-compatible endpoint with local heuristics as default. queue/join
documented as blocking ~35s (60s client timeout) matching the real 30s
production QUEUE_TIMEOUT_MS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- docker-compose.arena.yml: image tag 1.1.0 -> 1.2.0, refreshed the
TRUSTED_PROXY comment to reflect the live NPM+TLS front-end (no
longer "no DNS/TLS this phase" — that shipped mid-phase).
- Deployed on VPS2: docker compose pull + up -d, container recreated,
healthy, data volume untouched.
- Verified end-to-end through the public HTTPS URL: health, unified
prompt (ARENA_URL substituted, zero leftover template tokens), a
freshly registered test bot visible in GET /api/bots, bot auth via
the now-fixed GET /api/fights/poll, and data integrity (100 + 15
classic bots, unchanged from before the roll).
- docs/arena-deployment.md: recorded the second (post-poll-fix) image
digest and the fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds docker-compose.arena.yml (registry image only, no build, no payment
env, no TRUSTED_PROXY since no reverse proxy fronts it) and
docs/arena-deployment.md (full runbook: host paths, port, secret handling,
seed decision, NPM/TLS upgrade path, teardown) for the one canonical public
arena at http://146.59.87.168:9100 (user decision 2026-07-30: no DNS/TLS
this phase, plain HTTP on the raw port; TLS is a later env-only upgrade).
Deployed + verified on VPS2: healthy on-host and off-host, seeded with a
full read-only copy of archi-dev-box's botfights.db (115 bots/102,440
fights; source untouched, mtime verified unchanged).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>