diff --git a/README.md b/README.md index 0d1d7d9..a4147ab 100644 --- a/README.md +++ b/README.md @@ -108,11 +108,14 @@ alpine. We provide: ### Linting -Linting runs in a container, one way, everywhere. `script/lint` builds -`Dockerfile.lint`, which copies the repo into a digest-pinned node image and -runs eslint and prettier as build steps, so a successful build is a clean lint. -There is no host lint path: docker is required to lint, and that also works -where the docker daemon is remote and bind mounts are impossible. +Linting runs in a container, one way, in every path that produces a lint verdict +for `make check` or the pre-commit hook. `script/lint` builds `Dockerfile.lint`, +which copies the repo into a digest-pinned node image and runs eslint and +prettier as build steps, so a successful build is a clean lint. No lint path +reachable from `script/check` or `script/precommit` runs on the host: every lint +verdict those two produce comes from the container. Docker is therefore required +to lint, and the container route also works where the docker daemon is remote +and bind mounts are impossible. The formatting check is part of that, not a step beside it. `script/check` and `script/precommit` therefore call `script/lint` and stop; neither calls @@ -124,15 +127,17 @@ in each. `test/packaging/lint-once.test.ts` asserts that count by walking the invocation graph, so a second pass cannot creep back in unnoticed. `script/fmt-check` remains as a standalone entrypoint for asking the formatting -question on its own, without docker and without the rest of lint. Its verdict -cannot drift from the container's: prettier is pinned to an exact version, -installed from `yarn.lock` under `--frozen-lockfile` in both places, and reads -`.gitignore` as its default ignore file — which is why `.dockerignore` -deliberately keeps `.gitignore` in the build context. +question on its own, without docker and without the rest of lint. It is the one +formatting path that still runs on the host, and nothing reaches it: neither +`script/check` nor `script/precommit` calls it, so it never contributes to their +verdicts. Its own verdict cannot drift from the container's: prettier is pinned +to an exact version, installed from `yarn.lock` under `--frozen-lockfile` in +both places, and reads `.gitignore` as its default ignore file — which is why +`.dockerignore` deliberately keeps `.gitignore` in the build context. -Lint happens in exactly one place, which constrains the rest of the build. -`script/check` calls `script/lint`, so `make check` cannot run inside a -container without asking for docker inside docker. The image built from +Lint happens in exactly one place in that graph, which constrains the rest of +the build. `script/check` calls `script/lint`, so `make check` cannot run inside +a container without asking for docker inside docker. The image built from `Dockerfile` therefore runs `make test` and `make build` and does not lint; `script/cibuild` builds `Dockerfile.lint` first and that image second, so CI gets both verdicts. @@ -526,8 +531,8 @@ documents: runs the tests) must pass before merging to `main`. `make fmt-check` is available for a host-side formatting check on its own, but it is not a separate requirement: `make lint` already covers it, and running both would - check formatting twice. Never invoke eslint or prettier directly; linting runs - in the container only. + check formatting twice. Never invoke eslint or prettier directly; every lint + verdict `make check` and the pre-commit hook produce comes from the container. - **Formatting:** prettier with 4-space indents and `proseWrap: always` for markdown. Use `make fmt` to format. Use `yarn` not `npm`.