# Execution: Bring gateway-helper-operator up to house conventions Plan: `docs/plans/2026-10-08-2028-house-conventions.md` - [x] Step 0 — Save and commit the plan - [x] Step 1 — CLAUDE.md - [x] Step 2 — `.claude/` and docs scaffolding - [x] Step 3 — Makefile, lint, formatting - [x] Step 4 — Module path and version identity - [ ] Step 5 — Baseline tests - [ ] Step 6 — CI build workflow - [ ] Step 7 — Close out ## Step 1 — CLAUDE.md Rewrote `CLAUDE.md` in the five-section shape. The Go, Testing, Changelog and Branching text comes from the `go-project-bootstrap` skill references; the plan ordering and execution-summary rules come from `egress-proxies-operator/CLAUDE.md`, condensed from prose into bullets. Deviations from the plan: - The house container rules about Ubuntu dev images and separate dev/prod Dockerfiles were left out: this repo has one production Dockerfile and no dev image, and listing rules nobody follows only adds noise. - The `listener-port` row was removed from the annotation table and moved to Gotchas, so the table lists only what works. - Added a short Reviews subsection so the reviewer agents and `docs/reviews/` have a documented trigger. - `README.md` also claimed that deleting a certificate removes its listeners "instantly". Reworded and added the known limitation. Worth noting: Commands and CI/CD describe the repo as it is at this commit; Steps 3, 4 and 6 update them. `docs/flows.md` cites `main.go` line numbers that Step 4 shifts. ## Step 2 — `.claude/` and docs scaffolding Copied the two reviewer agents and `/ship` from `egress-proxies-operator/.claude/`. `/release` was rewritten for the semver rule instead of copied, because the egress text says "no tagging scheme is documented" and this repo now has one. Deviations from the plan: - `/ship` names "a `Co-Authored-By:` trailer for Claude" instead of the fixed `Claude ` string, matching CLAUDE.md. - `.gitignore` already covered `/bin/` and `*.out`, so only `.claude/settings.local.json` was added. - `settings.json` also allows `kubectl kustomize`, which the Commands section uses. Worth noting: `.claude/settings.json` leaves out `git commit`, `git push` and `git tag` on purpose, but `~/.claude/settings.json` allows `git commit` and `git push` globally, so on this machine the push confirmation rests on CLAUDE.md, not on the permission system. ## Step 3 — Makefile, lint, formatting Added `Makefile` (uh-cli's shape plus `run`, `docker-build` and `-race` on `test`), `.golangci.yml` (v2 defaults) and `.dockerignore` (egress's allowlist). `make lint` failed on first run, before reaching this repo's code: ``` $ golangci-lint run ./... .../go/1.27.1/libexec/src/crypto/internal/randutil/randutil.go:11:2: could not import math/rand/v2 (.../math/rand/v2/rand.go:213:17: method must have no type parameters) (typecheck) ``` The installed golangci-lint 2.12.2 was built with go1.26.4 and cannot type-check the Go 1.27 standard library. The `lint` target now runs under the go.mod toolchain, which is also what CI uses: ```make GO_MOD_VERSION := $(shell awk '$$1 == "go" {print $$2}' go.mod) lint: GOTOOLCHAIN=go$(GO_MOD_VERSION) golangci-lint run ./... ``` With that, lint reported the two expected dead variables (`gatewayGroup`, `gatewayKind` in `patch.go`), which were removed. `make fmt` reformatted `main.go` (import order) and the `patch.go` var block. Worth noting: this is likely the same failure the egress changelog records as "`make lint` is blocked by a Go 1.27 toolchain/staticcheck panic"; the same `GOTOOLCHAIN` pin should unblock it there. Rebuilding golangci-lint with Go 1.27 is the other fix. `.golangci.yml` carries no settings yet: uh-cli's `errcheck` exclusions are CLI-specific and nothing here needed one. ## Step 4 — Module path and version identity Module renamed to `gitea.home.hrajfrisbee.cz/kacerr/gatewayapi-certificates-operator`. `internal/version` copied from egress unchanged (code and test). `main.go` gained `--version`, a first log line with commit and Go version, the standard `--zap-*` flags, and passes `--metrics-bind-address` to the manager. ``` $ make build && ./bin/manager --version 0eb588e8bd3a-dirty $ make docker-build && docker run --rm gateway-cert-operator:dev --version 0eb588e8bd3a-dirty $ docker inspect gateway-cert-operator:dev --format '{{index .Config.Labels "org.opencontainers.image.revision"}} {{.Config.User}}' 0eb588e8bd3a-dirty 65532:65532 ``` Deviations from the plan: - The Dockerfile build also got `-trimpath`, and keeps `-s -w` (egress has neither). - The Dockerfile now does `COPY . .` and relies on the new `.dockerignore` allowlist, instead of copying `main.go` and `internal/` by name. - The `gozap.AddCaller()` option was kept so log lines look the same as before. Worth noting: the manager was not started against a cluster in this step; the flag wiring is verified by `--help` output and the build only. `GOARCH` defaults to `amd64` when `TARGETARCH` is empty (legacy builder, as on the CI runner) and follows the host under BuildKit, so a local build on an Apple Silicon machine is arm64. `docs/flows.md` still cites pre-change `main.go` line numbers in §2.