Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CHANGELOG.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,38 @@ change ni l'un ni l'autre a sa place dans `git log`.

### Ajouté

- **La route propre à la passerelle d'API : `scw/Client.GetAPIMetadata`**
(#776). `GET /metadata` répond `{"platform", "partition", "domain"}`, que le
SDK lit pour construire côté client un `srn://<service>.<domain>/…` pour chaque
produit qui en a reçu un.

Mesuré le 2026-09-14 avec `feint proxy --record` : un `apply` puis un
`destroy` de la fixture de conformance en ont envoyé **148, et cet émulateur a
répondu 404 à chacun**, soit 148 des 169 refus de cette exécution. Rien
n'échouait, parce que le SDK jette l'erreur et que le SRN reste vide. C'est de
la chance, pas une décision, et c'est exactement la forme de #257.

**L'instrument devait bouger avant le gestionnaire.** `Route.Operation` doit
nommer une opération que le scan de dérive trouve, et ce scan ne lisait que
`api/<produit>/<version>`, où `Client.GetAPIMetadata` ne se trouve pas : la
route serait devenue orpheline, alors que les trois baselines en portent zéro.
Le scan lit désormais le paquet de la passerelle, avec un critère propre : une
méthode qui **construit** une requête, et non une qui transporte celle d'un
autre. Réutiliser le filtre des produits était faux dans les deux sens, et
c'est mesuré : il trouvait `Client.Do`, le transport que toute requête
traverse, et `Config.String`, un formateur, et manquait la seule opération qui
compte.

Le contrat la décrit aussi, par `--gateway`, la même échappatoire que la forme
de refus utilise déjà : Scaleway publie un document par produit et la
passerelle n'en est pas un. La réponse est donc **validée**, pas exemptée.

Les trois valeurs sont celles du vrai cloud, lues lors d'un tir en lecture
seule sur un compte fr-par et versées dans
`corpus/scaleway/scw-gateway.jsonl`. Un corpus commité est anonymisé : il note
le statut et l'arbre des champs, jamais les valeurs, que tiennent le fragment
de contrat et un test qui les écrit au lieu de les relire du gestionnaire.

- **Un serveur rend une interface privée : `instance/v2alpha1/API.DetachServerPrivateNetworkInterface`.**
`POST /instance/v2alpha1/zones/{zone}/servers/{id}/detach-private-network-interface`
dissocie une interface de son serveur et répond le serveur. Le provider
Expand Down
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,37 @@ what this project is judged on: **a response shape a client can observe**, and

### Added

- **The API gateway's own route: `scw/Client.GetAPIMetadata`** (#776).
`GET /metadata` answers `{"platform", "partition", "domain"}`, which the SDK
reads to build a `srn://<service>.<domain>/…` client-side for every product
that gained one.

Measured 2026-09-14 through `feint proxy --record`: one `apply` plus `destroy`
of the conformance fixture sent **148 of these and this emulator answered 404
to every one** — 148 of that run's 169 refusals. Nothing failed, because the
SDK discards the error and the SRN stays empty. That is luck rather than a
decision, and the shape of #257 exactly.

**The instrument had to move before the handler could.** `Route.Operation`
must name an operation the drift scan finds, and the scan walked
`api/<product>/<version>` only, where `Client.GetAPIMetadata` is not — so the
route would have been an orphan, and all three baselines carry zero. The scan
now reads the gateway package on a criterion of its own: a method that
**builds** a request rather than one that carries someone else's. Reusing the
product walk's matcher was measured wrong in both directions — it found
`Client.Do`, the transport every call goes through, and `Config.String`, a
formatter, and missed the one operation that matters.

The contract describes it too, through `--gateway`, the same escape the
refusal shape already uses: Scaleway publishes one document per product and
the gateway is not one. So the response is **validated** rather than exempted.

The three values are the real cloud's, read on a read-only shot at an fr-par
account and committed as `corpus/scaleway/scw-gateway.jsonl`. A committed
corpus is sanitised, so it grades the status and the field tree and not the
values; those are held by the contract fragment and by a test that writes them
out rather than reading them from the handler.

- **A server gives up a private interface: `instance/v2alpha1/API.DetachServerPrivateNetworkInterface`.**
`POST /instance/v2alpha1/zones/{zone}/servers/{id}/detach-private-network-interface`
dissociates an interface from its server and answers the server. Terraform
Expand Down
4 changes: 2 additions & 2 deletions README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
> [!IMPORTANT]
> **Ce qu'on peut pointer vers cet émulateur, et ce qu'on ne peut pas.**
>
> **Prouvé** : 377 des 398 opérations montées sont pilotées par un vrai client, à chaque pull request. `scw`, `octl`, `exo`, Terraform et OpenTofu tournent contre l'émulateur en CI, et les machines démarrent réellement : connexion ssh sur le compte par défaut de chaque provider, subnets isolés, pare-feu qui filtre. La chaîne complète est décrite dans [docs/conformance.md](docs/conformance.md).
> **Prouvé** : 378 des 399 opérations montées sont pilotées par un vrai client, à chaque pull request. `scw`, `octl`, `exo`, Terraform et OpenTofu tournent contre l'émulateur en CI, et les machines démarrent réellement : connexion ssh sur le compte par défaut de chaque provider, subnets isolés, pare-feu qui filtre. La chaîne complète est décrite dans [docs/conformance.md](docs/conformance.md).
>
> **Pas prouvé** : quotas, prix, capacité réelle, validation des identifiants, authentification, cohérence à terme. Les 57 sections de [docs/limits.md](docs/limits.md) disent chacune ce qu'elle coûte. Un émulateur avec un seul compte implicite et aucune grille tarifaire devrait inventer ces chiffres, et quelqu'un agirait dessus.
>
Expand Down Expand Up @@ -140,7 +140,7 @@ valider](docs/confidence.md) dit où cette affirmation s'arrête.
```bash
feint serve
# feint dev listening on 127.0.0.1:4599
# scaleway 194 routes
# scaleway 195 routes
# outscale 100 routes
# exoscale 104 routes
# machines none
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
> [!IMPORTANT]
> **What is safe to point at this emulator, and what is not.**
>
> **Proven**: 377 of the 398 mounted operations are driven by a real client, on every pull request: each pack's own official CLI, and an infrastructure engine wherever a pack admits one, all of them running against the emulator in CI, and machines really boot: an ssh login on each provider's own default account, isolated subnets, a firewall that filters. The whole chain is described in [docs/conformance.md](docs/conformance.md).
> **Proven**: 378 of the 399 mounted operations are driven by a real client, on every pull request: each pack's own official CLI, and an infrastructure engine wherever a pack admits one, all of them running against the emulator in CI, and machines really boot: an ssh login on each provider's own default account, isolated subnets, a firewall that filters. The whole chain is described in [docs/conformance.md](docs/conformance.md).
>
> **Not proven**: quotas, prices, real capacity, identifier validation, authentication, eventual consistency. The 57 sections of [docs/limits.md](docs/limits.md) each say what one costs. An emulator with a single implicit account and no price list would have to invent those figures, and somebody would act on them.
>
Expand Down Expand Up @@ -129,7 +129,7 @@ that claim stops.
```bash
feint serve
# feint dev listening on 127.0.0.1:4599
# scaleway 194 routes
# scaleway 195 routes
# outscale 100 routes
# exoscale 104 routes
# machines none
Expand Down Expand Up @@ -856,13 +856,13 @@ same block is published in the body of every release.
<!-- coverage:start -->
<!-- Generated by `mise run docs:coverage`. Do not edit by hand. -->

398 routes are mounted across the three packs. The tables count *upstream operations*
399 routes are mounted across the three packs. The tables count *upstream operations*
rather than routes: what the provider's own SDK or API description declares, against
what this emulator serves, declines on purpose, or has not triaged yet.

#### Scaleway

194 routes mounted. Of the 536 operations upstream declares: 36% served,
195 routes mounted. Of the 537 operations upstream declares: 36% served,
63% declined on purpose, 0% untriaged.

| Group | Served | Declined | Untriaged | Upstream |
Expand All @@ -875,8 +875,8 @@ what this emulator serves, declines on purpose, or has not triaged yet.
| `vpc` | 19 | 18 | 0 | 37 |
| `block` | 22 | 5 | 0 | 27 |
| `account` | 5 | 7 | 0 | 12 |
| *… 2 smaller groups* | 10 | 8 | 0 | 18 |
| **Total** | **194** | **342** | **0** | **536** |
| *… 3 smaller groups* | 11 | 8 | 0 | 19 |
| **Total** | **195** | **342** | **0** | **537** |

#### Exoscale

Expand Down
Loading
Loading