ADR-003. A managing module reads before it writes
Status: accepted, 3 September 2026. Still in force.
Context
Scaleway’s update operations are PUT, not PATCH. The contract says so
plainly on the Load Balancer’s write operations:
Note that the request type is PUT and not PATCH. You must set all parameters.
Taken literally by a module, that sentence produces two defects at once. A user
who sets one field silently clears every field they did not mention. And a
module that sends its PUT on every run reports changed=true forever, which
makes changed a polite lie and makes the module useless in a handler.
Decision
A managing module reads the resource, normalises it, compares it with what the user asked for, and writes only if there is a difference. The fields the user did not give are filled from what was read.
Normalisation happens before comparison: enums, lists, None, ordering, nested
structures. Two representations of the same state must compare equal, or the
module writes on every run for a reason no user can see.
In check mode, it compares and reports without writing. The --diff output
shows both sides through the same reader, and secret parameters are masked on
both sides, and a mask on one side only turns every run into a spurious difference.
Because the module behaves this way, the contract’s sentence is true of the API and false of the module. Publishing it alongside the generator’s own sentence would publish a contradiction, so the generator strips it.
Consequences
A managing module costs one extra read per run. That is the price of an
idempotent module, and it is not negotiable: a module that always writes is not
idempotent whatever changed displays.
Some operations cannot be handled this way, and they are refused explicitly
rather than approximated: complete replacements of a sub-collection or a
sub-object, such as UpdatePlacementGroupServers, UpdateHealthCheck and
SetAcls. ADR-002 excludes them anyway.
What this record does not decide
How the module proves it behaved this way. A second run returning
changed=false is the proof, and it runs against the emulator,
ADR-006.