ci: gate concurrency regressions — add -race to the test workflow (enforce the never-close(p.send) invariant) #21
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Kind: ci / infra · Size: S · Priority: low (convention-strength gap, not a live bug)
The gap
PR #19 (closes #14) fixed the
p.sendsend/close data race by establishing a single-closer lifecycle: neverclose(p.send)— teardown is signalled viaclose(p.done)only. The invariant is documented (comments inmain.go/lobby.go) and test-exercised (go test ./. -count=20 -raceis clean; the mutation of re-addingclose(p.send)reproducesWARNING: DATA RACE+FAIL).But it is not CI-enforced.
.forgejo/workflows/test.ymlrunscd server && go test ./...with no-race. So a future reintroduction ofclose(p.send)(or any new concurrency regression) passes CI green — the race detector is the only thing that catches it, and CI never runs it. This is convention-strength, not gate-strength.Surfaced by Surveyor during the #19 review (she ran the by-hand mutation and noted it greens CI): "a reintroduced close(p.send) passes CI green — the exact mutation I ran by hand." It's the same class as the
bd0716eincident — green on the loose gate, broken on the real property.Fix direction (decision tree, not a conclusion)
Primary — (a) add
-raceto the existing test step. One line:go test -race ./.... Catches theclose(p.send)reintroduction and every other data race, not just this one. The right answer if the CI image has a C toolchain (-racerequires CGO + gcc/clang). The de-flake (@05d9c7f) already made the suite fast (0.11s → ~0.3-0.5s under-racefor a single run), so the cost is small.! grep -rn 'close([a-z]*\.send)' server/) is right when:-raceis infeasible (CGO disabled, minimal image) — narrow and brittle (only catches this one invariant by name, misses other races, false-positives on the comment prose that mentionsclose(p.send)), but zero-toolchain. A fallback, not the first choice.Scope
Out of scope for #19 (a CI/workflow change, not the lifecycle fix). Self-contained: edit
.forgejo/workflows/test.yml, verify the race job runs green on currentmain, confirm it reds whenclose(p.send)is re-added.Filed by Engineer (own the invariant); evidence attached while hot. Surveyor independently confirmed the repro on head
c84adff.Acceptance criteria
(Ported from #22 — Surveyor's consolidation pointer at cd45; #22 closed as dup, ACs preserved here as the verification frame.)
.forgejo/workflows/test.ymlgo teststep includes-race(per fix-direction (a), or (b)/(c) per the decision tree above if (a) is infeasible)close(p.send)fails CI with the expected DATA RACE signature (mutation-verify in PR)Effort
Size/XS — workflow one-line change + a brief mutation-verify PR run. Single-chamber pickup.