Two changes, both about the same failure mode: a text tool pointed at a stream that is structured data.
The enforcement hook sees API responses, not just files
-s cgl-style extraction was denied when it named a .json or .yaml file, and silent when the same data arrived over the network. gh api …/git/trees/…, gh pr list --json … and glab api … answer JSON while naming no file, so the check never saw them — while …/contents/pkg.json was covered only because its URL happens to end in .json.
Those list endpoints are exactly what a fleet audit uses, and that is where it cost something: two sweeps over 25 repositories in one week produced wrong tables, one missing what was there, the other matching a prose comment that said the opposite of the key it was reading. Both would have been caught by a parser.
After --jq, -q, or a downstream jq/yq/dasel/mlr/qsv the stream is text again and stays exempt — gh api … --jq '.[].title' | grep -oE '^[A-Z]+' is not the mistake this looks for. The advisory level is unchanged, so an ordinary gh api … | head does not start warning. Found and fixed by @CybotTM while auditing php-cs-fixer config locations across the extension fleet. (#40)
The -q collision is worth knowing if you extend this: gh api accepts -q as the short form of --jq, and grep -q is the exemption the hook leans on most. It is matched only between gh api and the next pipe.
Never merge stderr into a strict JSON parser
@aseemann added the anti-pattern to the jq cookbook after hitting it twice in one session: uv run … 2>&1 | python3 -c "json.load(…)" and glab api … 2>&1 | … both failed with Extra data, because 2>&1 put a package-install banner and a status line ahead of the JSON. A strict parser tolerates no leading bytes. Keep stderr separate from any command whose stdout you intend to parse. (#35)
Known and open
A suppressed repeat of an advisory cannot be told apart from a rule that never matched — the warning fires once per rule per session, so the second occurrence is silent for a reason that looks exactly like a gap. That produced a wrong bug report while this release was being prepared. Tracked in #41.