Skip to content

fix(browser): keep UTF-8 stderr tails valid#102543

Merged
steipete merged 3 commits into
openclaw:mainfrom
qingminglong:codex/fix-browser-utf8-tail-submit
Jul 9, 2026
Merged

fix(browser): keep UTF-8 stderr tails valid#102543
steipete merged 3 commits into
openclaw:mainfrom
qingminglong:codex/fix-browser-utf8-tail-submit

Conversation

@qingminglong

@qingminglong qingminglong commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where users reading browser Chrome launch diagnostics could see Unicode replacement characters when the bounded stderr tail retained only part of a multibyte UTF-8 character.

Why This Change Was Made

The browser plugin already trims leading continuation bytes after byte-bounded truncation. This keeps the same UTF-8 boundary invariant for trailing partial code points by decoding the retained tail with Node's StringDecoder, without changing Chrome launch or stderr collection behavior.

User Impact

Browser startup diagnostics remain valid UTF-8 after byte truncation or split stream chunks, so the displayed stderr tail is cleaner and less misleading.

Evidence

  • Claim proved: the browser bounded UTF-8 stderr tail drops incomplete leading/trailing multibyte code points and still decodes a split code point once the remaining bytes arrive.
  • Current-head proof at f2caf55a2f13dfffdb3dff793a5c05e22c47af45: node scripts/run-vitest.mjs extensions/browser/src/browser/bounded-utf8-tail.test.ts passed (1 file, 6 tests).
  • Chrome MCP stderr diagnostic proof at f2caf55a2f13dfffdb3dff793a5c05e22c47af45: node --import tsx -e "..." called decodeChromeMcpStderrTail with a stderr buffer ending in an incomplete UTF-8 code point and passed with {"decoded":"chrome-mcp stderr tail:","replacementChar":false}.
  • PR diff hygiene: git diff --check upstream/main...HEAD passed.
  • CI proof: CI / build-artifacts passed on f2caf55a2f13dfffdb3dff793a5c05e22c47af45.
  • Review proof: python .agents\skills\autoreview\scripts\autoreview --mode branch --base upstream/main passed with no accepted/actionable findings.
  • Observed result: focused coverage now asserts a one-byte UTF-8 tail decodes to an empty string and a split \u{1f600} byte sequence decodes only after all bytes are appended.

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 5:28 AM ET / 09:28 UTC.

Summary
The PR changes the browser bounded UTF-8 stderr-tail helper to decode with Node StringDecoder and adds tests for trailing partial and split multibyte code points.

PR surface: Source +1, Tests +18. Total +19 across 2 files.

Reproducibility: yes. from source and a focused Node probe: current main decodes the retained tail with Buffer.toString("utf8"), and Node emits the UTF-8 replacement bytes for a retained one-byte prefix. I did not run the repository Vitest in this read-only review.

Review metrics: none identified.

Root-cause cluster
Relationship: canonical
Canonical: #102543
Summary: This PR is the canonical narrow follow-up for trailing partial UTF-8 code points in the bounded browser stderr-tail helper; the merged source PR introduced the helper and overlaps in the same diagnostics surface.

Members:

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

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🦞 diamond lobster
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

  • No ClawSweeper repair is indicated; the patch is narrow, review findings are empty, and the remaining path is normal maintainer merge gating.

Security
Cleared: The diff only adds a Node built-in import and focused tests; it does not change dependencies, lockfiles, workflows, permissions, secrets handling, or executable-source resolution.

Review details

Best possible solution:

Land the narrow shared-helper fix after normal exact-head merge and CI gating, keeping browser diagnostics byte-bounded and valid UTF-8 for both managed Chrome and Chrome MCP stderr consumers.

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

Yes, from source and a focused Node probe: current main decodes the retained tail with Buffer.toString("utf8"), and Node emits the UTF-8 replacement bytes for a retained one-byte prefix. I did not run the repository Vitest in this read-only review.

Is this the best way to solve the issue?

Yes. Using Node StringDecoder at the shared browser-owned tail helper is the narrowest maintainable fix and avoids duplicating UTF-8 boundary handling in the managed Chrome and Chrome MCP callers.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body now includes current-head copied live output from a Node runtime invocation of the changed Chrome MCP stderr diagnostic decoder, plus focused tests and CI; that is sufficient for this helper-level text diagnostic change.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body now includes current-head copied live output from a Node runtime invocation of the changed Chrome MCP stderr diagnostic decoder, plus focused tests and CI; that is sufficient for this helper-level text diagnostic change.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This is a focused browser diagnostics bug fix with limited blast radius and no config, auth, schema, or public API change.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body now includes current-head copied live output from a Node runtime invocation of the changed Chrome MCP stderr diagnostic decoder, plus focused tests and CI; that is sufficient for this helper-level text diagnostic change.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body now includes current-head copied live output from a Node runtime invocation of the changed Chrome MCP stderr diagnostic decoder, plus focused tests and CI; that is sufficient for this helper-level text diagnostic change.
Evidence reviewed

PR surface:

Source +1, Tests +18. Total +19 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 1 +1
Tests 1 18 0 +18
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 20 1 +19

What I checked:

  • Repository policy read: Read the full root and scoped extension policies; their guidance required reviewing the browser plugin boundary, callers, tests, history, and Node dependency behavior rather than only the diff. (AGENTS.md:1, 4ad94febcb31)
  • Current main behavior: Current main trims leading continuation bytes but then decodes the retained tail with Buffer.toString("utf8"), which can emit a replacement character for an incomplete trailing UTF-8 sequence. (extensions/browser/src/browser/bounded-utf8-tail.ts:8, 4ad94febcb31)
  • PR implementation: The patch imports StringDecoder and changes decodeUtf8Tail to omit incomplete trailing multibyte input while preserving the existing leading-continuation trim. (extensions/browser/src/browser/bounded-utf8-tail.ts:2, 806bbc791abc)
  • Focused tests: The PR adds regression coverage for a retained one-byte prefix decoding to an empty string and for a split four-byte code point decoding only after the remaining bytes arrive. (extensions/browser/src/browser/bounded-utf8-tail.test.ts:19, 806bbc791abc)
  • Callers checked: The shared helper feeds managed Chrome launch diagnostics and Chrome MCP stderr draining, so the fix is at the common browser-owned stderr-tail boundary instead of duplicating decode logic in callers. (extensions/browser/src/browser/chrome-mcp.ts:172, 4ad94febcb31)
  • Node dependency contract: Node's built-in StringDecoder.write is documented in the embedded Node source as returning decoded text while omitting incomplete multibyte characters at the end; a local Node 24 probe showed StringDecoder buffering a split four-byte sequence while Buffer.toString("utf8") emitted efbfbd for the one-byte prefix.

Likely related people:

  • steipete: Merged the source browser stderr diagnostics PR and supplied maintainer proof for the shared bounded UTF-8 tail helper path. (role: recent area contributor and merger; confidence: high; commits: a522e4309cbb, 58da2f5897fe; files: extensions/browser/src/browser/bounded-utf8-tail.ts, extensions/browser/src/browser/chrome.ts, extensions/browser/src/browser/chrome-mcp.ts)
  • mikasa0818: Authored the merged source PR that introduced the bounded browser stderr-tail helper and Chrome launch diagnostics integration that this PR follows up. (role: introduced behavior; confidence: high; commits: a522e4309cbb; files: extensions/browser/src/browser/bounded-utf8-tail.ts, extensions/browser/src/browser/chrome.ts, extensions/browser/src/browser/chrome-mcp.ts)
  • vincentkoc: Requested UTF-8-safe stderr-tail handling and split multibyte regression coverage on the merged source PR, which defines this follow-up’s acceptance boundary. (role: reviewer; confidence: medium; files: extensions/browser/src/browser/bounded-utf8-tail.ts, extensions/browser/src/browser/chrome.ts)
  • zhangguiping-xydt: The current checkout's shallow/grafted blame attributes the browser helper lines to merged PR fix(codex): avoid broken emoji in dynamic tool timeout logs #102509, though the browser-specific ownership signal is weaker than the linked source PR history. (role: current-main carrier; confidence: low; commits: b23fdcfac953; files: extensions/browser/src/browser/bounded-utf8-tail.ts, extensions/browser/src/browser/chrome.ts, extensions/browser/src/browser/chrome-mcp.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-09T08:44:17.139Z sha 9d31c13 :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. 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
@qingminglong

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@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. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 9, 2026
@steipete steipete self-assigned this Jul 9, 2026
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Land-ready review complete.

  • Read the shared bounded-tail implementation, both production callers (chrome.ts and chrome-mcp.ts), adjacent caller tests, and Node's StringDecoder.write() contract.

  • Best-fix judgment: the shared decoder boundary is the right owner. It handles a byte-truncated leading sequence and an incomplete trailing sequence without adding persistent decoder state or another storage path.

  • Exact remote proof on Blacksmith Testbox tbx_01kx3497sjkxpktq998rjxa0zh:

    env CI=true corepack pnpm test extensions/browser/src/browser/bounded-utf8-tail.test.ts extensions/browser/src/browser/chrome-mcp.test.ts extensions/browser/src/browser/chrome.internal.test.ts

    Result: 3 files passed, 109 tests passed.

  • Fresh Codex autoreview: clean, no accepted/actionable findings (0.98 confidence).

  • Known gap: no live Chrome subprocess run; the changed invariant is deterministic byte decoding, and both subprocess consumers are covered by caller-level tests.

Proceeding through the repository-native exact-head prepare and merge guards.

@steipete
steipete merged commit c86fe21 into openclaw:main Jul 9, 2026
128 of 136 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

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

Labels

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: XS 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.

2 participants