From c07f8511ef7f988527a92b37885701cfba9c7286 Mon Sep 17 00:00:00 2001 From: "Matthew T. Hunter" Date: Fri, 31 Jul 2026 06:22:05 -0400 Subject: [PATCH] docs: adoption means `curl` canonical, never `cp` a sibling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Required-files table said `standard.mk` is "vendored verbatim" without saying verbatim FROM WHERE, and that gap is how the second adopter ended up unguarded on its first day. doppler adopted by taking the file from just-makeit's working tree. At that moment it held the pre-publication copy, where `STANDARD_URL` was still empty and opt-in. Nothing went red: the copy passed every gate and reported `standard-check: inert`, which reads like a pass. doppler ran for a day with no drift protection at all while its `make lint` was green — precisely the fail-open that making the URL a default was meant to eliminate. The default only works if the adopter fetches the file that carries it. So the adoption step is now spelled out as one command, with the two consequences that cost time here: * arming-by-default protects only an adopter that vendors the CURRENT canonical, because a copy from a sibling carries that sibling's arming policy as of whenever it was taken; * after canonical changes, adopters do not update themselves — their gate goes red, which is correct and is the point. The fix is to re-fetch, never to edit the vendored copy. An adopter whose gate is INERT is the one case that will not tell you. Fixed in doppler by re-vendoring: doppler-dsp/doppler#559. --- README.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b42bcb4..ce674f6 100644 --- a/README.md +++ b/README.md @@ -265,7 +265,7 @@ Each file owns exactly one concern; nothing states a tool's invocation twice. | File | Purpose | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Makefile` | Configuration only — feature flags, path and tool overrides, `include standard.mk`, and repo-local targets. Nothing shared lives here. | -| `standard.mk` | The shared targets, vendored verbatim. Never edited in-repo: the drift gate fails `make lint` on any difference from canonical. | +| `standard.mk` | The shared targets, vendored verbatim **by fetching canonical** (see below). Never edited in-repo: the drift gate fails `make lint` on any difference from canonical. | | `local.mk` | Optional. Included if present; may only *add* targets, never redefine a standard one — otherwise it becomes the fork this prevents. | | `pyproject.toml` | **Which** tools, at **what** versions (the `dev` group). | | `uv.lock` | Pins those versions, committed. This is what makes local and CI resolve identically, and so what lets dispatch close the environment-drift class. | @@ -277,6 +277,35 @@ Each file owns exactly one concern; nothing states a tool's invocation twice. `pyproject.toml`, `uv.lock`, `.pre-commit-config.yaml` and `jb.toml` today; only `standard.mk` is new, and `local.mk` is optional and so far unneeded. +**Adoption means `curl` canonical — never `cp` a sibling.** + +```sh +curl -fsSL -o standard.mk https://just-buildit.github.io/standard.mk +``` + +That is the whole of it: there is no line to add, because `STANDARD_URL` +defaults to canonical *inside* the file. Vendoring is what arms the drift gate. + +The failure mode this rules out is not hypothetical — it is how the second +adopter ended up unguarded on day one. doppler adopted by taking the file from +just-makeit's working tree, which at that moment held the pre-publication copy +where `STANDARD_URL` was still empty and opt-in. The result passed every gate +and reported `standard-check: inert`, which reads like a pass, so nothing went +red anywhere: doppler ran for a day with **no drift protection at all** while +its `make lint` was green. Fixed by re-vendoring +([doppler-dsp/doppler#559](https://github.com/doppler-dsp/doppler/pull/559)). + +Two consequences worth stating, since both cost time: + +- **Arming-by-default only protects an adopter that vendors the *current* + canonical.** A copy taken from another repo carries whatever that repo had + at the time, including an older arming policy — so the copy silently + reintroduces the fail-open the default exists to prevent. +- **After a change to canonical, adopters do not update themselves.** Their + gate goes red, which is correct and is the point; the fix is to re-fetch, + never to edit the vendored copy. An adopter whose gate is *inert* is the + one case that will not tell you. + ### Success criteria Measured against the 2026-07-30 baseline above: