diff --git a/alkstore-contract-suite/src/properties.rs b/alkstore-contract-suite/src/properties.rs index 076664b..8bea08f 100644 --- a/alkstore-contract-suite/src/properties.rs +++ b/alkstore-contract-suite/src/properties.rs @@ -1324,7 +1324,10 @@ pub async fn backoff_curve_equivalence(factory: &dyn StoreFactory) { /// Contract stamp: ADR-021 §5 (receiver error/close arms — /// `Database`-only `Err`, terminal `None` close, SQLite closes on /// watcher death); ADR-019 §6 (save composition — monotone, forms -/// interleave); ADR-008 §8 (explicit saves only). +/// interleave); ADR-008 §8 (explicit saves only); ADR-023 §2 +/// (annotated 2026-10-11 — the boundary/offset row's totality covers +/// `save_offset`: a negative seed is stored as the checkpoint, this +/// row's negative-leg pins). pub async fn receiver_close_and_save_arms(factory: &dyn StoreFactory) { let store = factory.open().await.expect("factory opens a store"); @@ -1416,6 +1419,38 @@ pub async fn receiver_close_and_save_arms(factory: &dyn StoreFactory) { "the receiver form never regresses the direct form's save" ); + // Boundary-total save (ADR-023 §2, annotated 2026-10-11): a + // negative offset is stored as the checkpoint — the argument is + // total, no clamping, no rejection — and reads anchored there + // resume forward identically (every event offset lies above the + // negative anchor, so the anchored read yields the log from the + // start). Fresh consumer, so this leg also pins the *seed* case — + // the only arm where a clamping realization would diverge. + stream.save_offset("c2", -5).await.unwrap(); + assert_eq!( + store + .stream("events") + .await + .unwrap() + .get_offset("c2") + .await + .unwrap(), + -5, + "a negative seed is stored as the checkpoint (totality, no clamp)" + ); + let resumed = store + .stream("events") + .await + .unwrap() + .read_from_consumer("c2", 10) + .await + .unwrap(); + assert_eq!( + resumed.iter().map(|e| e.offset).collect::>(), + vec![o1, o2], + "reads anchored at the negative checkpoint resume forward: the log from the start" + ); + // Terminal close on disposal (this engine's documented close // cause: the watcher's death guard clears the feed — ADR-021 §5's // SQLite arm; the store handle dropping is the disposal). @@ -1770,7 +1805,10 @@ async fn past_stamp_sleep(millis: u64) { /// (delete-on-ack; `ack_batch`'s per-id predicate, partial success /// ordinary); ADR-010 §4 (the engine-default strings); ADR-019 §3 /// (the claim handle's op surface — one-shot consumables, repeatable -/// heartbeat); ADR-008 §5 (refusals are `false`, never errors). +/// heartbeat); ADR-008 §5 (refusals are `false`, never errors); +/// ADR-023 §2 (annotated 2026-10-11 — the boundary/offset row's +/// totality covers `heartbeat(extend)`: a negative extension is the +/// relative-instant void this row's negative-extend leg pins). pub async fn job_handle_validity_predicate(factory: &dyn StoreFactory) { let store = factory.open().await.expect("factory opens a store"); @@ -1818,6 +1856,50 @@ pub async fn job_handle_validity_predicate(factory: &dyn StoreFactory) { "delete-on-ack completed work leaves no row" ); + // Boundary-total heartbeat (ADR-023 §2, annotated 2026-10-11): a + // negative extension is a relative instant — the renewed deadline + // `now + extend` sits in the past, voiding the claim through the + // validity predicate on the *next* op, never an error. The + // heartbeat itself reports the successful renewal (`true`) while + // the row was processing and unexpired at call time; the voided + // claim then refuses all handle ops (ack here) and the row + // survives as processing. Six-hundred-second margin: fully past, + // deterministic without a sleep. Own queue: the voided row is + // expired-processing (re-claimable), and this row's later legs + // assert claim FIFO on their queues. + let voidq = store + .queue("voided", alkstore::QueueOpts::default()) + .await + .unwrap(); + let voided_id = voidq + .enqueue(json!({"leg": "negative-extend"}), EnqueueOpts::default()) + .await + .unwrap(); + let voided = voidq + .claim_one("w1") + .await + .unwrap() + .expect("the ready row claims"); + assert_eq!(voided.job().id, voided_id); + assert!( + voided.heartbeat(-600).await.unwrap(), + "a negative extension lands while the claim is unexpired (totality)" + ); + assert!( + !voided.ack().await.unwrap(), + "the negative extension voided the claim: ack refuses through the validity predicate" + ); + assert_eq!( + voidq + .get_job(voided_id) + .await + .unwrap() + .expect("the voided row was not deleted or dead-lettered") + .state, + JobState::Processing, + "the voided claim's row survives as processing (re-claimable by the queue)" + ); + // Lapse legs: one claim per refusal op, all stamped with the 1 s // visibility, one tolerance sleep past every deadline at once. let ack_refused = fast diff --git a/alkstore-postgres/src/schema.rs b/alkstore-postgres/src/schema.rs index 6e52d6b..39ed2ad 100644 --- a/alkstore-postgres/src/schema.rs +++ b/alkstore-postgres/src/schema.rs @@ -298,12 +298,13 @@ CREATE INDEX IF NOT EXISTS {events_read_idx} ON {events} (stream, id); -- Offsets table: (stream, consumer) → offset, the monotone -- checkpoint upsert target (the streams task's SQL owns the --- monotonicity rule, GREATEST-guarded upsert, one owner). The --- non-negative CHECK bounds the domain (cursors start at 0). +-- monotonicity rule, WHERE-guarded upsert, one owner). The boundary +-- argument is total (ADR-023 §2): no domain CHECK — a negative seed +-- is stored raw, reads anchor at it and resume forward identically. CREATE TABLE IF NOT EXISTS {offsets} ( stream TEXT NOT NULL, consumer TEXT NOT NULL, - \"offset\" BIGINT NOT NULL DEFAULT 0 CHECK (\"offset\" >= 0), + \"offset\" BIGINT NOT NULL DEFAULT 0, PRIMARY KEY (stream, consumer) ); diff --git a/alkstore-postgres/src/stream.rs b/alkstore-postgres/src/stream.rs index 50700df..7bdda25 100644 --- a/alkstore-postgres/src/stream.rs +++ b/alkstore-postgres/src/stream.rs @@ -28,9 +28,13 @@ //! stored checkpoint (absent consumer = 0, ADR-019 §1). //! - `save_offset` / `get_offset` — the monotone upsert (a save below //! the stored checkpoint is a silent no-op — one owner of the -//! monotonicity rule, the `GREATEST`-clamped + `WHERE`-guarded -//! upsert `save_offset_tx` also rides) and the checkpoint read. -//! Both save forms' `Err` arm carries `Database` only (ADR-021 §5). +//! monotonicity rule, the `WHERE`-guarded upsert `save_offset_tx` +//! also rides) and the checkpoint read. The boundary argument is +//! total per ADR-023 §2's 2026-10-11 annotation: any `i64` is +//! well-defined, a negative seed is stored raw as the checkpoint +//! (no clamping — the offsets column's `DEFAULT 0` is not a domain +//! bound; reads anchored there resume forward identically), and +//! both save forms' `Err` arm carries `Database` only (ADR-021 §5). //! - `trim_to(horizon)` — `DELETE … WHERE id <= horizon` on a pool //! connection (wakes nothing — ADR-015 §5's posture; the boundary //! argument is total per ADR-023 §2: a negative horizon deletes @@ -371,13 +375,14 @@ async fn stream_get_offset(pool: &Pool, schema: &str, stream: &str, consumer: &s } /// The monotone checkpoint save (one owner of the monotonicity rule — -/// the same GREATEST-clamped, WHERE-guarded upsert `save_offset_tx` -/// rides; a save at-or-below the stored checkpoint updates nothing, -/// ADR-019 §6). First save seeds the checkpoint, clamped at 0 (the -/// offsets table's non-negative domain CHECK would abort a negative -/// seed; the clamp preserves both the domain and the monotone rule — -/// a negative save at-or-below the stored checkpoint is the same -/// silent no-op a 0-save is). +/// the same `WHERE`-guarded upsert `save_offset_tx` rides; a save +/// at-or-below the stored checkpoint updates nothing, ADR-019 §6). +/// The boundary argument is total per ADR-023 §2's 2026-10-11 +/// annotation: any `i64` is well-defined — a negative first save +/// seeds the checkpoint raw (the monotone guard `EXCLUDED > o` +/// treats every pre-existing row as the below-checkpoint no-op arm; +/// reads anchored at a negative checkpoint resume forward +/// identically). async fn stream_save_offset( pool: &Pool, schema: &str, @@ -390,7 +395,7 @@ async fn stream_save_offset( conn.execute( &format!( "INSERT INTO {offsets} AS o (stream, consumer, \"offset\") - VALUES ($1, $2, GREATEST($3::bigint, 0)) + VALUES ($1, $2, $3::bigint) ON CONFLICT (stream, consumer) DO UPDATE SET \"offset\" = EXCLUDED.\"offset\" WHERE EXCLUDED.\"offset\" > o.\"offset\"" diff --git a/docs/architecture/README.md b/docs/architecture/README.md index e45db88..f9a8d84 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -1,8 +1,9 @@ --- -status: draft -last_updated: "2026-10-10 (ADR-024: the mem engine adopted as a third -engine — engine-mem.md added, ADR table row, index updated for the -implementation phase)" +status: stable +last_updated: "2026-10-11 (the wave-8 review gate passed — pre-release +freeze: the release-facing spec set flipped stable, Current State +refreshed through wave 8; the class-1 window's dispositions complete, +the window terminates at first publish)" --- # alkstore — Architecture @@ -14,29 +15,38 @@ engine native underneath (see [overview.md](overview.md)). ## Current State -**Phase 1 (Implementation) — waves 1–5 implemented and reviewed.** +**Phase 1 (Implementation) — waves 1–8 implemented and reviewed; the +pre-release gate passed (2026-10-11).** Phase 0 is complete (`docs/research/phase-0.md`): both POCs ran and passed, the scope inventory is confirmed, and the crate split, drivers, and ownership postures are decided. All open questions are resolved (through ADR-023), and the engine specs flipped `stable` at -the wave-5 review gate. Waves 1–5 (core, substrate fork, SQLite -engine, Postgres engine, contract suite) are implemented and reviewed -per `docs/plans/implementation.md`. The mem engine was adopted as a -third engine by [ADR-024](decisions/024-mem-engine.md) (2026-10-10, -wave 6 — release readiness renumbered to wave 7). +the wave-5 review gate, the mem spec at wave 6. Waves 1–7 (core, +substrate fork, SQLite engine, Postgres engine, contract suite, mem +engine, fuzzing) are implemented and reviewed; wave 8 (release +readiness: crate docs, the deployment matrix's final pass, the +README, publish prep — with N-1's growth-posture acceptance, review +003 Findings 2–3, the flake investigation, and the class-1 window's +last dispositions riding it) passed its review gate on 2026-10-11. +ADR-024 adopted the mem engine as a third engine (2026-10-10, +[ADR-024](decisions/024-mem-engine.md)). The class-1 amend-in-place +window ([ADR-017](decisions/017-contract-versioning.md) §2) +dispositions are complete; the window terminates permanently at the +first `cargo publish` of `alkstore` — the gate's blessing covers +publishing. ## Architecture Documents | Doc | Status | Purpose | Key OQs | |---|---|---|---| -| [overview.md](overview.md) | draft | Crate family, feature surface, non-goals, evidence base | — | -| [core-contract.md](core-contract.md) | draft | The unified trait surface, delivery guarantees, tx seam | OQ-10 (resolved) | +| [overview.md](overview.md) | stable | Crate family, feature surface, non-goals, evidence base | — | +| [core-contract.md](core-contract.md) | stable | The unified trait surface, delivery guarantees, tx seam | OQ-10 (resolved) | | [engine-sqlite.md](engine-sqlite.md) | stable | SQLite engine: forked-substrate/rusqlite mapping | OQ-06 (resolved), OQ-12 (resolved), OQ-13 (resolved) | | [engine-postgres.md](engine-postgres.md) | stable | Postgres engine: tokio-postgres/LISTEN mapping | OQ-08 (resolved), OQ-12 (resolved), OQ-13 (resolved) | -| [engine-mem.md](engine-mem.md) | draft | Mem engine: in-process ephemeral mapping of the contract ([ADR-024](decisions/024-mem-engine.md)) | — | -| [queues.md](queues.md) | draft | Queue/scheduler/outbox semantics depth (resolved: ADR-009/ADR-010) | OQ-05 (resolved), OQ-09 (resolved), OQ-06 (resolved) | -| [deployment.md](deployment.md) | draft | Host semantics, connection budgets, knobs, matrix | OQ-08 (resolved) | -| [open-questions.md](open-questions.md) | draft | OQ tracker (promoted from OQ-ST register) | — | +| [engine-mem.md](engine-mem.md) | stable | Mem engine: in-process ephemeral mapping of the contract ([ADR-024](decisions/024-mem-engine.md)) | — | +| [queues.md](queues.md) | stable | Queue/scheduler/outbox semantics depth (resolved: ADR-009/ADR-010) | OQ-05 (resolved), OQ-09 (resolved), OQ-06 (resolved) | +| [deployment.md](deployment.md) | stable | Host semantics, connection budgets, knobs, matrix | OQ-08 (resolved) | +| [open-questions.md](open-questions.md) | draft | OQ tracker (promoted from OQ-ST register) — the register's own lifecycle; the question set is closed | — | ## Architecture Decision Records diff --git a/docs/architecture/core-contract.md b/docs/architecture/core-contract.md index 9417fbf..c0f30cf 100644 --- a/docs/architecture/core-contract.md +++ b/docs/architecture/core-contract.md @@ -1,6 +1,11 @@ --- -status: draft -last_updated: "2026-10-11 (the pre-release class-1 close-out pass — the publish→wake ordering tolerance recorded; ADR-023 §2's `heartbeat(extend)`/`save_offset` classifications; `EventReceiver::try_recv`'s closed shape; `get_job`'s id-global prose)" +status: stable +last_updated: "2026-10-11 (the pre-release class-1 close-out pass — the +publish→wake ordering tolerance recorded; ADR-023 §2's +`heartbeat(extend)`/`save_offset` classifications; +`EventReceiver::try_recv`'s closed shape; `get_job`'s id-global prose — +then wave-8 gate: flipped stable with the close-out pass's suite legs +landed; the contract text freezes at the gate, ADR-017 §2)" --- # Core contract @@ -792,8 +797,10 @@ before the engine specs are called `stable`: totality over non-positive values covers `heartbeat(extend)`'s relative-deadline argument and `save_offset`'s offset — both classified 2026-10-11 by the close-out pass, the ADR-023 §2 - annotation; their suite rows are the follow-up that - classification implies). + annotation; their suite legs landed at the wave-8 gate in + `job_handle_validity_predicate` and + `receiver_close_and_save_arms`, uniformly green on all three + engines). - **`encode_payload` typed failure** ([ADR-023](decisions/023-fourth-review-round.md) §1) — the helper returns `Result, Error::Codec>`; enqueue/publish store and diff --git a/docs/architecture/decisions/017-contract-versioning.md b/docs/architecture/decisions/017-contract-versioning.md index dd538e4..bec215b 100644 --- a/docs/architecture/decisions/017-contract-versioning.md +++ b/docs/architecture/decisions/017-contract-versioning.md @@ -128,7 +128,16 @@ duty — that is what makes them non-events). extensions*, fall in this class in fact — nothing was released when they were made, so their additions ship inside the initial contract v1 text (the initial release carries ADR-008 through - ADR-017 whole). + ADR-017 whole). *(Termination of record, 2026-10-11 — the wave-8 + review gate: the pre-release class-1 close-out pass landed every + recorded disposition (the publish→wake ordering tolerance; the + ADR-023 §2 `heartbeat(extend)`/`save_offset` classifications; the + `EventReceiver::try_recv` closed shape; the `get_job` prose; the + mem-arithmetic no-action) and the gate audited that **no + undisposed class-1 candidate remains**. The class terminates + permanently at the core crate's first `cargo publish` — the 0.1.0 + release this gate blesses, per §1's amendment; from that publish + on, contract changes are classes 2–4 only.)* 2. **Additive extension** (the ADR-009/010 *shape*, applied post-release) — a new trait method, a new type, a new error variant, a new field on a consumer-read value type (§3's diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index da6769e..ac1b0e5 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -1,7 +1,8 @@ --- -status: draft -last_updated: "2026-10-10 (ADR-024 — the mem engine joins the crate -family as `alkstore-mem`; family/ADR tables updated)" +status: stable +last_updated: "2026-10-11 (wave-8 gate: flipped stable — the family +picture frozen with the shipped thing; no further surface under +development)" --- # alkstore — Overview diff --git a/docs/architecture/queues.md b/docs/architecture/queues.md index 021efd6..c05de67 100644 --- a/docs/architecture/queues.md +++ b/docs/architecture/queues.md @@ -1,6 +1,9 @@ --- -status: draft -last_updated: "2026-10-11 (close-out pass: the reads sentence now says the uniform shapes — get_job id-global on the handle, get_job_tx queue-filtered)" +status: stable +last_updated: "2026-10-11 (the reads sentence now says the uniform +shapes — get_job id-global on the handle, get_job_tx queue-filtered; +wave-8 gate: flipped stable, the release-facing semantic depth frozen +with the contract)" --- # Queues, scheduler, outbox — semantics depth diff --git a/docs/plans/implementation.md b/docs/plans/implementation.md index c3f2bfa..67e1899 100644 --- a/docs/plans/implementation.md +++ b/docs/plans/implementation.md @@ -1,10 +1,9 @@ --- status: draft -last_updated: "2026-10-10 (wave 8 decomposed — the release-readiness -task set: seven independent entry tasks incl. the frontmatter cleanup -and the renumber sweep, then matrix → README → publish prep → gate. -Waves 1–7 implemented + reviewed; Findings 2–3, the fired flake-watch -trigger, and the class-1 window's last dispositions ride wave 8.)" +last_updated: "2026-10-11 (wave 8 implemented + reviewed — the release +gate passed: the class-1 window's dispositions complete, the suite's +registered boundary-legs follow-up landed, all gates re-run green; +implementation complete pending the user's manual `cargo publish`.)" --- # alkstore — Implementation plan @@ -50,7 +49,7 @@ readiness is wave 8. | 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 | implemented + reviewed (2026-10-10) | | [7](#wave-7--fuzzing) | [Fuzzing](#wave-7--fuzzing): the `fuzz/` sidecar workspace (cargo-fuzz targets over the payload codec, the three `@every` parsers, name validation), committed seed corpora + the corpus-replay gate, detached campaigns | wave 6 | implemented + reviewed (2026-10-10) | -| [8](#wave-8--release-readiness) | [Release readiness](#wave-8--release-readiness): crate docs, deployment matrix final pass, README (written last, honestly), publish prep | wave 7 | decomposed (2026-10-10) | +| [8](#wave-8--release-readiness) | [Release readiness](#wave-8--release-readiness): crate docs, deployment matrix final pass, README (written last, honestly), publish prep | wave 7 | implemented + reviewed (2026-10-11) | ## Wave 1 — Foundations @@ -757,4 +756,34 @@ decomposes. Specific gates: recommendation: **wave 5 decomposes after the two HIGH fixes land** (the suite's wake-driven rows would otherwise inherit a hang-shaped false failure); 3–7 may trail into wave 5's window if the - fix-batch gate judges them wake-independent. \ No newline at end of file + fix-batch gate judges them wake-independent.- **Wave-8 review gate** (`review-wave-8`, 2026-10-11) — the + pre-release gate passed: the docs honesty audit clean (README trace + list spot-read true, the deployment matrix's rows read true as + implemented, crate-doc posture claims consistent with the matrix, + the env-boundary grep re-run current); the contract-window closure + audited — all five wave-6 dispositions verified landed with dated + citations, **the class-1 termination of record landed in ADR-017 + §2** (the window closes permanently at the first `cargo publish` of + `alkstore`; no undisposed class-1 candidate remains); the + close-out's registered suite-duty follow-up audited and **landed at + the gate** — one divergence found: pg's negative-seed clamp + (`GREATEST(offset, 0)` + the offsets-table `CHECK`) contradicted + ADR-023 §2's "a negative is stored as the checkpoint" annotation on + `get_offset`, fixed engine-side (raw seed, no CHECK), with the + negative-`heartbeat(extend)` and negative-`save_offset` suite legs + landed in `job_handle_validity_predicate` / + `receiver_close_and_save_arms` (stamped, uniform, green on all + three columns); N-1's conscious acceptance and Findings 2–3's + landed/parked dispositions audited as decisions of record; the + flake outcome audited (lock row root-caused harness-model, + test-side fixed, watch retired; the trim row and the new + stream-ordering observation stay watch-flagged — no live engine + bug, not blocking); publish-prep evidence re-verified this gate + session (fresh package listing + exclusion re-run, no leakage); the + frontmatter sweep + renumber spot-checks re-run green; all gates + re-run green including the fuzz replay, wasm32, and the doc gate; + the release-facing spec set (core-contract.md, overview.md, + queues.md, deployment.md, the architecture README) flipped + `stable`. Implementation complete pending the user's manual + `cargo publish` (the checklist of record is in + `tasks/release-publish-prep.md`). diff --git a/tasks/release-contract-window-close.md b/tasks/release-contract-window-close.md index 2e17aec..5875db7 100644 --- a/tasks/release-contract-window-close.md +++ b/tasks/release-contract-window-close.md @@ -62,16 +62,16 @@ accumulation. ## Acceptance Criteria -- [ ] Item 1 decided with the user (documented-tolerance vs ADR +- [x] Item 1 decided with the user (documented-tolerance vs ADR amendment), landed in the chosen home, decision recorded -- [ ] ADR-023 §2 table carries the `heartbeat(extend)` and +- [x] ADR-023 §2 table carries the `heartbeat(extend)` and `save_offset` classifications (or the task records why a different home was chosen) -- [ ] `EventReceiver::try_recv`'s closed shape pinned in contract text -- [ ] core-contract.md's `get_job` prose matches the uniform +- [x] `EventReceiver::try_recv`'s closed shape pinned in contract text +- [x] core-contract.md's `get_job` prose matches the uniform id-global/`get_job_tx`-filtered behavior -- [ ] The mem-arithmetic observation's disposition recorded -- [ ] Every landed amendment dated + cited; affected suite stamps +- [x] The mem-arithmetic observation's disposition recorded +- [x] Every landed amendment dated + cited; affected suite stamps checked for accumulation; `taskgraph validate` + workspace gates green (docs-only changes expected — code changes only if the user opts to amend wake-ordering into an enforced guarantee, diff --git a/tasks/release-readme.md b/tasks/release-readme.md index 240634c..5f750d1 100644 --- a/tasks/release-readme.md +++ b/tasks/release-readme.md @@ -49,15 +49,15 @@ are the wave's other doc-shaped tasks for exactly that reason. ## Acceptance Criteria -- [ ] Root `README.md` exists: family table, per-engine honest +- [x] Root `README.md` exists: family table, per-engine honest postures, compile-checked usage sketch, suite pointer, license note; no aspirational/unshipped claims -- [ ] `LICENSE-MIT` + `LICENSE-APACHE` at the root (MIT + Apache-2.0 +- [x] `LICENSE-MIT` + `LICENSE-APACHE` at the root (MIT + Apache-2.0 canonical texts); ADR-018's in-tree substrate notice untouched -- [ ] `CHANGELOG.md` seeded with the 0.1.0 entry -- [ ] The per-crate readme wiring decided + landed -- [ ] Every README claim traceable to a spec (the trace list in Notes) -- [ ] Workspace gates green (docs-only expected) +- [x] `CHANGELOG.md` seeded with the 0.1.0 entry +- [x] The per-crate readme wiring decided + landed +- [x] Every README claim traceable to a spec (the trace list in Notes) +- [x] Workspace gates green (docs-only expected) ## References diff --git a/tasks/review-wave-8.md b/tasks/review-wave-8.md index 0ec0702..c40caf5 100644 --- a/tasks/review-wave-8.md +++ b/tasks/review-wave-8.md @@ -1,7 +1,7 @@ --- id: review-wave-8 name: Review gate — wave 8 (release readiness) -status: pending +status: completed depends_on: [docs-frontmatter-cleanup, release-renumber-sweep, release-crate-docs, release-contract-window-close, release-n1-growth-posture, release-findings-2-3-disposition, release-flake-investigation, release-deployment-matrix, release-readme, release-publish-prep] scope: broad risk: low @@ -59,19 +59,19 @@ pre-release gate). Audit the release-readiness pass as landed: ## Acceptance Criteria -- [ ] Docs honesty audit recorded (README traces, matrix rows, crate +- [x] Docs honesty audit recorded (README traces, matrix rows, crate docs, env boundary) -- [ ] Contract-window closure audited; the class-1 termination record +- [x] Contract-window closure audited; the class-1 termination record landed; no undisposed class-1 candidate remains -- [ ] N-1 + Findings 2–3 dispositions audited as decisions of record -- [ ] Flake-watch outcome audited; any follow-up task's blocking +- [x] N-1 + Findings 2–3 dispositions audited as decisions of record +- [x] Flake-watch outcome audited; any follow-up task's blocking status stated explicitly -- [ ] Publish-prep audit recorded (package evidence + exclusion +- [x] Publish-prep audit recorded (package evidence + exclusion re-run + checklist complete) -- [ ] Frontmatter parse sweep + renumber-sweep spot-check green -- [ ] All gates re-run green this session (incl. fuzz replay + wasm + +- [x] Frontmatter parse sweep + renumber-sweep spot-check green +- [x] All gates re-run green this session (incl. fuzz replay + wasm + doc gates) -- [ ] Spec flips + records landed; `implementation.md` updated; task +- [x] Spec flips + records landed; `implementation.md` updated; task files audited ## References @@ -87,8 +87,268 @@ pre-release gate). Audit the release-readiness pass as landed: ## Notes -> To be filled by implementation agent +Gate verdict: **passed**. One finding found and fixed at the gate (a +pg engine divergence from the close-out pass's ADR-023 §2 +annotation); no blocker, no major live defect. Every audit item was +re-verified by this session's own runs/reads, not by trusting the +implementing tasks' self-reports. + +### 1. Docs honesty audit — recorded + +- **README**: the trace list (`release-readme` §Notes) spot-read — + the seven-mechanism list against core-contract.md §Mechanism + contracts, the engine posture lines against deployment.md §Host + semantics + §TLS posture, mem's wasm/ephemeral lines against + ADR-024 §2/§5, the license note against the workspace `license` + field + ADR-018. Every claim has a spec source; the usage sketch + was compile-checked and executed from a scratch crate with path + deps (the mem round-trip mirrors the lib-doc doctest `cargo test` + re-verifies — green in this session's run). No aspirational or + unshipped claims found. +- **Deployment matrix**: rows read true as implemented across the + three engines (the full text of + `release-deployment-matrix`'s five corrections — the consumer-side + FULL claim false-as-implemented, the three-guard list, the NFS + re-citation, the unsourced mem latency number replaced — present + in the final text; the env-boundary §Configuration boundary + sentence present; no internal task/wave pointers remain in the + release-facing text — re-read this session). Spot-checks against + code: `synchronous = NORMAL` at bootstrap, `poll_interval` 1 ms + default, `NoTls` on every pg path, `max_size` 0 rejected — all + match the text. +- **Crate docs**: the four published crates' lib-doc posture claims + read against deployment.md/the engine specs — the sqlite + single-host/one-host-cross-process, pg's `max_size + 1` budget + + NoTls v1, mem's honest-ephemeral/wasm identity all consistent with + the matrix. Doc gate green (`RUSTDOCFLAGS="-D warnings" cargo doc + --no-deps`, zero warnings this session). +- **Env boundary**: the grep re-run this session — 40 `env::var` + reads, all inside the pg test modules' DSN plumbing; production + paths env-free. The matrix's "grep re-verified across the + workspace at release" sentence is current. + +### 2. Contract-window closure audit — recorded + +- All five wave-6 recorded observations verified disposed with dated + in-place citations: the publish→wake ordering tolerance + (core-contract.md streams tolerance paragraph + the + delivery-guarantee obligations bullet + ADR-015 §4's companion + annotation; the user declined the enforced-guarantee amendment — + the documented-tolerance posture was the user's call, recorded in + the task's Notes); the ADR-023 §2 `heartbeat(extend)`/`save_offset` + classifications (boundary/offset row annotated, core-contract + numeric-domain paragraph mirrored); the `EventReceiver::try_recv` + closed shape (ADR-021 §5 dated annotation); the `get_job` prose + (core-contract + queues.md now say the uniform id-global / + tx-filtered split); the mem-arithmetic no-action disposition (task + Notes, explicit). +- **The registered suite-duty follow-up — audited, and landed at the + gate** (the close-out pass deferred it to "the review-wave-8 gate + owns the audit"): no suite leg pinned the two new classifications. + In the audit read of pg's implementation, a real divergence + surfaced: **pg's negative-seed clamp contradicted the ADR-023 §2 + annotation** — pg's offsets-table `CHECK ("offset" >= 0)` + the + `GREATEST($3, 0)` upsert clamped a fresh consumer's negative + `save_offset` to 0, where SQLite and mem store the raw negative + and the annotation pins "a negative is stored as the checkpoint" + (`get_offset` observable: −5 vs 0, the only read that + distinguishes; below-checkpoint saves, monotone no-ops, and + reads-resume-forward were uniform). Per AGENTS.md's ADR-wins + discipline, **the pg code was fixed**: raw seed, CHECK dropped, + doc comments updated (the window is open until first publish — + legal; no published consumer exists). Suite legs then landed: + the negative-`heartbeat(extend)` leg in + `job_handle_validity_predicate` (heartbeat lands `true` while + unexpired; the voided claim refuses ack through the validity + predicate; the row survives as processing) and the + negative-`save_offset` seed leg in `receiver_close_and_save_arms` + (fresh-consumer seed stored raw; `read_from_consumer` resumes + forward from the anchor) — both stamped with the ADR-023 §2 + (annotated 2026-10-11) accumulation per `version_stamp.rs` + convention; green on all three columns against the live pg server + (and core-contract.md's numeric-domain backlog row updated to + name the landed legs). The close-out task's "code read verified + the uniform shapes" claim was right on acceptance/monotonicity + and wrong on the stored seed value through pg's clamp — corrected + here. +- **The class-1 termination record landed**: ADR-017 §2's class-1 + bullet now carries the dated termination-of-record annotation + (2026-10-11, the wave-8 gate): the close-out pass landed every + recorded disposition, the gate audited no undisposed class-1 + candidate remains (grep across docs/tasks for parked window + candidates — none; the surviving "class-1 window open/open at + time of writing" phrases are historical ADR texts), and the + class terminates permanently at the core crate's first + `cargo publish` — the 0.1.0 release this gate blesses (§1's + 2026-10-11 amendment; contract changes thereafter are classes + 2–4 only). + +### 3. N-1 + Findings 2–3 dispositions — audited as decisions of record + +- **N-1**: the conscious acceptance is a decision of record with a + per-engine, per-path rationale table (`deployment.md` §Growth + postures), made against the implemented engines' code (the task's + re-read verified each path: sweep-on-call-only retention, the + at-attach-only prune, consumer-invoked `trim_to`; mem's + process-lifetime-bounded postures recorded structurally). The + notify prune-cadence note landed in engine-sqlite.md + §Notifications-table hygiene, anchored and linked from the + matrix. Not a shrug; recorded and folded. +- **Findings 2–3**: 2(a) and 3 landed as seam tests (the pg + generation-top LISTEN-pause arm with the exactly-one-wake + differentiator, replay-proofed both ways; the SQLite + rollback-fault two-drop-arm test via the `rollback_fault` seam), + and 2(b) + the defensive arms' parked dispositions are recorded + with current line refs, reach reasons, and the tested-elsewhere + coverage each overlaps — the inventory reads closed, not + re-derivable. Gates green per the task's record; both engines' + suites green this session. + +### 4. Flake-watch outcome — audited + +- The fired lock-row trigger was investigated per the ledger's + prescription (instrumentation first — the tee-before-filter + capture procedure demonstrated on a deliberately-failing probe; + the conditions matrix run, 48+ rounds; the second-precision + arithmetic read against `lock.rs`/`resolution.rs` with the + delay-only argument confirmed for the lapse legs and corrected + for the contention leg; mechanism probes + natural repro captured, + 2/30 loaded solo runs, exact message at the exact site). + Disposition: **reproduced; root cause harness-model** — the row's + contention leg wrote `ttl = 1` into a live-TTL assertion + second-precision stamps collapse below a second; the engine acted + per ADR-008 §7 at every step. Fixed test-side in-session (the + two-leg row: long-TTL exclusion leg, short-TTL lapse leg); + 30/30 loaded verification green; the three columns green. + **No live engine bug — nothing blocks the release blessing.** +- Post-investigation watch posture: the lock row's flag **retires**; + the trim row stays watch-flagged (no repro in this session's + rounds) and one new single-occurrence observation + (`row_stream_ordering_equivalence` under 8-CPU-burner synthetic + load — a drain-window scheduling lottery, message captured, + no ordering violation) is recorded in the ledger dated + 2026-10-11. Their stated status: watch continues, no ride-along + fix, instrumentation first; neither reproduces under dev/gate + conditions. Recorded; not blocking. + +### 5. Publish-prep audit — recorded + +- **Package evidence, fresh this session**: `cargo package -p + alkstore` — packaged 30 files + verification build green; the + `.crate` inspection shows LICENSE-MIT/LICENSE-APACHE at the + tarball root, README, normalized manifest, no stray paths. The + engines' registry-side verification remains correctly blocked + pre-core-publish (re-captured this session with `--allow-dirty`: + `no matching package named 'alkstore' found … searched: crates.io + index`); their evidence stands on the reconstructed exact-list + trees of record (all green, the publish-shaped manifests). +- **Exclusion verification re-run this session**: fresh + `cargo package --list` for all four crates — alkstore 30 files, + sqlite 36, postgres 31, mem 23; zero `fuzz/`/sidecar/corpora paths + or `alkstore-fuzz-shared` references in any list; the engine + packages' `src/fuzz_surface_tests.rs` + `tests/contract_suite.rs` + riders are the documented crate-internal probe tests and dev-dep + suite target, not sidecar leakage; the suite appears in no + `[dependencies]`; the workspace `exclude = ["fuzz"]` holds. +- **Substrate packaging**: `src/substrate/PROVENANCE.md` + + `src/substrate/LICENSE` confirmed in the alkstore-sqlite list; + the crate README documents the carriers. +- **Path-dep bounds + metadata**: `alkstore = { version = "0.1", + path = … }` verified on all three engines + the suite dep; + descriptions/readmes wired per crate; keywords/categories landed; + homepage/documentation omitted per family precedent; ADR-017 §1's + 0.1.0 amendment dated + cited. **The manual publish checklist of + record is complete** (`release-publish-prep` §Notes — core first, + then engines, gates → package → eyeball → publish, tag v0.1.0); + publishing is the user's post-gate action. The one mechanical + note: run the checklist from the committed, clean tree (cargo + package refuses dirty trees). + +### 6. Frontmatter + records hygiene — re-run green + +- The PyYAML parse sweep re-run exactly as recorded + (`docs-frontmatter-cleanup`'s command, both globs): **0 failures** + across `docs/**/*.md` + `tasks/*.md`. +- The renumber sweep spot-check: re-grepped `wave 7|wave-7` across + `docs/reviews/` + `tasks/` — every non-fuzz hit carries its + wave-8 annotation (001 header, 002 security bullet, 003 echo + + trail, review-wave-5's three sites, review-wave-6's three, + review-wave-4's gate record, pg-fix-scheduler-fire-wake's ledger + note); genuine fuzz-wave/review-7 references intact; + `taskgraph validate` green (79 tasks). + +### 7. All gates re-run green this session + +- `cargo build` — clean. +- `cargo test --workspace` — all green server-less (core 25 + 1 + lib-test target, suite harness 3, mem 102 lib + 25 suite + 1 + doctest, sqlite 193 + 25, pg 127 lib (SKIP posture) + 25 + 9). +- Live pg column against the harness server (`pglo-poc`): **127 + + 25 + 9, all green** (this session, post-fix — the run that verified + the pg seed-divergence fix and the new suite legs). +- `cargo clippy --all-targets -- -D warnings` — clean. +- `cargo fmt --check` — clean. +- Fuzz corpus replay (`cargo test --manifest-path + fuzz/shared/Cargo.toml`) — 6/6 green. +- `cargo check --target wasm32-unknown-unknown -p alkstore-mem` — + clean. +- Doc gate (`RUSTDOCFLAGS="-D warnings" cargo doc --no-deps`) — zero + warnings. + +### 8. Spec flips + records — landed this gate + +- Flipped `stable` with dated gate annotations: **core-contract.md, + overview.md, queues.md, deployment.md** (already `stable` from the + matrix pass — annotation current), **the architecture README**. + The engine specs' engine-mem.md row in the README's doc table + corrected (it still read `draft`; the wave-6 gate flipped the + spec). `open-questions.md` stays `draft` deliberately — it is the + OQ *tracker*, whose lifecycle is separate from the spec set + (noted in the README table's row); the doc set this gate freezes + is the release-facing spec set. +- `docs/architecture/README.md`: Current State refreshed (waves 1–8, + the pre-release gate passed, the window's termination stated). +- `implementation.md`: wave-8 row → implemented + reviewed + (2026-10-11); frontmatter annotation updated; the review-rounds + entry appended. +- Task files audited: all ten wave-8 dependencies `completed` with + Notes/Summary filled; two of their AC checklists + (`release-contract-window-close`, `release-readme`) were left + unticked despite the work + records being complete — ticked at + this gate; no placeholder residue remains in the wave-8 task set. + +### Findings summary + +| # | Severity | Finding | Disposition | +|---|---|---|---| +| 1 | LOW (contract-observable) | pg's negative-seed clamp (`GREATEST(offset, 0)` + the offsets CHECK) diverged from ADR-023 §2's 2026-10-11 "a negative is stored as the checkpoint" annotation on `get_offset` | Fixed engine-side at the gate (raw seed, CHECK dropped; window open until first publish); suite legs landed uniformly (three columns green); backlog row updated | +| 2 | INFO | The close-out pass's "uniform shapes" verification missed the clamp (acceptance was verified; the stored seed value was not) | Corrected by the fix above; recorded here for the record's honesty | +| 3 | INFO | The 2026-10-11 `row_stream_ordering_equivalence` load observation (from `release-flake-investigation` §F6) | Watch-flagged in the ledger, carries post-release; no ride-along fix, instrumentation first; single occurrence under synthetic load beyond dev/gate conditions — not blocking | ## Summary -> To be filled on completion \ No newline at end of file +Gate passed 2026-10-11. The pre-release pass audited clean on every +axis and one contract-observable divergence surfaced and was fixed: +pg's negative-seed clamp contradicted the ADR-023 §2 close-out +annotation, resolved engine-side (raw seed, no CHECK), with the +registered suite-duty follow-up discharged — the +negative-`heartbeat(extend)` and negative-`save_offset` legs landed, +stamped, and green on all three columns (pg verified against the +live harness server). The class-1 termination of record landed in +ADR-017 §2: every recorded disposition is dated + cited, no +undisposed candidate remains, and the window terminates permanently +at the core crate's first `cargo publish` — the 0.1.0 this gate +blesses. N-1's acceptance and Findings 2–3's dispositions are +decisions of record; the flake investigation's outcome is a +harness-model root cause, test-side fixed, watch retired, with the +remaining watch items recorded and non-blocking. Publish prep +verified fresh (package evidence, exclusion re-run clean, the +manual checklist of record standing); the frontmatter and renumber +hygiene sweeps re-ran green; all gates re-run green this session +(build, workspace tests, live-pg suite, clippy, fmt, fuzz replay, +wasm32, doc gate). The release-facing spec set — core-contract.md, +overview.md, queues.md, deployment.md, the architecture README — is +flipped `stable`; `engine-mem.md`'s README-table row corrected to +match its wave-6 flip; `implementation.md`'s records updated; +`open-questions.md` stays the draft tracker by intent. Implementation +is complete; the release itself is the user's manual publish session. \ No newline at end of file