Skip to content

fix(simulate): template-coordinate order via canonical fgumi-sort + hermetic tests - #576

Merged
nh13 merged 2 commits into
mainfrom
nh/test-simulate-sort-hermetic
Jul 19, 2026
Merged

nh13 merged 2 commits into
mainfrom
nh/test-simulate-sort-hermetic

Conversation

@nh13

@nh13 nh13 commented Jul 11, 2026 •

Copy link
Copy Markdown
Member

The bug

fgumi simulate claims its output is template-coordinate sorted, but for ~0.7% of records it wasn't. Reproduced (1000 molecules, seed 42): 44 of 5994 records are out of order versus samtools sort --template-coordinate.

Root cause: simulate carried its own template-coordinate key (simulate/sort.rs, TemplateCoordKey::for_f1r2_pair), computed from intended parameters under a hard-coded "R1 is forward/left" assumption. But simulate emits both read-1 orientations, so for reverse-R1 (F2R1) pairs the key's pos1/strand disagreed with the record's actual leftmost-5′ coordinate — exactly what samtools keys on. A second, hand-rolled ordering that drifted from the one fgumi already has.

(Discovered while auditing the #[ignore]d test_simulate_sort tests — they were also stale, missing the now-required --reference, which is why the failure looked like a crash rather than a mis-sort.)

The fix (principled: one source of truth)

Delete simulate/sort.rs. Generate records in molecule order to an unsorted temp BAM, then sort into the final output with the canonical fgumi-sort engine (RawExternalSorter, SortOrder::TemplateCoordinate) — the same one fgumi sort/fgumi group use, which matches samtools sort --template-coordinate exactly at the coordinate-key level. Correct for every orientation by construction. grouped-reads forces the tertiary (library|mi) key lane since it always writes MI tags.

Verified: simulate-vs-samtools position diffs 44 → 0; output is now byte-identical to fgumi sort --order template-coordinate of the same records.

Hermetic tests (the regression gate)

Rewrote test_simulate_sort: run the prebuilt binary via CARGO_BIN_EXE_fgumi (no recursive cargo run → no timeout), generate a deterministic reference FASTA fixture, gate on #[cfg(feature="simulate")], and verify with fgumi sort --verify --order template-coordinate (fgumi's own checker) instead of a brittle byte-exact samtools diff. An #[rstest] table covers mapped-reads and grouped-reads simplex/duplex/large. No longer #[ignore]d — they run in the normal suite.

Verification

  • cargo ci-test → 4726 passed, 0 failed (incl. the 4 un-ignored sort tests; the deleted simulate/sort.rs unit tests are covered by the canonical fgumi-sort tests).
  • cargo ci-fmt, cargo ci-lint (-D warnings -W clippy::pedantic) → clean.

Independent of #572/#573/#574/#575.

Summary by CodeRabbit

  • Bug Fixes

    • Improved simulated BAM output ordering for mapped and grouped reads by delegating template-coordinate ordering to the canonical sorting engine.
    • Refined unmapped-read ordering behavior to match expected template-coordinate semantics.
    • Improved consistency of MI-related ordering in grouped-read outputs.
  • Tests

    • Reworked simulation sorting integration tests to run hermetically using the prebuilt fgumi binary (no reliance on external tools).
    • Consolidated and extended coverage for mapped, simplex grouped, duplex grouped, and larger duplex scenarios, validating via fgumi sort --verify --order template-coordinate.

@nh13
nh13 temporarily deployed to github-actions July 11, 2026 23:54 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Jul 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

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: 00eee876-e360-402b-b6ba-880e3771f67c

📥 Commits

Reviewing files that changed from the base of the PR and between 47aa253 and 829cebd.

📒 Files selected for processing (6)
  • src/lib/commands/simulate/common.rs
  • src/lib/commands/simulate/grouped_reads.rs
  • src/lib/commands/simulate/mapped_reads.rs
  • src/lib/commands/simulate/mod.rs
  • src/lib/commands/simulate/sort.rs
  • tests/integration/test_simulate_sort.rs
💤 Files with no reviewable changes (3)
  • src/lib/commands/simulate/mod.rs
  • src/lib/commands/simulate/sort.rs
  • src/lib/commands/simulate/common.rs

Walkthrough

Risk is concentrated in output-order identity and temporary-BAM finalization. Simulation now delegates template-coordinate ordering to fgumi-sort, while integration tests verify mapped, simplex, and duplex outputs.

Changes

Simulation sorting pipeline

Layer / File(s) Summary
Remove simulator sorting contracts
src/lib/commands/simulate/common.rs, src/lib/commands/simulate/mod.rs, src/lib/commands/simulate/sort.rs
MoleculeInfo, simulator exports, effective_molecule_locus, TemplateCoordKey, related ordering implementations, and dependent unit tests are removed.
Generate and externally sort BAMs
src/lib/commands/simulate/mapped_reads.rs, src/lib/commands/simulate/grouped_reads.rs
Mapped and grouped simulations write records to temporary unsorted BAMs, preserve truth TSV generation, then use RawExternalSorter for template-coordinate ordering; grouped reads enable tertiary lane keys.
Validate sorted simulation outputs
tests/integration/test_simulate_sort.rs
Feature-gated parameterized tests run the prebuilt binary against deterministic mapped, simplex, and duplex scenarios and verify ordering with fgumi sort --verify.

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

Sequence Diagram(s)

sequenceDiagram
  participant fgumi_simulate
  participant TemporaryBAM
  participant RawExternalSorter
  participant FinalBAM
  participant IntegrationTest
  fgumi_simulate->>TemporaryBAM: write simulated records in molecule order
  TemporaryBAM->>RawExternalSorter: provide unsorted BAM
  RawExternalSorter->>FinalBAM: write template-coordinate sorted BAM
  IntegrationTest->>FinalBAM: verify ordering with fgumi sort
Loading

Possibly related PRs

🚥 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 summarizes the main change: simulate ordering now uses canonical fgumi-sort and the tests were made hermetic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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/test-simulate-sort-hermetic

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

@codecov

codecov Bot commented Jul 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.83333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.06%. Comparing base (5accbbc) to head (829cebd).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/lib/commands/simulate/grouped_reads.rs 95.83% 1 Missing ⚠️
src/lib/commands/simulate/mapped_reads.rs 95.83% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #576      +/-   ##
==========================================
+ Coverage   92.99%   93.06%   +0.07%     
==========================================
  Files         167      166       -1     
  Lines      103266   102849     -417     
==========================================
- Hits        96030    95717     -313     
+ Misses       7236     7132     -104     

☔ 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 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 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 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.

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/commands/simulate/mapped_reads.rs (1)

232-243: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Remove the obsolete O(N) molecule metadata buffers.

External sorting means generation can stream directly in mol_id order.

  • src/lib/commands/simulate/mapped_reads.rs#L232-L243: draw the seed/unmapped decision inside the write loop.
  • src/lib/commands/simulate/grouped_reads.rs#L225-L230: draw the seed inside the write loop.
🤖 Prompt for 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.

In `@src/lib/commands/simulate/mapped_reads.rs` around lines 232 - 243, Remove the
eager O(N) molecule metadata collection around the mapped-read generation and
draw each molecule’s seed and unmapped decision directly inside the write loop,
preserving deterministic RNG advancement for every molecule. Apply the
corresponding change in src/lib/commands/simulate/mapped_reads.rs lines 232-243
and draw each seed inside the write loop in
src/lib/commands/simulate/grouped_reads.rs lines 225-230; update the surrounding
generation logic to use these per-iteration values without the metadata buffers.
🤖 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 `@tests/integration/test_simulate_sort.rs`:
- Around line 59-106: Replace the self-consistency-only `fgumi sort --verify`
assertion in `simulate_output_is_template_coordinate_sorted` with an independent
expected-result oracle. Generate or trace the expected ordered record names and
flags for mapped, simplex, and duplex cases, explicitly covering F2R1, then read
the simulated BAM and assert every record’s name and flag matches the expected
sequence without omissions or extras. Retain coverage for all existing
subcommands and duplex variants.

---

Outside diff comments:
In `@src/lib/commands/simulate/mapped_reads.rs`:
- Around line 232-243: Remove the eager O(N) molecule metadata collection around
the mapped-read generation and draw each molecule’s seed and unmapped decision
directly inside the write loop, preserving deterministic RNG advancement for
every molecule. Apply the corresponding change in
src/lib/commands/simulate/mapped_reads.rs lines 232-243 and draw each seed
inside the write loop in src/lib/commands/simulate/grouped_reads.rs lines
225-230; update the surrounding generation logic to use these per-iteration
values without the metadata buffers.
🪄 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: 5dbc371a-457f-4f93-9c22-8533fcbfdc68

📥 Commits

Reviewing files that changed from the base of the PR and between f55ac4b and 47aa253.

📒 Files selected for processing (6)
  • src/lib/commands/simulate/common.rs
  • src/lib/commands/simulate/grouped_reads.rs
  • src/lib/commands/simulate/mapped_reads.rs
  • src/lib/commands/simulate/mod.rs
  • src/lib/commands/simulate/sort.rs
  • tests/integration/test_simulate_sort.rs
💤 Files with no reviewable changes (2)
  • src/lib/commands/simulate/mod.rs
  • src/lib/commands/simulate/sort.rs

Comment thread tests/integration/test_simulate_sort.rs
nh13 added 2 commits July 18, 2026 11:25
…umi-sort engine

`simulate mapped-reads`/`grouped-reads` computed their own template-coordinate
sort key (`simulate/sort.rs`, `TemplateCoordKey::for_f1r2_pair`) from intended
parameters, hard-coding an "R1 is forward/left" assumption. But `simulate` emits
both read-1 orientations, so for reverse-R1 (F2R1) pairs the key's `pos1`/strand
disagreed with the record's actual leftmost 5' coordinate — the exact fields
`samtools sort --template-coordinate` keys on. Result: ~0.7% of records
(1000 molecules, seed 42: 44 of 5994) were emitted out of template-coordinate
order, so the "template-coordinate sorted" output wasn't.

Root cause is duplication: a second, hand-rolled ordering that drifted from the
one fgumi already has. Fix by deleting `simulate/sort.rs` and generating records
in molecule order to an unsorted temp BAM, then sorting into the final output
with the canonical `fgumi-sort` `RawExternalSorter` (`SortOrder::TemplateCoordinate`)
— the same engine `fgumi sort`/`fgumi group` use and that matches
`samtools sort --template-coordinate` exactly at the coordinate-key level.
`grouped-reads` forces the tertiary (library|mi) key lane since it always writes
MI tags. Correct for every orientation by construction; output is now byte-identical
to `fgumi sort --order template-coordinate` of the same records.

`MoleculeInfo` no longer carries a sort key (molecules are emitted in id order).
…rt --verify`

The previous `test_simulate_sort` tests were `#[ignore]`d, stale, and slow:
they shelled out to `cargo run --release` (recursively compiling fgumi inside the
test, blowing nextest's timeout), omitted the now-required `--reference`, and
byte-compared against an external `samtools`.

Rewrite them to:
- run the prebuilt binary via `CARGO_BIN_EXE_fgumi` (no recursive compile),
- generate a small deterministic reference FASTA fixture in a tempdir,
- gate on `#[cfg(feature = "simulate")]` so the binary has the subcommand,
- verify the output with `fgumi sort --verify --order template-coordinate` — fgumi's
  own canonical sort-order checker — instead of a brittle byte-exact samtools diff.

An `#[rstest]` table covers mapped-reads, grouped-reads simplex/duplex, and a
larger duplex dataset. These now run in the normal suite (no `#[ignore]`, no
samtools) and are the regression gate for the sort fix in the preceding commit.
@nh13
nh13 force-pushed the nh/test-simulate-sort-hermetic branch from 47aa253 to 829cebd Compare July 18, 2026 15:26
@nh13
nh13 temporarily deployed to github-actions July 18, 2026 15:26 — with GitHub Actions Inactive
@nh13

nh13 commented Jul 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 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 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 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 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 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 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 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 c018d4f into main Jul 19, 2026
11 checks passed
@nh13
nh13 deleted the nh/test-simulate-sort-hermetic branch July 19, 2026 15:26

This branch was previously deployed

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