masstrust
Calibrated trust and abstention for MS/MS molecular annotations.
What masstrust does
masstrust is a Rust toolkit for selective prediction in MS/MS molecular annotation.
It takes candidate rankings from external annotation or retrieval tools and decides whether the top-ranked molecular annotation should be trusted or abstained under a user-specified error-rate target.
The core idea:
Trust confident annotations. Abstain when uncertainty is too high.
What masstrust does NOT do
- Does not perform MS/MS database search or spectral matching
- Does not generate molecular structures
- Does not perform retrosynthesis
- Does not replace SIRIUS, CSI:FingerID, MassSpecGym, or similar tools
- Does not guarantee clinical correctness
masstrust is a post-hoc trust layer for annotation pipelines. It sits after your annotation tool of choice and controls the risk of accepting incorrect annotations.
Installation
Rust CLI (from source)
git clone https://github.com/kent-tokyo/masstrust
cd masstrust
cargo install --path crates/masstrust-cli
Python wheel (requires maturin)
maturin build --features extension-module
pip install target/wheels/masstrust-*.whl
Quick start — CLI
Step 1. Compute the risk-coverage curve from labeled candidates:
masstrust curve examples/labeled_candidates.csv \
--score score-gap \
--out risk_coverage.csv \
--verbose
Step 2. Calibrate a threshold at 5% error rate:
masstrust calibrate examples/labeled_candidates.csv \
--score score-gap \
--error-rate 0.05 \
--method empirical \
--out policy.json
Step 3. Apply the policy to new (unlabeled) candidates:
masstrust apply examples/candidates.csv \
--policy policy.json \
--out trusted_annotations.csv \
--abstained abstained.csv
Batch mode — apply one policy to many files:
masstrust batch data/*.csv \
--policy policy.json \
--out-dir ./results/
Compare multiple scoring methods on one labeled dataset:
masstrust compare examples/labeled_candidates.csv \
--scores score-gap,score-ratio,topk-gap,candidate-count \
--error-rate 0.05 --method empirical \
--bootstrap 1000 \
--out compare.csv
Evaluate a policy on separate held-out data — calibrate on one set (e.g. validation), evaluate on another (e.g. test) without recalibrating:
masstrust calibrate val.csv --score score-gap --error-rate 0.05 --method empirical --out policy.json
masstrust evaluate test.csv --policy policy.json --out eval_report.json
Detect confidence drift between calibration and new data:
masstrust drift --calibration examples/labeled_candidates.csv --new examples/candidates.csv \
--score score-gap --out drift_report.json
Guard against calibration/test leakage (query_id/inchikey/formula overlap):
masstrust validate-split --calibration val.csv --test test.csv
Sample output
$ masstrust calibrate examples/massspecgym_candidates.csv \
--score score-gap --error-rate 0.05 --method empirical --out policy.json
Calibration result (ScoreGap, empirical):
target error rate: 0.0500
global threshold: 0.120000
coverage: 0.5000 (4/8 queries accepted, 50.0%)
observed risk: 0.0000 (0/4 errors)
AURC: 0.151488
E-AURC: -0.001938
$ masstrust apply examples/candidates.csv --policy policy.json \
--out trusted.csv --abstained abstained.csv
Accepted: 1 Abstained: 1 (wrote trusted.csv and abstained.csv)
SVG plots (requires --features plot):
cargo build --features plot
masstrust curve examples/labeled_candidates.csv \
--score score-gap --out risk.csv \
--plot risk.svg --histogram hist.svg
Quick start — Python
import masstrust
# 1. Compute risk-coverage curve
curve = masstrust.compute_curve(
"examples/labeled_candidates.csv",
score="score-gap",
)
print(f"AURC: {masstrust.aurc(curve):.4f}")
# 2. Calibrate
policy = masstrust.calibrate(
"examples/labeled_candidates.csv",
score="score-gap",
error_rate=0.05,
method="empirical",
)
print(f"Threshold: {policy['threshold']:.4f}")
# 3. Apply to new data
decisions = masstrust.apply_policy("examples/candidates.csv", policy)
accepted = [d for d in decisions if d["accepted"]]
print(f"Accepted: {len(accepted)}/{len(decisions)}")
# Save / load policy
masstrust.save_policy("policy.json", policy)
policy = masstrust.load_policy("policy.json")
Input CSV format
query_id,candidate_id,rank,score,probability,is_correct
q1,cand_a,1,0.92,0.71,true
q1,cand_b,2,0.81,0.21,false
q2,cand_c,1,0.88,0.46,false
q2,cand_d,2,0.86,0.43,true
| Column | Required | Description |
|---|---|---|
query_id |
✓ | Spectrum identifier |
candidate_id |
✓ | Candidate structure identifier |
rank |
✓ | Rank among candidates for this query (1 = best) |
score |
✓ | Raw annotation score (higher is better) |
probability |
— | Posterior probability (required for max-prob, margin, entropy) |
is_correct |
— | Ground-truth label; required for calibrate and curve |
Parquet input is supported with --features parquet (auto-detected by .parquet extension).
Add --bootstrap 1000 to curve or compare for a bootstrap 95% confidence interval on AURC.
Confidence scoring methods
| Method | Formula | Requires |
|---|---|---|
score-gap |
score(rank-1) − score(rank-2) |
≥2 candidates |
score-ratio |
score(rank-1) / score(rank-2) |
≥2 candidates, score(rank-2) > 0 |
topk-gap |
score(rank-1) − mean(score(rank-2..min(5,n))) |
≥2 candidates |
candidate-count |
1 / n_candidates |
none — always scoreable |
max-prob |
probability(rank-1) |
probability column |
margin |
probability(rank-1) − probability(rank-2) |
probability, ≥2 candidates |
entropy |
1 − H_normalized over all candidate probabilities |
probability for all candidates |
effective-k |
exp(−H) over all candidate probabilities |
probability for all candidates |
Calibration methods
| Method | Behaviour | Notes |
|---|---|---|
empirical |
Maximum coverage where observed risk ≤ target | No statistical guarantee beyond validation set |
binomial |
Maximum coverage where one-sided Wilson upper bound ≤ target | Conservative; add --confidence-level 0.95 |
crc (experimental) |
Empirical target tightened by 1/(n+1) |
CRC-style correction; see caveats below |
# Empirical
masstrust calibrate labeled.csv --score score-gap --error-rate 0.05 --method empirical --out policy.json
# Binomial (conservative)
masstrust calibrate labeled.csv --score score-gap --error-rate 0.05 --method binomial --confidence-level 0.95 --out policy.json
# CRC-style (experimental)
masstrust calibrate labeled.csv --score score-gap --error-rate 0.05 --method crc --out policy.json
Batch selective-deployment certification (risksieve, optional)
masstrust certify-batch is a feature-gated (--features risksieve), independent
workflow, built on the risksieve crate's SCoRE-SDR
controller (Bai and Jin, 2026, arXiv:2603.24704). It is not exposed at all in a default build.
This is not a reusable threshold policy. Unlike calibrate/apply, it computes a fresh
selection for one specific calibration set + test batch pair every time you run it — the
default construction's e-values depend on the whole test batch's composition, so the same
calibration data can select a different subset of a different test batch. See
docs/risksieve-integration.md for why this is a separate
command rather than a new CalibrationMethod, and exactly what
GuaranteeKind::SelectiveDeploymentRisk does and does not claim.
masstrust certify-batch \
--calibration val.csv \
--test test.csv \
--score score-gap \
--alpha 0.05 \
--gamma 0.05 \
--construction coupled \
--accepted accepted.csv \
--abstained abstained.csv \
--certificate certificate.json \
--report report.md
- The risk guarantee is conditional on stated assumptions (exchangeability of calibration and
the entire test batch jointly, a
[0, 1]-bounded loss, and so on) —certificate.jsonandreport.mdboth record them in full; read them before trusting a number. - Zero selections is a normal, valid certificate, not an error — SCoRE-SDR's bound holds trivially on an empty selected set.
- If
test.csvhappens to carryis_correctlabels, the report also prints a realized selective risk — a post-hoc descriptive statistic computed from this one batch's actual outcomes. It is kept clearly separate from the theorem-backed certificate above it and never described as validating (or invalidating) that certificate.
Graded chemical loss (--loss-column)
By default the certified/realized loss is binary top-1 correctness (is_correct: 0.0 if
correct, 1.0 otherwise). --loss-column <name> certifies against any [0, 1]-bounded
precomputed loss instead — e.g. Tanimoto dissimilarity or scaffold mismatch, computed upstream
(masstrust never computes chemistry itself; see docs/graded-loss-integration.md):
masstrust certify-batch \
--calibration val.csv \
--test test.csv \
--score score-gap \
--alpha 0.05 \
--gamma 0.05 \
--loss-column tanimoto_loss \
--accepted accepted.csv \
--abstained abstained.csv \
--certificate certificate.json \
--report report.md
- Required on every scoreable calibration query (hard error if the column is absent, or a
value is missing/malformed/outside
[0, 1]/non-finite). Genuinely optional on--test— an unlabeled test set (no such column at all) still certifies successfully; it just can't produce a realized-risk number. certificate.json/report.mdrecordloss_kind/loss_label/loss_column/loss_domainso a--loss-columncertificate can never be misread as certifying exact-match risk.- Realized risk is always resolved against the same loss the certificate itself used — asking
for it under a different
--loss-column(or under binary correctness, for a graded-loss certificate) is a hard error, not a silently mismatched number.
masstrust's existing calibration methods (empirical/binomial/crc) are untouched by this
feature — see the scientific caveats below, which apply to certify-batch too.
Understanding risk and coverage
The risk-coverage curve summarises the accept/abstain tradeoff:
- Coverage = fraction of queries where a prediction is accepted
- Risk = fraction of accepted predictions that are incorrect
At any threshold, higher coverage comes at higher risk. masstrust finds the threshold that maximises coverage while keeping risk within the specified target.
risk
1.0 ┤ ╭──
│ ╭────╯
│ ╭────╯
0.05┤ ─ ─ ─ ─ ─ ─ ─╱── target
│ ╭───╯
0.0 ┤───────────╯
└──────────────────────────── coverage
0 1.0
The threshold is chosen as the rightmost point on the curve that stays at or below the target risk line.
Policy JSON
A calibrated policy is saved as a reproducible JSON file:
{
"version": "0.1.0",
"scoring_method": "score_gap",
"threshold": 0.18,
"target_error_rate": 0.05,
"calibration_method": "empirical",
"confidence_level": null,
"created_by": "masstrust"
}
Benchmarking on MassSpecGym
benchmarks/massspecgym/ is a self-contained pipeline (kept out of the Rust workspace — it depends on massspecgym/torch/rdkit) that trains the official Fingerprint FFN retrieval baseline, exports its predictions in masstrust's schema, and reports masstrust's own scoring methods' AURC/E-AURC/coverage-at-risk on real MassSpecGym data. This establishes a real, reproducible benchmark before any competitor comparison — none is claimed yet.
The harness has been validated end to end against real data via a small-scale preflight run (download → train → checkpoint → predictions → report), which found and fixed several real integration bugs along the way. The full benchmark run is not complete yet — no results are published. See benchmarks/massspecgym/README.md for the full protocol and current status.
Scientific caveats
masstrustcontrols observed or bounded risk under the chosen calibration procedure on the provided validation data. It does not guarantee correctness on out-of-distribution spectra.- Risk control is calibrated on the validation set provided. If the test distribution differs (different instrument, adduct type, compound class), guarantees may not transfer.
- The experimental
crcmethod assumes i.i.d. calibration data and binary 0/1 annotation loss. Verify these assumptions hold for your dataset before relying on the stated guarantee. - Small calibration sets (< ~20 queries) may produce very conservative thresholds or no valid threshold at all (reported as
threshold = +inf, i.e. abstain on everything). masstrustdoes not claim clinical validity or regulatory compliance.
References
- Angelopoulos, A. N., Bates, S., Fisch, A., Lei, L., & Schuster, R. (2022). Conformal Risk Control. arXiv:2208.02814. — basis for the
crccalibration method. - Geifman, Y., & El-Yaniv, R. (2017). Selective classification for deep neural networks. NeurIPS. — foundational selective prediction framework.
License
Licensed under either of:
at your option.
Metadata
Release files for masstrust 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| masstrust-0.3.0.tar.gz | 70.8 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| masstrust-0.3.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl | CPython 3.14 | CPython 3.14 | macOS 10.12+ x86-64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 11.0+ ARM64 | Details |
| masstrust-0.3.0-cp312-cp312-win_amd64.whl | CPython 3.12 | CPython 3.12 | Windows x86-64 | Details |
| masstrust-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | CPython 3.9 | Linux glibc 2.17+ x86-64 | Details |
Total release size: 1.5 MB
Release files / masstrust-0.3.0.tar.gz
| Download URL | masstrust-0.3.0.tar.gz |
|---|---|
| Size | 70.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
87cbe8bb71778890c958d80ae8c198779c031e0935c3b071b7bf49c7eeb0d77f
|
|
BLAKE2b-256 checksum How to use checksums |
bff1f2ee802e7dd0530f082701a14d997bf69c48382e8ac3531136ce6e5230a0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / masstrust-0.3.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
| Download URL | masstrust-0.3.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl |
|---|---|
| Size | 725.6 kB |
| Tags | CPython 3.14 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
43552544b8d094678396695eb073de3cdb45d0afb688d806a1b845627a02a20f
|
|
BLAKE2b-256 checksum How to use checksums |
329e926cb8b745e406502ef3a6b0bbba965f2123006fe0239b5d7ea56bab9e1f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / masstrust-0.3.0-cp312-cp312-win_amd64.whl
| Download URL | masstrust-0.3.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 276.4 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
a870d9c939bc1673a0002046c4705a218b2f9745a49a4d8e491464286f8e8cfc
|
|
BLAKE2b-256 checksum How to use checksums |
3d70940cc123fa07ebcd14b3a92be3e365f6830b81fcc091d03c1a326baec05b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / masstrust-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | masstrust-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 424.5 kB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
9e4aa2b884a8ce57fc397ab308c086b5e5f1e66f1ddaf5cc6b3b9c58465760b8
|
|
BLAKE2b-256 checksum How to use checksums |
e647b8ec2aa667601565b6700a3a65c23fcb6b39d1a61081eac10a5b7dea5882
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency log