Async runtime for Rust where correctness is structural: region-owned tasks, cancel-correct protocols, capability-gated effects, and deterministic replay testing
Rust
285
6,019 commits
updated Oct 18, 2026
Spec-first, cancel-correct, capability-secure async for Rust
cargo add asupersync --git https://github.com/Dicklesworthstone/asupersync
The Problem: Conventional executor APIs leave important lifecycle contracts to composition and discipline. Cancellation can abandon partial effects, detached tasks can outlive their owner, cleanup may be best-effort, and schedule dependent failures can be difficult to reproduce.
The Solution: Asupersync makes its core task-ownership and runtime-tracked effect contracts structural rather than conventional. Tasks are owned by regions that close to quiescence. Cancellation is an explicit request → drain → finalize protocol, with budgeted bounds on covered, cooperative paths; non-cooperative code and foreign calls do not acquire a universal shutdown bound. Runtime-managed effects require capabilities, with host-boundary exceptions documented explicitly. The lab runtime makes controlled schedules deterministic and replayable.
| Guarantee | What It Means |
|---|---|
| No orphan tasks | Every spawned task is owned by a region; region close waits for all children. Tasks you spawn through a Cx belong to that Cx's region. Tasks spawned through a RuntimeHandle belong to the root region and are drained when the runtime shuts down. |
| Cancellation is a request | Cancelling a task asks it to stop. It keeps running until it reaches a cancellation point (cx.checkpoint() or a cancel-aware await), so it can finish its own async cleanup and return a value. A task that never reaches one is never forcibly stopped, and it holds up its region's close. |
| Cleanup bounds | Cleanup budgets are advisory on the production runtime: a task that keeps running past its budget is not stopped. Runtime::shutdown_timeout bounds how long the caller waits for teardown. |
| No silent drops | A channel send can reserve capacity first and commit later, so a cancelled send never loses or half-sends a message. A one-call send() exists for the common case. |
| Deterministic testing | Lab runtime: virtual time, deterministic scheduling, trace replay. The same seed reproduces the same schedule. |
| Capability-scoped effects | Spawning, timers and runtime-managed effects go through an explicit Cx. Most public I/O entry points (TcpStream::connect, File::open) take no Cx and check no capability today; that work is tracked as asupersync-issue65-criticisms-kpmoy5.5. |
These guarantees are enforced by the runtime, not by the type system. They cost time per task: see Measured against tokio.
Experimental scheduling policy and diagnostics. These are not guarantees:
enable_adaptive_cancel_streak(true)): a
discounted UCB1 policy picks the cancel-streak limit from {4, 8, 16, 32, 64}
at deterministic epoch boundaries. Measured against the fixed limit of 16 on
two hosts, it did not beat it on cancel-heavy work and was 1-29% slower on
spawn+join, yield and channel round trips, so the default is the fixed limit.The attribute macro builds and drives the production runtime (a multi-thread
scheduler with the host-independent default worker count plus an on-demand
blocking pool; #[main(flavor = "current_thread")] and blocking = N adjust
both) and, when the entry future returns, drains the root region: tasks that
outlived main are protocol-cancelled and given drain_ms (default 2000) to
finish their cleanup before teardown. The first program needs no runtime
concepts:
use asupersync::main;
#[main]
async fn main() {
println!("hello from asupersync");
}
This exact program is examples/onramp_level0.rs.
Continue with the four-level graduated on-ramp to add the
prelude, capability context, outcomes, budgets, structured fan-out, two-phase
effects, and deterministic lab oracles.
If you already know tokio, this section maps the primitives you use daily to their asupersync equivalents. The APIs are intentionally different -- asupersync trades implicit convenience for explicit cancel-correctness -- but the concepts map cleanly.
| tokio | asupersync | Key difference |
|---|---|---|
tokio::spawn(fut) | cx.spawn(|cx| async move { fut.await }) or cx.spawn_in(&scope, |cx| fut) | Task is owned by a region; the factory receives its own Cx. See onramp_level2.rs. |
JoinHandle<T> | TaskHandle<T> | .join(cx).await returns Result<T, JoinError>; cancellation and panic remain distinct. |
tokio::task::JoinSet<T> | JoinSet<T, E, P> | JoinSet::in_cx(cx) or JoinSet::new(&scope) owns dynamic fan-out in one region; join_next, join_all, and cancel_all always retain drain ownership. |
tokio::spawn_blocking(f) | cx.spawn_blocking(|cx| f()) | Same idea: RuntimeBuilder::new() and #[main]/#[test] configure an on-demand pool, blocking_threads(0, 512) (blocking = N in the macros). With blocking_threads(0, 0) (blocking = 0) there is no pool, and the closure runs inline on the async worker. |
tokio::select! | race!(cx, { move |child| a(child), move |child| b(child) }) or cx.race_drained_with(...) | Returns only after the winner is selected and every loser is protocol-cancelled and drained. Each branch receives its own child Cx; pass it to the branch's operations. A prebuilt branch that awaits on the caller's cx (for example rx.recv(&cx)) never sees its cancellation, so the drain waits for it to finish on its own. Each branch runs in its own child region: tasks a losing branch spawned through its own Cx are cancelled and drained before the race returns, while tasks the winner spawned keep running. See docs/macro-dsl.md. |
tokio::join! | join!(a, b); use JoinSet::join_all(cx) for dynamic arity | Inline branches complete together; spawned dynamic members remain region-owned and are collected in spawn order. See macros_basic.rs. |
FuturesUnordered / join_all over borrowed data | cx::fiber::scope(|s| async move { s.spawn(fut) }) | Fibers run concurrently inside the calling task, may borrow from its stack (no 'static), and the scope waits for all of them. Each fiber has its own cancellation: the task's cancellation reaches every fiber, FiberHandle::cancel stops one, and a panicking fiber cancels its siblings. They are not parallel; use tasks for that. See fibers_borrowing.rs. |
tokio::time::sleep(dur) | sleep(now, dur) | Takes current Time instead of reading the clock implicitly. Works with virtual time in lab runtime. |
tokio::time::timeout(dur, fut) | timeout(now, dur, fut) or cx.scope().timeout(&cx, dur, |cx| op) | time::timeout returns Result<T, Elapsed> and drops the inner future when the clock wins; Scope::timeout spawns the operation as a region task and cancels and drains it on expiry, reporting a late terminal outcome instead of losing it. |
tokio::time::interval(dur) | interval(now, dur) | Same MissedTickBehavior options (Burst, Delay, Skip). |
tokio::sync::mpsc::channel(n) | channel::mpsc::channel::<T>(n) | Two-phase send: tx.reserve(&cx).await?.send(val). Reserve is cancel-safe; the commit returns an Outcome, which is Err with the value back if the receiver is gone. |
tokio::sync::oneshot::channel() | channel::oneshot::channel::<T>() | Two-phase: tx.reserve(&cx) then permit.send(val). |
tokio::sync::broadcast::channel(n) | channel::broadcast::channel::<T>(n) | Two-phase send. Lagging receivers get RecvError::Lagged. |
tokio::sync::watch::channel(init) | channel::watch::channel(init) | rx.changed(&cx).await? then rx.borrow_and_clone(). |
tokio::sync::Mutex | sync::Mutex | mutex.lock(&cx).await? -- takes &Cx, returns Result (can be cancelled). |
tokio::sync::RwLock | sync::RwLock | .read(&cx).await? / .write(&cx).await?. Writer-preference fairness. |
tokio::sync::Semaphore | sync::Semaphore | sem.acquire(&cx, n).await?. Permit is an obligation released on drop. |
tokio::sync::Barrier | sync::Barrier | barrier.wait(&cx).await?. Leader election built in (is_leader). |
tokio::sync::Notify | sync::Notify | notify.notified().await / notify.notify_one() / notify.notify_waiters(). Differences: notified() registers on first poll (use notified.as_mut().enable() to arm on creation); notify_one() accumulates permits when no waiter is present. |
tokio::sync::OnceCell | sync::OnceCell | `cell.get_or_init( |
tokio::task::yield_now() | yield_now() | Identical concept -- yields to the scheduler. |
1. Every async operation takes &Cx.
Where tokio reads ambient runtime state from thread-locals, asupersync passes an explicit capability context. This means cancellation and budgets compose structurally -- you can see exactly what a function can do from its signature.
// tokio
let permit = tx.reserve().await?;
// asupersync
let permit = tx.reserve(&cx).await?;
2. No orphan tasks. Scopes close to quiescence.
In tokio, tokio::spawn returns a detached task. In asupersync, every task lives in a region. When a scope exits, it waits for all children to finish. No fire-and-forget, no zombie tasks.
3. Outcome instead of just Result.
Tokio task results are Result<T, JoinError> where JoinError covers panics and cancellation. Asupersync uses a four-valued Outcome<T, E> that distinguishes Ok, Err, Cancelled(reason), and Panicked(payload). The severity lattice (Ok < Err < Cancelled < Panicked) drives how combinators aggregate results.
tokio:
use tokio::sync::mpsc;
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel(10);
tokio::spawn(async move {
for i in 0..5 {
tx.send(i).await.unwrap();
sleep(Duration::from_millis(100)).await;
}
});
while let Some(val) = rx.recv().await {
println!("got: {val}");
}
}
asupersync:
use asupersync::channel::mpsc;
use asupersync::{Cx, Outcome};
use asupersync::time::sleep;
use std::time::Duration;
async fn run(cx: &Cx) {
let (tx, mut rx) = mpsc::channel::<i32>(10);
let mut producer = cx.spawn(move |cx| async move {
for i in 0..5 {
let Ok(permit) = tx.reserve(&cx).await else {
break; // cancellation or a closed receiver stops production
};
let Outcome::Ok(()) = permit.send(i) else {
break; // the receiver may disconnect after reservation
};
sleep(cx.now(), Duration::from_millis(100)).await;
}
}).expect("spawn producer");
while let Ok(val) = rx.recv(&cx).await {
println!("got: {val}");
}
let _ = producer.join(cx).await;
}
The key differences: reserve/send two-phase pattern prevents message loss on cancellation, &cx threads through capabilities, and the task is owned by the scope rather than detached.
Tasks don't float free. Every task is owned by a region. Runtime-spawned tasks carry that ownership through admission, execution, and teardown. Regions form a tree. When a region closes, it guarantees all children are complete, all finalizers have run, and all registered obligations are resolved. This is the "no orphans" invariant, enforced by the public API shape, region accounting, and runtime/oracle checks rather than by discipline. It is not a claim that Rust's type system alone proves every adapter or host-boundary path.
use asupersync::{main, prelude::*};
// Typical executors: `spawn(async { ... })` detaches the task; nothing waits
// for it, and nothing cancels it, when the caller returns.
// Asupersync: the tasks belong to a region of this scope.
#[main]
async fn main(cx: &Cx) {
let scope = cx.scope_with_budget(Budget::new().with_poll_quota(64));
let mut tasks = JoinSet::new(&scope);
for value in 1..=2_u32 {
tasks
.spawn(cx, move |_| async move { Ok::<_, Error>(value) })
.expect("spawn region-owned task");
}
let results = tasks.join_all(cx).await;
// ← guaranteed: nothing spawned into the set is still running here
assert_eq!(results.len(), 2);
}
Cancellation is request, acknowledgement, drain, and finalization—not a silent
drop. It operates as a multi-phase protocol:
Running → CancelRequested → Cancelling → Finalizing → Completed(Cancelled)
↓ ↓ ↓
(bounded) (cleanup) (finalizers)
Cancelled(reason) when cancellation winsStock operations publish conditional bounds through
ResponsivenessRegistry: lookup resolves an operation,
and its entry's bound checks the requested goal and context. Finite results
count delivered operation polls or explicit checkpoint calls under the entry's
published assumptions. Masked operations, external or timer progress, blocking
work, and unknown operations return typed refusals where a finite bound cannot
be established. OwnerQuiescent explicitly requires independent owner progress;
an operation bound alone cannot establish region drain or a wall-clock deadline.
Budgets are sufficient conditions only for paths with a concrete published bound.
The native parked-task cancellation contract is a release-blocking behavioral
boundary. It parks real current-thread and owner-local tasks, and exercises a
cross-thread abort against a task parked on a multi-worker runtime, using
a mutex, bounded-channel send, and semaphore before aborting them, then checks
the exact nested TaskHandle result and waiter cleanup. It also pins abort-
before-first-poll delivery, cancellation racing with the end of a Pending
user-future poll, and panic classification through the same terminal-
publication boundary, and proves that acknowledged asynchronous cleanup can
cross another Pending without being truncated. Ordinary Cx::spawn*
preserves typed results after cancellation acknowledgement while retaining
v0.4.3 task-level cancellation for cancellation-blind late values;
cancellation-dominant combinators and blocking wrappers are tested separately.
Structural source audits and aggregate test counts cannot substitute for this
native behavioral lane. Its canonical remote-required command is recorded as
native-parked-task-cancellation in the proof-lane manifest. The runtime
additionally gives spawn adapters a private terminal-result sender with no
cancellation-aware send method, making publication through the completed
task's cancelled Cx unavailable at the type boundary.
Cancellation progress is observable through ProgressCertificate where the runtime wires it: today that is the HTTP/1 and HTTP/2 listeners' graceful-drain supervisor (src/server/shutdown.rs) and the opt-in scheduler governor; region close and Runtime::shutdown_timeout do not consult it. It tracks potential descent, classifies the current drain regime (warmup, rapid_drain, slow_tail, stalled, quiescent), and reports range-bounded Freedman and Azuma candidates plus a separate projected conditional calculation. Under the current range-only variation cap, raw Freedman is never tighter than Azuma, so the selected public envelope equals Azuma. At the current same-history horizon, telescoping makes both candidate tails algebraically 1; they are not evidence of convergence. The converging flag is instead an empirical status over the complete accepted finite non-negative observation history represented by running statistics. It requires positive endpoint net progress, no detected stall, bounded rebound count and magnitude, no latest-step rebound, and no dropped invalid sample. Non-finite or materially negative telemetry is dropped; that suppresses the remaining-step estimate and reports warmup instead of an actionable terminal phase until reset. The realized delta variance remains diagnostic-only rather than being reused as predictable variation. This makes the evidence behind "is shutdown actually converging?" inspectable without treating one trace as proof of future drift, termination, or bounded drain time.
For covered two-phase communication surfaces where cancellation could otherwise lose a message, Asupersync uses reserve/commit:
let permit = tx.reserve(cx).await?; // nothing committed yet
let outcome = permit.send(message);
// Inspect outcome: success publishes; disconnect returns the original value.
Dropping a permit aborts the reservation and releases capacity. The commit outcome determines whether the message was published or returned to the caller.
This is not a blanket claim for every effect. Inherently partial I/O and adapter surfaces publish their own cancel-safety boundaries, including operations such as read_exact and write_all that are explicitly not cancel-safe.
Runtime-managed effects flow through explicit capability tokens:
async fn my_task(cx: &Cx) {
cx.spawn(...); // ← spawn capability
sleep(cx.now(), Duration::from_millis(10)).await; // ← time, read through the Cx
cx.trace("checkpoint reached"); // ← trace capability
}
Swap Cx to change interpretation: production vs. lab vs. distributed.
I/O entry points such as TcpStream::connect(addr) and File::open(path) take no Cx, so they
check the calling task's context: without the IO capability they refuse with
[ASUP-E009]. Threads outside the runtime are not affected.
cx.with_ambient(future) checks them against an explicit cx instead. spawn_blocking still
runs its closure under a restricted context (asupersync-issue65-criticisms-kpmoy5.5).
This is not a blanket claim that every internal helper is Cx-threaded:
host-boundary code such as OS entropy for temporary file names, legacy sync DNS
wall-clock timing, and test/support harnesses must keep their authority
explicit, documented, and outside the deterministic runtime guarantee unless
they are reached through a capability-mediated path.
The lab runtime provides:
LabRuntime report checks 11 of the 24 built-in
oracles from runtime state: task leak, obligation leak, quiescence, loser
drain, finalizer, region tree, deadline monotonicity, the cancellation
protocol, DOWN-message order, managed-supervisor restarts and GenServer replies
(lab::oracle::LAB_RUNTIME_FED_ORACLE_NAMES). Nothing in the runtime feeds
the other 13 yet (channel atomicity, waker dedup and the actor oracles among
them); reports list them as passed and count them as not fed
(asupersync-52hxjz).Concurrency bugs become reproducible test failures.
Asupersync deliberately uses mathematically rigorous machinery where it buys real correctness, determinism, and debuggability. The intent is to make concurrency properties structural, so both humans and coding agents can trust the system under cancellation, failures, and schedule perturbations.
The runtime design is backed by a small-step operational semantics (asupersync_v4_formal_semantics.md) and a Lean project (formal/lean/Asupersync.lean) that checks six invariants of that abstract model, recorded in formal/lean/coverage/invariant_status_inventory.json: structured concurrency single-owner, region-close quiescence, cancellation protocol, race loser drain, obligation no leaks, and no ambient authority.
The proof posture is exact: these are Lean-checked model invariants with theorem and executable-test linkage. The production Rust runtime has not been proved to refine that model. This is therefore not a blanket mechanized proof of the executor, adapters, protocol implementations, platform backends, or distributed transports. Broader runtime-facing claims stay tiered through TLA+/TLC exports, lab/refinement oracles, and lane-specific coverage artifacts. The CI job lean-build is defined to run lake build on the pinned toolchain and upload a hash-bound receipt, but GitHub Actions is disabled for this repository, so it does not currently run; the last recorded local build is in formal/lean/coverage/lake_build_receipt.txt. The canonical proof command is RCH_REQUIRE_REMOTE=1 rch exec -- lake --dir formal/lean build; see artifacts/formal_proof_posture_contract_v1.json, tests/formal_proof_posture_contract.rs, and formal/README.md.
Some checked artifacts retain the legacy markers Lean-checked core invariants cover the six non-negotiable runtime invariants and checks the six non-negotiable runtime invariants. In this README those phrases mean coverage of the six abstract-model rows only; they do not assert a Rust refinement proof.
The canonical proof-command coverage map is artifacts/proof_lane_manifest_v1.json, checked by tests/proof_lane_manifest_contract.rs. It records which RCH_REQUIRE_REMOTE=1 rch exec -- ... lane covers each production graph, feature graph, fuzz smoke, lib/all-target/clippy/rustdoc frontier, and formal proof guarantee, plus what each lane explicitly does not prove. It also carries proof-lane resource-envelope classes for expected timeout, memory, remote-required, and no-local-fallback semantics; those classes harden proof admission metadata and do not replace OS-level RCH worker cgroup limits. The claim/status dashboard is artifacts/proof_status_snapshot_v1.json, checked by tests/proof_status_snapshot_contract.rs; it maps README/AGENTS proof claims to manifest lanes and validation-frontier blocker rows. Its top-level created_date is the contract inception date, not a whole-dashboard freshness receipt: inspect each claim's proof_evidence_status and, for fresh-rch-pass, its bounded evidence_date. A mapped green row identifies a canonical unblocked lane but does not by itself prove a current RCH pass. The nightly differential workflow runs the bounded-age assertion as a local drift alarm; that cadence check does not replace terminal remote-required RCH evidence for any claim row.
Public guarantee semantic evidence bundles are captured in artifacts/public_guarantee_semantic_evidence_bundles_v1.json, checked by tests/semantic_evidence_bundle_contract.rs and documented in docs/semantic_evidence_bundle.md. The first bundle set covers no-orphan-tasks, race-loser-drain, no-obligation-leaks, cancel-safe-send, deterministic-replay, and default-production-no-tokio. These bundles map public claims to proof lanes, fixtures, freshness states, and no-claim boundaries; they do not turn rerun-required, stale-evidence, blocked, no-win, or unsupported rows into fresh proof.
The artifact-governance final signoff is artifacts/artifact_governance_final_signoff_v1.json, checked by tests/artifact_governance_final_signoff_contract.rs and documented in docs/proof/artifact_governance_final_signoff.md. Its focused manifest lane is artifact-governance-final-signoff; cite it only for the A1-A5/A7/A8 governance aggregation, ledger registration, validation harness count alignment, proof manifest/status rows, README/AGENTS markers, closeout checklist, and no-claim boundaries. It does not prove release readiness, workspace health, runtime correctness, performance improvement, live RCH fleet availability, full-corpus artifact coverage, tracker closure while .beads is dirty, or permission to delete files.
The validation-frontier final signoff is artifacts/validation_frontier_signoff_v1.json, checked by tests/validation_frontier_signoff_contract.rs and documented in docs/proof/validation_frontier_runbook.md. Its focused manifest lane is validation-frontier-final-signoff; cite it only for the VF7 operator packet tying inventory, stale-progress receipts, downstream-consumer proof, graph budgets, the channel MPSC/select fixture split, proof manifest/status rows, e2e runner commands, deterministic Markdown summary, and no-claim boundaries together. It does not prove broad workspace health, release readiness, runtime correctness, performance improvement, no regression, source correctness outside cited surfaces, live RCH fleet availability, local Cargo fallback approval, tracker closure, or permission to delete files.
The Proof Evidence Debt Graph is artifacts/proof_evidence_debt_graph_contract_v1.json, emitted by scripts/proof_evidence_debt_graph.py, checked by tests/proof_evidence_debt_graph_contract.rs, and documented in docs/proof_evidence_debt_graph.md. It ranks stale, superseded, blocked, zero-test, local-fallback, missing-envelope, advisory-only, and failed proof evidence so operators can decide what must be rerun before citation. It does not certify workspace health or turn cached/advisory evidence into correctness proof.
The Semantic Evidence Bundles map is artifacts/semantic_evidence_bundles_v1.json, checked by tests/semantic_evidence_bundles_contract.rs, and documented in docs/semantic_evidence_bundles.md. It links public guarantees such as no orphan tasks, loser drain, no obligation leaks, cancel-safe send, deterministic replay, and no default Tokio to manifest-backed proof lanes, stale/missing evidence fixtures, source anchors, freshness policy, and no-claim boundaries. It does not execute the proof lanes or turn cached, stale, failed, local-fallback, or advisory evidence into fresh proof.
The Proof Lane Failure Repro Receipts contract is artifacts/proof_lane_failure_repro_receipt_contract_v1.json, emitted by scripts/proof_lane_failure_repro_receipt.py, checked by tests/proof_lane_failure_repro_receipt_contract.rs, and documented in docs/proof_lane_failure_repro_receipt.md. It converts saved failed RCH/proof-runner transcripts into minimal repro receipts for compile errors, test assertion failures, timeouts, worker disk pressure, SSH transport failures, retrieval timeouts after remote pass, zero-test proofs, and local-fallback refusals. It chooses the next smallest remote-required rerun or diagnostic command; it does not certify workspace health or turn a repro command into fresh proof.
The Reservation-Aware Fallback Work Finder is artifacts/reservation_aware_fallback_work_finder_contract_v1.json, emitted by scripts/reservation_aware_fallback_work_finder.py, checked by tests/reservation_aware_fallback_work_finder_contract.rs, and documented in docs/reservation_aware_fallback_work_finder.md. It converts read-only tracker, dirty-tree, and Agent Mail reservation fixture snapshots into safe next-action recommendations for claimable tasks, epic-only ready queues, active reservation blockers, stale in-progress candidates, tracker-only dirt, source peer dirt, no-useful-work blockers, and planning fallbacks. It never authorizes branches/worktrees, peer-reserved edits, or local Cargo fallback, and it does not certify source correctness.
The Second-Wave Swarm Control-Loop Certification bundle is artifacts/second_wave_swarm_control_loop_certification_v1.json, emitted by scripts/second_wave_swarm_control_loop_certification.py, assembled by scripts/run_second_wave_swarm_control_loop_certification_e2e.sh, checked by tests/second_wave_swarm_control_loop_certification_contract.rs, and documented in docs/second_wave_swarm_control_loop_certification.md. It aggregates the asupersync-ol11aa.1 through asupersync-ol11aa.7 topology, admission, SLO brownout, stale-proof debt, crashpack repro, and fallback work-finder evidence into one operator report. Every child proof command must keep RCH_REQUIRE_REMOTE=1 rch exec --, isolated CARGO_TARGET_DIR, nonzero test evidence, and no-local-fallback semantics. The bundle is not a performance benchmark, not a release publish proof, not a substitute for broad check/clippy/test gates, and not evidence for unrelated source surfaces.
The Third-Wave Swarm Guardrail E2E bundle is artifacts/third_wave_swarm_guardrail_e2e_contract_v1.json, emitted by scripts/third_wave_swarm_guardrail_e2e.py, assembled by scripts/run_third_wave_swarm_guardrail_e2e.sh, checked by tests/third_wave_swarm_guardrail_e2e_contract.rs, and documented in docs/third_wave_swarm_guardrail_e2e.md. It invokes child helpers for stale in-progress reaping, br/bv tracker graph drift, reservation lease watchdog coverage, swarm lane closeout, and RCH quiet-phase receipts against checked fixtures. It is not a broad workspace health proof, not a release publish proof, and not a substitute for broad check/clippy/test gates.
The third-wave operator runbook is docs/third_wave_swarm_operator_runbook.md, checked by tests/third_wave_swarm_operator_runbook_contract.rs. It gives the fail-closed signoff checklist for stale work reaping, br/bv drift, reservation renewal, RCH no-local-fallback validation, Agent Mail closeout, peer dirt handling, main push, and legacy mirror verification.
The admission-aware proof-lane atlas is anchored by artifacts/swarm_proof_lane_planner_contract_v1.json and checked by tests/swarm_proof_lane_planner_contract.rs. Its focused manifest lane is swarm-proof-lane-planner-contract, which proves planner fixtures, atlas decision receipts, deterministic JSON/Markdown report goldens, docs markers, manifest mapping, and proof-status claim rows without broad workspace, conformance, throughput, scheduler-performance, or all-target claims.
The migration readiness planner signoff is anchored by artifacts/migration_readiness_planner_signoff_v1.json and checked by the focused migration-readiness-planner-signoff-contract lane in tests/migration_readiness_planner_contract.rs. Its proof-status claim id is migration-readiness-planner-signoff; cite it only for the executable planner inventory, semantic map, operator report, fixture E2E, docs markers, child bead evidence, and validation-command closeout.
The runtime pressure-control evidence contract is artifacts/runtime_pressure_control_evidence_contract_v1.json, checked by tests/runtime_pressure_control_evidence_contract.rs. Its canonical lane is runtime-pressure-control-evidence-contract in the proof manifest. The operator handoff is docs/runtime_pressure_triage_runbook.md. That lane proves the pressure snapshot schema versions, region memory-budget pressure row schema, RCH proof-lane pressure row schema, no-local-RCH fallback evidence, operator diagnostics bundle, scheduler pressure flamegraph attribution, deterministic lab scenario families, docs markers, and operator scope limits stay aligned. It does not prove real-host throughput, performance improvement, scheduler regression closure, autonomous scheduler rewrites, production-on-by-default admission/backpressure, per-region allocator enforcement, RCH fleet availability, or a deadlock without explicit trapped-cycle proof. Production pressure signals are advisory unless paired with lab/replay evidence, a committed artifacts/flamegraphs/main-<bead-or-short-sha>.svg attribution artifact for triggered scheduler hot-path work, an RCH transcript or admission receipt that rules out local Cargo fallback for remote-required proof lanes, or a trapped-cycle proof, and adaptive controls remain opt-in until stronger evidence supports a wider rollout.
The memory-residency replay e2e contract is artifacts/memory_residency_replay_e2e_contract_v1.json, emitted by scripts/run_memory_residency_replay_e2e.sh, checked by tests/memory_residency_replay_e2e_contract.rs, and documented in docs/proof/memory_residency_replay_e2e.md. Its focused manifest lane is memory-residency-replay-e2e-contract; cite it only for the deterministic 64C/256G scenario matrix, e2e runner failure contract, manifest/status mapping, README/AGENTS markers, and no-claim boundaries. It includes no benchmark evidence and does not prove live host throughput, broad workspace health, release readiness, runtime correctness outside the memory-residency policy/accounting surfaces, p50, p95, p999, memory-use, or NUMA performance improvement.
The memory-residency operator safety contract is artifacts/memory_residency_operator_safety_contract_v1.json, checked by tests/memory_residency_operator_safety_contract.rs, and documented in docs/proof/memory_residency_operator_safety.md. Its focused manifest lane is memory-residency-operator-safety-contract; cite it only for enablement prerequisites, fail-closed M1-M4 safety gates, rollback guidance, Agent Mail handoff fields, closeout checklist, README/AGENTS markers, proof manifest/status rows, and no-claim boundaries. It does not prove release readiness, broad workspace health, allocator replacement, performance improvement, live RCH fleet availability, permission to delete files, or local Cargo fallback approval.
The clean-overlay proof orchestration contract is artifacts/clean_overlay_proof_orchestration_v1.json, checked by tests/clean_overlay_proof_orchestration_contract.rs, and documented in docs/clean_overlay_proof_orchestration_runbook.md. Its focused manifest lane is clean-overlay-proof-orchestration-contract; cite it only for shared-main operator-packet documentation and reference alignment — prerequisites, installed RCH clean-overlay capability evidence and fail-closed command admission, command examples, reservation expectations, RCH heartbeat-fresh/progress-stale cancellation guidance, peer-dirty and capability-drift blocker receipts, non-destructive cleanup/rollback, Agent Mail and br comment handoff templates, README/AGENTS markers, proof manifest/status rows, and no-claim boundaries. The referenced planner refuses enforced attempts while unselected peer dirt is present. No overlay command may be emitted unless captured rch exec --help evidence declares --base, --clean-overlay, --overlay-path, and --no-overlay; unsupported clients and blocked manifests emit only deterministic receipts. The A4 verifier does not prove behavioral correctness of those referenced A1-A3 surfaces; their focused tests are separate evidence. It does not prove release readiness, broad workspace health, performance improvement, live RCH fleet availability, permission to delete files, local Cargo fallback approval, or that peer dirt was excluded without supported installed capability evidence plus an admitted command and terminal execution evidence.
The proof-traffic final signoff is artifacts/proof_traffic_final_signoff_v1.json, checked by tests/proof_traffic_final_signoff_contract.rs, and documented in docs/proof_traffic_control.md. Its focused manifest lane is proof-traffic-final-signoff; cite it only for A1-A5 proof-traffic evidence aggregation, the capability-drift gate, admission receipt taxonomy, clean-overlay handshake, proof parking lot, blocked-loop e2e packet, proof manifest/status rows, README/AGENTS markers, no-local-fallback/no-peer-cancel policies, dependency-cycle receipt/checklist, and no-claim boundaries. It does not prove peer-dirt exclusion without supported capability evidence plus an admitted command and terminal execution evidence, release readiness, broad workspace health, runtime correctness, performance improvement, live RCH fleet availability, local Cargo fallback approval, permission to delete files, or permission to cancel peer builds.
The fourth-wave governor proof map is anchored by docs/fourth_wave_swarm_governor_runbook.md and checked by fourth-wave-governor-signoff-runbook in tests/fourth_wave_swarm_governor_runbook_contract.rs. The final aggregate signoff is artifacts/fourth_wave_governor_final_signoff_v1.json, checked by fourth-wave-governor-final-signoff in tests/fourth_wave_governor_final_signoff_contract.rs. The proof-status dashboard separates fourth-wave-governor-schema-contract, fourth-wave-governor-policy-engine, fourth-wave-swarm-replay-corpus, fourth-wave-runtime-bridge-contract, and the fourth-wave benchmark no-claim contract. The fourth-wave final aggregated signoff is a scoped executable operator report only: the benchmark contract records no fresh benchmark result and does not prove p95 improvement, throughput improvement, no regression, production-on-by-default control, broad workspace health, or RCH fleet availability.
One example: the cancellation/cleanup budget composes as a semiring-like object (componentwise min, with priority as max), which makes "who constrains whom?" algebraic instead of ad-hoc:
combine(b1, b2) =
deadline := min(b1.deadline, b2.deadline)
pollQuota := min(b1.pollQuota, b2.pollQuota)
costQuota := min(b1.costQuota, b2.costQuota)
priority := max(b1.priority, b2.priority)
This is the kind of structure that lets us reason about cancellation protocols and bounded cleanup with proof-friendly, compositional rules.
By default the scheduler uses a fixed cancel-streak limit of 16. With
RuntimeBuilder::enable_adaptive_cancel_streak(true), each worker runs a
deterministic discounted-UCB1 selector over {4, 8, 16, 32, 64} (starting at
16). Measured in one process against the fixed limit on two hosts
(2026-10-05), it did not beat it on cancel-heavy workloads and was 1-29% slower
on spawn+join, yield_now and channel round trips, which is why it is off by
default. At fixed epoch boundaries (128
dispatches by default), it discounts prior pull mass by 0.95, updates the
selected arm from a reward that blends Lyapunov decrease with deadline, fairness, and
fallback penalties, then chooses the next upper-confidence arm. An
anytime-valid e-process monitors the epoch rewards. The policy is a pure
function of the dispatch sequence (no RNG, no wall clock), so identical
schedules make identical choices; the golden
golden_test_lab_runtime_replay_determinism in
src/runtime/scheduler/three_lane_tests.rs replays it bit-exactly. The lab
runtime does not run this selector: LabRuntime uses a fixed cancel-streak
limit of 16, so a lab replay does not reproduce production arm choices.
This is a nonstationary stochastic-bandit controller, not an EXP3 adversarial no-regret claim. The separate ATP RaptorQ transport adapter has its own seeded, opt-in EXP3 controller; that mechanism is not the scheduler selector.
Cancellation drain progress is monitored over signed net-potential deltas. The runtime reports an Azuma baseline and an operational envelope that compares it with a range-only Freedman candidate:
P(S_t ≥ x and Q_t ≤ q) ≤ exp(-x² / (2(q + B x / 3)))
For t ≥ 1, c > 0, x > 0, and q ≥ 0, signed progress Y_i = -Δ_i gives cumulative centered shortfall S_t = Σ(E[Y_i | F_{i-1}] - Y_i) and predictable quadratic variation Q_t. The absolute signed step is bounded by c, and the centered upper increment is bounded by B = 2c. The implementation uses the outcome-independent cap Q_t ≤ t·c². With B = 2c, the resulting Freedman denominator is never smaller than Azuma's, so the selected envelope is always Azuma; the explicit raw candidate remains for auditability. A trace that exceeds the configured step range, or whose history is incomplete because an invalid sample was dropped, disables concentration claims for that verdict. At the current same-history horizon, the plug-in mean telescopes to zero deviation, so both public current-horizon candidates are the trivial bound 1.
Gross downward credit is retained for phase diagnostics only. Its accounted-potential total is pathwise nondecreasing, so the progress certificate does not use it for Ville or optional-stopping evidence. The projected confidence field is conditional on persistence of the empirical plug-in net-progress rate; it is not a proof of future drift.
The same monitor classifies operational drain regime (warmup, rapid_drain, slow_tail, stalled, quiescent) so operators can distinguish an observed slow tail from a configured stalled run. Its converging flag is an empirical status over the complete accepted finite non-negative observation history represented by running statistics. It is guarded by positive endpoint net progress, the stall rule, fixed rebound-count and rebound-magnitude limits, a non-increasing latest step, and the absence of dropped invalid samples; the conditional tails do not gate it. Incomplete telemetry fails actionable outputs closed to warmup, no remaining-step estimate, and disabled concentration.
Why it helps: shutdown and fail-fast behavior can be audited with explicit conditional confidence calculations and phase labels, instead of timeout heuristics alone.
Asupersync treats the task wait-for graph as a dynamic signal. The monitor tracks the Fiedler trajectory (algebraic connectivity), spectral gap/radius, and a nonparametric indicator stack (autocorrelation, variance ratio, flicker, skewness, Kendall tau, Spearman rho, Hoeffding's D, distance correlation), then calibrates forward risk with split conformal bounds and an anytime-valid deterioration e-process.
Status: implemented as an observability diagnostic over the live task wait graph. It is an early-warning signal, not a proof of trapped-cycle deadlock by itself.
Why it helps: structural degradation is detected before hard deadlock/disconnect events, with calibrated thresholds and continuously valid evidence rather than brittle one-off alarms.
The Lab runtime includes a DPOR-style schedule explorer (src/lab/explorer.rs) that treats executions as traces modulo commutation of independent events (Mazurkiewicz equivalence). Instead of a blind seed sweep, it tracks observed equivalence-class fingerprints and uses detected races to prioritize derived deterministic seeds. It does not restore an exact execution prefix and force an alternative enabled transition, so the observed class count is a campaign metric rather than a completeness guarantee.
Result: deterministic, replayable, race-informed schedule fuzzing with explicit coverage telemetry. It is useful bug-finding machinery, not certified DPOR coverage of every reachable equivalence class.
Oracles can run repeatedly during an execution without invalidating significance, using e-processes (src/lab/oracle/eprocess.rs). The key property is Ville's inequality (anytime validity):
P_H0(∃ t : E_t ≥ 1/α) ≤ α
So you can "peek" after every scheduling step and still control type-I error, which is exactly what you want in a deterministic scheduler + oracle setting.
LabRuntime feeds the monitor one observation per run that advances the lab (run_until_quiescent_with_report); a plain report() re-reads the same state and adds no evidence. The rejected invariants are available from runtime.oracles.eprocess_rejected_invariants().
What it does not add: each observation is the oracle's own pass/fail verdict for that run (EProcessMonitor::observe_report), and a lab run is deterministic. The e-process can therefore reject only an invariant whose oracle has already reported a violation. It summarizes the violation rate across runs and seeds with an anytime-valid bound. It does not detect anything the oracle verdicts miss.
For lab metrics that benefit from calibrated prediction sets, Asupersync uses split conformal calibration (src/lab/conformal.rs) with finite-sample, distribution-free guarantees (under exchangeability):
P(Y ∈ C(X)) ≥ 1 − α
The calibrator is opt-in: ScheduleExplorer::with_conformal_calibration feeds it every explored run's oracle report and conformal_anomaly_seeds() lists the seeds whose metrics fall outside the prediction set, even when no invariant failed. You can also feed it reports yourself (ConformalCalibrator::calibrate, then predict). No lab oracle consults it on its own, so no default verdict depends on it.
When a run violates an invariant (or conspicuously does not), Asupersync can produce a structured evidence ledger (src/lab/oracle/evidence.rs) using Bayes factors and log-likelihood contributions. This enables agent-friendly debugging: equations, substitutions, and one-line intuitions, so you can see exactly why the system believes "task leak" (or "clean close") is happening. Build one on request with EvidenceLedger::from_report(&report.oracle_report); no lab path emits it automatically.
Determinism is treated as a first-class algorithmic constraint across the codebase:
src/lab/virtual_time_wheel.rs) with explicit tie-breaking.src/distributed/consistent_hash.rs) for stable assignment without iteration-order landmines.src/lab/runtime.rs, src/trace/dpor)."Same seed, same behavior" holds end-to-end, not just for a demo scheduler.
| Feature | Asupersync | tokio | async-std | smol |
|---|---|---|---|---|
| Structured concurrency | ✅ Built in: every task belongs to a region | ⚠️ Opt-in (JoinSet, TaskTracker) | ❌ Manual | ❌ Manual |
| Cancellation | ⚠️ Request → drain → finalize on covered surfaces; a cancelled task can finish async cleanup and return a value | ⚠️ Drop-based; CancellationToken for cooperative cancellation | ⚠️ Drop-based | ⚠️ Drop-based |
| No orphan tasks | ✅ For Cx spawns; RuntimeHandle spawns belong to the root region | ❌ spawn detaches (JoinSet aborts on drop) | ❌ spawn detaches | ❌ spawn detaches |
| Bounded cleanup | ⚠️ Advisory budgets; a non-cooperative task holds up region close | ❌ Best-effort | ❌ Best-effort | ❌ Best-effort |
| Deterministic testing | ✅ Built-in lab runtime | ⚠️ Paused time; schedule exploration via external tools (loom, turmoil) | ❌ External tools | ❌ External tools |
| Obligation tracking | ✅ Runtime-tracked permits and leases with leak detection | ❌ None | ❌ None | ❌ None |
| Per-task cost | ⚠️ Several times tokio's (see Measured against tokio) | ✅ The reference point | — | — |
| Ecosystem | ✅ Broad support-class-scoped built-in surface (runtime, net, HTTP/1.1+H2, TLS, WebSocket, gRPC, DB, distributed primitives; adapter lanes stay explicitly bounded) | ✅ Largest; most async crates assume it | ⚠️ Medium | ⚠️ Small |
| Maturity | ⚠️ Experimental, pre-1.0; used in production by the author's own projects, no known independent production user | ✅ Production | ✅ Production | ✅ Production |
When to evaluate Asupersync:
When to consider alternatives:
The table above compares runtimes. This section compares ecosystem surface area. It maps common Tokio ecosystem crates to the corresponding Asupersync modules.
| Ecosystem Area | Typical Tokio Crates | Asupersync Surface | Parity status | Maturity | Determinism | Interop friction |
|---|---|---|---|---|---|---|
| Core runtime + task execution | tokio | src/runtime/, src/cx/, src/record/ | Built-in | Mature | Lab-strong | High |
| Structured concurrency + cancellation protocol | usually ad hoc on Tokio | Built into Cx, regions, obligations (src/cx/, src/cancel/, src/obligation/) | Built-in | Mature | Strong | High |
| Channels | tokio::sync::{mpsc, oneshot, broadcast, watch} | src/channel/{mpsc,oneshot,broadcast,watch}.rs | Built-in | Mature | Lab-strong | Medium |
| Sync primitives | tokio::sync::{Mutex,RwLock,Semaphore,Notify,Barrier,OnceCell} | src/sync/ | Built-in | Mature | Lab-strong | Medium |
| Time and timers | tokio::time | src/time/, src/runtime/timer*, src/lab/virtual_time_wheel.rs | Built-in | Mature | Lab-strong | Medium |
| Async I/O traits and extensions | tokio::io, tokio-util::io | src/io/ | Built-in | Active | Mixed | Medium |
| Codec/framing layer | tokio-util::codec | src/codec/ | Built-in | Active | Mixed | Medium |
| Byte buffers | bytes | src/bytes/ | Built-in | Mature | N/A | Low |
| Reactor backends | Tokio + Mio internals | src/runtime/reactor/{epoll,kqueue,windows,browser,lab}.rs (+ io_uring feature on Linux) | Built-in | Active | Mixed | Medium |
| TCP/UDP/Unix sockets | tokio::net | src/net/tcp/, src/net/udp.rs, src/net/unix/ | Built-in | Active | Mixed | Medium |
| DNS resolution | trust-dns, hickory, custom stacks | src/net/dns/ | Built-in | Active | Mixed | Medium |
| TLS | tokio-rustls, native-tls | src/tls/ (tls, tls-native-roots, tls-webpki-roots) | Feature-gated | Active | Mixed | Medium |
| WebSocket | tokio-tungstenite | src/net/websocket/ | Built-in | Active (broad RFC6455 conformance registry wired; runtime e2e coverage remains lane-specific) | Mixed | Medium |
| HTTP stack (HTTP/1.1 + HTTP/2) | hyper, h2, http-body, hyper-util | src/http/h1/, src/http/h2/, src/http/body.rs, src/http/pool.rs | Built-in | Active | Mixed | Medium |
| QUIC + HTTP/3 (default static-only QPACK; opt-in dynamic QPACK field-section and instruction-stream state machine) | quinn, h3, h3-quinn | src/net/quic_core/, src/net/quic_native/, src/http/h3_native.rs, src/http/h3_quic.rs (the http3 feature includes an established-connection adapter that maps SETTINGS, requests, informational/final responses, DATA, trailers, GOAWAY, cancellation, FIN, and reset semantics onto native QUIC stream bytes. A caller-driven single-connection owner now composes the real UDP endpoint, rustls QUIC handshake, WebPKI identity verification, authenticated handshake CIDs, negotiated ALPN, handshake-derived 1-RTT protection, bounded I/O/timer driving, NativeH3Session, and NativeH3Router; a no-mock loopback test carries an exact Router request/response through that path. Historical wrapper sources in src/net/quic/ remain parked outside the core feature graph (the former src/http/h3/ directory no longer exists); support matrix: artifacts/http3_qpack_support_matrix_v1.json. SECURITY (asupersync-7pwwwe, fixed fail-closed; asupersync-arq-quic-epic-b0k8qo.7.4): untrusted-root, wrong-hostname, expired-certificate, unverified-identity, non-H3 ALPN, and pre-I/O cancellation paths fail closed; there is no insecure skip-verify default. Native ATP-over-QUIC control frames and the transfer manifest ride the verified handshake-derived 1-RTT STREAM path; direct single-connection RaptorQ symbols ride verified 1-RTT DATAGRAM packets and rely on QUIC AEAD, while non-direct symbol planes retain explicit per-symbol auth. This row is still not a release-readiness, multi-connection listener/deployment, external-interoperability, migration, 0-RTT, WAN, or fleet-performance claim; see docs/quic_atp_threat_model.md for the precise ATP scope.) | Feature-gated | Active transport/QPACK surfaces plus authenticated single-connection H3-over-real-UDP composition; multi-connection deployment and external interop remain unproven | Mixed | Medium |
| Web framework primitives (router/extractors/local middleware/request-region/SSE helpers; not axum/warp parity) | axum, warp, tower-http | src/web/, src/service/, src/server/ | Partial native primitives | Active (bounded) | Mixed | Medium |
| gRPC | tonic + prost + tower + hyper | src/grpc/ | Built-in | Active | Mixed | Medium |
| Database clients | tokio-postgres, mysql_async, sqlx | src/database/{postgres,mysql,sqlite}.rs | Feature-gated | Active | Mixed | Medium |
| Messaging clients | async Redis/NATS/Kafka crates | src/messaging/{redis,nats,kafka}.rs | In progress | Early | Mixed | Medium |
| Service/middleware stack | tower, tower-layer, tower-service | src/service/ + optional tower adapter feature | Built-in | Active | Lab-strong | Low |
| Filesystem APIs | tokio::fs | src/fs/ | Partial blocking-backed facade; not full tokio::fs parity | Early | Mixed | Medium |
| Process management | tokio::process | src/process.rs | Built-in | Active | Mixed | Medium |
| Signals | tokio::signal | src/signal/ | Built-in | Active | Mixed | Medium |
| Streams and adapters | tokio-stream, futures-util::stream | src/stream/ | Built-in | Active | Lab-strong | Low |
| Observability | tracing, metrics, opentelemetry | src/observability/, src/tracing_compat.rs | Built-in + feature-gated integrations | Active | Mixed | Low |
| Deterministic concurrency testing | loom, tokio-test, external harnesses | src/lab/, frankenlab/, optional loom-tests feature | Built-in | Mature | Strong | Low |
| Tokio-locked third-party crates | crates that require Tokio runtime traits directly | boundary adapters via service/runtime integration points | Adapter needed | N/A | N/A | High |
This map is about capability coverage, not API compatibility. Asupersync intentionally uses a different model centered on Cx, regions, explicit cancellation, and deterministic replay.
Web framework status is deliberately bounded. src/web/ contains a lightweight
router, typed extractors, response conversion, local Handler middleware
wrappers, request-region helpers, health/static/multipart/session/security
utilities, and bounded Sse / StreamingSse surfaces. With http3 enabled,
Router::into_native_h3_router also supplies a caller-driven bridge for an
already-established NativeH3Session: it assembles bounded request bodies,
detaches caller-scoped handler dispatch only after FIN so other streams remain
drivable, caps both incomplete requests and in-flight dispatches, preserves
request/response stream identity, and resets malformed, unsupported, or
cancelled request streams without taking down the connection. The caller still
owns the explicit drive loop and dispatch-scope orchestration; the feature-gated
NativeQuicUdpConnection owns the single live UDP socket, completed TLS/ALPN
state, authenticated connection IDs, 1-RTT protection, and bounded I/O/timer
operations. With both http3 and tls,
NativeH3Listener owns that drive loop for
multiple authenticated peers on a freshly bound UDP socket. Its bind method
takes a runtime-owned Cx, address, Router, rustls server configuration
advertising h3, encoded QUIC transport parameters, and
NativeH3ListenerConfig; local_addr exposes the bound address, and
serve_with_shutdown runs the service through graceful shutdown. Configuration
bounds concurrent handshakes, connections, request regions, body buffering,
per-poll application work, request deadlines, and shutdown grace. Buffered
responses and Http3StreamResponder producers retain a real request task and
its spawn gateway through transport completion. Request timeout/reset cancels
that request, and awaited service exit joins admitted request regions and
checks their cleanup outcomes.
The native H3 listener also has an opt-in live request-body path:
let mut config = NativeH3ListenerConfig::default();
config.streaming_request_body_buffer_bytes = std::num::NonZeroUsize::new(64 * 1024);
With http3,tls enabled, this path resolves the static route/body policy and
validates declared lengths at HEADERS, before admitting a request region. Its
actual request task creates a bounded StreamingRawBody with that task's
Cx, so handlers can consume DATA before peer FIN. Queue pressure pauses
the affected request stream; consumer progress wakes the connection driver
without requiring another peer packet. Each request reserves its queue capacity
plus one bounded pending frame against the connection aggregate, and retains
that charge through request-region closure. The existing
router.max_buffered_body_bytes remains a total body-size ceiling, tightened
by the resolved Router policy.
Framed input reaches EOF only after actual protocol FIN, including bodies with
Content-Length zero or already-consumed declared lengths. Length mismatches
reset the request with H3_MESSAGE_ERROR; FIN inside a frame closes the
connection with H3_FRAME_ERROR. Early body abandonment stops input with
H3_NO_ERROR while allowing the response to finish, including when the peer
acknowledges that input stop with RESET_STREAM. A final request trailer section
is delivered through the same body queue and remains distinct from EOF. Its
internal queue accounting (name bytes + value bytes + four bytes per field)
must fit in min(queue bytes, 16 KiB), checked before constructing the
handler-side trailer map. This bound is separate from the existing native
QPACK decoding and QUIC reassembly limits. Oversized trailer metadata cancels
the request; forbidden trailer fields fail with H3_MESSAGE_ERROR. Handlers
on this opt-in path use StreamingRawBody or the async body collectors;
synchronous buffered extractors fail closed. The default None keeps
buffered request dispatch.
The live multi-peer, stalled-response, and receive-credit regressions are in
tests/quic_h3_live_udp.rs; the streaming request journeys are in
tests/quic_h3_listener_streaming.rs. Both compile and pass natively with
--features http3,tls (2026-10-04, 2780d3454): 21 of 21 streaming journeys,
and 16 live-UDP tests with 3 ignored. Two of the ignored tests are subprocess
roles that their parent tests launch. The third, kernel EAGAIN
backpressure, needs isolated Linux network namespaces and did not run.
Router::into_http1_streaming_handler bridges validated H1 heads
and a bounded live StreamingRawBody; buffered JSON/form collectors can consume
that body asynchronously. The H1 and H2 produced-handler adapters expose
bounded Http1StreamResponder / Http2StreamResponder response producers with
transport-owned backpressure and terminalization. The ordinary H2 request
adapters buffer before dispatch. The opt-in H2 ingress below supplies live
request bodies with buffered responses. The standalone H3 Router bridge also
assembles bounded request bodies before dispatch; the native H3 listener's
opt-in path delivers them incrementally. General full-duplex request/response
progress and external interoperability remain unverified. The native H3 path
also does not claim CONNECT, server push, or deployment readiness. WebSocket
upgrade authoring is provided separately
by web::websocket::WebSocketUpgrade. The SSE lane is proof-backed:
Sse finite bounded batch responses, plus a StreamingSse pull API carrying a
request-region E2E proof and an HTTP/1 transport drain proof
(tests/e2e_web.rs streaming artifact rows). It is not an
axum/warp/tower-http-compatible framework: handlers operate on Asupersync's
lightweight Request / Response types, middleware wraps the local Handler
trait rather than Tower layers, async handlers use explicit Cx-aware wrappers,
and protocol-specific ingress/egress limits remain explicit. Treat this as
native web primitives on top of the HTTP and service modules, not framework
parity.
With the opt-in http2-streaming Cargo feature, the native HTTP/2 listener
supports live uploads with
Http2Listener::bind_streaming_with_config and run_streaming.
Router::into_http2_streaming_parts binds the same router to HEADERS-time
static body-policy admission and to request dispatch:
use asupersync::http::h1::server::HostPolicy;
use asupersync::http::h2::listener::{Http2Listener, Http2StreamingListenerConfig};
// `router` has handlers that consume StreamingRawBody or async body collectors.
let mut config = Http2StreamingListenerConfig::default();
config.listener.allowed_hosts = HostPolicy::AllowList(vec!["localhost".to_string()]);
let (handler, config) = router.into_http2_streaming_parts(config);
let listener = Http2Listener::bind_streaming_with_config(
"127.0.0.1:8080", handler, config,
).await?;
listener.run_streaming(&runtime_handle).await?;
This path validates the request head and declared length before admitting a
request region. The body channel is created by the actual request task.
Stream WINDOW_UPDATE credit follows DATA delivered to that body consumer;
connection credit continues independently so a stalled upload leaves other
streams and control frames drivable. Padding is accounted on the wire and
credited internally, without being counted as application DATA. The listener
reserves bounded queue and pending-input capacity against a connection budget,
including the initial 65,535-byte receive allowance. The opt-in profile requires
an initial stream window of at least 65,535 bytes. listener.max_body_size
remains a separate whole-upload ceiling, tightened by static route policy and
then by request-local policy. H2 request trailers terminate input with
END_STREAM; merely reaching Content-Length does not terminate a live body.
The lower-level Connection::defer_stream_receive_window and
release_stream_receive_capacity APIs expose the same consumption-based flow
control to custom H2 drivers. Existing callers retain automatic replenishment.
The original exhaustive Http2ListenerConfig remains compatible;
Http2StreamingListenerConfig is a separate opt-in wrapper. The native TCP
integration target tests/http2_listener_streaming.rs covers live upload
progress, receive-credit exhaustion, trailers, admission budgets, body errors,
and request cleanup on current-thread and multithread runtimes. Run it with:
cargo test -p asupersync --features http2-streaming --test http2_listener_streaming
It compiles and passes natively: 17 of 17 tests (2026-10-04, 2780d3454).
Sixteen of them run on both a current-thread runtime and a two-worker
multi-thread runtime with sharded state. The feature stays opt-in and outside
the default build. The buffered and produced-response APIs are unchanged.
Filesystem status is deliberately conservative. src/fs/ currently exposes
File, buffered readers/writers, metadata, directory/path helpers,
try_exists, write_atomic, UnixVfs, and platform capability reports that
ATP consumes through src/atp/platform/. Most operations are async facades over
spawn_blocking_io; the poll-based File traits offload each bounded syscall
through the same blocking pool (and degrade to inline calls only on a runtime
built without a pool),
recursive directory removal and large copy operations inherit standard-library
partial-state semantics, and Linux io_uring support is limited to
feature-gated helper paths. Treat this as an early blocking-backed filesystem
layer, not comprehensive tokio::fs parity or a fully region-native filesystem
driver. The crash-safe ATP disk writer, platform doctor, sparse-write, journal,
resume, and verifier work remains tracked by the ATP-D beads.
The broader host-support policy is captured by the checked
Platform Capability Matrix, which
keeps supported, feature-gated, partial, unsupported, and not-applicable rows
separate so skipped or unsupported surfaces are never counted as green support
evidence.
If you do need Tokio-locked dependencies at the boundary, use the migration
playbook in docs/integration.md.
That guide maps the live asupersync-tokio-compat entrypoints to common
stacks: hyper/reqwest/tonic transport, tower/axum middleware, and narrower
Tokio runtime-context or I/O shims. The intended order is native Asupersync
first, compat adapters only where a third-party crate still requires Tokio
traits.
Start brownfield work with the read-only migration readiness planner in
docs/integration.md:
python3 scripts/migration_readiness_planner.py --project-root /path/to/rust/project --output-root target/migration-readiness
For deterministic examples, list and execute the repo-local fixtures:
python3 scripts/migration_readiness_planner.py --list
python3 scripts/migration_readiness_planner.py --execute --output-root "${TMPDIR:-/tmp}/asupersync_migration_planner_e2e"
The report links summary.final_verdict, proof_pack.proof_commands,
semantic_map.recommendations, and operator_report.phase_plan back to the
playbook vocabulary before any target project code is edited.
The reactor export contract is narrower than the directory listing suggests: runtime::reactor exports EpollReactor on Linux, IoUringReactor on Linux only (real with io-uring, intentional Unsupported without it), KqueueReactor on BSD-family targets, IocpReactor on Windows, BrowserReactor on wasm32, and LabReactor for deterministic testing. Historical files such as src/runtime/reactor/uring.rs and src/runtime/reactor/macos.rs are not part of the live export graph.
Interest-flag parity is also narrower than the shared Interest bitflag type suggests: Linux EpollReactor supports the full shipped readiness/mode surface used by the native runtime, KqueueReactor rejects Interest::DISPATCH and Interest::PRIORITY, and IocpReactor currently accepts only READABLE / WRITABLE. Treat Linux epoll plus optional io_uring as the primary production path, with BSD and Windows reactors available but intentionally narrower today.
# Add to Cargo.toml
cargo add asupersync --git https://github.com/Dicklesworthstone/asupersync
# Or manually add:
# [dependencies]
# asupersync = { git = "https://github.com/Dicklesworthstone/asupersync" }
git clone https://github.com/Dicklesworthstone/asupersync.git
cd asupersync
rch exec -- env CARGO_TARGET_DIR=${TMPDIR:-/tmp}/rch_target_readme_docs cargo build --release
Release archives and SHA256SUMS.txt have detached Minisign signatures. After
downloading an archive and its .minisig file, verify it with the established
release public key:
minisign -Vm asupersync-linux-amd64.tar.gz -p release/keys/asupersync.pub
Asupersync uses Rust Edition 2024 and builds on stable Rust with its
default features. The one nightly-only piece is ? on Outcome, from the
default nightly-outcome-try feature. The build script probes the compiler.
On nightly, the feature works as it always has. On stable or beta, it is
inactive: the crate builds without the Try impls, and Cargo prints a warning
for local builds. Contributor and release lanes track the pinned nightly
toolchain in rust-toolchain.toml, so the crate's own tests and examples keep
? on Outcome.
The stable lane checks the default features and the minimal subset (default
features disabled, proc-macros enabled) on Rust 1.95.0. That is the oldest
stable compiler the dependency graph accepts today (sysinfo 0.39 requires
1.95):
bash scripts/run_stable_lane_e2e.sh
That runner drives cargo +1.95.0 check (default features and the minimal
subset), clippy, and the focused Outcome unit tests through RCH with the
shared stable-lane target directory. Set STABLE_RUST_TOOLCHAIN to check
another stable release.
Asupersync's repository Cargo.lock governs this workspace; it does not pin a
downstream consumer's resolution. Default-feature consumers on stable Rust
need 1.95 or newer, the floor that today's dependency graph sets. Consumers who
want ? on Outcome should use the contributor/release nightly pin,
nightly-2026-08-31, from rust-toolchain.toml; another nightly works only if
its Try traits still match. Cargo.toml does not declare rust-version, so
1.95 is the lane's checked floor, not a promised lower bound.
Updated entry macros also support older 0.4.x runtimes. When the runtime
lacks Runtime::drain_root_region, omitting drain_ms preserves its legacy
teardown. An explicit positive drain_ms requires that runtime API.
The standalone downstream fixture now commits its own direct-minimal lock. The
pinned-nightly downstream-consumer-direct-minimal-check lane verifies that
lock against the default public consumer. Full transitive-minimal resolution is
not claimed: its current fail-closed probe selects curve25519-dalek 4.0.0
through nkeys / ed25519-dalek, which fails on the pinned nightly because it
requests the removed stdsimd feature. That precise blocker is recorded in the
downstream consumer artifact
rather than hidden behind an unused production constraint dependency.
Applications should commit and enforce their own lockfile. Vendoring is an optional source-availability control that must be maintained together with that lockfile and the generated source configuration; it does not replace advisory, license, publisher/source, build-script, or feature/target review. See the dependency supply-chain policy for the exact evidence boundary and the links to the dependency budget and consumer-profile contracts.
pub enum Outcome<T, E> {
Ok(T), // Success
Err(E), // Application error
Cancelled(CancelReason), // External cancellation
Panicked(PanicPayload), // Task panicked
}
// Severity lattice: Ok < Err < Cancelled < Panicked
// HTTP mapping: Ok→200, Err→4xx/5xx, Cancelled→499, Panicked→500
pub struct Budget {
pub deadline: Option<Time>, // Absolute deadline
pub poll_quota: u32, // Max poll calls
pub cost_quota: Option<u64>, // Abstract cost units
pub priority: u8, // Scheduling priority (0-255)
}
// Semiring: meet(a, b) = tighter constraint wins
let effective = outer_budget.meet(inner_budget);
pub enum CancelKind {
User, // Explicit cancellation
Timeout, // Timeout exceeded
Deadline, // Deadline passed
PollQuota, // Poll budget exhausted
CostBudget, // Cost budget exhausted
FailFast, // Sibling failed
RaceLost, // Lost a race
ParentCancelled, // Parent region cancelled
ResourceUnavailable, // A required resource is unavailable
Shutdown, // Runtime shutdown
LinkedExit, // A linked task exited
}
// Severity (CancelKind::severity):
// User < Timeout = Deadline < PollQuota = CostBudget
// < FailFast = RaceLost = LinkedExit < ParentCancelled = ResourceUnavailable < Shutdown
// Cleanup budgets scale inversely with severity
pub struct Cx { /* ... */ }
impl Cx {
pub fn spawn<F, Fut>(&self, f: F) -> Result<TaskHandle<Fut::Output>, SpawnError>;
pub fn spawn_in<F, Fut, P>(&self, scope: &Scope<'_, P>, f: F)
-> Result<TaskHandle<Fut::Output>, SpawnError>;
pub fn checkpoint(&self) -> Result<(), Error>; // Err once cancellation is requested
pub fn masked<F, R>(&self, f: F) -> R; // Run a synchronous closure with cancellation deferred
pub fn trace(&self, message: &str);
pub fn budget(&self) -> Budget;
pub fn is_cancel_requested(&self) -> bool;
}
┌─────────────────────────────────────────────────────────────────────────────┐
│ EXECUTION TIERS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ FIBERS │ │ TASKS │ │ ACTORS │ │ REMOTE │ │
│ │ │ │ │ │ │ │ │ │
│ │• Borrow-safe │ │• Parallel │ │• Long-lived │ │• Named compute│ │
│ │• Same-thread │ │• Send │ │• Supervised │ │• Leases │ │
│ │• Region-pinned│ │• Work-stealing│ │• Region-owned │ │• Idempotent │ │
│ │• Cancel-safe │ │• Region-heap │ │• Mailbox │ │• Saga cleanup │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │ │ │ │ │
│ └──────────────────┴────────┬─────────┴──────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ REGION TREE │ │
│ │ │ │
│ │ Root Region ──┬── Child Region ──┬── Task │ │
│ │ │ ├── Task │ │
│ │ │ └── Subregion ── Task │ │
│ │ └── Child Region ── Actor │ │
│ │ │ │
│ │ Invariant: close(region) → quiescence(all descendants) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ OBLIGATION REGISTRY │ │
│ │ │ │
│ │ SendPermit ──→ send() or abort() │ │
│ │ Ack ──→ commit() or nack() │ │
│ │ Lease ──→ renew() or expire() │ │
│ │ │ │
│ │ Invariant: region_close requires all obligations resolved │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ SCHEDULER │ │
│ │ │ │
│ │ Cancel Lane ──→ Timed Lane (EDF) ──→ Ready Lane │ │
│ │ ↑ │ │
│ │ (priority) Lyapunov-guided: V(Σ) must decrease │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
The workspace denies unsafe code by default. Required exceptions are tracked in
artifacts/unsafe_boundary_ledger_v1.json, with reviewer guidance in
docs/unsafe_boundary_ledger.md. The ledger is the canonical unsafe-boundary
inventory for auditors: each row names the source path, category,
category-specific evidence, safety invariant, and explicit no-claim boundary.
The focused unsafe-boundary-ledger-contract lane checks that the ledger still
matches live unsafe source locators and that proof manifest/status wiring stays
aligned. Passing that lane does not prove unsafe correctness, execute every
platform-specific FFI path, or replace category evidence; it only proves the
inventory and review-policy metadata are coherent.
| Lane | Purpose | Priority |
|---|---|---|
| Cancel Lane | Tasks in cancellation states | 200-255 (highest) |
| Timed Lane | Deadline-driven tasks (EDF) | Based on deadline |
| Ready Lane | Normal runnable tasks | Default priority |
Scheduler behavior is intentionally explicit:
cancel_streak_limit=16, ready or timed work gets a dispatch slot within limit + 1 steps per worker (src/runtime/scheduler/three_lane.rs).DrainObligations and DrainRegions, the effective bound is temporarily widened to 2 * cancel_streak_limit to finish cleanup without starving everything else (src/runtime/scheduler/three_lane.rs).fairness_yields, max_cancel_streak) so starvation claims can be checked against runtime counters, not guesses (src/runtime/scheduler/three_lane.rs).try_local_any_lane and pop_any_lane_with_hint) to reduce lock traffic on the hot path while keeping lane ordering rules intact (src/runtime/scheduler/three_lane.rs).governor_interval, default 32) (src/runtime/config.rs, src/runtime/builder.rs, src/runtime/scheduler/three_lane.rs).{4, 8, 16, 32, 64} at fixed epoch boundaries using reward signals that blend Lyapunov decrease, fairness pressure, deadline pressure, and fallback pressure (src/runtime/scheduler/three_lane.rs, src/runtime/config.rs, src/runtime/builder.rs).healthy, congested, unstable, and partitioned runtime states (src/runtime/scheduler/decision_contract.rs, src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).!Send tasks are pinned to owner workers and routed through non-stealable queues; steal paths explicitly reject moving them across workers (src/runtime/scheduler/three_lane.rs, src/runtime/scheduler/local_queue.rs).src/runtime/scheduler/local_queue.rs).Parker and explicit queue rechecks after wakeups, which closes lost-wakeup races between work injection and parking (src/runtime/scheduler/worker.rs, src/runtime/scheduler/three_lane.rs).Runtime state can be split into independently locked shards, so hot-path polling can proceed without serializing every region or obligation mutation. This is opt-in (RuntimeBuilder::with_sharded_state(true)); the default keeps the state behind one lock.
tasks): task table, stored futures, intrusive queue links.regions): region ownership tree and state transitions.obligations): permit/ack/lease lifecycle and leak tracking.instrumentation): trace and metrics surfaces.config): immutable runtime config.Multi-shard operations take shard locks in the canonical order E -> D -> B -> A -> C to prevent deadlocks. ShardGuard (src/runtime/sharded_state.rs) checks that order in debug builds, but only tests use it today; the sharded runtime paths lock shards directly, so in production the order is a convention, not a checked one. Shard locks are ContendedMutex instances, and optional lock-metrics instrumentation can measure wait/hold behavior (src/sync/contended_mutex.rs).
Region memory uses stable handles (HeapIndex) with slot index, generation, and type tag metadata instead of exposing raw allocation addresses.
src/runtime/region_heap.rs).src/runtime/region_heap.rs).src/runtime/region_heap.rs).RRef handles cannot be minted (asupersync-bi2462.39 tracks safe opt-in placement).Asupersync exposes runtime controls that are usually hidden behind ad hoc instrumentation. These controls are wired into scheduler and trace behavior directly.
| Control | API | Runtime Behavior |
|---|---|---|
| Logical clock mode | RuntimeBuilder::logical_clock_mode(...) | Select Lamport, Vector, or Hybrid logical clocks for causal ordering; defaults are chosen from runtime context and carried into event timelines (src/runtime/config.rs, src/trace/distributed/vclock.rs, src/runtime/state.rs) |
| Cancel attribution bounds | RuntimeBuilder::cancel_attribution_config(...) | Bound cancellation cause-chain depth and memory while preserving root-cause lineage and explicit truncation metadata when limits are hit (src/types/cancel.rs, src/runtime/state.rs) |
| Cancel reason on errors | Error::cancel_reason() | The error from cx.checkpoint() (and Error::cancelled) carries the structured CancelReason: kind, origin and cause chain. A joiner that only sees the task's Ok(Err(error)) can still tell why it was cancelled (src/error.rs) |
| Deadline monitor | RuntimeBuilder::deadline_monitoring(...) | Run a background monitor with configurable check cadence, warning thresholds, adaptive history percentiles, and custom warning callbacks (src/runtime/deadline_monitor.rs, src/runtime/builder.rs) |
src/runtime/deadline_monitor.rs).src/runtime/deadline_monitor.rs).src/runtime/deadline_monitor.rs).Asupersync does more work per task than tokio. Every task gets a region
membership, a cancellation state machine and a terminal-result channel, and
two-phase permits are tracked as obligations. That bookkeeping costs time.
These numbers come from one process running both runtimes. The build was a
release build with default features. The date was 2026-10-08, and the source
was that of commit 791a2e356. The same probe ran on three RCH workers: a
16-CPU host, a 10-CPU host shared with other builds at the time, and a busy
64-CPU host. Each figure is p50 per operation at n = 1,000. The ranges span
the three hosts, so shared-host noise is part of the range: the widest row
(spawn + join from a task) was 14× on the 16-CPU host.
| Operation | Asupersync | tokio | Ratio |
|---|---|---|---|
| spawn + join from a task, 4 workers | 4.4–10.7 µs | 0.30–0.74 µs | 12–23× |
spawn + join from block_on, current-thread | 2.6–5.5 µs | 0.22–0.58 µs | 7.7–12× |
yield_now, 4 workers | 0.37–0.61 µs | 0.25–0.38 µs | 1.5–2.0× |
yield_now, current-thread | 0.30–0.60 µs | 0.09–0.15 µs | 3.4–4.0× |
| mpsc ping-pong round trip, 4 workers | 1.37–2.13 µs | 0.20–0.48 µs | 4.5–7.0× |
| mpsc ping-pong round trip, current-thread | 1.29–2.14 µs | 0.17–0.31 µs | 6.8–7.5× |
fan-out child: fiber::scope vs tokio spawn + join, current-thread | 0.27–0.69 µs | 0.22–0.58 µs | 1.0–1.5× |
fan-out child: fiber::scope vs tokio spawn + join, 4 workers | 0.27–0.51 µs | 0.30–0.74 µs | 0.7–1.1× |
Server-shaped rows, also from one process. The TCP rows come from the 16- and 10-CPU hosts and another busy 64-CPU host; each loopback connection makes 200 round trips of a 64-byte message. The HTTP/1.1 rows come from that 64-CPU host, with 200 keep-alive requests per connection. The last column is tokio's throughput over asupersync's:
| Workload | Asupersync | tokio | tokio is faster by |
|---|---|---|---|
| TCP request/response, 1 connection | 29–42 K round trips/s | 44–67 K | 1.5–1.6× |
| TCP request/response, 64 connections | 65–161 K round trips/s | 91–187 K | 1.2–1.6× |
HTTP/1.1 keep-alive GET, 1 connection (one 64-CPU host; vs hyper 1.x) | 21 K requests/s | 42 K | 2.0× |
HTTP/1.1 keep-alive GET, 64 connections (same host; vs hyper 1.x) | 65 K requests/s | 122 K | 1.9× |
Reading the tables:
fiber::scope. It costs about
as much as a tokio task (0.7–1.5× across the three hosts), but fibers run
concurrently on one thread, not in parallel. Tokio's own in-task equivalent
is futures::stream::FuturesUnordered.These numbers already include the October 2026 cuts:
mpsc::send, which made ping-pong 2.7–4.1× faster;The remaining work items are listed under asupersync-issue65-criticisms-kpmoy5.1.
To reproduce, run benches/runtime_vs_tokio.rs, which puts tokio and asupersync
side by side in the same Criterion groups:
cargo bench -p asupersync --bench runtime_vs_tokio --features criterion-benches -- --noplot
The in-repo bench builds asupersync with the test-only features that the
conformance dev-dependency enables. For default-feature numbers like the
table above, build the same code in a separate crate that depends on
asupersync normally.
The method stayed consistent across many small, verified runtime changes: profile the hot paths, remove one source of contention or allocation at a time, then keep cancellation and determinism guarantees intact.
src/runtime/scheduler/three_lane.rs).TaskTable, so push/pop/steal paths avoid full runtime-state lock pressure (src/runtime/task_table.rs, src/runtime/scheduler/local_queue.rs, src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).wake_state.notify() with an explicit Idle -> Polling -> Notified state machine, so wakes that arrive during poll are coalesced once instead of double-enqueueing (src/record/task.rs, src/runtime/scheduler/three_lane.rs, src/runtime/scheduler/worker.rs).Waker::will_wake guards to skip redundant clones and refresh only when the executor context actually changes (src/transport/sink.rs, src/transport/mock.rs).src/runtime/scheduler/worker.rs, src/runtime/scheduler/three_lane.rs, src/transport/sink.rs).Vec usage toward SmallVec and pre-sized structures (src/runtime/scheduler/three_lane.rs, src/transport/router.rs, src/transport/aggregator.rs).TaskRecord with queue-tag membership checks, so owner pop and thief steal stay O(1) without per-operation node allocation (src/runtime/scheduler/intrusive.rs, src/runtime/scheduler/local_queue.rs).parking_lot primitives where it improves lock-path cost (src/runtime/*, src/transport/*, src/lab/*).src/runtime/scheduler/global_injector.rs).SmallVec to keep the common path allocation-free (src/runtime/scheduler/local_queue.rs, src/runtime/scheduler/intrusive.rs).src/runtime/scheduler/three_lane.rs, src/runtime/config.rs).src/runtime/io_driver.rs, src/runtime/reactor/*).RuntimeBuilder::with_timer_driver(TimerDriverHandle::with_wall_clock_coalescing(..)), and a coalesced timer fires at the first window boundary at or after its deadline, never before it (src/time/wheel.rs, src/time/driver.rs).Outcome::Panicked, dependents/finalizers are still driven, and one bad task does not take down a worker lane (src/runtime/scheduler/three_lane.rs, src/runtime/builder.rs).BTreeMap/BinaryHeap comparisons; the documented 10K corpus (release-perf profile, 2026-06-01) records a ~27x cancel-path advantage over BTreeMap, and the wheel now also wins the mixed insert/cancel/expire workload outright (benches/timer_wheel.rs).src/runtime/region_heap.rs).benches/scheduler_benchmark.rs, benches/reactor_benchmark.rs, benches/timer_wheel.rs, benches/cancel_drain_bench.rs, benches/tracing_overhead.rs).Asupersync ships a structured networking stack from raw sockets through application protocols. Runtime-owned endpoints participate in structured concurrency, readiness/registration cleanup is explicit, and the lab runtime can substitute virtual TCP for deterministic network testing. Cancel-safety is operation-specific: atomic datagram sends and covered two-phase/adapter surfaces state their guarantees, while partial byte-stream reads and writes such as read_exact and write_all retain their documented cancellation boundaries.
Reactor and I/O paths are also hardened for long-lived production behavior:
NotFound as already-cleaned state, so cancellation/drop races do not leak bookkeeping (src/runtime/io_driver.rs, src/runtime/reactor/registration.rs).src/runtime/reactor/token.rs).unknown_tokens instead of panicking when stale/backend events appear, so diagnostics stay available under fault conditions (src/runtime/io_driver.rs).epoll interest mapping supports edge-triggered and edge-oneshot modes plus explicit PRIORITY/HUP/ERROR propagation, so readiness semantics are carried with fewer implicit assumptions (src/runtime/reactor/epoll.rs).epoll paths explicitly clean stale fd/token mappings on ENOENT/closed-fd conditions, including fd-reuse edge cases (src/runtime/reactor/epoll.rs).io_uring poll handles timeout expiry (ETIME) as a timeout condition, not an operational failure, and ignores stale completions for deregistered tokens (src/runtime/reactor/io_uring.rs).src/net/tcp/ provides TcpStream, TcpListener, and split reader/writer halves. Connections are registered with the I/O reactor (epoll or io_uring) and use oneshot waker semantics: the reactor disarms interest after each readiness event, and the stream re-arms explicitly. This avoids spurious wakes at the cost of a set_interest call per poll cycle, which benchmarks show is negligible compared to syscall overhead.
A VirtualTcp implementation (src/net/tcp/virtual_tcp.rs) provides a fully in-memory TCP abstraction for lab-runtime tests. Same API surface, deterministic behavior, no kernel sockets.
src/http/h1/ implements HTTP/1.1 with chunked transfer encoding, connection keep-alive, and streaming request/response bodies. src/http/h2/ implements HTTP/2 frame parsing, HPACK header compression, flow control, and stream multiplexing over a single connection.
The shipped client is HTTP/1.1 only: asupersync::http::Client (a re-export
of h1::HttpClient) offers a pooled, redirect-aware fluent request API with a
tls-feature HTTPS arm, CONNECT tunnelling, and a cookie jar. HTTPS trusts
the roots selected by tls-native-roots / tls-webpki-roots plus any root
installed with HttpClient::builder().add_root_certificate(cert); with plain
tls and no installed root every https:// request fails closed before a
ClientHello (tests/http_client_https_e2e.rs proves both directions against a
real TLS listener). Connection pooling (src/http/pool.rs) applies to that
client; the HTTP/1.1 and HTTP/2 servers do not use it, and there is no
general-purpose HTTP/2 client (gRPC owns a private H2 channel). Optional
response compression lives in src/http/compress.rs.
src/net/websocket/ ships handshake, binary/text frames, ping/pong, and close
frames with status codes. The split reader/writer model allows concurrent send
and receive within the same region. Current tests/conformance wiring keeps
both the extension-negotiation suite and the broader directory-backed RFC 6455
suite live, covering framing, masking, control-frame, close, error-handling, and
fragmentation harnesses against the production WebSocket parser and handshake
surfaces. Runtime cancellation and integration behavior remain covered by the
focused tests/e2e_websocket.rs and tests/e2e/websocket/ lanes rather than by
the byte-level RFC harness alone.
The production HTTP/1 listener can now hand a routed upgrade directly to a
live ServerWebSocket: register the session with
WebSocketUpgrade::on_upgrade, pass Router::into_http1_handler() to
Http1Listener::bind_upgradeable, and keep the callback scoped to the
listener-owned connection task. The listener flushes exactly one validated
101 before transferring the socket, preserves request-codec read-ahead
(including a first frame coalesced with the handshake), and cancels the session
during graceful drain. A bare
101, a response mutated after callback registration, a duplicate callback,
or a selected but unimplemented extension never acquires the transport. This
bridge is HTTP/1-only; it does not claim HTTP/2 extended CONNECT,
permessage-deflate, or automatic keepalive support.
src/tls/ wraps rustls for TLS 1.2/1.3 with three feature flags:
| Flag | Root Certs |
|---|---|
tls | Bring your own |
tls-native-roots | OS trust store |
tls-webpki-roots | Mozilla's WebPKI bundle |
The tls feature selects rustls' ring provider so TLS works out of the box
instead of requiring each application to install a process-global
CryptoProvider. Asupersync's own certificate-pin SHA-256 helpers use the
existing pure-Rust sha2 dependency, but ring remains the native crypto backend
for rustls. Cross-compiling TLS to x86_64-pc-windows-gnu from a Unix worker
therefore requires the MinGW C toolchain (x86_64-w64-mingw32-gcc) even though
the asupersync source is Windows-gated.
tls-ring is another name for the same selection. tls-core compiles the TLS
code without linking any crypto provider, for applications that must not link
ring: pass a rustls CryptoProvider with crypto_provider on
TlsConnectorBuilder or TlsAcceptorBuilder, or install a process default.
Every builder resolves its provider in one order: the explicit one, then the
linked ring provider, then the process default; with none of them, building
fails with a configuration error. Asupersync's own TLS tests use ring and run
with tls.
src/net/dns/ provides async DNS resolution with address-family selection. src/net/udp.rs provides async UDP sockets with send/receive and cancellation safety.
src/transport/ covers runtime-level delivery behavior above raw sockets and below protocol clients:
router.rs tracks endpoint health and routing state with atomics (EndpointState, connection counters, failure counters) and uses RAII guards for active connection/dispatch accounting, including cancel/panic paths.aggregator.rs handles multipath symbol intake with dedup windows, reorder handling, and per-path statistics for loss/duplicate tracking.sink.rs and stream.rs use queued waiters with atomic flags and explicit wakeup bookkeeping to avoid lost-wakeup edge cases in bounded channel transport.sink.rs deduplicates waiter updates with Waker::will_wake checks and re-checks capacity after waiter registration, which closes the capacity-check/registration lost-wakeup race (src/transport/sink.rs).src/transport/mod.rs).Asupersync includes async clients for three databases, each respecting structured concurrency and cancellation.
| Database | Location | Wire Protocol | Auth |
|---|---|---|---|
| SQLite | src/database/sqlite.rs | Blocking pool bridge | N/A |
| PostgreSQL | src/database/postgres.rs | Binary protocol v3 | SCRAM-SHA-256 |
| MySQL | src/database/mysql.rs | MySQL wire protocol | caching_sha2 by default; mysql_native_password only with the explicit insecure_legacy_mysql_native_password opt-in (SHA-1 exchange, fail-closed otherwise) |
All three support prepared statements, transactions, and connection reuse. SQLite operations run on the blocking thread pool (since rusqlite is synchronous) with cancel-safe wrappers that respect region deadlines. PostgreSQL and MySQL implement their wire protocols directly over TcpStream, avoiding external driver dependencies.
The sqlite feature uses rusqlite with bundled SQLite for predictable local
behavior. Native Windows builds work with the normal platform C toolchain;
cross-compiling to x86_64-pc-windows-gnu also needs MinGW available because
libsqlite3-sys compiles the bundled SQLite C source.
src/runtime/blocking_pool.rs enforces several invariants that matter under cancellation and panic-heavy workloads:
min_threads.Asupersync's distributed runtime surface is designed around the same
invariants as local execution: explicit ownership, explicit cancellation, and
deterministic state transitions. The core crate ships the remote
protocol/state-machine surface, capability, lease, idempotency, saga contracts,
the native TCP+mTLS V3 client/service transport, and NativeRemoteRuntime.
Unix builds can additionally enable remote-service to run a supported static
process host. That host binds the built-in asupersync.remote.echo.v1
diagnostic computation to an exact protocol/registry fingerprint and explicit
certificate-pinned peer grants. Service schema v2 makes non-loopback exposure
an explicit fail-closed policy, and a terminal two-worker RCH acceptance run
has exercised the packaged service and probe across distinct hosts. Applications
can reuse the same strict TOML, mutual-TLS, SPKI, grant, listener, and drain
boundary around a caller-provided statically linked RemoteComputationRegistry
through RemoteComputationServiceBootstrap; the packaged CLI remains the echo
diagnostic host. A caller-owned NativeRemoteDiscoveryDriver can actively poll
an existing Discover<Key = SocketAddr> source and refresh one authenticated
route without detaching work or replacing unrelated destinations. Dynamic
plugins or code shipping, route persistence, restart-durable idempotency, and
production WAN reliability remain open deployment concerns rather than blanket
core-runtime claims.
RemoteComputationClient::from_bootstrap_endpoints accepts an ordered, unique,
nonempty static endpoint set while the existing new and endpoint APIs retain
their single-primary behavior. The finite attempt budget rotates that set only
for transient TCP or TLS establishment failures before request publication.
Cancellation, attempt timeout, certificate/name/pin rejection, authenticated
framing/session failure, EOF, and any delivery-ambiguous result fail closed on
the current endpoint. NativeRemoteRuntime inherits this behavior from its
configured route client. This constructor is static bootstrap failover; active
refresh requires the explicit driver below and still is not a load-balancing or
general multi-host/WAN claim.
Callers that already own a Discover<Key = SocketAddr> source can still poll it
manually and convert its current snapshot with
RemoteComputationClient::with_discovered_endpoints or
NativeRemoteRoute::with_discovered_endpoints. The returned value preserves
the original server name, trust roots, client identity, enforcing pins, wire
limits, retry policy, destination, and V3 hello; empty or duplicate snapshots
fail before NativeRemoteRuntime::replace_routes can advance its generation.
For structured active refresh, construct NativeRemoteDiscoveryDriver with an
Arc<NativeRemoteRuntime>, one logical destination, an Arc discovery source,
and a finite nonzero polling/retry policy, then await run(&cx) in a caller-owned
region task. The first poll is immediate. Synchronous source polling runs on the
supplied context's blocking pool and is awaited to completion; a context without
that authority is refused before polling, so the owning runtime needs a pool (the
RuntimeBuilder default, not blocking_threads(0, 0)). Cancellation stops future polls but
can wait for the current source poll, so production sources must bound their own
poll. Source errors and empty, duplicate, or invalid snapshots retain the
last-known-good route. A changed valid snapshot atomically replaces only that
destination, while unchanged snapshots do not advance the route generation and
a removed destination terminates rather than being resurrected. The driver does
not persist routes, choose a health policy, reload configuration/certificates,
or establish general WAN reliability.
| Primitive | Location | Runtime Behavior |
|---|---|---|
| Named remote spawn | src/remote.rs | spawn_remote creates a region-owned RemoteHandle; attached runtimes send protocol messages, while missing runtimes fail closed to an explicit deterministic fallback |
| Lease obligations | src/remote.rs | Leases are obligation-backed and participate in region close/quiescence |
| Idempotency store | src/remote.rs | Deduplicates spawn retries for the in-flight operation lifetime plus a bounded terminal-result retention window, with conflict detection |
| Session-typed protocol | src/remote.rs | Typestate model (OriginSession/RemoteSession) of the legal spawn/ack/cancel/result/renewal transitions; NativeRemoteRuntime does not drive it yet |
| Logical-time envelopes | src/remote.rs | Protocol messages carry logical clock metadata for causal correlation |
| Saga compensations | src/remote.rs | Forward steps and compensations are tracked as a structured rollback flow for distributed workflows |
| Native V3 runtime | src/remote.rs | NativeRemoteRuntime maps region-owned remote handles onto bounded TCP+mTLS sessions, supports ordered static pre-delivery bootstrap failover plus caller-owned single-destination discovery refresh, propagates cancel/lease traffic, and drains owned operations during close |
| Configured application service | src/remote.rs | RemoteComputationServiceBootstrap consumes a caller registry, validates strict schema-v2 exposure/TLS/SPKI/grants before bind, then returns the existing structured service plus deterministic full-registry identity |
| Static service process | asupersync --config ... remote serve | Unix remote-service feature; strict TOML, mutual TLS, certificate-bound grants, flushed readiness/terminal records, SIGINT/SIGTERM drain, and second-signal force-close |
The transport surface is deliberately separated from protocol state machines,
so message semantics can be tested independently of network backend details.
The authenticated service JSON envelopes are strict for protocol V1, V2, and
V3: requests, nested hellos, budgets, typed runtime IDs, depth-bounded recursive
cancellation reasons, outcomes, responses, and V3 control messages reject unknown fields.
Exact encoder goldens in
tests/remote_transport_lifecycle_contract.rs pin every shipped envelope and
variant. A field, tag, type, or ordering change therefore requires a deliberate
new protocol version; additive same-version fields are not silently ignored by
older peers.
tests/remote_transport_lifecycle_contract.rs proves that a TCP-backed
RemoteRuntime adapter preserves spawn/result, cancellation before ack,
cancellation while running, lease renewal, lease expiry, idempotency replay,
send failure, receive EOF, malformed envelope cleanup, delayed ack ordering,
capability denial, and deterministic no-runtime fallback behavior.
The same contract causally verifies a refused primary followed by one
authenticated secondary dispatch for both direct V1 calls and the V3 native
runtime, finite multi-endpoint exhaustion, cancellation before a later dial,
and enforced pin mismatch without endpoint fallthrough.
These goldens and refusals freeze the current process boundary, but do not by
themselves prove interoperability between archived binary releases, durable
idempotency across restart, or multi-host/WAN policy and operation.
Build the asupersync binary with the additive remote-service feature, then
provide an explicit versioned TOML file. Relative certificate paths resolve
from the configuration file's directory. Unknown fields, unsupported protocol
or schema versions, zero resource limits, empty grants, duplicate peer IDs,
invalid pins, unknown computations, and unreadable/empty TLS material all fail
closed. Service schema v2 also requires a literal socket address and an exact
exposure decision: loopback_only accepts only loopback addresses, while
network accepts only non-loopback or wildcard addresses. Hostnames are
refused so DNS cannot silently change the exposure boundary. Nonzero
TLS-handshake and initial-frame deadlines prevent unauthenticated or silent
authenticated sockets from retaining every connection slot.
schema_version = 2
protocol = "3.0"
listen = "127.0.0.1:7443"
listen_scope = "loopback_only"
server_certificate_chain = "/run/secrets/remote-server.crt"
server_private_key = "/run/secrets/remote-server.key"
client_ca_bundle = "/run/secrets/client-ca.crt"
max_frame_bytes = 1048576
max_connections = 256
tls_handshake_timeout_ms = 5000
initial_frame_timeout_ms = 5000
drain_timeout_ms = 30000
idempotency_retention_ms = 300000
max_idempotency_records_per_peer = 1024
[[peers]]
node_id = "origin-a"
spki_sha256 = ["BASE64_ENCODED_32_BYTE_SPKI_SHA256"]
computations = ["asupersync.remote.echo.v1"]
asupersync --format stream-json --config /etc/asupersync/remote.toml remote serve
The CLI deliberately registers only the diagnostic echo operation. An embedded application can host its own statically linked named computations through the same strict boundary without rebuilding TLS, pin, grant, listener, or drain plumbing:
let mut computations = RemoteComputationRegistry::new();
computations.register::<Request, Response, _, _>(
"orders.reconcile.v1",
|_cx, invocation| async move { reconcile(invocation).await },
)?;
// Synchronous preparation validates the complete file, TLS material, pins,
// and every configured name against this consumed executable registry. It
// opens no socket.
let bootstrap = RemoteComputationServiceBootstrap::from_toml_file(
"/etc/asupersync/remote.toml",
computations,
)?;
let (service, identity) = bootstrap.bind().await?;
let operator = service.handle();
let report = service.run(cx).await?;
identity.computations() is the complete registry in deterministic sorted
order, not the union or ordering of peer grants; its fingerprint is the exact
registry fingerprint enforced during admission. A configured name absent from
the supplied registry returns a typed UnknownComputation preparation error
before bind. A registered handler omitted from a peer's allowlist remains in
the identity but is refused before dispatch. Applications remain responsible
for publishing/flushing their own readiness record and for retaining the
service handle used to drain or force-close.
For an intentional cross-host listener, use a literal private/public or
wildcard address with listen_scope = "network". That opt-in prevents an
accidental localhost-to-network promotion; it does not configure host
firewalls, routing, DNS, certificates, load balancing, or production WAN
reliability. Those remain deployment-owned prerequisites.
The schema-v2 acceptance run hosted the packaged service on hz3 and the
packaged probe on hz4. Mutual TLS and both SPKI policies admitted one exact
23-byte echo with SHA-256
25250ce86841943e3b4f69558860a0919c455b4da4d8a6d2197d3f1b4396dc1c;
the service then handled SIGTERM and reported one accepted/completed connection,
zero active/failed/interrupted/panicked connections, and a successful RCH job
exit. This is concrete two-host fleet-path evidence, not a claim that arbitrary
firewalls, routes, certificate deployments, or production WANs are healthy.
The same feature also packages the client half as an authenticated deployment probe. Its configuration is separate from the service configuration: every route, trust anchor, client identity, enforcing server pin, pre-accept attempt timeout, post-accept completion timeout, retry bound, and lease is explicit. Bootstrap entries are literal socket addresses and are tried in order only for failures proven to precede request delivery.
schema_version = 1
protocol = "3.0"
bootstrap_endpoints = ["10.0.0.11:7443", "10.0.0.12:7443"]
server_name = "remote.internal.example"
server_ca_bundle = "/run/secrets/remote-server-ca.crt"
client_certificate_chain = "/run/secrets/origin-a.crt"
client_private_key = "/run/secrets/origin-a.key"
server_spki_sha256 = ["BASE64_ENCODED_32_BYTE_SPKI_SHA256"]
origin_node = "origin-a"
max_frame_bytes = 1048576
connect_timeout_ms = 5000
tls_handshake_timeout_ms = 5000
attempt_timeout_ms = 30000
completion_timeout_ms = 30000
max_attempts = 2
initial_backoff_ms = 50
max_backoff_ms = 1000
lease_ms = 30000
full_jitter = true
tcp_nodelay = true
asupersync --format stream-json --config /etc/asupersync/remote-probe.toml \
remote probe --payload deployment-ready
Success emits one remote_probe_completed record containing the correlated
task ID, echoed byte count, and SHA-256 digest; the payload and private-key
material are not repeated in the receipt. TLS identity or pin failure stops on
the current endpoint, and delivery-ambiguous timeout, cancellation, framing,
or transport loss is never replayed against a later endpoint. The command is a
bounded probe of the compiled-in asupersync.remote.echo.v1 operation, not a
generic remote-code client.
The process flushes a remote_service_ready record only after the listener is
bound. The first SIGINT or SIGTERM closes admission and drains structured
connection work; a second signal force-closes it. Successful exit follows a
remote_service_stopped record with terminal connection, drain, and phase
accounting. V3 deduplication is authenticated-peer scoped but process-local:
after a restart, callers must not retry an operation whose delivery outcome is
ambiguous. The packaged host is a reference process boundary for the compiled-in
echo operation; the library bootstrap supports caller-registered statically
linked handlers, not dynamic plugin loading, closure shipping, code generation,
service discovery, or restart-durable execution.
Treat the opt-in Unix remote-service binary as a static, restart-based service;
it has no hot-reload or live migration contract. Keep the last-known-good binary,
strict service/probe configuration, certificate set, and routing state together
as one deployment unit. To roll back, first remove the instance from external
traffic, send one SIGTERM, and wait for the flushed remote_service_stopped
record with zero active connections. If the configured drain deadline expires,
a second SIGTERM force-closes remaining work; record every affected operation as
delivery-ambiguous and do not replay it automatically.
Restore the complete prior deployment unit, start the prior binary, wait for its
flushed remote_service_ready record, and run remote probe with a new task
identity before returning traffic. Never infer success from process startup
alone, mix old and new certificates or route policy, reuse an in-flight task ID,
or retry work whose pre-rollback delivery outcome is unknown. Listener
idempotency is process-local, so rollback does not recover or deduplicate work
from the replaced process. If either terminal quiescence or the post-rollback
probe cannot be established, keep the instance out of service and escalate
rather than guessing.
| Channel | Location | Pattern | Cancel-Safe |
|---|---|---|---|
| MPSC | src/channel/mpsc.rs | Multi-producer, single-consumer | Two-phase send (reserve/commit) |
| Oneshot | src/channel/oneshot.rs | Single send, single receive | Two-phase send |
| Broadcast | src/channel/broadcast.rs | Fan-out to subscribers | Waiter cleanup on drop |
| Watch | src/channel/watch.rs | Last-value multicast | Always-current read |
| Session | src/channel/session.rs | Typed RPC with reply obligation | Reply is a linear resource |
The two-phase pattern separates reservation from publication. Dropping an
uncommitted permit aborts the reservation and releases its capacity. Inspect
the commit outcome: for MPSC, SendPermit::send returns
Outcome::Err(SendError::Disconnected(value)) with the original value if the
receiver has gone away. A successful commit publishes the message to the
channel; application consumption still depends on the receiver making progress.
| Primitive | Location | Notes |
|---|---|---|
| Mutex | src/sync/mutex.rs | Fair, cancel-safe (contention metrics: ContendedMutex) |
| RwLock | src/sync/rwlock.rs | Writer preference with reader batching |
| Semaphore | src/sync/semaphore.rs | Counting, with permit-as-obligation model |
| Barrier | src/sync/barrier.rs | N-way synchronization point |
| Notify | src/sync/notify.rs | One-time or multi-waiter notification |
| OnceCell | src/sync/once_cell.rs | Async one-time initialization |
| ContendedMutex | src/sync/contended_mutex.rs | Mutex with contention metrics |
| Pool | src/sync/pool.rs | Object pool with obligation-tracked checkout and return-on-drop |
The synchronization primitives are deterministic under the lab runtime and
their wait queues/guards have focused cancellation and cleanup coverage.
Futurelock detection and the obligation-leak oracle observe obligations
recorded in the runtime's obligation table (RuntimeState::create_obligation).
Stock mpsc, oneshot, and broadcast send permits reserved through a
runtime-built Cx register a SendPermit through the obligation mailbox;
sending commits it, while aborting or dropping an unsent permit aborts it.
Semaphore permits likewise register a SemaphorePermit, discharged when
capacity is released. A permit that escapes its task through mem::forget
is reported by the obligation_leak oracle by kind and holder. The lab also
detects a task parked while holding a semaphore permit as a futurelock
(tests/channel_permit_runtime_obligations_e2e.rs). A Cx built without a
runtime keeps the untracked behavior. Session-tracked permits
(src/channel/session.rs) and database transaction tokens remain standalone
typestate tokens (ObligationToken<K>) that those oracles do not see. Mutex
and RwLock guards release on drop and have guard/queue cleanup tests, but
they are not obligations either.
Beyond join, race, and timeout, the combinator library includes patterns for distributed systems and resilience:
| Combinator | Location | Purpose |
|---|---|---|
| quorum | Scope::quorum (src/cx/scope.rs) + src/combinator/quorum.rs | M-of-N completion: spawns every branch, returns once M succeed or success is impossible, then cancels and drains every remaining branch |
| hedge | Scope::hedge (src/cx/scope.rs); the hedge() future in src/combinator/hedge.rs | Start backup after delay, first response wins. Scope::hedge aborts and joins the loser; the standalone hedge() future drops it |
| first_ok | Scope::first_ok (src/cx/scope.rs) + src/combinator/first_ok.rs | Try lazy operations sequentially until one succeeds; an in-flight attempt is drained on cancellation |
| pipeline | Scope::pipeline (src/cx/scope.rs) + src/combinator/pipeline.rs | Executes typed, channel-connected stages and an async sink as scoped tasks, with explicit edge capacities and an overall admitted-work limit |
| map_reduce | Scope::map_reduce (src/cx/scope.rs) + src/combinator/map_reduce.rs | Spawns bounded scoped map tasks and reduces in input order, with separate limits for concurrency and retained work |
| circuit_breaker | src/combinator/circuit_breaker.rs | Failure detection, open/half-open/closed states |
| bulkhead | src/combinator/bulkhead.rs | Concurrency isolation (bounded parallelism) |
| rate_limit | src/combinator/rate_limit.rs | Token bucket throughput control |
| bracket | src/combinator/bracket.rs | Acquire/use/release with guaranteed cleanup |
| retry | src/combinator/retry.rs | Exponential backoff, budget-aware |
Use PipelineExecutionConfig with .pipeline(...).then(...).run(...).await, or
MapReduceLimits with .map_reduce(...).await. The existing outcome-fold APIs
remain available. Retained-work credit includes completed maps waiting for an
earlier input; pipeline credit remains held until the sink consumes the item.
These limits count work items, not payload bytes or the reducer's accumulator.
Errors, panics and cancellation stop admission and drain admitted children
before returning. A noncooperative child keeps the operation pending; dropping
the operation requests cancellation while its region retains cleanup ownership.
The downstream consumer
exercises both APIs with public default features on current-thread and
two-worker native runtimes, including exact ordered output and shutdown checks.
The core combinators publish cancel-safety contracts, and race/select-style winners drain losers through dedicated drain paths. Outcomes aggregate via the severity lattice. An explicit law sheet (src/combinator/laws.rs) documents algebraic properties (associativity, commutativity, distributivity), while the rewrite engine (src/plan/rewrite.rs) optimizes only through explicit RewritePolicy gates and conservative src/plan/analysis.rs side-condition checks. Unknown, MayLeak, or MayOrphan analysis results are not proof that a rewrite preserves cancel/drain/quiescence invariants.
src/raptorq/ implements RFC 6330 systematic RaptorQ codes, a fountain code where any K-of-N encoded symbols suffice to recover the original K source symbols. Its production consumer today is the ATP file-transfer data plane. The distributed snapshot-distribution model in src/distributed/ encodes region state into symbols, assigns replicas via consistent hashing, and supports quorum recovery. On native targets with tls, RemoteSymbolTransport implements DistributorTransport over authenticated mTLS sessions and bounded symbol storage. Cross-process scenarios live in tests/distribution_hedge_process.rs and tests/symbol_durable_process.rs; their presence does not establish current test success, arbitrary Rust-future migration, or general production-WAN reliability.
| Module | Purpose |
|---|---|
rfc6330.rs | Standard-compliant parameter computation |
systematic.rs | Systematic encoder/decoder |
gf256.rs | GF(2^8) arithmetic (addition, multiplication, inversion) |
linalg.rs | Matrix operations over GF(256) |
pipeline.rs | Full sender/receiver pipelines with symbol authentication (verify_auth; fail-closed). The production transport_rq transport now forces a deliberate posture choice — see asupersync-e880xo |
proof.rs | Decode proof system for verifiable recovery |
The implementation is deterministic (no randomness in lab mode) and can integrate with the security layer (src/security/) for per-symbol authentication tags (fail-closed when verify_auth is enabled — forged/contextless symbols are rejected). REALITY (asupersync-e880xo): the production ATP RaptorQ transport (src/net/atp/transport_rq) is now fail-closed on symbol-auth posture: a default RqConfig is MissingAuthenticationContext, so callers must deliberately choose with_symbol_auth(ctx) (every UDP symbol is signed and verified) or the explicit allow_unauthenticated_for_trusted_transport() opt-out (integrity-vs-manifest only). send_path refuses before any network I/O; receive_once rejects an accepted connection before any handshake, UDP exchange, or data transfer. The handshake additionally rejects any posture mismatch between peers in both directions. NO-CLAIM BOUNDARY: authenticated mode protects the UDP symbol plane only; the TCP control channel + manifest are still unauthenticated, and the sibling transport_tcp transport has no per-symbol authentication at all (integrity-vs-manifest only). Full Byzantine-injection prevention against an active MITM therefore requires with_symbol_auth AND an authenticated control channel/manifest (e.g. TLS) — otherwise a MITM can substitute a matching forged manifest + symbols. Pinned end-to-end by tests/atp_rq_symbol_auth_e2e_contract.rs (transport truth) and tests/decoding_secure_default.rs (config posture).
On the decode side, the runtime uses a policy-driven deterministic planner instead of a single fixed elimination strategy:
src/raptorq/decoder.rs).src/raptorq/decoder.rs, src/raptorq/proof.rs, src/raptorq/test_log_schema.rs).src/raptorq/decoder.rs).simd-intrinsics (src/raptorq/gf256.rs).Use the deterministic E2E wrapper with --bundle to run staged unit/perf-smoke gates plus scenario coverage with a single command:
# Fast smoke (unit sentinel + perf smoke + fast scenario profile)
NO_PREFLIGHT=1 ./scripts/run_raptorq_e2e.sh --profile fast --bundle
# Full profile
NO_PREFLIGHT=1 ./scripts/run_raptorq_e2e.sh --profile full --bundle
# Forensics profile (includes additional repair_campaign perf smoke)
NO_PREFLIGHT=1 ./scripts/run_raptorq_e2e.sh --profile forensics --bundle
Operational notes:
rch when available for Cargo test, benchmark, and scenario-test stages.--profile supports fast|full|forensics; --scenario <ID> can target one deterministic scenario.summary.json, scenarios.ndjson, and (when bundled) validation_stages.ndjson.VALIDATION_TIMEOUT or E2E_TIMEOUT if your environment is slower than expected.Every number below comes from the committed scorecard
artifacts/atp_bench_matrix/20260902T151751Z/scorecard.md
(ovh-a netns harness, release atp 0.4.10, atp-quic-tls13 vs optimally
tuned rsync-ssh-aes128gcm, SHA-256 verified every rep, median wall
seconds). The append-only record of every run and refuted hypothesis is
docs/atp_rq_beat_rsync_ledger.md.
| workload | regime | atp-quic-tls13 | rsync-ssh-aes128gcm | ATP/rsync |
|---|---|---|---|---|
| 50M | perfect (2 ms, 1 Gbit) | 0.651 s | 0.837 s (noisy) | 0.78 |
| 50M | good | 3.353 s | 3.838 s | 0.87 |
| 50M | bad (80 ms, 2 % loss, 50 Mbit) | 13.959 s | 17.346 s | 0.81 |
| tree_small | perfect | 2.953 s | 0.736 s | 4.01 |
| tree_small | good | 3.553 s | 2.037 s | 1.74 |
| tree_small | bad | 5.956 s | 7.341 s (noisy) | 0.81 |
Read it plainly: encrypted ATP is faster than rsync-over-ssh on lossy links
and on a single large file, and slower on small trees over clean links
(per-file overhead dominates a sub-second rsync). It also uses 1.6–2.1×
rsync's sender memory. Across real WAN paths the picture is worse for QUIC:
the dated cross-machine receipt
artifacts/atp_bench_matrix/wan_quic_receipt_2026-09-02.md
(Hetzner Ashburn → Contabo France, SHA-256 verified on both ends) shows
ATP-over-QUIC at 6.3 MB/s where ATP-over-TCP reaches 20 MB/s on the same
path, so the QUIC sender is window-limited at ~90 ms RTT. No unqualified
"beats rsync" claim is made for the encrypted tier.
atp bond-pull)RaptorQ's fountain property — any K-of-N symbols recover the K source symbols — makes it natural to pull a single object from many donors at once. In a bonded transfer, one receiver enrolls N donors; each donor is assigned a disjoint slice of the symbol stream (source + repair ESIs) and sprays it over UDP, and the receiver decodes from the union. The aggregate goodput is the sum of the donors' upload paths, and because symbols are order-independent, a donor that dies mid-transfer costs nothing but its remaining repair window, which is reallocated to the survivors (src/net/atp/bonding/, src/net/atp/transport_rq/bonded.rs).
Content agreement is fail-closed and the descriptor is never on the wire. The receiver and every donor independently derive the bonded descriptor (transfer-id, merkle root, per-entry object IDs, portable metadata commitment) from their own local bytes via the same derivation; enrollment rejects on any transfer-id / merkle-root / metadata / symbol-size / max-block-size mismatch (src/net/atp/bonding/derive.rs, enrollment checks in transport_rq/bonded.rs). A donor whose bytes have drifted cannot enroll, so it cannot corrupt the decode. Per-symbol authentication posture (RaptorQ symbol-auth key, or the explicit unauthenticated-lab opt-out) is the same deliberate, fail-closed choice as the single-source RaptorQ transport above.
The receiver-orchestrated CLI is one command:
# Receiver pulls /srv/payload from two donors, advertising its control endpoint.
atp bond-pull /srv/payload /dest --donors alice@h1,bob@h2 \
--advertise 203.0.113.7:8473 --rq-auth-key-hex "$KEY"
bond-pull starts the in-process bonded receiver, SSH-launches one bond-donate leg per donor host, and waits for the fail-closed commit — SHA/merkle-verified before anything lands in /dest.
Per-donor transport selection (--transport auto|tailscale|ssh|ip): each donor's tailnet membership is probed over ssh, then a dial path is chosen per donor (src/net/atp/bonding/transport_select.rs). auto prefers a shared Tailscale path (CGNAT 100.64.0.0/10) when both ends are on the tailnet, else a direct IP; ip/tailscale force a family; ssh tunnels the symbol stream. (The live ssh -L forward is the remaining real-multi-host step, tracked under z01bbr.8.3; today an ssh-selected leg reports its tunnel plan and falls back to a direct dial.) The chosen path per donor is recorded in the atp_bond_pull JSON receipt so a run is auditable after the fact.
Programmatic use — the BondedTransfer SDK builder drives a real bonded transfer over the same data path, cancel-correctly:
use asupersync::net::atp::sdk::BondedTransfer;
// Receive to completion and get the final report:
let report = BondedTransfer::receive(dest, local_src)
.expect_donors(2)
.listen("0.0.0.0:8473".parse()?)
.auth_key_hex(key_hex)
.run(&cx)
.await;
// Or spawn as an owned child and stream live progress:
let mut handle = BondedTransfer::receive(dest, local_src)
.expect_donors(2)
.spawn(&cx)?;
let addr = handle.control_addr().await; // bound control endpoint for donors
while let Some(p) = handle.next_progress().await { // per-donor ingress, blocks remaining, feedback rounds
println!("{:.0}% ({}/{} blocks)", p.progress_percent(), p.blocks_total - p.blocks_remaining, p.blocks_total);
}
let outcome = handle.wait_for_completion().await; // AtpOutcome: Ok / Err / Cancelled / Panicked
spawn runs the receiver as an owned child of the Cx's region; handle.cancel() aborts it and the child unwinds to quiescence committing nothing (a final cx.checkpoint() guards even the last instant before the irreversible commit). The progress stream emits a terminal Completed on success or Failed on a verification failure; cancellation and other terminal errors are observed as the stream closes plus the join outcome.
src/stream/ provides a composable stream library with the standard functional operators: map, filter, take, skip, chunks, chain, merge, zip, fold, for_each, inspect, enumerate, any_all, count, fuse, buffered, and try_stream. Streams integrate with channels (broadcast_stream, receiver_stream) and participate in cancellation; a dropped stream cleanly aborts any pending I/O.
The lab runtime includes dedicated failure detectors and recovery artifacts, so concurrency failures carry structured evidence instead of vague timeouts.
futurelock_max_idle_steps. Detection emits TraceEventKind::FuturelockDetected with task, region, and held-obligation details, and can optionally panic immediately (panic_on_futurelock) (src/lab/runtime.rs, src/lab/config.rs).verify_integrity()), plus structural validation (validate()) that checks reference validity, region-tree acyclicity, closed-region quiescence, and timestamp consistency before restore (src/lab/snapshot_restore.rs).src/lab/chaos.rs, src/lab/config.rs, src/lab/runtime.rs).src/lab/runtime.rs, src/trace/crashpack.rs).src/observability/entry.rs defines LogEntry with span IDs, task IDs, region context, and structured fields. Log levels (Trace through Error) are separate from cancellation severity. The LogCollector batches entries for export.
src/observability/metrics.rs provides Counter, Gauge, and Histogram abstractions with a zero-allocation hot path. Optional OpenTelemetry integration (src/observability/otel.rs) exports to any OTLP-compatible backend. Multiple exporters (stdout, in-memory for tests, null for benchmarks) can compose via MultiExporter.
src/observability/task_inspector.rs introspects live task state: obligation holdings, poll counts, wait dependencies, and cancellation status. src/observability/diagnostics.rs produces structured explanations: CancellationExplanation traces the full cancel propagation chain, TaskBlockedExplanation identifies what a task is waiting on, and ObligationLeak pinpoints which obligation was not resolved and by whom.
For structural runtime risk, diagnostics also maintain a spectral health monitor over the live task wait graph (src/observability/spectral_health.rs, src/observability/diagnostics.rs). It tracks the Fiedler trend and classifies early-warning severity (none/watch/warning/critical) using a multi-signal ensemble: autocorrelation (critical slowing), variance growth, flicker, skewness, Kendall tau, Spearman rho, Hoeffding's D, distance correlation, split-conformal lower bounds, and an anytime-valid deterioration e-process.
asupersync-macros/ provides proc macros for ergonomic structured concurrency:
use asupersync::{join, race, scope, spawn, Cx};
use asupersync::runtime::RuntimeState;
async fn macro_example(cx: &Cx, state: &mut RuntimeState) {
// `join!` awaits futures side by side and returns all their outputs.
let (a, b) = join!(worker_a(), worker_b());
// `spawn!` inside `scope!` creates region-owned tasks; the scope does not
// return until they are done. A `TaskHandle` is not a future to `join!`.
scope!(cx, state: state, {
let _task = spawn!(async { worker_a().await });
});
// Each branch gets its own child `Cx`, so a losing branch observes its
// cancellation and is drained before `race!` returns.
let winner = race!(cx, {
move |child| task_a(child),
move |child| task_b(child),
});
let _ = winner;
}
These macros are available in the default feature set. The default production
feature set is intentionally limited to proc-macros plus
nightly-outcome-try plus the empty compatibility markers runtime-core and
native-runtime; test-only internals are opt-in. The markers gate nothing yet.
They are on by default so that default builds keep those modules when the planned
runtime split puts them behind the markers. If you opt out of default features
for a minimal core-only build, re-enable proc-macros explicitly.
Current contract:
proc-macros builds are scope!, spawn!, join!, join_all!, race!, and select!; the root also exports the #[main], #[test], and #[lab_test] entry attributes.scope! binds a Scope for the current region; it does not create a fresh child-region boundary. Use Scope::region(...) when you need quiescence on scope exit.spawn! requires runtime state (state: &mut RuntimeState or ambient __state) in addition to Cx.join! and join_all! pin every branch once and poll all unfinished branches concurrently inside one poll_fn; neither macro serializes branches.race! expands only to the drain-correct Cx::race_drained* family: spawned losers are protocol-cancelled and drained before return. Prefer the factory form (move |child| work(child)), where each branch receives its own child Cx: loser cancellation targets the branch's task, so a prebuilt branch awaiting on the caller's cx never observes it and the drain waits for that branch to finish on its own. Each branch runs in its own child region, so the drain also cancels and awaits the tasks a losing branch spawned through its own Cx; tasks the winner spawned keep running and its region closes once they finish (a caller region with admission limits keeps branches in that region instead). On a race! timeout: expiry, the factory form cancels and drains every branch and returns Err(JoinError::Cancelled(_)); the prebuilt form abandons the race by drop.select! is also drain-correct; its else form instead polls each branch exactly once in source order, returns immediately, and drops all still-pending branches without draining.race! and blocking select! must be Send + 'static, and the Cx must carry spawn authority. The direct Cx::race, race_named, race_timeout and race_timeout_named calls also take boxed Send + 'static futures; they are the lower-level surface that drops the losing futures when the race ends instead of draining them.proc-macros do not have a usable macro DSL fallback: join! and race! intentionally fail with compile_error!, while scope!, spawn!, join_all!, and select! are unavailable until proc-macros is re-enabled.Compile-fail tests (via trybuild) verify that incorrect usage produces clear
error messages. See docs/macro-dsl.md for the full pattern catalog.
Current reality: the Cargo-compiled conformance registry for this repository is
the integration-test entrypoint at tests/conformance.rs, which includes the
live module list from tests/conformance/mod.rs. Do not copy the registry
counts into prose: the checked source of truth is
artifacts/conformance_registry_contract_v1.json, and
tests/conformance_registry_contract.rs verifies that its active and dormant
module lists still match tests/conformance/mod.rs. Some active entries or
result lanes are gated by mysql, quic, tls, or platform-specific cfgs.
The active registry covers:
Cx capability contractsImportant limitation: the repository also preserves conformance files on disk
that are not part of the live registry today. tests/conformance/mod.rs
leaves explicit commented-out pub mod entries for known bit-rot,
superseded-suite, relocated-suite, or unresolved-dependency follow-ups. Do not
infer dormancy from an on-disk filename or a prose list: the contract artifact
records every current dormant module's disposition, owner bead or supersession
path, and retention reason. Those files remain in-tree for repair work, but
they do not compile or run through this registry until they are re-wired in
tests/conformance/mod.rs (or through the explicitly recorded replacement
lane).
The separate conformance/ workspace member still exists for standalone
vendor/spec harnesses, but it should not be read as proof that every
disk-resident file under tests/conformance/ is active in CI.
Volatile project facts such as LOC totals, workspace-member counts, conformance
registry counts, and roadmap status are audited in
provider_audit_log.md. Treat live command output
and checked contract artifacts as the source of truth for those values.
Related test and CI entrypoints include:
scripts/run_all_e2e.sh (orchestrated suite execution and summary checks)scripts/run_raptorq_e2e.sh (RaptorQ deterministic scenarios)scripts/run_phase6_e2e.sh (phase-6 integration surface)scripts/check_no_mock_policy.py (no-mock/fake/stub policy gate)scripts/check_coverage_ratchet.py (coverage regression ratchet)scripts/check_wasm_flake_governance.py (WASM flake/quarantine/forensics release gate)These scripts are broader repository gates, not a substitute for the live
tests/conformance/mod.rs registry when you need the exact wired-vs-dormant
coverage picture.
Tests emit deterministic artifact bundles (event_log.txt,
failed_assertions.json, repro_manifest.json) when
ASUPERSYNC_TEST_ARTIFACTS_DIR is set, and the E2E runners emit JSON summaries
for replay automation.
Spork is an OTP-style layer built on Asupersync's kernel guarantees: regions (structured concurrency), obligations (linearity), explicit cancellation, and the deterministic lab runtime.
| OTP Concept | Spork / Asupersync Interpretation |
|---|---|
| Process | A region-owned task/actor (cannot orphan) |
| Supervisor | A compiled, deterministic restart topology over regions (boot ordering, dependencies, shutdown budgets). CompiledSupervisor::bind_managed runs it live: a failed child is cancelled, drained and restarted one-for-one, one-for-all or rest-for-one under a shared intensity/backoff policy (src/supervision.rs, used by src/app.rs). Actors also restart on failure individually (src/actor.rs) |
| Link | Failure propagation rule (sibling/parent coupling; deterministic) |
| Monitor + DOWN | Observation without coupling: deterministic notifications |
| Registry | Names as leases: reserve/commit or abort; dropping an unresolved lease panics (the lease is not yet a runtime-ledger obligation, so region close does not wait for it) |
| call/cast | Request/response and mailbox protocols with bounded drain on cancel |
src/supervision.rssrc/cx/registry.rssrc/spork.rs (spork::process_group)examples/spork_minimal_supervised_app.rsexamples/appspec_reference_journey.rs, with the e2e artifact runner scripts/run_appspec_reference_journey_e2e.sh (emits events.ndjson + summary.json + topology.txt)docs/spork_deterministic_ordering.mddocs/spork_glossary_invariants.mdsrc/trace/crashpack.rsAsupersync has formal semantics backing its engineering.
| Concept | Math | Payoff |
|---|---|---|
| Outcomes | Severity lattice: Ok < Err < Cancelled < Panicked | Monotone aggregation, no "recovery" from worse states |
| Concurrency | Near-semiring: join (⊗) and race (⊕) with laws | Lawful rewrites, DAG optimization |
| Budgets | Tropical semiring: (ℝ∪{∞}, min, +) | Critical path computation, budget propagation |
| Obligations | Linear-logic discipline: resources resolved exactly once (Rust is affine, so enforcement is #[must_use] + runtime leak detection, not purely static) | Leaked obligations are loudly detected at region close instead of silently dropped |
| Traces | Mazurkiewicz equivalence (partial orders) | DPOR-style guided exploration (not certified-optimal DPOR), stable replay |
| Cancellation | Two-player game with budgets | Scoped completeness when modeled responsiveness assumptions hold and budgets are sufficient |
| Adaptive scheduling | Discounted UCB1 over {4, 8, 16, 32, 64} | Opt-in dynamic preemption control with deterministic epoch updates |
| Drain certificates | Signed-step range bounds + empirical phase diagnostics | Conditional, auditable progress evidence for cancellation drain; the current-horizon tail bounds are the trivial 1, so the phase labels carry the signal |
| Structural diagnostics | Spectral graph theory + conformal + e-processes | Early warning on wait-graph fragmentation with calibrated alarms, computed on demand through Diagnostics |
See asupersync_v4_formal_semantics.md for the complete operational semantics.
Asupersync is intentionally "math-forward": it uses advanced math and theory-grade CS where it supports concrete, scoped claims such as controlled-schedule determinism, covered-surface cancel-correctness, published cleanup bounds, and reproducible concurrency debugging. The mechanisms below exist in the codebase today, but their support posture is not uniform:
| Mechanism | Current status |
|---|---|
| Discounted-UCB1 scheduler control | Implemented, default-on runtime scheduling control surface |
| Drain progress diagnostics | Implemented cancellation progress diagnostics; the HTTP/1 and HTTP/2 graceful-drain supervisor uses them, and the scheduler only with enable_governor (off by default). The current-horizon tail bounds are the trivial 1 |
| Spectral wait-graph health | Implemented observability diagnostic, computed when Diagnostics::analyze_structural_health is called; the scheduler runs its own copy only with enable_governor (off by default). Advisory early warning, not a standalone deadlock proof |
| Mazurkiewicz/Foata trace canonicalization and DPOR | Implemented lab/trace exploration machinery |
| Persistent homology trace scoring | Implemented lab exploration prototype; used to prioritize interesting schedules, not a production runtime gate |
| Sheaf-style saga consistency and TLA+ export | Implemented analysis/export APIs for verification workflows; the in-process saga executor does not run the sheaf check |
src/runtime/scheduler/three_lane.rs includes a deterministic discounted-UCB1 controller that selects cancel-streak limits from {4, 8, 16, 32, 64} at fixed epoch boundaries. It is opt-in (off by default) and updates from a bounded reward combining progress, fairness, deadline, and fallback components while an e-process monitors epoch rewards. This is a nonstationary stochastic-bandit control surface; the seeded opt-in EXP3 controller belongs to ATP transport adaptation, not scheduler preemption.
src/cancel/progress_certificate.rs models cancellation drain as a stochastic progress process with auditable evidence, diagnostic variance estimation, and conditional concentration calculations. The range-only raw Freedman candidate is never tighter than the Azuma baseline under the implemented cap, so the selected public envelope equals Azuma; realized variance is never reused as predictable variation. Both public current-horizon candidates are algebraically 1 under the same-history plug-in mean, while confidence_bound is a separate conditional projection. Verdicts include phase classification (warmup, rapid_drain, slow_tail, stalled, quiescent) plus an accepted-history empirical converging status. Neither the status nor the conditional calculations prove future drift, termination, or bounded drain time.
src/observability/spectral_health.rs computes Laplacian-spectrum diagnostics and an early-warning severity model (none/watch/warning/critical) over the live wait graph. It combines spectral trend analysis, nonparametric dependence tests, split-conformal next-step bounds, and an anytime-valid e-process, so structural degradation can be detected with calibrated confidence before hard failures.
Status: an on-demand observability diagnostic. Diagnostics::analyze_structural_health computes it when called, and the scheduler runs its own copy only with enable_governor, which is off by default. The classification is intentionally advisory: zero or falling spectral connectivity is a topology signal, while explicit trapped-cycle evidence remains a separate deadlock proof.
Instead of treating traces as opaque linear logs, Asupersync factors out pure commutations of independent events via trace theory. Two traces that differ only by swapping adjacent independent events are considered equivalent, and canonicalized to a unique representative (Foata normal form). See src/trace/canonicalize.rs.
$$ M(\Sigma, I) = \Sigma^* / \equiv_I $$
Payoff: canonical fingerprints for schedule exploration and stable replay across "same behavior, different interleaving" runs.
Given a dependency DAG (trace poset), Asupersync constructs a valid linear extension that minimizes "owner switches" (a proxy for context-switch entropy) using deterministic heuristics and an exact bounded A* solver. See src/trace/geodesic.rs and src/trace/event_structure.rs.
Payoff: smaller, more canonical traces that are easier to diff, replay, and minimize.
Asupersync includes DPOR-style race detection and backtracking point extraction, using a minimal happens-before relation (vector clocks per task) plus resource-footprint conflicts. See src/trace/dpor.rs and src/trace/independence.rs.
Payoff: systematic interleaving exploration that targets truly different behaviors instead of brute-force schedule fuzzing.
Schedule exploration is prioritized using topological signals from a square cell complex built out of commuting diamonds: edges are causality edges, squares represent valid commutations, and Betti numbers/persistence quantify "non-trivial scheduling freedom". The implementation uses deterministic GF(2) bitset linear algebra and boundary-matrix reduction. See src/trace/boundary.rs, src/trace/gf2.rs, and src/trace/scoring.rs.
Status: implemented lab exploration prototype. It feeds TopologyExplorer novelty scoring for deterministic schedule search; it is not a production scheduler policy, release gate, or runtime health alarm.
Payoff: an evidence-ledger, structure-aware notion of "interesting schedules" that tends to surface rare concurrency behaviors earlier.
In distributed obligation tracking, pairwise lattice merges can hide global inconsistency (phantom commits). Asupersync models this as a sheaf-style gluing problem and detects obstructions where no global assignment explains all local observations. See src/trace/distributed/sheaf.rs.
Status: an API you call on saga observations (SagaConsistencyChecker); nothing in the runtime runs it automatically.
Payoff: catches split-brain-style saga states that evade purely pairwise conflict checks.
The lab runtime monitors invariants (task leaks, obligation leaks, region quiescence) with e-processes (src/lab/oracle/eprocess.rs), adding one observation per run that advances the lab. Separately, src/obligation/eprocess.rs provides an obligation-leak monitor. It is opt-in: Runtime::enable_obligation_leak_monitor installs a Shiryaev–Roberts change detector that the runtime feeds with each committed or aborted obligation's age (each counted once). A leaked obligation alarms it at once, including one the Recover leak policy aborts, and the alarm latches. Runtime::obligation_leak_monitor_snapshot reads its statistic and alert state. The detector is enabled over a horizon of resolutions: for ages within the documented null, the probability of a false alarm within that horizon is at most α (its threshold is horizon/α). An obligation that is never resolved is not observed until its holder completes. The lab invariant monitors are anytime-valid e-processes: a supermartingale-based framework that supports optional stopping without "peeking penalties".
Payoff: turn long-running exploration into statistically sound monitoring, with deterministic, explainable rejection thresholds.
src/lab/conformal.rs calibrates oracle-metric thresholds with split conformal prediction, giving finite-sample, distribution-free coverage guarantees under exchangeability assumptions across deterministic schedule seeds.
Status: opt-in. ScheduleExplorer::with_conformal_calibration calibrates across explored seeds and reports the anomalous ones; no lab oracle consults the calibrator on its own.
Payoff when enabled: stable false-alarm behavior under workload drift, without hand-tuned magic constants.
Asupersync's concurrency combinators come with an explicit law sheet (severity lattices, budget semirings, race/join laws, etc.) and a rewrite engine guarded by conservative static analyses (obligation-safety and cancel-safety lattices; deadline min-plus reasoning). See src/combinator/laws.rs, src/plan/rewrite.rs, and src/plan/analysis.rs.
Status: the rewrite engine is opt-in through plan::execute::capture_optimized; no runtime path invokes it, and an executed plan race drops its losers the way Cx::race does (use Scope::race when losers must be drained).
Payoff: principled plan optimization without silently breaking cancel/drain/quiescence invariants.
Traces can be exported as TLA+ behaviors with spec skeletons for bounded TLC model checking of core invariants (no orphans, obligation linearity, quiescence). See src/trace/tla_export.rs. tests/lab_tla_export_tlc_e2e.rs exports a real LabRuntime trace and runs TLC on it (invariants NoObligationLeaks, QuiescenceOnClose, ObligationLinearity, plus a planted violation that TLC must reject); the CI job tla-tlc is defined to install Java and a sha-pinned tla2tools.jar and to fail closed if TLC is missing, but it does not run while GitHub Actions is disabled. TLC checks the recorded concrete behavior, not a parametric model of the runtime.
Payoff: bridge from deterministic runtime traces to model-checking workflows when you need "prove it", not "it passed tests".
The checked
artifacts/dependency_budget_contract_v1.json
freezes the exact direct Cargo edge allowset and package-version plus
unique-package-name ceilings for every canonical synthesized-consumer
profile/platform cell. The focused dependency-budget-contract lane verifies
the current marginal-ledger fingerprint, profile/target/host/edge-kind
partitions, automatic downward ratchet, safe direct-edge and graph-growth
negative fixtures, and the narrow reviewed-exception path. See
docs/dependency_budget_contract.md.
This contract does not authorize dependency removal or cutover and is not a
broad workspace, runtime, security, performance, or release-readiness claim.
The checked supply-chain gate is
scripts/ci/audit_dependencies.sh, with
policy and interpretation in
artifacts/dependency_supply_chain_policy_v1.json
and
docs/dependency_supply_chain_policy.md.
Its focused proof lane is dependency-supply-chain-policy-contract. The gate
requires both the root and separately tracked excluded-fuzz graphs to pass;
consult the live runner receipt for scanner evidence. The Rust contract alone
does not prove scanner execution, fuzz-target compilation or fuzz behavior.
The scoped terminal packet for the Phase-9 CI provenance campaign is
artifacts/dependency_ci_provenance_final_signoff_v1.json,
checked by the dependency-ci-provenance-final-signoff lane. It joins the
full-SHA GitHub Actions inventory, the owner-selected static-only JavaScript
package-tree receipt, fresh root/excluded-fuzz Cargo scanner evidence, the
direct-minimal downstream consumer result, and the generated AGENTS dependency
table contract. Its verdict is PASS_SCOPED_KEEP_DEFER, not release green. See
docs/dependency_ci_provenance_final_signoff.md
for replay and no-claim boundaries. The signoff grants no package-manager,
dependency-cutover, file-deletion, or local-Cargo-fallback authority.
[dependencies]
# crates.io
asupersync = "0.5.0"
# or git (main carries the unreleased 0.6.0 line; a `version = "0.5.0"`
# requirement would not match it)
# asupersync = { git = "https://github.com/Dicklesworthstone/asupersync", branch = "main" }
When migrating from 0.4.x, Cx::set_current now preserves restrictions
already held by its supplied context. Reinstalling a narrowed context no longer
restores full authority. If broader authority is intended, retain and explicitly
install the original privileged Cx. The public method signatures and ordinary
full-authority context behavior are unchanged.
Asupersync is feature-light by default; the lab runtime is available without flags.
| Feature | Description | Default |
|---|---|---|
test-internals | Expose test-only helpers (not for production) | No |
metrics | OpenTelemetry metrics provider (Tokio-free normal graph; OTLP protobuf helpers are fuzz/test-only) | No |
tracing-integration | Tracing spans/logging integration | No |
proc-macros | scope!, spawn!, join!, join_all!, race!, select!, plus #[main], #[test], and #[lab_test] | Yes |
nightly-outcome-try | Outcome Try/residual impls that enable ?; active only on a nightly compiler (on stable the crate builds without them) | Yes |
runtime-core | Compatibility marker for the planned runtime module split; gates nothing yet | Yes |
native-runtime | Compatibility marker for the planned runtime module split; a compile error on wasm32 browser builds, gates nothing else yet | Yes |
tower | Tower Service adapter support | No |
trace-compression | LZ4 compression for trace files | No |
debug-server | Debug HTTP server for runtime inspection | No |
config-file | TOML config file loading for RuntimeBuilder | No |
lock-metrics | Contended mutex wait/hold metrics | No |
io-uring | Linux io_uring reactor (kernel 5.1+) | No |
tls | TLS support via rustls | No |
tls-ring | The same as tls: TLS with the ring crypto provider | No |
tls-core | TLS code without a crypto provider; the application supplies one | No |
tls-native-roots | TLS with native root certs | No |
tls-webpki-roots | TLS with webpki root certs | No |
remote-service | Unix static RemoteRuntime V3 process host (cli + tls) | No |
sqlite | SQLite async wrapper with blocking pool bridge | No |
postgres | PostgreSQL async wire-protocol client | No |
mysql | MySQL async wire-protocol client | No |
kafka | Kafka integration via rdkafka | No |
simd-intrinsics | AVX2/NEON GF(256) kernels for RaptorQ | No |
loom-tests | Loom scheduler/concurrency verification surface | No |
cli | CLI tools (trace inspection) | No |
wasm-browser-minimal | Browser WASM: minimal semantic core | No |
wasm-browser-dev | Browser WASM: development profile with browser I/O | No |
wasm-browser-prod | Browser WASM: production profile with browser I/O | No |
wasm-browser-deterministic | Browser WASM: replay-safe with browser trace | No |
wasm-runtime | Browser runtime capability slices for WASM profile composition (implies wasm-browser-preview) | No |
wasm-browser-preview | Opt-in guard for experimental browser-targeted builds; not full WASM parity | No |
browser-io | Browser I/O capability slice for the wasm-browser-* profiles; not allowed with wasm-browser-minimal | No |
browser-trace | Browser trace capability slice; not allowed with wasm-browser-minimal | No |
deterministic-mode | Replay-safe deterministic timestamps for lab oracles and the deterministic browser profile | No |
desktop-runtime-profile | Bounded runtime configuration for native desktop hosts | No |
quic | Native, Tokio-free QUIC transport surfaces | No |
http3 | Native HTTP/3 (http::h3, http::h3_quic); implies quic | No |
http2-streaming | Live HTTP/2 request ingress with bounded body queues and consumption-based receive credit | No |
compression | HTTP response compression (gzip, deflate, Brotli) | No |
atp-cli | The standalone atp file-transfer binary (bundles tls) | No |
atpd-daemon | The unpublished atpd ATP daemon binary (cli) | No |
tailscale-path-provider | ATP Tailscale candidate-provider integration points; no Tailscale dependency | No |
messaging-fabric | Reserved name for the native FABRIC messaging lane; its module wiring is not fully gated yet | No |
tokio-compat | Tokio compatibility layer for ATP transfer actors; the general wrappers live in the separate asupersync-tokio-compat crate | No |
runtime-metrics | Scheduler and timer instrumentation counters; zero cost when disabled | No |
obligation-leak-detection | Real-time obligation leak detection with stack traces and region-boundary checks | No |
lab-stack-traces | Stack-trace capture for lab oracle violations | No |
cancel-correctness-oracle | Cancel-correctness property oracle for the cancellation protocol | No |
waker-profiling | Waker allocation hot-path profiling hooks | No |
fuzz | Fuzzing support (arbitrary derives, OTLP request helpers); outside the no-Tokio guarantee | No |
criterion-benches | Criterion-powered benchmark targets | No |
benchmark-adapters | Tokio-backed benchmark adapters; a benchmark-only quarantine lane | No |
dependency-ledger | Dependency marginal-ledger generator; build tooling, not a production graph | No |
The remaining features select internal proof lanes and CI umbrellas and are not
meant for applications: channel-mpsc-select-e2e, cross-subsystem-recovery-e2e,
distributed-hash-snapshot-recovery-e2e, h3-websocket-e2e,
obligation-cleanup-e2e, raptorq-roundtrip-e2e, real-service-e2e,
serialization-golden-harnesses, legacy-internal-test-harnesses and
ci-cross-platform.
Default features build on stable Rust 1.95 or newer (Edition 2024). On stable,
nightly-outcome-try is inactive, so ? on Outcome is unavailable. Rust
nightly remains the contributor/release toolchain (pinned by
rust-toolchain.toml), where nightly-outcome-try provides ? on Outcome.
The stable lane checks default features and the minimal subset (default
features disabled, proc-macros enabled) on Rust 1.95.0. Use
scripts/run_stable_lane_e2e.sh for the canonical local/RCH runner; it emits
structured per-stage logs and a summary.json for the stable-lane artifact.
See docs/api_audit.md for the current public API audit and stability notes.
use asupersync::{
// Capability context
Cx, Scope,
// Outcome types (four-valued result)
Outcome, OutcomeError, PanicPayload, Severity, join_outcomes,
// Cancellation
CancelKind, CancelReason,
// Resource management
Budget, Time,
// Error handling
Error, ErrorKind, Recoverability,
// Identifiers
RegionId, TaskId, ObligationId,
// Testing
LabConfig, LabRuntime,
// Policy
Policy,
};
Framework authors (e.g., HTTP servers) should wrap Cx:
use asupersync::{Budget, Cx};
/// Framework-specific request context
pub struct RequestContext<'a> {
cx: &'a Cx,
request_id: u64,
}
impl<'a> RequestContext<'a> {
pub fn is_cancelled(&self) -> bool {
self.cx.is_cancel_requested()
}
pub fn budget(&self) -> Budget {
self.cx.budget()
}
pub fn checkpoint(&self) -> Result<(), asupersync::Error> {
self.cx.checkpoint()
}
}
// Recommended HTTP status mapping:
// - Outcome::Ok(_) → 200 OK
// - Outcome::Err(_) → 4xx/5xx based on error type
// - Outcome::Cancelled(_) → 499 Client Closed Request
// - Outcome::Panicked(_) → 500 Internal Server Error
use asupersync::lab::{LabConfig, LabRuntime};
// Seed for deterministic scheduling (same seed = same execution)
let config = LabConfig::new(42)
// Maximum steps before timeout (prevents infinite loops)
.max_steps(100_000)
// Futurelock detection: tasks holding obligations without being polled
.futurelock_max_idle_steps(1000)
// Record the execution for replay
.with_default_replay_recording();
let lab = LabRuntime::new(config);
Futurelock detection is tied to held obligations and poll progress, not just elapsed time. The detector compares current step against each task's last_polled_step, and can either emit violations or panic based on panic_on_futurelock (src/lab/runtime.rs, src/lab/config.rs).
Lab snapshots also support structural validation and integrity checks. RestorableSnapshot computes a deterministic content hash over the full serialized snapshot, so semantic tampering is detectable before replay analysis (src/lab/snapshot_restore.rs).
Runtime leak handling is configurable via ObligationLeakResponse (Panic, Log, Silent, Recover) with optional threshold-based escalation (LeakEscalation), and zero thresholds are normalized to one to avoid invalid policy states (src/runtime/config.rs).
If a leak is detected while the thread is already unwinding, a Panic response is downgraded to Log to avoid double-panic aborts; leak counting is also guarded against reentrant inflation (src/runtime/state.rs).
use asupersync::{Budget, Time};
use std::time::Duration;
let now = Time::from_secs(1_000); // current logical time from the runtime or lab clock
// Request timeout with poll budget
let request_budget = Budget::new()
.with_timeout(now, Duration::from_secs(30))
.with_poll_quota(10_000) // Max 10k polls
.with_priority(192); // Above the default priority (128)
// Cleanup budget (tighter for faster shutdown)
let cleanup_budget = Budget::new()
.with_timeout(now, Duration::from_secs(5))
.with_poll_quota(500);
The oracle found an unresolved registered obligation. Inspect its task, region, and terminal transition to locate the owner or adapter that lost it. Ordinary MPSC permit destruction aborts and resolves the reservation; dropping that permit is a supported path, not itself a leak.
// Abort an unused reservation and release its capacity.
let permit = tx.reserve(cx).await?;
drop(permit);
// Or commit and handle a possible receiver disconnect.
let permit = tx.reserve(cx).await?;
let outcome = permit.send(message);
// Inspect outcome before deciding whether to retry or discard a returned value.
A region is stuck waiting for children that won't complete.
// Check for: infinite loops without checkpoints
loop {
cx.checkpoint()?; // Add checkpoints in loops
// ... work ...
}
A task is holding obligations but not making progress.
// Check for: awaiting something that will never resolve
// while holding a permit/lock
let permit = tx.reserve(cx).await?;
other_thing.await; // If this blocks forever → futurelock
let outcome = permit.send(msg);
// Handle the commit outcome if other_thing eventually completes.
Same seed should give same execution. If not:
// Check for: time-based operations
// WRONG: uses wall-clock time
let now = std::time::Instant::now();
// RIGHT: uses virtual time through Cx
let now = cx.now();
Also check for ambient randomness:
// WRONG: ambient entropy breaks determinism
let id = rand::random::<u64>();
// RIGHT: use capability-based entropy
let id = cx.random_u64();
To enforce deterministic collections in lab code, consider a clippy rule that
disallows std::collections::HashMap/HashSet in favor of util::DetHashMap/DetHashSet.
Asupersync compiles to wasm32-unknown-unknown and ships a Browser Edition
for JavaScript and TypeScript applications via wasm-bindgen. Be precise
about what crosses that boundary today: the wasm ABI exported by
asupersync-browser-core is a structured lifecycle ledger (regions, scopes,
task handles, capability-gated fetch/WebSocket calls, and fail-closed
scope-close ordering), not a scheduler. A JavaScript task_spawn records a
handle for work that runs on the host's own promises and event loop. Rust
futures are polled inside the module in two places only. Each ABI fetch
request runs as a Rust future driven by wasm-bindgen-futures. Rust code
that links asupersync-browser-core directly can also run !Send futures on
its bounded, scope-owned local executor (local::spawn_local_future, with
fetch::fetch_bytes for awaitable fetches). Neither path is the native Cx
runtime: there is no work stealing, and cancellation drops the future instead
of draining it.
@asupersync/browser supports the
browser main thread and dedicated workers. The shipped direct-runtime lane
requires a real browser window + document + WebAssembly environment, or
the required worker Web APIs. The packages are a release candidate, not GA:
the current package review in artifacts/browser_ga_final_signoff_v1.json is
RELEASE_CANDIDATE_NOT_GA_SIGNOFF, the last recorded headless-browser runs
date from March 2026, no browser-engine test runs in the validation lanes, and
the packages are not yet published to npm. They return to GA when the glue and
wasm are rebuilt together with the export-consistency check passing, at least
one browser-engine test runs in the validation lanes, and the packages are
published.fetch, WebSocket, and WebTransport datagrams plus reliable byte streams
when the host exposes globalThis.WebTransport over HTTPS. Existing sessions
can open bidirectional or send-only streams and accept server-initiated
bidirectional or receive-only streams. The high-level WebTransportHandle
and low-level @asupersync/browser-core facade share the same stream owner.@asupersync/browser now
exposes guarded MessageChannel / MessagePort / BroadcastChannel helpers
and WHATWG ReadableStream / WritableStream byte wrappers. Construction
requires explicit BrowserNativeMessagingCapability or
BrowserNativeStreamCapability authority, denies capability_not_granted
and degraded_mode_denied, and reports stable
ASUPERSYNC_BROWSER_NATIVE_* error codes. The proof artifact is
artifacts/wave2/browser_native_message_and_stream_apis_evidence.json.@asupersync/react and
@asupersync/next remain client-rendered browser adapters layered on top of
the same Browser Edition runtime boundary.asupersync supports the
canonical wasm-browser-* profile set (CI builds wasm-browser-prod), and
the repository ships asupersync-browser-core for the JS ABI/package
boundary. asupersync-wasm is a fail-closed scaffold excluded from the
workspace whose every export returns an error. That is real Rust-side browser
infrastructure, but it is not yet a stable external Rust consumer runtime
lane.RuntimeBuilder::browser().
It is dispatcher-backed, narrower than the shipped JS/TS Browser Edition
packages, and truthful about fail-closed host support. The refreshed
asupersync-j1xbon.4 support decision keeps this lane
artifact-contract-backed preview, not a stable external Rust Browser Edition
API.closeAsync() waits for its managed streamed fetches before requesting ABI
closure and preserves any refusal returned by that boundary. Native ledger
tests and browser host integration tests cover these different parts of the
ownership lifecycle.docs/WASM.md
tracks the lane pump as designed but not exposed.Create a runtime with explicit fetchAuthority.allowedOrigins and
fetchAuthority.allowedMethods, then use scope.fetch({ url, method }) for
streamed response consumption. The returned FetchStreamHandle exposes
response() for status and headers, read() for the next byte chunk, cancel()
for awaited teardown, and closed for the terminal cleanup outcome. HTTP error
statuses remain ordinary responses. The existing fetchRequest() ABI operation
retains its original behavior.
Each streamed fetch owns one ledger task and starts one host request. Authority
is captured at runtime creation and follows the recorded scope ancestry;
requests outside the origin, method, credential, or header-count grant are
refused before network I/O. Redirects are refused, and credentials are omitted
unless explicitly requested and granted. Reads pull on demand and count actual
response bytes, with a 16 MiB default response limit, a 1 MiB chunk limit, and
at most 64 active requests per runtime. Read to EOF, await request cancellation,
or use await scope.closeAsync() / await runtime.closeAsync() to drain managed
streamed fetches before owner closure. Pending cleanup retains admission
capacity, including when the host delivers a response after cancellation.
closeAsync() prevents new descendant fetch admissions while it drains and
shares an in-progress close attempt with concurrent callers. It returns the
actual cancellation, publication, or ABI-close refusal when cleanup cannot
complete, and a failed attempt restores fetch admission. This awaited path
covers the SDK's streamed fetches; it does not claim to drain unrelated host
operations. Synchronous close(), raw ABI exports, and withScope() retain
their existing behavior.
Given a live SDK WebTransportHandle, openStream() creates a bidirectional
stream and openUnidirectionalStream() creates a send-only stream.
acceptBidirectionalStream() and acceptUnidirectionalStream() receive one
server-initiated stream, returning Outcome.ok(null) when that incoming
collection ends. Each method reuses the existing authenticated session and
owning task; it does not create another WebTransport connection.
Stream read(), write(), finish(), and cancel() operations return typed
Outcomes. One read and one write may run concurrently on a bidirectional stream;
send-only and receive-only handles expose only their permitted operations.
Writes copy at most 1 MiB and await host backpressure. Pending opens, pending
accepts, and live streams share a 64-stream session limit. Only one accept may
wait per direction, and the adapter does not prefetch incoming streams.
Byte streams preserve order, not application message boundaries. finish()
sends FIN after admitted writes; a bidirectional stream can still receive data
afterward. Session cancellation and successful scope/runtime closure initiate
child-stream cleanup. Await pending admission operations and each stream's
closed promise to observe host cleanup settlement, including blocked writes
and streams delivered after cancellation. These receipts cannot force a host
promise that never settles to complete.
The maintained Node regressions in
scripts/test_browser_webtransport_lifecycle.mjs and
scripts/test_browser_sdk_webtransport_streams.mjs exercise the actual JS/TS
facades with native WHATWG streams and an intentional task-ABI recorder. They
cover this host boundary; packaged WASM execution, browser-engine behavior,
and live HTTP/3 interoperability require their separate integration lanes.
RuntimeBuilder::browser(), but it is intentionally narrower than the
shipped JS/TS Browser Edition packages. The current Rust-facing path is
dispatcher-backed and truthful about host support: supported hosts construct
a preview browser runtime, while unsupported hosts fail closed to structured
execution-ladder diagnostics rather than pretending full native-thread
parity already exists. asupersync-j1xbon.4 explicitly keeps this support
class at artifact-contract-backed preview until the stable API, ABI policy,
fixture logs, and docs are promoted together.BrowserRuntime creation fail-closed inside
ServiceWorkerGlobalScope; use the bounded broker registration and durable
handoff APIs instead.BrowserRuntime creation remains fail-closed inside
SharedWorkerGlobalScope; use the bounded coordinator attach, version
handshake, detach cleanup, and truthful fallback APIs instead.SharedArrayBuffer + Web Worker parallelism,
but this requires cross-origin isolation headers that many deployments
cannot enable.cfg-gated out on wasm32. Browser networking uses fetch,
WebSocket, and capability-gated WebTransport datagrams and streams instead.MessageChannel / BroadcastChannel / WHATWG stream helpers are guarded
same-browser wrappers only. They do not imply raw transport parity,
cross-origin federation, service/shared-worker direct runtime, filesystem or
process access, or a public Rust AsyncRead / AsyncWrite browser-core
wasm ABI.rustup target add wasm32-unknown-unknown
# Verify the semantic core closes under a browser profile
rch exec -- env CARGO_TARGET_DIR=${TMPDIR:-/tmp}/rch_target_wasm_browser_check cargo check --target wasm32-unknown-unknown \
--no-default-features --features wasm-browser-dev
# JS/TS SDK (not yet published to npm; use workspace-local packages for now)
# npm install @asupersync/browser
If you are authoring browser-facing code in Rust today, the truthful supported
lane is narrower: use the canonical wasm-browser-* profile checks for
semantic-core closure, use asupersync-browser-core / asupersync-wasm only
as the Rust-side ABI/package boundary, and use the maintained fixture workflow
at tests/fixtures/rust-browser-consumer/ plus
scripts/validate_rust_browser_consumer.sh for the repository's proven
browser-facing Rust example. The repo now exposes a preview public
RuntimeBuilder::browser() lane for external Rust consumers, but the
fixture-driven workflow remains the authoritative evidence for this path.
For the preview Rust lane, inspect the truthful execution ladder before and after requesting a lane:
use asupersync::runtime::RuntimeBuilder;
let ladder = RuntimeBuilder::new().inspect_browser_execution_ladder();
let selection = RuntimeBuilder::browser().build_selection();
The key fields to inspect are selected_lane, host_role, reason_code,
preferred_lane, and downgrade_order.
See docs/WASM.md for the full Browser Edition guide,
architecture diagrams, crate map, the current Rust-authored browser contract,
and known limitations.
The checked Browser Edition readiness matrix is
artifacts/browser_edition_readiness_matrix_v1.json,
with the human review table in
docs/browser_edition_readiness_matrix.md.
It binds Direct-runtime supported, Package ABI boundary, Preview public lane,
Broker/coordinator-only, Bridge-only, and Impossible / unsupported rows to
their fixture evidence, including vanilla/Vite and Webpack consumer lanes.
The scoped Browser Edition GA signoff packet is
artifacts/browser_ga_final_signoff_v1.json,
with the human report in
docs/browser_ga_final_signoff.md. It
aggregates B1 readiness, B2 package integrity, and B3 consumer compatibility
for the JS/TS package line while keeping the Rust browser API preview-only. Its
historical decision, as signed, reads:
JS/TS packages GA for browser main-thread and dedicated-worker consumers; Rust browser API preview-only.
The signoff's current package review, RELEASE_CANDIDATE_NOT_GA_SIGNOFF,
supersedes that decision: today the JS/TS packages are a release candidate, not
GA.
| Capability | Status |
|---|---|
| Single-thread deterministic kernel | ✅ Complete |
| Parallel scheduler + work-stealing | ✅ Implemented (three-lane scheduler) |
| I/O reactor (Linux epoll + optional io_uring primary path; BSD/Windows reactors have narrower interest support) | ✅ Implemented |
| TCP, HTTP/1.1, HTTP/2, TLS | ✅ Implemented |
| WebSocket | ⚠️ Runtime surface shipped; live RFC6455 conformance coverage now wires extension negotiation plus broader framing/control/close/masking/fragmentation harnesses, with runtime e2e coverage still lane-specific |
| HTTP/3 (default static-only QPACK; opt-in dynamic QPACK field-section and instruction-stream state machine) | ⚠️ Partial implementation: an established-connection adapter drives control and request/response lifecycle over native QUIC stream bytes, including static-QPACK headers/trailers, informational responses, GOAWAY, cancellation, resets, and reliable STREAM/control-frame recovery. A caller-driven NativeH3Router bridge assembles bounded requests through FIN, detaches bounded caller-scoped Router dispatches, and emits validated final responses on the originating stream while isolating per-stream refusal/reset. The feature-gated NativeH3Listener adds autonomous multi-peer TLS admission, runtime-owned request tasks, buffered and produced responses, deadlines, and graceful shutdown over native UDP. Opt-in streaming request ingress admits handlers at HEADERS, applies static body policy before admission, and uses bounded request-task-owned DATA queues with per-stream backpressure and FIN validation. The streaming listener's native suites pass (2026-10-04: 21/21 streaming journeys; 16 live-UDP tests plus 3 ignored, one of which needs isolated network namespaces). The live request path also carries a bounded final trailer section through the body queue and requires actual FIN before EOF. The native opt-in state machine separately supports dynamic QPACK field sections/tables, Huffman strings, encoder/decoder instruction-stream processing, and bounded blocked-stream scheduling. Deployment readiness, CONNECT, migration, 0-RTT, and external interop evidence remain open, so this is not a claim of h3/quinn drop-in parity or full QUIC deployment parity. |
| Database clients (SQLite, PostgreSQL, MySQL) | ✅ Implemented |
| Actor supervision (GenServer, links, monitors) | ✅ GenServers, actors and supervisors. cx.spawn_gen_server(server, capacity), cx.spawn_actor(actor, capacity) and cx.spawn_supervised_actor(factory, strategy, capacity) run them as tasks in the caller's region, on the native runtime and in the lab. Monitors and links fire when the watched task ends. cx.monitor(&handle) delivers one DOWN with the exit reason; cx.link(peer) cancels the other side of an abnormal exit (CancelKind::LinkedExit); cx.link_trapping(peer) delivers the peer's exit instead. A GenServer gets the same through GenServerHandle::monitor / link / link_trapping, as SystemMsg::Down / `SystemMsg::Ex |
Truncated — view the full README on GitHub.
3,597 followers · starred Jul 2026
324 followers · starred Feb 2026
130 followers · starred Jul 2026
194 followers · starred May 2026
Async runtime for Rust where correctness is structural: region-owned tasks, cancel-correct protocols, capability-gated effects, and deterministic replay testing
Rust
285
6,019 commits
updated Oct 18, 2026
Spec-first, cancel-correct, capability-secure async for Rust
cargo add asupersync --git https://github.com/Dicklesworthstone/asupersync
The Problem: Conventional executor APIs leave important lifecycle contracts to composition and discipline. Cancellation can abandon partial effects, detached tasks can outlive their owner, cleanup may be best-effort, and schedule dependent failures can be difficult to reproduce.
The Solution: Asupersync makes its core task-ownership and runtime-tracked effect contracts structural rather than conventional. Tasks are owned by regions that close to quiescence. Cancellation is an explicit request → drain → finalize protocol, with budgeted bounds on covered, cooperative paths; non-cooperative code and foreign calls do not acquire a universal shutdown bound. Runtime-managed effects require capabilities, with host-boundary exceptions documented explicitly. The lab runtime makes controlled schedules deterministic and replayable.
| Guarantee | What It Means |
|---|---|
| No orphan tasks | Every spawned task is owned by a region; region close waits for all children. Tasks you spawn through a Cx belong to that Cx's region. Tasks spawned through a RuntimeHandle belong to the root region and are drained when the runtime shuts down. |
| Cancellation is a request | Cancelling a task asks it to stop. It keeps running until it reaches a cancellation point (cx.checkpoint() or a cancel-aware await), so it can finish its own async cleanup and return a value. A task that never reaches one is never forcibly stopped, and it holds up its region's close. |
| Cleanup bounds | Cleanup budgets are advisory on the production runtime: a task that keeps running past its budget is not stopped. Runtime::shutdown_timeout bounds how long the caller waits for teardown. |
| No silent drops | A channel send can reserve capacity first and commit later, so a cancelled send never loses or half-sends a message. A one-call send() exists for the common case. |
| Deterministic testing | Lab runtime: virtual time, deterministic scheduling, trace replay. The same seed reproduces the same schedule. |
| Capability-scoped effects | Spawning, timers and runtime-managed effects go through an explicit Cx. Most public I/O entry points (TcpStream::connect, File::open) take no Cx and check no capability today; that work is tracked as asupersync-issue65-criticisms-kpmoy5.5. |
These guarantees are enforced by the runtime, not by the type system. They cost time per task: see Measured against tokio.
Experimental scheduling policy and diagnostics. These are not guarantees:
enable_adaptive_cancel_streak(true)): a
discounted UCB1 policy picks the cancel-streak limit from {4, 8, 16, 32, 64}
at deterministic epoch boundaries. Measured against the fixed limit of 16 on
two hosts, it did not beat it on cancel-heavy work and was 1-29% slower on
spawn+join, yield and channel round trips, so the default is the fixed limit.The attribute macro builds and drives the production runtime (a multi-thread
scheduler with the host-independent default worker count plus an on-demand
blocking pool; #[main(flavor = "current_thread")] and blocking = N adjust
both) and, when the entry future returns, drains the root region: tasks that
outlived main are protocol-cancelled and given drain_ms (default 2000) to
finish their cleanup before teardown. The first program needs no runtime
concepts:
use asupersync::main;
#[main]
async fn main() {
println!("hello from asupersync");
}
This exact program is examples/onramp_level0.rs.
Continue with the four-level graduated on-ramp to add the
prelude, capability context, outcomes, budgets, structured fan-out, two-phase
effects, and deterministic lab oracles.
If you already know tokio, this section maps the primitives you use daily to their asupersync equivalents. The APIs are intentionally different -- asupersync trades implicit convenience for explicit cancel-correctness -- but the concepts map cleanly.
| tokio | asupersync | Key difference |
|---|---|---|
tokio::spawn(fut) | cx.spawn(|cx| async move { fut.await }) or cx.spawn_in(&scope, |cx| fut) | Task is owned by a region; the factory receives its own Cx. See onramp_level2.rs. |
JoinHandle<T> | TaskHandle<T> | .join(cx).await returns Result<T, JoinError>; cancellation and panic remain distinct. |
tokio::task::JoinSet<T> | JoinSet<T, E, P> | JoinSet::in_cx(cx) or JoinSet::new(&scope) owns dynamic fan-out in one region; join_next, join_all, and cancel_all always retain drain ownership. |
tokio::spawn_blocking(f) | cx.spawn_blocking(|cx| f()) | Same idea: RuntimeBuilder::new() and #[main]/#[test] configure an on-demand pool, blocking_threads(0, 512) (blocking = N in the macros). With blocking_threads(0, 0) (blocking = 0) there is no pool, and the closure runs inline on the async worker. |
tokio::select! | race!(cx, { move |child| a(child), move |child| b(child) }) or cx.race_drained_with(...) | Returns only after the winner is selected and every loser is protocol-cancelled and drained. Each branch receives its own child Cx; pass it to the branch's operations. A prebuilt branch that awaits on the caller's cx (for example rx.recv(&cx)) never sees its cancellation, so the drain waits for it to finish on its own. Each branch runs in its own child region: tasks a losing branch spawned through its own Cx are cancelled and drained before the race returns, while tasks the winner spawned keep running. See docs/macro-dsl.md. |
tokio::join! | join!(a, b); use JoinSet::join_all(cx) for dynamic arity | Inline branches complete together; spawned dynamic members remain region-owned and are collected in spawn order. See macros_basic.rs. |
FuturesUnordered / join_all over borrowed data | cx::fiber::scope(|s| async move { s.spawn(fut) }) | Fibers run concurrently inside the calling task, may borrow from its stack (no 'static), and the scope waits for all of them. Each fiber has its own cancellation: the task's cancellation reaches every fiber, FiberHandle::cancel stops one, and a panicking fiber cancels its siblings. They are not parallel; use tasks for that. See fibers_borrowing.rs. |
tokio::time::sleep(dur) | sleep(now, dur) | Takes current Time instead of reading the clock implicitly. Works with virtual time in lab runtime. |
tokio::time::timeout(dur, fut) | timeout(now, dur, fut) or cx.scope().timeout(&cx, dur, |cx| op) | time::timeout returns Result<T, Elapsed> and drops the inner future when the clock wins; Scope::timeout spawns the operation as a region task and cancels and drains it on expiry, reporting a late terminal outcome instead of losing it. |
tokio::time::interval(dur) | interval(now, dur) | Same MissedTickBehavior options (Burst, Delay, Skip). |
tokio::sync::mpsc::channel(n) | channel::mpsc::channel::<T>(n) | Two-phase send: tx.reserve(&cx).await?.send(val). Reserve is cancel-safe; the commit returns an Outcome, which is Err with the value back if the receiver is gone. |
tokio::sync::oneshot::channel() | channel::oneshot::channel::<T>() | Two-phase: tx.reserve(&cx) then permit.send(val). |
tokio::sync::broadcast::channel(n) | channel::broadcast::channel::<T>(n) | Two-phase send. Lagging receivers get RecvError::Lagged. |
tokio::sync::watch::channel(init) | channel::watch::channel(init) | rx.changed(&cx).await? then rx.borrow_and_clone(). |
tokio::sync::Mutex | sync::Mutex | mutex.lock(&cx).await? -- takes &Cx, returns Result (can be cancelled). |
tokio::sync::RwLock | sync::RwLock | .read(&cx).await? / .write(&cx).await?. Writer-preference fairness. |
tokio::sync::Semaphore | sync::Semaphore | sem.acquire(&cx, n).await?. Permit is an obligation released on drop. |
tokio::sync::Barrier | sync::Barrier | barrier.wait(&cx).await?. Leader election built in (is_leader). |
tokio::sync::Notify | sync::Notify | notify.notified().await / notify.notify_one() / notify.notify_waiters(). Differences: notified() registers on first poll (use notified.as_mut().enable() to arm on creation); notify_one() accumulates permits when no waiter is present. |
tokio::sync::OnceCell | sync::OnceCell | `cell.get_or_init( |
tokio::task::yield_now() | yield_now() | Identical concept -- yields to the scheduler. |
1. Every async operation takes &Cx.
Where tokio reads ambient runtime state from thread-locals, asupersync passes an explicit capability context. This means cancellation and budgets compose structurally -- you can see exactly what a function can do from its signature.
// tokio
let permit = tx.reserve().await?;
// asupersync
let permit = tx.reserve(&cx).await?;
2. No orphan tasks. Scopes close to quiescence.
In tokio, tokio::spawn returns a detached task. In asupersync, every task lives in a region. When a scope exits, it waits for all children to finish. No fire-and-forget, no zombie tasks.
3. Outcome instead of just Result.
Tokio task results are Result<T, JoinError> where JoinError covers panics and cancellation. Asupersync uses a four-valued Outcome<T, E> that distinguishes Ok, Err, Cancelled(reason), and Panicked(payload). The severity lattice (Ok < Err < Cancelled < Panicked) drives how combinators aggregate results.
tokio:
use tokio::sync::mpsc;
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel(10);
tokio::spawn(async move {
for i in 0..5 {
tx.send(i).await.unwrap();
sleep(Duration::from_millis(100)).await;
}
});
while let Some(val) = rx.recv().await {
println!("got: {val}");
}
}
asupersync:
use asupersync::channel::mpsc;
use asupersync::{Cx, Outcome};
use asupersync::time::sleep;
use std::time::Duration;
async fn run(cx: &Cx) {
let (tx, mut rx) = mpsc::channel::<i32>(10);
let mut producer = cx.spawn(move |cx| async move {
for i in 0..5 {
let Ok(permit) = tx.reserve(&cx).await else {
break; // cancellation or a closed receiver stops production
};
let Outcome::Ok(()) = permit.send(i) else {
break; // the receiver may disconnect after reservation
};
sleep(cx.now(), Duration::from_millis(100)).await;
}
}).expect("spawn producer");
while let Ok(val) = rx.recv(&cx).await {
println!("got: {val}");
}
let _ = producer.join(cx).await;
}
The key differences: reserve/send two-phase pattern prevents message loss on cancellation, &cx threads through capabilities, and the task is owned by the scope rather than detached.
Tasks don't float free. Every task is owned by a region. Runtime-spawned tasks carry that ownership through admission, execution, and teardown. Regions form a tree. When a region closes, it guarantees all children are complete, all finalizers have run, and all registered obligations are resolved. This is the "no orphans" invariant, enforced by the public API shape, region accounting, and runtime/oracle checks rather than by discipline. It is not a claim that Rust's type system alone proves every adapter or host-boundary path.
use asupersync::{main, prelude::*};
// Typical executors: `spawn(async { ... })` detaches the task; nothing waits
// for it, and nothing cancels it, when the caller returns.
// Asupersync: the tasks belong to a region of this scope.
#[main]
async fn main(cx: &Cx) {
let scope = cx.scope_with_budget(Budget::new().with_poll_quota(64));
let mut tasks = JoinSet::new(&scope);
for value in 1..=2_u32 {
tasks
.spawn(cx, move |_| async move { Ok::<_, Error>(value) })
.expect("spawn region-owned task");
}
let results = tasks.join_all(cx).await;
// ← guaranteed: nothing spawned into the set is still running here
assert_eq!(results.len(), 2);
}
Cancellation is request, acknowledgement, drain, and finalization—not a silent
drop. It operates as a multi-phase protocol:
Running → CancelRequested → Cancelling → Finalizing → Completed(Cancelled)
↓ ↓ ↓
(bounded) (cleanup) (finalizers)
Cancelled(reason) when cancellation winsStock operations publish conditional bounds through
ResponsivenessRegistry: lookup resolves an operation,
and its entry's bound checks the requested goal and context. Finite results
count delivered operation polls or explicit checkpoint calls under the entry's
published assumptions. Masked operations, external or timer progress, blocking
work, and unknown operations return typed refusals where a finite bound cannot
be established. OwnerQuiescent explicitly requires independent owner progress;
an operation bound alone cannot establish region drain or a wall-clock deadline.
Budgets are sufficient conditions only for paths with a concrete published bound.
The native parked-task cancellation contract is a release-blocking behavioral
boundary. It parks real current-thread and owner-local tasks, and exercises a
cross-thread abort against a task parked on a multi-worker runtime, using
a mutex, bounded-channel send, and semaphore before aborting them, then checks
the exact nested TaskHandle result and waiter cleanup. It also pins abort-
before-first-poll delivery, cancellation racing with the end of a Pending
user-future poll, and panic classification through the same terminal-
publication boundary, and proves that acknowledged asynchronous cleanup can
cross another Pending without being truncated. Ordinary Cx::spawn*
preserves typed results after cancellation acknowledgement while retaining
v0.4.3 task-level cancellation for cancellation-blind late values;
cancellation-dominant combinators and blocking wrappers are tested separately.
Structural source audits and aggregate test counts cannot substitute for this
native behavioral lane. Its canonical remote-required command is recorded as
native-parked-task-cancellation in the proof-lane manifest. The runtime
additionally gives spawn adapters a private terminal-result sender with no
cancellation-aware send method, making publication through the completed
task's cancelled Cx unavailable at the type boundary.
Cancellation progress is observable through ProgressCertificate where the runtime wires it: today that is the HTTP/1 and HTTP/2 listeners' graceful-drain supervisor (src/server/shutdown.rs) and the opt-in scheduler governor; region close and Runtime::shutdown_timeout do not consult it. It tracks potential descent, classifies the current drain regime (warmup, rapid_drain, slow_tail, stalled, quiescent), and reports range-bounded Freedman and Azuma candidates plus a separate projected conditional calculation. Under the current range-only variation cap, raw Freedman is never tighter than Azuma, so the selected public envelope equals Azuma. At the current same-history horizon, telescoping makes both candidate tails algebraically 1; they are not evidence of convergence. The converging flag is instead an empirical status over the complete accepted finite non-negative observation history represented by running statistics. It requires positive endpoint net progress, no detected stall, bounded rebound count and magnitude, no latest-step rebound, and no dropped invalid sample. Non-finite or materially negative telemetry is dropped; that suppresses the remaining-step estimate and reports warmup instead of an actionable terminal phase until reset. The realized delta variance remains diagnostic-only rather than being reused as predictable variation. This makes the evidence behind "is shutdown actually converging?" inspectable without treating one trace as proof of future drift, termination, or bounded drain time.
For covered two-phase communication surfaces where cancellation could otherwise lose a message, Asupersync uses reserve/commit:
let permit = tx.reserve(cx).await?; // nothing committed yet
let outcome = permit.send(message);
// Inspect outcome: success publishes; disconnect returns the original value.
Dropping a permit aborts the reservation and releases capacity. The commit outcome determines whether the message was published or returned to the caller.
This is not a blanket claim for every effect. Inherently partial I/O and adapter surfaces publish their own cancel-safety boundaries, including operations such as read_exact and write_all that are explicitly not cancel-safe.
Runtime-managed effects flow through explicit capability tokens:
async fn my_task(cx: &Cx) {
cx.spawn(...); // ← spawn capability
sleep(cx.now(), Duration::from_millis(10)).await; // ← time, read through the Cx
cx.trace("checkpoint reached"); // ← trace capability
}
Swap Cx to change interpretation: production vs. lab vs. distributed.
I/O entry points such as TcpStream::connect(addr) and File::open(path) take no Cx, so they
check the calling task's context: without the IO capability they refuse with
[ASUP-E009]. Threads outside the runtime are not affected.
cx.with_ambient(future) checks them against an explicit cx instead. spawn_blocking still
runs its closure under a restricted context (asupersync-issue65-criticisms-kpmoy5.5).
This is not a blanket claim that every internal helper is Cx-threaded:
host-boundary code such as OS entropy for temporary file names, legacy sync DNS
wall-clock timing, and test/support harnesses must keep their authority
explicit, documented, and outside the deterministic runtime guarantee unless
they are reached through a capability-mediated path.
The lab runtime provides:
LabRuntime report checks 11 of the 24 built-in
oracles from runtime state: task leak, obligation leak, quiescence, loser
drain, finalizer, region tree, deadline monotonicity, the cancellation
protocol, DOWN-message order, managed-supervisor restarts and GenServer replies
(lab::oracle::LAB_RUNTIME_FED_ORACLE_NAMES). Nothing in the runtime feeds
the other 13 yet (channel atomicity, waker dedup and the actor oracles among
them); reports list them as passed and count them as not fed
(asupersync-52hxjz).Concurrency bugs become reproducible test failures.
Asupersync deliberately uses mathematically rigorous machinery where it buys real correctness, determinism, and debuggability. The intent is to make concurrency properties structural, so both humans and coding agents can trust the system under cancellation, failures, and schedule perturbations.
The runtime design is backed by a small-step operational semantics (asupersync_v4_formal_semantics.md) and a Lean project (formal/lean/Asupersync.lean) that checks six invariants of that abstract model, recorded in formal/lean/coverage/invariant_status_inventory.json: structured concurrency single-owner, region-close quiescence, cancellation protocol, race loser drain, obligation no leaks, and no ambient authority.
The proof posture is exact: these are Lean-checked model invariants with theorem and executable-test linkage. The production Rust runtime has not been proved to refine that model. This is therefore not a blanket mechanized proof of the executor, adapters, protocol implementations, platform backends, or distributed transports. Broader runtime-facing claims stay tiered through TLA+/TLC exports, lab/refinement oracles, and lane-specific coverage artifacts. The CI job lean-build is defined to run lake build on the pinned toolchain and upload a hash-bound receipt, but GitHub Actions is disabled for this repository, so it does not currently run; the last recorded local build is in formal/lean/coverage/lake_build_receipt.txt. The canonical proof command is RCH_REQUIRE_REMOTE=1 rch exec -- lake --dir formal/lean build; see artifacts/formal_proof_posture_contract_v1.json, tests/formal_proof_posture_contract.rs, and formal/README.md.
Some checked artifacts retain the legacy markers Lean-checked core invariants cover the six non-negotiable runtime invariants and checks the six non-negotiable runtime invariants. In this README those phrases mean coverage of the six abstract-model rows only; they do not assert a Rust refinement proof.
The canonical proof-command coverage map is artifacts/proof_lane_manifest_v1.json, checked by tests/proof_lane_manifest_contract.rs. It records which RCH_REQUIRE_REMOTE=1 rch exec -- ... lane covers each production graph, feature graph, fuzz smoke, lib/all-target/clippy/rustdoc frontier, and formal proof guarantee, plus what each lane explicitly does not prove. It also carries proof-lane resource-envelope classes for expected timeout, memory, remote-required, and no-local-fallback semantics; those classes harden proof admission metadata and do not replace OS-level RCH worker cgroup limits. The claim/status dashboard is artifacts/proof_status_snapshot_v1.json, checked by tests/proof_status_snapshot_contract.rs; it maps README/AGENTS proof claims to manifest lanes and validation-frontier blocker rows. Its top-level created_date is the contract inception date, not a whole-dashboard freshness receipt: inspect each claim's proof_evidence_status and, for fresh-rch-pass, its bounded evidence_date. A mapped green row identifies a canonical unblocked lane but does not by itself prove a current RCH pass. The nightly differential workflow runs the bounded-age assertion as a local drift alarm; that cadence check does not replace terminal remote-required RCH evidence for any claim row.
Public guarantee semantic evidence bundles are captured in artifacts/public_guarantee_semantic_evidence_bundles_v1.json, checked by tests/semantic_evidence_bundle_contract.rs and documented in docs/semantic_evidence_bundle.md. The first bundle set covers no-orphan-tasks, race-loser-drain, no-obligation-leaks, cancel-safe-send, deterministic-replay, and default-production-no-tokio. These bundles map public claims to proof lanes, fixtures, freshness states, and no-claim boundaries; they do not turn rerun-required, stale-evidence, blocked, no-win, or unsupported rows into fresh proof.
The artifact-governance final signoff is artifacts/artifact_governance_final_signoff_v1.json, checked by tests/artifact_governance_final_signoff_contract.rs and documented in docs/proof/artifact_governance_final_signoff.md. Its focused manifest lane is artifact-governance-final-signoff; cite it only for the A1-A5/A7/A8 governance aggregation, ledger registration, validation harness count alignment, proof manifest/status rows, README/AGENTS markers, closeout checklist, and no-claim boundaries. It does not prove release readiness, workspace health, runtime correctness, performance improvement, live RCH fleet availability, full-corpus artifact coverage, tracker closure while .beads is dirty, or permission to delete files.
The validation-frontier final signoff is artifacts/validation_frontier_signoff_v1.json, checked by tests/validation_frontier_signoff_contract.rs and documented in docs/proof/validation_frontier_runbook.md. Its focused manifest lane is validation-frontier-final-signoff; cite it only for the VF7 operator packet tying inventory, stale-progress receipts, downstream-consumer proof, graph budgets, the channel MPSC/select fixture split, proof manifest/status rows, e2e runner commands, deterministic Markdown summary, and no-claim boundaries together. It does not prove broad workspace health, release readiness, runtime correctness, performance improvement, no regression, source correctness outside cited surfaces, live RCH fleet availability, local Cargo fallback approval, tracker closure, or permission to delete files.
The Proof Evidence Debt Graph is artifacts/proof_evidence_debt_graph_contract_v1.json, emitted by scripts/proof_evidence_debt_graph.py, checked by tests/proof_evidence_debt_graph_contract.rs, and documented in docs/proof_evidence_debt_graph.md. It ranks stale, superseded, blocked, zero-test, local-fallback, missing-envelope, advisory-only, and failed proof evidence so operators can decide what must be rerun before citation. It does not certify workspace health or turn cached/advisory evidence into correctness proof.
The Semantic Evidence Bundles map is artifacts/semantic_evidence_bundles_v1.json, checked by tests/semantic_evidence_bundles_contract.rs, and documented in docs/semantic_evidence_bundles.md. It links public guarantees such as no orphan tasks, loser drain, no obligation leaks, cancel-safe send, deterministic replay, and no default Tokio to manifest-backed proof lanes, stale/missing evidence fixtures, source anchors, freshness policy, and no-claim boundaries. It does not execute the proof lanes or turn cached, stale, failed, local-fallback, or advisory evidence into fresh proof.
The Proof Lane Failure Repro Receipts contract is artifacts/proof_lane_failure_repro_receipt_contract_v1.json, emitted by scripts/proof_lane_failure_repro_receipt.py, checked by tests/proof_lane_failure_repro_receipt_contract.rs, and documented in docs/proof_lane_failure_repro_receipt.md. It converts saved failed RCH/proof-runner transcripts into minimal repro receipts for compile errors, test assertion failures, timeouts, worker disk pressure, SSH transport failures, retrieval timeouts after remote pass, zero-test proofs, and local-fallback refusals. It chooses the next smallest remote-required rerun or diagnostic command; it does not certify workspace health or turn a repro command into fresh proof.
The Reservation-Aware Fallback Work Finder is artifacts/reservation_aware_fallback_work_finder_contract_v1.json, emitted by scripts/reservation_aware_fallback_work_finder.py, checked by tests/reservation_aware_fallback_work_finder_contract.rs, and documented in docs/reservation_aware_fallback_work_finder.md. It converts read-only tracker, dirty-tree, and Agent Mail reservation fixture snapshots into safe next-action recommendations for claimable tasks, epic-only ready queues, active reservation blockers, stale in-progress candidates, tracker-only dirt, source peer dirt, no-useful-work blockers, and planning fallbacks. It never authorizes branches/worktrees, peer-reserved edits, or local Cargo fallback, and it does not certify source correctness.
The Second-Wave Swarm Control-Loop Certification bundle is artifacts/second_wave_swarm_control_loop_certification_v1.json, emitted by scripts/second_wave_swarm_control_loop_certification.py, assembled by scripts/run_second_wave_swarm_control_loop_certification_e2e.sh, checked by tests/second_wave_swarm_control_loop_certification_contract.rs, and documented in docs/second_wave_swarm_control_loop_certification.md. It aggregates the asupersync-ol11aa.1 through asupersync-ol11aa.7 topology, admission, SLO brownout, stale-proof debt, crashpack repro, and fallback work-finder evidence into one operator report. Every child proof command must keep RCH_REQUIRE_REMOTE=1 rch exec --, isolated CARGO_TARGET_DIR, nonzero test evidence, and no-local-fallback semantics. The bundle is not a performance benchmark, not a release publish proof, not a substitute for broad check/clippy/test gates, and not evidence for unrelated source surfaces.
The Third-Wave Swarm Guardrail E2E bundle is artifacts/third_wave_swarm_guardrail_e2e_contract_v1.json, emitted by scripts/third_wave_swarm_guardrail_e2e.py, assembled by scripts/run_third_wave_swarm_guardrail_e2e.sh, checked by tests/third_wave_swarm_guardrail_e2e_contract.rs, and documented in docs/third_wave_swarm_guardrail_e2e.md. It invokes child helpers for stale in-progress reaping, br/bv tracker graph drift, reservation lease watchdog coverage, swarm lane closeout, and RCH quiet-phase receipts against checked fixtures. It is not a broad workspace health proof, not a release publish proof, and not a substitute for broad check/clippy/test gates.
The third-wave operator runbook is docs/third_wave_swarm_operator_runbook.md, checked by tests/third_wave_swarm_operator_runbook_contract.rs. It gives the fail-closed signoff checklist for stale work reaping, br/bv drift, reservation renewal, RCH no-local-fallback validation, Agent Mail closeout, peer dirt handling, main push, and legacy mirror verification.
The admission-aware proof-lane atlas is anchored by artifacts/swarm_proof_lane_planner_contract_v1.json and checked by tests/swarm_proof_lane_planner_contract.rs. Its focused manifest lane is swarm-proof-lane-planner-contract, which proves planner fixtures, atlas decision receipts, deterministic JSON/Markdown report goldens, docs markers, manifest mapping, and proof-status claim rows without broad workspace, conformance, throughput, scheduler-performance, or all-target claims.
The migration readiness planner signoff is anchored by artifacts/migration_readiness_planner_signoff_v1.json and checked by the focused migration-readiness-planner-signoff-contract lane in tests/migration_readiness_planner_contract.rs. Its proof-status claim id is migration-readiness-planner-signoff; cite it only for the executable planner inventory, semantic map, operator report, fixture E2E, docs markers, child bead evidence, and validation-command closeout.
The runtime pressure-control evidence contract is artifacts/runtime_pressure_control_evidence_contract_v1.json, checked by tests/runtime_pressure_control_evidence_contract.rs. Its canonical lane is runtime-pressure-control-evidence-contract in the proof manifest. The operator handoff is docs/runtime_pressure_triage_runbook.md. That lane proves the pressure snapshot schema versions, region memory-budget pressure row schema, RCH proof-lane pressure row schema, no-local-RCH fallback evidence, operator diagnostics bundle, scheduler pressure flamegraph attribution, deterministic lab scenario families, docs markers, and operator scope limits stay aligned. It does not prove real-host throughput, performance improvement, scheduler regression closure, autonomous scheduler rewrites, production-on-by-default admission/backpressure, per-region allocator enforcement, RCH fleet availability, or a deadlock without explicit trapped-cycle proof. Production pressure signals are advisory unless paired with lab/replay evidence, a committed artifacts/flamegraphs/main-<bead-or-short-sha>.svg attribution artifact for triggered scheduler hot-path work, an RCH transcript or admission receipt that rules out local Cargo fallback for remote-required proof lanes, or a trapped-cycle proof, and adaptive controls remain opt-in until stronger evidence supports a wider rollout.
The memory-residency replay e2e contract is artifacts/memory_residency_replay_e2e_contract_v1.json, emitted by scripts/run_memory_residency_replay_e2e.sh, checked by tests/memory_residency_replay_e2e_contract.rs, and documented in docs/proof/memory_residency_replay_e2e.md. Its focused manifest lane is memory-residency-replay-e2e-contract; cite it only for the deterministic 64C/256G scenario matrix, e2e runner failure contract, manifest/status mapping, README/AGENTS markers, and no-claim boundaries. It includes no benchmark evidence and does not prove live host throughput, broad workspace health, release readiness, runtime correctness outside the memory-residency policy/accounting surfaces, p50, p95, p999, memory-use, or NUMA performance improvement.
The memory-residency operator safety contract is artifacts/memory_residency_operator_safety_contract_v1.json, checked by tests/memory_residency_operator_safety_contract.rs, and documented in docs/proof/memory_residency_operator_safety.md. Its focused manifest lane is memory-residency-operator-safety-contract; cite it only for enablement prerequisites, fail-closed M1-M4 safety gates, rollback guidance, Agent Mail handoff fields, closeout checklist, README/AGENTS markers, proof manifest/status rows, and no-claim boundaries. It does not prove release readiness, broad workspace health, allocator replacement, performance improvement, live RCH fleet availability, permission to delete files, or local Cargo fallback approval.
The clean-overlay proof orchestration contract is artifacts/clean_overlay_proof_orchestration_v1.json, checked by tests/clean_overlay_proof_orchestration_contract.rs, and documented in docs/clean_overlay_proof_orchestration_runbook.md. Its focused manifest lane is clean-overlay-proof-orchestration-contract; cite it only for shared-main operator-packet documentation and reference alignment — prerequisites, installed RCH clean-overlay capability evidence and fail-closed command admission, command examples, reservation expectations, RCH heartbeat-fresh/progress-stale cancellation guidance, peer-dirty and capability-drift blocker receipts, non-destructive cleanup/rollback, Agent Mail and br comment handoff templates, README/AGENTS markers, proof manifest/status rows, and no-claim boundaries. The referenced planner refuses enforced attempts while unselected peer dirt is present. No overlay command may be emitted unless captured rch exec --help evidence declares --base, --clean-overlay, --overlay-path, and --no-overlay; unsupported clients and blocked manifests emit only deterministic receipts. The A4 verifier does not prove behavioral correctness of those referenced A1-A3 surfaces; their focused tests are separate evidence. It does not prove release readiness, broad workspace health, performance improvement, live RCH fleet availability, permission to delete files, local Cargo fallback approval, or that peer dirt was excluded without supported installed capability evidence plus an admitted command and terminal execution evidence.
The proof-traffic final signoff is artifacts/proof_traffic_final_signoff_v1.json, checked by tests/proof_traffic_final_signoff_contract.rs, and documented in docs/proof_traffic_control.md. Its focused manifest lane is proof-traffic-final-signoff; cite it only for A1-A5 proof-traffic evidence aggregation, the capability-drift gate, admission receipt taxonomy, clean-overlay handshake, proof parking lot, blocked-loop e2e packet, proof manifest/status rows, README/AGENTS markers, no-local-fallback/no-peer-cancel policies, dependency-cycle receipt/checklist, and no-claim boundaries. It does not prove peer-dirt exclusion without supported capability evidence plus an admitted command and terminal execution evidence, release readiness, broad workspace health, runtime correctness, performance improvement, live RCH fleet availability, local Cargo fallback approval, permission to delete files, or permission to cancel peer builds.
The fourth-wave governor proof map is anchored by docs/fourth_wave_swarm_governor_runbook.md and checked by fourth-wave-governor-signoff-runbook in tests/fourth_wave_swarm_governor_runbook_contract.rs. The final aggregate signoff is artifacts/fourth_wave_governor_final_signoff_v1.json, checked by fourth-wave-governor-final-signoff in tests/fourth_wave_governor_final_signoff_contract.rs. The proof-status dashboard separates fourth-wave-governor-schema-contract, fourth-wave-governor-policy-engine, fourth-wave-swarm-replay-corpus, fourth-wave-runtime-bridge-contract, and the fourth-wave benchmark no-claim contract. The fourth-wave final aggregated signoff is a scoped executable operator report only: the benchmark contract records no fresh benchmark result and does not prove p95 improvement, throughput improvement, no regression, production-on-by-default control, broad workspace health, or RCH fleet availability.
One example: the cancellation/cleanup budget composes as a semiring-like object (componentwise min, with priority as max), which makes "who constrains whom?" algebraic instead of ad-hoc:
combine(b1, b2) =
deadline := min(b1.deadline, b2.deadline)
pollQuota := min(b1.pollQuota, b2.pollQuota)
costQuota := min(b1.costQuota, b2.costQuota)
priority := max(b1.priority, b2.priority)
This is the kind of structure that lets us reason about cancellation protocols and bounded cleanup with proof-friendly, compositional rules.
By default the scheduler uses a fixed cancel-streak limit of 16. With
RuntimeBuilder::enable_adaptive_cancel_streak(true), each worker runs a
deterministic discounted-UCB1 selector over {4, 8, 16, 32, 64} (starting at
16). Measured in one process against the fixed limit on two hosts
(2026-10-05), it did not beat it on cancel-heavy workloads and was 1-29% slower
on spawn+join, yield_now and channel round trips, which is why it is off by
default. At fixed epoch boundaries (128
dispatches by default), it discounts prior pull mass by 0.95, updates the
selected arm from a reward that blends Lyapunov decrease with deadline, fairness, and
fallback penalties, then chooses the next upper-confidence arm. An
anytime-valid e-process monitors the epoch rewards. The policy is a pure
function of the dispatch sequence (no RNG, no wall clock), so identical
schedules make identical choices; the golden
golden_test_lab_runtime_replay_determinism in
src/runtime/scheduler/three_lane_tests.rs replays it bit-exactly. The lab
runtime does not run this selector: LabRuntime uses a fixed cancel-streak
limit of 16, so a lab replay does not reproduce production arm choices.
This is a nonstationary stochastic-bandit controller, not an EXP3 adversarial no-regret claim. The separate ATP RaptorQ transport adapter has its own seeded, opt-in EXP3 controller; that mechanism is not the scheduler selector.
Cancellation drain progress is monitored over signed net-potential deltas. The runtime reports an Azuma baseline and an operational envelope that compares it with a range-only Freedman candidate:
P(S_t ≥ x and Q_t ≤ q) ≤ exp(-x² / (2(q + B x / 3)))
For t ≥ 1, c > 0, x > 0, and q ≥ 0, signed progress Y_i = -Δ_i gives cumulative centered shortfall S_t = Σ(E[Y_i | F_{i-1}] - Y_i) and predictable quadratic variation Q_t. The absolute signed step is bounded by c, and the centered upper increment is bounded by B = 2c. The implementation uses the outcome-independent cap Q_t ≤ t·c². With B = 2c, the resulting Freedman denominator is never smaller than Azuma's, so the selected envelope is always Azuma; the explicit raw candidate remains for auditability. A trace that exceeds the configured step range, or whose history is incomplete because an invalid sample was dropped, disables concentration claims for that verdict. At the current same-history horizon, the plug-in mean telescopes to zero deviation, so both public current-horizon candidates are the trivial bound 1.
Gross downward credit is retained for phase diagnostics only. Its accounted-potential total is pathwise nondecreasing, so the progress certificate does not use it for Ville or optional-stopping evidence. The projected confidence field is conditional on persistence of the empirical plug-in net-progress rate; it is not a proof of future drift.
The same monitor classifies operational drain regime (warmup, rapid_drain, slow_tail, stalled, quiescent) so operators can distinguish an observed slow tail from a configured stalled run. Its converging flag is an empirical status over the complete accepted finite non-negative observation history represented by running statistics. It is guarded by positive endpoint net progress, the stall rule, fixed rebound-count and rebound-magnitude limits, a non-increasing latest step, and the absence of dropped invalid samples; the conditional tails do not gate it. Incomplete telemetry fails actionable outputs closed to warmup, no remaining-step estimate, and disabled concentration.
Why it helps: shutdown and fail-fast behavior can be audited with explicit conditional confidence calculations and phase labels, instead of timeout heuristics alone.
Asupersync treats the task wait-for graph as a dynamic signal. The monitor tracks the Fiedler trajectory (algebraic connectivity), spectral gap/radius, and a nonparametric indicator stack (autocorrelation, variance ratio, flicker, skewness, Kendall tau, Spearman rho, Hoeffding's D, distance correlation), then calibrates forward risk with split conformal bounds and an anytime-valid deterioration e-process.
Status: implemented as an observability diagnostic over the live task wait graph. It is an early-warning signal, not a proof of trapped-cycle deadlock by itself.
Why it helps: structural degradation is detected before hard deadlock/disconnect events, with calibrated thresholds and continuously valid evidence rather than brittle one-off alarms.
The Lab runtime includes a DPOR-style schedule explorer (src/lab/explorer.rs) that treats executions as traces modulo commutation of independent events (Mazurkiewicz equivalence). Instead of a blind seed sweep, it tracks observed equivalence-class fingerprints and uses detected races to prioritize derived deterministic seeds. It does not restore an exact execution prefix and force an alternative enabled transition, so the observed class count is a campaign metric rather than a completeness guarantee.
Result: deterministic, replayable, race-informed schedule fuzzing with explicit coverage telemetry. It is useful bug-finding machinery, not certified DPOR coverage of every reachable equivalence class.
Oracles can run repeatedly during an execution without invalidating significance, using e-processes (src/lab/oracle/eprocess.rs). The key property is Ville's inequality (anytime validity):
P_H0(∃ t : E_t ≥ 1/α) ≤ α
So you can "peek" after every scheduling step and still control type-I error, which is exactly what you want in a deterministic scheduler + oracle setting.
LabRuntime feeds the monitor one observation per run that advances the lab (run_until_quiescent_with_report); a plain report() re-reads the same state and adds no evidence. The rejected invariants are available from runtime.oracles.eprocess_rejected_invariants().
What it does not add: each observation is the oracle's own pass/fail verdict for that run (EProcessMonitor::observe_report), and a lab run is deterministic. The e-process can therefore reject only an invariant whose oracle has already reported a violation. It summarizes the violation rate across runs and seeds with an anytime-valid bound. It does not detect anything the oracle verdicts miss.
For lab metrics that benefit from calibrated prediction sets, Asupersync uses split conformal calibration (src/lab/conformal.rs) with finite-sample, distribution-free guarantees (under exchangeability):
P(Y ∈ C(X)) ≥ 1 − α
The calibrator is opt-in: ScheduleExplorer::with_conformal_calibration feeds it every explored run's oracle report and conformal_anomaly_seeds() lists the seeds whose metrics fall outside the prediction set, even when no invariant failed. You can also feed it reports yourself (ConformalCalibrator::calibrate, then predict). No lab oracle consults it on its own, so no default verdict depends on it.
When a run violates an invariant (or conspicuously does not), Asupersync can produce a structured evidence ledger (src/lab/oracle/evidence.rs) using Bayes factors and log-likelihood contributions. This enables agent-friendly debugging: equations, substitutions, and one-line intuitions, so you can see exactly why the system believes "task leak" (or "clean close") is happening. Build one on request with EvidenceLedger::from_report(&report.oracle_report); no lab path emits it automatically.
Determinism is treated as a first-class algorithmic constraint across the codebase:
src/lab/virtual_time_wheel.rs) with explicit tie-breaking.src/distributed/consistent_hash.rs) for stable assignment without iteration-order landmines.src/lab/runtime.rs, src/trace/dpor)."Same seed, same behavior" holds end-to-end, not just for a demo scheduler.
| Feature | Asupersync | tokio | async-std | smol |
|---|---|---|---|---|
| Structured concurrency | ✅ Built in: every task belongs to a region | ⚠️ Opt-in (JoinSet, TaskTracker) | ❌ Manual | ❌ Manual |
| Cancellation | ⚠️ Request → drain → finalize on covered surfaces; a cancelled task can finish async cleanup and return a value | ⚠️ Drop-based; CancellationToken for cooperative cancellation | ⚠️ Drop-based | ⚠️ Drop-based |
| No orphan tasks | ✅ For Cx spawns; RuntimeHandle spawns belong to the root region | ❌ spawn detaches (JoinSet aborts on drop) | ❌ spawn detaches | ❌ spawn detaches |
| Bounded cleanup | ⚠️ Advisory budgets; a non-cooperative task holds up region close | ❌ Best-effort | ❌ Best-effort | ❌ Best-effort |
| Deterministic testing | ✅ Built-in lab runtime | ⚠️ Paused time; schedule exploration via external tools (loom, turmoil) | ❌ External tools | ❌ External tools |
| Obligation tracking | ✅ Runtime-tracked permits and leases with leak detection | ❌ None | ❌ None | ❌ None |
| Per-task cost | ⚠️ Several times tokio's (see Measured against tokio) | ✅ The reference point | — | — |
| Ecosystem | ✅ Broad support-class-scoped built-in surface (runtime, net, HTTP/1.1+H2, TLS, WebSocket, gRPC, DB, distributed primitives; adapter lanes stay explicitly bounded) | ✅ Largest; most async crates assume it | ⚠️ Medium | ⚠️ Small |
| Maturity | ⚠️ Experimental, pre-1.0; used in production by the author's own projects, no known independent production user | ✅ Production | ✅ Production | ✅ Production |
When to evaluate Asupersync:
When to consider alternatives:
The table above compares runtimes. This section compares ecosystem surface area. It maps common Tokio ecosystem crates to the corresponding Asupersync modules.
| Ecosystem Area | Typical Tokio Crates | Asupersync Surface | Parity status | Maturity | Determinism | Interop friction |
|---|---|---|---|---|---|---|
| Core runtime + task execution | tokio | src/runtime/, src/cx/, src/record/ | Built-in | Mature | Lab-strong | High |
| Structured concurrency + cancellation protocol | usually ad hoc on Tokio | Built into Cx, regions, obligations (src/cx/, src/cancel/, src/obligation/) | Built-in | Mature | Strong | High |
| Channels | tokio::sync::{mpsc, oneshot, broadcast, watch} | src/channel/{mpsc,oneshot,broadcast,watch}.rs | Built-in | Mature | Lab-strong | Medium |
| Sync primitives | tokio::sync::{Mutex,RwLock,Semaphore,Notify,Barrier,OnceCell} | src/sync/ | Built-in | Mature | Lab-strong | Medium |
| Time and timers | tokio::time | src/time/, src/runtime/timer*, src/lab/virtual_time_wheel.rs | Built-in | Mature | Lab-strong | Medium |
| Async I/O traits and extensions | tokio::io, tokio-util::io | src/io/ | Built-in | Active | Mixed | Medium |
| Codec/framing layer | tokio-util::codec | src/codec/ | Built-in | Active | Mixed | Medium |
| Byte buffers | bytes | src/bytes/ | Built-in | Mature | N/A | Low |
| Reactor backends | Tokio + Mio internals | src/runtime/reactor/{epoll,kqueue,windows,browser,lab}.rs (+ io_uring feature on Linux) | Built-in | Active | Mixed | Medium |
| TCP/UDP/Unix sockets | tokio::net | src/net/tcp/, src/net/udp.rs, src/net/unix/ | Built-in | Active | Mixed | Medium |
| DNS resolution | trust-dns, hickory, custom stacks | src/net/dns/ | Built-in | Active | Mixed | Medium |
| TLS | tokio-rustls, native-tls | src/tls/ (tls, tls-native-roots, tls-webpki-roots) | Feature-gated | Active | Mixed | Medium |
| WebSocket | tokio-tungstenite | src/net/websocket/ | Built-in | Active (broad RFC6455 conformance registry wired; runtime e2e coverage remains lane-specific) | Mixed | Medium |
| HTTP stack (HTTP/1.1 + HTTP/2) | hyper, h2, http-body, hyper-util | src/http/h1/, src/http/h2/, src/http/body.rs, src/http/pool.rs | Built-in | Active | Mixed | Medium |
| QUIC + HTTP/3 (default static-only QPACK; opt-in dynamic QPACK field-section and instruction-stream state machine) | quinn, h3, h3-quinn | src/net/quic_core/, src/net/quic_native/, src/http/h3_native.rs, src/http/h3_quic.rs (the http3 feature includes an established-connection adapter that maps SETTINGS, requests, informational/final responses, DATA, trailers, GOAWAY, cancellation, FIN, and reset semantics onto native QUIC stream bytes. A caller-driven single-connection owner now composes the real UDP endpoint, rustls QUIC handshake, WebPKI identity verification, authenticated handshake CIDs, negotiated ALPN, handshake-derived 1-RTT protection, bounded I/O/timer driving, NativeH3Session, and NativeH3Router; a no-mock loopback test carries an exact Router request/response through that path. Historical wrapper sources in src/net/quic/ remain parked outside the core feature graph (the former src/http/h3/ directory no longer exists); support matrix: artifacts/http3_qpack_support_matrix_v1.json. SECURITY (asupersync-7pwwwe, fixed fail-closed; asupersync-arq-quic-epic-b0k8qo.7.4): untrusted-root, wrong-hostname, expired-certificate, unverified-identity, non-H3 ALPN, and pre-I/O cancellation paths fail closed; there is no insecure skip-verify default. Native ATP-over-QUIC control frames and the transfer manifest ride the verified handshake-derived 1-RTT STREAM path; direct single-connection RaptorQ symbols ride verified 1-RTT DATAGRAM packets and rely on QUIC AEAD, while non-direct symbol planes retain explicit per-symbol auth. This row is still not a release-readiness, multi-connection listener/deployment, external-interoperability, migration, 0-RTT, WAN, or fleet-performance claim; see docs/quic_atp_threat_model.md for the precise ATP scope.) | Feature-gated | Active transport/QPACK surfaces plus authenticated single-connection H3-over-real-UDP composition; multi-connection deployment and external interop remain unproven | Mixed | Medium |
| Web framework primitives (router/extractors/local middleware/request-region/SSE helpers; not axum/warp parity) | axum, warp, tower-http | src/web/, src/service/, src/server/ | Partial native primitives | Active (bounded) | Mixed | Medium |
| gRPC | tonic + prost + tower + hyper | src/grpc/ | Built-in | Active | Mixed | Medium |
| Database clients | tokio-postgres, mysql_async, sqlx | src/database/{postgres,mysql,sqlite}.rs | Feature-gated | Active | Mixed | Medium |
| Messaging clients | async Redis/NATS/Kafka crates | src/messaging/{redis,nats,kafka}.rs | In progress | Early | Mixed | Medium |
| Service/middleware stack | tower, tower-layer, tower-service | src/service/ + optional tower adapter feature | Built-in | Active | Lab-strong | Low |
| Filesystem APIs | tokio::fs | src/fs/ | Partial blocking-backed facade; not full tokio::fs parity | Early | Mixed | Medium |
| Process management | tokio::process | src/process.rs | Built-in | Active | Mixed | Medium |
| Signals | tokio::signal | src/signal/ | Built-in | Active | Mixed | Medium |
| Streams and adapters | tokio-stream, futures-util::stream | src/stream/ | Built-in | Active | Lab-strong | Low |
| Observability | tracing, metrics, opentelemetry | src/observability/, src/tracing_compat.rs | Built-in + feature-gated integrations | Active | Mixed | Low |
| Deterministic concurrency testing | loom, tokio-test, external harnesses | src/lab/, frankenlab/, optional loom-tests feature | Built-in | Mature | Strong | Low |
| Tokio-locked third-party crates | crates that require Tokio runtime traits directly | boundary adapters via service/runtime integration points | Adapter needed | N/A | N/A | High |
This map is about capability coverage, not API compatibility. Asupersync intentionally uses a different model centered on Cx, regions, explicit cancellation, and deterministic replay.
Web framework status is deliberately bounded. src/web/ contains a lightweight
router, typed extractors, response conversion, local Handler middleware
wrappers, request-region helpers, health/static/multipart/session/security
utilities, and bounded Sse / StreamingSse surfaces. With http3 enabled,
Router::into_native_h3_router also supplies a caller-driven bridge for an
already-established NativeH3Session: it assembles bounded request bodies,
detaches caller-scoped handler dispatch only after FIN so other streams remain
drivable, caps both incomplete requests and in-flight dispatches, preserves
request/response stream identity, and resets malformed, unsupported, or
cancelled request streams without taking down the connection. The caller still
owns the explicit drive loop and dispatch-scope orchestration; the feature-gated
NativeQuicUdpConnection owns the single live UDP socket, completed TLS/ALPN
state, authenticated connection IDs, 1-RTT protection, and bounded I/O/timer
operations. With both http3 and tls,
NativeH3Listener owns that drive loop for
multiple authenticated peers on a freshly bound UDP socket. Its bind method
takes a runtime-owned Cx, address, Router, rustls server configuration
advertising h3, encoded QUIC transport parameters, and
NativeH3ListenerConfig; local_addr exposes the bound address, and
serve_with_shutdown runs the service through graceful shutdown. Configuration
bounds concurrent handshakes, connections, request regions, body buffering,
per-poll application work, request deadlines, and shutdown grace. Buffered
responses and Http3StreamResponder producers retain a real request task and
its spawn gateway through transport completion. Request timeout/reset cancels
that request, and awaited service exit joins admitted request regions and
checks their cleanup outcomes.
The native H3 listener also has an opt-in live request-body path:
let mut config = NativeH3ListenerConfig::default();
config.streaming_request_body_buffer_bytes = std::num::NonZeroUsize::new(64 * 1024);
With http3,tls enabled, this path resolves the static route/body policy and
validates declared lengths at HEADERS, before admitting a request region. Its
actual request task creates a bounded StreamingRawBody with that task's
Cx, so handlers can consume DATA before peer FIN. Queue pressure pauses
the affected request stream; consumer progress wakes the connection driver
without requiring another peer packet. Each request reserves its queue capacity
plus one bounded pending frame against the connection aggregate, and retains
that charge through request-region closure. The existing
router.max_buffered_body_bytes remains a total body-size ceiling, tightened
by the resolved Router policy.
Framed input reaches EOF only after actual protocol FIN, including bodies with
Content-Length zero or already-consumed declared lengths. Length mismatches
reset the request with H3_MESSAGE_ERROR; FIN inside a frame closes the
connection with H3_FRAME_ERROR. Early body abandonment stops input with
H3_NO_ERROR while allowing the response to finish, including when the peer
acknowledges that input stop with RESET_STREAM. A final request trailer section
is delivered through the same body queue and remains distinct from EOF. Its
internal queue accounting (name bytes + value bytes + four bytes per field)
must fit in min(queue bytes, 16 KiB), checked before constructing the
handler-side trailer map. This bound is separate from the existing native
QPACK decoding and QUIC reassembly limits. Oversized trailer metadata cancels
the request; forbidden trailer fields fail with H3_MESSAGE_ERROR. Handlers
on this opt-in path use StreamingRawBody or the async body collectors;
synchronous buffered extractors fail closed. The default None keeps
buffered request dispatch.
The live multi-peer, stalled-response, and receive-credit regressions are in
tests/quic_h3_live_udp.rs; the streaming request journeys are in
tests/quic_h3_listener_streaming.rs. Both compile and pass natively with
--features http3,tls (2026-10-04, 2780d3454): 21 of 21 streaming journeys,
and 16 live-UDP tests with 3 ignored. Two of the ignored tests are subprocess
roles that their parent tests launch. The third, kernel EAGAIN
backpressure, needs isolated Linux network namespaces and did not run.
Router::into_http1_streaming_handler bridges validated H1 heads
and a bounded live StreamingRawBody; buffered JSON/form collectors can consume
that body asynchronously. The H1 and H2 produced-handler adapters expose
bounded Http1StreamResponder / Http2StreamResponder response producers with
transport-owned backpressure and terminalization. The ordinary H2 request
adapters buffer before dispatch. The opt-in H2 ingress below supplies live
request bodies with buffered responses. The standalone H3 Router bridge also
assembles bounded request bodies before dispatch; the native H3 listener's
opt-in path delivers them incrementally. General full-duplex request/response
progress and external interoperability remain unverified. The native H3 path
also does not claim CONNECT, server push, or deployment readiness. WebSocket
upgrade authoring is provided separately
by web::websocket::WebSocketUpgrade. The SSE lane is proof-backed:
Sse finite bounded batch responses, plus a StreamingSse pull API carrying a
request-region E2E proof and an HTTP/1 transport drain proof
(tests/e2e_web.rs streaming artifact rows). It is not an
axum/warp/tower-http-compatible framework: handlers operate on Asupersync's
lightweight Request / Response types, middleware wraps the local Handler
trait rather than Tower layers, async handlers use explicit Cx-aware wrappers,
and protocol-specific ingress/egress limits remain explicit. Treat this as
native web primitives on top of the HTTP and service modules, not framework
parity.
With the opt-in http2-streaming Cargo feature, the native HTTP/2 listener
supports live uploads with
Http2Listener::bind_streaming_with_config and run_streaming.
Router::into_http2_streaming_parts binds the same router to HEADERS-time
static body-policy admission and to request dispatch:
use asupersync::http::h1::server::HostPolicy;
use asupersync::http::h2::listener::{Http2Listener, Http2StreamingListenerConfig};
// `router` has handlers that consume StreamingRawBody or async body collectors.
let mut config = Http2StreamingListenerConfig::default();
config.listener.allowed_hosts = HostPolicy::AllowList(vec!["localhost".to_string()]);
let (handler, config) = router.into_http2_streaming_parts(config);
let listener = Http2Listener::bind_streaming_with_config(
"127.0.0.1:8080", handler, config,
).await?;
listener.run_streaming(&runtime_handle).await?;
This path validates the request head and declared length before admitting a
request region. The body channel is created by the actual request task.
Stream WINDOW_UPDATE credit follows DATA delivered to that body consumer;
connection credit continues independently so a stalled upload leaves other
streams and control frames drivable. Padding is accounted on the wire and
credited internally, without being counted as application DATA. The listener
reserves bounded queue and pending-input capacity against a connection budget,
including the initial 65,535-byte receive allowance. The opt-in profile requires
an initial stream window of at least 65,535 bytes. listener.max_body_size
remains a separate whole-upload ceiling, tightened by static route policy and
then by request-local policy. H2 request trailers terminate input with
END_STREAM; merely reaching Content-Length does not terminate a live body.
The lower-level Connection::defer_stream_receive_window and
release_stream_receive_capacity APIs expose the same consumption-based flow
control to custom H2 drivers. Existing callers retain automatic replenishment.
The original exhaustive Http2ListenerConfig remains compatible;
Http2StreamingListenerConfig is a separate opt-in wrapper. The native TCP
integration target tests/http2_listener_streaming.rs covers live upload
progress, receive-credit exhaustion, trailers, admission budgets, body errors,
and request cleanup on current-thread and multithread runtimes. Run it with:
cargo test -p asupersync --features http2-streaming --test http2_listener_streaming
It compiles and passes natively: 17 of 17 tests (2026-10-04, 2780d3454).
Sixteen of them run on both a current-thread runtime and a two-worker
multi-thread runtime with sharded state. The feature stays opt-in and outside
the default build. The buffered and produced-response APIs are unchanged.
Filesystem status is deliberately conservative. src/fs/ currently exposes
File, buffered readers/writers, metadata, directory/path helpers,
try_exists, write_atomic, UnixVfs, and platform capability reports that
ATP consumes through src/atp/platform/. Most operations are async facades over
spawn_blocking_io; the poll-based File traits offload each bounded syscall
through the same blocking pool (and degrade to inline calls only on a runtime
built without a pool),
recursive directory removal and large copy operations inherit standard-library
partial-state semantics, and Linux io_uring support is limited to
feature-gated helper paths. Treat this as an early blocking-backed filesystem
layer, not comprehensive tokio::fs parity or a fully region-native filesystem
driver. The crash-safe ATP disk writer, platform doctor, sparse-write, journal,
resume, and verifier work remains tracked by the ATP-D beads.
The broader host-support policy is captured by the checked
Platform Capability Matrix, which
keeps supported, feature-gated, partial, unsupported, and not-applicable rows
separate so skipped or unsupported surfaces are never counted as green support
evidence.
If you do need Tokio-locked dependencies at the boundary, use the migration
playbook in docs/integration.md.
That guide maps the live asupersync-tokio-compat entrypoints to common
stacks: hyper/reqwest/tonic transport, tower/axum middleware, and narrower
Tokio runtime-context or I/O shims. The intended order is native Asupersync
first, compat adapters only where a third-party crate still requires Tokio
traits.
Start brownfield work with the read-only migration readiness planner in
docs/integration.md:
python3 scripts/migration_readiness_planner.py --project-root /path/to/rust/project --output-root target/migration-readiness
For deterministic examples, list and execute the repo-local fixtures:
python3 scripts/migration_readiness_planner.py --list
python3 scripts/migration_readiness_planner.py --execute --output-root "${TMPDIR:-/tmp}/asupersync_migration_planner_e2e"
The report links summary.final_verdict, proof_pack.proof_commands,
semantic_map.recommendations, and operator_report.phase_plan back to the
playbook vocabulary before any target project code is edited.
The reactor export contract is narrower than the directory listing suggests: runtime::reactor exports EpollReactor on Linux, IoUringReactor on Linux only (real with io-uring, intentional Unsupported without it), KqueueReactor on BSD-family targets, IocpReactor on Windows, BrowserReactor on wasm32, and LabReactor for deterministic testing. Historical files such as src/runtime/reactor/uring.rs and src/runtime/reactor/macos.rs are not part of the live export graph.
Interest-flag parity is also narrower than the shared Interest bitflag type suggests: Linux EpollReactor supports the full shipped readiness/mode surface used by the native runtime, KqueueReactor rejects Interest::DISPATCH and Interest::PRIORITY, and IocpReactor currently accepts only READABLE / WRITABLE. Treat Linux epoll plus optional io_uring as the primary production path, with BSD and Windows reactors available but intentionally narrower today.
# Add to Cargo.toml
cargo add asupersync --git https://github.com/Dicklesworthstone/asupersync
# Or manually add:
# [dependencies]
# asupersync = { git = "https://github.com/Dicklesworthstone/asupersync" }
git clone https://github.com/Dicklesworthstone/asupersync.git
cd asupersync
rch exec -- env CARGO_TARGET_DIR=${TMPDIR:-/tmp}/rch_target_readme_docs cargo build --release
Release archives and SHA256SUMS.txt have detached Minisign signatures. After
downloading an archive and its .minisig file, verify it with the established
release public key:
minisign -Vm asupersync-linux-amd64.tar.gz -p release/keys/asupersync.pub
Asupersync uses Rust Edition 2024 and builds on stable Rust with its
default features. The one nightly-only piece is ? on Outcome, from the
default nightly-outcome-try feature. The build script probes the compiler.
On nightly, the feature works as it always has. On stable or beta, it is
inactive: the crate builds without the Try impls, and Cargo prints a warning
for local builds. Contributor and release lanes track the pinned nightly
toolchain in rust-toolchain.toml, so the crate's own tests and examples keep
? on Outcome.
The stable lane checks the default features and the minimal subset (default
features disabled, proc-macros enabled) on Rust 1.95.0. That is the oldest
stable compiler the dependency graph accepts today (sysinfo 0.39 requires
1.95):
bash scripts/run_stable_lane_e2e.sh
That runner drives cargo +1.95.0 check (default features and the minimal
subset), clippy, and the focused Outcome unit tests through RCH with the
shared stable-lane target directory. Set STABLE_RUST_TOOLCHAIN to check
another stable release.
Asupersync's repository Cargo.lock governs this workspace; it does not pin a
downstream consumer's resolution. Default-feature consumers on stable Rust
need 1.95 or newer, the floor that today's dependency graph sets. Consumers who
want ? on Outcome should use the contributor/release nightly pin,
nightly-2026-08-31, from rust-toolchain.toml; another nightly works only if
its Try traits still match. Cargo.toml does not declare rust-version, so
1.95 is the lane's checked floor, not a promised lower bound.
Updated entry macros also support older 0.4.x runtimes. When the runtime
lacks Runtime::drain_root_region, omitting drain_ms preserves its legacy
teardown. An explicit positive drain_ms requires that runtime API.
The standalone downstream fixture now commits its own direct-minimal lock. The
pinned-nightly downstream-consumer-direct-minimal-check lane verifies that
lock against the default public consumer. Full transitive-minimal resolution is
not claimed: its current fail-closed probe selects curve25519-dalek 4.0.0
through nkeys / ed25519-dalek, which fails on the pinned nightly because it
requests the removed stdsimd feature. That precise blocker is recorded in the
downstream consumer artifact
rather than hidden behind an unused production constraint dependency.
Applications should commit and enforce their own lockfile. Vendoring is an optional source-availability control that must be maintained together with that lockfile and the generated source configuration; it does not replace advisory, license, publisher/source, build-script, or feature/target review. See the dependency supply-chain policy for the exact evidence boundary and the links to the dependency budget and consumer-profile contracts.
pub enum Outcome<T, E> {
Ok(T), // Success
Err(E), // Application error
Cancelled(CancelReason), // External cancellation
Panicked(PanicPayload), // Task panicked
}
// Severity lattice: Ok < Err < Cancelled < Panicked
// HTTP mapping: Ok→200, Err→4xx/5xx, Cancelled→499, Panicked→500
pub struct Budget {
pub deadline: Option<Time>, // Absolute deadline
pub poll_quota: u32, // Max poll calls
pub cost_quota: Option<u64>, // Abstract cost units
pub priority: u8, // Scheduling priority (0-255)
}
// Semiring: meet(a, b) = tighter constraint wins
let effective = outer_budget.meet(inner_budget);
pub enum CancelKind {
User, // Explicit cancellation
Timeout, // Timeout exceeded
Deadline, // Deadline passed
PollQuota, // Poll budget exhausted
CostBudget, // Cost budget exhausted
FailFast, // Sibling failed
RaceLost, // Lost a race
ParentCancelled, // Parent region cancelled
ResourceUnavailable, // A required resource is unavailable
Shutdown, // Runtime shutdown
LinkedExit, // A linked task exited
}
// Severity (CancelKind::severity):
// User < Timeout = Deadline < PollQuota = CostBudget
// < FailFast = RaceLost = LinkedExit < ParentCancelled = ResourceUnavailable < Shutdown
// Cleanup budgets scale inversely with severity
pub struct Cx { /* ... */ }
impl Cx {
pub fn spawn<F, Fut>(&self, f: F) -> Result<TaskHandle<Fut::Output>, SpawnError>;
pub fn spawn_in<F, Fut, P>(&self, scope: &Scope<'_, P>, f: F)
-> Result<TaskHandle<Fut::Output>, SpawnError>;
pub fn checkpoint(&self) -> Result<(), Error>; // Err once cancellation is requested
pub fn masked<F, R>(&self, f: F) -> R; // Run a synchronous closure with cancellation deferred
pub fn trace(&self, message: &str);
pub fn budget(&self) -> Budget;
pub fn is_cancel_requested(&self) -> bool;
}
┌─────────────────────────────────────────────────────────────────────────────┐
│ EXECUTION TIERS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ FIBERS │ │ TASKS │ │ ACTORS │ │ REMOTE │ │
│ │ │ │ │ │ │ │ │ │
│ │• Borrow-safe │ │• Parallel │ │• Long-lived │ │• Named compute│ │
│ │• Same-thread │ │• Send │ │• Supervised │ │• Leases │ │
│ │• Region-pinned│ │• Work-stealing│ │• Region-owned │ │• Idempotent │ │
│ │• Cancel-safe │ │• Region-heap │ │• Mailbox │ │• Saga cleanup │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │ │ │ │ │
│ └──────────────────┴────────┬─────────┴──────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ REGION TREE │ │
│ │ │ │
│ │ Root Region ──┬── Child Region ──┬── Task │ │
│ │ │ ├── Task │ │
│ │ │ └── Subregion ── Task │ │
│ │ └── Child Region ── Actor │ │
│ │ │ │
│ │ Invariant: close(region) → quiescence(all descendants) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ OBLIGATION REGISTRY │ │
│ │ │ │
│ │ SendPermit ──→ send() or abort() │ │
│ │ Ack ──→ commit() or nack() │ │
│ │ Lease ──→ renew() or expire() │ │
│ │ │ │
│ │ Invariant: region_close requires all obligations resolved │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ SCHEDULER │ │
│ │ │ │
│ │ Cancel Lane ──→ Timed Lane (EDF) ──→ Ready Lane │ │
│ │ ↑ │ │
│ │ (priority) Lyapunov-guided: V(Σ) must decrease │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
The workspace denies unsafe code by default. Required exceptions are tracked in
artifacts/unsafe_boundary_ledger_v1.json, with reviewer guidance in
docs/unsafe_boundary_ledger.md. The ledger is the canonical unsafe-boundary
inventory for auditors: each row names the source path, category,
category-specific evidence, safety invariant, and explicit no-claim boundary.
The focused unsafe-boundary-ledger-contract lane checks that the ledger still
matches live unsafe source locators and that proof manifest/status wiring stays
aligned. Passing that lane does not prove unsafe correctness, execute every
platform-specific FFI path, or replace category evidence; it only proves the
inventory and review-policy metadata are coherent.
| Lane | Purpose | Priority |
|---|---|---|
| Cancel Lane | Tasks in cancellation states | 200-255 (highest) |
| Timed Lane | Deadline-driven tasks (EDF) | Based on deadline |
| Ready Lane | Normal runnable tasks | Default priority |
Scheduler behavior is intentionally explicit:
cancel_streak_limit=16, ready or timed work gets a dispatch slot within limit + 1 steps per worker (src/runtime/scheduler/three_lane.rs).DrainObligations and DrainRegions, the effective bound is temporarily widened to 2 * cancel_streak_limit to finish cleanup without starving everything else (src/runtime/scheduler/three_lane.rs).fairness_yields, max_cancel_streak) so starvation claims can be checked against runtime counters, not guesses (src/runtime/scheduler/three_lane.rs).try_local_any_lane and pop_any_lane_with_hint) to reduce lock traffic on the hot path while keeping lane ordering rules intact (src/runtime/scheduler/three_lane.rs).governor_interval, default 32) (src/runtime/config.rs, src/runtime/builder.rs, src/runtime/scheduler/three_lane.rs).{4, 8, 16, 32, 64} at fixed epoch boundaries using reward signals that blend Lyapunov decrease, fairness pressure, deadline pressure, and fallback pressure (src/runtime/scheduler/three_lane.rs, src/runtime/config.rs, src/runtime/builder.rs).healthy, congested, unstable, and partitioned runtime states (src/runtime/scheduler/decision_contract.rs, src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).!Send tasks are pinned to owner workers and routed through non-stealable queues; steal paths explicitly reject moving them across workers (src/runtime/scheduler/three_lane.rs, src/runtime/scheduler/local_queue.rs).src/runtime/scheduler/local_queue.rs).Parker and explicit queue rechecks after wakeups, which closes lost-wakeup races between work injection and parking (src/runtime/scheduler/worker.rs, src/runtime/scheduler/three_lane.rs).Runtime state can be split into independently locked shards, so hot-path polling can proceed without serializing every region or obligation mutation. This is opt-in (RuntimeBuilder::with_sharded_state(true)); the default keeps the state behind one lock.
tasks): task table, stored futures, intrusive queue links.regions): region ownership tree and state transitions.obligations): permit/ack/lease lifecycle and leak tracking.instrumentation): trace and metrics surfaces.config): immutable runtime config.Multi-shard operations take shard locks in the canonical order E -> D -> B -> A -> C to prevent deadlocks. ShardGuard (src/runtime/sharded_state.rs) checks that order in debug builds, but only tests use it today; the sharded runtime paths lock shards directly, so in production the order is a convention, not a checked one. Shard locks are ContendedMutex instances, and optional lock-metrics instrumentation can measure wait/hold behavior (src/sync/contended_mutex.rs).
Region memory uses stable handles (HeapIndex) with slot index, generation, and type tag metadata instead of exposing raw allocation addresses.
src/runtime/region_heap.rs).src/runtime/region_heap.rs).src/runtime/region_heap.rs).RRef handles cannot be minted (asupersync-bi2462.39 tracks safe opt-in placement).Asupersync exposes runtime controls that are usually hidden behind ad hoc instrumentation. These controls are wired into scheduler and trace behavior directly.
| Control | API | Runtime Behavior |
|---|---|---|
| Logical clock mode | RuntimeBuilder::logical_clock_mode(...) | Select Lamport, Vector, or Hybrid logical clocks for causal ordering; defaults are chosen from runtime context and carried into event timelines (src/runtime/config.rs, src/trace/distributed/vclock.rs, src/runtime/state.rs) |
| Cancel attribution bounds | RuntimeBuilder::cancel_attribution_config(...) | Bound cancellation cause-chain depth and memory while preserving root-cause lineage and explicit truncation metadata when limits are hit (src/types/cancel.rs, src/runtime/state.rs) |
| Cancel reason on errors | Error::cancel_reason() | The error from cx.checkpoint() (and Error::cancelled) carries the structured CancelReason: kind, origin and cause chain. A joiner that only sees the task's Ok(Err(error)) can still tell why it was cancelled (src/error.rs) |
| Deadline monitor | RuntimeBuilder::deadline_monitoring(...) | Run a background monitor with configurable check cadence, warning thresholds, adaptive history percentiles, and custom warning callbacks (src/runtime/deadline_monitor.rs, src/runtime/builder.rs) |
src/runtime/deadline_monitor.rs).src/runtime/deadline_monitor.rs).src/runtime/deadline_monitor.rs).Asupersync does more work per task than tokio. Every task gets a region
membership, a cancellation state machine and a terminal-result channel, and
two-phase permits are tracked as obligations. That bookkeeping costs time.
These numbers come from one process running both runtimes. The build was a
release build with default features. The date was 2026-10-08, and the source
was that of commit 791a2e356. The same probe ran on three RCH workers: a
16-CPU host, a 10-CPU host shared with other builds at the time, and a busy
64-CPU host. Each figure is p50 per operation at n = 1,000. The ranges span
the three hosts, so shared-host noise is part of the range: the widest row
(spawn + join from a task) was 14× on the 16-CPU host.
| Operation | Asupersync | tokio | Ratio |
|---|---|---|---|
| spawn + join from a task, 4 workers | 4.4–10.7 µs | 0.30–0.74 µs | 12–23× |
spawn + join from block_on, current-thread | 2.6–5.5 µs | 0.22–0.58 µs | 7.7–12× |
yield_now, 4 workers | 0.37–0.61 µs | 0.25–0.38 µs | 1.5–2.0× |
yield_now, current-thread | 0.30–0.60 µs | 0.09–0.15 µs | 3.4–4.0× |
| mpsc ping-pong round trip, 4 workers | 1.37–2.13 µs | 0.20–0.48 µs | 4.5–7.0× |
| mpsc ping-pong round trip, current-thread | 1.29–2.14 µs | 0.17–0.31 µs | 6.8–7.5× |
fan-out child: fiber::scope vs tokio spawn + join, current-thread | 0.27–0.69 µs | 0.22–0.58 µs | 1.0–1.5× |
fan-out child: fiber::scope vs tokio spawn + join, 4 workers | 0.27–0.51 µs | 0.30–0.74 µs | 0.7–1.1× |
Server-shaped rows, also from one process. The TCP rows come from the 16- and 10-CPU hosts and another busy 64-CPU host; each loopback connection makes 200 round trips of a 64-byte message. The HTTP/1.1 rows come from that 64-CPU host, with 200 keep-alive requests per connection. The last column is tokio's throughput over asupersync's:
| Workload | Asupersync | tokio | tokio is faster by |
|---|---|---|---|
| TCP request/response, 1 connection | 29–42 K round trips/s | 44–67 K | 1.5–1.6× |
| TCP request/response, 64 connections | 65–161 K round trips/s | 91–187 K | 1.2–1.6× |
HTTP/1.1 keep-alive GET, 1 connection (one 64-CPU host; vs hyper 1.x) | 21 K requests/s | 42 K | 2.0× |
HTTP/1.1 keep-alive GET, 64 connections (same host; vs hyper 1.x) | 65 K requests/s | 122 K | 1.9× |
Reading the tables:
fiber::scope. It costs about
as much as a tokio task (0.7–1.5× across the three hosts), but fibers run
concurrently on one thread, not in parallel. Tokio's own in-task equivalent
is futures::stream::FuturesUnordered.These numbers already include the October 2026 cuts:
mpsc::send, which made ping-pong 2.7–4.1× faster;The remaining work items are listed under asupersync-issue65-criticisms-kpmoy5.1.
To reproduce, run benches/runtime_vs_tokio.rs, which puts tokio and asupersync
side by side in the same Criterion groups:
cargo bench -p asupersync --bench runtime_vs_tokio --features criterion-benches -- --noplot
The in-repo bench builds asupersync with the test-only features that the
conformance dev-dependency enables. For default-feature numbers like the
table above, build the same code in a separate crate that depends on
asupersync normally.
The method stayed consistent across many small, verified runtime changes: profile the hot paths, remove one source of contention or allocation at a time, then keep cancellation and determinism guarantees intact.
src/runtime/scheduler/three_lane.rs).TaskTable, so push/pop/steal paths avoid full runtime-state lock pressure (src/runtime/task_table.rs, src/runtime/scheduler/local_queue.rs, src/runtime/scheduler/three_lane.rs).src/runtime/scheduler/three_lane.rs).wake_state.notify() with an explicit Idle -> Polling -> Notified state machine, so wakes that arrive during poll are coalesced once instead of double-enqueueing (src/record/task.rs, src/runtime/scheduler/three_lane.rs, src/runtime/scheduler/worker.rs).Waker::will_wake guards to skip redundant clones and refresh only when the executor context actually changes (src/transport/sink.rs, src/transport/mock.rs).src/runtime/scheduler/worker.rs, src/runtime/scheduler/three_lane.rs, src/transport/sink.rs).Vec usage toward SmallVec and pre-sized structures (src/runtime/scheduler/three_lane.rs, src/transport/router.rs, src/transport/aggregator.rs).TaskRecord with queue-tag membership checks, so owner pop and thief steal stay O(1) without per-operation node allocation (src/runtime/scheduler/intrusive.rs, src/runtime/scheduler/local_queue.rs).parking_lot primitives where it improves lock-path cost (src/runtime/*, src/transport/*, src/lab/*).src/runtime/scheduler/global_injector.rs).SmallVec to keep the common path allocation-free (src/runtime/scheduler/local_queue.rs, src/runtime/scheduler/intrusive.rs).src/runtime/scheduler/three_lane.rs, src/runtime/config.rs).src/runtime/io_driver.rs, src/runtime/reactor/*).RuntimeBuilder::with_timer_driver(TimerDriverHandle::with_wall_clock_coalescing(..)), and a coalesced timer fires at the first window boundary at or after its deadline, never before it (src/time/wheel.rs, src/time/driver.rs).Outcome::Panicked, dependents/finalizers are still driven, and one bad task does not take down a worker lane (src/runtime/scheduler/three_lane.rs, src/runtime/builder.rs).BTreeMap/BinaryHeap comparisons; the documented 10K corpus (release-perf profile, 2026-06-01) records a ~27x cancel-path advantage over BTreeMap, and the wheel now also wins the mixed insert/cancel/expire workload outright (benches/timer_wheel.rs).src/runtime/region_heap.rs).benches/scheduler_benchmark.rs, benches/reactor_benchmark.rs, benches/timer_wheel.rs, benches/cancel_drain_bench.rs, benches/tracing_overhead.rs).Asupersync ships a structured networking stack from raw sockets through application protocols. Runtime-owned endpoints participate in structured concurrency, readiness/registration cleanup is explicit, and the lab runtime can substitute virtual TCP for deterministic network testing. Cancel-safety is operation-specific: atomic datagram sends and covered two-phase/adapter surfaces state their guarantees, while partial byte-stream reads and writes such as read_exact and write_all retain their documented cancellation boundaries.
Reactor and I/O paths are also hardened for long-lived production behavior:
NotFound as already-cleaned state, so cancellation/drop races do not leak bookkeeping (src/runtime/io_driver.rs, src/runtime/reactor/registration.rs).src/runtime/reactor/token.rs).unknown_tokens instead of panicking when stale/backend events appear, so diagnostics stay available under fault conditions (src/runtime/io_driver.rs).epoll interest mapping supports edge-triggered and edge-oneshot modes plus explicit PRIORITY/HUP/ERROR propagation, so readiness semantics are carried with fewer implicit assumptions (src/runtime/reactor/epoll.rs).epoll paths explicitly clean stale fd/token mappings on ENOENT/closed-fd conditions, including fd-reuse edge cases (src/runtime/reactor/epoll.rs).io_uring poll handles timeout expiry (ETIME) as a timeout condition, not an operational failure, and ignores stale completions for deregistered tokens (src/runtime/reactor/io_uring.rs).src/net/tcp/ provides TcpStream, TcpListener, and split reader/writer halves. Connections are registered with the I/O reactor (epoll or io_uring) and use oneshot waker semantics: the reactor disarms interest after each readiness event, and the stream re-arms explicitly. This avoids spurious wakes at the cost of a set_interest call per poll cycle, which benchmarks show is negligible compared to syscall overhead.
A VirtualTcp implementation (src/net/tcp/virtual_tcp.rs) provides a fully in-memory TCP abstraction for lab-runtime tests. Same API surface, deterministic behavior, no kernel sockets.
src/http/h1/ implements HTTP/1.1 with chunked transfer encoding, connection keep-alive, and streaming request/response bodies. src/http/h2/ implements HTTP/2 frame parsing, HPACK header compression, flow control, and stream multiplexing over a single connection.
The shipped client is HTTP/1.1 only: asupersync::http::Client (a re-export
of h1::HttpClient) offers a pooled, redirect-aware fluent request API with a
tls-feature HTTPS arm, CONNECT tunnelling, and a cookie jar. HTTPS trusts
the roots selected by tls-native-roots / tls-webpki-roots plus any root
installed with HttpClient::builder().add_root_certificate(cert); with plain
tls and no installed root every https:// request fails closed before a
ClientHello (tests/http_client_https_e2e.rs proves both directions against a
real TLS listener). Connection pooling (src/http/pool.rs) applies to that
client; the HTTP/1.1 and HTTP/2 servers do not use it, and there is no
general-purpose HTTP/2 client (gRPC owns a private H2 channel). Optional
response compression lives in src/http/compress.rs.
src/net/websocket/ ships handshake, binary/text frames, ping/pong, and close
frames with status codes. The split reader/writer model allows concurrent send
and receive within the same region. Current tests/conformance wiring keeps
both the extension-negotiation suite and the broader directory-backed RFC 6455
suite live, covering framing, masking, control-frame, close, error-handling, and
fragmentation harnesses against the production WebSocket parser and handshake
surfaces. Runtime cancellation and integration behavior remain covered by the
focused tests/e2e_websocket.rs and tests/e2e/websocket/ lanes rather than by
the byte-level RFC harness alone.
The production HTTP/1 listener can now hand a routed upgrade directly to a
live ServerWebSocket: register the session with
WebSocketUpgrade::on_upgrade, pass Router::into_http1_handler() to
Http1Listener::bind_upgradeable, and keep the callback scoped to the
listener-owned connection task. The listener flushes exactly one validated
101 before transferring the socket, preserves request-codec read-ahead
(including a first frame coalesced with the handshake), and cancels the session
during graceful drain. A bare
101, a response mutated after callback registration, a duplicate callback,
or a selected but unimplemented extension never acquires the transport. This
bridge is HTTP/1-only; it does not claim HTTP/2 extended CONNECT,
permessage-deflate, or automatic keepalive support.
src/tls/ wraps rustls for TLS 1.2/1.3 with three feature flags:
| Flag | Root Certs |
|---|---|
tls | Bring your own |
tls-native-roots | OS trust store |
tls-webpki-roots | Mozilla's WebPKI bundle |
The tls feature selects rustls' ring provider so TLS works out of the box
instead of requiring each application to install a process-global
CryptoProvider. Asupersync's own certificate-pin SHA-256 helpers use the
existing pure-Rust sha2 dependency, but ring remains the native crypto backend
for rustls. Cross-compiling TLS to x86_64-pc-windows-gnu from a Unix worker
therefore requires the MinGW C toolchain (x86_64-w64-mingw32-gcc) even though
the asupersync source is Windows-gated.
tls-ring is another name for the same selection. tls-core compiles the TLS
code without linking any crypto provider, for applications that must not link
ring: pass a rustls CryptoProvider with crypto_provider on
TlsConnectorBuilder or TlsAcceptorBuilder, or install a process default.
Every builder resolves its provider in one order: the explicit one, then the
linked ring provider, then the process default; with none of them, building
fails with a configuration error. Asupersync's own TLS tests use ring and run
with tls.
src/net/dns/ provides async DNS resolution with address-family selection. src/net/udp.rs provides async UDP sockets with send/receive and cancellation safety.
src/transport/ covers runtime-level delivery behavior above raw sockets and below protocol clients:
router.rs tracks endpoint health and routing state with atomics (EndpointState, connection counters, failure counters) and uses RAII guards for active connection/dispatch accounting, including cancel/panic paths.aggregator.rs handles multipath symbol intake with dedup windows, reorder handling, and per-path statistics for loss/duplicate tracking.sink.rs and stream.rs use queued waiters with atomic flags and explicit wakeup bookkeeping to avoid lost-wakeup edge cases in bounded channel transport.sink.rs deduplicates waiter updates with Waker::will_wake checks and re-checks capacity after waiter registration, which closes the capacity-check/registration lost-wakeup race (src/transport/sink.rs).src/transport/mod.rs).Asupersync includes async clients for three databases, each respecting structured concurrency and cancellation.
| Database | Location | Wire Protocol | Auth |
|---|---|---|---|
| SQLite | src/database/sqlite.rs | Blocking pool bridge | N/A |
| PostgreSQL | src/database/postgres.rs | Binary protocol v3 | SCRAM-SHA-256 |
| MySQL | src/database/mysql.rs | MySQL wire protocol | caching_sha2 by default; mysql_native_password only with the explicit insecure_legacy_mysql_native_password opt-in (SHA-1 exchange, fail-closed otherwise) |
All three support prepared statements, transactions, and connection reuse. SQLite operations run on the blocking thread pool (since rusqlite is synchronous) with cancel-safe wrappers that respect region deadlines. PostgreSQL and MySQL implement their wire protocols directly over TcpStream, avoiding external driver dependencies.
The sqlite feature uses rusqlite with bundled SQLite for predictable local
behavior. Native Windows builds work with the normal platform C toolchain;
cross-compiling to x86_64-pc-windows-gnu also needs MinGW available because
libsqlite3-sys compiles the bundled SQLite C source.
src/runtime/blocking_pool.rs enforces several invariants that matter under cancellation and panic-heavy workloads:
min_threads.Asupersync's distributed runtime surface is designed around the same
invariants as local execution: explicit ownership, explicit cancellation, and
deterministic state transitions. The core crate ships the remote
protocol/state-machine surface, capability, lease, idempotency, saga contracts,
the native TCP+mTLS V3 client/service transport, and NativeRemoteRuntime.
Unix builds can additionally enable remote-service to run a supported static
process host. That host binds the built-in asupersync.remote.echo.v1
diagnostic computation to an exact protocol/registry fingerprint and explicit
certificate-pinned peer grants. Service schema v2 makes non-loopback exposure
an explicit fail-closed policy, and a terminal two-worker RCH acceptance run
has exercised the packaged service and probe across distinct hosts. Applications
can reuse the same strict TOML, mutual-TLS, SPKI, grant, listener, and drain
boundary around a caller-provided statically linked RemoteComputationRegistry
through RemoteComputationServiceBootstrap; the packaged CLI remains the echo
diagnostic host. A caller-owned NativeRemoteDiscoveryDriver can actively poll
an existing Discover<Key = SocketAddr> source and refresh one authenticated
route without detaching work or replacing unrelated destinations. Dynamic
plugins or code shipping, route persistence, restart-durable idempotency, and
production WAN reliability remain open deployment concerns rather than blanket
core-runtime claims.
RemoteComputationClient::from_bootstrap_endpoints accepts an ordered, unique,
nonempty static endpoint set while the existing new and endpoint APIs retain
their single-primary behavior. The finite attempt budget rotates that set only
for transient TCP or TLS establishment failures before request publication.
Cancellation, attempt timeout, certificate/name/pin rejection, authenticated
framing/session failure, EOF, and any delivery-ambiguous result fail closed on
the current endpoint. NativeRemoteRuntime inherits this behavior from its
configured route client. This constructor is static bootstrap failover; active
refresh requires the explicit driver below and still is not a load-balancing or
general multi-host/WAN claim.
Callers that already own a Discover<Key = SocketAddr> source can still poll it
manually and convert its current snapshot with
RemoteComputationClient::with_discovered_endpoints or
NativeRemoteRoute::with_discovered_endpoints. The returned value preserves
the original server name, trust roots, client identity, enforcing pins, wire
limits, retry policy, destination, and V3 hello; empty or duplicate snapshots
fail before NativeRemoteRuntime::replace_routes can advance its generation.
For structured active refresh, construct NativeRemoteDiscoveryDriver with an
Arc<NativeRemoteRuntime>, one logical destination, an Arc discovery source,
and a finite nonzero polling/retry policy, then await run(&cx) in a caller-owned
region task. The first poll is immediate. Synchronous source polling runs on the
supplied context's blocking pool and is awaited to completion; a context without
that authority is refused before polling, so the owning runtime needs a pool (the
RuntimeBuilder default, not blocking_threads(0, 0)). Cancellation stops future polls but
can wait for the current source poll, so production sources must bound their own
poll. Source errors and empty, duplicate, or invalid snapshots retain the
last-known-good route. A changed valid snapshot atomically replaces only that
destination, while unchanged snapshots do not advance the route generation and
a removed destination terminates rather than being resurrected. The driver does
not persist routes, choose a health policy, reload configuration/certificates,
or establish general WAN reliability.
| Primitive | Location | Runtime Behavior |
|---|---|---|
| Named remote spawn | src/remote.rs | spawn_remote creates a region-owned RemoteHandle; attached runtimes send protocol messages, while missing runtimes fail closed to an explicit deterministic fallback |
| Lease obligations | src/remote.rs | Leases are obligation-backed and participate in region close/quiescence |
| Idempotency store | src/remote.rs | Deduplicates spawn retries for the in-flight operation lifetime plus a bounded terminal-result retention window, with conflict detection |
| Session-typed protocol | src/remote.rs | Typestate model (OriginSession/RemoteSession) of the legal spawn/ack/cancel/result/renewal transitions; NativeRemoteRuntime does not drive it yet |
| Logical-time envelopes | src/remote.rs | Protocol messages carry logical clock metadata for causal correlation |
| Saga compensations | src/remote.rs | Forward steps and compensations are tracked as a structured rollback flow for distributed workflows |
| Native V3 runtime | src/remote.rs | NativeRemoteRuntime maps region-owned remote handles onto bounded TCP+mTLS sessions, supports ordered static pre-delivery bootstrap failover plus caller-owned single-destination discovery refresh, propagates cancel/lease traffic, and drains owned operations during close |
| Configured application service | src/remote.rs | RemoteComputationServiceBootstrap consumes a caller registry, validates strict schema-v2 exposure/TLS/SPKI/grants before bind, then returns the existing structured service plus deterministic full-registry identity |
| Static service process | asupersync --config ... remote serve | Unix remote-service feature; strict TOML, mutual TLS, certificate-bound grants, flushed readiness/terminal records, SIGINT/SIGTERM drain, and second-signal force-close |
The transport surface is deliberately separated from protocol state machines,
so message semantics can be tested independently of network backend details.
The authenticated service JSON envelopes are strict for protocol V1, V2, and
V3: requests, nested hellos, budgets, typed runtime IDs, depth-bounded recursive
cancellation reasons, outcomes, responses, and V3 control messages reject unknown fields.
Exact encoder goldens in
tests/remote_transport_lifecycle_contract.rs pin every shipped envelope and
variant. A field, tag, type, or ordering change therefore requires a deliberate
new protocol version; additive same-version fields are not silently ignored by
older peers.
tests/remote_transport_lifecycle_contract.rs proves that a TCP-backed
RemoteRuntime adapter preserves spawn/result, cancellation before ack,
cancellation while running, lease renewal, lease expiry, idempotency replay,
send failure, receive EOF, malformed envelope cleanup, delayed ack ordering,
capability denial, and deterministic no-runtime fallback behavior.
The same contract causally verifies a refused primary followed by one
authenticated secondary dispatch for both direct V1 calls and the V3 native
runtime, finite multi-endpoint exhaustion, cancellation before a later dial,
and enforced pin mismatch without endpoint fallthrough.
These goldens and refusals freeze the current process boundary, but do not by
themselves prove interoperability between archived binary releases, durable
idempotency across restart, or multi-host/WAN policy and operation.
Build the asupersync binary with the additive remote-service feature, then
provide an explicit versioned TOML file. Relative certificate paths resolve
from the configuration file's directory. Unknown fields, unsupported protocol
or schema versions, zero resource limits, empty grants, duplicate peer IDs,
invalid pins, unknown computations, and unreadable/empty TLS material all fail
closed. Service schema v2 also requires a literal socket address and an exact
exposure decision: loopback_only accepts only loopback addresses, while
network accepts only non-loopback or wildcard addresses. Hostnames are
refused so DNS cannot silently change the exposure boundary. Nonzero
TLS-handshake and initial-frame deadlines prevent unauthenticated or silent
authenticated sockets from retaining every connection slot.
schema_version = 2
protocol = "3.0"
listen = "127.0.0.1:7443"
listen_scope = "loopback_only"
server_certificate_chain = "/run/secrets/remote-server.crt"
server_private_key = "/run/secrets/remote-server.key"
client_ca_bundle = "/run/secrets/client-ca.crt"
max_frame_bytes = 1048576
max_connections = 256
tls_handshake_timeout_ms = 5000
initial_frame_timeout_ms = 5000
drain_timeout_ms = 30000
idempotency_retention_ms = 300000
max_idempotency_records_per_peer = 1024
[[peers]]
node_id = "origin-a"
spki_sha256 = ["BASE64_ENCODED_32_BYTE_SPKI_SHA256"]
computations = ["asupersync.remote.echo.v1"]
asupersync --format stream-json --config /etc/asupersync/remote.toml remote serve
The CLI deliberately registers only the diagnostic echo operation. An embedded application can host its own statically linked named computations through the same strict boundary without rebuilding TLS, pin, grant, listener, or drain plumbing:
let mut computations = RemoteComputationRegistry::new();
computations.register::<Request, Response, _, _>(
"orders.reconcile.v1",
|_cx, invocation| async move { reconcile(invocation).await },
)?;
// Synchronous preparation validates the complete file, TLS material, pins,
// and every configured name against this consumed executable registry. It
// opens no socket.
let bootstrap = RemoteComputationServiceBootstrap::from_toml_file(
"/etc/asupersync/remote.toml",
computations,
)?;
let (service, identity) = bootstrap.bind().await?;
let operator = service.handle();
let report = service.run(cx).await?;
identity.computations() is the complete registry in deterministic sorted
order, not the union or ordering of peer grants; its fingerprint is the exact
registry fingerprint enforced during admission. A configured name absent from
the supplied registry returns a typed UnknownComputation preparation error
before bind. A registered handler omitted from a peer's allowlist remains in
the identity but is refused before dispatch. Applications remain responsible
for publishing/flushing their own readiness record and for retaining the
service handle used to drain or force-close.
For an intentional cross-host listener, use a literal private/public or
wildcard address with listen_scope = "network". That opt-in prevents an
accidental localhost-to-network promotion; it does not configure host
firewalls, routing, DNS, certificates, load balancing, or production WAN
reliability. Those remain deployment-owned prerequisites.
The schema-v2 acceptance run hosted the packaged service on hz3 and the
packaged probe on hz4. Mutual TLS and both SPKI policies admitted one exact
23-byte echo with SHA-256
25250ce86841943e3b4f69558860a0919c455b4da4d8a6d2197d3f1b4396dc1c;
the service then handled SIGTERM and reported one accepted/completed connection,
zero active/failed/interrupted/panicked connections, and a successful RCH job
exit. This is concrete two-host fleet-path evidence, not a claim that arbitrary
firewalls, routes, certificate deployments, or production WANs are healthy.
The same feature also packages the client half as an authenticated deployment probe. Its configuration is separate from the service configuration: every route, trust anchor, client identity, enforcing server pin, pre-accept attempt timeout, post-accept completion timeout, retry bound, and lease is explicit. Bootstrap entries are literal socket addresses and are tried in order only for failures proven to precede request delivery.
schema_version = 1
protocol = "3.0"
bootstrap_endpoints = ["10.0.0.11:7443", "10.0.0.12:7443"]
server_name = "remote.internal.example"
server_ca_bundle = "/run/secrets/remote-server-ca.crt"
client_certificate_chain = "/run/secrets/origin-a.crt"
client_private_key = "/run/secrets/origin-a.key"
server_spki_sha256 = ["BASE64_ENCODED_32_BYTE_SPKI_SHA256"]
origin_node = "origin-a"
max_frame_bytes = 1048576
connect_timeout_ms = 5000
tls_handshake_timeout_ms = 5000
attempt_timeout_ms = 30000
completion_timeout_ms = 30000
max_attempts = 2
initial_backoff_ms = 50
max_backoff_ms = 1000
lease_ms = 30000
full_jitter = true
tcp_nodelay = true
asupersync --format stream-json --config /etc/asupersync/remote-probe.toml \
remote probe --payload deployment-ready
Success emits one remote_probe_completed record containing the correlated
task ID, echoed byte count, and SHA-256 digest; the payload and private-key
material are not repeated in the receipt. TLS identity or pin failure stops on
the current endpoint, and delivery-ambiguous timeout, cancellation, framing,
or transport loss is never replayed against a later endpoint. The command is a
bounded probe of the compiled-in asupersync.remote.echo.v1 operation, not a
generic remote-code client.
The process flushes a remote_service_ready record only after the listener is
bound. The first SIGINT or SIGTERM closes admission and drains structured
connection work; a second signal force-closes it. Successful exit follows a
remote_service_stopped record with terminal connection, drain, and phase
accounting. V3 deduplication is authenticated-peer scoped but process-local:
after a restart, callers must not retry an operation whose delivery outcome is
ambiguous. The packaged host is a reference process boundary for the compiled-in
echo operation; the library bootstrap supports caller-registered statically
linked handlers, not dynamic plugin loading, closure shipping, code generation,
service discovery, or restart-durable execution.
Treat the opt-in Unix remote-service binary as a static, restart-based service;
it has no hot-reload or live migration contract. Keep the last-known-good binary,
strict service/probe configuration, certificate set, and routing state together
as one deployment unit. To roll back, first remove the instance from external
traffic, send one SIGTERM, and wait for the flushed remote_service_stopped
record with zero active connections. If the configured drain deadline expires,
a second SIGTERM force-closes remaining work; record every affected operation as
delivery-ambiguous and do not replay it automatically.
Restore the complete prior deployment unit, start the prior binary, wait for its
flushed remote_service_ready record, and run remote probe with a new task
identity before returning traffic. Never infer success from process startup
alone, mix old and new certificates or route policy, reuse an in-flight task ID,
or retry work whose pre-rollback delivery outcome is unknown. Listener
idempotency is process-local, so rollback does not recover or deduplicate work
from the replaced process. If either terminal quiescence or the post-rollback
probe cannot be established, keep the instance out of service and escalate
rather than guessing.
| Channel | Location | Pattern | Cancel-Safe |
|---|---|---|---|
| MPSC | src/channel/mpsc.rs | Multi-producer, single-consumer | Two-phase send (reserve/commit) |
| Oneshot | src/channel/oneshot.rs | Single send, single receive | Two-phase send |
| Broadcast | src/channel/broadcast.rs | Fan-out to subscribers | Waiter cleanup on drop |
| Watch | src/channel/watch.rs | Last-value multicast | Always-current read |
| Session | src/channel/session.rs | Typed RPC with reply obligation | Reply is a linear resource |
The two-phase pattern separates reservation from publication. Dropping an
uncommitted permit aborts the reservation and releases its capacity. Inspect
the commit outcome: for MPSC, SendPermit::send returns
Outcome::Err(SendError::Disconnected(value)) with the original value if the
receiver has gone away. A successful commit publishes the message to the
channel; application consumption still depends on the receiver making progress.
| Primitive | Location | Notes |
|---|---|---|
| Mutex | src/sync/mutex.rs | Fair, cancel-safe (contention metrics: ContendedMutex) |
| RwLock | src/sync/rwlock.rs | Writer preference with reader batching |
| Semaphore | src/sync/semaphore.rs | Counting, with permit-as-obligation model |
| Barrier | src/sync/barrier.rs | N-way synchronization point |
| Notify | src/sync/notify.rs | One-time or multi-waiter notification |
| OnceCell | src/sync/once_cell.rs | Async one-time initialization |
| ContendedMutex | src/sync/contended_mutex.rs | Mutex with contention metrics |
| Pool | src/sync/pool.rs | Object pool with obligation-tracked checkout and return-on-drop |
The synchronization primitives are deterministic under the lab runtime and
their wait queues/guards have focused cancellation and cleanup coverage.
Futurelock detection and the obligation-leak oracle observe obligations
recorded in the runtime's obligation table (RuntimeState::create_obligation).
Stock mpsc, oneshot, and broadcast send permits reserved through a
runtime-built Cx register a SendPermit through the obligation mailbox;
sending commits it, while aborting or dropping an unsent permit aborts it.
Semaphore permits likewise register a SemaphorePermit, discharged when
capacity is released. A permit that escapes its task through mem::forget
is reported by the obligation_leak oracle by kind and holder. The lab also
detects a task parked while holding a semaphore permit as a futurelock
(tests/channel_permit_runtime_obligations_e2e.rs). A Cx built without a
runtime keeps the untracked behavior. Session-tracked permits
(src/channel/session.rs) and database transaction tokens remain standalone
typestate tokens (ObligationToken<K>) that those oracles do not see. Mutex
and RwLock guards release on drop and have guard/queue cleanup tests, but
they are not obligations either.
Beyond join, race, and timeout, the combinator library includes patterns for distributed systems and resilience:
| Combinator | Location | Purpose |
|---|---|---|
| quorum | Scope::quorum (src/cx/scope.rs) + src/combinator/quorum.rs | M-of-N completion: spawns every branch, returns once M succeed or success is impossible, then cancels and drains every remaining branch |
| hedge | Scope::hedge (src/cx/scope.rs); the hedge() future in src/combinator/hedge.rs | Start backup after delay, first response wins. Scope::hedge aborts and joins the loser; the standalone hedge() future drops it |
| first_ok | Scope::first_ok (src/cx/scope.rs) + src/combinator/first_ok.rs | Try lazy operations sequentially until one succeeds; an in-flight attempt is drained on cancellation |
| pipeline | Scope::pipeline (src/cx/scope.rs) + src/combinator/pipeline.rs | Executes typed, channel-connected stages and an async sink as scoped tasks, with explicit edge capacities and an overall admitted-work limit |
| map_reduce | Scope::map_reduce (src/cx/scope.rs) + src/combinator/map_reduce.rs | Spawns bounded scoped map tasks and reduces in input order, with separate limits for concurrency and retained work |
| circuit_breaker | src/combinator/circuit_breaker.rs | Failure detection, open/half-open/closed states |
| bulkhead | src/combinator/bulkhead.rs | Concurrency isolation (bounded parallelism) |
| rate_limit | src/combinator/rate_limit.rs | Token bucket throughput control |
| bracket | src/combinator/bracket.rs | Acquire/use/release with guaranteed cleanup |
| retry | src/combinator/retry.rs | Exponential backoff, budget-aware |
Use PipelineExecutionConfig with .pipeline(...).then(...).run(...).await, or
MapReduceLimits with .map_reduce(...).await. The existing outcome-fold APIs
remain available. Retained-work credit includes completed maps waiting for an
earlier input; pipeline credit remains held until the sink consumes the item.
These limits count work items, not payload bytes or the reducer's accumulator.
Errors, panics and cancellation stop admission and drain admitted children
before returning. A noncooperative child keeps the operation pending; dropping
the operation requests cancellation while its region retains cleanup ownership.
The downstream consumer
exercises both APIs with public default features on current-thread and
two-worker native runtimes, including exact ordered output and shutdown checks.
The core combinators publish cancel-safety contracts, and race/select-style winners drain losers through dedicated drain paths. Outcomes aggregate via the severity lattice. An explicit law sheet (src/combinator/laws.rs) documents algebraic properties (associativity, commutativity, distributivity), while the rewrite engine (src/plan/rewrite.rs) optimizes only through explicit RewritePolicy gates and conservative src/plan/analysis.rs side-condition checks. Unknown, MayLeak, or MayOrphan analysis results are not proof that a rewrite preserves cancel/drain/quiescence invariants.
src/raptorq/ implements RFC 6330 systematic RaptorQ codes, a fountain code where any K-of-N encoded symbols suffice to recover the original K source symbols. Its production consumer today is the ATP file-transfer data plane. The distributed snapshot-distribution model in src/distributed/ encodes region state into symbols, assigns replicas via consistent hashing, and supports quorum recovery. On native targets with tls, RemoteSymbolTransport implements DistributorTransport over authenticated mTLS sessions and bounded symbol storage. Cross-process scenarios live in tests/distribution_hedge_process.rs and tests/symbol_durable_process.rs; their presence does not establish current test success, arbitrary Rust-future migration, or general production-WAN reliability.
| Module | Purpose |
|---|---|
rfc6330.rs | Standard-compliant parameter computation |
systematic.rs | Systematic encoder/decoder |
gf256.rs | GF(2^8) arithmetic (addition, multiplication, inversion) |
linalg.rs | Matrix operations over GF(256) |
pipeline.rs | Full sender/receiver pipelines with symbol authentication (verify_auth; fail-closed). The production transport_rq transport now forces a deliberate posture choice — see asupersync-e880xo |
proof.rs | Decode proof system for verifiable recovery |
The implementation is deterministic (no randomness in lab mode) and can integrate with the security layer (src/security/) for per-symbol authentication tags (fail-closed when verify_auth is enabled — forged/contextless symbols are rejected). REALITY (asupersync-e880xo): the production ATP RaptorQ transport (src/net/atp/transport_rq) is now fail-closed on symbol-auth posture: a default RqConfig is MissingAuthenticationContext, so callers must deliberately choose with_symbol_auth(ctx) (every UDP symbol is signed and verified) or the explicit allow_unauthenticated_for_trusted_transport() opt-out (integrity-vs-manifest only). send_path refuses before any network I/O; receive_once rejects an accepted connection before any handshake, UDP exchange, or data transfer. The handshake additionally rejects any posture mismatch between peers in both directions. NO-CLAIM BOUNDARY: authenticated mode protects the UDP symbol plane only; the TCP control channel + manifest are still unauthenticated, and the sibling transport_tcp transport has no per-symbol authentication at all (integrity-vs-manifest only). Full Byzantine-injection prevention against an active MITM therefore requires with_symbol_auth AND an authenticated control channel/manifest (e.g. TLS) — otherwise a MITM can substitute a matching forged manifest + symbols. Pinned end-to-end by tests/atp_rq_symbol_auth_e2e_contract.rs (transport truth) and tests/decoding_secure_default.rs (config posture).
On the decode side, the runtime uses a policy-driven deterministic planner instead of a single fixed elimination strategy:
src/raptorq/decoder.rs).src/raptorq/decoder.rs, src/raptorq/proof.rs, src/raptorq/test_log_schema.rs).src/raptorq/decoder.rs).simd-intrinsics (src/raptorq/gf256.rs).Use the deterministic E2E wrapper with --bundle to run staged unit/perf-smoke gates plus scenario coverage with a single command:
# Fast smoke (unit sentinel + perf smoke + fast scenario profile)
NO_PREFLIGHT=1 ./scripts/run_raptorq_e2e.sh --profile fast --bundle
# Full profile
NO_PREFLIGHT=1 ./scripts/run_raptorq_e2e.sh --profile full --bundle
# Forensics profile (includes additional repair_campaign perf smoke)
NO_PREFLIGHT=1 ./scripts/run_raptorq_e2e.sh --profile forensics --bundle
Operational notes:
rch when available for Cargo test, benchmark, and scenario-test stages.--profile supports fast|full|forensics; --scenario <ID> can target one deterministic scenario.summary.json, scenarios.ndjson, and (when bundled) validation_stages.ndjson.VALIDATION_TIMEOUT or E2E_TIMEOUT if your environment is slower than expected.Every number below comes from the committed scorecard
artifacts/atp_bench_matrix/20260902T151751Z/scorecard.md
(ovh-a netns harness, release atp 0.4.10, atp-quic-tls13 vs optimally
tuned rsync-ssh-aes128gcm, SHA-256 verified every rep, median wall
seconds). The append-only record of every run and refuted hypothesis is
docs/atp_rq_beat_rsync_ledger.md.
| workload | regime | atp-quic-tls13 | rsync-ssh-aes128gcm | ATP/rsync |
|---|---|---|---|---|
| 50M | perfect (2 ms, 1 Gbit) | 0.651 s | 0.837 s (noisy) | 0.78 |
| 50M | good | 3.353 s | 3.838 s | 0.87 |
| 50M | bad (80 ms, 2 % loss, 50 Mbit) | 13.959 s | 17.346 s | 0.81 |
| tree_small | perfect | 2.953 s | 0.736 s | 4.01 |
| tree_small | good | 3.553 s | 2.037 s | 1.74 |
| tree_small | bad | 5.956 s | 7.341 s (noisy) | 0.81 |
Read it plainly: encrypted ATP is faster than rsync-over-ssh on lossy links
and on a single large file, and slower on small trees over clean links
(per-file overhead dominates a sub-second rsync). It also uses 1.6–2.1×
rsync's sender memory. Across real WAN paths the picture is worse for QUIC:
the dated cross-machine receipt
artifacts/atp_bench_matrix/wan_quic_receipt_2026-09-02.md
(Hetzner Ashburn → Contabo France, SHA-256 verified on both ends) shows
ATP-over-QUIC at 6.3 MB/s where ATP-over-TCP reaches 20 MB/s on the same
path, so the QUIC sender is window-limited at ~90 ms RTT. No unqualified
"beats rsync" claim is made for the encrypted tier.
atp bond-pull)RaptorQ's fountain property — any K-of-N symbols recover the K source symbols — makes it natural to pull a single object from many donors at once. In a bonded transfer, one receiver enrolls N donors; each donor is assigned a disjoint slice of the symbol stream (source + repair ESIs) and sprays it over UDP, and the receiver decodes from the union. The aggregate goodput is the sum of the donors' upload paths, and because symbols are order-independent, a donor that dies mid-transfer costs nothing but its remaining repair window, which is reallocated to the survivors (src/net/atp/bonding/, src/net/atp/transport_rq/bonded.rs).
Content agreement is fail-closed and the descriptor is never on the wire. The receiver and every donor independently derive the bonded descriptor (transfer-id, merkle root, per-entry object IDs, portable metadata commitment) from their own local bytes via the same derivation; enrollment rejects on any transfer-id / merkle-root / metadata / symbol-size / max-block-size mismatch (src/net/atp/bonding/derive.rs, enrollment checks in transport_rq/bonded.rs). A donor whose bytes have drifted cannot enroll, so it cannot corrupt the decode. Per-symbol authentication posture (RaptorQ symbol-auth key, or the explicit unauthenticated-lab opt-out) is the same deliberate, fail-closed choice as the single-source RaptorQ transport above.
The receiver-orchestrated CLI is one command:
# Receiver pulls /srv/payload from two donors, advertising its control endpoint.
atp bond-pull /srv/payload /dest --donors alice@h1,bob@h2 \
--advertise 203.0.113.7:8473 --rq-auth-key-hex "$KEY"
bond-pull starts the in-process bonded receiver, SSH-launches one bond-donate leg per donor host, and waits for the fail-closed commit — SHA/merkle-verified before anything lands in /dest.
Per-donor transport selection (--transport auto|tailscale|ssh|ip): each donor's tailnet membership is probed over ssh, then a dial path is chosen per donor (src/net/atp/bonding/transport_select.rs). auto prefers a shared Tailscale path (CGNAT 100.64.0.0/10) when both ends are on the tailnet, else a direct IP; ip/tailscale force a family; ssh tunnels the symbol stream. (The live ssh -L forward is the remaining real-multi-host step, tracked under z01bbr.8.3; today an ssh-selected leg reports its tunnel plan and falls back to a direct dial.) The chosen path per donor is recorded in the atp_bond_pull JSON receipt so a run is auditable after the fact.
Programmatic use — the BondedTransfer SDK builder drives a real bonded transfer over the same data path, cancel-correctly:
use asupersync::net::atp::sdk::BondedTransfer;
// Receive to completion and get the final report:
let report = BondedTransfer::receive(dest, local_src)
.expect_donors(2)
.listen("0.0.0.0:8473".parse()?)
.auth_key_hex(key_hex)
.run(&cx)
.await;
// Or spawn as an owned child and stream live progress:
let mut handle = BondedTransfer::receive(dest, local_src)
.expect_donors(2)
.spawn(&cx)?;
let addr = handle.control_addr().await; // bound control endpoint for donors
while let Some(p) = handle.next_progress().await { // per-donor ingress, blocks remaining, feedback rounds
println!("{:.0}% ({}/{} blocks)", p.progress_percent(), p.blocks_total - p.blocks_remaining, p.blocks_total);
}
let outcome = handle.wait_for_completion().await; // AtpOutcome: Ok / Err / Cancelled / Panicked
spawn runs the receiver as an owned child of the Cx's region; handle.cancel() aborts it and the child unwinds to quiescence committing nothing (a final cx.checkpoint() guards even the last instant before the irreversible commit). The progress stream emits a terminal Completed on success or Failed on a verification failure; cancellation and other terminal errors are observed as the stream closes plus the join outcome.
src/stream/ provides a composable stream library with the standard functional operators: map, filter, take, skip, chunks, chain, merge, zip, fold, for_each, inspect, enumerate, any_all, count, fuse, buffered, and try_stream. Streams integrate with channels (broadcast_stream, receiver_stream) and participate in cancellation; a dropped stream cleanly aborts any pending I/O.
The lab runtime includes dedicated failure detectors and recovery artifacts, so concurrency failures carry structured evidence instead of vague timeouts.
futurelock_max_idle_steps. Detection emits TraceEventKind::FuturelockDetected with task, region, and held-obligation details, and can optionally panic immediately (panic_on_futurelock) (src/lab/runtime.rs, src/lab/config.rs).verify_integrity()), plus structural validation (validate()) that checks reference validity, region-tree acyclicity, closed-region quiescence, and timestamp consistency before restore (src/lab/snapshot_restore.rs).src/lab/chaos.rs, src/lab/config.rs, src/lab/runtime.rs).src/lab/runtime.rs, src/trace/crashpack.rs).src/observability/entry.rs defines LogEntry with span IDs, task IDs, region context, and structured fields. Log levels (Trace through Error) are separate from cancellation severity. The LogCollector batches entries for export.
src/observability/metrics.rs provides Counter, Gauge, and Histogram abstractions with a zero-allocation hot path. Optional OpenTelemetry integration (src/observability/otel.rs) exports to any OTLP-compatible backend. Multiple exporters (stdout, in-memory for tests, null for benchmarks) can compose via MultiExporter.
src/observability/task_inspector.rs introspects live task state: obligation holdings, poll counts, wait dependencies, and cancellation status. src/observability/diagnostics.rs produces structured explanations: CancellationExplanation traces the full cancel propagation chain, TaskBlockedExplanation identifies what a task is waiting on, and ObligationLeak pinpoints which obligation was not resolved and by whom.
For structural runtime risk, diagnostics also maintain a spectral health monitor over the live task wait graph (src/observability/spectral_health.rs, src/observability/diagnostics.rs). It tracks the Fiedler trend and classifies early-warning severity (none/watch/warning/critical) using a multi-signal ensemble: autocorrelation (critical slowing), variance growth, flicker, skewness, Kendall tau, Spearman rho, Hoeffding's D, distance correlation, split-conformal lower bounds, and an anytime-valid deterioration e-process.
asupersync-macros/ provides proc macros for ergonomic structured concurrency:
use asupersync::{join, race, scope, spawn, Cx};
use asupersync::runtime::RuntimeState;
async fn macro_example(cx: &Cx, state: &mut RuntimeState) {
// `join!` awaits futures side by side and returns all their outputs.
let (a, b) = join!(worker_a(), worker_b());
// `spawn!` inside `scope!` creates region-owned tasks; the scope does not
// return until they are done. A `TaskHandle` is not a future to `join!`.
scope!(cx, state: state, {
let _task = spawn!(async { worker_a().await });
});
// Each branch gets its own child `Cx`, so a losing branch observes its
// cancellation and is drained before `race!` returns.
let winner = race!(cx, {
move |child| task_a(child),
move |child| task_b(child),
});
let _ = winner;
}
These macros are available in the default feature set. The default production
feature set is intentionally limited to proc-macros plus
nightly-outcome-try plus the empty compatibility markers runtime-core and
native-runtime; test-only internals are opt-in. The markers gate nothing yet.
They are on by default so that default builds keep those modules when the planned
runtime split puts them behind the markers. If you opt out of default features
for a minimal core-only build, re-enable proc-macros explicitly.
Current contract:
proc-macros builds are scope!, spawn!, join!, join_all!, race!, and select!; the root also exports the #[main], #[test], and #[lab_test] entry attributes.scope! binds a Scope for the current region; it does not create a fresh child-region boundary. Use Scope::region(...) when you need quiescence on scope exit.spawn! requires runtime state (state: &mut RuntimeState or ambient __state) in addition to Cx.join! and join_all! pin every branch once and poll all unfinished branches concurrently inside one poll_fn; neither macro serializes branches.race! expands only to the drain-correct Cx::race_drained* family: spawned losers are protocol-cancelled and drained before return. Prefer the factory form (move |child| work(child)), where each branch receives its own child Cx: loser cancellation targets the branch's task, so a prebuilt branch awaiting on the caller's cx never observes it and the drain waits for that branch to finish on its own. Each branch runs in its own child region, so the drain also cancels and awaits the tasks a losing branch spawned through its own Cx; tasks the winner spawned keep running and its region closes once they finish (a caller region with admission limits keeps branches in that region instead). On a race! timeout: expiry, the factory form cancels and drains every branch and returns Err(JoinError::Cancelled(_)); the prebuilt form abandons the race by drop.select! is also drain-correct; its else form instead polls each branch exactly once in source order, returns immediately, and drops all still-pending branches without draining.race! and blocking select! must be Send + 'static, and the Cx must carry spawn authority. The direct Cx::race, race_named, race_timeout and race_timeout_named calls also take boxed Send + 'static futures; they are the lower-level surface that drops the losing futures when the race ends instead of draining them.proc-macros do not have a usable macro DSL fallback: join! and race! intentionally fail with compile_error!, while scope!, spawn!, join_all!, and select! are unavailable until proc-macros is re-enabled.Compile-fail tests (via trybuild) verify that incorrect usage produces clear
error messages. See docs/macro-dsl.md for the full pattern catalog.
Current reality: the Cargo-compiled conformance registry for this repository is
the integration-test entrypoint at tests/conformance.rs, which includes the
live module list from tests/conformance/mod.rs. Do not copy the registry
counts into prose: the checked source of truth is
artifacts/conformance_registry_contract_v1.json, and
tests/conformance_registry_contract.rs verifies that its active and dormant
module lists still match tests/conformance/mod.rs. Some active entries or
result lanes are gated by mysql, quic, tls, or platform-specific cfgs.
The active registry covers:
Cx capability contractsImportant limitation: the repository also preserves conformance files on disk
that are not part of the live registry today. tests/conformance/mod.rs
leaves explicit commented-out pub mod entries for known bit-rot,
superseded-suite, relocated-suite, or unresolved-dependency follow-ups. Do not
infer dormancy from an on-disk filename or a prose list: the contract artifact
records every current dormant module's disposition, owner bead or supersession
path, and retention reason. Those files remain in-tree for repair work, but
they do not compile or run through this registry until they are re-wired in
tests/conformance/mod.rs (or through the explicitly recorded replacement
lane).
The separate conformance/ workspace member still exists for standalone
vendor/spec harnesses, but it should not be read as proof that every
disk-resident file under tests/conformance/ is active in CI.
Volatile project facts such as LOC totals, workspace-member counts, conformance
registry counts, and roadmap status are audited in
provider_audit_log.md. Treat live command output
and checked contract artifacts as the source of truth for those values.
Related test and CI entrypoints include:
scripts/run_all_e2e.sh (orchestrated suite execution and summary checks)scripts/run_raptorq_e2e.sh (RaptorQ deterministic scenarios)scripts/run_phase6_e2e.sh (phase-6 integration surface)scripts/check_no_mock_policy.py (no-mock/fake/stub policy gate)scripts/check_coverage_ratchet.py (coverage regression ratchet)scripts/check_wasm_flake_governance.py (WASM flake/quarantine/forensics release gate)These scripts are broader repository gates, not a substitute for the live
tests/conformance/mod.rs registry when you need the exact wired-vs-dormant
coverage picture.
Tests emit deterministic artifact bundles (event_log.txt,
failed_assertions.json, repro_manifest.json) when
ASUPERSYNC_TEST_ARTIFACTS_DIR is set, and the E2E runners emit JSON summaries
for replay automation.
Spork is an OTP-style layer built on Asupersync's kernel guarantees: regions (structured concurrency), obligations (linearity), explicit cancellation, and the deterministic lab runtime.
| OTP Concept | Spork / Asupersync Interpretation |
|---|---|
| Process | A region-owned task/actor (cannot orphan) |
| Supervisor | A compiled, deterministic restart topology over regions (boot ordering, dependencies, shutdown budgets). CompiledSupervisor::bind_managed runs it live: a failed child is cancelled, drained and restarted one-for-one, one-for-all or rest-for-one under a shared intensity/backoff policy (src/supervision.rs, used by src/app.rs). Actors also restart on failure individually (src/actor.rs) |
| Link | Failure propagation rule (sibling/parent coupling; deterministic) |
| Monitor + DOWN | Observation without coupling: deterministic notifications |
| Registry | Names as leases: reserve/commit or abort; dropping an unresolved lease panics (the lease is not yet a runtime-ledger obligation, so region close does not wait for it) |
| call/cast | Request/response and mailbox protocols with bounded drain on cancel |
src/supervision.rssrc/cx/registry.rssrc/spork.rs (spork::process_group)examples/spork_minimal_supervised_app.rsexamples/appspec_reference_journey.rs, with the e2e artifact runner scripts/run_appspec_reference_journey_e2e.sh (emits events.ndjson + summary.json + topology.txt)docs/spork_deterministic_ordering.mddocs/spork_glossary_invariants.mdsrc/trace/crashpack.rsAsupersync has formal semantics backing its engineering.
| Concept | Math | Payoff |
|---|---|---|
| Outcomes | Severity lattice: Ok < Err < Cancelled < Panicked | Monotone aggregation, no "recovery" from worse states |
| Concurrency | Near-semiring: join (⊗) and race (⊕) with laws | Lawful rewrites, DAG optimization |
| Budgets | Tropical semiring: (ℝ∪{∞}, min, +) | Critical path computation, budget propagation |
| Obligations | Linear-logic discipline: resources resolved exactly once (Rust is affine, so enforcement is #[must_use] + runtime leak detection, not purely static) | Leaked obligations are loudly detected at region close instead of silently dropped |
| Traces | Mazurkiewicz equivalence (partial orders) | DPOR-style guided exploration (not certified-optimal DPOR), stable replay |
| Cancellation | Two-player game with budgets | Scoped completeness when modeled responsiveness assumptions hold and budgets are sufficient |
| Adaptive scheduling | Discounted UCB1 over {4, 8, 16, 32, 64} | Opt-in dynamic preemption control with deterministic epoch updates |
| Drain certificates | Signed-step range bounds + empirical phase diagnostics | Conditional, auditable progress evidence for cancellation drain; the current-horizon tail bounds are the trivial 1, so the phase labels carry the signal |
| Structural diagnostics | Spectral graph theory + conformal + e-processes | Early warning on wait-graph fragmentation with calibrated alarms, computed on demand through Diagnostics |
See asupersync_v4_formal_semantics.md for the complete operational semantics.
Asupersync is intentionally "math-forward": it uses advanced math and theory-grade CS where it supports concrete, scoped claims such as controlled-schedule determinism, covered-surface cancel-correctness, published cleanup bounds, and reproducible concurrency debugging. The mechanisms below exist in the codebase today, but their support posture is not uniform:
| Mechanism | Current status |
|---|---|
| Discounted-UCB1 scheduler control | Implemented, default-on runtime scheduling control surface |
| Drain progress diagnostics | Implemented cancellation progress diagnostics; the HTTP/1 and HTTP/2 graceful-drain supervisor uses them, and the scheduler only with enable_governor (off by default). The current-horizon tail bounds are the trivial 1 |
| Spectral wait-graph health | Implemented observability diagnostic, computed when Diagnostics::analyze_structural_health is called; the scheduler runs its own copy only with enable_governor (off by default). Advisory early warning, not a standalone deadlock proof |
| Mazurkiewicz/Foata trace canonicalization and DPOR | Implemented lab/trace exploration machinery |
| Persistent homology trace scoring | Implemented lab exploration prototype; used to prioritize interesting schedules, not a production runtime gate |
| Sheaf-style saga consistency and TLA+ export | Implemented analysis/export APIs for verification workflows; the in-process saga executor does not run the sheaf check |
src/runtime/scheduler/three_lane.rs includes a deterministic discounted-UCB1 controller that selects cancel-streak limits from {4, 8, 16, 32, 64} at fixed epoch boundaries. It is opt-in (off by default) and updates from a bounded reward combining progress, fairness, deadline, and fallback components while an e-process monitors epoch rewards. This is a nonstationary stochastic-bandit control surface; the seeded opt-in EXP3 controller belongs to ATP transport adaptation, not scheduler preemption.
src/cancel/progress_certificate.rs models cancellation drain as a stochastic progress process with auditable evidence, diagnostic variance estimation, and conditional concentration calculations. The range-only raw Freedman candidate is never tighter than the Azuma baseline under the implemented cap, so the selected public envelope equals Azuma; realized variance is never reused as predictable variation. Both public current-horizon candidates are algebraically 1 under the same-history plug-in mean, while confidence_bound is a separate conditional projection. Verdicts include phase classification (warmup, rapid_drain, slow_tail, stalled, quiescent) plus an accepted-history empirical converging status. Neither the status nor the conditional calculations prove future drift, termination, or bounded drain time.
src/observability/spectral_health.rs computes Laplacian-spectrum diagnostics and an early-warning severity model (none/watch/warning/critical) over the live wait graph. It combines spectral trend analysis, nonparametric dependence tests, split-conformal next-step bounds, and an anytime-valid e-process, so structural degradation can be detected with calibrated confidence before hard failures.
Status: an on-demand observability diagnostic. Diagnostics::analyze_structural_health computes it when called, and the scheduler runs its own copy only with enable_governor, which is off by default. The classification is intentionally advisory: zero or falling spectral connectivity is a topology signal, while explicit trapped-cycle evidence remains a separate deadlock proof.
Instead of treating traces as opaque linear logs, Asupersync factors out pure commutations of independent events via trace theory. Two traces that differ only by swapping adjacent independent events are considered equivalent, and canonicalized to a unique representative (Foata normal form). See src/trace/canonicalize.rs.
$$ M(\Sigma, I) = \Sigma^* / \equiv_I $$
Payoff: canonical fingerprints for schedule exploration and stable replay across "same behavior, different interleaving" runs.
Given a dependency DAG (trace poset), Asupersync constructs a valid linear extension that minimizes "owner switches" (a proxy for context-switch entropy) using deterministic heuristics and an exact bounded A* solver. See src/trace/geodesic.rs and src/trace/event_structure.rs.
Payoff: smaller, more canonical traces that are easier to diff, replay, and minimize.
Asupersync includes DPOR-style race detection and backtracking point extraction, using a minimal happens-before relation (vector clocks per task) plus resource-footprint conflicts. See src/trace/dpor.rs and src/trace/independence.rs.
Payoff: systematic interleaving exploration that targets truly different behaviors instead of brute-force schedule fuzzing.
Schedule exploration is prioritized using topological signals from a square cell complex built out of commuting diamonds: edges are causality edges, squares represent valid commutations, and Betti numbers/persistence quantify "non-trivial scheduling freedom". The implementation uses deterministic GF(2) bitset linear algebra and boundary-matrix reduction. See src/trace/boundary.rs, src/trace/gf2.rs, and src/trace/scoring.rs.
Status: implemented lab exploration prototype. It feeds TopologyExplorer novelty scoring for deterministic schedule search; it is not a production scheduler policy, release gate, or runtime health alarm.
Payoff: an evidence-ledger, structure-aware notion of "interesting schedules" that tends to surface rare concurrency behaviors earlier.
In distributed obligation tracking, pairwise lattice merges can hide global inconsistency (phantom commits). Asupersync models this as a sheaf-style gluing problem and detects obstructions where no global assignment explains all local observations. See src/trace/distributed/sheaf.rs.
Status: an API you call on saga observations (SagaConsistencyChecker); nothing in the runtime runs it automatically.
Payoff: catches split-brain-style saga states that evade purely pairwise conflict checks.
The lab runtime monitors invariants (task leaks, obligation leaks, region quiescence) with e-processes (src/lab/oracle/eprocess.rs), adding one observation per run that advances the lab. Separately, src/obligation/eprocess.rs provides an obligation-leak monitor. It is opt-in: Runtime::enable_obligation_leak_monitor installs a Shiryaev–Roberts change detector that the runtime feeds with each committed or aborted obligation's age (each counted once). A leaked obligation alarms it at once, including one the Recover leak policy aborts, and the alarm latches. Runtime::obligation_leak_monitor_snapshot reads its statistic and alert state. The detector is enabled over a horizon of resolutions: for ages within the documented null, the probability of a false alarm within that horizon is at most α (its threshold is horizon/α). An obligation that is never resolved is not observed until its holder completes. The lab invariant monitors are anytime-valid e-processes: a supermartingale-based framework that supports optional stopping without "peeking penalties".
Payoff: turn long-running exploration into statistically sound monitoring, with deterministic, explainable rejection thresholds.
src/lab/conformal.rs calibrates oracle-metric thresholds with split conformal prediction, giving finite-sample, distribution-free coverage guarantees under exchangeability assumptions across deterministic schedule seeds.
Status: opt-in. ScheduleExplorer::with_conformal_calibration calibrates across explored seeds and reports the anomalous ones; no lab oracle consults the calibrator on its own.
Payoff when enabled: stable false-alarm behavior under workload drift, without hand-tuned magic constants.
Asupersync's concurrency combinators come with an explicit law sheet (severity lattices, budget semirings, race/join laws, etc.) and a rewrite engine guarded by conservative static analyses (obligation-safety and cancel-safety lattices; deadline min-plus reasoning). See src/combinator/laws.rs, src/plan/rewrite.rs, and src/plan/analysis.rs.
Status: the rewrite engine is opt-in through plan::execute::capture_optimized; no runtime path invokes it, and an executed plan race drops its losers the way Cx::race does (use Scope::race when losers must be drained).
Payoff: principled plan optimization without silently breaking cancel/drain/quiescence invariants.
Traces can be exported as TLA+ behaviors with spec skeletons for bounded TLC model checking of core invariants (no orphans, obligation linearity, quiescence). See src/trace/tla_export.rs. tests/lab_tla_export_tlc_e2e.rs exports a real LabRuntime trace and runs TLC on it (invariants NoObligationLeaks, QuiescenceOnClose, ObligationLinearity, plus a planted violation that TLC must reject); the CI job tla-tlc is defined to install Java and a sha-pinned tla2tools.jar and to fail closed if TLC is missing, but it does not run while GitHub Actions is disabled. TLC checks the recorded concrete behavior, not a parametric model of the runtime.
Payoff: bridge from deterministic runtime traces to model-checking workflows when you need "prove it", not "it passed tests".
The checked
artifacts/dependency_budget_contract_v1.json
freezes the exact direct Cargo edge allowset and package-version plus
unique-package-name ceilings for every canonical synthesized-consumer
profile/platform cell. The focused dependency-budget-contract lane verifies
the current marginal-ledger fingerprint, profile/target/host/edge-kind
partitions, automatic downward ratchet, safe direct-edge and graph-growth
negative fixtures, and the narrow reviewed-exception path. See
docs/dependency_budget_contract.md.
This contract does not authorize dependency removal or cutover and is not a
broad workspace, runtime, security, performance, or release-readiness claim.
The checked supply-chain gate is
scripts/ci/audit_dependencies.sh, with
policy and interpretation in
artifacts/dependency_supply_chain_policy_v1.json
and
docs/dependency_supply_chain_policy.md.
Its focused proof lane is dependency-supply-chain-policy-contract. The gate
requires both the root and separately tracked excluded-fuzz graphs to pass;
consult the live runner receipt for scanner evidence. The Rust contract alone
does not prove scanner execution, fuzz-target compilation or fuzz behavior.
The scoped terminal packet for the Phase-9 CI provenance campaign is
artifacts/dependency_ci_provenance_final_signoff_v1.json,
checked by the dependency-ci-provenance-final-signoff lane. It joins the
full-SHA GitHub Actions inventory, the owner-selected static-only JavaScript
package-tree receipt, fresh root/excluded-fuzz Cargo scanner evidence, the
direct-minimal downstream consumer result, and the generated AGENTS dependency
table contract. Its verdict is PASS_SCOPED_KEEP_DEFER, not release green. See
docs/dependency_ci_provenance_final_signoff.md
for replay and no-claim boundaries. The signoff grants no package-manager,
dependency-cutover, file-deletion, or local-Cargo-fallback authority.
[dependencies]
# crates.io
asupersync = "0.5.0"
# or git (main carries the unreleased 0.6.0 line; a `version = "0.5.0"`
# requirement would not match it)
# asupersync = { git = "https://github.com/Dicklesworthstone/asupersync", branch = "main" }
When migrating from 0.4.x, Cx::set_current now preserves restrictions
already held by its supplied context. Reinstalling a narrowed context no longer
restores full authority. If broader authority is intended, retain and explicitly
install the original privileged Cx. The public method signatures and ordinary
full-authority context behavior are unchanged.
Asupersync is feature-light by default; the lab runtime is available without flags.
| Feature | Description | Default |
|---|---|---|
test-internals | Expose test-only helpers (not for production) | No |
metrics | OpenTelemetry metrics provider (Tokio-free normal graph; OTLP protobuf helpers are fuzz/test-only) | No |
tracing-integration | Tracing spans/logging integration | No |
proc-macros | scope!, spawn!, join!, join_all!, race!, select!, plus #[main], #[test], and #[lab_test] | Yes |
nightly-outcome-try | Outcome Try/residual impls that enable ?; active only on a nightly compiler (on stable the crate builds without them) | Yes |
runtime-core | Compatibility marker for the planned runtime module split; gates nothing yet | Yes |
native-runtime | Compatibility marker for the planned runtime module split; a compile error on wasm32 browser builds, gates nothing else yet | Yes |
tower | Tower Service adapter support | No |
trace-compression | LZ4 compression for trace files | No |
debug-server | Debug HTTP server for runtime inspection | No |
config-file | TOML config file loading for RuntimeBuilder | No |
lock-metrics | Contended mutex wait/hold metrics | No |
io-uring | Linux io_uring reactor (kernel 5.1+) | No |
tls | TLS support via rustls | No |
tls-ring | The same as tls: TLS with the ring crypto provider | No |
tls-core | TLS code without a crypto provider; the application supplies one | No |
tls-native-roots | TLS with native root certs | No |
tls-webpki-roots | TLS with webpki root certs | No |
remote-service | Unix static RemoteRuntime V3 process host (cli + tls) | No |
sqlite | SQLite async wrapper with blocking pool bridge | No |
postgres | PostgreSQL async wire-protocol client | No |
mysql | MySQL async wire-protocol client | No |
kafka | Kafka integration via rdkafka | No |
simd-intrinsics | AVX2/NEON GF(256) kernels for RaptorQ | No |
loom-tests | Loom scheduler/concurrency verification surface | No |
cli | CLI tools (trace inspection) | No |
wasm-browser-minimal | Browser WASM: minimal semantic core | No |
wasm-browser-dev | Browser WASM: development profile with browser I/O | No |
wasm-browser-prod | Browser WASM: production profile with browser I/O | No |
wasm-browser-deterministic | Browser WASM: replay-safe with browser trace | No |
wasm-runtime | Browser runtime capability slices for WASM profile composition (implies wasm-browser-preview) | No |
wasm-browser-preview | Opt-in guard for experimental browser-targeted builds; not full WASM parity | No |
browser-io | Browser I/O capability slice for the wasm-browser-* profiles; not allowed with wasm-browser-minimal | No |
browser-trace | Browser trace capability slice; not allowed with wasm-browser-minimal | No |
deterministic-mode | Replay-safe deterministic timestamps for lab oracles and the deterministic browser profile | No |
desktop-runtime-profile | Bounded runtime configuration for native desktop hosts | No |
quic | Native, Tokio-free QUIC transport surfaces | No |
http3 | Native HTTP/3 (http::h3, http::h3_quic); implies quic | No |
http2-streaming | Live HTTP/2 request ingress with bounded body queues and consumption-based receive credit | No |
compression | HTTP response compression (gzip, deflate, Brotli) | No |
atp-cli | The standalone atp file-transfer binary (bundles tls) | No |
atpd-daemon | The unpublished atpd ATP daemon binary (cli) | No |
tailscale-path-provider | ATP Tailscale candidate-provider integration points; no Tailscale dependency | No |
messaging-fabric | Reserved name for the native FABRIC messaging lane; its module wiring is not fully gated yet | No |
tokio-compat | Tokio compatibility layer for ATP transfer actors; the general wrappers live in the separate asupersync-tokio-compat crate | No |
runtime-metrics | Scheduler and timer instrumentation counters; zero cost when disabled | No |
obligation-leak-detection | Real-time obligation leak detection with stack traces and region-boundary checks | No |
lab-stack-traces | Stack-trace capture for lab oracle violations | No |
cancel-correctness-oracle | Cancel-correctness property oracle for the cancellation protocol | No |
waker-profiling | Waker allocation hot-path profiling hooks | No |
fuzz | Fuzzing support (arbitrary derives, OTLP request helpers); outside the no-Tokio guarantee | No |
criterion-benches | Criterion-powered benchmark targets | No |
benchmark-adapters | Tokio-backed benchmark adapters; a benchmark-only quarantine lane | No |
dependency-ledger | Dependency marginal-ledger generator; build tooling, not a production graph | No |
The remaining features select internal proof lanes and CI umbrellas and are not
meant for applications: channel-mpsc-select-e2e, cross-subsystem-recovery-e2e,
distributed-hash-snapshot-recovery-e2e, h3-websocket-e2e,
obligation-cleanup-e2e, raptorq-roundtrip-e2e, real-service-e2e,
serialization-golden-harnesses, legacy-internal-test-harnesses and
ci-cross-platform.
Default features build on stable Rust 1.95 or newer (Edition 2024). On stable,
nightly-outcome-try is inactive, so ? on Outcome is unavailable. Rust
nightly remains the contributor/release toolchain (pinned by
rust-toolchain.toml), where nightly-outcome-try provides ? on Outcome.
The stable lane checks default features and the minimal subset (default
features disabled, proc-macros enabled) on Rust 1.95.0. Use
scripts/run_stable_lane_e2e.sh for the canonical local/RCH runner; it emits
structured per-stage logs and a summary.json for the stable-lane artifact.
See docs/api_audit.md for the current public API audit and stability notes.
use asupersync::{
// Capability context
Cx, Scope,
// Outcome types (four-valued result)
Outcome, OutcomeError, PanicPayload, Severity, join_outcomes,
// Cancellation
CancelKind, CancelReason,
// Resource management
Budget, Time,
// Error handling
Error, ErrorKind, Recoverability,
// Identifiers
RegionId, TaskId, ObligationId,
// Testing
LabConfig, LabRuntime,
// Policy
Policy,
};
Framework authors (e.g., HTTP servers) should wrap Cx:
use asupersync::{Budget, Cx};
/// Framework-specific request context
pub struct RequestContext<'a> {
cx: &'a Cx,
request_id: u64,
}
impl<'a> RequestContext<'a> {
pub fn is_cancelled(&self) -> bool {
self.cx.is_cancel_requested()
}
pub fn budget(&self) -> Budget {
self.cx.budget()
}
pub fn checkpoint(&self) -> Result<(), asupersync::Error> {
self.cx.checkpoint()
}
}
// Recommended HTTP status mapping:
// - Outcome::Ok(_) → 200 OK
// - Outcome::Err(_) → 4xx/5xx based on error type
// - Outcome::Cancelled(_) → 499 Client Closed Request
// - Outcome::Panicked(_) → 500 Internal Server Error
use asupersync::lab::{LabConfig, LabRuntime};
// Seed for deterministic scheduling (same seed = same execution)
let config = LabConfig::new(42)
// Maximum steps before timeout (prevents infinite loops)
.max_steps(100_000)
// Futurelock detection: tasks holding obligations without being polled
.futurelock_max_idle_steps(1000)
// Record the execution for replay
.with_default_replay_recording();
let lab = LabRuntime::new(config);
Futurelock detection is tied to held obligations and poll progress, not just elapsed time. The detector compares current step against each task's last_polled_step, and can either emit violations or panic based on panic_on_futurelock (src/lab/runtime.rs, src/lab/config.rs).
Lab snapshots also support structural validation and integrity checks. RestorableSnapshot computes a deterministic content hash over the full serialized snapshot, so semantic tampering is detectable before replay analysis (src/lab/snapshot_restore.rs).
Runtime leak handling is configurable via ObligationLeakResponse (Panic, Log, Silent, Recover) with optional threshold-based escalation (LeakEscalation), and zero thresholds are normalized to one to avoid invalid policy states (src/runtime/config.rs).
If a leak is detected while the thread is already unwinding, a Panic response is downgraded to Log to avoid double-panic aborts; leak counting is also guarded against reentrant inflation (src/runtime/state.rs).
use asupersync::{Budget, Time};
use std::time::Duration;
let now = Time::from_secs(1_000); // current logical time from the runtime or lab clock
// Request timeout with poll budget
let request_budget = Budget::new()
.with_timeout(now, Duration::from_secs(30))
.with_poll_quota(10_000) // Max 10k polls
.with_priority(192); // Above the default priority (128)
// Cleanup budget (tighter for faster shutdown)
let cleanup_budget = Budget::new()
.with_timeout(now, Duration::from_secs(5))
.with_poll_quota(500);
The oracle found an unresolved registered obligation. Inspect its task, region, and terminal transition to locate the owner or adapter that lost it. Ordinary MPSC permit destruction aborts and resolves the reservation; dropping that permit is a supported path, not itself a leak.
// Abort an unused reservation and release its capacity.
let permit = tx.reserve(cx).await?;
drop(permit);
// Or commit and handle a possible receiver disconnect.
let permit = tx.reserve(cx).await?;
let outcome = permit.send(message);
// Inspect outcome before deciding whether to retry or discard a returned value.
A region is stuck waiting for children that won't complete.
// Check for: infinite loops without checkpoints
loop {
cx.checkpoint()?; // Add checkpoints in loops
// ... work ...
}
A task is holding obligations but not making progress.
// Check for: awaiting something that will never resolve
// while holding a permit/lock
let permit = tx.reserve(cx).await?;
other_thing.await; // If this blocks forever → futurelock
let outcome = permit.send(msg);
// Handle the commit outcome if other_thing eventually completes.
Same seed should give same execution. If not:
// Check for: time-based operations
// WRONG: uses wall-clock time
let now = std::time::Instant::now();
// RIGHT: uses virtual time through Cx
let now = cx.now();
Also check for ambient randomness:
// WRONG: ambient entropy breaks determinism
let id = rand::random::<u64>();
// RIGHT: use capability-based entropy
let id = cx.random_u64();
To enforce deterministic collections in lab code, consider a clippy rule that
disallows std::collections::HashMap/HashSet in favor of util::DetHashMap/DetHashSet.
Asupersync compiles to wasm32-unknown-unknown and ships a Browser Edition
for JavaScript and TypeScript applications via wasm-bindgen. Be precise
about what crosses that boundary today: the wasm ABI exported by
asupersync-browser-core is a structured lifecycle ledger (regions, scopes,
task handles, capability-gated fetch/WebSocket calls, and fail-closed
scope-close ordering), not a scheduler. A JavaScript task_spawn records a
handle for work that runs on the host's own promises and event loop. Rust
futures are polled inside the module in two places only. Each ABI fetch
request runs as a Rust future driven by wasm-bindgen-futures. Rust code
that links asupersync-browser-core directly can also run !Send futures on
its bounded, scope-owned local executor (local::spawn_local_future, with
fetch::fetch_bytes for awaitable fetches). Neither path is the native Cx
runtime: there is no work stealing, and cancellation drops the future instead
of draining it.
@asupersync/browser supports the
browser main thread and dedicated workers. The shipped direct-runtime lane
requires a real browser window + document + WebAssembly environment, or
the required worker Web APIs. The packages are a release candidate, not GA:
the current package review in artifacts/browser_ga_final_signoff_v1.json is
RELEASE_CANDIDATE_NOT_GA_SIGNOFF, the last recorded headless-browser runs
date from March 2026, no browser-engine test runs in the validation lanes, and
the packages are not yet published to npm. They return to GA when the glue and
wasm are rebuilt together with the export-consistency check passing, at least
one browser-engine test runs in the validation lanes, and the packages are
published.fetch, WebSocket, and WebTransport datagrams plus reliable byte streams
when the host exposes globalThis.WebTransport over HTTPS. Existing sessions
can open bidirectional or send-only streams and accept server-initiated
bidirectional or receive-only streams. The high-level WebTransportHandle
and low-level @asupersync/browser-core facade share the same stream owner.@asupersync/browser now
exposes guarded MessageChannel / MessagePort / BroadcastChannel helpers
and WHATWG ReadableStream / WritableStream byte wrappers. Construction
requires explicit BrowserNativeMessagingCapability or
BrowserNativeStreamCapability authority, denies capability_not_granted
and degraded_mode_denied, and reports stable
ASUPERSYNC_BROWSER_NATIVE_* error codes. The proof artifact is
artifacts/wave2/browser_native_message_and_stream_apis_evidence.json.@asupersync/react and
@asupersync/next remain client-rendered browser adapters layered on top of
the same Browser Edition runtime boundary.asupersync supports the
canonical wasm-browser-* profile set (CI builds wasm-browser-prod), and
the repository ships asupersync-browser-core for the JS ABI/package
boundary. asupersync-wasm is a fail-closed scaffold excluded from the
workspace whose every export returns an error. That is real Rust-side browser
infrastructure, but it is not yet a stable external Rust consumer runtime
lane.RuntimeBuilder::browser().
It is dispatcher-backed, narrower than the shipped JS/TS Browser Edition
packages, and truthful about fail-closed host support. The refreshed
asupersync-j1xbon.4 support decision keeps this lane
artifact-contract-backed preview, not a stable external Rust Browser Edition
API.closeAsync() waits for its managed streamed fetches before requesting ABI
closure and preserves any refusal returned by that boundary. Native ledger
tests and browser host integration tests cover these different parts of the
ownership lifecycle.docs/WASM.md
tracks the lane pump as designed but not exposed.Create a runtime with explicit fetchAuthority.allowedOrigins and
fetchAuthority.allowedMethods, then use scope.fetch({ url, method }) for
streamed response consumption. The returned FetchStreamHandle exposes
response() for status and headers, read() for the next byte chunk, cancel()
for awaited teardown, and closed for the terminal cleanup outcome. HTTP error
statuses remain ordinary responses. The existing fetchRequest() ABI operation
retains its original behavior.
Each streamed fetch owns one ledger task and starts one host request. Authority
is captured at runtime creation and follows the recorded scope ancestry;
requests outside the origin, method, credential, or header-count grant are
refused before network I/O. Redirects are refused, and credentials are omitted
unless explicitly requested and granted. Reads pull on demand and count actual
response bytes, with a 16 MiB default response limit, a 1 MiB chunk limit, and
at most 64 active requests per runtime. Read to EOF, await request cancellation,
or use await scope.closeAsync() / await runtime.closeAsync() to drain managed
streamed fetches before owner closure. Pending cleanup retains admission
capacity, including when the host delivers a response after cancellation.
closeAsync() prevents new descendant fetch admissions while it drains and
shares an in-progress close attempt with concurrent callers. It returns the
actual cancellation, publication, or ABI-close refusal when cleanup cannot
complete, and a failed attempt restores fetch admission. This awaited path
covers the SDK's streamed fetches; it does not claim to drain unrelated host
operations. Synchronous close(), raw ABI exports, and withScope() retain
their existing behavior.
Given a live SDK WebTransportHandle, openStream() creates a bidirectional
stream and openUnidirectionalStream() creates a send-only stream.
acceptBidirectionalStream() and acceptUnidirectionalStream() receive one
server-initiated stream, returning Outcome.ok(null) when that incoming
collection ends. Each method reuses the existing authenticated session and
owning task; it does not create another WebTransport connection.
Stream read(), write(), finish(), and cancel() operations return typed
Outcomes. One read and one write may run concurrently on a bidirectional stream;
send-only and receive-only handles expose only their permitted operations.
Writes copy at most 1 MiB and await host backpressure. Pending opens, pending
accepts, and live streams share a 64-stream session limit. Only one accept may
wait per direction, and the adapter does not prefetch incoming streams.
Byte streams preserve order, not application message boundaries. finish()
sends FIN after admitted writes; a bidirectional stream can still receive data
afterward. Session cancellation and successful scope/runtime closure initiate
child-stream cleanup. Await pending admission operations and each stream's
closed promise to observe host cleanup settlement, including blocked writes
and streams delivered after cancellation. These receipts cannot force a host
promise that never settles to complete.
The maintained Node regressions in
scripts/test_browser_webtransport_lifecycle.mjs and
scripts/test_browser_sdk_webtransport_streams.mjs exercise the actual JS/TS
facades with native WHATWG streams and an intentional task-ABI recorder. They
cover this host boundary; packaged WASM execution, browser-engine behavior,
and live HTTP/3 interoperability require their separate integration lanes.
RuntimeBuilder::browser(), but it is intentionally narrower than the
shipped JS/TS Browser Edition packages. The current Rust-facing path is
dispatcher-backed and truthful about host support: supported hosts construct
a preview browser runtime, while unsupported hosts fail closed to structured
execution-ladder diagnostics rather than pretending full native-thread
parity already exists. asupersync-j1xbon.4 explicitly keeps this support
class at artifact-contract-backed preview until the stable API, ABI policy,
fixture logs, and docs are promoted together.BrowserRuntime creation fail-closed inside
ServiceWorkerGlobalScope; use the bounded broker registration and durable
handoff APIs instead.BrowserRuntime creation remains fail-closed inside
SharedWorkerGlobalScope; use the bounded coordinator attach, version
handshake, detach cleanup, and truthful fallback APIs instead.SharedArrayBuffer + Web Worker parallelism,
but this requires cross-origin isolation headers that many deployments
cannot enable.cfg-gated out on wasm32. Browser networking uses fetch,
WebSocket, and capability-gated WebTransport datagrams and streams instead.MessageChannel / BroadcastChannel / WHATWG stream helpers are guarded
same-browser wrappers only. They do not imply raw transport parity,
cross-origin federation, service/shared-worker direct runtime, filesystem or
process access, or a public Rust AsyncRead / AsyncWrite browser-core
wasm ABI.rustup target add wasm32-unknown-unknown
# Verify the semantic core closes under a browser profile
rch exec -- env CARGO_TARGET_DIR=${TMPDIR:-/tmp}/rch_target_wasm_browser_check cargo check --target wasm32-unknown-unknown \
--no-default-features --features wasm-browser-dev
# JS/TS SDK (not yet published to npm; use workspace-local packages for now)
# npm install @asupersync/browser
If you are authoring browser-facing code in Rust today, the truthful supported
lane is narrower: use the canonical wasm-browser-* profile checks for
semantic-core closure, use asupersync-browser-core / asupersync-wasm only
as the Rust-side ABI/package boundary, and use the maintained fixture workflow
at tests/fixtures/rust-browser-consumer/ plus
scripts/validate_rust_browser_consumer.sh for the repository's proven
browser-facing Rust example. The repo now exposes a preview public
RuntimeBuilder::browser() lane for external Rust consumers, but the
fixture-driven workflow remains the authoritative evidence for this path.
For the preview Rust lane, inspect the truthful execution ladder before and after requesting a lane:
use asupersync::runtime::RuntimeBuilder;
let ladder = RuntimeBuilder::new().inspect_browser_execution_ladder();
let selection = RuntimeBuilder::browser().build_selection();
The key fields to inspect are selected_lane, host_role, reason_code,
preferred_lane, and downgrade_order.
See docs/WASM.md for the full Browser Edition guide,
architecture diagrams, crate map, the current Rust-authored browser contract,
and known limitations.
The checked Browser Edition readiness matrix is
artifacts/browser_edition_readiness_matrix_v1.json,
with the human review table in
docs/browser_edition_readiness_matrix.md.
It binds Direct-runtime supported, Package ABI boundary, Preview public lane,
Broker/coordinator-only, Bridge-only, and Impossible / unsupported rows to
their fixture evidence, including vanilla/Vite and Webpack consumer lanes.
The scoped Browser Edition GA signoff packet is
artifacts/browser_ga_final_signoff_v1.json,
with the human report in
docs/browser_ga_final_signoff.md. It
aggregates B1 readiness, B2 package integrity, and B3 consumer compatibility
for the JS/TS package line while keeping the Rust browser API preview-only. Its
historical decision, as signed, reads:
JS/TS packages GA for browser main-thread and dedicated-worker consumers; Rust browser API preview-only.
The signoff's current package review, RELEASE_CANDIDATE_NOT_GA_SIGNOFF,
supersedes that decision: today the JS/TS packages are a release candidate, not
GA.
| Capability | Status |
|---|---|
| Single-thread deterministic kernel | ✅ Complete |
| Parallel scheduler + work-stealing | ✅ Implemented (three-lane scheduler) |
| I/O reactor (Linux epoll + optional io_uring primary path; BSD/Windows reactors have narrower interest support) | ✅ Implemented |
| TCP, HTTP/1.1, HTTP/2, TLS | ✅ Implemented |
| WebSocket | ⚠️ Runtime surface shipped; live RFC6455 conformance coverage now wires extension negotiation plus broader framing/control/close/masking/fragmentation harnesses, with runtime e2e coverage still lane-specific |
| HTTP/3 (default static-only QPACK; opt-in dynamic QPACK field-section and instruction-stream state machine) | ⚠️ Partial implementation: an established-connection adapter drives control and request/response lifecycle over native QUIC stream bytes, including static-QPACK headers/trailers, informational responses, GOAWAY, cancellation, resets, and reliable STREAM/control-frame recovery. A caller-driven NativeH3Router bridge assembles bounded requests through FIN, detaches bounded caller-scoped Router dispatches, and emits validated final responses on the originating stream while isolating per-stream refusal/reset. The feature-gated NativeH3Listener adds autonomous multi-peer TLS admission, runtime-owned request tasks, buffered and produced responses, deadlines, and graceful shutdown over native UDP. Opt-in streaming request ingress admits handlers at HEADERS, applies static body policy before admission, and uses bounded request-task-owned DATA queues with per-stream backpressure and FIN validation. The streaming listener's native suites pass (2026-10-04: 21/21 streaming journeys; 16 live-UDP tests plus 3 ignored, one of which needs isolated network namespaces). The live request path also carries a bounded final trailer section through the body queue and requires actual FIN before EOF. The native opt-in state machine separately supports dynamic QPACK field sections/tables, Huffman strings, encoder/decoder instruction-stream processing, and bounded blocked-stream scheduling. Deployment readiness, CONNECT, migration, 0-RTT, and external interop evidence remain open, so this is not a claim of h3/quinn drop-in parity or full QUIC deployment parity. |
| Database clients (SQLite, PostgreSQL, MySQL) | ✅ Implemented |
| Actor supervision (GenServer, links, monitors) | ✅ GenServers, actors and supervisors. cx.spawn_gen_server(server, capacity), cx.spawn_actor(actor, capacity) and cx.spawn_supervised_actor(factory, strategy, capacity) run them as tasks in the caller's region, on the native runtime and in the lab. Monitors and links fire when the watched task ends. cx.monitor(&handle) delivers one DOWN with the exit reason; cx.link(peer) cancels the other side of an abnormal exit (CancelKind::LinkedExit); cx.link_trapping(peer) delivers the peer's exit instead. A GenServer gets the same through GenServerHandle::monitor / link / link_trapping, as SystemMsg::Down / `SystemMsg::Ex |
Truncated — view the full README on GitHub.
3,597 followers · starred Jul 2026
324 followers · starred Feb 2026
130 followers · starred Jul 2026
194 followers · starred May 2026