Follow this sequence in order. Do not emit findings until every Pass below is satisfied.
Baseline go.mod — Open go.mod and read the go directive.
Pass: You can state the exact go X.YY value (in the review preamble or working notes). Apply version-gated advice only when it matches this baseline (loop capture pre-1.22, slog/structured logging from 1.21, errors.Join from 1.20).
Read surrounding code — For each changed .go file, read full functions or logical units that contain the edits, not only the diff hunk.
Pass: At least one full enclosing function (or package-level init/var block) containing the change was read per changed file.
Scope the checklist — Decide which Review Checklist blocks apply (error handling, concurrency, interfaces/types, resources, naming). Load references for those blocks; skip blocks that are irrelevant to the diff.
Pass: The review (or working notes) lists which checklist blocks you applied, or marks blocks N/A with a one-line reason tied to the diff (e.g. “no concurrency in change”).
Pre-report verification — Load and follow review-verification-protocol.
Pass: The protocol’s Pre-Report Verification Checklist is satisfied for each finding you will report (actual code read, surrounding context checked, “wrong” vs “different style” distinguished, etc.).
StepObjective pass condition1go X.YY from go.mod is recorded before version-specific advice.2Full enclosing context read per changed file, not diff-only.3In-scope checklist blocks listed or N/A with diff-tied reason; references opened as needed.4review-verification-protocol completed for every reported issue.
Report findings as:
text
[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.
Issue TypeReferenceMissing error checks, wrapping, errors.Joinreferences/error-handling.mdRace conditions, channel misuse, goroutine lifecyclereferences/concurrency.mdInterface pollution, naming, genericsreferences/interfaces.mdResource leaks, defer misuse, slog, namingreferences/common-mistakes.md
_ = err without justifying comment)fmt.Errorf("...: %w", err))errors.Is/ errors.As used instead of string matchingerrors.Join used for aggregating multiple errors (Go 1.20+)-er conventionany preferred over interface{} (Go 1.18+)any or code generationdefer immediately after creationdefer in loops without closure wrappinginit() functions avoided in favor of explicit initializationuser.UserService → user.Service)slog used over log for structured logging (Go 1.21+)return err)panic for recoverable errorsinterface{} instead of any in Go 1.18+ codebasesThese are acceptable Go patterns — reporting them wastes developer time:
_ = err with reason comment — Intentionally ignored errors with explanationany — For truly generic code or interop with untyped APIs//nolint directives with reason — Acceptable when accompanied by explanationtype Option func(*T) with With* constructors is idiomaticsync.Pool for hot paths — Acceptable for reducing allocation pressure in performance-critical codecontext.Background() in main/tests — Valid root context for top-level callsselect with default — Non-blocking channel operation, intentional patterni, err, ctx, ok are idiomatic GoOnly flag these issues when the specific conditions apply:
IssueFlag ONLY IFMissing error checkError return is actionable (can retry, log, or propagate)Goroutine leakNo context cancellation path exists for the goroutineMissing deferResource isn't explicitly closed before next acquisition or returnInterface pollutionInterface has > 1 method AND only one consumer existsLoop variable capturego.mod specifies Go < 1.22Missing sloggo.mod specifies Go >= 1.21 AND code uses log package for structured output
Satisfy step 4 in Review Workflow: load review-verification-protocol and complete its pre-report checks for each issue.