Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/communitymech/datamodel/communitymech.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Auto generated from communitymech.yaml by pythongen.py version: 0.0.1
# Generation date: 2026-08-08T00:48:13
# Generation date: 2026-08-08T01:28:55
# Schema: communitymech
#
# id: https://w3id.org/communitymech
Expand Down
29 changes: 28 additions & 1 deletion src/communitymech/schema/communitymech.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1640,7 +1640,34 @@ classes:
required: false
inlined_as_list: true
taxonomy:
description: Organisms present in the community
description: >-
Organisms present in the community — its membership, not everything it
interacts with.

A host and an antagonist are **not** members (#319). The community
lives on or in its host and is applied against its antagonist; both
appear as `ecological_interactions` participants without appearing
here, which is why the network auditor reports them as
`UNKNOWN_SOURCE`/`UNKNOWN_TARGET` at warning severity rather than
gating on them (#326).

Of the 25 interaction participants currently outside this slot, 14 are
aggregate names for members that *are* present — `Variovorax` where
the record lists `Variovorax sp. CF313`, `YR634` and the rest — so
they are a naming coarseness rather than a membership question. The
remaining 11 are 6 hosts, 3 antagonists and 2 abiotic
(`anode`), and none of them belongs here.

The mirror-image question is #307: candidates deliberately screened
*out* are likewise not members, and live in
`engineering_design.counter_selection`. Both answers are the same, for
the same reason — this slot records what the community is made of, and
an edge to something outside it is not evidence that it should be
inside it.

`tests/test_interaction_participants_outside_taxonomy.py` holds the
population to those four groups, so a new host or antagonist has to be
classified rather than absorbed.
range: TaxonomicComposition
multivalued: true
ecological_interactions:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_interaction_participants_outside_taxonomy.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,32 @@ def test_the_group_sizes_are_what_the_decision_was_sized_against(group: str, exp
which is a much smaller commitment than the headline count suggests.
"""
assert len(globals()[group]) == expected


def test_the_schema_records_the_membership_decision():
"""#319's question, answered in the slot rather than in an issue thread.

"Should hosts and antagonists be taxonomy members?" was re-derived at least
twice — once when the auditor was written and once when this file was — and
each time from the same evidence. Recording it on `taxonomy` means the next
reader finds the answer where they are already looking.

Asserted positively: the description must *say* hosts and antagonists are
not members. A check that some phrase is absent would pass on a rewrite
that dropped the reasoning entirely.
"""
import yaml

schema = yaml.safe_load(
(REPO / "src/communitymech/schema/communitymech.yaml").read_text(encoding="utf-8")
)
description = schema["classes"]["MicrobialCommunity"]["attributes"]["taxonomy"]["description"]

assert "#319" in description
lowered = description.lower()
assert "host" in lowered and "antagonist" in lowered, (
"the taxonomy slot no longer states whether hosts and antagonists are "
"members, which is the question #319 asked and this file pins the "
"population for"
)
assert "not" in lowered, "the decision was 'no'; the description must say so"
Loading