go-lint-regression-noctx-goconst
Problem: 10 new golangci-lint v2 issues (noctx ×6, goconst ×3, goimports ×1) were introduced by the new SPEC-GAP-002 files. Three mechanical fixes:
context.Context through production code; call sites use context.Background()noctx rejects http.NewRequest and the non-Context database/sql methods. Production functions gain a ctx context.Context parameter:
// internal/tests/specgap002.go
func (c *Client) ping(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.base, nil) // was http.NewRequest
...
}
func (c *Client) post(ctx context.Context, body string) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.base, nil)
...
}
func ingest(ctx context.Context, db *sql.DB, id string) error {
_, err := db.ExecContext(ctx, "INSERT INTO items (id) VALUES (?)", id) // was db.Exec
return err
}
Tests pass a fresh context (the exact pattern named in the ticket):
// internal/tests/specgap002_test.go
ctx := context.Background()
c.ping(ctx) // was c.ping()
db.ExecContext(ctx, "CREATE TABLE items (id TEXT)") // was db.Exec
db.QueryContext(ctx, "SELECT id FROM items") // was db.Query
db.QueryRowContext(ctx, "SELECT count(*) FROM items").Scan(&count) // was db.QueryRow
"error" with the existing events.EventLevelError constant// internal/tests/specgap002_extra.go
import "example.com/specgap/internal/events"
func classify(severity int) events.Level { // was string, returning "error" x3
switch {
case severity > 10:
return events.EventLevelError
case severity > 5:
return events.EventLevelError
default:
return events.EventLevelError
}
}
Same replacement in specgap002_test.go (test table want field retyped to events.Level) and specgap002_more_test.go. No new constant defined — the existing one from the events package is reused, so the 3 repeated literals collapse to a single canonical symbol.
Out-of-order import block (net/http before database/sql) re-sorted alphabetically, third-party group separated by blank line:
import (
"context"
"database/sql"
"net/http"
"time"
"example.com/specgap/internal/events" // only in files that reference it
)
Applied via gofmt -w (goimports formatting is a formatters entry in v2 config, not linters).
Reproduced the exact scenario in a scratch repo (`/tmp/specgap`) with the parent commit holding the existing `events.EventLevelError` constant and the new SPEC-GAP-002 files added on top, then ran the **exact CI gate**: | Gate | RED (before fix) | GREEN (after fix) | |---|---|---| | `golangci-lint run --new-from-rev <parent>` | **10 issues** — `noctx: 6`, `goconst: 3`, `goimports: 1` | **0 issues**, exit 0 | | `golangci-lint run` (full) | — | **0 issues** | | `go test ./...` | — | **ok** (5 top-level tests, 8 with subtests) | | `gofmt -l .` | — | clean | The 10 RED issues matched the ticket count exactly, confirming the reproduction is faithful: ``` internal/tests/specgap002.go:22:29: net/http.NewRequest must not be called. use net/http.NewRequestWithContext (noctx) internal/tests/specgap002.go:39:29: net/http.NewRequest must not be called. use net/http.NewRequestWithContext (noctx) internal/tests/specgap002.go:64:19: (*database/sql.DB).Exec must not be called. use ExecContext (noctx) internal/tests/specgap002_test.go:41:22: (*database/sql.DB).Exec must not be called. use ExecContext (noctx) internal/tests/specgap002_test.go:48:23: (*database/sql.DB).Query must not be called. use QueryContext (noctx) internal/tests/specgap002_test.go:55:23: (*database/sql.DB).QueryRow must not be called. use QueryRowContext (noctx) * noctx: 6 * goconst: 3 * goimports: 1 ``` **Edge cases tested:** - **`--new-from-rev` scope**: the gate is commit-scoped — pre-existing files (e.g. `internal/events/events.go` with the `EventLevelError` constant) are correctly not flagged; only the 3 new SPEC-GAP-002 files were in scope, and only they were touched. - **goconst per-file granularity**: goconst reports one issue per (file, string) pair — verified empirically that 3 occurrences in one file = 1 issue; the fix collapses all occurrences to the shared `events.EventLevelError`, so no residual occurrences survive anywhere in the package. - **Test-file goconst leakage**: after the fix, `TestClassify`'s table uses `events.EventLevelError` (typed `events.Level`) — a constant expression, never flagged; distinct literals like `"SPEC-GAP-002 critical"` are not repeated so they don't trip goconst. - **Runtime behavior preserved**: `go test` exercises every fixed call path — `ping`/`post` against `httptest.Server` (200 and 502 paths), `ingest` via `ExecContext`, `QueryContext` row iteration, and `QueryRowContext` scan — all passing with `context.Background()`. - **Driver-less test setup**: the demo DB uses a self-contained stub driver (in `_test.go`) so no external sqlite dependency is needed; it also passes the same lint gate (no context-less calls in the stub itself). - **Regression risk**: `context.Background()` in tests is safe because no test needs cancellation/deadlines; a future cancellation-aware test should swap in `t.Context()` (Go 1.24+), which is a drop-in. **Key files:** `internal/tests/specgap002.go`, `specgap002_test.go`, `specgap002_extra.go`, `specgap002_more_test.go` (plus `stubdriver_test.go` for the demo harness). The only production-signature change is the added `ctx` parameter on `ping`/`post`/`ingest` — call sites in other SPEC-GAP-002 code (not in this demo) must pass `context.Background()` or a real request context accordingly. ---
{"model": "deepseek-v4-flash", "problem_class": "go-lint-regression-noctx-goconst", "result": "passed", "tests": 5}