lint runs on every leg, and gates over dead code and staticcheck's correctness checks - #105
Merged
Merged
Conversation
No leg of the matrix had golangci-lint, so the lint target printed its skip line inside every make ci step and lint ran nowhere. Nothing said so except that line. The workflow now installs the linter on every leg before make ci, at an exact version, through the Go toolchain: the install is checked against the checksum database, and the linter is built by the same Go the leg tests with. The step prints the version it installed. On CI the target treats an absent linter as a failure that names it, told apart by the same CI variable the branch guard reads. On a machine without the linter it still skips, with the skip line unchanged word for word, because that line is what a CI log is searched for. With the linter present it prints every finding: its caps per linter and per message, and its rule of one finding per line, are turned off. With the linter present, lint fails ci on any finding, which is what this target has always done when the linter was there. No row in the suite holds the CI check; it was exercised both ways, and with the check disabled, by running the target.
…by file The linter's dead-code check and its correctness checks found five things worth changing in this tree, and these are they. A guard that holds every git invocation to a deadline read its own package with parser.ParseDir, which is deprecated. It now lists the directory and parses each non-test file, so every file is still read whatever its build constraint. The replacement the deprecation names, a package loader, would see only the host's build and would add a dependency. The guard still reds on a second caller of the undeadlined call, including one in a file only another platform builds. Four declarations nothing used are gone: a citation-pattern loader the citation guard stopped calling when it moved to the shared engine, an ordering helper whose only call was replaced by a structured assertion, a wrapper every caller went around (its one sentence of contract now opens the doc of the function they call), and a struct field nothing read or wrote.
Two of the findings in the set the linter now gates on are lines that exist to prove something, and changing them as it asks would weaken the proof. Each carries a //nolint for that one linter, with its reason: - a %s of a whole config through an any, in the unknown-fields leak test. The verb is wrong for the type on purpose: a debug print through an any is how a secret would leak, and the row proves it does not. - the stall-window floor for a leg with nothing recorded. Nothing uses it, by design: a refusal tells a caller to pass it, and a guard polices that name.
…hecks .golangci.yml enables unused and staticcheck's correctness checks, and nothing else. The linter's default set, with every finding printed, reported the same 110 on all three legs. errcheck gave 93, and every one was false: writes to a terminal or a report stream the program cannot act on, and closes of handles opened only for reading. staticcheck's style families gave 10: nine rewrites of code that already reads clearly, and one that would have removed the %s path from a redaction test's positive control. The two classes kept gave 7, all signal, fixed or annotated in the two commits before this one, and with this configuration the tree reports none. CLAUDE.md records the posture: why these two, why a gate inside make ci rather than advice, what the two annotations protect, and that an unchecked error is not linted at all.
Observed 2026-10-05: a pull request's head commit carried two runs of the required check ci (windows-latest), one from the push event and one from the pull request, and with the first red and the second green the queue refused to enqueue the pull request, naming that check as failing. CLAUDE.md's record of the queue now says so, beside the way a pull request is enqueued here.
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 5, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong. No CI leg had golangci-lint, so
make lintprinted "golangci-lint not installed; skipping lint" inside everymake cistep, and lint ran nowhere. Nothing said so except that line.What changes.
make ci, withgo installat an exact version: the install is checked against the checksum database, and the linter is built by the same Go the leg tests with. The step prints the version it installed.make linttreats an absent linter as a failure that names it; on a machine without it, it still skips, with the same line. It prints every finding: the linter's caps per linter and per message, and its rule of one finding per line, are off..golangci.ymlenablesunusedand staticcheck's correctness checks, and nothing else.parser.ParseDir; it now parses each non-test file itself, so a file built only for another platform is still read. Four dead declarations are gone.//nolint:<linter> // <reason>: the%sof a whole config through ananyin the unknown-fields leak test, and the stall-window floor for a leg with nothing recorded.The measurement behind the set. The linter's default set, run with every finding printed, reported the same 110 findings on all three legs:
%spath from a redaction test's positive controlWith this configuration the tree reports none.
Rows and runs.
CIunset the target prints the skip line and exits 0; withCI=trueit exits non-zero, naming the linter.Mutations, each run and reverted.
make lintmade to skip underCI=true: the local row's second half reds.