Magic-link email
`/api/auth/email/start` issues a short-lived login link through the configured no-cost outbound provider. Local CI uses `local_synthetic_sink` and never sends mail.
Authentication
Google or email sign-in opens a `polis_session` HttpOnly cookie so a newcomer can finish setup. The public path is simple: sign in, answer setup questions, meet a member who confirms you're real before your first room, then receive placement only after that check.
`/api/auth/email/start` issues a short-lived login link through the configured no-cost outbound provider. Local CI uses `local_synthetic_sink` and never sends mail.
Google or email sign-in opens the private page first; setup questions come next; a member confirms you're real before the first room is placed.
The verified personhood binding lives in `polis_verified_pop_bindings`, keyed by email hash. It drives the `personhoodVerified` account state and gates real-room placement; it does not block access-first sign-in.
The Google callback no longer creates `polis_pending_auth` or rows in `polis_pending_auth_handoffs`. The retained `/api/auth/google/pending/exchange` path stays documented as fail-closed defensive code.
`/api/auth/session/refresh` accepts only an existing signed session and returns a refreshed `polis_session` cookie with `HttpOnly; Secure; SameSite=Lax`.
The Worker compares the cookie proof mode to the stored account proof mode and rejects mismatches with `AUTH_POP_SESSION_MISMATCH`.
Secret values live only in Infisical at `/polis/socialmedia2_com`: `POLIS_AUTH_SESSION_SECRET`, `POLIS_EMAIL_LOGIN_SIGNING_SECRET`, and provider keys by name.
Google OAuth and real outbound email provider setup are tracked separately in GitHub issues #132 through #149 and must remain no-cost unless explicitly approved.