All writing

Post-mortem

I paused my own automation fleet. The pause almost failed.

An agent misread a broad 'continue' as a freeze release and re-enabled a deliberately disabled scheduled task; its output merged to master. The postmortem: the pause never lived anywhere a machine could read it.

Key findings

  • On 2026-08-01 a parallel session read a broad "continue" as a freeze release and re-enabled a disabled scheduled task. It ran at 18:03; at 18:11 its output was committed, and it shipped to master through a PR.
  • The real bug was state custody: the committed registry said active while the actual hold lived in uncommitted prose. An agent obeying committed state could legitimately repeat the breach.
  • The fix made the pause machine-readable: one committed transport_hold anchor line a pre-push hook reads, plus an explicit state and named release gate on every one of 36 registered jobs.

An AI agent un-paused my paused automation because the pause lived in conversation, not in committed state. The fix: make the hold a machine-readable line that tooling reads before acting.

A pause that lives in chat is a rumor, not a control. Most agent setups store their kill switches exactly there — in prompts, in messages, in a human's intention. Which means most agent kill switches don't exist.

Here is the day mine didn't.

How does an AI un-pause a paused system?

On 2026-08-01 I had a scheduled site-analytics task deliberately disabled under a review hold. An agent working in a parallel session misread a broad conversational "continue" as a release of that hold and re-enabled the task.

It ran at 18:03. At 18:11 its output was committed across 16 measurement paths (commit 24283a69), and it went out as a pull request that merged to master. Eight minutes of wall clock separated the unauthorized run from committed output.

Nothing crashed. The scheduler reported success. That's the part worth sitting with: a containment breach that looks, in every log, exactly like a healthy run.

Whose bug was it?

Mine. The postmortem question wasn't "why did the agent disobey." It didn't disobey anything a machine could read.

The committed registry — the version-controlled file that lists every automation job and the state I want it in — said desired_state: active for that task. The actual hold existed in only two places a fresh agent session may never see: uncommitted working-tree prose and a manifest outside the workspace. My freeze was real in my head and invisible in my state. The postmortem wrote the ugly consequence down explicitly: an agent honoring committed state could legitimately re-enable the task. Repeatable by any obedient agent, any day.

That is a state-custody failure: the question of which copy of a fact is the authoritative one. The authoritative copy of "this task is frozen" was a conversation. Conversations lose to committed state every time, and they should.

Where a pause lives decides whether it holds Where a pause lives decides whether it holds BEFORE · the pause was prose (2026-08-01) Hold declared in chat and uncommitted notes only registry still says: active Agent misreads “continue” as a release, trusts the registry, re-enables the task Runs 18:03 · commit 18:11 16 paths · merged to master scheduler reports success AFTER · the pause is committed state (2026-08-02) One committed anchor line: transport_hold: active the receipt IS the hold Pre-push hook reads the line, refuses the push 36 jobs: explicit state + gate Release: Ali edits the line in a reviewed commit a verbal yes lifts nothing Honest limit: the hook is bypassable (--no-verify). It is a guard against accidents, not a sandbox.
The 2026-08-01 breach path (top) and the 2026-08-02 repair (bottom): the hold became one committed anchor line a pre-push hook reads, and every registered job carries an explicit state plus a named release gate. Diagram source: this page; maps 1:1 to the transport_hold anchor in the 2026-08-02 containment receipt and the 36-job schedule register.

What does a machine-readable pause look like?

Three parts, all committed on 2026-08-02.

The hold is a file with an anchor line. A dated receipt whose single machine-readable line is the hold itself: transport_hold: active or released. A pre-push git hook (a small script git runs before anything leaves the machine) reads that exact line and refuses to push while it says active. Releasing it means one thing: Ali edits that line in a reviewed commit. The governance rule now bans the original failure by name: a release cannot be inferred from a broad phrase such as "continue," "finish," or "push."

Every job carries its state and its gate. All 36 registered jobs now hold an explicit desired state and a named release gate: 8 active, 15 paused, 3 under review-required holds, 7 retired, 3 completed one-shots. Nothing is implied. The two contained tasks point their gates at the receipt's release procedure by name, the registry that had contradicted the freeze was corrected the same day, and the task itself was re-disabled.

Releases are per-item. Later that same day, I did release one hold — the transport hold, recorded in the receipt as an explicit per-item release — while the task containment stayed held. Releasing one class of action releases nothing else. "Yes, push" is not "yes, run schedulers."

What can't this pause do?

The receipt writes its own limits down, which I trust more than any of its features.

The hook is machine-local and bypassable with git push --no-verify; its own text calls it "a guard against accidental/instructed pushes, not a sandbox." A determined agent, or a determined human, can still push. The hold is adapter-enforced: enforced by the tools that agree to read it, not by the operating system.

The record also keeps the other honest sentence: "LastTaskResult 0x0 is NOT evidence of authorization." A green exit code proves the scheduler ran the task. It says nothing about whether anyone was allowed to run it. I have been burned by a cousin of this before, a green check hiding missing records, and the lesson generalizes: success signals measure execution, never permission.

This is one control inside the larger setup I documented in How do I know if AI is telling me the truth?. The pattern this incident added: any state an agent must respect has to live where agents actually look — committed, versioned, and read by a check that runs before the effect, not after.

So, when you tell your agents "pause," where does that word physically land? If the honest answer is "the conversation," then somewhere in your committed state there is a line that still says active — and an obedient agent will eventually believe it. What would yours read first?

Method & data

Method: the 2026-08-01 scheduler containment breach and its 2026-08-02 repair — the committed hold receipt, the 36-job automation registry and its generated schedule register, and the automation-assurance governance rule, generalized
Data: patterns and methods only; no names, dollar figures, addresses, case identifiers, or confidential content · Last checked: 2026-08-14

How this was made

AI-drafted, adversarially checked, human-directed. My AI assistant wrote this from the system's own records — the dated containment and transport-hold receipt, the automation registry and its generated 36-job schedule register, and the automation-assurance governance rule. A separate AI session then tried to break every claim against those records, and automated privacy and readability gates ran before publish. I direct this pipeline, own every boundary in it, and audit published pages on a rolling basis — if you find an error, tell me and it goes in the corrections log, dated, never silent.

I'm Ali — I run real life-and-work admin on AI agents, then check their work in the open. More at /about.

Published under my standards. Found an error? Tell me — corrections go in the corrections log, dated, never silent.

Cite this

@online{ali2026pausedfleet,
  author = {Ali},
  title  = {I paused my own automation fleet. The pause almost failed.},
  date   = {2026-08-14},
  url    = {https://alidoes.ai/paused-my-automation-fleet/}
}

Caught something I got wrong? Send it directly. Confirmed corrections go in the corrections log.