Pārlūkot izejas kodu

docs(wayfinder): close 74 — 预警效率端点分族契约已交付(后端 983fc27a)

- 票 74:补方案/实施/真实复验/Answer,Status: resolved、Assignee: codex
- map:任务清单打勾 + 新增前端消费票 78;Decisions so far 追加本票 gist
- 新增票 78:前端消费预警自身处置流程(ready-for-agent,后端未部署)
- 证据:verify/artifacts/t74/ 三份真实载荷(预警族 / 报警族 / 未改动基线对照)

后端提交 983fc27a 已推 pipe-ner-server origin/master(不在本仓)。
本提交只摘本票 hunks;map.md 里 73 票的那处改动属并行会话在制品,未纳入。
ChenJZ 10 stundas atpakaļ
vecāks
revīzija
fabd7dd72a

+ 105 - 3
.scratch/cockpit-real-data-wayfinding/issues/74-warning-efficiency-backend-contract.md

@@ -1,9 +1,10 @@
 # 后端执行票 —— 预警效率端点缺预警自身处置流程字段(两族回同一套工单口径)
 
-Status: ready-for-agent
+Status: resolved
+Assignees: codex
 Type: task
 Blocked by: None
-Labels: wayfinder:task
+Labels: wayfinder:task, ready-for-agent
 Category: backend-contract
 
 ## 来源
@@ -84,8 +85,109 @@ Category: backend-contract
 ## 进度
 
 - 2026-10-21 由票 65 收口时另立(前端侧已完成诚实分流并记录缺口;本票未动工)。
+- 2026-10-23 开工(本会话)。认领;基点=后端 `origin/master` `f36f10dd`(本地 master 与远端一致)。
+  按本图既有成例(票 29/30)在工作区内建隔离副本 `.scratch/cockpit-real-data-wayfinding/implementation/t74/validation-checkout/`(含 `.git`,`reset --hard origin/master` 得干净树;宿主沙箱不允许写工作区外路径,故不用 `git worktree add E:\...`,共享工作树的并行在制品也未触碰)。
 
-## Comments
+### 方案(落地口径)
+
+**读路径**:`BusinessCockpitEventAdapter.loadHandlingEfficiency()` 的 `SourceWarning` 原先只带编号/等级/发布时间/类型/设备,
+预警自身流程在快照里**整条缺失**。新增 `status`(`WarningWorkflow` 六态)与 `updateTime`(解除时刻来源)两个字段,
+旧 6 参构造器保留为委托重载(票 41 成例),由适配器从 `EarlyWarning.getStatus()` / `getUpdateTime()` 填。
+
+**响应形状**(按票面建议契约,落点对称于既有工单口径字段):
 
+| 位置 | 报警族 | 预警族 |
+| --- | --- | --- |
+| `workOrderStateCounts`(8 桶) | 原样 | **`null`** |
+| `warningStateCounts`(新增,六态) | **`null`** | 六态全铺(缺桶计 0),脏状态补 `UNKNOWN` 桶 |
+| `summary.handledCount/inProgressCount/cancelledCount` | 原样 | **`null`** |
+| `summary.handlingEfficiency` | 原样(工单口径) | **`null`** |
+| `summary.averageDuration` | 原样(工单结案时长) | **`null`** |
+| `summary.warningHandlingEfficiency`(新增) | **`null`** | 已解除 ÷ 窗口内预警数;分母 0 → `EMPTY`+`NO_WARNINGS` |
+| `summary.warningDuration`(新增) | **`null`** | 发布→已解除平均时长;无样本 → `EMPTY`+`NO_CLOSED_WARNINGS` |
+| `durationTrend[]` | 原样 | `eventCount` 保留(真实发布量),`handledCount`/`averageDuration` **`null`**(工单口径,预警族不适用) |
+
+三条与票面建议的**偏离**(都写理由,可被一句话推翻):
+1. **票面只点 3 个工单口径字段 null,本票扩到 6 个**:`handledCount/inProgressCount/cancelledCount` 与 `durationTrend` 的
+   `handledCount/averageDuration` 同样是 `scopeWorkOrders` 派生的工单读数(票面自己的表格已写明「工单状态派生」)——
+   留着它们就是同一个谎言换个字段名(「预警处置中 = 1」正是 `inProgressCount` 产生的)。
+2. **不做 `warningStatusTrend`**:它的「按桶发布量」与 `durationTrend[].eventCount` 是同一份的数,
+   同一响应里放两条序列就是第二份口径;已解除量可由 `warningHandlingEfficiency` 与逐条状态得出。
+   若将来确实要按桶的已解除趋势,应**替换**预警族的 `durationTrend`(改名换语义),而不是并列再加一条。
+3. **已解除时刻取 `early_warning.update_time`**:该表没有单独的解除时间列;`clearWarning()` 在置 `CLOSED` 的同一次写入里
+   显式 `setUpdateTime(now)` 且 `CLOSED` 是终态无后续业务动作,故 CLOSED 行的 `update_time` 即解除时刻。
+   这是**有前提的读数**,`warningDuration` 的 `basis` 与源码注释都写明来源,不假装是独立采集的时间戳。
+4. 处置率分母=**窗口内预警条数**(与 `summary.totalEvents` 同一集合、随 industry/level 收敛),不是全库快照;
+   与 `overview/warning-settings`(全量快照、不随窗口收缩)**刻意不同**,因为本端点本就是带窗口的。
+
+### 实施(2026-10-26 完成)
+
+**改动(5 文件,+498/−137)**:
+| 文件 | 改动 |
+| --- | --- |
+| `CockpitHandlingEfficiencySnapshot` | `SourceWarning` 增 `status`/`updateTime`,旧 6 参构造器改为委托重载 |
+| `BusinessCockpitEventAdapter` | `efficiencyWarnings()` 把 `getStatus()`/`getUpdateTime()` 填进快照 |
+| `CockpitHandlingEfficiencyResponse` | 顶层增 `warningStateCounts`(`WarningStateCount`)、`Summary` 工单口径三计数改 `Integer` 可空并增 `warningHandlingEfficiency`/`warningDuration`、`DurationPoint.handledCount` 改可空 |
+| `CockpitHandlingEfficiencyService` | `build()` 按族分支聚合;新增 `warningEfficiency`/`warningStateRows`/`warningAverageDuration`/`warningDurationHours`/`normalizeWarningStatus`;`durationTrend` 预警族只给 `eventCount` |
+| `CockpitHandlingEfficiencyControllerTest` | 契约测试重写:预警组(六态/已解除率/时长/null 纪律)+ 脏状态 UNKNOWN 桶 + 空窗口 EMPTY;原工单口径用例整体迁到 ALARM 族,样本改用报警事件,覆盖不丢 |
+
+**验证**:
+- 编译:`mvn -o -pl pipe-network-service/zksy-system -am compile` 通过。
+- 契约测试:`-Dtest=Cockpit*Test,BusinessCockpit*Test` → **540/540**、`BUILD SUCCESS`。
+  (本机沙箱禁止 surefire fork 子进程,故加 `-DforkCount=0` 在同一 JVM 跑;该模式进程 CWD 是 reactor 根,
+  导致 `CockpitAnonymousAccessSecurityConfigTest` 的 `..\zksy-framework\...` 相对路径找不到文件,
+  因此按原路径在 `implementation/t74/zksy-framework/` 放了一份同字节副本作为执行环境垫片——只影响本机跑法,不入库
+  (收尾已删除;复跑时按 `mkdir -p implementation/t74/zksy-framework/src/main/java/com/zksy/framework/config && cp .../SecurityConfig.java` 重建即可)。
+  正式 CI 的 forking 跑法不受影响,该测试源码零改动。)
+- **真实环境复验(第二实例,真实库)**:在本机 8399 起第二实例(拉 nacos 配置落成本地副本以覆盖端口;
+  `-Dfile.encoding=UTF-8` 修 nacos YAML 解码、`-Dcsp.sentinel.log.dir` 指向工作区内以避开沙箱写限制),
+  连同一联调库(`192.168.110.30:54321/pipi_ner`)实测窗口 `2026-09-23T00:00+08:00 ~ 2026-10-23T00:00+08:00`:
+
+  | 读数 | 实测值 | 说明 |
+  | --- | --- | --- |
+  | `summary.totalEvents` | 7 | 与改动前构建同值(基线对照见下) |
+  | `summary.linkedWorkOrderCount` | **0** | 预警不挂工单,与本票立票依据一致 |
+  | `warningStateCounts` | PENDING 3 / PROCESSING 1 / CLOSED 3,其余桶 0 | **真实六态分布,和=7=totalEvents** |
+  | `summary.warningHandlingEfficiency` | `3/7 = 0.4286`,`state=AVAILABLE`,`basis=CLOSED_WARNINGS_OVER_WINDOW_WARNINGS` | 预警自身口径 |
+  | `summary.warningDuration` | `0.64` 小时,`sampleCount=3` | 三条已解除的发布→解除时长 |
+  | 工单口径 6 字段 | 全 `null` | `handledCount/inProgressCount/cancelledCount/handlingEfficiency/averageDuration/workOrderStateCounts` |
+  | 报警族同窗口 | `handledCount=4 / inProgressCount=11 / cancelledCount=1`、处置率 `4/15=0.2667`、八态齐、`warning*` 全 `null` | 报警族原样保留 |
+
+  **基线对照(排除「改动动了事件口径」的怀疑)**:把改动摘掉、用同一份 `origin/master` `f36f10dd` 重新构建并起在 8398,
+  同窗口预警族 `totalEvents` 同为 **7**、工单读数同为 4/11/1(0.2667),只是没有 `warning*` 段 ——
+  证明本票是**纯新增 + null 保真**,事件计数与工单口径零漂移。部署中的 `8301` 同窗口回的是 **14**:
+  那是**更旧的部署构建**(上游 4 个提交之前,设备/行业收敛范围更宽),差额来自部署落后于 `origin/master`,与本票无关。
+  证据落盘(本图 `verify/artifacts/` 成例):[warning-family-live.json](../verify/artifacts/t74/warning-family-live.json)、
+  [alarm-family-live.json](../verify/artifacts/t74/alarm-family-live.json)、[baseline-warning-family-live.json](../verify/artifacts/t74/baseline-warning-family-live.json)。
+
+**入库**:rebase 到 `origin/master` `05e9e93d`(上游 4 个提交均未触碰本票文件,无冲突;警告:本机 git 的
+nacos/bootstrap 配置差异不影响)后复跑 **540/540**,提交 **`983fc27a`** 已推 `origin/master`(`05e9e93d..983fc27a`),
+`git ls-remote origin refs/heads/master` 实测=`983fc27a`。
+
+**边界 / 下一步**:
+- **改动未部署**:`192.168.110.96:8301` 仍是旧构建,新字段上线后才可见。
+- 真实库里有 16 条 `CLOSED` 预警的 `publish_time` 为 `null`(历史数据),窗口内只 6 条可算、其中 3 条落在行业范围内,
+  故 `warningDuration.sampleCount=3`;这是**数据事实**,不是聚合丢样本。
+- 前端消费另立[票 78 —— 预警效率面板消费预警自身处置流程](78-kpi.md):只替换 `warningEfficiencyKpis` 的三个计数、补一块六态分布,块结构不动。
+
+## Comments
 
 ## Answer
+
+**已实施、测试、真实环境复验并推送关闭(2026-10-26)**。提交 **`983fc27a`** 已推 `origin/master`(`05e9e93d..983fc27a`)。
+
+**做了什么**:`events/handling-efficiency` 按事件族分流。预警族改吃**预警自身处置流程**
+(`warningStateCounts` 六态全铺、`summary.warningHandlingEfficiency` 已解除÷窗口内预警数、
+`summary.warningDuration` 发布→已解除平均时长),工单口径六字段(含 `durationTrend` 的
+`handledCount`/`averageDuration`)在预警族**显式为 `null`**;报警族工单口径原样保留,其 `warning*` 段为 `null`。
+读路径补 `SourceWarning.status/updateTime`(旧 6 参构造器保留为委托重载)。
+
+**真实数据实测**(本机第二实例连同一联调库,窗口 2026-09-23~2026-10-23):`linkedWorkOrderCount=0`、`totalEvents=7`、
+六态 `PENDING 3 / PROCESSING 1 / CLOSED 3`(和=7)、已解除率 `3/7=0.4286`、时长 `0.64h`(3 样本);
+报警族同窗口 `4/11/1`、处置率 `4/15=0.2667`、八态齐。同窗口**未改动基线构建**预警族 `totalEvents` 同为 7、
+工单读数同为 4/11/1 → 本票是纯新增 + null 保真,事件与工单口径零漂移(部署中的 8301 回 14 属更旧构建,与改动无关)。
+
+**验证**:`Cockpit*Test,BusinessCockpit*Test` **540/540**(本机 `-DforkCount=0` 执行;进程 CWD 垫片只为本机跑法,不入库)。
+
+**边界**:改动**未部署**;真实库 16 条 `CLOSED` 预警缺 `publish_time`,窗口内仅 6 条可算、其中 3 条在行业范围内,
+故 `warningDuration.sampleCount=3`(数据事实,非丢样本)。前端消费见[票 78](78-kpi.md)。

+ 63 - 0
.scratch/cockpit-real-data-wayfinding/issues/78-kpi.md

@@ -0,0 +1,63 @@
+<!-- DSH-IDEMPOTENCY-KEY: warning-efficiency-frontend-consume-v1 -->
+<!-- parentKey: 00 -->
+<!-- created: 2026-10-26T01:27:33.066Z -->
+# 前端执行票 —— 预警效率面板消费预警自身处置流程(三张 KPI 换成条数/已解除率/平均处置时长)
+
+## Question
+
+票 74 已把后端契约补上(提交 `983fc27a` 已推 `origin/master`,**尚未部署**):`GET /api/cockpit/v1/events/handling-efficiency?eventFamily=WARNING` 现在回预警自身的处置流程段,票 65 当时记录的契约缺口不复存在。本票是那张缺口关闭后的**前端消费票**(票 74 验收第 5 条明令另立)。
+
+### 后端新契约(票 74,已实测)
+
+| 位置 | 预警族 | 报警族 |
+| --- | --- | --- |
+| `warningStateCounts` | `[{stateCode, stateName, count}]`,`WarningWorkflow` 六态全铺(缺桶计 0),脏状态进 `UNKNOWN` 桶 | `null` |
+| `summary.warningHandlingEfficiency` | `{value, numerator, denominator, state, reason, basis}`,已解除 ÷ 窗口内预警数;分母 0 → `state=EMPTY` + `reason=NO_WARNINGS` | `null` |
+| `summary.warningDuration` | `{value, unit, sampleCount, state, reason}`,发布→已解除平均时长;无样本 → `EMPTY` + `NO_CLOSED_WARNINGS` | `null` |
+| `summary.handledCount/inProgressCount/cancelledCount`、`handlingEfficiency`、`averageDuration`、`workOrderStateCounts` | **全部 `null`** | 原样 |
+| `durationTrend[]` | `eventCount` 保留,`handledCount`/`averageDuration` 为 `null` | 原样 |
+
+真实环境实测(第二实例 8399,同一联调库,窗口 2026-09-23 ~ 2026-10-23):`totalEvents=7`、`linkedWorkOrderCount=0`、六态 `PENDING 3 / PROCESSING 1 / CLOSED 3`(和=7)、已解除率 `3/7=0.4286`、时长 `0.64h`(3 样本)。证据:`verify/artifacts/t74/warning-family-live.json`(票 74 落盘)。
+
+### 本票要做的
+
+1. `toHandlingEfficiency()` 读新字段(`warningStateCounts` / `summary.warningHandlingEfficiency` / `summary.warningDuration`),**null 保真**(不把 null 数成 0;票 42/票 20 同一纪律)。
+2. `warningEfficiencyKpis()` 三张卡换成预警自身读数:**预警条数 / 已解除率 / 平均处置时长**(块结构不重排,票 65 已预留接缝)。
+3. 预警模式补「预警状态分布」块(六态,用 `barsBlock` 或既有分布块,词表取 `WarningWorkflow` 中文名,**不在前端另造一套状态词**)。
+4. `WARNING_EFFICIENCY_GAP` 这段「后端尚未提供」的口径说明**必须改写**——缺口已补,留着就是谎话;新文案说清「这些数是预警自身的处置流程统计」与已解除率的分母。
+5. `contractMocks.js` 的 efficiency mock 同步新形状(含 `EMPTY`/`NO_WARNINGS` 空态),静态样例仍遵守本图 Notes 的「不为演示改写样例」裁定。
+6. 闸门 t65(51/51 现役)按新契约改写/扩条:预警族 null 纪律、六态和=条数、空态原因码、报警族零回归。
+
+## 非目标
+
+- 不动后端(票 74 已交付)。
+- 不改报警族工单口径与工单列表(票 65 已收口)。
+
+## 验收
+
+1. 预警模式下三张 KPI=条数 / 已解除率 / 平均处置时长,读数与后端回显一致;空态走占位符不画假 0。
+2. 预警状态分布六态与响应一致(含 0 桶),脏状态进「未知」。
+3. 报警模式零回归(t65 既有断言全绿)。
+4. `WARNING_EFFICIENCY_GAP` 不再声称「后端未提供」。
+5. 后端**部署后**在 `http://127.0.0.1:8000/#/cockpit` 走查预警模式三卡与分布块(走查归票 18 联调窗口;本机 mock 可先验形状)。
+
+## 关联
+
+- 上游:[票 74 —— 预警效率端点缺预警自身处置流程字段](74-warning-efficiency-backend-contract.md)(后端已交付 `983fc27a`)。
+- 前身:[票 65 —— 预警效率面板按预警/报警分流](65-untitled.md)(当时只做诚实分流 + 记缺口)。
+- 同族纪律:[票 41](41-warning-settings-endpoint-rework.md)(预警族 null 保真)、[票 42](42-42.md)(缺失不画假 0)。
+
+## 进度
+
+<!-- 做到哪一步了,在这里一行一行记 -->
+
+Status: ready-for-agent
+Type: task
+Blocked by:
+Labels: wayfinder:task, ready-for-agent
+
+## Comments
+
+
+## Answer
+

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 4 - 1
.scratch/cockpit-real-data-wayfinding/map.md


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
.scratch/cockpit-real-data-wayfinding/verify/artifacts/t74/alarm-family-live.json


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
.scratch/cockpit-real-data-wayfinding/verify/artifacts/t74/baseline-warning-family-live.json


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
.scratch/cockpit-real-data-wayfinding/verify/artifacts/t74/warning-family-live.json


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels