--- id: pg-engine-integration name: Postgres engine — integration (full-surface wiring, suite adoption, crate docs) status: completed depends_on: [pg-engine-notify-listen, pg-engine-streams, pg-engine-queues, pg-engine-locks, pg-engine-scheduler-outbox] scope: moderate risk: medium impact: phase level: implementation tags: [wave-4, postgres-engine, integration] --- ## Description Close the wave's integration gaps once every mechanism is wired — the structural twin of wave 3's integration task (no lint-suppression removal on this side: the pg engine is greenfield, no `#![allow]` posture ever existed — the sweep below is the same discipline without that step): - **Full-surface sweep**: every `Store`/`TxHandle`/mechanism trait method implemented (no `todo!`/`unimplemented!`/error-stub remaining); the engine crate's lib re-exports its public surface (`open`, `PgOpts`, the concrete store type) per the module-per-file convention. Genuinely dead code must be **cut, not suppressed** — clippy `-D warnings` green without allows. - **Contract-suite adoption** (the plan's "waves 3 and 4 adopt the harness"): implement `StoreFactory` for the pg engine — **a fresh schema per `open`** (the SQLite factory's fresh-temp-file precedent; the POC's shared-server parallel-interference caveat is answered by exactly this isolation — each property's rows live in its own schema, so parallel property runs never observe one another), idempotent teardown (`DROP SCHEMA … CASCADE`; safe against an abandoned store per the factory contract's teardown posture). Pin the factory's isolation/idempotence contract (the SQLite factory's pin shape). Wire the engine's backlog column — the rows this engine owns now, running against the pg factory: - The ADR-023-stamped rows (extent-clamp, duration-refusal, `encode_payload` round-trip) — already written suite-side, factory-parameterized; they run against pg by this task's factory existing (verify, don't rewrite). - **The pg arm of the engine-scoped rows**: `PayloadTooLarge` produced (the pg rejection arm — oversized `notify`/`notify_tx` rejected client-side with the limit in the variant; the row text the SQLite integration task left for "wave 4's adoption"), drop = rollback no-ghosts, in-tx read-your-own-writes, enqueue-opts resolution, receiver close arms (the pg arm: stays open across reconnects, closes at shutdown — the row's engine-asymmetric legs may need the row split or parameterized per the suite's convention; implementer's choice, documented). - The SQLite-scoped rows (plain-path open §3, poll cadence §4) simply don't run against pg — the SQLite integration task's Notes already pinned that disposition. - **Crate docs**: the engine crate's lib-level doc comments state the multi-host posture and the listener budget line (ADR-016, deployment.md) — the identity statements this crate owns (the open task drafted them; this task verifies they reflect the finished engine). - **Gates**: full workspace build/test/clippy/fmt (the pg tests skip cleanly server-less but must be green against the harness server); coverage spot-check on the engine crate (no large uncovered regions outside error arms — the wave-3 gate's bar). ## Acceptance Criteria - [x] No `todo!`/`unimplemented!`/error-stub in the engine crate; full trait surface implemented; clippy `-D warnings` green without allows - [x] `StoreFactory` implemented for pg (fresh schema per `open`, idempotent CASCADE teardown); the factory's isolation/idempotence contract pinned - [x] The backlog column runs green against the pg factory: the three ADR-023 rows verified (not rewritten), the pg arm of the five engine-scoped rows present + stamped - [x] The `PayloadTooLarge` pg arm row present (the SQLite integration task's deferred adoption discharged) - [x] Crate lib docs carry the multi-host + listener-budget posture statements, reflecting the finished engine - [x] Workspace gates green: `cargo build`, `cargo test` (incl. against the harness server), clippy `-D warnings`, fmt clean - [x] Coverage spot-check: no large uncovered regions outside error arms ## References - docs/plans/implementation.md (Wave 4 section) - docs/architecture/core-contract.md (§Verification backlog) - docs/architecture/decisions/022-contract-suite-layout.md - docs/architecture/decisions/023-fourth-review-round.md (backlog additions) - docs/architecture/decisions/016-deployment-honesty.md §5 - alkstore-sqlite/tests/contract_suite.rs (the factory precedent) - alkstore-contract-suite/src/properties.rs (the rows to run/adopt) ## Notes > Decisions of record the description didn't pin: - **No stubs were found to sweep** — the mechanism tasks retired the wave-3 error-stub surface as they landed; the sweep verified the absence (`todo!`/`unimplemented!`/error-stub grep clean; clippy `-D warnings` green with zero `allow(...)` lint attributes anywhere in the crate). The sweep's *cut-not-suppress* residue was doc-staleness, not code: `store.rs`'s module docs still described the trait stubs ("wiring lands with the … task") and `lib.rs`'s tail still described the wave-4 build order — both rewritten to the finished-engine posture. - **Test-observation accessors honestly `#[cfg(test)]`-gated** (the SQLite integration task's precedent): `pool()`, `forwarder()`, `schema()`, `listener_application_name()`, and the `listener_application_name` field carried `#[cfg_attr(not(test), allow(dead_code))]`/ `#[allow(dead_code)]` gates (the tasks' "tests exercise it now / gate until then" posture). All five are lib-dead — the lib build reaches the fields directly — so they are `#[cfg(test)]`-gated with no `allow`s, and `PgStore::new` (left unused by the direct struct construction in `open_store`) was cut. No ADR-018 register entries: nothing diverged from a lineage-kept set (the pg engine is greenfield; these were this repo's own task-staged accessors). - **The `PayloadTooLarge` pg arm is a new suite row, not a parameterized split** — `payload_too_large_produced_on_pg` joins `payload_too_large_never_produced_on_sqlite` as its own factory-functioning row (one normative owner per arm's *property*; the two arms' assertions differ, so a shared row text would have carried engine-conditional branches — the drift surface ADR-022's one-text rule exists to avoid). Both carry the same ADR-008 §5 / ADR-016 §5 stamps; the matchability posture (engine-agnostic code writes one match) is stated on both. The limit pin cites the contract number (8000) — pg-column-specific, so it's contract text here, not engine detail. - **The receiver-arms row ran unchanged against pg** — no row split needed. The row's disposal-close legs drive the close through the store-handle drop (the dispose carrier every engine implements); pg's *cause* asymmetry (stays open across reconnects, closes only at engine shutdown — ADR-021 §5's pg arm) is documented in the pg engine's own module docs and engine tests (`receiver_stays_open_across_reconnects_closes_at_shutdown`, `engine_shutdown_closes_the_subscription_terminally`) rather than in the row text. - **The factory tracks its own schemas** — teardown drops exactly the schemas the instance minted (a per-instance registry), never a fixed prefix or the shared server's other schemas (a prefix- or name-based DROP would be a footgun against the harness's co-tenanted server). `DROP SCHEMA IF EXISTS … CASCADE` per minted name: `IF EXISTS` is the idempotence (a second teardown, or a schema an abandoned store's bootstrap re-created, are both safe shapes). Admin connection per teardown call — no shared client lifetime to outlive an await. - **Suite rows skip cleanly server-less** via a reachability probe in the test target (`harness_ready()` — one cheap admin connect with a 3 s timeout); the factory's `open` itself fails typed (`Database`) on an unreachable server. Same posture as the engine's own test modules. - **The trait-surface acceptance test renamed** — `store_trait_methods_are_wiring_stubs` → `store_trait_methods_are_wired` (the old name was the wave-3 stub-era label; the test's assertions were already full-surface). ## Summary > Landed: the pg engine's backlog column — `PgFactory` implemented in > the new integration test target (`alkstore-postgres/tests/ > contract_suite.rs`), a fresh engine-owned schema per `open` (unique > per call; parallel property runs never observe one another), > idempotent owned-teardown (`DROP SCHEMA IF EXISTS … CASCADE` over > exactly the instance's minted schemas); the factory's > isolation/idempotence contract pinned > (`opens_are_isolated_and_teardown_is_idempotent` — cross-open row > invisibility server-side + double-teardown + `pg_namespace` > proof). All ten rows green against the harness server: the exemplar > + the three ADR-023 rows (verified — not rewritten; factory- > parameterized text ran as-is) + the engine-scoped five (drop=rollback > no-ghosts, in-tx read-your-own-writes, enqueue-opts resolution, > receiver close/save arms — ran unchanged) + the new > `payload_too_large_produced_on_pg` row (the SQLite integration > task's deferred adoption discharged; typed > `PayloadTooLarge { limit: 8000 }` on `notify` and `notify_tx`, > client-side rejection pinned, re-exported from the suite lib). > Server-less runs skip cleanly (reachability probe). > > Full-surface sweep: no `todo!`/`unimplemented!`/error-stub > anywhere in the engine crate (verified by grep + the trait surface > exercised end-to-end); stale stub-era doc text cut (`store.rs`'s > "wiring lands with the … task" paragraph, `lib.rs`'s wave-4 build- > order tail → the finished-engine statement including the suite > target pointer); test-observation accessors honestly > `#[cfg(test)]`-gated (no lint `allow`s anywhere in the crate) and > the unused `PgStore::new` cut; the trait-surface test renamed to > its finished posture. Crate lib docs already carried the > multi-host + listener-budget (`max_size + 1`, deadpool#360) > identity statements — verified accurate against the finished > engine, no change needed beyond the tail. > > Verified: workspace `cargo build`/`cargo test` green against the > harness server (25 core + 3 harness + 111 pg + 10 pg suite + 9 pg > schema + 188 sqlite + 10 sqlite suite = 356 tests, 0 failures; > server-less pg suite skips clean); clippy `--workspace > --all-targets -D warnings` clean; `cargo fmt --check` clean. > Coverage spot-check (cargo-llvm-cov, engine crate, harness server > up): 93.27% lines, every file ≥85% (stream.rs 88.31%, queue.rs > 94.99%, scheduler.rs 92.84%...); misses are error arms > (commit/rollback-failure discards, `Codec` posture guards), the > `drive_sync` CurrentThread/foreign-runtime defensive branches, and > Debug impls — no large uncovered regions outside error arms, the > wave-3 gate's bar. The streams task's pre-existing flake > (`tx_publishes_compose_with_the_handle`) did not recur in these > runs (untouched by this change).