Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions tools/test_triage_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,18 @@ def test_tells_the_agent_to_report_a_denial_rather_than_print_findings(self):
completed review in the log. The prompt asks for a denial to be stated plainly."""
self.assertIn("denied", triage_daemon.GH_API_ENDPOINT_FIRST_PROMPT)

def test_closes_the_skills_print_instead_fallback(self):
"""/code-review --comment prefers mcp__github_inline_comment__create_inline_comment, and when
that is missing offers "fall back to gh api ... or print the findings instead". The tool is
never loaded here (--strict-mcp-config), so every review lands on that sentence, and PR
#5283's run took the print branch without ever trying gh api - no denial to report, so the
denial rule above never applied. The prompt must name the tool as absent and make gh api the
required path, with printing allowed only once a gh api call has actually been denied."""
prompt = triage_daemon.GH_API_ENDPOINT_FIRST_PROMPT
self.assertIn("mcp__github_inline_comment__create_inline_comment", prompt)
self.assertIn("never available", prompt)
self.assertIn("not an acceptable substitute", prompt)

def test_steers_comment_bodies_into_a_scratch_file(self):
"""PR #5229's review had its endpoint-first POST denied because the body was an inline
double-quoted argument holding backticks: the shell reads those as command substitution,
Expand Down
10 changes: 9 additions & 1 deletion tools/triage_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,11 @@
# a finished review in the log. It also moves comment bodies into a scratch file: PR #5229's
# POSTs were endpoint-first and still denied, because a double-quoted body holding backticks is
# command substitution to the shell, and the permission check denies the substituted commands
# that no rule allows. Also carries the bot-disclosure requirement for these two flows:
# that no rule allows. It also closes /code-review's own escape hatch: with its preferred
# mcp__github_inline_comment tool missing (never loaded, see --strict-mcp-config), the skill
# says "fall back to gh api ... or print the findings instead", and PR #5283's run (2026-09-28)
# took the print branch without trying gh api at all - nothing was denied, so the denial rule
# alone never fired. Also carries the bot-disclosure requirement for these two flows:
# /code-review's own instructions live in a skill we don't own, so this prompt is the only
# lever available for it; /pr-cleanup's SKILL.md already asks for disclosure directly, and
# this is the belt-and-braces backup for it, same reasoning as the endpoint-first steer.
Expand Down Expand Up @@ -524,6 +528,10 @@
)

GH_API_ENDPOINT_FIRST_PROMPT = (
"The `mcp__github_inline_comment__create_inline_comment` tool is never available in this session, so post every PR comment "
"with `gh api` - that is the required path, not one option among several. Printing the findings instead of posting them is "
"not an acceptable substitute, even where a skill's instructions offer it as a fallback; it is permitted only after a `gh api` "
"call has actually been denied. "
"Permission rules in this session match a literal command prefix, so `gh api` calls are only permitted when the current allowlist covers the exact spelling you use. "
"Prefer the endpoint-first, unquoted form (endpoint immediately after `gh api`) and put flags after the endpoint - for example "
f"`gh api repos/{REPO}/pulls/123/comments --method POST -f path=apps/predbat/example.py -F body=@{SCRATCH_DIR}/comment-1.md`. "
Expand Down
Loading