edgeCore 工程铁律合规评审与 2026 Q4 改进计划

版本 日期 状态
v1.1 2026-10-19 现行(增补索引与任务速查)
v1.0 2026-10-17 初版:系统评审结论 + Q4 任务清单

评审基准:《工程铁律与恢复细则(操作层)v2.4》(2026-10-16 发布) 评审方法:四组并行只读代码审查(CONN 连接生命周期 / REC 南向恢复 / SCAN+SAFE+SHUTDOWN+OBS / DRV+TEST+BUD-005),覆盖 internal/ 全部 14 个协议驱动、internal/core 采集调度与通道管理、cmd/main.go 退出路径、internal/pkg/logger、docs/RELEASE_GATE.md 与 CI 工作流;每条结论带代码证据(文件:行号),未依赖文档自评。 评审声明:本评审基于仓库当前代码(commit 4737ea86 之后的 dev 工作区)与文档记录,未涉及真实设备与现场网络;「未实现」指代码中无对应机制,不等于功能必然失效,但按铁律 TEST-004 口径未验证不得视为合规。

索引

章节索引

章节 内容 关键结论 / 入口
一、评审结论摘要 1.1 九大规则族合规总览 · 1.2 关键数字 · 1.3 总体判断 九族均「部分合规」;三大核心风险:重建准入缺失(C-2)/控制写入默认重发(BUD-005)/关停链路断裂(SHUTDOWN-001)
二、分族合规详评 按规则族逐条对标铁律条款 2.1 CONN · 2.2 REC · 2.3 BUD · 2.4 SCAN · 2.5 SAFE · 2.6 SHUTDOWN · 2.7 OBS · 2.8 DRV · 2.9 TEST
三、新发现问题清单 N-1~N-14,文档未登记的代码级问题 6 项直接违反必须级条款;ethercat 丢弃引用拨号、ice104 无自动重连、logger 关闭链路缺失、写命令默认重发 4 次为最重
四、文档一致性修正项 6 处文档与代码冲突及修正 含 omron/mitsubishi/snmp 已绑 linkMu(C-3 记载过时)、enforceAntiStarvation 已移除等
五、2026 Q4 改进任务清单 28 项任务 + 排期依赖 + 发布门禁衔接 5.1 角色定义 · 5.2 阶段划分 · 5.3 第一阶段 P0 · 5.4 第二阶段 P1 · 5.5 第三阶段 P2/P3 · 5.6 排期依赖 · 5.7 门禁衔接
附录:核查证据索引 全部代码证据位置速查 文件 + 行号,按主题归组

任务速查(28 项)

编号 任务 优先级 角色 周期
Q4-P0-01 REC-002 准入钩子(未全部确认离线禁拨号) P0 R2 W43
Q4-P0-02 严格口径与单设备链路放行分支 P0 R2 W43–W44
Q4-P0-03 连接代际 generation(准入三件套前置) P0 R1+R2 W43–W44
Q4-P0-04 并发回写测试(旧结果不得翻回在线) P0 R4 W44
Q4-P0-05 写幂等性拆分(结果待确认三态) P0 R1 W44–W45
Q4-P0-06 写结果不确定测试(禁重复控制动作) P0 R4 W45
Q4-P0-07 ethercat 先关后开 + t.master 互斥 P0 R1 W44
Q4-P0-08 opcua Disconnect 锁外 Close P0 R1 W44
Q4-P0-09 共享连接 deadline 协调专项(三驱动) P0 R1 W45–W46
Q4-P0-10 ReleaseUncertain 资源释放状态 P0 R1 W45–W46
Q4-P0-11 close_before_open 逐驱动测试 P0 R4+R1 W46
Q4-P0-12 logger 关闭链路 + Draining 屏障 + 全局关停预算 P0 R3 W46–W47
Q4-P0-13 阶段集成验证(故障注入 + 槽位耗尽 + soak) P0 R4 W47
Q4-P1-01 错误联合分类(阶段 + 证据 + 健康 + 范围) P1 R1 W48
Q4-P1-02 FailureUnknown 终态策略 P1 R1+R2 W48
Q4-P1-03 四超时语义拆分与租约所有权回收 P1 R1 W48–W49
Q4-P1-04 退避复位双条件 + 单资源节流 P1 R1 W49
Q4-P1-05 目标路径网络判定与迟滞恢复 P1 R1+R2 W49
Q4-P1-06 受控异步连接(删裸 go driver.Connect()) P1 R2+R3 W49
Q4-P1-07 卡死巡检恢复(强制重置重派) P1 R2 W50
Q4-P1-08 任务取消隔离(channelMu 带超时) P1 R2 W50
Q4-P1-09 时间戳族与数据质量五态 P1 R2 W50–W51
Q4-P1-10 任务分类与合并语义(四类显式化) P1 R2 W51
Q4-P1-11 驱动统一重连(omron/mitsubishi/ice104/snmp) P1 R1 W51
Q4-P1-12 Unknown 有界核实 P1 R2 W51
Q4-P2-01 panic 三态与 goroutine 异常边界 P2 R1+R2 W52
Q4-P2-02 进度监控(区分存活与推进) P2 R2 W52
Q4-P2-03 OBS 补齐(字段助手 / suppressed 计数 / LRU) P2 R2+R3 W52
Q4-P2-04 RELEASE_GATE 升级(未验证态 + 量化四行) P2 R4 W52
Q4-P2-05 PR 检查表落地(九项 + 铁律编号) P2 R4 W52
Q4-P2-06 文档一致性修正(§四 6 处批量) P2 R5 W52–W53
Q4-P2-07 G-Industrial 自动化 nightly P3 R4 W53
Q4-P2-08 编号证据链与季度复盘 P3 R5+负责人 W53

