Skip to content
September 24, 2026•9 min read•By Dzaki Amri Zaidaan

AI Writes the Code, You Own the Blast Radius: Engineering Accountability in Agentic Workflows

Agentic coding tools now generate migrations, infra changes, and refactors on demand — but the review surface is expanding faster than the code volume. This article breaks down the architecture of a production agent pipeline, a typed review-gate implementation, and the cost/latency trade-offs of shifting from code author to system owner.

#AI & ML#DevOps
two men working on computers in an office

The Problem & Industry Shift

For two decades, the bottleneck in software delivery was authoring. Typing, boilerplate, framework glue, test scaffolding — all of it consumed senior engineer hours. Agentic coding tools collapsed that bottleneck. A developer can now ask an agent to:

  • create a new service from a spec,
  • migrate a schema across 40 call sites,
  • rewrite a synchronous handler into an idempotent queue consumer,
  • generate Terraform for the new dependency,
  • and open a PR with tests attached.

The code volume goes up. The authoring effort goes down. But something else goes up that most teams under-model: the review and accountability surface.

When a human wrote 200 lines, they carried the full context of those 200 lines. When an agent writes 2,000 lines across 30 files, the human still signs off — but with a fraction of the context. The diff is no longer the unit of understanding; the system behavior is. This is the shift: developers are moving from code authors to system owners responsible for the blast radius of generated changes.

This is not a philosophical point. It has concrete engineering consequences:

  1. Review throughput becomes the new bottleneck. If generation is 10x faster but review is 1x, the queue inverts.
  2. Trust boundaries move. You no longer trust the author's intent; you must verify the artifact's behavior.
  3. Failure modes change. Agents rarely produce syntax errors. They produce plausible but wrong semantics — off-by-one in pagination, missing transaction boundaries, subtly incorrect retry logic.

The rest of this article treats the agent as a production system component with inputs, outputs, guardrails, and measurable failure rates — not as a magic autocomplete.

Architecture & Core Mechanics

The core insight is that an agentic coding pipeline is a distributed system with a human in the critical path. Treat it like any other pipeline: define stages, define contracts, measure each stage.

┌─────────────┐   ┌──────────────┐   ┌───────────────┐   ┌──────────────┐
│  Intent /   │──▶│  Retrieval   │──▶│  Generation   │──▶│  Static +    │
│  Task Spec  │   │  (repo ctx)  │   │  (LLM agent)  │   │  Dynamic     │
└─────────────┘   └──────────────┘   └───────────────┘   │  Verification│
                                                          └──────┬───────┘
                                                                 │
                          ┌──────────────────────────────────────┘
                          ▼
                   ┌──────────────┐   ┌───────────────┐   ┌──────────────┐
                   │  Diff +      │──▶│  Human Review │──▶│  Merge /     │
                   │  Risk Score  │   │  (gated)      │   │  Deploy      │
                   └──────────────┘   └───────────────┘   └──────────────┘

Stage 1 — Intent / Task Spec. The agent is only as good as the spec. Vague prompts produce vague diffs. Production teams increasingly write specs as structured artifacts (issue templates, JSON task descriptors) so the agent's output is checkable against the spec.

Stage 2 — Retrieval. The agent needs repository context. This is a retrieval problem: embeddings over the codebase, symbol graphs, and dependency manifests. Retrieval quality dominates output quality far more than model choice in most real repos.

Stage 3 — Generation. The model produces a candidate diff. Critically, generation should be constrained — the agent should not be allowed to touch files outside an allowlist derived from the task spec.

Stage 4 — Verification. This is where accountability is engineered, not asserted. Verification has three layers:

  • Static: type checks, linters, SAST, dependency policy (e.g., no new GPL deps).
  • Dynamic: unit tests, integration tests, and — for infra changes — plan/apply dry runs.
  • Semantic: does the diff actually satisfy the spec? This is the hardest layer and the one humans must own.

