ci: run PostgreSQL tests in isolated lane (#6730)

## Why

PR #6660 introduced four PostgreSQL-backed persistence tests and a
focused CI selector, but an exact test-name list does not automatically
cover future database tests. Broad ignored-test execution also exposed
shared-schema races and ambiguity between desired-state and
migration-applied schema expectations.

## What

- Establish a discoverable convention: PostgreSQL unit modules use
`postgres_tests`, PostgreSQL integration binaries use a `postgres_`
prefix, and unrelated external-infrastructure tests use an
`external_infra_` prefix.
- Add a dedicated nextest PostgreSQL profile and archive-backed CI job
covering the relevant crates without enumerating test names.
- Create a run-scoped desired-state source database and a unique
PostgreSQL database per test process for parallel-safe isolation, with
cleanup on success, failure, or interruption.
- Route destructive migration and migration-parity tests to clean
`template0` databases while desired-state tests clone the desired-state
database.
- Document discovery, schema modes, required role privileges, and a
bounded portable local runner.
- Keep the existing infrastructure-free unit-test jobs unchanged.

This is intentionally limited to test and CI harness behavior. It does
not move production database code, change persistence semantics, or
implement issue #20's broader shared test-utility refactor.

## Risk

Low production risk because all changes are confined to tests, CI
configuration, documentation, and test harness scripts.

Remaining operational risks:

- Cleanup retries `dropdb --force` five times across roughly four
seconds. Exhaustion warns with the database name but deliberately does
not mask the test result; individual PostgreSQL diagnostics are
suppressed.
- The seven-package boundary is duplicated between the runner and CI
archive and must remain synchronized if PostgreSQL tests move to a new
crate.
- Portable SHA fallback branches were exercised on Linux; no macOS Blox
workstation was needed for this Linux CI artifact.
- GitHub's unchanged generic Unit Tests job currently fails while
cold-linking `buzz-voice` because `sherpa-onnx-c-api` is absent. The
branch changes no voice/build/toolchain inputs; the exact parent
previously passed that job, and Blox passes the same infrastructure-free
suite (1,450/1,450). A prior-head one-job retry and the final-head run
both reproduced the hosted-runner failure.

## Verification

Author Blox workstation `2020088`:

- `cargo fmt --all -- --check`
- `just clippy`
- `just test-unit`: 1,450 passed; PostgreSQL tests remain skipped in
fast jobs
- PR #6660 focused tests: 4/4 passed through the final runner
- Full lane: 282/282 passed in 10.087s with a non-superuser role limited
to `CREATEDB`, `CREATEROLE`, and `pg_read_all_stats`
  - 272 desired-state tests
  - 10 migration-applied tests
  - 6 explicitly filtered external-infrastructure tests
- Cleanup fault injection: a deliberately underprivileged 282-test run
produced the expected 277 passes and 5 failures, and the post-run
catalog audit found zero lane databases after retry cleanup. The
restored successful run also left zero lane databases.

GitHub exact final head `92c231e48f299ea2af23817763f5ae80ac013d68`:

- [PostgreSQL
Tests](https://github.com/block/buzz/actions/runs/32789030203/job/97630827823):
282/282 passed across 10 binaries in 98.886s; 1,240 skipped, including 6
via the profile filter
- The shared relay/PostgreSQL archive predecessor completed successfully
- [Unit
Tests](https://github.com/block/buzz/actions/runs/32789030203/job/97626930420):
unrelated `sherpa-onnx-c-api` native-link failure described above
- Independent exact-head review on separate Blox workstation `2022762`:
no substantive findings after all initial findings were addressed. The
reviewer independently verified cleanup retry behavior, exit-status
preservation, shell portability, syntax, and a clean exact-head
worktree.

## References

- Stacked on #6660 at exact head
`561de54be4d9c2b622b7c2aa5b61bc3068f47e2a`
- https://github.com/TheSentinel454/buzz/issues/20
-
https://github.com/TheSentinel454/buzz/issues/20#issuecomment-5398526792

Generated with Codex.

## Update — August 24, 2026 review follow-up

- Centralized the repeated PostgreSQL test URL resolution in
crate-local, test-only helpers without introducing the broader shared
utility refactor from issue #20.
- Restored descriptive hybrid/Redis test function names. Structural
`external_infra_*_tests` modules now own exclusion, and the nextest
filter only recognizes module path segments.
- Added a three-second source guard that scans every Rust file and fails
CI when an ignored PostgreSQL test would be omitted or an
external-infrastructure test would be included. Fixture tests cover
accepted modules/binaries and both failure modes.
- Removed the two implementation-plan documents.

Performance profiling on Blox workstation `2027352` (same prebuilt
archive and cargo-nextest 0.9.143 for every comparison):

- Current per-test database model, 8 workers: 10.15–10.40s across three
runs. The 283 `createdb` calls and 284 `dropdb` calls consumed
28.85–29.46 aggregate seconds, about 39–40% of aggregate test-process
duration.
- Reusing one database per worker without cleanup: 6.55–6.84s, about 35%
faster, but all three runs failed because global matcher-queue tests
inherited a quiesced community from an earlier test; the failing test
varied with scheduling.
- Reusing workers with `TRUNCATE … RESTART IDENTITY CASCADE`: all 282
tests passed, but total time regressed to 10.47–10.67s. The 265 truncate
calls consumed 24.34–25.45 aggregate seconds, so truncation merely
replaced most clone/drop cost.
- Raising concurrency to 16 workers reduced one isolated-database run to
8.79s, but 24 workers exposed a cluster-global `pg_stat_activity` race.
The profile remains at the proven-safe 8 workers.

Decision: retain unique per-test databases. Harness cleanup uses `dropdb
--if-exists --force`; it drops the database rather than truncating
tables or deleting rows.

Verification at local branch head
`60086c1f6ee34a193c342255a5e8e6293b60e988`:

- Discovery inventory: exactly 282 intended tests; all 6 hybrid/Redis
tests present and structurally excluded.
- PR #6660 focused persistence tests: 4/4 passed.
- Full PostgreSQL lane: 282/282 passed three times; 1,240 skipped each
run; wall time 9.72–9.96s without profiling shims.
- Non-ignored tests with a desired-state database: 1,234/1,234 passed;
one mesh-demo timeout from the first run passed immediately in
isolation.
- `cargo fmt --all -- --check` and all-target/all-feature clippy for
`buzz-db`, `buzz-deletion`, and `buzz-relay` passed.

Final independent re-review at exact head
`42097c0136ab3fa8f0efe5720ae829c04575b9b6` on separate Blox workstation
`2028455`: no substantive residual findings. The reviewer independently
exercised ordinary strings, zero/one/three-hash raw strings, line/block
comments, and string-contained lookalikes, then reran the full 353-file
scan, shell syntax, Python AST parsing, and diff check.

Independent review found that the source guard's initial regular
expression could miss raw-string ignore reasons and treat a commented
attribute as real. Final head `42097c0136ab3fa8f0efe5720ae829c04575b9b6`
parses valid ordinary/raw Rust string literals only at attributes found
in comment-sanitized source; regression fixtures cover both cases. The
fixture suite, Python compilation, shell syntax, diff check, and full
353-file repository scan pass on Blox.

## Update — August 25, 2026 restack

PR #6660 merged, so this follow-up was rebased from its former exact
parent onto current `origin/main`
(`8d2d0ff5ad42733e9949442c4b6358d0ba87f9a8`). The final candidate head
is `05dcc2ab28948e3ab79bb44839a69f2ba44648a2`; the PR no longer carries
#6660's pre-squash history.

Fresh exact-head verification on Blox workstation `2028572`:

- Discovery guard passed across 353 Rust files; inventory remained
exactly 282 intended PostgreSQL tests.
- PR #6660 focused persistence tests: 4/4 passed.
- Full PostgreSQL lane: 282/282 passed three times; 1,243 skipped each
run; wall time 9.70–9.87s.
- `cargo fmt --all -- --check` and all-target/all-feature clippy for
`buzz-db`, `buzz-deletion`, and `buzz-relay` passed.

## Update — August 25, 2026 final hosted verification

- [GitHub PostgreSQL
Tests](https://github.com/block/buzz/actions/runs/32801679226/job/97667835080):
282/282 passed in 53.787s; 1,243 skipped.
- The final guard scanned all 353 Rust files successfully before the
hosted lane ran.
- The shared relay/archive prerequisite and infrastructure-free Unit
Tests job both passed at exact final head
`42097c0136ab3fa8f0efe5720ae829c04575b9b6`.

---------

Signed-off-by: Luke Tornquist <tornquist@squareup.com>
Signed-off-by: tornquist <tornquist@squareup.com>
This commit is contained in:
Luke Tornquist
2026-09-01 12:07:28 -04:00
committed by GitHub
parent 114dbf745f
commit bd73490418
62 changed files with 1621 additions and 444 deletions

View File

@@ -44,6 +44,14 @@ jobs:
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- '.config/nextest.toml'
- 'scripts/postgres-test-*.sh'
- 'scripts/reconcile-schema-after-pgschema.sql'
- 'bin/pgschema'
- 'bin/.pgschema-*.pkg'
- 'scripts/check-postgres-test-discovery.py'
- 'scripts/test-postgres-test-discovery.sh'
- 'scripts/test-postgres-test-wrapper.sh'
- 'deny.toml'
- '.github/workflows/ci.yml'
- 'scripts/run-tests.sh'
@@ -73,6 +81,11 @@ jobs:
- 'scripts/test-mobile-worktree-overrides.sh'
- '.github/workflows/mobile-release-candidate.yml'
- '.github/workflows/ci.yml'
- name: Validate PostgreSQL test discovery
if: github.event_name == 'push' || steps.filter.outputs.rust == 'true'
run: |
scripts/test-postgres-test-discovery.sh
scripts/test-postgres-test-wrapper.sh
- name: Release workflow source contract
run: scripts/test-release-ref-contract.sh
- name: Relay image eligibility contract
@@ -350,7 +363,8 @@ jobs:
target/ci/buzz-relay
target/ci/git-credential-nostr
target/ci/backend-integration-tests.tar.zst
key: relay-artifacts-${{ runner.os }}-${{ hashFiles('crates/**', 'migrations/**', 'Dockerfile', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo/config.toml', '.github/workflows/ci.yml') }}
target/ci/postgres-tests.tar.zst
key: relay-artifacts-${{ runner.os }}-${{ hashFiles('crates/**', 'migrations/**', 'Dockerfile', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo/config.toml', '.config/nextest.toml', 'scripts/postgres-test-*.sh', 'scripts/check-postgres-test-discovery.py', '.github/workflows/ci.yml') }}
- uses: rui314/setup-mold@7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3 # v1
if: steps.relay-artifacts-cache.outputs.cache-hit != 'true'
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2.9.1
@@ -384,9 +398,22 @@ jobs:
-p buzz-relay \
-p buzz-test-client \
--lib \
--bin buzz-relay \
--test e2e_event_reminder \
--archive-file target/ci/backend-integration-tests.tar.zst
postgres_package_args=()
while IFS= read -r package; do
postgres_package_args+=(-p "$package")
done < <(scripts/postgres-test-packages.sh)
if [[ "${#postgres_package_args[@]}" -eq 0 ]]; then
echo "no PostgreSQL test packages were discovered" >&2
exit 1
fi
cargo nextest archive \
--cargo-profile ci \
"${postgres_package_args[@]}" \
--lib \
--tests \
--archive-file target/ci/postgres-tests.tar.zst
- name: Save relay artifacts cache
# PR-scoped exact-source entries cannot warm main or other PRs and churn
# the shared cache pool. sccache provides read-only PR reuse instead.
@@ -397,7 +424,8 @@ jobs:
target/ci/buzz-relay
target/ci/git-credential-nostr
target/ci/backend-integration-tests.tar.zst
key: relay-artifacts-${{ runner.os }}-${{ hashFiles('crates/**', 'migrations/**', 'Dockerfile', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo/config.toml', '.github/workflows/ci.yml') }}
target/ci/postgres-tests.tar.zst
key: relay-artifacts-${{ runner.os }}-${{ hashFiles('crates/**', 'migrations/**', 'Dockerfile', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo/config.toml', '.config/nextest.toml', 'scripts/postgres-test-*.sh', 'scripts/check-postgres-test-discovery.py', '.github/workflows/ci.yml') }}
- name: Upload relay artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
@@ -406,9 +434,86 @@ jobs:
target/ci/buzz-relay
target/ci/git-credential-nostr
target/ci/backend-integration-tests.tar.zst
target/ci/postgres-tests.tar.zst
if-no-files-found: error
retention-days: 1
postgres-tests:
name: PostgreSQL Tests
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [changes, desktop-e2e-relay]
if: github.event_name == 'push' || needs.changes.outputs.rust == 'true'
permissions:
contents: read
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: buzz
POSTGRES_PASSWORD: ${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}
POSTGRES_DB: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U buzz -d postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 12
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 12
env:
PGHOST: localhost
PGPORT: "5432"
PGUSER: buzz
PG_BIN_DIR: /usr/bin
REDIS_URL: redis://localhost:6379
PGSCHEMA_PLAN_HOST: localhost
PGSCHEMA_PLAN_PORT: "5432"
PGSCHEMA_PLAN_USER: buzz
PGSCHEMA_PLAN_PASSWORD: buzz_dev
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
- name: Tune disposable PostgreSQL
env:
PGPASSWORD: ${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}
run: |
# Database-per-test cloning forces checkpoints. Durability is redundant
# for this disposable service and makes runtime depend on runner disk I/O.
psql --dbname postgres --set ON_ERROR_STOP=1 <<'SQL'
ALTER SYSTEM SET fsync = off;
ALTER SYSTEM SET full_page_writes = off;
ALTER SYSTEM SET synchronous_commit = off;
SELECT pg_reload_conf();
SQL
psql --dbname postgres --tuples-only --no-align --command \
"SELECT bool_and(setting = 'off') FROM pg_settings WHERE name IN ('fsync', 'full_page_writes', 'synchronous_commit')" \
| grep --fixed-strings --line-regexp t
- name: Install cargo-nextest
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
with:
tool: cargo-nextest@0.9.136
- name: Download backend test archive
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: desktop-e2e-relay
path: target/ci
- name: PostgreSQL-backed tests
env:
BUZZ_POSTGRES_ADMIN_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/postgres
PGPASSWORD: ${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}
run: |
scripts/postgres-test-run.sh \
--archive-file target/ci/postgres-tests.tar.zst
desktop-e2e-integration-shard:
name: Desktop E2E Integration (${{ matrix.shard }}/2)
runs-on: ubuntu-latest
@@ -689,68 +794,14 @@ jobs:
VALUES ('00000000-0000-4000-8000-00000000c0de', 'localhost:3000')
ON CONFLICT (lower(host)) DO NOTHING
;"
- name: Workflow message provenance tests
- name: Workflow message provenance unit tests
# The relay's workflow_sink suite is not selected by the infra-free
# unit job. Run both its pure tests and ignored PostgreSQL tests here so
# authored-template provenance cannot regress behind a green CI build.
# unit job. Its ignored database cases run in the isolated PostgreSQL
# lane; keep the pure provenance cases covered here without duplication.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-relay) and test(/workflow_sink/)' \
--run-ignored all
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Replaceable persistence PostgreSQL tests
# Transaction, concurrency, and mention-index coverage for the
# replaceable-event store seam. These tests require real Postgres and
# are ignored by the infrastructure-free unit-test job.
run: |
filter='package(buzz-db) and test(/tests::(parameterized_|concurrent_parameterized_)/)'
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E "${filter}" \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Database pressure observability PostgreSQL tests
# Explicit pool acquisition and advisory-lock metrics require real
# Postgres and are ignored by the infrastructure-free unit-test job.
run: |
filter='package(buzz-db) and test(/observability::tests::(pool_acquire_records_success_timeout_and_error_with_wait_time|advisory_lock_records_success_contention_timeout_and_error)/)'
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E "${filter}" \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Writer session timeout guardrails
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-db) and test(session_timeouts_install_through_db_new_and_bound_lock_waits)' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Audit writer session timeout guardrails
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-relay) and test(audit_writer_pool_installs_timeouts_and_bounds_advisory_lock_waits)' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Audit worker lock-timeout recovery
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-relay) and test(audit_worker_retries_lock_timeout_until_original_entry_is_appended_once)' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
-E 'package(buzz-relay) and test(/workflow_sink/)'
- name: Start relay
run: |
chmod +x ./target/ci/buzz-relay
@@ -779,26 +830,6 @@ jobs:
done
cat /tmp/buzz-relay.log
exit 1
- name: Invite security tests
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E '(package(buzz-db) and test(/relay_invite::tests/)) or (package(buzz-relay) and test(/api::invites::tests/))' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Workspace profile (kind:9033) gate tests
# Call-site integration for the 9033 authorization gate: open relay
# rosterless/steward transitions and the closed-relay admin/owner rule,
# against real Postgres. #[ignore]d in the default suite, selected
# explicitly here — see handlers::relay_admin::tests.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-relay) and test(/handlers::relay_admin::tests/)' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: NIP-ER reminder e2e
# Feature e2e for NIP-ER (Event Reminders, kind:30300): write-path
# validation, author-only read filtering, and scheduler delivery against
@@ -811,88 +842,6 @@ jobs:
--run-ignored ignored-only
env:
RELAY_URL: ws://localhost:3000
- name: NIP-MP coordinate deletion guard
# Verifies the never-delete-newer invariant of soft_delete_by_coordinate:
# a stale tombstone (created_at earlier than the live head) spares that
# head, and an equal-timestamp tombstone deletes it.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-db) and test(coordinate_delete_spares_head_newer_than_the_deletion)' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Admin API nip98 read-write attribution test
# The only real HTTP → nip98 operator principal → mutation → cross-table
# attribution coverage: an authenticated operator's dismiss attributes
# to the operator's own key with relay_operator authority. Staffing
# PUT/DELETE attribution is covered by
# nip98_staffing_put_and_delete_write_attributed_audit_rows in the
# roster-audit lane below. #[ignore]d in the default suite — see
# api::admin::tests::nip98_operator_dismiss_succeeds_attributed_to_operator.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-relay) and test(=api::admin::tests::nip98_operator_dismiss_succeeds_attributed_to_operator)' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Admin API unrostered-signer replay invariant
# The only causal proof that a validly-signing but unrostered key cannot
# consume NIP-98 replay slots: it asserts principal resolution fails
# BEFORE the replay ID is claimed (tracking.claim_count() == 0). This
# test is non-ignored, so it runs neither in Backend Integration's
# ignored-only selectors nor in the infra-free unit job — the unit job's
# api::admin selector excludes it because DB-free it only passes by
# waiting out the ~30s sqlx acquire timeout on a read-route fallthrough.
# It lives here so a reachable Postgres resolves (and fails) the lookup
# fast instead of timing out.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E 'package(buzz-relay) and test(=api::admin::tests::nip98_mode_unrostered_signer_does_not_consume_a_replay_slot)'
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Admin API roster-audit / timeout / canonicalization security tests
# Security-review fixes for the roster admin API, all #[ignore]d in the
# default suite (they need Postgres) and selected by no other job:
# - buzz-db relay_operators::tests: audit pre-image trail, per-target
# lock serialization, insertion-time audit ordering, and
# audit-failure rollback coupling.
# - buzz-db relay_operators::tests last-operator invariant: sole DB
# operator cannot self-demote or self-delete to zero, config presence
# lifts the guard, and concurrent cross-target deletes racing to zero
# leave exactly one operator (roster-wide advisory lock).
# - buzz-relay api::admin: NIP-98 staffing writes attributed audit rows,
# adversarial expirationSecs rejected at the resolve route, mixed-case
# staffing normalizes to one canonical row.
#
# --test-threads=1: the last-operator invariant counts the roster
# globally, and the sole-operator tests clear the roster then assert
# their operator is the only one. They must not race each other on the
# shared test roster, so this lane runs serially.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
--test-threads=1 \
-E '(package(buzz-db) and test(=relay_operators::tests::roster_mutations_write_pre_image_audit_rows)) or (package(buzz-db) and test(=relay_operators::tests::concurrent_upserts_serialize_and_record_true_pre_image)) or (package(buzz-db) and test(=relay_operators::tests::audit_order_follows_seq_under_backward_clock)) or (package(buzz-db) and test(=relay_operators::tests::audit_insert_failure_rolls_back_roster_mutation)) or (package(buzz-db) and test(=relay_operators::tests::demoting_sole_db_operator_without_config_is_rejected)) or (package(buzz-db) and test(=relay_operators::tests::deleting_sole_db_operator_without_config_is_rejected)) or (package(buzz-db) and test(=relay_operators::tests::config_present_allows_deleting_last_db_operator)) or (package(buzz-db) and test(=relay_operators::tests::concurrent_deletes_racing_to_zero_leave_one_operator)) or (package(buzz-relay) and test(=api::admin::tests::nip98_staffing_put_and_delete_write_attributed_audit_rows)) or (package(buzz-relay) and test(=api::admin::tests::resolve_route_rejects_adversarial_expiration_and_leaves_report_open)) or (package(buzz-relay) and test(=api::admin::tests::mixed_case_non_config_staffing_normalizes_to_one_row))' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Admin API escalation-scoping tests
# Escalation scoping for the moderation queue, all #[ignore]d (they need
# Postgres) and selected by no other job:
# - GET /reports defaults to the escalated-only backstop, scope=all
# restores full visibility, explicit status= overrides the default.
# - member reports with category 'illegal' auto-escalate at ingestion
# while every other category still lands 'open'.
run: |
cargo nextest run \
--archive-file target/ci/backend-integration-tests.tar.zst \
-E '(package(buzz-relay) and test(=api::admin::tests::reports_default_lists_escalated_only)) or (package(buzz-relay) and test(=api::admin::tests::reports_scope_all_lists_every_status)) or (package(buzz-relay) and test(=api::admin::tests::reports_explicit_status_filter_overrides_default)) or (package(buzz-db) and test(=moderation::tests::illegal_report_auto_escalates_at_ingest)) or (package(buzz-db) and test(=moderation::tests::non_illegal_report_lands_open_at_ingest)) or (package(buzz-db) and test(=relay_admin_actions::tests::auto_escalated_report_reopens_like_an_admin_escalated_one))' \
--run-ignored ignored-only
env:
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
- name: Upload relay log
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7