Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up required by the definitions of done in #26, #29 and #27. Filed as a single tracking issue for all three deliberately — see the ordering rule below, which is the whole reason this is one issue and not three.
Do not start a repo until the canonical change it depends on has landed here. Status is tracked at the top; the checklist is at the bottom.
Canonical status
CHECK_EPOCHcache-bust — landed onnext(PR #34, commit22a5a37), under review.dockerignoresecret patterns with**/prefixes.claude/exclusion +--build-arg VERSIONguidanceTHE ORDERING RULE — read before doing any repo
All three changes must land in a single commit per repo. Never
.dockerignore-first.This is not tidiness. Any path in the build context that churns between builds accidentally protects a repo, because it invalidates
COPY . .and forces the check layers to re-run..gitchurns on nearly every git operation;.claude/worktrees/churns wherever agents run. Tightening.dockerignoreremoves that protection. So adding the canonical.dockerignorewithout theCHECK_EPOCHfix is a strict regression: it converts a repo whose gate works by accident into one that reliably reports greens it did not earn.The fleet-level version of the same trap: if
.dockerignoreandCHECK_EPOCHare run as two separate passes across the roster, the window between the passes is exactly when CI stops meaning anything in every repo the first pass has reached and the second has not. Hence: one commit, per repo, all three.Absence of a
.dockerignoreis NOT a screening test for whether a repo is affected. A repo whose.dockerignorehas always excluded.gitnever had the protection and is exposed right now — cattbox is the worked example. Every repo needs the cache-bust regardless of its.dockerignorestate. A manager who checks for the file, finds one, and concludes the repo is fine has it exactly backwards.Per-repo definition of done
ARG CHECK_EPOCH+ the[ -n "$CHECK_EPOCH" ] || exit 1guard + the expandedRUN echo "check epoch: ${CHECK_EPOCH}" && make checkform in every stage containing a check-runningRUN.ARGis stage-scoped; most repos have check steps in two stages (make fmt-check/make lintin lint,make testin builder). A fix written against a single-stage repo silently leaves the other stage frozen and reviews as complete.script/cibuildandscript/dockerupdated. A warm localmake dockeris the likelier deception today, and once only cibuild is fixed the two entrypoints silently disagree about whether the tree is green.**/-prefix every depth-independent.dockerignorepattern. Do NOT apply**/to.gitignore— different semantics; prefixing there produces a file that is wrong in a way that looks careful.git describe, thread it in with--build-arg VERSION=...computed on the host..dockerignoreexcludes.git, sogit describein a build stage yields an empty version without erroring.script/cibuildruns on an unchanged tree, both executing the checks;script/bootstrap(orgo mod download) layer stillCACHEDin run 2 — this is the validity control proving no concurrent prune landed mid-pair, not merely a performance check;docker build .fails on the guard;.dockerignore..env,*.pemor*.key. The exposure is not necessarily only prospective.Method warnings
CACHED-vs-executed on the specific layer is what settles a question.docker builder pruneordocker system prune— this host is shared with ~18 sessions and a prune destroyed ~41 GB on 2026-08-09. Use--no-cache-filter=<stage>for scoped invalidation. The two-run protocol warms its own cache, so no prune is needed for a valid measurement.Repos to sweep
Each manager: confirm applicability first. A repo with no
Dockerfileticks with a note; do not invent one.Repos that already landed a variant of the
CHECK_EPOCHfix ahead of canonical (rfscan, dnswatcher, cattbox, vaultik at least) are not broken and need no urgent rework, but should re-run the negative control against the canonical form on their own machine rather than assuming their earlier verification transfers — several used the bare unreferenced-ARGform, which works but leaves the miss dependent on BuildKit behaviour rather than contractual.Related propagation, tracked separately
#25 changes
.golangci.yml, so its sha256 moves and every repo verifying by hash will mismatch. #32 (-count=1) and #28 (bootstrap version enforcement) are Go-only. Those are separate sweeps with different scopes and must not be folded into this commit.clawbot referenced this issue2026-08-09 16:56:09 +02:00
clawbot referenced this issue2026-08-09 16:57:28 +02:00
Scope addition, from the PR #34 review: the sweep is not three files per repo. It is a grep.
The canonical fix passed code review and failed on scope — five sites across three org-canonical documents still asserted the old guarantee, beyond the
Dockerfile/script/cibuild/script/docker/REPO_POLICIES.mdset. Consuming repos vendor those documents too, so the same sites exist downstream.Two are actively harmful rather than merely stale:
EXISTING_REPO_CHECKLIST.mdcarried a final acceptance item "docker buildsucceeds". The[ -n "$CHECK_EPOCH" ]guard makes that unsatisfiable by design. An agent working the fixup checklist hits a guard failure at the last box, and the cheapest way to tick it is to delete the guard. The fix disarming itself through its own documentation. Any consuming repo that vendored this checklist has a live instruction to undo the change it is about to receive.NEW_REPO_CHECKLIST.mdinstructed writing the pre-fixscript/cibuildverbatim, so a new repo created from it is born with the false green even after the sweep completes.Also
CODE_STYLEGUIDE_GO.md, which restated "docker build .... makes sure the code is compiled, linted and tests run" — both halves now wrong.Amended per-repo done-criterion, replacing "update these files":
> A repo-wide grep for
docker buildreturns only sites that describe it as failing closed by design, or that route throughscript/cibuild/script/docker.Check vendored checklists, styleguides,
README.md,CONTRIBUTING, runbooks, and any.gitea/workflows/step that invokesdocker builddirectly. A file list will miss sites; the grep will not. The canonical brief named two sites, the implementer found three, the reviewer found five — assume your repo's list is longer than you expect.clawbot referenced this issue2026-08-09 17:12:03 +02:00
The
.dockerignoreverification method in circulation cannot detect the defect. Anyone about to run this sweep must not use it.From the #29 implementation.
transferring contextis a BuildKit delta, not a total — it reports what this build had to send given what the daemon already holds, not what is in the context.Measured: the naive
.dockerignoreform (patterns without**/prefixes) reported 2.18kB transferred while 43 files, five of them secrets, were present in the image.That matters beyond a method note, because the definition of done in #29 as originally written required exactly that measurement — "verified absent from the build context by measuring
transferring contextsize before and after, not by reading the file". A sweep following it would have compared two small numbers, seen them differ, and recorded the broken form as fixed. The instruction intended to prevent verification-by-reading instead prescribed verification-by-artefact.Use image enumeration instead, per repo:
findinside the image. That is the measurement..dockerignoreexcluding everything otherwise passes every negative test.git statusnever sees these files —.gitignorecovers them, which is the exact property that made the exposure invisible.Also confirmed by enumeration rather than assumed:
**/foodoes match at the context root, so**/.envcovers a root.envand no separate unprefixed entry is needed.Two standing warnings, restated because this sweep is where they bite: do not apply
**/to.gitignore— different semantics, and the result is wrong in a way that looks careful — and check the consuming repo's checklists, which instruct agents to "extend" these files and are where the naive shape actually gets written.The
git describeconsequence is already written INTO the canonical corpus, so the sweep has to fix Makefiles too, not just ignore files.From the #27 implementation.
prompts/CODE_STYLEGUIDE_GO.mdandprompts/GO_HTTP_SERVER_CONVENTIONS.mdboth carry:and the canonical Dockerfile runs
makeinside the build..dockerignoreexcludes.git, so that$(shell ...)produces an empty string, with no error — the binary simply reports no version. The defect this issue warns about was therefore not merely undocumented, it was prescribed, and any repo that copied the styleguide Makefile has it today.Fixed canonically by changing
:=to?=so anARG VERSIONpassed into the build wins via the environment, plus documenting that the value is computed on the host and threaded in with--build-arg VERSION=....Add to the per-repo checklist in this sweep:
grep -rn 'git describe' .in the consuming repo. Any occurrence inside a Makefile, Dockerfile, or build script that runs during a Docker build is broken the moment.gitis excluded — and it fails silently, which is why nobody has noticed.VERSION :=toVERSION ?=in the Makefile so a build arg can win.--build-arg VERSION=...fromscript/cibuildandscript/docker. Assign it on its own line, never inline in the argument: a failing command substitution inside an argument does not tripset -e(confirmed indash), so the inline form degrades silently to an empty constant — the same trapCHECK_EPOCHhas.git describe --tagsdegrades to a bare hash there. A repo embedding a tag-derived version needs full history and tags fetched; a repo embedding no version needs nothing.Sequencing note: this belongs in the same single per-repo commit as the
.dockerignoretightening and theCHECK_EPOCHbust. A repo that tightens.dockerignorewithout it starts emitting unversioned binaries, and it will not announce itself.The single question that would have caught every defect in this batch, for whoever runs this sweep: "what does this do when the guard itself fails?"
Five canonical fixes landed. Across their review cycles, every defect found — in the original code and in the remedies — had the same shape: a mechanism that failed into a plausible result rather than an obvious error. Listing them because the pattern is more useful than any individual fix:
script/cibuildreported a green without running the suite.$(date +%s)inline in an argument does not tripset -e, so it degrades to an empty constant — a stable cache key, and the false green returns.ARGis empty, and empty is a stable cache key: a baredocker build .stayed broken while the scripted path was fixed.script/bootstrapprinted "installed" while a shadowing binary stayed onPATH, changing nothing any caller sees.-made2.12.2-rc1compare equal to a2.12.2pin and skip the install..dockerignorewith the right names but no**/prefixes protects only the context root, and reads as solved.transferring contextis a delta, not a total — 2.18kB reported while 43 files including five secrets were in the image.0 issues.while its own linter had a real finding.Three of those were the prescribed check rather than the code, including two definitions of done in these very issues: #29's "measure
transferring contextbefore and after" cannot detect the broken form, and #30's negative control as written passes against the unisolated form because differing content never collides in a content-keyed cache.What to actually do differently
Vendored prose is part of the artifact. Consuming repos receive files, not pull requests: a caveat recorded only in a PR body is not a caveat, and a checklist item an agent can satisfy by deleting a guard is a live instruction to disarm the fix.
clawbot referenced this issue2026-08-09 20:52:45 +02:00