docs(agents): record the search qualifier-token hazard beside the channel-control rule - #7452
Merged
Merged
Conversation
…nnel-control rule MCP `search_issues` pastes query text verbatim into GitHub search `q=`, so a bare word-colon-word token in pasted issue text is parsed as a qualifier, ANDed with the rest, and returns a silent zero. This repo's component keys have that shape, so ~10% of its titles carry one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aCUUSwWefnbCJ4Xk1vqQW
os-zhuang
approved these changes
Sep 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7185
Option B of that card diagnosed why MCP
search_issuesreturns a silenttotal_count 0for an issueissue_readreturns. This lands the documentation half the seat decided on: one clause, beside the channel-control rule that PR #7317 put in section 9's instrument-discipline area. The two rules are the same subject one level apart, so they belong together.The card's own standing instruction — do not close it on the mitigation alone without recording which cause the diagnosis found — is satisfied: the cause is recorded on the card, so the closing line above is the one the seat ruled for.
What changed
AGENTS.mdonly. Net +1 line (2 insertions, 1 deletion) — one now-stale bullet is replaced by two.search_issuespastes the caller's query text verbatim into GitHub searchq=, so GitHub's qualifier parser is live inside what the seat believes is free text. A bare word-colon-word token in pasted issue text is parsed as a search qualifier, ANDed with the rest of the query, matches nothing, and returns a silent zero.The evidence the clause carries
total_countresolve record:quick_actions doesIdentical words, identical order. The only difference is a pair of backticks.
Qualifiers are genuinely applied, not merely mishandled:
state:open action-id lookupreturns 0 whilestate:closed action-id lookupreturns 2, and both target issues are closed — so that zero is a correct filter, which is what proves the parse is real.Why this repository is unusually exposed: its component keys are word-colon-word, and 33 of 345 sampled titles (9.6%) carry one. So roughly one in ten near-verbatim title dedupe queries here is silently zeroed — a standing failure rate on the dedupe step every seat runs before filing.
The clause also records the two boundaries that keep it from over-reading: deliberate qualifiers (
in:title,state:closed) are honoured and remain useful, so the hazard is only the accidental ones; and this does not retire the control requirement — an empty result still always needs a known-must-hit control.The replaced bullet's ruled-out line keeps one correction worth not re-deriving: the unauthenticated REST search 403 seen in these containers is not from GitHub. It is the container's own egress proxy enforcing a repository-scoped path allowlist, and it says nothing about GitHub's search scope. It was briefly cited as scope evidence precisely because a status code was read without its body.
Scope
AGENTS.md. No.claude/, noskills/, nodocs/adr/, noCLAUDE.md, no scripts, and nothing undercontent/docs/releases/.⛔ Governed surface
AGENTS.mdis a governed surface. This PR is a DRAFT and stays draft — it has not been flipped ready, not enqueued, and auto-merge has not been armed. A human merge is the review record.node scripts/check-governed-queue-guard.mjs --test AGENTS.mdexits 3, which is the correct verdict for a governed-path PR, not a failure to fix. It names the authorized approvers itself, and both are requested on this PR.Gates
All run on the final commit
920c9ba87, working tree clean, every exit code captured by redirect before any pipe.pnpm docs:check-linksAGENTS.mdfrom diskpnpm check:control-bytespnpm check:shell-escape-residueAGENTS.md: 1 file, 15 fencespnpm check:governed-queue-guard(self-test)check-governed-queue-guard.mjs --test AGENTS.mdcheck-changeset-presence.mjsAGENTS.mdfrom diskThe gate set was re-derived on current
mainrather than taken from the dispatch list: every script underscripts/whereAGENTS.mdappears as a data path rather than an error string, plus the suites that resolve the repo-root file.🤖 Generated with Claude Code
https://claude.ai/code/session_019aCUUSwWefnbCJ4Xk1vqQW
Generated by Claude Code