Skip to content

Commit 4dc74a9

Browse files
committed
Harden read-quality indexing and document exon-boundary insertion handling
- anchor_base_quality now returns None when the CIGAR-derived query index falls past the stored sequence (a malformed CIGAR whose query length exceeds SEQ), instead of reading a bogus quality. Well-formed reads are unaffected. - Document why an insertion anchored at an internal exon's last base is left out of the spliced-CDS model: the inserted bases sit on the exon|intron boundary and are genomically ambiguous (end-of-exon vs spliced-out intron start), so they are reported intergenic rather than assigned a possibly-wrong codon. This is intentional; the exclusive upper bound (< segment.end) encodes it.
1 parent 21640f0 commit 4dc74a9

2 files changed

Lines changed: 14 additions & 0 deletions

File tree

src/read_count/observation.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ pub(super) fn anchor_base_quality(rec: &bam::Record, position: usize) -> Option<
9898
// silently failing every quality gate.
9999
return Some(u8::MAX);
100100
}
101+
// Defensive: a malformed CIGAR whose query length exceeds the stored
102+
// sequence could yield an index past the quality scores. Treat that as "no
103+
// observation" rather than reading a bogus quality.
104+
if qidx >= rec.sequence().len() {
105+
return None;
106+
}
101107
Some(qual.iter().nth(qidx).unwrap_or(0))
102108
}
103109

src/variants/codon/transcript_model.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ pub(super) fn transcript_offset_for_position(gene: &Gene, position: usize) -> Op
5656
None
5757
}
5858

59+
/// Whether an insertion anchored at `position` falls strictly inside this CDS
60+
/// segment. The upper bound is exclusive (`< segment.end`) on purpose: a VCF
61+
/// insertion places the inserted bases *after* the anchor, so an anchor at the
62+
/// segment's last base sits on the exon|intron boundary, where the inserted
63+
/// sequence is genomically ambiguous between "end of this exon" and "start of
64+
/// the intron" (spliced out). Such boundary insertions are intentionally left
65+
/// out of the spliced-CDS model rather than assigned a possibly-wrong codon;
66+
/// they surface as intergenic instead. Anchors inside an exon are unaffected.
5967
pub(super) fn insertion_anchor_in_segment(segment: &CdsSegment, position: usize) -> bool {
6068
position >= segment.start && position < segment.end
6169
}

0 commit comments

Comments
 (0)