--- id: release-contract-window-close name: Class-1 window's last dispositions — the wave-6 recorded observations status: completed depends_on: [] scope: moderate risk: medium impact: project level: implementation tags: [wave-8, contract, adr] --- ## Description ADR-017 §2's class-1 amend-in-place window **terminates permanently at the core crate's first release** — this pre-release pass is the last chance to land the contract-text dispositions the wave-6 review gate recorded for it (`tasks/review-wave-6.md` §Recorded findings). Land each as either contract/ADR text (a class-1 amendment, legal only now) or an explicit documented-tolerance record — no silent divergence survives into the release: 1. **Multi-thread publish→wake ordering tolerance** (streams): offset allocation precedes insert+wake, so two concurrent publishes can complete 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). Nothing contract-side pins wake-fire order vs offset order; the SQL engines share the shape in principle. Decide: document as a tolerated ordering (where — core-contract.md's delivery-guarantee table is the natural home) or amend as ADR text (wake order per stream = offset order — the heavier path, and one the mem engine's current-thread posture doesn't exercise). **Raise the recommendation with the user before landing** — this is a consumer-visible guarantee decision, exactly the class AGENTS.md says to escalate. 2. **ADR-023 §2 domain-table classifications** (all three engines uniform; the table is the contract's numeric-domain record): `heartbeat(extend)`'s seconds-shaped argument (boundary-total today: saturating/SQL add — a negative shortens/voids the claim); `save_offset`'s argument (negatives accepted, stored, reads resume forward; monotone no-op below the checkpoint); and pick the right home for each. 3. **`EventReceiver::try_recv`'s closed shape**: `Err(Closed)` (mirrors `WakeReceiver::try_recv`, ADR-008 §3) — mem-test-pinned today; ADR-021 §5 pins only `recv()`'s arms. Annotate the pinned shape. 4. **`get_job` id-global vs queue-scoped prose**: core-contract.md's "queue-scoped" handle phrasing reads as a filter but the uniform behavior is id-global lookup (`get_job_tx` *is* queue-filtered). Fix the prose so the contract says what all three engines do. 5. **Mem-arithmetic transplant note**: dispose the recorded one-owner-rule observation (the mem copies are byte-level transplants of the SQLite implementations; equivalence is suite-pinned three-way) — likely a no-action disposition recorded in the task Notes, but the record should say so explicitly. Every landed amendment follows the ADR amendment discipline (dated in-place annotation citing this pass; the suite's stamps accumulate if a row's cited § text changes meaning). Items 2–3 may add suite stamp citations — check whether any existing row's stamp needs the accumulation. ## Acceptance Criteria - [x] Item 1 decided with the user (documented-tolerance vs ADR amendment), landed in the chosen home, decision recorded - [x] ADR-023 §2 table carries the `heartbeat(extend)` and `save_offset` classifications (or the task records why a different home was chosen) - [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 - [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, which would be a follow-up, not this task) ## References - docs/architecture/decisions/017-contract-versioning.md §2 (the class-1 window and its first-release termination) - tasks/review-wave-6.md §Recorded findings (the observations this task disposes) - docs/architecture/core-contract.md (delivery-guarantee table; §Verification backlog) - docs/architecture/decisions/023-fourth-review-round.md §2 (the domain table) - docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md §5 (the receiver arms text) ## Notes All five dispositions landed 2026-10-11 as dated in-place annotations citing this pass (the pre-release class-1 close-out pass, [ADR-017](../docs/architecture/decisions/017-contract-versioning.md) §2's terminating window). Docs-only — no code change (item 1's enforced-guarantee alternative was declined with the user, so no follow-up code task spawns). 1. **Publish→wake ordering tolerance — decided with the user, documented tolerance.** The two candidates were raised with the user (2026-10-11) and the documented-tolerance posture was chosen over the ADR amendment (wake order per stream = offset order) — the amendment is arguably unachievable on Postgres while offsets are sequence-assigned pre-commit (commit order inverts sequence order; enforcement needs hole-filling/redesign) and contradicts the wake mechanism's hint-shaped best-effort posture. Landed: core-contract.md's streams section carries the tolerance paragraph (the full text: the mem multithreaded-runtime shape, the pg sequence/commit shape, the event-stays-in-the-log promise, the consumer recipe — lagged checkpoints or direct `read_since` sweeps below them), the delivery-guarantee obligations list carries the consumer-obligation bullet, and ADR-015 §4 carries the dated companion annotation (the ordering row pins *read* order only; wake order unpinned). 2. **`heartbeat(extend)` + `save_offset(offset)` — both join the ADR-023 §2 boundary/offset row**, annotated in place with the home rationale: the duration row's rejection rationale never applies (a non-positive `extend` is a relative instant like `delay`, not a lease handout — a negative shortens/voids the claim and the uniform validity predicate governs; the three engines' arithmetic — `saturating_add`/SQL integer add — is total over non-positive values, and the heartbeat reports `true` when the row was processing and unexpired at call time), and `save_offset`'s offset is literally an offset (negative stored, reads resume forward, regressions are the ADR-019 §6 monotone no-ops) — pinning rejection would have contradicted all three engines. core-contract.md's numeric-domain paragraph mirrors the extension. The verification-backlog numeric-domain row was extended to register the suite-duty follow-up those two classifications imply (their suite rows did not land here — docs-only task); before release-readiness, the review-wave-8 gate owns the audit. 3. **`EventReceiver::try_recv`'s closed shape — ADR-021 §5 dated annotation**: `Err(Closed)` (terminal; the `None` arm's causes), `Ok(None)` = idle, `Database` otherwise — mirroring `WakeReceiver::try_recv` (ADR-008 §3). Home is §5 so one normative section governs every receiver Err/close arm. Verified uniform by code read (mem `stream.rs`, sqlite `stream.rs`, pg `stream.rs` all map channel disconnect → `Err(Closed)`); core's rustdoc carried the shape from landing; the mem suite pins it. 4. **`get_job` prose — core-contract.md's queues section now says the uniform behavior**: id-global lookup on the handle (rows in any queue), `get_job_tx(queue, job_id)` queue-filtered. queues.md's reads sentence — which mischaracterized both as "name-taking pure reads" — corrected in the same pass. Code read verified the uniform shapes (mem `queue.rs`/`tx.rs`'s `merged_get_job`; SQLite substrate `get_job(conn, id)` vs the tx path; pg). ADR-019 §1's "queue-scoped claim/maintenance ops" phrasing stands — it names claim/maintenance ops only, and the corrected core-contract text now disambiguates the neighborhood. 5. **Mem-arithmetic observation — no-action disposition, recorded**: the mem copies are byte-level transplants of the SQLite implementations (`resolution.rs`, `scheduler.rs`'s `@every` parser and `skip_forward`); equivalence is suite-pinned three-way (`backoff_curve_equivalence`, `enqueue_opts_resolution` green on all three columns, re-verified this session). ADR-012 §2's one-owner rule is satisfied exactly as written (mem owns its modules; the suite is the honesty instrument) — no code or doc change warranted; the record here is the disposition. **Suite stamps checked** (the task's accumulation duty): no existing row's cited § text changed meaning, so no stamp accumulates. The four rows citing ADR-023 §2 (`extent_clamp_semantics`, `duration_refusal_on_non_positive_ttl`, the enqueue-opts resolution row, the backoff row) test classifications the amendments left meaning-identical — rows were *added* to the §2 table and annotated, existing cells' semantics untouched; the receiver-arms row citing ADR-021 §5 tests `recv()`/`save_offset`/close arms the annotation left verbatim. The two new classified behaviors' suite rows are the registered follow-up (Notes 2). ## Summary `release-contract-window-close` completed 2026-10-11: all five wave-6 recorded observations disposed as contract/ADR text with dated annotations before ADR-017 §2's class-1 window terminates at first release. Item 1 decided with the user — documented tolerance for the publish→wake ordering observation, landed in core-contract.md (streams tolerance paragraph + delivery-guarantee obligations bullet) with the ADR-015 §4 companion annotation; the wake = offset-order ADR amendment was presented and declined (unachievable against commit- ordered pg visibility without redesign; contradictorily sharpen a hint-shaped mechanism). Items 2–3: ADR-023 §2's boundary/offset row gained `heartbeat(extend)` and `save_offset(offset)` (total — negatives well-defined, with the homes' rationale annotated, the core-contract domain paragraph mirrored, and the backlog numeric- domain row registering the suite-duty follow-up); ADR-021 §5 gained the `EventReceiver::try_recv` closed-shape annotation (`Err(Closed)`, mirroring ADR-008 §3). Item 4: core-contract.md's `get_job` prose now says the uniform id-global/`get_job_tx`-filtered split (queues.md's mischaracterizing reads sentence corrected alongside). Item 5: the mem-arithmetic observation's no-action disposition recorded above. Suite-stamp accumulation checked — none required (no cited § text changed meaning). Verified docs-only: `cargo build`, workspace tests green (mem 102+25, SQLite 192+25, pg 125+25+9, core 25 — three-way equivalence rows green), clippy `--all-targets -D warnings` clean, `cargo fmt --check` clean, fuzz corpus replay green (6/6), `RUSTDOCFLAGS="-D warnings" cargo doc --no-deps` zero warnings, `taskgraph validate` green (79 tasks).