fix(schema): let a reloaded number pool declaration remove every range

Merged
PO
3d ago
+284-20

Why

A team that reloads a schema to remove every range of a NumberPool attribute declares ranges: []. That reload was accepted with schema_updated: false and the pool kept its ranges. The spec allows a declaration with zero ranges (FR-022), and a load that drops to zero ranges while objects hold values must be refused with those objects named.

Jira: IFC-3412

What changed

  • An explicit ranges: [], with no start_range / end_range, replaces the stored ranges or shorthand with zero ranges. The load is refused while an object holds a number, and the pool ends with zero ranges otherwise.
  • A reload that leaves the ranges out keeps them, like every other omitted parameter: omitted parameters, parameters: {}, and parameters that set no range key (for example only allocation_scope).
  • The SDK schema generator (tasks/backend.py) declares ranges as unset by default in the write model only, so a declaration without ranges no longer dumps as ranges: []. schema/openapi.json and the frontend REST types are regenerated.
  • An explicitly empty range list stays in the parameters dump, so a load merged from several files keeps it.

Depends on

The python_sdk pointer targets opsmill/infrahub-sdk-python#1424 (regenerated write model). That pull request must merge first; the pointer then moves to its merge commit.

How to review

The branch has four commits, in reading order:

  1. fix(sdk): the write-variant ranges field in tasks/backend.py.
  2. chore: the regenerated SDK write model (submodule pointer), schema/openapi.json and REST types. Skim it.
  3. fix(schema): backend/infrahub/core/schema/attribute_parameters.py (declares_zero_ranges, the serializer and update()).
  4. test(schema): the unit tests.

Tests

  • Unit, test_schema_update_validation.py: reload cases for omitted parameters, parameters: {}, parameters without a range key and an explicit ranges: [], against stored ranges and against a stored shorthand; two of them again in a load of several files, which merges the files through a dump and a parse.
  • Unit, test_number_pool_parameters.py: ranges: [] removes the ranges or the shorthand; the dump keeps only the declared range fields; a zero-range declaration survives a dump and a parse.
  • The zero-range pool emptying by the synchronizer is covered by the existing component test test_declaration_without_range_empties_the_pool.
  • Backend unit suite 4359 passed; frontend unit tests 2647 passed; /pre-ci passed.

Tests against the live application

16 checks passed on a local stack running this branch and the SDK branch of opsmill/infrahub-sdk-python#1424, through the REST API, the Python SDK and infrahubctl:

  • Pool declared with two ranges. Reloaded with parameters: {}, with parameters omitted, and with parameters: {} in a load of two files: accepted, schema_updated: false, the pool keeps both ranges.
  • With an object holding a number, a reload with ranges: [] is refused with HTTP 422 naming the object and its number, in a single file and in a load of two files. The pool keeps its ranges.
  • After the object is deleted, ranges: [] in a load of two files is accepted: the declaration and the pool end with zero ranges. Declaring a range again afterwards gives the pool that range.
  • Pool scoped by role with one range, reloaded with only allocation_scope: ["role"]: accepted, the range is kept.
  • GET /api/schema still returns the declared ranges.
  • Python SDK, client.schema.load with dicts: parameters: {} keeps the ranges, ranges: [] removes them.
  • Python SDK, schema built with the SDK models and to_schema_dict(): without ranges, the dump has no ranges key and the load keeps the ranges; with ranges=[], the dump carries ranges: [] and the load removes them.
  • infrahubctl schema load on a directory of two YAML files: parameters: {} keeps the ranges, ranges: [] removes them.

๐Ÿค– Generated with Claude Code