
Plate Slate v2 的 ADD 证明架构Ledger、Proof 与 Surface Ownership 三层设计实战【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate本篇技术指南围绕 plate 仓库中docs/plans/2026-04-13-slate-v2-add-proof-architecture-plan.md这一核心计划展开系统讲解 slate-v2 在 Agent 驱动开发ADD场景下如何用「文档层精确账本 代码层行为域证明文件 稳定包表面所有权」的三层架构同时解决「巨型证明文件变成垃圾场」与「盲目 1:1 源码恢复变成考古表演」两大失败模式。读完本文你将掌握一套可直接落地的 legacy 测试资产治理规范精确账本怎么写、证明文件如何按行为域拆分、四种 legacy 行映射状态的判定标准以及 Agent 在关闭 legacy 行时必须遵守的五条硬规则。一、背景为什么需要一套「证明架构」而非「测试文件搬运」在大型开源仓库中当核心包经历重构slate-v2 即 slate 核心的重写路线历史遗留的测试文件与当前架构之间会产生大量「账实不符」。传统的处理方式有两种而 plate 仓库在实践过程中恰好同时踩中了这两种失败模式巨型证明文件变成垃圾场单个文件如snapshot-contract.ts把公共表面、查询助手、选区移动、归一化、结构变换、id、发布机制、替换语义等互不相关的行为全部塞进一个文件导致文件体积失控、无法定位归属。盲目 1:1 源码恢复变成考古表演为了满足文件数量上的「完整」而把已死掉的旧测试脚手架原样搬回当前代码树制造大量无人维护、与当前架构脱节的「僵尸文件」。该计划在 问题章节 中明确指出仓库此前已用精确账本exact ledgers解决了「记账」一侧的问题但「证明」一侧仍存在结构性压力。所谓 ADDAgent-Driven Development就是让 Agent 在无人工陪跑的情况下依据文档与代码之间的契约来驱动开发此时「证明文件」proof file是 Agent 判断「某个旧行为是否仍被当前代码承接」的唯一依据因此它的组织方式直接决定 Agent 的工作质量。二、核心决策文档精确、代码有界、死壳显式跳过计划给出了一个三层拆分决策这是整个架构的灵魂精确 1:1 的 legacy 账本放在文档里docs/slate-v2/ledgers/目录下每个 legacy 测试文件都有一条精确记录作为永久考古层永不删除。当前行为域证明文件放在代码里证明文件按「活的行为域」组织而不是按「迁移的时代」组织。对死掉的 harness 与跨包拆分的 legacy 行显式标记 skip 或 mixed 映射。同时计划明确两条禁令不要把每个 legacy 测试文件都恢复成当前源码文件不要让巨型 omnibus全能型证明文件继续膨胀。一句话概括决策文档里精确代码里有界exact in docs, bounded in code。三、五条指导原则计划为这套架构定义了五条可执行的 Principles它们是后续所有拆分、映射、验证动作的判据Exact in docs, bounded in code文档承载精确性代码承载有界性两者职责不互换。Current package boundaries beat legacy folder nostalgia当前包边界优先于旧目录结构的情怀映射时以「当前代码住哪儿」为准而不是「旧代码原来在哪儿」。One proof file should own one behavior domain, not an era of migration一个证明文件只归属一个行为域不归属一个迁移时代。Dead harness files get explicit skip, not fake recovery死掉的 harness 文件显式 skip绝不假装恢复。Agents should be able to locate the owner with one grep, not a digAgent 应当用一次 grep 就能找到行为归属者而不是靠考古挖掘。这五条原则直接决定了后续的文件策略与 Agent 规则。在 原则章节 中有完整原文。四、目标形态三层架构逐层拆解4.1 Ledger Layer账本层——永久的考古层账本层保留四份精确账本作为 legacy 资产的永久考古档案账本文件覆盖范围仓库现状legacy-slate-test-files.md旧packages/slate/test/**1069 个 legacy 文件mapped-mirrored 979、mapped-recovered 49、mapped-mixed 5、explicit-skip 36legacy-slate-react-test-files.md旧packages/slate-react/test/**8 个 legacy 文件mapped-mirrored 5、mapped-mixed 1、explicit-skip 2legacy-slate-history-test-files.md旧packages/slate-history/test/**20 个 legacy 文件mapped-mirrored 17、explicit-skip 3legacy-playwright-example-tests.md旧playwright/integration/examples/**23 个 legacy 文件same-path-current 21、mapped-recovered 1、explicit-skip 1账本层的规则非常明确Ledger Layer 章节每个 legacy 文件必须且只能占一条精确行1:1每一行必须有一个主当前归属者primary current ownermapped-mixed仅用于真实的多归属拆分一个 legacy 文件内部确实被镜像mirrored、恢复recovered或显式跳过explicit-skip到多个当前归属者explicit-skip必须给出契约层面的理由不允许写「没用到」这种偷懒话术一条 lane 宣告 done 之前不允许存在needs-triage行。以 legacy-slate-test-files.md 的真实记录为例你可以直观看到账本的 TSV 行格式legacy_file mapping_status current_owner note packages/slate/test/apply-batch-generic-tree-ops.js mapped-recovered packages/slate/test/transaction-contract.ts; packages/slate/test/snapshot-contract.ts structural insert/move/set batch parity and live draft reads are covered directly packages/slate/test/apply-batch-failure-semantics.js explicit-skip none exact legacy partial-commit batch failure semantics are not part of the kept transaction contract; the current replacement seam proves atomic rollback on throw in transaction-contract.ts packages/slate/test/batch-matrix-manifest.js explicit-skip none matrix manifest registry is retired with the old batch harness packages/slate/test/children-accessor.js mapped-recovered packages/slate/test/snapshot-contract.ts children accessor routing and enumerable surface are covered directly注意同一份账本中的微妙差异apply-batch-generic-tree-ops.js因为同时涉及 transaction 与 snapshot 两个行为域而被标为 mapped-recovered 且拥有两个 current_owner而batch-matrix-manifest.js这类纯矩阵清单注册表matrix manifest registry则被明确标记为 explicit-skip理由是「随旧批量 harness 一起退役」。这正好对应了计划中「显式 skip 需要契约理由」的要求。4.2 Proof Layer证明层——按活的行为域组织证明文件不再按「一次迁移浪潮」组织而是按「当前活的行为域」组织。计划给出了好与坏两种形态的对照当前公认的好例子行为域单一、可独立阅读transaction-contract.ts—— 事务/写入语义normalization-contract.ts—— 归一化语义operations-contract.ts—— 操作语义transforms-contract.ts—— transforms 语义range-ref-contract.ts—— 选区引用语义clipboard-contract.ts—— 剪贴板语义history-contract.ts/integrity-contract.ts—— slate-history 包内的历史与完整性语义surface-contract.tsx—— slate-react 包表面bridge.ts/clipboard-boundary.ts—— slate-dom 包的 DOM 桥与剪贴板边界坏的形态一个巨型snapshot-contract.ts同时拥有公共表面、query 助手、选区移动、归一化、结构变换、id、发布机制、替换语义一个巨型 React runtime 证明文件永远拥有所有 React 面向行为。这个「坏形态」并非假设——原计划在 Problem 章节 明确指出前身slate-react的runtime.tsx垃圾场已经证明了同样的问题并且现在已经完成了按行为域的拆分。这与仓库中 legacy-slate-react-test-files.md 的记录相互印证旧editable.spec.tsx、react-editor.spec.tsx、use-slate.spec.tsx、use-slate-selector.spec.tsx、use-selected.spec.tsx五份文件分别被镜像到provider-hooks-contract.tsx、editable-behavior.tsx、react-editor-contract.tsx、surface-contract.tsx、projections-and-selection-contract.tsx、primitives-contract.tsx等当前证明归属者名下。4.3 Surface Ownership Layer表面所有权层——把稳定形状上移为包 API计划的关键洞察当证明文件反复重述同一个低层运行时形状时这个形状就应该上移为稳定的包表面。也就是说Agent 应当去证明包的原语primitives而不是在五个测试文件里手抄同一份形状。这条规则在渲染器原语renderer primitives上已经兑现并持续产生收益——参见仓库中对应的问题复盘文档 renderer-primitives-should-own-node-shapes-not-example-markup其核心结论正是「节点形状应由渲染器原语拥有而不是由示例标记拥有」。从当前源码结构可以印证这一层的落地方向packages/slate/src下internal/editor/、internal/editor-extension/、internal/transforms/、internal/dom-editor/等目录本身就是按行为域组织的稳定表面例如above.ts、getPointBefore.ts、getPointAfter.ts、getPositions.ts、unhangRange.ts、nodes.ts、previous.ts、next.ts等查询助手以独立源码文件存在packages/slate/src/internal/editor证明文件只需引用这些表面而无需在测试内重新实现。五、具体文件策略四个测试目录逐一拆解5.1packages/slate/test先动刀拆分snapshot-contract.ts保留不动的证明文件transaction-contract.ts、normalization-contract.ts、operations-contract.ts、transforms-contract.ts、range-ref-contract.ts、clipboard-contract.ts、text-units-contract.ts、extension-contract.ts、headless-contract.ts。下一步拆分对象snapshot-contract.ts计划给出的目标拆分为三个有界归属者surface-contract.ts—— 负责 barrel 导出、可覆写的编辑器实例表面、静态委托、children 访问器、公共方法可用性snapshot-contract.ts拆分后收窄职责—— 只负责不可变快照发布、版本化、id 稳定性、替换语义与投影助手query-contract.ts—— 负责未在其他位置更好安置的读/查询助手above、before、after、positions、unhangRange、nodes及相关读取期遍历行为。拆分判据是两条硬规则如果一个测试本质上是写语义write semantics它就不该住在snapshot-contract.ts如果一个测试本质上是查询/遍历语义query/traversal semantics它就不该和快照发布行放在一起。从 legacy-slate-test-files.md 可以看到query-contract.ts作为 current_owner 已经承接了interfaces/Editor/above/*、before/*、after/*、edges/*、end/*、hasBlocks/*、hasInlines/*、hasTexts/*、isBlock/*、isEdge/*、isEmpty/*、isEnd/*、isInline/*、isStart/*、isVoid/*、levels/*、marks/*等一大批 legacy 行——这正是「按行为域聚合、一次 grep 定位归属」原则在账本中的直接体现。而children-accessor.js行仍以snapshot-contract.ts为 owner第 28 行说明拆分尚未最终落地的部分仍保持原归属等待计划中的第二步动作。5.2packages/slate-react/test保持 one-shot runtime 拆分后的行为域压力一次性的 runtime 拆分已经完成接下来要做的是让剩余文件继续承受「行为域」压力防止它们成为下一批巨兽。目标形态为八个行为域文件surface-contract.tsx—— 包 API、助手表面、聚焦的低层编辑器行provider-hooks-contract.tsx—— provider/editor 生命周期 hook 归属react-editor-contract.tsx——ReactEditor映射、焦点、DOM path/point/range 转换primitives-contract.tsx—— 渲染器与原语归属editable-behavior.tsx—— 已挂载Editable/EditableBlocks行为projections-and-selection-contract.tsx—— 投影存储与 ref 局部性app-owned-customization.tsx—— app 拥有的运行时定制 lanelarge-doc-and-scroll.tsx—— 大文档与滚动行为。两条纪律已挂载的 DOM/runtime 行为 ≠ 导出的 API 形状两者不得混居共享的挂载管道属于test-utils.ts不允许在各证明文件里重复手抄。5.3packages/slate-history/test当前拆分可接受保持克制history-contract.ts与integrity-contract.ts两个文件保持现状只有当其中一个膨胀到足以掩盖缺口时才新增文件。这一克制态与账本吻合20 个 legacy history 测试文件中的 17 个都直接镜像到了history-contract.tslegacy-slate-history-test-files.md少数如undo/insert_text/non-contiguous.js因「基于时序的自动合并启发式不是活契约」而被显式跳过。5.4packages/slate-dom/test当前拆分已足够好bridge.ts与clipboard-boundary.ts保持现状且明确禁止把旧 DOMEditor/Android-only legacy harness 拖回这个包。这对应账本中apply-batch-dom-wrapper.js这类行的处理旧的 withDOM pending-selection/diff 矩阵整体退役当前 DOM/runtime/history 集成分散到各包的专属证明文件中legacy-slate-test-files.md 第 18 行。六、Legacy 恢复策略四种映射状态判定指南对每一条 legacy 行按以下优先级判定映射状态状态适用场景判定要点same-path-current相同相对路径的当前文件仍存在且仍诚实拥有该行为路径与行为双重吻合直接指向自身mapped-recovered行为仍然重要且某个当前证明文件直接拥有它行为活着但当前归属者路径变了mapped-mixed旧文件确实跨包或跨行为域拆分仅限真实的多归属拆分禁止当懒人逃生门explicit-skip死掉的矩阵助手、manifest 注册表、legacy 性能 harness 胶水、被取代的 wrapper-stack 脚手架、超出活契约范围的更宽 legacy 行为必须给出契约理由禁止「没用到」计划的底线很明确永远不要为了美学而恢复这些死资产。四条状态的完整定义见 Legacy Recovery Policy 章节。从仓库账本可以观察到这套策略的真实分布核心 slate 账本中 mapped-mirrored 高达 979 条说明绝大多数 legacy 行为由当前证明文件直接承接explicit-skip 36 条主要覆盖 CustomTypes 声明合并硬切割、fixture harness 入口、manifest 注册表等mapped-mixed 仅 5 条全部是真实跨包拆分如apply-batch-dom-wrapper.js拆到 slate-dom/slate-react/slate-history 三个包的证明文件。Playwright 例子账本则是另一种形态23 条中 21 条是same-path-current因为示例级集成测试的相对路径在 slate-v2 中依旧存在legacy-playwright-example-tests.md只有huge-document.test.ts因断言旧 chunking 内部实现而被显式跳过其活归属者是 benchmark lane。七、Agent 规则与拆分阈值7.1 五条 ADD 硬规则关闭任意一条 legacy 行时Agent 必须按序执行先问这个行为还属于活契约live claim吗是→ 映射到最小的当前证明归属者若没有合适的新建一个聚焦的新归属文件。否→ 显式 skip并给出契约理由。若一个证明文件跨越两个不相关的行为域 → 在继续加行之前先拆分它。若一个证明文件是 Agent 需要数千行上下文才能理解的原因 → 它已经太大了。7.2 建议阈值数字不神圣分类边界神圣证明文件超过约500–700 行时拆分一个文件拥有超过约40 条逻辑上不同的行时拆分一个文件一旦混入以下任意两类立即拆分公共表面public surface事务/写语义transaction/write semantics查询/遍历语义query/traversal semantics运行时 DOM 行为runtime DOM behavior计划特别强调具体数字不是神圣的分类边界才是神圣的。也就是说阈值是启发式信号真正的硬约束是「一个文件只属于一个行为域」。八、实施步骤六步落地路线在文档中冻结归属规则在账本索引docs/slate-v2/ledgers/README.md与主 no-regression 计划中增加一段简短规则块写明「精确账本 1:1 考古证明文件 当前行为归属者」。先拆分packages/slate/test/snapshot-contract.ts这是最高价值的 ADD 清理因为它已经承担了过多职责。更新账本归属行指向新的更小的证明文件。保持 slate-react 证明文件的行为域范围若新文件再次混入 API 形状、DOM 映射与无关 runtime 行为在加行之前先拆分。证明文件与包边界对齐不允许slate的证明文件拥有slate-dom或slate-react的运行时声明。加入轻量维护规则每条新恢复的行必须在同一次变更中声明其主归属文件。值得说明的是从 ledgers/README.md 的现状看tranche-3 阶段已落地了一批恢复的证明归属者query-contract.ts、legacy-editor-nodes-fixtures.ts、legacy-interfaces-fixtures.ts等并明确标注其暂存位置可见本计划中的步骤 1 与步骤 4 已在持续执行中。九、验收标准计划定义了六条可逐项核验的验收标准每个 legacy 文件在精确账本中保持 1:1 记账没有任何活 lane 依赖巨型 omnibus 证明文件来保持诚实每个证明文件只有一个主导行为域死 harness 文件是 explicit-skip 或 mixed绝不假恢复Agent 用一次 grep 打开一个文件就能找到某条行的证明归属者snapshot-contract.ts与剩余的 slate-react 证明文件不再滑入垃圾场地带。十、风险与缓解计划诚实地列出了三个主要风险及对应缓解措施风险缓解过早过度拆分会制造另一种 slop按行为域拆分不按 legacy 文件夹怀旧拆分一次重命名太多证明文件会搅乱链接与账本归属者先拆最糟的文件再小批量重接账本行团队可能把mapped-mixed当偷懒逃生门仅当旧文件真正跨越多个当前归属表面时才允许十一、验证方式每轮拆分后按以下流程验证归属质量读取精确账本中的某一行识别其主归属文件只打开该归属文件验证所声称的行为真实存在若该行需要第二、第三个文件才能说清楚因为第一个归属者太模糊说明归属仍然太松散每次计划内拆分后重跑受影响的包测试与账本回读ledger readback。十二、核心结论Hard Read最后计划用一段「硬读」收尾值得完整保留最干净的 ADD 形态既不是「把每个 legacy 文件都恢复成当前文件」也不是「保留一个巨型契约然后祈祷 grep 能救你」。它应当是三件事的组合文档中精确的 1:1 问责exact 1:1 accountability in docs代码中有界的当前证明归属者bounded current proof owners in code对死掉的 legacy 脚手架做显式切割explicit cuts for dead legacy scaffolding只有这套组合才能同时让人类维护者与 Agent 都远离混乱。对于正在维护大型编辑器类库、或正在用 Agent 驱动重构旧代码库的团队这套「文档记账 代码证明 表面归属」的三层模式完全可以平移复用为通用的 legacy 资产治理协议。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考