diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..198cdd3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,46 @@ +# Changelog + +All notable changes to Rosalind are recorded here. Versions follow [Semantic Versioning](https://semver.org). + +## [0.1.0] — 2026-06-02 + +First tagged release: a deterministic, low-memory genomics engine where **memory is a verifiable +contract** — predict it before you commit, honor it during the run, and verify it after. + +### The memory contract +- `rosalind plan` — predict a job's peak memory against a declared budget *before* committing a byte. +- `rosalind variants … --enforce` — honor the budget: refuse up front (exit 3) or fail loud (exit 4), + never a silent OOM-kill. Record-only without `--enforce`. +- `rosalind verify` — re-check a run's BLAKE3 receipt without re-running. +- The **`rosalind-budget` GitHub Action** — enforce the contract in *your* CI (fail the build on breach). + +### Variant calling +- **Bounded whole-genome germline SNV calling** (`variants --index`) over a coordinate-sorted BAM and a + persisted index: peak memory tracks coverage, not BAM size. Calibrated, abstention-aware. +- **Unbiased depth-cap downsampling** — a content-hash reservoir that bounds the working set without + biasing allele balance (no silent variant drops); dropped-read counts surfaced in the receipt. +- **Tumor/normal somatic** SNV + simple-indel calling (`somatic`). +- **Measured detection accuracy** on simulated diploid truth (precision/recall 1.00/1.00 on clean data); + `eval-germline` / `eval-somatic` truth-set comparison (the `eval-germline` path is GIAB-ready). + +### Index, alignment, I/O +- Build-once, memory-mapped, byte-reproducible FM-index (`index` / `locate`). +- Single-contig FM-index aligner (`align`); deterministic external-merge coordinate sort (`sort`); + streaming gzip/bgzf FASTA/FASTQ input. + +### Reproducible ML feature substrate +- `rosalind features --index` — the same bounded stream as a per-locus feature **TSV**, byte-identical + run-to-run, with a hash receipt: **bit-reproducible training inputs**. +- `python/rosalind.py` (stdlib + numpy) loads it; `examples/reproducible_features_demo.py` proves the + bit-reproducibility end-to-end. + +### Reproducibility & distribution +- Byte-identical primary outputs and a canonical-JSON BLAKE3 receipt per run. +- Prebuilt static/native binaries via a tagged release + `install.sh`; a 60-second quickstart. + +### Research direction +- The `~√t` (square-root-space) framework is retained as honest framing for **sublinear-space index + construction** (Phase D); today's index build is `O(reference)` and the contract covers call/query. + See [`docs/OPEN_PROBLEMS.md`](docs/OPEN_PROBLEMS.md). + +[0.1.0]: https://github.com/logannye/rosalind/releases/tag/v0.1.0 diff --git a/CONTRACT.md b/CONTRACT.md index ae76bec..60e6cce 100644 --- a/CONTRACT.md +++ b/CONTRACT.md @@ -14,7 +14,7 @@ the Phase-D research direction, not a present claim.) ## The four verbs -The contract applies to the bounded whole-genome germline path, `rosalind variants --index`. +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. ### 1. Declare @@ -48,8 +48,10 @@ With `--enforce`: - 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. +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`). ### 4. Verify — `rosalind verify` @@ -66,8 +68,9 @@ auditability story containers can't give you for a non-deterministic caller. ## What's bounded (honest scope) -- **Germline `variants --index`** is 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. +- **Germline `variants --index`** and **`features --index`** are 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 --reference` reports an