# 待验证清单 · 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`,`` 链入真文件):① 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 `` 看到该舱实时画面 | **真机** | ☐ 代码完成待验(归 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 字典登记依赖。