A knowledge graph that tracks biomedical claims through an epistemic lifecycle, detecting when previously untestable assertions become falsifiable and scoring their validation risk.
Many clinical practices were adopted based on physiological reasoning or observational data decades before randomized controlled trials tested them. Antiarrhythmic drugs were prescribed to post-MI patients for 30 years before CAST (1989) showed they increased mortality. Tight glucose control in the ICU was standard for a decade before NICE-SUGAR (2009) revealed harm. Hormone replacement therapy was prescribed to millions before WHI (2002) overturned the paradigm.
This project cross-references a claims layer against a capabilities timeline to detect feasibility transitions: the moment a previously untestable claim became empirically testable. It then scores the Brandolini risk of each claim: how widely accepted it was relative to how long it took to validate.
Nicholas Rescher coined the term "epistemetrics" in 2006 (Cambridge University Press) as the quantitative study of how knowledge grows and changes. It's broader than scientometrics (which counts papers and citations) because it asks not just "how much was published" but "how much do we actually know, and how confident should we be?" The concept has remained largely theoretical. This project is an attempt to operationalize it for clinical medicine.
Existing tools occupy adjacent spaces: CiteSpace and VOSviewer do citation analysis and co-citation clustering; SciFact (Allen AI) verifies individual claims against abstracts; BEL (Biological Expression Language) captures contradictory biological findings. But none track when a claim became testable or measure the gap between claim adoption and validation.
In classical logic, a vacuous truth is a universal statement that is trivially true because its antecedent class is empty: "All unicorns can fly" is true because there are no unicorns. Standard logic treats this as a single category and doesn't ask why the class is empty.
But in biomedical ontology, the reason matters. Consider: "All patients who regenerate a lost limb regain full function." The antecedent class is empty today, but it's empty for contingent reasons (we haven't developed limb regeneration yet), not necessary ones (there's no logical contradiction in the concept). Modal logic provides the vocabulary: an antecedent that is empty in all possible worlds is necessarily vacuous (like "all married bachelors"), while one that is empty only in the actual world is contingently vacuous.
We propose a further distinction:
- Logically vacuous: the antecedent is empty by definition or logical contradiction. These are filtered out (e.g., "vitamin C cures all disease" where the mechanism is unfalsifiable by construction).
- Empirically vacuous: the antecedent is empty because the required technology, methodology, or infrastructure doesn't yet exist. These are the interesting cases, because they have a shelf life that depends on capability development.
This distinction does not appear to be established in the formal logic or ontology literature. Strawson's presupposition failure (1950) is the closest philosophical precedent: he argued that statements whose presuppositions aren't met don't have a truth value at all, rather than being trivially true. But Strawson was addressing definite descriptions, not universals over contingently empty classes, and didn't consider the temporal dimension of when presuppositions might become satisfiable.
The temporal epistemic graph operationalizes this: by cross-referencing claims against a capabilities timeline, it detects the moment an empirically vacuous claim stops being vacuous and becomes testable. This is the "feasibility transition" at the core of the lifecycle model.
OWL's open-world assumption means the absence of a contradicting axiom doesn't confirm a claim. But in practice, clinical knowledge gets encoded into guideline-derived CDS rules and order sets, where treatment assumptions persist as operational ground truth until someone manually revises them. The ontology layer itself (SNOMED CT, ICD) mostly encodes taxonomy and structure, not treatment efficacy.
Evidence grading standards like GRADE exist in the guideline world (with a formal GRADE Ontology proposed in 2025), but there is no standard bridge connecting the strength of evidence behind a clinical claim to the systems that operationalize it. OWL annotation properties can carry arbitrary metadata, but reasoners ignore them. The confidence that produced a clinical axiom is invisible downstream.
This project explores whether a separate epistemic layer, tracking when claims became testable, what evidence supports them, and how widely they spread relative to their evidence grade, can fill this gap.
Every claim is tracked through 8 states:
capability
transition
vacuous ─────────────────> speculative
|
study designed /
methods available
|
v
testable
|
landmark trial
|
v
tested
/ | \
/ | \
v v v
confirmed qualified refuted
|
still practiced?
|
v
zombie (flag)
Any state -- retraction notice --> retracted
Key distinction: Logically vacuous claims ("vitamin C cures all disease") are unfalsifiable by construction and filtered out. Empirically vacuous claims ("antiarrhythmics reduce post-MI mortality") are falsifiable in principle but untestable until specific capabilities exist (multicenter RCTs, standardized endpoints, sufficient sample sizes). The latter are the interesting cases.
Brandolini's Law (the "bullshit asymmetry principle") says the energy to refute a false claim is an order of magnitude larger than the energy to produce it. In clinical medicine, a treatment can be adopted into guidelines based on mechanistic reasoning, but refuting it requires an RCT with IRB approval, multi-site enrollment, years of follow-up, and statistical rigor.
The Brandolini risk score surfaces claims that were widely accepted, weakly supported, and took decades to validate:
brandolini_risk = spread * (1 - evidence_strength) * validation_lag
where:
spread = log-normalized citation count of landmark trial [0-1]
evidence_strength = max evidence strength for the claim [0-1]
validation_lag = 1 - exp(-lag_years / 15), where lag_years =
landmark_year - acceptance_start_year [0-1]
The prototype dataset covers 41 clinical axioms across 11 medical domains, each tested by a landmark randomized controlled trial:
| Entity | Count |
|---|---|
| Claims | 41 |
| Landmark trial papers | 39 |
| Evidence records | 41 |
| Clinical research capabilities | 28 |
| TRANSITION edges | 161 |
Cardiology (9), Critical Care (7), Oncology (4), Surgery (3), Obstetrics (2), Endocrinology (3), Preventive Medicine (3), Nephrology (2), Neurology (3), Pulmonology (3), Infectious Disease (2)
Lifecycle velocity: Average time from speculative to testable: 19.6 years. From testable to tested: 13.4 years. Clinical claims take far longer to validate than AI performance claims.
Epistemic outcomes: Of 41 claims tested by landmark RCTs, 23 were refuted (56%), 12 confirmed (29%), and 6 qualified (15%). More than half of widely accepted clinical axioms were overturned.
Top Brandolini risks:
- PSA screening reduces prostate cancer mortality (0.217) -- qualified by PLCO/ERSPC showing overdiagnosis harm
- Intensive BP control reduces CKD progression (0.210) -- qualified by ACCORD showing no renal benefit
- Calcium + Vitamin D prevents hip fractures (0.192) -- qualified by WHI showing no significant benefit
- 1-hour antibiotic rule reduces sepsis mortality (0.183) -- qualified by Seymour et al. showing no benefit
- Radical mastectomy improves breast cancer survival (0.133) -- refuted by NSABP B-06
CAST (1989), ISCHEMIA (2020), SPRINT (2015), COURAGE (2007), ORBITA (2018), FAME (2010), POISE (2008), CABANA (2019), NICE-SUGAR (2009), ProCESS (2014), ARDSNet (2000), TRICC (1999), CORTICUS (2008), NSABP B-06 (2002), PLCO (2009), ACOSOG Z0011 (2011), Magpie (2002), WHI (2002), DECRA (2011), RESCUEicp (2016), HACA (2002), ACCORD (2008), DCCT (1993), WOSCOPS (1995), PROSEVA (2013), ASPREE (2018), and others.
Landmark Trial Papers ──> Claims with Lifecycle Data
|
Semantic Scholar API ──> Citation Counts ──> Spread Scores
|
Crossref API ──────────> Retraction Watch ──> Zombie Detection
|
Clinical Milestones ───> Capabilities ──────> Feasibility Triggers
|
Neo4j Graph
|
+---------+---------+
| |
FastAPI Server Next.js Frontend
(14 endpoints) (4 interactive views)
- Neo4j 5 Community for graph storage
- FastAPI server with 14 endpoints (claims, stats, Brandolini ranking, timeline, transitions, lifecycle analysis, sector analysis, capability impact)
- Semantic Scholar API for paper discovery and citation counts
- Crossref/Retraction Watch for zombie claim detection
- Pydantic models with clinical domain support
Four interactive views:
| View | Route | Tech | Description |
|---|---|---|---|
| Knowledge Frontier Sphere | / |
Three.js | Deformable icosahedron colored by clinical domain, displaced by claim density, animated across years |
| Claim Timeline | /timeline |
D3.js | Swimlane chart of 41 claims with 28 capability events as vertical markers |
| Brandolini Triage | /triage |
TanStack React Table | Sortable/filterable table of all claims ranked by Brandolini risk, with CSV export |
| Graph Explorer | /graph |
D3.js | Force-directed graph of claims, capabilities, and their relationships |
All views support click-to-detail panels showing full claim lifecycle, evidence records, linked papers, and capability dependencies.
- Python 3.11+
- Node.js 20+
- Docker (for Neo4j)
Copy .env.example to .env and populate the values before running anything. These are read by docker compose, the API server, and the ingest scripts:
cp .env.example .env| Variable | Required | Notes |
|---|---|---|
NEO4J_URI |
no | Defaults to bolt://localhost:7687 |
NEO4J_USER |
no | Defaults to neo4j |
NEO4J_PASSWORD |
yes | No default; set a strong value. Used for both the Neo4j container auth and all clients. |
CORS_ORIGINS |
no | Comma-separated allowed origins. Defaults to localhost; add your deployed frontend origin here. |
ANTHROPIC_API_KEY |
for extraction | Only needed for claim-extraction steps |
SEMANTIC_SCHOLAR_API_KEY |
no | Raises rate limits for paper enrichment |
OPENALEX_EMAIL |
no | Polite-pool email for OpenAlex |
cd /path/to/epistemetrics
docker compose up -dNeo4j will be available at http://localhost:7474 (browser) and bolt://localhost:7687.
pip install -e .
python scripts/ingest_clinical.py # Papers, claims, evidence, capabilities -> Neo4j
python scripts/compute_transitions.py # Lifecycle transitions + analysis
python scripts/phase3_scoring.py # Brandolini scoring + validationpython -m uvicorn src.api:app --port 8000 --reloadAPI docs at http://localhost:8000/docs.
cd frontend
npm install
npm run dev -- -p 3001Dashboard at http://localhost:3001.
| Endpoint | Description |
|---|---|
GET /api/health |
Health check |
GET /api/claims |
List claims (filter by state, predicate, min Brandolini) |
GET /api/claims/{id} |
Full claim detail with evidence, papers, capabilities, transitions |
GET /api/stats |
Counts, state distribution, predicate distribution |
GET /api/brandolini |
Risk ranking with limit and min_score params |
GET /api/timeline |
Claims with state history and capabilities (for D3 swimlane) |
GET /api/capabilities |
Capabilities sorted by date with claim counts |
GET /api/analysis/transitions |
Transitions per year |
GET /api/analysis/gap |
Brandolini gap (production vs. validation per year) |
GET /api/sphere |
Claims by clinical domain with aggregates |
GET /api/lifecycles |
Claims with full lifecycle (min_transitions filter) |
GET /api/analysis/sectors |
Per-domain analysis with Brandolini stats |
GET /api/analysis/capability-impact |
Capabilities ranked with testing velocity |
GET /api/analysis/lifecycle-completeness |
Lifecycle statistics |
temporal-epistemic-graph/
├── src/
│ ├── models.py # Pydantic models (Claim, Evidence, Capability, enums)
│ ├── graph.py # Neo4j CRUD + Cypher queries
│ ├── papers.py # Semantic Scholar API client
│ ├── extract.py # LLM-based claim extraction pipeline
│ ├── enrich.py # Brandolini scoring, evidence typing, Retraction Watch
│ ├── transitions.py # State transition engine (lifecycle computation)
│ ├── analysis.py # Temporal analysis (gap rates, capability impact, velocity)
│ ├── scoring.py # Enhanced scoring, zombie detection, sensitivity analysis
│ └── api.py # FastAPI server (14 endpoints)
├── scripts/
│ ├── ingest_clinical.py # Clinical pipeline: papers -> claims -> evidence -> Neo4j
│ ├── ingest_clinical_capabilities.py # 28 clinical research milestones
│ ├── compute_transitions.py
│ ├── phase3_scoring.py # Full scoring pipeline with validation
│ ├── ingest_all.py # Legacy: AI imaging claims pipeline
│ ├── ingest_capabilities.py # Legacy: AI capabilities
│ └── quality_report.py
├── data/
│ ├── clinical_claims.json # 41 clinical axioms with lifecycle data
│ ├── clinical_papers.json # 39 landmark trial papers
│ ├── claims.json # Legacy: 68 AI imaging claims
│ ├── seed_papers.json # Legacy: 60 AI papers
│ ├── analysis_report.md
│ └── phase3/
├── frontend/ # Next.js 16 dashboard
│ └── src/
│ ├── app/ # App Router pages (sphere, timeline, triage, graph)
│ ├── components/ # Sphere, Timeline, TriageTable, GraphExplorer, Nav, ClaimDetailPanel
│ └── lib/ # API client, types, constants
├── docker-compose.yml # Neo4j 5 Community
└── pyproject.toml
Clinical predicates used to structure claims:
| Predicate | Example |
|---|---|
| REDUCES | "Low-tidal-volume ventilation REDUCES ARDS mortality" |
| PREVENTS | "Calcium + Vitamin D PREVENTS hip fractures" |
| IMPROVES | "Decompressive craniectomy IMPROVES TBI outcomes" |
| INCREASES_RISK | "Perioperative beta-blockers INCREASES_RISK of stroke" |
| TREATS | "Antiarrhythmics TREATS post-MI ventricular arrhythmias" |
| DIAGNOSES | "Troponin DIAGNOSES myocardial infarction" |
| PREDICTS | "BNP PREDICTS heart failure outcomes" |
| DETECTS | "CT angiography DETECTS pulmonary embolism" |
| CLASSIFIES | "TNM staging CLASSIFIES cancer severity" |
| MATCHES_PERFORMANCE_OF | "PCI MATCHES surgery for stable angina" |
| OUTPERFORMS | "FFR-guided PCI OUTPERFORMS angiography-guided PCI" |
| ENABLES | "Multicenter RCT methods ENABLES large-scale validation" |
- Rescher, N. (2006). Epistemetrics. Cambridge University Press.
- Strawson, P.F. (1950). On Referring. Mind, 59(235), 320-344. doi:10.1093/mind/LIX.235.320
- GRADE Working Group (2025). Rationale and process for creating a GRADE Ontology. Journal of Clinical Epidemiology. doi:10.1016/j.jclinepi.2025.111712
- Prasad, V. et al. (2013). A Decade of Reversal: An Analysis of 146 Contradicted Medical Practices. Mayo Clinic Proceedings. doi:10.1016/j.mayocp.2013.05.012
- CAST Investigators (1989). Preliminary Report: Effect of Encainide and Flecainide on Mortality in a Randomized Trial of Arrhythmia Suppression after Myocardial Infarction. NEJM. doi:10.1056/NEJM198908103210629
- Finfer, S. et al. (2009). Intensive versus Conventional Glucose Control in Critically Ill Patients (NICE-SUGAR). NEJM. doi:10.1056/NEJMoa0810625
- Rossouw, J.E. et al. (2002). Risks and Benefits of Estrogen Plus Progestin in Healthy Postmenopausal Women (WHI). JAMA. doi:10.1001/jama.288.3.321
Apache 2.0