|
@@ -0,0 +1,201 @@
|
|
|
|
|
+<!-- DSH-IDEMPOTENCY-KEY: deck-51a682f3-5973748 -->
|
|
|
|
|
+<!-- parentKey: 00 -->
|
|
|
|
|
+# 后端执行票 —— 单设备业务优先级裁定落地(全部报警均有未结束工单时工单处置最高)
|
|
|
|
|
+
|
|
|
|
|
+Category: backend-execution
|
|
|
|
|
+
|
|
|
|
|
+## 来源
|
|
|
|
|
+
|
|
|
|
|
+[前端执行票 45](45-untitled.md) 实施前裁定(维护者 2026-10-16):
|
|
|
|
|
+- 监测点聚合:维持报警优先级最高(后端现行语义不动)。
|
|
|
|
|
+- **单设备**:只要该设备的**所有报警都有对应的工单**(即报警均已被工单承接、处置在进行),单设备自身状态应判**工单处置最高**——高于报警/预警。
|
|
|
|
|
+- 判定权归后端;前端只渲染(CONTEXT.md / ADR 0002 不变)。
|
|
|
|
|
+
|
|
|
|
|
+## 现状证据(前端票 45 侦察)
|
|
|
|
|
+
|
|
|
|
|
+- 权威解析器 `CockpitMonitoringPointStatusResolver.deviceStatus()` 现行顺序:
|
|
|
|
|
+ `alarm → warning → workOrderInProgress → online?NORMAL:OFFLINE`,即报警恒压工单。
|
|
|
|
|
+ 实测设备 `21119740`(alarm=true, warning=true, workOrderInProgress=true)→ 后端判 ALARM;
|
|
|
|
|
+ 按裁定应为工单处置(其报警已有工单承接时)。
|
|
|
|
|
+- `CockpitMonitoringPointStatus` 枚举优先级 ALARM(1)/WARNING(2)/WORK_ORDER(3)/NORMAL(4)/OFFLINE(5)/EMPTY(6)。
|
|
|
|
|
+- map-snapshot 不携带工单布尔——前端无法也不得自行判定。
|
|
|
|
|
+
|
|
|
|
|
+## 范围
|
|
|
|
|
+
|
|
|
|
|
+1. 明确「所有报警均有对应工单」的判定口径(报警-工单回联读模型已有 `alarm_data.work_order_id` 关联,票 12 已核实关联键)。
|
|
|
|
|
+2. 调整单设备状态解析:设备存在报警、且每条报警均有未结束/已关联工单时 → `WORK_ORDER`(工单处置);否则维持现行序。
|
|
|
|
|
+ 注意只影响**单设备**状态(设备卡片 deviceStatus、快照未关联设备 deviceStatus、统计计数),**监测点聚合 `resolve()` 语义由维护者另行确认是否跟随**(聚合用 min(priority),若单设备可判 WORK_ORDER(3) 而报警设备判 WORK_ORDER,聚合优先级序是否需把 WORK_ORDER 提到 ALARM 之前,须裁定并同步枚举 priority 与前端词表)。
|
|
|
|
|
+3. 契约测试覆盖:报警无工单 → ALARM;全部报警有工单 → WORK_ORDER;混合 → 按裁定;无报警维持现状。
|
|
|
|
|
+4. 落地后通知前端票 45 消费侧复核(前端 `DEVICE_STATUS_VISUALS.priority` 与 `POINT_STATUS_VISUALS.priority` 需同步新序——前端票 45 已按双轴实现,priority 同步是唯一耦合点)。
|
|
|
|
|
+
|
|
|
|
|
+## 非目标
|
|
|
|
|
+
|
|
|
|
|
+- 不改前端代码(前端词表同步由票 45 收口时复核)。
|
|
|
|
|
+- 不动监测点聚合 `resolve()` 除非第 2 条裁明确认需要。
|
|
|
|
|
+
|
|
|
|
|
+## 进度
|
|
|
|
|
+
|
|
|
|
|
+**已实施、验证、推送完成(2026-10-17)→ 关闭。**
|
|
|
|
|
+
|
|
|
|
|
+提交 `3772220e` + 编译解阻 `5d4d03c6`,已推 `origin/master`(远端核实 3772220e)。
|
|
|
|
|
+`Cockpit*Test,BusinessCockpit*Test` **512/512**;变异闸 **7/7** 打红并字节还原;前端 t09 **38/38**(零耦合,裁定 4 成立)。
|
|
|
|
|
+
|
|
|
|
|
+裁定全部落地:只取未处理报警(`alarm_status=0`);承接=`work_order_id` 非空且工单 `order_status ∈ {0..4,6}`;
|
|
|
|
|
+空集/读失败 → 维持 ALARM;`resolve()` 与枚举 priority 不动;已推送。
|
|
|
|
|
+
|
|
|
|
|
+两处如实留档:① 票面「21119740 应为工单处置」被真实数据证伪(该设备 2 条未处理报警均无工单承接,
|
|
|
|
|
+按裁定应为 ALARM);② 新规则在当前数据上不改变任何读数(正确行为,非未生效)。
|
|
|
|
|
+`zksy-system` 全量 2 失败/1 错误为既有(stash 对照逐条相同),与本票零交集。
|
|
|
|
|
+
|
|
|
|
|
+**下一步**:无(本票交付物已闭环)。前端消费侧无需跟随改动。
|
|
|
|
|
+
|
|
|
|
|
+Status: resolved
|
|
|
|
|
+Type: task
|
|
|
|
|
+Blocked by:
|
|
|
|
|
+Labels: wayfinder:task, backend-execution
|
|
|
|
|
+
|
|
|
|
|
+## Comments
|
|
|
|
|
+
|
|
|
|
|
+### local — 2026-10-16T18:13:25.050Z
|
|
|
|
|
+阶段闸门诊断完成(2026-10-17):当前工作树是前端 City-Lifeline-Cockpit(origin=192.168.110.30/ChenJZ/City-Lifeline-Cockpit),没有后端 Java/Maven/Gradle 源码或 CockpitMonitoringPointStatusResolver;后端仓库/负责人/权限未提供。只读真实接口复核:map-snapshot 仍返回设备 21119740 的 ALARM,设备工单接口中存在多条未结束工单但也有未关联当前报警的工单;因此票面“全部报警均有未结束/已关联工单”的设备级判据不能从现有设备汇总直接推断,需要后端按每条当前报警关联键(alarm_data.work_order_id)且工单状态 0–4/6 视为未结束,状态 5/7 视为结束,空/缺关联即不满足。未改前端或模拟后端,避免越权猜测。
|
|
|
|
|
+
|
|
|
|
|
+### local — 2026-10-16T18:32:36.319Z
|
|
|
|
|
+【诊断记录 2026-10-17 —— 后端仓库已定位,票面前提与真实数据不符,判定口径待裁定】
|
|
|
|
|
+
|
|
|
|
|
+### local — 2026-10-16T18:46:42.632Z
|
|
|
|
|
+【维护者裁定 2026-10-17(5 项,全部采纳推荐项)—— 据此实施】
|
|
|
|
|
+
|
|
|
|
|
+1. **报警范围**:只取未处理报警(`alarm_data.alarm_status = 0`)。已处理的历史流水不参与。
|
|
|
|
|
+2. **承接判据**:`alarm_data.work_order_id` 非空 **且** 该工单未结束(`work_order.order_status ∈ {0,1,2,3,4,6}`,0-based;5 已结案 / 7 已取消为终态)。
|
|
|
|
|
+3. **空集与缺数据**:设备 `alarm` 标志为真但取不到任何未处理报警行(或根本没有 `alarm_data` 行)→ **维持现行序 → ALARM**(「查不到」不等于「已承接」)。
|
|
|
|
|
+4. **聚合与优先级**:**不跟随**。`resolve()` 与枚举 `priority` 不改,前端 `POINT_STATUS_VISUALS.priority` 零改动、无耦合;仅单设备 `deviceStatus()` 按新规则判定。
|
|
|
|
|
+5. **交付边界**:提交并推送 `origin/master`。
|
|
|
|
|
+
|
|
|
|
|
+**本条同时记录一处契约边界(非目标,如实留档)**:`monitoring/situation` 的设备 `metricStatus`(`BusinessCockpitMonitoringSituationAdapter.metricStatus()`)词表为 `NORMAL/WARNING/ALARM/EXPIRED/OFFLINE/UNKNOWN`,**没有 `WORK_ORDER` 桶**,因此本次不改它——改它需要动 situation 响应契约,超出本票范围。
|
|
|
|
|
+
|
|
|
|
|
+### local — 2026-10-16T19:24:28.181Z
|
|
|
|
|
+【实施完成 2026-10-17 —— 已提交并推送 origin/master】
|
|
|
|
|
+
|
|
|
|
|
+**提交**:`3772220e`(本票) + `5d4d03c6`(编译解阻)→ 已推 `origin/master`(`git ls-remote` 核实远端 `master = 3772220e`,本地/远端 0 ahead/0 behind)。推送前远端已有 2 个新提交,已 `git fetch` + `rebase` 后复跑测试再推(未强推)。
|
|
|
|
|
+
|
|
|
|
|
+## 交付
|
|
|
|
|
+判定单源仍是 `CockpitMonitoringPointStatusResolver.deviceStatus()`:
|
|
|
|
|
+报警**且** `isAlarmsCoveredByOpenWorkOrders()` → `WORK_ORDER`,否则维持现行序。
|
|
|
|
|
+
|
|
|
|
|
+事实由 `BusinessCockpitDeviceFactResolver` 新增计算(新增 `AlarmDataService` 依赖):
|
|
|
|
|
+取 `alarm_data.alarm_status=0` 的行,**每一条**都要有 `work_order_id` 且对应工单
|
|
|
|
|
+`order_status ∈ {0..4,6}`;无未处理行 / 任一行不满足 / 读失败 → `false`(保守降级为 ALARM)。
|
|
|
|
|
+
|
|
|
|
|
+**三处透传接缝**(丢任一处结论都会被抹掉,变异 M6/M7 专门钉住):
|
|
|
|
|
+`CockpitMonitoringPointDeviceSnapshot`、分布快照 `SourceSmartDevice` + 分布适配器、
|
|
|
|
|
+`CockpitMonitoringDistributionService.effectiveDevice()` 重建、`CockpitMonitoringPointDetailService` 归一化。
|
|
|
|
|
+
|
|
|
|
|
+## 验证
|
|
|
|
|
+- `Cockpit*Test,BusinessCockpit*Test` **512/512**(基线 510 + 本票新增 2)。
|
|
|
|
|
+- 变异闸 [t52-mutations.mjs](../verify/t52-mutations.mjs) **7/7 打红并按字节还原**;覆盖:判定分支删除、判据放宽为「至少一条」、已结案/已取消算作承接、空集视为已承接、去掉 `alarm_status` 过滤、分布适配器不透传、`effectiveDevice` 重建丢事实。
|
|
|
|
|
+- 真实载荷取证 [real-data-consequence.md](../verify/artifacts/t52/real-data-consequence.md)。
|
|
|
|
|
+- 前端 t09 闸门 **38/38**(priority 与词表零改动,确认裁定 4「不跟随」成立)。
|
|
|
|
|
+
|
|
|
|
|
+## 顺带修复(既有阻塞,非本票引入)
|
|
|
|
|
+`zksy-system` 在 HEAD 上**根本编译不过**:`SseEmitterManager`(`5bc0c6e4` 引入)用 `SseEmitter`,
|
|
|
|
|
+而 `spring-webmvc` 只由 `springfox-spring-webmvc` 以 **provided** 传递(provided 不参与编译期),
|
|
|
|
|
+模块编译期缺类。已按 same-scope 显式声明 `provided` 补齐编译期(`5d4d03c6`);运行期无影响
|
|
|
|
|
+(boot 包 `BOOT-INF/lib` 本就含该 jar)。**未改任何运行语义。**
|
|
|
|
|
+
|
|
|
|
|
+## 既有失败(如实登记,与本票零交集)
|
|
|
|
|
+`zksy-system` 全量另有 **2 失败 / 1 错误**:`AlarmLifecycleServiceTest.insertWritesLogBeforeCommittingWithoutTrigger`、
|
|
|
|
|
+`WorkOrderServiceImplTest.cancelDoesNotWriteSuccessLogWhenStatusChangesConcurrently` / `cancelAllowsOnlyOrdersAwaitingDispatchOrAcceptance`。
|
|
|
|
|
+已把本票源码整体 `git stash` 后复跑,**同样 2 失败/1 错误、逐条相同** → 确认为 HEAD 级既有失败。
|
|
|
|
|
+
|
|
|
|
|
+## 两点如实留档
|
|
|
|
|
+1. **票面举例被证伪**:票面写「实测 21119740 按裁定应为工单处置」。实测该设备 2 条未处理报警
|
|
|
|
|
+ **都没有工单承接**,按裁定**就应当是 ALARM**。票面把设备级 `workOrderInProgress`(该设备存在任意
|
|
|
|
|
+ 未结束工单)误当成了「未处理报警已被逐条承接」——两者不是同一事实。
|
|
|
|
|
+2. **新规则在当前真实数据上不改变任何设备读数**(今天不存在「未处理且已承接」的报警行)。
|
|
|
|
|
+ 这是正确行为而非未生效;待业务侧为未处理报警建单后,该设备才会由 `ALARM` 变 `WORK_ORDER`。
|
|
|
|
|
+
|
|
|
|
|
+## 消费侧影响
|
|
|
|
|
+前端**零改动**(裁定 4):`POINT_STATUS_VISUALS`/`DEVICE_STATUS_VISUALS` 的 `priority`
|
|
|
|
|
+(ALARM 1 / WARNING 2 / WORK_ORDER 3)与后端枚举一致,本次未动枚举。
|
|
|
|
|
+`monitoring/situation` 的 `metricStatus` 词表无 `WORK_ORDER` 桶,仍按现状(已在裁定评论留档为非目标)。
|
|
|
|
|
+
|
|
|
|
|
+## 1. 交付环境(已具备)
|
|
|
|
|
+- 后端仓库:`E:\pipe-ner-server`,远端 `http://192.168.110.30:3000/shaoy/pipe-ner-server.git`,`master = origin/master = 91444f51`(`feat(alarm): 扩展报警指标并重构遥测报警评估逻辑`),工作树干净。
|
|
|
|
|
+- 只读数据库可达:KingbaseES `192.168.110.30:54321 / pipi_ner`(schema `app_user`),已用 psql 直连核对(非只看接口自证)。
|
|
|
|
|
+- 模块:后端代码在 `pipe-network-service/zksy-system`(域)与 `zksy-admin`(控制器+测试)。
|
|
|
|
|
+
|
|
|
|
|
+## 2. 权威链(现状)
|
|
|
|
|
+`CockpitMonitoringPointStatusResolver`(`zksy-system/src/main/java/com/zksy/cockpit/point/`):
|
|
|
|
|
+- `deviceStatus()`:`alarm → warning → workOrderInProgress → online ? NORMAL : OFFLINE`(报警恒压工单)。
|
|
|
|
|
+- 枚举 `CockpitMonitoringPointStatus`:ALARM(1)/WARNING(2)/WORK_ORDER(3)/NORMAL(4)/OFFLINE(5)/EMPTY(6)。
|
|
|
|
|
+- 调用点(改 `deviceStatus` 即全覆盖):`resolve()` 点位聚合(min priority)、`cards()` 设备卡 deviceStatus、`statistics()` 设备统计计数、`orderedDevices()` 排序、`getPublishedDeviceStatus()`(快照/未关联设备 deviceStatus)。
|
|
|
|
|
+
|
|
|
|
|
+事实来源 `BusinessCockpitDeviceFactResolver.resolve()`:
|
|
|
|
|
+- `alarm` = `equipment_status.alarm_status == 1`(设备级报警标志)。
|
|
|
|
|
+- `warning` = `early_warning.status ∈ {PENDING, PROCESSING, HANDLING, RELEASED}`。
|
|
|
|
|
+- `workOrderInProgress` = 该设备**任意**一张 `work_order.order_status ∈ {0,1,2,3,4,6}`(0-based;5 已结案、7 已取消为终态)——**不与报警逐条回联**。
|
|
|
|
|
+
|
|
|
|
|
+## 3. 真实数据(推翻票面前提)
|
|
|
|
|
+`alarm_data` 是**报警历史流水**(同一设备的重复报警会一行一条):
|
|
|
|
|
+
|
|
|
|
|
+| 事实 | 实测 |
|
|
|
|
|
+| --- | --- |
|
|
|
|
|
+| `alarm_data` 全表行数 / 涉及设备 | 90 行 / 仅 `21119740` 一台 |
|
|
|
|
|
+| 未处理(`alarm_status=0`) | 2 行(`BJ202610161600430761`、`BJ202610101851389458`) |
|
|
|
|
|
+| 带 `work_order_id` 的行 | 2 行,**且这 2 行 `alarm_status` 都是 1(已处理)** |
|
|
|
|
|
+| 「未处理 且 已关联工单」的行 | **0 行** |
|
|
|
|
|
+| 已关联工单的两条报警 | `89b53f56…`→WO291(order_status=0 待派单,未结束);`e68a942d…`→WO287(order_status=5 已结案) |
|
|
|
|
|
+| 设备 `21119740` | `equipment_status.alarm_status=1`、`online_status=1`;7 张工单,3 张未结束(291=0、286=1、285=3) |
|
|
|
|
|
+
|
|
|
|
|
+**因此票面「实测设备 21119740(alarm=true, warning=true, workOrderInProgress=true)→ 按裁定应为工单处置(其报警已有工单承接时)」无法成立**:该设备当前的 2 条未处理报警**都没有工单承接**;有工单的那 2 条报警都已经是「已处理」历史记录。
|
|
|
|
|
+
|
|
|
|
|
+## 4. 为什么必须先裁定
|
|
|
|
|
+范围第 1 条要求「明确『所有报警均有对应工单』的判定口径」,范围第 2 条又要求「监测点聚合语义由维护者另行确认」。上述数据事实使这两条**各自都有多种自洽读法、且结果可观测不同**(同一台设备在四种口径下两种判 ALARM、两种判 WORK_ORDER),按纪律不猜。
|
|
|
|
|
+另:`CockpitMonitoringPointStatus` 的 priority 同时驱动点位聚合(min)与前端图例排序(前端 `POINT_STATUS_VISUALS.priority` 与 t09 A3 闸门按此锁定),是否调整属维护者裁定范围。
|
|
|
|
|
+
|
|
|
|
|
+## 5. 尚未动工
|
|
|
|
|
+本轮只做诊断与事实核对,**未改任何后端代码**,未提交、未推送。裁定后按单源(`deviceStatus()`)实施并补契约测试。
|
|
|
|
|
+
|
|
|
|
|
+## Answer
|
|
|
|
|
+
|
|
|
|
|
+**已实施、验证并推送关闭(2026-10-17)。**
|
|
|
|
|
+
|
|
|
|
|
+### 裁定口径(维护者 2026-10-17,5 项)
|
|
|
|
|
+单设备存在报警(`equipment_status.alarm_status=1`)、且该设备**全部未处理报警**
|
|
|
|
|
+(`alarm_data.alarm_status=0`)都满足 `work_order_id` 非空 **且** 对应工单
|
|
|
|
|
+`work_order.order_status ∈ {0,1,2,3,4,6}`(未结束;5 已结案、7 已取消为终态)
|
|
|
|
|
+→ 判 `WORK_ORDER`;否则维持现行序。无未处理报警行 / 任一行不满足 / 读失败 → 保守判 `ALARM`。
|
|
|
|
|
+`resolve()` 聚合与枚举 `priority` **不动**(前端零耦合)。
|
|
|
|
|
+
|
|
|
|
|
+### 交付
|
|
|
|
|
+- 判定单源:`CockpitMonitoringPointStatusResolver.deviceStatus()`。
|
|
|
|
|
+- 事实计算:`BusinessCockpitDeviceFactResolver.alarmsCoveredByOpenWorkOrders()`(新增 `AlarmDataService` 依赖)。
|
|
|
|
|
+- **三处事实透传接缝**(丢任一处结论会被抹掉):`CockpitMonitoringPointDeviceSnapshot`、
|
|
|
|
|
+ 分布快照 `SourceSmartDevice` + `BusinessCockpitMonitoringDistributionAdapter`、
|
|
|
|
|
+ `CockpitMonitoringDistributionService.effectiveDevice()` 重建、`CockpitMonitoringPointDetailService` 归一化。
|
|
|
|
|
+- 提交 `3772220e`(本票)+ `5d4d03c6`(既有编译阻塞修复)→ 已推 `origin/master`(`git ls-remote` 核实远端 = `3772220e`)。
|
|
|
|
|
+
|
|
|
|
|
+### 验证
|
|
|
|
|
+- `Cockpit*Test,BusinessCockpit*Test` **512/512**(基线 510 + 新增 2)。
|
|
|
|
|
+- 变异闸 [t52-mutations.mjs](../verify/t52-mutations.mjs) **7/7 打红并按字节还原**;
|
|
|
|
|
+ 覆盖:判定分支删除、判据放宽为「至少一条」、已结案/已取消算作承接、空集视为已承接、
|
|
|
|
|
+ 去掉 `alarm_status` 过滤、分布适配器不透传、`effectiveDevice` 重建丢事实。
|
|
|
|
|
+- 真实载荷取证 [real-data-consequence.md](../verify/artifacts/t52/real-data-consequence.md)。
|
|
|
|
|
+- 前端 t09 闸门 **38/38**(确认裁定 4「不跟随」成立)。
|
|
|
|
|
+
|
|
|
|
|
+### 两点如实留档
|
|
|
|
|
+1. **票面举例被证伪**:票面写「实测 21119740 按裁定应为工单处置」。实测该设备 2 条未处理报警
|
|
|
|
|
+ **都没有工单承接**,按裁定**就应当是 ALARM**。票面把设备级 `workOrderInProgress`
|
|
|
|
|
+ (该设备存在任意未结束工单)误当成了「未处理报警已被逐条承接」——两者不是同一事实。
|
|
|
|
|
+2. **新规则在当前真实数据上不改变任何设备读数**(今天不存在「未处理且已承接」的报警行)。
|
|
|
|
|
+ 这是正确行为而非未生效;待业务侧为未处理报警建单后,该设备才会由 `ALARM` 变 `WORK_ORDER`。
|
|
|
|
|
+
|
|
|
|
|
+### 既有失败(与本票零交集)
|
|
|
|
|
+`zksy-system` 全量另有 **2 失败 / 1 错误**:`AlarmLifecycleServiceTest.insertWritesLogBeforeCommittingWithoutTrigger`、
|
|
|
|
|
+`WorkOrderServiceImplTest.cancelDoesNotWriteSuccessLogWhenStatusChangesConcurrently` /
|
|
|
|
|
+`cancelAllowsOnlyOrdersAwaitingDispatchOrAcceptance`。已把本票源码整体 stash 后复跑,
|
|
|
|
|
+**同样 2 失败/1 错误、逐条相同** → 确认为 HEAD 级既有失败。
|
|
|
|
|
+
|
|
|
|
|
+### 下一步
|
|
|
|
|
+无。本票交付物已闭环,前端消费侧无需跟随改动。
|
|
|
|
|
+
|