Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
---
|
||||
phase: 09-botfights-platform-upgrade
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- /home/archipelago/Projects/botfight/docker-compose.arena.yml
|
||||
- /home/archipelago/Projects/botfight/docs/arena-deployment.md
|
||||
autonomous: true
|
||||
requirements: [BOT-03]
|
||||
# user_setup RESOLVED 2026-07-30: user chose NO DNS/TLS — canonical arena URL is
|
||||
# http://146.59.87.168:9100 (plain HTTP on the raw port). The node→arena hop is
|
||||
# server-side so there is no mixed-content issue; a TLS subdomain can be added later
|
||||
# by changing only ARENA_UPSTREAM_URL (env), no code change. Data seed: FULL COPY
|
||||
# of archi-dev-box's 351 MB botfights.db (user decision, option-c data).
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "One canonical BotFights arena runs on VPS2 (146.59.87.168) in standalone mode — it owns the only real match/fighter database (D-03/BOT-03)"
|
||||
- "The arena answers /api/health on the VPS2 host before any DNS or TLS work begins, so a later public failure is unambiguously a routing problem and not an app problem"
|
||||
- "The arena's JWT signing secret is generated on the VPS2 host, stored 0600 outside git, and never appears in a tracked file or in a log"
|
||||
- "The arena rate-limits on the direct socket peer IP (no reverse proxy in front — TRUSTED_PROXY deliberately unset), so per-IP limits see real client IPs"
|
||||
- "Lightning/cashu payment features are left unconfigured on the public arena — they are explicitly out of this phase's scope"
|
||||
- "How to redeploy this arena from scratch is written down in the repo, because NPM's routing and the host .env are not git-tracked artifacts"
|
||||
artifacts:
|
||||
- path: /home/archipelago/Projects/botfight/docker-compose.arena.yml
|
||||
provides: "Reproducible compose definition for the canonical VPS2 arena (registry image, no build, no payment env)"
|
||||
contains: "TRUSTED_PROXY"
|
||||
- path: /home/archipelago/Projects/botfight/docs/arena-deployment.md
|
||||
provides: "The runbook: host paths, port, NPM proxy-host values, DNS record, secret handling, rollback"
|
||||
contains: "146.59.87.168"
|
||||
key_links:
|
||||
- from: public internet (node instances + cloud bots)
|
||||
to: the canonical arena container on VPS2
|
||||
via: "direct http://146.59.87.168:9100 (user-chosen: no DNS/NPM/TLS; port 9100 published by docker and open through the host firewall)"
|
||||
pattern: "9100"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Stand up the one canonical BotFights arena on VPS2 at `http://146.59.87.168:9100` —
|
||||
the shared endpoint every node's instance will proxy to (D-03/BOT-03). (User decision 2026-07-30:
|
||||
no DNS/TLS; plain HTTP on the raw port, TLS is a later env-only upgrade.)
|
||||
|
||||
Decision IDs map to `09-CONTEXT.md` **Locked Decisions**: D-01 = BOT-01 signer login,
|
||||
D-02 = BOT-02 unified prompt, D-03 = BOT-03 shared public match endpoint on VPS2,
|
||||
D-04 = BOT-04 registry/catalog.
|
||||
|
||||
Purpose: this is the longest-latency item on the demo path because it needs a DNS record at the
|
||||
registrar and a certificate issuance, neither of which Claude can perform. Starting it in wave 1,
|
||||
in parallel with the app work, is deliberate — if DNS stalls, the fallback (plain HTTP on the public
|
||||
IP and port) is still enough for a cloud bot, and the plan says so explicitly rather than leaving
|
||||
the demo to discover it.
|
||||
Output: a running canonical arena on VPS2, a committed compose file and runbook, a public hostname
|
||||
with a valid certificate, and a recorded decision about what data the arena starts with.
|
||||
|
||||
**Repos/hosts:** compose + runbook are committed in `/home/archipelago/Projects/botfight`
|
||||
(`git push origin main`); the arena itself runs on VPS2 (`debian@146.59.87.168`, key
|
||||
`~/.ssh/id_ed25519_vps168`, docker not podman, passwordless sudo). VPS2 is host infrastructure —
|
||||
the rootless-podman invariant applies to Archipelago nodes, not to this host.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/gsd-core/workflows/execute-plan.md
|
||||
@$HOME/.claude/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/09-botfights-platform-upgrade/09-CONTEXT.md
|
||||
@.planning/phases/09-botfights-platform-upgrade/09-RESEARCH.md
|
||||
@.planning/phases/09-botfights-platform-upgrade/09-PATTERNS.md
|
||||
@.planning/phases/09-botfights-platform-upgrade/09-VALIDATION.md
|
||||
</context>
|
||||
|
||||
## Environment facts verified during planning (do not re-derive, do re-check)
|
||||
|
||||
| Fact | Value |
|
||||
|---|---|
|
||||
| VPS2 access | `ssh debian@146.59.87.168` with `~/.ssh/id_ed25519_vps168`, passwordless sudo, docker |
|
||||
| Ports already bound on VPS2 | 22, 80, 81, 443, 2100, 2101, 2222, 3000, 3009, 5355, 7788, 8000, 8092, 8123, 8443, 8444, 9443 — **9100 is free** |
|
||||
| NPM install | container `nginx-proxy-manager-app-1`, compose dir `/home/debian/nginx-proxy-manager`, data `/home/debian/nginx-proxy-manager/data`, admin UI on :81, admin user `lfg2025@proton.me` |
|
||||
| Existing NPM proxy-host shape | `forward_scheme=http`, `forward_host=146.59.87.168`, `forward_port=<port>`, `ssl_forced=1`, `allow_websocket_upgrade=1`, Let's Encrypt cert (e.g. demo→2100, source→3000, fips→8444) |
|
||||
| DNS | `archipelago-foundation.org` on `ns29/ns30.domaincontrol.com` (GoDaddy). `demo.`/`source.`/`fips.` resolve to 146.59.87.168. **No wildcard** — a new subdomain needs a new A record |
|
||||
| Registry | `146.59.87.168:3000/lfg2025` (Gitea on the same host, so the arena can pull from `localhost:3000`) |
|
||||
| Existing arena data on archi-dev-box | `/var/lib/archipelago/botfights/botfights.db` — 115 bots, 102,440 fights, 351 MB, `payments`/`bets` empty |
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking" resolved="2026-07-30">
|
||||
<name>Task 1: Decide the arena hostname and what data the public arena starts with — RESOLVED: no hostname (http://146.59.87.168:9100 direct), full database copy</name>
|
||||
<decision>What hostname does the canonical arena use, and what data does it start with?</decision>
|
||||
<context>
|
||||
Two choices must be made before the arena is deployed, because both are baked into the compose
|
||||
file, the NPM proxy host, the DNS record, and (later) the app manifest every node reads.
|
||||
|
||||
(1) **Hostname.** Planning recommends `arena.archipelago-foundation.org` — it matches the
|
||||
established `<name>.archipelago-foundation.org` pattern already used by demo/source/fips/
|
||||
companion, and it is what plan 09-06 will write into `apps/botfights/manifest.yml` as
|
||||
`ARENA_UPSTREAM_URL`. Changing it later means re-signing and re-publishing the catalog.
|
||||
|
||||
(2) **Starting data.** archi-dev-box's existing BotFights instance holds 115 registered bots and
|
||||
102,440 fights (351 MB). Once nodes switch to proxy mode, that local database stops being read —
|
||||
it is preserved on disk, but those 115 fighters vanish from the UI unless the arena starts with
|
||||
them.
|
||||
|
||||
Option A — fresh empty arena. Cleanest and most private; the demo starts with an empty
|
||||
leaderboard and only bots registered from now on (including the cloud openclaw bot).
|
||||
Option B — seed the `bots` table only (recommended). Copies the 115 fighter rows (name, ELO,
|
||||
W/L, avatar, `secret_hash`, `public_key`) into a fresh arena DB and drops the 102k-row fight
|
||||
history, so the arena is small, the leaderboard looks alive for the demo, and every bot script
|
||||
that already holds credentials keeps working. It does publish those bot names and nostr pubkeys
|
||||
on a public server.
|
||||
Option C — copy the whole 351 MB database, fight history included. Most continuity, largest
|
||||
surface, and carries `payments`/`bets` tables (both currently empty) onto a public host.
|
||||
|
||||
Reversibility: the arena DB is brand new and can be re-seeded or wiped until real users register
|
||||
against it — so this is reversible today and progressively less so after the demo.
|
||||
</context>
|
||||
<options>
|
||||
<option id="option-a">
|
||||
<name>arena.archipelago-foundation.org + fresh empty database</name>
|
||||
<pros>Nothing private leaves archi-dev-box; smallest attack surface; fastest deploy</pros>
|
||||
<cons>Empty leaderboard on demo day; existing 115 bots are invisible until re-registered</cons>
|
||||
</option>
|
||||
<option id="option-b">
|
||||
<name>arena.archipelago-foundation.org + seed the bots table only (recommended)</name>
|
||||
<pros>Demo shows a populated roster; existing bot credentials keep working; arena stays small; no fight/payment history exported</pros>
|
||||
<cons>115 bot names and their nostr pubkeys become publicly visible on the internet</cons>
|
||||
</option>
|
||||
<option id="option-c">
|
||||
<name>arena.archipelago-foundation.org + full database copy</name>
|
||||
<pros>Complete continuity including fight history and stats</pros>
|
||||
<cons>351 MB transfer; exports fight history and empty-but-present payment tables to a public host</cons>
|
||||
</option>
|
||||
<option id="option-d">
|
||||
<name>A different hostname (state it) with one of the data options above</name>
|
||||
<pros>Whatever naming the domain owner prefers</pros>
|
||||
<cons>Must be decided now — it is written into the signed catalog in plan 09-06</cons>
|
||||
</option>
|
||||
</options>
|
||||
<resume-signal>RESOLVED by user 2026-07-30 via AskUserQuestion: (1) hostname — "can we do it a different way without needing to do that?" → no DNS record; the canonical arena URL is `http://146.59.87.168:9100` directly (server-side proxy hop, no mixed content; TLS subdomain is a later env-only upgrade). (2) data — "Full copy" → copy the entire 351 MB botfights.db from archi-dev-box (read-only export; source file untouched). Do NOT re-ask.</resume-signal>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Deploy the canonical arena on VPS2 and prove it healthy on the host</name>
|
||||
<precondition>The hostname and data-seed decision from Task 1 has been given, and `ssh debian@146.59.87.168` succeeds with the pinned key.</precondition>
|
||||
<reversibility rating="reversible">A single new docker compose project in its own directory on
|
||||
VPS2 with its own named volume; `docker compose down -v` plus deleting the directory removes it
|
||||
with no effect on any other service on that host.</reversibility>
|
||||
<files>/home/archipelago/Projects/botfight/docker-compose.arena.yml, /home/archipelago/Projects/botfight/docs/arena-deployment.md</files>
|
||||
<read_first>
|
||||
- `/home/archipelago/Projects/botfight/docker-compose.yml` — the existing service definition to
|
||||
derive from: container name, port 9100, named volume `botfights-data` mounted at
|
||||
`/app/server/data`, and the full env list including the payment vars that must NOT be set here.
|
||||
- `/home/archipelago/Projects/botfight/Dockerfile` — confirms `PORT=9100`, the non-root
|
||||
`botfights` user, and the built-in HEALTHCHECK hitting `/api/health`.
|
||||
- `/home/archipelago/Projects/botfight/server/src/middleware/jwt.ts` lines 1-8 — the module
|
||||
throws at import when `JWT_SECRET` is unset and `NODE_ENV=production`, which is why the host
|
||||
`.env` is mandatory, not optional.
|
||||
- `/home/archipelago/Projects/botfight/server/src/middleware/rate-limit.ts` lines 36-52 — why
|
||||
`TRUSTED_PROXY` must be set on this instance specifically (it sits behind NPM).
|
||||
- `.planning/phases/09-botfights-platform-upgrade/09-RESEARCH.md` "Open Questions" #2 — payments
|
||||
env vars deliberately left unset.
|
||||
</read_first>
|
||||
<action>
|
||||
Add `docker-compose.arena.yml` to the botfight repo — the canonical-arena counterpart of the
|
||||
existing dev compose file. It must:
|
||||
- use `image: localhost:3000/lfg2025/botfights:<tag>` (the Gitea registry runs on this same
|
||||
host, so no cross-host pull) with **no** `build:` section — the arena runs published images
|
||||
only, so what it runs is exactly what nodes run;
|
||||
- start at the currently published tag `1.1.0` (plan 09-05 rolls it to 1.2.0 once that image is
|
||||
built and pushed) and keep the tag in one place so the roll is a one-line edit;
|
||||
- bind `9100:9100`, `restart: unless-stopped`, container name `botfights-arena`, named volume
|
||||
`botfights-arena-data:/app/server/data`;
|
||||
- set `NODE_ENV=production`, `PORT=9100`, `FIGHT_LOOP_ENABLED=true`,
|
||||
`PUBLIC_ARENA_URL=http://146.59.87.168:9100`, `JWT_SECRET=${JWT_SECRET}` and
|
||||
OMIT `TRUSTED_PROXY` (no NPM in front — clients hit :9100 directly, so the arena must
|
||||
use the socket peer IP for rate limiting, not forwarded headers), and
|
||||
`BOTFIGHTS_CREATOR_PUBKEYS=${BOTFIGHTS_CREATOR_PUBKEYS:-da5e0c1b646bdb13c2300f805b0ca3e5afe5b052c594ce78bac8978d21c3fa39}`;
|
||||
- deliberately omit `ARENA_UPSTREAM_URL` (this instance IS the upstream) and omit every
|
||||
`BOTFIGHTS_WALLET_ENCRYPTION_KEY` / `BOTFIGHTS_NWC_URL` / `BOTFIGHTS_CASHU_MINT_URL` /
|
||||
`BOTFIGHTS_DEV_PAYOUT_LNADDRESS` variable, with a comment saying payments are out of scope for
|
||||
this deployment;
|
||||
- contain no secret values whatsoever — `JWT_SECRET` comes from a host `.env` file.
|
||||
|
||||
On VPS2 (`ssh debian@146.59.87.168`):
|
||||
1. `sudo ss -tlnp` and confirm 9100 is still free before binding it.
|
||||
2. Create `/opt/botfights-arena/`, copy `docker-compose.arena.yml` there as
|
||||
`docker-compose.yml`, and write `/opt/botfights-arena/.env` containing
|
||||
`JWT_SECRET=$(openssl rand -hex 32)` with mode 0600. Never print that value into the
|
||||
transcript, a log, or any file under a git repo.
|
||||
3. `docker compose up -d`, wait for the container's healthcheck, then verify on the host:
|
||||
`curl -fsS http://127.0.0.1:9100/api/health` returns `{"status":"ok","name":"botfights"}`.
|
||||
4. Apply the Task 1 data decision. For the seed options, export from archi-dev-box with a
|
||||
read-only sqlite connection (the node's app is live — never write to its database), copy the
|
||||
result to VPS2 over ssh, stop the arena container, place the file as the arena volume's
|
||||
`botfights.db`, restart, and verify the bot count through `GET /api/bots`. For option A do
|
||||
nothing beyond letting the app create its own database.
|
||||
5. Confirm the arena is reachable from off-host on the raw port before any DNS exists:
|
||||
from archi-dev-box, `curl -fsS http://146.59.87.168:9100/api/health`. If that fails, an OVH
|
||||
or ufw firewall rule is blocking 9100 — record it in the runbook and note that the plain-HTTP
|
||||
contingency in Task 3 depends on it.
|
||||
|
||||
Write `docs/arena-deployment.md` in the botfight repo covering: the host and directory, the
|
||||
port, how the secret is generated and where it lives, the exact NPM proxy-host field values, the
|
||||
DNS record, the seed decision that was taken, how to roll the image tag, and how to tear it
|
||||
down. NPM routing and the host `.env` are not git-tracked — this file is the only record.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>ssh -o BatchMode=yes debian@146.59.87.168 'curl -fsS http://127.0.0.1:9100/api/health' | grep -q '"status":"ok"' && curl -fsS --max-time 10 http://146.59.87.168:9100/api/health | grep -q '"status":"ok"'</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `ssh debian@146.59.87.168 'curl -fsS http://127.0.0.1:9100/api/health'` returns the ok payload.
|
||||
- `ssh debian@146.59.87.168 'sudo docker ps --filter name=botfights-arena --format "{{.Status}}"'` shows `Up` and healthy.
|
||||
- `ssh debian@146.59.87.168 'stat -c %a /opt/botfights-arena/.env'` prints `600`.
|
||||
- `ssh debian@146.59.87.168 'sudo docker inspect botfights-arena --format "{{json .Config.Env}}"'` contains no `ARENA_UPSTREAM_URL` entry and no `TRUSTED_PROXY` entry (direct exposure — rate limit on socket peer IP).
|
||||
- `grep -c 'BOTFIGHTS_WALLET_ENCRYPTION_KEY\|BOTFIGHTS_NWC_URL\|BOTFIGHTS_CASHU_MINT_URL' /home/archipelago/Projects/botfight/docker-compose.arena.yml` counts only commented lines, and no such variable is present in the container's env output.
|
||||
- `git -C /home/archipelago/Projects/botfight grep -c 'JWT_SECRET=' -- docker-compose.arena.yml` shows only the `${JWT_SECRET}` indirection, never a literal value.
|
||||
- `test -f /home/archipelago/Projects/botfight/docs/arena-deployment.md` and it contains the chosen hostname, `9100`, and the NPM field values.
|
||||
- For seed options B/C: `curl -fsS http://146.59.87.168:9100/api/bots` returns the expected number of fighters; the source database on archi-dev-box is unmodified (`mtime` unchanged).
|
||||
</acceptance_criteria>
|
||||
<done>A canonical arena container is running and healthy on VPS2 with a host-generated secret, correct proxy-trust settings, no payment configuration, and the agreed starting data.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Prove the arena is internet-reachable at http://146.59.87.168:9100 (no DNS/TLS — user decision 2026-07-30)</name>
|
||||
<precondition>Task 2 shows the arena healthy on-host.</precondition>
|
||||
<reversibility rating="reversible">Firewall rule (if one is needed) is a single ufw/iptables/OVH
|
||||
entry that can be removed; nothing else changes.</reversibility>
|
||||
<action>
|
||||
The user chose to skip DNS + NPM + Let's Encrypt entirely: the canonical arena URL IS
|
||||
`http://146.59.87.168:9100`. This works because the node→arena hop is a server-side proxy
|
||||
(no browser mixed-content) and cloud bots speak server-to-server. TLS can be added later by
|
||||
fronting the same port with an NPM host and changing only `ARENA_UPSTREAM_URL` — no code change.
|
||||
|
||||
Verify reachability from OFF the VPS: from archi-dev-box, `curl -fsS --max-time 10
|
||||
http://146.59.87.168:9100/api/health`. If it fails, check and fix host-level firewalling on
|
||||
VPS2 (`sudo ufw status`, iptables, and note OVH network-level firewall may need the user).
|
||||
Record the final reachable URL + any firewall change in `docs/arena-deployment.md` and in
|
||||
09-04-SUMMARY.md — plans 09-05/09-06/09-07 read the arena URL from there.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>curl -fsS --max-time 10 http://146.59.87.168:9100/api/health | grep -q '"status":"ok"'</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `curl -fsS http://146.59.87.168:9100/api/health` succeeds from archi-dev-box (off-host).
|
||||
- `curl -fsS http://146.59.87.168:9100/api/bots` returns the seeded fighters (full-copy decision: expect 115 bots).
|
||||
- `docs/arena-deployment.md` records the plain-HTTP decision and the later-TLS upgrade path.
|
||||
</acceptance_criteria>
|
||||
<done>The canonical arena is publicly reachable at http://146.59.87.168:9100 with the full data copy live.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| public internet → nginx-proxy-manager :443 | TLS termination; the only intended public entrance |
|
||||
| public internet → 146.59.87.168:9100 | The raw container port, reachable while it is bound to all interfaces |
|
||||
| VPS2 host filesystem → arena container | `/opt/botfights-arena/.env` carries the JWT signing key |
|
||||
| arena container → its SQLite volume | The single source of truth for every node's fighters |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-09-16 | Information disclosure | credentials over plain HTTP on the raw port | high | accept (user decision 2026-07-30) | User explicitly chose plain HTTP on :9100 over DNS/TLS setup; recorded in runbook with the env-only TLS upgrade path for later |
|
||||
| T-09-17 | Information disclosure | `JWT_SECRET` leaking into git, logs or `docker inspect` transcripts | high | mitigate | Generated on the host into a 0600 `.env` outside any repo; the compose file only carries `${JWT_SECRET}`; the value is never echoed |
|
||||
| T-09-18 | Spoofing | forged `X-Forwarded-For` from a direct caller to :9100 bypassing per-IP limits | medium | accept | `TRUSTED_PROXY` is required for the arena to honour those headers and NPM overwrites `X-Real-IP` for traffic through 443; a direct caller can already choose its own source IP cheaply, so this adds no meaningful capability |
|
||||
| T-09-19 | Denial of service | anonymous bot-registration flooding the public arena | medium | mitigate | Existing `rateLimit(3600_000, 5)` on `POST /api/bots`, now meaningful per real client IP thanks to `TRUSTED_PROXY` |
|
||||
| T-09-20 | Information disclosure | seeded bot rows publishing nostr pubkeys to the internet | medium | transfer | Surfaced as an explicit decision (Task 1) with the fresh-database option available; the user owns this choice |
|
||||
| T-09-21 | Tampering | writing to archi-dev-box's live database while exporting a seed | high | mitigate | Export uses a read-only sqlite URI; the acceptance criteria assert the source file is unmodified |
|
||||
| T-09-22 | Denial of service | binding a port already in use on a shared host | low | mitigate | 9100 verified free during planning and re-checked before binding |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `ssh debian@146.59.87.168 'curl -fsS http://127.0.0.1:9100/api/health'` — ok payload.
|
||||
- `curl -fsS http://146.59.87.168:9100/api/health` from archi-dev-box — ok payload (or a recorded
|
||||
firewall finding).
|
||||
- `curl -fsS http://146.59.87.168:9100/api/health` returns 200 from off-host — this is asserted
|
||||
again as plan 09-05 Task 1's precondition, which gates the rest of the demo path.
|
||||
- Supports `09-VALIDATION.md`'s manual-only item "Cross-node fighter visibility" by providing the
|
||||
shared endpoint that item depends on.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- One canonical arena container runs on VPS2 with a host-generated secret and no payment config.
|
||||
- Its compose definition and full runbook are committed to the botfight repo.
|
||||
- The full-copy data seed is live (115 bots visible via /api/bots) and the source DB on archi-dev-box is untouched.
|
||||
- The arena is internet-reachable at http://146.59.87.168:9100 (user-accepted plain HTTP; TLS is a later env-only upgrade).
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/09-botfights-platform-upgrade/09-04-SUMMARY.md` when done, recording the
|
||||
chosen hostname, the seed decision, and whether TLS or the fallback is in effect — plans 09-05,
|
||||
09-06 and 09-07 all read that hostname from here.
|
||||
Commit the botfight changes with `git add` by explicit path and `git push origin main`.
|
||||
Commit the SUMMARY in archy and `git push gitea-ai main`.
|
||||
</output>
|
||||
Reference in New Issue
Block a user