Divergence classes against Ensembl VEP 116.2
The two comparators of this repository, scripts/concordance/compare_vep_outputs.py for the SNP/indel datasets and scripts/validation/compare_sv_concordance.py for the structural-variant sets, score vep-rs against one Ensembl VEP release at a time, chosen by --reference-release. Under 116.2, the default, they apply the classes on this page, and docs/intended-divergences.md documents each class that sets tuples aside against Ensembl VEP 116.2, with its defect, a worked example on both engines and its counts on the measured sets. This page is the taxonomy for the 116.2 registry: every class the adjusted figure sets aside or counts when the reference is Ensembl VEP 116.2, with its mechanism in Ensembl VEP’s source at that release. Under 115.2 they apply the twelve classes the paper documents, unchanged, and write the reports they wrote when the paper was measured, byte for byte; the divergence page keeps those twelve as history, with their numbers, and says which of them release 116 retired.
Source citations name the module and line at the 116 release: the release/116.2 tag of ensembl-vep and the release/116 branch of ensembl-variation, as bundled in the ensemblorg/ensembl-vep:release_116.2 image. The paper’s figures were scored against release 115.2 and stay as published; nothing here changes them.
What changed between the two releases
Ensembl VEP 116 changed the behaviour behind two of the paper’s five defects and left the other three as they were.
| Paper’s defect | Classes at 115.2 | 116 | Under 116.2 |
|---|---|---|---|
| A, the splice-region verdict stored by assignment | 1, 2 | BaseTranscriptVariationAllele.pm:215 and VariationEffect.pm:87-110 unchanged | the same pair rules apply |
B, start_lost beside start_retained_variant | 3, 4 | VariationEffect.pm:851-963, 1028-1075 unchanged | the same pair rules apply |
| C, a skipped record annotated against its batch | 5, 6, 7, 8 | a record marked vep_skip is dropped before the input buffer (Parser.pm:491-501, validate_svf at :821-827; Parser/VCF.pm:477-481, 555-558, 575): no row in any format, the warning still written, --dont_skip restoring the passage | the batch-comparison classes retire; the record itself is the class reference_skipped_record |
| D, transcripts matched by coordinate alone | 9, 10 | 116.1’s chromosome-aware overlap (InputBuffer.pm:286-345, _chr_matches_for_vf_overlap at :348-357) keeps a record only when its chromosome, or a breakend mate’s, is the transcript’s | both masks are no-ops and are not applied |
| E, a mate row read at the record’s own coordinate | 11 | BaseVariationFeatureOverlapAllele.pm:257, 273 unchanged | the same pair mask applies |
none, <CNV:TR> expanded to literal sequence | 12 | Parser/VCF.pm:382-431 unchanged | the same pair mask applies |
The same chromosome-aware overlap adds three shapes of its own in which 116.2 drops rows vep-rs writes; they are classes 4 to 6 below. Class 7 is a row 116.2 writes for a reference allele, class 8 a buffer it writes as intergenic, and classes 9 to 13 five records it drops, pairs, or annotates where vep-rs does the opposite; none of these changed between the releases. Classes 14 to 16 are three more such records (a * ALT annotated from SVTYPE, a POS that is not a number numified, a real <CNV:TR> allele dropped beside an RN=0 one).
The classes
Each class has the name the reports print, a one-sentence definition, the Ensembl VEP source it cites, its treatment under the adjusted figure (set aside, or counted and not set aside), and the comparator that applies it. A class that counts without setting aside keeps the shape visible without crediting vep-rs for it.
1. reference_skipped_record
A structural record the reference dropped before its input buffer, marked vep_skip for a span over --max_sv_size (its SVLEN, else its END), an ALT type with no Sequence Ontology term (a lowercase <del> or SVTYPE=bnd included, the table’s keys being upper case), an unsupported multi-allelic list (<INS>,<DEL>, <INV>,<DUP>, <DEL>,T) or a deletion with neither END nor SVLEN or whose start exceeds its end (END at POS, SVLEN=0, a SVLEN that is not a number), or refused by validate_vf for an end more than one base before its start or not a number (END=0, END=abc, a breakpoint’s END=), so it has no reference row in any format; vep-rs annotates the vep_skip records in the default and tab outputs and refuses the validate_vf ones at warning level, and its vep-rs rows are set aside, whatever their allele. A reference block, one <NON_REF> or a list of them (<NON_REF>,<NON_REF>), is dropped on the unsupported-type route (NON_REF) and is this class; a gVCF variant site (G,<NON_REF>), dropped on the same route, is class 9 instead.
Source: Parser.pm:491-501 (the size test sets vep_skip and returns 0 in every mode; Config.pm:315 holds the 10,000,000 default), Parser.pm:821-827 (validate_svf returns 0 for a vep_skip record, so next() at :189 never hands it to the buffer unless --dont_skip), Parser.pm:475-488 (the coordinate checks of validate_vf, which return 0 for an end that is not a number or more than one base before the start), Parser/VCF.pm:477-481 (an ALT type with no Sequence Ontology term, get_SO_term at Parser.pm:663-728 over the table of ensembl-variation Utils/Config.pm:1417-1438), :555-558 (an incomplete deletion), :575 (the mark). The span is the one ensembl-io’s BaseVCF4.pm get_end derives: SVLEN first, else END, else the start itself, with a breakend’s END discarded (Parser/VCF.pm:487-489); a gnomAD-SV breakend record carries an SVLEN to its mate, so a same-chromosome breakend whose mate lies more than 10,000,000 bases away is skipped whole.
Treatment: set aside (both comparators). The class replaces the paper’s classes 5 to 8, whose predicates compared the two engines’ transcript sets on such a record; against 116.2 the reference has no row to compare.
How the record is recognised. The two comparators recognise it from what each reads. The SNP/indel comparator reads the two outputs and no input VCF, so it applies the output-only rule: 116.2 writes at least one row for every record it keeps, an intergenic_variant row when no transcript is in range, so a Location at which vep-rs wrote rows and the reference wrote nothing, under any allele, is a record the reference dropped. At least one vep-rs row at the Location must carry a structural allele (every route to vep_skip is structural), and tandem_repeat does not admit a Location because the reference keeps a <CNV:TR> record and writes it at another Location (the paper’s class 12); once admitted, every vep-rs row at the Location is set aside, a sequence allele beside the symbolic one of a mixed ALT list included, because the reference skips the line whole. Its datasets carry no structural record outside the chromosome 21 structural-variant sets the other comparator scores. The structural-variant comparator reads the input VCF and names the record from it: a port of the reference’s own routes (get_SO_term over the ALT list and SVTYPE, the incomplete-deletion test, and the size test over the span get_end derives) says which records 116.2 drops. Each such record is confirmed skipped when the reference wrote no row under the record’s own Location start and an Allele string the record produces (the Sequence Ontology class of its ALT and of its ALT list, the class term vep-rs prints for an ALT whose letters name a class but whose spelling has no term, deletion for <del> or <DEL:>, duplication for <Dup>, inversion for <Inv>, copy_number_variation for <CN=X>, insertion for <Ins>, chromosome_breakpoint for <Bnd>, the raw type of an ALT whose letters name none as both engines spell it, CPX, a breakend’s bracket, own-end and CHR2/END2 mate strings, a sequence ALT as written); exactly that record’s vep-rs rows, under those alleles, are set aside. A deletion whose start exceeds its end is written by vep-rs at the pair, 21:30425650-30425651 for 21 30425650 x N <DEL> . . SVTYPE=DEL;END=30425650, printed low to high and starting one base before the record’s own start, and the comparator locates its rows there. A kept record sharing the start, or the whole Location string, with a skipped one therefore neither hides it nor joins it (gnomAD-SV places a <CPX> at the Location of a kept <DEL>; a <NON_REF> block can start where a kept record starts), and two records at one start producing the same allele are told apart by the end of the Location. The reference’s own warnings file names each skipped line, but it is absent on a cached or fixture reference and its record excerpt is truncated, so the records and the outputs are the authority. A disagreement between them stops the comparison with an ERROR: naming the record: a record on a route whose own rows the reference wrote (a reference run under --dont_skip or under another --max_sv_size, declared with --reference-max-sv-size, -1 for no cap); vep-rs structural rows at a Location the reference wrote nothing for that no record on a route explains (a malformed record 116.2 drops for start > end+1, which is no vep_skip route, or a record missing from the input); or a skipped and a kept record at one start whose alleles and ends coincide, which no output can tell apart.
2. The pair classes of defects A and B
The six pair buckets of the paper’s registry (intronic_overcall_swap, ppt_overcall_swap, frameshift_splice_cascade_swap, splice_lastwrite_swap, start_cooccurrence_swap, covered_splice_region_swap) apply unchanged: EXCLUSION_REGISTRY of compare_vep_outputs.py is the pair-rule set of both registries by identity, and filter_registry_swap_pairs of the structural-variant comparator applies its excluding rules. Source at 116: ensembl-variation BaseTranscriptVariationAllele.pm:215 with VariationEffect.pm:87-110 (defect A), VariationEffect.pm:851-963 and :1028-1075 (defect B); the files differ from release 115 only in the copyright line.
3. The pair classes of defect E and the <CNV:TR> representation
filter_breakend_mate_local_read_pairs (the paper’s class 11; BaseVariationFeatureOverlapAllele.pm:257, 273, VariationEffect.pm:350-358) and filter_cnv_tr_expansion_divergences (the paper’s class 12; Parser/VCF.pm:382-431) apply in the structural-variant comparator. The <CNV:TR> pairing reads four shapes of the reference’s row: the unit insertion after the run and the unit deletion ending at it (the paper’s two), a literal substitution across the run or the base after it (a multi-allelic <CNV:TR>, a unit that is not the reference’s repeat, a . unit read as N, an SVLEN disagreeing with the unit count: Parser/VCF.pm:505-511, 532-543), and the reference’s own symbolic tandem_repeat row at the run when it ran without a FASTA, where every record is a gain to copy_number_gain (Parser/VCF.pm:516-527, Utils/VariationEffect.pm:246-256) and a loss vep-rs reads as the deletion of the run’s tail differs in the direction and coding terms alone. The literal shape includes a unit that is not DNA, repeated verbatim across the run (RUS=123;RUC=4 gives the allele 123123123123), and a loss whose literal reading is a substitution with another coding term (RN=3;RUS=AG,AG,C;RUC=1,1,1 gives C with protein_altering_variant; SVLEN=4000;RUS=CT;RUC=5 gives stop_retained_variant,3_prime_UTR_variant against vep-rs’s stop_lost with the span’s terms); a multi-allelic record whose reference rows collapse to one tuple pairs that tuple with each of vep-rs’s (RN=1,1,1;RUS=AGC,AGC,AGC;RUC=4,2,3 without a FASTA, one reference tuple against a gain and a loss).
4. bnd_own_chromosome_rows_lost
A bracket breakend whose mate is on another chromosome loses the rows of its own end when a mate-chromosome transcript reaches it before any transcript of its own chromosome and names its slice: the reference keeps the mate rows and writes nothing under the own-end allele, an order-dependent result.
Source: AnnotationType/Transcript.pm:122 ($vf->{slice} ||= $slice ||= $tr->{slice}: a record’s slice is named by the first transcript that reaches it, and in offline mode a record arrives without one), :125-143 (the slice test: a chromosome_breakpoint passes when the transcript’s chromosome is the record’s slice or any breakend’s, chr stripped; nothing else passes), AnnotationSource.pm:235-258 (the regions of a buffer are loaded in the order its records first ask for them, each record’s own region before its mates’, a region listed once at its first request, and the transcripts are visited in that order), InputBuffer.pm:191-207, 223-234 (a buffer holds the records of one chromosome). When an earlier record of the same buffer, on the record’s own chromosome and before it in the input, asked for a region holding a transcript within reach of the record’s mate before the record’s own region was asked for, that transcript names the slice and every own-chromosome transcript then fails the test. The record alone, with its mate, or under --buffer_size 1 keeps its own-end rows; --fork does not change the result.
Treatment: set aside in the structural-variant comparator under the cache authority (--vep-rs-cache): the reference wrote a Transcript row under the bracket allele and none under any own-end allele (N., .N, chromosome_breakpoint), and the vep-rs row’s transcript is one the cache files on the Location’s chromosome within 5,000 bases of the breakpoint, the reference’s own admission rule (StructuralVariationOverlap.pm:144-160). Counted and not set aside in the SNP/indel comparator, which has no transcript-to-chromosome authority.
5. bnd_synonym_mate_rows_lost
A bracket breakend whose mate’s chromosome is spelled with a prefix the mate-allele test does not resolve (21 30425650 x N N[Chr21:30425700[ . . SVTYPE=BND; chr21 is a cache synonym of 21, Chr21 is not) loses its mate rows: the reference writes the own-end rows alone, vep-rs the mate rows too, the worked example of docs/intended-divergences.md. A mate written with a RefSeq accession on another chromosome (N[NC_000002.12:321682[) passes the overlap test through the synonym table but fails the slice test, which compares the raw name with the cache’s, so the reference writes nothing under the mate allele; vep-rs does not resolve the accession and writes no mate row either, so nothing is set aside. An accession on the record’s own chromosome (N[NC_000021.9:30425700[) keeps its mate rows in the reference, which resolves it, and lacks them in vep-rs: a vep-rs under-annotation, charged to vep-rs.
Source: InputBuffer.pm:348-357 (_chr_matches_for_vf_overlap resolves the mate’s name through get_source_chr_name), AnnotationType/Transcript.pm:134 (the breakend’s seq_region_name, chr stripped and nothing else, against the transcript’s), StructuralVariationOverlap.pm:86-102 (a mate allele is added only when _close_to_feature, :144-160, passes: the mate’s seq_region_name against the transcript’s through Utils/VariationEffect.pm:111-124, the synonym table’s keys verbatim, else a case-folded equality, which Chr21 against 21 fails).
Treatment: set aside in the structural-variant comparator under the cache authority: the mate name, chr stripped, is not a chromosome the cache files, the reference wrote rows at the Location and none under the bracket allele, and the vep-rs row’s transcript is not on the Location’s own chromosome; or the mate name is the record’s own chromosome spelled with a prefix the reference does not resolve (Chr21), in which case vep-rs’s mate rows on the own chromosome are set aside too. Counted and not set aside in the SNP/indel comparator, where a synonym is any mate name outside the canonical contig set.
6. fasta_named_slice_intergenic
Under --check_ref or --lookup_ref with a FASTA whose sequence names differ from the cache’s (chr1 against 1), the variant’s slice is named after the FASTA and every transcript fails the slice test, so the reference writes intergenic_variant where vep-rs writes transcript rows.
Source: Parser.pm:749 (_get_ref_allele sets the record’s slice from get_slice), BaseVEP.pm get_slice (the slice’s seq_region_name is the FASTA’s), AnnotationType/Transcript.pm:141 (the test every transcript then fails).
Treatment: counted and not set aside in both comparators. The condition is the run’s configuration, not a property of any tuple, and it reaches every record of the run; a run that shows the count is re-run with matching sequence names rather than scored.
7. bnd_bare_reference_allele_row
A breakpoint record that names no mate (a bare <BND>, or one with SVLEN, POS2 or an END2 that is not a coordinate, and no bracket ALT) is held as N/<BND> (N/N[21:-7[ when the END2 is not a coordinate) and, with no breakend parsed from it, gets one allele per slash-separated part of that string, the reference base N included, so Ensembl VEP writes every row of the record twice under chromosome_breakpoint: ALLELE_NUM=1 for the reference allele and ALLELE_NUM=2 for the ALT. A reference allele has no variant effect, so vep-rs writes the ALT row once; the worked example is in docs/intended-divergences.md.
Source: Parser/VCF.pm:491-499 (the bracket mate is built only under defined $info->{CHR2} with END2 || END; :499 prepends the reference base), StructuralVariationOverlap.pm:64-77 (if (!@$breakends) { foreach (split(/\//, $vf->{allele_string})) { add_StructuralVariationOverlapAllele(...) } }, one allele per part), OutputFactory.pm:2029 (Allele = $vfoa->{breakend}->{string} || $svf->class_SO_term, the class term for both).
Treatment: set aside (both comparators). The reference-allele row duplicates the ALT row’s tuple, so each comparator’s unique-tuple construction drops it before the raw and the adjusted figure; the rows so dropped are counted on the reference’s raw output (count_bare_breakpoint_reference_rows, shared by both) and reported as the class’s set-aside rows, overall and per file (bnd_bare_reference_allele_rows in the structural-variant report, the class’s excluded count in the SNP/indel report). No tuple moves between the two figures for this class.
The same rows carry no feature_truncation under --no_stats, the reference protocol’s flag (OutputFactory.pm:2029 autovivifies an empty breakend before the terms are computed at :2034); with statistics on, Stats.pm:241 computes the terms first and the rows carry it. A reference produced with statistics on differs from the protocol’s on every mate-less breakpoint row.
8. bnd_mate_32bit_buffer_intergenic
Any coordinate of the reference’s input buffer that, with the --distance flank added, reaches 2^31 turns every record of the buffer into intergenic_variant rows: a breakend’s mate position, a span’s end (21 30425650 x N <DEL> . . SVTYPE=DEL;END=2147483647 under --max_sv_size -1, one intergenic row against vep-rs’s 5,074 transcript rows) or a record’s own position (21 2147483648 x N N[21:30425700[ . . SVTYPE=BND, two intergenic rows against vep-rs’s mate rows at the mate); the record that supplied the coordinate under all its alleles and every record loaded with it. Under the default flank of 5,000 the first such position is 2,147,478,648 and 2,147,478,647 annotates normally; under --distance 1 the turn moves to 2,147,483,647. No chromosome reaches these positions. vep-rs holds every coordinate in 64 bits, writes the breakend’s own-end rows and the other records’ rows against their transcripts, and writes nothing under the mate allele, as the reference does for any far mate below the bound. The worked example is in docs/intended-divergences.md.
Source: AnnotationSource.pm:190 (the flank added to each coordinate when the cache regions and the buffer’s bounds are chosen, every record’s start and end among them), :251-254 (every breakend’s mate position is one of those coordinates), :306-309 (_check_overlap keeps a transcript against the bounds with the flank added), InputBuffer.pm:386-389 (the mate position inserted into the buffer’s interval tree).
Treatment: counted and not set aside in both comparators. The records the shape damages beyond the breakend’s own are its neighbours in a buffer whose boundaries the outputs do not record, so no tuple is attributed to it. The SNP/indel comparator counts the reference’s rows at the Location of a record whose bracket allele names a mate at or past the bound (BND_MATE_32_BIT_LIMIT); the structural-variant comparator counts such records from the input, a bracket ALT or CHR2 with END2 (else END), and the reference’s tuples at their Locations (bnd_mate_32bit_buffer_records, bnd_mate_32bit_buffer_reference_tuples). A span’s end (SVLEN, else END) or a record’s own POS at or past the bound is counted as a mate position is, both comparators counting a reference Location whose start or end is at or past 2,147,478,648, and its rows stay counted, not set aside.
9. gvcf_variant_site_dropped
A gVCF variant site lists <NON_REF> beside its real allele (A G,<NON_REF>); the <NON_REF> token routes the line to the structural path, where G/<NON_REF> has no Sequence Ontology term, and the reference drops the site whole, the real allele with it. vep-rs annotates the real allele and reads <NON_REF> as the absence of a variant. The worked example is in docs/intended-divergences.md.
Source: Parser/VCF.pm:237-245 (an angle-bracket ALT routes the line), :469-481 (the ALTs joined and looked up), Parser.pm:663-728 (get_SO_term, no term for G/NON_REF).
Treatment: set aside (both comparators), vep-rs’s rows at the site, recognised by the record’s shape, <NON_REF> beside a sequence allele with no true SVTYPE (a block beside a symbolic allele is class 1; under a true SVTYPE both engines read the block as an allele of the structural record). The SNP/indel comparator reads the shape from the input VCFs (--input-dir, paired by stem, or --input-vcf; the runners pass them) and, for an ID-less record, from the record’s own name in vep-rs’s output (CHROM_POS_REF/ALT/<NON_REF>), at a Location the reference wrote nothing for; the structural-variant comparator reads the input record and sets aside vep-rs’s rows at the Locations and under the alleles vep-rs’s parser writes for the site (the anchor base trimmed from an indel, a lone allele minimised from both ends).
10. dot_breakend_without_svtype_pair
A dot-notation breakend without INFO/SVTYPE (N., .N) takes the sequence rules for its coordinates: the start is POS + 1 when the ALT’s length differs from REF’s and POS when it does not, the end is POS plus the length of REF minus one, and the span the reference writes follows the length of REF, the pair POS-(POS+1) with the positions of an insertion for a REF of one or two bases (N or NA against N.), (POS+1)-(POS+2) for a three-base REF beside an ALT of another length (21 30425650 x NAC .N . . . is 21:30425651-30425652 on both of its transcripts) and POS-(POS+2) beside an ALT of its own length (21 30425650 x NAC NA. . . . is 21:30425650-30425652); with SVTYPE=BND it writes the single base at POS + 1, as vep-rs writes it with or without SVTYPE and for every REF. When INFO names a mate through CHR2 and END2 (21 30425650 x N N. . . CHR2=21;END2=30425700), the mate is appended as a bracket allele and the reference writes the pair under both the N. and the N[21:30425700[ allele, vep-rs the point under both. The worked example is in docs/intended-divergences.md.
Source: BaseVCF4.pm:255-275 (get_start), :297-316 (get_end’s last branch), Parser/VCF.pm:237-245 (the dot still routes the line to the structural path), :491-497 (the mate appended from CHR2 and END2).
Treatment: set aside (both comparators): the reference’s row at a two-coordinate span and vep-rs’s at the point chr:(P+1), the span’s start or the base after it (the end of chr:P-(P+1) for a REF of one or two bases, the start of (P+1)-(P+2) for NAC against .N, the second base of P-(P+2) for NAC against NA.), on one feature and under one allele, the bare chromosome_breakpoint or the N. and bracket alleles of a record whose INFO names a mate, leave the adjusted figure as a pair.
11. missing_alt_annotated
A record whose ALT column is the missing value . is routed to the structural path by INFO/SVTYPE and annotated as an allele: a chromosome_breakpoint at POS + 1 for SVTYPE=BND, a deletion over END for SVTYPE=DEL; without SVTYPE the reference writes nothing for it, as vep-rs writes nothing in both cases. The worked example is in docs/intended-divergences.md.
Source: BaseVCF4.pm:486-490 (get_alternatives returns ['.']), Parser/VCF.pm:237-245, Parser.pm:710-711.
Treatment: set aside in the structural-variant comparator, which reads the input: the reference’s rows at the record’s Location. The SNP/indel comparator cannot tell them from a record with an allele and counts nothing.
12. non_integer_end_annotated
An INFO/END that is not an integer (30425949.5, 3.0425949e7) is taken as written, passes looks_like_number, and the record is annotated with the text in its Location and a fractional DISTANCE; vep-rs refuses the record. A SVLEN that is not an integer reaches the same Location text (SVLEN=300.7 gives 21:30425651-30425950.7, SVLEN=NaN gives 21:30425651-NaN and a JSON "end":nan), and so does a POS in a non-integer spelling on the sequence path (21 30425949.0 x A G gives 21:30425949.0); for these vep-rs reads the number (SVLEN=300.7 is 300 bases, NaN is 0, the pair 21:30425650-30425651, the POS is 30425949) and writes its rows at it. The worked example is in docs/intended-divergences.md.
Source: BaseVCF4.pm:302-308, :255-275 (a sequence record’s POS is kept as its text), Parser.pm:475.
Treatment: set aside (both comparators): the reference’s rows whose Location carries a coordinate that is not an integer. The structural-variant comparator, which reads the input, also sets aside vep-rs’s rows of the same record at the number it read (21:30425651-30425950, the pair 21:30425650-30425651 for NaN, 21:30425949), so that neither side is charged and the skipped-record cross-check does not stop on them; the SNP/indel comparator sets aside the reference’s text rows alone. An integer written with a sign or leading zeros (+30425949, 030425949) is the same number: both comparators read every coordinate as its number before comparing (canonical_location, normalize_location), so such rows agree with vep-rs’s and no class is needed for them.
13. cnv_tr_empty_expansion_dropped
With a FASTA, a <CNV:TR> whose expansion yields no alternate allele, or one equal to the reference run (RN=., a RUC that is not a positive number, a RUC times the unit length equal to SVLEN), is expanded to an allele string with no alternate and the reference writes nothing for it, without a warning; vep-rs writes the symbolic rows over the run, as the reference does without a FASTA. The worked example is in docs/intended-divergences.md.
Source: Parser/VCF.pm:382-431 (_expand_tandem_repeat_allele_string: :410 skips an RN of ., :414 and :419 numify RUC), :516-543 (the VariationFeature built from the string), Parser.pm:553-592.
Treatment: set aside in the structural-variant comparator, which reads the input: vep-rs’s tandem_repeat rows at the run of such a record (its counts truncated as Perl’s x operator truncates them; a unit of no bases repeats nothing under RUC, an empty expansion set aside like RN=., and under RB divides by zero in Perl, which ends the reference run, so no reference holds such a record) when the reference wrote nothing on the chromosome from the base before the run to the base after it. A reference run without a FASTA writes the symbolic rows and nothing is set aside. The SNP/indel comparator does not judge the class.
14. star_alone_svtype_annotated
A record whose only ALT is *, the VCF 4.4 marker for a base covered by an upstream deletion, names no allele; with a true INFO/SVTYPE the reference routes it to the structural path, where * is outside the VCF 4.4 forms, so SVTYPE names the type and the record is annotated from INFO alone: 21 30425650 x N * . . SVTYPE=DEL;END=30425949 is a deletion over END, 21 30425650 x N * . . SVTYPE=BND a chromosome_breakpoint at POS + 1 written twice (the reference base N and * as the two parts of N/*). Without SVTYPE the reference writes nothing for the record, as vep-rs writes in both cases: no row, the VCF line carried without CSQ, a JSON object with "most_severe_consequence":"?". The worked example is in docs/intended-divergences.md.
Source: Parser/VCF.pm:237-245 (N* is not a run of ACGT and SVTYPE is true), :469 (the allele string *), :472-475 (* fails ^<?(DEL|INS|DUP|INV|CNV|CN=?[0-9]+), so $type = $info->{SVTYPE}), StructuralVariationOverlap.pm:64-77 (one allele per part of N/*).
Treatment: set aside in the structural-variant comparator, which reads the input: the reference’s rows at the Location of a record whose ALTs are all * and whose SVTYPE Perl reads as true. The SNP/indel comparator cannot tell them from a record with an allele and counts nothing.
15. non_numeric_pos_numified
A structural record whose POS is not a number is annotated at the position Perl’s $start++ makes of the text: ., an empty column, 0x1D04A1D and fullwidth digits become 1 (21 . x N <DEL> . . SVTYPE=DEL;END=30425949 is 21:1-30425949 deletion, 3,254 transcript rows under --max_sv_size -1), 30_425_949 becomes 31, and a negative POS is kept (21 -5 x N <DEL> . . SVTYPE=DEL;SVLEN=-300 is 21:-4-295 deletion - intergenic_variant). A sequence record keeps the text and is refused (Invalid start '.' or end '0' coordinate); vep-rs refuses every form (Invalid POS). The worked example is in docs/intended-divergences.md.
Source: BaseVCF4.pm:255-264 ($start++ on the raw POS of a structural record, :263), Parser.pm:475-488 (a numified start passes looks_like_number and the start-against-end test).
Treatment: set aside (both comparators): the reference’s rows of a record whose POS is not a non-negative number (not digits with an optional fraction, exponent, leading + or surrounding blanks; a fractional POS is non_integer_end_annotated (class 12); a POS above 2^62 - 1, or at it for a structural record whose first base is POS + 1, is a number and not this class: vep-rs refuses the line as past its coordinate bound and the reference’s rows stay charged), at Locations vep-rs wrote nothing for. The structural-variant comparator reads the input and matches the rows by the start the reference prints, POS + 1 on the structural path and POS on the sequence path (21:-5 G - intergenic_variant); the SNP/indel comparator reads no input and sets aside a reference-only Location whose first coordinate is negative, the one trace no written POS leaves, while a start of 1 (a POS numified to 0, which a record at POS 0 also prints) or 31 is recognised by the structural-variant comparator alone.
16. cnv_tr_rn_zero_allele_dropped
With a FASTA, a multi-allelic <CNV:TR> whose RN is 0 for one allele expands that allele to an empty part of the joined allele string and loses the other allele: 21 30425587 x N <CNV:TR>,<CNV:TR> . . SVTYPE=CNV;END=30425596;SVLEN=9;RN=0,1;RUS=AGC;RUC=4 is minimised to AGCAGCAGC/- and annotated as the deletion alone, the four-unit gain gone; RN=1,0 and RN=2,0;RUS=AGC,AGC;RUC=2,2 are -/AGC, the gain alone, the RN=0 allele gone. vep-rs annotates both alleles, the RN=0 one as the loss of the whole run. The worked example is in docs/intended-divergences.md.
Source: Parser/VCF.pm:411 (for ( 1 .. 0 ) runs no iteration, so the allele is undefined), :428 (the alleles joined with /: AGCAGCAGC//AGCAGCAGCAGC, or a trailing empty part), Parser.pm:978 (/.+\/.+\/.+/ does not match an empty part, so the string is not treated as multi-allelic), :881 (the first minimised feature is kept).
Treatment: set aside in the structural-variant comparator, which reads the input: for a two-ALT record whose RN list has exactly one entry the loop at :411 runs no iteration for (0 or negative; . leaves no part and is not the shape), expanded by the reference under a FASTA (a row at or beside the run under an allele other than tandem_repeat), vep-rs’s tandem_repeat rows at the run whose tuple is the dropped allele’s alone: feature_elongation when the RN=0 allele leads and the real allele is a gain or unchanged, which vep-rs reads as a gain (RN=0,1;RUS=AGC;RUC=3 over the three-unit run at 30425588-30425596: the reference keeps AGCAGCAGC/- alone, upstream_gene_variant on ENST00000334068 and inframe_deletion on ENST00000390690, and vep-rs writes feature_elongation,coding_sequence_variant beside feature_truncation,inframe_deletion), and feature_truncation when the RN=0 allele trails and the real allele is a gain. A real allele that is a loss (RUC=2) shares the feature_truncation tuple with the RN=0 allele, so nothing is left to judge once the reference’s row pairs with it; a trailing RN=0 beside an unchanged real allele (RN=1,0;RUC=3) leaves the reference no alternate and no row, which is class 13. The kept allele pairs under class 3’s <CNV:TR> pairing. Without a FASTA nothing is set aside. The SNP/indel comparator does not judge the class.
The classes retired against 116.2
The structural-variant comparator does not apply these five masks under 116.2; its report lists them under masks_not_applied with the reason.
| Mask | Paper’s class | Why it does not apply |
|---|---|---|
filter_intended_divergences | 5 | 116 drops a vep_skip record before the input buffer; the reference writes no row to compare transcript sets against |
filter_giant_breakend_mate_divergences | 6 | 116 drops a breakend pair over --max_sv_size whole; its mate allele has no reference row |
filter_non_ref_batch_divergences | 8 | 116 drops a <NON_REF> record before the input buffer |
filter_cross_chromosome_divergences | 9 | 116.1’s chromosome-aware overlap never pairs a record with a transcript on another chromosome |
filter_cross_chromosome_orphan_intergenic | 10 | with no off-chromosome rows to displace it, the reference writes the intergenic row itself |
The SNP/indel comparator’s scope class sv_transcript_selection (class 5 on a whole-genome input) retires the same way: its pass runs only under 115.2.
What the classes reach
Against an Ensembl VEP 116.2 reference produced with the default flags, reference_skipped_record reaches exactly the records the reference’s warnings file names line N skipped for a vep_skip reason: on the chromosome 21 structural-variant sets these are the gnomAD-SV <BND> records whose SVLEN exceeds 10,000,000, every <CPX> and <CTX> record, and every <NON_REF> block; on a hand-built input, a <DEL>,<DUP> record is kept as copy_number_variation while <INS>,<DEL> and <INV>,<DUP> are dropped. The two class-D masks, applied under the 115.2 registry against a 116.2 reference, exclude nothing, because 116.1’s overlap never pairs a record with a transcript on another chromosome. Classes 4 to 6 are shapes the mechanism admits; whether a reference shows them depends on its input order, its mate names and its FASTA, and the report counts them when it does. Class 7 appears whenever the input carries a breakpoint record without a bracket mate; none of the chromosome 21 structural-variant sets does (every gnomAD-SV <BND> names its mate through CHR2 with END or END2, and the synthetic sets write breakends in bracket and dot notation). Classes 8 to 16 need a coordinate past 2,147,478,647, a gVCF variant site, a dot breakend without SVTYPE, a . or * ALT with SVTYPE, a non-integer END, SVLEN or POS text, an empty <CNV:TR> expansion or an RN=0 allele under a FASTA, or a POS that is not a number; none of the measured sets carries any of them.
Choosing the release
--reference-release defaults to 116.2 in both comparators. scripts/concordance/run_concordance.sh derives it from the Perl Docker image tag, the fixtures directory’s provenance or a local checkout’s Constants.pm; scripts/concordance/run_clone_measurement.sh derives it per cell, before the timed runs, from the ground truth’s provenance (the suite directory’s provenance.json, else the <output>.provenance.json sidecar beside its output, else the reference set’s provenance.json one directory up), the image tag first (release_116.2) and the cache version when the image is named by digest alone; either accepts --reference-release as an override. A reference whose provenance names neither fails the cell before anything is timed or scored (scripts/concordance/reference_release.py). The structural-variant comparator also takes --reference-max-sv-size when the reference ran with a cap other than Ensembl VEP’s default. A report written under 116.2 names its release and lists the classes it applied with their definitions and counts; a report written under 115.2 is the paper’s, unchanged. The divergence page, docs/intended-divergences.md, is written against 116.2: its classes 1 to 5 and 11 to 24 are the ones a 116.2 report applies, and the paper’s classes 6 to 10 stand there as retired, with the release that retired each.