Wave-6 decomposition (mem engine): eleven tasks per the pg-wave rhythm — foundations (crate scaffold, MemStore::new isolation, guarded state core, wake routing, wasm32 gate from birth), seam-tx (the load-bearing tx overlay: eleven staged _tx methods, commit-merge + wake-at-commit — pg-fix-tx-wake's discipline structural from the start, drop = discard trivial, with_tx panic posture), mechanisms mutually parallel (notify-listen close-at-engine-drop/no-replay/never-coalesced; queues = ADR-010 machine driver-free with the equal-jitter curve and opts resolution as ADR-012 §2's third owner; streams log+offsets+trim; locks TTL registry, no busy-path analog), scheduler-outbox (tick/catch-up-64/leadership through the __alkstore_scheduler lock, engine-uniform per ADR-009 §4; outbox over queues with the 60/5/5 seam stamp), integration (suite third StoreFactory column green on host under a current-thread flavor, wasm32 acceptance items, engine-mem.md to implementation-complete), and the review-wave-6 gate (born-pinned audit: conformance read, discharge-map wiring, wasm items, three-way equivalence green, class-1 window discipline). Window riders: suite-harness-current-thread — the wave's one suite-side pre-task, past_stamp_sleep's blocking sleep goes async per review 003's properties.rs:1683 posture note, enabling the current-thread flavor; pg-fix-scheduler-tick-seam — review 003 Finding 1, the cfg(test) transient-fault seam driving the real tick_with_retries through retry-then-success and exhaustion arms (the last uncovered wave-4 hardening arm, sqlite-commit-error-arm pattern). Task hygiene: pg-fix-open-path frontmatter fixed (unquoted 'max_size: 0' colon-space inside the name scalar broke YAML parsing — taskgraph validate had been red one-error since the wave-4 fix-batch decomposition; also restores review-wave-4-fixes' dependency resolution). implementation.md: wave-6 table row → decomposed, task-set listing with the parallelism note (rider + pre-task independent of the mem chain; rider closes before the gate), wave-6 decomposition bullet in the review-rounds record. Docs-only change; verified taskgraph validate (60 tasks, no cycles), cargo fmt --check, cross-reference read

This commit is contained in:
glm-5.3-flash committed 2026-10-10 09:57:01 +00:00
1 parent 060f262e62
commit 5abd351c86
13 files changed
+939 -5

No files matched your search

