2026-07-04 — v17 multi-trace consensus & mismatch view
Unit B ships: the multi-trace workspace now aligns loaded traces by position, computes a deterministic consensus using a pinned IUPAC tie-code algorithm, and surfaces per-position agreement/mismatch highlighting alongside a mismatch-count summary. The consensus can be exported as a standard FASTA file.
What shipped
-
New pure-logic module
src/consensus/consensus.ts—computeConsensus()implements a deterministic positional (ungapped) consensus with full IUPAC two-/three-/four-way tie resolution (M R W S Y K V H D B N);toConsensusFasta()serialises the result to standard 80-char-wrapped FASTA. -
New DOM component
src/components/ConsensusRow.ts— a styled panel withdata-testid="consensus-row"that renders a summary line and a monospace 80-base window of the consensus sequence; mismatch positions are highlighted with a.consensus-base--mismatchclass. - Consensus row is shown automatically whenever ≥ 2 resident (non-evicted) traces are present; hidden otherwise. Opening, switching, or closing workspace tabs re-evaluates the consensus.
-
New Export Consensus FASTA button in the toolbar — enabled only when ≥ 2 resident
traces are loaded; downloads
consensus.fastawith a header listing all contributing file names. -
Full light/dark theme support via new CSS design tokens
(
--color-consensus-*) added tosrc/style.css.
Algorithm (pinned)
At each position i (clamped to Math.min of all trace lengths):
- Count occurrences of each character (case-insensitive, uppercase-normalised).
- If all traces agree → consensus base = that character; not a mismatch.
-
Otherwise → mismatch; resolve:
find
maxCount; collect tiedBases sorted A<C<G<T<other; if all canonical and the sorted join is in the IUPAC table → use that code; else if sole winner → use that base; else →N.
A note on gapped alignment: this v1 uses simple positional (ungapped) consensus. True gapped alignment (e.g. Needleman–Wunsch) is scoped as a follow-up if needed.
Verification added
-
tests/core/consensus.test.ts— 25 unit tests with exact-value assertions: empty input, single-trace pass-through, length clamping, unanimous consensus, exact mismatch positions and count for a deliberate 2-trace mismatch, all twelve IUPAC tie codes (two-/three-/four-way), sole majority winner, non-IUPAC fallback to N, case-insensitivity, and exact FASTA bytes. -
tests/e2e/consensus.e2e.test.ts— 7 E2E tests asserting: consensus row hidden with one trace; export button disabled with one trace; row visible with mismatch count > 0 for two real fixtures; export button enabled; FASTA download name, header structure, and valid IUPAC body; row hides again after closing a tab; mismatch spans visually present.