diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index fa95485..face9f0 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -181,10 +181,11 @@ Plans:
3. 移动端(窄屏)布局下,同一场景正常显示且可操作
4. 数据端与渲染端保持双端分离——数据端无 DOM,仍可在 Node 环境跑回放验证
-**Plans**: 10 已执行 + 1 已规划待执行(04-11) — 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)已规划待执行**(执行前须 Task 0 汇报关卡等待用户「可以执行」);渲染适配与移动端/桌面端双布局(REND-01/REND-02)整体仍未完成
+**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)整体仍未完成
**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-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:
@@ -229,6 +230,10 @@ Plans:
- [x] 04-11-PLAN.md — 渲染端结构性重构·**第二步·移植实施(代码改动)**(D-58..D-68):把 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/` 下的原件**(MOVE);D-58 新建 `client-base/src/shared/`(摘取被移 `map` 文件所需的 10 个常量,`client-modules/src/shared.ts` 保留)并把被移 `map` 文件的 shared 说明符改指 4 处(`'../shared'` × 3 / `'../../shared'` × 1);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`;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 / 消费者改指 / 反向引用零命中(`@user/client-modules` 于 `client-base`)/ `@ts-expect-error` 落点(10 新增 + 7 既有)/ 39 文件允许差异 / 实现层差异 / 范围与用户改动 / 无 `import type` / CRLF 共 12 道 + 计划文件范围门禁 + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);`REND-01` / `REND-02` 仍 Pending
+**Wave 11** *(blocked on Wave 10 completion)*
+
+- [ ] 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
+
**UI hint**: yes
### Phase 5: Legacy 移植
diff --git a/.planning/STATE.md b/.planning/STATE.md
index e9f1ab0..142de46 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -5,14 +5,14 @@ current_phase: 04
current_phase_name: 渲染适配与双布局
status: executing
stopped_at: Completed 04-11-PLAN.md(渲染端结构性重构·第二步移植实施:components/elements/map + layout 下沉 @user/client-base(39 文件移动 / 42 新路径);client-base 新增 shared + 桶导出 + 5 依赖;实现层改指 @user/client-base;架构耦合 10 处 @ts-expect-error 暂记;按 D-68 不要求可运行;REND-01/REND-02 保持 Pending)
-last_updated: "2026-09-24T09:30:00.000Z"
+last_updated: "2026-09-24T10:35:43.630Z"
last_activity: 2026-09-24
-last_activity_desc: Completed 04-11-PLAN.md(渲染端结构性重构·第二步移植实施)
-state_head: 0b93426
+last_activity_desc: Planned 04-12-PLAN.md(04-11 落地修正:桶导出边界 + 消费者直连 + shared 单文件)
+state_head: 126d8e40201c0bb09ee628a71668cd214b9757de
progress:
total_phases: 7
completed_phases: 1
- total_plans: 82
+ total_plans: 83
completed_plans: 81
milestone_name: milestone
---
@@ -28,10 +28,10 @@ See: .planning/PROJECT.md (updated 2026-09-17)
## Current Position
-Phase: 04 (渲染适配与双布局) — IN PROGRESS
-Plan: 11/11 已执行(04-01..04-11)
-Status: 04-11 完成(结构性重构·第二步移植:通用渲染资产已下沉 client-base);Phase 4 整体仍未完成 — REND-01/REND-02 保持 Pending,其余渲染适配与移动端/桌面端双布局未做
-Last activity: 2026-09-24 — Completed 04-11-PLAN.md(渲染端结构性重构·第二步移植实施)
+Phase: 04 (渲染适配与双布局) — READY TO EXECUTE
+Plan: 11/12 已执行(04-01..04-11);04-12(04-11 落地修正:桶导出边界 + 消费者直连 + shared 单文件)已规划待执行(Wave 11)
+Status: 04-12 已规划并通过 checker(0 blocker / 0 warning / 4 info-advisory);待用户回复「可以执行」后执行;Phase 4 整体仍未完成 — REND-01/REND-02 保持 Pending
+Last activity: 2026-09-24 — Planned 04-12-PLAN.md(04-11 落地修正:桶导出边界)
Progress: [█████░░░░░] 50%
diff --git a/.planning/phases/04-render-adaptation/04-12-PLAN.md b/.planning/phases/04-render-adaptation/04-12-PLAN.md
new file mode 100644
index 0000000..0102ecf
--- /dev/null
+++ b/.planning/phases/04-render-adaptation/04-12-PLAN.md
@@ -0,0 +1,515 @@
+---
+phase: 04-render-adaptation
+plan: 12
+type: execute
+wave: 11
+depends_on:
+ - 04-01
+ - 04-02
+ - 04-03
+ - 04-04
+ - 04-05
+ - 04-06
+ - 04-07
+ - 04-08
+ - 04-09
+ - 04-10
+ - 04-11
+files_modified:
+ # ---- client-base 系统层:shared 目录折成单文件(D-70 第 4 条)----
+ - packages-user/client-base/src/shared.ts
+ # ---- 实现层:桶导出边界修正 + 消费者直连(D-69 / D-70 第 1/2/3 条)----
+ - packages-user/client-modules/src/render/utils/index.ts
+ - packages-user/client-modules/src/render/utils/saves.ts
+ - packages-user/client-modules/src/render/ui/save.tsx
+ - packages-user/client-modules/src/render/ui/title.tsx
+ # ---- 产物 ----
+ - .planning/phases/04-render-adaptation/04-12-SUMMARY.md
+files_deleted:
+ - packages-user/client-base/src/shared/shared.ts
+ - packages-user/client-base/src/shared/index.ts
+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 必须先向用户汇报「要解决的问题(04-11 落地后仍留 6 处违反 D-69 桶导出边界原则的残迹:`render/utils/index.ts` 越界转发 `./layout`、`render/ui/{save,title}.tsx` 与 `render/utils/saves.ts` 仍从 `../utils` / `../components` 取已移入系统层的内容、`client-base/src/shared/` 目录形态与单文件收口目标不符)」「锁定裁定 **D-69(桶导出边界原则,硬约束)** 与 **D-70(依 D-69 对 04-11 落地的 6 条修正范围)**」「大致解决方案(**修正桶导出边界 + 消费者直连 + shared 单文件化**:① 删 `render/utils/index.ts` 的 `./layout` 转发及其标注;② `render/ui/save.tsx` 拆分 `../utils` 导入、`adjustGrid` / `IGridLayoutData` 与 `render/ui/title.tsx` 的 `adjustCover` 改从 `@user/client-base` 引入;③ `render/utils/saves.ts` 的 `getConfirm` / `waitbox` 改从 `@user/client-base` 引入并删其标注;④ `client-base/src/shared/{shared.ts,index.ts}` 折成单文件 `client-base/src/shared.ts` 并删除 `shared/` 目录;⑤ **保留** 8 处架构耦合标注;⑥ 不新增任何转发导出、`render/index.tsx` 维持现状)」,然后必须**停下等待**用户明确回复「可以执行」四个字;收到该回复前不得执行任何任务、不得派发任何执行子代理。无论触发方式(`/gsd-execute-phase`、`/gsd-manager`、`/gsd-autonomous`、子代理/执行器派发)或配置模式(`.planning/config.json` 的 `mode: yolo`、`workflow.auto_advance`)如何,均不得自动放行。"
+ - "**D-69(硬约束):桶不得越界导出,且不得有转发导出**:本计划结束时,**in-scope barrel**(`client-modules/src/render/utils/index.ts`、`client-modules/src/render/index.tsx`、`client-base/src/index.ts`、`client-base/src/layout/index.ts`、`client-base/src/components/index.ts`、`client-base/src/elements/index.ts`、`client-base/src/map/index.ts`、`client-base/src/map/extension/index.ts`)内**每一条 `export * from` 的说明符都以 `./` 开头**(只指向自身文件夹内的文件或子文件夹),**零**越界说明符(`../…`、包名、`@user/client-base` 等);**不新增任何转发导出**;`packages-user/client-modules/src/render/index.tsx` **维持现状、零改动**(D-70 第 6 条:用户已删除越界两行,现合规),且其 7 条 `export *` 全部指向自身文件夹内。"
+ - "**D-70 第 1 条:`render/utils/index.ts` 不再导出 `./layout`**:`packages-user/client-modules/src/render/utils/index.ts` 删去指向 `./layout` 的那条 `export * from` **及其上一行的 `@ts-expect-error`**;该文件**零** `@ts-expect-error` 残留;仍保留 `./saves` 与 `./use` 两条 `export *`(原文不变),且再无任何指向 `./layout` 的说明符。"
+ - "**D-70 第 2 条:实现层消费者直连 `@user/client-base`**:`packages-user/client-modules/src/render/ui/save.tsx` 的原 `../utils` 单一导入被拆成两条——`adjustGrid` / `IGridLayoutData` 从 `@user/client-base` 引入、`getSave` / `SaveData` 仍从 `../utils` 引入;`packages-user/client-modules/src/render/ui/title.tsx` 的 `adjustCover` 从 `@user/client-base` 引入。两文件内均**不得**再出现把 `adjustGrid` / `IGridLayoutData` / `adjustCover` 从 `../utils` 引入的写法。"
+ - "**D-70 第 3 条:`render/utils/saves.ts` 直连且去标注**:`packages-user/client-modules/src/render/utils/saves.ts` 的 `getConfirm` / `waitbox` 改从 `@user/client-base` 引入,**其上一行的 `@ts-expect-error` 一并删除**;该文件**零** `@ts-expect-error` 残留,且不再出现指向 `../components` 的说明符。"
+ - "**D-70 第 4 条:`shared/` 折成单文件**:`packages-user/client-base/src/shared.ts` 为单文件(内容与 `client-base/src/shared/shared.ts` 逐字一致,10 常量 + `//#region 地图` / `//#endregion` + 注释逐字保留);`packages-user/client-base/src/shared/shared.ts` 与 `packages-user/client-base/src/shared/index.ts` **均已删除**,`packages-user/client-base/src/shared/` 目录**不存在**;`client-base/src/index.ts` 的 `export * from './shared'` 与 `map/{element,renderer,vertex}.ts` 的 `'../shared'`、`map/extension/door.ts` 的 `'../../shared'` 说明符**一字未改**且仍解析到 `shared.ts`(由「单文件在场 + 目录不存在 + 说明符原样」三条机器证据联合证明)。"
+ - "**D-70 第 5 条:8 处架构耦合标注逐字保留**:`packages-user/client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}` 内**引用 `render/use.ts` / `render/renderer` 的** `@ts-expect-error` 共 **8** 处(`misc.tsx` 2 处 + `choices/input/scroll/textboxTyper/tip.tsx` 与 `elements/index.ts` 各 1 处)**逐字保留、零改动、零增减**(属 D-59 / D-67,留待用户后续收尾);注意 `textboxTyper.ts` 另有 **1** 处既有 `无法推导` 标注(规划日位于 `:332`)**不在** D-70 第 5 条的 8 处内、但同属「逐字保留」,故这 7 个文件的 `@ts-expect-error` 总数为 **9**;这 7 个文件**不得**出现在本计划的 `files_modified` / `files_deleted` 内,`git status --porcelain` 对它们为零。"
+ - "**无运行时要求 + 范围零外溢 + REND 保持 Pending**:验证一律为**静态**(文件存在 / 内容 / 说明符 / 目录不存在 / porcelain),**不得**出现任何以「`pnpm check:type` 通过」「`pnpm build` 成功」「全仓或范围内 TS 诊断数归零」为条件的门禁或验收项(D-68 的延续);`packages-user/client-base/src/material/**`(D-42 / D-48)、`packages-user/client-base/src/load/**`、`packages/**`、`src/**`、其它 `package.json`、任何测试文件、legacy 面(D-55 / D-65)与用户的并发改动(D-56)**全部零触碰**;`REND-01` / `REND-02` 在本 run 后仍为 **Pending**,`.planning/REQUIREMENTS.md` 零改动。"
+ artifacts:
+ - path: packages-user/client-base/src/shared.ts
+ provides: "D-70 第 4 条的单文件常量面:由 `client-base/src/shared/shared.ts` 逐字折成,10 个常量(`CELL_WIDTH` / `CELL_HEIGHT` / `CELL_SIZE` / `MAP_BLOCK_WIDTH` / `MAP_BLOCK_HEIGHT` / `MAP_WIDTH` / `MAP_HEIGHT` / `DYNAMIC_RESERVE` / `MOVING_TOLERANCE` / `DOOR_ANIMATE_INTERVAL`)与 `@motajs/render` 导入行原文保留;`client-base/src/index.ts` 的 `./shared` 与 `map/*` 的相对说明符无需改动即可解析到它"
+ - path: packages-user/client-modules/src/render/utils/index.ts
+ provides: "D-69 合规的实现层 utils 桶:去掉了指向 `./layout` 的越界转发与其标注,仅剩 `./saves` / `./use` 两条同目录导出"
+ - path: packages-user/client-modules/src/render/ui/save.tsx
+ provides: "D-70 第 2 条的消费者直连样板:`adjustGrid` / `IGridLayoutData` 从 `@user/client-base` 引入,`getSave` / `SaveData` 仍从 `../utils`"
+ - path: packages-user/client-modules/src/render/ui/title.tsx
+ provides: "D-70 第 2 条的消费者直连样板:`adjustCover` 从 `@user/client-base` 引入"
+ - path: packages-user/client-modules/src/render/utils/saves.ts
+ provides: "D-70 第 3 条的消费者直连:`getConfirm` / `waitbox` 从 `@user/client-base` 引入,断链标注已删"
+ key_links:
+ - "`packages-user/client-base/src/index.ts:7`(`export * from './shared'`)↔ `packages-user/client-base/src/shared.ts` —— 目录→单文件折叠后该桶说明符**原文不变**仍解析;由「`shared.ts` 在场 + `shared/` 目录不存在 + 说明符原样」联合证明(D-70 第 4 条)"
+ - "`packages-user/client-base/src/map/{element.ts:5,renderer.ts:53,vertex.ts:25}`(`'../shared'`)与 `packages-user/client-base/src/map/extension/door.ts:9`(`'../../shared'`)↔ `packages-user/client-base/src/shared.ts` —— 4 处相对说明符**一字未改**,折叠后仍指向单文件"
+ - "`packages-user/client-modules/src/render/utils/saves.ts`(`getConfirm` / `waitbox`)↔ `@user/client-base`(`components/choices.tsx:597` 的 `getConfirm`、`components/misc.tsx:570` 的 `waitbox` 经 `client-base/src/index.ts` 的 `./components` 桶出口)—— D-69 的「消费者必须直连、不得经 barrel 转发」落地"
+ - "`packages-user/client-modules/src/render/ui/{save.tsx,title.tsx}` ↔ `@user/client-base`(`layout/layout.ts` 的 `adjustGrid` / `IGridLayoutData` / `adjustCover` 经 `client-base/src/index.ts` 的 `./layout` 桶出口)—— D-70 第 2 条落地;与 `render/utils/index.ts` 去掉 `./layout` 转发互为闭环"
+ - "`packages-user/client-modules/src/render/utils/index.ts`(去 `./layout` 后)↔ `packages-user/client-modules/src/render/index.tsx:47`(`export * from './utils'`)—— 公共面不再经 `render/utils` 透出 `layout` 内容,改由消费者从 `@user/client-base` 取(D-69 的「不转发导出」表述)"
+ - "`packages-user/client-base/src/components/{choices,input,misc,scroll,textboxTyper,tip}.tsx` 与 `elements/index.ts`(8 处 `@ts-expect-error`)↔ `git status --porcelain` 零命中 —— D-70 第 5 条的「逐字保留」证明"
+ assumptions:
+ - "**FLAGGED ASSUMPTION(specless fallback)— REND-01 edge unresolved:** 未提供 REND-01(渲染端适配新数据层接口)的验收边界;本计划**不发明**阈值,只交付「桶导出边界修正 + 消费者直连 + `shared` 单文件化」这一结构性修正切片(D-69 / D-70)。用户须在推进 REND-01 余下部分前补齐其边界判据。"
+ - "**FLAGGED ASSUMPTION(specless fallback)— REND-02 edge unresolved:** 未提供 REND-02(移动端与桌面端双布局)的验收边界;本计划不涉及双布局,也不发明其验收阈值。"
+ - "**`client-base/src/index.ts` 无需改动(本计划的判断):** D-70 第 4 条明示 `export * from './shared'` 说明符不受影响,故该文件**不列入** `files_modified`。若执行日实测发现该说明符需改写(例如解析失败),执行者必须**停下并告知用户**,不得自行改道。"
+ - "**`render/utils/index.ts` 去 `./layout` 会使 `render/utils` 桶少出三个符号(`adjustGrid` / `IGridLayoutData` / `adjustCover`):** 这是 D-69 的**预期结果**(桶不得转发),其两个消费者(`render/ui/save.tsx` / `title.tsx`)由 D-70 第 2 条改从 `@user/client-base` 取。**不得**为「保持导出面」而在任何 barrel 新增转发导出(D-69 明令禁止)。"
+ - "**D-70 第 5 条的 8 处标注与本次改动无交叉:** 这 8 处位于 `client-base/src/{components,elements}`,全部指向留在实现层的 `render/renderer` 与 `render/use.ts`;本计划不触碰这些文件,也不触碰其被指向的模块。若执行日发现其中任一文件被用户在并发编辑(porcelain 非空),执行者须在 SUMMARY 如实登记该并发改动,**不得**回滚 / 暂存 / 提交它。"
+ - "**执行日行号可能漂移:** 本计划引用的 `file:line` 是 2026-09-24 的规划日锚点;用户会并发改其它文件(D-56)。执行时一律以**当日实测**定位(按符号名 / 说明符文本检索),不得按规划日行号硬写;任一与规划日不同即在 SUMMARY 记录差异。"
+ - "**无运行时验证可得(D-68 的延续):** 本步不要求「保证能运行」;渲染端无运行时测试设施(04-07 / 04-08 / 04-09 已如实声明),本计划**不新增任何测试**;承载体为静态门禁 + 人工复核。**不得**以 `pnpm check:type` / `pnpm build` / TS 诊断数之类的条件冒充门禁。"
+ - "**规划日并发基线(D-56 实测,2026-09-24):** `git status --porcelain -- packages packages-user src` 有 **1** 条——` M packages-user/client-modules/src/render/index.tsx`(用户的并发未提交改动,即 D-70 第 6 条所述「用户已删除越界两行」);另有 ` M .planning/phases/04-render-adaptation/04-CONTEXT.md`(不在该集合内)。Task 1 步骤 (0a) 须逐行记录当日实测,Task 4 断言既有条目不消失、不新增计划外条目。**不得回滚 / 暂存 / 提交 / 修改**用户任何未提交改动。"
+ prohibitions:
+ - "不得在用户明确回复「可以执行」四个字之前执行本计划的任何任务、或派发任何执行子代理(AGENTS.md 的第一个 block 点约束;不因触发方式或 `yolo` / `auto_advance` 模式而放宽)。"
+ - "不得触碰本文 `files_modified` / `files_deleted` 之外的任何生产文件;尤其**不得**改动 `packages-user/client-modules/src/render/index.tsx`(D-70 第 6 条:维持现状)、`packages-user/client-base/src/index.ts`(`./shared` 说明符本就不需改)、`packages-user/client-base/src/{components,elements,map,layout}/**`(含 D-70 第 5 条的 8 处标注)、`packages-user/client-modules/src/render/utils/use.ts`、`render/{renderer.ts,use.ts}`。"
+ - "不得修改 `packages-user/client-base/src/material/**`(D-42 / D-48)、`packages-user/client-base/src/load/**`、`packages/**`、`src/**`、`tsconfig.json`;不得改动任何 `package.json`;不得新增 / 删除依赖;**不得执行 `pnpm i`**(本计划无依赖变更)。"
+ - "不得新增任何转发导出:不得在任何 barrel 出现指向自身文件夹之外的 `export * from`(含把 `@user/client-base` 或 `../…` 写进 `client-modules` 的 barrel);不得为补齐导出面而在 `render/utils/index.ts` 重新引入指向 `./layout` 的转发;不得把 `render/index.tsx` 的现有导出行改成越界形态(D-69)。"
+ - "不得修复任何 legacy 报错(D-55 / D-65):`core.*` / 全局 `loading` / `hook` / `Mota.require` 命中一律不管、不修、不登记为待办;不得因 `packages/legacy-ui` 的插件面顾虑而增加任何兼容代码(D-49 作废该类约束)。"
+ - "不得新增、删除或改写任何 `@ts-expect-error`:唯一允许删除的 2 处是 D-70 第 1/3 条点名的 `render/utils/index.ts` 与 `render/utils/saves.ts`(各 1 处,连同其上方被删的转发 / 断链行一并删除);D-70 第 5 条的 8 处架构耦合标注**逐字保留**;不得写无原因的裸 `// @ts-expect-error`(`dev.md`)。"
+ - "不得改写 / 删除任何既有 jsDoc 与注释(AGENTS.md);`client-base/src/shared.ts` 的注释文本必须与 `shared/shared.ts` 逐字一致;`render/utils/index.ts` 的 `./saves` / `./use` 两行原文、`render/ui/{save,title}.tsx` 与 `render/utils/saves.ts` 中与被改导入无关的行一律不动;不得新增 / 改名任何公共、受保护、私有成员、方法、字段、文件或目录(本步不引入任何新命名)。"
+ - "不得使用 `import type`(`dev.md`);不得新增、删除或修改任何测试文件;不得新增计划文件(本步是 04-11 的落地修正,不再分叉);除本计划的 `files_modified` / `files_deleted`、`04-12-SUMMARY.md` 与 `.planning/ROADMAP.md` 的登记外不得写任何其它 `.planning/` 文件(含 `.planning/STATE.md` / `WINDOWS.md` / `REQUIREMENTS.md`)。"
+ - "不得把任何门禁建立在「全仓 / 范围内 TS 诊断数」「`pnpm check:type`」「`pnpm build`」之上,也不得因这类检查失败而阻塞交付(D-68)。"
+ - "不得改写 / 覆盖 / 改号 `04-01`..`04-11` 的既有 `*-PLAN.md` 与 `*-SUMMARY.md`;不得改写既有 `04-CONTEXT.md`;不得产出 `04-13+` 或任何新计划文件。"
+ - "不得触碰、暂存、提交用户的并发改动(D-56):尤其不得提交 `packages-user/client-modules/src/render/index.tsx` 与 `.planning/phases/04-render-adaptation/04-CONTEXT.md` 的既有未提交改动;提交前必须以 `git status` 逐条核对暂存面,且只暂存本计划 `files_modified` / `files_deleted` 的条目。"
+---
+
+
+Phase 4 第十二个增量(用户裁定 2026-09-24 · **D-69 / D-70**)—— **04-11 落地修正:桶导出边界 + 消费者直连 + `shared` 单文件**。
+
+**要解决的问题:**
+
+04-11 完成了通用渲染资产(39 文件)下沉 `@user/client-base`,但落地形态仍留 6 处违反 **D-69 桶导出边界原则** 的残迹:
+
+1. `packages-user/client-modules/src/render/utils/index.ts` 仍以一条 `export * from` 越界转发已移入系统层的 `layout`(配 `@ts-expect-error` 暂记)——**barrel 不得转发自身文件夹之外的任何内容**。
+2. `packages-user/client-modules/src/render/ui/save.tsx` 仍从 `../utils` 取 `adjustGrid` / `IGridLayoutData`;`render/ui/title.tsx` 仍从 `../utils` 取 `adjustCover`——**消费者必须直连 `@user/client-base`**。
+3. `packages-user/client-modules/src/render/utils/saves.ts` 仍从 `../components` 取 `getConfirm` / `waitbox`(配 `@ts-expect-error` 暂记)——同上,须直连并去标注。
+4. `packages-user/client-base/src/shared/` 为 `shared/shared.ts` + `shared/index.ts` 两文件形态,与「单文件」的收口目标不符。
+5. (保留项)`client-base/src/{components,elements}` 内 8 处架构耦合 `@ts-expect-error` 属 D-59 / D-67,**逐字保留**,由用户后续收尾。
+6. (保留项)**不得**新增任何转发导出;`client-modules/src/render/index.tsx` 维持现状(用户已删除越界两行,现合规)。
+
+**锁定裁定(D-69 / D-70):**
+
+- **D-69(硬约束):** 一个 barrel(`index.ts` / `index.tsx`)**只允许 `export * from './<同目录下的文件或子文件夹>'`**,不得导出本文件夹之外的任何内容;反过来,任何需要被移内容的**消费端必须直接 `import ... from '@user/client-base'`**,不得经任何 barrel 转发导出。
+- **D-70:** 依 D-69 对 04-11 落地作 6 条修正(即上列 1..6)。
+
+**大致解决方案(本计划 = 04-12,单一计划文件):**
+
+| # | 面 | 处置 |
+|---|---|---|
+| F1 | `render/utils/index.ts` | 删除指向 `./layout` 的 `export * from` **及其上一行 `@ts-expect-error`**(D-70 第 1 条);保留 `./saves` / `./use` |
+| F2 | `render/ui/save.tsx` | 拆分 `../utils` 导入:`adjustGrid` / `IGridLayoutData` 改自 `@user/client-base`,`getSave` / `SaveData` 仍自 `../utils`(D-70 第 2 条) |
+| F2' | `render/ui/title.tsx` | `adjustCover` 改自 `@user/client-base`(D-70 第 2 条) |
+| F3 | `render/utils/saves.ts` | `getConfirm` / `waitbox` 改自 `@user/client-base`;**删除**其 `@ts-expect-error`(D-70 第 3 条) |
+| F4 | `client-base/src/shared/` | 折成单文件 `client-base/src/shared.ts`(逐字搬内容),删除 `shared/shared.ts` 与 `shared/index.ts` + 空目录(D-70 第 4 条) |
+| F5 | 8 处架构耦合标注 | **逐字保留、零改动**(D-70 第 5 条) |
+| F6 | 转发导出 | **零新增**;`render/index.tsx` 维持现状(D-70 第 6 条) |
+
+**范围与硬边界:** 改动面 = `files_modified` 的 5 个生产文件 + `files_deleted` 的 2 个文件;**零触碰** = `client-base/src/index.ts`、`client-base/src/{components,elements,map,layout}/**`、`client-modules/src/render/index.tsx`、`render/utils/use.ts`、`render/{renderer.ts,use.ts}`、`client-base/src/material/**`(D-42 / D-48)、`client-base/src/load/**`、`packages/**`、`src/**`、其它 `package.json`、任何测试文件、legacy 面(D-55 / D-65)、用户并发改动(D-56)。
+
+**任务切分(Task 0 汇报关卡 + 4 个工作任务):** 本增量委托指定 `04-12` 为唯一新计划,故落在**单一计划文件**内。Task 1(tracer)= `shared/`→`shared.ts` 折叠切片(端到端走通「目录→单文件后 barrel 说明符与 `map/*` 相对说明符仍解析」这一层);Task 2 = F1(桶去转发)+ F3(`saves.ts` 直连去标注)——D-69 在实现层 utils 桶上的两半;Task 3 = F2 / F2'(`render/ui` 两消费者直连);Task 4 = 收口(桶边界门禁 + 8 处标注逐字保留 + 范围门禁 + 人工复核 + SUMMARY + 白名单提交)。每个任务均落在单代理上下文预算内。
+
+## Source Audit(多源覆盖审计)
+
+| SOURCE | ID | Feature/Requirement | Plan | Status | Notes |
+|--------|----|---------------------|------|--------|-------|
+| GOAL | — | Phase 4:「渲染端通过新数据层接口驱动,并同时支持移动端与桌面端布局」 | 04-12 | COVERED(增量·结构修正子切片) | 本 run 只修正 04-11 落地形态(桶边界 / 消费者直连 / `shared` 单文件);接口适配与双布局属后续增量(见 assumptions 的两条 FLAGGED ASSUMPTION) |
+| REQ | REND-01 | 渲染端适配新数据层接口 | 04-12 | COVERED(子切片·结构前置;需求保持 Pending) | 分层/边界纠正是 REND-01 后续实现的**前置结构条件**(D-51 / D-69);本 run 不移交任何接口行为;验收边界未提供 → FLAGGED ASSUMPTION |
+| REQ | REND-02 | 渲染端同时支持移动端与桌面端布局 | 04-12 | COVERED(不涉及) | 本 run 范围不含双布局;验收边界未提供 → FLAGGED ASSUMPTION |
+| RESEARCH | — | (本阶段无 `04-RESEARCH.md`) | — | N/A | Phase 4 未产出 RESEARCH.md;等价输入为 `04-STRUCTURE-MIGRATION-IMPACT.md`(04-10 只读台账,A9/B9/C8/D10/E6/F10)与 `04-11-SUMMARY.md`(12 道门禁 + 交接余留) |
+| CONTEXT | D-69 | 桶导出边界原则(硬约束):barrel 只允许 `export * from './<同目录项>'`;消费者必须直连 `@user/client-base`,不得经 barrel 转发 | 04-12 | COVERED | Task 1/2/3 逐条落地;Task 4 的「桶边界门禁」对 8 个 in-scope barrel 逐条断言 `./` 前缀 |
+| CONTEXT | D-70.1 | `render/utils/index.ts` 删除 `./layout` 转发及其 `@ts-expect-error` | 04-12 | COVERED | Task 2 步骤 (1);门禁断言该文件零 `@ts-expect-error` 且无 `./layout` 说明符 |
+| CONTEXT | D-70.2 | `render/ui/save.tsx` 拆分 `../utils`(`adjustGrid` / `IGridLayoutData` → `@user/client-base`);`render/ui/title.tsx` 的 `adjustCover` → `@user/client-base` | 04-12 | COVERED | Task 3 步骤 (1) / (2);门禁断言两文件的 `@user/client-base` 说明符与 `../utils` 说明符形态 |
+| CONTEXT | D-70.3 | `render/utils/saves.ts` 的 `getConfirm` / `waitbox` → `@user/client-base`,删除其 `@ts-expect-error` | 04-12 | COVERED | Task 2 步骤 (2);门禁断言该文件零 `@ts-expect-error` 且无 `../components` 说明符 |
+| CONTEXT | D-70.4 | `client-base/src/shared/{shared.ts,index.ts}` → `client-base/src/shared.ts`(单文件),删除 `shared/` 目录;`index.ts` 的 `./shared` 与 `map/*` 的 `../shared` 不受影响 | 04-12 | COVERED | Task 1(tracer)步骤 (1)..(3);门禁断言 `shared.ts` 在场 + `shared/` 目录不存在 + 说明符原样 |
+| CONTEXT | D-70.5 | **保留** 8 处架构耦合 `@ts-expect-error` | 04-12 | COVERED(保留项) | 无任务改动这 7 个文件;Task 4 门禁断言 8 处逐字在场 + porcelain 零命中 |
+| CONTEXT | D-70.6 | **不得**新增转发导出;`render/index.tsx` 维持现状 | 04-12 | COVERED(排除) | Task 4 门禁把 `render/index.tsx` 纳入 in-scope barrel 集合并断言其 `export *` 全为 `./` 前缀;prohibitions 明列不得触碰 |
+| CONTEXT | D-33 | 范围外一律不改;不追求解决全部类型错误 | 04-12 | COVERED(边界) | `packages/` 与 `src/` 零改动;无任何「诊断归零」验收项 |
+| CONTEXT | D-42 / D-48 | `client-base/src/material/` 归用户、AI 不得改 | 04-12 | COVERED(禁用路径) | 范围门禁断言 `material/` porcelain 为空;prohibitions 明列 |
+| CONTEXT | D-49 | 不考虑 legacy 兼容(因 legacy 插件面而生的约束作废) | 04-12 | COVERED(排除) | 无兼容性任务;外部包零改动 |
+| CONTEXT | D-51 / D-53 | 分层纠正:通用渲染资产应属 `client-base`;目标布局不新建 `render/` | 04-12 | COVERED(延续) | 本 run 不移动文件,只修正 04-11 的落地形态以完全满足 D-51 的分层意图与 D-69 |
+| CONTEXT | D-55 / D-65 | 不考虑任何 legacy:legacy 报错一律不管、不修、不登记为待办 | 04-12 | COVERED(排除) | 无任何 legacy 任务 / 门禁 / 待办;prohibitions 明列 |
+| CONTEXT | D-56 | 用户会同步进行其它修改;不得触碰、不得提交用户并发改动 | 04-12 | COVERED | Task 1 步骤 (0a) 逐行记录当日基线(规划日实测 1 条:` M client-modules/src/render/index.tsx`);Task 4 断言既有条目逐条一致且仅新增计划内条目 |
+| CONTEXT | D-59 / D-67 / D-68 | 架构耦合以带原因 `@ts-expect-error` 暂记;本步不要求可运行 / 不要求零类型错误 | 04-12 | COVERED(延续 + 排除) | D-70.5 保留 8 处标注;全部门禁为静态;prohibitions 禁「TS 诊断数 / `check:type` / `build`」类门禁 |
+| CONTEXT | Deferred Ideas | 阶段 4 后续步骤(适配实施、双布局);`packages` 全部、`entry-client`、`legacy-plugin-*`、`data-fallback` | — | DEFERRED | 未写入任何任务;仅作为「零改动」的断言对象 |
+| LEDGER | `#04-10-B-01` / `#04-10-B-06` / `#04-10-C-01` / `#04-10-C-06` | `render/utils/index.ts:1` 是 `layout.ts` 的唯一外部入口,移出即断链;`render/ui/{save,title}.tsx` 经 `../utils` 间接消费 | 04-12 | COVERED | Task 2 + Task 3 逐条修正;门禁按说明符逐一断言新形态 |
+| LEDGER | `#04-10-B-05` | `render/utils/saves.ts:2`(`getConfirm` / `waitbox`,`../components`)——「第二步必改点」 | 04-12 | COVERED | Task 2 步骤 (2) 直连 `@user/client-base` 并去标注 |
+| LEDGER | `#04-10-D-01` | `layout.ts` 只依赖 `@motajs/render` ⇒ 不引入新依赖缺口;`render/utils/index.ts` 若反向 import 会形成合法方向 `client-modules → client-base` | 04-12 | COVERED | D-69 明确改由**消费者直连**(合法方向),不在 barrel 反向 import;本 run 无依赖变更 |
+
+## 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 只读汇报并等待用户确认(约 4k,不写文件);Task 1(tracer)起始只读基线 + `shared/`→`shared.ts` 折叠 + 门禁(约 12k);Task 2 `render/utils/index.ts` 去转发 + `saves.ts` 直连去标注 + 门禁(约 12k);Task 3 `render/ui/{save,title}.tsx` 直连 + 门禁(约 10k);Task 4 桶边界门禁 + 8 处标注逐字核对 + 范围门禁 + 人工复核 + `04-12-SUMMARY.md` + 提交(约 17k);固定开销约 5k;合计约 60k。**本计划刻意不做多计划拆分**:委托明确要求只产出 `04-12` 一份计划,且 6 条修正高度相关(同一桶边界主题),故以任务切分替代计划切分。
+
+
+
+@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
+@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
+
+
+
+@.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-STRUCTURE-MIGRATION-IMPACT.md
+@.planning/phases/04-render-adaptation/04-11-PLAN.md
+@.planning/phases/04-render-adaptation/04-11-SUMMARY.md
+@.planning/phases/04-render-adaptation/04-PATTERNS.md
+@AGENTS.md
+@dev.md
+
+
+
+
+
+ Task 0: 预执行汇报关卡 —— 汇报「04-11 落地修正(桶导出边界 + 消费者直连 + shared 单文件)」的问题、D-69 / D-70 逐条裁定、6 条修正的源→目标映射、范围与硬边界、验证方式,等待用户回复「可以执行」
+ 用户对 04-11 落地修正的裁定 D-69 / D-70 已写入 `.planning/phases/04-render-adaptation/04-CONTEXT.md`(以文件内实际存在 D-69 与 D-70 为准);当日工作树上 04-11 的落地产物在场(`packages-user/client-base/src/shared/shared.ts` 与 `shared/index.ts` 均为文件;`packages-user/client-modules/src/render/utils/index.ts` 含一条指向 `./layout` 的 `export * from` 且其上一行为 `@ts-expect-error`;`packages-user/client-modules/src/render/utils/saves.ts` 的 `getConfirm` / `waitbox` 仍自 `../components` 引入且上一行为 `@ts-expect-error`;`packages-user/client-modules/src/render/ui/save.tsx` 的 `../utils` 导入含 `adjustGrid` / `IGridLayoutData`;`render/ui/title.tsx` 的 `adjustCover` 仍自 `../utils` 引入)
+ (只读汇报,不修改任何文件)
+
+ - AGENTS.md(「任何计划的执行,其第一个 block 点必须是向我汇报计划内容并等待我确认」;只有明确回复「可以执行」四个字之后才允许开始执行;「任何公共、受保护、私有方法、字段等内容的命名必须先向我反馈」;「不得擅自修改所有 jsDoc 注释,不得擅自修改任何已有注释」;「除非我明确要求,否则任何修改必须经由 GSD 标准流程」)
+ - .planning/phases/04-render-adaptation/04-CONTEXT.md(**:122-131 的 D-69 与 D-70 逐条裁定原文**;D-33 范围;D-42 / D-48 `material/` 禁用;D-55 / D-65 legacy 不管;D-56 用户并发改动;D-59 / D-67 / D-68)
+ - .planning/phases/04-render-adaptation/04-11-SUMMARY.md(04-11 的落点表 / 12 道门禁摘要 / 「Known Stubs」的 4 条范围外余留(含 D-60 断链仅标注),本计划的输入)
+ - .planning/phases/04-render-adaptation/04-11-PLAN.md(R9 的 `render/utils/{index,saves}.ts` 标注口径、D-63 的消费者改指口径,本计划的修正对象)
+ - .planning/phases/04-render-adaptation/04-STRUCTURE-MIGRATION-IMPACT.md(台账 `#04-10-B-01` / `#04-10-B-05` / `#04-10-B-06` / `#04-10-C-01` / `#04-10-C-06` / `#04-10-D-01`:断链点与必改点的原始清点)
+ - .planning/phases/04-render-adaptation/04-12-PLAN.md(本计划全文:objective 的 F1..F6 表、tasks、must_haves、禁令、门禁)
+ - .planning/phases/04-render-adaptation/04-11-PLAN.md:297-388(上一增量 Task 0 汇报关卡的结构与汇报口径,本关卡对齐版式)
+ - dev.md(「项目结构」单向依赖 `src → packages-user → packages`;「双端分离」`@user/client-base` 系统层 / `@user/client-modules` 实现层;「模块原则」的**不转发导出**与引入位置;「类型规范」的 `@ts-expect-error` 须说明原因;「其他要求」的 CRLF)
+
+
+ **停下并向用户汇报,等待明确回复后才继续;汇报本身只读,不写任何文件、不改任何生产代码、不派发子代理。**
+
+ ① **要解决的问题(04-11 落地形态仍违反 D-69)**:04-11 已把 39 个通用渲染文件下沉 `@user/client-base`,但落地形态留下 6 处与 **D-69「桶导出边界原则」** 冲突的残迹,需按 **D-70** 逐条修正。逐条:
+ - **F1**:`packages-user/client-modules/src/render/utils/index.ts` 仍以一条 `export * from` 越界转发已移入系统层的 `layout`(配 `@ts-expect-error` 暂记)——barrel 不得转发自身文件夹之外的任何内容。
+ - **F2**:`render/ui/save.tsx` 仍从 `../utils` 取 `adjustGrid` / `IGridLayoutData`;`render/ui/title.tsx` 仍从 `../utils` 取 `adjustCover`——消费者必须直连 `@user/client-base`。
+ - **F3**:`render/utils/saves.ts` 仍从 `../components` 取 `getConfirm` / `waitbox`(配 `@ts-expect-error` 暂记)——同上,须直连并去标注。
+ - **F4**:`client-base/src/shared/` 为 `shared/shared.ts` + `shared/index.ts` 两文件形态,与单文件收口目标不符。
+ - **F5(保留项)**:`client-base/src/{components,elements}` 内 8 处架构耦合 `@ts-expect-error` 属 D-59 / D-67,**逐字保留**,由用户后续收尾。
+ - **F6(保留项)**:**不得**新增任何转发导出;`client-modules/src/render/index.tsx` 维持现状(用户已删除越界两行,现合规)。
+
+ ② **锁定裁定(须逐条汇报原文要点)**:
+ - **D-69(桶导出边界原则,硬约束)**:一个 barrel(`index.ts` / `index.tsx`)**只允许 `export * from './<同目录下的文件或子文件夹>'`**;**不得导出本文件夹之外的任何内容**(同包上层、其它文件夹、其它包、`@user/client-base` 一律禁止)。反过来:任何需要被移内容的**消费端必须直接 `import ... from '@user/client-base'`**,**不得经任何 barrel 转发导出**。本原则在此显式确立,作为后续所有结构改动的约束。
+ - **D-70(依 D-69 对 04-11 落地的修正范围)** 共 6 条,即上列 F1..F6(第 5 条为「保留」、第 6 条为「不得新增转发」)。
+ - 旁注(仅报告、不修改):`packages/client/src/index.ts:1` 的 `export * from '@motajs/client-base'` 亦违反 D-69,但在 `packages/`(D-33 只报告)。
+
+ ③ **源 → 目标映射(须原样呈报)**:
+
+ | # | 文件 | 现状 | 目标 |
+ |---|---|---|---|
+ | F1 | `client-modules/src/render/utils/index.ts` | `@ts-expect-error` + 指向 `./layout` 的 `export *` + `./saves` / `./use` | 去掉指向 `./layout` 的那条 `export *` 及其 `@ts-expect-error`;保留 `./saves` / `./use` |
+ | F2 | `client-modules/src/render/ui/save.tsx` | 一条 `../utils` 导入含 `getSave` / `SaveData` / `adjustGrid` / `IGridLayoutData` | 拆两条:`adjustGrid` / `IGridLayoutData` 自 `@user/client-base`;`getSave` / `SaveData` 自 `../utils` |
+ | F2' | `client-modules/src/render/ui/title.tsx` | `adjustCover` 自 `../utils` | `adjustCover` 自 `@user/client-base` |
+ | F3 | `client-modules/src/render/utils/saves.ts` | `@ts-expect-error` + `getConfirm` / `waitbox` 自 `../components` | `getConfirm` / `waitbox` 自 `@user/client-base`;删除该 `@ts-expect-error` |
+ | F4 | `client-base/src/shared/{shared.ts,index.ts}` | 两文件 | 折成单文件 `client-base/src/shared.ts`(内容逐字搬),删除两文件 + 空目录 |
+ | F5 | 8 处架构耦合标注 | 在场 | **逐字保留、零改动** |
+ | F6 | 全部 barrel | `render/index.tsx` 已合规 | **零新增转发导出**;`render/index.tsx` 维持现状 |
+
+ ④ **范围与硬边界(须原样呈报)**:改动面 = `files_modified` 的 5 个生产文件(`client-base/src/shared.ts`、`render/utils/index.ts`、`render/utils/saves.ts`、`render/ui/save.tsx`、`render/ui/title.tsx`)+ `files_deleted` 的 2 个文件(`client-base/src/shared/shared.ts`、`client-base/src/shared/index.ts`)。**零触碰** —— `client-base/src/index.ts`(`./shared` 说明符本就不需改)、`client-base/src/{components,elements,map,layout}/**`(含 8 处标注)、`client-modules/src/render/index.tsx`、`render/utils/use.ts`、`render/{renderer.ts,use.ts}`、`client-base/src/material/**`(D-42 / D-48)、`client-base/src/load/**`、`packages/**`、`src/**`、其它 `package.json`、任何测试文件、legacy 面(D-55 / D-65)、用户并发改动(D-56)。**无依赖变更、不执行 `pnpm i`。** **命名**:全部文件名 / 目录名与原先一致(本步不引入任何新命名——`shared.ts` 这一 basename 本已存在于 `shared/shared.ts`;`@user/client-base` 的公共导出面不增不减)。
+
+ ⑤ **验证方式(须原样呈报,并声明本步无运行时要求)**:D-68 的延续——本步**没有「保证能运行」的要求**。证明方式全部为**静态**:① **桶边界门禁**:8 个 in-scope barrel(`render/utils/index.ts`、`render/index.tsx`、`client-base/src/index.ts`、`client-base/src/layout/index.ts`、`client-base/src/components/index.ts`、`client-base/src/elements/index.ts`、`client-base/src/map/index.ts`、`client-base/src/map/extension/index.ts`)内每一条 `export * from` 的说明符都以 `./` 开头;② **F1 门禁**:`render/utils/index.ts` 零 `@ts-expect-error` 且无指向 `./layout` 的说明符,`./saves` / `./use` 仍在;③ **F2 / F2' 门禁**:两文件的 `@user/client-base` 说明符在场、`adjustGrid` / `IGridLayoutData` / `adjustCover` 不再自 `../utils` 引入;④ **F3 门禁**:`saves.ts` 零 `@ts-expect-error`、`@user/client-base` 说明符在场、无 `../components`;⑤ **F4 门禁**:`client-base/src/shared.ts` 在场且内容与 `git show HEAD:packages-user/client-base/src/shared/shared.ts` 逐字一致;`shared/` 目录不存在;`client-base/src/index.ts` 的 `./shared` 与 `map/*` 的 4 处相对说明符**一字未改**;⑥ **F5 门禁**:8 处架构耦合标注逐字在场且对应文件的 `git status --porcelain` 零命中;⑦ **范围与用户改动门禁**:`material/` / `load/` / `packages/` / `src/` porcelain 为空、`.planning/REQUIREMENTS.md` 零改动、`04-CONTEXT.md` 未提交改动仍在、porcelain 基线除计划内条目外零漂移;⑧ **CRLF 门禁**;⑨ **人工复核**。**不得使用** `pnpm check:type` / `pnpm build` / 全仓(或范围内)TS 诊断数作为门禁或验收项。
+
+ ⑥ **编号与 wave(须原样告知)**:本计划为 **04-12**(第十二个增量),`wave: 11`,`depends_on` 列 `04-01`..`04-11`;phase 目录内既有 `04-01`..`04-11` 的 `*-PLAN.md` 与 `*-SUMMARY.md` **一律不得改写 / 覆盖 / 改号**,也不得产出 `04-13+`。另须告知:本计划估算 **60k tokens**(`estimate.tasks: 5`),在单计划 smart-zone 预算内。
+
+ ⑦ **盖章效力(须原样告知)**:本计划为**代码改动型**增量,将改 5 个生产文件、删 2 个文件(并移除 `client-base/src/shared/` 空目录)、执行 1 次白名单提交。所有改动均可用 `git revert` 整体回退。
+
+ ⑧ **关卡性质与失败语义(必须原样告知用户)**:无论触发方式(`/gsd-execute-phase`、`/gsd-manager`、`/gsd-autonomous`、子代理/执行器派发)或配置模式(`.planning/config.json` 的 `mode: yolo`、`workflow.auto_advance`)如何,**执行者/子代理都必须在此停下并等待**用户明确回复「可以执行」四个字;未收到这四个字前不得执行任何任务、不得派发执行子代理,也不得以「自动化模式」为由自动放行。用户未回复「可以执行」即继续,或回复的是其它任何内容(含修订意见、沉默、自动化模式下的自动推进、子代理/执行器的自行放行),一律视为**未通过本关卡**:必须立即停止执行、保持只读、不写任何文件,直到用户明确回复「可以执行」四个字后方可继续。
+
+ ⑨ **若用户给出修订意见**(含否决 `shared` 单文件形态 / 否决某个消费者改指 / 希望扩大到其它 barrel / 不同意删除某处标注 / 希望保留 `render/utils/index.ts` 的转发):退出本计划、修订 `04-12-PLAN.md` 后重新汇报,不得自行改道执行。
+
+ 是否按本计划(04-11 落地修正:删 `render/utils/index.ts` 的 `./layout` 越界转发及其标注、`render/ui/{save,title}.tsx` 的 `adjustGrid` / `IGridLayoutData` / `adjustCover` 与 `render/utils/saves.ts` 的 `getConfirm` / `waitbox` 改直连 `@user/client-base` 并删 `saves.ts` 的标注、`client-base/src/shared/` 折成单文件 `client-base/src/shared.ts` 并删两文件 + 空目录、**逐字保留** 8 处架构耦合标注、**零新增转发导出**且 `render/index.tsx` 维持现状、`material/` 与 legacy 与 `packages/` 与 `src/` 与用户改动零触碰、无运行时要求)开始执行
+
+ AGENTS.md 要求任何计划的第一个 block 点必须是向用户汇报计划内容并等待用户确认。`.planning/config.json` 为 `mode: yolo`,因此该关卡必须显式声明为 `blocking-human` 并置 `autonomous: false`,否则计划层面不提供任何 block 点。本次存在会改变交付物形态的判断(`shared` 是否确需折成单文件;`render/utils` 桶少出三个符号是否为可接受结果;8 处架构标注是否确应留待用户收尾),以及一条会放宽验收的既有裁定(D-68:不要求可运行、不要求零类型错误)必须让用户明确知晓,避免执行者事后用「类型不干净」为由扩大范围或阻塞交付。规划日实测的用户并发未提交改动为 `packages-user/client-modules/src/render/index.tsx`(D-70 第 6 条所述「用户已删除越界两行」),本计划必须完全不触碰它。
+
+
+
+
+
+
+ 回复「可以执行」四个字(修订意见请按 action ⑨ 处理)
+
+ 用户在对话中明确回复「可以执行」四个字(人工核对用户回复原文;本关卡为人工关卡,无自动命令,失败语义写在 Task 0 的 action ⑧ 与 acceptance_criteria 中)
+
+
+ - 用户回复中明确包含「可以执行」四个字
+ - 汇报内容涵盖:要解决的问题(04-11 落地形态仍违反 D-69 的 6 处残迹)、锁定裁定 **D-69 原文要点**与 **D-70 的 6 条**(F1..F6,含第 5 条保留、第 6 条不得新增转发的旁注)、源→目标映射表、范围与硬边界(`client-base/src/index.ts` 与 8 处标注与 `render/index.tsx` 等零触碰 + 无依赖变更 + 本步不引入任何新命名)、验证方式
+ - 汇报中已原样告知 **D-68 的延续**(没有「保证能运行」的要求;不设 `check:type` / `build` / TS 诊断数类门禁)与 **本步不引入任何新命名**
+ - 汇报中已原样告知 **编号与 wave**(04-12 / wave 11 / `depends_on` 04-01..04-11)以及既有 `04-01`..`04-11` 产物不得改写 / 覆盖 / 改号、不得产出 `04-13+`
+ - 汇报中已原样告知**验证方式**(桶边界 / F1 / F2 / F3 / F4 / F5 / 范围与用户改动 / CRLF / 人工复核)
+ - 汇报中已原样告知**关卡性质**:执行者/子代理必须停下等待,不因触发方式或 `yolo` / `auto_advance` 模式自动放行
+
+ 用户明确回复「可以执行」;在此之前未执行任何任务、未修改任何文件、未派发任何执行子代理
+
+
+
+ Task 1(tracer):端到端一条线走通 —— `client-base/src/shared/` 折成单文件 `client-base/src/shared.ts`(逐字搬)+ 删除 `shared/shared.ts` 与 `shared/index.ts` + 移除空目录;证明 `client-base/src/index.ts` 的 `./shared` 与 `map/*` 的 4 处相对说明符仍解析
+ Task 0 已闭环:用户在对话中明确回复「可以执行」四个字(未收到则不得开始本任务)
+ packages-user/client-base/src/shared.ts, packages-user/client-base/src/shared/shared.ts(删除), packages-user/client-base/src/shared/index.ts(删除)
+
+ - packages-user/client-base/src/shared/shared.ts(整文件 32 行:`:1` 的 `import { ElementLocator, Font } from '@motajs/render';`、`//#region 地图`、10 个常量及其 jsDoc 注释、`//#endregion`——本任务**逐字**搬运的对象)
+ - packages-user/client-base/src/shared/index.ts(整文件 1 行:`export * from './shared';`——本任务删除的对象)
+ - packages-user/client-base/src/index.ts(整文件 10 行;`:7` 的 `export * from './shared';` 本任务**不得改动**,用于确认折叠后说明符原文不变)
+ - packages-user/client-base/src/map/element.ts:5、packages-user/client-base/src/map/renderer.ts:53、packages-user/client-base/src/map/vertex.ts:25、packages-user/client-base/src/map/extension/door.ts:9(4 处 `'../shared'` / `'../../shared'` 说明符;本任务**不得改动**)
+ - dev.md(「其他要求」的 CRLF;「模块原则」的引入位置;不转发导出)
+
+
+ (0a) **起始基线快照(只读前置,先做这一步)**:执行 `git status --porcelain -- packages packages-user src`,把输出**原样逐行**记为「只读起始基线」记入本任务的执行记录(并写入 `04-12-SUMMARY.md` 的对应栏):先写 bullet `- **只读起始基线(packages / packages-user / src)**:`,其后逐行抄录输出(每条一行,行首为两字符状态码;输出为空则写 `(无)`)。规划日实测为 **1** 条:` M packages-user/client-modules/src/render/index.tsx`(用户的并发未提交改动,D-70 第 6 条所述「用户已删除越界两行」;**本计划全程不得触碰**)。另记 `git rev-parse HEAD` 与 `git rev-parse --abbrev-ref HEAD` 的当日值写入记录(规划日为 `refine/data-client` 分支)。**不得回滚、暂存、提交或修改**任何既有改动。
+
+ (1) **建单文件**:把 `packages-user/client-base/src/shared/shared.ts` 的内容**逐字**复制为 `packages-user/client-base/src/shared.ts`——不得增删任何行、不得改任何常量值、不得改任何 jsDoc / 单行注释 / `//#region 地图` / `//#endregion`、不得改 `:1` 的 `import { ElementLocator, Font } from '@motajs/render';`(即使该导入在摘取后未被使用,也按「最小改动 + 不得改既有代码 / 注释」保留原文)。**不得**顺手清理无用导入、不得重排常量。
+
+ (2) **删除旧两文件**:删除 `packages-user/client-base/src/shared/shared.ts` 与 `packages-user/client-base/src/shared/index.ts`。删除后 `packages-user/client-base/src/shared/` 目录内不得留有任何文件;若目录仍存在(空目录),一并移除该空目录。
+
+ (3) **不改说明符**:**不得**改动 `packages-user/client-base/src/index.ts`(`:7` 的 `./shared` 说明符原文保留);**不得**改动 `map/element.ts:5` / `map/renderer.ts:53` / `map/vertex.ts:25` / `map/extension/door.ts:9` 的 4 处相对说明符。折叠后的解析由「单文件在场 + 目录不存在 + 说明符原样」联合证明(本任务的 `` 断言这三条)。
+
+ (4) **CRLF 与收口**:确认本任务创建的文件(`client-base/src/shared.ts`)为 CRLF 换行(`dev.md`);本任务只允许改 (1)..(3) 列出的文件,**不得**动任何其它文件、不得新增计划文件、不得派发会写文件的子代理。
+
+ 本任务是纯结构迁移收口(把系统层一个两文件目录折成单文件,内容逐字搬、说明符零改动),全部改动都在 git 追踪范围内,可用 `git revert` 或重跑本计划整体回退;未引入任何公共接口行为、契约或新命名。
+
+ node -e "const fs=require('fs');const f='packages-user/client-base/src/shared.ts';if(!fs.existsSync(f)){console.error('MISSING '+f);process.exit(1)}if(fs.existsSync('packages-user/client-base/src/shared')){console.error('FORBIDDEN shared/ DIR STILL PRESENT');process.exit(1)}const t=fs.readFileSync(f,'utf8').replace(/\r\n/g,'\n');const need=['CELL_WIDTH','CELL_HEIGHT','CELL_SIZE','MAP_BLOCK_WIDTH','MAP_BLOCK_HEIGHT','MAP_WIDTH','MAP_HEIGHT','DYNAMIC_RESERVE','MOVING_TOLERANCE','DOOR_ANIMATE_INTERVAL'];const miss=need.filter(x=>t.indexOf('export const '+x)===-1);if(miss.length>0){console.error('CONST MISSING '+miss.join(','));process.exit(1)}if(t.indexOf('import { ElementLocator, Font }')<0){console.error('IMPORT LINE CHANGED');process.exit(1)}console.log('OK shared.ts single file, 10 consts, shared/ dir gone')"
+ non-zero exit, 或 stderr 含 "MISSING" / "FORBIDDEN shared/ DIR STILL PRESENT" / "CONST MISSING" / "IMPORT LINE CHANGED"(`client-base/src/shared.ts` 未创建、`shared/` 目录仍在、常量缺失、或导入行被改动)
+ node -e "const fs=require('fs');for(const f of ['packages-user/client-base/src/shared/shared.ts','packages-user/client-base/src/shared/index.ts']){if(fs.existsSync(f)){console.error('OLD FILE REMAINS '+f);process.exit(1)}}console.log('OK shared/shared.ts + shared/index.ts deleted')"
+ non-zero exit, 或 stderr 含 "OLD FILE REMAINS"(`shared/shared.ts` 或 `shared/index.ts` 未被删除)
+ node -e "const fs=require('fs'),{execSync}=require('child_process');const head=execSync('git rev-parse HEAD',{encoding:'utf8'}).trim();const orig=execSync('git show '+head+':packages-user/client-base/src/shared/shared.ts',{encoding:'utf8',maxBuffer:1e8}).replace(/\r\n/g,'\n');const now=fs.readFileSync('packages-user/client-base/src/shared.ts','utf8').replace(/\r\n/g,'\n');if(orig!==now){console.error('SHARED SINGLE FILE NOT VERBATIM');process.exit(1)}const idx=fs.readFileSync('packages-user/client-base/src/index.ts','utf8');const q=String.fromCharCode(39);if(idx.indexOf('export * from '+q+'./shared'+q)<0){console.error('client-base barrel shared SPECIFIER CHANGED');process.exit(1)}const specs=[['packages-user/client-base/src/map/element.ts',q+'../shared'+q],['packages-user/client-base/src/map/renderer.ts',q+'../shared'+q],['packages-user/client-base/src/map/vertex.ts',q+'../shared'+q],['packages-user/client-base/src/map/extension/door.ts',q+'../../shared'+q]];const bad=specs.filter(s=>fs.readFileSync(s[0],'utf8').indexOf(s[1])<0);if(bad.length>0){console.error('MAP SHARED SPECIFIER CHANGED :: '+bad.map(b=>b[0]).join(','));process.exit(1)}console.log('OK shared.ts verbatim; barrel + 4 map specifiers unchanged')"
+ non-zero exit, 或 stderr 含 "SHARED SINGLE FILE NOT VERBATIM" / "barrel shared SPECIFIER CHANGED" / "MAP SHARED SPECIFIER CHANGED"(单文件内容与原件不逐字相同,或 `client-base/src/index.ts` / `map/*` 的说明符被改动)
+ node -e "const{execSync}=require('child_process');const o=execSync('git status --porcelain -- packages-user/client-base/src/material packages-user/client-base/src/load packages packages/ src',{encoding:'utf8'}).replace(/\s+$/,'');if(o.length>0){console.error('FORBIDDEN PATH TOUCHED: '+o);process.exit(1)}console.log('OK forbidden paths clean')"
+ non-zero exit, 或 stderr 含 "FORBIDDEN PATH TOUCHED"(`material/` / `load/` / `packages/` / `src/` 被改动 —— D-42 / D-48 / D-33 边界被破)
+ node -e "const fs=require('fs');const f='packages-user/client-base/src/shared.ts';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 shared.ts')"
+ non-zero exit, 或 stderr 含 "NON-CRLF"(`client-base/src/shared.ts` 出现非 CRLF 换行,违反 dev.md「换行使用 CRLF 格式」)
+
+
+ - `packages-user/client-base/src/shared.ts` 存在,且内容与 `git show :packages-user/client-base/src/shared/shared.ts` **逐行一致**(纯搬运、注释零改写)
+ - `packages-user/client-base/src/shared.ts` 含 10 个常量(`CELL_WIDTH` / `CELL_HEIGHT` / `CELL_SIZE` / `MAP_BLOCK_WIDTH` / `MAP_BLOCK_HEIGHT` / `MAP_WIDTH` / `MAP_HEIGHT` / `DYNAMIC_RESERVE` / `MOVING_TOLERANCE` / `DOOR_ANIMATE_INTERVAL`)与 `:1` 的 `@motajs/render` 导入行
+ - `packages-user/client-base/src/shared/shared.ts` 与 `packages-user/client-base/src/shared/index.ts` **均不存在**;`packages-user/client-base/src/shared/` 目录**不存在**
+ - `packages-user/client-base/src/index.ts` 的 `export * from './shared'` 说明符**一字未改**
+ - `map/element.ts` / `map/renderer.ts` / `map/vertex.ts` 的 `'../shared'` 与 `map/extension/door.ts` 的 `'../../shared'` **一字未改**
+ - `material/` / `load/` / `packages/` / `src/` 零改动;`client-base/src/shared.ts` 为 CRLF
+ - 未触碰任何其它文件;未新增计划文件;未派发会写文件的子代理
+
+ 端到端一条线走通折叠层:`client-base/src/shared.ts` 单文件逐字就位、`shared/` 目录(及其两文件)已移除、`client-base/src/index.ts` 的 `./shared` 与 `map/*` 的 4 处相对说明符原样保留;门禁(单文件在场 / 旧文件删除 / 逐字一致 / 说明符原样 / 范围 / CRLF)全绿;后续任务只需按同一形态横向铺开实现层的桶去转发与消费者直连
+
+
+
+ Task 2:实现层 utils 桶去转发(F1)+ `render/utils/saves.ts` 直连去标注(F3)—— 删 `render/utils/index.ts` 的 `./layout` 转发及其标注;`getConfirm` / `waitbox` 改自 `@user/client-base` 并删其标注
+ Task 0 已闭环(用户已回复「可以执行」)且 Task 1 已交付(`client-base/src/shared.ts` 单文件在场、`shared/` 目录不存在)
+ packages-user/client-modules/src/render/utils/index.ts, packages-user/client-modules/src/render/utils/saves.ts
+
+ - packages-user/client-modules/src/render/utils/index.ts(整文件 4 行:`:1` 的 `@ts-expect-error`(D-60 标注)、`:2` 的指向 `./layout` 的 `export * from`(F1 的删除对象)、`:3` `./saves`、`:4` `./use`(**不得改动**))
+ - packages-user/client-modules/src/render/utils/saves.ts(整合导入区 `:1-6`:`:1` `lz-string`、`:2` 的 `@ts-expect-error`(F3 的删除对象)、`:3` 的 `getConfirm` / `waitbox` 自 `../components`(F3 的改指对象)、`:4-6` 其余导入(**不得改动**);`saves.ts` 内 `getConfirm` 4 处调用、`waitbox` 1 处调用——D-70 第 3 条只改引入来源,调用点零改动)
+ - packages-user/client-base/src/components/choices.tsx:597 与 packages-user/client-base/src/components/misc.tsx:570(`getConfirm` / `waitbox` 的声明处,确认两符号确由 `@user/client-base` 的 `./components` 桶出口提供)
+ - packages-user/client-base/src/index.ts:8(`export * from './components';`——`@user/client-base` 提供 `getConfirm` / `waitbox` 的出口证据)
+ - packages-user/client-modules/src/action/move.ts:1-6(`// @ts-expect-error <原因>` 与 import 行的既有书写先例,用于确认本任务的删除/改指不涉及新增标注)
+ - dev.md(「模块原则」的**不转发导出**与引入位置;「类型规范」的 `@ts-expect-error` 须说明原因;「其他要求」的 CRLF)
+
+
+ (1) **F1 —— `render/utils/index.ts` 去转发(D-70 第 1 条)**:删除 `packages-user/client-modules/src/render/utils/index.ts` 中**位于文件顶部**的那条指向 `./layout` 的 `export * from` 语句,**并连同其上一行的 `@ts-expect-error` 一并删除**。删除后该文件应只剩两条同目录导出(`./saves` 与 `./use`),**原文与顺序不得改动**,且文件内**不得**残留任何 `@ts-expect-error`、**不得**留下指向 `./layout` 的说明符、**不得**改为引用 `@user/client-base`、**不得**为该桶补任何转发(D-69 明禁)。
+
+ (2) **F3 —— `render/utils/saves.ts` 直连并去标注(D-70 第 3 条)**:把 `packages-user/client-modules/src/render/utils/saves.ts` 中引入 `getConfirm` / `waitbox` 的说明符由相对 `../components` 改为 `'@user/client-base'`(**只替换说明符文本**,被导入符号列表 `{ getConfirm, waitbox }` 与语句形态不变),**并删除其正上方那一行的 `@ts-expect-error`**(该标注是 D-60 的断链暂记,现按 D-70 第 3 条去断链)。该文件其余导入(`lz-string` / `@motajs/system` / `@motajs/client-base` / `../../shared`)**一字不动**;文件内**不得**残留任何 `@ts-expect-error`。
+
+ (3) **不新增标注**:本任务**只允许删除**上述 2 处 `@ts-expect-error`;不得在任何位置新增 `@ts-expect-error`(尤其不得为 `render/utils/index.ts` 去 `./layout` 后的「导出面收窄」补标注——这是 D-69 的预期结果,不是错误)。
+
+ (4) **CRLF 与收口**:确认本任务修改的两个文件为 CRLF;本任务只允许改 (1) / (2) 列出的两个文件,**不得**改动 `render/utils/use.ts`、`render/ui/{save,title}.tsx`(留待 Task 3)、`render/index.tsx`(D-70 第 6 条维持现状)、`client-base/**` 或任何其它文件;不得新增计划文件;不得派发会写文件的子代理。
+
+ 本任务删除 1 条越界桶转发 + 1 条断链标注、并把 1 处消费者导入改指为 `@user/client-base`,全部改动均在 git 追踪范围内、无公共接口行为改动、无新命名,可用 `git revert` 或重跑本计划整体回退。
+
+ node -e "const fs=require('fs');const f='packages-user/client-modules/src/render/utils/index.ts';const t=fs.readFileSync(f,'utf8').replace(/\r\n/g,'\n');const q=String.fromCharCode(39);if(t.indexOf('@ts-expect-error')>=0){console.error('ANNOTATION STILL PRESENT');process.exit(1)}if(t.indexOf('export * from '+q+'./layout'+q)>=0){console.error('LAYOUT FORWARD EXPORT STILL PRESENT');process.exit(1)}for(const s of ['./saves','./use']){if(t.indexOf('export * from '+q+s+q)<0){console.error('MISSING KEPT EXPORT '+s);process.exit(1)}}console.log('OK render/utils barrel: no layout forward, no annotation, saves+use kept')"
+ non-zero exit, 或 stderr 含 "ANNOTATION STILL PRESENT" / "LAYOUT FORWARD EXPORT STILL PRESENT" / "MISSING KEPT EXPORT"(`render/utils/index.ts` 仍转发 `./layout`、或仍带 `@ts-expect-error`、或误删了 `./saves` / `./use` 两条同目录导出 —— D-70 第 1 条未落地)
+ node -e "const fs=require('fs');const f='packages-user/client-modules/src/render/utils/saves.ts';const t=fs.readFileSync(f,'utf8').replace(/\r\n/g,'\n');const q=String.fromCharCode(39);if(t.indexOf('@ts-expect-error')>=0){console.error('ANNOTATION STILL PRESENT (D-70.3)');process.exit(1)}if(t.indexOf(q+'../components'+q)>=0){console.error('OLD components SPECIFIER STILL PRESENT');process.exit(1)}const lines=t.split('\n');const i=lines.findIndex(l=>l.indexOf('getConfirm')>=0&&l.indexOf('import')>=0);if(i<0){console.error('getConfirm import LINE NOT FOUND');process.exit(1)}if(lines[i].indexOf(q+'@user/client-base'+q)<0){console.error('getConfirm/waitbox NOT REWIRED TO user client-base');process.exit(1)}if(lines[i].indexOf('waitbox')<0){console.error('waitbox SYMBOL LIST CHANGED');process.exit(1)}if((t.match(/getConfirm\(/g)||[]).length<4){console.error('getConfirm CALL SITES CHANGED');process.exit(1)}console.log('OK saves.ts rewired to user client-base; annotation removed; call sites intact')"
+ non-zero exit, 或 stderr 含 "ANNOTATION STILL PRESENT" / "OLD components SPECIFIER" / "NOT REWIRED" / "SYMBOL LIST CHANGED" / "CALL SITES CHANGED"(`saves.ts` 的标注未删、说明符未改指、被导入符号列表被改、或调用点被误改 —— D-70 第 3 条未落地或超出范围)
+ node -e "const fs=require('fs');const t=fs.readFileSync('packages-user/client-modules/src/render/utils/use.ts','utf8');if(t.indexOf('@ts-expect-error')>=0){console.error('render utils use.ts MUST BE UNTOUCHED');process.exit(1)}console.log('OK render/utils/use.ts untouched')"
+ non-zero exit, 或 stderr 含 "MUST BE UNTOUCHED"(误改了本任务范围外的 `render/utils/use.ts`)
+ node -e "const fs=require('fs');const files=['packages-user/client-modules/src/render/utils/index.ts','packages-user/client-modules/src/render/utils/saves.ts'];const bad=[];for(const f of files){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(f+' ('+(lf-crlf)+' stray LF)')}if(bad.length>0){console.error('NON-CRLF '+bad.join(' ; '));process.exit(1)}console.log('OK CRLF 2 files')"
+ non-zero exit, 或 stderr 含 "NON-CRLF"(本任务修改的文件出现非 CRLF 换行)
+
+
+ - `packages-user/client-modules/src/render/utils/index.ts` 不再含指向 `./layout` 的 `export * from`,**且**不再含任何 `@ts-expect-error`;`./saves` 与 `./use` 两条导出原文保留
+ - `packages-user/client-modules/src/render/utils/saves.ts` 的 `getConfirm` / `waitbox` 自 `@user/client-base` 引入;不再含指向 `../components` 的说明符;不再含任何 `@ts-expect-error`
+ - `saves.ts` 的被导入符号列表(`{ getConfirm, waitbox }`)、其余导入行与全部调用点零改动(`getConfirm(` 命中数 ≥ 4)
+ - `render/utils/use.ts` 零改动;`render/utils/index.ts` 与 `saves.ts` 均为 CRLF
+ - 未新增任何 `@ts-expect-error`;未触碰 `render/ui/**`、`render/index.tsx`、`client-base/**` 或任何其它文件;未新增计划文件;未派发会写文件的子代理
+
+ D-69 在实现层 utils 桶上的两半落地:`render/utils/index.ts` 不再越界转发 `./layout` 且标注清除;`render/utils/saves.ts` 的 `getConfirm` / `waitbox` 直连 `@user/client-base` 且标注清除;门禁(桶去转发 / 直连 / 调用点不变 / 范围 / CRLF)全绿
+
+
+
+ Task 3:`render/ui` 两消费者直连 `@user/client-base`(F2 / F2')—— `save.tsx` 拆分 `../utils` 导入(`adjustGrid` / `IGridLayoutData` 改指)+ `title.tsx` 的 `adjustCover` 改指
+ Task 0 已闭环(用户已回复「可以执行」)且 Task 2 已交付(`render/utils/index.ts` 已去 `./layout` 转发、`saves.ts` 已直连)
+ packages-user/client-modules/src/render/ui/save.tsx, packages-user/client-modules/src/render/ui/title.tsx
+
+ - packages-user/client-modules/src/render/ui/save.tsx(`:16` 既有的 `@user/client-base` 导入(`getConfirm` / `Page` / `PageExpose` / `Thumbnail`,**不得改动**);`:31` 的 `../utils` 导入(`getSave` / `SaveData` / `adjustGrid` / `IGridLayoutData`——F2 的拆分对象);`:180` 的 `computed` 与 `:181` 的 `adjustGrid(...)` 调用(确认符号仍在用、**调用点不得改动**))
+ - packages-user/client-modules/src/render/ui/title.tsx(`:35` 的 `import { adjustCover } from '../utils';`——F2' 的改指对象;`:71-76` 的 `adjustCover(...)` 调用(**不得改动**);`:31` 既有的 `@user/client-base` 导入(**不得改动**))
+ - packages-user/client-base/src/layout/layout.ts:3 / :28 / :69(`IGridLayoutData` / `adjustGrid` / `adjustCover` 的声明处,确认三符号确由 `@user/client-base` 的 `./layout` 桶出口提供)
+ - packages-user/client-base/src/index.ts:6(`export * from './layout';`——`@user/client-base` 提供三符号的出口证据)
+ - dev.md(「模块原则」的引入位置与**不转发导出**;「其他要求」的 CRLF;禁止 `import type`)
+
+
+ (1) **F2 —— `render/ui/save.tsx` 拆分 `../utils` 导入(D-70 第 2 条)**:把该文件中唯一一条自相对 `../utils` 的导入**拆成两条**——一条自 `'@user/client-base'` 引入 `{ adjustGrid, IGridLayoutData }`,另一条自 `'../utils'` 引入 `{ getSave, SaveData }`。要求:① 被导入符号**各自归位、不增不减**(`adjustGrid` / `IGridLayoutData` 只在 `@user/client-base` 那条出现,`getSave` / `SaveData` 只在 `../utils` 那条出现);② 两条均为常规 `import { ... } from '';` 语句,**不得**使用 `import type`(`dev.md`);③ 该文件其它行(`:16` 既有 `@user/client-base` 导入、被导入符号的使用点、全部组件 / 逻辑 / 注释)**一字不动**;④ **不得**删除或改写既有 jsDoc / 注释(AGENTS.md)。摆放:两条语句置于原位(原 `../utils` 导入所在位置)即可,不重排该文件其它导入。
+
+ (2) **F2' —— `render/ui/title.tsx` 的 `adjustCover` 改指(D-70 第 2 条)**:把 `packages-user/client-modules/src/render/ui/title.tsx` 中引入 `adjustCover` 的说明符由相对 `../utils` 改为 `'@user/client-base'`(**只替换说明符文本**,被导入符号列表 `{ adjustCover }` 与语句形态不变)。该文件其余内容**一字不动**(含 `:31` 既有的 `@user/client-base` 导入——本次**不合并**两条 `@user/client-base` 导入,仅按最小改动替换说明符)。
+
+ (3) **不新增标注 / 不改动无关面**:本任务**不得**新增任何 `@ts-expect-error`;**不得**改动 `render/ui` 下的其它文件(`main.tsx` / `settings.tsx` / `statistics.tsx` / `statusBar.tsx` / `toolbar.tsx` / `viewmap.tsx` 等,均不在本步范围);**不得**改动 `render/index.tsx`(D-70 第 6 条维持现状)或 `client-base/**`。
+
+ (4) **CRLF 与收口**:确认本任务修改的两个文件为 CRLF;本任务只允许改 (1) / (2) 列出的两个文件;不得新增计划文件;不得派发会写文件的子代理。
+
+ 本任务是消费者导入来源的最小改动(一条导入拆两条 + 一处说明符替换),全部改动均在 git 追踪范围内、无公共接口行为改动、无新命名,可用 `git revert` 或重跑本计划整体回退。
+
+ node -e "const fs=require('fs');const f='packages-user/client-modules/src/render/ui/save.tsx';const t=fs.readFileSync(f,'utf8').replace(/\r\n/g,'\n');const q=String.fromCharCode(39);const lines=t.split('\n');const utilIdx=lines.findIndex(l=>l.indexOf('from '+q+'../utils'+q)>=0);if(utilIdx<0){console.error('utils import NOT FOUND');process.exit(1)}const utilSym=lines[utilIdx].slice(lines[utilIdx].indexOf('{'),lines[utilIdx].indexOf('}'));for(const s of ['adjustGrid','IGridLayoutData']){if(utilSym.indexOf(s)>=0){console.error('STILL FROM utils :: '+s);process.exit(1)}}for(const s of ['getSave','SaveData']){if(utilSym.indexOf(s)<0){console.error('MISSING FROM utils :: '+s);process.exit(1)}}const cb=lines.filter(l=>l.indexOf('from '+q+'@user/client-base'+q)>=0);const cbSym=cb.map(l=>l.slice(l.indexOf('{'),l.indexOf('}'))).join(' ');for(const s of ['adjustGrid','IGridLayoutData']){if(cbSym.indexOf(s)<0){console.error('MISSING FROM user client-base :: '+s);process.exit(1)}}if(t.indexOf('import type')>=0){console.error('IMPORT TYPE FORBIDDEN');process.exit(1)}console.log('OK save.tsx split: adjustGrid/IGridLayoutData <- user client-base; getSave/SaveData <- utils')"
+ non-zero exit, 或 stderr 含 "utils import NOT FOUND" / "STILL FROM utils" / "MISSING FROM utils" / "MISSING FROM user client-base" / "IMPORT TYPE FORBIDDEN"(`save.tsx` 未拆分、`adjustGrid` / `IGridLayoutData` 仍自 `../utils`、`getSave` / `SaveData` 被误移、或使用了 `import type` —— D-70 第 2 条未落地或违反 dev.md)
+ node -e "const fs=require('fs');const f='packages-user/client-modules/src/render/ui/title.tsx';const t=fs.readFileSync(f,'utf8').replace(/\r\n/g,'\n');const q=String.fromCharCode(39);if(t.indexOf('from '+q+'../utils'+q)>=0){console.error('title.tsx STILL IMPORTS FROM utils');process.exit(1)}const lines=t.split('\n');const i=lines.findIndex(l=>l.indexOf('adjustCover')>=0&&l.indexOf('import')>=0);if(i<0){console.error('adjustCover import NOT FOUND');process.exit(1)}if(lines[i].indexOf(q+'@user/client-base'+q)<0){console.error('adjustCover NOT REWIRED');process.exit(1)}if((t.match(/adjustCover\(/g)||[]).length<1){console.error('adjustCover CALL SITE CHANGED');process.exit(1)}if(t.indexOf('@ts-expect-error')>=0){console.error('NEW ANNOTATION FORBIDDEN');process.exit(1)}console.log('OK title.tsx adjustCover <- user client-base')"
+ non-zero exit, 或 stderr 含 "STILL IMPORTS FROM utils" / "adjustCover import NOT FOUND" / "NOT REWIRED" / "CALL SITE CHANGED" / "NEW ANNOTATION FORBIDDEN"(`title.tsx` 的 `adjustCover` 未改指、调用点被误改、或新增了 `@ts-expect-error`)
+ node -e "const{execSync}=require('child_process');const o=execSync('git status --porcelain -- packages-user/client-modules/src/render/ui',{encoding:'utf8'}).replace(/\s+$/,'');const rows=o.length>0?o.split(/\r?\n/):[];const allowed=['main.tsx','save.tsx','settings.tsx','statistics.tsx','statusBar.tsx','title.tsx','toolbar.tsx','viewmap.tsx'];const bad=rows.filter(r=>{const parts=r.slice(3).trim().split(String.fromCharCode(47));const p=parts[parts.length-1];return allowed.indexOf(p)<0});if(bad.length>0){console.error('UNEXPECTED ui FILE TOUCHED :: '+bad.join(' ; '));process.exit(1)}console.log('OK render/ui: only in-scope ui files touched ('+rows.length+' rows)')"
+ non-zero exit, 或 stderr 含 "UNEXPECTED ui FILE TOUCHED"(`render/ui` 下出现了非导入改指目标之外的文件改动 —— 超出 F2 / F2' 范围)
+ node -e "const fs=require('fs');const files=['packages-user/client-modules/src/render/ui/save.tsx','packages-user/client-modules/src/render/ui/title.tsx'];const bad=[];for(const f of files){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(f+' ('+(lf-crlf)+' stray LF)')}if(bad.length>0){console.error('NON-CRLF '+bad.join(' ; '));process.exit(1)}console.log('OK CRLF 2 files')"
+ non-zero exit, 或 stderr 含 "NON-CRLF"(本任务修改的文件出现非 CRLF 换行)
+
+
+ - `render/ui/save.tsx`:`adjustGrid` / `IGridLayoutData` 自 `@user/client-base` 引入;`getSave` / `SaveData` 仍自 `../utils` 引入;无 `import type`;`:16` 既有 `@user/client-base` 导入与全部调用点 / 注释零改动
+ - `render/ui/title.tsx`:`adjustCover` 自 `@user/client-base` 引入;该文件不再有指向 `../utils` 的说明符;`adjustCover(...)` 调用点与其余内容零改动
+ - 两文件均未新增 `@ts-expect-error`;`render/ui` 下无范围外文件改动
+ - 两文件均为 CRLF;未触碰 `render/index.tsx`、`client-base/**` 或任何其它文件;未新增计划文件;未派发会写文件的子代理
+
+ `render/ui` 两消费者直连落地:`save.tsx` 的 `../utils` 导入已按 D-70 第 2 条拆分(`adjustGrid` / `IGridLayoutData` → `@user/client-base`;`getSave` / `SaveData` → `../utils`),`title.tsx` 的 `adjustCover` 已改指 `@user/client-base`;门禁(拆分 / 改指 / 范围 / CRLF)全绿
+
+
+
+ Task 4:收口 —— 桶边界门禁(D-69 的 8 个 in-scope barrel)+ F5 的 8 处架构标注逐字保留 + F6(`render/index.tsx` 维持现状)+ 范围与用户改动门禁 + 人工复核 + `04-12-SUMMARY.md` + 白名单提交
+ Task 0 已闭环(用户已回复「可以执行」)且 Task 1 / 2 / 3 均已交付(`client-base/src/shared.ts` 单文件在场、`shared/` 目录不存在、`render/utils/{index,saves}.ts` 已去转发 / 直连、`render/ui/{save,title}.tsx` 已直连)
+ packages-user/client-base/src/shared.ts, packages-user/client-base/src/shared/shared.ts(删除), packages-user/client-base/src/shared/index.ts(删除), packages-user/client-modules/src/render/utils/index.ts, packages-user/client-modules/src/render/utils/saves.ts, packages-user/client-modules/src/render/ui/save.tsx, packages-user/client-modules/src/render/ui/title.tsx, .planning/phases/04-render-adaptation/04-12-SUMMARY.md
+
+ - .planning/phases/04-render-adaptation/04-11-SUMMARY.md:72-120(上一增量的 Performance / 只读基线 / 落点表 / 门禁摘要 / 人工复核的写法,本 SUMMARY 对齐版式)
+ - .planning/phases/04-render-adaptation/04-12-PLAN.md(本计划的 must_haves(truths / artifacts / key_links / assumptions / prohibitions)、F1..F6 表与逐条门禁)
+ - .planning/ROADMAP.md(Phase 4 的 `**Plans:**` 行、`**Plan register note (2026-09-24 · 04-11 第二步):**` 与 `**Wave 10**` 条目——本步登记 `04-12` / `Wave 11` 的样式基准;本计划不在此文件内写其它内容)
+ - packages-user/client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}(F5 的逐字核对面:引用 `render/use.ts` / `render/renderer` 的 8 处为 `misc.tsx:10,15` 2 处、`input.tsx:14`、`choices.tsx:8`、`scroll.tsx:31`、`textboxTyper.ts:6`、`tip.tsx:4`、`elements/index.ts:3`;**注意** `textboxTyper.ts` 另有 1 处既有 `无法推导` 标注(规划日 `:332`)不在那 8 处内,故该文件的 `@ts-expect-error` 计数为 2、7 个文件合计 9)
+ - packages-user/client-modules/src/render/index.tsx(F6 的「维持现状」核对面:7 条 `export *`(`:45-51`)全部指向自身文件夹内;本任务不对其做任何改动)
+ - dev.md(「其他要求」的 CRLF;「模块原则」的不转发导出)
+
+
+ (1) **桶边界门禁(D-69 的机器证明)**:对下述 **8** 个 in-scope barrel 逐条读取其全部 `export * from` 行,断言每一条的说明符以 `./` 开头:`packages-user/client-modules/src/render/utils/index.ts`、`packages-user/client-modules/src/render/index.tsx`、`packages-user/client-base/src/index.ts`、`packages-user/client-base/src/layout/index.ts`、`packages-user/client-base/src/components/index.ts`、`packages-user/client-base/src/elements/index.ts`、`packages-user/client-base/src/map/index.ts`、`packages-user/client-base/src/map/extension/index.ts`。另**单独**断言 `render/utils/index.ts` 不再含指向 `./layout` 的说明符。任一越界说明符即门禁失败。**该门禁同时覆盖 F6**(`render/index.tsx` 的 7 条 `export *` 全为 `./` 前缀 = 维持现状且合规)。
+
+ (2) **F5 门禁(8 处架构标注逐字保留)**:断言 `packages-user/client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}` 内**引用 `render/use.ts` / `render/renderer` 的** `@ts-expect-error` 共 **8** 处,每处形如 `// @ts-expect-error <非空原因>`(无裸标注);这 7 个文件的 `@ts-expect-error` **总数**为 **9**(`textboxTyper.ts` 含 1 处既有 `无法推导` 标注,同属逐字保留、不在那 8 处内);且这 7 个文件的 `git status --porcelain` **零命中**(= 逐字保留、零改动)。
+
+ (3) **F4 / F1 / F2 / F3 的收口自检**:断言 `client-base/src/shared.ts` 在场 + `client-base/src/shared/` 不存在;`render/utils/index.ts` 无 `@ts-expect-error` 且无 `./layout` 说明符;`render/ui/save.tsx` 的 `@user/client-base` 说明符含 `adjustGrid` / `IGridLayoutData`;`render/ui/title.tsx` 的 `adjustCover` 自 `@user/client-base`;`render/utils/saves.ts` 无 `@ts-expect-error` 且 `getConfirm` 自 `@user/client-base`。
+
+ (4) **范围与用户改动门禁**:断言 `git status --porcelain -- packages-user/client-base/src/material packages-user/client-base/src/load packages packages/ src` 为空;`.planning/REQUIREMENTS.md` porcelain 为空;`.planning/phases/04-render-adaptation/04-CONTEXT.md` 与 `packages-user/client-modules/src/render/index.tsx` 的既有未提交改动**仍在**(不被回滚 / 提交);本计划改动面之外无新条目(把 `git status --porcelain -- packages packages-user src` 与 Task 1 步骤 (0a) 的起始基线逐条比对:既有条目不消失、仅新增本计划 `files_modified` / `files_deleted` 范围内的条目)。
+
+ (5) **CRLF 收口**:确认本计划触及的全部生产文件(`client-base/src/shared.ts`、`render/utils/index.ts`、`render/utils/saves.ts`、`render/ui/save.tsx`、`render/ui/title.tsx`)为 CRLF。
+
+ (6) **人工代码复核(不可自动化,如实记录结论)**:逐条打开当日源码确认——`client-base/src/shared.ts` 与 `git show HEAD:packages-user/client-base/src/shared/shared.ts` 逐字一致且 `shared/` 目录已消失、`client-base/src/index.ts:7` 与 `map/*` 4 处说明符原样;`render/utils/index.ts` 仅剩 `./saves` / `./use`、无标注;`render/utils/saves.ts` 的 `getConfirm` 导入说明符与标注状态;`render/ui/save.tsx` 拆分后的两条导入与 `:16` 既有导入;`render/ui/title.tsx` 的 `adjustCover` 说明符;F5 的 8 处标注逐字在场;`render/index.tsx` 的 7 条 `export *` 全为同目录。发现偏差即回到相应任务修正。把复核结论(通过 / 偏差及修正)写入 SUMMARY。
+
+ (7) **写 `04-12-SUMMARY.md`**:按 04-11-SUMMARY 的版式写——frontmatter(`phase` / `plan: 12` / `tags` / `requires` / `provides` / `affects` / `actuals` / `key-files`(created / modified / deleted)/ `key-decisions` / `requirements-completed: []` / `duration` / `completed` / `status`)+ 只读起始基线(Task 1 (0a) 的原文)+ Accomplishments(F1..F6 逐条落点表)+ Task Commits + 门禁实测结果 + 人工复核结论 + Decisions Made + Deviations(如有)+ Known Stubs(F5 的 8 处待用户收尾 / `packages/client/src/index.ts:1` 的旁注等)+ Next Phase Readiness。**如实声明本步无运行时验证(D-68 的延续)**。
+
+ (8) **白名单提交(单次)**:核对 `git status`,**只**暂存本计划 `files_modified` / `files_deleted` 的条目(含 `04-12-SUMMARY.md`)——绝不暂存 `packages-user/client-modules/src/render/index.tsx`、`.planning/phases/04-render-adaptation/04-CONTEXT.md` 或任何其它文件;以 `refactor(04-12): 桶导出边界修正——shared 单文件化 + 消费者直连 @user/client-base(D-69/D-70)` 为提交信息提交。**不得**借提交顺带格式化 / 重排无关文件;**不得** amend 任何既有提交。
+
+ (9) **不写其它 `.planning/` 文件**:本任务除 `04-12-SUMMARY.md` 外**不得**写 `.planning/STATE.md` / `WINDOWS.md` / `REQUIREMENTS.md`;ROADMAP 的 `04-12` / `Wave 11` 登记已在计划阶段完成(本任务不改 ROADMAP)。
+
+ 本任务是收口(门禁 + 文档 + 一次白名单提交),唯一的生产改动是 `04-12-SUMMARY.md`(文档);提交内容全部是本计划前序任务的成果,可用 `git revert` 整体回退。
+
+ node -e "const fs=require('fs');const barrels=['packages-user/client-modules/src/render/utils/index.ts','packages-user/client-modules/src/render/index.tsx','packages-user/client-base/src/index.ts','packages-user/client-base/src/layout/index.ts','packages-user/client-base/src/components/index.ts','packages-user/client-base/src/elements/index.ts','packages-user/client-base/src/map/index.ts','packages-user/client-base/src/map/extension/index.ts'];const bad=[];let total=0;for(const f of barrels){const lines=fs.readFileSync(f,'utf8').replace(/\r\n/g,'\n').split('\n');for(let i=0;i '+m[1])}}const idx=fs.readFileSync(barrels[0],'utf8');if(idx.indexOf('export * from '+String.fromCharCode(39)+'./layout'+String.fromCharCode(39))>=0)bad.push('render/utils still forwards ./layout');if(bad.length>0){console.error('BARREL BOUNDARY VIOLATION :: '+bad.join(' ; '));process.exit(1)}console.log('OK barrel boundary: '+barrels.length+' barrels, '+total+' export * lines, all own-folder')"
+ non-zero exit, 或 stderr 含 "BARREL BOUNDARY VIOLATION"(in-scope barrel 内出现非 `./` 前缀的 `export * from` 说明符,或 `render/utils/index.ts` 仍转发 `./layout` —— D-69 未落地)
+ node -e "const fs=require('fs');const files=['components/choices.tsx','components/input.tsx','components/misc.tsx','components/scroll.tsx','components/textboxTyper.ts','components/tip.tsx','elements/index.ts'];const bad=[];let total=0;let coupled=0;for(const k of files){const p='packages-user/client-base/src/'+k;if(!fs.existsSync(p)){bad.push('MISSING '+p);continue}const lines=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n').split('\n');const idxs=lines.map((l,i)=>l.indexOf('@ts-expect-error')>=0?i:-1).filter(i=>i>=0);total+=idxs.length;for(const i of idxs){if(!/@ts-expect-error\s+\S/.test(lines[i]))bad.push(k+':'+(i+1)+' BARE');if(lines[i].indexOf('render/use.ts')>=0||lines[i].indexOf('render/renderer')>=0)coupled++}}if(total!==9)bad.push('total '+total+' expected 9');if(coupled!==8)bad.push('coupled '+coupled+' expected 8');if(bad.length>0){console.error('F5 ANNOTATION GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK F5: '+coupled+' render-coupled annotations (of '+total+' in these files), all with reasons')"
+ non-zero exit, 或 stderr 含 "F5 ANNOTATION GATE FAILED" / "BARE"(D-70 第 5 条的 8 处「引用 `render/use.ts` / `render/renderer`」标注数量不符、这 7 个文件总数不等于 9、或存在无原因的裸标注 —— 被误改 / 误删 / 新增裸标注)
+ node -e "const{execSync}=require('child_process');const files=['packages-user/client-base/src/components/choices.tsx','packages-user/client-base/src/components/input.tsx','packages-user/client-base/src/components/misc.tsx','packages-user/client-base/src/components/scroll.tsx','packages-user/client-base/src/components/textboxTyper.ts','packages-user/client-base/src/components/tip.tsx','packages-user/client-base/src/elements/index.ts'];const bad=[];for(const f of files){const o=execSync('git status --porcelain -- '+f,{encoding:'utf8'}).replace(/\s+$/,'');if(o.length>0)bad.push(f)}if(bad.length>0){console.error('F5 FILES DIRTY :: '+bad.join(' ; '));process.exit(1)}console.log('OK F5: 8 annotation-bearing files untouched (porcelain clean)')"
+ non-zero exit, 或 stderr 含 "F5 FILES DIRTY"(D-70 第 5 条点名的文件被改动 —— 应逐字保留)
+ node -e "const fs=require('fs');const q=String.fromCharCode(39);const p=[];if(!fs.existsSync('packages-user/client-base/src/shared.ts'))p.push('shared.ts MISSING');if(fs.existsSync('packages-user/client-base/src/shared'))p.push('shared/ DIR PRESENT');const idx=fs.readFileSync('packages-user/client-modules/src/render/utils/index.ts','utf8');if(idx.indexOf('@ts-expect-error')>=0)p.push('utils/index annotation present');if(idx.indexOf('export * from '+q+'./layout'+q)>=0)p.push('utils/index layout forward present');const sv=fs.readFileSync('packages-user/client-modules/src/render/utils/saves.ts','utf8');if(sv.indexOf('@ts-expect-error')>=0)p.push('saves.ts annotation present');const ln=sv.split(/\r?\n/).find(l=>l.indexOf('getConfirm')>=0&&l.indexOf('import')>=0)||'';if(ln.indexOf(q+'@user/client-base'+q)<0)p.push('saves.ts not wired');const svx=fs.readFileSync('packages-user/client-modules/src/render/ui/save.tsx','utf8');const cbs=svx.split(/\r?\n/).filter(l=>l.indexOf('from '+q+'@user/client-base'+q)>=0).join(' ');if(!(cbs.indexOf('adjustGrid')>=0&&cbs.indexOf('IGridLayoutData')>=0))p.push('save.tsx not wired');const ti=fs.readFileSync('packages-user/client-modules/src/render/ui/title.tsx','utf8').split(/\r?\n/).find(l=>l.indexOf('adjustCover')>=0&&l.indexOf('import')>=0)||'';if(ti.indexOf(q+'@user/client-base'+q)<0)p.push('title.tsx not wired');if(p.length>0){console.error('CLOSURE SELF-CHECK FAILED :: '+p.join(' ; '));process.exit(1)}console.log('OK F1..F4 closure self-check')"
+ non-zero exit, 或 stderr 含 "CLOSURE SELF-CHECK FAILED"(F1..F4 任一未落地:`shared.ts` 缺失 / `shared/` 目录仍在 / 两处标注未删 / 两处桶转发仍在 / 三处消费者未直连)
+ node -e "const{execSync}=require('child_process');const bad=[];const o1=execSync('git status --porcelain -- packages-user/client-base/src/material packages-user/client-base/src/load packages packages/ src',{encoding:'utf8'}).replace(/\s+$/,'');if(o1.length>0)bad.push('FORBIDDEN PATH TOUCHED :: '+o1);const req=execSync('git status --porcelain -- .planning/REQUIREMENTS.md',{encoding:'utf8'}).replace(/\s+$/,'');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(/\s+$/,'');if(ctx.length===0)bad.push('USER CONTEXT EDIT MISSING (must be preserved)');const rix=execSync('git status --porcelain -- packages-user/client-modules/src/render/index.tsx',{encoding:'utf8'}).replace(/\s+$/,'');if(rix.length===0)bad.push('USER render/index.tsx EDIT MISSING (must be preserved)');if(bad.length>0){console.error('SCOPE GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK scope: forbidden paths clean; user edits (CONTEXT + render/index.tsx) preserved')"
+ non-zero exit, 或 stderr 含 "SCOPE GATE FAILED" / "FORBIDDEN PATH TOUCHED" / "REQUIREMENTS.md TOUCHED" / "USER CONTEXT EDIT MISSING" / "USER render/index.tsx EDIT MISSING"(禁用路径被改、`REQUIREMENTS.md` 被改、或用户的并发未提交改动被回滚 / 提交 —— D-42 / D-48 / D-33 / D-56 边界被破)
+ node -e "const fs=require('fs');const files=['packages-user/client-base/src/shared.ts','packages-user/client-modules/src/render/utils/index.ts','packages-user/client-modules/src/render/utils/saves.ts','packages-user/client-modules/src/render/ui/save.tsx','packages-user/client-modules/src/render/ui/title.tsx'];const bad=[];for(const f of files){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(f+' ('+(lf-crlf)+' stray LF)')}if(bad.length>0){console.error('NON-CRLF '+bad.join(' ; '));process.exit(1)}console.log('OK CRLF '+files.length+' changed production files')"
+ non-zero exit, 或 stderr 含 "NON-CRLF"(本计划触及的生产文件出现非 CRLF 换行)
+ node -e "const fs=require('fs');const f='.planning/phases/04-render-adaptation/04-12-SUMMARY.md';if(!fs.existsSync(f)){console.error('SUMMARY MISSING');process.exit(1)}const t=fs.readFileSync(f,'utf8');const need=['04-12','D-69','D-70','F1','F4','Self-Check'];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-12-SUMMARY.md present and keyed')"
+ non-zero exit, 或 stderr 含 "SUMMARY MISSING" / "SUMMARY INCOMPLETE"(`04-12-SUMMARY.md` 未写或缺少关键章节 / 标识)
+
+
+ - **桶边界门禁**:8 个 in-scope barrel 内每一条 `export * from` 的说明符都以 `./` 开头;`render/utils/index.ts` 不再转发 `./layout`
+ - **F5 门禁**:8 处「引用 `render/use.ts` / `render/renderer`」的架构耦合标注逐字在场、均带非空原因(这 7 个文件 `@ts-expect-error` 总数 9,含 `textboxTyper.ts` 的 1 处既有 `无法推导`)、对应文件 `git status --porcelain` 零命中
+ - **收口自检**:`client-base/src/shared.ts` 在场且 `shared/` 目录不存在;`render/utils/{index,saves}.ts` 零 `@ts-expect-error`;`render/utils/saves.ts` 的 `getConfirm` / `render/ui/save.tsx` 的 `adjustGrid` / `IGridLayoutData` / `render/ui/title.tsx` 的 `adjustCover` 均自 `@user/client-base`
+ - **范围门禁**:`material/` / `load/` / `packages/` / `src/` porcelain 为空;`.planning/REQUIREMENTS.md` 零改动;`04-CONTEXT.md` 与 `render/index.tsx` 的既有未提交改动仍在;本计划改动面之外零漂移
+ - **CRLF**:本计划触及的 5 个生产文件全部 CRLF
+ - `04-12-SUMMARY.md` 已写(含只读起始基线 / F1..F6 落点表 / 门禁实测 / 人工复核结论 / 无运行时验证声明 / Self-Check)
+ - 已按白名单完成单次提交(只含 `files_modified` / `files_deleted` 条目 + `04-12-SUMMARY.md`);未写其它 `.planning/` 文件;未派发会写文件的子代理
+
+ 收口完成:D-69 的桶边界门禁在 8 个 in-scope barrel 上转绿、F5 的 8 处架构标注逐字保留、F1..F4 全部落地的收口自检通过、范围与用户改动门禁通过、5 个生产文件 CRLF;`04-12-SUMMARY.md` 落盘;白名单单次提交完成;`REND-01` / `REND-02` 保持 Pending
+
+
+
+
+
+## Trust Boundaries
+
+| Boundary | Description |
+|----------|-------------|
+| (无新增外部边界) | 本计划是纯结构修正(barrel 说明符 + 导入来源 + 文件折叠),不引入外部输入 / 网络 / 进程边界;不新增依赖、不安装包、不执行 `pnpm i` |
+| 仓库工作树 → git 提交 | 用户的并发未提交改动(`04-CONTEXT.md`、`render/index.tsx`)与本次改动共处同一工作树;若暂存面把控不当,会把用户的改动混入本计划提交 |
+
+## STRIDE Threat Register
+
+| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
+|-----------|----------|-----------|----------|-------------|-----------------|
+| T-04-12-01 | Tampering | 提交暂存面(`git add`) | medium | mitigate | Task 4 步骤 (8) 明示只暂存 `files_modified` / `files_deleted` 条目;Task 4 的 `` 断言 `04-CONTEXT.md` 与 `render/index.tsx` 的未提交改动仍在(未被提交 / 回滚);prohibitions 明列 |
+| T-04-12-02 | Tampering | 分层边界(barrel 转发 / 反向依赖) | medium | mitigate | Task 4 的桶边界门禁对 8 个 in-scope barrel 逐条断言 `export * from` 说明符为 `./` 前缀;prohibitions 明禁任何越界 / 转发导出 |
+| T-04-12-03 | Tampering | D-70 第 5 条的 8 处架构标注 | low | mitigate | Task 4 的 F5 门禁断言 8 处逐字在场(均带原因)+ 对应文件 porcelain 零命中;prohibitions 明禁新增 / 删除 / 改写标注(除授权的 2 处删除) |
+| T-04-12-04 | Tampering | 已移内容的唯一性(`shared.ts`) | low | mitigate | Task 1 门禁断言 `client-base/src/shared.ts` 与 `git show HEAD:...shared/shared.ts` 逐字一致、且 `shared/` 目录不存在,防止留下两套真相 |
+| T-04-12-SC | Tampering | npm/pip/cargo 安装 | low | accept | 本计划无任何依赖新增 / 变更、不执行 `pnpm i`、不触及任何 `package.json`,故无供应链安装面;`T-04-12-SC` 保留为「本 run 不适用」的显式登记 |
+
+
+
+**Static-only(D-68 的延续:不设 `check:type` / `build` / TS 诊断数类门禁)**
+
+- [ ] Task 1 门禁:`client-base/src/shared.ts` 在场且逐字一致 + `shared/shared.ts` / `shared/index.ts` 已删 + `shared/` 目录不存在 + `client-base/src/index.ts` 与 `map/*` 的 5 个说明符一字未改 + `material/` / `load/` / `packages/` / `src/` porcelain 为空 + CRLF
+- [ ] Task 2 门禁:`render/utils/index.ts` 无 `@ts-expect-error`、无 `./layout` 转发、`./saves` / `./use` 仍在;`render/utils/saves.ts` 无 `@ts-expect-error`、`getConfirm` / `waitbox` 自 `@user/client-base`、无 `../components`、调用点不变;`render/utils/use.ts` 未动;CRLF
+- [ ] Task 3 门禁:`render/ui/save.tsx` 拆分正确(`adjustGrid` / `IGridLayoutData` → `@user/client-base`;`getSave` / `SaveData` → `../utils`)且无 `import type`;`render/ui/title.tsx` 的 `adjustCover` → `@user/client-base`、无 `../utils` 残留;`render/ui` 无范围外文件改动;CRLF
+- [ ] Task 4 门禁:8 个 in-scope barrel 的 `export * from` 全为 `./` 前缀;F5 的 8 处标注逐字在场 + 文件 porcelain 零命中;F1..F4 收口自检通过;范围与用户改动门禁通过;5 个生产文件 CRLF;`04-12-SUMMARY.md` 落盘
+- [ ] 人工代码复核结论写入 SUMMARY
+- [ ] 单次白名单提交只含本计划条目
+
+
+
+- **D-69 完全成立**:8 个 in-scope barrel 内零越界 / 转发 `export * from`;`render/utils/index.ts` 不再转发 `./layout`;`render/index.tsx` 维持现状
+- **D-70 六条全部落地**:F1(桶去转发 + 删标注)/ F2 + F2'(两 `render/ui` 消费者直连)/ F3(`saves.ts` 直连 + 删标注)/ F4(`shared` 单文件化)/ F5(8 处标注逐字保留)/ F6(零新增转发)
+- **范围零外溢**:`material/` / `load/` / `packages/` / `src/` / 其它 `package.json` / 测试文件 / legacy 面全部零触碰;用户的并发改动被保留且未被提交
+- **命名零变更**:不引入任何新公共 / 受保护 / 私有命名;`@user/client-base` 的公共导出面不增不减
+- **无运行时要求**:全部证明为静态门禁 + 人工复核;`REND-01` / `REND-02` 保持 Pending,`.planning/REQUIREMENTS.md` 零改动
+
+
+## Artifacts this phase produces
+
+| Artifact | Kind | Purpose |
+|---|---|---|
+| `packages-user/client-base/src/shared.ts` | 新增(折叠单文件) | D-70 第 4 条:由 `shared/shared.ts` 逐字折成;`client-base/src/index.ts` 的 `./shared` 与 `map/*` 的 4 处相对说明符无需改动即可解析到它 |
+| `packages-user/client-base/src/shared/{shared.ts,index.ts}` | 删除 | 折叠后不留两套真相;目录一并移除 |
+| `packages-user/client-modules/src/render/utils/index.ts` | 修改(D-69 合规) | D-70 第 1 条:去掉指向 `./layout` 的越界转发与其 `@ts-expect-error`;仅剩 `./saves` / `./use` |
+| `packages-user/client-modules/src/render/utils/saves.ts` | 修改(直连) | D-70 第 3 条:`getConfirm` / `waitbox` 自 `@user/client-base`;断链标注删除 |
+| `packages-user/client-modules/src/render/ui/save.tsx` | 修改(直连) | D-70 第 2 条:`../utils` 拆分;`adjustGrid` / `IGridLayoutData` 自 `@user/client-base` |
+| `packages-user/client-modules/src/render/ui/title.tsx` | 修改(直连) | D-70 第 2 条:`adjustCover` 自 `@user/client-base` |
+| `.planning/phases/04-render-adaptation/04-12-SUMMARY.md` | 新增(文档) | 落地记录 + 门禁实测 + 人工复核 + 无运行时验证声明 |
+| `.planning/ROADMAP.md`(Wave 11 + register note) | 修改(计划阶段完成) | `04-12` 的增量登记 |
+| 未改动(显式保留) | — | `client-base/src/index.ts`、`client-base/src/{components,elements,map,layout}/**`(含 8 处 D-70.5 标注)、`client-modules/src/render/index.tsx`、`render/utils/use.ts`、`render/{renderer.ts,use.ts}`、`client-base/src/{material,load}/**`、`packages/**`、`src/**` |
+
+
+
diff --git a/.planning/state.json b/.planning/state.json
index 7aaba9a..318c5a8 100644
--- a/.planning/state.json
+++ b/.planning/state.json
@@ -44,5 +44,5 @@
"label": "Advance to the next step",
"reason": "Phase 04 of 7 · executing"
},
- "updated_at": "2026-09-24T08:33:34.410Z"
+ "updated_at": "2026-09-24T10:35:43.701Z"
}