Skip to content

fix(codec,consensus): soft-only overlap-clip boundary, MC-independent codec clip, fgbio-faithful quality masking (CODEC3-03/04/05/06) - #533

Merged
nh13 merged 1 commit into
mainfrom
nh/fix-codec-masking-clip
Jul 18, 2026
Merged

nh13 merged 1 commit into
mainfrom
nh/fix-codec-masking-clip

Conversation

@nh13

@nh13 nh13 commented Jul 10, 2026 •

Copy link
Copy Markdown
Member

Summary

W6 of the final-audit burn-down: the codec masking/clip cluster. Drives CODEC3-03/04/05/06 to fgbio parity and documents CODEC3-07 as an intentional divergence. Stacked on #505 (nh/fix-codec-fr-pair-rejection) — the only open PR touching overlap.rs/codec_caller.rs — and retargets to main on merge.

Every finding was re-verified against fgbio 4.x source (both sides read), reproduced against the real fgbio CallCodecConsensusReads before and after, and covered by RED-first unit tests.

Findings

CODEC3-03 (S2) — overlap-clip mate boundary counted hard clips

num_bases_extending_past_mate_raw (shared by the simplex, duplex, and codec callers, mirroring fgbio UmiConsensusCaller.numBasesExtendingPastMate) derived the mate boundary from the MC tag counting soft + hard clips. fgbio uses mateUnSoftClippedStart/End — soft only — so a hard-clipped mate shifted the clip amount. Fixed to compute the boundary soft-only.

This is intentionally scoped to overlap clipping. The samtools-style soft + hard unclipped 5' position used for template-coordinate sorting and grouping (mate_unclipped_5prime, consumed by fgumi-sort and the grouping pipeline) is deliberately left unchanged — that key must follow samtools' convention, not fgbio's.

CODEC3-04 (S3) — overlap clip silently skipped when MC absent

The MC-tag path returns 0 (no clip) when the MC tag is missing, silently under-clipping. Codec always holds both primary FR reads, so it now derives the boundary from the mate record in hand (num_bases_extending_past_mate_vs_mate_raw), mirroring fgbio updateMateCigars (which backfills the mate CIGAR from the in-group mate before clipping). The MC-based entry point is retained for the simplex/duplex callers.

CODEC3-05 (S2 → S1 with --single-strand-qual) — single-strand tails never masked

pad_consensus fills single-strand tails with lowercase n (NO_CALL_BASE_LOWER), but the mask check tested only == NO_CALL_BASE (uppercase N), so the tails — the exact target of --single-strand-qual — were never masked. Now matches fgbio's a(i) ∈ {n,N} || b(i) ∈ {n,N}.

CODEC3-06 (S2, conditional) — outer-base masking order and semantics

fgbio applies outer masking first and assigns the quality; fgumi applied single-strand first, then outer as min. Rewrote mask_consensus_quals_query_based to match fgbio maskCodecConsensusQuals: outer first (assign), single-strand second (assign) — so single-strand masking wins where the two regions overlap.

CODEC3-07 (S3) — cell-barcode conflict guard: intentional divergence (documented, not fixed)

fgbio groups by MI only, then requires a single distinct CB across the molecule and errors on conflict. fgumi groups by the composite key MI\tCB (MiGroupIterator::with_cell_tag, wired in codec.rs), so every record reaching a single consensus group already shares one cell barcode — fgbio's cross-barcode conflict guard is structurally inapplicable. This is an intentional single-cell divergence (consistent with fgumi's opinionated hardcoded-CB design); documented in code, no behavior change.

Real-tool parity evidence (fgbio 4.x CallCodecConsensusReads)

Fixtures: a single-strand-tail molecule (--single-strand-qual 20 --outer-bases-qual 10), a hard-clipped-mate molecule, and an MC-absent molecule.

  • Before: fgumi left the single-strand tails at Q45 (fgbio Q20) and applied outer masking as min at the ends; it rejected the hard-clip and MC-absent molecules that fgbio consensus-called.
  • After: BAM content (seq + cigar + qual) is byte-identical between fgumi and fgbio across every molecule.

Tests

  • overlap.rs: soft-only mate boundary (..._soft_only_mate_end), MC-independent mate-record path (..._vs_mate_raw_no_mc_uses_mate), and MC/mate-record agreement without hard clips. RED-verified (soft+hard gives 5, soft-only gives 10).
  • codec_caller.rs: mask_consensus_quals_query_based lowercase-n masking (CODEC3-05) and outer-first-then-single-strand-wins (CODEC3-06). Both RED-verified against the old logic.
  • test_codec_command.rs: end-to-end --single-strand-qual masking of the single-strand tails (baseline vs masked), addressing the BS5 "option-gated behavior never exercised" gap.

cargo ci-fmt && cargo ci-lint && cargo ci-test all clean (2216 tests).

