SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
8.1 KB · 116 lines markdown
Rendered Raw Blame History
1# Biomarkers — canonical catalogue and derived links23The biomarker database (`/biomarkers`, `/biomarker/<slug>`; API `GET /v1/biomarkers`,4`GET /v1/biomarkers/:slug`) implements SPEC §17 (biomarkers as first-class entities), §525(biomarker → therapy context) and §121 (tumor-agnostic indications). It follows CLAUDE.md §8:6**curated metadata is allowed only when every code is verified against the authority**, and every7scientific link is derived from source records — never typed in.89## 1. What a biomarker entity is1011One row of `biomarkers` (`CI-BIO-…`) is an **identity record**, seeded from12`packages/database/src/seed-data/biomarkers.ts` (idempotent by `slug`; ids are minted once):1314| Field | Content | Rule |15|---|---|---|16| `slug`, `name`, `kind` | e.g. `braf-v600e`, "BRAF V600E", `gene_mutation` | `kind` is one of the twelve frozen values of the schema |17| `gene_id` | anchor gene (HGNC symbol resolved to `genes.id` at seed time) | unresolved symbols are reported and left `null`, never invented; `null` for non-gene markers |18| `ncit_code` | NCIt concept of the **biomarker / gene alteration** ("HER2/Neu Positive", "BRAF NP_004324.2:p.V600E", "NTRK Gene Fusion Positive"…), never the bare gene concept | **every code verified live** against the NCI EVS REST API (`GET /api/v1/concept/ncit/{code}`) on **2026-09-11, NCIt 26.08e** — all returned `active: true`, `conceptStatus: DEFAULT`; the API's preferred name is stored in `measurement.ncit.name` |19| `description` | one neutral sentence: what is measured, by which assay family, and whether it is used as a diagnostic, predictive or prognostic marker | no dosing, no thresholds of our own, no individual advice |20| `measurement` (jsonb) | `assays` (IHC, FISH/ISH, NGS, PCR, flow cytometry, PET imaging…), `scoring` (conventions as published: PD-L1 TPS/CPS/IC, HER2 IHC 0/1+/2+/3+ with ISH reflex, MSI-PCR vs MMR IHC, BCR-ABL1 %IS…), `notes`, `sources` (NCI / FDA pages, all HTTP 200 on 2026-09-11), `aliases`, `genes`, `variantSlugs`, `indicationTerms`, `tumorAgnostic`, `ncit`, `verification` | the seed is the only writer of this shape; there is no alias table, so aliases live here |2122The catalogue holds 54 markers: HER2, ER, PR, EGFR (any) + exon 19 deletion / L858R / T790M /23exon 20 insertion, ALK, ROS1, KRAS G12C, KRAS (any), NRAS, BRAF V600E, BRAF (any), MET exon 14 /24amplification, RET fusion, NTRK fusion, HER2 mutation, PD-L1, MSI-H, dMMR, TMB-H, BRCA1, BRCA2, HRD,25PIK3CA, ESR1 mutation, AR, AR-V7, PSMA, SSTR, CD19, CD20, BCMA, CD38, CD30, CD33, FLT3, IDH1, IDH2,26NPM1, KIT, PDGFRA, FGFR2 fusion, FGFR3 alteration, BCR-ABL1, JAK2 V617F, TP53, CDKN2A deletion,27ctDNA, Ki-67, del(17p).2829**Relationships stated in the metadata, not inferred:** PD-L1 is the protein of gene *CD274*;30HER2 is the protein of *ERBB2*; MSI-H (DNA phenotype, PCR/NGS) and dMMR (loss of MLH1/MSH2/MSH6/PMS231protein by IHC) are two measurements of one biological state and are kept as two entries whose notes32cross-reference each other; HER2 overexpression and HER2 (ERBB2) mutation are different markers.3334## 2. Scope of a biomarker (what the links are computed from)3536Formula `biomarker-links-v1`, identical in `apps/web/src/lib/queries/biomarkers.ts` and37`apps/api/src/routes/biomarkers.ts`:3839- **gene_ids** = anchor `gene_id` ∪ `measurement.genes` resolved by HGNC symbol40  (NTRK fusion → NTRK1/NTRK2/NTRK3; MSI-H and dMMR → MLH1/MSH2/MSH6/PMS2; BCR-ABL1 → ABL1 + BCR;41  del(17p) → TP53).42- **variant_ids** = `measurement.variantSlugs` resolved against `variants` (checked to exist in the43  production copy on 2026-09-11). When present the marker is *molecular-level* (BRAF V600E, EGFR44  L858R, KRAS G12C, MET exon 14, JAK2 V617F, HER2 amplification…) and every link is restricted to45  those variants instead of the whole gene.46- Markers with **neither** (TMB-H, HRD, ctDNA) have no gene-derived blocks: the pages show47  "Data not yet available" with the reason recorded in `measurement.notes`. Only the48  indication-text rule (§3.4) applies to them.4950## 3. Derived links (computed at query time; no biomarker link table is written)5152Every derived count carries the **Computed** claim badge and names its rule; every table of source53rows carries the **native** claim badge of the source (Curated for CIViC, Regulatory for approvals,54Published for trials and PubMed).5556### 3.1 Evidence and associated cancers57CIViC evidence items with `status = 'ACCEPTED'` and `evidence_type ∈ {PREDICTIVE, PROGNOSTIC,58DIAGNOSTIC}` whose `variant_ids` (molecular markers) or `gene_ids` (gene-level markers) overlap the59scope. Levels A–E and directions are shown exactly as curated (never re-scaled, never collapsed).60**Associated cancers** = distinct mapped `cancer_id` of that evidence, with counts by type and by61level. Submitted and rejected items are excluded; PREDISPOSING, ONCOGENIC and FUNCTIONAL items are62not part of the biomarker scope (they belong to the gene page).6364### 3.2 Drugs with predictive evidence65Union of (a) `therapy_ids` of the in-scope PREDICTIVE items and (b) targets of active66`knowledge_edges` `PREDICTS_RESPONSE_TO` whose source variant is in scope. Per drug the page shows67the number of items, sensitivity vs resistance counts (CIViC `significance`), the best native level,68the number of knowledge edges with their direction, and the cancer contexts — as separate columns,69never merged into a verdict.7071### 3.3 Trials72`clinical_trials` having an intervention mapped (`trial_interventions.drug_id`) to a scope drug73**and** a condition mapped (`trial_conditions.cancer_id`) to a scope cancer. Counts: total, active74(`RECRUITING`, `NOT_YET_RECRUITING`, `ENROLLING_BY_INVITATION`, `ACTIVE_NOT_RECRUITING`), recruiting,75active phase 3. The table lists active trials, newest update first. A trial listed here tests the76*drug* in the *cancer*; it does not mean the trial selects patients on the biomarker.7778### 3.4 Approvals79`drug_approvals` rows (a) whose `drug_id` is a scope drug — `matchedBy = drug` — and/or (b) whose80indication text contains one of the curated `indicationTerms` phrases (case-insensitive substring,81e.g. "microsatellite instability-high", "NTRK", "PD-L1") — `matchedBy = indication`. Each row keeps82its authority, jurisdiction, indication text, status and date. Health Canada DIN rows carry no83indication text, so they only ever match by drug.8485### 3.5 Tumor-agnostic rule (§121)86`measurement.tumorAgnostic = true` is a curated statement (MSI-H, dMMR, NTRK fusion, TMB-H, BRAF87V600E, RET fusion, HER2). The UI and API **never assert it alone**: the badge is accompanied by the88actual `drug_approvals` rows with `tumor_agnostic = true` (the source's flag, set by the openFDA89connector from the label text) reached through §3.4. When no such row is ingested yet, the page says90so explicitly ("no tumor-agnostic approval row ingested yet") instead of implying one exists.9192### 3.6 Literature93`publication_entity_edges` (status ≠ rejected) on the scope **variants** for molecular markers, or94on the scope **genes** otherwise. Bibliographic data as recorded by PubMed.9596## 4. What is not claimed9798- No clinical-utility grading of our own (no "Tier", "Level 1", "actionable" labels): only the99  source-native CIViC level and direction and the regulator's status are shown.100- No threshold or cut-off is stated as CancerIndex's; scoring conventions are quoted as published101  and labels/indications are the authority's own text.102- No "approved for biomarker X" statement: approvals are listed per authority and jurisdiction with103  their indication text, and the match rule (drug set / indication text) is displayed per row.104- No patient-level guidance: biomarker pages describe what a test measures, not what a person105  should do.106- Absence of a link is not evidence of absence: only ingested sources (CIViC, ClinicalTrials.gov,107  openFDA, Health Canada DPD, PubMed edges) are covered.108109## 5. Maintenance110111- Add a marker: append to `BIOMARKER_SEED` with a **verified** NCIt code (fetch the concept, record112  the date/version in the header if the version changed), run `pnpm db:seed`, run113  `packages/database/test/biomarkers.test.ts`.114- Changing the derivation rules = bump `BIOMARKER_LINKS_FORMULA` in both the web queries and the API115  route, and update §3 here.116