docs(04-13): register UI adaptation impact-collection plan (D-71/D-72 step 1)

This commit is contained in:
unanmed 2026-09-30 14:36:37 +08:00
parent 8b114c77c4
commit faba3d3c11
4 changed files with 546 additions and 11 deletions

View File

@ -181,11 +181,12 @@ Plans:
3. 移动端(窄屏)布局下,同一场景正常显示且可操作
4. 数据端与渲染端保持双端分离——数据端无 DOM,仍可在 Node 环境跑回放验证
**Plans**: 11 已执行 + 1 已规划待执行(04-12) — 04-01..04-07 已执行(04-06 = material 接口影响范围清点·只读;04-07 = material 接口适应实施·第二步);04-08(TextureManager 新接口影响范围清点·只读,D-38/D-39/D-40/D-41/D-42 第一步)已执行;04-09(TextureManager 新接口适应实施·第二步·代码改动,D-43..D-50)已执行;04-10(渲染端结构性重构影响范围清点·只读,D-51..D-57 第一步)已执行;04-11(渲染端结构性重构·第二步·移植实施·代码改动,D-58..D-68)已执行;**04-12(04-11 落地修正·桶导出边界 + 消费者直连 + shared 单文件·代码改动,D-69/D-70)已规划待执行**(执行前须 Task 0 汇报关卡等待用户「可以执行」);渲染适配与移动端/桌面端双布局(REND-01/REND-02)整体仍未完成
**Plans**: 12 已执行 + 1 已规划待执行(04-13) — 04-01..04-07 已执行(04-06 = material 接口影响范围清点·只读;04-07 = material 接口适应实施·第二步);04-08(TextureManager 新接口影响范围清点·只读,D-38/D-39/D-40/D-41/D-42 第一步)已执行;04-09(TextureManager 新接口适应实施·第二步·代码改动,D-43..D-50)已执行;04-10(渲染端结构性重构影响范围清点·只读,D-51..D-57 第一步)已执行;04-11(渲染端结构性重构·第二步·移植实施·代码改动,D-58..D-68)已执行;04-12(04-11 落地修正·桶导出边界 + 消费者直连 + shared 单文件·代码改动,D-69/D-70)已执行(异地执行,commit 81e4e98;`8b114c7 docs(04-12): sync tracking`);**04-13(部分 UI 的进一步接口适配·第一步·只读收集,D-71/D-72/D-73)已规划待执行**(执行前须 Task 0 汇报关卡等待用户「可以执行」);渲染适配与移动端/桌面端双布局(REND-01/REND-02)整体仍未完成
**Plan register note (2026-09-21):** 第五个增量 `04-05`(收口 `#04-01-M-06` / `#04-01-M-09`:状态栏 9 个数值属性改经 `client.hero.attribute.getFinalAttribute(...)` 读取 + 逐图层钩子类 `RendererLayerHook`,2026-09-20 执行)此前未登记进本路线图,本次一并补登;第六个增量 `04-06` = material 接口适应(D-30/D-31/D-32)**第一步·只读影响清点**,产出 `04-MATERIAL-INTERFACE-IMPACT.md`,第二步(实施)待用户审阅后另行规划。第七个增量 `04-07` = material 接口适应实施(**第二步·代码改动**,D-33..D-37),2026-09-22 已执行(10 文件原子提交)。**第八个增量 `04-08` = TextureManager 新接口适应(D-38..D-42)第一步·只读影响清点**,产出 `04-TEXTURE-INTERFACE-IMPACT.md`;第二步(实施)待用户审阅后另行规划。
**Plan register note (2026-09-24):** 第十个增量 `04-10` = 渲染端结构性重构(用户裁定 2026-09-23 · D-51..D-57)**第一步·只读影响清点**:把 `packages-user/client-modules/src/render/` 下的通用内容(`render/components`、`render/elements`、`render/map` 三文件夹 + `render/utils/layout.ts`,规划日实测 **39** 文件)迁往渲染系统层 `packages-user/client-base/src/`(D-51/D-52;目标布局按 D-53:`client-base/src/{components,elements,map}/` + `client-base/src/layout/`,**不新建 `render/` 目录**);不移植 `render/utils/` 其余(`index.ts`/`saves.ts`/`use.ts`)与 `ui`/`fx`/`weather`/`render` 顶层文件(D-54);legacy 一律只报告(D-55);用户并发改动零触碰(D-56)。台账按 A 被移集合内部交叉引用 / B 外部导入点(含 `entry-client` / `entry-data` / `packages/legacy-ui` 经 `@user/client-modules` 公共面的间接依赖)/ C barrel 与导出面 / D 分层与循环依赖风险(`client-base` 不得反向依赖 `client-modules`,含 `package.json` 依赖现状)/ E legacy 命中(仅报告)/ F 未确定 六类分组,每行精确到文件或符号 + `file:line` 且 ≥2 锚点;产出 `04-STRUCTURE-MIGRATION-IMPACT.md`,生产代码零改动且**零命名变更**;**已规划待执行**,执行前须 Task 0 汇报关卡等待用户「可以执行」;第二步(移植实施)待用户审阅后另行规划;`REND-01` / `REND-02` 仍 Pending。
**Plan register note (2026-09-24 · 04-11 第二步):** 第十一个增量 `04-11` = 渲染端结构性重构**第二步·移植实施(代码改动)**(用户裁定 2026-09-24 · D-58..D-68)。**移植按 MOVE 落地**:把 D-52 的 **39** 文件(`render/components` 13 / `render/elements` 5 / `render/map` 20 / `render/utils/layout.ts` 1)按 D-53 放进 `packages-user/client-base/src/{components,elements,map}/` 与 `client-base/src/layout/layout.ts`(并新增 `layout/index.ts`,D-61),**并删除 `client-modules/src/render/` 下的原件**;D-58 另新建 `client-base/src/shared/`(从 `client-modules/src/shared.ts` 摘取被移 `map` 文件所需的 10 个常量,原文件保留);D-63 `client-base/src/index.ts` 新增 `./components` / `./elements` / `./map` / `./layout` / `./shared` 五条桶导出,实现层消费者(`render/ui` 8 文件 11 处含 `toolbar.tsx` 两处深层导入、`fallback/ui.ts:2`、`render/index.tsx:5,45,46`、`client.ts:25`、`types.ts:2`)改指 `@user/client-base`;被移 `map` 文件的 shared 说明符改指 4 处(D-58);D-59 / D-68 的架构耦合(`render/renderer` 3 处 + `render/use.ts` 5 处)与 D-60 的 `render/utils/` 断链(`index.ts:1` / `saves.ts:2`)共 **10** 处以带原因的 `// @ts-expect-error` 暂记,**不反向引用、不解耦**;D-66 `client-base/package.json` 新增 5 条 `workspace:*` 依赖(`@motajs/animate` / `@motajs/common` / `@motajs/render-vue` / `@motajs/system` / `@user/data-common`)并执行 `pnpm i`;D-64 `?raw` 不处理、D-65 legacy 一律不管、D-62 命名一律不变;门禁 = 目标落位 / 移动已发生 / 桶导出 / 依赖与 lockfile / 消费者改指 / 反向引用零命中 / `@ts-expect-error` 落点(10 处新增 + 既有 7 条保留)/ 39 文件允许差异 / 实现层差异 / 范围与用户改动 / 无 `import type` / CRLF 共 12 道 + 计划文件范围门禁 + 人工复核(**D-68 明示不要求可运行、不要求零类型错误,故不设 `check:type` / `build` / TS 诊断数类门禁**);`autonomous: false`(Task 0 汇报关卡);第二步的后续余留(自包引用未验证 / 两行同源星导出 / 8 处反向耦合接线 / D-60 断链)由用户接手;`REND-01` / `REND-02` 仍 Pending。
**Plan register note (2026-09-24 · 04-12 落地修正):** 第十二个增量 `04-12` = **04-11 落地修正·桶导出边界 + 消费者直连 + `shared` 单文件(代码改动)**(用户裁定 2026-09-24 · **D-69 / D-70**)。**D-69(桶导出边界原则,硬约束)**:一个 barrel(`index.ts` / `index.tsx`)**只允许 `export * from './<同目录下的文件或子文件夹>'`**、不得导出本文件夹之外的任何内容;反过来,任何需要被移内容的**消费端必须直接 `import ... from '@user/client-base'`**、**不得经任何 barrel 转发导出**。**D-70 的 6 条修正**:① `client-modules/src/render/utils/index.ts` **删除**指向 `./layout` 的越界转发 `export *` 及其 `@ts-expect-error`(保留 `./saves` / `./use`);② `render/ui/save.tsx` **拆分** `../utils` 导入(`adjustGrid` / `IGridLayoutData` → `@user/client-base`,`getSave` / `SaveData` 仍留 `../utils`)、`render/ui/title.tsx` 的 `adjustCover` → `@user/client-base`;③ `render/utils/saves.ts` 的 `getConfirm` / `waitbox` → `@user/client-base` 并**删除**其 `@ts-expect-error`;④ `client-base/src/shared/{shared.ts,index.ts}` **折成单文件** `client-base/src/shared.ts` 并删除 `shared/` 目录(`client-base/src/index.ts` 的 `export * from './shared'` 与 `map/*` 的 `'../shared'` / `'../../shared'` 说明符**不受影响**,无需改动);⑤ **逐字保留** `client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}` 内 **8** 处引用 `render/use.ts` / `render/renderer` 的架构耦合 `@ts-expect-error`(属 D-59 / D-67,留待用户收尾;`textboxTyper.ts` 另有 1 处既有 `无法推导` 标注同属保留,故这 7 文件合计 9 处);⑥ **不得**新增任何转发导出,`client-modules/src/render/index.tsx` **维持现状**(用户已删除越界两行,现合规)。旁注(仅报告):`packages/client/src/index.ts:1` 的 `export * from '@motajs/client-base'` 亦违反 D-69,但在 `packages/`(D-33 只报告)。改动面 = `client-base/src/shared.ts` + `client-modules/src/render/{utils/index.ts,utils/saves.ts,ui/save.tsx,ui/title.tsx}` 五个生产文件 + `files_deleted` 的 `client-base/src/shared/{shared.ts,index.ts}`;门禁 = 桶边界(8 个 in-scope barrel 的 `export * from` 全为 `./` 前缀 + `render/utils/index.ts` 不再转发 `./layout`)/ F1..F4 收口自检 / F5 的 8 处标注逐字保留 + porcelain 零命中 / 范围与用户改动 / CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);无依赖变更、不执行 `pnpm i`;本步不引入任何新命名;`REND-01` / `REND-02` 仍 Pending。
**Plan register note (2026-09-30 · 04-13 第一步):** 第十三个增量 `04-13` = **部分 UI 的进一步接口适配·第一步·只读收集需要修改的点(只读)**(用户裁定 2026-09-25 · **D-71 / D-72 / D-73**)。**要解决的问题**:数据端经 `d8fa4b8 refactor: Delete global loading & hook object` 与加载系统重构后,渲染端部分 UI 仍以旧接口编写——① 全局 `loading` / `hook` 对象已删除,组件不得再依赖它们监听全局钩子、**必须在对应对象上监听**(残留:`render/ui/main.tsx:146-151` 的 `hook.on('statusBarUpdate', ...)`、`render/index.tsx:35-38` 的 `hook.on('restart', ...)`,及 `main.tsx:140-143` 的手工单次调用);② 加载系统重构,旧加载 UI(`render/ui/load.tsx` 的 `LoadScene` / `LoadSceneUI`)已不能用,仍调用 `loader.initSystemLoadTask()` / `loader.load()` / `loader.progress`(`:71,72,76-79,91-92,118-119,139`),须重新适配新加载系统(`@motajs/loader` 的 `LoadManager` + `packages-user/data-state/src/loader/**` 的 `MotaDataLoader` / `IMotaDataLoader`)。**D-72**:本目标至少两个计划——第一个只读收集(生产代码零改动),第二个及后续才执行;第一个计划的产出是后续执行计划的输入。**D-73**:沿用 D-33 / D-42 / D-48 / D-49 / D-55 / D-65 / D-56 / D-68,**D-69 桶导出边界继续适用**。**交付物** = `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md`(只读影响台账):元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / A 全局 loading / hook 使用点(UI 面)/ B 目标对象与钩子 API 证据 / C 旧加载 UI 清单与新加载系统 / D 分层与 barrel(D-69)检查 / E legacy 命中(仅报告)/ F 未能从阅读确定(未猜测)/ 修改点汇总(供后续执行计划消费)/ 处置;A–E 固定列序表 `| ID | 项目 | 命中处 file:line | 目标锚点 / 证据 file:line | 问题描述 | 影响 | 置信 |`,事实行每行 ≥2 个 `file:line` 锚点、证据行带 `[证据行]` 标记;每个 A 点给出「应改监听 / 使用的对象」+ 现行源码证据,或显式 undetermined(进 F 类)。**边界**:被查 = 渲染端部分 UI(`client-modules/src/render/ui/**` + `render/index.tsx`);`client.ts` / `client-modules/src/index.ts` / `entry-client/src/create.ts` 的 `loading` / `hook` 使用点**只报告**(非 UI,是否纳入由用户裁定);`packages/` 与 `src/` 仅报告(D-33)。**门禁**:只读基线逐条一致 + 台账结构 / 内容 / 证据纪律(≥2 锚点)+ 范围与用户改动 + 既有 `04-01`..`04-12` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);**本步为只读、不引入任何命名变更**;`REND-01` / `REND-02` 仍 Pending。
**Plan register note (2026-09-23):** 第九个增量 `04-09` = TextureManager 新接口适应**第二步(实施·代码改动)**(用户裁定 D-43..D-50:`renderWithoutCheck` 三处调用点改新 `render(tile, connection)`;`BlockCls` / `cls` 判定改为 `tileType === TileType.Autotile`、不做映射表;`extension/hero.ts` 勇士字面量填 `tileType: TileType.Unknown`;`MapRenderer` 不再自建 `AutotileProcessor` 而取 `manager.autotile`、保留 `readonly autotile` 字段与 `IMapRenderer` 签名;不改 `material/**` 与加载面;不考虑 legacy 兼容)。对象 = `packages-user/client-modules/src/render/map/{vertex.ts,renderer.ts,extension/hero.ts}` 的 **13 条** texture 归属 TS 诊断(vertex 6 / renderer 5 / hero 2),目标归零;`moving.ts` 与 `render/map/types.ts` 经核实无需改动。**已规划待执行**,执行前须 Task 0 汇报关卡等待用户「可以执行」;`REND-01` / `REND-02` 仍 Pending(本步仅为 REND-01 的 texture 子切片)。
Plans:
@ -234,6 +235,10 @@ Plans:
- [x] 04-12-PLAN.md — 04-11 落地修正·**桶导出边界 + 消费者直连 + `shared` 单文件(代码改动)**(D-69 / D-70):按 **D-69(硬约束:barrel 只允许 `export * from './<同目录项>'`,消费者必须直连 `@user/client-base`、不得经 barrel 转发)** 落地 D-70 的 6 条修正——① `client-modules/src/render/utils/index.ts` **删除**指向 `./layout` 的越界转发 `export *` 与其 `@ts-expect-error`(保留 `./saves` / `./use`);② `render/ui/save.tsx` 拆分 `../utils` 导入(`adjustGrid` / `IGridLayoutData` → `@user/client-base`,`getSave` / `SaveData` 仍留 `../utils`)、`render/ui/title.tsx` 的 `adjustCover` → `@user/client-base`;③ `render/utils/saves.ts` 的 `getConfirm` / `waitbox` → `@user/client-base` 并删除其 `@ts-expect-error`;④ `client-base/src/shared/{shared.ts,index.ts}` 折成单文件 `client-base/src/shared.ts` 并删除 `shared/` 目录(`client-base/src/index.ts` 的 `./shared` 与 `map/*` 的 4 处相对说明符**一字不改**、仍解析);⑤ **逐字保留** `client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}` 内 **8** 处引用 `render/use.ts` / `render/renderer` 的架构耦合 `@ts-expect-error`(D-59 / D-67,留待用户收尾;`textboxTyper.ts` 另有 1 处既有 `无法推导` 标注同属保留,故这 7 文件合计 9 处);⑥ **零新增转发导出**、`client-modules/src/render/index.tsx` 维持现状;门禁 = 桶边界(8 个 in-scope barrel 的 `export * from` 全为 `./` 前缀 + `render/utils/index.ts` 不再转发 `./layout`)/ F1..F4 收口自检 / F5 的 8 处标注逐字保留 + porcelain 零命中 / 范围与用户改动 / CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);无依赖变更、不执行 `pnpm i`;本步不引入任何新命名;`REND-01` / `REND-02` 仍 Pending
**Wave 12** *(blocked on Wave 11 completion)*
- [ ] 04-13-PLAN.md — 部分 UI 的进一步接口适配·**第一步·只读收集需要修改的点(只读,D-71 / D-72 / D-73)**:以 `d8fa4b8 refactor: Delete global loading & hook object` 后的工作树为基准,收集渲染端**部分 UI** 对已删全局 `loading` / `hook` 与旧加载系统的使用点,产出 `04-UI-ADAPTATION-IMPACT.md`(元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / A 全局 loading / hook 使用点(UI 面)/ B 目标对象与钩子 API 证据 / C 旧加载 UI 清单与新加载系统 / D 分层与 barrel(D-69)检查 / E legacy 命中(仅报告)/ F 未能从阅读确定(未猜测)/ 修改点汇总 / 处置;A 类 = `render/ui/load.tsx` 旧加载接口(`:71,72,76-79,91-92,118-119,139`)+ `render/ui/main.tsx` `statusBarUpdate`(`:140-143,146-151`)+ `render/index.tsx` `restart`(`:35-38`),边界非 UI 面(`client.ts:88-92,124-127` / `client-modules/src/index.ts` / `entry-client/src/create.ts:16,31,34-41`)只报告;B 类逐处给目标对象证据(`IMotaDataLoader` / `ILoadManager` / 数据端可 hook 对象接口)或 undetermined;C 类登记旧 `LoadScene` / `LoadSceneUI` 与已删 `client-base/src/load/**` + 新 `@motajs/loader` / `data-state/src/loader/**` / `CoreState.loader` / `loadManager`;D 类 4 个 barrel 节点(只报告);E 类 legacy 只报告;F 类 ≥ 5 条未确定项;事实行每行 ≥2 个 `file:line` 锚点),**本步生产代码零改动、不引入任何命名变更**;门禁 = 只读基线一致 + 台账结构 / 内容 / 证据纪律 + 范围与用户改动 + 既有 `04-01`..`04-12` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);第二步(适配实施)待用户审阅后另行规划(D-72);`REND-01` / `REND-02` 仍 Pending
**UI hint**: yes
### Phase 5: Legacy 移植
@ -427,7 +432,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
| 1. 事件系统 | 13/13 | In Progress| |
| 2. 寻路系统 | 5/5 | In Progress| |
| 3. 数据端完成 | 19/19 | Complete | 2026-09-12 |
| 4. 渲染适配与双布局 | 12/12 | In Progress| |
| 4. 渲染适配与双布局 | 12/12 (+1 planned) | In Progress| |
| 5. Legacy 移植 | 0/TBD | Not started | - |
| 6. 单元测试 | 18/18 | In Progress| |
| 7. 数据端缺陷修复 | 15/16 | 暂缓 (Deferred) | - |

