Slate v2 Phase 9 Richtext 决策实录:用跨仓库对比矩阵把“模糊未覆盖”收口为 Comparison-Only
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
导读
本文围绕 Slate v2 替换工程(replacement envelope)中 Phase 9 的richtext家族决策展开:它不是一个“实现新功能”的计划,而是一次证据纪律层面的收口——通过向替换兼容性矩阵(replacement compatibility matrix)新增一条 legacyrichtext对比行,并用跨仓库本地运行器在真实浏览器环境中验证该行,从而把家族账本(family ledger)里richtext的“模糊、尚未覆盖”状态锐化为明确的comparison-only(仅对比、不宣称当前实现覆盖)。读完本文,你将理解替换矩阵的运转机制、run-cross-repo-local.sh双仓库运行器的用法、如何用一条矩阵切片阻止“假装 parity”与“夹带实现”两类工程失真的具体操作,以及该决策如何为后续 Phase 9 各家族(tables、embeds、editable-voids 等)提供方法论模板。
背景:替换包络中的矩阵、账本与记分板
Slate v2 的替换工程围绕三个互相约束的控制文档展开,richtext决策正是同时作用于这三者:
- 替换兼容性矩阵:即
replacement-compatibility.test.ts对应的浏览器对比行集合,它是证明“当前 v2 在哪些行为缝(seam)上可以与 legacy Slate 对照”的实证载体。其顶层状态由 replacement-gates-scoreboard.md 维护。 - 替换家族账本(family ledger):replacement-family-ledger.md 按家族记录当前 v2 栈“保留(Preserved)/重定义(Redefined)/仅对比(Comparison-only)/有意延后(Intentionally Later)”四种状态。
- 主路线图(master roadmap):master-roadmap.md 规定 tranche 顺序与执行教义,是所有 Phase 9 支持计划的“当前队列真相”来源。
本决策文档(docs/plans/2026-04-06-slate-v2-phase9-richtext-decision.md)被明确标注为Supporting plan,即它不取代路线图,而是路线图某一 slice 落地的过程记录。
Goal:让richtext家族在替换包络中不再模糊
Make the
richtextfamily less vague in the replacement envelope.
模糊(vague)在这个语境里有具体所指:此前richtext在家族账本中的存在更像一个“后来再处理”的占位符——既没有被否认、也没有被证明,处于既不诚实也无从验证的灰色地带。本决策的目标是把这种模糊压缩掉,让richtext在替换包络中的位置可由一条矩阵行直接回答。
Scope:本 slice 只做三件事
决策的范围被刻意收敛为三项,全部是“证据层”动作而非“实现层”动作:
- 为替换兼容性矩阵新增一条 legacy
richtext行——注意是 legacy 行,即“legacy 侧存在该表面、当前 v2 尚未覆盖该表面”的对比条目; - 用该条证据锐化家族账本——把
richtext从泛化的“尚未覆盖”措辞改为逐家族、可核验的 comparison-only 措辞; - 保持当前 v2 侧诚实——不发明一个虚假的
richtext当前表面(no pretend current surface)。
三条范围项共同指向同一个原则:矩阵行的职责是让家族“可见且诚实”,而不是替实现团队预支承诺。
Constraints:三条不可逾越的纪律
范围之外,决策文档还显式列出三条约束,它们本质上是本次工作的验收红线:
- 不假装当前的 richtext parity:任何“当前 v2 已达到 richtext 平级”的表述都不被允许,即使局部行为(如某个 mark 的切换)看起来可用。
- 不在矩阵切片内隐藏大范围 richtext 实现批次:矩阵行是“对比证据”,不是“实现入口”。如果某个 slice 实际上承载了一个 broad richtext implementation batch,它就违反了本约束,哪怕矩阵行本身通过验证。
- 必须通过当前端口
3010的跨仓库本地运行器验证:证据不能停留在纸面,必须跑起来。
这三条约束与记分板规则中的一条一脉相承:“a gate is not green because nearby proof is green”(邻近证明为绿不代表该 gate 为绿),以及“parity success does not close a north-star gate automatically”(parity 成功不会自动关闭北星 gate)。可见本决策是整个替换工程“诚实证明文化”的一个切片级落地。
关键机制:跨仓库本地运行器与双仓库对比
要理解验证命令,先要理解背后的运行器。跨仓库对比基建在 2026-04-06-slate-v2-cross-repo-comparison-and-scoreboard.md 中完整落地,核心资产包括:
scripts/run-cross-repo-local.sh:跨仓库本地运行器,负责把当前仓库(plate 侧的 slate-v2 栈)与本地另一个slate仓库同时拉起;playwright/integration/examples/replacement-compatibility.test.ts:替换兼容性对比行所在的 Playwright 测试;- 替换占位符基准与替换超大文档基准脚本;
- 根 package.json 中对应的本地命令(如
yarn test:replacement:compat:local); - 记分板文档 replacement-gates-scoreboard.md。
从本决策文档给出的实际命令可以看到运行器的调用形态:
bash ./scripts/run-cross-repo-local.sh 3010 /examples/rich-inline ../slate 3210 /examples/richtext "yarn build:slate-browser:playwright && yarn exec playwright test playwright/integration/examples/replacement-compatibility.test.ts --project=chromium --workers=1"逐段拆解:
| 参数 | 含义 |
|---|---|
3010 | 当前仓库(slate-v2 侧)的本地端口,验证过程固定使用3010以满足约束 |
/examples/rich-inline | 当前仓库侧用于承载对比行为的示例路径 |
../slate | 被对比的 legacy 仓库相对路径(本地 sibling 目录) |
3210 | legacy 仓库侧的本地端口 |
/examples/richtext | legacy 仓库侧被对比的richtext示例路径 |
"yarn build:slate-browser:playwright && yarn exec playwright test ..." | 先在浏览器侧完成构建(slate-browser的 Playwright 构建),再以单 worker 的 Chromium 项目跑替换兼容性测试 |
注意--workers=1与--project=chromium:单 worker 保证双仓库并行服务下浏览器断言的可复现性;Chromium 是替换工程浏览器证明的默认事实标准(scoreboard 中 v2-only 示例行同样全部以 Chromium 证明)。命令中的构建步骤说明:矩阵验证依赖slate-browser的 Playwright 构建产物,而不是直接对源码做单元级断言——这是浏览器级(browser-proof)而非运行时级(runtime-proof)的证据。
Progress:从“加一行”到“账本锐化”的落地顺序
决策文档记录的进度严格按 Scope 推进:
- 新增一行:向替换兼容性矩阵加入 legacy
richtext行; - 跑通证明:通过上述跨仓库本地运行器把该行跑绿(该步同时验证了
/examples/richtext这条 legacy 对比缝在双仓库并联下真实存在、可加载、可断言); - 锐化账本:基于该证据更新家族账本——
richtext现在被明确定位为comparison-only,即“legacy 可见性存在,但当前家族声明尚不存在”,不再是模糊的 not-yet-covered; - 同步上层文档:同步记分板与顶层 v2 文档,让落地的 Phase 9 slice 在路线图栈中可见。
这四条顺序本身就是方法论:证据先于措辞,措辞先于同步。任何一步颠倒都会回到“模糊”状态。
事后验证:richtext家族账本的最终形态
把视角拉到决策落地之后,家族账本中richtext的条目已经不再是 comparison-only 的“历史快照”,而是被后续批次继续推进为Redefined(replacement-family-ledger.md 的 Richtext Family 条目):
- 浏览器证明覆盖:
strong、em、code、blockquote、heading-one、扩展选区(expanded selection)加粗的添加/移除、段落缝上的持续输入; - 运行时证明覆盖:任意 intrinsic 标签、
renderLeaf(...)宿主所有权、扩展选区 mark 添加/移除; - 明确“不是什么”:不是对所有旧 richtext 行为的 blanket parity,也不是旧工具栏/插件架构。
同时,example-parity-matrix.md 中richtext行在 2026-04-15 的 git-diff 重基线后被升级为recovered:源码与 legacy 的相似度0.874、diff 行数225,Chromium 证明覆盖渲染、浏览器文本插入以及“撤销恢复被删除的选中富文本”。这一行也从侧面印证了本决策的价值:矩阵行先保证了“可见”,后续批次再逐缝把“可见”推进为“已恢复”,每一步都有独立证据,没有一步是跳步的。
另一个有意思的收尾在 legacy Playwright 漂移表:legacyselect.test.ts(三击段落选择意图)的当前所有者被显式映射到richtext.test.ts的当前浏览器缝上——这意味着richtext这条缝后来承担了不止一个 legacy 测试意图的所有权,成为浏览器边界证明的汇聚点。
方法论模板:本决策如何复制到其他家族
本决策并非孤例。紧随其后的 2026-04-07-slate-v2-phase9-structural-comparison-families.md 完全复用了同一套模板,把tables、embeds、editable-voids从泛化的“later”桶中拉出来,变成有矩阵行支撑的 comparison-only 状态,验证命令结构完全一致(仅更换 legacy 示例路径与端口对)。这说明该决策文档沉淀出的是一套可重复的家族收口协议:
- 在替换矩阵中加 legacy-only 对比行(不伪造当前支持声明);
- 用跨仓库本地运行器以固定端口对(当前侧 3010)跑绿该行;
- 依据证据把家族账本从模糊措辞锐化为逐家族 comparison-only;
- 同步记分板与顶层路线图,保证 slice 在栈中可见。
配套的 Phase 9 家族决策还包括 placeholder-matrix、paste-html-matrix、highlight-matrix、code-highlighting-matrix、plaintext-readonly-family、anchor-matrix、browser-boundary-family 等,共同构成 Phase 9 的“逐家族证据收口”全景。
结语:一条矩阵行的工程意义
从表面看,本决策只做了一件小事——加一行、跑一次、改一段账本措辞。但它真正回答的是替换工程中最容易被含糊带过的问题:“某家族当前到底处于什么状态?”通过把richtext收口为 comparison-only,工程团队获得的是:
- 对 legacy 侧的诚实:不假装已覆盖;
- 对当前侧的诚实:不发明虚假表面;
- 对实现计划的约束:矩阵切片不得夹带实现批次;
- 对后续工作的可验证起点:任何“已恢复”的升级都必须有独立的浏览器/运行时证据。
这正是 Slate v2 替换工程把“替换”做成可审计过程而非一次性重写的核心原因。对于任何正在做“重写式替换”的编辑器团队,这份决策文档都是一份值得照抄的流程样本:先让证据可见,再让措辞精确,最后才轮到实现。
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考