Files
Neo-ZQYY/.kiro/specs/assistant-abolish-cleanup/design.md

225 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 设计文档助教废除Abolish全链路清理
## 概述
本设计描述如何安全地从 ETL 全链路中移除"助教废除"独立数据链路。
核心思路:**删除独立的废除链路API → ODS → DWD保留服务记录中已有的 `is_trash` 字段作为唯一废除判断源。**
清理范围覆盖:
- ETL 任务定义ODS 任务 + 注册表)
- DWD 加载映射FACT_MAPPINGS + TABLE_MAP
- DWS 聚合逻辑(死代码移除)
- DWD 验证器配置
- 数据库 DDL 和迁移脚本
- 属性测试
- 运维脚本
## 架构
### 清理前数据流
```mermaid
graph LR
API_Abolish["/AssistantPerformance/GetAbolitionAssistant"] --> ODS_ACR["ods.assistant_cancellation_records"]
ODS_ACR --> DWD_ATE["dwd.dwd_assistant_trash_event"]
ODS_ACR --> DWD_ATE_EX["dwd.dwd_assistant_trash_event_ex"]
DWD_ATE --> |"_extract_trash_records (死代码)"| DWS_DAILY["dws.dws_assistant_daily_detail"]
API_Service["/AssistantPerformance/GetAssistantServiceRecords"] --> ODS_ASR["ods.assistant_service_records"]
ODS_ASR --> DWD_SL_EX["dwd.dwd_assistant_service_log_ex"]
DWD_SL_EX --> |"is_trash 字段 (实际使用)"| DWS_DAILY
style API_Abolish fill:#f99,stroke:#c00
style ODS_ACR fill:#f99,stroke:#c00
style DWD_ATE fill:#f99,stroke:#c00
style DWD_ATE_EX fill:#f99,stroke:#c00
```
### 清理后数据流
```mermaid
graph LR
API_Service["/AssistantPerformance/GetAssistantServiceRecords"] --> ODS_ASR["ods.assistant_service_records"]
ODS_ASR --> DWD_SL_EX["dwd.dwd_assistant_service_log_ex"]
DWD_SL_EX --> |"is_trash 字段"| DWS_DAILY["dws.dws_assistant_daily_detail"]
style API_Service fill:#9f9,stroke:#090
style DWD_SL_EX fill:#9f9,stroke:#090
```
## 组件与接口
### 需要修改的文件清单
| 层级 | 文件 | 操作 | 需求 |
|------|------|------|------|
| ODS 任务 | `tasks/ods/ods_tasks.py` | 删除 `OdsTaskSpec` 条目 + 从默认序列移除 | 1.2, 1.3 |
| 任务注册 | `orchestration/task_registry.py` | 删除 `ODS_ASSISTANT_ABOLISH` 注册 | 1.1 |
| DWD 加载 | `tasks/dwd/dwd_load_task.py` | 删除 FACT_MAPPINGS 和 TABLE_MAP 条目 | 2.12.4 |
| DWS 日度 | `tasks/dws/assistant_daily_task.py` | 删除 `_extract_trash_records``_build_trash_index`,简化 `_aggregate_by_assistant_date` 签名 | 3.13.4 |
| DWD 验证 | `tasks/verification/dwd_verifier.py` | 删除废除表的 ID 和时间字段映射 | 4.14.4 |
| DDL | `db/etl_feiqiu/schemas/dwd.sql` | 删除 `dwd_assistant_trash_event` / `_ex` 的 CREATE TABLE + COMMENT | 6.16.2 |
| DDL | `db/etl_feiqiu/schemas/ods.sql` | 删除 `assistant_cancellation_records` 的 CREATE TABLE + COMMENT | 6.3 |
| DDL | `db/etl_feiqiu/schemas/schema_dwd_doc.sql` | 删除废除表的 CREATE TABLE + COMMENT | 6.4 |
| DDL | `db/etl_feiqiu/schemas/schema_ODS_doc.sql` | 删除废除表的 CREATE TABLE + COMMENT | 6.5 |
| DDL | `db/etl_feiqiu/schemas/dws.sql` | 更新 `dws_assistant_daily_detail` 注释 | 6.6 |
| DDL | `db/etl_feiqiu/schemas/schema_dws.sql` | 更新 `dws_assistant_daily_detail` 注释 | 6.7 |
| 迁移 | `db/etl_feiqiu/migrations/` | 新建 DROP TABLE 迁移脚本 | 5.15.5 |
| 属性测试 | `tests/test_property_1_fact_mappings.py` | 删除 `_REQ3_EXPECTED` 和相关引用 | 7.17.3 |
| 运维 | `scripts/ops/dataflow_analyzer.py` | 删除 `ODS_ASSISTANT_ABOLISH` spec 条目 | 8.1 |
| 运维 | `scripts/ops/gen_full_dataflow_doc.py` | 删除 `ODS_ASSISTANT_ABOLISH` spec 条目 | 8.1 |
| 运维 | `scripts/ops/etl_consistency_check.py` | 删除废除相关映射 | 8.18.2 |
| 运维 | `scripts/ops/blackbox_test_report.py` | 删除废除相关映射 | 8.18.4 |
| 运维 | `scripts/ops/field_audit.py` | 删除废除表审计条目 | 8.38.4 |
| 运维 | `scripts/ops/gen_field_review_doc.py` | 删除废除表字段定义 | 8.38.4 |
| 运维 | `scripts/ops/gen_api_field_mapping.py` | 从 ODS_TABLES 列表移除 | 8.3 |
| 运维 | `scripts/ops/export_dwd_field_review.py` | 删除废除表条目 | 8.4 |
| 运维 | `scripts/ops/check_ods_latest_indexes.py` | 删除废除表索引检查 | 8.3 |
### 不需要修改的文件(确认安全)
| 文件 | 原因 |
|------|------|
| `dwd_assistant_service_log_ex` 表 DDL | 保留 `is_trash` 等字段(需求 9 |
| `ods.assistant_service_records` 表 DDL | 保留 `is_trash` 等字段(需求 9 |
| `assistant_monthly_task.py` | 仅消费 `dws_assistant_daily_detail``trashed_seconds`/`trashed_count`,不直接引用废除表 |
| `assistant_salary_task.py` | 仅消费 `dws_assistant_monthly_summary`,不直接引用废除表 |
## 数据模型
### 被删除的表
```sql
-- ODS 层
ods.assistant_cancellation_records -- 78 条记录
-- DWD 层
dwd.dwd_assistant_trash_event -- 主表
dwd.dwd_assistant_trash_event_ex -- 扩展表
```
### 保留的废除相关字段
```sql
-- ods.assistant_service_records 中(保留)
is_trash INT -- 废除标记
trash_reason TEXT -- 废除原因
trash_applicant_id BIGINT -- 废除申请人 ID
trash_applicant_name TEXT -- 废除申请人姓名
-- dwd.dwd_assistant_service_log_ex 中(保留)
is_trash INTEGER -- 废除标记
trash_applicant_id BIGINT -- 废除申请人 ID
trash_applicant_name VARCHAR(64) -- 废除申请人姓名
trash_reason VARCHAR(255) -- 废除原因
```
### DWS 层字段(保留,数据来源变更说明)
```sql
-- dws.dws_assistant_daily_detail保留注释需更新
trashed_seconds INTEGER -- 数据来源dwd_assistant_service_log_ex.is_trash + income_seconds
trashed_count INTEGER -- 数据来源dwd_assistant_service_log_ex.is_trash 计数
-- dws.dws_assistant_monthly_summary保留
trashed_hours NUMERIC(10,2) -- 来自 daily_detail.trashed_seconds 汇总
```
## DWS 代码重构细节
### assistant_daily_task.py 变更
**删除方法:**
- `_extract_trash_records()` — 查询 `dwd.dwd_assistant_trash_event` 的 SQL已无消费者
- `_build_trash_index()` — 构建废除索引,已不参与判断逻辑
**修改方法:**
- `extract()` — 移除对 `_extract_trash_records` 的调用,移除 `trash_records` 变量
- `transform()` 或调用 `_aggregate_by_assistant_date` 的地方 — 移除 `trash_index` 参数传递
- `_aggregate_by_assistant_date()` — 从签名中移除 `trash_index` 参数;`is_trash` 判断逻辑保持不变
**不变逻辑:**
```python
# 这段逻辑保持不变——通过 is_trash 字段判断废除
is_trashed = bool(record.get('is_trash', 0))
if is_trashed:
agg['trashed_seconds'] += income_seconds
agg['trashed_count'] += 1
```
## 正确性属性
*正确性属性是一种在系统所有有效执行中都应成立的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规格与机器可验证正确性保证之间的桥梁。*
### Property 1废除聚合逻辑正确性is_trash 驱动)
*对任意*服务记录集合,其中每条记录包含 `is_trash` 标记和 `income_seconds` 值,聚合后:
- `trashed_seconds` 应等于所有 `is_trash=1` 记录的 `income_seconds` 之和
- `trashed_count` 应等于所有 `is_trash=1` 记录的数量
- `total_service_count` 应等于所有 `is_trash=0` 记录的数量
- `total_seconds` 应等于所有 `is_trash=0` 记录的 `income_seconds` 之和
**Validates: Requirements 3.4, 9.3**
### Property 2FACT_MAPPINGS 一致性(已有属性测试的回归验证)
*对任意* FACT_MAPPINGS 中的表名,该表名应在 TABLE_MAP 中有对应的 ODS 源表映射,且映射的每个 DWD 列名应为合法的 SQL 标识符。
**Validates: Requirements 2.12.4, 7.3**
> 注:此属性已由 `tests/test_property_1_fact_mappings.py` 实现。清理后需确保该测试仍然通过。
## 错误处理
### 迁移脚本安全性
- 所有 `DROP TABLE` 语句使用 `IF EXISTS`,确保幂等执行
- 迁移脚本在单个事务中执行,失败时自动回滚
- 迁移脚本包含注释说明移除原因,便于审计追溯
### 代码删除安全性
- 删除 `_extract_trash_records``_build_trash_index` 前,确认无其他调用者
- `_aggregate_by_assistant_date` 移除 `trash_index` 参数后,确认所有调用点已同步更新
- 保留 `is_trash` 判断逻辑不变,确保废除统计功能不受影响
### 回滚策略
- DDL 变更通过迁移脚本管理可通过反向迁移CREATE TABLE回滚
- 代码变更通过 Git 版本控制回滚
- ODS 表数据在删除前可选择性备份(数据量小,仅 78 条)
## 测试策略
### 属性测试
- 使用 `hypothesis` 库进行属性测试
- 每个属性测试至少运行 100 次迭代
- 每个测试用注释标注对应的设计属性编号
**Property 1 测试方案:**
- 生成随机服务记录列表(包含随机 `is_trash` 标记和 `income_seconds` 值)
- 调用 `_aggregate_by_assistant_date` 方法
- 验证 `trashed_seconds`/`trashed_count` 与手动计算的期望值一致
- 标签:`Feature: assistant-abolish-cleanup, Property 1: 废除聚合逻辑正确性`
**Property 2 测试方案:**
- 已由 `tests/test_property_1_fact_mappings.py` 覆盖
- 清理后运行 `pytest tests/ -v` 确认无回归
- 标签:`Feature: assistant-abolish-cleanup, Property 2: FACT_MAPPINGS 一致性`
### 单元测试
- 验证 `AssistantDailyTask` 不再有 `_extract_trash_records``_build_trash_index` 方法
- 验证 `_aggregate_by_assistant_date` 签名不包含 `trash_index` 参数
- 验证 FACT_MAPPINGS 不包含废除表条目
- 验证 TABLE_MAP 不包含废除表映射
- 验证 DwdVerifier 配置不包含废除表
### 集成验证
- 运行现有属性测试套件:`pytest tests/ -v`
- 运行 ETL 单元测试:`cd apps/etl/connectors/feiqiu && pytest tests/unit`
- 确认所有测试通过,无回归