Story 1740: seed_test_firms for BDD and integration tests
Why this exists. Cross-firm tests need a small, realistic two-tenant world. If every scenario hand-seeds its own firms, roles, clients, and matters, the next migration turns those scenarios into stale SQL. This Story creates one reusable seed coupled to the current factories and schema, so later BDD slices can test product behavior instead of rebuilding tenant setup.
Seed Shape
seed_test_firms
├── firm_a: Meridian
│ ├── owner user + active firm_admin membership
│ ├── default firm roles: Partner / Counsel / Member
│ ├── one active client
│ └── one active matter attached to that client
└── firm_b: Crestline
├── owner user + active firm_admin membership
├── default firm roles: Partner / Counsel / Member
├── one active client
└── one active matter attached to that client
Migration Coupling
The fixture builds rows through tests/factories.py and the
domain seed service for firm roles. Client and matter numbers come from
business.allocate_reference(...), the same DB function used by
application code, so the seed follows current constraints instead of relying
on a static SQL dump.
RLS Proof
The smoke test uses the runtime session factory, applies a real
firm-admin RLS context with bound set_config calls, and checks
that Meridian can see only Meridian's client and matter while Crestline can
see only Crestline's rows.
Meridian runtime context -> Meridian client + matter only Crestline runtime context -> Crestline client + matter only
Verification
make test-db bash scripts/run-with-test-db-env.sh uv run pytest tests/integration/test_seed_test_firms.py -v --tb=short uv run ruff check tests/factories.py tests/integration/conftest.py tests/integration/test_seed_test_firms.py tests/steps/conftest.py make test-db-alembic-roundtrip
One-sentence recall: seed_test_firms gives BDD
tests a realistic two-firm stage, while the runtime-role smoke test proves
the stage still has a wall between tenants.