gofumpt was pinned only by its version tag. It is now a tool of a
separate module in tools/, so `go tool` builds it from source checked
against the hashes in tools/go.sum, and mfer's own module gains no
dependencies. script/prettier no longer falls back to a prettier on
PATH, and fails when node_modules holds a different version than
package.json pins. The bootstrap comment now says what --frozen-lockfile
really does, package.json drops its made-up version, and the golang
image comment names its exact version.
Model: opus-5-5
The Makefile is now one shim per script/ entrypoint, in the order of
the canonical model Makefile, plus build, generate and fuzz. The new
script/build writes bin/mfer with the urfave_cli_no_docs tag and the
git describe revision that script/docker stamps. script/generate now
adds the Go bin directory to PATH itself, and the Docker lint stage
calls script/gofumpt --check directly. Removed: the tarball-caching
rules and their ignore entries, godoc, ci, fixme, clean, run, default,
fmt-check-go, fmt-check-md, and bin/gitrev.sh, which only the
Makefile called.
Model: opus-5-5
The Go format check ran plain gofmt, which accepts code that gofumpt,
the formatter script/fmt runs, rewrites; and the two covered different
files. Both now go through script/gofumpt, which runs one pinned
gofumpt version over every Go file in --write or --check mode, as
script/prettier does for Markdown. It replaces script/fmt-check-go;
make fmt-check-go and the Docker lint stage call it. go run builds the
pinned version, so nothing has to install gofumpt, and the check fails
when gofumpt cannot run instead of passing. Generated mfer/mf.pb.go
passes: gofumpt holds generated files to gofmt's rules. The check is
not redundant: .golangci.yml enables no golangci-lint formatters.
Model: opus-5-5
The test and format scripts regenerated mfer/mf.pb.go whenever
mfer/mf.proto looked newer by mtime, which a fresh checkout often causes,
so make check could rewrite a committed file and needed protoc. Nothing
regenerates it any more except make generate (script/generate), which
refuses to run unless protoc 33.4 and protoc-gen-go v1.36.11, the
versions that wrote the committed file, are on PATH, and records the
hash of mf.proto in mfer/mf.proto.sha256. A Go test compares that hash
with mf.proto and fails, naming make generate, when they differ. The
mtime rule, the unused protoc-gen-go v1.28.1 install rule, make clean's
deletion of mf.pb.go and the Dockerfile's touch workarounds are removed.
Model: opus-5-5
The final stage is scratch, which has no CA certificates, so fetch from
an HTTPS URL failed to verify any server. Copy the CA bundle from the
pinned builder image into the final stage.
Model: opus-5-5
script/lint now builds only the lint stage of the main Dockerfile
(docker build --no-cache --target lint), whose build runs the linter, so
a successful build is a clean lint. It is uncached because a cached
build runs no linter, and a trap removes the image it tagged; the tag
carries the process ID so concurrent runs do not collide. The lint stage
calls golangci-lint directly, since make lint now needs Docker. Nothing
installs or runs golangci-lint on the host any more: bootstrap and the
Makefile drop the install, and script/fmt drops golangci-lint run --fix.
Model: opus-5-5
The final stage is scratch, which has no C library, but the builder
compiled mfer with cgo on (the golang image's default). The binary
imports net (mfer's own HTTP code does, and so does google/uuid), so
with cgo on it came out dynamically linked and the image could not
start. The image's go build now sets CGO_ENABLED=0; nothing in mfer
needs cgo. A new builder step runs ldd on the binary and fails the
build unless it reports a static executable.
Model: opus-5-5
.dockerignore now sends .git but not .git/config, which can hold a
credential and which git describe does not need. The build stage stamps
main.Gitrev from the VERSION build argument when one is given, otherwise
from git describe --tags --always, and fails if .git is present and no
version comes out. git there trusts /src whoever owns it, since a
context sent as a tar archive keeps its files' owners. script/docker is
replaced by the canonical copy, which passes VERSION; bin/gitrev.sh uses
--tags too, so every entrypoint stamps the same value for a clean
commit.
Model: opus-5-5
Adds .prettierrc and .prettierignore, a single script/prettier entrypoint shared by fmt and fmt-check so the two cannot drift, and prettier 3.9.6 pinned by yarn.lock integrity hash.
Markdown formatting is now gated in the authoritative Docker build via a new mdfmt stage, since the golangci-lint image has no node. REPO_POLICIES.md is ignored so local tooling cannot drift it from upstream.
Removes the || true that made the previous prettier invocation unable to fail.
Adopts golangci-lint v2.12.2 and the canonical .golangci.yml (default: all), and fixes all resulting findings across the tree.
Two intended behavior changes: absent MFFilePath.Mtime is handled explicitly in freshen, list and export rather than dereferenced (main panicked); gpg positional key IDs now follow an explicit -- end-of-options marker.
All twelve reworded user-visible error messages restored to byte-identical parity with main and pinned by tests.
Closes#39
Splits the Dockerfile into a dedicated lint stage using the `golangci/golangci-lint` image directly, rather than copying the binary into the builder stage.
## Changes
### Dockerfile
- **Lint stage** (`AS lint`): Uses the pre-built `golangci/golangci-lint` image (pinned by sha256) to run `make fmt-check` and `make lint`. This is a self-contained stage with its own `go mod download` and source copy.
- **Builder stage** (`AS builder`): Runs only `make test` and the final binary build. No longer needs golangci-lint installed.
- **Stage dependency**: `COPY --from=lint /src/go.sum /dev/null` forces BuildKit to always execute the lint stage (without this, unused stages are silently skipped).
- Both stages touch `mfer/mf.pb.go` to prevent make from trying to regenerate via protoc.
With BuildKit, the lint and builder stages run in parallel after their shared `go mod download` layers complete, so lint/formatting failures surface much faster without blocking on test execution.
### Makefile
- Added `lint` to the `check` target prereqs: `check: test lint fmt-check` (was `check: test fmt-check`), matching the [REPO_POLICIES](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md) requirement.
Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #45
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>