# 已知边界与取舍 ## 不处理的写法 **块引用 / 列表项里的 `$$`** ```markdown > $$a = 1 > b = 2$$ ``` 这类写法会触发与顶层完全相同的 bug,但本插件只扫描行首(≤3 空格)的 `$$`,因此不处理。原因:要正确处理就得同时维护 `>` 前缀序列与列表缩进,还要保证闭栏匹配同一前缀;而不完整的实现比不实现更危险(可能把内容搬出引用块)。这是刻意的保守取舍。 **退化写法 `$$a$$ 尾随文本`** 开栏行内已出现 `$$` 但后面还有非空白文本时,DSH 会把它降级成普通段落字面文本(无害,不会变红),插件也原样保留。 ## 刻意不做的事 **没有收尾 `$$` 的块保持原样。** ```markdown $$a = 1 b = 2 ``` 作者意图不明确:可能忘写闭栏,也可能后文另有意图。擅自补一个 `$$` 有可能把两个本来要分开的块合并成一个公式。代价是这个块仍会被 DSH 吞到文件尾——但这是**作者没有写完整公式**才出现的状态,而本插件要修的是"写完整了却被误解析"。 ## 依赖的非契约细节 - `React.memo` 的 `.type` 是内层渲染函数,且 memo 对象未被冻结。这是 React 内部细节,不是公开契约(18/19 上稳定)。 - seed 模块表里存在 `@deepseek-ai/dsh-client-ui-primitives`,且聊天包用同一个 specifier `require` 它。 两者任一变化,插件都会**安静地变成 no-op**(状态句柄里能看到 `reason: 'seed-unavailable'` / `'markdown-text-shape-unknown'`),不会抛错、不会影响界面渲染。 同理,如果只给部分消费面打补丁(例如只处理聊天正文),就会出现在别处(工具输出、文档预览)仍然报错的不一致状态——所以这里选择包住组件本身,一次覆盖所有消费方。 ## 不负责的报错 本插件只处理**定界符取串**这一类失败。真正的 TeX 语法错误(例如拼错的 `\frac`、未闭合的 `{`)仍会照常变红——那是 KaTeX 在正常工作。用 `scripts/audit-markdown.mjs` 可以区分二者:若某文件报错但归一化是 no-op,说明它不属于本插件的范围。 ## 与上游修复的关系 上游一旦让 `$$` 块支持 Pandoc 语义(开栏行内容并入公式、收尾 `$$` 允许出现在行尾),本插件的改写结果与之**语义等价**:它只会动那几种当前会出错的形状,把定界符搬到各自独占一行。留着无害,也可以随时卸载: ```bash dsh plugin --profile web remove dsh-tex-block-normalizer ``` ## 流式输出期间的观感 归一化是整段文本的纯函数。消息流式输出时,一个块从"未闭合"变为"已闭合"会让已渲染前缀的行结构变化,增量解析器会重解析受影响的尾部。极端情况下可能看到一次轻微的重排——这是为换取正确性而接受的代价(未闭合期间不会有任何错误闪烁,因为流式语法本来就不带数学扩展)。