Skip to content

Engine B exceptions + GO/NCBITaxon residual cleanup (48 line-pairs, 28 files) - #109

Merged
realmarcin merged 2 commits into
mainfrom
ontology-residuals-engine-b-exceptions
Jun 10, 2026
Merged

Engine B exceptions + GO/NCBITaxon residual cleanup (48 line-pairs, 28 files)#109
realmarcin merged 2 commits into
mainfrom
ontology-residuals-engine-b-exceptions

Conversation

@realmarcin

Copy link
Copy Markdown
Contributor

Summary

Part A of the "work on these next" plan (residuals from PRs #90#107).

  • Ontology residuals: 50 → 28 via 9 GO rules and 13 NCBITaxon rules (48 line-pairs across 28 community files).
  • Engine B: adds OK_EXCEPTION verdict + per-target exceptions: allow-list so the 28 curator-accepted residuals stop appearing as MISMATCH/ID_NOT_FOUND.
  • Validator now reports 5023 OK_CANONICAL, 184 OK_EXCEPTION, 0 errors across communities_yaml and kgx_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.tsv and re-confirmed in OAK's current sqlite:obo:ncbitaxon adapter. Per [[ontology-term-cleanup]] memory, the OAK snapshot is NOT being refreshed — kg-microbe is the source of truth for current taxonomy.

  • Genus renames: Ochrobactrum → Brucella (2 species), Kazachstania → Maudiozyma, Clostridium straminisolvens → Acetivibrio, Rhizobium pusense → Agrobacterium.
  • Phylum/clade renames: Asgard group → Promethearchaeati; DPANN group → Nanobdellati; OP3 → Candidatus Omnitrophota; Eisenbacteria → Candidatus Eiseniibacteriota; Dormibacterota → Candidatus Dormiibacterota.
  • Spelling/disambiguation: Nitrosotalea devaniterrae; NCBITaxon:2426 → NCBITaxon:43773 ("Syntrophus ").
  • 1 RELABEL: Candidatus Micrarchaeota → Microcaldota (same id).

Engine B (scripts/validate_id_label_correspondence.py)

  • New OK_EXCEPTION verdict (non-error).
  • New exceptions: field on each target (list of {id, label, reason} mappings).
  • Loads exceptions per target, applies after canonical/synonym checks.
  • 28 communities_yaml entries + 6 kgx_nodes entries (mostly mirrored, plus the exporter-side CHEBI:16793 mercury(2+) cation divergence at src/communitymech/export/kgx_export.py:82).

Cross-repo sync needed

scripts/validate_id_label_correspondence.py is vendored byte-identical across CultureMech / MIM / CommunityMech. The OK_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

…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 realmarcin left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 realmarcin left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:301 and Anammox_Bioreactor_DNRA_Destabilization_Community.yaml:111: follows OAK replaced_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 and preferred_term retains 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 ontology replaced_by (GO:0000103 "sulfate assimilation") but is the correct choice -- the prior label "sulfate reduction (assimilatory)" was itself a mismatch, while preferred_term and context are dissimilatory. Good catch.

Findings not anchorable to diff lines

  • Cross-repo sync (already flagged in PR body): scripts/validate_id_label_correspondence.py is vendored byte-identical across CultureMech / MIM / CommunityMech; the new OK_EXCEPTION verdict + 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.yaml globs output/kgx/nodes.tsv. It exists locally, but if CI does not regenerate it before report-label-drift, the 6 kgx_nodes exceptions (incl. the CHEBI:16793 mercury(2+) cation exporter 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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@realmarcin
realmarcin merged commit 81bdda1 into main Jun 10, 2026
2 checks passed
@realmarcin
realmarcin deleted the ontology-residuals-engine-b-exceptions branch June 10, 2026 19:54
realmarcin added a commit that referenced this pull request Jun 10, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant