Skip to content

D5: Split phasing-summary.tsv and stratify the switch/flip counts #237

Description

@TimD1-bot

Note

Authorship: the content below was drafted by Claude Opus 5 (an AI coding agent) and
filed via gh under @TimD1-bot, a bot account operated by @TimD1. It reflects the
agent's analysis, not a statement authored by @TimD1.

Part of #47. Splits one output file into two and fixes a long-standing format defect in the same
rewrite.

Change

write_phasing_summary (src/phase.cpp:811, declared src/phase.h:50) splits into
write_phasing_variants_summary and write_phasing_blocks_summary.

The split axis is one question: can this quantity be restricted to a subset of variants at all?

New file STRATUM Columns Why
phasing-variants-summary.tsv yes, first column VARIANTS, SWITCH_ERRORS, FLIP_ERRORS, SWITCH_ERROR_RATE, FLIP_ERROR_RATE Each error is attributable to a single query variant, hence to that variant's region sets
phasing-blocks-summary.tsv no PHASE_BLOCKS, NG_50, SWITCH_NGC50, SWITCHFLIP_NGC50 Contiguity over genomic span; an NG50 computed over phase blocks intersected with a fragmented subset is not meaningful

The names say per-variant versus per-block rather than "errors" versus "metrics", because #46 adds
non-error columns (phased-variant counts and fractions) to the first file, at which point an
-errors- name would be wrong.

Attribution

ctg_pbs->switches[] and flips[] hold query variant indices (src/phase.cpp:618,625;
confirmed by their comparison against variant indices at src/print.cpp:570,574). An error is
attributed to the region sets of that variant, and switchflips.tsv already reports the same index
in its VARIANT column (src/phase.cpp:751,762,783), so the two files agree by construction.

One convention to document: a switch error is localized to the interval between two consecutive
phased variants, and that interval can straddle a boundary. Attributing to the variant is a choice
made for consistency with the existing VARIANT column, not because the interval has a single
correct answer.

VARIANTS is newly exposed

Today it is only a divisor (src/phase.cpp:824-825), computed as sum(qvars->n) over contigs
(src/phase.cpp:655). Per-subset rates are unauditable without the per-subset denominator, so it
becomes a column.

#46 later substitutes ASSESSED_PAIRS — adjacent phaseable-heterozygote pairs per phase block — for
this denominator. The phaseable subset does not exist until #46 marks unphased variants, so this
issue exposes the denominator it actually divides by, under its true name. Both land before rc1, so
no user sees the intermediate.

The rate-format fix

write_phasing_summary currently emits SWITCH_ERROR_RATE/FLIP_ERROR_RATE with %.6f%%
(src/phase.cpp:826, values already scaled by 100 at :824-825) — a string with a trailing
percent sign in a numeric column — and writes its single data row without a terminating newline.
Both are worked around by every consumer today.

The split rewrites this writer anyway, so it emits bare floats as true fractions
0.00020930, not 0.020930% — and terminates the row.

The column names do not change, so a consumer comparing a pre- and post-split run reads the same
column with values 100x apart. The legacy % sigil is self-describing, so a reader can discriminate
on the value rather than the column name; that is the mitigation, and the change is release-noted.

Out of scope

switchflips.tsv and phase-blocks.tsv stay unstratified — both are interval/event records rather
than variant records, and a phase block spans many subsets. Deferred, not blocked.

Per-subset NG50/NGC50 is explicitly declined, not deferred: these are contiguity metrics over genomic
span, and computed over phase blocks intersected with a fragmented subset they are not meaningful.

Testing

  • phasing-variants-summary.tsv's * row matches the old file's variant-attributed columns, and
    phasing-blocks-summary.tsv matches its contiguity columns — the split demonstrably loses nothing.
  • The rate columns parse as bare floats, and the file ends in a newline.
  • The current test_phase.cpp contains no write_phasing_summary case, so these writer tests are
    authored here rather than amended.

Depends on

Per-variant membership. Independent of the precision-recall stratum axis.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions