Skip to content

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

Open
luzhuang wants to merge 5 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 5 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 91.54930% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.55%. Comparing base (bd34daa) to head (ccf00ca).

Files with missing lines Patch % Lines
packages/loader/src/TextureLoader.ts 88.63% 3 Missing and 2 partials ⚠️
packages/core/src/asset/ResourceManager.ts 94.11% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #3084      +/-   ##
===========================================
+ Coverage    85.42%   85.55%   +0.13%     
===========================================
  Files          811      811              
  Lines        94654    94659       +5     
  Branches     11512    11551      +39     
===========================================
+ Hits         80854    80986     +132     
+ Misses       13710    13581     -129     
- Partials        90       92       +2     
Flag Coverage Δ
unittests 85.55% <91.54%> (+0.13%) ⬆️

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 on lines +159 to +161
const urls = typeof url === "string" ? [url] : url;
urls.forEach((url) => {
this._loadingPromises[this._getRemoteUrl(url)]?.cancel();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Map parsed virtual URLs before cancelling.

For a virtual sub-asset such as Assets/foo?q=materials[0], _loadSingleItem stores the pending promise under a key like <physicalPath>?q=materials[0]. This code maps the full logical string instead, so _getRemoteUrl cannot find the exact virtual-path entry and the load remains uncancelled. Reuse the same query parsing/key construction used by _loadSingleItem, and add a regression test for virtual sub-asset cancellation.

Proposed direction
       const urls = typeof url === "string" ? [url] : url;
       urls.forEach((url) => {
-        this._loadingPromises[this._getRemoteUrl(url)]?.cancel();
+        const { assetBaseURL, queryPath } = this._parseURL(url);
+        const remoteAssetBaseURL = this._getRemoteUrl(assetBaseURL);
+        const paths = queryPath ? this._parseQueryPath(queryPath) : [];
+        let remoteUrl = remoteAssetBaseURL;
+        if (queryPath) {
+          remoteUrl += "?q=" + paths.shift();
+          let index: string;
+          while ((index = paths.shift())) remoteUrl += `[${index}]`;
+        }
+        this._loadingPromises[remoteUrl]?.cancel();
       });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const urls = typeof url === "string" ? [url] : url;
urls.forEach((url) => {
this._loadingPromises[this._getRemoteUrl(url)]?.cancel();
const urls = typeof url === "string" ? [url] : url;
urls.forEach((url) => {
const { assetBaseURL, queryPath } = this._parseURL(url);
const remoteAssetBaseURL = this._getRemoteUrl(assetBaseURL);
const paths = queryPath ? this._parseQueryPath(queryPath) : [];
let remoteUrl = remoteAssetBaseURL;
if (queryPath) {
remoteUrl += "?q=" + paths.shift();
let index: string;
while ((index = paths.shift())) remoteUrl += `[${index}]`;
}
this._loadingPromises[remoteUrl]?.cancel();
});
🤖 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 `@packages/core/src/asset/ResourceManager.ts` around lines 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.

@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 不重复立项。

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