Repository navigation
test(core): split the Era handoff Loom model into offer / accept / cancel - #255
Merged
Merged
Conversation
dshbox-dev
added a commit
that referenced
this pull request
Oct 5, 2026
Maintainer review of #255: the UnsafeCell-backed copy of Tokio's oneshot state word would have been the repo's first `unsafe`, and it created a correspondence target that drifts with Tokio upgrades. The ticket's subject is guard ownership across offer/accept, not oneshot memory ordering, which is trusted to Tokio. The reduced oneshot is now a loom `Mutex<OfferSlot>` holding the stored offer and a receiver-dropped flag. Send refuses and returns the still-armed offer when the receiver was dropped; receiver drop marks the slot closed and drops any stored offer; one poll takes the offer and accepts it. The mutex stands in for the oneshot's send-to-receive synchronization. The guard remains a real value with Drop/Option::take. Assertions, the all-outcomes-reached check, the three negative controls and their messages, test names and era_model bounds are unchanged. Refs #247 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ncel The ER-07 handoff model CASed WAITING -> DELIVERED in one step, so its "delivered" stood for production's accept and the offered-but-not-accepted state was absent (#247). Production sends an EraHandoff whose EraHandoffGuard stays armed inside the offered message until EraHandoff::accept disarms it; dropping the message unaccepted runs the guard's Drop, which detaches cleanup_undelivered_successor. The model now carries a guard value with a Drop through a reduced oneshot that keeps Tokio 1.53's VALUE_SENT/CLOSED state-word protocol and orderings (AcqRel/Acquire set_complete CAS, Acquire poll, Acquire fetch_or close), with the message in a loom UnsafeCell so Loom checks the send/receive edge for causality. Oracle facts are Relaxed and read only after the joins, so no happens-before edge is added. The framework offers; the caller polls once and accepts in that poll, or drops the receiver, which lands before or after the offer. Every terminal state has exactly one owner: accepted (no framework cleanup) or cancelled before/after the offer (exactly one guard cleanup). The positive test also checks that all three outcomes are reached across the explored schedules. offered_but_unaccepted_handoff_without_guard_cleanup_is_detected treats a successful send as delivery and must fail with the cancel-after-offer assertion. The two existing ER-07 controls keep their names; the reclaim control is re-targeted to after accept. era_model bounds are unchanged. Docs: the "Era offer/accept window" entry leaves the not-represented list, the Phase 3 ownership note describes the split model, and the Era test count becomes thirteen (also in the review guide's ER table). Closes #247 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maintainer review of #255: the UnsafeCell-backed copy of Tokio's oneshot state word would have been the repo's first `unsafe`, and it created a correspondence target that drifts with Tokio upgrades. The ticket's subject is guard ownership across offer/accept, not oneshot memory ordering, which is trusted to Tokio. The reduced oneshot is now a loom `Mutex<OfferSlot>` holding the stored offer and a receiver-dropped flag. Send refuses and returns the still-armed offer when the receiver was dropped; receiver drop marks the slot closed and drops any stored offer; one poll takes the offer and accepts it. The mutex stands in for the oneshot's send-to-receive synchronization. The guard remains a real value with Drop/Option::take. Assertions, the all-outcomes-reached check, the three negative controls and their messages, test names and era_model bounds are unchanged. Refs #247 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dshbox-dev
force-pushed
the
test/era-offer-accept-model-20261005
branch
from
October 5, 2026 02:54
e1eb528 to
d64e3e7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #247
Summary
The ER-07 handoff model in
crates/cordis-core/tests/loom_era.rsused to CASWAITING -> DELIVEREDin one step. Production (FiberHandle::era_swap) sends anEraHandoffwhoseEraHandoffGuardstays armed inside the offered message untilEraHandoff::acceptdisarms it. That gives production an offered-but-not-accepted state, which the old model did not have.HandoffGuardvalue with aDrop(EraHandoffGuard,Option::takesingle-use) moves inside anEraOffer(EraHandoff) through a reduced oneshot slot, a loomMutex<OfferSlot>that holds the stored offer and a receiver-dropped flag. The mutex stands in for the oneshot's send-to-receive synchronization. Tokio's oneshot internals are trusted, not modeled, and the model contains nounsafe. The oracle facts useRelaxedand are read only after the joins. (Changed in e1eb528 after maintainer review; the first revision copied Tokio's state word into anUnsafeCell.)let _ = send.send(Ok(offer)). A refused offer is dropped while still armed.receive.awaitfollowed byhandoff.accept()in the same poll.offered_but_unaccepted_handoff_without_guard_cleanup_is_detected(new) treats a successful send as delivery. It fails withoffered but unaccepted successor must be cleaned exactly once by its armed guard.cancelled_handoff_without_framework_cleanup_is_detectedis unchanged in name and message. It now disarms a refused offer.cancellation_reclaiming_an_already_handed_off_successor_is_detectedis re-targeted to afteraccept. Its message is nowaccepted successor cannot retain framework cleanup ownership.era_modelis unchanged (max_threads = 3, max_branches = 64). No test was renamed, and CI does not select anyloom_eratest by name.docs/lifecycle-concurrency-modeling.md: removed the "Era offer/accept window" entry from the not-represented list, reworded the Phase 3 ER-07 handoff note and the controls bullet that follows it, and changed "twelve" to "thirteen" Era tests. Theready()bullets and LC-06 text, which Loom: model ready() publication sequence in ReadyHistoryModel (LC-06) #248 is editing, are untouched.docs/lifecycle-concurrency-review-guide.md: added the new control to the ER-07 row and updated the Era test count.Gates (
ci/gates.sh t247)PASS: toolchain, fmt, clippy, vocab, doc. The test, examples and latest gates were not run locally for this test/doc-only change.
cargo clippy --release -p cordis-core --features loom-tests --test loom_erareports nothing for the test file.Loom timings (local, CI commands)
cargo test --locked --release -p cordis-core --features loom-tests --test loom_era: 13 passed. The tests take 0.20 s, or about 0.4 s wall with the build already done (re-measured at e1eb528).... --test loom_inertia: 16 passed. The tests take 11.2 s, or about 14.2 s wall.Both are well inside the 15-minute Loom job timeout.
🤖 Generated with Claude Code