unbridled-41 opened a new pull request, #5089:
URL: https://github.com/apache/rocketmq-dashboard/pull/5089
## Problem
`normalizeAiMarkdown` (`web/src/pages/ai/render/markdown.ts`) prepares every
assistant text block for `react-markdown` (`TextBlock.tsx:46`, live and
replayed). Its docstring promises that it is "purely textual and idempotent:
well-formed input comes back unchanged", but the pass rewrote three shapes of
well-formed Markdown.
**1. Every heading with two or more hashes was demoted and gained a literal
`#`.** `/^(#{1,6})(?=\S)/` is anchored at the line start and greedy, so when
the full marker run is followed by a space the engine backtracks to a shorter
run that does satisfy `(?=\S)`:
```
"## 概述" => "# # 概述"
"### 三级标题" => "## # 三级标题"
"##### 五级" => "#### # 五级"
"# 一级" => "# 一级" (single hash unaffected)
```
**2. The bullet repair fired on emphasis, thematic breaks and signed
numbers:**
```
"**bold** start" => "* *bold** start"
"*italic* start" => "* italic* start"
"---" => "- --"
"-1 items" => "- 1 items"
```
**3. Both passes ran over the raw text, so markers inside a fenced block
were rewritten too** — a `diff` block the model is asked to show became `- old
line` / `+ new line`, which changes the diff.
Expected: the intended repairs (`##结论`, `-第一项`, ```` ```bashls ````) still
apply, and everything else comes back as written.
## Root cause
Both repairs are blind line-oriented regexes with no notion of what the
marker actually opens. `#{1,6}` backtracks (the `(?=\S)` guard then tests a
*partial* run), `[-+*]` cannot tell a bullet from an emphasis delimiter /
thematic break / sign, and neither pass skips fenced regions.
## Fix
Separate a marker only when it runs into its own text, keep emphasis /
thematic breaks / signed numbers as written, and track fenced regions so their
lines stay verbatim (`markdown.ts:18-79`). The intended repairs are unchanged —
verified by the pre-existing behaviour cases in the new test.
## Priority
**82** = impact 30 (a wrong render of every `##`+ heading and every diff
block in the AI console; the transcript is the product surface) + blast radius
16 (all assistant text, live and replayed) + reproducibility 20 (pure function,
deterministic) + maintenance 16 (the module's own documented contract is the
one being violated).
`FIX_CONFIDENCE` **90**.
## Tests
New `web/src/pages/ai/render/__tests__/markdown.test.ts` (12 cases) — **7
fail before the fix**, pass after.
```
$ npx vitest run src/pages/ai/render/__tests__/markdown.test.ts
✓ src/pages/ai/render/__tests__/markdown.test.ts (12 tests) 16ms
Test Files 1 passed (1)
Tests 12 passed (12)
```
Before the fix the same file reported `Tests 7 failed | 3 passed (10)`.
Module and neighbouring suites:
```
$ npx vitest run src/pages/ai
Test Files 18 passed (18)
Tests 206 passed (206)
$ npx eslint src/pages/ai/render/markdown.ts
src/pages/ai/render/__tests__/markdown.test.ts # 0 problems
$ npx prettier --check ...
# clean
$ npx tsc -b
# clean
```
## Risk
Low. The change is confined to one pure function plus its new test. The
repair is applied per line with a fence flag; unterminated fences simply stop
the repairs for the rest of the block (they previously had their code corrupt),
and an ATX run longer than six hashes — which CommonMark does not treat as a
heading — is now left alone instead of being rewritten into a heading.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]