Skip to content

Mark the canonical nucleotide projection on MappingRecordAllele (restore single g/c/p parity lost in the equivalence-set model) #784

Description

@bencap

Problem

Every variant is mapped by projecting up to the protein change and fanning back down to the full
nucleotide equivalence set. Because the genetic code is degenerate, that set holds many coding/genomic
members per variant (all codons that yield the same residue), and the reverse-translation tool returns
only the flat set — it carries no notion of which nucleotide member is canonical.

MappingRecordAllele marks is_authoritative (the measured allele) but nothing marks, at the
non-measured nucleotide level, the member that is the direct projection of the measured allele.

Regression vs. the old model. The legacy MappedVariant stored a single hgvs_g / hgvs_c / hgvs_p
— one coherent projection of the variant across all three levels, with the assay-level HGVS matching one of
them. The deduplicated-allele substrate (#739/#742) replaced that with a flat equivalence set and, in doing
so, dropped the "which nucleotide member is the one" information the old mapper implicitly committed to.

Impact. Serving surfaces can't reproduce a single canonical coding/genomic representation for a
genomic- or coding-assayed variant:

  • The spike: Design variant + annotation API shape for score set and variant pages #743 lean whole-set view (GET /score-sets/{urn}/variants) can surface the assay-level HGVS
    (measured, canonical) and the protein HGVS (the projection apex, always unambiguous), but not a
    canonical coding string for a genomic assay — e.g. a genomic-submitted score set has only genomic +
    protein available for the hover tooltip, with no useful coding representation.
  • Picking an arbitrary member of the degenerate coding set is wrong, not just imprecise: a degenerate
    sibling is a different variant than the one measured, so it would put an incorrect codon in the tooltip.

Why this can't be fixed at serve time

Computing the canonical nucleotide means forward-translating the measured allele (genomic→coding via
cdot/hgvs) and identifying the matching set member. On the lean whole-set view that runs over up to ~648k
variants per request — it would blow the page-load budget and duplicate mapping work the API isn't set up to
do. It must be precomputed by the pipeline. (A bounded single-variant detail endpoint could afford a live
translation, but the whole-set view cannot.)

Proposed fix

Add a canonical-nucleotide marker on the MappingRecordAllele linknot on Allele. Canonical-ness
is per-variant-context, exactly like is_authoritative: the same deduplicated coding allele can be the
canonical projection for one variant and a degenerate sibling for another, so the flag belongs on the link.

During the mapping / reverse-translation step, when the assay level is genomic or coding, forward-project
the measured (authoritative) allele to the other nucleotide level and flag the matching set member as
canonical. For a protein assay there is no canonical nucleotide — every c/g member is a genuine
degenerate sibling, so none is flagged (the old model's single value there was arbitrary anyway).

Protein is always the well-defined apex of the projection, so only the nucleotide cross-level projection
needs this marker.

Consumers / follow-through

Relates to the #743 Variant + Annotation API workstream (epic #746).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions