diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 98dcf53..81ed76c 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -481,7 +481,7 @@ Plans: **Goal**: 在已完成的数据端(可在 Node 环境独立运行/回放验证)之上完成渲染端框架,产出可在浏览器中运行并验证的最小版本 **Requirements**: TBD **Depends on**: Phase 8 -**Plans**: 10/10 plans executed (任务 1·UI 接口适配,D-10..D-14 已闭环;任务 2·迁移后 UI 修复,D-15..D-17 已闭环;任务 3·legacy UI 移植,book/equipbox/toolbox 已规划(09-06..09-08)并已按用户补齐的数据端接口修订——裸怪物临界 `calculateEnemyCritical`、与空装备对比 `compareEquip(-1)`、道具枚举 `iterateItems`、`@user/data-system` 依赖已声明;shop 已规划(09-09,D-38..D-41)并已按用户补齐的接口修订——价格 `IShopState.getPrice`/`setPrice`(GAP-S1 闭合)、交易 `IShopSystem.buyItem`/`sellItem`(GAP-S2 闭合)、支付资源 `money`(GAP-S3 闭合)、`IShopState` 已从 `@user/data-base` 导出(GAP-S0 闭合),**GAP-S4 已闭合(用户补齐 `@user/data-system` 的 `shop` 导出:`data-system/src/index.ts` `export * from './shop'` + `data-system/src/shop/index.ts`,`IShopSystem` / `IShopHeroAttr` 现可导入)**;本阶段增量派发,其余任务待用户再派发) +**Plans**: 10/10 plans executed (任务 1·UI 接口适配,D-10..D-14 已闭环;任务 2·迁移后 UI 修复,D-15..D-17 已闭环;任务 3·legacy UI 移植,book/equipbox/toolbox 已规划(09-06..09-08)并已按用户补齐的数据端接口修订——裸怪物临界 `calculateEnemyCritical`、与空装备对比 `compareEquip(-1)`、道具枚举 `iterateItems`、`@user/data-system` 依赖已声明;shop 已规划(09-09,D-38..D-41)并已按用户补齐的接口修订——价格 `IShopState.getPrice`/`setPrice`(GAP-S1 闭合)、交易 `IShopSystem.buyItem`/`sellItem`(GAP-S2 闭合)、支付资源 `money`(GAP-S3 闭合)、`IShopState` 已从 `@user/data-base` 导出(GAP-S0 闭合),**GAP-S4 已闭合(用户补齐 `@user/data-system` 的 `shop` 导出:`data-system/src/index.ts` `export * from './shop'` + `data-system/src/shop/index.ts`,`IShopSystem` / `IShopHeroAttr` 现可导入)**;本阶段增量派发,其余任务待用户再派发;**任务 5(09-11·legacy 接口只读统计)已规划、待用户派发后执行(只读产物,wave 8)**) Plans: **Wave 1** @@ -515,6 +515,10 @@ Plans: - [x] 09-10-PLAN.md — 任务 3·复查修正(R-1..R-8):对 `book.tsx`/`bookDetail.tsx`/`equipbox.tsx`/`toolbox.tsx`/`shop.tsx` 统一应用——R-1 移除自绘背景、R-2 长文本改 `TextContent`、R-3 顶层 jsDoc、R-4 JSX 分段注释、R-5 取消 `IShopItemEntry`/`IHeroAttrItem` 导出、R-6 非空判断(字面量 `isNil`/对象 `!`,去 `=== null`/`=== undefined`)、R-7 `shop` 的 `openShop` 移入 `onMounted`、R-8 `bookDetail` 改 `instanceof EnemyView`(已核实 `EnemyView` 为运行期类) +**Wave 8** *(独立于 Wave 6/7 · 任务 5·legacy 接口只读统计,只读产物)* + +- [ ] 09-11-PLAN.md — 任务 5·legacy 接口只读统计(D-42..D-45):只读扫描 `packages-user/client-base` + `packages-user/client-modules` 两包,产出统计文档 `.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md`(第 0 节分类口径 A-1..A-7 + A 残余 legacy 接口 + B `@deprecated` + C `core.*` 调用点 + 汇总表 + 每类计数);**全程只读,零 `.ts`/`.tsx` 改动** + ## Progress **Execution Order:** @@ -530,4 +534,4 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 6. 单元测试 | 18/18 | Obsolete(由 Phase 9 承接) | - | | 7. 数据端缺陷修复 | 15/16 | Complete(07-16 superseded) | - | | 8. 测试重构与接口对齐 | 11/11 | Complete | 2026-10-08 | -| 9. 最小浏览器可运行版本 | 10/10 | In Progress| | +| 9. 最小浏览器可运行版本 | 10/11 | In Progress| | diff --git a/.planning/phases/09-minimum-browser-runnable/09-11-PLAN.md b/.planning/phases/09-minimum-browser-runnable/09-11-PLAN.md new file mode 100644 index 0000000..7f55c5d --- /dev/null +++ b/.planning/phases/09-minimum-browser-runnable/09-11-PLAN.md @@ -0,0 +1,317 @@ +--- +phase: 09-minimum-browser-runnable +plan: 11 +type: execute +wave: 8 +depends_on: [] +files_modified: + - .planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md + - .planning/phases/09-minimum-browser-runnable/09-11-SUMMARY.md +autonomous: false +requirements: [] +estimate: + tokens: 52000 + raw_tokens: 52000 + tasks: 3 + confidence: low +must_haves: + truths: + - "**本计划的第一个 block 点是 Task 0 的 `blocking-human` 汇报关卡(AGENTS.md 硬要求,D-03 / D-44)**:Task 0 必须先汇报「本计划 = 任务 5 · legacy 接口只读统计」的要做什么 / 为什么 / 大致怎么做 / 影响范围,**必须列明统计范围(恰好两个包)、`legacy` 分类口径(A-1..A-7)、三大统计类别(A/B/C)、每类计数与汇总表、产出文档路径(须用户批准)、只读保证与开放项**,然后必须**停下等待**用户明确回复「可以执行」四个字;未收到前不得执行本计划任何一步、不得派发执行子代理,且不因触发方式或 `mode: yolo` / `workflow.auto_advance` 自动放行。" + - "**D-42(范围):** 统计**恰好**覆盖 `packages-user/client-base` 与 `packages-user/client-modules` 两个包内的 `.ts` / `.tsx` 源码,**排除** `node_modules`、`dist` 与任何生成物;**不外扩**到其它包(`packages/**`、`packages-user/data-**`、`packages-user/client-system`、`entry-*`、`src/`)。" + - "**D-43①(A. 残余的 legacy 接口):** 按文档内**显式定义**的分类口径枚举残余 legacy 接口 / 构造,逐条给出精确 `file:line` 锚点。口径:A-1 跨包 legacy 依赖(`import ... from '@motajs/legacy-ui' | '@motajs/legacy-common' | '@motajs/legacy-system'`);A-2 legacy 全局 `core`(声明于 `src/types/declaration/core.d.ts`,调用点归 C 类并交叉引用);A-3 legacy 单例 `client`(`client-modules/src/core.ts` 导出及其使用点);A-4 legacy patch 机制(`Patch` / `PatchClass` 及其 `.add(...)`);A-5 legacy UI 运行时符号(`mainUi` / `mainSetting` / `getVitualKeyOnce` / `triggerFullscreen`);A-6 legacy `Mota` 全局(`Mota.require(...)`);A-7 legacy 兼容 / 回退层(`client-modules/src/fallback/**`,含用户所称 data-fallback)。" + - "**D-43②(B. 标注 `@deprecated` 的接口):** 在两包内扫描 `@deprecated` JSDoc 标注,逐条给出 `file:line` + 符号 + 说明;**若实测为 0 条,必须显式报告「0 条」并写明扫描范围与匹配方式**(不得省略该节)。**规划日实测两包内 `@deprecated` 命中为 0**(全仓其它位置有命中,但不在本统计范围内)。" + - "**D-43③(C. 所有经 `core.*` 调用的接口):** 枚举两包内**全部经 legacy 全局 `core.` 的调用点**(仅代码,**排除注释与字符串字面量**),给出 (a) 去重后的成员清单 `core.`,(b) 按文件的 `file:line` 调用点,(c) 每类计数。**规划日实测**:`client-base` 出现 `core.*` 的文件含 `components/choices.tsx`、`components/floorSelect.tsx`、`components/misc.tsx`、`components/textboxTyper.ts`、`components/thumbnail.tsx`、`components/tip.tsx`、`elements/cache.ts`、`elements/misc.ts`、`shared.ts`;`client-modules` 出现 `core.*` 的文件含 `action/hotkey.ts`、`action/move.ts`、`fallback/audio.ts`、`fallback/load.ts`、`render/utils/saves.ts`、`render/weather/presets/{cloud,fog,sun}.ts`、`ui/{book,bookDetail,main,save,settings,shop,statistics,statusBar,title,toolbar,toolbox,viewmap}.tsx`、`client.ts`、`shared.ts`。" + - "**D-44(产出):** 产出一份统计文档于 `.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md`(**新命名产物,须 Task 0 呈报用户批准**),含第 0 节(口径与范围)、A/B/C 三节、**汇总表**与**每类计数**(机器可读行 `A-COUNT:` / `B-COUNT:` / `C-COUNT:`)。" + - "**D-45(只读):** 全程**只读**——**禁止**修改 / 删除 / 新增任何生产 `.ts` / `.tsx` 源码,**禁止**任何改造或修复;本计划**唯一允许写入**的文件是统计文档 `09-LEGACY-INTERFACES-AUDIT.md` 与 `09-11-SUMMARY.md`。" + - "**分类口径显式化 + 每条有据:** 「legacy」定义宽泛,文档第 0 节必须**显式定义**判定基准与 A-1..A-7 子类,**不得臆造条目**;文档中每个 `file:line` 锚点须指向真实存在且行号在范围内的行(门禁逐一校验)。" + - "**范围零外溢 + 静态门禁:** 仅新增上述两文档;**不修改** 09-01..09-10 任何文件、不修改任何 `.ts`/`.tsx`、不修改 `ROADMAP.md` 以外任何既有规划文件;验证一律为**静态断言**(文档存在 / 含 A·B·C 节 / 含每类计数 / 含汇总 / 锚点有效 / 两包均覆盖 / 只读守卫),**不使用** `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数作门禁。" + artifacts: + - path: .planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md + provides: "任务 5 的只读统计文档:第 0 节分类口径 + A(残余 legacy 接口)+ B(`@deprecated`)+ C(`core.*` 调用点)+ 汇总表 + 每类计数。" + - path: .planning/phases/09-minimum-browser-runnable/09-11-SUMMARY.md + provides: "本计划的执行摘要:统计范围、分类口径、A/B/C 计数、产出路径、只读确认。" + key_links: + - "`packages-user/client-modules/src/action/hotkey.ts:3`、`fallback/audio.ts:1-2`、`fallback/ui.ts:1`、`fallback/weather.ts:1`、`ui/settings.tsx:13,15`、`ui/title.tsx:28`、`ui/toolbar.tsx:14,20` ↔ `@motajs/legacy-ui` / `@motajs/legacy-common` / `@motajs/legacy-system` —— A-1 / A-4 / A-5 的跨包 legacy 依赖来源" + - "`src/types/declaration/core.d.ts` ↔ legacy 全局 `core` 声明处 —— A-2(legacy 接口本体)与 C 类调用点的类型来源" + - "`packages-user/client-modules/src/core.ts:6`(`export const client = new ClientCore(...)`)↔ `fallback/audio.ts:5,11`(`import { client }` / `const { ... } = client`)—— A-3 legacy 单例 `client` 的定义与使用" + - "`packages-user/client-base/src/elements/misc.ts:89,219`、`elements/cache.ts:491` ↔ legacy 全局 `Mota`(`Mota.require('@user/data-base')`)—— A-6 legacy `Mota` 全局" + - "`packages-user/client-modules/src/fallback/**`(`index.ts` / `audio.ts` / `ui.ts` / `weather.ts` / `load.ts`)—— A-7 legacy 兼容 / 回退层(含 data-fallback)" + assumptions: + - "**执行日行号可能漂移**:本计划内引用行号为 2026-10-11 规划日实测;文档锚点与门禁以**执行日实测**为准,门禁按「文件存在 + 行号在范围内」校验,不硬编码任何行号。" + - "**`@deprecated` 两包内实测为 0**:规划日已用全量文件扫描(含 `.ts` / `.tsx`)确认两包内无 `@deprecated`;执行日须**复扫**并以实测为准,若出现则如实登记。" + - "**「data-fallback」无同名符号**:规划日在 `packages`、`packages-user`、`src`(排除 `node_modules`)中未检索到字面量 `data-fallback` / `dataFallback`;本计划将 A-7 定义为 `client-modules/src/fallback/**` 兼容 / 回退层及 `Mota.require('@user/data-*')` 式数据回退。若用户所指另有其事,据其指定补充。" + - "**Markdown 使用 LF**:仓库既有 phase 文档(`09-06-PLAN.md` / `09-10-PLAN.md` / `09-10-SUMMARY.md` / `ROADMAP.md`)均为裸 LF;新文档随此约定(**不**强制 CRLF)。" + - "**`core.*` 统计口径**:仅计**代码**中的 `core.` 访问(含 `core.status.x` 这类取首成员 `status`),**排除**注释(`//` / `/* */`)与字符串字面量(如注释中的 `core.js` 不算)。" + prohibitions: + - "不得在用户明确回复「可以执行」四个字之前执行本计划的任何任务、或派发任何执行子代理。" + - "本计划**只做只读统计并产出文档**:**不得**修改 / 删除 / 新增任何生产 `.tsx` / `.ts` 源码;**不得**做任何改造、修复、迁移或接线(改造属后续另行规划,D-45)。" + - "**只读边界:** 除 `09-LEGACY-INTERFACES-AUDIT.md` 与 `09-11-SUMMARY.md` 两个文档外,**不得写入任何文件**;不得改 09-01..09-10 及其产物;不得改 `ROADMAP.md` 以外任何既有规划文件。" + - "**不得臆造条目:** 文档中每个 `file:line` 锚点必须指向真实存在且范围内的一行;不得凭印象编造成员名 / 调用点;分类口径须在第 0 节显式给出。" + - "不得把门禁建立在「全仓 TS 诊断数」「`pnpm check:type`」「`pnpm build`」之上;不得为了「验证」去改动源码。" + - "不得触碰、暂存、提交用户的并发改动(D-56):提交前 `git status` 逐条核对暂存面,只暂存本计划 `files_modified` 的条目。" + open_items: + - "**OI-1(产出文档命名 / 路径,D-44):** 提议 `.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md`(连字符命名法,随仓库 Markdown 约定)。**待用户批准。**" + - "**OI-2(分类口径 A-1..A-7):** 提议以「legacy 包依赖 / legacy 全局 `core` / legacy 单例 `client` / legacy patch 机制 / legacy UI 运行时符号 / legacy `Mota` 全局 / legacy 兼容回退层」七子类界定。**待用户确认**;若用户要增删子类,据其指定。" + - "**OI-3(data-fallback 所指):** 规划日未检索到 `data-fallback` 同名符号;暂归 A-7(`client-modules/src/fallback/**` 及 `Mota.require('@user/data-*')`)。若用户所指另有其事,请指明。" + - "**OI-4(B 类为 0 的呈现):** 若执行日复扫仍为 0,文档 B 节**显式报告 0 条**并写明扫描范围与匹配方式(不省略该节)。请确认此呈现方式。" + - "**OI-5(C 类粒度):** 默认给出「去重成员清单 + 按文件 `file:line` 调用点 + 每文件计数」;是否需要额外按 `core.` 维度汇总计数,请指明(默认一并给出)。" +--- + + +Phase 9 · 任务 5 · 第 11 个计划 —— **legacy 接口只读统计**(范围恰好 `packages-user/client-base` 与 `packages-user/client-modules`,产出**一份统计文档**)。 + +**要解决的问题(D-42..D-45):** 为后续「legacy 移植 / 去 legacy」改造提供一份**有据可查的只读台账**,精确枚举两包内 ① 残余 legacy 接口、② 标注 `@deprecated` 的接口、③ 所有经 `core.*` 调用的接口,逐条给出 `file:line` 锚点,并给出每类计数与汇总表。**本计划不做任何改造**(D-45 只读)。 + +**大致解决方案(本计划 = 09-11):** +- **Task 0(`blocking-human`)= 预执行汇报关卡**:汇报统计范围、`legacy` 分类口径(A-1..A-7)、三大类别 A/B/C、每类计数与汇总形式、产出文档路径(OI-1)、只读保证与开放项 OI-1..OI-5,并等待用户「可以执行」。 +- **Task 1 = 扫描并撰写文档骨架 + A 节 + B 节**:建立第 0 节分类口径(含方法论与只读声明),枚举 A(残余 legacy 接口,含跨包 legacy 依赖 / 单例 / patch / UI 符号 / `Mota` / 回退层)与 B(`@deprecated`,实测若 0 则显式报告 0),给出 A / B 计数。 +- **Task 2 = 扫描并撰写 C 节 + 汇总表 + 收口门禁**:枚举 C(`core.*` 调用点:去重成员清单 + 按文件 `file:line` + 每文件计数),补齐汇总表与机器可读计数(`A-COUNT:` / `B-COUNT:` / `C-COUNT:`),跑最终静态门禁(含锚点有效性与只读守卫),写 `09-11-SUMMARY.md`。 + +**为何先 A/B 后 C:** A/B 体量小、依赖分类口径先立;C 是重头(跨 ~28 个文件),单独成节并承载汇总与只读收口。三任务同属一个只读产物,无 `files_modified` 外扩。 + +**API coverage:** `detected:false`。**`No external API integration: 本计划仅为只读源码统计与文档撰写,不涉及任何外部 API。`** + + +@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/phases/09-minimum-browser-runnable/09-CONTEXT.md +@.planning/phases/09-minimum-browser-runnable/09-06-PLAN.md +@AGENTS.md +@dev.md + + + + + + Task 0: 预执行汇报关卡 —— 汇报「任务 5 · legacy 接口只读统计」的范围、分类口径、A/B/C 类别与产出路径,等待用户回复「可以执行」 + `packages-user/client-base/src` 与 `packages-user/client-modules/src` 均存在;两包内跨包 legacy 依赖(`@motajs/legacy-*`)仍在(如 `client-modules/src/action/hotkey.ts:3`);统计文档 `09-LEGACY-INTERFACES-AUDIT.md` 与 `09-11-SUMMARY.md` **尚不存在**。 + (只读汇报,不修改任何文件) + + - .planning/phases/09-minimum-browser-runnable/09-CONTEXT.md(D-03 / D-04 / D-06 / **D-42 / D-43 / D-44 / D-45**) + - .planning/phases/09-minimum-browser-runnable/09-11-PLAN.md(本计划全文,含分类口径 A-1..A-7 与 OI-1..OI-5) + - AGENTS.md(执行前须获批、命名须先反馈、修改方式须预先声明);dev.md(命名规则、注释规范、Markdown 连字符命名、CRLF 约定) + + + **停下并向用户汇报,等待明确回复「可以执行」后才继续;汇报本身只读。** + + ① **要解决的问题:** 任务 5 · legacy 接口只读统计。为后续 legacy 改造提供有据可查的只读台账——精确枚举两包内 ① 残余 legacy 接口、② `@deprecated` 接口、③ `core.*` 调用点,逐条给出 `file:line` 锚点 + 每类计数 + 汇总表。**只读,不改造。** + + ② **统计范围(D-42):** 恰好 `packages-user/client-base` 与 `packages-user/client-modules` 两包内的 `.ts` / `.tsx`(排除 `node_modules` / `dist`);不外扩到 `packages/**`、`packages-user/data-**`、`client-system`、`entry-*`、`src/`。 + + ③ **`legacy` 分类口径(D-43①,须用户确认,OI-2):** 显式定义七子类——**A-1** 跨包 legacy 依赖(`import ... from '@motajs/legacy-ui' | '@motajs/legacy-common' | '@motajs/legacy-system'`);**A-2** legacy 全局 `core`(声明于 `src/types/declaration/core.d.ts`;调用点归 C 类并交叉引用);**A-3** legacy 单例 `client`(`client-modules/src/core.ts:6` 导出及其使用点);**A-4** legacy patch 机制(`Patch` / `PatchClass` 及其 `.add(...)`);**A-5** legacy UI 运行时符号(`mainUi` / `mainSetting` / `getVitualKeyOnce` / `triggerFullscreen`);**A-6** legacy `Mota` 全局(`Mota.require(...)`);**A-7** legacy 兼容 / 回退层(`client-modules/src/fallback/**`,含用户所称 data-fallback,OI-3)。 + + ④ **三大类别与形式(D-43):** + - **A(残余 legacy 接口):** 表 `file:line | 符号 | 来源包 / 子类 | 说明` + **A 计数**。 + - **B(标注 `@deprecated` 的接口):** 表 `file:line | 符号 | 说明` + **B 计数**;**规划日实测两包内为 0 条**,执行日复扫;若为 0 则**显式报告 0** 并写明扫描范围与匹配方式(OI-4)。 + - **C(经 `core.*` 调用的接口):** 去重成员清单 `core.` + 按文件 `file:line` 调用点 + 每文件计数 + **C 计数**;仅计代码,排除注释与字符串字面量。 + + ⑤ **产出文档(D-44,须批准,OI-1):** 提议路径 `.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md`;含第 0 节(口径与范围)、A / B / C 三节、**汇总表**、**每类计数**(机器可读行 `A-COUNT:` / `B-COUNT:` / `C-COUNT:`)。 + + ⑥ **只读保证(D-45):** 全程只读;**禁止**修改 / 删除 / 新增任何生产 `.ts` / `.tsx`;本计划**唯一允许写入**的文件是上述统计文档与 `09-11-SUMMARY.md`。 + + ⑦ **验证方式(须用户确认):** 静态断言——文档存在;含 `## 0.` / `## A.` / `## B.` / `## C.` / `## 汇总`;含每类计数(`A-COUNT:` / `B-COUNT:` / `C-COUNT:`);A/B/C 锚点逐一校验「文件存在 + 行号在范围内」;两包均被 C 覆盖;**只读守卫**(`git status` 无任何 `.ts` / `.tsx` 改动)。**不设全仓类型 / 构建门禁。** + + ⑧ **开放项与关卡性质:** 呈报 OI-1(文档路径)、OI-2(分类口径)、OI-3(data-fallback 所指)、OI-4(B=0 呈现)、OI-5(C 粒度)。**无论触发方式或 `mode: yolo` / `workflow.auto_advance`,执行者 / 子代理必须停下等待用户明确回复「可以执行」四个字**;回复其它内容视为未通过;若用户给出修订意见,退出本计划、修订后重新汇报。 + + 是否按本计划执行任务 5 · legacy 接口只读统计(范围恰好两个包,产出 `09-LEGACY-INTERFACES-AUDIT.md`),并按分类口径 A-1..A-7 与 OI-1..OI-5 的默认处置产出文档(只读,不改任何源码) + + AGENTS.md / D-03 / D-04 要求执行前与命名先获批;`.planning/config.json` 为 `mode: yolo`,故本关卡显式 `blocking-human` 且 `autonomous: false`。本次核心 = 分类口径确认 + 产出文档命名批准 + 只读边界确认 + B=0 的呈现方式 + C 类粒度。行号为规划日实测、可能漂移,文档锚点与门禁以执行日实测为准。 + + + + + + + 回复「可以执行」四个字(如需调整 OI-1..OI-5 的处置,请在回复中指明;修订意见请按 action ⑧ 处理) + + node -e "const fs=require('fs');const has=p=>fs.existsSync(p);const read=p=>fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');const bad=[];const doc='.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md';const sum='.planning/phases/09-minimum-browser-runnable/09-11-SUMMARY.md';if(has(doc))bad.push('post-state: audit doc already exists');if(has(sum))bad.push('post-state: 09-11-SUMMARY already exists');if(!has('packages-user/client-base/src'))bad.push('missing client-base/src');if(!has('packages-user/client-modules/src'))bad.push('missing client-modules/src');if(has('packages-user/client-modules/src/action/hotkey.ts')){if(read('packages-user/client-modules/src/action/hotkey.ts').indexOf('@motajs/legacy-system')<0)bad.push('pre-state changed: hotkey legacy-system import gone')}else{bad.push('pre-state changed: hotkey.ts missing')}if(has('packages-user/client-modules/src/core.ts')){if(read('packages-user/client-modules/src/core.ts').indexOf('export const client')<0)bad.push('pre-state changed: client singleton gone')}else{bad.push('pre-state changed: core.ts missing')}if(bad.length>0){console.error('PRESTATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK pre-execution state intact (audit doc absent; both packages present; legacy import + client singleton present)')" + non-zero exit, 或 stderr 含 "PRESTATE FAILED"(汇报基线不成立,或产出文档已存在 / 关键 legacy 锚点已漂移) + 用户在对话中明确回复「可以执行」四个字(人工核对回复原文;用户若指定非默认的范围 / 分类口径 / 产出路径 / B=0 呈现,须在汇报与后续任务中据其指定执行) + + + - 用户回复中明确包含「可以执行」四个字 + - 汇报内容涵盖:D-42 范围、D-43 三大类别(A/B/C)、legacy 分类口径 A-1..A-7、D-44 产出路径、D-45 只读保证、OI-1..OI-5、验证方式(静态断言,无全仓门禁) + - 汇报中已原样告知:**全程只读、不改任何 `.ts`/`.tsx`、不做任何改造、B 若为 0 会显式报告 0、锚点不得臆造** + - 汇报中已原样告知**关卡性质**(必须停下等待,不因触发方式或 `yolo` / `auto_advance` 自动放行) + + 用户明确回复「可以执行」;在此之前未执行任何任务、未修改任何文件、未派发任何执行子代理 + + + + Task 1(口径 + A + B):建立统计文档骨架与分类口径,撰写 A 节(残余 legacy 接口)与 B 节(`@deprecated`) + Task 0 已闭环:用户明确回复「可以执行」四个字(若用户就 OI-1..OI-5 另有指定,按指定执行)。 + .planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md + + - .planning/phases/09-minimum-browser-runnable/09-CONTEXT.md(D-42 / D-43 / D-44 / D-45) + - packages-user/client-modules/src/action/hotkey.ts:1-6(`import { GameStorage } from '@motajs/legacy-system';`) + - packages-user/client-modules/src/fallback/audio.ts:1-11(`Patch, PatchClass` ← legacy-common;`mainSetting` ← legacy-ui;`client` 单例) + - packages-user/client-modules/src/fallback/ui.ts:1-11、fallback/weather.ts:1-9、fallback/index.ts:1-9(`Patch` / `PatchClass` 使用与回退层入口) + - packages-user/client-modules/src/ui/settings.tsx:11-18(`mainUi` / `getVitualKeyOnce` ← legacy-ui) + - packages-user/client-modules/src/ui/title.tsx:26-32(`mainSetting` / `triggerFullscreen` ← legacy-ui) + - packages-user/client-modules/src/ui/toolbar.tsx:12-21(`getVitualKeyOnce` ← legacy-ui;`generateBinary` ← legacy-common) + - packages-user/client-modules/src/core.ts:1-11(`export const client = new ClientCore(...)`) + - packages-user/client-base/src/elements/misc.ts:85-95,215-223、elements/cache.ts:487-495(`Mota.require('@user/data-base')`) + - src/types/declaration/core.d.ts(legacy 全局 `core` 声明处;只读参考) + - dev.md(Markdown 连字符命名;注释 / 命名规范) + + + (1) **创建文档骨架 `09-LEGACY-INTERFACES-AUDIT.md`**(仅此文件;**不修改任何源码**;OI-1 命名须已在 Task 0 获批)。 + + (2) **第 0 节 `## 0. 统计口径与范围`:** 写明——统计范围(恰好两个包、`.ts`/`.tsx`、排除 `node_modules`/`dist`);`legacy` **判定基准**;`A-1..A-7` **子类定义**;扫描方法论(用 node 递归遍历两包源码、按正则匹配、**排除注释与字符串**);**只读声明**(本文件为唯一产物之一,未改动任何源码);Markdown 使用 LF。 + + (3) **A 节 `## A. 残余的 legacy 接口`:** 按 A-1..A-7 分小节,逐条以表格登记 `file:line | 符号 | 来源包 / 子类 | 说明`。**必须逐条实测**(不得臆造)。已知起步锚点(执行日复核行号):A-1/A-4/A-5 见 `client-modules/src/action/hotkey.ts`、`fallback/{audio,ui,weather}.ts`、`ui/{settings,title,toolbar}.tsx`;A-3 见 `client-modules/src/core.ts` 与 `fallback/audio.ts:5,11`;A-6 见 `client-base/src/elements/{misc.ts:89,219,cache.ts:491}`;A-7 = `client-modules/src/fallback/**`(`index.ts` / `audio.ts` / `ui.ts` / `weather.ts` / `load.ts`)。A-2 只列 legacy 全局 `core` 本体并交叉引用 C 节。**给出 A 计数**并写入机器可读行 `A-COUNT: `。 + + (4) **B 节 `## B. 标注 @deprecated 的接口`:** 在两包内扫描 `@deprecated` JSDoc 标注,逐条登记 `file:line | 符号 | 说明`。**规划日实测为 0 条**;执行日**复扫**并如实登记。**若为 0,显式报告「0 条」**并写明扫描范围(两包全部 `.ts`/`.tsx`,排除 `node_modules`/`dist`)与匹配方式(`@deprecated` 字面量),不省略该节(OI-4)。**给出 B 计数**并写入机器可读行 `B-COUNT: `。 + + (5) **收口:** 不改任何源码;不改任何既有注释;文档仅含第 0 节 + A 节 + B 节(C 节与汇总由 Task 2 补齐);LF。 + + 纯新增只读文档;删除 / `git revert` 可整体回退;未触及任何源码。 + + node -e "const fs=require('fs');const p='.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md';const bad=[];if(!fs.existsSync(p)){bad.push('doc missing')}else{const t=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');for(const s of ['## 0.','## A. 残余的 legacy 接口','## B. 标注 @deprecated 的接口']){if(t.indexOf(s)<0)bad.push('missing heading: '+s)}if(!/A-COUNT:\s*\d+/.test(t))bad.push('missing A-COUNT');if(!/B-COUNT:\s*\d+/.test(t))bad.push('missing B-COUNT');if(t.indexOf('@motajs/legacy-')<0)bad.push('no legacy import grounded (A)');if(t.indexOf('@deprecated')<0)bad.push('no @deprecated mention (B)');if(t.indexOf('core')<0)bad.push('no core cross-reference (A-2)');const anchors=[...t.matchAll(/(packages-user\/[^\s`|)]+\.(?:ts|tsx)):(\d+)/g)];if(anchors.length<1)bad.push('no file:line anchors');for(const m of anchors){const f=m[1];const ln=parseInt(m[2],10);if(!fs.existsSync(f)){bad.push('anchor to missing file: '+f);continue}const lines=fs.readFileSync(f,'utf8').split(/\r?\n/);if(ln<1||ln>lines.length)bad.push('anchor line out of range: '+f+':'+ln)}}if(bad.length>0){console.error('AUDIT-AB GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK audit A+B authored (sections 0/A/B, counts, grounded anchors)')" + non-zero exit, 或 stderr 含 "AUDIT-AB GATE FAILED"(文档缺失 / 缺第 0 节或 A·B 节 / 缺 A·B 计数 / 无 legacy 或 @deprecated 依据 / 锚点指向不存在的文件或越界行号) + node -e "const {execSync}=require('child_process');const out=execSync('git status --porcelain',{encoding:'utf8'});const bad=out.split(/\r?\n/).filter(Boolean).filter(l=>/packages-user\/.*\.(ts|tsx)\s*$/.test(l));if(bad.length){console.error('READONLY FAILED :: source touched :: '+bad.join(' | '));process.exit(1)}console.log('OK read-only after Task 1: no .ts/.tsx touched')" + non-zero exit, 或 stderr 含 "READONLY FAILED"(出现任何 `.ts`/`.tsx` 改动,违反 D-45 只读) + + + - 文档 `09-LEGACY-INTERFACES-AUDIT.md` 存在,含 `## 0. 统计口径与范围`(含 legacy 判定基准 + A-1..A-7 + 方法论 + 只读声明)、`## A. 残余的 legacy 接口`、`## B. 标注 @deprecated 的接口` + - A 节按 A-1..A-7 分小节登记,逐条 `file:line` 锚点;已知跨包 legacy 依赖与单例 / `Mota` / 回退层均已进入台账 + - B 节如实登记;若实测为 0,显式报告「0 条」并写明扫描范围与匹配方式 + - 含机器可读 `A-COUNT:` 与 `B-COUNT:`;所有锚点文件存在且行号在范围内 + - 未改动任何 `.ts`/`.tsx`;未改任何既有注释;未改 `files_modified` 外文件 + + 第 0 节与 A、B 两节撰写完成,A/B 计数写入;静态门禁与只读守卫全绿 + + + + Task 2(C + 汇总 + 收口):撰写 C 节(所有经 `core.*` 调用的接口)与汇总表,补齐每类计数并跑最终静态门禁与只读守卫,写 SUMMARY + Task 1 已完成(文档第 0 节与 A、B 两节已就位,C 节与汇总待补)。 + .planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md, .planning/phases/09-minimum-browser-runnable/09-11-SUMMARY.md + + - .planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md(本文件现状:第 0 节 + A + B,待补 C 与汇总) + - src/types/declaration/core.d.ts(legacy 全局 `core` 的成员类型来源;只读参考) + - packages-user/client-base/src/components/choices.tsx、floorSelect.tsx、misc.tsx、textboxTyper.ts、thumbnail.tsx、tip.tsx;elements/cache.ts、elements/misc.ts;shared.ts(`core.*` 调用点) + - packages-user/client-modules/src/action/hotkey.ts、action/move.ts、fallback/audio.ts、fallback/load.ts、render/utils/saves.ts、render/weather/presets/{cloud,fog,sun}.ts、client.ts、shared.ts(`core.*` 调用点) + - packages-user/client-modules/src/ui/{book,bookDetail,main,save,settings,shop,statistics,statusBar,title,toolbar,toolbox,viewmap}.tsx(`core.*` 调用点) + + + (1) **C 节 `## C. 所有经 core.* 调用的接口`:** 用 node 递归遍历两包内 `.ts`/`.tsx`(排除 `node_modules`/`dist`),按正则匹配 `\bcore\.([A-Za-z_][A-Za-z0-9_]*)`,**排除注释(`//` / `/* */`)与字符串字面量**(如注释里的 `core.js` 不计)。产出: + - **C-1 去重成员清单:** 汇总所有被访问的 `core.`(如 `core.status` / `core.formatBigNumber` / `core.material` / `core.floors` / `core.saves` / `core.formatDate2` / `core.playSound` / `core.openBook` …;以执行日实测为准)。 + - **C-2 按文件调用点:** 表 `file:line | core. | 上下文`,逐条 `file:line`。 + - **C-3 每文件计数:** 表 `file | 调用点计数`。 + - **C 计数:** 写入机器可读行 `C-COUNT: `(n = 去重后调用点总数),并注明覆盖成员数 M。 + + (2) **汇总节 `## 汇总`:** 汇总表 `| 类别 | 计数 | 覆盖文件数 | 说明 |`,至少三行 A / B / C;并在表下重申三行机器可读计数 `A-COUNT:` / `B-COUNT:` / `C-COUNT:`(与各节一致)。 + + (3) **收口与门禁:** 不改任何源码;不改任何既有注释;文档 LF。本任务 `` 运行最终静态门禁(含 C 节与汇总、锚点有效性、两包均被 C 覆盖)与只读守卫。 + + (4) **写 `09-11-SUMMARY.md`:** 记录统计范围、分类口径(A-1..A-7)、A/B/C 计数、产出文档路径、只读确认、OI-1..OI-5 的最终裁定。 + + 纯新增只读文档(统计文档 + SUMMARY);删除 / `git revert` 可整体回退;未触及任何源码。 + + node -e "const fs=require('fs');const p='.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md';const bad=[];if(!fs.existsSync(p)){bad.push('doc missing')}else{const t=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');for(const s of ['## C. 所有经 core.* 调用的接口','## 汇总']){if(t.indexOf(s)<0)bad.push('missing heading: '+s)}for(const k of ['A-COUNT:','B-COUNT:','C-COUNT:']){if(!new RegExp(k+'\\s*\\d+').test(t))bad.push('missing '+k)}for(const m of ['core.status','core.formatBigNumber','core.material','core.floors']){if(t.indexOf(m)<0)bad.push('missing member: '+m)}if(!/packages-user\/client-base\/src[^\s`|)]*\.(?:ts|tsx):\d+/.test(t))bad.push('no client-base core anchor');if(!/packages-user\/client-modules\/src[^\s`|)]*\.(?:ts|tsx):\d+/.test(t))bad.push('no client-modules core anchor');const anchors=[...t.matchAll(/(packages-user\/[^\s`|)]+\.(?:ts|tsx)):(\d+)/g)];if(anchors.length<5)bad.push('too few anchors');for(const m of anchors){const f=m[1];const ln=parseInt(m[2],10);if(!fs.existsSync(f)){bad.push('anchor to missing file: '+f);continue}const lines=fs.readFileSync(f,'utf8').split(/\r?\n/);if(ln<1||ln>lines.length)bad.push('anchor out of range: '+f+':'+ln)}}if(bad.length>0){console.error('AUDIT-C GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK audit C + summary authored (sections C/summary, A/B/C counts, both packages covered, anchors valid)')" + non-zero exit, 或 stderr 含 "AUDIT-C GATE FAILED"(文档缺失 / 缺 C 节或汇总 / 缺某类计数 / 缺核心成员或某包锚点 / 锚点指向不存在的文件或越界行号) + node -e "const {execSync}=require('child_process');const out=execSync('git status --porcelain',{encoding:'utf8'});const bad=out.split(/\r?\n/).filter(Boolean).filter(l=>/packages-user\/.*\.(ts|tsx)\s*$/.test(l));if(bad.length){console.error('READONLY FAILED :: source touched :: '+bad.join(' | '));process.exit(1)}console.log('OK read-only final: no .ts/.tsx touched')" + non-zero exit, 或 stderr 含 "READONLY FAILED"(出现任何 `.ts`/`.tsx` 改动,违反 D-45 只读) + git -C . status --porcelain + 输出包含本计划 `files_modified`(`09-LEGACY-INTERFACES-AUDIT.md` + `09-11-SUMMARY.md`)之外的生产文件改动(如 `packages-user/**` 的 `.ts`/`.tsx`、`packages/**`、数据端、`package.json`) + + + - 文档含 `## C. 所有经 core.* 调用的接口`:去重成员清单 + 按文件 `file:line` 调用点 + 每文件计数;仅计代码、排除注释与字符串 + - 文档 `client-base` 与 `client-modules` 两包**均有** `core.*` 锚点 + - 文档含 `## 汇总` 表(A/B/C 三行)与三行机器可读计数 `A-COUNT:` / `B-COUNT:` / `C-COUNT:`(与各节一致) + - 全部 `file:line` 锚点指向真实存在且行号在范围内的行(无臆造) + - 未改动任何 `.ts`/`.tsx`;未改任何既有注释;范围守卫无越界改动;`09-11-SUMMARY.md` 已写 + + C 节与汇总表完成、三类计数齐备;最终静态门禁 + 锚点校验 + 只读守卫全绿;SUMMARY 落盘 + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| 只读边界 | 统计过程只读取两包源码;**禁止任何源码写入**(D-45) | +| 范围边界 | 统计范围恰好 `client-base` + `client-modules`;不外扩到其它包 / `src` | +| 分类口径边界 | 「legacy」定义须文档内显式给出(A-1..A-7);不得臆造条目 | +| 产出边界 | 仅允许写 `09-LEGACY-INTERFACES-AUDIT.md` 与 `09-11-SUMMARY.md` | +| 提交边界 | 不得把用户并发改动(D-56)纳入暂存/提交 | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan | +|-----------|----------|-----------|----------|-------------|-----------------| +| T-09-11-01 | Tampering | 借「统计」之机修改 / 新增生产源码(`.ts`/`.tsx`) | high | mitigate | `files_modified` 白名单 + prohibitions + Task 1/2 `READONLY` 门禁(`git status` 无 `.ts`/`.tsx` 改动) | +| T-09-11-02 | Elevation of Privilege | 未经批准即执行 / 使用未批准的产出文档命名 | high | mitigate | Task 0 `blocking-human`;OI-1 命名呈报;prohibitions 禁未获批命名 | +| T-09-11-03 | Tampering | 臆造条目(不存在的文件 / 越界行号 / 编造成员名) | high | mitigate | `` 要求逐条实测;Task 1/2 门禁逐一校验「文件存在 + 行号在范围内」 | +| T-09-11-04 | Information Disclosure | 统计范围外泄到其它包 / `src` | medium | mitigate | `` 明确扫描范围(两包、排除 `node_modules`/`dist`);`` 复述 | +| T-09-11-05 | Tampering | `core.*` 统计误计注释 / 字符串(如 `core.js`)或漏计 | medium | mitigate | `` 明确排除注释与字符串字面量;C 节给出方法论 | +| T-09-11-06 | Repudiation | 未跑静态门禁即提交 | medium | mitigate | Task 1/2 各有自动化门禁 + SUMMARY;未通过不得提交 | +| T-09-11-07 | Tampering | B 类为 0 被静默省略 | low | mitigate | ``/`acceptance` 明列「若为 0 须显式报告 0 并写明范围与匹配方式」(OI-4) | +| T-09-11-SC | Tampering | npm/pip/cargo installs | low | accept | 无第三方包安装、无依赖安装(纯只读统计,不改 `package.json`) | + + + +- **Task 1**:`09-LEGACY-INTERFACES-AUDIT.md` 存在,含 `## 0.` / `## A. 残余的 legacy 接口` / `## B. 标注 @deprecated 的接口`;含 `A-COUNT:` / `B-COUNT:`;有 `@motajs/legacy-` 与 `@deprecated` 依据;A/B 锚点文件存在且行号在范围内;只读(无 `.ts`/`.tsx` 改动)。 +- **Task 2**:含 `## C. 所有经 core.* 调用的接口` / `## 汇总`;含 `A-COUNT:` / `B-COUNT:` / `C-COUNT:`;含核心成员 `core.status` / `core.formatBigNumber` / `core.material` / `core.floors`;`client-base` 与 `client-modules` 两包均有 `core.*` 锚点;全部锚点有效;只读。 +- **只读守卫**:全程 `git status` 无任何 `.ts`/`.tsx` 改动;`files_modified` 外无生产文件改动。 +- **无全仓门禁**:全程不使用 `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数。 +- **人工复核**:结论写入 `09-11-SUMMARY.md`(含 A/B/C 计数与 OI-1..OI-5 的最终裁定)。 + + + +- 统计范围恰好 `packages-user/client-base` 与 `packages-user/client-modules` 两包(排除 `node_modules`/`dist`)。 +- 文档显式定义 `legacy` 分类口径(A-1..A-7),并逐条给出精确 `file:line` 锚点,无臆造。 +- A(残余 legacy 接口)、B(`@deprecated`,若 0 显式报告 0)、C(`core.*` 调用点)三类均已枚举;含每类计数与汇总表。 +- 全程只读:零 `.ts`/`.tsx` 改动;唯一写入为统计文档 + `09-11-SUMMARY.md`。 +- 产出文档路径经 Task 0 批准;静态门禁(文档结构 / 锚点有效性 / 两包覆盖 / 只读)全绿。 + + +## Artifacts this phase produces + +| 符号 / 路径 | 类型 | 说明 | +|---|---|---| +| `.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md`(新增) | 统计文档 | 第 0 节口径与范围 + A 残余 legacy 接口 + B `@deprecated` + C `core.*` 调用点 + 汇总表 + `A-COUNT:`/`B-COUNT:`/`C-COUNT:`(命名待批准,OI-1) | +| `.planning/phases/09-minimum-browser-runnable/09-11-SUMMARY.md`(新增) | 执行摘要 | 统计范围、分类口径、A/B/C 计数、产出路径、只读确认、OI-1..OI-5 裁定 | + +**命名说明:** 本计划**新增的唯一命名**是产出文档文件名 `09-LEGACY-INTERFACES-AUDIT.md`(连字符命名法);**不引入任何源码命名**,**不改任何既有文件命名**。 + +## Source Coverage Audit + +| 来源 | 项 | 处置 | +|------|----|------| +| GOAL | Phase 9(ROADMAP)「完成渲染端框架,产出可在浏览器运行并验证的最小版本」 | COVERED(增量·任务 5 只读统计子切片:为 legacy 改造提供台账) | +| REQ | Phase 9 ROADMAP「Requirements: TBD」,无需求 ID | N/A(`requirements: []` 如实标注) | +| RESEARCH | 无 RESEARCH.md(本阶段为增量派发,无独立研究产物) | N/A | +| CONTEXT | D-42(范围:恰好两个包) | COVERED(Task 1/2 扫描范围;只读守卫) | +| CONTEXT | D-43①(残余 legacy 接口) | COVERED(Task 1:A 节 A-1..A-7) | +| CONTEXT | D-43②(`@deprecated` 接口) | COVERED(Task 1:B 节;0 则显式报告 0) | +| CONTEXT | D-43③(所有经 `core.*` 调用的接口) | COVERED(Task 2:C 节) | +| CONTEXT | D-44(产出统计文档;路径待批准) | COVERED(Task 0 OI-1 + Task 1/2 产出 `09-LEGACY-INTERFACES-AUDIT.md`) | +| CONTEXT | D-45(只读,不改造) | COVERED(prohibitions + Task 1/2 只读门禁) | +| CONTEXT | D-03 / D-04 / D-06(执行前获批 / 命名获批 / 不扩范围) | COVERED(Task 0 + prohibitions + 范围门禁) | +| CONTEXT | Deferred Ideas | DEFERRED(未纳入任何任务) | +| 缺口 | `data-fallback` 无同名符号 | OPEN(OI-3:归 A-7,待用户确认所指) | + + +Create `.planning/phases/09-minimum-browser-runnable/09-11-SUMMARY.md` when done +