From 7e8bfde12db48f6150055651c4b05a45aac43e13 Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Sat, 10 Oct 2026 13:17:18 +0000 Subject: [PATCH] =?UTF-8?q?review-wave-6=20=E2=80=94=20the=20wave-6=20gate?= =?UTF-8?q?=20passes,=20engine-mem.md=20flipped=20to=20stable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The born-pinned gate audited the mem engine against the contract and ADR-024: the conformance read clean in mechanism substance (queue state machine, scheduler collapse, outbox, streams, locks, clock, validation, tx overlay, wake substrate — incl. a full guard-order and panic-hygiene audit); the suite's third column read row-by-row and 25/25 green under the per-test current-thread flavor (24 engine-shared rows + mem's payload_too_large non-occurrence arm + the factory-shape test); three-way arithmetic equivalence green on all columns; the wasm32 acceptance items verified (compile-clean, tokio sync+time, no blocking, flavor enforced); the rider's two arms verified (Finding 1 discharged; Findings 2-3 stay parked for wave 7); workspace gates, taskgraph validate green. Three edge-domain fixes landed inline: the stream cursor read's i64::MAX overflow (Bound::Excluded), trim_to's i64::MAX horizon endpoint (Bound::Included), and the scheduler register path now rejecting a parseable interval whose first boundary overflows with InvalidSpec — the one engine-vs-engine divergence the read found, aligned into the class-1 window — plus a pinning test and scaffold- residue doc/comment cleanups (clock allows, tx per-stream wake comment, wakes/stream module docs). Recorded findings with dispositions in the task's Notes for the wave-7 pre-release pass: the multi-thread publish-to-wake ordering tolerance, the heartbeat/ save_offset/EventReceiver-try_recv ADR-023 §2 classification gaps, and the mem arithmetic being a suite-pinned transplant. Verified: cargo build; cargo test --workspace green (mem 101 lib + 25 suite, sqlite 191+25, pg 124+25+9 server-less, core 25, harness 3); clippy --all-targets -D warnings clean; fmt clean; taskgraph validate (61 tasks). Gate record: tasks/review-wave-6.md (Notes + Summary), implementation.md wave-6 row + review-rounds entry. --- alkstore-mem/src/clock.rs | 4 - alkstore-mem/src/scheduler.rs | 31 ++++- alkstore-mem/src/stream.rs | 17 ++- alkstore-mem/src/tx.rs | 6 +- alkstore-mem/src/wakes.rs | 5 +- docs/architecture/engine-mem.md | 14 ++- docs/plans/implementation.md | 42 +++++-- tasks/review-wave-6.md | 200 ++++++++++++++++++++++++++++++-- 8 files changed, 282 insertions(+), 37 deletions(-) diff --git a/alkstore-mem/src/clock.rs b/alkstore-mem/src/clock.rs index a35e1e5..4c8f156 100644 --- a/alkstore-mem/src/clock.rs +++ b/alkstore-mem/src/clock.rs @@ -15,9 +15,6 @@ use std::sync::Mutex; #[cfg(test)] use crate::state::Guard; -// Mechanism task code stamps every timestamp through this accessor — -// scaffolding reads as dead until the wave-6 mechanism tasks wire it. -#[allow(dead_code)] fn process_unix_now() -> i64 { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -47,7 +44,6 @@ impl Clock { } /// Unix-seconds "now" — the one timestamp source of the engine. - #[allow(dead_code)] pub(crate) fn unix_now(&self) -> i64 { #[cfg(test)] let frozen = { *self.frozen.guard() }; diff --git a/alkstore-mem/src/scheduler.rs b/alkstore-mem/src/scheduler.rs index 0a7683e..7c53a65 100644 --- a/alkstore-mem/src/scheduler.rs +++ b/alkstore-mem/src/scheduler.rs @@ -165,7 +165,14 @@ pub(crate) fn schedule( visibility_timeout_s: stamps.visibility_timeout_s, backoff_base_s: stamps.backoff_base_s, dead_letter_retention_s: stamps.dead_letter_retention_s, - next_fire_at: now.saturating_add(interval), + // A parseable interval whose first boundary overflows the + // clock registers nothing: the SQLite register path + // (substrate/queue_ops.rs) rejects the same spec with + // InvalidSpec — one register-time semantics, engines + // aligned (the tick's i64::MAX sentinel stays identical). + next_fire_at: now + .checked_add(interval) + .ok_or_else(|| invalid_spec(&spec))?, }; { let mut sched = state.schedules.guard(); @@ -453,6 +460,28 @@ mod tests { assert_eq!(row.expires_s, Some(120)); } + #[tokio::test(flavor = "current_thread")] + async fn register_rejects_a_parseable_interval_whose_first_boundary_overflows() { + let store = store(); + // Parseable (n · 1s fits i64) but now + interval overflows the + // clock — the register path rejects with InvalidSpec, no row + // stored (aligned with the SQLite register semantics; distinct + // from the unparsable-too-large spec the parser refuses). + let err = store + .schedule( + "overflow", + "@every 9223372036854775807s", + "q", + serde_json::json!(1), + ScheduleOpts::default(), + ) + .await + .unwrap_err(); + assert!(matches!(err, Error::InvalidSpec { .. }), "{err:?}"); + let sched = store.state.schedules.guard(); + assert!(sched.rows.is_empty(), "nothing registered"); + } + #[tokio::test(flavor = "current_thread")] async fn register_rejects_bad_names_and_specs_pre_storage() { let store = store(); diff --git a/alkstore-mem/src/stream.rs b/alkstore-mem/src/stream.rs index 9b65a52..00396a3 100644 --- a/alkstore-mem/src/stream.rs +++ b/alkstore-mem/src/stream.rs @@ -3,9 +3,11 @@ //! FIFO by monotone offset; keyed publish rides the overlay). //! //! - Publishes append to the per-stream log under its section guard: -//! engine-assigned offsets (the engine-wide allocator — pg-bigserial -//! shaped, monotone, immutable, never renumbered; a fresh stream's -//! first event does not carry offset 1, the ADR-015 §4 note), keys +//! engine-assigned offsets (the engine-wide allocator — monotone, +//! immutable, never renumbered; the concrete numbering is engine- +//! internal and never compared cross-engine — ADR-015 §4: mem's +//! fresh-engine count starts at 1, the SQL engines' counters may +//! not), keys //! are carried metadata (a present key must be non-empty — //! `InvalidName`, ADR-015 §1), and the commit boundary fires one //! wake per event on the stream's engine-internal wake channel. @@ -30,6 +32,7 @@ //! (ADR-021 §5). use std::collections::VecDeque; +use std::ops::Bound; use std::sync::Arc; use serde_json::Value; @@ -72,7 +75,7 @@ pub(crate) fn read_events(s: &StreamState, stream: &str, from: i64, limit: i64) s.logs .get(stream) .map(|log| { - log.range((from + 1)..) + log.range((Bound::Excluded(from), Bound::Unbounded)) .take(limit.max(0) as usize) .map(|(_, row)| row.clone()) .collect() @@ -107,8 +110,10 @@ pub(crate) fn trim_events(s: &mut StreamState, stream: &str, horizon: i64) -> i6 let Some(log) = s.logs.get_mut(stream) else { return 0; }; - let horizon_next = horizon.saturating_add(1); - let removed: Vec = log.range(..horizon_next).map(|(k, _)| *k).collect(); + let removed: Vec = log + .range((Bound::Unbounded, Bound::Included(horizon))) + .map(|(k, _)| *k) + .collect(); let count = removed.len(); for offset in removed { log.remove(&offset); diff --git a/alkstore-mem/src/tx.rs b/alkstore-mem/src/tx.rs index 0862056..09eaa60 100644 --- a/alkstore-mem/src/tx.rs +++ b/alkstore-mem/src/tx.rs @@ -443,8 +443,10 @@ fn merge_and_wake(state: Arc, wakes: Arc, mut overlay: Overlay) } } // Wake-at-commit: staged notifies in stage order (duplicates ride — - // per-notify), plus one wake per staged event on its stream's - // engine-internal feed (per event — never coalesced). + // per-notify), plus one wake per staged stream on its engine-internal + // feed (receivers drain by cursor, so one wake per stream is enough — + // the feed is plumbing, not contract surface; never coalesced across + // commits). let mut fired: VecDeque = VecDeque::with_capacity(overlay.notifies.len()); fired.extend(overlay.notifies.iter().cloned()); for stream in overlay.events.keys() { diff --git a/alkstore-mem/src/wakes.rs b/alkstore-mem/src/wakes.rs index c1ea47c..edf03d3 100644 --- a/alkstore-mem/src/wakes.rs +++ b/alkstore-mem/src/wakes.rs @@ -6,8 +6,9 @@ //! commit order; coalescing is not applicable. The substrate realizes //! the shape structurally: //! -//! - **Commit-ordered source**: a mechanism (notify now — streams and -//! queue wakes arrive with their tasks) fires its commit's wakes +//! - **Commit-ordered source**: a mechanism (notify, stream publishes, +//! the tx commit-merge's staged notifies and publishes) fires its +//! commit's wakes //! through [`WakeBus::fire_commit_wakes`], under one guard: the //! commit sequence bumps and the per-channel fanout completes as a //! single operation, so every subscriber's receipt order is exactly diff --git a/docs/architecture/engine-mem.md b/docs/architecture/engine-mem.md index 29bbeeb..89860be 100644 --- a/docs/architecture/engine-mem.md +++ b/docs/architecture/engine-mem.md @@ -1,9 +1,13 @@ --- -status: implementation-complete -last_updated: 2026-10-10 (the wave-6 wave landed: the full surface -wired over guarded state, the suite's third `StoreFactory` column -green on the host under the current-thread flavor, the wasm32 -compile gate clean — the review gate holds the stable flip) +status: stable +last_updated: 2026-10-10 (the wave-6 review gate passed: the +conformance read clean — three edge-domain fixes landed inline (the +stream cursor read's `i64::MAX` overflow, `trim_to`'s horizon +endpoint, the scheduler register-time interval overflow now rejecting +with `InvalidSpec` like the SQLite register) plus scaffold-residue +cleanup; the third column's 25-row set green under the current-thread +flavor; the wasm32 gate + feature subset verified; the rider's arms +verified) --- # Mem engine diff --git a/docs/plans/implementation.md b/docs/plans/implementation.md index 2c0e335..cff92ed 100644 --- a/docs/plans/implementation.md +++ b/docs/plans/implementation.md @@ -1,11 +1,10 @@ --- status: draft -last_updated: 2026-10-10 (ADR-024 — the mem engine adopted as wave 6, -release readiness renumbered to wave 7; wave 6 decomposed — eleven -tasks per the pg-wave rhythm with the tx overlay load-bearing. Waves -1–5 implemented and reviewed; engine specs stable. Wave-5 review -residue decomposed — pg-fix-scheduler-fire-wake; flake-watch carried -to wave 7.) +last_updated: 2026-10-10 (wave 6 implemented and reviewed — the mem +engine landed, the suite's third column green under the current-thread +flavor, the wasm32 gate clean, the wave-6 gate passed with three +inline edge-domain fixes; Findings 2–3 and the flake watch carry to +wave 7.) --- # alkstore — Implementation plan @@ -44,7 +43,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) | | 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) | -| 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) | +| 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 | implemented + reviewed (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 | ## Wave 1 — Foundations @@ -496,7 +495,34 @@ decomposes. Specific gates: 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. -- **Wave 6 decomposition** (2026-10-10) — ADR-024 adopted the mem +- **Wave 6 review gate** (`review-wave-6`, 2026-10-10) — the + born-pinned gate passed: the conformance read clean (queue state + machine, scheduler collapse, outbox, streams, locks, clock, + validation, tx overlay, wake substrate each verified against the + contract and the pinned ADRs; guard-order discipline audited across + every section-guard site); the suite's third column read row-by-row + and green (the 24 engine-shared rows + mem's + `payload_too_large_never_produced_on_mem` arm + the factory-shape + test, 25 green under the per-test current-thread flavor); + three-way arithmetic equivalence green (backoff curve, opts + resolution on all three columns); the wasm32 acceptance items + verified (compile-clean, tokio sync+time subset, no blocking calls, + flavor enforced); the rider's arms verified (Finding 1 discharged; + Findings 2–3 confirmed still parked for wave 7). Three edge-domain + fixes landed inline at the gate: the stream cursor read's `i64::MAX` + overflow (`Bound::Excluded`), `trim_to`'s `i64::MAX` horizon + endpoint (`Bound::Included`), and the scheduler register path + aligning with SQLite on rejecting a parseable interval whose first + boundary overflows (`InvalidSpec`). Unpinned contract-adjacent + observations recorded in the task's Notes for the wave-7 pre-release + pass: the multi-thread publish-to-wake ordering tolerance (same + shape implied for the SQL engines; nothing pins wake-fire order vs + offset order), the `heartbeat(extend)`/`save_offset`/ + `EventReceiver::try_recv`-closed classifications missing from the + ADR-023 §2 table, and the mem arithmetic being a transplant of the + SQLite implementations (equivalence suite-pinned; ownership letter + satisfied). `engine-mem.md` flipped to `stable`. +- **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 diff --git a/tasks/review-wave-6.md b/tasks/review-wave-6.md index 9e43e67..0743dbd 100644 --- a/tasks/review-wave-6.md +++ b/tasks/review-wave-6.md @@ -1,7 +1,7 @@ --- id: review-wave-6 name: Review gate — wave 6 (mem engine) -status: pending +status: completed depends_on: [mem-engine-integration, pg-fix-scheduler-tick-seam] scope: moderate risk: low @@ -50,16 +50,16 @@ contract and the pinned ADR-024 text, and audit: ## Acceptance Criteria -- [ ] Full conformance code-read recorded (findings + dispositions +- [x] 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 +- [x] 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 +- [x] 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`, +- [x] The rider's arms verified; Finding 1 disposition recorded +- [x] 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) +- [x] `engine-mem.md` disposition decided (stable flip or follow-up) and `implementation.md`'s wave-6 row updated ## References @@ -74,8 +74,190 @@ contract and the pinned ADR-024 text, and audit: ## Notes -> To be filled by implementation agent +Gate verdict: **passed**. No blocker, no major live defect; three +edge-domain fixes landed inline (below); the remaining observations +are recorded with dispositions, none mem-divergent from the engines. + +### Fixed inline at the gate (this session, verified clippy/fmt/test green after each) + +1. **Stream cursor read overflow** (`stream.rs` `read_events`): the + cursor advanced by plain `from + 1`, panicking on debug build for a + caller-supplied `offset == i64::MAX` (direct `read_since`, or + indirect via `save_offset(i64::MAX)` + `read_from_consumer`) and + wrapping to a from-the-beginning read in release. Fixed with + `Bound::Excluded(from)` — boundary-total at every i64, the + ADR-023 §2 read-cursor classification this fix encodes. +2. **`trim_to` horizon endpoint**: `horizon.saturating_add(1)` clipped + `i64::MAX` and left a row at offset `i64::MAX` undeleted — the + exact-`<=` boundary broke at the one unreachable endpoint anyway. + Fixed with `Bound::Included(horizon)`; unreachable in practice + (2⁶³ publishes), fixed because the template cost nothing. +3. **Scheduler register overflow alignment** (conformance divergence + found by the read): mem registered a *parseable* interval whose + first boundary overflows (`@every 9223372036854775807s`) with a + saturating `next_fire_at` — accepted-never-fires — where the SQLite + register path rejects the same spec with `InvalidSpec`. + Class-1-window divergence between engines on a register-time + semantics; aligned mem to reject (`checked_add` → `InvalidSpec`, no + row stored) with a new pin test distinguishing it from the + unparsable-too-large spec the parser already refuses. The tick's + `i64::MAX` overflow sentinel stays identical in both engines. +4. **Scaffold-residue cleanup**: `clock.rs`'s stale + `#![allow(dead_code)]` on the now-wired accessor + scaffolding + comment removed; `tx.rs`'s commit-wake comment corrected to what + the code does (one wake per staged *stream* — receivers drain by + cursor, the feed is plumbing); `wakes.rs` module doc's "mechanisms + arrive with their tasks" updated to the wired mechanisms; + `stream.rs` module doc no longer claims "a fresh stream's first + event does not carry offset 1" for mem (mem's fresh count *is* 1; + the ADR-015 §4 note is engine-internal and never compared + cross-engine — the doc now says exactly that). + +### Recorded findings, no code change (dispositions) + +- **Multi-thread publish→wake ordering tolerance** (streams): the + publish path allocates the offset, then inserts under the guard, + then fires the wake after the guard drops — on a multi-thread + runtime two concurrent publishes can complete insert+wake out of + offset-allocation order, and a subscriber's cursor can skip an + event whose wake fires later (the event is never lost from the log, + but a pre-insert drain's checkpoint passes it). The SQL engines + share the shape in principle (offset assigned pre-commit, wake + post-commit — the "pg-shaped story" the mem docs cite), and nothing + contract-side pins wake-fire order vs offset order. Disposition: + this is a contract-level tolerance nobody pinned, not a mem-local + divergence — recorded for the wave-7 pre-release pass to either + document as tolerated or amend as ADR text (wake order per stream = + offset order). Mem's declared posture is current-thread-clean + (engine-mem.md) and the suite's mem column proves it under the + current-thread flavor, which is why nothing here fails today. +- **Mem arithmetic is a transplant, not an independent derivation** + (one-owner-rule note): `resolution.rs`'s backoff curve and opts + resolution, `scheduler.rs`'s `@every` parser and `skip_forward`, are + byte-level copies of the SQLite-side implementations (semantics + re-verified against the ADR text during this read). ADR-012 §2's + letter — each engine owns its implementation, equivalence + suite-pinned — is satisfied (mem owns its modules; the + `backoff_curve_equivalence` and `enqueue_opts_resolution` rows run + green on all three columns). Recorded so the gate's record doesn't + overstate the independent-signal value of the third copy; the suite + *is* the honesty instrument. +- **`heartbeat(extend)` unclassified** (ADR-023 §2): the domain table + classifies `try_lock`/`renew` durations but not the queue + heartbeat's seconds-shaped `extend` argument. Both engines treat it + boundary-total (`saturating_add`/SQL integer add — a negative + shortens/voids the claim). Recorded as a class-1-window doc + annotation candidate for wave 7's pre-release pass; no engine + diverges. +- **`save_offset`'s argument unclassified**: negatives accepted (stored, + reads resume forward), monotone no-op below the checkpoint — both + engines, contract pins monotonicity only (ADR-019 §6). Same + annotation candidate. +- **`EventReceiver::try_recv`'s closed shape unpinned**: + `Err(Closed)` (mirrors `WakeReceiver::try_recv`, ADR-008 §3); + taxonomy-consistent, mem-test-pinned, but ADR-021 §5 pins only + `recv()`'s arms. Same annotation candidate. +- **`get_job` is id-global, not queue-filtered** — uniform on all + three engines (the handle carries the queue, the lookup the id; + `get_job_tx` *is* queue-filtered on both engines with tx). Recorded + so the record doesn't misread core-contract's "queue-scoped" handle + phrasing as a filter; the ambiguity is contract-prose, not code. +- **Mem outbox `run_once` ignores a trailing ack/retry refusal** + (deadline lapsed mid-delivery): identical to SQLite; the uniform + validity predicate makes the refusal the at-least-once honesty — + conformant, noted for the boolean's silent discard. +- **Wake-bus attach-vs-close race (defense-in-depth note)**: + `WakeBus::attach`/`fire_commit_wakes` check `closed` before taking + the registry guard, so a listen racing the engine's drop could in + principle mint a feed whose sender post-dates the registry clear. + Unreachable through safe APIs (a live `&MemStore` borrow pins the + last reference — borrowck; the bus is reachable only through the + store), so no change; recorded as a hardening candidate if the bus + ever gains a second entry path. + +### Audit record (verified items) + +- **Conformance read**: queue state machine (claim predicate/ordering, + visibility, reclaim-eats-attempt, uniform validity predicate, + heartbeat, retry/fail/cancel/ack_batch, dead-letter + no-stranded + sweep, queue-scoped get_job incl. dead rows); scheduler (grammar + parser, register-time stamp resolution, one-guard fire-and-advance + tick in the schedules→queues order, 64-cap catch-up + grid-aligned + skip-forward, leadership acquire/renew/loss/clean-stop on the + reserved lock with runner-unique owner); outbox (derived reserved + backing queue unreachable by every consumer entry point, 60/5/5 + stamps, run_once ack/retry curve, tx half stamping identically); + streams (offset-ASC reads, absent-consumer 0 head read, monotone + saves, trim exact-`<=` never-renumbering and waking nothing, + attach-before-read subscribe, engine-drop close arms); locks + (contention loser `Ok(None)`, `ttl <= 0` refused on try + renew, + silent lapse, non-owner release = false, renew-past-expiry refused, + no `lock_tx`); clock (one accessor, all stamps read it, freeze + seam cfg(test) only); validation (every entry routed through core's + `validate_shared_name`/`validate_local_name`, no engine-local + rules); tx overlay (eleven `*_tx` staged with entry validation + before effect, one clock read, ADR-020 §3 stamps incl. per-job + override, merged reads queue-scoped + dead-visible + offset-ASC + + extent-clamped, one-op commit merge + wake-at-commit, drop = + discard through unwind, stage-time id/offset allocation with legal + gaps); wake substrate (channel-scoped, per-notify never coalesced, + attach-after-commit no-replay, close disconnects all, dropped-feed + detach, commit-ordered FIFO). Guard discipline audited: canonical + order (schedules → queues → streams) holds at every two-guard site; + no guard across an `.await` or user code; zero panics/unwrap/ + expect in library code. +- **Third column as compatibility instrument**: the mem target wires + exactly the 24 engine-shared rows + mem's + `payload_too_large_never_produced_on_mem` (stamped ADR-016 §5 + + ADR-024 §3) + the factory-shape test; the reconnection-shaped rows + stay per-engine wired (absent here, per ADR-024 §3's + classification); the three-way equivalence (`backoff_curve_equivalence`, + `enqueue_opts_resolution`) green on all three columns; 25/25 green + on the host. +- **wasm32 acceptance**: `cargo check --target wasm32-unknown-unknown + -p alkstore-mem` clean; manifest tokio subset sync+time (dev-deps + rt/macros only); no `spawn_blocking`/blocking-call in mem source; + current-thread flavor enforced on every mem-column test (a blocking + call would hang, not pass); on-target suite execution stays scoped + out behind the named adapter-crate collapse condition (ADR-024 §5 — + recorded, not an OQ). +- **Spec + matrix**: `engine-mem.md` read against the implemented + engine (tx overlay, asymmetry classification, isolation, wasm + identity — all true as landed; the stable flip records the gate in + its frontmatter); `deployment.md`'s mem rows read true as + implemented. +- **Rider closed**: `pg-fix-scheduler-tick-seam`'s two arms + (`one_faulted_tick_is_retried_and_the_job_fires`, + `tick_retry_exhaustion_exits_typed_and_leaves_the_lock_to_lapse`) + verified present against the real retry loop; review 003 Finding 1 + discharged; Findings 2–3 confirmed still parked for wave 7 + (implementation.md §Wave 7); the fire-wake gap + (`pg-fix-scheduler-fire-wake`) closed pre-wave and its retired gap + records verified; the wave-5 flake ledger's §6 update recorded. +- **Workspace gates re-run green this session**: `cargo build`; + `cargo test --workspace` green (core 25, suite harness 3, mem 101 + lib + 25 suite, SQLite 191 + 25, pg 124 + 25 + 9, pg column + server-less per the SKIP posture — the pg-side verification was the + rider tasks' own live runs); clippy `--all-targets -D warnings` + clean; `cargo fmt --check` clean; `taskgraph validate` green + (61 tasks). ## Summary -> To be filled on completion \ No newline at end of file +The wave-6 review gate passed and flipped `engine-mem.md` to +`stable`. The conformance read was clean in mechanism substance; the +findings class was edge-domain and hygiene: three inline fixes (the +stream cursor's `i64::MAX` overflow, `trim_to`'s horizon endpoint, +and the scheduler register-overflow alignment with SQLite's +`InvalidSpec` — the one true engine-vs-engine divergence the read +found, resolved into the class-1 window) and the expected residue +cleanups. The suite's third column is born pinned as ADR-024 +required — 25 green under the current-thread flavor, the three-way +arithmetic equivalence actually asserted — and the wasm32 acceptance +items verified. The unpinned contract-adjacent observations (the +multi-thread wake-ordering tolerance, three ADR-023 §2 table +classifications, the receiver try_recv closed shape) are recorded +above with their dispositions for the wave-7 pre-release pass; none +blocks. The rider (`pg-fix-scheduler-tick-seam`) closed Finding 1. +Task files audited: all eleven dependency tasks completed with +Notes/Summary filled. \ No newline at end of file