diff --git a/.dockerignore b/.dockerignore index e1128fa..8df76b7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,9 @@ # The lint build reads the Go sources, go.mod/go.sum and .golangci.yml; # none of that comes out of .git, so keep the build context small. +# +# This file is part of the lint gate, not housekeeping: only what reaches +# the container gets linted, so excluding a Go source here silently drops +# it from the lint (a self-contained file yields `0 issues.` at exit 0 with +# the violation still in the tree; it fails loudly only if other code still +# references it). Never exclude Go sources, go.mod/go.sum or .golangci.yml. .git diff --git a/TODO.md b/TODO.md index b979a44..f14deb8 100644 --- a/TODO.md +++ b/TODO.md @@ -89,7 +89,12 @@ is finished. the stage that actually runs `golangci-lint`. `--target` verifies the name exists, not that it is the right stage, and it stops the build there — so moving the lint step to another stage, or adding a stage after it, would go - unnoticed. + unnoticed. The same applies to `.dockerignore`, which is part of this gate + rather than housekeeping: only what reaches the container is linted, so + excluding a Go source there drops it from the lint silently — verified, a + planted violation plus that one path in `.dockerignore` gives `0 issues.` at + exit 0 with the violation still in the tree, and it fails loudly only when + other code still references the excluded file. - 2026-08-09 `TestAutoSaveOnSignalRacesTurnLoop` de-flaked at the cause (`fix/autosave-turn-budget-36`, closes #36). The failure text was captured diff --git a/script/lint b/script/lint index 94d31bf..a4b837c 100755 --- a/script/lint +++ b/script/lint @@ -7,8 +7,9 @@ # # --no-cache-filter forces the lint stage to re-execute every run, so an # unchanged tree is still actually linted; the deps stage keeps its cache, -# so the module download is not repeated. Both flags below must stay: do -# not "simplify" either one away. +# so the module download is not repeated. It and --target must both stay, +# for the reason in the next paragraph: do not "simplify" either of those +# two away. # # The stage name is written ONCE, in $stage, and passed to both --target # and --no-cache-filter, so the two flags cannot come to name different @@ -22,11 +23,24 @@ # silent skip, because the one name reaches both flags. # # What the tooling does NOT check, and is left to whoever edits this: -# $stage must name the stage in Dockerfile.lint that actually runs -# golangci-lint. --target verifies that the name exists, not that it is -# the right stage, and it stops the build at that stage — so moving the -# lint step into a different stage, or adding a stage after this one, -# would not be caught here. Keep this file and Dockerfile.lint in sync. +# +# 1. $stage must name the stage in Dockerfile.lint that actually runs +# golangci-lint. --target verifies that the name exists, not that it is +# the right stage, and it stops the build at that stage — so moving the +# lint step into a different stage, or adding a stage after this one, +# would not be caught here. Keep this file and Dockerfile.lint in sync. +# +# 2. .dockerignore decides what reaches the container, and only what +# reaches it gets linted. Excluding a Go file there removes it from the +# lint with no warning: verified by planting a real violation and adding +# just that file's path to .dockerignore, which produced `0 issues.` at +# exit 0 with the violation still sitting in the working tree. It shows +# up only if the rest of the package still references the excluded file, +# in which case the build fails loudly on `undefined:` typecheck errors; +# a self-contained file drops out silently. So .dockerignore is part of +# this gate, not housekeeping — keep it to build inputs the lint does +# not read, and never exclude Go sources, go.mod/go.sum or +# .golangci.yml. # # --output=type=cacheonly skips the image export. Nothing consumes the # image — the deliverable of this build is an exit code — and exporting it