Skip to content

feat(bam-io): add the shared grouping and library-lookup domain types (R0) - #734

Merged
nh13 merged 1 commit into
main-runallfrom
nh/runall-12-bam-io-grouping
Aug 10, 2026
Merged

nh13 merged 1 commit into
main-runallfrom
nh/runall-12-bam-io-grouping

Conversation

@nh13

@nh13 nh13 commented Aug 10, 2026 •

Copy link
Copy Markdown
Member

Prerequisite for porting src/lib/pipeline/steps/. Additive: nothing calls the new modules yet.

Why

The typed-step tree imports fgumi_bam_io::{DecodedRecord, GroupKey, GroupKeyConfig, Grouper, compute_group_key_from_raw, name_hash_key}. On this branch those types live in src/lib/unified_pipeline/{base,bam}.rs, and name_hash_key does not exist at all — so the new pipeline tree would have to import from the tree it is meant to replace, which inverts the dependency and breaks when unified_pipeline is eventually deleted.

This moves them next to the raw-record helpers they operate on, matching where feat-runall put them. feat-runall's own pipeline/mod.rs states the intent: "Shared grouping/decoded-record domain types … live in the fgumi-bam-io crate, next to the raw-record helpers they operate on."

What

  • crates/fgumi-bam-io/src/grouping.rs (779 lines) — DecodedRecord, GroupKey, GroupKeyConfig, Grouper, compute_group_key_from_raw, name_hash_key
  • crates/fgumi-bam-io/src/library.rs (193 lines) — LibraryLookup, LibraryIndex, build_library_lookup, which the group key depends on
  • module declarations + re-exports in lib.rs
  • ahash added to the crate's dependencies, via workspace = true (this branch's convention; feat-runall pins "0.8" directly). It was already a workspace dependency, used by fgumi-consensus, fgumi-pipeline-core, fgumi-sort, fgumi-umi.

Both files are self-contained: their only imports are noodles::sam and each other.

Duplication

unified_pipeline keeps its own copies of the equivalent types. That duplicate is intentional and temporary — it retires when unified_pipeline is deleted, after the commands migrate. Nothing is changed in unified_pipeline here, so no existing behaviour moves.

Verification

Full local gate on this branch:

  • cargo ci-fmt, cargo ci-lint, cargo ci-tag-literals — clean
  • RUSTDOCFLAGS="-D warnings" cargo ci-doc — clean
  • ./scripts/publish-crates.sh --check — clean
  • cargo ci-test — 8192 passed, 30 skipped (up 6 from 8186; the ported files bring their own tests)

Risk: command output changes — none; unsafe changes — none, and the CLAUDE.md allowlist is unchanged; memory bounds, queue capacity, and thread/backpressure policy changes — none.

  • Added shared grouping and library-lookup domain types to fgumi-bam-io.
  • Added GroupKey, DecodedRecord, GroupKeyConfig, Grouper, and raw-record grouping helpers.
  • Added LibraryLookup, LibraryIndex, and SAM-header library mapping.
  • Re-exported the new APIs from the crate root.
  • Added the workspace ahash dependency.
  • Existing unified_pipeline types remain temporarily. No command uses the new modules yet.
  • Formatting, linting, documentation, crate checks, and tests passed: 8,192 passed and 30 skipped.

@nh13
nh13 temporarily deployed to github-actions August 10, 2026 00:36 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Aug 10, 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: 6a3cf1f7-da24-4905-806d-cd3fd6177a2d

📥 Commits

Reviewing files that changed from the base of the PR and between 804bb73 and fbc534f.

📒 Files selected for processing (2)
  • crates/fgumi-bam-io/src/grouping.rs
  • crates/fgumi-bam-io/src/library.rs

Walkthrough

Adds shared BAM library indexing and hashing utilities. Adds normalized grouping keys, decoded-record UMI caching, raw BAM key computation, and the Grouper trait. Exposes these APIs through the crate root and adds focused tests.

Changes

BAM grouping infrastructure

Layer / File(s) Summary
Library indexing and hashing
crates/fgumi-bam-io/Cargo.toml, crates/fgumi-bam-io/src/library.rs
Adds LibraryLookup and LibraryIndex from SAM read groups. Adds unknown-library handling and shared AHash helpers for read groups, cell barcodes, and read names.
Grouping key and decoded-record contracts
crates/fgumi-bam-io/src/grouping.rs
Adds normalized paired and single-end GroupKey values, DecodedRecord raw-record access with UMI caching, and GroupKeyConfig constructors.
Raw key computation and grouping interface
crates/fgumi-bam-io/src/grouping.rs
Adds raw BAM metadata extraction, stamped-coordinate and name-only fallback handling, paired-record MC handling, single-end fallback, and the Grouper trait.
Validation and public exports
crates/fgumi-bam-io/src/grouping.rs, crates/fgumi-bam-io/src/lib.rs
Adds tests for key construction, ordering, fallback behavior, name-hash parity, and cache invalidation. Exports grouping and library APIs from the crate root.

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

Sequence Diagram(s)

sequenceDiagram
  participant BAMRecord
  participant GroupKeyConfig
  participant LibraryIndex
  participant GroupKey
  participant Grouper
  BAMRecord->>GroupKeyConfig: provide raw BAM record
  GroupKeyConfig->>LibraryIndex: hash RG and cell metadata
  LibraryIndex-->>GroupKeyConfig: return metadata values
  GroupKeyConfig->>GroupKey: build normalized grouping key
  GroupKey-->>Grouper: add decoded record
  Grouper-->>Grouper: emit completed groups or retain pending state
Loading

Possibly related PRs

  • fulcrumgenomics/fgumi#529: Related template-coordinate handling for secondary and supplementary reads during grouping-key computation.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title uses valid Conventional Commit syntax and accurately describes the shared grouping and library-lookup additions to bam-io.
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.

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

@nh13

nh13 commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

@codecov

codecov Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.48414% with 57 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main-runall@8b0956c). Learn more about missing BASE report.

Files with missing lines Patch % Lines
crates/fgumi-bam-io/src/grouping.rs 88.67% 54 Missing ⚠️
crates/fgumi-bam-io/src/library.rs 97.54% 3 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff               @@
##             main-runall     #734   +/-   ##
==============================================
  Coverage               ?   93.95%           
==============================================
  Files                  ?      232           
  Lines                  ?   126650           
  Branches               ?        0           
==============================================
  Hits                   ?   119000           
  Misses                 ?     7650           
  Partials               ?        0           

☔ 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 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: 3

🤖 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-bam-io/src/grouping.rs`:
- Around line 574-779: Add a focused test for the primary branch of
compute_group_key_from_raw, constructing a mapped paired record with an MC tag,
an RG tag resolved by a non-default LibraryIndex, and a CB value passed through
cell_tag: Some(CB). Assert the complete GroupKey, including populated mate
ref/position/strand, non-zero library_idx, and cell_hash, then build the mate
and verify both records normalize to the same key. Keep the test’s flag and
input coverage aligned with the corresponding typed/raw sibling implementations.
- Around line 192-203: Make the data field of DecodedRecord private, keeping
raw_bytes_mut as the sole mutable accessor so cache invalidation remains
enforced. Update any necessary access within DecodedRecord’s own implementation
without exposing data to crate-internal callers.

In `@crates/fgumi-bam-io/src/library.rs`:
- Around line 96-193: Add a #[cfg(test)] mod tests alongside LibraryIndex
covering from_header, get, library_name, and build_library_lookup. Construct
headers with missing, literal "unknown", and shared LB values to verify index 0
fallback, deduplication, and stable library names; also assert absent RG hashes
and out-of-range indices return unknown. Verify build_library_lookup keys
entries by RG identifier rather than LB value, using the existing test utilities
and public symbols.
🪄 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: b5e82451-7127-4221-a859-b074ee8d7da9

📥 Commits

Reviewing files that changed from the base of the PR and between 8b0956c and f3698f5.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (4)
  • crates/fgumi-bam-io/Cargo.toml
  • crates/fgumi-bam-io/src/grouping.rs
  • crates/fgumi-bam-io/src/lib.rs
  • crates/fgumi-bam-io/src/library.rs

Comment thread crates/fgumi-bam-io/src/grouping.rs Outdated
Comment thread crates/fgumi-bam-io/src/grouping.rs
Comment thread crates/fgumi-bam-io/src/library.rs
@nh13
nh13 force-pushed the nh/runall-12-bam-io-grouping branch from f3698f5 to 804bb73 Compare August 10, 2026 01:47
@nh13
nh13 temporarily deployed to github-actions August 10, 2026 01:47 — with GitHub Actions Inactive
@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: 4

🤖 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-bam-io/src/grouping.rs`:
- Around line 433-441: Extract the duplicated empty-name handling into a shared
helper near name_hash_key, using LibraryIndex::hash_name(None) for empty names
and Some(name) otherwise. Update both name_hash_key and
compute_group_key_from_raw to call this helper, preserving identical name-hash
behavior between the two paths.
- Around line 646-674: In the grouping test around the paired-key assertions,
replace the non-unknown check for key.pos2 with an assertion against the
expected MC-derived mate coordinate. Remove the tautological expected
GroupKey::paired construction and equality assertion, since it only
re-normalizes key’s own fields; retain the direct assertions for the other key
components.
- Around line 443-476: Update compute_group_key_from_raw so secondary and
supplementary records preserve the TC template coordinate by reusing the
existing read_tc_template_coordinate logic before returning the grouped key,
rather than returning only name_hash. Add coverage for mapped records with an
empty CIGAR and ensure the implementation handles unclipped_5prime_from_raw_bam
returning i32::MAX consistently.

In `@crates/fgumi-bam-io/src/library.rs`:
- Around line 20-35: Update the public documentation comments around
`LibraryLookup` and the referenced sections to wrap Rust identifiers and type
names—including `LB`, `ReadInfo::from`, `GroupKey`, `AHash`, and `u16`—in
backticks, while preserving the existing prose and links.
🪄 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: 456a9e1f-fe71-44dc-9804-e23fdd949386

📥 Commits

Reviewing files that changed from the base of the PR and between f3698f5 and 804bb73.

📒 Files selected for processing (2)
  • crates/fgumi-bam-io/src/grouping.rs
  • crates/fgumi-bam-io/src/library.rs

Comment thread crates/fgumi-bam-io/src/grouping.rs
Comment thread crates/fgumi-bam-io/src/grouping.rs
Comment thread crates/fgumi-bam-io/src/grouping.rs Outdated
Comment thread crates/fgumi-bam-io/src/library.rs Outdated
The typed-step pipeline tree needs `DecodedRecord`, `GroupKey`,
`GroupKeyConfig`, `Grouper`, `compute_group_key_from_raw` and
`name_hash_key`. Today those live in `src/lib/unified_pipeline/{base,bam}.rs`
(and `name_hash_key` does not exist at all), so the new tree would have to
depend on the tree it is meant to replace.

Move them next to the raw-record helpers they operate on, in `fgumi-bam-io`,
along with the `LibraryLookup`/`LibraryIndex` read-group-to-library machinery
the group key depends on. Both files are self-contained — their only imports are
`noodles::sam` and each other.

`unified_pipeline` keeps its own copies for now; the duplicate is retired when
that tree is deleted.
@nh13
nh13 force-pushed the nh/runall-12-bam-io-grouping branch from 804bb73 to fbc534f Compare August 10, 2026 02:47
@nh13
nh13 temporarily deployed to github-actions August 10, 2026 02:47 — with GitHub Actions Inactive
@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.

@nh13
nh13 merged commit 01284b2 into main-runall Aug 10, 2026
17 checks passed
@nh13
nh13 deleted the nh/runall-12-bam-io-grouping branch August 10, 2026 03:37
nh13 added a commit that referenced this pull request Aug 12, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 12, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 12, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 13, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 13, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 13, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 13, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 14, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 14, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 14, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 14, 2026
…one definition

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 14, 2026
…one definition (#741)

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 19, 2026
…#734)

The typed-step pipeline tree needs `DecodedRecord`, `GroupKey`,
`GroupKeyConfig`, `Grouper`, `compute_group_key_from_raw` and
`name_hash_key`. Today those live in `src/lib/unified_pipeline/{base,bam}.rs`
(and `name_hash_key` does not exist at all), so the new tree would have to
depend on the tree it is meant to replace.

Move them next to the raw-record helpers they operate on, in `fgumi-bam-io`,
along with the `LibraryLookup`/`LibraryIndex` read-group-to-library machinery
the group key depends on. Both files are self-contained — their only imports are
`noodles::sam` and each other.

`unified_pipeline` keeps its own copies for now; the duplicate is retired when
that tree is deleted.
nh13 added a commit that referenced this pull request Aug 19, 2026
…one definition (#741)

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 19, 2026
…#734)

The typed-step pipeline tree needs `DecodedRecord`, `GroupKey`,
`GroupKeyConfig`, `Grouper`, `compute_group_key_from_raw` and
`name_hash_key`. Today those live in `src/lib/unified_pipeline/{base,bam}.rs`
(and `name_hash_key` does not exist at all), so the new tree would have to
depend on the tree it is meant to replace.

Move them next to the raw-record helpers they operate on, in `fgumi-bam-io`,
along with the `LibraryLookup`/`LibraryIndex` read-group-to-library machinery
the group key depends on. Both files are self-contained — their only imports are
`noodles::sam` and each other.

`unified_pipeline` keeps its own copies for now; the duplicate is retired when
that tree is deleted.
nh13 added a commit that referenced this pull request Aug 19, 2026
…one definition (#741)

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.
nh13 added a commit that referenced this pull request Aug 23, 2026
…#734)

The typed-step pipeline tree needs `DecodedRecord`, `GroupKey`,
`GroupKeyConfig`, `Grouper`, `compute_group_key_from_raw` and
`name_hash_key`. Today those live in `src/lib/unified_pipeline/{base,bam}.rs`
(and `name_hash_key` does not exist at all), so the new tree would have to
depend on the tree it is meant to replace.

Move them next to the raw-record helpers they operate on, in `fgumi-bam-io`,
along with the `LibraryLookup`/`LibraryIndex` read-group-to-library machinery
the group key depends on. Both files are self-contained — their only imports are
`noodles::sam` and each other.

`unified_pipeline` keeps its own copies for now; the duplicate is retired when
that tree is deleted.
nh13 added a commit that referenced this pull request Aug 23, 2026
…one definition (#741)

`DecodedRecord`, `GroupKey`, `GroupKeyConfig`, `LibraryIndex`, `LibraryLookup`,
`build_library_lookup`, and the `Grouper` trait each existed twice: once in
`fgumi-bam-io` (ported in #734) and once in `unified_pipeline` / `read_info`.
The copies were textually identical apart from field visibility and doc
formatting, and the duplication was deliberate — #734 left the umbrella copies
in place so nothing had to be rewired.

That worked while the ported step library only ever *produced* these values.
It stops working at the first ported step that hands one to an umbrella
grouper: `GroupBam` calls `TemplateGrouper::add_records`, and the two identical
definitions are two incompatible types, so the call cannot be written at all.

Keep the `fgumi-bam-io` definition and re-export it from both former homes, so
every existing `crate::unified_pipeline::DecodedRecord` and
`crate::read_info::LibraryIndex` path resolves unchanged. Two supporting
changes fall out:

- `GroupKey::has_mate_position` only existed on the umbrella copy; ported to
  `fgumi-bam-io` so the surviving definition is a superset of both.
- `grouper.rs` reached into `DecodedRecord`'s fields directly, which are
  private on the `fgumi-bam-io` copy (made so during #734's review). Those five
  sites now go through `into_raw_bytes` / `record` / `raw_bytes`, which is what
  the accessors are for.

Net -483 lines with no behavior change; the full suite is unchanged at 8322.

This branch was previously deployed

1 inactive deployment
github-actions — fbc534f7 Deployed Aug 10, 2026 by nh13 via coverage #3412
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