Metadata-Version: 2.4
Name: snp-genomic-report
Version: 4.21
Summary: Turn raw consumer DNA data (FTDNA, AncestryDNA, 23andMe, MyHeritage) into a research/educational genomic PDF report. Not medical advice.
Project-URL: Homepage, https://github.com/benguscott/snp-genomic-report
Project-URL: Issues, https://github.com/benguscott/snp-genomic-report/issues
Author-email: Benjamin Guscott <benguscott@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Benjamin Guscott
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: 23andme,ancestrydna,bioinformatics,dna,genetic-genealogy,genomics,myheritage,pharmacogenomics,snp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.8
Requires-Dist: matplotlib>=3.5
Requires-Dist: reportlab>=3.6
Description-Content-Type: text/markdown

# SNP Genomic Report Skill (v4.21)

Author: Benjamin Guscott · benguscott@gmail.com

## Disclaimer

This tool is for **research and informational purposes only**. It does not provide
medical advice, genetic counselling, or clinical diagnosis, and its output is not a
substitute for clinical-grade genetic testing. Consumer genotyping arrays have
appreciable error rates and limited coverage; any finding of interest must be
confirmed with an accredited clinical laboratory before it informs a medical
decision. Consult a qualified healthcare professional or certified genetic
counsellor before acting on anything in a generated report.

Interpretation provenance and key references: see [`SOURCES.md`](SOURCES.md).

## Privacy

Raw DNA files are among the most sensitive personal data you can hold. Everything
here runs **locally** — no genotype data is transmitted anywhere (the optional
`generate_summaries.py` step is the sole exception: it sends *section text*, not raw
genotypes, to the Anthropic API only if you opt in). The `.gitignore` is configured
to keep raw data and generated reports out of version control; do not commit real
DNA files or PDFs. Treat any report as identifying health information.

## Requirements

- Python 3.8+
- `reportlab` and `matplotlib` (see `requirements.txt`)
- Optional: an `ANTHROPIC_API_KEY` for `generate_summaries.py`

New here? Run the pipeline on the bundled synthetic example before using real data —
see [`examples/`](examples/).

## Changelog

