Repository navigation
Solo: refuse what the read loops cannot do, check barcode and UMI input - #360
Open
BenjaminDEMAILLE wants to merge 1 commit into
Open
BenjaminDEMAILLE wants to merge 1 commit into
BenjaminDEMAILLE wants to merge 1 commit into
Conversation
Options the solo loops have no code for, and more than one --soloUMIdedup, are refused instead of writing empty or zero files with exit 0. A whitelist of the wrong length is fatal. CB_UMI_Complex positions must parse and set the UMI width. --soloUMIlen above 32 is refused. soloCellFiltering decompresses features.tsv. The gene name tag reaches a GTF given at mapping. CellReads.stats is counted per feature. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 2, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #354 (findings 4, 8, 9, and items 21, 22, 23, 26, 27).
Base:
main. See "Conflicts" below for #345 and #346. This is one PR because all of it is the same theme: solo input that is accepted, then gives a wrong or empty result with exit 0.Fixture for the tables: the tiny solo genome from the audit, 200 reads,
--soloBarcodeReadLength 0. "Solo STAR" has a limit on this machine: the Homebrew 2.7.11b binary stops atcould not open input file /geneInfo.tabon any solo run that reaches the transcriptome (#345 notes the same), so STAR's exit codes below only exist where it stops earlier. Everything about STAR is observed output; the source was not read.Summary of measurements
main--soloCBlen 16--soloUMIlen 33CB_UMI_Complex, no--soloUMIpositionCB_UMI_Complex,--soloUMIposition oops--quantMode GeneCountsgeneInfo.tab)--soloUMIdedup 1MM_All ExactgeneInfo.tab)Finding 4: side outputs that are empty
Problem
--soloTypewith--quantMode GeneCounts TranscriptomeSAM --outReadsUnmapped Fastxexits 0 with zero counts, an empty BAM and an empty FASTQ.align_reads_soloandalign_reads_solo_petake no quantification context, no unmapped writers and no chimeric or BySJout stage, andrun_smartseqhas none of them either.Change
The STARsolo block of
src/params/mod.rsrefuses, with--soloType, each of:--quantMode GeneCounts,--quantMode TranscriptomeSAM,--quantGeneCoverage,--quantGeneSplicing,--outReadsUnmapped Fastx,--outFilterType BySJout,--chimSegmentMinabove 0,--waspOutputMode.Deliberate divergence:
DIVERGENCE.md§1.10Needs maintainer sign-off. STAR's documentation allows these with solo; I could not run them here. Refusing can stop a command that "worked" before, but what it produced was empty files. If someone uses
--outFilterType BySJoutwith solo today, its filter was silently not applied, and that run now stops. The right long-term answer is implementing them, which finding 19 (shared read loop stage) would make easier.test/parity_suite.sh's two solo runs use none of these flags.§1.10 is numbered after §1.9, which #356, #347 and #348 all take, so a renumber is likely when they land.
Finding 8: whitelist length
Problem
A 14-base whitelist with
--soloCBlen 16gives an empty matrix and exit 0. Worse, packing drops the length, so a barcode made of leadingAs and a shorter entry can compare equal.What STAR does
Exit 104,
the total length of barcode sequence is 14 not equal to expected.Change
SoloContext::buildcompares the whitelist withlayout.cb_segment_lens().load_complexdoes the same for eachCB_UMI_Complexfile, so 6+10 cannot pass for 10+6.match_cbreturnsNoMatchon a length difference. The anchored layout, where length can vary by read, is the only way to get there now. A segment whose two ends use different anchors has no fixed length and so skips the startup check.Exit code is 1, not STAR's 104. This repo does not reproduce STAR's exit numbers in this path.
Finding 9:
CB_UMI_ComplexUMIProblem
--soloUMIposition,unwrap_or((0, 0))gave every read the same empty UMI: 200 reads count as 1.filter_map, so a CB segment could vanish.UBtag was--soloUMIlen, not the position's. An 8-base UMI with the default of 10 got a 10-baseUB.Change
check_positionsruns at validation: every spec must parse, with the anchored parser when an adapter is set.SoloContext.umi_lencomes fromlayout.umi_len(). Only a UMI whose ends use different anchors, which has no fixed width, falls back to--soloUMIlen.count.rstwice,lib.rsonce).Item 21:
--soloUMIlenabove 32UMIs pack into a
u64. 33 bases corrupted them; STAR exits 102. Now refused at validation, and aCB_UMI_Complexposition wider than 32 also. Exit code is 2 (clap), not 102.Item 22: several
--soloUMIdedupEach value was validated, then only the first was used. STAR's documentation says it writes one matrix per method. I chose refusing over implementing, since I cannot compare the file layout with STAR on this machine. It is in §1.10.
Item 23:
features.tsvinsoloCellFilteringWhen the raw folder held
features.tsv.gz,std::fs::copyput gzip bytes in a file calledfeatures.tsv. It now goes through the existingopen_maybe_gzip. The filtered matrix and barcodes were already plain.Item 26: gene name tag
--sjdbGTFtagExonParentGeneNameworked for an index built from a GTF, but a GTF given at mapping always readgene_name.GeneAnnotation::from_gtf_exons_configurednow takes the tags and sharesfind_attr_listwith the transcriptome tables, so several tags behave as they do there (the last one wins).Item 27:
CellReads.statsrecord_cell_readusedanyacross all features and shared one accumulator, so every feature's file held the same numbers. There is now one accumulator per feature, as the file's location already implied.With one exonic and one intronic read,
--soloFeatures Gene GeneFull:countedUonmainGene/CellReads.statsGeneFull/CellReads.statsNot compared with STAR's file, for the
geneInfo.tabreason above. The expected numbers follow from what the two matrices count.Tests
tests/solo_input_checks.rs, all 10 of which fail onmain(I ran the file there):solo_refuses_side_outputs_its_read_loops_do_not_write,umi_longer_than_a_u64_is_refused,several_umi_dedup_methods_are_refused,complex_needs_a_valid_umi_position,whitelist_of_another_length_is_fatal,complex_segment_whitelist_of_another_length_is_fatal,complex_umi_width_comes_from_its_position,cell_reads_stats_are_per_feature,gene_name_tag_applies_to_a_gtf_given_at_mapping,cell_filtering_writes_plain_features_from_gzipped_ones.Plus
barcode_of_another_length_never_matchesinsrc/solo/whitelist.rs.cargo test --release,cargo clippy --all-targetsandcargo fmtare clean on macOS.Conflicts
#345 and #346 change
solo/count.rsandsolo/mod.rstoo.git merge-treeagainst the heads of #344, #345 and #346 reports a conflict inCHANGELOG.mdonly (both add under[Unreleased]), so this does not need to be stacked. That is a textual check: I did not build or test the merged result.Not checked
test/parity_suite.shwas not run, so there is no check on real solo data. The parity flags are all still accepted, by reading them; no run confirmed it.record_cell_readwas not measured. It applies only with--soloCellReadStats CB.--chimOutTypeand--outSAMsplicingStatusoptions were not reviewed for solo; only--chimSegmentMinturns chimeric detection on, per the audit.🤖 Generated with Claude Code