Pārlūkot izejas kodu

docs(uat): 增补 UAT-INT-007 / UAT-INT-008(S8 告警面板与结果 KPI 双轨)

- UAT-INT-007(P1):九宫格 S8 面板读的 ado_s8_alert_record 全仓无写入方,
  现存 2 行属于另一租户/工厂且前端固定传 factoryId=1 因而不可达;
  34 条 ado_s8_exception 从不进面板。附 S1-S7 灰点是诚实展示而非缺陷的说明。
- UAT-INT-008(P2):S8 结果 KPI 监控与 S9 模块 KPI 阈值双轨,口径可互相矛盾;
  当前 5 条结果 KPI 监控均未启用故无实际冲突,待产品决策读取口径。

Co-authored-by: Cursor <cursoragent@cursor.com>
YY968XX 5 dienas atpakaļ
vecāks
revīzija
60282a42f9
1 mainītis faili ar 140 papildinājumiem un 1 dzēšanām
  1. 140 1
      doc/plan/UAT测试/内部UAT测试待办项.md

+ 140 - 1
doc/plan/UAT测试/内部UAT测试待办项.md

@@ -5,7 +5,7 @@
 | 项 | 内容 |
 |----|------|
 | 目录用途 | 内部 UAT 过程中发现、需产品/研发跟进的缺口(不是客户 UAT 用例本身) |
-| 登记日期 | 2026-08-27(首条);2026-09-04 增补 `UAT-INT-002`、`UAT-INT-003`、`UAT-INT-004`;2026-09-06 增补 `UAT-INT-005`、`UAT-INT-006`;2026-09-11 回写 INT-003/004(丙已编码+指南) |
+| 登记日期 | 2026-08-27(首条);2026-09-04 增补 `UAT-INT-002`、`UAT-INT-003`、`UAT-INT-004`;2026-09-06 增补 `UAT-INT-005`、`UAT-INT-006`;2026-09-11 回写 INT-003/004(丙已编码+指南);2026-09-28 增补 `UAT-INT-007`、`UAT-INT-008` |
 | 状态 | 见下方「待办索引」 |
 
 ---
@@ -345,6 +345,143 @@ UAT 时下列现象**符合当前设计**,不要单开缺陷单当页面 bug
 
 ---
 
