# EM 完整方向段可视化修复 — Phase 05 交接

## 状态

完成，2026-08-07。

启动分支为 `trajplanner`，启动 HEAD 为 `5d1c875`（Phase 04 handoff）。已确认 `ab3204b`、`5d1c875` 均为本阶段提交的祖先。

本阶段实现提交：

- `d33257c` — `fix: publish distinct EM observation semantics`

本交接文件单独提交；其真实提交哈希由提交后的最终答复提供给 Phase 06。

## 目标与非目标

完成主计划 Task 7：统一快照、路径图层、曲线单位、`s_end`、车辆与换向语义。

未进入 Task 8+、Web DOM、Native Painter、跨段规划扩展或实车操作。MovementTest 保持 `OBSERVE_ONLY`，未新增任何底盘、转向、制动、电机或换挡写输出。

## 实现摘要

- 新增 `VisualizationChartAnnotation`，`VisualizationChart` 增加不可变 `Annotations`，旧构造函数保持空注解兼容。
- 静态与动态快照使用 `gear-switch-end` / `final-goal` 标记，并补充车辆、计划起点标记；完整段不再重复发布 `current-horizon`。
- LS/ST/世界均标记 `s_end`；换向边界使用“换向点 N / s_end”，最终目标使用“终点 / s_end”。
- 动态快照构建器接收 `VehicleParameters`，曲率硬上限改为真实车辆 `MaximumCurvaturePerMeter`，横摆角速度轴改为 `ω (rad/s)`。
- MovementTest 网页发布回调把 `bootstrap.Vehicle` 传入动态快照构建器。

## 修改文件

实际修改：

- `ClumsyPilot/TrajectoryPlanningVisualization/Contracts/VisualizationCharts.cs`
- `ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/TrajectoryObservationStaticSnapshotBuilder.cs`
- `ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/TrajectoryObservationDynamicSnapshotBuilder.cs`
- `ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/TrajectoryObservationKinematicChartBuilder.cs`
- `ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/MovementTest.TrajectoryObservationTest.cs`
- `ClumsyPilot/tests/EMPlannerVerificationHost/TrajectoryObservationVisualizationChecks.cs`
- `ClumsyPilot/tests/TrajectoryPlanningVisualizationVerificationHost/ContractChecks.cs`
- `ClumsyPilot/tests/TrajectoryPlanningVisualizationVerificationHost/SampleSnapshotFactory.cs`

白名单内未改动：`VisualizationGeometry.cs`。现有折线/标记/方向段几何契约已满足 Task 7 语义，无需重复修改。

## 新增或改变的接口

- `VisualizationChartAnnotation(id, kind, labelChinese, x, double? y = null)`。
- `VisualizationChart.Annotations`；旧 6 参数构造器委托到带空注解的新构造器。
- `TrajectoryObservationDynamicSnapshotBuilder.Build(..., VehicleParameters vehicle, EmPlannerConfiguration configuration)`。
- `TrajectoryObservationKinematicChartBuilder.Build(..., VehicleParameters vehicle, EmPlannerConfiguration configuration)`。
- 曲线硬上限取 `VehicleParameters.MaximumCurvaturePerMeter`；没有直接曲率时回退到 `MinimumTurningRadiusMeters`。

## RED / GREEN / 回归证据

RED：

```powershell
dotnet run --project ClumsyPilot/tests/EMPlannerVerificationHost/EMPlannerVerificationHost.csproj -- trajectory-observation
dotnet run --project ClumsyPilot/tests/TrajectoryPlanningVisualizationVerificationHost/TrajectoryPlanningVisualizationVerificationHost.csproj
```

首个有效失败为 `static snapshot marks gear-switch s_end was false`，可视化宿主为 `chart exposes immutable annotations`。测试集还包含同一 current 不重复发布为 `current-horizon`、曲率上限必须来自车辆几何的断言；`Verification` 在首个失败处停止，因此未单独打印后续断言。

GREEN（串行运行，避免共享 `obj` DLL 锁）：

```powershell
dotnet run --project ClumsyPilot/tests/EMPlannerVerificationHost/EMPlannerVerificationHost.csproj -- trajectory-observation
```

退出码 0，输出 `PASS trajectory-observation`。

```powershell
dotnet run --project ClumsyPilot/tests/TrajectoryPlanningVisualizationVerificationHost/TrajectoryPlanningVisualizationVerificationHost.csproj
```

