# StandardScene 插件化拆分计划（导航场景插件化 · Phase C 落地）

> 版本：草案 **v2**（按评审反馈更新）
> 编写依据：对当前工程 `E:\Work\Core\Simple-FR\StandardSence`（.NET Framework 4.8 单体插件）的**逐文件精读**。
> 上游设计：承接并细化《配置向导与导航场景插件化设计.md》第 5 节「StandardScene 拆分」与第 11.3 节「Phase C」。
> 本文目标：把上游"框架级"拆分意图，落地为**基于真实代码事实、可直接执行**的文件级/类级拆分计划。
> 范围声明：本文原为**计划文档**。**自「会话1」(2026-06-09) 起已开始落地实施**，实际进度与代码现状见 **§11 实施进度记忆**（含已落地改动、当前可编译状态、待确认阻塞项）。

### ⚠️ 架构决策变更（2026-06-12，用户拍板）：「磁 / 二维码 / 激光」三场景 → **两场景平台**

原计划的 `Magnetic` / `QrCode` / `Laser` 三个导航 dll 调整为 **两个场景平台插件**（已落地，全解决方案 0 错误）：

| 插件 dll | scene id | 内容 | 说明 |
|---|---|---|---|
| `StandardScene.Magnetic.dll` | `scene.mag` | Kiva、MultiWheelLifterCar + `MagneticTrackCoder` | 磁导航平台（保留车型上的 Qr 地标段能力） |
| `StandardScene.QrLidar.dll` | `scene.qrlidar` | Forklift、MultiWheelForkLifter、DualLiftingCar、MultiVehicleCar、ArmCar + `SyncQrMap` | 激光+二维码融合平台：激光坐标导航由内核 `GhostCar.BasicGo` 兜底，`QrGo` 按轨道 tag 逐段触发，**融合或单独使用均可** |
| `StandardScene.Devices.dll` | `scene.device` | 不变 | 清单 id 由 `devices` 规范化 |
| `StandardScene.Protocol.VDA5050.dll` | `scene.vda5050` | 不变 | 清单 id 由 `protocol.vda5050` 规范化 |

关键机制结论与配套改动：

1. **车型按平台归位**（推翻 v2 "车型留基座"）：依据 = 项目存档按**短类名**（`JSONLoader` 用 `type.Name.ToLower()`）匹配车型，类迁 dll 不破坏旧存档；coder 特性 `GetCustomAttributes(inherit:true)` 沿继承链收集，内核 `GhostCar` 的 BasicGo 天然被所有车型继承。
2. **共享字段袋下沉基座**：`KivaFields.cs` / `MultiWheelLifterFields.cs`（ArmCar、MultiVehicleCar 跨平台继承它们）；`IScriptErrorRecoverable` 接口解耦 `AbstractLoopMission` 对 Kiva 的反向依赖。
3. **清单命名修正**：内核只识别 `<dll>.scene.json`，原裸 `scene.json` 永远不会被扫描到——已全部改名并规范 id。
4. **内核配套**（Simple 仓库）：① `Startup.LoadPlugins` 两阶段加载——清单 `requiresCore` 声明的基座（`StandardScene.dll`）自动并入 alwaysLoad 且 **non-collectible 先行加载**（否则衍生插件的 collectible ALC 解析不到基座，运行期必炸）；② `SceneManifest.navKinds` 多导航声明 + `INavigationProfile.Kinds`（qrlidar 同时覆盖 Laser+QrCode，`FindByKind` 按集合匹配）；③ `ShouldLoad` 规则改为「**有清单（含设备/协议）即参与激活判定**，无清单兼容全加载」，scene.device 因此可被选择性加载。
5. **平台配套**（Migu2.0）：`DeploymentProfile.NavKindToSceneId` 改映射 magnetic→scene.mag、qrcode/laser→scene.qrlidar；向导写 active-scenes.json 时固定并入 scene.device。

### v2 评审反馈要点（本次更新依据）

1. **宿主切换**：StandardScene 改为依赖 **`SimpleLite`（net8.0）**，**老 `SimpleComposer.exe`（net4.8）废弃**。内核引用层（命名空间 `SimpleComposer.RCS` → `SimpleLite.RCS` 等）正由**另一个 AI 会话**同步改造，本文按新宿主表述。
2. **目标框架统一 `net8.0`**（与 SimpleLite 一致；**非 net8.0-windows**）。SimpleLite UI 采用 **CycleGUI**、WebApi 采用 **EmbedIO**，故 StandardScene **需去除 WinForms 依赖**，窗体迁移到 CycleGUI 或平台 Web。
3. **设备驱动必须独立 dll**，且**支持热卸载/加载**（配合 SimpleLite `/plugins` reload/unload + collectible ALC）。
4. **`FactoryTest` 与松灵残留：直接删除**，不纳入 Core，也不纳入 Customer。
5. **`WebApi.cs` 是面向老平台的 Nancy 接口**：本次**整理后暂留 Core**，**后期废弃**，能力迁移到 SimpleLite 接口（见 `E:\Work\Core\Simple-FR\Simple\SimpleLite\Docs\MIGU-API.md`）。此版本先保留。

---

## 0. TL;DR（结论先行）

1. **导航方式与车型是正交的两个维度**。导航（磁 / 二维码 / 激光）由**轨道/站点字段 + TrackCoder**决定，不是车型固有属性；同一车型（如 `Kiva`）的类上**同时**挂磁、二维码、激光避障三类 coder。上游"按车型整包切到某导航 dll"**切不干净**，修正为「**车型留基座 + 导航能力抽离为可插拔 coder**」。
2. **激光"避障"(LidarArea) ≠ 激光"导航定位"(LidarMap/SLAM)**：避障通用留 Core，仅 SLAM 地图进 Laser。
3. **`WebApi.cs`(123KB) 是老平台 Nancy 接口**，导航耦合极弱（仅二维码 `QrMap`、激光 `getLidarMap`）。**整理后暂留 Core，标记 deprecated，后期迁 SimpleLite EmbedIO 接口**（§4.7 给出端点映射）。
4. **存在大量重复代码**可借本次"抽离标准功能"沉淀：磁导航循迹器写了**两份**、`newReset/newTrafficReset` 在 3 个车型复制、`SetDisplayInfo/GetCarStatus/Mstsc/EmergencyStop` 雷同。
5. **三个正交维度**：①导航(磁/二维码/激光) ②车型(顶升/叉车/Kiva/机械臂…) ③设备驱动(充电桩/门/按钮盒)。设备驱动**独立成可热插拔 dll**。
6. **VDA5050 是自成一体的 MQTT 协议栈**，独立 dll。
7. **两大技术主线**：① 把 TrackCoder 从"编译期特性硬绑定车型"改为"导航插件运行期注册"，需内核 `SimpleCore` 配合；② **net4.8 → net8.0 迁移**：换宿主（SimpleComposer→SimpleLite）+ **去 WinForms（窗体迁 CycleGUI/Web）**。

---

## 1. 现状盘点（基于代码事实）

### 1.1 工程概况（来自 `StandardScene.csproj`）

