Skip to content

fix(discord): prevent approval command previews from splitting emoji when truncated#99539

Merged
openclaw-clownfish[bot] merged 1 commit into
openclaw:mainfrom
zhangguiping-xydt:fix/discord-command-preview-unicode
Jul 6, 2026
Merged

fix(discord): prevent approval command previews from splitting emoji when truncated#99539
openclaw-clownfish[bot] merged 1 commit into
openclaw:mainfrom
zhangguiping-xydt:fix/discord-command-preview-unicode

Conversation

@zhangguiping-xydt

@zhangguiping-xydt zhangguiping-xydt commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Related: problem-mode user report; no public issue number

What Problem This Solves

Fixes an issue where Discord approval command previews could split emoji characters when a long command was truncated exactly at an emoji boundary. The broken preview could render a replacement character or a partial emoji instead of preserving readable Discord text.

Why This Change Was Made

Discord approval previews now truncate command text on grapheme boundaries while preserving the existing preview length budget and backtick escaping behavior. The truncation stops as soon as the next grapheme would exceed the budget, so long commands do not need to be expanded into a full character array.

User Impact

Users reviewing long command approvals in Discord will see stable previews that do not contain half emoji, lone surrogate replacement characters, or partial flag emoji when truncation occurs.

Evidence

Base checked: origin/main 0cc9927 still used raw UTF-16 .slice(0, maxChars) for Discord command previews.

Before-fix proof on the old truncation logic:

"aaaa\\ud83d..."
true

After-fix runtime proof through the Discord approval presentation payload:

single emoji boundary keeps budget and appends ellipsis: true
single emoji boundary has lone surrogate escape: false
flag emoji boundary keeps budget and appends ellipsis: true
flag emoji boundary has partial regional indicator: false

Live Discord message rendering proof after this patch:

proof: live Discord message create/read/delete via Discord REST API
channelIdRedacted: xxxxxxxxxxxxxxx0484
messageCount: 2
allCasesPassed: true
single emoji boundary:
  discordMessageCreated: true
  discordMessageFetched: true
  componentTextDisplayFound: true
  oldSliceHadLoneSurrogate: true
  renderedPreviewEqualsExpected: true
  renderedPreviewEndsWithEllipsis: true
  renderedPreviewHasLoneSurrogate: false
  renderedPreviewContainsReplacementCharacter: false
  renderedPreviewContainsSingleEmoji: false
  renderedPreviewContainsFlagEmoji: false
  renderedPreviewLength: 1002
flag emoji boundary:
  discordMessageCreated: true
  discordMessageFetched: true
  componentTextDisplayFound: true
  oldSliceHadLoneSurrogate: true
  renderedPreviewEqualsExpected: true
  renderedPreviewEndsWithEllipsis: true
  renderedPreviewHasLoneSurrogate: false
  renderedPreviewContainsReplacementCharacter: false
  renderedPreviewContainsSingleEmoji: false
  renderedPreviewContainsFlagEmoji: false
  renderedPreviewLength: 1002

The live proof built the approval payload from this branch, posted it as real Discord Components V2 messages in a Discord test channel, fetched each message back from Discord, verified the rendered Command text display contained the expected truncated preview, and deleted the proof messages afterwards.

Regression and changed-file checks:

node scripts/run-vitest.mjs extensions/discord/src/approval-handler.runtime.test.ts
Test Files  1 passed (1)
Tests  2 passed (2)

OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 CI=1 PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false corepack pnpm check:changed -- extensions/discord/src/approval-handler.runtime.ts extensions/discord/src/approval-handler.runtime.test.ts
check:changed passed

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord size: S labels Jul 3, 2026
@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 10:15 AM ET / 14:15 UTC.

Summary
The PR changes Discord approval preview truncation to accumulate grapheme segments before appending ellipsis and adds regression coverage for emoji and flag-emoji boundaries.

PR surface: Source +28, Tests +47. Total +75 across 2 files.

Reproducibility: yes. Source inspection shows current main slices Discord approval command previews by UTF-16 code units, and the PR body includes before/after proof for the exact emoji-boundary failure mode.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/discord/src/approval-handler.runtime.test.ts, vector/embedding metadata: extensions/discord/src/approval-handler.runtime.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • [P2] No repair lane is needed; the remaining action is ordinary maintainer review and exact-head merge gating.

Security
Cleared: The diff only changes local Discord text formatting and a colocated test, with no dependency, workflow, secret, package, install, or code-execution surface.

Review details

Best possible solution:

Merge the focused Discord plugin formatter fix after ordinary maintainer review and exact-head gates remain green.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main slices Discord approval command previews by UTF-16 code units, and the PR body includes before/after proof for the exact emoji-boundary failure mode.

Is this the best way to solve the issue?

Yes. The fix is in the private Discord presentation formatter used by approval payloads, and the shared UTF-16 helper would not preserve multi-code-point graphemes like flags.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against ed5ccda79c8b.

Label changes

Label justifications:

  • P2: This fixes a normal user-visible Discord approval preview bug with limited blast radius.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes after-fix live Discord create/read/delete output for real Components V2 messages, plus focused runtime and changed-file check output.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix live Discord create/read/delete output for real Components V2 messages, plus focused runtime and changed-file check output.
Evidence reviewed

PR surface:

Source +28, Tests +47. Total +75 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 31 3 +28
Tests 1 47 0 +47
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 78 3 +75

What I checked:

Likely related people:

  • gumadeiras: PR metadata and git history show the Discord approval runtime and the raw preview formatter entering with the native approval lifecycle refactor. (role: introduced approval runtime surface; confidence: high; commits: d78512b09d1d; files: extensions/discord/src/approval-handler.runtime.ts, extensions/discord/src/approval-handler.runtime.test.ts)
  • vincentkoc: Git history shows a later Discord/Slack approval runtime seam split and release touch on the same Discord approval runtime files. (role: recent adjacent contributor; confidence: medium; commits: c3d3cf23bcd2, e085fa1a3ffd; files: extensions/discord/src/approval-handler.runtime.ts, extensions/discord/src/approval-handler.runtime.test.ts)
  • steipete: File history shows nearby approval runtime test/refactor work on the same Discord approval area. (role: adjacent approval runtime contributor; confidence: medium; commits: c7347a492ee2, a51488c13ca4; files: extensions/discord/src/approval-handler.runtime.ts, extensions/discord/src/approval-handler.runtime.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jul 3, 2026
@zhangguiping-xydt zhangguiping-xydt changed the title fix: Discord command previews split emoji at truncation boundary fix(discord): command previews split emoji when truncated Jul 3, 2026
@zhangguiping-xydt zhangguiping-xydt changed the title fix(discord): command previews split emoji when truncated fix(discord): prevent approval command previews from splitting emoji when truncated Jul 3, 2026
@openclaw-clownfish
openclaw-clownfish Bot merged commit a13acac into openclaw:main Jul 6, 2026
151 of 160 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant