feat(scaleway): a server gives up a private interface, and the pin moves to 2.83.0 - #780
Merged
stephrobert merged 1 commit intoSep 14, 2026
Conversation
…ves to 2.83.0
Provider 2.83.0 was published at 15:06 on 2026-09-14, three hours after 2.82.0's
pin landed, and every `terraform destroy` against this emulator broke:
501 Not Implemented: feint does not serve
/instance/v2alpha1/zones/fr-par-1/servers/{id}/detach-private-network-interface
`fix(instance): detach private network interface before deleting it` (upstream
#4354) sends a call this pack declined. The drift machinery behaved the way it
is built to: the failure named the missing path instead of answering something
wrong.
THE REASON THAT EXPIRED, AND THE HALF THAT KEEPS IT
The refusal read "no client this project drives reaches for these operations —
a claim that held for the whole API until provider 2.81.0 moved private network
interfaces and placement groups onto it". A sentence that already carried one
expiry date has collected a second.
Only the detach leaves the list. `feint proxy` recorded a full apply plus
destroy: 35 v2alpha1 calls, the detach twice, and
AttachServerPrivateNetworkInterface **never**. Serving a half because its other
half is served would be surface nothing drives, so the reason is split rather
than deleted.
IT DISSOCIATES RATHER THAN DELETES, AND THAT IS MEASURED
The first implementation reused releaseNIC and deleted. Every suite stayed
green. The recording shows why that was luck:
200 POST …/detach-private-network-interface
200 GET …/private-network-interfaces/{id} <- still there
204 DELETE …/private-network-interfaces/{id} <- the client deletes it
404 GET …/private-network-interfaces/{id}
which is the upstream fix's own name spelled out as two calls. Deleting at the
detach answered the client's read with a 404, so it never sent its DELETE. Both
behaviours pass the suite; one matches what the client does. The SDK said the
same without any measurement: DetachAndDeletePrivateNetworkInterface exists
separately, which is only meaningful if the plain one leaves the interface
standing.
THREE VOCABULARIES THAT ARE NOT instance/v1's
Serving it needed the server rendered in v2alpha1's shape, which this pack did
not have — nineteen fields, taken from contracts/scaleway.json rather than from
memory. The contract check caught every divergence, and each is the same class:
server status v1 `running` v2alpha1 `started`
interface status `available`, never a server's word
volume type v1 `sbs_volume` v2alpha1 `sbs`
`b_ssd` and `unified` have no v2alpha1 spelling and answer
`unknown_volume_type`, the enum's own escape hatch, rather than a guessed
equivalence onto `sbs`: the products look alike and no measurement says they
are the same, which is exactly the invented format rule 4 forbids.
WHAT FALSIFY FOUND IN THIS WORK
Three tests were green for a reason that was not theirs:
- the empty-identifier test asserted "not 200", so it could not tell a
400 `invalid_arguments` from a 404, and an empty id resolves to nothing
anyway. The guard was redundant; the test was weak.
- the field test asserted PRESENCE, never whether a value belongs to its enum.
Both vocabulary defects passed under it.
- the enum test stayed green under the mutation that spoils the public
interface, because the server had no public address: `public_network_interface`
was null and the assertion never ran. The population trap, met in my own test.
Eight mutations bite now, including one that restores the delete-at-detach.
AND A GUARD I DISARMED WITHOUT NOTICING
Editing the decline reason moved a fragment that tools/falsify/specs/artefact-reasons.json
mutates, so a guard about artefacts printing stale reasons had quietly stopped
being measured. `falsify:lint` caught it; the fragment is retargeted on the
sentence as it stands today, and its three mutations bite again.
PROVEN
- conformance:leg -- terraform, scw-cli and **fields**: green. `fields` is the
only leg where the omission gate judges, and it judged the nineteen fields.
- conformance:stacks, conformance:quickstart: green.
- conformance:functional under incus-ovn, **three passes**, Scaleway and
Outscale, no divergence between them: machines really running on the host,
public paths, firewall in both directions, cross-VPC isolation, reboots,
stop/start cycles, rule sets, teardown. Incus identical before and after.
- The seven falsify specs the testplan named, plus the new one.
- evidence.json records the operation as driven, with `contract: clean`.
Assisted-by: Claude Code (claude-opus-5)
stephrobert
deleted the
fix/scaleway-serves-detach-private-network-interface
branch
September 14, 2026 19:26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Provider 2.83.0 was published at 15:06 on 2026-09-14, three hours after 2.82.0's
pin landed, and every
terraform destroyagainst this emulator broke:fix(instance): detach private network interface before deleting it(upstream#4354) sends a call this pack declined. The drift machinery behaved the way it
is built to: the failure named the missing path instead of answering something
wrong.
THE REASON THAT EXPIRED, AND THE HALF THAT KEEPS IT
The refusal read "no client this project drives reaches for these operations —
a claim that held for the whole API until provider 2.81.0 moved private network
interfaces and placement groups onto it". A sentence that already carried one
expiry date has collected a second.
Only the detach leaves the list.
feint proxyrecorded a full apply plusdestroy: 35 v2alpha1 calls, the detach twice, and
AttachServerPrivateNetworkInterface never. Serving a half because its other
half is served would be surface nothing drives, so the reason is split rather
than deleted.
IT DISSOCIATES RATHER THAN DELETES, AND THAT IS MEASURED
The first implementation reused releaseNIC and deleted. Every suite stayed
green. The recording shows why that was luck:
which is the upstream fix's own name spelled out as two calls. Deleting at the
detach answered the client's read with a 404, so it never sent its DELETE. Both
behaviours pass the suite; one matches what the client does. The SDK said the
same without any measurement: DetachAndDeletePrivateNetworkInterface exists
separately, which is only meaningful if the plain one leaves the interface
standing.
THREE VOCABULARIES THAT ARE NOT instance/v1's
Serving it needed the server rendered in v2alpha1's shape, which this pack did
not have — nineteen fields, taken from contracts/scaleway.json rather than from
memory. The contract check caught every divergence, and each is the same class:
b_ssdandunifiedhave no v2alpha1 spelling and answerunknown_volume_type, the enum's own escape hatch, rather than a guessedequivalence onto
sbs: the products look alike and no measurement says theyare the same, which is exactly the invented format rule 4 forbids.
WHAT FALSIFY FOUND IN THIS WORK
Three tests were green for a reason that was not theirs:
400
invalid_argumentsfrom a 404, and an empty id resolves to nothinganyway. The guard was redundant; the test was weak.
Both vocabulary defects passed under it.
interface, because the server had no public address:
public_network_interfacewas null and the assertion never ran. The population trap, met in my own test.
Eight mutations bite now, including one that restores the delete-at-detach.
AND A GUARD I DISARMED WITHOUT NOTICING
Editing the decline reason moved a fragment that tools/falsify/specs/artefact-reasons.json
mutates, so a guard about artefacts printing stale reasons had quietly stopped
being measured.
falsify:lintcaught it; the fragment is retargeted on thesentence as it stands today, and its three mutations bite again.
PROVEN
fieldsis theonly leg where the omission gate judges, and it judged the nineteen fields.
Outscale, no divergence between them: machines really running on the host,
public paths, firewall in both directions, cross-VPC isolation, reboots,
stop/start cycles, rule sets, teardown. Incus identical before and after.
contract: clean.Assisted-by: Claude Code (claude-opus-5)
🤖 Generated with Claude Code