1 Commits
Author SHA1 Message Date
sneak 75c4011a2e Rewrite REPO_POLICIES.md sentence by sentence (closes #136)
check / check (push) Waiting to run
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
+30 -26
View File
@@ -56,14 +56,14 @@ with your task.
- the step that runs `script/bootstrap` to install a Python `test` phase's
packages from `Pipfile.lock`
- [ ] A stage with none of these steps declares `ARG CACHEBUST` right after
`FROM`. A step that installs anything else as well, such as a
`script/bootstrap` that also installs node packages, comes after it too.
The `script/` builds pass a new `CACHEBUST` value on every build, which
reruns every `RUN` step after that line and leaves the layers above it and
the cache mounts in place; `--no-cache` would build those layers again and
empty the mounts. A stage without the `ARG` line is served from cache on
an unchanged tree, so the scripts and the `ARG` lines are re-vendored in
one commit.
`FROM`. A step that also installs anything else comes after
`ARG CACHEBUST` too. A `script/bootstrap` that also installs node packages
is one. The `script/` builds pass a new `CACHEBUST` value on every build,
which reruns every `RUN` step after that line and leaves the layers above
it and the cache mounts in place; `--no-cache` would build those layers
again and empty the mounts. A stage without the `ARG` line is served from
cache on an unchanged tree, so the scripts and the `ARG` lines are
re-vendored in one commit.
- [ ] Go: each Go stage downloads the modules (`COPY go.mod go.sum ./`,
`RUN go mod download`) above `ARG CACHEBUST`; the steps that compile
(`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
it above `ARG CACHEBUST`, with `COPY script/ script/`,
`COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When
`script/bootstrap` runs in that step, it installs nothing beyond system
packages, pipenv and its dependencies, and the packages from
`Pipfile.lock`. It installs pipenv and its dependencies by hash, with
`pip install --require-hashes`. It installs the packages from
`Pipfile.lock` with `pipenv install --deploy`, plus `--dev` when the 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`
`script/bootstrap` runs in that step, it installs nothing beyond these:
- system packages
- pipenv and its dependencies
- the packages from `Pipfile.lock`
It installs pipenv and its dependencies by hash, with
`pip install --require-hashes`. It installs the packages from `Pipfile.lock`
with `pipenv install --deploy`, plus `--dev` when the 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`
- [ ] The gate phases invoke their tools directly, never through `make lint` or
`script/test` — those are themselves a `docker build` and would recurse
inside a build step
@@ -111,15 +115,15 @@ with your task.
- 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 name may have a `config` segment, as in `config`, `deploy/config`
or `config/lib`. Such a submodule 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, and an alpine one needs
`apk add --no-cache git`. That stage takes the version from the `VERSION`
build argument when one is given, otherwise from
`git describe --tags --always`. That gives:
password in a remote URL, or the token the CI checkout step stores there.
Some submodule names have a `config` segment, as in `config`,
`deploy/config` or `config/lib`. Such a submodule 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, and an alpine one needs `apk add --no-cache git`. That
stage takes the version from the `VERSION` build argument when one is given,
otherwise from `git describe --tags --always`. That gives:
- the tag, on a tagged commit
- the tag, the number of commits since it and the short 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
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
directory to `**/.git/modules/**/config`, and Go's version stamping then
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`
phase's packages from `Pipfile.lock`
- A stage with none of these steps declares `ARG CACHEBUST` right after
`FROM`. A step that installs anything else as well, such as a
`script/bootstrap` that also installs node packages, comes after it too.
The `script/` builds pass a new `CACHEBUST` value on every build, which
reruns every `RUN` step after that line and leaves the layers above it and
the cache mounts in place; `--no-cache` would build those layers again and
empty the mounts. A stage without the `ARG` line is served from cache on
an unchanged tree, so the scripts and every stage's `ARG CACHEBUST` line
are added in the same commit.
`FROM`. A step that also installs anything else comes after
`ARG CACHEBUST` too. A `script/bootstrap` that also installs node packages
is one. The `script/` builds pass a new `CACHEBUST` value on every build,
which reruns every `RUN` step after that line and leaves the layers above
it and the cache mounts in place; `--no-cache` would build those layers
again and empty the mounts. A stage without the `ARG` line is served from
cache on an unchanged tree, so the scripts and every stage's
`ARG CACHEBUST` line are added in the same commit.
- Go: each Go stage downloads the modules (`COPY go.mod go.sum ./`,
`RUN go mod download`) above `ARG CACHEBUST`; the steps that compile
(`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
it above `ARG CACHEBUST`, with `COPY script/ script/`,
`COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When
`script/bootstrap` runs in that step, it installs nothing beyond system
packages, pipenv and its dependencies, and the packages from
`Pipfile.lock`. It installs pipenv and its dependencies by hash, with
`pip install --require-hashes`. It installs the packages from
`Pipfile.lock` with `pipenv install --deploy`, plus `--dev` when the 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`
`script/bootstrap` runs in that step, it installs nothing beyond these:
- system packages
- pipenv and its dependencies
- the packages from `Pipfile.lock`
It installs pipenv and its dependencies by hash, with
`pip install --require-hashes`. It installs the packages from
`Pipfile.lock` with `pipenv install --deploy`, plus `--dev` when the
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
- Non-server: the final stage brings up the dev environment
- 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/`
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/cibuild`. These are the four, and there is no fifth:
`script/cibuild`. Four scripts do this, and there is no fifth:
- `script/lint`
- `script/test`
- `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
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
directory to `**/.git/modules/**/config`, and Go's version stamping then
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`
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.
- It then runs `pipenv install --deploy`, with `--dev` when the tests need
the development packages. `--deploy` does all of these:
- `script/bootstrap` then runs `pipenv install --deploy`, with `--dev` when
the tests need the development packages. `--deploy` does all of these:
- installs only what `Pipfile.lock` names
- checks every package against the lockfile's hashes
- 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
`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
hide an install, which then succeeds while no caller sees any change.
wrote to. A shadowing binary can hide an install, which then succeeds
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
function defined and never invoked has the same exit status and the same
empty output as one that worked.
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
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
only for public, unauthenticated read-only APIs.
- **Error handling:**
- Internal errors must never leak implementation details to the client,
such as:
- Internal errors must never leak implementation details to the client.
Those details include:
- stack traces
- SQL queries
- file paths