Someone on your team pastes a stack trace into an assistant, gets a plausible diff back, and hits "apply." Twenty minutes later the preview environment is broken and nobody can say which automated run changed what. When I trace incidents like this, the weak point is almost never the model's reasoning. It is the seam where a text suggestion quietly inherits shell, network, and write permissions it never had to justify.

I recently reworked one of these flows into a conveyor of small, separately-permissioned stages. The principle: an assistant starts with observation rights only, and every escalation toward mutation passes through a machine-checkable gate. Inexpensive model capacity is great for the high-volume early stages — drafting summaries, proposing commands — but the gate itself must hold even when the model is down, hallucinating, or swapped for another vendor.

Start from a real breakage, not a prompt

My motivating incident was a dependency bump, not a migration. An assistant with a generic "run commands" tool tried to upgrade a package, hit a peer-dependency conflict, retried with --force, and left the lockfile in a state that passed local tests but failed the deploy build with a 422 from the registry webhook. Three separate automated runs had touched the lockfile and none of them recorded which actor asked for which command.