Skip to content

fix: announcement ordering, UTF-16-safe label cap, base prompt spend list - #3747

Open
Christian-Sidak wants to merge 1 commit into
MCPJam:mainfrom
Christian-Sidak:fix/issue-3705
Open

fix: announcement ordering, UTF-16-safe label cap, base prompt spend list#3747
Christian-Sidak wants to merge 1 commit into
MCPJam:mainfrom
Christian-Sidak:fix/issue-3705

Conversation

@Christian-Sidak

@Christian-Sidak Christian-Sidak commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Three latent issues from the #3696 review, batched:

  • announcementFor ordering (slack-app/listeners/actions/proposal-button.js): the resource-URL check ran before the kind switch, so a future cancel-kind op that also returns a resource would announce "Approved - follow it here" instead of "Cancelled". Fixed by checking kind first; URL is now used only inside the start branch and as a fallback for unrecognised kinds from newer servers.

  • UTF-16-safe button label cap (slack-app/listeners/views/proposal-builder.js): .slice(0, 75) sliced on UTF-16 code units, leaving an unpaired surrogate when an emoji sits at the boundary and causing Slack to reject the whole message. Replaced with capChars(), the code-point-safe helper already in the same file.

  • Base prompt spend enumeration (mcpjam-inspector/server/routes/v1/agent.ts): the frozen list of gated ops omitted the two added after original authoring: setEvalSuiteSchedule ("setting a schedule") and callServerTool ("running a third-party tool"). Updated the literal and the snapshot-pinned copy in agent-op-registry.test.ts.

Test plan

  • Existing announcementFor unit tests still pass (no cancel+url test existed; bug was latent)
  • agent-op-registry.test.ts snapshot updated to match new prompt text
  • Manual: approve a cancel proposal; message says "Cancelled" not "Approved - follow it here"
  • Manual: server-sent label with emoji at char 75 does not cause a 400 from Slack

Fixes #3705

🤖 Generated with Claude Code


Summary by cubic

Fixes cancel announcement ordering, makes Slack button labels code‑point safe, and expands the base prompt spend list to include schedules and third‑party tools; prevents wrong “Approved” messages, avoids Slack 400s on emoji boundaries, and aligns guidance with all gated actions. Fixes #3705.

  • Bug Fixes
    • announcementFor: check kind before resource URLs; cancel proposals now announce “Cancelled”, start still links to the run, and unknown kinds fall back to the URL.
    • proposal-builder: use capChars instead of .slice to cap labels on code points; prevents surrogate splits that cause Slack rejections.
    • agent prompt: add “setting a schedule” and “running a third‑party tool” to the spend list; updated test snapshot to match.

Written for commit e90a923. Summary will update on new commits.

Review in cubic

…list

Three latent issues from the MCPJam#3696 review:

- announcementFor: check kind before resource URL so cancel operations
  with a resource URL announce "Cancelled" rather than "Approved - follow
  it here". URL is now only used inside the start branch and as a fallback
  for unrecognised kinds (newer server).

- buildProposalBlocks: replace .slice(0, MAX_BUTTON_LABEL) with capChars()
  so the button label is capped on code-point boundaries. An emoji at the
  boundary would yield an unpaired surrogate that can make Slack reject the
  whole message.

- AGENT_API_BASE_PROMPT_LINES: add "setting a schedule" and "running a
  third-party tool" to the spend enumeration so the model is told about
  the two gated ops added after the original prompt was written. Snapshot
  in agent-op-registry.test.ts updated to match.

Fixes MCPJam#3705

Signed-off-by: Christian Sidak <christian@sentineltech.eu>
Signed-off-by: Christian-Sidak <61099993+Christian-Sidak@users.noreply.github.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. bug Something isn't working labels Aug 6, 2026
@chelojimenez

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The agent approval guidance now includes schedule changes and third-party tool execution as proposal-only actions. Slack proposal announcements prioritize cancellation messages and use resource URLs for applicable outcomes. Proposal button labels now use Unicode-safe truncation with an ellipsis when they exceed the character limit.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
slack-app/listeners/views/proposal-builder.js (1)

214-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add an emoji-boundary regression test.

The current coverage uses only ASCII text. Add a label with an emoji at the 75-character boundary. Assert that the rendered label remains within 75 code points and contains no unpaired surrogate. This verifies the capChars() behavior instead of only the existing ASCII limit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@slack-app/listeners/views/proposal-builder.js` around lines 214 - 221, Add a
regression test for the label-building flow using an emoji-containing label at
the 75-character boundary. Assert the rendered label is at most 75 Unicode code
points and contains no unpaired surrogate characters, exercising capChars()
rather than only ASCII truncation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mcpjam-inspector/server/routes/v1/agent.ts`:
- Line 651: Correct the shared base prompt wording near the
action-classification text in mcpjam-inspector/server/routes/v1/agent.ts:651-651
so only enabling a schedule is described as recurring quota or credit spending,
while call_server_tool is described as an external action requiring approval;
preserve the instruction that these tools propose actions rather than execute
them. Update the corresponding frozen prompt literal in
mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts:562-562 to
exactly match the production wording.

---

Nitpick comments:
In `@slack-app/listeners/views/proposal-builder.js`:
- Around line 214-221: Add a regression test for the label-building flow using
an emoji-containing label at the 75-character boundary. Assert the rendered
label is at most 75 Unicode code points and contains no unpaired surrogate
characters, exercising capChars() rather than only ASCII truncation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f61c868-5746-43fc-8d1f-95da64842fc1

📥 Commits

Reviewing files that changed from the base of the PR and between 98db5cc and e90a923.

📒 Files selected for processing (4)
  • mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts
  • mcpjam-inspector/server/routes/v1/agent.ts
  • slack-app/listeners/actions/proposal-button.js
  • slack-app/listeners/views/proposal-builder.js

"- Author cases as `steps` arrays; prefer a `prompt` step plus `toolCalledWith`-style assertions on the tools the conversation showed. Set `expectedOutput` when the user stated one.",
`- When creating a suite, set the suite \`model\` explicitly to \`${DEFAULT_SUITE_MODEL}\` unless the user asks for a different model.`,
"- Some actions SPEND the user's quota or credits (running a suite or a case, generating cases, cancelling a run). Calling those tools does NOT perform them: it PROPOSES the action and returns an approval id, and a person must click to confirm. Say that you've proposed it and what it will do. NEVER say it has started, is running, or has been cancelled.",
"- Some actions SPEND the user's quota or credits (running a suite or a case, generating cases, cancelling a run, setting a schedule, running a third-party tool). Calling those tools does NOT perform them: it PROPOSES the action and returns an approval id, and a person must click to confirm. Say that you've proposed it and what it will do. NEVER say it has started, is running, or has been cancelled.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the shared base-prompt classification.

The prompt currently presents call_server_tool as quota spending and treats all schedule changes as spending. The registry shows that call_server_tool is gated for external side effects, while disabling a schedule does not spend quota.

  • mcpjam-inspector/server/routes/v1/agent.ts#L651-L651: Describe only enabling a schedule as recurring spend, and describe call_server_tool as an external action that still requires approval.
  • mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts#L562-L562: Update the frozen prompt literal to match the corrected production wording.
📍 Affects 2 files
  • mcpjam-inspector/server/routes/v1/agent.ts#L651-L651 (this comment)
  • mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts#L562-L562
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mcpjam-inspector/server/routes/v1/agent.ts` at line 651, Correct the shared
base prompt wording near the action-classification text in
mcpjam-inspector/server/routes/v1/agent.ts:651-651 so only enabling a schedule
is described as recurring quota or credit spending, while call_server_tool is
described as an external action requiring approval; preserve the instruction
that these tools propose actions rather than execute them. Update the
corresponding frozen prompt literal in
mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts:562-562 to
exactly match the production wording.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="slack-app/listeners/actions/proposal-button.js">

<violation number="1" location="slack-app/listeners/actions/proposal-button.js:64">
P3: Reordering kind-vs-URL to fix the cancel-with-resource case is correct, but it also silently drops the server-built "follow it here" link for the other known kinds. Before this change the URL was consulted before the switch, so a `generate`, `schedule`, or `external` outcome that carries a resource URL surfaced the link; now the URL is used only for `start` and unknown kinds, so those outcomes lose the deep link even when the server supplied one. Two concrete knock-ons: the JSDoc just above this function still states "A URL wins over the copy when there is one," which no longer matches the implementation, and the characterization-test comment "A URL outranks the copy, whatever the kind" encodes the old semantics. If URL-scoped-to-start is intended, update the doc comment (and re-check whether generate/schedule/external ops are expected to return resource URLs whose links should not regress); otherwise restore the URL handling for those kinds.</violation>
</file>

<file name="mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts">

<violation number="1" location="mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts:562">
P3: The updated base prompt line now lists 'running a third-party tool' alongside quota-spending actions and describes schedule changes generically as spend. If call_server_tool is actually gated for external side effects rather than quota consumption, and only enabling a schedule (not disabling one) creates recurring spend, this wording could mislead the agent/user about what each action actually costs. Consider splitting the description so call_server_tool is described as an external action requiring approval, and only 'enabling' a schedule is called out as spend.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

case 'external':
return `:white_check_mark: Approved by <@${userId}> — the tool ran.`;
case 'start':
if (url) return `:white_check_mark: Approved by <@${userId}> — <${url}|follow it here>.`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Reordering kind-vs-URL to fix the cancel-with-resource case is correct, but it also silently drops the server-built "follow it here" link for the other known kinds. Before this change the URL was consulted before the switch, so a generate, schedule, or external outcome that carries a resource URL surfaced the link; now the URL is used only for start and unknown kinds, so those outcomes lose the deep link even when the server supplied one. Two concrete knock-ons: the JSDoc just above this function still states "A URL wins over the copy when there is one," which no longer matches the implementation, and the characterization-test comment "A URL outranks the copy, whatever the kind" encodes the old semantics. If URL-scoped-to-start is intended, update the doc comment (and re-check whether generate/schedule/external ops are expected to return resource URLs whose links should not regress); otherwise restore the URL handling for those kinds.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At slack-app/listeners/actions/proposal-button.js, line 64:

<comment>Reordering kind-vs-URL to fix the cancel-with-resource case is correct, but it also silently drops the server-built "follow it here" link for the other known kinds. Before this change the URL was consulted before the switch, so a `generate`, `schedule`, or `external` outcome that carries a resource URL surfaced the link; now the URL is used only for `start` and unknown kinds, so those outcomes lose the deep link even when the server supplied one. Two concrete knock-ons: the JSDoc just above this function still states "A URL wins over the copy when there is one," which no longer matches the implementation, and the characterization-test comment "A URL outranks the copy, whatever the kind" encodes the old semantics. If URL-scoped-to-start is intended, update the doc comment (and re-check whether generate/schedule/external ops are expected to return resource URLs whose links should not regress); otherwise restore the URL handling for those kinds.</comment>

<file context>
@@ -60,11 +61,15 @@ export function announcementFor(outcome, userId) {
     case 'external':
       return `:white_check_mark: Approved by <@${userId}> — the tool ran.`;
     case 'start':
+      if (url) return `:white_check_mark: Approved by <@${userId}> — <${url}|follow it here>.`;
       return `:white_check_mark: Approved by <@${userId}>, and it's away.`;
     default:
</file context>

"- Author cases as `steps` arrays; prefer a `prompt` step plus `toolCalledWith`-style assertions on the tools the conversation showed. Set `expectedOutput` when the user stated one.",
"- When creating a suite, set the suite `model` explicitly to `anthropic/claude-haiku-4.5` unless the user asks for a different model.",
"- Some actions SPEND the user's quota or credits (running a suite or a case, generating cases, cancelling a run). Calling those tools does NOT perform them: it PROPOSES the action and returns an approval id, and a person must click to confirm. Say that you've proposed it and what it will do. NEVER say it has started, is running, or has been cancelled.",
"- Some actions SPEND the user's quota or credits (running a suite or a case, generating cases, cancelling a run, setting a schedule, running a third-party tool). Calling those tools does NOT perform them: it PROPOSES the action and returns an approval id, and a person must click to confirm. Say that you've proposed it and what it will do. NEVER say it has started, is running, or has been cancelled.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The updated base prompt line now lists 'running a third-party tool' alongside quota-spending actions and describes schedule changes generically as spend. If call_server_tool is actually gated for external side effects rather than quota consumption, and only enabling a schedule (not disabling one) creates recurring spend, this wording could mislead the agent/user about what each action actually costs. Consider splitting the description so call_server_tool is described as an external action requiring approval, and only 'enabling' a schedule is called out as spend.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At mcpjam-inspector/server/routes/v1/__tests__/agent-op-registry.test.ts, line 562:

<comment>The updated base prompt line now lists 'running a third-party tool' alongside quota-spending actions and describes schedule changes generically as spend. If call_server_tool is actually gated for external side effects rather than quota consumption, and only enabling a schedule (not disabling one) creates recurring spend, this wording could mislead the agent/user about what each action actually costs. Consider splitting the description so call_server_tool is described as an external action requiring approval, and only 'enabling' a schedule is called out as spend.</comment>

<file context>
@@ -559,7 +559,7 @@ const PROMPT_BEFORE_REGISTRY = [
   "- Author cases as `steps` arrays; prefer a `prompt` step plus `toolCalledWith`-style assertions on the tools the conversation showed. Set `expectedOutput` when the user stated one.",
   "- When creating a suite, set the suite `model` explicitly to `anthropic/claude-haiku-4.5` unless the user asks for a different model.",
-  "- Some actions SPEND the user's quota or credits (running a suite or a case, generating cases, cancelling a run). Calling those tools does NOT perform them: it PROPOSES the action and returns an approval id, and a person must click to confirm. Say that you've proposed it and what it will do. NEVER say it has started, is running, or has been cancelled.",
+  "- Some actions SPEND the user's quota or credits (running a suite or a case, generating cases, cancelling a run, setting a schedule, running a third-party tool). Calling those tools does NOT perform them: it PROPOSES the action and returns an approval id, and a person must click to confirm. Say that you've proposed it and what it will do. NEVER say it has started, is running, or has been cancelled.",
   "- If a proposal tool is not available to you, you cannot run anything at all. Say so plainly and report the ids the user needs — do not imply you started something.",
   "- Always report the ids of anything you created.",
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agent/slack polish: announcement ordering for cancel-with-resource, UTF-16-safe label cap, stale spend list in base prompt

2 participants