Reproduced first-hand, twice, in one session
block-noncanonical-commit.sh blocks PowerShell commands that contain no git commit at all,
when the command carries {} or () grouping. Both of these were blocked while driving PR merges:
BLOCKED: this PowerShell git command cannot be parsed with confidence — blocked (fail-closed).
Remove the obfuscating construct (backtick, --%, subexpression, or {}/() grouping).
The commands that tripped it:
git fetch origin --prune 2>&1 | Select-Object -Last 5; git rev-list --left-right --count A...B; git merge-base A B | ForEach-Object { git log --oneline -1 $_ }
$r = ... ; foreach ($t in $p.reviewThreads.nodes) { if (-not $t.isResolved) { ... } }
Neither contains git commit. The second contains no git subcommand the guard cares about at all —
it is a GraphQL result loop that happens to sit in the same pipeline as a git status.
The same shape was independently reported by the L5 lane of the context-engineering pass against
block-no-verify.sh as well, on & 'script.ps1' and Get-ChildItem | ForEach-Object {...}.
Why this is worth fixing rather than living with
The guard is fail-closed by design, which is right for a commit guard. But the fail-closed
branch currently triggers on the presence of a grouping construct anywhere in the command line,
rather than on an unparseable git commit invocation. In PowerShell, {} and () are ordinary
control flow and subexpression syntax — foreach, if, ForEach-Object, $(...) — so the guard
denies a large fraction of legitimate non-commit PowerShell.
The cost is not only friction. A guard that blocks routine commands trains its users to reach for
the other shell to get work done, which is exactly the bypass the guard exists to prevent.
Suggested direction
Gate the fail-closed branch on the command actually containing a git commit invocation
(git commit, git -C … commit, an alias resolving to one) before applying the
unparseable-construct test. A command with no commit in it is out of the guard's stated scope and
should exit 0 regardless of its syntax.
Both guards need the same treatment: block-noncanonical-commit.sh and block-no-verify.sh.
Related
Refs #1403 — the guardrails performance work; PR #1385 explicitly did not address this false
positive, and the fresh-context verification recorded it as "ignored, neither fixed nor worsened".
Reproduced first-hand, twice, in one session
block-noncanonical-commit.shblocks PowerShell commands that contain no git commit at all,when the command carries
{}or()grouping. Both of these were blocked while driving PR merges:The commands that tripped it:
Neither contains
git commit. The second contains no git subcommand the guard cares about at all —it is a GraphQL result loop that happens to sit in the same pipeline as a
git status.The same shape was independently reported by the L5 lane of the context-engineering pass against
block-no-verify.shas well, on& 'script.ps1'andGet-ChildItem | ForEach-Object {...}.Why this is worth fixing rather than living with
The guard is fail-closed by design, which is right for a commit guard. But the fail-closed
branch currently triggers on the presence of a grouping construct anywhere in the command line,
rather than on an unparseable git commit invocation. In PowerShell,
{}and()are ordinarycontrol flow and subexpression syntax —
foreach,if,ForEach-Object,$(...)— so the guarddenies a large fraction of legitimate non-commit PowerShell.
The cost is not only friction. A guard that blocks routine commands trains its users to reach for
the other shell to get work done, which is exactly the bypass the guard exists to prevent.
Suggested direction
Gate the fail-closed branch on the command actually containing a git commit invocation
(
git commit,git -C … commit, an alias resolving to one) before applying theunparseable-construct test. A command with no commit in it is out of the guard's stated scope and
should exit 0 regardless of its syntax.
Both guards need the same treatment:
block-noncanonical-commit.shandblock-no-verify.sh.Related
Refs #1403 — the guardrails performance work; PR #1385 explicitly did not address this false
positive, and the fresh-context verification recorded it as "ignored, neither fixed nor worsened".