Read Judgment¶
How gbcms decides what one read says about one variant: REF, ALT, partial evidence of another allele, or depth only. This page is the spec: a table of read shapes and the call each gets, with the decision behind every call. The algorithms that implement it are in Allele Classification.
The table is executable. tests/read_judgment_cases.py builds every shape
(synthetic, four reads each) and tests/test_read_judgment_spec.py checks the
engine's call for each one. A decided case fails when the engine breaks its
rule. An open case pins today's call until its decision lands, so a change to
it shows in review instead of slipping in with an unrelated fix.
How a change to read judgment is made¶
- Spec first. A change to how reads are judged starts here: the shapes it affects, their call today, the proposed call, and the evidence (the read census's verdict on each shape, real-data counts adjudicated per read, and what other tools do: GATK, samtools/bcftools, fgbio, VarDict, Strelka2, freebayes, bam-readcount, LoFreq and the original GetBaseCounts, plus the domain's own tools (for RNA: GATK's RNA practice, STAR, ASE counters, RNA variant and editing callers) and the published literature, saying where a tool's handling is not documented). The census changes in step with a rule about read inputs (what a read contributes), so for such a rule it cannot be the evidence: check the bases in question themselves and the mates' alignments, ITD and indel rows first. Other tools' practice is a floor, not a ceiling: where none sets a standard, or the measurements support a better rule, propose that rule and say where and why it departs from practice.
Fix the class, not the row. Start from the mechanism: what about the
read, the alleles or the judge makes the call wrong, stated without the row
that showed it, and the rule that follows from the principles below. The
row is one instance, so the cases cover the other shapes of the same
mechanism (SNV, MNV, indel and delins; repeat and unique sequence; read
ends, strands and qualities). A cutoff comes from a mechanism (an error rate
per telling base, a quality, a read length), never from where a measurement
splits or from an oracle's own cut, and is checked across the values users
set. A rule narrower than its mechanism says why, or is recorded as a known
partial with the general rule ticketed. Judge it on data the bug was not
found in, against a truth that does not share the rule. Before proposing,
look for earlier work on the same mechanism: this register, REJECTED.md,
and closed issues, whose comments hold the measurements behind past
decisions.
2. Decide. The operator decides; the decision gets an entry in the register
below, stating the mechanism it follows from and naming any earlier decision
it amends.
3. Then code. The implementation turns the case table's open cells into
decided ones. A test expectation that changes is part of the decision, never a
side effect of the fix.
Principles¶
- Count the given allele; judge bases, not placement. A read is ALT only when its own bases carry the ALT, and REF only when its bases show REF where the alleles differ. Alignments can be wrong, so the CIGAR's placement of an indel never decides a call on its own (AGENTS.md invariant 7).
- Informative reads only. A read that cannot tell the alleles apart (one that starts or ends inside an indel's repeat tract, or holds no window of a complex variant) counts toward depth only.
- One oracle. For pure indels, the read census (
tests/census.py) judges each read by its bases alone; the engine's pure-indel counts are checked against it. - The sequence judge resolves sequence, not haplotypes (
--read-judge sequence, #304; operator 2026-10-25). It asks which local sequence a read's own bases spell at the row: REF, the row's ALT, or another allele at its site (the row's candidate sequences). Contexts (other listed rows, the guard's recurring background, alleles the reads spell away from the site) only explain the read's other differences, so they never pass for the row's allele. No linkage, no phasing: a variant linked to the row elsewhere never credits a read.
Decision register¶
Decided¶
| ID | Mechanism | Rule | Source |
|---|---|---|---|
| RJ-1 | A read that ends inside a repeat tract cannot show how many units its molecule holds, so its bases fit REF and the indel alike. | REF only from reads that span an informative window; a read starting or ending inside the tract is depth only. Amended 2026-10-15 (RJ-27): for a pure indel the window is its tract with one base each side. | C10 #157; #278 |
| RJ-2 | Alignments can be wrong and other alleles share the locus, so only the read's own bases across the change show the allele its molecule carries. | ALT only where the read's own bases hold the ALT: carriers ending inside the tract are depth only; a read with another indel in the window on the strict path, or a same-length deletion spelling another allele, is another allele; reads that keep the anchor of an anchor-changing insertion are another allele. | #161, cluster 1 (#188, #191, #192, #121) |
| RJ-3 | A read starting or ending at an indel is placed by the flank base that anchors it; a flank base it does not read cannot place it. | Reads starting (or ending) on a pure indel's flank are read from the flank when they read that base (unmasked, the reference's). A deciding base past a contig edge leaves the read depth only, counted and warned. Amended 2026-10-15 (RJ-27): one flank base decides, and a read whose first base is that flank base but unread or not the reference's is placed from its other flank. Named limit (2026-11-03, RJ-31, #409): a piece too short for its own bases to place it, at a spliced read's end or between two junctions. An aligner splices a novel junction only from a few bases past it (STAR from 5, an annotated one from 3, FORTE's setting from 1), so an end piece is written at the annotated junction where its molecule spliced at a novel one 2 to 6 bases on, its bases there mismatches; and a short piece between two junctions (47M 200N 6M 194N 47M) is placed where its few bases fit. The junction penalty hid such bases, and half the depth beside the junction; with no penalty they count at their own quality, so the piece can read as an ALT it does not carry (synthetic set, STAR overhang 3 and 5: 133 of 6,097 end-piece reads, 2.2%, at a hom-REF row, none under the penalty; a 6-base middle piece with a misplaced base: 4 of 4 reads ALT beside 10 unspliced REF reads at Q30 and bar 20, Q40 and bar 30, and Q40 and bar 20, depth only on develop, where the two junctions' penalties stacked to Q0). The rule that keeps such a piece depth only, with its cutoff from the aligner's novel-junction minimum and not a fixed length, is ticketed (#409). |
H3 #204; #278; #409 |
| RJ-4 | A complex event changes several bases at once and a partial match fits other alleles too, so only a read showing the whole event carries it. | Complex variants (delins, anchor-changing indels, MNP reads with an indel at the block) count exact carriers: the read's bases across the whole event with two flank bases; long events by junction windows. | C1 #141 |
| RJ-5 | Listed alleles overlap: a read whose bases spell another listed allele inside this row's window carries that allele, and one fitting two listed alleles equally carries neither for certain. | A REF read that is ALT for a co-annotated sibling whose event lies inside this row's discrimination window is not REF here (partial evidence), for reads and fragments alike. Amended 2026-10-22 (#300, operator): an ALT read the exact-carrier rule judged is contested by the siblings on its bases, wherever it could lie, never re-tested against REF on its aligned slice (that slice of a carrier the aligner wrote a unit off reads as REF, so listing a sibling zeroed the row's AD). The read, every readable base of it, is placed ungapped anywhere on this row's ALT and on each sibling's ALT, over the whole-read reach, its confident mismatches counted up to three: a sibling placing it with fewer, or as few, claims it (neither row's AD where the two tie: it is either allele, whether or not any read shows the sibling; partial evidence); a sibling spelling this row's own allele is no competitor; a read no allele places within three is judged by the aligned sibling tests as before. Other ALT calls keep the aligned guard. Amended 2026-11-02 (RJ-25, RJ-24): the siblings are every listed allele that meets the site (no floor); a sibling inside a long delins's core claims no REF read. Amended 2026-11-05 (#359, operator): ASJD reads the same sibling verdict as the main counts. detect_asjd makes the two sibling calls the main loop and the per-transcript counts make, so a read a sibling claims votes in neither of ASJD's REF and ALT partitions; every tally holds one verdict per read. Rules path only (the sequence judge has no sibling contest). Measured on the synthetic set: no co-annotated sibling, 0 of 1,072 rows move; with one sibling added per row, 12 of 2,144 rows move, in asjd_* only, and RD, AD, DP and the per-transcript counts are byte-identical. |
C2 #119; #300; #359 |
| RJ-6 | An indel's length is part of its allele, so a read carrying another length carries another allele. | Wrong-length pure indels are another allele (partial evidence); deletions of 50bp or more match within a 3-base band (retired by RJ-24: such deletions are judged by their bases at the POS breakpoint). | #91 |
| RJ-7 | A read with its own length change where the alleles differ does not show REF there: its molecule carries something else. | A read with another insertion or deletion inside the discrimination window (not the ALT at another placement) is not REF: neither, with partial evidence. Extends RJ-5 from annotated siblings to any indel. On the exact-carrier rule (2026-10-15, #287): a read whose bases fit REF over the windows, but whose own alignment changes the length inside them with an indel that does not recur as background (on 3 or more fragments and 20% of those spanning the windows, the event's own representation aside), is judged by its bases read on without gaps to its end or next splice; two or more confident mismatches against the reference show the indel (an insertion whose first bases repeat the flank, which the windows do not reach), and the read is another allele. Bases decide: a read whose bases still fit REF (one ending inside a run) stays REF, and a germline indel beside the event keeps its reads' call. | C26 #200, operator 2026-10-01; C39a #287 |
| RJ-8 | Bases outside the discrimination window do not tell the alleles apart, so a change there says nothing about which allele the read carries. | Another insertion or deletion outside the window, of any length, is a separate event: the read is REF where its bases across the window are REF, with no partial evidence. | C26 #200, operator 2026-10-01 |
| RJ-9 | Every base a read holds is evidence: a fit at the junction is overturned by later bases that contradict it. | A long complex event's junction windows are read on inward as far as the read reaches; a read whose later bases contradict an allele is not that allele. A read ending inside the event is judged by the bases it has (one base-identical to REF counts REF). | C25 #199, operator 2026-10-01 |
| RJ-10 | Bases past the fragment end are adapter, not the molecule, and can fit an allele by chance. | A read ends at its fragment end: bases past it (read-through into adapter, insert shorter than the read) are neither bases nor reach, in every read and rule, the census included. They are hard-clipped as the read enters counting, as if trimmed (a masked base would still fill a window as a match). Only an inward-facing pair defines a fragment (TLEN positive on the forward read), and only adapter-like bases are clipped: soft-clipped, or at most two aligned past the boundary, none inserted. More are the molecule's: TLEN, a reference distance, leaves out an ITD's inserted bases and a mate's clipped 5' bases. | C17 #176, operator 2026-10-02 (adapter-like bases only, same day) |
| RJ-11 | A record without base qualities cannot pass the quality gate every base is judged by. | A record with absent base qualities (QUAL *, stored as 0xFF) is dropped by the read filter and warned once per BAM, as a record without bases is. |
C19 #182, operator 2026-10-02 |
| RJ-12 | An unmapped record has no placement at the locus; mapping quality is the user's filter (--min-mapq), not evidence about the bases. |
An unmapped record (flag 0x4) is not an alignment: dropped by the read filter. A mapped read whose mate is unmapped still counts, and mapped MAPQ-0 alignments stay countable (--min-mapq 0, pseudogene loci such as PMS2). |
O7 #183, operator 2026-10-02 |
| RJ-13 | An aligner clips the bases it cannot place, often the variant itself; they are still the molecule's bases. | Soft-clipped bases inside the fragment are the read's own bases, judged by the same rules (an RNA read's clips are not evidence, RJ-18); split reads (SA) join their molecule and count once across the given breakpoints. Policy adopted now, built in 6.7.0. | C15 #173, C7 #144, C18 #177, operator 2026-10-02 |
| RJ-14 | An aligner can write one allele as several operations; the bases between the aligned flanks, not the operations, show the allele. | The ALT written across several insertion or deletion ops in the discrimination window counts ALT when the read's bases between its nearest aligned flanks are the ALT (masked bases fit, at least one base read; for an insertion, one of its own inserted bases, RJ-20), the ops' placement only a tie-break as in RJ-15: judged by its bases before the wrong-length and one-change rules read its ops. Amends RJ-2 and RJ-7. | C27 #201, operator 2026-10-02 |
| RJ-15 | Where an aligner writes a gap is a choice among equal spellings; the bases between the flanks are the molecule's. | A read whose own deletion covers the anchor is judged by its bases between its nearest aligned flanks: ALT, or REF, when they equal that allele (masked bases fit; at least one base read; for an insertion's ALT, one of its own inserted bases, RJ-20), the aligner's placement of its gap only a tie-break (a reference written as the anchor deleted and re-inserted is REF); otherwise neither, with partial evidence. Never Phase 3's closer haplotype. Deletion and insertion rows alike. Amended 2026-10-15 (RJ-27): a deletion whose every base between the flanks is masked is ALT where its confident flanks lie the ALT's length apart. | C28 #202, operator 2026-10-02; #278 |
| RJ-16 | A fit resting on low-quality bases is as likely an error as the allele, so a call needs at least one confident base's worth of evidence. | An exact-carrier ALT call needs evidence: its clearly read bases fit the ALT (as before), and its bases, each weighed by its quality (a base matches with 1 − e and mismatches with e/3), favour ALT over REF by at least what one base read at --min-baseq gives (about 2.5 log10 at 20). Bases matching both alleles cancel, so the evidence is the weight of the bases that mismatch REF less those that mismatch ALT, over the windows and, for a long event, the read's bases past them. A low-quality base counts for little instead of fitting either allele. |
C16 #174, operator 2026-10-03 |
| RJ-17 | A spliced read skips the intron's bases, so it shows nothing of an event there; only an aligned block across the window reads it. | A splice is not reference coverage: a pure-indel read is informative (RJ-1, RJ-2) only when one of its aligned blocks between splices spans the window, REF and ALT alike. A read spliced inside the change interval shows none of it past the splice (the event may sit in the skipped intron) and is depth only, as a read ending there is; a deletion written right after the read's splice has no aligned flank (its bases equal REF spliced at an acceptor further on) and is depth only, and so, the REF mirror, is an exon piece holding only part of a deletion's bases with no flank base of its own (amended 2026-10-30). Amends RJ-1 and RJ-2. Amended 2026-10-30 (#292): an exon piece that a junction at or inside a pure deletion's edge begins and the read's own end closes inside the deleted bases (or, mirrored, that the read's start opens inside them and a junction at or inside their far edge ends) holds part of the deletion and no flank base of its own, so no base places it (RJ-3): the aligner put it where its few bases fit. It is depth only, never REF, with BAQ on or off (BAQ's junction penalty had hidden its bases until RJ-31; with BAQ off, RJ-19's spliced judgment counted it REF). Since 2026-11-03 (RJ-31) there is no junction penalty, and this rule alone keeps such a piece out of REF. A piece holding all the deleted bases, or a flank base of its own beside them, is judged as before, as an unspliced read ending inside a unique deletion is (spec cases u-8, u+10); DNA reads have no junction and are unchanged. |
R5 #198, operator 2026-10-04; #292, operator 2026-10-30 |
| RJ-18 | STAR clips a junction overhang it cannot splice, so a clip at an exon edge holds the next exon's bases, not the reference beside it. | An RNA read's soft clip that reaches an exon edge or a junction end (annotated, or one the variant's reads splice at), or whose aligned bases end within five bases of one, is not allele evidence: STAR soft-clips a junction overhang it cannot splice, so such a clip holds the next exon's bases. Any other clip is the read's own bases (a local aligner clips a mismatching end) and is read as in DNA. A clip admits no RNA read. Amends RJ-13 for RNA. | C15 #173, operator 2026-10-04 (refined after review, same day) |
| RJ-19 | A spliced read's molecule is the mRNA, so its bases are compared with the alleles as spliced, not with the genome across the intron. | A spliced read is judged against the haplotypes spliced at its own junctions: the exact-carrier windows (event, growth, flank) are built over the reference spliced where the read splices, the far exon's bases read from the reference, so bases a length change pushes past the junction show against the next exon, and the read must hold the spliced flank as any read holds its flank. Every junction the windows reach is followed (a short exon between two is read through). Amended 2026-10-16 (RJ-27): so is every junction their reading on reaches, so a read spliced just past the windows reads on along its next exon, not the intron. A junction starting inside the bases where the alleles differ and running past them (or ending inside them) splices the haplotypes at the event's edge, so the bases decide however the aligner wrote the gap; such a read is also REF spliced where it splices (an alternative donor or acceptor, or a splice site the event straddles), so it counts ALT only when its bases favour ALT over that reading too, by one --min-baseq base's evidence, and is otherwise depth only. Any other splice through those bases leaves the read depth only. |
C32 #213, operator 2026-10-04 |
| RJ-20 | A masked insert shows its length but not its sequence; the length tells the ALT apart only where no other allele at the locus has it. | Current rule (amended 2026-10-15 with RJ-27, #278; re-confirmed 2026-10-26, #304). "Readable" is the one quality gate every base passes: not N and at or above --min-baseq. A read whose inserted bases are all unreadable, all N (fgbio masks a duplex disagreement to N at Q2) or all below --min-baseq, carries the insertion's length, not its sequence. Inside the discrimination window, an unreadable insert of the ALT's length is the ALT where no other allele of that length is at the locus (it matches both through masked bases otherwise: neither). One of another length is another allele: neither, with partial evidence. One written outside the window cannot be the variant: a separate event (RJ-8). It does not slide (RJ-21 judges a readable insert by its placements). A read whose readable inserted bases match the ALT is ALT however many are masked. In a run the aligner writes the masked base as the insertion, so the read's own inserted bases are its I-op bases, net of the reference bases its deletions beside them re-insert (counted, not placed: a masked re-inserted anchor still nets one readable base). A truncation needs one readable base, and its identity band reads its letters at any quality. The read census holds this rule. The CIGAR checks, which judge only an insertion the exact-carrier rule cannot (no prepared reference), still count an unreadable insert of the ALT's length neither, with partial evidence (has_unreadable_insert), never Phase 3, where REF pays for the gap so length alone would win ALT. History: C35 (2026-10-06) made such a read neither with partial evidence on every path; the 2026-10-15 amendment made it the ALT under the exact-carrier rule. |
C35 #240, operator 2026-10-06; #278; #304 |
| RJ-21 | Inside a repeat an insertion's placement is the aligner's choice; the read's bases over every placement it can take show the allele. | A windowed insertion of the variant's length with a readable base of its own is judged by the read's bases, never Phase 3's closer haplotype (where REF pays for the gap, so length won ALT against the bases, and another allele could be absorbed into REF), and over the best placements it can take, not only the aligner's: the insert slides a junction when the base it places onto the reference fits it (the same base, or a masked one), and a slide that takes in a read mismatch resolves it, so an absorbed sequencing error or a compensating mismatch slides back; only the placements with the fewest mismatches count. It is ALT when a placement shows the ALT by read bases (at the variant's junction as the strict path judges an insert there, its one readable base possibly a flank base taken in, as RJ-20 allows; or the variant's haplotype elsewhere in a repeat, the read's only change across the window) or when the read's bases across the window spell the ALT; otherwise it is another allele (neither, with partial evidence) when a placement sits inside the discrimination window, and a separate event (RJ-8) when none does. A readable insert written past the scan window is scanned when a placement reaches the window. Whether it can be read is its own inserted bases' question (RJ-20): an insert with no readable base does not slide, so it is judged where the aligner wrote it while a readable one with a masked edge base slides (an asymmetry RJ-20's homopolymer decision requires). Both backends give the same call. Amends RJ-8 (an insert's placement is where it can sit) and RJ-20 (the unreadable outside-window case). The census trusts the aligned flank: it misreads a readable insert written just outside the window that can sit inside it, and a compensating mismatch on the flank. | C36 #243, operator 2026-10-06 |
| RJ-22 | An insert that can sit inside the window may be an allele there, and one read cannot tell its own error from a recurring other allele. | A readable insert of the variant's length is never a separate event while one of its fewest-mismatch placements sits inside the discrimination window, every junction it can reach scored by the read's readable mismatches there (through the read's contiguous aligned bases, up to 64 junctions each way), not only the junctions a slide reaches base by base: readable mismatches beside the insert (the anchor read as another base, say) block that slide, but are resolved once the insert passes the base that does not fit, so a placement inside the window can be as good as the written one. Such a read carries another allele (neither, with partial evidence), never REF; and never ALT, though that placement may show the ALT's bases, since a per-read rule cannot tell one molecule's error from a recurring other allele. The strict path keeps its junction ALT when a slide could absorb a flank substitution into another insert: the read is the given ALT plus one substitution, as a REF read with a substitution in the window stays REF. An insert with no readable base is unchanged (RJ-20), and the same haplotype written inside a run still slides to the junction as RJ-21 judges it (not seen in the measured data). Amends RJ-8 and RJ-21. The census trusts the aligned flank, so it reads such a carrier as REF; and it needs the window to be one allele exactly, so it reads a junction ALT with a substitution in the window as neither (its first limit). Amended 2026-10-15 (RJ-26): a substitution the carriers share inside the event is another allele where it recurs; one read's is an error. | C37 #245, operator 2026-10-07; #278 |
| RJ-23 | Equal-length windows at one flank give REF and ALT molecules as many reads able to judge them, so the VAF is unbiased; a change both haplotypes carry is a separate event, not evidence. | Current rule, every amendment below applied (2026-11-03). Every complex event is read over one pair of equal-length windows at one flank, the same for both alleles (the base rule, below). Under the sequence judge a pure insertion of 50 bp or more is read over such windows from its anchor: a REF or ALT call holds, on its allele's sequence, the anchor and as many bases on as REF's window holds (the run the insert slides over and the base past it), and a read inside the insert, or holding only its far junction, is depth only, whichever allele it fits: a read that ties two alleles (the ALT with another allele, REF beaten; REF with another allele, the ALT beaten) must hold the equal windows of both, or it is depth only, not partial evidence. The guard's masks are laid by offset from the anchor on every candidate haplotype (REF's, the ALT's and each other allele's), by the columns of the path a read lies on, so a masked offset weighs on none of them: the listed or found changes the read carries between the anchor and a masked base are counted, and the read lies on one such path for every candidate (the changes it spans without carrying leave each candidate the copy its own alignment's columns match; a change it cannot place is a plain alternative, no mask moved for it). Where they hide the base that tells the windows apart, both windows read on to the next base that does, counted in the columns of the path the read lies on as the masks are (a listed deletion between the anchor and that base moves it nearer on a haplotype that carries it), and a read short of it is depth only. Where no base within reach tells the windows apart, every read is depth only and the row is named NO_TELLING_BASE. A delins whose longer side is over 50 bp is not read this way yet. The rules path is unchanged. The base rule and its amendments, oldest first: Every complex event is read by one pair of equal-length junction windows at one flank, the same for both alleles: the shorter allele's whole window (its event, grown through repeats, with two flank bases each side) against as many of the longer allele's bases, read inward from that flank, then on through the rest of the longer allele as far as the read reaches (RJ-9). Windows of equal length at one anchor give a REF and an ALT molecule the same number of read starts that can judge them, so the VAF is unbiased without padding the shorter window (which cost a third of the reads); reading junctions from either flank instead would let the longer allele count at both ends. Past 50 bases nothing changes in practice: only reads over the variant's first base (or admitted by a clip) are counted, so the far junction never decided a call. The flank is the POS flank; an RNA variant whose POS flank is cut by an exon edge reads from the other one (amended 2026-10-16, RJ-27: an exon start in the flank or at the event's first base cuts the left flank, an exon end only inside it, so an exon end where the event starts leaves the left flank whole), and when both alleles pass 50 bases the windows run from the flank nearer the first difference (an event ending a long run is out of reach from the other); a read judged from the right counts though it starts past POS, as the other allele's molecule starting there would. A change that recurs at a fixed distance beside the event is a separate event, as another indel outside the window is (RJ-8): it is masked in both windows, so a read carrying the given allele counts ALT; one on the ALT reads alone (a haplotype larger than the given allele: a phased neighbour, or an event the input under-describes) is named in gbcms_diagnostic, never withheld. Amended 2026-10-12: the windows run past the event through any bases the shorter allele's flank shares with the longer allele's next bases, and on through two bases from where they first differ (as a long deletion's run through its microhomology), so a read carrying only a substitution of the event's bases is neither allele; a read whose flank is clipped, under its own deletion, or aligned at the event's other copy (as mismatches over the event's far bases) is placed from the other flank as the allele its bases favour: with each allele's window placed from that flank at its own length, its confident bases (at or above the minimum quality, not N) must mismatch one allele by at least one base read at the minimum quality more than the other, so a REF molecule behind a poor clip shows no placement; it counts where that allele fits, else carries another allele (partial evidence when the ALT's), and one placed through aligned bases counts only where its allele fits, though it starts past POS. Amended 2026-10-16 (#279, operator: spanning carriers only): a read aligned straight across the windows (no indel of its own there) that fits the shorter allele read from its reading flank is confirmed from the other flank, read whole at the longer allele's length (the shorter allele extended on the reading side by the reference beyond it). This holds only where its own bases place that flank unambiguously: they continue the reference past it, one error aside, and fit it worse by two bases shifted by the length change either way. Where its confident bases there favour the longer allele by two bases, the aligner wrote that allele's other copy over the reading flank (an insert, or a deleted sequence, whose end resembles the flank, aligned onto it as mismatches, the rest clipped). A read holding the longer allele's window from there and reaching past it, as one read from the reading flank does, counts as that allele. One starting inside the event shows only the other junction, which the shorter allele's molecules have no counterpart of: depth only, never the shorter allele. Counting such reads would give the longer allele read starts the shorter one cannot have. A fit of the longer allele reads its whole event and stands. A recurring change the REF fragments carry too (a germline SNP or MNP, on 3 or more of them: one REF read's error is no background) is background, masked run or not; on the ALT fragments alone an isolated change is masked and named in the larger allele, and a run of changes (the base past the window included) is another allele, beside which no larger allele is named (the tallies cannot spell it: an MNP, or an indel shifting the bases past it; the observed allele names it from the reads' alignments). Amends RJ-4, RJ-9 and RJ-19 (no padding). Amended 2026-10-14: a change the REF molecules carry inside the repeat the event is grown through, off the given allele's own bases (a germline SNP in the run), is background too, found from the REF and ALT molecules told by their bases (RJ-25, from the variant's own reads) as beside the event (on 3 or more REF molecules and 20% of those reading it, or recurring on the ALT molecules and on 3 or more and 5% of the REF molecules); it is masked in both windows where it sits on each allele (left of the given allele at the same place, right of it shifted by the length change), taking the reference's base and the change's only (a third base there is another allele, 2026-10-14), so a REF read carrying it counts REF and a carrier carrying it counts ALT; the scan beside the event lets it fit as well, so a read carrying it is still read on past the event. A change there on the ALT molecules alone stays unmasked for an event changing the length: inside the repeat it may be the event's own sequence, another allele. An MNP has nothing to place, so the run it was grown through is beside it: an isolated change on its ALT molecules there is a phased neighbour, masked and named as beside any event (found from the molecules placed by their bases, so a carrier aligned with a clip or an indel at the block counts once its fellows show it; carriers all clipped short of the windows' reach cannot show it), and a run of them is another allele. The given allele's own bases are never masked (a germline change merged into the input's allele is named by COEXISTING_ALLELE). Amended again 2026-10-14 (operator): an MNP's bases it keeps inside its core sit on both alleles as the grown part's do, so background there (on 3 or more and 20% of the REF molecules, as above) is masked too, in cis or in trans with the MNP: the germline haplotype's REF reads count REF and its carriers ALT, on the MNP check's route and the exact-carrier rule's alike (VCF gives such a change its own record, its haplotype REF at the MNP's row); a change there on the ALT molecules alone is another allele. Inside a delins the bases kept depend on the alignment, so a change there stays as before (reads showing it are neither, on either side). Amended 2026-10-30 (#264, operator): under the sequence judge a pure insertion of 50 bp or more is read over these equal windows from the anchor, as the rules read it: a call holds, on its allele's sequence as the read aligns to it, the anchor and as many bases on as REF's window holds (the run the insert slides over and the base past it), so the ALT is read over the insert's first bases, never the whole insert. Both windows are counted in bases of the called allele's sequence from the anchor, so a listed change that sequence carries inside them (an insertion beside the run) lengthens neither. A read lying inside the insert, or holding only its far junction, holds no window and is depth only, as a REF read starting inside the run is, whichever allele it fits (one tying the ALT and another allele there is no partial evidence); a tie stays depth. Before this the judge counted reads inside a long insert ALT, giving the ALT read starts REF cannot have (HG002's het insertions of 50 bp or more read high), and could count REF a read short of REF's window where a listed change inside the run explained it on REF alone. Where the guard's masks hide the base telling REF's window from X's (a change past the run lies, on X's sequence, past the insert, so read there it would tell REF's molecules apart and never X's), both windows read on to the next base telling them apart unmasked, and a read short of it is depth only, a REF read as a carrier: RJ-27's read-on of 2026-10-20, here for both alleles alike, without its exception for a read short of that base fitting one allele alone and exactly. The guard's masks are laid on both windows by offset from the anchor, as "masked in both windows" says, over a read's reach: a change past the run takes any base at its offset on the ALT's sequence too (an inserted base there, or the reference past the insert), and one the ALT's sequence holds inside its window where the run is longer than the insert takes any base at that offset on REF's, so a masked offset weighs on neither allele. Where no base within the haplotypes the judge reads tells the windows apart (the run reaches past them, or masks take every base that would tell), every read is depth only and the row is named, NO_TELLING_BASE in gbcms_diagnostic (no column added); a run longer than the reads but told within reach leaves no read holding the windows too, unnamed (its depth shows it). Amended 2026-10-31 (#264, operator): the review's fix that lays the guard's masks on both windows by offset is accepted, and the masks are laid on every candidate haplotype, not on REF's and the ALT's only, so the code does what RJ-27 says (the masks are read on every haplotype alike): a listed allele of the ALT's length that differs from the ALT at a masked offset takes the mask there too, so no base tells it from the ALT, and a carrier of either, or a read with a third base at that offset (no allele's), is partial evidence of the ALT or that allele (the tie rule, RJ-25), never ALT. The offsets are those REF's haplotype and the ALT's mask; each candidate takes them at the same offsets from the anchor, which is the base before the ALT's run, wherever the row is written in it. The cis reading of a masked change on REF's haplotypes is removed; its measurement stays as the evidence for REJ-20261023-001. This rule is for pure insertions of 50 bp or more; a delins whose longer side is over 50 bp is a separate decision, drafted as a ticket. The switch GBCMS_JUDGE_LONG_INS (the default, window, off) is measurement only and temporary: it is retired when the sequence judge becomes the default (#331). Amended 2026-11-02 (#264 follow-up, operator; both for the sequence judge's pure insertions of 50 bp or more). (1) The window check is made on the haplotype of the allele the read's call names, and also on the ALT's where the call is partial evidence of another allele the read ties with the ALT, REF beaten (the tie rule, RJ-25): such a read fits the ALT as well as the other allele, so it is that allele's evidence only where it holds the ALT's equal window too. A read lying inside the insert, or holding only its far junction, held the other allele's window by an alignment to its haplotype, which has no long insert and so looks like REF's run, and counted partial evidence (HG002's chr18:74617096, a 1,997 bp insertion that begins with an inserted C and then the reference's own bases, beside a found 1 bp insertion A>AC, and chr4:660975); it is depth only. A tie of the ALT with REF, and a tie that holds both windows, are unchanged, and no ALT count can rise. (2) The guard's masks are laid by the columns of the path a read lies on, not by the offsets the haplotypes have without the listed or found changes beside X (Greptile's finding on PR #396, "Nearby changes move masks"): an insertion or deletion between the anchor and a masked base moves that base's offset on every haplotype the read lies on, so the offsets are those the haplotypes have with the change applied. This holds for a context of X, which lies outside its site (the repeat X changes with a base each side); one inside the site is another allele, with a haplotype of its own. The graph holds a copy of the span where a mask can lie within a read's reach (from the anchor, the longest read and the length changes of the rows beside it on) per set of such changes that can lie together, the copy of none too, each copy masked by the columns of its own set; the haplotype a call is examined on takes the masks of the copy its read lies on (amended 2026-11-02, below). A state's graph with more than 64 such sets in that span (seven independent changes or more) is not laid out by copy (RJ-27 gives the cap's rule), and its masks stay at the offsets without those changes: a named limit. Measured on HG002 (public; the c246, tr, sub and nocl arms, 26,189 rows, both judge paths): the tie check moves 367 read calls from partial evidence to depth only on 82 rows, all pure insertions of 50 bp or more, and changes no REF count, ALT count or VAF of any row (partial evidence falls on all 82 rows; DP falls by 42 reads on 25 rows: those reads lie off the anchor, and a read off the anchor was in DP only through its partial call, so as depth only they now count in no column); the masks by path columns move no read call, though they are laid by the columns of up to five context changes at the rows with masks (about 30 rows), and neither does a sweep of 12,078 synthetic read pairs (a listed insertion or deletion of 1, 2 or 4 bases before a masked base, REF and ALT molecules with it or without). What the masks change is the score of a read carrying such a change on a candidate: with a third base at the masked base it was four lower on X's haplotype (-8 against -12 in the contract test's first pair) and is now the same. The rules path is unchanged. Amended 2026-11-02 (#264 follow-up, review fix; for the sequence judge's pure insertions of 50 bp or more): a read lies on one copy of the masks' zone for every candidate. A state's best path took whichever copy masked its own mismatches, so a path that ended before a listed change was laid the masks as if it carried it: a read ending in the insert, long before a deletion listed past it (X a 60 bp insertion of new sequence, the guard masking a base 41 from the anchor, a listed sibling equal to X but at inserted base 40), took the deletion's copy for X (masking inserted base 38, where it has a third base) and the other copy for the sibling (masking base 40): X scored 0, the sibling -4, and the read was ALT from a deletion it cannot carry. A read now lies on the changes it carries and on those it spans without carrying. It carries a change where its best-scoring candidate's path takes the change's segment and its bases span the change's place (from the anchor to the base past the repeat the change slides over; an inserted base counts as past the anchor): a path that only touches the place carries nothing, as the copy laid for a deletion cuts the reference under it and holds its padding base, so a read ending on that base, or inside the repeat the deletion shortens, went through it at no cost and was held to a copy that hid a sequencing error (a third base at a masked offset made the read ALT, in the review's second round, 3 of 3 reads in a unique and in a repeat shape). It spans a change without carrying where the path passes the whole place on the reference. A change the read cannot place (its bases do not span the change's place) is neither carried nor barred (amended 2026-11-03, operator): it stays a plain alternative for every candidate, in both scorings, with no mask moved for it, as on develop. The read is scored first on graphs that hold no copy of the masks' zone (the changes that move a mask's offset are plain alternatives, the masks at the offsets without them); only where the best-scoring candidate's path spans the place of one or more of them is every candidate scored again, on graphs that hold copies for those changes only, held to the copies of the changes the path carries and those it spans without carrying, the other changes plain alternatives there too. Of the changes it spans without taking, each candidate may take the copy its own alignment's columns match (a gap in the alignment shifts them as the change would), as a REF read over the deletion's place may on X's haplotype. A read that spans none is scored on the first graphs alone. The first form of this rule (2026-11-02) barred every change a read could not place from every candidate, as an alignment alternative too. On HG002 (round 3) it moved 33 reads at 7 insertion rows the wrong way: 5 true-REF reads to depth only at chr11:11246952, 7 true-ALT reads to REF at chr3:194943570 (5) and chr1:31431867 (2), and 3 ALT credits at chr11:11246939 to reads of the neighbouring 3,643 bp insertion, a row that is not a truth allele. All 33 carry listed neighbours in cis that they cannot place; they are scored as on develop now. This was chosen over masking the union of the copies' offsets up to the first change, which also hides inserted base 40 from a read that carries the deletion: that read is told X from the sibling there (ALT), on its own copy, as this rule says. A read that carries the change and the insertion alike is unchanged; the reads whose calls move are those whose best path took the copy of a change the read cannot carry. Also 2026-11-02 (same review): the length the windows read on to, where the masks hide the base that tells them apart, is counted in the columns of the path a read lies on, as the masks are, not on the haplotypes without the listed changes: a deletion listed between the anchor and that base takes bases out of the haplotype of a read that carries it, so the base is nearer by as many columns there and the windows hold as many fewer. Before, a REF molecule carrying such a deletion that reached the base was two columns short of a window measured without it (depth only) while a molecule without the deletion reaching it was REF. The length before reading on (the run and the base past it) stays the called haplotype's columns, as 2026-10-30 says; only the reading on follows the path. Also 2026-11-02 (same review): the window check of (1) is the class rule for every call, not for a tie with the ALT alone: a read is told only on the windows of the alleles it ties, so a call holds its own allele's equal window and that of every other class that scores within the margin of it (one confident base). A tie of REF with another allele (the ALT beaten) was checked on that allele's window alone, and a call made by the fit check (a read leaving an indel at the ALT's site unexplained on the haplotype it fits best) on that haplotype's alone; each now holds the windows of the classes it ties as well. A call that beats every other class by the margin is unchanged, and so is a REF call the reach rule made (REF ties another allele the read never reaches, or one it writes its own indel across: RJ-25's tie rule makes it REF): it holds REF's window alone, as before, and the class plan decides these calls for every shape (operator, 2026-11-02; on HG002 six reads at three rows that the window demand had turned to depth only are REF again). The rules path is unchanged. |
C39 #253, operator 2026-10-08, 2026-10-09, 2026-10-12; C43 #277, operator 2026-10-14; #264, operator 2026-10-30, 2026-10-31, 2026-11-02 |
| RJ-24 | A long deletion's evidence is its junction; reading on through the deleted bases would expose REF to errors ALT never meets. | (Amended 2026-11-02, with RJ-25 (operator): extended to a delins. A delins that replaces 50 REF bases or more (the changed REF bases once the shared prefix and suffix are trimmed; for a pure deletion these are the deleted bases, RJ-24's own measure) has a core: the replaced bases 4 or more in from both ends. A substitution wholly inside it, listed or found on 3 fragments and 5%, changes bases only REF's molecules hold, so it is a context of REF's molecules, as in a long deletion's deleted bases: a read that reaches and spells it is REF; it is no candidate allele; and a sibling there claims no REF read (RJ-5). A delins that replaces fewer, such as 5>60 (five REF bases), has no core and is read as before; so has an event that keeps the length. Rules path: the sibling claim span (ref_guard_siblings), the guard's masks in REF's window (window::delins_core); judge: deleted_core. Worked row (shapes only): a 60>30 delins, a listed SNV at its 41st replaced base, 20 carriers, 30 REF reads, 6 REF-molecule reads carrying the SNV; (RD, AD, partial) (30, 20, 6) to (36, 20, 0) on both paths. HG002 holds too few het delins with a phased SNV inside to measure the benefit; the spike-in is owed.) (Amended 2026-10-30 and 2026-10-31 (twice), #297. The rule now, X and its close (operator, 2026-10-31, option A throughout): one test decides every candidate, on the rules path and under --read-judge sequence: a read is ALT only where its own confident bases carry the given ALT and tell it from every other candidate. At a pure deletion of 50 bp or more the candidates are REF, every other unit count of the same run that the input lists (always, wherever it first differs and whether or not a read shows it or reaches it: the input is taken as correct, invariant 7) and each unlisted count the reads show (RJ-25's presence test, is_found: spelled in full on 3 fragments and 5% of the fragments spelling the allele it is nearest). A read that stops before the place where it and the ALT first differ stays partial evidence. A read whose own bases spell an unlisted count in full is never ALT, whatever the floor (RJ-6: partial evidence, or depth only where the aligner doubts its placement, RJ-29); the floor decides only the reads that cannot tell. A read is the given deletion with a listed neighbour only where its confident bases show that row's change (RJ-28). The presence test reads the qualities the hold reads. The clauses below and the amendments of 2026-10-31 at the end hold the detail.) A pure deletion of 50 bp or more is judged by its bases at the POS breakpoint, however the aligner wrote it (a D op, a soft clip, a split read). Both alleles are read from the left flank over one window of equal length: 4 clean flank bases, the microhomology, then 4 clean bases of the allele's own continuation (REF: the deleted bases; ALT: the right flank). A read matching one window is that allele; matching both or neither, it is neither (partial evidence when it fits ALT better). Nothing past the window is checked, for either allele: read-on through the deleted bases would expose REF to errors ALT never meets. A read whose left flank is not aligned where the windows start (in its soft clip, under its own deletion, or written over the deleted bases' end as mismatches) is placed from the right flank, which both alleles share, as the ALT's window sits there (RJ-13; REF's window ends inside the deleted bases, which no ALT molecule holds), when its confident bases (at or above the minimum quality, not N) favour the left flank over the deleted bases REF has before the right flank by one base read at the minimum quality, and by more than nothing (the base next to the junction always differs, the deletion placed leftmost; a masked flank base weighs nothing for ALT, and the deleted base it is weighed against stays read, so a germline SNP at the anchor still shows the junction; an N flank shows nothing at any minimum quality). It is ALT where it fits, else another allele; written over the deleted bases' end, only where it fits. In DNA such a read counts toward depth when the rule decides it; a hard-clipped record is never evidence on its own. A read that fits REF but whose own alignment deletes or inserts 5 bases or more inside the deleted span carries another allele (C26): partial evidence. A co-annotated sibling claims a REF read (RJ-5) only from the anchor through REF's window's last deleted base: further into the deleted bases the windows read nothing and no ALT molecule holds them, and the flank before the anchor both windows read, so a sibling there would take REF reads alone. A change recurring at a fixed offset of the windows is a separate event, masked at that offset in both windows (as RJ-23): in the flank and microhomology, which both alleles share, one the REF reads carry too (a germline SNP or MNP, a run included, on 3 or more REF reads); an isolated one of the ALT reads' own; and past the junction an isolated one on the REF reads, where a run on reads fitting REF within a base is another allele (another breakpoint), not background; a run of changes on the ALT reads alone, the base either side of the windows included, is another allele; the isolated changes on the ALT reads alone are named in gbcms_diagnostic with the deletion, and beside a run none is; and masks never take every offset where the alleles differ. The 3-base length band of RJ-6 is retired. The same in RNA, after splice triage (a deletion written as a splice N stays excluded). Amended 2026-10-18 (#285): a run past the junction, on the ALT reads or on reads fitting REF, is a phased neighbour, not another breakpoint, where the bases after it rejoin that allele's continuation (the 12 after it read by 3 or more of its fragments, no change recurring on any) and no other breakpoint gives the reads' bases, the run as most show them: neither the deletion at another start or of another length (up to twice its length: prep holds as many bases past a deletion of 50 bp or more as it deletes), nor the allele with one more insertion or deletion from the junction through the run. The reads' bases are a consensus, so another breakpoint must give them exactly. A neighbour is masked in both windows as an isolated change is, and on the ALT reads alone named with the deletion through the run's last base, past the windows included. An allele's own recurring changes are first taken together (those in the windows, and on past them each within 12 bases of the last; #296, folded in): where another breakpoint gives the reads' bases exactly, the 12 after the last change read by 3 or more of its fragments, none of them is masked, isolated or run, and nothing is named, so a same-length deletion a few bases right, or another unit count of a VNTR whose units differ at one base, is another allele. A change on the carriers that another input row lists (a substitution giving that base there; prep records the input's substitution rows inside the reference it holds for the deletion) is that row's allele, not the reads' own: the input is taken as correct, so they carry the given deletion with a listed neighbour, masked and not named, and it is never evidence of another breakpoint (operator, 2026-10-19). A run at the junction whose bases are the deleted bases' own is the deletion shifted right, and a run before a repeat that a deletion of another length gives whole (another unit count of a VNTR) is that deletion: each stays another allele, as does a run whose bases keep mismatching after it. For the guard a fragment is read once, its mates merged base by base (the better-quality one's where both read a base), and taken as an allele by its bases past the windows where they place it, as RJ-27 reads on: the 12 there fit that allele within one base and the other by two or more, fit neither allele shifted by up to 8 bases nearly as well (a read of another length reads the same in a repeat), and the 24 bases it reads on along that allele fit it within one all told (another allele whose bases past the windows happen to read the same goes on to differ; a read ending sooner is not placed so, as it may end before it differs); else by its four continuation bases, which a run may make look like the other allele's. Past the windows it is read up to its next splice. Named limits: another breakpoint that also carries an SNV inside the run counts as the given deletion with a neighbour; where a deletion is one unit of a VNTR whose unit is about its length, the given deletion with a phased change and another unit count read the same over every base the guard reads, so such carriers are another allele unless the input lists the change (HG002's 90-bp deletion with its phased SNV: VAF 0.11 with the deletion alone in the input, 0.58 with the SNV row, truth 0.5); where the units are identical past what a read can spell, a read of an unlisted other unit count still counts ALT, and the row is named (UNIT_COUNT_UNSPANNED, #297, below); a listed one is held; a carrier whose run lies inside the windows and that carries two phased changes 13 to 24 bases past them is not placed and counts partial; a copy farther past the deletion than its length is not looked for; in RNA a run within 12 bases of a splice stays another allele unless 3 fragments read past it unspliced. Amends RJ-2 and RJ-6; builds RJ-13 for these deletions; RJ-5 reads REF's window only. Amended 2026-10-30 (#297, operator: the narrow rule, after an adversarial review rejected holding every run): where the bases past the deletion repeat with the period of another allele at its breakpoint (one more or one fewer unit of a tandem run whose deleted copy differs from it, so the windows stop at the copy's differing base), that allele reads like the ALT through the windows and on, until their bases first differ. Such alleles are computed from the reference exactly (the other deletions at the breakpoint, fewer bases or more up to twice the given, and the listed rows; a reference N tells nothing, so the two read on past it), never by a run detector. Each reads like the ALT through the windows, so REF is told from it at the junction. An insertion at the breakpoint (the bases before it again: a tandem copy, a run expanded) is not looked for: a REF read inside the copy fits it as well as REF, the general case of a read ending inside a repeat (RJ-1), which the junction windows do not hold (HG002 1:2750146: a first form found a 279-bp copy there on 3 fragments of the sample's other haplotype, the rules path's AD 64 went to 0, and the sequence judge, placing each read anywhere, tied 42 REF reads with the copy: the judge was right for that allele by the reads' bases, and the allele is no longer offered). The run is held for a listed one always (rule X, operator 2026-10-31: no read need show the count), and for one nobody listed only where it is really present at the site, spelled in full by its own bases on 3 or more fragments and 5% of those telling the ALT from it there (found as RJ-25 finds another allele: a fragment the aligner places here, RJ-29's test (XS below AS; MAPQ above 0 where it writes no XS), placed from the left flank, fitting the ALT's windows and not REF's, read on 24 bases past the allele's first difference, its bases past the windows fitting the allele but for one, showing its base at two or more of the bases where it and the ALT differ and the ALT's at none, and fitting REF read the same way worse by two: in a repeat whose copies differ, a REF molecule of the sample's own copies can fit the ALT's windows and a shifted copy by chance): an ALT call stands only where the read's confident bases where the two differ favour the ALT by one base read at --min-baseq (a base fitting neither costs both alike, an error, RJ-26; one of the other's against three of the ALT's is forgiven, as RJ-27 reads on); otherwise the read is the ALT or that allele: neither, with partial evidence (RJ-25). A read that fits the given deletion with a listed row applied past the junction (a phased neighbour the input names, an indel or a substitution) as well as the other allele, but for one base, and whose confident bases show that row's change (at one base or more past the first difference, where the deletion with the row and the ALT differ, it reads the row's base; 2026-10-31), is the deletion with that neighbour: it is no fragment spelling the other allele and its ALT call stands, the input taken as correct, as for a listed change in the windows (HG002 4:3610329: carriers of a 447-bp deletion with a listed 1-bp insertion 53 bases on read as one more 53-bp unit deleted for 54 bases; a first form without this found that allele on 5 fragments and turned 17 truth-ALT reads partial on the rules path, 16 under the judge). A site with no other count keeps its reads. The windows do not grow: REF, told from both at the junction, keeps its reads, and a co-annotated sibling still claims REF reads only through REF's window (the first build grew the windows through every run: rows lost every read where a run is longer than a read, VAF fell at hets with short far sides, and the grown window widened the sibling claim, HG002 chr10:7629321 VAF 0.59 to 0.90 against 0.5). Never past a read's reach, for a count nobody listed: where the first difference lies further from the windows' first base than a read can spell the count in full (the first difference and 24 bases past it; the longest read at the site holds fewer), no read can show it, nothing is held and the counts stand; a listed count is held wherever it first differs (2026-10-31: the reads that cannot reach the difference cannot tell the counts apart, so they are partial evidence, and a row whose listed count lies past every read has no ALT read until one can tell); where that is so for the nearest unit count on either side (more bases deleted, or fewer: the nearest that reads like the ALT past the junction for the bases it shifts the reference by and 12 more, a copy twice over, not a chance shift or a far count a repeat whose copies differ lets read alike), gbcms_diagnostic names the row, UNIT_COUNT_UNSPANNED(change:bases/longest). On the spike-in arm (D12 phase 1b, 2x151) that names 39 of 39 class-U rows and 5 of 40 class-T3 rows, each the one fewer unit deleted, which reads alike a unit longer than the planted one more (its bases then: the planted D, the unit and 4; bases is now the first difference and 24, so that a count first differing 4 to 23 bases before the longest read's end is named too, and the spike-in numbers are recounted on the closing build); a first form naming any count past reach also named 2 T2/T3 rows in long runs for a count 3 and 4 units off. Under the sequence judge the alleles found so are site states, so its reads tie the same way. Where it takes an ALT call, the allele is named in gbcms_diagnostic in the observed allele's form at the deletion's anchor, listed or not, with the fragments fitting the ALT's windows whose ALT call it takes and those that tell the given count from it: OBSERVED_ALLELE where none does, else COEXISTING_ALLELE (QC Flags). Named limits: REF keeps the windows while an ALT read must reach the difference, so beside a present other count AD reads low by the share of ALT reads ending short of it, as RJ-25's does (one 150-bp read of each allele from every start, the counts first differing 64 bases from the windows' first base: AD/(RD+AD) 86/227 = 0.379 for a true 0.5; a bar of the spike-in arm D12); an allele deleting more than twice the given bases is not looked for; a read spelling another count at a site where it is not present is no ALT (partial evidence, or depth only where the aligner doubts its placement; the sequence judge leaves it depth only, so partial_alt differs between the paths on it); an expansion at the breakpoint is not looked for (above); HG002 holds no third unit count, so the benefit is measured on the spike-in arm (#275). Amended 2026-10-31 (#297, operator: rule X; option (b) rejected). Rule X, stated at the start of this row, keeps a listed other unit count as a candidate allele always; it is the behaviour of the batch built from 444ce886. Option (b) was built and measured against that batch, and is not adopted. It held a listed count only where the reads show it (present when at least 1 fragment shows it by its bases where the two counts differ and 5% of those showing either do, RJ-25's sibling rule; decided absent when 3 or more deciding fragments tell the two apart and none or under 5% show it) and let a listed count so decided absent hold no ALT call, on both paths, and named the row in gbcms_diagnostic with a flag of its own. Measured: on the patient sets and on HG002 it changed no count against 444ce886's batch; on the spike-in arm it gained 141 S1 reads (the given count's short carriers counted ALT where no molecule carries the listed count) but credited the other allele's reads as ALT (4 to 12 reads) and made false-absent rows: by chance at 3 deciding fragments (a listed count really present is called absent exactly when none of its n deciders shows it, 2^-n of rows at equal haplotypes), and where BWA soft-clipped deciders fail the placement test (RJ-29), as spike-in row p1b_022. It added about eight conditions (a presence test for listed counts, "shown" in place of "spelled", the judge dropping absent states, the 3-fragment floor, depth for a read that shows an absent count, placement on both sides of the share, the new flag, a soft-clip placement fix), and it decided that a listed input allele was absent, against invariant 7. Kept instead: rule X, and its cost counted rather than hidden: the given count's reads that end before the first difference stay partial evidence at a listed count no molecule carries (the S1 rows in the listed form). Bar 7 of the spike-in arm counts them by class and depth (docs/harness/spike-in-297.md). Contract tests: tests/test_unit_count_contract.py, the last section (REJ-20261031-001 in .agents/learnings/REJECTED.md). Amended 2026-10-31 (#297 close, operator: option A throughout; the final review of rule X found four places where the branch departed from one principle, three on the rules path only; built as F1, F2, F3, F6, F7 and C1, one commit each, red first on both paths). The principle: a read is ALT only where its own confident bases carry the given ALT and tell it from every candidate (REF, every listed allele, each found allele that passes the presence test); a read that fits the ALT and another candidate equally is partial evidence; a read whose bases show another candidate is partial evidence (RJ-6). F1: a read is the deletion with its listed neighbour only where its confident bases show that neighbour's change (at one base or more past the first difference where the deletion with the row and the ALT differ, it reads the row's base); before, a row no read carried (a 1-bp deletion 270 bases past the junction, or an SNV) was a neighbour every tie read fitted, and 6 tie reads became ALT on the rules path, (RD, AD, partial) (6, 0, 6) to (6, 6, 0), the sequence judge staying (6, 0, 6) (RJ-28: a row's count must not depend on an input row the read does not carry); HG002 4:3610329 is unchanged. F2: a listed count whose first difference lies past every read's reach is held on both paths: the reads that cannot tell are partial evidence, (6, 12, 0) to (6, 0, 12) on the rules path, and the row is named UNIT_COUNT_UNSPANNED; the cost is a row with AD 0 until a read can tell (HG002: two rows lose their ALT reads on the rules path, a 154-bp deletion, ALT 15 to 0, and a 51-bp one, 5 to 0; the sequence judge already counted 0 there). F3: a read whose own bases spell an unlisted other count in full (fitting it but for one base past the windows, showing its base at two or more of the bases where it and the ALT differ and the ALT's at none, and REF read the same way worse by two; one test, spells_in_full, for the fragments tallied for the floor and for the hold of a read) is never ALT whatever the floor: partial evidence where the aligner places it here alone, depth only where it doubts its placement (RJ-29; the side the window was read from decides nothing, so a read placed from the right flank is partial too: operator, 2026-10-31); the floor of 3 fragments and 5% decides only the reads that cannot tell (two such reads beside the given count gave AD 14 against the judge's 12; four doubted ones, 16 against 12). The sequence judge leaves such reads depth only (an allele under the floor is no state): AD agrees on them, partial_alt does not. F6: the presence test reads each read's qualities as the hold does (heuristic BAQ where it applies, inside the readable range, so in RNA a clip reaching an exon edge is left out), not the stored qualities over the whole read (invariant 2); the guard's own tally of recurring changes still reads stored qualities. F7: "within a read's reach" is the first difference and the 24 bases the spelling test reads (it was the first difference and 4): an unlisted count that first differs 4 to 23 bases before the longest read's end, which no read could spell, is now named; bases in the flag is larger by 20 everywhere. C1a: one presence test, RJ-25's, stated once (carrier::is_found: 3 fragments and 5% of the fragments spelling the allele it is nearest) and asked by the exact-carrier guard, the junction guard's other unit counts and the sequence judge's found alleles; before, the judge counted reads (both mates) against 5% of all the site's reads, the junction guard 5% of the fragments that tell the ALT from the allele, so under the judge an unlisted unit count was a state if either test passed. C1b: one tolerance, RJ-27's (carrier::one_error_forgiven: one error against three misses), for the carrier rule and the junction judge's telling. Measured on HG002 (public; c246, tr, sub, nocl; each change against the build before it): F1 4 reads on 2 rows (ALT to partial, rules path); F2 46 reads on 2 rows; F3 4 reads on 4 rows; none of the three moves the sequence judge's counts. C1a moves nothing on the rules path and, under the sequence judge, 101 reads on 25 rows of the four arms (18 distinct): of the 447 found alleles weighed on the sub arm 6 change, 4 stop being states (3 reads from 2 fragments met the old floor of 3 reads) and 2 become states. F6 and C1b move nothing; F7 changes names only (no count). Amended 2026-10-31 (#297 close, round 2, operator: make the two fixes now; the judge's wrong-length read goes into #331; F4 is named as a limit of the rules path). A read placed from the right flank (the windows' first base in its left soft clip or under its own deletion) that spells an unlisted other unit count in full is partial evidence like one placed from the left: the hold's placement clause is gone, so the aligner's doubt (RJ-29) is the only depth-only case (RJ-24: a read placed from the right flank is ALT where it fits, else another allele). The sequence judge's presence test divides by the allele the found one is nearest, and mates that disagree count for neither (RJ-25). Measured on HG002 (public; c246, tr, sub and nocl, both paths; the local build of 697b6c25 reproduces the HPC batch on all 52,378 rows): the right-flank change moves no read; the judge's presence test moves nothing on the rules path and, under the sequence judge, 37 read calls on 8 arm rows (6 distinct rows), 7 of them (5 distinct rows) in the counts. Four rows lose a found allele as a state because a fragment telling it has mates that disagree (3 fragments become 2: chr10:92524445-47 and chrX:297274), one row gains one (chr4:660975, a 106-bp insertion: a 4-base insertion told on 3 fragments against the 2 fragments of REF, the allele it lies nearest, so 11 of its 79 ALT reads become partial evidence), and one read moves from depth to partial evidence (chr18:74617096). Named limits until the sequence judge is the default (#331): (a) under the judge, a read that spells a deletion of another length at X's anchor, below the presence floor, is depth only where the rules path calls it partial (RJ-7's own-indel rule looks only inside X's span, so the judge has no state to hold it as another allele); (b) F4, on the rules path: carriers of the deletion that also carry an unlisted 1-bp insertion are all held, because the telling test reads the read ungapped past the windows, where the judge places the read's own insertion as a separate event (RJ-8, RJ-27) and counts ALT the reads that reach the run's end ((6, 0) on the rules path against (6, 3) under the judge in test_a_listed_neighbour_makes_no_other_count). Amended 2026-11-02 (#297 close, the review of the pull request, operator: fix all three; each red first). (1) A listed pure deletion at the breakpoint whose REF runs past the reference prep holds for the row (a longer count of the run: a 600-bp deletion listed beside a 60-bp one before twelve copies of its unit, the reference ending 420 bases past the junction) was skipped, because its haplotype cannot be built there (the bases after its last deleted base are not held), so the given count's short carriers stayed ALT, against rule X. It is now an unresolved candidate: no read can be shown to tell it from the ALT, so it is held on both paths (the reads that cannot tell are partial evidence: on the rules path (RD, AD, partial) (6, 6, 0) to (6, 0, 6) in that shape, with 150-bp reads; the sequence judge already held them), it lies past every read's reach, and it is named UNIT_COUNT_UNSPANNED where it is the nearest count on its side. Where the bases held already differ from the ALT's inside the junction windows (a listed deletion from inside the run), a read of the ALT is told from it there, as from any allele, and nothing is held, as before. Named limit: where the reference past that deletion would tell the two counts apart (a flank that does not repeat), the rules path holds all the same, and the sequence judge, which reads the reference around the listed row, counts the carriers ALT: a 500-bp deletion listed beside a 60-bp one, (6, 0, 6) on the rules path against (6, 6, 0). Reading the bases from the listed row's own prepared reference would remove the difference; it is not built (a new condition, and the close's stop rule). (2) Memory: the alleles at the breakpoint were built whole (their bases to the first difference and 300 more, and their row, every deleted base) before the reach test; beside a long simple repeat that is half of the shifts, each thousands of bases long, so memory grew with the square of the deletion (a 24-kb deletion before a 24-kb (AC)n repeat held 580 MB for them, 805 MB peak through the engine; a 60-kb one 4.0 GB). The reach test now comes first: an allele past the longest read's reach keeps its length change and first difference (what the diagnostic names and what orders the nearest count), and its bases only up to the read's end where the listed-neighbour test reads them; a listed row that is the same haplotype brings its bases and row back. No count or flag changes: the 24-kb case peaks at 101 MB, a 100-kb one at 131 MB in 2.6 s. (RJ-25 holds the third change of this date, the mates.) Measured on HG002 (public; c246, tr, sub and nocl, both paths, 26,189 rows each; the local build of 8e9364e4 against each fix's build in turn): no row and no read call moves on any arm, for any of the three. |
C40 #254, operator 2026-10-09, 2026-10-13; #285, operator 2026-10-17, 2026-10-18; #297, operator 2026-10-30, 2026-10-31, 2026-11-02; operator 2026-11-02 |
| RJ-25 | A read counts for an allele only where its bases tell it from every other allele that may be at the locus; one that cannot fits either. | Current rule, 2026-11-02 (#394, #398; operator: option B, "tell what the read reaches"; reverses the REF clause decided on 2026-10-14). Both paths. (1) Candidates. Every listed allele whose span meets X's site (the sequence judge's meets: the REF spans overlap, an insertion's being its anchor; two rows that change the length meet where the runs they slide over overlap) is another allele there, always. The floor for a listed allele is removed (it asked one fragment and 5% of those spelling the allele it is nearest, 2026-10-14): the input is taken as correct (invariant 7), as rule X took it for another unit count at a long deletion (RJ-24, 2026-10-31). So a component of an MNP that no read shows apart from it is another allele too, and a carrier that reads only the component's base cannot tell the MNP from it: partial evidence (AD 14 to 10 in that shape). The presence test for an allele nobody listed (3 fragments and 5%, carrier::is_found) stays. A listed allele is a candidate where it differs from X inside the window X's own windows hold (one flank base each side of a pure indel, two of any other event; see (5)). (2) ALT. A read counts ALT only where it tells X from every other allele of X's length; a tie is never credited. SNV rows beside a listed length-changing allele are judged by their bases (the sequence judge), also under the rules (operator, 2026-11-03; #398). An SNV row (one base differing, after trimming: REF and ALT one base each, or a same-length row kept with its padding) where the same input lists an indel or delins whose REF span meets the row's site (its prepared span) (the judge's meets, after its beside step, which moves a pure indel anchored on the row's base to the next base, where it no longer meets) is counted by the sequence judge, as --read-judge sequence would count it; every other row keeps the rules. Prep decides it from the whole input (Variant::judge_routed, with the rows in the row's reach recorded), so no bin geometry, call or other row changes it; no column, flag or environment variable is added. Why: the rules' SNV check reads one base and weighs no listed allele that changes the length, so a read that spells such an allele counts ALT, while the judge holds the allele as a site state and calls the read partial evidence. Measured at the class rows (the rules lane against the judge lane of one build, 2026-11-03): patient sets, oracle v3, wrong-ALT reads (the oracle says another allele) 1,230 to 0 and wrong definite calls 1,258 to 7; HG002 (phased-haplotype truth), true ALT credited 454 to 520 and reads of the listed allele credited ALT 142 to 21; the judge adds no wrong-ALT. Precedent: a deletion of 50 bp or more already goes to a by-bases junction judge (RJ-24). MNV rows stay on the rules: they have 0 wrong-ALT on both paths, and 67 true-ALT reads at one MNV-plus-insertion shape (a 2-base MNV, an 18 to 19 bp insertion anchored on its first base, the reads carrying both) would go to partial (#331). The rules still count a routed-class row in two places, each with one warning per count: RNA mode (the judge does not judge spliced reads yet) and a count given no reference FASTA (the judge reads each row's candidate sequences from it). An earlier build took the read out of AD when the listed allele's own exact-carrier rule called it ALT: it removed reads that carry X (15 true-ALT reads on one HG002 row, because that rule ran without the listed allele's own guard), and was withdrawn. A listed allele of the row's own length that holds the row's change keeps counting its carriers at both rows (RJ-28). (3) REF, reversing the clause of 2026-10-14. A read counts REF where its confident bases tell REF from X and from every REF-length allele whose difference its span reaches (its span overlaps the allele's first to last differing base, measured before the guard's masks; see (5)). An allele past the read's end, or before its start, does not contest it: a read ending inside a long event is judged by the bases it has (RJ-9). Reached and not told (the base unread, below --min-baseq, or masked), the read is neither, without partial evidence, save a read that is ALT for a co-annotated sibling there (RJ-5). This is the sequence judge's reach rule (a read short of the difference shows REF; docs/proposals/sequence-judge.md), written here and built into the rules path; the judge's own-gap tie-break stays the judge's alone and narrow (decided 2026-10-27, REJECTED.md). Why the clause of 2026-10-14 went: it made a read that ends before a listed allele's difference neither, so RD and VAF moved by a read geometry that X's own molecules never meet (a REF-side molecule at a 30>2 delins: RD 80 to 30 with the floor removed), while the judge, which ties by reach, kept those reads. (4) Long events. A delins that replaces 50 REF bases or more has a core (RJ-24, amended 2026-11-02). (5) Two corrections of this rule, 2026-11-03 (rq1; operator; both are bugs against the text above, no new rule). (a) The candidate test reads the window X's own windows hold: one flank base each side of a pure indel, two of any other event (Event::flank). The first build read two flank bases for a pure indel as well, so a listed delins that is X plus a substitution at the second flank base entered as a candidate whose window equals X's: no read could tell the two apart and every carrier went to partial (AD 106 to 0 at one panel row, a 1-base insertion in a 4-base run). A listed allele that differs from X only past the window is weighed by the whole read (RJ-5, the sibling claims), not by the window. Named limit (#418, the same on develop): the rules path's REF side weighs only listed alleles that differ inside X's window. With X = CA>C at 100 and a listed padded row S = AGT>AGC at 101 (S changes only base 103), a REF read with Q5 at 103 is REF on the rules and neither on the judge, which holds S as a state. (b) The reach of a REF-length allele is measured on its difference from REF before the guard's masks: a mask hides a base from the windows, not from the read that spans it, so an allele that differs from REF only at masked bases still contests a read that spans them, and the read is neither (as before this decision). Its reach is measured on the whole difference from REF before the masks in every branch (first to last, over the window), also where the window shows a part of it: a REF read that covers a masked base of the allele and ends before the base the window shows is neither. A found allele's carriers hold the background at the masks; that is no difference of the allele's own, so it does not widen the reach (a listed allele is as the input gives it); an allele found with differences at the masks alone keeps them, which is the HG002 shape of the first correction. Stopgap tied to #418: a found allele's background bases are left out of its reach only where the allele also differs at an unmasked base inside X's window; where its only differences inside the window are masked, those differences are its reach. Without it HG002 c246 INS 1-9 gets 185 true-ALT reads called REF against develop's 182, because the allele's one unmasked difference lies outside the window. It goes when #418 is fixed. Measured on HG002 against f3c6565e: the rules lane moves 1 row and 14 read calls (neither to REF, the found allele's background no longer widening its reach); the judge lane none; c246 INS 1-9 true ALT called REF stays 182 (develop 182); the 1,302 class rows still equal the judge lane (15,933 read calls). The span follows the windows' edits (a separate indel, a trim). The first build found no difference in the masked window, took the allele to contest nothing, and called such reads REF (13 read calls at two HG002 insertions, 5 of them true ALT). The MNP check (tells_others_aligned) measures it the same way. Measured on HG002 (public, local), the corrections against 70768eed: the rules lane moves 8 arm-rows (6 distinct rows, five insertions and a deletion) and 91 read calls, all REF to neither (c246 73, tr 9, nocl 9), and c246 INS 1-9 true ALT called REF goes 185 to 182 (develop 182) and INS 10-49 28 to 26 (develop 26); the judge lane moves no row and no read call; the 1,302 class rows still equal the judge lane in every MAF field and in every read call (15,933). Contract tests: the made-up panel shape of (a), six cells and a guard cell that B still moves, in tests/test_ref_reach_contract.py; an_allele_whose_difference_inside_the_window_is_masked_still_contests_a_ref_read_that_reaches_it in carrier.rs. (6) Where the paths still differ. At a delins X row the rules need the read to hold X's whole window (the event and two flank bases each side): a read that starts or ends inside the event, or within two bases of it, is depth only (RJ-1, RJ-2; RJ-9 reads a read ending inside an event by the bases it has only for an event over 50 bases, from a junction), while the sequence judge counts what the read covers. Made-up reads that end inside the replaced span: a 25>20 delins, RD 30 on the rules against 45 on the judge; 60>30, 36 against 45. It is older than this decision (the same on develop). Closing it would be a third REF rule (a read-covers rule on the rules path, for REF and ALT); it is ticketed under #331. The unlike rows of rq2 (all inherited from develop, none from B): an MNV row beside an overlapping MNV (rules: the neighbour's base is neither REF nor ALT, neither with no partial; judge: partial, and one lone off-base read a tolerated error, RJ-26; #410); deletion rows by three causes (the read must hold the window, RJ-1 and RJ-27, against read-covers, with the delins gap, #414; a listed change 0 to 3 bases past X's right end, where the rules call the cis carriers partial and the judge ALT, #417; a deletion just left of the window, a separate event and ALT on the rules, RJ-8, partial on the judge). Supersedes #394's option A on the judge (every REF-length allele a tie to neither): not built. Worked row (shapes only): a 30>2 delins X with a listed SNV at its 20th replaced base, S spelled on 6 fragments that hold the whole REF window, 20 carriers, 30 REF reads that reach S's base, 50 that end before it; (RD, AD, partial) rules (30, 20, 6), judge (80, 20, 6) before; (80, 20, 6) on both after. Measured: HG002 (public; arms c246, tr, sub, nocl, the delins arm and the compound-het arms; 27,589 rows; --min-baseq 20; develop 3b63e6d0 against this change, each path). Rules path: 598 arm-rows change (c246 113, tr 49, nocl 424, compound-het 12; sub is nocl's subset and the delins arm moves none; 87 without the routing). The routing changes only class rows: of the 662 arm-rows it changes against the same build without it, none is another row. At the 1,302 class rows (c246 123, tr 42, nocl 1,137; sub 240 inside nocl) the rules lane equals the judge lane in every MAF field and in every read call (1,735, 858, 2,154 and 11,186 reads at c246, tr, sub and nocl). Read calls on the rules path against develop: ALT to neither 899, REF to neither 1,240, neither to REF 193, neither to ALT 311, REF to ALT 182, ALT to REF 1: the judge's calls at those rows. Phased truth at the class rows (strict view, c246 + tr + nocl, 1,251 scored reads): true ALT credited 454 to 521 (95 gained, 28 lost), true ALT called REF 96 to 15, reads of the listed allele credited ALT 142 to 21 (496 become partial evidence). Truth v2dbq20 at the scored targets: true ALT credited 30,455 to 30,457, true REF called REF unchanged (21,670), true ALT called REF 1,339 to 1,336, undecided reads credited ALT 2,584 to 2,534 and REF 3,577 to 3,557; truth v2db: true ALT credited 30,520 to 30,519, true ALT called REF 1,436 to 1,432. Judge: 49 arm-rows change (c246 16, tr 3, nocl 30: a listed substitution beside a deletion or insertion is now a state always), and 2 reads go from neither to ALT at one SNV row; truth classes equal. Counting invariants: 0 breaks in 55,178 rows over the two lanes. Rules and judge give the same (RD, AD) on 16,161 of the 27,589 rows (15,551 before). Wall time on HG002, 4 threads, untraced, develop to this build: c246 1.6 to 2.2 s, tr 1.4 to 1.6 s, sub 2.1 to 4.5 s, nocl 3.6 to 9.0 s (the judge costs about 10 ms a class row beside a deletion of 50 bp or more; the speed work is the speed phase's). The patient sets, ACCESS, the normals, WES, RNA and the spike-in are not measured here. Contract tests: tests/test_ref_reach_contract.py, tests/test_listed_sibling_floor_contract.py, tests/test_locus_alleles_contract.py. The history of the row follows; where it says a listed allele needs the floor, or that a REF read short of an allele is neither, this paragraph overrides it.) (Amended 2026-10-31, #297, rule X, operator: at a pure deletion of 50 bp or more, another unit count of the same run that the input lists is always one of the other alleles that may be at the locus, whether or not a read shows it, on the rules path and under --read-judge sequence; the floor of 3 fragments and 5% below finds only alleles nobody listed. RJ-24 holds the detail. Amended 2026-10-31 (#297 close, C1a): that floor is one test, stated once (carrier::is_found): the fragments spelling the allele in full number at least 3 and at least 5% of the fragments spelling the allele it is nearest. The exact-carrier guard, the junction guard's other unit counts and the sequence judge's found alleles all ask it; the sequence judge counts fragments (a read's mates are one; mates that disagree, one telling the found allele and the other beaten, or beaten by REF and by X, spell neither and count nowhere, as the guard's conflict) and takes as the nearest allele's fragments those a given allele scores best on, one read-scoring margin over the found allele: REF's where the found allele's haplotype lies nearer REF's (by the bases that differ over the window, the guard's masks fitting any base), X's where nearer X's, the larger of the two where as near. Amended 2026-10-31 (#297 close, round 2, operator): before, it took every fragment either given allele beats the found allele on, the REF fragments of a site included when the found allele lies near X, and so asked 3 fragments of 5% of the whole site.) A read that fits the ALT counts ALT only when, for every other allele of the ALT's length at the locus, it reads a base where the two differ, as the ALT's base and at or above --min-baseq; otherwise it is that allele or the ALT, neither with partial evidence. The other alleles are the co-annotated siblings that spell one (until 2026-11-02 a haplotype of the ALT's length differing from it inside the event and nowhere past two bases beside it; now every listed allele of that length that meets the site and differs from it inside the window) and those read in full on 3 or more fragments and on 5% of the fragments spelling the allele they are nearest, REF or the ALT (the larger when as near: an allele recurs above the errors of the molecules it could be an error of; nearness and spelling are read past the guard's masks, and for an MNP past the bases beside its own), by the variant's own reads' bases placed from the left flank as the windows read them, not where the aligner wrote the gap (the event and two flank bases each side read; for an event changing the length, the ALT placed that way fitting the eight bases past it but for two, and no worse than REF placed the same way). An allele whose every difference from the ALT is a change from the reference the REF molecules carry too, at a base the event keeps (on 3 or more and 5% of those reading it: a separate event on both haplotypes), is not another allele, co-annotated or not; the reference's own base is no such change, so an allele lacking part of the event (the germline haplotype beside a somatic change written as one MNP) is one. Nor is one differing from the ALT only where the guard masks (background, or the ALT reads' own isolated change): that is the ALT with a separate event, which no read could tell from it; nor, for an MNP, one differing only beside the MNP's own bases: with nothing to place, that is the ALT with a phased neighbour, named as beside any event. REF and ALT molecules are told by their bases as well (read through eight bases past the event, at most two changes beside it, and for an event changing the length fewer mismatches over the event and past it than the other allele placed the same way), so a carrier aligned with its gap outside the event, or shifted into a run past it, is never a REF molecule, and where the bases past the event repeat themselves the event's own bases tell the two apart. Where the reads show no other allele nothing changes: a carrier reading only the event's length, or an MNP read with a differing base below --min-baseq, counts ALT. Every read the MNP check calls ALT follows the same rule (one leaving a differing base unread, and one spelling another allele where the ALT keeps the reference's base, which that check does not compare), and a decomposed form counted beside the row reads the same other alleles. Amends RJ-4, and RJ-5 for siblings of the ALT's length (judged by the bases a read holds, not only by a claim). A pure insertion keeps RJ-20 until C43 judges pure indels by their bases. Amended 2026-10-14 (operator): REF alike, a read that fits REF counts REF only when, for every other allele of REF's length at the locus, it reads a base telling the two apart (found as for the ALT, from the REF molecules' window; not another allele: one whose every difference from REF is a change from the ALT's base that the ALT molecules carry too at a base the event keeps, a separate event on both haplotypes, the ALT's own base being no such change; at a base the event changes the ALT molecules may be a third allele's); otherwise it is neither, without partial evidence, save a read that is ALT for a co-annotated sibling there, partial evidence as RJ-5 says. [Reversed on 2026-11-02 for an allele the read does not reach: see the current rule above.] A co-annotated sibling is another allele only where the fragments spelling it in full (past the masks) are at least one and 5% of those spelling the allele it is nearest: a component of the event the reads never show apart from it (an SNV sign-out reports beside its MNP) is part of the event, not another allele, and at depth one error read spelling it shows nothing (the annotation lowers the 3-fragment floor, not the share). [Removed for listed alleles on 2026-11-02: see the current rule above.] Amended 2026-10-29 (operator, #304): under the sequence judge each allele the reads spell is a site state written as the bases it changes, past the guard's masks (the allele's own base where a mask takes a carrier's), as its spelling is read above: it holds no masked base as its change, so the masks stay on every state, and one that so written is a candidate the site already holds (the ALT with a listed neighbour beside it) is that candidate; spellings apart only at a mask are one allele. Written over the window with its carriers' bases, an allele held a masked base as its change and took from X and REF every read carrying the masked change, by that base alone (a 17-base duplication whose carriers all carry a listed SNV past the copies, with recurring changes masked beside it: 293 carriers per run partial). Amended 2026-10-31 (#297, operator: rule X; option (b) rejected): the floor of 3 fragments and 5% is not applied to a listed other unit count. Option (b) applied the sibling rule's share to it (present only where at least 1 fragment shows it and 5% of those showing either do; absent, and no state at the row under the sequence judge, where 3 or more deciding fragments tell the two counts apart and show none of it). Measured against the batch of 444ce886: no count changed on the patient sets or HG002; on the spike-in arm +141 S1 reads, 4 to 12 reads of the other allele credited ALT, and false-absent rows (chance at 3 deciding fragments, 2^-n at equal haplotypes; BWA soft-clipped deciders failing the placement test). It decided that a listed input allele was absent, against invariant 7. A listed allele stays a candidate; what RJ-25 asks of a read stays the same: its bases must tell the allele from the ALT, or it is partial evidence. Full record in RJ-24 (REJ-20261031-001). Amended 2026-10-31 (#297 close, C1a): one presence test. Three places decided whether the reads show an allele nobody listed, with three bars: the guard's (this row's text: 3 fragments and 5% of the fragments spelling the allele it is nearest), the junction guard's for other unit counts (the same, over the fragments that tell the ALT from the allele, written out a second time) and the sequence judge's told floor (reads, not fragments, and 5% of all the site's reads, not of the nearest allele's); under the judge an unlisted unit count met the last two, and the lower bar won. This row's text is the guard's, and carrier::is_found now states it once for all three. Measured on HG002 (public arms, against the build before): nothing moves on the rules path; under the sequence judge 101 reads on 25 rows move (18 distinct), 6 of the 447 found alleles weighed on the sub arm change their state (4 stop being states: 3 reads from 2 fragments met the old floor of 3 reads; 2 become states: 3 fragments against the 27 and 31 that a given allele beats them on, where the old floor was 5% of 91 reads). Round 2 (operator, 2026-10-31) divides by the allele the found one is nearest instead, and counts mates that disagree for neither; its effect on HG002 is in RJ-24. Named limit (operator, 2026-11-02): the share is taken against the allele the found one is nearest by its bases; where that allele has almost no fragments (a homozygous ALT site with few REF fragments), the 5% share cannot fail and the 3-fragment floor decides alone. A found allele that is an error of the ALT's molecules (an insert read short) is then present, and reads that fit it and the ALT equally are partial evidence: HG002 chr4:660975, a 289-bp insertion under the sequence judge, 3 fragments spelling a 4-bp insertion against 2 REF fragments, 11 true-ALT reads to partial (RD, AD, partial (0, 79, 2) to (0, 68, 13)). Amended 2026-11-02 (#297 close, the review of the pull request, operator: fix all three). A fragment whose mates disagree counts for neither also when the mate that tells the ALT ends before it holds the allele in full (fewer than 24 bases past the first difference): it still tells the ALT by the bases it reads where the two differ, and a mate that spells the allele in full contradicts it. Before, that mate's telling was dropped with the length check, the fragment counted as spelling the allele, and three such fragments found it and held the given count's short carriers: three fragments of a full mate spelling the two-unit count and a 90-bp mate telling the given one gave (RD, AD, partial) (6, 3, 15) on both paths, and give (6, 15, 3) on the rules path and (6, 15, 0) under the sequence judge. A short mate that tells the ALT alone still adds nothing to the share (it does not hold the allele in full). On HG002 no row and no read call moves (RJ-24 has the measurement). Measuring the share against the allele the found one could be an error of is #401, before the judge becomes the default. |
C43 #277, operator 2026-10-14; #304, operator 2026-10-29; #297, operator 2026-10-31, 2026-11-02; #394 (superseded), #398 (SNV rows routed to the judge), operator 2026-11-02, 2026-11-03 |
| RJ-26 | One mismatch on one read is most likely a sequencing error and costs both alleles alike; the same change recurring across fragments is a real allele. | One substitution in a read is an error, on REF and ALT reads alike: a read whose bases fit an allele but for one confident mismatch, where the other allele's reading mismatches that read base too (past the shorter allele's window, the reference's continuation, which both alleles share), counts for the allele its other bases show; the error costs both alleles alike in its evidence (RJ-16). An allele tolerates it only where the read writes that allele's length (no length change for REF, the ALT's for the ALT) or a separate event judged on both. Inside the event, or at a base the input names (the anchor), the substitution is no error when it recurs: on 2 or more fragments and 5% of those fitting the allele it is another allele at the locus (partial evidence when nearer the ALT), found from the variant's own reads. In the flank a shared substitution is a phased neighbour (RJ-23) and the reads keep their call, so the ALT written far off with a substitution in its flank is ALT. Amends RJ-16, RJ-22 and RJ-23. | #278, operator 2026-10-15 (D3, D4) |
| RJ-27 | A pure indel in a repeat is defined by its length over the tract, so a read must hold the tract and read past it, and its own indel is placed where its bases fit, not where the aligner wrote it. | Current rule, every amendment below applied (2026-11-03). The base rule below holds, but for two things under the sequence judge at a pure insertion of 50 bp or more (RJ-23, amended 2026-10-30): where the guard's masks hide every base telling the alleles apart, both windows read on to the next unmasked base that does, REF and ALT alike, and a read short of it is depth only, a REF read as a carrier (the exception below for a read short of that base fitting one allele alone and exactly does not apply); and the masks are read on every haplotype alike, another allele's too (2026-10-31), by the columns of the path a read lies on, the same for every candidate, the listed or found changes it carries counted, and so is the length the windows read on to (2026-11-02). A carrier ending at a masked change in cis with such an insertion is depth only (the named limit below). The base rule and its amendments, oldest first: A pure insertion or deletion prepared against the reference is judged by its reads' bases (the exact-carrier rule), the CIGAR checks only where the rule cannot judge it. Its windows are its tract, where REF and ALT differ over every placement (the anchor no part of it), grown through the repeat its change lengthens or shortens (on the allele holding its bases: the ALT for an insertion, REF for a deletion; other lengths of that repeat are other alleles a read must span it to tell apart), with one base each side; a repeat on the other allele only is beside the change (operator, 2026-10-16). A read holds the shorter allele's window and reads on through the longer one's, so one ending inside the tract is depth only (RJ-1) and one ending a base past it decides; a read whose first base is its anchoring flank but unread or not the reference's is placed from its other flank (RJ-3). The read's own indel inside the windows, or the nearest within 64 bases, is placed by its bases, from the windows' first base to its end, next splice or next indel, where they fit the reference with it best (the fewest mismatches over the same reach, one at most): inside the discrimination window (its tract with a base each side) a change of the ALT's length spelling the ALT (one error aside) is the ALT, the windows anchored where its bases put them, never REF; any other is another allele (partial evidence); placed only outside, it is a separate event, applied to both windows (RJ-7, RJ-8, RJ-21, RJ-22). An insert with no readable base sits where written (RJ-20); inside the window, of the ALT's length, it is the ALT. A read whose readings fit both alleles, or miss both alike, is read on past the windows to its next indel; one placed from its reading flank that fits the ALT though its bases place no length change (it writes none, or one they place nowhere) is read on too, and stays ALT only where its further bases fit the ALT better than REF. Where masks leave no base telling the alleles apart and both windows read on to one that does, a read short of it is held as far as before and counts where its own bases fit one allele alone and exactly (a clean REF read showing the reference's base where the masks take either). A fit resting on fewer bases than tell the alleles from those beside them is confirmed past the windows, where another allele's bases, shifted by its other length, show (one base past the tract may be another allele's extra base, the flank's twin): for the ALT where the read's own bases place no change or another one, a pure indel's REF where the read writes none, and either allele's fit on a tolerated mismatch, the read's bases from its first mismatch (or the window's end) must not fit the allele shifted by up to 8 bases better, by two confident bases, than as they stand where two or more mismatch: a shifted read is another allele, while a phased change beside the event (a DNP on every carrier) mismatches at its own bases under any shift and keeps the call. A deletion whose every base between the flanks is masked is ALT where its confident flanks lie the ALT's length apart (RJ-15). A change the REF molecules carry inside a deletion's deleted bases, single or several, is background on REF (RJ-23); the given allele's own bases are never masked. A spliced read is judged on its spliced reference (RJ-19), spliced inside the windows or past them within their reading on, so it reads on along its mRNA (the next exon's bases decide), and read from the left where the exon edge cutting the flank is its own junction; an exon end where the event starts leaves the left flank whole (RJ-23); an unspliced read starting at an exon start that cuts the left flank, or within the five bases of overhang an aligner writes into the intron as mismatches, reads the windows up to that edge, as a spliced read does (on its mRNA the bases before it are the previous exon's, so a run crossing the junction is read from inside), while a pre-mRNA read through the intron reads its bases as they are. Soft-clipped bases are read (RJ-13). A read whose insert is a shorter slice of the ALT's, the reference after it, shows another length: another allele, not a truncated ALT (the CIGAR path's identity band stays only where the rule cannot judge; operator, 2026-10-16). Mates that disagree resolve by quality, as for every bases-judged call (none is structural). A call whose held bases are all below --min-baseq takes the quality of the bases it read. Amended 2026-10-20 (#294, operator; for every event the rule judges, complex ones too): where the guard's masks hide every base telling the alleles apart, prep fetches on until the windows, every base the guard could mask masked, read on to one from either flank, so the rule judges the variant instead of the CIGAR checks; a read short of that base is held as above. A change the REF fragments show as their most common change there (background, or on more than 1% of them) that gives the reads the ALT's own base, shifted onto them where the aligner wrote no length change (the base an ALT read placed from the event's far flank shows past the shorter allele's tract; a germline SNP may give the same base), is told by the fragments placed apart from the event: those reading it whose bases, where the reference and that shifted ALT differ past it (aligned with it, no length change between), show the reference's more often than the shifted ALT's, overlapping 300 bases each side of the variant's REF span (or its read window, where wider). Where three or more of them carry it, and 3% of them (above the errors at one base: random ones, and most systematic ones), a haplotype holds it, read as the ALT over a short read: masked as background, at whatever share of the REF fragments; unless the carriers' pair orientations (read 1 forward and read 2 reverse, or the reverse), against the balance of all the reads placed apart, are too one-sided for a haplotype's (a binomial chance under 0.1%, where each orientation holds a fifth of the reads placed apart): a haplotype's molecules are read in both orientations, an oxoG or FFPE artifact sits in one (operator, 2026-10-21; a library read in one orientation, as an amplicon's, weighs none; eight carriers all one way are a haplotype's chance, twelve are not). Where the change is left unmasked though two or more of them carry it, over 1%, gbcms_diagnostic names it, POSSIBLE_MINORITY_HAPLOTYPE (the counts stand; one carrier is an error's). Otherwise, where 15 or more read it, a background change there is the ALT's own base on reads placed through the event: not masked, and spelling no other allele. With fewer, it is masked where it is background. An error both readings share decides nothing: a read whose bases place no length change and whose two readings miss exactly the same confident bases is read on with those bases unread, never counted for the allele that tolerates the error for the length the aligner wrote. Read on past the windows, where the alleles differ at most bases (the other shifted by its length), one confident error past them the other allele's reading does not share is forgiven where that reading misses three or more, the read writes that allele's length (as within the windows), and the error is a one-off: recurring as RJ-25 counts a tolerated substitution (on two fragments and 5% of those fitting that allele) it is another allele's base, never forgiven (operator, 2026-10-21). Within the windows only a shared error is tolerated (2026-10-15): there one base may be all that tells another allele of the same length. A read the aligner placed a unit or a copy off is read whole: one whose alignment is not clean (another event inside the discrimination window, or one no placement fits, RJ-7; or, placing no length change, two or more confident changes from the reference within 300 bases of the variant's REF span) and not spliced is placed ungapped on each allele, every readable base of it, over 300 bases past either end of where the change can be placed (at least the prepared reference; prep holds it apart from the reference the windows read), the guard's masks taking their bases as in the windows. An allele fits where its windows read exactly and at most one confident base past them mismatches; the read is that allele where it fits so and both the other allele (its event's bases open, weighed wherever the read holds as many of its bases as the shorter allele's windows, from either flank) and every other allele at the locus (RJ-25, each taking the masks where its base is one they take) miss by more. A read fitting the shorter allele's whole windows exactly and the longer allele only from inside its event is depth only (RJ-23); otherwise, and where its own bases place its indel outside the windows (RJ-8) or the ALT's change inside them, or the windows judge its change as written, the read keeps its call. A call decided past the windows (where the masks made both windows read on, or a read was read on past readings that tell nothing) rests on bases read where the aligner wrote the read, and in a repeat the other allele may hold them a copy over: it stands only where the other allele, the whole read placed ungapped anywhere on it over the same reach as the reference spells it, misses more confident bases than the called allele does (no mask is laid there: a base the guard masks beside the event may be the other allele's own shifted onto the reads written through it, as where a run meets another, and would let that allele fit them; HG002's 16-bp TC insertion at chr11:5794390, operator, 2026-10-22); where the other allele fits it with at most one miss and no more than the called one, the read is depth only (operator, 2026-10-22: HG002's 89-bp duplication on chr21, whose reads written through the copy fit REF where written and the insertion exactly a copy over, 2 of them counted REF). Every bin's fetch holds the reads the guard reads (its guard window). This replaces the decision of 2026-10-17 (#294) that a mask leaving no telling base is not applied: that counted a germline SNP's haplotype as the insertion (REJ-20261020-001). Named limits: the windows anchor on the exact repeat's edge (#290), so in an imperfect repeat (units differing at single bases) a read lying inside it, or read from a flank the repeat runs on past, is placed by the aligner, not by its bases, where the windows decide it (decided past them, it is placed anywhere as above): a carrier written a unit off fits REF as written, a germline SNP's read can read as one more unit, and a read whose bases, read whole, reach no unique sequence on either side keeps its aligned call; where 15 or more fragments placed apart read it, a haplotype carrying the change that shows on fewer than three of them, or under 3%, is taken for errors, and its reads, reading as the ALT over a short read, count ALT (with 30 to 45 of them, an SNP haplotype on 5% to 10% of the molecules in about a third of runs and on 15% in a tenth; at depth, any under 3% of the molecules, its reads adding to AD in proportion); these rows are named, POSSIBLE_MINORITY_HAPLOTYPE; a systematic error giving that base on 3% of the reads placed apart in both orientations, or in one orientation on fewer carriers than tell it from a haplotype (about ten), masks it, and the ALT's reads short of the next telling base are depth only; an ALT molecule carrying a compensating indel just past the windows, written as mismatches and with the windows' telling base unread, reads as REF with one error there and counts REF. Named limit (2026-10-30, #264; the sequence judge reads these masks on every haplotype alike): where a change the masks take is in cis with an insertion of 50 bp or more, past its run where reads written straight through it show its own base (HG002's duplications at chr21:41865095 and chr22:39653046, each with the SNVs that make its copies twins phased with it), a carrier ending at that base is depth only, as a REF read ending there is (both windows read on, RJ-23's amendment of 2026-10-30), though the phased truth places it on the insertion's haplotype; reading the base as the reference's on REF's haplotypes where REF's molecules show they lack it would credit the carrier on other fragments' evidence (REJ-20261023-001); it was measured with a temporary option in the round of 2026-10-30, not adopted, and the option is removed (operator, 2026-10-31). Amended 2026-10-31 (#264, operator): the sequence judge reads the masks on every haplotype alike in its code as in this text, another allele's haplotype included (RJ-23's amendment of the same date); the cis option named above is removed. Amended 2026-11-03 (RJ-31, #292): a splice lowers no base's quality, so the bases at a spliced read's junction are read at their own quality, and the clause "with BAQ masking the bases at its junction" is dropped (the bases it hid were the next exon's, which decide as before). Amends RJ-1, RJ-3, RJ-7, RJ-8, RJ-15, RJ-20, RJ-21, RJ-22 and RJ-23; builds RJ-13 for pure indels. Amended 2026-11-02 (#264 follow-up, operator): the sequence judge reads the masks on every haplotype alike by the columns of each path, in its code as in this text: a listed or found insertion or deletion between the anchor and a masked base moves that base's offset on every haplotype a read carrying it lies on, and the masks are laid there (RJ-23's amendment of the same date, which holds the rule, its named limit and what was measured). A read that ties the ALT with another allele must hold the ALT's equal window too (RJ-23, same date), and a read lies on one copy of the masks' zone for every candidate (RJ-23, same date). The cap on the sets of a masks zone (ZONE_MAX_ALTS, 64) is checked per state graph, not per site: in a graph whose zone, merged with the rows at one place there, has more sets than the cap, the zone is laid out as plain bubbles (a path may take two of its changes together, a haplotype more) and its masks stay at the offsets without those changes, while the other states' graphs are laid out by copy (a named limit; its behaviour past the cap is ticketed under #331). |
#278, operator 2026-10-15 (D1, D5, D6, D7, D8; groups B and C), 2026-10-16 (growth, D2); #294, operator 2026-10-20; #264, 2026-10-30 (named limit), operator 2026-10-31, 2026-11-02 |
| RJ-28 | A read's bases at a substitution's site show its change whatever else its molecule carries beside it, so a read carrying a longer allele that holds the change carries the change too; crediting it to one listed row alone would make a row's count depend on which rows were listed, not on the read's bases. | Under the sequence judge (--read-judge sequence), a read whose bases carry a substitution row's change at its site is that row's ALT, whatever else is listed: a candidate sequence holding the row's change there (an MNV listed beside its component SNV, or an allele the reads spell over a window) is the row's ALT, so a read carrying the MNV counts at both rows. At the MNV's row a read carrying only one of its components is another allele (partial evidence, RJ-25). The SNV's row names, per such MNV, how many of its ALT reads spell the MNV whole: MNV_SHARED(chrom:pos:REF>ALT:n/m) in gbcms_diagnostic, the overlap shown without changing AD or adding a column. Amended 2026-10-30 (operator, #304), its indel twin: a listed indel or delins that holds the row's whole change (the row with listed neighbours: a delins that is two listed deletions together) counts its carriers as the row's ALT, so one molecule counts at each row that holds it; the row names, per such listed row, how many of its ALT reads spell it whole: INDEL_SHARED(chrom:pos:REF>ALT:n/m) in gbcms_diagnostic, no count changed, no column added. Worked row (a patient panel row; allele shapes only): a 14-base deletion, a listed 7-base deletion four bases before it, and a listed 24>3 delins that is the two together; (RD, AD, partial) (747, 0, 129) → (747, 129, 0), the 7-base deletion counting AD 130 and the delins AD 125, so one molecule counts at all three; oracle v3 calls the 129 reads ALT, v2 a sibling or "either"; the rules path (746, 3, 126). |
#304, operator 2026-10-25 (phase D: O5, with the O3 diagnostic); operator 2026-10-30 (the indel twin) |
| RJ-29 | A read can fit none of the candidate sequences because it carries structure the given rows do not describe (a long clip, a large indel), not because it comes from elsewhere, so a misfit alone does not make it foreign; only the aligner's own doubt about its placement marks a read that may belong to another locus. | Under the sequence judge, a read whose best score over every one of the row's candidate sequences (REF, the ALT, the other alleles at its site, each with every context) falls below ten confident mismatches fits none of them. It is depth only where its aligner also doubts its placement (XS at least AS; MAPQ 0 where no XS is written); a read the aligner places here alone is judged by its bases at the row, as any other. The row names how many of its depth reads fit no candidate sequence: UNEXPLAINED_READS(n/m) in gbcms_diagnostic, so a row that may count foreign reads (a paralog's, reads placed at a homozygous deletion in a repeat) is visible without a new column. |
#304, operator 2026-10-25 (phase B: the fit rule, xs, with its diagnostic) |
| RJ-30 | A read's body can be a copy of a stretch inside a long listed insertion (an expanded repeat, a duplication) while its aligner placed it beside the insertion; all of an insertion's bases stand at its anchor's coordinate, so a band around the read's own placement that is not widened for the insertion cannot reach that path and stands on the placement's worse score. | Under the sequence judge, a listed insertion longer than the band's slack (16 bases) inside a read's reach (its span and its length each side) but past the window its band widens for (the slack and two bases each side) sends every state of the read to the full programme over its reach, and the linear aligner drops its band for the read. A deletion does not (a path to a far one pays the gap to it); insertions of 16 bases or fewer are left to the band. The site build uses the same scores. | #369, operator 2026-10-30 (the whole read); docs/proposals/sequence-judge.md §10 item 8 |
| RJ-31 | A splice moves no base, so it says nothing about the quality of the bases beside it; only a mechanism that misplaces a base (a piece too short for its own bases to place it, RJ-3) justifies masking one. | A splice never lowers a base's quality, with a GTF or without, in the main counts, the per-transcript counts, ASJD and the rescue re-count alike. Heuristic BAQ (--apply-baq, on by default in RNA) lowers by 20 only the five read bases each side of a read's own insertion or deletion, as before, and still spares the counted variant's own indel; a base is judged by its own quality against the run's --min-baseq, wherever it lies in the read. This reverses the junction penalty decided on 2026-05-04 (in effect for RNA since 4.1.0), which lowered the five read bases each side of every CIGAR N by 20: a base passed the bar only where its quality was 20 above it, so Q40 data passed at --min-baseq 20 and nothing passed at 30. The exon-edge exception (#106, R1) stays: at a variant within 5 bp of an annotated exon edge BAQ is skipped, and what it now lifts is the penalty of a read's own indels (on the synthetic set 89 of 1,072 rows differ without it, GTF, bar 30; no test sees it). Why: the penalty's strength was the instrument's quality bin and the run's bar, not a mechanism. Measured on 58 FORTE STAR slices (163,882 SNV rows in the first five bases of exons, 168,243 as the control band): clean rows (87,441) hold 0 ALT under every rule; at 219 germline hets the penalty hid 984 ALT reads (1.9%) at bar 20 and 38,541 (76%) at bar 30; at 100,278 DNA-absent low rows no junction penalty adds 16,243 ALT reads, 3.9%, the background rate. Indel and delins rows (41,112 in reach): clean rows 80 ALT reads under the penalty, 76 without; low rows 0.124% ALT under both. Delins ALT falls at bar 30 (280 to 173 reads in reach, 39 low rows 262 to 169), and that is right by bases: a base under the bar fits any allele, so with a junction's ten read bases masked a read could fit the ALT on the few bases left, whatever the masked bases showed. Measured on the FORTE slices with the builds before and after the change (p292d), the delins counts reproduce exactly (280 to 173), and the 117 reads that lose ALT at bar 30 are all spliced with the event 0 to 4 bases from the junction; 92 lie on a long piece (20 or more aligned bases), not a short anchor, and under B 91 of the 117 are REF and 18 partial evidence. So the fall is mostly REF reads the penalty had let count ALT, and only partly short pieces: a made-up read of a molecule spliced at a novel acceptor, written at the annotated one, whose 8 bases past it fit neither allele, counts ALT under A and partial evidence under B (3,616 made-up shapes at Q40: at bar 20 both rules agree, at bar 30 14 lose ALT, all short pieces, none gain). Community: GATK's SplitNCigarReads cuts reads at each N and changes no quality, HaplotypeCaller reads the pieces at full quality; htslib's BAQ (sam_prob_realn) returns before it changes any read with a reference skip; the ASE counters apply quality floors with no junction rule. No surveyed tool lowers a base's quality for lying near a junction. Options measured and not adopted (#292): keep the penalty (strength by instrument); spare it in the exact-carrier rule only (two quality gates for one base); skip BAQ on a spliced read whole, as samtools does (7 ALT and 1,476 REF reads differ from this rule); GATK's overhang clip (loses 8,515 ALT reads at hets for 899 gained, misses 128 of the 133 novel-acceptor reads); a short-anchor mask with a fixed cutoff (masks 1.98 million REF reads). REJ-20260925-002 (no N-penalty at annotated junctions only) is another rule. Limit (B's): RJ-3's short pieces, at a read's end or between two junctions (#409). Amends RJ-17 (the penalty no longer hid the partial deletion piece, which its own rule keeps depth only) and RJ-27 (the "BAQ masking the bases at its junction" clause). DNA reads have no junction: unchanged (a DNA identity batch is owed before merge). |
#292, operator 2026-11-03 (option B); #409 |
| RJ-32 | A read with no junction fits every transcript it overlaps, because no junction rules any out; a read with junctions fits only a transcript that has them (within 5 bases). | Per-transcript counts (RNA with a GTF): a read with no junction counts in the DP and RD (or AD) of each overlapping spliced transcript, and in the row's counts once; a single-exon transcript gets no per-transcript entry. A spliced read counts only in the transcripts whose introns hold all its junctions. Decided 2026-11-05 (operator): pins today's behaviour, no count changes. Measured: a row with two transcripts and 5 junction-free REF reads moves T1 from 4,20,36 to 4,25,41 and T2 from 3,6,11 to 3,11,16; the main counts count each of the 5 once. |
#344, operator 2026-11-05 |
Open¶
- REF credited on reads with a large clip that leaves REF nearly unopposed (#264's second
review, 2026-10-30; its own branch before the judge becomes the default, #331). At HG002's
insertions of 50 bp or more, of the judge's 167 REF calls on reads the truth cannot decide on
the tr arm, 65 are on reads with a soft clip of 30 bases or more: in 27 the readable bases stop
at the fragment end the pair gives (the clip past it taken for adapter), in 38 the read is whole
but most clipped bases are below
--min-baseqand weigh nothing, so a few confident bases decide REF against X by one mismatch or more (a 38M113S read: REF −4, X −29). Not decided: how a call weighs a read whose bases the candidates explain only in part.
Evidence behind RJ-4 (2026-09-25 to 09-28), #141. The decision is
the #141 comment of 2026-09-25;
the rounds are in the archived plan, .agents/archive/CYCLE_6.6.0_PLAN.md § C1. The ticket began as a
stale-score defect in the Smith-Waterman local fallback and became the exact-carrier rule once the
reads were adjudicated one by one (local data, aggregates only):
- 129 real reads took the fallback (40 signed-out complex variants in 40 IMPACT samples, SW
backend); 110 were linked exactly to their BAM read. 77 (70%) did not span the event (±1): 30 ALT,
10 REF, 37 tie. Of the 33 that did, ALT was right 23/23 and REF 3/4, and ties lost 2 ALT and 2 REF
reads that had a clear answer. 30 of the fallback's 53 ALT calls came from reads that do not span
the event.
- The first plan, flagging from the second try's (local) scores, was right for 32 of 67 REF/tie
reads against 36 as it stood: both flag on score closeness, not read content. A content rule on
ALT-specific 8-mers would demote 6 of the 23 true ALT carriers. The first round's 22 of 62
second-try ALT calls (35%) without ALT-specific sequence came largely from non-spanning reads
and detector misses.
- Every read at the 40 variants: of the ALT-like reads (at most 1 edit of the ALT over the event
±1), 3,276 (96%) carry the given ALT exactly over the event ±6, 54 are 1 edit off and 82 more than
1 edit off, and for 79 of those the same off sequence recurs (3 or more reads). Only 2 of the
fallback's 23 aligned-spanning ALT calls carry the given ALT exactly: it fires where end-to-end
alignment was poor, then credits near-matches. Soft clips: 11 of the 12 ALT-called fallback reads
clipped at the event carry the whole given ALT in their clipped bases, and none of the 16 REF- or
tie-called clipped reads carries either allele.
- Default backend, 38 variants, anchor-overlapping reads judged over the event ±2: ALT calls 4,185
(3,767 exact, 90%; 384 partial, 9%; 27 carry neither exactly), REF calls 13,390 (11,017 exact, 82%;
2,278 partial, 17%; 69 neither). The rule keeps 90% of ALT calls and 82% of REF calls, VAF rises
by a median of 3.8%, and 12 variants move by more than 10% (0.84× to 2.84×).
- Acceptance (25 signed-out IMPACT complex variants, truth = equal-length padded windows, reads
holding both): sw equals pairhmm on 25 of 25 traced variants; exact REF reads are called REF
7,457 of 7,468 times (11 neither) and exact ALT reads ALT 2,018 of 2,020 (2 partial), with no
REF↔ALT flip; ALT calls are 98.8% exact-ALT reads (develop 89.8%), REF calls 98.5% exact-REF
(develop 85.8%). On the RC set 8 of 1,154 rows change, all complex or in a complex row's group.
RNA (FORTE, about 7,150 synthetic delins probes in expressed genes, 2 samples; REF share of depth,
develop → the rule): genomic windows reached into the intron, so spliced reads were neither,
0.987 → 0.017 at 0-1 bp from an exon edge and 0.982 → 0.484 at 2-4 bp; with windows ending at a
read's own junction, 0.923 and 0.906 against 0.909 mid-exon.
- Other tools (VarDictJava and GATK Mutect2 source): neither counts exactly the given allele.
VarDict matches its own CIGAR-derived allele text and its rescue moves near-matching reads in
(soft-clip consensus with up to 3 mismatches); its REF is a one-base count and it has no
given-allele mode. Mutect2 credits each read's best haplotype by likelihood, even when the read
carries extra events, so under --alleles a read carrying a slightly different, unassembled allele
can be credited to the given one; it counts a read whose bases tell the alleles apart even when
the read ends partway through the event.
- Not adopted: flagging from the second try's scores, the 8-mer content rule, and that rule with
demotion of ALT calls lacking ALT sequence (REJ-20260925-001 in
.agents/learnings/REJECTED.md).
Evidence behind RJ-5's first form, the cluster contest of 6.5.0 (2026-09-22/23), #92 and #99
(adjudication,
acceptance; design in
.agents/archive/CYCLE_6.5.0_PLAN.md § T1). At a hypermutation cluster in a repeat tract of BRCA2
(five annotated deletions among four 1-3bp inserts in an AG-rich stretch of about 150bp; ACCESS
duplex and simplex fragments against sign-out), each annotated row counted the union of the carriers
compatible with it: per-row counts of 39-107 against sign-out 21-45, and a sum of about 397 against
about 150 distinct ALT molecules. Every deletion op in the cluster's molecules was canonically
left-aligned, one vote per molecule, and assigned only on exact canonical identity:
- no equivalence collisions: the five annotations canonicalize to distinct alleles, so exclusive
assignment is well-defined;
- exclusive assignment against sign-out: 28/28, 32/32 and 21/21 exact on the three 2bp deletions;
28 vs 22 (33bp) and 41 vs 45 (14bp), within a few molecules;
- the locus is messier than annotated: 1,299 molecules carry an unannotated 1bp deletion in the
tract (plus D11/D17 ladders) and 373 molecules carry 2 or more deletion ops in the window.
The contest that shipped in #99 (anchor-exact evidence never contested; every other ALT read
demoted to partial_alt if the read's own window does not favour the row's ALT over REF, if it is an
alignment-phase call on a pure indel, or if a sibling's ALT explains it strictly better) was
accepted on: the three 2bp deletions at 28/28, 32/32 and 21/21; the 33bp and 14bp deletions from 76
and 94 down to 37 and 51 against sign-out 22 and 45 (the remainder is same-length shifted ops, kept
so the shifted-representation rescue still works; the canonical-identity table above and these
figures differ for the two longer deletions because they are two different models); the other
signed-out variants of the truth panel (252 across four samples) unchanged; five IMPACT samples with
signed-out complex (delins) clusters, where every pure-deletion row matches exactly, delins rows keep
their own carriers, and the MAF and VCF input paths agree on every row; group-free panels (FLT3-ITD,
MSI, the RNA cohort) byte-identical. The release-candidate check of 2026-09-24 (28 DNA runs, 1030 of
1060 rows byte-identical; the 30 changed rows were 29 cluster rows and one CLIP_CANDIDATES flag)
reproduced it: 28/28, 32/32, 21/21 exact; 33bp 37 v 22; 14bp 51 v 45. Three earlier designs failed
real data and are not adopted (REJ-20260923-006 in .agents/learnings/REJECTED.md). Test 3 was later
replaced for exact-carrier calls by #300 (the amendment above).
Evidence behind RJ-6 (2026-09-17/18), #91
(phase 2,
phase 5). Before the rule a
read proving a wrong-length pure indel got a definitive call: on the large-deletion panel (unique
context, same-anchor read deletions against annotated 100 and 60bp) every length 40-120bp counted
as full ALT, and a 2bp deletion at the edge of a 10bp homopolymer read about 51% VAF where
exact-length support was about 1.4%. The synthetic matrix used 8 REF + 6 wrong-allele reads per
scenario. Real-data targets, read-truth verified and all exact on the final build: a FLT3-class 2bp
deletion ad 259 → 7 plus 252 partial (VAF 51% → 2.7%); an AR-class 9bp GGC-tract deletion ad 24 →
15 plus 9; an RNA 2bp-deletion locus ad 32 → 15 plus 17; a SMARCB1-class 19bp insertion stays 310.
The 74-row curated indel panel: 72/74 byte-identical after the rule (the two changed rows were
delins, window effects), 69/74 on the final build (exactly 5 changed rows); the 5-sample full-BAM
large-deletion and delins panel 14/15 byte-identical (the one difference a diagnostic partial_alt
read, with rd/ad/dp identical). A same-length insertion whose bases confidently mismatch the
expected insert (a third allele) had been absorbed into rd: ad unchanged everywhere, three
insertion rows moved a total of 8 provably mismatched reads from rd to partial, the largest 6 reads
on one row. The first draft of the placement band summed net deleted bases anywhere in the region, so
a D(2) at the anchor + M(53) + D(49) read passed it for an expected D(50); the shipped band was
placement-aware (retired by RJ-24). Four adversarial passes found 69 findings (19, 21, 7 and 21,
plus 1 more code finding), each fixed on the branch or tracked on #92. Not adopted: the
reciprocal-overlap tier and the split-suspect escape hatch to Phase 3 (REJ-20260917-001 in
.agents/learnings/REJECTED.md).
Evidence behind RJ-7 to RJ-9 (2026-10-01): on 105 changed DNA and WES rows the read census counts 57,199 REF reads; develop counted 60,619 and the decided rules 57,218. The largest moves are deep slippage loci (a BRCA2 cluster where an unannotated 1bp deletion in an A run sits inside two annotated rows' windows; a T run). RJ-9 changed no row on RC, FORTE or WES.
Behind RJ-7's choice (#200, decision):
the ticket offered (a) any insertion or deletion inside the discrimination window makes the read
not REF, and (b) keeping the 1-4bp "noise" policy and making the post-walk rule consistent with it
(no flip on an unrelated op); (a) was chosen and (b) is not adopted (REJ-20261001-001 in
.agents/learnings/REJECTED.md). The synthetic shapes, (REF, ALT, partial) on develop: −A carriers
on a +A row in a homopolymer (10, 0, 0); +A carriers on a −A row (10, 0, 0); a D(2) inside the 8bp
span of a unique −8 row (10, 0, 0); a D(1) right after the anchor of a unique +10bp insertion row
(10, 0, 0). Real-data cases from the cluster-1 acceptance: at one RC insertion locus (+AAG in an AAAG
repeat, two samples), six reads carrying a large deletion upstream and a D1 four bases into the
insertion's window were partial on develop, kept out of the row's REF only because a co-annotated
33bp deletion's Phase 3 wrongly called them ALT; at an RC 6bp deletion in a CAG/CAGCAA repeat, five
reads whose bases are REF across the discrimination window lost REF (REF + partial on develop,
partial on the branch), each carrying a same-length deletion of other bases 23bp away, outside the
window but inside the scan window. The ticket's remark that GATK counts such reads as neither
allele: as understood, GATK's AD credits a read to the allele whose haplotype it fits clearly
better, so RJ-7 is stricter than GATK, by decision, because it follows the reads' bases, which the
census checks. On the measured change, 112 of 144 files are byte-identical and 155 rows change (REF
−4,327, partial +4,324; ALT and depth unchanged); on every FORTE row the reads moved out of REF are no
more than those whose bases contradict both alleles.
Rarity behind RJ-9 (#199, decision): 769 anchor-changing one-base-REF rows among 1.13M signed-out; 133 with an ALT of 6 bases or more. The two false calls it removed, three synthetic reads each: CA>T (Del+SNV) before a 60-A run, reads carrying only C>T, were ALT (on develop at every run length); C>TA (Ins+SNV) before the same run was ALT too. Reads that keep the anchor with the extra A and end inside an 80-A run are base-identical to the REF reads, so they count REF like them; placement (the CIGAR's insertion) does not decide.
Evidence behind RJ-10 to RJ-13 (2026-10-02). A survey of every harness input
(RC DNA, FORTE, WES) found 1,197 reads with event bases past their fragment end
at 384 rows (0.03% of reads), 61 unmapped records placed on events (27 rows), and
no records with absent qualities or hard-clipped admitted reads. Masking adapter
bases alone (measured: 244 rows, ALT −63, REF −128) left reach: a read whose
molecule ends inside a repeat still counted REF on its adapter, hence RJ-10 clips.
An adversarial review found soft-clipping with masked qualities still left reach
in complex and MNP windows (a forward molecule ending on the event's first base
counted ALT, unlike the same read trimmed), and an outward pair's TLEN read as a
fragment; the clip now removes the bases and needs an inward pair. That build
lost 13 ALT reads at an FLT3 ITD: TLEN, a reference distance, left out the
molecule's 66 inserted bases. On the 12,239 read-through reads of the changed
rows, one aligned base past the boundary mismatched the reference 75% of the time
(adapter; 9,174 reads), two 30%, ten or more 0.7% (the molecule; 97 reads), and
446 reads held inserted bases past it (three aligned bases mismatched 9%, so
they are mostly the molecule). Hence only adapter-like bases are clipped. The
final rule changes 182 rows (ALT −57, REF −81); the first base past the
boundary is A, the adapter's first base, in 97% of clipped reads, and 52 of the
54 lost SNV ALT reads showed that A.
At --min-mapq 0 an unmapped mate carrying a CIGAR counted as an ALT read. Other
tools: GATK hard-clips adapter at the insert-size boundary and drops reads whose
bases and qualities differ in length (WellformedReadFilter) and unmapped reads
(MappedReadFilter); fgbio ClipBam clips bases past the mate (soft, soft with
mask, or hard); samtools and bcftools mpileup always discard unmapped reads, null
overlapping mates' duplicate bases by quality 0, and bcftools caps base quality at
max-BQ; bam-readcount filters nothing by default; VarDict, Strelka2, freebayes,
LoFreq and GetBaseCounts document none of these cases.
Evidence behind RJ-14 and RJ-15 (2026-10-02). RJ-14 changed no row on RC DNA, FORTE or WES (144 of 144 files byte-identical); it decides synthetic shapes the read census calls ALT. RJ-15 was prototyped three ways and measured against develop and the census on the same inputs: - strict, as C22 (an unmasked base wherever the alignment's haplotype differs from the ALT): ALT −26, of which 22 are reads with a masked base at the deleted anchor that the census and develop count ALT (the same bases placed one base along take the strict path and count ALT); - the pure-indel ALT-by-bases rule, which stops at the first deciding base: false ALT at insertion rows (a BRCA2 row 9 → 35, census 17); - the rule adopted: ALT net 0 on RC DNA (±1 read at 6 rows, all masked-base edge cases), −2 on WES; REF +57 at the BRCA2 cluster, every row toward the census (reads that were a co-annotated row's false ALT now count REF where their bases across this row's window are REF). Summed distance to the census on the changed indel rows: REF 344 → 251, ALT 40 → 44.
A fuzz of 2,400 random insertion, deletion and mismatch compositions near the anchor over eight
pure-indel rows (#202 body; rerun over 2,400 reads, five seeds, on the final head of the cluster-1
change) gave 130 ALT calls on reads whose bases are not exactly the ALT, all the same on develop: 42
carry the ALT plus mismatches, which is correct, and 88 delete the anchor base and fall to Phase 3,
whose PairHMM credits the closer of two haplotypes. Those 88 are the route RJ-15 closes. Real data
from the cluster-1 acceptance: at one RC insertion locus (+AAG in an AAAG repeat, two samples),
reads deleting 24-54bp across the anchor were partial on develop and counted REF + partial once a
co-annotated 33bp deletion's false ALT was withdrawn, 10 reads across the two samples. On a synthetic
−8 row in unique sequence, five reads that only delete the anchor and the next two bases (D3) hold
neither allele, yet the engine counted 5 REF. Not adopted: the strict and the ALT-by-bases
prototypes (REJ-20261002-001 in .agents/learnings/REJECTED.md).
Evidence behind RJ-16 (2026-10-02/03). Synthetic delins probes in covered sequence, where no read carries the ALT, found spurious ALT reads in data whose reads are not consensus-collapsed: FORTE RNA 2.0 per million reads (70 at the exon-edge and mid-exon probes), IMPACT 1.8 per million, one in WES; none in ACCESS duplex or simplex. Each was a read whose clearly read bases fit the ALT while most of its window was low quality (masked bases fit either allele). Three rules were measured on the probes and on every complex DNA/WES row with ALT reads (1,185 real ALT reads): every event base read (RNA probes 70 → 16, DNA 8 → 0; 46 real reads lost), at most one masked event base (RNA 31, DNA 0; 15 lost), and the quality-weighted evidence adopted (thresholds 2–3 log10: RNA 15–19, IMPACT 1, WES 0; 1–2 real reads lost). A survey: GATK HaplotypeCaller and Mutect2 weigh every base by its quality in each read's likelihood (bases below Q18 down to Q6) and count a read toward AD only if its best allele leads by 0.2 log10; Strelka2 (indel posterior ≥ 0.51) and bcftools (per-read indel quality) use per-read evidence too; the counting tools use hard base-quality cutoffs; none treats a low-quality base as fitting either allele.
An adversarial review of group 2 found three defects, fixed before merge: a read whose bases are exactly REF, written as the anchor deleted and re-inserted, had counted partial (RJ-15 now counts it REF, as its bases say); the evidence had compared REF and ALT readings over different read bases, so a shared flank base's quality could flip a call, and had skipped a long event's bases past its junction windows (both fixed by the mismatch-weight form above). A pre-existing limit remains: a REF molecule with one clear error just outside the window that its ALT reading is anchored away from can still count ALT (6.7.0).
Evidence behind RJ-17 to RJ-19 (2026-10-03/04), on FORTE RNA: the truth cohort
(94 signed-out rows), the T9 exon-edge indel probes (978 rows) and the C1 splice
probes (7,224 delins rows at exon-edge distances 0–4 and mid-exon controls, where
no read carries the ALT; run on local slices of the probe regions, byte-identical
to the full BAMs). Each rule was a separate prototype against the same base.
- RJ-17 changed no truth row. At the T9 probes it moved 24,703 REF reads to depth
on 30 rows, 24,695 of them normally spliced reads ending at the exon edge inside
a 12–60 bp splice-crossing deletion: their bases fit both alleles (the deletion's
first discriminating base or its margin lies past the splice). vaf is
alt_count / (ref_count + alt_count), so at such a deletion with carriers it
rises to the VAF among the reads that show the event (unspliced ones), as
RETENTION_DOMINANT describes; the T9 rows have no carriers and the truth set
has no such row, so no measured vaf moved.
- RJ-18, first as "an RNA clip is never evidence", changed no truth row; at the
splice probes spurious ALT 19 → 16, and 4,290 of 31.6 million REF reads
(0.01–0.02% in every stratum) became depth only. Refined (below): a clip is
read unless it reaches an exon edge or junction end; the three spurious ALT
reads stay removed and 337 of those REF reads come back.
- RJ-19 changed no truth or T9 row; at the splice probes spurious ALT 19 → 4
(exon edge 0–1 bp 14 → 2, 2–4 bp 5 → 2). REF −0.95% at edge 0–1 bp probes, from
reads reaching only one or two bases past the junction, which hold no spliced
flank; −0.11% at 2–4 bp, −0.01% at the controls. Re-judging the residual
spliced ALT reads' loci against haplotypes spliced at each read's junction,
1 of 7,461 reads fit the ALT. A first prototype that replaced the genomic
window's intronic bases one for one with the next exon's (instead of building
the windows over the spliced reference) required bases a repeat grew into the
intron and doubled the REF loss.
An adversarial review of group 3 found: transcript spans keyed by ID alone (an
ID reused on another chromosome, as PAR copies or version-stripped RefSeq IDs,
gave intergenic sites a strand; spans are now per transcript, chromosome and
strand); spliced windows that spliced only the nearest junction (REF reads
through a 3 bp exon counted 0; every junction reached is now followed); a
worker silently falling back when the reference could not be opened (now an
error); a delins carrier whose aligner wrote its junction starting inside the
event counted depth only while the same bases written X D N counted ALT (now
spliced at the event's edge); and RJ-18's first form dropping mid-exon clips, which are a local
aligner's clipped mismatching ends, the read's own bases (an MNP carrier whose
second base lies in such a clip counted ALT before group 3 and not after; now
read again: splice probes 261 rows, REF +337, partial +26, no ALT). A second
review of those follow-ups found the gap form calling REF molecules ALT or
partial: a read spliced at an alternative donor or acceptor inside the event,
or at a splice site the event straddles, skips the event's bases and so fits
the shorter ALT spliced at the event's edge (a pure-REF probe showed 50% VAF
with its kept base masked). Such a read is REF as aligned at its own junction;
it now counts ALT only over that reading too, else depth only (the 22 splice-
probe rows the gap form had first changed, REF +7 and partial +19, were such
molecules and are back to depth only; the probes hold no carriers). With every
rule, against the branch point: splice probes spurious ALT 19 → 2, REF −0.39%
(−121,786, almost all at probes 0–1 bp from an exon edge), partial −453.
A survey: GATK's RNA workflow splits reads at N (SplitNCigarReads), so each piece
ends at its exon edge and HaplotypeCaller counts a piece toward AD only when its
bases favour an allele (a read partly overlapping a tandem repeat is
uninformative), and runs with -dont-use-soft-clipped-bases; its overhang fixer
compares a short overhang only with the intron's reference. bcftools never uses
a spliced read for indels. phASER, WASP and ASEReadCounter never read clips.
JACUSA masks bases within 6 nt of a read's own junction, SNPiR and REDItools drop
sites within 4 bp of annotated junctions; none confirms a junction-adjacent base
against the next exon, which RJ-19 does. SplitNCigarReads changes no base quality, and
htslib's BAQ skips a read with a reference skip whole: gbcms lowers none at a splice
(RJ-31).
Other tools: GATK, Strelka2 and freebayes judge a read by its bases against haplotypes, so a split ALT counts ALT; bam-readcount, LoFreq and the original GetBaseCounts count CIGAR ops. A read deleting the anchor goes to GATK's spanning-deletion allele or another candidate where one exists, is its own haplotype in freebayes, a separate allele in VarDict and depth only in GetBaseCounts; a closer-haplotype credit, as Phase 3 gave, appears only in the likelihood tools without such a bucket.
Evidence behind the RJ-23 amendment and RJ-27's named limit of 2026-10-30 (#264), under the
sequence judge, HG002 (public). The bar is per read (operator, 2026-10-30): at het insertion rows
of 50 bp or more whose other haplotype is REF over the insertion's REF window (two ALTs at one
position, or any truth variant there on the other haplotype, are no test of REF's share: 112 of
the 720 rows of the insertion arm, among them five two-ALT rows that read RD 0), among the reads
the truth decides that hold the equal window on their own allele (each placed ungapped, every
base, at its best by confident mismatches), the share called ALT against the truth's, and the
wrong calls. With the windows read on: tr 266 of 967 called ALT (0.275) against the truth's 289
of 1,042 (0.277); nocl 392 of 1,088 (0.360) against 398 of 1,127 (0.353); c246 31 of 90 (0.344)
against 31 of 100 (0.310); no wrong call. The judge before the windows matched them as closely
on these reads (its excess ALT was reads lying inside the insert). The truth's own share is the
measured mapping loss: of the reads holding the equal window, 289 come from ALT molecules against
753 from REF's on tr, 398 against 729 on nocl, so a long insertion's VAF reads below 0.5 under any
count fair to both alleles (by BWA's placements 476 against 782 and 523 against 735, counting as
over the anchor reads whose bases lie inside a VNTR insert: at chr11:35248725 BWA places all 36
of the truth's ALT reads over the anchor, and 29 of them fit best inside the insert). The 0.5 bar
on rows (60% of 88 rows in band on the insertion arm before the windows, 64% of 76 with them)
tests the mapping, not the judge. At #144's two duplications (chr21:41865095 +89,
chr22:39653046 +98), reads placed on HG002's phased truth haplotypes, confident bases only, a
carrier fitting the insertion's haplotype by one base or more: of 39 carriers the judge counted
23 ALT before the windows, the rules 8, the windows 8; no non-carrier (34) is counted ALT by any.
The windows leave depth the carriers lying inside the insert (their first bases are the insert's
last, not the anchor) and those ending at the SNVs phased with each duplication past its run,
which the guard masks (RJ-27, #294) and which make its copies twins. The read-on makes depth the
REF reads short of the next base telling the windows apart (88 bases from the anchor at chr22,
130 at chr21): non-carriers counted REF 21 to 10 and 13 to 5. Reading those masks as the
reference's on REF's haplotypes where REF's molecules lack the change (a temporary option,
GBCMS_JUDGE_LONG_INS=cis, removed 2026-10-31) counts 18 carriers, crediting 10 reads on other
fragments' evidence (REJ-20261023-001). Of the
judge's REF calls on reads the truth cannot decide (167 of 923 on tr, 118 of 954 on nocl), every
one wins by a confident base or more on the read's own bases: 124 and 25 at rows where neither
truth haplotype is REF, the rest at het rows below the truth's two-base bar or with nearby truth
variants tying its haplotypes; the 65 with large clips are the open item above. The windows
remove REF calls resting on a listed change inside the run that the ALT's state cannot take (23
reads at a 5.2 kb tandem duplication on nocl). Tools reading long insertions from short reads
count them at their breakpoints, over windows a read can hold: GraphTyper2 writes only each
breakpoint's sequence (up to about 152 bp) into its graph and counts the reads aligning to its
REF and ALT sequence there; Paragraph genotypes each breakpoint on its own graph and combines
them. RNA does not take the sequence judge. On every arm (HPC, against the judge before the
windows): the patient sets change 8 rows, all insertions of 50 bp or more in the gate set, each
losing 1 to 4 ALT reads, REF unchanged, oracles v3 and v2 passing on every set; HG002's truth
arms lose the true ALT reads lying inside long inserts (50-299 bp: tr 835 to 526 of 865, nocl
1,230 to 876 of 1,270; 1 kb or more on nocl 1,762 to 978 of 1,836), true REF and wrong calls
unchanged but for the 5.2 kb duplication's 23 REF reads, no other class changing. The read-on
alone (against the windows without it) changes 8 HG002 rows and no patient row, losing REF reads
and no ALT read: 7 lose 1 to 3 (true REF on tr 401 to 397 of 448 at 50-299 bp, 287 to 286 of 288
at 300-999 bp; no wrong call); the eighth, at chr2:111764847 +106 beside a listed +56 three bases
on, lost 12 to the REF window then being counted in reference bases, the ALT's in columns (the
listed insertion lengthened REF's alone); counted in columns, it keeps them (RD 3 to 15). The
check made first, on every call, makes depth the reads inside a long insert tying another allele
(partial evidence before): partial to depth at 28 c246, 80 tr, 128 sub and 168 nocl rows (on tr
1,495 reads, 3 of them true ALT and 1 true REF), no REF or ALT count changing. The masks laid on
both windows by offset change 11 row entries on the four HG002 arms (10 rows: chr19:3332480 +329 is
on sub and on nocl), against the build before them. By truth, on nocl: 5 true REF reads REF to depth
(4 at chr17:367066 +402, 1 at chr9:108247879 +401), 1 true ALT read depth to ALT (chr17:367066 +402)
and 2 reads without a truth label depth to ALT (chr19:3332480 +329, the same on sub); on
c246, 1 true REF read REF to depth (chr7:158521942 +470) and 10 reads the truth cannot decide or label
(9 REF to depth, 1 depth to REF); on tr, 3 reads the truth cannot decide, REF to depth. #144's two
duplications are measured apart, on reads placed on the phased truth haplotypes, against the build
without the masks and with the same other fixes: chr22:39653046 changes no read, and chr21:41865095,
which is on none of the four arms, turns its last 5 REF reads to depth (REF 5 to 0, ALT 2). Those 5 are
not unreadable: each reads the reference's base at the masked SNV (89 bases from the anchor) and a
confident base (Q37) that is the reference's at the next telling base (129 bases from the anchor).
Before the masks, the ALT's last inserted base told them from the ALT by one confident mismatch
(ALT -4, REF 0 in the trace); masked, the ALT fits each as well as REF does (0 and 0), as the two
copies are twins. The symmetry bar is unchanged on every arm.
Evidence behind the amendments of 2026-10-31 (#264), HG002 (public), judge path, --min-baseq 20, on the four truth arms (c246, tr, sub, nocl) against the runs of the commit
before them; the delins and clustered-hotspot arms do not change. The masks on every candidate haplotype, with the anchor taken from the run (the build before the merge with
develop), move 4 reads in 2 rows on tr (chr13:40955543 +99, chr3:18596716 +157) and 4 reads in 2 rows on nocl and on sub (chr10:127797459 +2410, chr6:73601481 +276), each
from partial evidence to REF, each at a row where another candidate haplotype takes mirrored masks (the debug trace names them). By truth, the 4 on tr are reads the truth
calls REF but their bases do not decide; on nocl and sub 3 are true REF and 1 has no truth label; no true ALT read moves and no call is wrong; c246 does not change. The anchor
fix reaches no row: none of the long pure insertions in the arms' inputs (227 on tr, 729 on nocl, 444 on sub, 124 on c246) can shift left or has more than one REF base.
The merge with develop then moves 70 reads in 31 rows on c246, 17 in 14 on tr, 122 in 49 on sub and 327 in 129 on nocl, every one a read the band rule for a long listed
insertion (#369) sends to the full programme (the judge far lines of the trace); three rows differ with no moved read at them (two c246 SNV rows in the fragment strand
columns only, and one nocl and sub row in its UNEXPLAINED_READS count), all on the same judge far lines. The rules path of the merged build equals develop's byte for byte on
all eight arms (the MAF bodies and, sorted, the read calls). #144's two duplications give the same read calls as before (chr21:41865095 and chr22:39653046 unchanged).
Evidence behind the RJ-23 amendment of 2026-10-16 (#279). On HG002's long insertions, reads were compared base by base. Some fit the ALT placed from the right flank better, by two confident bases or more, than REF over their bases left of it: carriers of an insert whose end resembles the left flank, aligned over it. Counting all of them ALT moved rows in band from 357 to 411 at read level. It also overshot from 50 bp on: 50-149 bp to a median VAF of 0.611, and 150 bp or more to 0.857, because carriers that start inside the insert give the ALT read starts REF cannot have. Counting only those reaching past the insert's start, and making the rest depth rather than REF, kept RJ-23's one reading flank: 385 in band at read level, median 0.462. Implemented with the other flank anchored only where the read's bases place it unambiguously (a C run or a CAG repeat past it let deletion carriers written without their gap through). Against the merged build: HG002 10+ bp insertions in band 334 -> 343 (mean |VAF - 0.5| 0.157 -> 0.153), short insertions 552 -> 555, deletions unchanged. On the gate panel, 7 insertion rows change and no oracle-ALT read is lost; WES, normals and ACCESS, and FORTE are unchanged.
Evidence behind RJ-29 (2026-10-25), #304 phase B, HG002 truth and aggregate patient arms. The reads an absolute budget sends to depth are mostly structural, not noisy: 30-99% carry a soft clip of 20 or more bases (1-12% of kept reads do), on the panel 65% a CIGAR indel of 10 or more, only 0-6% are paralog-like (XS at least AS), and their qualities predict about 0.06 errors per read at every misfit level. Oracle agreement, panel / gate subset: the budget applied exactly .9262 / .9624, no budget .9323 / .9637, a budget scaled by read length .9313 / .9636, xs .9323 / .9637 (xs equals no budget on every patient arm within 0.01 points, and drops chr20's paralog-like REF reads). The exact budget loses 1,114 true ALT and 713 true REF calls on the panel to avoid 18 wrong ALT and 261 wrong REF. The residual risk is foreign reads the aligner places uniquely at homozygous deletions in repeats (HG002 chr17 3.6 kb: VAF 0.59 under xs, 0.97 under the exact budget); UNEXPLAINED_READS flags such rows. Tools with an absolute test (GATK, Paragraph, Graphtyper) score against haplotypes assembled from the reads, which explain each read's structure; the given rows here do not.
Evidence behind RJ-28 (2026-10-25), #304 phase D, on the 6.6.0 gate set (aggregates). 45 component-SNV rows sat beside 42 MNV rows; in 31 of the 45 the MNV accounts for at least 90% of the SNV's ALT reads. Within sign-out: develop 37 of 45 (37 of 38 informative), the judge counting the MNV's carriers as another allele 6 of 45; SNV median VAF 0.148 against 0.000; the multi-allelic-same-start stratum 0.839 against 0.613. On a synthetic DNP the exclusive reading credited the same reads 20, 6 or 20 times depending only on which rows were listed: it zeroed the SNV only when the MNV was listed alone, not when it was unlisted and not when both components were listed. Tools that count per base give the SNV's row the read: GetBaseCounts 1.2.5 (the sign-out and FORTE's fill-out), bam-readcount, mpileup, LoFreq, Strelka2, DeepVariant, and GATK HaplotypeCaller with given alleles. Exclusive tools (VarDict, FreeBayes, Mutect2, Lancet2) get there by emitting one record, which a genotyper of given rows cannot do; gnomAD keeps component SNV counts and lists MNVs separately. A molecule carrying the MNV enters both rows' mFSD size distributions (two KS tests on one event in the BH family); MNV_SHARED marks those rows. FORTE lists no MNV rows, and no truth set lists an MNV with its components.
Evidence behind the #278 decision of 2026-10-15 (comment), a prototype on every MNP, delins and pure-indel row of the 6.6.0 gate panel (sliced locally); these are the prototype's numbers, before the final build below: - Group A, what the read can see. RJ-1 (a read ending inside or just past the tract is depth only, for both alleles) moves 27.8k REF and 8.0k ALT reads on the panel and removes the REF excess the CIGAR rule shows on HG002: deletions' median VAF 0.455 → 0.500, short insertions 0.429 → 0.500, 10+ bp insertions 0.150 → 0.43. RJ-20 (an insertion carrier whose inserted bases are unreadable counts ALT where no other allele of that length is at the locus, as RJ-25 decides for complex events) gives +560 ALT on the panel, and AD +1 in all across the matched normals. - Group B, errors in the read. RJ-22 keeps about 1.8k ALT reads, and the matching REF reads, where the junction ALT has a substitution in the run. - Group C, another event in the read. Outside the windows (RJ-8) a read whose indel's best placement lies outside keeps its call as a separate event; that check, ahead of the read-on of #287, touches 0.7k REF reads and 4 tests. - Found on the prototype and fixed on the branch: a germline change joining the run a pure indel slides through left REF molecules reading as the ALT; in one matched normal that gave RD 437 → 0 and VAF 1.0. With background in the run masked around the indel's own bases, and the windows reading on where masks hide the alleles' difference, that normal reads RD 398 / AD 8, with sign-out at 8.
Evidence behind RJ-26 and RJ-27 (2026-10-15/16), #278. Other tools' read-level judges
(GATK HaplotypeCaller and Mutect2, Octopus) decide an indel read by one base past the
repeat and take a single mismatch as an error unless it recurs; the recurrence floor
(two fragments) is freebayes' and bcftools' default. Octopus, built and run on the same
synthetic shapes, agreed with the rule per read in 73 of 87 cases (its disagreements:
reads it re-aligns past the window). On the 6.6.0 gate panel, against a bases-only
oracle (each read placed ungapped on REF and on the ALT, an allele called where its
placement beats the other's by more than one confident base), the full local gate (411
runs) changes 1,062 rows of the flagged strata against develop; the rows within the
oracle's tolerance are sign-out 749, develop 838, this rule 867 (any discriminating
base; 794, 921 and 968 under a two-flank oracle, 14 rows farther from it than develop
and 58 closer). On HG002's het indels (truth VAF 0.5) against the CIGAR checks: 10+ bp
insertions in band (0.35-0.65) 110 -> 334 (median VAF 0.150 -> 0.424), short
insertions 465 -> 552, deletions 529 -> 563. The window growth (on the allele holding
the indel's bases) was chosen over growth on both alleles and over none (REJ-20261016-001 in
.agents/learnings/REJECTED.md): HG002 long
insertions mean |VAF - 0.5| .1498 against .1510 and .1540, deletions in band 563
against 563 and 571, oracle-correct panel reads 489,324 REF and 151,958 ALT against
488,127 / 151,533 and 492,962 / 154,045, reads of another allele counted ALT 897
against 851 and 1,166. The identity band for truncated inserts (D2) added 158 ALT reads
on HG002 long insertions with truth concordance unchanged, and on the panel 13 ALT
calls the oracle agrees with against 111 it does not: not adopted (REJ-20261016-002 in
.agents/learnings/REJECTED.md). An adversarial
review's third-allele shapes (21, pinned) led to the confirmation past the windows: a
count threshold lost 516 oracle-ALT panel reads (carriers of one row with a phased DNP
eight bases on); the shift test keeps them and removes 91 oracle-disagreeing calls for
36 correct ones. Normals and ACCESS: AD +3 against develop over 1,402 rows. FORTE:
11 of 25 pure-indel rows (all deletions) RD -230, AD +225, most of the AD a 12-bp
deletion STAR soft-clipped on 173 of its 175 carriers. RNA (#291): on insertions and deletions at both edges of an exon, spliced and exon
reads, BAQ on and off, without a GTF, every spliced read counts for its allele once
it reads on along its mRNA (before: spliced REF reads at indels two to four bases
before an exon's end neither, partial under BAQ; develop lost the spliced ALT reads
under BAQ); on the FORTE slices one row changes, with the GTF or without (RD +1, a
spliced REF read the intron had left undecided).
Evidence behind the RJ-27 amendment of 2026-10-20 to 2026-10-22 (#294,
decision record), what short
reads can tell at three HG002 rows. Every read (137) was fitted against the true haplotypes and
against the same pair with the insertion swapped: 53 fit every haplotype; 21 can only be sorted by
knowing the SNP's phase; at the #294 row no fragment reaches both the SNV and a base that tells the
insertion apart. Develop's extra ALT calls at two of the rows (8 of 13) were reads showing only a SNP
that happens to be in cis; in trans the same reading is the error the ticket describes. A whole-read
PairHMM with the nearby germline changes as haplotypes reached what these reads' bases can show: all
63 reads whose bases tell were right, with none wrong or missed. Two caveats: gbcms's own PairHMM had
its end gaps reversed (#299), and in gbcms the haplotypes would have to come from the guard. The
comment called it a candidate for later; #304 took it up for package 2. Considered and not
adopted: choosing the rule by whether the ALT is present, and a cis rescue (REJ-20261023-001 in
.agents/learnings/REJECTED.md).
Evidence behind RJ-25 and the RJ-23 grown-event amendment (2026-10-14), measured on a
synthetic arm of 13 shapes (each event on its own contig: REF, the given ALT and another
allele of its length; 2x150 pairs aligned by BWA-MEM; NovaSeq-binned base qualities, a
share of molecules with the telling bases or the whole core at Q2 in the stress shapes),
on the 6.6.0 gate panel (1,170 rows), its matched normals and ACCESS runs (1,402), TEMPO
WES (686) and 800 HG002 germline het delins (GIAB v5.0q), every changed read judged by
its own bases:
- Another allele of the ALT's length: develop credited 165 of its reads as the ALT
under the stress masks, and at natural quality 15 where the given allele is absent
(a phantom ALT, on a germline allele at 50%); for a somatic MNP at 10% on a germline
het's haplotype, a third of its AD (VAF 0.207 against 0.151 by informative reads).
The rule: none in any shape, VAF 0.137. With no other allele it loses what develop
loses (202 carriers over three shapes); demoting every read that left the ALT's bases
unread lost 286 there, 13 reads at the normals that their bases show to be the ALT,
and moved HG002 (REJ-20261014-001).
- On real data, against develop, the final build changes 18 gate-panel rows (RD +197,
AD -22), 9 matched-normal and ACCESS rows (RD +347), 3 WES rows (RD +28) and 3 HG002
rows (RD +9); the FORTE RNA cohort's one delins is unchanged. By rule:
- Another allele of the ALT's length: AD -43 at 10 panel rows, each beside another
allele the reads show (MNP sub-alleles in a hypermutated gene, co-annotated MNP
siblings, the germline haplotype under an MNP that merged it with a somatic change,
and a 3-to-36 duplication whose carriers all carry two SNVs in the copy: the given
ALT has no exact carrier and reads 0 with PARTIAL_DOMINANT). Of these, 20 carriers
at 4 rows were demoted only for a co-annotated component the reads never show
apart from its MNP, and count again; 2 more at one row (a GC>AG beside a
co-annotated GC>AA on about 5% of its molecules: AD 123 -> 125, sign-out 126) count
under the seen share. Of the panel's MNP ALT reads 3.3% leave a differing base
unread, and 0.6% read nothing that tells them from an allele the reads show.
- REF alike: 87 panel reads at 13 rows, 62 at 8 normal and ACCESS rows, 33 at 2 WES
rows and 3 at HG002 rows leave REF. Of the panel's, 83 read the base telling REF
from another allele below --min-baseq and 4 never reach it; of WES's, 31 sit at
the two rows whose given REF holds a homozygous germline change, where no molecule
carries the given REF (named by OBSERVED_ALLELE).
- The grown event: +284 REF reads at 2 panel rows, +409 at a matched normal, +61 at a
WES row and +12 at an HG002 row.
- The REF side's separate event, RJ-5's partial evidence for a REF read carrying a
co-annotated sibling, and the background at the bases an MNP keeps change no real
row; the synthetic arm is unchanged by them.
- Every MNP and delins row of the 6.6.0 gate panel (sliced during the HPC downtime; the
6.6.0 release reproduces all 73,649 of the gate's recorded non-VCF cells on the
slices, 23 RNA per-transcript lists in another order): of 742 MNP and 180 delins rows
over 235 runs, 39 MNP rows change (RD -203, AD -49) and 13 delins (RD +230, AD -7);
none of the 655 neighbouring rows. By cause: another allele the reads show, or REF
alike, at 24 rows (RD -112, AD -55; e.g. CC>AA beside its component CC>CA on about
40 reads: AD 33 -> 10, each of the 23 reading the telling base below --min-baseq);
the given REF on almost no molecule (a homozygous germline change merged into the
input's allele) at 12 rows (RD to 0 or 1); rows whose reads carry another allele
(ZERO_ALT, OBSERVED_ALLELE) at 9, losing develop's 32 partly read ALT reads; 43
clipped carriers with a phased neighbour at 5 MNP rows, whose plain fellows the MNP
check already counted; and the grown event at 2 delins (RD +284). Against sign-out
VAF 14 rows move closer and 38 farther: sign-out's counter credits reads that cannot
tell the given allele from another the reads show, counts a merged germline input's
somatic part alone, and leaves clipped carriers out.
- Decided on the fifth review (operator, 2026-10-14), each measured on every arm:
- The seen share: at depth one sequencing error spelled a co-annotated component in
full and made it another allele. In a Monte Carlo (CC>GT co-annotated with C>G, no
true component, 0.1% substitution errors, 5% of bases below min BQ), 3 of 60 loci
flipped at 200x and 9 of 60 at 1000x, each losing about 5% of RD and AD (47 RD at
1000x); with the share, none at either depth. A real sibling under 5% of its nearest
allele is not looked for: the reads that fit both, its low-quality ones, count for
the row, at most about 0.25% of depth.
- The bases an MNP keeps: GCA>ACT with a germline T at the kept base gave RD 20 / AD
10 in trans (the germline haplotype's REF reads neither: VAF 0.33 for 0.20), and in
cis carriers written with an indel at the block were neither (AD 5) while plain ones
counted. Masked as background, both give RD 40 / AD 10 on both routes. VCF gives such
a change its own record, its haplotype REF at the MNP's row; the original GBCMS
(strict span) calls it neither. 13 of the panel's 32 MNPs keep an interior base;
none has such a change.
- Other tools: GATK HaplotypeCaller and Mutect2 score each read against haplotypes and
count it in AD only when one allele beats the next by 0.2 log10, so a read that cannot
tell the given allele from an assembled germline haplotype is left out, and counts
where no such haplotype exists; Octopus credits reads to called haplotypes and drops
exact ties; the original GBCMS drops a DNP read with any base below its threshold,
other allele or not (as the first cut did). A two-allele tally (REF against ALT) cannot
see the other allele: it credits all 69 carriers of the duplication above. The read
census, given the true allele set, agrees with the rule.
- Inside the grown event: REF reads holding the given REF allele and a germline SNP in
the repeat the event grows through were neither, silently: 2 panel rows (about 140 REF
reads each, RD down 33-47%; VAF 0.43 read as 0.62 at one), one matched normal (410
reads) and one WES row (64). HG002 has 3 such rows, none affected. Masked, they count
REF.
- Limits: an allele on fewer than 3 fragments is not found (at low depth the call is
develop's); in a long event few reads hold every event base from the left flank, so an
allele the reads show is found less often there; and a read that cannot tell two
alleles apart counts toward neither, so beside another allele as common as the ALT,
with many partly read reads, the VAF reads low, as GATK's AD does. REF alike: a REF
read that ends before an allele's telling base deep in a long deleted span is neither
(a synthetic 28-to-6 delins with a het SNP in trans: RD 91 with the SNP at the 5th
deleted base, 73 at the 25th), the read-start asymmetry equal windows remove
elsewhere; on real data, 4 reads. Inside a delins the bases kept depend on the alignment, so a germline change
there is not masked: reads showing it are neither on either side. The older sibling
claim still takes reads that fit a co-annotated sibling no read shows (#282).
Evidence behind RJ-24 (2026-10-09), measured for the 6.7.0 plan and C40 on the 6.6.0 gate
panel's 60 deletions of 50+ bp (IMPACT, ABRA2-realigned) and 300 HG002 het deletions
(GIAB v5.0q, truth 0.5; WGS 35x, BWA-MEM only), every read judged by its own bases:
- 6.6.0 credits a carrier only from its CIGAR: on HG002 the carriers are clips (1,958 of
the junction carriers), and 6.6.0 reads VAF 0.000 at 287 of 300 hets; equal windows
at the POS breakpoint read 0.500.
- The 3-base length band credited no read on the panel (598 reads written with another
length are neither by their bases) and one on HG002, whose bases show the junction.
- k = 4 is enough: a dynamic k (raised until the alleles' continuations differ at m
positions, or until the junction has no other placement nearby) and k = 10 in
low-complexity sequence did no better against truth (REJ-20261009-001, -002).
- Read-on cost accuracy: REF was checked over every deleted base it covered and ALT
over four, so errors removed REF only. Without it, HG002 103/166 rows in 0.35-0.65
(100 with it), the panel 40/60 within 10% of sign-out (29) (REJ-20261009-003).
- Recurring changes inside the windows touch 12 of 60 panel deletions (and 7 of 213
HG002): in them, 38% of an allele's REF reads, or 72% of its ALT reads, carry the
change; unmasked, those rows would lose most of one allele.
- Low-complexity deletions (40 of 300 on HG002, none on the panel) still read high
(median 0.57): REF reads meet more errors in a repeat than ALT reads in the flank (C41
#264).
- Surveyed tools that test a known junction anchor 5-16 bases past the microhomology
(Manta, Delly, Paragraph, SvABA, Pindel); genome-wide placers need 20-25 for
uniqueness, which a genotyper given the breakpoint does not.
- ABRA2 and clips on the panel (60 deletions of 50+ bp; #254,
decision): ABRA2 writes
97% of carriers as a D op; 3.4% are clips, in 28 of 60 rows, and 6.6.0 credits none of them (the
6.7.0 plan counts 6,137 junction carriers written as a D op and 217 as a soft clip, 87 of them
with 10+ junction bases). 6.6.0 reads 4-7% low there, because ALT reads with a short far side are
clipped while REF reads need only a base or two. Under the rule about 5% of ALT reads become
depth: they show fewer than 4 bases past the junction, and their REF counterparts drop alike. 3
rows lose more: their ALT reads all carry a change 3-7 bases from the junction, a larger allele
(the shared sub-decision with #253). The junction-carrier counts on HG002 differ between the
sources: the decision comment gives 1,719 of 2,497 as clips (k = 10, "without realignment every
carrier is a clip"), the first bullet of this list 1,958; the basis of the difference is not
recorded.
- Junk risk: 23 junk clips at the breakpoint predict under 0.1 false carriers at 4^−4.
- Which breakpoint REF is read at: pooling REF from both breakpoints, as Manta, Delly and SVTyper do
(Paragraph genotypes each breakpoint on its own), puts a het near 1/3. On capture data row-level VAF
swings with depth along the event: REF at the left against the right breakpoint has median 1.02
over 48 panel deletions, and spans 0.69-1.86 for the middle 80% of rows, 19 of 48 differing by
more than 25%. On WGS (HG002) it does not. REF stays at the POS breakpoint (a far-breakpoint REF
read gives HG002 0.43 against 0.50).
- Spec shapes added for the rule (comment):
deletions of 500 bp and 1 kb (only one breakpoint is held and it is credited as junction
evidence); a split carrier, a primary soft-clipped at the junction plus a hard-clipped
supplementary, counted once; a hard-clipped record with no primary in the fetch, not evidence; REF
at the POS breakpoint only. Not added, because measured negligible: R1/R2 disagreement (23 of
about 195k panel fragments) and insertions longer than a read (none of 459 panel insertions
reaches 100 bp).
- Correction of the ticket's premise (2026-10-15, interim 6.7.0 gate adjudication;
comment): the "7 and 4
exact-junction reads" at the two deletions over 1 kb were runs of N in clipped tails, with 0-1
confident bases in the 30-mer. The panel's 1,023-bp rows are truncations: their reads carry
1,046-1,118-bp deletions from the same POS (the #285 bullet below says 1,086-1,118-bp; both are
as the sources give them), and no read holds the given junction, so 0 is right in 6.6.0 and
develop alike. What the rule delivered stands: clipped carriers whose own bases hold the junction
are credited (+184 reads across the gate's 50+ bp stratum). The limit the adjudication found is
right-clipped carriers whose aligned bases end before the junction windows, which get no read call
(#286).
- The sibling guard (2026-10-13): over the whole deleted span, co-annotated SNVs
inside it withdrew 2,667 REF reads at 10 of the panel's 60 deletions, where no ALT
molecule could carry them (one row's VAF 0.17 became 0.30); limited to the anchor
through REF's window, 378 reads at 2 rows, and 41 -> 45/60 rows within 10% of
sign-out. A growing continuation and a guard reading on past the windows gained
nothing on any arm (REJ-20261013-001).
- Runs past the junction (2026-10-19, #285 with #296): of the 587 local deletions of
50+ bp (panel 60, normals and ACCESS 77, WES 150, HG002 300), one carries a run past
the junction whose bases rejoin the flank: a phased GG>AA 3-4 bp past a 61-bp
deletion on all 48 carriers (0 of 444 other reads), which the run clause made
partial (ALT 0; sign-out 49). Against develop the panel changes at three rows: that
one (ALT 0 -> 48, the larger allele named), a 167-bp deletion whose REF molecules
carry a germline SNP on the first deleted base where the ALT has the same base (RD
117 -> 319, AD 293 -> 284, sign-out 352/291: they tie on the four continuation bases
and are told by the bases past the windows, the guard reading on that
REJ-20261013-001 tried with a growing continuation, here without it), and a 67-bp
deletion beside its sibling two bases right (AD 47 -> 46); the gate panel's 4,606
pure indels change at the same three, and normals and ACCESS, WES, HG002's 300 and
FORTE not at all. The prepared reference now holds as many bases past the deletion
as it deletes, so at three 1,023-bp panel rows the observed allele names the reads'
1,086-1,118-bp deletions. Two adversarial reviews: a VNTR unit count, a same-length
deletion shifted 2-3 bp right (31 of 150 random contexts counted ALT before the
joint check; develop's 2-bp shift about 23%), mates read in the wrong order, and
short reads of another allele; each is a test. A phased DNP at the junction counts
ALT in 36 of 40 random contexts (the other four: the deletion shifted right exactly,
or a DNP on every base the windows tell the alleles by), elsewhere 40 of 40. The
one-base-aside tolerance first posted (2026-10-18) counted it ALT in only 21 of the 40: in the
other 19 the deletion shifted right matched the reads at all but one base. The operator's
correction was an exact match, at the cost that another breakpoint that also carries an SNV
inside the run counts as the given deletion with a neighbour (REJ-20261018-001 in
.agents/learnings/REJECTED.md). HG002's
90-bp deletion, one unit of a VNTR of about 90-bp units whose carriers hold a phased
SNV equal to the next unit, reads VAF 0.11 with the deletion alone in the input and
0.58 with the SNV row (truth 0.5). The breakpoint search takes 0.1 s on a 1 Mb
deletion.
Evidence behind RJ-23 (2026-10-08), measured for the 6.7.0 plan on the 6.6.0 gate
panel's 137 delins rows (IMPACT, every read judged by its own bases beside the engine's
call) and on 400 HG002 germline het delins (GIAB v5.0q, truth VAF 0.5; WGS 35x, bwa-mem,
no realignment):
- The padded windows cost reads, not bias: on long delins (span 20+) one-sided windows
judge about 46% more ALT and 41% more REF reads at the same VAF, and the gate's
sign-out agreement there goes 0/14 → 9/14. On HG002 (span 20+) one-sided windows read
0.470–0.481 (6.6.0 0.464) with 25% more ALT reads.
- The alternatives are biased as read-start counts predict: whole alleles without
padding favour the shorter allele (panel VAF ×1.22); junctions read from either
flank favour the longer one (×0.87). On the four long delins (windows past 50
bases) the written counts match the one-sided reading (REF 1,356 against 1,351):
the reads that hold only the far junction are classified but never counted
(REJ-20261008-001 in .agents/learnings/REJECTED.md).
- Recurrent neighbours: in 47 of the 137 rows the ALT reads share a confident change
3–25 bases from the event that REF reads lack: the reads carry a larger allele.
Withholding those reads (as first decided) was measured and reversed on
2026-10-09: on HG002 it fired at 5 of 400 het delins, each larger allele ending on
a phased truth SNV in cis, and took their VAF from 0.42 (5/5 within 0.35–0.65) to
0.09 (0/5); on the panel it cut AD at the 49 rows with a recurrent neighbour by 54%
(sign-out agreement 25 → 13 of 49). A germline neighbour in cis sits on every ALT read and no REF read, so
reads cannot tell it from an under-described event; the counts stay the given
allele's and the diagnostic names the larger one.
- Reading from the right needs the POS gate lifted for the reads it judges: a REF
read starting inside the REF event holds the right windows as the ALT read
starting at the same place does, but only the ALT read was admitted (by its clip),
so long shapes read AD 94–97 against RD 29–51 from equal molecules.
The 2026-10-12 amendments, measured on every arm (the gate panel, matched normals of every panel tumour, ACCESS duplex and simplex with their normals, TEMPO WES, HG002) and on synthetic shapes: - A one-base shorter allele whose flank repeats the longer allele's next bases left a window that ended before the alleles differ: in one matched normal a germline substitution at a delins's first base counted 235 ALT reads (6.6.0, padded: 0). Of the 2,399 reads the windows turned ALT on the panel against 6.6.0, 1,134 fit the ALT throughout and 385 were REF with one substitution, 329 of them at that one row. - Placement from the other flank needs the flank shown: a REF molecule starting inside the event behind a low-quality or N clip fitted ALT through its masked flank. Carriers an aligner writes at the event's other copy (no clip) were left depth only while REF molecules from the same starts were judged; every surveyed genotyper re-scores a read's bases whatever its CIGAR (Delly, Manta, Paragraph, GraphTyper2, GATK, Strelka2, bcftools, ABRA2). - The placement is judged on confident bases, each allele placed from the same anchor at its own length. A first gate weighed the read's bases against its own alignment, at every quality: synthetic REF molecules behind a Q12 clip (a NovaSeq quality bin), aligned plainly from inside the event, counted ALT (51 of 200), and carriers of a long event read from the right lost the ALT when clipped at the window's last base (the gate scored the bases past the window). - A run of changes beside the event on the ALT fragments alone is another allele (count the given allele); an isolated recurring change stays a separate event, masked and named, as decided on 2026-10-09. A run the REF fragments carry too is background, as a germline SNP is: treated as another allele, a germline MNP in the flank left both alleles uncountable (synthetic: RD 6, AD 6 to 0, 0). Beside a run the guard names no larger allele: named from the isolated changes alone, it left out the run every ALT read carries. - No surveyed tool pads windows. GATK, Strelka2 (five bases each side of one breakpoint) and Octopus count a read once its discriminating bases are read; Paragraph genotypes each breakpoint apart; GangSTR, ExpansionHunter and Varlociraptor model spanning bias instead of equalising windows.
Evidence behind RJ-22 (2026-10-07): every read call at insertion rows traced on develop, each read judged by its local haplotype, on RC (ABRA2-realigned), FORTE (STAR) and the WES loci (BWA only, the control with no realigner). - The strict path's junction ALT with a substitution a slide absorbs: RC 28 of 12,015 junction ALT reads (FLT3 ITDs, a BRCA2 AAG row), WES 1 of 1,647, FORTE 0. 24 of the 29 substitutions appear in no other read and 5 also in non-carriers (an SNV on the haplotype); at every row the given ALT is the dominant non-REF haplotype and no other allele recurs. BWA had soft-clipped 19 of the 28 and written 9 with the insert elsewhere in the tract; ABRA2 moves a read only onto a contig with strictly fewer mismatches, and a singleton gets no contig of its own. - The carrier counted REF, measured with the fixed build against develop's outputs: RC 19 reads at 2 rows, both at one BRCA2 insertion row, G>GA (an 8-A haplotype, the anchor read as A plus an inserted A, in 11 or more reads across two samples, which ABRA2 wrote one and two junctions left); WES 2 (one fragment, a singleton anchor substitution); FORTE 2, one written past the scan window at the far end of a GCT tract. All REF to partial; no ALT or depth changed. Scoring the placements for ALT as well would credit the recurring allele (AD 23 → 28 and 28 → 40), so they decide only another allele against a separate event.
A survey: GATK prunes haplotypes seen in fewer than two reads and force-calls the given alleles beside the discovered ones, so a read with one molecule's substitution supports the given ALT; ABRA2 places it on the given allele's contig; bcftools treats every same-length insertion as one allele; GetBaseCountsMultiSample and bam-readcount count the CIGAR at the junction, and count a carrier with the gap elsewhere as REF.
The cases¶
Each group below is a set of shapes in read_judgment_cases.py, run at pure
indels in homopolymers, dinucleotide repeats, duplications and unique sequence,
and at anchor-changing events before an A run.
| Group | Shapes | Status |
|---|---|---|
| REF reads | spanning the tract; ending inside it | decided (RJ-1) |
| Carriers | exact carrier; the ALT at another placement in the tract | decided (RJ-2) |
| Complex, whole windows | REF, substitution only, anchor kept with a length change (another allele, read past the run), exact carrier; ending inside the run, on the base after it, past it (10-A run) | decided (RJ-4, RJ-27) |
| Siblings | a co-annotated SNV inside the span; outside the window | decided (RJ-5) |
| Other indels inside the window | D1 or I1 near the anchor, D2 after it (placed by its bases, onto the anchor for a 10-base insertion); an MNP's REF reads with a 24-bp duplication of the flank written as an insertion right after the block, on a minority of reads (another allele) or as germline background (REF) | decided (RJ-7) |
| Other indels outside the window | D1, D5 or I1 past the tract; a carrier with one | decided (RJ-8) |
| Complex, long events | the same read haplotypes before a 60-A run | decided (RJ-9) |
| Complex, one-sided windows | a 28-to-6 delins: exact carriers and REF reads with a few flank bases on one side (eight on the right, where the event grows through a repeat; four on the left); a 60-to-2 delins: REF reads starting inside the event, exact carriers; carriers ending before a change that recurs on ALT reads only; carriers with a recurring change on the window's last base, and with a run of changes from it on; a REF read starting inside the event behind a low-quality clip; a carrier written at the event's other copy as plain matches; a 17-to-1 delins whose ALT flank repeats the deleted bases' next two: exact carriers, REF reads, and a REF read with the event's first base substituted | decided (RJ-23) |
| Other alleles at the locus | a 28-to-6 delins with another allele of its length on four fragments, one inserted base apart: carriers with that base below --min-baseq (another allele), carriers reading it (ALT), the other allele's reads (another allele); the same with the other allele on two fragments, or absent (the unread carriers count ALT), or co-annotated; an MNP joining a somatic change to a germline SNP beside it: reads showing only the germline base (another allele), the somatic one (ALT), and with no germline allele (ALT) |
decided (RJ-25) |
| Other alleles of REF's length | GC>AT beside the germline GT: REF reads showing only the G (neither); a 28-to-6 delins with a germline change inside its deleted bases on a fifth of the REF molecules: REF reads with that base unread (neither); with no other allele, partly read REF reads (REF); GCA>ACT beside GTA on under a fifth of the REF molecules (neither), on 23% (REF: background at the base it keeps); a germline T at that base in cis with the MNP (GTA reads REF, ATT carriers ALT, those with an indel at the block too) or in trans (GTA reads REF); the T co-annotated (GTA reads partial evidence, RJ-5); a delins with a germline change at a base the ALT keeps, in cis: REF reads with that base unread (REF) | decided (RJ-25, 2026-10-14) |
| Co-annotated components | CC>GT co-annotated with C>G, no fragment spelling G then C in full: carriers reading only the G (ALT); one fragment spelling it beside 20 REF fragments (another allele); beside 100, one (ALT: an error's share) and five (another allele) | decided (RJ-25, 2026-10-14) |
| Background in the grown event | an insertion grown through a CA repeat with a germline SNP inside the repeat: REF reads (REF) and carriers (ALT) carrying it; the same SNP on the carriers alone (another allele); a third base where the background is masked, in the run or at a base an MNP keeps (another allele, on either side); a change at a base the event changes, carried by a third allele's molecules (no separate event) | decided (RJ-23, 2026-10-14) |
| Long deletions | 60 bp (unique), 60 bp with a 3-base microhomology, 1 kb: exact D carriers with four (or three) clean bases past the junction; right- and left-clipped carriers; a split carrier with a hard-clipped supplementary; a hard-clipped primary; REF reads holding four (or three) deleted bases past the microhomology; a REF read with an error inside the window, or 20 bases past it; a deletion of another length; one written as two with bases kept between; a read starting inside the deletion; carriers and REF reads with a recurring change in the window; a REF read starting inside the deletion behind a low-quality or N clip; carriers with a recurring change in the flank (written as a D or a clip) or on the windows' last base, and with a run of changes in the flank or from the last base on; REF reads, and carriers and REF reads, with a run of changes in the flank; left-clipped carriers with two, or four, low-quality flank bases; a carrier written over the deleted bases' end without a clip; REF reads carrying a co-annotated SNV past REF's window, and inside it; carriers and REF reads with a run from the window's last base on whose bases rejoin the allele's after it, or keep mismatching it; carriers with a run of three from the last base on; carriers and REF reads with a phased DNP inside the window; carriers of the deletion two bases right; carriers of a deletion one base longer, and of the given one with a phased DNP, before an A run; carriers with a DNP at the junction whose first base is the deleted one's; carriers of another unit count of a VNTR, alone and beside the given deletion's; overlapping mates whose first ends inside the bases a run must rejoin over; reads of another allele reading like ALT for 12 bases past the windows, then differing, and reads of it ending before they differ; carriers of the same deletion two or three bases right, alone and beside the given deletion's; carriers of another unit count of a VNTR whose units differ at one base; carriers whose change another input row lists, a row listing another base there, and none; a one-unit deletion beside a run of its unit, with carriers of two units short of the run alone (no hold), and with 2 or 3 of them, written or clipped, holding it among 40 or 80 of the given count (the 3-fragment and 5% floor), the two-unit deletion listed, the mirror (two units given, one present), an inserted unit (told at the junction: no hold), holding carriers the aligner places elsewhere as well (no hold), a reference N in the run, one read of each allele from every start (the AD-low limit), the held count named, the run longer than every read (listed or not: named), carriers of the deletion with a phased 1-bp insertion that reads as one more unit deleted (listed: ALT; not listed: held), a co-annotated SNV in the deleted copy beside a present count, units of 1, 2, 4 and 5 bases, and holding carriers with an error in the run, a third base past the difference, or the difference unread (tests/test_unit_count_contract.py) |
decided (RJ-24; runs #285; #296; #297) |
| The ALT across ops | a deletion written as two; a 1-base deletion in a run written D2 + I1 (at the anchor, inside the run); a 1-base insertion written I2 + D1 | decided (RJ-14) |
| Read inputs | read-through adapter base on an SNV (ALT, REF); absent qualities; a hard-clipped read at the previous complex classifier (with an unclipped control) | decided (RJ-10, RJ-11; C29 #207 is a bug fix) |
| Anchor deleted | the anchor deleted, with or without an insertion; an insertion row's anchor deleted | decided (RJ-15) |
| Unreadable inserts | +1 in a run with its inserted base N at the anchor or inside the run, or a letter below --min-baseq; a 10-base insert all N, all below --min-baseq, half masked; the anchor deleted and re-inserted with the insert unreadable (ALT, each) |
decided (RJ-20, RJ-27) |
| Inserts of other bases | a 10-base insert of other bases one junction left and four right (REF); an 8-base one inside its duplicated tract (another allele); the ALT written one junction off with a compensating mismatch (ALT); the ALT with an error at its first inserted base, written one junction right (another allele) | decided (RJ-21) |
| Inserts behind a substitution | +1 in a run, the ALT at the junction with a substitution in the run that all four reads carry (another allele: it recurs in the event); the ALT with its anchor substituted, written one junction left, in a run and as a 10-base insert (another allele) | decided (RJ-22, RJ-26) |
Run python tests/read_judgment_cases.py for the full table: every case's call,
with the read census's verdict next to each pure-indel case.
abbreviations