news 2026/9/14 20:32:21

Plate 编辑器基准实验室的 Evidence Kit 引导(Bootstrap):用证据契约与硬切规则取代旧版 App/Template 基准动物园

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Plate 编辑器基准实验室的 Evidence Kit 引导(Bootstrap):用证据契约与硬切规则取代旧版 App/Template 基准动物园

Plate 编辑器基准实验室的 Evidence Kit 引导(Bootstrap):用证据契约与硬切规则取代旧版 App/Template 基准动物园

【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate

本文基于 Plate 仓库中benchmarks/editor/iterations/000-bootstrap-evidence.md(Evidence Harness Bootstrap,第 000 期迭代记录)展开,介绍 Plate 如何用一套"证据优先"(evidence-first)的 Evidence Kit 实验台(lab)替换掉旧的独立 Next/Vite 基准应用,确立目标自有的基准行归一化契约、来源配置、注册表控制平面与硬切(hard-cut)守护,并给出完整的验证命令。读完本文,你将掌握该实验台的目录骨架、行归一化契约的字段语义、硬切机制的实现位置、基准注册表的运作规则,以及从npm run checknpm run evidence:full的完整验证链路,从而能够在该实验台内新增或审查一条 Slate v2 vs Slate 的基准证据行。

背景与动机:为什么旧的"基准应用动物园"必须被替换

在本次引导之前,benchmarks/editor是一个独立的 Next/Vite 基准应用(app)与模板(template)集合,用于承载编辑器框架基准研究。该迭代记录(verdict: accepted)明确指出,这个形态存在结构性问题:

  • 大量appstemplates等应用脚手架占据了默认归属权,基准实验的"默认所有者"变成了浏览器应用壳,而不是证据产物本身;
  • 历史上的临时基准 JSON(tmp/*benchmark*.json)散落在各包中,无法区分"当前有效的证据"与"一次性的历史输出";
  • 在 Slate v2 与 Slate 还没有可靠的对比行之前,任何关于性能数字的宣称都缺乏可验证的形态。

因此本次引导的 Goal 非常明确:用更小、更"证据优先"的实验台替换benchmarks/editor,专门用于编辑器框架基准研究。其核心原则是:默认所有者是证据产物(evidence artifacts),而非浏览器应用脚手架。

这一点也在实验台 README(benchmarks/editor/README.md)中得到了复述:"This directory is an Evidence Kit lab for editor framework benchmark research. It replaces the old standalone Next/Vite benchmark app. The default owner is now evidence artifacts, not browser app scaffolding."

目标定义:一个"证据优先"的编辑器基准实验室

第 000 期记录把目标收敛为一句话:Replacebenchmarks/editorwith a smaller evidence-first lab for editor framework benchmark research。展开来看,这个目标包含三层含义:

  1. 缩小而非扩编:不再维护庞大的浏览器应用/模板矩阵,实验台只保留证据所需的骨架;
  2. 先证明自身,再输出数字:实验台必须先能证明"自己产出的证据形态是正确的",之后才允许任何人引用 Slate v2 vs Slate 的数字(Current Result 原文:"The lab can prove its own evidence shape before anyone starts claiming Slate v2 vs Slate numbers");
  3. 硬切守护:一旦旧应用/模板路径"复活",基准行必须失败(fail),从而阻止无意的回归。

实验台骨架全景:Evidence Kit scaffold 的组成

第 000 期记录列出了引导阶段已经实现的骨架(Implemented),对照 benchmarks/editor 目录可以逐一印证:

骨架组件说明仓库中的落点
Fuzzer(模糊测试)随机生成基准行并校验归一化契约benchmarks/editor/test/fuzz/core-fuzz.mjs
Corpus(语料)固定种子用例,与生成用例一起覆盖契约benchmarks/editor/test/fixtures/corpus.json
Benchmark(基准行)核心/对比/富文本等基准行生成与检查benchmarks/editor/benchmarks 下多个*.mjs
Source fetchers(来源抓取器)抓取编辑器框架来源配置,供研究使用benchmarks/editor/benchmarks/fetch-editor-frameworks-research.mjs、fetch-source-pass-research.mjs
Package-boundary check(包边界检查)限制源码文件数、包体积、dry-run 打包体积benchmarks/editor/benchmarks/package-boundary-gates.mjs
Startup check(启动检查)校验包导入的 P95 耗时与导出数量上限benchmarks/editor/benchmarks/startup-import.mjs
Scope hash(范围哈希)由 evidence-kit 生成/更新基准作用域通过npm run bench:scopeevidence-kit scope --update
Perf docs(性能文档)生成 HTML 看板与可检索的 perf 文档benchmarks/editor/docs/perf(evidence.htmlindex.htmlrich-text.htmlslate-v2-internals.html

其中 fuzzer 是验证整个契约的"第一道门":它读取 corpus 中的固定用例,再以可复现的种子(默认0x5e_ed,即 24237)生成随机用例,逐条调用normalizeBenchmarkRow并做深度相等比较;此外它还会调用createEvidenceReadinessRows校验硬切就绪行、用构造的 Slate 对比产物校验三个活动面(slate-v2:dom-presentslate-v2:default-render-autoslate)各产出一行归一化结果。如果契约被破坏,npm run fuzz会直接失败。

目标自有的行归一化契约(Target-owned Normalization Contract)

第 000 期记录强调了一个关键设计:基准行的归一化契约由目标(target)自己拥有,实现在 benchmarks/editor/src/index.mjs。这意味着"一行证据长什么样"不是由上层应用壳定义的,而是由证据实验台与目标仓库共同约定。

目标声明:editorTargets

export const editorTargets = Object.freeze([ { id: 'slate-v2', label: 'Slate v2', role: 'engine-and-react-runtime', sourcePath: '../../.tmp/slate-v2', evidenceOwner: 'scripts/benchmarks plus packages/slate*', }, { id: 'slate', label: 'Slate', role: 'legacy-baseline', sourcePath: '../../../slate', evidenceOwner: 'upstream package behavior and local clone', }, ]);

从源码结构看,实验台当前只声明两个活动目标:

  • slate-v2,角色为"引擎 + React 运行时",本地源码路径指向.tmp/slate-v2(相对本实验台为../../.tmp/slate-v2),证据所有权归属于 Slate v2 自身的scripts/benchmarkspackages/slate*
  • slate,角色为"遗留基线"(legacy-baseline),本地源码路径指向../../../slate,证据所有权归属于上游包行为与本地克隆。

这两个目标同时出现在 benchmarks/editor/research/editor-frameworks-sources.json 的来源配置中,说明"来源配置"与"目标声明"是相互印证的同一事实。

行契约字段:normalizeBenchmarkRow

const normalized = { category: requireString(row.category, 'category'), fixture: requireString(row.fixture, 'fixture'), library: requireString(row.library, 'library'), status: requireString(row.status, 'status'), };

一行归一化后的基准行至少包含四个必填字段,另有四个可选的度量字段:

字段类型语义
categorystring(必填)基准类别,例如slate-react-huge-document-legacy-compare
fixturestring(必填)场景/固件标识,例如5000-blocks/combined-selection/startupMs
librarystring(必填)被测实现,例如slate-v2:default-render-autoslate
statusstring(必填)状态,例如okmissing-sourcemissing-artifactover-budget
medianUsnumber(可选)中位数耗时,统一换算为微秒
p95Usnumber(可选)P95 耗时,统一换算为微秒
opsnumber(可选)采样次数 / 操作次数
bytesnumber(可选)字节类指标(如堆增量)
notestring(可选)可读上下文,附在结果 JSON 中

所有数值字段都会经过requireFiniteNumber校验,任何NaN/Infinity都会抛错——这是契约对"脏数据"的零容忍设计。normalizeBenchmarkResult则在行之上再包一层结果对象:namegeneratedAtnode(Node 版本)与rows数组,并兼容rowsresults两种负载键名。

毫秒到微秒的统一换算

时间类指标在写入结果前统一由msToUs转换为微秒并保留三位小数:

function msToUs(value) { return Number((requireFiniteNumber(value, 'milliseconds') * 1000).toFixed(3)); }

度量字段的识别遵循命名约定:以Ms/Duration结尾的视为时间指标(写medianUs/p95Us),以Bytes/MB结尾或unit === 'bytes'的视为字节指标(写bytes),否则视为普通计数(写ops)。这保证了来自不同产物的指标最终都落到同一行形态上。

三个活动面的顺序与命名

export const slateLegacyCompareSurfaceOrder = Object.freeze([ 'v2DefaultRenderAuto', 'v2DomPresent', 'legacyChunkOn', ]);

Slate 遗留对比产物中的三个活动面分别映射为:slate-v2:default-render-autoslate-v2:dom-presentslate(chunk-on 基线),顺序固定,便于在结果 JSON 与文档看板中稳定呈现。

硬切(Hard-cut):旧路径回归即失败

第 000 期记录中"Hard-cut benchmark row that fails if old app/template paths return"是本引导最有特色的机制。它的实现分为两部分。

第一部分是硬编码的"陈腐表面路径"清单(benchmarks/editor/src/index.mjs 中的staleSurfacePaths):

export const staleSurfacePaths = Object.freeze([ 'apps', 'app', 'assets', 'components', 'data', 'lib/benchmark-types.ts', 'scripts/benchmark/run_contract_benchmarks.mjs', 'templates', 'tests/config', 'website', ]);

第二部分是createEvidenceReadinessRowsfindStaleSurfaces:只要这些路径中任何一个在实验台根目录重新出现,legacy-app-surface-removed这一行的状态就会从ok变为stale-surface,并在 note 中列出命中的路径。

三行就绪证据(evidence-readiness)分别为:

  1. editor-framework-source-map:来源配置条数是否不少于目标数(sources.length >= editorTargets.length);
  2. local-editor-targets:本地目标源码根是否存在(knownTargets.length >= editorTargets.length);
  3. legacy-app-surface-removed:旧应用/模板路径是否已被清除(staleMatches.length === 0)。

这三行由 fuzzer 在每次运行时强制校验(if (readinessRows.length < 3) throw),也被npm run checknpm run evidence:full覆盖。也就是说,任何人只要把appstemplateswebsite之类的旧目录放回实验台,整条验证链就会红——这就是"硬切"的落地方式:不是靠人约定,而是靠基准行失败来强制执行

来源配置:editor-frameworks-sources.json 与源码抓取

第 000 期记录提到 "Editor framework source config inresearch/editor-frameworks-sources.json"。该文件(benchmarks/editor/research/editor-frameworks-sources.json)当前声明了 2 个来源:

{ "version": 1, "topic": "editor-frameworks", "generatedBy": "@shapeshift-labs/evidence-kit", "sources": [ { "name": "slate-v2-package", "type": "file", "path": "../../.tmp/slate-v2/package.json", "fileName": "slate-v2-package.json", "why": "Slate v2 owns current deep Slate benchmark commands and artifact families." }, { "name": "slate-package", "type": "file", "path": "../../../slate/package.json", "fileName": "slate-package.json", "why": "Slate is the local baseline for Slate v2 compare lanes." } ] }

src/index.mjs中的readResearchSources会校验每个来源的nametype为非空字符串,why字段记录了该来源被纳入研究的理由——Slate v2 拥有当前深度基准命令与产物家族,Slate 是对比道的本地基线。对应的抓取命令是npm run research:editor-frameworks:fetchnpm run research:source-pass:fetch,抓取产物用于研究目录(benchmarks/editor/research)下的证据源地图。

控制平面:benchmark-registry.json 的注册表规则

虽然第 000 期主要完成的是引导骨架,但后续第 003 期(benchmarks/editor/iterations/003-evidence-control-plane.md)将注册表确立为控制平面,其规则在第 000 期的决策中已经埋下伏笔:未来对比应进入本实验台,而不是恢复旧的 app/template 动物园

注册表(benchmarks/editor/research/benchmark-registry.json)的核心政策是:

"policy": { "activeArtifactRule": "Only artifacts listed here are active benchmark evidence.", "discardRule": "Unregistered benchmark JSON files are ignored historical output." }

即:只有注册在案的产物才是"活动证据";未被注册的旧tmp/*benchmark*.json一律视为被忽略的历史输出,除非为它添加注册表条目、目标自有适配器、fuzzer、corpus 用例、基准行或来源记录(README 的 Rule 一节)。注册表当前登记的产物家族包括:

  • React 大型文档react-huge-document-legacy-compare(5,000 块、3 次迭代、20 次类型操作、combined-selection 道)、react-huge-document-overlaysreact-huge-document-browser-tracereact-huge-document-slate-browser-trace
  • React 局部性react-rerender-breadth
  • React 打字react-active-typing-breakdown
  • 核心当前core-normalization-currentcore-query-ref-observationcore-node-transformscore-text-selectioncore-editor-storecore-refs-projectioncore-transaction-current(可选);
  • 核心对比core-huge-document-comparecore-normalization-comparecore-observation-comparecore-rich-text-operations-comparehistory-compare
  • 剪贴板 / 协作 / issue 回放clipboard-large-payloadcollab-readinessissue-6038-transaction-executionhistory-retained-memory(可选)。

每个产物条目都携带idcategorykindslate-legacy-compare/current/compare/browser-trace/rows)、ownerfamilycwd、实际运行命令(command)、产物路径(path)、required标志与decision(该基准要回答的问题)。required: true的产物缺失会被健康报告标记为missing-artifact,反之标记为optional-missing-artifact——这正是第 002 期记录(benchmarks/editor/iterations/002-rich-text-editor-evidence-matrix.md)中"红行有用"机制的基础:缺件、超预算、未注册都会显式暴露出来,而不是被静默吞掉。

验证命令:从 check 到 evidence:full

第 000 期记录给出了三条核心验证命令,全部在 benchmarks/editor 目录内执行:

npm run check npm run evidence:full npm run docs:perf:search -- editor benchmark

结合 benchmarks/editor/package.json 的脚本定义,可以拆解出完整链路:

  • npm run check:对src/index.mjs、fuzzer、全部benchmarks/*.mjs逐个执行node --check语法检查,然后执行npm run evidence:full。这是"语法 + 全量验证"的总入口。
  • npm run evidence:full:按序执行
    1. test:evidence:fuzzer 跑 200 个生成用例 + 包边界门禁(--bytes 200000 --files 32 --packBytes 1250000 --packFiles 96,即源码 ≤200KB / ≤32 文件、dry-run 打包 ≤1.25MB / ≤96 文件);
    2. fuzz:fuzzer 跑 1000 个生成用例并写入复现文件(--write-repro test/fixtures/repro-latest.json);
    3. bench:evidence:依次产出core-latest.jsonslate-v2-legacy-latest.jsonrich-text-editors-latest.json,再以--p95Ms 100 --exports 32检查启动导入,最后执行evidence:health
    4. bench:startup:checkbench:package:gates
    5. bench:scopeevidence-kit scope --update);
    6. docs:perfdocs:perf:check(生成并校验 HTML 看板);
    7. research:list
  • npm run docs:perf:search -- editor benchmark:调用evidence-kit search,在生成的 perf 文档中检索关键词。例如要检索 Slate v2 与 Slate 的对比证据,可执行npm run docs:perf:search -- slate-v2 slate(见第 001 期记录 benchmarks/editor/iterations/001-slate-v2-legacy-evidence.md)。

bench:evidence的核心产物都落在 benchmarks/editor/benchmarks/results 目录,包括:

  • slate-v2-legacy-latest.json:第一个直接的 Slate v2 vs Slate 运行时对比结果(5,000 块工作负载);
  • rich-text-editors-latest.json:综合基准矩阵,从活动注册表再生成;
  • benchmark-health-latest.json:健康报告与排名后的下一步行动(next actions);
  • core-latest.jsonstartup-import-latest.jsonpackage-boundary-gates-latest.jsonbenchmark-scope-latest.json:核心行、启动检查、包边界门禁与作用域快照。

当前结果与决策:先证明形态,再谈数字

第 000 期记录对"当前结果"的表述非常克制:"The lab can prove its own evidence shape before anyone starts claiming Slate v2 vs Slate numbers."也就是说,引导阶段的验收标准不是某个性能数字,而是证据形态本身可证明——契约可校验、来源可追溯、硬切可执行、产物可再生成。

配套的 Decision 则划定了边界:

  • 未来的编辑器对比应该在本实验台内添加来源可追溯的 Slate v2 vs Slate 基准行;
  • 不应恢复被删除的 app/template 动物园,除非某条基准行证明了"浏览器目标应用才是正确的所有者"。

后续迭代印证了这一决策的落地方式:第 001 期把slate-v2-legacy对比产物作为第一条真实对比道,并刻意保留"混合结果"——部分选择密集行偏向 Slate chunking,就如实保留,因为"保留不舒适的行,而不是把基准变成营销"("the lane is useful because it preserves uncomfortable rows instead of turning the benchmark into marketing");第 002 期把综合矩阵作为当前富文本基准权威,并公开列出超预算红行(如cutTwoBlocksEditMsP50/cutTwoBlocksMsP50)与可选缺失产物(slate-transaction-benchmark.jsonslate-history-retained-memory-benchmark.json);第 004 期(benchmarks/editor/iterations/004-clipboard-over-budget-investigation.md)则直接围绕剪贴板超预算行展开调查。这套"红行即线索"的做法正是证据优先实验台的核心价值。

延后事项与演进路径

第 000 期记录的 Deferred 部分明确了两项遗留工作:

  1. 更多的 Slate v2 vs Slate 浏览器交互证明(Additional Slate v2 vs Slate browser interaction proof)——当前对比道集中在巨大文档工作负载,浏览器交互面(selection、输入法、拖拽等)仍需补充;
  2. 将更多既有 Slate v2 基准产物规范化进本实验台——即按注册表规则逐一登记、归一化,而不是直接引用历史 JSON。

对想深入该实验台的读者,建议按以下顺序阅读:

  • 实验台总览与命令清单:benchmarks/editor/README.md;
  • 归一化契约与目标声明:benchmarks/editor/src/index.mjs;
  • 活动注册表与控制平面:benchmarks/editor/research/benchmark-registry.json;
  • 来源配置:benchmarks/editor/research/editor-frameworks-sources.json;
  • 迭代记录:benchmarks/editor/iterations(000–004);
  • 最新证据产物:benchmarks/editor/benchmarks/results;
  • 生成的 HTML 看板:benchmarks/editor/docs/perf。

小结

第 000 期引导为 Plate 的编辑器基准研究确立了三个不可退让的基线:证据契约归一化(所有产物落到统一的category/fixture/library/status/medianUs/p95Us/ops/bytes行形态)、来源与注册表可追溯(只有注册在案的产物才算活动证据)、硬切守护(旧 app/template 路径一旦回归,验证立即失败)。在此之上,实验台先用npm run check/npm run evidence:full证明自身形态成立,再逐步吸纳 Slate v2 vs Slate 的对比道——无论结果是否"好看",都以红行如实呈现。这种"先证明形态、再输出数字"的纪律,正是富文本编辑器基准研究区别于营销型基准的关键所在。

【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 20:32:05

AI大模型时代企业知识管理:构筑先进组织的核心数字竞争力

生成式AI技术快速普及&#xff0c;企业数据规模爆发增长&#xff0c;但多数组织同时陷入知识过载与知识孤岛双重困境。海量信息淹没真正有价值的业务经验&#xff1b;核心隐性知识伴随人员离职流失&#xff1b;各系统相互割裂&#xff0c;跨团队知识传递偏差大&#xff0c;大量…

作者头像 李华
网站建设 2026/9/14 20:31:56

MATLAB实现RRT路径规划算法详解

1. RRT算法基础与MATLAB环境准备快速扩展随机树&#xff08;Rapidly-exploring Random Tree, RRT&#xff09;是机器人路径规划领域的经典算法&#xff0c;特别适合解决高维空间中的复杂障碍规避问题。2001年由Steven M. LaValle首次提出时&#xff0c;主要针对机械臂的运动规划…

作者头像 李华
网站建设 2026/9/14 20:31:46

三维场景上帝视角实现指南:相机控制、数据组织与性能优化

老读者都知道&#xff0c;我这两年一直在折腾三维可视化相关的项目&#xff0c;从智慧园区到港口监控&#xff0c;从数字孪生大屏到无人机航线规划&#xff0c;前后做了七八个。这些项目有一个共性需求&#xff0c;客户不管前面聊得多么天花乱坠&#xff0c;最后验收的时候几乎…

作者头像 李华
网站建设 2026/9/14 20:29:42

三边封制袋机PLC控制系统设计与485通讯应用

1. 三边封制袋机控制系统概述三边封制袋机作为包装机械领域的重要设备&#xff0c;其控制系统设计直接关系到生产效率和产品质量。这套采用松下PLC和威纶通触摸屏的控制系统&#xff0c;通过前后双伺服送料机构实现精准物料输送&#xff0c;并创新性地使用485通讯协议实现触摸屏…

作者头像 李华
网站建设 2026/9/14 20:28:42

Kafka运维速记:原理、部署、排障与高频面试题全攻略

1. 这份速记为谁整理 上周帮运维同事处理一个Kafka集群的问题&#xff0c;前前后后折腾了一天&#xff0c;最后发现是消费者端的参数配错了。那天晚上我坐在工位上想&#xff0c;接触Kafka这几年&#xff0c;踩过的坑、翻过的文档、答过的面试题其实都能串成一条线&#xff0c;…

作者头像 李华
网站建设 2026/9/14 20:28:09

SAP Gateway 深度读取的两条路径,Framework Expand 与 Data Provider Expand 的运行机制与性能取舍

在 SAP Fiori 或其他 OData Consumer 调用 SAP S/4HANA 后端时,有一种请求非常常见。页面需要显示一张 Sales Order 的抬头信息,同时还要展示这张订单下面的全部 Sales Order Item。如果按照普通 REST 请求思路处理,很容易变成两次甚至更多次 HTTP 请求,一次读取订单抬头,…

作者头像 李华