Skip to content

fix(review): unbreak /review slash command poisoned by \!\` sequence#234

Merged
max-sixty merged 1 commit into
mainfrom
hourly/review-24263944889
Apr 10, 2026
Merged

fix(review): unbreak /review slash command poisoned by \!\` sequence#234
max-sixty merged 1 commit into
mainfrom
hourly/review-24263944889

Conversation

@tend-agent
Copy link
Copy Markdown
Collaborator

Summary

Every /tend-ci-runner:review invocation has been silently broken since PR #217 merged at 2026-04-10 20:07 UTC. PRs #225#233 all received zero reviews from the bot — the review runs report success but the session artifacts show no assistant turn at all. This PR removes the poison and restores reviews.

Root cause

PR #217 (fix(ci-runner): replace if-not polling loop with || to avoid bash escaping) added an explanatory comment inside the CI-polling code block:

# Use `||` rather than `if \!` — the Bash tool escapes `\!` as `\\!`, which
# prevents bash from recognizing the pipeline-negation reserved word...

Claude Code's slash-command preprocessor scans the loaded file for \!` (a prefix that means "execute the next backticked string as a shell command") regardless of markdown code fences. It found \!` inside `if \!`, consumed text through the next backtick, and ran — the Bash tool escapes ` as bash. The em-dash is not a command, so bash reported:

Error: Shell command failed for pattern "\!` — the Bash tool escapes `":
/bin/bash: line 1: —: command not found

When the preprocessor fails, the prompt body is not delivered. Every /review <N> session in this window produced the same 5-line trace — two internal queue-operation messages, the command caveat, the command invocation, the stderr — and then nothing. The model was never given instructions to follow.

Evidence

All tend-review sessions in the past hour's window ran this preprocessor and failed identically:

Run PR Branch Session size Review posted
24261252532 #224 review-runs-timeout-detection ~120 lines ✅ APPROVED (ran before #217 merged at 20:07Z)
24262024783 #225 tend-mention-dedup-review-events 5 lines
24262028666 #226 hourly/review-24261599977 ❌ (checkout failure — infra race, separate issue)
24262305841 #226 hourly/review-24261599977 5 lines
24262406137 #227 raise-job-timeouts 5 lines
24262970448 #228 mention-verify-paginate 5 lines
24262987799 #229 tend-claude-md-workflow-update-note 5 lines
24263043865 #230 raise-job-timeouts 5 lines
24263117206 #231 mention-review-inline-reply-prompt 5 lines
24263177723 #232 raise-job-timeouts 5 lines
24263220447 #233 tend-mention-dedup-review-events 5 lines

Sample JSONL from run 24262987799 (PR #229):

{"type":"queue-operation"}
{"type":"queue-operation"}
{"type":"user","content":"<local-command-caveat>..."}
{"type":"user","content":"<command-name>/review</command-name>\n<command-args>229</command-args>"}
{"type":"user","content":"<local-command-stderr>Error: Shell command failed for pattern \"\!` — the Bash tool escapes `\": [stderr]\n/bin/bash: line 1: —: command not found</local-command-stderr>"}

No assistant turn. No Skill loads. No tool calls. No review.

Confirmation via the target PRs: gh pr view <N> --json reviews returns [] for every one of PRs #225#233. PR #224, reviewed before #217 landed, has the bot's APPROVED review.

The same preprocessor error is also visible in the tend-mention run 24261917519 when it loaded running-in-ci via the Skill tool — there the error appeared as a tool_result and the model continued working, because skill-load failures are non-fatal. Only the top-level slash-command invocation is lethal.

Gate assessment

  • Evidence level: Critical (wrong outcome — reviews 100% non-functional)
  • Classification: Structural (deterministic; every invocation fails the same way)
  • Occurrences this run: 9 (plus 1 non-fatal skill-load collision in tend-mention)
  • Historical evidence: N/A — this regression was introduced by fix(ci-runner): replace if-not polling loop with || to avoid bash escaping #217 earlier today and has no prior tracking entries
  • Change type: Targeted fix (two-line comment rephrase in two files)
  • Both gates: pass

Fix

Rephrase the comments in plugins/tend-ci-runner/skills/review/SKILL.md:294 and plugins/tend-ci-runner/skills/running-in-ci/SKILL.md:142 to avoid any \!` sequence. The guidance content is unchanged: "Use || rather than if-based negation; the Bash tool escapes the exclamation mark to a literal backslash-exclamation." No \! now appears adjacent to a backtick anywhere in plugins/.

grep '\!\' plugins/` after the fix returns zero matches.

Test plan

  • A tend-review run on this PR completes with an assistant session longer than 5 lines and posts an actual review (self-approval blocked, but the bot must at least read the diff and comment)
  • grep -r '\!\' plugins/` returns no matches
  • tend-mention and tend-notifications skill loads of running-in-ci no longer show Shell command failed for pattern in tool_results

🤖 Generated with Claude Code

PR #217 added a code-comment explaining the `||` vs `if \!` workaround,
but the comment itself contained `` `if \!` ``. Claude Code's slash-command
preprocessor scans the file for `` \!` `` (exec-command prefix) regardless of
markdown code fences, extracts the text up to the next backtick as a shell
command, and runs it. The extracted command was `` — the Bash tool escapes `,
which bash fails to parse (`—: command not found`), and the preprocessor
delivered an empty prompt body to Claude. Every `/review <N>` invocation
since the merge of PR #217 produced a 5-line session with no assistant
turn and no review posted — PRs #225#233 all received zero reviews from
the bot.

Rephrase the comment in both `review/SKILL.md` and `running-in-ci/SKILL.md`
to avoid the `` \!` `` sequence entirely. The guidance is unchanged; the
text no longer trips the slash-command preprocessor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tend-agent tend-agent added the claude-behavior Behavioral issues found by review-reviewers label Apr 10, 2026
@max-sixty max-sixty merged commit dc67f6f into main Apr 10, 2026
3 checks passed
@max-sixty max-sixty deleted the hourly/review-24263944889 branch April 10, 2026 21:33
tend-agent pushed a commit that referenced this pull request Apr 11, 2026
…ents

PR #226 rewrote the CI-polling code block in `running-in-ci/SKILL.md`
and `review/SKILL.md` to include the comment `# Use \`||\` rather than
\`if \!\` — the Bash tool escapes \`\!\` as \`\\!\``, re-introducing the
exact \\!\` sequence that PR #234 fixed on 2026-04-10. Claude Code's
slash-command preprocessor treats \\!\` as "execute the next backticked
string as a shell command", consumes text through the next backtick,
and runs ` — the Bash tool escapes ` as bash. The em-dash is not a
command, so bash reports:

    Error: Shell command failed for pattern "\!\` — the Bash tool escapes \`":
    /bin/bash: line 1: —: command not found

When the preprocessor fails, the prompt body is not delivered. Every
/review invocation produces the same 5-line trace with no assistant
turn — the model never sees the review instructions.

Evidence from the past hour on max-sixty/worktrunk:

- Run 24287041911 — tend-review on PR #2077 (fix/issue-2075), 16:49Z.
  Session artifact is 5 lines, ends with the stderr above. No review
  posted.
- Run 24287289871 — tend-review on PR #2077, 17:03Z. Same 5-line
  trace, same stderr, no review posted.

Both target the same PR because the bot pushed a commit that retriggered
pull_request_target; the PR currently has zero bot reviews despite two
review-workflow runs. Earlier review runs in the hour (24281048388 at
11:00Z, 24280957116 at 10:54Z) succeeded, which dates the regression to
the 76debaf merge that shipped PR #226.

Fix: rephrase both comments to avoid any \\!\` sequence, matching the
approach used in PR #234. The guidance content is preserved verbatim in
spirit; only the backticks around `if \!` and `\!` are dropped.

After the fix, `grep -rn '\!\`' plugins/` returns no matches.

Gate assessment:

- Evidence level: Critical (clearly wrong outcome — 100% of reviews on
  the affected PR are empty; also regresses a fix that was already
  shipped as PR #234)
- Classification: Structural — the slash-command preprocessor runs
  deterministically and will fail on every \\!\` sequence regardless of
  the model's approach
- Occurrences this run: 2 on the same PR (same mechanism as #234)
- Change type: Targeted fix (3 lines per file, 2 files)
- Both gates pass
tend-agent pushed a commit that referenced this pull request Apr 11, 2026
…ression

PR #226 (`fix(ci-runner): filter CI polling by run URL, not workflow name`)
reintroduced the exact poisoned-text regression that PR #234 fixed. Its diff
on plugins/tend-ci-runner/skills/review/SKILL.md and
plugins/tend-ci-runner/skills/running-in-ci/SKILL.md reverted the CI-polling
comment from the PR #234 wording back to the pre-#234 wording containing
`` `if \!` ``, which the slash-command preprocessor scans and exec's as bash.

Since #226 merged at 2026-04-11 15:01:22 UTC, every `/review` invocation has
failed identically with the 5-line trace: queue/dequeue, command-caveat,
command-name, local-command-stderr, then nothing. Three tend-review runs in
this hour's window (PRs #240, #241, #242) all produced that exact trace and
posted zero reviews.

Rephrase the CI-polling comment in both files to avoid any `\!` adjacent to a
backtick. The guidance is unchanged. Matches the wording that PR #234 already
merged successfully — this is a straight restoration of that fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tend-agent pushed a commit that referenced this pull request Apr 11, 2026
…ents

PR #226 rewrote the CI-polling code block in `running-in-ci/SKILL.md`
and `review/SKILL.md` to include the comment `# Use \`||\` rather than
\`if \!\` — the Bash tool escapes \`\!\` as \`\\!\``, re-introducing the
exact \\!\` sequence that PR #234 fixed on 2026-04-10. Claude Code's
slash-command preprocessor treats \\!\` as "execute the next backticked
string as a shell command", consumes text through the next backtick,
and runs ` — the Bash tool escapes ` as bash. The em-dash is not a
command, so bash reports:

    Error: Shell command failed for pattern "\!\` — the Bash tool escapes \`":
    /bin/bash: line 1: —: command not found

When the preprocessor fails, the prompt body is not delivered. Every
/review invocation produces the same 5-line trace with no assistant
turn — the model never sees the review instructions.

Evidence from the past hour on max-sixty/worktrunk:

- Run 24287041911 — tend-review on PR #2077 (fix/issue-2075), 16:49Z.
  Session artifact is 5 lines, ends with the stderr above. No review
  posted.
- Run 24287289871 — tend-review on PR #2077, 17:03Z. Same 5-line
  trace, same stderr, no review posted.

Both target the same PR because the bot pushed a commit that retriggered
pull_request_target; the PR currently has zero bot reviews despite two
review-workflow runs. Earlier review runs in the hour (24281048388 at
11:00Z, 24280957116 at 10:54Z) succeeded, which dates the regression to
the 76debaf merge that shipped PR #226.

Fix: rephrase both comments to avoid any \\!\` sequence, matching the
approach used in PR #234. The guidance content is preserved verbatim in
spirit; only the backticks around `if \!` and `\!` are dropped.

After the fix, `grep -rn '\!\`' plugins/` returns no matches.

Gate assessment:

- Evidence level: Critical (clearly wrong outcome — 100% of reviews on
  the affected PR are empty; also regresses a fix that was already
  shipped as PR #234)
- Classification: Structural — the slash-command preprocessor runs
  deterministically and will fail on every \\!\` sequence regardless of
  the model's approach
- Occurrences this run: 2 on the same PR (same mechanism as #234)
- Change type: Targeted fix (3 lines per file, 2 files)
- Both gates pass
tend-agent pushed a commit that referenced this pull request Apr 11, 2026
…v vars

tend-triage run 24286871206 (2026-04-11 16:40Z) on max-sixty/worktrunk
issue #2076 posted a comment with two visible rendering failures that
both originate in a single `cat > /tmp/comment.md << 'EOF'` heredoc:

1. The literal string "${GITHUB_REPOSITORY}" appears in three markdown
   links (e.g.
   https://github.com/${GITHUB_REPOSITORY}/blob/.../reference/config.md#L136-L141).
   The single-quoted heredoc disabled variable expansion, so the env
   var never interpolated.
2. The greeting "Thanks for the suggestion\!" renders as "Thanks for the
   suggestion\\!" — the Bash tool pre-escapes every `\!` to `\\!` before
   bash sees the heredoc, which makes the quoting mode irrelevant (both
   `<< 'EOF'` and `<<EOF` produce `\\!`).

The bot never verified the posted output, declared the task complete,
and the broken comment is still live on worktrunk#2076 as of this
commit (comment id 4229779789).

The prior `\!`-escape-in-comment-heredoc occurrence was recorded as
below-threshold in run 24281303125 (2026-04-11 11:55Z), where the
review bot wrote `if \!is_builtin` inside an inline-suggestion heredoc,
noticed the escaped `\\!` via a post-write verify, and recovered by
rewriting the comment via python3. That tracking entry's explicit
follow-up condition was "If this surface produces a second occurrence,
promote to a one-paragraph addition in running-in-ci/SKILL.md under
the existing \!-escape paragraph." Run 24286871206 is that second
occurrence, and it's worse: the bot did not recover, and the broken
artifact is public.

Extending the GitHub URLs paragraph in running-in-ci is the narrow
targeted fix the prior finding pointed to. The new prose explicitly
tells the bot to:

- Scan for literal `${GITHUB_REPOSITORY}` in the rendered comment, and
  rewrite heredocs as unquoted `<<EOF` or use the Write tool instead.
- Use the Write tool for any comment body containing an exclamation
  mark, because the Bash tool rewrites `\!` to `\\!` regardless of the
  heredoc quoting mode.

The new paragraph is carefully written to contain no `` \!` `` sequence
so it can't trip the slash-command preprocessor (the same footgun
PR #234 and the sibling PR #243 in this hour's cycle both address).
Verified with `grep -rn '\!\`' plugins/` returning zero matches.

This branch also carries PR #243's comment-rewrite on line 147 as a
dependency so that `/review` can actually run on this PR without
hitting the preprocessor error. If PR #243 merges first, the merge
of this branch is a no-op on those lines.

Gate assessment:

- Evidence level: High — structural, 2 occurrences in the same surface
  (heredoc-write comment body), second occurrence produced a live
  public broken artifact.
- Classification: Structural — the Bash tool's `\!`-escape is
  deterministic; single-quoted heredocs are standard bash semantics.
  The bot has no decision point that would produce different behavior.
- Change type: Targeted fix (two-sentence addition to an existing
  paragraph).
- Both gates pass.
tend-agent pushed a commit that referenced this pull request Apr 11, 2026
The Claude Code slash-command preprocessor treats a backtick-enclosed
token beginning with an exclamation mark as shell command substitution.
Any plugin skill file loaded by /review (or another slash command) that
contains this sequence crashes the session before the assistant turn
runs. The pattern has regressed twice already: PR #217 introduced it,
PR #234 removed it, PR #226 reintroduced it, PR #243 removed it again.
Each regression broke 100% of tend-review runs until the next fix
merged.

Add a local pre-commit hook that rejects the pattern at commit time.
The check constructs its search string as chr(33)+chr(96) so the hook
file itself is safe from the pattern it is searching for.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
max-sixty added a commit that referenced this pull request Apr 19, 2026
The Bash tool no longer rewrites exclamation marks to backslash-bang in
heredocs. Verified: both `<<EOF` and `<< 'EOF'` now pass `!` through
unchanged. Drop the guidance to use Write + `--body-file` for comment
bodies containing `!`, and drop "unescaped bangs" from the bot-comment
corruption signals.

The `${GITHUB_REPOSITORY}` heredoc-quoting guidance stays (that's bash
semantics, not a Claude Code bug), as does the bang-backtick pre-commit
guard (separate slash-command preprocessor issue, #234/#243/#244).

Co-Authored-By: Claude <noreply@anthropic.com>
max-sixty added a commit that referenced this pull request Apr 19, 2026
The Bash tool no longer rewrites exclamation marks to backslash-bang in
heredocs. Verified locally — both `<<EOF` and `<< 'EOF'` now pass `!`
through unchanged.

Changes:
- `running-in-ci`: drop the paragraph telling agents to use the Write
tool + `--body-file` for comment bodies containing `!`. Heredocs with
`gh ... --body` work fine again.
- `review-reviewers`: drop "unescaped bangs" from the bot-comment
corruption signals — no longer a thing to watch for.

Kept intentionally:
- The `${GITHUB_REPOSITORY}` heredoc-quoting warning (bash semantics
around single-quoted heredocs, not a Claude Code bug).
- The `.pre-commit-config.yaml` bang-backtick guard — that's a separate
slash-command preprocessor issue (#234/#243/#244), not the heredoc bug.

> _This was written by Claude Code on behalf of @max-sixty_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-behavior Behavioral issues found by review-reviewers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants