v1.1.0 Phase 1: Postgres test tier + CI hardening #94

Merged
claude-bot merged 4 commits from feat/v1.1.0-postgres-ci into main 2026-07-18 15:49:20 +00:00
Contributor

First slice of the v1.1.0 milestone — the test/CI foundation everything else rides on.

#68 — Postgres integration test tier

  • Gated the conftest JSONB→JSON monkeypatch on WEATHERBOT_TEST_DB=postgres, so a Postgres tier runs as a separate pytest invocation against a real PostgreSQL (real JSONB / FK / unique-NULL semantics). New pg_engine/pg_db fixtures build the schema from ORM metadata; @pytest.mark.postgres tests are excluded from the default SQLite run (addopts = -m "not postgres").
  • Postgres-tier tests: sent_alerts UNIQUE dedup under asyncpg, dashboard NULL-channel rows not deduped (documents the gap #57 will close), channel-delete ON DELETE SET NULL (the authoritative F-09 check SQLite couldn't do), and a pg_notify LISTEN/NOTIFY round-trip (the SSE contract).
  • Coverage-gap unit tests: VTEC parsing edges, SPC GIF assembly/fallback, AI total-timeout branch. (SPC cross-day/reissuance and notifier-link gaps already got tests in v1.0.2.)
  • Corrected CLAUDE.md's stale "no automated tests" note.

#65 — CI hardening

  • Added a postgres:16-alpine service and steps for ruff (permissive starter: E9/F63/F7), alembic upgrade head against a fresh PG (catches migration-chain errors), the SQLite bulk tier, and the Postgres tier.
  • pip-audit runs as an advisory (non-blocking) step — see below.
  • cd.yml unchanged (its pytest excludes the postgres marker by default, so no PG service needed).

Verified on the dev server (mirrors this CI)

ruff clean · alembic upgrade head clean through 0018 · SQLite tier 429 passed · Postgres tier 4 passed.

⚠️ Decision embedded: pip-audit is advisory, not gating

pip-audit --strict currently fails on a backlog of advisories in the pinned stack (starlette, pyjwt, python-multipart, python-dotenv, setuptools) — all cleared by the pending Renovate upgrades (#30–#37), which are out of scope for this test/CI slice. So pip-audit runs continue-on-error: true for now; once the Renovate backlog lands it's a one-line change to --strict gating. Flagging in case you'd rather prioritize those dependency upgrades to enable strict gating sooner.

Closes #65, #68

🤖 Generated with Claude Code

First slice of the v1.1.0 milestone — the test/CI foundation everything else rides on. ## #68 — Postgres integration test tier - Gated the conftest JSONB→JSON monkeypatch on `WEATHERBOT_TEST_DB=postgres`, so a Postgres tier runs as a separate pytest invocation against a real PostgreSQL (real JSONB / FK / unique-NULL semantics). New `pg_engine`/`pg_db` fixtures build the schema from ORM metadata; `@pytest.mark.postgres` tests are excluded from the default SQLite run (`addopts = -m "not postgres"`). - **Postgres-tier tests**: `sent_alerts` UNIQUE dedup under asyncpg, dashboard NULL-channel rows *not* deduped (documents the gap #57 will close), channel-delete `ON DELETE SET NULL` (the authoritative F-09 check SQLite couldn't do), and a `pg_notify` LISTEN/NOTIFY round-trip (the SSE contract). - **Coverage-gap unit tests**: VTEC parsing edges, SPC GIF assembly/fallback, AI total-timeout branch. (SPC cross-day/reissuance and notifier-link gaps already got tests in v1.0.2.) - Corrected CLAUDE.md's stale "no automated tests" note. ## #65 — CI hardening - Added a `postgres:16-alpine` service and steps for **ruff** (permissive starter: E9/F63/F7), **`alembic upgrade head`** against a fresh PG (catches migration-chain errors), the **SQLite bulk tier**, and the **Postgres tier**. - **pip-audit** runs as an *advisory (non-blocking)* step — see below. - `cd.yml` unchanged (its `pytest` excludes the postgres marker by default, so no PG service needed). ## Verified on the dev server (mirrors this CI) ruff clean · `alembic upgrade head` clean through 0018 · **SQLite tier 429 passed** · **Postgres tier 4 passed**. ## ⚠️ Decision embedded: pip-audit is advisory, not gating `pip-audit --strict` currently fails on a backlog of advisories in the pinned stack (starlette, pyjwt, python-multipart, python-dotenv, setuptools) — all cleared by the **pending Renovate upgrades (#30–#37)**, which are out of scope for this test/CI slice. So pip-audit runs `continue-on-error: true` for now; once the Renovate backlog lands it's a one-line change to `--strict` gating. Flagging in case you'd rather prioritize those dependency upgrades to enable strict gating sooner. Closes #65, #68 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Introduce a Postgres-backed test tier for behaviours SQLite can't express. The
conftest JSONB->JSON monkeypatch is now gated on WEATHERBOT_TEST_DB=postgres so
the tier runs as a separate pytest invocation against a real PostgreSQL with real
JSONB/FK/unique-NULL semantics; new pg_engine/pg_db fixtures build the schema from
ORM metadata. Tests marked `postgres` are excluded from the default (SQLite) run
via pytest.ini addopts.

New Postgres-tier tests: sent_alerts UNIQUE dedup under asyncpg, dashboard
NULL-channel rows not deduped (documents the gap #57 will close), channel-delete
ON DELETE SET NULL (the authoritative F-09 check), and a pg_notify LISTEN/NOTIFY
round-trip (the SSE contract). New unit tests close the remaining named gaps: VTEC
parsing edges, SPC GIF assembly/fallback, and the AI total-timeout branch.

Correct CLAUDE.md's stale "no automated tests" note.

Closes #68

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI: run migrations + Postgres tier on real Postgres; add ruff + pip-audit
Some checks failed
CI / test (pull_request) Has been cancelled
f70b65eaaf
Add a postgres:16-alpine service to the CI job and gate PRs on more than
compile+pytest: ruff (permissive starter rule set — E9/F63/F7), `alembic upgrade
head` against a fresh Postgres to catch migration-chain errors, the SQLite bulk
tier, and the new Postgres integration tier (WEATHERBOT_TEST_DB=postgres
pytest -m postgres). pip-audit runs as an advisory (non-blocking) step for now:
the pinned stack has an advisory backlog that the pending Renovate upgrades
(#30-#37) clear — flip it to `--strict` gating once that lands.

cd.yml is unchanged: its pytest run excludes the postgres marker by default, so
it needs no Postgres service.

Closes #65

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI: harden Postgres job — bound timeout, self-probe DB host, cap pip-audit
Some checks failed
CI / test (pull_request) Has been cancelled
853e6f9043
The initial run hung on the runner's service health-wait. Remove the service
health-cmd and instead probe readiness in a step that also auto-detects whether
the Postgres service is reachable as `postgres` (containerized job) or
`localhost` (host job), exporting PG_HOST for later steps. Add a 20-minute job
timeout and wrap pip-audit in `timeout` so no step can wedge the shared runner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ci: re-trigger CI
Some checks failed
CI / test (pull_request) Failing after 4s
c409fb5c2f
Empty commit to force a fresh pull_request run after the previous run was
cancelled mid-flight (the synchronize event did not spawn a new run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rbrooks force-pushed feat/v1.1.0-postgres-ci from c409fb5c2f
Some checks failed
CI / test (pull_request) Failing after 4s
to 91fdcebe01
All checks were successful
CI / test (pull_request) Successful in 3m48s
2026-07-18 15:43:31 +00:00
Compare
claude-bot deleted branch feat/v1.1.0-postgres-ci 2026-07-18 15:49:21 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/WeatherBot!94
No description provided.