+54 -4
View File
@@ -1,8 +1,9 @@
--- ---
status: draft status: draft
last_updated: 2026-10-10 (ADR-024 — the mem engine adopted as wave 6 last_updated: 2026-10-10 (ADR-024 — the mem engine adopted as wave 6,
and decomposed-in-place documentation; release readiness renumbered release readiness renumbered to wave 7; wave 6 decomposed — eleven
to wave 7. Waves 1–5 implemented and reviewed; engine specs stable.) tasks per the pg-wave rhythm with the tx overlay load-bearing. Waves
1–5 implemented and reviewed; engine specs stable.)
--- ---
# alkstore — Implementation plan # alkstore — Implementation plan
@@ -41,7 +42,7 @@ core crate plus the finished suite (wave 5) — born pinned, per
| [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) | | [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](#wave-4--postgres-engine): schema bootstrap, pool/open, listener/forwarder, all mechanisms, tx seam, pg backlog column | wave 1 | implemented + reviewed (2026-10-08) | | 4 | [Postgres engine](#wave-4--postgres-engine): schema bootstrap, pool/open, listener/forwarder, all mechanisms, tx seam, pg backlog column | wave 1 | implemented + reviewed (2026-10-08) |
| 5 | [Contract suite](#wave-5--contract-suite): the cross-engine equivalence properties (core-contract.md §Verification backlog), version-stamped per ADR-017 | waves 3 + 4 | implemented + reviewed (2026-10-10) | | 5 | [Contract suite](#wave-5--contract-suite): the cross-engine equivalence properties (core-contract.md §Verification backlog), version-stamped per ADR-017 | waves 3 + 4 | implemented + reviewed (2026-10-10) |
| 6 | [Mem engine](#wave-6--mem-engine): separate `alkstore-mem` crate, full contract v1 over in-memory mechanisms (tx overlay, queue/scheduler/streams/locks/wakes), the suite's third factory column (born pinned), wasm32 compile-clean acceptance | waves 1 + 5 | not yet decomposed | | 6 | [Mem engine](#wave-6--mem-engine): separate `alkstore-mem` crate, full contract v1 over in-memory mechanisms (tx overlay, queue/scheduler/streams/locks/wakes), the suite's third factory column (born pinned), wasm32 compile-clean acceptance | waves 1 + 5 | decomposed (2026-10-10) |
| 7 | [Release readiness](#wave-7--release-readiness): crate docs, deployment matrix final pass, README (written last, honestly), publish prep; fuzzing decision | wave 6 | not yet decomposed | | 7 | [Release readiness](#wave-7--release-readiness): crate docs, deployment matrix final pass, README (written last, honestly), publish prep; fuzzing decision | wave 6 | not yet decomposed |
## Wave 1 — Foundations ## Wave 1 — Foundations
@@ -311,6 +312,49 @@ transient-error retry loop, MEDIUM — engine-side, small,
mem-independent); Findings 2–3 follow their park recommendation into mem-independent); Findings 2–3 follow their park recommendation into
wave 7's pre-release pass. wave 7's pre-release pass.
**Wave 6's task set** (the decomposition, 2026-10-10 — the pg wave's
rhythm: foundations → seam → mechanisms in parallel → scheduler/outbox
→ integration → review gate):
- `mem-engine-foundations` — crate scaffold (core + tokio sync+time
only), `MemStore::new()` isolation, guarded state core, wake-routing
substrate, clock accessor; the wasm32 compile gate starts here and
stays green onward.
- `mem-engine-seam-tx` — the load-bearing task: the tx overlay (all
eleven `*_tx` staged, commit-merge + wake-at-commit, drop =
discard, `with_tx` panic posture) + the `Store` trait surface +
entry-point numeric-domain guards (`suite-tx-commit-atomicity-rows`
is what consumes it once integrated).
- `mem-engine-notify-listen` — channels wake substrate surface,
three recv forms, close-at-engine-drop, no-replay, never coalesced;
depends on the seam (tx-staged notify).
- `mem-engine-queues` — the ADR-010 state machine driver-free;
equal-jitter curve and opts resolution as the third owner.
- `mem-engine-streams` — in-memory log, per-consumer offsets,
`trim_to`, receiver arms.
- `mem-engine-locks` — TTL registry; the SQLite busy-path question
has no mem analog (loser is a clean `None`).
- `mem-engine-scheduler-outbox` — tick/boundary/catch-up/leadership
through the reserved scheduler lock; outbox over queues.
- `suite-harness-current-thread` — the wave's one suite-side pre-task
(async `past_stamp_sleep`); engine-independent, required before the
mem column's current-thread flavor.
- `mem-engine-integration` — full-surface wiring, the suite's third
`StoreFactory` column green on host under the current-thread
flavor, the wasm32 acceptance items, `engine-mem.md` to
implementation-complete.
- `pg-fix-scheduler-tick-seam` — review 003 Finding 1, riding the
window (engine-side, mem-independent; the last uncovered wave-4
hardening arm).
- `review-wave-6` — the born-pinned gate: conformance read, third-
column discharge audit, wasm acceptance audit, spec disposition;
depends on integration + the rider so the window closes everything.
Parallelism note: the foundation task blocks the seam; the seam blocks
the mechanisms; the mechanisms are mutually parallel. The suite pre-task
and the Findings-1 rider are independent of the mem chain entirely and
can run any time in the window (the rider must close before the gate).
## Wave 7 — Release readiness ## Wave 7 — Release readiness
The original wave 6, renumbered when the mem engine inserted at wave The original wave 6, renumbered when the mem engine inserted at wave
@@ -446,6 +490,12 @@ decomposes. Specific gates:
structural twin; wave-3 outcomes absorbed (constructors exist; structural twin; wave-3 outcomes absorbed (constructors exist;
arithmetic re-owned per engine; per-engine `@every` parser; arithmetic re-owned per engine; per-engine `@every` parser;
SQLite-scoped deferred notes stay put). See the Wave 4 section. SQLite-scoped deferred notes stay put). See the Wave 4 section.
- **Wave 6 decomposition** (2026-10-10) — ADR-024 adopted the mem
engine the same day the wave-5 gate closed; the task set follows the
pg wave's rhythm with the tx overlay as the load-bearing task, the
suite's third column as the born-pinned deliverable, the harness's
async-sleep pre-task, and review 003 Finding 1 riding the window.
See the Wave 6 section.
- **Wave-4 fix-batch decomposition** (2026-10-09) — the general - **Wave-4 fix-batch decomposition** (2026-10-09) — the general
review's findings decomposed into seven `pg-fix-*` tasks + a review's findings decomposed into seven `pg-fix-*` tasks + a
`review-wave-4-fixes` gate: Finding 1 → `pg-fix-forwarder-reconnect` `review-wave-4-fixes` gate: Finding 1 → `pg-fix-forwarder-reconnect`
+92
View File
@@ -0,0 +1,92 @@
---
id: mem-engine-foundations
name: Mem engine — crate scaffold, `MemStore::new()`, guarded state core, wake routing
status: pending
depends_on: []
scope: moderate
risk: medium
impact: component
level: implementation
tags: [wave-6, mem-engine]
---
## Description
The mem engine's foundations (wave 6 — [ADR-024](../architecture/decisions/024-mem-engine.md)):
a new workspace member `alkstore-mem` and the state core every later
task builds on.
- **Crate + manifest**: workspace member per
[ADR-024](../architecture/decisions/024-mem-engine.md) §1 —
dependencies are `alkstore` (versioned path pin per
[ADR-017](../architecture/decisions/017-contract-versioning.md) §4.1,
matching the other engines' manifests) plus tokio restricted to the
**wasm-supported subset (sync + time only)**. No driver
dependencies. `thiserror` via core; no other crates.io surface.
- **Constructor**: `MemStore::new()` — engine-native, no connection
string, no file path (the one documented exception to the
core-contract open prose, amended by
[ADR-024](../architecture/decisions/024-mem-engine.md) §4). Each
`new()` yields a fully isolated instance sharing nothing (the suite
factory's isolation contract); teardown is drop. No `PgOpts`-equivalent
opts struct exists — nothing to configure (if a knob surfaces during
the wave, `MemOpts` with `..Default::default()` follows the family
opts pattern; not assumed now).
- **Guarded per-mechanism state core**: the store instance is the
state — per-mechanism structures (queues+jobs, dead letters,
streams+offsets, locks, schedules) behind the family's locking
discipline (parking_lot short-held internal locks per AGENTS
convention 3; tokio primitives for cross-await coordination).
Layout is module-per-file under `src/`, mirroring the other
engines. Subsequent mechanism tasks own their tables' shapes; this
task owns the shared scaffolding: the guarded-state container idiom,
name validation at entry (same `InvalidName`/`ReservedName` rules as
every other engine — reserved prefix `__alkstore_`, the one
reserved string `__alkstore_listener_reconnected__` unused here but
still rejected), and the wake-routing substrate (in-process channels;
a mechanism registers its commit-ordered wake source, receivers
attach per channel).
- **Wake substrate shape**: no batching boundary exists — wakes
deliver at the commit boundary directly to each open receiver,
per-subscriber FIFO by commit order (engine-mem.md §Architecture;
coalescing not applicable). The routing core lives here; the
`listen()`/`WakeReceiver` surface lives in `mem-engine-notify-listen`.
- **Clock posture**: every timestamp (unix-seconds stamps, visibility
deadlines, TTLs, scheduler boundaries) reads the process clock —
there is no server clock to defer to. Keep the clock behind one
internal accessor so tests can observe timestamps deterministically
the same way the SQL engines' row shapes do.
The `Store` trait impl itself is ADR-007-shaped and lands in
`mem-engine-seam-tx` (the tx overlay is the load-bearing half);
this task lands everything up to the trait boundary.
## Acceptance Criteria
- [ ] `alkstore-mem` is a workspace member compiling clean; manifest
dependency surface is core + tokio (sync + time) only
- [ ] `MemStore::new()` constructs; two instances share nothing
(pinned by a unit test)
- [ ] The guarded state core, validation rules, wake-routing
substrate, and clock accessor exist with unit pins
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean from this task onward (tokio subset discipline enforced
here, not retro-fitted)
- [ ] Workspace gates green (`cargo build`, `cargo test`, clippy
`-D warnings`, fmt)
## References
- docs/architecture/decisions/024-mem-engine.md §1/§4
- docs/architecture/engine-mem.md §Identity and posture, §Architecture
- docs/architecture/core-contract.md §Naming / reserved namespace
- tasks/pg-engine-schema.md (the wave-4 rhythm this wave mirrors — its
"foundations first" slot)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+95
View File
@@ -0,0 +1,95 @@
---
id: mem-engine-integration
name: Mem engine — integration (full-surface wiring, suite third column, wasm32 acceptance)
status: pending
depends_on: [mem-engine-notify-listen, mem-engine-streams, mem-engine-queues, mem-engine-locks, mem-engine-scheduler-outbox, mem-engine-seam-tx, suite-harness-current-thread]
scope: moderate
risk: medium
impact: phase
level: implementation
tags: [wave-6, mem-engine, integration]
---
## Description
The integration task: wire the finished mechanisms into a complete
`Store`, adopt the contract suite as the third column, and carry the
wasm acceptance items through ([ADR-024](../architecture/decisions/024-mem-engine.md)
§5; the born-pinned posture — engine-mem.md §Isolation and the suite
factory):
- **Full-surface wiring**: every handle constructible off one
`MemStore`; trait-object plumbing; crate docs (module docs + a
crate-level doc carrying the honest-ephemeral posture statement —
no durability, single-process, ephemeral by design, never
fleet-valid, per [ADR-024](../architecture/decisions/024-mem-engine.md)
§2 — and the wasm identity line per engine-mem.md §Identity).
- **Suite third column**: a `tests/contract_suite.rs` target
implementing `StoreFactory` (fresh `MemStore::new()` per run,
teardown = drop — the factory's isolation contract verbatim) and
running the shared rows wired per engine: mem's column carries the
mechanism rows that express on it and omits the engine-shaped rows
that cannot (reconnect-wake, watcher-death close, watcher-cadence —
the per-engine wiring the suite's rows already use;
`PayloadTooLarge`'s non-occurrence arm *wires* — the arm is the
pin). The column runs under a **current-thread runtime flavor**
(the pre-task's async-sleep harness makes this clean).
- **wasm32 acceptance**: `cargo check --target wasm32-unknown-unknown
-p alkstore-mem` (and the workspace's other crates untouched)
clean; the manifest's tokio features verified as the sync+time
subset. On-target suite execution stays scoped out (the named
collapse condition — a wasm-bindgen-test adapter crate — recorded in
the task Notes at completion, not an OQ).
- **No `spawn_blocking` anywhere**: grep-verified; internals
current-thread-clean by construction, now proven by the flavor the
column runs under.
- Suite column green is the wave's center-of-mass: 25 rows' worth of
contract v1 assertions against a third, independent implementation —
any red row is either a mem defect or (if the row pins
implementation detail a correct engine could fail) a found suite
defect to raise with the reviewer *before* editing the row (rows pin
ADR text; a wobble is amend-in-place material under the class-1
window).
## Acceptance Criteria
- [ ] `StoreFactory` implemented for the mem engine; the third suite
column wired and **green on the host** (same row set per the
wiring table above)
- [ ] The column runs under the current-thread flavor; no blocking
calls in mem internals (grep-verified)
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean
- [ ] `engine-mem.md` updated from `draft`-initial to
implementation-complete (the spec grows with the wave per its
frontmatter note); crate docs carry the posture + wasm identity
- [ ] Workspace gates green; clippy `-D warnings`; fmt clean
- [ ] The class-1 window discipline respected: any suite-row change
or contract wobble surfaced to the reviewer, not silently
patched
## Dependencies note
`mem-engine-seam-tx` is listed because the overlay's commit-merge and
`*_tx` read shapes are what the suite's tx rows exercise on mem; the
mechanism tasks consume it, but a late seam fix may be needed if the
suite surfaces one — the task owns absorbing it.
## References
- docs/architecture/decisions/024-mem-engine.md §5 (acceptance items);
022-contract-suite-layout.md (the factory both engines already
implement — the shape to mirror)
- docs/architecture/engine-mem.md (spec of record)
- tasks/sqlite-engine-integration.md / tasks/pg-engine-integration.md
(the structural twins' integration tasks of record)
- tasks/review-wave-5.md appendix (the discharge map the third column
rides)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+65
View File
@@ -0,0 +1,65 @@
---
id: mem-engine-locks
name: Mem engine — named locks (in-memory TTL registry)
status: pending
depends_on: [mem-engine-seam-tx]
scope: narrow
risk: low
impact: component
level: implementation
tags: [wave-6, mem-engine, locks]
---
## Description
The named-locks mechanism over an in-memory TTL registry
(engine-mem.md §Mapping the contract, locks row):
- `store.try_lock(name, owner, ttl)` — acquire or fail (`Option<Lock>
`; no-work is a value); validation at entry (empty → `InvalidName`,
reserved → `ReservedName`); **duration guard at entry** —
`ttl <= 0` rejects with opaque `Err`
([ADR-023](../architecture/decisions/023-fourth-review-round.md) §2,
durations kind), never a silent immediately-expired lease.
- **`Lock` handle** ([ADR-019](../architecture/decisions/019-mechanism-handle-surfaces.md)):
`renew(ttl)` (absolute reset; renews past expiry refused) and
`release`. Registry entries carry owner + deadline; expiry is a
clock check at try/renew boundaries (tokio time; no ambient
revoker) — after TTL expiry exclusion lapses *silently* (the
ADR-008 §7 row), re-acquirable; the holder may still release.
- **Single-instance contention semantics**: two `try_lock`s on the
same name within the registry are serialized by the guarded-state
discipline — first wins, second gets `None` cleanly (the SQLite
busy-path question has no mem analog; loser is a value, never an
error). Not part of the tx seam (no `lock_tx` — contract-verbatim:
a lock held across a business tx is held by explicit acquisition;
the overlay neither sees nor stages locks).
## Acceptance Criteria
- [ ] `try_lock`/`renew`/`release` over the TTL registry; entry
validation (names + duration guard) — pinned
- [ ] TTL expiry: silent lapse, re-acquisition, renew-past-expiry
refused — pinned (clock-controlled tests via the state core's
clock accessor)
- [ ] Concurrent-contention shape: loser is `None`, winner's lease
intact — pinned
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean; workspace gates green
## References
- docs/architecture/core-contract.md §named locks
- docs/architecture/decisions/008-contract-v1-pinning.md §7;
019-mechanism-handle-surfaces.md; 023 §2
- docs/architecture/engine-mem.md §Mapping the contract (locks row)
- tasks/pg-engine-locks.md (the structural twin's task of record —
the duration guards land identically)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+73
View File
@@ -0,0 +1,73 @@
---
id: mem-engine-notify-listen
name: Mem engine — notify/listen surface (`WakeReceiver`, close-at-engine-drop)
status: pending
depends_on: [mem-engine-seam-tx]
scope: narrow
risk: medium
impact: component
level: implementation
tags: [wave-6, mem-engine, notify]
---
## Description
The notify/listen mechanism over the state core's wake-routing
substrate (engine-mem.md §Architecture):
- `store.notify(channel, payload)` — validation like every engine
(empty → `InvalidName`, reserved → `ReservedName`); encode via
core's `encode_payload` (`Codec` on failure, ADR-023 §1); delivers
committed-notify wakes to each open receiver on that channel at the
commit boundary, per-subscriber FIFO by commit order, never
coalesced (no batching boundary exists). No size limit at any size —
`PayloadTooLarge` is never produced (engine asymmetry classification,
[ADR-024](../architecture/decisions/024-mem-engine.md) §3).
- `store.listen(channel) -> Box<dyn WakeReceiver>` — starts from
"now" (attaches at the current commit watermark; a listener attached
after a commit never sees it). Delivers opaque
`Wake { channel }` signals — `recv`/`try_recv`/`recv_timeout` forms
per the pinned shapes ([ADR-008](../architecture/decisions/008-contract-v1-pinning.md)
§3).
- `notify_tx` — staged in the tx overlay by `mem-engine-seam-tx`; this
task's contract obligation is the close arms: **one close path —
engine drop closes open receivers** (process exit/shutdown;
terminal `recv() -> None`, cause = the documented engine asymmetry
realized as drop). No reconnection concept exists; the
reconnect-wake channel is never emitted (the reserved string stays
reserved but unused — and still rejected as a consumer name).
Unit tests pin: channel-scoped delivery + foreign-channel silence
(with the field carried, per the suite row's scoping observable),
burst floor (≥1 wake), attach-after-commit no-replay, close-at-drop
terminal `None`, commit-boundary delivery timing through
`notify_tx` (nothing pre-merge).
## Acceptance Criteria
- [ ] listen/notify surface trait-complete with entry validation and
core payload encoding
- [ ] Wake delivery: commit-ordered, channel-scoped, no-replay,
never coalesced — unit-pinned
- [ ] Engine drop closes open receivers (terminal `None`) — pinned
- [ ] `notify_tx` delivers wakes only after the overlay merge —
pinned with the seam task's commit-atomicity tests
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean; workspace gates green
## References
- docs/architecture/core-contract.md §notify / listen
- docs/architecture/decisions/006-wake-and-delivery-contract.md;
008-contract-v1-pinning.md §3; 021-tx-reads-and-value-shape-fixes.md §5
- docs/architecture/engine-mem.md §Architecture, §Asymmetry classification
- tasks/suite-wake-rows.md (the suite row the mem column will run —
the observable shapes it pins)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+86
View File
@@ -0,0 +1,86 @@
---
id: mem-engine-queues
name: Mem engine — queues (in-memory job table, ADR-010 state machine, engine-owned backoff curve)
status: pending
depends_on: [mem-engine-seam-tx, mem-engine-notify-listen]
scope: moderate
risk: medium
impact: component
level: implementation
tags: [wave-6, mem-engine, queues]
---
## Description
The queue mechanism: the
[ADR-010](../architecture/decisions/010-queue-semantics-depth.md) state
machine realized over an in-memory job table — all driver-free.
- **`Queue` handle surface** ([ADR-019](../architecture/decisions/019-mechanism-handle-surfaces.md)
§1): `enqueue` (auto-commit, resolving over the handle's opts),
`claim_one`/`claim_batch` (extents: `n <= 0` claims nothing),
`ack_batch` (per-id uniform predicate, lapsed/non-claimed silently
not counted), `cancel` (unconditional delete), `get_job`, and the
queue-scoped `sweep_expired` (no-stranded-rows: *every* past-expiry
row in any state moves to dead + retention enforcement).
- **Claim discipline**: exactly-once handout, `worker_id` claimant
identity (non-empty), claim ordering priority DESC → ready-time →
enqueue FIFO. Visibility expiry and reclaim — **reclaim consumes an
attempt**; the dual-execution window is contract-honest (a worker
past its deadline may complete its work but its ack will not land).
Under a single engine instance the claim race is in-process — the
guarded merge discipline must still make claim-vs-claim atomic and
claim-vs-expiry deterministic at the row level.
- **JobHandle ops** ([ADR-019](../architecture/decisions/019-mechanism-handle-surfaces.md)
§3): `ack`/`retry`/`fail` one-shot terminal, `heartbeat(&self)`
repeatable absolute-reset renewal; the uniform validity predicate
(processing + unexpired deadline); deadline lapse refuses all ops,
false not error. `retry(err, None)` computes the queue's
**equal-jitter exponential delay — mem's own implementation**
([ADR-012](../architecture/decisions/012-forked-substrate-design.md)
§2's one-owner rule, third owner; the SQLite engine's `resolution.rs`
is reference, not a dependency); `retry(err, Some(d))` overrides
verbatim; `fail` = immediate dead-letter with the engine-default
strings (`"failed"` / `"max attempts exceeded"`).
- **Opts stamping** ([ADR-020](../architecture/decisions/020-enqueue-opt-semantics-and-bridges.md)):
resolution rules (delay-over-`run_at`, relative `expires`) are
mem-owned (third copy); handle-enqueue stamps the handle's opts;
the tx/no-handle shapes stamped plain 300/3/5/none in
`mem-engine-seam-tx`. `get_job` shows resolved values.
- **Dead letters**: move-to-dead storage, `get_job` sees dead rows
(`last_error`/`died_at`), `dead_letter_retention_s` (None = forever)
enforced by `sweep_expired`. No redrive API.
- Timestamps and expiry checks are tokio-time/clock reads against the
state core's clock accessor; expiry is *checked* at claim/renew
boundaries (no ambient sweeper — `sweep_expired` is caller-driven,
cadence recipe unchanged).
## Acceptance Criteria
- [ ] Full `Queue`/`JobHandle` surfaces over the in-memory job table
- [ ] The ADR-010 state machine properties unit-pinned: visibility
reclaim consumes an attempt, dead-letter moves, no-stranded-rows
sweep, handle-op validity predicate, late-heartbeat boundary
- [ ] Equal-jitter curve + opts resolution pinned to the identical
numeric behavior the suite's equivalence rows assert (per the
engine-side pin posture used for the cap legs)
- [ ] Numeric-domain guards (extents) at entry — pinned
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean; workspace gates green
## References
- docs/architecture/queues.md; core-contract.md §queues
- docs/architecture/decisions/010-queue-semantics-depth.md;
019-mechanism-handle-surfaces.md §1/§3; 020 §1–§3; 023 §2
- docs/architecture/engine-mem.md §Mapping the contract (queues row)
- tasks/pg-engine-queues.md (the structural twin's task of record —
the wave-4 rhythm and the resolution rule set)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+87
View File
@@ -0,0 +1,87 @@
---
id: mem-engine-scheduler-outbox
name: Mem engine — scheduler (`schedule`/`unschedule`/`run_schedules`) and outbox helper
status: pending
depends_on: [mem-engine-queues, mem-engine-locks]
scope: moderate
risk: medium
impact: component
level: implementation
tags: [wave-6, mem-engine, scheduler, outbox]
---
## Description
The collapsed scheduler and the outbox helper
([ADR-009](../architecture/decisions/009-scheduler-collapse.md),
[ADR-014](../architecture/decisions/014-outbox-tx-enqueue.md)):
- **Scheduler surface**: `schedule(name, spec, queue, payload, opts)`
(upsert by name; *both* name-bearing arguments validated — schedule
name and queue argument identically, `InvalidName`/`ReservedName`),
`unschedule(name) -> bool`, and the opt-in
`run_schedules(stop: StopToken)` runner over a mem-owned tick task.
- **Tick machinery — engine-uniform** ([ADR-009](../architecture/decisions/009-scheduler-collapse.md)
§4's rule; single-instance leadership is trivially owned but the
machinery still runs): each boundary fire enqueues ordinary work
stamped with the schedule's `ScheduleOpts` resolved over the target
queue's derived engine defaults; fire+advance is atomic under the
guarded state (the no-double-fire floor); **bounded catch-up with
the fixed 64-boundary cap and skip-forward past the cap**
(mem-owned tick implementation — third owner per
[ADR-012](../architecture/decisions/012-forked-substrate-design.md)
§2); leadership rides the reserved `__alkstore_scheduler` lock
through the lock mechanism (so two runners on one instance contend
through the same machinery the other engines use; loss →
`Err(LeadershipLost)`, clean stop → `Ok(())`).
- **Spec grammar v1**: `@every <n><unit>` (`s|m|h|d`) only — mem owns
its parser (third copy, the grammar is small and pinned); cron
strings rejected (`InvalidSpec`). Boundary waits ride tokio time.
- **Outbox helper**: `Outbox { enqueue, run_once }` per
[ADR-019](../architecture/decisions/019-mechanism-handle-surfaces.md)
§5 — `run_once(worker_id, delivery) -> bool` is pull: claim one,
ack on `Ok`, `retry(err, None)` on `Err`; **no engine-issued
heartbeat inside delivery** (inherited posture);
`outbox_enqueue_tx` staged in the overlay by `mem-engine-seam-tx`
(the 60/5/5 stamp set); the derived backing queue
`__alkstore_outbox:{outbox}` unreachable by `enqueue_tx`
(validation already pins the reserved prefix), name format pinned
identical to the other engines (the suite's derived-queue-naming
row composes it).
Unit tests pin: boundary fires (deterministic, tokio-time driven),
bounded catch-up + skip-forward, leadership lock contention/loss
through two `run_schedules` calls, outbox run_once ack/retry shapes,
derived-name format.
## Acceptance Criteria
- [ ] Scheduler surface + tick: boundary fire, catch-up (≤64),
skip-forward — unit-pinned with tokio-time determinism
- [ ] Leadership contention through the `__alkstore_scheduler` lock;
`LeadershipLost` on loss, `Ok(())` on clean stop — pinned
- [ ] Schedule name + queue argument validation; `@every`-only parser
(cron → `InvalidSpec`) — pinned
- [ ] Outbox: `enqueue`/`run_once` semantics (no engine heartbeat);
derived backing-queue name format identical to both engines —
pinned
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean; workspace gates green
## References
- docs/architecture/queues.md; core-contract.md §scheduler, §outbox
- docs/architecture/decisions/009-scheduler-collapse.md §1/§3/§4/§6;
014-outbox-tx-enqueue.md; 019 §4/§5; 020 §3
- docs/architecture/engine-mem.md §Mapping the contract
(scheduler/outbox row)
- tasks/pg-engine-scheduler-outbox.md (the structural twin's task of
record — tick/catch-up/leadership shapes)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+95
View File
@@ -0,0 +1,95 @@
---
id: mem-engine-seam-tx
name: Mem engine — tx overlay, `Store` surface, `TxHandle` (staged `*_tx`, commit-merge + wake-at-commit, drop = discard)
status: pending
depends_on: [mem-engine-foundations]
scope: moderate
risk: high
impact: component
level: implementation
tags: [wave-6, mem-engine, seam]
---
## Description
The seam task, and the wave's load-bearing artifact
(engine-mem.md §The tx overlay): the `Store` trait impl plus the tx
overlay's full discipline.
- **`Store` surface**: the trait methods (`notify`, `stream`,
`queue`, `outbox`, `try_lock`, `listen`, `schedule`, `unschedule`,
`run_schedules`, `begin_tx`, `with_tx`) implemented over the
state core. `queue(name, opts)`/`outbox(name)` create/return
handles whose opts ride the handle (queues are names, not config
owners — the §3a stamp rules apply identically). Mechanism handles
are core-owned trait objects; engine types never appear in
signatures.
- **The tx overlay**: `begin_tx()` allocates a handle-private overlay.
All eleven `*_tx` methods stage effects in it — `enqueue_tx`,
`publish_tx`, `publish_with_key_tx`, `notify_tx`,
`save_offset_tx`, `get_job_tx`, `get_offset_tx`, `read_since_tx`,
`read_from_consumer_tx`, `outbox_enqueue_tx`, `commit`. Reads *inside* the tx merge the overlay over committed state (read-
your-own-writes, no round-trips: the tx-read rows'
`get_job_tx`/`read_since_tx` behaviors come free, but pin them).
Opt-stamping of staged effects runs at *enqueue* time on the
overlay (resolution identical to the no-handle paths, per
[ADR-020](../architecture/decisions/020-enqueue-opt-semantics-and-bridges.md)
§3: `enqueue_tx` stamps plain derived defaults 300/3/5/none;
`outbox_enqueue_tx` the 60/5/5 set).
- **Commit-merge + wake-at-commit**: commit merges the overlay
atomically (single guarded merge) and fires the overlay's pending
wakes *in the same operation* — a tx-staged notify delivers nothing
until the merge (the discipline pg got wrong and fixed via
`pg-fix-tx-wake`; here structural, and pinned from birth by the
suite's tx-commit-atomicity rows once integration wires them).
- **Drop = discard**: dropping the handle without commit/rollback
discards the overlay (rollback explicit form too) — no-ghosts
trivially, uncommitted state never touched committed state.
`with_tx` composition: `Ok` ⇒ commit, `Err`/drop/panic ⇒ rollback
(the N-5 panic posture applies; overlay discard must be panic-safe
through the unwind's drop).
- **Numeric domains** ([ADR-023](../architecture/decisions/023-fourth-review-round.md)
§2): validation at the trait-impl entry, before any storage-layer
effect — extents clamp empty, durations reject, boundaries total.
Same entry-point rule as the other engines, realized engine-side.
Engine-internal unit tests pin the overlay discipline directly
(merge atomicity, wake-after-not-before, drop-discard, panic-through-
unwind) in the family's mechanism-test posture; the suite column's
cross-engine rows land in `mem-engine-integration`.
## Acceptance Criteria
- [ ] The full `Store`/`TxHandle` trait surfaces implemented over
guarded state; no engine types in consumer signatures
- [ ] Overlay staging → commit-merge → wake-at-commit pinned by unit
tests (a tx-staged notify delivers nothing pre-commit, one wake
post-commit; enqueue/publish commit-atomicity shapes)
- [ ] Drop-without-commit and explicit rollback leave zero residue;
`with_tx` panic rolls back through the unwind's drop
- [ ] Tx reads see staged effects; other views see none pre-commit;
post-rollback reads' subjects gone (no-ghosts for reads)
- [ ] Numeric-domain guards at entry (extents/durations/boundaries)
pinned per [ADR-023](../architecture/decisions/023-fourth-review-round.md) §2
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean; workspace gates green
## References
- docs/architecture/core-contract.md §The seam; §Cross-cutting contracts
- docs/architecture/decisions/007-transactional-seam.md;
014-outbox-tx-enqueue.md; 020-enqueue-opt-semantics-and-bridges.md
§3; 021-tx-reads-and-value-shape-fixes.md; 023-fourth-review-round.md §2
- docs/architecture/engine-mem.md §The tx overlay (the spec of record)
- tasks/pg-fix-tx-wake.md (the failure shape the overlay makes
structurally impossible)
- tasks/review-wave-5.md appendix (the suite rows whose mem wiring
consumes this task)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+80
View File
@@ -0,0 +1,80 @@
---
id: mem-engine-streams
name: Mem engine — streams (in-memory log, per-consumer offsets, trim)
status: pending
depends_on: [mem-engine-seam-tx, mem-engine-notify-listen]
scope: moderate
risk: medium
impact: component
level: implementation
tags: [wave-6, mem-engine, streams]
---
## Description
The streams mechanism over an in-memory event log + per-consumer
offset table (engine-mem.md §Mapping the contract, streams row):
- **`StreamHandle` surface** ([ADR-019](../architecture/decisions/019-mechanism-handle-surfaces.md)
§2): `publish` / `publish_with_key` (present key must be non-empty
→ `InvalidName`), `read_since` / `read_from_consumer` (cursor reads,
`offset ASC`, extents clamp empty per
[ADR-023](../architecture/decisions/023-fourth-review-round.md) §2),
`save_offset` / `get_offset` (monotone saves — below-checkpoint
saves are silent no-ops, `Err` arm carries `Database` only),
`trim_to` (delete `offset <= horizon`, exact-boundary, returns
deleted count, negative horizon deletes nothing idempotently,
**wakes nothing**, surviving rows keep offsets, never renumbered),
and `subscribe` (durable consumption: attach, read to tail, resume
from saved offset; wake-driven with re-read — the wake substrate
delivers at commit; explicit saves only, no auto-checkpoint).
- **Ordering**: engine-assigned monotonically increasing per-stream
offsets, global FIFO by offset — the ADR-015 ordering row, mem's own
counter (per-stream; absolute values need not equal the SQL engines'
— the equivalence rows pin relative order).
- **`StreamEvent` shape** exactly as pinned
([ADR-015](../architecture/decisions/015-streams-depth.md) §3):
`{ offset, stream, key, payload, created_at }` — `created_at` is
unix-seconds at publish, informational, from the clock accessor.
Reads from a trimmed-away region resume at the horizon's first
remaining row.
- **Keyed publish rides the tx overlay** (staged `publish_with_key_tx`
landed in `mem-engine-seam-tx`); this task's non-tx forms, receiver,
and trim live here.
- **Receiver close arms** ([ADR-021](../architecture/decisions/021-tx-reads-and-value-shape-fixes.md)
§5): `recv()`'s `Err` carries `Database` only (payloads cross raw;
`Codec` at `payload_as<T>`); close is terminal — the one close path
is engine drop (the notify-listen task's close arm, realized
identically); no reconnection concept (the pg stays-open-across-
reconnect row is absent from mem's column).
## Acceptance Criteria
- [ ] Full `StreamHandle` surface over the in-memory log +
per-consumer offsets
- [ ] The ADR-015 properties unit-pinned: global FIFO, immutable
never-renumbered offsets (gaps legal post-trim), exact-boundary
trim semantics (reads resume at horizon; saved sub-horizon
offsets stay valid; trim wakes nothing), monotone save
composition (direct + receiver forms interleave)
- [ ] Key round-trips exactly (`None` vs `Some`); empty-`Some`-key
rejected at every entry point
- [ ] Extent/offset numeric-domain guards at entry — pinned
- [ ] `cargo check --target wasm32-unknown-unknown -p alkstore-mem`
clean; workspace gates green
## References
- docs/architecture/core-contract.md §streams
- docs/architecture/decisions/015-streams-depth.md;
019-mechanism-handle-surfaces.md §2/§6; 021 §5; 023 §2
- docs/architecture/engine-mem.md §Mapping the contract (streams row)
- tasks/pg-engine-streams.md (the structural twin's task of record)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
id: pg-fix-open-path id: pg-fix-open-path
name: Fix `max_size: 0` open hang + DSN options override (review 002 Finding 3 + options note) name: "Fix `max_size: 0` open hang + DSN options override (review 002 Finding 3 + options note)"
status: completed status: completed
depends_on: [] depends_on: []
scope: single scope: single
+68
View File
@@ -0,0 +1,68 @@
---
id: pg-fix-scheduler-tick-seam
name: "pg scheduler — transient-fault tick seam: retry/exhaustion arms tested (review 003 Finding 1)"
status: pending
depends_on: []
scope: narrow
risk: low
impact: component
level: implementation
tags: [wave-6, postgres-engine, scheduler, test-hardening]
---
## Description
Review 003 Finding 1 (MEDIUM — `docs/reviews/003-wave-5-general-review.md`):
the pg scheduler's transient-error retry loop
(`alkstore-postgres/src/scheduler.rs:680-704`, `tick_with_retries`)
has never executed under any test — `pg-fix-scheduler-resilience`
pinned its *constants* (`the_tick_retry_policy_is_pinned`) but the
loop that uses them (retry, backoff sleeps, exhaustion error, the
`eprintln` diagnostic — lcov 171-184, 237-260) is dead code under
test, with no fault seam anywhere in the pg scheduler for `tick_once`.
This is the last uncovered hardening arm from the wave-4 fix batch,
and the exact class that produced review 002's live bugs.
Fix shape (the review's recommendation): a `cfg(test)` transient-
fault seam on the pg tick path, following the `sqlite-commit-error-arm
` precedent — a one-shot armed flag feeding a fabricated
transient error into the *real* retry loop (never a replica):
- (a) one retried tick then success: the seam faults once, the next
`tick_once` succeeds, the job processes — the retry + backoff-sleep
arms execute for real;
- (b) exhaustion: the seam faults the max retry count, the loop
exhausts to the typed error shape and the `eprintln` diagnostic
fires, the runner survives (the resilience property the fix
promised).
Cross-test safety is per-store scoping (the commit-fault seam's
pattern); no production-path changes — the seam is cfg-gated, born
disarmed, consumed-on-use.
## Acceptance Criteria
- [ ] The seam lands cfg(test)-gated; the real `tick_with_retries`
executes under test (no loop replication)
- [ ] Arms (a) and (b) pinned as above; the runner survives
exhaustion
- [ ] `cargo test -p alkstore-postgres` green against the harness
server; skips clean server-less
- [ ] Clippy `-D warnings`, fmt clean; workspace gates green
## References
- docs/reviews/003-wave-5-general-review.md §Finding 1 (sites, lcov
inventory, recommendation)
- docs/architecture/decisions/024-mem-engine.md (the wave-6 window
this rider rides — the plan's wave-6 section, "Riding the window")
- tasks/sqlite-commit-error-arm.md (the seam pattern of record)
- tasks/pg-fix-scheduler-resilience.md (the constants the loop uses)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+81
View File
@@ -0,0 +1,81 @@
---
id: review-wave-6
name: Review gate — wave 6 (mem engine)
status: pending
depends_on: [mem-engine-integration, pg-fix-scheduler-tick-seam]
scope: moderate
risk: low
impact: phase
level: review
tags: [wave-6, review]
---
## Description
The wave-6 review gate (the plan's §Review gates, wave 6; the
born-pinned gate). Code-read the `alkstore-mem` engine against the
contract and the pinned ADR-024 text, and audit:
1. **Conformance read**: engine-vs-contract line by line, mirroring
the wave-3/4 gate pattern — every trait surface against
core-contract.md and the pinning ADRs (007/008/009/010/015/019/
020/021/023), the tx overlay against ADR-024 + engine-mem.md §The
tx overlay (commit-merge atomicity, wake-at-commit, drop = discard,
panic-through-unwind).
2. **The third column as the compatibility instrument born pinned**:
the mem column's wiring read row-by-row against the discharge map
(which rows carry, which engine-shaped rows omit and why — the
asymmetry classification, ADR-024 §3); `PayloadTooLarge`
non-occurrence arm present; three-way arithmetic equivalence
actually asserted green (backoff curve, opts resolution — the
ADR-012 §2 one-owner rule's third owner), plus the derived-queue
naming row composing identically.
3. **wasm32 acceptance audit** (ADR-024 §5): the compile gate clean,
tokio feature subset verified on the manifest, no blocking calls
in mem internals, the current-thread flavor actually enforced by
the column's tests.
4. **engine-mem.md read against the implemented engine**; the
deployment matrix's mem rows (`deployment.md`, landed with ADR-024)
still true as implemented (honesty carriers: identity + docs +
matrix — nothing runtime invented). Gate may flip `engine-mem.md`
to `stable` if the read is clean.
5. **The rider closed**: `pg-fix-scheduler-tick-seam`'s arms verified
(review 003 Finding 1 discharged into this window; Findings 2–3
confirmed still parked for wave 7).
6. **Contract-window discipline**: the class-1 amend-in-place window
is still open — any wobble the third implementation surfaced must
appear as resolved ADR text (or be recorded as a finding with its
disposition), not as a silent divergence between suite row and
engine behavior.
## Acceptance Criteria
- [ ] Full conformance code-read recorded (findings + dispositions
inline in this task's Notes, mirroring review-wave-3/4 style)
- [ ] Suite mem column green on host, 25-row set wired per the
classification; three-way equivalence rows green
- [ ] wasm32 compile gate + feature-subset + current-thread flavor
verified, recorded
- [ ] The rider's arms verified; Finding 1 disposition recorded
- [ ] Workspace gates re-run green this session (`cargo build`,
`cargo test`, clippy `-D warnings`, fmt)
- [ ] `engine-mem.md` disposition decided (stable flip or follow-up)
and `implementation.md`'s wave-6 row updated
## References
- docs/plans/implementation.md §Wave 6, §Review gates (wave 6 entry)
- docs/architecture/decisions/024-mem-engine.md (the charter this
gate audits code against)
- docs/architecture/engine-mem.md
- tasks/review-wave-3.md / tasks/review-wave-4.md (the gate pattern)
- docs/reviews/003-wave-5-general-review.md (Finding 1's disposition
trail; Findings 2–3's wave-7 park)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion
+62
View File
@@ -0,0 +1,62 @@
---
id: suite-harness-current-thread
name: Contract-suite harness — async sleep in `past_stamp_sleep`, current-thread flavor readiness
status: pending
depends_on: []
scope: narrow
risk: low
impact: component
level: implementation
tags: [wave-6, contract-suite]
---
## Description
The one suite-side change wave 6 carries
([ADR-024](../architecture/decisions/024-mem-engine.md) §5 item 4; the
review-003 posture note at `properties.rs:1683`): the suite's
`past_stamp_sleep` helper uses a blocking `std::thread::sleep` inside
async rows — safe under the multi-thread test flavors both existing
engines' targets use, but it would stall a current-thread runtime. The
mem engine's suite column **must** run under a current-thread flavor
(`#[tokio::test(flavor = "current_thread")]`) to keep the mem
engine's internals honestly current-thread-clean — which is what
wasm32 needs.
- Replace `past_stamp_sleep`'s blocking sleep with `tokio::time::sleep`
(async). The helper's semantics are unchanged (a bounded
pre-`run_at` settle before reads); the existing rows' determinism
posture is untouched — verify the two legs using it re-run green on
both engines with no timing drift (tolerances unchanged).
- Document (one line in the helper's doc comment or the factory
contract notes) the harness posture: **no blocking calls inside
suite rows** — the mem column enforces the flavor that catches
violations.
This task is engine-independent and can run any time before
`mem-engine-integration` wires the third column.
## Acceptance Criteria
- [ ] `past_stamp_sleep` is async (`tokio::time::sleep`)
- [ ] Both engines' existing suites re-run green with identical
assertions and tolerances (determinism posture intact)
- [ ] The no-blocking-calls posture noted where the harness's
determinism posture is documented
- [ ] Clippy `-D warnings`, fmt clean; workspace gates green
## References
- docs/architecture/decisions/024-mem-engine.md §5
- docs/reviews/003-wave-5-general-review.md §Finding 5 (the
`properties.rs:1683` posture note)
- docs/architecture/decisions/022-contract-suite-layout.md (the
factory contract the flavor rides)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion