Sweep of docs/reviews/ and tasks/ per the plan's §Wave 8 historical note: 'wave 7'-means-release-pass references annotated or reworded per the review-wave-5.md renumber-annotation precedent; genuine fuzzing-wave/review-7 references untouched. Out-of-scope architecture-doc trail records documented in the task's Notes. 12 annotated, 1 reworded (live pointer); taskgraph validate green.
20 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | |||
|---|---|---|---|---|---|---|---|---|---|---|---|
| review-wave-4 | Review gate — wave 4 (Postgres engine) | completed |
|
moderate | low | phase | review |
|
Description
Review the Postgres engine before wave 5 decomposes. Primary lens per the plan's review gates: engine-vs-contract conformance — the same discipline as the wave-3 gate, now against the second engine, with the pg-specific machinery added. Wave 5 (the contract suite) pins cross-engine equivalence; this gate checks the pg implementation against the pinned contract text line by line.
Check:
- Contract conformance: every trait method's behavior against
core-contract.md's per-mechanism text — validation at entry points
(auto-commit AND tx paths), error arms (
Database-only receivers,Codecat payload seams,LeadershipLostvs clean stop), value shapes (Job/StreamEventfield-for-field), the no-work-is-a-value vocabulary (None/false/empty-Vecwhere pinned, never errors). - ADR-023 follow-through: extent guards at trait-impl entry
(claims + all four stream reads); duration guards on both lock call
sites;
encode_payloadconsumed fallibly at every call site. - ADR-016 §5: the 8000-byte check is client-side, typed, before
any round trip, on both
notifyandnotify_tx; the limit constant has one owner. - Forwarder integrity (the pg engine's own high-risk machinery —
the analogue of the wave-3 gate's seam-integrity lens): the two
POC-pinned deadlock pitfalls structurally excluded (poll loop
before first query;
Clientalive for the listener's lifetime); reconnect backoff + re-LISTEN from the live channel set; the synthetic reconnect-wake on the reserved string broadcast to every subscriber; lag surfaced, not silent; receiver close semantics exactly the pg arm (open across reconnects, close at shutdown only, terminal, never reopens). - Seam integrity: drop = rollback under panic; failed
COMMIT/ROLLBACK arms discard (not re-pool) the object — pool
accounting exact under error paths (deployment.md's ADR-021 note);
ops-after-consume fail closed; no
spawn_blockinganywhere (the natively-async posture — a stray bridge would be a finding). - Backoff curve + boundary math: the engine-side formulas match ADR-010 §3's pinned range/cap and ADR-009 §4's boundary guarantee exactly (wave 5 pins cross-engine equivalence; this gate checks this implementation against the text).
- Schema posture: one engine-owned schema; payload columns
bytea(exact bytes — no JSONB normalization); no per-queue tables; bootstrap idempotent. - Backlog column: the engine's suite rows present, stamped, green
against the pg factory; the
PayloadTooLargepg arm row present. - Family standards: no panics, no unwrap/expect outside tests, no inline comments (doc comments fine), module-per-file.
- Gates: full workspace build/test/clippy/fmt; the pg suite green against the harness server.
Acceptance Criteria
- Contract conformance spot-checked against the spec text (not just the tests)
- ADR-023's numeric-domain + typed-encoding follow-through verified at their sites
- Forwarder + seam integrity verified (code-read, not test-name-trust)
- Backoff curve + scheduler boundary math match the pinned ADR text
- Backlog column present, stamped, green against the pg factory
- All gates green (incl. against the harness server)
- Findings recorded; wave 5 decomposition may proceed
References
- docs/plans/implementation.md (Review gates)
- docs/architecture/core-contract.md
- docs/architecture/engine-postgres.md
- docs/architecture/decisions/004-postgres-driver.md
- docs/architecture/decisions/016-deployment-honesty.md §5
- docs/architecture/decisions/023-fourth-review-round.md
- tasks/review-wave-3.md (the gate discipline's precedent)
Notes
Review performed 2026-10-08 (opencode, glm-5.3-flash) — full code-read of
alkstore-postgres/src (all 13 machinery files + 9 test modules, ~4.4k
lib lines) against core-contract.md, engine-postgres.md, ADR-004/007/
008/009/010/015/016/019/020/021. Zero conformance findings needing a
code change. Two flake investigations and four recorded observations
(all documentation/coverage-shaped, deferred to wave 5's natural homes)
below.
Gate checklist record (code-read against the spec text, per the acceptance criteria — not test-name-trust):
- Contract conformance: entry-point validation on every name-bearing
method, auto-commit AND tx paths, before any round trip
(
store.rswiring + all eleven*_txin tx.rs;InvalidNamefor empty/whitespace-only,ReservedNamefor prefixed, via core'svalidate_shared_name/validate_local_name; stream-consumer/ owner/worker ids as local names).Database-only receivers (recv/save_offsetErr arms —database_onlyremap in stream.rs);Codecat every payload/decode seam (encode + row decodes, no silent fallback);LeadershipLostvs clean stop arms (acquire-refusal and renewal-loss both return before any tick);Closedon consumed tx shells and pool-checkout paths. Value shapes decoded through core's#[doc(hidden)]constructors (18-columnJobshape,StreamEventfield-for-field, dead-visibleget_jobcarryinglast_error/died_at). No-work vocabulary held (Ok(None)/Ok(false)/emptyVecwhere pinned). Queue scoping (WHERE queue = $2) verified onget_job_tx/get_job/ack_batch/cancel; the live-then-dead select order matches the SQLite arm. - ADR-023 follow-through: extent guards at trait-impl entry on
claim_batch(n <= 0→ emptyVec), both auto-commit stream reads, both tx stream reads, andEventReceiver::read_since— pg's negative-LIMIT-is-a-server-error artifact unreachable. Duration guards on both lock call sites (try_lock,Lock::renew—ttl <= 0→ opaqueDatabase, detail in the source chain). Boundary args total (negativetrim_todeletes nothing, unguarded — verifiedid <= -7matches no rows).encode_payloadconsumed fallibly at all 8 call sites through the oneencode_payload_bytesalias; no silent fallback. - ADR-016 §5: the 8000-byte check is client-side, typed
(
PayloadTooLarge { limit: NOTIFY_PAYLOAD_LIMIT }), before any round trip, on bothnotifyandnotify_tx; one owner of the limit constant (tx::NOTIFY_PAYLOAD_LIMIT); predicatelen >= limit(the NUL-inclusive wire budget, probe-pinned in tx_tests); measured on the serde_json serialization (the stored-bytes form). - Forwarder integrity: pitfall 1 structurally excluded (the poll
task owns the
Connectionand is spawned before any client query every generation; the command select keeps co-residency permanent); pitfall 2 excluded (the loop owns theClientfor the generation's lifetime; drop only at shutdown or post-session-death). Reconnect: 50 ms → 2 s cap exponential, re-LISTEN from the live channel-set snapshot (registry-write-first ordering so a registration is never lost), synthetic reconnect-wake on the reserved string broadcast to every subscriber (verified: it rides the raw fanout, and the wake-per-receiver bridge passes it through with the channel filter's explicit reserved-string arm). No-replay honesty pinned (the gap test asserts the committed-during-gap notify is not delivered). Lag surfaced not silent (Lagged(n)logged-and-skipped at both the bridge loop and the stream subscriber). Receiver close semantics exactly the pg arm: the broadcast subscription + bridge outlive connection generations (close is shutdown-only — the fanout sender take inForwarder::shutdownplus the loop's clone at exit); a backend kill delivers the reconnect-wake, notNone; terminal; the pinned tests assert never-reopens. - Seam integrity: drop = rollback via the captured
Handle::spawndetached teardown (no current-context resolve — panic-safe; the runtime-gone arm closes the session server-side and the server aborts the open tx, so no ghost survives it); failed COMMIT/ROLLBACK/BEGIN arms discard viaObject::take(never re-pool an unknowable-state client) — pool accounting exact under error paths (the deferred-FK COMMIT-failure test pins it); ops-after-consume fail closed (Error::Closed);with_txderives from the trait's provided method overbegin_tx/commit/drop — no engine override to audit.grep spawn_blockingoveralkstore-postgres/srcmatches only doc text; every op is a straight.awaitthrough the held object (the natively-async posture holds — no stray bridge). The one sync-signature bridge (EventReceiver::save_offset→drive_syncon the dedicated idle wake runtime) is documented at the site with its probed-arms rationale — the honest sync→async seam, not aspawn_blockingre-entrancy trick, and it carries no engine state. - Backoff curve + boundary math:
backoff_delay_sis line-identical reasoning to the text — equal-jitter[base·2^(a−1)/2, base·2^(a−1)]integerized inclusive, 3600 s cap, attempt index = the post-claim row count, exponent clamp at 30 (saturating, never overflowing); statistical range pins at 400 draws per tuple + the 1800..=3600 cap band + end-to-end row assertions. Scheduler:@everyparser matches the pinned grammar (@every <n><unit>, s|m|h|d, positive n, checked_mul — cron/floats/zero/ unknown-units rejectInvalidSpecpre-storage); first-fire =now + interval(strictly after now); the one-firer-per-boundary machinery is exactly ADR-009 §4's two layers — (a) leadership via the engine's own lock machinery on__alkstore_scheduler(per- instance owner token; loss returnsErr(LeadershipLost)before any tick, both at acquire and mid-run), (b) the row-lockedSELECT … FOR UPDATEtick in one pool tx with fire-enqueues + boundary advance + soonest read committing together (crash mid-tick refires); 64-cap catch-up with skip-forward strictly past now ((gap/interval + 1)·intervalin 128-bit, clamped ati64::MAX). Resolved-stamps sets (plain 300/3/5/none, outbox 60/5/5, onemax_attemptsoverride, delay-over-run_at, relative-expires, one clock read per enqueue) match ADR-010 §3a / ADR-020 line for line; the outbox derivation__alkstore_outbox:{name}is reserved and unreachable byenqueue_tx/queue(). - Seam error mappings: all four helper shapes map into the opaque
Databasewith the source chain preserved; no engine-specific variants minted anywhere. - Schema posture: one engine-owned schema (default
alkstore,PgOpts-parametrized),byteapayload columns asserted per-table (schema_tests), bigserial offsets monotone-never-renumbered (gap test), no per-queue tables (queues are rows), idempotent bootstrap (triple-run converges), schema-prefixed index names (the co-tenant silent-skip hazard documented and answered), identifiers quoted through the onequote_identifierboundary (schema name is the only consumer-supplied interpolation; injection-safe). - Backlog column: 10 rows green against the pg factory (twice this
session): the exemplar name-validation row, the three ADR-023 rows
verified as the same suite functions the SQLite column runs (not
rewritten —
extent_clamp_semantics,duration_refusal_on_non_positive_ttl,payload_round_trip_stores_exact_encoding),payload_too_large_produced_on_pg(the pg arm of the asymmetry row, stamped ADR-008 §5/ADR-016 §5/ADR-020 §4 — the SQLite task's deferred adoption discharged), drop-rollback, in-tx-RYOW, enqueue-opts-resolution, receiver-close-and-save-arms, plus the factory-shape row. All carryContract stamp:doc stamps per the ADR-022 convention (grep-audited). - Family standards: no panics in library code (the only
expects outside#[cfg(test)]are the five Mutex-poisoned guards in forwarder.rs and the wake-runtime build — documented, unwrap-free elsewhere; one wake-runtimeexpectis a fixed-shape builder that cannot fail, module-doc'd). No inline comments beyond the correctness-constraint sites AGENTS.md's exception names (wake postures, unknowable-state arms, the loss-decision owner, predicate conjuncts — all non-obvious-behavior notes). Module-per- file holds;#[non_exhaustive]policy respected (none onPgOpts); core has no driver deps;eprintln!diagnostics at the five swallowed-wake/lag sites match the SQLite twin's posture (the logging story is a wave-7 item (release readiness) — wave 8 since the fuzzing wave's renumber — not a wave-4 defect). - Gates:
cargo build,cargo testserver-less (25 core + 188 sqlite + 111 pg-skip + 10 + 10 suite + 3 + 9 harness), clippy-D warnings, fmt — all green; the pg lib suite 111/111 green against the harness server (two consecutive full runs, 2×47 s, plus stream-module and suite-target re-runs).
Flake investigation (the two task agents' tx_publishes_compose_with_the_handle
report — see Summary below for the disposition): reproduced once in 53
solo runs and once in the first full-suite run of this session; wake
path code-read clean; the stand-alone binary probe that mirrors the
test's beats (64 runs) never missed (delivery latency ~20–210 ms).
Root cause unresolved at gate time — resolved engine-side by the
general review (see F-1's updates below).
Deferred (documented, not fixed — each needs its own small task or a wave-5/6 decision; none is a consumer-visible defect):
- F-1 — the
tx_publishes_compose_with_the_handleflake is open (contradicting the streams/locks agents' "unrelated, wait for wave 5" read: reproduced twice this session — once in a first-of-session full lib run, once in a solo run; ~2/106 runs total, all at the same site). Update (2026-10-09): root cause found by the wave-4 general review (docs/reviews/002-wave-4-general-review.md, Finding 2) — the tx enqueue/publish paths issue nopg_notifywake at all; the subscriber's pre-commit drain parks on a wake that never comes. Fix is engine-side (onepg_notifyinpublish_with_key_tx), not the suite-hardening candidates below, which become defense-in-depth. Update 2 (2026-10-09): retired —pg-fix-tx-wakelanded the engine-side fix. The tx producer paths (publish_with_key_tx,enqueue_tx,outbox_enqueue_tx) now issue theirpg_notifywakes commit-atomically inside the caller's tx (stream name / queue name / derived backing queue as the channel; rollback drops the row with its wake), pinned by tests;tx_publishes_compose_with_the_handleis deterministic (20 consecutive solo runs green). The suite-hardening candidates below remain valid as defense-in-depth but are no longer load-bearing for this flake. Correction to the facts below: the "engine's wake path is honest — the tx INSERT's commit is the NOTIFY carrier" conclusion was wrong (nothing on that path ever sent a NOTIFY); the 64-run probe simply sampled the lucky attach-read/drain-vs-commit ordering every time. Failure signature:must_recv_event's 15 s deadline exhausts — the bridge's re-drain never fires after a committedpublish_tx. Facts established: the engine's wake path is honest (the tx INSERT's commit is the NOTIFY carrier — verified by the 64-run probe mirroring the test's beats, which never missed and never even saw >210 ms; and by 6 whole-stream-module suite runs and 30 full-suite 8-thread runs, all clean); the delivery pipeline introduces no artificial delay (no debounce/sleep — wake → re-drain straight-line); the two test beats (the post-committry_recvdrains and the two 200 ms sleeps) are all before the wait and only make the test late-poll, not miss; and the deadline miss cannot be a slow delivery (a 210 ms probe ceiling vs a 15 s deadline). The residual suspicion therefore sits in the wake subscription path — aLagged/command-race interaction between the fresh receiver's bridge and the forwarder under load — but no mechanism was proved, and nothing in the code contradicts the contract. Recorded for wave 5's suite hardening (or a wave-5-adjacent test-infra task): the candidate dispositions are (a) hardenmust_recv_event's deadline (a parkedrecv().awaitwith a timeout wrapper instead of the 20 ms polling loop — the deadline assert then still bounds the property), (b) aLOG_LAGGED-style diagnostic counter on the bridge to discriminate "wake never arrived" from "wake arrived, re-drain missed", and (c) leave the skip-posture deadline as-is and re-triage on recurrence. Not decomposed now: the flake is test-infra, not engine code, and (b)+(c) are the cheap first steps. - F-2 —
bridge_loop's filter drops non-subscriber channel notifications before the reserved-string check is reachable in the&&'s false path — cosmetic only: the code is correct (the reserved-wake arm matches), the observation is that the condition's order matters and is load-bearing; a//note at the site would help future readers. Not fixed: AGENTS.md's comment policy says no inline comments unless load-bearing — this one arguably is, and the site already carries a doc-comment explaining the mapping; left as-is to avoid comment churn. - F-3 —
spawn_bridge'sspawned.is_finished() → abort()guard (stream.rs:599): detects a bridge task that finished before the receiver was even boxed (runtime-gone class) but the boxed receiver would surface after the bridge died — honest, but it's a probabilistic check (a task could finish between the check and the return, an unavoidable race the guard narrows). The task's failure arm (the mpsc disconnect) still delivers the terminalNone— no lie is surfaced either way. Noted for the wave-5 close-arm rows' fidelity; no action. - F-4 — wake-channel naming is now realized in code but no doc
section states it for streams: the plan's Wave 4 section (lines
174–182) records the decision, and
stream.rs/queue.rsdoc comments name it ("the mechanism-name-is-the-channel realization"), butcore-contract.md's streams/notify sections don't mention the channel naming (they don't need to — it's engine-internal), while the reserved reconnect string is a contract string. No action — recorded here so wave 7's docs pass notices where the naming live.
Wave 5 decomposition may proceed.
Summary
Review gate passed: 0 conformance findings; 1 open flake recorded (F-1) + 3 documentation/coverage-shaped notes (F-2..F-4, no action); all gates green.
The gate's primary lens (engine-vs-contract conformance, line-by-line
against core-contract.md and the ADRs) came back clean across every
checklist item: entry-point validation (both paths), error arms, value
shapes, no-work vocabulary, the ADR-023 guards at their pinned sites,
the ADR-016 §5 client-side typed 8000-byte check with one limit owner,
the forwarder's structural exclusions + reconnect + re-LISTEN +
reserved-string reconnect-wake + no-replay honesty + the pg close arm,
seam integrity incl. the unknowable-state discard arms and pool
accounting, the natively-async posture (no spawn_blocking anywhere),
the backoff curve and scheduler boundary math matching the ADR text
exactly, the one-schema/bytea/no-per-queue-tables posture, the
10-row backlog column (stamped, green against the pg factory, twice),
and family standards.
Gates at review time: cargo build / cargo test /
cargo clippy --all-targets -- -D warnings / cargo fmt --check all
green; the pg lib suite 111/111 green against the harness server
(2×47 s full runs + stream-module and suite-target re-runs).
The one thing this gate cannot close: the flagged
tx_publishes_compose_with_the_handle flake was reproduced twice
(~2/106 runs) and root-caused to neither engine code nor the test's
beat ordering — the engine's wake path is verified honest (64-run
stand-alone probe, whole-module and 30× full-suite runs clean); the
miss is a still-unexplained wake-subscription interaction under load.
Recorded as F-1 for wave 5's suite hardening (candidate dispositions
in Notes); the task agents' "wait for wave 5 if it recurs" posture is
adopted — it recurred, wave 5 gets the record. (Superseded
2026-10-09: the wake-path-honesty conclusion was wrong — the general
review root-caused the flake engine-side — and pg-fix-tx-wake
retired F-1; see F-1's updates in Notes.)
Wave 5 decomposition may proceed.