| 项 | 现状 | 目标（本次方向） |
|---|---|---|
| 输出类型 | `Library`（插件） | 多个 `Library` 插件 dll |
| 目标框架 | `.NET Framework 4.8` | **`net8.0`**（与 SimpleLite 一致，去 WinForms） |
| 宿主 | `SimpleComposer.exe`(net4.8) | **`SimpleLite`(net8.0)**，老 Composer 废弃 |
| 契约引用 | `RefSimpleCore.dll` + `SimpleComposer.exe` | **`SimpleCore`(netstandard2.0/net8) + `SimpleLite` 程序集** |
| UI | `System.Windows.Forms`（大量窗体） | **CycleGUI / 平台 Web**（移除 WinForms） |
| 对外接口 | `WebApi.cs`（Nancy 1.4.5） | 暂留 Core；后期迁 **SimpleLite EmbedIO**（MIGU-API） |
| 其它程序集 | `CommonUsage`、`MDCSToolBox`、`leegKeys-sdk`、`LessokajiWeaverUtilities` | 随归属 dll 保留/下沉 |
| NuGet | `MQTTnet`、`EasyModbusTCP`、`IoTClient`、`Jint`、`Nancy(1.4.5)`、`Newtonsoft.Json`、`DocumentFormat.OpenXml` | 随归属拆分（Nancy 验证 net8 兼容或对齐 SimpleLite 的 Nancy 2.0） |
| 产物落地 | `PostBuildEvent` 拷 dll → `build\plugins\` | 各 dll + `scene.json` → SimpleLite `plugins\` |

### 1.2 模块与文件分组（约 110 个有效 `.cs`）

| 目录 | 内容 | 现状性质 |
|---|---|---|
| `CarTypes/` | `Forklift`、`Kiva`、`ArmCar`、`DualLiftingCar`、`MultiWheelForkLifter`、`MultiVehicleCar`、`MultiWheelLifterCar`、`DummyCar`、`UselessCar`、`BasicFields`、`VehicleMonitor`(窗体) | 车型 + 内联导航 coder |
| `CarTypes/VDACar/` | `VDA5050Car`、`VDA5050Commons/Helper/Interface/Segment/WebApi`、`MasterMQTTCommunication`、`TextViewer`(窗体) | VDA5050 通信协议栈 |
| `Chained/`（含 `Loop/`） | 搬运/环线任务 + `DeliveryViewer/LoopViewer`(窗体) | 任务调度 |
| `Charge/` | 充电任务 + `ChargeStation*`/`ChargeStrategy*`/`Alarm*`/`Communication*` + 多个 `*Form`(窗体) | 充电逻辑 + UI/服务 |
| `ChargeStationType/` | `AbstractChargeStation` → `FL`/`MuXing`/`PCB` | 充电桩厂商驱动 |
| `InterLock/` | `AbstractInterlockMission`、`TrafficInterlockMission`、`TrafficInterlockViewer`(窗体) | 互锁/交管 |
| `Scheduler/` | `HeartBeat`/`NodeIsEnable`/`RegionalTrafficControl`/`SecuritySignal` Mission | 调度信号 |
| `ExtendDevice/Door/` | `BasicDoorController` → `ModbusDoorController`、`DoorMission`、`DoorTypeAttribute`、`DoorManager/DoorMonitor`(窗体) | 门控驱动 |
| `ExtendDevice/ButtonBox/` | `BasicButtonBox` → `LeegButtonBox`/`AzowieButtonBox`、`ButtonMission`、`ButtonBoxManager`(窗体) | 呼叫器驱动 |
| `Model/` | `Map`(含 `LidarMap`)、`SimpleMap`、`TaskModel`、`LoopTask`、各 `*Setting`、`VehicleStatus`、`MissionState`、`MapStructure` | 数据模型 |
| `Utils/` `TCP/` `CommonTools/` | Json/Modbus/WebAPIHelper、AsyncTcpClient、Snowflake/AtomicFile | 基础设施 |
| 根 | `Commons.cs`、`Heuristic.cs`、`LadderLogic.cs`、`StandardCADTool.cs`、`WebApi.cs`、`FactoryTest.cs` | 公共 + 契约 + 老 API + 产测 |

### 1.3 车型清单与继承

| 车型类 | `[CarType]` | 基类 | 关键特征 |
|---|---|---|---|
| `Kiva` | "Kiva" | `GhostCar` | 内联磁 coder `AllCarMagTrackCoder` + Qr + 避障 + 取放货 + `KivaCarTrackCoder`(转弯) |
| `Forklift` | "叉车" | `GhostCar` | 避障 + 取放货（无显式磁/二维码） |
| `MultiWheelLifterCar`(CarTypes) | "多舵轮顶升车" | `GhostCar` | 内联磁 coder `MagTrackCoder` + Qr + 钻车/夹抱 |
| `MultiWheelForkLifter` | "多舵轮叉车" | `GhostCar` | 简化取放货 |
| `MultiVehicleCar` | "多车联动AGV" | `GhostCar` | 多车 sync + Qr + 钻车 |
| `DualLiftingCar` | "锂电双举升" | `GhostCar` | 无 coder（仅 UI/测试） |
| `ArmCar` | "ArmCar" | `GhostCar` | 机械臂动作；**依赖 `VDA5050SiteField`**、继承 `Kiva*Fields` |
| `DummyCar` | "模拟车-包络" | `Car` | **命名空间 `AMRScene1`**；`Jint` 仿真 |
| `UselessCar` | （已注释，未注册） | `GhostCar` | 测试残留 |

### 1.4 Mission 继承体系（均派生内核 `Mission`，导航无关）

```
Mission
├─ AbstractChainedDeliveryMission / ChainedDeliveryMission(→TransportDelivery)   Chained/
├─ AbstractLoopMission(→LoopMission)                                             Chained/
├─ TrafficInterlockMission / AbstractInterlockMission                            InterLock/
│   └─ AbstractChargeLogiceMission(→StandardChargeMission)                       Charge/
├─ HeartBeat/NodeIsEnable/RegionalTrafficControl/SecuritySignal Mission          Scheduler/
├─ DoorMission / ButtonMission                                                   ExtendDevice/
└─ FactoryTest（产测，本次删除）                                                  根
```

### 1.5 设备驱动体系（第三正交维度，本次独立 dll + 热插拔）

- 充电桩：`AbstractChargeStation` → `FLChargeStation` / `MuXingChargeStation`(牧星) / `PCBChargeStation`；`ChargeStationType` 枚举；`StandardChargeMission` 按 `car.fields["MuXing"]` 区分 FRLD/MuXing。
- 门：`BasicDoorController` → `ModbusDoorController`；`DoorTypeAttribute`（注册契约）。
- 按钮盒：`BasicButtonBox` → `LeegButtonBox`(依赖 `leegKeys-sdk`/`leegiot`) / `AzowieButtonBox`。

### 1.6 VDA5050 子系统（独立 MQTT 协议栈）

- `VDA5050Car : Car` + `MasterMQTTCommunication` + `VDA5050Interface/Helper/Commons/Segment/WebApi` + `TextViewer`(窗体)；依赖 `CommonUsage.Protocols.VDA5050.*` + `MQTTnet`。
- VDA5050 车端自管导航定位，与磁/二维码/激光维度无关。
- 耦合点：`ArmCar` 引用 `VDA5050SiteField`（拆分时解依赖）。

### 1.7 删除项（拆分前清理，**不进 Core/Customer**）

| 文件/类 | 原因 | 处置 |
|---|---|---|
| `FactoryTest.cs` | 产测专用，非标准能力 | **删除**（评审已确认） |
| 根 `SongLingDeliveryViewer.Designer.cs` | 松灵客户残留，仅 `.Designer.cs`、无主文件、未被 `csproj` 收录 | **删除** |
| 根 `MultiWheelLifterCar.cs` | 与 `CarTypes/MultiWheelLifterCar.cs` 重名旧文件，**未被 `csproj` 收录**（死文件） | **删除** |
| `CarTypes/UselessCar.cs` | `[CarType]` 已注释、仅反射示例 | 删除（或移测试样例） |

---

## 2. 关键洞察（精读结论 → 对上游设计的修正）★

### 2.1 洞察 A：导航是"轨道/站点字段 + Coder"，与车型正交
- `CarTypes/BasicFields.cs:23` `TagValue //磁导航，二维码值，或者rfid 值`（站点字段）。
- 磁：`Kiva.cs:37`、`CarTypes/MultiWheelLifterCar.cs:34` `track.fields["Magnet"]`/`NaiveMagnet`（轨道字段）。
- 二维码：车型 coder `useVerb="dst.tag>0 && src.tag>0"` → `agv.QrGo(...)`。
- 激光避障：`useVerb="track.LidarArea != -2"` → `agv.SwitchLidarArea(...)`。
- **结论**：同一车型在不同轨道字段下走不同 coder 分支；按车型切 dll 会复制车型或丢能力。

### 2.2 洞察 B：导航逻辑以"特性"内联在车型，且多导航混杂
- `[TemplateTrackCoderSettings]`/`[ProgramTrackCoderSettings(program=typeof(...))]` 编译期硬绑定到车型类型。
- `Kiva` 同时挂磁(prio19)+二维码(prio30)+避障+取放货。
- **结论**：导航 dll 要可插拔地为车型提供 coder，必须把 coder 外置并由内核支持**运行期注册**（§7.1）。

