Skip to content

SPRINT-2 Gate F Report — Closeout + SPRINT-3 Kickoff

Status: SPRINT-2 CLOSED — awaiting Ryan SPRINT-3 go
Date: 2026-08-28
Prerequisite: Gate E pass (Ryan E-1..E-4)


Summary

SPRINT-2 (RealOutcomes auth unification via auth.last1.id) is complete. VM 117 GoTrue is retired. RealOutcomes on VM 116 authenticates exclusively through Last1 ID OIDC. Ryan verified both primary accounts, app surfaces, and network isolation (zero traffic to VM 117 /auth/v1/*).

Next: SPRINT-3 (realoutcomes-edge tunnel + realoutcomes.app production cutover). No execution until Ryan replies SPRINT-3 go.


Gate F verification (Ryan)

# Test Result
E-1 ryan@last1.enterprises login, admin badge, Veterans watchlist PASS
E-2 ryan@last1.org login, id 536a1797… unchanged PASS
E-3 Directory, watchlists, portfolio load PASS
E-4 Auth traffic only to auth.last1.id; no VM 117 :8000/auth/v1/* PASS

SPRINT-2 deliverables (Gates A–F)

Gate Work Report
A app_clients + BWS + REALOUTCOMES_APP_SECRET SPRINT-2_GATE_A_REPORT.md
B Last1 ID SDK + JWKS server auth SPRINT-2_GATE_B_REPORT.md
C Deploy VM 116 + OAuth smoke SPRINT-2_GATE_C_REPORT.md
D User ID FK remap + login verification SPRINT-2_GATE_D_REPORT.md
E Retire VM 117 GoTrue SPRINT-2_GATE_E_REPORT.md
F Closeout (this report) —

Execution plan: SPRINT-2_REALOUTCOMES_AUTH_EXECUTION_PLAN.md


Pattern lesson: Gate D UUID correction (52ce85f9 vs 396e95ce)

What happened

During Gate D FK remap for ryan@last1.enterprises, an initial target UUID 52ce85f9… was taken from an auth.identities (or secondary identity) row. The live OAuth id_token.sub uses public.identities.id = 396e95ce-abac-42e2-9980-c08f19a1af1d. Remap to the wrong id would have left child rows (watchlists, admin profile, search history) orphaned from the identity Ryan actually logs in with.

The error was caught in-session and corrected to 396e95ce… before Ryan login verification.

Root cause

Mistake Why it fails
Infer remap target from any identity table row matching email Multiple UUIDs can exist per email (legacy Supabase row, orphan OAuth upsert, provider linkage rows)
Trust Supabase-era public.users.id Pre-OAuth ids (d1034389…) do not match sovereign id_token.sub
Trust auth.identities.id without confirming token claim OAuth issuer emits sub from public.identities.id, not necessarily every related row

Correct pattern (binding for future product migrations)

  1. Source of truth for remap target: decode a real OAuth id_token (or /api/auth/user after one successful login) and use sub verbatim.
  2. Pre-remap: pg_dump full public + auth schemas; document every FK column touching user_id.
  3. Post-remap: assert one public.users row per email; assert users.id = sub for each test account; assert zero orphan FK rows.
  4. Never remap until Gate C OAuth loop proves which sub the app persists (callback upsert path is authoritative).
  5. Cross-check last1.id PostgREST: identities.id for email must equal chosen remap target before transaction.

One-line rule

Remap to id_token.sub, not to "an identity UUID we found in the database."

Document in runbooks for SPRINT-6 (Onset, real users) and any future FK migration.


DB / infra state at SPRINT-2 close

Component State
RealOutcomes auth auth.last1.id OIDC (PKCE + JWKS)
VM 117 GoTrue Retired (rollback backup on VM 117)
VM 117 stack Postgres, Envoy, REST, Storage, Edge Functions, Supavisor — running
App DATABASE_URL (VM 116) Still hosted Supabase (Gate D remap target); VM 117 DB is rehearsal stack until T3/SPRINT-5 cutover
Prod DNS realoutcomes.app still on Railway until SPRINT-3

SPRINT-3 pointer

Plan for Ryan review: SPRINT-3_REALOUTCOMES_EDGE_EXECUTION_PLAN.md

Reply SPRINT-3 go to authorize tunnel install + production DNS cutover.


END Gate F / SPRINT-2 closeout