.claude/skills/review-scaffold/SKILL.md
Review a scaffold PR
npx skillsauth add viqueen/claude-go-playground .claude/skills/review-scaffoldInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Audit a scaffold PR. Answer the question: "Does the structure match our architecture?"
Fetch the PR diff:
gh pr diff <number>
Identify the project from the PR file paths: connect-rpc-backend/ or grpc-backend/.
Check every item below. For each, report PASS or FAIL with a brief explanation. Items marked (Connect-RPC) or (gRPC) only apply to the corresponding project.
.gitignore covers gen/, .env, tmp/go.mod exists with a valid module pathMakefile has targets: codegen, tidy, vet, build, test, infra, start, debug, teardown, cleanMakefile target dependencies: tidy → codegen, vet → tidy, build → vet, test → vet, start → infra, debug → infraMakefile codegen uses docker build --target generate (not docker compose)Makefile start runs go tool air, debug runs go tool air -c .air.debug.tomlgo.mod has tool directives for github.com/air-verse/air and github.com/go-delve/delve/cmd/dlvDockerfile is multi-stage: generate (buf + sqlc) → build → runtimeDockerfile codegen tool installs use pinned versions (not @latest)Dockerfile generate stage copies from protos/ (not api/)Dockerfile buf/sqlc generate steps are conditional (skip when no protos or empty sql list)docker-compose.yml has infra only: postgres, opensearch, opensearch-dashboards (no app services)docker-compose.yml postgres has a healthcheck.air.toml watches go and sql files, builds cmd/server, excludes gen/ and tmp/.air.debug.toml builds with -gcflags='all=-N -l', runs via dlv exec on port 2345buf.gen.yaml uses v2 config with managed modebuf.gen.yaml go_package_prefix points to <module>/gen/sdkbuf.gen.yaml uses correct plugin for framework: connectrpc/go (Connect-RPC) or go-grpc (gRPC)buf.gen.yaml plugins output to gen/sdksqlc.yaml exists with empty sql: [] list.env has defaults for DATABASE_URL, OPENSEARCH_URL, SERVER_ADDRpkg/config — Config struct with Load() using godotenvpkg/connectapp — App interface with Handle() + Run(), h2c server, /health endpointpkg/connectutil/errors.go — NewErrorFrom(err, mappings) maps sentinel errors to connect codespkg/connectutil/interceptors.go — NewInterceptors() returns recovery + logging + validatepkg/grpcapp — App interface with Server() + Run(), native gRPC server, health check, reflectionpkg/connectutil/errors.go — NewErrorFrom has nil guard for errpkg/grpcutil/errors.go — NewErrorFrom(err, mappings) maps sentinel errors to gRPC status codes, has nil guardpkg/grpcutil/interceptors.go — NewServerOpts() returns ([]grpc.ServerOption, error), no panicspkg/grpcapp/app.go — health sidecar binds listener before goroutine (fail-fast on port conflict)pkg/cache — Cache[K,V] interface with in-memory implementation that evicts expired entries on Getpkg/outbox — Outbox[T] interface + Event struct, no implementationpkg/migrate — goose wrapper with Run(db, migrations, dir)pkg/ packages follow interface-first convention: interfaces exported, structs unexportedpkg/ has zero dependencies on internal/, cmd/, or gen/main.go — signal context, config load, setup calls, runsetup_connections.go — Connections struct with Pool + RiverClient, Close() uses fresh shutdown context (not the signal ctx)setup_connections.go — runs both river migrations and goose migrationssetup_connections.go — River workers bundle has at least one worker (placeholder)setup_domains.go — empty Domains struct, setupDomains() returns itsetup_gateway.go — creates connectapp.App, no handlers registered yetsetup_gateway.go — creates grpcapp.App with grpcutil.NewServerOpts(), no services registered yetmigrations.go with //go:embed directive.sql file (placeholder, version > 0) so the embed directive resolvesinternal/api/, internal/domain/, internal/outbox/pkg/ — exported helpers return errors, callers handle them at the boundaryprotos/sql/queries/Domains struct has zero fields## Scaffold PR Audit
### Summary
<one sentence: pass or issues found>
### Results
| Check | Status | Notes |
|-------|--------|-------|
| .gitignore | PASS | |
| go.mod | PASS | |
| ... | FAIL | <explanation> |
### Issues
<numbered list of FAIL items with details and suggested fixes>
gh pr diff $ARGUMENTSgh pr view $ARGUMENTS --json number,title,body,state,baseRefName,headRefName,urltesting
Review a test PR
tools
Review a search indexing PR
tools
Review a proto PR
tools
Review an integration PR