Files
alkstore/tasks/release-contract-window-close.md
T

202 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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).