In METPO's binned quantitative classes, consecutive bins share their boundary value: the lower bin declares maxInclusive N and the next declares minInclusive N. A measurement of exactly N therefore satisfies both class definitions.
Observed in metpo.owl, versionIRI https://w3id.org/metpo/releases/2026-06-12/metpo.owl.
Scope: this is systematic, not isolated
Every binned series is affected — 41 overlapping boundaries across 10 series:
| series |
bins |
overlapping boundaries |
| temperature optimum |
7 |
6 |
| temperature range |
7 |
6 |
| pH range |
6 |
5 |
| pH delta |
6 |
5 |
| temperature delta |
5 |
4 |
| GC |
4 |
3 |
| NaCl optimum |
4 |
3 |
| NaCl range |
4 |
3 |
| NaCl delta |
4 |
3 |
| pH optimum |
4 |
3 |
Concretely, for temperature optimum:
METPO:1000441 temperature optimum very low value <= 10
METPO:1000442 temperature optimum low value >= 10 and <= 22
METPO:1000443 temperature optimum mid1 value >= 22 and <= 27
METPO:1000444 temperature optimum mid2 value >= 27 and <= 30
METPO:1000445 temperature optimum mid3 value >= 30 and <= 34
METPO:1000446 temperature optimum mid4 value >= 34 and <= 40
METPO:1000447 temperature optimum high value >= 40
10 satisfies both 1000441 and 1000442; 22 satisfies both 1000442 and 1000443; and so on. The same shape appears in GC (<=42.65 / >=42.65), NaCl (<=1 / >=1) and pH (<=6 / >=6).
Why it matters
These classes read as a partition — "very low / low / mid1 / … / high" — but they are not disjoint. Consequences:
- A reasoner will infer a boundary-valued individual into two sibling classes. If the siblings are ever asserted
owl:disjointWith, that becomes an inconsistency rather than a modelling wrinkle.
- Any consumer binning a measurement must invent a tie-break, and different consumers will invent different ones, so the same input yields different METPO terms in different pipelines. That silently defeats the point of using a shared ontology for the bins.
- Boundary values are not rare in this domain. Growth temperatures cluster hard on round numbers — 10, 22, 30, 34, 37, 40 — so the ambiguous values are exactly the commonly reported ones, not tail cases.
The rule we adopted downstream
In kg-microbe-projects we bin BacDive growth temperatures to these terms. Our rule:
Evaluate bins in ascending order and take the first match.
which makes every bin after the first behave as lower-exclusive:
very low value <= 10
low 10 < value <= 22
mid1 22 < value <= 27
mid2 27 < value <= 30
mid3 30 < value <= 34
mid4 34 < value <= 40
high 40 < value
So a reading of exactly 10 is very low and exactly 22 is low — the lower bin wins. This is documented in our code and pinned by boundary tests at 10, 22, 30, 34 and 40. We are not proposing it as the right semantics, only stating what we do so our terms are interpretable; any consumer choosing "upper bin wins" would produce different terms from the same data.
Suggested fix
Make the intervals half-open in the ontology, so the partition is genuine and no tie-break is needed:
very low maxExclusive 10
low minInclusive 10 maxExclusive 22
mid1 minInclusive 22 maxExclusive 27
...
high minInclusive 40
That is the usual convention for binned ranges and would make boundary values unambiguous without changing which bin any non-boundary value falls into. Note it assigns boundary values to the upper bin, the opposite of our current downstream rule — we would rather follow the ontology than keep our own convention, so we would change to match.
If the current inclusive-both-ends encoding is deliberate (e.g. the bins are meant as overlapping guidance rather than a partition), it would help to say so in the class definitions, since the labels strongly imply a partition.
Reproducing
The overlap set above was extracted by walking owl:Restriction elements in metpo.owl and comparing each series' consecutive minInclusive / maxInclusive facets. Happy to contribute the extraction script or a PR applying the half-open bounds if that is useful.
In METPO's binned quantitative classes, consecutive bins share their boundary value: the lower bin declares
maxInclusive Nand the next declaresminInclusive N. A measurement of exactlyNtherefore satisfies both class definitions.Observed in
metpo.owl, versionIRIhttps://w3id.org/metpo/releases/2026-06-12/metpo.owl.Scope: this is systematic, not isolated
Every binned series is affected — 41 overlapping boundaries across 10 series:
Concretely, for temperature optimum:
10 satisfies both
1000441and1000442; 22 satisfies both1000442and1000443; and so on. The same shape appears in GC (<=42.65/>=42.65), NaCl (<=1/>=1) and pH (<=6/>=6).Why it matters
These classes read as a partition — "very low / low / mid1 / … / high" — but they are not disjoint. Consequences:
owl:disjointWith, that becomes an inconsistency rather than a modelling wrinkle.The rule we adopted downstream
In
kg-microbe-projectswe bin BacDive growth temperatures to these terms. Our rule:which makes every bin after the first behave as lower-exclusive:
So a reading of exactly 10 is
very lowand exactly 22 islow— the lower bin wins. This is documented in our code and pinned by boundary tests at 10, 22, 30, 34 and 40. We are not proposing it as the right semantics, only stating what we do so our terms are interpretable; any consumer choosing "upper bin wins" would produce different terms from the same data.Suggested fix
Make the intervals half-open in the ontology, so the partition is genuine and no tie-break is needed:
That is the usual convention for binned ranges and would make boundary values unambiguous without changing which bin any non-boundary value falls into. Note it assigns boundary values to the upper bin, the opposite of our current downstream rule — we would rather follow the ontology than keep our own convention, so we would change to match.
If the current inclusive-both-ends encoding is deliberate (e.g. the bins are meant as overlapping guidance rather than a partition), it would help to say so in the class definitions, since the labels strongly imply a partition.
Reproducing
The overlap set above was extracted by walking
owl:Restrictionelements inmetpo.owland comparing each series' consecutiveminInclusive/maxInclusivefacets. Happy to contribute the extraction script or a PR applying the half-open bounds if that is useful.