Lesson 30 of 34 intermediate 5 min read

The make vet test gate

Key takeaways Unit 6 studies quality practice in a real codebase. GopherTrunk’s foundation is one rule: make vet test must be green before any commit — static analysis plus the full unit suite, bundled into one command so there’s nothing to remember, skip, or half-run. Slow suites are split into make integration so the gate stays fast enough to obey. The rule is per-commit because commits are what people build on, bisect through, and ship from — and it’s non-negotiable because a gate with exceptions isn’t a gate.

Five units of concepts; one unit of practice. Everything from here on is how a real, working codebase — the one this site documents — wires those concepts into daily habit. It starts with the smallest possible policy, which does the most work.

One command, one answer

GopherTrunk’s contributor documentation reduces the whole of Units 2 and 4 to a single line:

make vet test    # must be green before any commit

Under the hood it’s exactly what this module taught, run across the whole repo: go vet first, then the unit suite. While iterating you run single packages (go test ./internal/scanner/ccdecoder/...); before committing, you run the gate. (Make targets are just named command recipes — the toolchain lesson covers the plumbing.)

The bundling is the design. A policy of “run vet, and also run the tests” has two halves, and two-halved habits decay into whichever half is remembered. make vet test has no halves: you ran the gate or you didn’t, and the answer is one green or one red. The same one line is simultaneously the habit, the contributor doc, and the CI job — so what you check locally and what the machine enforces can’t drift apart.

The speed contract — and the split it forces

A per-commit gate lives or dies on speed: developers commit many times a day, and a slow gate becomes a skipped gate, then a dead letter. That constraint forces an architecture you’ve already met — the pyramid’s split between fast and slow suites, here made policy:

Command Runs When
go test ./internal/... (one package) The code you’re editing Constantly, while iterating
make vet test Vet + all unit tests Before every commit — must be green
make integration Daemon, replay, end-to-end decode suites When the daemon, DSP, or replay paths changed; in CI

Notice what the split protects in both directions. The gate stays fast because the replay suites — minutes of decoding recorded radio captures — live outside it. And the heavy suites stay run because they have their own named command and their own trigger rule (“touched the daemon or DSP? run it”), instead of being an unenforced “please also remember.”

Why per-commit, and why no exceptions

Per-commit sounds strict until you list what a commit is in a working repository — three roles, each poisoned by a broken one:

  • A base. Teammates branch from it; a red base means everyone starts broken and can’t attribute their own failures — the keep-main-green argument, pushed down to every commit.
  • A bisection sample. git bisect interrogates history commit by commit; each broken commit is a skip, and enough of them turn “the exact commit” into “one of these seven.” A history of green commits is a searchable history — an asset the project buys one gate-run at a time and cashes during its worst debugging days.
  • A shippable point. Releases and rollbacks want to treat any commit as potentially deployable; “green except sometimes” means checking, which means sometimes not checking.

And why tolerate no exceptions — not “it’s just a comment change,” not “I’m in a hurry”? Because exception-granting is a judgment call made exactly when judgment is worst (tired, hurried, sure it’s fine — the builder brain at its most confident), and because each granted exception re-prices the next one. The gate’s entire value is that green is unconditional: anyone can build on, bisect through, or ship from any commit without asking permission or checking provenance. A rule this cheap to follow — seconds per commit — buys that property outright.

Rule of thumb: make the mandatory path one short command, and keep it fast enough that skipping it saves nothing worth having.

Quick check: why aren't GopherTrunk's replay integration suites part of the per-commit make vet test gate?

Recap

  • GopherTrunk’s foundation rule: make vet test green before any commit — vet plus the full unit suite, one command, one answer.
  • Bundling prevents decay: no halves to forget, and habit, docs, and CI share the same line.
  • The speed contract forces the healthy split: fast gate per commit, make integration for the heavy daemon/replay suites with their own trigger rule.
  • Per-commit green keeps every commit buildable-on, bisectable, and shippable — the searchable-history payoff arrives on your worst debugging day.
  • No exceptions, because exceptions are judged by builder brain at its most confident — and a gate with exceptions is a suggestion.

Next up: Replay: testing a radio without a radio

Frequently asked questions

What does GopherTrunk's make vet test actually run?

Two things, in sequence, across the whole repository — go vet’s static analysis, then the full unit-test suite. One command, one green-or-red answer. The project’s standing rule is that it must pass before any commit; the slower daemon and replay integration suites live behind a separate make integration target, run when the daemon, DSP, or replay paths change.

Why bundle vet and the tests into a single command?

Because a gate people must remember two halves of is a gate people half-run. A single memorable command has no partial compliance — you either ran the gate or you didn’t — and the same one line serves as the contributor documentation, the CI recipe, and the habit. Checks that are easy to run completely are the ones that actually get run.

Why is the gate per-commit instead of per-release or per-PR?

Because every commit is a point someone may later build on, bisect through, or ship from. A broken commit poisons all three — most expensively bisection, where a history of sometimes-broken commits can no longer answer “which change broke this?” cleanly. Per-commit green keeps the whole history load-bearing.