Memory is a contract, not a hope.
Every other variant caller treats RAM as an emergent property you guess at (-Xmx…,
--target-mem "heuristics may not work well") and then crash on. Rosalind treats it as a contract:
Rosalind never silently OOM-kills you — it fits, or it tells you up front, and it proves the realized peak with a receipt.
(It does not claim to "never refuse": when a budget is genuinely too small the run declines cleanly rather than crashing. Graceful degrade-don't-die — sliding down a space/time curve to finish anyway — is the Phase-D research direction, not a present claim.)
The contract applies to the bounded whole-genome germline path, rosalind variants --index.
State the RAM you have. --memory-budget-mb N on variants, --budget-mb N on plan/verify.
Ask before committing a byte whether the job fits. plan reads only the index header (plus your
declared depth/read-length assumptions) — it never opens the BAM:
rosalind plan --index genome.idx --max-depth 1000 --max-read-len 250 --budget-mb 2048It prints a breakdown — reference decode + active set @ max-depth + engine overhead, atop a measured
process baseline — and a verdict: [FITS] or [REFUSE].
rosalind variants --index genome.idx --alignments sample.sorted.bam \
--memory-budget-mb 2048 --enforce -o sample.vcfWith --enforce:
- predicted peak > budget → refuse up front (exit 3), before doing any work, with an actionable
message (raise the budget, lower
--max-depth, or drop--enforce); - realized peak > budget → fail loud (exit 4) after writing the VCF + receipt (you keep the data and the proof it overran) — never a silent overrun;
- otherwise the run completes within budget.
Without --enforce, the budget is record-only: the run always completes and the verdict is recorded in
the receipt. The active read set is capped at --max-depth (default 1000; 0 = uncapped) — deterministic
downsampling that bounds the working set; output changes only at sites deeper than the cap.
Re-check a receipt without re-running:
rosalind verify --manifest sample.vcf.manifest.jsonIt re-hashes the recorded inputs and outputs (BLAKE3) and re-checks the recorded peak against the budget
(supplied via --budget-mb, or read from the manifest). Exit 0 if everything matches and fits;
non-zero (exit 5) with a per-check report on any drift, missing file, or over-budget peak. This is the
auditability story containers can't give you for a non-deterministic caller.
- Germline
variants --indexis the bounded path: peak ≈ the largest contig's reference + the depth-capped active set, independent of BAM size. Reads stream one record at a time. - Somatic (
somatic) is region-bounded, not whole-genome-bounded (it collects both pileup streams for the region). - Index build (
rosalind index) is O(reference) in RAM today;plan --referencereports an advisory estimate. Sublinear-space construction is the Phase-D research direction (seedocs/OPEN_PROBLEMS.md). - The engine is single-threaded — outputs are deterministic, but there is no thread-invariance claim yet.
Rosalind's kernel is a bounded, deterministic PileupColumn stream. Compute your own per-locus
analytics over it (coverage, QC, methylation, ML features) and inherit bounded memory + determinism for
free — no variant calling required:
use rosalind::{PileupEngine, PileupParams};
// PileupEngine<S: ReadSource> is an Iterator<Item = Result<PileupColumn, _>>.
// Each PileupColumn carries the locus, ref_base, depth(), allele_counts(), strand_counts().
for column in PileupEngine::new(source, reference, contig, region, PileupParams::default()) {
let col = column?;
// your bounded per-locus metric here
}A complete, runnable example: examples/custom_pileup_analytics.rs
(cargo run --example custom_pileup_analytics).
Legacy / non-bounded. The
GenomicPlugintrait (src/plugin/), theframework/evaluator, and the Pythonrun_rna_seq_plugindemo still work but do not inherit the memory contract. Prefer thePileupColumnsubstrate above for bounded work.
Every receipt is canonical JSON (sorted keys, no timestamps) with BLAKE3 content hashes of the index, the
alignments, and the output VCF, plus the realized peak_rss_bytes / max_working_set_bytes and the
contract params (memory_budget_mb, contract_verdict, enforced, max_depth, max_read_len). Identical
inputs produce a byte-identical VCF and a byte-identical manifest — and rosalind verify proves it.