Skip to content

fix(flagstat): match samtools counts, alignment priority and percentages - #175

Draft
NicoDeVeaux wants to merge 5 commits into
mainfrom
ndv/fix-flagstat-qcfail-proper-dup
Draft

NicoDeVeaux wants to merge 5 commits into
mainfrom
ndv/fix-flagstat-qcfail-proper-dup

Conversation

@NicoDeVeaux

@NicoDeVeaux NicoDeVeaux commented Oct 23, 2026 •

Copy link
Copy Markdown

QC-failed records now populate the second flagstat column, unmapped records cannot count as properly paired, and QC-failed duplicates remain duplicates. The flagstat writer and the legacy stats accumulator now both give SECONDARY priority over SUPPLEMENTARY, so dual-flagged records are counted once. samtools stats reports secondary records alone as non-primary alignments, and percentage division follows samtools' C float expression before formatting.

This extends the secondary-priority and stats semantics proposed by Benjamin Demaille in #131 to the separate FlagstatCounts path introduced here. Merging the previous versions of #131 and this PR unchanged would leave the new counter double-counting. #131 remains open for maintainer coordination; adopting the samtools code's precedence for #125 still needs maintainer agreement.

The regression tests no longer modify the oracle to preserve the old overlap behavior. They retain the original samtools-generated all-flags fixture, cover overlap combined with QC-fail/duplicate flags, compare partitioned counter merges, and check large-count rounding. Integration tests use Cargo's actual test binary rather than falling back to an unrelated debug build. The branch also includes the recorded crossbeam-epoch/libz-sys lockfile updates and a separate iterator-only fix for three existing Clippy warnings.

Validation of candidate a9083c:

  • All 244 release tests pass on macOS and Linux: 205 library, 12 binary, 25 integration and two doc tests. Formatting and strict Clippy pass on both.
  • Native samtools 1.22.1 and 1.24 agree with the candidate in 48 targeted F/S CLI cases and 24 aggregate all-flags CLI cases, across 1/2/4/8 threads and two repeats. A compiled production-counter probe agrees in all 12,288 flag/placement rows.
  • Four pinned nf-core module tasks pass on two original paired-end BAMs. MultiQC 1.35 parsing and actual CLI raw exports agree with the corresponding samtools outputs for both pairs. These real fixtures have no QC-failed or supplementary reads; the synthetic cases exercise those triggers.
  • The local cached security audit passed at its recorded advisory snapshot. Fresh upstream CI and a fresh Linux audit remain separate checks.

This is targeted flagstat/stats evidence. It does not establish complete RNA-QC equivalence, Wave/container packaging, a full rnaseq run, genuine single-end coverage or strand-selection equivalence. Other stats fields, including reads properly paired, have separate definitions and are outside these targeted repairs. The wider frozen campaign retains five old-baseline expectation failures, and empty input still exits zero with one thread but nonzero with 2/4/8; no expectations were changed after scoring. The separate living review has two scientific PASS gates and nine pending recipes, so full merge/release acceptance remains UNKNOWN. Its byte/source/build records are trusted evidence, without machine or source-to-binary attestation.

This counting PR stays independent of the #118 noodles migration and its stacked #177/#178 fixes.

This update is written by GPT-6 on Nico DeVeaux's behalf. The original PR was prepared with Claude Code.

NicoDeVeaux and others added 5 commits October 23, 2026 11:13
…plicate counts

Failing tests for three divergences from samtools flagstat 1.22.1:

- QC-failed reads (0x200) are counted in the QC-passed column; the second
  column is always 0.
- "properly paired" counts a PAIRED|PROPER_PAIR record that is itself
  unmapped (samtools requires !UNMAP, bam_stat.c:61).
- A QC-failed duplicate (0x600) is in neither "duplicates" column, while
  "primary duplicates" counts it.

The unit tests check every 12-bit flag against a transcription of samtools'
flagstat_loop; the integration tests compare `rustqc rna` output with
golden output from samtools 1.22.1. The SECONDARY|SUPPLEMENTARY line
(#125) is kept at its current behaviour and pinned as such.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stat_loop

flagstat now keeps its own `[QC-passed, QC-failed]` counters
(`FlagstatCounts`), counted like samtools' `flagstat_loop` (bam_stat.c):

- QC-failed reads (0x200) go in the second column, with their own
  percentages, instead of being folded into the first.
- "properly paired" requires the read itself to be mapped.
- "duplicates" counts every 0x400 record, not the RSeQC bam_stat cascade
  counter that drops QC-failed duplicates.

The SECONDARY|SUPPLEMENTARY case (#125) is unchanged: such a record still
counts on both lines. The counters that only fed flagstat are removed from
BamStatAccum/BamStatResult; those samtools stats reads are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port PR #131 secondary priority to both legacy and QC-split counters. Match the pinned samtools C percentage arithmetic, restore unmodified exhaustive oracles, and cover QC-failed duplicate overlaps and partition merges.

Select the Cargo-provided integration binary at compile time so release tests keep their profile and CARGO_TARGET_DIR. Add a raw production-counter example for independent differential validation.

Fixes #125
Replace the three existing needless_range_loop findings with fixed-size iterator zips. Preserve cycle/channel order and u64 addition order; floating percentage calculations are unchanged.

Validated with cargo fmt --check, strict cargo clippy, and the complete 244-test release suite.
@NicoDeVeaux NicoDeVeaux changed the title fix(flagstat): split counts by QC pass/fail and follow samtools' flagstat_loop fix(flagstat): match samtools counts, alignment priority and percentages Nov 1, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant