Skip to content

pr-review: quality-gate false-positives on release/changelog PRs (documented commits live in base, invisible to gh pr diff) #300

Description

@cbeaulieu-gt

Summary

The claude-pr-review quality gate systematically false-BLOCKs release PRs (and any PR whose diff is a CHANGELOG that documents already-merged commits). The review model can't see the commits the changelog describes — they're in the PR's base branch, not in the PR diff — so it concludes the entries are "fabricated" and emits a blocking finding.

Concrete incident

glitchwerks/claude-configs PR #932 (chore(release): v0.18.0). Diff = CHANGELOG.md + pyproject.toml only. The changelog correctly documented 6 commits merged to main since v0.17.0. The review returned:

  • 🔴 Critical — "fabricated CHANGELOG entries" (only #927 is "the single actual change")
  • 🟡 High-Priority — "version should be PATCH not MINOR"
  • Verdict: BLOCK

Both findings were provably wrong: git log v0.17.0..main showed all 6 commits, git tag --contains was empty for each (all unreleased), and four touched agents/**/skills/** (MINOR-triggering). The release was correct; it had to be admin-override-merged.

Root cause

This is a context-scoping gap, not a gate-logic bug. The gate scripts (pr-review/lib/severity-regex.sh, lib/parse-marker.sh) correctly counted a marker the model produced. The defect is upstream in pr-review/action.yml:

  • For opened/reopened PRs the diff instruction is "Use gh pr diff <PR_NUMBER> to retrieve the full PR diff."
  • For a release PR, gh pr diff returns only the changelog + version bump — by definition, because the commits it documents are already in the base branch.
  • The model is handed a changelog claiming N entries but a 2-file diff, with no instruction to validate entries against git log <last-tag>..HEAD. It defaults to "fabricated."

This recurs on every multi-commit release PR.

Chosen fix (option 1): skip / make-advisory the gate for release PRs

Detect a release-shaped PR and do not let the quality gate block it:

  • Detection — PR title matches ^chore\(release\): (the repo's release-commit convention), OR the PR diff touches only changelog/version files (CHANGELOG.md, pyproject.toml, */VERSION, package.json version line).
  • Behavior — skip the claude-pr-review/quality-gate (and shadow) status, or post it as a neutral/success advisory state, so a release PR is never blocked by a finding the review can't substantiate from the diff.

This is the cleanest stop. (Alternatives considered but not chosen: feeding git log $(git describe --tags --abbrev=0)..HEAD into the review context; or a prompt instruction to validate changelog entries against the tag range before flagging fabrication. Either would also work but is more invasive than skipping a gate that has no meaningful diff to review.)

Implementation pointers

  • pr-review/action.yml — the "Resolve diff base" step (~L48–89) and the diff-instruction rendering (~L118–137); add the release-PR short-circuit before the gate steps (~L335–393 authoritative gate, ~L395–534 shadow gate).

Release/propagation note

claude-configs consumes this via uses: glitchwerks/github-actions/.github/workflows/claude-pr-review.yml@v2. The fix won't reach consumers until a v2.x.y is cut and the floating v2 tag is bumped (see #145 / #181 for that process).

Related (distinct root causes)

This issue is specifically the release/changelog-PR diff-context gap.

🤖 Generated by Claude Code on behalf of @cbeaulieu-gt

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions