diff --git a/docs/research/phase-0.md b/docs/research/phase-0.md index d16e490..fe266ac 100644 --- a/docs/research/phase-0.md +++ b/docs/research/phase-0.md @@ -5,7 +5,11 @@ per-engine drivers, rusqlite+honker-core for SQLite / tokio-postgres+ deadpool-postgres for Postgres, findings in poc-pg-posture-findings.md; OQ-ST-04 now has measured ground on both engines, wake contract numbers + tx-seam shapes + listener-recovery semantics recorded from -POC #2; OQ-ST-05/06 carry both POCs' per-subsystem votes) +POC #2; OQ-ST-05/06 carry both POCs' per-subsystem votes. Findings +review-pass verified 2026-10-04: contract suite runs green sequentially +(`--test-threads=1`); parallel invocation fails by cross-test +interference (shared db/channels harness) — recorded in the findings, +not a contract failure.) --- # alkstore — Phase 0 (Exploration) @@ -480,13 +484,38 @@ inherited watcher is tighter than a re-derived one (p50 1.40 vs 2.15 ms, max 29 vs 172 ms, with battle-tested failure handling), and the `.so` runtime dependency is packaging cost A doesn't pay for no compensating advantage. The transactional contract holds identically -on both (it is SQLite's property, not the posture's). New -constraints recorded for the engine crate regardless: +on both (it is SQLite's property, not the posture's). Constraints +recorded for the engine crate regardless: honker-core=0.5.0 pins rusqlite ^0.40.1 whose rustc requirement (≥1.99) is a deployment note, and mixed rusqlite+sqlx binaries currently need a vendored one-line libsqlite3-sys patch — OQ-ST-02's per-engine-crate split is what keeps the engine binary single-driver. +**Postgres half resolved by POC #2 (2026-10-04; findings: +`poc-pg-posture-findings.md`): tokio-postgres + deadpool-postgres.** +All three gate conditions held: the transactional property is native +(in-tx NOTIFY delivers only at commit; rollback drops job row + +business row + notification), exactly-once claim via `FOR UPDATE SKIP +LOCKED`, and the LISTEN wake layer is push (p50 1.1 ms, 300/300; +claim latency 3–6 ms vs poll-only 32–50 ms — 5–16×, the push channel +pgboss-rs lacks, measured). Structural findings the contract must +absorb: pooled connections cannot carry LISTEN (deadpool#360 — pinned +as our own test; the dedicated listener connection is a per-process +budget line outside the pool), and the `*_tx` seam differs from +SQLite's exactly where expected (pg's client is Send+Sync — the tx +handle is held directly across awaits; SQLite's is a bridged +writer-slot lease — same seam shape, different bridging). Listener +substrate vote: hand-rolled ~90-line forwarder (immediate reconnect, +quoting control, no dependency posture) over `postgres-notify` 0.3.8 +(lazy reconnect, connect_script skipped at initial connect, +unquoted-identifier LISTEN — derive-not-adopt; fallback if upstream +improves). The sqlx `PgListener` fallback retired unfired. + +**OQ-ST-03 resolution: per-engine drivers — rusqlite + honker-core +(SQLite engine), tokio-postgres + deadpool-postgres (Postgres +engine), under OQ-ST-02's per-engine-crate split.** Resolved +(2026-10-04), POC-backed on both halves. + **Resolved (2026-10-04, both halves): per-engine drivers — rusqlite + honker-core for the SQLite engine; tokio-postgres + deadpool-postgres for the Postgres engine.** The Postgres half is diff --git a/docs/research/poc-pg-posture-findings.md b/docs/research/poc-pg-posture-findings.md index 88da7ca..00073e0 100644 --- a/docs/research/poc-pg-posture-findings.md +++ b/docs/research/poc-pg-posture-findings.md @@ -352,10 +352,23 @@ Reading (shape, not absolute — different machines/databases): ~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 +## Property tests (the contract suite) — all green, sequentially `tests/contract.rs` — 11 tests, pg twin of POC #1's suite, all shared -assertions reused: +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 | |---|---| @@ -467,7 +480,9 @@ retired — no condition requiring it fired.** - POC crate: `/workspace/alkstore-pg-posture-poc` (self-contained, published-deps-only). -- Tests: `cargo test` → `tests/contract.rs` (11 tests). +- 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|smoke` per the binary's help (wake command prints the notify-latency table; pollvlisten the consumption-posture table).