Skip to content

OncoKB by tumour type: tests from the spec, and three fixes they found - #218

Merged
alisman merged 4 commits into
masterfrom
session/mut-annotation-oncokb-tt-tests
Nov 15, 2026
Merged

alisman merged 4 commits into
masterfrom
session/mut-annotation-oncokb-tt-tests

Conversation

@alisman

@alisman alisman commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Brings #202 (OncoKB by tumour type) up to invariant 14. The spec table below was written first, with each row cited to the portal's source. A separate agent then wrote the tests from that table, without the implementation in view. The tests found three bugs in #202, all fixed here:

  • Blank cancer types. The warehouse's derived clinical table holds '' for each attribute a study declares but a sample lacks. The sync treated '' as a value, so a sample with both cancer-type attributes blank was asked about with no tumour type. The mutation table, though, reads it with the study's type, so it never found the call (841 warehouse samples). Blank now counts as absent, as it does in the portal, whose API never returns a blank.
  • Germline mutations. A germline mutation was shown the somatic OncoKB call. The portal asks about germline mutations by HGVSc, never by protein change. The match is a case-insensitive germline substring. A germline row now gets no protein-change call, either per tumour type or gene-level.
  • -1 positions. The importer writes -1 for unknown protein positions, and the portal sends them on. The sync dropped them; it now sends them.

Tests

  • Fixture check check:oncokb-tumor-type (47 checks, added to gate.sh): it syncs the peer fixture against recorded OncoKB answers and reads the Mutations table at the pin. New fixture samples: FX-P41 to FX-P44 (blank cancer types, broad type only, two tumour types in one patient, germline).
  • Unit tests: packages/annotation-sync/test/oncokb-tumor-type.test.ts (rewritten) and test/mutation-table.test.ts.
  • Planted bugs in scripts/check-mutants.ts, all caught by oncokb-tumor-type:
    • oncokb-tt-blank-is-data: 1 failing check
    • oncokb-tt-cancer-type-not-detailed: 19 failing checks
    • oncokb-tt-germline-called: 1 failing check
    • oncokb-tt-tumour-type-ignored: 8 failing checks
  • Snapshot: mutations re-recorded; the SQL changed and the rendered card did not.

Verification

  • npm test: 4145 tests, 0 failing (34 TODO, all pre-existing).
  • node --test test/view-snapshots*.test.ts: passes.
  • tsc: clean. eslint on the changed files: clean.

Legacy reference

cbioportal-frontend e9d70fb: StoreUtils.ts (generateUniqueSampleKeyToTumorTypeMap 1180-1203, cancerTypeForOncoKb 919, fetchOncoKbData 784-789, queryOncoKbData 944-972), OncoKbUtils.ts 103 and 169-196, and the Results table's call, DefaultMutationMapperStore 988-1011 → DataFetcher 296-368.

Spec

T — the tumour type a mutation is asked about with (generateUniqueSampleKeyToTumorTypeMap, cancerTypeForOncoKb)

# Input Expected Source
T1 sample with CANCER_TYPE_DETAILED "Pancreatic Adenocarcinoma" tumour type "Pancreatic Adenocarcinoma" SU 1180-1190
T2 sample with CANCER_TYPE and CANCER_TYPE_DETAILED that differ the detailed one SU 1180-1190 (only CANCER_TYPE_DETAILED is read)
T3 sample with neither attribute (no clinical rows of either) the study's cancer type (type_of_cancer.name, e.g. "Colorectal Adenocarcinoma") SU 1194-1203; AS 479-499 samplesWithoutCancerTypeClinicalData; SU 1417-1427
T4 sample with CANCER_TYPE only none: tumorType null (stored as '') SU 1199 (map[k] === undefined only for samples without data; this sample has data); SU 919 `
T5 sample with CANCER_TYPE_DETAILED = "" (empty value) none (null) SU 919 (`''
T6 patient-level CANCER_TYPE_DETAILED only (not sample-level) as T3 when the sample has no sample-level rows: the study's type AS 410-425 (CLINICAL_DATA_TYPE_SAMPLE)
T7 two samples of one patient with different detailed types, same mutation two keys, one per tumour type SU (per uniqueSampleKey)

Q — which mutations are asked, and how (fetchOncoKbData, generateProteinChangeQuery)

# Input Expected Source
Q1 gene OncoKB curates (/utils/cancerGeneList oncokbAnnotated) asked SU 784-789
Q2 gene not curated, not a fusion not asked; stored with empty oncogenicity so the next sync skips it SU 784-789
Q3 mutation type Fusion, gene not curated asked (fusions are queried whatever the gene) SU 786-787 m.mutationType === fusionMutationType ||
Q4 germline mutation (mutationStatus "Germline", "GERMLINE", "germline") not asked by protein change (legacy asks by HGVSc; out of scope here) OAU 53-60; SU 944-952
Q5 the query {alteration: proteinChange, consequence: mutationType, gene: {entrezGeneId}, proteinStart, proteinEnd, tumorType, germline: false}; no evidenceTypes OKU 169-196; MMS 400-408
Q6 two mutations with equal gene, alteration, mutation type, tumour type one query OKU 103 generateQueryVariantId (id = entrez_tumorType_alteration_mutationType) and dedup
Q7 same gene/alteration/type, different tumour types two queries, each with its tumour type OKU 103
Q8 proteinChange empty / null not asked (no alteration)
Q9 protein positions absent (0 / null) sent as absent, not 0 OKU 190-191

S — what is stored and shown

# Input Expected Source
S1 OncoKB answers oncogenic "Oncogenic", levels stored oncogenicity and the four highest levels (sensitive, resistance, diagnostic, prognostic); the whole answer in data cBioLab (store)
S2 OncoKB answers no oncogenic "Unknown" cBioLab, as annotation.oncokb
S3 the mutation table, at the pin, a mutation with a stored row for its tumour type its oncogenicity and highest sensitive level; driver = Oncogenic / Likely Oncogenic / Resistance cBioLab
S4 the mutation table, a mutation with no row for its tumour type (study not synced) the gene-level annotation.oncokb row cBioLab
S5 a row stored at another release than the pin not read cBioLab (version pin)
S6 same alteration, two samples with different tumour types each row shows its own tumour type's level the point of the change

Corrections from the test author (checked against the legacy source)

Row Correction
Q3 Wrong as first written. fetchOncoKbData lets fusions through its gene filter (SU 786-787), but queryOncoKbData then drops mutationType !== 'Fusion' before both endpoints (SU 960-972, DMF 345-351): a Fusion mutation is never asked by protein change. C's exclusion was right; the test follows the portal. (mutation_derived holds 0 Fusion rows.)
T3/T5 The warehouse's derived clinical table holds '' for every sample × attribute a study declares; the portal's API never returns a blank. So blank = absent: both blank → the study's type (FX-P41); CANCER_TYPE set, detailed blank → none. C keyed both-blank samples with no tumour type while the table used the study's: fixed (841 warehouse samples).
T6 Patient-level cancer types: 0 rows in the warehouse; not built.
Q4 The portal's germline test is a case-insensitive substring (indexOf('germline')). C's table showed a germline mutation the somatic call: fixed (a germline row gets no protein-change call, tumour-type or gene-level). The key space now matches the substring too.
Q8 Empty protein changes do not occur; the importer writes MUTATED, which is asked as the portal would.
Q9 0 / null positions do not occur (one row has end 0); the importer's unknown is -1, which the portal passes on (DMF 361-362). C dropped -1: fixed (Q9b).
Q5 The Results table's call is DefaultMutationMapperStore.oncoKbData (DMS 988-1011) via DMF 296-368, not MMS 400-408 (group comparison's CANCER_TYPE variant).
S3 The portal also counts "Predicted Oncogenic" as a driver; it does not occur in OncoKB v7.7.

Not done

  • Germline mutations asked by HGVSc (the portal's second endpoint). They now show no call rather than the wrong one.
  • Patient-level cancer types (T6): the warehouse has no such rows.

Merging this alongside #211 will conflict in data_mutations.txt, peer-db.ts, package.json, gate.sh, TESTING.md and check-mutants.ts. Each conflict is two additions side by side; keep both.

Preview

  • /portal/results?study=paad_iatlas_prince_2022&genes=KRAS%20CDKN2A%20TP53&tab=Mutations

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q3ezTXeuA6xMdKduTsWw4c

Tests for #202 written from a spec table cited to the portal's source,
by an agent without the implementation in view (invariant 14): a peer
fixture check (check:oncokb-tumor-type, 47 checks), unit tests for the
sync source and the mutation table, and four planted bugs.

Fixes the tests found:
- blank cancer-type values count as absent, so such a sample is asked
  about with its study's cancer type, as the table reads it
- a germline mutation gets no protein-change OncoKB call
- the importer's -1 protein positions are sent, as the portal sends them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTXeuA6xMdKduTsWw4c
@vercel

vercel Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cbiolab-genie Ready Ready Preview Nov 14, 2026 11:33pm UTC
cbiolab-new Ready Ready Preview Nov 14, 2026 11:33pm UTC
cohort-lab Ready Ready Preview Nov 14, 2026 11:33pm UTC

Request Review

CI coverage: the key space SQL ran only in the fixture check. The test
checks the study is quoted by sq() and scopes both tables, and that no
study means no filter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTXeuA6xMdKduTsWw4c
The hand counts assumed 44 fixture samples; FX-P41 to FX-P44 make 49
(29 of the women's), recounted from data_clinical_*.txt. FX-P41-T1's
CANCER_TYPE is blank, so it is at 98%, and DEAD is the third 100% row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTXeuA6xMdKduTsWw4c
Cases 12, 13, 15 and 33 run only against the fixture database (the
planted-bug baseline runs them) and counted 40 patients and 44 samples.
Recounted from data_clinical_*.txt for FX-P41 to FX-P44: 44 patients,
49 samples (26 and 29 of the women's). CANCER_TYPE drops to 98.0% and
CANCER_TYPE_DETAILED and ONCOTREE_CODE to 95.9%, which moves them below
the 100% rows in the menu order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3ezTXeuA6xMdKduTsWw4c
@alisman
alisman merged commit 99b97e6 into master Nov 15, 2026
12 checks passed
@alisman
alisman deleted the session/mut-annotation-oncokb-tt-tests branch November 15, 2026 02:56

This branch was successfully deployed

1 active deployment
Preview – cohort-lab — 505cb4ec Deployed Nov 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant