Skip to content

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

Open
luzhuang wants to merge 11 commits into
galacean:dev/2.0from
luzhuang:fix/virtual-resource-identity-dev-2.0
Open

fix(loader): preserve virtual resource identity in Editor Preview#3084
luzhuang wants to merge 11 commits into
galacean:dev/2.0from
luzhuang:fix/virtual-resource-identity-dev-2.0

Conversation

@luzhuang

@luzhuang luzhuang commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

问题

Editor Preview 会将工程文件注册为 VFS 虚拟资源。SpriteAtlas 元数据中的页面路径 ./auto-atlas_image_0.tex,必须先基于 Atlas 的逻辑路径 SpriteAtlas/.../auto-atlas.atlas 推导为 SpriteAtlas/.../auto-atlas_image_0.tex,再由 ResourceManager 映射到 Blob 或 CDN 等物理加载地址。

此前 LoadItem.url 在进入 Loader 前被改写为物理 URL;后续相对路径推导随之基于物理 URL 运行,VFS key 因而丢失。对于无 scheme 的路径,原先的 file:// 用法还会把首段当作 host 并按 URL 规则小写化,导致 SpriteAtlas/... 被请求为 spriteatlas/...,Preview 无法启动。

修复

  • 已注册虚拟资源的 LoadItem.url 始终保留 virtualPathbaseUrl 只作用于普通、未注册的相对传输 URL。
  • ResourceManager 的加载、子资源回调、缓存查询与取消统一通过 _getRemoteUrl 派生物理 key;内部 cache/loading pool 仍只保存一份物理 key。
  • 虚拟相对路径通过 file:/// 的 pathname 解析,避免首段进入 host 规范化,并保留 leading slash 语义。
  • 纹理解码与内容恢复复用同一解码和 Object URL 释放路径;失败信息包含逻辑资源标识与字节数。

覆盖

  • Loader 收到 virtualPath,且 baseUrl 不会改写已注册 VFS key。
  • SpriteAtlas → 相对页面纹理 → ResourceManager 的端到端映射。
  • 虚拟资源加载后可按 virtualPath 从公开缓存接口取回同一对象。
  • pending 虚拟资源可按 virtualPath 从公开取消接口终止。
  • Texture content restoration 的解码失败诊断。

分支边界

这是 #3079dev/2.0 上的等价修复:基于 dev/2.0@bd34daa 重放 #3079 的最终 loader 改动。后续提交仅对齐项目的英文注释规范并闭环 review 反馈,不包含迁移分支的其他提交。

验证

  • HEADLESS=true pnpm vitest run:124 files / 1658 tests passed
  • focused loader/resource tests:4 files / 28 tests passed
  • pnpm b:module
  • pnpm b:types:12 个 package project 均通过
  • pnpm lint:0 errors;1622 existing warnings
  • pnpm format:check 与改动测试文件的 Prettier check
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes
    • Improved resolution of relative and leading-slash asset paths, including textures referenced from atlas files.
    • Preserved virtual asset identity end-to-end so dependent requests, caching, and cancellation use the expected virtual paths.
    • Refined non-HDR texture decoding/restoration and improved decode-failure errors to include the resource path and decoded byte length.
  • Documentation
    • Clarified documentation of virtual resource identity for URL handling.
  • Tests
    • Added/extended coverage for virtual atlas loading and virtual texture restoration, plus updated path-resolution assertions.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Virtual resource loading now preserves logical paths while resolving physical transport URLs. URL handling covers leading slashes, and texture decoding shares cleanup and error reporting across initial loads and content restoration, with expanded atlas and texture tests.

Changes

Virtual Resource Loading

Layer / File(s) Summary
Resource identity and URL resolution
packages/core/src/Utils.ts, packages/core/src/asset/LoadItem.ts, packages/core/src/asset/ResourceManager.ts, tests/src/core/Utils.test.ts, tests/src/core/resource/ResourceManager.test.ts, tests/src/loader/SpriteAtlasLoader.test.ts
URL resolution handles leading slashes, while ResourceManager preserves virtual paths for loaders and maps them to physical transport URLs. Tests cover virtual-resource caching, cancellation, atlas loading, and loader inputs.
Shared texture decoding and restoration
packages/loader/src/TextureLoader.ts, tests/src/loader/TextureLoader.test.ts
Initial texture decoding and content restoration use a shared helper that revokes object URLs and reports the resource URL and byte length on failure.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ResourceManager
  participant RemoteRequest
  participant TextureLoader
  ResourceManager->>ResourceManager: Preserve virtual resource URL
  ResourceManager->>RemoteRequest: Request physical resource URL
  RemoteRequest-->>TextureLoader: Return image bytes
  TextureLoader->>TextureLoader: Decode image and revoke object URL
  TextureLoader-->>ResourceManager: Return or restore Texture2D
Loading

Possibly related PRs

Suggested labels: bug, loader, texture

Suggested reviewers: guolei1990, cptbtptpbcptdtptp

Poem

I’m a rabbit with paths in my paws,
Virtual trails now follow their laws.
Textures decode, URLs take flight,
Errors name paths and bytes just right.
Atlas pages hop through the queue—
A tidy burrow of tests says “woo!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: loader handling now preserves virtual resource identity in Editor Preview.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.80460% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.57%. Comparing base (bd34daa) to head (b83bdd0).
⚠️ Report is 6 commits behind head on dev/2.0.

