Metadata-Version: 2.4
Name: anukriti-pgx-core
Version: 0.13.0
Summary: Deterministic pharmacogenomics infrastructure: CPIC-pinned phenotype engine, gene callers, and recommendation lookup. RESEARCH USE ONLY — unreviewed by a clinician, not for patient dosing.
Author: Anukriti contributors
License: Apache-2.0
Project-URL: Homepage, https://github.com/AnukritiAi-hq/anukriti-pgx-core
Project-URL: Documentation, https://github.com/AnukritiAi-hq/anukriti-pgx-core#readme
Project-URL: Issues, https://github.com/AnukritiAi-hq/anukriti-pgx-core/issues
Keywords: pharmacogenomics,cpic,pharmvar,bioinformatics,precision-medicine
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: service
Requires-Dist: fastapi>=0.104; extra == "service"
Requires-Dist: uvicorn[standard]>=0.24; extra == "service"
Requires-Dist: pydantic>=2.5; extra == "service"
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Dynamic: license-file

# anukriti-pgx-core

### Deterministic pharmacogenomics infrastructure

> Authoritative, CPIC-pinned, no LLMs, no randomness. Same inputs → same outputs.

[![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-green)]()
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue)]()
[![Status: Alpha](https://img.shields.io/badge/status-alpha-orange)]()

---

## ⚠️ Research use only — unreviewed by a clinician — not for patient dosing

**Releases 0.10.0 and 0.11.0 have not been reviewed by any clinician.** Each
carries an internal regression review written by the engine maintainer, a
programmer; both record the verdict **NOT APPROVED** and state that a human
clinician must rule on them. Both were published anyway. That was a process
failure; it is recorded here rather than left for a reader to discover, and
it is now gated: **a release whose clinical review carries no completed
signature block must ship labelled research-use-only, and
`tests/test_clinical_signoff_gate.py` fails the build if it does not.** 0.11.0
is labelled under exactly that rule and stays labelled until a clinician signs.

**0.13.0 adds the engine's first thiopurine recommendations** (TPMT + NUDT15 →
azathioprine, mercaptopurine, thioguanine), keyed on both genes jointly because
CPIC publishes no per-gene thiopurine recommendation. It is dosing-affecting,
it changes no existing call, and it is **unsigned**: three rulings are open at
`docs/CLINICAL_REVIEW_REQUEST_0.13.0.md`. Nothing in the platform consumes it
yet.

**0.11.0 withdraws a dose reduction from a patient** when the DPYD exonic tag
`c.1236G>A` is present and the causal `c.1129-5923C>G` is genotyped as
reference: `REDUCE_50PCT` → `STANDARD`. Measured in 5,008 1000 Genomes
chromosomes, it fires **0 times** — but that cohort is too small to have
expected otherwise, so what it establishes is an upper bound of ~6% of HapB3
carriers, and only ~16% in South Asians. **No Indian cohort measures it at
all.** See
[`validation/hapb3_withdrawal_impact.py`](validation/hapb3_withdrawal_impact.py).

Do not use this library to decide a patient's dose. The outstanding ruling is
set out in
[`docs/CLINICAL_REVIEW_REQUEST_0.11.0.md`](docs/CLINICAL_REVIEW_REQUEST_0.11.0.md)
with a blank sign-off block; a qualified clinician willing to review it is
genuinely wanted, and [`docs/REVIEWER_ROLE.md`](docs/REVIEWER_ROLE.md) states
exactly how bounded that ask is.

In the other direction, and on the same release: 0.11.0 also **corrected a
bias that under-called toxicity** — diplotype truncation by allele name had
been reporting HapB3 homozygotes as Normal Metabolizers on a standard dose.

The policy, the per-version release log and a table of what has and has not
been measured are in
[`docs/RELEASE_GOVERNANCE.md`](docs/RELEASE_GOVERNANCE.md).

---

## Platform and docs

This repo is the library at the core of the three-repo **Anukriti platform**
(`anukriti-pgx-core` + [`anukriti`](https://github.com/Abm32/anukriti-sandbox) +
[`anukriti-swarm`](https://github.com/AnukritiAi-hq/anukriti-swarm)).

- 🧭 **[`PLATFORM.md`](PLATFORM.md)** — canonical three-repo map. Start here
  if you're new to the platform.
- 📚 **[`anukriti_docs`](https://github.com/AnukritiAi-hq/anukriti_docs)** —
  14-module progressive learning course covering what the platform is, how
  it works, why deterministic, and the tech choices behind it.
- 🧾 **[`PROJECT_CONTEXT.md`](PROJECT_CONTEXT.md)** — the "why" doc for
  this library: D1–D11 locked founder decisions, forward-work items,
  regression contract.
- 🏛️ **[`docs/adr/`](docs/adr/)** — platform-wide Architecture Decision
  Records with "Revisit when" triggers.

---

## What this is

The deterministic core extracted from
[`anukriti`](https://github.com/AnukritiAi-hq/anukriti) (PGx product) and
[`anukriti-swarm`](https://github.com/AnukritiAi-hq/anukriti-swarm) (research
platform), now shippable as a standalone library and (optionally) HTTP service.

Three stacked layers:

```
    VCF variants (rsid → ref,alt,gt)
            │
            ▼  Layer 1: calling/       ← VCFCaller.call(gene, variants)
    Star alleles (*1, *17, *2/*17 …)
            │
            ▼  Layer 2: phenotype/     ← PhenotypeEngine.infer(gene, a1, a2)  ← PHASE 1
    Phenotype (PM / IM / NM / RM / UM)
            │
            ▼  Layer 3: recommendations/  ← RecommendationLookup.lookup(...)
    CPIC recommendation
```

Each layer is independently usable. A consumer that already has star alleles
(e.g. a swarm agent) uses Layer 2 directly. A consumer with VCF input
(e.g. a clinical pipeline) uses Layer 1, which calls into Layer 2 internally.

## Why this exists

Before the extraction, the same phenotype logic lived in two places:

- `anukriti-swarm/rules/phenotype_rules.py` — star-allele level, 3 genes
- `anukriti/src/*_caller.py` (16 files) — VCF level, 16 genes, inconsistent
  signatures

That meant two truth sources for the same CPIC tables, and no way for a
third party to consume just the deterministic core without pulling in a
FastAPI product or a multi-agent research framework.

This package **is the deterministic core**. It has:

- Zero runtime dependencies (Phase 1)
- No LLMs, no randomness, no I/O side effects
- CPIC table versions pinned by filename (e.g. `CYP2C19_named_diplotypes_v2022.1.json`)
- An explicit upgrade rhythm: CPIC updates → new file → new test pin → review → bump

## Phase status

| Phase | Scope | Status |
|---|---|---|
| **1** | Layer 2: PhenotypeEngine for CYP2D6 + CYP2C19 | ✅ **this release** |
| 2 | Layer 1: VCFCaller + 16 gene callers (normalized signatures) | planned |
| 3 | Layer 3: RecommendationLookup + optional HTTP service | planned |
| 4 | Swarm expansion to the 13 non-CYP2D6/2C19/HLA-B genes | planned |

## Install

```bash
pip install anukriti-pgx-core==0.13.0

# Or locally while iterating:
pip install -e /path/to/anukriti-pgx-core
```

## Quick use (Layer 2 — what Swarm consumes)

```python
from anukriti_pgx_core import PhenotypeEngine

engine = PhenotypeEngine()

result = engine.infer("CYP2C19", "*1", "*17")
# -> PhenotypeInference(
#        gene="CYP2C19",
#        diplotype="*1/*17",
#        activity_score=2.5,
#        phenotype="Rapid Metabolizer",           # per CPIC 2022 Table 2
#        confidence=1.0,
#        rule_version="cpic_activity_score_v2",
#        source="CPIC named-diplotype table (CYP2C19)",
#        cpic_table_version="CYP2C19_named_diplotypes_v2022.1",
#        ...
#    )

engine.supported_genes()
# -> ["CYP2C19", "CYP2D6"]

engine.cpic_table_version("CYP2C19")
# -> "CYP2C19_named_diplotypes_v2022.1"
```

## Authoritative sources (pinned)

| Gene | Layer | Table file | Citation |
|---|---|---|---|
| CYP2D6 | activity-score → phenotype | `CYP2D6_activity_v2019.10.json` | CPIC 2019 standardization (Caudle et al., PMID:31647186) |
| CYP2C19 | named diplotype → phenotype | `CYP2C19_named_diplotypes_v2022.1.json` | CPIC 2022 clopidogrel guideline Table 2 (Lee et al., PMID:35034351; NCBI NBK84114) |
| CYP2C19 | allele function (activity score) | `CYP2C19_activity_v2022.1.json` | CPIC 2022 allele functionality table |

Updating a pinned table = adding a new file + bumping the pin + adding/updating
the regression case. Silent in-place edits are not allowed.

## Tests

```bash
cd anukriti-pgx-core
pip install -e ".[dev]"
pytest

# Or standalone:
python -m tests.test_pinned_star_alleles
```

## Integration with existing Anukriti projects

### From `anukriti-swarm`

Swarm's `rules/phenotype_rules.py` is a thin re-export shim that delegates
here. All existing swarm code (`agents/pharmacogene/base.py`,
`core/verification/safety.py`, `core/runtime/runtime.py`) continues to work
unchanged. Migration to direct `anukriti_pgx_core` imports is opt-in per
call site.

### From `anukriti` (FastAPI product)

Phase 2 will migrate the 16 gene callers in `anukriti/src/` into
`anukriti_pgx_core.calling`. Until then, `anukriti` continues to use its
existing caller modules unchanged.

## License

Apache 2.0. See [LICENSE](LICENSE).
