feat(associations): flexible association-type section matching - #1355
feat(associations): flexible association-type section matching#1355kevinschaper wants to merge 4 commits into
Conversation
Generalize AssociationTypeMapping so a section can be matched by any combination of category, predicate, subject_category, object_category, primary_knowledge_source and provided_by — each an optional list (OR within a criterion, AND across; omitted = no constraint) — and identified by a stable `key`. This lets several sections share one biolink category (e.g. biolink:Association) distinguished by predicate/object, which the current category-only keying cannot express. - schema: add `key` + make the six match criteria multivalued on AssociationTypeMapping; add `key` to AssociationCount (regenerated model.py / model.ts). - loader normalizes scalar yaml to lists and defaults `key` to the category, so existing mappings and counts are unchanged. - get_solr_query_fragment builds the composite AND-of-OR clause; single-category mappings render identically to before. - parse_association_counts attributes results by rebuilding each mapping's exact query string and accumulates on `key`. - fixtures regenerated (counts identical); mapping tests updated to the list API. Backward-compatible; table-by-key resolution and frontend keying follow. Claude-Session: https://claude.ai/code/session_018c9UddtKsKtm35YNrxHWuL
Make the association table query key on the section key rather than a single
category, so sections that share a biolink category (or span several) resolve
to their full match criteria.
- get_association_table treats its `category` arg as a section key: it resolves
the AssociationTypeMapping and applies the mapping's category list plus
predicate / subject / object / source criteria as filters. An unknown key
falls back to a literal category filter, so existing single-category sections
and direct API use are unchanged (key defaults to the category).
- build_association_table_query now takes a category list.
- the /entity/{id}/{key} path param loosens from the AssociationCategory enum to
a string key.
- frontend: use-association-categories keys sections on `ac.key` (falling back
to category), so the section id and table URL carry the key.
Completes the flexible-section-matching enabler; LOINC and in-app MEDIC+CTD
mappings build on it.
Claude-Session: https://claude.ai/code/session_018c9UddtKsKtm35YNrxHWuL
✅ Deploy Preview for monarch-app canceled.
|
ReviewThis is solid groundwork — the composite-criteria design (list-valued 🐛 Bug: broken direction detection in
|
…category subject_category and object_category are now list[str] on AssociationTypeMapping, so get_generic_entity_grid's `context_category == mapping.subject_category` comparison was always false, silently dropping out of the YAML-metadata direction path into the string heuristic (and logging a spurious warning every call). Use membership (`in`) instead. Claude-Session: https://claude.ai/code/session_018c9UddtKsKtm35YNrxHWuL
Review: flexible association-type section matchingOverall this is a well-scoped, backward-compatible generalization — the "OR within a criterion, AND across criteria" model is clean, the query-fragment-rebuild approach in Potential issues1. 2. 3. 4. Query semantics quietly change for existing mappings that already had Minor / style
Nits
Nice groundwork PR — the design generalizes cleanly and the backward-compat story (verified via regenerated fixtures + existing suite) is convincing for the common case. The items above are mostly forward-looking correctness/ambiguity risks that matter once LOINC/MEDIC+CTD mappings actually land, plus one API-surface hardening question (#3) worth a quick look before merge. |
…categories Flexible matching started ANDing subject_category/object_category into every section's Solr query/count fragment. For legacy single-category sections those fields are entity-grid direction metadata, not match criteria, and constraining on them undercounts edges whose node categories differ from the declared ones — validated against monarch-kg-dev: GeneToExpressionSite 2,444,959 -> 412,772 (-83%, object is biolink:NamedThing/Cell/CellularComponent) and GenotypeToGene 160,230 -> 285 (-99.8%, object is biolink:SequenceVariant). Only sections authored with an explicit key (drug_indications, the clinical-measurement sections) opt into the full multi-criteria match; legacy sections (key defaulted to their category) match on category alone, exactly as before. Regenerated the count query/response fixtures accordingly. Claude-Session: https://claude.ai/code/session_018c9UddtKsKtm35YNrxHWuL
Review: flexible association-type section matchingThis is a well-scoped, backward-compatible generalization of A few things worth a look before this lands as the base for #1349/#1348: Correctness / design risk
Minor / quality
Test coverageBackend tests look thorough for the new list/OR/AND semantics and the legacy-vs-composite distinction ( Overall: solid, low-risk groundwork with good regression discipline. The |
Draft — the enabler that lets a node-page association section be defined by more than a single biolink category. Groundwork for LOINC (#1349) and in-app MEDIC+CTD (#1348); no user-visible change on its own (fully backward-compatible).
Why
Sections are currently keyed 1:1 on the association
category. That can't express sections whose edges all share one generic category (LOINC'sbiolink:Association) or that span several categories (MEDIC + CTD). This generalizes the matching.What
AssociationTypeMappingbecomes a set of optional list criteria —category,predicate,subject_category,object_category,primary_knowledge_source,provided_by— plus a stablekey. Values within a criterion are OR'd; criteria are AND'd; an omitted criterion is unconstrained.model.yaml→ regeneratedmodel.py/model.ts):key+ multivalued criteria onAssociationTypeMapping;keyonAssociationCount.get_solr_query_fragmentbuilds the compositeAND-of-ORclause (single-category mappings render identically);parse_association_countsattributes each facet result by rebuilding its exact query string and accumulates onkey.get_association_tabletreats its arg as a section key, resolves the mapping, and applies its category list + predicate/subject/object/source filters. Unknown key ⇒ literal category filter (back-compat)./entity/{id}/{key}path param loosens from the enum to a string.ac.key(falling back to category), so the section id and table URL carry the key.keyto the category, so existing mappings/behaviour are unchanged.Backward compatibility
Every existing single-category mapping keeps
key == category, single-value criteria render byte-identical, and counts are unchanged — verified by regenerating the counts fixtures from code (identical values) and the passing suite.Tests
Backend: mapping/parser/query/implementation suites green (134); mapping tests updated to the list API incl. composite + OR-within cases. Frontend:
useAssociationCategoriescovers key-preferred ids; typecheck/lint clean. (API-layer tests hit a pre-existingAttributeError: JSONcollection error also present onmain.)Follow-ons
category: [medic, ctd].biolink:ClinicalMeasuremententity-type support + hierarchy widget (separate).https://claude.ai/code/session_018c9UddtKsKtm35YNrxHWuL