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 |
|
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 yieldsoffset ASCglobal FIFO per stream — same publish order → same read order onread_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);keyround-trips exactly (NonestaysNone,SomestaysSome, on every read form);streamcarries the stream name andcreated_atis unix-seconds-at-publish (informational — tolerance-bounded proximity to now, never an ordering assertion). The single-event key/payload round-trip already pins inpayload_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 inextent_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_offsetreturns it;read_from_consumerresumes 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.rstargets - 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-postgresgreen (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"), keyedNoneexplicitly, unkeyed, keyedSome("a"), unkeyed) into one stream and pins the same order across four read forms: wholeread_since, cursor-paginatedread_since(limit 2, chained),read_sincefrom a mid-stream cursor,read_from_consumer(fresh consumer = 0 and from a mid saved checkpoint), and a subscriber's attach drain. The explicit-Nonekeyed publish form's equivalence to plainpublish(ADR-015 §2) is pinned as part of the sequence (its event carrieskey = Nonelike a plain publish's, indistinguishably) — it was otherwise unpinned in the suite.created_atis 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 draintry_recvuntilNone, mirroringreceiver_close_and_save_arms' pattern: the engines deliver the attach read asynchronously, so a leadingtry_recvcould 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_recvpolls (same shape as the pg engine's own trim testtrim_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 freshsubscribe("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 topayload_round_trip_stores_exact_encoding, tx-seam legs topublish_with_key_tx_commit_atomicity.trim_to_semantics— ADR-015 §5/ADR-019 §6 stamped; the negative-horizon/immutability legs cross-referenced toextent_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.