Skip to content

lint go: every lane enters each command that is a module of its own - #650

Merged
apostasie merged 1 commit into
mainfrom
claudio/20261110-lint-nested-modules
Nov 10, 2026
Merged

apostasie merged 1 commit into
mainfrom
claudio/20261110-lint-nested-modules

Conversation

@closer-claudio

Copy link
Copy Markdown
Contributor

The Go lanes ran at the repository root, and golangci-lint, vet, the
tidiness check, go-licenses, NilAway and deadcode all stop at a nested
go.mod: a command that is a module of its own, the shape build go builds
from inside (cmd//go.mod), was never linted by the shared lanes.
limen linted its own cmd/limen-lint-go through five lines in its root
justfile, and any other repository with such a command linted it not at
all.

The list is one statement, the root then each cmd/ carrying a
go.mod, built into an array; a tool module under .limen/tools is not
project code and is not on it. lib.just holds it as go_modules_init for
the commands handed to _per-platform, and a recipe body writes it out,
since the shell lane lints a body with its interpolations opaque and must
see the assignment the loop reads. Every lane loops over it from inside
the module, and _golangci-config renders one configuration per module,
the baseline with that module's own .lint-go.yaml when it has one (the
root's at golangci.yml as before, a command's beside it by name), so a
command's carve-outs are its own. NilAway reads its flags and its mode
per module. The fix lane follows the same list, for the fixers, the
formatter's convergence loop and tidiness, since lint would otherwise
refuse what fix cannot repair. _per-platform exports a leg's environment
in a subshell instead of prefixing it: a prefix binds to a simple command
alone, and a leg's command is now a loop. A lane names the module it
enters, so a finding's relative path is locatable. The two one-line
recipes, the formatter's check and deadcode, become bash blocks: the loop
is bash, and a plain recipe line runs under sh.

Found on the way: the mod lanes ended on the loop over the isolated tool
modules, whose body was [ -f ] && go ..., so a repository with no such
module ended the recipe on 1; continue instead. limen's root justfile
loses lint-lint-go; its tests of the nested module stay, since the test
lane still stops at the root. book/linting-go.md states the rule and
drops the "never enters" clause.

Tests, black-box through just on a fixture with a root module and a
command module: a malformed build constraint in the command fails lint go vet naming cmd/nested; a sound command passes vet and mod. limen's
own just lint now lints cmd/limen-lint-go through the shared lanes, on
its own overlay.

Closes #505

Evidence. just lint on this branch enters cmd/limen-lint-go through the shared lanes (the lane prints the module it enters) and is green, with limen's own hand-written lint of that module removed; just do fix go converges per module; just test green, 446 tests, the two new ones black-box through just on a fixture repository.

For a consumer: a repository with a command that is a module of its own gets that module linted at its next limen bump, on the baseline with the module's own .lint-go.yaml if it has one, and just do fix go formats it. Findings there are new findings, not a changed rule.

The Go lanes ran at the repository root, and golangci-lint, vet, the
tidiness check, go-licenses, NilAway, deadcode and govulncheck all stop
at a nested go.mod: a command that is a module of its own, the shape
build go builds from inside (cmd/<name>/go.mod), was never linted or
scanned by the shared lanes. limen linted its own cmd/limen-lint-go
through five lines in its root justfile, and any other repository with
such a command linted it not at all.

The list is one statement, the root then each cmd/<name> carrying a
go.mod, built into an array; a tool module under .limen/tools is not
project code and is not on it. lib.just holds it as go_modules_init for
the commands handed to _per-platform, and a recipe body writes it out,
since the shell lane lints a body with its interpolations opaque and
must see the assignment the loop reads; a test holds the copies to the
variable. Every lint lane, the vulnerability scan and the fix lane (the
fixers, the formatter's convergence loop, tidiness) loop over it from
inside each module, and _golangci-config renders one configuration per
module, the baseline with that module's own .lint-go.yaml when it has
one (the root's at golangci.yml as before, a command's beside it by
name), so a command's carve-outs are its own. NilAway reads its flags
and its mode per module. A lane names the module it enters, so a
finding's relative path is locatable.

_per-platform exports a leg's environment instead of prefixing it: a
prefix binds to a simple command alone, and a leg's command is now a
loop; the recipe is its own process, so nothing outlives it. The two
one-line recipes, the formatter's check and deadcode, become bash
blocks: the loop is bash, and a plain recipe line runs under sh.

Found on the way: the mod lanes ended on the loop over the isolated
tool modules, whose body was `[ -f ] && go ...`, so a repository with
no such module ended the recipe on 1; `continue` instead. limen's root
justfile loses lint-lint-go; its tests of the nested module stay, since
the test lane still runs the root alone. book/linting-go.md states the
rule and drops the "never enters" clause; book/errors-go.md's clause
narrows to the modules the lane still does not enter.

Tests, black-box through just on a fixture with a root module and a
command module: a malformed build constraint in the command fails
`lint go vet` naming cmd/nested; a sound command passes vet and mod.
limen's own `just lint` now lints cmd/limen-lint-go through the shared
lanes, on its own overlay.

Closes #505

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: closer-claudio <claudio@farcloser.world>
@closer-claudio
closer-claudio force-pushed the claudio/20261110-lint-nested-modules branch from 5cced96 to 3a9341b Compare November 10, 2026 08:52
@apostasie
apostasie merged commit 3fe8f03 into main Nov 10, 2026
14 checks passed
@apostasie
apostasie deleted the claudio/20261110-lint-nested-modules branch November 10, 2026 09:00
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.

lint go: a nested module is never linted

2 participants