# Execution: Distilled Gitea Actions image-build workflow Plan: `docs/plans/2026-08-11-1935-gitea-build-workflow.md` - [x] Step 1 — Create `.gitea/workflows/build.yaml` - [x] Step 2 — Replace CLAUDE.md CI TODO with a CI/CD subsection - [ ] Step 3 — Push branch + open MR - [ ] Step 4 — CHANGELOG entry (after the first successful run is confirmed) ## Steps 1–2 — workflow + CLAUDE.md The workflow distills the house pattern from 9 sibling projects (survey in the plan) plus improvements none of them combine: an immutable `sha-<12>` tag, a lightweight test gate, `:latest` moving only on real tag pushes, and a `concurrency` group. Work happened in a git worktree off `origin/main` so the main checkout (which had unrelated uncommitted changes) stayed untouched: ```bash git worktree add -b feat/gitea-build-workflow \ "$SCRATCH/wt-build" origin/main ``` Deviation from the plan's assumptions: while planning, `feat/proxy-operator` was still unmerged and the plan noted `main` lacked `internal/`/`test/`. By execution time `origin/main` had moved (`076bc66..f7000f7` — the proxy-operator MR merged), so the branch and its CI gate cover the full operator code. Verified the workflow parses and the check-gate commands pass on this exact tree (ruby stands in for a YAML linter because the system python3 has no `yaml` module): ```bash ruby -ryaml -e "YAML.load_file('.gitea/workflows/build.yaml'); puts 'YAML OK'" go vet ./... && go build ./... && go test -short ./... # all packages ok ``` Worth noting: the workflow itself cannot run end-to-end until (a) the MR merges (it only triggers on tags / manual dispatch, not branch pushes) and (b) the `REGISTRY_TOKEN` secret is created in this repo's Gitea settings (PAT with `write:package`). First real verification = manual dispatch with tag `manual-test`, expecting `manual-test` + `sha-…` in Packages and `:latest` untouched.