diff --git a/.planning/.continue-here.md b/.planning/.continue-here.md deleted file mode 100644 index 0f76dce7..00000000 --- a/.planning/.continue-here.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -context: default -phase: 09-botfights-platform-upgrade (already complete — this is off-plan work) -task: n/a -total_tasks: n/a -status: paused -last_updated: 2026-08-02T10:34:47.198Z ---- - -# BLOCKING CONSTRAINTS — Read Before Anything Else - -- [ ] CONSTRAINT: Never assume pushing one repo pushed another — this session pushed `archy` repeatedly via `git push gitea-ai main`, but the `botfight` repo's last 4 commits (the entire security-fix body of work) sat **local-only** the whole time and were only discovered/pushed at the very end of this session, during this handoff step. Structural mitigation: whenever a session touches more than one git repo, explicitly run `git status -sb` (ahead/behind vs. the tracked remote) in **every** repo touched before ending the session — not just the one most recently `git push`ed. - -**Do not proceed until the box above is checked (i.e. verify both repos are still in sync with their remotes before doing anything else).** - - -This is **not** a GSD plan/task in progress. Phase 09 (BotFights Platform Upgrade) is fully complete — plans 09-01 through 09-07 all have SUMMARY.md files, the last dated 2026-07-31 05:08. Everything described below happened *after* that, as live, user-directed, reactive work preparing for a same-day BotFights demo ("two real fighters playing with cashu"). None of it was tracked against a PLAN.md task list — the original GSD task (execute 09-06-PLAN.md: bump manifest + sign catalog) completed normally and stopped cleanly at its signing checkpoint, exactly as designed. Everything after that was ad hoc. - -**As of this handoff, everything is committed and pushed in both repos, and both demo nodes are deployed and verified healthy.** There is nothing mid-flight to resume — this file exists so a future session (or this one, after compaction) has the full picture instead of re-discovering it. - - - - -**botfight repo** (`/home/archipelago/Projects/botfight`, pushed to `origin/main` @ `10d4209`): -- iframe embedding fix (X-Frame-Options was unconditional), native Archipelago signer bridge (`nostr-provider.js`), "Sign in with Archipelago" docs for app developers -- Discoverability fixes: mode-picker guide banner, AI-answer visibility, "Latest Bouts" cut off on short viewports -- Fixed a proxy-URL leak (local/Tailscale addresses leaking into AI setup prompts via client-side `window.location.origin` — switched to server-rendered `/api/docs/prompt`) -- "Let BotFights answer for me" — server-side AI bot using an operator-supplied Anthropic/OpenAI API key (poll-mode bots) -- Fixed broken profile images (CSP `img-src`) -- Cashu ecash payments made the **primary** entry-fee AND payout UX (Lightning/NWC now secondary) — Minibits mint, `BOTFIGHTS_WALLET_ENCRYPTION_KEY`, escrow-style entry fee (21 sats, 42-sat winner-take-all pot) -- Fixed anonymous poll-mode bots being locked out of staked/ranked fights (auth gap) -- **Security audit found + fixed 6 instances of the same IDOR pattern** (client-supplied `pubkey` trusted with no verification against a real JWT) — `f5f57e6`, `c162d5e`: - - `POST /api/auth/update` — could hijack any bot's webhook/customization - - `GET /api/payments/winnings/:botId` — **critical**: zero auth at all, leaked live spendable Cashu bearer tokens to anyone who knew a botId (public in every URL) - - `POST /api/payments/connect-wallet` — **critical**: zero ownership check, could redirect any victim bot's future payouts to an attacker's wallet - - `POST /api/payments/claim/:paymentId`, `DELETE /api/payments/disconnect-wallet`, `POST /api/queue/join-ranked/:botId` — same pattern, lower severity - - Fix pattern: pubkey now always derived from `extractPubkeyFromAuth(Authorization: Bearer )`, never trusted from body/query. Added `verifyBotOwner()` helper in `bot-auth.ts` for routes serving both nostr-owner and anonymous-bot-secret audiences. -- Built the two things actually requested when the audit was found: **AI-answer settings reachable for existing bots** (`/api/bots/:name/ai-config`, not just at creation) and a **claim-winnings UI** (Cashu payouts were minted server-side but had zero frontend consumer — `41f1b93`) -- `10d4209`: fixed a real `tsc` error the podman build caught that local verification initially missed (misread a wrapper's exit code instead of the actual log content — lesson: always check log *content*, not just the shell wrapper's `$?`) -- Built + pushed `146.59.87.168:3000/lfg2025/botfights:1.2.11` - -**archy repo** (pushed to `gitea-ai/main`, my commits at `aea17248`/`b0a08345` — many other agents' commits have landed on top since, this is a busy shared tree): -- `apps/botfights/manifest.yml` bumped to 1.2.11; fixed `data_uid` from `1001` to `999` (the container's real internal UID — first attempt copied fedimint-clientd/barkd's value without checking this image's actual `Dockerfile`, which does `useradd --system` with no explicit UID) -- `scripts/image-versions.sh` kept in lockstep -- Catalog regenerated, signed (user ran `sign-catalog.sh`), published — verified live on `146.59.87.168:3000/lfg2025/archy/raw/branch/main/releases/app-catalog.json` -- Deployed to both nodes via RPC (`package.update`), both verified healthy: - - **archi-dev-box** (local): `botfights` container on `1.2.11`, `/api/health` → ok - - **x250-beta** (`archy-x250-beta.tail08d8f2.ts.net`): `botfights` container on `1.2.11`, `/api/health` → ok, `/api/bots` confirmed identical to `botfights.archipelago-foundation.org` (arena-proxy forwarding correctly) - - - -Nothing blocking the demo. One loose end, likely moot: -- Framework PT (`100.65.115.109`) SSH access is still blocked — the password was rotated 2026-07-26 and the current one isn't recorded anywhere. User redirected the demo plan away from Framework PT to x250-beta earlier in the session, so this probably doesn't matter anymore unless the user brings it up again. - - - -- Cashu is now the primary UX for both paying entry fees AND receiving payouts, Lightning/NWC demoted to a secondary "or connect a Lightning wallet instead" option — explicit user instruction. -- `data_uid: 999:999` (not 1001) in the botfights manifest — verified against the running container's actual `id` output, not assumed from another app's manifest. -- ai-config routes accept EITHER a nostr JWT (new, for browser owners) OR the bot's own secret (existing, for anonymous AI-agent poll-mode bots) — additive, not a replacement, since both audiences are real and pre-existing. - - - -- Framework PT SSH: password unknown since 2026-07-26 rotation. Not currently blocking anything (user moved to x250-beta). - - -## Required Reading (in order) -1. This file, obviously. -2. `.planning/phases/09-botfights-platform-upgrade/09-06-SUMMARY.md` and `09-07-SUMMARY.md` — the actual last GSD-tracked work in this area, for anyone confused about why there's no PLAN.md for tonight's work. -3. If continuing security work: re-read the fix pattern in `botfight` repo commits `f5f57e6` and `c162d5e` before touching any other route that reads a pubkey — the same bug class may exist elsewhere in the codebase that wasn't audited (only `auth.ts`, `payments.ts`, and `queue.ts` were checked; `bots.ts`, `tournaments.ts`, `bets.ts` were not re-audited for this exact pattern). - -## Critical Anti-Patterns (do NOT repeat these) -- **ANTI-PATTERN: trusting a shell wrapper's exit code instead of the actual command output.** During this session, `tsc --noEmit ... ; echo "EXIT=$?"` was read as "passed" from the *notification summary* (which reports the wrapper's own exit code, always 0 because `echo` always succeeds) rather than the log *content*. This let a real `tsc` compile error through to a `podman build` failure. → Structural mitigation: always `cat`/`Read` the actual log file and look for the error pattern or an explicit `EXIT=N` marker line before treating a background verification command as passed. -- **ANTI-PATTERN: assuming multi-repo work is saved because one repo was pushed.** → Structural mitigation described in the BLOCKING CONSTRAINT above. -- **ANTI-PATTERN (from earlier this session, already corrected): never run `archipelago --version` on a fleet node** — it starts the full daemon rather than printing a version string (deployed binaries predate the flag). Use source-reading instead of the binary for investigation. - -## Infrastructure State -- **archi-dev-box** (local node): `archipelago` daemon healthy, RPC on `127.0.0.1:5678` (session cookie in `/tmp/archy-dev-cookies.txt`, likely stale by the time this is read — re-login with `auth.login` / password `ThisIsWeb54321@`). `botfights` container healthy on `1.2.11`. -- **x250-beta** (`archy-x250-beta.tail08d8f2.ts.net`, tailnet IP rotates — resolve by MagicDNS name): reachable via plain `ssh archipelago@archy-x250-beta.tail08d8f2.ts.net` this session (no password prompt hit — key-based or cached). RPC session cookie in `/tmp/archy-cookies.txt` **on that remote node**, likely stale — re-login same way. `botfights` container healthy on `1.2.11`. -- Both nodes' local `/tmp` filled up mid-session (a 12G tmpfs, hit 0MB free once) — if you hit `ENOSPC` from the harness itself (not the actual command), check `df -h /tmp` and clean up stray large files (this session's culprit: two OTA release assets, ~260MB, downloaded to `/tmp` on the **local** machine as a relay step for an unrelated node update earlier in the session). -- Canonical arena: `https://botfights.archipelago-foundation.org` — both demo nodes proxy to this via `ARENA_UPSTREAM_URL`, confirmed serving identical bot/fight data on both. - - -The user is demoing BotFights live, same day, wants two real fighters paying/winning with Cashu ecash across two real node installs. All of that is now in place and verified. The security audit was NOT originally requested — it was triggered by investigating the user's question "can we confirm the fighter wins all the cashu sats into their node wallet automatically", which led to reading `payments.ts` end to end and discovering the payout claim flow had no frontend UI *and* the backend route serving it had no auth at all. That in turn led to checking every other route with a similar shape, which is how 5 more instances of the same bug were found. This is worth remembering: a seemingly simple product question ("where does the money go") uncovered a real, live, exploitable vulnerability in a publicly-deployed app — treat "let me just check how this actually works end to end" as time well spent, not scope creep. - - - -Nothing is required to "resume" — this was a complete, self-contained session of off-plan work, fully committed, pushed, deployed, and verified. If the user opens a new session and says something like "continue" or "where were we", the right first move is to summarize the state above (both nodes on `1.2.11`, security fixes live, demo-ready), not to look for a GSD plan to execute. If the user wants to resume *GSD-tracked* work specifically, `STATE.md` says Phase 10 (Key-Material Hardening, KEY-01..KEY-04, sourced from `docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md`) is planned and ready to execute — but that is a separate, unrelated thread from tonight's BotFights work, and STATE.md is being actively updated by other concurrent agents working other phases (01, 02, 10) in this shared tree, so re-read it fresh rather than trusting anything cached. - diff --git a/.planning/HANDOFF.json b/.planning/HANDOFF.json deleted file mode 100644 index cc92f2c1..00000000 --- a/.planning/HANDOFF.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "version": "1.0", - "timestamp": "2026-08-02T10:34:47.198Z", - "phase": "09", - "phase_name": "BotFights Platform Upgrade", - "phase_dir": ".planning/phases/09-botfights-platform-upgrade", - "plan": null, - "task": null, - "total_tasks": null, - "status": "paused", - "context_type": "ad_hoc_reactive", - "note": "This handoff does NOT track a GSD plan/task. Phase 09's plans 09-01..09-07 are all already complete (SUMMARY.md exists for each, most recent 09-07-SUMMARY.md dated 2026-07-31 05:08). Everything recorded here happened AFTER 09-06/09-07 were done, as live reactive demo-day work directed by the user in conversation, not from a PLAN.md task list. There is no in-progress GSD plan to resume — this is purely a work-state save so uncommitted/unpushed work and node state are not lost.", - "completed_tasks": [ - {"id": "botfight-security-audit", "name": "Found + fixed 6 IDOR/missing-auth vulnerabilities in botfight repo", "status": "done", "commit": "f5f57e6 (auth.ts), c162d5e (payments.ts/queue.ts)"}, - {"id": "botfight-ai-config-existing-bots", "name": "AI-answer settings UI for existing bots (not just at creation)", "status": "done", "commit": "41f1b93"}, - {"id": "botfight-claim-winnings-ui", "name": "Claim-winnings UI (Cashu payouts were backend-only, no frontend consumer)", "status": "done", "commit": "41f1b93"}, - {"id": "botfight-tsc-fix", "name": "Fixed possibly-undefined route param tsc error caught by podman build", "status": "done", "commit": "10d4209"}, - {"id": "botfight-1.2.11-release", "name": "Built + pushed botfights:1.2.11 image to registry", "status": "done"}, - {"id": "archy-manifest-1.2.11", "name": "Bumped apps/botfights/manifest.yml + scripts/image-versions.sh to 1.2.11, regenerated+signed+published catalog", "status": "done", "commit": "aea17248 (manifest bump), b0a08345 (signed catalog)"}, - {"id": "deploy-archi-dev-box", "name": "Updated BotFights to 1.2.11 on archi-dev-box via package.update RPC", "status": "done"}, - {"id": "deploy-x250-beta", "name": "Updated BotFights to 1.2.11 on x250-beta via package.update RPC", "status": "done"}, - {"id": "botfight-push-to-origin", "name": "Pushed 4 local-only botfight commits to origin (were unpushed until this handoff step)", "status": "done", "commit": "d00e792..10d4209 -> origin/main"} - ], - "remaining_tasks": [ - {"id": "framework-pt-access", "name": "Framework PT (100.65.115.109) SSH access still blocked — password was rotated 2026-07-26, current password unknown. User redirected focus to x250-beta instead, so this may no longer be needed for the demo.", "status": "blocked"} - ], - "blockers": [ - {"description": "Framework PT SSH password unknown (rotated, not recorded)", "type": "human_action", "workaround": "User already redirected demo plan to use x250-beta instead of Framework PT — likely moot unless user asks for Framework PT again."} - ], - "async_jobs": [], - "human_actions_pending": [], - "decisions": [ - {"decision": "Made Cashu the primary entry-fee AND payout UX for BotFights, Lightning/NWC secondary", "rationale": "Explicit user instruction: \"please make cashu the primary UX and lightning secondary\"", "phase": "09"}, - {"decision": "Fixed data_uid in apps/botfights/manifest.yml from 1001 to 999", "rationale": "Container's actual internal UID (confirmed via `podman exec botfights id`) is 999, not 1001 — first attempt copied fedimint-clientd/barkd's value without verifying against this specific image's Dockerfile (`useradd --system` with no explicit UID lands at 999)", "phase": "09"}, - {"decision": "Extended ai-config routes to accept EITHER nostr JWT (verifyBotOwner) OR the bot's own secret, rather than replacing bot-secret auth", "rationale": "Poll-mode AI-agent bots (no nostr identity) still need the original bot-secret path; nostr-logged-in browser owners needed a new path that didn't exist before", "phase": "09"} - ], - "uncommitted_files": [], - "unrelated_uncommitted_by_other_agent": [ - "core/archipelago/src/container/prod_orchestrator.rs (archy repo) — modified by a DIFFERENT concurrent agent, not touched by this session. Do NOT stage, commit, or stash this file." - ], - "next_action": "No GSD action required to resume — Phase 09 is fully complete and this was off-plan reactive work, now fully committed and pushed in both repos (archy @ b0a08345, botfight @ 10d4209 on origin/main), deployed to both demo nodes (archi-dev-box + x250-beta, both verified healthy on botfights:1.2.11), and catalog signed+published. If resuming demo work: verify nodes are still healthy (`curl http://127.0.0.1:9100/api/health` on each) since time has passed. If resuming GSD-tracked work: STATE.md says Phase 10 (Key-Material Hardening) is planned and ready to execute — that is a SEPARATE, unrelated GSD phase from tonight's BotFights firefighting.", - "context_notes": "This was a long reactive demo-prep session, not GSD-plan-driven. Started from GSD-executing 09-06-PLAN.md (bump BotFights manifest + sign catalog), which completed normally and STOPPED at the signing checkpoint as designed. Everything after that was live user-directed firefighting for a same-day demo: iframe embedding, native signer bridge, AI-answer feature, Cashu payment integration (both entry-fee and payout sides), a security audit that surfaced a systemic IDOR pattern (client-supplied pubkey trusted without verification) repeated across 6 routes — 2 of them critical (unauthenticated Cashu-token leak, unauthenticated wallet-hijack) — and a second-node deployment to x250-beta that surfaced a real manifest bug (data_uid). The single biggest risk caught in this handoff step itself: 4 botfight-repo commits (the entire security-fix work) were sitting LOCAL-ONLY, never pushed to origin, until this pause-work step explicitly checked ahead/behind counts and pushed them. Always verify `git status -sb` / ahead-behind against the actual remote before ending a session that touched a repo other than the one being actively `git push`ed in the visible workflow — pushing archy did not imply botfight got pushed too, they are separate repos." -} diff --git a/.planning/phases/02-ui-performance/.continue-here.md b/.planning/phases/02-ui-performance/.continue-here.md deleted file mode 100644 index 5424bb0f..00000000 --- a/.planning/phases/02-ui-performance/.continue-here.md +++ /dev/null @@ -1,98 +0,0 @@ -# Continue Here — Phase 02 (ui-performance) close-out - -**Written:** 2026-07-31, mid-session (user changing wifi; session may drop) -**Milestone:** v1.8.0 · **Phase 02 status:** executed, gap closure in progress - -## Where we are in one paragraph - -Phase 02's 8 plans all executed and were signed off by the user on real hardware. -`gsd-verifier` then returned **gaps_found (6/8 must-haves)**, which routed into -`/gsd-plan-phase 2 --gaps` → gap plans **02-09** (Server remount) and **02-10** -(timing verdict). 02-09 is **COMPLETE** — it proved the "Server.vue remounts" -finding was a *probe-measurement artifact*, not a defect (no source change needed; -regression tests now pin instance survival via `vm.$.uid`). 02-10 is still running. -A separate code review found and fixed 1 Critical + 6 Warnings; a follow-up security -task is also in flight. Once 02-10 and the security task land, **re-run the verifier**; -if it passes, mark the phase complete. - -## Critical hazards — read before ANY git command - -1. **SHARED WORKING TREE.** The user runs a SEPARATE session on **BotFights (phase 9)** - in this same checkout. Their uncommitted work is interleaved with ours. - - NEVER `git add -A` / `git add .` / `git commit -a` / `git stash` (stash refs are - shared — it strands their work) / `git checkout|restore` files you didn't edit / - `git reset --hard`. - - Stage ONLY exact paths you personally modified. - - Known to be THEIRS (do not stage/revert/modify): `releases/app-catalog.json` - (regenerated catalog, ~5090 lines, BotFights registry work), - `neode-ui/src/components/LightningChannelsPanel.vue`, `neode-ui/package-lock.json`, - `.planning/config.json`, `scripts/resilience/.gitignore-reports.tmp`. - - `neode-ui/src/views/AppDetails.vue` and `Cloud.vue` may hold a MIX of their edits - and our persist-audit edits — inspect `git diff -- ` hunk by hunk; never - commit a hunk you didn't write. -2. **DO NOT DEPLOY** to archi-dev-box right now. A frontend deploy would ship their - in-progress BotFights work plus unreviewed security changes to the node together. -3. **Never touch the user's dev servers:** `:8100` (vite), `:5959` (mock backend), - `:5173` (AIUI dev), `:3141` (claude-api-proxy). Never use broad `pkill` patterns — - an earlier agent killed the user's `:8100` session that way. Kill only exact PIDs - you started; use port 8104+ for your own. - -## Critical anti-patterns - -| Anti-pattern | Severity | Why | -|---|---|---| -| Changing existing visuals/animations during perf or refactor work | blocking | 02-02's KeepAlive restructure broke page margins and the up/down slide transitions; caught only at a human checkpoint, needed a dedicated fix commit. Perf work must be visually invisible. `keepAliveTabs.test.ts` structurally pins the DOM shape — if a change breaks it, the change is wrong. | -| Broad `pkill` / `git add -A` / `git stash` in a shared tree | blocking | Both have already destroyed or risked others' work in this project this session. | -| Parking review/verifier findings as "advisory" | blocking | User's explicit rule: findings get fixed in the same run, not deferred. | -| Trusting a CSS-selector remount probe | major | The generic `.view-container [data-controller-container]` selector cannot disambiguate the foreground tab from other still-connected KeepAlive-cached tabs; it produced a false "Server remounts" verdict that cost a whole gap-closure cycle. Use `vm.$.uid` (see `keepalive-remount-probe.spec.ts`). | - -## In-flight background agents (may still be running) - -| Agent | Owns | Deliverable | -|---|---|---| -| 02-10 executor | `02-PERF-REMEASURE.json`, `02-FINDINGS.md`, `02-10-SUMMARY.md`, STATE/ROADMAP | Verdict for 6 surfaces: cleared-as-noise / fixed / accepted deviation | -| security follow-up | `stores/resources.ts`, `composables/useCachedResource.ts`, persist call sites, `vite.config.ts`, `PWAUpdatePrompt.vue`, `02-REVIEW.md` | One-time snapshot purge, `persist` required everywhere, PWA auto-update | - -If neither has committed and both are gone, their work is recoverable from the plan -files and `02-REVIEW.md`; re-dispatch rather than guessing. - -## Next actions, in order - -1. Wait for / confirm 02-10 + security follow-up commits. -2. **Re-run `gsd-verifier` on phase 02** against `02-VERIFICATION.md`'s two gaps - (gap 1 closed by 02-09; gap 2 by 02-10). If passed → `phase.complete`. -3. **VPS2 domain migration** — see `.planning/todos/pending/2026-07-30-migrate-source-references-to-https-domain.md`. - ~196 refs of `146.59.87.168` → `https://source.archipelago-foundation.org`; - `companion.archipelago-foundation.org` and `fips.archipelago-foundation.org` are now - live (DNS verified). Needs a core Rust rebuild + on-node verification. NOTE: - `core/target` was deleted to reclaim disk, so the first cargo build will be slow. -4. **Phase 1 (federation & mesh hardening)** — 10 existing plans, PLUS a required gap - plan for the 8 items the user added on 2026-07-30: FED-07 (fedimint gateway ships - with a pre-set password — security blocker) and UIFIX-01..06 (FIPS/Tor pills on - mobile, connected-nodes scroll height, onboarding tickbox on short screens, Paid - Files lightbox, PiP robustness incl. surviving tab switches + buffering, loader - states). See ROADMAP phase 1 criteria 7-13 and `.planning/todos/pending/`. - -## Environment facts - -- This machine **IS** archi-dev-box (Tailscale MagicDNS; also `100.69.68.39`). Deploys - are loopback SSH: `ARCHIPELAGO_TARGET=archipelago@archi-dev-box scripts/deploy-to-target.sh --frontend-only`. -- UI password for archi-dev-box: **ask the user** — pass at runtime as `ARCHY_PASSWORD` - env var only, never written to any file or commit. -- `archy-x250-dev` (dev pair's 2nd node) is **offline/gone** — dev-pair verification is - deferred; run single-node and record the gap honestly. -- AIUI source: `https://git.tx1138.com/lfg2025/AIUI`, working branch `development`, - local clone at `/home/archipelago/Projects/AIUI`. D-14 embed defaults + embed - round-trip fixes are pushed upstream. -- git remote `gitea-ai` now uses HTTPS via `source.archipelago-foundation.org`. -- Node disk was at 85%; ~118G reclaimed (`core/target`, `image-recipe/build`, caches). - `image-recipe/results` (~34G of ISOs) was deliberately NOT deleted — needs user OK. - -## Known-open, user-accepted items (do not re-litigate) - -- Timing regressions on Discover/Web5/Fleet/AppDetails/OpenWrtGateway — 02-10 is - producing the verdict. -- `/dashboard/settings` deliberately withheld from KeepAlive (unaudited side effects - in its child sections). -- `PeerFiles.vue` raw-store loading/refreshing conflation; `CloudFolder.vue` TTL gate — - both flagged, out of phase 02 scope.