PR Hygiene: The Checks That Belong in Every Pull Request

RedHub AI Editorialupdated October 4, 20265 min read

A reviewer sits back from one huge clamped stack of drawings on her table, a red light spilling across the wall.
Jump to a section6

Four things should stop a pull request before anyone reads it: a leftover merge-conflict marker, a debug statement, a hardcoded secret, and a focused or skipped test. That short list is the core of PR hygiene, and none of it is a style preference. A second group, made up of untracked TODOs, blanket lint suppressions, source changes with no test and oversized diffs, deserves a warning, not a block, so a reviewer sees it without the push being stopped.

TL;DR: Block on conflict markers, debug statements, secrets and focused or skipped tests. Warn on untracked TODOs, blanket eslint-disable lines, source changed with no test, and oversized diffs. Remember that a diff-scoped check only sees the lines you added. The Codex Code-Review & PR-Hygiene Pack ($79) runs all eight with a dependency-free Python gate. For how this fits with human review, read the AI code review guide.

The four checks that block

If any of these is in the diff, the PR is not ready:

  • Leftover merge-conflict markers. A line that starts with seven <, = or > characters means a conflict was never resolved. The file just stopped causing an error.
  • Debug statements. console.log, a bare debugger, breakpoint(), pdb.set_trace(), var_dump or print_r left in committed code means a debugging session never got cleaned up.
  • Hardcoded secrets. API keys, tokens and passwords typed into source. The pack's gate looks for high-signal shapes: AWS key IDs starting AKIA, keys starting sk-, GitHub tokens starting ghp_, private-key headers, and names like api_key or password assigned a long literal. A secret pushed once stays in git history, so the fix ends with rotating the key. Our guide to exposed API keys and secrets walks through it.
  • Focused or skipped tests. A .only, .skip, fdescribe or xit means part of the suite quietly stopped running. CI still reports green while checking less than it claims.

The four checks that warn

These deserve a reviewer's attention, but context can make each one fine, so they should not stop a push on their own:

  • Untracked TODOs. A new TODO or FIXME with no issue number, ticket ID such as ABC-123, or @owner tends to become permanent once merged.
  • Blanket lint suppressions. An eslint-disable that switches a rule off for a whole file hides every future violation in it, not just the one that annoyed someone today.
  • Source changed with no test. Not every change needs a new test. A logic change with no test file anywhere in the diff is still worth a second look.
  • Oversized diffs. A big diff is harder to review carefully. The pack's gate warns past 600 added lines by default, and you can change the number.
Read-only by design: a hygiene check reports a file, a line and a verdict. It should never edit your code or rewrite history on your behalf.

What a diff-scoped check cannot see

A hygiene gate reads the lines you added in this change. That keeps it fast and quiet, and it also means old problems are invisible to it. A key committed last year in a file you did not touch never appears in the current diff. Neither does a key you deleted in this PR, even though it is still sitting in the history.

False positives pull the other way. In a command-line tool, console.log is the output, not leftover debugging. The pack's gate lets you skip a rule with --allow, and its own reference says to use that sparingly and say why. The catch is that a skipped rule is skipped for the whole diff, so one exception for one file turns the check off everywhere in that run. There is no clean answer here. Narrow exceptions take more setup, and broad ones get forgotten.

Where the checks run

  1. Locally, before push. Wire the gate into a pre-push hook so a blocking issue never leaves your machine. See how to gate bad commits before they reach CI.
  2. In CI, as a required check. The same script exits non-zero on BLOCK. GitHub's docs say that once status checks are required on a protected branch, all of them must pass before collaborators can merge.
  3. Next to human review. The gate clears the mechanical issues, so a reviewer's attention goes to logic, design and intent.

None of this is a security audit, and the gate does not judge whether the change is the right one. For validated, whole-repo security analysis, use a dedicated SAST tool such as Snyk or SonarQube.

Run all eight checks on every diff

The Codex Code-Review & PR-Hygiene Pack includes a runnable, dependency-free PR-hygiene gate that returns PASS or BLOCK with file-and-line proof and exits non-zero on BLOCK, plus five skills for PR descriptions, security smells, breaking changes, commits and review comments.

Get the Codex Code-Review & PR-Hygiene Pack — $79

Pairs well with

If the codebase is inherited, not new, the Codex Migration & Refactor Pack ($99) handles framework upgrades, dependency sweeps and dead-code removal, with a verifier that returns SHIP or HOLD. For apps built with AI builders, the Vibe-Coded App Pre-Launch Security Gate ($79) grades six security controls, including secrets kept out of the client bundle and repo, before launch. If your app calls an LLM, the Prompt Regression Lab ($89) applies the same idea to prompts: it diffs a committed baseline and fails CI on any regression.

More in this guide

What are the most important PR hygiene checks?

Leftover merge-conflict markers, debug statements, hardcoded secrets, and focused or skipped tests. Those four are worth treating as hard blockers on every pull request.

Should an oversized diff block a PR?

No. Flag it with a warning. A large diff is harder to review carefully, but it is not automatically wrong, so it should get a reviewer's attention without stopping the push.

Why does a skipped test matter if the suite still runs?

A .only or .skip means CI reports green while checking less than it claims. The suite runs, but part of it has quietly stopped testing anything.

Can a hygiene gate catch every leaked secret?

No. It reads only the lines added in the current diff, so a secret already in the repo, or one deleted in this PR but still in history, never shows up. It catches the new, obvious cases. A repo-wide scan or a SAST tool covers the rest.

Does a hygiene gate need anything installed?

Not necessarily. The pack's gate runs on the Python standard library plus git, so it works in a hook or a CI job without a dependency to install first.

Where should hygiene checks run, locally or in CI?

Both. Run them as a pre-push hook so issues never leave your machine, and again in CI as a required check, so the rules hold for anyone who skipped or never installed the hook.

How it decides
Diagram of the Vibe-Coded App Pre-Launch Security Gate: six weighted controls and a 78/100 score forced to DO NOT SHIP by a missing-authorization gate.

The gate this post refers to, drawn from the tool’s own logic. See the tool.