Skip to content

Fix issues with bounds - #269

Open
llucax wants to merge 3 commits into
frequenz-floss:v0.x.xfrom
llucax:bounds-fixes
Open

Fix issues with bounds#269
llucax wants to merge 3 commits into
frequenz-floss:v0.x.xfrom
llucax:bounds-fixes

Conversation

@llucax

@llucax llucax commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

This PR fixes a few issues found in the review of the PRs introducing bounds.

llucax added 3 commits August 14, 2026 21:19
`Bounds.__post_init__` only checked `lower > upper`, but every
comparison against `NaN` is `False`, so `Bounds(lower=float("nan"),
upper=10.0)` — and any other `NaN` endpoint — was accepted as a
well-formed bound. That let malformed wire data through as a valid
`Bounds`, bypassing the new invalid-bounds type and the semantic
accessor checks, even though a `NaN` endpoint can never satisfy the
range invariant.

Reject `NaN` in either present endpoint before the ordering check.
Because `bounds_from_proto2` catches the `ValueError` and falls back to
`InvalidBounds`, a `NaN` bound now flows through to `InvalidBounds` /
`InvalidBoundsSet` at every layer (bounds, metric samples, electrical
component config bounds) instead of masquerading as valid.

`InvalidBounds` intentionally still accepts `NaN`: its whole purpose is to
preserve malformed wire data verbatim for inspection.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
`math.isnan()` converts its argument to a `float`, so calling it on an
`int` too large to fit in a `float` (a legitimate `FloatInt` endpoint or
membership value) raised `OverflowError`:

    10**1000 in Bounds()     # OverflowError
    10**1000 in BoundsSet()  # OverflowError
    Bounds(lower=10**1000)   # OverflowError

Only a `float` can be `NaN`, so guard every `math.isnan()` call with an
`isinstance(x, float)` check. This covers membership on `Bounds` and
`BoundsSet` and the endpoint validation in `Bounds.__post_init__`, so
large integers now compare and sort as ordinary finite values.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
A `-inf` lower bound and a `+inf` upper bound denote the unbounded
direction, which the library already represents with `None`. Keeping the
infinite form gave the same interval two spellings, so equality, hashing
and `is_bounded()` disagreed for sets that already cover the whole space:

    Bounds(lower=-math.inf, upper=math.inf) == Bounds()      # was False
    bool(BoundsSet(bounds=(Bounds(-math.inf, math.inf),)))   # was True

Canonicalize a `-inf` lower and a `+inf` upper to `None` in
`Bounds.__post_init__`, so an all-covering bound collapses to the empty,
falsy unbounded set as documented. A wrong-side infinity (`+inf` lower or
`-inf` upper) is not the unbounded direction, so it is kept as a real
endpoint and a contradictory pair still raises. The check uses `==`
rather than `math.isinf()` to stay overflow-safe on large `int`
endpoints.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
@llucax
llucax requested a review from a team as a code owner August 14, 2026 19:21
@llucax
llucax requested review from ela-kotulska-frequenz, shsms and tiyash-basu-frequenz and removed request for a team August 14, 2026 19:21
@github-actions github-actions Bot added part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests part:metrics Affects the metrics protobuf definitions labels Aug 14, 2026
@llucax
llucax enabled auto-merge August 14, 2026 19:24
@llucax llucax self-assigned this Aug 14, 2026
@llucax llucax added this to the v0.4.1 milestone Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

part:docs Affects the documentation part:metrics Affects the metrics protobuf definitions part:tests Affects the unit, integration and performance (benchmarks) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant