5 Commits
Author SHA1 Message Date
clawbot dd4027b907 Fold the August fleet findings into the policies, or drop them (closes #62)
check / check (push) Failing after 1s
Of the cross-repository findings recorded on 2026-08-09, two were rules a repository must follow that `prompts/REPO_POLICIES.md` did not yet state, and each now sits in the paragraph a reader would be in. A new or changed check is proven by planting a defect it must catch and watching the run fail, since a green run alone does not show the check ran. A separate workflow limited to `main` by a `branches` list is first run from the feature branch by adding that branch to the list and removing it before merging, with any publishing job kept behind `if: github.ref_name == 'main'`.

The other findings are dropped, each with its reason on the issue; the `config verify` warning goes by sneak's ruling on #40 that there is no config check step.

Model: opus-5-5
2026-10-04 15:14:44 +02:00
clawbot 5e5e7ea951 Say which Dockerfile stages run script/bootstrap (closes #90)
check / check (push) Failing after 2s
The bullet in `prompts/REPO_POLICIES.md` that requires a `Dockerfile` said every Dockerfile installs its prerequisites by running `script/bootstrap`, which the canonical Go `Dockerfile` in the same file never does. Reading the example as the deliberate one, the bullet now says the gate phases and the build stage start from their pinned base images and install what those images lack either inline, as the Go example does for `git`, or by running `script/bootstrap`, as this repository's own `Dockerfile` does for its yarn packages; the development environment stage of a non-server repo runs `script/bootstrap`. The new repo checklist item says the same.

The `COPY --from=` lines and the build stage's `apk add` line are unchanged.

Model: opus-5-5
2026-10-04 14:48:47 +02:00
clawbot 13125ac6f5 Merge TODO.md with git's union merge (closes #98)
check / check (push) Failing after 1s
Every PR here adds an entry at the top of Completed Steps in `TODO.md`, so each merge to `next` left the other open PRs conflicting there. A root `.gitattributes` now marks `TODO.md` with `merge=union`: when two branches insert at the same place, git keeps both sides. It applies to this repository only; nothing canonical changes.

Union never reports a conflict in `TODO.md`. When two new entries share an identical line, one can land inside the other, and a rebased entry sits below every entry that reached `next` after the branch was cut, so the merged entries are read after every merge or rebase. Whether Gitea's own conflict check applies the attribute is not known.

Model: opus-5-5
2026-10-04 14:14:51 +02:00
clawbot 61a9afbb4f Keep a submodule's own .git/config out of the build context (closes #88)
check / check (push) Failing after 2s
A submodule that keeps its own `.git` directory, instead of one under `.git/modules/`, still shipped `sub/.git/config` into the build context, credential included. Both git patterns in the canonical `.dockerignore` now start with `**/`: `**/.git/config` and `**/.git/modules/**/config`.

A submodule whose name has a `config` segment (`config`, `deploy/config`, `config/lib`) still loses its whole git directory, because the pattern also matches that directory, and Go's version stamping then fails the build loudly. The file records this as a known gap with the way around it, `git submodule add --name`; closing it needs a wildcard re-include that makes every build walk excluded directories. `prompts/REPO_POLICIES.md` and both checklists say the same.

Model: opus-5-5
2026-10-04 12:48:55 +02:00
clawbot f3ad01a78c Install lint-phase libraries with apt-get, not apk (closes #83)
check / check (push) Failing after 1s
A key point under the canonical Go `Dockerfile` example in `prompts/REPO_POLICIES.md` said to install lint-phase system libraries with `apk add`. The lint phase is built on the golangci-lint image, which is Debian-based and has no `apk`, and `vips-dev` is the alpine package name. The point now gives the `apt-get` command with the Debian package name (`libvips-dev`) and removes the package lists in the same `RUN`.

The other `apk` mentions are about the alpine build stage or `script/bootstrap` on the host and stay. Nothing is pinned or unpinned; that is the open owner question on #72.

Model: opus-5-5
2026-10-04 11:31:48 +02:00
6 changed files with 98 additions and 23 deletions
+10 -3
View File
@@ -18,9 +18,16 @@
# 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.
# 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/modules/**/config
# under .git/modules/, nested again for a submodule's own submodules, or in
# its own .git directory when it keeps one.
# KNOWN GAP: a submodule whose name has a `config` segment (`config`,
# `deploy/config`, `config/lib`) loses its whole git directory, because
# `**/.git/modules/**/config` also matches that segment's directory
# under .git/modules/. Go's version stamping then fails the build;
# nothing leaks. Name such a submodule without that segment:
# `git submodule add --name`.
**/.git/config
**/.git/modules/**/config
# Agent scratch: one full checkout of the repo per in-flight agent.
# Anchored because it occurs once where agents run at the repo root.
+4
View File
@@ -0,0 +1,4 @@
# Every PR adds an entry at the top of TODO.md's Completed Steps; union keeps
# both sides instead of conflicting. Git never reports a conflict here: read
# the merged entries after every merge or rebase.
TODO.md merge=union
+35
View File
@@ -21,6 +21,41 @@ fmt-check, and commit.
# Completed Steps
- 2026-10-04: Went through the fleet findings recorded on 2026-08-09 (issue 62)
and added the two rules `REPO_POLICIES.md` did not yet state: a new or changed
check is proven by planting a defect it must catch; and a change to a separate
workflow limited to `main` is first run from the feature branch, added to that
workflow's `branches` list and removed again before merging. The other
findings were already stated, replaced by `--no-cache`, about git worktrees,
or about how agents work together. The warning against
`golangci-lint config verify` is dropped because sneak ruled on
https://git.eeqj.de/sneak/prompts/issues/40 (2026-08-10) that there is no
config check step and the config is assumed valid; a vendored `.golangci.yml`
stays byte-identical to the canonical copy. The issue gives each reason.
- 2026-10-04: `REPO_POLICIES.md` now says which `Dockerfile` stages run
`script/bootstrap` (issue 90). The gate phases and the build stage start from
their pinned base images and install what those images lack either inline, as
the canonical Go `Dockerfile` does for `git`, or by running
`script/bootstrap`, as this repo's own `Dockerfile` does for its yarn
packages. The development environment stage, the final stage of a non-server
repo, runs `script/bootstrap`. The new repo checklist says the same.
- 2026-10-04: Added a root `.gitattributes` that merges `TODO.md` with git's
union merge (issue 98), so two branches that each add an entry at the top of
Completed Steps merge without a conflict. Git now never reports a conflict in
`TODO.md`: a real conflict elsewhere keeps both versions of the line, and when
two new entries share an identical line, one is inserted into the middle of
the other, which a rebase can do to an entry already on `next`. Read the
merged entries after every merge or rebase. This applies to this repository
only; no canonical file changed.
- 2026-10-04: The canonical `.dockerignore` now also keeps out the git `config`
of a submodule that keeps its own `.git` directory, which still reached the
image (issue 88): both git patterns now carry the `**/` prefix. A submodule
whose name has a `config` segment (`config`, `deploy/config`, `config/lib`)
still loses its whole git directory, so Go's version stamping fails the build;
the file records this as a `KNOWN GAP:` with the remedy,
`git submodule add --name`. Closing it would take a wildcard re-include, which
makes BuildKit walk every excluded directory, such as `node_modules`, on every
build. `REPO_POLICIES.md` and both checklists say so in the same words.
- 2026-10-04: The note under the canonical Go `Dockerfile` example in
`REPO_POLICIES.md` now installs lint-phase system libraries with `apt-get`
under their Debian package names (issue 83). The `golangci/golangci-lint`
+9 -4
View File
@@ -63,10 +63,15 @@ with your task.
here run anywhere other than the repo root, the anchored entry misses
`services/api/.claude/`: add anchored entries for those directories.
- [ ] If the repo embeds a version in a binary: `.dockerignore` lets `.git` into
the build context. It keeps out `.git/config` and each submodule's
`config` under `.git/modules/` at any depth (`.git/modules/**/config`),
which `git describe` does not need and which can hold a credential: a
password in a remote URL, or the token the CI checkout step stores there.
the build context. It keeps out every git `config` at any depth
(`**/.git/config`, `**/.git/modules/**/config`): the repository's own,
each submodule's under `.git/modules/`, and that of a submodule keeping
its own `.git` directory. `git describe` does not need them, and each can
hold a credential: a password in a remote URL, or the token the CI
checkout step stores there. A submodule whose name has a `config` segment
(`config`, `deploy/config`, `config/lib`) loses its whole git directory to
`**/.git/modules/**/config`, and Go's version stamping then fails the
build: give it a name without that segment (`git submodule add --name`).
The stage that compiles has `git` (the Debian Go image has it; an alpine
one needs `apk add --no-cache git`) and takes the version from the
`VERSION` build argument when one is given, otherwise from
+13 -6
View File
@@ -71,10 +71,15 @@ Template files can be fetched from:
will run them in subdirectories, `services/api/.claude/` needs its own
anchored entry.
- If the image embeds a version in a binary: `.dockerignore` lets `.git`
into the build context. It keeps out `.git/config` and each submodule's
`config` under `.git/modules/` at any depth (`.git/modules/**/config`),
which `git describe` does not need and which can hold a credential: a
password in a remote URL, or the token the CI checkout step stores there.
into the build context. It keeps out every git `config` at any depth
(`**/.git/config`, `**/.git/modules/**/config`): the repository's own,
each submodule's under `.git/modules/`, and that of a submodule keeping
its own `.git` directory. `git describe` does not need them, and each can
hold a credential: a password in a remote URL, or the token the CI
checkout step stores there. A submodule whose name has a `config` segment
(`config`, `deploy/config`, `config/lib`) loses its whole git directory to
`**/.git/modules/**/config`, and Go's version stamping then fails the
build: give it a name without that segment (`git submodule add --name`).
The stage that compiles has `git` (the Debian Go image has it; an alpine
one needs `apk add --no-cache git`) and takes the version from the
`VERSION` build argument when one is given, otherwise from
@@ -119,8 +124,10 @@ are thin shims calling them. Model scripts:
- [ ] `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
installs
archive; pinned yarn via corepack); a non-server repo's development
environment stage runs it instead of inline installs; a gate phase or the
build stage installs what its base image lacks either inline or by running
it
- [ ] `script/setup` / `make setup` — readies a fresh clone: runs `bootstrap`,
then `install-precommit`, plus repo-specific init
- [ ] `script/test` / `make test` — `docker build --no-cache --target test .`,
+27 -10
View File
@@ -104,10 +104,14 @@ style conventions are in separate documents:
`lint` phase and a `test` phase, with the final stage depending on both so the
image cannot be built unless they pass. For non-server repos the final stage
brings up a development environment; for server repos it is the runtime image.
Dockerfiles install development prerequisites by running `script/bootstrap`
rather than duplicating installs inline; COPY `script/` and the dependency
manifests (`package.json` + `yarn.lock`, `go.mod` + `go.sum`, etc.) before
running it.
The gate phases and the build stage start from their pinned base images and
install what those images lack either inline, as the canonical Go `Dockerfile`
below does for `git`, or by running `script/bootstrap`, as the `prompts`
repo's own `Dockerfile` does for its yarn packages. The development
environment stage installs development prerequisites by running
`script/bootstrap` rather than duplicating its installs inline. A stage that
runs `script/bootstrap` COPYs `script/` and the dependency manifests
(`package.json` + `yarn.lock`, `go.mod` + `go.sum`, etc.) before running it.
- **Linting and testing run in Docker, as phases of the `Dockerfile`.** There is
no separate lint file. `script/lint` and `script/test` each build one phase
@@ -156,6 +160,9 @@ style conventions are in separate documents:
not evidence that anything ran: a sub-second build reporting success is a
cache hit, not a result. Never invalidate by pruning — `docker builder prune`
and friends destroy a build cache shared with every other build on the host.
When a check is added or changed, prove it works by planting a defect it must
catch and watching the run fail on it, then revert the defect. A green run
alone shows neither that the check ran nor that it covers what it should.
- **The gate phases are separate stages, and the build stage depends on both.**
The lint phase is based on the `golangci/golangci-lint` image (pinned by
@@ -248,11 +255,16 @@ style conventions are in separate documents:
&& rm -rf /var/lib/apt/lists/*
```
- `.dockerignore` lets `.git` into the build context. It keeps out
`.git/config` and each submodule's `config` under `.git/modules/` at any
depth (`.git/modules/**/config`), which `git describe` does not need and
which can hold a credential: a password in a remote URL, or the token the
CI checkout step stores there. The stage that compiles has `git` (the
- `.dockerignore` lets `.git` into the build context. It keeps out every git
`config` at any depth (`**/.git/config`, `**/.git/modules/**/config`): the
repository's own, each submodule's under `.git/modules/`, and that of a
submodule keeping its own `.git` directory. `git describe` does not need
them, and each can hold a credential: a password in a remote URL, or the
token the CI checkout step stores there. A submodule whose name has a
`config` segment (`config`, `deploy/config`, `config/lib`) loses its whole
git directory to `**/.git/modules/**/config`, and Go's version stamping
then fails the build: give it a name without that segment
(`git submodule add --name`). The stage that compiles has `git` (the
Debian Go image has it; an alpine one needs `apk add --no-cache git`) and
takes the version from the `VERSION` build argument when one is given,
otherwise from `git describe --tags --always`. That gives the tag on a
@@ -274,7 +286,12 @@ style conventions are in separate documents:
carry the same guarantee, because its gate phases may come from the cache. The
image build is uncached and so runs the gate phases a second time. That is the
price of the rule above, and it is worth paying: the image that ships is built
from a run of its own gates rather than from a cache entry.
from a run of its own gates rather than from a cache entry. A separate
workflow limited to `main` by a `branches` list under `on: push` cannot be
checked by review: to try a change to it, add the feature branch to that list
and push, then remove the branch from the list again before merging. Keep any
job in it that publishes behind `if: github.ref_name == 'main'`, so the run
from the feature branch publishes nothing.
- Use platform-standard formatters: `black` for Python, `prettier` for
JS/CSS/Markdown/HTML, `go fmt` for Go. Always use default configuration with