退出码 0，输出 `PASS trajectory-planning-visualization`。

## 执行器审计与清理

```powershell
rg -n "SendXYThSpeed|SendMotion|DriveStop|PredefinedDriveStop|AccumulateSpeed|SetGear|SetBrake" ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest
```

无匹配（rg 退出码 1，符合“无匹配”预期）。

`git diff --check` 与暂存后 `git diff --cached --check` 均退出码 0，仅有既有 LF/CRLF 提示，无新空白错误。

## 工作区保护

保留并未回退用户既有脏工作区与未跟踪内容，包括但不限于 `.gitignore`、`EmPlannerConfiguration.cs`、PathSmoothing/CoarsePath/Map 相关改动、文档和未跟踪报告。

实现提交只显式暂存本阶段白名单文件；提交后 `git diff --cached --name-only` 为空，未使用 `git reset --hard`、`git checkout --`、`git clean`、`git add .` 或 `git add -A`。

## 已知警告与偏差

- 既有两条编译 warning 保留：`Lidar2dDetect2LegTray.LegWidth` 与 `MultiWheelChassis.GetSteerWheels()`。
- `git diff --check` 持续输出仓库既有 LF/CRLF 提示，不影响空白检查结果。
- `VisualizationGeometry.cs` 本阶段未改动；如果后续阶段发现几何契约不足，应在 Phase 08 Painter 范围内处理，而不是本阶段扩展。

## 未运行项

- 未进入 Phase 06 或后续任何阶段。
- 未执行 Web DOM/jsdom、Native Painter、跨段规划扩展或实车操作。
- 未运行 `em-core-all`；本阶段验证命令按任务要求仅执行两个宿主、执行器审计和 `git diff --check`。

## Phase 06 事实

对应主计划 Task 8，阶段执行计划 Task 6：真实 DOM/SVG 测试与 Web 渲染修复。

Phase 06 允许创建/修改：

- 创建：`ClumsyPilot/tests/TrajectoryPlanningVisualizationWebDom/package.json`
- 创建：`ClumsyPilot/tests/TrajectoryPlanningVisualizationWebDom/package-lock.json`
- 创建：`ClumsyPilot/tests/TrajectoryPlanningVisualizationWebDom/dashboard.dom.test.mjs`
- 修改：`ClumsyPilot/TrajectoryPlanningVisualization/Web/index.html`
- 修改：`ClumsyPilot/TrajectoryPlanningVisualization/Web/app.css`
- 修改：`ClumsyPilot/TrajectoryPlanningVisualization/Web/app.js`
- 修改：`ClumsyPilot/tests/TrajectoryPlanningVisualizationVerificationHost/WebAssetChecks.cs`
- 交接：`docs/superpowers/handoffs/em-full-direction-visualization/phase-06.md`

接口与验证要求：

- 使用 Node 24 + `jsdom` 29.1.1 的开发专用依赖验证真实 DOM/SVG。
- 修复分页隐藏、空白总览、y 轴刻度/单位、稳定数据域、语义图层顺序、车辆/边界标记和论文风细线。
- 测试钩子 `window.__TRAJECTORY_VISUALIZATION_TEST__ === true` 只暴露不可变输入渲染钩子，不启动 fetch/SSE。

必须执行：

```powershell
npm install --package-lock-only --prefix ClumsyPilot/tests/TrajectoryPlanningVisualizationWebDom
npm test --prefix ClumsyPilot/tests/TrajectoryPlanningVisualizationWebDom
dotnet run --project ClumsyPilot/tests/TrajectoryPlanningVisualizationVerificationHost/TrajectoryPlanningVisualizationVerificationHost.csproj
```

期望 RED 是 hidden-section CSS、y ticks、语义类或 empty-state 断言失败；GREEN 是全部 DOM 测试通过且 .NET 宿主打印 `PASS trajectory-planning-visualization`。

实现提交信息：`fix: repair EM observation web charts`。

交接文件单独提交信息：`docs: record EM full-direction phase 06 handoff`。

Phase 06 退出门禁：现有四页布局不重做，正确渲染数据/轴/图层；本阶段不实现缩放。

Phase 06 的 Phase 05 实现提交为 `d33257c`，上一交接文件为本文件；调用方需在最终答复中提供本交接提交的真实哈希并验证可达。
