diff --git a/.planning/phases/04-render-adaptation/04-01-PLAN.md b/.planning/phases/04-render-adaptation/04-01-PLAN.md index 19ba6bb..8f83006 100644 --- a/.planning/phases/04-render-adaptation/04-01-PLAN.md +++ b/.planning/phases/04-render-adaptation/04-01-PLAN.md @@ -11,13 +11,13 @@ requirements: - REND-01 - REND-02 estimate: - tokens: 120000 - raw_tokens: 120000 + tokens: 62000 + raw_tokens: 62000 tasks: 3 confidence: low must_haves: truths: - - "`.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md` 存在,且含 `07-LOADSTATE-AUDIT.md` 式骨架:「背景 / 方法 / 发现 / 触发序列(举例) / 判定为「匹配」的同类边界 / 未能从阅读确定(未猜测) / 处置」七段,加上独立成节的「② 数据端缺失接口」,共 8 个二级标题" + - "`.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md` 存在,且含 `07-LOADSTATE-AUDIT.md` 式骨架:「背景 / 方法 / 发现 / 触发序列(举例) / 判定为「匹配」的同类边界 / 未能从阅读确定(未猜测) / 处置」七段,加上独立成节的「② 数据端缺失接口」,共 8 个二级标题;全文为 CRLF 换行(dev.md「其他要求」)" - "发现表每条记录精确到「接口名 + 所属文件:行 + 分类 + 问题描述 + 影响 + 置信 + 依据」(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「以接口签名为准」" @@ -28,7 +28,7 @@ must_haves: - 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 镜像路径)" + - "发现表「所属文件:行」列 ↔ `packages-user/client-{base,modules}/src/**` 的 tracked 源码行(不得指向 gitignored 镜像路径;由 Task 3 `` 的「锚点可追溯门禁」实际执行 `git ls-files packages-user/client-base packages-user/client-modules` 校验审计文档引用的全部 client 路径)" - "每条 `#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 的证据纪律(静态阅读不能定论的链路只登记、不判定)" @@ -89,6 +89,27 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 | 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,无研究项需覆盖 | + +## Estimate Basis(估算依据 — revision 2026-09-18) + +`estimate-check` 初报 `tokens: 120000` 超出 `smart_zone_tokens` 100000 预算(ratio 1.20,`confidence: low`,`sample_count: 0`)。本计划按「执行者实际触及量」重测(chars/4;`estimate-calibration` factor 1.0,项目无历史样本,故 `confidence` 仍为 low),并在本次修订中把重型整文件读取改为**强制委派**,使单计划落在预算内: + +| 部分 | 口径 | chars | ≈tokens | +|------|------|-------|---------| +| Task 1 读 + 写 | 结构参考文件 + 基准 `types.ts` + 骨架与两条实测记录 | ~53k | ~13k | +| Task 2 读 + 写 | 契约桥 / 组合根 / 类型直连基准 + 子代理事实表 | ~49k | ~12k | +| Task 3 读 + 写 | legacy 锚点切片 + 素材匹配判据 + ②节与处置定稿 | ~61k | ~15k | +| 三项任务固定开销 | 计划上下文 / 校验命令 / 编辑 | — | ~9k | +| **合计** | | | **~49k–62k** | + +**为何 120000 不可直接采信(不可操作的原因):** 初报值来自「全量整文件读」的朴素加总(被查文件全量约 450k chars ≈ 126k tokens),它假设执行者亲自读完整文件;但本计划按 D-09 把重型整文件组**强制**交由只读子代理(详见 Task 2 action (6) 与 Task 3 action (1)): + +- Task 2 委派组:`render/map/{renderer,vertex,types,moving,element,status}.ts`、`render/elements/props.ts`、`render/map/extension/hero.ts`; +- Task 3 委派组:`render/ui/{main,statistics,viewmap,settings,save,toolbar,statusBar}.tsx`、`render/components/{choices,misc}.tsx`、`render/utils/saves.ts`、`fallback/load.ts`、`render/elements/{cache,misc}.ts`、`client-base/src/load/loader.ts`。 + +子代理只回传「接口名 + 所属 `file:line` + 数据端基准签名」或「legacy 调用 + 所属 `file:line` + 建议替代接口」事实表(不贴大段源码、不写文件),执行者据事实表定性并登记,因此执行者上下文是上表而非全量读之和。审计覆盖面(A1..A7)不变,仅读法改变。 + +**为何不拆分为多计划:** D-01/D-02 锁定本次第一步为**单一**只读对账计划(04-01,交付物 `04-RENDER-INTERFACE-AUDIT.md`);拆分会违背用户决策。故对 `scope_sanity` 的非阻塞建议走「重测 + 强制委派(D-09)」路线而非 re-slice:`budget` 这一属性由**执行者上下文**满足,本计划的封面估算已按该口径给出。 @@ -132,7 +153,7 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 - 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)。 + (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)。**全文使用 CRLF 换行**(dev.md「其他要求」:换行使用 `CRLF` 格式);Task 2/3 追加内容同样保持 CRLF,不得出现孤立 `LF`。 (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 的锚点定性,必须打开基准文件核对): @@ -147,6 +168,8 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 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" + node -e "const fs=require('fs');const p='.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md';const s=fs.readFileSync(p,'utf8');const lf=(s.match(/\n/g)||[]).length;const crlf=(s.match(/\r\n/g)||[]).length;if(lf!==crlf){console.error('NON-CRLF LINE ENDINGS '+(lf-crlf));process.exit(1)}console.log('OK CRLF lines '+crlf)" + non-zero exit, 或 stderr 含 "NON-CRLF LINE ENDINGS"(审计文档出现非 CRLF 换行,违反 dev.md「换行使用 CRLF 格式」) - 审计文档存在于约定路径,且 8 个二级标题逐字存在(`## 背景` / `## 方法` / `## 发现` / `## ② 数据端缺失接口` / `## 触发序列(举例)` / `## 判定为「匹配」的同类边界` / `## 未能从阅读确定(未猜测)` / `## 处置`) @@ -154,6 +177,7 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 - `#04-01-M-01` 的「依据」列引用 `packages-user/data-state/src/types.ts`(或该包基准)的具体行,且其定性来自实际阅读而非锚点照抄 - 「② 数据端缺失接口」节存在且含固定结论行(`②节结论`) - `## 方法` 记录了 `git status --porcelain -- packages-user/client-base packages-user/client-modules` 的扫描前基线输出 + - 审计文档全文为 CRLF 换行(dev.md「其他要求」),Task 1 的 CRLF 门禁转绿 - 被查两个渲染端包零改动 审计文档骨架与三分类各一条实测记录端到端贯通,结构/ID 门禁转绿;后续 Task 2/3 只需在同一模板上横向补齐,无需再改结构 @@ -164,7 +188,7 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 .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 类型直连;「既有重构标记的处置口径」) + - .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` 基准) @@ -172,7 +196,7 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 - 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 需要重构` 标记) + - 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 需要重构` 标记;整文件扫描按 action (6) 委派给只读子代理,执行者只在存疑处按 `file:line` 切片复核) (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` 等)。 @@ -180,7 +204,7 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 (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),子代理只回传文本,**不得写文件**;主执行者负责汇总与定性一致性。 + (6) **必须**按 D-09 派只读子代理完成重型整文件扫描(对应 Estimate Basis 的重测口径):委派 `render/map/renderer.ts`、`render/map/vertex.ts`、`render/map/types.ts`、`render/map/moving.ts`、`render/map/element.ts`、`render/map/status.ts`、`render/elements/props.ts`、`render/map/extension/hero.ts`。子代理只回传事实表(每行:接口名 + 所属 `file:line` + 数据端基准签名或现行 import 原文),**不得写文件、不贴大段源码**;主执行者据事实表定性、登记并保证一致性,**不整文件读取上述八个文件**,只在事实表存疑时按 `file:line` 附近切片复核。 (7) 只修改审计文档;不得改动任何生产源码,不得新增计划文件。 @@ -203,18 +227,19 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 .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/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/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 锚点面;整文件扫描按 action (1) 委派给只读子代理,执行者只按需切片) + - 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(渲染侧素材族,用于「匹配」判据;整文件扫描按 action (1) 委派给只读子代理,执行者只按需切片) - 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.*` 读取,对每处先判定「读的是数据端状态」还是「渲染侧素材/全局」: + (1) 先按 D-09 派只读子代理完成 Task 3 的重型整文件扫描(对应 Estimate Basis 的重测口径):委派 `render/ui/{main,statistics,viewmap,settings,save,toolbar,statusBar}.tsx`、`render/components/{choices,misc}.tsx`、`render/utils/saves.ts`、`fallback/load.ts`、`render/elements/{cache,misc}.ts`、`client-base/src/load/loader.ts`。子代理只回传事实表(每行:legacy 调用 + 所属 `file:line` + 建议替代接口/基准位置),**不得写文件、不贴大段源码**;执行者**不整文件读取上述文件**,只在事实表存疑时按 `file:line` 附近切片复核。 + 然后按 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.` 就一律登记」)。 每条记录含 接口名 / 所属文件:行 / 分类 / 问题描述 / 影响 / 置信 / 依据。 @@ -222,11 +247,15 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 (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 第一步)` 提交**仅**审计文档,不得提交任何被查源码改动,不得新增后续步骤的计划文件。 + (6) 门禁与提交:运行只读门禁、**锚点可追溯门禁**(`git ls-files packages-user/client-base packages-user/client-modules`,确认审计文档引用的每个 `packages-user/client-{base,modules}/**` 路径都是 tracked 源码、未指向 gitignored 镜像路径)、CRLF 门禁与范围门禁(见 ``);追加内容保持 CRLF。随后以 `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" + node -e "const fs=require('fs'),cp=require('child_process');const t=fs.readFileSync('.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md','utf8');const paths=[...new Set(t.match(/packages-user\/(?:client-base|client-modules)\/[A-Za-z0-9._\/-]+\.tsx?/g)||[])];if(paths.length===0){console.error('NO CLIENT ANCHOR PATHS');process.exit(1)}const tracked=new Set(cp.execSync('git ls-files packages-user/client-base packages-user/client-modules',{encoding:'utf8'}).split(/\r?\n/).filter(Boolean).map(s=>s.replace(/\\/g,'/')));const missing=paths.filter(p=>!tracked.has(p));if(missing.length>0){console.error('UNTRACKED ANCHOR PATHS '+missing.length+' '+missing.join(','));process.exit(1)}console.log('OK tracked anchor paths '+paths.length)" + non-zero exit, 或 stderr 含 "NO CLIENT ANCHOR PATHS" / "UNTRACKED ANCHOR PATHS"(审计文档引用了 `git ls-files` 不认识的路径,即 gitignored 镜像或被臆造的路径) + node -e "const fs=require('fs');const s=fs.readFileSync('.planning/phases/04-render-adaptation/04-RENDER-INTERFACE-AUDIT.md','utf8');const lf=(s.match(/\n/g)||[]).length;const crlf=(s.match(/\r\n/g)||[]).length;if(lf!==crlf){console.error('NON-CRLF LINE ENDINGS '+(lf-crlf));process.exit(1)}console.log('OK CRLF lines '+crlf)" + non-zero exit, 或 stderr 含 "NON-CRLF LINE ENDINGS"(审计文档出现非 CRLF 换行,违反 dev.md「换行使用 CRLF 格式」) 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')" @@ -238,6 +267,7 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 - 「② 数据端缺失接口」节定稿:条目(如有)均含「现状 / 期望」,且节末结论行取固定两式之一;未确认候选在「未能从阅读确定(未猜测)」中逐条列出 - `## 判定为「匹配」的同类边界` / `## 未能从阅读确定(未猜测)` / `## 处置` 三段均非空且符合 07-LOADSTATE-AUDIT 的写法;`## 处置` 含双布局资产登记与「后续步骤未在本 run 规划」的明确表述 - ID 唯一且前缀与分类列一一对应(M=① 错配、L=③ 多余旧路径、G=② 数据端缺失) + - 审计文档引用的每个 `packages-user/client-{base,modules}/**` 路径都能在 `git ls-files` 输出中命中(无 gitignored 镜像或被臆造路径);全文为 CRLF 换行 - `git status --porcelain -- packages-user/client-base packages-user/client-modules` 为空;`.planning/phases/04-render-adaptation` 下无 04-01 以外的计划文件 - 审计文档已以 `docs(04-01)` 提交,提交内容仅含该文档 @@ -274,9 +304,11 @@ Output: `04-RENDER-INTERFACE-AUDIT.md`(本 run 唯一新增产物;零生产 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)` 仅含审计文档。 +5. 锚点可追溯门禁(Task 3):审计文档引用的每个 `packages-user/client-{base,modules}/**` 路径都能在 `git ls-files packages-user/client-base packages-user/client-modules` 输出中命中(落实 `must_haves.key_links[0]`)。 +6. CRLF 门禁(Task 1 与 Task 3):审计文档无孤立 `LF`,全文为 CRLF(dev.md「换行使用 CRLF 格式」)。 +7. 范围门禁(Task 3):`.planning/phases/04-render-adaptation` 下除 `04-01-PLAN.md` 外无其它 `*-PLAN.md`(后续步骤未被规划)。 +8. 人工核对:`## 判定为「匹配」的同类边界` 的素材族判据、`## 未能从阅读确定(未猜测)` 的逐条理由、`## 处置` 的双布局资产登记与「后续步骤未在本 run 规划」表述均齐备。 +9. 提交:`docs(04-01)` 仅含审计文档。