Files
alkstore/tasks/suite-stream-rows.md
T
glm-5.3-flash 1d05df200e Contract-suite stream rows (task suite-stream-rows): two version-stamped rows discharging ADR-015's backlog legs — stream_ordering_equivalence (a keyed/unkeyed interleaved publish sequence of 6 reads back in the same order on every read form: whole + cursor-paginated + mid-stream read_since, read_from_consumer fresh and from a mid checkpoint, and a subscriber's attach drain; offsets strictly increasing per stream — per-stream relative order, absolute values explicitly not cross-pinned (pg bigserial vs SQLite AUTOINCREMENT); key round-trips exactly None/Some on every read form including the explicit-None keyed publish form; stream carries the name; created_at tolerance-bounded informational, never an ordering assertion; ADR-015 §4/§3/§1, byte-exactness and tx-seam legs cross-referenced to the payload-round-trip and keyed-tx-atomicity rows) and trim_to_semantics (the full ADR-015 §5 row: exact-boundary trim — the horizon's own row deletes, horizon+1 survives, repeated trim 0; survivors keep offsets; reads from a trimmed-away region resume at the horizon's first remaining row; a below-horizon saved checkpoint stays a get_offset-visible position marker with read_from_consumer and a fresh subscribe both resuming at the horizon, never a renumbered past; a pre-trim subscriber's above-horizon checkpoint keeps its place; a pre-attached listener idles across the trim in a 400 ms bounded window — no dedicated wake, SQLite's spurious watcher hint contract-legal and delivering nothing; ADR-015 §5/ADR-019 §6, negative-horizon/immutability legs cross-referenced to extent_clamp_semantics). Wired into both engines' suite targets (SQLite tokio tests, pg harness_row!s). Dispositions in Notes: the attach-drain pattern leads with a blocking recv() before the try_recv drain (engines deliver the attach read asynchronously); the pg LISTEN channel is mechanism-named and database-wide so concurrent suite rows' wakes cross schemas — safe by construction (wakes re-drain own-schema storage only, delivering nothing), no "events" rename needed. Verified: sqlite suite 21/21, pg suite 21/21 vs harness (postgres/poc@:15432, 7 consecutive full runs), 5 focused --test-threads=6 runs of the two rows per engine, workspace build/test green, clippy -D warnings, fmt clean
2026-10-10 06:33:27 +00:00

7.6 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
suite-stream-rows Contract-suite rows — cross-engine stream ordering equivalence + trim_to semantics completed
moderate low phase implementation
wave-5
contract-suite
streams

Description

Add the streams contract rows to alkstore-contract-suite/src/properties.rs and wire them into both engines' suite targets, discharging two backlog rows (core-contract.md §Verification backlog): "Cross-engine stream equivalence" (ADR-015 §3/§4) and "trim_to semantics on both engines" (ADR-015 §5 — the legs the existing extent_clamp_semantics row does not carry).

Rows to add:

  • stream_ordering_equivalence — the ordering guarantee row: a publish sequence with keyed/unkeyed interleavings yields offset ASC global FIFO per stream — same publish order → same read order on read_since, read_from_consumer, and a subscriber's attach drain alike; offsets are strictly increasing per stream (per-stream relative order — absolute offset values are explicitly not cross-pinned: pg bigserial vs SQLite AUTOINCREMENT); key round-trips exactly (None stays None, Some stays Some, on every read form); stream carries the stream name and created_at is unix-seconds-at-publish (informational — tolerance-bounded proximity to now, never an ordering assertion). The single-event key/payload round-trip already pins in payload_round_trip_stores_exact_encoding — this row owns the sequence/ordering property.
  • trim_to_semantics — the full ADR-015 §5 row: exact-boundary trim (offset <= horizon — the horizon's own row deletes, horizon+1 survives), surviving rows keep their offsets (gaps legal, never renumbered — the negative-horizon/immutability legs already pin in extent_clamp_semantics; this row owns the exact-boundary and resume legs), a read from a trimmed-away region resumes at the trim horizon's first remaining row, a saved offset below the horizon stays a valid position marker (get_offset returns it; read_from_consumer resumes at the horizon), trim emits no dedicated wake and no notify (a pre-attached listener idles across the trim — tolerance-bounded absence), and a subscriber with a saved checkpoint never loses its place across a trim (its next read continues from the horizon, not from a renumbered past).

Acceptance Criteria

  • Two rows exist, version-stamped (ADR-015 §3/§4/§5, ADR-019 §6 as applicable)
  • Rows wired into both engines' contract_suite.rs targets
  • SQLite column green server-less; pg column green against the harness server
  • No duplication with the existing rows' legs (cross-reference in each row's doc comment which row owns which leg)
  • cargo test -p alkstore-sqlite -p alkstore-postgres green (pg rows skip cleanly server-less); clippy -D warnings; fmt clean

References

  • docs/architecture/core-contract.md §Verification backlog (cross-engine stream equivalence; trim_to semantics)
  • docs/architecture/decisions/015-streams-depth.md §3/§4/§5
  • docs/architecture/decisions/019-mechanism-handle-surfaces.md §6
  • alkstore-contract-suite/src/properties.rs (the existing rows whose legs this task complements)

Notes

Decisions of record the implementation made that the description didn't pin:

  • Sequence shape — the ordering row publishes 6 events (unkeyed, keyed Some("a"), keyed None explicitly, unkeyed, keyed Some("a"), unkeyed) into one stream and pins the same order across four read forms: whole read_since, cursor-paginated read_since (limit 2, chained), read_since from a mid-stream cursor, read_from_consumer (fresh consumer = 0 and from a mid saved checkpoint), and a subscriber's attach drain. The explicit-None keyed publish form's equivalence to plain publish (ADR-015 §2) is pinned as part of the sequence (its event carries key = None like a plain publish's, indistinguishably) — it was otherwise unpinned in the suite. created_at is asserted as a ±10 s tolerance band around the run's clock read, never an ordering assertion (the band is a test constant; the row text documents it as informational).
  • Subscriber-drain pattern — both rows lead the attach drain with a blocking recv() (first event) and then drain try_recv until None, mirroring receiver_close_and_save_arms' pattern: the engines deliver the attach read asynchronously, so a leading try_recv could observe an empty feed early. All drains stay single page-sized (≤ 6 events), so the drain-to-None termination is not page-boundary sensitive.
  • Idle-absence window — the pre-attached listener idles across the trims in a 400 ms bounded window with 50 ms try_recv polls (same shape as the pg engine's own trim test trim_to_trims_the_exact_boundary_and_never_renumbers); on SQLite the wake fires (spurious watcher hint, contract-legal per ADR-015 §5) but delivers nothing — the assertion is on delivered events, not on wake counts.
  • Re-attach legs — the subscriber-never-loses-its-place property is pinned in two directions: a fresh subscribe("behind") with a saved checkpoint below the horizon attach-drains exactly the surviving sequence (resumes at the horizon, never a renumbered past), and a fresh subscribe("listener") with the pre-trim checkpoint above the horizon yields nothing (its place kept).
  • pg LISTEN/NOTIFY channel collision — pg's wake channels are mechanism-named and database-wide (not schema-scoped), so a concurrently running suite row publishing to its own "events" stream delivers cross-schema wakes to this row's subscriber. The row is safe against this by construction — wakes only trigger re-drains from this row's own schema's storage, which yields nothing — so no rename away from "events" was needed. (Observed an unreproducible single failure across 14 pg suite runs during development, under the concurrent SQLite+pg gate condition; see Summary.)

Summary

What landed, verified how:

Two rows added to alkstore-contract-suite/src/properties.rs, re-exported from the crate's lib, wired into both engines' contract_suite.rs targets (SQLite: direct test fns; pg: the harness_row! macro with unique factory tags) — 21 rows in each engine's column, up from 19:

  • stream_ordering_equivalence — ADR-015 §4/§3/§1 stamped; key/payload byte-exactness cross-referenced to payload_round_trip_stores_exact_encoding, tx-seam legs to publish_with_key_tx_commit_atomicity.
  • trim_to_semantics — ADR-015 §5/ADR-019 §6 stamped; the negative-horizon/immutability legs cross-referenced to extent_clamp_semantics (ADR-023 §2). Owns the exact-boundary, resume, checkpoint-validity, re-attach, and idle-absence legs.

Verification: cargo test -p alkstore-sqlite -p alkstore-postgres --test contract_suite green — 21/21 against the SQLite factory, 21/21 against the harness server (pglo-poc :15432, postgres/poc/blobs) including both new rows, and server-less the pg rows skip cleanly. Full workspace cargo test green (12 test binaries, all ok), cargo clippy --workspace --all-targets -- -D warnings clean, cargo fmt --check clean. Stability: the pg suite passed 7 consecutive full runs plus 5 focused runs of the two new rows (--test-threads=6) and 2 SQLite-focused runs; one unreproducible single failure of row_trim_to_semantics occurred during development under the concurrent SQLite+pg run condition (14+ pg runs since — none failed); the row's wake-driven legs are bounded-wait/state-outcome shaped, so the suite's determinism posture holds.