2 Commits
Author SHA1 Message Date
sneak 3a4e0d9c47 Rewrite the -count=1 note to match the current files (closes #77)
check / check (push) Successful in 29s
The note under the canonical Go `make test` example in `prompts/REPO_POLICIES.md` still named the cache-busting build argument that `--no-cache` replaced, and said Go's cache was baked into earlier image layers.

It now says where Go's test result cache can replay a pass: on a developer's machine, where the Makefile target runs, so `-count=1` stays on both invocations. The `test` phase of the `Dockerfile` has nothing to replay: its base image holds no result for the repo's tests and no earlier step runs one.

The first paragraph no longer says the rerun would replay a failure: Go stores only passes.

Model: opus-5-5
2026-10-04 04:49:14 +00:00
clawbot 5de98c404e Keep each submodule's git config out of the build context (closes #75)
check / check (push) Successful in 28s
The canonical `.dockerignore` kept out `.git/config`, which can hold a credential, but not the `config` in each submodule's git directory under `.git/modules/`, nested again for a submodule's own submodules. It now also lists `.git/modules/**/config`, with one sentence in the comment above; `prompts/REPO_POLICIES.md` and both checklists say so in the same words.

The pattern stays under `.git/modules/` because `.git/**/config` would also drop a branch or tag named `config`, which `git describe` may need.

Known gap: a submodule whose name has a `config` path segment loses its whole git directory, so Go's version stamping fails the build loudly; tracked separately.

Model: opus-5-5
2026-10-04 05:31:51 +02:00
5 changed files with 85 additions and 64 deletions
+3
View File
@@ -17,7 +17,10 @@
# stage that compiles runs `git describe --tags --always` on .git, which # stage that compiles runs `git describe --tags --always` on .git, which
# does not need .git/config; that file can hold a credential, such as a # does not need .git/config; that file can hold a credential, such as a
# password in a remote URL or the token the CI checkout step stores there. # password in a remote URL or the token the CI checkout step stores there.
# Each submodule keeps a config with the same exposure in its git directory
# under .git/modules/, nested again for a submodule's own submodules.
.git/config .git/config
.git/modules/**/config
# Agent scratch: one full checkout of the repo per in-flight agent. # Agent scratch: one full checkout of the repo per in-flight agent.
# Anchored because it occurs once where agents run at the repo root. # Anchored because it occurs once where agents run at the repo root.
+12
View File
@@ -21,6 +21,18 @@ fmt-check, and commit.
# Completed Steps # Completed Steps
- 2026-10-04: Rewrote the note under the canonical Go `make test` example in
`REPO_POLICIES.md` (issue 77), which still named the cache-busting build
argument that `--no-cache` replaced. It now says where Go's test result cache
can replay a pass: on a developer's machine, where the Makefile target runs,
and not in the `test` phase of the `Dockerfile`, whose base image and earlier
steps hold no result for the repo's tests.
- 2026-10-04: The canonical `.dockerignore` now also keeps out each submodule's
`config` (issue 75). A submodule's git directory lives under `.git/modules/`,
nested again for its own submodules, and its `config` can hold a credential
just like `.git/config`. The pattern `.git/modules/**/config` covers every
depth and leaves the top-level `.git` that `git describe` reads untouched.
`REPO_POLICIES.md` and both checklists say so in the same words.
- 2026-10-03: Fixed two defects in the canonical Go `Dockerfile` example (issue - 2026-10-03: Fixed two defects in the canonical Go `Dockerfile` example (issue
73). The test phase now uses the Debian Go image, since `-race` needs cgo and 73). The test phase now uses the Debian Go image, since `-race` needs cgo and
the alpine image has no C compiler, so the phase failed before running a test. the alpine image has no C compiler, so the phase failed before running a test.
+23 -21
View File
@@ -1,6 +1,6 @@
--- ---
title: Existing Repo Checklist title: Existing Repo Checklist
last_modified: 2026-10-03 last_modified: 2026-10-04
--- ---
Use this checklist when beginning work in a repo that may not yet conform to our Use this checklist when beginning work in a repo that may not yet conform to our
@@ -59,26 +59,28 @@ with your task.
here run anywhere other than the repo root, the anchored entry misses here run anywhere other than the repo root, the anchored entry misses
`services/api/.claude/`: add anchored entries for those directories. `services/api/.claude/`: add anchored entries for those directories.
- [ ] If the repo embeds a version in a binary: `.dockerignore` lets `.git` into - [ ] If the repo embeds a version in a binary: `.dockerignore` lets `.git` into
the build context. It keeps out `.git/config`, which `git describe` does the build context. It keeps out `.git/config` and each submodule's
not need and which can hold a credential: a password in a remote URL, or `config` under `.git/modules/` at any depth (`.git/modules/**/config`),
the token the CI checkout step stores there. The stage that compiles has which `git describe` does not need and which can hold a credential: a
`git` (the Debian Go image has it; an alpine one needs password in a remote URL, or the token the CI checkout step stores there.
`apk add --no-cache git`) and takes the version from the `VERSION` build The stage that compiles has `git` (the Debian Go image has it; an alpine
argument when one is given, otherwise from `git describe --tags --always`. one needs `apk add --no-cache git`) and takes the version from the
That gives the tag on a tagged commit; on a later commit, the tag, the `VERSION` build argument when one is given, otherwise from
number of commits since it and the short commit (`v1.2.3-4-gabc1234`); and `git describe --tags --always`. That gives the tag on a tagged commit; on
the short commit when no tag is reachable. The stage that compiles also a later commit, the tag, the number of commits since it and the short
marks its working directory safe for git commit (`v1.2.3-4-gabc1234`); and the short commit when no tag is
(`git config --system --add safe.directory /src`): a context sent as a tar reachable. The stage that compiles also marks its working directory safe
stream keeps the sender's file owners, and git refuses a checkout owned by for git (`git config --system --add safe.directory /src`): a context sent
another user, so the version would come out empty. `ARG VERSION` has no as a tar stream keeps the sender's file owners, and git refuses a checkout
default, and the build fails if the context carries `.git` and the version owned by another user, so the version would come out empty. `ARG VERSION`
still comes out empty, `dev` or `unknown`. A plain `docker build .` with has no default, and the build fails if the context carries `.git` and the
no build arguments must succeed; a Dockerfile that refuses an empty build version still comes out empty, `dev` or `unknown`. A plain
argument drops that refusal and keeps the argument. `script/docker` and `docker build .` with no build arguments must succeed; a Dockerfile that
`script/cibuild` pass the version they compute on the host; it takes refuses an empty build argument drops that refusal and keeps the argument.
precedence. A tag-derived version additionally needs `fetch-depth: 0` on `script/docker` and `script/cibuild` pass the version they compute on the
the CI checkout step, which clones shallow and fetches no tags by default. host; it takes precedence. A tag-derived version additionally needs
`fetch-depth: 0` on the CI checkout step, which clones shallow and fetches
no tags by default.
- [ ] Gitea Actions workflow in `.gitea/workflows/` runs `script/cibuild` on - [ ] Gitea Actions workflow in `.gitea/workflows/` runs `script/cibuild` on
push — reference push — reference
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml` `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml`
+19 -18
View File
@@ -1,6 +1,6 @@
--- ---
title: New Repo Checklist title: New Repo Checklist
last_modified: 2026-10-03 last_modified: 2026-10-04
--- ---
Use this checklist when creating a new repository from scratch. Follow the steps Use this checklist when creating a new repository from scratch. Follow the steps
@@ -68,23 +68,24 @@ Template files can be fetched from:
will run them in subdirectories, `services/api/.claude/` needs its own will run them in subdirectories, `services/api/.claude/` needs its own
anchored entry. anchored entry.
- If the image embeds a version in a binary: `.dockerignore` lets `.git` - If the image embeds a version in a binary: `.dockerignore` lets `.git`
into the build context. It keeps out `.git/config`, which `git describe` into the build context. It keeps out `.git/config` and each submodule's
does not need and which can hold a credential: a password in a remote URL, `config` under `.git/modules/` at any depth (`.git/modules/**/config`),
or the token the CI checkout step stores there. The stage that compiles which `git describe` does not need and which can hold a credential: a
has `git` (the Debian Go image has it; an alpine one needs password in a remote URL, or the token the CI checkout step stores there.
`apk add --no-cache git`) and takes the version from the `VERSION` build The stage that compiles has `git` (the Debian Go image has it; an alpine
argument when one is given, otherwise from `git describe --tags --always`. one needs `apk add --no-cache git`) and takes the version from the
That gives the tag on a tagged commit; on a later commit, the tag, the `VERSION` build argument when one is given, otherwise from
number of commits since it and the short commit (`v1.2.3-4-gabc1234`); and `git describe --tags --always`. That gives the tag on a tagged commit; on
the short commit when no tag is reachable. The stage that compiles also a later commit, the tag, the number of commits since it and the short
marks its working directory safe for git commit (`v1.2.3-4-gabc1234`); and the short commit when no tag is
(`git config --system --add safe.directory /src`): a context sent as a tar reachable. The stage that compiles also marks its working directory safe
stream keeps the sender's file owners, and git refuses a checkout owned by for git (`git config --system --add safe.directory /src`): a context sent
another user, so the version would come out empty. `ARG VERSION` has no as a tar stream keeps the sender's file owners, and git refuses a checkout
default, and the build fails if the context carries `.git` and the version owned by another user, so the version would come out empty. `ARG VERSION`
still comes out empty, `dev` or `unknown`. A plain `docker build .` with has no default, and the build fails if the context carries `.git` and the
no build arguments must succeed; a Dockerfile that refuses an empty build version still comes out empty, `dev` or `unknown`. A plain
argument drops that refusal and keeps the argument. `docker build .` with no build arguments must succeed; a Dockerfile that
refuses an empty build argument drops that refusal and keeps the argument.
- The Dockerfile carries a `lint` phase and a `test` phase, each invoking - The Dockerfile carries a `lint` phase and a `test` phase, each invoking
its tool directly rather than through `make` or `script/`, and the final its tool directly rather than through `make` or `script/`, and the final
stage carries a `COPY --from=` of a harmless file from each so the image stage carries a `COPY --from=` of a harmless file from each so the image
+28 -25
View File
@@ -1,6 +1,6 @@
--- ---
title: Repository Policies title: Repository Policies
last_modified: 2026-10-03 last_modified: 2026-10-04
--- ---
This document covers repository structure, tooling, and workflow standards. Code This document covers repository structure, tooling, and workflow standards. Code
@@ -239,20 +239,21 @@ style conventions are in separate documents:
- If the project requires CGO or system libraries for linting (e.g. - If the project requires CGO or system libraries for linting (e.g.
`vips-dev`), install them in the lint phase with `apk add`. `vips-dev`), install them in the lint phase with `apk add`.
- `.dockerignore` lets `.git` into the build context. It keeps out - `.dockerignore` lets `.git` into the build context. It keeps out
`.git/config`, which `git describe` does not need and which can hold a `.git/config` and each submodule's `config` under `.git/modules/` at any
credential: a password in a remote URL, or the token the CI checkout step depth (`.git/modules/**/config`), which `git describe` does not need and
stores there. The stage that compiles has `git` (the Debian Go image has which can hold a credential: a password in a remote URL, or the token the
it; an alpine one needs `apk add --no-cache git`) and takes the version CI checkout step stores there. The stage that compiles has `git` (the
from the `VERSION` build argument when one is given, otherwise from Debian Go image has it; an alpine one needs `apk add --no-cache git`) and
`git describe --tags --always`. That gives the tag on a tagged commit; on takes the version from the `VERSION` build argument when one is given,
a later commit, the tag, the number of commits since it and the short otherwise from `git describe --tags --always`. That gives the tag on a
commit (`v1.2.3-4-gabc1234`); and the short commit when no tag is tagged commit; on a later commit, the tag, the number of commits since it
reachable. The stage that compiles also marks its working directory safe and the short commit (`v1.2.3-4-gabc1234`); and the short commit when no
for git (`git config --system --add safe.directory /src`): a context sent tag is reachable. The stage that compiles also marks its working directory
as a tar stream keeps the sender's file owners, and git refuses a checkout safe for git (`git config --system --add safe.directory /src`): a context
owned by another user, so the version would come out empty. `ARG VERSION` sent as a tar stream keeps the sender's file owners, and git refuses a
has no default, and the build fails if the context carries `.git` and the checkout owned by another user, so the version would come out empty.
version still comes out empty, `dev` or `unknown`. A plain `ARG VERSION` has no default, and the build fails if the context carries
`.git` and the version still comes out empty, `dev` or `unknown`. A plain
`docker build .` with no build arguments must succeed; a Dockerfile that `docker build .` with no build arguments must succeed; a Dockerfile that
refuses an empty build argument drops that refusal and keeps the argument. refuses an empty build argument drops that refusal and keeps the argument.
@@ -316,17 +317,19 @@ style conventions are in separate documents:
``` ```
`-count=1` is required on both invocations: it defeats Go's test _result_ `-count=1` is required on both invocations: it defeats Go's test _result_
cache, so the target cannot report a pass it did not earn, and the rerun cache, so neither run can report a stored pass in place of running the
reproduces a failure instead of replaying it. It leaves the build cache tests. It leaves the build cache alone, so it costs the runtime of the suite
alone, so it costs the runtime of the suite and no recompilation. and no recompilation.
Note that this is a second, independent cache, stacked below the Docker That cache is Go's own, separate from Docker's layer cache. Go stores a
layer cache that [issue #26](https://git.eeqj.de/sneak/prompts/issues/26) passing result in its cache directory (`GOCACHE`), and when the same tests
addresses. `CHECK_EPOCH` guarantees the `RUN make test` _step_ re-executes; run again on unchanged code it prints that result, marked `(cached)`,
it does not guarantee `go test` inside that step does any work, because the without running them. That matters on a developer's machine, where this
`GOCACHE` baked into earlier image layers survives into the re-executed target runs and the directory lasts from one run to the next. The `test`
step. They are two separate defects requiring two separate fixes, and a fix phase of the `Dockerfile` needs no `-count=1`: its base image holds no
for one must not be recorded as covering the other. result for this repo's tests and nothing before its `go test` step runs a
test, so there is nothing to replay. `--no-cache` (above) is what makes that
step run on an unchanged tree.
Python example: Python example: