Ekho-Labs/ai-coworker · PR #45
APPROVED
Pull request review dashboard

PR #45 — Pre-commit gate mirroring the CI lint job

PR #44 reached CI with govet fieldalignment findings that no local gate had ever checked. This PR wires the repository's existing lint configuration into the commit path, so the verdict arrives before the push rather than after it.

branch feat/pre-commit-lint-gatemain 3 files +38 / −1 no new lint rules · no CI changes

01 The commit path, before and after

The same linter, the same pinned version and the same .golangci.yml in both rows. Only the moment of the verdict moves. Hover or focus any node to trace its edges.

path before this PR success path failure / loop-back hover a node to trace
Before no local gate
verdict after the push
B1
git commit
nothing checked locally
B2
git push
B3
pull request
review requested
B4
CI lint job
golangci-lint v2.12.2 · govet enable-all · .github/workflows/ci.yml
B5
RED BUILD
fieldalignment findings surface here for the first time
B7
re-push
wait for CI again
B6
fix commit
reformat, reorder struct fields
After gate on the commit path
verdict before the push
A1
git commit
the hook runs first
.githooks/pre-commit
A2
[1] gofmt -l
the cheap check runs first, across the whole tree
A3
[2] golangci-lint run ./...
the repository's own .golangci.yml · fails closed when the binary is missing
A4
commit created
only after both gates pass
A5
CI lint passes
same linter, same version, same config — nothing left for CI to discover
F1
commit refused
"run gofmt -w . and restage"
F2
commit refused
findings printed · missing binary prints the make lint-tools hint

02 Three files

A shell hook, a version pin, and the two commands a new clone has to run. Each card expands.

  • gofmt -l runs first because it is cheap: a formatting problem is rejected before the expensive linter is ever started.
  • Then the full golangci-lint run ./... — the same command the CI lint job runs, against the same .golangci.yml.
  • A missing golangci-lint binary fails closed rather than silently skipping. An uninstalled linter would otherwise reintroduce exactly the CI-only failure mode the hook exists to remove.

bypass for a genuine emergency: git commit --no-verify

  • GOLANGCI_LINT_VERSION := v2.12.2 — a single pin, kept beside a comment tying it to .github/workflows/ci.yml.
  • make lint-tools installs exactly the CI version, so a local verdict and a CI verdict cannot diverge on linter version.
  • make hooks sets core.hooksPath to .githooks — one command, once per clone. The hooks themselves stay committed, so they stay in review.
  • The quickstart documents make lint-tools and make hooks immediately after the build and test commands, where a new clone will actually read them.

03 Verification & verdict

CLEAN TREE

A clean tree passes the whole hook in roughly 8s wall time with a warm cache.

LINT GATE

An induced fieldalignment violation blocked a real git commit: exit 1, no commit created.

FORMAT GATE

A misformatted file was stopped at the gofmt stage, before the linter ran.

SELF-APPLIED

This PR's own commit was created through the hook.

APPROVED
Three files move an existing, already-pinned lint configuration onto the commit path. No new lint rules, no CI changes, and a documented emergency bypass.