Test guest adoption routing, expiry and repeat claims
Summary
Closes the fixture-coverage gaps of Done-when 3 for the guest funnel ("test existing and new accounts, multiple workspaces, expired sessions and repeated adoption; do not imply roster membership") on the already-merged guest RPCs. tests/test_context_guest_adoption.py reuses the research fixture (real Context foundation, Spotify pipeline, guest, canonical release and roster-isolation migrations) and covers: ready and running guest work adopted into the personal workspace; organization adoption that records the verified account as created_by and the organization as owner_id with workspace-scoped read_context_request; a second workspace, another account, or an account created after the guest started being refused with Guest work already claimed once work is adopted; an existing explicit roster identity reused by adoption without new roster rows; expired unclaimed sessions unavailable to read, adopt, restart, complete or re-lease; idempotent repeated adoption (reused: true, same request) before and after expiry; purge retaining the claimed receipt while deleting unclaimed work; and anon/authenticated denial. Every adoption asserts zero account_artist_ids / artist_organization_ids rows. No migration is added. The onboarding CI job gains one discovery line and tests/README.md documents the suite.
Refs recoupable/app#2145 (child of epic recoupable/app#2116).
Merge sequencing
database → api. Sibling PR for this ticket: recoupable/api branch claude/ctx-2145-guest-adoption-tests (routing contract tests). Both are tests-only and independently mergeable; neither depends on an OPEN PR. Builds on merged database#72 (guest RPCs) and database#91 (20261009190000_context_research_without_roster.sql).
Verification
- Ran:
export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH" LC_ALL=C; python3 -m py_compile tests/test_context_guest_adoption.py→ ok - Ran:
python3 -m unittest discover -s tests -p 'test_context_guest_adoption.py'→ Ran 29 tests, OK (11 new cases + 18 inherited onboarding regressions through the fixture) - Ran:
python3 -m unittest discover -s tests -p 'test_*roster.py'→ Ran 38 tests, OK (research roster 27 + professional roster 11 unchanged) - Ran:
python3 -c "import yaml;yaml.safe_load(open('.github/workflows/artist-onboarding.yml'))"→ ok;grep -n test_context_guest_adoption .github/workflows/artist-onboarding.yml→ 1 line - Ran:
git diff --name-only origin/main | grep -c supabase/migrations→ 0 - Red → green: one-off mutation run (not committed) pointed the fixture's
CORRECTIONat a missing file so the suite ran against the pre-#91 schema: 8 of the 11 new tests failed (account_artist_ids'2' != '0', i.e. adoption would have enrolled a roster). With the merged correction applied, all 29 pass. - Not verified: hosted/production database (no migration applied anywhere), live providers (fixtures only), hosted deployment, the GitHub Actions run itself (local run used PostgreSQL 17; CI pins 16), Chat UI behaviour.
Out of scope / known gaps
- Campaign attribution on guest start (separate guest-row column carried onto the adopted request outside
input/topics) — needs its own migration + API + docs slice. - Chat organization destination picker (UI still claims into the personal account).
- Live browser verification of SCENARIOS S17/S32 remains pending.
- macOS note documented in
tests/README.md: setLC_ALL=Cifpg_ctlreports the postmaster became multithreaded.
🤖 Generated with Claude Code
Summary by cubic
Adds a test suite for the merged guest adoption RPCs, closing the Done-when 3 fixture gaps for recoupable/app#2145 without adding a migration. It reuses the research fixture and runs 29 tests (11 new plus 18 inherited onboarding regressions).
Coverage:
- Personal and organization adoption with actor/owner separation and workspace-scoped reads; second workspaces, other accounts, and accounts created after guest start refused with "Guest work already claimed".
- Expired unclaimed sessions unavailable to read, adopt, restart, complete, or re-lease; repeat adoption idempotent before and after expiry; purge keeps claimed receipts and removes unclaimed work.
- Existing explicit roster identity reused without new roster rows; every adoption asserts zero roster rows; anon/authenticated roles denied; suite added to the onboarding CI job and documented in
tests/README.md.