### 2.3 洞察 C：激光"避障" ≠ 激光"导航定位"
- 避障：`LidarArea`/`SwitchLidarArea`/`ChangeAvoidanceDistance`/`FrontLidarDetect`——几乎所有车型都有，通用 → Core。
- 定位：`Model/Map.cs:183 LidarMap`(拉 `127.0.0.1:4321` SLAM 栅格) + `WebApi.cs:1021 /map/getLidarMap` → Laser。

### 2.4 洞察 D：可"抽离为标准功能"的重复代码
| 重复项 | 位置 | 抽离目标 |
|---|---|---|
| 磁循迹器（选路+`MagGo/NaiveMagGo`） | `Kiva.cs:32 AllCarMagTrackCoder`、`CarTypes/MultiWheelLifterCar.cs:29 MagTrackCoder` | 合并为唯一 `MagneticTrackCoder`(Magnetic dll) |
| `newReset/newTrafficReset` | `Kiva.cs:715`、`Forklift.cs:279`、`CarTypes/MultiWheelLifterCar.cs:347` | 上提 Core 车型基类 |
| `SetDisplayInfo` | 各车型雷同 | Core 基类默认实现 |
| `Mstsc/EmergencyStop/ResetClumsy`(HTTP:8008) | 多车型重复 | Core 基类 |
| 避障/IO/纠偏 coder 模板 | 各车型重复粘贴 | Core 通用 coder 模板集 |
| `GetCarStatus` | `Commons` 与 `MultiWheelForkLifter` 各一份 | 统一 `Commons` |

### 2.5 洞察 E：`WebApi.cs` 是老平台 Nancy 接口，整体面临废弃
- `ApiController : NancyModule`(`WebApi.cs:35`)，40+ 端点；导航相关仅二维码 `QrMap`(`:38/:40/:2050`)+`QrSite`(`:2807`) 与激光 `getLidarMap`(`:1021`)。
- 其能力在 SimpleLite 已由 **EmbedIO**`/projection/*`（投影快照 + reflection + map-edit + scenes，见 MIGU-API.md）覆盖。
- **处置（本版）**：整理后**暂留 Core**（标 `[Obsolete]`/注释 deprecated）；**后期整体废弃**，迁移索引见 §4.7。

### 2.6 洞察 F：设备驱动是第三个正交维度（本次独立 dll + 热插拔）
- 充电桩/门/按钮盒按厂商/型号扩展，与导航、车型都正交。
- 通过既有特性（`ChargeStationType`/`DoorTypeAttribute`/新增 ButtonBoxType）注册，编译为独立 `Devices.*` dll，支持 SimpleLite `/plugins` 热加载/卸载。

### 2.7 洞察 G：UI 形态需从 WinForms 迁到 CycleGUI/Web（net8.0 约束）
- SimpleLite = `net8.0`（纯）、UI 用 **CycleGUI**、WebApi 用 **EmbedIO**，**不依赖 `System.Windows.Forms`**。
- StandardScene 现有窗体：`DeliveryViewer/LoopViewer/TrafficInterlockViewer/VehicleMonitor/各 Charge*Form/Door*/ButtonBox*/TextViewer` + `Commons` 内 `MessageBox`。
- **统一 net8.0 ⇒ 必须移除 WinForms**：窗体迁 **CycleGUI**（SimpleLite 立即模式 UI）或平台 **Web**；`MessageBox` 类提示改 CycleGUI 弹窗 / 平台通知。这是本次**重要工作量与风险**。

---

## 3. 目标架构与目录规划

### 3.1 分层依赖图

```mermaid
flowchart TD
    SC["SimpleCore (netstandard2.0/net8)<br/>AbstractCar/CarType/Mission/ITrackCoder/Heuristics<br/>+ 导航契约 NavKind/INavigationProfile/ISceneContext<br/>+ (新增)TrackCoder 运行期注册表"]
    SL["SimpleLite (net8.0 宿主)<br/>CycleGUI UI · EmbedIO WebApi · /plugins 热插拔 · /scenes 选择性加载"]
    CORE["StandardScene.Core (net8.0)<br/>导航无关基座：车型本体+任务/充电/互锁/调度+模型/工具+Commons+通用避障coder<br/>(暂留)WebApi.Core(Nancy, deprecated)"]
    MAG["StandardScene.Magnetic"]
    QR["StandardScene.QrCode"]
    LAS["StandardScene.Laser"]
    VDA["StandardScene.Protocol.VDA5050"]
    DCH["StandardScene.Devices.Charge<br/>(热插拔)"]
    DDR["StandardScene.Devices.Door<br/>(热插拔)"]
    DBT["StandardScene.Devices.ButtonBox<br/>(热插拔)"]

    SC --> CORE
    SC --> SL
    CORE --> MAG & QR & LAS & VDA & DCH & DDR & DBT
    SL -. 加载/卸载 .-> CORE & MAG & QR & LAS & VDA & DCH & DDR & DBT
```

### 3.2 解决方案目录布局（单工程 → 多工程，统一 net8.0）

```
StandardScene/                          解决方案根
├─ StandardScene.Core/                  net8.0，标准基座（alwaysLoad，不单独作为导航场景）
│   ├─ Navigation/                      INavigationProfile/NavKind/ISceneContext/Registry
│   ├─ Cars/                            车型基类 StandardCarBase + 各车型本体（无导航 coder、无 WinForms）
│   │   └─ Sim/                         DummyCar（仿真，AMRScene1 命名空间收敛）
│   ├─ Coders/                          通用 coder（避障/IO/纠偏/取放货模板）
│   ├─ Chained/ Charge/ ChargeStationType(抽象) / InterLock/ Scheduler/
│   ├─ ExtendDevice/                    设备框架（基类 + 注册特性）
│   ├─ Model/ Utils/ TCP/ CommonTools/
│   ├─ Ui/                              CycleGUI 面板（替代原 WinForms 窗体）
│   ├─ Commons.cs Heuristic.cs LadderLogic.cs StandardCADTool.cs
│   └─ WebApi.Core.cs                   老 Nancy API（deprecated，暂留，后期删）
├─ StandardScene.Magnetic/             → plugins/ + scene.json
├─ StandardScene.QrCode/               → plugins/ + scene.json
├─ StandardScene.Laser/                → plugins/ + scene.json
├─ StandardScene.Protocol.VDA5050/     → plugins/ + scene.json
├─ StandardScene.Devices.Charge/       → plugins/（热插拔）
├─ StandardScene.Devices.Door/         → plugins/（热插拔）
├─ StandardScene.Devices.ButtonBox/    → plugins/（热插拔）
└─ StandardScene.sln
```

### 3.3 各 dll 职责

| dll | 职责 | 可激活/热插拔 |
|---|---|---|
| `StandardScene.Core` | 导航无关一切：车型本体、任务/充电/互锁/调度、模型/工具、`Commons`/契约、通用避障 coder、（暂留）老 WebApi | 基座（`alwaysLoad`） |
| `StandardScene.Magnetic` | 统一 `MagneticTrackCoder` + 磁条字段语义 | 是 |
| `StandardScene.QrCode` | `QrTrackCoder` + `SyncQrMap` + 二维码地图下发 | 是 |
| `StandardScene.Laser` | `LidarMap`/`getLidarMap`（SLAM） | 是 |
| `StandardScene.Protocol.VDA5050` | VDA5050/MQTT 协议栈 + `VDA5050Car` | 是 |
| `StandardScene.Devices.Charge` | 充电桩 FL/MuXing/PCB 驱动 | **是（热插拔）** |
| `StandardScene.Devices.Door` | 门 Modbus 驱动 | **是（热插拔）** |
| `StandardScene.Devices.ButtonBox` | 按钮盒 Leeg/Azowie 驱动 | **是（热插拔）** |

---

## 4. 功能归属矩阵（文件级 / 类级）★

> 动作：**移动**/**拆分**/**抽离**/**保留**/**删除**/**迁UI**(WinForms→CycleGUI/Web)/**待复核**。

### 4.1 车型（`CarTypes/`）

| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `BasicFields.cs` | Core | 移动 | 车型公共字段 |
| `Kiva.cs::Kiva` | Core(Cars) | 拆分 | 本体留 Core；移除内联磁/Qr coder 特性 |
| `Kiva.cs::AllCarMagTrackCoder` | Magnetic | 抽离 | 并入唯一 `MagneticTrackCoder` |
| `Kiva.cs::KivaCarTrackCoder` | Core(Coders) | 移动 | 转弯，导航无关 |
| `Forklift.cs` | Core(Cars) | 移动 | 通用避障/取放货 |
| `CarTypes/MultiWheelLifterCar.cs::MultiWheelLifterCar` | Core(Cars) | 拆分 | 本体留 Core；移除内联磁/Qr |
| `CarTypes/MultiWheelLifterCar.cs::MagTrackCoder` | Magnetic | 抽离 | 并入 `MagneticTrackCoder`（去重） |
| `MultiWheelForkLifter.cs` | Core(Cars) | 移动 | `GetCarStatus` 并入 `Commons` |
| `MultiVehicleCar.cs` | Core(Cars) | 拆分 | 联动留 Core；Qr coder 外移 QrCode |
| `DualLiftingCar.cs` | Core(Cars) | 移动 | 无 coder |
| `ArmCar.cs` | Core(Cars) | 拆分/解耦 | 解除 `VDA5050SiteField` 依赖 |
| `DummyCar.cs` | Core(Cars/Sim) | 移动 | `AMRScene1` 命名空间收敛 |
| `UselessCar.cs` | — | 删除 | 未注册 |
| `VehicleMonitor.cs(.Designer)` | Core(Ui) | **迁UI** | WinForms → CycleGUI |

### 4.2 VDA5050（`CarTypes/VDACar/`）

| 现状 | 目标 | 动作 |
|---|---|---|
| `VDA5050*` + `MasterMQTTCommunication` | `Protocol.VDA5050` | 移动（整子目录） |
| `TextViewer.cs(.Designer)` | `Protocol.VDA5050`(Ui) | 迁UI（CycleGUI） |
| `VDA5050SiteField`（被 ArmCar 引用） | Core 公共字段 或 VDA dll | 待复核（ArmCar 留 Core 则下沉 Core） |

### 4.3 任务族（`Chained/` `InterLock/` `Scheduler/`）

| 现状 | 目标 | 动作 |
|---|---|---|
| `Chained/*`、`InterLock/*`、`Scheduler/*` 逻辑 | Core | 移动（导航无关） |
| `DeliveryViewer/LoopViewer/TrafficInterlockViewer`(窗体) | Core(Ui) | 迁UI（CycleGUI/Web） |

### 4.4 充电（`Charge/` `ChargeStationType/`）

| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `AbstractChargeLogicMission`、`StandardChargeMission` | Core | 移动 | 充电逻辑 |
| `ChargeStation*`/`ChargeStrategy*`/`Alarm*`/`Communication*`(服务) | Core | 移动 | 充电管理/服务 |
| 各 `Charge/*Form`(窗体) | Core(Ui) | 迁UI | CycleGUI/Web |
| `ChargeStationType/AbstractChargeStation.cs` | Core | 移动 | 抽象 + 注册契约 |
| `ChargeStationType/{FL,MuXing,PCB}ChargeStation.cs` | **`Devices.Charge`** | 拆分 | 厂商驱动，独立热插拔 dll |

### 4.5 扩展设备（`ExtendDevice/`）

| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `Door/BasicDoorController`、`DoorMission`、`DoorModel`、`DoorTypeAttribute` | Core(框架) | 移动 | 门控框架 + 注册契约 |
| `Door/ModbusDoorController` | **`Devices.Door`** | 拆分 | Modbus 驱动，独立热插拔 |
| `Door/DoorManager/DoorMonitor`(窗体) | Core(Ui)/Devices.Door(Ui) | 迁UI | CycleGUI |
| `ButtonBox/BasicButtonBox`、`ButtonMission`、`ButtonBoxModel` | Core(框架) | 移动 | 按钮盒框架 |
| `ButtonBox/LeegButtonBox`(`leegKeys-sdk`)、`AzowieButtonBox` | **`Devices.ButtonBox`** | 拆分 | 厂商驱动，`leegKeys-sdk` 随驱动走 |
| `ButtonBox/ButtonBoxManager`(窗体) | 对应 dll(Ui) | 迁UI | CycleGUI |

### 4.6 公共 / 契约 / 模型 / 基础设施

| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `Commons.cs::Commons` | Core | 移动 | 解除对 `DummyCar` 硬引用（`GetVehicleStatus`） |
| `Commons.cs::CustomOperationsBeforeLoading` | 各可激活 dll 各一份 | 复制/分发 | `MessageBox` 死锁提醒改 CycleGUI 弹窗 |
| `Commons.cs::NoReflectionApi`/`ReflectionApiWithParameter` | SimpleCore 或 Core | 待复核 | 多 dll 共用建议下沉 SimpleCore |
| `Heuristic.cs` | Core | 移动 | 启发式（宿主反射注册） |
| `LadderLogic.cs` | Core | 移动 | 防抖/梯形逻辑 |
| `StandardCADTool.cs`（多数 `CADTool`） | Core | 移动 | 地图编辑工具 |
| `StandardCADTool.cs::SyncQrMap` | QrCode | 拆分 | 二维码地图下发 |
| `Model/Map.cs::Map/ArcHelper` | Core | 移动 | 地图序列化 |
| `Model/Map.cs::LidarMap` | Laser | 拆分 | SLAM 栅格图 |
| `Model/*`（其余） | Core | 移动 | 数据模型 |
| `Utils/*`、`TCP/*`、`CommonTools/*` | Core | 移动 | 基础设施 |
| `FactoryTest.cs` | — | **删除** | 评审确认 |
| 根 `MultiWheelLifterCar.cs`、根 `SongLingDeliveryViewer.Designer.cs` | — | **删除** | 死/残留 |

### 4.7 老 WebApi（`WebApi.cs`）整理与迁移索引

**本版处置**：通用端点整理为 `WebApi.Core.cs` 暂留 Core 并标 deprecated；二维码/激光端点随导航 dll；**后期整体删除**，前端改用 SimpleLite 接口。下表为废弃迁移索引（老 Nancy → SimpleLite EmbedIO，依据 MIGU-API.md）：

| 老端点（`WebApi.cs`） | 行号 | SimpleLite 替代（`/api/sl/projection/...`） |
|---|---|---|
| `car_reflection/mission_reflection get_type/methods/fields/execute` | 191–537 | `reflection/methods/*`、`/fields/*`、`/execute/*`、`/bundle/*` |
| `car/getAllCars`、`api/agv/list` | 1047、2095 | `projection/cars` |
| `task/getTask` | 1099 | `projection/missions` |
| `map/getMap` | 995 | `projection/sites`+`/tracks`、或 `map-edit` |
| `car/goSite` | 1070 | `reflection/car/{id}/goto-site` |
| `car/reset/repair/blown/ForceStop/ReStart/...` | 767+ | `reflection/execute/{kind}/{id}/{method}`（`[MethodMember]`） |
| `car/createTask/carTask/cancelTask` | 542/597/900 | `reflection/execute` + `projection/deliveries/*` |
| `set{Charging,Envelope,TrafficControl,PlanRules}Setting` | 1680+ | `reflection/fields/{kind}/{id}/{field}`（写字段） |
| `api/CreateSite` | 2055 | `map-edit/objects/site` |
| `api/QrMap`（二维码） | 2050 | 暂随 QrCode dll；SimpleLite 侧待新增（无直接对应） |
| `map/getLidarMap`（激光） | 1021 | 暂随 Laser dll；SimpleLite 侧待新增（无直接对应） |

> 注：二维码地图下发、激光 SLAM 取图在 SimpleLite 现有 MIGU-API 中**无直接对应**，迁移时需在 SimpleLite/场景插件侧补接口，故这两块随导航 dll 先行保留。

---

## 5. "抽离标准功能"清单（去重与沉淀）

1. **统一磁导航循迹器**：`AllCarMagTrackCoder` + `MagTrackCoder` → 唯一 `StandardScene.Magnetic.MagneticTrackCoder`（参数化 fields）。
2. **车型基类 `StandardCarBase`(Core)**：上提 `newReset/newTrafficReset`、`SetDisplayInfo`、`Mstsc`、`EmergencyStop/Release`、`ResetClumsy`、`GetCarStatus` 默认实现。
3. **通用 Coder 模板集(Core/Coders)**：沉淀避障/IO/纠偏/避障尺寸等重复 `[TemplateTrackCoderSettings]`。
4. **导航能力抽象 `INavigationProfile`**：每个导航 dll 实现一个 Profile（声明 `NavKind` + 提供的 coder/字段语义），Core/宿主反射收集。
5. **`Commons` 去重**：合并 `GetCarStatus`；`GetVehicleStatus` 去除对 `DummyCar` 的硬编码（改标记接口）。
6. **设备注册标准化**：充电桩/门/按钮盒统一特性注册，驱动 dll 即插即用 + 热插拔。
7. **UI 标准化**：原 WinForms 窗体统一迁 CycleGUI 面板（沉淀少量通用面板基类）。

---

## 6. 命名空间与依赖治理

- **宿主/命名空间迁移**：`SimpleComposer.RCS`/`SimpleComposer.UI` → `SimpleLite.RCS`/对应（以内核改造为准，另一会话进行中）；引用 `SimpleComposer.exe` → `SimpleLite` 程序集 + `SimpleCore` 契约。
- **命名空间收敛**：`DummyCar` 的 `AMRScene1` → `StandardScene.Core.Cars.Sim`。
- **去 WinForms**：移除 `System.Windows.Forms` 引用，窗体迁 CycleGUI/Web，`MessageBox` 改 CycleGUI 弹窗。
- **反向依赖治理**：`Commons.GetVehicleStatus`↛`DummyCar`；`ArmCar`↛`VDA5050SiteField`；二维码相关集中 QrCode dll，Core 仅留中立扩展点。
- **三方依赖随归属**：`MQTTnet`→VDA5050；`leegKeys-sdk`→ButtonBox 驱动；`EasyModbusTCP/IoTClient`→Door/Charge 驱动或 Core 工具；`Nancy`→（暂留的 WebApi.Core，验证 net8 兼容或对齐 SimpleLite 的 Nancy 2.0）；`Jint`→含 DummyCar 仿真的 Core。

---

## 7. 关键技术难点与对策

### 7.1 难点①：TrackCoder 由"编译期特性"改为"运行期注册"
- 现状：coder 通过特性硬绑定车型类型。
- 目标：导航 dll 不改 Core 车型源码即可为车型补 coder。
- 对策：① **内核扩展（推荐）**——`SimpleCore` 增 coder 注册表，导航 dll 在 `INavigationProfile.OnActivate` 注册/卸载时移除（契合 `/plugins` 热插拔）；② 车型留占位、导航 dll 实现委派；③ **兜底**——Core 内置全量 coder，导航 dll 只承载 API/地图/字段/清单。
- **行动项**：与正在改内核引用的会话同步，确认是否纳入注册表 API。

### 7.2 难点②：net4.8 → net8.0 迁移（换宿主 + 去 WinForms）
- 宿主：引用 `SimpleComposer.exe`(net4.8) → `SimpleLite`/`SimpleCore`(net8)；`SimpleComposer` 独有类型在内核侧补齐/下沉（与另一会话协作）。
- **去 WinForms（重点）**：所有窗体迁 CycleGUI（SimpleLite 立即模式 UI）或平台 Web；`MessageBox`→CycleGUI 弹窗/平台通知。工作量集中在 `Charge/*Form`、`Delivery/Loop/TrafficInterlock Viewer`、`VehicleMonitor`、`Door/ButtonBox` 管理窗体、`VDACar/TextViewer`。
- 三方库 net8 验证：`Nancy(1.4.5)`（暂留 WebApi，验证或升 2.0）、`MQTTnet/EasyModbusTCP/IoTClient/Jint/Newtonsoft/DocumentFormat.OpenXml`。
- Fody/`LessokajiWeaver`：与内核一致（注意上游 §13.2 环境约束）。

### 7.3 难点③：插件钩子与多 dll 初始化
- `CustomOperationsBeforeLoading.Set()` 宿主按 dll 反射调用：拆分后每个可激活 dll 各保留一份；用 `INavigationProfile.OnActivate` 做导航 dll 自初始化，避免重复注册全局回调。

### 7.4 难点④：设备/导航 dll 热插拔（collectible 卸载）
- 配合 SimpleLite `/plugins/reload`、`/plugins/{name}/unload` 与 `/scenes/apply`：dll 须可被 collectible ALC 干净卸载（卸载前无存活 `Car/Mission` 实例），`OnDeactivate` 清理注册的 coder/设备/回调/MQTT 连接/TCP 客户端。

### 7.5 难点⑤：老 WebApi 暂留与最终下线
- `WebApi.Core`(Nancy) 暂留 Core 仅为过渡；新功能一律走 SimpleLite EmbedIO。按 §4.7 索引逐步迁移，迁完即删；二维码/激光取图需先在 SimpleLite/场景插件侧补接口。

---

## 8. 分阶段实施计划（务实路线）

> 原则：每阶段都能编译、能加载、可回退。

### C0 · 准备与对齐（低风险，先做）
- 删除：`FactoryTest.cs`、根 `SongLingDeliveryViewer.Designer.cs`、根 `MultiWheelLifterCar.cs`、`UselessCar`。
- 去重沉淀（§5）：统一 `MagTrackCoder`、`GetCarStatus`；提取 `StandardCarBase`。
- 命名空间收敛 `AMRScene1`→Core。
- 与内核会话对齐：`SimpleLite`/`SimpleCore` 引用与命名空间、coder 注册表（§7.1）、导航契约（上游 Phase A 已就绪）。
- 验收：编译通过、行为不变。

### C1 · Core 基座 net8.0 化（换宿主 + 去 WinForms 闭环）
- 新建 `StandardScene.Core`(net8.0)，迁入导航无关全部内容；引用切到 `SimpleLite`/`SimpleCore`。
- **去 WinForms**：窗体迁 CycleGUI；`MessageBox`→CycleGUI。
- 整理老 `WebApi`→`WebApi.Core`(deprecated, 暂留)。
- coder 先用兜底（§7.1 方案③）保证不回归。
- 验收：`StandardScene.Core.dll` 被 SimpleLite 加载、跑通搬运/充电/交管。

### C2 · 抽离导航能力 dll
- `Magnetic`（唯一 `MagneticTrackCoder`）/ `QrCode`（`QrTrackCoder`+`SyncQrMap`+`QrMap`）/ `Laser`（`LidarMap`+`getLidarMap`），各带 `scene.json`。
- 按 §7.1 选定方案把 coder 接到车型。
- 验收：仅激活某导航时对应能力可用，其余不加载。

### C3 · 设备驱动 dll 化（必做，热插拔）
- `Devices.Charge`(FL/MuXing/PCB)、`Devices.Door`(Modbus)、`Devices.ButtonBox`(Leeg/Azowie)；`leegKeys-sdk` 随驱动。
- 验证 `/plugins` reload/unload 热插拔；`OnDeactivate` 清理连接。
- 验收：设备驱动可独立热加载/卸载。

### C4 · VDA5050 协议 dll
- `Protocol.VDA5050`（整 `VDACar/` 迁出，含 MQTT）；解 `ArmCar↔VDA5050SiteField`。
- 验收：激活后 VDA5050 车可用、可卸载。

### C5 · 联调、WebApi 迁移与文档
- 三导航 + 设备 + 协议组合联调；对接 `/scenes/apply` + `active-scenes.json`。
- 按 §4.7 把可迁的 WebApi 端点切到 SimpleLite，逐步删 `WebApi.Core`。
- 更新本文件 §11 进度 + `scene.json` 实际清单 + `README/DEVELOPMENT_GUIDE`。

---

## 9. 插件清单契约（`scene.json`，对接上游 §5.5 与 SimpleLite `/scenes`）

```json
{
  "id": "scene.magnetic",
  "displayName": "磁导航场景",
  "navKind": "Magnetic",
  "assembly": "StandardScene.Magnetic.dll",
  "requiresCore": "StandardScene.Core.dll",
  "provides": { "trackCoders": ["MagneticTrackCoder"], "carTypeBindings": ["*"] }
}
```

- 平台「配置向导」→ `WizardController` 写配置 → 调 SimpleLite `POST /api/sl/projection/scenes/apply`（写 `active-scenes.json` + 增量 reload）。
- 数据契约：`data/config-deployment.json`（平台）/ `plugins/active-scenes.json`（内核）/ `plugins/<dll>.scene.json`（插件）。

---

## 10. 风险、待确认与验收口径

### 已确认（v2）
- 宿主 = SimpleLite；老 SimpleComposer 废弃。
- 目标框架 = `net8.0`（去 WinForms，UI 迁 CycleGUI/Web）。
- 设备驱动 = 独立 dll + 热插拔。
- `FactoryTest`、松灵残留 = 删除。
- `WebApi.cs` = 整理后暂留 Core、后期废弃迁 SimpleLite。

### 待确认
1. **coder 注册表**：内核是否纳入"运行期把 TrackCoder 注册到车型"的 API（否则 C2 用兜底方案③）。
2. **UI 迁移范围与节奏**：窗体一次性迁 CycleGUI，还是按 dll 分批；是否部分仅保留平台 Web 入口。
3. **VDA5050** 独立 dll 确认（推荐独立）。
4. **二维码地图下发 / 激光 SLAM 取图**：SimpleLite 侧补接口的归属与时间点。
5. **车型↔导航映射**：是否存在车型仅支持单一导航的硬约束。

### 验收口径（每阶段通用）
- 编译 0 错误；搬运/环线/充电/交管不回归。
- 选择性加载 + 热插拔：激活集合内能力可用，未激活不加载、可干净卸载。
- 反射 API（SimpleLite `/reflection`）、车型/面板随已激活 dll 自然收敛。

---

## 11. 实施进度记忆（跨会话持续更新）

> 状态：⬜ 未开始 / 🟦 进行中 / ✅ 完成 / ⏸ 暂缓。
> **最近更新：会话1（续3，2026-06-09）——设备三 dll 合并为单一 `StandardScene.Devices` + `ChangeAvoidanceParam` 去重(方案 B)，全解 `dotnet build` 0 错误。**

### 11.0 当前代码现状（重要：已领先早期文档）

会话1 接手时发现**代码已被先前会话推进**，与 v2 文档/会话14交接摘要描述的「net4.8 单体、未动代码」**不一致**。以 `StandardScene.csproj` 实际为准：

| 项 | 早期文档记述 | **当前实际** |
|---|---|---|
| 目标框架 | net4.8 | **`net8.0-windows`**（仍 `UseWindowsForms=true`，过渡态，**尚未**去 WinForms 到纯 net8.0） |
| 宿主/契约引用 | SimpleComposer.exe + RefSimpleCore | **已切 `SimpleLite.dll` + `SimpleCore.dll`(netstandard2.0)** |
| Nancy | 1.4.5 | **已对齐 `2.0.0`** |
| 死代码 | 在仓库 | csproj 已 `Compile Remove`，会话1 已物理删除 |
| 命名空间 | SimpleComposer.RCS | 车型 using 已是 `SimpleLite.RCS`（内核改造会话已推进） |

**可编译基线**：`dotnet build`（net8.0-windows，dotnet SDK 10.0.300）= **0 错误 / 47 警告**（均无害：重复 using、隐藏成员 CS0108、未用变量、`Thread.Abort` SYSLIB0006、CS4014 未 await 等）。

### 11.1 步骤状态

| 步骤 | 内容 | 状态 | 说明 |
|---|---|---|---|
| P0 | 精读现状 + 产出拆分计划 v1 | ✅ | 逐文件精读 |
| P0.1 | 按评审反馈更新 v2 | ✅ | |
| **路线决策** | 评审定 **路线乙**：先「纯搬运不改逻辑」的结构拆分，去重在新结构里从容做 | ✅ | 会话1 用户拍板 |
| **C0-a** | 物理删除死代码 + 清理 csproj | ✅ | 见 §11.3 |
| **C0-b** | 抽离 **4 个通用(导航无关) coder** 并在 4 车型切换 | ✅ | 见 §11.3；编译 0 错误 |
| C0-c | 合并两份磁循迹器为唯一 `MagneticTrackCoder` | ✅ | 用户定：采用含 `track.Speed` 的 `NaiveMagGo`；MWL 旧类已删、引用改向；编译 0 错误 |
| C0-d | `ChangeAvoidanceParam` 去重 | ✅ | 方案 B：4 参 flag 版 `AvoidanceParamCoder`(MWL+MultiVehicle) + 2 参 L,W 版 `AvoidanceParamLWCoder`(Kiva+Forklift)；见 §11.4-2 |
| C0-e | 提取 `StandardCarBase`（newReset/Mstsc/GetCarStatus 等上提）| ⬜ | 未启动 |
| C0-f | `AMRScene1` 命名空间收敛 | ⬜ | 建议并入 C1 建 Core 工程时一起做 |
| 路线乙·1 | 工程迁入 `StandardScene.Core/` + 重写 sln（纯搬运） | ✅ | 编译 0 错；AssemblyName 仍=`StandardScene`，对外 dll 名不变 |
| C1 | 去 WinForms + WebApi.Core 整理 | ⏸ | 用户暂缓（窗体后续迁 migu 平台）；过渡期各工程暂 `net8.0-windows` |
| C2 | Magnetic/QrCode/Laser 三导航 dll | ⏸ | 受阻于内核 coder 注册表(§11.4-4) + 用户将自行重构 coder |
| **C3** | 设备驱动 dll 化（Charge/Door/ButtonBox，热插拔） | ✅ | 见 §11.3-E3；**合为单一 `StandardScene.Devices`**(用户定，不分多个)，编译 0 错、scene.json 产出 |
| **C4** | VDA5050 协议 dll | ✅ | 见 §11.3-E2；`VDACar/` 整迁出、`VDA5050SiteField` 下沉 Core |
| C5 | 联调 + WebApi 迁移 SimpleLite + 文档收尾 | ⬜ | 含卫星 dll→宿主 `plugins/` 部署 + 真机联调（见 §11.4-5） |

### 11.2 关键决策记录
- **路线乙（会话1 确认）**：结构拆分优先、纯搬运不改逻辑；去重沉淀在新结构内做。理由：本环境无法跑真实 AGV 回归，纯搬运行为风险低、编译即可保障。
- 导航与车型正交；导航 coder 外置为可插拔（运行期注册，内核配合；**当前用兜底=Core/单体内置 coder**，用户要求"先抽离合适的通用 coder"）。
- 激光避障(LidarArea)留 Core，仅 SLAM 地图(LidarMap/getLidarMap)进 Laser。
- 设备驱动单列 `Devices.*` 独立 dll + 热插拔（评审确认）。
- 宿主 SimpleComposer→SimpleLite；框架统一 net8.0；UI 去 WinForms 迁 CycleGUI/Web（评审确认）。
- `FactoryTest`、松灵残留删除（评审确认，会话1 已执行）。
- 老 `WebApi.cs`(Nancy) 暂留 Core、标 deprecated，后期迁 SimpleLite EmbedIO，迁移索引见 §4.7（评审确认）。

### 11.3 会话1 已落地改动明细（2026-06-09）

**A. C0 死代码物理删除**（编译范围不变，0 错误）
- 删 `FactoryTest.cs`（`[MissionType]` 展会演示进程，反射注册，无其它引用）
- 删 根 `MultiWheelLifterCar.cs`（与 `CarTypes/MultiWheelLifterCar.cs` 重名死文件）
- 删 根 `SongLingDeliveryViewer.Designer.cs`（松灵残留，无主文件）
- 删 `CarTypes/UselessCar.cs`（`[CarType]` 已注释、未注册）
- `csproj`：移除上述 3 条 `Compile Remove`；**保留** `Chained\AbstractChainedDeliveryMission.cs` 的 Remove（孤立未编译旧版本，去留待后续核对）

**B. 抽离通用(导航无关) coder** —— 新增 `Coders/CommonTrackCoders.cs`（命名空间 `StandardScene.Coders`）
- 基类 `CommonTemplateTrackCoder : ITrackCoder`：内部复用内核 `ProgramCoderHelper.PrepareTrackEngine` + Topaz 求值，`useVerb`/`templateString` 与原模板逐字一致；统一用 `BasicXxxFields`（这些 coder 仅引用 Basic 字段，等价）。priority 由车型 `[ProgramTrackCoderSettings]` 指定。
- 4 个通用 coder：
  - `LidarAreaSwitchCoder`（避障，`track.LidarArea != -2` → `SwitchLidarArea`）
  - `AvoidanceDistanceCoder`（无 useVerb → `ChangeAvoidanceDistance(StopDistance,SlowDistance)`）
  - `IoAreaSwitchCoder`（`track.IOArea != -1` → `SwitchIoArea`）
  - `TrackingErrThreshCoder`（`BiasAlarmThresh>0||DthAlarmThresh>0` → `ChangeTrackingErrThresh`）
- 4 车型已把对应内联 `[TemplateTrackCoderSettings]` 删除，改为 `[ProgramTrackCoderSettings]` 引用（保留各自原 priority）：

| 车型 | LidarArea | AvoidanceDistance | IoArea | TrackingErrThresh |
|---|---|---|---|---|
| `Kiva` | 17 | 20 | 20 | 20 |
| `MultiWheelLifterCar` | 27 | 20 | 20 | 20 |
| `MultiVehicleCar` | 27 | 20 | 20 | 20 |
| `Forklift` | 20 | —(原无) | 20 | 20 |

- 各车型加 `using StandardScene.Coders;`。
- **验证**：每步 `dotnet build` 均 0 错误（Kiva 单切先验范式，再批量推 MWL/MultiVehicle/Forklift）。

**C. 仍保留为内联 Template / 程序 coder（本次未动）**
- 磁程序 coder：`Kiva.AllCarMagTrackCoder`、`MultiWheelLifterCar.MagTrackCoder`（待 C0-c 合并）
- `ChangeAvoidanceParam`（三变体，待 C0-d）
- `Kiva.KivaCarTrackCoder`(转弯)、`CalibrateWheelEncoder`(仅 Kiva)
- 二维码 `QrGo`（导航专用，归 QrCode dll）；各车型取放货/钻车/夹抱/TireFollowing 等（车型专用）

**D. 会话1（续）去重落地**（编译 0 错误 / 0 lint）
- **磁循迹器合并（C0-c）**：`Kiva.AllCarMagTrackCoder` 重命名为唯一 `MagneticTrackCoder`（含 `${track.Speed}` 的 `NaiveMagGo`，用户确认）；`MultiWheelLifterCar.MagTrackCoder` 整类删除，其 `[ProgramTrackCoderSettings(priority=19)]` 改向 `MagneticTrackCoder`。（暂置 `Kiva.cs` 的 `StandardScene.CarTypes` 命名空间，C2 抽 Magnetic dll 时物理迁出。）
- **避障 4 参对合并（C0-d 部分）**：新增 `Coders.AvoidanceParamCoder`（`CommonTemplateTrackCoder` 子类，覆写站点字段袋为含 `ChangeAvoidanceParam` 标志位的 `AvoidanceParamSiteFields`），useVerb/模板与原 `MWL`/`MultiVehicle` 逐字一致；两车型删内联 4 参模板、改 `[ProgramTrackCoderSettings(priority=20)]` 引用。基类新增可覆写 `SiteFieldsType` 钩子（默认 `BasicSiteFields`）。

**E. 会话1（续2）结构性拆分落地**（路线乙·结构拆分；全解决方案 `dotnet build` 0 错误 / 45 无害警告）

*E1. 工程迁入 `StandardScene.Core/`（纯搬运）*
- 原单体整体迁入子目录 `StandardScene.Core/`；`StandardScene.csproj`→`StandardScene.Core.csproj`（**AssemblyName 仍=`StandardScene`**，对外 dll 名不变）；重写 `StandardScene.sln`。
- 新增 `Properties/InternalsVisibleTo.cs`：对 4 卫星程序集开放 internal（`Protocol.VDA5050`/`Devices.Charge`/`Devices.Door`/`Devices.ButtonBox`），使卫星以"纯搬运"访问 Core internal，免去大量 internal→public 侵入式改动。

*E2. `StandardScene.Protocol.VDA5050`（C4）*
- `CarTypes/VDACar/`（10 文件）整迁至新工程；`scene.json`(provides VDA5050Car)；csproj 引 Core(ProjectReference)+SimpleLite/SimpleCore/CommonUsage/Topaz/Weaver + MQTTnet/Nancy/Jint/Newtonsoft。
- 解耦：`VDA5050SiteField` 由 `VDACar/VDA5050Car.cs` **下沉**至 Core `CarTypes/ArmCar.cs`（`ArmCar` 留 Core 且引用它，不能反依赖 VDA dll）。

*E3. `StandardScene.Devices`（C3，用户选 A；**门/充电桩/按钮盒合并为单一 dll**，用户定不分多个；内部按 `Door/`、`Charge/`、`ButtonBox/` 子目录组织，Core 的 IVT 仅 `StandardScene.Devices` 一项）*
- 搬出 6 具体驱动（**命名空间不变**，仍 `StandardScene.ExtendDevice.*` / `StandardScene.ChargeStationType`，以满足发现谓词 `t.Namespace==基类.Namespace`）：
  - Door：`ModbusDoorController`（基类 `BasicDoorController`+`[DoorType]` 留 Core）
  - Charge：`FL/PCB/MuXingChargeStation`（基类 `AbstractChargeStation`+`ChargeUdpService`/`StandardChargeMission` 留 Core）
  - ButtonBox：`Leeg/AzowieButtonBox`（基类 `BasicButtonBox`+`ButtonMission`/`ButtonBoxManager` 留 Core；该 dll 额外引 `Ref/leegKeys-sdk.dll`）
- **行为保持解耦（2 处下转型→基类虚方法）**：
  - `ChargeUdpService`：`if(cs is PCBChargeStation s) s.IndexReceive=msg[1]` → `cs.OnUdpMessage(msg)`（`AbstractChargeStation` 空实现、`PCB` override）。
  - `ButtonMission`：`if(bb is AzowieButtonBox a) a.ClearButtonRegister(i)` → `bb.ClearButtonRegister(i)`（`BasicButtonBox` 空实现、`Azowie` 改 override）。
- **类型发现改跨程序集（5 处，关键）**：原 Core 限定扫描（`Type.GetType(简单名)` / `typeof(基类).Assembly.GetTypes()` / `Assembly.GetExecutingAssembly().GetTypes()`）只在 Core 内找类型，驱动外移后**运行期将找不到**。统一改用内核公开的 `SimpleLite.Utils.UiTypeDiscovery.AllTypes()`（`AppDomain.GetAssemblies()` 全域 + 内置 `ReflectionTypeLoadException` 安全枚举），谓词不变 → 今天在 Core 内仍找到原类型(**行为等价**)、外移后亦能发现。涉及 `StandardChargeMission` / `DoorMission` / `DoorManager` / `ButtonMission` / `ButtonBoxManager`。
- 关键依据：SimpleLite 自身类型发现即 `UiTypeDiscovery`(AppDomain 全域) + `PluginManager`(从 `./plugins/*.dll` 以 collectible ALC 热加载)→**卫星 dll 路线运行期成立**（同时回证 VDA5050Car 可被发现）。

### 11.4 待确认 / 阻塞项（影响 C0 收尾与 C2）

1. ~~**磁 `NaiveMagGo` 参数差异**~~ **【会话1 已决】**：用户定采用含 `${track.Speed}` 的版本（Kiva 版）。已合并为唯一 `MagneticTrackCoder`；`MultiWheelLifterCar.MagTrackCoder` 删除并改向引用。编译 0 错误。（普通 `MagGo` 两份原本一致；合并后磁逻辑全平台统一。）
2. ~~**`ChangeAvoidanceParam` 统一方式**~~ **【会话1续3 已决：方案 B】**：用户选 B。落地＝4 参 flag 版 `AvoidanceParamCoder`(MWL+MultiVehicle) + 新增 2 参 L,W 版 `AvoidanceParamLWCoder`(Kiva+Forklift，触发统一取 `dst.CarLength!=-1 && dst.CarWidth!=-1`)；两车型内联 `[TemplateTrackCoderSettings]`→`[ProgramTrackCoderSettings(priority=20)]` 引用。Forklift 行为不变；Kiva 原无条件→统一后未配置长宽(-1)时不再下发 `(-1,-1)`（预期内安全收敛）。编译 0 错。原分析留档如下：
   - 现状：`Kiva`=无条件/2 参；`Forklift`=`L≠-1&&W≠-1`/2 参；`MWL`/`MultiVehicle`=`ChangeAvoidanceParam==true`/4 参(含中心点)。
   - 已落地（零行为变更）：把**逐字相同**的 `MWL`+`MultiVehicle` 4 参对合并为 `Coders.AvoidanceParamCoder`。
   - 关键事实：`CarLength/CarWidth/CarCenterX/CarCenterY` 均已在 `BasicSiteFields` 定义（中心点默认 0），故 4 参模板对各车型都可解析编译；差异只剩「触发条件 + 参数个数」。
   - 选项（已在会话中给用户）：**A**=真·单 coder 分支（flag→4 参 / 否则 L,W 有效→2 参；副作用：Kiva 未配置站点不再发 `(-1,-1)` + MWL 设了 L,W 但 flag=false 会新发 2 参）；**B**=两 coder（4 参 flag 版＋2 参 L,W 版；仅 Kiva `(-1,-1)` 行为差，无 MWL 污染）；**C**=只留已合并的同构对，Kiva/Forklift 维持内联（零变更）。**建议 B**（避障涉安全，最小行为差）。
3. ~~**去 WinForms 迁移策略**~~ **【会话1 暂定】**：用户"暂不/去掉"，本阶段不动窗体，留待 C1 专门处理。
4. ~~**内核 coder 运行期注册表**~~ **【会话1 已核查】**：当前内核**无插件化 coder 注册表**。`SegmentPlan.SetCoders()` 仅硬接 `TemplateCoderSet`+`ProgramCoderSet` 两套，均按**车型类特性**(`[*TrackCoderSettings]`)反射、在**同程序集**内 `Activator.CreateInstance`(无参构造)实例化——无外部 dll 扫描/动态注册 API。
   - 推论①：本次抽出的 `StandardScene.Coders.*` 程序 coder **能被正确加载**（车型特性 `typeof()` 引用 + 无参构造，命名空间无关），故 C0-b/c/d 成立。
   - 推论②：**C2「导航 coder 拆独立可热插拔 dll」受阻**——需内核侧（另一会话）补「运行期 coder 注册 / 插件程序集扫描」插桩；在此之前**继续兜底＝coder 留在 Core 同程序集**、由车型特性引用。
5. ~~**设备驱动外移后运行期发现**~~ **【会话1续2 已解】**：StandardScene 自有的设备类型发现原为 **Core 限定扫描**（与内核 `UiTypeDiscovery` 全域发现不一致），直接外移会断。已把 5 处统一改 `UiTypeDiscovery.AllTypes()`（行为等价、跨程序集）。**遗留验证项（运行期，归 C5）**：卫星 dll 须被 SimpleLite 实际加载入 AppDomain（`PluginManager` 从 `./plugins/` 加载）发现方生效——需将 `StandardScene.Devices.*.dll`+`scene.json` 部署到宿主 `plugins/` 并做一次真机/集成联调。与 coder(§11.4-4) 不同：设备发现码在**本仓库**、可自主修改，故 C3 不受内核阻塞。

### 11.5 下一会话推荐起手式
1. 读 §11.0（代码现状）+ §11.3（已落地，含 **E. 结构拆分**）+ §11.4（待确认/已解）。
2. **结构拆分现状**：`StandardScene.Core` + 卫星 `Protocol.VDA5050`、`Devices.{Door,Charge,ButtonBox}` 已建并全解 0 错；导航 dll(C2) 待用户重构 coder + 内核注册表后再动。
3. 待用户就 §11.4-2 拍板：`ChangeAvoidanceParam` 收尾（建议 B）。coder 整体重构由用户主导。
4. C5 验证项：把 `StandardScene.Devices.*.dll`+`scene.json` 部署到宿主 `plugins/`，真机/集成验证设备与 VDA 车型的**运行期发现**（§11.4-5）。
5. 校验手段：每步 `dotnet build StandardScene.sln`（net8.0-windows）须保持 0 错误；真机回归留待有环境时。

### 11.6 变更日志

| 时间 | 步骤 | 改动 | 备注 |
|---|---|---|---|
| 初始 | P0 | 新增 `StandardScene拆分计划.md`(v1) | 现状精读 + 归属矩阵 + 抽离清单 + 技术难点 + 分阶段 |
| v2 | P0.1 | 全文更新 | 宿主 SimpleLite、框架 net8.0、去 WinForms、设备独立 dll、删除项、WebApi 暂留+迁移索引 |
| 会话1 | C0-a | 物理删除 4 个死代码文件 + 清理 csproj | 编译 0 错误 |
| 会话1 | C0-b | 新增 `Coders/CommonTrackCoders.cs`（4 通用 coder）；Kiva/MWL/MultiVehicle/Forklift 切换为 ProgramTrackCoder 引用 | 编译 0 错误；NaiveMag/AvoidanceParam 留待确认 |
| 会话1续 | C0-c | 磁循迹器去重：`AllCarMagTrackCoder`→唯一 `MagneticTrackCoder`(含 `track.Speed`)；删 `MagTrackCoder` 改向引用 | 用户确认 track.Speed 版；编译 0 错误 |
| 会话1续 | C0-d | 避障同构对去重：`MWL`+`MultiVehicle` 4 参模板→`AvoidanceParamCoder`；基类加 `SiteFieldsType` 钩子 | 零行为变更；Kiva/Forklift 并法待定(§11.4-2) |
| 会话1续 | 核查 | 内核 coder 注册机制核查：无插件注册表，仅车型特性+同程序集反射 | 见 §11.4-4；C2 需内核插桩 |
| 会话1续2 | 路线乙·1 | 工程迁入 `StandardScene.Core/`、`.csproj`→`StandardScene.Core.csproj`、重写 `.sln`、加 `Properties/InternalsVisibleTo.cs`(4 卫星) | 纯搬运；编译 0 错 |
| 会话1续2 | C4 | 拆 `Protocol.VDA5050`：`CarTypes/VDACar/`(10 文件)整迁出；`VDA5050SiteField` 下沉 `ArmCar.cs` 解耦；scene.json | 编译 0 错 |
| 会话1续2 | C3 | 拆 `Devices.{Door,Charge,ButtonBox}`：6 驱动外移；2 处 `is 具体类`→基类虚方法；5 处类型发现→`UiTypeDiscovery.AllTypes()` 跨程序集 | 行为等价；全解编译 0 错、3 dll+scene.json 产出 |
| 会话1续3 | C3 | 三 `Devices.*` **合并为单一 `StandardScene.Devices`**（内部 Door/Charge/ButtonBox 子目录；IVT 3→1；删旧 3 工程、重写 sln） | 用户定"不分多个"；编译 0 错、单 dll+scene.json 产出 |
| 会话1续3 | C0-d | `ChangeAvoidanceParam` 去重收尾(方案 B)：新增 2 参 `AvoidanceParamLWCoder`；Kiva/Forklift 内联模板→`[ProgramTrackCoderSettings(priority=20)]` 引用 | 编译 0 错；Forklift 不变、Kiva `(-1,-1)` 安全收敛 |

---

*附：本计划引用的类/文件/行号均来自当前工程 `E:\Work\Core\Simple-FR\StandardSence` 实际代码走查；SimpleLite 接口依据 `E:\Work\Core\Simple-FR\Simple\SimpleLite\Docs\MIGU-API.md` 与 `SimpleLite.csproj`（net8.0 / CycleGUI / EmbedIO）。*
