Repository navigation
Cut task cues, failure text, shares and labels on code points - #2582
Merged
Merged
Conversation
Docs-not-needed: the fix routes existing bounds through code-point cuts and the existing cut() helper; no owned interface, tool, flow or stored shape changes.
Collaborator
Author
|
Verdict: PASS at 670497f Ran at this tip: Red first, on the base blobs at Review points:
|
This was referenced Nov 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Written-by: Dev
Fixes #2581
Owner: Dev
Reviewer: Reviewer
What changed
A bound that ends inside a surrogate pair leaves a lone surrogate: the next UTF-8 encoder writes it as U+FFFD, so a failed step's stored text, a task cue handed to another Bot, a co-seat share, an avatar, a role label and a timeline label could all carry a permanently damaged character. All six places the issue names now cut on a code-point boundary, reusing the existing helpers instead of a second implementation:
core/src/host/task-drive.js—queueCueForandcueForpass the one-lined title throughcut(title, 200)fromcore/src/shared/text-boundary.jsinstead ofslice(0, 200).plugins/workflow/src/graph.js— newcutCodePoints(value, max)(flattens first, budgets characters), the plugin-side counterpart of that helper.plugins/workflow/src/service.js— the failed step'sfailure.text(clipFailureText, 200 characters with the ellipsis).plugins/workflow/client.js—firstGlyphfor the three avatar sites (Mark,PaletteBotFace, the mini-flowchart label) and a code-point count/cut inbotPaletteSubtitle.plugins/social/src/social.js—cutCodePointsfor the co-seat envelope'stext(18 000 characters).plugins/timeline/src/sanitize.js—cleanLabelcuts its default 60 in code points.plugins/social/src/face-rooms.jsis untouched: #2438 / PR #2439 owns it.One decision the issue left to this PR:
cut(text, max)incore/src/shared/text-boundary.jskeeps a UTF-16-unit budget and is not unified withfits. Its callers bound the units a stored field may cost (a capability description at 2 000, the open-page snapshot's address and title, the busy-ack prompt at 600) and those shapes are pinned bycore/test/capabilities.test.js,core/test/browser-channel.test.jsandcore/test/busy-ack.test.js;fitsstays the character judgment for a consumer whose budget is characters (#2321). The difference is written into the comment abovecut(#2581) — only the boundary must never split a pair, and it does not.Red first
Every new test was run against the pre-change source (
origin/main) before the fix; each failed for the reason it exists:core/test/task-drive.test.js—#2581: a title of emoji is cut on a code point boundary in the cue:the cue carries no lone surrogate; false !== true.plugins/workflow/test/code-point-cut.test.js—#2581: a failed step keeps a well-formed text…:the stored failure text is well formed; false !== true.plugins/workflow/test/client.test.js— palette avatar:'\ud83d' !== '🚀'; mini-flowchart label: notextlabel was🚀; role subtitle:Array.from(role).lengthwas 27/28 with a lone surrogate.plugins/social/test/social.test.js—#2581: a co-seat room line keeps its emoji whole…:the envelope text carries no lone surrogate; false !== true.plugins/timeline/test/sanitize.test.js—#2581: cleanLabel cuts emoji…:30 !== 60characters kept, half a face at the end.plugins/workflow/test/graph.test.js— thecutCodePointsunit cases fail at import on the old source.Green at the tip with the same tests (see the Checkpoint block).
Ran at the tip
Not as one
npm run verifyprocess: this host's container has a 512-task cgroup limit, and the single command's per-file children abort withpthread_create: Resource temporarily unavailable. Each stage was run on its own, with the same commands,TZ=UTC:core:npm run lint— oxlint 0 errors,arch-docs: OK (17 changed file(s));npm test— 2 996 tests, 2 993 pass. The 3 failures are this host's environment, not the change:check-arch-docs.test.jsneedsgitonPATHand an exec-capableTMPDIR(both given, 7/7 pass) andusage-fields.test.jsshells out topython3, which this host does not have; CI runs it.node scripts/lint-plugins.mjsok,node core/scripts/build-client.mjs --check(client.js unchanged),node scripts/ds-bot-patches.mjs checkandcanonical(generate is a no-op),node .github/scripts/changelog.mjs check(3 fragments well formed)..github/scripts/*.test.mjs+policy/*.test.mjs671/671; interop lint + 37/37; live-e2e lint + 34/34.Docs-not-needed: the fix routes existing bounds through code-point cuts and the existing
cut()helper; no owned interface, tool, flow or stored shape changes.Checkpoint
{
"pr": 2582,
"claim": "Dev",
"issue": 2581,
"summary": "Six bounds on text another Bot or person supplied now cut on code-point boundaries instead of UTF-16 units, so an emoji is never split into a lone surrogate that a UTF-8 encoder would write as U+FFFD. Task cues go through the existing cut() helper; the three plugin packages get a small cutCodePoints helper and the workflow avatars take one code point. cut() itself keeps its unit budget, documented in place. face-rooms.js is untouched.",
"files": [
"core/src/host/task-drive.js",
"core/src/shared/text-boundary.js",
"plugins/workflow/src/graph.js",
"plugins/workflow/src/service.js",
"plugins/workflow/client.js",
"plugins/social/src/social.js",
"plugins/timeline/src/sanitize.js",
"plugins/workflow/test/code-point-cut.test.js",
"core/test/task-drive.test.js",
"plugins/social/test/social.test.js",
"plugins/timeline/test/sanitize.test.js",
"plugins/workflow/test/client.test.js"
],
"checks": {
"ran": "each verify stage on its own: core lint + arch-docs, core suite, four plugin suites, scripts/interop/live-e2e, patches check + canonical, build-client --check",
"result": "green",
"at": "670497f5cbae95431b1f99c0410973487c2bc968"
},
"next": "none — ready for review"
}