mirror of
https://github.com/motajs/template.git
synced 2026-10-16 10:30:18 +08:00
docs(09-17): plan task 8 read-only data-migration audit; record D-70..D-75
This commit is contained in:
parent
a6e2d83233
commit
b544360757
389
.planning/phases/09-minimum-browser-runnable/09-17-PLAN.md
Normal file
389
.planning/phases/09-minimum-browser-runnable/09-17-PLAN.md
Normal file
@ -0,0 +1,389 @@
|
||||
---
|
||||
phase: 09-minimum-browser-runnable
|
||||
plan: 17
|
||||
type: execute
|
||||
wave: 14
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- .planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md
|
||||
- .planning/phases/09-minimum-browser-runnable/09-17-SUMMARY.md
|
||||
autonomous: false
|
||||
requirements: []
|
||||
estimate:
|
||||
tokens: 60000
|
||||
raw_tokens: 60000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**本计划的第一个 block 点是 Task 0 的 `blocking-human` 汇报关卡(AGENTS.md 硬要求,D-03 / D-74)**:Task 0 必须先汇报「本计划 = 任务 8 · 旧引擎数据迁移的只读盘点」的要做什么 / 为什么 / 大致怎么做 / 影响范围,**必须列明:盘点范围(六类)、只读保证、七个盘点维度、D-72 五条拆分规则(含 tilesets/autotiles 例外)、命名候选的报备方式、产出文档路径(待批准)、静态门禁方式与开放项 OI-1..OI-6**,然后必须**停下等待**用户明确回复「可以执行」四个字;未收到前不得执行本计划任何一步、不得派发执行子代理,且不因触发方式或 `mode: yolo` / `workflow.auto_advance` 自动放行。"
|
||||
- "**D-74(本次规划单元 = 只读盘点):** 本计划**只产出只读盘点**计划,盘点产物文档为 `.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md`(**新命名产物,须 Task 0 呈报用户批准,OI-1**);**全程只读**——**零生产代码改动、零数据文件改动、零 PNG 生成**;盘点内容须为后续「迁移计划」提供**可直接消费的映射台账**(含字段映射候选与待报备命名候选)。**实际迁移不在本计划范围**(由用户盘点执行后再派发)。"
|
||||
- "**D-71(范围):** 本次只读盘点覆盖 **图块定义 tile、地图 maps、贴图素材 textures、怪物 enemy、道具 items、NPC** 六类;`animation` 素材**暂不处理**(不盘点 / 不挪动 `public/project/animates/*.animate`);`images` / `sounds` / `bgms` / `fonts` **不在本次范围**。**`public/project/autotiles/*.png` 与 `public/project/tilesets/*.png` 归入「贴图素材 textures」维度纳入盘点**(2026-10-13 用户裁定,D-71 补充)。"
|
||||
- "**维度 1 · 图块 tile(只读):** 解析旧 `public/project/maps.js` 的 `blocksInfo` 全表(此即 `maps.js` 顶层 `var maps_<hash> = {…}` 图块定义对象的运行时名,非文件中的字面键名;每项 `cls` / `id` / `name` / `trigger` / `animate` / `canPass` / `noPass` / `doorInfo` / `canBreak` / `script` / `autotileConnection` / `faceIds` / `cannotOut` / `cannotIn` 等),给出 `cls → TileType`(`packages-user/data-common/src/store/types.ts:6`)、`trigger/eventPass/pass/canBreak/doorInfo/animate` → `ITileRawData.{type,events,eventPass,pass}`(同文件 `:47`)的**映射候选**,并列出 id/num **全清单**。"
|
||||
- "**维度 2 · 贴图素材 textures(只读):** 逐一登记 `public/project/materials/*.png`(`terrains` / `items` / `enemys` / `enemy48` / `npcs` / `npc48` / `animates` / `icons` / `icons_old` / `ground` / `airwall` / `keyboard` 等)**以及 `public/project/autotiles/*.png`(`autotile.png` / `autotile1..3.png`)与 `public/project/tilesets/*.png`(`magictower.png`)的**内容与**像素尺寸**;按 **D-72 五条规则**推导**目标拆分方案**(① `npc` 与 `npc48`、`enemy` 与 `enemy48` 合并;② `terrains` / `items` / `enemy` / `npc` 分别成图、不混入同一张;③ `animates` 并入 `terrains`;④ 不同帧数不得同一张图;⑤ 单帧 4×4、多帧「帧数列 × 4 行」拆分),并给出**命名候选清单(标注「待用户报备批准」,本计划不落地使用)**。**例外(不套用 D-72⑤):** `tilesets/*.png` 走 `addTileset`(`source` / `identifier` / `cellWidth` / `cellHeight`)、`autotiles/*.png` 走 `addAutotile`(`source` / `identifier` / `type: AutotileType` 2×3 `Small2x3` / 3×4 `Big3x4`),**各自登记其参数候选与命名候选(均标注「待用户报备批准」)**。"
|
||||
- "**维度 3 · 怪物 enemy(只读):** 解析 `public/project/enemys.js`(及 `enemy48` 对应素材来源)→ `IEnemyRawData`(`packages-user/data-common/src/store/types.ts:319`)的 `attribute` / `special` **映射候选**(含 `special` 数字键、`bigImage` / `faceIds` / `notBomb` 等旧字段的归属)。"
|
||||
- "**维度 4 · 道具 items(只读):** 解析 `public/project/items.js` → `IItemRawData`(`packages-user/data-common/src/store/types.ts:176`);`cls`(`tools` / `items` / `equips` / `constants`)→ `ItemCategory`(同文件 `:125`)**映射候选**;装备 `equip`(`IItemEquipData`,`:161`)与效果脚本(`itemEffect` / `useItemEffect` / `useItemEvent` / `canUseItemEffect` / `hideInToolbox` 等)的归属。"
|
||||
- "**维度 5 · NPC(只读):** `npcs` / `npc48` → 图块与贴图归属(依 D-72① 合并为 `npc`),给出 `npcs`(14 条)与 `npc48`(10 条)图块到合并后 `npc` 的**映射候选**与贴图归属候选。"
|
||||
- "**维度 6 · 地图 maps(只读):** 解析 `public/project/floors/*.js`(`empty` / `MT0` / `sample0` / `sample1` / `sample2`)→ `IMapRawData`(`packages-user/data-common/src/store/types.ts:260`)的 `width` / `map` / `layerAlias` / `events` **映射候选**(旧 `map` 为二维数组、旧有 `height` / `title` / `firstArrive` / `changeFloor` / `afterBattle` / `afterGetItem` / `afterOpenDoor` / `cannotMove` / `bgmap` / `fgmap` / `autoEvent` 等字段的归属与取舍)。"
|
||||
- "**维度 7 · 贴图列表 schema 草案(只读):** 按 `packages-user/client-base/src/material/types.ts` 的 `ITextureManager.addGrid`(`:261`)/ `addRowAnimate`(`:275`)/ `addAutotile`(`:289`)/ `addTileset`(`:302`)能力,反向设计 `src/content/texture/.list.jsonc`(`src/content/client.jsonc:9` 的 `textureListDir`)字段结构**草案**(**仅草案**;新字段命名一律标注「待用户报备批准」,本计划不落地),且**须与 §2 的登记一致**(materials → grid / rowAnimate;autotiles → autotile;tilesets → tileset)。"
|
||||
- "**只读证据纪律:** 台账事实行须带 `file:line` 锚点;无法从阅读 / 静态解析确定的内容一律进「未确定项 / 待确认观察」章节(§8),**不得猜测编造**,**不得把疑似问题登记为缺陷**(仅当用户确认后方可登记)。"
|
||||
- "**范围零外溢 + 静态门禁:** 仅新增上述两文档;**不修改** 09-01..09-16 任何文件、不修改任何 `.ts` / `.tsx`、不修改 `public/project/**` 与 `src/content/**`、不生成任何 `.png`、不修改 `ROADMAP.md` / `STATE.md`(跟踪同步属 orchestrator 收尾);验证一律为**静态断言**(文档存在 / 含 §0..§9 章节 / 含各维度计数 / 锚点有效 / 只读守卫),**不使用** `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数作门禁。"
|
||||
artifacts:
|
||||
- path: .planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md
|
||||
provides: "任务 8 的只读盘点文档:§0 口径/范围/只读声明 + §1 tile + §2 textures(materials + autotiles + tilesets 登记、D-72 拆分方案+tilesets/autotiles 例外、命名候选)+ §3 enemy + §4 items + §5 NPC + §6 maps + §7 贴图列表 schema 草案(与 §2 一致)+ §8 未确定项 + §9 汇总与计数。"
|
||||
- path: .planning/phases/09-minimum-browser-runnable/09-17-SUMMARY.md
|
||||
provides: "本计划的执行摘要:盘点范围、七个维度、各维度计数、产出路径、只读确认、命名候选清单、OI-1..OI-6 的最终裁定。"
|
||||
key_links:
|
||||
- "`public/project/maps.js:3`(`blocksInfo` 首项)↔ `packages-user/data-common/src/store/types.ts:6`(`TileType`)/ `:47`(`ITileRawData`)—— 维度 1 的 cls→TileType 与字段映射两端"
|
||||
- "`public/project/enemys.js:3`(首项)↔ `packages-user/data-common/src/store/types.ts:319`(`IEnemyRawData`)—— 维度 3 的 attribute/special 映射"
|
||||
- "`public/project/items.js:3`(首个 `tools` 项)↔ `packages-user/data-common/src/store/types.ts:125`(`ItemCategory`)/ `:176`(`IItemRawData`)/ `:161`(`IItemEquipData`)—— 维度 4 的 cls→ItemCategory 与 equip/效果归属"
|
||||
- "`public/project/floors/MT0.js:1`(`main.floors.<id> = {…}`)↔ `packages-user/data-common/src/store/types.ts:260`(`IMapRawData`)—— 维度 6 的地图数据映射"
|
||||
- "`public/project/materials/*.png`(只读,如 `terrains.png` 规划日实测 32×1120)↔ `packages-user/client-base/src/material/types.ts:261`(`addGrid`)/ `:275`(`addRowAnimate`)—— 维度 2 materials 拆分方案与维度 7 grid/rowAnimate schema 的能力依据"
|
||||
- "`public/project/autotiles/*.png`(`autotile.png` / `autotile1..3.png`)↔ `packages-user/client-base/src/material/types.ts:289`(`addAutotile`,`type: AutotileType` 2×3 / 3×4)—— 维度 2 autotiles 例外登记与维度 7 autotile schema 的能力依据"
|
||||
- "`public/project/tilesets/*.png`(`magictower.png`)↔ `packages-user/client-base/src/material/types.ts:302`(`addTileset`,`source` / `identifier` / `cellWidth` / `cellHeight`)—— 维度 2 tilesets 例外登记与维度 7 tileset schema 的能力依据"
|
||||
- "`src/content/client.jsonc:9`(`textureListDir: texture/.list.jsonc`)/ `src/content/texture/.list.jsonc`(现状 `{}`)/ `src/content/tile.jsonc`(现状首项示例)/ `src/content/defaults/{tile,enemy,item,map}.jsonc`(目标 schema 骨架)—— 落点侧参考(D-70 消费接线由用户后续提供)"
|
||||
assumptions:
|
||||
- "**执行日行号可能漂移**:本计划内引用行号为 2026-10-13 规划日实测;文档锚点与门禁以**执行日实测**为准,门禁按「文件存在 + 行号在范围内」校验,不硬编码任何行号。"
|
||||
- "**`blocksInfo` 为运行时名称**:`public/project/maps.js` 顶层字面形态为 `var maps_<hash> = { \"1\": {…}, … }`(首项 `:3`);`blocksInfo` 是 `core.maps.blocksInfo` 的运行时名称,并非文件中的字面键名。文档须在 §0/§1 明示此对应,避免把运行时名误当文件键名检索。"
|
||||
- "**`blocksInfo` 条目数基线**:规划日实测 `public/project/maps.js` 的 `blocksInfo` 形如 `{ \"num\": {…} }`,首项在 `:3`;执行日以脚本枚举实测为准,计数以实测为准。"
|
||||
- "**PNG 像素尺寸读取方式**:以 `node` 读取 PNG `IHDR`(`width` = 偏移 16 起 4 字节大端,`height` = 偏移 20 起 4 字节大端)即可,无需任何依赖;规划日实测 `terrains.png` = 32×1120。"
|
||||
- "**autotiles / tilesets 素材基线**:规划日实测 `public/project/autotiles/` 含 `autotile.png` / `autotile1.png` / `autotile2.png` / `autotile3.png`,`public/project/tilesets/` 含 `magictower.png`;执行日以实测为准。"
|
||||
- "**用户并发改动(D-56)**:执行期工作树可能存在用户并发改动;只读守卫采用**「执行前基线对比」**,仅对本计划执行期**新增**的 `.ts` / `.tsx` / `public/project/**` / `src/content/**` 改动判红,避免误判用户既有改动(OI-6)。**基线仅在 Task 1 的 `<action>` 步骤 (0) 写入一次**(仓库外临时目录);Task 1 `<verify>` 的基线断言为**幂等**(基线已存在则不覆写),确保对比基准始终是「写入前的执行前状态」,从而能检出 Task 1 期间的越界写入。"
|
||||
- "**Markdown 使用 LF**:仓库既有 phase 文档与盘点产物(`09-LEGACY-INTERFACES-AUDIT.md` / `09-LEGACY-REPLACEMENT-AUDIT.md` / `ROADMAP.md`)均为裸 LF;新文档随此约定(**不**强制 CRLF)。"
|
||||
- "**「animation」边界**:D-71 明确 `animation` 素材暂不处理;本计划**不**盘点 `public/project/animates/*.animate`,也**不**设计 `src/content/animation/.list.jsonc`(仅可在 §8 记为「后续任务」。)"
|
||||
prohibitions:
|
||||
- "不得在用户明确回复「可以执行」四个字之前执行本计划的任何任务、或派发任何执行子代理。"
|
||||
- "本计划**只做只读盘点并产出文档**:**不得**修改 / 删除 / 新增任何生产 `.ts` / `.tsx` 源码;**不得**修改 / 删除 / 新增任何 `public/project/**` 或 `src/content/**` 数据文件;**不得生成任何 `.png` 素材**(D-75);**不得**做任何迁移、拆分、接线或改造。"
|
||||
- "**命名边界:** 盘点中提出的任何新增 / 修改命名(如拆分后贴图文件名、`addTileset` / `addAutotile` 的 `identifier` / 参数命名、`texture/.list.jsonc` 字段名)**只能作为「命名候选」写入台账并标注「待用户报备批准」**,**不得落地使用**、**不得写入任何 `src/content/**` 文件**(D-73 / AGENTS.md:公共 / 受保护 / 私有方法、字段命名须先报备获批)。"
|
||||
- "**只读边界:** 除 `09-DATA-MIGRATION-AUDIT.md` 与 `09-17-SUMMARY.md` 两个文档外,**不得写入任何文件**;不得改 09-01..09-16 及其产物;不得改 `09-CONTEXT.md`;**不得编辑 / 暂存 / 提交 `ROADMAP.md` 与 `STATE.md`**(跟踪同步属 orchestrator 收尾步骤,先例:09-11 / 09-12)。"
|
||||
- "**不得臆造条目:** 文档中每个 `file:line` 锚点必须指向真实存在且范围内的一行;映射候选须基于真实读取的旧数据字段;无法确定者一律进 §8「未确定项」,**不得**编造字段名 / 映射关系 / 尺寸。"
|
||||
- "**不得把观察当缺陷:** 盘点中发现的任何「疑似问题 / 不一致 / 缺失」**不得登记为缺陷**,只能写入 §8「未确定项 / 待确认观察」,待用户确认后方可另立计划。"
|
||||
- "**拆分规则例外不得遗漏:** `tilesets/*.png` 与 `autotiles/*.png` **不得**被套用 D-72⑤ 的 4×4 / 帧数列×4 行拆分;须各自按 `addTileset` / `addAutotile` 参数登记,并与 §7 schema 草案保持逐条一致。"
|
||||
- "不得把门禁建立在「全仓 TS 诊断数」「`pnpm check:type`」「`pnpm build`」之上;不得为了「验证」去改动源码或数据。"
|
||||
- "不得触碰、暂存、提交用户的并发改动(D-56):提交前 `git status` 逐条核对暂存面,只暂存本计划 `files_modified` 的条目。"
|
||||
open_items:
|
||||
- "**OI-1(产出文档命名 / 路径,D-74):** 提议 `.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md`(连字符命名法,随既有盘点产物约定)。**待用户批准。**"
|
||||
- "**OI-2(文档章节结构):** 提议 §0 口径与范围 → §1 tile → §2 textures → §3 enemy → §4 items → §5 NPC → §6 maps → §7 贴图列表 schema 草案 → §8 未确定项 → §9 汇总与计数。**待用户确认**;若用户要增删章节,据其指定。"
|
||||
- "**OI-3(命名候选呈现方式):** 提议将新增命名(拆分后文件名、`identifier` / 参数名、`.list.jsonc` 字段名)集中列入「命名候选(待报备)」表,逐条标注「待用户报备批准」,本计划不落地使用。**待用户确认。**"
|
||||
- "**OI-4(贴图拆分方案粒度,含 tilesets/autotiles 例外):** 提议按 D-72 五规则逐组给出「目标文件名(候选)+ 来源 PNG + 帧数 + 行列布局(单帧 4×4 / 多帧 帧数×4 行)」;**并对例外各给一行参数候选**——`tilesets/*.png` → `addTileset`(`source` / `identifier` / `cellWidth` / `cellHeight`)、`autotiles/*.png` → `addAutotile`(`source` / `identifier` / `type: AutotileType` 2×3 `Small2x3` / 3×4 `Big3x4`),**均标注「待用户报备批准」**。**待用户确认**粒度。"
|
||||
- "**OI-5(贴图列表 schema 草案深度):** 提议仅给出 `.list.jsonc` 字段结构草案与到 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset` 的对应关系(与 §2 登记逐条一致),**不含最终命名落地**(命名待报备)。**待用户确认。**"
|
||||
- "**OI-6(未确定项与只读守卫口径):** 提议「凡无法从阅读 / 静态解析确定者一律入 §8,不得登记为缺陷」;只读守卫采用**「执行前基线对比」**(只对执行期新增的 `.ts`/`.tsx`/`public/project`/`src/content` 改动判红),基线由 Task 1 `<action>` 步骤 (0) 一次性写入预批准的仓库外临时目录,`<verify>` 断言**幂等**不覆写。**待用户裁定。**"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Phase 9 · 任务 8 · 第 17 个计划 —— **旧引擎数据迁移的「只读盘点」**(范围 = 六类;产出**一份盘点文档**;**不实施迁移**)。
|
||||
|
||||
**要解决的问题(D-70..D-75):** 旧引擎数据位于 `public/project`(逻辑数据 `maps.js` 的 `blocksInfo`、`items.js`、`enemys.js`、`floors/*.js`;素材 `materials/*.png`、`autotiles/*.png`、`tilesets/*.png` 等),新引擎数据落点为 `src/content`(`tile.jsonc` / `enemy.jsonc` / `item.jsonc` / `maps/` / `texture/.list.jsonc` 及 `defaults/*`)。实际迁移前,需要一份**有据可查的只读映射台账**,把旧字段逐项对到新接口(`ITileRawData` / `IEnemyRawData` / `IItemRawData` / `IMapRawData` / `TextureManager`),并给出素材拆分方案与命名候选,使后续「迁移计划」可直接消费。**本计划不做任何迁移 / 拆分 / 生成 / 接线**(D-74 / D-75 只读)。
|
||||
|
||||
**大致解决方案(本计划 = 09-17):**
|
||||
- **Task 0(`blocking-human`)= 预执行汇报关卡**:汇报盘点范围(六类,**含 `autotiles/*.png` 与 `tilesets/*.png` 归入 textures 维度**)、七个盘点维度、D-72 五条拆分规则(**含 tilesets/autotiles 不套用 D-72⑤ 的例外**)、命名候选报备方式、产出文档路径(OI-1)、只读保证与开放项 OI-1..OI-6,并等待用户「可以执行」。
|
||||
- **Task 1 = 骨架 + §0 口径 + §1 tile + §2 textures**:采集只读基线;建立第 0 节(口径 / 范围 / 方法论 / 只读声明 / D-72 规则原文 / 命名待报备说明 / `blocksInfo` 名词说明);枚举并登记 `blocksInfo` 全表与 `cls → TileType` / 字段映射候选(含 id/num 全清单);逐一登记 `materials/*.png` **以及 `autotiles/*.png`、`tilesets/*.png`** 与像素尺寸,按 D-72 推导目标拆分方案(**materials → `addGrid` / `addRowAnimate`;autotiles → `addAutotile`;tilesets → `addTileset`,后两者不套用 D-72⑤**)与命名候选。
|
||||
- **Task 2 = §3 enemy + §4 items + §5 NPC + §6 maps + §7 schema 草案 + §8 未确定项 + §9 汇总 + 收口**:逐类完成映射候选台账;设计 `texture/.list.jsonc` 字段结构草案(依 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset`,与 §2 一致);汇总各维度计数;跑最终静态门禁(锚点有效性 + 章节完整 + 只读守卫)并写 `09-17-SUMMARY.md`。
|
||||
|
||||
**为何先 tile/textures 后 enemy/items/NPC/maps:** tile 与 textures 是「图块坐标系」的两半(逻辑 + 素材),承载 §0 口径与 D-72 拆分方法(含 tilesets/autotiles 例外)先立;enemy/items/NPC/maps 依赖 tile 的 id/num 清单与贴图归属,单独成节并承载汇总与只读收口。三任务同属一个只读产物,无 `files_modified` 外扩。
|
||||
|
||||
**API coverage:** `detected:false`。**`No external API integration: 本计划仅为只读数据盘点与文档撰写,不涉及任何外部 API。`**
|
||||
</objective>
|
||||
<execution_context>
|
||||
@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.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-LEGACY-INTERFACES-AUDIT.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: 预执行汇报关卡 —— 汇报「任务 8 · 旧引擎数据迁移的只读盘点」的范围(含 autotiles/tilesets 纳入 textures 维度)、七个维度、D-72 拆分规则与产出路径,等待用户回复「可以执行」</name>
|
||||
<precondition>`public/project/maps.js`、`public/project/enemys.js`、`public/project/items.js`、`public/project/floors/*.js`、`public/project/materials/*.png`、`public/project/autotiles/*.png`、`public/project/tilesets/*.png` 均存在;目标落点 `src/content/tile.jsonc` 与 `src/content/texture/.list.jsonc` 均存在;盘点文档 `09-DATA-MIGRATION-AUDIT.md` 与 `09-17-SUMMARY.md` **尚不存在**。</precondition>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- .planning/phases/09-minimum-browser-runnable/09-CONTEXT.md(D-03 / D-04 / D-06 / **D-70 / D-71 / D-72 / D-73 / D-74 / D-75**)
|
||||
- .planning/phases/09-minimum-browser-runnable/09-17-PLAN.md(本计划全文,含七个盘点维度与 OI-1..OI-6)
|
||||
- AGENTS.md(执行前须获批、命名须先反馈、修改方式须预先声明);dev.md(命名规则、注释规范、Markdown 连字符命名、依赖单向关系、双端分离)
|
||||
</read_first>
|
||||
<action>
|
||||
**停下并向用户汇报,等待明确回复「可以执行」后才继续;汇报本身只读。**
|
||||
|
||||
① **要解决的问题:** 任务 8 · 旧引擎数据迁移的**只读盘点**。为后续「旧引擎数据迁移」计划提供可直接消费的映射台账——把旧 `public/project` 数据逐项对到新 `src/content` 所需的新接口(`ITileRawData` / `IEnemyRawData` / `IItemRawData` / `IMapRawData` / `TextureManager`),给出字段映射候选、素材拆分方案与待报备命名候选。**只读,不迁移。**
|
||||
|
||||
② **盘点范围(D-71):** 六类——**图块定义 tile、地图 maps、贴图素材 textures、怪物 enemy、道具 items、NPC**;`animation` 素材**暂不处理**(不盘点 / 不挪 `public/project/animates/*.animate`);`images` / `sounds` / `bgms` / `fonts` **不在本次范围**。**「贴图素材 textures」维度显式包含 `public/project/materials/*.png`、`public/project/autotiles/*.png`(`autotile.png` / `autotile1..3.png`)与 `public/project/tilesets/*.png`(`magictower.png`)三类**(2026-10-13 用户裁定)。**落点与接线(D-70):** 迁移目标是 `src/content`(jsonc + 素材);把配置写入 store、把贴图列表写入 `TextureManager` 的**消费接线由用户后续单独提供,本次不实现**。
|
||||
|
||||
③ **七个盘点维度(本计划 §1..§7):**
|
||||
- **§1 图块 tile:** `public/project/maps.js` 的 `blocksInfo`(运行时名称 `core.maps.blocksInfo`;文件中字面形态为顶层 `var maps_<hash> = {…}` 对象,首项 `:3`)全表 → `cls → TileType`、`trigger/eventPass/pass/canBreak/doorInfo/animate` → `ITileRawData.{type,events,eventPass,pass}` 映射候选 + id/num **全清单**。
|
||||
- **§2 贴图素材 textures:** 逐一登记 `public/project/materials/*.png` **以及 `public/project/autotiles/*.png`、`public/project/tilesets/*.png`** 的内容与**像素尺寸**(`terrains` / `items` / `enemys` / `enemy48` / `npcs` / `npc48` / `animates` / `icons` / `icons_old` / `ground` / `airwall` / `keyboard`;`autotile` / `autotile1..3`;`magictower`);按 **D-72 五规则**推导目标拆分方案(① `npc`+`npc48`、`enemy`+`enemy48` 合并;② `terrains`/`items`/`enemy`/`npc` 分别成图;③ `animates` 并入 `terrains`;④ 不同帧数不同图;⑤ 单帧 4×4、多帧 帧数×4 行)+ **命名候选(待报备)**。**例外:** `tilesets/*.png` 走 `addTileset`、`autotiles/*.png` 走 `addAutotile`,**不套用** D-72⑤,各自登记参数候选(见 ④)。
|
||||
- **§3 怪物 enemy:** `public/project/enemys.js`(及 `enemy48` 素材来源)→ `IEnemyRawData` 的 `attribute` / `special` 映射候选。
|
||||
- **§4 道具 items:** `public/project/items.js` → `IItemRawData`;`cls`(`tools`/`items`/`equips`/`constants`)→ `ItemCategory` 映射候选;装备 `equip` 与效果脚本的归属。
|
||||
- **§5 NPC:** `npcs` / `npc48` → 图块与贴图归属(依 D-72① 合并为 `npc`)。
|
||||
- **§6 地图 maps:** `public/project/floors/*.js` → `IMapRawData`(`width` / `map` / `layerAlias` / `events`)映射候选。
|
||||
- **§7 贴图列表 schema 草案:** 依 `packages-user/client-base/src/material/types.ts` 的 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset` 反向设计 `src/content/texture/.list.jsonc` 字段结构**草案**(**仅草案;命名待报备;与 §2 登记一致**)。
|
||||
|
||||
④ **D-72 五条合并 / 分图规则与 tilesets / autotiles 例外(须原样告知):** 五规则——① `npc` 与 `npc48`、`enemy` 与 `enemy48` 均**合并**(不再有 48 变体);② `terrains` / `items` / `enemy` / `npc` **分别存储**,不得混入同一张图片;③ `animates` **合并入 `terrains`**;④ **不同帧数**的素材不得放入同一张图片;⑤ 单帧素材按 **4×4** 规格拆分,多帧素材按「**帧数列 × 4 行**」拆分。**例外(不套用⑤):** **`tilesets/*.png` → `addTileset`(`source` / `identifier` / `cellWidth` / `cellHeight`)**;**`autotiles/*.png` → `addAutotile`(`source` / `identifier` / `type: AutotileType`:2×3 `Small2x3` / 3×4 `Big3x4`)**;两者各自登记**参数候选**与**命名候选**(均标注「待用户报备批准」)。
|
||||
|
||||
⑤ **命名候选报备方式(D-73,须确认,OI-3):** 盘点中提出的任何新增 / 修改命名(拆分后贴图文件名、`addTileset` / `addAutotile` 的 `identifier` / 参数名、`.list.jsonc` 字段名)**只能作为「命名候选」写入台账并标注「待用户报备批准」**,**不落地使用**、**不写入任何 `src/content/**` 文件**。
|
||||
|
||||
⑥ **产出文档(D-74,须批准,OI-1):** 提议路径 `.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md`;章节结构见 OI-2(§0..§9),含各维度**映射候选**、**素材拆分方案(含 tilesets/autotiles 例外参数候选)**、**命名候选表**、**未确定项**与**各维度计数**(机器可读行 `TILE-COUNT:` / `MATERIAL-COUNT:` / `SPLIT-COUNT:` / `ENEMY-COUNT:` / `ITEM-COUNT:` / `NPC-COUNT:` / `MAP-COUNT:`)。
|
||||
|
||||
⑦ **只读保证(D-74 / D-75):** 全程只读;**禁止**修改 / 删除 / 新增任何生产 `.ts` / `.tsx`;**禁止**改 / 增删 `public/project/**` 与 `src/content/**`;**禁止生成任何 `.png` 素材**;本计划**唯一允许写入**的文件是上述盘点文档与 `09-17-SUMMARY.md`。
|
||||
|
||||
⑧ **验证方式(须用户确认,OI-6):** 静态断言——文档存在;含 `## 0.` 至 `## 9.` 章节;含七个维度计数键;锚点逐一校验「文件存在 + 行号在范围内」;**只读守卫**采用「执行前基线对比」(基线由 Task 1 `<action>` 步骤 (0) 一次性写入仓库外临时目录,`<verify>` 断言幂等不改写;仅对执行期新增的 `.ts`/`.tsx`/`public/project`/`src/content` 改动判红)。**不设全仓类型 / 构建门禁。**
|
||||
|
||||
⑨ **开放项与关卡性质:** 呈报 OI-1(文档路径)、OI-2(章节结构)、OI-3(命名候选呈现)、OI-4(拆分方案粒度,含 tilesets/autotiles 例外参数候选)、OI-5(schema 草案深度)、OI-6(未确定项与只读守卫口径)。**无论触发方式或 `mode: yolo` / `workflow.auto_advance`,执行者 / 子代理必须停下等待用户明确回复「可以执行」四个字**;回复其它内容视为未通过;若用户给出修订意见,退出本计划、修订后重新汇报。
|
||||
</action>
|
||||
<decision>是否按本计划执行任务 8 · 旧引擎数据迁移的只读盘点(范围 = 六类,textures 维度含 materials + autotiles + tilesets;产出 `09-DATA-MIGRATION-AUDIT.md`,含七个维度的映射候选 / 拆分方案(含 tilesets/autotiles 例外)/ 命名候选 / 未确定项),并按 OI-1..OI-6 的默认处置产出文档(只读,不改任何源码与数据,不生成素材,不实施迁移)</decision>
|
||||
<context>
|
||||
AGENTS.md / D-03 / D-04 要求执行前与命名先获批;`.planning/config.json` 为 `mode: yolo`,故本关卡显式 `blocking-human` 且 `autonomous: false`。本次核心 = 盘点范围确认(含 autotiles/tilesets 纳入 textures)+ 七个维度确认 + D-72 拆分规则(含例外)确认 + 命名候选报备方式确认 + 产出文档命名批准 + 只读边界确认。执行期可能存在用户并发改动(D-56),故只读守卫默认采用「执行前基线对比」(OI-6)。行号为规划日实测、可能漂移,文档锚点与门禁以执行日实测为准。
|
||||
</context>
|
||||
<options>
|
||||
<option id="execute-default">
|
||||
<name>可以执行(采纳全部默认处置)</name>
|
||||
<pros>只读、零源码 / 零数据 / 零 PNG 改动;七个维度结构清晰;textures 维度完整纳入 materials + autotiles + tilesets;产出可复核映射台账;命名候选集中报备;命名按提议路径</pros>
|
||||
<cons>无</cons>
|
||||
</option>
|
||||
<option id="execute-narrow">
|
||||
<name>可以执行 + 收窄维度(仅盘点 §1 tile 与 §4 items,其余维度暂缓)</name>
|
||||
<pros>文档更短、更快</pros>
|
||||
<cons>遗漏 textures(含 autotiles/tilesets)/enemy/NPC/maps 与 schema 草案,与 D-71「覆盖六类」及后续迁移计划「可直接消费」的意图不符</cons>
|
||||
</option>
|
||||
<option id="revise">
|
||||
<name>修订范围 / 维度 / 拆分规则理解 / 产出路径后重新汇报</name>
|
||||
<pros>避免带着错误口径产出文档</pros>
|
||||
<cons>须修订 PLAN.md 后重新汇报</cons>
|
||||
</option>
|
||||
</options>
|
||||
<resume-signal>回复「可以执行」四个字(如需调整 OI-1..OI-6 的处置,请在回复中指明;修订意见请按 action ⑨ 处理)</resume-signal>
|
||||
<verify>
|
||||
<automated>node -e "const fs=require('fs');const bad=[];const doc='.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md';const sum='.planning/phases/09-minimum-browser-runnable/09-17-SUMMARY.md';if(fs.existsSync(doc))bad.push('post-state: data-migration audit doc already exists');if(fs.existsSync(sum))bad.push('post-state: 09-17-SUMMARY already exists');for(const p of ['public/project/maps.js','public/project/enemys.js','public/project/items.js','public/project/floors/MT0.js']){if(!fs.existsSync(p))bad.push('missing input: '+p)}for(const d of ['public/project/materials','public/project/autotiles','public/project/tilesets','public/project/floors']){if(!fs.existsSync(d))bad.push('missing input dir: '+d)}for(const p of ['packages-user/data-common/src/store/types.ts','packages-user/client-base/src/material/types.ts','src/content/tile.jsonc','src/content/texture/.list.jsonc']){if(!fs.existsSync(p))bad.push('missing target/type ref: '+p)}if(bad.length>0){console.error('PRESTATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK pre-execution state intact (input data incl. autotiles/tilesets + target content + type refs present; output docs absent)')"</automated>
|
||||
<fails_when>non-zero exit, 或 stderr 含 "PRESTATE FAILED"(汇报基线不成立,或产出文档已存在 / 关键输入(含 autotiles、tilesets 素材目录)或目标文件缺失)</fails_when>
|
||||
<human-check>用户在对话中明确回复「可以执行」四个字(人工核对回复原文;用户若指定非默认的范围 / 维度 / 拆分规则理解 / 产出路径 / 只读守卫口径,须在汇报与后续任务中据其指定执行)</human-check>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- 用户回复中明确包含「可以执行」四个字
|
||||
- 汇报内容涵盖:D-71 六类范围(textures 维度**显式含 materials + autotiles + tilesets**)、七个盘点维度(§1..§7)、D-72 五条拆分规则**及 tilesets/autotiles 不套用 D-72⑤ 的例外**、D-73 命名候选报备方式、D-70 落点与接线边界、D-74/D-75 只读保证、OI-1..OI-6、验证方式(静态断言,无全仓门禁)
|
||||
- 汇报中已原样告知:**全程只读、不改任何 `.ts`/`.tsx` 与 `public/project/**` 与 `src/content/**`、不生成任何 `.png`、不实施迁移、命名候选只报备不落地、锚点不得臆造、疑似问题只入「未确定项」不当缺陷**
|
||||
- 汇报中已原样告知**关卡性质**(必须停下等待,不因触发方式或 `yolo` / `auto_advance` 自动放行)
|
||||
</acceptance_criteria>
|
||||
<done>用户明确回复「可以执行」;在此之前未执行任何任务、未修改任何文件、未派发任何执行子代理</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1(基线 + 口径 + §1 tile + §2 textures):采集只读基线,建立盘点文档第 0 节,登记图块映射候选与 id/num 全清单、登记 materials/autotiles/tilesets 素材与 D-72 拆分方案(含例外)及命名候选</name>
|
||||
<precondition>Task 0 已闭环:用户明确回复「可以执行」四个字(若用户就 OI-1..OI-6 另有指定,按指定执行)。</precondition>
|
||||
<files>.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md(新增;另向预批准临时目录写只读基线,仓库外)</files>
|
||||
<read_first>
|
||||
- .planning/phases/09-minimum-browser-runnable/09-CONTEXT.md(D-70 / D-71 / D-72 / D-73 / D-74 / D-75)
|
||||
- public/project/maps.js(`blocksInfo` 全表;文件顶层 `var maps_<hash> = {…}`,首项在 `:3`,含各 `cls` 与 `trigger` / `animate` / `canPass` / `noPass` / `doorInfo` / `canBreak` / `script` / `autotileConnection` / `faceIds` / `cannotOut` / `cannotIn` 等字段)
|
||||
- packages-user/data-common/src/store/types.ts:6-63(`TileType` / `ITilePassData` / `ITileRawData`)、:125-193(`ItemCategory` / `IItemRawData` 供 §0 口径参考)
|
||||
- packages-user/client-base/src/material/types.ts:12-28(`AutotileType` / `AutotileConnection`)、:217-307(`ITextureManager` 的 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset`)
|
||||
- public/project/materials/ 目录(`terrains.png` / `items.png` / `enemys.png` / `enemy48.png` / `npcs.png` / `npc48.png` / `animates.png` / `icons.png` / `icons_old.png` / `ground.png` / `airwall.png` / `keyboard.png`)
|
||||
- public/project/autotiles/ 目录(`autotile.png` / `autotile1.png` / `autotile2.png` / `autotile3.png`)、public/project/tilesets/ 目录(`magictower.png`)
|
||||
- src/content/tile.jsonc:1-12(目标 `ITileRawData` 示例)、src/content/client.jsonc:9(`textureListDir`)、src/content/texture/.list.jsonc:1-3(现状 `{}`)、src/content/defaults/tile.jsonc
|
||||
- dev.md(命名;Markdown 连字符命名;注释规范);AGENTS.md(只读边界;命名须先报备)
|
||||
</read_first>
|
||||
<action>
|
||||
(0) **采集只读基线(先于任何写入):** 运行 `git status --porcelain`,取其改动路径(去重排序)中匹配 `.ts` / `.tsx` 或前缀 `public/project/` / `src/content/` 的条目,写入**预批准临时目录**的基线文件 `process.env.TEMP + '/opencode/gsd-09-17-baseline.txt'`(仓库外,供 Task 1/2 的只读守卫对比;OI-6)。基线只记录执行前的既有改动,**不修改任何仓库文件**。**此步骤是本计划中唯一写入基线的动作**;后续 `<verify>` 只读该基线、不覆写(幂等)。
|
||||
|
||||
(1) **创建文档骨架 `09-DATA-MIGRATION-AUDIT.md`**(仅此文件 + 上述临时基线;**不修改任何源码与数据**;OI-1 命名须已在 Task 0 获批)。首行标题 + 只读声明 + LF。
|
||||
|
||||
(2) **第 0 节 `## 0. 盘点口径与范围`:** 写明——盘点范围(六类,D-71;**textures 维度显式含 `materials/*.png` + `autotiles/*.png` + `tilesets/*.png`**;`animation` 暂不处理;`images`/`sounds`/`bgms`/`fonts` 不在范围);落点与接线边界(D-70);**名词说明(`blocksInfo`)**:`blocksInfo` 为**运行时名称**(`core.maps.blocksInfo`),在 `public/project/maps.js` 中其**字面形态**为顶层 `var maps_<hash> = { "1": {…}, … }` 的图块定义对象(首项在 `:3`);本文档凡称 `blocksInfo` 一律指代该顶层对象(**非**文件中的字面键名,检索时勿按字面串匹配);**方法论**(用 `node` 只读解析 `public/project` 的 JS 数据与 PNG 头部,逐项实测,锚点须真实,不臆造);**D-72 五条拆分规则原文 + tilesets/autotiles 例外说明**;**命名待报备说明**(D-73:命名候选只入台账、标注「待用户报备批准」、不落地);**只读声明**(本文件为唯一产物之一,未改动任何源码 / 数据、未生成任何 PNG);Markdown 使用 LF。
|
||||
|
||||
(3) **§1 `## 1. 图块定义 tile`:** 用 `node` 只读解析 `public/project/maps.js` 的 `blocksInfo` 全表(**即 `public/project/maps.js:1-2` 顶层 `var maps_<hash> = {…}` 对象**;`blocksInfo` 为其运行时名称 `core.maps.blocksInfo`)。产出:
|
||||
- **`cls → TileType` 映射候选:** `animates → Animate`、`terrains → Terrain`、`items → Item`、`enemys → Enemy`、`npcs` / `npc48 → Npc`、`autotile → Autotile`、`enemy48 → Enemy`(合并到 `Enemy`)等(以执行日实测 `cls` 集合为准:规划日实测含 `animates` / `terrains` / `autotile` / `items` / `npcs` / `npc48` / `enemys` / `enemy48`)。
|
||||
- **字段映射候选:** `trigger` → `events`(事件 id 映射候选)/ `ITileRawData.eventPass`;`canPass` / `noPass` / `cannotOut` / `cannotIn` → `ITileRawData.pass`(`ITilePassData.onlyEvents` / `inPass` / `outPass`,方向映射候选);`canBreak` / `doorInfo` / `animate` / `script` / `autotileConnection` / `faceIds` 的**归属候选**(能确定者给新接口落点或对应机制;不能确定者进 §8)。
|
||||
- **id/num 全清单:** 表 `num | id | cls | 关键字段`,逐条列出(`TILE-COUNT` = 实测条目数)。
|
||||
- **指向贴图归属:** 每条 id 归属到 §2 的哪张(合并后)贴图(`terrains` / `items` / `enemy` / `npc`)/ 或哪类 tileset / autotile(`autotile` 类图块对应 §2 的 autotile 素材);`animates` 归 `terrains`(D-72③)。
|
||||
|
||||
(4) **§2 `## 2. 贴图素材 textures`:**
|
||||
- **登记(materials):** 逐一列出 `public/project/materials/*.png`,给出**内容**(承载的图块类)与**像素尺寸**(`node` 读 PNG `IHDR`:宽 = 偏移 16 起 4 字节大端,高 = 偏移 20 起 4 字节大端;规划日实测 `terrains.png` = 32×1120)。
|
||||
- **登记(autotiles,例外):** 逐一列出 `public/project/autotiles/*.png`(`autotile.png` / `autotile1.png` / `autotile2.png` / `autotile3.png`)与像素尺寸;说明其走 **`addAutotile`**(`source` / `identifier` / `type: AutotileType`);核对像素尺寸以**推导**该自动元件类型——**2×3 为 `Small2x3`、3×4 为 `Big3x4`**(尺寸不足以判定者进 §8);**明确 `autotiles/*.png` 不套用 D-72⑤ 的 4×4 / 帧数列×4 行拆分**;给出 `type` 参数候选与 `identifier` 命名候选(标注「待用户报备批准」)。
|
||||
- **登记(tilesets,例外):** 逐一列出 `public/project/tilesets/*.png`(`magictower.png`)与像素尺寸;说明其走 **`addTileset`**(`source` / `identifier: IIndexedIdentifier` / `cellWidth` / `cellHeight`);**明确 `tilesets/*.png` 不套用 D-72⑤ 的 4×4 / 帧数列×4 行拆分**;给出 `cellWidth` / `cellHeight` 切格尺寸候选与 `identifier` 命名候选(标注「待用户报备批准」)。
|
||||
- **D-72 目标拆分方案(materials):** 逐组给出「来源 PNG → 目标图(候选)+ 帧数 + 行列布局」,落实五规则:① `npcs.png` + `npc48.png` → 一张 `npc`;`enemys.png` + `enemy48.png` → 一张 `enemy`;② `terrains` / `items` / `enemy` / `npc` 各自成图、不混;③ `animates.png` 并入 `terrains`;④ 不同帧数的素材拆到不同图;⑤ 单帧按 **4×4**(消费方式对应 **`addGrid`**)、多帧按「**帧数列 × 4 行**」(消费方式对应 **`addRowAnimate`**)。给出 `SPLIT-COUNT`(materials 目标图数量,实测)。
|
||||
- **命名候选(待报备):** 集中列入「命名候选(待报备)」表,逐条标注「待用户报备批准」,**不落地**(OI-3);表须涵盖 materials 拆分后文件名**以及** autotiles 的 `identifier` / tilesets 的 `identifier` 参数命名候选。
|
||||
- **像素尺寸不足以直接判定帧数 / 自动元件类型 / 切格尺寸者** → 进 §8,不臆造。
|
||||
|
||||
(5) **收口:** 不改任何源码 / 数据;不改任何既有注释;文档仅含第 0 节 + §1 + §2(§3..§9 由 Task 2 补齐);LF;含机器可读行 `TILE-COUNT:` / `MATERIAL-COUNT:` / `SPLIT-COUNT:`(`MATERIAL-COUNT` 须**计入 materials + autotiles + tilesets 三类 PNG 总数**)。
|
||||
</action>
|
||||
<reversibility rating="reversible">纯新增只读文档(+ 仓库外临时基线);删除 / `git revert` 可整体回退;未触及任何源码或数据文件。</reversibility>
|
||||
<verify>
|
||||
<automated>node -e "const {execSync}=require('child_process');const fs=require('fs');const base=process.env.TEMP+'/opencode/gsd-09-17-baseline.txt';if(fs.existsSync(base)){console.log('OK baseline already captured by action step (0) (idempotent; verify does NOT overwrite) -> '+base+' | preserved pre-write baseline')}else{const lines=execSync('git status --porcelain',{encoding:'utf8'}).split(/\r?\n/).filter(Boolean).map(l=>l.slice(3).trim()).filter(p=>/(\.(ts|tsx)$|^public\/project\/|^src\/content\/)/.test(p)).sort();fs.mkdirSync(require('path').dirname(base),{recursive:true});fs.writeFileSync(base,lines.join('\n'));console.log('OK baseline captured ('+lines.length+' pre-existing source/data changes) -> '+base+' | fallback: action step (0) did not persist baseline')}"</automated>
|
||||
<fails_when>non-zero exit(无法读取 / 采集只读基线;后续只读守卫将无对照)</fails_when>
|
||||
<automated>node -e "const fs=require('fs');const p='.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-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.','## 1.','## 2.']){if(t.indexOf(s)<0)bad.push('missing heading: '+s)}for(const k of ['TILE-COUNT:','MATERIAL-COUNT:','SPLIT-COUNT:']){if(!new RegExp(k+'\\s*\\d+').test(t))bad.push('missing '+k)}for(const m of ['TileType','ITileRawData','animates','terrains','4×4','addGrid','addRowAnimate','addAutotile','addTileset']){if(t.indexOf(m)<0)bad.push('missing token: '+m)}if(t.indexOf('待用户报备批准')<0)bad.push('missing naming-candidate report marker');const anchors=[...t.matchAll(/((?:public\/project|packages-user|src\/content)\/[^\s|)\u0060]+\.(?:js|png|ts|tsx|jsonc)):(\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 out of range: '+f+':'+ln)}}if(bad.length>0){console.error('AUDIT-TILE-TEX GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK audit section 0 + tile + textures authored (headings, counts, cls/type addGrid/addRowAnimate/addAutotile/addTileset tokens, naming markers, anchors valid)')"</automated>
|
||||
<fails_when>non-zero exit, 或 stderr 含 "AUDIT-TILE-TEX GATE FAILED"(文档缺失 / 缺 §0 或 §1 或 §2 / 缺 TILE·MATERIAL·SPLIT 计数 / 缺 cls 或类型 token(含 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset`)/ 缺命名候选报备标记 / 锚点指向不存在的文件或越界行号)</fails_when>
|
||||
<automated>node -e "const {execSync}=require('child_process');const fs=require('fs');const base=process.env.TEMP+'/opencode/gsd-09-17-baseline.txt';const cur=execSync('git status --porcelain',{encoding:'utf8'}).split(/\r?\n/).filter(Boolean).map(l=>l.slice(3).trim()).filter(p=>/(\.(ts|tsx)$|^public\/project\/|^src\/content\/)/.test(p)).sort();const prev=fs.existsSync(base)?fs.readFileSync(base,'utf8').split(/\r?\n/).filter(Boolean).sort():[];const added=cur.filter(x=>!prev.includes(x));if(added.length){console.error('READONLY FAILED :: new source/data changes :: '+added.join(' | '));process.exit(1)}console.log('OK read-only after Task 1: no new .ts/.tsx/public-project/src-content changes vs pre-write baseline')"</automated>
|
||||
<fails_when>non-zero exit, 或 stderr 含 "READONLY FAILED"(本计划执行期(含 Task 1 动作阶段)新增了 `.ts`/`.tsx` 或 `public/project/**` 或 `src/content/**` 改动,违反 D-74/D-75 只读)</fails_when>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- 只读基线已由 `<action>` 步骤 (0) 一次性采集到 `process.env.TEMP + '/opencode/gsd-09-17-baseline.txt'`(仓库外),未改动任何仓库文件;`<verify>` 的基线断言为**幂等**(不覆写),故对比基准恒为执行前状态,可检出 Task 1 期间的越界写入
|
||||
- 文档 `09-DATA-MIGRATION-AUDIT.md` 存在,含 `## 0. 盘点口径与范围`(范围 / 落点接线边界 / **`blocksInfo` 名词说明** / 方法论 / D-72 规则原文 + 例外 / 命名待报备说明 / 只读声明)、`## 1. 图块定义 tile`、`## 2. 贴图素材 textures`
|
||||
- §1 给出 `cls → TileType` 与字段映射候选、id/num 全清单、贴图归属;§2 逐一登记 **materials + autotiles + tilesets** 三类 PNG 与像素尺寸、按 D-72 给出 materials 目标拆分方案(单帧对应 `addGrid`、多帧对应 `addRowAnimate`)、给出 autotiles(`addAutotile`)/ tilesets(`addTileset`)**例外**参数候选、命名候选表(标注「待用户报备批准」)
|
||||
- 含机器可读 `TILE-COUNT:` / `MATERIAL-COUNT:`(计入三类 PNG 总数)/ `SPLIT-COUNT:`;全部 `file:line` 锚点文件存在且行号在范围内;无法确定者入 §8(Task 2 补齐)而非臆造
|
||||
- 未改动任何 `.ts`/`.tsx`、`public/project/**`、`src/content/**`;未生成任何 `.png`;未改任何既有注释;未改 `files_modified` 外文件
|
||||
</acceptance_criteria>
|
||||
<done>第 0 节与 §1、§2 撰写完成,TILE/MATERIAL/SPLIT 计数写入;materials 拆分方案与 autotiles/tilesets 例外登记就位;只读基线与静态门禁全绿</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2(§3 enemy + §4 items + §5 NPC + §6 maps + §7 schema 草案 + §8 未确定项 + §9 汇总 + 收口):完成剩余维度映射候选、schema 草案(与 §2 一致)与汇总计数,跑最终静态门禁并写 SUMMARY</name>
|
||||
<precondition>Task 1 已完成(文档第 0 节与 §1、§2 已就位;只读基线文件存在于仓库外,且由 Task 1 `<action>` 步骤 (0) 采集、未被覆写)。</precondition>
|
||||
<files>.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md, .planning/phases/09-minimum-browser-runnable/09-17-SUMMARY.md</files>
|
||||
<read_first>
|
||||
- .planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md(本文件现状:第 0 节 + §1 + §2,待补 §3..§9)
|
||||
- public/project/enemys.js(全表;首项 `:3`;字段 `name`/`hp`/`atk`/`def`/`money`/`exp`/`point`/`special`/`value`/`range`/`faceIds`/`bigImage`/`notBomb` 等)
|
||||
- packages-user/data-common/src/store/types.ts:319-340(`IEnemyRawData`)
|
||||
- public/project/items.js(全表;`cls` 实测 `tools` / `items` / `equips` / `constants`;字段 `name`/`text`/`hideInToolbox`/`itemEffect`/`itemEffectTip`/`useItemEffect`/`useItemEvent`/`canUseItemEffect`/`equip` 等)
|
||||
- packages-user/data-common/src/store/types.ts:125-193(`ItemCategory` / `IItemEffect` / `IItemEquipData` / `IItemRawData`)
|
||||
- public/project/floors/empty.js、MT0.js、sample0.js、sample1.js、sample2.js(`main.floors.<id> = {…}`;字段 `floorId`/`title`/`width`/`height`/`map`(二维数组)/`events`/`changeFloor`/`afterBattle`/`afterGetItem`/`afterOpenDoor`/`cannotMove`/`bgmap`/`fgmap`/`autoEvent` 等)
|
||||
- packages-user/data-common/src/store/types.ts:260-285(`IMapRawData`)
|
||||
- packages-user/client-base/src/material/types.ts:217-307(`addGrid` / `addRowAnimate` / `addAutotile` / `addTileset` 参数形状,供 §7 schema 草案)
|
||||
- src/content/enemy.jsonc、src/content/item.jsonc、src/content/defaults/{enemy,item,map,texture}.jsonc(目标 schema 骨架,供映射候选与草案对照)
|
||||
- dev.md(命名;Markdown 连字符命名);AGENTS.md(命名须先报备;只读边界)
|
||||
</read_first>
|
||||
<action>
|
||||
(1) **§3 `## 3. 怪物 enemy`:** 用 `node` 只读解析 `public/project/enemys.js`,逐条登记 `id → IEnemyRawData` 映射候选:`num`(由 §1 的 `enemys` / `enemy48` 图块数字得来)、`attribute`(`name` / `hp` / `atk` / `def` / `money` / `exp` / `point` 等落点)、`special`(旧 `special` 为数字数组、伴随 `value` / `range` / `zoneSquare` / `add` 等字段 → 新 `Record<number, any>` 映射候选);`faceIds` / `bigImage` / `notBomb` 的归属候选(`enemy48` 变体合并入 `enemy`,D-72①)。给出 `ENEMY-COUNT:`。
|
||||
|
||||
(2) **§4 `## 4. 道具 items`:** 用 `node` 只读解析 `public/project/items.js`,逐条登记 `id → IItemRawData` 映射候选:`category`(`cls` → `ItemCategory`:`tools` / `constants` / `equips` 归属候选,`items` → `ItemCategory` 归属候选——说明映射依据,不确定者进 §8);`name` / `text` / `hideInToolbox`;效果脚本(`itemEffect` / `useItemEffect` / `useItemEvent` / `canUseItemEffect` / `itemEffectTip`)→ `IItemEffect`(`useEvent` / `useEffect` / `canUse`)归属候选;装备(`equips` 项的 `equip`)→ `IItemEquipData`(`slots` / `animate` / `value` / `percentage` / `loadEvent` / `unloadEvent`)归属候选;`num` 由 §1 的 `items` 图块数字得来。给出 `ITEM-COUNT:`。
|
||||
|
||||
(3) **§5 `## 5. NPC`:** 用 §1 的 `npcs` / `npc48` 图块集合,给出合并为 `npc` 的**图块映射候选**(`npcs` 14 条 + `npc48` 10 条,规划日实测;执行日以实测为准)与**贴图归属候选**(`npcs.png` + `npc48.png` → 一张 `npc`,D-72①)。给出 `NPC-COUNT:`。
|
||||
|
||||
(4) **§6 `## 6. 地图 maps`:** 逐一解析 `public/project/floors/*.js`,给出 `id → IMapRawData` 映射候选:`floorId` ← 楼层 id;`width` ← 旧 `width`;`map`(新 `Record<number, number[]>`)← 旧二维数组 `map` 的**层级映射候选**(如按行索引 → 键),`layerAlias`(`Record<number,string>`)与旧二维数组 / `bgmap` / `fgmap` 的关系候选;`events`(`Record<number, Record<number, Record<number, string>>>`)← 旧 `events` 的归属候选。旧 `title` / `height` / `firstArrive` / `changeFloor` / `afterBattle` / `afterGetItem` / `afterOpenDoor` / `cannotMove` / `autoEvent` 等字段的归属与取舍(能定者给落点;不能定者入 §8)。给出 `MAP-COUNT:`(楼层文件数)。
|
||||
|
||||
(5) **§7 `## 7. 贴图列表 schema 草案(texture/.list.jsonc)`:** 依 `ITextureManager` 的 `addGrid`(`source` / `map` / `width` / `height`)、`addRowAnimate`(`source` / `map` / `width` / `height`)、`addAutotile`(`source` / `identifier` / `type: AutotileType`)、`addTileset`(`source` / `identifier: IIndexedIdentifier` / `cellWidth` / `cellHeight`)能力,**反向设计** `src/content/texture/.list.jsonc` 的字段结构**草案**,**须与 §2 的登记逐条一致**:materials 图 → `grid`(单帧,4×4 切格)/ `rowAnimate`(多帧,帧数列×4 行)条目;`autotiles/*.png` → `autotile` 条目(承载 `identifier` 与 `type`,对应 `addAutotile`);`tilesets/*.png` → `tileset` 条目(承载 `identifier` 与 `cellWidth` / `cellHeight`,对应 `addTileset`)。**仅草案**;所有新字段命名列入「命名候选(待报备)」表,标注「待用户报备批准」,**不落地写入任何文件**(D-73 / OI-3 / OI-5)。
|
||||
|
||||
(6) **§8 `## 8. 未确定项 / 待确认观察`:** 集中登记所有无法从阅读 / 静态解析确定的内容与疑似不一致(**不得登记为缺陷**,仅作待确认观察);每条写明「缺什么才能确定」,供用户裁定(含 autotiles 自动元件类型无法由尺寸判定者、tilesets 切格尺寸不确定者)。
|
||||
|
||||
(7) **§9 `## 9. 汇总`:** 汇总表 `| 维度 | 计数 | 说明 |`,覆盖七个维度;并在表下重申机器可读计数行 `TILE-COUNT:` / `MATERIAL-COUNT:` / `SPLIT-COUNT:` / `ENEMY-COUNT:` / `ITEM-COUNT:` / `NPC-COUNT:` / `MAP-COUNT:`(与各节一致)。
|
||||
|
||||
(8) **收口与门禁:** 不改任何源码 / 数据;不改任何既有注释;不生成任何 PNG;文档 LF。本任务 `<verify>` 运行最终静态门禁(§3..§9 章节 + 各维度计数 + 锚点有效性 + 只读守卫)。
|
||||
|
||||
(9) **写 `09-17-SUMMARY.md`:** 记录盘点范围(六类,textures 含 materials + autotiles + tilesets)、七个维度、各维度计数、产出文档路径、只读确认、命名候选清单、OI-1..OI-6 的最终裁定。
|
||||
</action>
|
||||
<reversibility rating="reversible">纯新增只读文档(盘点文档 + SUMMARY);删除 / `git revert` 可整体回退;未触及任何源码或数据文件。</reversibility>
|
||||
<verify>
|
||||
<automated>node -e "const fs=require('fs');const p='.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-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 ['## 3.','## 4.','## 5.','## 6.','## 7.','## 8.','## 9.']){if(t.indexOf(s)<0)bad.push('missing heading: '+s)}for(const k of ['TILE-COUNT:','MATERIAL-COUNT:','SPLIT-COUNT:','ENEMY-COUNT:','ITEM-COUNT:','NPC-COUNT:','MAP-COUNT:']){if(!new RegExp(k+'\\s*\\d+').test(t))bad.push('missing '+k)}for(const m of ['IEnemyRawData','IItemRawData','ItemCategory','IMapRawData','addGrid','addRowAnimate','addAutotile','addTileset','待用户报备批准']){if(t.indexOf(m)<0)bad.push('missing token: '+m)}const anchors=[...t.matchAll(/((?:public\/project|packages-user|src\/content)\/[^\s|)\u0060]+\.(?:js|png|ts|tsx|jsonc)):(\d+)/g)];if(anchors.length<5)bad.push('too few anchors: '+anchors.length);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-MIG-FINAL GATE FAILED :: '+bad.join(' ; '));process.exit(1)}console.log('OK data-migration audit complete (sections 3-9, seven counts, mapping + addGrid/addRowAnimate/addAutotile/addTileset tokens, anchors valid)')"</automated>
|
||||
<fails_when>non-zero exit, 或 stderr 含 "AUDIT-MIG-FINAL GATE FAILED"(文档缺失 / 缺 §3..§9 任一章节 / 缺任一维度计数 / 缺映射目标 token(含 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset`)/ 锚点指向不存在的文件或越界行号)</fails_when>
|
||||
<automated>node -e "const {execSync}=require('child_process');const fs=require('fs');const base=process.env.TEMP+'/opencode/gsd-09-17-baseline.txt';const cur=execSync('git status --porcelain',{encoding:'utf8'}).split(/\r?\n/).filter(Boolean).map(l=>l.slice(3).trim()).filter(p=>/(\.(ts|tsx)$|^public\/project\/|^src\/content\/)/.test(p)).sort();const prev=fs.existsSync(base)?fs.readFileSync(base,'utf8').split(/\r?\n/).filter(Boolean).sort():[];const added=cur.filter(x=>!prev.includes(x));if(added.length){console.error('READONLY FAILED :: new source/data changes :: '+added.join(' | '));process.exit(1)}console.log('OK read-only final: no new .ts/.tsx/public-project/src-content changes vs pre-write baseline')"</automated>
|
||||
<fails_when>non-zero exit, 或 stderr 含 "READONLY FAILED"(本计划执行期新增了 `.ts`/`.tsx` / `public/project/**` / `src/content/**` 改动,违反 D-74/D-75 只读)</fails_when>
|
||||
<automated>git status --porcelain</automated>
|
||||
<fails_when>输出包含本计划 `files_modified`(`09-DATA-MIGRATION-AUDIT.md` + `09-17-SUMMARY.md`)之外、且**基线不存在**的生产文件或数据改动(如 `.ts`/`.tsx`、`public/project/**`、`src/content/**`、`package.json`);用户既有并发改动(D-56)不计</fails_when>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- 文档含 `## 3. 怪物 enemy` / `## 4. 道具 items` / `## 5. NPC` / `## 6. 地图 maps` / `## 7. 贴图列表 schema 草案` / `## 8. 未确定项 / 待确认观察` / `## 9. 汇总`
|
||||
- §3/§4 逐条给出 `IEnemyRawData`(`attribute`/`special`)与 `IItemRawData`(`category` 由 `cls` 映射、`equip` 与效果脚本归属)映射候选;§5 给出 npcs/npc48 合并为 `npc` 的图块与贴图归属候选;§6 给出 `IMapRawData`(`width`/`map`/`layerAlias`/`events`)映射候选
|
||||
- §7 给出 `texture/.list.jsonc` 字段结构草案并与 `addGrid`/`addRowAnimate`/`addAutotile`/`addTileset` 对应,且**与 §2 登记一致**(materials → grid/rowAnimate;autotiles → autotile;tilesets → tileset);所有新增命名标注「待用户报备批准」且未落地
|
||||
- §8 集中登记未确定项 / 待确认观察(**未登记为缺陷**);§9 汇总含七维度计数(`TILE-COUNT:` / `MATERIAL-COUNT:` / `SPLIT-COUNT:` / `ENEMY-COUNT:` / `ITEM-COUNT:` / `NPC-COUNT:` / `MAP-COUNT:`)
|
||||
- 全部 `file:line` 锚点指向真实存在且行号在范围内的行(无臆造);未改动任何 `.ts`/`.tsx`、`public/project/**`、`src/content/**`;未生成任何 `.png`;未改任何既有注释;`09-17-SUMMARY.md` 已写
|
||||
</acceptance_criteria>
|
||||
<done>§3..§9 完成、七维度计数齐备、schema 草案(与 §2 一致)与命名候选就位;最终静态门禁 + 锚点校验 + 只读守卫全绿;SUMMARY 落盘</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 只读边界 | 盘点只读取 `public/project/**` 与 `src/content/**` 与类型定义;**禁止任何源码 / 数据写入与 PNG 生成**(D-74 / D-75) |
|
||||
| 范围边界 | 只覆盖六类(tile / maps / textures(含 materials + autotiles + tilesets)/ enemy / items / NPC);`animation` 素材不处理;`images`/`sounds`/`bgms`/`fonts` 不在范围(D-71) |
|
||||
| 拆分规则边界 | materials 依 D-72 五规则;**tilesets / autotiles 不套用 D-72⑤**,走 `addTileset` / `addAutotile` 参数登记 |
|
||||
| 命名边界 | 任何新增 / 修改命名(拆分文件名、`identifier` / 参数名、schema 字段名)只作候选入台账、标注「待用户报备批准」,不得落地使用(D-73 / AGENTS.md) |
|
||||
| 产出边界 | 仅允许写 `09-DATA-MIGRATION-AUDIT.md` 与 `09-17-SUMMARY.md`(+ 仓库外只读基线);**不生成任何 `.png`**(D-75) |
|
||||
| 提交边界 | 不得把用户并发改动(D-56)纳入暂存 / 提交;不改 `ROADMAP.md` / `STATE.md` |
|
||||
|
||||
**威胁级别说明(security_enforcement = ASVS L1,block on high):** 本计划为**纯只读 Markdown 盘点**,不执行任何生产代码、不引入依赖、不做任何写入面扩展,**不存在 `high` 级威胁**;下列寄存器均为 `medium` 及以下,并逐条给出缓解。
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-09-17-01 | Tampering | 借「盘点」之机修改 / 新增生产源码或数据(`.ts`/`.tsx`、`public/project/**`、`src/content/**`) | medium | mitigate | `files_modified` 白名单 + prohibitions + Task 1/2 `READONLY` 门禁(与**执行前**(Task 1 `<action>` 步骤 (0) 写入、`<verify>` 幂等不覆写)的基线对比,检出执行期任何新增改动) |
|
||||
| T-09-17-02 | Elevation of Privilege | 未经批准即执行 / 使用未报备命名(含 `identifier` / schema 字段名) | medium | mitigate | Task 0 `blocking-human`;命名候选仅入台账并标注「待用户报备批准」;prohibitions 禁未获批命名落地 |
|
||||
| T-09-17-03 | Tampering | 臆造条目(编造字段 / 映射 / 尺寸 / 自动元件类型 / 切格尺寸,或指向不存在文件 / 越界行号) | medium | mitigate | `<action>` 要求逐项实测;尺寸不足以判定者入 §8;Task 1/2 门禁逐一校验「文件存在 + 行号在范围内」 |
|
||||
| T-09-17-04 | Tampering | 生成 / 覆写 PNG 素材(违反 D-75) | medium | mitigate | prohibitions 明列不生成素材;只读守卫覆盖 `public/project/**` 与 `src/content/**`(基线对比) |
|
||||
| T-09-17-05 | Information Disclosure | 盘点范围外泄(处理 animation / images / sounds / bgms / fonts) | low | mitigate | §0 与 prohibitions 明列六类范围;`<verification>` 复述 |
|
||||
| T-09-17-06 | Tampering | `autotiles` / `tilesets` 被误套 D-72⑤ 拆分,或 §2 登记与 §7 schema 不一致 | medium | mitigate | §2 / §7 `<action>` 双处明确例外并对齐;Task 2 shell token 门禁同时要求 `addAutotile` / `addTileset` 且 §7 明列「与 §2 一致」 |
|
||||
| T-09-17-07 | Repudiation | 未跑静态门禁即提交 / 未记录只读确认 | low | mitigate | Task 1/2 各有自动化门禁 + `09-17-SUMMARY.md` 只读确认;未通过不得提交 |
|
||||
| T-09-17-SC | Tampering | npm/pip/cargo installs | low | accept | 无第三方包安装、无依赖安装(纯只读盘点,不改 `package.json`) |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- **Task 1**:只读基线由 `<action>` 步骤 (0) 一次性采集(仓库外),`<verify>` 断言**幂等**(不覆写,保证对比基准为执行前状态);`09-DATA-MIGRATION-AUDIT.md` 存在,含 `## 0.` / `## 1.` / `## 2.`;含 `TILE-COUNT:` / `MATERIAL-COUNT:`(计入 materials + autotiles + tilesets)/ `SPLIT-COUNT:`;含 `TileType` / `ITileRawData` / `animates` / `terrains` / `4×4` 与 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset` token;含「待用户报备批准」命名候选标记;锚点有效;只读(无新增 `.ts`/`.tsx`/`public/project`/`src/content` 改动,含 Task 1 动作阶段)。
|
||||
- **Task 2**:含 `## 3.` / `## 4.` / `## 5.` / `## 6.` / `## 7.` / `## 8.` / `## 9.`;含七维度计数;含 `IEnemyRawData` / `IItemRawData` / `ItemCategory` / `IMapRawData` 与 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset` token;含「待用户报备批准」标记;全部锚点有效;只读。
|
||||
- **只读守卫**:执行期无**新增** `.ts`/`.tsx`/`public/project/**`/`src/content/**` 改动(与**执行前**基线对比,基线仅由 Task 1 `<action>` 步骤 (0) 写入、`<verify>` 幂等不改写);`files_modified` 外无越界生产文件或数据改动。
|
||||
- **无全仓门禁**:全程不使用 `pnpm check:type` / `pnpm build` / 全仓 TS 诊断数。
|
||||
- **人工复核**:结论写入 `09-17-SUMMARY.md`(含七维度计数、命名候选清单、OI-1..OI-6 的最终裁定)。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 盘点范围恰好六类(tile / maps / textures / enemy / items / NPC);`animation` 素材不处理、`images`/`sounds`/`bgms`/`fonts` 不在范围(D-71);**textures 维度显式含 `materials/*.png` + `autotiles/*.png` + `tilesets/*.png`**。
|
||||
- §1 给出 `blocksInfo` 全表 + `cls → TileType` 与字段映射候选 + id/num 全清单;§2 逐一登记 materials + autotiles + tilesets 三类 PNG 与像素尺寸 + 按 D-72 五规则的 materials 拆分方案(单帧 `addGrid` / 多帧 `addRowAnimate`)+ **autotiles(`addAutotile`)/ tilesets(`addTileset`)例外参数候选** + 命名候选(待报备)。
|
||||
- §3/§4/§5/§6 分别给出 `IEnemyRawData` / `IItemRawData` / NPC 合并 / `IMapRawData` 的映射候选;§7 给出 `texture/.list.jsonc` 字段结构草案并与 `addGrid`/`addRowAnimate`/`addAutotile`/`addTileset` 对应,且与 §2 一致。
|
||||
- 台账事实行带 `file:line` 锚点;无法确定者进 §8「未确定项」,**未登记为缺陷**;命名候选只报备不落地;含七维度计数与汇总表。
|
||||
- 全程只读:零 `.ts`/`.tsx` 改动、零 `public/project/**` 与 `src/content/**` 改动、零 PNG 生成;唯一写入为盘点文档 + `09-17-SUMMARY.md`(+ 仓库外只读基线)。只读守卫以**执行前**基线为对比基准(Task 1 `<action>` 步骤 (0) 写入、`<verify>` 幂等不覆写),可检出执行期(含 Task 1 动作阶段)的越界写入。
|
||||
- 产出文档路径经 Task 0 批准;静态门禁(文档结构 / 锚点有效性 / 只读)全绿。
|
||||
</success_criteria>
|
||||
|
||||
## Artifacts this phase produces
|
||||
|
||||
| 符号 / 路径 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md`(新增) | 只读盘点文档 | §0 口径与范围 + §1 tile(`cls → TileType`、字段映射候选、id/num 全清单)+ §2 textures(materials + autotiles + tilesets 登记 + 像素尺寸 + D-72 拆分方案(含 tilesets/autotiles 例外)+ 命名候选)+ §3 enemy + §4 items + §5 NPC + §6 maps + §7 `texture/.list.jsonc` schema 草案(与 §2 一致)+ §8 未确定项 + §9 汇总与七维度计数(命名待批准,OI-1) |
|
||||
| `.planning/phases/09-minimum-browser-runnable/09-17-SUMMARY.md`(新增) | 执行摘要 | 盘点范围、七维度、各维度计数、产出路径、只读确认、命名候选清单、OI-1..OI-6 裁定 |
|
||||
|
||||
**命名说明:** 本计划**新增的唯一命名**是产出文档文件名 `09-DATA-MIGRATION-AUDIT.md`(连字符命名法);**不引入任何源码 / 数据命名**,**不改任何既有文件命名**;盘点中提出的所有候选命名(含 `addAutotile` / `addTileset` 的 `identifier` 与参数名、schema 字段名)**只作台账记录并标注「待用户报备批准」,不落地使用**。
|
||||
|
||||
## Source Coverage Audit
|
||||
|
||||
| 来源 | 项 | 处置 |
|
||||
|------|----|------|
|
||||
| GOAL | Phase 9(ROADMAP)「在已完成的数据端之上完成渲染端框架,产出可在浏览器中运行并验证的最小版本」 | COVERED(增量·任务 8 只读盘点子切片:为旧引擎数据迁移提供台账) |
|
||||
| REQ | Phase 9 ROADMAP「Requirements: TBD」,无需求 ID | N/A(`requirements: []` 如实标注) |
|
||||
| RESEARCH | 无 RESEARCH.md(本阶段为增量派发,无独立研究产物) | N/A |
|
||||
| CONTEXT | D-70(落点 `src/content`;消费接线由用户后续提供,本次不实现) | COVERED(§0 范围与接线边界;prohibitions) |
|
||||
| CONTEXT | D-71(六类范围;animation 暂不处理;images/sounds/bgms/fonts 不在范围) | COVERED(§0 + §1..§6;prohibitions) |
|
||||
| CONTEXT | D-71 补充(`autotiles/*.png` 与 `tilesets/*.png` 归入 textures 纳入盘点,2026-10-13) | COVERED(§2 登记 + Task 0 汇报 ②③ + Task 1 action(4) + gate token `addAutotile`/`addTileset`;key_links 三条素材链接) |
|
||||
| CONTEXT | D-72(五条合并 / 分图规则) | COVERED(§0 规则原文 + §2 materials 拆分方案 + §5 NPC 合并;门禁校验 `animates`/`terrains`/`4×4`) |
|
||||
| CONTEXT | D-72 例外(tilesets/autotiles 不套用⑤,走 addTileset/addAutotile) | COVERED(§2 例外登记 + §7 schema 一致 + Task 0 汇报 ④ + prohibitions「例外不得遗漏」) |
|
||||
| CONTEXT | D-73(命名须先报备;schema 反向设计) | COVERED(§2 / §7 命名候选 + 门禁校验「待用户报备批准」标记 + prohibitions) |
|
||||
| CONTEXT | D-74(本次规划单元 = 只读盘点;产出 `09-DATA-MIGRATION-AUDIT.md`) | COVERED(Task 0 OI-1 + Task 1/2 产出;只读守卫) |
|
||||
| CONTEXT | D-75(素材迁移阶段由 AI 脚本生成 PNG;本盘点不生成) | COVERED(prohibitions + 只读守卫覆盖 `public/project`/`src/content`) |
|
||||
| CONTEXT | D-03 / D-04 / D-06(执行前获批 / 命名获批 / 不扩范围) | COVERED(Task 0 + prohibitions + 范围门禁) |
|
||||
| CONTEXT | Deferred Ideas | DEFERRED(未纳入任何任务) |
|
||||
| 增量维度 | 图块 tile / 贴图 textures / 怪物 enemy / 道具 items / NPC / 地图 maps / 贴图列表 schema 草案(increment_scope 七项) | COVERED(§1 / §2 / §3 / §4 / §5 / §6 / §7;§8 未确定项;§9 汇总) |
|
||||
| 缺口 | 无(盘点维度已由 increment_scope 完整给定,含 autotiles/tilesets 纳入裁定) | CLOSED |
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/09-minimum-browser-runnable/09-17-SUMMARY.md` when done
|
||||
</output>
|
||||
|
||||
<!--
|
||||
与既有只读盘点计划的既有范式对齐说明(09-11 / 09-12):
|
||||
- 三任务结构:Task 0 `checkpoint:decision@blocking-human`(执行前获批)+ Task 1/2 `auto`(分节撰写 + 只读守卫)。
|
||||
- 只读产物唯一、无 `files_modified` 外扩;静态 node 门禁;只读守卫采用「执行前基线对比」(因执行期可能存在用户并发改动 D-56)。
|
||||
- `ROADMAP.md` / `STATE.md` 的跟踪同步属 orchestrator 收尾步骤,本计划不编辑、不暂存、不提交(先例:09-11 / 09-12)。
|
||||
|
||||
修订(2026-10-13,解决 checker warning:requirement_coverage):
|
||||
- §2 textures 维度显式登记 `public/project/autotiles/*.png` 与 `public/project/tilesets/*.png`(内容 + 像素尺寸),与 `materials/*.png` 并列。
|
||||
- 声明拆分规则例外:tilesets → `addTileset`(source/identifier/cellWidth/cellHeight)、autotiles → `addAutotile`(source/identifier/type: AutotileType 2×3 Small2x3 / 3×4 Big3x4),**不套用** D-72⑤ 的 4×4 / 帧数列×4 行拆分;各自给出参数候选 + 命名候选(标注「待用户报备批准」)。
|
||||
- Task 0 预执行汇报明确纳入 autotiles/tilesets;prestate 门禁校验 `public/project/autotiles` 与 `public/project/tilesets` 目录存在。
|
||||
- §7 schema 草案与 §2 登记逐条一致(materials → grid/rowAnimate;autotiles → autotile;tilesets → tileset)。
|
||||
- Task 1 `<automated>` 断言的每个 token(含 `addGrid` / `addRowAnimate` / `addAutotile` / `addTileset`)均在 Task 1 `<action>` 中明确指示,不再有未落地的 token。
|
||||
- key_links 新增 autotiles / tilesets PNG ↔ `addAutotile`(`:289`)/ `addTileset`(`:302`)两条链接,与 materials ↔ `addGrid`/`addRowAnimate` 并列。
|
||||
|
||||
修订(2026-10-13,revision 3,解决 checker warning:task_completeness —— Task 1 只读守卫无法检出 Task 1 期间写入):
|
||||
- 根因:`execute-plan.md` 规定 `<verify>` 在该任务动作之后运行;Task 1 `<verify>` 首个 `<automated>` 会重跑 `fs.writeFileSync(base, <current git status>)`,把基线覆写为「含 Task 1 动作后状态」的值,于是第三个 `<automated>` 的 `cur - prev` 差值对 Task 1 期间的越界写入恒为空 —— 正是在违规场景下失效。
|
||||
- 修复:将 Task 1 `<verify>` 的基线采集改为**幂等**——基线已存在则**不覆写**(打印保留提示),仅在步骤 (0) 未落下基线时兜底写入。基线因此仅由 Task 1 `<action>` 步骤 (0)(任何写入之前)写入一次,`<verify>` 的对比基准恒为**执行前**状态,可检出 Task 1 期间新增的 `.ts`/`.tsx`/`public/project/**`/`src/content/**` 改动。
|
||||
- 同步更新:Task 1 `<action>` 步骤 (0)、`assumptions`(D-56 条)、`acceptance_criteria`、`<verification>`、`success_criteria`、`<threat_model>` 的 T-09-17-01,均明确「基线一次性写入、`<verify>` 幂等不覆写」。Task 2 的只读守卫未改动(其只读基线、不写入)。
|
||||
|
||||
修订(2026-10-13,revision 3,info advisory:`blocksInfo` 名词消歧义):
|
||||
- `blocksInfo` 为运行时名称(`core.maps.blocksInfo`),并非 `public/project/maps.js` 中的字面键名(该文件顶层字面形态为 `var maps_<hash> = { "1": {…}, … }`,首项 `:3`)。
|
||||
- 已在 §0(Task 1 action 步骤 (2))加入「名词说明(`blocksInfo`)」,并在 §1(Task 1 action 步骤 (3))与 Task 0 汇报 ③、`must_haves.truths` 维度 1、`assumptions` 中同步指明,避免执行者按字面串检索 `blocksInfo` 而误判。
|
||||
-->
|
||||
@ -158,6 +158,17 @@
|
||||
|
||||
- **D-55(任务 7 阻断标记):** `09-14` / `09-15` / `09-16` 标记为**暂时无法执行(BLOCKED)**。共同根因:相关调用点在**模块级文件**(无法经 props 取主对象、且禁 `client` 单例)或依赖**未导出类型 / 主对象缺失接口 / 无等价物 API**。完成情况:仅 `09-13`(回退层去除 + 调用点)已落地;`A-6`(loading)由用户自行处理;存档相关(`A-1-1` + 7 条)按 D-54 延后。**待用户提供/调整注入路径与缺失接口后另行规划。**
|
||||
|
||||
### 任务 8(当前规划单元:旧引擎数据迁移)
|
||||
|
||||
> 本节界定**本次规划运行**的范围:仅规划任务 8 的**只读盘点**计划;实际迁移在盘点执行后由用户再派发时另行规划。旧数据位于 `public/project`(素材 `materials/*.png`、`animates/*.animate`、`images/`、`tilesets/`、`autotiles/`、`sounds/`、`bgms/`,逻辑数据 `maps.js` 的 `blocksInfo`、`items.js`、`enemys.js`、`events.js`、`functions.js`、`floors/*.js`);新引擎数据存储落点为 `src/content`(`client.jsonc`/`core.jsonc`/`tile.jsonc`/`enemy.jsonc`/`item.jsonc`/`maps/`/`texture/.list.jsonc`/`animation/.list.jsonc` 及 `defaults/*`)。
|
||||
|
||||
- **D-70(落点与接线边界):** 迁移目标为 `src/content`(jsonc 数据 + 素材文件)。把配置写入 store、把贴图列表写入 `TextureManager` 的**消费接线由用户后续单独提供**,本次不实现接线。
|
||||
- **D-71(范围):** 本次迁移覆盖 **图块定义 tile、地图 maps、贴图素材 textures、怪物 enemy、道具 items、NPC** 六类;`animation` 素材**暂不挪**(不处理 `animates/*.animate`)。`images/sounds/bgms/fonts` 不在本次迁移范围。`public/project/autotiles/*.png` 与 `public/project/tilesets/*.png` 归入「贴图素材 textures」维度,**纳入**本次盘点与迁移(2026-10-13 用户裁定)。
|
||||
- **D-72(合并 / 分图规则):** ① `npc` 与 `npc48`、`enemy` 与 `enemy48` 均**合并**(不再有 48 变体);② `terrains`/`items`/`enemy`/`npc` **分别存储**,不得混入同一张图片;③ `animates` **合并入 `terrains`**;④ **不同帧数**的素材不得放入同一张图片;⑤ 单帧素材按 **4×4** 规格拆分,多帧素材按「**帧数列 × 4 行**」拆分。
|
||||
- **D-73(贴图列表 schema 与命名):** `texture/.list.jsonc`(及 `animation/.list.jsonc`)的字段结构由 AI 依据 `TextureManager` 的 `addGrid`/`addRowAnimate`/`addAutotile`/`addTileset` 能力反向设计;**新增或修改的任何公共 / 受保护 / 私有方法、字段等命名,必须先向用户报备并获批准后方可使用**(符合 `AGENTS.md`)。
|
||||
- **D-74(本次规划单元 = 只读盘点):** 本规划运行只产出**只读盘点**计划,盘点产物文档为 `.planning/phases/09-minimum-browser-runnable/09-DATA-MIGRATION-AUDIT.md`;**全程只读**——零生产代码改动、零数据文件改动、零 PNG 生成。盘点内容须为后续“迁移计划”提供可直接消费的映射台账(含字段映射候选与待报备命名候选)。实际迁移计划在盘点执行后由用户再派发。
|
||||
- **D-75(素材生成归属):** 迁移阶段将由 AI **用脚本生成**符合 D-72 规则的 PNG 素材文件;本盘点阶段**不生成**任何素材。
|
||||
|
||||
### the agent's Discretion
|
||||
|
||||
- 无。用户明确未授权 AI 自行决定 UI 形态或任务范围。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user