Skip to content

Rewrite README to reflect the current state of Shuttle - #326

Open
sarsko wants to merge 3 commits into
mainfrom
readme-reflect-current-state
Open

Rewrite README to reflect the current state of Shuttle#326
sarsko wants to merge 3 commits into
mainfrom
readme-reflect-current-state

Conversation

@sarsko

@sarsko sarsko commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

This CR is borderline draft (because it is AI slop), but I'm leaving it open because I do think it or a version of it will want to be merged. I have yet to review this CR properly.

My opinions:

  1. Current README does not accurately present current Shuttle.
  2. The new tool to find tools is LLMs. What the LLMs say is heavily based on what is in the README, and we want the LLMS to give stuff that is useful to the person reading. Blabla randomized is not useful, blabla can run most tokio applications and find bugs is useful.
  3. People occasionally read READMEs too. The README should be valuable to them too.

AI SLOP BELOW

The README had drifted a long way from the library it describes. It was 82 lines, roughly 60 of which were a near-verbatim copy of the crate-level docs in shuttle/src/lib.rs (the same std Mutex example, the same check_random rewrite, the same Loom paragraph), plus badges and a single sentence about the wrappers.

Nothing in it was wrong. But it said nothing about async, the replay workflow, seven of the eight schedulers, Config, the SHUTTLE_* environment variables, labels, the vector-clocks or annotation features, Shuttle Explorer, the 0.9.2 split into shuttle-engine/shuttle-schedulers/shuttle-std, or tokio beyond one passing mention.

Since shuttle/Cargo.toml sets readme = "../README.md", this is also the crates.io landing page.

What changed

Reordered around "what can I test, and how do I debug a failure", and pulled the useful onboarding content that only existed in lib.rs into the README.

  • A section on testing tokio code, the largest addition. Tokio support is a dependency swap rather than a module, which is non-obvious enough that a one-line mention doesn't get anyone there. Covers the package = "shuttle-tokio" setup, #[tokio::test], which tokio modules are actually modeled, time and timeouts, what is re-exported from real tokio and therefore unsafe under Shuttle, the environment variables the harness reads, and the companion crates.
  • The replay workflow, previously only in the crate docs, despite being the strongest reason to reach for Shuttle.
  • A table of all eight built-in schedulers with their entry points and when to use each.
  • Config knobs and the SHUTTLE_* environment variables.
  • A coverage table for the std replacements, with the caveats stated rather than left to be discovered: Arc is std's, the atomic implementation is unsound, fence(Relaxed) panics, time is not modeled, no OnceLock/LazyLock/mpmc.
  • The other wrappers, Shuttle Explorer, and a repository layout table.
  • Moved the Loom soundness–scalability paragraph into the intro, where it belongs; it was orphaned just above ## License.

No code changes. shuttle/src/lib.rs docs are deliberately untouched.

Two things called out as design decisions

Some of this is judgement, so flagging it explicitly rather than burying it:

  1. The README and the lib.rs doc block are still independent near-duplicates. There is no include_str! anywhere, which is why they drifted. This PR does not address that; it treats the README as the pitch-and-orientation document and leaves lib.rs as the API narrative. If you would rather have a single source of truth via #![doc = include_str!("../README.md")], that is a bigger change (every code fence becomes a doctest and needs annotating, and intra-doc links become URLs) and probably its own PR.
  2. The tokio section is deliberately long. It documents the sharp edges, in particular that timeout ignores its duration entirely and only fires via trigger_timeouts, and that task_local! currently gives shared storage across all Shuttle tasks. Happy to trim it down to a pointer at wrappers/tokio/README.md if you'd prefer the README stay short.

Verification

