Files
alkstore/tasks/pg-suite-infra-hardening.md
T
glm-5.3-flash 5c03fb2130 pg suite-infra hardening (task pg-suite-infra-hardening): the wave-4 review's F-1 defense-in-depth candidates — must_recv_event re-shaped from the 20 ms try_recv polling loop to a parked recv().await under the 15 s timeout wrapper (stream_tests.rs, the sole pg copy — SQLite twin untouched; the poll loop's wake-subscription interaction surface the F-1 flake suspected is out of the hot path, and the deadline assert still bounds the property). The parked form's terminal arms are explicit: Some(Err(e)) keeps the errored-instead-of-idling panic, None gets a receiver-closed panic the poll form never saw. The deadline miss self-diagnoses (the small-honest realization of candidate (b)'s discriminator): read_since(offset, 1000) over rows beyond the receiver's position names the residual class — rows durable undelivered (wake/re-drain class) vs no rows (publish-visibility class); with the parked recv a wake-arrived-but-re-drain-missed arm is structurally implausible (only a read error could miss, and it surfaces Err). Candidate (b)'s literal bridge-side counter skipped, reason recorded in the task (surfacing the bridge wake count across the dyn EventReceiver boundary needs downcast/keyed-global machinery beyond the small-honest bar); the small honest piece did land: wait_wake's Lagged(n) arm now logs (eprintln, house posture matching notify.rs's bridge_loop — and forwarder.rs's 'the receiver bridge's Lagged arm logs / recovers' doc claim now true at both bridges), stream name threaded into wait_wake's signature so the log attributes the lag. Verified: pg stream module 21/21 vs harness server (full module run), tx_publishes_compose_with_the_handle 5 solo re-runs green (determinism re-check under the parked shape), two consecutive full pg harness runs green (121 lib + 25 suite + 9 schema, ~72 s each), cargo test -p alkstore-postgres green server-less (skips clean), workspace cargo test green (12 binaries), clippy -D warnings, fmt clean
2026-10-10 08:00:29 +00:00

116 lines
5.4 KiB
Markdown

---
id: pg-suite-infra-hardening
name: Postgres test-infra hardening — F-1's defense-in-depth candidates
status: completed
depends_on: []
scope: single
risk: low
impact: isolated
level: implementation
tags: [wave-5, postgres-engine, tests]
---
## Description
Land the defense-in-depth test-infra hardening the wave-4 review
recorded for F-1 (`tasks/review-wave-4.md` Notes) — **explicitly not
load-bearing since `pg-fix-tx-wake` retired F-1's engine-side root
cause** (the compose test is deterministic, 20/20 solo runs green at
the fix-batch gate). This task exists because wave 5 was the named
home ("wave 5's suite hardening, or a wave-5-adjacent test-infra
task") and the candidates are cheap; if the wave-5 window gets tight,
cancelling this task loses nothing but insurance.
Work (the review's candidate dispositions, cheapest first):
- **(a) Harden `must_recv_event`'s deadline** — replace the 20 ms
polling loop with a parked `recv().await` under a timeout wrapper;
the deadline assert still bounds the property, the poll-loop's
wake-subscription interaction surface goes away.
- **(b) A `LOG_LAGGED`-style diagnostic counter on the bridge** —
discriminates "wake never arrived" from "wake arrived, re-drain
missed" if a wake-shaped flake ever recurs. Land only if it is a
small, honest addition (a test-observation counter, `#[cfg(test)]`-
gated or eprintln-postured per the house test style); skip and
record if it wants more machinery than that.
Candidate (c) (leave the skip-posture as-is) is the do-nothing arm —
adopted by default for anything not landed.
## Acceptance Criteria
- [x] `must_recv_event` parks on `recv().await` under a timeout
wrapper (no polling loop); the pg stream tests stay green
against the harness server (a full stream-module run)
- [x] Candidate (b) either landed small or recorded as skipped with
the reason
- [x] `cargo test -p alkstore-postgres` green (server-less skips
clean); clippy `-D warnings`; fmt clean
## References
- tasks/review-wave-4.md (F-1's Notes — the candidate dispositions)
- tasks/review-wave-4-fixes.md (F-1 retired; defense-in-depth posture)
- tasks/pg-fix-tx-wake.md (the engine-side fix that made this
non-load-bearing)
## Notes
Decisions of record:
- **(a)** landed as specified: `must_recv_event` is now
`timeout(15 s, receiver.recv())` — parked, no polling loop. The
old helper's `try_recv`-loop `Err` arm split into the parked
shape's two failure arms: `Some(Err(e))` → the same
"receiver errored instead of idling" panic (an error during the
wait surfaces immediately, as before), and `None` → a new
"receiver closed before the event arrived" panic (the parked form
makes the terminal arm visible, the poll form never saw it).
`try_recv` is otherwise untouched as a test tool (other pg test
modules still drain with it).
- **(b)**: the `wait_wake`'s `Lagged(n)` arm now logs (eprintln,
house posture — matching notify.rs's `bridge_loop`; it also makes
forwarder.rs's "the receiver bridge's `Lagged` arm logs / recovers"
doc claim true at both bridges — that claim was half-wrong on the
stream side). The arm still treats lag as a wake (re-drain).
The stream name is threaded into `wait_wake`'s signature so the
log attributes lag to the stream, not anonymous.
- **(b)'s full bridge-side counter — skipped, recorded**: surfacing
the bridge's wake-observation count into the deadline panic would
require plumbing a counter Arc across the `dyn EventReceiver`
trait boundary (a test downcast or a keyed global registry) —
more machinery than the small-honest bar. The discriminator's job
is covered test-side instead: with the parked recv, a "wake arrived,
re-drain missed" arm is structurally implausible (the re-drain
reads exactly what a re-read reads; only a read error could miss,
and it surfaces `Err`), so the deadline panic self-diagnoses: it
reads the durable rows beyond the receiver's position via
`read_since(offset, 1000)` and names the residual class — rows
undelivered (wake/re-drain class; wait_wake's Lagged log speaks to
feed lag there) vs no rows (publish-visibility class). Test
harness only; no engine-state change.
- The deadline stays 15 s (the review's bound of record; unchanged
— only the wait shape moved from poll to park).
## Summary
**Landed**: `must_recv_event` re-shaped from the 20 ms `try_recv`
polling loop to a parked `recv().await` under a 15 s timeout wrapper
(stream_tests.rs — the sole pg copy; the SQLite twin untouched, this
task is pg-specific), with a self-diagnosing deadline panic
(`read_since` presence check naming the failure class); the stream
bridge's `Lagged(n)` arm now logs the lag (`stream.rs` `wait_wake`,
stream name threaded in — the surfaced-not-silent posture now true
at all wake-feed bridges); the literal bridge-side diagnostic counter
skipped with reason above (the deadline diagnosis covers the
discrimination test-side).
**Verified**: the pg stream module 21/21 green against the harness
server (one full module run, ~19 s at `--test-threads=4`);
`tx_publishes_compose_with_the_handle` 5 solo re-runs green
(determinism re-check under the new parked shape); two consecutive
full pg harness runs green (121 lib + 25 contract-suite + 9 schema,
~72 s each); `cargo test -p alkstore-postgres` green server-less
(harness rows skip cleanly); workspace `cargo test` green (12 test
binaries); `cargo clippy --all-targets -- -D warnings` clean;
`cargo fmt --check` clean.