PROPAGATION: roll the Go tooling fixes (#28 bootstrap version enforcement, #30 lint cache/lock isolation) into every Go repo — as ONE commit per repo #39

Open
opened 2026-08-09 20:52:34 +02:00 by clawbot · 0 comments
Collaborator

Follow-up required by the definitions of done in #28 and #30. One tracking issue for both, deliberately: a repo that adopts the lint isolation without the bootstrap fix still has host/container version skew, so its newly-trustworthy lint result is produced by an untrustworthy linter. They close different halves of the same question — "is this lint result mine, and is it from the pinned tool?"

Separate from #35, which covers the Docker build-context trio and has a different scope and blast radius. A repo can take these two in either order relative to that one.

Canonical status

Both landed on next and passed independent review; see #34 sections 2 and 5 for the full adoption instructions and control tables.

Per-repo definition of done

  1. Replace the if missing golangci-lint guard in script/bootstrap with the canonical block from REPO_POLICIES.md. Place it after Go is ensured present. The block ends with a call site — if you move the definitions above your own main(), the call goes inside main(). Definitions with no invocation are a silent no-op reproducing the original defect.
  2. Replace script/lint with the canonical block: per-checkout GOLANGCI_LINT_CACHE, per-checkout TMPDIR, --allow-serial-runners, per-invocation capture files via mktemp, bounded retry, stderr-based lock detection.
  3. Add the lint state directory to both ignore files, each written to its own semantics — unanchored in .gitignore, and per moby/patternmatcher rules in .dockerignore. Do not transplant between them.
  4. Keep GOLANGCI_LINT_VERSION exactly what --version prints for the pinned ref. Not a prefix of it: a parser stopping at the first - makes a host running 2.12.2-rc1 compare equal to a 2.12.2 pin and skip the install.
  5. Expect bootstrap to start FAILING on machines with a shadowing linter. That is the point — it names the offending path and a human fixes it.
  6. Re-run make lint after adopting on any machine that had a stale linter, and expect new findings. A green host run taken before adoption does not carry over. One repo's container surfaced thirteen findings its host run missed.

Acceptance evidence, per repo — controls, not observations

Each must be paired against the pre-fix form in the same environment. A control that passes against the broken form proves nothing, and that pairing caught every real defect in this batch.

  • Shadowing control (#28): a wrong-version binary earlier in PATH than the install target. Canonical form must exit non-zero naming the shadowing path; the naive compare-then-install form must print success while leaving the stale binary resolved. Run it as adopted — pasted into a script/bootstrap-shaped file and executed, not sourced with functions called by hand.
  • Contamination control (#30): two checkouts with identical content and different known findings. Identical content is essential — the cache is keyed on content, so a differing-content control passes against the unisolated form and proves nothing.
  • Concurrency control (#30): two script/lint runs in one checkout, each with a different finding; each must report its own.
  • Signal control (#30): a mid-run SIGTERM/INT/HUP must exit >=128, not 1. Include the dead-terminal case.

Repos

  • attrsum
  • bsfirehose
  • dnswatcher
  • gohttpserver
  • homoicon
  • mfer
  • neoirc
  • pixa
  • rgoue
  • routewatch
  • secret
  • sfdupes
  • simplelog
  • smartconfig
  • upaas
  • vaultik
  • webhooker

Confirm applicability first; a repo with no Go toolchain ticks with a note.

Repos that already landed a local variant (vaultik's per-repo GOLANGCI_LINT_CACHE at its #78, for one) are not broken but are not covered: per-repo isolation still shares one directory across that repo's own checkouts, and it reads as a fix. Adopt the canonical block byte-for-byte.

Read before starting

#35 carries a list of every defect found in this batch and the five method rules that caught them. The single most useful question, which would have caught all of them: what does this do when the guard itself fails? Every remedy that broke, broke into a plausible-looking success rather than an obvious error.

That applies to prose as much as code. A caveat recorded only in a pull request is not a caveat — consuming repos receive files.

Follow-up required by the definitions of done in #28 and #30. One tracking issue for both, deliberately: a repo that adopts the lint isolation without the bootstrap fix still has host/container **version skew**, so its newly-trustworthy lint result is produced by an untrustworthy linter. They close different halves of the same question — "is this lint result mine, and is it from the pinned tool?" Separate from https://git.eeqj.de/sneak/prompts/issues/35, which covers the Docker build-context trio and has a different scope and blast radius. A repo can take these two in either order relative to that one. ## Canonical status Both landed on `next` and passed independent review; see https://git.eeqj.de/sneak/prompts/pulls/34 sections 2 and 5 for the full adoption instructions and control tables. ## Per-repo definition of done 1. **Replace the `if missing golangci-lint` guard in `script/bootstrap`** with the canonical block from `REPO_POLICIES.md`. Place it after Go is ensured present. **The block ends with a call site** — if you move the definitions above your own `main()`, the call goes inside `main()`. Definitions with no invocation are a silent no-op reproducing the original defect. 2. **Replace `script/lint`** with the canonical block: per-checkout `GOLANGCI_LINT_CACHE`, per-checkout `TMPDIR`, `--allow-serial-runners`, per-invocation capture files via `mktemp`, bounded retry, stderr-based lock detection. 3. **Add the lint state directory to both ignore files, each written to its own semantics** — unanchored in `.gitignore`, and per `moby/patternmatcher` rules in `.dockerignore`. Do not transplant between them. 4. **Keep `GOLANGCI_LINT_VERSION` exactly what `--version` prints** for the pinned ref. Not a prefix of it: a parser stopping at the first `-` makes a host running `2.12.2-rc1` compare equal to a `2.12.2` pin and **skip the install**. 5. **Expect bootstrap to start FAILING** on machines with a shadowing linter. That is the point — it names the offending path and a human fixes it. 6. **Re-run `make lint` after adopting on any machine that had a stale linter, and expect new findings.** A green host run taken before adoption does not carry over. One repo's container surfaced thirteen findings its host run missed. ## Acceptance evidence, per repo — controls, not observations Each must be **paired against the pre-fix form in the same environment**. A control that passes against the broken form proves nothing, and that pairing caught every real defect in this batch. - **Shadowing control (#28):** a wrong-version binary earlier in `PATH` than the install target. Canonical form must exit non-zero naming the shadowing path; the naive compare-then-install form must print success while leaving the stale binary resolved. **Run it as adopted** — pasted into a `script/bootstrap`-shaped file and executed, not sourced with functions called by hand. - **Contamination control (#30):** two checkouts with **identical content** and different known findings. Identical content is essential — the cache is keyed on content, so a differing-content control passes against the unisolated form and proves nothing. - **Concurrency control (#30):** two `script/lint` runs in **one** checkout, each with a different finding; each must report its own. - **Signal control (#30):** a mid-run SIGTERM/INT/HUP must exit >=128, not 1. Include the dead-terminal case. ## Repos - [ ] attrsum - [ ] bsfirehose - [ ] dnswatcher - [ ] gohttpserver - [ ] homoicon - [ ] mfer - [ ] neoirc - [ ] pixa - [ ] rgoue - [ ] routewatch - [ ] secret - [ ] sfdupes - [ ] simplelog - [ ] smartconfig - [ ] upaas - [ ] vaultik - [ ] webhooker Confirm applicability first; a repo with no Go toolchain ticks with a note. Repos that already landed a local variant (vaultik's per-repo `GOLANGCI_LINT_CACHE` at its #78, for one) are not broken but are **not covered**: per-repo isolation still shares one directory across that repo's own checkouts, and it reads as a fix. Adopt the canonical block byte-for-byte. ## Read before starting https://git.eeqj.de/sneak/prompts/issues/35 carries a list of every defect found in this batch and the five method rules that caught them. The single most useful question, which would have caught all of them: **what does this do when the guard itself fails?** Every remedy that broke, broke into a plausible-looking success rather than an obvious error. That applies to prose as much as code. A caveat recorded only in a pull request is not a caveat — consuming repos receive files.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/prompts#39