Hermetic Supabase test guard (global autouse)

Date: 2026-08-05 · Commit: entirely-api 0eb8a99 · Type: decision

Problem class

Host-side pytest runs use the real /opt/unlikely-api/.env. A test that mocks its own module’s get_client (e.g. supabase_write_service.get_client) still leaks to production when the exercised code path calls a downstream service that resolves services.supabase_service.get_client itself. Instance that proved it: migration-031 status_event_service inserted 2 fake-project rows into prod project_status_events on 2026-08-05 (deleted same day).

Decision

Replace the narrow per-module conftest stub with a global autouse fixture in tests/conftest.py that patches at the choke point: supabase_service._client (the singleton get_client() returns) + create_client as backstop. This covers all ~60 importers regardless of import style (top-level bind or function-local), because they bind the function, not the client.

  • Per-test overrides unaffected: tests monkeypatch their own module’s get_client attribute, which shadows the real function entirely.
  • The stub records tables touched; pytest_sessionfinish prints them so unmocked paths stay visible instead of silently no-opping.
  • Only bypass in tree: services/status_poller.py (standalone cron, own create_client, imported by nothing tests touch).

Audit result (empirical, from the recorder)

3 test cases reached the real client before the guard:

  • test_supabase_write_service.py ×2 → project_status_events (the known leak)
  • test_holding_pool_actions.py::test_shepherd_findings_include_hold_follow_up_due → real reads on projects via pipeline_shepherd (previously unguarded)

Verification

366 passed, 1 skipped in ~9s (--ignore=tests/test_cert_pipeline.py, known pillow_heif host-side collection failure). project_status_events canary count 0 → 0 across the run.