fix(dingtalk): reopen code fences without inserting a blank line#5204
fix(dingtalk): reopen code fences without inserting a blank line#5204wenshao merged 1 commit intoQwenLM:mainQwenLM/qwen-code:mainfrom he-yufeng:fix/dingtalk-fence-blank-linehe-yufeng/qwen-code:fix/dingtalk-fence-blank-lineCopy head branch name to clipboard
Conversation
splitChunks reopened a fence with a value ending in a newline and then appended another, so a continued code block started with a blank line. Drop the trailing newline from the reopened fence so the existing append adds the single separator.
doudouOUC
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review
✅ Local verification — LGTMBuilt and ran real tests for this PR in an isolated What the fix doesIn - buf = inCode ? '```\n' : '';
+ buf = inCode ? '```' : '';A/B test — the new test actually catches the bugSame PR test file; only the 1-line source fix was toggled:
Failure on the buggy source: This is the meaningful proof: the new test fails before the change and passes after, so it is a real guard rather than a tautology. Behavioral A/B on the real
|
| 被测源码 | markdown.test.ts 结果 |
|---|---|
| PR(已修复) —— 重置为纯围栏 | 17 通过(16 旧 + 1 新)✅ |
修复前 —— 重置为 围栏 + \n(仅回退该行) |
1 失败 / 16 通过 ❌ |
在有 bug 的源码上的失败信息:
× splitChunks > reopens code fences without inserting a blank line
→ expected true to be false // chunks[1].startsWith(fence+'\n\n') === true
❯ src/markdown.test.ts:104:48
这正是关键证据:新测试在修复前失败、修复后通过,说明它是真实的守护,而非恒真断言。
对真实 splitChunks 模块的行为 A/B
输入:一个超长代码块(围栏 + x\n×2000 + 围栏)→ 2 个分片。检查 chunks[1] 的原始开头:
修复前 : "```\n\nx\nx" hasBlankLine=true 第1行 = (空行) ← 多余空白
PR修复 : "```\nx\nx\n" hasBlankLine=false 第1行 = x ← 代码紧跟围栏
为什么原有测试没抓到
原有的边界测试断言是 chunks[1].trimStart().startsWith(fence),trimStart() 会把开头那行空行去掉,因此从结构上就对该 bug 视而不见。新测试改用原始 startsWith,补上了这个缺口。
影响范围 / 风险
- 单行改动,仅限
splitChunks的inCode分支(仅影响 DingTalk 渠道)。非代码块的重置分支(: '')未改动。 @qwen-code/channel-dingtalk包完整测试套件在还原后的 PR HEAD 上 17/17 全通过。- 该包内无其他测试文件,无连带影响。
Verified locally via tmux in an isolated worktree (A/B: only the 1-line fix toggled). Logs: post-fix 17/17, pre-fix 1 fail @ markdown.test.ts:104.
What this PR does
In
splitChunks, when a code block spans the chunk limit the next chunk reopens the fence with a value that already ends in a newline, and the line-append step then adds a second newline. The continued chunk therefore begins with the fence followed by a blank line instead of the code. This drops the trailing newline from the reopened fence and lets the existing append add the single separator.Why it's needed
A fenced code block longer than the 3800-char DingTalk limit gets a spurious blank first line in every continued chunk, which renders as leading whitespace inside the code. The existing fence test only checked
trimStart().startsWith('```'), so it didn't catch the extra newline.Reviewer Test Plan
How to verify
Run
npx vitest run packages/channels/dingtalk/src/markdown.test.ts. The new testreopens code fences without inserting a blank linebuilds a code block past the chunk limit and asserts the continued chunk starts with the fence directly followed by the code, not a blank line. It fails before this change and passes after; the other 16 markdown tests are unchanged.Evidence (Before & After)
N/A — non–user-visible string handling, covered by the new unit test.