# 基线卡片 02:工单状态与处置率读模型 > 按决策票 [05 真实联调基线与收口证据门槛](../../issues/05-integration-baseline-and-evidence.md) 的固定骨架产出,对应执行票 [11 工单状态与处置率读模型对齐](../../issues/11-backend-work-order-rate.md)。**状态判定:③ 真实数据联调完成**(2026-10-08 部署后复验通过,见 §4.3;④ 模式整体收口仍待真人验收)。 ## 一、基线 | 项 | 值 | | --- | --- | | 记录时间 | 2026-10-08(本地时钟) | | 记录角色 | 后端执行代理(实施 + 编译 + 契约测试 + 部署后复验) | | 联调环境 baseUrl | `http://192.168.110.96:8301`(**实测可达**) | | 后端仓库 / 分支 / 提交 | `http://192.168.110.30:3000/shaoy/pipe-ner-server` / `master` / **`89ca989`**(含本票口径修订 `3de679c` 与上游 `7df9a87`) | | 运行实例 | PID 26956,启动于 2026-10-08 18:39:11(重启后加载新字节码) | | 后端推送状态 | **已推送**;远端 `master=89ca989` 与本地一致,工作树干净 | | 前端仓库 / 分支 / 提交 | 本票**不涉及**前端(前端消费与 mock 归执行票 14–16) | | 访问控制 | 驾驶舱只读 REST 免鉴权(ADR 0005);实测无凭据 HTTP 200 | | 只读数据源 | 本地联调实例的只读快照;`readOnly: true` | | 目标部署 | `192.168.110.30:8301` **移出本阶段**(不参与状态判定) | ## 二、收口条件五行 | # | 条件 | 状态 | 证据 | 未完成项 | | --- | --- | --- | --- | --- | | ① | 后端提交 / 编译 / 契约测试 | **已完成** | 编译通过;`-Dtest=Cockpit*Test` **299/299 通过**(提交后复跑一致);提交 `3de679c` + `9380c1b` 已推送 `origin/master` | 无 | | ② | 状态筛选与 `MANHOLE` 跨端 | 不在本票范围 | — | 归执行票 12 | | ③ | `createdAt` 数据时间 | 不在本票范围 | — | 归规格 08 / 执行票 12 | | ④ | real 生命周期 | 不在本票范围 | — | 归规格 09 / 执行票 14 | | ⑤ | 真实环境 / 访问控制 / 数据快照 + 走查 | **已完成(后端契约层)** | 部署后复验通过(§4.3):新 `basis` 生效、`sum(0–6)==denominator`、分母≠事件数;免鉴权 200 | 前端 real 走查归执行票 14–16;真人验收归决策票 01 | ## 三、本票交付内容(口径修订) | 项 | 修订前 | 修订后 | | --- | --- | --- | | 分子 | 状态 5 | 状态 5(不变) | | 分母 | 事件总数 | **状态 0–6 工单数之和**(状态 7 取消排除) | | 范围 | 事件范围 | **当前行业/时间范围内全部工单**(按 `work_order.create_time`),不要求关联报警/事件 | | `basis` | `CLOSED_WORK_ORDERS_OVER_TOTAL_EVENTS` | **`CLOSED_WORK_ORDERS_OVER_ELIGIBLE_WORK_ORDERS`** | | 分母 0 的 `reason` | `NO_EVENTS` | **`NO_ELIGIBLE_WORK_ORDERS`**(`state=EMPTY` 不变) | 同口径覆盖三处(用户裁定「三处同族分母一并修订」):`events/handling-efficiency`、`events/history-analysis`(汇总)、`overview/warning-settings`(两 family 共用一份全范围工单读数)。`workOrderStateCounts` / `workOrderStates` 同步改为工单口径,使 `sum(状态 0–6) == denominator` 可被审计复算。历史分析小时桶与预警设置日趋势**仍是事件桶**(口径不同,未改)。 ## 四、实测记录(可复制命令与结果) ### 4.1 联调环境探针(旧口径诊断 + 部署后复验共用) > **注意**:下方原命令把时间窗**写死**为 `2026-09-08 ~ 2026-10-08`,该窗口早已过期,复跑会得到空数据。**部署后请改用 §4.3 的相对窗口命令**(`AddDays(-31)`,永不过期)并按其自洽性判据判定。此处保留原命令与当时结果,是因为它记录的是**诊断时点的实测证据**,不应回改。 ```powershell $base='http://192.168.110.96:8301/api/cockpit/v1' $a = Invoke-WebRequest "$base/events/handling-efficiency?eventFamily=ALARM&startTime=2026-09-08T00:00:00%2B08:00&endTime=2026-10-08T00:00:00%2B08:00" -UseBasicParsing ($a.Content | ConvertFrom-Json).data.summary ``` 结果: | 端点 | 关键实测值 | | --- | --- | | `/events/handling-efficiency?eventFamily=ALARM` | `totalEvents=6`、`handledCount=1`、`denominator=6`(**=`totalEvents`,事件数**)、`basis=CLOSED_WORK_ORDERS_OVER_TOTAL_EVENTS`;`workOrderStateCounts` 为 `0=1, 5=1`(**旧口径按事件回联累加**,不能据此反推新分母——见 §4.3 勘误) | | `/events/handling-efficiency?eventFamily=WARNING`(近 31 天) | `totalEvents=4`、`denominator=4`(事件数)、`handledCount=0` | | `/events/handling-efficiency?eventFamily=WARNING`(默认窗口) | `totalEvents=0`、`denominator=0`、`state=EMPTY`、`reason=NO_EVENTS` | **口径错误已被真实数据复现**:旧实例 `denominator=6` 等于 `totalEvents`,而按新口径分母应为**范围内全部状态 0–6 工单数**(此窗口内当次 `workOrderStateCounts` 仅给出**事件回联**的 `0=1, 5=1`,不等于新口径分母;见 §4.3 勘误)。旧口径把「事件数」当分母即错,无需依赖具体数值即可判定。 ### 4.2 修订后:本地编译与定向契约测试 ```powershell cd E:\pipe-ner-server mvn -o -pl pipe-network-service/zksy-admin -am compile mvn -o -pl pipe-network-service/zksy-admin -am test "-Dtest=Cockpit*Test" "-DfailIfNoTests=false" "-Dsurefire.failIfNoSpecifiedTests=false" ``` 结果:编译通过;`Tests run: 299, Failures: 0, Errors: 0, Skipped: 0`(`BUILD SUCCESS`)。本票新增/改写的针对性覆盖: - **0–7 字典**:`dictionaryMatchesTheRuntimeWorkOrderStatusEnumCodeForCode` 逐码逐名比对运行时 `WorkOrderStatusEnum`,并锁 8 态。 - **分母含状态 6**:`rateDenominatorIncludesDelayingStateSixAndExcludesCancelledSeven`(5/6/7/7 → 分母 2、分子 1、`0.5000`)。 - **状态 7 排除**:同上 + `cancelledWorkOrdersAreExcludedFromTheRateDenominator`(全为 7 → 分母 0 → `EMPTY`)。 - **分母 0**:`emptyWindowReportsEmptyEfficiencyAndDurationStates`(`NO_ELIGIBLE_WORK_ORDERS`)。 - **分子 5**:`summaryNumeratorAndDenominatorMatchTheReportedStateDistribution`(自洽复算)。 - **分母与事件解耦**:`rateIsAvailableFromWorkOrdersEvenWhenNoEventsFallInTheWindow`(窗口内无事件仍算出处置率)。 - **两 family 共用**:`bothFamiliesShareTheSameWorkOrderScopedRate`(overview service 层)。 ### 4.3 联调环境复验(**已执行,通过 — 2026-10-08**) **部署依据**:`origin/master = 89ca989`(含本票口径修订 `3de679c` 与上游 `7df9a87`);运行进程 PID 26956,启动于 18:39:11(重启后加载新字节码)。复验票据:[17 部署后真实环境复验](../../issues/17-postdeploy-live-verification.md)。 **复验结果(新口径已生效)**: | 请求 | basis | num/den | value | state | 自洽性 | | --- | --- | --- | --- | --- | --- | | `events/handling-efficiency?eventFamily=ALARM`(近 31 天) | `CLOSED_WORK_ORDERS_OVER_ELIGIBLE_WORK_ORDERS` | 2/3 | `0.6667` | AVAILABLE | `sum(0..6)=3`==分母,`totalEvents=6`≠分母 ✓ | | 同上 `?eventFamily=WARNING` | 同上 | 2/3 | `0.6667` | AVAILABLE | 工单范围与 family 无关(符合决策 06)✓ | | `events/history-analysis?eventFamily=WARNING` | (无 basis 字段) | 汇总 2/3 | `0.6667` | AVAILABLE | 行级仍 `reason=NO_EVENTS`(事件桶未变)✓ | | `overview/warning-settings` | (无 basis 字段) | warning 2/3、alarm 2/3 | `0.6667` | AVAILABLE | 两 family 同源;事件计数各算(10 / 6)✓ | `stateCounts` 实测为 `1=1, 5=2`(分母 3 = 状态 1 的 1 张 + 状态 5 的 2 张;状态 7 无工单)。 **对照(部署前同请求,旧口径)**:`basis=CLOSED_WORK_ORDERS_OVER_TOTAL_EVENTS`、`num/den=1/6`、`value=0.1667` —— 分母恰等于 `totalEvents`,即旧口径把事件数当工单分母。修正确已生效。 **数据稀疏事实(如实记录,不当作缺陷)**:`work_order` 表仅 3 行(状态 1×1、5×2),故分母为 3。样本极小,本节只验证**口径与自洽性**,不宣称统计意义;真人验收仍按决策票 01 执行。 > **勘误留存(2026-10-08)**:本卡片早先版本写「重新部署后应期望 ALARM 组 `denominator=2`、`value=0.5000`」,**该预期错误**。那个 2 由**旧响应**的 `stateCounts`(`0=1, 5=1`)反推;但旧 `stateCounts` 只统计**已关联报警**的工单(未关联者 `continue` 跳过)且按事件累加,而新口径分母取自 `scopeWorkOrders`(范围内**全部**工单,含未关联报警者)。两者基数不同,不可互推 —— 实测分母为 3(全部工单),并非 2。判据应为**自洽性**(`sum(0–6) == denominator` 且分母 ≠ 事件数),而非固定数值。 **复验用命令(可复制,窗口相对当前时间、永不过期)**: ```powershell $base='http://192.168.110.96:8301/api/cockpit/v1' $end=(Get-Date).ToString('yyyy-MM-ddTHH:mm:sszzz'); $start=(Get-Date).AddDays(-31).ToString('yyyy-MM-ddTHH:mm:sszzz') $r = Invoke-RestMethod "$base/events/handling-efficiency?eventFamily=ALARM&startTime=$([uri]::EscapeDataString($start))&endTime=$([uri]::EscapeDataString($end))" $s = $r.data.summary "basis = $($s.handlingEfficiency.basis)" # 期望 CLOSED_WORK_ORDERS_OVER_ELIGIBLE_WORK_ORDERS "num/den= $($s.handlingEfficiency.numerator)/$($s.handlingEfficiency.denominator)" "events = $($s.totalEvents)" # 分母必须 ≠ 事件数 ($r.data.workOrderStateCounts | Where-Object { $_.stateCode -ge 0 -and $_.stateCode -le 6 } | Measure-Object -Property count -Sum).Sum # 期望 == denominator ``` ### 4.4 部署窗口内的真实环境故障(已解决,如实登记) 复验前的重启窗口内曾出现 **5 个只读端点 500**(`events/*` 与 `overview/warning-settings`)。根因是**数据库表结构重构与 Java 层不匹配**:`app_user.equipment_warning_type` 已重构为关联表(`equipment_type_id` + `warning_type_id`),元数据移到新表 `app_user.warning_type`;`app_user.alarm_data.warning_type` 列已删除。 该重构由上游 `7df9a87「优化报警管理」` 完整修复(新增 `EquipmentWarningType` 实体、`AlarmData` 去 `warning_type`、`WarningThresholdServiceImpl` 与 4 个 XML mapper 一并改到新结构)。本会话曾基于落后基点做局部修复,发现上游已有完整解后已废弃该分支并跟随 master。**教训:复验前必须先 `git fetch` 确认远端基线。** | 判据 | 期望 | | --- | --- | | `basis` | `CLOSED_WORK_ORDERS_OVER_ELIGIBLE_WORK_ORDERS` | | `sum(workOrderStateCounts[0..6])` | **== `denominator`**(自洽,可复算) | | `denominator` | **≠** `totalEvents`(不再是事件数) | | 分母 0 时 | `state=EMPTY` + `reason=NO_ELIGIBLE_WORK_ORDERS` | 不得以「分母等于某个具体数字」作为通过条件 —— 分母随真实工单数据变化。 ## 五、真人验收 **未执行。** 本卡片不宣称任何人工验收结论。真实设备报警闭环仍按决策票 01 由真人团队执行。 ## 六、未完成项与补齐条件 1. ~~**部署后复验**~~:**已完成**(§4.3,2026-10-08):新 `basis` 生效、`sum(0–6)==denominator`、分母≠事件数。由 [票 17](../../issues/17-postdeploy-live-verification.md) 承载并已回写。 2. **前端消费与 mock 对齐**:前端 `contractMocks.js` 的 `denominator = total`(事件数)与 `reason: 'NO_EVENTS'`,以及 `handlingRateHint()` 文案「…没有可参与计算的事件…」仍为旧口径 → 补齐条件:归执行票 14–16(规格 10 已把该文案改动划在前端域)。 3. **真人验收**:未执行 → 补齐条件:按决策票 01 由真人团队用真实设备报警走完整流程。 ## 七、状态判定 **当前状态:③ 真实数据联调完成(2026-10-08 达成)。**(④ 模式整体收口仍待真人验收。) 依据:编译通过 + 299/299 定向契约测试通过(提交后复跑一致),且**部署后真实环境复验通过**(§4.3)—— `events/handling-efficiency` 回新 `basis=CLOSED_WORK_ORDERS_OVER_ELIGIBLE_WORK_ORDERS`、`num/den=2/3`、`sum(状态0–6)=3`==分母、`totalEvents=6`≠分母;`history-analysis` 汇总同步为新口径而小时桶仍事件桶;`overview/warning-settings` 两 family 共用同一份工单范围读数。三项判定均符合 [票 17](../../issues/17-postdeploy-live-verification.md) 的事前期望。 **不进入 ④ 的原因**:④ 要求「该模式全部面板 + 地图 + 推送在真人验收下通过」—— 本卡片只覆盖「工单状态与处置率」这一后端切片,前端 real 生命周期接线(执行票 14–16)与真人设备报警闭环(决策票 01)尚未发生。 **提交事实**:`3de679c`(本票口径修订,14 文件)+ `9380c1b`(**非本票**:修复 `HEAD` 中 `CockpitFreshnessSemanticsControllerTest.java` 未闭合语句导致 `zksy-admin` 测试模块无法编译,与本票口径无关,单独成提交便于审计)→ `git push origin master`,`5b53a6d..9380c1b`;其后上游 `7df9a87`(报警管理重构,已完整修复 warning 表结构漂移所致的 500)与合并提交 `89ca989` 构成当前复验基线。 ## 部署窗口内的故障记录(已解决) 见 §4.4:重启窗口曾出现 5 个只读端点 500,根因是数据库表结构重构(`equipment_warning_type` 改关联表、`alarm_data.warning_type` 删列)与 Java 层不匹配,由上游 `7df9a87` 完整修复。本会话基于落后基点做过的局部修复已废弃(分支未推送、无损失)。 ## 八、关联 - 本图执行票:[11 工单状态与处置率读模型对齐](../../issues/11-backend-work-order-rate.md) - 复验承载:[17 部署后真实环境复验](../../issues/17-postdeploy-live-verification.md) - 上游决策:[01 报警—工单闭环读模型与 Gogs 票拆分边界](../../issues/01-backend-slice-ticket-boundary.md)、[05 真实联调基线与收口证据门槛](../../issues/05-integration-baseline-and-evidence.md)、[06 异常统计、工单处置率与管理字段词汇](../../issues/06-cross-mode-business-semantics.md) - 规格:[10 业务语义规格](../../issues/10-business-semantics-spec.md) - 下游:执行票 [12 报警/工单读模型与 district](../../issues/12-backend-read-model-district.md)、前端票 14–16 - 上位台账:[票 25 后端契约缺口待办](../../../cockpit-shell-panel-layout/issues/25-backend-contract-gaps.md)、Gogs #63