AI question hub/Production AI
Reviewed, source-backed answer 14 min read English · original

How can teams detect and stop low-quality AI-generated code at pull-request time?

A pull-request admission and review system that evaluates evidence and risk instead of guessing authorship, using clear acceptance criteria, deterministic checks, accountable ownership, targeted human review, and outcome metrics.

Real question signalStack Overflow
Can you prevent AI Workslop as soon as you receive a Pull Request?
View the original question
Direct answer

Require each pull request to explain the problem, the intended behavior, and how the change was checked. Run relevant build, test, type, lint, security, and dependency checks before review. Apply these requirements to all code, including AI-assisted changes.

Review the parts automation cannot settle: whether the implementation meets the requirement, fits the existing design, handles failures, and can be operated safely. A passing pipeline is useful evidence, but only for the cases and rules it checks. Route sensitive changes to the appropriate owners.

Keep diffs focused and return incomplete changes to the author with specific missing evidence. Track rework, escaped defects, and review effort to see whether the process helps. Trying to infer authorship from code is a poor substitute for checking the change itself.

[2][3][4][5]

What the gate should decide

The merge decision should answer a concrete question: "Has the author supplied enough evidence for this particular change, and has the right person assessed the remaining uncertainty?" It is a quality and risk decision, not a test of whether a model helped write text in the diff.

This distinction matters. A small hand-written change can be unsafe, while a carefully checked generated change can be sound. Treating a tool's guess about authorship as a blocker encourages concealment and creates arguments about provenance instead of fixing the missing test, unexplained dependency, or risky design. A team may require disclosure of generated code when its legal, security, customer, or internal policy requires it. That disclosure should be a transparent record of process, not a substitute for evidence. It also should not require authors to paste sensitive prompts, credentials, or proprietary context into a public pull request.

Set a short written definition of "ready for review" and apply it to everyone. NIST's Secure Software Development Framework recommends integrating secure development practices into an organization's existing lifecycle, rather than treating security as a separate late activity. NIST SP 800-218 is a useful common vocabulary for this approach.

A practical definition of ready

A ready pull request has a single intended outcome that a reviewer can compare with a linked issue or decision record. Its description says what changed, why it changed, which acceptance criteria it addresses, how it was tested, what was intentionally left out, and what risks or operational effects remain. The author owns this explanation and the first round of failures. Reviewers are not a substitute test team for a change the author has not run.

Judge review size by how much a reviewer needs to understand, as well as the line count. A one-line permission change, generated lockfile update, schema migration, or new network dependency may need more scrutiny than a larger local refactor. Set a normal diff-size expectation as a prompt to split work, then allow an explicit exception for generated files, mechanical upgrades, migrations, or cohesive refactors. Require the exception to say why splitting would make the change less safe and how the reviewer should inspect it. Do not use a hard line-count limit as an automatic proxy for quality.

Controls at each point in the workflow

Stage Required evidence or control What it catches early Human decision still needed
Before opening the pull request Issue and acceptance criteria, local build and targeted tests, formatter and lint, author self-review, generated-code disclosure if policy requires it Vague work, obvious failures, accidental files, code the author cannot explain Whether the proposed design is the right solution
Pull-request admission Template completeness, issue link, scope label, ownership routing, changed-file and dependency classification, size or exception policy Unowned work, surprise broad changes, missing test plan, review sent to the wrong people Whether the scope and risk rating are plausible
Continuous integration Reproducible build, tests, type checking, linting, code and secret scanning, dependency review, architecture tests, duplication and dead-code analysis, performance checks when affected Regressions detectable by tools, known vulnerable dependencies, policy violations, incompatible interfaces Whether green checks exercise the important behavior and assumptions
Human review Acceptance-criteria traceability, domain and security review based on risk, operational and rollback assessment Incorrect intent, misleading tests, unsafe tradeoffs, maintainability problems Final accountable approval

The specific tooling can differ. The control is the required result, not a named vendor. For example, GitHub protected branches can require approving reviews and passing status checks before merge. They can also dismiss approvals after a code-changing push, preventing an approval of an earlier diff from silently covering later content. GitHub protected branches documents both controls.

Before the pull request

Start with a ticket, issue, short design record, or equivalent. It should contain observable acceptance criteria, such as "a signed-out caller receives no object metadata" or "a retry after a timeout creates at most one invoice." Avoid criteria such as "improve API" or "add caching" without a boundary and expected behavior. Link the pull request to that record so the reviewer can test the change against a known intent rather than reverse-engineering it from code.

Ask the author to run the fastest relevant checks locally and self-review the complete diff. A useful checklist asks: Did I modify only files needed for this outcome? Did I remove debug output, unused helpers, commented-out alternatives, accidental formatting churn, and generated artifacts that should not be committed? Did I test both the expected case and the key denial or failure case? Can I explain every added dependency and public interface change? This is especially valuable with generated code because fluent output can hide redundant helpers and unused branches.

Make generated-code disclosure proportional. For an ordinary low-risk change, a checkbox such as "AI assistance used: yes or no" plus an attestation that the author reviewed and tested the contribution may be enough if policy requires it. For a regulated or security-sensitive change, record the approved tool or environment, the human accountable for the output, and any required provenance record. Keep the raw prompt outside the pull request unless policy and data handling rules make its retention appropriate. Code must still meet the same tests and reviews.

Pull-request admission

Admission is the point to stop an incomplete change before a reviewer opens twenty files. A bot or repository rule can validate the presence of an issue link, problem statement, acceptance criteria, test evidence, risk classification, and required disclosure. It can flag, rather than automatically reject, a large diff, unrelated directories, generated files, lockfile changes, permission changes, infrastructure files, database migrations, or public API modifications. The author then either narrows the pull request or explains the cohesive reason for the wider scope.

Route the pull request using path ownership and risk labels. On GitHub, a CODEOWNERS file identifies people or teams responsible for paths, requests their review when owned paths change, and can be combined with branch protection to require a code-owner approval. GitHub's CODEOWNERS documentation explains the behavior and an important safeguard: protect the ownership file itself, or an unreviewed edit could weaken later routing.

Admission should also identify what kind of change it is. A source-only feature change, a dependency update, a configuration change, and a migration should not all receive the same checklist. Classifying them early decides which CI jobs and reviewers are mandatory. This is better than asking a general reviewer to spot every special case in a noisy diff.

Continuous integration

Use required checks that run from the proposed commit in a clean, reproducible environment. At minimum, run the build, formatting or lint rules, static type checks where the language supports them, and targeted tests for the changed component. Run the relevant integration, contract, migration, or end-to-end tests when the change crosses a boundary. Require checks on the mergeable result when the platform supports it, not only on a branch that may be behind its target. GitHub status checks are designed to report validation such as builds, tests, code scanning, and deployments, and a required check must pass before merge. GitHub status checks notes that a skipped job can report success, so workflow conditions deserve review too.

Test evidence should show behavior, not merely a coverage percentage. A changed authorization rule needs allowed and denied cases. A parser needs malformed and boundary inputs. A fix for a production incident needs a test that would have failed before the fix. When a test is impractical, require the author to say why, state the compensating control, and obtain an explicit reviewer acceptance. Do not let "AI generated the tests" count as an explanation of what they prove.

Run security checks appropriate to the repository. Static application security testing can identify classes of vulnerabilities and coding errors; it cannot understand all business rules. GitHub's code-scanning documentation describes event-triggered scans and support for CodeQL or third-party SARIF-producing tools. GitHub code scanning is one implementation option. Add secret scanning and a policy that blocks real credentials, while providing a documented false-positive path for test fixtures and invalid examples.

Treat dependency changes as a distinct supply-chain decision. Require an explanation for a new direct dependency, a compatible license where relevant, a pinned or locked resolution where the ecosystem supports it, and a review of new transitive packages. A dependency review can surface added, removed, and updated packages and known vulnerabilities in a pull request. GitHub dependency review documents that it can be made a required merge check and configured with vulnerability severity and license policies. A clean result does not prove that a package is maintained, suitable, or free of undisclosed flaws, so the reviewer still evaluates necessity and trust.

Add repository-specific architectural checks when the architecture has real rules. Examples include forbidden imports across layers, prohibition of direct database access outside a data module, dependency-cycle detection, API compatibility tests, infrastructure-policy validation, and migration checks. Use duplication and dead-code tools as review signals, not unquestionable judges. A short duplicated block may be clearer than a premature abstraction; an apparent dead path may be a framework entry point. Require an explanation or an approved suppression, and periodically remove stale suppressions.

Apply performance budgets only where the change can affect a measured resource. Examples are a maximum bundle-size increase, query-count ceiling, p95 latency tolerance in a representative benchmark, memory allocation budget, or startup-time budget. The baseline, workload, hardware, and permitted variance must be documented. Otherwise a performance check creates unstable noise and teaches authors to work around the measurement.

Human review

Review in a deliberate order. First, compare the pull request with the linked problem and acceptance criteria. Next, inspect the changed behavior and its tests, including negative paths and failure handling. Then inspect interfaces, data handling, concurrency, error reporting, observability, migration and rollback effects, and the smallest surrounding context needed to understand the diff. Only after that should the reviewer spend time on naming or style that automation can enforce.

Risk-based review means raising the bar for changes with larger blast radius, not distrusting a particular author. Triggers can include authentication and authorization, payment or money movement, personal or health data, cryptography, production infrastructure, externally reachable endpoints, database migrations, customer-visible contracts, permissions, new dependencies, and incident hotfixes. Require the relevant owner and, where appropriate, security, privacy, operations, or database review. A designated owner should be accountable for the decision, even when a group provides the approvals.

Manual review remains essential. OWASP's Code Review Guide describes manual code review as a component of a secure lifecycle and discusses using review alongside automated scanning. OWASP Code Review Guide is a useful security-focused reference. It does not make two reviewers a mathematical guarantee. Reviewers can miss defects, so the purpose of redundancy is to reduce uncertainty in a risk-aware process.

Example gate for a high-risk service

Consider a pull request that changes an authorization check in a service that returns customer account data. The desired outcome is clear: a caller may read only accounts in the caller's organization, and an administrator's existing access remains unchanged. This is high risk because an error could disclose personal or financial information across tenants.

At admission, require the linked security or product issue, explicit allowed and denied acceptance criteria, a data-classification label, a rollback plan, and a scope explanation for every affected service, policy, and test file. If organizational policy requires disclosure, the author records AI assistance and confirms human review. The pull request cannot enter the normal review queue while this evidence is missing. A large generated refactor is split from the narrow authorization fix unless there is a documented reason it must be atomic.

Its required CI checks should build the service; run type, lint, and unit tests; run integration tests with callers from the same and a different organization; test malformed and missing identities; scan source and dependencies; check the database or policy migration if one exists; and validate the relevant API contract. If the service has a latency or query budget, run the representative performance test. Test results should be attached or linked so a reviewer can see what behavior was exercised, not merely a green aggregate.

Before merge, require approval from the service owner and a security-qualified reviewer, with a fresh approval after the final code push. The reviewers verify that the authorization decision is made at the intended layer, cannot be bypassed through another endpoint, uses the correct tenant identity, produces safe audit information, and has a workable rollback or feature-flag path. The accountable release owner confirms post-deployment monitoring for denial spikes and cross-tenant access alerts. An emergency path may reduce elapsed time, but it must not erase accountability.

The admission path is a loop: issue and acceptance criteria, author self-check, evidence-completeness decision, risk classification and owner routing, required CI evidence, risk-matched human review, accountable approval, then merge and observe. A missing artifact, failed test, changed scope, or reviewer finding returns the pull request to the author with a specific missing piece of evidence. Enough green badges never compensate for an unreviewed authorization decision.

Avoiding noisy or unfair gates

Every automated gate has false positives and false negatives. Begin with rules that have a clear, high-severity meaning: a failing build, a reproducible test failure, a committed credential, a known vulnerable dependency above the team's defined threshold, or a forbidden production permission. Make these blocking once their reliability is established. For lower-confidence signals such as duplication, style complexity, broad diff, generated-code detection, or speculative static-analysis findings, start by warning, explaining, and collecting data. Promote a rule to a blocker only if the team can give authors a fast, fair way to fix or suppress a demonstrably wrong result.

Suppression should be explicit and reviewable. Ask for the rule identifier, a short justification, an owner, and an expiry or follow-up issue when practical. Do not let a comment such as "false positive" become permanent configuration. If a scanner is chronically noisy, tune or remove it. A control that reviewers routinely ignore trains the same shallow approval behavior that the process is meant to prevent.

Emergency overrides are legitimate for an outage, active security incident, or other time-critical harm, but must be narrow. Define who may approve the override, which checks may be bypassed, the reason and expiration, how the change will be monitored, and the deadline for backfilling skipped tests and review. Log the exception in the pull request or incident record. A break-glass path that bypasses every guard indefinitely is not an emergency control.

Provenance and traceability

There are two useful kinds of provenance. Change provenance links the issue, author, reviewers, risk decision, CI runs, dependencies, and release. Build provenance links a released artifact to the source commit and build process. Neither says that the code is good, but both allow a team to investigate, reproduce, and audit a decision later.

For released binaries, packages, or container images, use signed build attestations where the platform and risk justify them, then verify them at the consuming or release boundary. GitHub describes artifact attestations as cryptographically signed build-provenance claims and warns that they are not themselves a guarantee of secure software. GitHub artifact attestations makes the important distinction. SLSA likewise treats provenance as progressively stronger information about what built an artifact, its inputs, and the protection of that process. SLSA specification provides the current framework.

Do not confuse this provenance with an AI detector. A signed build can prove where an artifact came from, and a review record can prove who accepted the risk. Neither can determine whether a model drafted a function. If a policy requires AI-use records, store them with appropriate access controls and retention, and keep the merge gate focused on the code's demonstrated behavior.

Metrics for code quality and review effort

Avoid individual leaderboards for pull requests opened, lines changed, review comments, or time-to-approval. They reward splitting work mechanically, writing volume, rubber-stamping, or avoiding difficult changes. Instead, review trends at team and service level, segmented by change risk and type so a routine documentation update is not compared with a data migration.

  • Percentage of pull requests admitted with complete acceptance criteria, test evidence, and risk classification. A rising value shows that readiness is moving upstream.
  • Time from review-ready to merge, paired with rework cycles and reviewer waiting time. Faster is useful only when rework and defects do not rise.
  • CI reliability, including flaky-job rate, median feedback time, and the share of failures the author resolves before requesting review again. Slow or flaky CI shifts work back onto reviewers.
  • Escaped defects, rollbacks, incidents, security findings, and customer-impacting regressions attributed to recently changed components. Review these as learning signals, not blame scores.
  • Rate and age of policy suppressions, emergency overrides, oversized-diff exceptions, and stale ownership entries. These show where the process or architecture needs attention.
  • Review coverage for high-risk changes, including whether the required domain owner and security or operations reviewer participated when triggered.

Read these measures together. A lower merge time combined with more rollbacks is not improvement. A temporary increase in returned pull requests after introducing admission checks may be healthy if it prevents reviewers from performing author work and later reduces rework.

Introduce the checks gradually

Start with a small baseline: a pull-request template, required build and tests, one or two reliable security or dependency checks, and code-owner routing for the most sensitive paths. Publish examples of a good description, a good risk statement, and an acceptable exception. Assign a maintainer to resolve unclear rules quickly. The goal is a quick feedback loop before reviewer time is consumed.

After a few weeks, inspect which fields are routinely useful, which checks are flaky, how often exceptions occur, and which reviewers are overloaded. Add architecture, performance, provenance, or stronger approval controls only where the observed risk justifies them. Protect the main branch so the rules cannot be casually bypassed, and ensure approvals are refreshed after meaningful changes. This approach makes the gate stricter through evidence, not through suspicion of colleagues who use AI tools.

Evidence

Sources used for this answer.

Question signals show what people need. Primary documentation supports the answer. Both remain visible.

  1. 01
    Can you prevent AI Workslop as soon as you receive a Pull Request?Stack Overflow · question signal · checked 4 Sept 2026
  2. 02
    NIST SP 800-218csrc.nist.gov · primary evidence · checked 4 Sept 2026
  3. 03
    GitHub protected branchesdocs.github.com · implementation guidance · checked 4 Sept 2026
  4. 04
    GitHub's CODEOWNERS documentationdocs.github.com · implementation guidance · checked 4 Sept 2026
  5. 05
    GitHub status checksdocs.github.com · implementation guidance · checked 4 Sept 2026
  6. 06
    GitHub code scanningdocs.github.com · implementation guidance · checked 4 Sept 2026
  7. 07
    GitHub dependency reviewdocs.github.com · implementation guidance · checked 4 Sept 2026
  8. 08
    OWASP Code Review Guideowasp.org · primary evidence · checked 4 Sept 2026
  9. 09
    GitHub artifact attestationsdocs.github.com · implementation guidance · checked 4 Sept 2026
  10. 10
    SLSA specificationslsa.dev · primary evidence · checked 4 Sept 2026