orchestrator.dispatch() had one job: send a task to the dispatch engine, and record whether it actually ran. The original implementation keyed that decision on the engine’s exit code alone. For as long as “exit 0” and “the engine did real work” meant the same thing, that was a perfectly reasonable shortcut. It stopped being reasonable the moment those two facts came apart, and they came apart in a lab this project doesn’t own.

The refactor that wasn’t about this project at all

engine-gateway-lab, a sibling lab, refactored its own confirm gate so that a manual-handoff case (human review required, a paste artifact written, nothing actually executed) returned a status field describing that outcome instead of exiting nonzero. From that lab’s point of view this was a clean improvement: richer information, still a well-formed JSON contract. From Control Tower’s point of view, nothing in its own code had changed, and everything about what its own dispatch guard could rely on had changed. pending-response (no work done, a placeholder written) now came back exit 0, and exit 0 was the only thing dispatch() was checking. Any future skipped or declined outcome would have had the identical problem.

The trigger was noticing, not testing

No test in this project failed. Nothing here broke. What caught it was a habit: treating a refactor in a neighboring lab as a reason to critically re-review this project’s own assumptions about that lab’s contract, rather than waiting for a local test to fail first. Days before VeilGremlin’s first real dispatch, that review found the gap and closed it the same session it was raised.

The fix: an allowlist, not a blocklist

The fix inverted the check. Instead of asking “did the exit code say failure” (a blocklist: anything not explicitly bad is trusted), the guard now asks “does the JSON explicitly say this is one of the outcomes that means real work happened.” Only status in {in-progress, done} combined with skipped: false is recordable as a dispatch. Anything else (the new pending-response, an explicit skipped: true, a missing status field, or any value the guard doesn’t recognize) is refused before any state-changing event is appended. The task stays ready. Nothing about DAG state gets corrupted by a phantom success; the worst outcome of the bug becomes “this task didn’t get marked dispatched when it should have,” which is loud, recoverable, and re-dispatchable, instead of silent and wrong.

What next

The guard closed one specific hole in one specific seam. The next post in this arc is about a different kind of contract entirely, not what a dispatcher trusts about its runner’s exit status, but what a whole tool’s own public interface promises the rest of the estate it will and won’t do.

What Next

The Lego-Block Contract

What it takes for a tool to be fully useful standalone and a well-behaved factory component at the same time, through exactly two named seams.