Bug: ~ (tilde) used as a range separator in CJK text is parsed as strikethrough and silently dropped
Environment
- pi-web: 0.8.6 (
@agegr/pi-web)
- Markdown pipeline: react-markdown 10 + remark-gfm 4 (bundled in the web UI)
Description
In Chinese/Japanese, ~ is the standard notation for numeric ranges (e.g. 5~7U, 100~200倍, 8~9点). Because the GFM strikethrough implementation (micromark-extension-gfm / remark-gfm) accepts a single tilde as a strikethrough delimiter, any assistant message containing two ~ in the same paragraph gets mangled: the tildes disappear and an arbitrary span of text gets a strikethrough line.
This is very common in LLM assistant output for CJK users (I hit it repeatedly, e.g. when explaining "57U 保证金 × 100200倍杠杆").
Steps to reproduce
- Open pi-web chat.
- Ask the assistant to output text with
~ ranges, e.g.:
**5~7U 保证金 × 100~200倍杠杆 = 500~800U 名义**
- Observed rendering:
5~~7U 保证金 × 100~~200倍杠杆 — i.e. the segment 7U 保证金 × 100 is rendered with a strikethrough line, and the ~ characters are dropped entirely.
Root cause
GFM strikethrough is implemented with one-or-two tilde delimiters. Verified locally with the exact same dependencies:
const { micromark } = require('micromark');
const { gfm, gfmHtml } = require('micromark-extension-gfm');
micromark('a~b c~d', { extensions: [gfm()], htmlExtensions: [gfmHtml()] });
// → <p>a<del>b c</del>d</p>
micromark('5~7U 保证金 × 100~200倍', { extensions: [gfm()], htmlExtensions: [gfmHtml()] });
// → <p>5<del>7U 保证金 × 100</del>200倍</p>
Note: ~ surrounded by spaces (a ~ b ~ c) stays literal, which is why only compact CJK ranges are affected.
Impact
- Assistant replies containing numeric ranges get visually corrupted for CJK users (missing
~, random strikethrough across CJK segments).
- The content is silently altered — a
5~7U range becomes 57U, which can also mislead data-heavy answers (finance/trading use cases hit this constantly).
Suggested fixes
- Disable single-tilde strikethrough (require
~~): remark-gfm has no direct toggle, but a custom remark/micromark extension can override the strikethrough tokenizer, or a small pre-process pass can escape ~ → \~ before parsing.
- Render
del nodes without eating the tilde, or strip strikethrough support entirely (rarely used in assistant chat for CJK).
- Optionally add a markdown option in pi-web settings to toggle strikethrough.
Happy to submit a PR if a direction is agreed on.
Bug:
~(tilde) used as a range separator in CJK text is parsed as strikethrough and silently droppedEnvironment
@agegr/pi-web)Description
In Chinese/Japanese,
~is the standard notation for numeric ranges (e.g.5~7U,100~200倍,8~9点). Because the GFM strikethrough implementation (micromark-extension-gfm / remark-gfm) accepts a single tilde as a strikethrough delimiter, any assistant message containing two~in the same paragraph gets mangled: the tildes disappear and an arbitrary span of text gets a strikethrough line.This is very common in LLM assistant output for CJK users (I hit it repeatedly, e.g. when explaining "5
7U 保证金 × 100200倍杠杆").Steps to reproduce
~ranges, e.g.:5~~7U 保证金 × 100~~200倍杠杆— i.e. the segment7U 保证金 × 100is rendered with a strikethrough line, and the~characters are dropped entirely.Root cause
GFM strikethrough is implemented with one-or-two tilde delimiters. Verified locally with the exact same dependencies:
Note:
~surrounded by spaces (a ~ b ~ c) stays literal, which is why only compact CJK ranges are affected.Impact
~, random strikethrough across CJK segments).5~7Urange becomes57U, which can also mislead data-heavy answers (finance/trading use cases hit this constantly).Suggested fixes
~~): remark-gfm has no direct toggle, but a custom remark/micromark extension can override the strikethrough tokenizer, or a small pre-process pass can escape~→\~before parsing.delnodes without eating the tilde, or strip strikethrough support entirely (rarely used in assistant chat for CJK).Happy to submit a PR if a direction is agreed on.