fix(node): refuse adding or removing a number pool range through the pool
Problem
The ranges of a CoreNumberPool are bounds in its mutation input, not references to range nodes. Three paths did not account for that:
add(),extend()andremove()on therangesrelationship did not change the pool: the first two dropped the range without an error, andremove()sent the remaining ranges as references, which Infrahub refused.infrahubctl object update --set ranges=...lost the edit in silence.- Loading an object file that declares
rangesas objects failed. The loader created the pool without its ranges, so Infrahub gave it the default range, then created each declared range as a node of its own, which Infrahub refused as overlapping: the default range on a new pool, or the range it already held on an existing one. Reported by Wim.
Close IFC-3543
What each entry point does
Nothing that produced the intended result is taken away. What was silent becomes explicit, and the object file starts working.
| Entry point | Before | After |
|---|---|---|
| Any node or field other than the ranges of a number pool | worked | unchanged |
pool.ranges.add(), .extend(), .remove() | dropped the range, or sent references Infrahub refused | raise FeatureNotSupportedError, naming the ways out |
pool.start_range and pool.end_range | worked, deprecated in Infrahub 1.12 | unchanged |
object create CoreNumberPool --set ranges='[{"start": 1, "end": 10}]' | worked | unchanged |
object create CoreNumberPool --set ranges=range-1 | sent a reference Infrahub refused | refused, naming the fields it takes |
object update CoreNumberPool --set ranges=... | applied nothing, without an error | refused, naming the create that upserts the pool |
object create --file, object update --file, object load | failed: the pool was created without its ranges, then each range on its own, which Infrahub refused as overlapping | the ranges travel with the pool |
An object file sets the ranges, on a new pool and on one that already exists:
ranges:
data:
- start: 64512
end: 65534
The rule is keyed on the (name, peer) pair, so another relationship to CoreNumberPoolRange keeps references, add() and remove().
Not covered
pool.ranges.peers: editing the list is not supported and the SDK does not report it.add_relationships(),remove_relationships()andinfrahubctl loadof an export reach Infrahub through other paths and bypass the refusal.
The table of relationships is a stopgap. The lasting fix belongs in Infrahub: a schema that states the mutation takes the peer's fields, or a mutation that accepts references like every other relationship.
Tests
Unit tests cover each refused method for both clients, both CLI guards, and the object file in each form it accepts. The object-file failure lands red in its own commit before the fix.
Run against a live Infrahub 1.12.0.post1, with testcontainers:
uv run pytest tests/integration/test_number_pool_attach_ranges.py 8 passed in 2:08
What that covers: the ranges a create and an upsert declare, the way out the refusal names, a range node added, changed and deleted on its own, an object file loaded twice against the same pool, and attaching and detaching numbers.
š¤ Generated with Claude Code