0001-Sprint2规划会议纪要 » 历史记录 » 版本 1
Huarui Lin, 2026-04-15 21:00
| 1 | 1 | Huarui Lin | # <div align="center"> Sprint 2 规划会议纪要:数据基建与时序状态机护栏落地 </div> |
|---|---|---|---|
| 2 | |||
| 3 | **会议日期**:2026-04-15 |
||
| 4 | **项目名称**:基金量化定投选基系统 (2026-04-11-01) |
||
| 5 | **会议目标**:锁定 M2 交付标准,对齐 DuckDB/Polars 混合架构边界,解决时序状态机边界逻辑冲突,确立实体机压测基线与 Redmine 强卡控验收标准。 |
||
| 6 | **参会角色**:项目经理(Henry Lin)、算法/研发工程师、基础架构/运维工程师、数据资产管理员。 |
||
| 7 | |||
| 8 | --- |
||
| 9 | ## 一、 会议确认项 |
||
| 10 | |||
| 11 | 1. **CONF-01 S2 绝对红线确立**:全局严禁手写 `import pandas`(CI AST 拦截);严禁魔法数字(必须走 `config/config.yaml` 新增节点读取);DuckDB 严守粗筛边界(严禁执行滚动窗口逻辑)。 |
||
| 12 | 2. **CONF-02 FW-3 防火墙特例豁免决策**:正式批准 `data_loader.py` 中的 `process_timeseries()` 阶段豁免执行 FW-3(按年份拆分提取)规则,允许一次性加载全量 Arrow 数据进行缺失值填充与截断状态机计算。 |
||
| 13 | 3. **CONF-03 DuckDB 显式列投影强制约束**:在 S2-01 的 DuckDB SQL 中,严禁使用 `SELECT *`。对 `fund_basic_info` 必须硬编码 `SELECT fund_id, fund_name, fund_type, create_date` 进行显式投影。仅允许 `fund_type` 作为临时审计字段随 Arrow 流转,在最终落盘为 Parquet 前,必须通过 Polars 显式 `select` 将其彻底丢弃。 |
||
| 14 | 4. **CONF-04 data_audit.json Schema 零偏移确认**:S2-04 产出的 `data_audit.json` 必须严格遵循《0002-数据基建》中定义的完整 JSON 结构(含 `pipeline`, `input`, `filtering`, `cleaning`, `output` 五大根节点),拒绝任何字段名自定义或结构增删。 |
||
| 15 | 5. **CONF-05 审计关键比率计算逻辑确认**:明确 `filtering.whitelist_retention_rate` 的计算公式必须为:`whitelist_retained_funds / whitelist_total_funds`。其中分母 `whitelist_total_funds` 必须取 `fund_basic_info` 原始 CSV 的物理总行数,严禁使用去重或其他口径。若分母为 0,统一调用 `calc_rate` 工具函数返回 0.0。 |
||
| 16 | 6. **CONF-06 config.yaml 扩展节点确认**:确认在 `config/config.yaml` 中新增两个合法节点:① `data.raw_paths`(字典结构,声明路径);② `duckdb.memory_limit`(字符串类型,默认 `"40GB"`)。 |
||
| 17 | 7. **CONF-07 建仓期硬删与 `segment_id` 跨段逻辑决策**:采用“选项 A”。建仓期(12周)剔除逻辑严格锚定并仅作用于 `segment_id == 0`,即使 `segment_0` 被完全物理抹除,后续 `segment_1` 及以后的数据段仍予保留,以所有段有效周数总和参与后续存活期过滤,坚决遵守 CR-001 段独立性原则。 |
||
| 18 | 8. **CONF-08 异常值置 NULL 的涨跌幅计算基准决策**:采用“选项 B”。异常值(单周涨跌幅绝对值 > 50%)判定必须基于“本周原始有值且上周原始有值”的真实相邻周计算,由 `ffill` 填充产生的值不参与此异常值判定逻辑,防止长缺失恢复后的首周数据被误杀置 NULL。 |
||
| 19 | 9. **CONF-09 Parquet 物理存储格式强制约束**:确认 `data/processed/` 下产出的文件命名严格为 `net_value_YYYY.parquet`。PyArrow `write_parquet()` 必须显式指定 `row_group_size=100000`;写入模式必须为“覆盖写”,严禁追加。 |
||
| 20 | 10. **CONF-10 最终落盘 Schema 绝对锁定**:产出 Parquet 必须且仅能包含 4 列:`fund_id`(String), `net_value_date`(Date), `cumulative_net_value`(Float64), `segment_id`(UInt32)。任何多余的临时计算列在落盘前必须被 Polars 显式 `select` 丢弃。 |
||
| 21 | 11. **CONF-11 DuckDB VIEW 重建机制确认**:`create_duckdb_view()` 函数严禁依赖任何持久化数据库状态。每次被调用时,必须动态扫描 `data/processed/` 目录下的年份文件,拼接生成 `v_net_value_processed` VIEW。 |
||
| 22 | 12. **CONF-12 数据血缘 Hash 校验时机确认**:确认 `src/utils/hash.py` 的调用时机必须在 Parquet 文件落盘完成后,按年份文件逐个计算 SHA-256,并将结果列表持久化至 `data/metadata/processed_hash.json`。 |
||
| 23 | 13. **CONF-13 M2 内存压测执行环境决策**:采用“选项 A(实体机裸跑测试)”。S2-04 的压测必须在 64GB 实体机宿主机上直接运行 Python 脚本,不施加 Docker cgroup 限制,以获取最真实的物理内存消耗峰值作为算力安全结论的最终背书。 |
||
| 24 | 14. **CONF-14 净值字段数据类型强制映射确认**:本系统在全链路(DuckDB 抽取、Polars 计算、Parquet 落盘)必须且只能使用 `Float64`,严禁使用原生 `Decimal` 类型,以防止 Polars 滚动窗口性能劣化及内存溢出风险。 |
||
| 25 | 15. **CONF-15 Redmine Story 强卡控验收标准映射锁定**:S2-01至S2-05的Redmine自定义字段必须严格按本次会议确认的配置扩展、SQL约束、状态机单测覆盖、审计Schema及压测内存指标逐条填入,作为PR合并的强阻断门禁。 |
||
| 26 | 16. **CONF-16 审计工具函数 `calc_rate` 交付归属决策**:采用“选项 B”。`calc_rate` 工具函数必须作为 S2-04(审计日志产出)的交付物,与其唯一调用者绑定,严禁在 S2-01 阶段提前产出导致“悬空代码”。 |
||
| 27 | 17. **CONF-17 R-6 风险(白名单覆盖率异常)阻断级别决策**:采用“选项 B(有条件放行)”。若 S2-04 压测真实触发 `whitelist_retention_rate < 15%` 阈值,M2 里程碑标记为“带风险通过”,不阻断 Step 3 开发。但必须在 Redmine 建立 High 级别 Bug 单拉起排查,若在下个 Sprint 回顾前未闭环,则触发熔断机制。 |
||
| 28 | |||
| 29 | --- |
||
| 30 | ## 二、 会议待办项 |
||
| 31 | |||
| 32 | | 编号 | 责任人 | 任务描述 | 截止时间 | 验收标准 | |
||
| 33 | | :--- | :--- | :--- | :--- | :--- | |
||
| 34 | | **TODO-01** | 研发工程师 | S1 占位 Mock 测试代码物理销毁 | S2-01 交付同步 | 必须在 S2-01 首个 PR 中同步物理删除 S1 遗留的占位测试代码,CI 全绿方可进入 Review。 | |
||
| 35 | | **TODO-02** | 研发工程师 | CI 性能熔断预案触发监控 | Sprint 2 持续 | S2 引入真实 I/O 后,单次 CI 执行总耗时超 180 秒立即触发 Runner capacity 调优或流水线拆分。 | |
||
| 36 | | **TODO-03** | 研发工程师 | 产出特例豁免 ADR 文档 | 会后首个 PR | 于 Gitea `/docs/adr/` 提交 `002-s2-full-arrow-exception.md`,必须固化特例生效的精确物理边界、内存预估依据及下游禁用声明;同步更新架构基线文档。 | |
||
| 37 | | **TODO-04** | 研发工程师 | 产出时序状态机核心逻辑单测矩阵 | S2-02 交付同步 | `tests/test_data_loader.py` 必须覆盖 CONF-07 的“`segment_0` 被建仓期完全吞噬后 `segment_1` 仍保留”场景,以及 CONF-08 的“长缺失 ffill 恢复首周免于 >50% 误杀”场景。 | |
||
| 38 | | **TODO-05** | 研发工程师 | 实体机全量压测报告归档 | S2-04 交付 | 压测日志必须包含 DuckDB 阶段峰值、全量 Arrow 转换峰值、Polars 状态机峰值三个维度的 `peak_memory_gb`,且总峰值必须 ≤ 40GB,日志文件上传至 Redmine S2-04 任务附件。 | |
||
| 39 | | **TODO-06** | 项目经理 | Redmine 验收标准录入与派发 | 会后 4 小时内 | S2-01 至 S2-05 任务卡片的自定义字段已按 CONF-15 逐条填入,并指派给研发。 | |
||
| 40 | |||
| 41 | --- |
||
| 42 | ## 三、 会议风险项 |
||
| 43 | |||
| 44 | | 编号 | 风险描述 | 应对策略/演进路线 | 跟踪机制 | |
||
| 45 | | :--- | :--- | :--- | :--- | |
||
| 46 | | **RISK-01** | 白名单基金覆盖率(`whitelist_retention_rate`)在压测时可能异常跌破 15% 阈值(R-6 风险具象化)。 | 采用“有条件放行”策略。M2 不阻断,但立即建立 High 级别 Redmine Bug 单,PM 联动数据资产管理员排查上游数据质量或白名单规则。若下个 Sprint 回顾前未闭环,则熔断后续 Pipeline。 | Redmine Bug 单状态跟踪,Sprint 回顾会专项汇报。 | |
||
| 47 | |||
| 48 | --- |
||
| 49 | ## 四、 会议架构决策记录(ADR)产出要求 |
||
| 50 | |||
| 51 | 基于本次会议确认的 CONF-02、CONF-07、CONF-08,要求研发工程师在会后 PR 中,于 Gitea 仓库 `/docs/adr/` 目录下提交以下 ADR: |
||
| 52 | 1. **`002-s2-full-arrow-exception.md`**:固化 FW-3 豁免的技术选型理由(预估内存安全边界、状态机行级处理特性)及严苛的下游禁用声明。 |
||
| 53 | 2. **`003-s2-timeseries-state-machine-decisions.md`**:固化为何建仓期剔除仅锚定 `segment_0`(遵守 CR-001 段独立性),以及为何异常值判定必须剥离 ffill 填充值(防止长缺失恢复首周误杀)。 |
||
| 54 | |||
| 55 | --- |
||
| 56 | ## 五、 Sprint 2 交付物全景清单(已对齐) |
||
| 57 | |||
| 58 | 以下为本次会议最终锁定需新增或重写的文件及核心约束简述(供 Redmine 录入与 PR 检查点对齐): |
||
| 59 | | 分类 | 文件路径 | 核心约束简述 | |
||
| 60 | | :--- | :--- | :--- | |
||
| 61 | | **业务参数** | `config/config.yaml` | 新增 `data.raw_paths` 与 `duckdb.memory_limit` 节点,零魔法数字。 | |
||
| 62 | | **核心源码** | `src/data_loader.py` | DuckDB 显式投影防偏移;Polars 全量 Arrow 状态机处理(含 CONF-07/CONF-08 逻辑);Parquet 4 列强锁落盘;VIEW 动态重建。 | |
||
| 63 | | **工具扩展** | `src/utils/tools.py` (或同类) | 包含 `calc_rate` 函数(分母为 0 时返回 0.0),仅随 S2-04 交付,禁止提前产出。 | |
||
| 64 | | **质量保障** | `tests/test_data_loader.py` | 覆盖 segment_0 吞噬后保留、长缺失免误杀等 5 个核心边界单测。 | |
||
| 65 | | **数据产出** | `data/processed/net_value_YYYY.parquet` | `row_group_size=100000`,覆盖写,绝对纯净的 4 列 Schema。 | |
||
| 66 | | **数据产出** | `data/metadata/data_audit.json` | 严格符合 5 大根节点 Schema,`retention_rate` 分母取物理总行数。 | |
||
| 67 | | **数据产出** | `data/metadata/processed_hash.json` | 落盘后即刻生成的各年份文件 SHA-256 校验字典。 | |
||
| 68 | | **技术真相** | `docs/data_contract.md` | 沉淀完整的数据流转 Schema 与类型映射契约。 | |
||
| 69 | | **技术真相** | `docs/adr/002-s2-full-arrow-exception.md` | 记录 FW-3 豁免决策。 | |
||
| 70 | | **技术真相** | `docs/adr/003-s2-timeseries-state-machine-decisions.md` | 记录状态机核心边界决策。 | |
||
| 71 | |||
| 72 | --- |
||
| 73 | **会议闭环状态**:✅ 全部议程结束,无遗留阻塞项。研发团队可依据本纪要启动 Sprint 2 实施。 |