This is what the #235 canary actually established, and it inverts the conclusion that PR set out to reach.
The claim that failed
label-correspondence was credited with making the grounding backfill safe to run unattended. It is not. scripts/validate_id_label_correspondence.py compares an (id, label) pair against the ontology's canonical label and synonyms — that is its entire scope. It has no view of the edge a CURIE lands on. predicate_id in src/traitmech/schema/traitmech.yaml:377 is a bare pattern-constrained string with no binding, so nothing in just qc, audit-graphs, or validate-strict inspects domain or range either.
OK_CANONICAL: 308 → 311 was a true statement about three TSV rows and said nothing about the 66 edges those rows then grounded.
What that let through
causally upstream of is the exact label of RO:0002411, so it passed every check — and it was still wrong. RO defines it over occurrents ("the end of p precedes the end of q, and p is not an occurrent part of q"), while all 13 edges it grounded connected material entities:
| shape |
edges |
CHEMICAL → CHEMICAL |
6 |
GENE_OR_PROTEIN → CHEMICAL |
6 |
GENE_OR_PROTEIN → CAPACITY |
1 |
Reverted in #235. The point is not the revert, it is that an exact label match was not sufficient, which is exactly the tier boundary the loop was going to fan out along.
The pre-existing question this measurement surfaced
Not introduced by #235 and deliberately not relitigated there, but now quantified. Both regulation relations are also processual — "increases/decreases the rate or magnitude of execution of q" — and the corpus overwhelmingly uses them between material entities:
| predicate |
edges |
process → process |
RO:0002213 positively regulates |
206 |
27 (13%) |
RO:0002212 negatively regulates |
102 |
9 (8%) |
Common non-conforming shapes: GENE_OR_PROTEIN → BIOLOGICAL_PROCESS, ENVIRONMENTAL_FACTOR → BIOLOGICAL_PROCESS, CHEMICAL → QUALITY. RO has a material-entity branch for some of these — RO:0004034 / RO:0004035, acts upstream of, positive/negative effect — which is where gene-product→process claims belong.
This predates #235: promotes→RO:0002213 and inhibits→RO:0002212 have been in mappings/predicate_grounding.tsv:58-65 for some time. It is a corpus-wide curation decision, not a cleanup.
Proposal
Add a column to mappings/predicate_grounding.tsv recording which (subject_type, object_type) pairs a predicate may connect, and have ground_causal_predicates.py refuse edges that do not match — reporting them as residual rather than grounding them.
That makes the constraint declarative and checkable, and it is the precondition for fanning the grounding loop out. Without it the next unit fails the same way with a green gate.
Whether to then re-examine the 308 existing regulation edges is a separate call, and should be made with the numbers above in hand.
This is what the #235 canary actually established, and it inverts the conclusion that PR set out to reach.
The claim that failed
label-correspondencewas credited with making the grounding backfill safe to run unattended. It is not.scripts/validate_id_label_correspondence.pycompares an(id, label)pair against the ontology's canonical label and synonyms — that is its entire scope. It has no view of the edge a CURIE lands on.predicate_idinsrc/traitmech/schema/traitmech.yaml:377is a bare pattern-constrained string with no binding, so nothing injust qc,audit-graphs, orvalidate-strictinspects domain or range either.OK_CANONICAL: 308 → 311was a true statement about three TSV rows and said nothing about the 66 edges those rows then grounded.What that let through
causally upstream ofis the exact label of RO:0002411, so it passed every check — and it was still wrong. RO defines it over occurrents ("the end of p precedes the end of q, and p is not an occurrent part of q"), while all 13 edges it grounded connected material entities:CHEMICAL → CHEMICALGENE_OR_PROTEIN → CHEMICALGENE_OR_PROTEIN → CAPACITYReverted in #235. The point is not the revert, it is that an exact label match was not sufficient, which is exactly the tier boundary the loop was going to fan out along.
The pre-existing question this measurement surfaced
Not introduced by #235 and deliberately not relitigated there, but now quantified. Both regulation relations are also processual — "increases/decreases the rate or magnitude of execution of q" — and the corpus overwhelmingly uses them between material entities:
positively regulatesnegatively regulatesCommon non-conforming shapes:
GENE_OR_PROTEIN → BIOLOGICAL_PROCESS,ENVIRONMENTAL_FACTOR → BIOLOGICAL_PROCESS,CHEMICAL → QUALITY. RO has a material-entity branch for some of these —RO:0004034/RO:0004035, acts upstream of, positive/negative effect — which is where gene-product→process claims belong.This predates #235:
promotes→RO:0002213 andinhibits→RO:0002212 have been inmappings/predicate_grounding.tsv:58-65for some time. It is a corpus-wide curation decision, not a cleanup.Proposal
Add a column to
mappings/predicate_grounding.tsvrecording which(subject_type, object_type)pairs a predicate may connect, and haveground_causal_predicates.pyrefuse edges that do not match — reporting them as residual rather than grounding them.That makes the constraint declarative and checkable, and it is the precondition for fanning the grounding loop out. Without it the next unit fails the same way with a green gate.
Whether to then re-examine the 308 existing regulation edges is a separate call, and should be made with the numbers above in hand.