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>
- F-T-003 actually closed: clients/typescript/src/subscribe.ts now
bounds the 401-refresh loop at 3 consecutive refusals, surfaces an
onError describing the loop, and resets on any successful stream
open. New test covers the cap. The Stage 2 dashboard fix only
addressed adminRequest in dashboard/src/lib/api.ts; the originally-
cited TS client file was untouched.
- users/invitations subtab dropped the redundant api.apps.get fetch
the other 5 subtabs already shed in Stage 6.
- Queue visibility-timeout validator pulled out as
validate_queue_visibility_timeout, with two thresholds: hard-reject
below MIN_QUEUE_VISIBILITY_TIMEOUT_SECS (30s — catches typos), warn-
log between MIN and SAFE_VISIBILITY_VS_EXEC_BUDGET_SECS (300s) so
operators see when their visibility is below the dispatcher's
per-message executor budget. Stage 6 only had the hard floor; the
reviewer caught that a 60s handler still races a 30s visibility
even after the floor. Four new unit tests cover none/above-safe/
between/below-min.
- pic dead-letters count subcommand: cheap headless probe for
unresolved DL totals, parallels the dashboard's badge query.
- pic dead-letters replay now has a happy-path integration test
(replay_against_real_dl_row_succeeds): inserts a synthetic DL row
directly via the rust-postgres sync driver (added as dev-dep),
drives `pic dead-letters replay`, asserts the row is resolved with
reason=replayed and count drops back to 0. Plus a count smoke test.
All 75 CLI integration tests + 16 TS client tests + 4 new
visibility-timeout unit tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the audit's High-severity CLI coverage gap, raising the count
from ~25 to ~40+ subcommands and bringing the integration test count
from 63 to 73.
- pic triggers {ls, rm, create-kv, create-cron, create-dead-letter,
create-from-json}: three per-kind wrappers cover the most common
trigger shapes; the generic create-from-json is the escape hatch
for docs/files/pubsub/email/queue and any future advanced retry
knobs — body JSON inline, via @<file>, or "-" for stdin.
- pic dead-letters {ls, show, replay, resolve}: full operator
workflow for the dispatcher's dead_letters rows, including the
--unresolved filter and the per-row replay + manual-resolve actions.
- pic secrets {ls, set, rm}: list names + updated_at, set values
via stdin (the only secure channel — inline values would leak
into shell history), and delete by name. --json on set treats
stdin as raw JSON for non-string values.
Ten new integration tests follow the established #[ignore] pattern,
gated on DATABASE_URL. All 73 ignored tests pass against the local
dev stack.
The `pic admin reset-password` server-binary subcommand exists on
the picloud binary side already; the audit's "surface it in pic
--help" note is a one-line addition deferred to Stage 6 with the
other small UX touches.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>