feat(iit): harden QC pipeline consistency and release artifacts
Implement IIT quality workflow hardening across eQuery deduplication, guard metadata validation, timeline/readability improvements, and chat evidence fallbacks, then synchronize release and development documentation for deployment handoff. Includes migration/scripts for open eQuery dedupe guards, orchestration/status semantics, report/tool readability fixes, and updated module status plus deployment checklist. Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# IIT / CRA Agent 指标口径与 SSOT 对照表(Phase 0)
|
||||
|
||||
> 文档版本:v1.0
|
||||
> 创建日期:2026-03-08
|
||||
> 适用范围:IIT 业务端大盘 / 报告与关键事件 / AI 实时工作流水 / AI 对话
|
||||
> 目标:先统一“同名指标”的定义和数据源,再进入修复,避免反复打补丁
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与问题定义
|
||||
|
||||
当前线上/测试反馈的核心不是单点报错,而是同一指标在多个页面口径不一致,例如:
|
||||
|
||||
- 大盘通过率与趋势通过率不一致
|
||||
- 报告页健康分与大盘健康分不一致
|
||||
- 时间线问题数与待处理 eQuery 不一致
|
||||
- 报告中 D1/D2/D3D4/D6 与下方维度评分对不上
|
||||
|
||||
这些问题在工程上属于**口径漂移(metric drift)**,必须先冻结 SSOT(Single Source of Truth),再排查数据同步、规则执行、前端展示。
|
||||
|
||||
---
|
||||
|
||||
## 2. 指标分层模型(必须统一)
|
||||
|
||||
IIT 指标按 4 层定义,禁止跨层混算:
|
||||
|
||||
1. **事实层(Raw Facts)**:REDCap 原始记录与事件数据
|
||||
2. **执行层(QC Results)**:`qc_field_status` / `qc_event_status` 的规则执行结果
|
||||
3. **聚合层(Project Stats)**:`iit_qc_project_stats`、`iit_record_summary` 的聚合快照
|
||||
4. **呈现层(UI/API)**:Dashboard/Reports/AiStream/AiChat
|
||||
|
||||
约束:
|
||||
|
||||
- 呈现层不允许重新发明计算公式,只消费聚合层或执行层
|
||||
- 同一名称指标只能有一个“主口径”
|
||||
- 不同用途的指标必须显式命名(例如“按受试者通过率”与“按事件通过率”)
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心指标 SSOT 对照表(冻结版)
|
||||
|
||||
## 3.1 项目健康度与通过率
|
||||
|
||||
| 指标名 | 业务定义 | SSOT 来源 | 当前代码入口 | 备注 |
|
||||
|---|---|---|---|---|
|
||||
| healthScore | 健康度总分(0-100) | `iit_qc_project_stats.health_score` | `iitQcCockpitService.getStats()` | 不允许前端 fallback 推导 |
|
||||
| healthGrade | 健康度等级 | `iit_qc_project_stats.health_grade` | `iitQcCockpitService.getStats()` | 同上 |
|
||||
| passRate (大盘) | 按受试者通过率 | `passed_records / total_records` | `iitQcCockpitService.getStats()` | 保留 1 位小数 |
|
||||
| passRate (趋势) | 按日志条目通过率(旧) | `iit_qc_logs` 分组计算 | `iitQcCockpitController.getTrend()` | 与大盘不是同一口径,必须重命名或替换 |
|
||||
|
||||
结论:
|
||||
|
||||
- 当前“通过率”至少有两种口径,UI 未标注,必然引发“100% vs 33%”类问题。
|
||||
|
||||
## 3.2 D1/D2/D3D4/D6 报表
|
||||
|
||||
| 报表 | 业务定义 | SSOT 来源 | 当前查询入口 |
|
||||
|---|---|---|---|
|
||||
| D1 筛选入选 | 入排规则是否通过 | `qc_field_status`(D1) + `record_summary`(受试者全集) | `iitQcCockpitService.getEligibilityReport()` |
|
||||
| D2 完整性 | 缺失字段率 | `qc_field_status`(D2) | `iitQcCockpitService.getCompletenessReport()` |
|
||||
| D3/D4 质疑跟踪 | eQuery 生命周期 | `iit_equeries` | `iitQcCockpitService.getEqueryLogReport()` |
|
||||
| D6 方案偏离 | 访视超窗等偏离 | `qc_field_status`(D6) | `iitQcCockpitService.getDeviationReport()` |
|
||||
|
||||
结论:
|
||||
|
||||
- D 类报表与大盘维度评分来自不同聚合路径时,必须明确“时点一致性”(同一批次同一时刻)。
|
||||
|
||||
## 3.3 AI 实时工作流水
|
||||
|
||||
| 指标 | 业务定义 | SSOT 来源 | 当前入口 | 风险 |
|
||||
|---|---|---|---|---|
|
||||
| timeline total | 时间线受试者总数 | `qc_field_status` 聚合 + pass 补充 | `iitQcCockpitController.getTimeline()` | 与 eQuery 总数不是同一概念 |
|
||||
| red/yellow 问题数 | 每受试者 FAIL/WARNING 汇总 | `qc_field_status` | `getTimeline()` | 应与 field-issues 可对账 |
|
||||
| 事件中文名 | event display label | `qc_event_status.event_label` | `getTimeline()` LEFT JOIN | 空值时会回退技术名 |
|
||||
|
||||
## 3.4 AI 对话
|
||||
|
||||
| 语义工具 | 主要数据源 | 适用问题 | 当前实现 |
|
||||
|---|---|---|---|
|
||||
| `read_report` | `QcReportService` 缓存报告 | 通过率、问题统计、趋势摘要 | `ToolsService` |
|
||||
| `look_up_data` | REDCap 原始数据 | 单患者字段值、原始记录核查 | `ToolsService` |
|
||||
| `check_quality` | `QcExecutor` 实时执行 | 用户明确要求“重跑质控” | `ToolsService` |
|
||||
| `search_knowledge` | 项目知识库(RAG) | 方案文本、入排标准文本 | `ToolsService` |
|
||||
|
||||
结论:
|
||||
|
||||
- 对话错误不等于“模型幻觉”,优先排查是否选错工具或工具查询不完整。
|
||||
|
||||
---
|
||||
|
||||
## 4. 现存口径漂移点(已识别)
|
||||
|
||||
1. **趋势口径漂移**
|
||||
- 趋势接口仍从 `iit_qc_logs` 计算通过率;大盘通过率来自 `iit_qc_project_stats`。
|
||||
- 导致“卡片 100%,趋势 33%”。
|
||||
|
||||
2. **健康分 fallback 风险**
|
||||
- 大盘前端在 `healthScore` 缺失时回退为 `Math.round(passRate)`。
|
||||
- 数据未准备好时会把通过率误当健康分,造成“待处理质疑很多但仍 100 分”。
|
||||
|
||||
3. **报告缓存时点风险**
|
||||
- `read_report` 优先读缓存报告(默认有效期 24h),若未及时刷新会滞后于大盘/流水。
|
||||
|
||||
4. **“总数”语义混淆**
|
||||
- 时间线问题数、eQuery 待处理数、D3D4 报表数本质是不同对象,UI 文案未区分。
|
||||
|
||||
5. **展示字段名兼容风险**
|
||||
- 若 `eventLabel/fieldLabel` 空,前端回退技术字段名;用户会误判为“事件名错误”。
|
||||
|
||||
---
|
||||
|
||||
## 5. 冻结规则(修复期强制执行)
|
||||
|
||||
1. 页面上所有“通过率”必须标注口径:
|
||||
- 按受试者(record)
|
||||
- 按事件(record-event)
|
||||
- 按规则检查条目(field-level checks)
|
||||
|
||||
2. 健康度评分只允许来自 `healthScoreEngine` 落库结果,不允许前端推算。
|
||||
|
||||
3. 报告页、大盘、AI 对话必须显示“统计快照时间”,便于用户识别时点差异。
|
||||
|
||||
4. UI 文案新增说明:
|
||||
- “待处理质疑”来自 `iit_equeries`
|
||||
- “时间线问题总数”来自 `qc_field_status`
|
||||
|
||||
5. 涉及 D1/D2/D3D4/D6 的变更,必须附带“口径回归测试”记录。
|
||||
|
||||
---
|
||||
|
||||
## 6. Phase 1 进入条件
|
||||
|
||||
满足以下条件后,才进入根因排查与代码修复:
|
||||
|
||||
- [ ] 本文“SSOT 对照表”已被团队确认(产品/研发/质控)
|
||||
- [ ] 每个页面核心指标已标注口径
|
||||
- [ ] 已选定“最小复现项目”与冻结时间窗口
|
||||
|
||||
Phase 1 执行手册见:
|
||||
`docs/03-业务模块/IIT Manager Agent/09-技术评审报告/2026-03-08-IIT-CRA-最小复现项目对账执行手册-Phase1.md`
|
||||
|
||||
Reference in New Issue
Block a user