diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index 2c9f033..d7675a6 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -455,7 +455,7 @@ Plans:
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)
+- [x] 08-02-PLAN.md — data-common 对齐(`utils.test.ts` 退役、`DirectionMapper` 删除、`addHook().load()` 移除、158/175→72;含经确认的 sandbox 首步预读生产修复)
- [ ] 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 裁决)
@@ -483,4 +483,4 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8
| 5. Legacy 移植 | 0/TBD | Not started | - |
| 6. 单元测试 | 18/18 | In Progress| |
| 7. 数据端缺陷修复 | 15/16 | Complete(07-16 superseded) | - |
-| 8. 测试重构与接口对齐 | 0/11 | Planned | - |
+| 8. 测试重构与接口对齐 | 1/11 | In Progress | - |
diff --git a/.planning/phases/08-test-refactor-alignment/08-02-PLAN.md b/.planning/phases/08-test-refactor-alignment/08-02-PLAN.md
index 6ad0b62..79ce505 100644
--- a/.planning/phases/08-test-refactor-alignment/08-02-PLAN.md
+++ b/.planning/phases/08-test-refactor-alignment/08-02-PLAN.md
@@ -99,6 +99,12 @@ Output: 12 个既有测试文件的对齐改动;可能含 1 个文件的退役
- **Q2【中】`sandbox` 失败码契约**:断言 158/175 改为当前实际发出的 72/194,还是视为应保留的契约(需生产修复)?D-05/D-10 下倾向改测试断言,须用户确认。
- **Q3**:`mover.test.ts` 等夹具中的 `DirectionMapper` 残留(已删导出)如何处置——删除该注入位并改用 shipped `IFaceManager`/`IFaceHandler`,还是按既有 `as never` 假值保留(research 记录部分夹具已如此)。
+
+ **裁决日期:** 2026-10-04(用户「可以执行」)
+ - **Q1:** 退役 `packages-user/data-common/src/common/__test__/utils.test.ts`(直接删除;等价覆盖位置在 08-02-SUMMARY 登记)。
+ - **Q2:** `sandbox.test.ts` 的失败码断言改为当前实际发出的码(执行/收口失败 `logger.error(72, method)`、被动步后主动步 `logger.warn(194, ...)`),不做生产修复。
+ - **Q3:** 删除测试夹具中的 `DirectionMapper` 注入位,改用 shipped `IFaceManager`/`IFaceHandler` 表达原断言意图。
+
RESEARCH §8.1/§8.2/§8.3 给出逐符号 delta 与 emit anchor。D-05 明令「只对齐、不新增接口」;D-10 默认零生产改动。本计划不改 `logger.json`。
diff --git a/.planning/phases/08-test-refactor-alignment/08-02-SUMMARY.md b/.planning/phases/08-test-refactor-alignment/08-02-SUMMARY.md
new file mode 100644
index 0000000..7d528a7
--- /dev/null
+++ b/.planning/phases/08-test-refactor-alignment/08-02-SUMMARY.md
@@ -0,0 +1,51 @@
+# 08-02 SUMMARY — data-common 对齐
+
+**执行日期:** 2026-10-04
+**计划:** `08-02-PLAN.md`
+**状态:** 完成(聚焦 147/147 通过;eslint 0;已提交)
+
+## Task 0 裁决(用户)
+
+- **Q1:** 退役 `common/__test__/utils.test.ts`(直接删除)。
+- **Q2:** `sandbox` 失败码断言改为当前实际码(`logger.error(72, method)`)。
+- **Q3:** 删除 `DirectionMapper` 注入残留,改用 shipped `IFaceHandler` 语义。
+
+## 生产改动(唯一,经用户确认的重构遗漏)
+
+- `packages-user/data-common/src/replay/sandbox.ts`:
+ - `play()` 入口与 `step()` 入口各补「惰性预读首步」(`!appendingStep && !reader.expired && !ended` → `appendingStep = reader.read()`)。
+ - 成因:`75a39ad refactor: 被动录像步应当在主动录像步执行期间完成` 重构后丢失初始预读,`appendingStep` 恒为 `null` 被 `replayStep` 当作「已播完」,导致 `step()`/`play()` 无法执行任何命令。
+ - 用户确认为「忘记写了首步读取,在 play 和 step 处预读即可」。
+
+## 测试对齐改动(12 个声明文件中的 5 个失败文件)
+
+| 文件 | 旧 → 新 |
+|------|---------|
+| `common/__test__/face.test.ts` | `getFaceDirection` 未知图块断言 `toBeUndefined()` → `toBe(FaceDirection.Unknown)`(3 处;含未知图块用例标题/注释同步为 Unknown) |
+| `replay/__test__/array.test.ts` | 短字符串内联类型码基址 `9 → 32`:`'hi'` 期望 `11 → 34`(2 处)、空串期望 `9 → 32`(1 处);同步注释与类型表说明 |
+| `replay/__test__/system.test.ts` | 移除 2 处 `addHook(...).load()`;`onRecordCommand` 索引期望 `1 → 0`(生产传 `array.length - 1`) |
+| `replay/__test__/sandbox.test.ts` | 移除 7 处 `addHook(...).load()`;命令桩改为 shipped 契约:`type: ReplayCommandType.Active` + `execute/finalize` 返回 `ReplayCommandResult`(`Success`/`Failed`);失败码 `158 → 72`(`logger.error(72, 'execute')`)、`175 → 72`(`logger.error(72, 'finalize')`),断言改用 `logger.error` |
+| `common/__test__/utils.test.ts` | **删除**(退役)。被测的 `getFaceMovement`/`degradeFace`/`nextFaceDirection`/`fromDirectionString` 已从源码整体删除;等价覆盖在 `common/__test__/faceManager.test.ts`(`Dir4FaceHandler`/`Dir8FaceHandler`/`IFaceHandler`)与 `face.test.ts` |
+
+其余 7 个声明文件(`faceManager`、`indexer`、`mover`、`eventStore`、`tileStore`、`replay/array` 的非失败用例等)零改动。
+
+## 期望值改写台账
+
+- `array.test.ts`:`firstParamToken` short-string `11→34`、empty-string `9→32`、type-table short-string `11→34`(依据 `replay/types.ts:286-301` 的「32~255: n-32 长度字符串」)。
+- `system.test.ts`:`onRecordCommand` index `1→0`(依据 `replay/system.ts:66`)。
+- `sandbox.test.ts`:`getReplayed()` `1→2`(见下方观测)。
+
+## 观测(未登记为缺陷,待用户确认)
+
+- `sandbox.test.ts`「errors code 72 and stops…」:执行一步后 `getReplayed()` 现为 **2**(旧实现为 1)。原因是 shipped `replayStep` 在执行主动步前即预读下一步(`sandbox.ts:210`),`reader.index` 因此包含未执行的下一步;这与 `IReplaySandbox.getReplayed` 文档「已经播放过、不包括当前正在播放的步骤数」存在措辞差异。本计划按 shipped 行为对齐为 `2`,**未改生产**;是否调整实现或文档待用户裁定。
+
+## 门禁证据
+
+- `pnpm exec vitest run packages-user/data-common/src/{common,store,replay}/__test__` → **11 passed / 147 passed**。
+- `pnpm exec eslint --fix` 后 `eslint` 对改动文件 **0 报错**。
+- 生产改动仅 `data-common/src/replay/sandbox.ts`(经确认);其余改动全为 `__test__/` 测试文件。
+- 仓库级 skipped 仍为 1(未新增 skip)。
+
+## 并发保护(D-08)
+
+- 未触碰、未暂存、未提交任何用户并发改动(`client-*` / `system/src/ui/*` / 未跟踪 `client-modules/src/ui/`)。