--- id: core-pin-offset-initial-value name: Verify and pin EventReceiver::offset()'s pre-yield value (review 004 item 12) status: completed depends_on: [] scope: narrow risk: low impact: project level: implementation tags: [review-004-fixes, core, contract, verification] --- ## Description The named gap from `docs/reviews/004-pre-release-general-review.md` §"Findings recorded, not fixed" item 12: `EventReceiver::offset()` pins the *post-yield* value only; the *pre-yield* return (the seeded checkpoint vs 0) is unpinned in core-contract.md's receiver text. Two steps, in order: 1. **Verify the three engines' pre-yield values empirically** — the review explicitly did not verify them this session. Probe per engine: a fresh consumer's `offset()` before any yield, and a consumer with a saved checkpoint's `offset()` before any yield. The contract suite is the natural home (a three-way equivalence leg, stamped per `version_stamp.rs` convention); per-engine tests are the acceptable alternative if the suite's harness shape fights the probe — implementer's choice, recorded. 2. **Pin the semantics in the contract text** — core-contract.md's `EventReceiver::offset()` paragraph gains the pre-yield return (dated annotation). Doc-only. **If the engines diverge**: do NOT paper over with a doc pin — record the divergence precisely (which engine, which arm) and raise with the user; a contract-observable divergence is a fix-the-code-or-amend conversation, not a doc edit. ## Acceptance Criteria - [x] The three engines' pre-yield `offset()` values verified equal by live runs (the probe/leg recorded; green on all three columns — pg against the harness server) - [x] core-contract.md's `EventReceiver::offset()` text pins the pre-yield return with a dated annotation - [ ] If divergent instead: the divergence recorded and raised with the user (this AC replaces the doc pin, not supplements it) - [x] Doc gate green; any new suite leg green on all three columns ## References - docs/reviews/004-pre-release-general-review.md §"Findings recorded, not fixed" item 12 (the named gap) - docs/architecture/core-contract.md (the receiver text, the verification backlog) - alkstore-contract-suite (the three-column harness; the version-stamp convention) ## Notes - **The engines were equal — the doc-pin branch applies, not the divergence branch.** Read first (all three `offset()` bodies are `self.position`, and all three constructors initialize `position: 0` unconditionally — mem `alkstore-mem/src/stream.rs:353`, sqlite `alkstore-sqlite/src/stream.rs:399`, pg `alkstore-postgres/src/stream.rs:620`), then verified live by the new suite leg on all three columns: 0 on every pre-yield arm (fresh, positive-checkpoint, negative-seed), no divergence to raise. - **Probe home: the contract suite** (the task's first choice) — a new row `receiver_offset_pre_yield_is_zero` in `alkstore-contract-suite/src/properties.rs`, wired into all three engines' `tests/contract_suite.rs` executors. Four arms: fresh consumer, consumer with a stored positive checkpoint, consumer with a stored negative checkpoint (the ADR-023 §2 totality seed — the arm a checkpoint-seeded realization would surface on), and a first-observation composition leg (the attach read prefetches unobserved; the first `recv` moves `offset()` to the last-yielded offset). Stamp per the `version_stamp` convention: ADR-008 §8's `EventReceiver` shape + the core-contract.md pin (no ADR owns this property's pre-yield arm — the review item is the pin's origin, so the backlog row is the cited pin). - **Doc pin location**: the task said "core-contract.md's `EventReceiver::offset()` paragraph" — no such standalone paragraph exists; the receiver's contract text lives in the streams/ `subscribe(consumer)` bullet (ADR-008 §8 pins only the shape comment "the receiver's current offset"). The pin landed there (dated annotation), *and* on `offset()`'s own trait doc in `alkstore/src/event_receiver.rs` (core's doc comments are contract text per AGENTS.md; dated the same). ADR-008 §8's shape comment was deliberately left untouched — a doc-only verification task takes no ADR amendment. - **Verification-backlog bullet added** (core-contract.md), matching the section's evolved role: the new bullet records the verified pin with the row's name and the all-three-columns result, same posture as the review-004 suite legs before it. - Frontmatter `last_updated` extended with the pin (dated), keeping the freeze note intact. ## Summary The pre-yield `offset()` question closed: all three engines return 0 before any yield regardless of stored checkpoint (positive, negative, or absent) — the no-yield sentinel, composing with the pinned pre-yield `save_offset()` no-op; the first `recv`/`try_recv` observation is the first move. Pinned in three places: the contract text (core-contract.md streams row + verification-backlog bullet, dated 2026-10-11), the core trait doc (`event_receiver.rs::offset()`), and the suite (new stamped row `receiver_offset_pre_yield_is_zero` on `alkstore-contract-suite`). Verified: the new row green on all three columns (pg against the harness server `pglo-poc` :15432), full pg column green (135+26+9), workspace tests green server-less, clippy `-D warnings`, `cargo fmt --check`, doc gate zero warnings, fuzz corpus replay 6/6, wasm32 mem check green. Contract-observation only — no engine code changed, no ADR amendment.