Preserve pileup calls around ambiguous query bases - #714
Closed
SuhasSrinivasan wants to merge 3 commits into
Closed
Conversation
Open
Contributor
Author
|
Closing this overlapping PR to keep #597 as the single active review path for ordinary IUPAC query bases. The two remaining downstream-state cases and the applicable performance evidence are documented in #597 (comment); this branch remains preserved for its exact tests. The separate |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #668.
Summary
=before tallying and reports it through one aggregate diagnostic; resolving=from the reference is not implemented here.Severity
Severity: High — scientific completeness and reliability
Rationale: Accepted ambiguity can silently remove valid downstream modified calls and coverage while the command exits successfully, or can panic after writing partial output. This can bias pileup counts toward reads without ambiguous observations.
Root cause
The optimized reverse scanner treated every non-ACGT query symbol as unreachable and its complement helper panicked outside A/C/G/T. In both pileup workers, several aligned-position conversions either unwrapped an ambiguous query base or abandoned the entire record. One overrun path also advanced the modification iterator before converting the current query base but saved that pending state only after the fallible conversion, so skipping the observation lost downstream state.
Implementation
R/Y,M/K,B/V,D/H,S,W, andN.Option<DnaBase>.=) before either worker parses modifications or changes a tally. Reject that complete record, increment the existing failed-record total and a dedicated approximate counter, and emit one final explanation of the reference-resolution requirement.Preserved behavior
N_diff; no A/C/G/T identity is invented.=guard adds one allocation-free packed-byte scan per processed record.Non-goals
NorU, negative-strand MM groups, or malformed MM/ML recovery.SEQ =; affected records are rejected before tallying and pileup continues. Deciding whether unresolved IUPAC observations should incrementN_diffis separate policy work.=rejection, and exact optimized/generic scientific and performance oracles. The maintainer should choose or combine the implementations rather than merge both overlapping diffs independently.Behavior before and after
Nbefore a valid downstream 5mC callchr1:1-2, modified count/valid coverage 15a315a8f4557d043736415c4f9743619f39f8f7d31974b3ed620708859df1784SEQ =plus a valid earlier call=as ordinary ambiguity can silently include only part of the recorda85202b69e79e708656e71858e4243cb1cc51e22a44bb9f65650a23dacb407faTesting
Test environment
bb20328778b2a5e3f0f815b36af2ae09c1df7ae77cc1afd1313f8af725dd34635a4620c704a774fe; clean after testing5cecc3fb3a9336068d9e3c68d5c08d678153dd2cCargo.lockSHA-256f9d3389f8fc63c9ad653dad3fbf43a1c26cc54008f0a39e06e71ff6455a1e9b5;rust-htslib0.46.0,hts-sys2.2.0794047e609d4b3993f27bff54b1a6249c93d1d472668b0f766a91fd761eb4f6dcargo test -p mod_kit pileup::base_mods_adapter::base_mods_adapter_tests::test_ambiguous_query_bases_preserve_mm_scanning -- --exact --test-threads=1cargo test -p mod_kit base_mods_adapter_tests --lib -- --test-threads=1cargo test --offline --locked -p mod_kit pileup::pileup_processor::reference_equal_base_tests::odd_length_padding_is_not_a_reference_equal_base --lib -- --exact --test-threads=1=is detected and an odd-length BAM record's unused low padding nibble is not=no-partial-tally regressioncargo test --offline --locked -p modkit --test test_pileup test_pileup_rejects_reference_equal_query_before_tallying -- --exact --test-threads=1cargo test -p modkit --test test_pileup -- --test-threads=1=rejection test exercise optimized and generic workersTMPDIR=/private/tmp/modkit-668-supervisor-full-bb20328 cargo test --offline --locked --workspace --all-targets --no-fail-fast -- --test-threads=141458d8efc760a6849bbc6e95f2322be5d02c4a602ec4e24d24325d942866319; paired reverse output matches the behavior table=branch guard=record before tallying and emits exact 1/1 from the valid control. This guards the branch's=boundary rather than reproducing issue #668's original IUPAC defectcargo build --offline --locked --release -p modkitat the tested headfb9dff56b0b5ec233e5f65f5fed6eb4e029dd408ca4a314c92ca293307f0a4e1; the earlier pre-=artifact did not match and its timing was discardedmodkit pileup rna_top50_tx.bam OUT --reference rna_top50_tx.padded.fa --modified-bases C:m A:a A:17596 T:17802 --no-filtering --threads 8 --io-threads 4 --suppress-progress; 898,198,413-byte/1,632,831-read direct-RNA BAM; one warm-up then U1/F1/U2/F2/U3/F3 release runs--modified-bases2c98dc0193764a410a8d84b1227733ec101f47db5541ec7c313e7d07e1a447c8; raw generic/optimized files are intentionally not compared because their selected reference-position scopes differget_query_base, packed=preflight, adapter frequency/complement, and both overrun state pathsrustfmt --checkon all five changed Rust files;git diff --check upstream/master...HEADTests not performed
R/N/Ysymbols rather than enumerating every IUPAC ambiguity symbol, although the source explicitly covers every supported ambiguity complement pair.N_diffdirectly; exclusion fromN_diffis established by both workers skipping before every tally method.Scientific validation
N_diff.=contributes no partial call, while the matched valid control contributes exactly one call and unit coverage in both workers.Output and compatibility
=is rejected before tallying and produces an aggregate error log because the base identity requires reference resolution.=is whole-record-fatal but not process-fatal, and the command continues after logging aggregate rejection/failure counts. This PR does not make output transactional for unrelated fatal errors.Reviewer guide
base_mods_adapter.rs.=preflight, including its odd-length padding rule, and confirm it precedes all tally mutation in both workers.get_query_basehelper and confirm every ordinary-IUPACNonebranch skips only the current position.break 'overranin both workers.=no-partial-tally regressions.Checklist