Every technical claim was checked against the source rather than carried over from the old text. Specifically avoided documenting shuttle::check (#[doc(hidden)]) and the tokio crate's check/default_shuttle_config (both #[deprecated] and slated to move).

  • All relative links resolve, all heading anchors match, all code fences balance.
  • The four wrapper versions in the tokio examples were cross-checked against the crates' actual manifests.
  • No MSRV or platform-support claims, since none is declared anywhere in the repo and CI is Linux/stable+beta only.

Relation to other open PRs

The tokio examples here say version = "1" for shuttle-tokio, which is what #327 republishes it as, and which matches what wrappers/README.md already tells users to write. The rest of the README stands alone.

This PR touches only README.md, so it does not conflict with #325 or #327 and can merge in any order; merging it before #327 would just mean the documented requirement lands slightly ahead of the release.

Not included

wrappers/README.md documents a tokio-version-importer-do-not-use-directly crate that does not exist in the tree. Left alone here. (The shuttle_enabler gap in that file is addressed in #325.)


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

The README had drifted a long way from the library it describes. It was
largely a copy of the crate-level docs in shuttle/src/lib.rs, covering
check_random and the Loom comparison and little else, with a single
sentence about the wrappers.

Rewrite it around what Shuttle can test today and how a failure gets
debugged:

* A dedicated section on testing tokio code, covering the dependency-swap
  setup, #[tokio::test], which tokio modules are actually modeled, how
  time and timeouts work (timeouts fire via trigger_timeouts rather than
  elapsing), what is re-exported from real tokio and therefore unsafe to
  use under Shuttle, and the environment variables the tokio harness reads.
* The replay workflow, which was previously only in the crate docs.
* A table of all eight built-in schedulers and their entry points.
* Config knobs and the SHUTTLE_* environment variables.
* Coverage of the std replacements, including the known gaps: Arc is
  std's, atomics are unsound, no OnceLock/LazyLock/mpmc, time is not
  modeled.
* The other wrappers, Shuttle Explorer, and a repository layout table
  covering the 0.9.2 split into shuttle-engine/schedulers/std.

No code changes; shuttle/src/lib.rs docs are left alone.
shuttle-tokio is being republished as 1.0.0 so that it mirrors the version of
the crate it wraps, matching the other wrappers. Point the tokio setup and
companion crate examples at `1`, which also makes them agree with the examples
in wrappers/README.md.
Comment thread README.md Outdated
[A Randomized Scheduler with Probabilistic Guarantees of Finding Bugs](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf).
Shuttle is a library for testing concurrent Rust code. It takes control of the scheduler, so that
thread interleavings are chosen by Shuttle rather than by the OS. That gives you two things a normal
concurrency test cannot: interleavings are explored deliberately instead of by luck, and any failure

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this luck term

Comment thread README.md Outdated

This repository also houses a collection of [wrappers](/wrappers) and their implementations. These make it easier to test code using popular libraries such as `tokio` and `rand`, as well as synchronization primitives from `std::sync` and collections from `std::collections`. For more information on how to use these wrappers, see the [wrappers/README.md](/wrappers/README.md).
Shuttle implements a number of *randomized concurrency testing* techniques, including
[A Randomized Scheduler with Probabilistic Guarantees of Finding Bugs](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved down to the section with schedulers

Comment thread README.md Outdated
[A Randomized Scheduler with Probabilistic Guarantees of Finding Bugs](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf)
(PCT).

Shuttle is inspired by [Loom](https://github.com/tokio-rs/loom), but focuses on randomized testing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention that Shuttle has seen more love than Loom in recent years? Also mention that Shuttle can also be run exhaustively? (though without any POR)

Comment thread README.md Outdated
than Loom. Empirically, randomized testing is successful at finding most concurrency bugs, which
tend not to be adversarial.

Beyond the core library, this repository houses a collection of drop-in

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be explicit that the core philosophy of Shuttle is to require minimal changes to the code

Comment thread README.md Outdated

```rust
#[cfg(all(feature = "shuttle", test))]
use shuttle::{sync::*, thread};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how we want people to swap imports. Use the wrapper crates instead

Comment thread README.md

## Reproducing a failure

When a Shuttle test fails, it prints the schedule that caused the failure:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that schedulers like the random scheduler will also print the seed ?

Comment thread README.md
- Vector clocks, which power the causality tracking exposed through `shuttle::current`, are behind
the `vector-clocks` feature.

## Choosing a scheduler

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the uncontrolled nondeterminism check scheduler should have its own little section

- Drop the "by luck" framing in the opening paragraph.
- Move the PCT citation down into the scheduler section.
- Note that Shuttle can run exhaustively via check_dfs, with no POR.
- State the minimal-changes-to-the-code goal explicitly.
- Recommend the shuttle-sync wrapper instead of hand-rolled cfg import
  swapping, and note the std::sync superset and missing thread wrapper.
- Document that check_random prints the failing seed, and how a seed
  differs from a schedule as a reproducer.
- Give the uncontrolled nondeterminism check scheduler its own section.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant