/** * Metric catalog (CLAUDE.md §250-252, §352). Every derived number shown on the site references * one of these definitions by slug; the formula text and version are displayed on /methodology. * * Composite scores (CI-IMPACT etc.) are intentionally absent from Phase 1 (§353). */ export interface MetricSeed { slug: string; name: string; description: string; formula: string; formulaVersion: string; unit: string; higherIsWorse: boolean | null; aggregation: string | null; validDimensions: string[]; sourceSlugs: string[]; category: string; eligibility: Record; experimental: boolean; } export const METRIC_CATALOG: MetricSeed[] = [ // --- Burden (epidemiology observations) --- { slug: 'incidence_count', name: 'Annual new cases', description: 'Number of new cases diagnosed in the reference year for the population scope. Registry counts are observed; national/global figures may be estimates and are labeled as such.', formula: 'epidemiology_observations.value WHERE metric = incidence_count', formulaVersion: 'ci-incidence-count-v1', unit: 'count', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'sex', 'age_group', 'year'], sourceSlugs: ['cdc-wonder', 'seer', 'iarc-globocan'], category: 'burden', eligibility: { requires: ['incidence_count'], entityLevel: 'top' }, experimental: false, }, { slug: 'mortality_count', name: 'Annual deaths', description: 'Number of deaths with this cancer as underlying cause in the reference year for the population scope.', formula: 'epidemiology_observations.value WHERE metric = mortality_count', formulaVersion: 'ci-mortality-count-v1', unit: 'count', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'sex', 'age_group', 'year'], sourceSlugs: ['cdc-wonder', 'seer', 'iarc-globocan'], category: 'burden', eligibility: { requires: ['mortality_count'], entityLevel: 'top' }, experimental: false, }, { slug: 'as_incidence_rate', name: 'Age-standardized incidence rate', description: 'Incidence per 100,000 person-years, age-standardized to the standard population declared by the source. Rates standardized to different standard populations are never compared in one ranking.', formula: 'epidemiology_observations.value WHERE metric = as_incidence_rate (standard_population fixed per scope)', formulaVersion: 'ci-asir-v1', unit: 'per_100k', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'sex', 'year'], sourceSlugs: ['cdc-wonder', 'seer', 'iarc-globocan'], category: 'burden', eligibility: { requires: ['as_incidence_rate'], entityLevel: 'top' }, experimental: false, }, { slug: 'as_mortality_rate', name: 'Age-standardized mortality rate', description: 'Deaths per 100,000 person-years, age-standardized to the standard population declared by the source.', formula: 'epidemiology_observations.value WHERE metric = as_mortality_rate (standard_population fixed per scope)', formulaVersion: 'ci-asmr-v1', unit: 'per_100k', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'sex', 'year'], sourceSlugs: ['cdc-wonder', 'seer', 'iarc-globocan'], category: 'burden', eligibility: { requires: ['as_mortality_rate'], entityLevel: 'top' }, experimental: false, }, // --- Lethality --- { slug: 'mortality_incidence_ratio', name: 'Mortality-to-incidence ratio', description: 'Deaths divided by new cases in the same population, year and sex. A crude proxy of lethality; it is not a survival probability and is affected by incidence trends and registration completeness.', formula: 'mortality_count / incidence_count (same geography, year, sex, source family)', formulaVersion: 'ci-mir-v1', unit: 'ratio', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'sex', 'year'], sourceSlugs: ['cdc-wonder', 'seer', 'iarc-globocan'], category: 'lethality', eligibility: { requires: ['incidence_count', 'mortality_count'], minIncidence: 100, entityLevel: 'top' }, experimental: false, }, { slug: 'five_year_survival', name: '5-year relative survival', description: '5-year relative survival for the diagnosis period and population declared by the source. Population survival statistics do not predict an individual outcome.', formula: 'survival_observations.probability WHERE survival_type = relative AND duration_months = 60 AND stage IS NULL', formulaVersion: 'ci-5ys-v1', unit: 'probability', higherIsWorse: false, aggregation: 'none', validDimensions: ['geography', 'sex', 'diagnosis_period'], sourceSlugs: ['seer'], category: 'lethality', eligibility: { requires: ['five_year_relative_survival'], minCohort: 50, entityLevel: 'top' }, experimental: false, }, // --- Clinical research (ClinicalTrials.gov) --- { slug: 'active_trials', name: 'Active clinical trials', description: 'Interventional studies registered on ClinicalTrials.gov whose overall status is RECRUITING, NOT_YET_RECRUITING, ENROLLING_BY_INVITATION or ACTIVE_NOT_RECRUITING and whose conditions map to this cancer or one of its descendants in the NCIt hierarchy.', formula: 'COUNT(DISTINCT trial) FROM trial_conditions JOIN clinical_trials WHERE cancer_id IN descendants(cancer) AND study_type = INTERVENTIONAL AND overall_status IN (RECRUITING, NOT_YET_RECRUITING, ENROLLING_BY_INVITATION, ACTIVE_NOT_RECRUITING)', formulaVersion: 'ci-active-trials-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trials', eligibility: { entityLevel: 'any' }, experimental: false, }, { slug: 'recruiting_trials', name: 'Recruiting clinical trials', description: 'Interventional studies currently RECRUITING whose conditions map to this cancer or its descendants.', formula: 'COUNT(DISTINCT trial) … overall_status = RECRUITING AND study_type = INTERVENTIONAL', formulaVersion: 'ci-recruiting-trials-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trials', eligibility: { entityLevel: 'any' }, experimental: false, }, { slug: 'phase3_trials', name: 'Active Phase III trials', description: 'Active interventional studies with PHASE3 among their phases, mapped to this cancer or its descendants.', formula: 'COUNT(DISTINCT trial) … active statuses AND PHASE3 = ANY(phases)', formulaVersion: 'ci-phase3-trials-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trials', eligibility: { entityLevel: 'any' }, experimental: false, }, // --- Research activity (PubMed) --- { slug: 'publications_5y', name: 'Publications, last 5 years', description: 'PubMed records matching the cancer’s MeSH-anchored query (stored verbatim with the count) with a publication date in the last 5 full years plus the current year.', formula: 'literature_counts.count WHERE window_key = 5y (query stored per row)', formulaVersion: 'ci-pubs-5y-v1', unit: 'count', higherIsWorse: false, aggregation: 'none', validDimensions: ['entity_level'], sourceSlugs: ['pubmed'], category: 'research', eligibility: { entityLevel: 'any', requiresQuery: true }, experimental: false, }, { slug: 'publications_12m', name: 'Publications, last 12 months', description: 'PubMed records matching the cancer’s query with a publication date in the last 12 months.', formula: 'literature_counts.count WHERE window_key = 12m', formulaVersion: 'ci-pubs-12m-v1', unit: 'count', higherIsWorse: false, aggregation: 'none', validDimensions: ['entity_level'], sourceSlugs: ['pubmed'], category: 'research', eligibility: { entityLevel: 'any', requiresQuery: true }, experimental: false, }, { slug: 'publication_growth', name: 'Publication growth', description: 'Ratio of publications in the last 12 months to the average annual publications over the preceding 5-year window. Values above 1 indicate accelerating literature.', formula: 'publications_12m / (publications_5y_prior / 5)', formulaVersion: 'ci-pub-growth-v1', unit: 'ratio', higherIsWorse: null, aggregation: 'none', validDimensions: ['entity_level'], sourceSlugs: ['pubmed'], category: 'trend', eligibility: { entityLevel: 'any', minPublications5y: 50 }, experimental: false, }, // --- Molecular knowledge --- { slug: 'curated_evidence_items', name: 'Curated clinical evidence items', description: 'Accepted CIViC evidence items whose disease maps to this cancer or its descendants.', formula: 'COUNT(civic_evidence_items) WHERE status = ACCEPTED AND cancer_id IN descendants(cancer)', formulaVersion: 'ci-civic-evidence-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['civic'], category: 'molecular', eligibility: { entityLevel: 'any' }, experimental: false, }, { slug: 'associated_genes', name: 'Genes with curated or cohort evidence', description: 'Distinct genes linked to this cancer (or descendants) by an accepted CIViC evidence item or by a GDC cohort frequency of at least 5% with ≥ 20 affected cases.', formula: 'COUNT(DISTINCT gene) FROM (civic accepted evidence ∪ gdc frequency ≥ 0.05 AND cases_affected ≥ 20)', formulaVersion: 'ci-genes-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['civic', 'gdc'], category: 'molecular', eligibility: { entityLevel: 'any' }, experimental: false, }, { slug: 'genomic_cohorts', name: 'Public genomic cohorts', description: 'Open-access genomic studies (GDC projects) whose disease maps to this cancer or its descendants.', formula: 'COUNT(genomic_cohorts) WHERE cancer_id IN descendants(cancer)', formulaVersion: 'ci-cohorts-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['gdc'], category: 'molecular', eligibility: { entityLevel: 'any' }, experimental: false, }, // --- Gap indexes (derived; require burden) --- { slug: 'trial_gap', name: 'Trial Gap Index', description: 'Burden percentile minus active-trial percentile within the same scope. Positive values flag cancers with high mortality burden but comparatively few active trials. A quantitative signal, not an accusation (CLAUDE.md §324). Caveat (Phase 1): trial counts aggregate a cancer and its NCIt descendants only; registrations phrased at a broader level (e.g. "colorectal cancer" for colon and rectal cancer) are attributed to the broader entity, which can overstate the gap of narrower top-level sites.', formula: 'percentile(mortality_count) − percentile(active_trials)', formulaVersion: 'ci-trial-gap-v1', unit: 'percentile_points', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'year'], sourceSlugs: ['clinicaltrials', 'cdc-wonder', 'seer', 'iarc-globocan'], category: 'unmet_need', eligibility: { requires: ['mortality_count', 'active_trials'], entityLevel: 'top' }, experimental: false, }, { slug: 'research_gap', name: 'Research Gap Index', description: 'Burden percentile minus research-activity percentile (publications, last 5 years) within the same scope. Positive values flag cancers with high mortality burden but comparatively little literature. Caveat (Phase 1): literature counts are query-based per entity (query stored on each row); they are not aggregated over descendants.', formula: 'percentile(mortality_count) − percentile(publications_5y)', formulaVersion: 'ci-research-gap-v1', unit: 'percentile_points', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'year'], sourceSlugs: ['pubmed', 'cdc-wonder', 'seer', 'iarc-globocan'], category: 'unmet_need', eligibility: { requires: ['mortality_count', 'publications_5y'], entityLevel: 'top' }, experimental: false, }, // --- Clinical-trial intelligence (SPEC §10; computed in packages/ranking/src/trial-intelligence.ts) --- { slug: 'phase3_recruiting_trials', name: 'Recruiting Phase III trials', description: 'Interventional studies with PHASE3 among their phases and overall status RECRUITING, mapped to this cancer or its descendants.', formula: 'COUNT(DISTINCT trial) … overall_status = RECRUITING AND PHASE3 = ANY(phases) AND study_type = INTERVENTIONAL', formulaVersion: 'ci-phase3-recruiting-v1', unit: 'count', higherIsWorse: false, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trials', eligibility: { entityLevel: 'any' }, experimental: false, }, { slug: 'trial_growth_yoy', name: 'Trial registration growth (year over year)', description: 'Relative change in the number of interventional studies first posted in the last 12 months versus the preceding 12 months, over the cancer and its descendants. Requires at least 20 studies in the prior window so small denominators do not produce spurious growth.', formula: '(new_trials_12m − new_trials_prior_12m) / new_trials_prior_12m (first_posted_date windows; interventional; descendants)', formulaVersion: 'ci-trial-growth-v1', unit: 'ratio', higherIsWorse: null, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trend', eligibility: { entityLevel: 'any', minPriorTrials: 20 }, experimental: false, }, { slug: 'trial_termination_share', name: 'Trial termination share', description: 'Share of interventional studies first posted since 2010 that ended TERMINATED or WITHDRAWN among those that reached a terminal status (COMPLETED, TERMINATED, WITHDRAWN). Registrant-reported statuses; reasons are shown as posted and never inferred. Requires ≥ 30 terminal studies.', formula: '(terminated + withdrawn) / (completed + terminated + withdrawn) WHERE first_posted_date ≥ 2010-01-01 AND study_type = INTERVENTIONAL', formulaVersion: 'ci-trial-termination-v1', unit: 'ratio', higherIsWorse: true, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trials', eligibility: { entityLevel: 'any', minTerminalTrials: 30 }, experimental: false, }, { slug: 'sponsor_concentration', name: 'Sponsor concentration (HHI)', description: 'Herfindahl–Hirschman index of lead sponsors over active interventional studies (sum of squared sponsor shares; 1 = a single sponsor). Requires ≥ 10 active studies.', formula: 'Σ (active_trials_by_lead_sponsor / active_trials)² over the cancer and its descendants', formulaVersion: 'ci-sponsor-hhi-v1', unit: 'index', higherIsWorse: null, aggregation: 'descendants', validDimensions: ['entity_level'], sourceSlugs: ['clinicaltrials'], category: 'trials', eligibility: { entityLevel: 'any', minActiveTrials: 10 }, experimental: false, }, { slug: 'trials_per_1000_deaths', name: 'Active trials per 1,000 annual deaths', description: 'Active interventional studies divided by annual deaths (thousands) in the same population scope. A burden-normalized measure of clinical-research intensity; it depends on the epidemiology source of the scope and on how registrants phrase conditions.', formula: 'active_trials / (mortality_count / 1000) (same geography, year, sex, source family; deaths ≥ 100)', formulaVersion: 'ci-trials-per-deaths-v1', unit: 'per_1000_deaths', higherIsWorse: false, aggregation: 'none', validDimensions: ['geography', 'year'], sourceSlugs: ['clinicaltrials', 'cdc-wonder', 'cdc-uscs', 'seer', 'iarc-globocan'], category: 'unmet_need', eligibility: { requires: ['mortality_count', 'active_trials'], minDeaths: 100, entityLevel: 'top' }, experimental: false, }, { slug: 'publications_per_1000_deaths', name: 'Publications (5 y) per 1,000 annual deaths', description: 'PubMed records over the last 5 years divided by annual deaths (thousands) in the same population scope. A burden-normalized measure of research output.', formula: 'publications_5y / (mortality_count / 1000) (same geography, year, sex, source family; deaths ≥ 100)', formulaVersion: 'ci-pubs-per-deaths-v1', unit: 'per_1000_deaths', higherIsWorse: false, aggregation: 'none', validDimensions: ['geography', 'year'], sourceSlugs: ['pubmed', 'cdc-wonder', 'cdc-uscs', 'seer', 'iarc-globocan'], category: 'unmet_need', eligibility: { requires: ['mortality_count', 'publications_5y'], minDeaths: 100, entityLevel: 'top' }, experimental: false, }, { slug: 'trial_gap_ratio', name: 'Trial Gap Ratio', description: 'log₂ of a cancer’s share of deaths divided by its share of active interventional trials, both computed over the eligible top-level cancers of the scope. 0 = trial share matches death share; +1 = twice as many deaths as trials would suggest; −1 = half. Scale-free, so it can be compared across scopes, unlike the percentile-based Trial Gap Index.', formula: 'log2( (deaths / Σ deaths) / (active_trials / Σ active_trials) ) over eligible top-level cancers (deaths ≥ 100, active_trials ≥ 1)', formulaVersion: 'ci-trial-gap-ratio-v1', unit: 'log2_ratio', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'year'], sourceSlugs: ['clinicaltrials', 'cdc-wonder', 'cdc-uscs', 'seer', 'iarc-globocan'], category: 'unmet_need', eligibility: { requires: ['mortality_count', 'active_trials'], minDeaths: 100, entityLevel: 'top' }, experimental: false, }, { slug: 'research_gap_ratio', name: 'Research Gap Ratio', description: 'log₂ of a cancer’s share of deaths divided by its share of publications (last 5 years), both over the eligible top-level cancers of the scope. 0 = literature share matches death share; positive values flag comparatively under-published cancers. Caveat: literature counts are query-based per entity and not aggregated over descendants.', formula: 'log2( (deaths / Σ deaths) / (publications_5y / Σ publications_5y) ) over eligible top-level cancers (deaths ≥ 100, publications_5y ≥ 1)', formulaVersion: 'ci-research-gap-ratio-v1', unit: 'log2_ratio', higherIsWorse: true, aggregation: 'none', validDimensions: ['geography', 'year'], sourceSlugs: ['pubmed', 'cdc-wonder', 'cdc-uscs', 'seer', 'iarc-globocan'], category: 'unmet_need', eligibility: { requires: ['mortality_count', 'publications_5y'], minDeaths: 100, entityLevel: 'top' }, experimental: false, }, ];