Skip to content

Phase B4: bounded whole-genome variants --index over the persisted index - #19

Merged
logannye merged 7 commits into
mainfrom
rosalind/phase-b4-variants-index
May 28, 2026
Merged

Phase B4: bounded whole-genome variants --index over the persisted index#19
logannye merged 7 commits into
mainfrom
rosalind/phase-b4-variants-index

Conversation

@logannye

Copy link
Copy Markdown
Owner

Summary

Wires Rosalind's germline caller onto the persisted multi-contig index, delivering the flagship capability:

rosalind variants --index <idx> --alignments <sorted.bam> calls germline variants across every contig of a persisted index in bounded, predictable memory — reads stream one record at a time, the reference is read from the index per-contig, the pileup is already columnar — emitting a multi-contig VCF plus a memory + reproducibility receipt that shows the bounded peak.

This operationalizes Rosalind's core differentiator — memory as a declared, predictable, verifiable contract — on the workload builders actually run (align elsewhere, arrive with a sorted BAM, call with Rosalind). No FM-index/aligner is needed on this path: only the reference (self-contained from the .idx via B4a) + the streaming pileup + the abstention-aware caller shipped in Phase A.

Spec: docs/superpowers/specs/2026-05-27-phase-b4-variants-index-design.md · Plan: docs/superpowers/plans/2026-05-27-phase-b4-variants-index.md.

What's in it (by commit)

  • StreamingBamSource (src/io/bam.rs) — a bounded ReadSource that pulls one BAM record at a time via bam::Reader::read (never materializes the file), sharing the Record → AlignedRead mapping (record_to_aligned_read) with read_bam_as_core_reads. A (contig_id, pos) monotonicity guard rejects unsorted / @SQ-order-mismatched input (accepts equal positions for depth; rejects strict descent).
  • call_germline_region_tracked + call_germline_whole_genome (src/call/) — the per-contig caller now also surfaces the engine's max pileup working set (call_germline_region delegates, signature unchanged → existing call sites untouched). The whole-genome drive makes a single sorted pass, partitions it per contig with a peeking PerContig adapter, decodes each contig's reference from the B4a ReferenceView, and reuses the tested per-contig caller. Peak ≈ largest contig's reference + the pileup working set — independent of BAM size.
  • variants --index (src/main.rs) — --index XOR --reference (exactly one). --index loads the index (ContigSet + ReferenceView), streams the sorted BAM, runs the drive, and writes a multi-contig VCF (one ##contig per contig) + manifest. --chrom/--region-start error under --index; SAM under --index errors with guidance (the legacy SAM reader is single-contig).
  • Memory receipt + record-only --memory-budget-mb — the run reports realized peak RSS + the engine's max pileup working set (stderr + manifest params). --memory-budget-mb flags overage against the realized peak but never aborts (enforcement is Phase C). Makes the bounded contract visible + verifiable, not just claimed.

Test plan / gates (spec §8 — all verified)

  • Bounded reads: variants --index streams the BAM (no full-file Vec); structurally uses StreamingBamSource, never read_bam_as_core_reads/BamSource.
  • No rebuild: the path never builds an FM-index / calls SA-IS.
  • Self-contained: calls from the .idx alone — integration test deletes the source FASTA and still calls.
  • Parity: single-contig --index records == variants --reference <same fa> on the same sorted BAM.
  • Multi-contig / whole-genome: call::whole_genome lib test asserts the drive == the per-contig union; multi-contig ##contig headers.
  • Sort safety: out-of-order / index-order-mismatched BAM rejected with a clear error (unit-tested).
  • Reproducible + receipt: manifest records .idx+BAM BLAKE3 + realized peak RSS + max working set; --memory-budget-mb 0 flags EXCEEDED but the run completes (record-only).

Full suite green: 154 lib + all integration binaries, 0 failed; zero warnings on the feature surface. Final whole-branch review verdict: READY TO MERGE (no Critical/Important findings).

Known follow-ups (out of B4's scope by design)

  • Perf (fast-follow): record_to_aligned_read does a per-record linear ContigSet::by_name on the streaming path → O(reads × contigs). Correct, and a pre-existing pattern (the materializing reader does the same); B4 scoped perf out ("deliver the capability, perf follows"). Clean fix: a one-time tid → contig_id table in StreamingBamSource.
  • Nits: --region-start 0 isn't distinguishable from the default under --index (harmless); two clippy::type_complexity warnings (project doesn't gate clippy).
  • Deferred to later phases: the aligner over the index (align --index / somatic --index) → Phase E; SAM streaming; on-demand ref_base (O(window) reference); budget enforcement + rosalind plan/verify → Phase C.

🤖 Generated with Claude Code

logannye and others added 7 commits May 27, 2026 17:26
…persisted index

Reprioritized ahead of the aligner (builder value: BYO-aligner -> BAM; Rosalind's edge is the reproducible/BOUNDED/abstention-aware caller). variants --index calls germline variants across all contigs in BOUNDED memory: a StreamingBamSource (record-at-a-time, no full-BAM Vec) + coordinate-sort monotonicity guard; per-contig reference via ReferenceView (B4a); reuses call_germline_region + write_germline_vcf (multi-contig ##contig) + manifest. Surfaces the memory contract: realized peak RSS + engine working-set in the receipt + record-only --memory-budget-mb (no enforcement = Phase C). Sub-stages: (1) streaming sorted source, (2) bounded multi-contig drive + variants --index + multi-contig VCF, (3) memory receipt. Deferred: aligner, somatic --index, on-demand ref_base, SAM streaming, enforcement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…persisted index

4 tasks: (1) StreamingBamSource (record-at-a-time + (contig_id,pos) sort guard; shared record mapping), (2) call_germline_region_tracked + call_germline_whole_genome drive (per-contig PerContig adapter + ReferenceView decode; reuses the per-contig caller), (3) variants --index CLI (BAM-only, XOR --reference, multi-contig VCF + manifest), (4) memory receipt (peak RSS + max working set) + record-only --memory-budget-mb. CLI tests via index->align->sort->variants (no rust-htslib dev-dep). Derived from the committed spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Streams one record at a time via bam::Reader::read (no full-file Vec), sharing the Record->AlignedRead mapping (extracted as record_to_aligned_read) with read_bam_as_core_reads. A (contig_id,pos) monotonicity guard rejects unsorted / index-order-mismatched BAMs. The bounded-reads foundation for whole-genome variants --index.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…+ ReferenceView

call_germline_region_tracked surfaces the max pileup working set (call_germline_region delegates, signature unchanged). call_germline_whole_genome makes a single sorted pass, partitions per contig (PerContig adapter), decodes each contig's reference from ReferenceView, and reuses the per-contig caller — peak ≈ largest contig + working set, independent of input size. Verified == the per-contig union.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ersisted index

variants takes --index XOR --reference (exactly one). --index loads the index (ContigSet + ReferenceView), streams a sorted BAM (StreamingBamSource), runs call_germline_whole_genome, and writes a multi-contig VCF + manifest (inputs = .idx + BAM). --chrom/--region-start error under --index; SAM under --index errors with guidance. Parity with --reference on a single contig; self-contained (no FASTA).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pure formatting (1-line -> 4-line assert! reflow) so src/call/whole_genome.rs is fmt-clean; no semantic change. Folded out of the Task 3 commit, which kept to its two named files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…get-mb

Surfaces the bounded-memory contract: the run reports realized peak RSS + the engine's max pileup working set (to stderr and the manifest params). --memory-budget-mb flags overage against the realized peak but never aborts (enforcement is Phase C). Operationalizes Rosalind's differentiator — predictable, verifiable memory — on the flagship whole-genome workload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@logannye
logannye merged commit b39dcbe into main May 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant