docs(09-05): record cross-instance fighter visibility proof (BOT-03)
CI / check (push) Failing after 6m4s

A throwaway 1.2.0 container in proxy mode (no volume, ARENA_UPSTREAM_URL
pointed at the canonical arena) demonstrated: a fighter registered
directly against the arena is visible through it (D1), a fighter
registered through it is visible on the arena directly (reverse), SSE
streams incrementally through it, /api/health answers locally during an
arena outage, and /api/bots degrades cleanly during that outage. Also
documents a deviation: the canonical URL now sits behind
nginx-proxy-manager (per the mid-phase DNS/TLS decision superseding this
plan's original plain-HTTP wording), so a stopped arena's 502 through
that URL is NPM's own HTML page rather than arena-proxy.ts's JSON body —
the underlying JSON degradation contract is separately confirmed live
against the raw fallback port, which has no intermediary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-07-30 23:35:39 -04:00
co-authored by Claude Fable 5
parent 773112b7f1
commit 90d5e2d16d
+22
View File
@@ -313,3 +313,25 @@ cleanly):** `wavetest2`, `wavetest3` — both anonymous, harmless, real
fighters; consistent with the arena's existing `FIGHT_LOOP_ENABLED=true`
mock-bot background activity. `wavetest3` fought one live match as part of
verifying the SSE stream above.
## Verified cross-instance behaviour (plan 09-05 Task 3, 2026-07-31)
A throwaway `botfights:1.2.0` container (`botfights-proxytest`, port 9101,
no volume mount — nothing worth reading locally) ran on archi-dev-box with
`ARENA_UPSTREAM_URL=https://botfights.archipelago-foundation.org`, alongside
(never touching) the installed `botfights` app on port 9100 (image 1.1.0).
| Check | Result |
|---|---|
| Proxy instance has no local data of its own | Startup still seeds a local 100+15 mock-bot DB (unrelated background code path that runs regardless of `ARENA_UPSTREAM_URL`) — but every `/api/*` request is intercepted by `arena-proxy` before it ever reaches a local route handler, so that local data is never exposed through the API |
| `GET /api/bots` via the proxy instance | Returned 103 bots, including `wavetest2` and `wavetest3` — both registered directly against the arena in Task 2, never touching this instance. **This is the D1 proof: a fighter registered on one host is visible through a different instance that never stored it.** |
| Reverse direction: register via the proxy instance | `POST http://127.0.0.1:9101/api/bots {"name":"wavetest4"}` succeeded, and `wavetest4` was immediately visible in `GET https://botfights.archipelago-foundation.org/api/bots` directly |
| SSE through the proxy instance | `wavetest3` matched into a real fight; `GET http://127.0.0.1:9101/api/fights/<id>/stream` delivered `spectator_count`/`ping` at connection open and a second `ping` ~15s later — incremental, not buffered |
| `/api/health` bypass during a deliberate arena outage | `docker compose stop` on the VPS2 arena (seconds); `GET http://127.0.0.1:9101/api/health` still returned `200 {"status":"ok",...}` throughout — confirmed answered locally per `arena-proxy.ts`'s `LOCAL_BYPASS_PATHS`, never forwarded |
| `/api/bots` during the same outage, via the **canonical HTTPS URL** (fronted by nginx-proxy-manager since 2026-07-30) | `502`, but the body was NPM's own HTML error page, not the app's JSON — because NPM itself answers with a gateway-level 502 before the request ever reaches the stopped container; `fetch()` inside `arena-proxy.ts` succeeds against NPM and passes its response through verbatim. This supersedes the plan's original acceptance wording (written when the arena was still plain-HTTP/no-NPM); NPM 502ing here is expected, correct behavior for a proxy in front of a stopped upstream. |
| `/api/bots` during a second, separate short outage, via the **raw fallback port** (`http://146.59.87.168:9100`, no NPM in front) | `502 {"error":"Arena unreachable."}``arena-proxy.ts`'s own JSON degradation path (already unit-tested in 09-01), confirmed live against a real stopped upstream with no intermediary |
| Recovery | `docker compose start` on VPS2 both times; arena `healthy` again within seconds; the proxy instance's own subsequent requests succeeded immediately, no restart needed on the node side |
| Installed app isolation | `podman ps --filter name=botfights` showed the installed `botfights` app (port 9100, image `:1.1.0`) with its original container id and uptime, unaffected throughout; no `botfights-proxytest*` container remains after cleanup |
**Test bots registered during this task, left in the arena (same rationale
as Task 2 — clearly named, no delete API exists):** `wavetest4`.