1 Commits
Author SHA1 Message Date
sneak 75c4011a2e Rewrite REPO_POLICIES.md sentence by sentence (closes #136)
check / check (push) Successful in 33s
Every sentence of prompts/REPO_POLICIES.md is rewritten against the
sentence rules: one idea per sentence, about 30 words at most, lists as
bulleted lists, subject and verb early, the main rule before any
exception. No rule's meaning changed: nothing is added, removed,
loosened or tightened, every reason stays, and code blocks, digests,
URLs, file names, commands and quoted strings are unchanged. Both repo
checklists carry the same rewrite of the sentences they quote word for
word.

Model: fable-5-1
2026-11-04 01:55:14 +00:00
3 changed files with 62 additions and 53 deletions

No files matched your search

+30 -26
View File
@@ -56,14 +56,14 @@ with your task.
- the step that runs `script/bootstrap` to install a Python `test` phase's - the step that runs `script/bootstrap` to install a Python `test` phase's
packages from `Pipfile.lock` packages from `Pipfile.lock`
- [ ] A stage with none of these steps declares `ARG CACHEBUST` right after - [ ] A stage with none of these steps declares `ARG CACHEBUST` right after
`FROM`. A step that installs anything else as well, such as a `FROM`. A step that also installs anything else comes after
`script/bootstrap` that also installs node packages, comes after it too. `ARG CACHEBUST` too. A `script/bootstrap` that also installs node packages
The `script/` builds pass a new `CACHEBUST` value on every build, which is one. The `script/` builds pass a new `CACHEBUST` value on every build,
reruns every `RUN` step after that line and leaves the layers above it and which reruns every `RUN` step after that line and leaves the layers above
the cache mounts in place; `--no-cache` would build those layers again and it and the cache mounts in place; `--no-cache` would build those layers
empty the mounts. A stage without the `ARG` line is served from cache on again and empty the mounts. A stage without the `ARG` line is served from
an unchanged tree, so the scripts and the `ARG` lines are re-vendored in cache on an unchanged tree, so the scripts and the `ARG` lines are
one commit. re-vendored in one commit.
- [ ] Go: each Go stage downloads the modules (`COPY go.mod go.sum ./`, - [ ] Go: each Go stage downloads the modules (`COPY go.mod go.sum ./`,
`RUN go mod download`) above `ARG CACHEBUST`; the steps that compile `RUN go mod download`) above `ARG CACHEBUST`; the steps that compile
(`golangci-lint run`, `go test`, `go build`) mount Go's build cache (`golangci-lint run`, `go test`, `go build`) mount Go's build cache
@@ -76,15 +76,19 @@ with your task.
- [ ] Python: a `test` phase that installs its packages from `Pipfile.lock` does - [ ] Python: a `test` phase that installs its packages from `Pipfile.lock` does
it above `ARG CACHEBUST`, with `COPY script/ script/`, it above `ARG CACHEBUST`, with `COPY script/ script/`,
`COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When `COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When
`script/bootstrap` runs in that step, it installs nothing beyond system `script/bootstrap` runs in that step, it installs nothing beyond these:
packages, pipenv and its dependencies, and the packages from - system packages
`Pipfile.lock`. It installs pipenv and its dependencies by hash, with - pipenv and its dependencies
`pip install --require-hashes`. It installs the packages from - the packages from `Pipfile.lock`
`Pipfile.lock` with `pipenv install --deploy`, plus `--dev` when the tests
need the development packages. It installs no Python there, because the It installs pipenv and its dependencies by hash, with
tests use the base image's. The tests run after `ARG CACHEBUST`, and every `pip install --require-hashes`. It installs the packages from `Pipfile.lock`
other stage installs its Python packages after it, as in the Python `test` with `pipenv install --deploy`, plus `--dev` when the tests need the
phase example in `REPO_POLICIES.md` development packages. It installs no Python there, because the tests use the
base image's. The tests run after `ARG CACHEBUST`, and every other stage
installs its Python packages after it, as in the Python `test` phase example
in `REPO_POLICIES.md`
- [ ] The gate phases invoke their tools directly, never through `make lint` or - [ ] The gate phases invoke their tools directly, never through `make lint` or
`script/test` — those are themselves a `docker build` and would recurse `script/test` — those are themselves a `docker build` and would recurse
inside a build step inside a build step
@@ -111,15 +115,15 @@ with your task.
- that of a submodule keeping its own `.git` directory - that of a submodule keeping its own `.git` directory
`git describe` does not need them, and each can hold a credential: a `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 password in a remote URL, or the token the CI checkout step stores there.
submodule name may have a `config` segment, as in `config`, `deploy/config` Some submodule names have a `config` segment, as in `config`,
or `config/lib`. Such a submodule loses its whole git directory to `deploy/config` or `config/lib`. Such a submodule loses its whole git
`**/.git/modules/**/config`, and Go's version stamping then fails the build. directory to `**/.git/modules/**/config`, and Go's version stamping then
Give it a name without that segment (`git submodule add --name`). The stage fails the build. Give it a name without that segment
that compiles has `git`: the Debian Go image has it, and an alpine one needs (`git submodule add --name`). The stage that compiles has `git`: the Debian
`apk add --no-cache git`. That stage takes the version from the `VERSION` Go image has it, and an alpine one needs `apk add --no-cache git`. That
build argument when one is given, otherwise from stage takes the version from the `VERSION` build argument when one is given,
`git describe --tags --always`. That gives: otherwise from `git describe --tags --always`. That gives:
- the tag, on a tagged commit - the tag, on a tagged commit
- the tag, the number of commits since it and the short commit - the tag, the number of commits since it and the short commit
(`v1.2.3-4-gabc1234`), on a later commit (`v1.2.3-4-gabc1234`), on a later commit
+22 -18
View File
@@ -82,7 +82,7 @@ Template files can be fetched from:
`git describe` does not need them, and each can hold a credential: a `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 password in a remote URL, or the token the CI checkout step stores
there. A submodule name may have a `config` segment, as in `config`, there. Some submodule names have a `config` segment, as in `config`,
`deploy/config` or `config/lib`. Such a submodule loses its whole git `deploy/config` or `config/lib`. Such a submodule loses its whole git
directory to `**/.git/modules/**/config`, and Go's version stamping then directory to `**/.git/modules/**/config`, and Go's version stamping then
fails the build. Give it a name without that segment fails the build. Give it a name without that segment
@@ -123,14 +123,14 @@ Template files can be fetched from:
- the step that runs `script/bootstrap` to install a Python `test` - the step that runs `script/bootstrap` to install a Python `test`
phase's packages from `Pipfile.lock` phase's packages from `Pipfile.lock`
- A stage with none of these steps declares `ARG CACHEBUST` right after - A stage with none of these steps declares `ARG CACHEBUST` right after
`FROM`. A step that installs anything else as well, such as a `FROM`. A step that also installs anything else comes after
`script/bootstrap` that also installs node packages, comes after it too. `ARG CACHEBUST` too. A `script/bootstrap` that also installs node packages
The `script/` builds pass a new `CACHEBUST` value on every build, which is one. The `script/` builds pass a new `CACHEBUST` value on every build,
reruns every `RUN` step after that line and leaves the layers above it and which reruns every `RUN` step after that line and leaves the layers above
the cache mounts in place; `--no-cache` would build those layers again and it and the cache mounts in place; `--no-cache` would build those layers
empty the mounts. A stage without the `ARG` line is served from cache on again and empty the mounts. A stage without the `ARG` line is served from
an unchanged tree, so the scripts and every stage's `ARG CACHEBUST` line cache on an unchanged tree, so the scripts and every stage's
are added in the same commit. `ARG CACHEBUST` line are added in the same commit.
- Go: each Go stage downloads the modules (`COPY go.mod go.sum ./`, - Go: each Go stage downloads the modules (`COPY go.mod go.sum ./`,
`RUN go mod download`) above `ARG CACHEBUST`; the steps that compile `RUN go mod download`) above `ARG CACHEBUST`; the steps that compile
(`golangci-lint run`, `go test`, `go build`) mount Go's build cache (`golangci-lint run`, `go test`, `go build`) mount Go's build cache
@@ -143,15 +143,19 @@ Template files can be fetched from:
- Python: a `test` phase that installs its packages from `Pipfile.lock` does - Python: a `test` phase that installs its packages from `Pipfile.lock` does
it above `ARG CACHEBUST`, with `COPY script/ script/`, it above `ARG CACHEBUST`, with `COPY script/ script/`,
`COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When `COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When
`script/bootstrap` runs in that step, it installs nothing beyond system `script/bootstrap` runs in that step, it installs nothing beyond these:
packages, pipenv and its dependencies, and the packages from - system packages
`Pipfile.lock`. It installs pipenv and its dependencies by hash, with - pipenv and its dependencies
`pip install --require-hashes`. It installs the packages from - the packages from `Pipfile.lock`
`Pipfile.lock` with `pipenv install --deploy`, plus `--dev` when the tests
need the development packages. It installs no Python there, because the It installs pipenv and its dependencies by hash, with
tests use the base image's. The tests run after `ARG CACHEBUST`, and every `pip install --require-hashes`. It installs the packages from
other stage installs its Python packages after it, as in the Python `test` `Pipfile.lock` with `pipenv install --deploy`, plus `--dev` when the
phase example in `REPO_POLICIES.md` tests need the development packages. It installs no Python there,
because the tests use the base image's. The tests run after
`ARG CACHEBUST`, and every other stage installs its Python packages
after it, as in the Python `test` phase example in `REPO_POLICIES.md`
- Server: the final stage builds and runs the application - Server: the final stage builds and runs the application
- Non-server: the final stage brings up the dev environment - Non-server: the final stage brings up the dev environment
- Image pinned by sha256 hash with version/date comment - Image pinned by sha256 hash with version/date comment
+10 -9
View File
@@ -235,7 +235,7 @@ style conventions are in separate documents:
executes, and the build still exits 0. Every `docker build` in `script/` executes, and the build still exits 0. Every `docker build` in `script/`
therefore passes `--build-arg CACHEBUST="$(date +%s)-$$"`, the time and the therefore passes `--build-arg CACHEBUST="$(date +%s)-$$"`, the time and the
script's process id. So no two builds share a value, not even the three in one script's process id. So no two builds share a value, not even the three in one
`script/cibuild`. These are the four, and there is no fifth: `script/cibuild`. Four scripts do this, and there is no fifth:
- `script/lint` - `script/lint`
- `script/test` - `script/test`
- `script/cibuild` - `script/cibuild`
@@ -440,7 +440,7 @@ style conventions are in separate documents:
`git describe` does not need them, and each can hold a credential: a `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 password in a remote URL, or the token the CI checkout step stores
there. A submodule name may have a `config` segment, as in `config`, there. Some submodule names have a `config` segment, as in `config`,
`deploy/config` or `config/lib`. Such a submodule loses its whole git `deploy/config` or `config/lib`. Such a submodule loses its whole git
directory to `**/.git/modules/**/config`, and Go's version stamping then directory to `**/.git/modules/**/config`, and Go's version stamping then
fails the build. Give it a name without that segment fails the build. Give it a name without that segment
@@ -499,8 +499,8 @@ style conventions are in separate documents:
dependencies by hash. It does so with `pip install --require-hashes -r` dependencies by hash. It does so with `pip install --require-hashes -r`
and a requirements file in `script/` that lists each of them with `==` and and a requirements file in `script/` that lists each of them with `==` and
its `--hash`. pip refuses to install a dependency the file does not list. its `--hash`. pip refuses to install a dependency the file does not list.
- It then runs `pipenv install --deploy`, with `--dev` when the tests need - `script/bootstrap` then runs `pipenv install --deploy`, with `--dev` when
the development packages. `--deploy` does all of these: the tests need the development packages. `--deploy` does all of these:
- installs only what `Pipfile.lock` names - installs only what `Pipfile.lock` names
- checks every package against the lockfile's hashes - checks every package against the lockfile's hashes
- fails when the lockfile is out of date with `Pipfile` - fails when the lockfile is out of date with `Pipfile`
@@ -850,14 +850,15 @@ style conventions are in separate documents:
- after installing, re-resolves the binary the way callers do, with - after installing, re-resolves the binary the way callers do, with
`hash -r` and then through `PATH`, not through the directory the installer `hash -r` and then through `PATH`, not through the directory the installer
wrote to. It fails and names the resolved path. A shadowing binary can wrote to. A shadowing binary can hide an install, which then succeeds
hide an install, which then succeeds while no caller sees any change. while no caller sees any change. In that case it fails and names the
resolved path.
- is actually called, and prints the version on both success paths. A - is actually called, and prints the version on both success paths. A
function defined and never invoked has the same exit status and the same function defined and never invoked has the same exit status and the same
empty output as one that worked. empty output as one that worked.
Node is the exception to the whole-token comparison. The canonical Node is the exception to the whole-token comparison. The canonical
`script/bootstrap` compares only node's major version, because the `script/bootstrap` compares only node's major version. That is because the
`Dockerfile` stages start from a node 22 alpine image, which is not the `Dockerfile` stages start from a node 22 alpine image, which is not the
exact pin, and nvm cannot install a prebuilt node on alpine. exact pin, and nvm cannot install a prebuilt node on alpine.
@@ -927,8 +928,8 @@ style conventions are in separate documents:
an explicit allowlist of known origins. Wildcard (`*`) is acceptable an explicit allowlist of known origins. Wildcard (`*`) is acceptable
only for public, unauthenticated read-only APIs. only for public, unauthenticated read-only APIs.
- **Error handling:** - **Error handling:**
- Internal errors must never leak implementation details to the client, - Internal errors must never leak implementation details to the client.
such as: Those details include:
- stack traces - stack traces
- SQL queries - SQL queries
- file paths - file paths