Not in this PR

Summary by CodeRabbit

  • Bug Fixes
    • Improved paired-read consensus clipping using soft-only mate boundaries, improving behavior when mate details (including MC tag) are absent or malformed.
    • Updated single-strand quality masking to correctly mask lowercase n tails and to apply outer masking first, with single-strand masking overriding on overlaps.
  • New Features
    • Added an order-independent mate-versus-mate overlap clipping helper to improve consistent overlap calculations.
  • Tests
    • Added an end-to-end regression test covering --single-strand-qual (baseline vs masked tail qualities) and expanded overlap/masking regression coverage.

@nh13
nh13 temporarily deployed to github-actions July 10, 2026 05:33 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9a94198-0989-4149-a405-56273b7fb743

📥 Commits

Reviewing files that changed from the base of the PR and between 814acb0 and 6048732.

📒 Files selected for processing (4)
  • crates/fgumi-consensus/src/codec_caller.rs
  • crates/fgumi-raw-bam/src/lib.rs
  • crates/fgumi-raw-bam/src/overlap.rs
  • tests/integration/test_codec_command.rs

Walkthrough

Mate-based clipping now derives soft-only boundaries from MC tags or mate records, while consensus quality masking recognizes lowercase padding and gives single-strand masking precedence over outer masking. Unit and integration tests cover the revised clipping and masking behavior.

Changes

CODEC overlap and masking

Layer / File(s) Summary
Soft-only mate overlap calculation
crates/fgumi-raw-bam/src/overlap.rs, crates/fgumi-raw-bam/src/lib.rs
Overlap clipping uses strand-aware soft-only mate boundaries, supports mate-record fallback without MC tags, excludes hard clips, rejects malformed CIGAR data, saturates oversized calculations, and re-exports the mate-record helper.
Consensus clipping and quality masking
crates/fgumi-consensus/src/codec_caller.rs
Consensus clipping uses the symmetric mate helper; query-based masking recognizes uppercase and lowercase no-call padding, with single-strand masking overriding outer masking.
Behavior regression coverage
crates/fgumi-raw-bam/src/overlap.rs, crates/fgumi-consensus/src/codec_caller.rs, tests/integration/test_codec_command.rs
Unit and integration tests verify soft-only boundaries, malformed and oversized CIGAR inputs, missing-MC fallback, symmetric dovetails, lowercase single-strand tails, and masking precedence.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Codec
  participant Overlap
  participant QualityMasking
  participant ConsensusBAM
  Codec->>Overlap: compute symmetric mate-extension clips
  Overlap-->>Codec: return R1/R2 clip lengths
  Codec->>QualityMasking: mask outer and single-strand qualities
  QualityMasking-->>Codec: return masked consensus qualities
  Codec->>ConsensusBAM: write consensus record
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main codec/consensus clipping and masking changes in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nh/fix-codec-masking-clip

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.78543% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.95%. Comparing base (24d7f7e) to head (6048732).

Files with missing lines Patch % Lines
crates/fgumi-raw-bam/src/overlap.rs 98.38% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #533      +/-   ##
==========================================
+ Coverage   92.94%   92.95%   +0.01%     
==========================================
  Files         167      167              
  Lines      103119   103337     +218     
==========================================
+ Hits        95845    96059     +214     
- Misses       7274     7278       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 2e793c2 to 9598288 Compare July 10, 2026 05:41
@nh13
nh13 temporarily deployed to github-actions July 10, 2026 05:41 — with GitHub Actions Inactive
@nh13

nh13 commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

Both reviewers run (§0 step 6); all findings were in-diff and addressed by amending the commit.

