Skip to content

Incorrect HPO identifier for Macroscopic hematuria in the rare disease examples #458

Open

Description

@Nine-Fingers

Problem

The Bethlem myopathy and rare-disease examples use HP:0011463 where the
phenotype is macroscopic hematuria:

  • HP:0011463 — Childhood onset
  • HP:0012587 — Macroscopic hematuria

Same shape as #451: a syntactically valid identifier for an unrelated concept,
so nothing in schema validation catches it.

curl -s "https://www.ebi.ac.uk/ols4/api/ontologies/hp/terms?obo_id=HP:0011463" \
  | jq -r '._embedded.terms[0].label'   # => Childhood onset
curl -s "https://www.ebi.ac.uk/ols4/api/ontologies/hp/terms?obo_id=HP:0012587" \
  | jq -r '._embedded.terms[0].label'   # => Macroscopic hematuria

Neither term carries the other's label in any synonym field.

The identifier is wrong, not the label

HP:0011463 is also used correctly in these same files, which is what makes
precision necessary here. In v2/BethlemMyopathyExample.java, five lines apart (abridged):

PhenotypicFeature motorDelay = PhenotypicFeature.newBuilder()
        .setType(ontologyClass("HP:0001270", "Motor delay"))
        .setOnset(TimeElement.newBuilder().setOntologyClass(
                ontologyClass("HP:0011463", "Childhood onset")))      // correct
        .setSeverity(mild).build();

PhenotypicFeature hematuria = PhenotypicFeature.newBuilder()
        .setType(ontologyClass("HP:0011463", "Macroscopic hematuria"))  // the defect
        .setOnset(TimeElement.newBuilder().setAge(
                Age.newBuilder().setIso8601Duration("P14Y")))
        .addModifiers(ontologyClass("HP:0031796", "Recurrent"))
        .addEvidence(citation).build();

Four signals agree the label is right and the identifier wrong:

  1. the variable is named hematuria;
  2. the same file uses HP:0011463 correctly as an onset class five lines above;
  3. the defective site is a setType carrying its own setOnset of P14Y and a
    "Recurrent" modifier — and HPO defines HP:0011463 as onset between 1 and 5
    years, so a feature whose type is "Childhood onset" and whose onset is
    age 14 is incoherent;
  4. the example's citation is Bao M, et al., "COL6A1 mutation leading to Bethlem
    myopathy with recurrent hematuria: a case report."

Scope — which occurrences change, and which must not

HP:0011463 appears 37 times across 19 files — 25 in text files and 12 in
the six binary fixtures (each .pb contains two: one defective, one correct). 16 are the defect; 21 are correct and must stay.

Usage Count Action
paired with "Macroscopic hematuria" 16 → HP:0012587
paired with "Childhood onset" in onset fields 21 leave unchanged

The defective sites span v1/v2 BethlemMyopathyExample.java,
docs/rd-example.rst, docs/rd-example-java.rst, six
python/data/v{1,2}/*.json fixtures and the six matching .pb files.

The JSON and .pb fixtures are coupled, and must change together

python/tests/test_io.py asserts phenopacket_pb == phenopacket_json (and the
same for family and cohort, v1 and v2). The .pb files carry the defect too, so
editing the JSON without the binaries fails that test.

As far as we can see this build does not regenerate them: the protobuf plugin's
only Python output directory is python/src, and neither workflow rebuilds
python/data. But python/data/v1/README.md records that the content
corresponds to TestData.V1.comprehensive*() in phenopacket-tools as of October
2022, so there may be a regeneration path we cannot see from here.

Would you prefer we edit the fixtures directly, or regenerate them from
phenopacket-tools?
Both identifiers are ten bytes, so a direct edit needs no
re-serialization — but that is your call, not ours.

Interaction with open PR #421

PR #421 (Add an example for creating a phenopacket in Python) adds four more
HP:0011463 occurrences in docs/rd-example-python.rst and
python/tests/test_rd_example.py, of which two are the defective pairing.
Worth catching there before it lands, and worth sequencing so a fix and that PR
do not collide.

Offer

Happy to open a PR correcting the 16 defective occurrences — text and binary
fixtures together so test_io.py stays green — and leaving the 21 correct ones
untouched, in the same shape as the #451 fix (#457). Just say how you would like it
sequenced against #421.

How this was found

While preparing the fix for #451 (now #457) we built the identifier/label validator suggested
there: it pairs each CURIE with its adjacent label, resolves the CURIE, and
reports mismatches. It rediscovered #451 at six sites — two beyond the four that
issue lists — and surfaced this as a second instance of the same class. Glad to
contribute it if useful; it needs only bash, python3 and network access to
OLS4.


🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions