You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds GARD — the NCATS Genetic and Rare Diseases rare-disease registry — as a biolink:Disease source in the existing disease (diseasephenotype) pipeline. GARD is a flat CSV of rare-disease terms (CURIE, preferred label, pipe-separated synonyms); it carries no cross-references, so it contributes identifiers and labels/synonyms only — no concord — and every term is typed biolink:Disease.
Ingest
New handler:src/datahandlers/gard.py downloads the Salesforce ContentVersion CSV (pull_gard) and parses it to per-prefix labels/synonyms files (pull_gard_labels_and_synonyms). The DisplayName is emitted as a label and as an exact synonym; each pipe-separated Synonyms value becomes its own OIO:hasExactSynonym row (matching the Orphanet/DOID convention). The URL column is read for reference only and is not ingested — the CURIE resolves via the Biolink prefix map.
Download:get_gard / get_gard_labels_and_synonyms rules in src/snakefiles/datacollect.snakefile; disease_gard_ids (an awk transform of the labels file, mirroring DOID/Orphanet) in src/snakefiles/diseasephenotype.snakefile. The download URL is configured as gard_download_url in config.yaml (a query-string Salesforce link with no stable filename, fetched directly rather than via pull_via_urllib); pin or repoint it there for a reproducible build.
Wiring:GARD added to disease_ids and disease_labelsandsynonyms; GARD joins the existing Disease.txt (no new compendium file), so the util.py aggregators and report_tables.py need no change.
Design (load-bearing)
extra_prefixes=[GARD]: GARD is not in the Biolink Model's diseaseid_prefixes (verified against the pinned biolink_version), so write_compendium would silently drop every GARD CURIE; the disease build passes extra_prefixes=[GARD] at the write_compendium call site in build_compendium (the documented escape hatch). Filing GARD with the Biolink team is the long-term fix — the same situation GTDB is in (PR feat: add GTDB as a biolink:OrganismTaxon source in the taxon pipeline #978). Two network-marked tests in tests/datahandlers/test_gard.py lock this in: one asserts GARD is absent from diseaseid_prefixes (and flips to prompt dropping the line once registered), the other asserts NodeFactory.create_node(..., extra_prefixes=[GARD]) for biolink:Disease does not raise (mirroring test_all_override_target_types_are_writable). The committed source-impact report's section-4 samples are flagged "NOT emitted — prefix not registered", which is exactly this precondition made visible.
No concords: GARD provides no xrefs to other disease vocabularies, so there is no GARD concord file. A GARD term no other source already maps joins the build as a single-identifier clique (a new clique); the impact report confirms this (see below).
Parse safety net: the handler logs a parsed/skipped/empty-name summary at the end of the parse so a future NCATS format change (e.g. a header or ID-column rename) can't silently zero the output. A scan of the published CSV found no DisplayName/Synonyms value with an embedded tab or newline and no row with an empty DisplayName.
Impact report
Generated (synthetic mode) and committed at docs/sources/GARD/impact-report.md (+ impact-report/ detail CSVs). The baseline disease intermediates were assembled from the 2025dec11 published build snapshot; that snapshot's concords predate the MP-in-disease addition, so MP's concord was rebuilt locally from UberGraph for the baseline (the report's Babel commit header pins the exact tree). GARD's own intermediates were built locally. Results: 16,214 identifiers / 16,214 new single-identifier cliques (a 6.72% increase, 241,269 → 257,483 total cliques), 0 merges, 0 modified cliques, 0 xrefs — the addition is purely additive; GARD disturbs no existing clique.
Docs
docs/sources/GARD/README.md (new) + an entry in the docs/sources/ index + the committed impact-report.md.
Also adds [tool.ruff.format] exclude = ["*.md"] to pyproject.toml: origin/main lacks this CI fix and ruff 0.16.0 began formatting Python code fences inside Markdown (overlapping rumdl), which would fail this PR's "Check Python formatting with ruff" job. It is a prerequisite for this PR's CI and is documented inline.
Testing
uv run pytest tests/datahandlers/test_gard.py -m unit --no-cov -q → 2 passed, 2 deselected
uv run pytest tests/datahandlers/test_gard.py --network --no-cov -q → 4 passed
uv run pytest -m unit --no-cov -q → 404 passed, 107 deselected
uv run ruff check . / ruff format --check . / snakefmt --check . / rumdl check . (committed files) → all clean
uv run snakemake -c 1 -n get_gard get_gard_labels_and_synonyms disease_gard_ids → 3 jobs resolve in the correct chain
uv run source-impact-report --source GARD --mode synthetic --intermediate-root /tmp/impact/intermediate → report written (16,214 new cliques, 0 merges)
Deferred
Biolink registration: registering GARD in the Biolink Model's diseaseid_prefixes is the long-term fix for the extra_prefixes=[GARD] escape hatch (and removes the report's "NOT emitted" flag).
Questions for the reviewer
extra_prefixes vs. Biolink-first. This PR ships the extra_prefixes=[GARD] escape hatch so the ~16k rare-disease terms actually surface in Disease.txt now (rather than being silently dropped), with Biolink registration tracked as the long-term fix — is that the preferred path, or should GARD wait on upstream Biolink registration before being kept?
Per the GARD URL field: a row with no URL has no public rarediseases.info.nih.gov page and is a candidate/provisional term — not a real rare disease — so it is now excluded from the ingest. This drops ~9,949 of ~16,214 rows, keeping 6,265 real rare-disease terms.
The filter is the single if not (row.get("URL") or "").strip(): continue line in src/datahandlers/gard.py; because disease_gard_ids derives ids from the labels file via awk, the exclusion cascades into the ids file and the compendium automatically. The parse logs a kept/skipped/no-URL/empty-name summary so a future NCATS format change can't silently zero the output.
A source-impact report (synthetic mode) is now generated and committed at docs/sources/GARD/impact-report.md (+ impact-report/ detail CSVs). Baseline disease intermediates came from the 2025dec11 published snapshot (MP's concord, absent from that snapshot, was rebuilt locally from UberGraph). Result: 6,265 new single-identifier cliques (241,269 → 247,534), 0 merges / 0 modified / 0 xrefs — purely additive, no existing clique disturbed.
The report's section-4 samples are flagged "NOT emitted — prefix not registered in Biolink Model for biolink:Disease"; that flag is why the build passes extra_prefixes=[GARD] (see the PR body's Design section). Registering GARD upstream removes both the flag and the need for the escape hatch.
Reverted: the URL-field filter was a false positive
A missing GARD URL does not mean a row isn't a real rare disease — a term may simply lack a GARD page. Per maintainer feedback: GARD:0001049 "Cerebral arteriopathy ... type 1" (CADASIL) has a URL, while GARD:0024558 "Cerebral arteriopathy with subcortical infarcts and leukoencephalopathy" (also CADASIL) does not — same disease family, so excluding the no-URL one would drop a real rare disease.
The if not (row.get("URL") or "").strip(): continue filter in src/datahandlers/gard.py is removed; all 16,214 GARD terms are ingested (no URL gating). The URL column is back to "reference only, not ingested" (the CURIE resolves via the Biolink prefix map).
The source-impact report is regenerated: 16,214 new cliques (241,269 → 257,483, +6.72%), 0 merges / 0 modified / 0 xrefs — still purely additive.
Tests updated: the verbatim fixture (one row with a URL+synonyms, one without either) now asserts both are kept.
@gaurav this branch successfully rebuilt the Disease Compendia at /projects/babel/runs/goetzs/NIH-GARD-1.18 on HT1 with the GARD ontology. Do you want me to put anything from that here or is a path to the sucessful output enough to merge this?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds GARD — the NCATS Genetic and Rare Diseases rare-disease registry — as a
biolink:Diseasesource in the existingdisease(diseasephenotype) pipeline. GARD is a flat CSV of rare-disease terms (CURIE, preferred label, pipe-separated synonyms); it carries no cross-references, so it contributes identifiers and labels/synonyms only — no concord — and every term is typedbiolink:Disease.Ingest
src/datahandlers/gard.pydownloads the Salesforce ContentVersion CSV (pull_gard) and parses it to per-prefixlabels/synonymsfiles (pull_gard_labels_and_synonyms). TheDisplayNameis emitted as a label and as an exact synonym; each pipe-separatedSynonymsvalue becomes its ownOIO:hasExactSynonymrow (matching the Orphanet/DOID convention). TheURLcolumn is read for reference only and is not ingested — the CURIE resolves via the Biolink prefix map.get_gard/get_gard_labels_and_synonymsrules insrc/snakefiles/datacollect.snakefile;disease_gard_ids(anawktransform of the labels file, mirroring DOID/Orphanet) insrc/snakefiles/diseasephenotype.snakefile. The download URL is configured asgard_download_urlinconfig.yaml(a query-string Salesforce link with no stable filename, fetched directly rather than viapull_via_urllib); pin or repoint it there for a reproducible build.GARDadded todisease_idsanddisease_labelsandsynonyms;GARDjoins the existingDisease.txt(no new compendium file), so theutil.pyaggregators andreport_tables.pyneed no change.Design (load-bearing)
extra_prefixes=[GARD]: GARD is not in the Biolink Model'sdiseaseid_prefixes(verified against the pinnedbiolink_version), sowrite_compendiumwould silently drop every GARD CURIE; the disease build passesextra_prefixes=[GARD]at thewrite_compendiumcall site inbuild_compendium(the documented escape hatch). Filing GARD with the Biolink team is the long-term fix — the same situation GTDB is in (PR feat: add GTDB as a biolink:OrganismTaxon source in the taxon pipeline #978). Two network-marked tests intests/datahandlers/test_gard.pylock this in: one assertsGARDis absent fromdiseaseid_prefixes(and flips to prompt dropping the line once registered), the other assertsNodeFactory.create_node(..., extra_prefixes=[GARD])forbiolink:Diseasedoes not raise (mirroringtest_all_override_target_types_are_writable). The committed source-impact report's section-4 samples are flagged "NOT emitted — prefix not registered", which is exactly this precondition made visible.DisplayName/Synonymsvalue with an embedded tab or newline and no row with an emptyDisplayName.Impact report
Generated (synthetic mode) and committed at
docs/sources/GARD/impact-report.md(+impact-report/detail CSVs). The baseline disease intermediates were assembled from the2025dec11published build snapshot; that snapshot's concords predate the MP-in-disease addition, so MP's concord was rebuilt locally from UberGraph for the baseline (the report'sBabel commitheader pins the exact tree). GARD's own intermediates were built locally. Results: 16,214 identifiers / 16,214 new single-identifier cliques (a 6.72% increase, 241,269 → 257,483 total cliques), 0 merges, 0 modified cliques, 0 xrefs — the addition is purely additive; GARD disturbs no existing clique.Docs
docs/sources/GARD/README.md(new) + an entry in thedocs/sources/index + the committedimpact-report.md.[tool.ruff.format] exclude = ["*.md"]topyproject.toml:origin/mainlacks this CI fix and ruff 0.16.0 began formatting Python code fences inside Markdown (overlappingrumdl), which would fail this PR's "Check Python formatting with ruff" job. It is a prerequisite for this PR's CI and is documented inline.Testing
uv run pytest tests/datahandlers/test_gard.py -m unit --no-cov -q→2 passed, 2 deselecteduv run pytest tests/datahandlers/test_gard.py --network --no-cov -q→4 passeduv run pytest -m unit --no-cov -q→404 passed, 107 deselecteduv run ruff check ./ruff format --check ./snakefmt --check ./rumdl check .(committed files) → all cleanuv run snakemake -c 1 -n get_gard get_gard_labels_and_synonyms disease_gard_ids→ 3 jobs resolve in the correct chainuv run source-impact-report --source GARD --mode synthetic --intermediate-root /tmp/impact/intermediate→ report written (16,214 new cliques, 0 merges)Deferred
GARDin the Biolink Model'sdiseaseid_prefixesis the long-term fix for theextra_prefixes=[GARD]escape hatch (and removes the report's "NOT emitted" flag).Questions for the reviewer
extra_prefixesvs. Biolink-first. This PR ships theextra_prefixes=[GARD]escape hatch so the ~16k rare-disease terms actually surface inDisease.txtnow (rather than being silently dropped), with Biolink registration tracked as the long-term fix — is that the preferred path, or should GARD wait on upstream Biolink registration before being kept?