CodeRabbit CLI (--base nh/fix-codec-fr-pair-rejection) — 4 findings, all fixed:

  • (major) overlap.rs num_bases_extending_past_mate_vs_mate_raw guarded on the per-record is_fr_pair_raw, which is asymmetric for dovetail pairs (htsjdk/samtools#1771) — a dovetail-forward pair the codec caller accepts via is_primary_fr_pair_raw could have its forward clip zeroed. Switched to the symmetric per-pair is_primary_fr_pair_raw(rec, mate) (both records are in hand) + added a ..._symmetric_on_dovetail regression test.
  • (major) codec_caller.rs clip path — same root cause; resolved by the guard change above, so the mate-based clip is now consistent with the pair-level FR gate at the surrounding filter.
  • (major) integration test — strengthened the unmasked-tail assertion to > Q20 and rely on the differential (baseline high vs masked == ss_qual) as the masking-function oracle (a full interior-profile assertion would pin the consensus-quality model, which the repo's test-function-not-implementation convention discourages).
  • (minor) integration test — unmasked-tail threshold tightened from > 2 to > 20.

Local CR-style review — 1 finding, fixed: the public rustdoc on num_bases_extending_past_mate_raw linked to the pub(crate) unclipped_other_start (rustdoc private_intra_doc_links warning); retargeted to the public mate_unclipped_5prime.

cargo ci-fmt && ci-lint && ci-test green (2216 tests).

@nh13

nh13 commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

Parity note: the before/after evidence was additionally re-confirmed against the released fgbio 4.1.0 (fgbio CallCodecConsensusReads), not only the dev build — fixed-fgumi output is byte-identical (seq+cigar+qual) to 4.1.0 across all fixtures, and 4.1.0's codec behavior matches the source checkout used for the source-level verification. CODEC3-07's premise also holds on 4.1.0 (it errors on the conflicting-CB fixture).

@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 9598288 to 4a05caf Compare July 10, 2026 06:06
@nh13
nh13 temporarily deployed to github-actions July 10, 2026 06:06 — with GitHub Actions Inactive
@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 4a05caf to 7289c94 Compare July 10, 2026 16:23
@nh13
nh13 temporarily deployed to github-actions July 10, 2026 16:23 — with GitHub Actions Inactive
Base automatically changed from nh/fix-codec-fr-pair-rejection to main July 10, 2026 16:46
@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 7289c94 to 668c0cc Compare July 11, 2026 01:14
@nh13
nh13 temporarily deployed to github-actions July 11, 2026 01:14 — with GitHub Actions Inactive
@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 668c0cc to e8ee6b0 Compare July 12, 2026 15:09
@nh13
nh13 temporarily deployed to github-actions July 12, 2026 15:09 — with GitHub Actions Inactive
@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 2259d6b to 9adc759 Compare July 18, 2026 01:54
@nh13
nh13 temporarily deployed to github-actions July 18, 2026 01:54 — with GitHub Actions Inactive
@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 9adc759 to 814acb0 Compare July 18, 2026 02:00
@nh13
nh13 temporarily deployed to github-actions July 18, 2026 02:00 — with GitHub Actions Inactive
@nh13

nh13 commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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 `@crates/fgumi-consensus/src/codec_caller.rs`:
- Around line 3405-3425: Update
test_mask_consensus_quals_outer_first_then_single_strand_wins so an outer-only
position starts below Q10, such as Q5, while retaining the overlap position’s
behavior. Adjust the expected masked qualities to require that outer masking
assigns Q10 to that position, thereby distinguishing assignment from min while
preserving single-strand Q20 precedence at position 0.

In `@crates/fgumi-raw-bam/src/overlap.rs`:
- Around line 206-207: Update the alignment-end calculation in the
overlap-processing function around reference_length_from_cigar and alignment_end
to use a checked or saturating addition that cannot overflow when ref_len is
oversized. Ensure malformed raw-BAM input fails closed before clipping, and add
a regression test covering an oversized reference-consuming CIGAR.
🪄 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: cc168976-61e9-42e0-8e18-4056e16bf68e

📥 Commits

Reviewing files that changed from the base of the PR and between 2259d6b and 814acb0.

📒 Files selected for processing (4)
  • crates/fgumi-consensus/src/codec_caller.rs
  • crates/fgumi-raw-bam/src/lib.rs
  • crates/fgumi-raw-bam/src/overlap.rs
  • tests/integration/test_codec_command.rs

Comment thread crates/fgumi-consensus/src/codec_caller.rs
Comment thread crates/fgumi-raw-bam/src/overlap.rs Outdated
… codec clip, fgbio-faithful quality masking

Codec masking/clip parity fixes (CODEC3-03/04/05/06); CODEC3-07 documented
as an intentional divergence.

- CODEC3-03: the consensus overlap-clip mate boundary
  (num_bases_extending_past_mate_raw, shared by the simplex/duplex/codec
  callers) counted soft+hard clips; fgbio uses soft-only
  (mateUnSoftClippedStart/End). Compute it soft-only. The samtools-style
  soft+hard unclipped 5' used for template-coordinate sort/group
  (mate_unclipped_5prime) is deliberately left unchanged.
- CODEC3-04: codec derives the overlap-clip boundary from the mate record in
  hand (num_bases_extending_past_mate_vs_mate_raw) rather than the read's MC
  tag, so clipping still occurs when MC is absent -- mirroring fgbio
  updateMateCigars, which backfills the mate CIGAR from the in-group mate.
- CODEC3-05: single-strand quality masking missed the lowercase-'n'-padded
  single-strand tails (it checked uppercase 'N' only); now matches fgbio's
  a(i) in {n,N} || b(i) in {n,N}.
- CODEC3-06: outer-base masking now runs first and assigns (not min),
  matching fgbio maskCodecConsensusQuals order and semantics.

CODEC3-07: fgumi groups reads by the composite key MI\tCB, so a
within-molecule cell-barcode conflict cannot occur and fgbio's require(<=1)
guard is inapplicable -- an intentional single-cell divergence, documented in
code (not a fix).

Verified against fgbio 4.x CallCodecConsensusReads: before-fix outputs
diverged (unmasked tails at Q45 vs Q20; hard-clip and MC-absent molecules
rejected by fgumi but consensus-called by fgbio); after-fix BAM content
(seq+cigar+qual) is byte-identical across all fixtures.
@nh13
nh13 force-pushed the nh/fix-codec-masking-clip branch from 814acb0 to 6048732 Compare July 18, 2026 02:26
@nh13
nh13 temporarily deployed to github-actions July 18, 2026 02:26 — with GitHub Actions Inactive
@nh13

nh13 commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13
nh13 merged commit a72e4ec into main Jul 18, 2026
10 checks passed
@nh13
nh13 deleted the nh/fix-codec-masking-clip branch July 18, 2026 14:55
@nh13 nh13 mentioned this pull request Jul 17, 2026
nh13 added a commit that referenced this pull request Aug 20, 2026
…#760)

RawRecordClipper::clip_extending_past_mate_ends (the live 'fgumi clip' path) measured read-through past the mate in reference space, so an indel near the clip boundary over-clipped (whole-read clip -> the read unmapped, and its mate then left unclipped) or under-clipped. It now delegates the count to the query-space core (num_bases_extending_past_mate_vs_mate_raw), computes both reads' counts before clipping either (order-independence), and adds existing 3' hard-clipping back into the total. Ports fgbio#1172's deterministic cases and adds property tests (never-unmap, idempotent, symmetric).

Removes the now-redundant reference-space duplicates: SamRecordClipper's past-mate methods (that struct is never constructed in production) and record_utils::num_bases_extending_past_mate; redirects the #[cfg(test)] consensus bridge to the correct core.

The FR gate goes through the symmetric is_primary_fr_pair_raw (via the vs_mate entry) rather than per-record is_fr_pair_raw, adopting fgumi's established classification (#505/#533) that is intentionally more correct than fgbio/htsjdk on dovetails. The general simplex/duplex consensus path still uses the per-record gate (see #839).
nh13 added a commit that referenced this pull request Aug 20, 2026
…#760)

RawRecordClipper::clip_extending_past_mate_ends (the live 'fgumi clip' path) measured read-through past the mate in reference space, so an indel near the clip boundary over-clipped (whole-read clip -> the read unmapped, and its mate then left unclipped) or under-clipped. It now delegates the count to the query-space core (num_bases_extending_past_mate_vs_mate_raw), computes both reads' counts before clipping either (order-independence), and adds existing 3' hard-clipping back into the total. Ports fgbio#1172's deterministic cases and adds property tests (never-unmap, idempotent, symmetric) over a generator that exercises real read-through (dovetail) and aligned-base overhang clips, with an in-code non-vacuous-coverage check.

Removes the now-redundant reference-space duplicates: SamRecordClipper's past-mate methods (that struct is never constructed in production) and record_utils::num_bases_extending_past_mate; redirects the #[cfg(test)] consensus bridge to the correct core.

The FR gate goes through the symmetric is_primary_fr_pair_raw (via the vs_mate entry) rather than per-record is_fr_pair_raw, adopting fgumi's established classification (#505/#533) that is intentionally more correct than fgbio/htsjdk on dovetails. The general simplex/duplex consensus path still uses the per-record gate (see #839).
nh13 added a commit that referenced this pull request Aug 21, 2026
…#760)

RawRecordClipper::clip_extending_past_mate_ends (the live 'fgumi clip' path) measured read-through past the mate in reference space, so an indel near the clip boundary over-clipped (whole-read clip -> the read unmapped, and its mate then left unclipped) or under-clipped. It now delegates the count to the query-space core (num_bases_extending_past_mate_vs_mate_raw), computes both reads' counts before clipping either (order-independence), and adds existing 3' hard-clipping back into the total. Ports fgbio#1172's deterministic cases and adds property tests (never-unmap, idempotent, symmetric) over a generator that exercises real read-through (dovetail) and aligned-base overhang clips, with an in-code non-vacuous-coverage check.

Removes the now-redundant reference-space duplicates: SamRecordClipper's past-mate methods (that struct is never constructed in production) and record_utils::num_bases_extending_past_mate; redirects the #[cfg(test)] consensus bridge to the correct core.

The FR gate goes through the symmetric is_primary_fr_pair_raw (via the vs_mate entry) rather than per-record is_fr_pair_raw, adopting fgumi's established classification (#505/#533) that is intentionally more correct than fgbio/htsjdk on dovetails. The general simplex/duplex consensus path still uses the per-record gate (see #839).

This branch was previously deployed

1 inactive deployment
github-actions — 60487320 Deployed Jul 18, 2026 by nh13 via coverage #2676
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