A profile's settings.json gains a `forbid` list, and ForbiddenCommandGate
refuses anything on it. Tagged Discipline, so it reaches dispatched workers: a
rule about what may be RUN is true whoever holds the shell, and a worker knows
less about what a command costs here than the session that dispatched it.
It refuses rather than warns, at PreToolUse. A block that arrives after the
shell has run is not a block — proven twice tonight, since a REJECTED tool call
had already reverted a tree and the next measurements were taken against the
wrong ground.
Why a setting rather than a brief: a lane spawned later never reads a warning
sent earlier. Advice is something a fresh agent may not have; a refusal at the
door is a property of the checkout. Same argument as Parked::DISPATCH refusing
rather than letting a binding read as configured and do nothing.
It matches what a command RUNS, not what it mentions. The first version refused
the echo that quoted the command it was testing for, so the command is now split
at the points a shell would start a new one and each segment tested at its head.
A backtick is deliberately NOT such a point, though the shell treats it as one:
backticks are how prose quotes a command, and counting them refused this gate's
own commit message for naming what it forbids. A rule that cannot be written
about is one nobody can explain.
The shipped list starts with the ones that have a body count. Stash is first:
refs/stash is a single common ref shared by every worktree, so one lane's pop
takes another lane's work into the wrong tree and what a person sees is their
edit mysteriously reverting.