From cb450f7de3d5c3dce8f7de808a492054653be9d8 Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 8 Sep 2026 04:58:31 +0000 Subject: [PATCH] Compare versions when bootstrap installs a pinned tool (closes #28) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canonical `if missing ; then install; fi` guard tests PATH presence and never version, so on any already-provisioned machine a pin is inert and a version bump is a no-op, while the Dockerfile installs the pinned version into a clean image and CI then disagrees with local about what the tool is. Comparing versions alone is not enough either: an installer writes to its own directory while callers resolve through PATH, so a shadowing binary lets the install succeed and change nothing anyone sees. REPO_POLICIES.md now states the whole form — exact whole-token comparison, mis-parse falling through to a reinstall, re-resolution through PATH after installing, and a call site that prints the version. Model: opus-5 --- TODO.md | 5 +++++ prompts/REPO_POLICIES.md | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/TODO.md b/TODO.md index e0f9b9a..1a22b5d 100644 --- a/TODO.md +++ b/TODO.md @@ -21,6 +21,11 @@ fmt-check, and commit. # Completed Steps +- 2026-09-08: Made a pinned tool in `script/bootstrap` actually reach the host. + `REPO_POLICIES.md` now requires comparing the installed version against the + pin rather than testing `PATH` presence, and re-resolving the binary through + `PATH` after installing, so a version bump cannot be a silent no-op and a + shadowed install cannot report success. - 2026-09-08: Closed the false green in the canonical CI gate: `script/cibuild` and `script/docker` now build with `--no-cache`, so the Dockerfile's check layers cannot be served from cache on an unchanged tree, and the text claiming diff --git a/prompts/REPO_POLICIES.md b/prompts/REPO_POLICIES.md index 0ce4531..e4f3134 100644 --- a/prompts/REPO_POLICIES.md +++ b/prompts/REPO_POLICIES.md @@ -287,6 +287,28 @@ style conventions are in separate documents: v2.12.2 (released 2026-05-06), installed commit-pinned via `go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@c0d3ddc9cf3faa61a4e378e879ece580256d76e5`. +- **`script/bootstrap` installs a pinned tool by comparing versions, never by + testing presence.** An `if ! command -v ; then install; fi` guard tests + `PATH` only, so on an already-provisioned machine the pin is inert and a + version bump is a silent no-op — while the Dockerfile, installing into a clean + image, gets the pinned version, so a local `make check` and `make docker` can + disagree about what the tool even is. The canonical form: + - compares the installed version against the pin over the **whole** version + token; a parser that stops at the first `-` reports `2.12.2` for a host + running `2.12.2-rc1` and skips the install; + - treats absent, non-zero, empty or unrecognised `--version` output as a + mismatch, so the failure direction is a redundant install and never a + skipped one; + - after installing, re-resolves the binary the way callers do — `hash -r`, + then through `PATH`, not through the directory the installer wrote to — + and fails naming the resolved path, since an install that a shadowing + binary hides succeeds while changing nothing any caller sees; + - is actually called, and prints the version on both success paths: a + function defined and never invoked has the same exit status and the same + empty output as one that worked. + + Keep it POSIX sh: no arrays, no `[[`, no `grep -P`. + - When pinning images or packages by hash, add a comment above the reference with the version and date (YYYY-MM-DD).