Patient-as-a-Node (PaaN): Thinking Doc
Status: thinking artifact, not a build commitment. We answered “should we build?” with “keep thinking.” This doc captures the full reasoning so we can revisit when we’re ready to commit.
Context
You asked four interlocking questions and we surfaced several more along the way:
- Refresh on PaaN. What have we been planning? Is “patient → has → disease/gene/phenotype” the right schema? To what end?
- PDR2’s loss function — really. How is patient genetics actually integrated during training? Is it PRS? What else? And — important — why does the
PersonalizedRepurposingLosscode exist but never run? - What could we attach to a Patient node that PDR2 didn’t have? And what could we acquire that PDR2 didn’t even consider, given access to any test in the developed world?
- Where have other researchers wandered? What’s the literature say?
- Supervision — what does it mean in ML, and what’s the landscape of supervision-producing tests we could use?
- Node vs subgraph — what’s the real distinction?
- Compositions reframe everything. Maureen isn’t an overlay on PrimeKG; she’s an overlay on whatever Composition we’re training against.
Underneath all of it is the real question: should PaaN remain a distant “Phase 12 / final stage” or do we start building an imperfect-but-working prototype now? Decision: not yet — but we now know what “yet” looks like.
0. A note on the PDR2 framing
PDR2 (paper) already is a patient-as-a-node architecture. I had this wrong twice. The corrected mechanistic description is in §5. What PDR2 specifically did:
- Patient nodes with
WAS_DIAGNOSEDedges to disease nodes, added to the training KG so the foundation model learns patient embeddings from epoch 1. - PRS values + biomarker expressions are NOT in the graph — they’re scalar feature vectors used by the loss.
- Per-patient fine-tune freezes the foundation and trains only 1,802 weights inside the loss (per-disease + per-protein) that reweight the global ranking based on the patient’s features.
- AUPRC lifts reported as 1.3–5.4× across three case patients; MRR/Hits stay similar.
- Validation by literature review only — no per-patient outcome labels like our RGCC.
Our PaaN ambition is richer than PDR2’s in two ways:
- More patient edges — variants, treatments, drug sensitivities, in addition to diagnoses.
- Real per-patient supervision — RGCC drug sensitivities as labels, not just literature review.
The rest of this doc is structured as if from scratch — refreshing what we’ve been thinking, then sketching how to do something genuinely beyond PDR2.
1. The mental model — Maureen as overlay on a Composition
This is the central reframe. My memories predated Compositions, so I was sketching as if PrimeKG were the only target graph. It isn’t.
A Composition is a named, versioned recipe — “use these KG sources, apply these per-source domain/predicate filters” (docs/kg_composition_pipeline_writeup.md). Six exist already: gp_kg_baseline_v1, primekg_baseline_v1, rtx_kg2_full, rtx_kg2_tier1, tier1_mvp_v1, tier1_mvp_with_primekg_v1. Training runs point at a composition by id; the same canonical store backs every experiment.
The right mental model is:
┌──────────────────────────────────────────────┐
│ Composition (e.g. tier1_mvp_with_primekg) │ the underlying graph
│ ├─ PrimeKG (genes, drugs, diseases, ...) │ chosen sources × domains × predicates
│ ├─ CIViC (variants) │
│ ├─ OncoKB (variants, biomarkers) │
│ └─ PharmGKB (PGx) │
└──────────────────────────────────────────────┘
⊕ overlay
┌──────────────────────────────────────────────┐
│ Maureen (her node + her edges) │ patient overlay (attachable to any composition)
│ ├─ patient → has_disease → CRC │
│ ├─ patient → carries_variant → BRAF V600E │
│ ├─ patient → over_expresses → PTGS2 (z=3.1) │
│ ├─ patient → tried_drug → FOLFOX (no_resp) │
│ └─ patient → sensitive_to → drug_X (RGCC) │
└──────────────────────────────────────────────┘
↓ train / infer
Composition + Maureen
(or Composition alone, with Maureen attached only at inference)
This matters because:
- We’re not committing to PrimeKG. We’re committing to the geometry of the chosen composition. Different compositions have different entity types and relations available; Maureen’s edge schema has to work against any of them.
- Maureen is optional. Same training pipeline runs with or without her node attached. With her: patient-aware loss kicks in. Without her: standard KG link prediction (today’s PDR2 path).
- The anchor scoping machinery already planned in docs/kg_anchor_scoping_planning.md (Phase F) does not replace PaaN — it’s an analysis/filter/explain layer that works on top of any composition. PaaN (Phase 12) is the actual training-time architecture; Phase F is the post-prediction tooling. Both stay useful; they answer different questions.
- Browsability: same UI as the KG Composition tab. Maureen gets a card; click and you see her resolved CURIEs, her edges by type, her 1-hop neighborhood. No separate UI needed.
2. Refresh on prior thinking
The PaaN concept lives across four planning docs. None stand alone — they form a chain:
| Phase | Doc | What it covers | Status |
|---|---|---|---|
| 8.5 | [[kg/pdr_phase8.5_variant_kg_planning | pdr_phase8.5_variant_kg_planning.md]] | Variants as first-class entities — prerequisite for variant-aware patient edges |
| F | [[kg/kg_anchor_scoping_planning | kg_anchor_scoping_planning.md]] | Patient anchor sets → reachability subgraphs for inspection, inference filtering, explainability, per-patient fine-tune. Phase F.7 is the per-patient fine-tune use case |
| 12 | PDR_PIPELINE_PLAN.md § Phase 12 | Patient as an actual node in the training graph — the “holy grail” stage | Mentioned, not fully designed |
| 13 | [[planning/temporal_patient_modeling_planning | the temporal-modeling plan]] | Temporal trajectory encoder for the patient node (four tiers) |
Two distinctions worth pinning down:
-
Phase F vs Phase 12. Phase F is patient-centric subgraph extraction for analysis tasks — explaining a prediction, filtering candidates, building a per-patient fine-tune slice. The Phase F doc is explicit: it does not define the production training set, because that would kill discovery. Phase 12 is the architectural change — putting Maureen in the graph as a trained node and changing the loss accordingly. Phase F is “use a knife on the graph”; Phase 12 is “change the graph.”
-
The “has” edge schema we sketched. Phase 8.5 proposes edge types like
variant_of_gene,predicts_response_to,has_significance. But the patient→variant connection itself isn’t explicit yet. Three options:- (a) Implicit composition:
Patient → DYSREGULATED_GENE → Gene → VARIANT— current sketch - (b) Explicit:
Patient → CARRIES_VARIANT → Variant - (c) Both:
Patient → CARRIES_VARIANT → Variant → variant_of_gene → Gene
Your earlier note: “the variant info is critically discriminating and absolutely needed for MVP.” That implies (c) — explicit variant edges and the variant→gene chain. Phase 8.5 must ship before the MVP can be meaningful.
- (a) Implicit composition:
3. Node vs subgraph — what the real distinction is
You pushed back, rightly, that a subgraph is just one or more nodes connected to the graph. Let me re-do this distinction.
Every set of nodes induces a subgraph in graph theory — that’s not what makes one pattern different from the other. The real distinction is identity:
- Patient as an explicit node: Maureen has her own row in
mods_kg_entity. She has a canonical CURIE (e.g.,MAPLE_PATIENT:maureen-001). She has an entity_type. Edges from and to her are first-class rows inmods_kg_relation. The model can score(maureen, treats?, drug_X)as a triple. She is one thing in the graph. - Patient as a subgraph (SHEPHERD pattern): Maureen has no node of her own in the KG. She’s represented by the set of pre-existing nodes that describe her — her phenotypes, her variants, her diseases. The model embeds her by pooling over that set. The patient is implicit in a collection of edges, not first-class.
| Trade-off | Explicit node | Implicit subgraph |
|---|---|---|
Scoring (patient, *, drug) as a query | Direct triple | Need to pool over patient’s neighborhood, then score |
| Per-patient edges (RGCC, treatment history) | Naturally live on her node | Awkward — they’re either edges on existing nodes (e.g., gene→drug) or live outside the graph entirely |
| Inductive on a new patient | Hard for transductive entity embeddings, fine for NBFNet-style message passing | Trivial — just compute the subgraph |
| Browse “this patient in the graph” | Click her node, see her neighborhood — same UX as any KG entity | Need a join across her CURIEs |
| Schema invasiveness | New entity type + edge types + migration | Zero schema change |
| The “anchor” loss pattern you described | Natural — her node embedding is the anchor every gradient step references | Less obvious — what gets anchored? An aggregate of her CURIEs? |
For our setup the explicit-node pattern wins, primarily because (1) you want her browsable like a KG entity, (2) RGCC sensitivities and treatment history are most natural as edges on her, and (3) “patient as anchor in training” needs her to have a single embedding the loss can reference. The SHEPHERD subgraph pattern stays useful for cases where you want to drop in a new patient without schema work — relevant if we ever extend beyond one patient.
4. Supervision — a standalone primer
Supervision shows up in every ML conversation, often without anyone defining it. Here it is from first principles, then mapped to our setup.
What “supervision” means in ML
Training a neural network is just gradient descent on a loss function. The loss measures how wrong the model’s predictions are. The model adjusts its parameters in whatever direction reduces the loss.
Where does the loss come from? You need pairs of (input, target_output). The model takes an input, produces a prediction, compares it to the target, computes a loss. Across millions of these pairs, the model’s parameters drift toward reproducing the targets from the inputs.
Supervision is the source of those targets. If we have explicit labels — like “this drug worked, this didn’t” — that’s supervised learning. If we don’t, we either find another way to generate targets or do without.
Types of supervision
| Type | Where targets come from | Example in our setup |
|---|---|---|
| Supervised | Explicit human/instrument-provided labels | Maureen’s RGCC drug sensitivities (% cell death per drug) |
| Self-supervised | Derived from the input data itself | KG link prediction: “is this triple true?” — corrupt a true triple, train the model to distinguish corrupted from real. This is what PDR2 does today. |
| Weakly supervised | Noisy, partial, or proxy labels | ”Drug was prescribed” → assumes it worked. “More sources assert this edge” → assumes it’s true. |
| Semi-supervised | Small labeled + large unlabeled | RGCC’s 224 labels (112 drugs x 2 draws) + millions of KG triples |
| Contrastive / metric learning | Pairs of similar/dissimilar items | SHEPHERD’s “match this patient to her causal gene” |
| Reinforcement | Rewards over a sequence of actions | Treatment-decision policies — not where we are yet |
The PDR2 foundation training is self-supervised over the KG: it generates negative samples by corruption and asks the model to rank positives above negatives. No human labels needed. This is why PDR2 can be trained on huge KGs at all — labels for “does drug X treat disease Y” don’t exist at scale.
What supervision the PaaN architecture would add
If we put Maureen in the graph and the loss objective includes terms that involve her edges, we’d add:
- Patient-edge link prediction — “is
(maureen, sensitive_to, drug_X)a true triple given the rest of her edges?” Self-supervised in the same way as PDR2’s existing loss. Her RGCC edges supply the positives. - Drug-sensitivity regression — predict her actual % cell death given the drug. Truly supervised — direct labels.
- Treatment-outcome classification — given a drug she tried, predict the response category (CR/PR/SD/PD/intolerant). Supervised but small N.
- Auxiliary cross-source corroboration — predict “what fraction of KG sources support this edge” as a soft label. Weakly supervised.
Supervision-producing tests — what we have and what we could order
The detailed landscape lives in the supervision-tests appendix. Summary by category, with (input → output) supervision pairs called out:
| Category | What we currently have on Maureen | What we could order (with the strongest single supervision signal) |
|---|---|---|
| Genomic DNA/RNA | Caris WES + WTS (23K+ genes), 9 alterations + 176 expressions | Tempus xT/xR (second WTS for confidence); Methylation EPIC v2 → tumor classifier (95% acc, 184 subclasses); scRNA-seq → per-clone drug sensitivity (scDEAL, scPDS) |
| Liquid biopsy / MRD | None | Signatera longitudinal (Pt-specific, sens 88%) → recurrence label months ahead of imaging; Guardant Reveal → therapy response monitoring |
| Pharmacogenomics | None tracked structurally | OneOme RightMed → DPYD/UGT1A1 for 5-FU/irinotecan toxicity — Pt-specific, lifetime-valid, one-time test. Most under-used CRC-relevant supervision source we don’t have. |
| Functional drug screens | 224 RGCC values (112 drugs x 2 draws) | Patient-derived organoid (PDO) panels (OPTIC trial-validated for CRC, 2026); Travera mass-response (~80% acc, days TAT); PDX panel (slow but most-correlated with patient response — 92%/65%/61% concordance for irinotecan/bev/cetuximab) |
| Proteomics | None | Olink Explore 3072 (~3000 proteins, pre-Dx LC AUC 0.76–0.90 in UK Biobank) — orthogonal to genomic and would close a major modality gap |
| Immune profiling | RGCC immune frame markers | Adaptive immunoSEQ (TCR-β clonotype) → ICI response priors. Less relevant for MSS CRC but valuable for any ICI consideration |
| Microbiome | None | Gut metagenomics → ICI response priors. Modest signal for MSS CRC, but cheap and consumer-grade options exist |
| Imaging-derived | RECIST tracked clinically | Delta-radiomics (CT/PET features pre/post Tx) — AUC 0.77–0.89 for response; per-scan supervision |
| Longitudinal clinical | Treatment episodes, CEA, encounters | CEA delta (functionally a cheap weekly RECIST surrogate, ~10× higher temporal resolution than RECIST itself) |
| N-of-1 designs | None structured | Anti-EGFR rechallenge in RAS-WT (Maureen is RAS wild-type and is on cetuximab, so this design class does apply to her) |
| Computational | None | CMap/LINCS signature reversal — input her WTS, get a ranked list of drugs that reverse her tumor’s expression signature. Population-level priors, but uses her data directly. We have the WTS; CMap is public. |
The single-patient pitfall (the central methodological risk): a model fit to one person’s labels memorizes her, not biology. Defensive principles:
- Train on population, validate on patient. Foundation model trains on KG (population-level); Maureen’s labels are mostly used at inference and validation.
- Functional screens as labels, not features. RGCC’s 224 drug sensitivities are held-out evaluation, not training input — otherwise we overfit to RGCC’s specific assay conditions, not patient outcomes.
- Triangulate across orthogonal modalities. A drug ranked high by KG reasoning, LINCS signature reversal, and PDO screen is robust. Any single source overfits.
- Pre-register rank lists. Freeze top-30 before exposure to outcomes. Confirmation bias contaminates everything otherwise.
- Negative controls. Include drugs known to be ineffective for CRC and drugs known to be effective. If known-ineffectives score high or known-effectives score low, the model is broken.
- Calibrated uncertainty, not point predictions. Bayesian posteriors / ensembles / conformal prediction. One-patient point estimates are meaningless.
This pitfall is what shapes how RGCC and other Pt-specific supervision should be used — as evaluation and as auxiliary supervision, never as the dominant training signal.
5. PDR2’s actual mechanism (after reading the paper)
Apology in advance: I had this wrong in two earlier drafts. The paper is now read and the description below is the corrected one. The key correction: PDR2 IS already a patient-as-a-node architecture — just a minimal one. I shouldn’t have claimed otherwise.
Source: Oğuztüzün, Gao, Li, Qi, Koyutürk, Xu. Learning to take it personally: Precision drug repurposing through patient-specific loss on knowledge graphs using Biobank data. J. Biomedical Informatics 179 (2026) 105039. DOI. And the code at docs/References/PDR2/.
Stage 1 — foundation training on GP-KG with patient nodes already added
GP-KG: 61,146 entities, 1.2M relations, 7 entity types, 9 relation categories. Plus patient nodes — one per UK Biobank participant in the cohort (4,124 AD patients aged 50–65), each connected to disease nodes via a WAS_DIAGNOSED relation. About 37 patient edges per individual.
The foundation is ULTRA, 6 layers, 64-dim hidden, DistMult message passing with sum aggregation, layer normalization + residual connections. Trained 100 epochs (500 batches/epoch, batch 512) with plain BCE-with-logits over link prediction. 10 strict negatives per positive. AdamW lr=5×10⁻⁴, weight decay 10⁻⁴. (Paper §2 “Initial training of foundation model.”)
The patient edges (WAS_DIAGNOSED) are part of the training KG — the model learns embeddings for patients alongside everything else. So the patient IS a node, with edges, from the start.
What’s NOT in the graph: PRS values, biomarker expression values. Those are “external inputs to the patient-specific loss function.” (Paper §2.)
Stage 2 — per-patient fine-tuning with the personalized loss
For each of the 4,124 patients (or in the case studies, three representatives — Robin, Zoro, Usopp), a separate fine-tune run.
Foundation is frozen (all 168,705 model parameters). Only 1,802 learnable weights inside the loss are trained — 341 disease weights (one per PRS-aligned disease in GP-KG) + 1,461 protein weights (one per UK Biobank-aligned protein in GP-KG). 93.6× reduction in trainable parameters vs foundation.
The personalized loss (Paper §2, Eq. 1):
L = L_pred − λ₁·L_prs − λ₂·L_expr
L_prs = Σᵢ (wᵢ · PRSᵢ · s_pred) for each disease i
L_expr = Σⱼ (vⱼ · (expr_j − ref_j) · s_pred) for each protein j
Where:
L_predis standard BCE link prediction loss on the batchs_predis the predicted score for the current triple being scored in the batch — any triple, not just patient tripleswᵢ,vⱼare the learnable per-disease and per-protein weights (this is what fine-tuning trains)PRSᵢ,(expr_j − ref_j)are the patient’s fixed feature values- The minus signs are because the goal is to maximize the influence of high PRS values and biomarker deviations on relevant drug scores
So for each triple in the batch, the loss term effectively says: “multiply this triple’s predicted score by a patient-specific scalar that’s a weighted sum of PRS and biomarker deviations, with weights w and v learning which diseases/proteins matter for this patient’s drug ranking.”
Fine-tuning: 3 epochs, 100 batches/epoch, AdamW lr=10⁻⁴. Patient edges (~37 total) get a 90/10 train/validation split; the biomedical KG split is unchanged across patients. The test set is the KG-only test split — to verify fine-tuning preserves general knowledge.
Reported results (Paper Table 1)
| Patient | Best λ | Baseline AUPRC (no ploss) | AUPRC with ploss | Lift |
|---|---|---|---|---|
| Robin | (0.1, 0.1) | 0.076 | 0.251 | 3.3× |
| Zoro | (0.5, 0.1) | 0.277 | 0.368 | 1.3× |
| Usopp | (0.5, 0.1) | 0.065 | 0.353 | 5.4× |
MRR, Hits@1/3/10 stay essentially unchanged across rows (the relation-aware filter limits these metrics). AUPRC is computed under the global / broader candidate pool — that’s where the personalization shows.
Validation is by literature review only — no patient-level gold standard. Three patients × top-3 drug candidates each = 9 drugs PubMed-checked for AD-relevant mechanism and patient-profile alignment. One notable independent win: PDR2 predicted lithium as a top candidate for Usopp (high bipolar PRS); a Nature 2025 paper (Aron et al., ref [51]) independently validated lithium deficiency as an AD pathogenesis mechanism after PDR2’s experiments completed. That’s a real “predicted something the field hadn’t yet established” outcome.
What this means for our PaaN ambition (the corrected version)
I was wrong twice over:
- Wrong: “PDR2 isn’t patient-as-a-node.” Correction: it is. Patient nodes with
WAS_DIAGNOSEDedges enter the graph from foundation training onward. - Wrong: “The personalized loss exists but isn’t used.” Correction: it is used, in a separately-invoked per-patient fine-tune script (
--use_ploss). - Right: the foundation is frozen during fine-tune; only the loss’s 1,802 weights update.
So our PaaN ambition isn’t “introduce patient as a node,” it’s “make the patient a richer node than PDR2’s”:
- PDR2: ~37
WAS_DIAGNOSEDedges only. PRS + biomarkers enter the loss as scalars, not as graph structure. - Our proposed PaaN:
WAS_DIAGNOSED(have it) pluscarries_variant(we have data, PDR2 didn’t),over_expresses/under_expresses(we have, PDR2 used as loss feature only),tried_drug(we have with outcomes),sensitive_to_drug/resistant_to_drug(we have from RGCC — PDR2 didn’t have anything like this),allergic_to(we have). - Variant data + assayed drug sensitivities are the two big additions. The first is a structural enrichment of the graph (variant-level paths instead of gene-level). The second is a completely new supervision signal that PDR2 didn’t have access to.
Three architectural moves beyond PDR2
In rough order of difficulty:
Move 1 (cheapest): More patient edges, same loss mechanism. Add the richer edge types to Maureen’s node before training. Foundation pre-trains with them; per-patient fine-tune still freezes foundation and trains the 1,802 loss weights. Tests whether the richer graph structure alone moves AUPRC.
Move 2 (medium): Unfreeze patient-related parameters during fine-tune. Instead of freezing all 168K foundation parameters, unfreeze the embeddings of patient + patient-1-hop entities. Now her node’s embedding can move during fine-tune; the rest of the graph stays put. This is closer to what your “every backfill biased toward Maureen” framing actually requires.
Move 3 (hardest): Multi-task loss with patient-specific supervision. Extend the loss with explicit (drug, response, patient) terms tied to RGCC sensitivities. Now we have labeled supervision from RGCC, not just PRS-modulated unlabeled scoring. The patient becomes a real training signal, not just a feature for reweighting.
These compose: Move 1 + Move 2 + Move 3 is the “Maureen-anchored richer graph with labeled supervision and learnable patient embedding” architecture from §6.
The experiment to run first (much cheaper now we understand it)
We have the foundation checkpoint already (from prior PDR2 runs on GP-KG and PrimeKG). For the minimum reproduction-and-extension:
- Build a
KG_ZORO-style fine-tune dataset for Maureen — her diagnosis edges asWAS_DIAGNOSEDtriples to GP-KG / PrimeKG disease nodes (a few of these), train/validation split. - Compute her PRS values for the 341 GP-KG-aligned diseases (from germline VCF + GWAS sumstats; ~half a day).
- Pull her biomarker / expression deviations for the 1,461 GP-KG-aligned proteins from
ModsGeneExpression(already structured). - Run
python script/run.py -c config/transductive/inference.yaml --patient_id maureen --dataset <our_dataset> --use_ploss -l1 0.1 -l2 0.1 --ckpt <foundation_ckpt>. - Measure: full-ranking AUPRC on drug-treats-disease pairs; Spearman ρ between the model’s drug ranking for Maureen’s CRC and her RGCC drug sensitivities; convergence of the 1,802 weights to see which diseases/proteins the loss elevates.
This is direct reproduction of PDR2’s method on Maureen. It’s the right baseline before designing anything beyond it. Cost: ~1 day setup + a few hours of fine-tune compute.
5a. Population-supervised KG skeleton — a different way to use patient data
This section has been fleshed out into its own doc: population_supervised_outcome_planning.md.
That doc covers: (1) the SHEPHERD lift and why synthetic patients don’t transfer to therapeutic supervision (proxy patients do); (2) patient cohorts as standard supervised-ML training data, with loss-function options and the patient-of-1 validation problem; (3) the data-source unification table; (4) calibration and scale — z-scaling, quantile normalization, linker drugs, single-source-first, ensembles (with the Haibe-Kains 2013 receipt for why this is harder than it looks); (5) a two-track architecture recommendation (PDR2/ULTRA for KG path reasoning + bi-encoder regression for cell-line outcome prediction); (6) gotchas; (7) a recommended MVP — GDSC v2 + bi-encoder + Maureen’s RGCC as held-out validation.
The reframe (population tapestry, Maureen as query in learned geometry, three implementation options a/b/c) and the five open questions originally drafted here are absorbed and extended in that doc.
6. The “patient as anchor in training” mechanism
You described it semantically as: “every training calculation should be in service of pushing the result closer to ‘this works with what we know about Maureen’ than away from it.” We agreed to test both of the two concrete mechanisms below, plus stay open to new patterns.
This is the §5 “Move 2 / Move 3” beyond PDR2’s mechanism: PDR2’s foundation is frozen during fine-tune, so the patient embedding never moves and the loss’s only learnable parameters are scalar reweighting coefficients. The mechanisms below are about how to make the model itself — not just the reranker — respond to the patient.
Option A — Auxiliary loss term weighting Maureen’s edges heavily
L_total = L_KG_link_prediction + λ_patient · L_patient_edges
- Every batch samples some standard KG triples (whole-graph link prediction) and also samples Maureen’s edges as positives.
L_patient_edgescould be: link prediction on her edges (same BCE form, just over her sub-edges), MSE on her drug sensitivities, multi-task combination.λ_patientis the dial — high = the whole graph’s geometry gets dragged to keep her facts well-fit; low = her edges are just one signal among many.- Every gradient step “knows about Maureen” because some fraction of the batch is her.
Pros: minimally invasive. Standard architecture, standard optimizer. Closest in spirit to what PDR2’s PersonalizedRepurposingLoss was reaching for. Easy to ablate (set λ_patient = 0 and compare).
Cons: she’s still one node among hundreds of thousands. Her gradient signal washes out unless λ_patient is large, and large risks pulling the whole graph toward her idiosyncrasies (over-personalization, loss of generalization).
Option B — Patient-conditional message passing
The GNN’s message-passing at every layer is modulated by Maureen’s embedding. Concretely, several patterns:
- Attention conditioning: attention weights over neighbors are a function of
(source_emb, target_emb, patient_emb). Edges that are more relevant to her get heavier weight. - Gated message passing: each message gets multiplied by a gating function of the patient embedding. Edges “irrelevant to Maureen” decay.
- Hypernetwork: a small network takes the patient embedding and outputs the GNN’s weights themselves. The model is literally a different model for each patient.
Pros: architecturally elegant. Matches the “her node bends every computation” intuition. TxGNN does something analogous for relations (relation-conditional message passing) and gets ~30% lift on rare diseases.
Cons: more parameters, more training instability, more compute. Patient-conditional everything is heavy. And: with one patient, we can’t disentangle “good architecture” from “got lucky on this specific patient.”
Option C — Patient as central hub of training sampling
Bias the training sampler so most batches include triples in her 2-hop neighborhood. The model spends most of its capacity on her region of the graph; the rest is loosely fit. Conceptually closer to “fine-tune on her subgraph” than “rebuild the architecture.”
This is what Phase F.7 sketches. Less ambitious than A or B but probably the cheapest way to get a measurable lift on her specifically.
How we’d decide
Test plan if we ever build:
| Run | Architecture | Loss | Sampling | Compare to |
|---|---|---|---|---|
| Baseline | Standard ULTRA on Composition | BCE | Uniform | — |
| Personalized loss only | Standard ULTRA on Composition | BCE + personalized loss | Uniform | Baseline (does PDR2’s own mechanism help?) |
| Maureen-anchored (Option A) | Standard ULTRA on Composition + Maureen | BCE + λ·patient-edge loss | Uniform | Baseline (does adding her node help?) |
| Maureen-anchored + biased sampling (Option C) | Standard ULTRA on Composition + Maureen | Same as A | 50% Maureen-neighborhood | Option A (does sampling matter?) |
| Patient-conditional (Option B) | Patient-conditional ULTRA | Same as A | Uniform | Option A (does architecture matter?) |
Five runs. Each gets the same eval: full-ranking MRR + Spearman ρ vs RGCC. We’d run on whatever Composition is current (probably tier1_mvp_with_primekg_v1 after CIViC/OncoKB/PharmGKB ingest).
Once one of A/B/C/PersonalizedLoss demonstrably wins, we expand on it. Until then, designing further is overcommitting.
7. What we have + what the architecture should support
Reframing from the earlier draft: the right question isn’t “what supervision should we order before committing to an architecture?” It’s “what supervision should the architecture be able to support, so we can start small with what we have and add new tests over time?”
V1 won’t have everything. We start with current data, get something working, then expand as new tests come in. Retraining is acceptable for major data additions; fine-tuning is preferred for incremental additions. The architectural commitment is to a graph schema and loss design flexible enough that new edge types and supervision signals plug in without re-architecting.
What that means concretely:
- Edge schema needs to be extensible — adding a new edge type (e.g.,
methylation_classorpdo_sensitivity) shouldn’t require schema migration of every patient - Loss needs to be extensible — adding a new auxiliary supervision term shouldn’t require rewriting existing terms
- The patient node needs feature slots that accept multi-modal additions (gene expression today; proteomics, methylation, radiomics later)
- Inductive scoring path needs to handle new edge types without retraining (NBFNet-style message passing handles this well)
Below is the floor (what we have) and the ceiling (what we’d want the architecture to support, eventually). The architecture should make the path between them additive, not migration-heavy.
Currently in MODS (floor)
| Source | Count | Type | PDR2 has? |
|---|---|---|---|
| Diagnosis history | Variable | Conditions → WAS_DIAGNOSED edges | yes (their ~37 edges per patient is exactly this) |
| Genomic alterations (Caris + Invitae + Guardant) | 9 | HGVS, VAF, ClinVar interpretation, germline/somatic | no — PDR2 has only PRS, not variants |
| Gene expressions (Caris WTS) | 176 | tpm-percentile, regulation classification, CMS1-cohort-normalized | partial — PDR2 uses biomarker expressions as loss features (1,461 proteins) but not as graph nodes/edges |
| Therapy associations | 19 | Biomarker→drug, evidence level L1–L3 | no |
| Resistance factors (RGCC) | 16 | MDR1, MRP1, GSTP1, ERCC1, TYMS, DHFR — % expression | no |
| CTC profiles (RGCC OncoTrace) | 7 | CTC count, phenotype markers | no |
| Drug sensitivities (RGCC) | 224 (112 drugs x 2 draws) | % apoptosis at fixed [drug] — direct labels, 1% integer granularity (we verified — rgcc_parser.py:175 stores raw integer percent, with a separate band classification at 35%/80%; raw value is preserved) | no — PDR2 had no per-patient drug response labels at all, only PubMed-review validation |
| Biomarker trajectories | Variable | CEA, LDH, albumin, lymphocytes — Phase 13 trajectory features | no — PDR2 uses static biomarker values, no time series |
| Treatment episodes | Variable | Regimen, dates, RECIST outcome, toxicity | no |
| EHR (Kaiser FHIR) | 300+ | Encounters, conditions, meds, allergies, immunizations | no — PDR2 uses ICD-10 diagnoses only |
| PRS values | None yet — computable from her germline VCF + public GWAS sumstats | Polygenic risk scores per disease | yes (UK Biobank PRSs for their 4,124 patients) |
Worth acquiring next (in priority order)
Each row below produces supervision signals that the current set lacks. Costs and TATs are rough.
| Priority | Acquisition | Why it matters | Supervision signal it adds |
|---|---|---|---|
| 1 | PGx panel (OneOme RightMed or Caris PGx) | UGT1A1 for irinotecan dose, DPYD for 5-FU/cape. Lifetime-valid, one-time. Pt-specific toxicity label. | (genotype → toxicity-risk class) Pt direct |
| 2 | Compute PRS for Maureen from her existing germline data | Required input to PDR2’s PersonalizedRepurposingLoss experiment; ~free if we have her VCF | (PRS values, used by personalized loss as features) |
| 3 | Methylation EPIC v2 (with classifier) | Heidelberg-style tumor classifier (95% acc, 184 subclasses) gives biological-atypia label that often correlates with non-standard response | (methylome → tumor class) Pop label, gives orthogonal supervision |
| 4 | PDO panel (if a US commercial vendor / OPTIC slot can be arranged) | OPTIC trial-validated for CRC; produces 50–500 (drug → IC50/AUC) labels per biopsy — the only single-patient large-N signal | (drug → IC50) Pt direct at scale |
| 5 | Signatera or Guardant Reveal MRD | Longitudinal recurrence label months ahead of imaging; converts a static problem into a temporal one | (ctDNA dynamics → recurrence/response) Pt L |
| 6 | Olink Explore 3072 proteomics | Orthogonal modality to genomic; closes “what’s actually expressed at protein level” gap | (proteome → outcome) Pop priors + Pt L |
| 7 | Single-cell RNA + scATAC on a biopsy | Per-clone drug sensitivity via scDEAL/scPDS — addresses resistance via subclonal mechanisms | (clone → drug sensitivity) Pop methods, Pt clones |
| 8 | Delta-radiomics (from existing CT/PET DICOM) | Re-extract features from her scans; cheap because the imaging already exists | (radiomic vector + delta → response) Pop + Pt L |
| 9 | Compute CMap/LINCS signature reversal from her Caris WTS | Free / open-source, no new test needed | (tumor signature → drug-reversal ranking) Pop priors |
| 10 | TCR-β immunoSEQ | TCR clonal expansion as immune-response label; less load-bearing for MSS CRC | (TCR clonality → ICI response) Pop priors + Pt L |
Items 1, 2, 8, 9 are all near-zero cost: 1 is a routine PGx test, 2 needs only her VCF + open-source PRS tools, 8 reuses existing scans, 9 is computational on data we already have. They should be done before any PaaN MVP, because they all change what supervision the loss can use.
Items 3, 5, 6 are mid-cost premium tests with strong supervision payoff.
Item 4 (PDO) is the single highest-payoff acquisition because it generates dozens to hundreds of patient-specific drug labels from one biopsy. But it’s the hardest to obtain logistically.
8. Literature: where others have wandered (with SHEPHERD deep-dive)
Cluster A — Literal patient-as-a-node architectures
- SHEPHERD (npj Digital Medicine 2025, Zitnik Lab). Closest prior art; same lab as TxGNN. Deep-dive in §8a below.
- GraphCare (arXiv:2305.12788, ICLR 2024) — per-patient KG built by merging LLM-extracted concept-specific subgraphs from biomedical KGs; bi-attention GNN for MIMIC outcome prediction.
- Patient-centric mutation KG for anti-cancer targeting (bioRxiv 2024.09.29.615658) — PPI + patient-centric mutation network + transcriptomics + drug response. Most oncology-aligned paper found (abstract only — bioRxiv returned 403).
- Person-Centric KG ablation (arXiv:2408.15294, 2024) — explicit per-admission patient node, demographic/clinical/social edges, MIMIC ablation.
- RGCN-with-literals for temporal patient pathways (arXiv:2502.21138, 2025) — literal patient nodes with literal-valued features.
Cluster B — KG drug repurposing without the patient
TxGNN (Nat Med 2024), DREAMwalk (Nat Comm 2023), Decagon, BioPathNet, K-Paths, MLAN, GDRnet — all population-level. None model the patient. This is the cleanest gap.
Cluster C — Adjacent fields
- Causal ITE on graphs (TARNet+CGC, CauGramer, DCHGNN, van der Schaar lab) — graph-structured covariates for treatment effects, doesn’t ingest biomedical KGs.
- EHR-KG (Frontiers PCKG survey 2024, MedGCN, Mendel.ai) — patient-centric KGs for clinical outcome prediction, not repurposing.
- Rare disease subgraph methods (PhenoKG, RareNet, RareAgent — all 2025) — diagnostic reasoning, not therapy ranking.
- Patient digital twins (Nat Rev Cancer 2025) — mechanistic ODE/PDE, not graph-based.
White space
No published paper combines all of:
- Patient as a node in a PrimeKG-class biomedical KG
- Multi-omic patient edges (variants + expression + treatment + functional sensitivities)
- Patient-specific supervision (assayed drug response as labels)
- KG link-prediction backbone for repurposing
That’s our specific differentiator. SHEPHERD has 1 (phenotype-only); the bioRxiv mutation paper has 2+3 (no phenotype/treatment integration, no inductive reasoner); none combine all four.
8a. SHEPHERD deep-read
Sources: npj Digital Medicine 2025, Zitnik Lab project page, GitHub: mims-harvard/SHEPHERD, medRxiv preprint. The Nature link returned a 303 from WebFetch — mechanistic details below come from the project page, GitHub README, and search snippets. Read the PDF before basing any architecture decision on these claims.
What it is. SHEPHERD is diagnostic, not therapeutic. Three tasks, all phenotype-driven:
- Causal gene discovery — given patient phenotypes + candidate genes, rank genes (true causal gene at avg rank 3.52 across 465 real UDN patients).
- Patients-like-me retrieval.
- Novel disease characterization.
It does not model drug repurposing. There are no drug nodes in its KG and no therapy-ranking objective.
Architecture.
- Backbone: geometric deep learning over a rare-disease KG (“knowledge-grounded metric learning”). PyTorch + PyTorch Geometric. The README doesn’t specify which GNN flavor; the paper’s methods section would.
- Patient encoding: each patient = a set of HPO terms + optional candidate Ensembl gene IDs. The phenotypes define a subgraph in the KG; the model embeds the patient by aggregating over that subgraph. This is patient-as-subgraph, not patient-as-explicit-node.
- KG: a custom rare-disease KG hosted on Harvard Dataverse, smaller than PrimeKG.
- Training: ~40K simulated patients across 2,134 diseases. Evaluated on 465 real UDN patients.
- Loss: metric learning framing — pull matched (patient embedding, causal gene embedding) together, push non-matches apart. Likely contrastive/triplet.
- Inductive over patients: trained on simulated, deployed on real. A new patient is scored at inference without retraining.
What’s transferable to a PaaN-for-repurposing design
- A patient is meaningfully embedded into a biomedical KG, and that embedding drives ranking — same general shape as ours.
- Inductive scoring on novel patients — exactly the capability we’d need if we don’t want to retrain when Maureen’s data updates.
- Same KG family as TxGNN/PrimeKG — tooling is compatible.
What doesn’t transfer
- Diagnostic, not therapeutic. No drug-repurposing supervision signal.
- Phenotype-only patient. Our patient has variants, expression, treatments, CTC profiles, drug sensitivities — none of which SHEPHERD shows how to combine.
- Simulated-patient training. SHEPHERD scales by training on 40K synthetic patients. We have one real patient and no way to simulate “Maureen-like” synthetic patients without losing what makes her useful as a single instance. We have to find a different way to inject patient-specific supervision.
- Metric learning vs link prediction. SHEPHERD’s contrastive objective fits retrieval; ours fits ranking. Different loss surface.
Net. SHEPHERD validates the idea that patients can be embedded into a biomedical KG and the embedding can drive useful downstream tasks. It does not give us the exact mechanism. The Maureen-anchored architectures in §6 are what we need to design, and they look more like PDR2 + patient edges + patient loss than like SHEPHERD.
9. If we wanted to build — the staged path (revised, not yet committed)
Three scenarios, in order of ambition. We’re not committing to any of them yet, but here’s what each would entail given the constraints you’ve added.
Scenario X (cheapest, do-anytime): direct PDR2 reproduction on Maureen
After reading the paper (§5), this is well-specified. PDR2 already exposes a CLI flag (--use_ploss) for the per-patient fine-tune. The foundation model is frozen; only 1,802 weights inside the loss train.
Steps:
- Add Maureen as a patient node in the chosen Composition’s training graph, with
WAS_DIAGNOSEDedges to her diseases (~5–10 edges; far fewer than PDR2’s UK Biobank average of 37 because she’s one patient with limited diagnosis breadth). - Re-run foundation training on (Composition + Maureen’s diagnosis edges) — this is needed because PDR2’s foundation included patient nodes from epoch 1. If we already have a foundation trained without Maureen’s node, we can skip this and just attempt fine-tune on the frozen one (the patient embedding will be random, which is the closest PDR2 analog).
- Compute PRS for Maureen from her germline VCF + public GWAS sumstats (~half a day if Invitae export available). Filter to PRSs whose disease CURIE is in the Composition.
- Pull her expression deviations for the proteins/genes in the Composition from
ModsGeneExpression(already structured; ~176 values). - Run
python script/run.py -c config/transductive/inference.yaml --patient_id maureen --dataset <maureen-zoro> --use_ploss -l1 0.1 -l2 0.1 --ckpt <foundation_ckpt>(using PDR2’s reported optimum (0.1, 0.1) for the case patient with lowest baseline AUPRC). - Measure: AUPRC on KG link prediction; Spearman ρ between the model’s drug ranking for her CRC and her RGCC drug sensitivities; convergence of the 1,802 weights to see which diseases/proteins are upweighted.
- ~1 day setup + a few hours of fine-tune compute.
Tells us whether PDR2’s exact mechanism transfers to Maureen and what the AUPRC and RGCC-ρ baseline numbers are. Any architecture in §6 that goes beyond PDR2’s mechanism (Move 2 or 3) needs to clear those bars. Useful baseline to publish against either way.
Scenario Y (MVP, if we decide to build): “Maureen as a node, attached to current Composition”
Bundled scope:
- Phase 8.5 (variant nodes) — CIViC/OncoKB/PharmGKB ingest, since you noted variants are critical for MVP.
- Phase F.1–F.2 (anchor resolver + storage) — needed to translate her medical record into canonical CURIEs.
- Phase 13 Tier 1 (trajectory features as static attributes on her node).
- Phase 12.0 (the actual node + edges):
- Add
patienttomods_kg_entity(just an entity_type — no separate table, no join). Maureen gets a row keyed by canonical CURIE. - Materialize her edges:
has_disease,carries_variant(after 8.5),over/under_expresses_gene,tried_drug(with outcome attribute),sensitive_to_drug/resistant_to_drug(from RGCC),allergic_to, plus Tier 1 trajectory features as node attributes. - Store her
mods_kg_entity.idonModsPatientfor the back-pointer (no join table). - Browsable in the KG Composition tab next to compositions — same UI, same interaction patterns.
- Add
- Foundation training is back on the table. Two training architectures to test:
- Option A: standard ULTRA + auxiliary loss term weighting her edges
- Option B: patient-conditional message passing (relation- and patient-conditional)
- Validate against RGCC ρ (held-out), held-out-recent-months trajectory, clinician sanity-check on top-10 drugs.
Time estimate revised. With Phase 8.5 bundled (~3 weeks based on Phase F doc + connector ingest), Phase F.1–F.2 (~1.5 days), Phase 13 Tier 1 (~2 days), Phase 12.0 schema + ETL (~1 week), Option A foundation retrain (~1 week) — realistically 5–7 weeks, not 1–2. The 1–2-week framing in the earlier draft assumed no retraining and no variants; with both included, it’s bigger.
Scenario Z (full ambition): co-developed patient + KG geometry, with population tapestry
- The Composition includes population sources (§5a): GDSC, CCLE, DepMap, LINCS, TCGA, PDXNet, GENIE — each ingested as a
mods_kg_source. Each contributes thousands of patient/cell-line nodes withgenome_alteration,sensitive_to,resistant_to,treated_with → outcomeedges. - Maureen’s node and her edges are added to the same graph; she’s one node among thousands of “patient-like” entities.
- The foundation model trains on the population-tapestry composition from epoch 1. The §6 anchor-loss patterns (A/B/C) determine how the patient-edge supervision enters the loss — per-batch sampling can rotate which patient is “anchored” to prevent overfit to any one.
- Both auxiliary-loss (Option A) and patient-conditional message passing (Option B) are tested; whichever wins is expanded on.
- Phase 13 Tier 4 (temporal encoder) feeds Maureen’s node feature vector — her node updates as her trajectory evolves.
- New patients can be added by adding new rows to
mods_kg_entitywith their edges; inductive scoring via NBFNet handles them at inference without retraining. - Supervision sources expand per §7: PGx, PRS, possibly PDO/Olink/Methylation added as additional edges and auxiliary loss terms.
This is the “data structure that understands Maureen’s disease in the most granular way possible, attachable to new data sources as we find them” you described. The population tapestry is what gives it enough signal to be more than a one-patient overfit. It’s a real research project — months to years, with substantial risk of dead ends.
What “imperfect but working prototype” means under each scenario
- Scenario X is the imperfect prototype for whether PDR2’s loss buys anything. Doesn’t depend on PaaN at all. Cheapest learning per day.
- Scenario Y is the imperfect prototype for PaaN as an architecture — proves the schema, the loss patterns, the validation pipeline, and gives us a measurement.
- Scenario Z is the production target. Not an MVP.
If we ever commit to building, my recommendation would be X first, then Y if X is encouraging, then Z if Y validates. Each scenario’s failure pattern teaches us something different.
10. Open questions (updated)
- Composition target. Which Composition is the right one to attach Maureen to?
tier1_mvp_with_primekg_v1after variant connectors ingest is the obvious candidate, butprimekg_baseline_v1(already ingested) lets us measure earlier. Trade-off: latest-and-greatest vs measurable-now. - Foundation retraining cost. Each training run is ~1 H100-day. Five runs (§6’s test plan) = 5 H100-days = real money. Worth it once the architecture is locked, premature before.
- PRS computation pipeline. Needs her germline VCF (Invitae provides this; need to confirm export availability) + a GWAS sumstats source + PRS tool. Not blocked by anything except the work itself. Probably half a day.
- PDO acquisition. Highest-payoff data acquisition (§7 item 4), but logistics (vendor selection, biopsy timing, insurance) are real. Worth scoping before relying on it.
- Multi-patient generalization design. “I’d like to be able to browse Maureen’s node the same way we browse our KGs” implies a generalized UI pattern. Already supported by the existing KG Composition tab if Maureen is just another entity. But if we ever add a second patient, do we want a
mods_patient_setthat groups them, or are they justentity_type='patient'rows? - PDR2 paper — now read. Resolved. §5 is corrected. Key findings: patient IS already a node (
WAS_DIAGNOSEDedges); fine-tune freezes foundation and trains only 1,802 loss weights; reported AUPRC lift 1.3–5.4× across the three case patients; validation by literature only (no patient-level gold standard like our RGCC). Limitations they note: cohort of 3 patients for case studies (4,124 in principle); single disease (AD); no automated per-patient λ adaptation; multi-modal extensions and longitudinal data are future work. - Does the population-tapestry direction (§5a) shift priorities in §7? If we go Scenario Z (population tapestry), the priority for ordering Maureen-specific tests changes — the highest-value acquisitions become ones that integrate with the public population data (e.g., Tempus xT uses the same genome reference as TCGA; methylation EPIC v2 aligns with TCGA methylation). Worth thinking about acquisition order in light of which other patient data we’d be training against.
- Closure criterion for MVP — you said “net positive energy output,” i.e., any measurable improvement counts. ρ improvement on RGCC is the cleanest single signal. Worth pinning down whether we need just RGCC improvement, or also concordance with clinician-curated top-10, or also held-out-recent-months.
TL;DR
- Important correction: PDR2 IS already a patient-as-a-node architecture. I had this wrong in earlier drafts. Each UK Biobank patient enters the graph as a node with ~37
WAS_DIAGNOSEDedges. The foundation model trains on the augmented graph. Then for each patient, fine-tune freezes the foundation and trains only 1,802 weights inside the loss (341 per-disease + 1,461 per-protein) — these weights learn which diseases/proteins matter for the patient’s drug ranking. AUPRC lifts 1.3–5.4× across the three reported case patients (Robin, Zoro, Usopp); MRR stays unchanged. Validation is literature-review only. Lithium prediction for Usopp was independently validated by a Nature 2025 paper after PDR2’s experiments completed — a real “predicted before the field knew” win. - Our white space isn’t “introduce a patient node” — PDR2 already does that. Our white space is richer patient edges (variants, gene expression as graph structure not just loss features, treatment outcomes, drug sensitivities) + labeled per-patient supervision from RGCC and similar functional assays. PDR2 has zero patient-level outcome labels; we have 224.
- Three architectural moves beyond PDR2 (§5, end): (1) richer patient edges, same frozen-foundation loss mechanism; (2) unfreeze patient-1-hop embeddings during fine-tune so her node embedding actually moves; (3) multi-task loss with RGCC sensitivities as labeled supervision. They compose; we should test the cheapest one first.
- The first experiment to run is direct PDR2 reproduction on Maureen (§9 Scenario X): build a
KG_ZORO-style fine-tune dataset, compute her PRS, run--use_ploss. Establishes the PDR2-mechanism baseline on her data. ~1 day setup. Doesn’t require any architectural innovation. - Population tapestry (§5a) is a meaningfully different direction. Train the foundation on granular per-patient outcomes from many patients/cell lines (GDSC, CCLE, DepMap, LINCS, TCGA, PDXNet, GENIE, PDO consortia) — Maureen becomes one query point in a learned geometry, not the sole anchor. Composes with the Maureen-anchored architecture, doesn’t replace it.
- Compositions reframe the design. Maureen is an overlay attachable to any Composition (current options: GP-KG, PrimeKG, future ones include CIViC/OncoKB/PharmGKB after Phase 8.5 ingest). She becomes a first-class entity (
entity_type='patient') browsable next to compositions. Schema: simple — node ID onModsPatient, no join table. - Variants mandatory for MVP (Phase 8.5 bundled). Tier 1 trajectory features bundled too.
- Supervision matters more than the architecture until we have orthogonal sources. RGCC is the floor (and confirmed-continuous-1%-granularity, not 20% bands — your concern was reasonable but the data is finer-grained than that). PGx, PRS, CMap/LINCS reversal, methylation, PDO, Olink — every additional source closes a different supervision gap.
- Recommended next concrete step: spawn a new planning session for “Create Maureen’s Patient Entity node + edges, expose in KG browser.” This is Scenario Y’s first deliverable, stripped of any training-architecture commitment. It gives us a browsable patient subgraph in the existing KG Composition tab UI, forces us to make the schema decisions in §10 Q1–Q2, and produces an artifact that’s immediately useful for inspection. The training-architecture question (X → Y → Z, in that order) follows after we have a stable patient-node data substrate. The new planning session should reference this thinking doc and pick up from §9 Scenario Y’s schema and ETL details.
Parallelization Analysis (if we ever execute)
Surfaces touched per scenario:
| Surface | Scenario X | Scenario Y |
|---|---|---|
| Backend API | No | Yes (Maureen as KG entity in browsing API) |
| Frontend component | No | Yes (new “Patient” card in KG Composition tab, or extension of existing) |
| Worker handler | Maybe (training run dispatch) | Yes (training run, anchor resolution, possibly PRS compute) |
Migration (backend/migrations.py) | No | Yes (Phase 8.5 + Phase F.2 + nodeID column on ModsPatient) |
| MCP tool | Maybe | Yes (mods_kg_get_patient_node, etc.) |
| DB-stored config | No | No |
| Docs | Brief writeup | Phase 12.0 writeup |
| Tests | Yes (run-level integration) | Yes (schema + materialization + training-run integration) |
Parallel split (Scenario Y):
- Phase 8.5 variant ingest, Phase F.1–F.2 anchor service, and Phase 13 Tier 1 trajectory features can all happen in parallel — they touch different services and tables.
- The Phase 12.0 schema (entity_type=‘patient’, new edges) must land before the training-architecture experiments — serial dependency.
- Within training, Options A/B/C runs are fully parallel (each is an independent H100 job).
- Frontend KG Composition tab update for “patient as browsable entity” can run in parallel with backend schema once API contract is defined.
Collision hotspots:
backend/migrations.py— Phase 8.5 + Phase F.2 + Phase 12.0 schema each add a migration. Coordinate migration numbers; batch the work to one session if possible.backend/mcp_servers/mods_server.py— both Phase F and Phase 12.0 add MCP tools. Single-session preferred to avoid merge drift.frontend/src/components/ModsKGCompositionTab.jsx— Phase F.4 (anchor inspection sub-tab) and Phase 12.0 (patient as entity card) both touch this file. Sequence them.- Cloud SQL load — variant connectors ingest is multi-GB; coordinate timing with any other large migrations.
Verify-how per surface:
- Schema migration:
column_exists/table_existsguards verified by running migration twice; finalpsqlcount audit. - Backend API: pytest with a fixture patient (Maureen-like synthetic).
- Frontend:
preview_*walkthrough of the KG Composition tab with Maureen visible as a card; click to expand should show resolved CURIEs, edge breakdown, 1-hop neighborhood. - MCP tool: invoke from a
claudeterminal session, verify output shape. - Training run: Spearman ρ on RGCC against the existing Phase 7.5 validation harness (Run B baseline = ρ 0.351 on PrimeKG — ⚠ superseded pending restatement, GH #324; re-run per timepoint before using as a comparator).
- Personalized-loss experiment: side-by-side MRR + ρ comparison against the current PDR2 baseline.