Tell the reader the lock does not protect them

The build lock protects a second WRITER. It does not protect a READER, and
nothing in the docs said so. Every build starts with `bun run clean`, which
rm -rf's public/doxa-maps, so anything reading the tree mid-build gets a
confident wrong answer: "that bundle is missing", "the dashboard tab does not
exist", "461 files were deleted". Each of those has actually happened here, and
one nearly produced a bug report against a correct change.

check:settled already existed and was already wired in package.json. It was
mentioned in zero markdown files, which is the whole gap: the primitive was
built and never reached the people who needed it. Documented now in the one
place an inheritor reads, with the instruction to grade it by exit code --
like every gate here it prints teaching prose after its verdict, so `| tail -1`
inverts the signal.

Also recorded why a pgrep check is NOT a substitute, because that is the form
the standing brief prescribes and it is the weaker instrument. A process list
samples an instant; the lock knows the queue. Between one queued build finishing
and the next acquiring the lock there is a real window where zero build
processes exist and the tree is about to be wiped -- and a long quiet period
makes that window look more convincing, not less, since the queue is idle
precisely because it is between runs. Measured today: pgrep reported 0 builders
while the gate reported builders=1 waiters=1, and ps confirmed a build had
started 17 seconds earlier.

Verified by execution: check:settled exits 1 with builders=1 waiters=1
churn(45s)=456 while a build runs; check:doc-scripts passes, so every command
quoted here exists in package.json.
This commit is contained in:
doxa-maps-88655c70 2026-09-23 14:46:11 +00:00
parent 1a782109c3
commit b25db86985

View file

@ -225,6 +225,35 @@ bun run serve # serve the BUILT tree at http://localhost:4173
`bun run build` takes a **lock**: if another build is already running it fails fast rather than
corrupting the shared output. Set `BUILD_LOCK_WAIT=600` to queue behind it instead.
### Before you MEASURE the built tree — `bun run check:settled`
```bash
bun run check:settled # exit 0 = safe to measure/publish; exit 1 = do not
```
**The lock protects a second WRITER. It does not protect a READER.** Every build begins with
`bun run clean`, which `rm -rf`s `public/doxa-maps/`, so while a build runs the tree is transiently
near-empty — and anything reading it then gets a confident, wrong answer: "that bundle is missing",
"the dashboard tab does not exist", "461 files were deleted". Those are not hypotheticals; each has
happened here, and one nearly produced a bug report against a correct change.
So run this gate before any browser check, any publish, and any claim about what the tree contains.
It reports `builders`, `waiters`, `churn(45s)`, `dirs`, `leaves` and `quietFor`, and **grade it by
exit code** — like every gate here, it prints teaching prose after its verdict, so `| tail -1` will
mislead you.
★ **Do not substitute a `pgrep` check for this.** A process list samples an INSTANT; the lock knows
the QUEUE. Between one queued build finishing and the next acquiring the lock there is a real window
where zero build processes exist and the tree is nonetheless about to be wiped — and a long quiet
period makes that window look *more* convincing, not less, because the queue is idle precisely
because it is between runs. Measured 2026-09-23: `pgrep` reported 0 builders while the gate reported
`builders=1 waiters=1`, and `ps` confirmed a build had started 17 seconds earlier.
If you are one of several agents working this repo at once, the stronger rule is simply: **do not run
`bun run build` at all.** Edit source, and let one owner run the single authoritative build. To
sanity-check one bundle without touching anyone else's output, use
`BUNDLE=<name> bun x vite build` — it does not clean the whole tree.
---
## Repository layout