Some checks failed
check / check (push) Has been cancelled
script/cibuild was a plain `docker build .`, and the Dockerfile does `COPY . .` followed by `RUN make check`. Docker invalidates a COPY layer only when the copied content changes, so on an unchanged tree the check layer was served from cache, the suite never ran, and the build still exited 0. Measured here: run 1 took 18.5s and ran the suite; run 2 on a byte-identical tree took 0.286s with `RUN make check` CACHED. script/cibuild and script/docker now assign a per-invocation nonce on its own line and pass it as --build-arg CHECK_EPOCH. The Dockerfile declares ARG CHECK_EPOCH, guards it with `[ -n "$CHECK_EPOCH" ] || exit 1`, and expands it into the check command. Post-fix, two consecutive runs both execute make check (17.4s / 8.1s) with `RUN script/bootstrap` still CACHED, so dependency layers are untouched and the build ceiling is not at risk. The guard is what makes a bare `docker build .` — the command REPO_POLICIES named verbatim — fail closed rather than reuse the empty and therefore stable cache key; verified failing in 0.455s. Holding the epoch constant restores the false green (run 2 fully CACHED), which pins the varying value as the operative mechanism rather than a coincidence. Because the guard references $CHECK_EPOCH it is itself value-keyed: BuildKit renders the epoch into that layer's description and re-runs the layer when the value changes. Each stage therefore has two independent invalidation points, the guard and the expansion, and the guard always precedes the check RUN. Both are kept and the prose now records this; the expansion remains defence in depth and is what puts the epoch in the build log. The false guarantee was org-canonical text in more than one document, so it is corrected everywhere it appeared rather than only where the issue first found it. REPO_POLICIES.md carried it in two places, and its Go multistage template had check steps in two stages; ARG is stage-scoped, so both stages get the treatment or the fleet inherits the half-fixed shape. CODE_STYLEGUIDE_GO.md restated the guarantee for the bare command this change makes fail closed. NEW_REPO_CHECKLIST.md specified the pre-fix script/cibuild verbatim, so every new repo would have been born with the false green, and EXISTING_REPO_CHECKLIST.md ended on a `docker build` acceptance item that the guard makes unsatisfiable by design — an agent working that checklist would have been led to delete the guard to tick the last box. Both checklists' Dockerfile criteria were also satisfiable by a Dockerfile whose check layers are still frozen, and now require the ARG and guard in every check-running stage.
5.5 KiB
5.5 KiB
title, last_modified
| title | last_modified |
|---|---|
| New Repo Checklist | 2026-08-09 |
Use this checklist when creating a new repository from scratch. Follow the steps
in order. Full policies are at
https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md.
Template files can be fetched from:
https://git.eeqj.de/sneak/prompts/raw/branch/main/<path>
1. Initialize
git init- Ask the user for the license (MIT, GPL, or WTFPL)
2. First Commit (README only)
- Create
README.mdwith all required sections:- Description: name, purpose, category, license, author
- Getting Started: copy-pasteable code block
- Rationale: why does this exist?
- Design: how is it structured?
- TODO: initial task list
- License: matches chosen license
- Author: @sneak
git add README.md && git commit
3. Scaffolding (feature branch)
git checkout -b initial-scaffolding
Fetch Template Files
.gitignore— fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore, extend for language-specific artifacts.editorconfig— fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfigMakefile— fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile, adapt targets for the project's language and tools- For JS/docs repos:
.prettierrcand.prettierignore— fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrcandhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierignore
Create Project Files
LICENSEfile matching the chosen licenseREPO_POLICIES.md— fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.mdDockerfileand.dockerignore— fetch.dockerignorefromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore- All Dockerfiles must run
make checkas a build step, and every stage containing a check-runningRUNmust declareARG CHECK_EPOCHwith theRUN [ -n "$CHECK_EPOCH" ] || exit 1guard immediately below it — see theCHECK_EPOCHrule inREPO_POLICIES.md. Without them the check layer is served from cache on an unchanged tree and the build reports a green it never ran. - Server: also builds and runs the application
- Non-server: brings up dev environment and runs
make check - Image pinned by sha256 hash with version/date comment
- All Dockerfiles must run
- Gitea Actions workflow at
.gitea/workflows/check.ymlthat runsscript/cibuildon push — referencehttps://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml - Language-specific:
- Go:
go mod init sneak.berlin/go/<name>,.golangci.yml(fetch fromhttps://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml) - JS:
yarn init,yarn add --dev prettier - Python:
pyproject.toml
- Go:
Configure script/ Entrypoints and Makefile
Implementations live in script/ (scripts-to-rule-them-all); Makefile targets
are thin shims calling them. Model scripts:
https://git.eeqj.de/sneak/prompts/raw/branch/main/script/<name>
- scripts are POSIX sh (
#!/bin/sh,set -eu, no bashisms) so they run on alpine images without bash script/bootstrap/make bootstrap— installs all dependencies, idempotently, assuming nothing (pkg manager detection nix/apt/brew/apk; node used if present, else pinned version via nvm from a hash-verified archive; pinned yarn via corepack); Dockerfile runs it instead of inline installsscript/setup/make setup— readies a fresh clone: runsbootstrap, theninstall-precommit, plus repo-specific initscript/test/make test— runs real tests, not a no-op (30-second timeout)script/lint/make lint— runs linterscript/fmt/make fmt— formats code (writes)script/fmt-check/make fmt-check— checks formatting (read-only)script/check/make check— runstest,lint,fmt-check; must not modify filesscript/projectname— outputs the project name (used byscript/dockerfor the image tag)script/docker/make docker— builds Docker image, tagged viascript/projectname(byte-identical across repos); assignsepoch="$(date +%s%N)$$"on its own line and passes--build-arg CHECK_EPOCH="$epoch"script/cibuild— cd to repo root, assignepoch="$(date +%s%N)$$"on its own line, then rundocker build --build-arg CHECK_EPOCH="$epoch" .(what CI runs). The build arg is mandatory: see theCHECK_EPOCHrule inREPO_POLICIES.mdfor why each element is load-bearing. A baredocker build .fails closed by design.script/precommit— called by the pre-commit hook; runsscript/checkscript/install-precommit— installs the pre-commit hook that runsscript/precommitmake hooks— shims toscript/install-precommit- README Entrypoints section documents the scripts and links the standard
4. Verify
make checkpassesmake dockersucceeds- No secrets in repo
- No mutable image/package references
- No unnecessary files in repo root
- All dates written as YYYY-MM-DD
5. Merge and Set Up
- Commit, merge to
main make hooksto install pre-commit hook- Add remote and push
- Verify
mainpassesmake check