Make bun run build refuse by default instead of asking politely
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
"Agents never run the full build" is already a top-level heading in AGENT-BRIEF.md, and the research that established it was three hours old. It was violated anyway -- by a dispatch prompt that said `bun run build` while telling the agent to read the brief first. The clean step then wiped public/doxa-maps mid-probe and an unrelated bundle read back as "did not mount", one step from a fictional defect in a file that was fine. Documentation cannot fix that; an explicit instruction beats a standing rule at the point of work. So the build refuses with exit 75 and prints the cheaper paths (bun run tree, BUNDLE= vite build, settled-tree-gate) unless BUILD_ALLOW=1 is set. Opt-in rather than caller-detection, deliberately: the first draft keyed on two environment variables that do not exist in a spawned process -- a guard that could never fire. A probe then reported a third variable as the discriminator; it is set in the parent too, so it marks any session rather than a child. No environment variable distinguishes them. Negative-tested both directions: no flag exits 75 with the refusal, BUILD_ALLOW=1 reaches "build lock acquired".
This commit is contained in:
parent
0b58ab4560
commit
eb95d02597
2 changed files with 55 additions and 0 deletions
|
|
@ -45,6 +45,14 @@ Only push to `main` what you have actually verified — it is the branch a human
|
|||
`bun run build` takes minutes, and its first step deletes `public/doxa-maps/` — which wipes the
|
||||
output every other agent is using. **Use the dev server; it hot-reloads.**
|
||||
|
||||
**This is now ENFORCED, not just asked.** `bun run build` refuses with exit 75 unless you set
|
||||
`BUILD_ALLOW=1`. If you hit that refusal it is telling you the truth — take one of the cheaper
|
||||
paths it prints rather than reaching for the flag. Only the coordinator, running the single
|
||||
authoritative build for a wave, should set it. This rule was documented here *before* it was
|
||||
enforced and got violated anyway, by a dispatch prompt that said `bun run build` while telling the
|
||||
agent to read this file first. An explicit instruction beats a standing rule at the point of work,
|
||||
so the build now refuses instead of asking.
|
||||
|
||||
```sh
|
||||
bun x vite --port <YOUR OWN PORT> --strictPort # e.g. 5299, 5399, 5499 …
|
||||
BUNDLE=<name> bun x vite build # one bundle's compiled output; does NOT clean
|
||||
|
|
|
|||
|
|
@ -19,6 +19,53 @@ LOCK_FILE="${BUILD_LOCK_FILE:-public/.build.lock}"
|
|||
WAIT="${BUILD_LOCK_WAIT:-0}"
|
||||
mkdir -p "$(dirname "$LOCK_FILE")"
|
||||
|
||||
# ── THE COORDINATOR-ONLY GUARD ───────────────────────────────────────────────────────────────
|
||||
# ★ WHY A GUARD AND NOT A DOCUMENTED RULE (measured 2026-09-23, the third instance of one shape)
|
||||
# "Agents never run `bun run build`" is ALREADY a top-level heading in AGENT-BRIEF.md, and the
|
||||
# research doc that established it is three hours old. It was violated anyway — by the
|
||||
# coordinator, who put `bun run build` into a dispatch prompt while telling the same agent to
|
||||
# read the brief first. The agent obeyed the prompt, the build's clean step wiped public/ mid-
|
||||
# probe, and an unrelated bundle read back as "did not mount." That near-diagnosis was a
|
||||
# fictional defect in a file that was fine.
|
||||
#
|
||||
# So the failure mode is NOT that the rule is missing, buried, or unclear. It is that an
|
||||
# explicit instruction beats a standing rule at the point of work, every time. Documentation
|
||||
# cannot fix that; only something that REFUSES the action can. The lock below already makes
|
||||
# concurrent builds impossible — but it does not make an UNNECESSARY build impossible, and N
|
||||
# queued agents still cost N full rebuilds, each one cleaning the tree out from under every
|
||||
# concurrent reader.
|
||||
#
|
||||
# This guard is deliberately a SPEED BUMP, not a wall: it fails with the cheaper alternative
|
||||
# printed, and any caller can proceed by setting BUILD_ALLOW=1. That is the point — the person
|
||||
# who genuinely needs a full build spends one line saying so, while the agent who inherited
|
||||
# `bun run build` from a careless prompt gets told what to run instead.
|
||||
#
|
||||
# ★ WHY OPT-IN AND NOT SUBAGENT-DETECTION (a gate that could not fail, caught before shipping)
|
||||
# The first version of this guard fired on `CLAUDE_AGENT_ID` / `CLAUDE_SUBAGENT`. MEASURED: both
|
||||
# are UNSET in a real subagent — I invented them — so the guard would have passed silently 100%
|
||||
# of the time while looking like protection. A probe agent then reported CLAUDE_CODE_CHILD_SESSION
|
||||
# as the discriminator; that is ALSO wrong, and instructively so — it is set to 1 in the
|
||||
# subagent AND in the coordinator, so it marks "a Claude process", not "a child". The agent could
|
||||
# not have known: it only saw its own side. A discriminator is only validated by comparing BOTH
|
||||
# environments, which is why this is now opt-in rather than detection. There is no env var here
|
||||
# that distinguishes coordinator from subagent; anything claiming to is an untested guess.
|
||||
if [ "${BUILD_ALLOW:-}" != "1" ]; then
|
||||
echo "🚫 FULL BUILD REFUSED — a full build is almost never what you want here, and its FIRST" >&2
|
||||
echo " step deletes public/doxa-maps/ entirely, which tears" >&2
|
||||
echo " the tree out from under every other agent reading it (measured 3+ times, incl. a" >&2
|
||||
echo " 461-file phantom deletion and several false 'element did not mount' diagnoses)." >&2
|
||||
echo "" >&2
|
||||
echo " USE INSTEAD, cheapest first:" >&2
|
||||
echo " bun run tree # regenerates manifest.json + leaf pages, NO clean" >&2
|
||||
echo " BUNDLE=<name> bun x vite build # rebuilds ONE bundle, leaves the others alone" >&2
|
||||
echo " node internal/settled-tree-gate.mjs # just READ the tree someone else built" >&2
|
||||
echo "" >&2
|
||||
echo " If you ARE the coordinator and genuinely want the one authoritative full build," >&2
|
||||
echo " re-run it as: BUILD_ALLOW=1 bun run build" >&2
|
||||
echo " If you are a SUBAGENT, do not set BUILD_ALLOW — ask the coordinator to build instead." >&2
|
||||
exit 75 # EX_TEMPFAIL, same code as a held lock — 'not now', not 'broken'
|
||||
fi
|
||||
|
||||
# fd 9 = the lock handle
|
||||
exec 9>"$LOCK_FILE"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue