Skip to content

fix(loader): preserve virtual resource identity in Editor Preview - #3079

Open
luzhuang wants to merge 1 commit into
feat/migrate-2.0from
fix/migrate-preview-local
Open

fix(loader): preserve virtual resource identity in Editor Preview#3079
luzhuang wants to merge 1 commit into
feat/migrate-2.0from
fix/migrate-preview-local

Conversation

@luzhuang

@luzhuang luzhuang commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

分支关系

本 PR 已直接重建在最新 feat/migrate-2.0@f6da19d79,不再依赖 #3078,也不包含任何 clone 改动。

最新基线已经包含 #3074 的 Shader payload 判型:一次 text 请求后由 payload 决定预编译 JSON 或 ShaderLab 源码,并以逻辑路径作为相对 #include 基准。因此本 PR 不再重复修改 ShaderLoader,也不复制 Shader fixture。

为什么要改

Editor Preview 中一个资源有两个正交事实:

  • virtualPath 是稳定逻辑身份,用于引用、报错定位和推导同目录依赖
  • path 是 Blob/CDN/构建产物等物理传输地址,只负责实际读取字节

此前 ResourceManager.baseUrl 会把已经命中 VFS 的逻辑路径改写成普通 HTTP 地址。SpriteAtlas 再根据该地址推导页面路径时无法命中 VFS。相对逻辑路径还通过 file://<path> 计算,URL parser 把首段当成 hostname 并小写,导致 SpriteAtlas/... 变成不同的 spriteatlas/... key。

初版方案曾公开增加 LoadItem.resolvedUrl。全链路审查后已删除:物理地址已经由虚拟资源表与 ResourceManager 拥有,不应再复制到 Loader 输入形成第二份状态。

修复后的契约

  • 注册过的虚拟资源在 LoadItem.url 中始终保留逻辑 virtualPath
  • baseUrl 只解析未命中 VFS 的普通相对 URL
  • ResourceManager 唯一拥有 virtualPath -> path 映射、cache/loading key 与 I/O 请求边界
  • Loader 通过逻辑 URL 请求;ResourceManager 在 I/O 边界映射到物理地址
  • 相对虚拟路径在 file:/// 下按 path segment 解析,保留大小写与 leading-root 语义
  • SpriteAtlas 继续从既有逻辑 item.url 推导页面;不增加 loader-specific transport 分支
  • Shader 行为原样继承 fix(loader): decouple shader format from physical path #3074,payload 拥有表示格式,逻辑 URL 拥有 include 基准
  • Texture 首次加载与设备恢复共用一个 ArrayBuffer-to-Image decoder,由它统一拥有 object URL 生命周期和带资源身份的错误

实际链路

Editor manifest { virtualPath, path, type }
  -> ResourceManager { logical identity, physical request owner }
  -> loader receives logical LoadItem.url
  -> dependent logical path
  -> ResourceManager maps it to the physical request URL

例如 Atlas 内容中的 ./auto-atlas_image_0.tex 会先由逻辑 Atlas 路径推导出 SpriteAtlas/Art/UI/auto-atlas_image_0.tex,再查 VFS 映射到对应 Blob/CDN URL;不会从 Blob URL 猜目录。

实际改动

  • ResourceManager 在 VFS 命中时保留 loader 输入的逻辑身份
  • Utils.resolveAbsoluteUrl 修复相对路径首段被 hostname 规则小写的问题
  • LoadItem.url 文档明确逻辑身份契约;没有新增 resolvedUrl 字段
  • Texture 两套 Image/Object URL 状态机收敛为一个 helper
  • 新增完整 ResourceManager -> SpriteAtlas -> page 映射测试与 Texture restoration 错误测试
  • 删除重基后已由基线覆盖的 Shader 改动和测试,以及无行为差异的 SpriteAtlas production 改动

TDD 与验证

  • 旧实现下,边界用例分别证明了 VFS key 首段被小写、baseUrl 覆盖逻辑身份、Texture restoration 仅返回原始浏览器 Event
  • 聚焦浏览器测试:5 files passed,28 tests passed
  • 全量浏览器测试:137 files passed,1758 tests passed
  • pnpm run b:module:通过
  • pnpm run b:types:15 个 package project 全部通过
  • pnpm lint:0 error;仓库既有 1978 warnings 保持不变

发布边界

0.0.0-experimental-2.0-migrate.5 已从更早的分支状态发布,不包含本次重基后的独立 loader 提交;包含该修复的发布必须使用新版本。

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • ^(dev/)?\d+.\d+$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 86ef073d-be37-4e59-92bd-7f2701b7b286

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/migrate-preview-local

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 28, 2026

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 尘小沫

结论

feat/migrate-2.0...f83b1902167f244571fae82bb047c76ac8eb0654 的 5 个提交做了首次完整增量审查。把虚拟资源的逻辑身份与物理传输地址拆开,方向正确;但当前仍有 1 个 P1 会在 baseUrl 与 VFS 同时启用时绕过虚拟资源映射,另有 3 个 P2。实际 review 动作为 REQUEST_CHANGES,目标 HEAD 为 f83b1902167f244571fae82bb047c76ac8eb0654。自动 CR 不替代人工 Reviewer 的合入门禁,修复后仍需人工审核确认。

问题

  1. [P1] 保留虚拟资源的逻辑 item.url,不要让 baseUrl 把它改写成第三种混合地址packages/core/src/asset/ResourceManager.ts:364-370 先命中了 virtualResourceEntry,随后仍无条件把相对 assetBaseURLbaseUrl 合并;而 packages/loader/src/SpriteAtlasLoader.ts:28,36,58 正依赖 item.url 作为 atlas 与页面的虚拟身份。触发方式是同时设置 resourceManager.baseUrl 并注册 SpriteAtlas/Migrated/ui.atlas -> blob:...atlas 及其页面映射:传给 loader 的 item.url 会变成 https://base/.../SpriteAtlas/Migrated/ui.atlas_request() 和子页面 load() 都无法命中以 SpriteAtlas/... 为 key 的 VFS,最终错误请求 base URL。应保留 ResourceManager 为唯一解析 owner:命中 virtualResourceEntry 时让 item.url 始终保持 assetBaseURL,仅把 virtualResourceEntry.path 写入 resolvedUrl/cache key;只有未命中 VFS 的相对 URL 才应用 baseUrl。同时把现有仅断言 loader type 的 baseUrl 用例改成真实 atlas 链路测试,断言 atlas 配置与页面最终都请求各自的物理地址。

  2. [P2] 对 Stage-3 无法被 clone traversal 消费的字段显式拒绝,不要静默注册packages/core/src/clone/CloneManager.ts:14-37 的 context 接受 string | symbol,且没有检查 Stage-3 context 的 private/static;下游 CloneUtil._deepCloneObjectComponentCloner.cloneComponent 却只用 Object.keys(source)。因此 @deepClone/@assignmentClone 用在 private、static 或 symbol-named field 时 TypeScript 可以进入这条新协议,但 mode 永远不会被消费,显式 clone intent 静默退化。最小方向是把这些 unsupported context 在 decorator 边界明确报错,并补负向契约测试;若确实要支持 symbol field,则只扩展 enumerable own-symbol traversal,仍应明确拒绝 private/static,不能增加 fallback 或第二条 clone 路径。

  3. [P2] 修正本次新增注释中的协议事实与格式packages/core/src/clone/CloneManager.ts:9 写成 Stage-3 field decorator 接收“initial value”,实际第一参数是 undefined,初始字段值只会传给 decorator 返回的 initializer;packages/core/src/asset/LoadItem.ts:16-18 又宣称 resolvedUrl 可用于解析相对文件,但 SpriteAtlasLoader.ts:24-28 已正确说明 Blob 等物理 URL 不能作为兄弟资源基址。请把契约统一为:url 是相对依赖的逻辑基址,resolvedUrl 仅是 ResourceManager 派生的物理传输/格式判定地址。此外 CloneManager.ts:30-32ShaderLoader.ts:14-15SpriteAtlasLoader.ts:24-27Utils.ts:85-88 的新增 // 注释块末尾句号应按仓库注释规范移除。

  4. [P2] 让 PR 元信息覆盖独立的 clone 协议变更 — 标题与 Summary 只描述 virtual resource identity,但首个提交同时改变了三个公开 clone decorator 的调用协议和运行时存储时机。这与 loader 修复是可独立理解、回滚的变更单元。优先拆分;若迁移预览分支必须合并交付,至少在标题/Summary、行为变化与验证中明确列出 Stage-3 decorator 支持及其边界,避免 release/changelog 和回滚决策漏掉这项公开 API 行为。

架构、熵增与测试治理

上游 Editor Builder/project manifest 分别拥有 virtualPath(逻辑身份)和 path(物理产物);Engine 内应由 ResourceManager 唯一拥有映射与 cache key,loader 只消费规范化结果;下游 ShaderLoader 用物理后缀选择 .shaderc 协议,SpriteAtlasLoader 用逻辑路径派生兄弟资源。改动新增 resolvedUrl 后,本应从一个含混 URL 收敛成两项正交事实,但保留的 baseUrl 改写让 item.url 仍在“逻辑身份/普通物理 URL”间切换,形成第三种混合语义;删除虚拟路径上的这次改写后,数据流可收敛为 manifest -> ResourceManager -> { logical url, physical resolvedUrl } -> loader,无需同步层或 legacy fallback。

Clone 链上,legacy decorator 与 Stage-3 decorator 是真实编译协议边界,两者复用 _registerFieldMode 和同一 clone traversal,没有新增平行 clone 状态机;需要删除的是对不可消费 context 的静默路径。现有测试没有为了旧契约保留生产 compatibility branch,也没有应删除的 legacy fixture;但 SpriteAtlas 测试直接调用 loader,绕过了本次最关键的 ResourceManager 规范化边界,Stage-3 测试也只覆盖 string-named instance field。应按上述公开链路与负向边界补测,不要用 mock/兼容分支继续掩盖 owner 漂移。

@luzhuang luzhuang changed the title fix: preserve virtual resource identity in Editor Preview fix(loader): preserve virtual resource identity in Editor Preview Jul 28, 2026
@luzhuang
luzhuang changed the base branch from feat/migrate-2.0 to fix/migrate-stage3-clone-decorators July 28, 2026 07:36

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 尘小沫

结论

f83b1902167f244571fae82bb047c76ac8eb0654...865fa27c9976a90479a4a62eeb8bf0cfda9c503d 的 1 个增量提交做了复审,并按当前 fix/migrate-stage3-clone-decorators...865fa27c9976a90479a4a62eeb8bf0cfda9c503d 重新核对了完整 loader diff。上一轮 baseUrl + VFS 的 P1 已修复;但本轮沿 Shader 下游继续追踪后发现 1 个新的 P1:源码 Shader 的逻辑路径仍被物理 Blob URL 覆盖,导致相对 #include 解析失败;另有 1 个上轮未闭环的注释 P2。当前阻塞级别为 P1,实际 review 动作为 REQUEST_CHANGES,目标 HEAD 为 865fa27c9976a90479a4a62eeb8bf0cfda9c503d。自动 CR 不替代人工 Reviewer 的合入门禁,修复后仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 865fa27c9976a90479a4a62eeb8bf0cfda9c503d 修复:ResourceManager 命中 VFS 时保留 item.url = assetBaseURL,只把物理地址写入 resolvedUrl/cache key;新的 SpriteAtlas 用例也从 ResourceManager.load() 贯通验证了 atlas 与页面各自命中物理地址。
  2. Stage-3 decorator 对不可消费 context 静默注册 — 当前 PR 已改为依赖 #3078,base 是 fix/migrate-stage3-clone-decorators;clone 文件不再属于本 PR 的实际 diff,因此该项对 #3079 不适用,需在依赖 PR 独立闭环。
  3. LoadItem 对逻辑/物理 URL 的协议说明失真 — 已修复:url 明确承载虚拟资源身份,resolvedUrl 明确只用于直接传输与格式判定、不能作为虚拟兄弟资源基址。
  4. PR 元信息遗漏独立 clone 协议变更 — 已通过依赖 #3078、调整 base,并在 PR body 中单列 Dependency/Contract/Change/Verification 收口;当前标题与实际 loader diff 一致。

问题

  1. [P1] Shader 只应用物理 URL 判型,请求和相对 #include 基址必须继续使用逻辑 URLpackages/loader/src/ShaderLoader.ts:16-28item.resolvedUrl 赋给同一个 url,随后既传给 ResourceManager._request(),又传给 Shader.create(..., path)。触发方式是注册源码 Shader Shader/Migrated/source.shader -> blob:https://.../source,且源码包含 #include "./common.glsl"Shader.create 的公开契约明确第三参数用于解析相对 include(packages/core/src/shader/Shader.ts:49,97),下游 packages/shader-compiler/src/Preprocessor.ts:35-40 会执行 new URL(includeName, basePathForIncludeKey);Blob URL 不能作为相对 URL 基址,这里会抛 TypeError: Invalid URL,Editor Preview 中该 Shader 无法编译。同时,_request(resolvedUrl) 会让已经解析好的物理地址再次经过 _getRemoteUrl,当物理地址恰好也是另一个 VFS key 时会发生二次映射。应保留 ResourceManager 为唯一映射 owner:分别取 logicalUrl = item.url!transportUrl = item.resolvedUrl ?? logicalUrl,只用 transportUrl 判断 .shaderc,两条请求都调用 _request(logicalUrl, ...),源码分支把 logicalUrl 传给 Shader.create。对应地,重写 tests/src/loader/ShaderLoader.test.ts:16-28:不要直接构造 LoadItem 调内部 loader 并断言物理地址进入 _request;从 resourceManager.load(virtualPath) 走完整 VFS 链,断言 _requestByRemoteUrl 收到物理地址,并补一个 Blob 物理地址 + 相对 include 的源码 Shader 用例。无需增加 compatibility branch 或第二条解析路径。
  2. [P2] 清理本轮仍未闭环的新增 // 注释句号packages/core/src/Utils.ts:85-88packages/core/src/asset/ResourceManager.ts:364-366packages/loader/src/ShaderLoader.ts:14-15packages/loader/src/SpriteAtlasLoader.ts:24-27 的新增注释块仍以句号结尾;tests/src/loader/ShaderLoader.test.ts:22tests/src/loader/SpriteAtlasLoader.test.ts:34@ts-ignore 说明也同样如此。按仓库规范,单行/连续 // 注释末尾不加句号;统一移除即可。LoadItem 的多行 TSDoc 句号应保留。

架构、熵增与测试治理

上游 Editor manifest 仍是 { virtualPath, path } 的事实 owner,Engine 内 ResourceManager 应唯一拥有 VFS 映射、cache key 和 { logical url, transport resolvedUrl } 的机械派生;下游 SpriteAtlas 已正确使用逻辑 URL 派生页面、由 _request/load 回到 ResourceManager 映射,Texture 也沿用同一入口。新增一个不持久化的 resolvedUrl 派生值本身把原先含混的单 URL 拆成两个正交概念,没有形成第三份真相;但 Shader 当前又把两者合回同一局部变量,并让物理地址重入逻辑映射,实际新增了第二条转换路径。保留 ResourceManager owner、删除 Shader 的物理地址重映射并恢复逻辑 include 基址后,数据流才能收敛为 manifest -> ResourceManager -> { logical, transport } -> loader

测试侧,新的 SpriteAtlas 用例已经替换了绕过规范化边界的内部直调用,能够反向守住上一轮 P1;Shader 用例却仍直接调用 loader,并把“物理地址进入 _request”固化成断言,属于按新公开契约应重写的失效 fixture。应删除这条错误断言并改走公开加载链,而不是为了它保留 wrapper、fallback、镜像状态或第二条 URL 转换。除 Shader 这条路径外,本轮未发现新增兼容分支、平行状态机或可删除的持久镜像状态。

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 尘小沫

结论

