From f480ec704cbb4da0a5ad805ded60699418dc5587 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Fri, 18 Sep 2026 09:40:38 +0800 Subject: [PATCH] docs(04): create phase plan for read-only render/data interface audit --- .planning/ROADMAP.md | 9 +- .../phases/04-render-adaptation/04-01-PLAN.md | 292 ++++++++++++++++++ 2 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 .planning/phases/04-render-adaptation/04-01-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index cd0fe82..245fa52 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -181,7 +181,12 @@ Plans: 3. 移动端(窄屏)布局下,同一场景正常显示且可操作 4. 数据端与渲染端保持双端分离——数据端无 DOM,仍可在 Node 环境跑回放验证 -**Plans**: TBD +**Plans**: 1 plan(第一步·只读对账;本阶段增量规划,后续适配实施与双布局待对账结果出来后另行规划 — 04-CONTEXT D-01/D-02) + +Plans: + +- [ ] 04-01-PLAN.md — 渲染端 ↔ 数据端接口对账(只读清点,产出 `04-RENDER-INTERFACE-AUDIT.md`;按 ① 错配 / ② 数据端缺失 / ③ 多余旧路径 三类登记) + **UI hint**: yes ### Phase 5: Legacy 移植 @@ -375,7 +380,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 | 1. 事件系统 | 13/13 | In Progress| | | 2. 寻路系统 | 5/5 | In Progress| | | 3. 数据端完成 | 19/19 | Complete | 2026-09-12 | -| 4. 渲染适配与双布局 | 0/TBD | Not started | - | +| 4. 渲染适配与双布局 | 0/1 | In Progress| - | | 5. Legacy 移植 | 0/TBD | Not started | - | | 6. 单元测试 | 18/18 | In Progress| | | 7. 数据端缺陷修复 | 15/16 | 暂缓 (Deferred) | - | diff --git a/.planning/phases/04-render-adaptation/04-01-PLAN.md b/.planning/phases/04-render-adaptation/04-01-PLAN.md new file mode 100644 index 0000000..e0c4785 --- /dev/null +++ b/.planning/phases/04-render-adaptation/04-01-PLAN.md @@ -0,0 +1,292 @@ +--- +phase: 04-render-adaptation +plan: 1 +type: execute +wave: 1 +depends_on: [] +files_modified: + - .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md +autonomous: true +requirements: + - REND-01 + - REND-02 +estimate: + tokens: 120000 + raw_tokens: 120000 + tasks: 3 + confidence: low +must_haves: + truths: + - "`.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md` 存在,且含 `07-LOADSTATE-AUDIT.md` 式骨架:「背景 / 方法 / 发现 / 触发序列(举例) / 判定为「匹配」的同类边界 / 未能从阅读确定(未猜测) / 处置」七段,加上独立成节的「② 数据端缺失接口」,共 8 个二级标题" + - "发现表每条记录精确到「接口名 + 所属文件:行 + 分类 + 问题描述 + 影响 + 置信 + 依据」(D-07);分类只取 ① 错配(`#04-01-M-N`)或 ③ 多余旧路径(`#04-01-L-N`),② 数据端缺失另走独立节(D-08)" + - "「② 数据端缺失接口」为独立节,每条以 `### #04-01-G-N:标题(严重度)` 登记并含「现状 / 期望」两段;节末有固定结论行(确认 N 项,或明示本步未确认缺失接口)" + - "每条 `#04-01-M-*` / `#04-01-L-*` 记录的「所属文件:行」锚点指向 `packages-user/client-base` 或 `packages-user/client-modules` 的 tracked 源码行;每条 `#04-01-M-*` 在「依据」列引用至少一个数据端基准文件(`data-common` / `data-base` / `data-system` / `data-state` 的 `src/*.ts`),支持 D-05「以接口签名为准」" + - "已确认走新接口的同类读取(`core.material.*` 渲染侧素材族、`hook` / `loading` 订阅等)登记在「判定为『匹配』的同类边界」,未被误报为错配;静态阅读无法定论的调用链登记在「未能从阅读确定(未猜测)」而非写成缺陷" + - "被查两个渲染端包零改动:`git status --porcelain -- packages-user/client-base packages-user/client-modules` 为空;除本审计文档与 `04-01-PLAN.md` 外不新增任何计划文件(后续适配实施与双布局未规划、未实施)" + - "`## 处置` 登记:本步为只读清点、无生产代码改动;后续步骤由用户在对账结果出来后决定如何拆分;双布局既有资产(`render/use.ts` 的 `Orientation`/`onOrientationChange`、`shared.ts` 布局常量)仅登记为后续起点,不展开实施" + artifacts: + - path: .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md + provides: "渲染端 ↔ 数据端接口对账账本:8 段骨架 + 三分类记录表 + 独立的数据端缺失接口节 + 匹配边界 + 未确定段 + 处置结论;供用户决定后续适配与双布局如何拆分" + key_links: + - "发现表「所属文件:行」列 ↔ `packages-user/client-{base,modules}/src/**` 的 tracked 源码行(经 `git ls-files` 验证,不得指向 gitignored 镜像路径)" + - "每条 `#04-01-M-*` 的「依据」列 ↔ 数据端 `types.ts` / `core.ts` / `ins.ts` 的现行接口签名(D-04/D-05);接口名必须能在基准文件中逐字命中" + - "「判定为『匹配』的同类边界」段 ↔ 04-PATTERNS.md §4 的 A3 组判据(`core.*` 读取先判「数据端状态」还是「渲染侧素材」),防止把素材读成数据端错配" + - "「未能从阅读确定(未猜测)」段 ↔ 07-LOADSTATE-AUDIT.md:48-53 的证据纪律(静态阅读不能定论的链路只登记、不判定)" + - "`## 处置` ↔ 后续步骤的用户决策(D-01):本 run 只交付清点,适配实施与双布局的拆分由用户在对账结果出来后决定" + assumptions: + - "**FLAGGED ASSUMPTION(specless fallback)— REND-01 edge unresolved:** 未提供 REND-01(渲染端适配新数据层接口)的边界/验收判据,探测结果为 `unclassified / unresolved`。本计划**不发明** REND-01 的验收阈值;它只交付供 REND-01 实施阶段消费的只读差异账本。用户须在规划适配工作前补齐 REND-01 的边界判据。" + - "**FLAGGED ASSUMPTION(specless fallback)— REND-02 edge unresolved:** 未提供 REND-02(移动端与桌面端双布局)的边界/验收判据,探测结果为 `unclassified / unresolved`。本计划**不发明** REND-02 的验收阈值;仅在对账文档「处置」段登记既有双布局资产为后续起点,布局实现不在本 run。用户须在规划双布局前补齐 REND-02 的边界判据。" + - "数据端接口签名在本次 `04-PATTERNS.md` 之后可能仍被用户并行修改实现但不改签名(D-05);对账以基准文件的**现行签名**为准,若执行时发现签名已变,以执行当日基准文件为准并在「未能从阅读确定」记录该变更。" + - "审计文档为新增 untracked 文件,`04-PATTERNS.md` 亦为尚未提交的规划产物(`git status` 显示 `??`);本计划的门禁只断言「无新增计划文件」与「被查包零改动」,不对 `.planning` 下其它规划产物的提交状态做断言。" + prohibitions: + - "不得修改或新建 `packages-user/client-base` / `packages-user/client-modules` 下的任何文件——本步是只读清点(D-02/D-09)。" + - "不得规划、设计或实施渲染适配与双布局工作——本 run 只交付只读对账(D-01/D-02);不得新增任何后续步骤的计划文件。" + - "不得写入任何缺少 `file:line` 锚点的记录;静态阅读无法定论的调用链只能进「未能从阅读确定(未猜测)」段,不得写成缺陷或错配。" + - "不得把纯渲染侧读取(如 `core.material.*`、`core.icons.*` 等素材/全局)登记为数据端错配;它们属于「判定为『匹配』的同类边界」。" + - "不得把被查范围扩大到其它包(`packages/**`、`entry-client`、`legacy-plugin-client`、`legacy-plugin-data`、`data-fallback`,以及作为基准的 `data-*` 包本体)(D-03)。" +--- + + +Phase 4 第一步(增量规划,D-01/D-02):对渲染端与数据端做**只读接口对账**,产出 `.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md`,清点所有「渲染端实现 ↔ 数据端现行接口」不匹配项,供用户后续决定剩余工作(适配实施 + 移动端/桌面端双布局)如何拆分。 + +**本 run 只做清点,不改任何代码。** 被查对象限 `packages-user/client-base` 与 `packages-user/client-modules`(D-03);数据端 `data-common` / `data-base` / `data-system` / `data-state` 仅作接口基准(D-04),对账以接口签名为准、不受用户并行修改数据端**实现**的影响(D-05)。 + +三类固定分类(D-06):① 错配(`#04-01-M-N`) ② 数据端缺失(`#04-01-G-N`,独立成节,D-08) ③ 多余旧路径(`#04-01-L-N`)。每条记录精确到接口名,含所属文件 `file:line`、问题描述、影响(D-07)。 + +Purpose: 阶段 4 无法一次规划完毕。先拿到第一手对账账本,才能把「适配实施」与「双布局实施」拆成可执行、可验证的后续计划,避免在未核实接口差异的前提下直接改动渲染端。 + +Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产代码改动)。 + +**UI 说明**:本 run 为只读对账,不产出任何 UI/前端实现产物,不适用 UI-SPEC(`check ui-plan-gate` 因 ROADMAP Phase 4 含「移动端/桌面端布局」词汇而结构性命中,属预期)。Phase 4 的移动端/桌面端双布局 UI 工作属 `## Deferred Ideas`,其 UI-SPEC 应在规划双布局时单独产出;本 run 只在审计文档「处置」段登记既有双布局资产为其起点。 + +**Artifacts this phase produces(本计划产出物)**: + +- **文件**:`.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md`(新建,唯一写入目标)。 +- **章节**(8 个二级标题,下游验证按标题名核对):`## 背景` / `## 方法` / `## 发现` / `## ② 数据端缺失接口`(独立成节,D-08) / `## 触发序列(举例)` / `## 判定为「匹配」的同类边界` / `## 未能从阅读确定(未猜测)` / `## 处置`。 +- **元信息块**(标题下 4 行,对照 07-LOADSTATE-AUDIT.md:3-6):`**日期:**` / `**范围:**`(被查 client-base + client-modules;data-* 为接口基准) / `**性质:**`(只读清点,未修改任何代码) / `**接口基准:**`(各包 `types.ts` / `core.ts` / `ins.ts` 现行签名)。 +- **发现表列**(固定顺序):`| ID | 接口名 | 所属文件:行 | 分类 | 问题描述 | 影响 | 置信 | 依据 |`。 +- **记录 ID 前缀**(下游按前缀检索): + - `#04-01-M-N` —— ① 错配(N 从 1 递增) + - `#04-01-L-N` —— ③ 多余旧路径 + - `#04-01-G-N` —— ② 数据端缺失,独立节内以 `### #04-01-G-N:标题(严重度)` + `- **现状**:` / `- **期望**:` 登记 +- **② 节结论行**(固定写法,必须出现其一):`**②节结论:** 本步确认 N 项数据端缺失接口(见上)` 或 `**②节结论:** 本步未确认数据端缺失接口;相关不确定项见「未能从阅读确定(未猜测)」`。 +- **`## 处置` 必备内容**:本步为只读清点、无生产代码改动;后续适配实施与移动端/桌面端双布局**未在本 run 规划**,由用户在对账结果出来后决定拆分;双布局既有资产(`render/use.ts` 的 `Orientation`/`onOrientationChange`、`shared.ts` 的 `MAP_BLOCK_WIDTH`/`STATUS_BAR_WIDTH`/`MAIN_WIDTH` 等布局常量)仅登记为后续起点,不展开。 + +## Source Audit(多源覆盖审计) + +| SOURCE | ID | Feature/Requirement | Plan | Status | Notes | +|--------|----|---------------------|------|--------|-------| +| GOAL | — | Phase 4:「渲染端通过新数据层接口驱动,并同时支持移动端与桌面端布局」 | 04-01 | COVERED(仅第一步) | D-01 增量规划:本 run 只规划第一步(只读对账);适配实施与双布局属 CONTEXT.md `## Deferred Ideas`,待对账结果出来后另行规划 | +| REQ | REND-01 | 渲染端适配新数据层接口 | 04-01 | COVERED(仅清点) | 本 run 交付 REND-01 的差异账本,不实施适配;REND-01 验收边界未提供 → 见 assumptions 的 FLAGGED ASSUMPTION | +| REQ | REND-02 | 渲染端同时支持移动端与桌面端布局 | 04-01 | COVERED(仅登记资产) | 本 run 只登记双布局既有资产为后续起点(04-PATTERNS.md §7);布局实现属 Deferred | +| CONTEXT | D-01 | 增量规划,本次只锁定第一步 | 04-01 | COVERED | 04-01 即第一步;不产出后续步骤计划 | +| CONTEXT | D-02 | 交付物为审计文档;该步只读 | 04-01 | COVERED | `files_modified` 仅审计文档;只读门禁:`git status --porcelain -- packages-user/client-base packages-user/client-modules` 为空 | +| CONTEXT | D-03 | 被查对象限 client-base + client-modules | 04-01 | COVERED | 范围外路径不登记为被查项 | +| CONTEXT | D-04 | data-* 仅作接口基准 | 04-01 | COVERED | 基准文件为各包 `types.ts` / `core.ts` / `ins.ts` 等 | +| CONTEXT | D-05 | 以接口为准,不受实现变动影响 | 04-01 | COVERED | 每条 `#04-01-M-*` 的「依据」列须引用数据端基准文件 | +| CONTEXT | D-06 | 三类划分 | 04-01 | COVERED | 三个 ID 前缀一一对应 | +| CONTEXT | D-07 | 精确到接口名 + 文件 + 描述 + 影响 | 04-01 | COVERED | 发现表列固定;门禁要求每条含 `file:line` | +| CONTEXT | D-08 | 单文档分节;缺失接口独立成节 | 04-01 | COVERED | `## ② 数据端缺失接口` 独立节 + 固定结论行 | +| CONTEXT | D-09 | 允许只读子代理 | 04-01 | COVERED | Task 2/3 允许派只读子代理分派 A1..A7 扫描组,仅回传文本,不得写文件 | +| RESEARCH | — | (本阶段无 RESEARCH.md) | — | N/A | Phase 4 未产出 RESEARCH.md,无研究项需覆盖 | + + + +@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md +@C:/Users/book/.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-PATTERNS.md +@.planning/phases/03-data-completion/03-CONTEXT.md +@.planning/phases/07-data-fixes/07-LOADSTATE-AUDIT.md +@.planning/phases/06-unit-tests/06-TEST-FINDINGS.md +@.planning/phases/06-unit-tests/06-COVERAGE-GAPS.md +@.planning/phases/02-pathfinding/02-INTERFACE-DRAFT.md +@AGENTS.md +@dev.md + + + + + + Task 1(tracer):审计文档骨架端到端贯通 —— 8 段结构 + 三分类各一条实测记录 + 结构/ID 门禁转绿 + .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md + + - .planning/phases/07-data-fixes/07-LOADSTATE-AUDIT.md(全文件:章节骨架、方法段、「触发序列」、「判定为安全/匹配的同类边界」、「未能从阅读确定(未猜测)」、处置段写法) + - .planning/phases/06-unit-tests/06-TEST-FINDINGS.md:7-18(字段定义表)与 :24-30(分节表格写法) + - .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md:10-13(`### G-xx:标题(严重度)` + 现状 / 期望 骨架) + - .planning/phases/02-pathfinding/02-INTERFACE-DRAFT.md:3-5(「接口事实源」声明块写法) + - .planning/phases/04-render-adaptation/04-PATTERNS.md(§1 章节骨架表与发现表字段、§4 A3 锚点表、§5 A4 新接口对照面) + - .planning/phases/04-render-adaptation/04-CONTEXT.md(D-01..D-09、Deferred Ideas) + - packages-user/data-state/src/types.ts(ICoreState 基准,逐字比对用) + - packages-user/client-base/src/types.ts(`IClientBase extends ICoreState` 桥头) + - packages-user/client-modules/src/action/move.ts:1-6(`// @ts-expect-error 需要重构` + `import { HeroMover, IMoveController } from '@user/data-state'`) + - packages-user/client-modules/src/render/ui/main.tsx:28-30,99-128(新旧接口同文件并存) + - packages-user/client-modules/src/render/map/renderer.ts:33(`IGameMap` / `IGameMapHooks` / `IMapLayer` 直连) + - dev.md(「双端分离」:`@user/client-base` 为系统层、`@user/client-modules` 为实现层) + + + (1) 新建 `04-RENDER-INTERFACE-AUDIT.md`,先写标题与 4 行元信息块(`**日期:** 2026-09-18`;`**范围:**` 被查 `packages-user/client-base` + `packages-user/client-modules`、`data-*` 为接口基准;`**性质:** 只读清点,未修改任何代码`;`**接口基准:**` 各包 `types.ts` / `core.ts` / `ins.ts` 的现行签名,D-04/D-05)。 + (2) 写 `## 背景`:REND-01 / REND-02、D-01 增量规划、本次只清点不实施、以及「对账以接口为准、不受实现变动影响」的理由。 + (3) 写 `## 方法`:枚举面 = 04-PATTERNS.md 的 A1..A7 七组;判定口径 = 每条 `core.*` 读取先判「读的是数据端状态」还是「渲染侧素材/全局」;证据纪律 = 每条含 `file:line`、静态阅读不能定论者进「未能从阅读确定」;只读约束;并**实际执行** `git status --porcelain -- packages-user/client-base packages-user/client-modules`,把输出(预期为空)记入本节作为「扫描前基线」;写明允许只读子代理(D-09:仅回传文本、不得写文件)。 + (4) 写 `## 发现` 表头(列序固定:ID / 接口名 / 所属文件:行 / 分类 / 问题描述 / 影响 / 置信 / 依据),并**实测**填入每类各一条(不得直接照抄 04-PATTERNS.md 的锚点定性,必须打开基准文件核对): + - ① 错配 `#04-01-M-01`:以 `packages-user/client-modules/src/action/move.ts:3`(`// @ts-expect-error 需要重构` + `import { HeroMover, IMoveController } from '@user/data-state'`)为起点,打开 `packages-user/data-state/src/types.ts`(必要时含该包 barrel)逐字确认这两个符号是否仍导出、形状/签名是否已变;「依据」列必须写出基准文件的 `file:line`。 + - ③ 多余旧路径 `#04-01-L-01`:以 `packages-user/client-modules/src/render/ui/main.tsx:99-128` 的 legacy `core.status.*` / `core.isReplaying()` 读取为准,判定其应由 `ICoreState`(`packages-user/data-state/src/types.ts`)的哪个成员取代;「依据」列写出该成员的基准 `file:line`。 + 若执行时锚点已漂移、或该读取已迁到新接口,改取同组其它锚点(同文件其它行或 04-PATTERNS.md §4/§5 的其它锚点),并在「未能从阅读确定」段记录替换原因;不得把未核实项写成缺陷。 + (5) 写 `## ② 数据端缺失接口`:按 `### #04-01-G-N:标题(严重度)` + `- **现状**:` / `- **期望**:` 登记**经阅读确认**的「渲染端需要而数据端未提供」项;若阅读后确认不存在此类项,则本节不登记条目,改为写「本步未确认数据端缺失接口」的说明。节末**必须**写结论行,取以下之一:`**②节结论:** 本步确认 N 项数据端缺失接口(见上)` 或 `**②节结论:** 本步未确认数据端缺失接口;相关不确定项见「未能从阅读确定(未猜测)」`。不得为满足门禁而臆造缺失项。 + (6) 写 `## 触发序列(举例)`(至少 1 条:渲染端调用 → 按旧形状解读 → 结果偏离的链路)、`## 判定为「匹配」的同类边界`(至少登记 `core.material.*` 素材族为何不算数据端错配,并给出判据)、`## 未能从阅读确定(未猜测)`(本 tracer 阶段至少登记「② 节是否有缺失项」的不确定性来源)、`## 处置`(含:本步只读;后续适配实施与双布局未在本 run 规划、由用户在对账结果出来后决定拆分;双布局既有资产 `packages-user/client-modules/src/render/use.ts` 的 `Orientation` / `onOrientationChange` 与 `packages-user/client-modules/src/shared.ts` 的布局常量仅登记为后续起点,不展开)。 + (7) 全程不得修改任何被查源码;本任务只写审计文档一个文件。 + + + node -e "const fs=require('fs');const p='.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md';const t=fs.readFileSync(p,'utf8');const need=['## \u80cc\u666f','## \u65b9\u6cd5','## \u53d1\u73b0','## \u2461 \u6570\u636e\u7aef\u7f3a\u5931\u63a5\u53e3','## \u89e6\u53d1\u5e8f\u5217\uff08\u4e3e\u4f8b\uff09','## \u5224\u5b9a\u4e3a\u300c\u5339\u914d\u300d\u7684\u540c\u7c7b\u8fb9\u754c','## \u672a\u80fd\u4ece\u9605\u8bfb\u786e\u5b9a\uff08\u672a\u731c\u6d4b\uff09','## \u5904\u7f6e'];const miss=need.filter(h=>t.indexOf(h)<0);if(miss.length>0){console.error('MISSING HEADINGS '+miss.length);process.exit(1)}const rows=t.split(/\r?\n/).filter(l=>/^\|\s*#04-01-[ML]-\d+\s*\|/.test(l));const bad=rows.filter(l=>!/:\d+/.test(l));if(rows.length<2||bad.length>0){console.error('BAD FINDING ROWS '+rows.length+'/'+bad.length);process.exit(1)}if(t.indexOf('#04-01-M-')<0||t.indexOf('#04-01-L-')<0){console.error('MISSING CATEGORY PREFIX');process.exit(1)}if(t.indexOf('\u2461\u8282\u7ed3\u8bba')<0){console.error('GAP SECTION WITHOUT CONCLUSION');process.exit(1)}console.log('OK headings 8 findingRows '+rows.length)" + non-zero exit, 或 stderr 含 "MISSING HEADINGS" / "BAD FINDING ROWS" / "MISSING CATEGORY PREFIX" / "GAP SECTION WITHOUT CONCLUSION" + + + - 审计文档存在于约定路径,且 8 个二级标题逐字存在(`## 背景` / `## 方法` / `## 发现` / `## ② 数据端缺失接口` / `## 触发序列(举例)` / `## 判定为「匹配」的同类边界` / `## 未能从阅读确定(未猜测)` / `## 处置`) + - 发现表列序为 `ID | 接口名 | 所属文件:行 | 分类 | 问题描述 | 影响 | 置信 | 依据`,且至少含 1 条 `#04-01-M-*` 与 1 条 `#04-01-L-*`,每条都带 `file:line` 锚点 + - `#04-01-M-01` 的「依据」列引用 `packages-user/data-state/src/types.ts`(或该包基准)的具体行,且其定性来自实际阅读而非锚点照抄 + - 「② 数据端缺失接口」节存在且含固定结论行(`②节结论`) + - `## 方法` 记录了 `git status --porcelain -- packages-user/client-base packages-user/client-modules` 的扫描前基线输出 + - 被查两个渲染端包零改动 + + 审计文档骨架与三分类各一条实测记录端到端贯通,结构/ID 门禁转绿;后续 Task 2/3 只需在同一模板上横向补齐,无需再改结构 + + + + Task 2:① 错配全量清点 —— 数据端 import / 契约桥 / 组合根继承 / 类型直连逐字比对 + 触发序列 + .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md + + - .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md(Task 1 产出的现有内容,在同一模板上追加) + - .planning/phases/04-render-adaptation/04-PATTERNS.md(§2 A1 契约桥、§3 A2 组合根/单例、§5 A4 新接口对照面、§6 A5 类型直连;「既有重构标记的处置口径」) + - packages-user/data-common/src/types.ts(L0 `IDataCommon` 基准) + - packages-user/data-base/src/types.ts(L1 `IStateBase` 与 `IGameMap` / `IMapLayer` / `IGameMapHooks` 基准) + - packages-user/data-system/src/types.ts(L2 `IStateSystem` 基准) + - packages-user/data-state/src/types.ts(L3 `ICoreState` 基准) + - packages-user/data-common/src/replay/types.ts 与 packages-user/data-common/src/store/types.ts(录像/图块 raw-data 契约基准) + - packages-user/client-base/src/types.ts(`IClientBase extends ICoreState`)与 packages-user/client-modules/src/types.ts(实现层契约 extends 系统层契约) + - packages-user/client-modules/src/client.ts:46(`export class ClientCore extends CoreState implements IClientCore`)与 packages-user/client-modules/src/core.ts:1-6(单例 + 既有重构 TODO) + - packages-user/client-modules/src/render/map/{renderer,moving,element,status,vertex,types}.ts、packages-user/client-modules/src/render/elements/props.ts、packages-user/client-modules/src/render/map/extension/hero.ts(数据端类型/契约直连与 `@ts-expect-error 需要重构` 标记) + + + (1) 枚举被查两包内所有 `@user/data-common|data-base|data-system|data-state` 的 import(含 `import type`),逐处打开基准文件比对**接口名、成员、参数/返回签名**是否仍成立:A1 契约桥(`IClientBase extends ICoreState` 后 `ICoreState` 新增/改名/删成员会使桥断裂)、A2 组合根(`ClientCore extends CoreState` 的 override 签名、`loading.once('coreInit')` 生命周期、`core.firstData.name` 读取点)、A5 类型直连(`IGameMap` / `IMapLayer` / `IGameMapHooks` / `ISaveableContent` / `IHeroMoveController` 等)。 + (2) 逐条登记为 `#04-01-M-N`(N 从 2 递增,`M-01` 已在 Task 1 占用):填入 接口名 / 所属文件:行 / 分类=`① 错配` / 问题描述(旧形状或旧签名具体差在哪)/ 影响 / 置信(高/中/低)/ 依据(基准文件 `file:line`)。**一条记录只归一类**;跨类则拆条。 + (3) 带 `// @ts-expect-error 需要重构` 的 import(`action/move.ts:3`、`render/map/extension/hero.ts:5,7,9`、`render/ui/main.tsx:28`)是强线索但**不是结论**:必须与基准文件实签核对后才定性;核对后仍成立的保持「匹配」并写入边界段,核对后发现签名已变的登记为 `#04-01-M-*`。 + (4) 把最高置信的 1–3 条错配的「调用 → 按旧形状解读 → 结果偏离」链路写进 `## 触发序列(举例)`(格式对照 07-LOADSTATE-AUDIT.md:29-35)。 + (5) 若某 import 的定性无法从静态阅读确定(例如依赖运行时形状、或基准文件正在被用户并行改动),写入 `## 未能从阅读确定(未猜测)`,**不得**登记为错配。 + (6) 允许派只读子代理分派 A1/A2/A4/A5 扫描组(D-09),子代理只回传文本,**不得写文件**;主执行者负责汇总与定性一致性。 + (7) 只修改审计文档;不得改动任何生产源码,不得新增计划文件。 + + + node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md','utf8');const rows=t.split(/\r?\n/).filter(l=>/^\|\s*#04-01-M-\d+\s*\|/.test(l));if(rows.length===0){console.error('NO MISMATCH ROWS');process.exit(1)}const noAnchor=rows.filter(l=>!/:\d+/.test(l));const noBase=rows.filter(l=>!/data-(common|base|system|state)\/src\//.test(l));if(noAnchor.length>0){console.error('MISMATCH ROW WITHOUT ANCHOR '+noAnchor.length);process.exit(1)}if(noBase.length>0){console.error('MISMATCH ROW WITHOUT BASELINE '+noBase.length);process.exit(1)}console.log('OK mismatch rows '+rows.length)" + non-zero exit, 或 stderr 含 "NO MISMATCH ROWS" / "MISMATCH ROW WITHOUT ANCHOR" / "MISMATCH ROW WITHOUT BASELINE" + + + - 每条 `#04-01-M-*` 记录都含 `file:line` 锚点(指向 `packages-user/client-base` 或 `packages-user/client-modules`) + - 每条 `#04-01-M-*` 的「依据」列引用至少一个 `data-common|data-base|data-system|data-state` 的 `src/*.ts` 基准文件 + - A1 契约桥、A2 组合根、A5 类型直连三组均有实际比对结论(登记为错配或写明为匹配边界),A4 新接口调用作为「匹配」判据进入边界段 + - `## 触发序列(举例)` 至少含 1 条错配链路,且与发现表中的 `#04-01-M-*` 对应 + - 无法定论的 import 已进入「未能从阅读确定(未猜测)」,未被写成错配 + - 被查两个渲染端包零改动;未新增任何计划文件 + + ① 错配在 A1/A2/A4/A5 四组上全量清点完毕,每条可追溯到接口名与基准 `file:line`;触发序列与边界段同步更新 + + + + Task 3:③ 多余旧路径全量清点 + ② 缺失节收口 + 匹配边界/未确定/处置定稿 + 只读与范围门禁 + .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md + + - .planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md(Task 1/2 产出,做定稿而非重写) + - .planning/phases/04-render-adaptation/04-PATTERNS.md(§4 A3 legacy `core.*` 读取锚点表与判定口径、§7 A6 双布局既有资产、Shared Patterns「分类口径」「证据纪律」「只读约束」) + - .planning/phases/07-data-fixes/07-LOADSTATE-AUDIT.md:37-46(「判定为安全/匹配的同类边界」写法)与 :48-53(「未能从阅读确定(未猜测)」写法) + - packages-user/data-base/src/game.ts:155,166,266-267(`hook`、`GameListener`、`@deprecated gameListener`) + - packages-user/data-state/src/core.ts(顶层装配与 legacy bridge 落点)、packages-user/data-state/src/ins.ts(`state` 单例) + - packages-user/entry-data/src/mota.ts:125-136(`r()` / `rf()` 渲染调用门控) + - packages-user/data-system/src/path/types.ts 与 packages-user/data-state/src/types.ts(判定 legacy 读取的替代接口目标) + - packages-user/client-modules/src/action/move.ts:66-67,97,123,156、packages-user/client-modules/src/render/ui/{main,statistics,viewmap,settings,save,toolbar,statusBar}.tsx、packages-user/client-modules/src/render/components/choices.tsx、packages-user/client-modules/src/fallback/load.ts、packages-user/client-modules/src/render/utils/saves.ts(A3 锚点面) + - packages-user/client-base/src/load/loader.ts:103,129,151,167,188,284,418 与 packages-user/client-modules/src/render/elements/{cache,misc}.ts、packages-user/client-modules/src/render/components/misc.tsx(渲染侧素材族,用于「匹配」判据) + - packages-user/client-modules/src/render/use.ts:22-52 与 packages-user/client-modules/src/shared.ts:33-97(双布局既有资产) + + + (1) 按 04-PATTERNS.md §4 的 A3 锚点表逐处核对 legacy `core.*` 读取,对每处先判定「读的是数据端状态」还是「渲染侧素材/全局」: + - 数据端状态类(如 `core.isReplaying()` / `core.isPlaying()` / `core.status.*` / `core.getNextLvUpNeed()` / `core.itemCount()` / `core.getLvName()` / `core.maps.*` / `core.flags.*` / `core.firstData.*` / `core.startGame()` / `core.status.replay.*`)→ 登记为 `#04-01-L-N`(N 从 2 递增,`L-01` 已在 Task 1 占用),分类=`③ 多余旧路径`,并在「依据」列写出应取代它的新接口/基准 `file:line`; + - 纯渲染侧素材/全局(`core.material.images.*`、`core.materials`、`core.icons.icons` 等)→ **不登记为缺陷**,写入 `## 判定为「匹配」的同类边界` 并给出判据(对照 04-PATTERNS.md 「不得因出现 `core.` 就一律登记」)。 + 每条记录含 接口名 / 所属文件:行 / 分类 / 问题描述 / 影响 / 置信 / 依据。 + (2) 若同一处 legacy 读取同时是「形状已变」而非单纯旧路径,按「一条只归一类」拆条(错配归 `#04-01-M-*`,旧路径归 `#04-01-L-*`),并在两条之间互相引用 ID。 + (3) `## ② 数据端缺失接口` 定稿:逐条确认/补全 `### #04-01-G-N` 的「现状 / 期望」;最终结论行取固定两式之一。凡不能确认的候选一律不登记为缺失项,转入「未能从阅读确定(未猜测)」。 + (4) 定稿 `## 判定为「匹配」的同类边界`(至少覆盖 `core.material.*` 素材族、`hook`/`loading` 订阅新接口用法),定稿 `## 未能从阅读确定(未猜测)`(逐条说明为何静态阅读不能定论),定稿 `## 处置`(本步只读、零生产改动;后续适配与双布局未在本 run 规划、由用户决定拆分;`render/use.ts` 的 `Orientation`/`onOrientationChange` 与 `shared.ts` 布局常量登记为后续双布局起点,不展开实施)。 + (5) 全表 ID 唯一性自检:`#04-01-M-*` / `#04-01-L-*` / `#04-01-G-*` 各自序号连续且不重复;每条分类列与 ID 前缀一致(M=① 错配、L=③ 多余旧路径、G=② 数据端缺失)。 + (6) 门禁与提交:运行只读门禁与范围门禁(见 ``);随后以 `docs(04-01): 渲染端 ↔ 数据端接口对账(只读清点,D-01 第一步)` 提交**仅**审计文档,不得提交任何被查源码改动,不得新增后续步骤的计划文件。 + + + node -e "const fs=require('fs');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md','utf8');const rows=t.split(/\r?\n/).filter(l=>/^\|\s*#04-01-L-\d+\s*\|/.test(l));if(rows.length===0){console.error('NO LEGACY ROWS');process.exit(1)}const bad=rows.filter(l=>!/:\d+/.test(l));if(bad.length>0){console.error('LEGACY ROW WITHOUT ANCHOR '+bad.length);process.exit(1)}const lines=t.split(/\r?\n/);const gh=lines.map((l,i)=>({l:l.trim(),i:i})).filter(o=>/^### #04-01-G-\d+/.test(o.l));for(const g of gh){const body=lines.slice(g.i+1,g.i+7).join('\n');if(body.indexOf('\u73b0\u72b6')<0||body.indexOf('\u671f\u671b')<0){console.error('GAP ENTRY MISSING FIELDS');process.exit(1)}}if(t.indexOf('\u2461\u8282\u7ed3\u8bba')<0){console.error('GAP SECTION WITHOUT CONCLUSION');process.exit(1)}console.log('OK legacy rows '+rows.length+' gaps '+gh.length)" + non-zero exit, 或 stderr 含 "NO LEGACY ROWS" / "LEGACY ROW WITHOUT ANCHOR" / "GAP ENTRY MISSING FIELDS" / "GAP SECTION WITHOUT CONCLUSION" + git status --porcelain -- packages-user/client-base packages-user/client-modules + stdout 非空(任一被查渲染端包出现改动/新增行)—— 违反只读约束 + node -e "const cp=require('child_process');const out=cp.execSync('git status --porcelain -- .planning/phases/04-render-adaptation',{encoding:'utf8'});const extra=out.split(/\r?\n/).filter(l=>/\d{2}-\d{2}-PLAN\.md/.test(l)&&l.indexOf('04-01-PLAN.md')<0);if(extra.length>0){console.error('UNEXPECTED PLAN FILES '+extra.length);process.exit(1)}console.log('OK plan scope')" + non-zero exit, 或 stderr 含 "UNEXPECTED PLAN FILES"(出现了 04-01 以外的计划文件) + + + - A3 锚点表的每一处 `core.*` 读取都已判定并落位:数据端状态类登记为 `#04-01-L-*`、素材类进入「判定为『匹配』的同类边界」,无遗漏、无误报 + - 每条 `#04-01-L-*` 含 `file:line` 锚点,并在「依据」列指出应取代它的新接口/基准位置 + - 「② 数据端缺失接口」节定稿:条目(如有)均含「现状 / 期望」,且节末结论行取固定两式之一;未确认候选在「未能从阅读确定(未猜测)」中逐条列出 + - `## 判定为「匹配」的同类边界` / `## 未能从阅读确定(未猜测)` / `## 处置` 三段均非空且符合 07-LOADSTATE-AUDIT 的写法;`## 处置` 含双布局资产登记与「后续步骤未在本 run 规划」的明确表述 + - ID 唯一且前缀与分类列一一对应(M=① 错配、L=③ 多余旧路径、G=② 数据端缺失) + - `git status --porcelain -- packages-user/client-base packages-user/client-modules` 为空;`.planning/phases/04-render-adaptation` 下无 04-01 以外的计划文件 + - 审计文档已以 `docs(04-01)` 提交,提交内容仅含该文档 + + 三类记录全部落位且互斥、匹配边界与未确定段定稿、缺失节收口、只读与范围门禁全绿、审计文档已提交;用户可据此决定阶段 4 剩余工作的拆分 + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| 数据端接口基准 → 审计文档 | 只读引用 `data-*` 的 `types.ts` / `core.ts` / `ins.ts`;基准不变,仅记录差异 | +| 渲染端源码 → 审计文档 | 只读引用被查两包源码;不得产生任何写回 | +| 执行者 → 仓库工作树 | 本 run 唯一允许写入的文件是审计文档;被查渲染端包必须保持零改动 | +| 审计文档 → 后续适配计划 | 「处置」段的结论被下游用户/计划消费,错报会直接污染阶段 4 的拆分决策 | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan | +|-----------|----------|-----------|----------|-------------|-----------------| +| T-04-01 | Tampering | 被查渲染端包 `packages-user/client-base` / `client-modules` | high | mitigate | Task 1–3 均为只读;Task 3 门禁 `git status --porcelain -- packages-user/client-base packages-user/client-modules` 必须为空,非空即失败 | +| T-04-02 | Repudiation | 发现表记录(无锚点则不可追溯) | medium | mitigate | 每条记录强制含 `file:line`;`#04-01-M-*` 强制在「依据」列引用数据端基准文件;由 Task 2/3 的 `` 门禁机器判定 | +| T-04-03 | Spoofing | 「判定为『匹配』的同类边界」段 | medium | mitigate | 该段必须给出判据(`core.material.*` 素材族 vs 数据端状态),且「未能从阅读确定」段为强制段——不得把未核实项伪装成匹配或缺陷 | +| T-04-04 | Elevation of Privilege | 被查范围(`packages/**`、`entry-client`、`legacy-plugin-*`、`data-fallback`、`data-*` 本体) | medium | mitigate | 范围由 D-03/D-04 限定;范围外路径不登记为被查项,只能作为理解接线方式的参考 | +| T-04-05 | Information Disclosure | 审计文档引用的源码行与接口名 | low | accept | 记录只含接口名、文件行号、问题描述与影响,不含凭据/密钥;如需提及敏感常量仅以标识符呈现 | +| T-04-06 | Denial of Service | 只读子代理越权写入(D-09) | low | mitigate | Task 2/3 明确子代理仅回传文本、不得写文件;最终由主执行者的只读门禁统一验证 | +| T-04-SC | Tampering | npm / pnpm 依赖安装 | high | mitigate | 本计划零依赖变更、不修改任何 `package.json`;出现安装需求即暂停并要求用户确认包合法性(blocking human checkpoint),不得自动继续 | + + + +1. 结构门禁(Task 1):审计文档 8 个二级标题逐字存在,`#04-01-M-*` / `#04-01-L-*` 各至少 1 条且每条含 `file:line`,「② 数据端缺失接口」节含固定结论行。 +2. 错配门禁(Task 2):每条 `#04-01-M-*` 含 `file:line` 且「依据」列引用 `data-common|data-base|data-system|data-state` 的 `src/*.ts`。 +3. 旧路径与缺失节门禁(Task 3):每条 `#04-01-L-*` 含 `file:line`;每个 `### #04-01-G-*` 之后紧跟的 6 行内含「现状」「期望」;② 节结论行存在。 +4. 只读门禁(Task 3):`git status --porcelain -- packages-user/client-base packages-user/client-modules` 输出为空。 +5. 范围门禁(Task 3):`.planning/phases/04-render-adaptation` 下除 `04-01-PLAN.md` 外无其它 `*-PLAN.md`(后续步骤未被规划)。 +6. 人工核对:`## 判定为「匹配」的同类边界` 的素材族判据、`## 未能从阅读确定(未猜测)` 的逐条理由、`## 处置` 的双布局资产登记与「后续步骤未在本 run 规划」表述均齐备。 +7. 提交:`docs(04-01)` 仅含审计文档。 + + + +- `.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md` 按 8 段骨架产出,三类记录(① 错配 `#04-01-M-*` / ② 数据端缺失 `#04-01-G-*`(独立节)/ ③ 多余旧路径 `#04-01-L-*`)互斥且完整,每条精确到接口名 + `file:line` + 描述 + 影响(D-06/D-07/D-08)。 +- 对账以数据端接口签名为基准(D-04/D-05),每条错配可追溯到基准文件行;未受用户并行修改实现的影响。 +- 已确认匹配的读取(`core.material.*` 素材族、`hook`/`loading` 订阅)进入边界段而非误报;无法定论的链路进入「未能从阅读确定(未猜测)」而非写成缺陷。 +- 被查两个渲染端包零改动;本 run 只新增审计文档一个文件,未规划、未实施后续适配与双布局(D-01/D-02/D-03)。 +- 双布局既有资产已在「处置」段登记为后续起点(REND-02 的已知落点),且明确「验收边界待用户补齐」(REND-01/REND-02 的 specless fallback flagged assumptions)。 + + + +Create `.planning/phases/04-render-adaptation/04-01-SUMMARY.md` when done + +