Review pass in this repo: contract suite re-verified (11/11 pass under --test-threads=1 against the harness server; default parallel runs interfere across tests via the shared db/channels engine_for_test harness — each test spawns its own listener on poc:q/s/n and truncates shared tables, so parallel tests receive each other's notifications and race truncates). Recorded as a harness caveat in the findings with the Phase 1 note (per-test namespaces), NOT as a contract failure — every test passes in isolation. Findings invocation note + artifacts section updated; phase-0 frontmatter carries the verification qualifier. OQ-ST-03 closure text already folded by the POC session stands.
27 KiB
status, title, last_updated
| status | title | last_updated |
|---|---|---|
| findings | POC #2 findings — Postgres engine posture: LISTEN/NOTIFY wiring, the pool tx-seam, and reactive parity on tokio-postgres | 2026-10-04 |
POC #2 findings — Postgres engine posture
Verdict: PASS — tokio-postgres + deadpool-postgres carries the unified
surface with the transactional property intact, and LISTEN beats poll
decisively. OQ-ST-03 closes with per-engine drivers (rusqlite+honker-core
for SQLite, tokio-postgres+deadpool for Postgres); OQ-ST-04's
contract-pinning now has measured ground on both engines. All three
sub-modules returned affirmative findings; the sqlx PgListener fallback
was never needed and stays retired. Every shared contract property from
POC #1 holds on Postgres, plus the pg-native facts (in-tx NOTIFY delivers
at commit; pooled connections cannot deliver notifications — deadpool#360
— pinned as our own test).
POC code: /workspace/alkstore-pg-posture-poc (standalone crate,
published-deps-only, same harness conventions as POC #1). Server:
dockerized postgres:16-alpine on :15432 (pglo-poc container, db
blobs, user/password postgres/poc — the alkblobs POC harness
convention). Toolchain: rustc/cargo 1.99.0.
Versions / dependency surface (verified 2026-10-04)
tokio-postgres0.7.18 (updated 2026-09-03, actively maintained, MIT/Apache-2.0).with-serde_json-1feature for JSONB/Value binding.deadpool-postgres0.14.2 (pool + per-connection statement cache;RecyclingMethod::Fastdoes not clobber LISTEN state — it recycles with a health query only — which is also why a LISTEN-registered connection returning to the pool keeps its registration but loses the delivery path; see the #360 section).postgres-notify0.3.8 (MIT, single maintainer, 5.9k downloads total, ~1.5k recent; published 2026-01-07 by the sole owner). Verified in-probe; quirks below under Sub-module L (b).- No version conflicts, no vendoring needed. The pg engine is single-driver by construction (per OQ-ST-02's split); no libsqlite3-sys-style link collision exists on this side.
Sub-module L (listen plumbing) — findings
The #360 constraint: verified empirically, pinned as a test
The spec's requirement (dedicated non-pooled LISTEN connection) was asserted with our own probe rather than trusted from the issue tracker:
tests/contract.rs::pooled_listen_registers_but_cannot_deliver— three-part honest probe: (1)LISTENissued through a pooled deadpool connection registers server-side (the session shows it inpg_listening_channels()), (2) the registered notification is never deliverable (no delivery API exists on the pooled object — verified by source read: deadpool 0.14.2's connect taskspawn(async move { connection.await })plain-awaits the tokio-postgresConnectionfuture, whoseFutureimpl discards all async messages;ClientWrapperexposes no notification surface whatsoever), and (3) the control — a dedicated connection driven bypoll_message— delivers the identical notification immediately.- Source-verified against the installed 0.14.2 (not just the issue):
deadpool-postgres/src/lib.rslines ~221 and ~311 —create()spawns the connection task with a bareconnection.await, andClientWrapper::dropaborts it. deadpool#360 remains open.
Consequence recorded for the engine: the listener connection is a
separate budget line, outside the pool, per process. Pool
max_size + 1 per LISTEN-ing process (pgdiag-st-4 verified the
accounting end-to-end: pool size 6 observed + 1 listener + probe conns
= exactly the server-side count).
Hand-rolled forwarder (a) — built and measured (~90 lines)
src/listen.rs: dedicated connection per listener process, a spawned
task driving Connection::poll_message and fanning out into a tokio
broadcast channel (bounded 1024; lag is surfaced, not silent — the
bridge logs Lagged(n) and keeps going). Reconnect policy: exponential
backoff 50 ms → 2 s cap; re-LISTEN after every reconnect (the LISTEN
SQL is re-issued from the channel list on each reconnect), plus a
synthetic reconnect wake on a reserved channel after each
successful re-LISTEN — that synthetic wake is how the no-replay hole
is communicated to subscribers (below).
Two deadlocks found and fixed during the build — both are exactly the failure modes a hand-rolled forwarder owns and both are now pinned by the passing tests:
- Query-vs-poll starvation deadlock. With the raw
Connectionpolled for async messages, any client query (batch_execute) awaits its response through the same connection — if the poll loop task is spawned after the first client query, the query never completes. The poll loop must be running before the first query. (The initial version deadlocked the LISTEN itself; caught in-probe, restructured, pinned by every listen test passing.) - Client-drop closes the connection. Dropping
tokio_postgres::Clientterminates the server session even if theConnectiontask still runs. A long-lived listener must keep theClientalive for the listener's lifetime (std::mem::forgetin the one-shot probe path; ownership in the shared listener path). Verified in-probe (examples/raw_listen_selfcheck.rsetc).
Neither failure mode was visible from the docs; both are the "every failure mode is maintained by us" cost the spec predicted for the hand-rolled posture. They are contained (~90 lines, two pitfalls) and now test-pinned.
postgres-notify 0.3.8 (b) — built, verified working, with four documented quirks
src/pgnotify.rs wraps PGRobustClient as the listener substrate.
Verified in-probe (pnlisten command + examples/pn_reconnect_flow.rs):
- Initial connect does NOT execute the connect_script (source:
PGClient::connectnever runs it; onlyreconnect()does). The initial LISTEN must be issued explicitly viasubscribe_notify— which conveniently registers channels into the config'ssubscriptionsset that the reconnect script re-issues. The spec's caveat ("restoration behavior must be verified by test") was sharper than doc'd: restoration works on reconnect, but the first LISTEN is entirely yours. - Reconnect is lazy. The polling task reports a drop via a
Disconnectedcallback, butreconnect()only runs when the next query fails its connection check. A killed listener connection sits disconnected until the client issues something. The engine's listener loop would need a periodic keepalive/trigger query to make recovery timely — more machinery ours-with-a-dependency, not fewer. - Auto-reconnect + re-LISTEN verified: backend kill (by pid, via
pg_terminate_backend) →Disconnectedcallback → trigger query →Reconnect(attempt #1, backoff 500 ms base) →Connected→ LISTEN re-issued from the script → post-reconnect notification delivered.PASS pnlisten: reconnect + connect_script re-LISTEN verified. issue_listen/issue_unlistendo not quote identifiers —LISTEN poc:pnis a syntax error at the server. Channel names through this crate must be quote-free (letters/digits/underscore). Alsoapplication_name(config field) is interpolated into the connect script, so it does not apply to the initial connection either — server-side kill-by-name targeting misses the initial connection.
Comparison verdict (preference recorded, this is OQ-ST-04/OQ-ST-06
input, not a Phase 0 ADR): (a) hand-rolled forwarder wins — the
hand-rolled version is ~90 lines with immediate reconnect (no lazy
trigger dependency), full identifier control (quoted channels — our
poc: prefixes work), no dependency posture (single-maintainer crate
with 1.5k recent downloads and behavior quirks the docs misdescribe),
and the two deadlock pitfalls are already learned and pinned. The
(b) crate would still force us to own a keepalive + reconnect trigger
loop on top (its reconnect laziness), eroding most of the "turnkey"
advantage. Posture (b) stays recorded as the fallback if a future
upstream fix lands (channel quoting + eager reconnect) and the
maintenance posture improves.
Multi-channel and fan-out
- One LISTEN connection serves N channels: verified (
LISTEN a; LISTEN b; LISTEN c;on one connection, all three deliver —shared_listener_multichannel.rs, and every contract test runs three channels through one listener). No per-channel connection is ever warranted at this scale; fan-out to per-subscriber receivers is a broadcast split, ~zero cost. - 4 subscribers on one channel, every one wakes: verified
(
listen_wake_fanout_and_burst).
Payload boundary
pg_notify ≤ 8000 bytes confirmed. Probe: 7700-byte payload delivers;
the engine checks the limit client-side and returns a typed
PayloadTooLarge error before the round-trip for 8100 bytes
(notify_payload_boundary). Honest contract recorded: notify payloads
are hints; large payloads ride a table row with the id in the
notification (the honker-outbox shape, pg-native).
Sub-module T (tx-seam over the pool) — findings
Both candidate shapes implemented:
- (a) caller-owned tx handle (
OwnedTxHandle): the trait'sbegin_txchecks a pooled connection out, issuesBEGIN, and hands the caller a handle owning theObject.*_txmethods downcast the handle (as_any_mut, same as POC #1's sketch) and issue their SQL through it. Commit/rollback return the object to the pool. - (b) closure-scoped (
with_tx): pool checkout + BEGIN + closure- COMMIT/ROLLBACK inside one future; the caller never holds the transaction.
The load-bearing structural finding: the whole SQLite side's
thread-affinity rigging does not exist on Postgres — deliberately.
POC #1's SQLite tx handle needed an Arc<Mutex<Option<Connection>>>
with every op round-tripping spawn_blocking, because rusqlite's
connection is neither Send-across-await nor Sync, and the handle
had to be callable from async trait methods. tokio-postgres's Client
(and deadpool's Object) is Send + Sync (request-channel
design: Arc<InnerClient> + unbounded mpsc), verified by a
compile-time probe in this POC (tmp sendsync check: Client and
Object both asserted Send + Sync). So shape (a)'s handle is
Option<Object> held directly, ops are straight .awaits, no
mutex, no spawn_blocking, no per-op hop cost. The as_any_mut
downcast friction from POC #1 remains (same trait shape), but the
thread-affinity friction does not carry over. This is the honest
per-engine delta the unified trait must absorb: same seam shape, but
the PostgreSQL handle is free to be held across await points while the
SQLite handle must own a blocking thread.
- Commit-atomicity property holds and was verified directly:
NOTIFYissued inside the caller's tx (viapg_notify($1,$2)) is delivered to listeners only at commit of the sending transaction (notify_fires_only_on_commit: notify in an open tx → listener silent for 400 ms → commit → delivery < 3 s;tx_enqueue_rollback_… drops_all_ghost_free: rollback drops the job row, the business row, and the notification — no ghosts anywhere). This is pg's native statement-vs-commit semantics, exactly the analogue of honker's notify-in-tx atomicity — no emulation needed. - Read-your-writes under
read committed(the honest default): verified both directions (in-tx reads see own writes; post-commit reads from other pool connections see the commit). No surprises. - Shape (a) vs (b) for the engine posture: (a) is the viable
contract seam (long transactions compose naturally; the caller drives
begin/commit — which is exactly what POC #1's
TxHandlesketch assumed). (b) works for self-contained ops but composes poorly with the caching-subscriber pattern (state can't outlive the closure). Preference recorded: (a), with (b) available as a wrapper — note (b) is implementable over (a) trivially but not vice versa. Deadlock risk on (a): none found (the connection is checked out exclusively; no re-entrant checkout happens inside the handle's ops). - Prepared-statement discipline: deadpool's per-connection
statement cache is keyed per pooled connection and the cache is
re-usable across checkouts; with
RecyclingMethod::Fastthere is noDISCARD ALL/DEALLOCATErecycling, so the "prepared statement s1 does not exist" failure (alkblobs POC-era) does not recur: the engine's claim SQL is prepared implicitly through the same pooled connection repeatedly during the probes with zero errors (n=3000 seam iterations ×2 sync postures + pollvlisten's 12 × 60 claims). The queue SQL is ordinary SQL — no manual prepare discipline needed at POC scale; noting the engine crate should keep usingprepare_cachedif it wants explicit caching (deadpool'sClientWrapper::prepare_cachedexists for exactly this).
Sub-module W (wake-vs-poll parity) — findings
LISTEN-driven wake latency (pgdiag-st-2)
300 notify-commits at 25 ms spacing, listener attached before first commit, delivery = wake-on-channel after commit:
- p50 = 1.10–1.15 ms, p99 = 1.42–1.45 ms, max = 1.49–2.21 ms, 300/300 delivered (0 missed).
Cross-engine relative claim (contract input): this is the same sub-2.5 ms order as POC #1's SQLite watcher at its 1 ms cadence (p50 1.40 ms arm-A / 2.15 ms arm-B) — the wake layer is not the Postgres engine's weakness; it's tighter than poll-based wake and structurally push (nothing polls: the server delivers).
- Burst-stress (30 rapid commits, no spacing): 30/30 delivered
(both release and debug runs; commit burst executes at ~200–520
commits/s, all 30 per-payload notifications delivered). LISTEN does
not coalesce the way a poller does — each committed NOTIFY is
delivered. The per-payload assert (not per-count) is what our
contract tests pin:
seen.contains(payload_i)for every i. - Re-attach storm (N listeners × M channels): the shape is one listener connection with N broadcast subscribers — re-attach is a broadcast re-subscribe, no server round-trips; the reconnect path re-issues M LISTENs on the one connection (verified in the reconnect test; the storm is O(M) SQL statements once per reconnect).
LISTEN connection failure and the replay hole
listener_reconnect_recovery_and_replay_hole: listener connection
killed mid-subscription (pg_terminate_backend targeted at the
listener's application_name — the listener sets
application_name('alkstore-pg-poc-listener') precisely to be
kill-targetable and diagnosable) →
- the commit during the gap is not re-delivered (LISTEN has no replay — the honest contract the spec predicted holds);
- the listener reconnects (exponential backoff 50 ms base) and re-LISTENs;
- a synthetic wake is broadcast on a reserved channel (
__listener_ reconnected__) when the connection re-establishes — this is the mechanism that turns the no-replay hole into a recoverable event: subscribers getDisconnected-ish signal via the wake and re-read state. Verified: reconnect wake arrives; post-reconnect deliveries work; state re-read is complete (all three commits — pre-kill, in-gap, post-reconnect — visible to a fresh consumer read despite the in-gap notification never being delivered); - the assertion
!saw_replaypins the no-replay honesty.
This is the "on reconnect, wake all subscribers once" recovery the spec sketched, now implemented and pinned. The engine's subscriber contract inherits it: wake = opaque hint + re-read; gaps surface as a reconnect wake, not as lost silence (the SQLite side's missed-wake stress tests the overtriggering twin of this contract).
Poll-vs-listen claim latency (pgdiag-st-3) — the decisive measurement
Enqueue→claim latency, one job in flight, 1/8/32 claimants, both postures, release build (debug numbers were consistent):
| posture | claimants | p50 ms | p90 | p99 | max |
|---|---|---|---|---|---|
| poll (50 ms interval) | 1 | 50.0 | 50.8 | 65.3 | 65.3 |
| poll | 8 | 32.5 | 36.7 | 46.5 | 46.5 |
| poll | 32 | 40.4 | 49.3 | 51.1 | 51.1 |
| listen | 1 | 6.0 | 6.4 | 8.6 | 8.6 |
| listen | 8 | 3.1 | 7.0 | 7.6 | 7.6 |
| listen | 32 | 5.7 | 6.6 | 10.6 | 10.6 |
LISTEN-driven claiming beats even a 50 ms poll by 5–16× at p50; against pgboss-style 1 s default poll intervals the gap would be ~100–300×. The claimants-scaling is flat-to-better (multiple claimants absorb wakeup jitter). The LISTEN-driven claim path with re-poll safety net is the engine's default consumption posture; poll-only (interval-tunable) remains the fallback when a LISTEN connection is unavailable/not wanted. This decides the pg half of the reactivity-vs-pgboss gap: the push channel pgboss-rs lacks, this engine gets, measured.
The seam/cost probe (pgdiag-st-1)
begin + enqueue_tx + commit per iteration through the pool, n=3000,
release, sequential (POC #1's seam workload's pg twin):
synchronous_commit=on(ship config): p50 = 2.40 ms, p90 = 2.73, p99 = 3.00, max = 6.93 ms (0 fails);synchronous_commit=off: p50 = 2.26 ms, p90 = 2.66, p99 = 3.02, max = 40.9 ms (0 fails).
Reading (shape, not absolute — different machines/databases):
- The pg seam is flat and tight at p50–p99 (~2.3–3 ms) — the pool
checkout + BEGIN + INSERT + COMMIT round-trip cost with the
per-connection statement cache warm. The
=offknob does not materially change p50–p99 here (the local docker fsync floor is small; the knob would matter more on replicated/farther storage). The max-tail differences (~7 ms vs ~41 ms) reflect exactly that:=onpays fsync per commit predictably;=offbatches, occasionally longer flush batches.synchronous_commitremains a per-session durability knob with honest trade shape — measured, both postures reported; per-session SET mechanics verified (pool.rs sets it via the connect options;set_sync_commit_sessionvia SET). - Cross-engine: SQLite's seam (same workload shape) was 0.354/0.183 ms (arm A) vs sqlx's 0.707 ms in POC #1 — i.e., Postgres' transactional seam on the network stack costs ~3–10× the SQLite one here, which is the honest expected order (network round-trips vs in-process file writes). The unified trait absorbs this as "engine costs differ by orders for the same op" — the per-engine performance expectations must not be baked into the shared contract numbers.
- Raw floor re-measure (methodology cross-check): prepared SELECT round-trip p50 = 284 µs (p99 344 µs) — consistent with the POC #5-era ~150–500 µs claim, same box, docker-hop counted (the docker bridge adds overhead vs the earlier bare box; the shape cross-checks). Fresh-session connect: p50 ≈ 23 ms — matches the ~19–25 ms B2-era figure and validates the pooling discipline's value (~2.4 ms amortized vs 23 ms fresh).
Property tests (the contract suite) — all green, sequentially
tests/contract.rs — 11 tests, pg twin of POC #1's suite, all shared
assertions reused. Invocation note (verified 2026-10-04 in this
repo's review pass): the suite passes under cargo test --test contract -- --test-threads=1 in one process; default parallel execution fails
6–8 tests by cross-test interference, not by contract failure — each
test builds its own engine + listener over the same database and
channels (poc:q/s/n) and truncates the shared tables, so parallel
tests receive each other's notifications and race each other's
truncates ("delivered before commit", "jobs lost", incomplete
state re-reads). Every test passes in isolation; the harness lacks
per-test channel/table namespaces, which a Phase 1 test harness must
have as a first-class feature (the same shared-server parallel-suite
shape alkblobs' --all-features gates solve with engine-scoped
namespaces). Recorded as a harness caveat — none of the failure modes
are contract failures.
| Property | Result |
|---|---|
| enqueue+business+notify in one caller tx; rollback drops all (no ghosts: queue, stream, notification) | ✅ |
| exactly-once claim under 4 concurrent producers + 4 concurrent claimants (SKIP LOCKED claim SQL) | ✅ |
| 40 jobs 4 producers → 40 unique claims + full ack + zero ghosts | ✅ |
| stream read/save offset through caller tx; rollback drops; offset advances | ✅ |
| lock acquire/release/renew with TTL; expiry re-acquirable | ✅ |
| fan-out: 4 subscribers × 1 channel, every one wakes | ✅ |
| burst 30 commits: per-payload 30/30 delivered; state re-read complete | ✅ |
| listen-wake queue claim path (commit → notify → wake → claim) | ✅ |
| in-tx NOTIFY delivers only on commit (not at statement time) | ✅ |
| pooled-LISTEN-discard (#360): registers but never delivers; dedicated control delivers | ✅ |
| listener-kill → reconnect-wake → no replay of gap notify → post-commit delivery → state re-read complete | ✅ |
| notify payload boundary (7700 ok; 8100 rejected client-side) | ✅ |
| read-your-writes under read committed (in-tx + post-commit) | ✅ |
Decision gate — evaluated
- Contract: every shared property holds. The commit-atomicity
property via in-tx NOTIFY is verified natively (
notify_fires_only_ on_commit+ rollback-ghost tests); exactly-once claim holds under concurrency viaFOR UPDATE SKIP LOCKEDclaim SQL. ✅ - Seam: the caller-tx shape survives with measured costs (2.4 ms
p50 ship config). Preference for shape (a) recorded with evidence.
The
*_txseam is cheaper to hold on pg than on SQLite (Send+Sync client; no spawn_blocking round-trips). ✅ - Wake: LISTEN plumbing is robust (reconnect honest, synthetic reconnect-wake closes the replay hole operationally, fan-out correct) and decisively beats poll (3.1–6 ms vs 32–50 ms at comparable claimant counts; 300/300 isolated wakes at 1.1 ms p50). ✅
Verdict: PASS on all three gate conditions. OQ-ST-03 closes with "per-engine drivers: rusqlite+honker-core (SQLite) / tokio-postgres + deadpool-postgres (Postgres)". The sqlx PgListener fallback posture is retired — no condition requiring it fired.
What feeds where
- OQ-ST-03 (Postgres half): resolved — tokio-postgres + deadpool as recorded; per-engine-crate split (OQ-ST-02) keeps binary drivers single, eliminating the link-collision class of problems the SQLite arm documented.
- OQ-ST-04 (reactive contract, pg side): measured ground.
- Wake contract numbers: LISTEN p50 ≈ 1.1 ms (push), claim-latency p50 ≈ 3–6 ms end-to-end; poll-only fallback ≈ interval-bound.
- Listener semantics: no replay; recovery = synthetic reconnect-wake
- re-read; subscriber contract stays opaque-wake + re-read (identical shape to SQLite's overtriggering watcher — the two engines now share the same wake contract).
- Delivery-guarantee split confirmed native: notify = fire-and-forget
(commit-atomic, at-most-once per listener session, no replay);
streams = durable with offsets. The trait must NOT promise replay
under
listen()— both engines are honest only as opaque wake. - Tx-seam: caller-held tx handle (
*_txon a handle) is the seam on both engines; pg's handle is async-native (Send+Sync client) while SQLite's is a bridged lease. Same shape, different bridging mechanism — the core-crateTxHandletrait from POC #1's sketch stands, with the pg handle as the trivial-instance case.
- OQ-ST-05 (queue semantics): re-derive-on-tokio-postgres posture
strengthened — the minimal queue table +
SKIP LOCKEDclaim + LISTEN wake is ~40 lines of SQL around the pool, the exactly-once property rides pg's native serialization semantics, and the pgboss-rs schema family remains design-reference (its states matter only for retry/dead-letter depth, which is OQ-ST-05's design work; the POC's minimal table sufficed for every property). - OQ-ST-08 (multi-host): the pg engine is natively multi-host — the property tests ran all-through-network (docker bridge), the listener/wake machinery is connection-based (per-process), and nothing assumes single-host. The engine-capability question remains for the trait surface, but the pg side has no single-host assumption to remove.
- Dependency postures (OQ-ST-06-adjacent, per-subsystem votes):
honker-core = published-library (POC #1); deadpool-postgres +
tokio-postgres = published-library (this POC — clean, zero
conflicts); postgres-notify = derive-not-adopt (the 0.3.8 quirks
- single-maintainer posture + our forwarder being already-learned territory; fallback if upstream improves).
Honest caveats
- Same single-box posture as POC #1 (8-core shared dev box, dockerized server over the docker bridge). Absolute numbers carry the docker-hop (~284 µs raw floor here vs the ~150 µs-era bare-metal figure); relative/shape claims are the deliverable and were consistent across re-runs (debug and release).
- The LISTEN re-attach "storm" is tested as one-connection-N-channels re-listen (our engine shape); a per-listener-connection storm (N processes each × M channels at reconnect) is bounded by N × M separate LISTEN statements — plausible but not measured (the engine shape never exercises it; recording as assumption with the reasoning).
- The queue table is the minimal spec-out-of-scope shape (enqueue, claim, ack, visibility column present but not scheduled/retried). Retry/backoff/dead-letter depth remains OQ-ST-05's design work; the transactional and claim properties this POC pins are the hard driver-coupled part and they pass.
postgres-notifyverification was against 0.3.8's published source (crate downloaded into the cargo registry cache); behavior quirks (lazy reconnect, initial-connect script skip, identifier quoting) are recorded from that source plus in-probe verification, cited as of 2026-10-04.- The synthetic reconnect-wake channel is a reserved name
(
__listener_reconnected__) — engine consumers choosing their own channel names must not collide; a prefix convention or a separate meta-channel namespace is Phase 1 contract surface.
Artifacts
- POC crate:
/workspace/alkstore-pg-posture-poc(self-contained, published-deps-only). - Tests:
cargo test→tests/contract.rs(11 tests; sequential invocation: all pass; parallel default invocation interferes across tests via the shared db/channels — see the invocation note above). - Probe binary:
cargo run --release -- seam|watch|burst|claim|pollvlisten|pool|pnlisten|smokeper the binary's help (wake command prints the notify-latency table; pollvlisten the consumption-posture table). - Probe examples (
examples/pgdiag_st1.rsraw floor + fresh session;pgdiag_st4.rspool-budget accounting;raw_listen_*.rs,pn_*.rs,shared_listener_*.rs,attach_control.rsthe listener-substrate steps; each runs standalone against the harness server). - Harness: docker
pglo-poc(postgres:16-alpine, :15432, dbblobs). Note for re-runs: the container also carriessynchronous_commit=offas a server default from its earlier POC use; the POC's pools setsynchronous_commitper connection via connect options, so probes are self-consistent — butSHOW synchronous_commitoutside the POC readsoffon the server.