Three related fixes from the test audit.
**The CLI journey fixture gets its own database.** It spawned a real picloud —
whose dispatcher/orchestrator claim loops are global by design (one instance owns
one database) — against the shared dev DB, so it could claim the manager-core
suites' outbox/workflow rows (the same class of bug already fixed for the e2e
suites, one binary over). It now clones one dedicated database per journey run
from the migrated template. test-support gains `named_test_db_url` (explicit
stable name) + a blocking wrapper for the sync `LazyLock` fixture. The one journey
that talks to Postgres directly (dead-letter injection) now uses the fixture's DB
URL, not the base DATABASE_URL, so it hits the database the server reads.
**workflow_orchestrator moves to per-test databases.** Its `claim_ready_step` is
global, so the old harness serialized every test behind a process-wide CLAIM_LOCK
AND ran `DELETE FROM workflow_runs` (unscoped — it wiped every app's runs) before
each one. A private database per test makes the global claim see only that test's
rows, so both the lock and the unscoped DELETE are deleted.
**DB-backed suites fail loud instead of skipping green.** ~15 manager-core suites
`return None` when DATABASE_URL is unset and report PASS — so in any environment
that lost its database the entire integration surface reports green while running
nothing (why the CI gap went unnoticed for so long). New
`picloud_test_support::abort_if_db_required` panics when `PICLOUD_REQUIRE_DB` is
set (CI now sets it) but DATABASE_URL is not, injected into each suite's skip
path. Local runs without the var still skip cleanly.
Mutation-verified: with PICLOUD_REQUIRE_DB=1 and DATABASE_URL unset, a suite
panics; without the var it skips.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI ran `cargo test --workspace` with no `--include-ignored`, so it executed 927
tests and skipped 237 — every DB-backed integration test is
`#[ignore = "needs DATABASE_URL..."]`, which covers ALL of api.rs, ALL of
authz.rs, and the entire CLI journey suite. The isolation and RBAC tests existed
but never ran (AUDIT.md F-Q-014, logged and never remediated). CI provides
Postgres, so it can run them.
Three things had to be right for that to go green:
- **`--all-targets`, not a bare workspace run.** `-- --include-ignored` un-ignores
not just `#[ignore]` tests but also ` ```ignore ` DOCTESTS, which are
illustrative pseudocode that does not compile. `--all-targets` runs lib/bins/
integration tests but excludes doctests (the same reason clippy uses it); a
separate `--doc` step runs the doctests without the flag. Structural, so a
future pseudocode doctest can't silently break CI either.
- **The CLI journeys are their own step.** They spawn a real picloud whose
dispatcher/orchestrator claim loops are global by design; run concurrently with
the manager-core suites on the shared database they would claim those suites'
outbox and workflow rows. Sequential steps keep the live server off the DB
while the other suites use it. The step also rebuilds `-p picloud` first (the
harness execs the prebuilt binary) and sets the dev-mode env the server needs.
- **A higher `max_connections`.** `#[sqlx::test]` pools are lazy, but mass-parallel
test startup briefly opens many at once (each test creates its own throwaway
database); on a many-core box that transient spike exceeded the default 100 and
Postgres answered "sorry, too many clients already". Steady-state peak is only
~26; 500 absorbs the spike with room to spare. Serving the app needs nothing
like this many. (This is the local compose ceiling; a small CI runner's default
100 has ample headroom for its lower parallelism.)
Also fixes the test the CI gap had let rot: api.rs asserted `v["schema"] == 66`
with a hand-bump comment, and since nothing ran it, it sat broken from migration
0066 to 0073. It now asserts `/version` surfaces the live constants
(`migrations::latest_version()`, `SDK_VERSION`) — the wiring — while value drift
stays caught by schema_snapshot + check-versioning. A constant hand-synced to
another constant is a chore, not a test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>