go-track CI papercuts: coverage-badge dilution by generated files + bootstrap-v0.1.0 gets no CI
Two go-track CI papercuts surfaced repeatedly across the module-extraction programme (27+ modules, Jul 2026). Both are small, well-understood cicd component fixes; this issue captures the full investigation so the work can be picked up without re-deriving it. Per the repo's spec-first rule, each part likely wants a short spec — but everything needed to write and implement them is below.
Part A — Generated files dilute the coverage badge (go-test)
Problem
go-test runs go test -race -coverprofile=cover.out $[[ inputs.paths ]] then drives the badge off go tool cover -func=cover.out | tail -1. When paths is ./..., mockery-generated mocks and other generated code are included in the coverage denominator. Generated files have ~0% test coverage, so the badge reads far below the real figure for hand-written code.
Evidence (from the extraction programme)
go/config: real coverage 92.2%, but./...including the generatedconfigmock/package dilutes it to ~55%.go/forge: real 95.9%,./...includingmocks/+ doubles dilutes to 46.8%.
Current workaround (fragile, per-repo)
Each module hand-scopes the paths input to exclude generated dirs, e.g. paths: ". ./direct/... ./forgetest/..." or paths: ".". This is manual, easy to get wrong, has to be maintained as packages are added, and means the badge silently misreports if someone forgets.
Proposed fix
Have go-test strip generated files from cover.out before computing the badge, so paths can stay ./... and the badge reflects hand-written code without per-repo bookkeeping. Go's own generated-file convention is the reliable signal: the first line matches ^// Code generated .* DO NOT EDIT\.$ (mockery, protoc, stringer, etc. all emit it). Sketch:
- After
go test -coverprofile=cover.out …, enumerate.gofiles whose first line matches the generated marker. - Drop those files' entries from
cover.out(their lines arepath.go:from.col,to.col stmts count). - Run
go tool cover -func=cover.out | tail -1on the filtered profile for the badge.
Gate behind an input, e.g. exclude_generated (default true), so a consumer can opt out. Keep paths as-is for what gets tested; this only changes what's counted.
Acceptance
- With
exclude_generated: trueandpaths: "./...", a module with amocks/*mockpackage reports the same badge % as scopingpathsby hand does today. - Turning it off reproduces current behaviour.
- Self-test (
tests/go-test/) fixture gains a generated file (with the marker) and asserts it is absent from the counted profile.
Open questions
- A1: Filter in shell (grep/awk over
cover.out), or via a small tool already in the dev-tools image? Shell keeps the image lean. - A2: Match only the exact Go marker, or also honour an explicit exclude-glob input for non-marked generated dirs?
Part B — Bootstrap v0.1.0 releases get no CI (go-test + go-lint)
Problem
A brand-new module's first release runs no go-test/go-lint in CI, and its coverage badge reads unknown until some later code-touching MR.
Root cause
go-test and go-lint gate on a changes: rule, default:
["**/*.go", "**/go.mod", "**/go.sum", ".golangci.*", ".gitlab-ci.yml"]A releaser-pleaser Release MR for a bootstrap v0.1.0 changes only CHANGELOG.md (the tag/release is cut from it). That matches nothing in the changes list, so test+lint are skipped on the Release MR — and main-push workflow:rules already exclude them — so v0.1.0 is tagged having only ever been validated locally. (Security jobs do run on the Release MR, so the govulncheck/osv/trivy signal is covered; only test+lint+coverage are missing.) Confirmed identical on multiple bootstrap Release MRs (e.g. aferobilly).
Proposed fix
Add CHANGELOG.md (and **/CHANGELOG.md if nested changelogs are ever used) to the default changes array of both go-test and go-lint, so a CHANGELOG-only Release MR triggers test+lint and the bootstrap release gets a real CI pass + a coverage badge.
Trade-off (acceptable / desired)
Every Release MR (not just v0.1.0) will now also run test+lint. That is the point — a release should be validated before it is tagged — and the extra cost is one test+lint run per release MR. No effect on ordinary code MRs (they already match **/*.go).
Acceptance
- A CHANGELOG-only MR triggers
go-testandgo-lint. - A bootstrap
v0.1.0Release MR shows a passing test+lint pipeline and publishes a coverage badge before the tag is cut. - Ordinary MRs are unaffected.
Open question
- B1: Add
CHANGELOG.mdto the component defaults (fixes the whole fleet at once, the intent here), or document it as a per-repo override? Defaults are preferred — every toolkit module has this gap.
Notes
- Parts A and B are independent; they can ship as separate specs/MRs. They are bundled here because both are
go-test-adjacent papercuts from the same programme and share the same investigation context. - Both are
feat/fixon thegotrack → a cicd minor. Follow the standard component-authoring flow (spec → template + self-test + reference page → decision-log row).