Commit Graph
130 Commits
Author SHA1 Message Date
clawbot 917fe4bc1d Rename script/install to script/fetch-policy
check / check (push) Canceled after 0s
By convention, and in scripts-to-rule-them-all, script/install installs
the program itself. This script fetches the shared policy files into a
repo. The make target, the test names and the messages take the new
name. Behaviour is unchanged.

Model: opus-5-5
2026-11-10 20:19:00 +00:00
clawbot ff42f4013d Correct the kept-lines bullet; test .editorconfig with no own line
check / check (push) Successful in 1m1s
REPO_POLICIES said an ignore file lacking the closing comment keeps every
line the canonical file has never held; blank lines and comments are
dropped, so it now says entries, in a bullet of its own.

A new scenario covers an .editorconfig lacking the comment with no line
of its own, which the script replaces.

Model: opus-5-5
2026-11-09 22:31:17 +00:00
clawbot 5d82424a20 REPO_POLICIES: say which lines an ignore file lacking the comment keeps
check / check (push) Failing after 49s
Model: opus-5-5
2026-11-09 21:46:41 +00:00
clawbot 8a25e502f4 script/install: do not stop on a missing closing comment
check / check (push) Successful in 55s
A .gitignore or .dockerignore lacking the canonical last line no longer
stops the script: each line the canonical file has never held goes
below the fetched content. An .editorconfig lacking it is replaced,
unless it has such a line, which stops the script.

The stub curl now writes files with no execute bit, as a real download
does, so the tests exercise the mode the script sets.

Model: opus-5-5
2026-11-09 21:34:29 +00:00
clawbot 9f83f3c1b1 README: script/install stops when its target is this repo
check / check (push) Successful in 54s
Started from this repo with a path, the script writes into that clone,
so "stops when run here" was false.

Model: opus-5-5
2026-11-09 20:46:27 +00:00
clawbot e89fc86adc Drop make install from the required targets; test three more stops
check / check (push) Successful in 48s
The install target stays in this repo's Makefile only. sneak/vaultik
already has an install target with another meaning, and every repo
still gets script/install.

Tests: a repo's own script/update-policy stops the script, and a repo
whose only JavaScript source is a .js or .mjs file gets the JavaScript
style guide.

Model: opus-5-5
2026-11-09 20:04:01 +00:00
clawbot 76b75fa79f script/install: write every listed file the repo lacks
check / check (push) Successful in 48s
A listed file the repo lacks is now written whole, with no keep rule.
A prompts/NAME.md goes to docs/NAME.md unless the repo keeps it at
NAME.md, and any other file goes to its own path. A language's files
are skipped when git tracks no source file of that language.

A listed path git ignores now stops the script before it writes.

README bullets split into short sentences, and a false sentence about
template repos deleted.

Model: opus-5-5
2026-11-09 19:38:41 +00:00
clawbot f4275b9ac0 script/install: stop on a repo's own script of the same name
check / check (push) Successful in 26s
script/install replaced any tracked script/install or
script/update-policy in the target, including a repo's own unrelated
script. It now stops when such a file has a line the canonical file
has never held. An older shared copy is still replaced.

The padded file in the self-replacement test is now an earlier
canonical version, so the new stop does not catch it.

Model: opus-5-5
2026-11-09 18:49:16 +00:00
clawbot 454f3410a1 Add script/install; script/update-policy runs it and commits (closes #165)
check / check (push) Successful in 31s
script/install fetches the policy files from prompts over HTTP and
writes them into a repo, installing itself and script/update-policy
there. script/update-policy fetches the current script/install, runs
it on its own repo and commits without pushing. The file list and the
rules for keeping a repo's own entries move to script/install.

Model: opus-5-5
2026-11-09 18:32:46 +00:00
clawbot 936ead8425 Add script/update-policy to re-vendor policy files (closes #162)
check / check (push) Successful in 24s
One command fetches the policy files a repo vendors from `prompts`, keeps the repo's own entries, commits them by name and pushes. A line the canonical file has never held stops the script before anything is written, as does a failed fetch. The canonical `.dockerignore` gains the closing comment the script needs. `test/update-policy.sh` runs in the `test` phase of `Dockerfile`.

Judgement call: `.gitea/workflows/check.yml` and `.prettierrc` are replaced whole.
Limitation: a repo with its own `.golangci.yml` settings, such as `sneak/homoicon`, stops until those are dealt with.

Model: opus-5-5
2026-11-09 11:00:11 +01:00
clawbot d673785d33 Format Go with gofmt, then golines -m 77 (#161)
check / check (push) Successful in 24s
2026-11-07 05:21:32 +01:00
clawbot 8c889fa622 REPO_POLICIES: script/ entrypoints are the single source of truth (#157)
check / check (push) Successful in 1m16s
2026-11-06 01:18:52 +01:00
clawbot 6e5fa4c607 REPO_POLICIES: pinning covers what we download ourselves; distribution packages are outside it (#156)
check / check (push) Canceled after 3s
2026-11-06 01:18:44 +01:00
clawbot 9389bf0172 Commit yarn 4 in the tree and install with --immutable (closes #149)
check / check (push) Successful in 16s
Follows sneak's ruling at
#149 (comment). This
repository now carries yarn 4.18.1 under .yarn/releases. The
distribution's yarn only starts that file, and that file does the work.
yarn.lock is converted once, and script/bootstrap installs with
--immutable instead of stopping on yarn's major version. Node is the
distribution's newest Node package: nodejs-current on Alpine and
nodejs_latest on nix. Every Dockerfile stage that needs yarn also copies
.yarnrc.yml and .yarn/releases/. The policies and both checklists say
so, with the steps for converting and for a new repository.

Model: opus-5-5
2026-11-04 21:32:55 +01:00
clawbot 3066aae835 Allow go test on one package while iterating (closes #51)
check / check (push) Canceled after 0s
Follows sneak's ruling at
#51 (comment). An agent
whose work is confined to one package may run `go test` directly on that
package's suite, or on individual tests in it, while iterating. `go build`,
`go vet` and the linter still go through make targets. The full `make check`
is still required before every push. The `Makefile` gains nothing.

The rule on Docker now says the lint and test gates run there, because a run
while iterating is not a gate.

Model: opus-5-5
2026-11-04 19:32:37 +01:00
clawbot 86c7617f86 Install node, yarn and python from the distribution (closes #146)
check / check (push) Canceled after 0s
Follows sneak's ruling at
#146 (comment). Runtimes
and the installer tools bundled with python come from the distribution,
with no version and no hash. Third-party packages stay pinned by hash.

script/bootstrap drops nvm and corepack. It installs node, yarn and the
node packages only when yarn.lock is in the tree, and stops there when
yarn's major version is not 1. This repository's Dockerfile starts from
Alpine 3.24. The Python example starts from debian:trixie-slim, keeps
pipenv at $HOME/.pipenv on a host and in an image, and sets
PIP_ONLY_BINARY=:all:, so pip downloads no build tools without a hash
check.

Model: opus-5-5
2026-11-04 09:55:26 +01:00
clawbotandsneak b36ddacee1 Rewrite REPO_POLICIES.md sentence by sentence (closes #136) (#147)
check / check (push) Canceled after 0s
Rewrites every sentence of `prompts/REPO_POLICIES.md` against the sentence rules, for #136. No rule's meaning, `must`/`should` or order changed. Code blocks, digests, URLs and commands are byte-identical. Both checklists carry the same rewrite of the paragraph they quote.

## For sneak

Kept as they are: each looks false or contradicts another rule. Line numbers are this branch's.

- Lines 196-197: the final stage carries the `COPY --from=` lines; in the `Dockerfile` (345-346) the build stage does, the runtime stage none.
- Lines 629-641 and 670-675: `make test` runs `go test` and `pytest` on the host; 80-81 make targets shims, 183-185 make `script/test` a Docker build.
- Lines 23-37 pin by hash; 103-112 install node (nvm) and yarn (corepack) by version. Tracked at #146.
- Line 131 counts four extensions; `script/lint`, `script/fmt`, `script/fmt-check`, `script/docker` (85-89) are not in the standard either.
- Lines 149-151: the Makefile is the single source of truth; 80-81 (implementation in `script/`), 211 (tool invoked in a phase), 616 (test command in the `Dockerfile`).
- Lines 64-68 require `make test` and `make lint`, which 183-185 make Docker builds; line 167 only says a repo should have a `Dockerfile`.
- Line 759 says byte-identical; the block at 767 has `tag="$(script/projectname)"`, both scripts have `tag="$("$SCRIPT_DIR/projectname")"`.
- Lines 834-839: `script/bootstrap` never tests presence, 860 excepts only node; `ensure_yarn` in the canonical `script/bootstrap` skips the install when yarn is present, without a version check.

## Disclosures

- Judgement call: short name lists stay inline under about 15 words.

Model: fable-5-1
Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #147
Co-authored-by: clawbot <35+clawbot@noreply.example.org>
2026-11-04 05:17:16 +01:00
clawbot 8400e4cd1f Update the canonical .golangci.yml for golangci-lint v2.15.0 (closes #142)
check / check (push) Canceled after 0s
Moves the pin to v2.15.0 and enables canonicalheader again, because that
release fixes the random misses behind
#105.

The depguard exemption reached every directory below one ending in test,
and a whole checkout under such a directory. It now covers only the files
directly inside, and the directory a repository is cloned into does not
count. gomodguard_v2 also blocks github.com/go-redis/redis/v9, whose
pre-releases can still be imported.

uniq-by-line is now false, so a line that trips two linters reports both
findings.

Three comments are corrected. A new comment says the file has no
formatters section, so golangci-lint run does not run gofmt.

Model: opus-5-5
2026-11-04 01:28:09 +01:00
clawbot b656617183 Allow packages from the distribution's own package index unpinned (closes #72)
check / check (push) Canceled after 0s
A package from the distribution's own package index now needs no version
and no hash, and pulling that index is allowed, on sneak's answer at
#72 (comment). The
distribution is the pinned base image's in a Dockerfile and the host's
on a host. It is trusted, and everything else stays pinned by hash. A
package source that a Dockerfile adds itself does not get the exception.

The pinning rule of REPO_POLICIES.md and both checklists say so, and the
canonical Go Dockerfile's apk add line has a comment saying why it is
allowed.

Model: opus-5-5
2026-11-04 00:28:23 +01:00
clawbot 229ea67434 Skip the verbose test rerun after a timeout (closes #61)
check / check (push) Canceled after 0s
A hung test used the 90-second backstop twice, because the verbose
rerun waited for the same hang. The Go recipe now looks in the first
run's output for the lines Go prints for a hang, and exits 1 with no
rerun. A failure with neither line in its output still reruns with -v.

The Python make test example takes the same timeout wrapper as its
Dockerfile example. The 60 and 90 second rule and the 5-minute rule say
a hung package uses the backstop once. The Go item in both repo
checklists now asks for this.

Model: opus-5-5
2026-11-03 23:08:23 +01:00
clawbot 430964ceac Add API_POLICIES.md (closes #137)
check / check (push) Canceled after 0s
prompts/API_POLICIES.md states sneak's rule from
sneak/routewatch#199: a value in an API
response is never a string with a label or unit in it. A native value
is sent as that type, with its unit in the field name.

The list at the top of REPO_POLICIES.md and the two code style
commands in the README now name the new file.

Model: opus-5-5
2026-10-27 18:49:49 +01:00
clawbot 279b10164d Keep a Python test phase's lockfile install in check builds (closes #133)
check / check (push) Canceled after 0s
A Python `test` phase that installs its packages from `Pipfile.lock` now does so above `ARG CACHEBUST`, through `script/bootstrap`, in a layer of its own. Check builds keep that layer as they keep Go's modules, and the tests still run after the line on every build. In that step `script/bootstrap` installs only system packages, pipenv and its dependencies by hash, and the lockfile's packages. The policy, both checklists and the README list the steps above the line the same way; the policy has a short example. This writes down sneak's ruling at sneak/rfscan#80 (comment).

rfscan installs pipenv by version, not by hash, so its `script/bootstrap` does not meet this rule yet.

Model: opus-5-5
2026-10-26 20:39:00 +01:00
clawbot aef30c320a Allow homoicon's local copy of sobek in the canonical .golangci.yml (closes #134)
check / check (push) Canceled after 0s
sneak decided that homoicon keeps a local copy of sobek, its JavaScript
engine, and fixes it in its own tree
(sneak/homoicon#1759 (comment)).
homoicon's go.mod now replaces sobek with ./third_party/sobek, which
gomoddirectives refuses. The canonical .golangci.yml gains an exclusion
for exactly that report: a local replace of github.com/grafana/sobek in
a repository's root go.mod. Every other local replace is still refused.
It is an exclusion rather than a replace-allow-list entry because
gomoddirectives does not check that list for a replace that points at a
local path. TODO.md records the change.

Model: opus-5-5
2026-10-21 17:01:38 +02:00
clawbot 065357920a Keep modules, lint cache and system packages in check builds (closes #130)
check / check (push) Canceled after 0s
On sneak's ruling in #130, check
builds keep three more things besides Go's build cache. In each stage of
the canonical Go Dockerfile, the system-package install and the module
download come before ARG CACHEBUST, so Docker keeps those layers until
the base image, the install line, go.mod or go.sum changes. Modules are
kept as a layer, not a cache mount, because Go does not check a cache
mount's files again. golangci-lint run also mounts golangci-lint's cache.
Every step that lints, tests or compiles still comes after ARG CACHEBUST,
both go test runs keep -count=1, and a step that also installs node
packages stays below the line. The policy, checklists, Go style guide,
README and script comments say the same.

Model: opus-5-5
2026-10-18 16:56:25 +02:00
clawbot e3f79c49da Keep Go's build cache in check builds (closes #113)
check / check (push) Canceled after 0s
The script/ builds pass a new CACHEBUST build argument on every run in
place of --no-cache, which also emptied Go's build cache mount. Every
Dockerfile stage declares ARG CACHEBUST first, so every RUN step still
reruns on an unchanged tree. The canonical Go Dockerfile mounts only
Go's build cache, on the steps that compile, so compiled packages
survive between check builds; both go test runs carry -count=1, so no
test result is reused. golangci-lint's own cache and the module cache
are not kept.

A repository re-vendors the scripts and adds the ARG lines in one
commit: a stage without the line is served from cache with no warning.

Unverified: not yet tried on the shared CI runner.

Model: opus-5-5
2026-10-15 16:50:31 +02:00
clawbot f9e23ccae3 Install the pinned node when the installed one is another major version (closes #118)
check / check (push) Canceled after 0s
script/bootstrap used whatever node was installed, so on the CI runner
image, which ships node 24, the pinned yarn 1.22.22 printed the
deprecation warning DEP0169 on every bootstrap. It now uses the
installed node only when its major version is the pinned one, and
otherwise installs the pinned node with nvm, as it already did when node
was missing, with yarn and the packages under it. It prints the node
version it uses. Only the major is compared because the Dockerfile
stages use a node 22 alpine image that nvm cannot replace. script/fmt
and script/fmt-check carry the same test to pick their yarn: the yarn on
PATH, or yarn under the pinned node loaded through nvm.

Model: opus-5-5
2026-10-08 04:14:21 +02:00
clawbot c55a0cb2f0 Tag the image build in the checklist's script/cibuild item (closes #125)
check / check (push) Canceled after 0s
The new-repository checklist gave script/cibuild's image build without a
tag, so a repository written from it left a dangling image behind on
every run, and it used $version without saying where it comes from. The
item now gives the build as the canonical script/cibuild runs it, with
-t "$tag", and names the two steps the script runs before it, each on
its own line: the version from git describe --tags --always --dirty
(unknown if empty) and the tag from script/projectname. The other docker
build commands the checklists and REPO_POLICIES.md give for script/
already matched their scripts.

Model: opus-5-5
2026-10-07 13:02:05 +02:00
clawbot 1d9b046b91 Stop the lint and test builds writing an image (closes #123)
check / check (push) Canceled after 0s
script/lint and script/test build their Dockerfile phase with
--output type=cacheonly in place of a tag. The phase still runs
uncached and a failing step still fails the build, but no image is
written: nothing used those images, and writing one out took about 16
seconds of a Go repository's test build. script/cibuild and
script/docker keep their tags. REPO_POLICIES.md, both checklists and
the README now say the gate builds write no image.

Model: opus-5-5
2026-10-07 12:02:02 +02:00
clawbot 0b20f18734 Set a time limit on the canonical check job (closes #120)
check / check (push) Canceled after 0s
The canonical check workflow gave its job no time limit, so a hung
script/cibuild held the shared runner until the runner's own default.
The check job now sets timeout-minutes: 20. script/cibuild runs three
Docker builds (the test phase, the lint phase, then the image, which
runs both again), each held to the 5-minute build limit, plus the
bootstrap. REPO_POLICIES.md and both checklists name the limit among
what the workflow sets.

Model: opus-5-5
2026-10-07 11:31:34 +02:00
clawbot a04a76d59c Make the canonical package.json private instead of declaring MIT (closes #119)
check / check (push) Canceled after 0s
Repositories copy package.json to get prettier, and with "license": "MIT"
each of them declared MIT whatever its own licence is. "private": true
keeps yarn from printing "No license field" and makes no licence claim.
This repository's LICENSE and README License section are unchanged.

Model: opus-5-5
2026-10-07 11:02:12 +02:00
clawbot b3508a4361 Fetch history and tags in the canonical workflow (closes #110)
check / check (push) Successful in 24s
The policy said a repository whose version comes from git tags needs `fetch-depth: 0` on its CI checkout, because the checkout action clones shallow with no tags; every repository's version comes from `git describe --tags --always`, but the canonical `.gitea/workflows/check.yml` did not set it, so CI stamped a bare short commit id where a local build of a tagged repository stamps the tag. The checkout step now sets `fetch-depth: 0` with a one-line comment, and the workflow bullet of `prompts/REPO_POLICIES.md` and both checklists name it beside `persist-credentials: false` and the `concurrency` block, as part of what the workflow does.

Unverified: a live run, which waits on the shared runner.

Model: opus-5-5
2026-10-06 08:15:41 +02:00
clawbot 8fe0709414 Refresh apt package lists once in script/bootstrap (closes #115)
check / check (push) Canceled after 0s
`pkg_install` in the canonical `script/bootstrap` ran `apt-get install` with no `apt-get update` before it. The Gitea runner image starts with empty package lists, so a repository's own `pkg_install` of anything the image lacks, Go included, failed with "Unable to locate package". The apt branch now refreshes the lists once, before the first install of a run, in the same `$SUDO env DEBIAN_FRONTEND=noninteractive` form, and skips the refresh on later calls. nix, brew and apk are unchanged. Repositories that refresh in their own section, or changed their copy, drop that at their next re-vendor.

Model: opus-5-5
2026-10-06 07:31:21 +02:00
clawbot 01954b6946 Say that a build from a linked worktree needs the version passed in (closes #111)
check / check (push) Canceled after 0s
A plain `docker build .` from a checkout whose `.git` is a file (a linked worktree, or a repository checked out as a submodule) stops at the version check of the canonical `Dockerfile` example: that file points to a git directory outside the build context, so `git describe` prints nothing. The check is right to refuse an empty version; what was missing is what to do. `prompts/REPO_POLICIES.md` and both checklists now say such a build is given its version with `--build-arg VERSION=...`, as `script/docker` and `script/cibuild` already do. The check itself is unchanged.

Model: opus-5-5
2026-10-06 06:33:19 +02:00
clawbot 6aac45857a Cancel replaced CI runs and drop the checkout token (closes #107)
check / check (push) Canceled after 0s
The canonical `.gitea/workflows/check.yml` lacked two settings `dnswatcher` had added, so a byte-identical re-vendor removed them. A `concurrency` block grouped by workflow and branch, with `cancel-in-progress: true`, makes a new push cancel the older run on the same branch and leaves every other branch's runs alone; on 2026-10-02 45 stale runs had queued on the one shared runner. `persist-credentials: false` on the checkout step keeps the job's token out of `.git/config`; `script/cibuild` needs no token. Each has a one-line comment, and the policy's workflow bullet and both checklists describe the file as it now is.

Unverified: the two live checks, which wait on the shared runner.

Model: opus-5-5
2026-10-06 05:52:57 +02:00
clawbot f5c4bb6e2c Disable canonicalheader in the canonical .golangci.yml (closes #105)
check / check (push) Successful in 28s
In golangci-lint v2.14.0, `canonicalheader` misses findings at random in a package that also calls `ResponseWriter.Header()`: on the same tree, repeated runs sometimes reported a non-canonical header key and sometimes reported nothing. So one commit could fail lint on one run and pass on the next, in every Go repository that vendors this file. Reproduced with the pinned image and the canonical config.

The canonical `.golangci.yml` now disables it, with a comment saying it comes back once a pinned golangci-lint release fixes it. New `.golangci.yml` sha256: `e49052a1418127b54b20cea530dfd3cc6ddfc126a9fd27fd570ccca1a3f18bc7`.

Model: opus-5-5
2026-10-06 05:15:41 +02:00
clawbot cc440118c8 Say where a repository's own .gitignore and .editorconfig entries go (closes #103)
check / check (push) Successful in 39s
The canonical `.gitignore` had no place for a repository's own build outputs, and nothing said a repository's own `.editorconfig` sections survive a re-vendor, so re-vendoring dropped them: a Go repository lost `/bin/`, `*.test` and `*.out`, and its tabs for Go files.

`.gitignore` now ends with a section, like `.dockerignore`'s header, where a repository adds its own build outputs (a root binary written `/myapp`) and its own environment-template negations, which a re-vendor keeps. `.editorconfig` gains `[*.go]` with tabs and the same kind of closing note. `prompts/REPO_POLICIES.md`, both checklists and the Go styleguide say these two files are the canonical content followed by the repository's own entries. Closes #104 too.

Model: opus-5-5
2026-10-06 04:15:16 +02:00
clawbot b09fff488b Assign the image tag on its own line in script/ (closes #101)
check / check (push) Successful in 49s
`script/cibuild`, `script/docker`, `script/lint` and `script/test` passed the image tag from `script/projectname` inline in the `docker build` arguments. A failing command substitution inside an argument does not trip `set -e`, so the scripts went on to `docker build` with an empty, `-lint` or `-test` tag, against the rule their own comment states. Each now assigns `tag` on its own line before `docker build`, so the script stops where `script/projectname` fails. The snippets in `prompts/REPO_POLICIES.md` show the same form, and the policy states the own-line rule.

Consuming repositories pick this up on their next re-vendor; the defect failed closed.

Model: opus-5-5
2026-10-06 02:52:23 +02:00
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
clawbot c32b10e77f Let fx own signals and the exit code in the server example (closes #86)
check / check (push) Failing after 2s
The server lifecycle example in `prompts/GO_HTTP_SERVER_CONVENTIONS.md` dropped its exit code, installed its own SIGINT/SIGTERM handler beside the one fx's `Run()` installs, and exited from a goroutine when Sentry could not start, so no stop hook ran.

fx now owns signals and the exit code: `main` calls `Run()`; a listen error shuts fx down with `fx.ExitCode(1)` through `fx.Shutdowner`; `enableSentry()` returns its error from the start hook; the stop hook shuts the HTTP server down within 5 seconds, flushes Sentry, and fails when requests are still running. The start hook builds the HTTP server before the listen goroutine so the stop hook can reach it. A new paragraph says who owns signals and the exit code.

Model: opus-5-5
2026-10-04 11:02:18 +02:00
clawbot c43c1f4bca Pin host Go tools by commit hash with go install (closes #37)
check / check (push) Failing after 2s
Writes sneak's 2026-09-09 ruling ("commit pinned installation, not pulled into deps") into the `prompts/REPO_POLICIES.md` bullet that says `script/bootstrap` installs a pinned tool by comparing versions: a Go tool a repo needs on the host is installed with `go install` pinned to a commit hash, naming the tool's main package, and is never tracked as a `go.mod` tool dependency or through a `tools.go` file, either of which pulls the tool's own dependencies into the repo's `go.mod` and `go.sum`.

golangci-lint is unchanged: no repo installs it on the host, and it stays pinned by its image digest.

Model: opus-5-5
2026-10-04 09:49:13 +02:00
clawbot 567944f8d8 Ignore hardware-backed SSH key files in the canonical ignore files (closes #81)
check / check (push) Failing after 2s
`ssh-keygen` names the private key of a key backed by a hardware security key `id_ecdsa_sk` or `id_ed25519_sk`. The canonical `.gitignore` and `.dockerignore` listed only `id_rsa`, `id_dsa`, `id_ecdsa` and `id_ed25519`, so a repository could commit these files or copy them into an image.

Both names are added beside their plain counterparts in each file's own style: unanchored in `.gitignore`, `**/`-prefixed in `.dockerignore`, case-folded with character ranges in both. A pattern matches the whole file name, so the `.pub` halves stay trackable and still reach the build context.

Model: opus-5-5
2026-10-04 09:14:52 +02:00
clawbot fa3202f214 Give package.json the MIT license field (closes #76)
check / check (push) Failing after 2s
`package.json` now carries `"license": "MIT"`, matching `LICENSE`. Without it yarn printed `warning package.json: No license field` and `warning No license field` each time `script/bootstrap` ran inside the Docker phases of `make check`. No other yarn warning appears in the bootstrap output.

Model: opus-5-5
2026-10-04 08:31:46 +02:00
clawbot 562b40bfe5 Keep agent guidance in one root AGENTS.md (closes #31)
check / check (push) Failing after 9s
Writes down sneak's 2026-08-22 ruling: the in-repo memory rule that older vendored copies of `REPO_POLICIES.md` still carry was retired, not lost.

`prompts/REPO_POLICIES.md` gains one bullet after the files a new repo must contain: guidance for coding agents lives in one `AGENTS.md` at the repository root, never under a file or directory named after one agent tool, and never split into separate memory files. `AGENTS.md` joins the files allowed in the repo root, which would otherwise forbid it. Both checklists get the matching item; the existing-repo one says to move such a file's content into `AGENTS.md` and delete it.

The Dockerfile finding at the end of the issue is tracked in #90.

Model: opus-5-5
2026-10-04 08:02:24 +02:00
clawbot 5805909fb9 Rewrite the -count=1 note to match the current files (closes #77)
check / check (push) Successful in 35s
The note under the canonical Go `make test` example in `prompts/REPO_POLICIES.md` named a cache-busting build argument that `--no-cache` replaced, and said Go's test result cache survived in earlier image layers. Neither is true of the current files.

The note now says where that cache can replay a pass: on a developer's machine, where the Makefile target runs, so both invocations there keep `-count=1`. The `test` phase of the `Dockerfile` has nothing to replay, since its base image holds no result for the repo's tests and no step before `go test` runs one, so it needs no `-count=1`. Go stores only passing results, so neither run can report a stored pass.

Model: opus-5-5
2026-10-04 07:31:48 +02:00
clawbot 3c1b435990 Fall back to dev when git describe prints nothing (closes #74)
check / check (push) Successful in 31s
The Makefile examples in `prompts/CODE_STYLEGUIDE_GO.md` and `prompts/GO_HTTP_SERVER_CONVENTIONS.md` now read `VERSION ?= $(or $(shell git describe --tags --always 2>/dev/null),dev)`.

When `git describe` prints nothing (outside a git checkout, or where git is missing or refuses the checkout) the old line stamped an empty version without a word; it now falls back to `dev`, the same way in every repo. The comment above each line says so.

In a Docker build stage with `.git` present, a real version needs git installed and the checkout trusted, as the canonical `Dockerfile` does; the `Dockerfile` already fails when the version comes out empty, `dev` or `unknown`.

Model: opus-5-5
2026-10-04 07:02:27 +02: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