fix(node): refuse adding or removing a number pool range through the pool

Merged
PO
2d ago
+709-21

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() and remove() on the ranges relationship did not change the pool: the first two dropped the range without an error, and remove() 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 ranges as 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 pointBeforeAfter
Any node or field other than the ranges of a number poolworkedunchanged
pool.ranges.add(), .extend(), .remove()dropped the range, or sent references Infrahub refusedraise FeatureNotSupportedError, naming the ways out
pool.start_range and pool.end_rangeworked, deprecated in Infrahub 1.12unchanged
object create CoreNumberPool --set ranges='[{"start": 1, "end": 10}]'workedunchanged
object create CoreNumberPool --set ranges=range-1sent a reference Infrahub refusedrefused, naming the fields it takes
object update CoreNumberPool --set ranges=...applied nothing, without an errorrefused, naming the create that upserts the pool
object create --file, object update --file, object loadfailed: the pool was created without its ranges, then each range on its own, which Infrahub refused as overlappingthe 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() and infrahubctl load of 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