migec 2.5.0
A molecule is sample + cell + UMI, and checkout's counters were keyed on the UMI alone
w.umis.emplace_back(s, umi_key) merged every cell's copy of one UMI into a single entry. On sc5p_v2_hs_PBMC_1k that read 221,026 pooled UMIs where there are 311,962 molecules, put the depth 1.41x high, and fired the saturation warning at an apparent 21% occupancy against a true 3e-6. The key is now cell then UMI.
The follow-through: effective_length is a property of the counter, so it spans 26 nt on a 10x run. Weighed against the 10 nt UMI, the composition-skew warning read "25.4 of 10 nt usable" — which cannot be true, so it was dead on every single-cell library. It is weighed against barcode_length now. checkout.summary.tsv carries all three lengths as columns, and checkout.barcode_space.tsv's second column is renamed umi_length -> barcode_length, which is what its value always was.
Cell Ranger, on all three axes
scripts/compare_cellranger{,_chains,_contigs}.py, docs/single_cell.rst. Run against both 5.0.0 (10x's published calls) and 10.1.0 (run here) — the two agree at Jaccard 0.9938, which is the control saying the migec gap is not version drift.
- Cells: migec 888 against 479, sharing 470, and it loses 1.9 points of reads-in-cells. The extra barcodes are nearly empty, so a cell count on its own is not an accuracy figure.
- Per-cell chains, migec + arda against a per-cell assembler: TRA 426/426, TRB 468/469 recall, junction agreement 0.9507 / 0.9915, 22 s over 47,584 consensuses.
- Reference-free contigs (
arda cells): 933/943 CDR3s recovered verbatim, k-mer coverage 0.9759, chain recall 0.9777.
The knee is Kneedle at its global maximum, and it refuses when there is no knee
Kneedle's published rule — walk the local maxima, stop at the first that falls by a sensitivity step — is degenerate without the paper's smoothing spline: on 136,032 barcodes the unsmoothed difference curve has 287 local maxima and the walk stops at fifteen cells. The global maximum needs no smoothing parameter, and is now guarded at 10x the mean molecules per observed barcode, so an ambient-only library reports no knee instead of a meaningless rank.
place_reads asks union-find before it scans: 640.9 s -> 32.6 s
Exact, not a heuristic: join already returns immediately when the two roots match, so the pairs skipped are the ones whose answer it discarded. Consensus FASTQ and mig.tsv are MD5-identical over 47,584 molecules.
Full detail in CHANGELOG.md.
🤖 Generated with Claude Code