diff --git a/.planning/phases/06-unit-tests/06-10-PLAN.md b/.planning/phases/06-unit-tests/06-10-PLAN.md
new file mode 100644
index 0000000..5d0b341
--- /dev/null
+++ b/.planning/phases/06-unit-tests/06-10-PLAN.md
@@ -0,0 +1,256 @@
+---
+phase: 06-unit-tests
+plan: 10
+type: execute
+wave: 3
+depends_on: [06-01, 06-02]
+files_modified:
+ - packages-user/data-system/src/combat/context.test.ts
+ - packages-user/data-system/src/combat/mapDamage.test.ts
+ - packages-user/data-state/test/enemyCombination.test.ts
+ - .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+autonomous: true
+requirements: [TEST-01]
+estimate:
+ tokens: 62000
+ raw_tokens: 62000
+ tasks: 3
+ confidence: low
+must_haves:
+ truths:
+ - "TEST-01 由数据端行为单测满足,门禁为固定非 watch 命令 `pnpm test:ci` 全绿(D-08)。"
+ - "G-06-01-A:一只怪物同时受 光环基础效果(`onApply`)+ 常规查询效果(`registerCommonQueryEffect`)+ 特殊查询效果(`registerSpecialQueryEffect`)+ final 效果(`registerFinalEffect`)作用,显式断言四阶段顺序 `special → base → query → final`(后两阶段内部次序按实现可取子序列断言),并断言 buildup 完成后计算后怪物的最终 atk/def/hp 与特殊属性(D-25 深化)。"
+ - "G-06-01-B:多怪跨施加的嵌套光环 —— m1 产生光环 A1 施加到 m2;m2 因此获得特殊属性并生成光环 A2;A2 反向施加 m1 与 m2;m3 在 A1 范围外、在 A2 范围内。断言 m1/m2/m3 各自计算后最终属性、m2 持有被转换特殊属性而 m1/m3 不持有、转换器对代码 20 与 21 均被调用、A1 范围边界可观测(m1/m3 不受 A1 影响)。"
+ - "G-06-01-C:系统层同点多来源地图伤害叠加 —— 有来源+有来源、无来源+无来源、多来源(>2,且有来源与无来源混合)三种组合;断言 `getSeparatedDamage` 条数与 `getReducedDamage` 的 damage 求和 / type 取最大 / extra 并集符合语义。"
+ - "G-06-07-A:构建「尽可能多流水线同时生效」的单怪(顶层多特殊属性 + 光环 25 / 支援 26 + 常规查询 + 特殊查询 + final 效果 + 真实 `MainEnemyFinalEffect`),经真实 `MainDamageCalculator` 断言唯一精确的最终 `{damage, turn}`(仅含 damage 与 turn 两字段)。"
+ - "接口覆盖:本计划只经既有公开接口驱动(`EnemyContext`、`MapDamage`、`MainDamageCalculator`、`createCoreState`),不新增生产接口、不 mock 数据层接口本身;名称含 legacy 的接口/方法一律排除(D-30)。"
+ - "code 覆盖(模块可达):本计划不引入新码;新增用例复用并再确认本模块既有可达码(如 102/103/104)的覆盖不被削弱(D-31)。"
+ - "测试形态(D-01):阶段 1/2 为纯系统层单测(`data-system/src/combat`,fake/显式依赖注入,延续 D-21);阶段 3 经 `CoreState` 集成路径(`data-state/test`)。"
+ - "阶段化(D-43):计划按 构件→组合/流水线→完整/集成 三阶段组织,取消 tracer-first;每阶段跑绿后才进入下一阶段;某阶段发现阻断性 bug 时暂停并按 D-05/D-07 向用户汇报、等确认,不得跳过或弱化。"
+ - "质量门禁(D-44):每个计划执行后、提交前,改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误(全局既有无关错误不在范围);`pnpm test:ci` 全绿;任一不通过不得提交。"
+ - "执行节奏(D-33):本计划执行前先向用户确认;执行完成后暂停,用中文分条简要汇报验证结果,详细结果写入共用的 `06-TEST-FINDINGS.md`。"
+ - "增量补测(D-46):只新增/扩展 `*.test.ts`,不改动已执行的 06-01..06-09 计划与任何生产/核心源码;fixture 文件内联(D-02/D-03),异步路径只用真实计时器(D-04)。"
+ - "疑似缺陷按正确预期编写并标记 `it.skip`/`it.todo`,并按 D-06 格式登记到共用的 `06-TEST-FINDINGS.md`(本计划预期无需新增 skip)。"
+ artifacts:
+ - path: packages-user/data-system/src/combat/context.test.ts
+ provides: G-06-01-A 四类效果同时生效的最终属性断言、G-06-01-B 多怪跨施加嵌套光环最终属性断言
+ - path: packages-user/data-system/src/combat/mapDamage.test.ts
+ provides: G-06-01-C 同点多来源地图伤害叠加的 separated/reduced 断言
+ - path: packages-user/data-state/test/enemyCombination.test.ts
+ provides: G-06-07-A 最大流水线组合单怪最终 {damage,turn} 断言
+ - path: .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+ provides: 阶段级 code → 模块 → 用例 映射表(本计划 create-or-append 06-10 小节)
+ key_links:
+ - "context.test.ts 用测试用 fake `IAuraConverter`/`IAuraView` 手动装配(`new EnemyContext()` + `resize` + `bindHero` + `registerAuraConverter` + `registerCommonQueryEffect` + `registerSpecialQueryEffect` + `registerFinalEffect` + `setEnemyAt` + `buildup`)驱动,绝不引用/重测顶层真实实现(D-21)"
+ - "context.test.ts 的 G-06-01-B 复用既有 `createContextFixture(w,h)`、`FakeAura`(priority/range/param/couldApplyBase/couldApplySpecial/onApply/onApplySpecial)、`FakeConverter(codes, factory)` 与 `modules.RectRange`/`FullRange` 参数形状(Rect:`{x,y,w,h}`;Manhattan:`{cx,cy,radius}`;Full:`undefined`)"
+ - "mapDamage.test.ts 复用既有 `FakeView(value, indexes)`/`FakeConverter(views)`/`createInfo(damage)` 与 `MapLocIndexer` 夹具,新增内联 reducer 实现「damage 求和 / type 取最大 / extra 并集」语义,经 `getSeparatedDamage`/`getReducedDamage` 观测"
+ - "enemyCombination.test.ts 复用 `createCoreState`、`createContext`(真实 `CommonAuraConverter`/`GuardAuraConverter`/`MainEnemyFinalEffect`)、`createEnemy`、`createHero`/`createContextHandler`、`MainDamageCalculator` 与 `createSpecial`"
+ - "`.planning/phases/06-unit-tests/06-COVERAGE-MAP.md` 为共享 create-or-append 文件(幂等、顺序无关):写 06-10 小节前先检查表头(`| code | 模块 | 用例 | 计划 |`)是否存在,不存在则先创建,再只追加/更新本小节,绝不重写他节"
+ prohibitions:
+ - "不创建或修改任何生产/核心源码,只新增/扩展 `*.test.ts` 与规划产物"
+ - "不改动 06-01..06-09 的 PLAN.md"
+ - "不测试 `saveState`/`loadState`(集中到 06-13)(D-32)"
+ - "不安装覆盖率工具(D-09)"
+ - "不建立跨文件共享 fixture/factory helper,fixture 全部文件内联(D-02/D-03)"
+ - "异步路径只用真实计时器,禁用 `vi.useFakeTimers()`(D-04)"
+ - "疑似 bug 不得弱化为通过;按正确预期编写并标记 `it.skip`/`it.todo`(D-05)"
+---
+
+
+按 D-43 阶段化(构件 → 组合/流水线 → 完整/集成)补齐 06-01(战斗系统)与 06-02(顶层战斗实现)人工评审发现的覆盖缺口(D-46):
+
+- **G-06-01-A** 四类效果同时生效后的最终属性未断言(`context.test.ts`)
+- **G-06-01-B** 多怪跨施加的嵌套光环未覆盖(`context.test.ts`)
+- **G-06-01-C** 地图伤害叠加场景未覆盖(`mapDamage.test.ts`)
+- **G-06-07-A** 缺少「尽可能多流水线组合」的单怪最终伤害断言(`enemyCombination.test.ts`)
+
+Purpose: 现有用例覆盖了单效果、单光环、阶段顺序与系统层流水线,但缺少「多来源/多效果同时叠加后唯一的最终结果」与「跨怪嵌套光环」的组合断言。本计划只补测试,不改任何生产代码。
+
+Output: 3 个既有 `*.test.ts` 的扩展与 `06-COVERAGE-MAP.md` 的 06-10 小节。
+
+阶段结构(D-43):阶段 1 构件级(G-06-01-C 同点多来源地图伤害)→ 阶段 2 组合/流水线(G-06-01-A 四类效果同时生效 + G-06-01-B 多怪嵌套光环)→ 阶段 3 完整/集成(G-06-07-A 最大流水线组合单怪最终伤害)。每阶段跑绿后再进入下一阶段。
+
+
+
+@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
+@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
+
+
+
+@.planning/phases/06-unit-tests/06-CONTEXT.md
+@.planning/phases/06-unit-tests/06-COVERAGE-GAPS.md
+@.planning/phases/06-unit-tests/06-PATTERNS.md
+@.planning/phases/06-unit-tests/06-TEST-FINDINGS.md
+@.planning/codebase/TESTING.md
+@dev.md
+@packages-user/data-system/src/combat/context.ts
+@packages-user/data-system/src/combat/mapDamage.ts
+@packages-user/data-system/src/combat/types.ts
+@packages-user/data-system/src/combat/context.test.ts
+@packages-user/data-system/src/combat/mapDamage.test.ts
+@packages-user/data-state/test/enemyCombination.test.ts
+@packages-user/data-state/src/enemy/calculator.ts
+@packages-user/data-state/src/enemy/aura.ts
+@packages-user/data-state/src/enemy/final.ts
+@packages/common/src/logger.json
+
+
+
+- 只写测试,绝不修改 `packages-user/*/src` 下的非 `*.test.ts` 文件。
+- 每个 `it(...)` 之前必须有一行中文注释说明覆盖内容(dev.md 注释规范),测试范围变化时同步更新。
+- 异步动作(mover/战斗长动作)用真实计时器 + await 控制器完成,禁用 `vi.useFakeTimers()`(D-04)。
+- fixture 内联且最小(D-02/D-03),沿用目标文件既有 helper,不新造跨文件 helper。
+- 警告/错误路径经 `logger.catch` / `vi.spyOn(logger, ...)`。
+- 疑似 bug:按正确预期编写、标记 `it.skip`/`it.todo`、中文注释锚定 `#06-XX-N` 并登记 `06-TEST-FINDINGS.md`;`pnpm test:ci` 必须保持全绿(D-05)。
+- 本计划不测 `saveState`/`loadState`(D-32)。
+- `06-COVERAGE-MAP.md` 为共享 create-or-append 文件(幂等、顺序无关):写入前先检查表头(`| code | 模块 | 用例 | 计划 |`)是否存在,不存在则先创建,再只追加/更新本计划小节,绝不重写他节。
+- **执行协议(D-33):执行本计划前必须先向用户确认;执行完成后暂停,用中文分条简要汇报本计划验证结果;详细结果写入共用的 `06-TEST-FINDINGS.md`。**
+- **阶段门禁(D-43):本计划按 构件 → 组合/流水线 → 完整/集成 三阶段顺序执行,每阶段跑绿后才进入下一阶段;若某阶段发现阻断性 bug 使后续阶段无法运行,暂停并按 D-05/D-07 向用户汇报、等确认,不得跳过或弱化。**
+- **质量门禁(D-44,每个计划执行后、提交前必过)**:对改动文件运行 `eslint --fix`,并确保 `eslint <改动文件>` **0 错误**;对**本计划改动的测试文件**运行 `pnpm exec vue-tsc --noEmit`,并按输出文件路径过滤,确保这些文件路径下 **0 类型错误**(全局既有无关错误,如 `client-modules`/`legacy-plugin-data`,不在本门禁范围);`pnpm test:ci` **全绿**。任一不通过则**不得提交**。
+
+
+
+
+
+ 阶段 1(构件级):G-06-01-C 同点多来源地图伤害的 separated/reduced 叠加断言
+ packages-user/data-system/src/combat/mapDamage.test.ts
+
+ packages-user/data-system/src/combat/mapDamage.ts(`addMapDamage`/`deleteMapDamage`/`getSeparatedDamage`/`getReducedDamage`/`useConverter`/`useReducer`/`markDirty`)
+ packages-user/data-system/src/combat/mapDamage.test.ts(既有 `createInfo`/`FakeView`/`FakeConverter`/`FakeReducer`/`createFixture`)
+ packages-user/data-system/src/combat/types.ts(`IMapDamageInfo` 的 damage/type/extra 字段;`IMapDamageReducer.reduce`)
+ packages-user/data-state/src/enemy/mapDamage.ts(`MainMapDamageReducer` 的「求和 / 取最大 type / 并集 extra」参考语义,**只读参考、不导入**)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-01-C)
+ .planning/phases/06-unit-tests/06-PATTERNS.md(A 节 mapDamage + 共享样板 4)
+
+
+ 在 `mapDamage.test.ts` 内联新增一个语义 reducer 与三类叠加用例,扩展既有夹具(`createFixture` 提供 `MapLocIndexer`、`FakeView`、`FakeConverter`、`FakeReducer`)。
+ 1) 新增内联 helper `createTypedInfo(damage, type, catchIds, repulseIds)`(返回 `IMapDamageInfo`,`extra.catch`/`extra.repulse` 为 `Set`)与 `createSemanticReducer()`(`reduce` 对 iterable 做 damage 求和、type 取最大、`extra.catch`/`extra.repulse` 并集,返回 `createTypedInfo(...)`)。
+ 2) 用例「有来源 + 有来源 同点叠加」:`useReducer(createSemanticReducer())` + `useConverter(new FakeConverter([new FakeView(7, [idx]), new FakeView(4, [idx])]))`(同一 `MapLocIndexer` 索引);断言 `getSeparatedDamage(locator)` 长度 2、`getReducedDamage(locator).damage === 11`。
+ 3) 用例「无来源 + 无来源 同点叠加」:`useReducer` 后对同一 locator `addMapDamage(locator, createTypedInfo(3, ...))` 与 `addMapDamage(locator, createTypedInfo(5, ...))`(`FakeConverter([])`);断言 separated 长度 2、reduced.damage === 8。
+ 4) 用例「多来源(>2,有来源与无来源混合)」:converter 产出两条 sourced(如 7 与 4,type 分别 0/2,extra 分别含不同 catch/repulse 标记),再 `addMapDamage` 两条 sourceless(如 3 与 2,type 1);断言 separated 长度 4、reduced.damage === 16、reduced.type === 最大 type(2)、`reduced.extra.catch`/`extra.repulse` 为各来源并集(按标记集合显式断言)。
+ 5) 每个 `it` 前写一行中文注释;只经公开方法断言,不直接读内部 `ArrayBuffer`。若某组合在实现下出现与语义不符的结果,按 D-05 写正确预期 + `it.skip` 并在 `06-TEST-FINDINGS.md` 登记 `#06-10-N`,不得弱化为通过。
+
+
+ pnpm exec vitest run packages-user/data-system/src/combat/mapDamage.test.ts
+ 该文件运行失败(非 skip),或 G-06-01-C 的三种叠加组合中任一缺少 `getSeparatedDamage` 条数断言或 `getReducedDamage` 的 damage/type/extra 断言,或现有 102/103/104 用例回归失败
+
+
+ - `mapDamage.test.ts` 零非跳过失败。
+ - 新增用例覆盖 G-06-01-C 三种组合(sourced+sourced、sourceless+sourceless、多来源混合),均断言 separated 条数与 reduced 的 damage/type/extra。
+ - 新增 reducer/信息构造 helper 为文件内联,未建立跨文件 helper(D-03)。
+ - 每个新增 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 1 的 G-06-01-C 覆盖全部跑绿后才进入阶段 2。若发现阻断性 bug 使后续阶段无法运行,暂停并按 D-05/D-07 向用户汇报、等确认。
+
+
+
+ 阶段 2(组合/流水线):G-06-01-A 四类效果同时生效的最终属性 + G-06-01-B 多怪跨施加嵌套光环
+ packages-user/data-system/src/combat/context.test.ts
+
+ packages-user/data-system/src/combat/context.ts(`registerAuraConverter`/`registerCommonQueryEffect`/`registerSpecialQueryEffect`/`registerFinalEffect`/`addAura`/`setEnemyAt`/`bindHero`/`buildup`/`getEnemyByLoc`)
+ packages-user/data-system/src/combat/context.test.ts(既有 `createContextFixture`/`FakeAura`/`FakeConverter`/`createEnemy`/`createSpecial`,以及 L1046 四阶段用例、L895 两层嵌套用例)
+ packages-user/data-system/src/combat/types.ts(`IEnemyCommonQueryEffect`/`IEnemySpecialQueryEffect`/`IEnemyFinalEffect`/`IAuraView`)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-01-A、G-06-01-B)
+ .planning/phases/06-unit-tests/06-PATTERNS.md(A 节 context + 共享样板 4)
+
+
+ 在 `context.test.ts` 的 aura/阶段顺序分区新增两条用例,全部复用既有 fake 装配(`createContextFixture` + `FakeAura` + `FakeConverter`),不引用顶层真实实现(D-21)。
+ 1) G-06-01-A「四类效果同时生效」:`createContextFixture()`;`bindHero`;e1(`createEnemy('e1')`,基础 atk 2/def 0/hp 10)加 `createSpecial(20)` 并 `setEnemyAt({x:0,y:0}, e1)`;`registerAuraConverter(new FakeConverter([20], () => aura))`,其中 aura = `new FakeAura({ priority: 1, range: new modules.FullRange(), param: undefined, couldApplyBase: true, couldApplySpecial: true, onApply: h => { order.push('base'); h.enemy.addAttribute('atk', 5); }, onApplySpecial: () => { order.push('special'); return { add: () => [createSpecial(21)], delete: () => [], modify: () => false }; } })`;`registerCommonQueryEffect(20, { priority: 1, apply: h => { order.push('query'); h.enemy.addAttribute('def', 2); } })`;`registerSpecialQueryEffect({ priority: 1, for: () => ({ shouldQuery: h => h.enemy.hasSpecial(21), add: () => [], delete: () => [], modify: () => { order.push('special-query'); return true; } }) })`;`registerFinalEffect({ priority: 1, apply: h => { order.push('final'); h.enemy.addAttribute('hp', 4); } })`;`buildup()`。断言:`order` 以 `'special'` 开头且 `indexOf('special') < indexOf('base') < indexOf('query') < indexOf('final')`(`'special-query'` 允许落在 query 阶段内任意位置,用子序列断言,不硬编码其在 query 前后);最终计算后怪物 `getAttribute('atk') === 7`、`getAttribute('def') === 2`、`getAttribute('hp') === 14`、`hasSpecial(21) === true`。
+ 2) G-06-01-B「多怪跨施加嵌套光环」:`createContextFixture(5, 3)`;`bindHero`;m1(0,0) atk 2 + `createSpecial(20)`,m2(1,0) atk 4,m3(4,0) atk 6,均 `setEnemyAt`;`registerAuraConverter(new FakeConverter([20, 21], code => code === 20 ? a1 : a2))`,其中 a1 = `new FakeAura({ priority: 10, range: new modules.RectRange(), param: { x: 1, y: 0, w: 1, h: 1 }, couldApplyBase: true, couldApplySpecial: true, onApply: h => h.enemy.addAttribute('atk', 100), onApplySpecial: () => ({ add: () => [createSpecial(21)], delete: () => [], modify: () => false }) })`(只覆盖 m2),a2 = `new FakeAura({ priority: 5, range: new modules.FullRange(), param: undefined, onApply: h => h.enemy.addAttribute('atk', 3) })`;`buildup()`。断言:`converter.convertCalls` 同时包含 20 与 21;m2 `hasSpecial(21) === true` 而 m1/m3 `hasSpecial(21) === false`(A1 范围边界可观测);最终 atk `m1 === 5`、`m2 === 107`、`m3 === 9`(A1 只加成 m2,A2 加成三只)。
+ 两条用例前各写一行中文注释。若任一断言与实现不符,按 D-05 将该项改为正确预期的 `it.skip` 并在 `06-TEST-FINDINGS.md` 登记 `#06-10-N`(注明最小复现与疑似原因),不得弱化为通过。
+
+
+ pnpm exec vitest run packages-user/data-system/src/combat/context.test.ts
+ 该文件运行失败(非 skip),或 G-06-01-A 未断言四阶段顺序/最终 atk/def/hp/special,或 G-06-01-B 未断言三只怪各自最终属性与 A1 范围边界,或既有 97–101/110/四阶段/嵌套用例回归失败
+
+
+ - `context.test.ts` 零非跳过失败。
+ - G-06-01-A:四类效果(光环基础 + 常规查询 + 特殊查询 + final)同时生效,四阶段顺序与最终属性均有显式断言。
+ - G-06-01-B:m1→A1→m2→A2→m1/m2 的跨施加链与 m3 的 A1 范围外/A2 范围内均有断言,含三只怪最终 atk 与 special 差异。
+ - 全部经文件内联 fake 驱动,未引用顶层真实实现(D-21)。
+ - 每个新增 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 2 的 G-06-01-A/B 覆盖在阶段 1 跑绿的基础上全部跑绿后才进入阶段 3。若发现阻断性 bug 使后续阶段无法运行,暂停并按 D-05/D-07 向用户汇报、等确认。
+
+
+
+ 阶段 3(完整/集成):G-06-07-A 最大流水线组合单怪的最终 {damage,turn}
+ packages-user/data-state/test/enemyCombination.test.ts, .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+
+ packages-user/data-state/test/enemyCombination.test.ts(既有 `createCoreState`/`createContext`/`createEnemy`/`createHero`/`createContextHandler`/`createSpecial`/`createOrderAura`/`createSpecialAura`)
+ packages-user/data-state/src/enemy/calculator.ts(各 special 分支:先攻/魔攻/连击/多段/破甲/反击/吸血/固伤/仇恨/坚固/模仿/支援递归)
+ packages-user/data-state/src/enemy/final.ts(`MainEnemyFinalEffect`)
+ packages-user/data-state/src/enemy/calculator.test.ts(各单分支的确定性数值参考)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-07-A)
+ packages/common/src/logger.json
+
+
+ 在 `enemyCombination.test.ts` 新增阶段 3(完整/集成)用例:在 `createCoreState()` + 真实 `createContext(state, hero)`(真实 `CommonAuraConverter`/`GuardAuraConverter`/`MainEnemyFinalEffect`)之上构造一只「尽可能多流水线同时生效」的怪,然后经真实 `MainDamageCalculator` 断言唯一精确的最终 `{damage, turn}`。
+ 组合内容(全部同时生效):怪物自带的顶层特殊属性(至少 先攻 1、魔攻 2、2连击 4、多段 6、破甲 7、反击 8、吸血 11、固伤 22、仇恨 17、坚固 3)、真实光环 25(`createSpecial(25, { haloRange: 0, haloSquare: false, hpBuff, atkBuff, defBuff })`)、真实支援 26(`createSpecial(26, undefined)` 并由相邻支援怪提供 `guard` 坐标)、`context.registerCommonQueryEffect(25, ...)`、`context.registerSpecialQueryEffect(...)`、`context.registerFinalEffect({ priority, apply })`(自定义最终效果);固定 `hero = createHero({ atk: 20, def: 5, hp: 100 })`;`context.setEnemyAt` 放置主怪与支援怪;`context.buildup()` 后取 `targetView.getComputedEnemy()`,以 `createContextHandler(context, computed, hero, locator)` 交给 `new MainDamageCalculator()`。
+ 断言:结果为单一对象 `{ damage, turn }`(`expect(info).toEqual({ damage: D, turn: T })`,`D`/`T` 为按各分支语义推导并在注释中写出推导过程的确定值;同时 `expect(Object.keys(info!).sort()).toEqual(['damage','turn'])` 证明确无额外字段)。数值须由实现者在注释中给出逐项推导(基础伤害 + 各 special 加成 + 光环改后属性 + 支援递归 + 自定义 final),不得直接抄运行结果而不写推导。可再补一条对照断言:去掉支援怪(或某一效果)后 `{damage,turn}` 与最大组合不同,证明组合确实同时生效。
+ 写一行中文注释说明覆盖内容。若计算器某分支与推导不符,按 D-05 写正确预期 + `it.skip` 并登记 `06-TEST-FINDINGS.md` 的 `#06-10-N`,不得弱化。
+ 完成后以 create-or-append 方式写入 `06-COVERAGE-MAP.md` 的 06-10 小节:本计划**不引入新码**,因此先确认表头存在(不存在则创建),再追加 `## 06-10 战斗系统 / 顶层组合缺口补测` 小节,列出 G-06-01-A/B/C、G-06-07-A → 用例名 → 计划 06-10 的映射,并注明「本计划无新增码,复用既有可达码」;只追加/更新本小节,绝不重写他节。
+
+
+ pnpm exec vitest run packages-user/data-state/test/enemyCombination.test.ts
+ 该文件运行失败(非 skip),或最大组合用例未断言单一 `{damage,turn}` 精确值,或结果对象含 damage/turn 以外字段,或对照用例未证明组合生效,或 06-10 小节未写入 `06-COVERAGE-MAP.md`
+
+
+ - `enemyCombination.test.ts` 零非跳过失败。
+ - G-06-07-A:最大组合怪经真实 `MainDamageCalculator` 得到唯一精确 `{damage,turn}`,且注释含逐项推导。
+ - 存在一条对照断言(去掉某效果/支援后结果不同),证明多流水线同时生效。
+ - `06-COVERAGE-MAP.md` 存在 06-10 小节(create-or-append,未重写他节),列出 G-06-01-A/B/C、G-06-07-A 的用例映射。
+ - 每个新增 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 3 的 G-06-07-A 覆盖在阶段 1/2 跑绿的基础上全部跑绿,且 06-10 小节已写入 `06-COVERAGE-MAP.md`。完成后暂停并用中文分条汇报;详细结果写入 `06-TEST-FINDINGS.md`。
+
+
+
+
+
+## Trust Boundaries
+
+| Boundary | Description |
+|----------|-------------|
+| none | 仅新增/扩展仓库内 Node Vitest 测试;无运行时输入面、网络、DOM 或文件写入。 |
+
+## STRIDE Threat Register
+
+| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
+|-----------|----------|-----------|----------|-------------|-----------------|
+| T-06-10-01 | Tampering | `data-system/src/combat` 与 `data-state/test` 下测试文件 | low | mitigate | 只导入已跟踪模块、合成 fixture;不改核心源码;门禁 `pnpm test:ci` + 复核仅 `*.test.ts` 变更。 |
+| T-06-10-02 | Information disclosure | 合成 fixture | low | accept | 合成属性/录像/地图,无真实数据或密钥(D-02)。 |
+| T-06-10-03 | Repudiation | 全局 stub 泄漏 | low | accept | 既有文件已在 `afterAll`/`vi.hoisted` 管理 stub;新增用例不引入新 stub。 |
+| T-06-10-SC | Tampering | 包安装 | high | mitigate | 明确不引入任何新依赖;若确需安装,停止并先走包合法性 checkpoint。 |
+
+
+
+- 三个测试文件聚焦运行通过;`pnpm test:ci` 全量绿。
+- `git status` 仅显示三个 `*.test.ts` 与 `06-COVERAGE-MAP.md` 的变更;无核心文件改动。
+- 任何 `it.skip`/`it.todo` 均有 `#06-10-N` 条目(预期无需新增)。
+- 以 create-or-append 方式写入 `06-COVERAGE-MAP.md` 06-10 小节;表头不存在则先创建;幂等、顺序无关,不重写他节。
+- **执行协议**:执行前必须先向用户确认;执行后暂停并用中文分条汇报。
+
+
+
+- G-06-01-A、G-06-01-B、G-06-01-C、G-06-07-A 均有可跑绿的新增用例。
+- 四类效果同时生效的最终属性、多怪嵌套光环的三只怪最终属性、同点多来源地图伤害的 separated/reduced、最大组合单怪的 `{damage,turn}` 均被显式断言。
+- 无生产代码改动,`pnpm test:ci` 全绿。
+
+
+
+Test files (extended):
+- `packages-user/data-system/src/combat/mapDamage.test.ts`(新增 `createTypedInfo`、`createSemanticReducer` 与 3 条叠加用例)
+- `packages-user/data-system/src/combat/context.test.ts`(新增 G-06-01-A 四类效果用例、G-06-01-B 多怪嵌套光环用例)
+- `packages-user/data-state/test/enemyCombination.test.ts`(新增最大流水线组合用例)
+
+Planning artifacts:
+- `06-COVERAGE-MAP.md` create-or-append 06-10 小节
+
+
+
diff --git a/.planning/phases/06-unit-tests/06-12-PLAN.md b/.planning/phases/06-unit-tests/06-12-PLAN.md
new file mode 100644
index 0000000..b16071b
--- /dev/null
+++ b/.planning/phases/06-unit-tests/06-12-PLAN.md
@@ -0,0 +1,237 @@
+---
+phase: 06-unit-tests
+plan: 12
+type: execute
+wave: 3
+depends_on: [06-03, 06-04]
+files_modified:
+ - packages-user/data-common/src/replay/array.test.ts
+ - packages-user/data-base/src/enemy/manager.test.ts
+ - .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+autonomous: true
+requirements: [TEST-01]
+estimate:
+ tokens: 52000
+ raw_tokens: 52000
+ tasks: 3
+ confidence: low
+must_haves:
+ truths:
+ - "TEST-01 由数据端行为单测满足,门禁为固定非 watch 命令 `pnpm test:ci` 全绿(D-08)。"
+ - "G-06-04-B(可跑绿):构造 5+ 条异质录像命令(参数个数与类型各不相同,混合 boolean/各路宽整数/float/string/bigint),经 `createReadStream` 与 `get` 逐条读回一致(`createReadStream` 的 `index === position + 1`、`get(i)` 的 `index === i`,故两者只比较 `command`/`params`,不对整体对象做相等);并覆盖异质序列删除首步后的读回(删除首步为当前可用路径)。"
+ - "G-06-04-A(正确预期 + `it.skip`):多字节 bigint 与超 int32 的 int64 编解码受 `#06-04-1`/`#06-04-2` 阻塞,按正确预期编写并保持 `it.skip`,中文注释锚定 `06-TEST-FINDINGS.md` 的 `#06-04-1`/`#06-04-2`;`pnpm test:ci` 保持全绿。"
+ - "G-06-03-A(正确预期 + `it.skip`):多 code/id(4 朝向)复用同一 prefab 并各自生成互相独立怪物的完整链路受 `#06-03-1` 阻塞,按正确预期编写并标记 `it.skip`,中文注释锚定 `#06-03-1`;`pnpm test:ci` 保持全绿。"
+ - "接口覆盖:本计划只经既有公开接口驱动(`ReplayArray` 的 add/delete/set/get/createReadStream/setCommandWidth/rebuildIndexArray/getCommandArray/getParamArray,`EnemyManager` 的 addPrefab/reusePrefab/getPrefab/createEnemy/createEnemyById),名称含 legacy 的接口/方法排除(D-30)。"
+ - "code 覆盖(模块可达):本计划不引入新码;复用并再确认既有可达码(如 148/152/155/163)的覆盖不被削弱(D-31)。"
+ - "测试形态(D-01):纯数据模块单测(fake / 显式依赖注入,延续 Phase 3 D-03);不引入真实录像数据(D-02)。"
+ - "阶段化(D-43):计划按 构件→组合→完整 三阶段组织,取消 tracer-first;每阶段跑绿后才进入下一阶段;某阶段发现阻断性 bug 时暂停并按 D-05/D-07 向用户汇报、等确认,不得跳过或弱化。"
+ - "质量门禁(D-44):每个计划执行后、提交前,改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误(全局既有无关错误不在范围);`pnpm test:ci` 全绿;任一不通过不得提交。"
+ - "执行节奏(D-33):本计划执行前先向用户确认;执行完成后暂停,用中文分条简要汇报验证结果,详细结果写入共用的 `06-TEST-FINDINGS.md`。"
+ - "增量补测(D-46):只新增/扩展 `*.test.ts`,不改动已执行的 06-01..06-09 计划与任何生产/核心源码;fixture 文件内联(D-02/D-03),不使用 fake timers(D-04)。"
+ - "受阻塞缺口不得弱化为通过:G-06-04-A、G-06-03-A 一律以正确预期 + `it.skip` 登记(D-05),不得写成可通过的断言(D-46)。"
+ artifacts:
+ - path: packages-user/data-common/src/replay/array.test.ts
+ provides: G-06-04-B 异质多命令序列读回(可跑绿)与 G-06-04-A 多字节 bigint/int64 正确预期 skip
+ - path: packages-user/data-base/src/enemy/manager.test.ts
+ provides: G-06-03-A 多 code/id 复用同一 prefab 生成独立怪物的正确预期 skip
+ - path: .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+ provides: 阶段级 code → 模块 → 用例 映射表(本计划 create-or-append 06-12 小节)
+ key_links:
+ - "array.test.ts 复用既有 `createArray(overrides)`、`paramCases`、`firstParamToken(array)` 与 `ReplayCommandWidth`/`ReplayParamValue`;异质序列经 `add`/`get`/`createReadStream`/`getCommandArray`/`getParamArray`/`setCommandWidth` 观测,不读内部实现细节"
+ - "既有 `it.skip`(`round-trips a multi-byte bigint` 锚定 `#06-04-2`、`round-trips int64 values above the int32 range` 锚定 `#06-04-1`)与 `deletes a middle step and shifts later param indexes`(`#06-04-3`)、`reads the new order after inserting a step`(`#06-04-4`)保持不变,不得取消 skip"
+ - "manager.test.ts 复用既有 `createManager`/`createPrefab`/`bridge`/`dirtyCodes`;复用链路经 `addPrefab(1,'slime')` → `reusePrefab(1, 100|101|102|103, ...)` → `createEnemy(100..103)`/`createEnemyById(...)` 驱动;既有 `#06-03-1` skip 不改动"
+ - "`.planning/phases/06-unit-tests/06-COVERAGE-MAP.md` 为共享 create-or-append 文件(幂等、顺序无关):写 06-12 小节前先检查表头(`| code | 模块 | 用例 | 计划 |`)是否存在,不存在则先创建,再只追加/更新本小节,绝不重写他节"
+ prohibitions:
+ - "不创建或修改任何生产/核心源码,只新增/扩展 `*.test.ts` 与规划产物"
+ - "不改动 06-01..06-09 的 PLAN.md"
+ - "不测试 `saveState`/`loadState`(集中到 06-13)(D-32)"
+ - "不安装覆盖率工具(D-09)"
+ - "不建立跨文件共享 fixture/factory helper,fixture 全部文件内联(D-02/D-03)"
+ - "不使用 fake timers(D-04)"
+ - "受阻塞缺口不得弱化为通过;按正确预期编写并标记 `it.skip`/`it.todo`(D-05)"
+---
+
+
+按 D-43 阶段化(构件 → 组合 → 完整)补齐 06-04(录像)与 06-03(enemy 数据模型)人工评审发现的覆盖缺口(D-46):
+
+- **G-06-04-B** 异质多命令序列的读回未专门验证(`replay/array.test.ts`,可跑绿)
+- **G-06-04-A** 多字节 bigint / int64 参数类型未真正验证(`replay/array.test.ts`,受 `#06-04-1`/`#06-04-2` 阻塞 → 正确预期 `it.skip`)
+- **G-06-03-A** 多 code/id(4 朝向)共用同一 prefab 的实例化路径未验证(`enemy/manager.test.ts`,受 `#06-03-1` 阻塞 → 正确预期 `it.skip`)
+
+Purpose: 现有用例的录像序列参数基本同质,enemy 复用的**读**路径有断言但**生成**路径受 bug 阻塞。本计划补「异质序列整体读回」的可跑绿用例,并把两个受阻塞缺口以正确预期 `it.skip` 纳入(D-46),不修任何生产代码。
+
+Output: 2 个既有 `*.test.ts` 的扩展与 `06-COVERAGE-MAP.md` 的 06-12 小节。
+
+阶段结构(D-43):阶段 1 构件级(G-06-04-B 异质序列读回)→ 阶段 2 组合(G-06-04-A 受阻塞的编解码正确预期 skip)→ 阶段 3 完整(G-06-03-A 复用实例化正确预期 skip)。每阶段跑绿后再进入下一阶段。
+
+
+
+@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
+@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
+
+
+
+@.planning/phases/06-unit-tests/06-CONTEXT.md
+@.planning/phases/06-unit-tests/06-COVERAGE-GAPS.md
+@.planning/phases/06-unit-tests/06-PATTERNS.md
+@.planning/phases/06-unit-tests/06-TEST-FINDINGS.md
+@.planning/codebase/TESTING.md
+@dev.md
+@packages-user/data-common/src/replay/array.ts
+@packages-user/data-common/src/replay/types.ts
+@packages-user/data-common/src/replay/array.test.ts
+@packages-user/data-base/src/enemy/manager.ts
+@packages-user/data-base/src/enemy/manager.test.ts
+@packages/common/src/logger.json
+
+
+
+- 只写测试,绝不修改 `packages-user/*/src` 下的非 `*.test.ts` 文件。
+- 每个 `it(...)` 之前必须有一行中文注释说明覆盖内容(dev.md 注释规范),测试范围变化时同步更新。
+- fixture 内联且最小(D-02/D-03),沿用目标文件既有 helper,不新造跨文件 helper。
+- 警告/错误路径经 `logger.catch` / `vi.spyOn(logger, ...)`。
+- 受阻塞缺口:按正确预期编写、标记 `it.skip`、中文注释锚定既有 `#06-04-1`/`#06-04-2`/`#06-03-1`;`pnpm test:ci` 必须保持全绿(D-05)。
+- 本计划不测 `saveState`/`loadState`(D-32)。
+- `06-COVERAGE-MAP.md` 为共享 create-or-append 文件(幂等、顺序无关):写入前先检查表头(`| code | 模块 | 用例 | 计划 |`)是否存在,不存在则先创建,再只追加/更新本计划小节,绝不重写他节。
+- **执行协议(D-33):执行本计划前必须先向用户确认;执行完成后暂停,用中文分条简要汇报本计划验证结果;详细结果写入共用的 `06-TEST-FINDINGS.md`。**
+- **阶段门禁(D-43):本计划按 构件 → 组合 → 完整 三阶段顺序执行,每阶段跑绿后才进入下一阶段;若某阶段发现阻断性 bug 使后续阶段无法运行,暂停并按 D-05/D-07 向用户汇报、等确认,不得跳过或弱化。**
+- **质量门禁(D-44,每个计划执行后、提交前必过)**:对改动文件运行 `eslint --fix`,并确保 `eslint <改动文件>` **0 错误**;对**本计划改动的测试文件**运行 `pnpm exec vue-tsc --noEmit`,并按输出文件路径过滤,确保这些文件路径下 **0 类型错误**(全局既有无关错误,如 `client-modules`/`legacy-plugin-data`,不在本门禁范围);`pnpm test:ci` **全绿**。任一不通过则**不得提交**。
+
+
+
+
+
+ 阶段 1(构件级):G-06-04-B 5+ 条异质录像命令序列的整体读回
+ packages-user/data-common/src/replay/array.test.ts
+
+ packages-user/data-common/src/replay/array.ts(`add`/`delete`/`set`/`get`/`createReadStream`/`getCommandArray`/`getParamArray`/`setCommandWidth`/`rebuildIndexArray`/`length`)
+ packages-user/data-common/src/replay/array.test.ts(既有 `createArray`/`paramCases`/`firstParamToken` 与「stream and buffer combination」分区)
+ packages-user/data-common/src/replay/types.ts(`ReplayParamValue`/`ReplayCommandWidth`)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-04-B)
+ .planning/phases/06-unit-tests/06-PATTERNS.md(B 节 array + 共享样板)
+
+
+ 在 `array.test.ts` 的「stream and buffer combination」分区新增可跑绿用例。构造 6 条参数个数与类型各不相同的命令(保持一致、无需修复):`add(1, [10])`(单 int)、`add(2, [true, 'x'])`(boolean + 短 string)、`add(3, [])`(无参数)、`add(4, [100n])`(单字节 bigint)、`add(5, [1, -32769, 3])`(多 int)、`add(6, ['a'.repeat(300), 1.5])`(长 string + float)。断言:`array.length === 6`;`createReadStream(0)` 依次 `read()` 的 `command`/`params` 精确等于每一步期望,末尾 `read()` 返回 `null`;`setCommandWidth(ReplayCommandWidth.Uint16)` 后再次逐条读回一致。
+ **索引语义(务必区分,否则整体对象相等会失败)**:`createReadStream(0)` 读回的 `index` 为 `position + 1`(即 1..6,与既有 `reads a sequence of steps through a read stream` 的 L292 形状一致),而 `array.get(i)` 的 `index === i`(0..5)。因此逐条把 `get(i)` 与流读回对应时,**只比较 `command` 与 `params`**(`expect(array.get(i)).toMatchObject({ command, params })`),或对 `index` 做 ±1 校正后比较,**不要**对 `get(i)` 与 `read()` 的返回值做 `toEqual` 整体相等。
+ 再增一条可跑绿用例覆盖异质序列的**删除首步**:在上述 6 步基础上 `delete(0)`,断言 `array.length === 5` 且 `get(0)` 等于原第 2 步(`{command:2, params:[true,'x'], index:0}`,`get` 的 index 从 0 起);随后 `createReadStream(0)` 逐条读回剩余 5 步——同样只比较 `command`/`params`(原第 2..6 步),流读回的 `index` 为 1..5,而 `get(i)` 为 0..4(删除首步为当前可用路径,`#06-04-3` 仅阻塞中间删除)。
+ 注意:**不要**在本计划重写或取消既有 `it.skip`(`deletes a middle step...` `#06-04-3`、`reads the new order after inserting a step` `#06-04-4`、`round-trips a multi-byte bigint` `#06-04-2`、`round-trips int64 values above the int32 range` `#06-04-1`)。每步用一个内联 `expectedSteps` 数组保存期望,避免重复字面量。两条用例前各写一行中文注释。若读回与期望不符,按 D-05 写正确预期 + `it.skip` 并登记 `06-TEST-FINDINGS.md` 的 `#06-12-N`,不得弱化。
+
+
+ pnpm exec vitest run packages-user/data-common/src/replay/array.test.ts
+ 该文件运行失败(非 skip),或异质序列未覆盖 5+ 条且参数类型/个数各异,或未同时经 `createReadStream` 与 `get` 逐条断言,或删除首步后的异质读回缺失,或既有 148/152/153/155 用例回归失败
+
+
+ - `array.test.ts` 零非跳过失败。
+ - G-06-04-B:5+ 条异质命令(不同参数个数与类型,含 boolean/整数/float/string/bigint)逐条读回一致;删除首步后的异质序列读回一致;`createReadStream`(`index = position + 1`)与 `get(i)`(`index = i`)的比对只覆盖 `command`/`params`。
+ - 未改动既有 `it.skip` 集合(4 条 skip 数量与锚点不变)。
+ - 每个新增 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 1 的 G-06-04-B 覆盖全部跑绿后才进入阶段 2。若发现阻断性 bug,暂停并按 D-05/D-07 向用户汇报、等确认。
+
+
+
+ 阶段 2(组合):G-06-04-A 多字节 bigint / 超 int32 int64 的正确预期 skip(含异质序列)
+ packages-user/data-common/src/replay/array.test.ts
+
+ packages-user/data-common/src/replay/array.test.ts(既有两条 `it.skip`:多字节 bigint、int64 超 int32)
+ packages-user/data-common/src/replay/array.ts(`normalizeParam` 与 `decodeParam` 的 bigint/int64 分支,**只读参考**)
+ .planning/phases/06-unit-tests/06-TEST-FINDINGS.md(`#06-04-1`、`#06-04-2`)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-04-A)
+
+
+ G-06-04-A 的两个受阻塞缺口按 D-46 以正确预期 `it.skip` 纳入:
+ 1) 确认既有 `it.skip('round-trips a multi-byte bigint')`(锚定 `#06-04-2`)与 `it.skip('round-trips int64 values above the int32 range')`(锚定 `#06-04-1`)存在且断言按正确预期编写;若任一缺失则按既有形状补回(含中文注释锚点)。**不得取消 skip、不得修改其断言为可通过**。
+ 2) 新增一条 `it.skip` 组合用例 `G-06-04-A:异质序列中的多字节 bigint 与超 int32 int64 一起读回`:`const array = createArray()`;`array.add(0, [true, 0x0102030405060708n, 2147483648, 'x'])`;按正确预期断言 `array.get(0).params` 精确等于 `[true, 0x0102030405060708n, 2147483648, 'x']`;中文注释锚定 `06-TEST-FINDINGS.md` 的 `#06-04-1`/`#06-04-2` 并说明「修复两个编码/解码缺陷后取消 skip」。该用例为 `it.skip`,不影响 `pnpm test:ci` 绿。
+ 若执行时发现 `#06-04-1`/`#06-04-2` 已在后续修复批次解决(编码/解码已正确),则取消对应 skip 并转为可跑绿回归用例,同时在 `06-TEST-FINDINGS.md` 更新状态;否则保持 skip。
+
+
+ pnpm exec vitest run packages-user/data-common/src/replay/array.test.ts
+ 该文件运行失败(非 skip),或 G-06-04-A 缺少正确预期的 `it.skip`(多字节 bigint / 超 int32 int64),或 skip 用例被改写成可通过断言、或中文注释锚点缺失
+
+
+ - G-06-04-A:两条既有 skip 保持(锚定 `#06-04-1`/`#06-04-2`),并新增一条异质序列组合 skip(正确预期)。
+ - `pnpm test:ci` 仍全绿(新增 skip 不产生失败)。
+ - 每个新增 `it.skip` 前有单行中文注释并锚定 `06-TEST-FINDINGS.md` 条目(D-05)。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 2 的 G-06-04-A 以正确预期 skip 纳入且在阶段 1 跑绿基础上保持全绿后才进入阶段 3。若发现阻断性 bug,暂停并按 D-05/D-07 向用户汇报、等确认。
+
+
+
+ 阶段 3(完整):G-06-03-A 多 code/id 复用同一 prefab 生成独立怪物的正确预期 skip(含覆盖表写入)
+ packages-user/data-base/src/enemy/manager.test.ts, .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+
+ packages-user/data-base/src/enemy/manager.test.ts(既有 `createManager`/`createPrefab`/`bridge` 与 `#06-03-1` 的 skip)
+ packages-user/data-base/src/enemy/manager.ts(`addPrefab`/`reusePrefab`/`getPrefab`/`getPrefabById`/`createEnemy`/`createEnemyById`,**只读参考**)
+ .planning/phases/06-unit-tests/06-TEST-FINDINGS.md(`#06-03-1`)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-03-A)
+
+
+ 在 `manager.test.ts` 的「reuse mapping」分区新增一条正确预期 `it.skip`,专门覆盖「4 个朝向 code → 1 个 prefab → 分别 createEnemy 得到 4 个互相独立的怪」的完整链路(当前受 `#06-03-1` 阻塞):
+ 1) `const manager = createManager()`;`manager.addPrefab(createPrefab(1, 'slime'))`;
+ 2) 四个朝向复用同一来源:`manager.reusePrefab(1, 100, 'slime-up')`、`reusePrefab(1, 101, 'slime-right')`、`reusePrefab(1, 102, 'slime-down')`、`reusePrefab(1, 103, 'slime-left')`;
+ 3) 正确预期:先断言读路径 `getPrefab(100..103)` 均等于 `getPrefab(1)`;再 `const created = [100, 101, 102, 103].map(code => manager.createEnemy(code))`,断言 `created.every(e => e !== null)`、各 `e.id === 'slime'`、四者互不相同(`new Set(created).size === 4`)、且与模板不同;对第一个 `setAttribute('hp', 99)` 后断言其余三者与模板 `hp` 仍为 20,证明互相独立;
+ 4) 同样对 `createEnemyById('slime-up'|'slime-right'|'slime-down'|'slime-left')` 断言读回同一来源且各自独立。
+ 整条用例为 `it.skip`,中文注释锚定 `06-TEST-FINDINGS.md` 的 `#06-03-1` 并说明「修复复用映射后取消 skip」;不改动既有同锚点 skip。注意 D-30:不使用 `fromLegacyEnemy` 等 legacy 接口。
+ 完成后以 create-or-append 方式写入 `06-COVERAGE-MAP.md` 的 06-12 小节:本计划**不引入新码**,先确认表头存在(不存在则创建),再追加 `## 06-12 录像与 enemy 模型缺口补测` 小节,列出 G-06-04-A(skip)/G-06-04-B/G-06-03-A(skip)→ 用例名 → 计划 06-12 的映射,并注明「本计划无新增码,复用既有可达码;两条为受阻塞的正确预期 skip」;只追加/更新本小节,绝不重写他节。
+
+
+ pnpm exec vitest run packages-user/data-base/src/enemy/manager.test.ts
+ 该文件运行失败(非 skip),或 G-06-03-A 缺少 4 朝向复用 → 4 个独立怪物的正确预期 `it.skip`,或该 skip 被写成可通过断言,或 06-12 小节未写入 `06-COVERAGE-MAP.md`,或既有 manager 用例回归失败
+
+
+ - `manager.test.ts` 零非跳过失败。
+ - G-06-03-A:新增正确预期 `it.skip` 覆盖 4 个朝向 code/id 复用同一 prefab 并生成 4 个互相独立怪物的完整链路,锚定 `#06-03-1`。
+ - `06-COVERAGE-MAP.md` 存在 06-12 小节(create-or-append,未重写他节),列出 G-06-04-A/B、G-06-03-A 的用例映射。
+ - 每个新增 `it.skip` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 3 的 G-06-03-A 正确预期 skip 在阶段 1/2 跑绿基础上保持全绿,且 06-12 小节已写入 `06-COVERAGE-MAP.md`。完成后暂停并用中文分条汇报;详细结果写入 `06-TEST-FINDINGS.md`。
+
+
+
+
+
+## Trust Boundaries
+
+| Boundary | Description |
+|----------|-------------|
+| none | 仅新增/扩展仓库内 Node Vitest 测试;无运行时输入面、网络、DOM 或文件写入。 |
+
+## STRIDE Threat Register
+
+| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
+|-----------|----------|-----------|----------|-------------|-----------------|
+| T-06-12-01 | Tampering | `data-common/src/replay` 与 `data-base/src/enemy` 下测试文件 | low | mitigate | 只导入已跟踪模块、合成 fixture;不改核心源码;门禁 `pnpm test:ci` + 复核仅 `*.test.ts` 变更。 |
+| T-06-12-02 | Information disclosure | 合成 fixture | low | accept | 合成录像/怪物属性,无真实数据或密钥(D-02)。 |
+| T-06-12-03 | Repudiation | 受阻塞 skip 被误改为通过 | low | mitigate | skip 用例保留中文注释与 `06-TEST-FINDINGS.md` 锚点;`pnpm test:ci` 全绿即证明未弱化。 |
+| T-06-12-SC | Tampering | 包安装 | high | mitigate | 明确不引入任何新依赖;若确需安装,停止并先走包合法性 checkpoint。 |
+
+
+
+- 两个测试文件聚焦运行通过;`pnpm test:ci` 全量绿。
+- `git status` 仅显示两个 `*.test.ts` 与 `06-COVERAGE-MAP.md` 的变更;无核心文件改动。
+- G-06-04-A、G-06-03-A 均为正确预期 `it.skip` 且有 `06-TEST-FINDINGS.md` 锚点;G-06-04-B 为可跑绿。
+- 以 create-or-append 方式写入 `06-COVERAGE-MAP.md` 06-12 小节;表头不存在则先创建;幂等、顺序无关,不重写他节。
+- **执行协议**:执行前必须先向用户确认;执行后暂停并用中文分条汇报。
+
+
+
+- G-06-04-B 有可跑绿的异质多命令序列读回用例。
+- G-06-04-A、G-06-03-A 以正确预期 `it.skip` 纳入并锚定既有 finding 条目,`pnpm test:ci` 保持全绿。
+- 无生产代码改动。
+
+
+
+Test files (extended):
+- `packages-user/data-common/src/replay/array.test.ts`(新增异质序列读回 2 条可跑绿用例 + 1 条组合正确预期 skip)
+- `packages-user/data-base/src/enemy/manager.test.ts`(新增 4 朝向复用生成独立怪物的正确预期 skip)
+
+Planning artifacts:
+- `06-COVERAGE-MAP.md` create-or-append 06-12 小节
+
+
+
diff --git a/.planning/phases/06-unit-tests/06-13-PLAN.md b/.planning/phases/06-unit-tests/06-13-PLAN.md
new file mode 100644
index 0000000..69407e9
--- /dev/null
+++ b/.planning/phases/06-unit-tests/06-13-PLAN.md
@@ -0,0 +1,267 @@
+---
+phase: 06-unit-tests
+plan: 13
+type: execute
+wave: 3
+depends_on: [06-03, 06-05, 06-06, 06-09]
+files_modified:
+ - packages-user/data-base/src/hero/saveLoad.test.ts
+ - packages-user/data-base/src/map/saveLoad.test.ts
+ - packages-user/data-state/test/saveablesRoundTrip.test.ts
+ - .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+autonomous: true
+requirements: [TEST-01]
+estimate:
+ tokens: 62000
+ raw_tokens: 62000
+ tasks: 3
+ confidence: low
+must_haves:
+ truths:
+ - "TEST-01 由数据端行为单测满足,门禁为固定非 watch 命令 `pnpm test:ci` 全绿(D-08)。"
+ - "G-06-09-B:所有含 `saveState`/`loadState` 的类在 `NoCompression`/`LowCompression`/`HighCompression` 三档下各验证一次往返;接受 compression 参数的类(`EquipmentState`/`HeroItems`/`HeroState`/`StaticTile`/`DynamicTile`)各自三档循环;不接受 compression 参数的类(`HeroLocation`/`HeroRendering`/`HeroEquipment`/`FlagSystem`/`ReplaySystem`)经**容器三档**(`HeroState` 与 `CoreState`)确认读取正确。"
+ - "G-06-09-A:`CoreState` 顶层往返对每类 saveable 的**全部关键状态**逐一严格断言(勇士属性/位置/修饰器、flags 多字段、地图多块/激活状态、enemy 多属性、录像 ≥10 步多样化命令),必须严格一致(D-13 的关键字段显式断言)。"
+ - "录像内容要求:至少 10 步、命令不全相同、多种组合(Up/Right/Down/Left/Teleport/UseItem/Equip/Unequip 混合且参数类型多样),读档后逐条 exact 断言命令与参数。"
+ - "失败/受阻塞分支按 D-05 处理:既有 `#06-09-1`/`#06-09-2`/`#06-09-3`/`#06-09-5` 的 `it.skip` 保持不变;若三档扩展在某档命中已知缺陷,则写正确预期 + `it.skip` 并锚定既有 finding 条目,绝不弱化为通过;`pnpm test:ci` 保持全绿。"
+ - "接口覆盖:只经既有公开接口驱动(各 `saveState`/`loadState`、`CoreState.saveState`/`loadState`、`getSaveableContent`);名称含 legacy 的接口/方法排除(D-30)。"
+ - "code 覆盖(模块可达):本计划不引入新码;复用并再确认 06-09 既有可达码(55/58/59/112/113/119/120/122/124/177/178)的覆盖不被削弱(D-31)。"
+ - "存读档集中(D-32):本计划是本批次唯一测试 `saveState`/`loadState` 的计划;其它计划不测;不引入 `fake-indexeddb`、不 `saveSystem.init`(D-10)。"
+ - "阶段化(D-43):计划按 构件→组合→完整/集成 三阶段组织,取消 tracer-first;每阶段跑绿后才进入下一阶段;某阶段发现阻断性 bug 时暂停并按 D-05/D-07 向用户汇报、等确认,不得跳过或弱化。"
+ - "质量门禁(D-44):每个计划执行后、提交前,改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误(全局既有无关错误不在范围);`pnpm test:ci` 全绿;任一不通过不得提交。"
+ - "执行节奏(D-33):本计划执行前先向用户确认;执行完成后暂停,用中文分条简要汇报验证结果,详细结果写入共用的 `06-TEST-FINDINGS.md`。"
+ - "增量补测(D-46):只新增/扩展 `*.test.ts`,不改动已执行的 06-01..06-09 计划与任何生产/核心源码;fixture 文件内联(D-02/D-03),不使用 fake timers(D-04)。"
+ artifacts:
+ - path: packages-user/data-base/src/hero/saveLoad.test.ts
+ provides: G-06-09-B hero 各单档类三档化(含经 HeroState 容器三档覆盖 Location/Rendering/Equipment)
+ - path: packages-user/data-base/src/map/saveLoad.test.ts
+ provides: G-06-09-B StaticTile/DynamicTile 三档化
+ - path: packages-user/data-state/test/saveablesRoundTrip.test.ts
+ provides: G-06-09-A CoreState 顶层全关键状态严格一致 + 录像 ≥10 步多样化;G-06-09-B flags/replay 容器三档
+ - path: .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+ provides: 阶段级 code → 模块 → 用例 映射表(本计划 create-or-append 06-13 小节)
+ key_links:
+ - "hero/saveLoad.test.ts 复用既有 `SAVE_COMPRESSIONS`、`createState`/`createEquipEnv`/`createHeroState`/`createFollowerState`/`registerItem`;三档循环参照既有 `HeroEquipsStore`/`HeroFollower` 的 `for (const compression of SAVE_COMPRESSIONS)` 形状"
+ - "map/saveLoad.test.ts 复用既有 `SAVE_COMPRESSIONS`、`createMapFixture`/`setLayerReference`;三档循环参照既有 `MapLayer`/`GameMap`/`MapState` 用例形状;DynamicTile 的 `#06-09-3` skip 保持不变"
+ - "saveablesRoundTrip.test.ts 以公开入口 `CoreState.saveState(compression)` / `loadState(state, compression)`(D-45)为主路径,`getSaveableContent(id)` 作辅助;录像经 `state.replaySystem.record(code, ...params)` 写入 ≥10 步;不接触 `saveSystem.init`/IndexedDB(D-10)"
+ - "`06-SAVE-EXCLUSIONS.md` 为既有排除清单(存档无关/元数据字段),本计划三档断言仍只覆盖该清单允许的关键字段(D-13/D-42)"
+ - "`.planning/phases/06-unit-tests/06-COVERAGE-MAP.md` 为共享 create-or-append 文件(幂等、顺序无关):写 06-13 小节前先检查表头(`| code | 模块 | 用例 | 计划 |`)是否存在,不存在则先创建,再只追加/更新本小节,绝不重写他节"
+ prohibitions:
+ - "不创建或修改任何生产/核心源码,只新增/扩展 `*.test.ts` 与规划产物"
+ - "不改动 06-01..06-09 的 PLAN.md"
+ - "不引入 `fake-indexeddb`,不 `saveSystem.init`,不做 IndexedDB 端到端存档(D-10)"
+ - "不做整体深度相等;不比较派生/缓存/序列化容器结构(D-13)"
+ - "不安装覆盖率工具(D-09)"
+ - "不建立跨文件共享 fixture/factory helper,fixture 全部文件内联(D-02/D-03)"
+ - "不使用 fake timers(D-04)"
+ - "受阻塞/已知缺陷不得弱化为通过;按正确预期编写并标记 `it.skip`/`it.todo`(D-05)"
+---
+
+
+按 D-43 阶段化(构件 → 组合 → 完整/集成)补齐 06-09(存档)人工评审发现的覆盖缺口(D-46):
+
+- **G-06-09-A** `CoreState` 顶层关键状态不完整、录像步数过少
+- **G-06-09-B** 多数 saveLoad 类未验证三档压缩均能正确读取
+
+Purpose: 现有顶层往返对每类 saveable 只断言 1 个关键字段、录像仅 1 步;hero/map 多个类只在 `NoCompression` 验证。本计划把每类关键状态逐一严格断言、录像构造 ≥10 步多样化命令,并把单档类三档化(不区分压缩度的类经容器三档确认)。本计划只补测试,不改任何生产代码。
+
+本计划是本批次**唯一**测试 `saveState`/`loadState` 的计划(D-32)。
+
+Output: 3 个既有 `*.test.ts` 的扩展与 `06-COVERAGE-MAP.md` 的 06-13 小节。
+
+阶段结构(D-43):阶段 1 构件级(hero 单档类三档化 + 经容器覆盖无参类)→ 阶段 2 组合(map StaticTile/DynamicTile 三档化)→ 阶段 3 完整/集成(CoreState 顶层全关键状态严格一致 + 录像 ≥10 步多样化 + flags/replay 容器三档)。每阶段跑绿后再进入下一阶段。
+
+
+
+@C:/Users/book/.config/opencode/gsd-core/workflows/execute-plan.md
+@C:/Users/book/.config/opencode/gsd-core/templates/summary.md
+
+
+
+@.planning/phases/06-unit-tests/06-CONTEXT.md
+@.planning/phases/06-unit-tests/06-COVERAGE-GAPS.md
+@.planning/phases/06-unit-tests/06-PATTERNS.md
+@.planning/phases/06-unit-tests/06-TEST-FINDINGS.md
+@.planning/phases/06-unit-tests/06-SAVE-EXCLUSIONS.md
+@.planning/codebase/TESTING.md
+@dev.md
+@packages-user/data-common/src/save/types.ts
+@packages-user/data-base/src/hero/state.ts
+@packages-user/data-base/src/hero/equipStore.ts
+@packages-user/data-base/src/hero/items.ts
+@packages-user/data-base/src/hero/location.ts
+@packages-user/data-base/src/hero/rendering.ts
+@packages-user/data-base/src/hero/equipment.ts
+@packages-user/data-base/src/hero/saveLoad.test.ts
+@packages-user/data-base/src/map/staticTile.ts
+@packages-user/data-base/src/map/dynamicTile.ts
+@packages-user/data-base/src/map/saveLoad.test.ts
+@packages-user/data-state/src/core.ts
+@packages-user/data-state/test/saveablesRoundTrip.test.ts
+@packages-user/data-common/src/replay/system.ts
+@packages-user/data-base/src/flag/system.ts
+@packages/common/src/logger.json
+
+
+
+- 只写测试,绝不修改 `packages-user/*/src` 下的非 `*.test.ts` 文件。
+- 每个 `it(...)` 之前必须有一行中文注释说明覆盖内容(dev.md 注释规范),测试范围变化时同步更新。
+- fixture 内联且最小(D-02/D-03),沿用目标文件既有 helper,不新造跨文件 helper。
+- 三档压缩:`NoCompression`/`LowCompression`/`HighCompression`;对不接受 compression 参数的类经容器三档确认。
+- 警告/错误路径经 `logger.catch` / `vi.spyOn(logger, ...)`。
+- 「状态相同」只用关键字段显式断言(D-13);排除清单见 `06-SAVE-EXCLUSIONS.md`。
+- 已知缺陷:既有 `#06-09-1..5` 的 `it.skip` 保持不变;新命中的缺陷按正确预期编写、标记 `it.skip`、中文注释锚定既有 `#06-09-N`(或新建 `#06-13-N`),`pnpm test:ci` 必须保持全绿(D-05)。
+- 不引入 `fake-indexeddb`,不 `saveSystem.init`(D-10)。
+- `06-COVERAGE-MAP.md` 为共享 create-or-append 文件(幂等、顺序无关):写入前先检查表头(`| code | 模块 | 用例 | 计划 |`)是否存在,不存在则先创建,再只追加/更新本计划小节,绝不重写他节。
+- **执行协议(D-33):执行本计划前必须先向用户确认;执行完成后暂停,用中文分条简要汇报本计划验证结果;详细结果写入共用的 `06-TEST-FINDINGS.md`。**
+- **阶段门禁(D-43):本计划按 构件 → 组合 → 完整/集成 三阶段顺序执行,每阶段跑绿后才进入下一阶段;若某阶段发现阻断性 bug 使后续阶段无法运行,暂停并按 D-05/D-07 向用户汇报、等确认,不得跳过或弱化。**
+- **质量门禁(D-44,每个计划执行后、提交前必过)**:对改动文件运行 `eslint --fix`,并确保 `eslint <改动文件>` **0 错误**;对**本计划改动的测试文件**运行 `pnpm exec vue-tsc --noEmit`,并按输出文件路径过滤,确保这些文件路径下 **0 类型错误**(全局既有无关错误,如 `client-modules`/`legacy-plugin-data`,不在本门禁范围);`pnpm test:ci` **全绿**。任一不通过则**不得提交**。
+
+
+
+
+
+ 阶段 1(构件级):G-06-09-B hero 单档类三档化 + 经 HeroState 容器三档覆盖无参类
+ packages-user/data-base/src/hero/saveLoad.test.ts
+
+ packages-user/data-base/src/hero/saveLoad.test.ts(既有 `SAVE_COMPRESSIONS` 与 EquipmentState/HeroItems/HeroState 单档用例、HeroLocation/HeroRendering/HeroEquipment 无参用例)
+ packages-user/data-base/src/hero/equipStore.ts(`EquipmentState.saveState(compression)`/`loadState(save, compression)`;`#06-09-1` 相关)
+ packages-user/data-base/src/hero/items.ts(`HeroItems.saveState(compression)`/`loadState(state, compression)`)
+ packages-user/data-base/src/hero/state.ts(`HeroState.saveState(compression)` 聚合 location/rendering/equip/items)
+ packages-user/data-base/src/hero/location.ts / rendering.ts / equipment.ts(`saveState()`/`loadState(state)` 无 compression 参数)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-09-B)
+ .planning/phases/06-unit-tests/06-SAVE-EXCLUSIONS.md
+
+
+ 把 hero 单档类三档化,并让无 compression 参数的类经 `HeroState` 容器三档确认:
+ 1) `EquipmentState`:把既有「百分比加成恢复」用例改为 `for (const compression of SAVE_COMPRESSIONS)` 三档循环(每档新建 `EquipmentState`,`saveState(compression)` → `loadState(saved, compression)` → 断言百分比修饰器值);把既有 value-modifier 与 compressed 两条 `it.skip`(锚定 `#06-09-1`)保持不变。
+ 2) `HeroItems`:三档循环,每档新建 env/items → 设已知数量 → `saveState(compression)` → 改变数量 → `loadState(saved, compression)` → 断言永久/消耗两表数量与 `getItemState` 关键字段。
+ 3) `HeroState`:三档循环,每档新建 `createHeroState()` → 注册并插入修饰器、设 base 属性、设位置/楼层/朝向 → `saveState(compression)` → 改状态 → `loadState(saved, compression)` → 断言 base 属性、final 属性、`getLocation()` 与 `location.floorId`。
+ 4) 无参类经容器三档:新增用例,三档循环内用 `hero.saveState(compression)`/`loadState(saved, compression)`,断言 `hero.location`(坐标/楼层/朝向)、`hero.rendering.alpha`(若 `HeroState` 公开该成员)、`hero.equip.getEquipped(...)`(若公开)在每档均恢复到存档点;成员名以 `state.ts` 实际公开成员为准,不确定时只断言确定公开的 location 字段并在注释中说明。
+ 实现时若某档命中已知缺陷(如 `#06-09-1`),按 D-05 将该档改为正确预期 `it.skip` 并中文注释锚定既有 `#06-09-N`,不得弱化为通过;若发现新缺陷,登记 `06-TEST-FINDINGS.md` 的 `#06-13-N`。每个新增/改写的 `it` 前保持单行中文注释。
+
+
+ pnpm exec vitest run packages-user/data-base/src/hero/saveLoad.test.ts
+ 该文件运行失败(非 skip),或 EquipmentState/HeroItems/HeroState 任一未三档循环,或 Location/Rendering/Equipment 未经容器三档确认,或既有 `#06-09-1`/`#06-09-2` skip 被取消/改写
+
+
+ - `hero/saveLoad.test.ts` 零非跳过失败。
+ - G-06-09-B(hero 部分):EquipmentState/HeroItems/HeroState 三档循环;HeroLocation/HeroRendering/HeroEquipment 经 HeroState 容器三档确认;无参类三档均有断言。
+ - 既有 `#06-09-1`/`#06-09-2` skip 保持不变;新命中缺陷按 D-05 处理并锚定。
+ - 每个新增/改写的 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 1 的 G-06-09-B(hero)覆盖全部跑绿后才进入阶段 2。若发现阻断性 bug,暂停并按 D-05/D-07 向用户汇报、等确认。
+
+
+
+ 阶段 2(组合):G-06-09-B map StaticTile/DynamicTile 三档化
+ packages-user/data-base/src/map/saveLoad.test.ts
+
+ packages-user/data-base/src/map/saveLoad.test.ts(既有 `SAVE_COMPRESSIONS`、`createMapFixture`/`setLayerReference`,与 StaticTile/DynamicTile 单档用例)
+ packages-user/data-base/src/map/staticTile.ts / dynamicTile.ts(`saveState()`/`loadState(save)`;既有 `#06-09-3` skip)
+ packages-user/data-base/src/map/mapLayer.ts(tile `saveState(SaveCompression.NoCompression)` 的调用形状)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-09-B)
+ .planning/phases/06-unit-tests/06-SAVE-EXCLUSIONS.md
+
+
+ 把 map 的两个单档 tile 类三档化:
+ 1) `StaticTile`:把既有「覆盖事件恢复」用例改为 `for (const compression of SAVE_COMPRESSIONS)` 三档循环,每档新建 fixture/tile、设覆盖事件 → `tile.saveState(compression)` → 改事件 → `tile.loadState(saved, compression)` → 断言事件映射恢复到存档点(沿用既有锚点与关键字段断言)。
+ 2) `DynamicTile`:同样三档循环断言覆盖事件恢复;既有「恢复图块数字」的 `it.skip`(锚定 `#06-09-3`)保持不变,不改写。
+ 若某档命中已知缺陷,按 D-05 将该档改为正确预期 `it.skip` 并锚定既有 `#06-09-3`(或登记 `#06-13-N`),不得弱化为通过。每个改写的 `it` 前保持单行中文注释并更新为「三档」描述。
+
+
+ pnpm exec vitest run packages-user/data-base/src/map/saveLoad.test.ts
+ 该文件运行失败(非 skip),或 StaticTile/DynamicTile 未三档循环,或既有 `#06-09-3` skip 被取消/改写,或既有 MapLayer/GameMap/MapState 三档用例回归失败
+
+
+ - `map/saveLoad.test.ts` 零非跳过失败。
+ - G-06-09-B(map 部分):StaticTile 与 DynamicTile 均三档循环并断言关键事件字段恢复。
+ - 既有 `#06-09-3` skip 保持不变。
+ - 每个改写的 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 2 的 G-06-09-B(map)覆盖在阶段 1 跑绿的基础上全部跑绿后才进入阶段 3。若发现阻断性 bug,暂停并按 D-05/D-07 向用户汇报、等确认。
+
+
+
+ 阶段 3(完整/集成):G-06-09-A 顶层全关键状态严格一致 + 录像 ≥10 步 + G-06-09-B flags/replay 容器三档(含覆盖表写入)
+ packages-user/data-state/test/saveablesRoundTrip.test.ts, .planning/phases/06-unit-tests/06-COVERAGE-MAP.md
+
+ packages-user/data-state/test/saveablesRoundTrip.test.ts(既有 `SAVEABLE_IDS`/`COMPRESSIONS`/`seedState`/`mutateState`/`assertRestored` 与 5 saveable × 3 档用例)
+ packages-user/data-state/src/core.ts(公开 `saveState`/`loadState`、`getSaveableContent`、5 个注册 id)
+ packages-user/data-common/src/replay/system.ts(`record(code, ...params)`/`route`)
+ packages-user/data-common/src/replay/types.ts(`ReplayCommandCode` 0..7)
+ packages-user/data-base/src/flag/system.ts(`setFieldValue`/`addFieldValue`/`getFieldValue`)
+ .planning/phases/06-unit-tests/06-COVERAGE-GAPS.md(G-06-09-A、G-06-09-B)
+ .planning/phases/06-unit-tests/06-SAVE-EXCLUSIONS.md
+
+
+ 扩展 `saveablesRoundTrip.test.ts`(主路径保持公开 `CoreState.saveState`/`loadState`,D-45):
+ 1) G-06-09-A 全关键状态:扩展 `seedState` 写入**每类 saveable 的全部关键状态**——勇士:base 属性 hp/atk/def/money/exp、`state.hero.location.setPos(x, y)` / `state.hero.location.setFloor('F1')`、朝向经 `state.hero.location.mover.setFaceDir(FaceDirection.Up)`(**`HeroLocation` 自身没有 `setFaceDir`**:其 `saveState`/`loadState` 通过 `mover.faceDirection` 与 `mover.setFaceDir` 读写朝向,故必须先 `mover` 再 `setFaceDir`,并需从 `@user/data-common` 导入 `FaceDirection`)、修饰器值;flags:`setFieldValue('score',7)`、`setFieldValue('coins',12)`、`addFieldValue('stage',2)`;地图:`createMap('F1',2,2)` → `addLayer` → `setZIndex(0)` → `setBlock(5,0,0)`/`setBlock(7,1,1)` → `setActiveStatus(true)`;enemy:`addPrefab` → `compareWith` → `modifyPrefabAttribute` 设 hp 30 与 atk 9;录像:`record` ≥10 步多样化命令。
+ 2) 录像 ≥10 步多样化序列(命令不全相同):`state.replaySystem.record(0)`、`record(1)`、`record(2)`、`record(3)`、`record(4, 2, 3)`(Teleport)、`record(5, 12)`(UseItem)、`record(6, 3, 0, true)`(Equip)、`record(7, 0)`(Unequip)、`record(1)`、`record(5, 'potion')`;断言 `state.replaySystem.route.length === 10` 且对每步 `route.get(i)` 精确等于 `{command, params, index}`。
+ 3) `mutateState` 同样改遍上述全部关键状态;`assertRestored` 对上述**每一项**逐一严格断言(勇士属性/位置/修饰器、flags 三字段、地图两块与激活状态、enemy 两属性、录像 10 步逐条)。保留 5 saveable × 3 压缩档循环(D-11),并使用既有 `#06-09-5` 的 skip 不变。
+ 4) G-06-09-B(flags/replay 容器三档):新增用例对 `@system/flags` 与 `@system/replay` 三档循环——每档改 flags 字段与追加录像步 → `saveState(compression)` → 再改 → `loadState(snapshot, compression)` → 断言 flags 字段与录像步数/逐条命令恢复到存档点(不区分压缩度的类经容器三档确认读取正确)。
+ 若某档命中已知缺陷(`#06-09-1..5`),按 D-05 写正确预期 + `it.skip` 并锚定;不得弱化为通过。每个新增/改写的 `it` 前有单行中文注释。
+ 完成后以 create-or-append 方式写入 `06-COVERAGE-MAP.md` 的 06-13 小节:本计划**不引入新码**,先确认表头存在(不存在则创建),再追加 `## 06-13 存档缺口补测` 小节,列出 G-06-09-A、G-06-09-B → 用例名 → 计划 06-13 的映射,并注明「本计划无新增码,复用 06-09 既有可达码」;只追加/更新本小节,绝不重写他节。
+
+
+ pnpm exec vitest run packages-user/data-state/test/saveablesRoundTrip.test.ts
+ 该文件运行失败(非 skip),或顶层往返未对每类 saveable 的全部关键状态逐一断言,或录像少于 10 步/命令全相同,或 flags/replay 未三档经容器确认,或 06-13 小节未写入 `06-COVERAGE-MAP.md`,或既有 `#06-09-5` skip 被取消
+
+
+ - `saveablesRoundTrip.test.ts` 零非跳过失败。
+ - G-06-09-A:每类 saveable 的全部关键状态逐一严格断言;录像 ≥10 步多样化命令逐条 exact 断言。
+ - G-06-09-B(flags/replay):三档经容器确认读取正确。
+ - `06-COVERAGE-MAP.md` 存在 06-13 小节(create-or-append,未重写他节),列出 G-06-09-A/B 的用例映射。
+ - 既有 `#06-09-1..5` skip 保持不变;每个新增/改写的 `it` 前有单行中文注释。
+ - D-44 门禁通过:改动文件 `eslint --fix` 后 `eslint <改动文件>` 0 错误;本计划改动的测试文件在 `pnpm exec vue-tsc --noEmit` 输出中按文件路径过滤 0 类型错误;`pnpm test:ci` 全绿。
+
+ 阶段 3 的 G-06-09-A/B(顶层)覆盖在阶段 1/2 跑绿的基础上全部跑绿,且 06-13 小节已写入 `06-COVERAGE-MAP.md`。完成后暂停并用中文分条汇报;详细结果写入 `06-TEST-FINDINGS.md`。
+
+
+
+
+
+## Trust Boundaries
+
+| Boundary | Description |
+|----------|-------------|
+| none | 仅新增/扩展仓库内 Node Vitest 测试;无运行时输入面、网络、DOM 或文件写入(不碰 IndexedDB)。 |
+
+## STRIDE Threat Register
+
+| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
+|-----------|----------|-----------|----------|-------------|-----------------|
+| T-06-13-01 | Tampering | `data-base/src/hero`、`data-base/src/map`、`data-state/test` 下测试文件 | low | mitigate | 只导入已跟踪模块、合成快照;不安装包、不改核心源码;门禁 `pnpm test:ci` + 复核仅 `*.test.ts` 变更。 |
+| T-06-13-02 | Information disclosure | 快照 fixture | low | accept | 合成状态,无真实存档文件或密钥(D-02)。 |
+| T-06-13-03 | Repudiation | 全局 stub 泄漏 | low | accept | 既有文件已在 `vi.hoisted`/`afterAll` 管理 stub;新增用例不引入新 stub。 |
+| T-06-13-SC | Tampering | 包安装(尤其 `fake-indexeddb`) | high | mitigate | 明确不引入 `fake-indexeddb` 或任何新依赖;若确需安装,停止并先走包合法性 checkpoint。 |
+
+
+
+- 三个测试文件聚焦运行通过;`pnpm test:ci` 全量绿。
+- `git status` 仅显示三个 `*.test.ts` 与 `06-COVERAGE-MAP.md` 的变更;无核心文件改动。
+- 既有 `#06-09-1..5` 的 `it.skip` 保持不变;任何新增 skip 均有 `#06-13-N`(或既有)条目。
+- 以 create-or-append 方式写入 `06-COVERAGE-MAP.md` 06-13 小节;表头不存在则先创建;幂等、顺序无关,不重写他节。
+- **执行协议**:执行前必须先向用户确认;执行后暂停并用中文分条汇报。
+
+
+
+- G-06-09-A:顶层每类 saveable 的全部关键状态逐一严格断言;录像 ≥10 步多样化命令逐条 exact 断言。
+- G-06-09-B:所有含 `saveState`/`loadState` 的类三档覆盖(无参类经容器三档)。
+- 无生产代码改动,`pnpm test:ci` 全绿。
+
+
+
+Test files (extended):
+- `packages-user/data-base/src/hero/saveLoad.test.ts`(EquipmentState/HeroItems/HeroState 三档化 + 经 HeroState 容器覆盖 Location/Rendering/Equipment)
+- `packages-user/data-base/src/map/saveLoad.test.ts`(StaticTile/DynamicTile 三档化)
+- `packages-user/data-state/test/saveablesRoundTrip.test.ts`(全关键状态严格一致 + 录像 ≥10 步多样化 + flags/replay 容器三档)
+
+Planning artifacts:
+- `06-COVERAGE-MAP.md` create-or-append 06-13 小节
+
+
+