DEV Community

kongkong
kongkong

Posted on

Put a Deterministic Gate Between Generated Code and Main

Generated code should enter a repository through the same narrow door as human code.

That door is not “the agent said the task succeeded.” It is a deterministic sequence: inspect the patch, classify risky paths, run repository checks, require the right reviewer, and only then allow a merge.

This tutorial builds the first gate as a small POSIX shell script. It does not judge whether the implementation is correct. It rejects patches that are too large for the chosen review budget, touch sensitive paths without escalation, or contain whitespace and conflict-marker errors detected by Git.

Define what the gate owns

The gate answers three questions:

  1. Is the patch within a reviewable size budget?
  2. Does it touch a path that requires an explicit owner?
  3. Does the diff pass Git's structural checks?

It does not replace tests, type checks, security scanning, or human review. Keeping the scope small makes its result explainable.

Add the script

Save this as scripts/verify-patch.sh:

#!/bin/sh
set -eu

base_ref=${1:-HEAD^}
max_files=${MAX_FILES:-20}
max_lines=${MAX_LINES:-800}

files=$(git diff --name-only --diff-filter=ACMR "$base_ref"...HEAD)
file_count=$(printf '%s\n' "$files" | awk 'NF { count += 1 } END { print count + 0 }')
line_count=$(git diff --numstat "$base_ref"...HEAD | \
  awk '{ added += $1; deleted += $2 } END { print added + deleted + 0 }')

if [ "$file_count" -gt "$max_files" ]; then
  printf 'FAIL patch touches %s files (limit %s)\n' "$file_count" "$max_files" >&2
  exit 1
fi

if [ "$line_count" -gt "$max_lines" ]; then
  printf 'FAIL patch changes %s lines (limit %s)\n' "$line_count" "$max_lines" >&2
  exit 1
fi

if printf '%s\n' "$files" | grep -Eq '(^|/)(\.env($|\.)|infra/|migrations/|CODEOWNERS$)'; then
  printf 'FAIL sensitive path requires explicit review\n' >&2
  printf '%s\n' "$files" >&2
  exit 1
fi

git diff --check "$base_ref"...HEAD

printf 'PASS files=%s changed_lines=%s\n' "$file_count" "$line_count"
Enter fullscreen mode Exit fullscreen mode

Make it executable:

chmod +x scripts/verify-patch.sh
Enter fullscreen mode Exit fullscreen mode

Then compare the current branch with the target branch:

MAX_FILES=20 MAX_LINES=800 ./scripts/verify-patch.sh origin/main
Enter fullscreen mode Exit fullscreen mode

The triple-dot diff means “changes on this branch since its merge base with the target.” That is usually the patch a pull request reviewer needs to inspect.

Test the gate in a disposable repository

The script should prove both acceptance and rejection. From an empty temporary directory:

git init
git config user.email test@example.com
git config user.name PatchGateTest
mkdir -p scripts src
cp /path/to/verify-patch.sh scripts/verify-patch.sh
printf 'export const answer = 41;\n' > src/value.js
git add . && git commit -m baseline

printf 'export const answer = 42;\n' > src/value.js
git add . && git commit -m safe-change
./scripts/verify-patch.sh HEAD^
Enter fullscreen mode Exit fullscreen mode

Expected result:

PASS files=1 changed_lines=2
Enter fullscreen mode Exit fullscreen mode

Now test a sensitive path:

mkdir -p infra
printf 'resource "example" {}\n' > infra/main.tf
git add . && git commit -m sensitive-change
./scripts/verify-patch.sh HEAD^
Enter fullscreen mode Exit fullscreen mode

Expected result and exit status 1:

FAIL sensitive path requires explicit review
infra/main.tf
Enter fullscreen mode Exit fullscreen mode

I ran these paths on macOS with Git 2.50.1 and the system POSIX shell. The safe patch passed; the infrastructure patch failed as intended.

Wire it into CI

For GitHub Actions, fetch enough history to identify the merge base and call the same repository script:

name: patch-policy
on: [pull_request]

jobs:
  verify-patch:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: ./scripts/verify-patch.sh "origin/${{ github.base_ref }}"
Enter fullscreen mode Exit fullscreen mode

Pin third-party actions to a full commit SHA in a security-sensitive repository. The version tag above keeps the example readable but is a mutable reference.

After this patch-policy job, run the repository's normal formatter, type checker, tests, dependency review, secret scanning, and build. Use CODEOWNERS or an equivalent rule to route sensitive changes rather than merely blocking them forever.

Choose budgets from review behavior

The example limits are not universal safety numbers. Start with the distribution of recent pull-request sizes and the team's review capacity. A generated dependency lockfile may add thousands of legitimate lines; a one-line authorization change may be high risk.

Useful extensions include:

  • separate limits for generated and hand-maintained files;
  • deny binary additions unless explicitly approved;
  • require tests when application code changes;
  • require migration rollback notes when schema files change;
  • identify newly executable files or permission changes;
  • emit a machine-readable result for the pull-request UI.

The gate should tell the author what happened and how to escalate. A mysterious red check encourages bypasses.

Apply it to an AI development platform

The MonkeyCode repository describes AI tasks running in managed development environments. If a team uses MonkeyCode—or any coding agent—to create repository changes, this gate belongs in the target repository's CI. That keeps the merge policy independent from whichever model or task interface produced the patch.

This article does not test MonkeyCode's generated patches or claim that it lacks these controls. The verified artifact is the repository gate and its disposable Git test.

Disclosure: I contribute to the MonkeyCode project. The workflow connection is based on public product documentation; the patch-policy script is tool-independent.

Developers evaluating that workflow can join the MonkeyCode Discord. The team can discuss integration questions and current availability, eligibility, and limits for free model credits.

Generated code becomes ordinary code at the repository boundary. That is a feature: deterministic policy, project-owned tests, and accountable review remain useful even when the generator changes next month.

Top comments (0)