docs(09-14): rescope plan per user decision (A-6 DEFERRED; GameStorage/SaveSystem only)

This commit is contained in:
unanmed 2026-10-12 16:38:55 +08:00
parent 2d99b090e3
commit 529bb5578d

View File

@ -6,66 +6,57 @@ wave: 11
depends_on: [09-13]
files_modified:
- packages-user/client-modules/src/action/hotkey.ts
- packages-user/client-base/src/elements/cache.ts
- packages-user/client-base/src/elements/misc.ts
- .planning/phases/09-minimum-browser-runnable/09-14-SUMMARY.md
autonomous: false
requirements: []
estimate:
tokens: 30000
raw_tokens: 34000
tasks: 3
tokens: 20000
raw_tokens: 22000
tasks: 2
confidence: low
must_haves:
truths:
- "**本计划的第一个 block 点是 Task 0 的 `blocking-human` 汇报关卡(AGENTS.md 硬要求,D-03)**:Task 0 必须先汇报「本计划 = 任务 7 · 第一批改造(ALT)· 4 个计划中的第 2 个(跨包 legacy 依赖:GameStorage / Mota.require / 全局 core 收口)」的要做什么 / 为什么 / 大致怎么做 / 影响范围,**必须列明:逐条 ALT 条目表(ID / 原接口成员 / 替代方案 / 涉及文件:行 / 编辑要点);逐文件影响表;两个执行日必须核实的风险点(R1:`@user/data-base` 当前未导出 `loading`,审计 A-6 替代锚点疑似失效;R2:`GameStorage` → `SaveSystem` 的实例获取路径与语义差异);命名影响;开放项 OI-1..OI-4**,然后必须**停下等待**用户明确回复「可以执行」四个字;未收到前不得执行本计划任何一步、不得派发执行子代理,且不因触发方式或 `mode: yolo` / `workflow.auto_advance` 自动放行。"
- "**D-50 / D-52(范围 / 依据):** 实现本批 ALT 之**第 2 组**(A-1-1 / A-6-1 / A-6-2 / A-6-3 / A-2-1,共 5 条)的替代改造;严格依据 `09-LEGACY-REPLACEMENT-AUDIT.md` 的替代方案与 `file:line` 锚点,**不 invent**。"
- "**本计划的第一个 block 点是 Task 0 的 `blocking-human` 汇报关卡(AGENTS.md 硬要求,D-03)**:Task 0 必须先汇报「本计划 = 任务 7 · 第一批改造(ALT)· 4 个计划中的第 2 个 —— 裁剪后范围:跨包 legacy 依赖 `GameStorage` → `SaveSystem`(A-1-1)+ A-2-1 umbrella 记录;`Mota.require` / `loading`(A-6-1/2/3)按用户决定 **DEFERRED(用户自行处理)**」的要做什么 / 为什么 / 大致怎么做 / 影响范围,**必须列明:逐条 ALT 条目表(ID / 原接口成员 / 替代方案 / 涉及文件:行 / 编辑要点);逐文件影响表;执行日必须核实的风险点(R2:`GameStorage` → `SaveSystem` 的实例获取路径与语义差异);命名影响;开放项 OI-1 / OI-3 / OI-4;以及 A-6 DEFERRED(用户自行处理 `loading`)的范围裁剪说明**,然后必须**停下等待**用户明确回复「可以执行」四个字;未收到前不得执行本计划任何一步、不得派发执行子代理,且不因触发方式或 `mode: yolo` / `workflow.auto_advance` 自动放行。"
- "**D-50 / D-52(范围 / 依据):** 实现本批 ALT 之**第 2 组剩余部分**(A-1-1 / A-2-1);`Mota.require('@user/data-base')` 三处(A-6-1 / A-6-2 / A-6-3)**按用户决定 DEFERRED,用户自行处理 `loading`**,本计划**不修改** `cache.ts` / `misc.ts`。替代严格依据 `09-LEGACY-REPLACEMENT-AUDIT.md` 的替代方案与 `file:line` 锚点,**不 invent**。"
- "**D-53(其它分类不在本批):** 不触碰 `可直接替换` / `有替代但需适配` / `无替代` / `待定`;本组只改 ALT 条目。"
- "**R1(审计锚点核实):** 规划日实测 `packages-user/data-base` 的 barrel(`src/index.ts`:`./enemy` `./flag` `./hero` `./map` `./shop` `./types`)**未导出 `loading`**;`Mota.require('@user/data-base').loading` 的 `loading`(`once('loaded'|'coreInit', …)` / `loaded` 形态)在新 data-base 中**无当前承载**。执行日必须**先核实** `loading` 的真实承载(如新加载器 `packages-user/data-state/src/loader/loader.ts` 的 `MotaDataLoader` 的 `loadedPromise` / 加载 hook);若确实无等价替代,**记录锚点失效并 STOP 请示**,不得猜测造接口。"
- "**R2(替代可行性核实):** A-1-1 审计替代为 `SaveSystem`(`save/system.ts:41`);`GameStorage` 为 localStorage 键值存储、`SaveSystem` 为 Dexie 存档 / 全局存储(语义与实例获取路径不同)。执行日必须核实 `hotkey.ts` 取得 `SaveSystem` 实例的**合规路径**(D-11:不得引入 `client` 单例);若无法合规取得,**记录并 STOP 请示**。"
- "**A-2-1(umbrella)部分收口:** 全局 `core`(`src/types/declaration/core.d.ts:1302`)的替代为 `CoreState`(`packages-user/data-state/src/core.ts:76`);本计划只收口本组 ALT 用法,**不删除 `core` 全局声明**;全量收口须待其余分类(ADAPT / NONE / TBD)完成后另行规划。**`09-14-SUMMARY.md` 必须逐条列明本计划 REPLACED(已收口)的对象与 DEFERRED(未收口 / 待其它批次)的对象**——含 `client-modules/src/core.ts:6` 的 `core` 单例定义如何处置(本计划未编辑该文件、未改其定义)——使 40 条 ALT 的整体覆盖可审计。"
- "**范围零外溢 + 静态门禁:** 只改 `files_modified`;不改既有注释 / JSDoc;不用 `import type`;源码 CRLF;验证一律静态断言(legacy 用法消失 + 替代符号出现 + CRLF + 范围 / `git status` 守卫),**不使用** `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数。"
- "**A-2-1(umbrella)部分收口:** 全局 `core`(`src/types/declaration/core.d.ts:1302`)的替代为 `CoreState`(`packages-user/data-state/src/core.ts:76`);本计划只收口本组 ALT 用法,**不删除 `core` 全局声明**;全量收口须待其余分类(ADAPT / NONE / TBD)完成后另行规划。**`09-14-SUMMARY.md` 必须逐条列明本计划 REPLACED(已收口)的对象与 DEFERRED(未收口 / 待其它批次)的对象**——含 `client-modules/src/core.ts:6` 的 `core` 单例定义如何处置(本计划未编辑该文件、未改其定义),以及 **A-6-1/2/3(`Mota.require` / `loading`)DEFERRED(用户自行处理)**——使 40 条 ALT 的整体覆盖可审计。"
- "**范围零外溢 + 静态门禁:** 只改 `files_modified`(本计划仅 `action/hotkey.ts`);不改既有注释 / JSDoc;不用 `import type`;源码 CRLF;验证一律静态断言(legacy 用法消失 + 替代符号出现 + CRLF + 范围 / `git status` 守卫),**不使用** `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数。"
artifacts:
- path: packages-user/client-base/src/elements/cache.ts
provides: "`createCache()` 的 `Mota.require('@user/data-base')` 改为静态模块导入(`loading` 承载按执行日核实)。"
- path: packages-user/client-base/src/elements/misc.ts
provides: "两处 `Mota.require('@user/data-base')` 改为静态模块导入(`loading` 承载按执行日核实)。"
- path: packages-user/client-modules/src/action/hotkey.ts
provides: "`GameStorage` 用法替换为 `SaveSystem` 全局存储(实例路径按执行日核实)。"
provides: "`GameStorage` 用法替换为 `SaveSystem` 全局存储(实例路径按执行日核实,R2)。"
- path: .planning/phases/09-minimum-browser-runnable/09-14-SUMMARY.md
provides: "本计划执行摘要:本组 ALT 条目、逐文件改动、R1/R2 核实结论、**A-2-1 收口覆盖(REPLACED vs DEFERRED 逐条,含 `core.ts:6` 单例定义处置)**、命名影响、门禁结果。"
provides: "本计划执行摘要:本组 ALT 条目(A-1-1 / A-2-1)、逐文件改动、R2 核实结论、**A-2-1 收口覆盖(REPLACED vs DEFERRED 逐条,含 `core.ts:6` 单例定义处置与 A-6-1/2/3 DEFERRED 用户自行处理)**、命名影响、门禁结果。"
key_links:
- "`packages-user/client-base/src/elements/cache.ts:491` / `misc.ts:89,219`(`Mota.require('@user/data-base')`)↔ `packages-user/data-base/src/index.ts:1`(静态导入)—— A-6-1/2/3"
- "`packages-user/data-base/src/index.ts`(未导出 `loading`)↔ `packages-user/data-state/src/loader/loader.ts`(`MotaDataLoader` 加载信号)—— R1 核实点"
- "`packages-user/client-modules/src/action/hotkey.ts:3,518-522`(`GameStorage`)↔ `packages-user/client-base/src/save/system.ts:41`(`SaveSystem` 全局存储)—— A-1-1"
- "`src/types/declaration/core.d.ts:1302`(全局 `core`)↔ `packages-user/data-state/src/core.ts:76`(`CoreState`)—— A-2-1"
assumptions:
- "**执行日行号可能漂移**:引用行号为 2026-10-11 规划日实测;门禁以执行日实测为准。"
- "**R1 为规划日已发现的风险**:`@user/data-base` 未导出 `loading`(规划日 grep 全仓确认);审计 A-6 替代锚点疑似失效,执行日须核实并按真实代码调整,必要时 STOP。"
- "**A-6 已由用户决定 DEFERRED(用户自行处理 `loading`)**:本计划不修改 `cache.ts` / `misc.ts`,亦不核实 / 改写 `Mota.require('@user/data-base')`;`loading` 承载由用户自行处置。"
- "**用户并发改动(D-56)**:执行期存在用户 `packages-user/data-state/**` 并发改动;`git status` 守卫豁免这些既有改动。"
- "**Markdown 使用 LF,源码使用 CRLF**。"
prohibitions:
- "不得在用户明确回复「可以执行」四个字之前执行本计划任何一步、或派发任何执行子代理。"
- "**不得 invent 替代 / 不得猜测 `loading` 承载**:若 `loading` 无当前等价替代,记录锚点失效并 STOP,不得造出未存在的符号。"
- "**不得触碰 A-6(DEFERRED)**:本计划**不得**修改 `packages-user/client-base/src/elements/cache.ts` / `misc.ts`,不得处理 `Mota.require('@user/data-base')` / `loading`(用户自行处理)。"
- "**不得 invent 替代**:替代只取自审计;无等价替代时记录并 STOP,不得造出未存在的符号。"
- "**不得引入 `client` 单例**;不得为取得实例而新增未批准命名(D-04)。"
- "不得触碰非 ALT 分类用法;不得改 09-01..09-13 任何文件;不得改既有注释 / JSDoc;不得用 `import type`;不得新增 `?.`(dev.md 允许场景除外)。"
- "不得把门禁建立在「全仓 TS 诊断数」「`pnpm check:type`」「`pnpm build`」之上;不得为「验证」改动源码。"
open_items:
- "**OI-1(批次拆分):** 本计划为任务 7 批次 4 计划中的第 2 个;**待用户确认**(可合并 / 重排)。"
- "**OI-2(A-6 锚点失效,R1):** `@user/data-base` 未导出 `loading`;审计 A-6 替代锚点疑似失效。处置选项:(a) 执行日核实到真实承载(新加载器)后按真实的写;(b) 若无可替代,记录失效并**先补设计**。**待用户裁定。**"
- "**OI-2(A-6 已 DEFERRED):** `Mota.require('@user/data-base')` / `loading`(A-6-1/2/3)**按用户决定 DEFERRED,用户自行处理**;本计划不核实、不改写、不记录锚点失效结论,仅在本计划范围 / 覆盖审计中标注为 DEFERRED。"
- "**OI-3(A-1-1 实例路径,R2):** `hotkey.ts` 为模块级(非组件),取得 `SaveSystem` 实例的合规路径未定(D-11 禁 `client` 单例)。**待用户裁定接入口径**;若无法合规取得则本条目暂缓。"
- "**OI-4(命名影响):** 预期不新增公共命名;若执行日不可避免需新增,须呈报批准。**待用户确认。**"
---
<objective>
Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组** —— **跨包 legacy 依赖:`GameStorage` / `Mota.require` / 全局 `core` 收口**(5 条 ALT)。
Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组**(裁剪后范围)—— **跨包 legacy 依赖:`GameStorage` 收口 + 全局 `core` umbrella 部分收口**。
**要解决的问题(D-50..D-53):** 本组处理 `client-base` / `client-modules` 中跨包 legacy 依赖:① `@motajs/legacy-system` 的 `GameStorage`(`hotkey.ts` 热键配置持久化);② 三处 `Mota.require('@user/data-base')`(`cache.ts` / `misc.ts`);③ 全局 `core` 的 ALT 用法收口(umbrella)。
**要解决的问题(D-50..D-53):** 本组处理 `client-modules` 中跨包 legacy 依赖:`@motajs/legacy-system` 的 `GameStorage`(`hotkey.ts` 热键配置持久化);以及全局 `core` 的 ALT 用法收口(umbrella)。**注:原第 2 组中的 `Mota.require('@user/data-base')` 三处(A-6-1/2/3)已由用户决定 DEFERRED(用户自行处理 `loading`),不在本计划范围。**
**大致解决方案(本计划 = 09-14):**
- **Task 0(`blocking-human`)= 预执行汇报关卡**:汇报本组范围、逐条 ALT 表、逐文件影响表、**R1(A-6 锚点失效风险)** 与 **R2(`SaveSystem` 实例路径风险)**、命名影响、OI-1..OI-4,等待「可以执行」。
- **Task 1 = `Mota.require` → 静态导入(A-6-1/2/3)**:改 `cache.ts` / `misc.ts` 为顶部静态导入;执行日核实 `loading` 承载(R1);无替代则 STOP。
- **Task 2 = `GameStorage` → `SaveSystem`(A-1-1)+ A-2-1 umbrella 记录**:`hotkey.ts` 热键配置持久化改用新存档 / 全局存储;执行日核实实例路径(R2);无法合规取得则 STOP;A-2-1 作为 umbrella 在 SUMMARY 记录部分收口。
- **Task 0(`blocking-human`)= 预执行汇报关卡**:汇报本组裁剪后范围、逐条 ALT 表(A-1-1 / A-2-1)、逐文件影响表、**R2(`SaveSystem` 实例路径风险)**、命名影响、OI-1 / OI-3 / OI-4、A-6 DEFERRED 说明,等待「可以执行」。
- **Task 1 = `GameStorage` → `SaveSystem`(A-1-1)+ A-2-1 umbrella 记录**:`hotkey.ts` 热键配置持久化改用新存档 / 全局存储;执行日核实实例路径(R2);无法合规取得则 STOP;A-2-1 作为 umbrella 在 SUMMARY 记录部分收口。
**API coverage:** `detected:false`。**`No external API integration: 本计划仅为源码改造,不涉及任何外部 API。`**
</objective>
@ -85,141 +76,96 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
@dev.md
</context>
## ALT 条目清单与影响表(本组 5 条)
## ALT 条目清单与影响表(本组裁剪后 2 条;原第 2 组 5 条,A-6-1/2/3 已 DEFERRED)
| ID | 原接口/成员(锚点) | 替代方案(锚点) | 涉及文件:行 | 编辑要点 |
| --- | --- | --- | --- | --- |
| A-6-1 | `Mota.require('@user/data-base')`(cache.ts:491) | 直接 ESM 导入(data-base/index.ts:1) | client-base/src/elements/cache.ts:491 | 改顶部静态导入;核实 `loading` 承载(R1) |
| A-6-2 | `Mota.require('@user/data-base')`(misc.ts:89) | 直接 ESM 导入 | client-base/src/elements/misc.ts:89 | 改顶部静态导入;核实 `loading` 承载(R1) |
| A-6-3 | `Mota.require('@user/data-base')`(misc.ts:219) | 直接 ESM 导入 | client-base/src/elements/misc.ts:219 | 改顶部静态导入;核实 `loading` 承载(R1) |
| A-1-1 | `GameStorage`(hotkey.ts:3) | `SaveSystem`(save/system.ts:41) | client-modules/src/action/hotkey.ts:3,518-522 | 热键配置持久化改新存档 / 全局存储;核实实例路径(R2) |
| A-2-1 | 全局 `core`(core.d.ts:1302) | `CoreState`(data-state/core.ts:76) | client-modules/src/core.ts:6(umbrella) | 只收口本组 ALT 用法;不删 `core` 全局声明 |
## 逐文件影响表(本组)
> **DEFERRED(用户自行处理):** A-6-1(cache.ts:491)/ A-6-2(misc.ts:89)/ A-6-3(misc.ts:219)—— `Mota.require('@user/data-base')` → 静态导入(`loading` 承载)。**用户决定本计划不改**,由用户自行处理;本计划不修改 `cache.ts` / `misc.ts`。
## 逐文件影响表(本组裁剪后)
| 文件 | 动作 | 改动内容 | 关联 ALT |
| --- | --- | --- | --- |
| `packages-user/client-base/src/elements/cache.ts` | 修改 | `createCache()` 内 `Mota.require('@user/data-base')` → 顶部静态导入 | A-6-1 |
| `packages-user/client-base/src/elements/misc.ts` | 修改 | 两处 `Mota.require('@user/data-base')` → 顶部静态导入 | A-6-2 / A-6-3 |
| `packages-user/client-modules/src/action/hotkey.ts` | 修改 | `GameStorage` → 新存档 / 全局存储(`SaveSystem`) | A-1-1 |
<tasks>
<task type="checkpoint:decision" gate="blocking-human">
<name>Task 0: 预执行汇报关卡 —— 汇报「任务 7 · 第一批改造(ALT)· 第 2 组:跨包 legacy 依赖」的范围、逐条 ALT 表、逐文件影响表、R1/R2 风险与 OI,等待用户回复「可以执行」</name>
<precondition>`packages-user/client-base/src/elements/{cache,misc}.ts` 与 `packages-user/client-modules/src/action/hotkey.ts` 存在;`packages-user/data-base/src/index.ts` 存在;审计文档 `09-LEGACY-REPLACEMENT-AUDIT.md` 已存在。</precondition>
<name>Task 0: 预执行汇报关卡 —— 汇报「任务 7 · 第一批改造(ALT)· 第 2 组(裁剪后):跨包 legacy 依赖 `GameStorage` → `SaveSystem` + A-2-1 umbrella」的范围、逐条 ALT 表、逐文件影响表、R2 风险、A-6 DEFERRED 说明与 OI,等待用户回复「可以执行」</name>
<precondition>`packages-user/client-modules/src/action/hotkey.ts` 存在;`packages-user/client-base/src/save/system.ts` 存在;审计文档 `09-LEGACY-REPLACEMENT-AUDIT.md` 已存在。</precondition>
<files>(只读汇报,不修改任何文件)</files>
<read_first>
- .planning/phases/09-minimum-browser-runnable/09-CONTEXT.md(D-03 / D-04 / **D-50 / D-52 / D-53**)
- .planning/phases/09-minimum-browser-runnable/09-LEGACY-REPLACEMENT-AUDIT.md(A-1-1 / A-6-* / A-2-1)
- .planning/phases/09-minimum-browser-runnable/09-14-PLAN.md(本计划全文,含「ALT 条目清单与影响表」「逐文件影响表」与 R1/R2)
- packages-user/data-base/src/index.ts(核实 `loading` 是否导出,R1)
- .planning/phases/09-minimum-browser-runnable/09-LEGACY-REPLACEMENT-AUDIT.md(A-1-1 / A-2-1;A-6-* 仅作 DEFERRED 标注)
- .planning/phases/09-minimum-browser-runnable/09-14-PLAN.md(本计划全文,含「ALT 条目清单与影响表」「逐文件影响表」与 R2)
- packages-user/client-base/src/save/system.ts(`SaveSystem` 全局存储 `getGlobal` / `setGlobal`,R2)
- AGENTS.md(执行前须获批、命名须先反馈、问题须先确认);dev.md(命名、注释、依赖单向、CRLF)
</read_first>
<action>
**停下并向用户汇报,等待明确回复「可以执行」后才继续;汇报本身只读。**
① **要解决的问题:** 任务 7 · 第一批改造(ALT)第 2 组:`client-base` / `client-modules` 中跨包 legacy 依赖(`GameStorage` / `Mota.require` / 全局 `core` 收口),共 5 条。
① **要解决的问题:** 任务 7 · 第一批改造(ALT)第 2 组(裁剪后):`client-modules` 中跨包 legacy 依赖 `GameStorage`(`hotkey.ts` 热键配置持久化),以及全局 `core` 的 ALT 用法 umbrella 部分收口,共 2 条。**原第 2 组的 A-6(`Mota.require('@user/data-base')` / `loading`,三处)已按用户决定 DEFERRED(用户自行处理),不在本计划范围。**
② **逐条 ALT 条目表:** 原样呈现本计划「ALT 条目清单与影响表」的 5 行。
② **逐条 ALT 条目表:** 原样呈现本计划「ALT 条目清单与影响表」的 2 行(A-1-1 / A-2-1),并说明 A-6-1/2/3 的 DEFERRED 处置。
③ **逐文件影响表:** 原样呈现本计划「逐文件影响表」的 3 行,并说明 `files_modified` 精确为 3 个源文件。
③ **逐文件影响表:** 原样呈现本计划「逐文件影响表」的 1 行,并说明 `files_modified` 精确为 1 个源文件(`client-modules/src/action/hotkey.ts`)。
④ **R1(A-6 锚点疑似失效,须用户知悉):** 规划日实测 `packages-user/data-base` 的 barrel **未导出 `loading`**;`Mota.require('@user/data-base').loading` 所依赖的 `loading`(`once('loaded'|'coreInit', …)` / `loaded`)在新 data-base 中无当前承载。执行日先核实真实承载(如新加载器 `packages-user/data-state/src/loader/loader.ts` 的 `MotaDataLoader`);**若无等价替代,记录锚点失效并 STOP 请示**,不猜测。**OI-2。**
④ **A-6 DEFERRED(范围裁剪,须用户知悉):** `Mota.require('@user/data-base')` 三处(A-6-1 cache.ts:491 / A-6-2 misc.ts:89 / A-6-3 misc.ts:219)及其 `loading` 承载**按用户决定 DEFERRED,用户自行处理**;本计划**不修改** `cache.ts` / `misc.ts`,不核实 / 不改写 `loading`。
⑤ **R2(A-1-1 实例路径,须用户知悉):** `hotkey.ts` 为模块级,替代 `SaveSystem` 需要实例;`GameStorage`(localStorage 键值)与 `SaveSystem`(Dexie 存档 / 全局存储)语义不同。执行日核实合规取得路径(D-11 禁 `client` 单例);无法合规取得则记录并 STOP。**OI-3。**
⑥ **A-2-1(umbrella):** 全局 `core` → `CoreState`;本计划只收口本组 ALT 用法,**不删 `core` 全局声明**;全量收口待其它分类批次。
⑦ **编辑策略:** Task 1 改 `cache.ts` / `misc.ts` 的 `Mota.require` 为顶部静态导入(A-6-1/2/3);Task 2 改 `hotkey.ts` 的 `GameStorage`(A-1-1)+ 记录 A-2-1 umbrella。
⑦ **编辑策略:** 本计划只有 Task 1——改 `hotkey.ts` 的 `GameStorage`(A-1-1)+ 记录 A-2-1 umbrella。**本计划无 A-6 编辑任务。**
⑧ **范围与禁止:** 只改 ALT 条目相关用法;不触碰其它分类;不改 09-01..09-13;不改既有注释;不用 `import type`;不引入 `client` 单例;源码 CRLF。
⑧ **范围与禁止:** 只改 ALT 条目相关用法;不触碰其它分类;不改 09-01..09-13;不改既有注释;不用 `import type`;不引入 `client` 单例;源码 CRLF;**不触碰 A-6(`cache.ts` / `misc.ts`)**。
⑨ **验证方式:** 静态断言——`cache.ts` / `misc.ts` 无 `Mota.require('@user/data-base')` 且出现静态 `import`;`hotkey.ts` 无 `GameStorage` 且出现替代符号;CRLF;范围 / `git status` 守卫。**不设全仓类型 / 构建门禁。** 若 R1/R2 触发 STOP,则相应条目标记为「待裁定」,门禁对未改文件不作强制。
⑨ **验证方式:** 静态断言——`hotkey.ts` 无 `GameStorage` / `@motajs/legacy-system` 且出现替代符号;CRLF;范围 / `git status` 守卫。**不设全仓类型 / 构建门禁。** 若 R2 触发 STOP,则相应条目标记为「待裁定」,门禁对未改文件不作强制。
⑩ **开放项:** OI-1(批次拆分)、OI-2(A-6 锚点失效)、OI-3(A-1-1 实例路径)、OI-4(命名影响)。**无论触发方式或 `mode: yolo` / `workflow.auto_advance`,执行者 / 子代理必须停下等待用户明确回复「可以执行」四个字**;回复其它内容视为未通过。
⑩ **开放项:** OI-1(批次拆分)、OI-2(A-6 DEFERRED,用户自行处理)、OI-3(A-1-1 实例路径 / R2)、OI-4(命名影响)。**无论触发方式或 `mode: yolo` / `workflow.auto_advance`,执行者 / 子代理必须停下等待用户明确回复「可以执行」四个字**;回复其它内容视为未通过。
</action>
<decision>是否按本计划(09-14)执行任务 7 · 第一批改造 · 第 2 组:跨包 legacy 依赖替换(`Mota.require` → 静态导入、`GameStorage` → `SaveSystem`、A-2-1 部分收口),并在 R1/R2 无法满足时按 STOP 处置</decision>
<decision>是否按本计划(09-14,裁剪后范围)执行任务 7 · 第一批改造 · 第 2 组:跨包 legacy 依赖替换(`GameStorage` → `SaveSystem`、A-2-1 部分收口),并在 R2 无法满足时按 STOP 处置;A-6(`Mota.require` / `loading`)保持 DEFERRED(用户自行处理)</decision>
<context>
AGENTS.md / D-03 / D-04 要求执行前与命名先获批;`.planning/config.json` 为 `mode: yolo`,故本关卡显式 `blocking-human` 且 `autonomous: false`。本次核心 = ALT 范围确认 + R1(A-6 锚点失效)+ R2(A-1-1 实例路径)+ 命名影响确认。行号与 `loading` 导出现状为规划日实测,以执行日为准。
AGENTS.md / D-03 / D-04 要求执行前与命名先获批;`.planning/config.json` 为 `mode: yolo`,故本关卡显式 `blocking-human` 且 `autonomous: false`。本次核心 = 裁剪后 ALT 范围确认(A-1-1 / A-2-1;A-6 DEFERRED)+ R2(A-1-1 实例路径)+ 命名影响确认。行号为规划日实测,以执行日为准。
</context>
<options>
<option id="execute-default">
<name>可以执行(采纳全部默认处置;R1/R2 触发时按 STOP 处置)</name>
<pros>如实落实可替代部分;对疑似失效锚点不猜测;保留全部 ALT 追踪</pros>
<cons>若 R1/R2 成立,A-6 / A-1-1 可能暂缓,本组部分条目延后</cons>
<name>可以执行(采纳全部默认处置;R2 触发时按 STOP 处置)</name>
<pros>如实落实可替代部分;对疑似失效锚点不猜测;保留全部 ALT 追踪;A-6 保持 DEFERRED(用户自行处理)</pros>
<cons>若 R2 成立,A-1-1 可能暂缓,本组部分条目延后</cons>
</option>
<option id="execute-defer">
<name>可以执行 + 先将 A-6 / A-1-1 标记为「待裁定」,仅执行可确定部分</name>
<name>可以执行 + 先将 A-1-1 标记为「待裁定」,仅执行可确定部分</name>
<pros>避免中途 STOP</pros>
<cons>本组实际改动减少</cons>
</option>
<option id="revise">
<name>修订分组范围 / R1/R2 处置后重新汇报</name>
<name>修订分组范围 / R2 处置后重新汇报</name>
<pros>避免带着未定锚点改造</pros>
<cons>须修订 PLAN.md 后重新汇报</cons>
</option>
</options>
<resume-signal>回复「可以执行」四个字(如需指定 R1/R2 的处置或调整 OI,请在回复中指明)</resume-signal>
<resume-signal>回复「可以执行」四个字(如需指定 R2 的处置或调整 OI,请在回复中指明)</resume-signal>
<verify>
<automated>node -e "const fs=require('fs');const bad=[];for(const p of ['packages-user/client-base/src/elements/cache.ts','packages-user/client-base/src/elements/misc.ts','packages-user/client-modules/src/action/hotkey.ts','packages-user/data-base/src/index.ts']){if(!fs.existsSync(p))bad.push('missing: '+p)}const audit='.planning/phases/09-minimum-browser-runnable/09-LEGACY-REPLACEMENT-AUDIT.md';if(!fs.existsSync(audit))bad.push('missing audit');if(bad.length){console.error('PRESTATE FAILED :: '+bad.join(' ; '));process.exit(1)}const db=fs.readFileSync('packages-user/data-base/src/index.ts','utf8');console.log('OK prestate intact; data-base barrel exports loading? '+(/loading/.test(db)?'YES':'NO (R1 confirmed: audit anchor likely stale)'))"</automated>
<automated>node -e "const fs=require('fs');const bad=[];for(const p of ['packages-user/client-modules/src/action/hotkey.ts','packages-user/client-base/src/save/system.ts']){if(!fs.existsSync(p))bad.push('missing: '+p)}const audit='.planning/phases/09-minimum-browser-runnable/09-LEGACY-REPLACEMENT-AUDIT.md';if(!fs.existsSync(audit))bad.push('missing audit');if(bad.length){console.error('PRESTATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK prestate intact (hotkey.ts + save/system.ts + audit)')"</automated>
<fails_when>non-zero exit, 或 stderr 含 "PRESTATE FAILED"(输入文件或审计文档缺失)</fails_when>
<human-check>用户在对话中明确回复「可以执行」四个字(人工核对回复原文;用户若指定 R1/R2 的处置,须在汇报与后续任务中据其指定执行)</human-check>
<human-check>用户在对话中明确回复「可以执行」四个字(人工核对回复原文;用户若指定 R2 的处置,须在汇报与后续任务中据其指定执行)</human-check>
</verify>
<acceptance_criteria>
- 用户回复中明确包含「可以执行」四个字
- 汇报内容涵盖:D-50 / D-52 / D-53、本组 5 条 ALT 条目表、逐文件影响表、R1(A-6 锚点失效)、R2(A-1-1 实例路径)、编辑策略、命名影响、OI-1..OI-4
- 汇报中已原样告知:不猜 `loading` 承载、不引入 `client` 单例、只改 ALT、CRLF 与范围零外溢
- 汇报内容涵盖:D-50 / D-52 / D-53、本组裁剪后 2 条 ALT 条目表(A-1-1 / A-2-1)、逐文件影响表、R2(A-1-1 实例路径)、A-6-1/2/3 DEFERRED(用户自行处理)、编辑策略、命名影响、OI-1 / OI-2 / OI-3 / OI-4
- 汇报中已原样告知:不触碰 A-6(`cache.ts` / `misc.ts`)、不 invent 替代、不引入 `client` 单例、只改 ALT、CRLF 与范围零外溢
- 汇报中已原样告知**关卡性质**(必须停下等待,不因触发方式或 `yolo` / `auto_advance` 自动放行)
</acceptance_criteria>
<done>用户明确回复「可以执行」;在此之前未执行任何任务、未修改任何文件、未派发任何执行子代理</done>
</task>
<task type="auto">
<name>Task 1: 将 `Mota.require('@user/data-base')` 改为静态导入(A-6-1 / A-6-2 / A-6-3),并核实 `loading` 承载(R1)</name>
<precondition>Task 0 已闭环:用户明确回复「可以执行」四个字(若用户就 R1 / OI 另有指定,按指定执行)。</precondition>
<files>packages-user/client-base/src/elements/cache.ts, packages-user/client-base/src/elements/misc.ts</files>
<read_first>
- packages-user/client-base/src/elements/cache.ts:485-505(`createCache()` 中 `Mota.require('@user/data-base')` 的用法)
- packages-user/client-base/src/elements/misc.ts:80-100 与 214-232(两处 `Mota.require('@user/data-base')`)
- packages-user/data-base/src/index.ts(核实 `loading` 是否导出,R1)
- packages-user/data-state/src/loader/loader.ts(新加载器 `MotaDataLoader` 的加载信号,潜在的 `loading` 承载,只读参考)
- packages/legacy-ui/src/preset/ui.ts:222(legacy 中 `loading.once('coreInit', …)` 的同族用法,只读参考)
- .planning/phases/09-minimum-browser-runnable/09-CONTEXT.md(D-11 主对象经 props 获取、禁 `client` 单例)
</read_first>
<action>
(1) **核实 `loading` 承载(先于编辑,R1):** 读 `@user/data-base` barrel 与全包检索 `loading` 的导出 / 等价物。规划日实测:`@user/data-base` **未导出 `loading`**;执行日须进一步确认 `loading`(`once('loaded'|'coreInit', …)` / `loaded`)在新架构的真实承载。
- 若定位到等价替代(例如新加载器 `MotaDataLoader` 的 `loadedPromise` / 加载 hook,或某个静态可导入的信号对象),**按真实符号**改写三处用法,并在 SUMMARY 记录「审计锚点 `@user/data-base` 不精确,实为 X」。
- 若确认**无等价替代**:**记录审计锚点失效 + STOP 请示**(回到 Task 0 / 用户裁决),**不得**造出未存在的符号,也**不得**保留 `Mota.require` 视作完成。
(2) **静态导入改造(A-6-1/2/3,在 R1 满足前提下):** 将 `cache.ts`(约 491 行)与 `misc.ts`(约 89、219 行)中的 `Mota.require('@user/data-base')` 改为文件顶部标准 ESM 导入(`import { … } from '@user/data-base'`;导入位置遵循 dev.md——首行起、无注释夹杂、无空行)。保持原行为(`loading` 的 `once('loaded', …)` / `loaded` 语义按真实承载等价实现)。
(3) **不 invent / 不越界:** 只改 ALT 条目相关用法;`cache.ts` 中 `core.material`(ADAPT)、`core.getAnimateFrames`(TBD)、`core.getTilesetOffset`(ALT,属 09-16)等**本任务不改**。
(4) **行尾 / 注释:** 保持 CRLF;不改既有注释 / JSDoc;不使用 `import type`;不新增 `?.`(dev.md 允许场景除外)。
</action>
<reversibility rating="reversible">三处调用点替换;`git revert` 可回退。</reversibility>
<verify>
<automated>node -e "const fs=require('fs');const bad=[];const code=p=>fs.readFileSync(p,'utf8').split(/\r?\n/).filter(l=>!/^\s*(\/\/|\*|\/\*)/.test(l)).join('\n');for(const p of ['packages-user/client-base/src/elements/cache.ts','packages-user/client-base/src/elements/misc.ts']){const t=code(p);if(/Mota\.require\(\s*'@user\/data-base'/.test(t))bad.push(p+' still has Mota.require(@user/data-base)');if(!/@user\/data-base'/.test(t))bad.push(p+' no static @user/data-base import');}if(bad.length){console.error('MOTA-REQUIRE GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK Mota.require(@user/data-base) replaced by static import')"</automated>
<fails_when>non-zero exit, 或 stderr 含 "MOTA-REQUIRE GATE FAILED"(仍存在 `Mota.require('@user/data-base')` 或缺少静态导入)</fails_when>
<automated>node -e "const fs=require('fs');const bad=[];for(const p of ['packages-user/client-base/src/elements/cache.ts','packages-user/client-base/src/elements/misc.ts']){const b=fs.readFileSync(p,'utf8');if(b.indexOf('\r\n')<0)bad.push('not CRLF: '+p);if(/\bimport\s+type\b/.test(b))bad.push('import type: '+p)}if(bad.length){console.error('CRLF/IMPORT FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK files CRLF and no import type')"</automated>
<fails_when>non-zero exit, 或 stderr 含 "CRLF/IMPORT FAILED"(非 CRLF 或出现 `import type`)</fails_when>
<automated>git status --porcelain</automated>
<fails_when>输出包含本计划 `files_modified` 之外、且非用户既有并发改动(`packages-user/data-state/**`)的生产文件改动</fails_when>
</verify>
<acceptance_criteria>
- `loading` 承载已核实:要么按真实符号改写并记录,要么记录锚点失效并 STOP(二选一,均须写入 SUMMARY)
- 若执行改写:`cache.ts` / `misc.ts` 无 `Mota.require('@user/data-base')`、有静态导入;行为语义保持
- 未触碰非 ALT 用法(`core.material` / `core.getAnimateFrames` / `core.getTilesetOffset` 等)
- 被改文件 CRLF、无 `import type`;未改 `files_modified` 外文件(用户并发改动除外)
</acceptance_criteria>
<done>`Mota.require` 三处按真实承载改写;或记录 A-6 锚点失效并 STOP;门禁(若改写)全绿</done>
</task>
<task type="auto">
<name>Task 2: 替换 `GameStorage` 为 `SaveSystem` 全局存储(A-1-1)并记录 A-2-1 umbrella(部分收口)</name>
<precondition>Task 1 已完成(或已按 R1 STOP 记录);Task 0 已获批。</precondition>
<name>Task 1: 替换 `GameStorage` 为 `SaveSystem` 全局存储(A-1-1)并记录 A-2-1 umbrella(部分收口)</name>
<precondition>Task 0 已闭环:用户明确回复「可以执行」四个字(若用户就 R2 / OI 另有指定,按指定执行)。</precondition>
<files>packages-user/client-modules/src/action/hotkey.ts</files>
<read_first>
- packages-user/client-modules/src/action/hotkey.ts:1-6,510-526(`GameStorage` 导入与热键配置持久化)
@ -232,9 +178,9 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
- 若存在合规路径:将热键配置持久化从 `GameStorage`(`keyStorage.data` / `read()` / `setValue()` / `toJSON()`)改为经 `SaveSystem` 的全局存储(`getGlobal` / `setGlobal` 或审计等价方案),保持「读入 → 反序列化到 `gameKey` → 变更时写回」的行为等价。
- 若无法合规取得:**记录 R2 阻断 + STOP**,不得引入 `client` 单例,也不得保留 `GameStorage` 视作完成。
(2) **A-2-1(umbrella,部分收口):** 不删 `src/types/declaration/core.d.ts` 的全局 `core` 声明,也不改 `client-modules/src/core.ts` 的单例定义(其属 ADAPT 分类 / 其它批次)。在 `09-14-SUMMARY.md` 记录 A-2-1 的**部分收口**状态(本组 ALT 用法已改;全量收口待其余分类批次),并**逐条列明 REPLACED(已收口)与 DEFERRED(未收口 / 待其它批次)的对象**:至少含 `GameStorage`(已 REPLACED,`hotkey.ts`)、`Mota.require('@user/data-base')` 三处(状态按 R1 结论 REPLACED 或 STOP)、以及 DEFERRED 的 `client-modules/src/core.ts:6` 单例定义 / 全局 `core` 声明与其它分类(ADAPT / NONE / TBD)成员,使 40 条 ALT 的整体覆盖可审计。
(2) **A-2-1(umbrella,部分收口):** 不删 `src/types/declaration/core.d.ts` 的全局 `core` 声明,也不改 `client-modules/src/core.ts` 的单例定义(其属 ADAPT 分类 / 其它批次)。在 `09-14-SUMMARY.md` 记录 A-2-1 的**部分收口**状态(本组 ALT 用法已改;全量收口待其余分类批次),并**逐条列明 REPLACED(已收口)与 DEFERRED(未收口 / 待其它批次)的对象**:至少含 `GameStorage`(已 REPLACED,`hotkey.ts`),以及 DEFERRED 的 A-6-1/2/3(`Mota.require('@user/data-base')` / `loading`,**用户自行处理**)、`client-modules/src/core.ts:6` 单例定义 / 全局 `core` 声明与其它分类(ADAPT / NONE / TBD)成员,使 40 条 ALT 的整体覆盖可审计。
(3) **不 invent / 不越界:** 只改 `hotkey.ts` 中与 A-1-1 相关的用法;`hotkey.ts` 内 `core.*` 其它用法(`core.status` / `core.isMoving` / `core.isReplaying` / `core.doSL` / `core.turnHero` / `core.getNextItem` / `core.confirmRestart` / `core.actions` / `core.openBook` 等)属其它分类或其它组,**本任务不改**(`core.debug` 属 09-16)。
(3) **不 invent / 不越界:** 只改 `hotkey.ts` 中与 A-1-1 相关的用法;`hotkey.ts` 内 `core.*` 其它用法(`core.status` / `core.isMoving` / `core.isReplaying` / `core.doSL` / `core.turnHero` / `core.getNextItem` / `core.confirmRestart` / `core.actions` / `core.openBook` 等)属其它分类或其它组,**本任务不改**(`core.debug` 属 09-16)。**不得触碰 A-6(`cache.ts` / `misc.ts`)。**
(4) **命名 / 行尾 / 注释:** 预期不新增命名;如必须新增须呈报批准(D-04)。保持 CRLF;不改既有注释 / JSDoc;不使用 `import type`;不新增 `?.`(dev.md 允许场景除外)。
</action>
@ -242,7 +188,7 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
<verify>
<automated>node -e "const fs=require('fs');const bad=[];const p='packages-user/client-modules/src/action/hotkey.ts';const t=fs.readFileSync(p,'utf8').split(/\r?\n/).filter(l=>!/^\s*(\/\/|\*|\/\*)/.test(l)).join('\n');if(/GameStorage/.test(t))bad.push('hotkey.ts still uses GameStorage');if(!/\bSaveSystem\b/.test(t))bad.push('hotkey.ts: no SaveSystem replacement (expected audit symbol)');if(/\bfrom '@motajs\/legacy-system'/.test(t))bad.push('hotkey.ts still imports @motajs/legacy-system');if(bad.length){console.error('GAMESTORAGE GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK GameStorage replaced (or recorded STOP) in hotkey.ts')"</automated>
<fails_when>non-zero exit, 或 stderr 含 "GAMESTORAGE GATE FAILED"(仍用 `GameStorage`、无替代符号,或仍导入 `@motajs/legacy-system`)</fails_when>
<automated>node -e "const fs=require('fs');const b=fs.readFileSync('packages-user/client-modules/src/action/hotkey.ts','utf8');const bad=[];if(b.indexOf('\r\n')<0)bad.push('not CRLF');if(/\bimport\s+type\b/.test(b))bad.push('import type');if(/\bclient\b\s*\./.test(b)&&/from '\.\.\/core'/.test(b)&&!/^\s*\/\//m.test(b)){}if(bad.length){console.error('CRLF/IMPORT FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK hotkey.ts CRLF and no import type')"</automated>
<automated>node -e "const fs=require('fs');const b=fs.readFileSync('packages-user/client-modules/src/action/hotkey.ts','utf8');const bad=[];if(b.indexOf('\r\n')<0)bad.push('not CRLF');if(/\bimport\s+type\b/.test(b))bad.push('import type');if(bad.length){console.error('CRLF/IMPORT FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK hotkey.ts CRLF and no import type')"</automated>
<fails_when>non-zero exit, 或 stderr 含 "CRLF/IMPORT FAILED"(非 CRLF 或出现 `import type`)</fails_when>
<automated>git status --porcelain</automated>
<fails_when>输出包含本计划 `files_modified` 之外、且非用户既有并发改动(`packages-user/data-state/**`)的生产文件改动</fails_when>
@ -250,10 +196,11 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
<acceptance_criteria>
- `hotkey.ts` 已去除 `GameStorage`(及 `@motajs/legacy-system` 导入)并改用合规的 `SaveSystem` / 全局存储;或记录 R2 阻断并 STOP
- 未引入 `client` 单例;未新增未批准命名;未触碰其它分类用法
- A-2-1 部分收口状态已写入 SUMMARY(不删 `core` 全局声明),且 SUMMARY **逐条列明 REPLACED vs DEFERRED 对象**(含 `client-modules/src/core.ts:6` 单例定义未编辑/未改的处置),使 40 条 ALT 覆盖可审计
- **未触碰 A-6**:`packages-user/client-base/src/elements/cache.ts` / `misc.ts` 未被本计划修改
- A-2-1 部分收口状态已写入 SUMMARY(不删 `core` 全局声明),且 SUMMARY **逐条列明 REPLACED vs DEFERRED 对象**(含 `client-modules/src/core.ts:6` 单例定义未编辑/未改的处置、A-6-1/2/3 DEFERRED 用户自行处理),使 40 条 ALT 覆盖可审计
- 被改文件 CRLF、无 `import type`;未改 `files_modified` 外文件(用户并发改动除外)
</acceptance_criteria>
<done>`GameStorage` 替换到位(或记录阻断 STOP);A-2-1 部分收口记录完成;门禁全绿</done>
<done>`GameStorage` 替换到位(或记录阻断 STOP);A-2-1 部分收口记录完成(含 A-6 DEFERRED 标注);门禁全绿</done>
</task>
</tasks>
@ -264,7 +211,8 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
| Boundary | Description |
|----------|-------------|
| 范围边界 | 只改 ALT 条目相关用法;不触碰 DIRECT / ADAPT / NONE / TBD(D-53) |
| 替代依据边界 | 替代方案只取自审计;锚点失效时记录并 STOP,**不猜**(D-52 / R1) |
| A-6 边界 | **不触碰 A-6(`Mota.require` / `loading`):用户自行处理,本计划禁改 `cache.ts` / `misc.ts`** |
| 替代依据边界 | 替代方案只取自审计;锚点失效时记录并 STOP,**不猜**(D-52 / R2) |
| 单例边界 | 不得引入 `client` 单例取得实例(D-11 / R2) |
| 命名边界 | 未经批准不得新增命名(D-04) |
| 文件 / 提交边界 | 仅改 `files_modified`;不把用户并发改动(`data-state/**`)纳入提交 |
@ -273,38 +221,37 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-09-14-01 | Tampering | 臆造 `loading` 替代 / 编造不存在的符号 | high | mitigate | R1 前置核实;prohibitions 禁猜;无替代则 STOP + 记录 |
| T-09-14-01 | Tampering | 越界改动 A-6(`cache.ts` / `misc.ts` / `Mota.require` / `loading`) | high | mitigate | prohibitions 禁改 A-6;`files_modified` 不含这两文件;`git status` 守卫 |
| T-09-14-02 | Elevation of Privilege | 为取得实例而引入 `client` 单例 / 使用未批准命名 | high | mitigate | R2 前置核实;prohibitions;D-04 / D-11 |
| T-09-14-03 | Tampering | 越界改动非 ALT 用法(`core.status` 等) | high | mitigate | 范围门禁 + `<action>` 明列不改项 + `git status` 守卫 |
| T-09-14-04 | Repudiation | 保留 `Mota.require` / `GameStorage` 却视作完成 | medium | mitigate | MOTA-REQUIRE / GAMESTORAGE 门禁强制 legacy 用法消失 |
| T-09-14-04 | Repudiation | 保留 `GameStorage` 却视作完成 | medium | mitigate | GAMESTORAGE 门禁强制 legacy 用法消失(本计划不再设 MOTA-REQUIRE 门禁,A-6 已 DEFERRED) |
| T-09-14-05 | Information Disclosure | 把用户并发改动(`data-state/**`)误纳入提交 | medium | mitigate | `git status` 守卫豁免既有并发改动 |
| T-09-14-06 | Repudiation | 未跑静态门禁即提交 | medium | mitigate | Task 1/2 各有自动化门禁 + SUMMARY |
| T-09-14-06 | Repudiation | 未跑静态门禁即提交 | medium | mitigate | Task 1 有自动化门禁 + SUMMARY |
| T-09-14-SC | Tampering | npm/pip/cargo installs | low | accept | 无第三方包安装 |
</threat_model>
<verification>
- **Task 1**:`cache.ts` / `misc.ts` 无 `Mota.require('@user/data-base')` 且有静态导入;R1 结论写入 SUMMARY;CRLF / import type 检查;范围门禁。
- **Task 2**:`hotkey.ts` 无 `GameStorage` / `@motajs/legacy-system`,有 `SaveSystem`;A-2-1 部分收口记录(含 REPLACED vs DEFERRED 逐条、`core.ts:6` 单例定义处置);CRLF / import type 检查;范围门禁。
- **R1/R2 触发时**:记录锚点失效 / 阻断并 STOP,相应条目标记「待裁定」。
- **Task 1**:`hotkey.ts` 无 `GameStorage` / `@motajs/legacy-system`,有 `SaveSystem`;A-2-1 部分收口记录(含 REPLACED vs DEFERRED 逐条、`core.ts:6` 单例定义处置、A-6-1/2/3 DEFERRED 用户自行处理);CRLF / import type 检查;范围门禁。
- **A-6(DEFERRED)**:`cache.ts` / `misc.ts` **不在本计划范围**,不修改、不核实、不改写 `loading`。
- **R2 触发时**:记录阻断并 STOP,相应条目标记「待裁定」。
- **无全仓门禁**:不使用 `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数。
- **人工复核**:结论写入 `09-14-SUMMARY.md`。
</verification>
<success_criteria>
- 本组 5 条 ALT:A-6-1/2/3(`Mota.require` → 静态导入)、A-1-1(`GameStorage` → `SaveSystem`)按审计落地;A-2-1 umbrella 部分收口并记录(SUMMARY 含 REPLACED vs DEFERRED 逐条,覆盖可审计)。
- R1 / R2 若成立,**如实记录并 STOP**,不猜测、不保留 legacy 用法冒充完成。
- 零越界:不触碰其它分类、不引入 `client` 单例、不新增未批准命名。
- 静态门禁(MOTA-REQUIRE / GAMESTORAGE / CRLF / 范围)全绿(或按 STOP 分支记录)。
- 本组裁剪后 2 条 ALT:A-1-1(`GameStorage` → `SaveSystem`)按审计落地;A-2-1 umbrella 部分收口并记录(SUMMARY 含 REPLACED vs DEFERRED 逐条,覆盖可审计)。
- A-6-1/2/3(`Mota.require` / `loading`)保持 **DEFERRED(用户自行处理)**,本计划未触碰 `cache.ts` / `misc.ts`。
- R2 若成立,**如实记录并 STOP**,不猜测、不保留 `GameStorage` 冒充完成。
- 零越界:不触碰其它分类、不触碰 A-6、不引入 `client` 单例、不新增未批准命名。
- 静态门禁(GAMESTORAGE / CRLF / 范围)全绿(或按 STOP 分支记录)。
</success_criteria>
## Artifacts this phase produces
| 符号 / 路径 | 类型 | 说明 |
|---|---|---|
| `packages-user/client-base/src/elements/cache.ts`(修改) | 源码 | `Mota.require` → 静态导入 |
| `packages-user/client-base/src/elements/misc.ts`(修改) | 源码 | 两处 `Mota.require` → 静态导入 |
| `packages-user/client-modules/src/action/hotkey.ts`(修改) | 源码 | `GameStorage` → `SaveSystem` 全局存储 |
| `.planning/phases/09-minimum-browser-runnable/09-14-SUMMARY.md`(新增) | 执行摘要 | 本组 ALT、逐文件改动、R1/R2 结论、**A-2-1 REPLACED vs DEFERRED 逐条**、命名影响、门禁结果 |
| `.planning/phases/09-minimum-browser-runnable/09-14-SUMMARY.md`(新增) | 执行摘要 | 本组 ALT(A-1-1 / A-2-1)、逐文件改动、R2 结论、**A-2-1 REPLACED vs DEFERRED 逐条(含 A-6 DEFERRED 用户自行处理)**、命名影响、门禁结果 |
**命名说明:** 预期**不新增源码命名**;如需新增须先获用户批准。
@ -315,12 +262,13 @@ Phase 9 · 任务 7 · 第一批改造(ALT 条目)· **第 2 组 / 共 4 组
| GOAL | Phase 9(ROADMAP) | COVERED(去 legacy 跨包依赖子切片) |
| REQ | 「Requirements: TBD」 | N/A(`requirements: []`) |
| RESEARCH | 无 RESEARCH.md | N/A |
| CONTEXT | D-50(第一批 = 40 条 ALT) | COVERED(本组 5/40) |
| CONTEXT | D-50(第一批 = 40 条 ALT) | COVERED(本组 2/40;A-6-1/2/3 DEFERRED) |
| CONTEXT | D-51(准确记录源文件清单) | COVERED(`files_modified` + 逐文件影响表) |
| CONTEXT | D-52(依据审计,不 invent) | COVERED(prohibitions + R1 STOP) |
| CONTEXT | D-52(依据审计,不 invent) | COVERED(prohibitions + R2 STOP) |
| CONTEXT | D-53(其它分类不在本批) | COVERED(范围门禁) |
| CONTEXT | D-03 / D-04(执行前获批 / 命名获批) | COVERED(Task 0 + prohibitions) |
| 缺口 | R1(A-6 锚点疑似失效) / R2(A-1-1 实例路径) | OPEN(Task 0 OI-2 / OI-3,待用户裁定) |
| ALT | A-6-1 / A-6-2 / A-6-3(`Mota.require` / `loading`) | **DEFERRED(用户自行处理)** —— 用户决定本计划不改;不修改 `cache.ts` / `misc.ts` |
| 缺口 | R2(A-1-1 实例路径) | OPEN(Task 0 OI-3,待用户裁定) |
<output>
Create `.planning/phases/09-minimum-browser-runnable/09-14-SUMMARY.md` when done