Stage 5 — Risk Scoring & Human Gate. Not all diffs deserve the same scrutiny. A 3-line config change and a 400-line auth refactor should not enter the same review queue. Risk scoring routes diffs to the appropriate review depth.

Stage 6 — Merge / Deploy. Standard CI/CD, but with provenance metadata attached: which agent, which model version, which spec, which verification results.

The key architectural principle: the agent is untrusted by default. Every stage is a checkpoint, not a formality. This mirrors how you'd treat any third-party service writing to your production systems [1].

Production Code Example

The following TypeScript implements the verification and risk-gating layer — the part that converts "the agent wrote code" into "a human can responsibly approve it." It is framework-agnostic and runs in a CI worker.

// agent-gate.ts — verification + risk gating for agent-generated diffs
// Runs in CI after the agent opens a PR. Blocks merge until gates pass.

import { execFile } from "node:child_process";
import { promisify } from "node:util";

const run = promisify(execFile);

type Severity = "low" | "medium" | "high" | "critical";

interface DiffFile {
  path: string;
  additions: number;
  deletions: number;
  // Files the agent was allowed to touch, derived from the task spec.
  inAllowlist: boolean;
}

interface VerificationResult {
  staticChecks: boolean;
  testsPassed: boolean;
  specSatisfied: boolean; // set by a separate semantic-eval job
  touchedSensitivePaths: string[];
}

interface RiskAssessment {
  score: number;          // 0..100
  severity: Severity;
  requiresHumanReview: boolean;
  reasons: string[];
}

// Paths that always escalate risk regardless of diff size.
const SENSITIVE_PATTERNS: RegExp[] = [
  /^infra\//,            // Terraform / IaC
  /^src\/auth\//,        // auth & session logic
  /^migrations\//,       // DB migrations
  /\.github\/workflows\//, // CI/CD definitions
  /^src\/billing\//,     // money-touching code
];

function assessRisk(files: DiffFile[], v: VerificationResult): RiskAssessment {
  const reasons: string[] = [];
  let score = 0;

  // 1. Verification failures are disqualifying, not just additive.
  if (!v.staticChecks) { score += 40; reasons.push("static checks failed"); }
  if (!v.testsPassed)  { score += 40; reasons.push("tests failed"); }
  if (!v.specSatisfied) { score += 30; reasons.push("spec not verified"); }

  // 2. Out-of-allowlist edits are a strong signal of scope creep.
  const outOfScope = files.filter((f) => !f.inAllowlist);
  if (outOfScope.length > 0) {
    score += 25;
    reasons.push(`edited ${outOfScope.length} file(s) outside task allowlist`);
  }

  // 3. Sensitive paths escalate regardless of size.
  const sensitive = files
    .map((f) => f.path)
    .filter((p) => SENSITIVE_PATTERNS.some((re) => re.test(p)));
  if (sensitive.length > 0) {
    score += 20;
    reasons.push(`touched sensitive paths: ${sensitive.join(", ")}`);
  }

  // 4. Diff size: large diffs get more scrutiny, but size alone is weak.
  const totalLines = files.reduce((n, f) => n + f.additions + f.deletions, 0);
  if (totalLines > 500) { score += 10; reasons.push(`large diff (${totalLines} lines)`); }

  score = Math.min(score, 100);
  const severity: Severity =
    score >= 70 ? "critical" : score >= 45 ? "high" : score >= 20 ? "medium" : "low";

  return {
    score,
    severity,
    // Anything above "low" requires a named human reviewer. No auto-merge.
    requiresHumanReview: severity !== "low",
    reasons,
  };
}

// Entry point: invoked by CI on every agent-authored PR.
async function gate(prNumber: number): Promise<void> {
  const files = await collectDiff(prNumber);
  const verification = await runVerification(files);
  const risk = assessRisk(files, verification);

  // Attach provenance so the merge commit records how the code was produced.
  await annotatePR(prNumber, {
    agent: process.env.AGENT_ID ?? "unknown",
    model: process.env.MODEL_VERSION ?? "unknown",
    risk,
  });

  if (risk.requiresHumanReview) {
    await requestReview(prNumber, risk.severity, risk.reasons);
    process.exit(0); // do not fail the build; block merge via branch protection
  }
  console.log(`Auto-eligible: risk=${risk.severity} score=${risk.score}`);
}

// --- stubs for brevity; wire to your VCS + CI provider ---
declare function collectDiff(pr: number): Promise<DiffFile[]>;
declare function runVerification(files: DiffFile[]): Promise<VerificationResult>;
declare function annotatePR(pr: number, meta: Record<string, unknown>): Promise<void>;
declare function requestReview(pr: number, sev: Severity, reasons: string[]): Promise<void>;

void gate(Number(process.env.PR_NUMBER));

Three engineering decisions worth calling out:

  1. Verification failures are disqualifying, not merely additive. A failed test should not be "offset" by a small diff. The scoring weights reflect that.
  2. Allowlist enforcement is a first-class signal. Agents drift; an out-of-scope edit is often the first symptom of a misread spec.
  3. Provenance is attached at merge time. When something breaks six weeks later, you can answer "which model, which spec, which agent" without archaeology.

Performance, Cost & Trade-offs

The economics of agentic coding are real, but they are not uniform across the pipeline. The gains concentrate in generation; the costs concentrate in verification and review.

StageHuman-onlyAgent-assistedNotes
Authoringbaseline~5–10x fasterLargest gain; scales with task specificity
Static verificationsecondssecondsNo meaningful change
Test executionminutesminutesAgent-generated tests may be weaker; audit them
Human reviewbaselinehigher per diffLarger, less-contextual diffs cost more to review
Incident costbaselinerisk of increasePlausible-but-wrong semantics are harder to catch

Key trade-offs to internalize:

  • Latency vs. accuracy in retrieval. Larger context windows improve generation quality but increase token cost and latency. Most teams find a symbol-graph + targeted-embedding retrieval beats dumping the whole repo into context [2].
  • Auto-merge vs. human gate. Auto-merging low-risk diffs (docs, formatting, dependency bumps within policy) is where the productivity win actually lands. Auto-merging anything touching auth, billing, or IaC is how you get a postmortem.
  • Test generation is not test verification. An agent that writes both the code and the test can produce a green suite that asserts the wrong behavior. Treat agent-authored tests as candidates, and require at least one human-authored or independently-derived assertion on critical paths.
  • Security surface. Agents can introduce dependencies, exfiltrate context via prompts, or follow instructions embedded in retrieved files (prompt injection). Constrain tool access and treat retrieved content as untrusted input [3].

The uncomfortable truth: the productivity gain is real, and so is the accountability concentration. A single reviewer now approves changes whose behavioral surface they did not personally construct. That is a management and process problem as much as a technical one — but it is solvable with the gating architecture above.

Actionable Checklist / Summary

When adopting agentic coding in production, do these in order:

  • Write specs as artifacts, not prompts. Structured task descriptors make agent output checkable.
  • Enforce an allowlist per task. The agent should not be able to edit files outside the spec's scope.
  • Gate on verification, not vibes. Static checks + tests + a semantic spec check, all blocking.
  • Score risk and route review depth. Small, low-risk diffs can auto-merge; sensitive paths always require a named human.
  • Attach provenance to every merge. Agent ID, model version, spec ID, verification results.
  • Audit agent-authored tests. At least one independent assertion on critical paths.
  • Treat retrieved content as untrusted. Defend against prompt injection from repo files and dependencies.
  • Measure review latency, not just generation speed. The bottleneck moved; your metrics should move with it.

The headline is not "AI writes code." It is that the developer's job has shifted from producing diffs to owning the behavior those diffs create — and that ownership must be engineered into the pipeline, not assumed.

References