Skip to content

fix(globi): hasHost with a pollinator subject is forage, not pest_pressure - #2

Open
vbeefy wants to merge 1 commit into
mainfrom
fix/globi-pollinator-hashost
Open

fix(globi): hasHost with a pollinator subject is forage, not pest_pressure#2
vbeefy wants to merge 1 commit into
mainfrom
fix/globi-pollinator-hashost

Conversation

@vbeefy

@vbeefy vbeefy commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Problem

lib/globi-classify.js::resolveVariable resolves GloBI's hasHost term with a generic rule:

// Invertebrate has host plant = pest pressure
if (srcBio === 'invertebrate' && tgtIsPlant)  pest_pressure

A bee is an invertebrate, and its "host plant" is the plant it forages on. So every bee→plant hasHost record became a harmful crop-pest claim — a sign inversion: a mutualist recorded as harm.

This is the most damaging error class for an agroecology knowledge base. It doesn't just add noise — it inverts the recommendation ("this bee damages your dandelion" instead of "this bee pollinates it"). It also corrupts anything downstream that treats "organism harming a crop" as a pest node.

Fix

A pollinator guard placed before the generic invertebrate rule:

  • subject primary_role='pollinator' OR a POLLINATOR_FAMILIES bee family (Apidae, Halictidae, Andrenidae, Megachilidae, Colletidae, Melittidae, Stenotritidae)
  • with a plant object ⇒ pollination / beneficial

Both signals are needed. The family fallback matters because much of the corpus carries primary_role='unclassified'; the role check independently catches non-bee flower-visitors such as Syrphidae (hoverflies), which no bee-family list would.

Not over-correcting

Regression tests pin the paths that must not change:

  • a genuine herbivore → plant still ⇒ pest_pressure
  • a fungal pathogen → plant still ⇒ pathogen_pressure

Retroactive re-derive

fix-globi-pollinator-category.cjs corrects already-loaded claims by re-running the fixed classifyTriple over the affected candidate set and writing back only where the derived category changes.

Two deliberate properties:

  • Self-limiting — a real pest re-derives to pest_pressure and is left untouched.
  • One source of truth — it reuses the classifier instead of duplicating the mapping, so it can't drift from it.

Dry-run by default; every change is revision-logged (fully reversible).

Same bug class as hasVector

GloBI's broad terms (hasHost, hasVector) get resolved by generic bio_category rules, and each such rule can silently mis-brand mutualists — cf. the earlier "hasVector is dispersal, not disease" correction, which had mislabeled seed-dispersers as disease vectors. Useful heuristic when adding or auditing one of these rules: ask which mutualist it would mis-brand.

Test plan

node --test backend/lib/globi-classify.test.js10/10 pass (verified against this branch's base).

🤖 Generated with Claude Code

…ssure

`lib/globi-classify.js::resolveVariable` resolved GloBI's `hasHost` with
the generic rule "invertebrate has host plant => pest_pressure". A bee IS
an invertebrate and its "host plant" is the plant it FORAGES on, so every
bee->plant hasHost record became a harmful crop-pest claim — a sign
inversion (a mutualist recorded as harm).

Fix: a pollinator guard placed BEFORE the generic invertebrate rule —
subject primary_role='pollinator' OR a POLLINATOR_FAMILIES bee family
(Apidae, Halictidae, Andrenidae, Megachilidae, Colletidae, Melittidae,
Stenotritidae) with a plant object => pollination/beneficial. The family
fallback matters because much of the corpus carries
primary_role='unclassified'; the role check independently catches non-bee
flower-visitors such as Syrphidae.

Regression-pinned: a genuine herbivore still => pest_pressure and a fungal
pathogen still => pathogen_pressure, so the guard cannot over-correct.

Also adds fix-globi-pollinator-category.cjs, which re-derives already-
loaded claims by re-running the FIXED classifyTriple over the affected set
and writing back only where the derived category changes. That is
deliberately self-limiting — a real pest re-derives to pest_pressure and
is left alone — and keeps one source of truth rather than duplicating the
mapping. Dry-run by default; every change is revision-logged.

This is the same bug class as the earlier "hasVector is dispersal, not
disease" correction: GloBI's broad terms (hasHost, hasVector) are resolved
by generic bio_category rules, and each such rule needs a mutualist guard.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <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