Building Anton · Chapter 11 of 14

Anton, chapter 11: The gate

June 26, 2026 · 4 min read

The model was fast now, but every fix still ended with me.

A change could be written, reviewed, merged, and tested automatically. Then it sat in the repository until I opened a terminal, connected to the home server, pulled the code, rebuilt the containers, and watched the health checks.

The intelligence had accelerated.

Delivery had not.

The question for this period was whether the loop could close completely: issue, fix, review, merge, deploy, running on the family's phones.

No person in the middle.

But speed was not the interesting part. The challenge was closing the loop without allowing an automated mistake to reach the five people who depended on Anton.

A pipeline that deploys quickly and deploys the wrong thing is worse than deploying by hand.

The path to production

The foundation was conventional.

Nothing could merge until type checking, the build, and the complete test suite passed. Afterward, a deployment job joined the private Tailscale network and invoked the update process on the home server.

Production did not expose SSH to the public internet. The runner entered the tailnet like any other authorised machine.

On the server, the existing deployment script remained in control: pull the new version, build it, start it, probe its health, and restore the previous image if the probe failed.

I already trusted that path.

The automation did not replace it. It called it.

That distinction mattered. Closing the loop did not require inventing a second deployment mechanism.

It required making the proven one reachable.

A gate that was confidently wrong

The post-deployment smoke gate was where I got educated.

The idea was simple: ask the live system a small number of representative questions. Keep the new deployment only when it answers correctly.

The first version called an endpoint that did not exist. Every deployment returned a 404, rolled back, and paged me with a critical alert.

Loudly wrong is irritating, but useful. It gets attention.

The second version reached the right endpoint and still rolled everything back. One test expected a conversation-search request to route to the knowledge domain. Anton correctly routed it to memory.

The system was right.

The gate was wrong.

The gate won anyway.

That is the authority of an automated check: it does not need to understand more than the system it judges. It only needs permission to stop it.

The gate that never ran

The third failure was worse.

Six model calls took longer than the deployment timeout, so the smoke check was silently skipped.

The pipeline stayed green.

For several deployments, the gate appeared to be protecting production while never producing a verdict at all.

A false failure is noisy. Someone investigates it.

A silently skipped check reports confidence it never earned.

That is one of the most dangerous failure modes in automation because the output looks exactly like success.

The gate had to fit inside its own operational budget.

I ran the cases concurrently, reduced the blocking set, and separated checks into two tiers.

The hard tier could roll back a deployment. It contained only fast, essential family-facing paths.

The soft tier tested broader behaviour and reported regressions without blocking the release.

A check should have authority proportional to both its importance and its reliability.

The day it paid for itself

A few days later, the hard gate rejected a deployment that had genuinely broken two family-facing paths.

The old version returned automatically.

I had not noticed the regression.

The mechanism I built because I did not trust myself caught it before the family did.

That was the moment the work paid for itself.

Not when the pipeline deployed something successfully, but when it refused to.

Keeping the builders alive

The agents that picked up issues and reviewed pull requests were long-lived sessions.

After enough work, their context filled up. They became slower, less precise, and occasionally strange.

A watchdog learned to identify stalled sessions, terminate them, and start fresh ones.

A supervisor watched the issue queue. When there was no work, it put the fleet to sleep. When an issue became ready, it woke the necessary workers.

That small piece of stagecraft made the difference between an automation that survived an afternoon and one that could operate for weeks.

Persistent automation needs a lifecycle, not only a loop.

The quiet result

Where it landed was quieter than I expected.

I file an issue and describe the change.

Later, the fix is either running on the family's phones or it never left the repository.

In both cases, I did not touch the server.

The loop closes on itself.

What I notice is not the speed.

The part I trust most is the one whose only purpose is to stop everything else.

References