Summary
For variants outside the CDS, MappedVariant.hgvs_p is populated with a nucleotide-style expression carrying a protein accession, such as NP_078951.2:n.*21C>T. This is not valid protein HGVS. The value propagates to the CSV exports (mavedb.post_mapped_hgvs_p) and to the score set view in mavedb-ui, where it renders as a variant label and in histogram tooltips.
Reproduction
curl 'https://reg.genome.network/allele?hgvs=NM_024675.4:c.*21C>T'
The MANE RefSeq transcript allele in the response:
{
"hgvs": ["NM_024675.4:c.*21C>T"],
"proteinEffect": { "hgvs": "NP_078951.2:n.*21C>T" },
"MANE": {
"nucleotide": { "RefSeq": { "hgvs": "NM_024675.4:c.*21C>T" } },
"protein": { "RefSeq": { "hgvs": "NP_078951.2:n.*21C>T" } }
}
}
ClinGen synthesizes a pseudo-protein expression for positions with no amino-acid consequence: the NP accession paired with the transcript-relative coordinate and an n. prefix. Every UTR variant in an affected score set has this shape.
Root cause
src/mavedb/lib/clingen/allele_registry.py::extract_hgvs_from_ca_allele_data copies ClinGen's value into hgvs_p without checking that it is a p. expression. Both branches are affected:
# transcript_accession branch
if hgvs_c:
if allele.get("proteinEffect"):
hgvs_p = allele["proteinEffect"].get("hgvs")
break
# MANE fallback branch
hgvs_p = allele["MANE"].get("protein", {}).get("RefSeq", {}).get("hgvs")
extract_hgvs_from_pa_allele_data has the same gap, taking aminoAcidAlleles[0]["hgvs"][0] unvalidated.
The value is written to the database by src/mavedb/worker/jobs/external_services/hgvs.py::populate_hgvs_for_score_set:
mapped_variant.hgvs_g = hgvs_g
mapped_variant.hgvs_c = hgvs_c
mapped_variant.hgvs_p = hgvs_p
Suggested fix
src/mavedb/lib/variants.py already defines the needed predicate, is_hgvs_p (re.compile(r"(^|:)p\.")), currently used only as a CSV fallback filter. Apply it at extraction time in all three places:
hgvs_p = allele["proteinEffect"].get("hgvs")
if hgvs_p and not is_hgvs_p(hgvs_p):
hgvs_p = None
Consider the same treatment for hgvs_c (c./n.) and hgvs_g (g.) so the columns are self-describing by construction.
Follow-up
- A backfill is needed for rows already written. A
WHERE hgvs_p IS NOT NULL AND hgvs_p NOT LIKE '%:p.%' scan will size the impact.
src/mavedb/lib/csv/specs.py::_post_mapped_hgvs_p returns mapping.hgvs_p unchecked and only validates the VRS fallback path. Consider validating the stored column too, as defense in depth.
Affected surfaces
GET /score-sets/{urn}/variants/data and the annotations CSV (mavedb.post_mapped_hgvs_p)
v_variant_annotations.hgvs_p
- mavedb-ui score set view: variant search labels and histogram tooltips
Summary
For variants outside the CDS,
MappedVariant.hgvs_pis populated with a nucleotide-style expression carrying a protein accession, such asNP_078951.2:n.*21C>T. This is not valid protein HGVS. The value propagates to the CSV exports (mavedb.post_mapped_hgvs_p) and to the score set view in mavedb-ui, where it renders as a variant label and in histogram tooltips.Reproduction
The MANE RefSeq transcript allele in the response:
{ "hgvs": ["NM_024675.4:c.*21C>T"], "proteinEffect": { "hgvs": "NP_078951.2:n.*21C>T" }, "MANE": { "nucleotide": { "RefSeq": { "hgvs": "NM_024675.4:c.*21C>T" } }, "protein": { "RefSeq": { "hgvs": "NP_078951.2:n.*21C>T" } } } }ClinGen synthesizes a pseudo-protein expression for positions with no amino-acid consequence: the NP accession paired with the transcript-relative coordinate and an
n.prefix. Every UTR variant in an affected score set has this shape.Root cause
src/mavedb/lib/clingen/allele_registry.py::extract_hgvs_from_ca_allele_datacopies ClinGen's value intohgvs_pwithout checking that it is ap.expression. Both branches are affected:extract_hgvs_from_pa_allele_datahas the same gap, takingaminoAcidAlleles[0]["hgvs"][0]unvalidated.The value is written to the database by
src/mavedb/worker/jobs/external_services/hgvs.py::populate_hgvs_for_score_set:Suggested fix
src/mavedb/lib/variants.pyalready defines the needed predicate,is_hgvs_p(re.compile(r"(^|:)p\.")), currently used only as a CSV fallback filter. Apply it at extraction time in all three places:Consider the same treatment for
hgvs_c(c./n.) andhgvs_g(g.) so the columns are self-describing by construction.Follow-up
WHERE hgvs_p IS NOT NULL AND hgvs_p NOT LIKE '%:p.%'scan will size the impact.src/mavedb/lib/csv/specs.py::_post_mapped_hgvs_preturnsmapping.hgvs_punchecked and only validates the VRS fallback path. Consider validating the stored column too, as defense in depth.Affected surfaces
GET /score-sets/{urn}/variants/dataand the annotations CSV (mavedb.post_mapped_hgvs_p)v_variant_annotations.hgvs_p