Review checklist
This is the checklist to run down — by eye, on any diff, yours or an AI’s — after the tools in Verification Tools have run and come back clean. It fits on one printed page on purpose: a checklist nobody actually opens during a review is worthless. Every line links to the lesson that explains why, so this page stays a list, not a re-run of the course.
Errors
Section titled “Errors”- Does every
errorreturn get checked before the value next to it is used? - Is any
errorhandled twice — logged and returned up the stack? See Error Values. - Does a
:=inside anif/foraccidentally shadow an outererr? See Variables & Types. - Is a concrete error type ever assigned to an
error-typed variable and returned as-is? See A nil pointer inside an interface is not nil. - Does every
errors.Ascall pass a pointer (&target), not the target itself? See Wrapping Errors. - Is
recover()called directly inside the deferred function — never through a helper one call away? See Panic and Recover. - Does any package outside
maincalllog.Fataloros.Exit, skipping its callers’defers? See Panic and Recover.
Concurrency
Section titled “Concurrency”- Does every goroutine have a visible exit condition — a closed channel, a cancelled
ctx, or a value it is waiting for? See Goroutines. - Is
wg.Addcalled before the goroutine starts, from the same goroutine that callswg.Wait? See Goroutines. - Does every goroutine that can panic recover from inside itself? See Panic and Recover.
- Is any type containing a
sync.Mutex(or similar) ever used or passed by value? See The sync package. - If a loop launches goroutines or defers closures, does the
go.modgodirective actually guarantee per-iteration variables (1.22+), or is the loop var captured explicitly? See Functions. - Does a bare
breakinsideselectinsideforactually reach the loop it looks like it targets? See Control Flow. - Does background work reuse a request-scoped
context.Contextit should have detached withcontext.WithoutCancel, or get stored in a struct field? See Context.
Resources
Section titled “Resources”- Is every
deferthat closes/unlocks/releases something scoped to one acquisition, not accumulating across a loop? See io and bufio. - Is a resource used (
resp.Body, a file, a lock) only after the error from acquiring it has been checked? See The client side. - Does every
http.Clientused outside a quick script setTimeout? See The client side.
API contract
Section titled “API contract”- Is
resp.StatusCodechecked before the response body is trusted as data? See The client side. - Does
omitemptysit on atime.Timeor struct field expecting it to omit the zero value? See encoding/json. - Does every field the JSON contract needs actually get exported (and tagged)? See encoding/json.
- Is a nil slice returned where the contract requires
[], or vice versa? See encoding/json.
- Does an
appendon a sub-slice risk overwriting a parent slice’s backing array? See Slices. - Is a map ever written to before it has been initialized with
makeor a literal? See Maps. - Does any call site still assume
maps.Keys/maps.Valuesreturn a slice instead of aniter.Seq? See Iterators.
Tooling & style
Section titled “Tooling & style”- Is every
time.Sleep/duration literal explicit about its unit (5 * time.Second, never a bare5)? See time. - Does a new interface have more than one real implementation — or is
any/a concrete type simpler? Isinterface{}used whereanyreads better? Is a receiver named after the type, notthis/self? See Interfaces and Methods.