+## UAT-INT-007 九宫格 S8 面板读的告警表全仓无写入方
+
+| 项 | 内容 |
+|----|------|
+| **责任模块** | **S8 异常监控**(主归属);九宫格看板为唯一展示方 |
+| 功能入口 | 九宫格智慧运营看板 → S8 异常监控面板(`FUNC-S9-005`,`/aidop/smart-ops/grid`) |
+| 发现日期 | 2026-09-28 |
+| 优先级 | P1(面板对所有租户恒空;是否本轮客户验收必修由负责人定) |
+| 性质 | **能力缺口**:检测链路已通,但产出没有接到展示层读的那张表;不是同步失败、不是租户权限、不是指标口径问题 |
+
+### 1. 现象与现状(已核实)
+
+S8 是自成闭环的模块,九宫格里那块 S8 面板是它**唯一的对外露出**。面板三块的数据源分别是:
+
+| 面板区块 | 接口 | 读取对象 | 现状 |
+|----------|------|----------|------|
+| 重点报警信息 | `GET /api/AidopKanban/s8-alerts` | `ado_s8_alert_record` | 恒空 |
+| 7 日异常趋势 | `GET /api/AidopKanban/s8-home-trend` | `ado_s8_alert_record`(同表) | 恒空 |
+| S1–S7 状态点 | 无接口 | 前端硬编码 `s8ModuleStatus` 全 `'unknown'` | **故意如此,非缺陷** |
+
+1. **`ado_s8_alert_record` 全 `server/` 检索零 INSERT。** 命中处只有:`AidopKanbanController.cs` 5 处 `FROM`(全 SELECT)、`UpdateScripts/1.0.349.sql`(租户号重映射)、`1.0.349.verify.sql`(断言备份 ≥ 2 行)。**没有任何写入方。**
+2. 库里仅 2 行,归属 `tenant_id=797403760988230` / `factory_id=797403760988231`。UAT 租户 `838257186181189` 为 **0 行**。
+3. 读取 SQL 带 `AND factory_id=@factoryId`,前端恒传 `factoryId=1`,而那 2 行的 `factory_id` 是雪花号 —— **这 2 行对任何租户都取不到**。故面板对全部租户恒空。
+4. **检测链路本身是通的**:`ado_s8_exception` 有 34 条存活异常(`created_at` 2026-09-21~09-24),`module_code` 分布 S4 = 29、S2 = 3、S1 = 2。真实检出的异常一条都到不了唯一的展示面。
+5. 告警子系统其余表全部 0 行:`ado_s8_alert_channel`、`ado_s8_alert_model`、`ado_s8_rule_model`、`ado_s8_rule_condition`。旁证「告警层设计了但未建」。
+6. S1–S7 状态点:前端注释已记录,原先是从效果图抄来的写死红黄灯(S2=critical / S4=warn / S6=orange),「从不请求、从不更新」;因后端全仓无模块健康服务,已明确改为 `unknown` + 「未监测」。**这是诚实标注,不要当缺陷单开。**
+
+### 2. UAT 提示(符合当前实现,不要单开缺陷)
+
+| 看到的现象 | 归哪 |
+|------------|------|
+| 九宫格 S8 面板报警列表空、趋势图无点 | 本项 |
+| S8 面板 S1–S7 七个灰点、提示「未监测」 | 本项 §1.6,故意如此 |
+| S8 异常列表页(`/aidop/s8/exceptions`)有数据,但九宫格面板没有 | 本项(两者读不同表) |
+| `ado_s9_kpi_value_l1_day` 里 `S8_L1_001/002` 的 `calc_time` 停在很久以前 | **不是缺陷**,见下 |
+
+**`S8_L1_001` / `S8_L1_002` 的陈旧行不是缺陷。** 这两个指标由 `S8KpiSnapshotService.RefreshAsync` 产出,全仓只有 3 个调用方且都是 HTTP 处理器(`home-grid/{moduleCode}`、`detail-kpis/{moduleCode}` 的 `mc=="S8"` 分支、`smart-diagnosis/S8`),**没有定时调用方**。但这两个接口都是「先刷新再读」,所以任何人真正查看这两个指标时拿到的都是新值;表里的旧行只是休眠缓存,不会被当成新数据读出去。**对自成闭环的模块,懒计算是正确设计,不要为此加定时任务。**
+
+### 3. 待决策点(未立项、未编码)
+
+| # | 要拍板的事 |
+|---|------------|
+| 1 | **「报警」是不是「异常」的筛选子集?** 若每条异常都该上面板 → 把两个接口改读 `ado_s8_exception`(改动最小,不需新增写入链路,`created_at`/`severity`/`module_code` 已够用)。若只有达到等级/规则的异常才该报警 → 须补 异常→`ado_s8_alert_record` 的产出链路并先定告警规则。 |
+| 2 | 若走告警链路:规则配在 `ado_s8_alert_model` / `ado_s8_rule_condition`(现均 0 行)还是复用 `ado_s8_watch_rule.severity`。 |
+| 3 | S1–S7 状态点的模块健康源要不要做;若做,权威是谁(全仓现无 module health / system status 服务)。 |
+| 4 | `factory_id` 口径:前端恒传 1,库里是雪花号。见 §4。 |
+
+未决策前 **不改这两个接口的读取对象、不新增告警写入链路**。
+
+### 4. 跨模块影响(实施前须再确认)
+
+| 波及 | 可能影响 |
+|------|----------|
+| 九宫格看板 | S8 面板的条数、等级色、趋势口径 |
+| S8 异常列表 / 详情 | 若改读 `ado_s8_exception`,面板与列表页须同口径(含 `is_deleted`、`exception_code` 非空过滤) |
+| **`factory_id` 全局** | 前端恒传 `factoryId=1` 与库中雪花号不一致,会让**所有**按 `factory_id` 等值过滤的查询落空;本项只记录,影响面未排全,须单独立项 |
+| S8 告警渠道 / 通知 | `ado_s8_notification_log` 已有 34 行,与 `alert_record` 的关系待确认 |
+
+### 5. 明确不做(本项边界)
+
+- 不为 `S8_L1_001/002` 增加定时刷新任务(§2 已说明懒计算正确)。
+- 不把 S1–S7 灰点改回写死的红黄灯。
+- 不在本项做 `factory_id` 口径统一(须单独立项,影响面跨全部模块)。
+- 不在本项改 S8 自身的检测、派工、核实、闭环链路。
+
+---
+
+## UAT-INT-008 S8 结果 KPI 监控与模块 KPI 阈值双轨,口径可互相矛盾
+
+| 项 | 内容 |
+|----|------|
+| **责任模块** | **S8 异常监控**(主归属);S1–S7 / S9 KPI 主数据为对照方 |
+| 功能入口 | S8 监控项配置(`ado_s8_monitor_metric`);智慧运营看板 KPI 主数据(`ado_smart_ops_kpi_master`) |
+| 发现日期 | 2026-09-28 |
+| 优先级 | P2(当前**未激活**,无实际矛盾;一旦启用即产生可见冲突,须先定口径) |
+| 性质 | **架构 / 口径待决**,不是 bug;目前是休眠风险 |
+
+### 1. 现象与现状(已核实)
+
+「S8 监控某模块 KPI 超限」与「该模块自己判该 KPI 超限」,在当前系统里是**两套完全独立的计算**,四个维度都不同:
+
+| | 模块侧(如 S9_L1_003 判超限) | S8 侧 |
+|---|---|---|
+| 值从哪来 | `ado_s9_kpi_value_l1_day.metric_value`,`MdpNightlyFullRebuildJob` 每日 03:40 跑批(S1–S7) | `RATIO` / `DATE` / `VALUE_RANGE` 机制在轮询时现场算 |
+| 阈值配在哪 | `ado_smart_ops_kpi_master` 的 `Direction` + `YellowThreshold` + `RedThreshold` | `ado_s8_monitor_metric` 的 `default_target_ratio` / `default_lower_bound` / `default_upper_bound` / `default_grace_minutes` |
+| 何时判定 | **读取时现算**(`AidopS4KpiMerge.AchievementLevel`) | `S8WatchSchedulerJob` 按 `poll_interval_seconds` 轮询 |
+| 状态翻转 | 无,单次判定 | `trigger_count_required` / `recover_count_required`,连续命中/恢复才翻转 |
+| 指标编码 | `S9_L1_003` | `ORDER_DELIVERY_RATE` |
+
+**两边用互不相通的命名空间,库里没有任何映射表把二者关联** —— 即使都算出数,也无法对账。
+
+### 2. 当前为何尚无矛盾
+
+`ado_s8_monitor_metric` 共 13 条,按 `is_result_kpi` 分成两类:
+
+| 类别 | 条数 | 启用 | 内容 |
+|------|------|------|------|
+| `is_result_kpi=0` 过程型 | 8 | **全部启用** | 计划交付超期、计划到货时间、阶段计划完成时间、阶段偏差天数、计划完工时间、当前库存量、检验值、订单变更次数 |
+| `is_result_kpi=1` 结果 KPI 型 | 5 | **全部 `enabled=0`** | 检验合格率(98)、订单交付满足率(95)、到货达成率(95)、总周期达成率(90)、工单完工率(95) |
+
+启用的 8 条都是**单据级**判定(这一张采购订单行超期),与模块 KPI 的**聚合值**不是同一个东西,因此不构成重复计算。30 条 `ado_s8_watch_rule` 同样都是对象级:`TIMEOUT`/`PURCHASE_ORDER_LINE` 10 条(未启用)、`OUT_OF_RANGE`/`SALES_ORDER_LINE` 10 条(启用)、`SHORTAGE`/`WORK_ORDER` 10 条(启用)。
+
+**一旦启用那 5 条结果 KPI,立刻出现可见矛盾。** 例:`ORDER_DELIVERY_RATE` 目标 95;模块侧 `S9_L1_003` 订单交付满足率 Yellow 95 / Red 80。实际值 90 时 S8 判「低于 95 → 开异常单」,S9 看板判「80 < 90 < 95 → 黄色预警」。同一件事两个结论,且两个 90 还可能不是同一算法算出来的。
+
+### 3. 顺带记录:模块侧阈值仍是初始模板
+
+`ado_smart_ops_kpi_master` 中 32 个 L1 指标只有**两组阈值**:`higher_is_better` 一律 Yellow 95 / Red 80,`lower_is_better` 一律 Yellow 110 / Red 120。从 `lower_is_better` 配 110/120 的形态看,这些应是**达成率百分比**而非业务绝对值(否则「订单评审周期」阈值 110 天讲不通),确认需读 `AidopS4KpiMerge.AchievementLevel` 实现。无论如何,32 个指标共用两组阈值说明这批配置尚未按业务逐个定过。
+
+### 4. 待决策点(未立项、未编码)
+
+| # | 要拍板的事 |
+|---|------------|
+| 1 | **那 5 条结果 KPI 监控的本意是哪种?**(甲)对模块 KPI 做阈值守护 → 不该自己算值也不该自己配阈值,应直读 `ado_s9_kpi_value_l1_day` + `ado_smart_ops_kpi_master`,收口为单一数据源,S8 职责只剩「转红 → 开异常单 → 派工 → 闭环」。(乙)用更严/更实时的口径独立复核 → 两套并存合理,但必须补编码映射表与对账口径。 |
+| 2 | 若选甲:S8 是否还需要 `trigger_count_required` 这类连续命中语义(模块侧无此概念)。 |
+| 3 | 若选乙:`ORDER_DELIVERY_RATE` ↔ `S9_L1_003` 这类映射登记在哪张表,两值不一致时以谁为准。 |
+| 4 | 模块侧 32 个 L1 指标的阈值是否按业务逐个重定(现为两组模板值)。 |
+
+未决策前 **不启用 `is_result_kpi=1` 的 5 条监控项**,也不改任一侧的阈值来源。
+
+### 5. 跨模块影响(实施前须再确认)
+
+| 波及 | 可能影响 |
+|------|----------|
+| S8 | 规则引擎是否改为读 KPI 值表;监控项配置页语义 |
+| S1–S7 / S9 看板 | 若 S8 改读同一阈值,阈值调整会同时改变看板颜色与异常产出 |
+| S9 KPI 主数据 | 阈值成为两个消费方共用,改动影响面变大 |
+| 智慧诊断 | 异常与 KPI 颜色若仍可不一致,诊断结论的可信度 |
+
+### 6. 明确不做(本项边界)
+
+- 不在本项启用那 5 条结果 KPI 监控。
+- 不把 S8 已启用的 8 条单据级监控解释成与模块 KPI 重复。
+- 不在本项重定模块侧 32 个指标的阈值。
+- 不在本项把 S8 异常挂给 S1–S7 的智慧诊断作证据源(S8 自成闭环,不加跨模块耦合)。
+
+---
+
 ## 待办索引
 
 | ID | 标题 | 责任模块 | 状态 |
@@ -355,3 +492,5 @@ UAT 时下列现象**符合当前设计**,不要单开缺陷单当页面 bug
 | UAT-INT-004 | 第三方主动调用我方标准 API 推数入站(方式丙) | **数据中台** | 🔶 编码+指南已落;G1/联调/全量开通见 **P-046** |
 | UAT-INT-005 | 当前 BOM 按标准目录设计,真非标(一单一结构)不适用 | **S0**(S1/S2 协作) | 待讨论 / 待产品决策(未编码,本轮不做) |
 | UAT-INT-006 | S0 运营建模未走数据中台闭环 | **S0**(中台/S1 协作) | 待讨论 / 待产品决策(未编码,本轮不做) |
+| UAT-INT-007 | 九宫格 S8 面板读的告警表全仓无写入方 | **S8** | 待决策读取对象(未编码);面板对全部租户恒空 |
+| UAT-INT-008 | S8 结果 KPI 监控与模块 KPI 阈值双轨,口径可互相矛盾 | **S8**(S9 KPI 主数据对照) | 待产品决策(未编码);当前 5 条结果 KPI 监控未启用,无实际矛盾 |