Factory diary

Chapter 05 Β·

The most expensive token is the one of an AI waiting

The most expensive run delivered nothing: an AI polling a status that never changed. Waiting is a job for code.

⏱️ 8 min read

In the previous chapter, The bottleneck isn't the code, it's the tests, the factory's first full night hid a strange number: 1h20 of testing was an agent waiting for a command to finish. With testing solved, a bigger question was left. Why was an AI waiting in the first place?

The answer was in a run from days before, the most expensive of the whole project. It delivered nothing.

This chapter is about that run, about the rule I took from it that same night and about a way of waiting I didn't know existed.

4:37 pm: the first task the factory picked up on its own

It was the Tuesday from chapter 2, The day AI took the wheel from me. At 3:46 pm, I had opened a session just to write down the backlog. At 4:37 pm, the tool took the first task from it and started working on it on its own: a screen to follow, live, what each run was doing.

Before going on, the legend for the rest of the chapter, the same one from chapter 4:

The start was the usual. The agent developed for about 20 minutes, another one reviewed, a third one wrote the tests. The build got stuck a few times, because a forgotten copy of the app was holding a file open, but it passed. The check passed. At 5:11 pm, the task reached the last two stages, the ones that take care of the code after it leaves the factory:

That's where the run stopped moving and kept spending.

The same question nine times

The agent following the request needed a GitHub command-line tool to read its state. That tool was off the list of what it could run without my permission.

So it asked. The answer was the same: it needs approval. It waited and asked again, and again. At some point, it wrote down on its own that it had already asked for access once, that the request had been ignored and that it would not ask again. And it kept checking.

There were nine checks, all with the same answer. The workflow told it to check the request every minute, for up to 12 hours. If I hadn't cancelled it, that would have been 12 hours of an AI asking whether a locked door had opened by itself.

The agent before it, the one sending the code, had already gone through something similar. It burned about 15 refused attempts until it found the way of calling the same tool that the list allowed. And the one waiting for continuous integration was also that agent, checking, turn after turn.

At 5:39 pm I cancelled it. In the log, the run has a single outcome: cancelled.

The most expensive run, from 4:37 pm to 5:39 pm: the develop, review, test, build and check stages fill the first half; the second half is almost all waiting, with the agent that sends the code waiting for continuous integration and the agent that follows the request checking a blocked status nine times

The cost of waiting

When I went to look at what it cost, the numbers told the same story as chapter 4, only louder:

The rereading is the detail that matters. In chapter 4, I said the model rereads the whole context on every turn. A check that only asks "is it done yet?" looks cheap. For an AI, each of those questions is a read of the whole task, with everything it has done up to that point. The longer the task, the more expensive the same question gets.

A person waiting for a build finishes waiting and that's it. An AI waiting pays to remember what it was doing, every time it looks at the clock.

The rule, that same night

The cancellation was at 5:39 pm. The fixes came the same day, from the factory itself.

At 6:04 pm, the first one. A wait that gets the same "blocked" answer three times in a row stops waiting and raises a flag. The maximum follow-up time dropped from 12 to 4 hours, and the check went to every 2 minutes. And when an agent has several refused calls in a row, that shows up as an alert, instead of turning into expensive silence.

At 8:17 pm, the second one, which is the one that changed the design. The one waiting for continuous integration was no longer the AI. The engine started checking GitHub on its own, on its own clock, and calling the agent only when there is a result. The agent that sends the code also moved to a cheaper model, because what was left for it to do asked for less.

In the first run after that, at 8:33 pm, the engine checked continuous integration four times. The agent was called once.

The rule ended up like this:

It's the same split chapter 4 made with testing: the engine runs, the agent judges. The difference is that, here, I only noticed after paying the highest bill of the project.

"Cancel the monitor"

That same week, on the night I told in chapter 3, I went to sleep and woke up to the work done, my last message before going to sleep was this:

"Cancel the monitor, I'm going to sleep and leaving the PC running."

The monitor was Claude following the runs for me. Every so often, it looked at whether something had finished or broken. It was exactly the agent of the nine checks, only on my side of the desk. I cancelled it because it made no sense to pay an AI to watch another AI work while I slept.

But I still wanted someone watching. And that's when I found out the problem already had a ready-made solution, inside Claude Code itself.

The Monitor that doesn't spend tokens

Claude Code has a feature called Monitor, which I didn't know about. The name is the same as the one I had cancelled, but the way it watches is the opposite. When I asked it to follow the runs, Claude itself explained to me how it works:

It's the 8:17 pm rule, only outside the factory. The one keeping an eye on things is code, with no AI.

I started using this mode a lot at night, to follow the project's runs. I left the Monitor running, went to sleep, and Claude only woke up when there was something to look at.

Two ways of waiting for the same run for an hour. On top, the AI checking: each check is a turn, and each turn rereads the whole context, adding up to millions of tokens. Below, Claude Code's Monitor: a script checks every minute with no AI, the session stays idle, and the AI wakes up a single time, when the result changes

What I take from this

The AI doesn't know it is spending while it waits. For it, checking one more time is just one more reasonable step. The one who has to know is the design of the workflow.

Today, when I build a new stage, I ask one question before any other: is there any waiting in here? If there is, it goes to the engine. The AI keeps the before and the after of the wait, never the wait itself.

And the rule that doesn't change still stands. The engine waits, gives up and calls, but it doesn't approve anything in my place. The blocked request that afternoon was waiting for a permission from me, and the right thing was to keep waiting for me. The wrong thing was paying an AI to keep asking.

The next step

Waiting was only half the problem that Tuesday. Later that same day, five runs ran in parallel, and four of them failed when merging code. There was no contradiction at all between them. They had only added a line at the end of the same file.

In the next chapter, chapter 6, Git was made for humans, I tell the story of that night and why, with several AIs working at the same time, even the format of a file becomes an architecture decision.

Next chapterGit was made for humansTwo agents conflict just by adding a line at the end of the same list. With AIs in parallel, file layout becomes architecture. ← All chapters

Newsletter

Get the next chapters.

One email when a new chapter is out. No spam, unsubscribe anytime.