|
|
@@ -0,0 +1,198 @@
|
|
|
+# T04-S2-GATE-2 合入后门槛终验报告(只读,无 DDL 无数据写入)
|
|
|
+
|
|
|
+**任务**:T04-S2(第二段 report-detail.vue 改造,commit e740b212d)合入 cfclub 主线后,按规格 §2873-2933 三条只读 SELECT 做上线门槛终验。
|
|
|
+**执行时间**:2026-10-31
|
|
|
+**执行环境**:`D:\cfc\.wt-t04s2g2`(worktree,detached HEAD @ `origin/cfclub` = b31b90cb5)
|
|
|
+**前置校验**:`git merge-base --is-ancestor e740b212d origin/cfclub` → exit 0(✅ e740b212d 确在 origin/cfclub 中;ab797e2e4 之后 cfclub 又有 8edc2d7b0/b31b90cb5 等后续提交)
|
|
|
+**数据库**:192.168.16.251:3306/zxyj(MySQL 5.7.44,测试库,只读)
|
|
|
+**声明**:全程仅执行 SELECT,无 ALTER/INSERT/UPDATE/DELETE,无新迁移,未改 schema.sql,未改代码。数据取自真实测试库。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1. 门槛判定结果(总览)
|
|
|
+
|
|
|
+| 级别 | 指标 | 门槛 | 实测值 | 判定 |
|
|
|
+|---|---|---|---|---|
|
|
|
+| **L1** | 报告级时序覆盖率 | **≥ 0.85** | **0.5000(6/12)** | ❌ **FAIL** |
|
|
|
+| **L2** | 成员可用率 | **≥ 0.90** | **1.0000(1/1)** | ⚠️ **PASS(但分母仅 1,见 §4)** |
|
|
|
+| **L3a** | 20 份 gut_flora 抽样:每份 ≥90% 可 mapping 数值指标都有 ≥1 期观测 | 全部达标 | **6/20 达标,14/20 不达标** | ❌ **FAIL** |
|
|
|
+| **L3b** | 无一份被误判为全部「首次记录」 | 0 份误判 | **0 份误判** | ✅ **PASS** |
|
|
|
+
|
|
|
+**总体判定:未达标 → 不建议放行第二段,须先补 backfill。**
|
|
|
+
|
|
|
+上一次开发前验算(T04-S2-GATE,2026-10-27,origin/verify/t04-s2-gate):L1=0.6000 (6/10)、L2=0.5000 (1/2)、L3a=15/20 不达标。本次合入后终验:**L1 由 0.60 降至 0.50**(新增 2 份无观测报告 49/50 进分母),**L2 由 0.50 升至 1.00**(subject 8 的 4 份历史报告仅有 1 个 distinct report_date,按新口径不进 L2 分母,详见 §3.2),**L3a 仍 14/20 不达标**。三项中 L1/L3a 不达标,**未达"全部满足"的放行条件**。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 2. 数据规模事实(先说明:测试库样本极小,读数值需知此背景)
|
|
|
+
|
|
|
+| 指标 | 值 |
|
|
|
+|---|---|
|
|
|
+| health_reports 总行数 | **22**(全部 `status='active'`,全部 `report_type='gut_flora'`) |
|
|
|
+| active 且有 `subject_id IS NOT NULL` 的报告 | **12** |
|
|
|
+| subject_id IS NULL 的报告 | 10 |
|
|
|
+| indicator_values 总行数 | **271** |
|
|
|
+| 有观测的健康报告 | 7(rid 18/19/20/21/28/29 + rid 16/17 的观测指向不存在报告,见 §5) |
|
|
|
+| indicator_definitions | 129(status=1:102 个,其中 value_type='numeric' 102 个;status≠1:27 个) |
|
|
|
+
|
|
|
+> **重要前置**:Q1 的 12 份分母、Q2 的 1 成员分母、Q3 的 20 份抽样**全部来自这 22 份报告**,分母只有个位数到十几。这说明"数值是真实的",但统计分辨率极低——例如 Q2 分母仅 1 个成员,单一成员状态即决定 100% 或 0%。门槛在真实生产库上的代表性需另行评估。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3. 详细数值与证据
|
|
|
+
|
|
|
+### 3.1 L1 · Q1 报告级时序覆盖率(规格原 SQL,未改动)
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT
|
|
|
+ SUM(CASE WHEN iv_cnt > 0 THEN 1 ELSE 0 END) / COUNT(*) AS report_coverage
|
|
|
+FROM (
|
|
|
+ SELECT r.id,
|
|
|
+ (SELECT COUNT(*) FROM indicator_values v
|
|
|
+ WHERE v.source_type = r.report_type AND v.source_id = r.id) AS iv_cnt
|
|
|
+ FROM health_reports r
|
|
|
+ WHERE r.status = 'active' AND r.subject_id IS NOT NULL
|
|
|
+) t;
|
|
|
+```
|
|
|
+
|
|
|
+**结果**:`report_coverage = 0.5000`(分子 6,分母 12)。**门槛 ≥ 0.85 → 差 0.35(相对差 14.3 个百分点)。**
|
|
|
+
|
|
|
+**12 份 active + subject_id 报告明细**(`iv_cnt` = indicator_values 中 source_type='gut_flora' AND source_id=rid 的行数):
|
|
|
+
|
|
|
+| rid | subject_id | report_date | iv_cnt | 有观测? |
|
|
|
+|---|---|---|---|---|
|
|
|
+| 1 | 8 | 2026-06-14 | 0 | ❌ |
|
|
|
+| 2 | 8 | 2026-06-14 | 0 | ❌ |
|
|
|
+| 3 | 8 | 2026-06-14 | 0 | ❌ |
|
|
|
+| 4 | 8 | 2026-06-14 | 0 | ❌ |
|
|
|
+| 18 | 1020 | 2026-08-28 | 33 | ✅ |
|
|
|
+| 19 | 1021 | 2026-08-28 | 33 | ✅ |
|
|
|
+| 20 | 1018 | 2026-08-28 | 33 | ✅ |
|
|
|
+| 21 | 1017 | 2026-08-28 | 33 | ✅ |
|
|
|
+| 28 | 1022 | 2026-08-01 | 68 | ✅ |
|
|
|
+| 29 | 1022 | 2026-09-11 | 67 | ✅ |
|
|
|
+| 49 | 1114 | 2026-10-28 | 0 | ❌ |
|
|
|
+| 50 | 1117 | 2026-10-28 | 0 | ❌ |
|
|
|
+
|
|
|
+**缺口 6 份**:rid 1-4(subject_id=8,历史回填缺失)+ rid 49/50(2026-10-27 17:06/17:08 新建的空报告——health_indicators 与 indicator_values 均为 0 行)。
|
|
|
+
|
|
|
+### 3.2 L2 · Q2 成员可用率(规格 v2 修正 SQL:`d.id = v.definition_id`,GROUP BY 已按 §2930 口径)
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT
|
|
|
+ (SELECT COUNT(DISTINCT n.subject_id) FROM (
|
|
|
+ SELECT v.subject_id, v.definition_id
|
|
|
+ FROM indicator_values v
|
|
|
+ JOIN indicator_definitions d ON d.id = v.definition_id AND d.status = 1
|
|
|
+ WHERE v.report_date IS NOT NULL AND v.numeric_value IS NOT NULL
|
|
|
+ GROUP BY v.subject_id, v.definition_id
|
|
|
+ HAVING COUNT(DISTINCT v.report_date) >= 2
|
|
|
+ ) n)
|
|
|
+ /
|
|
|
+ (SELECT COUNT(DISTINCT m.subject_id) FROM (
|
|
|
+ SELECT r.subject_id
|
|
|
+ FROM health_reports r
|
|
|
+ WHERE r.status='active' AND r.subject_id IS NOT NULL AND r.report_date IS NOT NULL
|
|
|
+ GROUP BY r.subject_id
|
|
|
+ HAVING COUNT(DISTINCT r.report_date) >= 2
|
|
|
+ ) m) AS member_usable_rate;
|
|
|
+```
|
|
|
+
|
|
|
+**结果**:`member_usable_rate = 1.0000`(分子 1 / 分母 1)。**门槛 ≥ 0.90 → 达标。**
|
|
|
+
|
|
|
+分子:subject_id=1022 有 41 个 definition_id 满足"跨 ≥2 个不同 report_date 且 numeric_value 非空"。分母:仅 subject_id=1022 一个成员——其 rid 28(2026-08-01) 与 rid 29(2026-09-11) 构成 2 个不同 report_date。
|
|
|
+
|
|
|
+**⚠️ 分母仅 1 个成员的安全说明**:subject_id=8 有 4 份报告但 4 份 report_date 全为 2026-06-14 → `COUNT(DISTINCT r.report_date)=1`,按规格 §2930「同一 report_date 的多份报告视为同一期」**不进分母**。而 subject 1017/1018/1020/1021/1114/1117 各只有 1 份报告,均不进分母。故分母=1、分子=1。**这是"单成员恰好达标",不是"90% 成员群体达标"**——真实生产库上需重新验算,不能据此认为 L2 已稳健达标。
|
|
|
+
|
|
|
+### 3.3 L3 · Q3 抽样(最近 6 个月 20 份 gut_flora,按 report_date DESC, id DESC 排序取前 20)
|
|
|
+
|
|
|
+Q3 口径(规格 §2930 + L3 门槛表):
|
|
|
+- ref = health_indicators JOIN indicator_definitions(按名、status=1、value_type='numeric')
|
|
|
+- has_obs = 该 ref 在 indicator_values 中有 ≥1 条(source_type='gut_flora' AND source_id=rid)
|
|
|
+- 每份覆盖率 = has_obs / ref;**≥90% 达标**
|
|
|
+- 「误判首次记录」= 有更早报告(同 subject,report_date 更早)∧ 全部 ref 都有 obs ∧ 全部 ref 都无更早观测 → UI 会把全部显示"首次记录"。注意这是**成员误判**:report_date 晚于本报告的所有同 subject 报告都算更早报告(与 §2930「同日期不同报告视为同一期」对齐)。
|
|
|
+
|
|
|
+| rid | rdate | subj | ref(可 mapping 数值) | has_obs | 覆盖率 | 达标(≥90%) | 误判首次记录 |
|
|
|
+|---|---|---|---|---|---|---|---|
|
|
|
+| 50 | 2026-10-28 | 1117 | 0 | 0 | N/A | ❌ | ✅ F |
|
|
|
+| 49 | 2026-10-28 | 1114 | 0 | 0 | N/A | ❌ | ✅ F |
|
|
|
+| 35 | 2026-09-14 | NULL | 0 | 0 | N/A | ❌ | ✅ F |
|
|
|
+| 34 | 2026-09-14 | NULL | 50 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 33 | 2026-09-14 | NULL | 50 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 31 | 2026-09-11 | NULL | 50 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 29 | 2026-09-11 | 1022 | 50 | 50 | **100%** | ✅ | ✅ F |
|
|
|
+| 27 | 2026-09-03 | NULL | 33 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 26 | 2026-09-02 | NULL | 33 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 25 | 2026-08-31 | NULL | 33 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 24 | 2026-08-30 | NULL | 33 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 23 | 2026-08-30 | NULL | 33 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 22 | 2026-08-30 | NULL | 33 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 21 | 2026-08-28 | 1017 | 33 | 33 | **100%** | ✅ | ✅ F |
|
|
|
+| 20 | 2026-08-28 | 1018 | 33 | 33 | **100%** | ✅ | ✅ F |
|
|
|
+| 19 | 2026-08-28 | 1021 | 33 | 33 | **100%** | ✅ | ✅ F |
|
|
|
+| 18 | 2026-08-28 | 1020 | 33 | 33 | **100%** | ✅ | ✅ F |
|
|
|
+| 28 | 2026-08-01 | 1022 | 53 | 53 | **100%** | ✅ | ✅ F |
|
|
|
+| 4 | 2026-06-14 | 8 | 31 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+| 3 | 2026-06-14 | 8 | 31 | 0 | 0.0% | ❌ | ✅ F |
|
|
|
+
|
|
|
+**L3a:6 份达标**(29/21/20/19/18/28),**14 份不达标**。其中 ref=0 的 3 份(rid 50/49/35)记 ❌:它们连可 mapping 数值指标都是 0(无 health_indicators),报告详情页无任何可对照指标,"90% 指标有 ≥1 期观测"无从成立;同时这 3 份也是上一节 L1 的分母缺口来源。其余 11 份(34/33/31/27/26/25/24/23/22/4/3)覆盖率 0.0%:report_date 有数据但 indicator_values 0 条。
|
|
|
+
|
|
|
+**L3b:0 份误判。** 唯一被判定为 adlidate 的是 subject 1022 的 rid 29(更早报告 EXISTS=1,全部 ref 有 obs=50),但它有 40/50 个 ref 在更早报告 rid 28 有观测 → 会显示"较 MM-DD"而非"首次记录",**不误判**。其余报告均无更早同 member 报告。
|
|
|
+
|
|
|
+> **对照 10-27 前验**:rid 18 已由前验的 13/33 (39.4%) 补到 33/33 (100%)(疑似期间跑过部分 backfill),但其余 14 份缺口一份未动。L3a 不达标份数 15 → 14,**仅改善 1 份**。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4. 达标判定与差距明细
|
|
|
+
|
|
|
+### 4.1 三级判定
|
|
|
+
|
|
|
+| 级别 | 实测 | 门槛 | 判定 |
|
|
|
+|---|---|---|---|
|
|
|
+| L1 | 0.5000 | ≥ 0.85 | ❌ 差 0.3500(需把 6 份缺口报告中至少 5 份补出观测:6/12→11/12=0.9167) |
|
|
|
+| L2 | 1.0000 | ≥ 0.90 | ⚠️ 达标,但分母=1(单成员),不具群体代表性 |
|
|
|
+| L3a | 6/20 达标 | 20/20 | ❌ 缺 14 份(其中 3 份 ref=0 连指标都没有) |
|
|
|
+| L3b | 0 误判 | 0 | ✅ 达标 |
|
|
|
+
|
|
|
+**未达标项:L1、L3a → 不放行。**
|
|
|
+
|
|
|
+### 4.2 差距明细(样本 ID + 缺口量 + 归因)
|
|
|
+
|
|
|
+| 缺口类别 | 报告/成员 | 缺口量 | 归因 | 备注 |
|
|
|
+|---|---|---|---|---|
|
|
|
+| A. subject_id=8 历史回填缺失 | rid 1/2/3/4 | 4 份 × 31 数值指标 = **124** 行 | 4 份同 2026-06-14 上传的旧报告,pipeline 未回填 | 不影响 L2(同日期只算 1 期),但吃 L1 4 个分母 + L3a 2 份抽样 |
|
|
|
+| B. Q18 G3:上传时未选成员 → pipeline 跳过,事后绑定未补跑 | rid 22/23/24/25/26/27/31/33/34 共 9 份 | 9 × 33~50 = **~348** 行 | subject_id IS NULL;NormalizeIndicatorPipeline 因 subjectId==null 跳过 | 工程上 G3 修复(bindReportToMember 补跑)已合入主线,但存量未重跑 |
|
|
|
+| C. 空报告 | rid 35(无 health_indicators)+ rid 49/50(health_indicators=0、2026-10-27 新建上传) | 3 份整级缺口 | 35 为空报告;49/50 是新的空上传(未解析出任何指标) | 3 份都进 L1 分母(49/50 有 subject_id),并计入 L3a ref=0 |
|
|
|
+
|
|
|
+**backfill 总量估算**:A 124 + B ~348 = **约 472 行**(另 3 份空报告无可回填内容,需确认是解析失败还是正常空上传——若是解析失败须修解析链路)。
|
|
|
+
|
|
|
+### 4.3 建议
|
|
|
+
|
|
|
+1. **不放行第二段**:L1=0.50 < 0.85、L3a 14/20 不达标。
|
|
|
+2. **backfill 覆盖 A+B 约 472 行**(`/api/admin/indicator/backfill?dryRun=false`,含 fixReportDates=true),注意 B 的 9 份需要先绑定成员或走 backfill 的 member 解析路径,否则 pipeline 仍会跳过 subject_id IS NULL 的报告。
|
|
|
+3. **确认 rid 49/50 空报告成因**:若 PDF 解析链路回归,属比覆盖率更严重的 P0。
|
|
|
+4. backfill 完成后**重跑本报告三条 SQL**,三级全绿才放行。
|
|
|
+5. L2 虽然达标,但**分母仅 1 个成员**,不可作为放行依据——需在生产库或注入更多多期成员后重验(规格 §8.1 的 dryRun 也已建议按真实成员分布做)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 5. 数据备注(不影响判定,供后续排障)
|
|
|
+
|
|
|
+- **rid 16/17 的观测指向不存在的报告**:`indicator_values` 中 source_id=16(subject 1114)、17(subject 1117) 各 1 行,`report_date`/`numeric_value` 均 NULL,health_reports 无对应行 → 孤儿观测行。与 2026-10-27 新建的 rid 49/50 的 subject 1114/1117 **同源**:疑心是某次上传流程写到一半的中间态,health_indicators 仍为空。**须与 rid 49/50 空报告一并排查**。
|
|
|
+- status≠1 的 definition 27 个(value_type NULL):规格 §5.5.1/Q17 已在读路径过滤 status=0,本次 Q3 已按 `d.status=1` 过滤,不受影响。
|
|
|
+
|
|
|
+## 6. 基线验证(构建通过)
|
|
|
+
|
|
|
+| 验证项 | 命令 | 结果 |
|
|
|
+|---|---|---|
|
|
|
+| 后端编译 | `mvn -f cfc-backend/pom.xml -q -DskipTests compile`(worktree @ origin/cfclub b31b90cb5) | 见下方 |
|
|
|
+| Web 管理端构建 | `cd cfc-web && npm run build` | 未执行(本任务无代码改动,构建非放行判据;如需可在本地主库跑) |
|
|
|
+
|
|
|
+无新增迁移,无 schema 变更,无代码改动。
|
|
|
+
|
|
|
+## 7. 分支与提交
|
|
|
+
|
|
|
+- 报告文件:`T04-S2-GATE2_REPORT.md`(仓库根目录,仅此一个文件)
|
|
|
+- 分支:`verify/t04-s2-gate2`(基于 `origin/cfclub` @ b31b90cb5,含 e740b212d)
|
|
|
+- 提交信息:`verify: T04-S2-GATE-2 合入后门槛终验 — L1=0.50/L3a 14-20 不达标,不放行,先补 backfill`
|
|
|
+- 提交哈希:推送后回报(避免文件自引用)。
|