Skip to content

chore: retire stale nolint directives and guard against new ones - #313

Merged
OmarAlJarrah merged 1 commit into
mainfrom
chore/openapi-retire-stale-nolints
Aug 9, 2026
Merged

chore: retire stale nolint directives and guard against new ones#313
OmarAlJarrah merged 1 commit into
mainfrom
chore/openapi-retire-stale-nolints

Conversation

@OmarAlJarrah

Copy link
Copy Markdown
Member

Summary

Three of the seven //nolint directives in the tree suppressed nothing. A directive that has
outlived its finding is worse than no comment at all: it reads as a live constraint on the code
under it, and the gate stays green either way, so the only way to tell a real suppression from a
dead one is to delete it and look.

Deleted, each confirmed inert by deletion + golangci-lint run (table below):

  • pass/validate_propids_test.go:86//nolint:forcetypeassert. forcetypeassert has never been
    in the enabled set in .golangci.yml, so this never suppressed anything. The justification it
    carried ("validDoc builds it") is still worth having, so it stays as a plain comment.
  • compilers/openapi/internal/load/load.go:83//nolint:unparam on Load. unparam does not
    check exported functions unless check-exported is set, which it is not.
  • compilers/openapi/internal/load/load.go:482//nolint:errorlint on joinedParts. The
    assertion below it is to an anonymous interface{ Unwrap() []error }, which errorlint allows as
    the standard idiom for splitting a join. Only the directive is gone; the paragraph explaining why
    the code hand-asserts rather than calling errors.As is the real content and is kept.

The four that remain all suppress a finding that reappears the moment they are removed, and all four
already state why, so none needed a rationale added.

To stop the class from re-accumulating, nolintlint is now enabled with allow-unused: false,
require-specific: true, and require-explanation: true — an inert, bare, or unexplained directive
now fails the gate. It does not close the hole completely, and the config says so at the setting:
allow-unused only reaches directives naming an enabled linter, so one naming a disabled or
nonexistent linter is still reported by nothing. That is exactly the shape of the
forcetypeassert directive above, and it is filed as #306 rather than fixed here.

Separately, applyExclusive took two adjacent positional bools, so its call sites read
applyExclusive(c, s, true, exclusiveBoolean) with nothing at the call site saying what true
meant. The min/max selector becomes a named boundSide type, which also retires the isMin bool
threaded through reconcileBound, inclusiveIsTighter, setExclusiveFlag, and setExclusiveBound.
Behaviour-neutral; no golden churn.

Scope

This closes #88 partially, and it is worth being precise about which part. The issue's item 1 (eight
//nolint:unused directives) and its lowerDiscriminator dead-parameter item were already
discharged by #97 — zero nolint:unused remain and lowerDiscriminator no longer takes the
parameter described. What was still live is applyExclusive, fixed here, and three new directives
of the same kind the issue was opened for, also fixed here.

The issue's remaining item — nullUnionCollapse returning its hint parameter unchanged — is
deliberately left. That signature is where #281 is doing its work, and nothing currently guards the
hint at that site (passing a literal "MUTANT" in its place leaves the whole suite green), so
moving the parameter here would settle a naming question that belongs to #281.

Test plan

scripts/check-coverage.sh and the rest of the gate pass; coverage stays at 100%.

Every //nolint in the tree was classified by execution, not by reading: delete the directive, run
golangci-lint run, restore. The cache matters — a warm cache reports 0 issues. for a file whose
directive was just deleted, which is indistinguishable from a stale directive, so every run below
was preceded by golangci-lint cache clean.

directive result with the directive deleted verdict
pass/validate_propids_test.go:86 forcetypeassert 0 issues. stale — deleted
load.go:83 unparam 0 issues. stale — deleted
load.go:482 errorlint 0 issues. stale — deleted
load.go:508 errorlint load.go:510:15: type switch on error will fail on wrapped errors load-bearing — kept
internal/harness/path_test.go:66 staticcheck path_test.go:66:30: SA1012: do not pass a nil Context load-bearing — kept
internal/harness/harness_test.go:29 staticcheck harness_test.go:29:21: SA1012: do not pass a nil Context load-bearing — kept
compilers/openapi/openapi.go:70 gocritic openapi.go:70:20: appendAssign: append result not assigned to the same slice load-bearing — kept

Deleting the unparam directive also requires deleting the now-orphaned // line above it;
removing only the directive leaves load.go:82:1: File is not properly formatted (gci).

The new nolintlint config was checked by planting each defect it claims to catch and confirming
the gate reddens:

planted outcome
the deleted unparam directive, restored red — directive ... is unused for linter "unparam"
the deleted errorlint directive, restored red — directive ... is unused for linter "errorlint"
bare //nolint red — should mention specific linter
//nolint:gocritic with no explanation red — should provide explanation
the deleted forcetypeassert directive, restored green — not caught, the #306 gap

For the signature change, main and this branch were both built and run over a spec exercising
every branch of the min/max split — both dialects, exclusive-tighter, inclusive-tighter, equal
magnitudes, and the wrong-form refusal. Emitted IR and the full diagnostic list are byte-identical.
That comparison is not blind: inverting the polarity of the new selector
(if side == minBoundmaxBound) makes both the IR and the diagnostics differ, and reddens
TestConstraints_ExclusiveNumeric31 and the constraints and numeric-precision conformance cases.
Swapping the two constants' numeric values, by contrast, changes nothing — correctly, since only the
names are ever compared.

Closes #88

@OmarAlJarrah
OmarAlJarrah merged commit 19529dc into main Aug 9, 2026
1 check passed
@OmarAlJarrah
OmarAlJarrah deleted the chore/openapi-retire-stale-nolints branch August 9, 2026 09:10
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.

openapi: code hygiene — stale nolint directives and awkward signatures

1 participant