SpeakTrue

M021 Email Signup Verification

Reader and post-read action

This document is for a future implementation or release-verification agent landing cold on the M021 email sign-up work. After reading it, the agent should be able to verify that both public browser create-account surfaces still use Supabase Auth safely, diagnose local regressions with one deterministic command, and record live smoke evidence without exposing secrets.

Scope

M021 email sign-up verification covers two public browser surfaces:

The contract is limited to browser-facing account creation, existing email sign-in, existing Google OAuth, session-neutral check-email confirmation, and the regression commands named below. It does not add a server-side sign-up endpoint; in short, there is no server-side sign-up endpoint for this contract. It does not change Supabase Auth configuration, and does not claim live proof unless the live smoke command is run with explicit test-account environment variables.

Marketing create-account flow

The marketing surface must keep its existing email-auth dialog selectors while adding a create-account mode. In create-account mode, the browser submits the entered email and password to the public Supabase browser client with auth.signUp.

Expected behavior:

  1. The user opens the email auth dialog from the marketing page.
  2. The user chooses Create account mode.
  3. The form validates that email and password fields are present before any network call.
  4. The submit button is disabled during the async auth request and restored on safe failure.
  5. A successful sign-up that does not create an immediate session shows the check-email confirmation message.
  6. The success path remains session-neutral: it must not redirect, append session-transfer fragments, call session-transfer helpers, or render raw provider payloads.

The marketing flow must preserve existing sign-in and OAuth behavior: auth.signInWithPassword remains the email sign-in path, and existing Google OAuth remains available through Supabase Auth.

Strict web-app create-account flow

The strict web-app gate must expose create-account mode without removing the existing strict-gate sign-in, Google OAuth, marketing sign-in, root render, health, or protected strict-mode behavior.

Expected behavior:

  1. The unauthenticated strict web-app root renders the strict auth gate.
  2. The user chooses Create account mode in the email auth modal.
  3. The form validates email and password before calling Supabase.
  4. The browser submits through the public Supabase client with auth.signUp.
  5. If Supabase returns no session, the UI shows check-email confirmation and stays on the gate.
  6. The create-account branch must not call strict-gate refresh helpers, reload app defaults, redirect, transfer tokens, or render raw provider payloads. More directly: it must not render raw provider payloads or tokens in status, alert, console, or markup surfaces.

If a Supabase project is configured to return an immediate real session after sign-up, downstream session observers may react to that real session. The sign-up submit branch itself must still avoid parallel redirects, token-transfer helpers, and raw payload rendering.

Check-email and session-neutral behavior

Sign-up success has two truthful outcomes, depending on Supabase Auth configuration:

The default expected M021 behavior is check-email confirmation when no session exists. A successful no-session sign-up must not call openWebAppWithSession, appendSessionTransferFragment, legacySupabaseAuthHeaders, reloadAppDefaultsAfterAuth, speaktrueSetStrictAuthGateVisible, window.location.assign, or equivalent token-transfer/redirect helpers.

Public Supabase browser boundary

Browser code may use only these public Supabase Auth operations for this contract:

Browser code must not introduce /api/auth/signup, /api/auth/sign-up, /api/auth/register, Supabase auth.admin calls, service-role/admin APIs, custom auth-table writes, Apple OAuth claims, or browser-visible secrets. It must not expose service_role, SUPABASE_SERVICE_ROLE_KEY, client_secret, private_key, passwords, access tokens, refresh tokens, or raw provider response JSON in markup, JavaScript output, console output, docs evidence, or test fixtures.

Preserved regressions

The focused regression set must continue to catch these failures:

Deterministic verification command

Run this local deterministic verifier before claiming the M021 browser sign-up contract is intact:

python3 scripts/verify_m021_s03_auth_signup.py

For the documentation/verifier guard itself, run:

web/python-web-app/venv/bin/pytest web/python-web-app/tests/test_m021_auth_signup_verification.py -q

The deterministic verifier is credential-free. It intentionally omits live Supabase Auth signup smoke checks and instead runs the focused pytest contracts plus the marketing and strict web-app browser-auth source/runtime checks.

Live smoke prerequisites

Live Supabase Auth smoke is opt-in and must use pre-provisioned test-account credentials. When the harness is available and the test environment is intentionally configured, run exactly:

SPEAKTRUE_M021_LIVE_SMOKE=1 SPEAKTRUE_M021_SIGNUP_EMAIL=<redacted-test-email> SPEAKTRUE_M021_SIGNUP_PASSWORD=<redacted-test-password> deno run -A scripts/live_m021_auth_signup_smoke.mjs

Required environment variables:

At least one target URL variable (SPEAKTRUE_M021_MARKETING_URL or SPEAKTRUE_M021_WEB_APP_URL) must be set. The harness may run one surface or both surfaces in a single invocation depending on which target variables are present.

The live smoke must fail closed when required variables are absent. It must not retry in a loop, because repeated sign-up attempts can hit Supabase Auth rate limits or create unmanaged test accounts.

Acceptable live outcomes:

Unacceptable live outcomes:

Redaction rules

All command output, docs, summaries, and evidence must redact sensitive values:

Evidence fields

When live smoke is run, record evidence with these fields:

Field Required value
Timestamp/date UTC or local date/time of the run.
Target surface Marketing, strict web-app, or both.
Command The live smoke command with email/password redacted.
Redacted identity Redacted email shape only.
Observed outcome check-email confirmation or real session observed.
Secret-safety result State that no password, token, raw provider payload, or browser-visible secret was recorded.
Exit code 0 for pass, non-zero for failure.
Notes Rate-limit, configuration, or selector diagnostics if relevant.

S04 remediation status

The S04 remediation runbook is M021 Live Signup Remediation. It distinguishes deterministic local regression proof from live Supabase signup proof and defines the allowed evidence statuses: deterministic-regression-passed, live-blocked-rescoped, live-pass, and live-failed-redacted.

Current live evidence status: blocked/re-scoped/deferred for missing pre-provisioned live-smoke configuration in the 2026-05-02 execution environment. The S04 verifier and live harness are present, and the deterministic regression can pass, but SPEAKTRUE_M021_LIVE_SMOKE, SPEAKTRUE_M021_SIGNUP_EMAIL, SPEAKTRUE_M021_SIGNUP_PASSWORD, SPEAKTRUE_M021_MARKETING_URL, and SPEAKTRUE_M021_WEB_APP_URL were unavailable, so live Supabase Auth signup proof is not validated and no live Supabase Auth signup proof is claimed.

Timestamp/date Status Target surface Command Redacted identity Observed outcome Secret-safety result Exit code Notes
2026-05-02 live-blocked-rescoped Marketing and/or strict web-app python3 scripts/verify_m021_s04_live_signup_remediation.py Not available Deterministic regression passed or can be rerun locally; live Supabase signup not validated because live-smoke env is absent. No password, token, raw provider payload, full email, service-role marker, client secret, private-key marker, or browser-visible secret was recorded. 0 for verifier blocked/re-scope path when regression/docs pass Missing live env is deferred to a provisioned operational smoke; do not claim live signup passed.