Engine B exceptions + GO/NCBITaxon residual cleanup (48 line-pairs, 28 files) - #109
Conversation
…ross 28 files)
Part A of the "work on these next" plan:
GO residuals (9 rules, 15 line-pairs across 14 files):
- 7 REPOINTs via OAK `replaced_by` (IAO:0100001): GO:0006807, GO:0019048,
GO:0019419, GO:0030641, GO:0044262, GO:0044409, GO:0019318.
- 1 REPOINT for a bad-map: GO:0051271 → GO:2000146 (current id for
"negative regulation of cell motility").
- 1 RELABEL for a rename: GO:0019645 "dissimilatory reduction"
→ "anaerobic electron transport chain".
NCBITaxon residuals (13 rules, 33 line-pairs across 15 files), all
verified against the kg-microbe ncbitaxon snapshot at
data/transformed/ontologies/ncbitaxon_nodes.tsv and re-confirmed in
OAK's current sqlite:obo:ncbitaxon adapter:
- Spelling: Candidatus Nitrosotalea devanaterra → Nitrosotalea devaniterrae.
- Genus renames: Kazachstania exigua → Maudiozyma exigua; Ochrobactrum
intermedium/pituitosum → Brucella intermedia/pituitosa; Clostridium
straminisolvens → Acetivibrio straminisolvens; Rhizobium pusense →
Agrobacterium pusense.
- Phylum/clade renames: Asgard group → Promethearchaeati; DPANN group →
Nanobdellati; candidate division OP3 → Candidatus Omnitrophota;
Eisenbacteria → Candidatus Eiseniibacteriota; Dormibacterota →
Candidatus Dormiibacterota.
- 1 wrong-id REPOINT: NCBITaxon:2426 ("Syntrophus") → NCBITaxon:43773
("Syntrophus <bacteria>") since 2426 now points to Teredinibacter.
- 1 RELABEL: NCBITaxon:1801631 "Candidatus Micrarchaeota" → "Microcaldota".
Engine B (scripts/validate_id_label_correspondence.py):
- Add OK_EXCEPTION verdict + per-target `exceptions:` allow-list so the
curator-accepted residuals (true terminal obsoletes, taxa absent from
the current OAK snapshot, no-clean-CHEBI-term cases) no longer surface
as MISMATCH/ID_NOT_FOUND errors. Each entry carries a one-line `reason`.
- Populate the allow-list with the 28 residuals remaining after the GO
and NCBITaxon fixes above (11 CHEBI + 3 ENVO + 12 GO + 2 NCBITaxon),
plus the kgx_nodes-side mercury(2+) cation exporter divergence.
After this PR the validator reports: 5023 OK_CANONICAL, 184 OK_EXCEPTION,
0 errors across communities_yaml and kgx_nodes.
NOTE: validate_id_label_correspondence.py is vendored byte-identical
across the Mech repos — the OK_EXCEPTION + load_exceptions changes here
must be synced to CultureMech and MIM in a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
realmarcin
left a comment
There was a problem hiding this comment.
Reviewed the Engine B exceptions + GO/NCBITaxon residual cleanup. I independently verified every replacement id against the local OAK adapters (sqlite:obo:ncbitaxon, sqlite:obo:go). All 14 NCBITaxon repoints resolve to the exact replacement labels claimed, and crucially the OLD ids now resolve to unrelated organisms in the current snapshot (e.g. NCBITaxon:1934217 "DPANN group" is now Influenza A virus; :194708 "Ochrobactrum intermedium" is now a plant Adinandra latifolia) — confirming the taxids were recycled and the cleanup is genuinely needed. The genus reclassifications (Ochrobactrum→Brucella, Kazachstania→Maudiozyma, Clostridium→Acetivibrio, Rhizobium→Agrobacterium) and the Syntrophus disambiguation (2426→43773, since 2426 is now Teredinibacter) are all correct. The Engine B script, schema bindings, justfile rc-tracking, and CI workflow look sound. One semantic concern on a GO repoint is inline below.
Findings not anchorable to diff lines
- NIT (AMD_Acidophile_Heterotroph_Network.yaml:300-301 and Anammox_Bioreactor_DNRA_Destabilization_Community.yaml:110-111): GO:0006807 "nitrogen compound metabolic process" → GO:0008152 "metabolic process" drops the nitrogen specificity that is central to these N-cycling communities. I checked the obvious alternative GO:0034641 "cellular nitrogen compound metabolic process" and it is ALSO obsolete, so there is no cleaner current term — the broad parent is a defensible choice. Flagging only so it is a conscious tradeoff (an
exceptions:entry preserving the original specificity would be the alternative).
| id: GO:0019419 | ||
| label: sulfate reduction (assimilatory) | ||
| id: GO:0000103 | ||
| label: sulfate assimilation |
There was a problem hiding this comment.
RISK: This repoints GO:0019419 → GO:0000103 "sulfate assimilation", but preferred_term (line 405) is "dissimilatory sulfate reduction" and the surrounding notes (lines 136, 169, 364) all describe dissimilatory sulfate reduction coupled to organic-carbon oxidation. Assimilatory and dissimilatory sulfate reduction are distinct processes. GO obsoleted :0019419 with the note "same meaning as sulfate assimilation", which is why the gate steered here — but GO:0019420 "dissimilatory sulfate reduction" is an ACTIVE term that matches the curator's intent exactly. Concrete fix: repoint to GO:0019420 / dissimilatory sulfate reduction instead of GO:0000103.
…19420 - Iberian_Pit_Lake_Stratified_Community.yaml: the biological_process preferred_term "dissimilatory sulfate reduction" was bound to GO:0000103 "sulfate assimilation" (the assimilatory pathway), contradicting the preferred_term and the surrounding notes describing dissimilatory sulfate reduction. Repointed to GO:0019420 "dissimilatory sulfate reduction" (canonical label verified via OAK). - Left the broad GO:0008152 nitrogen-loss NIT untouched (conscious tradeoff). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
realmarcin
left a comment
There was a problem hiding this comment.
Review: Engine B exceptions + GO/NCBITaxon residual cleanup
Independently re-verified all 48 changed (id, label) line-pairs (15 GO + 33 NCBITaxon) against the local OAK sqlite adapters (sqlite:obo:go, sqlite:obo:ncbitaxon, snapshots dated 2025-06). Every new pair matches OAK canonical exactly, and every retired NCBITaxon id now resolves to an unrelated organism (e.g. NCBITaxon:2426 -> Teredinibacter turnerae, NCBITaxon:1934217 -> an Influenza A virus, NCBITaxon:221109 -> Oceanobacillus iheyensis), confirming the old pairs were stale id-recycling and the repoints are correct. The validator/config/schema-binding/CI additions are coherent. No correctness bugs or fabricated/mismatched references found. Two low-severity notes below.
NIT
- GO:0006807 -> GO:0008152 in
AMD_Acidophile_Heterotroph_Network.yaml:301andAnammox_Bioreactor_DNRA_Destabilization_Community.yaml:111: follows OAKreplaced_by, but collapses "nitrogen compound metabolic process" to the top-level "metabolic process", dropping N-cycle specificity in two nitrogen-focused communities. The GO snapshot has no live nitrogen-specific successor, so this is the only gate-passing option andpreferred_termretains the specificity -- acceptable, just flagging the information loss.
Confirmation (not a defect)
- GO:0019419 -> GO:0019420 in
Iberian_Pit_Lake_Stratified_Community.yaml:407-408: deviates from the ontologyreplaced_by(GO:0000103 "sulfate assimilation") but is the correct choice -- the prior label "sulfate reduction (assimilatory)" was itself a mismatch, whilepreferred_termand context are dissimilatory. Good catch.
Findings not anchorable to diff lines
- Cross-repo sync (already flagged in PR body):
scripts/validate_id_label_correspondence.pyis vendored byte-identical across CultureMech / MIM / CommunityMech; the newOK_EXCEPTIONverdict +load_exceptions()must be synced to the other two copies or they will drift from byte-identical. - kgx_nodes target depends on a build artifact:
conf/id_label_targets.yamlglobsoutput/kgx/nodes.tsv. It exists locally, but if CI does not regenerate it beforereport-label-drift, the 6 kgx_nodes exceptions (incl. theCHEBI:16793 mercury(2+) cationexporter divergence) and the claimed 184 OK_EXCEPTION count will not be exercised on CI. Confirm the workflow builds the KGX export, or note that the kgx surface is host-only for now.
| id: GO:0006807 | ||
| label: nitrogen compound metabolic process | ||
| id: GO:0008152 | ||
| label: metabolic process |
There was a problem hiding this comment.
NIT: GO:0006807 -> GO:0008152 follows OAK replaced_by, but "metabolic process" is the top-level root term -- the preferred_term here is "nitrogen compound metabolic process", so the N-specificity is dropped from the bound ontology term. Verified there is no live nitrogen-specific successor in the GO snapshot, so this is the only gate-passing option; acceptable, noting the loss. Same change at Anammox_Bioreactor_DNRA_Destabilization_Community.yaml:111.
| id: GO:0019419 | ||
| label: sulfate reduction (assimilatory) | ||
| id: GO:0019420 | ||
| label: dissimilatory sulfate reduction |
There was a problem hiding this comment.
Confirmation (not a defect): repoint to GO:0019420 "dissimilatory sulfate reduction" deviates from the ontology replaced_by of the obsolete GO:0019419 (which is GO:0000103 "sulfate assimilation"), but is the semantically correct choice -- the prior label "sulfate reduction (assimilatory)" was a mismatch and preferred_term/context here are dissimilatory. Verified GO:0019420 is current (not deprecated) in OAK.
PR #116 was the original Engine B foundation PR. Its bulk was carried in PR #109 via the vendored byte-identical scripts/validate_id_label_correspondence.py (with #109 additionally adding the OK_EXCEPTION mechanism on top). Four items in #116 had NOT yet been carried over: 1. .gitignore — exclude cache/ (the OAK label cache directory created locally during validate runs) 2. scripts/.validate_id_label_correspondence.sha256 — integrity sidecar for the vendored validator; regenerated against the current main copy (which includes #109's OK_EXCEPTION extension) rather than the original PR #116 hash 3. tests/data/optional_binding/omits_bound_optionals.yaml — fixture 4. tests/test_optional_binding_obligation.py — regression test that REQUIRED id↔label bindings on OPTIONAL slots do NOT promote those slots to de-facto required; verified by linkml-term-validator validate-data --labels. Pins the optional-slot contract for shared_environment_term and chebi_term Both new tests pass locally (test_absent_optional_bound_slot_does_not_trip _required_obligation + test_present_wrong_label_is_caught). With this PR landed, PR #116 can be closed as fully superseded. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Part A of the "work on these next" plan (residuals from PRs #90–#107).
OK_EXCEPTIONverdict + per-targetexceptions:allow-list so the 28 curator-accepted residuals stop appearing as MISMATCH/ID_NOT_FOUND.communities_yamlandkgx_nodes.GO (9 rules, 15 line-pairs across 14 files)
7 REPOINTs via OAK
replaced_by(IAO:0100001), 1 REPOINT for a bad-map (GO:0051271 → GO:2000146), 1 RELABEL for a rename (GO:0019645 → "anaerobic electron transport chain").NCBITaxon (13 rules, 33 line-pairs across 15 files)
All replacement ids verified against the kg-microbe ncbitaxon snapshot at
data/transformed/ontologies/ncbitaxon_nodes.tsvand re-confirmed in OAK's currentsqlite:obo:ncbitaxonadapter. Per [[ontology-term-cleanup]] memory, the OAK snapshot is NOT being refreshed — kg-microbe is the source of truth for current taxonomy.Engine B (
scripts/validate_id_label_correspondence.py)OK_EXCEPTIONverdict (non-error).exceptions:field on each target (list of{id, label, reason}mappings).CHEBI:16793 mercury(2+) cationdivergence atsrc/communitymech/export/kgx_export.py:82).Cross-repo sync needed
scripts/validate_id_label_correspondence.pyis vendored byte-identical across CultureMech / MIM / CommunityMech. TheOK_EXCEPTION+load_exceptions()change here must be synced to those repos in a follow-up.Test plan
uv run python scripts/term_label_audit.py CHEBI ENVO GO NCBITaxon— residuals match the exceptions list (11 CHEBI + 3 ENVO + 12 GO + 2 NCBITaxon).uv run python scripts/validate_id_label_correspondence.py -c conf/id_label_targets.yaml— exits 0; summary shows 5023 OK_CANONICAL / 184 OK_EXCEPTION / 0 errors.just validate-all— every YAML validates against the schema.just test— 136 passed, 9 skipped.🤖 Generated with Claude Code