This repo is not on the org-standard Go lint configuration, and the linter version pinned in the backend Docker build is two minor versions behind what is now deployed across the org's Go repos.
REPO_POLICIES.md states: ".golangci.yml is standardized and must NEVER be modified by an agent, only manually by the user. Fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml."
Linter version mismatch.Dockerfile.backend pins golangci-lint at commit 9f61b0f53f80672872fced07b6874397c3ed197b (v2.7.2, dated 2026-02-27). The org standard is v2.12.2, commit c0d3ddc9cf3faa61a4e378e879ece580256d76e5.
make check in backend/ currently reports 0 issues. against the non-standard config. Moving to the stricter standard config plus a newer linter is expected to surface new findings; fixing those findings is part of this work unit.
Definition of done
backend/.golangci.yml is byte-identical to the org standard — sha256sum backend/.golangci.yml outputs 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb. Copy it verbatim; do not hand-edit, tune, or add exclusions to it.
Dockerfile.backend pins golangci-lint to commit c0d3ddc9cf3faa61a4e378e879ece580256d76e5, with a comment above the reference reading the version and date in the form # golangci-lint v2.12.2 (YYYY-MM-DD) per the hash-pinning policy.
Every new lint finding surfaced by the standard config and the newer linter is fixed in the Go source. Suppressing findings by editing .golangci.yml is explicitly forbidden. A targeted //nolint:linter // reason on an individual line is acceptable only where the finding is genuinely a false positive, and each one must carry a written justification comment.
cd backend && make check passes and reports 0 issues.
make check at the repo root still passes.
docker build -f Dockerfile.backend . succeeds.
TODO.md is updated in the same commit as the work.
Commit title ends with (closes #N) for this issue number.
Implementation requirements
Use make targets and script/ entrypoints only. Never invoke go, gofmt, or golangci-lint directly.
Do not change the .golangci.yml in any way after copying it. If the standard config disagrees with the code, the code changes.
Keep this commit scoped to lint configuration, the linter version pin, and the source fixes required to make them pass. Do not fold in unrelated compliance work — those are separate issues.
No attribution trailers in the commit message.
## Problem
This repo is not on the org-standard Go lint configuration, and the linter version pinned in the backend Docker build is two minor versions behind what is now deployed across the org's Go repos.
Verified on `main` at `fbfe1df`:
1. **`.golangci.yml` content mismatch.**
```
sha256(backend/.golangci.yml) = 33ba2bf7fe4a44779d09b0fb31d6daf03685f8dc9d2bc417f963d7aabb0d17dc
sha256(org standard, prompts/.golangci.yml) = 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb
```
`REPO_POLICIES.md` states: "`.golangci.yml` is standardized and must _NEVER_ be modified by an agent, only manually by the user. Fetch from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml`."
2. **Linter version mismatch.** `Dockerfile.backend` pins golangci-lint at commit `9f61b0f53f80672872fced07b6874397c3ed197b` (v2.7.2, dated 2026-02-27). The org standard is **v2.12.2**, commit `c0d3ddc9cf3faa61a4e378e879ece580256d76e5`.
`make check` in `backend/` currently reports `0 issues.` against the non-standard config. Moving to the stricter standard config plus a newer linter is expected to surface new findings; fixing those findings is part of this work unit.
## Definition of done
- [ ] `backend/.golangci.yml` is byte-identical to the org standard — `sha256sum backend/.golangci.yml` outputs `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`. Copy it verbatim; do **not** hand-edit, tune, or add exclusions to it.
- [ ] `Dockerfile.backend` pins golangci-lint to commit `c0d3ddc9cf3faa61a4e378e879ece580256d76e5`, with a comment above the reference reading the version and date in the form `# golangci-lint v2.12.2 (YYYY-MM-DD)` per the hash-pinning policy.
- [ ] Every new lint finding surfaced by the standard config and the newer linter is **fixed in the Go source**. Suppressing findings by editing `.golangci.yml` is explicitly forbidden. A targeted `//nolint:linter // reason` on an individual line is acceptable only where the finding is genuinely a false positive, and each one must carry a written justification comment.
- [ ] `cd backend && make check` passes and reports `0 issues.`
- [ ] `make check` at the repo root still passes.
- [ ] `docker build -f Dockerfile.backend .` succeeds.
- [ ] `TODO.md` is updated in the same commit as the work.
- [ ] Commit title ends with ` (closes #N)` for this issue number.
## Implementation requirements
- Use `make` targets and `script/` entrypoints only. Never invoke `go`, `gofmt`, or `golangci-lint` directly.
- Do not change the `.golangci.yml` in any way after copying it. If the standard config disagrees with the code, the code changes.
- Keep this commit scoped to lint configuration, the linter version pin, and the source fixes required to make them pass. Do not fold in unrelated compliance work — those are separate issues.
- No attribution trailers in the commit message.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:36:49 +02:00
Escalation: the current config is not merely non-standard, it is invalid and silently inert
Follow-up audit found the problem is worse than a hash mismatch. backend/.golangci.yml declares version: "2" on line 1 but uses golangci-lint v1 schema below it:
Line 18 uses a top-level linters-settings: key. In v2 this moved to linters.settings:.
Line 30 adds issues.exclude-use-default: false, which does not exist in v2 and is absent from the canonical file.
The canonical file's explanatory header comment — which exists specifically to prevent this edit — was stripped.
Verified empirically with golangci-lint v2.10.1:
$ golangci-lint config verify
jsonschema: "issues" does not validate ... additional properties 'exclude-use-default' not allowed
jsonschema: "" does not validate ... additional properties 'linters-settings' not allowed
The command is terminated due to an error: the configuration contains invalid elements
Why this matters more than the version bump
Every threshold in the file is inert: lll: 88, funlen: 80/50, cyclop: 15, dupl: 100 are all ignored. lll falls back to its default of 120 columns.
So when cd backend && make check prints 0 issues., that is not evidence the code is clean — it is evidence the linter ran with defaults and found nothing at defaults. The green result we have been relying on is meaningless.
Concretely, three lines already exceed the 77-character hard wrap required by CODE_STYLEGUIDE_GO.md, and go unreported today:
internal/server/server.go:65 — 93 chars
internal/server/server.go:97 — 81 chars
internal/reportbuf/reportbuf.go:166 — 88 chars
All three are long //nolint justification comments; lll would catch them once the config is valid.
Consequences for this issue
Expect substantially more than a handful of new findings once the canonical config actually loads. Budget accordingly; this may not fit one commit. If it does not, split into "adopt config + linter version" and "fix the findings" and note the split here.
The definition of done already requires sha256sum backend/.golangci.yml to equal 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb. Add one verification step: after copying, run the linter's own config verification and confirm it reports the config valid. A config that fails to verify must never be committed again.
The three lll violations above are in scope.
This also raises the priority of this issue above the other compliance items: until the config is valid, no other issue's "lint passes" claim can be trusted.
## Escalation: the current config is not merely non-standard, it is invalid and silently inert
Follow-up audit found the problem is worse than a hash mismatch. `backend/.golangci.yml` declares `version: "2"` on line 1 but uses **golangci-lint v1 schema** below it:
- Line 18 uses a top-level `linters-settings:` key. In v2 this moved to `linters.settings:`.
- Line 30 adds `issues.exclude-use-default: false`, which does not exist in v2 and is absent from the canonical file.
- The canonical file's explanatory header comment — which exists specifically to prevent this edit — was stripped.
Verified empirically with golangci-lint v2.10.1:
```
$ golangci-lint config verify
jsonschema: "issues" does not validate ... additional properties 'exclude-use-default' not allowed
jsonschema: "" does not validate ... additional properties 'linters-settings' not allowed
The command is terminated due to an error: the configuration contains invalid elements
```
### Why this matters more than the version bump
Every threshold in the file is **inert**: `lll: 88`, `funlen: 80/50`, `cyclop: 15`, `dupl: 100` are all ignored. `lll` falls back to its default of 120 columns.
So when `cd backend && make check` prints `0 issues.`, that is **not evidence the code is clean** — it is evidence the linter ran with defaults and found nothing at defaults. The green result we have been relying on is meaningless.
Concretely, three lines already exceed the 77-character hard wrap required by `CODE_STYLEGUIDE_GO.md`, and go unreported today:
- `internal/server/server.go:65` — 93 chars
- `internal/server/server.go:97` — 81 chars
- `internal/reportbuf/reportbuf.go:166` — 88 chars
All three are long `//nolint` justification comments; `lll` would catch them once the config is valid.
### Consequences for this issue
- Expect **substantially more** than a handful of new findings once the canonical config actually loads. Budget accordingly; this may not fit one commit. If it does not, split into "adopt config + linter version" and "fix the findings" and note the split here.
- The definition of done already requires `sha256sum backend/.golangci.yml` to equal `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`. Add one verification step: after copying, run the linter's own config verification and confirm it reports the config valid. A config that fails to verify must never be committed again.
- The three `lll` violations above are in scope.
This also raises the priority of this issue above the other compliance items: until the config is valid, no other issue's "lint passes" claim can be trusted.
Branch feat/golangci-standard-config off main at fbfe1df.
Copy the org standard .golangci.yml verbatim over backend/.golangci.yml
(target sha256 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb).
No edits, no added exclusions.
Repoint the golangci-lint pin in Dockerfile.backend from 9f61b0f53f80672872fced07b6874397c3ed197b to c0d3ddc9cf3faa61a4e378e879ece580256d76e5, and update the comment above it
to # golangci-lint v2.12.2 (2026-08-09).
Make the config-validity check permanent rather than a one-off manual step.
The escalation asks for golangci-lint config verify to be run after
copying; a one-time run does not stop the schema from rotting again. So backend/Makefile's lint target gains a golangci-lint config verify
line ahead of golangci-lint run ./.... From then on make lint — and
therefore make check, the pre-commit hook, and the Docker build — fails on
an invalid config instead of silently falling back to defaults. This also
keeps the verification reachable through a make target, so nothing has to
invoke the linter by hand.
Fix every surfaced finding in the Go source. No .golangci.yml edits.
Update TODO.md in the same commit, correcting the stale Status/Next Step
(it still describes feat/reportbuf-storage as unmerged; it is merged).
Gate on cd backend && make check, root make check, and docker build -f Dockerfile.backend . (via make docker, which is what
exercises the pinned v2.12.2 rather than whatever is on the local PATH).
Scope note on the three lines called out in the escalation
The canonical config sets lll.line-length: 88, so of the three lines listed
only one is an actual lint finding:
internal/server/server.go:65 — 93 chars, is an lll finding.
internal/server/server.go:97 — 81 chars, under 88, not reported.
internal/reportbuf/reportbuf.go:166 — 88 chars, exactly at the limit, not
reported.
All three do violate the 77-column hard wrap in CODE_STYLEGUIDE_GO.md, and
the escalation puts all three in scope, so all three get wrapped. In each case
the length comes from a long //nolint justification on the code line; the fix
is to move the justification to a preceding comment block and leave a short //nolint:linter // see comment above on the line itself. The suppressions
themselves are unchanged in meaning and are not being widened.
Expected outcome: one commit, no split needed. Will report back if the v2.12.2
run inside the Docker build surfaces materially more than the local v2.10.1 run
did.
## Implementation plan
Branch `feat/golangci-standard-config` off `main` at `fbfe1df`.
1. Copy the org standard `.golangci.yml` verbatim over `backend/.golangci.yml`
(target sha256 `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`).
No edits, no added exclusions.
2. Repoint the golangci-lint pin in `Dockerfile.backend` from
`9f61b0f53f80672872fced07b6874397c3ed197b` to
`c0d3ddc9cf3faa61a4e378e879ece580256d76e5`, and update the comment above it
to `# golangci-lint v2.12.2 (2026-08-09)`.
3. Make the config-validity check permanent rather than a one-off manual step.
The escalation asks for `golangci-lint config verify` to be run after
copying; a one-time run does not stop the schema from rotting again. So
`backend/Makefile`'s `lint` target gains a `golangci-lint config verify`
line ahead of `golangci-lint run ./...`. From then on `make lint` — and
therefore `make check`, the pre-commit hook, and the Docker build — fails on
an invalid config instead of silently falling back to defaults. This also
keeps the verification reachable through a `make` target, so nothing has to
invoke the linter by hand.
4. Fix every surfaced finding in the Go source. No `.golangci.yml` edits.
5. Update `TODO.md` in the same commit, correcting the stale Status/Next Step
(it still describes `feat/reportbuf-storage` as unmerged; it is merged).
6. Gate on `cd backend && make check`, root `make check`, and
`docker build -f Dockerfile.backend .` (via `make docker`, which is what
exercises the pinned v2.12.2 rather than whatever is on the local PATH).
### Scope note on the three lines called out in the escalation
The canonical config sets `lll.line-length: 88`, so of the three lines listed
only one is an actual lint finding:
- `internal/server/server.go:65` — 93 chars, **is** an `lll` finding.
- `internal/server/server.go:97` — 81 chars, under 88, not reported.
- `internal/reportbuf/reportbuf.go:166` — 88 chars, exactly at the limit, not
reported.
All three do violate the 77-column hard wrap in `CODE_STYLEGUIDE_GO.md`, and
the escalation puts all three in scope, so all three get wrapped. In each case
the length comes from a long `//nolint` justification on the code line; the fix
is to move the justification to a preceding comment block and leave a short
`//nolint:linter // see comment above` on the line itself. The suppressions
themselves are unchanged in meaning and are not being widened.
Expected outcome: one commit, no split needed. Will report back if the v2.12.2
run inside the Docker build surfaces materially more than the local v2.10.1 run
did.
The escalation warned to budget for "substantially more" findings once the
canonical config actually loaded, and to split into "adopt config + linter
version" and "fix the findings" if it did not fit one commit. It fit: with the
standard config loading correctly under v2.12.2 the backend produced exactly one finding, lll on internal/server/server.go:65.
The linters that had been silently inert under the broken config — funlen, cyclop, dupl, and lll at its real 88-column threshold instead of the
120-column default — had nothing further to report. The backend is small
enough that the defaults it had been accidentally linted against were not far
off the intended thresholds.
Two corrections to the escalation's line inventory, for the record:
internal/server/server.go:97 (81 cols) and internal/reportbuf/reportbuf.go:166 (88 cols) are notlll findings.
The canonical config sets lll.line-length: 88, and lll reports lines
strictly over the limit, so 81 passes and 88 sits exactly at it.
They do violate the 77-column hard wrap in CODE_STYLEGUIDE_GO.md, and the
escalation explicitly scoped them in, so both were wrapped alongside the
genuine finding.
All three were long //nolint justifications on the code line; each
justification moved to a comment block above, leaving a short directive behind.
No suppression added or widened, and .golangci.yml untouched after the
verbatim copy.
On the verification requirement: rather than running golangci-lint config verify once by hand, it is now the first step of the backend lint target, so
it runs on every make check, every pre-commit, and every Docker build. An
invalid config fails the build from now on instead of silently degrading to
defaults — which is the failure this issue exists to close out.
## No split needed — delivered as one PR
PR #31 on branch `feat/golangci-standard-config`.
The escalation warned to budget for "substantially more" findings once the
canonical config actually loaded, and to split into "adopt config + linter
version" and "fix the findings" if it did not fit one commit. It fit: with the
standard config loading correctly under v2.12.2 the backend produced exactly
**one** finding, `lll` on `internal/server/server.go:65`.
The linters that had been silently inert under the broken config — `funlen`,
`cyclop`, `dupl`, and `lll` at its real 88-column threshold instead of the
120-column default — had nothing further to report. The backend is small
enough that the defaults it had been accidentally linted against were not far
off the intended thresholds.
Two corrections to the escalation's line inventory, for the record:
- `internal/server/server.go:97` (81 cols) and
`internal/reportbuf/reportbuf.go:166` (88 cols) are **not** `lll` findings.
The canonical config sets `lll.line-length: 88`, and `lll` reports lines
strictly over the limit, so 81 passes and 88 sits exactly at it.
- They do violate the 77-column hard wrap in `CODE_STYLEGUIDE_GO.md`, and the
escalation explicitly scoped them in, so both were wrapped alongside the
genuine finding.
All three were long `//nolint` justifications on the code line; each
justification moved to a comment block above, leaving a short directive behind.
No suppression added or widened, and `.golangci.yml` untouched after the
verbatim copy.
On the verification requirement: rather than running `golangci-lint config
verify` once by hand, it is now the first step of the backend `lint` target, so
it runs on every `make check`, every pre-commit, and every Docker build. An
invalid config fails the build from now on instead of silently degrading to
defaults — which is the failure this issue exists to close out.
My escalation listed three lines as lll violations that would surface once the canonical config loaded. Two of those three were wrong, and the implementer was right to push back rather than accept the list as given.
Verified directly against the canonical config at /home/user/dev/prompts/.golangci.yml:
lll:line-length:88
lll reports lines strictly over 88. So:
Line
Length
lll finding?
internal/server/server.go:65
93
Yes — correctly predicted
internal/server/server.go:97
81
No — under the limit
internal/reportbuf/reportbuf.go:166
88
No — at the limit, not over it
Where my escalation went wrong: I carried over the audit's framing, which measured those lines against the 77-column hard-wrap guidance in CODE_STYLEGUIDE_GO.md ("Try to hard wrap long lines at 77 characters or less") and then described them as things lll would catch. Those are two different standards. 77 is styleguide guidance; 88 is what the linter actually enforces. Conflating them produced a false prediction, and the "expect substantially more findings" warning that followed was built on the same overreach.
The implementer wrapped all three anyway, which is fine — the escalation explicitly scoped them in, and they do violate the 77-column guidance even though only one violates lll. But the single real lll finding is the honest count, and the anticipated second PR was correctly not created.
Recording this because the wrong claim is durable once it is in the tracker, and because the general lesson applies to the rest of this backlog: several other issues I filed cite audit findings I did not personally re-derive. Implementers should verify the specific line numbers and thresholds in an issue against the source before treating them as fact — and say so when they do not hold up, as happened here.
None of this changes the definition of done or the core finding: the previous config was genuinely schema-invalid and genuinely inert, and that part stands.
## Correction to my earlier escalation comment
My escalation listed three lines as `lll` violations that would surface once the canonical config loaded. **Two of those three were wrong**, and the implementer was right to push back rather than accept the list as given.
Verified directly against the canonical config at `/home/user/dev/prompts/.golangci.yml`:
```yaml
lll:
line-length: 88
```
`lll` reports lines strictly over 88. So:
| Line | Length | `lll` finding? |
| --- | --- | --- |
| `internal/server/server.go:65` | 93 | **Yes** — correctly predicted |
| `internal/server/server.go:97` | 81 | **No** — under the limit |
| `internal/reportbuf/reportbuf.go:166` | 88 | **No** — at the limit, not over it |
Where my escalation went wrong: I carried over the audit's framing, which measured those lines against the **77-column hard-wrap guidance in `CODE_STYLEGUIDE_GO.md`** ("Try to hard wrap long lines at 77 characters or less") and then described them as things `lll` would catch. Those are two different standards. 77 is styleguide guidance; 88 is what the linter actually enforces. Conflating them produced a false prediction, and the "expect substantially more findings" warning that followed was built on the same overreach.
The implementer wrapped all three anyway, which is fine — the escalation explicitly scoped them in, and they do violate the 77-column guidance even though only one violates `lll`. But the single real `lll` finding is the honest count, and the anticipated second PR was correctly not created.
Recording this because the wrong claim is durable once it is in the tracker, and because the general lesson applies to the rest of this backlog: several other issues I filed cite audit findings I did not personally re-derive. Implementers should verify the specific line numbers and thresholds in an issue against the source before treating them as fact — and say so when they do not hold up, as happened here.
None of this changes the definition of done or the core finding: the previous config was genuinely schema-invalid and genuinely inert, and that part stands.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
This repo is not on the org-standard Go lint configuration, and the linter version pinned in the backend Docker build is two minor versions behind what is now deployed across the org's Go repos.
Verified on
mainatfbfe1df:.golangci.ymlcontent mismatch.REPO_POLICIES.mdstates: ".golangci.ymlis standardized and must NEVER be modified by an agent, only manually by the user. Fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml."Linter version mismatch.
Dockerfile.backendpins golangci-lint at commit9f61b0f53f80672872fced07b6874397c3ed197b(v2.7.2, dated 2026-02-27). The org standard is v2.12.2, commitc0d3ddc9cf3faa61a4e378e879ece580256d76e5.make checkinbackend/currently reports0 issues.against the non-standard config. Moving to the stricter standard config plus a newer linter is expected to surface new findings; fixing those findings is part of this work unit.Definition of done
backend/.golangci.ymlis byte-identical to the org standard —sha256sum backend/.golangci.ymloutputs021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb. Copy it verbatim; do not hand-edit, tune, or add exclusions to it.Dockerfile.backendpins golangci-lint to commitc0d3ddc9cf3faa61a4e378e879ece580256d76e5, with a comment above the reference reading the version and date in the form# golangci-lint v2.12.2 (YYYY-MM-DD)per the hash-pinning policy..golangci.ymlis explicitly forbidden. A targeted//nolint:linter // reasonon an individual line is acceptable only where the finding is genuinely a false positive, and each one must carry a written justification comment.cd backend && make checkpasses and reports0 issues.make checkat the repo root still passes.docker build -f Dockerfile.backend .succeeds.TODO.mdis updated in the same commit as the work.(closes #N)for this issue number.Implementation requirements
maketargets andscript/entrypoints only. Never invokego,gofmt, orgolangci-lintdirectly..golangci.ymlin any way after copying it. If the standard config disagrees with the code, the code changes.Escalation: the current config is not merely non-standard, it is invalid and silently inert
Follow-up audit found the problem is worse than a hash mismatch.
backend/.golangci.ymldeclaresversion: "2"on line 1 but uses golangci-lint v1 schema below it:linters-settings:key. In v2 this moved tolinters.settings:.issues.exclude-use-default: false, which does not exist in v2 and is absent from the canonical file.Verified empirically with golangci-lint v2.10.1:
Why this matters more than the version bump
Every threshold in the file is inert:
lll: 88,funlen: 80/50,cyclop: 15,dupl: 100are all ignored.lllfalls back to its default of 120 columns.So when
cd backend && make checkprints0 issues., that is not evidence the code is clean — it is evidence the linter ran with defaults and found nothing at defaults. The green result we have been relying on is meaningless.Concretely, three lines already exceed the 77-character hard wrap required by
CODE_STYLEGUIDE_GO.md, and go unreported today:internal/server/server.go:65— 93 charsinternal/server/server.go:97— 81 charsinternal/reportbuf/reportbuf.go:166— 88 charsAll three are long
//nolintjustification comments;lllwould catch them once the config is valid.Consequences for this issue
sha256sum backend/.golangci.ymlto equal021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb. Add one verification step: after copying, run the linter's own config verification and confirm it reports the config valid. A config that fails to verify must never be committed again.lllviolations above are in scope.This also raises the priority of this issue above the other compliance items: until the config is valid, no other issue's "lint passes" claim can be trusted.
Implementation plan
Branch
feat/golangci-standard-configoffmainatfbfe1df.Copy the org standard
.golangci.ymlverbatim overbackend/.golangci.yml(target sha256
021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb).No edits, no added exclusions.
Repoint the golangci-lint pin in
Dockerfile.backendfrom9f61b0f53f80672872fced07b6874397c3ed197btoc0d3ddc9cf3faa61a4e378e879ece580256d76e5, and update the comment above itto
# golangci-lint v2.12.2 (2026-08-09).Make the config-validity check permanent rather than a one-off manual step.
The escalation asks for
golangci-lint config verifyto be run aftercopying; a one-time run does not stop the schema from rotting again. So
backend/Makefile'slinttarget gains agolangci-lint config verifyline ahead of
golangci-lint run ./.... From then onmake lint— andtherefore
make check, the pre-commit hook, and the Docker build — fails onan invalid config instead of silently falling back to defaults. This also
keeps the verification reachable through a
maketarget, so nothing has toinvoke the linter by hand.
Fix every surfaced finding in the Go source. No
.golangci.ymledits.Update
TODO.mdin the same commit, correcting the stale Status/Next Step(it still describes
feat/reportbuf-storageas unmerged; it is merged).Gate on
cd backend && make check, rootmake check, anddocker build -f Dockerfile.backend .(viamake docker, which is whatexercises the pinned v2.12.2 rather than whatever is on the local PATH).
Scope note on the three lines called out in the escalation
The canonical config sets
lll.line-length: 88, so of the three lines listedonly one is an actual lint finding:
internal/server/server.go:65— 93 chars, is anlllfinding.internal/server/server.go:97— 81 chars, under 88, not reported.internal/reportbuf/reportbuf.go:166— 88 chars, exactly at the limit, notreported.
All three do violate the 77-column hard wrap in
CODE_STYLEGUIDE_GO.md, andthe escalation puts all three in scope, so all three get wrapped. In each case
the length comes from a long
//nolintjustification on the code line; the fixis to move the justification to a preceding comment block and leave a short
//nolint:linter // see comment aboveon the line itself. The suppressionsthemselves are unchanged in meaning and are not being widened.
Expected outcome: one commit, no split needed. Will report back if the v2.12.2
run inside the Docker build surfaces materially more than the local v2.10.1 run
did.
No split needed — delivered as one PR
PR #31 on branch
feat/golangci-standard-config.The escalation warned to budget for "substantially more" findings once the
canonical config actually loaded, and to split into "adopt config + linter
version" and "fix the findings" if it did not fit one commit. It fit: with the
standard config loading correctly under v2.12.2 the backend produced exactly
one finding,
llloninternal/server/server.go:65.The linters that had been silently inert under the broken config —
funlen,cyclop,dupl, andlllat its real 88-column threshold instead of the120-column default — had nothing further to report. The backend is small
enough that the defaults it had been accidentally linted against were not far
off the intended thresholds.
Two corrections to the escalation's line inventory, for the record:
internal/server/server.go:97(81 cols) andinternal/reportbuf/reportbuf.go:166(88 cols) are notlllfindings.The canonical config sets
lll.line-length: 88, andlllreports linesstrictly over the limit, so 81 passes and 88 sits exactly at it.
CODE_STYLEGUIDE_GO.md, and theescalation explicitly scoped them in, so both were wrapped alongside the
genuine finding.
All three were long
//nolintjustifications on the code line; eachjustification moved to a comment block above, leaving a short directive behind.
No suppression added or widened, and
.golangci.ymluntouched after theverbatim copy.
On the verification requirement: rather than running
golangci-lint config verifyonce by hand, it is now the first step of the backendlinttarget, soit runs on every
make check, every pre-commit, and every Docker build. Aninvalid config fails the build from now on instead of silently degrading to
defaults — which is the failure this issue exists to close out.
Correction to my earlier escalation comment
My escalation listed three lines as
lllviolations that would surface once the canonical config loaded. Two of those three were wrong, and the implementer was right to push back rather than accept the list as given.Verified directly against the canonical config at
/home/user/dev/prompts/.golangci.yml:lllreports lines strictly over 88. So:lllfinding?internal/server/server.go:65internal/server/server.go:97internal/reportbuf/reportbuf.go:166Where my escalation went wrong: I carried over the audit's framing, which measured those lines against the 77-column hard-wrap guidance in
CODE_STYLEGUIDE_GO.md("Try to hard wrap long lines at 77 characters or less") and then described them as thingslllwould catch. Those are two different standards. 77 is styleguide guidance; 88 is what the linter actually enforces. Conflating them produced a false prediction, and the "expect substantially more findings" warning that followed was built on the same overreach.The implementer wrapped all three anyway, which is fine — the escalation explicitly scoped them in, and they do violate the 77-column guidance even though only one violates
lll. But the single reallllfinding is the honest count, and the anticipated second PR was correctly not created.Recording this because the wrong claim is durable once it is in the tracker, and because the general lesson applies to the rest of this backlog: several other issues I filed cite audit findings I did not personally re-derive. Implementers should verify the specific line numbers and thresholds in an issue against the source before treating them as fact — and say so when they do not hold up, as happened here.
None of this changes the definition of done or the core finding: the previous config was genuinely schema-invalid and genuinely inert, and that part stands.
clawbot referenced this issue2026-09-04 00:30:19 +02:00
clawbot referenced this issue2026-09-04 00:31:43 +02:00