{"id":4803,"date":"2026-08-13T10:49:24","date_gmt":"2026-08-13T10:49:24","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/08\/13\/the-agent-proposes-the-pipeline-disposes-controls-for-ai-authored-change\/"},"modified":"2026-08-13T10:49:24","modified_gmt":"2026-08-13T10:49:24","slug":"the-agent-proposes-the-pipeline-disposes-controls-for-ai-authored-change","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/08\/13\/the-agent-proposes-the-pipeline-disposes-controls-for-ai-authored-change\/","title":{"rendered":"The Agent Proposes, the Pipeline Disposes: Controls for AI-Authored Change"},"content":{"rendered":"<div><img data-opt-id=602512365  fetchpriority=\"high\" decoding=\"async\" width=\"770\" height=\"330\" src=\"https:\/\/devops.com\/wp-content\/uploads\/2026\/07\/ai-agent-code-gates-770x330-1.jpg\" class=\"attachment-large size-large wp-post-image\" alt=\"\" \/><\/div>\n<p><img data-opt-id=675585015  fetchpriority=\"high\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/devops.com\/wp-content\/uploads\/2026\/07\/ai-agent-code-gates-770x330-1-150x150.jpg\" class=\"attachment-thumbnail size-thumbnail wp-post-image\" alt=\"\" \/><\/p>\n<p>The pull request was clean. Tight commit message, a one-line fix to a retry helper, green checks. I approved it in the time it takes to drink coffee. It came from an agent we\u2019d wired into our workflow to chew through flaky-test toil, and it had done exactly that all week.<\/p>\n<p>What I almost missed: The change widened the retry window and dropped the jitter on a client that fans out to a downstream service we don\u2019t own. Under normal load, invisible. Under a partial outage, that\u2019s a synchronized retry storm \u2014 the kind of thundering-herd regression that reads as one removed line and behaves as an incident. A change-budget gate caught it because the file lived behind a protected path, not because I did. I\u2019d already clicked approve.<\/p>\n<p>That was the moment I stopped trusting my own review as a control. Not because the agent was bad but because it was good enough that the diff looked fine, and \u2018the diff looked fine\u2019 is not a control; it\u2019s a vibe.<\/p>\n<h3>Why Human Review Stopped Scaling<\/h3>\n<p>Code review was designed around a human bottleneck. One engineer writes a few hundred lines a day, another reads them and the slowness is load-bearing \u2014 it\u2019s the rate limit that keeps the queue legible. Agents delete that assumption. A single agent can open a dozen PRs an hour, each individually plausible, each touching a different corner of the system.<\/p>\n<p>Plausible is the problem. Agent-authored changes are optimized to pass the smell test. They have clean names, reasonable commit messages and tests that go green, because the agent can see the test suite and write to it. A reviewer scanning 20 of these a day is not really reviewing \u2014 they\u2019re rubber-stamping with extra steps, and they\u2019ll wave through the one that matters because it looks like the 19 that didn\u2019t.<\/p>\n<p>You cannot fix this by reviewing harder. The bottleneck you removed isn\u2019t coming back. You fix it by moving the control out of the human\u2019s head and into the pipeline, where it runs the same way on PR number 1 and PR number 200.<\/p>\n<h3>Provenance is the New Gate<\/h3>\n<p>Here\u2019s the uncomfortable reframe: An AI-authored change is an artifact from an untrusted producer, and we already know how to handle those. We\u2019ve spent years building supply-chain controls for exactly this shape of problem \u2014 code entering the pipeline from somewhere you don\u2019t fully trust, that you need to verify before you act on it.<\/p>\n<p>The supply-chain world settled on a clear idea: Don\u2019t trust the artifact, verify its provenance. The SLSA framework formalizes this as a signed attestation that travels with an artifact and answers how it was produced. The in-toto project gives you the attestation format. Sigstore gives you the signing and verification. None of this was built for agents, and all of it applies directly.<\/p>\n<p>So make every agent-authored change carry a provenance record, and make that record machine-checkable. Not a label a human reads \u2014 a signed attestation the pipeline enforces. Which model and version produced this change? What prompt or task spec drove it? Which tools was it allowed to call? Which tests and evals gated it? What they returned? If the change shows up without that record, it doesn\u2019t get reviewed. It gets rejected at the door.<\/p>\n<p>This is the inversion that matters. The default is deny. The agent earns its way into the human queue by proving where the change came from, not by looking convincing.<\/p>\n<h3>The Gate, in About 20 Lines<\/h3>\n<p>The control I trust is boring on purpose. A pipeline stage, vendor-neutral, that refuses to advance an AI-authored change unless it carries a verifiable provenance attestation and clears the eval and policy gates. Nothing here is exotic \u2014 it\u2019s the supply chain playbook pointed at a new kind of producer.<\/p>\n<pre><code># ci: gate for AI-authored changes. deny-by-default.\r\ngate:\r\n  applies_when: change.author_type == \"agent\"\r\n  require_all:\r\n\r\n    # 1. provenance must exist and verify (SLSA-style attestation, sigstore-signed)\r\n    - attestation.present: true\r\n    - attestation.signature_valid: true\r\n    - attestation.fields_present: [model_id, task_spec_ref, tools_allowed, tests_run]\r\n\r\n    # 2. executable eval gate \u2014 the agent's own tests don't count alone\r\n    - eval_suite.passed: true            # independent suite the agent cannot edit\r\n    - eval_suite.coverage_delta &gt;= 0     # no silent removal of checks\r\n\r\n    # 3. policy-as-code \u2014 least privilege, protected paths, change budget\r\n    - policy.protected_paths_untouched: true   # iac\/prod\/*, auth\/*, billing\/*\r\n    - policy.requested_scopes \u2286 task_spec.granted_scopes\r\n    - policy.lines_changed &lt;= budget.per_pr     # change-budget guardrail\r\n\r\n  on_fail: reject            # never auto-merge; route to human with the failing reason\r\n  on_pass: route_to_human    # human reviews a verified change, not a raw one<\/code><\/pre>\n<p>Three things make this hold up. The eval suite is independent of the agent and the agent can\u2019t write to it, so green isn\u2019t self-certified. The policy checks are mechanical facts about the change \u2014 paths, scopes, line counts \u2014 not judgments about whether the code is \u2018good\u2019 and the failure mode is rejection, not merge. A gate that auto-merges on pass and only flags on fail has the logic backwards; the whole point is that nothing reaches a human until it\u2019s already provably in-bounds.<\/p>\n<h3>Staged Autonomy, and What Still Breaks<\/h3>\n<p>Provenance and policy tell you <em>whether<\/em> to trust a change. Staged autonomy decides <em>how much rope<\/em> the agent gets to begin with. I run agents through four levels:<\/p>\n<p>Observe (read-only, it comments)<\/p>\n<p>Recommend (it drafts, a human commits)<\/p>\n<p>Bounded-write (it merges, but only inside an explicit allowlist of paths and scopes with a change budget)<\/p>\n<p>Governed (wider authority, every action attested and reversible)<\/p>\n<p>An agent earns the next level by accumulating a clean track record at the current one. It doesn\u2019t start at bounded-write because it sounded confident in a demo.<\/p>\n<p>I\u2019ll be honest about the holes, because pretending they\u2019re closed is how you get burned. Provenance proves origin, not correctness \u2014 a signed attestation on a wrong change is a well-documented wrong change. Your eval suite is now a security boundary, which means a gap in coverage is a gap in your defenses, and agents are very good at finding the path that your tests don\u2019t watch. Policy as code only constrains what you thought to encode; the regression that bit me was caught by a path rule, but a subtler one could live entirely inside an allowed path. Every signing key and policy engine you add is itself attack surface \u2014 the OWASP guidance on supply chain and AI risks is worth reading precisely because these controls become the thing worth attacking.<\/p>\n<p>None of that is an argument against the gates. It\u2019s an argument for treating them as load-bearing infrastructure \u2014 versioned, tested, owned \u2014 instead of a checkbox. The eval suite and the policy bundle deserve the same on-call rigor as the service they protect.<\/p>\n<h3>The Takeaway<\/h3>\n<p>The agent proposes; the pipeline disposes. Stop asking whether the diff looks fine, because at agent volume your judgment isn\u2019t the control and was never going to be. Make every AI-authored change prove its provenance, pass an eval gate it can\u2019t edit and clear policy rules a machine enforces the same way every time. Build those controls outside the agent\u2019s reasoning loop, where its confidence can\u2019t reach them.<\/p>\n<p><a href=\"https:\/\/devops.com\/the-agent-proposes-the-pipeline-disposes-controls-for-ai-authored-change\/\" target=\"_blank\" class=\"feedzy-rss-link-icon\">Read More<\/a><\/p>\n<p>\u200b<\/p>","protected":false},"excerpt":{"rendered":"<p>The pull request was clean. Tight commit message, a one-line fix to a retry helper, green checks. I approved it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4804,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[5],"tags":[],"class_list":["post-4803","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/4803","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=4803"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/4803\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/4804"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=4803"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=4803"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=4803"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}