Skip to content

[Bug] Merge-gate PR extractor grabs 2 from 2>&1 redirect when the PR arg is a shell variable #568

@rafik-wahid-cubeish

Description

@rafik-wahid-cubeish

Affected

.claude/hooks/_lib-extract-pr.shextract_pr_number() (used by block-unreviewed-merge.sh, require-design-review-for-ui.sh, require-architecture-review.sh, block-merge-on-red-ci.sh)

Given / When / Then

Given an approved PR (#27) with valid Rex + design + CEO markers at HEAD
When the merge is run as gh pr merge $PR --repo "$REPO" --squash --delete-branch 2>&1 | tail -5 (PR number passed via an unexpanded shell variable, with a 2>&1 stderr redirect)
Then the gate blocks claiming "PR #2 has no recorded code-reviewer approval" and looks for …__2-rex.approved — expected: it should resolve PR #27 (or fail safe to the gh pr view fallback), not silently target a different PR number scraped from the redirect.

Repro

  1. On a branch whose open PR is, say, docs(#19): full rule-audit table at docs/rule-audit.md #27, with all approval markers present.
  2. Run: PR=27; gh pr merge $PR --repo <project-repo> --squash --delete-branch 2>&1 | tail -5
  3. The hook receives the literal string gh pr merge $PR … 2>&1 | tail -5. Step 2 of extract_pr_number matches gh pr merge up to the first | (span [^|;&]* includes 2>&1), then grep -oE '[0-9]+' | head -1 returns 2.
  4. Gate blocks on PR [P2] Dogfood: add .github/workflows/ to apexstack itself #2's (nonexistent) markers. Workaround: use a literal PR number and drop 2>&1gh pr merge 27 --repo <project-repo> --squash --delete-branch.

Framework version

v2.3.0

Severity

major (wrong result — blocks the correct merge / could mis-target another PR; trivial workaround exists)

Notes

Two compounding causes: (1) the extractor parses the raw command string, so a $VAR PR arg is never the real number; (2) when no bare integer follows merge, the [^|;&]* span greedily catches the 2 in 2>&1. Suggested fix: strip redirection tokens ([0-9]*>&?[0-9]*, &>, >>) from the span before number extraction, and/or when the first post-merge token isn't a bare integer, fall through to the step-3 gh pr view fallback instead of returning a stray digit. A test case with a 2>&1 redirect + variable PR arg would lock the regression.

Glossary

Term Definition
Merge gate PreToolUse hooks that block gh pr merge until required approval markers exist at the PR HEAD.
PR extractor extract_pr_number() in _lib-extract-pr.sh — parses the PR number from the merge command string.
Stderr redirect (2>&1) Shell syntax sending file descriptor 2 (stderr) to fd 1 (stdout); the 2 is a fd number, not a PR number.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions