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
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
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.
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.
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.
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.
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.
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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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
nextand passed independent review; see #34 sections 2 and 5 for the full adoption instructions and control tables.Per-repo definition of done
if missing golangci-lintguard inscript/bootstrapwith the canonical block fromREPO_POLICIES.md. Place it after Go is ensured present. The block ends with a call site — if you move the definitions above your ownmain(), the call goes insidemain(). Definitions with no invocation are a silent no-op reproducing the original defect.script/lintwith the canonical block: per-checkoutGOLANGCI_LINT_CACHE, per-checkoutTMPDIR,--allow-serial-runners, per-invocation capture files viamktemp, bounded retry, stderr-based lock detection..gitignore, and permoby/patternmatcherrules in.dockerignore. Do not transplant between them.GOLANGCI_LINT_VERSIONexactly what--versionprints for the pinned ref. Not a prefix of it: a parser stopping at the first-makes a host running2.12.2-rc1compare equal to a2.12.2pin and skip the install.make lintafter 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.
PATHthan 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 ascript/bootstrap-shaped file and executed, not sourced with functions called by hand.script/lintruns in one checkout, each with a different finding; each must report its own.Repos
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_CACHEat 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.
clawbot referenced this issue2026-08-09 20:52:45 +02:00