865fa27c9976a90479a4a62eeb8bf0cfda9c503d...18edc9f85baeaaebce1985445b7fa09a71d20600 的 1 个增量提交做了复审,并按当前 fix/migrate-stage3-clone-decorators...18edc9f85baeaaebce1985445b7fa09a71d20600 重新核对了完整 loader diff。上一轮 Shader 请求与 include 基址混用物理 URL 的 P1 已修复;但替代实现重新用物理地址后缀决定 Shader 编码,和已合入 dev/2.0#3074 契约冲突,opaque CDN/hash 地址下的预编译 Shader 仍会走错解析器;另有 2 个 P2。当前阻塞级别为 P1,实际 review 动作为 REQUEST_CHANGES,目标 HEAD 为 18edc9f85baeaaebce1985445b7fa09a71d20600。自动 CR 不替代人工 Reviewer 的合入门禁,修复后仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 865fa27c9976a90479a4a62eeb8bf0cfda9c503d 修复:VFS 命中时保留 item.url = assetBaseURL,cache key 与实际请求仍使用映射后的 path
  2. Stage-3 decorator 对不可消费 context 静默注册#3079 已改为依赖 #3078,clone 文件不在当前实际 diff 中;该项对本 PR 不适用。
  3. LoadItem 的逻辑/物理 URL 契约失真及派生状态泄漏 — 已由 18edc9f85baeaaebce1985445b7fa09a71d20600 修复:resolvedUrl 从公开类型、ResourceManager 写入和测试 fixture 中全部删除,物理地址只保留在虚拟资源表与请求边界。
  4. PR 元信息遗漏独立 clone 协议变更 — 已通过依赖 #3078、调整 base,并重写 PR body 的 Dependency/Contract/Change/Verification 收口。
  5. Shader 把物理 URL 用作请求输入与相对 #include 基址 — 已由 18edc9f85baeaaebce1985445b7fa09a71d20600 修复:两条请求都使用逻辑 url,源码分支也把逻辑 url 传给 Shader.create;新测试从 ResourceManager.load() 贯通验证了物理请求地址和逻辑 include 基址。

问题

  1. [P1] 不要再从物理 URL 后缀推断 Shader 编码,编码事实应由已取回的 payload 决定packages/loader/src/ShaderLoader.ts:15-20 额外读取 _getRemoteUrl(url) 并用 /\.shaderc.../ 选择 JSON/Text 分支。当前 Preview 的 Blob upload 会附加 #name,但这只是一个上游实现细节;Builder 的 CDN upload 直接保留服务端 URL,公开 { virtualPath, path } 契约也允许 opaque/hash 地址。触发方式是 Shaders/custom.shader -> https://cdn.example.com/assets/8fca12?version=1,内容为预编译 JSON:正则返回 false,代码把 JSON 字符串交给 Shader.create 的 ShaderLab 源码解析器,资源加载失败。这个场景已经由合入 dev/2.0#30748fe06577d36f92a226b1031e7613f925aaac72e4fix(loader): decouple shader format from physical path)明确修复并用 opaque physical path 反向验证;当前分支是在恢复其根因。应保留 ResourceManager 为唯一 virtualPath -> path 映射 owner,删除 remoteUrl、私有 _getRemoteUrl 访问、后缀正则和 JSON/Text 双请求分支,直接采用 #3074 的单次 text 请求 + payload 判型:JSON payload 交给 _createFromPrecompiled,其余源码交给 Shader.create(code, undefined, logicalUrl)。同时把 tests/src/loader/ShaderLoader.test.ts:16-40#outline.shaderc fixture 改成无扩展 opaque 地址并返回 JSON 文本;不要再用带后缀 fixture 固化已退场的 transport 命名契约。
  2. [P2] 统一 Texture 首次解码与设备恢复的 Image 失败路径packages/loader/src/TextureLoader.ts:103-105 已把初次图片解码失败改为包含逻辑 URL 与字节数的 Error,但同一数据流下游 TextureContentRestorer.restoreContent() 的平行 Image 解码仍在 :154-165 直接 reject 原始 Event。资源在首次加载后、设备恢复前若 CDN 内容变化或映射产物损坏,诊断信息仍会丢失;同一个字节到 Image 的转换也继续维护两套 Blob/Image/onload/onerror/revokeObjectURL 状态机。应保留逻辑 urlbuffer.byteLength 为唯一诊断事实,提取一个被初次加载与 restorer 共用的 Image 解码 helper,删除两份事件/URL 生命周期处理,并补失败回归测试;不要再加 wrapper 或兼容分支。
  3. [P2] 清理仍未闭环的新增 // 注释句号packages/core/src/Utils.ts:85-88packages/core/src/asset/ResourceManager.ts:364-366packages/loader/src/SpriteAtlasLoader.ts:24-27,以及 tests/src/loader/SpriteAtlasLoader.test.ts:39,43 的新增连续 // / @ts-ignore 注释仍以句号结尾。按仓库规范统一移除;LoadItem 的多行 TSDoc 句号应保留。ShaderLoader 的对应注释应随问题 1 的错误判型路径一起删除,而不是继续润色。

架构、熵增与测试治理

上游 Editor manifest 是 { virtualPath, path, type } 的事实 owner:virtualPath 负责稳定身份,path 只负责传输,Preview 为 Blob URL 附加文件名并不是协议;Engine 内 ResourceManager 应唯一拥有映射、cache/loading key 与请求边界。删除 resolvedUrl 后,loader 输入从“逻辑 URL + 派生物理 URL”两项收敛回一个逻辑身份,没有新增持久镜像状态,SpriteAtlas 页面也已经沿 logical atlas -> logical page -> ResourceManager -> physical request 正确闭环。

当前剩余熵增集中在两个落点:Shader 又新增一次私有映射查询、一个 transport 后缀正则和 JSON/Text 两条请求/解析路径,把 payload 编码事实错误转移给地址命名;应保留 payload 为编码 owner,并删除这整条后缀判型路径。Texture 则让同一 Image 转换继续存在两套错误与对象 URL 生命周期 owner;应合并为单一 helper。测试侧,新的 Shader/Atlas 用例已经改走公开 ResourceManager.load() 链路,这是正确方向;但 Shader 的带 .shaderc fragment fixture 锁定了错误的 transport 契约,必须按 #3074 的 opaque path + JSON payload 公开契约重写。除上述两处外,未发现新增 compatibility branch、legacy fallback、平行加载状态机或为旧测试保留的生产 wrapper。

@luzhuang

Copy link
Copy Markdown
Contributor Author

已在 bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 收掉当前 head 的复审问题:

  • P1:Shader 删除物理 URL 后缀判型,恢复 fix(loader): decouple shader format from physical path #3074 的单次文本请求 + payload 判型;新增 opaque CDN URL 回归测试,同时保留逻辑路径作为 #include 基准。
  • P2:Texture 初次加载与内容恢复共用同一个 ArrayBuffer-to-Image 解码边界;新增恢复阶段错误携带逻辑资源路径的浏览器测试。
  • 相关链路 121 tests passed,b:typesb:module、完整 lint(0 error)均通过。

PR 描述和仓库内工程记录已同步更新,请基于当前 head 重新 review。

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 尘小沫

结论

18edc9f85baeaaebce1985445b7fa09a71d20600...bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 的 1 个增量提交做了复审,并按当前 fix/migrate-stage3-clone-decorators...bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 重新核对了完整 loader diff。Shader 已恢复 #3074 的 payload 判型契约,Texture 两套 Image 解码状态机也已收敛;本轮未发现新的 P0/P1,但上一轮注释规范 P2 尚未完全闭环。当前阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 865fa27c9976a90479a4a62eeb8bf0cfda9c503d 修复:VFS 命中时保留逻辑 item.url,cache/loading key 与实际请求继续使用映射后的物理 path
  2. Stage-3 decorator 对不可消费 context 静默注册#3079 已依赖 #3078 并把 base 指向 fix/migrate-stage3-clone-decorators,clone 改动不在当前实际 diff 中,因此对本 PR 不适用。
  3. LoadItem 泄漏派生物理 URL 与双源状态 — 已由 18edc9f85baeaaebce1985445b7fa09a71d20600 修复:resolvedUrl 已从公开类型、ResourceManager 写入与测试 fixture 中删除。
  4. PR 元信息遗漏独立 clone 协议变更 — 已通过依赖 #3078、调整 base,并在 PR body 中明确 Dependency、Contract、Change 与 Verification 收口。
  5. Shader 把物理 URL 用作请求输入与相对 #include 基址 — 已由 18edc9f85baeaaebce1985445b7fa09a71d20600 修复:请求使用逻辑 URL,源码编译也保留逻辑路径作为 include 基址。
  6. Shader 从物理 URL 后缀推断编码 — 已由 bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 修复:删除 _getRemoteUrl、后缀正则与 JSON/Text 双请求,恢复单次 text 请求后按 payload 判型;opaque CDN 回归用例可反向守住该契约。
  7. Texture 首次解码与设备恢复维护平行 Image 状态机 — 已由 bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 修复:两条路径共用 decodeImage,对象 URL 生命周期与包含逻辑 URL、字节数的诊断错误由同一 helper 统一拥有;恢复失败测试可证伪旧的原始 Event 路径。

问题

  1. [P2] 清理仍未闭环的新增 // 注释句号packages/core/src/Utils.ts:85-88packages/core/src/asset/ResourceManager.ts:364-366packages/loader/src/SpriteAtlasLoader.ts:24-27,以及 tests/src/loader/SpriteAtlasLoader.test.ts:39,43 的新增连续 // / @ts-ignore 注释仍以句号结尾。上一轮指出的 Shader 注释已随错误判型路径删除,但这些落点没有变化;按仓库规范统一移除末尾句号即可。LoadItem 的多行 TSDoc 句号应保留。

架构、熵增与测试治理

沿本次直接链路复核后,上游 Editor manifest 继续拥有 { virtualPath, path, type } 的输入事实,Engine 内 ResourceManagervirtualPath -> path 映射、cache/loading key 与 I/O 请求边界的唯一 owner;下游 SpriteAtlas 只从逻辑路径派生页面,Shader payload 是源码/预编译表示的 owner,Texture 的 decodeImage 是 Image 事件和对象 URL 生命周期的 owner。相较上一 head,Shader 删除了 1 次私有映射查询、1 个 transport 后缀判型和 JSON/Text 两条请求路径;Texture 将 2 套解码状态机合并为 1 套,没有新增持久状态、同步层或第三份真相。

测试侧,Shader 的 fixture 已从带 .shaderc 后缀的物理地址改为 opaque CDN URL,并从公开 ResourceManager.load() 链路验证物理请求、payload 解析与逻辑 include 基址;Texture 恢复失败用例会在旧实现返回原始浏览器 Event 时失败。未发现为旧测试保留的 compatibility branch、legacy fallback、wrapper、镜像状态或第二条转换/校验路径,也没有需要随新契约删除的残留 fixture、mock 或 snapshot。

@luzhuang
luzhuang force-pushed the fix/migrate-stage3-clone-decorators branch from 51dffa3 to 2b82411 Compare July 28, 2026 09:46
@luzhuang luzhuang removed the documentation Improvements or additions to documentation label Jul 28, 2026
@luzhuang
luzhuang force-pushed the fix/migrate-preview-local branch from bc9a989 to 3719142 Compare July 28, 2026 09:55
@luzhuang
luzhuang changed the base branch from fix/migrate-stage3-clone-decorators to feat/migrate-2.0 July 28, 2026 09:56
@luzhuang
luzhuang force-pushed the fix/migrate-preview-local branch from 3719142 to 6291edd Compare July 28, 2026 09:58

Copy link
Copy Markdown
Contributor Author

已解耦并直接重建到最新 feat/migrate-2.0@f6da19d79,当前 head:6291edd1df4d9380bbf98814c97ba7409b8c6330

  • 不再依赖 fix(core): support Stage-3 clone decorators #3078,不包含 clone diff
  • 最新基线已包含 fix(loader): decouple shader format from physical path #3074,因此删除重复 Shader production/test diff
  • 删除无行为差异的 SpriteAtlas production 改动;保留完整 ResourceManager -> Atlas -> page 行为测试
  • VFS 命中时保留逻辑 LoadItem.url,物理映射仍由 ResourceManager 唯一拥有
  • 相对虚拟路径保留大小写与 leading-root 语义
  • Texture 初次加载与 restoration 共用一个 Image/object-URL 解码边界
  • 已收掉上一轮注释格式 P2;PR 中不包含工程 note

本地验证:聚焦 5 files / 28 tests;全量 137 files / 1758 tests;b:moduleb:types、lint(0 error)通过。请基于当前 head 重新 review。

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 尘小沫

结论

上一轮 checkpoint bc9a989 之后分支已重建,旧、新 head 历史发散;本轮因此以实际 PR 范围 f6da19d...6291edd 的单个提交、8 个文件做了完整增量复审,并重新核对当前 tree 的 loader 上下游。重建已移除 clone 与重复 Shader diff,VFS 逻辑身份、相对路径和 Texture 解码 owner 均已收敛;本轮未发现新的 P0/P1/P2。当前阻塞级别为 ,实际 review 动作为 COMMENTED,目标 HEAD 为 6291edd。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已在当前 6291edd 闭环:VFS 命中时 LoadItem.url 保留 virtualPath,cache/loading key 与 I/O 请求继续由 ResourceManager 从表中机械映射到物理 path;Atlas 链路测试贯通验证了 atlas 与 page 各自命中物理地址。
  2. Stage-3 decorator 对不可消费 context 静默注册 — 当前 head 直接建立在 feat/migrate-2.0@f6da19d79673cfe8f8a5ffa739a82a7ebdeb4619,不再依赖 #3078,单提交及完整 diff 均无 clone 改动,因此对本 PR 不适用。
  3. LoadItem.resolvedUrl 泄漏派生物理地址并形成双源 — 当前公开类型、ResourceManager 写入及测试 fixture 均无该字段;物理地址只保留在虚拟资源表以及 cache/I/O 边界。
  4. PR 元信息遗漏独立 clone 协议变更 — 重建后 clone 已完全移出实际 diff,标题、正文、单提交和 8 文件变更范围现已一致。
  5. Shader 把物理 URL 用作请求输入与相对 #include 基址 — 最新基线已包含 #3074;当前 ShaderLoader 仍以逻辑 URL 请求并传给 Shader.create 作为 include 基址,本 PR 未复制旧 Shader production/test 改动。
  6. Shader 从物理 URL 后缀推断编码 — 最新基线继续采用单次 text 请求后按 payload 判型;opaque 物理地址契约由基线测试拥有,当前 PR 没有恢复后缀正则、JSON/Text 双请求或私有映射查询。
  7. Texture 首次解码与设备恢复维护平行 Image 状态机 — 当前 decodeImage 同时服务初次加载与 restoration,统一拥有 Image 事件、object URL 释放和包含逻辑资源身份与字节数的错误;恢复失败测试可反向证伪旧的原始浏览器 Event 路径。
  8. 新增单行注释末尾句号未清理 — 当前 Utils、ResourceManager 与 Atlas 测试新增的连续 // / @ts-ignore 注释均已按规范移除末尾句号;LoadItem 的多行 TSDoc 正确保留句号。

架构、熵增与测试治理

沿实际改动向上游一层核对,Editor project manifest / ProjectLoader 拥有 { virtualPath, path, type } 输入事实,ResourceManager 是 virtualPath -> path 映射、loader 选择、cache/loading key 与 I/O 请求边界的唯一 owner;Utils.resolveAbsoluteUrl 只机械派生逻辑依赖路径,不持有映射状态。向下游一层,SpriteAtlas 从逻辑 atlas 路径派生 page,再回到 ResourceManager 映射;Shader 由 payload 拥有表示格式、逻辑 URL 拥有 include 基址;Texture 的 decodeImage 拥有浏览器 Image/object-URL 生命周期。

相较基线,owner 数量没有增加:ResourceManager 只收紧 1 个 VFS/baseUrl 分支,路径解析仍是 1 条标准 URL 转换,Texture 的 2 套 Image 状态机合并为 1 套;没有新增持久状态、镜像字段、同步层、wrapper、legacy fallback、兼容分支或第三份真相。测试侧,Atlas 用例从公开 ResourceManager.load() 贯通逻辑身份、相对派生与两个物理请求边界;Texture restoration 用例守住统一错误契约;基线已拥有的 Shader 契约没有在本 PR 重复 fixture/mock。未发现为旧测试保留第二条生产转换/校验路径,也没有应随当前契约继续删除或重写的残留测试、fixture 或 snapshot。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants