Skip to content

fix(gateway): keep live chat assistant buffer tail truncation UTF-16 safe#102484

Merged
steipete merged 2 commits into
openclaw:mainfrom
wings1029:fix/utf16-safe-live-chat-buffer-tail
Jul 9, 2026
Merged

fix(gateway): keep live chat assistant buffer tail truncation UTF-16 safe#102484
steipete merged 2 commits into
openclaw:mainfrom
wings1029:fix/utf16-safe-live-chat-buffer-tail

Conversation

@wings1029

Copy link
Copy Markdown
Contributor

What Problem This Solves

capLiveAssistantBuffer() in live-chat-projector.ts uses text.slice(-MAX_LIVE_CHAT_BUFFER_CHARS) for tail truncation of the assistant live chat buffer. A negative slice can split a surrogate pair at the leading edge, causing the 500,000-character live buffer to start with a broken character.

Why This Change Was Made

This is the only remaining negative-slice tail truncation in src/gateway/ that is not surrogate-safe. It now uses sliceUtf16Safe() from @openclaw/normalization-core/utf16-slice, which adjusts the slice boundary to avoid splitting surrogate pairs.

Unlike the other truncation fixes (which use truncateUtf16Safe for positive-index prefix truncation), this one requires sliceUtf16Safe with a negative start index to preserve the tail behavior.

User Impact

  • Live chat buffer display keeps emoji intact at the leading tail boundary
  • No behavior change for ASCII text

Evidence

  • 4 new test cases in live-chat-projector.test.ts (new file, tests previously untested function)
  • Existing test suites continue to pass

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS labels Jul 9, 2026
@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 9, 2026, 3:30 AM ET / 07:30 UTC.

Summary
The branch changes gateway live chat assistant buffer tail truncation to use sliceUtf16Safe and adds a merge-path regression test for the UTF-16 surrogate boundary.

PR surface: Source +1, Tests +11. Total +12 across 2 files.

Reproducibility: yes. Current main's raw negative slice can start the retained live chat tail with low surrogate 0xde80, and the focused Node probe confirms the current PR test shape reproduces that boundary.

Review metrics: none identified.

Root-cause cluster
Relationship: canonical
Canonical: #102484
Summary: This PR is the canonical visible fix for the gateway live chat assistant buffer tail UTF-16 boundary; the merged UI truncation work is adjacent but does not cover this gateway tail slice.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦞 diamond lobster
Result: blocked until real behavior proof is added.

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

Rank-up moves:

  • [P1] Add redacted after-fix proof for the current head, such as terminal output from the focused gateway merge test or a live gateway/chat transcript showing the boundary behavior.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body and comments still provide tests only, not after-fix real behavior proof such as redacted terminal output, logs, a recording, linked artifact, or live gateway/chat transcript. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The remaining merge blocker is evidentiary: this external PR still lacks redacted real after-fix behavior proof for the current head, and tests/CI alone do not satisfy the contributor proof gate.

Maintainer options:

  1. Decide the mitigation before merge
    Merge the focused gateway fix after redacted real behavior proof is added for the current head, keeping sliceUtf16Safe at the buffer cap and the merge-path boundary regression test.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] No repair lane is needed because the code finding is resolved; the remaining blocker is contributor-supplied real behavior proof before maintainer merge review.

Security
Cleared: The diff uses an existing workspace helper and adds focused tests; it does not change dependencies, workflows, secrets handling, package scripts, or other supply-chain surfaces.

Review details

Best possible solution:

Merge the focused gateway fix after redacted real behavior proof is added for the current head, keeping sliceUtf16Safe at the buffer cap and the merge-path boundary regression test.

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

Yes. Current main's raw negative slice can start the retained live chat tail with low surrogate 0xde80, and the focused Node probe confirms the current PR test shape reproduces that boundary.

Is this the best way to solve the issue?

Yes for the code and test shape. Reusing the existing sliceUtf16Safe helper at the private buffer cap is the narrow maintainable fix, and the follow-up test now exercises the public merge path and exact split boundary.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is a focused gateway display correctness bug with limited blast radius and no security, data-loss, or availability emergency signal.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦞 diamond lobster.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body and comments still provide tests only, not after-fix real behavior proof such as redacted terminal output, logs, a recording, linked artifact, or live gateway/chat transcript. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +1, Tests +11. Total +12 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 1 +1
Tests 1 11 0 +11
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 13 1 +12

What I checked:

  • Current main bug path: Current main still caps the live assistant buffer with raw negative String.prototype.slice, so a retained tail can start inside a surrogate pair. (src/gateway/live-chat-projector.ts:35, 9aa19fef2ff0)
  • Runtime caller path: Gateway assistant stream events flow through resolveMergedAssistantText before emitChatDelta updates live chat buffers, so the cap affects the displayed live assistant text path. (src/gateway/server-chat.ts:800, 9aa19fef2ff0)
  • Helper contract: sliceUtf16Safe normalizes negative starts and advances a start boundary that lands on a low surrogate paired with the previous high surrogate. (packages/normalization-core/src/utf16-slice.ts:16, 9aa19fef2ff0)
  • Export contract: The normalization package already exports the ./utf16-slice subpath used by the PR, so the import is an existing workspace package contract rather than a new dependency surface. (packages/normalization-core/package.json:47, 9aa19fef2ff0)
  • Prior finding fixed: The current PR head deletes the earlier private-helper test and adds a merge-path test whose input overflows by one UTF-16 code unit; current main would start with low surrogate 0xde80, while the helper returns the safe tail. (src/gateway/server-chat.stream-text-merge.test.ts:96, 6c55764fc32b)
  • Source reproduction probe: A read-only Node probe confirmed the old slice(-500000) result begins with low surrogate 0xde80 for the PR's current test shape, and the safe-slice algorithm returns exactly the expected tail.

Likely related people:

  • zw-xysk: Current-main blame shows commit 57db713 added the live chat projector cap and the UTF-16 helper package surface. (role: introduced current behavior and helper path; confidence: high; commits: 57db713ff73f; files: src/gateway/live-chat-projector.ts, src/gateway/server-chat.stream-text-merge.test.ts, packages/normalization-core/src/utf16-slice.ts)
  • steipete: The merged adjacent PR was landed by steipete, and this PR's second commit from steipete moved the regression test to the exported gateway merge path. (role: recent adjacent owner and current fixup author; confidence: high; commits: 57db713ff73f, 6c55764fc32b; files: src/gateway/server-chat.stream-text-merge.test.ts, src/gateway/live-chat-projector.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-09T07:07:37.257Z sha e60d356 :: needs real behavior proof before merge. :: [P2] Make the surrogate-boundary test hit the split point

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 9, 2026
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Land-ready at exact head 6c55764fc32b983fd7014c66b8ff02c5d737c72d.

Review improvements:

  • kept the cap helper private;
  • removed a new helper-only test file whose tail case never exceeded the cap and whose replacement-character assertion could not detect a lone surrogate;
  • added an exact regression to the existing public merge-path suite, with the retained 500,000-unit tail beginning on the low half of an emoji under the old implementation.

Proof:

  • node scripts/run-vitest.mjs src/gateway/server-chat.stream-text-merge.test.ts — 20 tests passed across 2 files.
  • git diff --check passed.
  • Exact-head CI run 29001171916 passed on attempt 2. Attempt 1 had only an infrastructure annotation: the self-hosted check-lint runner lost communication.
  • Fresh exact-head autoreview found no actionable findings at 0.99 confidence.

No known proof gaps.

@steipete
steipete merged commit e5aefd5 into openclaw:main Jul 9, 2026
153 of 154 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…safe (openclaw#102484)

* fix(gateway): keep live chat assistant buffer tail truncation UTF-16 safe

* test(gateway): cover UTF-16 tail cap through merge path

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants