feat(web-shell): support compact echarts full data blocks - #6232
Conversation
|
Thanks for the PR! Template looks good ✓ On direction: this is a natural extension of the existing Web Shell customization surface. The codebase already has On approach: the scope is tight — one extension point, one bundled skill, two tests, no drive-by changes. The regex fix ( 中文说明感谢贡献! 模板完整 ✓ 方向:这是 Web Shell 现有自定义接口( 方案:范围紧凑——一个扩展点、一个内置 skill、两个测试、没有夹带无关改动。正则修复( — Qwen Code · qwen3.7-max |
|
Code review: clean. The implementation follows established Web Shell patterns (context providers, optional render callbacks, fallback-to-default). No correctness bugs, no security issues, no unnecessary abstraction. The regex fix from Two things I verified specifically:
Tests: 40 Markdown tests pass (including 2 new custom-renderer tests covering both the intercept and fallback paths), 12 bundled-skills integration tests pass (including parsing the new Build + typecheck: clean across all packages. Real-scenario verification: This PR adds a library-level React callback prop — the I did verify the bundled skill is discoverable at runtime: Skill appears in the listing and parses with all required fields (name, description, body) per the integration test. 中文说明代码审查: 无问题。实现遵循了 Web Shell 现有模式(Context Provider、可选渲染回调、回退到默认)。无正确性 bug、无安全问题、无不必要的抽象。正则从 特别验证了两点:
测试: 40 个 Markdown 测试通过(含 2 个新增的自定义渲染器测试,覆盖拦截和回退两条路径),12 个 bundled-skills 集成测试通过(含解析新增 构建 + 类型检查: 全部通过。 实际场景验证: 此 PR 添加的是库级别的 React 回调属性——只有 Web Shell 宿主注册了 已验证内置 skill 在运行时可被发现: Skill 出现在列表中,且集成测试确认所有必填字段(name、description、body)解析正确。 — Qwen Code · qwen3.7-max |
|
Re-run at maintainer request after multiple review iterations. Here's where things stand. The PR has evolved significantly since the initial triage. What started as a tight extension point + bundled skill has grown into a full-featured chart rendering system (~6700 additions, 14 files). The growth is justified — the Security posture is strong. Defense-in-depth: prototype pollution blocking, URI scheme filtering, HTML tag scanning, path traversal prevention in data refs, tree-walking sanitization with depth limits, and key allow/deny lists. Tests verify each protection layer individually. wenshao's latest suggestions (7 items, commit
None of the outstanding suggestions are correctness or security blockers. They're hardening and code quality improvements that can be addressed in follow-up work. Reflection: This is a well-built feature. The extension point ( Approving. ✅ 中文说明按 maintainer 要求重新执行 triage,经过多轮 review 迭代后的当前状态: PR 从初始 triage 以来大幅演进。 从紧凑的扩展点 + 内置 skill 成长为完整的图表渲染系统(约 6700 行新增,14 个文件)。增长合理—— 安全姿态扎实。 纵深防御:prototype pollution 阻断、URI scheme 过滤、HTML tag 扫描、data ref 路径遍历防护、带深度限制的树遍历净化、key allow/deny 列表。测试逐一验证每层防护。 wenshao 最新建议(7 项,commit
所有未解决建议都不是正确性或安全阻塞项。它们是可以在后续工作中处理的加固和代码质量改进。 总结: 这是一个构建良好的功能。扩展点( 批准 ✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
✅ Maintainer verification — built & exercised locallyVerified at head Scope: 6 files, +207 / −11 — a source-gated What I ran
¹ Run after building — a few specs (incl. Real-UI E2E — the extension point genuinely renders a chartI served the real 1 · 2 · Same fence, 3 · Handled chart + unhandled 4 · Mutation tests — the 2 new tests are load-bearing
Observations (non-blocking)
🇨🇳 中文报告(完整对应)✅ 维护者验证 —— 已在本地构建并实测在 PR head 改动范围: 6 个文件,+207 / −11 —— 在 Web Shell 的 Markdown renderer 上新增一个受 跑了哪些检查
¹ 构建后运行 —— 少数用例(含 真实 UI 端到端 —— 扩展点确实能渲染图表我用 web-shell 的 vite dev server 挂载了真实的
(截图见上方英文部分。) 变异测试 —— 2 个新增测试是「有效的」
观察项(不阻塞合并)
|
✅ Maintainer re-verification at head
|
| Check | Result |
|---|---|
web-shell · Markdown.test.ts |
46/46 (was 40 — +6: null, renderer-throws, rendered-node-throws, c++/c#/f#) |
Full web-shell vitest suite |
706/706 (55 files) |
core · bundled-skills.integration.test.ts |
12/12 — incl. web-shell-charts/SKILL.md parses with required fields ✓ |
npm run build (all packages, incl. web-shell lib + tsc) |
✅ exit 0 |
Prettier (7 files) · ESLint (5 TS/TSX) · git show --check |
✅ clean |
Real-UI E2E — the hook genuinely renders a chart
I served the real <Markdown> component through the web-shell vite dev server (serve-mode src aliases → no stubs, no mocks) and registered a host renderCodeBlock that turns an echarts-fulldata fence into a live Apache ECharts chart. The PR ships no chart runtime by design — a host-provided renderer is exactly the contract. DOM assertions are embedded in the capture; 0 console errors.
1 · echarts-fulldata → live host chart; the adjacent plain ts fence still uses the built-in highlighter (dark). The hook is scoped, not a takeover — echartsCanvas=1, preCode=1.
2 · Only theme changes → the chart re-themes (light). Proves theme is threaded from useTheme() through the render info to the host.
3 · <Markdown> with no source prop → hook gated OFF. Both fences fall back to default code blocks, and the echarts-fulldata block keeps its full language tag (not truncated to echarts) — echartsCanvas=0, preCode=2.
Mutation tests — the new tests are load-bearing
Each mutation to Markdown.tsx is caught by exactly the test that guards that behavior; restoring the file leaves all 8 custom-code-block tests green.
Mutation applied to Markdown.tsx |
Proves | Result |
|---|---|---|
theme: appTheme → theme: 'dark' |
theme comes from useTheme(), not hard-coded |
✅ replace test fails |
language-([^\s]+) → (\w+) in extractRawFenceLanguage |
the full hyphenated fence tag is captured | ✅ replace test fails (echarts-fulldata → echarts) |
custom != null → custom !== undefined |
null also declines (harden contract) |
✅ returns null test fails |
bypass CustomCodeBlockBoundary (return node directly) |
the error boundary is load-bearing (harden) | ✅ rendered content throws test fails |
drop !!source from the gate |
source-gating actually blocks the host renderer | ✅ source omitted test fails (spy called 1×) |
Notes (non-blocking)
- The
docs/design/skill-required-capabilities.mddraft leaves open whetherweb-shell-chartsshould be a core bundled skill or host-injected. As shipped it is core-bundled and unconditionally exposed, so a non-Web-Shell session that activates it could have the model emit anecharts-fulldatablock that renders as raw code on clients without the renderer — the exact gap the draft names. Worth a follow-up, not a blocker for this hook. - Cross-platform: pure TS/React plus one markdown skill, no platform-specific APIs; I verified on macOS.
Re-verified in an isolated git worktree at 6d706dc5 (= PR head.sha). Screenshots are element-captures of the real <Markdown> output, hosted from a branch on my fork.
🇨🇳 中文报告(完整对应)
✅ 维护者在 head 6d706dc5 的复验 —— harden + docs 两个提交之后
这是我上次在 d0ef6d88 验证之后的跟进。新增的两个提交 —— 634772ea6(harden 加固)和 6d706dc59(docs 设计文档)—— 改动了运行时行为,所以我在一个全新的 git worktree 里从零重新构建并再次实测了本 PR。harden 提交恰好补上了我上次指出的 null 路径缺口。 结论:LGTM,可以合并。
改动范围(相对 main 净值): 7 个文件,+818 / −13。运行时改动是在 Web Shell 的 Markdown renderer 上新增一个受 source 门控的 renderCodeBlock 钩子,外加一个内置 web-shell-charts skill。那份 +323 行的 docs/design/skill-required-capabilities.md 只是讨论草稿 —— grep 在代码里找不到任何对 required-capabilities 的引用。
自 d0ef6d88 以来的变化,以及我核对了什么
634772ea6(harden 加固):null现在也会“婉拒” → 回退到默认代码块(之前只有undefined才回退 —— 上次我指出null路径没被测到)。新增测试returns null✓,下方变异测试已证明其承重。- host renderer 外面加了两道相互独立的保险,都会回退到内置的
CodeBlock:try/catch:当renderCodeBlock(...)同步抛错时 →console.error('[web-shell] … failed:', error)(2 个参数)。已有测试 ✓。- 一个
CustomCodeBlockBoundary错误边界:当返回的节点在渲染阶段抛错时 →console.error(…, error, componentStack)(3 个参数),并且以resetKey={code}复位。已有测试 ✓。
resolveFenceLanguage新增fsharp语言以及c++/c#/f#别名。
6d706dc59(docs): 设计草稿,无运行时代码。
测试套件 —— 全新 worktree @ 6d706dc5,先跑完整 npm run build
| 检查项 | 结果 |
|---|---|
web-shell · Markdown.test.ts |
46/46(原为 40 —— 新增 6:null、renderer 抛错、渲染节点抛错、c++/c#/f#) |
web-shell 完整 vitest 套件 |
706/706(55 个文件) |
core · bundled-skills.integration.test.ts |
12/12 —— 含 web-shell-charts/SKILL.md parses with required fields ✓ |
npm run build(所有包,含 web-shell lib + tsc) |
✅ exit 0 |
Prettier(7 文件)· ESLint(5 个 TS/TSX)· git show --check |
✅ 干净 |
真实 UI 端到端 —— 钩子确实渲染出了图表
我通过 web-shell 的 vite 开发服务器(serve 模式的 src 别名 → 不打桩、不 mock)挂载了真实的 <Markdown> 组件,并注册了一个 host renderCodeBlock,把 echarts-fulldata 代码围栏变成一张实时的 Apache ECharts 图表。本 PR 有意不自带图表运行时 —— 由 host 提供 renderer 正是它约定的契约。DOM 断言直接内嵌在截图流程里;0 条 console 报错。
1 · echarts-fulldata → host 实时图表;相邻的普通 ts 围栏仍走内置高亮器(暗色)。 钩子是有作用域的,不是全盘接管 —— echartsCanvas=1, preCode=1。
2 · 只改 theme → 图表随之换主题(亮色)。 证明 theme 是从 useTheme() 经 render info 一路传给 host 的。
3 · <Markdown> 不带 source prop → 钩子被门控关闭。 两个围栏都回退成默认代码块,且 echarts-fulldata 块保留完整语言标签(没被截断成 echarts)—— echartsCanvas=0, preCode=2。
变异测试 —— 新增测试确实承重
对 Markdown.tsx 的每一处变异,都恰好被守护该行为的那条测试逮住;把文件还原后,8 条自定义代码块测试全绿。
对 Markdown.tsx 施加的变异 |
证明了什么 | 结果 |
|---|---|---|
theme: appTheme → theme: 'dark' |
theme 来自 useTheme(),而非写死 |
✅ replace 测试失败 |
extractRawFenceLanguage 里 language-([^\s]+) → (\w+) |
完整的带连字符围栏标签被捕获 | ✅ replace 测试失败(echarts-fulldata → echarts) |
custom != null → custom !== undefined |
null 也会婉拒(harden 契约) |
✅ returns null 测试失败 |
绕过 CustomCodeBlockBoundary(直接返回节点) |
错误边界是承重的(harden) | ✅ rendered content throws 测试失败 |
从门控里去掉 !!source |
source 门控确实拦住了 host renderer | ✅ source omitted 测试失败(spy 被调用 1 次) |
说明(不阻塞合并)
docs/design/skill-required-capabilities.md草稿留了个未定问题:web-shell-charts到底该做核心内置 skill,还是由 host 注入。当前实现里它是核心内置且无条件暴露的,因此非 Web-Shell 会话若激活它,模型可能产出一个echarts-fulldata块、在没有该 renderer 的客户端上就渲染成原始代码 —— 正是草稿点名的那个缺口。值得后续跟进,但不阻塞本钩子。- 跨平台:纯 TS/React 加一个 markdown skill,无平台相关 API;我在 macOS 上验证。
在隔离的 git worktree 中于 6d706dc5(= PR head.sha)复验。截图是对真实 <Markdown> 输出的元素级截取,图片托管在我 fork 的一个分支上。
wenshao
left a comment
There was a problem hiding this comment.
Rendering extension point and tests look clean. One suggestion on the bundled skill visibility below.
Decision on
|
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No critical issues found. Two minor suggestions below on defense-in-depth and test coverage gaps.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Code Review Summary
Overall this is a well-structured PR. The renderCodeBlock customization hook is clean, the ErrorBoundary integration is solid, and the test coverage for the Markdown pipeline is thorough. A few actionable items in EchartsFullDataBlock:
Issues to fix
-
getCellproduces blank table cells for named dimensions + array-format source (Medium) — Whendimensionsare named strings like['day', 'orders']butsourcerows are arrays like['Mon', 120],Number('day')yieldsNaNand every cell returnsundefined. This is a common ECharts dataset format that ECharts itself handles by mapping named dimensions to array indices internally. -
optionreference instability causes chart re-init on every parent re-render (Medium) —createEchartsFullDataRenderercallsparseOption(info.code)on every render, producing a fresh object. TheuseEffectdependency onoptioncauses dispose + re-init on every parent re-render even after streaming settles (theme change, upstream toggle, etc.). AuseMemooninfo.codefor the parsed result would fix this. -
No loading indicator while
loadEcharts()resolves (Low-Medium) —ChartLoadingStateexists but is only shown forparseError && isStreaming. During asyncloadEcharts()resolution, users see a blank 360px container.
Minor items
- The
.catchhandler in the chartuseEffectsetschartErrorstate but never callsconsole.error— makes production debugging harder. Other error paths in this codebase (e.g.,MarkdownFencedCode's custom renderer catch) do log to console. - Test gap: no test exercises the
loadEcharts=undefinedpath ("Chart runtime is unavailable") or the useEffect.catchbranch.
What's good
- Clean separation of
MarkdownFencedCodefromMarkdownCodefor the custom renderer logic - ErrorBoundary with
resetKeystied tolanguageandisStreaming/codeis a smart strategy - Comprehensive test suite for the Markdown pipeline (51 tests covering decline/null/false fallback, resolved aliases, error boundary reset, components.code precedence)
Object.hasOwnguard onLANGUAGE_ALIASESprevents prototype pollution
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Automated Code Review
9 parallel review agents analyzed correctness, security, code quality, performance, test coverage, attacker/oncall/maintainer mindset, and build/tests. Reverse audit pruned 6 false positives.
Build: ✅ passed | Tests: ✅ 102 web-shell + 14 CLI passed
| Severity | Count |
|---|---|
| Critical | 1 |
| Suggestion | 4 |
See inline comments below for details.
wenshao
left a comment
There was a problem hiding this comment.
/review (medium effort) on 4191476: 8 findings — 3 bugs (array-row {c} labels break in the preferred envelope format, stale chart-error overlay during data-ref re-resolution, fence-language highlighting regression for glued-meta info strings) and 5 suggestions. All posted inline with concrete repro and a suggested fix; the two heavier bug claims were verified against real echarts 5.6.0 / react-markdown 9.1.0 rather than from memory.
中文
对 4191476 的 /review(中等强度):共 8 条——3 个 bug(推荐的 envelope 数组行格式下 {c} 标签渲染整行、data-ref 重新解析期间旧图表错误覆盖层滞留、粘连 meta 的 fence 语言高亮回归)+ 5 条建议。全部内联附具体复现与修法;两条较重的 bug 用真实 echarts 5.6.0 / react-markdown 9.1.0 实测验证,非凭记忆推断。
— claude-fable-5 via Claude Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Review Summary
Verdict: Approve ✅
The PR adds a well-structured echarts-fulldata code block renderer with two-layered sanitization (top-level allowlist + nested denylist), proper async lifecycle management, and solid test coverage (106 tests passing).
Strengths
- Two-layered sanitization approach (
SAFE_TOP_LEVEL_OPTION_KEYSallowlist +UNSAFE_OPTION_KEYSdenylist) is defense-in-depth renderRequestRefcancellation pattern correctly prevents stale async operationsisEchartsFullDataEnvelopetype guard is thorough with fallbacktryParsepath- Clean separation between data resolution, parsing, sanitization, and rendering
- Good i18n coverage (EN/ZH)
Minor Observations
- One inline comment posted below re: array index shifting in
sanitizeOptionValue - Test coverage is comprehensive but could benefit from a streaming-to-settled transition test for
EchartsFullDataBlockFromCode(verifying theisStreamingprop flip)
Deterministic Analysis
- tsc: 0 errors
- eslint: 0 errors
- Tests: 106/106 passing (50 EchartsFullDataBlock + 56 Markdown)
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Re-review of PR #6232
The code has evolved significantly across 3 prior review rounds. Many previously reported issues have been addressed (getCell delegation, parseOption memoization, chartError clearing, ResizeObserver, theme init, accessibility attributes, etc.).
Build & Tests: All passing (50/50 EchartsFullDataBlock, 56/56 Markdown, ESLint clean, TypeCheck clean on changed files).
This review focuses on 8 new issues not covered in prior rounds. The most impactful:
- URI sanitization gap --
isUnsafeUriStringmisses protocol-relative URLs and uncommon schemes - Silent annotation disabling --
datainUNSAFE_OPTION_KEYSstrips markLine/markPoint data at all depths - Zero diagnostic logging in the parse/validation/data-ref pipeline
The security design is solid overall -- the two-layer allowlist+denylist with leaf-value filtering is well-structured, and normalizeDataRef has thorough path traversal prevention.
wenshao
left a comment
There was a problem hiding this comment.
No new review findings. Downgraded from Approve to Comment because the presubmit CI-status check could not be completed due a GitHub API TLS timeout.
— GPT-5 via Qwen Code /review
Suggestions — commit
|
| File | Issue | Suggested fix |
|---|---|---|
Markdown.tsx:418 |
extractRawFenceLanguage regex change from \w+ to [^\s]+ affects ALL code blocks globally, not just echarts-fulldata. Hyphenated language tags now pass the full tag to resolveFenceLanguage. |
Document as a breaking change for renderCodeBlock consumers, or gate the new regex to only apply when a custom renderer is registered. |
EchartsFullDataBlock.tsx:1027 |
normalizeEnvelopeDataset uses .replace('Chart data row', 'Chart envelope data.source row') on error messages — fragile string substitution that breaks if validateDatasetCell rewords. |
Pass a rowLabel prefix parameter to validateDatasetCell instead of post-hoc string replacement. |
index.ts:41-57 + index.tsx:129-145 |
Identical 19-line echarts export blocks duplicated in both entry points. | Have one file re-export from the other, or extract a shared barrel file. |
EchartsFullDataBlock.tsx:1648 |
Render effect includes t (i18n function) in dependency array. Language switch causes every chart to dispose and reinitialize. |
Store t in a ref and remove from deps, like loadEchartsRef. |
EchartsFullDataBlock.tsx:176 |
UNSAFE_OPTION_HTML_TAG_PATTERN blocklist misses <video>, <audio>, <details>, <math>, etc. |
Broaden to /\/?[a-z][a-z0-9]*(?=[\s/>])/i to block all HTML-like tags. |
EchartsFullDataBlock.tsx:290 |
isUnsafeUriString doesn't detect CSS url() wrappers (e.g., url(javascript:alert(1))). |
Add /^url\s*\(/i.test(normalized) check. |
EchartsFullDataBlock.tsx:302 |
sanitizeDatasetCell uses isUnsafeUriString but not isUnsafeOptionString — HTML tags in dataset cells pass through. |
Use isUnsafeOptionString for consistency with option-value sanitization. |
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Automated Review Summary
Verdict: Comment — No blocking issues found. The security architecture is well-designed with effective layered defenses (top-level allowlist, nested denylist, forced tooltip safety overrides, JSON cloning, depth/size limits). Test coverage is thorough (2820+ lines of tests covering sanitization, prototype pollution, URI injection, and HTML injection).
Deterministic analysis: 0 findings (tsc, eslint)
Tests: 854/859 passed (5 pre-existing build-artifact.test.ts env failures, unrelated to PR)
9 suggestions for improvement below, focused on defense-in-depth, accessibility, and API contract clarity.
wenshao
left a comment
There was a problem hiding this comment.
No high-confidence issues found. The sanitization architecture (top-level allowlist + nested denylist + URI/HTML stripping + size limits) is thorough and well-designed. Lib build and both test suites (130 tests) pass cleanly.
Low-confidence items that may deserve a human look:
DATA_REF_TIMEOUT_MS(30s) is shared between data-ref resolution and ECharts runtime loading — different operations with different expected durations.UNSAFE_OPTION_HTML_TAG_PATTERNdenylist omits<video>,<audio>,<source>,<track>,<math>(mitigated byrenderMode: 'richText').resolvedDataRefCacheRefhas no error invalidation — transient failures become permanent for that component instance.- No
console.warnwhenresolveDataRefis undefined and chart usesdata.kind: "ref"— all other failure paths log. - ECharts exports (3 values + 10 types) copy-pasted across
index.tsandindex.tsx. - Test gaps: no
markPoint.datasanitization test, no#/\in data-ref validation, no e2e Markdown render forc#/f#fences.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Summary
This PR adds a well-structured custom code block renderer hook (renderCodeBlock) to the web-shell Markdown component and a comprehensive EchartsFullDataBlock implementation with a two-layered sanitization strategy, data-ref resolution, and theme-aware chart rendering.
Build: ✅ PASS (vite, both builds clean)
Tests: ✅ PASS (862 tests across 61 files, 0 failures)
Deterministic checks (tsc/eslint): ✅ 0 findings (pre-verified)
The overall design is solid — the two-layer sanitizer (allowlist top-level / denylist nested), the envelope/legacy data model, and the host-supplied ECharts runtime loader are all well-reasoned. Findings below are primarily defense-in-depth gaps and maintenance concerns, no critical correctness bugs were found.
Findings overview
| Severity | Count | Themes |
|---|---|---|
| Suggestion | 5 | Sanitization consistency, dual entry-point files, useEffect cleanup safety, observability, type contract |
| Nice to have | 2 | File size, test-only export surface |
The most impactful item is the sanitizeDatasetCell HTML-tag gap (#1) — not exploitable today (React auto-escapes, ECharts renders on canvas), but a latent defense-in-depth hole if any future render path trusts dataset cell content. The dual entry-point files (#2) and the unprotected dispose() (#3) are the next highest-leverage cleanups.
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
✅ Local end-to-end verification (maintainer)I rebuilt and exercised this PR locally at head 1. Build & tests
The full suite was run after building sibling + web-shell dist, so the 2. Mutation testing — are the tests load-bearing?I reverted one piece of logic at a time and confirmed the PR's own tests catch it, then restored (tree ends clean). All 7 mutations were detected:
The surgical single-test failures (M2/M3/M5/M6/M7) show the specs pinpoint each behavior; the broad cascades (M1/M4) show the plumbing and hyphenated-language handling are load-bearing across many cases. 3. Real UI — rendered from a real fence, with a host-supplied ECharts runtimeA lightweight harness mounts the real Highlights worth calling out:
4. Open review threads — honest read138 threads total: 121 resolved, 17 unresolved — all 17 are VerdictFunctionally correct, safe, and thoroughly tested. Real end-to-end rendering works across chart types, both themes, the data view, i18n, sanitization and error paths; the tests are load-bearing; the packaged public API type-checks. This supports merging — the 17 bot notes are good optional follow-ups. 中文报告(点击展开)✅ 本地端到端验证(维护者)我在 head 1. 构建与测试
完整套件是在构建完 sibling 与 web-shell dist 之后跑的,这样那些 import 2. 变异测试 —— 这些测试是否真的承重?我逐条把关键逻辑改坏,确认 PR 自带的测试能抓到,然后还原(最终工作区干净)。7 个变异全部被检出:
M2/M3/M5/M6/M7 精确地只挂 1 个测试,说明用例精准锚定了各自的行为;M1/M4 的大面积连锁失败说明整条插件链路和连字符语言处理是全局承重的。 3. 真实 UI —— 从真实 fence 渲染,ECharts 运行时由宿主注入一个轻量 harness 挂载真实的 (截图见上方英文部分的两张拼图。) 值得强调的点:
4. 未解决的 review 线程 —— 如实说明共 138 条线程:121 条已解决,17 条未解决 —— 这 17 条全部是 结论功能正确、安全、测试充分。 真实端到端渲染在各种图表类型、深浅两主题、数据视图、i18n、净化与错误路径上都跑通;测试确实承重;打包后的公共 API 类型检查通过。支持合并 —— 那 17 条 bot 建议是很好的可选后续项。 Verified locally on a clean worktree at |









Summary
echarts-fulldataenvelope withversion,data, andoptionso compact inline datasets can be injected into ECharts options.resolveDataRef(ref, meta)for large data artifacts.Validation
vitest run client/components/messages/EchartsFullDataBlock.test.tsx(42 tests)vite buildvite build --config vite.lib.config.tstsc -p tsconfig.lib.jsondataworks-charteval iteration 5 passed 12/60/180/500-row generation cases in the companion skill repo.