任务详情(交付物、关联规则、验收标准)见 5.3 / 5.4 / 5.5;关键路径与并行说明见 5.6。


一、评审结论摘要

1.1 九大规则族合规总览

规则族 合规判定 已落地(证据) 主要缺口
CONN 连接生命周期 部分合规 runConnect 持 linkMu 包 dial/install 且退避不持锁;各驱动 t.mu 仅包引用交换;bacnet 旧协程退出等待为最佳实践 7/7 驱动「先关后开」零错误检查;ethercat 丢弃引用直接拨号(违规);generation、ReleaseUncertain 均零实现
REC 南向恢复 部分合规 REC-006 断链证据回写已单测;REC-007 Unknown 不判断;全局限流 10/s + single-flight REC-002 四条件合取未实现(关键);并发回写无防护;错误分类纯字符串匹配;5min 超时语义混用;断网无目标路径判定
BUD 恢复预算 部分合规 指数退避 + 冷却 + 滑窗限流;任务级 context 超时 拨号成功即复位退避(违规);单资源最小间隔缺失;写操作默认重发 4 次(高危);共享连接 deadline 三驱动无协调
SCAN 采集调度 部分合规(偏弱) 三层并发预算(全局/每链路串行/每设备信号量);单条目防重入 卡死巡检已被移除(enforceAntiStarvation 不存在,与文档记载不符);任务取消后底层 I/O 继续占锁;时间戳族仅 LastCollectTime
SAFE panic 保障 部分合规 scan_engine 与看门狗为单次迭代 recover 结构(正确范式) dispatchLoop 其余迭代体无 recover;无三态分类、无 panic 限频;无进度监控(假存活不可观测)
SHUTDOWN 关停 部分合规(偏弱) 关停函数顺序正确(调度→南向→pipeline→store) logger.Close 完全不存在;无 Draining 屏障;无阶段/全局预算;cm.Shutdown 未停调度引擎(消费者已关、生产者仍写)
OBS 可观测性 部分合规 panic 日志含组件+堆栈;backpressure reason 为枚举 重连日志缺 event/generation/reason/attempt/elapsed_ms 字段;限频无 suppressed 计数
DRV 驱动矩阵 部分合规 9/14 驱动接入 ConnectionManager;omron/mitsubishi/snmp 已补 LinkMutexBinder(文档记载过时) omron/mitsubishi/snmp/ice104 无统一重连编排(ice104 断线后无自动重连);能力矩阵未建档
TEST 验收门禁 部分合规 RELEASE_GATE.md 已有 Lag P95/失败率/heap 等量化阈值;并发重连、状态机、故障注入测试齐备 缺「未验证」态与发布阻断规则;写结果不确定测试、槽位耗尽测试、并发回写测试零覆盖;PR 检查表无流程载体

1.2 关键数字

  • 缺口清单 C-1~C-17 全部确认存在(其中 C-3 描述已过时,见 §四)。
  • 新发现代码级问题 14 项(N-1~N-14,见 §三),其中直接违反必须级条款 6 项。
  • 313 个 _test.go 中,TEST-001 验收矩阵 13 行仅 5 行完整覆盖、3 行部分、5 行未覆盖。
  • 文档与代码/铁律冲突 6 处(见 §四)。

1.3 总体判断

项目在并发控制、超时、退避、限流、断链证据回写等基础机制上质量良好(linkMu 锁范围、三层并发预算、单次迭代 recover 均为正确实践)。核心风险集中在三处:① 恢复准入缺少「设备全部离线」铁律校验(C-2),多从站链路存在被反复重建、耗尽连接资源的风险;② 控制写入默认重发(BUD-005),timeout 丢响应场景会重复执行现场动作;③ 关停链路的 logger 从未接入关闭路径且调度引擎未停(SHUTDOWN-001),升级场景存在日志丢失与「消费者已关、生产者仍写」窗口。 上述三项与铁律四条件合取、写幂等性、关停屏障共同构成 Q4 第一阶段主体。


二、分族合规详评

每族仅列与铁律条款的差距,已合规项见 §1.1。行号引用为评审时点代码位置,按 §0.5 属审计入口。

2.1 CONN 连接生命周期

规则 现状 证据与差距
CONN-001/002 先关后开 部分 7 个使用 ConnectionManager 的驱动均为「换引用前调 Close 但丢弃返回值」:modbus/transport.go:474-489、s7/transport.go:369-372、dlt645/transport.go:137-139、ethernetip/transport.go:179-181、bacnet/bacnet.go:314-341(质量最高,含旧协程等待但关闭错误仍忽略)、opcua/opcua.go:135-148(重连前无显式旧会话关闭);ethercat 为直接违规——t.master = newUDPMaster() 覆盖旧引用且 handleCycleError 不停 cycle 线程直接重连(ethercat/transport.go:100-106,243-251),旧 UDP fd 泄漏 + 旧/新 cycle goroutine 与 t.master 数据竞争(refreshTxSnapshots:231 无锁读)
CONN-003 锁三职责 部分 connection_manager.go:439-448 退避不持锁(合规);违规点:opcua/opcua.go:136-144 Disconnect 持 d.mu 执行 c.Client.Close(ctx) 网络 I/O,与同文件 :748-750 注释自相矛盾,Close 阻塞将连带阻塞 Health() 等状态读;ethercat connectOnce 完全无 t.mu
CONN-004 generation 未实现 全仓库驱动层零命中;s7/transport.go:583-593 withRetry 持旧 client 引用执行 RPC,重连换 client 后旧结果无标识回写
CONN-005 并发重建 已实现 single-flight CAS(connection_manager.go:453)+ linkMu 绑定 7 驱动
CONN-006 ReleaseUncertain 未实现 全仓零命中;s7/transport.go:422-428、ethernetip/transport.go:207-214 Close 失败即 SetState(StateDisconnected),违反「禁止把状态直接重置为 Disconnected」

2.2 REC 南向恢复

规则 现状 证据与差距
REC-002 重建准入(铁律) 未实现(关键) channel_manager.go:160-204 看门狗仅判 isChannelLinkUp + 30s 冷却;驱动 ScheduleReconnect(connection_manager.go:452)无设备状态校验。在线计数(channel_manager.go:483-539)为二元制——NodeStateQuarantine 计入 offline(:505-509),不满足「已确认离线」严格口径;单设备链路无显式等价分支(无注释无测试)
REC-002 并发防护(C-10) 未实现 准入快照(channel_manager.go:168-179 RLock 后即释放)与回写(finalizeScanCollect→onCollectSuccess,node_status.go:211-231,1 次成功即翻在线)之间无原子衔接——「检查时全离线、检查后被旧结果翻回在线」竞争窗口真实存在
REC-004 状态同步 部分 链路确认断开同步置离线已实现(channel_manager.go:423);「数据停更超阈值 + 链路已断 → 强制置离线」未实现(全库无周期陈旧巡检,仅事件驱动);回写无 generation 校验
REC-005 错误分类(C-12) 部分 modbus/transport.go:197-217 纯 strings.Contains 匹配且 i/o timeout 一律设备级;无重新分类判据——共享传输所有从站连续超时均不累计 collectFailCount,永不升级链路级,形成「连接未断、链路不可用」的永久停采(评审预言的风险在代码中成立)
REC-006/007 已实现/部分 REC-006 与代码一致;REC-007 缺「Unknown 有界核实」——看门狗对 Unknown 直接跳过(:183),仅靠 connMgr 内部 64 次重试兜底
REC-008 超时语义 部分 channelReconnectTimeout=5min(channel_manager.go:124)实际圈住 EnsureConnected 全部退避轮次(connection_manager.go:462-465),充当恢复总预算/租约,四种语义未拆分;租约到期后无「先确认旧 goroutine 退出再清标志」的所有权回收
REC-009/BUD-004 限流 部分 全局限流 + single-flight 已实现;单资源最小间隔缺失(新故障从 baseDelay=100ms 重新起退);退避复位违规——拨号成功即 RecordSuccess 复位(connection_manager.go:159-166,413-414),正是 BUD-003 禁止的「仅因握手成功即复位」
REC-011 断网判定 未实现 断网判定完全依赖驱动 Health() 与错误字符串;无目标地址/接口/路由域判定、无迟滞恢复、无按目标低频探测
REC-012 异步连接 部分(形式违规) channel_manager.go:923-933 与 :2511 为裸 go driver.Connect() 无主 goroutine——无有界队列、无重复请求合并、关停不可回收;仅因 modbus Connect 内部转发 EnsureConnected 间接受益于退避/限流

2.3 BUD 恢复预算

规则 现状 证据与差距
BUD-001 重试职责 部分 多层重试独立叠加风险存在(驱动 withRetry × 采集层);读/写未区分策略
BUD-002 时间预算 部分 ReadPoint 5s/ReadAllPoints 10s/Connect 10s 存在;T_task 六段拆分未落实;驱动层 context 取消依赖参差(拨号 client.Open() 不可取消,仅受 t.timeout 约束,transport.go:433)
BUD-003 退避冷却限流 部分 机制齐备但复位条件违规(见 REC-009);无按资源敏感度的策略档位
BUD-004 单资源节流(C-9) 未实现 无单资源最小重连间隔、无显式单资源最大并发拨号
BUD-005 写幂等性(C-16) 未实现(高危) 写主路径三层零重试(server.go:1622→channel_manager.go:1486→driver_executor.go:237/293),唯一重试在 modbus 驱动层:transport.go:589-664 withRetry 对 timeout/crc/exception 不 break 继续重发,maxRetries 默认 3 → timeout 丢响应时写命令默认重发最多 4 次;全仓无幂等声明/去重标识/回读确认;失败日志无三态区分
BUD-006 deadline 协调(C-13) 部分(三驱动违规) profinetio/rpc.go:39-93 有 c.mu 串行化但响应不校验 callID、deadline 设后无清理(:52,84);mitsubishi/transport.go:155-193 transact 无连接级锁,并发请求互相破坏 deadline 且残留响应必被误关联;knxnetip/transport.go:413-467 无锁读,并发写后各自读必然错配;ice104/transport.go:155-228 后台 readLoop 与前台握手共享 conn 双读者互毁 deadline

