allelix 2.3.1__tar.gz → 2.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {allelix-2.3.1 → allelix-2.4.0}/PKG-INFO +64 -35
  2. {allelix-2.3.1 → allelix-2.4.0}/README.md +63 -34
  3. {allelix-2.3.1 → allelix-2.4.0}/allelix/__init__.py +1 -1
  4. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/__init__.py +10 -2
  5. allelix-2.4.0/allelix/annotators/_resolution.py +259 -0
  6. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/base.py +11 -0
  7. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/clinvar.py +231 -231
  8. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/gnomad.py +4 -4
  9. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/gwas.py +8 -2
  10. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/pharmgkb.py +32 -3
  11. allelix-2.4.0/allelix/annotators/rsid_identity.py +237 -0
  12. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/snpedia.py +7 -1
  13. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/_helpers.py +183 -28
  14. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/_options.py +24 -1
  15. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/analyze.py +8 -0
  16. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/config.py +48 -9
  17. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/db.py +15 -2
  18. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/utility.py +124 -141
  19. {allelix-2.3.1 → allelix-2.4.0}/allelix/config.py +47 -1
  20. {allelix-2.3.1 → allelix-2.4.0}/allelix/data/clinvar_clnsig_snapshot.yaml +1 -1
  21. {allelix-2.3.1 → allelix-2.4.0}/allelix/data/high_value_snps.yaml +1 -1
  22. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/_versions.py +3 -2
  23. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/gwas_loader.py +2 -2
  24. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/manager.py +13 -13
  25. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/pharmgkb_loader.py +1 -1
  26. allelix-2.4.0/allelix/databases/rsid_identity_loader.py +377 -0
  27. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/schema.py +28 -0
  28. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/snpedia_parser.py +2 -2
  29. {allelix-2.3.1 → allelix-2.4.0}/allelix/exporters/plink.py +9 -4
  30. {allelix-2.3.1 → allelix-2.4.0}/allelix/models.py +71 -4
  31. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/_helpers.py +24 -2
  32. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/base.py +11 -1
  33. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/ftdna.py +23 -12
  34. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/ftdna_famfinder.py +5 -5
  35. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/ftdna_illumina.py +9 -1
  36. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/livingdna.py +2 -2
  37. allelix-2.4.0/allelix/parsers/myheritage.py +205 -0
  38. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/twentythreeandme.py +1 -1
  39. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/vcf.py +528 -72
  40. allelix-2.4.0/allelix/reports/__init__.py +108 -0
  41. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/_pipeline.py +286 -260
  42. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/diff.py +5 -5
  43. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/high_value.py +43 -4
  44. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/html.py +110 -10
  45. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/json_report.py +33 -5
  46. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/terminal.py +24 -4
  47. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/vcf.py +38 -7
  48. {allelix-2.3.1 → allelix-2.4.0}/allelix/utils/allele.py +84 -5
  49. {allelix-2.3.1 → allelix-2.4.0}/allelix/utils/build_detect.py +39 -9
  50. allelix-2.4.0/allelix/utils/plausibility.py +77 -0
  51. {allelix-2.3.1 → allelix-2.4.0}/allelix.egg-info/PKG-INFO +64 -35
  52. {allelix-2.3.1 → allelix-2.4.0}/allelix.egg-info/SOURCES.txt +12 -0
  53. {allelix-2.3.1 → allelix-2.4.0}/pyproject.toml +7 -7
  54. allelix-2.4.0/tests/test_allele_identity_invariants.py +492 -0
  55. {allelix-2.3.1 → allelix-2.4.0}/tests/test_changelog_sanitize.py +5 -5
  56. allelix-2.4.0/tests/test_chip_gvcf_parity.py +591 -0
  57. {allelix-2.3.1 → allelix-2.4.0}/tests/test_cli.py +107 -25
  58. {allelix-2.3.1 → allelix-2.4.0}/tests/test_cli_vcf_out.py +3 -3
  59. {allelix-2.3.1 → allelix-2.4.0}/tests/test_config.py +1 -1
  60. {allelix-2.3.1 → allelix-2.4.0}/tests/test_end_to_end.py +29 -15
  61. {allelix-2.3.1 → allelix-2.4.0}/tests/test_extract_rsidless_gh128.py +1 -1
  62. {allelix-2.3.1 → allelix-2.4.0}/tests/test_models.py +5 -5
  63. allelix-2.4.0/tests/test_myheritage_delimiter.py +100 -0
  64. allelix-2.4.0/tests/test_myheritage_lowpass.py +148 -0
  65. {allelix-2.3.1 → allelix-2.4.0}/tests/test_original_rsid_never_serializes.py +8 -8
  66. allelix-2.4.0/tests/test_plausibility.py +412 -0
  67. allelix-2.4.0/tests/test_resolution_hoist.py +306 -0
  68. allelix-2.4.0/tests/test_rsid_identity.py +674 -0
  69. allelix-2.4.0/tests/test_symbolic_vcf_rejection.py +104 -0
  70. {allelix-2.3.1 → allelix-2.4.0}/tests/test_version.py +2 -2
  71. allelix-2.3.1/allelix/parsers/myheritage.py +0 -118
  72. allelix-2.3.1/allelix/reports/__init__.py +0 -40
  73. {allelix-2.3.1 → allelix-2.4.0}/LICENSE +0 -0
  74. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/alphamissense.py +0 -0
  75. {allelix-2.3.1 → allelix-2.4.0}/allelix/annotators/cadd.py +0 -0
  76. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/__init__.py +0 -0
  77. {allelix-2.3.1 → allelix-2.4.0}/allelix/cli/focused.py +0 -0
  78. {allelix-2.3.1 → allelix-2.4.0}/allelix/compare.py +0 -0
  79. {allelix-2.3.1 → allelix-2.4.0}/allelix/data/__init__.py +0 -0
  80. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/__init__.py +0 -0
  81. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/alphamissense_loader.py +0 -0
  82. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/cadd_loader.py +0 -0
  83. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/cpic_loader.py +0 -0
  84. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/gnomad_loader.py +0 -0
  85. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/loader_utils.py +0 -0
  86. {allelix-2.3.1 → allelix-2.4.0}/allelix/databases/snpedia_loader.py +0 -0
  87. {allelix-2.3.1 → allelix-2.4.0}/allelix/exporters/__init__.py +0 -0
  88. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/__init__.py +0 -0
  89. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/ancestrydna.py +0 -0
  90. {allelix-2.3.1 → allelix-2.4.0}/allelix/parsers/myhappygenes.py +0 -0
  91. {allelix-2.3.1 → allelix-2.4.0}/allelix/py.typed +0 -0
  92. {allelix-2.3.1 → allelix-2.4.0}/allelix/reports/methylation.py +0 -0
  93. {allelix-2.3.1 → allelix-2.4.0}/allelix/utils/__init__.py +0 -0
  94. {allelix-2.3.1 → allelix-2.4.0}/allelix.egg-info/dependency_links.txt +0 -0
  95. {allelix-2.3.1 → allelix-2.4.0}/allelix.egg-info/entry_points.txt +0 -0
  96. {allelix-2.3.1 → allelix-2.4.0}/allelix.egg-info/requires.txt +0 -0
  97. {allelix-2.3.1 → allelix-2.4.0}/allelix.egg-info/top_level.txt +0 -0
  98. {allelix-2.3.1 → allelix-2.4.0}/setup.cfg +0 -0
  99. {allelix-2.3.1 → allelix-2.4.0}/tests/test_cli_helpers.py +0 -0
  100. {allelix-2.3.1 → allelix-2.4.0}/tests/test_compare.py +0 -0
  101. {allelix-2.3.1 → allelix-2.4.0}/tests/test_mock_data_invariants.py +0 -0
  102. {allelix-2.3.1 → allelix-2.4.0}/tests/test_registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: allelix
3
- Version: 2.3.1
3
+ Version: 2.4.0
4
4
  Summary: Open-source genotype analysis toolkit. Format-agnostic ingestion, database-agnostic annotation, offline-first.
5
5
  Author: Allelix
6
6
  Maintainer-email: dial481 <dial481@users.noreply.github.com>
@@ -55,7 +55,7 @@ Dynamic: license-file
55
55
 
56
56
  # Allelix
57
57
 
58
- > **Status:** Production. Nine parser formats (including VCF + gVCF), four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three GRCh38-only enrichment sources (gnomAD + AlphaMissense + CADD), licensable-source gating for commercial users, dual-build ClinVar caches (GRCh37 + GRCh38), HTML/JSON/terminal reports and annotated VCF output for pipeline integration (v2.3.0+), methylation + pharmacogenomics focused commands, report diffing, persistent config with commercial-mode safety switch. Modern-build position detection requires at least three concordant seed SNPs and an 80% winning ratio before it overrides a fallback or header signal; a tentative GRCh36 signal instead fails closed to GRCh36 because no modern position cache is safe for it (ADR-0025, ADR-0037). No regex on prose anywhere in production. The [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md) tracks every release.
58
+ > **Status:** Production. Nine parser formats (including VCF + gVCF), four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three GRCh38 enrichment sources (gnomAD + AlphaMissense + CADD) reached from GRCh37 input through a cross-build rsID identity table, licensable-source gating for commercial users, dual-build ClinVar caches (GRCh37 + GRCh38), HTML/JSON/terminal reports and annotated VCF output for pipeline integration (v2.3.0+), methylation + pharmacogenomics focused commands, report diffing, persistent config with commercial-mode safety switch. Modern-build position detection requires at least three concordant seed SNPs and an 80% winning ratio before it overrides a fallback or header signal; a tentative GRCh36 signal instead fails closed to GRCh36 because no modern position cache is safe for it (ADR-0025, ADR-0037). No regex on prose anywhere in production. The [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md) tracks every release.
59
59
 
60
60
  ## Quickstart
61
61
 
@@ -64,7 +64,7 @@ Dynamic: license-file
64
64
  ```bash
65
65
  pip install allelix
66
66
 
67
- # Download reference databases (~16 GB default install; ~22 GB if you opt into CADD).
67
+ # Download reference databases (~18 GB default install; ~24 GB if you opt into CADD).
68
68
  # Use --no-gnomad / --no-alphamissense to skip the large ones.
69
69
  # CADD is opt-in: download with `allelix db update --cadd`, then pass
70
70
  # `--cadd` to an analysis or set `sources.cadd = true` persistently.
@@ -79,6 +79,10 @@ allelix analyze your_wgs.vcf.gz --output report.html
79
79
  # Multi-sample VCF — pick which sample to analyze
80
80
  allelix analyze trio.vcf.gz --sample HG002 --output report.html
81
81
 
82
+ # VCF quality gate: rows the variant caller filtered (FILTER not PASS) are
83
+ # skipped and counted; calls with GQ below 20 or no reads become no-calls.
84
+ allelix analyze your_wgs.vcf.gz --keep-filtered --min-gq 10 --output report.html
85
+
82
86
  # Filter to a custom panel (rsIDs + gene names, one per line; '#' comments and blank lines ignored)
83
87
  allelix analyze your_genotype_file.txt --filter-file my_panel.txt --output report.html
84
88
 
@@ -95,15 +99,15 @@ See [Development](#development) for source installs and running tests, [Managing
95
99
 
96
100
  | Format | Status | Notes |
97
101
  |---|---|---|
98
- | MyHappyGenes (Tempus) | ✓ | Tab-delimited, 5 columns. **Build is auto-detected** — real-world MHG exports mislabel the header as "build 37.1" while shipping GRCh38 coordinates. Allelix detects from position data and warns on header/data disagreement (ADR-0021). |
102
+ | MyHappyGenes (Tempus) | ✓ | Tab-delimited, 5 columns. **Build is auto-detected** — real-world MHG exports mislabel the header as "build 37.1" while shipping GRCh38 coordinates. Allelix detects from position data and warns on header/data disagreement (ADR-0021). See [docs/formats.md](https://github.com/allelix/allelix/blob/main/docs/formats.md#myhappygenes-tempus). |
99
103
  | 23andMe | ✓ | Tab-delimited, 4 columns, concatenated genotype. Supports build 36/37/38 from header. I-prefixed probe IDs passed through. |
100
104
  | AncestryDNA | ✓ | Tab-delimited, 5 columns. Chromosome mapping: 23→X, 24→Y, 25→X (PAR), 26→MT. V1 and V2 chip layouts. |
101
105
  | Family Tree DNA | ✓ | CSV, double-quoted fields, concatenated genotype. Build 37 default. |
102
- | MyHeritage DNA | ✓ | CSV, same structure as FTDNA. Detected by "MyHeritage" in comment header. Handles double-double-quoted field variant. |
106
+ | MyHeritage DNA | ✓ | CSV, same structure as FTDNA. Detected by "MyHeritage" in the file's preamble. Handles double-double-quoted fields and files re-saved through a spreadsheet (padded rows, signature not on line 1, tab-delimited copies). Two exports: the **array** export (pre-2026 kits) and the **low-pass WGS** export (kits from January 2026; genotypes imputed from about 2x coverage), which the report labels as imputed and whose `##reference=build37` line is used as the header build. See [docs/formats.md](https://github.com/allelix/allelix/blob/main/docs/formats.md#myheritage). |
103
107
  | Living DNA | ✓ | Tab-delimited despite `.csv` extension. Handles AX-, AFFX-prefixed and CHR:POS positional SNP IDs. |
104
108
  | FTDNA Illumina raw | ✓ | Tab-delimited variant of the FTDNA export (distinct from the CSV format above). `RSID/CHROMOSOME/POSITION/RESULT` columns. Build 37 default. |
105
109
  | FTDNA FamFinder | ✓ | Third FTDNA file shape: tab-delimited with **separate `ALLELE1` / `ALLELE2` columns** instead of a concatenated `RESULT`. Detected by the `famfinder` substring in the file header plus the 5-column canonical header. Build 37 default. |
106
- | VCF / gVCF | ✓ | REF/ALT encoding, `0/1` genotype notation. Plain VCF: absence at a position means reference. gVCF: explicit reference blocks (lines with `<NON_REF>` ALT and `END=` INFO) are skipped — they match nothing in any annotation database. Multi-sample files require `--sample <ID>`. Streams via stdlib; `.vcf.gz` handled transparently. Optional `pip install allelix[vcf-index]` enables pysam-backed tabix random access for fast `extract --snps` on huge VCFs. |
110
+ | VCF / gVCF | ✓ | REF/ALT encoding, `0/1` genotype notation. Plain VCF: absence at a position means reference. gVCF: explicit reference blocks (lines with `<NON_REF>` ALT and `END=` INFO) are not annotated — they match nothing in any annotation database — but they are read at high-value positions: a block with low genotype quality or no reads there makes the position a no-call, and so does a gVCF position no record covers. High-value no-calls list the reason (for example `low_gq_block`, `no_coverage`, `filtered`, `low_gq_call`). A plain VCF has no reference blocks, so a position without a record is reported as unknown rather than as reference or as a no-call. Multi-sample files require `--sample <ID>`. Rows the variant caller rejected (FILTER other than `PASS` or `.`) are skipped and counted in the report; `--keep-filtered` keeps them. A call with genotype quality below `--min-gq` (default 20) or with no reads (DP 0) is reported as a no-call. The spanning-deletion allele `*` is treated as symbolic. A VCF that holds only structural-variant or copy-number records (such as a provider's separate `sv` / `cnv` file) is rejected with a message naming the file to use instead; see [docs/formats.md](https://github.com/allelix/allelix/blob/main/docs/formats.md#sequencingcom-30x-whole-genome) for per-provider deliverables. Streams via stdlib; `.vcf.gz` handled transparently. Optional `pip install allelix[vcf-index]` enables pysam-backed tabix random access for fast `extract --snps` on huge VCFs. |
107
111
 
108
112
  Adding a new format means adding one file to `allelix/parsers/` and registering an instance in the `PARSERS` list in `allelix/parsers/__init__.py`.
109
113
 
@@ -113,23 +117,24 @@ Adding a new format means adding one file to `allelix/parsers/` and registering
113
117
  |---|---|
114
118
  | **v2.2** | Annotation model expansion (cross-source conflict surfacing, risk-allele display, structured MTAG flag), custom-panel UX improvements, methylation panel retune + citations, ClinVar source switch (VCF → `variant_summary.txt`), CLI cleanups (`db clean` / `db path`). |
115
119
  | **v2.3** | Annotated VCF output plus v2.3.1 correctness hardening: cross-build enrichment guards, GWAS effect-type disambiguation, conservative build confidence, SNPedia orientation handling, and strict slow-suite drift verification. |
116
- | **v2.4** | Forward-strand normalization for GWAS risk alleles, broader and chromosome-aware build sampling with explicit provenance, test isolation, and deferred cache-loader hardening. |
120
+ | **v2.4** | Correctness hardening: cross-build rsID identity table with explicit allele translation, plausibility flag for genotyping-artifact detection, VCF quality gate honouring FILTER and genotype quality, unified rsID-recovery step across all commands, and parser/format hygiene. |
117
121
  | **Later** | Variant consequences, CNVs and repeat expansions, gnomAD genomes, supplemental genotype-file merging, ancestry estimation, and PRS support. These are directional themes rather than release commitments. |
118
122
 
119
- Issues and milestones are tracked at [github.com/allelix/allelix/issues](https://github.com/allelix/allelix/issues). Annotator-level strand-aware carrier matching (R-1) shipped in v2.1.0's ADR-0035 cluster.
123
+ Issues and milestones are tracked at [github.com/allelix/allelix/issues](https://github.com/allelix/allelix/issues). Annotator-level strand-aware carrier matching shipped in v2.1.0's ADR-0035 cluster.
120
124
 
121
125
  ## Supported Databases
122
126
 
123
127
  | Database | Status | Notes |
124
128
  |---|---|---|
125
- | ClinVar (GRCh37 + GRCh38) | ✓ | Public domain (NCBI). SNVs + indels + multi-allelic sites. **Both builds cached**; `analyze` dispatches by detected build (ADR-0021). Carrier rule (ADR-0007) requires the user to carry the ALT allele. Indel-anchor protection (ADR-0011) prevents single-base array readouts from matching anchor-base indels. |
129
+ | ClinVar (GRCh37 + GRCh38) | ✓ | Public domain (NCBI). SNVs + indels + multi-allelic sites. **Both builds cached**; `analyze` dispatches by detected build (ADR-0021). Rows are matched by chromosome, position, REF and ALT, never by rsID alone, and reference-allele records (REF = ALT) are never reported (ADR-0039). Carrier rule (ADR-0007) requires the user to carry the ALT allele. Indel-anchor protection (ADR-0011) prevents single-base array readouts from matching anchor-base indels. |
126
130
  | ClinPGx (formerly PharmGKB) | ✓ | CC BY-SA 4.0. Clinical annotations only — single-rsid SNVs; star alleles and haplotypes deferred (ADR-0009). **Primary non-finding filter is the ClinVar REF carrier rule (ADR-0023):** if ClinVar publishes a single-base REF for the rsid and the user is homozygous for it, the row is suppressed. CPIC's `(rsid, base) → function_class` join (ADR-0020) survives as a secondary tier for rsids ClinVar doesn't catalog. Earlier prose tiers (ADR-0013, ADR-0017, ADR-0018) are superseded. |
127
131
  | CPIC (per-allele function table) | ✓ | Internal data source for the ClinPGx filter. Fetched from `api.cpicpgx.org` at `db update` time. Used to populate the `pharmgkb_allele_function` table — not surfaced to end users as its own annotator. |
128
132
  | SNPedia | ✓ | CC BY-NC-SA 3.0 US. Pre-built cache downloaded via `db update` (~216K wiki pages, ~105K genotype rows). The cache carries SNPedia's orientation metadata: minus-strand alleles are complemented before matching, while unknown-orientation palindromic genotypes abstain rather than risk a false match. If the database is absent, analysis runs without it. For commercial use, pass `--exclude-snpedia`. The cache can also be rebuilt from source via `scripts/scrape_snpedia.py` + `scripts/parse_snpedia.py`. |
129
- | GWAS Catalog | ✓ | Public domain (EBI/NHGRI). Trait–SNP associations with p-values and effect sizes. Carrier rule (ADR-0007) requires the user to carry the risk allele. P-value magnitude scoring maps continuous p-values to the 0–10 scale; only a confidence-interval field that positively identifies a bare odds ratio receives the odds-ratio modifier. Beta coefficients and ambiguous or unit-bearing effects receive no modifier (ADR-0038). Unknown-risk-allele entries fire on rsID match alone but are capped at 3.0. GWAS risk-allele strand normalization remains deferred to v2.4. |
130
- | gnomAD | ✓ | ODbL v1.0. **GRCh38-only enrichment annotator** — adds population allele frequency context to existing annotations. Shows how common each variant is in the general population (~16M exome variants from 730K individuals). A pathogenic variant that 35% of people carry reads very differently from one seen in 0.001%. Pre-built cache downloaded via `db update` (~6GB on disk). It is deliberately disabled, including for rsID resolution, on GRCh37 and GRCh36 inputs. Use `--no-gnomad` to skip. |
131
- | AlphaMissense | ✓ | CC BY 4.0. **GRCh38-only enrichment annotator** — adds DeepMind's protein-structure-based pathogenicity predictions to existing annotations. Scores 71M missense variants on a 0–1 scale: <0.34 = likely benign, >0.564 = likely pathogenic. Complements ClinVar's expert classifications with computational predictions — especially valuable for variants ClinVar hasn't reviewed yet. Pre-built cache downloaded via `db update` (~8GB on disk). It is deliberately disabled on GRCh37 and GRCh36 inputs. Use `--no-alphamissense` to skip. |
132
- | CADD | ✓ | LicenseRef-CADD (non-commercial). **GRCh38-only enrichment annotator** — adds PHRED-scaled deleteriousness scores from CADD v1.7. **Opt-in**, disabled by default and always disabled on GRCh37 and GRCh36 inputs; see [CADD modes](#cadd-modes) below for details. |
133
+ | GWAS Catalog | ✓ | Public domain (EBI/NHGRI). Trait–SNP associations with p-values and effect sizes. Carrier rule (ADR-0007) requires the user to carry the risk allele. The reported allele is the study's effect (risk) allele, which can be the reference allele (ADR-0039). P-value magnitude scoring maps continuous p-values to the 0–10 scale; only a confidence-interval field that positively identifies a bare odds ratio receives the odds-ratio modifier. Beta coefficients and ambiguous or unit-bearing effects receive no modifier (ADR-0038). Unknown-risk-allele entries fire on rsID match alone but are capped at 3.0. GWAS risk-allele strand normalization remains deferred. |
134
+ | gnomAD | ✓ | ODbL v1.0. **GRCh38-only enrichment annotator** — adds population allele frequency context to existing annotations. Shows how common each variant is in the general population (~16M exome variants from 730K individuals). A pathogenic variant that 35% of people carry reads very differently from one seen in 0.001%. Pre-built cache downloaded via `db update` (~7 GB on disk). GRCh37 input is enriched only through the rsID identity table's explicit allele translation (ADR-0040); gnomAD's own rsID resolution stays GRCh38-only, and GRCh36 input receives nothing. Use `--no-gnomad` to skip. |
135
+ | AlphaMissense | ✓ | CC BY 4.0. **GRCh38-only enrichment annotator** — adds DeepMind's protein-structure-based pathogenicity predictions to existing annotations. Scores 71M missense variants on a 0–1 scale: <0.34 = likely benign, >0.564 = likely pathogenic. Complements ClinVar's expert classifications with computational predictions — especially valuable for variants ClinVar hasn't reviewed yet. Pre-built cache downloaded via `db update` (~8GB on disk). GRCh37 input is enriched only through the rsID identity table (ADR-0040); GRCh36 input receives nothing. Use `--no-alphamissense` to skip. |
136
+ | CADD | ✓ | LicenseRef-CADD (non-commercial). **GRCh38-only enrichment annotator** — adds PHRED-scaled deleteriousness scores from CADD v1.7. **Opt-in**, disabled by default; GRCh37 input is scored only through the rsID identity table (ADR-0040) and GRCh36 input never; see [CADD modes](#cadd-modes) below for details. |
137
+ | dbSNP rsID identity | ✓ | Public domain (NCBI dbSNP). Not an annotator: a cross-build table of each annotator rsID's GRCh37 and GRCh38 placement and alleles (ADR-0040). Supplies the reference allele for GRCh37 and GRCh38 array data, recovers rsIDs for rsID-less VCFs on both builds, and translates a GRCh37 allele to its GRCh38 coordinates so gnomAD, AlphaMissense and CADD can be looked up. Strand-inverted loci are translated explicitly; palindromic sites (A/T, C/G, or a site whose dbSNP alleles include all four bases) and alleles that became the GRCh38 reference abstain. Pre-built cache downloaded via `db update` (~4.9M rows covering ~3.0M rsIDs, from dbSNP b157). |
133
138
 
134
139
  ### CADD modes
135
140
 
@@ -139,16 +144,16 @@ CADD ranks how deleterious any single-nucleotide variant is using 100+ annotatio
139
144
 
140
145
  Two modes:
141
146
 
142
- - **Cache mode** (default): pre-built ~5.8 GB SQLite cache (~120M GRCh38 variant keys). Covers nearly every GRCh38 position allelix can annotate from its other databases (gnomAD, AlphaMissense, ClinVar). It is deliberately disabled for GRCh37 and GRCh36 input, even when an rsID happens to exist in the cache.
147
+ - **Cache mode** (default): pre-built ~5.8 GB SQLite cache (~120M GRCh38 variant keys). Covers nearly every GRCh38 position allelix can annotate from its other databases (gnomAD, AlphaMissense, ClinVar). GRCh37 input is scored only after translation through the rsID identity table; GRCh36 input never is.
143
148
  - **Full mode** (`options.cadd_full = true`): tabix queries against the complete CADD v1.7 file via pysam (GRCh38 only). Adds coverage for novel or private variants that appear only in WGS/WES data and are not in any pre-computed database. Requires `pip install allelix[cadd]` for the pysam dependency.
144
149
 
145
- If your input is a GRCh38 genotyping chip file, cache mode is normally all you need. CADD enrichment is unavailable for GRCh37 and GRCh36 chip files.
150
+ If your input is a genotyping chip file, cache mode is normally all you need. GRCh37 chip files are scored through the rsID identity table; GRCh36 files are not scored.
146
151
 
147
152
  ### Build coverage asymmetry (GRCh37 vs GRCh38)
148
153
 
149
- ClinVar dispatches per build and ships with both GRCh37 and GRCh38 caches. gnomAD v4.1 exomes, AlphaMissense, and CADD v1.7 are GRCh38 datasets in Allelix's current data model. Their enrichment and provenance are therefore emitted only for GRCh38 analyses; GRCh37 and GRCh36 analyses intentionally receive none of those values. This guard prevents an rsID or coordinate collision from attaching a valid GRCh38 score to the wrong allele on another assembly.
154
+ ClinVar dispatches per build and ships with both GRCh37 and GRCh38 caches. gnomAD v4.1 exomes, AlphaMissense, and CADD v1.7 are GRCh38 datasets. Every enrichment lookup is made at GRCh38 coordinates by chromosome, position, reference and alternate allele, never by rsID. For GRCh37 input, the cross-build rsID identity table (ADR-0040) translates the allele the user carries at its GRCh37 position into the matching GRCh38 allele, written explicitly on the GRCh38 forward strand where the reference strand was inverted between assemblies. Palindromic sites (A/T, C/G, or all four bases in dbSNP, whose strand cannot be told from sequence) and alleles that are the GRCh38 reference receive no values rather than a guess. Without the identity table installed, GRCh37 analyses receive no gnomAD, AlphaMissense or CADD values; GRCh36 analyses never do.
150
155
 
151
- The same rule applies to position-based rsID recovery: ClinVar can resolve against the selected GRCh37 or GRCh38 cache, while the broader gnomAD resolver participates only on GRCh38. GRCh37 files with rsIDs still use ClinPGx, GWAS Catalog, and SNPedia normally, but an rsID-less GRCh37 VCF has narrower recovery coverage. If you convert between assemblies, re-normalize REF/ALT as part of the conversion and pass `--build` explicitly when the file does not carry a trustworthy build signal.
156
+ Position-based rsID recovery for rsID-less VCFs uses ClinVar (on the selected build), the identity table (on GRCh37 and GRCh38), and gnomAD (GRCh38 only). The same recovery step runs for `analyze`, `stats`, `extract` and `export plink`, so high-value warnings, extracted genotypes and PLINK allele coding all see the recovered rsIDs (ADR-0043). The identity table covers the rsIDs the annotators hold, so an rsID-less GRCh37 VCF now recovers ClinPGx, GWAS Catalog and SNPedia rsIDs as well as ClinVar ones. If you convert between assemblies, re-normalize REF/ALT as part of the conversion and pass `--build` explicitly when the file does not carry a trustworthy build signal.
152
157
 
153
158
  ### Known ClinPGx limitation: reference-genotype rows where ClinVar and CPIC both lack data
154
159
 
@@ -165,7 +170,7 @@ The CFTR × ivacaftor leak (~30+ rows on real data, pre-v0.7.3) is fixed by the
165
170
 
166
171
  Two ClinVar rows in real-world reports are known upstream artifacts, not Allelix bugs:
167
172
 
168
- - **PKD1 rs199476100 GG (Pathogenic/Likely pathogenic, magnitude 8.5).** This is a stop-gained variant with a gnomAD frequency of 0.0005% (7 observations in 1.38 million chromosomes). Homozygosity for this variant is biologically implausible — PKD1 is autosomal dominant and the nonsense variant would be embryonic-lethal or devastating in homozygous state. The chip genotyping call is almost certainly a probe artifact. The code correctly reports what ClinVar says and what the chip reads; the error is upstream of Allelix. Future work: population-frequency filtering could flag ultra-rare variants where the chip call is likely unreliable.
173
+ - **PKD1 rs199476100 GG (Pathogenic/Likely pathogenic, magnitude 8.5).** This is a stop-gained variant with a gnomAD frequency of 0.0005% (7 observations in 1.38 million chromosomes). Homozygosity for this variant is biologically implausible — PKD1 is autosomal dominant and the nonsense variant would be embryonic-lethal or devastating in homozygous state. The chip genotyping call is almost certainly a probe artifact. The code correctly reports what ClinVar says and what the chip reads; the error is upstream of Allelix. The row is now marked implausible (see [Plausibility flag](#plausibility-flag)) but is still shown.
169
174
 
170
175
  - **IL10 rs1800896 CT (Pathogenic, magnitude 9.0).** This is a common polymorphism (MAF ~20–40%) in the IL-10 promoter. ClinVar's Pathogenic classification comes from a single submitter for hepatitis C susceptibility; another submission classifies the allele as "Uncertain risk allele" for leprosy susceptibility. Allelix's per-SCV loader keeps each submitter's significance paired with its own condition, so it does not create cross-submission combinations. The remaining concern is the upstream strength of a single-submitter classification on a common variant. Future work: review-status weighting could down-weight that evidence.
171
176
 
@@ -217,22 +222,41 @@ allelix config set license.commercial true
217
222
 
218
223
  # Assert that you hold a commercial CADD license
219
224
  allelix config set license.cadd true
225
+
226
+ # Tune the plausibility flag (allele frequencies between 0 and 1)
227
+ allelix config set plausibility.homozygous_max_af 0.0001
228
+ allelix config set plausibility.heterozygous_max_af 0
220
229
  ```
221
230
 
222
231
  CLI flags (`--no-gnomad`, `--no-alphamissense`, `--no-cadd`, `--exclude-snpedia`, `--cadd`) override the config for a single run. The config sets the baseline; flags override per-invocation.
223
232
 
233
+ ### Plausibility flag
234
+
235
+ Genotyping arrays sometimes miscall very rare variants, most visibly as a homozygous call for an allele almost nobody carries. Allelix compares each call with the allele's gnomAD frequency and marks it for review. The row is never hidden (ADR-0041).
236
+
237
+ | Call | gnomAD frequency of the allele | Flag |
238
+ |---|---|---|
239
+ | Homozygous | below `plausibility.homozygous_max_af` (default 0.0001, i.e. 0.01%) | **implausible**: often a genotyping artifact |
240
+ | Heterozygous | at or below `plausibility.heterozygous_max_af` (default 0: gnomAD has the site but no carriers) | **suspicious** |
241
+ | Either | otherwise | plausible |
242
+
243
+ The HTML report shows a ⚠ icon next to a flagged genotype, with the reason on hover and in the detail panel. The terminal table marks implausible calls with ⚠ and suspicious ones with ?. JSON reports carry `plausibility` on every annotation (`plausible`, `suspicious`, `implausible`, or empty when not assessed).
244
+
245
+ A call is not assessed when gnomAD has no frequency for the allele. Allelix's gnomAD cache covers exome sites with an rsID, so a missing value says nothing about rarity. Calls are also not assessed when the gnomAD database is skipped. Homozygous calls on X are not assessed because a male's single X reads as homozygous; heterozygous X calls are. Y and mitochondrial calls are not assessed. Confirm a flagged call with a clinical-grade test before relying on it.
246
+
224
247
  ### Database sizes and download times
225
248
 
226
249
  Not all databases are equal in size. `allelix db update` downloads them all by default, but you can skip the large ones if disk space or bandwidth is a concern:
227
250
 
228
251
  | Database | On disk | Download time | What it adds |
229
252
  |---|---|---|---|
230
- | ClinVar (GRCh37 + GRCh38) | ~900MB | 1–2 min | Core clinical variant classifications. Required. |
253
+ | ClinVar (GRCh37 + GRCh38) | ~1.6 GB | 1–2 min | Core clinical variant classifications. Required. |
231
254
  | ClinPGx + CPIC | ~6MB | seconds | Drug-gene interactions. |
232
- | GWAS Catalog | ~200MB | 1–2 min | Trait-SNP associations from genome-wide studies. |
233
- | gnomAD | ~6GB | 5–15 min | Population allele frequencies (how common is this variant?). |
255
+ | GWAS Catalog | ~950 MB | 1–2 min | Trait-SNP associations from genome-wide studies. |
256
+ | gnomAD | ~7 GB | 5–15 min | Population allele frequencies (how common is this variant?). |
234
257
  | AlphaMissense | ~8GB | 5–15 min | Missense pathogenicity predictions (how likely to break protein function?). |
235
- | CADD (opt-in) | ~5GB | 5–15 min | Variant deleteriousness scores (how damaging is this variant?). Download with `db update --cadd`; enable per analysis or in config. |
258
+ | dbSNP rsID identity | ~460 MB | ~1 min | Cross-build placements: reference allele for array data, rsID recovery on both builds, GRCh37 enrichment translation. |
259
+ | CADD (opt-in) | ~6 GB | 5–15 min | Variant deleteriousness scores (how damaging is this variant?). Download with `db update --cadd`; enable per analysis or in config. |
236
260
 
237
261
  gnomAD and AlphaMissense are the largest but add the most interpretive context. gnomAD answers "is this variant rare or common?" — a pathogenic variant carried by 35% of the population reads very differently from one seen in 3 people. AlphaMissense answers "does this missense change likely damage the protein?" — especially valuable for the thousands of variants ClinVar hasn't reviewed yet.
238
262
 
@@ -240,25 +264,26 @@ To skip either during download: `allelix db update --no-gnomad --no-alphamissens
240
264
 
241
265
  ### Managing your data
242
266
 
243
- Allelix stores reference database caches at `~/.local/share/allelix/` (Linux/macOS) or the XDG-equivalent on other platforms. Default install (no CADD) is ~16 GB on disk; with the CADD opt-in it's ~22 GB.
267
+ Allelix stores reference database caches at `~/.local/share/allelix/` (Linux/macOS) or the XDG-equivalent on other platforms. Default install (no CADD) is ~18 GB on disk; with the CADD opt-in it's ~24 GB.
244
268
 
245
269
  ```
246
270
  ~/.local/share/allelix/
247
271
  ├── alphamissense.sqlite ~7.8 GB
248
- ├── gnomad.sqlite ~6.1 GB
272
+ ├── gnomad.sqlite ~7.1 GB
249
273
  ├── cadd.sqlite ~5.8 GB (only if you opted into --cadd)
250
- ├── clinvar.GRCh37.sqlite ~470 MB
251
- ├── clinvar.GRCh38.sqlite ~480 MB
252
- ├── gwas_catalog_associations.tsv ~700 MB
253
- ├── snpedia.sqlite ~390 MB
254
- ├── gwas.sqlite ~190 MB
255
- └── pharmgkb.sqlite ~14 MB
274
+ ├── clinvar.GRCh37.sqlite ~800 MB
275
+ ├── clinvar.GRCh38.sqlite ~800 MB
276
+ ├── gwas_catalog_associations.tsv ~745 MB
277
+ ├── rsid_identity.sqlite ~457 MB
278
+ ├── gwas.sqlite ~202 MB
279
+ ├── snpedia.sqlite ~194 MB
280
+ └── pharmgkb.sqlite ~6 MB
256
281
  ```
257
282
 
258
283
  **The caches are disposable and re-downloadable.** Everything here was fetched by `allelix db update` and can be re-fetched at any time. There's no per-user state in the cache — your genotype files never enter this directory. Safe to delete to reclaim space (or to force a full refresh if you suspect a cache went stale):
259
284
 
260
285
  ```bash
261
- # Reclaim all ~16-22 GB, with size report and confirmation prompt
286
+ # Reclaim all ~18-24 GB, with size report and confirmation prompt
262
287
  allelix db clean
263
288
 
264
289
  # Preserve the CADD cache (avoids re-downloading the slowest one, ~5.8 GB)
@@ -308,9 +333,10 @@ Allelix source code is licensed under the **GNU Affero General Public License v3
308
333
  | ClinPGx (formerly PharmGKB) | clinpgx.org | CC BY-SA 4.0 | Attribution required |
309
334
  | CPIC | cpicpgx.org | CC BY-SA 4.0 | Attribution required. Per-allele function data fetched from `api.cpicpgx.org` at `db update` time; used internally for the ClinPGx non-finding filter (ADR-0020), not surfaced as its own annotator. |
310
335
  | SNPedia | snpedia.com | CC BY-NC-SA 3.0 US | Attribution required, **non-commercial only**. Use `--exclude-snpedia` to omit. |
311
- | gnomAD | gnomad.broadinstitute.org | ODbL v1.0 | Attribution required. GRCh38-only population allele frequencies for context; not a clinical annotator. Use `--no-gnomad` to omit. |
312
- | AlphaMissense | zenodo.org/records/10813168 | CC BY 4.0 | Attribution required. Cheng et al., Science 2023. GRCh38-only missense variant pathogenicity predictions. Use `--no-alphamissense` to omit. |
313
- | CADD | cadd.gs.washington.edu | LicenseRef-CADD | Attribution required, **non-commercial by default**. Commercial licenses available from UW CoMotion. GRCh38-only enrichment; download with `allelix db update --cadd`, then enable per analysis with `--cadd` or persistently in config. Use `--no-cadd` to omit. |
336
+ | gnomAD | gnomad.broadinstitute.org | ODbL v1.0 | Attribution required. GRCh38 population allele frequencies for context (GRCh37 input through the identity table); not a clinical annotator. Use `--no-gnomad` to omit. |
337
+ | AlphaMissense | zenodo.org/records/10813168 | CC BY 4.0 | Attribution required. Cheng et al., Science 2023. GRCh38 missense variant pathogenicity predictions (GRCh37 input through the identity table). Use `--no-alphamissense` to omit. |
338
+ | dbSNP (rsID identity table) | ncbi.nlm.nih.gov/snp | Public domain | No restrictions. Cross-build rsID placements derived from dbSNP; not surfaced as an annotator. |
339
+ | CADD | cadd.gs.washington.edu | LicenseRef-CADD | Attribution required, **non-commercial by default**. Commercial licenses available from UW CoMotion. GRCh38 scores (GRCh37 input through the identity table); download with `allelix db update --cadd`, then enable per analysis with `--cadd` or persistently in config. Use `--no-cadd` to omit. |
314
340
 
315
341
  **Commercial users:** When `license.commercial = true`, non-commercial sources are gated by a three-state permission model. SNPedia is permanently blocked (no commercial license is available). CADD is blocked by default but can be unlocked — the University of Washington offers commercial licenses at `https://els2.comotion.uw.edu/product/cadd-scores`; after purchasing, assert your license with `allelix config set license.cadd true` to re-enable CADD in commercial mode. All other databases (ClinVar, ClinPGx, GWAS Catalog, gnomAD, AlphaMissense) are compatible with commercial use. `allelix config show` displays the permission state for each source.
316
342
 
@@ -359,7 +385,7 @@ Almost always a schema or interpreter version bump in a recent allelix release t
359
385
 
360
386
  ### Build mismatch warning when analyzing a known-good file
361
387
 
362
- Either: (a) the file's header claims one build and the position data confidently indicates another (real-world MHG / Tempus exports do this — header says 37, positions are 38), or (b) the position signal is too small or mixed to be authoritative. Allelix requires at least three concordant seed SNPs and an 80% winning ratio; weaker GRCh37/38 evidence is reported as tentative and the header or fallback remains effective. A tentative GRCh36 winner is the safety exception: Allelix uses GRCh36 so it cannot accidentally query a modern position cache. Modern position-keyed caches are unavailable for that build (see [`docs/grch36-liftover.md`](https://github.com/allelix/allelix/blob/main/docs/grch36-liftover.md)).
388
+ Either: (a) the file's header claims one build and the position data confidently indicates another (real-world MHG / Tempus exports do this — header says 37, positions are 38), or (b) the position signal is too small or mixed to be authoritative. Allelix requires at least three concordant seed SNPs and an 80% winning ratio. A VCF record without an rsID counts as a seed when it sits at that seed's position on a build, so variant-caller output with an empty ID column is detected by position too. Weaker GRCh37/38 evidence is reported as tentative and the header or fallback remains effective. A tentative GRCh36 winner is the safety exception: Allelix uses GRCh36 so it cannot accidentally query a modern position cache. Modern position-keyed caches are unavailable for that build (see [`docs/grch36-liftover.md`](https://github.com/allelix/allelix/blob/main/docs/grch36-liftover.md)).
363
389
 
364
390
  If you trust the file's header more than allelix's detection, force the build: `--build grch37` or `--build grch38`. The build banner in the analyze output will reflect what was actually used.
365
391
 
@@ -391,6 +417,9 @@ Notable load-bearing ADRs:
391
417
  - **ADR-0036 — Annotated VCF output contract.** JSON and annotated VCF schemas evolve independently.
392
418
  - **ADR-0037 — Conservative position-based build confidence.** A winning build needs at least three matches and an 80% ratio; weaker signals remain diagnostic only.
393
419
  - **ADR-0038 — GWAS effect-modifier disambiguation.** Only positively identified odds ratios receive an effect-size modifier; beta and ambiguous effects abstain.
420
+ - **ADR-0042 — VCF quality gate.** The variant caller's FILTER and genotype quality are honoured, low-quality reference blocks are no-calls, and every exclusion is counted in the report.
421
+ - **ADR-0043 — One rsID-recovery step.** Every command that needs rsIDs recovers them for rsID-less input through the same shared step; build detection votes by position instead.
422
+ - **ADR-0041 — Plausibility flag.** Very rare homozygous calls and heterozygous calls with no gnomAD carriers are flagged for review, never suppressed.
394
423
 
395
424
  Release history: see [`CHANGELOG.md`](https://github.com/allelix/allelix/blob/main/CHANGELOG.md).
396
425
 
@@ -16,7 +16,7 @@
16
16
 
17
17
  # Allelix
18
18
 
19
- > **Status:** Production. Nine parser formats (including VCF + gVCF), four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three GRCh38-only enrichment sources (gnomAD + AlphaMissense + CADD), licensable-source gating for commercial users, dual-build ClinVar caches (GRCh37 + GRCh38), HTML/JSON/terminal reports and annotated VCF output for pipeline integration (v2.3.0+), methylation + pharmacogenomics focused commands, report diffing, persistent config with commercial-mode safety switch. Modern-build position detection requires at least three concordant seed SNPs and an 80% winning ratio before it overrides a fallback or header signal; a tentative GRCh36 signal instead fails closed to GRCh36 because no modern position cache is safe for it (ADR-0025, ADR-0037). No regex on prose anywhere in production. The [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md) tracks every release.
19
+ > **Status:** Production. Nine parser formats (including VCF + gVCF), four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three GRCh38 enrichment sources (gnomAD + AlphaMissense + CADD) reached from GRCh37 input through a cross-build rsID identity table, licensable-source gating for commercial users, dual-build ClinVar caches (GRCh37 + GRCh38), HTML/JSON/terminal reports and annotated VCF output for pipeline integration (v2.3.0+), methylation + pharmacogenomics focused commands, report diffing, persistent config with commercial-mode safety switch. Modern-build position detection requires at least three concordant seed SNPs and an 80% winning ratio before it overrides a fallback or header signal; a tentative GRCh36 signal instead fails closed to GRCh36 because no modern position cache is safe for it (ADR-0025, ADR-0037). No regex on prose anywhere in production. The [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md) tracks every release.
20
20
 
21
21
  ## Quickstart
22
22
 
@@ -25,7 +25,7 @@
25
25
  ```bash
26
26
  pip install allelix
27
27
 
28
- # Download reference databases (~16 GB default install; ~22 GB if you opt into CADD).
28
+ # Download reference databases (~18 GB default install; ~24 GB if you opt into CADD).
29
29
  # Use --no-gnomad / --no-alphamissense to skip the large ones.
30
30
  # CADD is opt-in: download with `allelix db update --cadd`, then pass
31
31
  # `--cadd` to an analysis or set `sources.cadd = true` persistently.
@@ -40,6 +40,10 @@ allelix analyze your_wgs.vcf.gz --output report.html
40
40
  # Multi-sample VCF — pick which sample to analyze
41
41
  allelix analyze trio.vcf.gz --sample HG002 --output report.html
42
42
 
43
+ # VCF quality gate: rows the variant caller filtered (FILTER not PASS) are
44
+ # skipped and counted; calls with GQ below 20 or no reads become no-calls.
45
+ allelix analyze your_wgs.vcf.gz --keep-filtered --min-gq 10 --output report.html
46
+
43
47
  # Filter to a custom panel (rsIDs + gene names, one per line; '#' comments and blank lines ignored)
44
48
  allelix analyze your_genotype_file.txt --filter-file my_panel.txt --output report.html
45
49
 
@@ -56,15 +60,15 @@ See [Development](#development) for source installs and running tests, [Managing
56
60
 
57
61
  | Format | Status | Notes |
58
62
  |---|---|---|
59
- | MyHappyGenes (Tempus) | ✓ | Tab-delimited, 5 columns. **Build is auto-detected** — real-world MHG exports mislabel the header as "build 37.1" while shipping GRCh38 coordinates. Allelix detects from position data and warns on header/data disagreement (ADR-0021). |
63
+ | MyHappyGenes (Tempus) | ✓ | Tab-delimited, 5 columns. **Build is auto-detected** — real-world MHG exports mislabel the header as "build 37.1" while shipping GRCh38 coordinates. Allelix detects from position data and warns on header/data disagreement (ADR-0021). See [docs/formats.md](https://github.com/allelix/allelix/blob/main/docs/formats.md#myhappygenes-tempus). |
60
64
  | 23andMe | ✓ | Tab-delimited, 4 columns, concatenated genotype. Supports build 36/37/38 from header. I-prefixed probe IDs passed through. |
61
65
  | AncestryDNA | ✓ | Tab-delimited, 5 columns. Chromosome mapping: 23→X, 24→Y, 25→X (PAR), 26→MT. V1 and V2 chip layouts. |
62
66
  | Family Tree DNA | ✓ | CSV, double-quoted fields, concatenated genotype. Build 37 default. |
63
- | MyHeritage DNA | ✓ | CSV, same structure as FTDNA. Detected by "MyHeritage" in comment header. Handles double-double-quoted field variant. |
67
+ | MyHeritage DNA | ✓ | CSV, same structure as FTDNA. Detected by "MyHeritage" in the file's preamble. Handles double-double-quoted fields and files re-saved through a spreadsheet (padded rows, signature not on line 1, tab-delimited copies). Two exports: the **array** export (pre-2026 kits) and the **low-pass WGS** export (kits from January 2026; genotypes imputed from about 2x coverage), which the report labels as imputed and whose `##reference=build37` line is used as the header build. See [docs/formats.md](https://github.com/allelix/allelix/blob/main/docs/formats.md#myheritage). |
64
68
  | Living DNA | ✓ | Tab-delimited despite `.csv` extension. Handles AX-, AFFX-prefixed and CHR:POS positional SNP IDs. |
65
69
  | FTDNA Illumina raw | ✓ | Tab-delimited variant of the FTDNA export (distinct from the CSV format above). `RSID/CHROMOSOME/POSITION/RESULT` columns. Build 37 default. |
66
70
  | FTDNA FamFinder | ✓ | Third FTDNA file shape: tab-delimited with **separate `ALLELE1` / `ALLELE2` columns** instead of a concatenated `RESULT`. Detected by the `famfinder` substring in the file header plus the 5-column canonical header. Build 37 default. |
67
- | VCF / gVCF | ✓ | REF/ALT encoding, `0/1` genotype notation. Plain VCF: absence at a position means reference. gVCF: explicit reference blocks (lines with `<NON_REF>` ALT and `END=` INFO) are skipped — they match nothing in any annotation database. Multi-sample files require `--sample <ID>`. Streams via stdlib; `.vcf.gz` handled transparently. Optional `pip install allelix[vcf-index]` enables pysam-backed tabix random access for fast `extract --snps` on huge VCFs. |
71
+ | VCF / gVCF | ✓ | REF/ALT encoding, `0/1` genotype notation. Plain VCF: absence at a position means reference. gVCF: explicit reference blocks (lines with `<NON_REF>` ALT and `END=` INFO) are not annotated — they match nothing in any annotation database — but they are read at high-value positions: a block with low genotype quality or no reads there makes the position a no-call, and so does a gVCF position no record covers. High-value no-calls list the reason (for example `low_gq_block`, `no_coverage`, `filtered`, `low_gq_call`). A plain VCF has no reference blocks, so a position without a record is reported as unknown rather than as reference or as a no-call. Multi-sample files require `--sample <ID>`. Rows the variant caller rejected (FILTER other than `PASS` or `.`) are skipped and counted in the report; `--keep-filtered` keeps them. A call with genotype quality below `--min-gq` (default 20) or with no reads (DP 0) is reported as a no-call. The spanning-deletion allele `*` is treated as symbolic. A VCF that holds only structural-variant or copy-number records (such as a provider's separate `sv` / `cnv` file) is rejected with a message naming the file to use instead; see [docs/formats.md](https://github.com/allelix/allelix/blob/main/docs/formats.md#sequencingcom-30x-whole-genome) for per-provider deliverables. Streams via stdlib; `.vcf.gz` handled transparently. Optional `pip install allelix[vcf-index]` enables pysam-backed tabix random access for fast `extract --snps` on huge VCFs. |
68
72
 
69
73
  Adding a new format means adding one file to `allelix/parsers/` and registering an instance in the `PARSERS` list in `allelix/parsers/__init__.py`.
70
74
 
@@ -74,23 +78,24 @@ Adding a new format means adding one file to `allelix/parsers/` and registering
74
78
  |---|---|
75
79
  | **v2.2** | Annotation model expansion (cross-source conflict surfacing, risk-allele display, structured MTAG flag), custom-panel UX improvements, methylation panel retune + citations, ClinVar source switch (VCF → `variant_summary.txt`), CLI cleanups (`db clean` / `db path`). |
76
80
  | **v2.3** | Annotated VCF output plus v2.3.1 correctness hardening: cross-build enrichment guards, GWAS effect-type disambiguation, conservative build confidence, SNPedia orientation handling, and strict slow-suite drift verification. |
77
- | **v2.4** | Forward-strand normalization for GWAS risk alleles, broader and chromosome-aware build sampling with explicit provenance, test isolation, and deferred cache-loader hardening. |
81
+ | **v2.4** | Correctness hardening: cross-build rsID identity table with explicit allele translation, plausibility flag for genotyping-artifact detection, VCF quality gate honouring FILTER and genotype quality, unified rsID-recovery step across all commands, and parser/format hygiene. |
78
82
  | **Later** | Variant consequences, CNVs and repeat expansions, gnomAD genomes, supplemental genotype-file merging, ancestry estimation, and PRS support. These are directional themes rather than release commitments. |
79
83
 
80
- Issues and milestones are tracked at [github.com/allelix/allelix/issues](https://github.com/allelix/allelix/issues). Annotator-level strand-aware carrier matching (R-1) shipped in v2.1.0's ADR-0035 cluster.
84
+ Issues and milestones are tracked at [github.com/allelix/allelix/issues](https://github.com/allelix/allelix/issues). Annotator-level strand-aware carrier matching shipped in v2.1.0's ADR-0035 cluster.
81
85
 
82
86
  ## Supported Databases
83
87
 
84
88
  | Database | Status | Notes |
85
89
  |---|---|---|
86
- | ClinVar (GRCh37 + GRCh38) | ✓ | Public domain (NCBI). SNVs + indels + multi-allelic sites. **Both builds cached**; `analyze` dispatches by detected build (ADR-0021). Carrier rule (ADR-0007) requires the user to carry the ALT allele. Indel-anchor protection (ADR-0011) prevents single-base array readouts from matching anchor-base indels. |
90
+ | ClinVar (GRCh37 + GRCh38) | ✓ | Public domain (NCBI). SNVs + indels + multi-allelic sites. **Both builds cached**; `analyze` dispatches by detected build (ADR-0021). Rows are matched by chromosome, position, REF and ALT, never by rsID alone, and reference-allele records (REF = ALT) are never reported (ADR-0039). Carrier rule (ADR-0007) requires the user to carry the ALT allele. Indel-anchor protection (ADR-0011) prevents single-base array readouts from matching anchor-base indels. |
87
91
  | ClinPGx (formerly PharmGKB) | ✓ | CC BY-SA 4.0. Clinical annotations only — single-rsid SNVs; star alleles and haplotypes deferred (ADR-0009). **Primary non-finding filter is the ClinVar REF carrier rule (ADR-0023):** if ClinVar publishes a single-base REF for the rsid and the user is homozygous for it, the row is suppressed. CPIC's `(rsid, base) → function_class` join (ADR-0020) survives as a secondary tier for rsids ClinVar doesn't catalog. Earlier prose tiers (ADR-0013, ADR-0017, ADR-0018) are superseded. |
88
92
  | CPIC (per-allele function table) | ✓ | Internal data source for the ClinPGx filter. Fetched from `api.cpicpgx.org` at `db update` time. Used to populate the `pharmgkb_allele_function` table — not surfaced to end users as its own annotator. |
89
93
  | SNPedia | ✓ | CC BY-NC-SA 3.0 US. Pre-built cache downloaded via `db update` (~216K wiki pages, ~105K genotype rows). The cache carries SNPedia's orientation metadata: minus-strand alleles are complemented before matching, while unknown-orientation palindromic genotypes abstain rather than risk a false match. If the database is absent, analysis runs without it. For commercial use, pass `--exclude-snpedia`. The cache can also be rebuilt from source via `scripts/scrape_snpedia.py` + `scripts/parse_snpedia.py`. |
90
- | GWAS Catalog | ✓ | Public domain (EBI/NHGRI). Trait–SNP associations with p-values and effect sizes. Carrier rule (ADR-0007) requires the user to carry the risk allele. P-value magnitude scoring maps continuous p-values to the 0–10 scale; only a confidence-interval field that positively identifies a bare odds ratio receives the odds-ratio modifier. Beta coefficients and ambiguous or unit-bearing effects receive no modifier (ADR-0038). Unknown-risk-allele entries fire on rsID match alone but are capped at 3.0. GWAS risk-allele strand normalization remains deferred to v2.4. |
91
- | gnomAD | ✓ | ODbL v1.0. **GRCh38-only enrichment annotator** — adds population allele frequency context to existing annotations. Shows how common each variant is in the general population (~16M exome variants from 730K individuals). A pathogenic variant that 35% of people carry reads very differently from one seen in 0.001%. Pre-built cache downloaded via `db update` (~6GB on disk). It is deliberately disabled, including for rsID resolution, on GRCh37 and GRCh36 inputs. Use `--no-gnomad` to skip. |
92
- | AlphaMissense | ✓ | CC BY 4.0. **GRCh38-only enrichment annotator** — adds DeepMind's protein-structure-based pathogenicity predictions to existing annotations. Scores 71M missense variants on a 0–1 scale: <0.34 = likely benign, >0.564 = likely pathogenic. Complements ClinVar's expert classifications with computational predictions — especially valuable for variants ClinVar hasn't reviewed yet. Pre-built cache downloaded via `db update` (~8GB on disk). It is deliberately disabled on GRCh37 and GRCh36 inputs. Use `--no-alphamissense` to skip. |
93
- | CADD | ✓ | LicenseRef-CADD (non-commercial). **GRCh38-only enrichment annotator** — adds PHRED-scaled deleteriousness scores from CADD v1.7. **Opt-in**, disabled by default and always disabled on GRCh37 and GRCh36 inputs; see [CADD modes](#cadd-modes) below for details. |
94
+ | GWAS Catalog | ✓ | Public domain (EBI/NHGRI). Trait–SNP associations with p-values and effect sizes. Carrier rule (ADR-0007) requires the user to carry the risk allele. The reported allele is the study's effect (risk) allele, which can be the reference allele (ADR-0039). P-value magnitude scoring maps continuous p-values to the 0–10 scale; only a confidence-interval field that positively identifies a bare odds ratio receives the odds-ratio modifier. Beta coefficients and ambiguous or unit-bearing effects receive no modifier (ADR-0038). Unknown-risk-allele entries fire on rsID match alone but are capped at 3.0. GWAS risk-allele strand normalization remains deferred. |
95
+ | gnomAD | ✓ | ODbL v1.0. **GRCh38-only enrichment annotator** — adds population allele frequency context to existing annotations. Shows how common each variant is in the general population (~16M exome variants from 730K individuals). A pathogenic variant that 35% of people carry reads very differently from one seen in 0.001%. Pre-built cache downloaded via `db update` (~7 GB on disk). GRCh37 input is enriched only through the rsID identity table's explicit allele translation (ADR-0040); gnomAD's own rsID resolution stays GRCh38-only, and GRCh36 input receives nothing. Use `--no-gnomad` to skip. |
96
+ | AlphaMissense | ✓ | CC BY 4.0. **GRCh38-only enrichment annotator** — adds DeepMind's protein-structure-based pathogenicity predictions to existing annotations. Scores 71M missense variants on a 0–1 scale: <0.34 = likely benign, >0.564 = likely pathogenic. Complements ClinVar's expert classifications with computational predictions — especially valuable for variants ClinVar hasn't reviewed yet. Pre-built cache downloaded via `db update` (~8GB on disk). GRCh37 input is enriched only through the rsID identity table (ADR-0040); GRCh36 input receives nothing. Use `--no-alphamissense` to skip. |
97
+ | CADD | ✓ | LicenseRef-CADD (non-commercial). **GRCh38-only enrichment annotator** — adds PHRED-scaled deleteriousness scores from CADD v1.7. **Opt-in**, disabled by default; GRCh37 input is scored only through the rsID identity table (ADR-0040) and GRCh36 input never; see [CADD modes](#cadd-modes) below for details. |
98
+ | dbSNP rsID identity | ✓ | Public domain (NCBI dbSNP). Not an annotator: a cross-build table of each annotator rsID's GRCh37 and GRCh38 placement and alleles (ADR-0040). Supplies the reference allele for GRCh37 and GRCh38 array data, recovers rsIDs for rsID-less VCFs on both builds, and translates a GRCh37 allele to its GRCh38 coordinates so gnomAD, AlphaMissense and CADD can be looked up. Strand-inverted loci are translated explicitly; palindromic sites (A/T, C/G, or a site whose dbSNP alleles include all four bases) and alleles that became the GRCh38 reference abstain. Pre-built cache downloaded via `db update` (~4.9M rows covering ~3.0M rsIDs, from dbSNP b157). |
94
99
 
95
100
  ### CADD modes
96
101
 
@@ -100,16 +105,16 @@ CADD ranks how deleterious any single-nucleotide variant is using 100+ annotatio
100
105
 
101
106
  Two modes:
102
107
 
103
- - **Cache mode** (default): pre-built ~5.8 GB SQLite cache (~120M GRCh38 variant keys). Covers nearly every GRCh38 position allelix can annotate from its other databases (gnomAD, AlphaMissense, ClinVar). It is deliberately disabled for GRCh37 and GRCh36 input, even when an rsID happens to exist in the cache.
108
+ - **Cache mode** (default): pre-built ~5.8 GB SQLite cache (~120M GRCh38 variant keys). Covers nearly every GRCh38 position allelix can annotate from its other databases (gnomAD, AlphaMissense, ClinVar). GRCh37 input is scored only after translation through the rsID identity table; GRCh36 input never is.
104
109
  - **Full mode** (`options.cadd_full = true`): tabix queries against the complete CADD v1.7 file via pysam (GRCh38 only). Adds coverage for novel or private variants that appear only in WGS/WES data and are not in any pre-computed database. Requires `pip install allelix[cadd]` for the pysam dependency.
105
110
 
106
- If your input is a GRCh38 genotyping chip file, cache mode is normally all you need. CADD enrichment is unavailable for GRCh37 and GRCh36 chip files.
111
+ If your input is a genotyping chip file, cache mode is normally all you need. GRCh37 chip files are scored through the rsID identity table; GRCh36 files are not scored.
107
112
 
108
113
  ### Build coverage asymmetry (GRCh37 vs GRCh38)
109
114
 
110
- ClinVar dispatches per build and ships with both GRCh37 and GRCh38 caches. gnomAD v4.1 exomes, AlphaMissense, and CADD v1.7 are GRCh38 datasets in Allelix's current data model. Their enrichment and provenance are therefore emitted only for GRCh38 analyses; GRCh37 and GRCh36 analyses intentionally receive none of those values. This guard prevents an rsID or coordinate collision from attaching a valid GRCh38 score to the wrong allele on another assembly.
115
+ ClinVar dispatches per build and ships with both GRCh37 and GRCh38 caches. gnomAD v4.1 exomes, AlphaMissense, and CADD v1.7 are GRCh38 datasets. Every enrichment lookup is made at GRCh38 coordinates by chromosome, position, reference and alternate allele, never by rsID. For GRCh37 input, the cross-build rsID identity table (ADR-0040) translates the allele the user carries at its GRCh37 position into the matching GRCh38 allele, written explicitly on the GRCh38 forward strand where the reference strand was inverted between assemblies. Palindromic sites (A/T, C/G, or all four bases in dbSNP, whose strand cannot be told from sequence) and alleles that are the GRCh38 reference receive no values rather than a guess. Without the identity table installed, GRCh37 analyses receive no gnomAD, AlphaMissense or CADD values; GRCh36 analyses never do.
111
116
 
112
- The same rule applies to position-based rsID recovery: ClinVar can resolve against the selected GRCh37 or GRCh38 cache, while the broader gnomAD resolver participates only on GRCh38. GRCh37 files with rsIDs still use ClinPGx, GWAS Catalog, and SNPedia normally, but an rsID-less GRCh37 VCF has narrower recovery coverage. If you convert between assemblies, re-normalize REF/ALT as part of the conversion and pass `--build` explicitly when the file does not carry a trustworthy build signal.
117
+ Position-based rsID recovery for rsID-less VCFs uses ClinVar (on the selected build), the identity table (on GRCh37 and GRCh38), and gnomAD (GRCh38 only). The same recovery step runs for `analyze`, `stats`, `extract` and `export plink`, so high-value warnings, extracted genotypes and PLINK allele coding all see the recovered rsIDs (ADR-0043). The identity table covers the rsIDs the annotators hold, so an rsID-less GRCh37 VCF now recovers ClinPGx, GWAS Catalog and SNPedia rsIDs as well as ClinVar ones. If you convert between assemblies, re-normalize REF/ALT as part of the conversion and pass `--build` explicitly when the file does not carry a trustworthy build signal.
113
118
 
114
119
  ### Known ClinPGx limitation: reference-genotype rows where ClinVar and CPIC both lack data
115
120
 
@@ -126,7 +131,7 @@ The CFTR × ivacaftor leak (~30+ rows on real data, pre-v0.7.3) is fixed by the
126
131
 
127
132
  Two ClinVar rows in real-world reports are known upstream artifacts, not Allelix bugs:
128
133
 
129
- - **PKD1 rs199476100 GG (Pathogenic/Likely pathogenic, magnitude 8.5).** This is a stop-gained variant with a gnomAD frequency of 0.0005% (7 observations in 1.38 million chromosomes). Homozygosity for this variant is biologically implausible — PKD1 is autosomal dominant and the nonsense variant would be embryonic-lethal or devastating in homozygous state. The chip genotyping call is almost certainly a probe artifact. The code correctly reports what ClinVar says and what the chip reads; the error is upstream of Allelix. Future work: population-frequency filtering could flag ultra-rare variants where the chip call is likely unreliable.
134
+ - **PKD1 rs199476100 GG (Pathogenic/Likely pathogenic, magnitude 8.5).** This is a stop-gained variant with a gnomAD frequency of 0.0005% (7 observations in 1.38 million chromosomes). Homozygosity for this variant is biologically implausible — PKD1 is autosomal dominant and the nonsense variant would be embryonic-lethal or devastating in homozygous state. The chip genotyping call is almost certainly a probe artifact. The code correctly reports what ClinVar says and what the chip reads; the error is upstream of Allelix. The row is now marked implausible (see [Plausibility flag](#plausibility-flag)) but is still shown.
130
135
 
131
136
  - **IL10 rs1800896 CT (Pathogenic, magnitude 9.0).** This is a common polymorphism (MAF ~20–40%) in the IL-10 promoter. ClinVar's Pathogenic classification comes from a single submitter for hepatitis C susceptibility; another submission classifies the allele as "Uncertain risk allele" for leprosy susceptibility. Allelix's per-SCV loader keeps each submitter's significance paired with its own condition, so it does not create cross-submission combinations. The remaining concern is the upstream strength of a single-submitter classification on a common variant. Future work: review-status weighting could down-weight that evidence.
132
137
 
@@ -178,22 +183,41 @@ allelix config set license.commercial true
178
183
 
179
184
  # Assert that you hold a commercial CADD license
180
185
  allelix config set license.cadd true
186
+
187
+ # Tune the plausibility flag (allele frequencies between 0 and 1)
188
+ allelix config set plausibility.homozygous_max_af 0.0001
189
+ allelix config set plausibility.heterozygous_max_af 0
181
190
  ```
182
191
 
183
192
  CLI flags (`--no-gnomad`, `--no-alphamissense`, `--no-cadd`, `--exclude-snpedia`, `--cadd`) override the config for a single run. The config sets the baseline; flags override per-invocation.
184
193
 
194
+ ### Plausibility flag
195
+
196
+ Genotyping arrays sometimes miscall very rare variants, most visibly as a homozygous call for an allele almost nobody carries. Allelix compares each call with the allele's gnomAD frequency and marks it for review. The row is never hidden (ADR-0041).
197
+
198
+ | Call | gnomAD frequency of the allele | Flag |
199
+ |---|---|---|
200
+ | Homozygous | below `plausibility.homozygous_max_af` (default 0.0001, i.e. 0.01%) | **implausible**: often a genotyping artifact |
201
+ | Heterozygous | at or below `plausibility.heterozygous_max_af` (default 0: gnomAD has the site but no carriers) | **suspicious** |
202
+ | Either | otherwise | plausible |
203
+
204
+ The HTML report shows a ⚠ icon next to a flagged genotype, with the reason on hover and in the detail panel. The terminal table marks implausible calls with ⚠ and suspicious ones with ?. JSON reports carry `plausibility` on every annotation (`plausible`, `suspicious`, `implausible`, or empty when not assessed).
205
+
206
+ A call is not assessed when gnomAD has no frequency for the allele. Allelix's gnomAD cache covers exome sites with an rsID, so a missing value says nothing about rarity. Calls are also not assessed when the gnomAD database is skipped. Homozygous calls on X are not assessed because a male's single X reads as homozygous; heterozygous X calls are. Y and mitochondrial calls are not assessed. Confirm a flagged call with a clinical-grade test before relying on it.
207
+
185
208
  ### Database sizes and download times
186
209
 
187
210
  Not all databases are equal in size. `allelix db update` downloads them all by default, but you can skip the large ones if disk space or bandwidth is a concern:
188
211
 
189
212
  | Database | On disk | Download time | What it adds |
190
213
  |---|---|---|---|
191
- | ClinVar (GRCh37 + GRCh38) | ~900MB | 1–2 min | Core clinical variant classifications. Required. |
214
+ | ClinVar (GRCh37 + GRCh38) | ~1.6 GB | 1–2 min | Core clinical variant classifications. Required. |
192
215
  | ClinPGx + CPIC | ~6MB | seconds | Drug-gene interactions. |
193
- | GWAS Catalog | ~200MB | 1–2 min | Trait-SNP associations from genome-wide studies. |
194
- | gnomAD | ~6GB | 5–15 min | Population allele frequencies (how common is this variant?). |
216
+ | GWAS Catalog | ~950 MB | 1–2 min | Trait-SNP associations from genome-wide studies. |
217
+ | gnomAD | ~7 GB | 5–15 min | Population allele frequencies (how common is this variant?). |
195
218
  | AlphaMissense | ~8GB | 5–15 min | Missense pathogenicity predictions (how likely to break protein function?). |
196
- | CADD (opt-in) | ~5GB | 5–15 min | Variant deleteriousness scores (how damaging is this variant?). Download with `db update --cadd`; enable per analysis or in config. |
219
+ | dbSNP rsID identity | ~460 MB | ~1 min | Cross-build placements: reference allele for array data, rsID recovery on both builds, GRCh37 enrichment translation. |
220
+ | CADD (opt-in) | ~6 GB | 5–15 min | Variant deleteriousness scores (how damaging is this variant?). Download with `db update --cadd`; enable per analysis or in config. |
197
221
 
198
222
  gnomAD and AlphaMissense are the largest but add the most interpretive context. gnomAD answers "is this variant rare or common?" — a pathogenic variant carried by 35% of the population reads very differently from one seen in 3 people. AlphaMissense answers "does this missense change likely damage the protein?" — especially valuable for the thousands of variants ClinVar hasn't reviewed yet.
199
223
 
@@ -201,25 +225,26 @@ To skip either during download: `allelix db update --no-gnomad --no-alphamissens
201
225
 
202
226
  ### Managing your data
203
227
 
204
- Allelix stores reference database caches at `~/.local/share/allelix/` (Linux/macOS) or the XDG-equivalent on other platforms. Default install (no CADD) is ~16 GB on disk; with the CADD opt-in it's ~22 GB.
228
+ Allelix stores reference database caches at `~/.local/share/allelix/` (Linux/macOS) or the XDG-equivalent on other platforms. Default install (no CADD) is ~18 GB on disk; with the CADD opt-in it's ~24 GB.
205
229
 
206
230
  ```
207
231
  ~/.local/share/allelix/
208
232
  ├── alphamissense.sqlite ~7.8 GB
209
- ├── gnomad.sqlite ~6.1 GB
233
+ ├── gnomad.sqlite ~7.1 GB
210
234
  ├── cadd.sqlite ~5.8 GB (only if you opted into --cadd)
211
- ├── clinvar.GRCh37.sqlite ~470 MB
212
- ├── clinvar.GRCh38.sqlite ~480 MB
213
- ├── gwas_catalog_associations.tsv ~700 MB
214
- ├── snpedia.sqlite ~390 MB
215
- ├── gwas.sqlite ~190 MB
216
- └── pharmgkb.sqlite ~14 MB
235
+ ├── clinvar.GRCh37.sqlite ~800 MB
236
+ ├── clinvar.GRCh38.sqlite ~800 MB
237
+ ├── gwas_catalog_associations.tsv ~745 MB
238
+ ├── rsid_identity.sqlite ~457 MB
239
+ ├── gwas.sqlite ~202 MB
240
+ ├── snpedia.sqlite ~194 MB
241
+ └── pharmgkb.sqlite ~6 MB
217
242
  ```
218
243
 
219
244
  **The caches are disposable and re-downloadable.** Everything here was fetched by `allelix db update` and can be re-fetched at any time. There's no per-user state in the cache — your genotype files never enter this directory. Safe to delete to reclaim space (or to force a full refresh if you suspect a cache went stale):
220
245
 
221
246
  ```bash
222
- # Reclaim all ~16-22 GB, with size report and confirmation prompt
247
+ # Reclaim all ~18-24 GB, with size report and confirmation prompt
223
248
  allelix db clean
224
249
 
225
250
  # Preserve the CADD cache (avoids re-downloading the slowest one, ~5.8 GB)
@@ -269,9 +294,10 @@ Allelix source code is licensed under the **GNU Affero General Public License v3
269
294
  | ClinPGx (formerly PharmGKB) | clinpgx.org | CC BY-SA 4.0 | Attribution required |
270
295
  | CPIC | cpicpgx.org | CC BY-SA 4.0 | Attribution required. Per-allele function data fetched from `api.cpicpgx.org` at `db update` time; used internally for the ClinPGx non-finding filter (ADR-0020), not surfaced as its own annotator. |
271
296
  | SNPedia | snpedia.com | CC BY-NC-SA 3.0 US | Attribution required, **non-commercial only**. Use `--exclude-snpedia` to omit. |
272
- | gnomAD | gnomad.broadinstitute.org | ODbL v1.0 | Attribution required. GRCh38-only population allele frequencies for context; not a clinical annotator. Use `--no-gnomad` to omit. |
273
- | AlphaMissense | zenodo.org/records/10813168 | CC BY 4.0 | Attribution required. Cheng et al., Science 2023. GRCh38-only missense variant pathogenicity predictions. Use `--no-alphamissense` to omit. |
274
- | CADD | cadd.gs.washington.edu | LicenseRef-CADD | Attribution required, **non-commercial by default**. Commercial licenses available from UW CoMotion. GRCh38-only enrichment; download with `allelix db update --cadd`, then enable per analysis with `--cadd` or persistently in config. Use `--no-cadd` to omit. |
297
+ | gnomAD | gnomad.broadinstitute.org | ODbL v1.0 | Attribution required. GRCh38 population allele frequencies for context (GRCh37 input through the identity table); not a clinical annotator. Use `--no-gnomad` to omit. |
298
+ | AlphaMissense | zenodo.org/records/10813168 | CC BY 4.0 | Attribution required. Cheng et al., Science 2023. GRCh38 missense variant pathogenicity predictions (GRCh37 input through the identity table). Use `--no-alphamissense` to omit. |
299
+ | dbSNP (rsID identity table) | ncbi.nlm.nih.gov/snp | Public domain | No restrictions. Cross-build rsID placements derived from dbSNP; not surfaced as an annotator. |
300
+ | CADD | cadd.gs.washington.edu | LicenseRef-CADD | Attribution required, **non-commercial by default**. Commercial licenses available from UW CoMotion. GRCh38 scores (GRCh37 input through the identity table); download with `allelix db update --cadd`, then enable per analysis with `--cadd` or persistently in config. Use `--no-cadd` to omit. |
275
301
 
276
302
  **Commercial users:** When `license.commercial = true`, non-commercial sources are gated by a three-state permission model. SNPedia is permanently blocked (no commercial license is available). CADD is blocked by default but can be unlocked — the University of Washington offers commercial licenses at `https://els2.comotion.uw.edu/product/cadd-scores`; after purchasing, assert your license with `allelix config set license.cadd true` to re-enable CADD in commercial mode. All other databases (ClinVar, ClinPGx, GWAS Catalog, gnomAD, AlphaMissense) are compatible with commercial use. `allelix config show` displays the permission state for each source.
277
303
 
@@ -320,7 +346,7 @@ Almost always a schema or interpreter version bump in a recent allelix release t
320
346
 
321
347
  ### Build mismatch warning when analyzing a known-good file
322
348
 
323
- Either: (a) the file's header claims one build and the position data confidently indicates another (real-world MHG / Tempus exports do this — header says 37, positions are 38), or (b) the position signal is too small or mixed to be authoritative. Allelix requires at least three concordant seed SNPs and an 80% winning ratio; weaker GRCh37/38 evidence is reported as tentative and the header or fallback remains effective. A tentative GRCh36 winner is the safety exception: Allelix uses GRCh36 so it cannot accidentally query a modern position cache. Modern position-keyed caches are unavailable for that build (see [`docs/grch36-liftover.md`](https://github.com/allelix/allelix/blob/main/docs/grch36-liftover.md)).
349
+ Either: (a) the file's header claims one build and the position data confidently indicates another (real-world MHG / Tempus exports do this — header says 37, positions are 38), or (b) the position signal is too small or mixed to be authoritative. Allelix requires at least three concordant seed SNPs and an 80% winning ratio. A VCF record without an rsID counts as a seed when it sits at that seed's position on a build, so variant-caller output with an empty ID column is detected by position too. Weaker GRCh37/38 evidence is reported as tentative and the header or fallback remains effective. A tentative GRCh36 winner is the safety exception: Allelix uses GRCh36 so it cannot accidentally query a modern position cache. Modern position-keyed caches are unavailable for that build (see [`docs/grch36-liftover.md`](https://github.com/allelix/allelix/blob/main/docs/grch36-liftover.md)).
324
350
 
325
351
  If you trust the file's header more than allelix's detection, force the build: `--build grch37` or `--build grch38`. The build banner in the analyze output will reflect what was actually used.
326
352
 
@@ -352,6 +378,9 @@ Notable load-bearing ADRs:
352
378
  - **ADR-0036 — Annotated VCF output contract.** JSON and annotated VCF schemas evolve independently.
353
379
  - **ADR-0037 — Conservative position-based build confidence.** A winning build needs at least three matches and an 80% ratio; weaker signals remain diagnostic only.
354
380
  - **ADR-0038 — GWAS effect-modifier disambiguation.** Only positively identified odds ratios receive an effect-size modifier; beta and ambiguous effects abstain.
381
+ - **ADR-0042 — VCF quality gate.** The variant caller's FILTER and genotype quality are honoured, low-quality reference blocks are no-calls, and every exclusion is counted in the report.
382
+ - **ADR-0043 — One rsID-recovery step.** Every command that needs rsIDs recovers them for rsID-less input through the same shared step; build detection votes by position instead.
383
+ - **ADR-0041 — Plausibility flag.** Very rare homozygous calls and heterozygous calls with no gnomAD carriers are flagged for review, never suppressed.
355
384
 
356
385
  Release history: see [`CHANGELOG.md`](https://github.com/allelix/allelix/blob/main/CHANGELOG.md).
357
386
 
@@ -10,7 +10,7 @@ from importlib.metadata import PackageNotFoundError, version
10
10
  def _read_pyproject_version() -> str | None:
11
11
  """Read the package version from ``pyproject.toml``.
12
12
 
13
- GH #34: fall back to ``pyproject.toml`` when run from a bare source
13
+ fall back to ``pyproject.toml`` when run from a bare source
14
14
  checkout (no editable install, no installed package metadata). Keeps
15
15
  ``--version`` and the outbound HTTP User-Agent reporting the real
16
16
  version string instead of the ``0.0.0+local`` sentinel that
@@ -13,6 +13,7 @@ from allelix.annotators.clinvar import CLINVAR_SUPPORTED_BUILDS, ClinVarAnnotato
13
13
  from allelix.annotators.gnomad import GnomadAnnotator
14
14
  from allelix.annotators.gwas import GWASCatalogAnnotator
15
15
  from allelix.annotators.pharmgkb import PharmGKBAnnotator
16
+ from allelix.annotators.rsid_identity import RsidIdentityAnnotator
16
17
  from allelix.annotators.snpedia import SNPediaAnnotator
17
18
 
18
19
  if TYPE_CHECKING:
@@ -47,14 +48,19 @@ def get_annotators(
47
48
  REF allele lookup universally determines whether the user is
48
49
  homozygous reference (and thus a non-finding for that variant).
49
50
  """
51
+ rsid_identity = RsidIdentityAnnotator(data_dir)
50
52
  clinvar = ClinVarAnnotator(data_dir, builds=clinvar_builds, include_benign=include_benign)
51
- pharmgkb = PharmGKBAnnotator(data_dir, clinvar_ref_provider=clinvar.reference_for)
53
+ pharmgkb = PharmGKBAnnotator(
54
+ data_dir,
55
+ clinvar_ref_provider=clinvar.reference_for,
56
+ palindromic_provider=rsid_identity.palindromic_rsids,
57
+ )
52
58
  gwas = GWASCatalogAnnotator(data_dir, filter_traits=gwas_filter_traits)
53
59
  snpedia = SNPediaAnnotator(data_dir, clinvar_ref_provider=clinvar.reference_for)
54
60
  gnomad = GnomadAnnotator(data_dir)
55
61
  alphamissense = AlphaMissenseAnnotator(data_dir)
56
62
  cadd = CaddAnnotator(data_dir, full_mode=cadd_full)
57
- return [clinvar, pharmgkb, gwas, snpedia, gnomad, alphamissense, cadd]
63
+ return [clinvar, pharmgkb, gwas, snpedia, gnomad, alphamissense, cadd, rsid_identity]
58
64
 
59
65
 
60
66
  _ANNOTATOR_CLASS_LIST: list[type[Annotator]] = [
@@ -65,6 +71,7 @@ _ANNOTATOR_CLASS_LIST: list[type[Annotator]] = [
65
71
  GnomadAnnotator,
66
72
  AlphaMissenseAnnotator,
67
73
  CaddAnnotator,
74
+ RsidIdentityAnnotator,
68
75
  ]
69
76
  _ANNOTATOR_CLASSES: dict[str, type[Annotator]] = {cls.name: cls for cls in _ANNOTATOR_CLASS_LIST}
70
77
 
@@ -82,6 +89,7 @@ __all__ = [
82
89
  "GWASCatalogAnnotator",
83
90
  "GnomadAnnotator",
84
91
  "PharmGKBAnnotator",
92
+ "RsidIdentityAnnotator",
85
93
  "SNPediaAnnotator",
86
94
  "get_annotator_class",
87
95
  "get_annotators",