Skip to content

A capacity witness that cannot flake, and the social card actually served - #176

Merged
caviri merged 4 commits into
developfrom
fix/capacity-witness
Aug 17, 2026
Merged

A capacity witness that cannot flake, and the social card actually served#176
caviri merged 4 commits into
developfrom
fix/capacity-witness

Conversation

@caviri

@caviri caviri commented Aug 16, 2026

Copy link
Copy Markdown
Member

The soft spot

capacity.oversell-by-one was the last mutation judged by a coin flip. Its witness was a declared-flaky concurrency spec, which made the entry ambiguous in both directions: a MISMATCH might be the flake, and on 2026-08-14 an expected red simply failed to arrive because the flaky spec stayed green under its own mutation.

The mutation is one character in capacity.go:46>= becomes >, so the room seats one person too many and the queue starts one arrival late.

The witness

The race spec's real claim is an end state: the confirmed roster equals the capacity, read back from the DB. Only sharing the last seat needs concurrency — where the last seat is does not.

So the new spec fills an event to exactly its capacity one join at a time, counting the roster after each, then asserts the next arrival queues with the confirmed count unmoved. Same claim, same path through the handlers, no goroutines and no clock. Three capacities (1, 2, 3), because a rule that is off by one is off by one at every cap and a single number cannot distinguish "the boundary moved" from "this event was set up wrong". Under the mutation it fails in 0.012 s.

The flaky spec is dropped from expectReds, not deleted

expectReds is by design the one place KNOWN_FLAKY cannot reach, so a flaky test listed there makes the verdict unreliable both ways. The original justification — "a flaky test can still be a genuine witness" — was sound while it was the only witness hammering the cap; that premise is now gone.

Dropping it does not silence it: its red lands in extras, is excused, and is printed with its reason on every run. Evidence on screen, not on the ballot. The spec stays as a test, because it pins capacityMu, which once genuinely oversold an event. The flake itself is untouched and still reds CI — a test-side race, out of scope here.

Verdicts

Seven runs of mutate.sh run capacity.oversell-by-one, EXACT every time (7 reds observed / 6 expected / 1 excused). No MISMATCH in either column.

Full fast tier: 38 run — 37 exact, 1 known gap, 0 untested, 0 other failures. The baseline's "other failure" was this entry; nothing else moved. Backend green across three runs, ~10 s wall, the runner's Go arena 9.0–9.2 s against a ~9.3 s baseline.

And the social card is now actually served

:8081 had been serving the old 90,689-byte card because build/ snapshots static/ at build time. Rebuilt through the shared helper and restarted; served sha256 now byte-identical to the static file.

Two traps found doing it, both documented:

  • The 9p EPERM on the atomic swap has a reproducible cause — with the :8081 server up, all five rename attempts burn; stop it and the next attempt succeeds. The order is stop, build, start.
  • The swap does not reach a server that booted against the old tree, and the bytes are still right. adapter-node serves through sirv, whose manifest is built once at boot — so :8082 streamed the current file while advertising the previous length and ETag: Content-Length: 85099, 58,130 correct bytes, curl: (18) transfer closed with 26969 bytes remaining on every request. Hashing the download says MATCH. The obvious check would have passed while every crawler saw a truncated image and every cache honoured a false ETag. Both ports now agree on bytes and headers.

caviri added 4 commits August 16, 2026 10:20
`capacity.oversell-by-one` was judged by a spec that hammers concurrent
joins — declared flaky in the mutation runner, and ambiguous in both
directions: a MISMATCH could be the flake firing, and the flake once
stayed GREEN under the very mutation it exists to catch.

The half an off-by-one cap actually breaks needs no concurrency: it is
where the last seat IS, not whether two arrivals can share it. This
fills an event to exactly its capacity one join at a time, reading the
roster back from the DB after each, and asserts the next arrival queues
with the confirmed count unmoved. Three capacities, because a rule that
is off by one is off by one at every cap; the seated joins at capacity
2 and 3 are the positive control against an event that simply queues
everybody.

The concurrency spec stays — it pins a real race that once oversold.
…lake

The entry's expectReds named the concurrency spec — the runner's one
KNOWN_FLAKY entry — which made the verdict a coin flip in both
directions. A MISMATCH could be the flake firing rather than a
regression, and the flake has stayed GREEN under this very mutation,
which is an expected red that never arrived and no excuse list can
reach: expectReds is by design where the filter does not apply.

Recorded rather than predicted (--record, then read). The observed set
under the mutation is 7 reds; 6 are frozen and the race spec is left
out, so its red now lands in the extras column, is excused with its
reason, and is PRINTED on every run of this entry. The evidence stays
on screen without being on the ballot.

The rule that survived is written down in both places that used to
teach the opposite: a verdict may only rest on witnesses that cannot
flake. The runner's own "put it in expectReds" hint said the thing
that caused this, so it now says what to do instead.

The flake itself is untouched and still reds CI — a test-side race,
tracked separately.
Both were hit while getting the running :8081 server onto the current
static/og-default.jpg, and both were previously written down as
something else.

The 9p EPERM on the atomic swap is not only the filesystem. With the
:8081 adapter-node server up, `frontend-build.sh build` burned all five
rename attempts and gave up; one `prod-frontend.sh stop` later the very
next attempt succeeded, with the :8082 server still running. When every
retry fails, ask who is serving the tree. The order is stop, build,
start — which is what prod-frontend.sh's `start` already does, so the
case that hits the wall is calling the helper directly.

And swapping the tree in does not reach a server that booted against
the old one. adapter-node serves the client dir through sirv, which
builds its manifest once at boot, so afterwards it streams the CURRENT
file while advertising the PREVIOUS length and ETag: the tunnel's :8082
server answered every request with Content-Length 85099, an ETag to
match, and 58130 correct bytes. Hashing the download says MATCH — the
body really is the new card — while every client sees a truncated image
and every cache honours a false ETag. Compare headers, and read curl's
exit code. Restarted both servers; verified byte-for-byte and
header-for-header against the static file.
The two traps recorded in e93f1c1 were hand-wrapped; prettier owns .claude now
(the exemption came off during the develop merge), and CI runs the formatter
with --fail-on-change. Layout only.
@caviri
caviri merged commit 935e2eb into develop Aug 17, 2026
1 check passed
@caviri
caviri deleted the fix/capacity-witness branch August 17, 2026 08:38
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.

1 participant