Portable standard-library primitives
This document specifies the language-neutral Timer, Timeout<T>, and
RevisionBarrier convenience APIs. Bindings may expose idiomatic names and
types, but an implementation earns the corresponding coverage feature only by
replaying the canonical fixtures against its public production API.
The three versioned features are:
stdlib_timer_v1stdlib_timeout_v1stdlib_revision_barrier_v1
All time in this contract is monotone logical time. Production implementations normally read a platform monotone clock; conformance runners inject a clock and wait driver and must never sleep or depend on wall-clock scheduling.
Shared rules
- Logical instants and durations are unsigned 64-bit integers.
start + durationis checked. Overflow returns typedUnavailableand never wraps.- A clock observation lower than the most recently accepted observation returns
Unavailable(clock_regression)without changing the stored state. - A deadline is inclusive:
now >= deadlinereaches the deadline. - The first terminal result is latched. Later reads return the same result and invoke no caller-supplied adapters.
- The adapter owns no executor, async runtime, or thread. Waiting is driven by a caller-owned clock/wait seam.
Timer
Starting a timer at start for duration produces a pending timer whose
deadline is start + duration. A zero duration therefore fires on the first
observation at start.
observe(now) has two non-error observations:
Pending(deadline)whennow < deadline;Fired(fired_at)whennow >= deadline.
The first firing latches its actual observation instant as fired_at; later
observations preserve that value. A timer cannot return to pending.
Timeout<T>
Timeout<T> is a caller-driven adapter around an operation probe and a
cancellation probe. It is not a future executor and it is not the reactive
TimeoutCell.
TimeoutCell emits a reactive timeout edge; this adapter resolves a single
operation to one of:
Completed(T)TimedOutCancelledUnavailable(reason)
Each nonterminal poll(now, operation, cancellation) uses this precedence:
- Reject a regressed clock without polling either adapter.
- If
now >= deadline, returnTimedOutwithout polling either adapter. - Sample the operation and cancellation adapters once each.
- A completed operation wins, including when cancellation is observed in the same poll.
- An unavailable operation returns
Unavailable(operation_unavailable). - Cancellation returns
Cancelled; an unavailable cancellation adapter returnsUnavailable(cancellation_unavailable). - Otherwise remain pending.
This order makes exact-deadline behavior and simultaneous completion/cancellation deterministic in every binding.
RevisionBarrier
A revision barrier waits for both:
current_revision >= required_revision; and- a caller-supplied derived predicate to be true.
Revisions never decrease. Registration increments a wake generation, then the waiter re-reads the revision and predicate after registration. This register-then-recheck rule closes the check-to-sleep race: an advance that lands between the initial check and waiter registration is observed immediately.
A waiter may have an inclusive deadline and a cancellation adapter. Deadline
dominance is checked before cancellation. Its terminal outcomes are
Satisfied(revision), TimedOut, Cancelled, Disposed, and
Unavailable(reason). Disposal wakes all waiters and latches.
Effect receipts and transport acknowledgements are application-owned observations. Recording a receipt cannot advance a barrier revision, change its wake generation, or satisfy a waiter.
Canonical fixtures and mutation gates
The canonical corpus is under conformance/stdlib/ and validates against
schemas/stdlib-fixture.schema.json. Each family declares a scenario and
assertion floor. A runner that opens zero fixtures, executes fewer than the
declared floor, or merely echoes fixture expectations fails conformance.
The spec test runner also applies named mutations. At minimum it proves that the corpus detects:
- changing
>=to>at a deadline; - checking cancellation before pre-deadline completion;
- failing to latch a terminal result;
- omitting the barrier’s post-registration recheck;
- treating an effect receipt as barrier authority; and
- replacing production transitions with fixture bookkeeping.
Bindings may advertise a feature to the peer suite only after their public API passes the matching canonical family and its mutation checks. Unsupported bindings stay visible as staged and receive no pass credit.