Repository navigation
fix(metrics): grouping-key correctness — strand tie-break, unsuffixed MI, library/cell partition, reject duplex-to-simplex (DXM3-02/03/05/07, SIMM3-01) - #532
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughGrouping keys now include library and cell-barcode identity, duplex metrics retain unsuffixed MI entries in DS-family counts, and simplex metrics reject inputs containing the same base UMI on both strands. ChangesMetrics grouping and validation
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #532 +/- ##
==========================================
+ Coverage 92.59% 92.64% +0.05%
==========================================
Files 166 166
Lines 99950 100184 +234
==========================================
+ Hits 92546 92815 +269
+ Misses 7404 7369 -35 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
cde1627 to
8c51b0d
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/commands/shared_metrics.rs`:
- Around line 573-576: Update the test suite around
test_families_partitioned_by_library to add coverage for cell_barcode
partitioning: construct two templates with identical coordinate, strand, and
library values but different CB tags, then assert they are assigned to separate
families. Ensure the test exercises the cell_barcode field derived from
SamTag::CB.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8289b2d9-0329-45f6-8ec2-d352217853de
📒 Files selected for processing (3)
src/lib/commands/duplex_metrics.rssrc/lib/commands/shared_metrics.rssrc/lib/commands/simplex_metrics.rs
8c51b0d to
7b75bec
Compare
7b75bec to
7801c8a
Compare
7801c8a to
3745bab
Compare
…uffixed MI (DXM3-03, DXM3-05, DXM3-07) DXM3-07: the duplex-metrics canonical mate-key ordered by (ref, unclipped-5') only, dropping the strand tie-break that fgumi's own group/dedup canonicalization uses ((ref, pos, strand), unified_pipeline/base.rs) and that fgbio's ReadInfo r1Earlier applies. When both mates of a duplex share an identical (ref, unclipped-5'), the two strands canonicalized to different keys and were reported as two single-strand (ab=1, ba=0) families instead of one (ab=1, ba=1). Add strand to the canonical tuple (positive sorts first, matching group's <=). DXM3-03: an unsuffixed MI (no /A,/B) incremented neither the AB nor BA strand counter, so its DS family got ds_size = 0 and was silently dropped by the family-size histogram (which iterates 1..=max), undercounting ds_families and skewing ds_fraction denominators. Treat an unsuffixed MI as the AB strand, matching fgbio's Pair(ab=n, ba=0) single-strand DS family. Root-cause fix: size-0 never occurs. DXM3-05: the unclipped-5' helper counts soft AND hard clips, which deliberately matches samtools (unclipped_start in bam.c, used by markdup + template-coordinate sort) and htsjdk, keeping the metrics key consistent with fgumi's own group/dedup coordinates. Only the docstring was wrong (it claimed fgbio parity; fgbio's unSoftClippedStart is soft-only). Corrected the docstring; no behavior change.
…put to simplex-metrics (DXM3-02, SIMM3-01) DXM3-02: the duplex/simplex metrics grouping key (ReadInfoKey) omitted the library (RG->LB) and cell barcode (CB), so reads from different libraries or cells at the same coordinate/strand merged into one CS/DS family — wrong cs_count, read_pairs, and DS classification on multi-library or single-cell input. Add library (via read_info::LibraryIndex, matching group/dedup) and a hardcoded CB cell barcode to ReadInfoKey, mirroring fgbio's ReadInfo(library, cellBarcode) and its takeNextGroup boundary. No --cell-tag flag: fgumi deliberately hardcodes CB (group.rs/dedup.rs), unlike fgbio. SIMM3-01: simplex-metrics groups per-UMI by base_umi (MI with /A,/B stripped) and consensus-calls both strands' RX together with no strand-swap. For duplex-UMI input the two strands carry swapped UMI halves (ACGT-TGCA vs TGCA-ACGT), so the merged consensus ties to garbage (NNNN) and distorts umi_counts. There is no fgbio oracle for this; per the chosen behavior, detect a base UMI observed on both the /A and /B strands within a coordinate group and fail loud, pointing the user at duplex-metrics.
3745bab to
8cbb9cb
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Five duplex/simplex-metrics grouping-key correctness fixes. The governing principle: the metrics grouping key must match fgumi's own
group/dedup(samtools-style coordinates, strand canonicalization, LB/CB partitioning) — not fgbio blindly. Two audit "parity" claims turned out to be over-reaches and are handled accordingly.Stacked on #506 (
nh/fix-duplex-metrics-empty-half-umi) — the only open PR touchingshared_metrics.rs.DXM3-07 — strand tie-break in the canonical mate-key
The canonical
ReadInfoKeyordered mates by(ref, unclipped-5')only, dropping the strand tie-break that fgumi's owngroup/dedupuse ((ref, pos, strand),unified_pipeline/base.rs) and that fgbio'sReadInfo.r1Earlierapplies. When both mates of a duplex share an identical(ref, unclipped-5'), the two strands canonicalized to different keys and were reported as two single-strand(ab=1, ba=0)families instead of one(ab=1, ba=1). Added strand to the tuple (<=, matchinggroup).DXM3-03 — unsuffixed MI counted as a single-strand DS family
An unsuffixed
MI(no/A,/B) incremented neither strand counter, so its DS family gotds_size = 0and was silently dropped by the family-size histogram (which iterates1..=max), undercountingds_familiesand skewingds_fraction. Now treated as the AB strand (ab=n, ba=0), matching fgbio'sPair(n, 0)single-strand DS family. Root-cause fix — size-0 never occurs.DXM3-02 — partition families by library (and cell)
ReadInfoKeyomitted the library (RG→LB) and cell barcode (CB), so reads from different libraries/cells at the same coordinate/strand merged into one CS/DS family. Addedlibrary(viaread_info::LibraryIndex, matchinggroup/dedup) + a hardcodedCBto the key, mirroring fgbio'sReadInfo(library, cellBarcode)and itstakeNextGroupboundary.No
--cell-tagflag — fgumi deliberately hardcodesCB(group.rs/dedup.rs); fgbio exposes--cell-tag, fgumi does not. This corrects the audit's suggestion.DXM3-05 — doc-only (intentional samtools divergence)
The unclipped-5′ helper counts soft and hard clips, matching samtools
unclipped_start(bam.c, used bymarkdup+ template-coordinate sort) and htsjdkgetUnclippedStart, keeping the metrics key consistent with fgumi's owngroup/dedupcoordinates. This is an intentional divergence from fgbio's soft-onlyunSoftClippedStart. The only defect was the docstring falsely claiming fgbio parity — corrected. No behavior change.SIMM3-01 — reject duplex input to simplex-metrics
simplex-metrics groups per-UMI by
base_umi(MI with/A,/Bstripped) and consensus-calls both strands'RXtogether with no strand-swap. For duplex-UMI input the two strands carry swapped UMI halves (ACGT-TGCAvsTGCA-ACGT), so the merged consensus ties to garbage (NNNN). There is no fgbio oracle here; per the chosen behavior, simplex-metrics now detects a base UMI observed on both the/Aand/Bstrands within a coordinate group and fails loud, pointing at duplex-metrics.fgbio parity verification
Built a 2-library × (AB+BA) fixture at one coordinate,
TemplateCoordinate-sorted, and ran fgbio 4.1.0CollectDuplexSeqMetricsandfgumi duplex-metrics. Both report identicalfamily_sizes:Two CS families of size 2 (library-partitioned) — confirming DXM3-02.
Tests (TDD, red-first)
duplex_metrics.rs:test_duplex_strands_cogroup_when_mates_share_five_prime(DXM3-07),test_unsuffixed_mi_counts_as_single_strand_ds_family(DXM3-03),test_families_partitioned_by_library(DXM3-02).simplex_metrics.rs:test_simplex_metrics_rejects_duplex_input(SIMM3-01).Commits
17f4e1a0— DXM3-03, DXM3-05, DXM3-07 (grouping-key parity)cde1627e— DXM3-02, SIMM3-01 (library/cell partition + duplex-input rejection)Summary by CodeRabbit