# The build was not slow, it was waiting in line — and it took three wrong measurements to see it

> About twenty AI agents work in parallel in the same repository. They all write code, and they all want to see that what they wrote compiles. For months my complaint was a single sentence: builds are too slow.

Canonical: https://optionos.app/log/en/derleme-yavas-degildi/
Published: 2026-08-31

About twenty AI agents work in parallel in the same repository. They all write code, and they all want to see that what they wrote compiles. For months my complaint was a single sentence: builds are too slow.

Trying to fix that sentence, I dug in the wrong place three times. Each time I had a number, each time I trusted it, each time the next measurement overturned it.

## Three measurements, three wrong places

| # | What I looked at | What I found | Why it was wrong |
|---|---|---|---|
| 1 | Compile duration | median 3.3 s — fast | I measured how long the work took, not when it started |
| 2 | Queue duration | median 33.7 s | Queue records were segmented; I counted only part of them |
| 3 | The whole queue | 282 hours of waiting | This one held — after burning two rounds |

The gap between the first two said it on its own:

```
compile      ███ 3.3 s
job lifetime ████████████████████████████████ 33.7 s
             └──────────── waiting: 30.4 s ────────────┘
```

Compilation took 3.3 seconds but the job lived 33.7. I was paying a tenfold tax and it appeared in no record.

The third measurement then toppled the second. I thought total waiting was thirty-one hours; reading all the records it came out at two hundred and eighty-two.

```
what I thought   ███ 31 hours
actual           ████████████████████████████ 282 hours
```

My own measurement had been nine times too low.

## Almost half the builds taught nothing

Then I counted repeats. Same agent, same package, again within ten minutes.

| Measure | Value |
|---|---|
| Build calls in one day | 1,067 |
| Of those, repeats | 470 |
| Repeat rate | 44% |
| Time spent on repeats | 16.5 hours |
| Worst single case | one agent, one package, 67 of 76 calls were repeats |

```
first-time builds  ███████████████████ 597
repeats            ███████████████ 470
```

## The system was telling me the wrong thing

What I noticed between measurement rounds was more unsettling: the indicators I was reading were not true.

| What the system said | What was actually there |
|---|---|
| "47 builds running" | 2 — the other 45 were dead records, the oldest three days old |
| "Build succeeded" | The product folder was empty |
| "Build rights belong to one agent" | Anyone sending a message could start a build without knowing |

The last one was the sneakiest. Sending a message to an agent triggered a five-and-a-half-minute application build that nobody asked for; about forty messages moved through the fleet that day. I thought I had built a monopoly — that rule was protected by a sentence, not by a mechanism.

## What I tried, and what it cost

| What I tried | What happened |
|---|---|
| The compiler's content-addressed cache | Exists in the compiler, the package manager will not open it — route closed |
| A separate build area per agent | The same code compiled more than four times over; what I bought as isolation was duplication |
| Moving work to a remote machine | 8 cores (12 here), no cache, every job from zero — and it died silently |
| A sweeper for dead locks | On all 84 dead markers the lock could already be acquired — the lock was not the problem |
| Declaring the build monopoly as a rule | The fleet read the rule and still took the expensive path in one job out of five |
| A queue for agents to report work | 32 submissions after the last reply, 0 replies — it had no consumer |
| Patching a rule that was wrong | The right move was to delete it; I reverted the patch |

Two of these taught the most.

The remote machine was a tempting shortcut: push the load elsewhere. I measured it — the place I pushed to was weaker than here and every job started from scratch. Instead of taking load it added latency.

I was about to write the dead-lock sweeper. I measured before writing and saw the blockage had nothing to do with locks — the job at the head of the line was holding everything behind it. What I was about to build would have solved a problem that did not exist.

## What I am building now

Where I landed: agents will not carry work results to each other. Nobody tells anybody "I built it, here is the output".

```
OLD                           NEW
agent ──result──> agent       agent ──record──> system
                                                system ──notice──> agent
                                                (the notice carries an address, not the result)
```

Four decisions:

1. **Everyone writes to the system.** The requesting agent lands a record, and that record states what it expects — before any result exists.
2. **The notice carries an address, not a body.** Anything copied drifts a little at every stop it passes through.
3. **One ledger, append only.** Old records are never corrected; a new record changes the previous verdict going forward. The live view and the historical audit derive from the same ledger — I am not opening a second record for auditing, because two records always drift apart.
4. **Roles are separate from people.** "Who plans the work" and "who runs it" are positions; which agent stands there can change. If a position is empty the work does not stop, the requester does it.

One more separation: checking and delivering are not the same job.

| What I want | Where it goes |
|---|---|
| "Is this correct?" | To the cheapest sufficient answer — no full build needed |
| "Build me this" | Into the real build line |

They used to pass through the same door, and every check paid for a full build.

## The cost

Publishing a text page today, I paid exactly this tax once more. The page's publishing gate wanted a package I had never touched to be compiled. The build went to the remote machine, said "done", and left the product there; the gate looked for it here and did not find it. I waited twenty minutes, and during that time not a single compiler was running.

I fixed the gate: if the source has not changed, no build starts at all.

```
before  ████████████████████████████ 250 s
after   █ 12 s
```

But I only made that fix because I hit the problem — the gate had been there for months and nobody had measured it.

Building the system is not free either. Keeping a record per request, producing a receipt per result: an accounting layer that does no work. I only do this where more than one agent races for the same resource. For someone working alone it would be ceremony.

## How I will know this decision has rotted

If the time between request and result does not fall. The only thing that legitimises what I am building is that duration — not the number of records, not the elegance of the ledger, not the tidiness of the roles. If an agent gets its result later than it does today, the accounting layer has cost more than the work, and I will reopen the decision.

And this: I do not have that measurement yet. The code has not landed. What I wrote is a plan, not an achievement.

## This is not the conclusion

"Agents should not message each other, they should write to the system" is an easy sentence. Everyone nods at it.

The sentence was not what I learned. What I learned was that I measured the wrong thing three times in a row:

| Where I looked | Where it actually was |
|---|---|
| Slowness in compilation | In the queue |
| 31 hours in the queue | 282 hours in the queue |
| Blockage in the lock | At the head of the line |

A number carries you to the wrong place with exactly the same confidence. What I learned was to look not at the number but at what the number covers — and to accept from the start that my own measurement can rot.
