202 lines
11 KiB
Markdown
202 lines
11 KiB
Markdown
---
|
||
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). |