Patch release on top of v2.2.0. No cache invalidation: existing v2.2.0 caches remain current on upgrade and allelix db update signal-skips every annotator.
Highlights
- ClinVar per-SCV duplicate-row collapse. The v2.2.0 per-SCV TSV migration emitted a small number of exact-duplicate rows on a handful of variants (same rsid, same source, same null clinical significance, same empty trait). v2.2.1 collapses them at load time. Verified on the GIAB GRCh38 benchmark: the v2.2.0 → v2.2.1 written-row delta is exactly the duplicate-row collapses at the affected rsIDs; unique-dedup-key count is unchanged; zero unique real classifications removed. Not an over-filter regression.
- ClinVar curatorial-term filter expansion. The placeholder-significance filter set grew to include three non-classification curatorial terms (
other,association,association_not_found) that ClinVar's submission summary feed occasionally carried through into the cache. These now drop at ingest, matching the sentinel-scan denylist documented in the test protocol. - VCF parser robustness on real-world inputs.
can_parseused to leak a rawUnicodeDecodeErrortraceback when fed a binary file labeled.vcf.gz(e.g. a tabix index that downloaded with the wrong filename from an upstream mirror) or a real VCF carrying a non-UTF-8 byte in a tool-emitted header (##source=,##CL=— common in GATK / DeepVariant / bcftools output). The parser now opens both gzip and plain paths witherrors="replace"so real-world headers parse cleanly (the replacement strategy touches only header strings — VCF data lines are pure ASCII by spec so genotype fidelity is unaffected), andcan_parsecatchesUnicodeDecodeErrorandEOFErroralongsideOSErrorso format sniffing never leaks a traceback. Four committed CI fixtures cover the full{plain, gzipped} × {UTF-8, non-UTF-8}matrix. - CHANGELOG and commit-message sanitize gate. Public CHANGELOG content and every release-layer commit message are now structurally guarded against bare tracker references and internal-only sections. The structural guard runs on every fast-tier pytest pass.
- Invariant-based real-data battery. The gold-standard VCF battery used to pin exact annotation totals as pass criteria. Those totals legitimately drift on every dedup / vocab / ClinVar refresh, and the drift-and-re-pin loop went stale historically. v2.2.1 replaces the pinned counts with floor invariants, a published-HG002 ground-truth ride-along covering spot-checks at MTHFR rs1801133 (C677T het), APOE rs7412 (E2 het), APOE rs429358 (no E4), VEGFA rs2010963 (G/G homozygote), and Factor V rs6025 (not a carrier), the significance vocabulary union, and per-row universal invariants, plus a standalone harness the protocol invokes to assert all four invariant categories. A future legitimate dedup change will not trigger a false alarm; a real over-filter regression will fail the spot-checks hard.
Known limitations
- GRCh38 rsID-less VCFs (typical for benchmark callers) still fall back to ClinVar position resolution for rsID-keyed lookups. Full dbSNP resolution is targeted for v2.3+.
Calibration
- VCF / gVCF parsing was already working in v2.2.0. This release is robustness on the same flagship path, not a missing feature and not a regression.
.vcf.gzcarriers and gVCF reference-block skipping continue to behave as before. - Array carrier counts unchanged. The v2.1.0 strand-aware carrier-matching pathway is untouched; per the v2.1.0 calibration this release does not move array-side results.
- JSON report schema stays at 6. No new fields, no semantic changes.
Fixed
- ClinVar per-SCV duplicate rows collapsed at load time.
- ClinVar curatorial-term placeholders now filtered at ingest (
other,association,association_not_found). - VCF parser no longer leaks tracebacks on binary input labeled
.vcf.gz, on non-UTF-8 header bytes, or on truncated gzip streams. - Public CHANGELOG and release-layer commit messages structurally scrubbed of tracker references and internal-only sections.
Changed
- Gold-standard VCF battery section in the test protocol now references a ground-truth ride-along data file and standalone harness; pass criteria are floor + spot-check + vocabulary + per-row invariants, not pinned counts.
Added
tests/fixtures/mock_vcf{,_non_utf8_header}.vcf{,.gz}— four committed CI fixtures covering the full{plain, gzipped} × {UTF-8, non-UTF-8}parser-robustness matrix.test_data/HG002_GROUND_TRUTH.yaml— published HG002 spot-check data: extract genotypes at MTHFR / APOE / VEGFA / Factor V; per-rsID analyze-output invariants; ClinVar + PharmGKB significance vocabulary union; per-file floors; universal per-row invariants.test_data/check_ground_truth.py— standalone harness that loads the ground-truth YAML and asserts floors + spot-checks + vocab + universal invariants on any allelix JSON report.
Verification
-
Tests. 1703 passed, 0 skipped, 5 deselected (slow / integration).
-
Coverage. CI 3.11 / 3.12 matrix clears the 92.5 floor. Local 3.14 measures 92.97; CI runs ~0.1–0.2pp lower per the calibration note in
pyproject.toml. -
Lint.
ruff check/ruff format --check/mypyall clean. -
Ground-truth harness on the three bundled WGS battery files, all invariants hold:
File Annotations Unique keys GIAB GRCh38 benchmark 773 630 GIAB GRCh37 benchmark 3,058 2,157 HG00187 GATK-HC gVCF 6 6 -
Wrong-allele safety invariant. Every alt-set annotation with a stamped CADD score has its alt directly in gnomAD's alts at that rsID; zero via-complement hits.