Repository navigation
Conversation
…inkFlowLab#2429) Fixes ThinkFlowLab#2429 Written-by: Delivery-2 cleanPrompt and readStepResult clipped with a bare String#slice, so a bound that landed between the halves of a surrogate pair stored a lone high surrogate: a prompt of 3,999 characters plus an emoji came back as 4,000 units ending in \ud83d, which every encoder reads as U+FFFD and every reader draws as a replacement character. cleanLine fourteen lines above already cut on code points and says why. The bound also counted UTF-16 units, so an emoji-heavy prompt reached half the room of an ASCII one. One local cut() helper now serves all three callers; no maximum, payload shape or endpoint changes. Docs-not-needed: no ownership, contract or module boundary changed; two text bounds in graph.js now cut on code points like cleanLine beside them.
|
Written-by: Delivery-2 @Birfy review request for this exact tip: Red-first on a clean base plus the gates are in the PR body; Please review |
|
Closing: our account has no write access to Owner: Delivery-2 |
Written-by: Delivery-2
Fixes #2429
Owner: Delivery-2
Tip SHA: dccec83 — the fork's commit for tree
b48551cf45; the same tree was checked locally atd4e35ce, whose message and base5e71a07eare identicalBranch:
delivery2/workflow-prompt-codepoints(forkHugoXK/FlyBot, basedelivery/ai-centric-development-service@5e71a07e)Reproduce
cleanPromptandreadStepResultclip with a bareString#slice, so a bound that lands between the halves of a surrogate pair stores the lone high surrogate. A person meets it where the prompt is drawn (Settings → Workflows canvas, the run stage) and where a step-result body is kept from a Bot's reply:Actual on base:
prompt 4000 d83d false/body 2000 d83d false— both end in\ud83d, which every encoder reads as U+FFFD and every reader draws as�. Expected: the cut lands after the whole emoji, the stored text is well formed, and the maximum counts code points, exactly ascleanLinefourteen lines above already does — "Cut on code points, never on UTF-16 units: a unit offset can split a surrogate pair and leave a lone surrogate, which renders as a replacement character." The same class was fixed for the host under #1993/#2000 and for the workflow node avatar under #2017; these two bounds were left.The bound also counted UTF-16 units, so an emoji-heavy prompt reached half the room of an ASCII one: a prompt of 4,000 emoji was cut at 2,000.
What changed
plugins/workflow/src/graph.js(+5/−5) — one localcut(text, max)helper, the code-point cutcleanLinealready performed, now used bycleanLine,cleanPromptand thereadStepResultbody. No maximum changes: 300, 4,000 and 2,000 stay, and each now counts code points, so the whole bound is kept.plugins/workflow/test/prompt-bounds.test.js(new, 27 lines) — three cases: a prompt bound and a step-result body bound that land inside an emoji, plus the code-point count that a prompt of whole emoji keeps.changelog.d/2429-workflow-text-bounds-code-points.fixed.md(new, 1 line) — a user can see this text.No payload shape, endpoint, key, contract or module boundary changes; no other plugin, no
core/, no generated file touched.Red without the source change
plugins/workflow/test/prompt-bounds.test.json base5e71a07ewith the source untouched — 3 fail / 0 pass:With the fix at the tip:
# pass 3 / # fail 0.What I ran (at the tree
d4e35ce=b48551cf)The 7 core failures are the same environment group on the base tree, unrelated to this diff:
test/project-runtime-setup.test.js(no Codex login cache on this box) andtest/workbench-client.test.js(the six scoped-routing/composer cases). Base full run was# tests 3159 / # pass 3152 / # fail 7— same names, same count.Not run
npm run verifyas one command stops before the suites on this box: core lint'sarch-docsstep callsgit diff origin/main…, and this clone has noorigin/mainref (its remote is the fork; the lane's base is the delivery branch). Each gate above was run individually, withARCH_DOCS_BASEpointing at the lane's base.node core/scripts/build-workbench.mjs --checkfails here onERR_MODULE_NOT_FOUND: Cannot find package 'react'— a dependency of this box, not of this diff; the workbench panel is untouched.core/index.jsandcore/src/host/are untouched.Docs-not-needed: no ownership, contract or module boundary changed; two text bounds in
graph.jsnow cut on code points likecleanLinebeside them. This line is also in the branch commit.Checkpoint
{ "pr": 2433, "claim": "Delivery-2", "issue": 2429, "summary": "cleanPrompt and readStepResult clipped with a bare String#slice, so a bound that landed between the halves of a surrogate pair stored a lone high surrogate, drawn as a replacement character. The bound also counted UTF-16 units, so an emoji-heavy prompt reached half the room of an ASCII one. One local cut() helper, the code-point cut cleanLine already made, now serves cleanLine, cleanPrompt and the step-result body, and three cases prove both bounds on code points.", "files": ["plugins/workflow/src/graph.js", "plugins/workflow/test/prompt-bounds.test.js", "changelog.d/2429-workflow-text-bounds-code-points.fixed.md"], "checks": { "ran": "cd plugins/workflow && node --import ./test/resolve.mjs --test \"test/*.test.js\" && ARCH_DOCS_BASE=upstream/delivery/ai-centric-development-service npm --prefix core run lint && node scripts/ds-bot-patches.mjs check && node .github/scripts/changelog.mjs check", "result": "green", "at": "d4e35ce43695df777b1a3f08d5ec7130c09a897f" }, "next": "none — ready for review" }