METPO proposal v8: trait-realization and electron-role predicates (#302, #303) - #320
Conversation
Both defects share one root cause: the corpus has no range-correct relation whose object is a trait. RO:0002327 (enables) has been doing that job, but biolink gives it range 'biological process or activity', and a TRAIT node is a disposition — so 164 edges entail trait ⊑ BiologicalProcessOrActivity (#302). The obvious alternative is worse: METPO's chemical-interaction predicates inherit rdfs:domain microbe via METPO:2000001, which no causal-graph node can satisfy (#301). That squeeze is what forced PR #300 to collapse donor and acceptor onto one generic relation, losing the role for 7 of 15 edges (#303). Cohort v8 proposes the three predicates that resolve it, following the v1 convention of domain = range = METPO:1007401 (trait causal node), which sidesteps the microbe domain and the process range at once: METPO:2007700 confers 146 edges / 114 records METPO:2007701 has electron donor 13 edges / 13 records METPO:2007702 has electron acceptor 5 edges / 3 records The partition is exhaustive: 146 + 13 + 5 = 164, computed from the corpus and cross-checked against ENABLES_RANGE_ON_TRAIT in reports/predicate_domain_audit.tsv. Cross-ontology alignments go in xrefs + a SSSOM file (skos:closeMatch to RO:0002327, METPO:2000009 and METPO:2000008), never in definition_source (#83). No corpus edges are grounded here; the 164-edge migration follows as a separate PR, since #301 notes doing it all at once would be unreviewable. Also fixes a pre-existing bug this cohort ran into (#318): verify_metpo_proposal's Scope-A check ran even for cohorts shipping no classes template, so class_tsv_text was "" and every corpus traitmech: id read as uncited — failing every predicate-only cohort (v2, v4, v6). The script already announced it would skip that case and check_scope_c already honoured it. v1/v7 still fail, correctly: 120 synthetic ids are genuinely un-lifted, tracked in #319. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @realmarcin's task in 6m 5s —— View job Review: METPO proposal v8The mechanical parts hold up. What I verified independently:
The three problems below are all in prose that gets copy-pasted upstream (the 🟡 The
|
There was a problem hiding this comment.
Three accuracy problems in text that ships upstream to METPO; the ID hygiene, ontology grounding and the verify_metpo_proposal fix all check out. Details in the review comment: #320 (comment)
…review)
Review found the dissimilatory_iron_reduction prose factually wrong. All
three of DIR's Fe(III) species are terminal electron acceptors — the
file's own node descriptions say so ("Terminal electron acceptor reduced
in DIR") — so there is no donor-shaped edge in that graph to be confused
with. The real #303 loss is that after PR #300 reversed two of them onto
enables, nothing in predicate terms records the acceptor role at all.
Rewritten in both the observations cell and proposal.md.
Also from the review:
- Publish the explicit 164-edge partition as an appendix, so the buckets
are checkable rather than inferrable from counts. This resolves the
query about oxygen_preference: its "O2 as terminal electron acceptor"
node is typed MOLECULAR_FUNCTION (it denotes the USE of O2, not O2), so
it lands in confers, not under has electron acceptor whose definition
requires a chemical species. Retyping it is corpus work, left to the
migration PR.
- State that the declared OWL range is deliberately weaker than the
definitions, and why tightening it was rejected.
- Fix this cohort's own Scope-A row, which repeated v2's now-stale "none
in corpus" claim; there are 120, tracked in #319.
The reviewer's arithmetic finding does not hold: the published breakdown
has nine terms summing to 146 (81+32+12+5+5+4+4+2+1); the review's tally
omitted CHEMICAL 4 and reached 142. Verified against the corpus and left
unchanged. The substring-match observation is real but pre-existing and
is filed as #321.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks — three of the four findings were real and are fixed; one does not hold. Detail below, with what I verified against the corpus in each case. 🟡 DIR narrative — valid, fixedYou're right, and the error was mine. All three of DIR's Fe(III) species are terminal electron acceptors — Rewritten in both the 🟡
|
|
Claude finished @realmarcin's task in 3m 13s —— View job Re-review: METPO proposal v8 (commit
|
There was a problem hiding this comment.
Re-reviewed after 2dd3a6c. All three prior findings are resolved and verified against the corpus; the 142-vs-146 finding was my arithmetic error (I dropped CHEMICAL 4) and the published tally is correct. Details in #320 (comment)
…review) Hand-editing that file's curation event to describe the O2 reversal overwrote the half the script had written: the record claimed "Migrated 1 causal edge(s) ... (1 to has electron acceptor)" while the file actually migrated two — multicopper_oxidase --confers--> the trait as well. A 128-file migration where one record disclaims half its own change is exactly what misleads a later reader of the audit trail. Rewritten to the form the script emits for the other mixed file (dissimilatory_manganese_reduction), so the record now matches both the file and what a re-run would reproduce, while keeping the explanation of why the O2 edge was reversed. Audited every MIGRATE_ENABLES_TRAIT_EDGES event in the corpus against its own file rather than fixing only the reported one: 0 remaining disagreements across all 128. Also fixed the pre-existing numerator at proposal.md:93 (from #320): "114 of these 145 subjects" was the trait-RECORD count leaking into a sentence about subjects. By the appendix it is 125 (81 BIOLOGICAL_PROCESS + 32 GENE_OR_PROTEIN + 12 ENVIRONMENTAL_FACTOR), now stated with the breakdown so it cannot drift from the table again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…323) * Migrate 164 enables->TRAIT edges onto the v8 predicates (#302, #303) RO:0002327 (enables) has range 'biological process or activity', and a TRAIT node is a disposition, so all 164 of these edges entailed trait ⊑ BiologicalProcessOrActivity. They now carry the predicates proposed in proposals/metpo_traitmech_v8 (merged in #320): confers METPO:2007700 146 edges, direction unchanged has electron donor METPO:2007701 13 edges, direction reversed has electron acceptor METPO:2007702 5 edges, direction reversed The 18 electron edges are reversed back to <trait> -> <chemical>, which restores the donor/acceptor role PR #300 had to collapse onto enables (#303). The organism-subject problem that forced that collapse does not arise here: these predicates take a causal-node domain, not METPO:2000001's microbe domain (#301). The three mapping rows are GATED rather than the '*'/'*' used by earlier placeholder rows: confers is object_types=TRAIT with the 9 observed subject types, and the electron pair is TRAIT -> CHEMICAL. That enforces the "a chemical species" clause the declared OWL range deliberately does not, and is why oxygen_preference's MOLECULAR_FUNCTION node ("O2 as terminal electron acceptor", the USE of O2 rather than O2) grounds to confers instead. Applied by scripts/migrate_enables_trait_edges.py, which edits the raw lines rather than round-tripping through write_validated_trait: that helper is not byte-identical on hand-edited YAML (#322) and would have buried 164 real changes in reflow churn across 128 files. Baseline deltas, both intended and both verified: - predicate_domain_audit: 530 -> 366. ENABLES_RANGE_ON_TRAIT is fully burned down, 164 -> 0. The remaining 366 are the untouched #301 microbe-domain class. - evidence_snippet: 6 rows re-keyed, count unchanged at 2737. Reversing an edge changes its baseline key (subject->object), so 6 pre-existing findings re-key; all 6 old keys are present in the previous baseline. No new snippet defects. validate-strict: 477 files, 0 errors. pages/ regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Catch the O2 acceptor edge, and update the playbook (PR #323 review) Two review findings, both valid. manganese_oxidation described O2 as the "terminal oxidant", which names the terminal-electron-acceptor role, but ACCEPTOR_RE matched only `electron acceptor|terminal electron` so the edge fell to the `confers` catch-all. That is not false, just strictly weaker — precisely the loss #303 exists to stop. Widened the rule to `oxidant` (and `reductant`, for symmetry on the donor side) and reversed that edge onto METPO:2007702. Verified against the pre-migration corpus that the widened rule reclassifies exactly one edge and no others, so the partition moves 146/13/5 -> 145/13/6 and nothing else shifts. proposals/metpo_traitmech_v8 counts, appendix and observations cells updated to match. docs/CURATION_PLAYBOOK.md still told curators the #302 decision "is not settled", cited the now-zero 164-edge count, and gave a worked `enables` example — the opposite of what this PR establishes, in the one place the repo documents the convention. Rewritten to state the settled convention with a table of the three predicates, the trait -> chemical direction of the electron pair, the node-type gating, and the placeholder-id caveat. Also closed the loop the proposal had deferred TO this PR: the oxygen_preference MOLECULAR_FUNCTION node keeps its type and grounds to `confers`, and the mapping gate (object_types=CHEMICAL) stops it drifting onto the electron pair later. Recorded in the proposal's classification notes rather than left dangling. Two advisory findings filed rather than fixed: #324 (the script's mid-loop abort can leave a repo-wide partial migration) and #325 (no history/records entry for a 128-file change, and nothing enforces one). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Correct the five prose count sites left at 146/13/5 (PR #323 review) The previous commit corrected the partition tables, the appendix, the grand total and both ROBOT traits_addressed cells, but not the prose around them — so proposal.md asserted two different partitions about 60 lines apart. Fixed: proposal.md:93 114 of these 146 subjects -> 145 proposal.md:99 The 18 electron edges -> 19 (13 + 6) proposal.md:187 Edge partition (146 + 13 + 5) -> (145 + 13 + 6) proposal.md:288 Repoint the 146 ... reverse 18 -> 145 ... 19 predicate_grounding.tsv:102 across the 146 migrated edges -> 145 Line 288 mattered most: it is the adoption plan someone follows literally when METPO mints the real ids, and it was wrong on both the repoint count and the reversal count. The subject_types pipe-list on the confers mapping row is deliberately unchanged: CHEMICAL still has 3 edges, so all nine node types remain observed. Line 254 keeps "146/13/5 to 145/13/6" because that sentence records the correction itself. Every remaining count claim cross-checked against the corpus: confers 145, donor 13, acceptor 6, electron 19, total 164. PR description synced too, since it becomes the squash commit message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Restore the confers edge to manganese_oxidation's own record (PR #323 review) Hand-editing that file's curation event to describe the O2 reversal overwrote the half the script had written: the record claimed "Migrated 1 causal edge(s) ... (1 to has electron acceptor)" while the file actually migrated two — multicopper_oxidase --confers--> the trait as well. A 128-file migration where one record disclaims half its own change is exactly what misleads a later reader of the audit trail. Rewritten to the form the script emits for the other mixed file (dissimilatory_manganese_reduction), so the record now matches both the file and what a re-run would reproduce, while keeping the explanation of why the O2 edge was reversed. Audited every MIGRATE_ENABLES_TRAIT_EDGES event in the corpus against its own file rather than fixing only the reported one: 0 remaining disagreements across all 128. Also fixed the pre-existing numerator at proposal.md:93 (from #320): "114 of these 145 subjects" was the trait-RECORD count leaking into a sentence about subjects. By the appendix it is 125 (81 BIOLOGICAL_PROCESS + 32 GENE_OR_PROTEIN + 12 ENVIRONMENTAL_FACTOR), now stated with the breakdown so it cannot drift from the table again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Implements the "mint METPO terms" decision for the #301/#302/#303 cluster.
The problem, in one line
The corpus has no range-correct relation whose object is a trait, and both
available candidates are wrong in opposite directions.
RO:0002327(enables) has been filling the gap. The repo's own vendoreddata/raw/biolink-model.yaml:5099-5110gives it range'biological process or activity'; a
TRAITnode is a disposition, so each of164 edges entails
trait ⊑ BiologicalProcessOrActivity(164enablesedges point at TRAIT nodes, violating RO:0002327's range — and theenablesmapping row is ungated #302).METPO:2000008/2000009+ 64 siblings)are transitively
subPropertyOf METPO:2000001, whoserdfs:domainismicrobe.
CausalNodeTypeEnumhas no organism member, so no causal-graphedge can ever satisfy it (366 causal-graph edges assert microbe-domain METPO predicates on non-organism subjects #301).
That squeeze is exactly what forced PR #300 to reverse 15 electron edges onto
enables, collapsing donor and acceptor onto one relation and losing the rolefor 7 of them (#303).
What this proposes
Cohort
proposals/metpo_traitmech_v8/, three predicates, following the v1convention of domain = range =
METPO:1007401(trait causal node) — the choicethat sidesteps the microbe domain and the process range at once:
METPO:2007700METPO:2007701METPO:2007702The partition is exhaustive and verified: 146 + 13 + 5 = 164, computed by
walking every
causal_graphs[].edges[]and cross-checked against theindependently-derived
ENABLES_RANGE_ON_TRAITcount inreports/predicate_domain_audit.tsv(the audit added in #314).The donor/acceptor pair deliberately reverses direction back to
<trait> has electron donor <chemical>— restoring whatMETPO:2000008/2000009expressed before their organism domain made them unusable here. That reversal is
what lets one relation per role replace one generic relation, so
dissimilatory_iron_reduction's two acceptor edges stop being indistinguishablefrom its donor-shaped edge.
What was checked
just verify-proposal metpo_traitmech_v8→ PASS (failures: 0).just robot-validate-proposal metpo_traitmech_v8→ PASS: template compiles,merges with
metpo.owl, ELK reasons with no UNSAT (+6 axioms, matching v6'sdelta for a comparable cohort).
just qcgreen;uv run pytest→ 420 passed; ruff clean.definition_sourceanchor verified to be a realgraph_idin the citedfile. Cross-ontology alignments live in
xrefs+metpo_proposal_mappings.sssom.tsvas
skos:closeMatch, never indefinition_source(Emit cross-ontology equivalents as mappings, not definition_source, in METPO proposals #83).2007700is free,and the highest real minted METPO property is
METPO:2000516.Also fixed here: #318
Building this cohort hit a pre-existing bug.
verify_metpo_proposal's Scope-Acheck ran even for cohorts shipping no classes template, so
class_tsv_textwas""and every corpustraitmech:id read as uncited — failing everypredicate-only cohort (v2, v4, v6) once the corpus gained its first synthetic id.
The script already printed "Scope C/A check will skip" for that case and
check_scope_calready honoured it; only Scope-A did not.Fixed, with 4 regression tests. The fix was canaried against the pre-fix code:
the key test fails without the guard and passes with it, so it genuinely bites.
v1 and v7 still fail this check — correctly, because 120 synthetic ids really are
un-lifted, which is filed separately as #319.
Scope: proposal only
No corpus edges are grounded here. #301 warns that doing the whole sweep at once
would be unreviewable, so the 164-edge migration follows as a separate PR,
where the proof of landing is
ENABLES_RANGE_ON_TRAITfalling 164 → 0 in theratcheted audit. The placeholder IDs are not minted upstream yet; the round-trip
plan is in
proposal.md.Closes nothing on its own — #302 and #303 stay open until the migration lands.
🤖 Generated with Claude Code