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
2 changes: 1 addition & 1 deletion README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
>
> **Prouvé** : 376 des 397 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 56 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.
> **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.
>
> **Inconnu** : 21 opérations sont montées et n'ont jamais été pilotées par un client. Chacune dit pourquoi aucun client officiel ne l'atteint, à la route et dans [docs/routes.md](docs/routes.md). Elles sont comptées plutôt qu'escamotées, une par une, dans [coverage/evidence.json](coverage/evidence.json).
>
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
>
> **Proven**: 376 of the 397 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 56 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.
> **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.
>
> **Unknown**: 21 operations are mounted and have never been driven by a client. Every one of them states why no official client reaches it, at the route and in [docs/routes.md](docs/routes.md). They are counted rather than glossed, one by one, in [coverage/evidence.json](coverage/evidence.json).
>
Expand Down Expand Up @@ -831,8 +831,8 @@ argument is that the upstream moves:
| Client | Version proven in CI | Emulated provider |
|---|---|---|
| `scw` | 2.56.3 | Scaleway |
| Terraform | 1.13.3 with providers `outscale/outscale ~> 1.7`, `scaleway/scaleway 2.81.0` | Exoscale, Outscale, Scaleway |
| OpenTofu | 1.12.5 with providers `outscale/outscale ~> 1.7`, `scaleway/scaleway 2.81.0` | Exoscale, Outscale, Scaleway |
| Terraform | 1.13.3 with providers `outscale/outscale ~> 1.7`, `scaleway/scaleway 2.82.0` | Exoscale, Outscale, Scaleway |
| OpenTofu | 1.12.5 with providers `outscale/outscale ~> 1.7`, `scaleway/scaleway 2.82.0` | Exoscale, Outscale, Scaleway |
| `octl` | 0.0.32 | Outscale |
| `exo` | 1.95.6 | Exoscale |

Expand Down
6 changes: 3 additions & 3 deletions docs/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ Each row is one `required_providers` entry, read where it is written.
| `tools/conformance/faults` | `outscale/outscale` | `~> 1.7` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `tools/conformance/outscale/terraform` | `outscale/outscale` | `~> 1.7` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `tools/conformance/outscale/terraform-doorway` | `outscale/outscale` | `~> 1.7` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `tools/conformance/scaleway/terraform` | `scaleway/scaleway` | `2.81.0` | exact: the version that answered | yes |
| `tools/conformance/scaleway/terraform` | `scaleway/scaleway` | `2.82.0` | exact: the version that answered | yes |
| `examples/stacks/exoscale` | `exoscale/exoscale` | `>= 0.71.0` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `examples/stacks/outscale` | `outscale/outscale` | `~> 1.7` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `examples/stacks/outscale/modules/net` | `outscale/outscale` | `~> 1.7` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `examples/stacks/scaleway` | `scaleway/scaleway` | `2.81.0` | exact: the version that answered | yes |
| `examples/stacks/scaleway` | `scaleway/scaleway` | `2.82.0` | exact: the version that answered | yes |
| `examples/quickstart/outscale` | `outscale/outscale` | `~> 1.7` | constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
| `examples/quickstart/scaleway` | `scaleway/scaleway` | `2.81.0` | exact: the version that answered | yes |
| `examples/quickstart/scaleway` | `scaleway/scaleway` | `2.82.0` | exact: the version that answered | yes |

Read the third column narrowly, because it is the one a consumer pins against.
An **exact** constraint names the version that answered. A **constraint** is
Expand Down
1 change: 1 addition & 0 deletions docs/limits-acks.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"The cost of DNS/TLS interception, measured (#76)": "2026-08-27",
"The firewall enforces, within stated bounds": "2026-08-28",
"The guest's DHCP client is not how a published address reaches a machine (#587)": "2026-08-29",
"The Scaleway gateway serves `GET /metadata` and this emulator does not (#776)": "2026-09-14",
"The per-parameter half: 18 Scaleway list operations, 72 parameters, each served or refused (#277)": "2026-08-29",
"The station reaches an OVN private address only via the network's router, and the posted uplink routes do not go there (#496)": "2026-08-27",
"The three packs hand their security groups to the runtime, within two measured bounds": "2026-08-28",
Expand Down
37 changes: 37 additions & 0 deletions docs/limits.md
Original file line number Diff line number Diff line change
Expand Up @@ -3252,6 +3252,43 @@ choice rather than an accident:
publishes none, and listing the private groups under a public label would be
the same lie #271 names, pointed the other way.

## The Scaleway gateway serves `GET /metadata` and this emulator does not (#776)

The Scaleway SDK that provider **2.82.0** embeds asks the gateway for its
metadata, and uses the domain it answers to compute a `srn://…` client-side for
every product that gained one. This emulator mounts no such route.

Measured 2026-09-14, one `apply` plus `destroy` of the conformance fixture
through `feint proxy --record`: **539 exchanges over 100 paths, of which 148 are
`GET /metadata` and every one is answered 404** — 148 of the run's 169 refusals.

Nothing fails, and that is luck rather than a decision. `scw/client.go` reads the
metadata and its callers discard the error:

```go
apiMetadata, err := s.client.GetAPIMetadata()
if err == nil {
resp.setSRN(apiMetadata.Domain)
}
```

So the SRN stays empty and the apply completes. A caller that stops ignoring it
turns this into a failure with no change on this side, which is the shape of
#257 exactly.

What the real cloud answers is known rather than guessed — a read-only shot
against a real `fr-par` account the same day, no resource created:

```
GET https://api.scaleway.com/metadata -> 200
{"platform": "external", "partition": "scw", "domain": "scw.eu"}
```

It is not mounted yet because `Route.Operation` must name an operation the drift
scan finds, and that scan walks `api/<product>/<version>` only, where
`GetAPIMetadata` is not. A route declaring it becomes an orphan, and all three
baselines carry zero. The instrument gets decided before the handler: #776.

## The per-parameter half: 18 Scaleway list operations, 72 parameters, each served or refused (#277)

#271's gate catches a handler that never reads its query at all. Its comment
Expand Down
2 changes: 1 addition & 1 deletion examples/quickstart/scaleway/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ terraform {
# apply proves the emulator answered whatever was newest that morning and
# nothing anybody can replay. `feint docs --check` refuses an applied
# example that pins nothing.
version = "2.81.0"
version = "2.82.0"
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions examples/stacks/scaleway/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ terraform {
source = "scaleway/scaleway"
# Exact for the same reason the conformance fixture is exact: a floating
# constraint turned CI red the hour 2.81.0 was published, with no change
# on this side (#257). 2.81.0 is the pin rather than the 2.80.0 that made
# on this side (#257). 2.81.0 was the pin rather than the 2.80.0 that made
# it green again — #260 serves the /instance/v2alpha1 routes that release
# reads private NICs through, and a stack pinned below them would stop
# exercising what the emulator now claims to serve.
version = "2.81.0"
#
# Moved to 2.82.0 on 2026-09-14, with the conformance fixture, and the
# move is measured rather than assumed: that release adds an `srn`
# attribute to six products, three of them served here.
version = "2.82.0"
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion internal/cli/docs_proved_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,12 @@ func rowContaining(t *testing.T, rendered, key string) string {
func TestTheProvedPageSeparatesAnExactPinFromAConstraintAndFromNothing(t *testing.T) {
rendered := provedPage(t)

// The number is written here rather than read from the fixture, on purpose:
// read from it, this would compare the page against its own source and pass
// whatever the pin became. Written here, moving the pin costs one line and
// somebody has to look at this test while doing it.
exact := rowContaining(t, rendered, "tools/conformance/scaleway/terraform`")
if !strings.Contains(exact, "2.81.0") || !strings.Contains(exact, "exact") {
if !strings.Contains(exact, "2.82.0") || !strings.Contains(exact, "exact") {
t.Errorf("the Scaleway fixture pins one version and the page does not say so:\n %s", exact)
}

Expand Down
9 changes: 8 additions & 1 deletion tools/conformance/scaleway/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ terraform {
# the machine that regenerated the artefact and false on the runner. An
# artefact claiming "a real client proved this" has to mean the client CI
# actually runs.
version = "2.81.0"
#
# Moved to 2.82.0 on 2026-09-14, and the move is the proof rather than the
# claim: the release adds an `srn` attribute to six products, three of
# which this emulator serves (iam, vpcgw, ipam/flexibleip), plus
# `fix(instance): infer project_id from server if not explicit`. Every one
# of those is a reason a newer provider could stop driving this fixture,
# which is exactly why the pin is exact and why it moves deliberately.
version = "2.82.0"
}
}
}
Expand Down
Loading