ripr
ripr is a static RIPR mutation-exposure analyzer for Rust workspaces.
It answers a draft-time testing question:
For the behavior changed in this diff, do the current tests appear to contain
a discriminator that would notice if that behavior were wrong?
ripr is alpha software. The current release is a syntax-first scanner that is
useful for early feedback, not a proof system.
This is the product repository for ripr. The 0.1.x line is the first
publishable alpha cut of the tool.
Mission
ripr helps Rust developers and coding agents write tests that actually notice
changed behavior.
It performs static RIPR exposure analysis over changed Rust code, creates mutation-shaped probes, and reports whether existing tests appear to contain the discriminators needed to expose those changes.
It is a fast draft-mode companion to real mutation testing: static guidance while the pull request is moving, real mutation confirmation when the change is ready.
Vision
The vision for ripr is to become the live test-adequacy layer between coverage
and mutation testing for Rust/Cargo workspaces.
Coverage tells developers what executed. Mutation testing tells developers what
survived. ripr tells developers, reviewers, and agents what changed behavior
appears to lack a meaningful oracle before the expensive mutation run begins.
The end state is an LSP-native sidecar that watches changed code, identifies missing discriminators, explains the evidence path, emits agent-ready test intent, and calibrates itself against real mutation outcomes.
Category
ripr defines its category as:
Static Mutation Exposure Analysis
More specifically:
Static oracle-gap analysis for diff-derived mutation probes.
The tool is not trying to be a coverage dashboard, a full mutation engine, a proof system, a second rust-analyzer, or a generic LLM test generator. Its job is to shorten the path from "this behavior changed" to "this is the exact test oracle that should notice."
What ripr Does
ripr reads changed Rust code, creates mutation-shaped probes, and estimates
whether related tests appear to reach, infect, propagate, observe, and
discriminate the changed behavior.
It looks for missing or weak test oracles such as:
- boundary changes without boundary-value assertions
- error-path changes checked only with
is_err() - return-value changes checked only with smoke assertions
- field construction changes without field, object, or snapshot assertions
- side effects without mock, event, state, persistence, or metric oracles
What ripr Does Not Do
ripr does not run mutants.
It does not report killed or survived, prove test adequacy, replace coverage,
or replace real mutation testing. Use a real mutation runner, such as
cargo-mutants, when the change is ready for confirmation.
Where It Fits
coverage:
did this code execute?
ripr:
does changed behavior appear exposed to a meaningful oracle?
mutation testing:
did tests fail when a concrete mutant was run?
The goal is fast, honest oracle-gap feedback while code is still changing.
Ecosystem Positioning
| Existing layer | What it answers | Gap |
|---|---|---|
cargo-llvm-cov |
Did code execute? | Not oracle-aware |
| selective retest tools | Which tests are impacted? | Not assertion-aware |
cargo-mutants |
Did real mutants survive? | Too expensive for live draft feedback |
rust-analyzer |
What does Rust code mean in the editor? | Does not rank mutation exposure |
ripr |
Does changed behavior appear exposed to a meaningful oracle? | New middle layer |
Install
Once ripr is published to crates.io:
For local development from this repository:
ripr targets Rust 2024 and requires Rust 1.92 or newer.
Quick Start
# Check local tooling and workspace shape
# Analyze the current Git diff against origin/main
# Analyze an explicit unified diff
# Emit stable JSON for tools and agents
# Emit GitHub Actions annotations
# Explain one finding
# Emit an agent-ready context packet
# Start the experimental LSP sidecar
Example Finding
WARNING src/pricing.rs:88
Static exposure: weakly_exposed (predicate, control)
Changed behavior:
after: if amount >= discount_threshold {
RIPR:
Reach: yes
Infect: weak
Propagate: yes
Observe: yes
Discriminate: weak
Gap:
- No detected boundary input for the changed predicate
- No strong discriminator was detected
Recommended next step:
Add below, equal, and above threshold tests with exact assertions.
Output Formats
Human output is optimized for local use.
JSON output is versioned and intended for editor integrations, CI, and coding agents:
GitHub output emits workflow annotations.
Classifications
| Classification | Meaning |
|---|---|
exposed |
Static evidence suggests a complete RIPR path to a strong oracle. |
weakly_exposed |
A path exists, but infection or discrimination appears weak. |
reachable_unrevealed |
Related tests appear reachable, but no meaningful oracle was found. |
no_static_path |
No static test path was found for the changed owner. |
infection_unknown |
Reachability exists, but input or fixture evidence is opaque. |
propagation_unknown |
The changed behavior crosses an opaque propagation boundary. |
static_unknown |
Syntax-first analysis cannot make a credible judgment. |
Current Scope
The 0.1.x alpha line is intentionally narrow:
- one published package:
ripr - one CLI binary:
ripr - one shared analysis engine
- syntax-first unified diff analysis
- basic Rust function, test, and assertion indexing
- human, JSON, and GitHub outputs
- experimental LSP sidecar
The package is not split into ripr-core, ripr-cli, or ripr-lsp. Public
crate boundaries can be added later if external consumers need them.
Development
Useful sample commands: