An AI agent will tell you the code is done, the tests are green, the change is safe. Sometimes it's right. Sometimes it's confidently wrong — and that's the whole problem.
The rails are how you let an agent move fast anyway: it can propose anything, but a gate — not the agent — decides what actually ships.
Every idea below is paired with the real thing — examples come from a fictional but fully worked engagement, Harbor Mutual, a regional insurer.
Why the rails exist at all
Speed is only safe if something catches the mistakes
An agent can produce a working change in minutes. That's a gift right up until the moment it's wrong — and a probabilistic actor is sometimes wrong. Without something standing between "the agent says done" and "it's live," speed just means breaking things faster.
The rails are a set of automatic checks every change must pass before it can take effect. They're called rails because nobody has to remember them — every change runs on them, every time, whether a human or an agent wrote it.
Build them once, early, and from then on the agent can move as fast as it likes. The rails are what make that speed trustworthy instead of terrifying.
Harbor's pod built the rails before a single feature existed — five automatic checks, a locked main branch, and a dev environment defined in code. Then everything they built afterward rode through them.
"Five workflows, branch protection on main, a blocking Stop hook, a Bicep dev environment. Proven on the walking skeleton. Everything since has ridden them."
The rails were built once and never stopped running — under every change, from the first one to go-live.
You're trusting the agent's word that each change is safe. The first time it's confidently wrong about something that touches real customer data, you find out in production.
Go deeper — the full method
The rails are not a phase. They get built in Phase 3 (the factory), they run under every change all through Build, the same artifact gets promoted to production in Phase 8, and they get watched in Phase 9. The pipeline is a standing standard: the workflows, the merge bar, the deploy-and-promote path, the infrastructure pipeline, the agents that work inside the pipeline — and the one principle that governs all of it.
That principle is the whole reason agent-built software can be trusted to ship at all: the agent proposes, a gate disposes. An agent investigates, plans, and produces a change as a reviewable artifact — a branch and a pull request, an infrastructure plan, a fix suggestion — but a deterministic policy layer plus a named human decides whether that change ever takes effect. This is not our invention. It is what every mature agentic-DevOps system in the industry converged on, independently, by 2026: none of them lets an agent merge to a protected branch or apply destructive infrastructure unsupervised. The rails are where that rule stops being a good intention and becomes a fact about the world.
Five workflows, plus the branch protection that makes them mandatory. ci
— build/test/lint/coverage — hard block. grader
— a fresh agent's check-by-check verdict against the spec, pinned to the exact
changed lines — required to run; advises, never blocks.
correctness — a fresh agent hunts the changed lines for plain logic
defects — blocks on a high-confidence defect. security
— the security-reviewer agent, on a risk:high label or any guarded path
— blocks on HIGH. deploy-dev — ships the merged
artifact to dev and rolls back on a failed deploy. All five ride one rule: the agent
proposes, a gate disposes.
The rule that governs everything
The agent proposes; a gate disposes
This single sentence is the spine of the whole pipeline. The agent does the investigating, the planning, the producing — but it stops at a reviewable thing: a proposed change someone (or something) else gets to judge. The agent never has the last word on anything that's already protected.
This isn't a house rule. Every serious agent-and-DevOps system in the industry landed on the exact same shape, independently — because it's the only rule that holds when the agent is wrong.
- The agent may produce any change — a code branch, an infrastructure plan, a fix for a broken pipeline.
- A gate — an automatic check plus, where it matters, a named human — decides whether that change ever takes effect.
Machines decide the mechanical questions — does it build, do the tests pass. Humans own the judgment — is this the right change, is the risk acceptable.
Three different companies solving three different problems, one rule underneath all of them:
"Can only push to branches it creates, cannot approve or merge its own work, and its checks won't even run without explicit human approval."
"Diagnoses a broken pipeline and stops at a merge request with the fix. It does not push to the protected branch; it proposes."
"Detects configuration drift and proposes a remediation plan. Applying it is a human choice, never a silent auto-apply."
Go deeper — the full method
Strip away the vendor names and every working agentic-DevOps system in 2025–2026 is the same shape. The agent does the investigating, planning, and producing. It stops at a reviewable artifact. A deterministic policy layer plus a human decides whether the artifact takes effect. The agent never has the last word on a protected resource. We did not adopt it because the industry did; we arrived at it for the same reason they did — it is the only rule that holds when the agent is wrong, and a probabilistic actor is sometimes wrong. This is the same sentence that runs through the whole standard — gates report, humans decide — mechanically enforced rather than merely intended.
Three corollaries fall out of the principle. Each one is a design rule for the rails, not a nicety:
- Mechanical self-validation is mandatory. Before an agent surfaces a change as done, it must re-run the build, the tests, the linters from the environment itself and prove them green — not assert success, prove it. This is exactly what the Stop hook is: the agent cannot end its turn on a red test or a broken build. An agent's claim that something works is an opinion; the environment's green is ground truth.
- A bounded tool surface beats raw access. An agent given named, constrained tools (read a file, write a file, run the tests, run the linter) outperforms — and is far safer than — an agent handed the whole filesystem and a shell with "fix it." The constraint is what makes the agent's behavior legible and its blast radius small.
- Autonomy is graded, and it widens slowly. A new piece of agent automation starts in a propose-and-approve posture and only graduates to a tighter loop after its behavior has been watched and trusted on real work. The risk of agentic systems is almost never the model being dumb; it is granting too much autonomy too quickly.
Underneath all three: identity is the real guardrail. What an agent can do is bounded by the permissions of the credential it runs under, not by the words in its prompt. When a prompt fails — and prompts fail — the identity is what is still holding.
Why "done" can't be the agent's opinion
The agent has to prove it works — not just say so
"It works on my machine" is bad enough from a person. From an agent that will cheerfully report success it didn't earn, it's a trap. So the rails refuse to take the agent's word for anything they can check themselves.
Before an agent is allowed to call a change done, it has to re-run the build, the tests, and the checks from the environment itself and show them green. Not assert success — prove it.
There's a small script that enforces this: when the agent tries to finish its turn, the script fires and looks at the actual state. Broken build or a red test? It refuses to let the agent stop. "Done" stops being the agent's opinion and becomes a fact the environment confirmed.
Every change Harbor's agents built had to clear this before a human ever saw it. On spec 0016 — the change that merges duplicate claims — the agent built it, the script held it to a green suite, and:
Eleven green tests — and, as the next module shows, that still wasn't enough on its own. Green is necessary; it's just not sufficient.
Every other gate assumes the basics already pass. The self-check is what makes "the tests are green" mean something — the agent couldn't have stopped otherwise.
Go deeper — the full method
Mechanical self-validation is the first corollary of agent proposes, gate disposes. Before an agent surfaces a change as done, it re-runs the build, the tests, and the linters from the environment itself and proves them green. This is the Stop hook: a script that fires when an agent tries to finish its turn. If tests fail or the build is broken, it refuses to let the agent stop. "Done" stops being the agent's opinion.
The same discipline applies to agents working inside the pipeline. A self-healing CI agent does not get to claim the pipeline is fixed — it re-runs the tests and the lint from the environment and proves green before it surfaces a fix. A proposed fix the agent has not validated against the environment is not a fix; it is a guess wearing a green checkmark.
The Stop hook is also the first rail proven by deliberate failure: before Foundation closes, a failing test is planted to confirm the hook actually blocks an agent from finishing. A rail that has only ever seen green has not been tested; it has been assumed.
What actually stands at the gate
Five checks — and knowing which ones can say "no"
The rails are five automatic checks that run on every proposed change. The thing that matters most about them is which ones block (a hard stop, the machine's call) and which only advise (an input to a human's call). Confusing the two is how teams either ship unreviewed agent code or drown every typo in ceremony.
- The build-and-test check — does it compile, do the tests pass, is enough of the new code covered? Blocks. A red one is a closed door.
- The grader — a fresh agent reads the spec and the change and posts a verdict. Required to run, but only advises.
- The correctness check — a fresh agent, separate from the grader, hunts the changed lines for plain logic bugs: the off-by-one a green test suite never exercises. Blocks on a high-confidence defect; a named human can override on the record.
- The security check — a reviewer agent runs on high-risk changes and anything touching a dangerous file. Blocks on high risk.
- The deploy — once merged, ships the change to dev and rolls back if the deploy fails.
On spec 0016, the build-and-test check went green — all eleven tests. Then the grader, a fresh agent that did not write the code, walked the spec's checks one by one and caught the hole the eleven tests never thought to test:
"Two claims with an empty policy number were landing in the same match bucket and merging into one. Real bug, real data, invisible to a green suite."
The grader advised — its verdict was a comment. Sara, who didn't write the change, read it, agreed, and bounced it back to be fixed.
A confident, polished AI verdict is exactly how an agent talks a human into approving harm. So the grader surfaces the truth and hands it to a person who owns the call. The machine informs; it never decides.
Go deeper — the full method
The rails are five workflows in the repo, plus the branch protection that makes them mandatory. Each one is clear about whether it blocks (a hard gate, a machine's call) or advises (an input to a human's call).
| Workflow | Fires on | Blocks or advises | What it does |
|---|---|---|---|
ci | every PR | Blocks (hard gate) | Build, tests, lint, 80% coverage on new code. The mechanical floor — a red CI is a closed door. |
grader | every PR | Advises (required to run, can't block) | A fresh AI agent reads the spec in the diff and posts a check-by-check verdict as a PR comment, each check pinned to an exact changed line. "The grader ran" is required; what it said is the human Checker's input. |
correctness | every PR that changes source | Blocks on a high-confidence defect | A fresh AI agent — separate from the grader — hunts the changed lines for plain logic defects: the bug class ci can't see (it compiles, the tests pass) and security doesn't look for (it's not exploitable, just wrong). Passes trivially when no source changed; a named human can override on the record. |
security | the risk:high label or any PR touching a registered gated path | Blocks on HIGH; advises otherwise | Runs the security-reviewer agent. Path-triggered: fires on any PR touching a guarded path (auth, migrations, the pipeline, infra), independent of the spec's tier. |
deploy-dev | merge to main | n/a (it ships) | Deploys the merged artifact to the client's dev environment, and restores the last good version when a deploy fails. |
deploy-promote | manual only — never a trigger | n/a (it ships) | Promotes that same artifact onward to test and production. Holds until a named approver signs, and refuses a target environment that has no approver configured. Restores the last good version when a promotion fails. |
The grader advises; it never blocks. It is tempting to let a confident AI verdict gate the merge. We do not, and the reason is in the threat model: a polished, plausible explanation is exactly how an agent talks a human into approving harm. The grader's job is to surface the check-by-check truth — including the hole the author was blind to — and hand it to a person who owns the decision.
An agent gate may block on a defect, never on a judgment. Security blocks on a HIGH vulnerability and correctness blocks on a high-confidence logic defect; the grader does not. The line is not how much we trust the agent — it is what is being decided. "There is an off-by-one on this line" is a concrete, checkable defect an agent can hold the door on; "is this the right change for the spec" is a judgment a polished verdict should never settle alone. Both blocking agent gates carry a named-human override on the record, so a false positive informs without trapping a good change behind a machine's mistake.
The reviewers are scaffolded, so their verdicts are reproducible. An AI reviewer told to "inspect the diff" invents line numbers, wanders outside the change, and skims a large one. The grader and the correctness gate are instead handed a deterministic, machine-generated list of exactly which lines changed as their scope — so every finding pins to a real changed line and none is skipped. Same diff in, same anchors out.
The correctness gate runs on the server because the local check can't bind a human. A pre-push check on the agent's own machine refuses to let it push until its self-review is recorded — but that binds only the agent; a human pushing from their terminal sails past it. So the review runs again on every PR: the local check is fast-feedback courtesy, the server gate is the universal backstop that does not care who pushed or how.
The security gate is path-triggered, not just tier-triggered.
A change can be tiered MEDIUM and still touch the auth code, the migration folder, or the
pipeline YAML. Registering a guarded path with the security workflow makes it run on
any PR touching that path, in addition to firing on the risk:high
label. The gate is the workflow plus the path registration.
The one moment that matters
The merge bar — what every change must clear to land
Five checks are just suggestions until something makes them mandatory at the moment a change merges into the main branch. That's the merge bar: settings on the repository that turn the rails from a good habit into a law.
- The checks are green — build, tests, coverage all passing.
- The grader has run — it can say anything, but it must have run and posted.
- The correctness check passed — no high-confidence defect, or a named human recorded the override.
- Someone who didn't write it approved it — the author is never their own only approver. This rule survives even a two-person pod.
A high-risk change adds two more: the security check passed, and a named human recorded a sentence accepting the risk — not a thumbs-up, a name attached to a decision.
Spec 0016 was tiered HIGH — merging claim records is hard to undo, and a wrong merge mangles two policyholders' data. So it had to clear the full bar:
recorded a named sign-off in the change, accepting the HIGH risk, before a non-author merged it
The agent could push only to its own branch, could not merge its own work, and every commit it made was co-authored — so the history always shows who, or what, wrote each line.
A true-emergency merge past a gate needs the Pod Lead plus one other human, an exception label, and a retro item. Two of those in a month isn't bad luck — it means the gate or the specs are wrong. Fix that; don't normalize the bypass.
Go deeper — the full method
Branch protection is what turns five workflows from suggestions into rails. It is repository configuration — set by the Setup Owner or a named client admin — and it makes the gates mandatory at the one moment that matters: the merge.
Every PR, to merge, must clear:
- CI green — build, tests, lint, coverage all passing. Hard block.
- The grader has run — the workflow completed and posted. The verdict can say anything; the running is required.
- Correctness review passed — no high-confidence defect on the changed lines, or a named human recorded the override. The override is a label, audited in the PR timeline; the guarantee that the person clearing it is not the author comes from the non-author approval below, not the label — a gate should never claim an enforcement it cannot check.
- A non-author approval — someone who did not write the change approved it. The author is never their own only approver; this survives even a two-person pod.
A risk:high change adds two more:
- The security workflow passed — the security-reviewer agent's pass, blocking on HIGH.
- A named human sign-off recorded in the PR — a person, by name, accepting the risk. A recorded sentence, not a thumbs-up.
Constraints on the agent, enforced by the platform, not by trust: it pushes
only to branches it creates (spec/NNNN-*), never to main; it
cannot approve or merge its own work; every commit it makes is
co-authored, so provenance is in the history.
The one escape hatch is deliberately expensive: a true-emergency merge past a gate requires the Pod Lead plus one other human, an exception label, and a Retro+ agenda item. Two exceptions in a month means the gate or the specs are wrong — fix that, don't normalize the bypass.
From merged to in production
A merge isn't a deploy — promotion is
Landing on the main branch doesn't put a change in front of customers. The rails move it up through environments — dev, then test, then production — and the gap between "merged" and "in production" is where the most protected stop in the whole standard lives.
- Merge → dev, automatically. The merge already cleared the bar, and dev is the safe place to exercise the rails constantly.
- Dev → test, on demand. Promoted deliberately, smoke-tested on arrival.
- Test → production, by ceremony. Evidence on the table, every named role asked, a human saying go out loud, on the record. No amount of agent confidence ever removes this stop.
Two rules govern every promotion: promote the proven artifact, never rebuild it (a rebuild is something no environment ever verified), and a rollback that's never run is a wish — rehearse it before you need it.
At go-live, the pod rehearsed the rollback in test first — deploy, roll back, redeploy — and it failed:
"The previous artifact came back, but a config key had moved ahead of it, so the rolled-back app booted against config it didn't understand."
"The fix rode the loop as spec 0046 — config versioned with the artifact. Re-rehearsed Wednesday: clean. The same artifact that passed test, rc-1.0.1, was promoted to production, not rebuilt."
Go deeper — the full method
A merge is not a deploy to production. The rails move a change up through environments, and the gap between "merged" and "in production" is where the most important word lives: promotion.
- Merge → dev, automatically. The
deploy-devworkflow ships every merged change to dev with no human in the loop — the merge already cleared the bar, and dev is the safe place for the rails to be exercised constantly. - Dev → test, on demand. Promoted deliberately, smoke-tested on arrival. The test environment is added at the first hardening pass, not in Phase 3.
- Test → prod, by ceremony. The first promotion is the Phase 8 go/no-go: evidence on the table, every named role asked, a human saying go out loud, on the record. Every promotion after rides the client's release cadence — and a human go/no-go every time. The single most protected stop in the standard.
Promote the artifact; never rebuild it. The same build that passed test goes to production — promoted, not freshly compiled "real quick." A rebuilt artifact is something no environment ever verified, running in the one environment where that matters.
A rollback that has never run is a wish. The deploy pipeline restores the last good version on a failed deploy — and that path is rehearsed in test (deploy → roll back → redeploy) with the trigger condition written down in advance, not invented mid-incident. A rail that has never failed safely has not been proven.
The change with no clean undo
Infrastructure is HIGH risk every time — so it's read-only until the last step
The cloud environment itself is defined in version-controlled files instead of clicked together by hand. An agent can draft a change to it in seconds — but a wrong one is hard to undo and runs in production later. So the whole pipeline between draft and changed cloud is deliberately read-only.
The agent's draft goes through a funnel where every step before the last one just looks, changing nothing:
- Does it even compile? A malformed change is caught by a machine, not by a half-finished apply.
- Does it break the rules? An automatic policy check blocks public storage, unencrypted disks, untagged resources — on every change, not on a reviewer remembering.
- What exactly would it do? A dry-run previews every create, change, and delete — and a human reads it before approving.
Only then does a scoped apply run. A change approved without reading its preview is a change approved blind.
Adding the test environment was an infrastructure change — so it went down the funnel. The compile check passed. The policy check did not:
"PSRule flagged two things — a storage account that would have defaulted to public network access, and a resource group missing the required cost-center tag."
The agent fixed both, the gate went green, Tom read the dry-run to confirm nothing unexpected, and only then did the apply run — under an identity scoped to that one resource group and nothing else.
An agent running a destructive infrastructure apply unattended — deleting or replacing, with no human reading the dry-run first. Every read-only step exists for exactly this. Never auto-apply a destructive change.
Go deeper — the full method
Infrastructure is code, it lives in the repo, and it is HIGH risk every time — because it is hard to undo and it runs in production later. The agent-safe IaC pipeline is a read-only-until-the-last-step funnel:
| Step | What runs | Blocks? |
|---|---|---|
| Schema validate | bicep build against the resource schema | Hard block on a malformed template |
| Policy-as-code | PSRule for Azure (public access, encryption, tags, region) | Hard block on a policy violation |
| Dry-run | bicep what-if — the exact change preview | Posted to the PR; a human reads it |
| Cost / budget review | The price of the diff on the PR | Can block on a budget breach |
| Approval | A named human approves the what-if and the policy result | Required to proceed |
| Apply | Scoped, least-privilege deploy identity | — (the only step that changes cloud) |
| Drift assessment | Scheduled real-infra-vs-code compare | Opens a remediation PR; never auto-applies |
Every step before the apply is read-only — the agent and the pipeline can
do all the thinking, validating, and previewing they want, and nothing changes until a human
has read the dry-run and a least-privilege identity executes a scoped apply. The default
profile is .NET/Azure (Bicep); the pattern is stack-independent. A destructive
apply an agent runs unattended is the one mistake on this page with no clean
undo.
What holds when the prompt fails
Identity is the real guardrail — not the instructions
An agent's instructions can be talked into something they shouldn't do — prompts fail. What an agent can actually do isn't bounded by the words in its prompt; it's bounded by the permissions of the credential it runs under. That's the wall still standing when everything else gives way.
- Every actor gets its own narrow credential — scoped to exactly what its job needs and nothing more. An over-scoped identity means a subverted prompt can reach everything that identity could.
- Secrets live in the client's vault, never in the repo — not in code, not in a config file, not in a spec. A key in a commit is the one unrecoverable mistake.
- There's a kill switch — a whole class of agent identity can be disabled in one move if something goes wrong.
When a red pipeline got a self-healing agent pointed at it, the agent ran under its own scoped credential — able to read the repo and open a proposed change, nothing more:
If its prompt had been steered somewhere bad, the identity was the wall still standing.
And before go-live, every secret the pod had ever touched was rotated into production-only values the pod couldn't read. The engagement reached production with the pod having never known a production secret.
Go deeper — the full method
Every actor that touches the rails — human or agent — runs under its own credential, scoped to exactly what its job needs. This is the guardrail still standing when a prompt has been talked into something it shouldn't do. No role grant, no resource access — and an agent's instructions cannot grant it a role.
- Each agent that acts on infra or the pipeline gets its own least-privilege identity — a managed or federated credential (no stored secret, rotated automatically) scoped to the resource or resource group, never the whole subscription. Every action is then attributable to it in the audit log.
- Secrets live in the client's vault, never in the repo — not in code, not in CLAUDE.md, not in a spec. A key in a commit is the one unrecoverable foundation mistake: a rotation event and an audit-log review, not an edit.
- Secrets rotate before production — into production-only values the pod cannot read, signed by the client's security. The engagement should end with the pod having never known a production secret.
- There is a kill switch — conditional-access policy at the class level can disable a whole category of agent identity in one operation.
Treat an agent as a first-class non-human identity with its own lifecycle, owner, and time-bounded access — not a script running under a human's credentials. Every agent identity has a named owner or it does not exist.
Now watch one change ride the rails
A single change, from proposed to deployed
You've got the ideas; here's the actual journey one change takes — spec 0016 at Harbor, the duplicate-claim merge. Notice that the agent's work stops early, at a proposed change, and a gate (and a human) carry it the rest of the way. Step through it.
The agent stops at a proposed change
The agent built the change on its own branch — it can't touch main — and the Stop hook held it to a green suite first: eleven tests passing before it was allowed to finish. Then it opens the change for review and stops. From here, gates and humans take over.
Does it build, test, and cover?
The build-and-test check runs automatically: compile, the full test suite, the linter, and coverage on new code. It went green — all eleven tests. This one blocks: a red result is a closed door no human can wave through without an expensive exception.
A second agent checks against the spec
A fresh agent that did not write the code reads the spec and the change, walking the acceptance checks one by one. It caught the hole eleven green tests missed — two claims with an empty policy number merging into one. It posts a verdict and advises; it never blocks.
The security reviewer runs
Spec 0016 is tiered HIGH — merging claim records is hard to undo. That fires the security check, the reviewer agent. On a HIGH change this one blocks, and the merge bar will also demand a named human's recorded sign-off accepting the risk.
Someone who didn't write it decides
Sara — not the author — read the grader's catch, agreed, and bounced the change back to be fixed on the same branch. Every gate, including a fresh grader run, ran again on the corrected change. Then Wes recorded his HIGH sign-off.
A non-author merges
With CI green, the grader run, a non-author approval, the security pass, and Wes's named sign-off all true, the merge bar clears. A non-author merges — the agent never could have merged its own work even if it tried.
The deploy ships it to dev
The merge already cleared the bar, so the deploy workflow ships the change to dev with no human in the loop — and would roll back automatically if the deploy failed. Production is later, and by ceremony; dev is where the rails get exercised constantly.
Go deeper — the full method
One spec = one branch = one PR. The journey of spec 0016 is the principle in motion: the
agent investigates, plans, and produces the change as a reviewable artifact, then stops. The
Stop hook proved the suite green before the agent could finish. On the PR, ci
blocks and went green; grader ran and advised, catching the empty-policy-number
bug the eleven tests never thought to cover; security fired on the
risk:high label and blocked until it passed.
A non-author — Sara — read the grader's verdict and bounced the change back; the
fix landed on the same branch and every gate, including a fresh grader run, re-ran. Wes
recorded the HIGH named sign-off. Only with CI green, the grader run, a non-author approval,
the security pass, and the recorded sign-off all true did the merge bar clear — and a
non-author merged, because the agent cannot approve or merge its own work. The
deploy-dev workflow then shipped the merged artifact to dev automatically, and
would have rolled back on a failed deploy. Production is later, by ceremony; dev is where the
rails get exercised constantly.
How it goes wrong
The failure modes, and the defense against each
Every one of these has happened to someone. Knowing them by name is half the defense — and Harbor's rails caught several of them in the act.
| The trap | What it looks like | The defense | At Harbor |
|---|---|---|---|
| The unexercised pipeline | CI green because nothing real ever ran through it | Force each rail to fail on purpose and prove it catches. | Every rail shaken down before Foundation closed |
| Auto-merging the agent's fix | A self-healing pipeline pushes its own fix to main | The agent proposes; the merge bar disposes. Stop at the PR. | Held — the self-heal agent stopped at a PR |
| The raw-shell agent | "Here's the whole repo and a shell, fix the build" | A small, named tool surface — read, write, run tests, run lint. | Fix agent had four tools, nothing more |
| The rebuilt artifact | Production gets a fresh build, not the one that passed test | Promote the proven artifact; never rebuild. | rc-1.0.1 promoted, not recompiled |
| The rollback only ever written | Documented, reviewed, never run — until an incident | Rehearse it in test, before it's needed. | Caught — failed in Tuesday's rehearsal |
| A secret in the repo | A key committed to code, a config, or a spec | The client's vault from day one. | Pod never knew a production secret |
| The unattended destructive apply | An agent applies infra that deletes or replaces, unread | Read-only until the last step; a human reads the dry-run. | Tom read every what-if before any apply |
| Ignoring drift | Real infra diverges from code and nobody acts | Drift is a proposed fix waiting for a human, not a notice to dismiss. | Drift opened a PR; Tom absorbed it into the code |
Go deeper — the full method
- The pipeline that exists but was never exercised. CI green because nothing real ever ran through it. The rails are proven by a change breaking and being caught, not by the YAML being present. Force each failure.
- Auto-merging the agent's fix. A self-healing pipeline that pushes its own fix to the protected branch has thrown away the only rule that makes it safe. Stopping at the PR is the whole design.
- The raw-shell agent. Handing an agent the whole repo and a shell with "fix the build" instead of a bounded, named tool surface. It will touch three things nobody wanted touched, and the log won't tell you why.
- The rebuilt artifact. Production gets a fresh build instead of the promoted one that passed test — now production runs something no environment verified. Promote, never rebuild.
- The rollback that was only ever written. Documented, reviewed, never run — then executed for the first time during an incident. Rehearse it in test.
- A secret in the repo. The one unrecoverable foundation mistake. The client's vault from day one.
- The unattended destructive apply. An agent runs an infrastructure
applythat deletes or replaces, with no human reading the dry-run first. Every step before the apply is read-only for exactly this reason. - Autonomy granted too fast. Wiring a brand-new agent automation straight to closed-loop because it worked twice. Autonomy widens slowly, after behavior is watched.
- The over-scoped agent identity. An agent running with subscription-wide rights "to keep it simple." When its prompt is subverted, the blast radius is everything it could reach. Scope to the resource, give it its own identity, keep the kill switch.
- Approval fatigue. Gating every trivial step behind a human until they rubber-stamp without reading. Shift oversight from per-step to per-strategy — approve the plan up front, retain the ability to intervene.
- Ignoring drift. The schedule flags that real infrastructure diverged from the code, and nobody acts, so the repo stops being the truth. Drift is a proposed remediation waiting for an operator, not a notification to dismiss.
When the rails are doing their job
The agent moves fast — and you never have to trust its word
The rails aren't a brake on the agent. They're what lets you take it off the leash: it can propose anything, as fast as it likes, because nothing it proposes takes effect until a gate — and where it matters, a named human — says so. One principle, wired into every place a change could go wrong. Where to go next: