Skip to content

feat(conformance, ci): the example stacks are applied every night, and the gate that does it names its runtime and its budget (#504) - #582

Merged
stephrobert merged 2 commits into
mainfrom
feat/504-the-stack-gate-runs-every-night
Aug 28, 2026
Merged

feat(conformance, ci): the example stacks are applied every night, and the gate that does it names its runtime and its budget (#504)#582
stephrobert merged 2 commits into
mainfrom
feat/504-the-stack-gate-runs-every-night

Conversation

@stephrobert

Copy link
Copy Markdown
Owner

Closes #504.

#520 is not closed here — it is disproved, measured, and recorded. See the
last section.

conformance:functional is the only gate that boots real machines and applies the
example stacks, and nothing in CI ran it. Yesterday it earned that sentence:
it is what surfaced the isolation-detach race, finding that cost three pull
requests
, and the defect was older than the entire range bisected.

Where the gate runs, and why not where it seemed obvious

A stacks job of its own, parallel to the two mode legs on
runtime-proof.yml, incus-ovn only. Not a step on the existing incus-ovn leg,
and both reasons are measurements:

  • that leg was red on four of the last seven scheduled nights, and a step
    queued behind a red is a gate that never runs — which is The only gate that boots real machines never plays the example stacks, where all four dataplane defects were found by hand #504's own complaint;
  • it would inherit that leg's host. Reproduced locally: the three ssh suites
    each exit 0 and each leave something standing (scw-* and exo-* rule
    sets no client call can delete, fnt-default, feint-uplink), and feint stop
    sweeps none of them;
  • three passes is half an hour, which would push a 45-minute job onto its own
    timeout, and a job that times out is a verdict nobody reads.

No job renamed, so .github/rulesets/main.json is untouched — this workflow
is schedule/dispatch only and none of its jobs is a required check. streak and
report now needs: [runtime, stacks], so a red stack gate cannot be
summarised or closed unseen
, and the header says out loud that #125's promotion
criterion is widened on purpose.

The setup steps are duplicated from the incus-ovn leg deliberately:
extracting them while that leg is red would make any new red ambiguous.
TestBothRuntimeJobsPinTheSameHost holds the two copies to the same pins.
actionlint, zizmor (--persona regular --min-severity low) and poutine clean. No
secret, no cross-repository token.

The budget: three passes, and the arithmetic that chose it

The class this gate hunts struck 9 times in 13 runs. So one pass calls it
absent 31 % of the time; three passes bring that to 3 %, against 9.6 % for
two. At 295 s a pass, measured, three are about fifteen minutes and fit a
75-minute job; five would double the cost for a factor of ten and sit on the
timeout.

Sequential on one host, so pass k+1's doorstep is pass k's closing verdict.

Proof the gate bites

A gate that has never refused anything is the thing this repository spends its
time removing. So: #475 planted (ApplyFirewall returns nil), rebuilt, one pass —
red in 69 s, naming stack, machine, address and port:

scaleway: a rule of platform-app-worker-a's group opens 8080 and
platform-web-0 does not reach 10.30.2.5:8080

Restored, rebuilt, green.

Two defects found inside the gate itself, both "a comment is not a control"

The closing doorstep was a comment. functional.sh ended with
guard_leftovers_for "$RUNTIME" "the end of the run" under a paragraph stating
the doorstep question was asked again on the way out. It was not:
guard_leftovers_for arms --doorstep on the literal word doorstep, so it
never asked what machines and networks were left standing. Fixed — and the test
reads the scope the file passes and then executes the guard with it.

The runtime resolution was #574's line, one directory over.
RUNTIME="${FEINT_FUNCTIONAL_RUNTIME:-incus-ovn}" silently overrode what the
caller asked for, exactly as evidence:update did before yesterday. Extracted to
tools/runtime-mode.sh and shared with evidence:update — whose unchanged
tests are what prove the move changed nothing.

Falsification

the-stack-gate-runs-somewhere.json8 of 8 bite.
evidence-leg-mode.json retargeted onto the moved file (falsify --lint caught
its four dead fragments) — 7 of 7 bite.

One mutation was dropped rather than kept: neutralising || exit 1 on the
resolver call does not bite, because the resolver still prints its refusal. It
was removed instead of being wrapped in a comment that would have lied about it.

#520 — out of the pilotable, and its stated cause disproved

Terraform is refused for that pack since #525, so the pack's own API was driven
instead: 100 back-to-back by-id reads of one balancer, 100 fresh
create-then-read pairs
, one elastic IP, 50 instance poolszero empty
names, addresses or sizes
.

There is no window: createLoadBalancer writes name and ip before the
operation that already says state: success. And the stack's third by-id door
read back fine in the same apply, so whatever produced the nulls discriminates
between the three doors and this pack does not.

Recorded in docs/limits.md with its acknowledgement re-dated. What would lift it
is upstream exoscale/terraform-provider-exoscale#573; no change to this pack
would.
The issue is left open for the maintainer to act on rather than closed
from here.

The nightly red of runtime-proof — the brief's attribution was wrong

Seven consecutive red scheduled nights, last green 2026-08-21, and four
distinct causes
, of which the witness doorstep is one:

night incus incus-ovn
08-22 … 08-25 Scaleway ssh suite Scaleway ssh suite
08-26 Scaleway ssh suite Outscale network suite
08-27 green dataplane witness gate (doorstep)
08-28 feint images (alpine CDN) same

The witness gate landed 2026-08-26 18:15, so 08-27 is the only night it has
ever been reached
. Not fixed here: the honest repair is #521's shape — ask the
doorstep after the stop, so the leak reddens the run that leaked — and that
needs the leaking suites fixed too. A bare feint clean there would hide a real
leak. The stacks job is immune by construction.

Gates

prepush green · docs:check green · falsify:lint 899 mutations over 145
specs · two spec replays 15/15 · actionlint, zizmor, poutine clean ·
FEINT_VM=incus-ovn mise run conformance:functional green 3/3, plus six
extra single-pass runs green · host clean at the end.

What was not obtained

Where testplan was wrong

It sent a change to tools/conformance/functional.sh to
conformance:leg -- fieldsa leg with no machine runtime, the one population
this gate refuses to run in
— and never named the gate itself. Fixed in the same
lot: rules.go now triages functional.sh, functionallib.sh and
runtime-mode.sh by name onto FEINT_VM=incus-ovn mise run conformance:functional,
each with what it still does not prove.

… no change to this pack would lift them (#520)

#520 records a real observation and a deduced cause, and the deduction was
wrong. The filing says so itself: "Deduced, not instrumented: ... that points
at the pack's by-id GET racing its own async create-completion, but nobody has
captured the raw exchange."

Instrumented on 2026-08-28, on the surface this repository has decided to
drive. Terraform is refused for this pack since #525, so the reads were driven
against the pack's own HTTP API, with --vm off because the question is the
document and not the runtime:

  GET /v2/load-balancer/{id} back to back, one balancer   100 reads,  0 empty
  create a balancer, read it by id with no delay          100 pairs,  0 empty
  create an elastic IP, read it by id with no delay         1 pair,   0 empty
  create an instance pool, read its size by id              50 pairs, 0 empty

There is no window to race. createLoadBalancer puts the resource with `name`
and `ip` in its attributes before it writes the operation, and that operation
already answers `state: success`: the async shape is in the envelope, never in
the document. The `exo` CLI reads the same balancer back with its name and
ip_address filled.

Two consequences, and the second is why this stays a limit rather than becoming
a fix. The stack has three by-id data sources and only two came back null; this
emulator serves all three from one store and answers all three completely, so
whatever produced the nulls tells them apart and this pack does not. What tells
them apart is on the client side, and it is the client #525 refuses: the
provider builds two clients and one does not honour EXOSCALE_API_ENDPOINT
(upstream #573), and `setEndpointFromContext` in egoscale/v2 does not rewrite a
literal address. That last sentence is a reading of the provider rather than a
measurement of it, and docs/limits.md says so: the fork is not checked out here.

The disproof is written where the next reader meets it, per the rule that a
finding is verified before it is fixed and a disproof is recorded so nobody
"fixes" it again. The changelog line for this lands with the rest of the lot.

Assisted-by: Claude Code (claude-opus-5)
… the gate that does it names its runtime and its budget (#504, #574)

`conformance:functional` is the only gate here that boots real machines and
applies `examples/stacks/`, and nothing in CI played it. No leg of
runtime-proof.yml applies a stack; `mise run conformance` skips the stack
suites without a runtime. It is what surfaced the isolation-detach race — an
ACL deleted while the daemon resolved it at `incus start`, machines dying
behind a green apply — a defect that cost three pull requests (#577, #578) and
was older than the whole range bisected.

WHERE IT RUNS, AND WHY THERE

A `stacks` job of its own on runtime-proof.yml, parallel to the two mode legs,
incus-ovn only. Three reasons, and the first two are measurements rather than
preferences:

  - a step on the incus-ovn leg queues behind six suites that were red on four
    of the last seven scheduled nights, and a step that is never reached is a
    gate that never runs, which is this issue's own complaint;
  - it would inherit that leg's host. Reproduced locally on 2026-08-28: the
    three ssh suites each exit 0 and each leave something standing — `scw-…`
    and `exo-…` rule sets no client call can delete, `fnt-default` and
    `feint-uplink` no resource owns — and `feint stop` sweeps none of them.
    That is why the witness gate failed at its own doorstep on the one night it
    has been reached since it landed. A job of its own starts clean;
  - three passes is half an hour, which would push a 45-minute job onto its own
    timeout, and a job that times out is a verdict nobody wrote.

No job renamed, so the required status checks in .github/rulesets/main.json are
untouched: this workflow is schedule and dispatch only, and none of its jobs is
a required check. `streak` and `report` now wait for `stacks`, so a night whose
stack gate went red is not summarised, or closed, before anybody looked at it.
The setup steps repeat the incus-ovn leg's deliberately — extracting them while
that leg is red would make any new red ambiguous between the gate and the
refactor — and TestBothRuntimeJobsPinTheSameHost holds the two copies to the
same pins.

THE FOUR THINGS THE DAY IMPOSED

1. The doorstep at both ends, and this one was a comment. The gate closed with

       guard_leftovers_for "$RUNTIME" "the end of the run"

   under a paragraph saying the doorstep question was asked again on the way
   out. `guard_leftovers_for` arms `--doorstep` on the literal `doorstep`
   alone, so the closing call asked about DHCP orphans and trapped objects and
   never once asked what machines and networks were left standing. A green run
   that leaked a network exited 0 and the next run met the refusal: the state
   #521 removed from `mise run conformance`, described here and never done.
   TestTheStackGateEndsOnItsOwnDoorstep reads the scope the file passes and
   then executes the guard with it, so it measures the effect, not the spelling.

2. The mode announced with its provenance. The gate opened with
   `RUNTIME="${FEINT_FUNCTIONAL_RUNTIME:-incus-ovn}"` — #574's line one
   directory over — so an exported FEINT_VM was ignored without a word. Worse
   here than there: the one assertion the two modes disagree about, isolation
   between two VPCs, is this gate's own subject. The resolution moved to
   tools/runtime-mode.sh and both callers pass what differs (subject, knob,
   default, what `off` would cost). tools/evidence/mode_test.go did not move,
   deliberately: those tests were written against the behaviour, so they are
   what proves the extraction changed none of it.

3. A red that names the stack and the machine, unchanged and proved rather than
   assumed. Planted #475's defect (ApplyFirewall hands nothing to the runtime),
   the gate went red in 69 s on
   "scaleway: a rule of platform-app-worker-a's group opens 8080 and
   platform-web-0 does not reach 10.30.2.5:8080".

4. The intermittency budget: three passes, sequential on one host. The class
   struck 9 times in 13 runs, so one pass calls it absent 31% of the time;
   three passes make that 3%, against 9.6% for two. Five would buy another
   factor of ten for the same time again and put the CI job on its timeout.
   At 295 s a pass, three are ~15 min locally. Sequential rather than parallel
   because pass k+1's doorstep is pass k's closing verdict. The count is
   announced with its provenance like the mode, and lowering it says what it
   gives up.

MEASURED

  mise run prepush                                     green
  mise run docs:check                                  green
  falsify the-stack-gate-runs-somewhere.json           8/8 mutations bit
  falsify evidence-leg-mode.json (retargeted)          7/7 mutations bit
  the gate bites                                       #475 planted in
      ApplyFirewall, red in 69 s: "scaleway: a rule of platform-app-worker-a's
      group opens 8080 and platform-web-0 does not reach 10.30.2.5:8080"
  FEINT_VM=incus-ovn mise run conformance:functional   run 1: passes 1 and 2
      green, pass 3 RED, 665 s; run 2, on an idle station: green, 884 s

THE ONE RED, WRITTEN DOWN RATHER THAN RE-RUN AWAY

Pass 3 of the first three-pass run went red on the Scaleway firewall pair, with
the same verdict shape the planted defect produced:

    FAIL: scaleway: a rule of platform-app-worker-a's group opens 8080 and
          platform-web-0 does not reach 10.30.2.4:8080 — the group describes a
          port the host does not open

Passes 1 and 2 were green on that same assertion, same binary, same host. This
lot changes no emulator code — the diff is a workflow, a shell gate, tests, a
resolver and a testplan rule — so whatever it is, it is on main.

Measured after it: 6 green and 0 red out of 6 further single-pass runs
of the Scaleway stack, back to back on an otherwise idle station, plus the
second three-pass run above. The failing pass ran while this station was also
compiling and running `go test`; that perturbation is a candidate this
measurement does not separate from the emulator, and it is written down rather
than dismissed.

So it is seen once and not reproduced, and it is not attributed here. What it
does establish is the point of the budget rather than a defect: a one-pass gate
would have reported green on the very run that contained it.

Assisted-by: Claude Code (claude-opus-5)
@stephrobert
stephrobert merged commit 8bb7266 into main Aug 28, 2026
30 checks passed
@stephrobert
stephrobert deleted the feat/504-the-stack-gate-runs-every-night branch August 28, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The only gate that boots real machines never plays the example stacks, where all four dataplane defects were found by hand

1 participant