2.4 SCAN 采集调度

规则 现状 证据与差距
SCAN-001 端到端链条 部分 链条可观测性依赖单点 LastCollectTime
SCAN-002/005 时间戳族(C-6) 未实现 全库仅 LastCollectTime(model/metrics.go:110、channel_manager.go:31);LastValidSampleAt/LastValueChangedAt/LastCollectSuccessAt/LastCommitAt/LastErrorAt 均不存在;点位时间戳为执行时间(各驱动 TS: time.Now(),如 omron/udp_scheduler.go:125),数值不变时无法区分「值未变但采样成功」;质量态仅 Good/Bad,缺五态
SCAN-003 负载过载 部分(与文档记载不符) processReadyTasks(scan_engine.go:438-464)无卡死巡检;enforceAntiStarvation 全库不存在(仅历史测试注释提及),RecordStarvationRescue(scan_engine_metrics.go:116)无生产调用点——文档 §0.4/细则 1 称「已实现」与代码不符;execution_layer.go:300-307 任务超时仅返回 ErrTimeout 而 ReadFunc 仍在跑并持 channelMu(:473-476),同链路后续任务级联阻塞=链路级饿死,违反 SCAN-003⑤
SCAN-004 阈值族 未实现 2×PollPeriod 为文档口径,无分协议五参数配置
SCAN-006 任务合并语义 未实现 写/事件类任务不经调度器(channel_manager.go:1486 直写),无独立队列/保序/丢弃策略声明

2.5 SAFE panic 保障

规则 现状 证据与差距
SAFE-001 四层语义(C-5) 部分 单次迭代 recover 仅 2 处(scan_engine.go:387-400 safeProcessReadyTasks、channel_manager.go:151-158 看门狗);dispatchLoop 的 recover 未覆盖同迭代 scheduleWake/nextReadyTime(:369/:372),这两处 panic 仍会杀死唯一调度 goroutine;无三态分类;重复 panic 无限频/退避;驱动自发重连 goroutine(connection_manager.go:462 起)无自身 recover
SAFE-002 进度监控 未实现 存活证据仅状态计数(GetActiveTaskCount)与 15s 链路巡检;「goroutine 活着但阻塞在 channelMu」不可观测

2.6 SHUTDOWN 关停

规则 现状 证据与差距
SHUTDOWN-001 硬序契约 部分(阶段④断裂) 顺序 ①②③ 正确(main.go:389-393);logger.Close 全链不存在——logger 包无导出 Close(仅 AsyncRotateWriter.Close,logger.go:287,且 InitLogger 不持有 writer 引用),main 无调用;无 Draining 屏障,驱动自发重连 goroutine 在关停中仍可触发新重连(违反阶段④);cm.Shutdown(channel_manager.go:1786-1803)未调 scanEngineAdapter.Stop()——dispatchLoop/executionLayer 在关停后继续运行,在途 executeTaskAsync 仍可写已 defer 关闭的 shadow/store(消费者已关、生产者仍写)
SHUTDOWN-002 期限与结果(C-7/C-14) 部分 仅 srv 5s / pprof 2s 超时;cm.Shutdown 无超时(一个驱动卡死阻塞全部);无全局总预算;AsyncRotateWriter.Close(logger.go:287-293)close(closeCh) 后立即 file.Close() 不等待 loop 排空=丢日志/写已关文件,二次 Close panic;InitLogger 被调用两次(main.go:68→129),首个 writer loop goroutine 泄漏

2.7 OBS 可观测性

规则 现状 证据与差距
OBS-001 字段契约 部分 重连日志仅 driver+error(connection_manager.go:468-471),缺 event/channel_id/device_id/reason/attempt/elapsed_ms;generation 不存在故无该字段;reason 部分为字符串枚举(backpressure_controller.go:188)
OBS-002 指标基数 部分 指标为内存 map(model/metrics.go:144-161)非 Prometheus,高基数风险暂不存在;但 deviceMetrics/pointMetrics 按 ID 全量驻留无上限无保留期
OBS-003 数据预算 部分 LogThrottle(reconnect.go:47-66)无 suppressed 计数;AsyncRotateWriter dropCnt 仅每 1000 次写 stderr 不入指标;bacnet/scheduler.go:385-398 逐点静默无计数——违反「禁止完全静默」

2.8 DRV 驱动矩阵

驱动 ConnectionManager LinkMutex 重连编排 判定
bacnet/modbus/s7/dlt645/ethernetip/opcua/knxnetip/ethercat 已接入(8) 5/8 已绑 connMgr 统一 基本合规(关闭语义见 CONN)
profinetio 半接入(new 未调 Ensure/Schedule) 未绑 自管计数 缺口
omron-fins 无 已绑 Connect 内直拨,无退避/限流/单飞,无后台重连 缺口
mitsubishi-slmp 无 已绑 Connect 内线性重试(attempt×100ms 无封顶),失败后无自愈 缺口
snmp 无 已绑 UDP 现建现用 可接受(无连接语义)需豁免建档
ice104 无 未绑 readLoop 失败即退出 goroutine,无任何自动重连 缺口(最重)

看门狗侧 ReconnectScheduler 为可选接口,未实现驱动被静默跳过(channel_manager.go:189-192)——「静默跳过」本身违反 DRV 豁免须显式建档的要求。

2.9 TEST 验收门禁

规则 现状 证据与差距
TEST-001 矩阵 5/13 完整覆盖 已覆盖:时序(connection_manager_linkmu_test.go:10)、并发重连(connection_manager_reconnect_test.go:55)、状态机(connection_manager_test.go:31,277)、故障注入(integration/fault_propagation_test.go:50)、资源 soak(soak_test.go:21,//go:build soak 默认不执行);未覆盖:并发回写(依赖 generation)、槽位耗尽(C-11)、写结果不确定、生命周期旧代际覆盖;部分:关闭异常(无 close_before_open 专项)、关停(缺「I/O 执行中收信号」场景)
TEST-002 恢复判据 未落实 无按协议定义的恢复成功判据文档与断言
TEST-003 PR 检查表 未实现 无 PULL_REQUEST_TEMPLATE.md、无 CONTRIBUTING.md,九项检查表无流程载体
TEST-004 判定分类 部分 RELEASE_GATE.md 有 PASS/WARN/BLOCK 与发布矩阵(:144-153),但缺「未验证」态;WARN≠有条件豁免(无限定/范围/责任人/风险缓解要素)
TEST-005 量化门禁(C-15) 部分 已有 Lag P95<150ms/drift<80ms/失败率<0.1%/heap drift<8%/GC<30ms(:116-127);缺:连接尝试次数/单位时间、单资源最大并发拨号、活跃 fd/socket 稳态、违规事件(关闭失败/旧代际回写/未确认释放后拨号)=0 四行;G-Industrial 未自动化(人工+报告模板),CI 仅跑 G-Stability(ci.yml:69-74)

三、新发现问题清单(文档未登记)

编号 位置 问题 违反规则 风险
N-1 ethercat/transport.go:100-106,143,231,243-251 connectOnce 丢弃旧 master 引用直接拨号,不停 cycle 线程;t.master 无锁读写 CONN-001/003(直接违规) 旧 UDP fd 泄漏 + goroutine 数据竞争,反复故障后资源耗尽
N-2 opcua/opcua.go:136-144 Disconnect 持 d.mu 执行 Close 网络 RPC CONN-003 Close 阻塞连带阻塞 Health 等所有状态读,看门狗连带卡死
N-3 mitsubishi/transport.go:155-193、knxnetip/transport.go:413-467 transact 无连接级串行化,共享 conn 并发读写 BUD-006 响应错配(张冠李戴)→ 脏数据写 shadow;deadline 互毁
N-4 ice104/transport.go:226-227,241-242 readLoop 读失败仅置 connected=false 退出,无自动重连 REC-003/DRV 断线后须人工介入,恢复退化
N-5 channel_manager.go:923-933,2511 裸 go driver.Connect() 无主 goroutine REC-012 绕过退避/限流/关停回收;重复启动无界排队
N-6 channel_manager.go:1786-1803 cm.Shutdown 未停 scanEngineAdapter(scan_engine_compat.go:161 生产零调用) SHUTDOWN-001⑤ 消费者已关、生产者仍写 shadow/store
N-7 logger.go:287-293、main.go:68,129 logger.Close 不存在;AsyncRotateWriter.Close flush-then-close 竞态 + 二次 Close panic;InitLogger 双调用泄漏首个 loop SHUTDOWN-001④ 升级/退出丢日志;goroutine 泄漏
N-8 modbus/transport.go:589-664,748,852,866 写命令经 withRetry 对 timeout/crc 继续重发,默认最多 4 次 BUD-005(高危) timeout 丢响应=重复执行现场控制动作(脉冲/启停/复位)
N-9 connection_manager.go:159-166,413-414 拨号成功即 RecordSuccess 复位退避至最低间隔 BUD-003/004 闪断场景退避失效,重连风暴
N-10 scan_engine.go:438-464、scan_engine_metrics.go:116 enforceAntiStarvation 已移除、卡死巡检不存在、RecordStarvationRescue 无调用点 SCAN-003;文档 §0.4/细则1「已实现」记载与代码不符 任务 Running 卡死后永久蒸发(饿死形态),无巡检兜底
N-11 execution_layer.go:300-307,473-476 任务取消后 ReadFunc 仍在跑并持 channelMu SCAN-003⑤ 同链路后续任务级联超时=链路级饿死
N-12 profinetio/rpc.go:52,84,125-140 响应不校验 callID;deadline 设后无清理 BUD-006 残留响应误关联;deadline 污化后续请求
N-13 omron/fins.go:97-106 等 omron/mitsubishi/snmp 已实现 LinkMutexBinder 并由 channel_manager.go:857 调用 文档 C-3 与架构11 §52-56/174/345 记载过时(正向) 误导后续评审基线
N-14 docs/RELEASE_GATE.md 文件存在且已有部分量化阈值 C-15 范围收窄(正向) —

四、文档一致性修正项(6 处)

# 位置 修正内容
1 架构 11 §52-56/174 omron/mitsubishi/snmp「未绑定 LinkMutexBinder」→ 改为「已绑 linkMu、未接入 ConnectionManager、无 ReconnectScheduler」
2 架构 11 §345 「补 LinkMutexBinder」建议 → 改为「引入 ConnectionManager + ReconnectScheduler」
3 南向采集通道决策方案:494 「链路级重连经 driver.ConnectionManager」→ 补充 omron/mitsubishi/snmp/ice104 不成立的现状说明
4 南向采集通道决策方案:498 补充 REC-002 四条件合取要求与现状(准入只判链路层)
5 南向采集通道决策方案:517 「RecordFailure 5 次失败重连」→ 现路径为 watchdog 30s 冷却 + ScheduleReconnect + 设备级错误不计入
6 铁律文档 C-3 / §0.4 更新 omron/mitsubishi/snmp linkMu 已绑的事实;enforceAntiStarvation 相关表述改为「已移除,卡死巡检待恢复」(N-10)

五、2026 Q4 改进任务清单

5.1 角色定义

角色 职责范围
R1 南向内核 internal/driver/**、connection_manager.go、reconnect_limiter
R2 采集调度 internal/core/scan_engine.go、execution_layer、channel_manager 准入与状态回写
R3 平台工程 cmd/main.go、logger、pipeline、storage、server 关停
R4 质量保障 测试体系、CI/nightly、RELEASE_GATE、PR 流程
R5 文档治理 docs/ 全部文档与铁律维护
负责人 任务分派、豁免审批、阶段评审与发布判定

5.2 阶段划分与周次对照

阶段 周次 日期 目标
一:正确性缺口(P0) W43–W47 10/19–11/22 消除错误恢复、连接资源泄漏、重复控制动作、关停断裂四类风险
二:跨协议统一(P1) W48–W51 11/23–12/20 故障分类、预算、调度、驱动能力统一
三:治理与验证(P2/P3) W52–W53 12/21–12/31 量化门禁、发布阻断、编号证据链、季度复盘

5.3 第一阶段任务(P0,W43–W47)

编号 任务与交付物 关联 优先级 角色 周期 验收标准
Q4-P0-01 REC-002 准入钩子:checkChannelHealth 与 ConnectionManager.ScheduleReconnect 之间增加统一准入点,按链路归组统计设备状态,未全部确认离线即拒绝拨号(仅降级/冷却) REC-002/C-2 P0 R2 W43 状态机测试:多从站链路 1 台在线时触发重连→断言无拨号;onlineCount==0→放行
Q4-P0-02 严格口径与单设备分支:Unknown/Quarantine/过期/回写中 不计入在线与确认离线;单设备链路离线即放行的显式分支 + 注释 + 测试固化 REC-002/C-2 P0 R2 W43–W44 单元测试覆盖四种状态计数;单设备链路测试断言立即放行
Q4-P0-03 连接代际 generation:ChannelManager/transport 增加 per-channel 递增代际,采集回写前校验,旧代结果丢弃 CONN-004/C-4/C-10 P0 R1+R2 W43–W44 生命周期测试:旧请求延迟返回→断言不覆盖新状态(TEST-001 矩阵行)
Q4-P0-04 并发回写测试:准入检查通过后注入旧连接迟到成功结果 REC-002 并发防护/TEST-001 P0 R4 W44 -race 下断言设备不被翻回在线、重建流程不被绕过
Q4-P0-05 写幂等性拆分:写路径独立 writeWithRetry,仅发送前错误(未建立/拨号失败)可重试;发送后 timeout/crc 返回「执行结果待确认」三态错误码;点位配置增补幂等声明 BUD-005/C-16/N-8 P0 R1 W44–W45 mock 驱动吞响应→断言不重发且 API/状态机呈现待确认;失败日志三态可查
Q4-P0-06 写结果不确定测试:写已执行但响应丢失场景 TEST-001/BUD-005 P0 R4 W45 write_uncertain_test.go:无重复控制动作(强制项)
Q4-P0-07 ethercat 先关后开:connectOnce 入口停 cycle 线程 + 关旧 master,确认释放后装新;t.master 加互斥 CONN-001/003/N-1 P0 R1 W44 close_before_open 测试(关闭失败禁拨)+ -race 无数据竞争
Q4-P0-08 opcua Disconnect 锁外 Close:锁内摘取 clients map、锁外逐个 Close CONN-003/N-2 P0 R1 W44 测试:Close 阻塞不阻塞 Health 读取
Q4-P0-09 共享连接 deadline 协调专项:mitsubishi/knxnetip transact 加连接级互斥 + 响应序号关联;profinetio 响应校验 callID + 超时 drain + deadline 四出口清理;ice104 前台握手与后台 readLoop 隔离 BUD-006/C-13/N-3/N-12 P0 R1 W45–W46 并发 transact 测试:响应不错配;超时后下一请求不误关联残留响应
Q4-P0-10 ReleaseUncertain 状态:ConnState 增加释放不确定态,Close 失败/协程未退出即进入;期间禁止同资源快速新建、重连间隔≥普通退避上限;bacnet 试点后推广 CONN-006/C-8 P0 R1 W45–W46 关闭失败测试:不断言 Disconnected、禁拨号、低频核验日志可查
Q4-P0-11 close_before_open 逐驱动测试:s7/modbus/ethernetip/dlt645/opcua(mock Close 返错→断言 factory 未调用、保留引用) CONN-001/002/C-1 P0 R4+R1 W46 每驱动 1 个表驱动用例,-race 全绿
Q4-P0-12 logger 关闭链路:导出 logger.Close()(doneCh 等待 loop 排空后关文件,幂等);修复双 InitLogger 泄漏;main.go 增加 Draining 状态 + 全局关停预算(建议 30s)+ cm.Shutdown 先停 scanEngineAdapter 再逐驱动带超时 Disconnect + logger.Close 置末 SHUTDOWN-001/002/C-7/C-14/N-6/N-7 P0 R3 W46–W47 关停测试:I/O 执行中发信号→有界关闭、顺序正确、退出前 fd 采样无残留;无「向已关 logger 写日志」竞态
Q4-P0-13 阶段集成验证:故障注入(单设备异常/共享链路断开/网络断开)+ 槽位耗尽仿真(transport 层错误注入)+ 72h soak short TEST-001/C-11 P0 R4 W47 恢复作用范围正确;单资源节流生效;无永久拨号循环;资源趋势稳态

5.4 第二阶段任务(P1,W48–W51)

编号 任务与交付物 关联 优先级 角色 周期 验收标准
Q4-P1-01 错误联合分类:transport 增加共享链路健康证据(同连接其他从站近期成功数);连续失败且健康证据丢失→超时重分类为 TransportReadTimeout 链路级并累计;按阶段表拆分子类型 REC-005/C-12 P1 R1 W48 测试:全从站连续超时→升级链路级并触发受控重建;单从站超时→仅隔离设备
Q4-P1-02 FailureUnknown 终态:有界诊断窗口 + 限频探测 + 「不可判定故障」可观测告警 REC-001 P1 R1+R2 W48 状态机测试:Unknown 不永久悬置、不误判 LinkDown
Q4-P1-03 四超时语义拆分:dialTimeout/recoveryAttemptBudget/reconnectWaitTimeout/recoveryLeaseTimeout 具名化;租约到期先确认旧 goroutine 退出再清标志 REC-008 P1 R1 W48–W49 测试:租约超时后无新旧重连流程并发
Q4-P1-04 退避复位双条件:握手成功 + 稳定连接时长 + 成功采集次数才逐步复位;单资源最小重连间隔 + 显式最大并发拨号 BUD-003/004/C-9/N-9 P1 R1 W49 测试:闪断场景退避不失效;单资源拨号间隔≥配置值
Q4-P1-05 目标路径网络判定:按目标地址/接口/路由域维护低频探测;恢复判定连续成功/迟滞 REC-011 P1 R1+R2 W49 测试:管理网断但设备网通→不暂停设备网采集
Q4-P1-06 受控异步连接:删除裸 go driver.Connect()(channel_manager.go:923/2511),改 ReconnectScheduler 幂等提交 + 有界队列 + 同链路请求合并 + 关停可回收 REC-012/N-5 P1 R2+R3 W49 测试:队列满返回「恢复已排队」;关停时无残留 goroutine
Q4-P1-07 卡死巡检恢复:ScanTask 增加 runningSince;dispatchLoop 每轮按 10×Interval/5min 规则强制重置重派并记日志 SCAN-003/N-10 P1 R2 W50 测试:mock 永不返回任务→被强制重派且 Skipped 日志可追踪
Q4-P1-08 任务取消隔离:SerialQueueManager 记录 in-flight 句柄,外层超时后置取消标志并隔离该队列 worker;channelMu 带超时获取 SCAN-003/N-11 P1 R2 W50 测试:驱动忽略 ctx 时同链路后续任务不被级联阻塞
Q4-P1-09 时间戳族与质量五态:ShadowPoint 增加 lastValidSampleAt/lastValueChangedAt/lastCollectSuccessAt/lastCommitAt/lastErrorAt;新鲜度以有效样本判定;质量态五枚举 SCAN-002/005/C-6 P1 R2 W50–W51 测试:值不变但采样成功→不报陈旧;部分点位失败→关键点位停更可判
Q4-P1-10 任务分类与合并语义:周期采样(可合并)/状态核验(可降频不可饿死)/控制写入(保序独立队列)/事件告警(不可覆盖)四类显式化 SCAN-006 P1 R2 W51 测试:写入任务不因周期合并被丢弃;事件不塌缩
Q4-P1-11 驱动统一重连:omron/mitsubishi/ice104 实现 ReconnectScheduler(委托 connMgr);ice104 补 BindLinkMutex;profinetio 拨号改 EnsureConnected;snmp 走正式豁免 DRV/C-3/N-4/N-13 P1 R1 W51 每驱动:断线→自动恢复测试;snmp 豁免六要素+生命周期字段建档
Q4-P1-12 Unknown 有界核实:Unknown 持续超 N 个巡检周期→有限诊断或升级告警 REC-007 P1 R2 W51 测试:Unknown 不永久跳过

5.5 第三阶段任务(P2/P3,W52–W53)

编号 任务与交付物 关联 优先级 角色 周期 验收标准
Q4-P2-01 panic 三态与 goroutine 边界:recover 上移覆盖 dispatchLoop 整个迭代体;RecoveredAndContinue/RestartWorker/ComponentFailed 三态落地;重复 panic 限频退避;每 goroutine 异常边界清查 SAFE-001/C-5 P2 R1+R2 W52 测试:迭代体内任意位置 panic→循环存活;重复 panic→ComponentFailed 报警不风暴
Q4-P2-02 进度监控:ScanEngine/ExecutionLayer/SerialQueueManager 增加 lastProgressAt,诊断接口输出 now-lastProgressAt 超阈报警 SAFE-002 P2 R2 W52 测试:goroutine 阻塞→进度指标超阈可观测
Q4-P2-03 OBS 补齐:关键事件字段助手(event/channel_id/device_id/generation/reason/attempt/elapsed_ms 单调时钟);LogThrottle 增 suppressed 计数;pointMetrics LRU 上限 OBS-001/002/003 P2 R2+R3 W52 测试:限频事件 suppressed 计数可查;单条日志长度有上限
Q4-P2-04 RELEASE_GATE 升级:判定矩阵增设「未验证」态且强制门禁未验证默认 BLOCK;阈值表补重连速率/单资源并发拨号/fd-socket 稳态/违规事件=0 四行;WARN 改造为有条件豁免(范围/期限/责任人/风险缓解) TEST-004/005/C-15/N-14 P2 R4 W52 门禁文档版本化;数值有测试环境记录
Q4-P2-05 PR 检查表落地:新增 .github/PULL_REQUEST_TEMPLATE.md(TEST-003 九项 + 铁律编号字段);ci.yml 增加 PR 体校验 TEST-003 P2 R4 W52 模板生效;缺失铁律编号的 PR 被标记
Q4-P2-06 文档一致性修正:§四 6 处批量更新(架构 11、南向方案、铁律 C-3 与 §0.4) 文档治理/N-10/N-13 P2 R5 W52–W53 审查清单逐项核对通过
Q4-P2-07 G-Industrial 自动化:nightly workflow 增加仿真器 job 承接协议分级表 + S1–S6 + 量化阈值,输出报告归档 TEST-005 P3 R4 W53 nightly 跑通并产出带数值的报告
Q4-P2-08 编号证据链与季度复盘:建立「铁律→不变量→代码符号→测试→门禁」映射表(记录 commit SHA);Q4 复盘:未验证项与豁免项纳入版本记录;形成 2027 Q1 输入 §0.5/TEST-004/阶段三 P3 R5+负责人 W53 映射表随版本发布;复盘报告经负责人签发

5.6 排期依赖与并行说明

  • 关键路径:Q4-P0-03(generation)是 Q4-P0-01/02/04 的前置;Q4-P0-12(关停)依赖 Q4-P0-10 的关闭语义统一,两者在 W46 需协同。
  • 可并行:R1(驱动层)与 R2(调度层)、R3(平台层)任务按周并行;Q4-P0-04/06/11(测试)随对应实现周交付,采用 TDD 时序(先写失败测试)。
  • 每周五阶段站会:对表验收,未过项不留到下周(对齐 TEST-004「未验证≠通过」)。
  • 阶段门:W47 末第一阶段评审(负责人签发后才进入第二阶段);W53 末季度复盘并裁定 2027 Q1 计划。

5.7 与发布门禁的衔接

  • 本计划全部 P0 项完成并验证前,涉及连接生命周期、控制写入、关停路径的发布默认阻断(TEST-004 阻断规则)。
  • Q4-P2-04 落地后,「未验证」态与量化阈值纳入 RELEASE_GATE.md,与 CI/nightly 形成自动判定。
  • 每项任务的测试证据(测试名 + 运行记录 + commit SHA)登记进 §0.5 要求的编号映射表,作为版本发布记录的一部分。

附录:核查证据索引

主题 主要证据位置
重连准入与看门狗 internal/core/channel_manager.go:121-204, 397-441, 483-539, 886-933, 1786-1803, 2511
设备状态 internal/core/channel_device_state.go:11-47, 112-161, 168、internal/core/node_status.go:211-300
连接管理 internal/driver/connection_manager.go:78, 145-166, 233-266, 341-346, 402-474、internal/driver/reconnect_limiter.go
驱动 connectOnce/Close modbus/transport.go:186-279, 474-489, 589-664、s7/transport.go:363-428, 583-593、bacnet/bacnet.go:221, 314-361、dlt645/transport.go:131-147、ethernetip/transport.go:173-218、opcua/opcua.go:135-148, 738-795、ethercat/transport.go:100-155, 231, 243-251
deadline 协调 profinetio/rpc.go:39-140、mitsubishi/transport.go:155-193、knxnetip/transport.go:413-467、ice104/transport.go:155-228、dlt645/transport.go:322-389
调度与饿死 internal/core/scan_engine.go:49-77, 369-420, 438-464, 523-614, 745-760、execution_layer.go:230-355, 445-476、backpressure_controller.go:66-188、scan_engine_metrics.go:116
退出与日志 cmd/main.go:55, 68, 129, 389-393、internal/pkg/logger/logger.go:230-293, 337、internal/server/server.go:288-292
测试与门禁 internal/**/313 个 _test.go、integration/soak_test.go:14-31、docs/RELEASE_GATE.md:29-153, 228-238、.github/workflows/ci.yml:69-100