ripr helps Rust developers and coding agents answer 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 a static Reachability-Infection-Propagation-Revealability (RIPR)
exposure analyzer for Rust workspaces. It reads changed Rust code, builds
mutation-shaped static probes, and reports whether existing tests appear to
reach, affect, propagate, observe, and discriminate the changed behavior.
It is alpha software. The current release is useful for fast feedback while a pull request is moving. It is not a proof system, and it does not replace real mutation testing.
Coverage can tell you that code executed.
Mutation testing can tell you whether a concrete mutated version of the code was caught by the test suite.
During everyday development, teams often need a cheaper question answered earlier:
This behavior changed. Do the nearby tests actually check the thing that changed?
That is what ripr is for.
It is designed to find weak or missing test discriminators, such as:
- a boundary change without equality-boundary assertions
- an error-path change checked only with
is_err() - a return-value change covered only by a smoke assertion
- a field construction change without field or object assertions
- a side effect without a mock, event, state, persistence, or metric oracle
ripr analyzes a diff and classifies static exposure evidence for changed
behavior.
It looks for:
Reachability:
can a related test reach the changed code?
Infection:
could the changed expression alter local state or control?
Propagation:
could that altered state reach a visible boundary?
Revealability:
does a test oracle appear to observe the affected behavior?
Then it reports whether the current tests appear to expose the changed behavior to a meaningful discriminator.
ripr does not run mutants.
It does not report killed or survived, prove test adequacy, replace
coverage, or replace real mutation testing.
Use ripr for fast, static, draft-time oracle-gap feedback. Use a real mutation
runner, such as cargo-mutants, when the change is ready for execution-backed
confirmation.
coverage:
did this code execute?
ripr:
does changed behavior appear exposed to a meaningful test oracle?
mutation testing:
did tests fail when a concrete mutant was run?
ripr is the middle layer: faster and more targeted than mutation testing, more
oracle-aware than coverage.
Install from crates.io:
cargo install riprLinks:
- crates.io: https://crates.io/crates/ripr
- docs.rs: https://docs.rs/ripr
For local development from this repository:
cargo install --path crates/riprripr targets Rust 2024 and requires Rust 1.93 or newer.
Check local tooling and workspace shape:
ripr doctorCheck the current Git diff against origin/main:
ripr check --base origin/mainAnalyze an explicit unified diff:
ripr check --diff example.diffEmit JSON for tools, editors, CI, or agents:
ripr check --diff example.diff --jsonEmit GitHub Actions annotations:
ripr check --diff example.diff --format githubExplain a finding:
ripr explain --diff example.diff probe:src_lib.rs:88:predicateEmit an agent context packet:
ripr context --diff example.diff --at probe:src_lib.rs:88:predicate --jsonStart the experimental language server:
ripr lsp --stdioWARNING src/pricing.rs:88
Static exposure: weakly_exposed
Probe: predicate
Changed behavior:
if amount >= discount_threshold {
Evidence:
Reachability: related tests found
Infection: changed predicate can alter branch behavior
Propagation: branch appears to influence returned total
Revealability: tests assert returned values, but no equality-boundary case was found
Gap:
No detected test input for amount == discount_threshold.
Recommended next step:
Add below, equal, and above-threshold tests with exact assertions.
The wording is intentionally conservative. Static analysis can identify evidence and gaps; it should not claim real mutation outcomes.
| 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 |
Static analysis cannot make a credible judgment. |
ripr should not use mutation-runtime outcome language such as killed or
survived unless explicit real mutation data is being reported in a calibration
context.
The current alpha line is intentionally narrow:
- one published package:
ripr - one CLI binary:
ripr - one shared analysis engine
- syntax-backed unified diff analysis
- parser-backed Rust function, test, assertion, owner, and probe facts with lexical fallback
- 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.
ripr is currently strongest as a fast, syntax-backed draft signal with
first-class repo seam evidence.
Current capabilities:
| Capability | Current state | Next checkpoint |
|---|---|---|
| Distribution | Crate and extension packaging paths exist. | Verify one-click editor install from a fresh profile. |
| Diff analysis | Evidence-first Voice A findings with syntax-backed changed-line probes, probe-relative oracle strength, local flow sinks, observed/missing activation values, and explicit stop reasons. | Campaign 5B config and policy. |
| Repo seam inventory | First-class RepoSeam model with deterministic seam IDs, cached seam fact layers, test-grip evidence across the five RIPR stages, and 11-class SeamGripClass classification. |
Campaign 5B config and policy. |
| Test discovery | Parser-backed test and assertion facts with exact, broad, relational, snapshot, mock, smoke, custom-helper, side-effect observer, and unknown oracle kinds; per-test efficiency ledger with smoke/broad/disconnected/opaque/circular/likely-vacuous reasons and duplicate-discriminator groups. | Campaign 5B config and policy. |
| Output | Human, JSON, context, and GitHub formats render evidence-first findings with stop reasons; repo exposure report and v2 agent seam packets render classified seam evidence; ripr and ripr+ Shields badges publish unresolved gap counts. |
Seam-native badge count mapping after config. |
| LSP | Experimental tower-lsp-server sidecar with evidence-aware Finding diagnostics, related-test links, hovers, server-side context packets, seam-native diagnostics + hover, and seam code actions for copying packets/assertions and opening related tests (seam diagnostics remain off by default). |
ripr.toml seam-diagnostic defaults. |
| Agent context | Compact context packet plus per-seam write_targeted_test and inspect_static_limitation packets carrying recommended test placement, nearest tests to imitate, candidate values, missing discriminators, patterns to imitate/avoid, and assertion templates. Documented agent dispatch workflow in docs/AGENT_DISPATCH_WORKFLOW.md. |
Campaign 5B config and policy. |
| Calibration | Advisory cargo xtask mutation-calibration joins imported cargo-mutants runtime data to static seam evidence by seam_id or unambiguous file/line and writes target/ripr/reports/mutation-calibration.{json,md}; ambiguous file/line candidates stay unassigned. |
Future calibration fixtures; runtime mutation language stays inside calibration/runtime reports. |
Campaign 5A is complete. The active product work is Campaign 5B — operationalizing the seam evidence:
ripr.toml config
SARIF and opt-in CI policy
seam-native badge count mapping
Deeper capability state lives in Capability matrix and Metrics.
The VS Code extension starts ripr lsp --stdio and can resolve the server from:
1. explicit ripr.server.path
2. bundled server binary, if present
3. downloaded cached server binary
4. verified first-run GitHub Release download
5. ripr on PATH
6. actionable error
See:
Most contributors should use the repo automation instead of remembering the gate order manually.
cargo xtask shape
cargo xtask fix-pr
cargo xtask check-pr
cargo xtask pr-summaryUseful evidence commands:
cargo xtask fixtures
cargo xtask goldens check
cargo xtask golden-drift
cargo xtask test-oracle-report
cargo xtask dogfood
cargo xtask reports index
cargo xtask receipts
cargo xtask receipts check
cargo xtask check-allow-attributes
cargo xtask check-local-context
cargo xtask metricsA good ripr PR is scoped by production risk, not line count:
small production delta
complete evidence package
clear spec-test-code-output-metric trail
Large fixture, golden, spec, docs, metrics, or traceability diffs are welcome when they make one production behavior reviewable.
See:
Start here:
| Need | Doc |
|---|---|
| Understand the model | Static exposure model |
| Understand JSON/context output | Output schema |
| See current product direction | Roadmap |
| See active campaigns | Implementation campaigns |
| See implementation checkpoints | Implementation plan |
| Run Codex Goals | Codex Goals |
| See behavior contracts | Specs |
| See design decisions | ADRs |
| Add or review fixtures | Testing and Test taxonomy |
| Understand repo automation | PR automation |
| Understand architecture | Architecture |
| Review capability state | Capability matrix and Metrics |
| Contribute a scoped PR | Contributing and Scoped PR contract |
| Understand CI | CI strategy |
| Understand dogfooding | Dogfooding |
| Understand docs organization | Documentation system |
| Capture repo knowledge | Learnings |
| Release the crate or extension | Release, Publishing, and Open VSX |
| Work on extension assets | Brand assets |
| Find repo instructions for agents | Agent instructions |
Run the normal local gate:
cargo xtask check-prRun the full Rust checks directly:
cargo fmt --check
cargo check --workspace --all-targets
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo doc --workspace --no-depsRelease/package checks:
cargo package -p ripr --list
cargo publish -p ripr --dry-runUseful sample commands:
cargo run -p ripr -- check --diff crates/ripr/examples/sample/example.diff
cargo run -p ripr -- check --diff crates/ripr/examples/sample/example.diff --json