WIP: Foundry slice 1, pair a world and see its connection (#5, #6) #1368

Draft
claude-bot wants to merge 21 commits from feat/5-foundry-connect into main
Collaborator

Draft, not to merge before v4.8.0 final is cut (this is v5.0 work, and merging would ship it in 4.8.0). It's open for CI.

Slice 1 of v5.0 (D333–D342). The contract is docs/design/foundry-connection.md.

  • Backend: pairing codes (Redis DB 0, once, 10 minutes), per-GM tokens stored as sha256, the /api/foundry/ws socket, one holder per campaign across workers with handoff, status, remove and unpair. Migration f5001a1b2c3d.
  • The quest-board Foundry module, served per server (/api/foundry/module.json and a zip carrying the server's wss:// address). It has a GM-only form and a lasting status marker. Node tests run in a new CI job.
  • Settings → Foundry (CAMP-16), as drawn on lane 2b and with the wording approved (part ac, 33 rows).
  • Security: two review passes, five findings, all fixed with tests (scoped token replacement, pairer must still be a GM, transport frame cap, token bound to its Foundry user, Gamemaster only).
  • Checked live on docker-test: real Postgres, Redis and two workers. Handoff took 1.4 s on a clean close and 24 s after a worker was killed. The 64 KiB cap held. Unpair closed every socket within 8.4 s. No token appears in the logs.

Still to do before merge:

  • the first real pairing on foundry-dev with the owner at the browser (throwaway on the qb-foundry-test endpoint, ready);
  • a render check of Settings → Foundry;
  • v4.8.0 final.

🤖 Generated with Claude Code

**Draft, not to merge before v4.8.0 final is cut** (this is v5.0 work, and merging would ship it in 4.8.0). It's open for CI. Slice 1 of v5.0 (D333–D342). The contract is `docs/design/foundry-connection.md`. - **Backend:** pairing codes (Redis DB 0, once, 10 minutes), per-GM tokens stored as sha256, the `/api/foundry/ws` socket, one holder per campaign across workers with handoff, status, remove and unpair. Migration `f5001a1b2c3d`. - **The `quest-board` Foundry module,** served per server (`/api/foundry/module.json` and a zip carrying the server's `wss://` address). It has a GM-only form and a lasting status marker. Node tests run in a new CI job. - **Settings → Foundry (CAMP-16),** as drawn on lane 2b and with the wording approved (part ac, 33 rows). - **Security:** two review passes, five findings, all fixed with tests (scoped token replacement, pairer must still be a GM, transport frame cap, token bound to its Foundry user, Gamemaster only). - **Checked live on docker-test:** real Postgres, Redis and two workers. Handoff took 1.4 s on a clean close and 24 s after a worker was killed. The 64 KiB cap held. Unpair closed every socket within 8.4 s. No token appears in the logs. **Still to do before merge:** - the first real pairing on foundry-dev with the owner at the browser (throwaway on the `qb-foundry-test` endpoint, ready); - a render check of Settings → Foundry; - v4.8.0 final. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A token keeps working only while its pairer is a GM (owning the campaign
is not enough), hello needs role 4 as pairing does, and a token is bound
to the Foundry user it was made for. The module only connects for a
full Gamemaster. Also: the CAMP-16 catalogue rows for pairing, the
migration head in webapp/CLAUDE.md, and the WebSocket note for a
self-hoster's proxy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test(webapp): Foundry settings tests, lint fix, Contents count
Some checks failed
CI / Bot tests and audit (pull_request) Has been cancelled
CI / Backend lint (ruff) (pull_request) Has been cancelled
CI / Feedback site tests (pull_request) Has been cancelled
CI / Foundry module tests (pull_request) Has been cancelled
CI / Bot/backend version sync (pull_request) Has been cancelled
CI / Docker image build (pull_request) Has been cancelled
CI / Does this change touch the recording path? (pull_request) Has been cancelled
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been cancelled
CI / Which journeys does this change need? (pull_request) Has been cancelled
CI / Frontend (shard 2/2) (pull_request) Has been cancelled
CI / Frontend (shard 1/2) (pull_request) Has been cancelled
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Has been cancelled
CI / Backend migration, tests, and audit (pull_request) Has been cancelled
4e2270a43e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge remote-tracking branch 'origin/main' into feat/5-foundry-connect
Some checks failed
CI / Backend lint (ruff) (pull_request) Failing after 35s
CI / Foundry module tests (pull_request) Successful in 20s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 58s
CI / Which journeys does this change need? (pull_request) Successful in 22s
CI / Does this change touch the recording path? (pull_request) Successful in 23s
CI / Bot/backend version sync (pull_request) Successful in 29s
CI / Feedback site tests (pull_request) Successful in 1m33s
CI / Bot tests and audit (pull_request) Successful in 2m4s
CI / Docker image build (pull_request) Successful in 4m55s
CI / Backend migration, tests, and audit (pull_request) Failing after 8m30s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 11m35s
CI / Frontend (shard 2/2) (pull_request) Successful in 16m21s
CI / End-to-end journeys (phone) (pull_request) Successful in 13m2s
CI / Frontend (shard 1/2) (pull_request) Failing after 19m34s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 28m3s
CI / End-to-end journeys (desktop) (pull_request) Successful in 28m7s
036bbcfea0
fix(webapp): the Unpair confirm says what it does, and Remove sits at the row's end (#5)
Some checks failed
CI / Backend lint (ruff) (pull_request) Failing after 37s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m4s
CI / Does this change touch the recording path? (pull_request) Successful in 35s
CI / Foundry module tests (pull_request) Successful in 40s
CI / Which journeys does this change need? (pull_request) Successful in 17s
CI / Feedback site tests (pull_request) Successful in 1m35s
CI / Bot/backend version sync (pull_request) Successful in 58s
CI / Frontend (shard 2/2) (pull_request) Has been cancelled
CI / Bot tests and audit (pull_request) Has been cancelled
CI / Frontend (shard 1/2) (pull_request) Has been cancelled
CI / Backend migration, tests, and audit (pull_request) Has been cancelled
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been cancelled
CI / Docker image build (pull_request) Has been cancelled
6482412ac7
Render check: the confirm had a title and buttons only; it now repeats
the band's approved sentence (ac-030). The GM list no longer stops at
40rem, so Remove lines up at the column's right edge on desktop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
style: ruff format the Foundry socket test
Some checks failed
CI / Foundry module tests (pull_request) Successful in 18s
CI / Bot/backend version sync (pull_request) Successful in 33s
CI / Does this change touch the recording path? (pull_request) Successful in 21s
CI / Which journeys does this change need? (pull_request) Successful in 19s
CI / Backend lint (ruff) (pull_request) Successful in 1m20s
CI / Feedback site tests (pull_request) Successful in 1m40s
CI / Bot tests and audit (pull_request) Successful in 2m9s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 3m3s
CI / Docker image build (pull_request) Successful in 4m6s
CI / Frontend (shard 2/2) (pull_request) Successful in 8m1s
CI / Frontend (shard 1/2) (pull_request) Failing after 9m28s
CI / Backend migration, tests, and audit (pull_request) Failing after 9m31s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 8m55s
CI / End-to-end journeys (phone) (pull_request) Successful in 10m50s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 11m31s
CI / End-to-end journeys (desktop) (pull_request) Successful in 11m33s
9bdd5a5791
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test: the guards for the Foundry section and its tokens (#5)
Some checks failed
CI / Foundry module tests (pull_request) Successful in 15s
CI / Backend lint (ruff) (pull_request) Successful in 37s
CI / Bot/backend version sync (pull_request) Successful in 26s
CI / Which journeys does this change need? (pull_request) Successful in 32s
CI / Does this change touch the recording path? (pull_request) Successful in 34s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 57s
CI / Feedback site tests (pull_request) Successful in 1m35s
CI / Bot tests and audit (pull_request) Successful in 2m6s
CI / Docker image build (pull_request) Successful in 6m53s
CI / Frontend (shard 2/2) (pull_request) Successful in 7m44s
CI / Frontend (shard 1/2) (pull_request) Successful in 9m12s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 8m38s
CI / End-to-end journeys (phone) (pull_request) Successful in 11m20s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 12m7s
CI / End-to-end journeys (desktop) (pull_request) Successful in 13m1s
CI / Backend migration, tests, and audit (pull_request) Failing after 27m58s
0d20287c9a
CI: the settings list now has Foundry; the not-found route test asks
for a section that does not exist (every drawn one is built); and the
export ledger says foundry_tokens never travel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(webapp): the Foundry socket gets its sessions from main.py (#5)
All checks were successful
CI / Foundry module tests (pull_request) Successful in 17s
CI / Backend lint (ruff) (pull_request) Successful in 39s
CI / Bot/backend version sync (pull_request) Successful in 29s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m1s
CI / Which journeys does this change need? (pull_request) Successful in 40s
CI / Does this change touch the recording path? (pull_request) Successful in 42s
CI / Feedback site tests (pull_request) Successful in 1m36s
CI / Bot tests and audit (pull_request) Successful in 2m8s
CI / Docker image build (pull_request) Successful in 6m12s
CI / Frontend (shard 2/2) (pull_request) Successful in 8m21s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 8m58s
CI / Frontend (shard 1/2) (pull_request) Successful in 10m12s
CI / End-to-end journeys (phone) (pull_request) Successful in 23m48s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 25m35s
CI / End-to-end journeys (desktop) (pull_request) Successful in 25m59s
CI / Backend migration, tests, and audit (pull_request) Successful in 39m37s
eb6417c1f2
CI: tests/test_task_session_hygiene.py allows the pooled
AsyncSessionLocal only in database.py, main.py and cli.py. The socket
is a web connection, not a Celery task, so main.py hands the factory to
it through app.state rather than the router importing it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All checks were successful
CI / Foundry module tests (pull_request) Successful in 17s
Required
Details
CI / Backend lint (ruff) (pull_request) Successful in 39s
Required
Details
CI / Bot/backend version sync (pull_request) Successful in 29s
Required
Details
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m1s
Required
Details
CI / Which journeys does this change need? (pull_request) Successful in 40s
Required
Details
CI / Does this change touch the recording path? (pull_request) Successful in 42s
Required
Details
CI / Feedback site tests (pull_request) Successful in 1m36s
Required
Details
CI / Bot tests and audit (pull_request) Successful in 2m8s
Required
Details
CI / Docker image build (pull_request) Successful in 6m12s
Required
Details
CI / Frontend (shard 2/2) (pull_request) Successful in 8m21s
Required
Details
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 8m58s
Required
Details
CI / Frontend (shard 1/2) (pull_request) Successful in 10m12s
Required
Details
CI / End-to-end journeys (phone) (pull_request) Successful in 23m48s
Required
Details
CI / End-to-end journeys (keyboard) (pull_request) Successful in 25m35s
Required
Details
CI / End-to-end journeys (desktop) (pull_request) Successful in 25m59s
Required
Details
CI / Backend migration, tests, and audit (pull_request) Successful in 39m37s
Required
Details
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/5-foundry-connect:feat/5-foundry-connect
git switch feat/5-foundry-connect
Sign in to join this conversation.
No description provided.