Uh oh!
There was an error while loading. Please reload this page.
test: SwapSeam helper + advisory gremlins mutation workflow - #306
Conversation
internal/testutil.SwapSeam(t, ptr, stub) replaces the hand-rolled save/stub/restore blocks around package-level seam variables: swap, then LIFO-restore via t.Cleanup. Generic, so non-function seams (timeouts) work too. Converted the three blocks in internal/submit (watch_test.go x2, run_watch_test.go x1); internal/push has none. The ~26 blocks in internal/cli are deliberately left for the decomposition work to pick up; converting them here would collide. mutation.yml formalizes the gremlins ritual that produced #262-#264: workflow_dispatch only, one package per run, advisory (lived mutants never fail the job — no thresholds). Prints a survivors-to-triage summary, uploads the JSON report, and CONTRIBUTING.md documents how survivors get triaged into pinning-test issues. Fixes#295 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
LukasWodka
commented
Jul 14, 2026
👋 Heads-up — Code review queue is at 44 / 30 Above the WIP limit. The team convention is to review existing PRs before opening new work. Open PRs currently in Code review (oldest first):
Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.) |
Uh oh!
There was an error while loading. Please reload this page.
LukasWodka
commented
Jul 14, 2026
@BugBot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 852eb8c. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
saadqbal
left a comment
There was a problem hiding this comment.
👍 Clean — SwapSeam is a tidy generic over the hand-rolled save/stub/restore, with the right caveats documented (LIFO cleanup, not t.Parallel-safe, test-only). The mutation workflow is workflow_dispatch-only so it can't gate anything, and it input-validates the package/coefficient. Nice.
saadqbal
commented
Jul 14, 2026
Status: approved, but 2 open Cursor Bugbot findings block merge (develop requires conversation resolution): Pipeline hides gremlins failures (mutation.yml:84) and Zero timeout coefficient accepted (mutation.yml:76). Address/resolve those and it's ready. |
- Reject a zero timeout-coefficient. The digit check accepted `0`/`00`,
which collapses gremlins' per-mutant timeout so survivors report TIMED
OUT instead of KILLED/LIVED — the exact failure mode this input guards
against. Now require a positive integer (> 0), matching the error text.
- Add `set -o pipefail` to the run step. The implicit default shell is
`bash -e {0}` (no pipefail), so `gremlins | tee` masked a non-zero
gremlins exit behind tee's 0, letting a broken suite pass the job —
contradicting the workflow's "tool/test health fails the run" contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
saadqbal
left a comment
There was a problem hiding this comment.
Re-approving — Bugbot fixes verified: set -o pipefail unmasks a gremlins/test failure through the | tee, and the coefficient validation now rejects zero/all-zeros ((*[1-9]*) gate). Both findings addressed. 👍

Summary
testutil.SwapSeam(generic seam swapper). Newinternal/testutilpackage (no shared test-support package existed) with one helper:Swaps the value behind a package-level seam variable and LIFO-restores it via
t.Cleanup. Generic, so non-function seams (timeouts) work too. Comes with its own tests (100% coverage, including nested-swap restore ordering).Converted blocks — honest count vs the ticket. The ticket estimated "7+ blocks repo-wide". Reality on today's develop: ~34 hand-rolled save/restore sites repo-wide, of which ~26 live in
internal/cli(out of scope here — the WS-B decomposition PRs own that tree) and 8 elsewhere. Of the packages this PR is scoped to:internal/submit— 3 blocks, all converted (watch_test.gox2finalJobStatusTimeout,run_watch_test.gox1watchJobFn)internal/push— 0 blocks found (its tests don't use seam-var stubbing)The remaining 5 out-of-scope non-cli blocks (
internal/apix2,internal/helmx1,internal/nodebootx1,internal/uix1) are trivial follow-up candidates once this merges.mutation.yml(advisory gremlins workflow). Formalizes the manual gremlins ritual that already produced #262/#263/#264:workflow_dispatchonly — never on PRs/pushes, never a merge gatepackageinput (routed through env vars, not raw interpolation)--threshold-*flags, so lived mutants never fail the job; the run summary listsLIVED/TIMED OUTsurvivors to triage and the JSON report is uploaded as an artifacttimeout_coefficientinput (default 3) because gremlins' default timeout misclassifies kills asTIMED OUT(reproduced locally)CONTRIBUTING.md (existed already — extended, not created): a "Test seams" subsection documenting
SwapSeam, and a "Mutation testing" section documenting the ritual — one package per run, how to read survivors, which ones are noise, and that real gaps become issues titledtest(<pkg>): pin <behavior> (mutation survivor).Test plan
Ran locally:
go build ./...,go vet,gofmt -s— cleango test -race -cover ./internal/testutil/ ./internal/submit/ ./internal/push/— green; submit/push coverage unchanged (80.4% / 89.0%), testutil 100%errcheck/ineffassign/misspell(CI's pinned versions) on the touched files — cleaninternal/slug: default coefficient mistimes-out all mutants;--timeout-coefficientraised → 11 KILLED / 3 LIVED / 2 TIMED OUT, which is what informed the workflow's default inputmutation.ymlNOT run locally: the workflow itself on Actions (dispatch-only; can be triggered once merged to develop).
Fixes#295
🤖 Generated with Claude Code
Note
Low Risk
Test-only helper and documentation plus a non-gating CI workflow; no production code paths change.
Overview
Adds
internal/testutil.SwapSeam, a generic helper that stubs package-level test seams and restores them viat.Cleanup(including LIFO nested swaps).internal/submitwatch tests are updated to use it instead of hand-rolled save/stub/restore forwatchJobFnandfinalJobStatusTimeout.Introduces a manual-only GitHub Actions workflow Mutation (gremlins) (
workflow_dispatch, one package per run, validated inputs, pinned gremlins v0.5.0). Lived mutants do not fail the job; the step summary lists survivors and uploads JSON/log artifacts.CONTRIBUTING.md gains Test seams (
SwapSeamusage) and Mutation testing (ritual, triage, issue titling).Reviewed by Cursor Bugbot for commit 23b3853. Bugbot is set up for automated code reviews on this repo. Configure here.