Wave 4 decomposed: Postgres engine — 11 tasks (schema, open/opts, seam, forwarder, mechanisms, scheduler/outbox, integration, review gate); plan synced
This commit is contained in:
1 parent
ecb8211694
commit
4caea21098
11 files changed
+1287
-3
No files matched your search
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-10-08 (wave 3 implemented + reviewed; review-gate fixes: substrate boundary move, writer-slot error-arm release; wave 4/5 decomposition may proceed)
|
||||
last_updated: 2026-10-08 (wave 4 decomposed — 11 tasks; waves 1–3 implemented + reviewed)
|
||||
---
|
||||
|
||||
# alkstore — Implementation plan
|
||||
@@ -35,7 +35,7 @@ parallel).
|
||||
| [1](#wave-1--foundations) | Workspace scaffold; core crate (errors, value types, full trait surface); contract-suite scaffold | — | implemented + reviewed (2026-10-08) |
|
||||
| [2](#wave-2--sqlite-substrate-fork) | honker-core fork into `alkstore-sqlite/src/substrate/`: port, deltas, provenance, test floor | wave 1 (workspace scaffold only) | implemented + reviewed (2026-10-08) |
|
||||
| [3](#wave-3--sqlite-engine) | SQLite engine: connection architecture, re-derived queue ops on contract v1, scheduler/outbox, tx seam, SQLite backlog column | waves 1 + 2 | implemented + reviewed (2026-10-08) |
|
||||
| 4 | Postgres engine: schema bootstrap, pool/open, listener/forwarder, all mechanisms, tx seam, pg backlog column | wave 1 | not yet decomposed |
|
||||
| 4 | [Postgres engine](#wave-4--postgres-engine): schema bootstrap, pool/open, listener/forwarder, all mechanisms, tx seam, pg backlog column | wave 1 | decomposed (11 tasks) |
|
||||
| 5 | Contract suite: the cross-engine equivalence properties (core-contract.md §Verification backlog), version-stamped per ADR-017 | waves 3 + 4 | not yet decomposed |
|
||||
| 6 | Release readiness: crate docs, deployment matrix final pass, README (written last, honestly), publish prep; mem-engine and fuzzing decisions | wave 5 | not yet decomposed |
|
||||
|
||||
@@ -101,6 +101,86 @@ shaped this wave's task set:
|
||||
panic probe → wave 5's contract-suite rows; N-1's growth-posture
|
||||
review → wave 6.
|
||||
|
||||
## Wave 4 — Postgres engine
|
||||
|
||||
The second engine: the core contract implemented on tokio-postgres +
|
||||
deadpool-postgres per engine-postgres.md — schema bootstrap (one
|
||||
engine-owned schema, default `alkstore`, ADR-010 §8), the pool/open
|
||||
constructor, the hand-rolled LISTEN forwarder (dedicated non-pooled
|
||||
listener connection, bounded broadcast fanout, exponential-backoff
|
||||
reconnect with re-LISTEN, the synthetic reconnect-wake on
|
||||
`__alkstore_listener_reconnected__`), the full `Store`/`TxHandle`/
|
||||
mechanism-handle trait impls (natively async — no `spawn_blocking`
|
||||
seam; the tx handle holds the pooled object directly, ADR-007's pg
|
||||
arm), the re-derived queue machinery (`FOR UPDATE SKIP LOCKED` claims,
|
||||
LISTEN-driven wake with re-poll safety net), the scheduler leader loop
|
||||
and outbox helper, and the engine's backlog column in the contract
|
||||
suite (factory-parameterized; wave 5 runs the same rows against both
|
||||
engines).
|
||||
|
||||
The wave is deliberately shaped as wave 3's structural twin — same
|
||||
task rhythm (constructor → seam → mechanisms in parallel →
|
||||
scheduler/outbox → integration → review gate) — because the two
|
||||
engines implement the same contract and the wave-3 task set's
|
||||
boundaries proved clean. The deltas are the engine's own: no
|
||||
substrate (the pg machinery is re-derived greenfield per ADR-004/005,
|
||||
with the pg-boss schema family as design reference), a natively-async
|
||||
seam (Send+Sync client, POC #2 compile-probe), the forwarder as the
|
||||
wake substrate (with its two POC-pinned deadlock pitfalls owned as
|
||||
test-pinned failure modes), and the `PayloadTooLarge` client-side
|
||||
check (this engine *produces* the variant — the one runtime carriage
|
||||
of an engine asymmetry, ADR-016 §5).
|
||||
|
||||
Wave-3 outcomes absorbed into the task set:
|
||||
|
||||
- **The `#[doc(hidden)]` constructors** (`Job::from_row`,
|
||||
`StreamEvent::from_row`, `Schedule::new`, `Wake::new`) already
|
||||
exist — wave 3's pre-work task built them engine-agnostically; wave
|
||||
4 consumes them as-is (no wave-4 equivalent needed).
|
||||
- **The engine-side arithmetic is re-owned, not shared**: the
|
||||
equal-jitter backoff curve, the opts-resolution rules
|
||||
(delay-over-`run_at`, relative-`expires`, the derived stamp sets
|
||||
300/3/5/none and 60/5/5), and the outbox backing-queue derivation
|
||||
are each engine's own implementation (ADR-012 §2's one-owner rule
|
||||
applied per engine); the pg tasks re-implement them from the ADR
|
||||
text, and the contract suite (wave 5) pins the two engines'
|
||||
arithmetic to identical outputs. The SQLite engine's `resolution.rs`
|
||||
is reference, not a dependency.
|
||||
- **The `@every` spec grammar has no shared parser on this side** —
|
||||
the SQLite engine reuses the substrate's `parse_every_interval`
|
||||
(one-line delta D-31's neighbor); the pg engine owns its parser
|
||||
(the grammar is small and pinned: `@every <n><unit>`, `s|m|h|d`).
|
||||
Equivalence of *behavior* (what fires, when) is suite-pinned; the
|
||||
parsers themselves are per-engine.
|
||||
- **The wave-3 review's deferred notes** (reader-pool close path,
|
||||
commit-error-arm coverage) stay SQLite-scoped — the pg engine's
|
||||
pool is deadpool-managed (no hand-rolled close path to review) and
|
||||
its commit-error arm gets coverage in the pg tasks' own tests.
|
||||
- **The suite's factory contract** (isolation + idempotent teardown)
|
||||
is what the pg factory implements — a fresh schema per `open` per
|
||||
the SQLite factory's precedent (fresh temp file there); the
|
||||
POC's shared-server parallel-interference caveat (findings,
|
||||
invocation note) is answered by exactly that isolation, not by
|
||||
sequential-only harnesses.
|
||||
|
||||
Test posture: the engine's tests need a live Postgres server. The
|
||||
harness convention is the POC's (dockerized `postgres:16-alpine` on
|
||||
:15432, the `pglo-poc` container — still running in the dev
|
||||
environment); connection settings ride environment/config, never
|
||||
hardcoded. Tests that cannot reach a server skip cleanly (the
|
||||
`SKIP`-posture), so the workspace gates stay green server-less — but
|
||||
the wave's acceptance requires the suite green *against* the server.
|
||||
|
||||
One design point the architecture leaves to implementation (pinned in
|
||||
the wave-4 tasks, flagged here for visibility): **the queue/stream
|
||||
wake-channel naming**. The contract pins LISTEN as the pg wake
|
||||
trigger and pins the channels/queues shared namespace, but no doc
|
||||
names the channel an enqueue/publish notifies on. The tasks pin the
|
||||
natural realization — the mechanism name *is* the wake channel
|
||||
(`listen(queue_name)` receives that queue's enqueue wakes; same for
|
||||
streams), legal by construction under the shared namespace — with
|
||||
the reserved reconnect-wake channel staying the only reserved string.
|
||||
|
||||
## Decided points
|
||||
|
||||
- **Contract-suite layout — option (a)**: a small internal
|
||||
@@ -159,4 +239,8 @@ decomposes. Specific gates:
|
||||
`open_writer_connection` boundary move out of `substrate/mod.rs`;
|
||||
the writer-slot error-arm stranding in
|
||||
`with_writer`/`begin`/`commit`); two minor notes deferred to
|
||||
wave 5/6 (reader-pool close path, commit-error-arm coverage).
|
||||
wave 5/6 (reader-pool close path, commit-error-arm coverage).
|
||||
- **Wave 4 decomposition** (2026-10-08) — shaped as wave 3's
|
||||
structural twin; wave-3 outcomes absorbed (constructors exist;
|
||||
arithmetic re-owned per engine; per-engine `@every` parser;
|
||||
SQLite-scoped deferred notes stay put). See the Wave 4 section.
|
||||
Reference in new issue
Block a user