Files with missing lines Patch % Lines
packages/loader/src/TextureLoader.ts 88.63% 3 Missing and 2 partials ⚠️
packages/core/src/asset/ResourceManager.ts 91.89% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #3084      +/-   ##
===========================================
+ Coverage    85.42%   85.57%   +0.15%     
===========================================
  Files          811      811              
  Lines        94654    94703      +49     
  Branches     11512    11566      +54     
===========================================
+ Hits         80854    81043     +189     
+ Misses       13710    13568     -142     
- Partials        90       92       +2     
Flag Coverage Δ
unittests 85.57% <90.80%> (+0.15%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@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.

🫧 尘小沫

结论

本轮审查了 bd34daa45612af8b402cd3be916ff181f21ae742...53bb5b4542b6baa51d84247fde54878ddb78eedf 的 4 个提交、8 个文件,并把 348ebfa6e486648036c25d7db101b8ed0f045c70...53bb5b4542b6baa51d84247fde54878ddb78eedf 的三个注释增量、#3079 最终 tree 与当前 dev/2.0 上下游逐项对账。VFS 逻辑身份、Atlas 相对依赖和 Texture 解码 owner 的主体方向正确;当前未发现新的 P0/P1,但 dev/2.0 的公开缓存/取消入口仍保留一处同根因的双口径 P2。当前阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 53bb5b4542b6baa51d84247fde54878ddb78eedf。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已在 348ebfa6e486648036c25d7db101b8ed0f045c70 闭环:VFS 命中时 LoadItem.url 保留 virtualPath,Atlas 链路测试贯通验证 atlas 与 page 各自命中物理地址。
  2. LoadItem.resolvedUrl 泄漏派生物理地址并形成双源 — 当前公开类型、ResourceManager 写入及 fixture 均无该字段;物理地址只存在于虚拟资源表和内部 cache/loading/I/O 边界。
  3. Shader 使用物理 URL 作为请求、相对 #include 基址或编码判据 — 当前 dev/2.0 基线继续以逻辑 URL 请求和解析 include,并按 payload 区分源码/预编译表示;本 PR 没有恢复旧的后缀判型或双请求路径。
  4. Texture 首次解码与内容恢复维护平行 Image 状态机 — 当前两条路径共用 decodeImage,Image 事件、object URL 释放及包含逻辑资源身份和字节数的错误均由同一 helper 拥有;恢复失败测试可反向证伪旧路径。
  5. 迁移分支夹带 clone 协议及重复 Shader 变更#3084 直接基于 dev/2.0,完整 diff 仅含 loader/VFS 修复的 8 个文件,标题、正文和实际变更范围一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已统一连续 // / @ts-ignore 说明并移除末尾句号;LoadItem 的多行 TSDoc 正确保留句号。

问题

  1. [P2] 让公开缓存查询与取消操作复用 ResourceManager 的虚拟路径映射,删除逻辑/物理 key 双口径packages/core/src/asset/ResourceManager.ts:346-359,421-431 现在把虚拟资源按 virtualResourceEntry.path 写入 _assetUrlPool / _loadingPromises,但 :106-108getFromCache(url):153-164cancelNotLoaded(url) 仍直接拿调用方 URL 索引这两个物理-key pool。注册 Texture/page.tex -> blob:... 后,await load("Texture/page.tex") 再调用 getFromCache("Texture/page.tex") 会得到 null;加载过程中调用 cancelNotLoaded("Texture/page.tex") 也找不到对应 promise。它们既违反本 PR 新明确的“请求 URL 是资源身份”契约,也让同一个 ResourceManager 对 load 与公开管理 API 维护两套 key 语义。应保留 _virtualPathResourceMap 为唯一映射 owner,把 load/cache/cancel 的 pool-key 派生收口到同一规则,并删除 getFromCache / cancelNotLoaded 对调用方 URL 的直接索引;不要通过同时写入 virtual/physical 两份镜像 key 来同步。补两条公开链路测试:虚拟资源加载后可按 virtualPath 取回同一对象,以及 pending 虚拟加载可按 virtualPath 取消。#3079 最终 tree 已有前一条缓存映射测试,可直接按当前公开契约重放。

架构、熵增与测试治理

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

相较基线,本 PR 没有新增持久状态、镜像字段、wrapper、legacy fallback 或 compatibility branch:LoadItem 没有引入第二个 resolved URL,Texture 的两套解码状态机反而合并为一套,三个后续提交也只有注释变化。剩余熵增是问题 1 中同一事实的两种公开 key 口径;应保留 ResourceManager 的映射与物理 pool 为 owner,删除公开入口的直接索引,而不是增加第三份 alias 状态。测试侧,Atlas 已从公开 ResourceManager.load() 贯通逻辑身份、相对派生和两个物理请求边界,Texture restoration 守住统一错误契约;当前缺口仅是 cache/cancel 管理链路。未发现为旧测试保留的生产兼容逻辑,也没有应随新契约继续保留的 legacy fixture、mock 或 snapshot。

Copy link
Copy Markdown
Contributor Author

@GuoLei1990 这条 P2 成立,已在 ccf00ca14 闭环。

  • _getRemoteUrl 现在是 virtualPath → physical key 的唯一派生入口;load_onSubAssetSuccessgetFromCachecancelNotLoaded 全部复用它。
  • _assetUrlPool / _loadingPromises 仍只保存物理 key,没有增加 virtual/physical 镜像 alias。
  • 新增公开链路测试:虚拟资源加载后可按 virtualPath 取回同一缓存对象;pending 虚拟资源可按 virtualPath 取消。
  • 自审时额外发现子资源成功回调还在直接读取映射表,也一并收口到同一 helper,避免留下第二套路径解析实现。

验证结果:本地全量 124 files / 1658 tests,相关 4 files / 28 tests,b:moduleb:types、lint(0 errors)和格式检查均通过;CI 30434660162 全绿。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/src/core/resource/ResourceManager.test.ts (1)

184-204: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Clean up the pending load created by this test.

new AssetPromise(() => {}) never settles, and the test only restores the loader spy. Because the same ResourceManager is reused across tests, its _loadingPromises retains this entry indefinitely. Cancel it in finally (using physicalPath) or use a self-cleaning resolved mock.

Proposed fix
       } finally {
+        resourceManager.cancelNotLoaded(physicalPath);
         loaderSpy.mockRestore();
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/src/core/resource/ResourceManager.test.ts` around lines 184 - 204,
Clean up the unresolved load created in the “preserves the virtual resource
identity for loaders” test: in the finally block, cancel the pending
resource-manager load using physicalPath before restoring loaderSpy, or replace
the mock with a self-cleaning resolved AssetPromise. Ensure _loadingPromises
does not retain the test entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/asset/ResourceManager.ts`:
- Around line 159-161: Update the cancellation loop in ResourceManager to parse
each logical URL and construct the same physical-path-plus-query key used by
_loadSingleItem before looking up _loadingPromises. Preserve direct URL
cancellation while ensuring virtual sub-assets such as material queries resolve
to their exact pending promise key, and add a regression test covering
cancellation of a virtual sub-asset.

---

Outside diff comments:
In `@tests/src/core/resource/ResourceManager.test.ts`:
- Around line 184-204: Clean up the unresolved load created in the “preserves
the virtual resource identity for loaders” test: in the finally block, cancel
the pending resource-manager load using physicalPath before restoring loaderSpy,
or replace the mock with a self-cleaning resolved AssetPromise. Ensure
_loadingPromises does not retain the test entry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fe5f665a-1713-4c56-a236-312193947492

📥 Commits

Reviewing files that changed from the base of the PR and between 53bb5b4 and ccf00ca.

📒 Files selected for processing (2)
  • packages/core/src/asset/ResourceManager.ts
  • tests/src/core/resource/ResourceManager.test.ts

Comment thread packages/core/src/asset/ResourceManager.ts Outdated

@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.

🫧 尘小沫

结论

本轮完整增量审查了 53bb5b4542b6baa51d84247fde54878ddb78eedf...ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 的 1 个提交、2 个文件,并沿 load/getFromCache/cancelNotLoaded 的 key 派生向上游 VFS 注册事实、向下游子资源 promise 与 loader I/O 各追一层。ccf00ca14 已闭环主资源按 virtualPath 查询缓存和取消加载的上一轮 P2,且没有引入逻辑/物理 alias;但带 ?q= 的虚拟子资源仍使用另一套 loading key 派生,当前有 1 个 P2。阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 ccf00ca14d5da98cd2f0522c8fe52f67cceb9810。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 348ebfa6e486648036c25d7db101b8ed0f045c70 修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。
  2. LoadItem.resolvedUrl 形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。
  3. Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
  4. Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用 decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。
  5. 迁移分支夹带 clone/Shader 变更#3084 基于 dev/2.0,完整 PR diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已闭环单行注释、@ts-ignore 说明和多行 TSDoc 标点;本增量新增/修改注释也符合该约定。
  7. 主资源 cache/cancel 的逻辑/物理 key 双口径ccf00ca14 已让 getFromCache(virtualPath)cancelNotLoaded(virtualPath)_onSubAssetSuccess_loadSingleItem 复用 _getRemoteUrl;新增两条公开链路测试能在旧实现上失败,且 _assetUrlPool / _loadingPromises 仍只存物理 key。

问题

  1. [P2] 让虚拟子资源取消复用 _loadSingleItem 的完整 loading-key 派生,删除 query key 的第二套口径packages/core/src/asset/ResourceManager.ts:159-162 现在把调用方传入的完整字符串直接交给 _getRemoteUrl,但该 helper 在 :187-189 只对完整 key 做 VFS 精确查表;与此同时,:341-373,376-407,479 的加载路径会先从 Assets/model?q=materials[0] 拆出基础 virtualPath,再映射为物理地址,并把子 promise 写到 blob:...?q=materials[0]。因此 cancelNotLoaded("Assets/model?q=materials[0]") 仍会索引逻辑 key,返回的子资源 promise 不会被取消;新增测试 tests/src/core/resource/ResourceManager.test.ts:206-229 只覆盖无 query 的主资源,无法守住该分支。保留 _parseURL 为 query 拆分 owner、_virtualPathResourceMap 为 virtualPath→physicalPath 事实 owner、物理 _loadingPromises 为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生收口为 load/cancel 共用的机械路径,并删除 _loadSingleItem 内联拼 key 与 cancelNotLoaded 直接精确映射这两套实现,不要增加 logical/physical 镜像 alias。补一条从公开 load(virtualPath + "?q=...")cancelNotLoaded 的反向测试。本问题也与 CodeRabbit 的现有 discussion #discussion_r3672281364 结论一致,本 review 不另发重复 inline comment。

架构、熵增与测试治理

向上游一层,Editor manifest / ProjectLoader 拥有 { virtualPath, path, type } 注册事实;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和 cache/loading key 派生。向下游一层,Loader 继续消费逻辑身份以解析相对依赖,_request 在叶子 I/O 边界映射物理地址;子资源链由 _parseURL / _parseQueryPath 生成规范 query,并以 _subAssetPromiseCallbacks 协调主/子资源完成状态。

相较上一 HEAD,本增量没有新增持久状态、镜像字段、wrapper、legacy fallback 或 compatibility branch;_getRemoteUrl 替换了 _onSubAssetSuccess_loadSingleItem 的直接查表,owner 数量净减少,主资源公开入口也已统一。剩余熵增仅是完整 loading key 仍由 _loadSingleItem 拼装,而取消入口只做基础精确映射;按问题 1 收口后应只保留一条机械派生路径,不增加第三份真相。测试侧,新增 cache/main-cancel 用例均从公开 API 验证新契约,且新 pending 用例在 finally 清理自身 promise;未发现为了旧测试保留的生产 compatibility branch、legacy fallback、镜像状态或第二套校验。CodeRabbit 已单独跟踪旧 preserves the virtual resource identity for loaders fixture 的 pending promise 清理,本 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.

🫧 尘小沫

结论

本轮完整增量审查了 ccf00ca14d5da98cd2f0522c8fe52f67cceb9810...8608990efae4bf89e0746e46818b6f66ffea179a 的 2 个提交、2 个文件,并回看完整 PR 的 8 个文件,沿公开 URL 契约与 load/getFromCache/cancelNotLoaded 的 key 派生向上游 VFS 注册事实、向下游子资源 promise 和 Loader I/O 各追一层。两个增量提交均只简化 TSDoc,没有改变执行逻辑或测试;主资源 cache/cancel 已闭环,但上一轮带 ?q= 的虚拟子资源取消仍未闭环,且本增量又抹去了 LoadItem.url 对逻辑身份的关键公开说明。本轮共 2 个 P2,未发现新的 P0/P1;目标 HEAD 的 12 项 GitHub checks 均通过。阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 8608990efae4bf89e0746e46818b6f66ffea179a。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 348ebfa6e486648036c25d7db101b8ed0f045c70 修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。
  2. LoadItem.resolvedUrl 形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。
  3. Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
  4. Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用 decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。
  5. 迁移分支夹带 clone/Shader 变更#3084 基于 dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已闭环单行注释、@ts-ignore 说明和多行 TSDoc 标点;本增量的 TSDoc 形式与标点也符合约定。
  7. 主资源 cache/cancel 的逻辑/物理 key 双口径ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 已让 getFromCache(virtualPath)cancelNotLoaded(virtualPath)_onSubAssetSuccess_loadSingleItem 复用 _getRemoteUrl;公开链路测试能在旧实现上失败,且 _assetUrlPool / _loadingPromises 仍只存物理 key。

问题

  1. [P2] 让虚拟子资源取消复用 _loadSingleItem 的完整 loading-key 派生,删除 query key 的第二套口径packages/core/src/asset/ResourceManager.ts:159-162 仍把调用方传入的完整字符串直接交给 _getRemoteUrl,而该 helper 在 :187-189 只对完整 key 做 VFS 精确查表;加载路径却在 :341-374,376-407,479 先把 Assets/model?q=materials[0] 拆成基础 virtualPath,映射物理地址,再把子 promise 写到 blob:...?q=materials[0]。因此 cancelNotLoaded("Assets/model?q=materials[0]") 仍索引逻辑 key,无法取消返回的子资源 promise;现有 tests/src/core/resource/ResourceManager.test.ts:206-229 只覆盖无 query 的主资源。最新两个提交只改 TSDoc,CodeRabbit discussion #discussion_r3672281364 虽因邻近文档行被自动标记 resolved,代码行为并未改变。保留 _parseURL 为 query 拆分 owner、_getRemoteUrl / _virtualPathResourceMap 为基础 virtualPath→physicalPath owner、物理 _loadingPromises 为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生从 _loadSingleItem 收口为 load/cancel 共用的机械路径,删除 _loadSingleItem 的内联拼 key和 cancelNotLoaded 的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开 load(virtualPath + "?q=...")cancelNotLoaded 的反向测试。

  2. [P2] 在 LoadItem.url 上保留虚拟资源的逻辑身份契约,不要把本 PR 的关键边界简化成泛化的 “Resource URL”packages/core/src/asset/LoadItem.ts:30-33 将原来明确的“virtual resources keep their virtual path”改成了 Resource URL.。这不是普通措辞细节:ResourceManager._loadSingleItem:348-356 有意把 virtualPath 交给 Loader,SpriteAtlasLoader.ts:31-54 依赖它先解析逻辑相对页面,只有 _requestResourceManager.ts:201-204 的叶子 I/O 边界映射物理地址。删掉这条公开 TSDoc 后,url 看起来又可以被理解成 transport URL,正好遮蔽了本 PR 要固定的身份/地址边界。保留 LoadItem.url 为唯一逻辑请求身份、VFS path 为唯一物理地址;恢复一句简洁但明确的契约,例如说明注册虚拟资源时该字段保持 virtualPath 以供 Loader 解析依赖,不要重新增加 resolvedUrl、wrapper 或第二份地址状态。

架构、熵增与测试治理

向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,registerVirtualResources 将其交给 ResourceManager;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,getResourceByRef 产生带 ?q= 的逻辑子资源请求,Loader 继续消费逻辑身份解析相对依赖,_request 才在叶子 I/O 边界映射物理地址,_subAssetPromiseCallbacks 与物理 _loadingPromises 协调主/子资源完成状态。

相较 ccf00ca14,本增量新增 0 个运行时 owner、状态、转换、校验、兼容分支或抽象,未引入 mirror/cache/wrapper/legacy fallback,执行熵没有增加;但 LoadItem.url 的公开契约信息减少了一层,形成问题 2 的认知熵。完整 PR 仍把 Texture 的两套解码状态机合并为一个 decodeImage owner,也没有为旧测试保留生产 compatibility branch。剩余运行时熵只有问题 1:完整 loading key 仍由 _loadSingleItem 拼装,取消入口只做完整字符串的精确 VFS 映射;收口后应只保留一条机械派生路径。测试侧,主资源 cache/cancel 已由公开链路覆盖,但 query 子资源取消仍无反向测试;权威契约没有需要保留的旧 fixture/mock/snapshot,也不应为现有测试增加 compatibility branch 或第二条转换路径。

@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.

🫧 尘小沫

结论

本轮完整增量审查了 8608990efae4bf89e0746e46818b6f66ffea179a...ffe4bdafc8e6d31a23dc4f8976b9ea7fc5f09c9f 的 1 个提交、1 个文件,并回看完整 PR 的 8 个文件,沿 cancelNotLoaded 的 key 派生向上游 VFS 注册与 getResourceByRef 子资源请求、向下游 _loadingPromises 和 Loader I/O 各追一层。增量提交把单字符串取消从“临时单元素数组 + forEach 闭包”改为直接分支,把数组取消改为索引循环;对合法输入行为等价,没有新增状态、owner 或兼容路径,也未改变测试。上一轮 2 个 P2 仍未闭环,本轮未发现新的 P0/P1/P2;目标 HEAD 的 12 项 GitHub checks 均通过。阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 ffe4bdafc8e6d31a23dc4f8976b9ea7fc5f09c9f。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 348ebfa6e486648036c25d7db101b8ed0f045c70 修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。
  2. LoadItem.resolvedUrl 形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。
  3. Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
  4. Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用 decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。
  5. 迁移分支夹带 clone/Shader 变更#3084 基于 dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已闭环单行注释、@ts-ignore 说明和多行 TSDoc 标点。
  7. 主资源 cache/cancel 的逻辑/物理 key 双口径ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 已让 getFromCache(virtualPath)cancelNotLoaded(virtualPath)_onSubAssetSuccess 与主资源加载复用 _getRemoteUrl;公开链路测试能在旧实现上失败,且两个 pool 仍只保存物理 key。

问题

  1. [P2] 让虚拟子资源取消复用加载链的完整 loading-key 派生,删除 query key 的第二套口径packages/core/src/asset/ResourceManager.ts:158-163 的新分支仍把调用方的完整字符串直接交给 _getRemoteUrl,而该 helper 在 :188-190 只做完整 key 的 VFS 精确查表;加载路径却在 :342-375,480 先从 Assets/model?q=materials[0] 拆出基础 virtualPath,映射物理地址,再把子 promise 写到 <physicalPath>?q=materials[0]。因此字符串和数组两个 overload 都仍会用逻辑 query key 索引,无法取消对应子资源 promise;现有 tests/src/core/resource/ResourceManager.test.ts:206-229 只覆盖无 query 的主资源。保留 _parseURL / _parseQueryPath 为 query 解析 owner、_virtualPathResourceMap 为基础 virtualPath→physicalPath owner、物理 _loadingPromises 为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生收口为 load/cancel 共用的机械路径,删除 _loadSingleItem 的内联拼 key 和 cancelNotLoaded 的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开 load(virtualPath + "?q=...")cancelNotLoaded 的反向测试。

  2. [P2] 在 LoadItem.url 上保留虚拟资源的逻辑身份契约,不要把关键边界写成泛化的 “Resource URL”packages/core/src/asset/LoadItem.ts:30-33 仍只写 Resource URL.;但 ResourceManager._loadSingleItem:349-357 有意把 virtualPath 交给 Loader,packages/loader/src/SpriteAtlasLoader.ts:31-54 依赖它先解析逻辑相对页面,只有 ResourceManager._request:202-204 的叶子 I/O 边界映射物理地址。当前 TSDoc 让 url 容易再次被理解为 transport URL,遮蔽了本 PR 要固定的身份/地址边界。保留 LoadItem.url 为唯一逻辑请求身份、VFS path 为唯一物理地址;恢复一句简洁但明确的契约,说明注册虚拟资源时该字段保持 virtualPath 以供 Loader 解析依赖,不要重新增加 resolvedUrl、wrapper 或第二份地址状态。

架构、熵增与测试治理

向上游一层,Editor manifest / registerVirtualResources 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑子资源请求;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,Loader 继续消费逻辑身份解析相对依赖,_request 才在叶子 I/O 边界映射物理地址,_subAssetPromiseCallbacks 与物理 _loadingPromises 协调主/子资源完成和取消状态。

相较 8608990e,本增量新增 0 个运行时 owner、状态、转换、校验、兼容分支或抽象,删除了单字符串取消的 1 次临时数组分配和 forEach 闭包,执行熵略降;但它没有改变 key 语义,问题 1 的两条派生路径仍在。完整 PR 仍未引入 mirror/cache/wrapper/legacy fallback,Texture 的两套解码状态机已合并;问题 2 则继续保留一层公开契约认知熵。测试侧,本增量无需为等价遍历重写测试,既有主资源 cache/cancel 用例仍有效,但 query 子资源取消仍缺反向测试;未发现为旧测试保留的 production compatibility branch、legacy fixture/mock/snapshot 或第二条校验路径。

@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.

🫧 尘小沫

结论

本轮完整增量审查了 ffe4bdafc8e6d31a23dc4f8976b9ea7fc5f09c9f...1e07682fe8ed9038c49fc0615d085f2a0547fea3 的 1 个提交、1 个文件,并回看完整 PR 的 8 个文件,沿 _onSubAssetSuccess 与完整 loading key 派生向上游 VFS 注册、getResourceByRef 和 Loader 子资源通知,向下游 _subAssetPromiseCallbacks_loadingPromises 与叶子 I/O 各追一层。最新提交把子资源 callback map 的查找/创建收口为一次局部引用,行为与上一 HEAD 等价,减少一次顶层 map 访问和 4 行代码,没有新增状态、owner 或兼容路径;本轮未发现新的 P0/P1/P2,目标 HEAD 的 12 项 GitHub checks 均通过。上一轮 2 个 P2 仍未闭环,阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 1e07682fe8ed9038c49fc0615d085f2a0547fea3。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 348ebfa6e486648036c25d7db101b8ed0f045c70 修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。
  2. LoadItem.resolvedUrl 形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。
  3. Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
  4. Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用 decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。
  5. 迁移分支夹带 clone/Shader 变更#3084 基于 dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已闭环单行注释、@ts-ignore 说明和多行 TSDoc 标点;本增量的新单行注释形式也符合约定。
  7. 主资源 cache/cancel 的逻辑/物理 key 双口径ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 已让 getFromCache(virtualPath)cancelNotLoaded(virtualPath)_onSubAssetSuccess 与主资源加载复用 _getRemoteUrl;公开链路测试能在旧实现上失败,且两个 pool 仍只保存物理 key。

问题

  1. [P2] 让虚拟子资源取消复用加载链的完整 loading-key 派生,删除 query key 的第二套口径packages/core/src/asset/ResourceManager.ts:153-164 仍把调用方的完整字符串直接交给 _getRemoteUrl,而该 helper 在 :188-190 只做完整 key 的 VFS 精确查表;加载路径却在 :336-405,476 先从 Assets/model?q=materials[0] 拆出基础 virtualPath,映射物理地址,再把子 promise 写到 <physicalPath>?q=materials[0]。因此字符串和数组两个 overload 都仍会用逻辑 query key 索引,无法取消对应子资源 promise;现有 tests/src/core/resource/ResourceManager.test.ts:206-229 只覆盖无 query 的主资源。保留 _parseURL / _parseQueryPath 为 query 解析 owner、_virtualPathResourceMap 为基础 virtualPath→physicalPath owner、物理 _loadingPromises 为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生收口为 load/cancel 共用的机械路径,删除 _loadSingleItem 的内联拼 key 和 cancelNotLoaded 的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开 load(virtualPath + "?q=...")cancelNotLoaded 的反向测试。

  2. [P2] 在 LoadItem.url 上保留虚拟资源的逻辑身份契约,不要把关键边界写成泛化的 “Resource URL”packages/core/src/asset/LoadItem.ts:30-33 仍只写 Resource URL.,最新增量又把 ResourceManager.ts:347-353 的身份说明缩成了“Only resolve unmapped relative URLs against baseUrl”;但 packages/loader/src/SpriteAtlasLoader.ts:31-54 依赖 item.url 先按逻辑路径解析相对页面,只有 ResourceManager._request:202-204 的叶子 I/O 边界映射物理地址。当前 TSDoc 与相邻注释都没有固定本 PR 的核心身份/地址边界,容易让 url 再次被理解为 transport URL。保留 LoadItem.url 为唯一逻辑请求身份、VFS path 为唯一物理地址;恢复一句简洁但明确的公开契约,说明注册虚拟资源时该字段保持 virtualPath 以供 Loader 解析依赖,不要重新增加 resolvedUrl、wrapper 或第二份地址状态。

架构、熵增与测试治理

向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑子资源请求;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,GLTF/RenderTarget Loader 通过 _onSubAssetSuccess 提供可提前交付的子资源,_subAssetPromiseCallbacks 只协调早到值与等待者,主资源完成后的 _getResolveResource 仍是权威 fallback;Loader 消费逻辑身份解析相对依赖,_request 才在叶子 I/O 边界映射物理地址。

相较 ffe4bdaf,本增量新增 0 个 owner、持久状态、转换、校验、兼容分支或抽象,复用既有 callback map,删除 1 个局部 remote key 和 1 次重复 map 访问,执行熵略降;callback 的 eager resolution 与主资源 fallback 没有增加第三份真相。完整 PR 仍未引入 mirror/cache/wrapper/legacy fallback,Texture 的两套解码状态机已合并;剩余运行时熵只有问题 1 的两条完整 loading-key 派生路径,问题 2 则保留公开契约认知熵。测试侧,本增量是等价收口,无需新增实现级测试;既有主资源 cache/cancel 与 Atlas/Texture 链路测试仍有效,但 query 子资源取消仍缺反向测试。未发现为旧测试保留的 production compatibility branch、legacy fixture/mock/snapshot 或第二条转换/校验路径。

@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.

🫧 尘小沫

结论

本轮完整增量审查了 1e07682fe8ed9038c49fc0615d085f2a0547fea3...71d3e7c49ee65c416600553c078817495ed3b46c 的 1 个提交、1 个文件,并回看完整 PR 的 10 个提交、8 个文件,沿 Utils.resolveAbsoluteUrl 与完整 loading key 派生向上游 Project VFS 注册、getResourceByRef,向下游 SpriteAtlas/GLTF 相对依赖、子资源 promise 与叶子 I/O 各追一层。最新提交把非 scheme 路径的 href.slice("file:///".length) 等价收口为 pathname 加一次首斜杠裁剪;对 1,271 组覆盖绝对 URL、leading slash、Unicode、保留 %、query/hash 字面量的输入对比无行为差异,减少 4 行代码且没有新增状态、owner、兼容路径或测试负债。本轮未发现新的 P0/P1/P2,目标 HEAD 的 12 项 GitHub checks 均通过;上一轮 2 个 P2 仍未闭环,阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 71d3e7c49ee65c416600553c078817495ed3b46c。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 348ebfa6e486648036c25d7db101b8ed0f045c70 修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。
  2. LoadItem.resolvedUrl 形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。
  3. Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
  4. Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用 decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。
  5. 迁移分支夹带 clone/Shader 变更#3084 基于 dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已闭环单行注释、@ts-ignore 说明和多行 TSDoc 标点;本增量的新单行注释也符合约定并准确说明 empty file host 的作用。
  7. 主资源 cache/cancel 的逻辑/物理 key 双口径ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 已让 getFromCache(virtualPath)cancelNotLoaded(virtualPath)_onSubAssetSuccess 与主资源加载复用 _getRemoteUrl;公开链路测试能在旧实现上失败,且两个 pool 仍只保存物理 key。

问题

  1. [P2] 让虚拟子资源取消复用加载链的完整 loading-key 派生,删除 query key 的第二套口径packages/core/src/asset/ResourceManager.ts:153-164 仍把调用方的完整字符串直接交给 _getRemoteUrl,而该 helper 在 :188-190 只做完整 key 的 VFS 精确查表;加载路径却在 :338-405,476 先从 Assets/model?q=materials[0] 拆出基础 virtualPath,映射物理地址,再把子 promise 写到 <physicalPath>?q=materials[0]。因此字符串和数组两个 overload 都会用逻辑 query key 索引,无法取消对应子资源 promise;上游 getResourceByRef({ url, key }) 正会机械生成这种逻辑请求,而现有 tests/src/core/resource/ResourceManager.test.ts:206-229 只覆盖无 query 的主资源。保留 _parseURL / _parseQueryPath 为 query 解析 owner、_virtualPathResourceMap 为基础 virtualPath→physicalPath owner、物理 _loadingPromises 为唯一状态;抽出 load/cancel 共用的“解析基础 URL → VFS 映射 → 规范化并拼回 query”机械派生,删除 _loadSingleItem 的内联拼 key 和 cancelNotLoaded 的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开 load(virtualPath + "?q=...")cancelNotLoaded 的反向测试。

  2. [P2] 在 LoadItem.url 上保留虚拟资源的逻辑身份契约,不要把关键边界写成泛化的 “Resource URL”packages/core/src/asset/LoadItem.ts:30-33 仍只写 Resource URL.,而 ResourceManager.ts:344-354 有意把 virtualPath 交给 Loader,packages/loader/src/SpriteAtlasLoader.ts:31-54 依赖它先按逻辑路径解析相对页面,只有 ResourceManager._request:200-204 的叶子 I/O 边界映射物理地址。最新增量对 Utils 注释的收口准确解释了路径保大小写,却没有固定这个公开身份/地址契约,url 仍容易被理解为 transport URL。保留 LoadItem.url 为唯一逻辑请求身份、VFS path 为唯一物理地址;在该公开 TSDoc 中明确注册虚拟资源时字段保持 virtualPath 供 Loader 解析依赖,不要重新增加 resolvedUrl、wrapper 或第二份地址状态。

架构、熵增与测试治理

向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑子资源请求;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,SpriteAtlas/GLTF 以逻辑身份解析相对依赖,GLTF/RenderTarget 通过 _onSubAssetSuccess 提前交付子资源,_subAssetPromiseCallbacks 只协调早到值与等待者,主资源完成后的 _getResolveResource 仍是权威 fallback;_request 才在叶子 I/O 边界映射物理地址。

相较 1e07682f,本增量新增 0 个 owner、持久状态、转换、校验、兼容分支或抽象,删除 1 个局部 head、收短 4 行注释并复用 URL 的 pathname 结果,概念与执行熵略降;现有 Utils 与 Atlas 链路测试继续覆盖本次等价重构,无需为实现写新测试。完整 PR 仍未引入 mirror/cache/wrapper/legacy fallback,Texture 的两套解码状态机已合并;剩余运行时熵只有问题 1 的两条完整 loading-key 派生路径,问题 2 则保留公开契约认知熵。测试侧,主资源 cache/cancel 与 Atlas/Texture 链路测试仍有效,但 query 子资源取消仍缺反向测试;未发现为旧测试保留的 production compatibility branch、legacy fixture/mock/snapshot 或第二条转换/校验路径。

GuoLei1990

This comment was marked as outdated.

@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.

🫧 尘小沫

结论

本轮完整增量审查了 71d3e7c49ee65c416600553c078817495ed3b46c...b83bdd0eee638261155fd89bfed9bd2c1ddba16d 的 1 个提交、2 个文件,并回看完整 PR 的 11 个提交、8 个文件,沿物理 asset key 派生向上游 Project VFS 注册、getResourceByRef,向下游 SpriteAtlas/GLTF/RenderTarget Loader、子资源 callback、cache/loading pool 与叶子 I/O 各追一层。最新提交已闭环上一轮虚拟 query 子资源无法按逻辑路径取消的问题,并把同根因的 baseUrl 相对资源 cache/cancel key 一并收口;新增三条公开链路测试可反向守住旧实现。本轮未发现新的 P0/P1/P2,目标 HEAD 的 12 项 GitHub checks 均通过;仍有 1 个公开契约 P2 未闭环,阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 b83bdd0eee638261155fd89bfed9bd2c1ddba16d。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。

已关闭问题清单

  1. baseUrl 覆盖虚拟资源逻辑身份 — 已由 348ebfa6e486648036c25d7db101b8ed0f045c70 修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。
  2. LoadItem.resolvedUrl 形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。
  3. Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
  4. Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用 decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。
  5. 迁移分支夹带 clone/Shader 变更#3084 基于 dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。
  6. 新增注释不符合仓库约定07a8d6a11649e6f95ac1262e1bb9b3e055919930d5735fa7c60549959513415ffad062145724365653bb5b4542b6baa51d84247fde54878ddb78eedf 已闭环单行注释、@ts-ignore 说明和多行 TSDoc 标点;本增量的新单行注释也准确且符合约定。
  7. 主资源 cache/cancel 的逻辑/物理 key 双口径ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 已让公开 cache/cancel 与主资源加载复用 VFS 物理映射,两个 pool 仍只保存物理 key。
  8. 虚拟 query 子资源与 baseUrl 相对资源存在第二套 loading/cache key 口径b83bdd0eee638261155fd89bfed9bd2c1ddba16d 已让 _getRemoteUrl 唯一拥有 VFS/baseUrl 基础物理 key,让 _getRemoteAssetURL 唯一拥有 query key 格式;load、cache、cancel 与子资源 callback 机械复用,且新增公开链路测试覆盖两类旧失配。

问题

  1. [P2] 在 LoadItem.url 的公开 TSDoc 中固定虚拟资源的逻辑身份契约packages/core/src/asset/LoadItem.ts:30-33 仍只写 Resource URL.;最新提交在 packages/core/src/asset/ResourceManager.ts:348-350 增加的 // Preserve virtual paths for loaders 准确记录了内部实现意图,但自定义 Loader 作者仍无法从公开类型得知:VFS 命中时 item.url 保持 virtualPath,SpriteAtlas 在 packages/loader/src/SpriteAtlasLoader.ts:53 用它解析相对依赖,GLTF 在 packages/loader/src/GLTFLoader.ts:41 用它作为资源基址,只有 _request 才映射物理地址。保留 LoadItem.url 为唯一 Loader 可见的逻辑请求身份、VFS path 为唯一物理地址;把这一条件契约写回该公开 TSDoc,不要重新增加 resolvedUrl、wrapper、镜像字段或第二条地址转换路径。

架构、熵增与测试治理

向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑请求;ResourceManager 唯一拥有 virtualPath/baseUrl→physical base key、query loading key、loader 选择和 cache/loading 状态。向下游一层,SpriteAtlas/GLTF/RenderTarget Loader 继续以逻辑身份解析依赖或通知子资源,_subAssetPromiseCallbacks 只协调早到值与等待者,_request 才在叶子 I/O 边界取物理地址。

相较 71d3e7c4,本增量新增 0 个持久状态、镜像 key、校验、兼容分支或 legacy fallback;增加 2 个无状态 private helper,同时删除 load/cancel 中两处内联物理 key 拼装,使 VFS/baseUrl 映射与 query 序列化各只剩一个 owner,没有把复杂度转移给 Loader 或测试。测试侧新增 baseUrl cache、baseUrl cancel、虚拟 query 子资源 cancel 三条公开链路用例,并为既有 pending fixture 补齐 catch/cancel 清理;未发现为旧测试保留的 production compatibility branch、失效 fixture/mock/snapshot 或第二条转换/校验路径。剩余熵仅是问题 1 的公开契约认知缺口。

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