Skip to content

Remove ontology; read participant aliases via cross-core join - #264

Merged
samseaver merged 2 commits into
stagingfrom
remove-ontology-and-participant-aliases
Sep 16, 2026
Merged

samseaver merged 2 commits into
stagingfrom
remove-ontology-and-participant-aliases

Conversation

@samseaver

Copy link
Copy Markdown
Contributor

Two related fixes to reaction quick-search, plus a guard so the same class of bug cannot return silently.

The outage this came from

Reaction search was failing with what the browser reported as a CORS error. It was not CORS. Solr answered HTTP 400 undefined field participant_aliases, and a 400 carries no Access-Control-Allow-Origin header, so the browser discarded the response and blamed the wrong layer. The real error was in the body all along.

participant_aliases had never existed — not in any schema, not in the compiler, not on any core. This UI has queried it since v3.6.5.

1. ontology removed entirely

Gone from the biochemistry JSON and both Solr schemas, but the UI still carried nine references: two type declarations, two special cases that existed only to filter it out of compound queries, a detail row on each of the reaction and compound pages, an entry in the reaction fl list, an explanatory comment, and two tests asserting the workaround.

2. Participant aliases via cross-core join

Searching reactions by a participating compound's alias did not work. The clause beside the undefined field — aliases — looked like a working fallback and was not: stoichiometry children carry no aliases, so of 262,517 children exactly 0 matched it. Participant search worked by compound id and participant name only.

It now reads the aliases from the compounds core at query time:

{!join from=id to=compound fromIndex=${SOLR_COMPOUNDS_COLLECTION}}aliases:X

inside the existing block join. fromIndex comes from config so it follows the environment — compounds_staging when querying reactions_staging. A mismatch resolves against the other environment's data rather than erroring, which is why it is threaded from config rather than written literally.

Verified against live cores, not mocks:

term by participant name via join
ChEBI 30616 0 4,702
L-Glutamine 237 266
cpd00053 0 (200 via compound:) —

30616 is not ATP's name, not its ModelSEED id, and not in any reaction's own fields; 4,702 matches cpd00002's participant count exactly. L-Glutamine shows the join adding 29 reactions name matching misses. The join is genuinely applied rather than parsed away: drop the {!join} prefix and the same query returns 0.

3. The guard, generalised

The existing test asserted "the query must not contain ontology" — protection against exactly one field. It now extracts every field: token from the generated query and asserts each is one the core defines. Three fields have reached production as undefined-field 400s — ontology, stoichiometry, participant_aliases — each fixed individually, none of them prevented.

423 unit tests pass.

Deployment ordering

This must ship before the backend field is withdrawn. Production currently serves participant_aliases as a denormalised field on the stoichiometry children, because the deployed UI needs it. Once this is deployed, ModelSEEDDatabase 42d9e70f is reverted and the cores reposted without it. Doing that in the other order takes reaction search down.

🤖 Generated with Claude Code

Sam Seaver and others added 2 commits September 16, 2026 12:34
ontology is gone from the biochemistry JSON and from both Solr schemas, but the
UI still carried it: two type declarations, two special cases that existed only
to filter it out of compound queries, a detail row on each of the reaction and
compound pages, an entry in the reaction fl list, a comment explaining the trap,
and two tests asserting the workaround. All removed. A field that no longer
exists anywhere should not leave nine references behind to be rediscovered.

The ontology guard test is kept but generalised. It asserted "q must not contain
ontology", which protects against exactly one field; it now extracts every field:
token from the generated query and asserts each is one the core defines. That
would have caught ontology, stoichiometry and participant_aliases alike -- three
fields that have reached production as undefined-field 400s, each fixed
individually and none of them prevented.

participant_aliases now exists: the compiler emits it on every stoichiometry
child and the schema declares it (ModelSEEDDatabase 0cd43867), so the join clause
is restored and the aliases clause beside it is dropped. That one matched nothing
-- child documents never carried aliases -- and its presence made the gap look
like a working fallback.

Verified against the live cores rather than mocks: the exact query the browser
sends returns 200 on both, and ChEBI 30616, which is not ATP's name, not its
ModelSEED id and not in any reaction field, now finds 4,702 reactions where it
previously found none. 423 unit tests pass.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Searching reactions by a participating compound's alias now reads the aliases
from the compounds core at query time:

    {!join from=id to=compound fromIndex=${SOLR_COMPOUNDS_COLLECTION}}aliases:X

inside the existing stoichiometry block join, replacing a participant_aliases
field copied onto all 262,346 stoichiometry children. Same answers, one copy of
the data, and editing a compound's aliases takes effect without reposting the
56,012 reactions that reference it.

fromIndex comes from SOLR_COMPOUNDS_COLLECTION so it follows the environment --
compounds_staging when the UI is querying reactions_staging. Getting that wrong
resolves the clause against the other environment's data rather than erroring,
which is why it is threaded from config instead of written literally.

Verified against the live cores, not mocks. The three-way OR unions correctly:
L-Glutamine gives 237 reactions by participant name and 266 through the join, so
the alias path adds 29 the name search misses; cpd00053 gives 200 through the
compound branch alone; ChEBI 30616 gives 4,702 through the join and 0 by name or
id. The join is really applied rather than parsed away: remove the {!join}
prefix and the same query returns 0, because children have no aliases field.
423 unit tests pass.

participant_aliases also leaves the fl list. It was only ever fetched to be read
back; the join needs nothing returned.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@samseaver
samseaver merged commit 4cab18c into staging Sep 16, 2026
2 checks passed
@samseaver
samseaver deleted the remove-ontology-and-participant-aliases branch September 16, 2026 18:42
samseaver pushed a commit that referenced this pull request Sep 16, 2026
Hotfix: participant-alias search rebuilt as a cross-core join, ontology removed
throughout, and the undefined-field guard generalised. See PR #264.
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