Skip to content

Generic identifier, table and reference grounders, and the feedback loop - #35

Merged
NingyuSUN merged 5 commits into
mainfrom
generic-grounders
Oct 5, 2026
Merged

NingyuSUN merged 5 commits into
mainfrom
generic-grounders

Conversation

@NingyuSUN

@NingyuSUN NingyuSUN commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Generic grounders and a generic feedback loop, so what the literature work showed (checks against pinned sources, and an agent that revises after bioevidence rejects its answer) applies to any biological domain. Part of #26. The next PR uses them for a real AI experiment on single-cell cell-type annotation.

Grounders

Each grounder checks what a record cites against a pinned release of a reference, offline and deterministically. Each one's name records the release it used, and every message says what to fix.

Grounder Checks Codes
OntologyGrounder A term (Cell Ontology, HPO, MONDO, UBERON …) exists and is not obsolete (the message names the replacement). Its label is the term's name or an exact synonym (the message names the term the label belongs to). It is of the right kind (e.g. a cell_type must be under CL:0000000). BEV016, BEV023, BEV017, BEV024
GeneGrounder HGNC symbols and IDs. Previous symbols, aliases and wrong case are reported with the approved symbol (CD20 → MS4A1, CD45 → PTPRC). Records scoped to another species are not checked. BEV016, BEV023, BEV017, BEV015
VariantGrounder HGVS form and version. The RefSeq accession is on the record's genome build, and the position is inside the chromosome. BEV024, BEV016, BEV017
TableGrounder Evidence citing a row of a pinned table (cluster=3;gene=CD8A): the row exists (the message names the closest keys), and the claimed values match at the precision written. BEV016, BEV017, BEV015, BEV024
ReferenceGrounder A pinned reference resource (e.g. canonical markers) contradicts the claim or its supporting evidence: by default a different term that is not an ancestor or descendant; with conflict="disjoint", only terms the ontology declares disjoint (inherited disjoint_from, e.g. T cell and B cell). Review only, never rejects. BEV025

New codes:

  • BEV023: obsolete or superseded identifier (reject).
  • BEV024: malformed identifier, or the wrong kind for its place (reject).
  • BEV025: a reference resource conflicts with the record (review).

bioevidence validate gains --ontology, --term-root, --genes and --assembly-report.

Feedback loop

feedback.revise(propose, validator) wraps any proposer (a model, an agent, a person):

  • Fixable findings go back as reasons that point at the evidence item concerned.
  • Findings that need judgment (BEV004, BEV021, BEV022, BEV025) or a human decision by policy (BEV008–BEV013) are not fed back. The record goes to a person as it is.
  • Verified evidence is carried through revisions while the claim stays the same, so an agent cannot withdraw evidence against its answer. The literature agent loop showed that it would. A revision that states a different claim is validated on its own evidence, since carried stances would mean something else.

Checks

  • ruff, mypy, pytest: coverage 98.80%.
  • 42 new tests on hand-made fixtures.
  • mkdocs build --strict, wheel build and installed-wheel smoke test.
  • The parsers were also run on the real Cell Ontology (2026-06-08, 3,540 terms) and HGNC set (2026-09-29, 45,140 genes). That found two bugs, both fixed with regression tests:
    • ontology: cl/cl-basic was parsed as the prefix CL/CL-BASIC;
    • label lookup returned duplicate IDs.

Changes after the first push, from trying the grounders on the single-cell case (next PR)

  • Ontology labels match ignoring a plain plural ("hepatocytes").
  • Ontology parses disjoint_from, and ReferenceGrounder has conflict="disjoint". With the default rule, ASCT+B flagged CCL5 cited for an NK T cell, because ASCT+B lists it for cytotoxic T cells, a sibling type. Disjointness restricts conflicts to lineages the Cell Ontology itself declares exclusive. This needs the full cl.obo: cl-basic.obo drops the axioms.
  • Evidence is carried only for an unchanged claim.

…ck loop

OntologyGrounder, GeneGrounder and VariantGrounder check the ontology
terms, gene symbols and HGVS variants a record cites against pinned
releases; TableGrounder checks cited rows and values of a pinned table;
ReferenceGrounder sends a record that a curated reference contradicts
to review. Messages name what to fix. New codes BEV023 (obsolete or
superseded identifier), BEV024 (malformed or wrong kind) and BEV025
(reference conflict, review only).

feedback.revise runs validate, feedback and revision around any
proposer: fixable findings go back as reasons, conflicts and policy
decisions go to a person unchanged, and verified evidence is carried
through revisions.
Evidence lines are relative to their statement: a revision that states
another cell type or the opposite predicate is validated on its own
evidence, instead of inheriting stances that meant something else.
'Hepatocytes' names CL:0000182 as well as 'hepatocyte' does; both sides
are normalised the same way, so distinct terms stay distinct.
Ontology parses disjoint_from and inherits it through is_a. With
conflict="disjoint", ReferenceGrounder reports a supporting marker
only when every type the reference lists it for is declared disjoint
from the claimed type, so a marker listed for a sibling type is not a
conflict.
@NingyuSUN
NingyuSUN merged commit 7ac9910 into main Oct 5, 2026
10 checks passed
@NingyuSUN
NingyuSUN deleted the generic-grounders branch October 6, 2026 02:41
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