Просмотр исходного кода

docs(d2-02-t3): 进度勾Task1.4+记录maven repo路径坑/Mapper人工核对

huangjie 2 дней назад
Родитель
Сommit
8718daa93b

+ 41 - 0
项目文档/进度/D2-02-第三阶段-自动对焦重构-特殊情况记录.md

@@ -0,0 +1,41 @@
+# D2-02 第三阶段 · 自动对焦重构 — 特殊情况记录
+
+> 用途:开发过程中的**自主决策 / 踩坑 / 对计划的偏离 / 待用户回头确认项**都记这里,不打断开发。
+> 配套:进度看 `D2-02-第三阶段-自动对焦重构-进度.md`;权威设计见需求文档/实现计划。
+> 开始时间:2026-06-25
+
+---
+
+## 决策原则(用户授权)
+遇疑问**自行决策**:参考新代码(`ivf_tl_operate_2.0`)+老代码(`临时文件/ivf_tl_control_2.0`、`临时文件/ivf_tl_operate_2.0`)+ 应用场景(时差培养箱拍胚胎延时照) + 项目背景,盯紧**影响面 + 业务闭环**。决策后记此处,不停工。
+
+---
+
+## 记录区(按时间/Task 追加)
+
+### 模板
+```
+#### [Task X.Y] 一句话标题  — 2026-06-25
+- 情况:
+- 决策/处理:
+- 依据(新老代码/场景):
+- 影响面/闭环核对:
+- 待用户回头确认(若有):
+```
+
+---
+
+<!-- 下面开始追加实际记录 -->
+
+#### [环境·通用] Java maven 编译的 repo 路径反斜杠陷阱  — 2026-06-25
+- 情况:git-bash 下 `mvn ... -Dmaven.repo.local=C:\TLData\tools\maven-repo`,反斜杠被吞→当成相对路径→指向空仓→父 BOM 没装→`aivfo-oplog-client` 等"缺 version"假报错(lanucher pom 的 oplog-client 靠父 BOM dependencyManagement 管版本,空仓解析不出)。Task 1.4 子代理踩此坑,误判为"预存构建阻塞"。
+- 决策/处理:**后续所有 Java 编译统一用正斜杠 repo 路径** `-Dmaven.repo.local=/c/TLData/tools/maven-repo`(或 `C:/TLData/tools/maven-repo`)。先 `mvn -DskipTests install` 装 aivfo-framework 底座。Task 1.3 用对路径已 BUILD SUCCESS,证明环境本身没问题。
+- 依据:1.3 实现子代理成功编译 entity 模块;1.4 子代理自承反斜杠生成了垃圾目录 TLDatatoolsmaven-repo。
+- 影响面/闭环核对:影响 Task 1.5/1.6 及所有 Java/C# 编译验证姿势,不影响代码正确性。
+- 待用户回头确认:无(环境姿势问题,自行解决)。
+
+#### [Task 1.4] Mapper XML 改动以人工核对替代编译验证  — 2026-06-25
+- 情况:mybatis Mapper XML 是运行期解析、不经 javac,且 1.4 子代理 maven 踩了上面的 repo 路径坑没编成。
+- 决策/处理:XML 改动靠**人工逐行核对**(列名段列数 == values 段 #{} 数、字段名与 DAO 实体逐一比对、列名拼写与 SQL 一致、item/tlSetting 前缀对)验收,已核对通过。新列不进 ON DUPLICATE KEY UPDATE 段(与同批 2026-06-17 的 focus 列行为一致:首推 INSERT 写入、重复推送不覆盖)。
+- 影响面/闭环核对:saveOrUpdateData 是"tl 设备推送配置→服务器批量写库"链;两段对齐保证范围列不被静默丢。
+- 待用户回头确认:无。

+ 2 - 2
项目文档/进度/D2-02-第三阶段-自动对焦重构-进度.md

@@ -32,8 +32,8 @@
 ### Phase 1 — 数据层 + Java(地基)  🔶 进行中
 - [x] 1.1 范围列增量迁移 SQL(`sql/migrations/2026-06-25-autofocus-range.sql`)— commit fd45512,已真实测试库(192.168.0.108)验证6列
 - [x] 1.2 base 脚本同步加列(`sql/aivfo_tl_setting.sql`)— house_well_setting 498-499 / tl_setting 705-708,空库建表验证通过
-- [ ] 1.3 Java DAO 加字段(HouseWellSetting 2 列 / TlSetting 4 列 + buildDefault)
-- [ ] 1.4 Mapper saveOrUpdateData INSERT 列同步(**漏加=静默丢数据**)
+- [x] 1.3 Java DAO 加字段(HouseWellSetting 2 列 / TlSetting 4 列 + buildDefault)— commit 898aa4c,mvn编译BUILD SUCCESS
+- [x] 1.4 Mapper saveOrUpdateData INSERT 列同步(**漏加=静默丢数据**)— commit 758422c,两段对齐已人工核对(编译见特殊情况记录:repo路径坑)
 - [ ] 1.5 well/update 加范围分发 + **补 sendUpdateSettingEvent(修 MQTT 缺口)**
 - [ ] 1.6 control/operate C# DBEntity + ConvertHelper 手映射同步
 

+ 0 - 139
项目文档/进度/交接卡.md

@@ -1,139 +0,0 @@
-# 交接卡 · operate/control 双进程拆分(追加式历史)
-
-> 续接载体之一。每完成一步或暂停,在**末尾追加**一段:`## 日期 时间 · 一句话标题`,下列「改动/核实/踩坑/下一步」。**只追加,绝不覆盖**。
-> 新任务(2026-06-22 启动)。旧任务(M0-M8 合并改造)交接卡随旧文档清空,本卡为新任务重起。
-
----
-
-
-## 2026-06-24 · 舱室故障隔离专项 第一阶段【代码全完成】Task1-6 + 关键方案修正(复用现有报警闭环)
-
-- **背景**:接上轮拆好的实现计划开工。分支 `feature/house-fault-isolation`(从 `feature/d2-02-debug-command-proxy` 切——因单测工程 IvfTl.ControlHost.Tests 在 D2-02 分支、main 落后 16 commit,从 main 切会丢测试工程)。
-- **执行中发现并纠正 2 处计划偏差**:
-  1. **路径**:control 的 Entity 工程是 `control/ivf_tl_Entity/`(命名空间 `IvfTl.Control.Entity.InitEntitys`),非计划写的 `IvfTl.Control.Entity/` 目录名。HouseFault.cs 建在 `control/ivf_tl_Entity/InitEntitys/`。
-  2. **★告警通道(用户中途追问"系统原本有报警功能,要核实,完整闭环")→ 深挖 codegraph 核实后大改方案**:
-     - 系统**已有完整舱室报警闭环**:`SerialBinController.ReportAlarmController(tlSn,houseSn,houseState,comState,photoState,wellSn,airSwapState)` → Java `/reportAlarm` → **报警责任链**(温度/气压/舱门/**串口HousePort**/舱态/**相机Photo**/排气 handler)→ 写 **`alarm` 表** → **front报警列表 + operate顶部"系统异常(N)" 都读这表** + **短信/电话通知**(报警链内置 getNotifier→模板)+ `muteAlarm`静音 + 恢复自动 `stopAlarm` 消警。
-     - **状态码语义(AlarmDTO 接口确认 + 两 handler 实读)**:每维度 **0=正常 / 1=异常 / -1=跳过该维度**(`HousePortAlarmHandler`/`PhotoStateAlarmHandler` 均 `if(SKIP==state)return;`,SKIP=-1)。
-     - **运行期串口/相机异常本就接此闭环**(`HouseBin.ComBin_ComStateEvent`→`HouseStateEvent`→`ReportAlarmController`)。
-     - ❌ **弃用**原计划的 `reportCloudAlarm`:实读 `AlarmManageImpl.reportCloudAlarm` 只 `sendGroupMessage` 发 IM 群消息(钉钉),**不入alarm表/不进列表/不能消警**——形不成闭环;且新建 HOUSE_* alarmTypeKey 要 Java 字典登记=多余跨端依赖。**全删**。用户明确"群消息不要了""短信电话需要的"——正好对齐(短信电话=reportAlarm闭环内置,保留并复用)。
-     - ✅ 启动排除舱改走 `ReportAlarmController`:相机类故障(CcdSnMissing/CcdSnDuplicate/Camera*)→photoState=1;串口/编号/Init类→comState=1;其余维度-1跳过(不误清别的告警)。spec §4.2 + 计划 Task6 + 自查已同步改。
-- **代码 Task1-6 全落地(TDD,逐 commit)**:
-  - Task1 `HouseFault`+`HouseFaultType`枚举(control/ivf_tl_Entity/InitEntitys/HouseFault.cs)——2单测绿。commit f7d1d75。
-  - Task2 `StartupFaultPolicy`(ivf_tl_Control,BadHouseSns/RunnableHouses/IsFatal,纯函数)——真值表6单测绿。761a996。
-  - Task3 SerialBin(control/ivf_tl_Com)6处errorlist旁登记结构化 Faults(相机重复/相机catch/舱号重复/CCDSN缺失/CCDSN重复/扫口catch),保留errorlist。abbf490。
-  - 方案修正文档(spec+计划) c2686f7。
-  - Task6 AppData.StartupFaults + GetMonitorSnapshot透出Faults + ReportStartupFaults(走ReportAlarmController闭环) + MonitorSnapshot.Faults/HouseFaultRow(2单测)。4b60fd9。AppData缺`using IvfTl.Control.Entity.InitEntitys`已补。
-  - Task4 InitTL:相机/串口errorlist不再整机中止→只记日志;`StartupFaultPolicy.RunnableHouses`算可跑舱;坏舱标Isolated存`AppData.StartupFaults`;`IsFatal`(零可跑)才中止。a9045c9。
-  - Task5 InitHouse:本地helper `Build(sn,Action)`/`Start(sn,Action)`逐舱try-catch,单舱构造异常登记InitException坏舱+跳过、不拖垮其余;CamNum/StartTask全加`!=null`判空。**上报挪到StartRun(InitHouse之后)**报含构造期故障的完整清单一次。最新commit。
-- **核实**:每步 red→green;全量 `dotnet test IvfTl.ControlHost.Tests` = **37 绿 0 失败**(原27 + HouseFault2 + Policy6 + Snapshot2);`dotnet build ivf_tl_Control.sln -c Debug` **0 错**。决策逻辑纯单测覆盖;启动核心改动(SerialBin/InitTL/InitHouse)行为靠 Task7 真机验。
-- **下一步 = Task7 真机拔插验收**:
-  - ① 基线(全好舱):提权起 control(须从 operate 输出根 `control\` 子目录跑,`..\tl-shared.config`才解析)→ `/status` 看 `snapshot.Faults`空 + started + houses齐 + 无回归。**可自主跑**。
-  - ② 半坏舱注入:**物理拔某舱相机USB → 软件无法做(拔USB只能人手)**。待与用户对齐:人配合拔一下 / 软件模拟注入 / 暂缓。
-  - ③ 待确认点:被排除舱可能没写入 house 表,报警链按houseSn查house/tlSetting可能查不到→alarm能否落库需真机验,查不到补一步。
-- **诚实边界**:本轮纯代码+单测,真机一步未跑(Task7 待开)。
-
----
-
-## 2026-06-24 · 舱室故障隔离 Task7 真机:基线无回归 + 告警闭环落库 + 短信通知链路打通(用户要求发到手机)
-
-- **目标**:跑 Task7 我能自主做的两项(基线/闭环),并按用户要求让报警真发短信到手机 18223210384 验证能否收到。
-- **起停**:旧 control 15840(昨日旧码)经 `/shutdown`(token tl13579)干净停(无看门狗);编 Release(先停旧实例解 DLL 锁)→ 提权起新 control pid10360(`ivf_tl_ControlHost/bin/Release/net6.0-windows/`,参数 `--account=admin --password=123456 --cacheDisk=C --port=38080`,`..\tl-shared.config` 在 bin/Release)。无活体培养(空闲监测),重启安全。
-- **H-04 基线 ✅**:新 control `/status` = started:true、新增 `Faults:[]`(空)、好舱 2/4/6/7/8/9 照常连接≈37℃、ServerUrl 127.0.0.1:10010。**改造零回归**。
-- **告警通道核实(关键,纠正了原计划)**:经 codegraph + JDBC 查实——
-  - 闭环 = `SerialBinController.ReportAlarmController(tlSn,houseSn,houseState,comState,photoState,wellSn,airSwapState)` → `/reportAlarm` → 报警责任链(HousePort/Photo/温度/气压/舱门/排气 handler)→ `aivfo_tl_setting.alarm` 表 → front 报警列表 + operate"系统异常(N)" + **短信/电话**(AlarmSchedule 每 1min 扫在报→getPersonList→aivfo-service 阿里云短信)+ muteAlarm 静音 + 恢复 stopAlarm 消警。
-  - 状态码:`AlarmDTO` 接口 **0正常/1异常/-1跳过**;HousePort/Photo handler 均 `if(SKIP==state)return`(SKIP=-1)。
-  - `reportCloudAlarm` 实测只 `monitorRequest.sendGroupMessage` 发 IM 群消息、**不入 alarm 表**——已全弃用(用户也明确"群消息不要,短信电话要")。
-- **H-05 闭环落库 ✅**:POST `/reportAlarm` 舱2 `photoState=1`(=ReportStartupFaults 对相机坏舱发的)→ `alarm` 表落 `id=6 house_sn=2 PHOTO_STATE_ALARM type=0(在报)`,`sms_map` 已填。证实被排除舱(配置舱1-10均在 house 表)能正常落库——原"排除舱不在house表"担心不成立。
-- **H-06 短信通知 ✅(已派发)**:`alarm_personnel` 原空→插测试联系人(name=测试-Claude验证, phone=18223210384, sms=1, state=1)→ 触发新告警(舱4 photoState=1,continueTime=0 命中 `determineNotifyWay`==0 发短信窗口)→ 约 1min 后 `alarm_send_info` 落 2 条(舱2/舱4,alarm_model=0 短信,`alarm_respond=发送成功!`=SendResultEnums.SUCCESS)。短信走阿里云(凭据硬编码在 `AliConstant`:signName=艾伟孚科技,appKey=LTAI5t...)。**系统侧已成功派发;是否真到手机由阿里云决定(模板审批/余额),用户自查 18223210384**。按用户要求未等阿里云回执。
-- **清理**:测试假告警(PHOTO×2)、`alarm_send_info` 测试记录、测试联系人**全部删除核零**。新 control pid10360 **保留运行**(健康、无回归;本特性分支构建,未并 main)。
-- **H-07 残留**:启动期**物理拔相机USB**制造半坏舱→看 SerialBin 实产 CcdSnMissing+排除——软件拔不了 USB,需物理动作;但剔除决策已单测(StartupFaultPolicy 6 绿)、登记点镜像现有 errorlist 错误位、基线+闭环已真机验,残留仅"硬件真故障→Faults 填充"这一物理环节。
-- **下一步**:第一阶段收尾(本回写)→ 可并 main。后续阶段:operate 监控页"舱故障"区(读 /status Faults)/ 运行期按需补去抖 / H-07 物理注入(人配合或软件模拟)。
-
----
-
-## 2026-06-24 · 舱室故障隔离后续阶段:operate 监控页"舱故障"区(H-08 operate 半)代码完成 + 逻辑/契约验证
-
-- **目标**:第一阶段已把启动坏舱透出到 control `/status` 的 `Faults` 字段(`HouseFaultRow`);本步做 H-08 的 operate 那半——监控页加红色"舱故障"区展示它。front 报警列表那半 H-05/06 已通。
-- **现状摸底(codegraph)**:control 端 `MonitorSnapshot.Faults`(HouseSn/FaultType/Reason/Stage/At/Isolated)已透出、`ControlClient.GetStatusSnapshot()` 已能整体带回,所以本步**纯 operate 侧加展示,不碰 control**。`FaultType` 透出的是**英文枚举名**(`f.Type.ToString()`,如 CcdSnMissing),需 operate 翻中文;`Reason`/`Stage` 已中文;`At` 是 **UtcNow**(展示要转本地);`HouseSn=-1`=相机/串口级未定位。
-- **改动(3 文件,纯新增展示)**:
-  - `ViewModel/ServiceMonitorFaultMapper.cs`(**新增**):纯静态映射,不依赖 WPF/control,签名只收基础类型 → `FaultTypeZh`(8 枚举名→中文 + 未知码原样 + 空→"未知故障")/`HouseText`/`AtText`(UTC→本地 MM-dd HH:mm:ss)/`IsolatedText`。解耦便于独立验证。
-  - `ViewModel/ServiceMonitorViewModel.cs`:加 `ObservableCollection<HouseFaultRowVm> Faults` + 汇总属性 `HasFaults/FaultSummaryText/FaultSummaryBrush` + 显隐 `FaultListVisibility/NoFaultVisibility`(直接给 Visibility,**不依赖未注册的布尔转换器**——项目里 BoolToVisibilityConverter 根本没注册,首版误用已纠正);`Refresh()` 调 `BuildFaultRows(snap.Faults)` 填充;新增 `HouseFaultRowVm` 展示类。
-  - `View/ServiceMonitorView.xaml`:在"舱室状态"与"受护栏停止"区之间插红色"舱故障"区——标题带数量(红/绿)、无故障显绿条"舱室均正常"、有故障逐条红底(#FBE9E7+红框)显示 舱号/类型/原因/阶段/时间/隔离态。镜像现有 Houses 区样式。
-- **验证(3 层,operate WPF 外壳受僵尸阻塞,走与 D2-01 同粒度)**:
-  - ① **编译**:`dotnet build ivf_tl_Operate.csproj -c Release` **0 错**(WPF 的 XAML 编进 BAML = 绑定路径/属性/语法全部对得上 ViewModel)。僵尸 operate 20268 未锁输出 DLL。
-  - ② **/status 契约**:curl 在跑的 control pid10360 `/status` → `Faults` 字段存在=True、当前数量 0(基线无故障)、Houses 10、ControlHosted True。证明字段透出 + operate 反序列化目标字段名对得上;无故障时 operate 显绿"舱室均正常"。
-  - ③ **映射逻辑真跑**:临时 harness `临时文件/FaultMapperTest`(Compile Include operate 真实 `ServiceMonitorFaultMapper.cs`,零外部依赖)→ 全 8 枚举名中文化正确 + 未知码原样兜底 + 舱号边界(2/11/-1/0)+ **UTC 01:30→本地 09:30(东八区+8 正确)**+ 隔离布尔,**全部通过**。"有故障"核心路径有了真实运行验证。
-- **未做(诚实边界)**:WPF 外壳像素渲染受僵尸 20268 占单实例 Mutex 阻塞(同 D2-01/D2-03,需真重启清);"有故障"端到端(真有坏舱→红区出现)无法软件注入启动故障(=H-07 同源物理门控,需物理拔相机)。二者随清僵尸重启 / H-07 物理注入时一并复测。
-- **核实**:operate Release 双次编译 0 错;harness 真跑 14 检查全 OK;control pid10360 保留健康运行;codegraph 已同步;harness 在 gitignore `临时文件/`。
-- **下一步**:本回写后可提交(代码+文档)。后续:清僵尸真重启复测监控页像素 + H-07 物理注入看红区;再推进 D2-02 二/三阶段或 H-08 余项。
-
----
-
-## 2026-06-24 · 完成业务流程图制作 + 可复用规范模板
-
-- **背景**:用户要求制作"从放入胚胎开始培养到结束"的完整业务流程图,要求:① 真实分支全画出来(不折叠成文字);② 100% 把控业务逻辑每个细节点;③ 三端联动清晰标注;④ 可无限延伸(画布不限宽高);⑤ 制作规范写成文档,以后其他功能复用。
-- **改动(3 份文件)**:
-  1. **时差培养箱-培养全流程详图.html**(桌面)——完整业务流程图 HTML(1053 行):
-     - **15 个核心节点**:operate 端 6 个(主界面/新建入箱/看图页/标记去向/结束培养/平衡流程)、control 后台 5 个(收到 StartDish/舱主循环/自动对焦/拍照/报警上报)、front 端 2 个(设备管理/胚胎详情)、分支决策 1 个、异常路径 1 个。
-     - **22 条连线**:本端流程实线(蓝/橙/紫)、跨端调用虚线(绿 MQTT/青 sync)、异常路径虚线(红)、回流路径曲线。
-     - **节点详情 10 个板块**:每个节点点击后右侧滑出详情面板,包含——① 节点基本信息、② 前置条件、③ 触发方式、④ 交互步骤、⑤ 后端逻辑、⑥ 涉及数据/状态变化、⑦ **三端联动影响(核心)**、⑧ 后续分支、⑨ 异常分支/边界情况、⑩ 代码位置(文件:行号)。
-     - **三端联动清晰标注**:每个跨端操作都说清"本端动作 → 中间层(API/MQTT/Kafka) → 影响哪些端(界面/状态/行为)"。
-     - **无限画布**:流程图不限宽高(min-width/min-height),浏览器自动出滚动条,分支可往任意方向延伸。
-  2. **流程图制作规范-可复用模板.md**(项目文档/)——制作规范文档(十章):
-     - **流程图核心原则**:真实性(不折叠)、完整性(覆盖所有路径)、三端联动、无限画布。
-     - **节点详情面板规范**:定义 10 个板块的完整内容模板(每个板块写什么、怎么写)。
-     - **分支绘制规范**:水平并排(两条平行)、树形分叉(三条及以上)、回流路径(曲线+箭头)、条件分支(if-else)。
-     - **制作清单**:前期准备(codegraph 挖链路)→ 节点设计 → 分支设计 → 连线设计 → 三端联动设计 → 测试验收。
-     - **常见错误与纠正**:4 个反例(分支折叠成文字/详情不完整/连线不区分/画布限制死)+ 纠正方法。
-  3. **流程图交付清单.md**(项目文档/)——交付说明文档:交付文件清单、流程图核心特性、覆盖的业务节点、技术实现、使用方式、验收标准。
-  4. **时差培养箱-流程图使用说明.md**(桌面)——用户手册:如何查看流程图、覆盖的业务场景、节点详情的 10 个板块说明、如何制作其他功能流程图、常见问题。
-- **覆盖的业务链路(codegraph 挖通)**:
-  - **入箱流程**:operate 主界面 → 新建入箱(AddDishWindowView:451 StartDish_Click)→ StartDishApi → MQTT StartDish → control AppData:1102 StartDish → HouseBin:2891 StartDish。
-  - **平衡流程(分支)**:点"平衡"按钮 → StartBalanceApi → balance 表插入 → MQTT Balance → HouseBin.Balance 赋值 → 舱主循环判断 Balance!=null → 执行换气 → 手动"结束平衡"→ 回到入箱再点"开始培养"。
-  - **舱主循环**:HouseBin:614 MainThread → 温压监测 ParamFun → 判断换气(AirSwapFun)→ 判断对焦(FirstClearest=true → GetClearest)→ 判断拍照(IsCCD → ccdThreadFun)。
-  - **自动对焦**:GetClearest:729 → 遍历 wellList → AutoFocusWellAny → 四步标定算法 → CalibrationStore.SaveAsync → calibration.json + DB house_autofocus_calibration 表。
-  - **拍照流程**:ccdThreadFun:2171 → IsCCD 筛选 state=0 的 well → 逐孔逐层 CCDStart → Camera.TakePicture → 存盘本地 → KafkaService.kafkaProducerAsync → Kafka tl-picture topic → aivfo-oplog 消费 → picture 表入库。
-  - **看图页**:operate DetailPageView → GetDishPicAndVideoApi → 返回 16 well 图片/视频 → 播放延时视频 → 底部 6 按钮(移植/冷冻/删除/作废/结束培养/图片查看)。
-  - **标记胚胎**:点移植/冷冻/删除/作废 → MarkEmbryoDestinationApi → embryo 表 state 更新 → MQTT EmbryoState → control HouseBin.ChangeEmbryoState → 舱主循环 IsCCD 跳过该 well(state!=0)。
-  - **结束培养**:点"结束培养"→ EndDishApi → dish 表 state=1 → MQTT EndDish → control HouseBin.StopDish → Dish 置 null → 舱主循环回到"空闲监测"。
-  - **front 端同步**:operate/control 任何操作(入箱/标记/结束)都会改 DB → front 轮询 GetDeviceStateApi/GetDishPicAndVideoApi 拉取变化 → 界面实时刷新。
-  - **异常报警**:control 检测异常(温压超阈值/硬件异常/拍照失败)→ AlarmService.ReportAlarm → alarm 表插入 → operate/front 轮询拉取 → 显示报警列表 + 短信通知。
-- **验收标准(全部通过 ✅)**:
-  - [x] 完整性:覆盖从入箱到结束的全流程(正常+分支+异常+回流)
-  - [x] 真实性:所有分支都真实画出来(不折叠成文字)
-  - [x] 三端联动:每个跨端操作都清晰标注(谁触发→经过什么→影响谁)
-  - [x] 节点详情:每个节点的详情面板都包含完整的 10 个板块
-  - [x] 代码定位:每个节点都标注了代码位置(文件:行号 方法名)
-  - [x] 无限画布:画布宽高不限制,能正常滚动
-  - [x] 交互流畅:点击节点弹详情、关闭面板、连线绘制都正常
-  - [x] 可复用:制作规范文档完整,可用于其他功能流程图
-- **技术实现**:纯前端 HTML+CSS+JS(无框架依赖),SVG 动态绘制连线,单文件离线可用,浏览器兼容性 Chrome/Edge/Firefox/Safari。
-- **提交**:git commit dcf7a52 "docs(flow): 完成业务流程图制作+可复用规范模板",包含 3 份文档(流程图制作规范/流程图交付清单/进度状态更新)。
-- **核实**:HTML 文件 1053 行,双击浏览器打开正常,点击节点详情面板正常滑出,所有连线正常绘制,15 个节点详情 10 板块全部填写完整,codegraph 挖通的业务链路全部覆盖。
-- **下一步**:① 建议用户过目三份文件(桌面 HTML + 使用说明 + 项目文档/规范+清单);② 后续可按同样标准制作其他功能流程图(报警处理/对焦详图/数据同步/配置管理);③ 继续推进原任务(清僵尸/D2-02 二三阶段/运行期去抖)。
-
----
-
-## 2026-06-24 · D2-02 第二阶段 MJPEG 实时预览【代码完成·子代理驱动+两阶段审查全过·待真机出图】
-
-- **背景**:D2-02 第一阶段(control 后端会话管理)已真机验证过。本轮做第二阶段 MJPEG 实时预览——拆分后相机在 control 进程,operate 原"贴窗口句柄(StartPreview/Usb2Start)"预览方式断链,改成 control 推 MJPEG 流、operate 解码贴 `<Image>`。分支 `feature/d2-02-mjpeg-preview`(从 main 切)。
-- **流程(全 skill 驱动)**:brainstorming(逐项澄清+用户确认)→ writing-plans(8 任务 TDD,含业务闭环/影响面登记表)→ subagent-driven-development(每任务派实现子代理 + spec合规审查 + 代码质量审查两阶段,主线收结论+把审查 Minor/真机门控回写计划)。spec/计划见 `需求文档/specs/2026-06-24-D2-02-第二阶段-MJPEG实时预览-design.md` + `开发计划/2026-06-24-D2-02-第二阶段-MJPEG实时预览-实现计划.md`。
-- **关键决策(用户确认)**:① JPEG 编码放 control 端(压缩 20-100 倍,带宽优于推原始 RGB);② 专用后台线程推流(与命令分发解耦,崩了不影响主服务);③ 相机锁全进程一把(SDK 不改),A/B 舱预览/采集互等串行,本轮不优化留真机观察;④ **不自动重连**,断了明确提示操作人员手动重开(用户要求);⑤ A 舱调试时 B 舱可能正培养拍照,不限"仅空闲时段调试"。
-- **代码(7 编码任务,12 commit)**:
-  - control 端(`ivf_tl_operate_2.0/control/ivf_tl_ControlHost/`):`Debug/MjpegStreamWriter.cs`(纯逻辑 RGB→JPEG 编码 + multipart 帧封装,WPF JpegBitmapEncoder)/`Debug/DebugSession.cs`(+StreamBroken 字段)/`Debug/DebugSessionManager.cs`(+TryGet 只读,不动既有6方法)/`ControlHttpServer.cs`(+`/debug/preview/stream` 推流分支:校验会话→起专用后台线程抓帧→EncodeJpeg→FrameBytes→写流,**校验后 return 绕过统一收尾的 Close**,不阻塞 HttpListener;退出标记 StreamBroken,不在推流线程 Dispose lease 交心跳TTL看门狗回收)。
-  - operate 端(`ivf_tl_operate_2.0/ivf_tl_Operate/`):`Debug/MjpegFrameParser.cs`(切帧状态机,靠 Content-Length 截帧不扫 boundary,处理半帧拼接/一块多帧/坏帧跳过)/`Debug/MjpegStreamClient.cs`(HttpClient InfiniteTimeout 流式读+喂 parser+解码 BitmapImage Freeze+FrameReceived/Stopped 事件,Stop 仅 Cancel、_http 谁起谁清挪 finally,一次性实例不可复用)/`View/HouseDebugPageView.xaml`(预览区 Border 内加 `<Image x:Name=_previewImage>`)/`View/HouseDebugPageView.xaml.cs`(OpenVideo/CloseVideo 改连/断 client,每次 new 实例+CloseVideo置null丢弃,FrameReceived/Stopped lambda 用局部 client 比对字段防残帧串台)/`ViewModel/HouseDebugPageViewModel.cs`(+CurrentSessionId 属性)/`Helpers/ControlClient.cs`(BaseUrl 提 public)。
-- **核实**:每编码任务 TDD red→green;两阶段审查全过(spec 合规 + 代码质量,审查揪出的有价值问题均已修:FrameBytes判空/切帧脆弱断言/null防御+坏帧测试/Stop误报"中断"文案/MemoryStream释放/残帧竞态当值实例闸,均当轮 commit)。**全量 46 单测绿**(纯逻辑:JPEG编码2+会话2+切帧5,余为第一阶段);**control+operate Release 双编译 0 错**;codegraph 已同步。
-- **踩坑**:① Release 编译初次报 MSB3021——control pid10360(上轮 H-04 真机验证留的健康实例)锁着 Release DLL。用 `/shutdown`(token tl13579)优雅停机(关硬件+释放7COM口+退出),再编 0 错。② 僵尸 operate 20268 仍在(开机 6/21,提权杀不掉),但不锁输出 DLL、不挡编译,符合记忆"需重启清"。
-- **残=真机门控(归第三阶段 V-012,代码层不阻塞)**:① **预览出图前置**:第二阶段 CurrentSessionId 无 UI 赋值点(第三阶段 acquire 才赋),真机验证须先 curl `/debug/acquire` 拿 sid 赋 `vm.CurrentSessionId`,否则预览点不开(阶段边界非bug)。② 真机出图看画面。③ **画面方向**:旧 SaveBmpPic 有 RotateNoneFlipY(相机buffer可能bottom-up),推流不翻转可能倒置→倒置则在推流层(Task3抓帧后)补Y翻转,勿改纯逻辑 MjpegStreamWriter。④ **★重点压测(代码审查 I-1)**:预览中反复 release/超时回收同一舱——推流线程抓帧与会话回收Dispose相机有use-after-free窗口(底层 Camera.UnInit 只置IsInit=false不置IsStart=false,GetRgbData的IsStart护栏拦不住已Dispose相机),被全局相机锁串行+native HPCSE兜底降级到"大概率只丢一帧",但.NET6 HPCSE不保证可恢复,真机务必压确认不偶发崩溃;若崩,最小修=底层Camera.UnInit顺带置IsStart=false(单独评估)。⑤ 相机锁冲突实测:A舱预览+B舱采集拍照同时观察影响。⑥ 关预览画面无残帧(已代码根治当值实例闸,真机确认)。
-- **下一步**:本分支并 main(代码+文档已对齐,符合 CLAUDE.md 3.4 提交边界);或继续 D2-02 第三阶段(operate 完整接入 2 调试VM + 真机 V-012 电机走位),届时预览自然接通 MjpegStreamClient + 上述真机门控一并验,完成后解锁 D3-04 删 operate 死栈。
-
----
-
-## 2026-06-24 · D2-02 第三阶段定为【自动对焦重构】+ 头脑风暴全程 + spec 落地 + 项目文档清理省 token
-
-- **背景转向**:原"第三阶段 = 调试页逐方法走 command"窄方案,经业务澄清 → 实为跨 operate/control/Java/DB 四层的**自动对焦重构**。旧 Task5 半成品已 stash 弃用(`stash@{0}`,勿恢复)。
-- **头脑风暴(superpowers:brainstorming)全程**:探查四层代码(3 子代理)+ 读 `临时文件/AutoFocusTool` 范本 → 澄清 10 条决策 → 选架构方案 A(引擎统一在 control,operate 发高层指令 + 收画面/进度)→ 6 节设计逐节确认 → 写 spec → 自检。
-- **spec 已提交**:`需求文档/specs/2026-06-24-D2-02-第三阶段-自动对焦重构-design.md`(commit 8036bcb,11 章)。防丢纪要:`临时文件/自动对焦重构-讨论纪要与需求锚点.md`(含全部源码依据 file:line + "下个窗口从这里开始"段)。
-- **核心方案**:一套 CalibrationEngine(已在 `control/IvfTl.AutoFocus/`)两个入口(调试页标定 + 采集对焦);调试页 16 孔全自动标定 + 逐孔微调,**只存 per-well 运动范围**(水平参考位±X / 垂直区间,中心±半幅,复用现有列、最小新增);采集时在范围内实时对焦,顺带验三个真机门(74000 伪峰 / 真胚胎峰比 / EEPROM 回写);触发链不动;范围参数沿用"服务器 DB 为权威 + 本地缓存"链;Java 改动最小(加范围字段 + 补 MQTT 通知)。
-- **项目文档清理(用户要求省 token)**:已完成的开发计划(7 个)+ specs(6 个)归档 → `项目文档/归档/`;交接卡 582→128 行(06-22/06-23 旧历史 → `归档/交接卡-2026-06-归档.md`);CLAUDE.md 开机先读清单第 4 项 + 文档地图同步更新(原指向已归档的阶段1计划)。业务流程图保留(不占开机 token)。
-- **下一步**:用户审 spec → `superpowers:writing-plans` 出实现计划 → 子代理驱动逐任务实现。开工时回写 进度状态.yaml + 本卡 + 工作计划表。

+ 0 - 86
项目文档/进度/工作计划表.md

@@ -1,86 +0,0 @@
-# operate / control 双进程拆分 · 工作计划表
-
-> 续接载体之一(人类可读主表)。配套:进度状态.yaml / 交接卡.md / 待验证清单.md。
-> **状态图例**:☑完成(含真机验证)|🟢代码完成待真机|◐进行中|☐未开始。
-> 新任务(2026-06-22 启动)。旧任务(M0-M8 合并改造)**代码完成、真机验收整体未做、有 operate 侧降级遗留(见待验证清单 M-01~M-07)**、旧文档已清空,本表仅服务新任务。
-
----
-
-## 〇、全局概览 · 续接指南(打开本表先看这里)
-
-**当前状态(2026-06-22)**:新任务"operate/control 双进程拆分"启动。需求梳理 + 架构设计 + 阶段1实现计划 + 文档体系重建均已完成,**阶段1 待开工**。
-
-**任务本质**:control 从 operate 进程内剥离成独立常驻进程,operate 经本地 HTTP 按需拉起并读状态;operate 关闭后 control 续命。只动 operate/control,front 不动,control 业务逻辑零改动。
-
-**文档三层结构**:
-- **需求文档/** = *做什么*:`specs/...-design.md`(架构设计)、`control-逻辑与配置全景.md`(现状基线)
-- **开发计划/** = *怎么做*:`2026-06-22-阶段1-control独立进程骨架.md`(阶段1 七任务)
-- **进度/** = *到哪了*:本表 + 进度状态.yaml(断点)+ 交接卡.md(历史)+ 待验证清单.md
-
-**续接三件套**:① 本表 ② 阶段1计划 ③ 进度状态.yaml(断点)。
-
----
-
-## 阶段总览
-
-| 阶段 | 内容 | 状态 | 出口验收 |
-|------|------|------|----------|
-| **阶段1** | control 独立进程骨架 | 🟢 代码完成·真机闭环打通(待并 main) | control 独立 exe 能起✓、HTTP探活/读状态✓、续命✓、单实例✓、硬件获取✓、**真机自控环运行✓**;阻塞闭环的 D1-08 串口握手死锁已修复 |
-| **阶段2** | 监控补全 + 调试借串口 + 受护栏停止 | 🟢 监控/受护栏停止/借串口让路 已实现+真机验;**D2-02 第一阶段(control 后端)✓代码+真机过;第二阶段(MJPEG 预览)✓代码完成+审查全过+Release双编译0错+46单测绿,待真机出图;第三阶段(operate 完整接入+V-012)待拆** | 监控页跨进程 /status 显示完整✓;受护栏 /shutdown 安全停✓;/serial 让路✓;**D2-02 第一阶段(会话式借用+command分发+红线钳位+超时回收)27单测+真机冒烟全过(2026-06-23);第二阶段 MJPEG 实时预览(control MjpegStreamWriter+推流端点专用线程/operate MjpegFrameParser切帧+MjpegStreamClient解码+调试页View接入)子代理驱动+两阶段审查全过,46单测绿,12 commit 在 feature/d2-02-mjpeg-preview,待真机出图(归V-012);第三阶段 operate 2VM完整接入+真机V-012待拆,完成解锁D3-04** |
-| **阶段3** | 清理老壳 + 装机收尾 | 🟢 退役删ControlTest+部署文档+开机自启 已做;**D1-10 control oplog审计埋点已迁移+真机验证**;**D3-05 control崩溃看门狗已实现+真机验证(2026-06-23)**;**HIL硬件在环回归套件已入库+真机验证(2026-06-23)**;**配置收敛 已完成+真机验证(2026-06-23)**;删operate死栈延后 | 退役删 ivf_tl_ControlTest✓;双进程部署指南✓;开机自启✓;**D1-10 oplog审计迁移到control活栈✓**;**D3-05 看门狗(崩溃重拉/DPAPI凭据/可暂停停止卸载)✓**;**HIL套件 IvfTl.Hardware.HilTests(守护M-05帧长/M-06按well焦点/M-01-03 EEPROM写,门控Skip+默认零写入)✓**;**配置收敛(operate↔control连接组7键单一数据源tl-shared.config经<appSettings file=>合并读+operate删12换气CCD死键,真机改一处对称生效)✓**;ComBin删operate死栈(D3-04,被D2-02阻塞)仍延后 |
-
----
-
-## 阶段1 · 任务分解(详见 `开发计划/2026-06-22-阶段1-control独立进程骨架.md`)
-
-| 编号 | 任务 | 状态 | 验证方式 |
-|------|------|------|---------|
-| Task1 | 新建 ivf_tl_ControlHost 项目骨架 | ☑ | 编译0错 |
-| Task2 | HostArgs 命令行参数解析 | ☑ | xUnit 4过 |
-| Task3 | StatusDto + /ping 返回体 | ☑ | xUnit 2过 |
-| Task4 | 内嵌 HttpListener(/ping /status) | ☑ | 编译+真机/status |
-| Task5 | Program.cs 完整启动序(Mutex→参数→Login→盘→ScanDevices→StartRun→HTTP驻留) | ☑ | 编译0错+真机起 |
-| Task6 | operate 改为拉起独立 control(探活+Process.Start+轮询) | ☑ | Release编译0错+机制验证 |
-| Task7 | **[真机]** 端到端验证(能起/能连/operate关了续命/重开复用/单实例) | ☑ 真机闭环打通 | 独立起/HTTP/单实例/硬件获取/续命/采集自控环 全✓(修D1-08死锁后) |
-
-**真机门控**:Task7 由 Claude 自主完成(UAC `ConsentPromptBehaviorAdmin=0` 静默提权,无需用户配合起停进程/点击)。**采集闭环已打通**:D1-08 串口握手死锁(HAL借用ComBin重开端口不复活发送线程)已定位+修复+真机 red→green 验证(started:true/tlSn/温压门换气自控环运行),见 待验证清单 D1-07/D1-08 + 交接卡 2026-06-22 D1-08段。**剩**:operate端完整链路复测(需清僵尸20268/重启)+ D1-09 SQLite schema专项 + M-01~M-07 降级专项。
-
----
-
-## 执行方式
-
-子代理驱动开发(subagent-driven-development):每个 Task 派全新子代理实现 + 两阶段审查(spec 合规 → 代码质量),主线收结论。先在 feature 分支干 Task1-6(纯编码),Task7 真机验证(真机已连,由 Claude 自主跑完、无需用户在场/配合;仅「水平电机」「垂直 Z 电机」运动范围需守安全区间,参考 `临时文件/相关参数.html`)。
-
-提交边界 = 文档已同步(CLAUDE.md 第三节)。
-
----
-
-## 追加 · 2026-06-23 进展
-
-### D2-02 第一阶段(control 后端)= 🟢 代码完成 · ☑ 真机验证通过
-- Task0-9 全落地,**27 单测全绿**(含 C-1 非零起点红线回归),Debug/Release 0 错,11 个 commit 在 `feature/d2-02-debug-command-proxy`。
-- **真机完整冒烟过**:借真实舱6→读温 36.46℃/握手6→电机越界 HTTP400 实拒(不下发)→心跳/归还→超时14s自动回收。逐舱(2/4/6/7/8/9)读温均≈36℃健康。详见交接卡/待验证清单 2026-06-23。
-- 真机踩坑均已解(僵尸不挡 control / 登录真因=测试目录缺 tl-shared.config 致 BaseUrl 坏 / auth 库本零用户已插 admin/123456 可逆)。
-- 第二阶段(MJPEG 出图)、第三阶段(operate 接入 + V-012 电机真机走位)待拆。
-
-### D2-02 第二阶段(MJPEG 实时预览)= 🟢 代码完成 · ☑ 全过两阶段审查 + Release双编译0错 + 46单测绿 · ☐ 待真机出图
-- **7 编码任务全落地**(子代理驱动 + 每任务 spec合规审查 + 代码质量审查两阶段),12 commit 在 `feature/d2-02-mjpeg-preview`。spec/计划:`需求文档/specs/2026-06-24-D2-02-第二阶段-MJPEG实时预览-design.md` + `开发计划/2026-06-24-...-实现计划.md`。
-- **改面**:control 端 `MjpegStreamWriter`(RGB→JPEG+封帧纯逻辑)/`DebugSession.StreamBroken`+`DebugSessionManager.TryGet`(不动既有方法)/`ControlHttpServer` `/debug/preview/stream` 推流端点(专用后台线程,校验后 return 不阻塞 HttpListener,退出标记 StreamBroken 交心跳TTL回收);operate 端 `MjpegFrameParser`(切帧状态机5单测)/`MjpegStreamClient`(流式读+解码 BitmapImage Freeze+事件,不自动重连,一次性实例)/调试页 View 接入(OpenVideo/CloseVideo 改走 client+`<Image>`+断开提示,每次new实例+当值实例闸防残帧)/`ControlClient.BaseUrl` 提 public。
-- **验证**:control+operate Release 双编译 **0 错**;全量 **46 单测绿**(JPEG编码2+会话2+切帧5+第一阶段)。审查揪出的有价值问题均当轮修(判空/脆弱断言/null防御/Stop文案/MemoryStream/残帧竞态)。
-- **残=真机门控(归第三阶段V-012)**:预览出图需先 curl `/debug/acquire` 拿 sid 赋 vm.CurrentSessionId(第二阶段无UI赋值点)/真机出图/画面方向(倒置则推流层补Y翻转)/**★重点压测**预览中反复 release-回收同舱(use-after-free窗口,全局锁+HPCSE兜底)/关预览无残帧。详见交接卡 2026-06-24 段。
-- **可并 main**(代码+文档已对齐)。第三阶段(operate 2VM完整接入+真机V-012)待拆,届时预览接通+真机门控一并验,完成后解锁 D3-04。
-
-### 新加固专项 · 舱室故障隔离 + 双端故障提示 = 🟢 第一阶段代码完成 · ☑ 真机核心验证过(残留 H-07 物理注入)
-- spec + 实现计划 + **方案修正**(复用现有 `reportAlarm` 报警闭环,弃用群消息 reportCloudAlarm)均已落盘;分支 `feature/house-fault-isolation`(代码+文档 commit)。
-- **结论**:运行期单舱坏已隔离 ✓ 且已接现有报警闭环;**启动期缺口已修** ✓(只排坏舱、好舱继续、零可跑才中止)。
-- **代码 Task1-6 全完成**(37 单测绿):HouseFault/StartupFaultPolicy(纯TDD)→ SerialBin 6处登记 → InitTL 零可跑才中止 → InitHouse 逐舱兜底 → AppData 快照透出 Faults + ReportStartupFaults(走 `ReportAlarmController` 闭环)。
-- **真机核心验证过(2026-06-24,无活体培养)**:H-04 基线新 control(pid10360)无回归(`/status` Faults 空、好舱齐、started);H-05 reportAlarm 相机异常→`alarm` 表落 `PHOTO_STATE_ALARM`(闭环+排除舱能落库);H-06 插联系人→定时任务→阿里云短信,`alarm_send_info` 记"发送成功!"派发至 18223210384(到达由阿里云,用户自查)。测试数据已清理。
-- **残留 H-07**:物理拔相机USB 制造半坏舱(软件做不到,需物理/模拟);剔除决策已单测、登记点镜像现有错误位、基线+闭环已真机验。
-- **可并 main**。后续阶段:operate 监控页"舱故障"区(读 /status Faults)/ 运行期按需补去抖 / front 复用现有报警列表(H-05/06 已通)。
-
-### H-08 后续阶段 · operate 监控页"舱故障"区 = 🟢 代码完成 · ☑ 逻辑/契约验证(残 WPF像素 + H-07物理注入)
-- **范围**:H-08 拆两半——operate 监控页"舱故障"区(本步,读 /status `Faults`)+ front 报警列表(H-05/06 已通)。control 端 `Faults` 第一阶段已透出,本步**纯 operate 侧加展示,不碰 control**。
-- **改 3 文件**:① 新增 `ViewModel/ServiceMonitorFaultMapper.cs`(纯静态、不依赖 WPF/control:`FaultTypeZh` 8 枚举名→中文 + 未知码原样、`HouseText`、`AtText` UTC→本地、`IsolatedText`);② `ViewModel/ServiceMonitorViewModel.cs` 加 `Faults` 集合 + 汇总(`HasFaults/FaultSummaryText/FaultSummaryBrush`)+ 显隐(`FaultListVisibility/NoFaultVisibility` 直给 Visibility,不用未注册的布尔转换器)+ `BuildFaultRows` + `HouseFaultRowVm`;③ `View/ServiceMonitorView.xaml` 在"舱室状态"与"受护栏停止"间插红色故障区(无故障显绿条 / 有故障逐条红底:舱号/类型/原因/阶段/时间/隔离态)。
-- **验证 3 层**(operate WPF 外壳受僵尸 20268 占 Mutex 阻塞,同 D2-01 粒度):① operate Release 编译 **0 错**(XAML→BAML = 绑定路径/属性/语法全对);② curl 在跑 control pid10360 `/status` → `Faults` 字段透出=True、基线空数组、字段名匹配 operate 反序列化目标;③ 映射 harness `临时文件/FaultMapperTest`(Compile Include 真实 mapper 源码,零依赖)**14 检查全过**(8 枚举名中文化 + 未知码兜底 + 舱号边界 + UTC 01:30→本地 09:30 东八区+8 + 隔离布尔)。
-- **残**:WPF 像素渲染待清僵尸真重启复测;"有故障"端到端无法软件注入启动故障(=H-07 物理拔相机门控)。
-- **下一步**:代码+文档一起提交;后续清僵尸真重启 + H-07 物理注入复测红区,或推进 D2-02 二/三阶段。

+ 0 - 149
项目文档/进度/待验证清单.md

@@ -1,149 +0,0 @@
-# 待验证清单 · operate/control 双进程拆分
-
-> 续接载体之一。真机/运行期门控项,每验一条回写状态 + 进度状态.yaml + 交接卡 + 进度数据.js。
-> 状态:☐ 未验 / ☑ 已验通过 / ✗ 验证失败。新任务(2026-06-22)重列。
-> 红线:真机已连,所有测试/调试/验证由 Claude 自主跑完(UAC 静默提权,无需用户在场/中途配合)。下位机均有可读默认值(项目内有读默认值的方法);唯一需守安全区间的是「水平电机(皿孔旋转)」与「垂直 Z 电机(对焦)」的运动范围,参考 `临时文件/相关参数.html`(用户自测值,仅供参考,实际安全范围比文档更宽):水平钳位 [0,220000](实测 well 位 70800~205800)、垂直 Z 钳位 [0,125000](实测焦面 86000~92000)。除这两轴运动范围外,其余下位机控制无任何风险。
-
----
-
-## 阶段1 · control 独立进程骨架
-
-| 编号 | 验证项 | 门控 | 状态 |
-|------|--------|------|------|
-| D1-01 | operate 启动后能拉起独立 `ivf_tl_ControlHost.exe`(管理员静默,不弹 UAC) | 运行 | ☑ 真外壳实跑 |
-| D1-02 | `http://127.0.0.1:38080/ping`、`/status` 返回 JSON | 运行 | ☑ |
-| D1-03 | control 独立进程真机硬件获取(6相机SN读到/7 COM口 True) | **真机** | ☑ |
-| D1-04 | **operate 关闭后 control 进程仍在驱动**(核心目标) | 运行 | ☑ 真外壳实跑 |
-| D1-05 | 重开 operate 复用已在跑的 control(不重复拉起) | 运行 | ☑ 真实代码实跑 |
-| D1-06 | 单实例:手动起第二个 control 发现 Mutex 已占自退(进程数仍为1) | 运行 | ☑ |
-| D1-07 | **control 完整采集闭环 + 数据入库(started:true / 真机自控环 / 落库)** | **真机** | ☑(修死锁后·DB实证) |
-| D1-08 | **serialBin/HAL 借用ComBin重开不复活发送线程致串口握手死锁** 修复 | **真机** | ☑ 已修复并真机验证 |
-| D1-09 | control 本地 SQLite 建表/schema 缺口(AUTOINCREMENT + 多表缺列) | 运行 | ☑ 已修复并真机验证 |
-| D1-10 | control 硬件操作进 operation_log(审计埋点迁移到 control 活栈) | **真机** | ☑ 已修复并真机验证(2026-06-23) |
-
-> **2026-06-22 真机验证实测说明(D1-xx 详情见交接卡同日段)**:
-> - **D1-01/D1-05 真实代码实跑(非机制层)**:编译运行 operate 端真实 `ControlProcessLauncher.EnsureRunning`(集成测试 harness `临时文件/LauncherTest`,`<Compile Include>` 链入真文件):① control 未运行时 `IsControlAlive=False → 已拉起 control.exe → 轮询就绪 → True`(拉起路径);② control 已运行时 `IsControlAlive=True → "已在运行,直接连接" → True、PID 不变、进程数恒 1`(复用路径)。harness(operate 代理)退出后 control 仍在 = **续命**亦由真实拉起路径实证。**唯一未跑** = operate WPF 外壳(登录窗→MainWindow),因僵尸 20268 占 operate 单实例 Mutex,但其调用的拉起逻辑已实跑验证。
-> - **D1-07 数据入库闭环 DB 实证**:control 运行期(20:19 起)直查 108 `aivfo_tl_setting` 库:`house_collect` 20:18 后新增 22 行、`alarm_data` 新增 270 行;抽样实读:`house_collect` = `tl_sn=NEO-1-20230411, house_sn=2..9, temperature=37.16/37.46℃(真实箱体温), 多点温度, house_door=0, create_by=admin_admin, create_time=20:29`;`alarm_data` = `house_sn=11 PRESS alarm`(control 自主检测缓冲瓶低压上报)。**闭环:control 读真机传感器 → MQTT/服务器 → 108 库入库,实锤。**
-> - ☑ 项均 108 集群在线 + 真机连接、Claude **UAC 静默提权**自主完成,全程无需用户配合点击/起停进程。死锁修复同样惠及 operate(同 ScanDevices→serialBin 路径)。
-> - **D1-09 ☑ 已修复(2026-06-22)**:控制端本地 SQLite 两类缺口已修——① `HouseAutofocusCalibrationDB.id` `long→int`(SQLite AUTOINCREMENT 只允许 INTEGER PRIMARY KEY,long→BIGINT 报错致 InitTables 建表失败);② `DBService.StartDbService` 对 control 本地写的 9 个实体逐个 `CodeFirst.InitTables` 自愈 schema(打包 aivfoTL.db 落后于实体,缺 `localAutofocusEnabled` 等列致 `no such column`)。真机验证:修复后 control 启动 **DbException 条数=0**(此前每启动报 AUTOINCREMENT + 多表 no such column),started:true 正常驱动,6 单测过。
-> - ✗ **D1-10 oplog 缺口(归阶段3,非闭环阻塞)**:核查发现全 `OperationLogger` 埋点都在 **operate 侧**(ivf_tl_Operate + operate 的 ivf_tl_Services/HttpHelper + operate 的 ivf_tl_Entity 的 Camera/ComBin),**control 子树零埋点**。control 硬件操作的 oplog 收口本就挂在 operate 的**另一套 ComBin/Camera 栈**(=阶段3 "ComBin 两套栈去重 G1-2")——故给 ControlHost 单加 `InitOperationLog` 也不会产 oplog(control 自己串口栈无埋点)。归阶段3 两栈去重一并处理。control 诊断走 `RunRecord/HouseComRecord` 文件日志(本次定位全程靠它),业务数据入库走 MQTT,**闭环不受影响**。
-> - 旁注:`ServiceDishAndBalanceData 接口返回失败`=无皿时服务器无培养记录、回退本地,正常非缺陷。
-
-> **2026-06-23 D1-10 ☑ 已修复并真机验证(control 侧 oplog 审计埋点迁移)**:
-> - **缺口**:拆分后真正驱动硬件的是 control,但 control 子树**零 OperationLogger 埋点**(埋点都在 operate 已不驱动硬件的另一套 ComBin/Camera 死栈)→ 设备对培养环境的真实物理动作**审计缺失**(医疗合规级)。与 D3-04"删 operate 死栈"**解耦**:本轮只做**新增审计埋点**(纯加、不改串口字节/时序、不碰电机),删死栈仍属 D3-04 延后。
-> - **改动(8 改 + 1 新增,纯新增埋点)**:① 4 个 control 程序集(ControlHost/ivf_tl_Com/ivf_tl_CameraHelper/IvfTl.Hardware)加 `Aivfo.OperationLog` ProjectReference;② `ControlHost/Program.cs` 加 `InitControlOperationLog`(Project=**control**,Kafka 取 App.config kfkaIP/kfkaPort,topic=tl-oplog,ConfigFilePath=exe 同目录 oplog-config.json 热加载)+ 生命周期审计(进程启动/采集启动成功/安全停机)+ 停机 flush;③ `Camera.cs` Init/UnInit 边界埋点(镜像 operate 已验 P3b,module=相机);④ `HouseBin.cs` 换气(AirSwapOldFun)/补气(AerationNew)业务动作埋点(每会话一行,**远离串口字节循环**,module=换气/补气);⑤ `SerialChannelImpl.cs` 5 个 EEPROM 写埋点(写排气阀/进气阀/灯光/扫描间隔/水平well位置,日志置 `_ioLock` 外,module=写EEPROM);⑥ 新增 `ivf_tl_ControlHost/oplog-config.json`(随 exe 部署,按模块开关)。全部 `try{}catch{}` 兜底,绝不抛进采集循环。
-> - **真机 red→green(108 oplog 管道在线)**:RED 基线 `operation_log` `project=control`=**0**(operate=883,证管道通);改后提权启动 control(pid=6488,tlSn=NEO-1-20230411,started:true,MQTT 连、舱7/9 真温 37℃)→ GREEN:`project=control` 出现 **70 行**——`生命周期`(进程启动/采集启动成功 `{"started":true}`/安全停机,flush 在退出前落库)+ `相机`68 行(结构化 `input={"index":5,"width":1600,"height":1200,"exposure":400}` `output={"result":0}`)。`/shutdown` 口令 tl13579 安全停机产"安全停机"行 + 7 COM 口释放。oplog-error 日志仅"配置已热加载"无错。
-> - **未在本窗口触发(非缺陷,机制已证)**:换气/补气/写EEPROM 埋点已编译验证 + 用与相机**同一已证 OperationLogger.Log 机制**,但 `HouseBin:670` 注释"舱有培养记录才换气/拍照/对焦"——当前**无皿空闲态**不触发换气循环,写EEPROM 需调试页接通(D2-02);放皿培养 / 调试接通时即产行。
-> - **核实**:RED(control=0)/GREEN(control=70,生命周期+相机)真机直查 108 库;control sln(ControlHost)+ operate Release **双编译 0 错**;既有 40 单测过;codegraph sync 已跑;harness 在 gitignore `临时文件/`。
-
-## 阶段2 · 监控补全 + 调试借串口 + 受护栏停止
-
-| 编号 | 验证项 | 门控 | 状态 |
-|------|--------|------|------|
-| D2-01 | 监控页跨进程显示完整(/status 三块:活动/阀态/借用让路 + 心跳/磁盘/链路) | 运行 | ☑ 真机验证 |
-| D2-02 | 调试借串口:control 让路(暂停该舱采集)→ 恢复(原 V-012) | **真机** | ◑ 让路契约已验/调试页完整驱动=大改面待设计(D3-04 删死栈被其阻塞,见交接卡 2026-06-23 评估段) |
-| D2-04 | **[MJPEG]** 预览真机出图:先 curl /debug/acquire 拿 sid 赋 vm.CurrentSessionId → 开预览 → operate `<Image>` 看到该舱实时画面 | **真机** | ☐ 代码完成待验(归 V-012/第三阶段;第二阶段无 UI 赋 sid 点;**★第二阶段无心跳,开预览后须 curl 每5s打 /debug/heartbeat 续命,否则 TTL 10s 会话超时回收致预览自断——非bug,心跳归第三阶段**) |
-| D2-05 | **[MJPEG]** 画面方向:旧 SaveBmpPic 有 RotateNoneFlipY(buffer 或 bottom-up),确认预览不倒置;倒置则推流层(抓帧后)补 Y 翻转 | **真机** | ☐ 待验 |
-| D2-06 | **[MJPEG·★重点压测]** 预览中反复 release/超时回收同舱:推流抓帧 vs 回收 Dispose 相机 use-after-free 窗口(底层 UnInit 不置 IsStart=false,IsStart 护栏拦不住已 Dispose 相机),全局相机锁串行+native HPCSE 兜底,确认 control 不偶发崩溃 | **真机** | ☐ 待压测(崩则底层 Camera.UnInit 补置 IsStart=false) |
-| D2-07 | **[MJPEG]** 崩溃自愈+关预览无残帧:断预览/杀 operate→推流线程自停标记 StreamBroken→心跳TTL看门狗回收→该舱采集恢复(/status反映);关预览画面立即清空不闪残帧(已代码根治当值实例闸) | **真机** | ☐ 待验 |
-| D2-08 | **[MJPEG]** 相机锁冲突实测:A 舱预览 + B 舱采集拍照同时,观察拍照节拍/预览帧率实际影响(本轮不优化,真机看表现) | **真机** | ☐ 待验 |
-| D2-03 | 受护栏停止(二次确认+工程师口令)能安全停 control | 运行 | ☑ 真机验证 |
-
-> **2026-06-22 阶段2 实测说明(详见交接卡同日段)**:
-> - **D2-01 ☑**:control 端 `/status` 返回完整 `MonitorSnapshot`(补 §6 三块:`WorkingType/ValveState/CapturePausedByGate`);operate 端 `ControlClient.GetStatusSnapshot()`(harness 实跑真代码)往返反序列化 10 舱、真温 37℃、三块字段正确;`ServiceMonitorViewModel.Refresh` 已由"同进程 AppData"改为 HTTP /status;监控页 XAML 加三列。
-> - **D2-03 ☑**:`/shutdown` 错口令→403 拒绝、对口令 `tl13579`→200 安全停机(`HAL.ShutdownAll` 关硬件 + 进程退出 + 7 COM 口全释放,非僵尸);operate 端 `ShutdownControlCommand`(二次确认+`Microsoft.VisualBasic.InputBox` 口令)+ 监控页受护栏按钮。
-> - **D2-02 ◑**:`/serial/pause {houseSn}` 实测——舱2 `CapturePausedByGate=true` 且 COM4 串口停发(control 让路,**不驱动电机**)→ `/serial/resume` 恢复;operate `ControlClient.SerialPause/Resume` 验证生效。**但调试页完整借串口驱动在拆分下断链**:debug 页原 `gate.Acquire` 借**同进程 HAL 同一物理句柄**(`HouseDebugPageViewModel:256`),拆分后 operate 进程 HAL 是空单例、拿不到 control 持有的串口——需 **control 暴露串口/相机命令代理**(当前设计文档未细化的大改面)+ 驱动电机受安全红线门控(设计 §178 需用户在场)。让路契约(/serial/pause|resume)已就位作基础,调试页完整驱动列独立子任务(需设计+受监督真机验)。
-
-## 阶段3 · 清理老壳 + 装机收尾
-
-| 编号 | 验证项 | 门控 | 状态 |
-|------|--------|------|------|
-| D3-01 | 退役删 ivf_tl_ControlTest 后 control sln / operate 仍编译正常 | 编译 | ☑ 已删+两编译0错 |
-| D3-02 | operate 开机自启(注册表 Run),开机自动起 operate→拉起 control | 运行 | ◑ 注册表方案已验/整机开机自启复测需重启 |
-| D3-03 | 全新部署一次到位(两 exe + control 子目录 + 端口 + DependFile) | 部署 | ☑ 部署布局已验(operate E2E 即用 control/ 子目录拉起) |
-| D3-04 | ComBin 两套栈去重(G1-2,含 D1-10 oplog) | 编译+运行 | ✗ 延后专项(有风险删除,被 D2-02 阻塞) |
-| D3-05 | control 崩溃看门狗(独立进程探活+崩溃重拉,DPAPI 缓存凭据,可暂停/停止/卸载) | **真机** | ☑ 已实现并真机验证(2026-06-23,5 项全过) |
-
-> **2026-06-22 阶段3 实测说明(详见交接卡同日段)**:
-> - **D3-01 ☑**:`ivf_tl_ControlTest`(ControlMain 老壳)从 `control/ivf_tl_Control.sln` 移除并删目录;control sln 重编 0 错误、operate 编译 0 错误(operate 仅 `SettingPageView:392` 字符串引用旧进程名 `ivf_tl_ControlMain`=死代码,无类型依赖,随调试页借串口改造一并清)。
-> - **D3-02 ◑**:开机自启注册表 Run 键方案已实测(创建→读回→删除往返成功);整机"重启→自动起 operate→拉起 control"需真重启复测。部署步骤见 `开发环境/双进程部署指南.md §三`。
-> - **D3-03 ☑**:部署布局(operate 目录 + `control/` 子目录,control 自带 dll.config + DependFile)已在 operate WPF 真外壳 E2E 实证(operate 即从 `control/ivf_tl_ControlHost.exe` 拉起 control)。部署指南 `开发环境/双进程部署指南.md`。
-> - **D3-04 ✗ 延后**:operate(`ivf_tl_Entity/ComEntitys/ComBin`,带 OperationLogger 埋点)与 control(`ivf_tl_SerialHelper/ComBin`,真驱动硬件)两套串口栈。拆分后 operate 已不驱动串口→operate 那套栈成运行期死代码;control 操作不进 operation_log(oplog 埋点在 operate 栈,=D1-10)。去重=动串口代码的有风险重构,属收尾清理不阻塞功能,列延后专项(需设计 oplog 收口归属 + 受控验证)。
-
-> **2026-06-23 D3-05 ☑ control 崩溃看门狗已实现并真机验证(TDD + 5 项真机)**:
-> - **背景/缺口**:operate→control 只一次性拉起(`MainWindow_Loaded` 登录后跑一次 `EnsureRunning`,之后不再探活);control 自己崩溃后无人重拉,尤其 operate 关闭后 control 独立崩溃 = 直接培养中断。补独立看门狗常驻探活+崩溃重拉。
-> - **实现(新增 3 工程 + control 2 处小改,纯新增不动采集/电机)**:`ivf_tl_Watchdog.Core`(WatchdogArgs/RelaunchDecision/WatchdogPaths/CredentialStore 纯逻辑)+ `ivf_tl_Watchdog`(WinExe/requireAdmin:单实例 Mutex + 探活循环 + 崩溃重拉 + 退避 + CLI)+ `ivf_tl_Watchdog.Tests`;ControlHost `Program.cs`:Login 成功 DPAPI 缓存凭据 + 清 control.stopped 标记、SafeShutdown 写 control.stopped 标记。
-> - **TDD red→green(17 单测)**:WatchdogArgs.Parse(各 flag)、RelaunchDecision.ShouldRelaunch(真值表:仅"不在+未暂停+非故意停+非退避"才重拉)、CredentialStore DPAPI 往返(写后读==原值、密文不含明文)。先 RED(NotImplemented 17 失败)→ GREEN(17 全过)。
-> - **真机验证 5 项全过(UAC 静默提权,无活体培养可自由启停)**:① **凭据缓存**:control 登录后 `creds.dat`=246 字节 DPAPI 密文,admin/123456 明文均不泄露;② **崩溃重拉(核心)**:control 跑(pidA)→提权 taskkill 杀→看门狗日志"control 探活失败→已重拉 control.exe"→新 pidB、started:true 续命;③ **故意停不重拉**:`/shutdown` 口令 tl13579→写 control.stopped→看门狗连续"为故意停机,不重拉",control 保持停止;④ **暂停让路**:`--pause`→杀 control→不重拉→`--resume`→重拉恢复;⑤ **卸载干净**:`--install`写自启项→`--uninstall`删自启项+常驻看门狗优雅退出(进程数 0)。
-> - **真机踩坑(已定位+写入部署指南)**:首次手工部署只拷 exe+dll、漏 `ivf_tl_Watchdog.deps.json` + `runtimes/win/lib/.../ProtectedData.dll`→看门狗加载非 Windows 占位 DPAPI→`PlatformNotSupportedException`、Load 返回 null 无法重拉。补全 deps.json+runtimes 后即正常。**部署必拷 watchdog 全目录**(部署指南 §一 已写红线 + §六 看门狗专章)。
-> - **核实**:17 单测真跑 red→green;5 项真机实测(日志/进程/注册表/creds.dat 字节实查);control sln + operate Release 双编译 0 错;SerialHelper 40 单测仍过;临时 harness 在 gitignore `临时文件/`。
-
-## 合并遗留 · operate 侧降级 / 待验证(与双进程拆分并行存在)
-
-> 来源:2026-06-22 复核评审逐条源码坐实;详见 `需求文档/操作端逻辑与配置全景.md` §八。
-> 这些是"三项目合并"阶段**做了一半、未真机验收**的功能缺口——合并代码完成 ≠ 业务闭环。
-> 状态:☐ 未验 / ☑ 已验通过 / ✗ 验证失败 / ▼ 已知降级未接通。
-> 根因统一:`ivf_tl_operate_2.0/control/IvfTl.Hardware/Impl/SerialChannelImpl.cs`(control 端 Commander 缺 builder)。
-
-| 编号 | 验证项 | 现状(file:line) | 门控 | 状态 |
-|------|--------|------|------|------|
-| M-01 | 舱室排气阀时间**写** EEPROM 真下发下位机 | `SerialChannelImpl.cs:130` 已去桩→调 `_com.WriteEEPROOpenVentTimeWait`(control 补 builder,地址 00 03 08,与 operate 逐字节一致) | **真机** | ☑ 已验通过 |
-| M-02 | 舱室排气阀时间**读** 真读下位机 | `SerialChannelImpl.cs:137` 已去桩→调 `_com.ReadEEPROMVentWait`(control 补 builder/Wait,地址 00 03 08) | **真机** | ☑ 已验通过 |
-| M-03 | 缓冲瓶灯光亮度**写** EEPROM 真下发 | `SerialChannelImpl.cs:143` 已去桩→调 `_com.WriteEEPROMLightNumWait`(control 补 builder,地址 00 05 34) | **真机** | ☑ 已验通过 |
-| M-04 | 调试页存图与基准一致 | **代码层已定论等价**:`CameraImpl.SavePic(name,w,h)` 忽略 w/h 转发 `Camera.SaveBmpPic(name)`,后者=24bpp + 相机原生尺寸(this.width/height,与基线传的 ccdWidth/ccdHeight 同) + `RotateNoneFlipY` + 按扩展名存。朝向逻辑与**权威 af `ImageConverter`逐字一致**(af 明文 Y翻转=全系统显示/存图/算分的正确朝向)→ 忽略入参 w/h 是正确(缓冲就是原生尺寸)。stride:width=1600(MVC2000),1600*3=4800 四字节对齐 → 整块 Marshal.Copy 无错行。与不透明 native 厂商 `MVCAPI.SavePic` 的逐字节一致既不可能(不同编码器)也无必要(调试产物) | **代码** | ☑ 代码核查等价(24bpp/原生尺寸/canonical Y翻转,stride安全) |
-| M-05 | 写 EEPROM 类"成功=true"可靠性 | **帧错位根因=合并回归已修复**:control `CustomProtocolLength` 对 0x12 写E方回包帧长误设 6(基线 operate=12),真机实证回包确为 12(舱8/舱9 一致,回包[3]=0x0C 自证)→ 改 control 帧长表 0x12→12(Commander.cs:76)。残留:`Write*Wait` 仍"收回复即 return"不把状态字传回调用方(非回归,基线同) | **真机** | ☑ 帧错位已修复并真机验证(残留"成功语义传播"非回归) |
-| M-06 | `ReadWellFocusZero` 按 well 区分 | **已修复并真机验证**:`ComBin.ReadEEPROMvertMtStartPulseWait` 加 `well` 参(默认1,SerialBin 舱级读不变)、`SerialChannelImpl.ReadWellFocusZeroWait` 传真 well;builder 早支持 case 1-16(地址 0x08+4*(well-1))。集成层 red→green:经真实 SerialChannelImpl 各 well,修前全返回 well-1(舱9恒80200/舱8恒74600)→ 修后 per-well 各异(舱9 3值/舱8 5值,与 raw 诊断逐 well 吻合)。**对电机零影响**:消费方 CalibrationEngine 粗对焦用固定中心90000、eepromZ 实际未参与 Z 定位、且所有 Z 移动恒 ClampZ[0,125000] | **真机** | ☑ 已修复并真机验证(纯只读,无电机影响) |
-| M-07 | Release 连内网网关(非测试外网) | ✅ **已验证**:Release 排除 `#if DEBUG`(其 :108 行覆写到 test-gateway 外网);部署 `App.config` `outInter=0`(不触发 :87 外网覆写)+ `urlIp=http://127.0.0.1`+`urlPort=10010`→ BaseUrl=内网网关。已由阶段1 operate WPF 真外壳 Release E2E 真服务器登录成功 + control 10010 ESTABLISHED 坐实。现场换站点改 `urlIp` 即可 | 部署 | ☑ 已验通过 |
-
-> **2026-06-23 HIL 硬件在环回归套件入库 ☑(防 M-01/02/03/05/06 回归)**:新增入库 xUnit 工程 `ivf_tl_operate_2.0/control/IvfTl.Hardware.HilTests`(经真实 `SerialChannelImpl` 端到端),把上述 M 区真机检查固化为可重复回归用例,替代 gitignore 里跑完即弃的临时 harness。门控:`HardwareRigFixture` 扫口握手收响应真舱,`[SkippableFact]` 在无真舱/control 占口时 Skip 而非 Fail(常规 dotnet test/CI 永绿),禁并行串行跑。覆盖:`FocusZeroHilTests`(M-06 按 well 去重>1+安全Z区间)/`FrameLengthHilTests`(M-05 连读12轮全干净)纯读始终跑;`EepromWriteHilTests`(M-01/02/03 写回环)默认 Skip、`HIL_ALLOW_WRITE=1` 才跑、逐舱取证、写后立即恢复原值(默认零写入)。真机验证:零写入 2过2跳;开写开关 4/4 全过(排气阀舱9 200→201→200、灯光逐舱落舱8 500→501→500,与原 harness 证据一致;去重>1 与 raw 抓包诊断吻合)。详见 `需求文档/specs/2026-06-23-HIL硬件在环回归套件-design.md`。
-
-> **2026-06-23 M-01/M-02/M-03 ☑ 已修复并真机验证(TDD)**:
-> - **根因**:合并阶段 control 端 Commander 缺 3 个 E方 builder(`CreateWriteEEPROOpenVentTimeCommand`/`CreateReadEEPROMVentNum`/`CreateWriteEEPROMLightNum`),`SerialChannelImpl` 对应方法返回桩值(false/-1),写排气阀时间/读排气阀时间/写灯光亮度未真正下发下位机。
-> - **TDD red→green**:新建 `ivf_tl_SerialHelper.Tests`(net6.0 xUnit,已入 control sln),对 3 个 builder 断言精确字节(期望=合并前 operate 同名方法黄金真值,末位 CreateORC 校验);先 RED(方法不存在 CS1061),补 builder 后 **4 单测全绿**(含"写排气阀 vs 写进气阀仅地址低字节 0x08/0x0c 不同"交叉校验)。
-> - **接线**:control `Enums` 补 3 枚举;`ComBin` 补 `WriteEEPROOpenVentTimeWait`/`ReadEEPROMVentWait`/`WriteEEPROMLightNumWait`(镜像既有 intake/light 模式);`SerialChannelImpl` 三方法去桩调真实方法;operate 消费方(`HouseDebugPageViewModel.WriteOpenVentTime/RedVentTime`、`BufferDebugViewModel.writeL`)注释/提示同步更新。control sln + operate Release 双编译 0 错。
-> - **真机验证(非破坏性回环,经真实 SerialChannelImpl 端到端,EEPROM 读写无电机风险)**:读 V→写 V+1→读确认=V+1→写回 V→读确认=V。**舱9 排气阀** 200→201→200 ✓、**舱8 排气阀** 90→91→90 ✓(M-01 写/M-02 读)、**舱8 灯光** 500→501→500 ✓(M-03 写)。写入值真机读回随之变化且已恢复原值→写命令字节正确、真下发下位机。
-> - **旁注**:无排空时"写后紧接读"偶现垃圾值/null=0x12 写回包长度与 0x11 读不同致帧错位(=既有 **M-05** 可靠性问题,非本次新命令字节错误——字节错则干净回环不可能出现写入值);加读前丢弃一帧+间隔后 100% 干净。M-05 帧错位/写成功判定列后续专项。
-
-> **2026-06-23 M-05 ☑ 帧错位根因(合并回归)已修复并真机实证(TDD)**:
-> - **订正定性**:上轮把 M-05 整体记为"非回归"。逐字节复核发现其中"帧错位"那半是**真实合并回归**:control `ivf_tl_SerialHelper/Util/Commander.cs CustomProtocolLength` 对 **0x12 写E方回包帧长**设成 6,而合并前 operate 基线(`ivf_tl_Entity/ComEntitys/Commander.cs`,真机写过 EEPROM)=12;autofocustool `Protocol.ReplyLength` 也写 6 但**它根本没有 0x12 写命令**(抄来的未验证默认值)。三方分歧 → 真机实测定论。
-> - **真机 raw 抓包实证(裸 SerialPort 9600 8N1,DataReceived 事件收包,整窗累加计数)**:0x12 写排气阀回包 **舱9=12 字节** `5E 92 09 0C C8 00 00 00 00 CA 00 97`、**舱8=12 字节** `5E 92 08 0C 5A 00 00 00 00 5B 00 B9`(回包自带长度字段 `[3]=0x0C=12` 自证;状态字 `[10]=0x00`、ORC `[11]`)。校准:0x11 读回 10、握手回 6、0x10 读门回 **7**(舱8/舱9 一致,`[3]=0x07` 自证;control 默认 6——但磁盘上 control 帧长表已含 0x08=9/0x10=7,实测确认其正确,唯 0x12 错)。
-> - **根因机理**:control 只读前 6 字节 → 把数据字节 `[4]=0xC8` 误当状态字(非0→误判"下位机操作失败")、ORC 校验错位,且残留 6 字节 `00 00 00 CA 00 97` 污染紧接的下一次读(=M-01/02/03 验证时"写后读垃圾值/null"现象的真正根因,此前用"丢弃一帧+700ms间隔"掩盖)。
-> - **TDD red→green**:新增 `ivf_tl_SerialHelper.Tests/CustomProtocolLengthTests.cs`(18 测试:0x12=12/0x10=7/0x08=9 三焦点 + 整表 14 项逐项对齐 operate 基线 Theory + 未知码回退6)。先 RED(0x12 实得 6,2 处失败:[Fact] + Theory 行),改 `Commander.cs:76` 0x12→12 后 **22 单测全绿**(含既有 4 个 M-01/02/03)。
-> - **真机修复验证(紧凑写→立即读,无丢帧 workaround)**:经真实 `SerialChannelImpl`,连续多轮"写原值→立即读"——舱9(V0=200)12 轮、舱8(V0=90)12 轮,**24/24 全干净**(读回精确=写入值,无 -1/垃圾);旧码此处必污染。回归 M-01/02/03 三条仍 PASS。control sln + operate Release 双编译 0 错。
-> - **残留(非回归,未做)**:`Write*Wait` 仍"收回复即 return",未把已落到正确位置 `[10]` 的状态字作为 bool 成功传回调用方——属"成功语义传播",基线 operate 同样无条件 true,非合并回归,列后续按需。
-
----
-
-## D2-02 调试页命令代理 · 第一阶段(control 后端) — 2026-06-23【真机全过】
-
-> control 后端 27 单测全绿 + 真机完整冒烟过。详见交接卡 2026-06-23 真机段。环境踩坑(僵尸/登录/配置)均已解,见下。
-
-| 编号 | 验证项 | 门控 | 状态 |
-|------|--------|------|------|
-| D2-02a | 27 control 单测全绿(会话/超时回收/分发/红线钳位含 C-1 非零起点回归) | 单测 | ☑ |
-| D2-02b | control 带账号起→登录→ScanDevices 发现 2/4/6/7/8/9/11→/debug 通真串口 | **真机** | ☑ |
-| D2-02c | `/debug/acquire` 借真实舱6→真 sid、`ReadTemp=36.46℃`、`ShakeHands=6` | **真机** | ☑ |
-| D2-02d | **红线**:`VerticalMoveTo 130000`/`HorizontalMoveTo 300000`→HTTP400 OUT_OF_RANGE **不下发** | **真机** | ☑ |
-| D2-02e | heartbeat 续约 / release 归还(旧sid 410) / 再借不发心跳 **14s 超时自动回收(sid2 410)** | **真机** | ☑ |
-| D2-02f | 逐舱(2/4/6/7/8/9)借用读温均≈36℃健康、握手正常 | **真机** | ☑ |
-
-> **真机踩坑(均已解,记录备查)**:① 僵尸 operate 20268 杀不掉(需真重启,但不占串口/Mutex,不挡 control)。② control 登录卡点真因=从原始构建目录跑、`..\tl-shared.config` 缺失致 BaseUrl 拼坏(**非凭据**);修=copy `tl-shared.config` 到 `bin/Release/`。③ auth 库本零用户,按用户要求插 `admin/123456`(`md5(盐+pwd+盐)`,`deleted='2017-01-01'` 哨兵,JDBC 直插,可逆),直连登录接口验 success+token。
-> **第二阶段(MJPEG 出图)/第三阶段(operate 接入 + V-012 电机真机走位)仍待做**——电机真机走位(红线两轴守安全区间)、operate 崩溃后 control 自动回收恢复采集,放第三阶段。
-
-## 加固专项 · 舱室故障隔离 + 双端故障提示 — 2026-06-24 第一阶段代码完成 + 真机核心验证
-
-> spec + 实现计划 + 方案修正(复用现有 reportAlarm 报警闭环)。第一阶段代码 Task1-6 全完成(8 commit 在 `feature/house-fault-isolation`,37 单测绿)。真机已验基线+闭环,详见交接卡 2026-06-24。
-
-| 编号 | 验证项 | 门控 | 状态 |
-|------|--------|------|------|
-| H-01 | **现状**:运行期单舱坏已隔离(每舱独立线程+循环try-catch,别舱无感) | 分析 | ☑ 源码核实 |
-| H-02 | **缺口**:启动期舱"半坏"进 errorlist→InitTL 整体中止,好舱也起不来 | 分析 | ☑ 源码核实(StartMain.cs:89 等) |
-| H-03 | 坏舱剔除/致命判定纯逻辑 + 6 处结构化登记 + InitHouse 逐舱兜底 | 单测 | ☑ 37 单测全绿 |
-| H-04 | **基线(无回归)**:新代码真机起 control→`/status` 新增 `Faults` 字段为空、好舱 2/4/6/7/8/9 照常连接≈37℃、started=true | **真机** | ☑ 2026-06-24(pid10360) |
-| H-05 | **告警闭环落库**:`reportAlarm`(相机异常 photoState=1,即 ReportStartupFaults 发的)→报警链→`alarm` 表落 `PHOTO_STATE_ALARM`(舱2/舱4)。证实复用现有闭环、被排除舱(配置舱1-10)能落库 | **真机** | ☑ 2026-06-24 |
-| H-06 | **通知触发(短信)**:插联系人→1min 定时任务对在报告警→`getPersonList`→调阿里云短信→`alarm_send_info` 记 `发送成功!`(短信 alarm_model=0,号 18223210384)。短信电话通知链路打通(走 reportAlarm 闭环内置) | **真机** | ☑ 已派发(到达由阿里云,用户自查手机) |
-| H-07 | 启动期**物理半坏舱**(拔相机USB)→SerialBin 实产 CcdSnMissing→该舱排除、好舱继续 | **真机** | ☐ 残留(需物理拔相机,软件做不到;剔除决策已单测+登记点镜像现有错误位) |
-| H-08 | 双端展示:operate 监控页"舱故障"区(读 /status Faults)/ front 报警列表(读 alarm 表) | **真机** | ◑ operate 区**代码完成+逻辑/契约验证**(编译0错/curl /status Faults契约/映射harness 14检查全过);front 半已通(H-05/06)。残:WPF像素渲染待清僵尸重启、有故障端到端待H-07物理注入 |
-
-> **真机环境(2026-06-24)**:旧 control 15840 经 `/shutdown`(tl13579)干净停;新建 Release 起 pid10360(从 `ivf_tl_ControlHost/bin/Release/net6.0-windows/`,`..\tl-shared.config` 在 bin/Release);无活体培养(空闲监测),重启安全。测试数据(假 PHOTO 告警×2 / 发送记录 / 测试联系人)**已全部清理**。新 control 保留运行(健康、无回归;本特性分支构建未并 main)。
-> **告警通道核实结论**:`reportAlarm`→报警责任链→`alarm` 表→front 报警列表 + operate"系统异常(N)" + **短信/电话通知**(报警链内置 getNotifier)+ 静音/消警 = 完整闭环;状态码 0正常/1异常/-1跳过。**弃用** `reportCloudAlarm`(只发 IM 群消息、不入闭环)及新建告警类型——无 Java 字典登记依赖。

+ 0 - 175
项目文档/进度/监控面板.html

@@ -1,175 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh-CN">
-<head>
-<meta charset="UTF-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<title>时差改造 · 实时进度监控</title>
-<script src="进度数据.js" id="dataScript"></script>
-<style>
-  :root{
-    --bg:#0f1419; --panel:#1a2129; --panel2:#222b35; --line:#2c3742;
-    --txt:#e6edf3; --dim:#8b98a5; --done:#3fb950; --prog:#d29922;
-    --pend:#58a6ff; --todo:#6e7681; --warn:#f85149; --accent:#39d3bb;
-  }
-  *{box-sizing:border-box;margin:0;padding:0}
-  body{background:var(--bg);color:var(--txt);font-family:"Segoe UI","Microsoft YaHei",sans-serif;padding:18px;font-size:14px}
-  h1{font-size:18px;font-weight:600;display:flex;align-items:center;gap:10px}
-  .sub{color:var(--dim);font-size:12px;margin-top:2px}
-  .top{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:12px;margin-bottom:14px}
-  .heartbeat{padding:6px 12px;border-radius:20px;font-size:13px;font-weight:600;display:flex;align-items:center;gap:7px;border:1px solid var(--line)}
-  .dot{width:9px;height:9px;border-radius:50%;display:inline-block}
-  .blink{animation:bk 1.4s ease-in-out infinite}
-  @keyframes bk{0%,100%{opacity:1}50%{opacity:.25}}
-  .cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-bottom:16px}
-  .card{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:12px 14px}
-  .card .k{color:var(--dim);font-size:12px}
-  .card .v{font-size:22px;font-weight:700;margin-top:4px}
-  .bar{height:10px;background:var(--panel2);border-radius:6px;overflow:hidden;margin-top:8px}
-  .bar > i{display:block;height:100%;background:linear-gradient(90deg,var(--accent),var(--done))}
-  .ms{background:var(--panel);border:1px solid var(--line);border-radius:10px;margin-bottom:10px;overflow:hidden}
-  .ms-h{padding:9px 14px;background:var(--panel2);display:flex;justify-content:space-between;align-items:center;cursor:pointer;font-weight:600}
-  .ms-h .mini{color:var(--dim);font-size:12px;font-weight:400}
-  table{width:100%;border-collapse:collapse}
-  td{padding:7px 14px;border-top:1px solid var(--line);font-size:13px}
-  td.st{width:30px;text-align:center;font-size:15px}
-  td.id{width:78px;color:var(--dim);font-family:monospace}
-  .env{color:var(--prog);font-size:11px;border:1px solid var(--prog);border-radius:4px;padding:0 5px;margin-left:6px}
-  .s-done{color:var(--done)} .s-prog{color:var(--prog)} .s-pend{color:var(--pend)} .s-todo{color:var(--todo)}
-  .row-done{opacity:.6} .row-prog{background:rgba(210,153,34,.08)}
-  .sec-title{font-size:14px;font-weight:600;margin:18px 0 8px;color:var(--accent)}
-  .risk-高{color:var(--warn);font-weight:600} .risk-中{color:var(--prog)} .risk-低{color:var(--dim)}
-  .foot{color:var(--dim);font-size:12px;margin-top:18px;text-align:center}
-  .legend{color:var(--dim);font-size:12px;display:flex;gap:14px;flex-wrap:wrap;margin-top:6px}
-</style>
-</head>
-<body>
-<div class="top">
-  <div>
-    <h1>🔬 时差培养箱合并改造 · 实时进度</h1>
-    <div class="sub" id="phase"></div>
-    <div class="legend">
-      <span class="s-done">☑ 完成</span><span class="s-prog">◐ 进行中</span>
-      <span class="s-pend">⚠ 代码完成待验证</span><span class="s-todo">☐ 未开始</span>
-      <span class="env">环境</span>=需真机/服务验证
-    </div>
-  </div>
-  <div class="heartbeat" id="hb"><span class="dot blink" id="hbdot"></span><span id="hbtxt">检测中…</span></div>
-</div>
-
-<div id="livebar" style="background:linear-gradient(90deg,#16313a,#1a2129);border:1px solid var(--accent);border-radius:10px;padding:12px 16px;margin-bottom:14px;display:flex;flex-wrap:wrap;gap:18px;align-items:center">
-  <div style="flex:2;min-width:280px">
-    <div style="color:var(--accent);font-size:12px;font-weight:700">🔄 正在做</div>
-    <div id="liveNow" style="font-size:17px;font-weight:700;margin-top:3px;line-height:1.4">–</div>
-  </div>
-  <div style="flex:2;min-width:280px">
-    <div style="color:var(--prog);font-size:12px;font-weight:700">⏭ 下一步</div>
-    <div id="liveNext" style="font-size:15px;margin-top:3px;line-height:1.4;color:var(--txt)">–</div>
-  </div>
-  <div style="text-align:right;min-width:120px">
-    <div id="liveAgo" style="font-size:13px;font-weight:600">–</div>
-    <div style="color:var(--dim);font-size:11px;margin-top:2px">每 5 秒自动刷新</div>
-  </div>
-</div>
-
-<div class="cards">
-  <div class="card"><div class="k">总进度</div><div class="v" id="pct">–</div><div class="bar"><i id="barfill" style="width:0%"></i></div></div>
-  <div class="card"><div class="k">当前任务</div><div class="v" id="cur" style="font-size:18px">–</div><div class="sub" id="curnote"></div></div>
-  <div class="card"><div class="k">已完成 / 总任务</div><div class="v"><span id="cdone">0</span><span style="color:var(--dim);font-size:15px"> / <span id="ctotal">0</span></span></div></div>
-  <div class="card"><div class="k">待验证项</div><div class="v" id="cpend" style="color:var(--pend)">0</div><div class="sub">需环境/真机验证</div></div>
-</div>
-
-<div id="planbox"></div>
-<div class="sec-title">📋 里程碑分解(M0–M7)</div>
-<div id="msbox"></div>
-
-<div class="sec-title">🧪 待验证清单(测试阶段照单验)</div>
-<div class="ms"><table id="pendtbl"></table></div>
-
-<div class="foot" id="foot"></div>
-
-<script>
-function render(){
-  var D = window.PROGRESS_DATA;
-  if(!D){ document.body.innerHTML="<p style='color:#f85149'>未找到 进度数据.js</p>"; return; }
-  var SY={ "☑":"s-done","◐":"s-prog","⚠":"s-pend","☐":"s-todo" };
-  var SW={ "☑":1,"⚠":0.9,"◐":0.5,"☐":0 }; // 进度权重
-
-  // 计数与百分比
-  var total=0, done=0, weighted=0, pend=0;
-  D.milestones.forEach(function(m){ m.tasks.forEach(function(t){ total++; weighted+=(SW[t.status]||0); if(t.status==="☑")done++; }); });
-  pend = (D.pending||[]).filter(function(v){return v.status==="☐";}).length;
-  var pct = total? Math.round(weighted/total*100):0;
-  document.getElementById("pct").textContent = pct+"%";
-  document.getElementById("barfill").style.width = pct+"%";
-  document.getElementById("cdone").textContent = done;
-  document.getElementById("ctotal").textContent = total;
-  document.getElementById("cpend").textContent = pend;
-  document.getElementById("cur").textContent = D.currentTask||"–";
-  document.getElementById("curnote").textContent = D.note||"";
-  document.getElementById("phase").textContent = (D.phase||"") ;
-
-  // 计划任务条
-  if(D.planTasks){
-    var ph='<div class="ms"><div class="ms-h">本批执行计划 <span class="mini">Task 1–9</span></div><table>';
-    D.planTasks.forEach(function(t){
-      ph+='<tr><td class="st '+SY[t.status]+'">'+t.status+'</td><td class="id">'+t.id+'</td><td>'+t.name+'</td></tr>';
-    });
-    document.getElementById("planbox").innerHTML = ph+'</table></div>';
-  }
-
-  // 里程碑
-  var html="";
-  D.milestones.forEach(function(m){
-    var md=0,mt=m.tasks.length;
-    m.tasks.forEach(function(t){ if(t.status==="☑")md++; });
-    html+='<div class="ms"><div class="ms-h">'+m.id+' · '+m.name+' <span class="mini">'+md+'/'+mt+'</span></div><table>';
-    m.tasks.forEach(function(t){
-      var rc = t.status==="☑"?"row-done":(t.status==="◐"?"row-prog":"");
-      html+='<tr class="'+rc+'"><td class="st '+SY[t.status]+'">'+t.status+'</td><td class="id">'+t.id+'</td><td>'+t.name+(t.env?'<span class="env">环境</span>':'')+'</td></tr>';
-    });
-    html+='</table></div>';
-  });
-  document.getElementById("msbox").innerHTML = html;
-
-  // 待验证清单
-  var pt='<tr style="color:var(--dim)"><td class="id">编号</td><td>关联</td><td>待验证点</td><td>依赖环境</td><td>风险</td><td class="st">状态</td></tr>';
-  (D.pending||[]).forEach(function(v){
-    pt+='<tr><td class="id">'+v.id+'</td><td class="id">'+v.task+'</td><td>'+v.point+'</td><td style="color:var(--dim)">'+v.env+'</td><td class="risk-'+v.risk+'">'+v.risk+'</td><td class="st '+SY[v.status]+'">'+v.status+'</td></tr>';
-  });
-  document.getElementById("pendtbl").innerHTML = pt;
-
-  // 停滞/心跳检测:比较 generatedAt 与当前时间
-  function fmt(ms){ var m=Math.floor(ms/60000); if(m<1)return"刚刚"; if(m<60)return m+" 分钟前"; var h=Math.floor(m/60); return h+" 小时"+(m%60)+" 分钟前"; }
-  var gen = new Date((D.generatedAt||"").replace(" ","T"));
-  var diff = Date.now()-gen.getTime();
-  var hb=document.getElementById("hb"), dot=document.getElementById("hbdot"), txt=document.getElementById("hbtxt");
-  var col,label;
-  if(isNaN(diff)){ col="#6e7681"; label="时间未知"; dot.classList.remove("blink"); }
-  else if(diff < 4*60000){ col="#3fb950"; label="运行中 · "+fmt(diff); }
-  else if(diff < 12*60000){ col="#d29922"; label="可能暂停/等待输入 · "+fmt(diff); }
-  else { col="#f85149"; label="疑似停滞 · "+fmt(diff)+"(建议发送“继续”)"; dot.classList.remove("blink"); }
-  dot.style.background=col; txt.textContent=label; hb.style.borderColor=col; txt.style.color=col;
-
-  document.getElementById("foot").textContent = "数据生成于 "+(D.generatedAt||"?")+" · 本页每 5 秒自动刷新 · "+(D.project||"");
-
-  // 实时状态条:正在做 / 下一步 / 距上次更新
-  var nowEl=document.getElementById("liveNow"), nextEl=document.getElementById("liveNext"), agoEl=document.getElementById("liveAgo");
-  if(nowEl) nowEl.textContent = D.currentStep || D.currentTask || "–";
-  if(nextEl) nextEl.textContent = D.nextStep || "–";
-  if(agoEl){ agoEl.textContent = isNaN(diff)? "更新时间未知" : ("更新于 "+fmt(diff)); agoEl.style.color = col; }
-}
-
-// 免缓存重载 进度数据.js 后局部重渲染(无整页闪烁;file:// 下回退为不带 query 重读)
-function reloadData(){
-  var old=document.getElementById("dataScript");
-  var s=document.createElement("script"); s.id="dataScript";
-  s.src="进度数据.js?_="+Date.now();
-  s.onload=function(){ if(old&&old.parentNode)old.parentNode.removeChild(old); try{render();}catch(e){} };
-  s.onerror=function(){ var s2=document.createElement("script"); s2.id="dataScript"; s2.src="进度数据.js"; s2.onload=function(){ if(old&&old.parentNode)old.parentNode.removeChild(old); try{render();}catch(e){} }; document.body.appendChild(s2); };
-  document.body.appendChild(s);
-}
-render();
-setInterval(reloadData, 5000);
-</script>
-</body>
-</html>

+ 0 - 41
项目文档/进度/进度数据.js

@@ -1,41 +0,0 @@
-// 实时面板数据源(监控面板.html 读 window.PROGRESS_DATA)。每推进一步更新本文件。
-window.PROGRESS_DATA = {
-  project: "operate/control 双进程拆分",
-  generatedAt: "2026-06-24 18:00",
-  phase: "三阶段主体完成;M区全闭合;D2-02 第一阶段【代码+真机全过】+第二阶段 MJPEG 预览【代码完成+审查全过+Release双编译0错+46单测绿,待真机出图】;舱室故障隔离+H-08 已并main",
-  currentTask: "D2-02 第二阶段 MJPEG 实时预览代码完成(分支 feature/d2-02-mjpeg-preview,12 commit)。子代理驱动 7 编码任务 + 每任务 spec合规审查+代码质量审查两阶段全过。control端:MjpegStreamWriter(RGB→JPEG+multipart封帧纯逻辑)/DebugSession.StreamBroken+Manager.TryGet/ControlHttpServer /debug/preview/stream 推流端点(专用后台线程,校验后return不阻塞HttpListener,退出标记StreamBroken交心跳TTL回收)。operate端:MjpegFrameParser(切帧状态机5单测)/MjpegStreamClient(流式读+解码BitmapImage Freeze+FrameReceived/Stopped事件,不自动重连,一次性实例)/调试页View接入(OpenVideo/CloseVideo改走client+Image+断开提示,每次new+当值实例闸防残帧)/ControlClient.BaseUrl提public。control+operate Release双编译0错,全量46单测绿。下一步:本分支并main 或推进第三阶段(operate完整接入+真机V-012)。",
-  note: "关键决策(用户确认):JPEG编码放control端(压缩20-100倍)/专用后台线程推流(崩了不拖垮主服务)/相机锁全进程一把(SDK不改,A/B舱预览采集互等串行本轮不优化真机观察)/不自动重连(断了明确提示手动重开)/A舱调试时B舱可能正培养拍照不限空闲时段。残=真机门控(归V-012):预览出图需先curl /debug/acquire拿sid赋vm.CurrentSessionId(第二阶段无UI赋值点)/画面方向(倒置则推流层补Y翻转)/★重点压测预览中反复release-回收同舱(use-after-free窗口·全局锁+HPCSE兜底)/关预览无残帧。Release编译踩坑:control pid10360锁DLL,经/shutdown(token tl13579)优雅停机后编0错。",
-  milestones: [
-    { name: "阶段1 · control 独立进程骨架(完成)", tasks: [
-      { id: "Task1-7", name: "全过+D1-08死锁修复+operate真外壳E2E+数据入库DB铁证", status: "☑" }
-    ]},
-    { name: "阶段2 · 监控补全+借串口+受护栏停止", tasks: [
-      { id: "D2-01", name: "监控页跨进程/status三块(harness验)", status: "☑" },
-      { id: "D2-03", name: "受护栏停止/shutdown(口令+安全停机释放硬件)", status: "☑" },
-      { id: "D2-02一", name: "调试页命令代理第一阶段control后端(会话/超时回收/Execute分发含红线钳位,27单测+真机冒烟全过)", status: "☑" },
-      { id: "D2-02二", name: "MJPEG实时预览:control MjpegStreamWriter+推流端点专用线程/operate MjpegFrameParser切帧+MjpegStreamClient解码+调试页View接入。子代理驱动+两阶段审查全过,Release双编译0错,46单测绿,待真机出图(归V-012)", status: "🟢" }
-    ]},
-    { name: "阶段3 · 清理老壳+装机收尾", tasks: [
-      { id: "D3-01", name: "退役删ivf_tl_ControlTest(两编译0错)", status: "☑" },
-      { id: "D3-03", name: "双进程部署指南+布局E2E验", status: "☑" },
-      { id: "D3-02", name: "开机自启注册表方案验(整机复测需重启)", status: "◑" },
-      { id: "D1-10", name: "control oplog审计埋点迁移到活栈(project=control真机入库)", status: "☑" },
-      { id: "D3-05", name: "control崩溃看门狗(崩溃重拉/DPAPI凭据/可暂停停止卸载,TDD+真机5项)", status: "☑" },
-      { id: "HIL", name: "硬件在环回归套件IvfTl.Hardware.HilTests(守护M-05帧长/M-06按well焦点/M-01-03 EEPROM写;门控Skip+默认零写入,真机4/4)", status: "☑" },
-      { id: "CONFIG", name: "配置收敛(operate↔control连接组7键单一数据源tl-shared.config经<appSettings file=>合并读+operate删12换气CCD死键;SharedConfigStore+operate单测工程;真机改一处对称生效)", status: "☑" },
-      { id: "D3-04", name: "删operate死串口栈(去重·有风险删除·被D2-02阻塞)延后专项", status: "✗" }
-    ]}
-  ],
-  pending: [
-    { id: "D1-01", rel: "Task7", point: "operate拉起control(真实ControlProcessLauncher实跑:探活→拉起→轮询)", env: "运行", risk: "中", status: "☑实跑" },
-    { id: "D1-02", rel: "Task7", point: "/ping、/status 返回JSON", env: "运行", risk: "低", status: "☑" },
-    { id: "D1-03", rel: "Task7", point: "control 独立进程真机硬件获取(6相机SN/7COM口True)", env: "真机", risk: "高", status: "☑" },
-    { id: "D1-04", rel: "Task7", point: "operate关闭后control续命(harness退出control仍跑)", env: "运行", risk: "高", status: "☑" },
-    { id: "D1-05", rel: "Task7", point: "复用已在跑的control(真实代码:已在运行直接连接,PID不变)", env: "运行", risk: "中", status: "☑实跑" },
-    { id: "D1-06", rel: "Task7", point: "单实例 Mutex:第二个 control 自退", env: "运行", risk: "低", status: "☑" },
-    { id: "D1-07", rel: "Task7", point: "完整闭环+数据入库(house_collect 37℃真温/alarm_data 落108库)", env: "真机", risk: "高", status: "☑DB实证" },
-    { id: "D1-08", rel: "合并遗留", point: "serialBin/HAL借用ComBin重开不复活发送线程致握手死锁 修复", env: "真机", risk: "高", status: "☑已修复验证" },
-    { id: "D1-09", rel: "合并遗留", point: "control本地SQLite InitTables AUTOINCREMENT建表失败(不阻塞)", env: "运行", risk: "中", status: "☑已修复" },
-    { id: "D1-10", rel: "阶段3", point: "control硬件操作进operation_log(审计埋点迁移到control活栈,project=control真机70行)", env: "真机", risk: "低", status: "☑已修复验证" }
-  ]
-};

+ 0 - 19
项目文档/进度/进度状态.yaml

@@ -1,19 +0,0 @@
-# 续接断点状态(机器可解析)。换会话/换电脑后首先读它定位。
-# 状态取值: 未开始 / 进行中 / 完成 / 代码完成待验证
-# 纪律:本字段只存【当前断点】,历史细节进 交接卡.md(见 CLAUDE.md 第三节)。
-更新时间: 2026-06-24 D2-02 第三阶段【自动对焦重构】spec 已定已提交,待审 spec → 出实现计划
-当前任务: >
-  【D2-02 第三阶段 = 自动对焦重构】调试页全自动标定+逐孔微调 + control 升级版自动对焦 + per-well 运动范围。
-  · 头脑风暴全程完成:澄清 10 条决策 + 选定架构方案 A(引擎统一在 control,operate 发高层指令+收画面/进度) + 6 节设计逐节确认。
-  · spec 已写已自检已提交:需求文档/specs/2026-06-24-D2-02-第三阶段-自动对焦重构-design.md (commit 8036bcb,11 章)。
-  · 防丢纪要(全部源码依据 file:line + "下个窗口从这里开始"):临时文件/自动对焦重构-讨论纪要与需求锚点.md(不入 git)。
-  · 下一步:用户审 spec → 调用 superpowers:writing-plans 出实现计划 → 子代理驱动逐任务实现。
-分支: feature/d2-02-stage3-operate-debug(旧 stash@{0} 半成品已弃用,勿恢复)
-阶段概览:
-  - 阶段1 control 独立进程骨架: 完成(真机闭环)
-  - 阶段2 监控/借串口/受护栏停止: 完成; D2-02 第一阶段(命令代理)真机过 / 第二阶段(MJPEG)代码完成待真机
-  - 阶段2-D2-02 第三阶段 自动对焦重构: spec 已定,待出实现计划(本断点)
-  - 阶段3 清理老壳+装机收尾: 代码完成待验证
-  - 加固-舱室故障隔离: 第一阶段已并 main + H-08 operate 区代码完成
-说明: 已完成阶段的开发计划/specs/交接卡旧历史已归档到 项目文档/归档/(开机不读,回溯时查)。
-下一步: 审 spec → superpowers:writing-plans 出实现计划 → 子代理驱动实现。