Files
pad/.github/workflows
xarmian e5e2bd7b86 chore: flip CI only-new-issues=false + scope lint policy (TASK-771) (#253)
* chore: gate CI on full lint, scoped to checks we enforce (TASK-771)

Flip golangci-lint-action's only-new-issues from true to false so CI
fails on ANY linter finding, not just findings on PR-changed lines.
This catches lint regressions on the next push instead of letting them
drift into main.

The gate flip is paired with a deliberate scope-down of .golangci.yml:

1. errcheck is disabled. The codebase has 325 pre-existing unchecked-
   error sites where the error is intentionally discarded (best-effort
   logging writes, defensive parses with zero-valued fallbacks, etc.).
   Auditing every site is its own project — bigger than IDEA-732 by
   an order of magnitude. Tracked as a follow-up if/when we want the
   safety net back.

2. staticcheck is restricted to the SA* check family (real-bug
   detectors). The ST*/QF*/S* families are stylistic/quick-fix
   suggestions we don't gate CI on yet — they would have re-flooded
   the lint output with capitalized error strings, De Morgan's law
   simplification suggestions, etc., that aren't bug-finding signals.
   Re-enable selectively if the team wants them.

After scoping, the live linters are: govet, ineffassign, staticcheck
(SA*), unused, gofmt — exactly the set that IDEA-732 cleaned up.

Other changes in this PR:

- Drop pull-requests:read permission. It was only required by the
  golangci-lint-action when only-new-issues=true (the action used it
  to fetch PR diff metadata). Not needed any more.
- Update the Run-golangci-lint comment block to explain the new
  policy and reference the IDEA-732 cleanup PRs (#247/#249/#251/#252).
- Replace the SA4017 //lint:ignore directive in cmd/pad/main.go:4631
  with an inline //nolint:staticcheck — the multi-line //lint:ignore
  block was too far from the if statement for staticcheck's
  proximity rule, so the directive wasn't taking effect.
- Apply gofmt -w on three files where post-deletion blank-line
  artifacts had drifted (cmd/pad/main.go imports, two trailing newline
  fix-ups in handlers_items.go and middleware_ratelimit.go).

Verified:
- `golangci-lint run ./...` reports 0 issues.
- `go build ./...` clean.
- `go vet ./...` clean.
- `go test ./...` all pass.

Parent: PLAN-644.

* chore: address Codex round 1 on PR #253 (TASK-771)

Two LOWs from Codex on the gate-flip PR:

1. //nolint:staticcheck was broader than necessary (suppressed any
   future staticcheck diagnostic on the line) and didn't self-report
   when the underlying false positive gets fixed upstream. Codex
   suggested swapping back to a tightly-placed //lint:ignore SA4017.

   I tried that, but golangci-lint v2's staticcheck integration does
   not honour //lint:ignore the way direct staticcheck does — the
   directive was silently no-op'd via golangci-lint while the same
   directive worked when staticcheck was invoked directly.

   So instead of fighting the linter wrapper, sidestep the false
   positive entirely: rewrite the keepalive check from
   `strings.HasPrefix(line, ":")` to `len(line) > 0 && line[0] == ':'`.
   Same observable behaviour for a single-byte ASCII prefix, no
   suppression directive needed at all, no exposure when staticcheck
   eventually fixes the false positive.

2. The new lint-step comment in ci.yml said main is "clean of
   staticcheck SA*/U1000" — but U1000 is reported by the standalone
   `unused` linter in .golangci.yml, not by staticcheck.checks.
   Tighten the comment to attribute each enforced check correctly.

Verified:
- `golangci-lint run ./...` reports 0 issues
- `go test ./cmd/pad/...` passes (the SSE watch loop is exercised by
  reconcile_test.go and the broader integration tests).
2026-04-25 12:36:05 -04:00
..