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 paths — rosalind variants --index (germline calling) and rosalind features --index (per-locus feature egress), which share the same streaming engine and therefore the same plan/--enforce/verify envelope.
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) by an
unbiased content-hash reservoir — it bounds the working set without biasing allele balance, so a deep
variant is not silently dropped. Output changes only at sites deeper than the cap, and the dropped-read
count is surfaced (stderr + the receipt's over_max_depth).
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 --indexandfeatures --indexare the bounded paths: peak ≈ the largest contig's reference + the depth-capped active set, independent of BAM size. Reads stream one record at a time; output rows (VCF calls or feature rows) stream straight to disk with no genome-wide buffer. - 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 manifest identical except for the realized peak_rss_bytes (a
machine-dependent measurement) — rosalind verify re-checks the recorded hashes and peak against the budget.