diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index cd6dff73..3220a434 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -1,7 +1,14 @@ name: integration (local supabase) +# `pull_request` is deliberate and deliberately unfiltered. Until #574 this lane +# ran only after a merge, so the one gate built to catch route/schema drift was +# structurally incapable of failing a PR: #574 added a test file demanding env +# this workflow did not set, merged green, and left main red for three pushes. +# A paths filter would buy back ~5 minutes on frontend-only PRs at the cost of a +# narrower version of the same blind spot, so the whole lane runs on every PR. on: workflow_dispatch: + pull_request: push: branches: [main] @@ -33,5 +40,20 @@ jobs: SUPABASE_DB_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres python -m db.migrate cp .env.local.example .env python -m db.seed_local_rich + # Function mode is a requirement of the lane, not a preference: the quiz + # subcutaneous tests (#545) drive `generate`/`answer`/`submit` through real + # HTTP, so without the seam they would call live Gemini. Their autouse + # fixture raises rather than skips when it is unset — a skip would report + # green having run nothing — which is what turned this step red. Set here + # rather than in the fixture so every test in the lane sees one mode, and + # mirroring e2e.yml, the other runner of these handlers. + # + # Safe to apply lane-wide: no other integration test constructs an agent, + # so nothing here can trip UnregisteredHandlerError. `.env.local.example` + # (copied to .env above) defines neither variable, so the integration + # conftest's load_dotenv(override=True) cannot clobber them. - name: Run integration tests + env: + SAPLING_MODEL_MODE: function + SAPLING_FUNCTION_HANDLERS: agents.function_handlers_e2e run: RUN_INTEGRATION=1 python -m pytest -m integration -q diff --git a/docs/local-supabase.md b/docs/local-supabase.md index 63fa0af5..b25ee4c7 100644 --- a/docs/local-supabase.md +++ b/docs/local-supabase.md @@ -178,12 +178,19 @@ The script refuses to run against a non-local `SUPABASE_URL`. With the local stack up and `backend/.env` active, from `backend/`: - RUN_INTEGRATION=1 python -m pytest -m integration -q + SAPLING_MODEL_MODE=function SAPLING_FUNCTION_HANDLERS=agents.function_handlers_e2e \ + RUN_INTEGRATION=1 python -m pytest -m integration -q These bypass the hermetic mocks and hit the real local Supabase (real Postgres, encryption round-trips, migrated schema). Skipped by default. The suite seeds the rich dataset (idempotent) on first run and never resets your DB. +The function-mode variables are not optional. The quiz subcutaneous tests (#545) +drive the write paths through real HTTP, so without the seam they would call live +Gemini; their fixture raises rather than skips when it is unset, so the bare +`RUN_INTEGRATION=1 …` invocation errors out. `.github/workflows/integration.yml` +sets the same pair. + ## Test-profile production build (`build:test` / `start:test`, #380) `npm run dev` is fine for hand-testing, but browser E2E (Playwright) should run