Skip to content

Bug: '~' used as a range separator in CJK text is parsed as strikethrough and silently dropped #385

Description

@drgnchan

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

  1. Open pi-web chat.
  2. Ask the assistant to output text with ~ ranges, e.g.:
    **5~7U 保证金 × 100~200倍杠杆 = 500~800U 名义**
    
  3. 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

  1. 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.
  2. Render del nodes without eating the tilde, or strip strikethrough support entirely (rarely used in assistant chat for CJK).
  3. Optionally add a markdown option in pi-web settings to toggle strikethrough.

Happy to submit a PR if a direction is agreed on.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions