💡 Why toSoftwareIntermediate✨ AI-assisted

Why Gemini 4 Argon Outputs Need Automated Code Review Gates

WittyTech Daily··5 min read
#gemini-4-argon#code-review#ci#guardrails

If your plan for Gemini 4 Argon code review is "a person reads the diff", that plan has an expiry date. Google's announcement raises the maximum output from 64K tokens to 1M, and says the model can "generate hundreds of thousands of tokens in a single trajectory." One response can now be larger than most pull requests are ever allowed to be.

Argon is currently rolling out to trusted cyber defenders through Google's Fairwind Program, with paid API customers and Google AI Ultra subscribers named as the start of the wider release. You probably can't call it yet, which is the right time to build a gate that doesn't care which model wrote the code.

The math behind Gemini 4 Argon code review

A rough rule of thumb is ten tokens per line of code (your tokenizer will differ). At that rate, 64K tokens is around 6,000 lines, which is survivable. 1M tokens is around 100,000 lines. Even at a brisk 500 lines an hour, that is 200 hours, or five work weeks, for one answer.

Nobody will do that. The reviewer skims the first screen, trusts the rest and clicks approve. 1M is a ceiling, not a typical response, but your process has to survive the ceiling. Human attention fails exactly when the output is largest, which is also when the model had the most room to go wrong.

Four gates to run before a human looks

Run them cheapest first, and stop at the first failure.

  1. Diff size. Cap files and changed lines. A change over the cap is sent back to be split, not reviewed. This one gate turns "1M tokens" into chunks a person can actually read.
  2. Secret scan. Anything in the prompt or context, including a key someone pasted in for convenience, can end up in the output. Scan the commit range with gitleaks.
  3. Build. Cheap, binary, and it catches whole categories of nonsense, such as imports of packages that don't exist.
  4. Tests. The existing suite must still pass.

None of these needs a model. They are deterministic, so a failure is a fact, not an opinion.

A model-agnostic gate you can wire into CI today

The script below never calls a model. It reads the model ID from an AI_MODEL_ID variable or from a Generated-by: commit trailer, and stamps it on every result line. When Argon opens up to you, the only change is the ID in the trailer, and you can compare gate pass rates per model.

git commit -m "Add billing export module" -m "Generated-by: <model-id>"

The second -m makes a separate paragraph, which git reads as a trailer block. The script reads it back with the %(trailers:key=...,valueonly) format from git's pretty-formats reference.

#!/usr/bin/env python3
"""Pre-review gate for large machine-written changes. Calls no model API."""
import json
import os
import shlex
import subprocess
import sys

BASE = os.environ.get("GATE_BASE", "origin/main")
MAX_FILES = int(os.environ.get("GATE_MAX_FILES", "40"))
MAX_LINES = int(os.environ.get("GATE_MAX_LINES", "2000"))
BUILD_CMD = os.environ.get("GATE_BUILD_CMD", "python -m compileall -q .")
TEST_CMD = os.environ.get("GATE_TEST_CMD", "pytest -q -x")


def run(args, check=False):
    return subprocess.run(args, capture_output=True, text=True, check=check)


def model_id():
    """Env var wins, then 'Generated-by:' commit trailers, else 'unknown'."""
    if os.environ.get("AI_MODEL_ID"):
        return os.environ["AI_MODEL_ID"]
    out = run(["git", "log", f"{BASE}..HEAD",
               "--format=%(trailers:key=Generated-by,valueonly)"], check=True).stdout
    ids = sorted({line.strip() for line in out.splitlines() if line.strip()})
    return ",".join(ids) or "unknown"


def check_diff_size():
    out = run(["git", "diff", "--numstat", f"{BASE}...HEAD"], check=True).stdout
    files = lines = 0
    for row in out.splitlines():
        added, deleted, _path = row.split("\t", 2)
        files += 1
        if added != "-":  # binary files report "-"
            lines += int(added) + int(deleted)
    ok = files <= MAX_FILES and lines <= MAX_LINES
    return ok, f"{files} files, {lines} changed lines (limits {MAX_FILES}/{MAX_LINES})"


def check_secrets():
    r = run(["gitleaks", "git", "--redact", "--no-banner", f"--log-opts={BASE}..HEAD"])
    return r.returncode == 0, (r.stdout + r.stderr).strip()[-500:]


def check_command(cmd):
    r = run(shlex.split(cmd))
    return r.returncode == 0, (r.stdout + r.stderr).strip()[-500:]


# Cheapest first: a 4,000-line diff never reaches the test runner.
GATES = [
    ("diff-size", check_diff_size),
    ("secrets", check_secrets),
    ("build", lambda: check_command(BUILD_CMD)),
    ("tests", lambda: check_command(TEST_CMD)),
]


def main():
    model = model_id()
    for name, gate in GATES:
        ok, detail = gate()
        print(json.dumps({"model": model, "gate": name, "passed": ok}))
        if not ok:
            print(detail, file=sys.stderr)
            return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())

The git calls use check=True, so a missing base branch raises an error instead of passing on an empty diff: the gate fails closed. The 40-file and 2,000-line defaults are arbitrary; tune them to your team's normal pull request size and swap in your own build and test commands.

name: ai-output-gate
on:
  pull_request:

jobs:
  gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0  # the gate needs the base branch history
      - name: Install gitleaks
        run: |
          curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz \
            | sudo tar -xz -C /usr/local/bin gitleaks
      # install your project dependencies here
      - name: Run the gate
        env:
          GATE_BASE: origin/${{ github.base_ref }}
          GATE_BUILD_CMD: "python -m compileall -q ."
          GATE_TEST_CMD: "pytest -q -x"
          GATE_MAX_LINES: "2000"
        run: python ai_review_gate.py

With the default shallow clone the base branch isn't there, so keep fetch-depth: 0. Then mark the job as required in your branch protection rules, or it is only a suggestion. Pin the gitleaks version as shown.

The objection: gates only catch the easy problems

True. A green gate means a human may start reviewing, not that the code is right. A 3,000-line change can compile, pass the existing tests and still encode the wrong business rule, because tests only cover what already has tests.

An LLM reviewer is a fair extra layer for triage, but its verdict is an opinion, not a gate that fails the same way every time. You should also ask the model for smaller changes, and the diff-size gate is what makes that request stick.

Gates don't replace the reviewer. They shrink the haystack so the reviewer's attention goes to logic, not to find-the-leaked-key.

Start with the diff-size cap this week

Add the script to one repo where people already use coding assistants. Set the line cap a little above your largest normal pull request, make the job required, and add the Generated-by trailer to your commit template.

Whichever model writes the code, production gets safer when the first reviewer of a million-token answer is a script that fails the same way every time.

← More in Software