curate-grouping
Create, edit, review, or audit dismech disease groupings in kb/groupings/*.yaml. Use for Grouping records, member unions, grouping_basis and grouping_rationale, membership_criteria boolean logic, crit
SKILL.md.claude/skills/curate-grouping/SKILL.md
GitHubCurate a Disease Grouping
Treat kb/groupings/ as the source of truth. A grouping is an explicit curated
union of already-distinct diseases, modules, or other groupings. It validates
against Grouping, not Disease, and points down by listing members; it does
not recreate the MONDO hierarchy.
Discover relevant examples
rg --files kb/groupings -g "*.yaml" | sort
rg -il "<disease family or mechanism>" kb/groupings
sed -n "1,160p" kb/groupings/Mucopolysaccharidoses.yaml
Use Mucopolysaccharidoses for a NECESSARY criteria example and
Inherited_Arrhythmia_Syndromes for nested boolean logic with
NECESSARY_AND_SUFFICIENT criteria. Inspect the current YAML rather than
copying a static catalog.
Define the boundary
- Set
name, optionaldisplay_name,creation_date,description,grouping_basis,grouping_rationale,membership_criteria, andmembers. - Use
grouping_basisto record why the members belong together; inspect the schema for current enum values rather than inventing one. - Explain the lump/keep-split boundary in
grouping_rationale. A grouping sits over distinct entities, so do not put aLUMPflag on it. - An optional MONDO mapping is a cross-reference, not the source of membership.
Model membership criteria
Each membership_criteria block needs a human-readable description. Its
optional logic is a LogicalCriterion tree:
- Branch nodes use
operator: AND,OR, orNOTwithoperands. - Leaf nodes use
criterion_predicateand the matching payload:HAS_PHENOTYPE,HAS_GENE,CONFORMS_TO_MODULE,HAS_BIOLOGICAL_PROCESS,HAS_CLASSIFICATION,HAS_INHERITANCE,HAS_MAPPING, orOTHER. - Use
negated: trueto negate a leaf when clearer than aNOTbranch.
Choose criteria_semantics deliberately:
NECESSARY: member => criteria. Audit listed members for contradictions.SUFFICIENT: criteria => member. Discover candidate additions.NECESSARY_AND_SUFFICIENT: both directions; the criteria define membership.
Do not encode an acknowledged exception to a necessary condition. A listed member that fails a necessary criterion is a contradiction to resolve by correcting the member annotation, criterion, or membership.
HP and GO leaves are evaluated over is_a/part_of ontology closure;
HAS_GENE remains exact. The closure is read from the committed
cache/closure/<prefix>.csv files, so the audit is offline and deterministic.
A criterion term with no cached closure evaluates to UNKNOWN (never a
downgraded exact match, which would report false contradictions) and fails
--strict. After adding or changing an HP or GO criterion term, run
just build-grouping-closure-cache and commit cache/closure/; never
hand-edit those files. The cache is a snapshot: if a member's term was added
to the ontology after the last build it reads NOT_SATISFIED, so run
just build-grouping-closure-cache --refresh after an ontology release before
calling such a finding a contradiction. State the criterion at the intended
conceptual level rather than compensating for a missing annotation.
Add members and differentiators
Grouping members are diseases, named disease subtypes, or nested disease
groupings. Do not add a mechanism module as a member. Use a module reference
inside membership criteria or a differentiating mechanism when the module helps
define or distinguish diseases; use a ModuleCollection in
kb/module_collections/ when the task is to organize modules themselves.
members[].membermust resolve to a realDisease.nameor grouping name according tomember_type;SUBTYPEmembers name their parent disease.- Every referenced module and optional
#Node Namemust exist. - Use
differentiating_mechanismsfor what distinguishes a member from its siblings; bind genes, phenotypes, processes, or modules when appropriate. - Keep grouping names unique.
Nest a grouping inside another
A grouping can list another grouping as a member with member_type: GROUPING.
That declaration is the only source of hierarchy: the index page's tree, a
grouping page's "Where this grouping sits" strip, and the evaluator all read it
and nothing else (no MONDO inference).
- Nest only when every disease member of the child belongs to the parent under
the parent's own criteria, and both rationales agree on the relation. Run
just grouping-nesting-auditfirst: it prints the declared tree and the undeclared containments (child member set ⊆ parent member set). A containment is a lead, not a ruling — orthogonal cross-cuts such asCentrosomopathiesvsPrimary_Microcephaly_Spectrumcontain each other's members by design and must stay separate. - A nested grouping replaces the direct rows it covers; do not list a disease
both directly and through a nested grouping. Keep the differentiating text by
folding it into the GROUPING row's
differentiating_mechanisms(one entry per covered disease, gene bindings included), asMotor_Neuron_Disordersdoes forBulbospinal_Muscular_Atrophies. - Diseases reached through a nested grouping are still members:
just check-groupingsevaluates them against the parent's criteria and prints them as(via <child>), and the parent page shows them asnested viarows that count toward coverage. - Record the change in the parent's
notesand in a history record underhistory/other/<Parent_slug>/.
Validate and inspect
just validate-grouping kb/groupings/<Grouping>.yaml
just check-groupings kb/groupings/<Grouping>.yaml
just check-groupings --strict --offline kb/groupings/<Grouping>.yaml
just build-grouping-closure-cache # after adding an HP/GO criterion term
just validate-grouping-batch kb/groupings/<Grouping>.yaml # what CI runs
just gen-grouping-page kb/groupings/<Grouping>.yaml
Use just validate-groupings for the full set. CI runs
validate-grouping-batch on every changed grouping file: schema, terms,
references, then the strict offline audit, which fails on a malformed
criteria tree, a dangling member or module reference, an uncached criterion
term, or a listed member that does not satisfy a NECESSARY criterion. Treat
the evaluator's UNKNOWN as missing information, not failure; investigate
every NOT_SATISFIED listed member. Generated pages/groupings/*.html files
are derived and must not be committed with hand-authored changes.