
Plate 仓库非 React 测试覆盖收口实战Phase 3 之后的审查、评分与停止决策【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate本文基于 Plate 仓库Rich-text editor with AI and shadcn/ui 的 monorepo在 2026-03-25 完成的非 React 测试覆盖审查Testing Review Non React Post Phase 3展开。文章完整还原了这次审查的目标、可复现的验证命令、文件级评分规则、阈值分布、Phase 4 冻结路线图及其执行记录并结合仓库内真实源码docx 列表清理器、表格边框查询、Slate 删除变换等与测试基建脚本讲解为什么这样做命令如何工作哪些文件被选中及为何被选中。读者读完后可以掌握在大型 monorepo 中对非 React 临时切分做覆盖收口的一整套可操作流程重新生成作用域清单、跑 scoped 覆盖率、做套件健康检查、按文件价值评分定批、以及判断何时应该诚实地停止。一、背景什么是非 React 临时切分覆盖审查Plate 是一个以 React 为核心的富文本编辑器 monorepo但仓库中大量核心逻辑docx/markdown 序列化、Slate 变换、表格查询、插件契约本身并不依赖 React 渲染层。在 2026-03-25 之前项目已经经历了多个覆盖阶段2026-03-24系列完成了全仓库full-repo与非 React 路径的多轮testing-review2026-03-25又先做了 broad Bun suite-health 清理见 2026-03-25-broad-bun-suite-health-fix.md。本关联文档 2026-03-25-testing-review-non-react-post-phase-3.md 记录的正是在Phase 3 覆盖率烧尽之后、以及 broad 套件健康清理之后对临时非 React 切分做的一次全新复审fresh testing-review pass。它的核心目标很明确重新跑一遍限定在非 React 作用域内的覆盖率重新生成文件清单与评分检查套件健康更新或锁定下一份非 React 路线图最后给出继续还是停止的结论。它不是一个功能开发文档而是一份可复现的测试工程方法论文档——这类文档在开源仓库中价值极高因为它沉淀了覆盖率治理的纪律文件优先、诚实评分、及时止损。二、Goal 与 Status一次审查的验收清单原文档的 Goal 只有一句话Run a fresh testing-review pass for the temporary non-React cut after Phase 3 and the broad Bun suite-health cleanup.在 Phase 3 与 broad Bun 套件健康清理之后对临时非 React 切分做一次全新测试审查。与之配套的 Status 清单定义了这次审查必须交付的五个动作这也是任何一次覆盖收口审查的通用验收清单运行一次全新的、限定作用域的非 React 覆盖率Run fresh scoped non-React coverage运行套件健康检查Run suite-health checks重新生成包级与文件级评分Regenerate package and file scoring更新或锁定下一份非 React 路线图Update or lock the next non-React roadmap总结继续还是停止Summarize whether to continue or stop。五个动作在本轮全部完成文档中均标记为[x]。这种先定义验收项再执行的结构正是文档中反复强调的file-first ranking, not package theater文件优先排名而非包剧场纪律在流程层面的体现。三、Verification可复现的验证命令与工具链原文档在 Verification 一节给出了五类可复现命令。它们各自解决一个具体的审查问题下面结合仓库脚本逐一展开。3.1 重新生成非 React 测试文件清单# 产物.claude/tmp/non_react_test_files.txt615 个文件这是整个流程的起点。原文档 Notes 中特别强调了一个关键教训The previous scoped non-React file list was stale. This pass regenerated it before coverage. The earlier list would have lied about remaining gaps.上一份非 React 文件清单已经过时。本次在跑覆盖率之前重新生成它。旧清单会说谎掩盖真正的缺口。也就是说如果沿用旧清单跑覆盖率结果会虚假地好看或虚假地难看重新生成清单保证覆盖率快照与当前源码结构一致。从仓库测试基建看这种按清单圈定测试范围的模式与 tooling/scripts/test-fast.mjs 的路径过滤机制一脉相承该脚本会把非-开头的裸参数视为 path filter通过globSync做动态匹配、对静态路径做前缀/包含匹配从而只跑被圈定的测试文件。3.2 限定作用域的覆盖率运行bun test --coverage --coverage-reporterlcov --coverage-dir.coverage-repo-2026-03-25b --reporterdots针对的是重新生成的非 React 文件清单。这里三个关键参数的含义--coverage启用 Bun 内建覆盖率采集--coverage-reporterlcov输出 LCOV 格式产物为.coverage-repo-2026-03-25b/lcov.info后续评分正是以这份 lcov 为输入源详见下文输入与约束--reporterdots点状进度输出适合长跑时观察。本次运行结果记录于配套的 覆盖率优先级映射文档Fresh non-React coverage:2784 pass, 0 fail, 566 files, 2.32s。同一时刻 fast suite全量快速套件的结果为3022 pass, 0 fail, 614 files, 3.83s平均单测耗时 0.508ms、中位数 0.212ms。也就是说非 React 切分覆盖了 fast suite 566 个文件中的绝大部分。3.3 套件健康检查profile 与 slowestpnpm test:profile -- --top 25 pnpm test:slowest -- --top 25这两个命令都路由到 tooling/scripts/test-slowest.mjs区别在于--profile只输出性能画像、不因超阈值而失败profileOnly 分支而pnpm test:slowest在存在超限用例时会以退出码 1 失败。脚本内部会以 junit reporter 跑一遍 fast suite输出到/tmp/plate-test-slowest/junit-fast.xml解析testcase的 time 属性按每个用例耗时和每个文件总耗时两个维度排序打印 Top N 慢用例与 Top 20 慢文件并用!超慢桶、~警告区标注依据 tooling/config/test-suites.mjs 中的阈值判定健康状态export const FAST_TEST_SLOW_CASE_THRESHOLD_MS isCI ? 90 : 75; export const FAST_TEST_SLOW_FILE_THRESHOLD_MS isCI ? 180 : 150;即单用例慢桶阈值本地 75ms / CI 90ms单文件总耗时慢桶阈值本地 150ms / CI 180ms。一旦出现慢桶违规脚本会提示Move the offending spec to*.slow.ts[x]so it runs viapnpm test:slow即把超标用例迁移到慢速车道。本次审查的慢桶检查结论threshold breaches: none无任何阈值越界且警告区warning zone也没有需要处理的常客。这与 2026-03-25-main-push-test-slowest-and-use-event-plate-id.md 中把test:slowest纳入 main push 检查的做法互相印证套件健康是持续门禁不是一次性审查。3.4 三类测试债务扫描原文档给出了三条 ripgrep 扫描命令分别对应三种常见的测试债务形态# 1. 被 skip 的用例describe.skip / it.skip / test.skip / xit / xdescribe rg -n describe\.skip|it\.skip|test\.skip|xit\(|xdescribe\( packages apps \ -g *.spec.ts -g *.spec.tsx -g *.slow.ts -g *.slow.tsx # 2. 被整块注释掉的用例^\s*//\s*(describe|it|test)( rg -n ^\s*//\s*(describe|it|test)\( packages apps \ -g *.spec.ts -g *.spec.tsx -g *.slow.ts -g *.slow.tsx # 3. 跨 spec 导入from ...spec通常意味着测试之间的隐式耦合 rg -n from .*\.spec|from \.*\.spec\ packages apps \ -g *.spec.ts -g *.spec.tsx -g *.slow.ts -g *.slow.tsx本次扫描结论skipped-test debt scannone worth fixing没有值得修的跳过用例commented-out spec scannone worth fixingcross-spec import scannone零命中。注意这三条命令是债务检测而非必须清零。结论用词是 none worth fixing——即使有零星命中只要不构成实际问题就不值得投入。这与后文覆盖率虚荣coverage vanity的反对立场完全一致审查的目标是产出诚实的数据与决策不是数字洁癖。四、覆盖率的输入与约束lcov 与四条红线配套的 覆盖率优先级映射文档 给出了本次评分的输入与约束这是理解为什么要这样评的关键Coverage source.coverage-repo-2026-03-25b/lcov.info即 3.2 节命令的产物约束一临时排除/reacttemporary exclude/react约束二不做浏览器或 e2e 覆盖工作no browser or e2e coverage work约束三不做覆盖率虚荣no coverage vanity约束四文件优先排名不做包剧场file-first ranking, not package theater。这四条红线定义了整个收口的边界只对纯逻辑层负责不越界到渲染层与 e2e且反对用包覆盖率这种容易被平均掩盖真相的指标做决策。五、Scoring Rules文件级评分规则全文评分规则是这套方法论的核心资产原文共六条逐条继承如下作用域packages/**/src/**。排除项测试文件、barrel桶文件/重导出索引、声明文件、明显的纯类型文件、/react、以及packages/playwright下的浏览器包工作。扣分项包装器wrappers、微小的碎屑tiny crumbs、DOM 重残留DOM-heavy leftovers、schema 尘埃schema dust、以及巨大的序列化器污泥giant serializer sludge。加分项确定性变换deterministic transforms、查询queries、parser 或 serializer 接缝seams、插件契约plugin contracts、插件解析plugin resolution、以及有界运行时辅助bounded runtime helpers。诚实原则不在 lcov 中出现的运行时文件一律视为未覆盖Missing-from-lcov runtime files are treated as uncovered。原文档的原话是Pretending they are covered is clown math.假装它们被覆盖了是荒谬数学。包评分定义package_score是该包内剩余文件评分最高的前 5 个之和the sum of the top 5 remaining file scores in that package而不是把所有残余碎屑加起来——这样包分不会被碎屑数量污染。这套规则的哲学很清晰评分奖励的是有契约、可确定性验证的代码惩罚的是低信噪比、高维护成本的代码。它直接决定了下一节的批次排序。六、阈值分布与批次排序从 score 5 到 score 1本次复审后的文件评分阈值分布为阈值剩余文件数score 55score 425score 370score 2108score 1210关键结论文档 Strong Take 原意There are noscore 6files left. The entire honestscore 5set is just five files, and four of them are one tinybasic-nodesparser-plugin lane.已无score 6的文件整个诚实的score 5集合只剩 5 个文件其中 4 个属于basic-nodes同一条极小的 parser-mark 插件车道。6.1 Strict Next Batch必须收口的 5 个文件docx— docxListToList.ts — score5basic-nodes— BaseCodePlugin.ts — score5basic-nodes— BaseStrikethroughPlugin.ts — score5basic-nodes— BaseItalicPlugin.ts — score5basic-nodes— BaseUnderlinePlugin.ts — score56.2 Wider Optional Batch可选的 7 个 score-4 文件table— getSelectedCellsBorders.ts — score4autoformat— AutoformatPlugin.ts — score4core— DebugPlugin.ts — score4udecode/depset— get-package-manager.ts — score4table— getCellIndices.ts — score4basic-nodes— BaseBoldPlugin.ts — score4slate— deleteText.ts — score46.3 按价值排序的包与最佳文件Packages By Value前 12 名basic-nodes— 24slate— 20docx— 18table— 17core— 16docx-io— 16list-classic— 16dnd— 15markdown— 12resizable— 12suggestion— 10cursor— 9Best Files By ValueTop 15含覆盖率与未覆盖行数#包文件score覆盖率未覆盖行1docxdocxListToList.ts578.9%82basic-nodesBaseCodePlugin.ts576.9%63basic-nodesBaseStrikethroughPlugin.ts583.3%44basic-nodesBaseItalicPlugin.ts582.6%45basic-nodesBaseUnderlinePlugin.ts582.6%46tablegetSelectedCellsBorders.ts495.1%127docx-iosettings.ts40.0%118slatehasDOMNode.ts418.2%99autoformatAutoformatPlugin.ts488.9%810slatehasEditableTarget.ts420.0%811slatehasSelectableTarget.ts420.0%812slatehasTarget.ts420.0%813coreDebugPlugin.ts490.6%514udecode/depsetget-package-manager.ts481.5%515tablegetCellIndices.ts481.8%4这张表信息量很大值得专门解读两点高覆盖率 ≠ 高优先级getSelectedCellsBorders.ts覆盖率高达 95.1% 却只排 score 4说明它的剩余缺口多位于跨单元格边界left-adjacent、right-edge这类低价值分支而hasDOMNode.ts覆盖率仅 18.2% 却也只有 score 4因为它是 DOM-only 接缝真实代码但错误的阶段。score 与覆盖率是正交的两个维度score 衡量剩余缺口值不值得补覆盖率衡量已经覆盖了多少。评分 剩余价值而不是覆盖率缺口大小。七、从源码看被选中文件的真实结构评分不是凭空给分。下面以 4 个代表性文件为例说明它们为什么被选中、测试要补什么。这些文件路径均可直接在仓库中打开验证。7.1 docx 列表转换器docxListToList.tsexport const docxListToList (element: Element): Result { const listLevel getDocxListIndent(element); let listHtml ; let nextSibling: Element | null element; while (nextSibling) { if (isDocxBookmark(nextSibling)) { nextSibling nextSibling.nextElementSibling; continue; } if (!isDocxList(nextSibling)) break; const nextListLevel getDocxListIndent(nextSibling); if (nextListLevel listLevel) break; // 更低层级当前列表结束 if (nextListLevel listLevel) { const nestedList docxListToList(nextSibling); // 递归处理嵌套 if (nestedList.list) listHtml nestedList.list.outerHTML; nextSibling nestedList.nextSibling; continue; } listHtml li${getDocxListContentHtml(nextSibling)}/li; const currentElement nextSibling; nextSibling currentElement.nextElementSibling; currentElement.remove(); } const listTagName isDocxOl(element) ? ol : ul; const list parseHtmlElement(${listTagName}${listHtml}/${listTagName}); return { list, nextSibling }; };这是一个典型的确定性 parser 接缝输入 DOM 元素、输出 HTML 字符串与下一个兄弟节点。它同时包含两个扣分项/加分项的判别特征——递归嵌套与兄弟游标推进是有边界的确定性变换加分而 bookmark 跳过则是容易被漏测的分支。因此 Phase 4 执行记录中对该文件的补测就是两件事bookmark 跳过与嵌套列表递归见 docxListToList.spec.ts。7.2 表格选中边框查询getSelectedCellsBorders.ts该文件导出getSelectedCellsBorders及三个辅助谓词isSelectedCellBordersNone/isSelectedCellBordersOuter/isSelectedCellBorder核心逻辑是对选中的单元格集合计算包围盒getSelectedCellsBoundingBox然后单次遍历所有单元格按top/bottom/left/right四个方向判断边框可见性并综合出none全无边框与outer外框完整两个聚合状态。它被评为 score 4 的原因在源码里写得很清楚存在大量边界条件——首行单元格的 top 边框要看自身、非首行要看上方单元格的 bottom 边框getTopTableCell、首列同理要看左侧单元格的 right 边框getLeftTableCell再加上colSpan/rowSpan展开循环。Phase 4 对它的补测正是补齐left-adjacent 边框检查和right-edge 边界 fallthrough见 getSelectedCellsBorders.spec.tsx。7.3 单元格索引查询getCellIndices.tsexport const getCellIndices ( editor: SlateEditor, element: TTableCellElement ): CellIndices { const { getOption } getEditorPluginTableConfig(editor, { key: KEYS.table }); let indices getOption(cellIndices, element.id!); if (!indices) { indices computeCellIndices(editor, { cellNode: element })!; if (!indices) { editor.api.debug.warn( No cell indices found for element. Make sure all table cells have an id., TABLE_CELL_INDICES ); } } return indices ?? { col: 0, row: 0 }; };这是一个缓存优先、计算兜底、降级默认的三段式查询先查插件 option 缓存cellIndices按element.id索引未命中则实时计算计算失败则告警并返回{ col: 0, row: 0 }。对应测试 getCellIndices.spec.ts 补的是三个分支cache-hit命中缓存、warn计算失败告警与fallback默认降级——正好覆盖这三段式中的每一段。7.4 Slate 删除变换deleteText.ts这是slate包内部的删除核心变换包含一整套复杂分支void 节点的定位与剔除、跨块合并mergeNodes、range unhang、point ref 保护以及一个非常特殊的泰文脚本处理——当删除方向为reverse且删除的是泰文字符串时按码点而非字形簇删除THAI_SCRIPT_REGEX /[\u0E00-\u0E7F]/删 N 个字符后把剩余码点插回。Phase 4 对它的补测聚焦两处point-inside-void 删除光标在 void 内部时把范围挤到 void 外与文档末尾的前向删除 no-opeditor.api.after(at, opts) || editor.api.end([])兜底后的空操作见 deleteText.spec.tsx。这类变换 边界组合正是评分规则中deterministic transforms的加分对象。7.5 basic-nodes 的 parser-mark 车道BaseCodePlugin.tsexport const BaseCodePlugin createSlatePlugin({ key: KEYS.code, node: { isLeaf: true }, parsers: { html: { deserializer: { rules: [ { validNodeName: [CODE] }, { validStyle: { fontFamily: Consolas } }, ], query({ element }) { const blockAbove findHtmlParentElement(element, P); if (blockAbove?.style.fontFamily Consolas) return false; return !findHtmlParentElement(element, PRE); }, }, }, }, render: { as: code }, rules: { selection: { affinity: hard } }, }).extendTransforms(({ editor, type }) ({ toggle: () { editor.tf.toggleMark(type); }, }));它是插件契约 解析器接缝的典型createSlatePlugin声明 key、isLeaf 节点、HTML 反序列化规则CODE标签或 Consolas 字体系列以及query否决逻辑P 标签内 Consolas 不算 code、PRE 内部不算。它与其他三个兄弟插件BaseStrikethrough/BaseItalic/BaseUnderline共享同一条 parser-mark 车道因此 Phase 4 用一个合并的 BaseMarkPlugins.spec.ts 统一覆盖parser 否决 toggle 接线一次收口四个文件这也解释了为什么5 个 score-5 文件中有 4 个是一条车道。八、Caveats数据噪声与诚实解读配套文档专门列出四条 Caveats防止读者被包级数据误导包总分比文件分噪声更大信任文件排名Trust the file ranking morebasic-nodes看起来分高只是因为一条小的 parser-mark 车道还部分未覆盖不代表整个包需要清扫slate被 DOM-editor 残留物抬高它们是真实文件但对最后一轮非 React 收口而言错误的阶段wrong phasedocx-io自我高估schema 尘埃与html-to-docx.ts未覆盖但都不是高 ROI 目标。这些 Caveats 是方法论的重要组成部分数据要标注使用边界。包分数只能用来寻找值得看的文件不能用来判断包质量。九、Stop Condition诚实的停止条件文档给出的停止条件是一段值得反复读的工程判断Stop non-React coverage after the phase-4 roadmap below. The remaining misses after that are mostly DOM-only Slate crumbs, schema or type dust, wrapper/plugin residue, and giant low-ROI serializer sludge. That is where more non-React coverage turns into percentage cosplay. Switch to React or architecture-safety work instead.完成下面的 Phase 4 路线图后停止非 React 覆盖。此后的剩余缺口大多是 Slate 的 DOM-only 碎屑、schema/类型尘埃、包装器/插件残渣以及低 ROI 的巨大序列化器污泥。继续补下去非 React 覆盖就会变成百分比角色扮演。应当转向 React 或架构安全性工作。percentage cosplay百分比角色扮演这个词精准定义了覆盖率虚荣的形态当剩余缺口全是低价值代码时覆盖率数字再涨也没有工程意义。停止条件 剩余价值的边际收益归零而不是数字到 100。十、Phase 4 路线图冻结规则、执行与收尾配套的 2026-03-25-non-react-coverage-roadmap-phase-4.md 是本次审查的决策产物它定义了非 React 覆盖的最后一班车。10.1 Lock Rules冻结规则仅限临时非 React 切分Phase: temporary non-React cut only以文件级 TSV 作为唯一真相来源Frozen threshold: use the file TSV as source of truthTier 1 所有剩余score 5文件Tier 2 可选的score 4最佳清理项保持队列文件优先Keep the queue file-first不得回退成包清扫Do not collapse this back into package sweeps后续 pass 只能把条目标记为done/removed/deferred除非候选集合发生实质性变化否则不得重排整个队列Do not reshuffle the whole thing。10.2 Execution Policy执行策略Tier 1只有当你还想要最后一轮非 React 冲刺时才执行Tier 2可选打磨不是强制完成 Tier 1 或 Tier 2 后停止非 React 覆盖并转向After Tier 1 or Tier 2, stop non-React coverage and move on。10.3 执行记录已全部完成2026-03-25-non-react-coverage-roadmap-phase-4-execution.md 记录了 Phase 4 的实际工作量Tier 1 与 Tier 2 共 12 个文件全部标记[done]Tier 15 个docxListToListbookmark 跳过 嵌套递归、BaseCode/Strikethrough/Italic/Underline 四个插件合并进新增的BaseMarkPlugins.spec.ts覆盖 parser 否决 toggle 接线Tier 27 个getSelectedCellsBordersleft-adjacent 与 right-edge、AutoformatPlugin混合规则 undo-on-delete 与无insertTrigger的成功自动格式化、DebugPlugin默认 console logger 表面、get-package-manageryarn fallback 与空 user-agent 默认、getCellIndicescache-hit 与 warn/fallback、deleteTextvoid 内删除与文档末尾前向删除 no-op。10.4 Deferred By Design刻意延期清单hasDOMNode.ts等 score-4 Slate DOM-editor 助手——理由DOM-only 接缝真实代码错误阶段settings.tsdocx-io schema 尘埃——理由低信号数据/schema 常量ROI 差html-to-docx.ts——理由巨大序列化器污泥不适合作为最后的非 React 投入BasePlugin.ts及类似 core 基础 slab——理由是广泛重构目标不适合做晚期覆盖切片isTouchEvent.ts等工具尘埃——理由未覆盖但不值得动。10.5 Update Rule队列维护规则文件获得直接测试 → 翻转为[done]文件被证明是虚假 ROI → 翻转为[deferred]并附理由文件消失 → 翻转为[removed]禁止因为新一轮 pass 有新感觉就重排队列Do not reshuffle the queue because a fresh pass had a new vibe。这套冻结 状态翻转机制保证路线图是可追溯的执行台账而不是反复无常的待办清单。十一、最终结论为什么这一轮是最后的诚实路线图原文档 Notes 的最后两行是整份文档的题眼There are no remainingscore 6non-React files. Only fivescore 5files remain, so this is the last honest non-React roadmap.已无score 6的非 React 文件只剩 5 个score 5文件所以这是最后一份诚实的非 React 路线图。结合 Phase 4 执行记录末尾的 OutcomePhase 4 is complete. Non-React coverage work is spent enough that more passes would mostly be crumbs, wrappers, DOM-only Slate dust, or sludge.Phase 4 完成。非 React 覆盖工作已经投入得足够充分更多轮次的收益将主要是碎屑、包装器、Slate 的 DOM-only 尘埃或污泥。以及执行时的完整验证链# 定向跑新增/扩展的 8 个 spec 文件 bun test packages/docx/src/lib/docx-cleaner/utils/docxListToList.spec.ts \ packages/basic-nodes/src/lib/BaseMarkPlugins.spec.ts \ packages/table/src/lib/queries/getSelectedCellsBorders.spec.tsx \ packages/table/src/lib/utils/getCellIndices.spec.ts \ packages/autoformat/src/lib/AutoformatPlugin.spec.tsx \ packages/core/src/lib/plugins/debug/DebugPlugin.spec.ts \ packages/udecode/depset/src/utils/get-package-manager.spec.ts \ packages/slate/src/internal/transforms/deleteText.spec.tsx # 按目录批量回归 bun test packages/docx/src/lib/docx-cleaner/utils packages/basic-nodes/src/lib \ packages/table/src/lib packages/autoformat/src/lib packages/core/src/lib \ packages/udecode/depset/src/utils packages/slate/src/internal/transforms # 构建 类型检查 lint 全链路 pnpm install pnpm turbo build --filter./packages/docx --filter./packages/basic-nodes \ --filter./packages/table --filter./packages/autoformat \ --filter./packages/core --filter./packages/udecode/depset --filter./packages/slate pnpm turbo typecheck --concurrency1 --filter./packages/docx --filter./packages/basic-nodes \ --filter./packages/table --filter./packages/autoformat \ --filter./packages/core --filter./packages/udecode/depset --filter./packages/slate pnpm lint:fix至此非 React 覆盖工作以一个明确的停止点收尾剩余缺口已被定性为低价值代码继续投入将违背no coverage vanity的红线。这个停止点本身就是这套方法论最有价值的产品。十二、给测试工程实践的四个可迁移要点先刷新清单再跑覆盖率作用域清单一旦过时覆盖率快照就会失真。任何切分式覆盖率审查的第一步都应该是重新生成测试文件清单。文件评分优先于包评分包分数噪声大会被残留物抬高真正可操作的是文件级排名用剩余价值而非覆盖率缺口排序能自然避开低 ROI 的污泥与尘埃。为停止建立显式条件当剩余缺口主要是 DOM-only 接缝、schema 尘埃、包装器残渣与序列化器污泥时继续补覆盖就是百分比角色扮演。把停止条件写进路线图防止覆盖工作无限延伸。用状态机维护收口队列done / removed / deferred三态 禁止随意重排让路线图成为可追溯的台账deferred必须附理由理由本身就是在沉淀工程判断。延伸阅读本次审查的原始记录2026-03-25-testing-review-non-react-post-phase-3.md覆盖率评分与数据详情2026-03-25-coverage-priority-map-testing-review-non-react-post-phase-3.md冻结路线图2026-03-25-non-react-coverage-roadmap-phase-4.md执行记录2026-03-25-non-react-coverage-roadmap-phase-4-execution.md测试基建快速套件脚本 tooling/scripts/test-fast.mjs、慢速/性能分析脚本 tooling/scripts/test-slowest.mjs、阈值常量 tooling/config/test-suites.mjs、根脚本入口 package.json关联源码docxListToList.ts、getSelectedCellsBorders.ts、getCellIndices.ts、deleteText.ts、BaseCodePlugin.ts【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考