View File

@ -5,14 +5,14 @@ current_phase: 04
current_phase_name: 渲染适配与双布局
status: executing
stopped_at: Completed 04-12-PLAN.md(桶导出边界修正:shared 单文件化 + 消费者直连 @user/client-base;8 个 in-scope barrel 全部只导出同目录项;架构耦合 8 处标注逐字保留;由用户在异地执行,commit 81e4e98;REND-01/REND-02 保持 Pending)
last_updated: "2026-09-25T00:00:00.000Z"
last_updated: "2026-09-30T06:35:14.477Z"
last_activity: 2026-09-25
last_activity_desc: Completed 04-12-PLAN.md(桶导出边界修正;用户在异地执行)
state_head: d8fa4b8
last_activity_desc: Planned 04-13-PLAN.md(部分 UI 进一步接口适配·第一步只读收集)
state_head: 8b114c77c408ccb9f1ca8f9f34c5817140de5cf6
progress:
total_phases: 7
completed_phases: 1
total_plans: 83
total_plans: 84
completed_plans: 82
milestone_name: milestone
---
@ -28,10 +28,10 @@ See: .planning/PROJECT.md (updated 2026-09-17)
## Current Position
Phase: 04 (渲染适配与双布局) — IN PROGRESS
Plan: 12/12 已执行(04-01..04-12)
Status: 04-12 完成(桶导出边界修正);下一步 = 部分 UI 的进一步接口适配(D-71),走两步:先只读收集(04-13)、再执行;Phase 4 整体仍未完成 — REND-01/REND-02 保持 Pending
Last activity: 2026-09-25 — Completed 04-12-PLAN.md(桶导出边界修正;异地执行)
Phase: 04 (渲染适配与双布局) — READY TO EXECUTE
Plan: 12/13 已执行(04-01..04-12);04-13(部分 UI 进一步接口适配·第一步只读收集)已规划待执行(Wave 12)
Status: 04-13 已规划并通过 checker(0 blocker / 0 warning / 5 info-advisory,已修订 4 项);待用户回复「可以执行」后执行;Phase 4 整体仍未完成 — REND-01/REND-02 保持 Pending
Last activity: 2026-09-30 — Planned 04-13-PLAN.md(部分 UI 进一步接口适配·第一步只读收集)
Progress: [█████░░░░░] 50%

View File

@ -0,0 +1,530 @@
---
phase: 04-render-adaptation
plan: 13
type: execute
wave: 12
depends_on:
- 04-01
- 04-02
- 04-03
- 04-04
- 04-05
- 04-06
- 04-07
- 04-08
- 04-09
- 04-10
- 04-11
- 04-12
files_modified:
- .planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md
autonomous: false
requirements:
- REND-01
- REND-02
estimate:
tokens: 60000
raw_tokens: 60000
tasks: 5
confidence: low
must_haves:
truths:
- "**本计划的第一个 block 点是 Task 0 的 `blocking-human` 汇报关卡(AGENTS.md 硬要求)**:Task 0 必须先向用户汇报「要解决的问题(数据端 `d8fa4b8 refactor: Delete global loading & hook object` 后,全局 `loading` / `hook` 对象已删除、加载系统已重构,部分 UI 仍以旧全局对象与旧加载系统接口编写,需先只读收集需修改的点)」「锁定裁定 **D-71(目标:① 组件不得依赖已删的全局 `loading` / `hook`,必须在对应对象上监听;② 旧加载 UI 已不可用,须重新适配新加载系统)/ D-72(至少两个计划,本计划 = 第一个·只读收集;第二个及后续才执行)/ D-73(沿用 D-33 / D-42 / D-48 / D-49 / D-55 / D-65 / D-56 / D-68 / D-69)**」「大致解决方案(只读影响台账 `04-UI-ADAPTATION-IMPACT.md`,A–F 六类分列 + 修改点汇总,事实行每行 ≥2 个 `file:line` 锚点,生产代码零改动)」,然后必须**停下等待**用户明确回复「可以执行」四个字;收到该回复前不得执行任何任务、不得派发任何执行子代理。无论触发方式(`/gsd-execute-phase`、`/gsd-manager`、`/gsd-autonomous`、子代理/执行器派发)或配置模式(`.planning/config.json` 的 `mode: yolo`、`workflow.auto_advance`)如何,均不得自动放行。**本步为只读台账、不引入任何命名变更**(不新增 / 改名 / 删除任何公共、受保护、私有成员、方法、字段、文件或目录)——Task 0 必须原样告知用户这一条。"
- "**只读硬约束(生产代码零改动)**:本 run 生产源码改动为 **0**——`git status --porcelain -- packages packages-user src` 在 Task 1 步骤 (0a) 起逐行原样记录进台账 `## 只读起始基线` 一节,Task 1 / Task 4 门禁断言其后**逐条一致**(不新增、不消失、状态码不变);`files_modified` 只含 `04-UI-ADAPTATION-IMPACT.md` 一个交付物;本 `04-13-PLAN.md` 与 `04-13-SUMMARY.md` 属计划 / 执行簿记,不算生产改动。**不得**修改、移动、复制、预建任何 `packages-user/**` / `packages/**` / `src/**` 生产文件(含 `client-modules/src/render/ui/**`)。"
- "**台账结构完整(固定小节 + 固定列序表)**:交付物 `04-UI-ADAPTATION-IMPACT.md` 必须有:6 行元信息块(日期 / 范围 / 性质 / **基准提交 `d8fa4b8 refactor: Delete global loading & hook object` 及当日 HEAD** / 新加载系统基准 / 下一步)、`## 只读起始基线`、`## 背景`、`## 方法`、`## 基准变更(d8fa4b8)`、`## A 全局 loading / hook 使用点(UI 面)`、`## B 目标对象与钩子 API 证据`、`## C 旧加载 UI 清单与新加载系统`、`## D 分层与 barrel(D-69)检查`、`## E legacy 命中(仅报告)`、`## F 未能从阅读确定(未猜测)`、`## 修改点汇总(供后续执行计划消费)`、`## 处置`。A / B / C / D / E 各节一张**固定列序**表 `| ID | 项目 | 命中处 file:line | 目标锚点 / 证据 file:line | 问题描述 | 影响 | 置信 |`。"
- "**证据纪律(每行 ≥2 个 `file:line` 锚点)**:A–E 的**事实行**每行至少 **2** 个完整 `文件:行` 锚点(识别正则接受 `.(tsx?|md|json):\\d+`,故基准文件如 `04-CONTEXT.md:135`、`packages/loader/src/types.ts:288` 同样计数);**证据行**(零命中 / 对照扫描,仅在 ID 单元格带 `[证据行]` 标记)改为必须携带核对命令(`git grep` / `git status --porcelain`)与原样结果、有真实锚点时至少 1 个,**豁免 ≥2 计数**;**非证据行带 `[证据行]` 标记即违规**。静态阅读不能定论者一律进 F 类,**不得写成错配 / 缺失 / 残留 / 待办**。"
- "**A 类覆盖全部 UI 面全局对象使用点(含边界非 UI 面只报告)**:至少覆盖 ① `packages-user/client-modules/src/render/ui/load.tsx` 的旧加载接口使用点(`:36` `client.loader`、`:71` `loader.initSystemLoadTask()`、`:72` `loader.load()`、`:75-79` 的 `loader.progress` 异步迭代与 `getLoadedTasks` / `getLoadedByte`、`:91-92` `getLoadedTasks` / `getAddedTasks`、`:118-119` `getTotalByte` / `getLoadedByte`、`:139` `getByteRatio`);② `packages-user/client-modules/src/render/ui/main.tsx` 的 `hook.on('statusBarUpdate', ...)` 监听点(`:140-143` 手工单次调用 + `:145-152` 被注释的 `hook.on` / `hook.off`);③ `packages-user/client-modules/src/render/index.tsx` 的 `hook.on('restart', ...)`(`:35-38`);④ **边界(非 UI,仅报告,不列为 AI 工作项)**:`packages-user/client-modules/src/client.ts:88-92,124-127`、`packages-user/client-modules/src/index.ts:1-8`、`packages-user/entry-client/src/create.ts:15-41` 的 `loading` / `hook` 被注释 / 移除点。**每条含命中处 `file:line` + 基准锚点 `file:line`(`d8fa4b8` 的删除事实或对应对象声明)。**"
- "**B 类为每处 A 提供「应改监听的对象」+ 证据,或显式「undetermined」**:对 A 的每一处给出目标对象 / 钩子接口并附现行源码 `file:line` 证据——旧加载面 → 新加载系统对象 `IMotaDataLoader`(`packages-user/data-state/src/loader/types.ts:19-72`)与 `ILoadManager`(`packages/loader/src/types.ts:288-335`)及实现 `LoadManager`(`packages/loader/src/manager.ts:10-112`)/ `MotaDataLoader`(`packages-user/data-state/src/loader/loader.ts:18-151`);状态栏 → 可 hook 的数据端对象接口(`packages-user/data-base/src/hero/types.ts:277-295` `IHeroLocationHooks`、`:428-443` `IHeroRenderingHooks`、`:652-671` `IEquipmentStateHooks`、`:883-903` `IHeroStateHooks`、`packages-user/data-common/src/common/mover.ts:166` `IObjectMoverHooks`、`packages-user/data-base/src/map/types.ts:220` `IMapLayerHooks`、`:599` `IGameMapHooks`、`packages-user/data-common/src/replay/types.ts:80` `IReplaySandboxHooks`、`:342` `IReplaySystemHooks`)。**无法从阅读确定目标对象者一律写「undetermined(无法从阅读确定目标对象)」,不得臆测。**"
- "**C 类覆盖「旧加载 UI 清单」与「新加载系统提供物」两侧且带 `file:line`**:旧侧 = `packages-user/client-modules/src/render/ui/load.tsx`(`LoadScene` / `LoadSceneUI`,`:35` / `:165`)与装配点 `packages-user/client-modules/src/render/index.tsx:11,25`(`createGameRenderer` 定义 `:13`,规划日实测**全仓无调用者**)、以及已删除的旧系统 `packages-user/client-base/src/load/{loader.ts,types.ts,data.ts,index.ts}`(`d8fa4b8` 删除)与旧接口 `IMotaAssetsLoader`(其 `initSystemLoadTask` / `addCustomLoadTask` / `load` / `progress` 成员);新侧 = `@motajs/loader`(`packages/loader/src/{manager.ts,starter.ts,stream.ts,task.ts,types.ts,index.ts}`)与 `packages-user/data-state/src/loader/{loader.ts,types.ts,hook.ts,index.ts}`(`MotaDataLoader` / `IMotaDataLoader` / `DefaultDataLoaderHook`)、以及 `CoreState.loader` / `CoreState.loadManager`(`packages-user/data-state/src/core.ts:205-208`、`packages-user/data-state/src/types.ts:26-43`)。**只登记事实与锚点,不得给修复 / 改写建议。**"
- "**D 类(D-69 桶导出边界)逐个登记 barrel 涉及与转发 / 反向依赖风险**:至少覆盖 `packages-user/client-modules/src/render/ui/index.ts`(14 行,**未** `export * from './load'`——旧加载 UI 不经 `ui` 桶暴露,由 `render/index.tsx:11` 深导)、`packages-user/client-modules/src/render/index.tsx:43-49`(7 条 `export *`,全为同目录项)、`packages-user/client-modules/src/index.ts`(`export * from './render'` 等)、`packages-user/client-base/src/index.ts`(`./material` / `./save` / `./types` / `./layout` / `./shared` / `./components` / `./elements` / `./map`),并判定每处 `export * from` 是否违反 D-69、是否存在为补齐导出面而转发 / 反向依赖的**候选**;**`packages/` 命中(如 `packages/client/src/index.ts`)只报告**(D-33)。**不得给补位 / 改指方案。**"
- "**E 类(legacy 命中·仅报告)与 in-scope 严格分开**:标题下明写「本节仅报告:按 D-49 / D-55 / D-65 不考虑任何 legacy 内容,legacy 相关报错一律不管、不修、不登记为待办」。逐条登记 —— `packages-user/client-modules/src/render/ui/main.tsx` 的 `core.*`(`:97,101-132,137` 等)与 `packages-user/client-modules/src/render/ui/{load.tsx,settings.tsx,statusBar.tsx,toolbar.tsx}` 等 UI 文件的 `core.*` / `Mota.require`;`packages/legacy-ui/src/preset/ui.ts:13,222` 经 `Mota.require('@user/data-base')` 取已删 `hook` / `loading`(**`packages/` 只报告**);`client` / `state` 单例使用(`render/ui/*.tsx` 的 `import { client } from '../../core'`、`main.tsx` 的 `state`,D-23 / D-28 适用范围)。"
- "**F 类(未能从阅读确定·未猜测)非空且只登记不判定**,至少覆盖:① `main.tsx` `statusBarUpdate` 的**精确监听对象集合**(状态栏聚合了 `client.hero.attribute` 只读属性 —— 该对象**不可 hook** —— 、`client.flags`、`core.status` 等,单一目标对象无法从阅读确定);② `render/index.tsx` 的 `restart` 事件在全局 `hook` 删除后**无新发射者**(`git grep` 仅命中 legacy `core.restart()` / `action/hotkey.ts:507` 的 hotkey 实现)⇒ 事件来源与新接线方式未定;③ 旧加载 UI 的「任务进度 / 字节进度 / 总字节」新数据来源(新 `ILoadManager` 有 `getTotalByte` / `getLoadedByte` / `getLoadedTasks` / `getAddedTasks` / `getTaskRatio` / `getByteRatio`,但旧 UI 期望的 `loader.progress` 迭代语义在新 API 下的等价写法未定);④ `packages-user/client-modules/src/client.ts` 与 `packages-user/entry-client/src/create.ts` 是否纳入「部分 UI」适配范围(D-71 措辞为「组件 / UI」,此二处非 UI);⑤ 旧加载面 `IMotaAssetsLoader` 的 `addCustomLoadTask` 能力在新 `IMotaDataLoader` 下由谁承接(`addCustomTask` 语义是否等价)。**不得把本类任何一条写成错配、缺失、残留或待办。**"
- "**修改点汇总(供后续执行计划消费)**:台账末节 `## 修改点汇总` 必须以固定列序表逐条列出「文件 `file:line` | 现状(旧全局对象 / 旧加载接口)| 应改为监听 / 使用的对象(附 B 类证据锚点,或 undetermined)| 归属(UI / 边界非 UI / 其余)| 置信」,使后续第二个执行计划可直接据此挑选工作集;**只汇总本台账已登记的条目,不得新增未登记事实、不得给代码写法**。"
- "**第二步(适配实施)不被规划**:台账只清点、分类、定位、分组,**不含**代码改动方案、不含具体 import / 调用改写写法、不产出 `04-14-PLAN.md` 或任何新 `*-PLAN.md`;`## 处置` 明写「第一步只读收集完成;第二步(适配实施)待用户审阅本文件后另行规划」(D-72)。"
- "**无运行时要求 + REND 保持 Pending(D-68 延续)**:验证一律为**静态**(porcelain 基线一致 + 台账结构 / 锚点 / 分类关键词 + 禁用路径 porcelain 为空 + CRLF + 既有产物保护),**不得**出现任何以「`pnpm check:type` 通过」「`pnpm build` 成功」「TS 诊断数归零」为条件的门禁或验收项;`packages-user/client-base/src/material/**`(D-42 / D-48)、`packages/**`、`src/**`、任何测试文件、用户并发改动(D-56)**全部零触碰**;`REND-01` / `REND-02` 在本 run 后仍为 **Pending**,`.planning/REQUIREMENTS.md` 零改动。"
artifacts:
- path: .planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md
provides: "「部分 UI 的进一步接口适配」(D-71 / D-72)**第一步·只读影响台账**:元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / `A 全局 loading / hook 使用点(UI 面)` / `B 目标对象与钩子 API 证据` / `C 旧加载 UI 清单与新加载系统` / `D 分层与 barrel(D-69)检查` / `E legacy 命中(仅报告)` / `F 未能从阅读确定(未猜测)` / `修改点汇总(供后续执行计划消费)` / `处置`;A–E 每节固定列序表,事实行每行 ≥2 个 `file:line` 锚点,证据行带 `[证据行]` 标记与核对命令;供用户审阅后裁定第二步适配的工作集与改指目标"
key_links:
- "`packages-user/client-modules/src/render/ui/load.tsx:71,72,76-79,91-92,118-119,139`(旧加载接口 `initSystemLoadTask` / `load` / `progress`)↔ `packages-user/data-state/src/loader/types.ts:19-72`(新 `IMotaDataLoader`:`start` / `loaded` / `manager` / `addCoreConfig` / `addExtraConfig` / `addCustomTask` / `getConfig`)与 `packages/loader/src/types.ts:288-335`(`ILoadManager`)—— 旧加载 UI 必须改依新加载系统的改指依据(B 类证据)"
- "`packages-user/client-modules/src/render/index.tsx:11,25`(`LoadSceneUI` 深导 + `sceneController.open(LoadSceneUI, {})`)↔ `packages-user/client-modules/src/render/index.tsx:13`(`createGameRenderer` 定义,规划日实测无调用者)—— 旧加载 UI 当前**不可达**的事实链"
- "`packages-user/client-modules/src/client.ts:88-92,124-127`(被注释的 `loading.once('loaded' / 'assetBuilt')`)↔ `packages-user/data-state/src/core.ts:205-208` 与 `packages-user/data-state/src/loader/loader.ts:84-142`(新加载系统在数据端 `start()` / `loaded()`)—— 「对应对象」接线的数据端锚点(本步只登记,不改)"
- "`packages-user/client-modules/src/render/ui/main.tsx:97,101-132`(状态栏读取字段)↔ `packages-user/data-base/src/hero/types.ts:277,428,652,883` 与 `packages-user/data-common/src/common/mover.ts:166`、`packages-user/data-base/src/map/types.ts:220,599`、`packages-user/data-common/src/replay/types.ts:80,342`(可 hook 的数据端对象接口)—— `statusBarUpdate` 改监听对象的候选证据;`client.hero.attribute` 不可 hook 为 F 类依据"
- "`packages-user/client-modules/src/render/ui/index.ts`(无 `./load` 导出)↔ `packages-user/client-modules/src/render/index.tsx:11`(深导 `./ui/load`)↔ `packages-user/client-base/src/index.ts`(8 条同目录 `export *`)—— D-69 桶导出边界的检查链"
- "`packages-user/client-modules/src/render/ui/{load.tsx,main.tsx}` 与 `packages-user/client-modules/src/render/index.tsx`(`core.*` / `client` 单例 / `state`)↔ `packages/legacy-ui/src/preset/ui.ts:13,222`(经 `Mota.require('@user/data-base')` 取已删 `hook` / `loading`)—— E 类 legacy 只报告对象"
- "`git status --porcelain -- packages packages-user src`(Task 1 步骤 (0a) 逐行记录;规划日 2026-09-30 实测为空)↔ Task 1 / Task 4 门禁的逐条一致断言 + `.planning/phases/04-render-adaptation/04-CONTEXT.md` 未提交改动仍在的断言 ↔ 只读(生产代码零改动)与 D-56 证明"
assumptions:
- "**FLAGGED ASSUMPTION(specless fallback)— REND-01 edge unresolved:** 未提供 REND-01(渲染端适配新数据层接口)的验收边界;本计划**不发明**阈值,只交付「部分 UI 进一步接口适配」的第一步只读影响台账(D-71 / D-72)。用户须在推进第二步与 REND-01 余下部分前补齐边界判据。"
- "**FLAGGED ASSUMPTION(specless fallback)— REND-02 edge unresolved:** 未提供 REND-02(移动端与桌面端双布局)的验收边界;本计划不涉及双布局,也不发明其验收阈值。"
- "**基准提交为 `d8fa4b8 refactor: Delete global loading & hook object`(规划日 2026-09-30 实测 HEAD `8b114c7 docs(04-12): sync tracking (executed on another device)`,分支 `refine/data-client`):** 该提交删除了 `packages-user/client-base/src/load/**`(旧加载系统)与 `packages-user/data-base/src/game.ts`、`packages-user/data-base` 的 `load`(全局 `hook` / `loading` 对象),并把 16 个文件里的 `loading` / `hook` 用法改为注释;本台账以该提交后的工作树为基准,行号在当日实测下有效。**执行日一律以当日实测定位(按符号名 / 文本检索),任一与规划日不同即以当日实测写入台账并在 SUMMARY 说明差异,不得按本计划的规划日行号硬写。**"
- "**规划日实测(须用户在审阅时确认):** UI 面 A 类 = `load.tsx`(旧加载接口 7 组使用点)+ `main.tsx`(`statusBarUpdate` 2 处监听 + 1 处手工调用)+ `render/index.tsx`(`restart` 1 处);边界非 UI = `client.ts`(2 处被注释)、`client-modules/src/index.ts`(1 处 `loading.once('coreInit')` 已移除)、`entry-client/src/create.ts`(`registered` / `clientRegistered` / `renderLoaded` 共 3 处,均注释);C 类旧侧 = `load.tsx`(`LoadScene` / `LoadSceneUI`)+ `render/index.tsx:11,25` + 已删的 `client-base/src/load/**`;新侧 = `@motajs/loader` + `data-state/src/loader/**` + `CoreState.loader` / `loadManager`;D 类 = 4 个 barrel 节点;E 类 = `core.*` / `Mota.require` / `client` / `state`;F 类 ≥ 5 条。**执行日以当日实测为准。**"
- "**`createGameRenderer` 规划日实测无调用者:** `git grep -n \"createGameRenderer\" -- packages-user packages src` 仅命中 `render/index.tsx:13` 的定义;`packages-user/client-modules/src/index.ts:1-8` 的 `create()` 现只调用 `patchAll()` + `createRender()`。故旧加载 UI(`LoadSceneUI`)当前**不可达**。此为**事实登记**(不作为「问题」判定):执行日须以 `git grep` 复验并原样记录;若当日已有调用者,按当日实测改写。"
- "**执行日行号可能漂移:** 用户会并发改其它文件(D-56);本计划引用的 `file:line` 是 2026-09-30 的规划日锚点。执行时一律按符号名 / 文本检索定位,不得按规划日行号硬写。"
- "**无运行时验证可得(D-68 的延续):** 本步为只读收集,不产生任何运行时行为(不启动渲染、不改代码、不新增测试),承载体为静态门禁 + 人工复核;**不得**以 `pnpm check:type` / `pnpm build` / TS 诊断数之类的条件冒充门禁。"
- "**台账只登记事实、不改代码、不做适配设计:** `## 修改点汇总` 只汇总本台账已登记的条目;任何「应改为 X」的具体代码写法、任何 `import` / 调用改写方案、任何接口新增 / 改名,均属第二步(D-72)且须用户裁定,本步一概不做。"
prohibitions:
- "不得在用户明确回复「可以执行」四个字之前执行本计划的任何任务、或派发任何执行子代理(AGENTS.md 的第一个 block 点约束;不因触发方式或 `yolo` / `auto_advance` 模式而放宽)。"
- "不得修改任何生产源码:`packages/**`、`packages-user/**`、`src/**` 的生产文件一律零改动;不得新增 / 删除 / 改写任何 `.ts` / `.tsx` 生产文件;**不得移动、不得复制、不得预建**任何目标文件或目录(适配属第二步,本步不规划)。"
- "不得改动 `package.json` / `pnpm-lock.yaml` / `tsconfig.json` / `.eslintrc`;不得新增依赖;不得执行 `pnpm i`。"
- "不得修改任何既有 jsDoc / 注释文本(AGENTS.md);**不得引入任何命名变更**(不新增 / 改名 / 删除任何公共、受保护、私有成员、方法、字段、文件或目录);如发现某接口确需新增或改名,只登记进 F 类交用户裁决,不得自行命名。"
- "不得把任何 legacy 内容当成问题或待办(D-49 / D-55 / D-65):`core.*` / 已删的全局 `loading` / `hook` / `Mota.require` 命中一律只报告,不得修复、不得登记为待办、不得写成错配或残留。"
- "不得触碰、暂存、提交用户的并发改动(D-56):不得提交 `.planning/phases/04-render-adaptation/04-CONTEXT.md` 的既有未提交改动;提交前必须以 `git status` 逐条核对暂存面,只暂存本计划的 `files_modified` 与 `04-13-SUMMARY.md`。"
- "不得改写 / 覆盖 / 改号 `04-01`..`04-12` 的既有 `*-PLAN.md` 与 `*-SUMMARY.md`;不得改写既有 `04-CONTEXT.md`;不得产出 `04-14+` 或任何新计划文件。除本 `04-13-PLAN.md`、`04-UI-ADAPTATION-IMPACT.md`、`04-13-SUMMARY.md` 与 `.planning/ROADMAP.md` 的登记外,不得写任何其它文件(含 `.planning/STATE.md` / `WINDOWS.md` / `REQUIREMENTS.md`)。"
- "不得给出适配方案:不得给出具体 `import` / 调用改写写法、不得给出新接口设计、不得裁定改指目标;`statusBarUpdate` / `restart` 的目标对象无法从阅读确定者一律进 F 类。"
- "不得把 A / B / C / D / E 混为一类:A 记全局 `loading` / `hook` 的使用点、B 记目标对象与钩子 API 证据、C 记旧加载 UI 与新加载系统、D 记分层与 barrel(D-69)、E 记 legacy 命中(仅报告);同一事实若跨类,拆条并互相引用,不得互相冒充。"
- "不得使用 `import type`(dev.md 项目规则);不得新增、删除或修改任何测试文件与既有测试。"
- "不得把任何门禁建立在「全仓 / 范围内 TS 诊断数」「`pnpm check:type`」「`pnpm build`」之上,也不得因这类检查失败而阻塞交付(D-68)。"
- "不得以「无运行时」为由弱化验证:每条 `<automated>` 必须有 `<fails_when>`;确实无法运行的门禁必须显式声明为不可得并降级为静态 + 人工,不得伪造绿。"
---
<objective>
Phase 4 第十三个增量(用户裁定 2026-09-25 · **D-71 / D-72 / D-73**)—— **部分 UI 的进一步接口适配·第一步(只读收集需要修改的点)**。
**要解决的问题:**
数据端经用户近期调整后,渲染端**部分 UI** 仍以已失效的旧接口编写,主要有两类(D-71):
1. **全局 `loading` / `hook` 对象已被删除**(提交 `d8fa4b8 refactor: Delete global loading & hook object`):组件**不得**再依赖这些全局对象监听全局钩子,**必须在对应的对象上监听**。当前 UI 面仍有对 `hook.on('statusBarUpdate', ...)`(`render/ui/main.tsx:146-151`)、`hook.on('restart', ...)`(`render/index.tsx:35-38`)的注释残留与手工单次调用(`main.tsx:140-143`)。
2. **加载系统重构**:旧加载系统(`packages-user/client-base/src/load/**` 与 `IMotaAssetsLoader`)已随 `d8fa4b8` 删除,现使用新的加载系统(`@motajs/loader` 的 `LoadManager` + `packages-user/data-state/src/loader/**` 的 `MotaDataLoader` / `IMotaDataLoader`)。**旧的加载 UI(`render/ui/load.tsx`)已不能用了,需要重新适配**——它仍调用 `loader.initSystemLoadTask()` / `loader.load()` / `loader.progress` 等旧接口(`load.tsx:71,72,76-79,91-92,118-119,139`)。
**锁定裁定(D-71 / D-72 / D-73):**
- **D-71(目标)**:完成部分 UI 的进一步接口适配;上列两类即待适配点。
- **D-72(两步走)**:本目标**至少两个计划**——**第一个计划只做只读收集**(清点需要修改的点,产出影响台账;生产代码零改动);**第二个及后续**才真正执行适配。第一个计划的产出是后续执行计划的输入。
- **D-73(边界延续)**:沿用既有约束——范围外一律不改、不追平全部类型错误(D-33);`client-base/src/material/**` 归用户、AI 不得改(D-42 / D-48);不考虑任何 legacy(D-49 / D-55 / D-65);不得触碰 / 提交用户并发改动(D-56);不要求「保证能运行」、不得以 `check:type` / `build` / TS 诊断数作为门禁(D-68);桶导出边界(**D-69**)继续适用。
**大致解决方案(本计划 = 04-13,单一计划文件,只读):**
产出唯一交付物 `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md`。台账结构(模型参照 `04-TEXTURE-INTERFACE-IMPACT.md` / `04-STRUCTURE-MIGRATION-IMPACT.md`):
| 节 | 内容 | 类别 |
|---|---|---|
| 元信息块 + 只读起始基线 | 日期 / 范围 / 性质 / 基准提交 `d8fa4b8` + 当日 HEAD / 新加载系统基准 / 下一步;Task 1 (0a) 的 porcelain 原样快照 | — |
| 基准变更(d8fa4b8) | 该提交删除全局 `loading` / `hook` 与旧加载系统、并把 16 文件用法改注释的事实清单(带 `file:line`) | — |
| A 全局 loading / hook 使用点(UI 面) | 每处 `file:line`:`load.tsx` 旧加载接口、`main.tsx` `statusBarUpdate`、`render/index.tsx` `restart`;边界非 UI 面(`client.ts` / `client-modules/index.ts` / `entry-client/create.ts`)只报告 | A |
| B 目标对象与钩子 API 证据 | 每处 A 应改监听 / 使用的对象 + 现行源码 `file:line`,或显式 undetermined | B |
| C 旧加载 UI 清单与新加载系统 | 旧 `LoadScene` / `LoadSceneUI` + 已删的 `client-base/src/load/**` / `IMotaAssetsLoader`;新 `@motajs/loader` + `data-state/src/loader/**` + `CoreState.loader` / `loadManager` | C |
| D 分层与 barrel(D-69)检查 | `render/ui/index.ts`(无 `./load` 导出)/ `render/index.tsx` 7 条导出 / `client-modules/src/index.ts` / `client-base/src/index.ts` 的转发 / 反向依赖候选 | D |
| E legacy 命中(仅报告) | `core.*` / `Mota.require`(legacy)不修、不登记为待办;`client` / `state` 单例另属 D-23 / D-28 的只读范围(**非 legacy**),一并只报告 | E / D-23 / D-28 |
| F 未能从阅读确定(未猜测) | `statusBarUpdate` 精确对象集合 / `restart` 无新发射者 / 旧加载 UI 新数据来源 / 客户端边界是否纳入 / `addCustomLoadTask` 承接 | F |
| 修改点汇总(供后续执行计划消费) | 固定列表:文件 `file:line` / 现状 / 应改对象(证据或 undetermined)/ 归属 / 置信 | — |
| 处置 | 只读完成;第二步待用户审阅后另行规划(D-72) | — |
**范围与硬边界:** 被查对象 = 渲染端**部分 UI**(`packages-user/client-modules/src/render/ui/**` + `packages-user/client-modules/src/render/index.tsx`)及其对已删全局 `loading` / `hook` 与旧加载系统的使用点;边界(非 UI)面(`client.ts` / `client-modules/src/index.ts` / `entry-client/src/create.ts`)**只报告**;`packages-user/client-base/src/material/**`(D-42 / D-48)、`packages/**`、`src/**`、legacy 面(D-55 / D-65)、用户并发改动(D-56)零触碰。生产源码零改动;本步**只读**,不引入任何命名变更,不规划第二步。
**任务切分(Task 0 汇报关卡 + Task 1 tracer + 2 个横向铺开任务 + Task 4 收口):** 委托明确指定 `04-13` 为唯一新计划,故落在**单一计划文件**内。Task 1(tracer)= **旧加载 UI(`load.tsx`)对旧加载接口的使用**这一条线**端到端**走完台账每一节(A 使用点 → B 新对象证据 → C 旧 / 新加载系统两侧 → D barrel → E legacy → F undetermined → 修改点汇总),先用一个真实适配点证明台账格式与证据纪律;Task 2 = A 类剩余 UI 面(`main.tsx` `statusBarUpdate` / `render/index.tsx` `restart`)+ 边界非 UI 面(只报告)+ B 类目标对象证据铺开;Task 3 = C / D / E / F 铺开 + `## 修改点汇总` 定稿;Task 4 = 收口(只读基线一致 + 台账结构 / 锚点门禁 + 范围门禁 + 既有产物保护 + CRLF + 人工复核 + `04-13-SUMMARY.md` + 白名单提交)。
## Source Audit(多源覆盖审计)
| SOURCE | ID | Feature/Requirement | Plan | Status | Notes |
|--------|----|---------------------|------|--------|-------|
| GOAL | — | Phase 4:「渲染端通过新数据层接口驱动,并同时支持移动端与桌面端布局」 | 04-13 | COVERED(增量·只读收集子切片) | 本 run 只收集「部分 UI 进一步接口适配」需修改的点(D-71 / D-72 第一步);适配实施与双布局属后续增量(见 assumptions 的两条 FLAGGED ASSUMPTION) |
| REQ | REND-01 | 渲染端适配新数据层接口 | 04-13 | COVERED(子切片·只读前置;需求保持 Pending) | 「组件改在对应对象上监听、旧加载 UI 改依新加载系统」是 REND-01 的 UI 切片;本 run 不移交任何接口行为;验收边界未提供 → FLAGGED ASSUMPTION |
| REQ | REND-02 | 渲染端同时支持移动端与桌面端布局 | 04-13 | COVERED(不涉及) | 本 run 范围不含双布局;验收边界未提供 → FLAGGED ASSUMPTION |
| RESEARCH | — | (本阶段无 `04-RESEARCH.md`) | — | N/A | Phase 4 未产出 RESEARCH.md;等价输入为既有台账 `04-TEXTURE-INTERFACE-IMPACT.md` / `04-STRUCTURE-MIGRATION-IMPACT.md`(格式模板)与 `04-12-PLAN.md`(只读 / 关卡风格) |
| CONTEXT | D-71.1 | 全局 `loading` / `hook` 已删,组件须在对应对象上监听 | 04-13 | COVERED | Task 1(tracer 的旧加载面)+ Task 2(`statusBarUpdate` / `restart` / 边界面);B 类逐处给目标对象证据或 undetermined |
| CONTEXT | D-71.2 | 加载系统重构,旧加载 UI 需重新适配 | 04-13 | COVERED | Task 1(tracer)+ Task 3(C 类旧 / 新加载系统两侧清单) |
| CONTEXT | D-72 | 至少两个计划;第一个只读收集 | 04-13 | COVERED(第一步) | 本 run = 第一步;`## 处置` 明写第二步待用户审阅后另行规划 |
| CONTEXT | D-73 / D-33 | 范围外一律不改、不追平全部类型错误 | 04-13 | COVERED(边界) | `packages/` 与 `src/` 零改动;无「诊断归零」验收项 |
| CONTEXT | D-42 / D-48 | `client-base/src/material/` 归用户、AI 不得改 | 04-13 | COVERED(禁用路径) | 范围门禁断言 `material/` porcelain 为空;prohibitions 明列 |
| CONTEXT | D-49 / D-55 / D-65 | 不考虑任何 legacy | 04-13 | COVERED(E 类仅报告) | 无 legacy 任务 / 门禁 / 待办;prohibitions 明列 |
| CONTEXT | D-56 | 用户并发改动零触碰 | 04-13 | COVERED | Task 1 (0a) 逐行记录基线(规划日实测为空);Task 4 断言既有条目一致且 `04-CONTEXT.md` 未提交改动仍在 |
| CONTEXT | D-68 | 不要求可运行、不以 TS 诊断数 / `check:type` / `build` 为门禁 | 04-13 | COVERED(延续) | 全部门禁为静态;prohibitions 明列 |
| CONTEXT | D-69 | 桶导出边界原则(硬约束) | 04-13 | COVERED(D 类检查) | D 类逐个登记 barrel 涉及与转发 / 反向依赖候选;只报告,不给补位方案 |
| LEDGER | `#04-10-E-03` | `render/elements/cache.ts:491-492` / `render/elements/misc.ts:89,219` 的全局 `loading` + `Mota.require('@user/data-base')` | 04-13 | COVERED(E 类对照) | 04-11 已把这些文件移入 `client-base`;本步把 UI 面 legacy 命中只报告 |
| LEDGER | `#04-08-E-03` / `#04-08-F-06` | 旧加载系统 `client-base/src/load/loader.ts` 与 `textures` 写入侧归属 | 04-13 | COVERED(C 类对照) | `d8fa4b8` 已删除旧加载系统;本步登记新加载系统提供物,不改代码 |
| Deferred Ideas | — | 阶段 4 后续步骤(适配实施、双布局);`packages` 全部、`entry-client`、`legacy-plugin-*`、`data-fallback` | — | DEFERRED | 未写入任何任务;`entry-client` 仅作 A 类边界只报告对象 |
## Estimate Basis(估算依据)
`estimate-calibration` 返回 `factor: 1`、`applied: false`、`sample_count: 0`、`confidence: low`(项目无历史样本),故 `tokens == raw_tokens` 并如实标注 `confidence: low`。按「执行者实际触及量」估算(`estimate.tasks: 5` = Task 0 汇报关卡 + 4 个工作任务):Task 0 只读汇报并等待用户确认(约 5k,不写文件);Task 1(tracer)起始只读基线 + 台账骨架 + 旧加载 UI 一条线端到端(约 16k);Task 2 A 类剩余 UI 面 + 边界面 + B 类目标对象证据铺开(约 13k);Task 3 C / D / E / F 铺开 + 修改点汇总定稿(约 13k);Task 4 收口门禁 + 人工复核 + `04-13-SUMMARY.md` + 白名单提交(约 13k);合计约 60k。**本计划刻意不做多计划拆分**:委托明确要求只产出 `04-13` 一份只读计划。
</objective>
<execution_context>
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/REQUIREMENTS.md
@.planning/phases/04-render-adaptation/04-CONTEXT.md
@.planning/phases/04-render-adaptation/04-TEXTURE-INTERFACE-IMPACT.md
@.planning/phases/04-render-adaptation/04-STRUCTURE-MIGRATION-IMPACT.md
@.planning/phases/04-render-adaptation/04-11-PLAN.md
@.planning/phases/04-render-adaptation/04-12-PLAN.md
@AGENTS.md
@dev.md
</context>
<tasks>
<task type="checkpoint:decision" gate="blocking-human">
<name>Task 0: 预执行汇报关卡 —— 汇报「部分 UI 的进一步接口适配·第一步(只读收集)」的问题、D-71 / D-72 / D-73 裁定、收集面与台账结构、范围与硬边界、验证方式,等待用户回复「可以执行」</name>
<precondition>用户对「部分 UI 进一步接口适配」的裁定 D-71 / D-72 / D-73 已写入 `.planning/phases/04-render-adaptation/04-CONTEXT.md`(以文件内实际存在 D-71 / D-72 / D-73 为准);当日工作树上 `d8fa4b8 refactor: Delete global loading & hook object` 已在 HEAD 历史中(`git merge-base --is-ancestor d8fa4b8 HEAD` 退出码 0);`packages-user/client-base/src/load/` 目录不存在;`packages-user/client-modules/src/render/ui/load.tsx` 仍含 `loader.initSystemLoadTask()` / `loader.load()` / `loader.progress` 形态;`packages-user/client-modules/src/render/ui/main.tsx` 仍含被注释的 `hook.on('statusBarUpdate', ...)`;`packages-user/client-modules/src/render/index.tsx` 仍含被注释的 `hook.on('restart', ...)`。</precondition>
<files>(只读汇报,不修改任何文件)</files>
<read_first>
- AGENTS.md(「任何计划的执行,其第一个 block 点必须是向我汇报计划内容并等待我确认」;只有明确回复「可以执行」四个字之后才允许开始执行;「任何公共、受保护、私有方法、字段等内容的命名必须先向我反馈」;「不得擅自修改所有 jsDoc 注释,不得擅自修改任何已有注释」;「除非我明确要求,否则任何修改必须经由 GSD 标准流程」)
- .planning/phases/04-render-adaptation/04-CONTEXT.md(**:133-139 的 D-71 / D-72 / D-73 逐条裁定原文**;D-33 范围;D-42 / D-48 `material/` 禁用;D-49 / D-55 / D-65 legacy 不管;D-56 用户并发改动;D-68 无运行时门禁;D-69 桶导出边界)
- .planning/phases/04-render-adaptation/04-12-PLAN.md(上一增量 Task 0 汇报关卡的结构与口径,本关卡对齐版式)
- .planning/phases/04-render-adaptation/04-TEXTURE-INTERFACE-IMPACT.md 与 04-STRUCTURE-MIGRATION-IMPACT.md(台账格式 / 证据纪律模板:元信息块 + 固定列序表 + A–F 分类 + 处置)
- .planning/phases/04-render-adaptation/04-13-PLAN.md(本计划全文:objective 的台账结构表、tasks、must_haves、禁令、门禁)
- dev.md(「项目结构」单向依赖;「双端分离」`@user/client-base` 系统层 / `@user/client-modules` 实现层;「模块原则」的**不转发导出**与引入位置;「其他要求」的 CRLF)
</read_first>
<action>
**停下并向用户汇报,等待明确回复后才继续;汇报本身只读,不写任何文件、不改任何生产代码、不派发子代理。**
① **要解决的问题(D-71)**:数据端经用户近期调整(含 `d8fa4b8 refactor: Delete global loading & hook object` 与加载系统重构)后,渲染端**部分 UI** 仍以已失效的旧接口编写,主要有两类:
- **全局 `loading` / `hook` 对象已被删除**:组件不得再依赖这些全局对象监听全局钩子,必须在对应的对象上监听。当前残留:`packages-user/client-modules/src/render/ui/main.tsx:146-151`(被注释的 `hook.on('statusBarUpdate', ...)` / `hook.off`)+ `:140-143`(避免「未使用函数」的手工单次调用)、`packages-user/client-modules/src/render/index.tsx:35-38`(被注释的 `hook.on('restart', ...)`)。
- **加载系统重构**:旧加载系统(`packages-user/client-base/src/load/**` 与 `IMotaAssetsLoader`)已随 `d8fa4b8` 删除,现使用新加载系统(`@motajs/loader` 的 `LoadManager` + `packages-user/data-state/src/loader/**` 的 `MotaDataLoader` / `IMotaDataLoader`)。**旧加载 UI(`packages-user/client-modules/src/render/ui/load.tsx`)已不能用了**——它仍调用 `loader.initSystemLoadTask()`(`:71`)、`loader.load()`(`:72`)、`loader.progress`(`:76-79,91-92,118-119,139`)等旧接口,须重新适配。
② **锁定裁定(须逐条汇报原文要点)**:
- **D-71(目标)**:完成部分 UI 的进一步接口适配;上列两类即待适配点。
- **D-72(两步走)**:本目标至少两个计划——第一个计划只做只读收集(清点需要修改的点,产出影响台账;生产代码零改动);第二个及后续才真正执行适配。第一个计划的产出是后续执行计划的输入。
- **D-73(边界延续)**:沿用 D-33(范围外不改、不追平全部类型错误)、D-42 / D-48(`client-base/src/material/**` 归用户、AI 不得改)、D-49 / D-55 / D-65(不考虑任何 legacy)、D-56(不得触碰 / 提交用户并发改动)、D-68(不要求可运行、不得以 `check:type` / `build` / TS 诊断数作为门禁)、**D-69(桶导出边界原则继续适用)**。
③ **源 → 目标映射(须原样呈报)**:本计划 = 04-13,唯一交付物 = `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md`(只读台账),结构 = 元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / `A 全局 loading / hook 使用点(UI 面)` / `B 目标对象与钩子 API 证据` / `C 旧加载 UI 清单与新加载系统` / `D 分层与 barrel(D-69)检查` / `E legacy 命中(仅报告)` / `F 未能从阅读确定(未猜测)` / `修改点汇总(供后续执行计划消费)` / `处置`;A–E 固定列序表 `| ID | 项目 | 命中处 file:line | 目标锚点 / 证据 file:line | 问题描述 | 影响 | 置信 |`,事实行每行 ≥2 个 `file:line` 锚点,证据行带 `[证据行]` 标记与核对命令。
④ **范围与硬边界(须原样呈报)**:被查对象 = 渲染端**部分 UI**(`packages-user/client-modules/src/render/ui/**` + `packages-user/client-modules/src/render/index.tsx`)及其对已删全局 `loading` / `hook` 与旧加载系统的使用点;**边界(非 UI,仅报告)** = `packages-user/client-modules/src/client.ts:88-92,124-127`、`packages-user/client-modules/src/index.ts:1-8`、`packages-user/entry-client/src/create.ts:15-41`。**零触碰** = `client-base/src/material/**`(D-42 / D-48)、`packages/**`、`src/**`、任何测试文件、legacy 面(D-55 / D-65)、用户并发改动(D-56)。**生产源码零改动;无依赖变更、不执行 `pnpm i`。** **本步为只读台账、不引入任何命名变更**(不新增 / 改名 / 删除任何公共、受保护、私有成员、方法、字段、文件或目录)。
⑤ **验证方式(须原样呈报,并声明本步无运行时要求)**:D-68 的延续——本步**没有「保证能运行」的要求**。证明方式全部为**静态**:① **只读基线门禁**:`git status --porcelain -- packages packages-user src` 与 Task 1 (0a) 逐行一致;`.planning/REQUIREMENTS.md` 零改动;`.planning/phases/04-render-adaptation/04-CONTEXT.md` 的既有未提交改动仍在;② **台账结构门禁**:要求小节齐备、A–E 表存在、固定列序;③ **证据纪律门禁**:事实行每行 ≥2 个 `file:line` 锚点(证据行豁免)、`[证据行]` 标记未误用;④ **内容门禁**:`load.tsx` 旧加载接口使用点、`main.tsx` `statusBarUpdate`、`render/index.tsx` `restart`、新加载系统 `file:line` 证据、D-69 barrel 检查、E 类 legacy 只报告、F 类未确定、修改点汇总均在案;⑤ **范围门禁**:`material/` / `packages/` / `src/` porcelain 为空;⑥ **既有产物保护**:`04-01`..`04-12` 的 `*-PLAN.md` / `*-SUMMARY.md` porcelain 为空、phase 目录内无 `04-14+`;⑦ **CRLF 门禁**;⑧ **人工复核**。**不得使用** `pnpm check:type` / `pnpm build` / 全仓(或范围内)TS 诊断数作为门禁或验收项。
⑥ **编号与 wave(须原样告知)**:本计划为 **04-13**(第十三个增量),`wave: 12`,`depends_on` 列 `04-01`..`04-12`;phase 目录内既有 `04-01`..`04-12` 的 `*-PLAN.md` 与 `*-SUMMARY.md` **一律不得改写 / 覆盖 / 改号**,也不得产出 `04-14+`。本计划估算 **60k tokens**(`estimate.tasks: 5`),在单计划 smart-zone 预算内。
⑦ **盖章效力(须原样告知)**:本计划为**只读**增量,**生产代码改动为 0**;只写一个台账文档(+ 计划 / SUMMARY 簿记 + ROADMAP 登记)。无任何代码改动需回退。
⑧ **关卡性质与失败语义(必须原样告知用户)**:无论触发方式(`/gsd-execute-phase`、`/gsd-manager`、`/gsd-autonomous`、子代理/执行器派发)或配置模式(`.planning/config.json` 的 `mode: yolo`、`workflow.auto_advance`)如何,**执行者 / 子代理都必须在此停下并等待**用户明确回复「可以执行」四个字;未收到这四个字前不得执行任何任务、不得派发执行子代理,也不得以「自动化模式」为由自动放行。用户未回复「可以执行」即继续,或回复的是其它任何内容(含修订意见、沉默、自动化模式下的自动推进、子代理的自行放行),一律视为**未通过本关卡**:必须立即停止执行、保持只读、不写任何文件,直到用户明确回复「可以执行」四个字后方可继续。
⑨ **若用户给出修订意见**(含要求把 `client.ts` / `entry-client` 提为正式工作项 / 要求纳入更多 UI 文件 / 否决某类分类口径 / 不同意台账结构):退出本计划、修订 `04-13-PLAN.md` 后重新汇报,不得自行改道执行。
</action>
<decision>是否按本计划(04-13:只读收集「部分 UI 的进一步接口适配」需修改的点——全局 `loading` / `hook` 使用点(`load.tsx` / `main.tsx` / `render/index.tsx`,另 `client.ts` / `client-modules/index.ts` / `entry-client/create.ts` 只报告)+ 旧加载 UI 与新加载系统两侧清单 + D-69 barrel 检查 + legacy 只报告 + 未确定项 + 修改点汇总,产出 `04-UI-ADAPTATION-IMPACT.md`,生产代码零改动、不引入任何命名变更、无运行时要求)开始执行</decision>
<context>
AGENTS.md 要求任何计划的第一个 block 点必须是向用户汇报计划内容并等待用户确认。`.planning/config.json` 为 `mode: yolo`,因此该关卡必须显式声明为 `blocking-human` 并置 `autonomous: false`,否则计划层面不提供任何 block 点。本次存在会改变台账范围 / 分类的判断(`client.ts` 与 `entry-client` 是否纳入「部分 UI」;`statusBarUpdate` 聚合对象的精确集合;`restart` 无新发射者时如何登记),以及一条会放宽验收的既有裁定(D-68:不要求可运行、不要求零类型错误)必须让用户明确知晓,避免执行者事后用「类型不干净」为由扩大范围或阻塞交付。规划日实测的用户并发未提交改动为 `.planning/phases/04-render-adaptation/04-CONTEXT.md`(D-71..D-73 的落点),本计划必须完全不触碰它。
</context>
<options>
<option id="execute">
<name>可以执行</name>
<pros>按本计划只读收集:产出 `04-UI-ADAPTATION-IMPACT.md` 台账,不产生任何生产代码改动、不引入任何命名变更;后续第二个执行计划据此挑选工作集</pros>
<cons>无(只读台账;正确性由静态门禁 + 人工复核共同证明)</cons>
</option>
<option id="widen-scope">
<name>可以执行,但把 client.ts / entry-client 提为正式工作项</name>
<pros>把非 UI 面的 `loading` / `hook` 使用点一并纳入正式适配范围</pros>
<cons>超出 D-71 的「部分 UI」措辞;需修订本计划并重新汇报</cons>
</option>
<option id="revise">
<name>修订收集面 / 分类口径 / 台账结构后再执行</name>
<pros>避免带着错误的范围或错误的分类落地后再返工</pros>
<cons>退出本计划并修订 PLAN.md 后重新汇报,增加一轮往返</cons>
</option>
</options>
<resume-signal>回复「可以执行」四个字(修订意见请按 action ⑨ 处理)</resume-signal>
<verify>
<human-check>用户在对话中明确回复「可以执行」四个字(人工核对用户回复原文;本关卡为人工关卡,无自动命令,失败语义写在 Task 0 的 action ⑧ 与 acceptance_criteria 中)</human-check>
</verify>
<acceptance_criteria>
- 用户回复中明确包含「可以执行」四个字
- 汇报内容涵盖:要解决的问题(两类待适配点:已删的全局 `loading` / `hook`、重构后的加载系统与旧加载 UI)、锁定裁定 **D-71 / D-72 / D-73 原文要点**、收集面与台账结构(元信息块 + 12 小节 + A–F 六类)、范围与硬边界(`material/` 与 legacy 与 `packages/` 与 `src/` 与用户改动零触碰 + 无依赖变更 + 本步不引入任何新命名)、验证方式
- 汇报中已原样告知 **D-68 的延续**(没有「保证能运行」的要求;不设 `check:type` / `build` / TS 诊断数类门禁)与 **本步不引入任何新命名**
- 汇报中已原样告知 **编号与 wave**(04-13 / wave 12 / `depends_on` 04-01..04-12)以及既有 `04-01`..`04-12` 产物不得改写 / 覆盖 / 改号、不得产出 `04-14+`
- 汇报中已原样告知**验证方式**(只读基线 / 台账结构 / 证据纪律 / 内容 / 范围 / 既有产物保护 / CRLF / 人工复核)
- 汇报中已原样告知**关卡性质**:执行者 / 子代理必须停下等待,不因触发方式或 `yolo` / `auto_advance` 模式自动放行
</acceptance_criteria>
<done>用户明确回复「可以执行」;在此之前未执行任何任务、未修改任何文件、未派发任何执行子代理</done>
</task>
<task type="tracer">
<name>Task 1(tracer):一条线端到端走通 —— 以「旧加载 UI `load.tsx` 使用旧加载接口」为唯一真实适配点,逐节落成台账骨架(A 使用点 → B 新对象证据 → C 旧 / 新加载系统 → D barrel → E legacy → F undetermined → 修改点汇总)</name>
<precondition>Task 0 已闭环:用户在对话中明确回复「可以执行」四个字(未收到则不得开始本任务)</precondition>
<files>.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md</files>
<read_first>
- packages-user/client-modules/src/render/ui/load.tsx(整文件 165 行:`:36` `const loader = client.loader;`、`:63-68` `loadEnd`、`:70-80` `startLoad`(`:71` `initSystemLoadTask()` / `:72` `load()` / `:75` `@ts-expect-error 需要重构` / `:76-79` `for await (const _ of loader.progress)` 与 `getLoadedTasks` / `getLoadedByte`)、`:86-110` `renderTaskList`(`:91-92`)、`:112-145` `renderByteList`(`:118-119,139`)、`:165` `LoadSceneUI`——本任务的 tracer 对象)
- packages-user/data-state/src/loader/types.ts(整文件 72 行:`IMotaDataLoader` 的 `manager` / `start()` / `loaded()` / `addCoreConfig` / `addExtraConfig` / `addCustomTask` / `getConfig`——**新加载系统的目标对象**)
- packages/loader/src/types.ts:80-335(`ILoadManager` 的 `onStartLoad` / `onProgress` / `onLoadEnd` 钩子与 `addTask` / `load()` / `getLoadedByte` / `getTotalByte` / `getLoadedTasks` / `getAddedTasks` / `getTaskRatio` / `getByteRatio`——**新加载系统提供的对象 / 钩子**)
- packages/loader/src/manager.ts:10-112(`LoadManager` 实现)与 packages/loader/src/starter.ts:3-11(`WebLoadStarter`)
- packages-user/data-state/src/loader/loader.ts:18-151(`MotaDataLoader` 实现:`:84-142` `start()` 的 `yield* this.manager.load()` 三段式、`:148-150` `loaded()`)与 packages-user/data-state/src/core.ts:204-208(`this.loadManager = new LoadManager(); this.loader = new MotaDataLoader(...)`)
- packages-user/data-state/src/types.ts:26-43(`ICoreState.loader` / `loadManager`)
- packages-user/client-modules/src/render/index.tsx:11,13,25(`LoadSceneUI` 深导 + `createGameRenderer` 定义 / `sceneController.open(LoadSceneUI, {})`)与 packages-user/client-modules/src/index.ts:1-8(`create()` 现只 `patchAll()` + `createRender()`)
- packages-user/client-modules/src/render/ui/index.ts(10 行,**无** `export * from './load'`)
- .planning/phases/04-render-adaptation/04-TEXTURE-INTERFACE-IMPACT.md(台账版式:元信息块 / 方法 / A–F 表 / 处置)与 04-STRUCTURE-MIGRATION-IMPACT.md(证据纪律:`[证据行]` 标记与 ≥2 锚点规则)
- dev.md(「模块原则」的不转发导出与引入位置;「其他要求」的 CRLF)
</read_first>
<action>
(0a) **起始基线快照(只读前置,先做这一步)**:执行 `git status --porcelain -- packages packages-user src`,把输出**原样逐行**记为「只读起始基线」写入台账 `## 只读起始基线`:先写 bullet `- **只读起始基线(packages / packages-user / src)**:`,其后逐行抄录(每条一行,行首两字符状态码;输出为空则写 `(无)`)。规划日实测为**空**。另记 `git rev-parse HEAD`(规划日 `8b114c7`)与 `git rev-parse --abbrev-ref HEAD`(规划日 `refine/data-client`)当日值;并记录 `.planning/phases/04-render-adaptation/04-CONTEXT.md` 的既有未提交改动仍在。**不得回滚、暂存、提交或修改**任何既有改动。
(1) **建台账骨架(元信息块 + 各小节标题 + 固定表头)**:用 Write 工具创建交付物 `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md`(CRLF)。写入:
- 标题 `# 部分 UI 进一步接口适配影响范围清点(只读)`;
- **元信息块**(固定 6 行):`**日期:**`(当日)/ `**范围:**`(被查 = 渲染端部分 UI(`client-modules/src/render/ui/**` + `render/index.tsx`)对已删全局 `loading` / `hook` 与旧加载系统的使用点;边界非 UI 面只报告;`packages/` 与 `src/` 仅报告(D-33 沿用))/ `**性质:**`(只读清点(D-71 / D-72 第一步),未修改任何生产代码,未引入任何命名变更)/ `**基准提交:**`(`d8fa4b8 refactor: Delete global loading & hook object`;当日 HEAD)/ `**新加载系统基准:**`(`@motajs/loader` + `packages-user/data-state/src/loader/**`)/ `**下一步:**`(第二步适配实施未规划,待用户审阅本文件后另行规划(D-72));
- `## 只读起始基线`(填 (0a) 内容);
- `## 背景`(D-71 / D-72 / D-73 要点 + 「本步只清点、不修改、不规划第二步」);
- `## 方法`(枚举面两侧;A–F 六类判定口径表;证据纪律:事实行 ≥2 个 `file:line` 锚点、证据行带 `[证据行]` 标记 + 核对命令;分列规则;「只登记不判定,未确定者一律进 F 类」);
- `## 基准变更(d8fa4b8)`(小节标题 + 事实清单占位,本任务先填旧加载系统删除与 `load.tsx` 一行 `loading.emit('loaded')` 移除两条事实);
- `## A 全局 loading / hook 使用点(UI 面)`、`## B 目标对象与钩子 API 证据`、`## C 旧加载 UI 清单与新加载系统`、`## D 分层与 barrel(D-69)检查`、`## E legacy 命中(仅报告)`、`## F 未能从阅读确定(未猜测)` 六节,A–E 每节写入固定表头 `| ID | 项目 | 命中处 file:line | 目标锚点 / 证据 file:line | 问题描述 | 影响 | 置信 |` 与 `|---|---|---|---|---|---|---|`;F 节写「条目形如 `- **#04-13-F-NN**:现象 + 为什么读不出来 + 需要用户裁决的点。**只登记,不判定。**」;
- `## 修改点汇总(供后续执行计划消费)`(固定表头 `| 文件 file:line | 现状(旧全局对象 / 旧加载接口) | 应改为监听 / 使用的对象(证据锚点或 undetermined) | 归属 | 置信 |`)与 `## 处置`(只读完成;第二步待用户审阅后另行规划)。
(2) **tracer 行 —— A 类(旧加载 UI 的旧加载接口使用点)**:在 `## A` 表填入以 `#04-13-A-01` 起编号的事实行,逐条覆盖 `load.tsx` 的旧加载接口使用点,每行 `命中处 file:line` + `目标锚点 / 证据 file:line`(基准侧用 `d8fa4b8` 删除事实或对应新对象声明锚点),至少覆盖:`:36`(`client.loader` = `ICoreState.loader`,基准 `packages-user/data-state/src/types.ts:29`)、`:71`(`initSystemLoadTask`)、`:72`(`load`)、`:75-79`(`loader.progress` 异步迭代 + `getLoadedTasks` / `getLoadedByte`)、`:91-92`(`getLoadedTasks` / `getAddedTasks`)、`:118-119`(`getTotalByte` / `getLoadedByte`)、`:139`(`getByteRatio`)。另起一条记录装配链事实 `#04-13-A-02`:`render/index.tsx:11,25` + `createGameRenderer`(`:13`,`git grep` 复验无调用者)——旧加载 UI 当前不可达。
(3) **tracer 行 —— B 类(目标对象证据)**:在 `## B` 表对 A-01 / A-02 给出「应改监听 / 使用的对象」并附现行 `file:line` 证据 —— `IMotaDataLoader`(`packages-user/data-state/src/loader/types.ts:19-72`,`start()` / `loaded()` / `manager`)、`ILoadManager`(`packages/loader/src/types.ts:288-335`,`onStartLoad` / `onProgress` / `onLoadEnd` + `getLoadedByte` / `getTotalByte` / `getLoadedTasks` / `getAddedTasks` / `getTaskRatio` / `getByteRatio`)、`LoadManager`(`packages/loader/src/manager.ts:10-112`)、`MotaDataLoader`(`packages-user/data-state/src/loader/loader.ts:18-151`)。凡无法从阅读确定等价写法者写「undetermined(无法从阅读确定目标对象)」并交叉引用 F 类。
(4) **tracer 行 —— C / D / E / F / 修改点汇总(先只填 tracer 相关)**:
- `## C`:填入旧侧 `packages-user/client-modules/src/render/ui/load.tsx:35,165`(`LoadScene` / `LoadSceneUI`)与 `packages-user/client-modules/src/render/index.tsx:11,13,25`、以及已删的 `packages-user/client-base/src/load/{loader.ts,types.ts,data.ts,index.ts}`(`d8fa4b8` 删除)与旧接口 `IMotaAssetsLoader`(注明「已随 `d8fa4b8` 删除,现行不存在」);新侧 `@motajs/loader`(`packages/loader/src/index.ts:1-5` 导出 + `manager.ts` / `starter.ts` / `task.ts` / `types.ts`)与 `packages-user/data-state/src/loader/index.ts` 导出(`loader.ts` / `types.ts` / `hook.ts` / `jsoncProcessor.ts`)、`MotaDataLoader` / `IMotaDataLoader` / `DefaultDataLoaderHook`、`CoreState.loader` / `loadManager`(`packages-user/data-state/src/core.ts:204-208`)。
- `## D`:填 `packages-user/client-modules/src/render/ui/index.ts`(**无** `./load` 导出)、`packages-user/client-modules/src/render/index.tsx:43-49`(7 条同目录 `export *`)、`packages-user/client-base/src/index.ts`(8 条同目录 `export *`)三条事实行,判定是否违反 D-69、是否存在转发 / 反向依赖候选。
- `## E`:填 `load.tsx` 与 `render/index.tsx` 内 `core.*` / `client` 单例 / `Mota.require` 的只报告事实行(无则写「0 命中」并附 `git grep` 命令与原样结果,标注 `[证据行]`)。
- `## F`:填 `#04-13-F-01`(旧加载 UI 的任务 / 字节进度在新 `ILoadManager` 下的等价数据来源未定)、`#04-13-F-02`(`loader.progress` 异步迭代语义在新 API 下的等价写法未定)等 tracer 相关未确定项。
- `## 修改点汇总`:填 tracer 点对应行(旧加载 UI → 新加载系统对象,证据锚点或 undetermined)。
(5) **CRLF 与收口**:确认台账为 CRLF;本任务只允许创建 / 编辑该台账文件,**不得**改任何生产文件、不得新增计划文件、不得派发会写文件的子代理。
</action>
<reversibility rating="reversible">本任务只创建一个 `.planning/` 下的只读台账文档,无任何生产代码 / 契约 / 命名变更,全部内容可用 git 回退或重跑本计划重建。</reversibility>
<verify>
<automated>node -e "const fs=require('fs');const f='.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md';if(!fs.existsSync(f)){console.error('MISSING '+f);process.exit(1)}const t=fs.readFileSync(f,'utf8');const need=['只读起始基线','背景','方法','基准变更(d8fa4b8)','A 全局 loading / hook 使用点(UI 面)','B 目标对象与钩子 API 证据','C 旧加载 UI 清单与新加载系统','D 分层与 barrel(D-69)检查','E legacy 命中(仅报告)','F 未能从阅读确定(未猜测)','修改点汇总','处置'];const miss=need.filter(k=>t.indexOf(k)<0);if(miss.length>0){console.error('SECTION MISSING :: '+miss.join(','));process.exit(1)}if(t.indexOf('#04-13-A-01')<0){console.error('TRACER ROW A-01 MISSING');process.exit(1)}console.log('OK ledger skeleton + tracer row');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "MISSING" / "SECTION MISSING" / "TRACER ROW A-01 MISSING"(台账文件未创建、要求小节缺失、或 tracer 行 `#04-13-A-01` 未落盘)</fails_when>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8').replace(/\r\n/g,'\n');const rows=t.split('\n').filter(l=>/^\|\s*#04-13-[A-E]-\d+/.test(l));const bad=[];for(const r of rows){const ev=r.indexOf('[证据行]')>=0;const n=(r.match(/[A-Za-z0-9_.\/-]+\.(?:tsx?|md|json):\d+/g)||[]).length;if(!ev&&n<2)bad.push('ROW <2 anchors :: '+r.slice(0,70))}if(rows.length<6)bad.push('TOO FEW ROWS ('+rows.length+')');if(bad.length>0){console.error('EVIDENCE DISCIPLINE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK anchor discipline: '+rows.length+' classed rows');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "EVIDENCE DISCIPLINE FAILED" / "ROW <2 anchors" / "TOO FEW ROWS"(A–E 事实行少于 2 个 `file:line` 锚点,或分类行不足 6 条)</fails_when>
<automated>node -e "const{execSync}=require('child_process');const o=execSync('git status --porcelain -- packages-user/client-modules packages-user/client-base packages-user/data-state packages packages/ src',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');if(o.length>0){console.error('PRODUCTION TREE TOUCHED :: '+o);process.exit(1)}console.log('OK no production changes (read-only)');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "PRODUCTION TREE TOUCHED"(只读清点改动了任何生产文件 —— 违反只读硬约束与 D-33 / D-42 / D-48)</fails_when>
<automated>node -e "const fs=require('fs');const f='.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md';const s=fs.readFileSync(f,'utf8');const lf=(s.match(/\n/g)||[]).length;const crlf=(s.match(/\r\n/g)||[]).length;if(lf!==crlf){console.error('NON-CRLF '+f);process.exit(1)}console.log('OK CRLF ledger');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "NON-CRLF"(台账出现非 CRLF 换行,违反 dev.md「换行使用 CRLF 格式」)</fails_when>
</verify>
<acceptance_criteria>
- `04-UI-ADAPTATION-IMPACT.md` 存在,含标题 + 6 行元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / A–F 六节 / `修改点汇总` / `处置`
- `## 只读起始基线` 逐行原样记录当日起始 porcelain(规划日为空)
- `## A` 至少有 `#04-13-A-01`(`load.tsx` 旧加载接口使用点)与 `#04-13-A-02`(装配链不可达事实),每行 ≥2 个 `file:line` 锚点
- `## B` 对 A-01 / A-02 给出目标对象(`IMotaDataLoader` / `ILoadManager` / `LoadManager` / `MotaDataLoader`)与 `file:line` 证据,或显式 undetermined
- `## C` / `## D` / `## E` / `## F` 均有 tracer 相关事实 / 条目;`## 修改点汇总` 有 tracer 点对应行
- 台账为 CRLF;生产源码零改动(porcelain 为空);未新增计划文件;未派发会写文件的子代理
</acceptance_criteria>
<done>端到端一条线走通:旧加载 UI 这一个真实适配点已在台账每一节留下带 `file:line` 锚点的痕迹(A 使用点 → B 新对象证据 → C 旧 / 新加载系统 → D barrel → E legacy → F undetermined → 修改点汇总);门禁(结构 / 锚点 / 只读 / CRLF)全绿;后续任务只需按同一形态横向铺开其余 UI 面与分类</done>
</task>
<task type="auto">
<name>Task 2:横向铺开 A 类剩余 UI 面与边界非 UI 面(`main.tsx` `statusBarUpdate` / `render/index.tsx` `restart` / `client.ts` / `client-modules/index.ts` / `entry-client/create.ts`)+ B 类目标对象证据铺开</name>
<precondition>Task 0 已闭环(用户已回复「可以执行」)且 Task 1 已交付(台账骨架 + tracer 行 `#04-13-A-01` / A-02 落盘)</precondition>
<files>.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md</files>
<read_first>
- packages-user/client-modules/src/render/ui/main.tsx(整文件 314 行:`:95-138` 状态更新函数 `updateStatus` / `updateDataFallback`、`:140-143` 手工单次调用 + 注释「后续修改后需要删除」、`:145-152` 被注释的 `hook.on('statusBarUpdate', ...)` / `hook.off`;`:28` `import { state } from '@user/data-state'`;`:32` `import { client } from '../../core'`)
- packages-user/client-modules/src/render/index.tsx(整文件 49 行:`:29-41` `createRender` 内 `:35-38` 被注释的 `hook.on('restart', ...)`;`:43-49` 7 条 `export *`)
- packages-user/client-modules/src/client.ts(整文件 149 行:`:88-92` 与 `:124-127` 被注释的 `loading.once('loaded' / 'assetBuilt')`;`:39,60,131` 新加载系统 `WebLoadStarter` / `this.loader.addCoreConfig`;`:137-148` `initMapExtensions`)
- packages-user/client-modules/src/index.ts(16 行:`create()` 现只 `patchAll()` + `createRender()`;`d8fa4b8` 移除了 `loading.once('coreInit', createGameRenderer)`)
- packages-user/entry-client/src/create.ts(整文件 41 行:`:16` / `:31` / `:34-41` 被注释的 `loading.once('registered', createModule)` / `loading.emit('clientRegistered')` / `createModule()` + `hook.emit('renderLoaded')`)
- packages-user/data-base/src/hero/types.ts:277-295,428-443,652-671,883-903(`IHeroLocationHooks` / `IHeroRenderingHooks` / `IEquipmentStateHooks` / `IHeroStateHooks`)与 packages-user/data-common/src/common/mover.ts:166-235(`IObjectMoverHooks`)
- packages-user/data-base/src/map/types.ts:220,599(`IMapLayerHooks` / `IGameMapHooks`)与 packages-user/data-common/src/replay/types.ts:80,342(`IReplaySandboxHooks` / `IReplaySystemHooks`)
- .planning/phases/04-render-adaptation/04-CONTEXT.md:135-139(D-71 / D-72 / D-73 原文)与 :44(D-14:全局 `hook` / `loading` 属 legacy)
</read_first>
<action>
(0a) **复验起始基线**:再次执行 `git status --porcelain -- packages packages-user src` 并与台账 `## 只读起始基线` 逐行比对;不一致则在台账 `## 处置` 记差异,**不得**改用户改动。
(1) **A 类 —— `main.tsx` `statusBarUpdate` 监听点**:在 `## A` 表追加事实行(`#04-13-A-03` 起),记录 `packages-user/client-modules/src/render/ui/main.tsx:140-143`(避免「未使用函数」的手工单次调用 + 注释)与 `:145-152`(被注释的 `hook.on('statusBarUpdate', updateStatus)` / `hook.on('statusBarUpdate', updateDataFallback)` 与 `hook.off`),`命中处 file:line` + 基准锚点 `d8fa4b8`(该提交把这两处改为注释);并登记状态栏读取的字段来源(`:97,101-132,137`)作为 B 类证据的行内依据。
(2) **A 类 —— `render/index.tsx` `restart` 监听点**:追加事实行,记录 `packages-user/client-modules/src/render/index.tsx:35-38`(被注释的 `hook.on('restart', ...)` 与 `sceneController.closeAll()` / `sceneController.open(GameTitleUI, {})`),基准锚点 `d8fa4b8`;并附 `git grep` 事实:`restart` 现仅命中 legacy `core.restart()`(`packages-user/client-modules/src/render/ui/settings.tsx:112`)与 hotkey 实现(`packages-user/client-modules/src/action/hotkey.ts:507`),**无新发射者**——该结论的 F 类归属在 (5) 登记。
(3) **A 类 —— 边界(非 UI,仅报告)面**:在 `## A` 表末尾(或紧随其后的子小节)追加**只报告**条目,逐条带 `file:line`:`packages-user/client-modules/src/client.ts:88-92`(被注释的 `loading.once('loaded', ...)` + `fallbackLoad` / `loading.emit('assetBuilt')`)与 `:124-127`(被注释的 `loading.once('assetBuilt', initMapExtensions)`)、`packages-user/client-modules/src/index.ts:1-8`(`create()` 已不再调用 `createGameRenderer`)、`packages-user/entry-client/src/create.ts:16,31,34-41`(三处 `loading` / `hook` 被注释)。**明写这些不在 D-71「部分 UI」范围内、仅登记供用户裁定是否纳入第二步**(交叉引用 F 类)。
(4) **B 类 —— 目标对象证据铺开**:在 `## B` 表为 `main.tsx` / `render/index.tsx` / 边界面逐条给出「应改监听 / 使用的对象」+ 现行 `file:line` 证据:状态栏 → 可 hook 的数据端对象接口(`packages-user/data-base/src/hero/types.ts:277-295,428-443,652-671,883-903`、`packages-user/data-common/src/common/mover.ts:166-235`、`packages-user/data-base/src/map/types.ts:220,599`、`packages-user/data-common/src/replay/types.ts:80,342`);`restart` / 加载面 → 新加载系统(`packages-user/data-state/src/loader/types.ts:19-72` 等)。**若无法从阅读确定单一目标对象(`statusBarUpdate` 为多对象聚合、`restart` 无新发射者),一律写「undetermined(无法从阅读确定目标对象)」并交叉引用 F 类,不得臆测。**
(5) **F 类 —— 登记未确定项**:在 `## F` 追加 `#04-13-F-03`(`statusBarUpdate` 的精确监听对象集合 —— 状态栏聚合了不可 hook 的 `client.hero.attribute` 只读属性、`client.flags`、`core.status` 等)、`#04-13-F-04`(`restart` 在全局 `hook` 删除后无新发射者,事件来源与新接线方式未定)、`#04-13-F-05`(`client.ts` / `client-modules/index.ts` / `entry-client/create.ts` 是否纳入「部分 UI」适配范围)。逐条写「现象 + 为什么读不出来 + 需要用户裁决的点」,**只登记不判定**。
(6) **同步更新 `## 基准变更(d8fa4b8)` 与 `## 修改点汇总`**:补入 `main.tsx` / `render/index.tsx` / 边界面三条基准变更事实;`## 修改点汇总` 追加对应行(现状 / 应改对象或 undetermined / 归属 / 置信)。
(7) **CRLF 与收口**:只允许编辑该台账文件;**不得**改任何生产文件、不得新增计划文件、不得派发会写文件的子代理。
</action>
<reversibility rating="reversible">本任务只向 `.planning/` 下的只读台账追加事实行,无任何生产代码 / 契约 / 命名变更,可用 git 回退或重跑本计划重建。</reversibility>
<verify>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8').replace(/\r\n/g,'\n');const need=['#04-13-A-03','#04-13-F-03','#04-13-F-04','#04-13-F-05','main.tsx:140-143','render/index.tsx:35-38','client.ts:88-92','entry-client/src/create.ts:16,31,34-41'];const miss=need.filter(k=>t.indexOf(k)<0);if(miss.length>0){console.error('A/B/F EXPANSION MISSING :: '+miss.join(' | '));process.exit(1)}console.log('OK A/B/F expansion');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "A/B/F EXPANSION MISSING"(`main.tsx` / `render/index.tsx` / 边界面 A 行或 F-03..F-05 未落盘)</fails_when>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8').replace(/\r\n/g,'\n');const rows=t.split('\n').filter(l=>/^\|\s*#04-13-[A-E]-\d+/.test(l));const bad=[];for(const r of rows){const ev=r.indexOf('[证据行]')>=0;const n=(r.match(/[A-Za-z0-9_.\/-]+\.(?:tsx?|md|json):\d+/g)||[]).length;if(!ev&&n<2)bad.push('ROW <2 anchors :: '+r.slice(0,70))}const f=t.split('\n').filter(l=>/^- \*\*#04-13-F-\d+/.test(l));if(f.length<5)bad.push('F rows <5 ('+f.length+')');if(bad.length>0){console.error('EVIDENCE DISCIPLINE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK anchor discipline: '+rows.length+' table rows, '+f.length+' F entries');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "EVIDENCE DISCIPLINE FAILED" / "ROW <2 anchors" / "F rows"(A–E 事实行锚点不足,或 F 类条目少于 5 条)</fails_when>
<automated>node -e "const{execSync}=require('child_process');const o=execSync('git status --porcelain -- packages-user/client-modules packages-user/client-base packages-user/data-state packages packages/ src',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');if(o.length>0){console.error('PRODUCTION TREE TOUCHED :: '+o);process.exit(1)}console.log('OK no production changes (read-only)');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "PRODUCTION TREE TOUCHED"(本任务改动了生产文件 —— 违反只读硬约束)</fails_when>
<automated>node -e "const fs=require('fs');const f='.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md';const s=fs.readFileSync(f,'utf8');const lf=(s.match(/\n/g)||[]).length;const crlf=(s.match(/\r\n/g)||[]).length;if(lf!==crlf){console.error('NON-CRLF '+f);process.exit(1)}console.log('OK CRLF ledger');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "NON-CRLF"(台账出现非 CRLF 换行)</fails_when>
</verify>
<acceptance_criteria>
- `## A` 新增 `main.tsx`(`:140-143` / `:145-152`)、`render/index.tsx`(`:35-38`)事实行,以及 `client.ts:88-92,124-127` / `client-modules/src/index.ts` / `entry-client/src/create.ts:16,31,34-41` 的**只报告**边界条目
- `## B` 为上述每处给出目标对象证据(可 hook 的数据端对象接口)或显式 undetermined
- `## F` 含 `#04-13-F-03` / `F-04` / `F-05`,均写「现象 + 读不出原因 + 需用户裁决的点」,无「错配 / 缺失 / 残留 / 待办」措辞
- `## 基准变更(d8fa4b8)` 与 `## 修改点汇总` 已同步;台账为 CRLF;生产源码零改动
</acceptance_criteria>
<done>A / B 类横向铺开完成:`main.tsx` `statusBarUpdate`、`render/index.tsx` `restart` 与三个边界非 UI 面均在案(带 `file:line`),B 类给出目标对象证据或 undetermined,F 类新增 3 条未确定项;门禁(内容 / 锚点 / 只读 / CRLF)全绿</done>
</task>
<task type="auto">
<name>Task 3:铺开 C(旧加载 UI 清单 + 新加载系统入口 / API / 钩子)/ D(barrel 与 D-69)/ E(legacy 只报告)+ `## 修改点汇总` 定稿</name>
<precondition>Task 0 已闭环(用户已回复「可以执行」)且 Task 1 / Task 2 已交付(台账骨架 + tracer 行 + A/B/F 铺开)</precondition>
<files>.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md</files>
<read_first>
- packages/loader/src/index.ts:1-5(导出面)与 packages/loader/src/task.ts(`LoadTask`)与 packages/loader/src/types.ts:194-266(`ILoadTask` / `ILoadTaskInit` / `ILoadTaskHooks`)
- packages-user/data-state/src/loader/index.ts(导出面)与 packages-user/data-state/src/loader/hook.ts:5-24(`DefaultDataLoaderHook`:`onCoreConfigLoaded` 里 `addExtraConfig`)
- packages-user/client-base/src/index.ts(8 条 `export *`)与 packages-user/client-modules/src/index.ts(`export * from './render'` 等)与 packages-user/client-modules/src/render/index.tsx:43-49(7 条 `export *`)
- packages-user/client-modules/src/render/ui/index.ts(10 行,**无** `export * from './load'`)
- packages-user/client-modules/src/render/ui/main.tsx 与 load.tsx / settings.tsx / statusBar.tsx / toolbar.tsx(`core.*` / `Mota.require` / `client` / `state` 命中的只报告对象)与 packages/legacy-ui/src/preset/ui.ts:13,222(`Mota.require('@user/data-base')` 取已删 `hook` / `loading`)
- .planning/phases/04-render-adaptation/04-TEXTURE-INTERFACE-IMPACT.md(A–F 分节与「处置」写法)与 04-STRUCTURE-MIGRATION-IMPACT.md(E 类只报告措辞)
- dev.md(「模块原则」的不转发导出与引入位置;「其他要求」的 CRLF)
</read_first>
<action>
(0a) **复验起始基线**:与 `## 只读起始基线` 逐行比对;不一致在 `## 处置` 记差异,**不得**改用户改动。
(1) **C 类铺开 —— 旧侧「旧加载 UI 清单」**:在 `## C` 表逐条登记(带 `file:line`):`packages-user/client-modules/src/render/ui/load.tsx`(`LoadScene` `:35` / `LoadSceneUI` `:165`)与装配点 `packages-user/client-modules/src/render/index.tsx:11,25`(`createGameRenderer` `:13`);已删除的旧系统 `packages-user/client-base/src/load/{loader.ts,types.ts,data.ts,index.ts}` 与旧接口 `IMotaAssetsLoader`(`initSystemLoadTask` / `addCustomLoadTask` / `load` / `progress`),注明「已随 `d8fa4b8` 删除,现行不存在」;并登记 `packages-user/client-modules/src/render/use.ts` 的 `onLoaded` 已随该提交删除(若当日实测仍存在则按当日改写)。**只登记事实,不给修复方案。**
(2) **C 类铺开 —— 新侧「新加载系统提供物」**:逐条登记(带 `file:line`):`@motajs/loader`(`packages/loader/src/index.ts:1-5`;`LoadManager` `packages/loader/src/manager.ts:10-112`;`WebLoadStarter` `packages/loader/src/starter.ts:3-11`;`ILoadTask` / `ILoadTaskHooks` `packages/loader/src/types.ts:194-266`;`ILoadManager` `:288-335`);`packages-user/data-state/src/loader/{loader.ts,types.ts,hook.ts,index.ts}`(`MotaDataLoader` / `IMotaDataLoader` / `DefaultDataLoaderHook`);`CoreState.loader` / `loadManager`(`packages-user/data-state/src/core.ts:205-208`)、`ICoreState.loader` / `loadManager`(`packages-user/data-state/src/types.ts:26-43`)。**明写这些是新加载 UI 重新适配时必须使用的入口 / API / 钩子**(但本步不写用法)。
(3) **D 类铺开(D-69)**:在 `## D` 表逐条登记 `packages-user/client-modules/src/render/ui/index.ts`(14 行,**没有** `export * from './load'` ⇒ 旧加载 UI 不经 `ui` 桶暴露,由 `render/index.tsx:11` 深导)、`packages-user/client-modules/src/render/index.tsx:43-49`(7 条 `export *`)、`packages-user/client-modules/src/index.ts`(`export * from './render'` / `'./action'` / `'./fallback'` / `'./client'` / `'./core'` / `'./shared'` / `'./types'`)、`packages-user/client-base/src/index.ts`(8 条同目录 `export *`),判定每处是否违反 D-69、是否存在为补齐导出面而转发 / 反向依赖的**候选**;`packages/` 命中(如 `packages/client/src/index.ts`)**只报告**(D-33)。
(4) **E 类铺开(legacy 仅报告)**:标题写「本节仅报告:按 D-49 / D-55 / D-65 不考虑任何 legacy 内容,legacy 相关报错一律不管、不修、不登记为待办」。以 `git grep -n -E "\bcore\.|\bMota\.require\b" -- packages-user/client-modules/src/render/ui` 与 `git grep -n -F "from '../../core'" -- packages-user/client-modules/src/render/ui` 逐文件汇总命中(带 `file:line`),并登记 `packages/legacy-ui/src/preset/ui.ts:13,222`(`Mota.require('@user/data-base')` 取已删 `hook` / `loading`,**`packages/` 只报告**)。**全节只报告,无任何修复 / 待办措辞。**
(5) **F 类收口**:确认 F 类 ≥ 5 条(Task 1 / Task 2 已给 F-01..F-05);如执行日发现新未确定项,按 `#04-13-F-06`+ 追加,逐条「现象 + 读不出原因 + 需用户裁决的点」。
(6) **`## 修改点汇总` 定稿**:以固定列序表逐条汇总**本台账已登记**的全部修改点:`文件 file:line | 现状(旧全局对象 / 旧加载接口)| 应改为监听 / 使用的对象(附 B 类证据锚点,或 undetermined)| 归属(UI / 边界非 UI / 其余)| 置信`。**只汇总已登记事实,不得新增未登记事实、不得给代码写法。**
(7) **`## 处置` 定稿**:写「本文件是部分 UI 进一步接口适配(D-71 / D-72)第一步(只读收集)的交付物;本步未修改任何生产代码、未引入任何命名变更;相对 `## 只读起始基线` 零变化;第二步(适配实施)未规划,待用户审阅本文件后另行规划(D-72);本文件不含适配方案 / import 改写方案 / 新 `*-PLAN.md`;`REND-01` / `REND-02` 保持 Pending」。如当日实测与规划日数值有差异,按 assumptions 的「以当日实测为准」如实写明。
(8) **CRLF 与收口**:只允许编辑该台账文件;**不得**改任何生产文件、不得新增计划文件、不得派发会写文件的子代理。
</action>
<reversibility rating="reversible">本任务只向 `.planning/` 下的只读台账补齐 C / D / E / F 与修改点汇总,无任何生产代码 / 契约 / 命名变更,可用 git 回退或重跑本计划重建。</reversibility>
<verify>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8');const need=['packages/loader/src/manager.ts:10-112','packages/loader/src/types.ts:288-335','packages-user/data-state/src/loader/types.ts:19-72','packages-user/data-state/src/loader/loader.ts:18-151','packages-user/data-state/src/core.ts:205-208','render/ui/index.ts','packages-user/client-base/src/index.ts','legacy-ui/src/preset/ui.ts:13,222','修改点汇总'];const miss=need.filter(k=>t.indexOf(k)<0);if(miss.length>0){console.error('C/D/E SECTION MISSING :: '+miss.join(' | '));process.exit(1)}console.log('OK C/D/E + summary coverage');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "C/D/E SECTION MISSING"(C 类新加载系统锚点、D 类 barrel 锚点、E 类 legacy 锚点或修改点汇总缺失)</fails_when>
<automated>node -e "const{execSync}=require('child_process');const g=execSync('git grep -n -E \"\\\\bcore\\\\.|\\\\bMota\\\\.require\\\\b\" -- packages-user/client-modules/src/render/ui',{encoding:'utf8'}).trim();const t=require('fs').readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8');const n=g.length?g.split(/\r?\n/).length:0;if(!t.includes('E legacy 命中(仅报告)')){console.error('E SECTION MISSING');process.exit(1)}console.log('OK E section present; ui core/Mota hits today = '+n);"</automated>
<fails_when>non-zero exit, 或 stderr 含 "E SECTION MISSING"(E 类小节缺失)</fails_when>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8').replace(/\r\n/g,'\n');const rows=t.split('\n').filter(l=>/^\|\s*#04-13-[A-E]-\d+/.test(l));const bad=[];for(const r of rows){const ev=r.indexOf('[证据行]')>=0;const n=(r.match(/[A-Za-z0-9_.\/-]+\.(?:tsx?|md|json):\d+/g)||[]).length;if(!ev&&n<2)bad.push('ROW <2 anchors :: '+r.slice(0,70))}const f=t.split('\n').filter(l=>/^- \*\*#04-13-F-\d+/.test(l));if(f.length<5)bad.push('F rows <5 ('+f.length+')');if(t.indexOf('应改为监听 / 使用的对象')<0&&t.indexOf('应改为监听 / 使用')<0)bad.push('MODIFICATION SUMMARY HEADER MISSING');if(bad.length>0){console.error('FINAL DISCIPLINE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK final: '+rows.length+' table rows, '+f.length+' F entries, summary present');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "FINAL DISCIPLINE FAILED" / "ROW <2 anchors" / "F rows" / "MODIFICATION SUMMARY HEADER MISSING"(事实行锚点不足 / F 类 < 5 / 修改点汇总表头缺失)</fails_when>
<automated>node -e "const{execSync}=require('child_process');const req=execSync('git status --porcelain -- .planning/REQUIREMENTS.md',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');const prod=execSync('git status --porcelain -- packages-user/client-modules packages-user/client-base packages-user/data-state packages packages/ src',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');const ctx=execSync('git status --porcelain -- .planning/phases/04-render-adaptation/04-CONTEXT.md',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');const bad=[];if(req.length>0)bad.push('REQUIREMENTS.md TOUCHED');if(prod.length>0)bad.push('PRODUCTION TREE TOUCHED :: '+prod);if(ctx.length===0)bad.push('USER CONTEXT EDIT MISSING');if(bad.length>0){console.error('SCOPE GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK scope: read-only, REQUIREMENTS untouched, user CONTEXT edit preserved');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "SCOPE GATE FAILED" / "REQUIREMENTS.md TOUCHED" / "PRODUCTION TREE TOUCHED" / "USER CONTEXT EDIT MISSING"(`REQUIREMENTS.md` 被改 / 生产文件被改 / 用户并发 `04-CONTEXT.md` 改动被回滚 —— 违反 D-33 / D-56 / 只读约束)</fails_when>
<automated>node -e "const fs=require('fs');const f='.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md';const s=fs.readFileSync(f,'utf8');const lf=(s.match(/\n/g)||[]).length;const crlf=(s.match(/\r\n/g)||[]).length;if(lf!==crlf){console.error('NON-CRLF '+f);process.exit(1)}console.log('OK CRLF ledger');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "NON-CRLF"(台账出现非 CRLF 换行)</fails_when>
</verify>
<acceptance_criteria>
- `## C` 完整登记旧加载 UI 清单(`load.tsx` / `render/index.tsx:11,25` / 已删 `client-base/src/load/**` / `IMotaAssetsLoader`)与新加载系统提供物(`packages/loader/src/**` / `data-state/src/loader/**` / `CoreState.loader` / `loadManager`),均带 `file:line`
- `## D` 登记 4 个 barrel 节点并判定 D-69 合规性 / 转发 / 反向依赖候选;`packages/` 命中只报告
- `## E` 标题含「仅报告」,逐条带 `file:line`,无修复 / 待办措辞
- `## F` ≥ 5 条,均为「现象 + 读不出原因 + 需用户裁决的点」
- `## 修改点汇总` 以固定列序表汇总已登记修改点;`## 处置` 明写只读完成 + 第二步待规划 + REND 保持 Pending
- 台账为 CRLF;生产源码零改动;`.planning/REQUIREMENTS.md` 零改动;用户 `04-CONTEXT.md` 未提交改动仍在
</acceptance_criteria>
<done>C / D / E / F 铺开与 `## 修改点汇总` 定稿完成:旧加载 UI 与新加载系统两侧、barrel(D-69)检查、legacy 只报告、未确定项、修改点汇总全部在案(带 `file:line`);门禁(内容 / 锚点 / 范围 / 只读 / CRLF)全绿;台账可供用户审阅与第二步执行计划消费</done>
</task>
<task type="auto">
<name>Task 4:收口 —— 只读基线一致 + 台账结构 / 锚点 / 分类门禁 + 范围与用户改动门禁 + 既有产物保护 + CRLF + 人工复核 + `04-13-SUMMARY.md` + 白名单提交</name>
<precondition>Task 0 已闭环(用户已回复「可以执行」)且 Task 1 / 2 / 3 均已交付(台账骨架 + tracer 行 + A/B/F 铺开 + C/D/E 铺开与修改点汇总定稿)</precondition>
<files>.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md, .planning/phases/04-render-adaptation/04-13-SUMMARY.md</files>
<read_first>
- .planning/phases/04-render-adaptation/04-10-SUMMARY.md 与 04-12-SUMMARY.md(只读增量的 SUMMARY 版式:只读基线 / 台账落点 / 门禁实测 / 人工复核结论 / 无运行时验证声明 / Known Stubs / Next Phase Readiness)
- .planning/phases/04-render-adaptation/04-13-PLAN.md(本计划的 must_haves(truths / artifacts / key_links / assumptions / prohibitions)、台账结构表与逐条门禁)
- .planning/ROADMAP.md(Phase 4 的 `**Plans:**` 行、`**Plan register note (2026-09-24 · 04-12 落地修正):**` 与 `**Wave 11**` 条目——本步登记 `04-13` / `Wave 12` 的样式基准;本计划不在此文件内写其它内容)
- .planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md(本计划的唯一交付物)
- dev.md(「其他要求」的 CRLF)
</read_first>
<action>
(1) **只读基线门禁**:执行 `git status --porcelain -- packages packages-user src`,与台账 `## 只读起始基线` 逐行比对,断言**逐条一致**(不新增、不消失、状态码不变);断言 `.planning/REQUIREMENTS.md` porcelain 为空;断言 `.planning/phases/04-render-adaptation/04-CONTEXT.md` 的既有未提交改动**仍在**(未被回滚 / 提交)。
(2) **台账结构门禁**:断言标题 + 6 行元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / `## A 全局 loading / hook 使用点(UI 面)` / `## B 目标对象与钩子 API 证据` / `## C 旧加载 UI 清单与新加载系统` / `## D 分层与 barrel(D-69)检查` / `## E legacy 命中(仅报告)` / `## F 未能从阅读确定(未猜测)` / `## 修改点汇总(供后续执行计划消费)` / `## 处置` 全部在场;A–E 表为固定列序 `| ID | 项目 | 命中处 file:line | 目标锚点 / 证据 file:line | 问题描述 | 影响 | 置信 |`。
(3) **证据纪律门禁**:A–E 事实行每行 ≥2 个 `file:line` 锚点(带 `[证据行]` 标记的行豁免 ≥2 计数、但须含核对命令与原样结果);`[证据行]` 标记未出现在非证据行;F 类 ≥ 5 条。
(4) **内容门禁**:断言台账含 tracer 与铺开的关键锚点 —— `load.tsx:71,72`、`main.tsx:140-143`(或 `146-151`)、`render/index.tsx:35-38`、新加载系统 `packages-user/data-state/src/loader/types.ts:19-72` 与 `packages/loader/src/types.ts:288-335`、`render/ui/index.ts`、`legacy-ui/src/preset/ui.ts:13,222`、`## 修改点汇总`;且 `## D` 明写 D-69 判定、`## E` 明写「仅报告」、`## F` 明写「未猜测 / 只登记不判定」。
(5) **范围与用户改动门禁**:断言 `git status --porcelain -- packages-user/client-base/src/material packages packages/ src` 为空;本计划改动面之外零漂移(除 `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md`、`04-13-SUMMARY.md`、`04-13-PLAN.md`、`.planning/ROADMAP.md` 外无新条目)。
(6) **既有产物保护门禁**:断言 `.planning/phases/04-render-adaptation/` 下 `04-01`..`04-12` 的 `*-PLAN.md` 与 `*-SUMMARY.md` 的 porcelain 为空;断言目录内**不存在** `04-14+` 或任何新计划文件。
(7) **CRLF 收口**:确认台账 `04-UI-ADAPTATION-IMPACT.md` 与 `04-13-SUMMARY.md` 为 CRLF(与既有台账 / SUMMARY 一致;计划文件 `04-13-PLAN.md` 与既有 `*-PLAN.md` 一样为 LF,不属本门禁范围)。
(8) **人工代码复核(不可自动化,如实记录结论)**:逐条打开当日源码确认 —— 台账每一条 A 类锚点指向真实存在的旧接口调用 / 被注释监听点;B 类目标对象证据的 `file:line` 指向真实声明;C 类旧侧「已删除」结论由当日 `git grep` 复验;D 类 barrel 导出集合与 D-69 判定一致;E 类 legacy 命中与 `git grep` 输出一致;F 类无一条越过「只登记不判定」的边界。发现偏差即回到相应任务修正。把复核结论(通过 / 偏差及修正)写入 SUMMARY。
(9) **写 `04-13-SUMMARY.md`**:按 04-10 / 04-12 的只读增量版式写 —— frontmatter(`phase` / `plan: 13` / `tags` / `requires` / `provides` / `affects` / `actuals` / `key-files`(created / modified / deleted)/ `key-decisions` / `requirements-completed: []` / `duration` / `completed` / `status`)+ 只读起始基线(Task 1 (0a) 的原文)+ Accomplishments(A–F 六类与修改点汇总的落点表)+ Task Commits + 门禁实测结果 + 人工复核结论 + Decisions Made + Deviations(如有)+ Known Stubs(`statusBarUpdate` / `restart` 的 undetermined 项、边界非 UI 面是否纳入、`createGameRenderer` 无调用者等)+ Next Phase Readiness(第二步适配实施待用户审阅后另行规划,D-72)。**如实声明本步为只读收集、无运行时验证(D-68 的延续),`REND-01` / `REND-02` 保持 Pending。**
(10) **白名单提交(单次)**:核对 `git status`,**只**暂存本计划的 `files_modified`(`04-UI-ADAPTATION-IMPACT.md`)与 `04-13-SUMMARY.md`(ROADMAP 的登记若在计划阶段已完成则不在本任务重复提交;若本任务需补登 ROADMAP,则一并只暂存 `.planning/ROADMAP.md`)——绝不暂存 `.planning/phases/04-render-adaptation/04-CONTEXT.md` 或任何其它文件;以 `docs(04-13): 部分 UI 进一步接口适配只读影响台账(D-71/D-72 第一步)` 为提交信息提交。**不得**借提交顺带格式化 / 重排无关文件;**不得** amend 任何既有提交。
(11) **不写其它 `.planning/` 文件**:本任务除 `04-13-SUMMARY.md` 外**不得**写 `.planning/STATE.md` / `WINDOWS.md` / `REQUIREMENTS.md`;ROADMAP 的 `04-13` / `Wave 12` 登记已在计划阶段完成(本任务不重复改 ROADMAP)。
</action>
<reversibility rating="reversible">本任务是收口(门禁 + 文档 + 一次白名单提交),唯一新增生产面为零;提交内容全部是只读台账与 SUMMARY,可用 git revert 整体回退。</reversibility>
<verify>
<automated>node -e "const{execSync}=require('child_process');const base=execSync('git status --porcelain -- packages packages-user src',{encoding:'utf8'}).replace(/\r\n/g,'\n').replace(/\s+$/,'');const ledger=require('fs').readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8');const esc=s=>s.replace(/[.*+?^\${}()|[\]\\]/g,'\\$&');if(base.length>0){const lines=base.split('\n').filter(Boolean);const miss=lines.filter(l=>ledger.indexOf(l.slice(3).trim())<0);if(miss.length>0){console.error('BASELINE DRIFT :: '+miss.join(' ; '));process.exit(1)}if(ledger.indexOf('\u53ea\u8bfb\u8d77\u59cb\u57fa\u7ebf')<0){console.error('BASELINE NOTE MISSING');process.exit(1)}}console.log('OK read-only baseline consistent (today entries = '+(base?base.split('\n').filter(Boolean).length:0)+')');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "BASELINE DRIFT" / "BASELINE NOTE MISSING"(当日起始基线与台账记录不一致 —— 只读基线被破坏)</fails_when>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8');const need=['只读起始基线','背景','方法','基准变更(d8fa4b8)','A 全局 loading / hook 使用点(UI 面)','B 目标对象与钩子 API 证据','C 旧加载 UI 清单与新加载系统','D 分层与 barrel(D-69)检查','E legacy 命中(仅报告)','F 未能从阅读确定(未猜测)','修改点汇总','处置','#04-13-A-01','load.tsx:71','main.tsx:140-143','render/index.tsx:35-38','packages-user/data-state/src/loader/types.ts:19-72','packages/loader/src/types.ts:288-335','render/ui/index.ts','legacy-ui/src/preset/ui.ts:13,222'];const miss=need.filter(k=>t.indexOf(k)<0);if(miss.length>0){console.error('LEDGER CONTENT MISSING :: '+miss.join(' | '));process.exit(1)}console.log('OK ledger structure + tracer + expansion content');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "LEDGER CONTENT MISSING"(台账结构 / tracer / A 铺开 / 新加载系统 / D / E 关键内容缺失)</fails_when>
<automated>node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','utf8').replace(/\r\n/g,'\n');const rows=t.split('\n').filter(l=>/^\|\s*#04-13-[A-E]-\d+/.test(l));const bad=[];for(const r of rows){const ev=r.indexOf('[证据行]')>=0;const n=(r.match(/[A-Za-z0-9_.\/-]+\.(?:tsx?|md|json):\d+/g)||[]).length;if(!ev&&n<2)bad.push('ROW <2 anchors :: '+r.slice(0,70))}const f=t.split('\n').filter(l=>/^- \*\*#04-13-F-\d+/.test(l));if(f.length<5)bad.push('F rows <5 ('+f.length+')');if(bad.length>0){console.error('EVIDENCE DISCIPLINE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK final discipline: '+rows.length+' rows, '+f.length+' F entries');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "EVIDENCE DISCIPLINE FAILED" / "ROW <2 anchors" / "F rows"(事实行锚点不足或 F 类 < 5)</fails_when>
<automated>node -e "const{execSync}=require('child_process');const bad=[];const mat=execSync('git status --porcelain -- packages-user/client-base/src/material',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');if(mat.length>0)bad.push('MATERIAL TOUCHED :: '+mat);const pkg=execSync('git status --porcelain -- packages packages/ src',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');if(pkg.length>0)bad.push('FORBIDDEN PATH TOUCHED :: '+pkg);const req=execSync('git status --porcelain -- .planning/REQUIREMENTS.md',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');if(req.length>0)bad.push('REQUIREMENTS.md TOUCHED');const ctx=execSync('git status --porcelain -- .planning/phases/04-render-adaptation/04-CONTEXT.md',{encoding:'utf8'}).replace(/[ \t\r\n]+$/,'');if(ctx.length===0)bad.push('USER CONTEXT EDIT MISSING');if(bad.length>0){console.error('SCOPE GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK scope: material/packages/src clean; REQUIREMENTS untouched; user CONTEXT preserved');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "SCOPE GATE FAILED" / "MATERIAL TOUCHED" / "FORBIDDEN PATH TOUCHED" / "REQUIREMENTS.md TOUCHED" / "USER CONTEXT EDIT MISSING"(`material/` / `packages/` / `src/` 被改、`REQUIREMENTS.md` 被改、或用户并发 `04-CONTEXT.md` 改动被回滚 —— D-42 / D-48 / D-33 / D-56 边界被破)</fails_when>
<automated>node -e "const{execSync}=require('child_process');const o=execSync('git status --porcelain -- .planning/phases/04-render-adaptation',{encoding:'utf8'}).replace(/\s+$/,'');const rows=o.length?o.split(/\r?\n/):[];const existing=rows.filter(r=>/04-(0[1-9]|1[0-2])-(PLAN|SUMMARY)\.md$/.test(r));const newPlan=rows.filter(r=>/04-(1[4-9]|[2-9][0-9])-/.test(r));const bad=[];if(existing.length>0)bad.push('EXISTING ARTIFACT DIRTY :: '+existing.join(' ; '));if(newPlan.length>0)bad.push('NEW PLAN FILE :: '+newPlan.join(' ; '));if(bad.length>0){console.error('ARTIFACT PROTECTION FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK existing 04-01..04-12 artifacts untouched; no 04-14+ plan');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "ARTIFACT PROTECTION FAILED" / "EXISTING ARTIFACT DIRTY" / "NEW PLAN FILE"(改写 / 覆盖了既有 `04-01`..`04-12` 产物,或产出了 `04-14+` 计划文件)</fails_when>
<automated>node -e "const fs=require('fs');const files=['.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md','.planning/phases/04-render-adaptation/04-13-SUMMARY.md'];const bad=[];for(const f of files){if(!fs.existsSync(f)){bad.push('MISSING '+f);continue}const s=fs.readFileSync(f,'utf8');const lf=(s.match(/\n/g)||[]).length;const crlf=(s.match(/\r\n/g)||[]).length;if(lf!==crlf)bad.push('NON-CRLF '+f)}if(bad.length>0){console.error('CLOSURE FILE GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK CRLF ledger + SUMMARY present');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "CLOSURE FILE GATE FAILED" / "MISSING" / "NON-CRLF"(台账或 SUMMARY 缺失 / 非 CRLF)</fails_when>
<automated>node -e "const fs=require('fs');const f='.planning/phases/04-render-adaptation/04-13-SUMMARY.md';if(!fs.existsSync(f)){console.error('SUMMARY MISSING');process.exit(1)}const t=fs.readFileSync(f,'utf8');const need=['04-13','D-71','D-72','只读','Pending'];const miss=need.filter(k=>t.indexOf(k)<0);if(miss.length>0){console.error('SUMMARY INCOMPLETE :: '+miss.join(','));process.exit(1)}console.log('OK 04-13-SUMMARY.md present and keyed');"</automated>
<fails_when>non-zero exit, 或 stderr 含 "SUMMARY MISSING" / "SUMMARY INCOMPLETE"(`04-13-SUMMARY.md` 未写或缺少关键章节 / 标识)</fails_when>
</verify>
<acceptance_criteria>
- **只读基线门禁**:当日起始 porcelain 与台账 `## 只读起始基线` 逐条一致;`.planning/REQUIREMENTS.md` 零改动;用户 `04-CONTEXT.md` 未提交改动仍在
- **台账结构 / 内容门禁**:12 小节 + 固定列序表 + tracer / A 铺开 / 新加载系统 / D / E 关键锚点全部在场
- **证据纪律门禁**:A–E 事实行每行 ≥2 个 `file:line` 锚点(证据行豁免);F 类 ≥ 5 条
- **范围门禁**:`material/` / `packages/` / `src/` porcelain 为空
- **既有产物保护**:`04-01`..`04-12` 的 `*-PLAN.md` / `*-SUMMARY.md` porcelain 为空;无 `04-14+`
- **CRLF**:台账 / SUMMARY / 本计划均为 CRLF
- `04-13-SUMMARY.md` 已写(含只读起始基线 / A–F 落点 / 门禁实测 / 人工复核结论 / 无运行时验证声明 / 待规划第二步)
- 已按白名单完成单次提交(只含 `files_modified` 条目 + `04-13-SUMMARY.md`,ROADMAP 如需补登则一并);未写其它 `.planning/` 文件;未派发会写文件的子代理
</acceptance_criteria>
<done>收口完成:只读基线一致、台账结构 / 内容 / 锚点门禁全绿、范围与用户改动门禁通过、既有 `04-01`..`04-12` 产物零触碰、台账与 SUMMARY 均 CRLF;`04-13-SUMMARY.md` 落盘;白名单单次提交完成;`REND-01` / `REND-02` 保持 Pending;第二步(适配实施)待用户审阅后另行规划</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| (无新增外部边界) | 本计划是纯只读清点(读源码 + 写一个 `.planning/` 文档),不引入外部输入 / 网络 / 进程边界;不新增依赖、不安装包、不执行 `pnpm i` |
| 仓库工作树 → git 提交 | 用户的并发未提交改动(`.planning/phases/04-render-adaptation/04-CONTEXT.md`,D-71..D-73 的落点)与本次改动共处同一工作树;若暂存面把控不当,会把用户的改动混入本计划提交 |
| 台账内容 → 后续执行计划 | 台账若把「读不出来」写成「错配 / 缺失 / 残留 / 待办」,会误导第二步执行者扩大范围或臆造方案 |
## STRIDE Threat Register
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-04-13-01 | Tampering | 只读硬约束(生产代码零改动) | high | mitigate | Task 1 / 2 / 3 / 4 的 `<verify>` 均含「production tree touched」类断言(`git status --porcelain` 对 `packages-user/client-*` / `packages` / `src` 为空);prohibitions 明列不得改任何生产文件 |
| T-04-13-02 | Tampering | 提交暂存面(`git add`) | medium | mitigate | Task 4 步骤 (10) 明示只暂存 `files_modified` 与 `04-13-SUMMARY.md`(及必要的 ROADMAP 登记);Task 4 的 `<verify>` 断言用户 `04-CONTEXT.md` 未提交改动仍在(未被提交 / 回滚);prohibitions 明列 |
| T-04-13-03 | Tampering | 既有产物(`04-01`..`04-12`)与 `04-CONTEXT.md` | medium | mitigate | Task 4 的「既有产物保护门禁」断言既有 `*-PLAN.md` / `*-SUMMARY.md` porcelain 为空、无 `04-14+`;prohibitions 明禁改写 / 覆盖 / 改号 |
| T-04-13-04 | Spoofing | 台账证据可信度(臆测替代阅读) | medium | mitigate | 证据纪律门禁要求事实行 ≥2 个真实 `file:line` 锚点;F 类「未猜测」边界由人工复核核验;Task 4 步骤 (8) 逐条复核并记录结论 |
| T-04-13-05 | Repudiation | 「无运行时」被用来弱化验证 | low | mitigate | 每条 `<automated>` 必带 `<fails_when>`;D-68 明示禁止 `check:type` / `build` / TS 诊断数类门禁;prohibitions 明列不得伪造绿 |
| T-04-13-SC | Tampering | npm/pip/cargo 安装 | low | accept | 本计划无任何依赖新增 / 变更、不执行 `pnpm i`、不触及任何 `package.json`,故无供应链安装面;`T-04-13-SC` 保留为「本 run 不适用」的显式登记 |
</threat_model>
<verification>
**Static-only(D-68 的延续:不设 `check:type` / `build` / TS 诊断数类门禁)**
- [ ] Task 0:用户明确回复「可以执行」四个字(`blocking-human` 关卡)
- [ ] Task 1 门禁:台账骨架 + 12 小节 + tracer 行 `#04-13-A-01` 落盘;A–E 事实行 ≥2 锚点;生产树零改动;CRLF
- [ ] Task 2 门禁:`main.tsx` / `render/index.tsx` / 边界非 UI 面 A 行 + F-03..F-05 落盘;锚点纪律;生产树零改动;CRLF
- [ ] Task 3 门禁:C 类旧 / 新加载系统锚点 + D 类 barrel 锚点 + E 类 legacy 锚点 + `## 修改点汇总` 表头与内容在场;F 类 ≥ 5;范围门禁(`REQUIREMENTS.md` 零改动 + 用户 `04-CONTEXT.md` 改动仍在);CRLF
- [ ] Task 4 门禁:只读基线一致 + 台账结构 / 内容 / 锚点 + 范围 + 既有产物保护 + CRLF + `04-13-SUMMARY.md` 落盘
- [ ] 人工代码复核结论写入 SUMMARY
- [ ] 单次白名单提交只含本计划条目;`REND-01` / `REND-02` 保持 Pending
</verification>
<success_criteria>
- **只读收集完成**:唯一交付物 `04-UI-ADAPTATION-IMPACT.md` 落盘,A–F 六类 + 修改点汇总齐备,事实行每行 ≥2 个 `file:line` 锚点;生产代码改动为 **0**
- **两类待适配点均清点**:① 已删全局 `loading` / `hook` 的使用点(`load.tsx` 旧加载接口 / `main.tsx` `statusBarUpdate` / `render/index.tsx` `restart`;`client.ts` / `client-modules/index.ts` / `entry-client/create.ts` 只报告);② 旧加载 UI(`LoadScene` / `LoadSceneUI`)与新加载系统提供物(`@motajs/loader` + `data-state/src/loader/**` + `CoreState.loader` / `loadManager`)
- **每处均有目标对象证据或 undetermined**:可确定者给现行源码 `file:line`;不可确定者进 F 类「只登记不判定」
- **D-69 与 legacy 边界遵守**:D 类完成 barrel 检查(只报告,不给补位方案);E 类 legacy 一律只报告、不修、不登记为待办
- **范围零外溢**:`material/` / `packages/` / `src/` / 其它 `package.json` / 测试文件全部零触碰;用户的并发改动被保留且未被提交
- **命名零变更**:不引入任何新公共 / 受保护 / 私有命名;台账只登记,不为任何目标对象 / 文件命名拍板
- **无运行时要求**:全部证明为静态门禁 + 人工复核;`REND-01` / `REND-02` 保持 Pending,`.planning/REQUIREMENTS.md` 零改动
- **第二步不被规划**:不产出 `04-14+` 或任何新 `*-PLAN.md`;`## 处置` 明写第二步待用户审阅后另行规划(D-72)
</success_criteria>
## Artifacts this phase produces
| Artifact | Kind | Purpose |
|---|---|---|
| `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md` | 新增(只读台账) | 部分 UI 进一步接口适配(D-71 / D-72)第一步交付物:元信息块 + 12 小节 + A–F 六类 + 修改点汇总,每个 A 点带 `file:line` 且有 B 类目标对象证据或 undetermined |
| `.planning/phases/04-render-adaptation/04-13-SUMMARY.md` | 新增(文档) | 只读收集记录 + 门禁实测 + 人工复核 + 无运行时验证声明 + 第二步待规划 |
| `.planning/ROADMAP.md`(Wave 12 + register note) | 修改(计划阶段完成) | `04-13` 的增量登记 |
| 未改动(显式保留) | — | `packages-user/client-modules/src/render/ui/**`、`packages-user/client-modules/src/render/index.tsx`、`packages-user/client-modules/src/{client.ts,index.ts}`、`packages-user/entry-client/src/**`、`packages-user/client-base/src/**`、`packages-user/data-state/src/loader/**`、`packages/loader/src/**`、`.planning/REQUIREMENTS.md` |
<output>
Create `.planning/phases/04-render-adaptation/04-13-SUMMARY.md` when done
</output>

View File

@ -44,5 +44,5 @@
"label": "Advance to the next step",
"reason": "Phase 04 of 7 · executing"
},
"updated_at": "2026-09-24T10:35:43.701Z"
"updated_at": "2026-09-30T06:35:14.551Z"
}