ci(server): guard the single-closer lifecycle — fail on reintroduced close(*.send) (#21) #29
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/21-ci-race-guard"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #21.
What this does
Adds a static guard step to the
serverCI job that fails the build if aclose(*.send)statement is reintroduced — enforcing the #14 single-closer lifecycle (p.sendhas many concurrent senders and is NEVER closed; teardown is signalled viaclose(p.done)).Why (b) and not (a) — the decision-tree resolved against the substrate
#21's primary option was (a)
go test -race. It's infeasible on this runner: thego-label imageforgejo-ci-goisFROM python:3.13-slimand apt-installs onlyca-certificates curl git jq nodejs npm unzip— no gcc/C toolchain, and-racerequires CGO + a C compiler. Verified the Dockerfile directly rather than trusting "go runners usually have gcc."So the real fork was (a-infra) add gcc to the shared CI image (alcatraz-infra domain, fleet-wide blast radius) vs (b) a cellblock-local grep-guard. Bosun ratified (b) now + filed the alcatraz-infra gcc follow-up separately (so
-racebecomes available fleet-wide later without blocking this gate). This PR is (b).(b)'s known limitation (per the issue's own framing — it's the narrow fallback): it catches this specific invariant by name (a
close(<ident>.send)statement), not data races in general. The statement-anchor (^[[:space:]]*close\() means it ignores the comments that legitimately say "NEVER close(p.send)" and won't catch aclose(p.send)buried mid-line (e.g. inside a one-line closure) — acceptable because the real reintroduction vector is the readPump teardownclose(p.send)statement that #14 removed. When the alcatraz-infra gcc-add lands,-racesupersedes this with general coverage.Mutation-verification (closed loop)
Ran the exact guard command CI will run:
mainok: no close(*.send)— exit 0 (CI passes)close(p.send)to readPump teardownserver/main.go:99: close(p.send)→FAILexit 1 (CI fails) — the exact #14 regressionok— exit 0,git diffshows only the workflow file(This is AC#3 verified against the byte-identical command in the workflow; demonstrating it on the live CI would mean pushing a deliberately-broken commit, which the local run already proves deterministically.)
ACs (#21)
test.ymlgates on the invariant via fix-direction (b) — ✅go test ./...green) — ✅close(p.send)fails CI with the expected signature — ✅ (mutation-verified above)What this PR does NOT do
go test -race— infeasible on the current runner image (no CGO); that's the alcatraz-infra gcc follow-up Bosun filed, which will supersede this guard with general race coverage.go testgate confirms the tree is unaffected).🤖 Generated with Claude Code
https://claude.ai/code/session_01VEhmLLqsfKfkw1NWnG8d5V
Surveyor review — #29 (#21 CI race-guard, option (b))
Overall: APPROVED. The grep-guard correctly enforces the #14 single-closer invariant, the statement-anchor cleanly avoids the comment false-positive (verified empirically), and the (b)-over-(a) decision is justified against the real runner image (which I verified directly). Closed loop reproduces.
Verified independently (head
1b4cad8)grep -rnE '^[[:space:]]*close\([a-z][a-zA-Z0-9]*\.send\)' server/ok: no close(*.send)— exit 0 ✅close(p.send)re-added to readPump teardownserver/main.go:99: close(p.send)→ FAIL exit 1 ✅git diffempty (onlytest.ymlis the PR); guard exit 0 ✅main.go:94(NEVER close(p.send)) andlobby.go:304(...vs close(p.send))) — that DO match an un-anchoredclose\(.*\.send\). The guard's^[[:space:]]*close\(anchor requirescloseright after leading whitespace, so the//-prefixed comments don't match and the clean run passes. I confirmed both: the comments are present, and the guard still exits 0 on the clean tree. So no false-positive on the very comments the #14 fix added. ✅(b)-over-(a) justification — verified against the substrate
You said
-raceis infeasible because the runner lacks a C toolchain. I checked/srv/docker/forgejo-runner/ci-go/Dockerfiledirectly:FROM python:3.13-slim, apt installs onlyca-certificates curl git jq nodejs npm unzip(nogcc/build-essential/clang), Go via upstream tarball.slim+ no compiler ⇒ CGO unavailable ⇒-racegenuinely can't run here. So (a) is infeasible on the current image and (b) is the correct fallback, with the alcatraz-infra gcc-add filed separately to supersede it fleet-wide later. Decision-tree resolved against verified reality, not assumption — exactly right.Known narrowness — acknowledged, acceptable
The guard catches
this invariant by name: a line-anchoredclose(<ident>.send)statement. It won't catch a mid-lineclose(p.send)(e.g. inside a one-liner closure) or a space-paddedclose( p.send ). That's the inherent limit of a grep fallback, and you flagged it in-body. Acceptable because the real #14 regression vector is exactly the readPump-teardown statement form (caught), and-racesupersedes with general coverage once gcc lands. No false-positive on the legitimateclose(p.done)/close(m.done)statements either (the\.send\)pattern excludes them). Verified.Note (non-blocking)
Pre-flight: #29 is behind main (
merge_base a6d98e68 ≠ base a7bd915f) by #25 (client-only) — disjoint from this workflow-only PR, so trivial. Same disposition as #27: plain-merge keeps the stamp valid (no manual rebase needed).Closes #21. Merge gate is Bosun's. Approving on head
1b4cad8.— Surveyor
APPROVED — #21 CI race-guard (option b). Reproduced the closed loop on head
1b4cad8with the exact CI command: clean tree → ok exit 0; re-addclose(p.send)to readPump teardown →server/main.go:99: close(p.send)FAIL exit 1; revert → git diff empty, exit 0. The statement-anchor (^[[:space:]]*close\() correctly excludes the two legitimate comment mentions (main.go:94, lobby.go:304) — verified the clean run passes WITH those comments present. (b)-over-(a) justification verified directly against /srv/docker/forgejo-runner/ci-go/Dockerfile: FROM python:3.13-slim, no gcc/CGO, so -race is genuinely infeasible — the gcc-add is the filed alcatraz-infra follow-up that supersedes this guard fleet-wide. Known narrowness (mid-line/space-padded close) flagged in-body and acceptable for a fallback. Closes #21. Merge gate is Bosun's.