Skip to content

fix(codec)!: downsample after filtering to the most common alignment - #731

Merged
nh13 merged 1 commit into
mainfrom
730/nhomer/fix-codec-cap-after-alignment-filter
Aug 12, 2026
Merged

nh13 merged 1 commit into
mainfrom
730/nhomer/fix-codec-cap-after-alignment-filter

Conversation

@nh13

@nh13 nh13 commented Aug 9, 2026 •

Copy link
Copy Markdown
Member

Closes #730.

codec --max-reads applied its cap before filter_to_most_common_alignment_raw, while fgbio filters each strand first, checks --min-reads on the filtered lists, and only then caps — inside ssCaller.consensusCall, which is constructed with maxReadsPerStrand (CodecConsensusCaller.scala:115, 196-198, 234-235).

Capping first samples across a family that still mixes alignment patterns, so the majority pattern among the sampled reads can differ from the majority in the full family. The alignment filter then cuts the family a second time and can push it below --min-reads, rejecting a family fgbio consenses. See #730 for the worked example.

The cap now runs after the filter and the read-count check, and independently per strand.

Dropping the shared index vector is safe

The old code computed one index vector from R1's ranks and applied it to both r1_infos and r2_infos, which kept the two lists index-aligned. Nothing downstream depends on that: filter_to_most_common_alignment_raw already ran independently per strand and routinely returns different lengths, phase 4 takes the longest of each list independently, and phase 5 builds a separate single-strand consensus from each. So the lists were already free to diverge before this change.

Impact

Measured on CODEC.group.adjacency.fgbio.bam:

cap before after delta
--max-reads 2 103,144 103,541 +397
--max-reads 3 105,478 105,539 +61

Runs that do not set --max-reads are unaffected.

Behaviour note

Because each strand is now capped on its own ranks, a template can be retained on one end and dropped on the other when only one end survives the alignment filter. That matches fgbio. The codec --max-reads help text and the CHANGELOG entry added in #727 claimed both ends are always retained together, which is no longer true — both are corrected here.

Testing

codec_cap_runs_after_the_alignment_filter builds the worked example from #730 — ten templates, six carrying the majority alignment and four a minority one, with the three lowest-ranking names deliberately split across both groups — and asserts a consensus is produced. Verified failing against the previous ordering (count == 0, the family rejected as InsufficientReads) and passing after.

cargo ci-fmt, ci-lint and ci-test are clean: 7195 passed, 30 skipped.

Stacked on #727

Based on 725/nhomer/fix-deterministic-consensus-downsampling, since it rewrites the same block. Merge #727 first; this PR retargets to main once that lands.

Risk: codec consensus output changes, pinned by fgbio-compatible alignment filtering and reproducible hash-based downsampling; unsafe changes: none, and the CLAUDE.md allowlist is unchanged; memory bounds, queue capacity, and thread/backpressure policy changes: none.

Fix: Filter each strand to its majority alignment, validate --min-reads, then downsample independently with --max-reads.

  • Update help text and the changelog to document independent strand downsampling and possible paired-end divergence.
  • Add regression coverage for post-filter capping, zero-cap rejection, independent strand selection, and consensus generation.
  • Recover 397 consensus records with --max-reads 2 and 61 with --max-reads 3 on CODEC.group.adjacency.fgbio.bam.
  • Runs without --max-reads remain unchanged.

@nh13
nh13 temporarily deployed to github-actions August 9, 2026 05:13 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

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: b2328500-335c-4c4d-a366-f9b7511862e8

📥 Commits

Reviewing files that changed from the base of the PR and between dceccc5 and 75dc637.

📒 Files selected for processing (1)
  • crates/fgumi-consensus/src/codec_caller.rs

Walkthrough

Pre-filter capping could reject families that fgbio would consensus. The pipeline now filters alignments, validates minimum reads, and caps each strand independently. Tests and --max-reads documentation cover the new behavior.

Changes

CODEC consensus downsampling

