Context
Depends on: #739
VEP results currently live as two columns on mapped_variants (vep_functional_consequence, vep_access_date), which holds a single consequence string with no record of how it was derived. VEPAnnotation replaces them with a temporal per-allele table.
Schema
| Column |
Notes |
allele_id |
FK to alleles |
consequence_terms |
all terms from the matched transcript entry |
most_severe_consequence |
single term, ranked by Ensembl severity order |
consequence_source |
enum: transcript | most_severe |
matched_transcript |
transcript the consequence was read from; null when consequence_source = 'most_severe' |
access_date |
date of the VEP call |
source_version |
version the VEP call was made against |
error |
sanitized failure description; null on success |
created_at / superseded_at |
temporal support |
Consequence resolution
VEP's top-level most_severe_consequence is the worst call across every transcript overlapping the variant's position. Overlapping transcripts have different exon structures and reading frames, so that field regularly reports a consequence that does not apply to the transcript the allele belongs to. A single BRCA1 coding variant returns 368 transcript_consequences entries.
Resolution is against Allele.transcript, which is NOT NULL at every level:
- Send
refseq=1 for NM_/NR_ transcripts so transcript_consequences carries RefSeq IDs. Ensembl and genomic HGVS are sent without it.
- Match
Allele.transcript against transcript_consequences[].transcript_id, comparing with versions stripped.
- On a match, take the most severe of that entry's
consequence_terms and record consequence_source = 'transcript' with matched_transcript set.
- With no match, use the top-level
most_severe_consequence and record consequence_source = 'most_severe'.
Severity ranking uses Ensembl's published order (rest.ensembl.org/info/variation/consequence_types?rank=1, 41 terms). Terms outside that list are not ranked; the first term is used rather than dropping the consequence.
Routing
Only level = 'coding' and level = 'genomic' alleles are annotated. Protein-level alleles are never sent to VEP and the coding alleles enumerated by reverse translation carry the answer instead. In the UI, a protein level allele could aggregate over the most severe consequence of the underlying VEP calls of its encoding variants.
Acceptance Criteria
VEPAnnotation table created with the schema above; vep_functional_consequence and vep_access_date removed from mapped_variants
- Consequence is read from the
transcript_consequences entry matching Allele.transcript; most_severe_consequence is used only when no entry matches
consequence_source and matched_transcript are populated on every row
refseq=1 is sent for NM_/NR_ transcripts and omitted otherwise
- Alleles with
level = 'protein' are not submitted to VEP
- Writing a new annotation sets
superseded_at on the previous current row in the same transaction
- Temporal query at a past timestamp returns exactly one row per allele
Context
Depends on: #739
VEP results currently live as two columns on
mapped_variants(vep_functional_consequence,vep_access_date), which holds a single consequence string with no record of how it was derived.VEPAnnotationreplaces them with a temporal per-allele table.Schema
allele_idallelesconsequence_termsmost_severe_consequenceconsequence_sourcetranscript|most_severematched_transcriptconsequence_source = 'most_severe'access_datesource_versionerrorcreated_at/superseded_atConsequence resolution
VEP's top-level
most_severe_consequenceis the worst call across every transcript overlapping the variant's position. Overlapping transcripts have different exon structures and reading frames, so that field regularly reports a consequence that does not apply to the transcript the allele belongs to. A single BRCA1 coding variant returns 368transcript_consequencesentries.Resolution is against
Allele.transcript, which is NOT NULL at every level:refseq=1for NM_/NR_ transcripts sotranscript_consequencescarries RefSeq IDs. Ensembl and genomic HGVS are sent without it.Allele.transcriptagainsttranscript_consequences[].transcript_id, comparing with versions stripped.consequence_termsand recordconsequence_source = 'transcript'withmatched_transcriptset.most_severe_consequenceand recordconsequence_source = 'most_severe'.Severity ranking uses Ensembl's published order (
rest.ensembl.org/info/variation/consequence_types?rank=1, 41 terms). Terms outside that list are not ranked; the first term is used rather than dropping the consequence.Routing
Only
level = 'coding'andlevel = 'genomic'alleles are annotated. Protein-level alleles are never sent to VEP and the coding alleles enumerated by reverse translation carry the answer instead. In the UI, a protein level allele could aggregate over the most severe consequence of the underlying VEP calls of its encoding variants.Acceptance Criteria
VEPAnnotationtable created with the schema above;vep_functional_consequenceandvep_access_dateremoved frommapped_variantstranscript_consequencesentry matchingAllele.transcript;most_severe_consequenceis used only when no entry matchesconsequence_sourceandmatched_transcriptare populated on every rowrefseq=1is sent for NM_/NR_ transcripts and omitted otherwiselevel = 'protein'are not submitted to VEPsuperseded_aton the previous current row in the same transaction