원클릭으로
merge-terms
// Use when asked to merge two MONDO terms — obsoleting one and transferring its metadata to the surviving term
// Use when asked to merge two MONDO terms — obsoleting one and transferring its metadata to the surviving term
| name | merge-terms |
| description | Use when asked to merge two MONDO terms — obsoleting one and transferring its metadata to the surviving term |
Every step below uses ODK tools (owltools, robot, make NORM). Read the odk skill first for how to invoke them — sh run.sh <cmd> if you have a TTY, otherwise direct docker run ... -i obolibrary/odkfull:<tag> (the tag lives in src/ontology/run.sh).
The commands below show the body (what goes after sh run.sh or after the docker prefix). Pick the wrapper based on your environment.
If any are missing, ask before proceeding.
From src/ontology/:
owltools --use-catalog mondo-edit.obo \
--obsolete-replace MONDO:XXXXXXX MONDO:YYYYYYY \
-o -f obo mondo-edit.obo
Where MONDO:XXXXXXX = obsoleted, MONDO:YYYYYYY = surviving.
What owltools does:
obsolete <original name>is_obsolete: true and replaced_by: MONDO:YYYYYYY on the obsoleted termmake NORM
Then mv NORM mondo-edit.obo. This deduplicates source qualifiers on identical subset/xref/is_a lines and re-quotes property_value URIs that owltools mangles.
NORM does not dedupe synonyms across different scopes (e.g. an EXACT and a RELATED with the same text both stay) — handle in Step 5.
obo-checkout.pl src/ontology/mondo-edit.obo MONDO:XXXXXXX MONDO:YYYYYYY
The obsoleted stanza must contain ONLY the lines below. Delete anything else owltools left behind (def, comment, xref, synonym, subset, is_a, intersection_of, relationship, other property_value) — but only after verifying the content is on the surviving term.
| Allowed line | Source |
|---|---|
id: MONDO:XXXXXXX | unchanged |
name: obsolete <original name> | set by owltools |
property_value: IAO:0000231 MONDO:TermsMerged | add manually (obsoletion reason) |
property_value: IAO:0000233 "https://github.com/monarch-initiative/mondo/issues/NNNN" xsd:anyURI | add manually (issue link) |
is_obsolete: true | set by owltools |
replaced_by: MONDO:YYYYYYY | set by owltools |
owltools transfers content but several things need manual attention:
Fix synonym evidence. owltools added a synonym like synonym: "<obsoleted name>" EXACT [MONDO:XXXXXXX]. Replace MONDO:XXXXXXX with one of the transferred xrefs (e.g. [Orphanet:NNNNNN]) — but only if that source actually uses the name. Picking any xref at random fabricates evidence. To confirm: either reuse a citation from the pre-merge obsolete stanza if the same synonym was already cited there, or open the xref at source (omim.org/entry/NNNNNN, orpha.net/en/disease/detail/NNNNNN, etc.) and check the name appears as a label or synonym. If no transferred xref carries the name, leave [] and flag in the Step 8 summary. If the obsoleted name duplicates an existing synonym with a different scope, reconcile manually — pick the correct scope, drop the duplicate.
Remove obsoletion-tracking metadata that came from the obsoleted term:
subset: obsoletion_candidatesubset: scheduled for obsoletion on or after (if present)property_value: IAO:0006012 "<date>" xsd:string (scheduled-obsoletion date — would otherwise claim the surviving term is scheduled for obsoletion)Decide which definition to keep. Default = whichever the issue says is correct. If the issue is silent, keep the surviving term's existing definition. If the surviving term had no definition and the obsoleted one did, use the obsoleted one's. State the choice in the final summary so the user can override.
Check for redundant is_a. If a transferred is_a is a superclass of another is_a already on the surviving term (e.g. MONDO:0000001 "disease" alongside a more specific class), remove the redundant one along with its source qualifiers.
Check for an unwanted alt_id. Some owltools versions add alt_id: MONDO:XXXXXXX to the surviving term. If present, remove it (Mondo policy: no alt_id for merges).
(Step 7.5 #8 will verify that all meaningful content from the obsolete stanza actually made it onto the surviving term — don't duplicate that check here.)
owltools usually rewires is_a children, but does not touch references in relationship:, intersection_of:, disjoint_from:, etc. Sweep for ANY remaining reference:
obo-grep.pl --noheader -r 'MONDO:XXXXXXX' src/ontology/mondo-edit.obo
For each hit outside the obsoleted stanza itself, checkout that term, repoint the axiom to MONDO:YYYYYYY, and check it back in.
Check in:
obo-checkin.pl src/ontology/mondo-edit.obo MONDO:XXXXXXX MONDO:YYYYYYY [any rewired children]
Normalize:
make NORM
then mv NORM mondo-edit.obo.
Run targeted QC. The merge-relevant SPARQL checks live under src/sparql/qc/general/ and src/sparql/qc/mondo/. Run them via robot verify (this is a body — wrap with sh run.sh or docker per the warning at the top of the skill):
robot verify --catalog catalog-v001.xml -i mondo-edit.obo \
--queries \
../sparql/qc/general/qc-proxy-merge-missing-preferred.sparql \
../sparql/qc/general/qc-misused-replaced-by.sparql \
../sparql/qc/general/qc-obsoletion-reason.sparql \
../sparql/qc/general/qc-deprecated-class-reference.sparql \
../sparql/qc/general/qc-xref-without-precision.sparql \
../sparql/qc/general/qc-duplicate-exact-synonym-no-abbrev.sparql \
../sparql/qc/mondo/qc-omim-subsumption.sparql \
-O reports/
Empty exit + PASS Rule ... 0 violation(s) per query = clean.
On qc-omim-subsumption.sparql. Flags a class and one of its ancestors both carrying the same OMIM:NNNNNN xref with {source="MONDO:equivalentTo"} — two classes can't both be the OMIM-equivalent. Often triggered by merges, since transferring an equivalentTo OMIM xref onto the surviving term may collide with the same xref already on an ancestor/descendant. Fix by demoting one side's source qualifier (MONDO:equivalentTo → MONDO:obsoleteEquivalent / MONDO:Redundant / a more specific mapping kind) on whichever class shouldn't claim equivalence, or dropping the duplicate xref from the descendant. Docs: https://mondo.readthedocs.io/en/latest/editors-guide/quality-control-tests/#qc-omim-subsumptionsparql.
Note: these queries do NOT catch a missing IAO:0000231 MONDO:TermsMerged on the obsoleted term — the Step 8 checklist is the real safety net.
Before claiming done, run every check below. If any fails, fix it before moving to Step 8 — do not just note it.
Run these greps. Replace XXXXXXX with the obsoleted ID and YYYYYYY with the surviving ID.
# 1. Obsolete stanza must contain ONLY: id, name, IAO:0000231, IAO:0000233, is_obsolete, replaced_by.
# Any other line (def, comment, subset, xref, synonym, is_a, relationship, other property_value) is a failure.
obo-grep.pl --noheader -r 'id: MONDO:XXXXXXX' src/ontology/mondo-edit.obo
# 2. Surviving stanza must NOT contain obsoletion-tracking metadata.
obo-grep.pl --noheader -r 'id: MONDO:YYYYYYY' src/ontology/mondo-edit.obo \
| grep -E 'subset: obsoletion_candidate|IAO:0006012|scheduled for obsoletion'
# Expected: no output. Any hit = failure.
# 3. No synonym on the surviving term should cite the obsoleted MONDO ID as evidence.
obo-grep.pl --noheader -r 'id: MONDO:YYYYYYY' src/ontology/mondo-edit.obo \
| grep "\[MONDO:XXXXXXX\]"
# Expected: no output.
# 4. No alt_id anywhere referencing the obsoleted ID.
grep "alt_id: MONDO:XXXXXXX" src/ontology/mondo-edit.obo
# Expected: no output.
# 5. No reference to the obsoleted ID outside its own stanza (catches missed children).
obo-grep.pl --noheader -r 'MONDO:XXXXXXX' src/ontology/mondo-edit.obo
# Expected: only the line "id: MONDO:XXXXXXX" inside the obsolete stanza itself.
# Anything else (a leftover synonym evidence on the surviving term, an unrewired
# child term still pointing at the obsolete) = failure, fix it before continuing.
# 6. Flag any duplicate synonym text on the surviving term (different scopes, same text).
obo-grep.pl --noheader -r 'id: MONDO:YYYYYYY' src/ontology/mondo-edit.obo \
| awk '/^synonym:/ {match($0, /"[^"]*"/); print substr($0, RSTART, RLENGTH)}' \
| sort | uniq -d
# Expected: no output. Any duplicate text = manual reconciliation needed (pick correct scope, drop the other).
Definition matches issue intent. Re-read the GitHub issue body. If it specifies which definition to keep (or supplies a new one), confirm the surviving term reflects that. If the issue is silent, the surviving term's pre-merge definition should be unchanged.
All meaningful content transferred. Compare the pre-merge obsolete stanza to the post-merge surviving stanza:
git show HEAD:src/ontology/mondo-edit.obo | obo-grep.pl --noheader -r 'id: MONDO:XXXXXXX' -
obo-grep.pl --noheader -r 'id: MONDO:YYYYYYY' src/ontology/mondo-edit.obo
Walk through every xref:, synonym:, is_a:, relationship:, intersection_of:, and property_value: on the obsolete stanza. Each must have an equivalent on the surviving term unless it was explicitly dropped. Allowed drops:
is_a (see Step 5.4)[MONDO:XXXXXXX] synonym evidenceMONDO:Lexical-qualified xref — these are auto-generated string-match cross-refs and don't need to survive a mergeIf you can't account for a line, fix it.
Show the user git diff src/ontology/mondo-edit.obo and the table below, filled in:
| What | From obsoleted | Status |
|---|---|---|
| Synonyms | "..." [evidence] | transferred / merged citations / already on surviving / scope reconciled |
| Xrefs | PREFIX:ID | transferred / merged sources / skipped (duplicate) |
| Subsets | subset_name | transferred / source merged / removed (obsoletion-tracking) |
is_a | MONDO:NNNNNNN ! parent | transferred / source merged / removed (redundant) |
intersection_of | ... | transferred / already on surviving |
| Relationships | ... | transferred / source merged |
| Property values | curated_content_resource, etc. | transferred / removed (IAO:0006012 scheduled date) |
| Definition | ... | kept surviving / replaced from obsoleted (per issue) |
| Children rewired | MONDO:NNNNNNN | rewired / none |
| New xrefs from issue | PREFIX:ID | added / n/a |
| Obsoleted-stanza cleanup | — | reduced to id+name+TermsMerged+issue+is_obsolete+replaced_by |
alt_id | — | none / removed |
Use when running any ODK-backed command in this repo — owltools, robot, make NORM, robot verify, or any other tool that lives inside the ODK docker image
Generate a formatted Mondo release announcement with statistics table from release diff reports
Analyze MONDO GitHub issues for validity, suggest improvements, and generate structured reports with duplication checks and identifier validation