Layer / File(s) Summary
Filter, validate, and cap consensus reads
crates/fgumi-consensus/src/codec_caller.rs
The pipeline filters each strand to its most common alignment before minimum-read validation and capping. The in-place helper retains the lowest-ranked records independently for R1 and R2. A zero cap rejects the family as insufficient input.
Validation and command documentation
crates/fgumi-consensus/src/codec_caller.rs, src/lib/commands/codec.rs
Integration tests cover post-filter capping, independent strand selection, zero-cap rejection, and consensus generation. The --max-reads help text documents reproducible per-strand downsampling and possible mate divergence.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant consensus_reads_raw
  participant AlignmentFilter
  participant ReadCap
  participant ConsensusCaller
  consensus_reads_raw->>AlignmentFilter: Filter each strand to its common alignment
  AlignmentFilter-->>consensus_reads_raw: Return filtered reads
  consensus_reads_raw->>ReadCap: Apply validated per-strand max-reads cap
  ReadCap-->>ConsensusCaller: Return retained reads
  ConsensusCaller-->>consensus_reads_raw: Generate strand consensus
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commit format and clearly describes the codec downsampling change.
Linked Issues check ✅ Passed The changes implement filter-first processing, minimum-read validation, independent strand capping, and documentation updates required by [#730].
Out of Scope Changes check ✅ Passed The changes are limited to codec consensus logic and related --max-reads documentation for [#730].

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

@codecov

codecov Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.03846% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 94.11%. Comparing base (ade4853) to head (75dc637).

Files with missing lines Patch % Lines
crates/fgumi-consensus/src/codec_caller.rs 99.03% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #731      +/-   ##
==========================================
- Coverage   94.12%   94.11%   -0.01%     
==========================================
  Files         181      181              
  Lines      109415   109503      +88     
==========================================
+ Hits       102987   103062      +75     
- Misses       6428     6441      +13     

☔ 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 commented Aug 9, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

@nh13

nh13 commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 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 4671-4703: FLAG MISSING COVERAGE for divergent per-strand
retention. Extend the consensus_reads_from_sam_records test fixture so R1 and R2
filtering retains different template sets, rather than sharing each template’s
CIGAR, then assert that each strand’s cap is computed from its own filtered
reads instead of capping pairs jointly.
- Around line 740-742: Validate max_reads_per_strand at the options boundary so
zero is rejected and cannot reach the capping logic in the surrounding
codec-caller flow. Also guard the existing max_reads_per_strand branch before
both cap_infos_to_lowest_ranking calls, ensuring programmatic callers with zero
are rejected rather than emptying r1_infos and r2_infos.
🪄 Autofix

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: 81fcdb86-07b0-48c4-9af5-7dd79da13b43

📥 Commits

Reviewing files that changed from the base of the PR and between 00bba7b and dceccc5.

⛔ Files ignored due to path filters (1)
  • CHANGELOG.md is excluded by !**/CHANGELOG.md
📒 Files selected for processing (2)
  • crates/fgumi-consensus/src/codec_caller.rs
  • src/lib/commands/codec.rs

Comment thread crates/fgumi-consensus/src/codec_caller.rs
Comment thread crates/fgumi-consensus/src/codec_caller.rs
Base automatically changed from 725/nhomer/fix-deterministic-consensus-downsampling to main August 10, 2026 13:47
`codec --max-reads` applied its cap before `filter_to_most_common_alignment_raw`,
while fgbio filters each strand first, checks `--min-reads` on the filtered
lists, and only then caps (inside `ssCaller.consensusCall`).

Capping first samples across a family that still mixes alignment patterns, so
the majority pattern among the sampled reads can differ from the majority in the
full family. The alignment filter then cuts the family a second time and can
push it below `--min-reads`, rejecting a family fgbio consenses.

The cap is now applied after the filter and the read-count check, and
independently per strand, matching fgbio. Nothing downstream pairs the two
strand lists by index, so dropping the shared index vector is safe: phase 4
takes the longest of each list independently and phase 5 builds a separate
single-strand consensus from each.

On a CODEC library this recovers 397 consensus records at `--max-reads 2`
(103,144 -> 103,541) and 61 at `--max-reads 3` (105,478 -> 105,539). Runs
without `--max-reads` are unaffected.

Because each strand is now capped on its own ranks, a template can be retained
on one end and dropped on the other when only one end survives the alignment
filter; the help text and CHANGELOG no longer claim otherwise.

Closes #730
@nh13
nh13 force-pushed the 730/nhomer/fix-codec-cap-after-alignment-filter branch from dceccc5 to 75dc637 Compare August 11, 2026 02:52
@nh13
nh13 temporarily deployed to github-actions August 11, 2026 02:52 — with GitHub Actions Inactive
@nh13

nh13 commented Aug 12, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 12, 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 06d40d0 into main Aug 12, 2026
16 checks passed
@nh13
nh13 deleted the 730/nhomer/fix-codec-cap-after-alignment-filter branch August 12, 2026 15:41
@nh13 nh13 mentioned this pull request Aug 12, 2026
@nh13 nh13 mentioned this pull request Aug 15, 2026

This branch was previously deployed

1 inactive deployment
github-actions — 75dc6379 Deployed Aug 11, 2026 by nh13 via coverage #3428
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.

codec --max-reads downsamples before filtering to the most common alignment, diverging from fgbio

1 participant