Motivation
Multi-antigen vaccine constructs (peptide or mRNA) can present non-mutant self-peptides to the patient's MHC. Three failure modes are currently unmodeled in vaxrank:
-
Off-target self-peptide presentation inside SLP windows. A 25-mer SLP that flanks a mutation can still slide MHC-I/II k-mers across non-mutant regions. Those k-mers are wild-type and won't drive a tumor-specific response — they dilute the immune response and waste vaccine dose. Today vaxrank ranks windows only by mutant-epitope binding; it never scores the interior of the window for non-mutant binders.
-
Self-cross-reactivity within ±1 aa. A window may produce a k-mer that differs by ≤1 aa from a strongly-presenting self-peptide. Those neoantigens carry autoimmunity risk: the responding T-cell clone may also recognize the wild-type self-peptide on healthy tissue.
-
Tissue-aware autoimmunity safety. When self-cross-reactivity is unavoidable, prefer windows whose source proteins are not highly expressed in essential tissues (heart, brain, liver, kidney, lung, pancreas, gut epithelium). Even if some autoimmunity is triggered, hitting a less-essential tissue is far safer.
This issue tracks a safety module that scores candidate vaccine windows on those three axes and uses the scores as ranking tie-breakers (or, optionally, hard filters).
Scope
A. Self-peptide presentation scoring
For each candidate SLP window:
- Slide MHC-I (8-11) and MHC-II (13-25) k-mers across the non-mutant residues only.
- Score each k-mer with the configured presentation predictor (mhcflurry-presentation by default).
- Drop k-mers that already appear in a configurable reference proteome (already-tolerated; not new presentation).
- Aggregate per window: `self_strong_count` (rank ≤ 0.5%), `self_mild_count` (rank ≤ 2.0%), `worst_self_rank`.
The reference proteome should be pluggable: default to the patient's matched reference (already in vaxrank), but allow users to substitute a custom k-mer index (e.g. tumor-cell-line proteome, restricted self-proteome, or species-specific for non-human work).
B. Self-cross-reactivity (within ±1 aa)
For each mutant epitope produced by a window:
- Look up all reference-proteome peptides within Hamming distance 1.
- If any has a strong predicted presentation rank (configurable threshold, default rank ≤ 0.5%), flag the epitope as `autoimmune_risk`.
- Aggregate to a window-level `autoimmune_risk_count`.
C. Tissue-expression-aware safety penalty
When at least one autoimmune-risk hit fires for a candidate window, weight it against tissue expression:
- Look up the source gene's expression across essential tissues (GTEx is the standard source — bundle a small `gtex_essential_tissue_tpm.tsv` or query a configurable URL/file).
- `autoimmune_risk_score = autoimmune_risk_count × max_tpm_in_essential_tissue`.
- Use as a tie-breaker (or a configurable weighted term in the combined score) to prefer:
- windows with zero autoimmune-risk hits, then
- windows whose source proteins are lowly expressed in essential tissues.
The tissue list and TPM threshold are configurable; default essential-tissue list: heart, brain (cortex / cerebellum / basal ganglia), liver, kidney cortex/medulla, lung, pancreas, small intestine, colon. The TPM threshold for "highly expressed" defaults to 10.
API sketch
```yaml
In vaxrank YAML config
vaccine_peptides:
safety:
enabled: false # off by default; opt-in
presentation_predictor: mhcflurry # uses --mhc-predictor by default
reference_proteome: default # "default" = patient ref proteome already in use
self_kmer_lengths_class_i: [8, 9, 10, 11]
self_kmer_lengths_class_ii: [13, 14, 15]
rank_strong: 0.5
rank_mild: 2.0
cross_reactivity_max_hamming: 1
cross_reactivity_rank_strong: 0.5
tissue_expression:
enabled: false
source: bundled # bundled GTEx file, or path to user-supplied TSV
essential_tissues:
- heart
- brain_cortex
- liver
- kidney
- lung
- pancreas
- small_intestine
- colon
tpm_high_threshold: 10.0
weight_in_combined_score: 0.0 # 0 = tie-breaker only; >0 = additive penalty
```
CLI sketch
```
--vaccine-safety-enabled
--vaccine-safety-cross-reactivity-hamming 1
--vaccine-safety-tissue-source gtex_essential_tissue_tpm.tsv
--vaccine-safety-tpm-high 10.0
```
Manifest fields
Each ranked window gains a `safety` block:
```json
{
"safety": {
"self_strong": 0,
"self_mild": 2,
"worst_self_rank": 8.4,
"autoimmune_risk_count": 0,
"autoimmune_risk_hits": [],
"essential_tissue_tpm_max": 0.3,
"essential_tissue": "none",
"safety_score": 0.0
}
}
```
Acceptance
- `safety` block on each window's manifest entry.
- Windows can be ranked / filtered by safety score (configurable weight in the combined score).
- Pluggable reference-proteome backend; default pulls from existing vaxrank reference proteome.
- Bundled small GTEx essential-tissue TPM table (or HTTPS-fetchable manifest).
- Tests: window ordering changes when safety is enabled and one window has a strong self-binder vs another has none; cross-reactivity flag fires for a 1-aa-distance hit; tissue penalty downranks a window whose gene is highly expressed in heart relative to a low-expression peer.
Related
This issue covers the interior of an SLP window and the cross-reactivity / tissue axes — distinct from #247 (junctions) and #249 (boundaries).
Motivation
Multi-antigen vaccine constructs (peptide or mRNA) can present non-mutant self-peptides to the patient's MHC. Three failure modes are currently unmodeled in vaxrank:
Off-target self-peptide presentation inside SLP windows. A 25-mer SLP that flanks a mutation can still slide MHC-I/II k-mers across non-mutant regions. Those k-mers are wild-type and won't drive a tumor-specific response — they dilute the immune response and waste vaccine dose. Today vaxrank ranks windows only by mutant-epitope binding; it never scores the interior of the window for non-mutant binders.
Self-cross-reactivity within ±1 aa. A window may produce a k-mer that differs by ≤1 aa from a strongly-presenting self-peptide. Those neoantigens carry autoimmunity risk: the responding T-cell clone may also recognize the wild-type self-peptide on healthy tissue.
Tissue-aware autoimmunity safety. When self-cross-reactivity is unavoidable, prefer windows whose source proteins are not highly expressed in essential tissues (heart, brain, liver, kidney, lung, pancreas, gut epithelium). Even if some autoimmunity is triggered, hitting a less-essential tissue is far safer.
This issue tracks a safety module that scores candidate vaccine windows on those three axes and uses the scores as ranking tie-breakers (or, optionally, hard filters).
Scope
A. Self-peptide presentation scoring
For each candidate SLP window:
The reference proteome should be pluggable: default to the patient's matched reference (already in vaxrank), but allow users to substitute a custom k-mer index (e.g. tumor-cell-line proteome, restricted self-proteome, or species-specific for non-human work).
B. Self-cross-reactivity (within ±1 aa)
For each mutant epitope produced by a window:
C. Tissue-expression-aware safety penalty
When at least one autoimmune-risk hit fires for a candidate window, weight it against tissue expression:
The tissue list and TPM threshold are configurable; default essential-tissue list: heart, brain (cortex / cerebellum / basal ganglia), liver, kidney cortex/medulla, lung, pancreas, small intestine, colon. The TPM threshold for "highly expressed" defaults to 10.
API sketch
```yaml
In vaxrank YAML config
vaccine_peptides:
safety:
enabled: false # off by default; opt-in
presentation_predictor: mhcflurry # uses --mhc-predictor by default
reference_proteome: default # "default" = patient ref proteome already in use
self_kmer_lengths_class_i: [8, 9, 10, 11]
self_kmer_lengths_class_ii: [13, 14, 15]
rank_strong: 0.5
rank_mild: 2.0
cross_reactivity_max_hamming: 1
cross_reactivity_rank_strong: 0.5
tissue_expression:
enabled: false
source: bundled # bundled GTEx file, or path to user-supplied TSV
essential_tissues:
- heart
- brain_cortex
- liver
- kidney
- lung
- pancreas
- small_intestine
- colon
tpm_high_threshold: 10.0
weight_in_combined_score: 0.0 # 0 = tie-breaker only; >0 = additive penalty
```
CLI sketch
```
--vaccine-safety-enabled
--vaccine-safety-cross-reactivity-hamming 1
--vaccine-safety-tissue-source gtex_essential_tissue_tpm.tsv
--vaccine-safety-tpm-high 10.0
```
Manifest fields
Each ranked window gains a `safety` block:
```json
{
"safety": {
"self_strong": 0,
"self_mild": 2,
"worst_self_rank": 8.4,
"autoimmune_risk_count": 0,
"autoimmune_risk_hits": [],
"essential_tissue_tpm_max": 0.3,
"essential_tissue": "none",
"safety_score": 0.0
}
}
```
Acceptance
Related
This issue covers the interior of an SLP window and the cross-reactivity / tissue axes — distinct from #247 (junctions) and #249 (boundaries).