Files
Endoleap/headless/STEP4_ACCEPTANCE.md
T

7.6 KiB
Raw Blame History

Step 4:渐进功能与呈现验收

状态:已完成最终功能入口复核,调度余项未完成,整体进度 3/7。此文件随实现提交;完整目标仍包含后续真实服务、迁移和集成验收。

范围与直接证据

原要求 代码与验证入口 本次结果
导入、深复制逐步加入并允许编辑 imports.ts、canvas-runtime/duplicate.ts;imports.test.mjs、imports-engine.test.mjs、import-document-stream.test.mjs、duplicate*.test.mjs;实际页面文件选择/工具栏 Node 与页面检查通过。SHA 完成前可显示和编辑;完整校验完成且对应 Root 持久化后才发送。单项失败保留已加入内容并报告 partial。复制保留原图、新建身份,父层新增连线,复用合法资源且不自动启动 run。
loader 旧捕获与后续编辑/ACK 协调 loading.ts、engine.ts;loading-engine.test.mjs、浏览器存储和实际页面 当前 loading v1–v6 路径、未读 tail、undo/redo、重开、取消及源校验检查通过。旧数据不覆盖后来的编辑/ACK;已声明的 partial 状态保留。
公共 hooks 和局部订阅 canvas-bindings/react.ts、canvas-bindings;react-hooks-fixture.tsx、renderer.integration.mjs --hooks-only 同一最终源码的 StrictMode 入口 10 项通过;包括 owner 切换、engine close、资源句柄与 unloaded/absent。普通字段与 ACK 的无关投影复用由实际页面计数验证。
输入、呈现与合作调度 frame queue、scene/paint projection、retained projection;frame-queue.test.mjs、retained-projection.test.mjs、实际页面与生产规模入口 页面验证拖动最终位置、IME、Portal、detach、未知焦点与订阅取消。生产万元素早/中/尾段输入与副本捕获隔离通过;性能仍有限制,见下文。

所有 *.test.mjs 均位于 tests/headless/,源码位于 src/lib/ 或 src/components/canvas/。每个测试文件中的断言决定其覆盖范围;通过总数不代表 Draft 的 T01–T36 或整个项目已经完成。

编码与发布边界

  1. writePrefix 是有序单 writer,逐个保存 Root,异步编码不会跳过中间 Root。
  2. 外部对象、getter、custom toJSON 和浅冻结值在第一次让出前按原 codec 捕获;私有容器只证明成员固定,内部未知值仍需捕获。
  3. core 的 JSON 脱离、深冻结元素可以延后逐字段编码。需要标准 Object/Array 原型且没有继承的 toJSON;每次未知值捕获后重新检查环境。外部回调不能改变已经捕获的前项,也不能让后项错误沿用旧环境。
  4. 标量归一化、UTF-8 计数、history/import/pending 容器与首次元素遍历共用软预算。已完成的深不可变编码可复用,但不能省略 unsafe occurrence 的求值。
  5. 编码、调度或存储失败保留待存 Root;持久化没有确认,不解除网络发送屏障。旧 Root 与编码期间的新编辑保持各自内容。
  6. journal 比较先判断子值是否相同,再为变化项分配路径,避免为共享的整个前缀创建临时数组。patch 顺序与字节语义不变。

recovery-encoding.test.mjs 验证首次归一化确实在 yield 间发生、继承行为、外部回调、Proxy trap 次数、UTF-8、冷/热深度边界;engine.test.mjs 以 17000 元素验证暂停编码期间编辑、逐 Root 落盘和发送屏障。journal-delta.test.mjs 验证精确重放及属性顺序;浏览器检查验证真实 IndexedDB 重开。

可复现命令

node --test tests/headless/*.test.mjs
npm run typecheck -- --incremental false
node tests/headless/renderer.integration.mjs
node tests/headless/renderer.integration.mjs --turbopack
node tests/headless/renderer.integration.mjs --hooks-only
node tests/headless/browser-storage.mjs
node tests/headless/package.integration.mjs
HEADLESS_PERFORMANCE_COUNT=10000 HEADLESS_PERFORMANCE_EDIT_DURING_COPY=1 HEADLESS_PERFORMANCE_REPORT=/private/tmp/headless-step4-production-10000.json node tests/headless/renderer.integration.mjs --performance --production --turbopack

性能入口须在其它构建/测试结束后单独执行;功能检查可并行。这里验证真实 Chrome、IndexedDB、Web Locks 和实际前端,但 HTTP 为隔离 fixture,不能据此声称已完成真实 Foundry 集成。

本次运行结果(2026-11-11)

  • Node:780 项通过;全量前端 TypeScript 检查通过。
  • 实际页面:webpack 51 项、Turbopack 51 项通过;公共 hooks 10 项通过。
  • 浏览器存储:57 组通过;SDK:263 个打包文件,类型、独立消费和编译后的浏览器/Worker 检查通过。
  • webpack 曾在全部断言结束后被 Chrome 日志管道阻止退出。renderer.integration.mjs 现于 Chrome 退出后释放 stdio;重新运行的 51 项检查自动正常退出。
  • 生产规模环境:本机 arm64、macOS 15.6、Node 23.10.0、Chrome 157.0.8103.39,Next production Turbopack;无并行构建/测试、无计时代码插桩。
  • 10000-child 展开分区深复制:首副本呈现 799.5ms、本地完成帧 36264.8ms、加入并同步 36469.9ms;帧间隔 P95 33.4ms/max316.6ms;25 次 longtask,max341ms/total1869ms。
  • early 五次 input→两次 rAF:50.5/31.3/22.6/20.9/41.3ms;middle(5255 项)21.5ms、tail(9131 项)39.4ms。全部发生于复制活跃期间,DOM/focus 保留;中尾 CDP 往返约18.1/27.4ms。它们不含精确的派发前排队延迟。
  • 服务端最终 20005 元素/3 canvas;原/新父层边、原文后续输入、副本旧快照、pan 后副本挂载通过。样本呈现时挂载35节点,全过程最大136,pan 后28;屏幕外 IME/Portal 各保留1,独立应用面板不额外保活,runStartsDuringScenario=0。

原始报告 /private/tmp/headless-step4-production-10000.json 和同名 PNG 为本次本机观察;命令与断言已保存在仓库,可独立复现。单次运行不同 adaptive 批次和 GC 负载,不能比较前轮26.2秒而宣称确定改善或回退,更不能说所有停顿已解决。

明确剩余项

复制规划的 createDuplicatePlanner().checkpoint() 当前返回 freeze(clone(state));它具有 JSON 脱离性质,但这项来源尚未传递给 codec。preparation.planner / source.plan 因而仍可能经未知父对象走同步 normalization。下一项是由 core 提供同元素一致的、不可伪造的 JSON 脱离来源事实,并在 runtime 自建 checkpoint envelope 中保留这项事实,补首次 checkpoint 编码、外部回调与恢复测试。不能仅以 Object.freeze 推定来源,也不能跳过完整 checkpoint/发送屏障。

此项完成并复验前,Step 4 保持未完成。本文件只确认已列入口和观察,未完成项不能转移到后端阶段来虚增进度。

调度限制与后续分工

6ms 是合作调度软目标。捕获成员引用、未知值的同步 JSON 语义、单个字符串/native 操作、原子模型发布和 GC 仍可能超过一个时间片。未知调用不能假冒不可变值以换取响应速度;也不能把普通循环停顿一概称为 GC。测试测量 input 到两次 rAF;CDP 往返另含传输和驱动时间,均不是精确的输入派发前排队延迟。

未登记的第三方 Portal/未知输入 owner 保留明确的兼容回退;任意全局 Root selector、结构变化和未知 ACK 不保证 O(1)。renderer 不保存第二份业务文档,不为裁剪丢弃完整模型。

下一阶段由服务/集成工作负责真实 Foundry 协议、权限、迁移、冻结请求幂等与恢复联调,并沿用现有远程 CI。分支推送不等于主线合并或部署,仍需单独报告。