mirror of
https://github.com/motajs/template.git
synced 2026-10-14 08:40:16 +08:00
docs(08): plan phase 8 test refactor and alignment
Register Phase 8 (TEST-02), mark 07-16 superseded, add CONTEXT/RESEARCH/PATTERNS/PLAN-CHECK and 08-01..08-11 plans; record 08-01 migration summary.
This commit is contained in:
parent
36d8b4fb3c
commit
b053c509c7
@ -35,6 +35,7 @@ Requirements for the engine's completion. Each maps to roadmap phases.
|
||||
### 测试(Testing)
|
||||
|
||||
- [ ] **TEST-01**: 为核心系统(数据层等)补齐单元测试
|
||||
- [ ] **TEST-02**: 测试文件统一归入 `__test__` 目录,并按数据端当前接口对齐既有测试、修复重构遗漏导致的测试失效
|
||||
|
||||
### 数据端缺陷修复(Fix)
|
||||
|
||||
@ -67,15 +68,17 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
| LEGACY-01 | Phase 5 | Pending |
|
||||
| LEGACY-02 | Phase 5 | Pending |
|
||||
| TEST-01 | Phase 6 | In Progress |
|
||||
| TEST-02 | Phase 8 | Pending |
|
||||
| FIX-01 | Phase 7 | Complete |
|
||||
|
||||
**Coverage:**
|
||||
|
||||
- v1 requirements: 12 total
|
||||
- Mapped to phases: 12
|
||||
- v1 requirements: 13 total
|
||||
- Mapped to phases: 13
|
||||
- Unmapped: 0 ✓
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-09-07*
|
||||
*Last updated: 2026-09-15: added FIX-01 (Phase 7 数据端缺陷修复); TEST-01 remains In Progress.*
|
||||
*2026-09-14: corrected TEST-01 from Complete to In Progress (Phase 6 data-layer slice done; rendering-side unit tests outstanding)*
|
||||
*2026-10-04: added TEST-02 (Phase 8 测试重构与接口对齐); 07-16 superseded.*
|
||||
|
||||
@ -350,7 +350,7 @@ Plans:
|
||||
3. pnpm test:ci 全绿且不新增跳过用例,数据范围 check:type / check:circular 门禁通过
|
||||
4. 改动仅限数据端(packages 与 packages-user/data-*),不改动渲染端 @user/client-* 与 legacy 渲染接线,双端分离约束保持
|
||||
|
||||
**Plans**: 16 plans — 07-01..07-15 已执行(07-15 完成 4 条复审缺口修复);**07-16 暂缓(DEFERRED)**:寻路重构后的测试对齐批次,待用户完成数据端手工修改后再执行(按 D-02 一系统一计划;每个计划以 D-09 预执行汇报关卡开头,`autonomous: false`)
|
||||
**Plans**: 16 plans — 07-01..07-15 已执行(07-15 完成 4 条复审缺口修复);**07-16 标记为 SUPERSEDED(2026-10-04)**:寻路重构后的测试对齐批次不再执行,其缺口清单转为 Phase 8 的对齐输入(按 D-02 一系统一计划;每个计划以 D-09 预执行汇报关卡开头,`autonomous: false`)
|
||||
|
||||
> **阶段重开(2026-09-16)**:`07-LOADSTATE-AUDIT.md` 登记的同引用审计条目 `#06-17-1`(A)与 `#06-17-2`(B)在本阶段收口后追加为计划 `07-09`,Phase 7 因此由 `Complete` 回到未完成;执行 07-09 后 `07-VERIFICATION.md`(2026-09-16 结论仅覆盖 8/8 计划的工作树)**失效,必须重跑 `/gsd-verify-work`** 重新出具验证结论。
|
||||
|
||||
@ -361,10 +361,11 @@ Plans:
|
||||
|
||||
> **阶段四次追加(2026-09-17)**:用户完成寻路系统重构(`4aaea68`)后,数据端 **17 个测试文件 / 73 用例**因接口变动与形状变化失败(接口族:寻路 `useMapState`/`useDirGroup` 变更、录像 `route`→`array` 与 `onRecordCommand` 0-based 索引、`HeroLocation.setFloor(IGameMap)`、`CoreState.initMapState` 删除;另含 5 个疑似行为变化的文件)。经用户要求追加计划 `07-16`(**只改测试、不改生产代码**),已完成规划并登记缺口(`07-VERIFICATION.md` 的 `### Post-Refactor Test Breakage`)。
|
||||
> **该计划暂缓(DEFERRED)**:用户观察到数据端仍需大量手工修改、并将继续导致测试报错,故等数据端全部改完后再执行。恢复时该缺口清单(2026-09-17 快照)与 `07-16-PLAN.md` **须先重新核对(很可能需要重规划)**,再走 `/gsd-execute-phase 7 --gaps-only`;随后 `/gsd-verify-work 7` 重出验证。
|
||||
> **该计划 SUPERSEDED(2026-10-04)**:用户已完成数据端「系统性收尾」,接口再次变动,17 行快照与 `07-16-PLAN.md` 均已过期;该计划退役、不再执行,测试文件迁移与接口对齐整体转由 **Phase 8** 承接,`07-VERIFICATION.md` 的 `### Post-Refactor Test Breakage` 作为 Phase 8 的对齐输入。
|
||||
|
||||
Plans:
|
||||
|
||||
- [ ] 07-16-PLAN.md — **暂缓(DEFERRED)**:寻路重构后的测试对齐批次——把 17 个测试文件对齐到已发布接口(只改测试、不改生产代码),含 5 个疑似行为变化文件待用户 Task 0 逐行裁决。**待用户完成数据端手工修改后再执行**(恢复前须重新核对缺口清单与计划)
|
||||
- [x] 07-16-PLAN.md — **SUPERSEDED(2026-10-04)**:寻路重构后的测试对齐批次——原计划把 17 个测试文件对齐到 2026-09-17 快照的接口(只改测试、不改生产代码),含 5 个疑似行为变化文件待用户 Task 0 逐行裁决。因数据端「系统性收尾」再次变动接口,该快照与计划均已过期,**转由 Phase 8 承接**(缺口清单作为 Phase 8 输入)
|
||||
- [x] 07-15-PLAN.md — 复审缺陷批次:CR-01(`HeroEquipment.compareEquip` 对已装备项漏算)/ WR-01(`normalizeParam` 回退口径致字节偏移错位)/ WR-02(`checkBufferExpand` 乘数为 1 时自我递归)/ WR-03(`HeroAttribute.clone()` 绕过簿记)——**已执行**(`07-15-SUMMARY.md`)
|
||||
- [x] 07-10-PLAN.md — replay:CR-01(`set()` 索引数组损坏,与 `delete()` 对齐)/ 审计 H `#06-17-3`(`setReplayArray` 漏 `expireStreams`)/ WR-01(bigint 长度字节溢出)/ WR-02(参数计数用未截断长度)/ WR-03(编解码格式版本)/ WR-07(`insert`/`delete`/`set` 越界校验)
|
||||
- [x] 07-11-PLAN.md — 容器同引用:`#06-17-4`(`equipStore` 重建实例脱钩)/ `#06-17-5`(`flag/system` 字段脱钩)/ `#06-17-6`(followers 重建脱钩)
|
||||
@ -437,10 +438,41 @@ Plans:
|
||||
|
||||
- [x] 07-14-PLAN.md — legacy hero 代理:经用户裁定 **WONTFIX**(`#06-17-7`;兼容层即将删除,零代码、零测试;计划原定的该包首个测试文件按裁决不产出)
|
||||
|
||||
### Phase 8: 测试重构与接口对齐
|
||||
|
||||
**Goal**: 将全部测试文件(`.test.ts` / `.perf.ts`)迁入 `__test__` 目录,并按数据端「系统性收尾」后的当前接口重对齐测试、修复重构遗漏的细节问题,使 `pnpm test:ci` / `test:perf` 重新全绿
|
||||
**Depends on**: Phase 7(数据端缺陷修复)
|
||||
**Requirements**: TEST-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
|
||||
1. 全部 `.test.ts` 与 `.perf.ts` 均位于各自源码目录下的 `__test__` 文件夹内,测试命令仍能发现并运行它们
|
||||
2. 因数据端接口变动而失效的测试全部对齐到当前 shipped 接口,`pnpm test:ci` 0 失败
|
||||
3. 重构遗漏的细节问题已修复(测试面或经用户确认的数据端细节),不弱化既有断言
|
||||
4. `pnpm test:perf` 仍可运行;不新增跳过用例
|
||||
|
||||
**Plans**: 11 planned(08-01..08-11;规划 2026-10-04,`gsd-plan-checker` 判 PASS / 0 blocker / 3 非阻塞 warning)——迁移 `08-01`(独立先行)→ 子系统对齐 `08-02..08-09` → 错误码与接口覆盖 `08-10` → 收口 `08-11`;每个计划 `autonomous: false`,以 blocking-human Task 0 汇报关卡开头
|
||||
|
||||
Plans:
|
||||
|
||||
- [ ] 08-01-PLAN.md — 全量目录迁移到 `__test__/`(Rule A/B 分流改相对导入 + `script/test-data-node.ts:67,122` 硬编码路径;门禁=文件数守恒 66/6、零配置/零生产改动)
|
||||
- [ ] 08-02-PLAN.md — data-common 对齐(`utils.test.ts` 去留、`DirectionMapper` 删除、`addHook().load()` 移除、158/175→72)
|
||||
- [ ] 08-03-PLAN.md — data-base enemy+flag 对齐(`EnemyManager` 单参构造、legacy bridge 类型)
|
||||
- [ ] 08-04-PLAN.md — data-base hero 对齐(录像桩 `route`→`array`、`getItem`→`addItem`、`setFloor(IGameMap)`)
|
||||
- [ ] 08-05-PLAN.md — data-base map 对齐(`addLayer(alias)`、`MapState(state)`;陈旧码 62/63/64/84/130/125 裁决)
|
||||
- [ ] 08-06-PLAN.md — data-system combat+event 对齐(`CombatFlow` 构造、`.load()` 移除、DEV 守卫码)
|
||||
- [ ] 08-07-PLAN.md — data-system path 对齐(`useMapState` 删除、`useFaceHandler` 注入)
|
||||
- [ ] 08-08-PLAN.md — data-state src 对齐(`createCoreState` 删除→`CoreState({loadStarter,coreURL})`;`coreEventLayer` A1/A2)
|
||||
- [ ] 08-09-PLAN.md — data-state 集成对齐(共享夹具 `closed-loop.ts`、`tileLegacy` 去留、寻路注入)
|
||||
- [ ] 08-10-PLAN.md — 错误码 21 缺口 + loader 公共接口覆盖盘点与补测
|
||||
- [ ] 08-11-PLAN.md — 收口(`test:ci`+`test:perf` 全绿、skipped=1、零生产改动终审、阶段 SUMMARY)
|
||||
|
||||
**Scope note (2026-10-04)**: 由原 `07-16`(寻路重构后的测试对齐,已 SUPERSEDED)转来并扩展,加入「测试文件迁入 `__test__`」的组织重构要求。用户并发进行渲染端收尾,可能触及数据端内容但不改接口设计、不影响测试;AI 不得提交用户改动的文件,发生冲突须暂停汇报。
|
||||
**Input (2026-10-04)**: `07-VERIFICATION.md` 的 `### Post-Refactor Test Breakage`(2026-09-17 的 17 行快照)作为对齐起点,但**必须先重测当日失败清单**,不得直接沿用旧快照。
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
||||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
@ -450,4 +482,5 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
||||
| 4. 渲染适配与双布局 | 15/16 | In Progress| |
|
||||
| 5. Legacy 移植 | 0/TBD | Not started | - |
|
||||
| 6. 单元测试 | 18/18 | In Progress| |
|
||||
| 7. 数据端缺陷修复 | 15/16 | 暂缓 (Deferred) | - |
|
||||
| 7. 数据端缺陷修复 | 15/16 | Complete(07-16 superseded) | - |
|
||||
| 8. 测试重构与接口对齐 | 0/11 | Planned | - |
|
||||
|
||||
@ -236,6 +236,7 @@ Recent decisions affecting current work:
|
||||
### Roadmap Evolution
|
||||
|
||||
- Phase 7 added: 数据端缺陷修复(仅数据端;修复 Phase 6 单元测试暴露的疑似缺陷,使正确预期用例转绿,不含渲染端)
|
||||
- Phase 8 added (2026-10-04): 测试重构与接口对齐(测试文件迁入 `__test__` + 按数据端当前接口重对齐 + 细节修复);承接已 SUPERSEDED 的 07-16;需求 TEST-02
|
||||
|
||||
### Pending Todos
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
# Phase 7 — 接力说明(07-16 暂缓,等数据端改完再启动)
|
||||
# Phase 7 — 接力说明(07-16 已 SUPERSEDED)
|
||||
|
||||
**更新:** 2026-09-17(晚)
|
||||
> **SUPERSEDED(2026-10-04)**:`07-16-PLAN.md` 及其 17 行缺口快照(2026-09-17)已退役,不再执行;测试文件迁移与接口对齐整体移交 **Phase 8(测试重构与接口对齐)**。本文件保留为历史接力记录。
|
||||
|
||||
**更新:** 2026-09-17(晚)|**标记 superseded:** 2026-10-04
|
||||
**HEAD:** 见 `git log -1`(分支 `refactor/data`)
|
||||
|
||||
## 当前状态:**Phase 7 暂缓**
|
||||
## 当前状态:**07-16 SUPERSEDED(转 Phase 8)**
|
||||
|
||||
- `07-01..07-15` 全部已执行并提交。
|
||||
- `07-16`(寻路重构后的测试对齐)**已完成规划,但暂缓(DEFERRED)** —— 用户仍在手工重构数据端,接口/形状还会继续变,测试会持续报错。
|
||||
|
||||
372
.planning/phases/08-test-refactor-alignment/08-01-PLAN.md
Normal file
372
.planning/phases/08-test-refactor-alignment/08-01-PLAN.md
Normal file
@ -0,0 +1,372 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
# 迁移目标:同目录 __test__/(规则 A,+1 层)
|
||||
- packages-user/data-common/src/common/__test__/face.test.ts
|
||||
- packages-user/data-common/src/common/__test__/faceManager.test.ts
|
||||
- packages-user/data-common/src/common/__test__/indexer.test.ts
|
||||
- packages-user/data-common/src/common/__test__/mover.test.ts
|
||||
- packages-user/data-common/src/common/__test__/utils.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/array.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/func.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/sandbox.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/saveLoad.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/system.test.ts
|
||||
- packages-user/data-common/src/store/__test__/eventStore.test.ts
|
||||
- packages-user/data-common/src/store/__test__/tileStore.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/enemy.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/manager.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/special.test.ts
|
||||
- packages-user/data-base/src/flag/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/flag/__test__/system.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/attribute.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/attribute.perf.ts
|
||||
- packages-user/data-base/src/hero/__test__/equipStore.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/equipment.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/follower.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/items.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/location.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/modifier.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/mover.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/rendering.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/state.test.ts
|
||||
- packages-user/data-base/src/map/__test__/dynamicTile.test.ts
|
||||
- packages-user/data-base/src/map/__test__/eventPath.test.ts
|
||||
- packages-user/data-base/src/map/__test__/eventView.test.ts
|
||||
- packages-user/data-base/src/map/__test__/gameMap.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mapLayer.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mapLifecycle.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mapState.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mover.test.ts
|
||||
- packages-user/data-base/src/map/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/map/__test__/staticTile.test.ts
|
||||
- packages-user/data-base/src/map/__test__/tile.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/combat.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/context.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/context.perf.ts
|
||||
- packages-user/data-system/src/combat/__test__/damage.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/damage.perf.ts
|
||||
- packages-user/data-system/src/combat/__test__/mapDamage.test.ts
|
||||
- packages-user/data-system/src/event/__test__/eventDispatch.test.ts
|
||||
- packages-user/data-system/src/path/__test__/graph.test.ts
|
||||
- packages-user/data-system/src/path/__test__/performance.test.ts
|
||||
- packages-user/data-system/src/path/__test__/system.test.ts
|
||||
- packages-user/data-state/src/__test__/coreEventLayer.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/aura.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/calculator.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/comparer.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/final.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/mapDamage.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/special.test.ts
|
||||
- packages-user/data-state/src/event/__test__/event.test.ts
|
||||
- packages-user/data-state/src/replay/__test__/commands.test.ts
|
||||
- packages-user/data-state/__test__/coreNode.test.ts
|
||||
- packages-user/data-state/__test__/dataClosure.test.ts
|
||||
- packages-user/data-state/__test__/enemyCombination.test.ts
|
||||
- packages-user/data-state/__test__/nodeReplay.test.ts
|
||||
- packages-user/data-state/__test__/nodeTracer.test.ts
|
||||
- packages-user/data-state/__test__/replayPlayback.test.ts
|
||||
- packages-user/data-state/__test__/saveablesRoundTrip.test.ts
|
||||
- packages-user/data-state/__test__/tileLegacy.test.ts
|
||||
- packages-user/data-state/__test__/mapScenario.perf.ts
|
||||
- packages-user/data-state/__test__/saveables.perf.ts
|
||||
- packages-user/data-state/__test__/saveablesReal.perf.ts
|
||||
- packages-user/data-state/__test__/replayVerifier.ts
|
||||
- packages-user/data-state/__test__/fixtures/closed-loop.ts
|
||||
- packages-user/data-state/__test__/fixtures/floors.json
|
||||
- script/test-data-node.ts
|
||||
files_deleted:
|
||||
- packages-user/data-common/src/common/face.test.ts
|
||||
- packages-user/data-common/src/common/faceManager.test.ts
|
||||
- packages-user/data-common/src/common/indexer.test.ts
|
||||
- packages-user/data-common/src/common/mover.test.ts
|
||||
- packages-user/data-common/src/common/utils.test.ts
|
||||
- packages-user/data-common/src/replay/array.test.ts
|
||||
- packages-user/data-common/src/replay/func.test.ts
|
||||
- packages-user/data-common/src/replay/sandbox.test.ts
|
||||
- packages-user/data-common/src/replay/saveLoad.test.ts
|
||||
- packages-user/data-common/src/replay/system.test.ts
|
||||
- packages-user/data-common/src/store/eventStore.test.ts
|
||||
- packages-user/data-common/src/store/tileStore.test.ts
|
||||
- packages-user/data-base/src/enemy/enemy.test.ts
|
||||
- packages-user/data-base/src/enemy/manager.test.ts
|
||||
- packages-user/data-base/src/enemy/saveLoad.test.ts
|
||||
- packages-user/data-base/src/enemy/special.test.ts
|
||||
- packages-user/data-base/src/flag/saveLoad.test.ts
|
||||
- packages-user/data-base/src/flag/system.test.ts
|
||||
- packages-user/data-base/src/hero/attribute.test.ts
|
||||
- packages-user/data-base/src/hero/attribute.perf.ts
|
||||
- packages-user/data-base/src/hero/equipStore.test.ts
|
||||
- packages-user/data-base/src/hero/equipment.test.ts
|
||||
- packages-user/data-base/src/hero/follower.test.ts
|
||||
- packages-user/data-base/src/hero/items.test.ts
|
||||
- packages-user/data-base/src/hero/location.test.ts
|
||||
- packages-user/data-base/src/hero/modifier.test.ts
|
||||
- packages-user/data-base/src/hero/mover.test.ts
|
||||
- packages-user/data-base/src/hero/rendering.test.ts
|
||||
- packages-user/data-base/src/hero/saveLoad.test.ts
|
||||
- packages-user/data-base/src/hero/state.test.ts
|
||||
- packages-user/data-base/src/map/dynamicTile.test.ts
|
||||
- packages-user/data-base/src/map/eventPath.test.ts
|
||||
- packages-user/data-base/src/map/eventView.test.ts
|
||||
- packages-user/data-base/src/map/gameMap.test.ts
|
||||
- packages-user/data-base/src/map/mapLayer.test.ts
|
||||
- packages-user/data-base/src/map/mapLifecycle.test.ts
|
||||
- packages-user/data-base/src/map/mapState.test.ts
|
||||
- packages-user/data-base/src/map/mover.test.ts
|
||||
- packages-user/data-base/src/map/saveLoad.test.ts
|
||||
- packages-user/data-base/src/map/staticTile.test.ts
|
||||
- packages-user/data-base/src/map/tile.test.ts
|
||||
- packages-user/data-system/src/combat/combat.test.ts
|
||||
- packages-user/data-system/src/combat/context.test.ts
|
||||
- packages-user/data-system/src/combat/context.perf.ts
|
||||
- packages-user/data-system/src/combat/damage.test.ts
|
||||
- packages-user/data-system/src/combat/damage.perf.ts
|
||||
- packages-user/data-system/src/combat/mapDamage.test.ts
|
||||
- packages-user/data-system/src/event/eventDispatch.test.ts
|
||||
- packages-user/data-system/src/path/graph.test.ts
|
||||
- packages-user/data-system/src/path/performance.test.ts
|
||||
- packages-user/data-system/src/path/system.test.ts
|
||||
- packages-user/data-state/src/coreEventLayer.test.ts
|
||||
- packages-user/data-state/src/enemy/aura.test.ts
|
||||
- packages-user/data-state/src/enemy/calculator.test.ts
|
||||
- packages-user/data-state/src/enemy/comparer.test.ts
|
||||
- packages-user/data-state/src/enemy/final.test.ts
|
||||
- packages-user/data-state/src/enemy/mapDamage.test.ts
|
||||
- packages-user/data-state/src/enemy/special.test.ts
|
||||
- packages-user/data-state/src/event/event.test.ts
|
||||
- packages-user/data-state/src/replay/commands.test.ts
|
||||
- packages-user/data-state/test/coreNode.test.ts
|
||||
- packages-user/data-state/test/dataClosure.test.ts
|
||||
- packages-user/data-state/test/enemyCombination.test.ts
|
||||
- packages-user/data-state/test/nodeReplay.test.ts
|
||||
- packages-user/data-state/test/nodeTracer.test.ts
|
||||
- packages-user/data-state/test/replayPlayback.test.ts
|
||||
- packages-user/data-state/test/saveablesRoundTrip.test.ts
|
||||
- packages-user/data-state/test/tileLegacy.test.ts
|
||||
- packages-user/data-state/test/mapScenario.perf.ts
|
||||
- packages-user/data-state/test/saveables.perf.ts
|
||||
- packages-user/data-state/test/saveablesReal.perf.ts
|
||||
- packages-user/data-state/test/replayVerifier.ts
|
||||
- packages-user/data-state/test/fixtures/closed-loop.ts
|
||||
- packages-user/data-state/test/fixtures/floors.json
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 70000
|
||||
raw_tokens: 70000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**文件数守恒**:迁移后 `pnpm test:ci` 采集到的测试文件总数仍为 **66**(数据端 65 `.test.ts` + `script/check-data-circular.test.ts`),`pnpm test:perf` 采集总数仍为 **6**;任何数量的增减都视为迁移不完整。"
|
||||
- "**物理落位**:71 个测试文件(65 `.test.ts` + 6 `.perf.ts`)+ 3 个随迁非测试文件(`replayVerifier.ts` + `fixtures/closed-loop.ts` + `fixtures/floors.json`)全部位于目标 `__test__/` 目录下;原路径不再有同名文件(迁移 = 移动,非复制)。"
|
||||
- "**导入重写分流正确**:`data-{common,base,system}/src/**` 与 `data-state/src/**` 的下沉文件按**规则 A**(每个相对 specifier 多一层)改写;`data-state/test/** -> data-state/__test__/**` 的下沉文件按**规则 B**(相对 specifier 原样不变)。动态 `import()` 与 `typeof import()` 的字符串同样按规则处理;`@user/*`、`@motajs/*`、`vitest` 裸包 specifier 一律不变。"
|
||||
- "**外部脚本路径同步**:`script/test-data-node.ts` 第 67 行与第 122 行对 `data-state/test/{replayVerifier.ts,fixtures/closed-loop.ts}` 的 `require` 路径改为 `data-state/__test__/...`;`pnpm test:data-node` 的入口无需其它改动。"
|
||||
- "**零配置改动**:不修改 `vite.config.ts`(其无 `test.include`,用默认 glob 命中 `__test__/`)、`vitest.perf.config.ts`(`**/*.perf.ts` 深度无关)、`tsconfig.json`(`packages-user/**/*.ts` 深度无关)、`eslint.config.js`、`package.json`。"
|
||||
- "**测试仍可红**:本计划的门禁是「文件数守恒 + 物理落位 + 发现仍发生 + eslint 通过」,**不要求测试全绿**;对齐由 08-02..08-09 承担。"
|
||||
- "**零生产改动**:`packages-user/data-*/src/**` 下除本计划声明的测试/夹具文件外零改动;不改任何 `logger.json`、不改接口、不改实现。"
|
||||
artifacts:
|
||||
- path: script/test-data-node.ts
|
||||
provides: "两处 require 路径改为 `__test__/` 下的新位置(第 67 行 replayVerifier、第 122 行 fixtures/closed-loop)。"
|
||||
- path: packages-user/data-state/__test__/replayVerifier.ts
|
||||
provides: "随迁的非测试 helper(被 `nodeReplay.test.ts` 与 `script/test-data-node.ts` 引用),不在 65 计数内。"
|
||||
- path: packages-user/data-state/__test__/fixtures/closed-loop.ts
|
||||
provides: "随迁的共享夹具(规则 B,specifier 不变),被 dataClosure/nodeTracer/nodeReplay 等引用。"
|
||||
key_links:
|
||||
- "`vite.config.ts` 无 `test.include` <-> Vitest 默认 include glob `**/*.{test,spec}.?(c|m)[jt]s?(x)` —— `__test__/` 不在默认 exclude 内,故迁入后仍被采集(本计划 Task 1 用 flag 子目录先证此假设)。"
|
||||
- "`vitest.perf.config.ts` 的 `include: ['**/*.perf.ts']` <-> `__test__/` 下 perf 文件仍被 test:perf 采集。"
|
||||
- "`script/test-data-node.ts:67,122` 硬编码旧 `test/` 路径 <-> `pnpm test:data-node` 断链——迁移必须同步改,否则脚本失败。"
|
||||
- "规则 A 与规则 B 分流 <-> `data-state/test/` 与 `data-state/__test__/` 同为 `data-state/` 直接子目录、深度相同——对 data-state 一律套用「+1 层」会改坏 Rule B 文件。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
把数据端四包(`packages-user/data-common`、`data-base`、`data-system`、`data-state`)的**全部**单测(65 `*.test.ts` + 6 `*.perf.ts`)连同 3 个随迁非测试文件,迁移到各源码目录下的 `__test__/`;`data-state/test/` 整体迁为 `data-state/__test__/`(`fixtures/` 与 `replayVerifier.ts` 随迁),同步改写相对导入与 `script/test-data-node.ts` 的两处硬编码路径。迁移后测试**可能仍为红**——本计划只负责「位置正确 + 发现守恒 + 导入可解析 + 零配置改动 + 零生产改动」。
|
||||
|
||||
Purpose: 承接已 SUPERSEDED 的 07-16,对应需求 TEST-02 的「测试文件统一归入 `__test__` 目录」这一半(另一半「按当前接口对齐」由 08-02..08-09 承担)。先做纯迁移、再做对齐(D-06),使「文件是否都在新位置并被采集」可独立验证,避免把位置问题与接口问题混在一起排查。
|
||||
|
||||
Output: 74 个移动到新位置的测试/夹具文件 + 1 个改路径的脚本;零新建生产文件、零新增依赖、零配置改动;08-01 不产出 SUMMARY 之外的规划改动(SUMMARY 由 08-11 统一产出)。
|
||||
|
||||
**迁移映射总表(old -> new)**
|
||||
|
||||
| 组 | 源目录 | 目标目录 | 规则 | 文件 |
|
||||
|----|--------|----------|------|------|
|
||||
| 1 | `data-common/src/common/` | `data-common/src/common/__test__/` | A | face, faceManager, indexer, mover, utils (5) |
|
||||
| 2 | `data-common/src/replay/` | `data-common/src/replay/__test__/` | A | array, func, sandbox, saveLoad, system (5) |
|
||||
| 3 | `data-common/src/store/` | `data-common/src/store/__test__/` | A | eventStore, tileStore (2) |
|
||||
| 4 | `data-base/src/enemy/` | `data-base/src/enemy/__test__/` | A | enemy, manager, saveLoad, special (4) |
|
||||
| 5 | `data-base/src/flag/` | `data-base/src/flag/__test__/` | A | saveLoad, system (2) |
|
||||
| 6 | `data-base/src/hero/` | `data-base/src/hero/__test__/` | A | attribute, equipStore, equipment, follower, items, location, modifier, mover, rendering, saveLoad, state + attribute.perf (12) |
|
||||
| 7 | `data-base/src/map/` | `data-base/src/map/__test__/` | A | dynamicTile, eventPath, eventView, gameMap, mapLayer, mapLifecycle, mapState, mover, saveLoad, staticTile, tile (11) |
|
||||
| 8 | `data-system/src/combat/` | `data-system/src/combat/__test__/` | A | combat, context, damage, mapDamage + context.perf, damage.perf (6) |
|
||||
| 9 | `data-system/src/event/` | `data-system/src/event/__test__/` | A | eventDispatch (1) |
|
||||
| 10 | `data-system/src/path/` | `data-system/src/path/__test__/` | A | graph, performance, system (3) |
|
||||
| 11 | `data-state/src/` | `data-state/src/__test__/` | A | coreEventLayer (1) |
|
||||
| 12 | `data-state/src/enemy/` | `data-state/src/enemy/__test__/` | A | aura, calculator, comparer, final, mapDamage, special (6) |
|
||||
| 13 | `data-state/src/event/` | `data-state/src/event/__test__/` | A | event (1) |
|
||||
| 14 | `data-state/src/replay/` | `data-state/src/replay/__test__/` | A | commands (1) |
|
||||
| 15 | `data-state/test/` | `data-state/__test__/` | B | coreNode, dataClosure, enemyCombination, nodeReplay, nodeTracer, replayPlayback, saveablesRoundTrip, tileLegacy (8) + mapScenario.perf, saveables.perf, saveablesReal.perf (3) + replayVerifier.ts + fixtures/closed-loop.ts + fixtures/floors.json |
|
||||
|
||||
**Source Coverage Audit(本阶段四源对照,全量)**
|
||||
|
||||
| 来源 | 项 | 归属计划 | 状态 |
|
||||
|------|----|----------|------|
|
||||
| GOAL | 迁移全部单测到 `__test__/` | 08-01 | COVERED |
|
||||
| GOAL | 按 shipped 接口重对齐、修复重构遗漏失效 | 08-02..08-09 | COVERED |
|
||||
| GOAL | 以 `logger.json` 补齐错误码与公共接口覆盖 | 08-10 | COVERED |
|
||||
| GOAL | `pnpm test:ci` + `pnpm test:perf` 全绿(保留唯一不可达码 147 的 skip) | 08-11 | COVERED |
|
||||
| REQ | TEST-02 | 08-01..08-11 全部 | COVERED |
|
||||
| RESEARCH | 迁移配置零改动 | 08-01 | COVERED |
|
||||
| RESEARCH | 逐子系统接口 delta(8.1..8.11) | 08-02..08-09 | COVERED |
|
||||
| RESEARCH | 21 个缺口错误码(9.1) | 08-10 | COVERED |
|
||||
| RESEARCH | 7 个陈旧登记码(9.2) | 08-05 / 08-10 | COVERED |
|
||||
| RESEARCH | 公共接口覆盖表(10.x) | 08-10 | COVERED |
|
||||
| CONTEXT | D-01..D-10 全部锁定决策 | 各计划 Task 0 / 约束 | COVERED |
|
||||
| CONTEXT | Deferred:`script/check-data-circular.test.ts`、渲染端/legacy、全仓 `check:type` | 不纳入 | 排除(非缺口) |
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划**尚未裁决**(Task 0 的 `<record>` 为空)。执行者**必须**在 Task 0 停下向用户汇报,取得「可以执行」后方可继续。**不得**按任何默认自动推进。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: 迁移口径裁决关卡(D-09)—— 汇报本计划并等待用户确认</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- .planning/phases/08-test-refactor-alignment/08-CONTEXT.md(D-01/D-02/D-06/D-08/D-09/D-10)
|
||||
- .planning/phases/08-test-refactor-alignment/08-PATTERNS.md(`0. Planner TL;DR`、`M1/M2/M3`、`Config / Barrel / External References`)
|
||||
- .planning/phases/08-test-refactor-alignment/08-RESEARCH.md(`迁移配置裁决`)
|
||||
- packages-user/data-state/test/(14 个 tracked 文件的全清单,确认随迁集)
|
||||
- script/test-data-node.ts(第 67、122 行的硬编码路径)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划要解决的问题(数据端 71 个测试文件仍在旧位置、无 `__test__/` 归属,且 `script/test-data-node.ts` 硬编码旧路径)与拟定方案(全量 `git mv` 到 `__test__/` + 规则 A/B 分流改导入 + 改脚本路径 + 文件数守恒验证),等待用户明确回复「可以执行」后写入 `<record>`:
|
||||
|
||||
- **M1**:迁移方式(`git mv` 逐文件 / 一次性脚本 / 其他);是否允许编辑 `script/test-data-node.ts`(该文件非生产但按 AGENTS.md 需确认)。
|
||||
- **M2**:确认「测试仍红是预期」——本计划门禁仅「文件数守恒 + 物理落位 + 发现仍发生」,不做接口对齐。
|
||||
- **M3**:确认规则 B(`data-state/test/**` specifier 原样)与规则 A(其余 +1 层)的分流无误。
|
||||
- **M4**:若某声明文件在 `git status --short` 中显示用户有未提交改动,执行者应停止并汇报(D-08),需用户确认处理方式。
|
||||
</decision>
|
||||
<record>
|
||||
**裁决日期:** 2026-10-04(用户「可以执行」)
|
||||
- **M1:** 用 `git mv` 逐文件迁移,**不写一次性脚本**;允许编辑 `script/test-data-node.ts`(仅改两处路径字符串)。
|
||||
- **M2:** 确认「测试仍红是预期」——因接口与约定改动所致;本计划只做迁移,不做接口对齐。
|
||||
- **M3:** 确认规则 A(`data-{common,base,system}/src/**` 与 `data-state/src/**` 相对 specifier +1 层)与规则 B(`data-state/test/**` → `data-state/__test__/**` specifier 原样)分流无误。
|
||||
- **M4:** 任一声明文件若在 `git status --short` 中显示用户有未提交改动,执行者停止并汇报(D-08)。
|
||||
</record>
|
||||
<context>
|
||||
本计划是 D-06 的「独立先行迁移计划」。用户明确「问题修复不会很复杂,顶多是某些内容重构时有细节没有注意到」;接口设计不再变更(D-05)。迁移不改测试内容与风格,只改位置与相对导入。`utils.test.ts` / `tileLegacy.test.ts` / `coreEventLayer.test.ts` 的**去留**不在本计划裁决,它们先随文件迁移,去留由 08-02 / 08-09 / 08-08 的 Task 0 裁决。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="tracer">
|
||||
<name>Task 1: 端到端验证迁移假设 —— 先迁 flag 子目录并证明默认 glob 命中</name>
|
||||
<files>packages-user/data-base/src/flag/__test__/saveLoad.test.ts, packages-user/data-base/src/flag/__test__/system.test.ts</files>
|
||||
<action>
|
||||
用 `git mv` 把 `packages-user/data-base/src/flag/{saveLoad,system}.test.ts` 移到同目录 `flag/__test__/` 下(保留历史;不得复制)。按**规则 A** 改写这两个文件内的每个相对 specifier:`'./x' -> '../x'`、`'../x' -> '../../x'`。裸包 specifier(`@user/*`、`@motajs/*`、`vitest`)不变。移动前先 `git status --short` 核对这两个文件无用户未提交改动;若有则停止并汇报(D-08)。移动后立即运行聚焦命令,证明 `__test__/` 下的文件仍被默认 glob 采集且相对导入可解析——这是对「迁移零配置改动」这一关键假设的端到端验证。仅动这两个文件,不碰其它子系统。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/flag/__test__/system.test.ts packages-user/data-base/src/flag/__test__/saveLoad.test.ts</automated>
|
||||
<fails_when>命令非零退出,或 vitest 汇总行出现 `failed` 且无 `Test Files` 命中(说明文件未被采集/导入不可解析)。注意:用例断言失败属预期(测试仍红),只要「文件被采集且执行到用例」即算通过本步的发现验证。</fails_when>
|
||||
</verify>
|
||||
<done>`flag/__test__/` 下两个文件存在、被 vitest 采集、相对导入解析到 `flag/` 下的源码;原 `flag/` 下不再有这两个 `.test.ts`。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 规则 A 批量迁移(组 1-14)</name>
|
||||
<files>组 1-14 的全部源文件与其 `__test__/` 目标(见 frontmatter `files_modified` / `files_deleted`)</files>
|
||||
<action>
|
||||
对组 1-14(`.planning/phases/08-test-refactor-alignment/08-PATTERNS.md` 的 File Classification 表 #1-#14)执行规则 A 迁移:`data-{common,base,system}/src/**` 与 `data-state/src/**` 下的测试下沉到各自同目录 `__test__/`。逐文件 `git mv`,然后按规则 A 改写:普通 `import`、动态 `import()`、`typeof import()` 三种字符串形式一律 +1 层;所有 `./` 与 `../` 相对 specifier 均处理,裸包 specifier 不动。仅改 specifier 与必要处,不动任何 `it` 内容、不动既有注释(除因路径变化必须同步的导入语句本身)。每个子系统(`data-common` / `data-base/{enemy,flag,hero,map}` / `data-system/{combat,event,path}` / `data-state/{,enemy,event,replay}`)迁完即先跑其聚焦命令确认文件仍被采集。移动前逐文件核对无用户未提交改动。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm test:ci</automated>
|
||||
<fails_when>vitest 汇总的 `Test Files` 总数不等于 66(说明有文件丢失或未被采集)。用例红/绿不作为本步判据。</fails_when>
|
||||
</verify>
|
||||
<done>组 1-14 的文件全部位于目标 `__test__/` 且被 test:ci 采集;`test:ci` 采集总数 = 66。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: 规则 B 迁移 data-state/test -> __test__ + 脚本路径 + 收口验证</name>
|
||||
<files>data-state/test 全部 14 个 tracked 文件的 `__test__/` 目标(含 `replayVerifier.ts`、`fixtures/closed-loop.ts`、`fixtures/floors.json`)、script/test-data-node.ts</files>
|
||||
<action>
|
||||
用 `git mv` 把 `packages-user/data-state/test/` 下的全部 tracked 文件移到 `packages-user/data-state/__test__/`,`fixtures/` 子目录随迁。按**规则 B**:这些文件的相对 specifier(含 `../src/core`、`../../data-common/src/...`、`./fixtures/...`、`./replayVerifier`)**原样保留**,不得套用 +1 层。然后把 `script/test-data-node.ts` 第 67 行与第 122 行中的 `data-state/test/` 改为 `data-state/__test__/`(仅改路径字符串)。最后做收口验证:跑 `pnpm test:ci` 确认采集总数 66、跑 `pnpm test:perf` 确认采集总数 6、`pnpm exec eslint <本次改动文件>` 通过、并用 `git ls-files` 确认旧路径全部消失。移动前逐文件核对无用户未提交改动。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm test:perf; pnpm test:ci; pnpm exec eslint script/test-data-node.ts packages-user/data-state/__test__/</automated>
|
||||
<fails_when>test:perf 采集 `Test Files` 总数不等于 6,或 test:ci 采集总数不等于 66,或 eslint 有报错(证明迁移改坏了 specifier 或留了未使用变量)。</fails_when>
|
||||
</verify>
|
||||
<done>`data-state/test/` 目录在 git 中不再存在;`data-state/__test__/` 含 8 test + 3 perf + 3 随迁文件;`script/test-data-node.ts:67,122` 指向新路径;test:perf = 6 文件、test:ci = 66 文件;eslint 通过。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 规划/执行者 -> git 工作树 | 迁移会触碰文件系统并暂存路径;用户正在并发改动数据端(D-08)。 |
|
||||
| 迁移 -> 测试门禁语义 | 「文件被采集」若以放宽方式伪造,会让后续对齐计划建立在错误基线上。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-01 | Tampering | `git add` 范围 | high | mitigate | 一律 `git add <显式路径>`;禁止 `git add -A`/`-a`/`git stash`/`git clean`/`git reset --hard`;提交前 `git status --short` 核对暂存区只含本计划声明路径。 |
|
||||
| T-08-02 | Repudiation | 文件丢失/未采集被忽略 | medium | mitigate | 以「test:ci 采集数 = 66 且 test:perf = 6」为硬门禁;数量不符即失败。 |
|
||||
| T-08-03 | Tampering | 规则 B 误套 +1 层 | medium | mitigate | Task 3 明确 `data-state/test/**` specifier 原样;Task 1 先以 Rule A 证明 glob 假设。 |
|
||||
| T-08-04 | Tampering | 提交用户并发改动 | high | mitigate | 逐文件移动前 `git status --short` 核对;若声明文件有用户改动则 STOP 并汇报(D-08)。 |
|
||||
| T-08-05 | Tampering | 依赖/配置漂移 | low | accept | 本计划不改 `package.json`/锁文件/配置;无安装动作,故无供应链风险。 |
|
||||
| T-08-SC | Tampering | 包安装 | high | mitigate | 本计划**不安装任何包**;无 npm/pip/cargo 安装动作,供应链面为零。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm test:ci` 采集 `Test Files` 总数 = 66(迁移前后守恒;含 1 个 `script/check-data-circular.test.ts`)。
|
||||
- `pnpm test:perf` 采集总数 = 6。
|
||||
- `git ls-files` 下所有旧 `*.test.ts` / `*.perf.ts` 路径(组 1-15 源路径)已不存在;新 `__test__/` 路径存在。
|
||||
- `script/test-data-node.ts:67,122` 指向 `__test__/`。
|
||||
- `pnpm exec eslint` 对本次改动文件 0 报错。
|
||||
- 未修改任何配置文件、未改任何生产源码(`git status --short` 与受限 diff 佐证)。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获得用户「可以执行」并写入 `<record>` 后,Task 1-3 才执行。
|
||||
- [ ] 65 `.test.ts` + 6 `.perf.ts` + 3 随迁文件全部物理落位到目标 `__test__/`。
|
||||
- [ ] 导入重写分流正确(规则 A / 规则 B)。
|
||||
- [ ] `script/test-data-node.ts` 两处路径同步。
|
||||
- [ ] 零配置改动、零生产改动、零新增依赖。
|
||||
- [ ] `pnpm test:ci` 与 `pnpm test:perf` 发现数守恒。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-01-SUMMARY.md` when done(记录:文件数守恒证据、规则 A/B 分流清单、脚本改动、eslint/门禁结果、零生产改动证据)。
|
||||
</output>
|
||||
47
.planning/phases/08-test-refactor-alignment/08-01-SUMMARY.md
Normal file
47
.planning/phases/08-test-refactor-alignment/08-01-SUMMARY.md
Normal file
@ -0,0 +1,47 @@
|
||||
# 08-01 SUMMARY — 测试目录迁移
|
||||
|
||||
**执行日期:** 2026-10-04
|
||||
**计划:** `08-01-PLAN.md`(测试目录迁移,独立先行)
|
||||
**状态:** 完成(门禁通过;提交待用户指示,见文末)
|
||||
|
||||
## Task 0 裁决(用户「可以执行」)
|
||||
|
||||
- **M1**:`git mv` 逐文件迁移,不写一次性脚本;允许编辑 `script/test-data-node.ts`。
|
||||
- **M2**:测试仍红属预期(接口/约定改动所致),本计划不做接口对齐。
|
||||
- **M3**:规则 A(+1 层)/ 规则 B(原样)分流确认无误。
|
||||
- **M4**:任一声明文件若有用户未提交改动则停止汇报;实际检查 `git status` 时声明路径无用户改动,正常执行。
|
||||
|
||||
## 迁移结果
|
||||
|
||||
- **移动总量**:71 个测试文件(65 `.test.ts` + 6 `.perf.ts`)+ 3 个随迁非测试文件(`replayVerifier.ts`、`fixtures/closed-loop.ts`、`fixtures/floors.json`)= **74**。
|
||||
- **规则 A(+1 层,`git mv` 逐文件)**:58 文件,覆盖 `data-common/src/{common,replay,store}`、`data-base/src/{enemy,hero,map}`、`data-system/src/{combat,event,path}`、`data-state/src/{,enemy,event,replay}`;另有 tracer 阶段先迁的 `data-base/src/flag` 2 文件,共 **60** 文件。
|
||||
- **规则 B(specifier 原样)**:`packages-user/data-state/test/` 整体 `git mv` 为 `packages-user/data-state/__test__/`(14 tracked 文件,含 `fixtures/`)。
|
||||
- **脚本同步**:`script/test-data-node.ts` 第 67、122 行 `data-state/test/` → `data-state/__test__/`(仅路径字符串)。
|
||||
- **导入改写**:对规则 A 文件按「每个相对 specifier 加一层」机械改写(`'./x'→'../x'`、`'../x'→'../../x'`;动态 `import()` / `typeof import()` / `new URL()` / `require()` 字符串一并处理);裸包 specifier(`@user/*`、`@motajs/*`、`vitest`)不变。改写文件 57 个(1 个文件无相对 specifier)。
|
||||
|
||||
## 门禁证据
|
||||
|
||||
| 门禁 | 结果 |
|
||||
|------|------|
|
||||
| `pnpm test:ci` 采集文件数 | **66**(守恒;含 `script/check-data-circular.test.ts`) |
|
||||
| `pnpm test:perf` 采集文件数 | **6**(守恒) |
|
||||
| 规则 A 新位置残留 `./` specifier | **0** |
|
||||
| 规则 B specifier 原样 | 保持(`../src/core`、`./fixtures/...`、`./replayVerifier`、`../../data-common/...`) |
|
||||
| `pnpm exec eslint <77 个改动 ts 文件>` | **0 报错** |
|
||||
| 配置改动 | **无**(`vite.config.ts` / `vitest.perf.config.ts` / `tsconfig.json` / `eslint.config.js` / `package.json` 均未改) |
|
||||
| 生产源码改动 | **无**(`packages-user/*/src/**` 下仅测试/夹具移动;无接口/实现改动) |
|
||||
|
||||
测试用例仍大量失败(如 `createCoreState is not a function`),**属预期**——接口对齐由 08-02..08-09 承担。
|
||||
|
||||
## Tracer 见证
|
||||
|
||||
`flag/__test__/{system,saveLoad}.test.ts` 迁移后聚焦运行:文件被采集、导入解析成功(12 passed / 5 failed 断言漂移),证明「默认 glob 命中 `__test__/`、零配置改动」假设成立。
|
||||
|
||||
## 并发保护(D-08)
|
||||
|
||||
- 执行前检查声明路径无用户未提交改动。
|
||||
- 检测到用户并发改动(未触碰、未暂存、未提交):`packages-user/client-base/src/types.ts`、`packages-user/client-modules/src/client.ts`、`packages-user/client-modules/src/types.ts`,以及未跟踪目录 `packages-user/client-modules/src/ui/`。
|
||||
|
||||
## 未决 / 待用户指示
|
||||
|
||||
- 本计划的 git 提交**尚未进行**(含并发用户改动,提交须显式路径且待用户指示)。
|
||||
172
.planning/phases/08-test-refactor-alignment/08-02-PLAN.md
Normal file
172
.planning/phases/08-test-refactor-alignment/08-02-PLAN.md
Normal file
@ -0,0 +1,172 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-common/src/common/__test__/face.test.ts
|
||||
- packages-user/data-common/src/common/__test__/faceManager.test.ts
|
||||
- packages-user/data-common/src/common/__test__/indexer.test.ts
|
||||
- packages-user/data-common/src/common/__test__/mover.test.ts
|
||||
- packages-user/data-common/src/common/__test__/utils.test.ts
|
||||
- packages-user/data-common/src/store/__test__/eventStore.test.ts
|
||||
- packages-user/data-common/src/store/__test__/tileStore.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/array.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/func.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/sandbox.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/saveLoad.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/system.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 55000
|
||||
raw_tokens: 55000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-common/src/**` 下除 12 个声明测试文件外零改动;不改 `common/{face,faceManager,indexer,mover}.ts`、`replay/*.ts`、`store/*.ts`、`types.ts`、`index.ts`。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**Hook 契约对齐**:所有 `*.addHook({...}).load()` 链改为 `*.addHook({...})`(`Hookable.addHook` 即注册并返回仅含 `unload()` 的 `IHookController`,`packages/common/src/hook.ts:23-32`、`types.ts:52-60`);不得保留 `.load()`。"
|
||||
- "**朝向工具对齐**:测试中引用已删除的 `DirectionMapper`(`@motajs/common` 已无此导出)与已删除的 `common/utils.ts` 的四个纯函数时,按 shipped `IFaceHandler`(`degrade`/`movement`/`next`/`dirOf`)或其具体实现(`Dir4FaceHandler`/`Dir8FaceHandler`)表达原断言意图;不得用 `as never`/`Object.create` 伪造已删成员(`07-16` 禁令延续)。"
|
||||
- "**录像失败码契约对齐**:`sandbox.test.ts` 中对码 158/175 的断言改为当前实际发出的码(执行/收口失败统一 `logger.error(72, method)`、被动步后主动步 `logger.warn(194, ...)`),或经 Task 0 裁定保留旧契约——二选一,不得两存。"
|
||||
- "**无断言弱化、无新增 skip**:不删除既有 `it`,不新增 `it.skip`/`describe.skip`/`it.todo`;仓库级 skipped 计数仍恰为 1(唯一为 `data-base/src/hero/__test__/equipment.test.ts` 的码 147,D-04)。"
|
||||
- "**测试注释规范**:每个 `it` 前保留/同步一行中文注释(`dev.md:86`);不修改任何既有 jsDoc;仅允许三类注释落笔(文件头覆盖说明追加、覆盖描述变化的 `it` 前注释、点名已删接口改为点名 shipped 接口)。"
|
||||
- "**聚焦门禁**:每个文件 `pnpm exec vitest run <file>` 0 失败后,`pnpm test:ci` 中 `data-common` 的测试文件 0 失败(除非 Task 0 裁定某文件退役)。"
|
||||
artifacts:
|
||||
- path: packages-user/data-common/src/common/__test__/utils.test.ts
|
||||
provides: "按 Task 0 裁决处置——改写为对 shipped `Dir4FaceHandler`/`Dir8FaceHandler`(或 `IFaceHandler`)的等价覆盖,或经用户批准退役(退役须由 08-11 SUMMARY 登记等价覆盖位置)。"
|
||||
- path: packages-user/data-common/src/replay/__test__/sandbox.test.ts
|
||||
provides: "删除全部 `.load()` 链;158/175 断言按 Task 0 裁决改为 72/194 或保留。"
|
||||
- path: packages-user/data-common/src/replay/__test__/system.test.ts
|
||||
provides: "删除 `.load()` 链;确认 `ReplaySystem.array`(shipped 成员)复用无误。"
|
||||
key_links:
|
||||
- "`Hookable.addHook` 即时 `hook.awake?.(...)` 并返回 `IHookController`(`unload()`)<-> 测试旧写法 `addHook(...).load()`——删 `.load()` 即可,不是改名。"
|
||||
- "`common/index.ts` 仅导出 `./face`/`./faceManager`/`./indexer`/`./mover`/`./types` <-> `common/utils.ts` 已整体删除——`utils.test.ts` 的被测对象消失。"
|
||||
- "`IFaceHandler.degrade/movement/next/dirOf`(`faceManager.ts`)<-> 旧 `getFaceMovement`/`degradeFace`/`nextFaceDirection`/`fromDirectionString`——朝向能力的新 shipped 面。"
|
||||
- "`sandbox.ts:136` `logger.error(72, method)` 与 `:187` `logger.warn(194, ...)` <-> 06-COVERAGE-MAP 登记的 158/175——契约码迁移。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
按数据端「系统性收尾」后的当前接口,对齐 `packages-user/data-common` 的 12 个测试文件(`common` 5 + `store` 2 + `replay` 5),使该包的聚焦运行 0 失败。涵盖失败族 A(引用已删/改名导出:`utils.ts` 四个纯函数、`DirectionMapper`)、D(`addHook(...).load()` 链)、G(`sandbox` 映射码 158/175 漂移)。
|
||||
|
||||
Purpose: `data-common` 是 Layer 0,其它三包都依赖它;先对齐它可避免上层失败被底层连带掩盖。本计划只改测试面(D-05/D-10),不新增接口。
|
||||
|
||||
Output: 12 个既有测试文件的对齐改动;可能含 1 个文件的退役(`utils.test.ts`,按 Task 0 裁决);零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划**尚未裁决**(Task 0 的 `<record>` 为空)。执行者必须在 Task 0 停下汇报并等待「可以执行」;不得按默认自动推进。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: data-common 对齐裁决关卡 —— utils.test.ts 去留、158/175 契约、DirectionMapper 残留</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-common/src/common/index.ts(确认仅导出 face/faceManager/indexer/mover/types,无 utils)
|
||||
- packages-user/data-common/src/common/faceManager.ts(`IFaceHandler` 契约与 `Dir4FaceHandler`/`Dir8FaceHandler`)
|
||||
- packages-user/data-common/src/common/utils.test.ts(现被测的 4 个纯函数)
|
||||
- packages-user/data-common/src/replay/sandbox.ts(`:84,89,93,119,136,178,187` 的实际发码点)
|
||||
- packages-user/data-common/src/replay/sandbox.test.ts(`:80,92,118,171,193,257,279,299,331,367,403`)
|
||||
- packages-user/data-common/src/common/mover.test.ts(`DirectionMapper` 引用点)
|
||||
- packages/common/src/hook.ts / packages/common/src/types.ts(`IHookController`)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划要解决的问题(`data-common` 测试引用已删的 `utils.ts` 与 `DirectionMapper`、保留 `addHook().load()` 链、断言已迁移的 158/175 码)与拟定方案,等待用户明确回复「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1【高】`utils.test.ts` 去留**:被测的 4 个纯函数已从源码整体删除,覆盖职责已由 `faceManager.test.ts` 承接。选择:(A) 改写为对 `Dir4FaceHandler`/`Dir8FaceHandler` 的等价测试(可能重复);(B) 退役该文件(须在 SUMMARY 登记等价覆盖位置)。
|
||||
- **Q2【中】`sandbox` 失败码契约**:断言 158/175 改为当前实际发出的 72/194,还是视为应保留的契约(需生产修复)?D-05/D-10 下倾向改测试断言,须用户确认。
|
||||
- **Q3**:`mover.test.ts` 等夹具中的 `DirectionMapper` 残留(已删导出)如何处置——删除该注入位并改用 shipped `IFaceManager`/`IFaceHandler`,还是按既有 `as never` 假值保留(research 记录部分夹具已如此)。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH §8.1/§8.2/§8.3 给出逐符号 delta 与 emit anchor。D-05 明令「只对齐、不新增接口」;D-10 默认零生产改动。本计划不改 `logger.json`。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: common + store 对齐</name>
|
||||
<files>packages-user/data-common/src/common/__test__/{face,faceManager,indexer,mover,utils}.test.ts, packages-user/data-common/src/store/__test__/{eventStore,tileStore}.test.ts</files>
|
||||
<action>
|
||||
对齐 7 个文件。`utils.test.ts` 按 Q1 裁决处置(改写或退役)。移除对已删 `DirectionMapper` 的引用(按 Q3 裁决);涉及朝向位移/降级/旋转的断言改用 shipped `IFaceHandler` 的 `degrade`/`movement`/`next`/`dirOf` 或 `Dir4FaceHandler`/`Dir8FaceHandler` 表达原意图,保持原断言覆盖内容。`eventStore`/`tileStore` 若仅因连带失败则零改动,以聚焦运行结果为准。禁止用 `as never`/`Object.create` 伪造已删成员;不弱化断言;每个 `it` 前保留一行中文注释;不改既有 jsDoc。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-common/src/common/__test__ packages-user/data-common/src/store/__test__</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`(除 Task 0 明确授权的退役文件外),或运行期报 `not a function` / `Cannot read properties of undefined`。</fails_when>
|
||||
</verify>
|
||||
<done>`common`(含按裁决定的 utils)与 `store` 的测试文件聚焦运行 0 失败;无生产源码改动。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: replay 对齐(array/func/sandbox/saveLoad/system)</name>
|
||||
<files>packages-user/data-common/src/replay/__test__/{array,func,sandbox,saveLoad,system}.test.ts</files>
|
||||
<action>
|
||||
对齐 5 个文件。逐处把 `x.addHook({...}).load()` 改为 `x.addHook({...})`(如需卸载则用返回的 controller)。`sandbox.test.ts` 的 158/175 断言按 Q2 裁决改为 72/194 或保留;同步更新受影响的 `it` 前中文注释。确认 `route`/`ReplaySystem.array` 等 shipped 成员名复用正确。仅改测试断言的调用形状与期望值,不删除用例、不弱化断言。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-common/src/replay/__test__</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`,或 `addHook(...).load is not a function`、`reading 'add'` 等运行期错误。</fails_when>
|
||||
</verify>
|
||||
<done>`replay` 5 文件聚焦运行 0 失败;`.load()` 链清零;158/175 按裁决单一处置;无生产改动。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 源码接口 | 对齐方向为「测试适配源码」;反向改源码即越界。 |
|
||||
| 执行者 -> git | 提交范围必须限于声明文件。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-02-01 | Tampering | 用 `as never`/`Object.create` 伪绿 | high | mitigate | 明令禁止;`<fails_when>` 点名运行期错误形态;每个 `it` 保留语义断言。 |
|
||||
| T-08-02-02 | Repudiation | 删用例/放宽断言求绿 | high | mitigate | 不删 `it`、不新增 skip;期望值改写仅由 Task 0 授权;SUMMARY 登记。 |
|
||||
| T-08-02-03 | Tampering | 生产源码漂移 | high | mitigate | 声明路径全为 `__test__/` 测试文件;聚焦 diff 与 `git status --short` 佐证。 |
|
||||
| T-08-02-04 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;声明文件若有用户改动则 STOP(D-08)。 |
|
||||
| T-08-02-SC | Tampering | 包安装 | high | mitigate | 本计划不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-common/src/common/__test__ packages-user/data-common/src/store/__test__ packages-user/data-common/src/replay/__test__` 0 失败。
|
||||
- `pnpm test:ci` 中 `data-common` 归属文件 0 失败。
|
||||
- `git status --short` 仅显示声明测试文件被改;`packages-user/data-common/src/**` 非测试文件零改动。
|
||||
- 仓库 skipped 计数仍为 1。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`。
|
||||
- [ ] 12 个声明文件(或依裁决退役 `utils.test.ts`)对齐完成、聚焦运行 0 失败。
|
||||
- [ ] 零生产改动、零新增 skip、零断言弱化。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-02-SUMMARY.md` when done(记录:Q1/Q2/Q3 裁决、逐文件旧写法→新形状、期望值改写台账、无生产改动证据)。
|
||||
</output>
|
||||
159
.planning/phases/08-test-refactor-alignment/08-03-PLAN.md
Normal file
159
.planning/phases/08-test-refactor-alignment/08-03-PLAN.md
Normal file
@ -0,0 +1,159 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-base/src/enemy/__test__/enemy.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/manager.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/special.test.ts
|
||||
- packages-user/data-base/src/flag/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/flag/__test__/system.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 45000
|
||||
raw_tokens: 45000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-base/src/{enemy,flag}/**` 下除 6 个声明测试文件外零改动。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**EnemyManager 构造对齐**:测试按 shipped `constructor(private readonly tileStore: ITileStore) {}`(`enemy/manager.ts:35`)构造;不再向构造器传 legacy bridge。测试内若仍引用 `IEnemyLegacyBridge`,以 shipped `enemy/types.ts` 实际导出面为准(若已无该类型则移除引用)。"
|
||||
- "**flag 兼容面**:`FlagSystem` 的容器面(`occupied`/`setField`/`getField`/`getOrInsert`/`getOrInsertComputed`/`deleteField`/`setFieldValue`/`addFieldValue`/`getFieldValue`/`getFieldValueDefaults`)与码 111 均存在;flag 测试若仅因连带失败则最小对齐。"
|
||||
- "**错误码存在性**:53/96/117/118/119/120 与 111 在当前源码均有 emit 点;断言值以实际运行为准,不弱化原断言意图。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`,不新增 skip;skipped 总数仍为 1。"
|
||||
- "**聚焦门禁**:`pnpm exec vitest run` 对 enemy 4 文件与 flag 2 文件 0 失败。"
|
||||
artifacts:
|
||||
- path: packages-user/data-base/src/enemy/__test__/manager.test.ts
|
||||
provides: "EnemyManager 构造实参对齐到单参 `tileStore`;若 `IEnemyLegacyBridge` 已从 `enemy/types.ts` 消失则移除相关假桥接。"
|
||||
- path: packages-user/data-base/src/flag/__test__/system.test.ts
|
||||
provides: "FlagSystem 容器面按 shipped 形状复核(预计最小改动)。"
|
||||
key_links:
|
||||
- "`core.ts:150` `new EnemyManager<IEnemyAttr>(this.tileStore)` <-> `enemy/manager.ts:35` 单参构造——测试必须提供 `ITileStore`,不再有 legacy bridge 形参。"
|
||||
- "`EnemyLegacyBridge`(`data-state/src/enemy/legacy.ts:4`)与 `data-state/src/enemy/index.ts:5` 的 `export * from './legacy'` <-> `data-base/src/enemy/types.ts` 是否仍导出 `IEnemyLegacyBridge`——决定测试是否可继续引用该类型。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-base` 的 `enemy`(4 文件)与 `flag`(2 文件)测试到 shipped 接口,使两子系统聚焦运行 0 失败。这两个子系统在 RESEARCH 中判定「失败主要为连带(fixture 桩)而非独立接口改名」(A3),故改动面预计以 `EnemyManager` 构造实参与少量桩为主。
|
||||
|
||||
Purpose: 属 Layer 1,`data-system`/`data-state` 依赖它;先对齐可减少上层连带失败。
|
||||
|
||||
Output: 6 个既有测试文件的对齐改动;零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: enemy/flag 对齐裁决关卡 —— EnemyManager 构造实参与 legacy bridge 类型</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-base/src/enemy/manager.ts(`:35` 构造器;`:51,113,168,185` 发码点)
|
||||
- packages-user/data-base/src/enemy/types.ts(是否仍导出 `IEnemyLegacyBridge`)
|
||||
- packages-user/data-base/src/enemy/__test__/manager.test.ts(`:6,38,42,58`)
|
||||
- packages-user/data-base/src/enemy/__test__/enemy.test.ts、saveLoad.test.ts、special.test.ts
|
||||
- packages-user/data-base/src/flag/system.ts(容器面)与 flag/field.ts(码 111)
|
||||
- packages-user/data-base/src/flag/__test__/{system,saveLoad}.test.ts
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划问题(EnemyManager 构造形状变化、legacy bridge 类型可能已删;flag 连带失败)与方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1**:`EnemyManager` 测试构造改为 `new EnemyManager(tileStore)` 时,用真实 `TileStore` 还是内联 stub?(预计沿用 Phase 6 既有夹具风格)
|
||||
- **Q2**:`IEnemyLegacyBridge` 若已从 `data-base/src/enemy/types.ts` 删除,测试中作为协作对象的假桥接应删除还是改为新形状;若类型仍在,是否需要改。
|
||||
- **Q3**:flag 子系统是否有超出「连带」的独立失效(以执行当日聚焦运行结果为准);若有,是否仍在本计划 test-only 范围内。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH A3 明确 enemy/flag 的失败判定为「连带」,置信度 MEDIUM,需执行期以编译/运行结果为准。D-05 禁止新增接口;D-10 默认零生产改动。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: enemy 测试对齐</name>
|
||||
<files>packages-user/data-base/src/enemy/__test__/{enemy,manager,saveLoad,special}.test.ts</files>
|
||||
<action>
|
||||
对齐 4 个文件。`manager.test.ts` 按 shipped 单参构造 `new EnemyManager(tileStore)` 装配(按 Q1 决定真实 TileStore 或 stub);按 Q2 处置 `IEnemyLegacyBridge` 引用/假桥接。复核码 53/96/117/118/119/120 断言值与 emit 点一致。若仅连带失败则最小改动。不弱化断言、不删用例、不改既有 jsDoc、每个 `it` 保留一行中文注释。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/enemy/__test__</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`,或 `EnemyManager is not a constructor` / `reading '...'` 等运行期错误。</fails_when>
|
||||
</verify>
|
||||
<done>enemy 4 文件聚焦运行 0 失败;无生产改动。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: flag 测试对齐 + 提交前门禁</name>
|
||||
<files>packages-user/data-base/src/flag/__test__/{saveLoad,system}.test.ts</files>
|
||||
<action>
|
||||
对齐 2 个文件(预计最小改动)。确认 `FlagSystem` 容器面与码 111 断言匹配。随后对本次改动文件执行 eslint。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/flag/__test__; pnpm exec eslint packages-user/data-base/src/enemy/__test__ packages-user/data-base/src/flag/__test__</automated>
|
||||
<fails_when>flag 聚焦运行有非零 `failed`,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>flag 2 文件聚焦运行 0 失败;enemy+flag 全部声明文件 eslint 通过。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 接口 | 只允许测试适配源码。 |
|
||||
| 执行者 -> git | 提交范围限于声明文件。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-03-01 | Tampering | 伪绿(伪造已删类型/成员) | high | mitigate | 禁止 `as never`/`Object.create`;运行期错误由 `<fails_when>` 捕获。 |
|
||||
| T-08-03-02 | Repudiation | 删用例/放宽断言 | high | mitigate | 不删 `it`、不新增 skip;期望值改写须 Task 0 授权并在 SUMMARY 登记。 |
|
||||
| T-08-03-03 | Tampering | 生产源码漂移 | high | mitigate | 声明路径全为 `__test__/`;`git status --short` 佐证。 |
|
||||
| T-08-03-04 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;声明文件有用户改动则 STOP(D-08)。 |
|
||||
| T-08-03-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-base/src/enemy/__test__ packages-user/data-base/src/flag/__test__` 0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数仍为 1。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`。
|
||||
- [ ] enemy 4 + flag 2 文件对齐完成、聚焦 0 失败。
|
||||
- [ ] 零生产改动、零新增 skip、零断言弱化。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-03-SUMMARY.md` when done。
|
||||
</output>
|
||||
171
.planning/phases/08-test-refactor-alignment/08-04-PLAN.md
Normal file
171
.planning/phases/08-test-refactor-alignment/08-04-PLAN.md
Normal file
@ -0,0 +1,171 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-base/src/hero/__test__/attribute.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/attribute.perf.ts
|
||||
- packages-user/data-base/src/hero/__test__/equipStore.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/equipment.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/follower.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/items.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/location.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/modifier.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/mover.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/rendering.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/state.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 65000
|
||||
raw_tokens: 65000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-base/src/hero/**` 下除 12 个声明测试文件外零改动;不改 `location.ts`/`types.ts`/`items.ts`/`equipment.ts`/`follower.ts`/`mover.ts` 等实现。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**录像桩形状对齐(C 族)**:hero 测试中的录像桩生产写入面为 `replay.array.add(code, params)`(`equipment.ts:196,214`、`items.ts:101`、`mover.ts:181-190,223`);桩对象必须暴露 `array: { add }`,同时保留 `disable`/`revert`。移除旧 `route` 成员及其接口名(按 Task 0 裁决处理接口名与注释)。"
|
||||
- "**Hook 契约对齐(D 族)**:`controller.addHook({...}).load()`、`rendering.addHook(hook).load()`、`controller.load()`、`hero.addHook({...}).load()`、`location.addHook({...}).load()` 一律改为不带 `.load()`。"
|
||||
- "**HeroItems 对齐(F 族)**:`getItem` 已删;涉及「取/加道具」的断言改用 shipped `addItem`/`getItemState`/`itemCount` 表达原意图,保持覆盖率与断言强度。"
|
||||
- "**setFloor 对齐(F/G 族)**:`HeroLocation.setFloor` 收 `IGameMap`(`location.ts:55-59` 读 `map.floorId`)。所有 `setFloor('<string>')` 改为传真实 `IGameMap`(经 `maps.createMap`/`fromRaw` 构造),使 `floorId` 断言回到原期望值。`setFloor(undefined)` 分支的处置由 Task 0 裁决(Open Q7)。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`,不新增 skip;`equipment.test.ts` 中码 147 的既有 `it.skip` 保持原样(D-04,本计划唯一允许的 skip)。"
|
||||
- "**聚焦门禁**:`pnpm exec vitest run packages-user/data-base/src/hero/__test__` 0 失败(含 async mover 用例不再 30s 悬挂)。"
|
||||
artifacts:
|
||||
- path: packages-user/data-base/src/hero/__test__/equipment.test.ts
|
||||
provides: "录像桩 `route` -> `array`;解除码 147 skip 之外的失败;`:353` 的 147 skip 逐字保留。"
|
||||
- path: packages-user/data-base/src/hero/__test__/saveLoad.test.ts
|
||||
provides: "录像桩 `array` + 7 处 `setFloor(<IGameMap>)`;`floorId` 断言回到 `'F2'`/`'F1'`。"
|
||||
- path: packages-user/data-base/src/hero/__test__/location.test.ts
|
||||
provides: "`setFloor(<IGameMap>)` 形态;`setFloor(undefined)` 分支按 Task 0 裁决处置。"
|
||||
key_links:
|
||||
- "`equipment.ts:170-195` 的 `replay.disable()`/`revert()`/`array.add(...)` <-> 录像桩 `{ array, disable, revert }` 三成员形状——整体对齐,不得只补 `array` 而留 `route`。"
|
||||
- "`mover.ts:203` 把 `this.tile.map` 交给通行谓词 <-> 夹具 `setFloor` 传字符串会使 `location.map` 为字符串、谓词读 `map.eventLayer` 得 `undefined` 而拒绝移动——hero 与 data-state 集成测试共同根因。"
|
||||
- "`hero/types.ts:621 addItem` / `:627 getItemState` <-> 已删的 `HeroItems.getItem`。"
|
||||
- "`IHeroLocation.setFloor(map: IGameMap | null)`(`hero/types.ts:331`)与实现 `setFloor(map: IGameMap)`(`location.ts:55`)签名不一致 <-> `setFloor(null/undefined)` 在实现下不可表达(Open Q7)。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-base` 的 `hero` 子系统 11 个 `.test.ts` + 1 个 `.perf.ts` 到 shipped 接口/形状,使该子系统聚焦运行 0 失败。涵盖失败族 C(录像桩 `route`->`array`)、D(`addHook(...).load()`)、F(`HeroItems.getItem` 删除、`setFloor(IGameMap)`)、G(断言随语义漂移)。
|
||||
|
||||
Purpose: hero 是失败最广的子系统之一(11 文件),且其录像桩/楼层形状的修复直接解除多条 30s 悬挂与 `floorId` 断言失败。
|
||||
|
||||
Output: 12 个既有文件的对齐改动;零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: hero 对齐裁决关卡 —— setFloor(undefined) 分支、录像桩接口名、HeroItems.getItem 替代</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-base/src/hero/location.ts(`:24` floorId/map、`:55-59` setFloor、`:74-79` loadState)
|
||||
- packages-user/data-base/src/hero/types.ts(`:331` setFloor 签名、`:621` addItem、`:627` getItemState)
|
||||
- packages-user/data-base/src/hero/__test__/location.test.ts(`:107,110` `setFloor('F2')`/`setFloor(undefined)`)
|
||||
- packages-user/data-base/src/hero/__test__/{equipment,items,follower,mover,saveLoad}.test.ts(录像桩与 setFloor 调用点)
|
||||
- packages-user/data-base/src/hero/equipment.ts(`:196,214`)、items.ts(`:101,144`)、mover.ts(`:181-190,223`)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1【中】`setFloor(undefined)` 分支**:`location.test.ts:110` 的「清空楼层」用例在 shipped 非空实现下不可表达。选择:(A) 删除该半覆盖;(B) 认定 `IHeroLocation.setFloor(map: IGameMap | null)` 接口允许 `null`、要求生产实现对齐(属 D-10 例外,需用户确认);(C) 其他。
|
||||
- **Q2**:录像桩的测试内接口名(如 `ReplayRouteStub`)与相关用途注释如何随 `route`->`array` 改名——保留旧名/改为无 `route` 语义的新名/一并更新注释(R1 注释范围)。任何新的测试内标识符命名需用户先批准。
|
||||
- **Q3**:`HeroItems.getItem`→`addItem`/`getItemState` 的替代是否保持原用例意图(用例自述「getItem 等价于增加一个道具」)。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH §8.7、PATTERNS `P4`/`P6`。D-05 禁止新增接口;D-10 默认零生产改动,`setFloor(null)` 是否属重构遗漏由用户裁定。既有唯一 `it.skip` 是 `equipment.test.ts:353`(码 147),本计划不改其 skip 状态。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 录像桩 + Hook 链对齐(equipment/items/follower/mover/saveLoad)</name>
|
||||
<files>packages-user/data-base/src/hero/__test__/{equipment,items,follower,mover,saveLoad}.test.ts</files>
|
||||
<action>
|
||||
对齐 5 个文件。把录像桩成员 `route` 改为 `array`(保留 `disable`/`revert`,接口名与注释按 Q2 裁决);删除所有 `.load()` 链。`items.test.ts` 的 `getItem` 调用按 Q3 改为 `addItem`/`getItemState`(保持原断言意图)。`saveLoad.test.ts` 的 7 处 `setFloor(<string>)` 改为传真实 `IGameMap`,保留 `floorId` 原期望值。不得弱化断言、不删用例。确认 `mover.test.ts`/`follower.test.ts` 的异步移动用例不再 30s 悬挂。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/hero/__test__/equipment.test.ts packages-user/data-base/src/hero/__test__/items.test.ts packages-user/data-base/src/hero/__test__/follower.test.ts packages-user/data-base/src/hero/__test__/mover.test.ts packages-user/data-base/src/hero/__test__/saveLoad.test.ts</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`(含 `Test timed out in 30000ms`),或 `reading 'add'`、`addHook(...).load is not a function`。</fails_when>
|
||||
</verify>
|
||||
<done>5 文件聚焦运行 0 失败;录像桩 `array`、`.load()` 链清零、setFloor 传真实地图。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 剩余 hero 测试对齐(attribute/equipStore/location/modifier/rendering/state + perf)</name>
|
||||
<files>packages-user/data-base/src/hero/__test__/{attribute,attribute.perf,equipStore,location,modifier,rendering,state}.{test,perf}.ts</files>
|
||||
<action>
|
||||
对齐 7 个文件。`location.test.ts`/`state.test.ts` 的 `setFloor`/`changeFloor.target` 改传真实 `IGameMap`;`setFloor(undefined)` 分支按 Q1 处置。删除 `rendering.test.ts`/`state.test.ts`/`location.test.ts` 的 `.load()` 链。复核 attribute/modifier/equipStore 是否仅连带失败(最小改动)。`attribute.perf.ts` 只改因导入/接口漂移必需的形状,不动性能参数与计时逻辑。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/hero/__test__; pnpm exec eslint packages-user/data-base/src/hero/__test__</automated>
|
||||
<fails_when>hero 全部聚焦运行有非零 `failed`,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>hero 12 文件全部对齐、聚焦 0 失败、eslint 通过;码 147 的 skip 保持且仓库 skipped = 1。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 接口 | 只允许测试适配源码。 |
|
||||
| 执行者 -> git | 提交范围限于声明文件。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-04-01 | Tampering | 只补 `array` 却留 `route` 造成桩与断言不一致 | medium | mitigate | 声明桩为整体形状对齐(`{array,disable,revert}`);聚焦运行捕获不一致。 |
|
||||
| T-08-04-02 | Tampering | 用 `as never`/`Object.create` 伪绿 | high | mitigate | 明令禁止;`<fails_when>` 点名运行期错误。 |
|
||||
| T-08-04-03 | Repudiation | 删用例/放宽断言求绿 | high | mitigate | 不删 `it`、不新增 skip;期望值改写须 Task 0 授权并登记。 |
|
||||
| T-08-04-04 | Tampering | 借 `setFloor(null)` 之名改生产 | high | mitigate | 默认零生产改动;仅当 Task 0 明确裁定为 D-10 例外且用户确认方可最小修复。 |
|
||||
| T-08-04-05 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;声明文件有用户改动则 STOP(D-08)。 |
|
||||
| T-08-04-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-base/src/hero/__test__` 0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数恰为 1(147)。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`。
|
||||
- [ ] hero 11 test + 1 perf 对齐完成、聚焦 0 失败。
|
||||
- [ ] 录像桩/`.load()`/setFloor/getItem 四类形状全部对齐。
|
||||
- [ ] 零生产改动(除非 Q1 授权 D-10 例外)、零新增 skip。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-04-SUMMARY.md` when done。
|
||||
</output>
|
||||
171
.planning/phases/08-test-refactor-alignment/08-05-PLAN.md
Normal file
171
.planning/phases/08-test-refactor-alignment/08-05-PLAN.md
Normal file
@ -0,0 +1,171 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 05
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-base/src/map/__test__/dynamicTile.test.ts
|
||||
- packages-user/data-base/src/map/__test__/eventPath.test.ts
|
||||
- packages-user/data-base/src/map/__test__/eventView.test.ts
|
||||
- packages-user/data-base/src/map/__test__/gameMap.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mapLayer.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mapLifecycle.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mapState.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mover.test.ts
|
||||
- packages-user/data-base/src/map/__test__/saveLoad.test.ts
|
||||
- packages-user/data-base/src/map/__test__/staticTile.test.ts
|
||||
- packages-user/data-base/src/map/__test__/tile.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 65000
|
||||
raw_tokens: 65000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-base/src/map/**` 下除 11 个声明测试文件外零改动;不改 `gameMap.ts`/`mapState.ts`/`mapLayer.ts`/`mover.ts`/`types.ts`。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**别名/加层对齐(F 族)**:`IGameMap.setLayerAlias` 已删;别名改为 `addLayer(alias: string): IMapLayer`(`map/types.ts:654`、`gameMap.ts:61-71`)。所有 `map.addLayer()` 无参调用改为 `map.addLayer('<alias>')`;所有 `setLayerAlias(layer, 'event')` 删除并把别名并入 `addLayer`。事件层仍须经 `map.setEventLayer(layer)` 生效。"
|
||||
- "**MapState 构造对齐(F 族)**:`new MapState(tileStore, state)` 改为单参 `new MapState(state)`(`mapState.ts:36`)。`MapState.fromRaw(raw)` 为 shipped 装载入口。"
|
||||
- "**朝向注入口对齐(A/F 族)**:删除测试夹具中已删的 `DirectionMapper`(`@motajs/common` 无此导出、`IDataCommon` 无 `directionMapper` 成员);朝向能力改用 `IFaceManager`/`IFaceHandler`。不得用 `as never`/`Object.create` 伪造。"
|
||||
- "**Hook 契约对齐(D 族)**:删除 `layer.addHook({...}).load()`、`map.addHook({...}).load()` 的 `.load()`。"
|
||||
- "**陈旧校验码裁决(G 族,Open Q6)**:62/63/64/84/130/125 在当前 `mapState.ts`/`gameMap.ts`/`mapLayer.ts` 中无 emit 点——其处置(契约取消=改测试 / 重构遗漏=另立生产修复)由 Task 0 逐条裁定,不得自行补测或自行修生产。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`,不新增 skip;skipped 总数仍为 1。"
|
||||
- "**聚焦门禁**:`pnpm exec vitest run packages-user/data-base/src/map/__test__` 0 失败。"
|
||||
artifacts:
|
||||
- path: packages-user/data-base/src/map/__test__/gameMap.test.ts
|
||||
provides: "`addLayer(alias)`/`setEventLayer` 对齐;重复别名相关断言按 Q6 处置(shipped 发 131,84 无 emit)。"
|
||||
- path: packages-user/data-base/src/map/__test__/mapState.test.ts
|
||||
provides: "`new MapState(state)` 单参;raw 校验码按 Q6 处置。"
|
||||
- path: packages-user/data-base/src/map/__test__/mapLayer.test.ts
|
||||
provides: "删除 `.load()` 链;码 130 按 Q6 处置。"
|
||||
key_links:
|
||||
- "`gameMap.ts:61-71 addLayer(alias)` 内 `this.aliasLayerMap.set(alias, layer)` <-> 已删 `setLayerAlias`——别名只能在加层时给定。"
|
||||
- "`map/types.ts:654 addLayer(alias: string): IMapLayer` 为必填参 <-> 无参 `addLayer()` 运行时 alias 为 `undefined`,随后因 `setLayerAlias` 缺失而炸。"
|
||||
- "`mapState.ts:40-95 fromRaw(raw)`(`createMap`->`addLayer(alias)`->`setEventLayer`) <-> `CoreState.initMapState` 已删——事件层装配的新归属。"
|
||||
- "`map/mover.ts:19-20` `tile.state.faceManager.get(DYNAMIC_MOVER_FACE)` <-> `DynamicTileMover` 依赖 faceManager 预注册 Dir8 handler(缺则发 192)。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-base` 的 `map` 子系统 11 个测试文件到 shipped 接口/形状,使该子系统聚焦运行 0 失败。这是 RESEARCH 判定失败最集中的子系统:`DirectionMapper` 注入、`MapState` 构造、`setLayerAlias`/`addLayer` 别名、`.load()` 链、陈旧校验码共五类。
|
||||
|
||||
Purpose: map 提供 `MapState.fromRaw`(`coreEventLayer` 与 data-state 集成的关键)与事件层,其对齐质量直接决定后续 data-state 计划与覆盖计划能否顺利。
|
||||
|
||||
Output: 11 个既有文件的对齐改动;零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: map 对齐裁决关卡 —— 陈旧校验码 62/63/64/84/130/125 的处置</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-base/src/map/gameMap.ts(`:61-71` addLayer、`:129` 实际发码 131)
|
||||
- packages-user/data-base/src/map/mapState.ts(`:40-95` fromRaw、实际发码 60/61/121/55/122)
|
||||
- packages-user/data-base/src/map/mapLayer.ts(实际发码集合,无 130)
|
||||
- packages-user/data-base/src/map/types.ts(`:332,340-345` getMapData 重载、`:654` addLayer)
|
||||
- packages-user/data-base/src/map/__test__/{gameMap,mapState,mapLayer}.test.ts(84/62/63/64/130 断言点)
|
||||
- .planning/phases/06-unit-tests/06-COVERAGE-MAP.md(62/63/64/84/130/125 登记段)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划问题与方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1【中】陈旧校验码逐条处置**:62/63/64(`mapState` raw 校验)、84(`gameMap` 重复别名)、130(`mapLayer` 非本层图块)、125(`mapState` 楼层集)在当前源码均无 emit 点。逐条选择:(A) 契约取消——改写/移除相应用例;(B) 重构遗漏——另立生产修复(超出本计划,D-10 需用户确认)。**不得两存,不得由执行者自行补测。**
|
||||
- **Q2**:`addLayer(alias)` 中 `'event'` 之外的层别名取值约定(是否沿用测试原意),以及事件层 `setEventLayer` 的断言是否逐字保留。
|
||||
- **Q3**:`DynamicTileMover` 测试是否需在夹具中预注册 Dir8 handler 以避免 192;若需,属测试夹具变更(非生产)。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH §8.6、§9.2、OQ6;PATTERNS `P8`。D-05 禁止新增接口;D-10 默认零生产改动。60/61 仍为 `fromRaw` 的 shipped 校验码。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 别名/加层/构造/DirectionMapper 对齐(gameMap/mapState/mapLayer/tile/dynamicTile/staticTile/eventView/eventPath/mapLifecycle)</name>
|
||||
<files>packages-user/data-base/src/map/__test__/{gameMap,mapState,mapLayer,tile,dynamicTile,staticTile,eventView,eventPath,mapLifecycle}.test.ts</files>
|
||||
<action>
|
||||
对齐 9 个文件。所有 `map.addLayer()` -> `map.addLayer('<alias>')`;`setLayerAlias` 调用删除并把别名并入 `addLayer`,随后 `setEventLayer(layer)` 生效。`new MapState(tileStore, state)` -> `new MapState(state)`。删除夹具中的 `DirectionMapper` 注入(按 shipped `IFaceManager`/`IFaceHandler` 表达朝向,必要时按 Q3 预注册 handler)。删除 `.load()` 链。陈旧码相关断言按 Q1 逐条处置。不弱化其它断言、不删用例、每个 `it` 保留一行中文注释、不改既有 jsDoc。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/map/__test__/gameMap.test.ts packages-user/data-base/src/map/__test__/mapState.test.ts packages-user/data-base/src/map/__test__/mapLayer.test.ts packages-user/data-base/src/map/__test__/tile.test.ts packages-user/data-base/src/map/__test__/dynamicTile.test.ts packages-user/data-base/src/map/__test__/staticTile.test.ts packages-user/data-base/src/map/__test__/eventView.test.ts packages-user/data-base/src/map/__test__/eventPath.test.ts packages-user/data-base/src/map/__test__/mapLifecycle.test.ts</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`,或 `setLayerAlias is not a function`、`addLayer(...).setEventLayer` 相关运行期错误。</fails_when>
|
||||
</verify>
|
||||
<done>9 文件聚焦运行 0 失败;别名/构造/DirectionMapper/.load() 四类对齐。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: mover + saveLoad 对齐 + 提交前门禁</name>
|
||||
<files>packages-user/data-base/src/map/__test__/{mover,saveLoad}.test.ts</files>
|
||||
<action>
|
||||
对齐 `mover.test.ts`(`DynamicTileMover` 构造、faceManager 预注册、`.load()` 链)与 `saveLoad.test.ts`(`getMapData` 重载、loadState 形状)。随后对本次改动文件执行 eslint 并跑 map 全量聚焦。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-base/src/map/__test__; pnpm exec eslint packages-user/data-base/src/map/__test__</automated>
|
||||
<fails_when>map 聚焦运行有非零 `failed`,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>map 11 文件全部对齐、聚焦 0 失败、eslint 通过;skipped = 1。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 接口 | 只允许测试适配源码。 |
|
||||
| 「陈旧码」判定 -> 生产契约 | 误把契约变更当缺陷会诱发越权生产改动。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-05-01 | Tampering | 把陈旧码当缺失补测/改生产 | high | mitigate | 逐条 Task 0 裁定;默认只改测试;生产修复须 D-10 用户确认。 |
|
||||
| T-08-05-02 | Tampering | 用 `as never`/`Object.create` 伪造已删 `DirectionMapper` | high | mitigate | 明令禁止;`<fails_when>` 点名运行期错误。 |
|
||||
| T-08-05-03 | Repudiation | 删用例/放宽断言求绿 | high | mitigate | 不删 `it`、不新增 skip;期望值改写须授权并登记。 |
|
||||
| T-08-05-04 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;声明文件有用户改动则 STOP(D-08)。 |
|
||||
| T-08-05-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-base/src/map/__test__` 0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数恰为 1。
|
||||
- 陈旧码处置逐条记入 SUMMARY。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`,陈旧码逐条裁定。
|
||||
- [ ] map 11 文件对齐完成、聚焦 0 失败。
|
||||
- [ ] 零生产改动(除经确认的 D-10 例外)、零新增 skip。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-05-SUMMARY.md` when done(含陈旧码逐条处置台账)。
|
||||
</output>
|
||||
160
.planning/phases/08-test-refactor-alignment/08-06-PLAN.md
Normal file
160
.planning/phases/08-test-refactor-alignment/08-06-PLAN.md
Normal file
@ -0,0 +1,160 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 06
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-system/src/combat/__test__/combat.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/context.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/context.perf.ts
|
||||
- packages-user/data-system/src/combat/__test__/damage.test.ts
|
||||
- packages-user/data-system/src/combat/__test__/damage.perf.ts
|
||||
- packages-user/data-system/src/combat/__test__/mapDamage.test.ts
|
||||
- packages-user/data-system/src/event/__test__/eventDispatch.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 55000
|
||||
raw_tokens: 55000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-system/src/{combat,event}/**` 下除 7 个声明测试文件外零改动。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**Hook 契约对齐(D 族)**:`combat.test.ts:442,474,499` 的 `.load()` 链删除。"
|
||||
- "**CombatFlow 构造对齐(F 族)**:按 shipped `constructor(readonly state: IStateBase) { super(); }`(`combat.ts:38-40`)装配;测试实参以执行当日源码为准(Q1)。"
|
||||
- "**eventDispatch 朝向对齐(A 族)**:删除已删的 `DirectionMapper`(`eventDispatch.test.ts:69,104,143`),改用 shipped `IFaceManager`/`IFaceHandler` 或移除无用的注入位(Q2)。"
|
||||
- "**DEV 守卫码保持可触发**:98/99/101(`context.ts`)带 `import.meta.env.DEV` 守卫;保持 Vitest 默认 `mode=test`(DEV=true),不为这些码切换构建模式。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`,不新增 skip;skipped 总数仍为 1。"
|
||||
- "**聚焦门禁**:combat 4 test + 2 perf 与 event 1 文件聚焦运行 0 失败。"
|
||||
artifacts:
|
||||
- path: packages-user/data-system/src/combat/__test__/combat.test.ts
|
||||
provides: "删除 `.load()` 链;`CombatFlow` 构造与 `bindContext`/`bindDamage` 校验码 138/139/140/141 断言复核。"
|
||||
- path: packages-user/data-system/src/event/__test__/eventDispatch.test.ts
|
||||
provides: "删除 `DirectionMapper` 引用;码 171/172 断言复核。"
|
||||
key_links:
|
||||
- "`combat.ts:38-40 CombatFlow(readonly state: IStateBase)` <-> 旧测试装配——首参需 `IStateBase`。"
|
||||
- "`context.ts:401/456/465/485/506/705/767/776/786/796` 的 DEV 守卫码 <-> Vitest 默认 `mode=test`(DEV=true)——断言依赖 DEV,不得切生产模式。"
|
||||
- "`event/executor.ts:39,46`=172、`:66,73`=171 <-> `eventDispatch.test.ts` 的事件注册/派发断言。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-system` 的 `combat`(4 test + 2 perf)与 `event`(1 文件)到 shipped 接口,使两子系统聚焦运行 0 失败。主要为 `addHook(...).load()` 删除、`CombatFlow` 构造、`DirectionMapper` 移除。
|
||||
|
||||
Purpose: Layer 2 依赖 Layer 1;combat/event 的对齐为 data-state 集成与后续覆盖计划铺路。
|
||||
|
||||
Output: 7 个既有文件的对齐改动;零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: combat/event 对齐裁决关卡 —— CombatFlow 构造实参、eventDispatch 朝向注入</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-system/src/combat/combat.ts(`:38-40` 构造、`:62,75,119,179,184,211,215,233,237` 发码点)
|
||||
- packages-user/data-system/src/combat/context.ts(DEV 守卫码)
|
||||
- packages-user/data-system/src/combat/__test__/combat.test.ts(`:442,474,499` `.load()`)
|
||||
- packages-user/data-system/src/event/executor.ts(`:39,46,66,73`)与 event/__test__/eventDispatch.test.ts(`:69,104,143` DirectionMapper)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1**:`CombatFlow` 测试构造需传的 `IStateBase` 从何而来(沿用 Phase 6 既有夹具装配还是新建最小 state 桩);以执行当日源码签名为准。
|
||||
- **Q2**:`eventDispatch.test.ts` 的 `DirectionMapper` 注入是删除(无用坐标位)还是改注入 shipped `IFaceManager`/`IFaceHandler`,取决于该断言是否真的用到朝向。
|
||||
- **Q3**:确认 DEV 守卫码(98/99/101)保持默认 `mode=test` 触发,不做构建模式切换。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH §8.8/§8.9;D-05 禁止新增接口;D-10 默认零生产改动。Phase 6 已建立 combat Layer-2 测试夹具(可复用)。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: combat 对齐(4 test + 2 perf)</name>
|
||||
<files>packages-user/data-system/src/combat/__test__/{combat,context,damage,mapDamage}.test.ts, packages-user/data-system/src/combat/__test__/{context,damage}.perf.ts</files>
|
||||
<action>
|
||||
对齐 6 个文件。删除 `.load()` 链(`combat.test.ts:442,474,499`);`CombatFlow` 构造按 Q1 对齐 `IStateBase`。复核码 138/139/140/141、97/98/99/100/101/110、102/103/104、106/107 断言与 emit 点一致;保持 DEV 守卫可触发。perf 文件只改因导入/构造漂移必需的形状,不动性能参数与计时逻辑。不弱化断言、不删用例。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-system/src/combat/__test__</automated>
|
||||
<fails_when>combat 聚焦运行汇总行出现非零 `failed`(含 perf 收集错误),或 `addHook(...).load is not a function`、构造相关运行期错误。</fails_when>
|
||||
</verify>
|
||||
<done>combat 4 test + 2 perf 聚焦运行 0 失败。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: eventDispatch 对齐 + 提交前门禁</name>
|
||||
<files>packages-user/data-system/src/event/__test__/eventDispatch.test.ts</files>
|
||||
<action>
|
||||
对齐 eventDispatch:按 Q2 处置 `DirectionMapper` 引用;复核码 171/172 断言。随后跑 combat+event 全量聚焦并 eslint。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-system/src/combat/__test__ packages-user/data-system/src/event/__test__; pnpm exec eslint packages-user/data-system/src/combat/__test__ packages-user/data-system/src/event/__test__</automated>
|
||||
<fails_when>event 或 combat 聚焦有非零 `failed`,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>combat+event 7 文件全部对齐、聚焦 0 失败、eslint 通过。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 接口 | 只允许测试适配源码。 |
|
||||
| 执行者 -> git | 提交范围限于声明文件。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-06-01 | Tampering | 伪绿(伪造已删注入位) | high | mitigate | 禁止 `as never`/`Object.create`;`<fails_when>` 点名运行期错误。 |
|
||||
| T-08-06-02 | Repudiation | 删用例/放宽断言求绿 | high | mitigate | 不删 `it`、不新增 skip;期望值改写须授权并登记。 |
|
||||
| T-08-06-03 | Tampering | 为触发 DEV 码切换构建模式 | medium | mitigate | 明确保持默认 `mode=test`;不改配置。 |
|
||||
| T-08-06-04 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;声明文件有用户改动则 STOP(D-08)。 |
|
||||
| T-08-06-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-system/src/combat/__test__ packages-user/data-system/src/event/__test__` 0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数仍为 1。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`。
|
||||
- [ ] combat 4+2 与 event 1 对齐完成、聚焦 0 失败。
|
||||
- [ ] 零生产改动、零新增 skip。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-06-SUMMARY.md` when done。
|
||||
</output>
|
||||
158
.planning/phases/08-test-refactor-alignment/08-07-PLAN.md
Normal file
158
.planning/phases/08-test-refactor-alignment/08-07-PLAN.md
Normal file
@ -0,0 +1,158 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 07
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-system/src/path/__test__/graph.test.ts
|
||||
- packages-user/data-system/src/path/__test__/performance.test.ts
|
||||
- packages-user/data-system/src/path/__test__/system.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 45000
|
||||
raw_tokens: 45000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-system/src/path/**` 下除 3 个声明测试文件外零改动;不改 `types.ts`/`graph.ts`/`finder.ts`/`system.ts`。"
|
||||
- "**注入面改名对齐(F 族)**:`useMapState` 已删且无同名替代——测试侧删除该调用;图宽度改由 `useMapLayer(layer)` 内 `indexer.setWidth(layer.width)` 提供(`graph.ts:38-43`)。`useDirGroup` 已被 `useFaceHandler(face: IFaceHandler<number> | null)` 取代——测试注入真实处理器对象(`Dir4FaceHandler`/`Dir8FaceHandler`),不得再传数字。"
|
||||
- "**builder face 默认值对齐**:builder 的 `face` 默认值由旧 `InternalDirectionGroup.Dir4` 变为 `null`;缺失即 `build()` 走 173 早退。凡调用 `build()`/`finder.find()` 的测试路径必须显式注入方向处理器,默认对齐用 `Dir4FaceHandler`(对应旧默认意图),要八方向的用例注入 `Dir8FaceHandler`。"
|
||||
- "**DirectionMapper 移除(A 族)**:`graph.test.ts` 中 `DirectionMapper` import/使用删除。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`,不改性能用例的规模参数与断言阈值,不新增 skip;skipped 总数仍为 1。"
|
||||
- "**聚焦门禁**:`pnpm exec vitest run packages-user/data-system/src/path/__test__` 0 失败。"
|
||||
artifacts:
|
||||
- path: packages-user/data-system/src/path/__test__/graph.test.ts
|
||||
provides: "移除 `useMapState`/`DirectionMapper`;`useFaceHandler(<Handler>)` 注入;八方向用例注入 `Dir8FaceHandler`。"
|
||||
- path: packages-user/data-system/src/path/__test__/system.test.ts
|
||||
provides: "移除 `finder.useMapState`;补注入 `Dir4FaceHandler` 使 `find` 不早退 173。"
|
||||
- path: packages-user/data-system/src/path/__test__/performance.test.ts
|
||||
provides: "移除 `finder.useMapState` 与内联 builder 的 `useMapState`;补注入处理器;保持规模参数不变。"
|
||||
key_links:
|
||||
- "`MapGraphBuilder.useMapLayer(layer)` 内 `indexer.setWidth(layer.width)` <-> 已删 `useMapState` 的「提供图宽度」职责——测试只能删除该调用,不能改名。"
|
||||
- "`graph.ts:69-88` 三处 173 早退(layer/predicate/face 任一为 null) <-> builder face 默认 null——未注入处理器时断言会退化为空图。"
|
||||
- "`finder.ts:108-116` `useMapLayer` 的 `layer.state !== this.state` 告警 182 <-> 测试注入层的 state 一致性。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-system` 的 `path` 子系统 3 个测试文件到 shipped 寻路接口(`useMapLayer`/`useFaceHandler`),使该子系统聚焦运行 0 失败。这是 RESEARCH 记录的「接口整体改名」子系统。
|
||||
|
||||
Purpose: 寻路注入面改名(`useMapState`->`useMapLayer`、`useDirGroup`->`useFaceHandler`)影响 graph/system/performance 三文件与 data-state 的 replayPlayback;本计划处理 path 直属 3 文件,replayPlayback 归 08-09。
|
||||
|
||||
Output: 3 个既有文件的对齐改动;零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: path 对齐裁决关卡 —— 处理器注入选择(Dir4 默认 vs Dir8)与 useMapState 删除</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-system/src/path/types.ts(`IMapGraphBuilder`/`IPathFinder` 现有成员,无 `useMapState`)
|
||||
- packages-user/data-system/src/path/graph.ts(`:34-51`、`:69-88` 173 早退、`:102` face.mapMovement)
|
||||
- packages-user/data-system/src/path/finder.ts(`:107-127`)
|
||||
- packages-user/data-common/src/common/faceManager.ts(`Dir4FaceHandler`/`Dir8FaceHandler`)
|
||||
- packages-user/data-system/src/path/__test__/{graph,system,performance}.test.ts(`useMapState`/`useDirGroup` 调用点)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1**:默认注入 `Dir4FaceHandler`(保持旧默认 `InternalDirectionGroup.Dir4` 意图)还是 `Dir8FaceHandler`;显式八方向用例(`graph.test.ts:346`)改用 `Dir8FaceHandler` 对象确认。
|
||||
- **Q2**:确认 `useMapState` 在 builder 与 finder 两处均删除、宽度由 `useMapLayer` 承担;删除后不再使用的 `maps` 局部变量按 lint 处理。
|
||||
- **Q3**:`performance.test.ts` 的注入面改动不得触碰规模参数与断言阈值(仅改注入)。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH §8.10、PATTERNS `P7`、OQ/Code Examples。`core.ts:194-200` 的顶层装配无 `useFaceHandler` 注入,故测试须自行注入处理器。D-05 禁止新增接口。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: graph + system 对齐</name>
|
||||
<files>packages-user/data-system/src/path/__test__/{graph,system}.test.ts</files>
|
||||
<action>
|
||||
对齐 2 个文件。`graph.test.ts` 删除 `useMapState`/`DirectionMapper`,`createFixture` 默认注入 `Dir4FaceHandler`(按 Q1),八方向用例注入 `Dir8FaceHandler` 对象。`system.test.ts` 删除 `finder.useMapState`,补注入 `Dir4FaceHandler` 使 `find` 不早退 173。仅改注入面,不动用例规模与断言。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-system/src/path/__test__/graph.test.ts packages-user/data-system/src/path/__test__/system.test.ts</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`,或 `useMapState is not a function`、读 null 属性(173 早退后空图)类错误。</fails_when>
|
||||
</verify>
|
||||
<done>graph+system 聚焦运行 0 失败;注入面全部对齐。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: performance 对齐 + 提交前门禁</name>
|
||||
<files>packages-user/data-system/src/path/__test__/performance.test.ts</files>
|
||||
<action>
|
||||
对齐 `performance.test.ts`:删除 finder 与内联 builder 两处 `useMapState`,补注入处理器,保持性能矩阵规模参数与断言阈值不变。随后跑 path 全量聚焦并 eslint。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-system/src/path/__test__; pnpm exec eslint packages-user/data-system/src/path/__test__</automated>
|
||||
<fails_when>path 聚焦运行有非零 `failed`,或 eslint 报错(含未使用变量)。</fails_when>
|
||||
</verify>
|
||||
<done>path 3 文件全部对齐、聚焦 0 失败、eslint 通过。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 寻路接口 | 只允许测试适配源码。 |
|
||||
| 性能断言 -> 真实意图 | 改规模参数等于改测试意图。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-07-01 | Tampering | 为转绿改性能规模/阈值 | medium | mitigate | 明令只改注入面;`<fails_when>` 与人工复核。 |
|
||||
| T-08-07-02 | Tampering | 用数字当 `IFaceHandler` 或伪造成员 | high | mitigate | 注入真实处理器对象;禁止 `as never`。 |
|
||||
| T-08-07-03 | Repudiation | 删用例/放宽断言 | high | mitigate | 不删 `it`、不新增 skip。 |
|
||||
| T-08-07-04 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;声明文件有用户改动则 STOP(D-08)。 |
|
||||
| T-08-07-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-system/src/path/__test__` 0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数仍为 1。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`。
|
||||
- [ ] path 3 文件对齐完成、聚焦 0 失败、性能参数不变。
|
||||
- [ ] 零生产改动、零新增 skip。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-07-SUMMARY.md` when done。
|
||||
</output>
|
||||
168
.planning/phases/08-test-refactor-alignment/08-08-PLAN.md
Normal file
168
.planning/phases/08-test-refactor-alignment/08-08-PLAN.md
Normal file
@ -0,0 +1,168 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 08
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 08-01
|
||||
files_modified:
|
||||
- packages-user/data-state/src/__test__/coreEventLayer.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/aura.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/calculator.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/comparer.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/final.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/mapDamage.test.ts
|
||||
- packages-user/data-state/src/enemy/__test__/special.test.ts
|
||||
- packages-user/data-state/src/event/__test__/event.test.ts
|
||||
- packages-user/data-state/src/replay/__test__/commands.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 60000
|
||||
raw_tokens: 60000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-state/src/**` 下除 9 个声明测试文件外零改动;不改 `core.ts`/`types.ts`/`ins.ts`/`enemy/**`/`event/**`/`replay/**` 等实现。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**CoreState 构造对齐(B 族)**:`createCoreState()` 已整体删除。测试统一改为 `new CoreState({ loadStarter, coreURL })`(`ICoreStateConfig` 形状:`readonly loadStarter: ILoadTaskStarter; readonly coreURL: string;`,`data-state/src/types.ts:7-15`)。`loadStarter` 来源由 Task 0 裁决(Q1)。"
|
||||
- "**initMapState 对齐(A/F 族)**:`CoreState.initMapState` 已删,同名职责归 `MapState.fromRaw(raw)`(单参 raw 对象)。(A1) `coreEventLayer.test.ts` 重定向到 `MapState.fromRaw` 并保留原有「事件层被选为事件层、其余层序/zIndex 不变」的断言意图,清理已无意义的 `vi.mock('./enemy')`/`vi.mock('./legacy')`/`Object.create` 骨架;或 (A2) 退役该文件(等价覆盖已在 `mapState.test.ts`/`mapLifecycle.test.ts`,须用户认领)。"
|
||||
- "**legacy 模块消失(E 族)**:`data-state/src/legacy/` 已不存在;相关 `vi.mock('./legacy', ...)`/import 删除或按 Q4 处置。"
|
||||
- "**形状对齐(F 族)**:`event.test.ts` 的 `new CoreState()`->带 config、`map.addLayer()`->`addLayer('<alias>')`、`state.hero.location.setFloor('F1')`->传真实 `IGameMap`。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`(除 A2 授权的整文件退役),不新增 skip;skipped 总数仍为 1。"
|
||||
- "**聚焦门禁**:`pnpm exec vitest run packages-user/data-state/src/__test__ packages-user/data-state/src/enemy/__test__ packages-user/data-state/src/event/__test__ packages-user/data-state/src/replay/__test__` 0 失败。"
|
||||
artifacts:
|
||||
- path: packages-user/data-state/src/__test__/coreEventLayer.test.ts
|
||||
provides: "按 Q4 重定向到 `MapState.fromRaw`(保留原断言意图)或退役。"
|
||||
- path: packages-user/data-state/src/event/__test__/event.test.ts
|
||||
provides: "CoreState 带 config 构造 + addLayer(alias) + setFloor(真实地图)。"
|
||||
- path: packages-user/data-state/src/replay/__test__/commands.test.ts
|
||||
provides: "CoreState 带 config 构造;码 2001-2008 断言复核。"
|
||||
key_links:
|
||||
- "`core.ts:111` `constructor(config: Readonly<ICoreStateConfig>)` 读 `config.loadStarter`/`config.coreURL` <-> 无参构造抛 `Cannot read properties of undefined (reading 'loadStarter')`(失败族 B)。"
|
||||
- "`core.ts` 已无 `initMapState` <-> `mapState.ts:40-95 fromRaw(raw: IMapRawData)` 承担图层装配(createMap->addLayer(alias)->setEventLayer)。"
|
||||
- "`ins.ts:11-14` `new CoreState({ loadStarter: new WebLoadStarter(), coreURL: 'placeholder' })` <-> Node 测试的 `loadStarter` 参考来源。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-state` 的 `src/` 直属 9 个测试文件(`coreEventLayer` 1、`enemy/` 6、`event/` 1、`replay/` 1)到 shipped 接口/形状,使这些文件聚焦运行 0 失败。核心是失败族 B(`CoreState` 配置)、A/F(`createCoreState`/`initMapState` 删除、`fromRaw`)、E(legacy 模块消失)。
|
||||
|
||||
Purpose: `data-state` 是 Layer 3 顶层;`CoreState` 构造形状与 `loadStarter` 夹具决定同一包内 8 个集成测试与 3 个 perf 文件(08-09)的改法,故本计划先落地统一的 `CoreState` 装配约定。
|
||||
|
||||
Output: 9 个既有文件的对齐改动(或 `coreEventLayer.test.ts` 退役);可能新增 1 个测试内 `loadStarter` 夹具(命名须用户批准);零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: data-state src 对齐裁决关卡 —— loadStarter 夹具形态、coreEventLayer A1/A2</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-state/src/core.ts(`:111` 构造、`:205,207` 读 config、导出面仅 `CoreState`)
|
||||
- packages-user/data-state/src/types.ts(`:7-15` `ICoreStateConfig`)
|
||||
- packages-user/data-state/src/ins.ts(`:11-14` 参考实例)
|
||||
- packages-user/data-state/src/__test__/coreEventLayer.test.ts(`:36-46,47-71,73-124,126-159`)
|
||||
- packages-user/data-base/src/map/mapState.ts(`:40-95` fromRaw)
|
||||
- packages/loader/src/starter.ts(`WebLoadStarter`)与 packages/loader/src/types.ts(`:186` 接口)
|
||||
- packages-user/data-state/src/{event/event.test.ts,replay/commands.test.ts,enemy/*.test.ts}
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划问题与方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1【高】`loadStarter` 夹具形态**:(a) `new WebLoadStarter()`;(b) 测试内 inline stub 实现 `ILoadTaskStarter`;(c) 抽出一个共享测试夹具(**新文件/新标识符命名须用户先批准**,且 08-09 将复用)。在无新依赖前提下,研究倾向 (a) 或 (b)。
|
||||
- **Q2【高】`coreEventLayer.test.ts` 的 A1/A2**:(A1) 重定向到 `MapState.fromRaw` 并保留原断言语义、清理旧 mock 骨架;(A2) 退役该文件(等价覆盖已在 `mapState.test.ts`/`mapLifecycle.test.ts`,须用户明确认领)。
|
||||
- **Q3**:`event.test.ts`/`commands.test.ts` 的 `setFloor`/`addLayer` 形状对齐确认。
|
||||
- **Q4**:`data-state/src/legacy/` 消失后的 `vi.mock('./legacy', ...)` 处置(删除)。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH OQ1/OQ4、§8.11;PATTERNS `P2`/`P6`。D-05 禁止新增接口;D-10 默认零生产改动;若需新测试内命名,AGENTS.md 要求先批准。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: coreEventLayer + event + commands 对齐(CoreState 装配约定)</name>
|
||||
<files>packages-user/data-state/src/__test__/coreEventLayer.test.ts, packages-user/data-state/src/event/__test__/event.test.ts, packages-user/data-state/src/replay/__test__/commands.test.ts</files>
|
||||
<action>
|
||||
对齐 3 个文件。按 Q1 统一 `CoreState` 装配(`new CoreState({ loadStarter, coreURL })`)。`coreEventLayer.test.ts` 按 Q4(A1 重定向到 `MapState.fromRaw` / A2 退役)执行;A1 时保留原断言意图并删除失效 mock 骨架。`event.test.ts` 的 `addLayer()`->`addLayer('<alias>')`、`setFloor('F1')`->真实 `IGameMap`。`commands.test.ts` 复核码 2001-2008。不弱化断言、不删用例。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-state/src/__test__ packages-user/data-state/src/event/__test__ packages-user/data-state/src/replay/__test__</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`,或 `createCoreState is not a function`、`reading 'loadStarter'`、`reading 'floorId'` 类运行期错误。</fails_when>
|
||||
</verify>
|
||||
<done>3 文件聚焦运行 0 失败(或 coreEventLayer 按 A2 退役并登记)。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: data-state src/enemy 6 文件对齐 + 提交前门禁</name>
|
||||
<files>packages-user/data-state/src/enemy/__test__/{aura,calculator,comparer,final,mapDamage,special}.test.ts</files>
|
||||
<action>
|
||||
对齐 6 个文件(Phase 6 已建立的数据-state enemy 测试)。按 Q1 的 `CoreState` 装配约定统一构造;复核码 137 及各用例断言。若仅连带失败则最小改动。随后跑 data-state src 全量聚焦并 eslint。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-state/src/__test__ packages-user/data-state/src/enemy/__test__ packages-user/data-state/src/event/__test__ packages-user/data-state/src/replay/__test__; pnpm exec eslint packages-user/data-state/src/__test__ packages-user/data-state/src/enemy/__test__ packages-user/data-state/src/event/__test__ packages-user/data-state/src/replay/__test__</automated>
|
||||
<fails_when>data-state src 聚焦运行有非零 `failed`,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>data-state src 9 文件全部对齐、聚焦 0 失败、eslint 通过;skipped = 1。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 接口 | 只允许测试适配源码。 |
|
||||
| 夹具命名 -> 用户审批 | 新测试内标识符须先获批。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-08-01 | Tampering | 伪绿(`Object.create`/`as never` 伪造已删 `initMapState`) | high | mitigate | 明令禁止;A1 重定向真实 `fromRaw`,A2 退役须用户认领。 |
|
||||
| T-08-08-02 | Repudiation | 删用例/放宽断言求绿 | high | mitigate | 不删 `it`、不新增 skip;期望值改写须授权并登记。 |
|
||||
| T-08-08-03 | Tampering | 未获批新增命名 | medium | mitigate | 新夹具/标识符须 Task 0 批准;无批准则用 inline stub(零新命名)。 |
|
||||
| T-08-08-04 | Tampering | 提交用户并发改动(用户可能正改 `data-state/src/core.ts`) | high | mitigate | 移动脚本只改测试;提交 `git add <显式路径>`;若 `core.ts` 有用户改动则只读不改、不暂存(D-08)。 |
|
||||
| T-08-08-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-state/src/__test__ packages-user/data-state/src/enemy/__test__ packages-user/data-state/src/event/__test__ packages-user/data-state/src/replay/__test__` 0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数恰为 1。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`(Q1 loadStarter、Q2 A1/A2)。
|
||||
- [ ] data-state src 9 文件对齐完成(或 coreEventLayer 退役)、聚焦 0 失败。
|
||||
- [ ] 零生产改动、零新增 skip;新命名(若有)已获批。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-08-SUMMARY.md` when done(记录 Q1 装配约定、Q2 处置、期望值改写台账)。
|
||||
</output>
|
||||
176
.planning/phases/08-test-refactor-alignment/08-09-PLAN.md
Normal file
176
.planning/phases/08-test-refactor-alignment/08-09-PLAN.md
Normal file
@ -0,0 +1,176 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 09
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on:
|
||||
- 08-01
|
||||
- 08-08
|
||||
files_modified:
|
||||
- packages-user/data-state/__test__/coreNode.test.ts
|
||||
- packages-user/data-state/__test__/dataClosure.test.ts
|
||||
- packages-user/data-state/__test__/enemyCombination.test.ts
|
||||
- packages-user/data-state/__test__/nodeReplay.test.ts
|
||||
- packages-user/data-state/__test__/nodeTracer.test.ts
|
||||
- packages-user/data-state/__test__/replayPlayback.test.ts
|
||||
- packages-user/data-state/__test__/saveablesRoundTrip.test.ts
|
||||
- packages-user/data-state/__test__/tileLegacy.test.ts
|
||||
- packages-user/data-state/__test__/mapScenario.perf.ts
|
||||
- packages-user/data-state/__test__/saveables.perf.ts
|
||||
- packages-user/data-state/__test__/saveablesReal.perf.ts
|
||||
- packages-user/data-state/__test__/replayVerifier.ts
|
||||
- packages-user/data-state/__test__/fixtures/closed-loop.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 65000
|
||||
raw_tokens: 65000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只对齐既有测试、零生产改动**:`packages-user/data-state/{__test__,src}/**` 下除 13 个声明文件外零改动;不改 `core.ts`、`ins.ts`、`hero/predicate.ts` 等实现。若某失效只有改生产才能转绿,按 D-10 退出并汇报。"
|
||||
- "**CoreState 装配统一**:全部 8 test + 3 perf + 共享夹具 `fixtures/closed-loop.ts` 统一按 08-08 Task 0 的 `loadStarter` 契约装配(Q1),删除全部 `createCoreState()` 调用。"
|
||||
- "**共享夹具根因对齐**:`fixtures/closed-loop.ts` 的 `setFloor('F1')` 改为传真实 `IGameMap`(`state.maps.fromRaw` 的返回值),使 `location.map` 为对象、通行谓词可读到 `map.eventLayer`;夹具其余装配与 `IClosedLoopFixture` 成员逐字保留(`route: IReplayArray` 等 shipped 成员名不变)。"
|
||||
- "**寻路注入对齐(F 族)**:`replayPlayback.test.ts` 的 `useMapState` 删除;`DefaultPassPredicateImpl(state.maps)`->`(state)`;补注入方向处理器使 `find` 不早退 173;`setFloor` 传真实地图。"
|
||||
- "**别名/加层对齐(F 族)**:`coreNode.test.ts:21` 的 `map.addLayer()` 补别名;`saveablesRoundTrip.test.ts:135` 同。"
|
||||
- "**tileLegacy 裁决(Open Q3)**:`data-state/src/legacy/` 与 `TileLegacyBridge`/`LegacyTileData` 已不存在。`tileLegacy.test.ts` 选择:退役(并在 SUMMARY 登记等价覆盖位置),或重定向到新 legacy/loader 适配路径——由 Task 0 裁定,不得自行删测。"
|
||||
- "**无断言弱化、无新增 skip**:不删 `it`(除 tileLegacy 经授权退役),不新增 skip;skipped 总数仍为 1。"
|
||||
- "**聚焦门禁**:`pnpm exec vitest run packages-user/data-state/__test__` 0 失败;`pnpm test:perf` 采集 6 且 0 失败。"
|
||||
artifacts:
|
||||
- path: packages-user/data-state/__test__/fixtures/closed-loop.ts
|
||||
provides: "CoreState 装配 + 两处 `setFloor(<IGameMap>)`;`IClosedLoopFixture` 成员逐字保留。"
|
||||
- path: packages-user/data-state/__test__/replayPlayback.test.ts
|
||||
provides: "`useMapLayer`/`useFaceHandler`/`DefaultPassPredicateImpl(state)`/`setFloor(真实地图)` 对齐。"
|
||||
- path: packages-user/data-state/__test__/tileLegacy.test.ts
|
||||
provides: "按 Q3 退役或重定向。"
|
||||
key_links:
|
||||
- "`closed-loop.ts:166,234` 传字符串 setFloor -> `location.map` 为字符串 -> `mover.ts:203` 交给谓词 -> `predicate.ts:33-35` 读 `map.eventLayer` 得 undefined -> 拒绝移动(`dataClosure`/`nodeTracer` 的 `expected +0 to be 1`/`false to be true`)——夹具是共同根因。"
|
||||
- "`core.ts:194-200` 顶层装配 `useMapLayer(null)`/`usePassPredicate(new DefaultPassPredicateImpl(this))`、无 `useFaceHandler` <-> replayPlayback 测试须自行补注入处理器。"
|
||||
- "`data-state/src/legacy/` 与 `TileLegacyBridge`/`LegacyTileData` 全仓 0 命中(除本测试) <-> tileLegacy.test.ts 无被测对象。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
对齐 `packages-user/data-state` 的集成测试层 `data-state/__test__/`(8 test + 3 perf + 共享夹具 + helper)到 shipped 接口/形状,使该层聚焦运行 0 失败。核心根因是三处:`createCoreState`/`CoreState` 配置(B/A)、共享夹具 `closed-loop.ts` 的 `setFloor('F1')` 导致通行拒绝(G)、寻路注入面改名(F)。
|
||||
|
||||
Purpose: 这是本阶段集成面最重的一批(11 test/perf + 共享夹具),且 `dataClosure`/`nodeTracer` 的失败完全由共享夹具解释;把夹具与消费文件放在同一计划内可避免跨计划文件冲突。
|
||||
|
||||
Output: 13 个既有文件的对齐改动(或 `tileLegacy.test.ts` 退役);零生产改动、零新增依赖。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-08-PLAN.md
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。`loadStarter` 契约须与 08-08 的 Task 0 裁决保持一致。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: data-state 集成裁决关卡 —— tileLegacy 去留、loadStarter 契约一致、夹具改动确认</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- packages-user/data-state/__test__/fixtures/closed-loop.ts(`:47-61,91-146,163-172,233-246`)
|
||||
- packages-user/data-state/__test__/{coreNode,dataClosure,nodeTracer,replayPlayback,saveablesRoundTrip,enemyCombination,nodeReplay,tileLegacy}.test.ts
|
||||
- packages-user/data-state/__test__/{mapScenario,saveables,saveablesReal}.perf.ts
|
||||
- packages-user/data-state/src/hero/predicate.ts(`:5-8,25-35`)
|
||||
- packages-user/data-state/__test__/replayVerifier.ts
|
||||
- 08-08-PLAN.md 的 Task 0(`loadStarter` 契约)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1【高】`tileLegacy.test.ts` 去留**:被测模块 `data-state/src/legacy/` 与 `TileLegacyBridge`/`LegacyTileData` 已整体删除。选择:(A) 退役该文件(SUMMARY 明写等价覆盖位置);(B) 重定向到新 legacy/loader 适配路径(须指明 shipped 被测面)。
|
||||
- **Q2**:确认与 08-08 Task 0 一致的 `loadStarter` 契约用于本层 11 文件 + `closed-loop.ts`。
|
||||
- **Q3**:`closed-loop.ts` 的 `setFloor(<IGameMap>)` 与两处调用点改动确认;`dataClosure.test.ts`/`nodeTracer.test.ts` 是否如研究预期「零改动、由夹具解释」(不为其「看起来参与」而改断言)。
|
||||
- **Q4**:`replayPlayback.test.ts` 注入的处理器选择(与 08-07 一致的 Dir4 默认)。
|
||||
</decision>
|
||||
<context>
|
||||
RESEARCH §8.11、OQ1/OQ3;PATTERNS `P6`/`P7`;07-16 的 A7(夹具与零改动文件)。D-05 禁止新增接口;D-10 默认零生产改动;tileLegacy 退役须用户明确认领。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 共享夹具 + 寻路/楼层核心(closed-loop/coreNode/replayPlayback/saveablesRoundTrip)</name>
|
||||
<files>packages-user/data-state/__test__/fixtures/closed-loop.ts, packages-user/data-state/__test__/coreNode.test.ts, packages-user/data-state/__test__/replayPlayback.test.ts, packages-user/data-state/__test__/saveablesRoundTrip.test.ts</files>
|
||||
<action>
|
||||
对齐 1 夹具 + 3 文件。`closed-loop.ts` 按 Q2 统一 `CoreState` 装配,两处 `setFloor('F1')` 改为传真实 `IGameMap`(Q3),保留 `IClosedLoopFixture` 成员。`coreNode.test.ts:21`/`saveablesRoundTrip.test.ts:135` 的 `addLayer()` 补别名。`replayPlayback.test.ts` 删除 `useMapState`、`DefaultPassPredicateImpl(state.maps)`->`(state)`、补注入处理器(Q4)、`setFloor` 传真实地图。不弱化断言。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-state/__test__/coreNode.test.ts packages-user/data-state/__test__/replayPlayback.test.ts packages-user/data-state/__test__/saveablesRoundTrip.test.ts</automated>
|
||||
<fails_when>聚焦运行汇总行出现非零 `failed`,或 `createCoreState is not a function`、`reading 'floorId'`、`reading 'eventLayer'`、`useMapState is not a function` 类错误。</fails_when>
|
||||
</verify>
|
||||
<done>夹具 + 3 文件聚焦运行 0 失败。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 其余集成测试 + perf 对齐 + 收口门禁</name>
|
||||
<files>packages-user/data-state/__test__/{dataClosure,nodeTracer,enemyCombination,nodeReplay,tileLegacy}.test.ts, packages-user/data-state/__test__/{mapScenario,saveables,saveablesReal}.perf.ts, packages-user/data-state/__test__/replayVerifier.ts</files>
|
||||
<action>
|
||||
对齐余下文件。`dataClosure.test.ts`/`nodeTracer.test.ts` 若如研究预期由夹具解释则保持零改动(Q3)。`tileLegacy.test.ts` 按 Q1 退役或重定向。`enemyCombination`/`nodeReplay` 按 Q2 装配 `CoreState`;3 个 perf 文件统一装配并只改形状、不动性能参数与计时逻辑;`replayVerifier.ts` 作为随迁 helper,若因 `CoreState` 形状漂移需同步则最小对齐。随后跑 data-state 全量聚焦、`pnpm test:perf`、eslint。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-state/__test__; pnpm test:perf; pnpm exec eslint packages-user/data-state/__test__</automated>
|
||||
<fails_when>data-state 聚焦运行有非零 `failed`,或 test:perf 采集数不等于 6 或出现非零 `failed`,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>data-state 集成层全部对齐、聚焦 0 失败、test:perf 6 文件 0 失败、eslint 通过;tileLegacy 按裁决处置并登记。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 测试 -> shipped 接口 | 只允许测试适配源码。 |
|
||||
| 共享夹具 -> 多测试 | 夹具改动影响面广,误改会波及多条用例。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-09-01 | Tampering | 为让零改动文件「参与」而改断言 | medium | mitigate | Q3 明确 dataClosure/nodeTracer 由夹具解释时保持零改动。 |
|
||||
| T-08-09-02 | Tampering | 伪绿(`Object.create`/`as never` 伪造 legacy) | high | mitigate | tileLegacy 只允许退役或重定向,禁止伪造;`<fails_when>` 捕获运行期错误。 |
|
||||
| T-08-09-03 | Repudiation | 删用例/放宽断言 | high | mitigate | 不删 `it`(除授权退役)、不新增 skip;期望值改写须授权并登记。 |
|
||||
| T-08-09-04 | Tampering | 改性能参数/计时逻辑 | medium | mitigate | perf 只改装配形状。 |
|
||||
| T-08-09-05 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;声明文件有用户改动则 STOP(D-08)。 |
|
||||
| T-08-09-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm exec vitest run packages-user/data-state/__test__` 0 失败。
|
||||
- `pnpm test:perf` 采集 6、0 失败。
|
||||
- eslint 对声明文件 0 报错。
|
||||
- 非测试源码零改动;skipped 计数恰为 1。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`(Q1 tileLegacy、Q2 loadStarter 一致)。
|
||||
- [ ] data-state 集成层 8 test + 3 perf + 夹具 + helper 对齐完成、聚焦 0 失败。
|
||||
- [ ] 零生产改动、零新增 skip;夹具根因修复后 dataClosure/nodeTracer 转绿。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-09-SUMMARY.md` when done(记录 Q1 处置、夹具改动、期望值改写台账、零改动文件说明)。
|
||||
</output>
|
||||
209
.planning/phases/08-test-refactor-alignment/08-10-PLAN.md
Normal file
209
.planning/phases/08-test-refactor-alignment/08-10-PLAN.md
Normal file
@ -0,0 +1,209 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 10
|
||||
type: execute
|
||||
wave: 4
|
||||
depends_on:
|
||||
- 08-02
|
||||
- 08-03
|
||||
- 08-04
|
||||
- 08-05
|
||||
- 08-06
|
||||
- 08-07
|
||||
- 08-08
|
||||
- 08-09
|
||||
files_modified:
|
||||
- packages-user/data-common/src/replay/__test__/array.test.ts
|
||||
- packages-user/data-common/src/replay/__test__/sandbox.test.ts
|
||||
- packages-user/data-common/src/store/__test__/tileStore.test.ts
|
||||
- packages-user/data-common/src/store/__test__/eventStore.test.ts
|
||||
- packages-user/data-base/src/enemy/__test__/enemy.test.ts
|
||||
- packages-user/data-base/src/map/__test__/mover.test.ts
|
||||
- packages-user/data-base/src/hero/__test__/items.test.ts
|
||||
- packages-user/data-system/src/event/__test__/eventDispatch.test.ts
|
||||
- packages-user/data-system/src/path/__test__/graph.test.ts
|
||||
- packages-user/data-system/src/path/__test__/system.test.ts
|
||||
- packages-user/data-state/src/event/__test__/event.test.ts
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 75000
|
||||
raw_tokens: 75000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**只加测试、零生产改动**:本计划不改任何生产源码;若为触发某码而需要生产改动,按 D-10 退出并汇报。沿用 Phase 6 gap-fill 的 `logger.catch(fn)` 断言机制(`packages/common/src/logger.ts`)。"
|
||||
- "**21 个缺口码全覆盖**(当前发出、06-COVERAGE-MAP 未登记):70、72、73、179、194、181、133、134、170(data-common);192、193(data-base);171、172、173、182、183(data-system);66、67、68、69、1001(data-state)。每个可达码新增一个**通过**的触发断言;不可达码按 D-04 用带注释的 `it.skip`(当前唯一允许的不可达码是 147,本计划不新增不可达码,除非执行期实测确认)。"
|
||||
- "**7 个陈旧登记码处置记录**:62/63/64/84/130/125/158/175 若在 08-02/08-05 Task 0 已裁定为契约变更,则本计划**不补测**,只在 SUMMARY 逐条登记「码 → 归属 → 处置(取消/迁移到 72 等)」;不得为旧码补测或用生产改动复活。"
|
||||
- "**公共接口覆盖缺口**:`data-state/src/loader/**` 子系统的公开面(`MotaDataLoader`/`DefaultDataLoaderHook`/`PrefixedJSONCProcessor`)当前无独立测试(RESEARCH §10.4 ❌)——经 Task 0 裁定是否新建 loader 测试文件;若新建,文件路径与名称须用户先批准。"
|
||||
- "**测试注释规范**:每个**新增** `it` 前一行中文注释(`dev.md:86`);不改任何既有 jsDoc;不新增 `it.skip` 以外的 skip;仓库 skipped 计数仍为 1(除非实测新增不可达码并经用户确认)。"
|
||||
- "**聚焦门禁**:每批新增用例后,对应文件与所属包聚焦运行 0 失败;`pnpm test:ci` 全绿(除征得同意的不可达 skip)。"
|
||||
artifacts:
|
||||
- path: packages-user/data-common/src/replay/__test__/sandbox.test.ts
|
||||
provides: "码 72(执行/finalize 失败)、73(非法 getPassive)、194(主动步后被动步)触发断言。"
|
||||
- path: packages-user/data-common/src/replay/__test__/array.test.ts
|
||||
provides: "码 70(未知 param type)、179(越界 index)触发断言。"
|
||||
- path: packages-user/data-common/src/store/__test__/tileStore.test.ts
|
||||
provides: "码 133/134(重复 num/id)触发断言。"
|
||||
- path: packages-user/data-common/src/store/__test__/eventStore.test.ts
|
||||
provides: "码 170(事件 id 重复注册)触发断言。"
|
||||
- path: packages-user/data-base/src/map/__test__/mover.test.ts
|
||||
provides: "码 192(faceManager 缺 Dir8 handler)触发断言。"
|
||||
- path: packages-user/data-base/src/hero/__test__/items.test.ts
|
||||
provides: "码 193(loadState 缺 item id 注册)触发断言。"
|
||||
- path: packages-user/data-system/src/event/__test__/eventDispatch.test.ts
|
||||
provides: "码 171(事件 id 不在 store)、172(事件返回非布尔)触发断言。"
|
||||
- path: packages-user/data-system/src/path/__test__/graph.test.ts
|
||||
provides: "码 173(图构建缺绑定)、183(起始点越界)触发断言。"
|
||||
- path: packages-user/data-system/src/path/__test__/system.test.ts
|
||||
provides: "码 182(useMapLayer state 不一致)触发断言。"
|
||||
- path: packages-user/data-state/src/event/__test__/event.test.ts
|
||||
provides: "码 1001(setBlock 未知图块)触发断言。"
|
||||
- path: packages-user/data-state/src/loader/__test__/loader.test.ts
|
||||
provides: "(条件)码 66/67/68/69 与 loader 公共面覆盖;仅当 Task 0 批准新建。"
|
||||
key_links:
|
||||
- "`logger.catch(fn)` 返回 `{ ret, info }` <-> 缺口码断言机制(Phase 6 既有)。"
|
||||
- "`packages/common/src/logger.json` 为码文案权威 <-> 断言只校验 code,不硬编码文案。"
|
||||
- "码 181 在 `itemStore.ts:13` 与 `enemyStore.ts:13` 两处发出 <-> 需在能触达 store 重复注册的层(data-common store 或上层 enemy/item 测试)覆盖。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
按 §9.1 的 21 个缺口错误码(当前发出、覆盖表未登记)与 §10.4 的 loader 公共接口缺口,补测数据端覆盖:每个可达码新增一个通过的 `logger.catch` 触发断言,并覆盖 loader 子系统的公开面。记录 §9.2 的 7 个陈旧登记码的处置(不补测,逐条登记)。
|
||||
|
||||
Purpose: 对应 D-07「覆盖侧单列计划」——先在 08-02..08-09 收敛接口面,再做码/公共接口覆盖盘点与补测,避免在失败基线上补测。
|
||||
|
||||
Output: 若干既有测试文件的**新增用例**(可能含 1 个经批准新建的 loader 测试文件);零生产改动、零新增依赖;覆盖矩阵与陈旧码处置记录(08-10-SUMMARY)。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/phases/06-unit-tests/06-COVERAGE-MAP.md
|
||||
@packages/common/src/logger.json
|
||||
@.planning/codebase/TESTING.md
|
||||
@.planning/codebase/CONVENTIONS.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: 覆盖补测裁决关卡 —— 21 码清单确认、陈旧码记录、loader 新文件命名</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- .planning/phases/08-test-refactor-alignment/08-RESEARCH.md(§9.1 缺口 21 码、§9.2 陈旧 7 码、§10.4 loader ❌)
|
||||
- .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
|
||||
- packages/common/src/logger.json(相关码文案)
|
||||
- 各 emit 点:data-common/src/{replay/array.ts,replay/sandbox.ts,store/tileStore.ts,store/eventStore.ts,store/itemStore.ts,store/enemyStore.ts}
|
||||
- data-base/src/{map/mover.ts,hero/items.ts}
|
||||
- data-system/src/{event/executor.ts,path/graph.ts,path/finder.ts,path/system.ts}
|
||||
- data-state/src/{loader/jsoncProcessor.ts,loader/loader.ts,loader/hook.ts,event/map.ts}
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报本计划要解决的问题(21 个已发出但未覆盖的码 + loader 子系统公共面无独立覆盖)与方案,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1**:确认 §9.1 的 21 码清单为本阶段补测范围;逐码确认归属测试文件与触达方式(尤其 181 在 `itemStore`/`enemyStore` 两处、173 的所有权)。
|
||||
- **Q2**:§9.2 的 7 个陈旧码(62/63/64/84/130/125/158/175)是否全部按「契约变更」记录、不补测;与 08-02/08-05 Task 0 的裁定保持一致。
|
||||
- **Q3**:是否新建 loader 测试文件(路径 `data-state/src/loader/__test__/loader.test.ts`?文件名?);**任何新文件路径与文件名必须用户先批准**(AGENTS.md 命名规则)。若不新建,66/67/68/69 归何处。
|
||||
- **Q4**:新增用例是否引入任何新的测试内标识符命名(须先批准)。
|
||||
</decision>
|
||||
<context>
|
||||
D-03 以 `logger.json` 为准;D-04 不可达码用 `it.skip`;D-07 覆盖清单列;D-10 零生产改动。Phase 6 的 `logger.catch` 断言与 inline fixture 模式可复用。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: data-common + data-base 缺口码补测</name>
|
||||
<files>packages-user/data-common/src/{replay/__test__/array.test.ts,replay/__test__/sandbox.test.ts,store/__test__/tileStore.test.ts,store/__test__/eventStore.test.ts}, packages-user/data-base/src/{enemy/__test__/enemy.test.ts,map/__test__/mover.test.ts,hero/__test__/items.test.ts}</files>
|
||||
<action>
|
||||
为码 70/72/73/179/194/181/133/134/170(data-common)与 192/193(data-base)新增通过的 `logger.catch` 触发断言。码 181 按 Q1 决定落点(`itemStore`/`enemyStore` 重复注册)。每个新增 `it` 前一行中文注释。不修改既有用例语义、不改生产源码。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-common/src/replay/__test__ packages-user/data-common/src/store/__test__ packages-user/data-base/src/enemy/__test__ packages-user/data-base/src/map/__test__/mover.test.ts packages-user/data-base/src/hero/__test__/items.test.ts</automated>
|
||||
<fails_when>聚焦运行出现非零 `failed`(新增断言本身失败,或 `logger.catch` 未捕获到目标码)。</fails_when>
|
||||
</verify>
|
||||
<done>data-common 9 码 + data-base 2 码有通过断言;聚焦 0 失败。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: data-system + data-state 缺口码补测(含 loader 子系统)</name>
|
||||
<files>packages-user/data-system/src/{event/__test__/eventDispatch.test.ts,path/__test__/graph.test.ts,path/__test__/system.test.ts}, packages-user/data-state/src/{event/__test__/event.test.ts,loader/__test__/loader.test.ts(条件)}</files>
|
||||
<action>
|
||||
为码 171/172/173/182/183(data-system)与 1001(data-state event)新增通过断言;码 66/67/68/69(loader)按 Q3 落点覆盖(新建 loader 测试文件或并入既有文件),并一并覆盖 loader 公共面。每个新增 `it` 前一行中文注释。不改生产源码。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm exec vitest run packages-user/data-system/src/event/__test__ packages-user/data-system/src/path/__test__ packages-user/data-state/src/event/__test__ packages-user/data-state/src/loader/__test__</automated>
|
||||
<fails_when>聚焦运行出现非零 `failed`,或 loader 测试文件不存在/未被采集(当 Q3 批准新建时)。</fails_when>
|
||||
</verify>
|
||||
<done>data-system 5 码 + data-state 1001(+ loader 66/67/68/69 按裁决)有通过断言;聚焦 0 失败。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: 覆盖矩阵 + 陈旧码登记 + 提交前门禁</name>
|
||||
<files>(08-10-SUMMARY.md 记录;不改其它文件)</files>
|
||||
<action>
|
||||
汇总本计划的码→模块→用例矩阵;逐条登记 §9.2 陈旧码处置(与 08-02/08-05 裁定一致);记录 loader 覆盖结论。随后跑 `pnpm test:ci` 确认全绿(仅保留经同意的不可达 skip),并 eslint。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm test:ci; pnpm exec eslint packages-user/data-common/src packages-user/data-base/src packages-user/data-system/src packages-user/data-state/src</automated>
|
||||
<fails_when>test:ci 汇总出现非零 `failed`,或 skipped 数偏离约定,或 eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>21 缺口码(可达)全部有通过断言;陈旧码逐条登记;test:ci 全绿;eslint 通过。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 补测 -> 生产契约 | 补测不得反向要求生产改动。 |
|
||||
| 覆盖矩阵 -> 真实覆盖 | 「有测试」不等于「覆盖了该码」。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-10-01 | Repudiation | 用弱断言或空断言凑覆盖 | high | mitigate | 每个码以 `logger.catch` 捕获其 code 并断言 `toContain(code)`;聚焦运行证明真实触发。 |
|
||||
| T-08-10-02 | Tampering | 为触发旧码改生产 | high | mitigate | 陈旧码明确不补测;生产改动须 D-10 用户确认。 |
|
||||
| T-08-10-03 | Tampering | 未获批新建文件/命名 | medium | mitigate | loader 新文件路径/名与任何新标识符须 Task 0 批准。 |
|
||||
| T-08-10-04 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;新增/修改文件若有用户改动则 STOP(D-08)。 |
|
||||
| T-08-10-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 21 个缺口码(可达者)各有通过断言;不可达者按 D-04 处置并记录。
|
||||
- 7 个陈旧码逐条登记、无补测、无生产复活。
|
||||
- `pnpm test:ci` 全绿;skipped 计数符合约定;eslint 通过。
|
||||
- 零生产改动。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`(Q1 清单、Q2 陈旧码、Q3 loader 文件批准)。
|
||||
- [ ] §9.1 21 码补齐;loader 公共面按裁决覆盖。
|
||||
- [ ] 覆盖矩阵与陈旧码处置登记完成。
|
||||
- [ ] 零生产改动、零新增依赖。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-10-SUMMARY.md` when done(含码→模块→用例矩阵、陈旧码处置表、loader 覆盖结论)。
|
||||
</output>
|
||||
149
.planning/phases/08-test-refactor-alignment/08-11-PLAN.md
Normal file
149
.planning/phases/08-test-refactor-alignment/08-11-PLAN.md
Normal file
@ -0,0 +1,149 @@
|
||||
---
|
||||
phase: 08-test-refactor-alignment
|
||||
plan: 11
|
||||
type: execute
|
||||
wave: 5
|
||||
depends_on:
|
||||
- 08-10
|
||||
files_modified: []
|
||||
autonomous: false
|
||||
gap_closure: false
|
||||
requirements:
|
||||
- TEST-02
|
||||
estimate:
|
||||
tokens: 40000
|
||||
raw_tokens: 40000
|
||||
tasks: 2
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "**`pnpm test:ci` 全绿**:`Test Files` 无非零 `failed`、`Tests` 汇总无非零 `failed`,且采集文件总数为 **66**(数据端 65 + `script/check-data-circular.test.ts`)。"
|
||||
- "**`pnpm test:perf` 全绿**:采集文件总数 **6**,无非零 `failed`。"
|
||||
- "**跳过数恰为 1**:仓库 skipped 计数恰为 **1**,且唯一跳过项是 `packages-user/data-base/src/hero/__test__/equipment.test.ts` 的码 147 用例(不可达,D-04)。多于 1 视为引入了未授权 skip;少于 1 需说明 147 用例的去向并经用户确认。"
|
||||
- "**质量门禁**:`pnpm exec eslint` 对全部本次改动的测试文件 0 报错;`pnpm exec prettier --check`(或等效)对本次改动文件无格式差异(CRLF)。"
|
||||
- "**零生产改动终审**:本阶段(08-01..08-11)的提交区间内,`packages-user/data-*/src/**` 与 `packages/common/src/**` 的**非测试文件**零改动(除非某处经用户明确确认为 D-10 例外并逐条登记)。"
|
||||
- "**摘要完整**:产出阶段 SUMMARY,逐条记录:文件数守恒证据、逐子系统接口 delta 的对齐结果、21 缺口码覆盖、陈旧码处置、任何 `it.skip`/用例增删/期望值改写、D-10 例外(如有)、以及「未解决/需后续处理」清单。"
|
||||
artifacts:
|
||||
- path: .planning/phases/08-test-refactor-alignment/08-11-SUMMARY.md
|
||||
provides: "本阶段的收口摘要(全绿证据 + 逐项台账 + 未决清单)。"
|
||||
key_links:
|
||||
- "`pnpm test:ci` 的全绿 <-> TEST-02 的验收标准「`pnpm test:ci` 与 `pnpm test:perf` 全绿(唯一不可达码 147 的 `it.skip` 保留)」。"
|
||||
- "08-01 的 Source Coverage Audit(GOAL/REQ/RESEARCH/CONTEXT 四源) <-> 本计划逐项复核是否全部 COVERED、无遗漏。"
|
||||
---
|
||||
|
||||
<objective>
|
||||
收口 Phase 8:在 08-01..08-10 全部完成后,跑通 `pnpm test:ci` 与 `pnpm test:perf` 全绿,执行 eslint/prettier 质量门禁,确认 `it.skip` 计数恰为 1(码 147),终审零生产改动,并产出阶段 SUMMARY。对应 TEST-02 的最终验收。
|
||||
|
||||
Purpose: 把前十个计划的成果收敛为一个可验证的完成状态,并留下完整台账以满足「全绿 = 所有测试通过 + 仅保留不可达码 147」的验收定义(D-04)。
|
||||
|
||||
Output: 阶段 SUMMARY(08-11-SUMMARY.md);本计划默认零文件改动(若收口时发现测试面残留失败,按 test-only 修复并在 SUMMARY 登记;若需生产改动则停在 Task 0 汇报)。
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
|
||||
@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-01-PLAN.md
|
||||
@.planning/phases/08-test-refactor-alignment/08-10-PLAN.md
|
||||
@AGENTS.md
|
||||
@dev.md
|
||||
|
||||
**执行起点提示**:本计划尚未裁决(Task 0 的 `<record>` 为空)。执行者必须先在 Task 0 停下汇报并等待「可以执行」。
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="checkpoint:decision" gate="blocking-human">
|
||||
<name>Task 0: 收口裁决关卡 —— 全绿口径与残留失败的处置边界</name>
|
||||
<files>(只读汇报,不修改任何文件)</files>
|
||||
<read_first>
|
||||
- .planning/phases/08-test-refactor-alignment/08-CONTEXT.md(D-04 验收定义)
|
||||
- .planning/phases/08-test-refactor-alignment/08-01-PLAN.md(Source Coverage Audit)
|
||||
- 各 08-*-SUMMARY.md(08-01..08-10 的执行结果)
|
||||
</read_first>
|
||||
<decision>
|
||||
汇报收口口径与当前残留状态,等待「可以执行」后写入 `<record>`:
|
||||
|
||||
- **Q1**:确认验收口径 = `test:ci`(66 文件)+ `test:perf`(6 文件)全绿、skipped 恰为 1(147)、eslint/prettier 通过。
|
||||
- **Q2**:若收口时仍存在测试面残留失败:允许在 test-only 范围内修复并登记;若某残留只有改生产才能转绿,是否按 D-10 开一个「重构遗漏」例外(需逐条确认),或记录为未决项、暂不阻塞收口。
|
||||
- **Q3**:确认本阶段 SUMMARY 需要包含的未决/后续事项清单(如 `setFloor(null)` 实现与接口不一致、loader 码归属、任何用户裁定为「另立计划」的项)。
|
||||
</decision>
|
||||
<context>
|
||||
D-04/D-10;07-VERIFICATION 的「快照会过期」纪律——收口以**当日重测**为准,不沿用任何历史数字。
|
||||
</context>
|
||||
<verify>
|
||||
<automated>Read
|
||||
</verify>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: 全量门禁 + 残留处置</name>
|
||||
<files>(默认零改动;仅当存在测试面残留失败时,改动对应 `__test__/` 文件)</files>
|
||||
<action>
|
||||
运行 `pnpm test:ci` 与 `pnpm test:perf`,记录采集文件数与通过/失败/skipped。若存在测试面残留失败,按 test-only 修复(每处改动须与失败根因对应,期望值改写须登记);不弱化断言、不新增 skip。随后对全部本次改动文件执行 eslint 与 prettier 检查。若某残留必须改生产才能转绿,停止并汇报(Q2)。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pnpm test:ci; pnpm test:perf; pnpm exec eslint packages-user/data-common/src packages-user/data-base/src packages-user/data-system/src packages-user/data-state/src</automated>
|
||||
<fails_when>任一命令非零退出,或 `test:ci` 采集数 ≠ 66、`test:perf` 采集数 ≠ 6、skipped 数 ≠ 1、汇总行出现非零 `failed`、eslint 报错。</fails_when>
|
||||
</verify>
|
||||
<done>`test:ci` 66 文件全绿、`test:perf` 6 文件全绿、skipped 恰为 1(147)、eslint 通过。</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: 阶段 SUMMARY</name>
|
||||
<files>.planning/phases/08-test-refactor-alignment/08-11-SUMMARY.md</files>
|
||||
<action>
|
||||
产出阶段 SUMMARY,至少包含:全绿证据(test:ci/test:perf 汇总行、skipped=1 与 147 用例定位)、Source Coverage Audit 的四源逐项 COVERED 复核、逐子系统对齐结果(08-02..08-09)、21 缺口码覆盖矩阵与 7 陈旧码处置(08-10)、任何 `it.skip`/用例增删/期望值改写台账、D-10 例外(如有)、零生产改动终审证据(受限 diff)、以及未决/后续事项清单。不得修改任何既有 jsDoc。
|
||||
</action>
|
||||
<verify>
|
||||
<automated>Test-Path .planning/phases/08-test-refactor-alignment/08-11-SUMMARY.md</automated>
|
||||
<fails_when>SUMMARY 文件不存在,或缺少上述任一必录项。</fails_when>
|
||||
</verify>
|
||||
<done>阶段 SUMMARY 完成,TEST-02 验收证据齐备。</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| 收口 -> 验收真实性 | 「全绿」可能被 skip/弱断言伪造。 |
|
||||
| 执行者 -> git | 终审提交范围。 |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-08-11-01 | Repudiation | 以新增 skip/弱断言达成「全绿」 | high | mitigate | skipped 恰为 1 且定位到 147;用例增删/期望值改写逐条登记;eslint/prettier 门禁。 |
|
||||
| T-08-11-02 | Tampering | 借收口改生产 | high | mitigate | 默认零改动;生产改动须 D-10 用户确认并登记。 |
|
||||
| T-08-11-03 | Tampering | 提交用户并发改动 | high | mitigate | `git add <显式路径>`;禁止 `git add -A`;终审 `git status --short` 白名单核对(D-08)。 |
|
||||
| T-08-11-SC | Tampering | 包安装 | high | mitigate | 不安装任何包。 |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `pnpm test:ci` 66 文件全绿;`pnpm test:perf` 6 文件全绿;skipped = 1(147)。
|
||||
- eslint/prettier 通过。
|
||||
- 零生产改动终审(受限 diff)。
|
||||
- 08-11-SUMMARY.md 存在且含全部必录项。
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Task 0 获「可以执行」并写入 `<record>`。
|
||||
- [ ] `test:ci` + `test:perf` 全绿、skipped 恰为 1。
|
||||
- [ ] SUMMARY 产出、四源覆盖复核完成。
|
||||
- [ ] TEST-02 验收达成。
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/08-test-refactor-alignment/08-11-SUMMARY.md` when done。
|
||||
</output>
|
||||
136
.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
Normal file
136
.planning/phases/08-test-refactor-alignment/08-CONTEXT.md
Normal file
@ -0,0 +1,136 @@
|
||||
# Phase 8: 测试重构与接口对齐 - Context
|
||||
|
||||
**Gathered:** 2026-10-04
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
将数据端(`packages-user/data-{common,base,system,state}`)的全部单元测试(`*.test.ts` / `*.perf.ts`)迁移到各源码目录下的 `__test__/`,并按数据端「系统性收尾」后的当前接口重对齐、修复重构遗漏导致的失效;以 `logger.json` 为准补齐**数据端错误码**与**公共接口**覆盖。验收 = `pnpm test:ci` 与 `pnpm test:perf` 全绿(既有不可达码的 `it.skip` 保留)。
|
||||
|
||||
**范围**
|
||||
|
||||
- 纳入:`packages-user/data-common`、`data-base`、`data-system`、`data-state` 的全部测试(65 `.test.ts` + 6 `.perf.ts`)。
|
||||
- 排除:`script/check-data-circular.test.ts`(脚本,暂不纳入);渲染端 `@user/client-*`;legacy。
|
||||
|
||||
**迁移目标**
|
||||
|
||||
- 同目录测试 → 同目录 `__test__/`(例:`src/hero/__test__/`)。
|
||||
- 集成测试目录 `data-state/test/` → `data-state/__test__/`(`fixtures/` 随迁)。
|
||||
|
||||
**基线(2026-10-04 侦察,HEAD `109fad3`,分支 `refine/data-client`)**
|
||||
|
||||
- `pnpm test:ci`:66 文件 / 45 failed, 21 passed;用例 339 failed / 367 passed / 1 skipped;6 unhandled rejection;~186s。
|
||||
- 唯一 skip:`data-base/src/hero/equipment.test.ts:353`(code 147,不可达,维持)。
|
||||
- 失败族:A 夹具引用已删/改名导出;B `CoreState` 加载配置形状(`loadStarter`);C 录像桩缺 `replay.array`;D Hook/控制器接口变化(`addHook(...).load`);E 测试引用已移动/删除模块;F 公共接口改名/签名;G 断言随语义漂移。
|
||||
- 配置:`vite.config.ts` 无 `test.include`(用默认 glob)、`vitest.perf.config.ts` include `**/*.perf.ts`、`tsconfig.json` include `packages-user/**/*.ts` → 迁移**无需改配置**。
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### 范围与口径
|
||||
|
||||
- **D-01:** 范围 = 四包 `packages-user/data-{common,base,system,state}` 全部单测;`script/` 暂不纳入。
|
||||
- **D-02:** 迁移到同目录 `__test__/`;`data-state/test/` → `data-state/__test__/`(`fixtures/` 随迁)。
|
||||
- **D-03:** 错误码覆盖以 `packages/common/src/logger.json` 为准。
|
||||
- **D-04:** 「全绿」= 所有测试通过;既有表示**不可达错误码**的 `it.skip` 保留(当前仅 code 147 一条)。
|
||||
- **D-05:** 接口设计不再变更;本阶段只做「对齐」(接口语义变化 + 接口设计变化),不新增接口。
|
||||
|
||||
### 计划组织
|
||||
|
||||
- **D-06:** **迁移方式 (a)**:先出独立「目录迁移」计划(全量移动 + 修相对导入,测试仍红但位置正确、可独立验证),后续按子系统对齐。
|
||||
- **D-07:** **覆盖侧单列计划**:先盘点数据端错误码(从 `packages-user/data-*` 的 `logger.error/warn` 调用点反推)与公共接口清单及现有覆盖缺口,再补测。
|
||||
|
||||
### 并发与执行纪律(用户 2026-10-04)
|
||||
|
||||
- **D-08:** 用户并发进行渲染端收尾,可能触及数据端内容,但**不改接口设计、不影响测试**;AI **不得提交用户改动的文件**;若 AI 正在进行的行动与用户改动冲突,**先暂停并向用户汇报**。
|
||||
- **D-09:** 每个计划执行前按项目规则设 **Task 0 汇报关卡**(`autonomous: false`),用户确认后方可执行。
|
||||
- **D-10:** 测试面零生产改动;仅当某失效确由数据端重构遗漏导致、且用户确认后,才可做最小生产修复(否则退出并汇报)。
|
||||
|
||||
### the agent's Discretion
|
||||
|
||||
- 迁移计划的具体移动方式(脚本/逐文件)、对齐计划的子系统切分与顺序、覆盖补测的范围与用例设计,由实现者在上述约束下决定;发现新的接口/设计疑问立即提问,不自行假设。
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### 项目与阶段约束
|
||||
|
||||
- `.planning/PROJECT.md` — 数据/渲染分离、接口设计由用户主导
|
||||
- `.planning/REQUIREMENTS.md` — `TEST-02`
|
||||
- `.planning/ROADMAP.md` — Phase 8 goal、成功标准
|
||||
- `.planning/STATE.md` — 既有决策、门禁、仓库状态
|
||||
- `dev.md` — 四层数据架构、依赖方向、注释与代码规范(CRLF、无副作用、无循环引用)
|
||||
- `AGENTS.md` — 审批与执行纪律
|
||||
|
||||
### 输入
|
||||
|
||||
- `.planning/phases/07-data-fixes/07-VERIFICATION.md` — `### Post-Refactor Test Breakage`(2026-09-17 旧快照,须重测后使用)
|
||||
- `.planning/phases/06-unit-tests/06-COVERAGE-MAP.md` — `code → 模块 → 用例` 映射
|
||||
- `packages/common/src/logger.json` — 错误码权威码表
|
||||
|
||||
### 受影响源码与测试
|
||||
|
||||
- `packages-user/data-common/src/{common,replay,store}/`
|
||||
- `packages-user/data-base/src/{enemy,flag,hero,map}/`
|
||||
- `packages-user/data-system/src/{combat,event,path}/`
|
||||
- `packages-user/data-state/src/`(`coreEventLayer`、`enemy/`、`event/`、`replay/`)与 `packages-user/data-state/test/`
|
||||
|
||||
### 配置与工具
|
||||
|
||||
- `vite.config.ts`、`vitest.perf.config.ts`、`tsconfig.json`
|
||||
- `.planning/codebase/TESTING.md`、`.planning/codebase/CONVENTIONS.md`
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
|
||||
- Phase 6 已建立的测试夹具与断言模式(inline fixture、`vi.hoisted` stub、dynamic import harness)
|
||||
- `logger.catch(fn)` 断言警告码机制(`packages/common/src/logger.ts`)
|
||||
|
||||
### Established Patterns
|
||||
|
||||
- 依赖方向 `data-common → data-base → data-system → data-state`;数据端 DOM-free、Node 可跑
|
||||
- 错误经 `logger.error/warn(code)` 上报,码唯一、不复用
|
||||
- Phase 6/7 的文件级门禁:`eslint` + `vue-tsc` 过滤 + `pnpm test:ci`
|
||||
|
||||
### Integration Points
|
||||
|
||||
- `data-state/src/core.ts` `createCoreState` / loader 配置形状
|
||||
- Hook 控制器(`addHook(...)` 返回对象)接口变化
|
||||
- 录像桩 `replay.array`
|
||||
- `setFloor(IGameMap)`、path finder/builder 注入面
|
||||
|
||||
</code_context>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- 迁移与对齐分离(D-06),迁移计划须验证「采集文件数与迁移前一致」且 `test:ci`/`test:perf` 仍可发现文件。
|
||||
- 覆盖盘点方法:从源码 `logger.error/warn` 调用点反推数据端码清单,与测试逐码对照。
|
||||
- 用户明确「问题修复不会很复杂,顶多是某些内容重构时有细节没有注意到」。
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
- `script/check-data-circular.test.ts`。
|
||||
- 渲染端 / legacy 测试(后续阶段)。
|
||||
- `pnpm check:type` 全仓(既有渲染端诊断不在本阶段范围)。
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 8-测试重构与接口对齐*
|
||||
*Context gathered: 2026-10-04*
|
||||
325
.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
Normal file
325
.planning/phases/08-test-refactor-alignment/08-PATTERNS.md
Normal file
@ -0,0 +1,325 @@
|
||||
# Phase 8: 测试重构与接口对齐 - Pattern Map
|
||||
|
||||
**Mapped:** 2026-10-04
|
||||
**Scope:** 71 个测试文件(65 `*.test.ts` + 6 `*.perf.ts`)+ 3 个随迁非测试文件(`replayVerifier.ts`、`fixtures/closed-loop.ts`、`fixtures/floors.json`)
|
||||
**Analogs found:** 迁移布局 = 无先例(greenfield);夹具/断言模式 = 全部有现存 analog
|
||||
|
||||
---
|
||||
|
||||
## 0. Planner TL;DR
|
||||
|
||||
1. **全仓不存在任何 `__test__/` 目录**(`git ls-files` + glob 均为 0)。目标布局无历史先例,最接近的 analog 是「源码同目录测试」现状与唯一聚合目录 `data-state/test/`。迁移本身应视为**纯文件系统 + 导入重写**,不引入新测试风格;风格一律沿用现有测试。
|
||||
2. **导入重写有两条不同规则**,不可用「所有 `../` +1」一刀切:
|
||||
- **规则 A(+1 层)**:`data-{common,base,system}/src/**/<sys>/*.{test,perf}.ts` → 同目录 `__test__/`;以及 `data-state/src/**/*.test.ts` → 同目录 `__test__/`。所有相对 specifier 多一层。
|
||||
- **规则 B(层数不变)**:`data-state/test/**` → `data-state/__test__/**`(`test/` 与 `__test__/` 同为 `data-state/` 直接子目录,深度相同)。相对 specifier **原样保留**。
|
||||
3. **唯一外部测试路径引用**:`script/test-data-node.ts:67,122` 硬编码 `data-state/test/{replayVerifier.ts,fixtures/closed-loop.ts}`,`pnpm test:data-node` 依赖它 → 迁移时必须同步改;这是脚本非生产文件,但按 AGENTS.md 仍需用户确认(建议在迁移计划 Task 0 一并汇报)。
|
||||
4. **无配置需改**:`vite.config.ts` 无 `test.include`(默认 glob 命中 `__test__/`)、`vitest.perf.config.ts` 的 `**/*.perf.ts` 深度无关、`tsconfig.json` `packages-user/**/*.ts` 深度无关、`eslint.config.js` 无测试路径 glob。
|
||||
5. 每个 `it` 前必须有**一行中文单行注释**(`dev.md:86`);迁移只改路径与 aligned 断言,不得丢注释。
|
||||
|
||||
---
|
||||
|
||||
## File Classification(按目标 `__test__/` 目录分组)
|
||||
|
||||
> Role 均为 test;Data Flow 用 `unit` / `integration` / `perf` / `fixture` / `helper` 标注。所有路径均为 git-tracked。
|
||||
|
||||
| # | 目标目录 | 文件(basename) | 数量 | Data Flow | 最接近 Analog |
|
||||
|---|----------|------------------|------|-----------|----------------|
|
||||
| 1 | `data-common/src/common/__test__/` | face, faceManager, indexer, mover, utils | 5 unit | unit | 各自现位于同目录(`packages-user/data-common/src/common/*.test.ts`) |
|
||||
| 2 | `data-common/src/replay/__test__/` | array, func, sandbox, saveLoad, system | 5 unit | unit | `packages-user/data-common/src/replay/sandbox.test.ts` |
|
||||
| 3 | `data-common/src/store/__test__/` | eventStore, tileStore | 2 unit | unit | `packages-user/data-common/src/store/tileStore.test.ts` |
|
||||
| 4 | `data-base/src/enemy/__test__/` | enemy, manager, saveLoad, special | 4 unit | unit | `packages-user/data-base/src/enemy/manager.test.ts` |
|
||||
| 5 | `data-base/src/flag/__test__/` | saveLoad, system | 2 unit | unit | `packages-user/data-base/src/flag/system.test.ts` |
|
||||
| 6 | `data-base/src/hero/__test__/` | attribute, equipStore, equipment, follower, items, location, modifier, mover, rendering, saveLoad, state, attribute.perf | 11 unit + 1 perf | unit/perf | `packages-user/data-base/src/hero/follower.test.ts`、`equipment.test.ts` |
|
||||
| 7 | `data-base/src/map/__test__/` | dynamicTile, eventPath, eventView, gameMap, mapLayer, mapLifecycle, mapState, mover, saveLoad, staticTile, tile | 11 unit | unit | `packages-user/data-base/src/map/mapLayer.test.ts`、`mapState.test.ts` |
|
||||
| 8 | `data-system/src/combat/__test__/` | combat, context, damage, mapDamage, context.perf, damage.perf | 4 unit + 2 perf | unit/perf | `packages-user/data-system/src/combat/combat.test.ts` |
|
||||
| 9 | `data-system/src/event/__test__/` | eventDispatch | 1 unit | unit | 自身 |
|
||||
| 10 | `data-system/src/path/__test__/` | graph, performance, system | 3 unit | unit | `packages-user/data-system/src/path/graph.test.ts` |
|
||||
| 11 | `data-state/src/__test__/` | coreEventLayer | 1 unit | unit | `packages-user/data-state/src/coreEventLayer.test.ts`(**去留待裁决**,见 No Analog / RESEARCH OQ4) |
|
||||
| 12 | `data-state/src/enemy/__test__/` | aura, calculator, comparer, final, mapDamage, special | 6 unit | unit | `packages-user/data-state/src/enemy/calculator.test.ts` |
|
||||
| 13 | `data-state/src/event/__test__/` | event | 1 unit | unit | `packages-user/data-state/src/event/event.test.ts` |
|
||||
| 14 | `data-state/src/replay/__test__/` | commands | 1 unit | unit | `packages-user/data-state/src/replay/commands.test.ts` |
|
||||
| 15 | `data-state/__test__/` | coreNode, dataClosure, enemyCombination, nodeReplay, nodeTracer, replayPlayback, saveablesRoundTrip, tileLegacy, mapScenario.perf, saveables.perf, saveablesReal.perf, **replayVerifier.ts**, **fixtures/closed-loop.ts**, **fixtures/floors.json** | 8 unit + 3 perf + 2 helper + 1 fixture | unit/integration/perf/helper | `packages-user/data-state/test/nodeReplay.test.ts`、`test/fixtures/closed-loop.ts` |
|
||||
|
||||
**合计核对:** 逐目录求和 5+5+2+4+2+11+11+4+1+3+1+6+1+1+8 = **65 个 `*.test.ts`**;perf:目录 #6 的 1 + 目录 #8 的 2 + 目录 #15 的 3 = **6 个 `*.perf.ts`**;随迁非测试文件 3 个(`replayVerifier.ts` + `fixtures/closed-loop.ts` + `fixtures/floors.json`)。
|
||||
|
||||
---
|
||||
|
||||
## Pattern Assignments
|
||||
|
||||
### M1. 迁移导入重写 — 规则 A(+1 层)
|
||||
|
||||
**适用:** #1–#14(同目录测试下沉到 `__test__/`,目录深一层)。
|
||||
**规则:** 每个**相对** specifier 增加一层:`'./x'`→`'../x'`,`'../x'`→`'../../x'`,`'../../../pkg/src/x'`→`'../../../../pkg/src/x'`。**动态 `import()` 与 `typeof import()` 的字符串同样要改**;`'@user/*'`、`'@motajs/*'`、`'vitest'` 裸包 specifier **不变**。
|
||||
|
||||
**Analog(改写前 → 改写后,file:line):**
|
||||
|
||||
`packages-user/data-common/src/common/face.test.ts`(→ `common/__test__/face.test.ts`)
|
||||
```ts
|
||||
// before
|
||||
import { FaceDirection } from './types'; // :3
|
||||
interface TestModules { RoleFaceBinder: typeof import('./face').RoleFaceBinder; } // :11
|
||||
const faceModule = await import('./face'); // :20
|
||||
// after
|
||||
import { FaceDirection } from '../types';
|
||||
interface TestModules { RoleFaceBinder: typeof import('../face').RoleFaceBinder; }
|
||||
const faceModule = await import('../face');
|
||||
```
|
||||
|
||||
`packages-user/data-base/src/hero/follower.test.ts`(→ `hero/__test__/follower.test.ts`)
|
||||
```ts
|
||||
// before
|
||||
import { type IPassPredicate } from '../map'; // :13
|
||||
import { HeroFollowersController } from './follower'; // :14
|
||||
import { HeroLocation } from './location'; // :15
|
||||
// after
|
||||
import { type IPassPredicate } from '../../map';
|
||||
import { HeroFollowersController } from '../follower';
|
||||
import { HeroLocation } from '../location';
|
||||
```
|
||||
|
||||
`packages-user/data-state/src/replay/commands.test.ts`(→ `replay/__test__/commands.test.ts`,跨包相对路径)
|
||||
```ts
|
||||
// before
|
||||
import { createCoreState } from '../core'; // :15
|
||||
import { ReplaySystem } from '../../../data-common/src/replay/system'; // :16
|
||||
import { ... } from './commands'; // :23
|
||||
// after
|
||||
import { createCoreState } from '../../core';
|
||||
import { ReplaySystem } from '../../../../data-common/src/replay/system';
|
||||
import { ... } from '../commands';
|
||||
```
|
||||
|
||||
**完整 `./` 相对导入清单(规则 A 命中,供逐文件核对):** `data-common/src/common/{face,faceManager,indexer,mover,utils}.test.ts`、`data-common/src/store/tileStore.test.ts`、`data-common/src/replay/{array,func,sandbox,saveLoad,system}.test.ts`、`data-system/src/{event/eventDispatch.test.ts,path/{system,performance}.test.ts,combat/{combat,context,damage,mapDamage}.test.ts + context.perf.ts + damage.perf.ts}`、`data-base/src/**`(见 RESEARCH §8 各 anchor)。`data-base` 的 `../map`(仅 `follower.test.ts:13`、`mover.test.ts:11`)与 `data-system/eventDispatch.test.ts:10` 的 `../types` 是仅有的 `../` 命中。
|
||||
|
||||
### M2. 迁移导入重写 — 规则 B(层数不变)
|
||||
|
||||
**适用:** #15(`data-state/test/**` → `data-state/__test__/**`)。
|
||||
**依据:** `test/` 与 `__test__/` 同为 `packages-user/data-state/` 直接子目录,`../src/core` 在两侧都解析到 `data-state/src/core`,故**相对 specifier 全部原样**。
|
||||
|
||||
Analog `packages-user/data-state/test/coreNode.test.ts`:
|
||||
```ts
|
||||
import { createCoreState } from '../src/core'; // :3 → 迁移后不变
|
||||
```
|
||||
Analog `packages-user/data-state/test/nodeReplay.test.ts`:
|
||||
```ts
|
||||
import { ReplaySystem } from '../../data-common/src/replay/system'; // :3 → 不变
|
||||
import { ... } from './replayVerifier'; // :8 → 不变
|
||||
```
|
||||
Analog `packages-user/data-state/test/fixtures/closed-loop.ts`:
|
||||
```ts
|
||||
import { CoreState, createCoreState } from '../../src/core.ts'; // :23 → 不变(fixtures/ 与 __test__/fixtures/ 同深度)
|
||||
```
|
||||
`mapScenario.perf.ts:18` / `saveablesReal.perf.ts:14` 的 `'./fixtures/floors.json'` 同样不变。
|
||||
|
||||
> **陷阱:** 迁移执行器若对 `data-state` 一律套用「+1 层」会把规则 B 的文件改坏。建议迁移计划按下表分流:`data-state/test/**` → 不改 specifier;`data-state/src/**/*.test.ts` → +1。
|
||||
|
||||
### M3. 随迁的非测试文件(容易漏项)
|
||||
|
||||
| 文件 | 迁移 | 备注 |
|
||||
|------|------|------|
|
||||
| `data-state/test/replayVerifier.ts` | → `data-state/__test__/replayVerifier.ts` | 被 `nodeReplay.test.ts:8` 与 `script/test-data-node.ts:67` 引用;**不是** test 文件,不在 65 计数内 |
|
||||
| `data-state/test/fixtures/closed-loop.ts` | → `data-state/__test__/fixtures/closed-loop.ts` | `fixtures/` 随迁(D-02);被 `dataClosure.test.ts:17`、`nodeTracer.test.ts:2`、`script/test-data-node.ts:122` 引用 |
|
||||
| `data-state/test/fixtures/floors.json` | → `data-state/__test__/fixtures/floors.json` | 被 `mapScenario.perf.ts:18`、`saveablesReal.perf.ts:14` 以 JSON import 引用 |
|
||||
|
||||
---
|
||||
|
||||
## 夹具与断言模式(对齐计划复用)
|
||||
|
||||
### P1. `vi.hoisted` 全局桩(每个测试文件顶部)
|
||||
|
||||
**最小形式**(只补 `main`/`location` 全局)— analog `packages-user/data-common/src/replay/sandbox.test.ts:7-18`:
|
||||
```ts
|
||||
import { logger } from '@motajs/common';
|
||||
import { afterAll, afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { ReplaySystem } from './system';
|
||||
|
||||
vi.hoisted(() => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
});
|
||||
afterEach(() => { vi.restoreAllMocks(); });
|
||||
afterAll(() => { vi.unstubAllGlobals(); });
|
||||
```
|
||||
|
||||
**扩展形式**(额外 polyfill `Map.prototype.getOrInsert`/`getOrInsertComputed`)— analog `packages-user/data-base/src/hero/follower.test.ts:18-46`(同型见 `equipment.test.ts:21-49`、`mapState.test.ts:17-45`、`saveablesRoundTrip.test.ts:23-47`、`calculator.test.ts:17-41`)。**迁移原样带过去即可**。
|
||||
|
||||
### P2. 动态 `import()` harness + `typeof import()` 类型
|
||||
|
||||
**Analog** `packages-user/data-common/src/common/face.test.ts:10-26`:
|
||||
```ts
|
||||
interface TestModules {
|
||||
RoleFaceBinder: typeof import('./face').RoleFaceBinder;
|
||||
logger: typeof import('@motajs/common').logger;
|
||||
}
|
||||
let modules: TestModules;
|
||||
beforeAll(async () => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
const faceModule = await import('./face');
|
||||
const commonModule = await import('@motajs/common');
|
||||
modules = { RoleFaceBinder: faceModule.RoleFaceBinder, logger: commonModule.logger };
|
||||
});
|
||||
```
|
||||
同型:`packages-user/data-system/src/path/graph.test.ts:32-62`、`packages-user/data-state/src/enemy/calculator.test.ts:43-59`。**注意 `typeof import('./face')` 也须随规则 A 改路径。**
|
||||
|
||||
**`vi.mock` 变体**(模块级桩,迁移后 `vi.mock('./enemy')`/`vi.mock('./legacy')` 路径也要 +1)— analog `packages-user/data-state/src/coreEventLayer.test.ts:47-71`:
|
||||
```ts
|
||||
vi.mock('./enemy', () => ({ /* class stubs + registerSpecials: vi.fn() */ })); // :47
|
||||
vi.mock('./legacy', () => ({ ItemLegacyBridge: class {}, TileLegacyBridge: class {} })); // :59
|
||||
let modules: TestModules;
|
||||
beforeAll(async () => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
const coreModule = await import('./core'); // :69
|
||||
modules = { CoreState: coreModule.CoreState };
|
||||
});
|
||||
```
|
||||
|
||||
### P3. `logger.catch` 错误码断言(码覆盖主力)
|
||||
|
||||
**Analog** `packages-user/data-common/src/common/face.test.ts:71-82`:
|
||||
```ts
|
||||
// 验证绑定未知主图块时经 logger 观测错误码 43 且不建立绑定
|
||||
it('warns code 43 for an unknown main block', () => {
|
||||
const binder = createBinder();
|
||||
const result = modules.logger.catch(() => binder.bind(2, 99, FaceDirection.Up));
|
||||
expect(result.info.map(info => info.code)).toContain(43);
|
||||
expect(binder.getMainFace(2)).toBeNull();
|
||||
});
|
||||
```
|
||||
同型:`packages-user/data-base/src/map/mapState.test.ts:111-112`(`logger.catch(...)` + `toContain(121)`)、`mapLayer.test.ts:185-190`(码 80)。解构形式 `const { info } = logger.catch(...)` 见 `data-common/src/replay/system.test.ts:66`、`replay/saveLoad.test.ts:83`。**缺口码补测(RESEARCH §9.1 的 21 个)直接沿用此机制。**
|
||||
|
||||
### P4. 录像桩形状(C 族;**当前测试用 `route`,须改 `array`**)
|
||||
|
||||
生产写入面是 `replay.array.add(code, params)`(`equipment.ts:196,214` 等)。现有桩 analog 是**旧形状** `packages-user/data-base/src/hero/equipment.test.ts:63-99`:
|
||||
```ts
|
||||
interface ReplaySystemStub {
|
||||
route: ReplayRouteStub; // ← 旧字段,须改 array
|
||||
disable: ReturnType<typeof vi.fn>;
|
||||
revert: ReturnType<typeof vi.fn>;
|
||||
}
|
||||
function createReplaySystem(): ReplaySystemStub {
|
||||
let disabled = 0;
|
||||
const commands: [ReplayCode, unknown[]][] = [];
|
||||
const route: ReplayRouteStub = {
|
||||
add(code, params) { if (disabled > 0) return; commands.push([code, params]); },
|
||||
commands
|
||||
};
|
||||
const disable = vi.fn(() => { disabled++; });
|
||||
const revert = vi.fn(() => { if (disabled > 0) disabled--; });
|
||||
return { route, disable, revert };
|
||||
}
|
||||
```
|
||||
**目标形状**(对齐后,RESEARCH Pattern 2):把 `route` 键改为 `array: { add }`,保留 `disable`/`revert`。
|
||||
生产真实形状的可复用 analog:`packages-user/data-state/test/fixtures/closed-loop.ts:170-172,247-250`(直接用真 `ReplaySystem`,`replay.array` + `createReplaySandbox({ route: replay.array, ... })`)。
|
||||
|
||||
### P5. Hook 控制器(D 族;删 `.load()`)
|
||||
|
||||
`addHook` 即注册,返回 `IHookController`(仅 `unload()`)— 契约源 `packages/common/src/hook.ts:23-32`、`packages/common/src/types.ts:52-60`。
|
||||
**现有测试全是旧写法**(须删 `.load()`):
|
||||
- `packages-user/data-base/src/hero/follower.test.ts:119-125`:`env.controller.addHook({...}).load();`
|
||||
- `packages-user/data-common/src/replay/sandbox.test.ts:74-80`:`sandbox.addHook({ onStep: ... }).load();`
|
||||
- `packages-user/data-base/src/map/mapLayer.test.ts:143-149`:`layer.addHook({ onUpdateBlock } ).load();`
|
||||
- `packages-user/data-base/src/map/gameMap.test.ts:150-154`、`:100-104`
|
||||
```ts
|
||||
// 对齐后(保留返回值以备 unload)
|
||||
const controller = layer.addHook({ onUpdateBlock: (block, x, y) => { updates.push([block, x, y]); } });
|
||||
// controller.unload();
|
||||
```
|
||||
|
||||
### P6. `CoreState` 构造(B 族;工厂已删)
|
||||
|
||||
现有夹具用已删除的 `createCoreState()` — analog `packages-user/data-state/test/fixtures/closed-loop.ts:64`:
|
||||
```ts
|
||||
const state = createCoreState(); // ← 已删
|
||||
```
|
||||
**目标形状**(RESEARCH §8.11 / ins.ts:11-14):
|
||||
```ts
|
||||
import { CoreState } from '../core';
|
||||
import { WebLoadStarter } from '@motajs/loader'; // loadStarter 来源须用户裁决,见 OQ1
|
||||
const state = new CoreState({ loadStarter: new WebLoadStarter(), coreURL: 'placeholder' });
|
||||
```
|
||||
全部 10 个 data-state test + 3 个 perf + `fixtures/closed-loop.ts` 均依赖此形状。
|
||||
|
||||
### P7. 寻路注入面(path F 族)
|
||||
|
||||
`useMapState`/`useDirGroup` 已删,改为 `useMapLayer`/`useFaceHandler`。现有测试处于**过渡态**— analog `packages-user/data-system/src/path/system.test.ts:339-340`:
|
||||
```ts
|
||||
system.finder.useMapState(maps); // :339 已删方法,须移除
|
||||
system.finder.useMapLayer(layer); // :340 保留
|
||||
```
|
||||
`graph.test.ts:39,59` 仍 import `DirectionMapper`(已删)—须一并移除。
|
||||
**目标形状**(RESEARCH Code Examples):
|
||||
```ts
|
||||
system.finder.useMapLayer(state.maps.get('F1')!.eventLayer);
|
||||
system.finder.usePassPredicate(predicate);
|
||||
system.finder.useFaceHandler(faceHandler); // 取代 useDirGroup
|
||||
```
|
||||
|
||||
### P8. 地图构造 / 别名(map F 族)
|
||||
|
||||
`MapState` 构造已是单参 `state`(现测试 `mapState.test.ts:87` 仍传 `(tileStore, state)`);`setLayerAlias` 已删,别名改由 `addLayer(alias)` 传入。现有旧写法 analog `gameMap.test.ts:115-130`:
|
||||
```ts
|
||||
const first = map.addLayer(); // :118 → addLayer('<alias>')
|
||||
map.setLayerAlias(first, 'event'); // :121 → 删除,别名在 addLayer 传入
|
||||
const result = logger.catch(() => map.setLayerAlias(second, 'event')); // :125 → 应改为重复别名 131
|
||||
```
|
||||
**目标形状**(RESEARCH Code Examples / gameMap.ts:61):`const layer = map.addLayer('event');` + `map.setEventLayer(layer);`。`coreNode.test.ts:21` 的 `map.addLayer()` 无参调用同样须补别名。
|
||||
|
||||
---
|
||||
|
||||
## Shared Patterns
|
||||
|
||||
### S1. `describe`/`it` 中文单行注释(强制,`dev.md:86`)
|
||||
每个 `it` 前一行中文注释说明覆盖内容;迁移时**逐文件保留并同步**。反例核对基线:`packages-user/data-state/test/coreNode.test.ts:6`、`nodeReplay.test.ts:163`、`face.test.ts:34`。
|
||||
|
||||
### S2. 文件头一行注释
|
||||
多数测试文件首行是 `// 测试 …`(如 `sandbox.test.ts:1`、`follower.test.ts:1`、`equipment.test.ts:1`);迁移时保留。
|
||||
|
||||
### S3. 全局桩固定搭配
|
||||
`vi.stubGlobal('main', { replayChecking: true })` + `vi.stubGlobal('location', { origin: 'http://localhost' })` 是数据端测试入场券;`afterAll(() => vi.unstubAllGlobals())` 收尾。**不得删。**
|
||||
|
||||
### S4. 禁止的「假绿」手段
|
||||
`as never` 伪造已删成员、`Object.create` 造骨架、删除测试用例——RESEARCH Anti-Patterns 明令禁止(延续 `07-16-PLAN.md:484/599`)。`it.skip` 仅可保留既有不可达码 147(`equipment.test.ts:352-353`)。
|
||||
|
||||
### S5. 唯一既有 `it.skip`
|
||||
`packages-user/data-base/src/hero/equipment.test.ts:353`(code 147);迁移后随文件进入 `hero/__test__/`,内容不动。
|
||||
|
||||
---
|
||||
|
||||
## Config / Barrel / External References
|
||||
|
||||
| 引用点 | 是否需要改 | 说明 |
|
||||
|--------|------------|------|
|
||||
| `script/test-data-node.ts:67` | **是** | `require('../packages-user/data-state/test/replayVerifier.ts')` → `__test__/replayVerifier.ts` |
|
||||
| `script/test-data-node.ts:122` | **是** | `require('...data-state/test/fixtures/closed-loop.ts')` → `__test__/fixtures/closed-loop.ts` |
|
||||
| `package.json:test:data-node` | 否 | 映射到上述 script,无需改 |
|
||||
| `vite.config.ts:46-49` | 否 | 无 `test.include`,用 Vitest 默认 glob;`__test__/` 不在默认 exclude |
|
||||
| `vite.config.ts:21-27` 别名 | 否 | `@user/<pkg>` → `packages-user/*/src`,与测试落位无关 |
|
||||
| `vitest.perf.config.ts:29` | 否 | `include: ['**/*.perf.ts']` 深度无关 |
|
||||
| `tsconfig.json:30` | 否 | `packages-user/**/*.ts` 覆盖 `__test__/` |
|
||||
| `eslint.config.js` | 否 | 无测试路径 glob / ignore(`git grep` 0 命中) |
|
||||
| 各包 `index.ts` barrel | 否 | `git grep` 确认无 barrel 引用测试文件 |
|
||||
| `.planning/**` | 否 | 规划文档引用不参与运行 |
|
||||
|
||||
> `git grep -nE "data-state/test|test/fixtures|replayVerifier"` 全仓(排除 `.planning`)仅命中:`data-state/test/nodeReplay.test.ts:8`(随迁保留)、`script/test-data-node.ts:67,122`(须改)。
|
||||
|
||||
---
|
||||
|
||||
## No Analog Found
|
||||
|
||||
| 目标 | Role | 说明 |
|
||||
|------|------|------|
|
||||
| 任意 `**/__test__/` 目录布局 | — | 全仓 0 个现存 `__test__/`;无历史 analog,属全新约定 |
|
||||
| `data-state/src/__test__/coreEventLayer.test.ts` 的对齐目标 | test | 其被测面 `CoreState.initMapState` 已删;改写为 `MapState.fromRaw` 或退役均无现成 analog,须用户裁决(RESEARCH OQ4) |
|
||||
| `data-state/test/tileLegacy.test.ts` 的对齐目标 | test | 被测模块 `src/legacy/` 已整体删除,无替代登录点(RESEARCH OQ3) |
|
||||
| 21 个缺口错误码的补测用例 | test | 现有测试未覆盖这些码,无逐码 analog;仅可复用 P3 的 `logger.catch` 断言机制与源码 emit 点(RESEARCH §9.1) |
|
||||
|
||||
---
|
||||
|
||||
## Metadata
|
||||
|
||||
**Analog search scope:** `packages-user/data-{common,base,system,state}/**`、`script/**`、`vite.config.ts`、`vitest.perf.config.ts`、`tsconfig.json`、`eslint.config.js`、`package.json`
|
||||
**Files scanned (tests read for patterns):** `data-state/test/{coreNode,nodeReplay,saveablesRoundTrip}.test.ts`、`data-state/test/{replayVerifier.ts,fixtures/closed-loop.ts}`、`data-state/src/coreEventLayer.test.ts`、`data-state/src/enemy/calculator.test.ts`、`data-base/src/hero/{follower,equipment}.test.ts`、`data-base/src/map/{mapState,mapLayer,gameMap}.test.ts`、`data-common/src/common/face.test.ts`、`data-common/src/replay/sandbox.test.ts`、`data-system/src/path/{graph,system}.test.ts`
|
||||
**Tracked-source gate:** 所有引用路径经 `git ls-files` 校验为 tracked;无 gitignored mirror 路径
|
||||
**Pattern extraction date:** 2026-10-04
|
||||
118
.planning/phases/08-test-refactor-alignment/08-PLAN-CHECK.md
Normal file
118
.planning/phases/08-test-refactor-alignment/08-PLAN-CHECK.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Phase 8 计划预执行核查报告(08-PLAN-CHECK)
|
||||
|
||||
**核查对象**: `08-01-PLAN.md` .. `08-11-PLAN.md`(11 份)
|
||||
**阶段目标(ROADMAP.md:443)**: 将全部 `.test.ts` / `.perf.ts` 迁入 `__test__`,按数据端「系统性收尾」后 shipped 接口重对齐、修复重构遗漏,使 `pnpm test:ci` / `test:perf` 重新全绿
|
||||
**需求**: `TEST-02`(唯一映射;`TEST-01` 不在本阶段范围)
|
||||
**核查方式**: goal-backward 静态核查 + `git ls-files` 实测 + 配置只读核对
|
||||
**核查时间**: 2026-10-04
|
||||
**总体结论**: **PASS(无 BLOCKER)**,含 3 项 WARNING + 8 项 INFO;warning 建议在执行前/执行中处理,不阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 0. 实测事实基线(已核)
|
||||
|
||||
| 事实 | 实测结果 | 与计划声明 |
|
||||
|------|----------|------------|
|
||||
| 数据端 `.test.ts`(四包 + `data-state/test`) | 65(`git ls-files`) | 与 PATTERNS/08-01 一致 |
|
||||
| 数据端 `.perf.ts` | 6 | 一致 |
|
||||
| `data-state/test/` tracked 文件 | 14(8 test + 3 perf + `replayVerifier.ts` + `fixtures/closed-loop.ts` + `fixtures/floors.json`) | 一致 |
|
||||
| 现存 `__test__/` 目录 | 0 | 与 PATTERNS 一致(greenfield) |
|
||||
| `script/test-data-node.ts` 硬编码旧路径 | 第 67、122 行命中 `data-state/test/...` | 08-01 定位正确 |
|
||||
| `vite.config.ts` `test.include` | 无(默认 glob) | 零配置改动成立 |
|
||||
| `vitest.perf.config.ts` | `include: ['**/*.perf.ts']` | 成立 |
|
||||
| `tsconfig.json` include | `packages-user/**/*.ts` | 成立 |
|
||||
| `.prettierrc` | `endOfLine: "crlf"`;`prettier` 为 devDependency | 08-11 CRLF 口径成立 |
|
||||
| `eslint.config.js` ignores | 仅 `node_modules`/`dist`/`public`(测试文件纳入 lint) | 成立 |
|
||||
| 11 份计划 `autonomous:` | 全部 `false`,且各恰 1 个 `blocking-human` Task 0 | 约束成立 |
|
||||
| estimate 预算 | 全部 < 100000(08-10 最大 75000,ratio 0.7),无 over_budget | 成立 |
|
||||
|
||||
**跨源覆盖审计**:`ROADMAP.md:448-451` 四条成功标准 ↔ 计划映射完整(迁移→08-01;对齐→08-02..08-09;覆盖→08-10;全绿→08-11)。`REQUIREMENTS.md:38` `TEST-02` 由 `08-01..08-11` 全部 `requirements` 字段认领。`08-CONTEXT.md` D-01..D-10 全部有落点。Deferred(`script/check-data-circular.test.ts`、渲染端/legacy、全仓 `check:type`)未被任何计划引入。
|
||||
|
||||
---
|
||||
|
||||
## 1. 逐维度判定
|
||||
|
||||
| # | 维度 | 判定 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 1 | Requirement Coverage | **PASS** | `TEST-02` 被全部计划认领;无 PROJECT.md 相关需求被静默丢弃 |
|
||||
| 2 | Task Completeness | **PASS** | 11 计划均有 `checkpoint:decision gate="blocking-human"` Task 0;auto/tracer 任务含 files/action/verify/done |
|
||||
| 3 | Dependency Correctness | **PASS** | 无环;`08-01 → (08-02..08-08) → 08-09 → 08-10 → 08-11`;无前向引用 |
|
||||
| 3b | Undeclared/Temporal Coupling | **PASS** | 同波(wave 2)计划文件集互斥(按包/子系统切分),无共享可变资源;08-08→08-09 的 `loadStarter` 契约已由 `depends_on` 声明 |
|
||||
| 4 | Key Links Planned | **PASS** | 迁移-脚本、Hook/朝向/录像桩/注入面等 wiring 均在 `key_links` 显式 |
|
||||
| 5 | Scope Sanity | **PASS**(见 I1) | 见下方 I1;estimate 未超预算,D-06 锁定单一迁移计划 |
|
||||
| 6 | Verification Derivation | **PASS** | must_haves.truths 可观测(文件数守恒、全绿、skipped=1) |
|
||||
| 7 | Context Compliance | **PASS** | D-01..D-10 全覆盖;无 Deferred 项被纳入 |
|
||||
| 7b | Scope Reduction Detection | **PASS** | 未发现「v1/静态/placeholder/未接线」等缩减语;覆盖计划覆盖全部 21 码 |
|
||||
| 7c | Architectural Tier Compliance | **PASS** | 与 RESEARCH `## Architectural Responsibility Map` 一致:测试落位归各数据包目录,对齐归测试面,只读对照源码 |
|
||||
| 8 | Nyquist Compliance | **WARNING**(W1/W3) | 见 W1、W3 |
|
||||
| 9 | Cross-Plan Data Contracts | **PASS** | 共享夹具 `closed-loop.ts` 与其消费者同在 08-09;08-10 依赖全部前序计划后再触碰同批文件,串行无冲突 |
|
||||
| 10 | AGENTS.md Compliance | **PASS** | Task 0 汇报关卡、命名先批准、不改既有 jsDoc、test-only 默认、每日重测纪律均落实 |
|
||||
| 11 | Research Resolution | **INFO**(I3) | `## Open Questions(需用户决策)` 未带 `(RESOLVED)`,但 8 项 OQ 全部落为 Task 0 裁决项 |
|
||||
| 12 | Pattern Compliance | **PASS** | 计划引用 PATTERNS `M1/M2/M3`、`P1..P8`、`S1..S5`,Analog 与 File Classification 对齐 |
|
||||
| — | Verify Command Format Sanity | **PASS** | 无 `2>/dev/null || echo`、无 `\| grep -E '^pkg'`、无 `\|\| true` 喂比较 |
|
||||
| — | Verify Command Path Resolvability | **WARNING**(W2) | 见 W2 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 具体问题清单(file -> plan -> problem)
|
||||
|
||||
### Warnings(建议执行前修正)
|
||||
|
||||
**W1 — [nyquist] 08-11 的 CRLF/prettier 门禁未进入 `<automated>`**
|
||||
- 文件: `.planning/phases/08-test-refactor-alignment/08-11-PLAN.md`(plan 08-11)
|
||||
- 问题: `must_haves.truths` 与 `<verification>` 均要求 `pnpm exec prettier --check` 无格式差异(CRLF),但 Task 1 的 `<verify><automated>` 仅为 `pnpm test:ci; pnpm test:perf; pnpm exec eslint ...`,**不含 prettier**。CRLF(`dev.md:116`、`.prettierrc endOfLine:"crlf"`)这一硬性属性没有自动化检查兜底;批量改导入若写成 LF 不会被该门禁判失败。
|
||||
- required_property: 阶段验收所声明的格式/CRLF 属性必须由一个可失败的自动化命令判定。
|
||||
- 示例修正(非绑定): 在 08-11 Task 1 的 `<automated>` 追加 `pnpm exec prettier --check <本次改动文件>`(或 `pnpm exec prettier --check "packages-user/**/__test__"`)。
|
||||
|
||||
**W2 — [verify_path_resolvability] 08-10 Task 2 验证命令含条件路径,可能误判失败**
|
||||
- 文件: `.planning/phases/08-test-refactor-alignment/08-10-PLAN.md`(plan 08-10, Task 2)
|
||||
- 问题: `<automated>` 无条件包含 `packages-user/data-state/src/loader/__test__`,但该目录**仅在 Task 0 Q3 批准新建 loader 测试时**才存在(`files_modified` 未声明该文件,artifacts 标注「条件」)。若 Q3=否,`pnpm exec vitest run` 会因「No test files found」非零退出,与 Q3 分支矛盾。
|
||||
- required_property: 每个 `<verify>` 命令在 Task 0 任一决策分支下都能正确判定通过/失败。
|
||||
- 示例修正(非绑定): 将 loader 路径从主命令拆出,仅在 Q3 批准时作为第二条条件命令执行;或 Q3=否时把 66/67/68/69 明确落到已存在的 test 文件。
|
||||
|
||||
**W3 — [nyquist] 08-04 / 08-06 的聚焦命令不会采集 `*.perf.ts`,与所声称的「含 perf 0 失败」不符**
|
||||
- 文件: `.planning/phases/08-test-refactor-alignment/08-04-PLAN.md`(Task 2)、`08-06-PLAN.md`(Task 1)
|
||||
- 问题: 两处 `must_haves.truths` 声称「…+N perf … 聚焦运行 0 失败」,但 `<automated>` 用 `pnpm exec vitest run <dir>` 走默认 `vite.config.ts`(**无 `test.include`**,默认 glob 为 `**/*.{test,spec}.?(c|m)[jt]s?(x)`,**不匹配 `*.perf.ts`**)。因此 `attribute.perf.ts`、`context.perf.ts`、`damage.perf.ts` 的完成状态不由这两条命令判定。(缓解:`08-09` Task 2 与 `08-11` Task 1 会运行 `pnpm test:perf`(6 文件),全局仍有兜底。)
|
||||
- required_property: 每个任务对制定文件的完成判定必须由其 `<verify>` 命令真实覆盖。
|
||||
- 示例修正(非绑定): 聚焦命令改用 `pnpm exec vitest run --config vitest.perf.config.ts <perf 路径>`,或在 truth 中明示 perf 由 `pnpm test:perf` 在 08-09/08-11 统一判定。
|
||||
|
||||
### Advisories(INFO)
|
||||
|
||||
**I1 — [scope_sanity] 08-01 单计划触达 75 个文件(远超 15 建议上限)**
|
||||
- `.planning/phases/08-test-refactor-alignment/08-01-PLAN.md`:`files_modified` 74 目标 + `script/test-data-node.ts`,`files_deleted` 74。
|
||||
- 判定为 INFO 而非 BLOCKER/WARNING 的依据:(a) `08-CONTEXT.md` **D-06 锁定「独立目录迁移计划」单数**,拆分将抵触锁定决策;(b) 本 plan estimate 70000 tokens、ratio 0.7 < budget 100000、`over_budget=false`;(c) 迁移为机械 `git mv` + specifier 改写,且有「文件数守恒(66/6)」硬门禁。故不建议拆分,仅提示执行时注意上下文。
|
||||
|
||||
**I2 — [requirement_coverage] `script/check-data-circular.test.ts` 在 66-全绿门禁内但被声明为范围外**
|
||||
- `08-11-PLAN.md` 要求 `test:ci` 66 文件全绿(含该脚本测试),而 `08-CONTEXT.md`/Deferred 将其排除、无计划处理它。
|
||||
- 实测参考:`07-VERIFICATION.md` 的 17-失败文件快照未含该文件,且其被测对象为独立脚本分类函数,不受数据端接口变动影响——判定其当前为绿。若执行日实测该文件为红,则阶段目标不可达,需回退汇报。
|
||||
|
||||
**I3 — [research_resolution] RESEARCH 的 `## Open Questions` 未标 `(RESOLVED)`**
|
||||
- `.planning/phases/08-test-refactor-alignment/08-RESEARCH.md:526` 标题为 `## Open Questions(需用户决策)`。按维度 11 字面应 FAIL,但 8 项 OQ **全部**已成为 Task 0 裁决项:OQ1→08-08 Q1/08-09 Q2;OQ2→08-02 Q1;OQ3→08-09 Q1;OQ4→08-08 Q2;OQ5→08-02 Q2;OQ6→08-05 Q1;OQ7→08-04 Q1;OQ8→08-10 Q3。属设计使然(D-09 全程 Task-0 门控),故记 INFO。
|
||||
|
||||
**I4 — [task_completeness] 08-01 Task 1 与 Task 2 对 group 5(flag)处理重叠**
|
||||
- `08-01-PLAN.md` Task 1 用 tracer 先迁 `flag/{saveLoad,system}.test.ts`;Task 2 又声明「组 1-14」迁移(含 group 5)。执行者可能对已迁文件重复 `git mv`。建议 Task 2 显式「跳过已由 Task 1 完成的 flag 组」。
|
||||
|
||||
**I5 — [task_completeness] 部分对齐计划未复述「每个 it 前中文单行注释」不变量**
|
||||
- `08-04`、`08-06`、`08-07`、`08-08`、`08-09` 的 truths/action 未逐字重述;依赖 `08-PATTERNS.md` `S1` 与 `dev.md:86`(均在各计划 context 中)。建议对齐计划统一在约束中保留该句。
|
||||
|
||||
**I6 — [verification_derivation] 08-01 的「文件数守恒」不校验导入重写正确性(设计使然)**
|
||||
- import specifier 写错时文件仍被 glob 采集(计数仍 66),仅表现为该文件 failed;08-01 显式接受「仍红」。导入正确性实际由 08-02..08-09 的「聚焦 0 失败」兜底。此为 D-06 既定分层,记 INFO。
|
||||
|
||||
**I7 — [task_completeness] 08-10 条件新建的 loader 测试文件未列入 `files_modified`**
|
||||
- `08-10-PLAN.md` artifacts 含 `packages-user/data-state/src/loader/__test__/loader.test.ts`(条件),但 frontmatter `files_modified` 未含。若批准新建,执行期 wave 文件重叠检查无法覆盖该新文件。
|
||||
|
||||
**I8 — [verification_derivation] 基线「当日重测」在执行序列中发生于迁移之后**
|
||||
- `ROADMAP.md:456` 要求先重测当日失败清单。计划未设独立的 pre-alignment 基线 run;但 `08-01` Task 2/3 的 `pnpm test:ci` 会输出当前完整失败清单(迁移不改测试成败),事实上完成重测。记 INFO。
|
||||
|
||||
---
|
||||
|
||||
## 3. 结论与最小修订需求
|
||||
|
||||
- **无 BLOCKER**:需求覆盖、任务完整性、依赖图、上下文合规、`autonomous:false`+Task 0、路径 tracked、配置零改动、21 码覆盖、66/6 全绿与 skipped=1 验收均成立。计划集合**能够**达成 Phase 8 目标。
|
||||
- **建议(不阻塞)的最小修订**:
|
||||
1. W1:在 `08-11` Task 1 的 `<automated>` 补 `pnpm exec prettier --check`。
|
||||
2. W2:`08-10` Task 2 将条件 loader 路径改为分支命令。
|
||||
3. W3:`08-04`/`08-06` 的 perf 覆盖改由 `vitest.perf.config.ts` 聚焦运行,或在 truth 明示由 `pnpm test:perf` 全局判定。
|
||||
- 其余 INFO 为可选的清晰度改进。
|
||||
|
||||
**Verdict: PASS(0 BLOCKER / 3 WARNING / 8 INFO)—— 可由 planner 按需吸收 warning,或直接进入执行(执行前须经各计划 Task 0 用户「可以执行」关卡)。**
|
||||
642
.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
Normal file
642
.planning/phases/08-test-refactor-alignment/08-RESEARCH.md
Normal file
@ -0,0 +1,642 @@
|
||||
# Phase 8: 测试重构与接口对齐 - Research
|
||||
|
||||
**Researched:** 2026-10-04
|
||||
**Domain:** 数据端(`packages-user/data-{common,base,system,state}`)单测目录迁移 + 按「系统性收尾」后 shipped 接口重对齐
|
||||
**Confidence:** HIGH(接口结论均以 live 源码为锚;不确定性集中在「该删还是该改」的裁决项)
|
||||
|
||||
## Summary
|
||||
|
||||
本阶段的本质是**测试对齐**,不是生产改造。侦察基线(`pnpm test:ci` = 66 文件 / 45 failed / 21 passed;339 failed / 367 passed / 1 skipped,HEAD `109fad3`)所反映的全部失败族,其根因均可从**当前 live 源码**逐条定位:Phase 6/7 编写测试后,用户又做了一轮「系统性收尾」(删 `createCoreState`/`DirectionMapper`/`getFaceMovement` 系列工具/`initMapState`/`setLayerAlias`/`TileLegacyBridge`,收紧 `CoreState` 构造配置、`MapState`/`MapLayer`/`HeroLocation.setFloor` 签名、把 `Hookable.addHook` 的返回从「可 `.load()`」改为 `IHookController`(仅 `.unload()`),把录像写入面从 `replay.route` 改为 `replay.array`,把寻路注入面从 `useMapState`/`useDirGroup` 改为 `useMapLayer`/`useFaceHandler`),并新增/移除了一批 logger 码。测试仍在断言已被删除或改签名的旧面,因此大面积红。
|
||||
|
||||
**Primary recommendation:** 按 D-06 先出**纯目录迁移计划**(只移动 + 修相对导入,验证采集文件数与迁移前一致),再按子系统出**对齐计划**(每个失败族给出「旧断言 → 新调用形状」的逐文件修改),最后出**覆盖补测计划**(21 个当前发出但 06-COVERAGE-MAP 无覆盖的码 + 7 个已不再发出却被覆盖表登记的码)。任何「删测试文件」或「改契约」的决定(`utils.test.ts`、`tileLegacy.test.ts`、`coreEventLayer.test.ts`、158/175 码、62/63/64/84/130 码)都必须走 Task 0 用户裁决,不得由执行者自行假设。
|
||||
|
||||
## User Constraints (from CONTEXT.md)
|
||||
|
||||
> 以下逐字复制自 `08-CONTEXT.md`。Planner 必须原样遵守;研究不得推荐与之冲突的方案。
|
||||
|
||||
### Locked Decisions
|
||||
|
||||
- **D-01:** 范围 = 四包 `packages-user/data-{common,base,system,state}` 全部单测;`script/` 暂不纳入。
|
||||
- **D-02:** 迁移到同目录 `__test__/`;`data-state/test/` → `data-state/__test__/`(`fixtures/` 随迁)。
|
||||
- **D-03:** 错误码覆盖以 `packages/common/src/logger.json` 为准。
|
||||
- **D-04:** 「全绿」= 所有测试通过;既有表示**不可达错误码**的 `it.skip` 保留(当前仅 code 147 一条)。
|
||||
- **D-05:** 接口设计不再变更;本阶段只做「对齐」(接口语义变化 + 接口设计变化),不新增接口。
|
||||
- **D-06:** **迁移方式 (a)**:先出独立「目录迁移」计划(全量移动 + 修相对导入,测试仍红但位置正确、可独立验证),后续按子系统对齐。
|
||||
- **D-07:** **覆盖侧单列计划**:先盘点数据端错误码(从 `packages-user/data-*` 的 `logger.error/warn` 调用点反推)与公共接口清单及现有覆盖缺口,再补测。
|
||||
- **D-08:** 用户并发进行渲染端收尾,可能触及数据端内容,但**不改接口设计、不影响测试**;AI **不得提交用户改动的文件**;若 AI 正在进行的行动与用户改动冲突,**先暂停并向用户汇报**。
|
||||
- **D-09:** 每个计划执行前按项目规则设 **Task 0 汇报关卡**(`autonomous: false`),用户确认后方可执行。
|
||||
- **D-10:** 测试面零生产改动;仅当某失效确由数据端重构遗漏导致、且用户确认后,才可做最小生产修复(否则退出并汇报)。
|
||||
|
||||
### the agent's Discretion
|
||||
|
||||
- 迁移计划的具体移动方式(脚本/逐文件)、对齐计划的子系统切分与顺序、覆盖补测的范围与用例设计,由实现者在上述约束下决定;发现新的接口/设计疑问立即提问,不自行假设。
|
||||
|
||||
### Deferred Ideas (OUT OF SCOPE)
|
||||
|
||||
- `script/check-data-circular.test.ts`。
|
||||
- 渲染端 / legacy 测试(后续阶段)。
|
||||
- `pnpm check:type` 全仓(既有渲染端诊断不在本阶段范围)。
|
||||
|
||||
## Phase Requirements
|
||||
|
||||
| ID | Description | Research Support |
|
||||
|----|-------------|------------------|
|
||||
| TEST-02 | 测试文件统一归入 `__test__` 目录,并按数据端当前接口对齐既有测试、修复重构遗漏导致的测试失效(`REQUIREMENTS.md:38`,Traceability `:71` 映射 Phase 8) | 迁移配置可零改动(见「迁移配置裁决」);接口 delta 逐子系统清单(见「逐子系统接口 Delta」);`pnpm test:ci` / `pnpm test:perf` 全绿验收 |
|
||||
|
||||
> 说明:Phase 8 只映射 `TEST-02`。`TEST-01`(Phase 6)保持 In Progress,不在本阶段范围(`REQUIREMENTS.md:70`)。
|
||||
|
||||
## Architectural Responsibility Map
|
||||
|
||||
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||||
|------------|-------------|----------------|-----------|
|
||||
| 测试文件落位(`__test__/`) | 各数据包源码目录 | — | D-02 要求「同目录 `__test__/`」,迁移面仅文件系统 |
|
||||
| 接口对齐(旧断言 → shipped 形状) | `packages-user/data-*` 测试 | 各包源码 `types.ts`(对照面,只读) | 以 shipped 源码为唯一事实源;D-10 禁止生产改动 |
|
||||
| 错误码覆盖盘点 | `packages/common/src/logger.json`(码表) | `packages-user/data-*` 源码 `logger.*` 调用点 | D-03/D-07 明确以码表为准、从调用点反推 |
|
||||
| 公共接口覆盖盘点 | 各包 barrel `index.ts` + `types.ts` | `06-COVERAGE-MAP.md`(既有映射) | 覆盖现状基线;本阶段只补测试 |
|
||||
| 性能测试(`*.perf.ts`) | 隔离 lane `vitest.perf.config.ts` | 各包 `*.perf.ts` | `test:perf` 独立 include,与 `test:ci` 隔离 |
|
||||
| 日志码契约(新增/退役码) | `logger.json` | 用户裁决 | 涉及契约变化,D-10 + AGENTS.md 要求用户确认 |
|
||||
|
||||
## 迁移配置裁决(研究任务 4)
|
||||
|
||||
**裁决:迁移到 `__test__/` 不需要任何配置改动。**
|
||||
|
||||
| 配置 | 现状(anchor) | 迁移后是否需改 | 依据 |
|
||||
|------|----------------|----------------|------|
|
||||
| `vite.config.ts` 测试收集 | `test: { testTimeout: 30000, hookTimeout: 30000 }`,**无 `test.include`**(`vite.config.ts:46-49`) | 否 | 使用 Vitest 默认 include glob(`**/*.{test,spec}.?(c|m)[jt]s?(x)`)。`__test__/` 不在默认 exclude 列表内,命中不受目录名影响 |
|
||||
| `vite.config.ts` 别名 | `packages-user/*/src` → `@user/<name>`(`vite.config.ts:21-27`) | 否 | 别名按包名解析;`__test__/` 内的相对导入仍是源码目录内的相对路径 |
|
||||
| `vitest.perf.config.ts` | `test: { include: ['**/*.perf.ts'], ... }`(`vitest.perf.config.ts:29`) | 否 | `**` 匹配任意深度,`__test__/` 下的 `*.perf.ts` 仍被收集 |
|
||||
| `tsconfig.json` | `include` 含 `"packages-user/**/*.ts"`(`tsconfig.json:30`) | 否 | `**/*.ts` 覆盖 `__test__/` |
|
||||
| `package.json` 脚本 | `test:ci = vitest run`、`test:perf = vitest run --config vitest.perf.config.ts`(`package.json:14-15`) | 否 | 命令不带路径过滤 |
|
||||
|
||||
**唯一需要做的是导入路径编辑**(不是配置):`data-state/test/*.ts` 迁到 `data-state/__test__/` 后,`../src/core` 与 `./fixtures/...` 的相对层级多一层,相关 specifier 需同步改;`test/fixtures/` 目录随迁后其内部对 `../../src/core.ts` 的引用也需重算。这属于「迁移计划」的文件编辑范畴(D-06),不属配置项。
|
||||
|
||||
**验证迁移完整性的方法(供迁移计划采用):** 迁移前记录 `pnpm test:ci` 采集文件数(基线 66 = 数据端 65 `.test.ts` + `script/check-data-circular.test.ts` 1);迁移后重跑确认采集数仍为 66、`test:perf` 采集 6。
|
||||
|
||||
## 逐子系统接口 Delta(研究任务 1)
|
||||
|
||||
> 每行给出「测试当前写法(file:line)→ shipped 形状(file:line)」与类别(对应基线失败族 A–G)。类别定义:A=引用已删/改名导出;B=`CoreState` 加载配置形状;C=录像桩 `replay.array`;D=`addHook(...).load()` 链;E=引用已移动/删除模块;F=公共接口改名/签名;G=断言语义漂移。所有 shipped 形状均以 live 源码为准,不采用 07-VERIFICATION 旧快照。
|
||||
|
||||
### 8.1 data-common/common
|
||||
|
||||
| 符号 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|------|------------------------|------------------------------|------|
|
||||
| `utils.ts` 整个模块 | `import { degradeFace, fromDirectionString, getFaceMovement, nextFaceDirection } from './utils'`(`packages-user/data-common/src/common/utils.test.ts:4-9`) | **模块与 4 个函数在全仓源码中已不存在**(对 `packages-user/data-common/src` 的全量扫描仅命中测试文件本身)。`common/index.ts` 只导出 `./face`、`./faceManager`、`./indexer`、`./mover`、`./types`(`packages-user/data-common/src/common/index.ts:1-5`)。职责替代:`IFaceHandler` 的 `degrade`/`movement`/`next`/`dirOf`(`packages/common/src/utils/types.ts:152`;实现 `packages-user/data-common/src/common/faceManager.ts:94-216`),已由 `faceManager.test.ts` 覆盖 | E |
|
||||
| `DirectionMapper` | `import { DirectionMapper } from '@motajs/common'` + `new DirectionMapper()`(`data-base/src/map/tile.test.ts:15,93`;`dynamicTile.test.ts:15,93`;`mapState.test.ts:14,84`;`mapLayer.test.ts:16,104`;`gameMap.test.ts:13,86`;`saveLoad.test.ts:13,91`;`mover.test.ts:14,89` 等) | **`@motajs/common` 已无 `DirectionMapper`**(`packages/common/src` 全量扫描 0 命中);`IDataCommon` 也已无 `directionMapper` 成员(`packages-user/data-common/src/types.ts:50-65` 逐字:`tileStore`/`itemStore`/`mapStore`/`eventStore`/`roleFace`/`faceManager`/`replaySystem`)。朝向能力改由 `IFaceManager`(`faceManager.ts:13-39`)+ `IFaceHandler` 提供 | A / F |
|
||||
| `RoleFaceBinder`/`FaceManager`/`Dir4FaceHandler`/`Dir8FaceHandler` | `face.test.ts:11`、`faceManager.test.ts:4` | 均存在(`face.ts:13` `export class RoleFaceBinder`;`faceManager.ts:94,176,222`) | —(兼容) |
|
||||
| `ObjectMover`/`ObjectAnimDirection`/`ObjectMoveType`/`IObjectMovable`/`ObjectMoveStep` | `mover.test.ts:5-10`、`indexer.test.ts:3` | `common/mover.ts`、`common/indexer.ts` 存在(`common/index.ts:3-4`) | —(兼容,待执行期以编译为准) |
|
||||
|
||||
### 8.2 data-common/replay
|
||||
|
||||
| 符号 / 行为 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|-------------|------------------------|------------------------------|------|
|
||||
| `addHook(...).load()` 链 | `sandbox.addHook({...}).load()`(`packages-user/data-common/src/replay/sandbox.test.ts:80,257,279,299,331,367,403`);`system.addHook({...}).load()`(`system.test.ts:84,122`) | `Hookable.addHook(hook): C` 返回 `IHookController`,**只有 `unload()`**(`packages/common/src/hook.ts:23-32`;接口 `packages/common/src/types.ts:52-60` 逐字:`readonly hook: Partial<H>; unload(): void;`)。`addHook` 内部已直接 `hook.awake?.(...)` 并加入 `loadedList`(`hook.ts:29-30`),**无 `load()` 方法** | D |
|
||||
| `ReplaySystem.array` | `route: system.array`(`sandbox.test.ts:36,229`;`saveLoad.test.ts:78`;`system.test.ts:126,141`) | `ReplaySystem.array` 存在(`packages-user/data-common/src/replay/system.ts:27` `readonly array: IReplayArray;`) | —(兼容) |
|
||||
| `ReplaySandbox` 配置 `route` | `route: system.array`(`sandbox.test.ts:36`) | `ReplaySandbox` 构造器首参 `readonly route: IReplayArray`(`sandbox.ts:55-59`);config 字段在 `IReplaySandboxConfig` | —(兼容,`route` 指数组本身) |
|
||||
| 码 158 / 175 | `expect(warn).toHaveBeenCalledWith(158, '1', '[]')`(`sandbox.test.ts:92,118`)、`...(175, '1')`(`sandbox.test.ts:171,193`) | **当前 `sandbox.ts` 不发出 158/175**;执行/finalize 失败统一走 `logger.error(72, method)`(`sandbox.ts:136`),被动/未知步走 `logger.warn(157,...)`(`:89,119,178`)与 `logger.warn(194,...)`(`:187`)。`logger.json:242-243` 仍有 158/175 文案,但无调用点 | G(契约变化,需裁决) |
|
||||
|
||||
### 8.3 data-common/store
|
||||
|
||||
| 符号 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|------|------------------------|------------------------------|------|
|
||||
| `TileStore` 全部公开面 | `tileStore.test.ts` 调 `addTile`/`getEvent`/`getData`/`idToNumber`/`numberToId`/`num`/`id` | 全部存在(`packages-user/data-common/src/store/tileStore.ts:18-88`:`getData`/`getEvent`/`getType`/`addTile`/`idToNumber`/`numberToId`/`num`/`id`/`identity`) | —(兼容) |
|
||||
| `GameEventStore` | `eventStore.test.ts` 经 `@user/data-common` barrel 取 `GameEvent`/`GameEventStore` | 存在(`store/eventStore.ts:5` `export class GameEventStore`;`store/index.ts:1`) | —(兼容) |
|
||||
| 码 170/133/134/181 | 无(06-COVERAGE-MAP 未登记) | 新增调用点:`logger.warn(170, id)`(`eventStore.ts:16`)、`logger.warn(133, ...)`/`(134, ...)`(`tileStore.ts:35,39`)、`logger.warn(181, ..., 'item'/'enemy')`(`itemStore.ts:13`、`enemyStore.ts:13`) | 覆盖缺口(见 §9) |
|
||||
|
||||
### 8.4 data-base/enemy
|
||||
|
||||
| 符号 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|------|------------------------|------------------------------|------|
|
||||
| `EnemyManager` 构造 | `manager.test.ts` 经 `./manager` 动态导入后构造(`manager.test.ts:38,42`) | `constructor(private readonly tileStore: ITileStore) {}`(`packages-user/data-base/src/enemy/manager.ts:35`)——**首参为 tileStore,且构造器不再接收 legacy bridge** | F(需执行期核对实参个数) |
|
||||
| `IEnemyLegacyBridge` 类型 | `manager.test.ts:6` `type IEnemyLegacyBridge`;`:58` 以假桥接对象作协作 | `enemy/types.ts` 是否仍导出 `IEnemyLegacyBridge` 需执行期确认(核心装配 `core.ts:150` 已 `new EnemyManager<IEnemyAttr>(this.tileStore)`,全仓 `EnemyLegacyBridge` 仅在 `data-state/src/enemy/legacy.ts:4`;`data-state/src/enemy/index.ts:5` 仍 `export * from './legacy'`) | F |
|
||||
| 码 53/96/117/118/119/120 | `manager.test.ts`/`enemy.test.ts`/`saveLoad.test.ts` 断言 | 全部存在:53(`manager.ts:51`)、117(`:113`)、119(`:168`)、118(`:185`)、96(`enemy.ts:27`)、120(`enemy.ts:102`) | —(码在,断言值待核) |
|
||||
|
||||
### 8.5 data-base/flag
|
||||
|
||||
| 符号 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|------|------------------------|------------------------------|------|
|
||||
| `FlagSystem` 容器面 | `flag/system.test.ts` 调 `occupied`/`setField`/`getField`/`getOrInsert`/`getOrInsertComputed`/`deleteField`/`setFieldValue`/`addFieldValue`/`getFieldValue`/`getFieldValueDefaults` | 全部存在(`packages-user/data-base/src/flag/system.ts:9-58`) | —(兼容) |
|
||||
| `FlagCommonField` 码 111 | `logger.warn(111, String(this.key))`(`flag/field.ts:28`) | 存在 | —(兼容) |
|
||||
|
||||
### 8.6 data-base/map(失败最集中)
|
||||
|
||||
| 符号 / 行为 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|-------------|------------------------|------------------------------|------|
|
||||
| `DirectionMapper` 注入 | `directionMapper: new DirectionMapper()`(11 个 map 测试文件,见 §8.1) | 已删除(见 §8.1) | A |
|
||||
| `MapState` 构造 | `new MapState(tileStore, state)`(`packages-user/data-base/src/map/tile.test.ts:96`) | `constructor(readonly state: IDataCommon) {}`(`mapState.ts:36`)——**单参 `state`** | F |
|
||||
| `IGameMap.setLayerAlias` | `map.setLayerAlias(layer, 'event')`(`gameMap.test.ts:121,125,136,261-263`;`mapState.test.ts:122`;`coreEventLayer.test.ts:20,97`) | **方法已不存在**;别名改为在加层时传入:`addLayer(alias: string): IMapLayer`(`map/types.ts:654`;实现 `gameMap.ts:61-71`,逐字 `addLayer(alias: string): IMapLayer`,内部 `this.aliasLayerMap.set(alias, layer)`) | F |
|
||||
| `addLayer()` 无参调用 | `map.addLayer()`(`gameMap.test.ts:106,118,119,135,175,182,200,216,242,249,258-260`;`mapState.test.ts:121`;`event.test.ts:73`;`saveablesRoundTrip.test.ts:135`;`coreNode.test.ts:21`;`saveables.perf.ts:198`) | `addLayer(alias: string)` 为必填参(`gameMap.ts:61`)。无参调用运行时 alias 为 `undefined`,随后 `setLayerAlias` 缺失才炸;**对齐时须改为 `addLayer('<alias>')`** | F |
|
||||
| `addHook(...).load()` 链 | `layer.addHook({...}).load()`(`mapLayer.test.ts:149,353,574,605,660,681`);`map.addHook({...}).load()`(`gameMap.test.ts:104,154,223`);`mover.test.ts:180` | 同 §8.2:`addHook` 返回 `IHookController`(`packages/common/src/hook.ts:23-32`;`types.ts:52-60`) | D |
|
||||
| 码 84(重复别名) | `gameMap.test.ts:116,127` `expect(...code).toContain(84)` | **`gameMap.ts` 当前只发 131**(`gameMap.ts:129` `logger.warn(131)`),无 84 调用点 | G |
|
||||
| 码 130(非本层图块) | `mapLayer.test.ts:584,591` `toContain(130)` | **`mapLayer.ts` 当前无 130 调用点**(现发 8/9/80/81/123/124/127/128/129/46,见 `mapLayer.ts:180,196,237,245,265,352,357,398,402,413,472,871,902,908`) | G |
|
||||
| 码 62/63/64/125(raw 校验) | `mapState.test.ts` 断言(06-COVERAGE-MAP:57-60 登记) | **`mapState.ts` 当前只发 60/61/121/55/122**(`:45,57,100,263,272`);无 62/63/64/125 调用点 | G |
|
||||
| `getMapData()` | `layer.getMapData()` / `getMapData(x,y,w,h)`(`mapLayer.test.ts:165,176-178,186,197,208`;`saveLoad.test.ts:111,266`) | 两个重载均存在(`map/types.ts:332,340-345`;实现 `mapLayer.ts:220-260`) | —(兼容) |
|
||||
| `DynamicTileMover` 构造 | `map/mover.test.ts` | `constructor(public readonly tile: IDynamicTile)`(`map/mover.ts:18`),内部 `tile.state.faceManager.get(DYNAMIC_MOVER_FACE)`(`:19-20`),缺 handler 发 192(`:47`) | F(依赖 faceManager 预注册) |
|
||||
| 码 126 / 192 | `mapLayer.test.ts`(126,06-COVERAGE-MAP:66) | `logger.warn(126, ...)`(`map/mover.ts:42`);`logger.warn(192)`(`map/mover.ts:47`,192 无覆盖) | —/覆盖缺口 |
|
||||
|
||||
### 8.7 data-base/hero
|
||||
|
||||
| 符号 / 行为 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|-------------|------------------------|------------------------------|------|
|
||||
| 录像桩 `route` vs `array` | 桩对象 `{ route: { add } }` 或 `route: ReplayRouteStub`(`equipment.test.ts:77,86-89`;`items.test.ts:62`;`follower.test.ts:67`;`mover.test.ts:48`) | 生产写入面为 `replay.array.add(...)`:`equipment.ts:196,214`、`items.ts:101`、`mover.ts:181-190,223`。桩必须暴露 `array: { add }`(保留 `disable`/`revert`) | C |
|
||||
| `addHook(...).load()` 链 | `controller.addHook({...}).load()`(`follower.test.ts:125,187,215,241,282,311,334,355`);`rendering.addHook(hook).load()`(`rendering.test.ts:68`);`controller.load()`(`rendering.test.ts:81`);`hero.addHook({...}).load()`(`state.test.ts:151,158`);`location.addHook({...}).load()`(`location.test.ts:86,105`) | 同 §8.2(`hook.ts:23-32`;`types.ts:52-60`) | D |
|
||||
| `HeroItems.getItem` | `env.items.getItem('key')` / `env.items.getItem('missing')`(`items.test.ts:137,179`) | **`HeroItems` 已无 `getItem`**;公开面为 `getItemState`/`itemCount`/`addItem`(实现 `items.ts:40,46,51`;接口 `hero/types.ts:621 addItem`, `:627 getItemState`)。用例注释自述「getItem 等价于增加一个道具」,替代面即 `addItem` | F |
|
||||
| `HeroLocation.setFloor` 参数 | `location.setFloor('F2')` / `setFloor('F1')` / `setFloor(undefined)`(`location.test.ts:107,110`;`saveLoad.test.ts:284,289,511,518,543,593,599`;`event.test.ts:76`;`saveablesRoundTrip.test.ts:127,165`;`replayPlayback.test.ts:124`) | `setFloor(map: IGameMap): void`,内部 `this.floorId = map.floorId`(`location.ts:55-59`;接口 `hero/types.ts:331` 逐字 `setFloor(map: IGameMap | null): void;`——**实现与接口签名不一致,实现非空**)。字符串调用需改为传真实 `IGameMap`;`setFloor(undefined)` 在实现下不可表达 | F / G(需裁决,见 Open Q) |
|
||||
| `HeroEquipment` 构造 | `new HeroEquipment<IHeroAttr>(store, attribute)`(`equipment.test.ts:154`) | `constructor(private readonly store, private readonly attribute)`(`equipment.ts:21-26`) | —(兼容) |
|
||||
| `HeroFollowersController` 构造 | `new HeroFollowersController(state, location, faceHandler)`(`follower.test.ts:91`) | `constructor(state, heroLocation, faceHandler)`(`follower.ts:101-110`) | —(兼容) |
|
||||
| `HeroState` 构造 | 经 `createEnv` 装配 | `constructor(state, faceHandler, attribute)`(`state.ts:37-51`) | —(兼容) |
|
||||
| `alpha`/`setAlpha`/`addFollower`/`removeFollower` | `follower.rendering.alpha`、`setAlpha`、`controller.addFollower(...)`(`follower.test.ts:129,137,285` 等) | 全部存在:`rendering.ts:15,29`;`follower.ts:131 addFollower`, `:196 removeFollower`;接口 `hero/types.ts:436,459,525,562` | —(兼容;此前的 `reading 'alpha'` 系上层桩缺字段连带) |
|
||||
| 码 108/109/116/142/144/146/147/176 | 各测试断言 | 全部存在:`attribute.ts:83,104,180,260`;`follower.ts:47`;`mover.ts:150,193`;`equipment.ts:165,183,208,243,265,269,280` | —(码在,断言值待核) |
|
||||
| 码 58/59 | `equipStore.test.ts`/`saveLoad.test.ts` | `equipStore.ts:362,374` | —(兼容) |
|
||||
| 码 193 | 无(06-COVERAGE-MAP 未登记) | `logger.warn(193, raw.num.toString())`(`items.ts:144`,loadState 缺 item id 注册) | 覆盖缺口 |
|
||||
|
||||
### 8.8 data-system/combat
|
||||
|
||||
| 符号 / 行为 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|-------------|------------------------|------------------------------|------|
|
||||
| `addHook(...).load()` 链 | `combat.test.ts:442,474,499`(`.load()`) | 同 §8.2(`hook.ts:23-32`) | D |
|
||||
| `CombatFlow` 构造 | `combat.test.ts` 装配 | `constructor(readonly state: IStateBase) { super(); }`(`combat.ts:38-40`)——需传 state | F(需核验测试实参) |
|
||||
| `bindContext`/`bindDamage` 一致性校验 | `combat.test.ts` 断言 138/139/140/141 | `logger.warn(138, 'an enemy context object')`(`combat.ts:62`)、`(138, 'a damage context object')`(`:75`)、`(140)`(`:119`)、`(139, ...)`(`:179,211,215,233,237`)、`(141)`(`:184`) | —(码在) |
|
||||
| 码 97/98/99/100/101/110 | `context.test.ts` | 全部存在且带 `import.meta.env.DEV` 守卫(`context.ts:401`=97、`456/767`=100、`465`=99、`485/506`=98、`705`=110、`776/786/796`=101)。**注意**:Vitest 默认 `mode=test`,`import.meta.env.DEV` 为 `true`,故 98/99/101 会触发;若测试改为生产模式构建则不会触发 | —(码在;断言依赖 DEV) |
|
||||
| 码 102/103/104 | `mapDamage.test.ts` | `mapDamage.ts:153`=104、`:197/355`=103、`:351`=102 | —(码在) |
|
||||
| 码 106/107 | `damage.test.ts` | `damage.ts:76,100,190`=107;`:80,104,126,194`=106 | —(码在) |
|
||||
|
||||
### 8.9 data-system/event
|
||||
|
||||
| 符号 / 行为 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|-------------|------------------------|------------------------------|------|
|
||||
| `DirectionMapper` | `eventDispatch.test.ts:69,104,143` | 已删除(见 §8.1) | A |
|
||||
| 码 171/172 | `eventDispatch.test.ts` 覆盖 | `event/executor.ts:39,46`=172;`:66,73`=171 | —(码在) |
|
||||
| 事件注册面 | `eventDispatch.test.ts` | `event/index.ts:1-3`(`./system`、`./executor`、`./types`) | —(兼容) |
|
||||
|
||||
### 8.10 data-system/path(接口整体改名)
|
||||
|
||||
| 符号 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|------|------------------------|------------------------------|------|
|
||||
| `useMapState` | `system.finder.useMapState(maps)`(`system.test.ts:339`;`performance.test.ts:361`;`replayPlayback.test.ts:109`);`builder.useMapState(maps)`(`graph.test.ts:276`;`performance.test.ts:368`) | **方法不存在**。`IPathFinder` 现为 `useMapLayer(layer: IMapLayer | null)`(`path/types.ts:125`;实现 `finder.ts:107-115`,转发 `this.graph.useMapLayer(layer)`)。`IMapGraphBuilder.useMapLayer(layer: IMapLayer | null)`(`path/types.ts:52`;实现 `graph.ts:34-39`) | F |
|
||||
| `useDirGroup` | `graph.test.ts:334`(注释/用法) | **方法不存在**。改为 `useFaceHandler(face: IFaceHandler<number> | null)`(`path/types.ts:70` builder / `:143` finder;实现 `graph.ts:49-51`、`finder.ts:125-127`) | F |
|
||||
| 方向解析方式 | 测试用 `new DirectionMapper()` 作 `directionMapper` | `graph.ts:102` 遍历 `face.mapMovement()`(`IFaceHandler`),不再经 `IDirectionMapper` | F |
|
||||
| `PathfindingSystem` 构造 | `system.test.ts` 装配 | `constructor(readonly state: IStateBase) { this.finder = new PathFinder(state); }`(`system.ts:25-27`) | F(需核验实参) |
|
||||
| `useCostFunction`/`usePassPredicate` | 测试已覆盖 `usePassPredicate` 语义 | 存在(`path/types.ts:58,64,131,137`) | — |
|
||||
| 码 173/182/183 | 无(06-COVERAGE-MAP 未登记) | `graph.ts:70,74,78`=173、`:82`=183;`finder.ts:110`=182;`system.ts:40`=173 | 覆盖缺口 |
|
||||
|
||||
### 8.11 data-state
|
||||
|
||||
| 符号 / 行为 | 测试当前写法(anchor) | shipped 形状(anchor,逐字) | 类别 |
|
||||
|-------------|------------------------|------------------------------|------|
|
||||
| `createCoreState` | `import { CoreState, createCoreState } from '../src/core'`(`dataClosure.test.ts:15`;`coreNode.test.ts:3`;`saveablesRoundTrip.test.ts:21`;`replayPlayback.test.ts:14`;`enemyCombination.test.ts:20`;`src/replay/commands.test.ts:15`;`test/fixtures/closed-loop.ts:23`;`saveables.perf.ts:12`;`saveablesReal.perf.ts:13`;`mapScenario.perf.ts:16`) | **`createCoreState` 已从 `core.ts` 整体删除**(`core.ts:1-330`,导出仅 `export class CoreState`(`:76`),文件以 `loadState`/`//#endregion` 收尾,无 factory)。新入口 = `new CoreState(config)`,config 形状 `ICoreStateConfig`(见下) | A |
|
||||
| `CoreState` 加载配置 | `new CoreState()`(`event.test.ts:55`,唯一无参构造点);旧夹具 `createCoreState()` 无参 | `constructor(config: Readonly<ICoreStateConfig>)`(`core.ts:111`),构造体内 `config.loadStarter`(`:205`)、`config.coreURL`(`:207`)。`ICoreStateConfig` 逐字:`readonly loadStarter: ILoadTaskStarter;` / `readonly coreURL: string;`(`data-state/src/types.ts:7-15`)。无参构造 → `Cannot read properties of undefined (reading 'loadStarter')`(失败族 B)。参考实例:`new CoreState({ loadStarter: new WebLoadStarter(), coreURL: 'placeholder' })`(`ins.ts:11-14`)。Node 测试需一个 `ILoadTaskStarter` 实现(`packages/loader/src/starter.ts:3` 仅 `WebLoadStarter`;`packages/loader/src/types.ts:186` 为接口) | B |
|
||||
| `CoreState.initMapState` | `initializer.initMapState(floors, data)`(`src/coreEventLayer.test.ts:44,137`);`FakeMapState`/`CoreInitializer` 骨架(`:42-45`) | **`initMapState` 已从 `core.ts` 删除**;职责现由 `MapState.fromRaw(raw)` 承担(`mapState.ts:40-95`,逐字:`fromRaw(raw: IMapRawData): IGameMap | null`,内部 `createMap`→`addLayer(alias)`→`setEventLayer`→事件点位)。**注意 `fromRaw` 参数为单个 raw 对象**,与旧 `(floors, data)` 双参形状不同 | A / F |
|
||||
| 顶层 `src/legacy/` 模块 | `import { LegacyTileData, TileLegacyBridge } from '../src/legacy/tile'`(`src/tileLegacy.test.ts:3`);`vi.mock('./legacy', ...)`(`src/coreEventLayer.test.ts:59`) | **`data-state/src/legacy/` 目录不存在**(glob `data-state/src/legacy/**` = 0 文件);`TileLegacyBridge`/`LegacyTileData` 在全仓源码 0 命中(仅 `.planning` 与本测试)。`core.ts` 已不再装配 legacy bridge(对比 `core.ts:1-224` 无相关 import) | E(测试对象消失) |
|
||||
| `event.test.ts` 装配 | `new CoreState()`(`:55`);`map.addLayer()`(`:73`);`state.hero.location.setFloor('F1')`(`:76`) | 见 B / F / F 各条 | B / F |
|
||||
| `data-state` 夹具目录 | `test/fixtures/closed-loop.ts`(`closed-loop.ts:23,64`)随迁后路径变化 | 迁移层面(D-02) | 迁移 |
|
||||
| 码 112/113/177/178 | `saveablesRoundTrip.test.ts` | `core.ts:259,281,306,325` | —(码在) |
|
||||
| 码 2001–2008 | `src/replay/commands.test.ts` | `src/replay/commands.ts:43,52,96,108,136,160,193,218` | —(码在) |
|
||||
| 码 137 | `src/enemy/calculator.test.ts` | `src/enemy/calculator.ts:94` | —(码在) |
|
||||
| 码 66/67/68/69、1001 | 无(06-COVERAGE-MAP 未登记) | `loader/jsoncProcessor.ts:16,25`;`loader/loader.ts:122`;`loader/hook.ts:9`;`event/map.ts:26` | 覆盖缺口 |
|
||||
|
||||
## 数据端错误码覆盖表(研究任务 2)
|
||||
|
||||
**盘点口径(D-07):** 以 `packages/common/src/logger.json`(权威码表,全 282 行已读)为准,从 `packages-user/data-{common,base,system,state}/src` 的 `logger.error(`/`logger.warn(` 调用点反推。共扫描到 **102 个唯一码**(按包去重后:data-common 26、data-base 38、data-system 20、data-state 18)。
|
||||
|
||||
**对照基线:** `06-COVERAGE-MAP.md` 表列 **88 个码**(combat 15 + calculator 1 + enemy 4 + replay 17 + hero 7 + map 21 + common/flag 3 + save/load 11 + mover 1 + commands 8)。
|
||||
|
||||
**判定结果:**
|
||||
- **已发出且已覆盖:74 个**(102 − 21 未覆盖 − 7 陈旧)。
|
||||
- **已发出但 06-COVERAGE-MAP 无覆盖(缺口):21 个。**
|
||||
- **06-COVERAGE-MAP 有登记但当前源码无发出点(陈旧/契约变化):7 个。**
|
||||
|
||||
### 9.1 缺口清单(当前发出、覆盖表未登记 — 21 个)
|
||||
|
||||
| code | 归属模块(emit anchor) | 说明 |
|
||||
|------|--------------------------|------|
|
||||
| 70 | `data-common/src/replay/array.ts:405,728` | 编码/解码未知 param type(`logger.error(70, 'encode'/'decode', ...)`) |
|
||||
| 72 | `data-common/src/replay/sandbox.ts:136` | 回放步执行/finalize 失败(统一收口,取代旧 158/175) |
|
||||
| 73 | `data-common/src/replay/sandbox.ts:84,93` | 非法 `getPassive` 调用 |
|
||||
| 133 | `data-common/src/store/tileStore.ts:35` | `addTile` 重复 num |
|
||||
| 134 | `data-common/src/store/tileStore.ts:39` | `addTile` 重复 id |
|
||||
| 170 | `data-common/src/store/eventStore.ts:16` | 事件 id 重复注册 |
|
||||
| 179 | `data-common/src/replay/array.ts:448,500,544` | 越界 index(`insert`/`delete`/`set`),Phase 7 新增 |
|
||||
| 181 | `data-common/src/store/itemStore.ts:13`、`enemyStore.ts:13` | store 重复注册覆盖 |
|
||||
| 194 | `data-common/src/replay/sandbox.ts:187` | 主动步后出现被动步 |
|
||||
| 192 | `data-base/src/map/mover.ts:47` | `faceManager` 缺 Dir8 handler |
|
||||
| 193 | `data-base/src/hero/items.ts:144` | `loadState` 缺 item id 注册 |
|
||||
| 171 | `data-system/src/event/executor.ts:66,73` | 事件 id 不在 eventStore |
|
||||
| 172 | `data-system/src/event/executor.ts:39,46` | 事件返回非布尔 |
|
||||
| 173 | `data-system/src/path/graph.ts:70,74,78`、`system.ts:40` | 图构建缺绑定(旧码,仍发出) |
|
||||
| 182 | `data-system/src/path/finder.ts:110` | `useMapLayer` state 不一致 |
|
||||
| 183 | `data-system/src/path/graph.ts:82` | 起始点越界 |
|
||||
| 66 | `data-state/src/loader/jsoncProcessor.ts:16` | prefixed jsonc 前缀缺失 |
|
||||
| 67 | `data-state/src/loader/jsoncProcessor.ts:25` | prefixed jsonc 解析失败 |
|
||||
| 68 | `data-state/src/loader/loader.ts:122` | extra config id 冲突 |
|
||||
| 69 | `data-state/src/loader/hook.ts:9` | 上一加载阶段 core config 未加载 |
|
||||
| 1001 | `data-state/src/event/map.ts:26` | `setBlock` 未知图块 |
|
||||
|
||||
> 注:173 在 `06-COVERAGE-MAP.md` 正文(02 相关小节)曾被提及,但**不在覆盖表内**,故计为缺口;补测计划需明确它是否属于本阶段新增覆盖(D-07),或经用户确认归入 path 子系统专项。
|
||||
|
||||
### 9.2 陈旧登记(覆盖表有、当前源码无发出 — 7 个)
|
||||
|
||||
| code | `06-COVERAGE-MAP.md` 登记 | 当前源码 | 需裁决 |
|
||||
|------|---------------------------|----------|--------|
|
||||
| 62 | `mapState` raw key 非数字(`06-COVERAGE-MAP.md:58`) | `mapState.ts` 无 62 调用点(现发 60/61/121/55/122) | 契约是否已取消,或测试应删除 |
|
||||
| 63 | `mapState` 容器缺失(`:59`) | 无调用点 | 同上 |
|
||||
| 64 | `mapState` 非法值/类型(`:60`) | 无调用点 | 同上 |
|
||||
| 84 | `gameMap` 重复别名(`:63`) | `gameMap.ts` 无 84;别名改由 `addLayer(alias)` 承担 | 契约是否已取消 |
|
||||
| 130 | `mapLayer` 非本层图块(`:70`) | `mapLayer.ts` 无 130 | 契约是否已取消 |
|
||||
| 158 | `sandbox` 执行失败(`:39`) | 无 158;改 `logger.error(72, method)`(`sandbox.ts:136`) | 契约码迁移(158→72) |
|
||||
| 175 | `sandbox` notExecuted 失败(`:45`) | 无 175;同上 | 契约码迁移 |
|
||||
|
||||
> 另:`06-COVERAGE-MAP.md:210` 正文提到码 125(`mapState` 排序楼层集不一致),但当前 `mapState.ts` 无 125 调用点,且 125 未进入表。补测盘点时应一并裁决。
|
||||
|
||||
### 9.3 码表文案可识别性(供补测断言)
|
||||
|
||||
- 码表权威在 `packages/common/src/logger.json`;示例逐字:`"147": "No available equipment slot to equip $1."`(`logger.json:232`)、`"179": "Replay $1 received an out-of-range index $2, ..."`(`:264`)。
|
||||
- 断言机制沿用 `logger.catch(fn)` 与 `logger` spy(Phase 6 已建立,`packages/common/src/logger.ts`)。
|
||||
- 不可达码 147 的 `it.skip` 保留(D-04;`data-base/src/hero/equipment.test.ts:352-353` 注释 + skip,`logger.json:232` 文案)。
|
||||
|
||||
## 公共接口覆盖表(研究任务 3)
|
||||
|
||||
> 口径:以各包 barrel `index.ts` 与 `types.ts` 的公开面为准,对照 `06-COVERAGE-MAP.md` 模块归属与当前测试文件。标 ✅ = 有测试覆盖;⚠️ = 部分/待执行期核验;❌ = 当前无测试覆盖。
|
||||
|
||||
### 10.1 data-common(Layer 0 公共层)
|
||||
|
||||
| 公开面(barrel anchor) | 主要接口/类 | 覆盖 |
|
||||
|-------------------------|-------------|------|
|
||||
| `common`(`data-common/src/common/index.ts:1-5`) | `RoleFaceBinder`、`FaceManager`/`Dir4FaceHandler`/`Dir8FaceHandler`、`MapLocIndexer`、`ObjectMover` 及 `ObjectMoveType`/`ObjectAnimDirection` | ✅(`face`/`faceManager`/`indexer`/`mover` 测试;**唯一断裂 = `utils.test.ts` 引已删模块**) |
|
||||
| `event`(`data-common/src/event/index.ts:1-2`) | `GameEvent`、事件类型 | ✅(`eventStore.test.ts` 经 barrel) |
|
||||
| `replay`(`data-common/src/replay/index.ts:1-5`) | `ReplayArray`、`ReplaySandbox`、`ReplaySystem`、安全收集装饰器 | ✅(`array`/`sandbox`/`system`/`func`/`saveLoad` 测试) |
|
||||
| `save`(`data-common/src/save/index.ts:1`) | `SaveCompression` 等 | ⚠️(经各 saveLoad 测试间接) |
|
||||
| `store`(`data-common/src/store/index.ts:1-5`) | `TileStore`/`ItemStore`/`MapStore`/`GameEventStore` | ✅(`tileStore`/`eventStore`;Item/Map store 经上层) |
|
||||
| `types`(`data-common/src/types.ts`) | `IEnemyAttr`、`IHeroAttr`、`IDataCommon`、`IDataCommonExtended` | ⚠️(结构类型,无独立测试,合理) |
|
||||
|
||||
### 10.2 data-base(Layer 1 数据层)
|
||||
|
||||
| 公开面(barrel anchor) | 主要接口/类 | 覆盖 |
|
||||
|-------------------------|-------------|------|
|
||||
| `enemy`(`data-base/src/enemy/index.ts:1-4`) | `Enemy`、`EnemyManager`、special | ✅(`enemy`/`manager`/`special`/`saveLoad`) |
|
||||
| `flag`(`data-base/src/flag/index.ts:1-3`) | `FlagSystem`、`FlagCommonField` | ✅(`system`/`saveLoad`) |
|
||||
| `hero`(`data-base/src/hero/index.ts`) | `HeroState`/`HeroAttribute`/`HeroEquipment`/`HeroEquipsStore`/`HeroItems`/`HeroFollowersController`/`HeroLocation`/`HeroMover`/`HeroRendering`/修饰器 | ✅(11 个测试文件;`getItem` 已删、`setFloor` 签名变化导致部分红) |
|
||||
| `map`(`data-base/src/map/index.ts:1-5`) | `GameMap`/`MapState`/`MapLayer`/`DynamicTileMover`/tile | ✅(11 个测试文件;`DirectionMapper`/`setLayerAlias`/`MapState` 构造/`.load()` 导致大面积红) |
|
||||
| `types`(`data-base/src/types.ts`) | `IStateBase`、`IStateSaveData`、`IDataBaseExtended` | ⚠️(结构类型) |
|
||||
|
||||
### 10.3 data-system(Layer 2 系统层)
|
||||
|
||||
| 公开面(barrel anchor) | 主要接口/类 | 覆盖 |
|
||||
|-------------------------|-------------|------|
|
||||
| `combat`(`data-system/src/combat/index.ts`) | `CombatFlow`、`DamageSystem`、`EnemyContext`、`MapDamage`、`enemy.ts` | ✅(`combat`/`damage`/`context`/`mapDamage` + 2 perf) |
|
||||
| `event`(`data-system/src/event/index.ts:1-3`) | `GameEventSystem`、executor | ✅(`eventDispatch`) |
|
||||
| `path`(`data-system/src/path/index.ts:1-4`) | `PathFinder`、`MapGraphBuilder`、`PathfindingSystem` | ✅(`graph`/`system`/`performance`;注入面改名致红) |
|
||||
| `types`(`data-system/src/types.ts`) | `IDataSystem` 等 | ⚠️(结构类型) |
|
||||
|
||||
### 10.4 data-state(Layer 3 顶层)
|
||||
|
||||
| 公开面(barrel anchor) | 主要接口/类 | 覆盖 |
|
||||
|-------------------------|-------------|------|
|
||||
| `enemy`(`data-state/src/enemy/index.ts:1-8`) | `CommonAura`/`GuardAura`、`MainDamageCalculator`、`MainEnemyComparer`、`MainEnemyFinalEffect`、`EnemyLegacyBridge`、mapDamage 视图/转换器、`registerSpecials` | ✅(6 个测试) |
|
||||
| `event`(`data-state/src/event/index.ts:1-5`) | 8 个内建函数、`createEventRegistrations` | ✅(`event.test.ts`) |
|
||||
| `hero`(`data-state/src/hero/index.ts:1-3`) | `DefaultHeroMoveTopImpl`、`DefaultPassPredicateImpl` | ⚠️(经集成测试) |
|
||||
| `loader`(`data-state/src/loader/index.ts:1-4`) | `MotaDataLoader`、`DefaultDataLoaderHook`、`PrefixedJSONCProcessor` | ❌(无独立 loader 测试,且码 66/67/68/69 未覆盖) |
|
||||
| `replay`(`data-state/src/replay/index.ts:1`) | `ReplayMove`/`ReplayTeleport`/`ReplayUseItem`/`ReplayEquip`/`ReplayUnequip` | ✅(`commands.test.ts`) |
|
||||
| `common`(`data-state/src/common.ts`) | 顶层公共导出 | ⚠️ |
|
||||
| `core`(`data-state/src/core.ts`) | `CoreState` | ✅(多集成测试;`createCoreState` 删除、构造签名变化致红) |
|
||||
| `ins`(`data-state/src/ins.ts`) | 兼容 singleton `state` | ❌(无测试,属兼容层,合理) |
|
||||
| `shared`(`data-state/src/shared.ts`) | `TILE_WIDTH`/`TILE_HEIGHT`/zIndex 常量/`HERO_DEFAULT_ATTRIBUTE` | ⚠️(经 CoreState 间接) |
|
||||
| `types`(`data-state/src/types.ts`) | `ICoreStateConfig`、`ICoreState`、`ICoreStateExtended` | ⚠️(结构类型) |
|
||||
|
||||
**覆盖结论:** 公共接口面已由 Phase 6 基本铺满。本阶段**不需要新增接口**(D-05);覆盖工作集中在 §9.1 的 21 个错误码 + `loader` 子系统的独立覆盖缺口。
|
||||
|
||||
## Standard Stack
|
||||
|
||||
> 本阶段**不安装任何外部包**(纯测试重构 + 对齐),故无 Package Legitimacy Audit。以下为既有测试栈(只读)。
|
||||
|
||||
### Core
|
||||
| Library | Version | Purpose | 依据 |
|
||||
|---------|---------|---------|------|
|
||||
| vitest | `^4.0.18` | 测试运行器(`test:ci`/`test:perf`) | `package.json:105`;配置 `vite.config.ts`、`vitest.perf.config.ts` |
|
||||
| vue-tsc / typescript | `^2.2.12` / `6.0.3` | 类型面(本阶段不设 `check:type` 门禁) | `package.json:99,106` |
|
||||
| tsx | `^4.21.0` | 脚本执行(`test:data-node`) | `package.json:17,98` |
|
||||
|
||||
### Supporting
|
||||
| Library | Version | Purpose | When to Use |
|
||||
|---------|---------|---------|-------------|
|
||||
| `@motajs/common` `logger`/`Hookable`/`IFaceHandler` | workspace | 断言日志码、钩子/朝向驱动 | 全部测试 |
|
||||
| `@user/data-*` barrels | workspace | 被测面 + 类型 | 全部测试 |
|
||||
|
||||
**Installation:** 无需新增依赖。若 Node 环境需要非 Web 的 `ILoadTaskStarter` 以替代 `WebLoadStarter`,优先复用 `packages/loader` 既有实现或测试内 inline stub,**不得新增依赖**(除非用户批准)。
|
||||
|
||||
**Version verification:** 版本取自 `package.json`(本会话已读),未联网核验;本阶段不引入新包,风险为零。
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### System Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 迁移计划(D-06) │
|
||||
│ src/**/*.test.ts ──move──▶ src/**/__test__/ │
|
||||
│ data-state/test/ ─move──▶ data-state/__test__/ + fixtures/ │
|
||||
│ 修相对导入;不改生产、不改配置 │
|
||||
└───────────────┬─────────────────────────┘
|
||||
│(文件数守恒校验)
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ 对齐计划(按子系统,D-05 只对齐不改接口) │
|
||||
│ │
|
||||
│ shipped 源码(唯一事实源) ◀──对照── 测试断言 │
|
||||
│ core.ts / types.ts / *.ts *.test.ts │
|
||||
│ │ ▲ │
|
||||
│ │ 失败族 A..G 分类 │ │
|
||||
│ └──────────── 逐文件「旧写法→新形状」──┘ │
|
||||
└───────────────┬───────────────────────────────────────────┘
|
||||
│(接口面收敛后)
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ 覆盖计划(D-07) │
|
||||
│ logger.json 码表 ─┐ │
|
||||
│ 源码 logger.* 调用点 ─┴─▶ 码→模块→用例 覆盖矩阵 │
|
||||
│ 21 缺口 + 7 陈旧 ─▶ 补测 / 裁决删除 │
|
||||
└───────────────┬───────────────────────────────────────────┘
|
||||
▼
|
||||
验收:pnpm test:ci(66 文件全绿,1 skip 保留) + pnpm test:perf(6 文件可跑)
|
||||
```
|
||||
|
||||
### Recommended Project Structure(迁移目标,D-02)
|
||||
|
||||
```
|
||||
packages-user/data-common/src/
|
||||
├── common/__test__/ # face/faceManager/indexer/mover 测试
|
||||
├── event/__test__/
|
||||
├── replay/__test__/
|
||||
├── save/__test__/
|
||||
└── store/__test__/
|
||||
packages-user/data-base/src/
|
||||
├── enemy/__test__/
|
||||
├── flag/__test__/
|
||||
├── hero/__test__/
|
||||
└── map/__test__/
|
||||
packages-user/data-system/src/
|
||||
├── combat/__test__/
|
||||
├── event/__test__/
|
||||
└── path/__test__/
|
||||
packages-user/data-state/
|
||||
├── __test__/ # 原 test/ 迁入;fixtures/ 随迁
|
||||
└── src/
|
||||
├── enemy/__test__/
|
||||
├── event/__test__/
|
||||
├── replay/__test__/
|
||||
└── ...(coreEventLayer.test.ts → src/__test__/)
|
||||
```
|
||||
|
||||
### Pattern 1: `addHook` 后的控制器(对齐 D 族)
|
||||
**What:** `Hookable.addHook(hook)` 注册即生效,返回 `IHookController`(仅 `unload()`)。
|
||||
**When to use:** 所有 `*.addHook({...})` 调用点。
|
||||
**Example:**
|
||||
```ts
|
||||
// Source: packages/common/src/hook.ts:23-32, packages/common/src/types.ts:52-60
|
||||
const controller = layer.addHook({ onUpdateBlock: (block, x, y) => { ... } });
|
||||
// 旧写法(错误):layer.addHook({...}).load();
|
||||
// 结束时若需卸载:controller.unload();
|
||||
```
|
||||
|
||||
### Pattern 2: 录像桩形状(对齐 C 族)
|
||||
**What:** 生产写入经 `replay.array.add(code, params)`,且 `shouldReplay` 包裹的读取会 `disable()`/`revert()`。
|
||||
**Example:**
|
||||
```ts
|
||||
// Source: packages-user/data-base/src/hero/equipment.ts:196,214; packages-user/data-common/src/replay/system.ts:27
|
||||
const commands: [ReplayCode, unknown[]][] = [];
|
||||
let disabled = 0;
|
||||
const replaySystem = {
|
||||
array: { add(code, params) { if (disabled > 0) return; commands.push([code, params]); } },
|
||||
disable: () => { disabled++; },
|
||||
revert: () => { if (disabled > 0) disabled--; }
|
||||
};
|
||||
// 旧写法(错误):{ route: { add } }
|
||||
```
|
||||
|
||||
### Anti-Patterns to Avoid
|
||||
- **用 `as never` / `Object.create` 把已删除成员「假装」出来**:`07-16-PLAN.md:484/599` 已明令禁止;本阶段延续。
|
||||
- **改生产文件让测试转绿**:D-10 禁止;仅经用户确认的「重构遗漏」才可最小修复。
|
||||
- **删测试用例以图全绿**:D-04 要求「全绿 = 所有测试通过」,仅不可达码 147 的既有 `it.skip` 可保留;删除文件/用例须用户裁决。
|
||||
|
||||
## Don't Hand-Roll
|
||||
|
||||
| Problem | Don't Build | Use Instead | Why |
|
||||
|---------|-------------|-------------|-----|
|
||||
| Node 环境的 `ILoadTaskStarter` | 自写一套加载器 | 复用 `WebLoadStarter`(`packages/loader/src/starter.ts:3`)或测试内 inline stub;先问用户 | 避免引入非授权设计 |
|
||||
| 朝向位移/降级/旋转 | 在新测试里重写 `getFaceMovement` 等 | `IFaceHandler` 的 `degrade`/`movement`/`next`/`dirOf`(`faceManager.ts:94-216`) | 旧工具已删,接口是 shipped 面 |
|
||||
| 图块/地图 fixture 装配 | 自造地图数据结构 | `MapState.fromRaw(raw)`(`mapState.ts:40-95`)+ `addLayer(alias)` | 与生产装载路径一致 |
|
||||
| 日志断言 | 直接 `console` | `logger.catch(fn)` / `logger` spy(`packages/common/src/logger.ts`) | Phase 6 既有机制 |
|
||||
|
||||
**Key insight:** 本阶段的复杂度不在「写新代码」,而在「判定旧断言对应的新形状」;任何凭直觉猜测的形状都会在 vitest 的 `parse()`/运行期第一次调用处爆炸,因此每个不明确点都应落到 Open Questions 让用户裁决,而不是自行假设。
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### Pitfall 1: 把 `createCoreState` 当成改名(其实是被删)
|
||||
**What goes wrong:** 试图找 `createCoreState` 的新名字,或保留旧 import 让它静默为 `undefined`。
|
||||
**Why:** `core.ts` 已无 factory;`new CoreState()` 无参又会因 `config.loadStarter` 抛 B 族错误。
|
||||
**How to avoid:** 统一改为 `new CoreState({ loadStarter, coreURL })`;测试夹具需先解决 `loadStarter` 来源(Open Q)。
|
||||
**Warning signs:** `Cannot read properties of undefined (reading 'loadStarter')` 或 `not a function`。
|
||||
|
||||
### Pitfall 2: `addHook(...).load()` 看似只是删 `.load()`
|
||||
**What goes wrong:** 删掉 `.load()` 后忘记 `addHook` 已自动加载;或误以为返回对象是 sandbox 本体而继续链式调用。
|
||||
**Why:** `IHookController` 只有 `unload()`;`hook.awake` 在 `addHook` 内即时调用。
|
||||
**How to avoid:** 逐处把 `x.addHook({...}).load()` 改为 `x.addHook({...})`;如需卸载用返回的 controller。
|
||||
**Warning signs:** `addHook(...).load is not a function`。
|
||||
|
||||
### Pitfall 3: `setFloor` 传字符串
|
||||
**What goes wrong:** 保留 `setFloor('F1')`。
|
||||
**Why:** 实现 `setFloor(map: IGameMap)` 读 `map.floorId`(`location.ts:55-59`),字符串无 `floorId`。
|
||||
**How to avoid:** 先建真实 `IGameMap`(`maps.createMap`/`fromRaw`),再 `setFloor(map)`;`setFloor(undefined)` 分支(`location.test.ts:110`)在实现下不可表达。
|
||||
**Warning signs:** `Cannot read properties of undefined (reading 'floorId')` 或 `expected undefined to be 'F2'`。
|
||||
|
||||
### Pitfall 4: 覆盖表的「陈旧码」被当成待补测
|
||||
**What goes wrong:** 为 62/63/64/84/130/158/175 补测,却发现源码根本不发。
|
||||
**Why:** 用户收尾重构移除了这些调用点/迁移了码(158/175→72)。
|
||||
**How to avoid:** 先按 §9.2 与用户确认这些码是「取消」还是「迁移」,再决定补测或退役对应用例。
|
||||
**Warning signs:** `logger.catch` 得到的 `info` 为空。
|
||||
|
||||
### Pitfall 5: DEV-only 码在非 DEV 模式不触发
|
||||
**What goes wrong:** 98/99/101(`context.ts`)带 `import.meta.env.DEV` 守卫;若测试用生产构建跑则断言失败。
|
||||
**How to avoid:** 保持 Vitest 默认 `mode=test`(DEV=true);不要为这些码切换构建模式。
|
||||
|
||||
## Code Examples
|
||||
|
||||
### 正确构造 CoreState(对齐 B 族)
|
||||
```ts
|
||||
// Source: packages-user/data-state/src/core.ts:111,205-207; src/types.ts:7-15; src/ins.ts:11-14
|
||||
import { CoreState } from './core';
|
||||
import { WebLoadStarter } from '@motajs/loader';
|
||||
|
||||
const state = new CoreState({
|
||||
loadStarter: new WebLoadStarter(),
|
||||
coreURL: 'placeholder'
|
||||
});
|
||||
```
|
||||
|
||||
### 正确建图并设事件层(对齐 map F 族)
|
||||
```ts
|
||||
// Source: packages-user/data-base/src/map/mapState.ts:40-95; gameMap.ts:61; map/types.ts:654
|
||||
const map = state.maps.createMap('F1', 4, 1);
|
||||
const layer = map.addLayer('event'); // 别名在此传入(不再 setLayerAlias)
|
||||
layer.setMapRef(new Uint32Array([1, 1, 1, 1]));
|
||||
map.setEventLayer(layer); // 别名必须为 'event' 才由 fromRaw 自动选为事件层
|
||||
```
|
||||
|
||||
### 正确注入寻路面(对齐 path F 族)
|
||||
```ts
|
||||
// Source: packages-user/data-system/src/path/finder.ts:107,121,125; graph.ts:34,45,49
|
||||
system.finder.useMapLayer(state.maps.get('F1')!.eventLayer);
|
||||
system.finder.usePassPredicate(predicate);
|
||||
system.finder.useFaceHandler(faceHandler); // 取代 useDirGroup
|
||||
// 旧:system.finder.useMapState(state.maps) / builder.useMapState(...)
|
||||
```
|
||||
|
||||
## State of the Art
|
||||
|
||||
| Old Approach | Current Approach | When Changed | Impact |
|
||||
|--------------|------------------|--------------|--------|
|
||||
| `createCoreState()` 无参工厂 | `new CoreState({ loadStarter, coreURL })` | 数据端收尾重构(HEAD `109fad3`) | 测试夹具全部需构造 config |
|
||||
| `CoreState.initMapState(floors, data)` | `MapState.fromRaw(raw)` | 同上 | 初始化职责移出 core;coreEventLayer.test 需重定向或退役 |
|
||||
| `IDataCommon.directionMapper` + `DirectionMapper` | `IFaceManager` + `IFaceHandler`(`degrade`/`movement`/`next`/`dirOf`) | `4aaea68` 后 | map/path 测试大面积改注入面 |
|
||||
| `getFaceMovement`/`degradeFace`/`nextFaceDirection`/`fromDirectionString` | `IFaceHandler` 方法 | 同上 | `utils.ts` 与 `utils.test.ts` 一并消失 |
|
||||
| `IGameMap.setLayerAlias(layer, alias)` | `addLayer(alias)` | 收尾重构 | map 测试需改加层方式 |
|
||||
| `Hookable.addHook(...).load()` | `addHook` 即时加载,返回 `IHookController(unload)` | 收尾重构 | 全数据端 ~30 处 `.load()` 需删 |
|
||||
| 录像写入 `replay.route.add` | `replay.array.add` | `a2a8e6e` | data-base hero 4 个桩需改名 |
|
||||
| 寻路 `useMapState`/`useDirGroup` | `useMapLayer`/`useFaceHandler` | 寻路重构 | path 测试注入面改写 |
|
||||
| `HeroItems.getItem` | `getItemState` / `addItem` | 收尾重构 | items.test 2 处调用 |
|
||||
| `HeroLocation.setFloor(string)` | `setFloor(IGameMap)` | 收尾重构 | 位置/存档测试需真实地图 |
|
||||
| 码 158/175 回放失败 | 统一 `error(72)`;另有 `warn(194)` | 收尾重构 | sandbox.test 断言需改 |
|
||||
|
||||
**Deprecated/outdated:**
|
||||
- `data-state/src/legacy/`(`TileLegacyBridge`/`LegacyTileData`)——已删除,`tileLegacy.test.ts` 失去被测对象。
|
||||
- `DirectionMapper` 与旧朝向工具——已从仓库删除,勿在补测中重建。
|
||||
- 06-COVERAGE-MAP 的 62/63/64/84/130/158/175 登记——当前无发出点(见 §9.2)。
|
||||
|
||||
## Assumptions Log
|
||||
|
||||
| # | Claim | Section | Risk if Wrong |
|
||||
|---|-------|---------|---------------|
|
||||
| A1 | 迁移到 `__test__/` 不需改 `vite.config.ts`/`vitest.perf.config.ts`/`tsconfig.json` | 迁移配置裁决 | 若某配置隐式排除 `__test__`,迁移后文件不被采集 → 需补配置 |
|
||||
| A2 | data-common `mover.test.ts`/`indexer.test.ts` 仅因 `DirectionMapper`/`utils` 连带失败,其余面兼容 | §8.1 | 若 `ObjectMover` 面也变,需追加 delta |
|
||||
| A3 | data-base/enemy、flag 失败主要为连带(fixture 桩)而非独立接口改名 | §8.4/§8.5 | 若 manager 构造/legacy 类型真变,需补 delta |
|
||||
| A4 | data-system/combat 失败主要来自 `.load()` 与 `CombatFlow` 构造实参,而非战斗语义 | §8.8 | 若语义/断言值漂移,需逐用例核 |
|
||||
| A5 | 测试不得删,删除类处置(utils.test/tileLegacy.test/coreEventLayer.test)需用户裁决 | Summary/Open Q | 若用户允许删,迁移计划范围扩大 |
|
||||
| A6 | 陈旧码(62/63/64/84/130/158/175)是重构后的契约变化而非遗漏缺陷 | §9.2 | 若实为遗漏,应走 D-10 生产修复流程 |
|
||||
| A7 | Node 测试可用 `WebLoadStarter` 或 inline stub 满足 `loadStarter` | §8.11/Don't Hand-Roll | 若必须真实加载器,测试装配复杂度上升 |
|
||||
|
||||
## Open Questions(需用户决策)
|
||||
|
||||
1. **【高】`createCoreState` 的替代夹具形态**:`createCoreState()` 已删除。测试应统一改为 `new CoreState({ loadStarter, coreURL })`,但 `loadStarter` 用什么?(a)直接 `new WebLoadStarter()`;(b)测试内 inline stub;(c)其他。**这决定 10 个 data-state 测试文件与 3 个 perf 文件 + `fixtures/closed-loop.ts` 的迁移改法**。
|
||||
- What we know:`ins.ts:11-14` 用 `WebLoadStarter`;`@motajs/loader` 只导出 `WebLoadStarter` 一个实现。
|
||||
- Recommendation:Task 0 让用户拍板;在无新依赖前提下,倾向 (a) 或 (b)。
|
||||
|
||||
2. **【高】`utils.test.ts` 去留**:其被测的 4 个纯函数已从源码整体删除,覆盖职责已由 `faceManager.test.ts` 承接。删除该文件,还是改写为对 `Dir4FaceHandler`/`Dir8FaceHandler` 的等价测试(可能重复)?需用户裁决。
|
||||
|
||||
3. **【高】`tileLegacy.test.ts` 去留**:`data-state/src/legacy/tile` 与 `TileLegacyBridge`/`LegacyTileData` 已不存在。删除该文件(并在 SUMMARY 明写等价覆盖位置),还是重定向到新 legacy/loader 适配路径?
|
||||
|
||||
4. **【高】`coreEventLayer.test.ts` 的 A1/A2 裁决**:`CoreState.initMapState` 已删除,`MapState.fromRaw` 承担同名职责(`mapState.ts:40-95`)。(A1) 重定向到 `MapState.fromRaw` 并保留层序/zIndex/事件层/矩阵判据(会清理已无意义的 `vi.mock('./enemy')`/`vi.mock('./legacy')` 与 `Object.create` 骨架);(A2) 退役该文件(等价覆盖已在 `mapState.test.ts`/`mapLifecycle.test.ts`)。07-16-PLAN 已把该点列为待裁决,本阶段必须落实。
|
||||
|
||||
5. **【中】回放失败码契约(158/175 → 72)**:`sandbox.test.ts` 断言 158/175,但源码现统一发 `error(72)` + `warn(194)`。是(a)改测试断言到 72/194,还是(b)视 158/175 为应保留的契约(需生产修复)?D-05/D-10 下倾向于 (a),须用户确认。
|
||||
|
||||
6. **【中】map 校验码 62/63/64/84/130/125 的处置**:这些码在 06-COVERAGE-MAP 有登记,但当前 `mapState.ts`/`gameMap.ts`/`mapLayer.ts` 无发出点(`fromRaw` 仅校验 60/61,`setLayerAlias`/重复别名告警 84 已随方法删除)。是契约取消(改测试)还是重构遗漏(生产修复)?
|
||||
|
||||
7. **【中】`setFloor(undefined)` 分支**:`location.test.ts:110` 的「清空楼层」用例在 shipped 非空实现(`location.ts:55`)下不可表达。删除该半覆盖,还是允许实现接受 `null`(`hero/types.ts:331` 接口本就声明 `IGameMap | null`,实现与接口不一致)?这可能需要用户在生产侧确认接口/实现对齐。
|
||||
|
||||
8. **【低】`loadStarter` 之外的 loader 码覆盖**:码 66/67/68/69 + 1001 无覆盖;是否纳入本阶段补测计划(D-07),还是归渲染端/后续阶段?
|
||||
|
||||
## Environment Availability
|
||||
|
||||
| Dependency | Required By | Available | Version | Fallback |
|
||||
|------------|------------|-----------|---------|----------|
|
||||
| Node.js | 全部测试 | 未在本会话探测(AGENTS.md 要求命令先获批) | 要求 `>=24.0.0`(`package.json:8`) | — |
|
||||
| pnpm | 安装/脚本 | 未探测 | 要求 `>=12.0.0`(`package.json:9`) | — |
|
||||
| Vitest | `test:ci`/`test:perf` | 声明 `^4.0.18`(`package.json:105`) | 12.5.1(`packageManager`) | — |
|
||||
|
||||
**说明:** 本阶段无外部服务/DB/DOM 依赖(数据端 DOM-free、Node 可跑)。上表版本来自 `package.json` 只读值,未执行 `node --version` 等探测命令(遵循 AGENTS.md「运行任何命令须先获批」)。执行计划可在 Task 0 获批后统一探测。
|
||||
|
||||
## Validation Architecture
|
||||
|
||||
> `workflow.nyquist_validation` 未在 `.planning/config.json` 中显式置 false(`config.json:26` `"nyquist_validation": true`),故本节保留。
|
||||
|
||||
### Test Framework
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Framework | Vitest `^4.0.18`(`package.json:105`) |
|
||||
| Config file | `vite.config.ts`(默认通道);`vitest.perf.config.ts`(perf 隔离通道) |
|
||||
| Quick run command | `pnpm test:ci`(单条 <30s 可用 `pnpm exec vitest run <path> -x`) |
|
||||
| Full suite command | `pnpm test:ci`(66 文件)+ `pnpm test:perf`(6 文件) |
|
||||
|
||||
### Phase Requirements → Test Map
|
||||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||||
|--------|----------|-----------|-------------------|--------------|
|
||||
| TEST-02 | 数据端测试落位 `__test__/` 且被采集 | 结构 | `pnpm test:ci`(文件数 = 66) | 迁移后 ✅ |
|
||||
| TEST-02 | `pnpm test:ci` 全绿(1 skip 保留) | 集成 | `pnpm test:ci` | ❌ 当前 45 failed(本阶段目标) |
|
||||
| TEST-02 | `pnpm test:perf` 全绿 | 集成 | `pnpm test:perf` | ❌ 当前受连带失败影响 |
|
||||
| TEST-02 | 21 个缺口码有触发断言 | 单元 | 各子系统 `*.test.ts` | ❌ Wave 0 补测 |
|
||||
|
||||
### Sampling Rate
|
||||
- **Per task commit:** `pnpm exec vitest run <changed spec paths>`(<30s)
|
||||
- **Per wave merge:** `pnpm test:ci`
|
||||
- **Phase gate:** `pnpm test:ci` 与 `pnpm test:perf` 双绿后 `/gsd-verify-work`
|
||||
|
||||
### Wave 0 Gaps
|
||||
- [ ] 迁移后目录内的测试文件(65 `.test.ts` + 6 `.perf.ts`)——保留与迁移前一致的用例
|
||||
- [ ] `__test__/` 共享夹具(`data-state/__test__/fixtures/closed-loop.ts` 随迁);`loadStarter` 夹具(Open Q1)
|
||||
- [ ] 缺口码补测用例(21 个,见 §9.1)
|
||||
- [ ] 陈旧码处置记录(7 个,见 §9.2)——测试变更或删除均须在 SUMMARY 逐条登记
|
||||
- [ ] Framework install:无(Vitest 已在 devDependencies)
|
||||
|
||||
## Security Domain
|
||||
|
||||
> `security_enforcement` 未显式置 false(`config.json:49` `"security_enforcement": true`,ASVS level 1)。本阶段为**测试重构与对齐**,无新增生产攻击面。
|
||||
|
||||
### Applicable ASVS Categories
|
||||
|
||||
| ASVS Category | Applies | Standard Control |
|
||||
|---------------|---------|-----------------|
|
||||
| V2 Authentication | no | 数据端无认证 |
|
||||
| V3 Session Management | no | 无会话 |
|
||||
| V4 Access Control | no | 无权限面 |
|
||||
| V5 Input Validation | no(仅测试夹具构造合法数据) | `fromRaw`/`addTile`/`logger` 校验为被测对象,不在本阶段修改 |
|
||||
| V6 Cryptography | no | 无手写加密;压缩走既有 `SaveCompression` |
|
||||
|
||||
### Known Threat Patterns for test-refactor
|
||||
|
||||
| Pattern | STRIDE | Standard Mitigation |
|
||||
|---------|--------|---------------------|
|
||||
| 用 `as never`/`Object.create` 伪造已删接口使测试假绿 | Tampering | `07-16-PLAN.md:484/599` 明令禁止;本阶段延续,planner 在 `<fails_when>` 点名 |
|
||||
| 删测试/放宽断言以求全绿 | Repudiation | D-04 只允许保留不可达码 147 的既有 skip;删除/改写须 SUMMARY 逐条登记并经用户裁决 |
|
||||
| 提交用户并发改动文件 | Tampering | D-08 禁止;提交前 `git status --short` 白名单核对 |
|
||||
|
||||
## Sources
|
||||
|
||||
### Primary (HIGH confidence,本会话 Read 的 repo 源)
|
||||
- `packages/common/src/logger.json`(全 282 行,码表权威)
|
||||
- `packages/common/src/{hook.ts,types.ts}`(`Hookable`/`IHookController`)
|
||||
- `packages-user/data-common/src/{index.ts,types.ts,common/{index,face,faceManager,tileStore}.ts,replay/{index,system,sandbox,array}.ts,store/{index,tileStore,eventStore,itemStore,enemyStore}.ts}`
|
||||
- `packages-user/data-base/src/{index.ts,types.ts,map/{index,types,gameMap,mapState,mapLayer,mover}.ts,hero/{location,state,follower,items,equipment,equipStore}.ts,enemy/{index,manager}.ts,flag/system.ts}`
|
||||
- `packages-user/data-system/src/{index.ts,path/{index,types,finder,graph,system}.ts,combat/combat.ts}`
|
||||
- `packages-user/data-state/src/{index.ts,types.ts,core.ts,ins.ts,enemy/index.ts}`
|
||||
- 配置:`vite.config.ts`、`vitest.perf.config.ts`、`tsconfig.json`、`package.json`、`.planning/config.json`
|
||||
- 规划物:`08-CONTEXT.md`、`06-COVERAGE-MAP.md`、`REQUIREMENTS.md`、`ROADMAP.md`、`07-VERIFICATION.md`、`dev.md`、`AGENTS.md`
|
||||
|
||||
### Secondary (MEDIUM confidence,本轮 Grep 命中但未逐字 Read 的测试断言)
|
||||
- 各 `*.test.ts` 的调用点(file:line 已在正文标注);执行期以编译/运行结果为准
|
||||
|
||||
### Tertiary (LOW confidence,需执行期验证)
|
||||
- data-base/enemy、flag、combat 的「连带失败」判定(A3/A4);未逐用例跑测(受 AGENTS.md 命令审批约束)
|
||||
|
||||
## Metadata
|
||||
|
||||
**Confidence breakdown:**
|
||||
- Standard Stack: HIGH — 直接读 `package.json`,无新依赖
|
||||
- Architecture / 接口 delta: HIGH — 全部结论锚定 live 源码 `file:line`;不确定性仅在「删/改」裁决项
|
||||
- Pitfalls: HIGH — 可由已读源码与失败族直接推断
|
||||
- 覆盖表: HIGH — 由 `logger.json` + 全量 grep 调用点反推;「陈旧码」解释为 MEDIUM(需用户确认契约意图)
|
||||
|
||||
**Research date:** 2026-10-04
|
||||
**Valid until:** 7 天(仓库处于用户并发收尾期,接口可能继续变化;执行前必须重测,不得沿用本快照当判据——沿用 `07-VERIFICATION.md:365-367` 的「快照会过期」纪律)
|
||||
|
||||
---
|
||||
|
||||
*Phase: 8-测试重构与接口对齐*
|
||||
*Research complete: 2026-10-04*
|
||||
Loading…
Reference in New Issue
Block a user