| Version | Date | Changes |
|---------|------|---------|
| **4.21** | 2026-06 | Public-release audit fixes. ROH: emit terminal runs (end-of-chromosome runs were dropped) and restrict scan to autosomes 1–22 so AncestryDNA chr23–26 no longer inflate F_ROH (cross-platform F_ROH now consistent). `data_platform()` matches `ancestrydna` not the dead `ancestry` branch. CYP2C9 no-call no longer reported as `Normal metaboliser (*1/*1)`; both *2/*3 het orders accepted. Cover/provenance coverage labels disambiguated (genotyped/called vs present-on-array vs in-DB). SKILL.md restored as canonical skill definition; validator guards missing SKILL.md. Added transparent `.gz` input handling (stdlib gzip, no new deps). Honest scoping: VCF marked **not implemented**, LivingDNA marked **experimental/untested**; documented the validated platform vintages (FTDNA 2023 GSA, AncestryDNA V2.0, 23andMe v5, MyHeritage OmniExpress — all GRCh37). Added MIT LICENSE, synthetic example, disclaimer/privacy/requirements. |
| **4.20** | 2026-06 | Root fix: infer missing `ref`/`alt` for 94 DB entries from observed alleles; derive all missing diplotype keys. Eliminates reactive per-file gap-filling. rs1800629 TNF-α GG/AA sentiment corrected. rs13266634 SLC30A8 R325W inverted-risk corrected. |
| **4.16** | 2026-06 | 21 genotype keys added from additional AncestryDNA validation data. rs13266634 SLC30A8 R325W inverted-risk fix. |
| **4.15** | 2026-06 | 96 heterozygous keys added from observed validation genotypes. rs4588 hom keys. 8 fallback entries enriched. rs1800629 TNF-α GG/AA sentiment corrected. |
| **4.14** | 2026-06 | AncestryDNA strand audit. `supplemented_rsids` scoped to DB targets. 355 hom keys from het keys. 194 misleading fallback stubs replaced. rs17817449 FTO ref/alt corrected. rs1800896 IL-10 + rs8050136 FTO keys added. `get_sentiment`/`get_interp`: complement lookup chain (exact→rev→comp→comp-rev). `get_interp` fallback rewritten to "Genotype class (XY) — locus context". |
| **4.13** | 2026-06 | `validate_skill.py` pre-packaging integrity checker added (37 checks, auto-fix mode). Systematic bug class analysis: (1) Class 2 — replaced `'ε4' in apoe_call` string search with `e4_allele_count >= 1` in APOE key findings block (same root cause as the reassuring bug fixed in 4.11). (2) Class 3 — fixed 9 allele-order mismatches in annotation DB (TC/CT, TG/GT, GA/AG etc.) so platforms reporting alphabetical genotype order get specific interpretation text. (3) Class 4 — added half-call guards (`'-' not in geno`) to all substring membership checks to prevent `-T` or `C-` half-calls triggering risk findings. (4) Class 5 — added TPMT poor/intermediate, CYP2C19*2 poor/intermediate, Prothrombin G20210A carrier, HFE compound het to §35 key findings. |
| **4.12** | 2026-06 | Add LRRK2 G2019S GA (carrier) and AA (homozygous) to §35 key findings — previously the 4.11 fix stopped AA appearing in Reassuring but neither variant was flagged in Key Findings. Confirmed via 18-case synthetic genotype test suite. |
| **4.11** | 2026-06 | Bug fix: LRRK2 §35 reassuring — AA homozygous G2019S was marked reassuring (wrong). Bug fix: APOE ε3/ε3 excluded from reassuring by substring match on "No ε4". Bug fix: `data_platform()` misidentified AncestryDNA V2/23andMe v5 as FTDNA by SNP count. New: Integrated Warfarin Profile table (CYP2C9 + VKORC1 + CYP4F2 synthesis). Fix: §9 MT zero-call explained per platform. Fix: §4 het rate expected range platform-aware. Fix: cover/footer counts use DB size (413) not matched count. Fix: §31 APOE note conditional. Fix: §17 HLA-C/CTLA4 dedup. Fix: §28 archaic/§29 ancestry dedup. Fix: §33 blood type O-allele no-call flagged. Fix: forensic table widths to mm. |
| **4.10** | 2026-06 | Fix 47 sentiment misclassifications (GOOD/NEUTRAL/BAD) across annotation DB. Fix `get_sentiment()` unsafe fallback — `homozygous reference ≠ GOOD`, fallback now NEUTRAL. Remove rs4148323 duplicate from §18. Fix SKILL.md stale version and SNP count references. Document `sentiment_by_geno` requirement for new DB entries. |
| **4.9** | 2026-06 | Per-row colour coding (green/amber/red/neutral) in all SNP tables. `sentiment_by_geno` field (626 mappings) added to all 413 DB entries. `coloured_T()`, `SNP_TABLE()`, colour legend in §10. |
| **4.8** | 2026-06 | Fix generator version stamp; dynamic polymorphism counts everywhere; no-call vs absent-from-array in §11; dynamic APOE haplotype calling in §12; breast cancer male caveat in §18; §34 conditional APOE limitation; §35 expanded key findings (CFH, SLCO1B1, DPYD *13 conditional wording, APOE ε4). |
| 4.7 | 2026-05 | API-powered section summaries via generate_summaries.py; forensic phenotype table; 12 key SNP interpretations expanded to 30+ words; rs429358 (APOE ε4) added to annotation DB |
| 4.6 | 2026-05 | Remove filename-based sex hints — sex determined wholly from X het rate and FTDNA XY-only pattern |
| 4.5 | 2026-05 | Fix FTDNA male sex determination (XY-only → infer Male); expanded filename sex-hint keywords; FTDNA/GSA het rate note in QC section |
| 4.4 | 2026-05 | Fix het rate formula (het/het+hom, excludes hemizygous X/Y/MT calls); sex mismatch warning from filename; 23andMe GSA het rate platform note in QC section |
| 4.3 | 2026-05 | Fix ROH artefact in dual-dataset mode: QC now computed on primary platform only; chromosome name normalisation (AncestryDNA chr23→X etc.) prevents cross-platform ROH inflation |
| 4.2 | 2026-05 | Dual-dataset merging (optional secondary file fills coverage gaps); coverage warning and [SUPP] tags; §35 low-coverage note; MyHeritage workflow guidance |
| 4.1 | 2026-05 | Fix MyHeritage/AncestryDNA comment-header parse bugs; add DPYD\*13, FGFR2, breast cancer panel, SLCO1B1\*5, CYP2B6\*6, KCNQ1 S225L, SCN5A, CTLA4; remove unreliable MTHFR proxy rs2274976; annotation DB 411 entries |
| 4.0 | 2026-05 | Initial standalone skill: replace static template with executable `generate_report.py`; add `snp_annotations_enhanced.json` with per-genotype interpretations; streamlined 3-command workflow; dynamic §35 summary |
| 3.0 | 2026-03 | Previous report template version (generate\_report\_template.py) — retired |

---

## Overview

Analyses raw SNP genotyping data from consumer DNA tests and produces a comprehensive ~50-page clinical genomic PDF report covering ~413 individually annotated polymorphisms across 33 biological and clinical domains.

**DO NOT ASK QUESTIONS — begin analysis immediately when a genotype file is uploaded.**

## Supported Input Formats

Files may be plain text or gzip-compressed — a `.gz` file is decompressed
transparently, so there's no need to gunzip a download first.

| Platform | Format | Header Pattern | Status |
|----------|--------|----------------|--------|
| FTDNA | CSV | `RSID,CHROMOSOME,POSITION,RESULT` | Validated |
| 23andMe | TSV | `# rsid  chromosome  position  genotype` | Validated |
| AncestryDNA | TSV | `rsid  chromosome  position  allele1  allele2` (`#` comment header) | Validated |
| MyHeritage | CSV | `RSID,CHROMOSOME,POSITION,RESULT` (FTDNA-like, `#` header) | Validated |
| LivingDNA | CSV/TSV | FTDNA-like | ⚠️ **Experimental — untested.** No LivingDNA file has been run through this pipeline. It is not explicitly detected and only works if its export closely matches FTDNA's layout. |
| VCF | — | — | ❌ **Not implemented.** No VCF parser exists; a VCF input will be misdetected and will not produce a correct report. Convert to a supported raw-text format first. |

### What has actually been validated

The four *Validated* formats were each run end-to-end on at least one real consumer
export, **all on GRCh37 / build 37**:

| Platform | Export tested |
|----------|---------------|
| FTDNA | 2023 autosomal CSV, Illumina GSA chip |
| AncestryDNA | array version V2.0, forward strand |
| 23andMe | v5 "Full" export (build 37, Annotation Release 104) |
| MyHeritage | OmniExpress-based export (2019-vintage format) |

The dual-dataset merge was validated with an AncestryDNA V2.0 + MyHeritage pairing.

**Not validated — use with caution:** other platform vintages (e.g. 23andMe v3/v4,
older FTDNA builds); any **GRCh38 / build 38** file (rsID-based SNP lookup is
build-independent, but the ROH metric uses base-pair positions and assumes build 37,
so ROH figures on a build-38 file are unreliable); LivingDNA; and VCF. Strand and
allele-order handling are calibrated to the exports above and may differ on an
untested platform.

## Workflow

Run these commands in sequence. **Do not write custom code** — the bundled scripts handle everything.

> **MyHeritage users:** The MyHeritage OmniExpress array covers only ~150 of the 413 target clinical SNPs. If you also have an AncestryDNA or FTDNA file, upload both — the dual-dataset workflow below fills most coverage gaps and produces a substantially more complete report.

### Step 1 — Install dependencies

```bash
pip install reportlab matplotlib
```

### Step 2 — Run the analysis pipeline

```bash
python3 scripts/analyze_snps.py \
  /path/to/your_dna_file.csv \
  analysis.json \
  references/snp_annotations_enhanced.json
```

Expected output confirms platform, SNP count, call rate, and how many curated SNPs were found.

If platform shows `unknown`, check the file header with `head -3 <file>`.

### Step 2b — Optional: generate API-enriched section summaries

Requires `ANTHROPIC_API_KEY` set in the environment. Produces subject-specific synthesis paragraphs for each report section.

```bash
export ANTHROPIC_API_KEY=your_key_here

python3 scripts/generate_summaries.py \
  analysis.json \
  references/snp_annotations_enhanced.json \
  --output analysis_rich.json
```

Then use `analysis_rich.json` as the input to generate_report.py.

Without this step, the report uses static section summaries. With it, each section gets a Claude-authored synthesis of the actual genotype pattern, covering biological mechanisms and drug interactions.

### Step 3b — Optional: supplement with a second platform file

If the subject has data from two platforms (e.g., MyHeritage + AncestryDNA, or any combination), pass the secondary file as a fourth argument:

```bash
python3 scripts/analyze_snps.py \
  /path/to/primary.csv \
  analysis.json \
  references/snp_annotations_enhanced.json \
  /path/to/secondary.csv
```

The secondary file supplements the primary — its calls are only used where the primary has no data or a no-call. SNPs sourced from the secondary are tagged `[SUPP]` in the report tables.

**Recommended pairings:**

| Primary | Secondary | Coverage |
|---------|-----------|----------|
| AncestryDNA V2.0 | MyHeritage | ~410 SNPs |
| FTDNA GSA | MyHeritage | ~410 SNPs — near-complete |
| MyHeritage | AncestryDNA V2.0 | ~360 SNPs |
| MyHeritage | FTDNA GSA | ~410 SNPs |

### Step 4 — Generate the PDF report

```bash
python3 scripts/generate_report.py \
  analysis.json \
  report.pdf \
  references/snp_annotations_enhanced.json
```

Expected output: `Report saved: report.pdf`

---

## Report Contents (36 Sections)

1. Cover page (platform, SNP count, date, predicted sex)
2. Abbreviation key
3. Data provenance & platform identification
4. Global quality metrics
5. Per-chromosome distribution & heterozygosity (table + 2 charts)
6. Allele frequencies, GC content & Ti/Tv (3 charts)
7. ROH & F_ROH
8. Sex determination
9. Mitochondrial DNA
10. Pharmacogenomics: CYP2C9, VKORC1, CYP4F2, integrated warfarin summary, CYP2D6, NAT2, CYP1A2, CYP3A5, DPYD, TPMT, CYP2C19, UGT1A1, metformin, methotrexate
11. Clinical no-call gaps
12. Alzheimer's GWAS (APOE note + IGAP loci)
13. Cardiovascular (lipids, CAD/9p21, blood pressure, haemostasis/thrombosis, QT interval, AF)
14. T2D & glucose metabolism
15. Obesity & leptin/adiponectin axis
16. Inflammatory cytokine profile (Th1/Th2)
17. Autoimmune (HLA screen, coeliac, IBD, MS + Vitamin D convergence, asthma, psoriasis)
18. Cancer, liver/NAFLD, AMD, restless legs syndrome
19. Iron/HFE (haemochromatosis)
20. Methylation cycle (MTHFR, MTR, MTRR, CBS)
21. Vitamin D axis (synthesis → activation → transport → receptor)
22. Micronutrient metabolism (vitamin A, choline, omega-3, B12, selenium, histamine/DAO)
23. Neuropsychiatric (serotonin, dopamine/COMT, BDNF, FKBP5/HPA, oxytocin, GABA, opioid, PD, GWAS)
24. Circadian rhythm & sleep
25. Pain & endocannabinoid system
26. Sensory genetics (bitter taste TAS2R38, sweet/umami, olfaction, photic sneeze)
27. Blood type & antigen systems
28. Archaic introgression
29. Ancestry informative markers
30. Prostate & PSA
31. Longevity (FOXO3, IGF-1/mTOR, telomere panel, CETP centenarian variant, antioxidants)
32. ECM, connective tissue & musculoskeletal (collagen, elastin, MMP, muscle, OA, bone, vascular, migraine)
33. Forensic phenotype reconstruction (skin, eye, hair colour; earwax)
34. Limitations & caveats
35. Summary & conclusions (dynamically generated key findings based on actual genotypes)
36. References

---

## How Genotype Interpretation Works

`snp_annotations_enhanced.json` contains per-genotype interpretation text for all 413 annotated SNPs. Every entry has three required fields for colour coding to work correctly:

- **`interp_by_geno`** — dict mapping each genotype string to interpretation text
- **`sentiment_by_geno`** — dict mapping each genotype string to `GOOD`, `MIXED`, `BAD`, or `NEUTRAL`

### sentiment_by_geno — rules for new entries

**Every key in `interp_by_geno` must have a corresponding key in `sentiment_by_geno`** (excluding `ref` and `alt` descriptor keys, which should be `NEUTRAL`). If a key is missing, `get_sentiment()` returns `NEUTRAL` rather than guessing — this is safe but means the row will be uncoloured.

Sentiment values:

| Value | Meaning | Colour |
|-------|---------|--------|
| `GOOD` | Reassuring — wild-type, no risk variant, protective allele, longevity-associated | Green |
| `MIXED` | Heterozygous risk carrier, intermediate phenotype, or genuine trade-off | Amber |
| `BAD` | Risk variant present — elevated disease risk, reduced enzyme activity requiring dose adjustment, pathogenic allele | Red |
| `NEUTRAL` | No directional clinical interpretation — dose modifier only, performance trait, pharmacokinetic variant without health direction, incomplete information, or bidirectional effect | White/grey |

**Critical rules — learned from audit of 530 assignments:**

1. **Homozygous reference ≠ GOOD by default.** Some loci have the risk allele on the reference strand (e.g. PNPLA3 I148M: reference G = risk allele; homozygous GG = BAD not GOOD). Always check which allele carries the risk before assigning GOOD to a homozygous-reference genotype.

2. **Absence of a beneficial allele ≠ GOOD.** FOXO3 CC (longevity allele absent) = NEUTRAL, not GOOD. CETP AA (I405V absent, no centenarian HDL phenotype) = NEUTRAL. Reserve GOOD for genotypes that are actively reassuring.

3. **Dose/pharmacokinetic modifiers = NEUTRAL throughout.** VKORC1, CYP4F2, CYP2C19*17, CYP4F2 — these affect drug dosing but neither direction is a health risk. All genotypes = NEUTRAL.

4. **Bidirectional pleiotropic variants = NEUTRAL.** PHACTR1 G (CAD protective, migraine risk), COMT Val/Met (neither warrior nor worrier is clinically bad). Use NEUTRAL when the effect direction is genuinely ambiguous.

5. **PPARG-type inversions.** The Ala12 allele (G at rs1801282) is protective; Pro12 (C) is the less-protective reference. Protective homozygote (GG) = GOOD; reference homozygote (CC) = NEUTRAL. Do not assume ref = GOOD.

6. **Dominant-negative and gain-of-function variants on the reference strand.** TERT rs10069690 T allele creates a dominant-negative isoform — CT = BAD despite being heterozygous. Check the mechanistic direction, not just allele frequency.

7. **Inverted-risk loci.** Some SNPs have the common allele as the risk allele — do not assume common = non-risk. Known examples: rs1800629 TNF-α -308G>A (G is ancestral/common; A is the rare risk allele — GG is GOOD, AA is BAD, but the DB was originally calibrated with ref=A causing inversion); rs13266634 SLC30A8 R325W (C/Arg325 is the common risk allele; T/Trp325 is the rare protective allele — CC is MIXED, TT is GOOD). Always verify which allele carries clinical risk before assigning sentiment.

8. **`--` (no-call) is always NEUTRAL** — unknown is not bad.

For all other SNPs, interpretation is automatically derived by comparing the observed genotype to reference/alternate alleles — producing "Homozygous reference / Heterozygous / Homozygous variant" classifications with gene context. The report works for any subject's genotype profile.

### Platform strand conventions

The annotation DB was originally calibrated on FTDNA GSA data. AncestryDNA, 23andMe, and MyHeritage report on the forward (+) strand per their file headers, but at some loci the allele encoding differs from the FTDNA convention. `get_sentiment()` and `get_interp()` both try four lookups before falling back: exact genotype → reversed (GA→AG) → complement (CC→GG) → complement-reversed. This handles cross-platform strand differences automatically at runtime.

When adding new DB entries, include keys for **all three diplotype states** (hom-ref, het, hom-alt) for both allele orderings (AG and GA). The `ref` and `alt` fields must be the forward-strand alleles; the complement lookup handles platforms that report the opposite strand.

The **§35 Summary is dynamically generated**: key findings (HFE carrier/homozygous, HFE compound het C282Y+H63D, MTHFR 677TT, Factor V Leiden het/hom, Prothrombin G20210A carrier, TPMT poor/intermediate metaboliser, CYP2C19*2 poor/intermediate, DPYD *2A, DPYD putative *13, CFH Y402H, SLCO1B1 proxy, APOE ε3/ε4, ε4/ε4 unresolved, LRRK2 G2019S carrier/homozygous, FOXO3 longevity allele, CYP2C9 warfarin variants) are only flagged when the relevant genotype is actually detected. The Reassuring block covers: MTHFR wild-type, thrombophilia absent, DPYD *2A absent, LRRK2 G2019S absent, APOE ε3/ε3.

---

## Release Process

Before packaging or publishing any update, run the integrity validator:

```bash
python3 validate_skill.py
```

The validator runs a series of checks across these categories:
- Version consistency across all files (single source of truth: `GENERATOR_VERSION` in `generate_report.py`)
- `analyze_snps.py` derives version dynamically — no hardcoded literal to drift
- `generate_summaries.py` API key handling
- SKILL.md structural content (no broken Step 2b, no stale SNP counts, changelog current)
- No personal data or Cowork-specific output paths in scripts
- Annotation DB integrity (sentiment_by_geno coverage, valid values, allele-order gaps)
- Critical §35 logic (LRRK2 exact match, APOE count-based check, DPYD half-call guard)
- Live pipeline smoke test

Fix any failures before packaging. Use `--fix` to auto-resolve version drift in SKILL.md:

```bash
python3 validate_skill.py --fix
```

**Per-release checklist:**
1. `python3 validate_skill.py` — must return ALL CHECKS PASS
2. Bump `GENERATOR_VERSION` in `generate_report.py` (one edit; all other version references derive from it or are updated by `--fix`)
3. Add changelog entry in `generate_report.py` docstring
4. Run `python3 validate_skill.py --fix` to propagate new version to SKILL.md title
5. Add changelog row to SKILL.md manually (validator checks this is present)
6. Run pipeline on a test file to confirm PDF output

---

## Troubleshooting

| Symptom | Fix |
|---------|-----|
| `Platform: unknown` | Check file header: `head -3 <file>` — FTDNA starts `RSID,CHROMOSOME,POSITION,RESULT` |
| `Found 0 of target SNPs` | Verify path to `snp_annotations_enhanced.json` |
| `reportlab not found` | Re-run Step 1 |
| PDF is very small or blank | Check the output path is writable |
| Many no-calls for PGx SNPs | Normal for some platforms; note in report and recommend clinical PGx testing |
| MyHeritage: only ~150 SNPs found | Expected — OmniExpress array has limited clinical coverage. Add AncestryDNA/FTDNA as supplement (Step 3b) |

---

## Files in This Skill

```
snp-genomic-report/
├── SKILL.md                       ← canonical skill definition
├── README.md                     ← this file
├── SOURCES.md                    ← interpretation provenance + key references
├── RELEASE_NOTES_v4.21.md
├── LICENSE
├── requirements.txt
├── .gitignore
├── validate_skill.py             ← Pre-packaging integrity checker — run before every release
├── examples/
│   ├── example_ftdna_SYNTHETIC.csv  ← synthetic demo input (not a real person)
│   ├── example_report_SYNTHETIC.pdf ← sample output from the synthetic input
│   └── README.md
├── scripts/
│   ├── analyze_snps.py           ← Platform detection, parsing, QC, ROH, SNP lookup
│   ├── generate_report.py        ← Full report generator: charts + 36-section PDF (all in one)
│   └── generate_summaries.py     ← Optional: Anthropic API section summaries (requires ANTHROPIC_API_KEY)
└── references/
    ├── snp_annotations_enhanced.json  ← 413 SNPs with per-genotype interpretations + sentiment_by_geno (PRIMARY)
    └── target_rsids.txt               ← Flat list of target rsIDs
```

## Trademarks & affiliation

This project is independent and is **not affiliated with, endorsed by, or sponsored
by** any genetic testing company. Family Tree DNA / FTDNA, AncestryDNA, 23andMe,
MyHeritage, and Living DNA are trademarks of their respective owners; they are
referenced here only to describe the raw-data file formats the tool can read.
