Files
dpb/doc/桃育种系统统计引擎实施记录.md
T
34047007@qq.com e937fc930c checkpoint: real-scale 数据链 + 统计引擎 + ABLUP 稀疏性能修复
init 后首次落盘,累计工作:
- 数据侧:simulate_breeding_data real-scale 3.5万树重建 + 分层观测
- 引擎侧:ABLUP 稀疏生产档 EM-REML(blup 1.6.0/1.7.0);性能倒挂修复——
  系谱闭包收口为 BFS 可达祖先 + N_EXACT 3000 对齐 N_SUBSAMPLE(选中 200~3000 树
  不再顶进数小时精确迹尾),A/B 数值等价实证 + 守卫探针
- 前端:观测过滤 + 表单/HTTP 工具链完善
- 文档:业务链/观测梳理 + 引擎实施记录 + 规划对照总表
- gitignore:排除 Temp/调试脚本/一次性验证输出
2026-08-07 08:03:10 +08:00

2098 lines
270 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.
# 桃育种系统 · 统计引擎实施记录
> **版本**v1.42026-08-04 追加统计严谨·预测完整性与 MLOps 复现性:PA 落库 / 溯源 / germplasm_id 填充 / 砧木扩列 / Calo 相关校正 / 空间竞争协变量 + 组合得失漏斗)
> **定位**:记录统计引擎多轮 P0/P1 落地 + 田间刚需(花粉档案)+ 决策正确性(无性系级指数)+ 统计严谨(配合力交配设计 / 相关校正 / 空间竞争)+ MLOps 复现性 + 组合得失漏斗的实现、验证与文件清单——**G×E 交互引擎**(2026-08-03)、**性状方向标注**2026-08-04)、**花粉档案**2026-08-04)、**无性系级指数**2026-08-04)、**配合力交配设计**2026-08-04)、**统计严谨·MLOps 复现性**2026-08-04,①Calo②PA③溯源④germplasm_id⑤砧木⑥空间竞争)与**组合得失漏斗**2026-08-04,⑧ v_combination_funnel)。本文档为持续追加的落地台账,与规格文档 `桃育种系统模块扩展需求规格.md`(v2.10)配套;规格管"应该长什么样",本文管"实际落地了什么、怎么验证的"。 配套《桃育种系统业务链路与数据模型说明书》v1.1(2026-08-06 重生成,已同步 O1 花期数据消费补强 / N4 plan→trial→target 血缘 / 亲本校验 / 世代闭环落库 / 新增 §九 QA 与 CI 章节)与代码保持一致,三者(规格 + 实施记录 + 说明书)互为索引。
> **相关探针**`Temp/claude/e2e_gxe_20260803.py`G×E5 场景)· `Temp/claude/e2e_direction_20260804.py`(方向标注,7 组)· `Temp/claude/e2e_pollen_20260804.py`(花粉档案)· `Temp/claude/e2e_clone_index_20260804.py`(无性系级指数,6 组)· `Temp/claude/e2e_combining_design_20260804.py`(配合力交配设计,5 组)· `Temp/claude/e2e_prediction_rigor_20260804.py`(②③④,4 组)· `Temp/claude/e2e_rootstock_20260804.py`(⑤)· `Temp/claude/e2e_corr_spatial_20260804.py`(①⑥,3 组)· `Temp/claude/e2e_combination_funnel_20260804.py`(组合得失漏斗,3 组)。 · `Temp/claude/e2e_o1_bloom_20260805.py`O1 花期数据消费补强:四态软警示 + 窗口覆盖三态 + 库存五态 + 反向门禁,4 组)
---
## 一、G×E 交互引擎 P02026-08-03
### 1.1 背景与目标
复审清单第 2 条要求**基因型×环境(G×E)交互随机效应**显式建模。桃为多年生多年多点(MET)试验作物,同一克隆/家系在跨点、跨年表现往往相反(如 c1 在 A 站高、B 站低,c2 反之),若只估主效应会系统性误排 EBV。本轮在 `run_ablup` 上扩展 G×E 模式(`method=GXEBLUP`),并补齐可辨识性门禁与异步任务记录。
### 1.2 引擎能力(`statistics/service.py::run_ablup`
| 参数 | 取值 | 行为 |
|---|---|---|
| `gxe` | `True` / `False` | `True` 走 GXEBLUP(含 G×E 随机互作);`False` 回归纯 ABLUP(G×E 项关闭) |
| `gxe_env` | `site` / `year` | 环境维度。`site` 自动入固定效应 `trial_study``year` 自动入固定效应 `year` |
| `method` | `GXEBLUP` / `ABLUP` | 按 gxe 开关自动落库;model_name 形如 `GXEBLUP_{trait}_{env}_{ts}` |
| `fixed_effects` | 列表 | 调用方显式指定时与自动效应合并 |
**G×E 落库输出(`breeding_prediction.note` JSON**
- `sigma_gxe`:G×E 方差分量 σ²gxe(>0 表示存在交互)
- `gxe_ratio`:σ²gxe 占比
- `n_cross_env`:跨环境基因型数(有多少基因型至少在 2 个环境中观测)
- `skipped`:跳过明细(如缺站点株数)
**记录级 vs 基因型级**
- 家系分组(无 clone)时基因型=组合,G×E 记录逐树;`year` 模式记录级 = (树,年) 逐条(train_n 为记录数,EBV 行按树写)。
- 克隆坍缩(见 1.5)时基因型=clone,多株坍缩为基因型节点。
### 1.3 自动固定效应
| gxe_env | 自动固定效应 | 说明 |
|---|---|---|
| `site` | `trial_study` | 站点由 `trial_study_id` 解析(缺站点的株记录跳过并写 `skipped` |
| `year` | `year` | 年份由观测 `evaluate_year` 解析 |
调用方仍可用 `fixed_effects` 显式追加(如 `["trial_study"]`),引擎合并去重。
### 1.4 可辨识性门禁(`G×E 不可辨识` → 409,拒绝运行)
| 门禁 | 触发 | 处置 |
|---|---|---|
| 无跨环境重复 | 没有任何基因型在 ≥2 个环境出现(`n_cross_env == 0` | `G×E 不可辨识:无任何基因型跨环境重复。拒绝运行。` |
| 单元内无重复 | 每个(基因型×环境)单元仅 1 条观测,σ²gxe 与残差混杂 | `无任何基因型×环境单元内重复(每格仅 1 条观测…)` |
| 无可分环境记录 | 所有记录缺站点/年份 | `G×E 分析无可分环境的记录` |
门禁拒绝时在 `StatisticsJobModel` 落一条 `status=FAILED` + `error_msg`(同步 409 抛出,异步失败可查)。
### 1.5 克隆坍缩
同 clone 经扩繁的多株 tree 在 G×E 模式下**坍缩为基因型节点 `c{clone}`**G×E 专用系谱 `gxe_pedigree``c{clone}` 为个体,父母指向组合亲本(或树亲本);`record_map` 全部映射到 `c{clone}`。同 clone 各株 EBV 一致(重复测量聚合,杜绝自由度虚高)。
### 1.6 异步任务记录(`StatisticsJobModel`
| 字段 | 值 | 说明 |
|---|---|---|
| `job_type` | `GXE` / `ABLUP`/ `COMBINING` 等) | 任务类型 |
| `status` | `SUCCESS` / `FAILED` | 任务状态 |
| `result_ref` | prediction id | 关联结果 |
| `error_msg` | 文本 | 失败原因(可辨识性门禁消息亦落此) |
### 1.7 验证(`Temp/claude/e2e_gxe_20260803.py`5 场景全过)
| 场景 | 数据 | 断言要点 |
|---|---|---|
| [1] site-G×E 家系分组 | 2 组合×2 站×3 株,无 clone | 自动 `fixed={trial_study}``method=GXEBLUP`、σ²gxe>0、n_cross_env=2、train_n=12、EBV 行=12、job_type=GXE SUCCESS |
| [2] 不可辨识门禁 | 各组合仅单站 | 409 `G×E 不可辨识:无任何基因型跨环境重复`、job FAILED + error_msg |
| [2b] 单元内无重复 | 2 基因型×2 站每格 1 株 | 409 含 `单元内重复`、job FAILED |
| [3] year-G×E | 2 clone×2 年交叉互作 | 自动 `fixed={year}`、train_n=16(记录级)、EBV 行=8(树级)、σ²gxe>0、n_cross_env=2 |
| [5] 克隆坍缩(site | 2 clone×2 站×每格 2 株 | `record_map` 全为 `c{clone}`、同 clone EBV 相同、train_n=8、EBV 行=8 |
| [4] 回归 gxe=False | 同 [1] 数据 | `method=ABLUP`、显式 `fixed_effects=["trial_study"]`、EBV 行=12、job_type=ABLUP SUCCESS |
测试基座用 `_spy_solve` 包一层真引擎(monkeypatch `blup.solve`),捕获 `fixed`/`record_map` kwargs 后仍跑真解,验证引擎传参;`GATE_RELAX=dict(min_clone_n=1, min_pedigree_rate=0.0, max_missing_rate=1.0)` 放开数量门槛专注验证 G×E 逻辑。
---
## 二、性状方向标注 direction / into_ebv / default_h22026-08-04
### 2.1 缺陷背景(科学正确性硬伤)
`bre_trait` 原仅 `stage`/`is_core`,**无方向标注**。选择指数与决策默认"高 EBV = 优",对**低优性状**(裂果率、病害级别、酸度——若目标是低酸)会**选反**:Smith-Hazel 的 b 与加权 Z 隐含"越大越好"。用户确认缺陷属实,拍板修复范围:
- **翻转范围**:指数+决策+排行**全翻转**;
- **into_ebv 范围**'0' 仅从**选种相关候选**剔除(指数/EBV 排行/决策预览/ABLUP 下拉),describe/correlation/trait_values 不受影响;
- **default_h2 兜底**zsum + smith_hazel 都兜底(无实测 h² 用先验,两者皆无才报错)。
### 2.2 数据模型变更
`bre_trait` 新增三列(幂等 ALTER`backend/sql/weld_trait_direction.sql`create_all 只建新表,新列须手写 SQL):
| 列 | 类型 | 默认 | 说明 |
|---|---|---|---|
| `direction` | varchar(16) | `'desc'` | 性状方向:`desc`=越大越好 / `asc`=越小越好 |
| `into_ebv` | varchar(1) | `'1'` | 是否选种目标:`1`=进 EBV/指数/决策候选 / `0`=仅记录 |
| `default_h2` | double precision | NULL | 先验遗传力 h²(指数无实测 h² 时兜底;桃经典先验,可在性状字典改) |
**种子数据(`backend/sql/bre_trait_seed.sql`INSERT 0 43ON CONFLICT DO UPDATE 含三新列)**
- 7 个数值 core 性状(max/avg_fruit_weight、longitudinal/transverse/lateral_dia、flesh_thickness、ssc):`direction='desc'``into_ebv='1'``default_h2` 取桃经典先验(果重/糖度 0.5、果径/肉厚 0.4/0.3);
- 其余 categorical/date 性状:`into_ebv='0'``default_h2=NULL`
**ORM/API 透传**`TraitModel`/`TraitBaseSchema`/`TraitUpdateSchema`/`TraitOutSchema`/`TraitQueryParam` 补齐三字段;`batch_export` mapping_dict、`batch_import` header_dict/fieldsdirection/into_ebv 缺省 `'desc'/'1'`、default_h2 `_to_float`**required_headers 仍只校验原 14 键,兼容旧模板**)、`import_template_download` 选项同步。
### 2.3 后端翻转逻辑(`statistics/service.py`
**辅助** `_trait_meta_map(codes=None)``{trait_code: {direction, into_ebv, default_h2}}`,供指数/决策/排行共享方向语义。
| 模块 | 变更 |
|---|---|
| `list_traits(core_only, selection_only)` | select 新增三字段;`selection_only=True``where(into_ebv == "1")`controller 加 `selection_only` query 参数) |
| `selection_index` | `cols` 剔除 `into_ebv='0'` 写入 `extra["dropped"]`(用户可见提示) |
| `_weighted_z_index`zsum | **z 标准化后对 asc 性状取负**`z = -z`),统一"越大越优"use_h2 兜底 `h = herit.get(c) or default_h2` |
| `_smith_hazel_index` | h² 取 `h_eff[c] = 实测 h² or default_h2`**`h_eff[c] is None` 才 409**`缺实测且无先验 default_h2: …`);a 归一化后对 asc 元素取负 |
| `run_ablup` | 写时 rank 排序 `reverse=(direction != "asc")`EBV 排行即优度序) |
| `ebv_ranking` | **读时重排**(见 §三) |
| `clone_ranking` | 按当前方向重排 `ebv_mean``reverse=(direction != "asc")` |
| `decision_preview` | `_top_n``into_ebv='0'` 直接返回空集;`ranked` 按方向取最优前 N(asc 取 EBV 最小);op 缺省 `<=`asc/ `>=`desc),pheno 与 ebv 共用 |
| `compare_predictions` | 轮次对比 rank 排序方向感知(见 §三) |
### 2.4 前端
| 文件 | 变更 |
|---|---|
| `api/module_bre/statistics.ts` | `listTraits(coreOnly, selectionOnly)``selection_only` 参数 |
| `views/module_bre/statistics/index.vue` | **`selTraits``listTraits(true, true)`)仅用于指数权重/EBV 批次/ABLUP-G×E 性状下拉**,与 describe/correlation 共享的 `traitSel` 解耦(后者保留全量);asc 性状标签加 '↓越小越优' 角标 |
| `views/module_bre/trait/index.vue` | 表单/表格/详情/搜索四处加 direction el-selectdesc/asc+文案)、into_ebv 开关、default_h2 输入 |
| `views/module_bre/selection_rule/index.vue` | conditions_json 文本框说明:"op 缺省按性状方向(desc≥ / asc≤),rank_top_n 按方向取最优前 N" |
### 2.5 验证(`Temp/claude/e2e_direction_20260804.py`7 组全过)
基座 4 性状 dA(desc,1,0.5)/bB(asc,1,0.25)/cC(desc,0,None)/dD(desc,1,None) + 4 批次 pA(h²=0.5)/pB/pC/pD(h²=None) + 12 株 EBV=[10.0..32.0] 升序。
| 组 | 验证点 | 断言要点 |
|---|---|---|
| [1] | list_traits 三字段 + selection_only | 返回 direction/into_ebv/default_h2`selection_only=True` 过滤 `into_ebv='0'` |
| [2] | zsum 方向翻转 | 同数据 desc→asc 排名**精确互反**top2 从最高 EBV 2 株翻为最低 2 株) |
| [3] | into_ebv='0' 剔除 | 权重含 cC → 结果 traits 不含 cC、`result_json.dropped` 有提示 |
| [4a] | smith_hazel default_h2 兜底 | 批次 pD h²=None 但性状 dD 带 default_h2=0.25 → 成功 |
| [4b] | smith_hazel 无实测无先验 | 批次无 h² 且性状无 default_h2 → 409 `缺实测且无先验` |
| [5] | decision rank_top_n 方向 | asc 命中 EBV 最低 2 株、desc 命中最高 2 株;无 op 时 asc 走 `<=` |
| [6] | ebv_ranking 读时重排 | 性状事后改方向后按当前方向重排(rank 按优度重编号) |
| [7] | compare_predictions 方向感知 | asc 反序两批 rank1=最低 EBV 株(cur_ebv=10.0)desc 反序两批 rank1=最高 EBV 株(32.0) |
---
## 三、本轮修复的结构性 bug(方向盲区家族)
同一缺陷模式——**"高 EBV = 优"硬编码**——在排行/对比链路还有两处遗留,本轮一并修复:
### 3.1 `ebv_ranking` 方向盲区(读时重排)
原实现只在 `direction=="asc"` 时重排,`desc` 信任**写时持久化 rank**。当性状事后改方向(如 bB 由 asc 改 desc),已落库批次 rank 仍是 asc 序 → 读回倒序、最低 EBV 排第一。修复:**读时始终按 `predicted_value` + 当前 direction 重排并重编号 rank**,且 `self.db.expunge(r)`——因为 GET 会话走 `session.begin()`(退出自动提交),不 expunge 会把重排后的 rank 写回库,破坏"GET 纯读"。
### 3.2 `compare_predictions` 硬编码降序
原实现两处排序 `reverse=True`(写死高 EBV=rank 1)。对 asc 性状展示的 rank 列会把**最差株显示为第 1**(Spearman 相关/位移量对反转不变量,但暴露的 rank 列是错的)。修复:读 trait direction`reverse = (direction != "asc")` 同时用于 rank_cur 与 rank_prevcorr/flip 判定对反转不变量保持不变。
---
## 四、花粉档案 breeding_pollen2026-08-04
### 4.1 缺陷背景(田间刚需)
用户反馈:桃花期仅 3–7 天,**父本花粉是杂交季命脉**,但代码里没有 `bre_pollen` 表(仅在测试文件提及),`bre_pollination` 有花朵数/坐果数/去雄/套袋,却**无花粉采集日期、贮藏方式(-20℃/液氮)、活力检测(TTC 染色率/离体萌发率%)、授粉窗口计划**。后果:明年复盘"这批坐果为什么低"毫无抓手。核验属实(比描述更严重:一期文档规划的 `pollination_method`/`pollen_source`/`pollen_viability` 三字段也全未实现)。
### 4.2 架构决策(用户确认)
| 决策点 | 拍板 | 理由 |
|---|---|---|
| 父本锚点 | **树级 `male_tree_id`** FK→bre_tree(与 pollination.male_tree_id 一致) | 单父本溯源;混合/外地采集时为空 + `source_type` 区分 |
| 活力建模 | **单值+方法**`viability_method`[ttc/germination]+`viability_pct`+`viability_test_date` | 不建子表,够用且简单 |
| 窗口计划 | **派生有效期+校验**`collect_date`+`expiry_date`;窗口=[采集日,失效日] 由 pollination 校验) | 不建独立计划表;`/bre/pollen/available_lots` 提供"当前花期可用批次" |
### 4.3 数据模型(`backend/sql/weld_pollen.sql`,幂等 DDL + create_all 注册)
新表 `bre_pollen`lot_code UNIQUE / male_tree_id FK SET NULL / source_type tree|mixed|external / collect_date / collect_method / quantity / storage_method fridge|minus20|minus80|liquid_n2 / viability_method ttc|germination / viability_pct / viability_test_date / expiry_date / remark+ `ALTER bre_pollination ADD pollen_lot_id integer REFERENCES bre_pollen(id) ON DELETE SET NULL` + `ADD pollination_method varchar(32)`(补一期文档规划但遗漏的授粉方式)。
ORM`module_bre/pollen/` 五件套(model/schema/crud/service/controller),路由前缀 `/bre/pollen``module_bre/__init__.py` 注册 `PollenRouter`create_all 经 import 链自动拾取新模型)。
### 4.4 服务层关键逻辑(`pollen/service.py` + `pollination/service.py`
| 逻辑 | 实现 |
|---|---|
| 去重 | `_check_code`:批次号存在 → 409「已存在」(create/update/batch_import 均走) |
| FK 校验 | `assert_parents_exist`(父本树不存在→409;**自动跳过 None**,可空 male_tree_id 安全) |
| 标签填充 | `_attach_fk_labels`male_tree_id→tree_no;授粉侧 pollen_lot_id→lot_code |
| 授粉窗口校验 | `_validate_pollen_window`:授粉日期须在批次 [collect_date,expiry_date] 内,否则 409「授粉日期 X 不在花粉批次 Y 的授粉窗口 [A ~ B] 内」;update 时字段未变沿用库内现值 |
| 可用批次 | `available_lots(date_on)`:返回窗口内批次(label 含窗口区间+活力%),缺省今天 |
### 4.5 菜单/权限(`backend/sql/bre_menu.sql`
| 项 | 值 |
|---|---|
| 菜单 | 900056 花粉档案(parent 900030 杂交配组,hiddenroute `/bre/pollen`component `module_bre/pollen/index` |
| 按钮 E 段 | 900601-900608`module_bre:pollen:detail/query/create/update/delete/export/import/download` |
| 角色关联 | SUPER_ADMIN/ADMIN 范围扩至 900600-900699 |
### 4.6 前端
| 文件 | 变更 |
|---|---|
| `api/module_bre/pollen.ts` | PollenAPI 全套 + `getAvailableLots`(授粉窗口下拉) |
| `views/module_bre/pollen/index.vue` | 花粉 CRUD 页(贮藏/活力/采集方式下拉、采集/测定/有效期日期、活力% 数字) |
| `views/module_bre/pollination/index.vue` | 表单/表格/搜索加 `pollen_lot_id`(批次下拉)+ `pollination_method`(授粉方式下拉) |
| `views/module_bre/_shared/StageView.vue` + `stage_cross/index.vue` | 杂交配组第三标签「花粉档案」 |
### 4.7 验证(`Temp/claude/e2e_pollen_20260804.py` 全过 + `vue-tsc`
| 组 | 断言 |
|---|---|
| [pollen.create] | male_tree_no 标签=T015108、活力 85.5% 回填、窗口落库 |
| [dup] | 409「花粉批次号 … 已存在」 |
| [fk] | 409「采集父本树不存在或已被删除」 |
| [list/detail/options/available_lots] | 均含新批次;available_lots 返回窗口内批次 |
| [pollination 窗口内] | create 成功、pollen_lot_no 标签、授粉方式回填 |
| [window 窗口外] | 409 含「授粉窗口 [2026-07-01 ~ 2026-09-30]」 |
| [update/delete] | 授粉日期改窗口内仍通过;pollen update 活力/有效期生效;软删生效 |
---
## 五、选择指数·无性系级聚合(2026-08-04)
### 5.1 决策正确性背景
用户提出决策正确性缺陷:`selection_index` 对每个 `tree_id` 算指数并排名、`apply_selection` 写每株,但**桃是无性繁殖**——一个 clone 经扩繁的多株遗传同质,应聚合为一个遗传实体再排名。后果:同一个优系 3 株可能被拆成 3 个独立指数条目,可能只选中其中 1 株而漏掉该系其他株,也不利"系级决选"。用户拍板:指数前先按 clone 聚合 EBVmean/max 由**可靠性加权**),在 clone 级算 Smith-Hazel,再决定入选 clone。
**自株退化(工程补充)**`tree.clone_id` 在实生苗阶段可空(v2.2/A1 决策),若把无 clone 的株全部剔除,实生苗阶段选择会塌缩。故未晋升 clone 的实生株**退化为自株单元**(key=`-tree_id`,每株独立参与指数与决选),入选命中规则 stage 时晋升建 clone。
### 5.2 数据模型变更
**无表结构变更**(复用 `tree.clone_id` + `breeding_prediction_value` 既有字段)。仅接口与计算层变更:
| 接口 | 变更 |
|---|---|
| `SelectionIndexIn.aggregate` | 新增:`clone`(默认,无性系级)/ `tree`(旧单株级行为保留) |
| `selection_index` 响应 | 每条 top 项含 `clone_id`/`clone_code`/`n_trees`/`tree_ids`clone 级);tree 模式含 `tree_id`;整体 `"aggregate"` 回显 |
### 5.3 聚合与排名逻辑(`statistics/service.py`
**`_clone_units(cols, tree_ids, ebv_by_trait, pheno_by_trait, rel_by_tree)`**——聚合单元构造:
-`tree.id/clone_id/tree_no`(限定 tree_ids)→ 按 `clone_id` 分桶,空桶自株 key=`-tree_id`
- 单元 `ebv_src[c][key]` = 可靠性加权 `Σ(ebv×rel)/Σ(rel)`(桶内每 trait 各算一份),全 rel=0 回退简单均值;
- 单元 `pheno_src[c][key]` = 简单均值(smith_hazel 表型均值用);
- 返回 `[{key, clone_id, label, n_trees, tree_ids}]`
**排名单位切换**zsum / Smith-Hazel 改为在单元 key 集上计算(`ebv_src`/`pheno_src` 取数),方向感知沿用 v2.3(统一越大越优);Smith-Hazel 的 G 矩阵 pair 相关仍由树级 `ebv_by_trait` 抽样估计,b = P⁻¹Ga 在 clone 单元上评分。响应组装把单元字段映射回每条 top(tree 模式还原 `tree_id`)。
**`apply_selection` 按遗传实体写**
- top 项可能是 clone 级(`tree_ids`)或旧树级(`tree_id`),统一构建 `units`
- 每单元 `rel = min(rel_by_tree.get(t, 1.0) for t in u_tids)`(保守:最弱证据株门控全系);
- 写一条 `selection_result``clone_id` 指向全系(self 为 NULL+ `tree_id` 溯源一株(优先已有记录株)+ reason 含「系内N株」;
- 入选单元命中规则 stage → `_promote_tree_to_clone(首株, stage)` 幂等晋升建 clone(复用既有 clone、推进 stage),self 株由此回填 `clone_id`
### 5.4 前端
| 文件 | 变更 |
|---|---|
| `api/module_bre/statistics.ts` | `selectionIndex` data 类型加 `aggregate?: 'clone' | 'tree'` |
| `views/module_bre/statistics/index.vue` | 工具栏「聚合:无性系级/单株级」radio(默认无性系级)+ 说明文案(桃无性繁殖默认;未晋升实生株按单株参与);clone 模式结果表显示 clone_code/clone_id/n_trees/涉及单株 |
### 5.5 验证(`Temp/claude/e2e_clone_index_20260804.py`6 组全过)
基座:目标/组合/2 cloneX=2株 T1T2、Y=2株 T3T4+ 2 自株(T5T6+ 2 性状 A(desc) B(asc) + 2 批次。A 系 EBVT1=10(rel.1)/T2=30(rel.9) 加权 28T3=20(rel.9)/T4=40(rel.1) 加权 22——**可靠加权 X 排 Y 前,简单均值则 X20<Y30 反序**,验证加权是有效差异而非巧合。
| 组 | 验证点 | 断言要点 |
|---|---|---|
| [1] | clone 聚合单元 + 可靠加权排名 | 6 株 → 4 单元;clone 单元 n_trees=2/tree_ids 正确;自株 key 独立;X(加权28) 排 Y(加权22) 前 |
| [2] | tree 模式兼容 | `aggregate="tree"` 返回 6 条含 `tree_id`desc 首=EBV 最高株 T4 |
| [3] | 方向翻转 clone 级 | A 改 asc → top 精确互反,首=最低聚合 EBV 的 T5 自株 |
| [4] | smith_hazel clone 级 | b 含 A/Btop 含 clone 单元(n_trees/tree_ids 正确) |
| [5] | apply_selection clone 级写入 | top_n=2 → 写 2 条决选:cloneX 一条(clone_id + 溯源 T1/T2 之一 + reason「系内2株」)+ self T6 一条 |
| [6] | apply 晋升建 clone | top_n=4 含自株 → T5/T6 命中 sp 规则晋升建 cloneclone_id 回填);clone X 株 stage 推进 sp |
> **科学正确性收口**:指数排名单位与决选写入单位统一为**遗传实体**——同一优系多株不会再被拆散、单株误选漏选;自株退化保住实生苗阶段选择能力,且入选即晋升、天然补上 clone 归属。
---
## 六、配合力交配设计 design_type2026-08-04
### 6.1 缺陷背景(统计严谨)
用户指出统计严谨缺陷:`combining.solve` 只实现 **Griffing 对称全双列**model A),但 `run_combining``bre_combining_ability` 都**没有 `design_type` 字段**区分完全双列 / 部分双列 / line×tester(NCII) / NCIII。后果:用 line×tester 设计时,GCA/SCA 算法与 ANOVA 自由度都与全双列不同,当前一律按全双列算**会算错**(自由度错、GCA 含互反/自交效应)。用户拍板修复:`bre_cross_combination` / `bre_combining_ability``design_type``combining.solve` 按设计分支(line×tester 用 NCII 双因素模型)。
### 6.2 数据模型变更
`bre_cross_combination``design_type` varchar(16) NULL(缺省按 `full_diallel` 计);`bre_combining_ability` 同步落 `design_type`。取值**硬编码校验**(同 `selection_index.method`,非 sys_dict):`full_diallel`(完全双列,默认)/ `partial_diallel`(部分双列)/ `line_tester`line×tester NCII/ `nciii`NCIII 测交)。DDL 见 `backend/sql/weld_combining_design.sql`(幂等 ALTER + COMMENT)。create/update 接受 code 或中文标签并归一化,非法值 409(`交配设计取值不合法`)。
### 6.3 求解器分支(`scripts/breeding_stats/combining.py`
| 设计 | 模型 |
|---|---|
| `full_diallel` / `partial_diallel` | **Griffing 对称全双列** model A`y_ij = μ + g_i + g_j + s_ij`,Σg=0 约束,最小二乘 BLUE |
| `line_tester`NCII | **双因素模型** model B`y_ij = μ + l_i + t_j + (lt)_ij`parent1=line(母本)、parent2=tester(父本),**分别 Σl=0 / Σt=0**SCA = line×tester 互作 = 残差 |
| `nciii` | 同一 model B,门槛 **tester 恰好 2 个** |
工程要点:
- **可辨识性**tester 列从索引 `1+n_l` 起 → **显式列选择**(非连续切片);基线列切出后吸收剩余列。
- **顺序 ANOVASS 型)**SS_lineintercept→line)→ SS_tester(→tester after line)→ SS_sca(残差);df_line=n_l-1、df_tester=n_t-1、df_sca=n-1-df_line-df_tester。输出 `design`/`roles`/`df_line`/`df_tester`/`df_sca`
- **门禁**:同亲本既作 line 又作 tester(角色重叠)→ `ValueError` → 任务 FAILED + CustomException「角色重叠」;NCIII tester≠2 → 拒绝。
- **gca_se 持久化**GCA 标准误**内嵌 `anova_json["gca_se"]`**(避免 DB 迁移,gca_json/sca_json 形状稳定);前端 GCA 表加 SE 列。
### 6.4 运行过滤与持久化(`statistics/service.py::run_combining`
`run_combining``design_type` 参数透传 `combining.solve`**按设计过滤组合**——只纳入 `cc.design_type or 'full_diallel' == dt` 的组合,杜绝全双列标注组合混入 line×tester 运行(混算根因)。`bre_combining_ability.design_type` 随结果落库,`anova_json``design` 供前端分显示。
### 6.5 前端
| 文件 | 变更 |
|---|---|
| `api/module_bre/statistics.ts` | `RunStatsPayload.design_type?: string`(配合力运行时下发) |
| `api/module_bre/cross_combination.ts` | 查询/表格/表单类型加 `design_type` |
| `views/module_bre/statistics/index.vue` | 运行对话框「交配设计」radioDESIGN_LABELS 四选项 + 说明);配合力批次表「设计」列;详情 ANOVA 按 `a.design` 分支——NCII/NCIII → line/tester/互作 F 与 p + roles 计数,双列 → GCA FGCA 表 SE 列;SCA 表展示 |
| `views/module_bre/cross_combination/index.vue` | 表单/表格/详情/搜索四处 `design_type`radio + DESIGN_LABELS 中英映射,createInitialFormData 默认 full_diallel |
### 6.6 验证(`Temp/claude/e2e_combining_design_20260804.py`5 组全过 + `vue-tsc`
基座:数值性状 + 目标 + 6 亲本;NCII 2×2line_tester 4 组合)+ NCIII 2×2nciii 4 组合)+ 1 条 full_diallel(应被 line_tester 运行排除)。
| 组 | 验证点 | 断言要点 |
|---|---|---|
| [1] | NCII line_tester 运行 | design_type 落库;anova.design=line_tester**df 1/1/1**roles.lines/testers 正确;平衡 2×2 精确解 gca{l1:-2,l2:+2,t1:-1,t2:+1}SCA 恰 4 条;`E2EDTMIX`full_diallel)被排除;`anova.gca_se` 内嵌 |
| [2] | NCIII 分支 | 只纳入 nciii 标注组合;同一双因素模型;df_line/df_tester=1SCA 4 条;gca{n1:-2,n2:+2} |
| [3] | 角色重叠 gate | 同亲本作 line 又作 tester → 任务 FAILED + CustomException 含「角色重叠」 |
| [4] | create/update 校验 | `line_tester`→原样、中文「完全双列」→归一化 `full_diallel``bogus_design`→409、update→`nciii` |
| [5] | 持久化复查 | commit 后新会话 design_type / anova.design / gca_se 均真实落库 |
> **科学正确性收口**:配合力计算不再默认"一律全双列"——line×tester(NCII)/NCIII 走双因素模型,GCA/SCA 与 ANOVA 自由度按设计正确计算;运行层按 `design_type` 过滤组合,杜绝混算;角色重叠直接拒绝,消除亲本角色语义错误。**待办**`partial_diallel`Griffing model 4,无互反)与 model 3(含互反、需单株表型)本轮未单独实现,随使用按需补。
---
## 七、统计严谨·预测完整性与 MLOps 复现性(v1.42026-08-04
### 7.1 缺陷背景(七条复审逐条核实)
用户抛出七条统计严谨/完整性复核主张,**逐条对照代码核实均为真缺陷**后按优先级落地(便宜且值得马上补 ②④ → 中期 ③⑤ → 需新能力 ①⑥):
| # | 主张(核实) | 落地 |
|---|---|---|
| ② | `bre_prediction_value` 只存 reliability,未存预测准确度 **PA** | 加 `pa = √reliability`;批次 `bre_prediction.accuracy` 改填真 PA |
| ④ | `PredictionValueModel.germplasm_id` **永未填充**run_ablup 只写 tree_id | 写 EBV 行时回填 `tree.germplasm_id`,亲本级 EBV 查询可用 |
| ③ | `bre_prediction` 无 data_version / 输入哈希 / 引擎版本,**MLOps 溯源不全** | 加三字段 + 确定性输入哈希,同数据重跑一致、改观测必变 |
| ⑤ | `bre_rootstock` 仅 code/name/remark,无矮化类、砧穗亲和性 | 扩 `dwarf_class` + `compatibility`,全链路透传 |
| ① | Smith-Hazel 的 G 矩阵用"EBV 皮尔逊相关"近似(**无真 MT-BLUP** | 改 **Calo 可靠性校正** `r_g = r_EBV/√(rel_i·rel_j)`(真 MT-BLUP 记遗留) |
| ⑥ | 果园**株间竞争 / 边缘效应**未建模 | `run_ablup` 新增 `covariate="competition"`Chebyshev 邻域株数) |
| ⑦ | 前端 D 层 `_coming_soon` 占位页 | **保持占位属预期**P2 远景,本轮不动) |
### 7.2 数据模型变更(`backend/sql/weld_prediction_rigor.sql` + `weld_rootstock.sql`
| 表 | 列 | 类型 | 说明 |
|---|---|---|---|
| `bre_prediction_value` | `pa` | double precision | 预测准确度 PA = √reliability(每株每性状) |
| `bre_prediction` | `data_version` | varchar(32) | 数据版本(`_DATA_VERSION="v2.7"`service.py |
| `bre_prediction` | `input_hash` | varchar(64) | SHA256`{tree_id}:{均值表型}` + `{个体}\|dam\|sire` 确定性序列化(数据漂移可检测) |
| `bre_prediction` | `engine_version` | varchar(32) | 引擎版本(`blup.ENGINE_VERSION="1.0.0"` |
| `bre_rootstock` | `dwarf_class` | varchar(32) | 矮化类:矮化/半矮化/乔化/柱状/其他 |
| `bre_rootstock` | `compatibility` | varchar(16) | 砧穗亲和性:强/中/弱 |
> `accuracy` 语义正名:原误填"均值 EBV 的平方根"(量纲不符),现改填**真 PA = √(批次内可靠性均值)**`numeric(5,3)`3 位小数),与 `bre_prediction_value.pa`(每株)口径一致。
### 7.3 引擎逻辑(`statistics/service.py` + `blup.py`
| 规格点 | 实现 |
|---|---|
| ② PA | `run_ablup` 写 EBV 行 `pa = √reliability`;批次 `accuracy = √(均值 rel)``ebv_ranking` 单株响应透出 `pa` |
| ④ germplasm_id | `run_ablup` 写 EBV 行 `germplasm_id = tree.germplasm_id`(晋升回填的种质;无种质株保持 NULL 合规) |
| ③ 溯源 | 批次级落 `data_version` / `input_hash` / `engine_version``input_hash` 覆盖全部参与树 × 全部观测(含 NULL 表型拼接),**改 1 条观测哈希必变** |
| ① Calo | `_smith_hazel_index` G 非对角改 `r_g = r_EBV/√(rel_i·rel_j)`(rel 取配对树该性状均值),钳制 [−1,1];可靠性缺失/近零 → 0(保守);`extra["g_corr"]`(性状对)+ `extra["g_note"]``bre_selection_index.result_json` 可审计;rel 数据即 ② 落库的 reliability |
| ⑥ 空间竞争 | `run_ablup(covariate="competition")`:同 **(plot_id, block_no)** 网格内 Chebyshev 距离 1(8 邻域,不含自身)株数作协变量;相邻越多竞争越强、边缘株相邻少隐式捕捉边缘效应;G×E 分支同步支持(三处 `covariate == "crop_load"` 泛化为 covariate 真值);**全无 row/col → CustomException**(显式数据需求);`bre_tree.row_no/col_no` 数据能力已全链路就位(模型/前端录入/表格/详情/导入导出) |
### 7.4 前端
| 文件 | 变更 |
|---|---|
| `api/module_bre/statistics.ts` | 指数批次表/EBV 行类型加 `germplasm_id`/`pa` |
| `views/module_bre/statistics/index.vue` | 指数批次表加 `germplasm_id`/`pa` 列;ABLUP 运行对话框协变量 el-checkbox 改 **radio**(无 / crop_load / competition+ 说明文案 |
| `api/module_bre/rootstock.ts` + `views/module_bre/rootstock/index.vue` | `dwarf_class`/`compatibility` 全量:常量、搜索、表格、详情、表单、handleSearch/onResetSearch |
### 7.5 验证(三探针全过 + `vue-tsc`
**`e2e_prediction_rigor_20260804.py`(②③④,4 组)**
| 组 | 断言 |
|---|---|
| [1] | 每株 `pa = √rel` 逐条一致;批次 `accuracy` = √(均值 rel);溯源三字段(data_version=v2.7 / engine=1.0.0 / acc=0.439);germplasm 级查询(按 gA 查得 2 条);ebv_ranking 透出 pa |
| [2] | 复现性:同数据重跑 input_hash 完全一致 |
| [3] | 数据漂移:改 1 条观测值后重跑哈希必变 |
| [4] | 跨会话持久化:commit 后新会话读取值/哈希仍在(全行扫描断言) |
**`e2e_rootstock_20260804.py`(⑤)**create/detail/update/list(搜索 dwarf_class/options/export(含新列)/template(下拉选项)/DB 直查全过。
**`e2e_corr_spatial_20260804.py`(①⑥,3 组)**
| 组 | 断言 |
|---|---|
| [1] | Calo 校正值:`g_corr` 含性状对、`g_note` 含"可靠性校正"`got_rg` 与独立重算 `clamp(r/√(rel_i·rel_j))` 一致(容差 1e-4),例 r=0.9966/rel 0.1925·0.1345 → r_g=1.0 |
| [2] | competition 消费验证:有坐标运行成功,EBV 与无协变量最大差异 0.5465(差分消费,非仅字段) |
| [3] | 数据需求判定:全无 row/col → CustomException 含 row_no/col_no |
### 7.6 遗留(已记账,不动引擎)
- **真 MT-BLUP**:多性状 G 需全新多变量 REML 求解器(Kronecker 积 G/R + 方差分量迭代,数值收敛风险大)。本轮用 Calo 可靠性校正顶上(业界对"EBV 相关替代 G"的标准修正),`g_corr`/`g_note` 落库可审计。后续要做即按此接口替换。
**2026-08-04 追加加固**:逐对独立估计的 r_g 在 ≥3 性状时可能违反三角不等式使 G 非正定 → `_smith_hazel_index` 构造 G 后做**最近半正定投影**(Higham 特征值截断,`np.linalg.eigh`),b=P⁻¹Ga 才良性;新增稳定性警示 `extra["warnings"]`(完整观测树 <30 / P 条件数 >1000 / G 非正定已投影 / r_g 钳到 [−1,1] 边界)随 `result_json` 落库可审计,不阻断。数值验证:0.9/0.9/0.9 相关阵 det<0 → 投影触发;2 性状正定场景无警示。
- **⑦ 前端 D 层占位**:分子育种/品种保护/AI 增强 `_coming_soon` 保持占位,属 P2 远景预期。
### 7.7 组合得失漏斗 v_combination_funnelv2.82026-08-04
**缺陷背景(逐条复审第 8 条,最贴业务)**:数据本已齐全——`bre_pollination.flower_count/effective_count`(花→果)、`bre_seed_lot.seed_count/germination_rate`(种→苗)、`bre_seedling.seedling_count`(出苗)——但**无任何按 `bre_cross_combination` 汇总的派生指标**:结实率/出苗率/选择强度未滚到组合层,配合力第一手证据(组合得失链路)字段在但没合成进配合力上下文。核实属实:全库无 结实率/出苗率/选择强度/funnel 实现;唯一"选择强度链"是 `seed_lot.used_count` 机械累加(账本非派生指标);`run_combining` 只取 `func.avg(value_numeric)` 组合均值、`combining.solve` 只认 `combo/parent1/parent2/value`。用户拍板:补视图/派生表即可,数据已齐、风险极低。
**六级链路与派生指标**
| 环节 | 数据源(均按 combination_id 聚合) | 派生 |
|---|---|---|
| 花→果 | `bre_pollination` Σflower_count / Σeffective_count | **结实率** fruit_set_rate = Σeff/Σflower×100 |
| 果→种 | `bre_seed_lot` Σseed_count / AVG germination_rate | 出苗基数 |
| 种→苗 | `bre_seedling` Σseedling_count / Σstrong_seedling_count | **出苗率** emergence_rate = Σseedling/Σseed×100 |
| 苗→定植 | `bre_planting` Σtree_count | 定植数 |
| 定植→树 | `bre_tree` 非软删 COUNT | 树数(评价群体基数) |
| 树→入选 | `bre_selection_result` 非软删 COUNT | **选择强度** selection_rate = 入选数/树数×100 |
缺环节的组合比率列留 NULL`bre_cross_combination` 主表 LEFT JOIN 六源,按组合一行)。
**实现**
- `backend/sql/weld_combination_funnel.sql``v_combination_funnel` 普通 VIEWDROP IF EXISTS + CREATE OR REPLACE 幂等,F2 决策保 fresh 不用 MV),psql 应用(create_all 只建 ORM 表,视图须手写 SQL)。
- `statistics/service.py::combination_funnel()`:查视图返回 `{rows, n}`Numeric→int/float 归一),视图未就绪 CustomException 提示。
- `statistics/controller.py``GET /statistics/combination-funnel``module_bre:statistics:query` 权限)。
**验证(`Temp/claude/e2e_combination_funnel_20260804.py`3 组全过)**
| 组 | 断言 |
|---|---|
| [1] | 全六级组合:150 花/50 果→结实率 33.33%、100 种(发芽率均值90%)/80 苗→出苗率 80%、55 定植/3 树/2 入选→选择强度 66.67%,逐计数精确断言 |
| [2] | 仅授粉组合:fruit_set=50.0% 算得出,种/苗/定植/树/入选 全 NULLLEFT JOIN 正确性) |
| [3] | 跨会话持久化:commit 后新会话读同值 |
> **工程教训**:首跑清理阶段 FK 崩——helper 里 `db.add()` 后**未 flush 就取 `.id`** 拿到 None,删除 `WHERE id IN (None,…)` 不命中留下孤儿行。修复:add 后先 `await db.flush()` 再取 id。此为探针自身 bug,非视图/端点缺陷。
---
## 八、分子育种「建数据能力」(2026-08-04)
> 分子层四表 DDL 早已在 `backend/sql/bre_tables.sql`(§3.7),但 module_bre 无 ORM/服务 → DNA 指纹/QTL/GWAS/GS 全 inert。用户拍板先建「数据能力」:四模块 CRUD + Excel 导入导出 + VCF 导入 + 指纹防错(无性系混杂检测)。GS/GWAS/GBLUP 引擎仍占位。菜单 900210-900213 由占位页切真实页面,900214 GWAS 保持 `_coming_soon`。
### 8.1 DDL 缺口与补列
`bre_genotype_sample` 原 DDL 无样本名字段(只有 dataset_id/source_type/source_id/sample_type/sample_date/method/lab/remark)。VCF 表头映射、UI 展示、指纹报告都靠样本名 → 按 weld 惯例补列(create_all 只建新表、不改既有表):
```sql
ALTER TABLE bre_genotype_sample ADD COLUMN IF NOT EXISTS sample_name varchar(128);
COMMENT ON COLUMN bre_genotype_sample.sample_name IS '样本名称(VCF 表头/UI 展示,可空)';
CREATE INDEX IF NOT EXISTS ix_bre_genotype_sample_dataset_name ON bre_genotype_sample (dataset_id, sample_name);
```
### 8.2 四模块五件套
| 模块 | 表 | 关键列 / 约束 | 导入必填 |
|---|---|---|---|
| marker | bre_marker | marker_name UNIQUEchromosome/position/marker_type/panel/assembly_version | marker_name |
| genotype_dataset | bre_genotyping_dataset | dataset_name/platform/panel/purpose/run_date/lab | dataset_name |
| genotype_sample | bre_genotype_sample | **sample_nameweld 补)**dataset_id FK→dataset | sample_namedataset 名解析成 ID |
| genotype_call | bre_genotype_call | sample_id/marker_id 双 FK + **UNIQUE(sample_id,marker_id)**allele 按 VCF/GP 编码 | sample_name/marker_name(解析成 ID/allele |
- **五件套**model/schema/crud/service/controller`module_bre/__init__.py` 注册。ORM 严格对齐 bre_tables.sql——分子表无 `status` 列,模型覆盖 `__table_args__``Index("ix_bre_<表>_created_deleted", "created_time", "is_deleted")`)跳基类默认 status 索引。
- **FK 存在性**sample/call create/update 前 `assert_parents_exist`(父级软删也拦截→409「XX不存在或已被删除」)。
- **名称透出**get_list/detail 后查 ref_map 填 dataset_name / sample_name / marker_nameseed_lot combination_name 同款 `_attach_fk_labels`)。
- **Excel 导入导出**header_dict 中文头→列,名称解析成 ID;导入模板/导出 mapping_dict 含 created_by 名解析。
### 8.3 VCF 导入(POST /bre/genotype_call/import/vcf
1. 跳过 `##` 行,定位 `#CHROM` 表头 → FORMAT 后为样本列,GT 在 FORMAT 子字段索引。
2. markerID 非 `.` 用 ID、否则 `CHROM:POS`,按 UNIQUE 查重 → 缺失建号(marker_type=snp、panel=dataset.panel)。
3. 样本:按 `(dataset_id, sample_name)` 查重 → 缺失建号(sample_type=vcf、method=genotypingsource 留空)。
4. GT`|``/` 规范化;`.`/`./.`/`./` 跳过;allele 存 GT 编码(0/0、0/1、1/1)。
5. 内存 dict 以 `(sample_id, marker_id)` 去重(文件内重复 last-wins);已存在分型跳过 → **重跑幂等**500/批批量 insert。
6. 返回 `{dataset_id, dataset_name, variants, samples, samples_created, markers_created, calls_inserted, skipped_missing}`
### 8.4 DNA 指纹防错(GET /bre/genotype_call/fingerprint/check
纯数据层比对,无外部依赖:
1. 取 dataset 内样本 + 分型结果,构建 `{sample_id: {marker_id: allele}}`allele 规范化。
2. 两两比对:共同 marker `< min_markers` 跳过(信息量不足);否则 `identity = 匹配数/共同数`
3. 判定:同源对(source_type+source_id 相同且非空)`identity < threshold` →「同源指纹不一致(疑似样品污染/取错)」;异源对 `identity ≥ threshold` →「异源指纹一致(疑似无性系混杂/标签互换)」。
4. 返回按 identity 降序的 pair 行(样本名含来源、共同数、匹配数、identity、标记)。
### 8.5 菜单 / 权限 / 前端
- `bre_menu.sql`900210-900213 component_path 由 `_coming_soon/index``module_bre/{marker,genotype_dataset,genotype_sample,genotype_call}/index`F 段按钮 `id=900700+seq*10+border`(八按钮:查看/查询/新增/编辑/删除/导出/导入/下载模板),`ON CONFLICT (id) DO NOTHING` 幂等;SUPER_ADMIN/ADMIN 角色关联 64 行。
- 前端:4 api .ts + 4 index.vue。genotype_sample 搜索/表单带 dataset 下拉;genotype_call 带 sample/marker 双下拉 +「导入 VCF」(dataset 下拉+文件上传,报计数)与「指纹检测」(dataset 下拉+min_markers+阈值,结果表两色标签:danger=同源不一致、warning=异源一致)两个自定义按钮/对话框。
### 8.6 e2e 验证(e2e_molecular_20260804.py
| 组 | 断言 |
|---|---|
| [1] | 四模块 CRUD 闭环:dataset→marker→sample→call create/detail/update/list/optionsFK 名称透出(sample.dataset_name、call.sample_name/marker_name |
| [2] | 唯一键/父级:重复 (sample,marker)→409「已存在」;sample 引用不存在 dataset→409;重复 marker_name→409 |
| [1b] | 删除闭环:call→sample→marker→dataset 软删后 detail 不可见 |
| [3] | 指纹:6 样本 3 标记——同源对 1 处不一致→命中「同源指纹不一致」(identity 2/3);异源对全一致→2 对「异源指纹一致」(identity 1.0);同源全一致对不误报;共同 marker 不足(S-Y 仅 1 标记)对不出现 |
| [3b] | 空数据集指纹 samples=0/flagged=0 |
| [4] | VCF6 variant × 3 样本——markers_created=5/samples_created=3/calls_inserted=13/skipped_missing=2;文件内重复标记 last-wins(P01,V100)=1/1);自动建号元数据(V500 chrom=2/pos=500/type=snp/panel=dataset.panel);**重跑幂等**samples/markers/calls 均 0 新增) |
清理按 FK 逆序物理删(call→sample→marker→dataset,前缀 E2EM-),重跑幂等。
---
## 九、精修项落地:DUS 数据能力 + stage 感知 + k-fold CV + 公平性报告(2026-08-04
### 9.1 缺陷背景(用户核实四条缺口,全部拍板落地)
用户核对后确认四条精修缺口属实并拍板「全部落地,更新文档,保留版本」:
1. **DUS/品种保护**:无 DUS 模块、无 UPOV TG/53 描述符观测模板(菜单 900230 预留仍占位);档位=**数据能力(三表)**。
2. **stage 感知**`bre_trait.stage`(v2.0 定义)存在但 BLUP/选择指数/决策无视,童期/成株性状混用无警示。
3. **模型外部验证**:可靠性仅 PEV 法(内部);档位=**ABLUP + GXEBLUP 双支持** k-fold CV(外部预测准确度)。
4. **AI 伦理·分组偏差**:G×E 引擎已覆盖互作,缺按 site 的系统性 EBV 偏差/公平性报告。
### 9.2 DUS 数据能力(三表)
| 表 | 业务列 | 约束 |
|---|---|---|
| `bre_dus_descriptor` | descriptor_no(UPOV TG/53 特性号)、trait_id→bre_trait(可空=自由描述符)、trait_code 快照、descriptor_name、expression_type(QN/PQ/QL)、method、example_varieties(标准品种)、test_stage、required | uq_descriptor_no |
| `bre_dus_test` | test_name、germplasm_id→bre_germplasm、trial_study_id→bre_trial_study、tester、test_date、status(planning/testing/completed/report)、conclusion(pending/distinct/not_distinct)、report_path | uq_test_name |
| `bre_dus_observation` | dus_test_id→bre_dus_test、dus_descriptor_id→bre_dus_descriptor、value_numeric、value_text、expression_note | uq(test,descriptor) |
- 表新建走 **create_all**(不在既有 DDL,无需 weld);五件套 `module_bre/dus/` 注册 `/bre/dus_test/*`descriptor 9 端点含导入导出+模板,test 9observation 6)。
- 种子 `sql/bre_dus_seed.sql`UPOV TG/53 桃描述符 **15 条**`trait_code → bre_trait LEFT JOIN` 解析 trait_id**8 条关联**),`ON CONFLICT(descriptor_no) DO NOTHING` 幂等。
- 菜单 `sql/bre_menu_refine.sql`900230 component 切真实页 `module_bre/dus/index`**G 段按钮 900800-900808**perm `module_bre:dus_test:*`,八按钮含导入/下载模板)+ SUPER_ADMIN/ADMIN 角色关联。
- FK 名称透出:trait_name / germplasm_name / trial_study_name / descriptor_no+descriptor_name;描述符导入按中文头「关联性状编码」→trait_id。
### 9.3 stage 感知
- `_trait_meta_map` 读入 `trait.stage`(缺省 evaluation);`PredictionModel.stage` 落库(`sql/weld_refine.sql` 补列)+ 预测批次表展示(童期 warning / 成株 primary 标签)。
- `selection_index``stage` 入参:传 juvenile/evaluation 只纳入该阶段性状(异阶段写入 `skipped_stage`,同阶段无性状→409 带剔除清单);不传且横跨两阶段 → `stage_warning`(童期/成株性状清单 + 「证据来自不同发育阶段,需人工复核」)。
- `decision_preview` 同理:传 stage 时异阶段规则条件跳过(matched=None、reasons 不出现);不传且规则引用性状横跨两阶段 → `stage_warning`
### 9.4 k-fold CV(外部验证)
- 求解器 `scripts/breeding_stats/blup.py::kfold_cv`:**sire 家系分层留出**(同家系不进训练/测试双折避免乐观,无父本个体自成一系)、固定种子;每折训练子集重估方差组分 → 留出个体 EBV 由系谱预测(个体保留在 A 矩阵、仅掩蔽表型)→ pearson+RMSE;单折失败(train<2 / G×E 结构不可辨识)记 None+warning 不中断。
- 落库 `bre_cv_result`method=KFCV/ABLUP|KFCV/GXE、k/n_total/n_individuals/mean/pooled pearson/RMSE/cv_accuracy/h2+ `bre_cv_fold` 明细;MLOps 溯源 data_version/input_hash/engine_version 复用。
- 端点:`POST /bre/statistics/cv/run`trait_id/code/year/fixed/covariate/**gxe/gxe_env**/k 2~10ABLUP 与 GXEBLUP 同入口)、`GET /bre/statistics/cv`(批次)、`GET /bre/statistics/cv/{id}`(含折明细)。
### 9.5 公平性报告(只读,不建表)
`GET /bre/statistics/fairness?prediction_id=&group_by=site&threshold_sd=1.0`
- `site_summary`:每 site n_trees/n_groups/n_individuals/EBV 分布(mean/sd/min/max/mean_reliability/**deviation=site_meangrand_mean**、`flagged=|deviation|>threshold_sd×grand_sd`
- `rank_consistency`:site 内组合均值 EBV 排名 vs 全体组合排名,共享组合 ≥2 时手写 Spearman。
- `gxe_pattern`:组合×site 单元均值(单元 n≥2),暴露跨 site 排名翻转。
### 9.6 验证(e2e_refine_20260804.py 全过 + vue-tsc
| 组 | 断言 |
|---|---|
| [1] | DUS:三表 CRUD + 种子命中(15 条、TG/53/5=果形、≥1 条关联 trait_id)+ FK/唯一键/子表阻断删除/软删全 409 路径 |
| [2] | stageselection_index 无 stage→警示含两性状;juvenile→traits 只含童期 + skipped_stage=[成株]decision_preview juvenile→成株规则条件跳过(matched=None)、童期规则命中部分株;ABLUP 批次 stage 落库(juvenile/evaluation 各对) |
| [3] | CVABLUP k=3 折 pearson 全非 Nonesire 家系留出→留出株 EBV 收缩到均值、pearson=0 为设计预期)+ GXE k=2 跨 site 跑通 + 幂等重跑新批次 + data_version=“v2.7”/engine/input_hash + job SUCCESS |
| [4] | fairness2 site 9 株 site_summary 2 行(deviation 异号、flagged 布尔)+ rank_consistency 2 行(shared≥2、spearman 非 None+ gxe_pattern n≥2 单元 |
清理按 FK 逆序物理删(前缀 E2ER-),TG/53 种子描述符与既有数据不动。
---
## 十一、六项能力完善:MT-BLUP + GBLUP/ssGBLUP + DUS 特异性检验 + AMMI/FW 稳定性 + MLOps 重训回滚 + BLUP stage 拆分(2026-08-04
### 11.1 缺陷背景(用户两轮复核核实六条缺口、逐项拍板「全部落地」)
1. **MT-BLUP**Smith-Hazel 的 G 非对角仍用 Calo 校正 EBV 相关近似(`service.py` 已诚实文档化为回退),缺真遗传相关估计 → 拍板**成对双性状 BLUP**(非全多变量 REML)。
2. **GBLUP/ssGBLUP**:分子层只有数据能力(四模块 CRUD + VCF + 指纹),无 VanRaden G / 基因组选择引擎 → item 明确两者都做。
3. **DUS 特异性统计检验**`conclusion` 纯人工(无判定端点)→ 拍板**参照=同 trial_study 自动 + 可显式指定**。
4. **AMMI/Finlay-Wilkinson 稳定性**:G×E 随机效应已估 σ²gxe,无跨环境稳定性排名。
5. **MLOps 自动重训 + 版本回滚**APScheduler 在但统计无重训接线、无 is_active → 拍板**漂移检测端点 + 手动触发**,不注册 cron。
6. **BLUP stage 拆分**run_ablup 只打标签(model_name 后缀)不按 stage 取数。
### 11.2 MT-BLUP`scripts/breeding_stats/mtblup.py` + `statistics/service.py`
- `mtblup.solve_bivariate(pedigree, phenos, code1, code2)`ENGINE_VERSION=1.0.0):共享系谱复用 `blup._order_pedigree/_build_ainv` 建 A/A⁻¹;模型 y=[y1;y2] 堆叠、X/Z 块对角;Var(u)=G0⊗AG0=[[Va1,ρ√(Va1Va2)],[·,Va2]])、Var(e)=diag(Ve1,Ve2)⊗I。**降维**Va1/Ve1、Va2/Ve2 取自各性状单性状 REML(=既有 herit 来源),仅对 ρ∈[0.99,0.99] 1-D golden-max 最大化精确 REML ll(复用 `_golden_max` + `_solve_gxe` 的 V=Z(G0⊗A)Z'+R、slogdet+yPy 模板)。返回 r_g/σa 矩阵/n_common/n_iter/converged/warning;单性状观测 <2 → 该性状 NAN。
- `run_genetic_corr(trait_ids, year)``_gather_shared_phenos` union 树集 + 树级均值 + 共享系谱;两两 bivariate,对角=单性状 h²·P_ii、非对角=r_g·√(G_ii·G_jj) 组装 G0Higham 特征值截断投影半正定;落 `bre_genetic_corr_result`trait_codes/matrix/sigma_a/heritability/pairs_json/n_common + data_version/input_hash/engine_version+ `StatisticsJobModel(job_type="GENCORR")``list_genetic_corr` / `genetic_corr_detail`
- `_smith_hazel_index``g_method="calo"|"mtblup"``selection_index` 透传):mtblup 时逐对 `solve_bivariate` 填 G 非对角,单对不收敛回退 Calo + warning 清单(不阻断指数);≥3 性状 r_g 三角不等式违反 → 特征值截断投影半正定;`extra["g_source"]="mtblup|calo"` 落库可审计。
- 端点:`POST /statistics/genetic-corr/run`trait_ids 多选 + year)、`GET /statistics/genetic-corr``GET /statistics/genetic-corr/{cid}`
### 11.3 GBLUP / ssGBLUP`scripts/breeding_stats/genomic.py` + `statistics/service.py`
- `build_g_matrix(genotypes, markers, *, maf_min, method=2, blend=0.02)`dosage 0/1/2 样本×标记,缺格按列均值 2p 填充;MAF 过滤(`maf>=maf_min`,全滤 → ValueError);VanRaden **method1** G=ZZ'/2Σp(1-p)diag≈1/ **method2** G=ZDZ'D=1/[2p(1-p)]);blend 岭 `G=(1−ω)G+ω·mean(diag)·I` 保证可逆。
- `solve_gblup(pedigree, phenos, G, *, tol)`:仅基因型个体入模型,MME 用 G⁻¹ 替代 A⁻¹;σ²a 用 `_golden_max` profile(仿 `blup.solve`);返回 ebv/reliability(=1PEV/σ²a)/h2/σa/σe/converged/warning。
- `solve_ssgblup(pedigree, phenos, G, genotyped, *, tol)`**H⁻¹ = A⁻¹ + [[0,0],[0, G⁻¹ A22⁻¹]]**Aguilar et al. 2010);A22=A[genotyped,genotyped] 稠密子阵 `np.linalg.inv`(病态加 `_RIDGE=1e-6`);**V 块必须用 H 协方差**——按 Aguilar 块公式构造完整 HD=GA22H=A+[[A12A22⁻¹DA22⁻¹A21, A12A22⁻¹D],[D·A22⁻¹A21, D]];非基因型块 += L·D·L'、交叉块 += L·D、基因型块 = G),REML 似然 V=ZH[z,z]Z'+RH⁻¹ 仅进 MME 系数矩阵。**修复前 V 块误用 `Hinv[z,z]` 致似然失构**。基因型+非基因型个体都出 EBV。
- `run_gblup(dataset_id, trait_id, trait_code, year=None, method="gblup"|"ssgblup", maf_min=0.05)`:取数 `bre_genotype_call` join `bre_marker` pivot sample×marker 剂量(`"0/0"→0/"0/1"→1/"1/1"→2`,多等位跳过);样本→个体映射 source_type='tree' 直连 + sample_name↔tree.tree_no/germplasm.cultivar_name 名称兜底,未映射→跳过 + note warning 清单;`genotyped = sorted(dosage)` 对齐 `build_g_matrix` 内部 `sorted(genotypes)` 行序(**修复前用全部映射树,零有效调用树会错位 G 索引静默污染 EBV**);input_hash 覆盖(基因型矩阵哈希 + phenos + ped);落 PredictionModelmethod=GBLUP/ssGBLUPengine_version 落库)+ PredictionValueModel(每树 EBV/rel/pa/rank+ job_type="GBLUP"`list_genotyping_datasets`genotyping_dataset 列表 + n_samples)。
- 端点:`POST /statistics/gblup/run``GET /statistics/gblup/datasets`;批次/EBV 复用 `list_predictions`(按 method 过滤)+ `ebv_ranking`
### 11.4 DUS 特异性统计检验(`dus/service.py` + `fdist.py`
- `fdist.f_icdf(p, d1, d2)`F-CDF 二分反解;`t_crit(alpha, df)=√f_icdf(alpha, 1, df)`t²=F(1,df))。
- `dus.distinctness(candidate_rows, reference_rows, descriptor_meta, alpha=0.01)`
- **QN**:候选 vs 参照单因素 ANOVA → MSE,df → `LSD = t_crit(α,df)·√(MSE·(1/n_cand+1/n_ref))``|cand_mean ref_mean| > LSD` → 该描述符 distinct(逐参照比较,任一超 LSD 即 distinct)。
- **PQ/QL**:表达状态众数——候选众数 ∉ 参照众数集 → distinct。
- 汇总逐描述符 {descriptor_no, name, expression_type, candidate_value, ref_values, statistic, critical, distinct};总体建议=≥1 个 **required** 描述符 distinct → distinct,否则 not_distinct,数据不足→pending(不判)。
- `test_distinctness(test_id, reference_test_ids=None, alpha=0.01)`:默认参照=同 `trial_study_id` 其他非软删 test(候选自身分组:同 germplasm_id 的测试合并为重复),可显式覆盖;取候选+参照观测+描述符 → 判定 → **落 `analysis_json`**(逐描述符表+建议+参照集+alpha+运行时间);`conclusion` 当前 pending 时自动填建议(人工可改)。`distinctness_report(test_id)` 读已存分析;DusTestOutSchema 加 analysis_json。
- 端点:`POST /bre/dus_test/distinctness/{test_id}``GET /bre/dus_test/distinctness/{test_id}`
### 11.5 AMMI / Finlay-Wilkinson 稳定性(`scripts/breeding_stats/stability.py` + `statistics/service.py`
- `finlay_wilkinson(table)`:每基因型对**环境指数**(该环境全基因型均值 `np.nanmean(Y, axis=0)`)回归 y_gj=b·I_j+alstsq)→ b/截距/R²/se_b/dev_ms`flag_stable = |b1| ≤ 2·se_b`,且**完美拟合(dev_ms≤1e-12·max(1,ptp(y)²))时 se_b 无信息量 → b≈1(|b−1|≤1e-6)才判稳**(修复前浮点 b 永不精确=1 且 se_b=0 → 误判不稳)。
- `ammi(table, n_components=2)`:μ+g+e 两因素分解 → 残差 SVDnp.linalg.svd,首引)→ λ1/λ2、每基因型 IPC1/IPC2 得分、`ASV=√((IPC1·SS_ipc2/SS_ipc1)²+IPC2²)`Purchase 2000IPC1 按 SS 比例缩放)、Wricke ecovalence=Σ(y_ijy_i.y_.j+y..)²、`ipc_variance`(各 IPC 解释比例);rows 按 ASV 升序 + rank。
- `run_stability(trait_id, trait_code, gxe_env="site"|"year", year=None, methods=("ammi","finlay"))`:两向表 genotype=clone(缺则 combination,再退 tree)× env=site(trial_study_id)/year(evaluate_year),每格多株均值(仿 `trait_values` 取数);有效格子 <2×2 → 409;落 `bre_stability_result`detail_json + data_version/input_hash/engine_version+ job_type="STABILITY"`list_stability` / `stability_detail`
- 端点:`POST /statistics/stability/run``GET /statistics/stability``GET /statistics/stability/{sid}`
### 11.6 MLOps 自动重训 + 版本回滚(`statistics/service.py` + `sql/weld_advanced.sql`
- weld`bre_prediction.is_active boolean default false``run_ablup`/GXE/GBLUP 落库:同 trait 无 active 批次 → 本批 active=true,否则 false**版本链语义**)。
- `_gather_digest_inputs(trait_id, year)`:轻量抽取——仅组装进 `_input_digest` 的 phenos+pedigree(复用 run_ablup 的取数 SQL,不含 fixed/cov/门禁),供 drift 重算当前哈希(规避全量抽取风险)。
- `GET /statistics/model/drift?prediction_id=`:从该批次 job params_json 取 (trait_id,year,gxe,gxe_env) → `_gather_digest_inputs` 重算 → {prediction_id, changed, current_hash, stored_hash, data_version}。
- `POST /statistics/model/retrain?prediction_id=`**漂移才重训**——`run_ablup`(同 params) 建新批次并 `await model_activate(new_id)` 转移 active**修复前新批次默认 inactive**——旧批次仍 active,重训后新批次卡在非生效态,破坏版本链语义)→ {retrained, old_id, new_id, new_hash};无漂移 → {retrained:false, reason}。
- `POST /statistics/model/activate/{id}`trait 内标 active(回滚原语);`list_predictions`/PredictionOut 加 is_active。
### 11.7 BLUP stage 拆分(`statistics/service.py` + `sql/weld_advanced.sql`
- weld`bre_trait_observation.stage varchar(16)`(观测级发育阶段,缺省继承 trait.stage)。TraitObservationModel + schemacreate/update/out+ 前端观测表单 stage 下拉(juvenile/evaluation)。
- `run_ablup(stage=None)` + RunStatsIn.stagestage 给定 → 取数 `where(coalesce(obs.stage, trait.stage) == stage)`;过滤时 model_name 加 `_{stage}` 后缀 + PredictionModel.stage=生效 stage;未给定但数据 obs.stage 与 trait.stage 出现分歧 → note 警示("有 N 条观测标注了观测级 stage,但本次未按阶段拆分…",不阻断);GXE 分支同步应用;非法 stage → 409。
### 11.8 前端
- `statistics.ts`runGeneticCorr/listGeneticCorr/geneticCorrDetail + runStability/listStability/stabilityDetail + runGblup/getGblupDatasets + modelDrift/modelRetrain/modelActivate + 类型。
- `statistics/index.vue`:新「遗传相关 MT-BLUP」(性状多选→相关矩阵表格)、「稳定性 AMMI/FW」(性状+env+methods→FW b/R²/flag 表 + AMMI IPC/ASV/rank 表)、「基因组选择 GBLUP」(dataset+性状+method radio+maf→批次/EBV 表)三 tabABLUP 运行对话框加 stage 三态(全部/童期/成株);Smith-Hazel 对话框加 g 矩阵来源 radioCalo/MT-BLUP);预测批次表加「当前版本」标签 + 漂移检测/自动重训/设为当前版本按钮。
- `dus/index.vue`:DUS 测试行加「特异性判定」按钮→对话框(alpha + 参照默认同点 + 逐描述符结果表 + 建议)→「应用判定」写 conclusion。
- `vue-tsc --noEmit` 通过(EXIT=0)。
### 11.9 验证(`Temp/claude/e2e_advanced_*.py` 6 组全过)
- **stability**3 组合×3 站点 FW b=2.0/1.0/0.0、flag=F/T/FC1 稳定)、r²=1/C2 None(常量响应 R² 无定义)、AMMI 9 格 IPC1≥IPC2 rank 升序、year 维度、非法 methods 409、list/detail。
- **stage**juvenile/evaluation 各只含对应观测树 + model_name `_{stage}`、不传含全部 4 株 + note 警示、非法 stage 409。
- **mtblup**r_g=0.99y2=2·y1 强正相关)对称、σa12>0、h²∈(0,1)、n_common=4、Smith-Hazel g_method=mtblup `g_source` 落库;**顺带修 `_smith_hazel_index` 未定义变量 `tid` 真 bug**。
- **gblup**GBLUP 5 EBV 非基因型株=0 + ssGBLUP 非零 + solve_ssgblupV 块用 H、g 亲本 EBV 有限、G method1 diag_mean≈1+ 样本 4 直连+1 名称兜底+1 全多等位(回归 genotyped 对齐修复)+1 未映射 warning + list_genotyping_datasets n_samples=6。
- **dus**:自动参照同点 5 测试、D1 LSD=1.239 df=3 t_crit=5.8409 distinct、D2 PQ distinct、D3 非必测 not distinct、analysis_json+conclusion 自动建议、显式参照覆盖、无重复 pending+warning。
- **mlops**:首批 active → 改观测 drift changed → retrain 新批次 active 旧 inactive → 无新漂移幂等 {retrained:false} → activate 旧批次回滚(直接断言 `model_retrain` 修复)。
- 后端重启 + openapi 确认 6 组新端点 + 2 新表(bre_genetic_corr_result / bre_stability_resultcreate_all`weld_advanced.sql` psql `-w` 幂等。
### 11.10 本轮修的三处引擎级 bug(e2e 探针暴露)
1. **ssGBLUP V 块**genomic.py):REML 似然 V=ZH[z,z]Z'+R 必须用 **H 协方差**`Hinv[z,z]` 是把逆矩阵喂给协方差位置 → 似然失构、h² 失真。H 按 Aguilar 块公式构造。
2. **genotyped 与 G 行序错位**service.py):`genotyped` 必须 `sorted(dosage)` 对齐 `build_g_matrix` 内部 `sorted(genotypes)`;用全部映射树时,零有效调用树(全多等位)会静默错位 G 索引污染 EBV。
3. **`_smith_hazel_index` 未定义 `tid`**service.py):mtblup 分支取系谱树集的集合推导式引用未定义变量 → 首次走 g_method=mtblup 即 NameError。改 `{tid for tid, d in pheno_all.items() if any(c in d for c in cols)}`
4. **`model_retrain` 不激活新批次**(service.py):重训后补 `await model_activate(new_id)`,否则新批次默认 inactive 卡在旧批次下,版本链断裂。
5. **`flag_stable` 完美拟合误判**stability.py):残差≈0 → se_b=0 → `|b1|≤2·se_b` 恒假(浮点 b≠1 精确)。改 dev_ms 阈值判定:完美拟合 → `|b1|≤1e-6` 判稳。
### 11.11 收尾修复:统计二级菜单深链(前端,用户反馈"4 个二级菜单页面都一样")
统计分析下 4 个二级菜单(统计计算/育种值/选择指数与决策/图形分析)的 `component_path` 均指向 `module_bre/statistics/index`,而该页是单页多 tab`activeTab` 默认 `batches`)且不读路由 → 点谁都落在"模型批次"页。修复:`statistics/index.vue``useRoute()` + `ROUTE_TAB_MAP``activeTab` 初始值按路由取。**关键坑**:数据库 `sys_menu.route_path` 实为**相对路径**`statistics`/`prediction_value`/`selection_decision`/`statistics_chart`),经父级 `/breeding` 拼接后实际 URL 是 `/breeding/statistics/...`,与 seed SQL 写的 `/bre/...` 绝对路径**不一致**——故**必须按 `route.name` 匹配**StatisticsCalc→batches、PredictionValue→ebv、SelectionDecision→index、StatisticsChart→correlation),而非 `route.path`(首次按 path 匹配 `/bre/...` 全部落空,用户刷新仍默认页)。四个菜单路由 `name` 各异,RouterView 缓存键 `name+params` 不同 → 每次点击组件重挂载,深链可靠。图形分析无专属 tab,暂归"相关性"。`pnpm type-check` EXIT=0vitebase=/web,端口 5666HMR 生效。
## 十二、田间试验精度补强·砧木×接穗随机互作 G×R(2026-08-04
### 12.1 缺陷背景(用户核实两条精度缺口,拍板先做 G×R)
用户核实田间试验设计精度两条缺口:① **无 R 侧空间协方差**(行-列 AR1×AR1,当前 `np.eye(m)*Ve` 纯对角)——该项需先补 `tree.row_no/col_no` 数据与设计图,留待后续;② **无 scion×rootstockG×R)随机互作**——`rootstock` 当前仅作固定哑变量(v2.0 ⑤ 砧木建模铁律「BLUP 固定效应扣除」),无第三个随机效应槽。用户拍板**先做 G×R 随机互作**(探索到跑通真实数据档位成本可控)。
### 12.2 架构决策
- **结构同构、求解器零改动**:G×E 分支 `_solve_gxe`blup.py)的 Z₂ 已按 `(基因型,因子水平)` 分组配 `I·σ²` 交互,**因子无关**pair-grouping 机制),G×R 只是把分组键换成 `(基因型, 砧木水平)`MME/REML/输出键全部复用。
- **Z₂ 单槽位 → G×E/G×R 必须互斥**:`if gxe and gxr` 显式 409(文案「共用同一随机效应槽(Z₂)」),前端再加双向互斥 watcher 兜底。
- **克隆坍缩系谱共享**`gxe_pedigree`clone 树坍缩为 `c{clone}` 节点,父母本=组合/种质亲本)构建块从 `if gxe:` 内**上移**为 G×E/G×R 共享(纯构建、ABLUP 路径不执行)。
- **rootstock 移出固定效应**`gxr=True` 时强制 `fixed_effects` 剥离 `rootstock`,p_est 不再计入砧木水平,防与 Z₂ 共线。
### 12.3 求解器(`backend/scripts/breeding_stats/blup.py`
`_solve_gxe` 加两个可选参数(默认值保现有 G×E 行为逐字节不变):
- `factor_label="G×E"`——未收敛警告「{factor_label} 似然面可能极平/边界最优」;
- `factor_name="环境"`——方差归零警告「{factor_label} 方差分量收敛到 0(数据不支持基因型×{factor_name}互作)」。
- 公开 `solve()` 加参并透传 `_solve_gxe`**服务端走的是 `solve()`,首次探针即暴露漏传**)。
- `ENGINE_VERSION` "1.1.0"→"1.2.0"。
### 12.4 服务端(`statistics/schema.py` + `controller.py` + `service.py`
- `RunStatsIn` + `run_ablup``gxr: bool`controller 透传。
- 互斥门禁(job 创建前):`gxe and gxr` → 409。
- job_type=`"GXR" if gxr else ("GXE" if gxe else "ABLUP")`params_json 落 `gxr`
- `elif gxr:` 分支镜像 G×E site 分支:
- 遍历 `phenotypes.items()`int tid),`rid = f"t{tid}"`**字符串键**)查 `rootstock_map[rid]``rs{rootstock}`),缺砧木 → `skipped++` 跳过并 note 警示;无任何可分砧木记录 → 409。
- `rec_gxr[rid] = (grp, rs)`grp 优先 `c{clone_of[tid]}`(克隆坍缩)、退 `f{combo_of[tid]}``rec_map[rid]` 同理。
- 门禁三件套镜像:`n_cross_rootstock`=同基因型跨砧木数==0、max cell_counts<2、`residual_df = m - q - p_est`<1p_est 含 intercept + trial_study 水平-1(若固定)+ covariate**rootstock 不计入**)→「G×R 不可辨识」409。
- `rec_fixed`(仅 trial_study,经 `fixed_map`+ `rec_cov`cov_map);rootstock 从 `fixed_effects` 剥离。
- 求解:`blup.solve(gxe_pedigree, rec_phenos, gxe=rec_gxr, record_map=rec_map, fixed=..., covariate=..., factor_label="G×R", factor_name="砧木")`
- `method="GXRBLUP"`model_name `GXRBLUP_{trait}` + `_{stage}?` + `_{ts}`
- note`stage/sigma_a/sigma_gxr(=sigma_gxe)/sigma_e/gxr_ratio(=gxe_ratio)/n_cross_rootstock(=n_cross_env)/n_genotypes/warning/skipped/stage_note`
- EBV 写入共用段 accuracy 个体集按 gxr 选 `gxr_tree_ids`
- `_DATA_VERSION` "v2.9"→"v2.10"。
### 12.5 前端(`statistics.ts` + `statistics/index.vue`
- `RunStatsPayload.gxr`
- G×E tab `gxeEnabled` 后加 `<el-checkbox v-model="gxrEnabled">启用砧木×接穗互作(G×R)随机效应</el-checkbox>`;双向互斥 watcher;运行按钮文案「运行 MET / GxE / GxR」、辅助文案三分支。
- 批次表互作方差列 v-if 扩为 `GXEBLUP || GXRBLUP``fmtGxeNote``n.sigma_gxr != null` 分支(σ²gxr/σ²gxe、gxr_ratio/gxe_ratio、跨砧木/跨环境基因型)。
- `runGxe` payload 加 `gxr: gxrEnabled.value``vue-tsc` 通过(EXIT=0)。
### 12.6 验证(`Temp/claude/e2e_gxr_20260804.py`4 组全过)
1. **正例**:2 基因型(clone)× 2 砧木 × 2 株 = 8 株,强交叉互作观测(clone1×R1 高/R2 低、clone2 相反)→ GXRBLUP、job_type=GXR、σ²gxr=74.8>0、n_cross_rootstock=2、n_genotypes=2、8 EBV 行。
2. **门禁负例**:同基因型仅跨 1 砧木 → CustomException「G×R 不可辨识」。
3. **互斥负例**`gxe=True, gxr=True` → CustomException「Z₂」。
4. **rootstock 剥离**`gxr=True` 同时 `fixed_effects=["rootstock"]` → 剥离后不共线、正常出 σ²gxr。
- 后端重启(含孤儿 reloader worker 清理)后 openapi 确认 `gxr: True` 入参;`vue-tsc` EXIT=0。
## 十三、基因组选择(GS)实证严谨性·GBLUP/ssGBLUP 专用 k-fold 交叉验证(2026-08-04
### 13.1 缺陷背景(用户核实两条 GS 实证缺口,拍板先做 k-fold)
用户核实 GS 实证严谨性两条缺口:
**GS 缺自身交叉验证**——`run_cv`/`kfold_cv`(blup.py)是 A 矩阵系谱预测(ABLUP/GXE),GBLUP 落库的 `accuracy=√mean(reliability)` 是**理论准确度**(PEV 推导),**对模型误设不敏感**:G 算错/标记编码错/遗传力先验偏时 PEV 可靠性依然漂亮,真实预测能力却崩了,只有掩蔽留出「GEBV vs 表型 pearson」能测出实证预测能力。
**SSR panel 难构 VanRaden G**——`_dosage_from_gt` 只吃 `0/1` 两段整数且 `max≤1`SSR 片段编码(`168/174`)、多等位(`0/1/2`)、phasing`0|1`)全部被丢弃 → SSR calls 静默变缺失 → `m_after_maf→0``build_g_matrix` 直接 ValueError「MAF≥0.05 的标记为 0」→ 409。这是"有引擎但数据接不进"的现实坑。
用户拍板**先做 GS k-fold(①)**SSR dummy 编码(②)留待后续。
### 13.2 架构决策
- **核心洞察——掩蔽留出已原生支持**:`_profile_solve`(genomic.py)已实现「仅观测子集进模型、**全部个体**出 EBV」——非观测个体 Z 行全 0、经 G⁻¹/H⁻¹ 的 cross-relationship 预测(e2e_advanced_gblup 已验证非基因型株 tree4 出非零 EBV)。所以 GS CV 掩蔽留出 = 传训练子集 phenos → 全个体 GEBV → 取留出个体与观测表型相关。**G/H/Hinv 只建一次,逐折只换 z_train 子阵**(折划分不改变关系矩阵)。
- **折划分差异(与 ABLUP 的本质区别)**:ABLUP 的 `kfold_cv`**sire 家系分层留出**(同一家系不跨训练/测试,防同家系信息泄漏)。GS 的候选是 genotyped∩phenos 的**同世代样本、无系谱家系树**,用**固定种子随机分层**(round-robin 到 k 折)即标准做法——文档明示该差异,将来要防近亲泄漏可加「按 G 关系分层」。
- **方法互通**`method="gblup"` → 关系矩阵 Gindividuals=genotyped);`method="ssgblup"``_build_h` 合并关系阵 Hindividuals=order,含非基因型亲属)。两者共用一个输出 dict 形状(与 blup.kfold_cv 逐键对齐)。
### 13.3 求解器(`backend/scripts/breeding_stats/genomic.py`
1. **抽取 `_build_h(pedigree, genotyped, G, *, ridge, extra_base)`**solve_ssgblup 的 base/non_base→`_order_pedigree`→A/Ainv→Hinv→H 构建提成 helper,返回 `(order, idx, H, Hinv)`。solve_ssgblup 改调(行为不变)。
- **缺失基因型个体按 base 补入系谱**(原 `if missing_gen: raise ValueError``for g in missing_gen: base.append(g)`)——无表型基因型树不再触发 ValueErrorCV/ssGBLUP 更稳(与 phenos 兜底一致)。
2. **新增 `kfold_cv_genomic(phenos, G, genotyped, *, k=5, seed=20260804, method="gblup", pedigree=None, ridge)`**
- `method="gblup"`individuals = sorted(genotyped)G 行序);`relmat_inv = np.linalg.inv(G)`(奇异回退 pinv);zmat_full = G。
- `method="ssgblup"``_build_h(pedigree, genotyped, G, extra_base=list(phenos))` → individuals = orderrelmat_inv = Hinvzmat_full = H。
- `cand = sorted(genotyped ∩ phenos)``n_total = len(cand)``<2` → 空 folds + warning(对齐 blup.kfold_cv)。
- 折划分:`rng = random.Random(seed)`shuffle cand → `bin_of = {c: i % k}`
- 逐折:`test_set = {c: b == fold}``train_phenos = phenos test_set``z_train = 观测个体索引``_profile_solve(zmat_full[ix_(z,z)], X, y, relmat_inv, n, z_train)` → 全 EBV → 留出个体 GEBV vs 表型 `blup._pearson` + RMSE;单折失败(训练<2/测试空/求解异常/未收敛/测试有效<2)→ error 记 warning **不中断**
- 输出 dict 与 blup.kfold_cv **逐键对齐**`k/n_total/n_individuals/folds/mean_pearson/mean_rmse/pooled_pearson/pooled_rmse/cv_accuracy/h2/warning`)。
3. `ENGINE_VERSION` "1.0.0"→"1.1.0"。
### 13.4 服务端(`statistics/schema.py` + `controller.py` + `service.py`
- **`_gather_gblup_inputs(dataset_id, maf_min)` 提取**run_gblup 的 dataset→samples→call_rows→markers→sample→tree 映射→dosage→`build_g_matrix`→genotyped 装配(约 60 行)提成 helper,返回 `(dosage, marker_order, genotyped, G, g_meta, unmapped)`。run_gblup 改调(行为逐字节不变),GS CV 复用。**e2e_advanced_gblup.py 复跑兜底回归**。
- **`run_cv` 签名扩展**:加 `dataset_id: int | None = None, method: str | None = None, maf_min: float = 0.05`params_json 落三键。
- **GS 分支**(公共表型/系谱装配后、`elif gxe:` 前,与 G×E/ABLUP **互斥**——双开时 GS 优先):
- `_gather_gblup_inputs(dataset_id, maf_min)``gs_phenos = {f"t{tid}": v}`(键对齐 run_gblup "t{tid}" 约定)→ `kfold_cv_genomic(gs_phenos, G, genotyped, k=k, method=method, pedigree=pedigree)`
- method 名 `"KFCV/GBLUP"` / `"KFCV/ssGBLUP"`method varchar(16) 放得下)。
- input_hash = sha256(`_input_digest(pedigree, gs_phenos)` + `\n` + geno_str)geno_str 镜像 run_gblup`f"{s}|{mk}|{dosage[s].get(mk, '.')}"` 全排序)。
- engine_version 按分支:GS 用 `genomic.ENGINE_VERSION`ABLUP/GXE 用 `blup.ENGINE_VERSION``cv_engine_version`/`method_name` 先默认后覆盖)。
- **schema `CvRunIn`** + controller run_cv 透传 `dataset_id/method/maf_min`
- `_DATA_VERSION` "v2.10"→"v2.11"。
### 13.5 前端(`statistics.ts` + `statistics/index.vue`
- `CvRunPayload``dataset_id?/method?/maf_min?`
- CV tab 加 **mode radioABLUP / GS**:GS 模式显示基因型数据集下拉(复用已加载 `gbDatasets`+ method radioGBLUP/ssGBLUP+ MAF≥ 输入;**隐藏 G×E 控件**;辅助文案分支「掩蔽留出 GEBV vs 表型 pearson(实证预测能力,固定种子随机分层)」。
- `submitCv` 按 mode 组装 payloadGS 传 dataset_id/method/maf_min);`vue-tsc` EXIT=0。
### 13.6 验证(`Temp/claude/e2e_gblup_cv_20260804.py`3 组全过 + 回归)
构造:5 家系 × 3 全同胞 = 15 株(每系独立组合+亲本种质),10 标记(MK0/MK1 为 QTL 效应 2.0,家系 QTL 剂量 `[(2,2),(2,1),(1,2),(1,0),(0,0)]`→遗传值 8/6/6/2/0,非 QTL 标记 `(f*3+j)%3` 家系特征化),表型 = 12 + 2·dose(MK0) + 2·dose(MK1) + 低噪(±0.3),家系内基因型一致 → 留出预测靠 G/H 同家系交叉关系,强信号。
1. **GBLUP 正例**`run_cv(trait, dataset_id, method="gblup", k=5)` → job SUCCESS`CvResultModel.method=="KFCV/GBLUP"``cv_accuracy=0.794 > 0.3``==mean_pearson`、n_total/n_individuals=15/15、input_hash 64hex、engine_version=1.1.0、5 折 n_train/n_test≥1、`CvFoldModel` 5 行。
2. **ssGBLUP 正例**`method="ssgblup"``"KFCV/ssGBLUP"`、cv_accuracy=0.794 > 0.3H 合并系谱+标记,家系内同基因型仍强预测)。
3. **门禁负例**:dataset 仅 1 个无映射样本(sample_name=NO_MATCH)→ `CustomException`「基因型样本均无法映射到单株」,FAILED job 落库。
4. **回归**`e2e_advanced_gblup.py` 复跑全过(`_gather_gblup_inputs` 提取后 run_gblup 行为不变:h²/5 条 EBV/非基因型株 EBV=0、note 未映射警示)。
- 后端重启(含孤儿 reloader worker 清理)后 openapi 确认 `CvRunIn` 出现 `dataset_id/method/maf_min``vue-tsc` EXIT=0。
## 十四、现代桃育种领域覆盖·S-等位基因交配兼容性 + 抗病/需冷量性状字典(2026-08-04
### 14.1 背景(用户核实四方向覆盖,拍板按建议次序做)
| 方向 | 核实结论 | 处置 |
|---|---|---|
| ① S-等位基因(自交不亲和)交配兼容性 | **完全未建模**`bre_pollen`/`bre_pollination` 无 S-allele 字段、`bre_cross_combination` 无兼容性校验、"配了不结"硬需求空白 | 落地(本批) |
| ② 需冷量/需热量 | 环境侧已建(`bre_germplasm.chilling_requirement` 属性 + `bre_environment_condition.chilling_hours/GDD`),**选种性状侧 bre_trait 缺失**(66 行字典无一条) | 落地(本批) |
| ③ 抗病性状(细菌性穿孔病/褐腐病/白粉病) | `bre_germplasm.disease_resistance` 仅自由文本,**bre_trait 一条都没有** | 落地(本批) |
| ④ MAS/QTL/GWAS 闭环 | 900214 仍 `_coming_soon`,发现层(GWAS/QTL 定位→MAS)完全缺失 | 留待单独立项 |
关键事实:**统计引擎 `_trait_meta_map` 仅消费 `data_type='numeric'` 的性状**(EBV/选择指数/决策候选),故抗病/需冷量必须建 numeric 而非 categorical 分级;桃属配子体自交不亲和(S-RNase),`Sf` 等位为自交亲和型(SI 功能缺失),多数商业化品种携带。
### 14.2 ②③ 性状字典种子(`backend/sql/bre_disease_chilling_traits.sql`
幂等 `ON CONFLICT (trait_code) DO UPDATE`,新增 **5 条** numeric trait,全部 `into_ebv='1'`(选种目标)+ `direction='asc'`(低值优):
| trait_code | 名称 | category | unit | 说明 |
|---|---|---|---|---|
| `disease_shot_hole` | 细菌性穿孔病 | 抗病性 | 级 | 0-5 级病情指数(0=免疫…5=高感),`valid_min=0/valid_max=5`h²=0.3 |
| `disease_brown_rot` | 褐腐病 | 抗病性 | 级 | 同上 |
| `disease_powdery_mildew` | 白粉病 | 抗病性 | 级 | 同上 |
| `chilling_requirement` | 需冷量 | 生态适应性 | h | 打破休眠 0~7.2℃ 低温累计小时(0-3000),h²=0.5 |
| `heat_requirement` | 需热量 | 生态适应性 | GDD | 发芽前 >7.2℃ 有效积温(0-10000),h²=0.4 |
`stage='evaluation'` + `method` 测定说明;前端 trait 页 category 自由文本自动显示、0 改动。
### 14.3 ① S-等位基因建模(`germplasm` + `cross_combination`
- **`bre_germplasm.s_alleles`**`String(32)`,如 `S1/S3``Sf`=自交亲和型):model + schemaCreate/Update/Out+ `ALTER TABLE` + `COMMENT`
- **兼容校验**`cross_combination/service.py`):
- `_parse_s_alleles(raw)`:分隔符 `/ , ;` → 归一化小写等位集合;空白返回 None。
- `_s_compat_check(female_s, male_s)`**任一亲本含 `sf`→full 放行**(Sf 不排斥);否则共享 2 个→`none`、1 个→`half`、0 个→`full`;缺 S 数据→`unknown` 跳过。
- `_check_s_compat(female_id, male_id)`:读亲本 s_alleles → `none``CustomException` 409「S-等位基因完全不相容(共享 …),该组合无法坐果」(**"配了不结"硬门禁**);`half` 返回警示文案。
- `create`/`update` 在亲本存在性断言后调用;`CrossCombinationOutSchema.s_compat`(可选派生字段)落半兼容警示;**同亲本自交共享 2 等位自然被 409 拦截**(除非含 Sf)。
### 14.4 前端
- germplasm 表单加 **S-等位基因** 输入(type inputplaceholder「如 S1/S3Sf=自交亲和型」)+ 导出列;`germplasm.ts` `GermplasmForm/GermplasmTable``s_alleles?`
- cross_combination 组合提交**包装 createApi/updateApi**:响应含 `s_compat``msg.warning` 展示(统一消息入口);409 由统一错误处理自动提示。
### 14.5 验证(`Temp/claude/e2e_s_allele_20260804.py`6 组全过)
1. **纯函数 8 例**S1/S3×S1/S3→none、×S2/S4→full、×S1/S2→half、S1/Sf×S1/S1→full、大小写/混合分隔→none、缺数据→unknown、`_parse_s_alleles` 归一化断言。
2. **service 层 create**:共享 S1/S3→409「不相容」;共享 S1→`s_compat` 半兼容文案;0 共享→无警示;Sf 放行;缺 S 跳过。
3. **②③ 落库核验**bre_trait 5 条 numeric+asc+into_ebv=1 已落库。
4. **openapi 核验**`BreedingGermplasm{Create/Update/Out}.s_alleles` + `CrossCombinationOut.s_compat`
5. `vue-tsc` EXIT=0;后端重启后核验。
## 十五、GWAS/QTL/MAS 标记辅助选择闭环(2026-08-04
> v2.13 §十四 标记「④ GWAS/QTL/MAS 闭环留待后续单独立项」——本轮单独立项落地,补齐**发现层**:GWAS/QTL 定位 → 显著标记 → MAS 面板,900214 占位页翻真实页。桃在成熟期/果重等位点已有已知 QTL,MAS 让童期幼苗在无表型/无 EBV 时也能被标记辅助选择。
### 15.1 求解器 `backend/scripts/breeding_stats/gwas.py``ENGINE_VERSION=1.0.0`,纯 numpy 零 scipy
- **模型**:逐标记单标记回归 `y ~ μ + PC1..PCn_pc + marker`;加性效应=标记回归系数。
- **群体结构**:标记剂量矩阵(缺失按列均值填)中心化 → `np.linalg.svd` 前 n_pc 个主成分得分(`pc_scores = U[:,:n_pc]·s[:n_pc]`)作协变量。
- **p 值**`t = coef/SE``p = fdist.f_pvalue(t², 1, df)`df = n n_pc 2)——**复用 DUS LSD 已验证的正则不完全 beta,零 scipy 新依赖**。
- **多重检验**`threshold_bonf = sig_level/m_after_maf`BH-FDR qnumpy argsort 自底向上保单调)。
- **QTL 定位**sig_bonf 标记按 chromosome 排序,相邻间距 < qtl_window 合并簇,簇内最小 p 为峰标记(单显著标记也落 QTL 兜底)。
- **共线兜底(本轮关键修复)**:非 QTL 标记与 PC 共线时 XtX 奇异,`np.linalg.inv` 返回病态(负对角元 → `sqrt` 域错)。改**微小岭回归** `reg=1e-8·max(diag(XtX))` 兜底——共线方向 SE 大而有限 → t 小 → p≈1(效应被 PC 吸收,正确非显著);与群轴正交的 QTL 标记不受影响(1e-8 相对岭可忽略)。
- MLM 预留:method 参数(gwas/ssgwas),本轮仅实现 gwas。
### 15.2 数据装配与 5 张新表
- **`_gather_gwas_inputs(dataset_id, maf_min)`**service.py 新 helper,仿 `_gather_gblup_inputs` 但 marker 查询补 chromosome/position)→ `(dosage, marker_order, markers_meta, genotyped, unmapped)`。**独立 helperrun_gblup/run_cv 零回归**。
- **`bre_gwas_result`**(批次:n_individuals/n_markers/m_after_maf/maf_min/n_pc/sig_level/threshold_bonf/n_sig_bonf/n_sig_fdr/n_qtl/data_version/input_hash/engine_version/remark
- **`bre_gwas_snp`**(逐标记:marker_id/marker_name/chromosome/position/maf/effect/se/t_value/p_value/neg_log10p/q_value/sig_bonf/sig_fdrFK CASCADE
- **`bre_qtl`**trait_id/chromosome/start_bp/end_bp/peak_marker_id/peak_marker_name/peak_p/n_markers/effect/source=known|gwas/gwas_result_id
- **`bre_mas_panel`** + **`bre_mas_panel_marker`**favorable_dose/direction=high|low/effectUNIQUE(panel,marker)
- ORM 于 `statistics/model.py`ModelMixin 全套),`create_all` 建表 + `backend/sql/weld_gwas.sql` 幂等 `CREATE TABLE IF NOT EXISTS` 双保险。
### 15.3 服务端端点与 MAS 决策 hook
- `POST /bre/statistics/gwas/run`GwasRunIn: dataset_id/trait_id/trait_code/year/method/maf_min/n_pc/sig_level/qtl_window)→ job_type=GWAS`_gather_gwas_inputs` + `asyncio.to_thread(gwas.run_gwas)` + input_hash(系谱+表型+基因型确定性序列化)+ engine_version;成功落 bre_gwas_result + bre_gwas_snp 批量 + bre_qtlsource=gwas)。
- `GET /bre/statistics/gwas/list` + `GET /bre/statistics/gwas/{id}`result + snps + qtls)。
- `bre_qtl` CRUD(已知 QTL 录入 source=known+ `bre_mas_panel` CRUD + `POST /bre/statistics/mas-panel/{id}/markers`(全量替换)。
- **decision_preview MAS hook**:条件循环 `("pheno","ebv")``("pheno","ebv","marker")``_mas_hit_map` 按候选树批量查 call → `_dosage_from_gt` → 有利剂量命中计数(direction=high: dose≥favorable_dose / low: ≤),`conds["marker"]={panel_id:{min_hits}}` —— **童期幼苗无表型/无 EBV 也能被标记辅助选中**
- `_DATA_VERSION` v2.12;端点权限复用 `module_bre:statistics:*`900071 已授 ADMIN900214 翻转无需新增按钮)。
### 15.4 前端(`gwas.ts` + `gwas/index.vue`900214 翻转)
- **GWAS 结果 tab**:批次表 + **Manhattan 图**(裸 `echarts.init`:x=染色体累加位置、逐染色体分组着色、显著点红色、Bonf 阈值 markLine、dataZoom+ **QQ 图**(期望 log10((i+.5)/m) vs 观测)+ SNP 表 + QTL 区间表。
- **QTL 定位 tab**:已知 QTL 录入 CRUDtrait/chromosome/区间/peak/effect/remark)。
- **MAS 面板 tab**:面板 CRUD + 标记选择对话框(marker/favorable_dose/direction/effect)。
- 运行对话框参数:dataset_id/trait_id/year/maf_min=0.05/n_pc=3/sig_level=0.05/qtl_window=1000000。
- `sys_menu 900214``component_path='module_bre/gwas/index'``bre_menu.sql` §6d);`vue-tsc` EXIT=0。
### 15.5 验证(`Temp/claude/e2e_gwas_20260804.py`7 段全过 + 回归)
1. **run_gwas**job GWAS/SUCCESSbre_gwas_result n=32/m=200→200/bonf=2/fdr=2/qtl=2/input_hash 64 位/engine_version=1.0.0/threshold_bonf=sig/m_after_maf。
2. **bre_gwas_snp**:全字段(chromosome/position/neg_log10p/q_value);MK0/MK1 均 Bonf 显著且为所在染色体(chr1/chr3)最小 pMK0 p=2.3e-05、MK1 p=5.4e-05)。
3. **QTL 定位**2 区间峰标记=MK0/MK1source=gwas 落库且挂批次。
4. **已知 QTL CRUD**create/update/listsource=known)全过。
5. **MAS**:面板 2 标记(favorable_dose=2/high)→ decision_preview marker 条件(min_hits=1)命中 16 株 + **无表型童期幼苗 1 株**,低剂量株不命中。
6. **门禁**dataset 无映射样本 → CustomException「无法映射」。
7. **清理**finally FK 逆序自动清理。
- **回归**`e2e_advanced_gblup.py` + `e2e_gblup_cv_20260804.py` 复跑**零回归**GBLUP/ssGBLUP CV accuracy 0.794);openapi 核验 10 条 gwas/qtl/mas-panel 路径。
### 15.6 数据设计要点(避免 PC 吞噬 QTL 的实证教训)
- **标记数太少(如 20)且非 QTL 标记全为群轴共线**时,标记矩阵秩塌缩,SVD 前 n_pc 个 PC 本身跨越因果标记 → 效应被 PC 吸收、SE 膨胀、无显著标记(实测 MK0 p=0.77)。
- **正确设计**:2 群体结构(各 16 株)+ 200 标记,非 QTL 标记携带「群轴 + 组内独立伪随机变异」(PC1=群轴、PC2/3 与 QTL 标记低相关),QTL 标记剂量在群体内多重集一致(与群轴正交)→ PC 校正后效应保留、双 QTL Bonf 显著。
- **功效**n=32、m=200、QTL 效应 2.0 时 p~1e-5Bonf 阈值 2.5e-4 余量 10×);n=24 则功效不足(p~2.5e-4 擦线)。
## 十六、九缺口补齐:经典侧计算端点 + 分子侧严谨性 + 求解器核心(2026-08-04
> 用户自 GWAS/QTL/MAS 闭环后重扫 12 项缺口,A1(S-等位)与 A4(G×R)已同日落地剔除,余 9 项拍板「全部补齐」,分三批独立 e2e + 回归。三批均 e2e 通过、回归零回归,后端重启 + openapi 核验 + HTTP smoke + 前端 vue-tsc EXIT=0。
### 16.1 批1 经典侧计算端点(纯计算不建表,`statistics/controller.py` + `service.py` + 前端 statistics/index.vue
| 缺口 | 落地 |
|---|---|
| A5 数据质量 | `POST /statistics/data-quality`——`data_quality_report(trait_id, site_id?, tree_ids?)`tree 级观测装配(同 run_ablup+ 缺失率 + CV + **IQR****MAD 稳健 z-score** 双法异常标记,输出 `{trait, n_trees, missing_rate, cv, outliers, summary}`;前端「数据质量」对话框 |
| A3 遗传增益 | `POST /statistics/genetic-gain`——**ΔG=k·r_g·σ_A**k 由 top_p 经 **Acklam 有理近似 Φ⁻¹**(纯 numpy 零 scipy)、r_g=批次 PA(√mean reliability)、σ_A=√h²·σ_P,逐轮 `{round, current_mean, ΔG_units, ΔG_pct_mean, next_mean, cumulative}` |
| A6 主动选配 | `POST /statistics/mating-recommend`——S-等位硬过滤(复用 `cross_combination._s_compat_check`none 剔除/half flag+ 亲缘 A 惩罚 `score=w_ebv·mid_parent_EBVw_kin·max(0,rthreshold)``{pairs:[{female, male, ebv_mean, r, s_compat, score, flags}]}`;**计算端点不落库**(用户拍板) |
### 16.2 批2 分子侧严谨性(`gwas.py` / `genomic.py` / VCF 装配 / MAS 语义)
| 缺口 | 落地 |
|---|---|
| B1 EMMAX | `gwas._emmax`:零模型 y=Xβ+u+e(u~N(0,σ²g·K)),方差分量复用 `genomic._profile_solve`**eigh 对角化** K=QΛQ' → V⁻¹=Q(σ²Λ+σ²eI)⁻¹Q';逐标记 GLS t²→`fdist.f_pvalue`;run_gwas 后处理抽共享函数,GLM 逐字节不变;`method="emmax"`gwas 1.1.0 |
| B2 SSR 多等位 | VCF 按 ALT 数定 marker_type`_allelic_from_gt` 每等位 0/1/23 处装配按 marker_type 分支 SSR 展开每等位一列;`build_g_matrix` 多等位 VanRaden 推广(genomic 1.2.0 |
| B3 QTL×E | `POST /statistics/gwas-qtl-x-e`:分环境 run_gwas 合并 QTL → stable(≥2 环境同号)/ env-specific / 异号 G×QTL 警示,计算端点不建表 |
| B4 MAS 语义 | `weld_mas_semantics.sql` 幂等 ADD COLUMNmode/favorable_allele/haplotype_group`_mas_hit_map` additive/dominance/recessive/allele/haplotype 五语义 |
### 16.3 批3 求解器核心(`blup.py`ENGINE_VERSION 1.3.0
- **A2 AR1×AR1 空间协方差** `solve_spatial`e~N(0,σ²e·R)、R=AR1(ρ)⊗AR1(ρ)、R⁻¹ 纯 numpy eigh、REML 对 (h²,ρ) 坐标上升黄金搜索;`run_ablup(spatial=True)` → method=AR1×AR1/model_name=SPATIAL_*,ρ/σ²a/σ²e/h² 落 note;与 G×E/G×R 互斥、缺 row/col 坐标 409`spatial=False` 逐字节不变。
- **A7 稀疏 A⁻¹+共轭梯度**:`_build_ainv_sparse`COO+ `_cg_solve`max_iter=800/tol=1e-9);`use_sparse = n_with_parents>0 and n>N_SPARSE(1000)` 阈值分派 → `"solver":"sparse-cg"` + `cg_iter`**Hutchinson k=100**(固定种子 20260804)估 PEV 对角 → `"reliability_approx":True`;收敛失败回退稠密;稠密路径(n≤1000)逐字节不变。
### 16.4 版本与验证
- `_DATA_VERSION` v2.13ENGINE_VERSIONblup 1.3.0 / genomic 1.2.0 / gwas 1.1.0。
- **批1** `Temp/claude/e2e_data_mating_gain_20260804.py`data-quality 命中离群株 / ΔG 自洽 / mating-recommend 剔除不相容对 + 亲缘惩罚生效 / 无观测 409 门禁。
- **批2** `Temp/claude/e2e_molrigor_20260804.py` 五段:EMMAX 复现双 QTL + SSR 混合 GBLUP 全标记进入 + QTL×E stable/env-specific + dominance/haplotype 语义命中 + 门禁。
- **批3** `Temp/claude/e2e_spatial_sparse_20260804.py` 三段:AR1×AR1 ρ=0.9796/h²=0.0013/method 标签 + 稀疏路径 EBV 3.49e-12 / h² 0.00 / CG 7 折 / Hutchinson mean-rel Δ0.054n=20 最坏,文档标注近似)+ 默认稠密路径引擎级 0 差(落库 4.92e-05 为 numeric(12,4)/numeric(6,4) Postgres 量化,非回归)。
- **回归**e2e_gwas7 段)/e2e_advanced_gblup/e2e_gblup_cv/e2e_gxr/e2e_refine/e2e_corr_spatial 全绿;openapi 核验 4 新端点 + RunStatsIn.spatial/gxe/gxr + GwasRunIn/GwasQtlXEIn.method=emmax + MasPanelMarkerIn 三字段;HTTP smokedata-quality trait 28、genetic-gain top_p=0.2 得 k=1.3998、409 门禁);vue-tsc EXIT=0。
## 十七、十二项真缺口补齐:引擎三件 + 模块四件 + 底座五件(2026-08-05
> 用户「全部补齐」后做全量现状盘点(2 个 Explore 代理 + 关键文件精读),发现总表大量「待建」标记过时——35 个 module_bre 后端模块 CRUD 全部齐全、数据字典四类已灌、描述统计/ANOVA 引擎已落地。真实缺口收敛为 **12 件**,用户拍板范围=只补这 12 件;移动端(V1.2)/品种登记 PVP(V3.0)/AI 三件套(V4.0)留波次不建。分三批独立 e2e + 回归,每批验收。三批均 e2e 通过、全量回归零回归,后端重启 + openapi 核验(631 路径)+ vue-tsc EXIT=0。完整台账见规格 §8.248.26。
### 17.1 批1 引擎三件(solver 扩展,独立新路径)
- **ssGWAS**`scripts/breeding_stats/gwas.py`ENGINE_VERSION **1.2.0**):run_gwas `method="ssgwas"` 分支 → `_ssgwas`——`genomic.build_g_matrix`blend 岭保正定)构 G → `genomic.solve_gblup` 全样本 GEBV û;**Wang et al. 单步 GWAS MEM 对角近似**`ê_j=(M_j'Z'G⁻¹û)/(2Σp_j(1p_j))``Var(ê_j)=σ²u/(2Σp_j(1p_j))`Wald `t=ê/SE`、df=n2 → `fdist.f_pvalue`;共享 `_finalize`/`_bh_qvalues`/`_cluster`(GLM/EMMAX 逐字节不变);门禁无基因型样本报错、G⁻¹ 岭兜底;服务端 method 透传 + 前端 gwas 运行对话框下拉加 ssgwas。
- **全 MT-BLUP 多变量 REML**`scripts/breeding_stats/mtblup.py`ENGINE_VERSION **1.1.0**):`solve_multi`——m 性状 y 堆叠、X/Z 块对角、Var(u)=G0⊗A、Var(e)=diag(ve_i·I)**EM-REML 迭代**(单性状 REML 初始、G0 非对角 0 → 迭代更新 G0/ve、特征值截断 + Higham 投影保正定、max_iter 兜底不收敛→`converged=False`+warning);输出 G0 全元素 + r_g 矩阵 + n_iter/converged/warning`run_genetic_corr``full_mtblup=True` 一次 m 性状给完整 G0(逐对 bivariate 路径保活)。
- **AR1×AR1 双参 ρ**`scripts/breeding_stats/blup.py`ENGINE_VERSION **1.4.0**):`solve_spatial(aniso=False)`——R_ij=ρ_row^|Δrow|·ρ_col^|Δcol|、内层 `_f_rho` 拆 ρ_row/ρ_col 交替坐标上升;`run_ablup(spatial=True, spatial_aniso=True)` → method=AR1×AR1(aniso)、note 落 rho_row/rho_col**aniso=False 输出与 v1 逐字节一致**(回归断言);门禁/互斥/缺坐标逻辑不变。
### 17.2 批2 模块四件(标准 CRUD 五件套 + 前端 + 菜单翻转)
- **field_operation 农事操作 900051**`bre_field_operation`tree_id/plot_id/op_type/op_date/op_detail/operator_id);op_type 字典(施肥/喷药/修剪/灌溉/疏果/套袋/采收)bre_dict 灌入。
- **observation 通用观测 900050**`bre_observation` EAV 通用录入(可挂 plot 级、不强制 trait);obs_type numeric/text/date。
- **breeding_report 育种报告 900075**`bre_report` CRUD + `POST /report/generate`(按 report_type 聚合 bre_prediction/bre_stability_result/bre_cv_result 成结构化报告 + doc_path);前端列表 + 生成对话框。
- **analysis_dataset 分析数据集 900070**:新表 `bre_analysis_dataset`trait_codes/sample_ids/config jsonb + statuscreate_all + 幂等 weld 兜底);CRUD +「查看性状值」跳 statistics trait-values 复用既有视图。
- **菜单翻转 + 文案清理**:幂等 UPDATE component_path→`module_bre/<name>/index`、E 段按钮 900xxx900014/900015/900021/900061/900063/900065 菜单 description 残留「待建」→ UPDATE 去除。
### 17.3 批3 底座五件
- **审计切面**`bre_audit_log`16 列已建零实现)→ `module_bre/audit/``base_crud.py` 三写方法事务内 flush 后追加 **CREATE 记录级 / UPDATE 字段级 diff(每变更字段一行)/ DELETE 记录级**`settings.AUDIT_BRE_ENABLED` + 模型 `__bre_audit__` opt-in;批量导入会话标志抑制逐行、仅汇总 IMPORT 一条;`GET /bre/audit/list|detail`
- **统一编号服务**`app/utils/number_gen.py` `NumberGenService`(前缀/日期/序列/回绕规则)+ **`pg_advisory_xact_lock` 原子取号** + `bre_sequence` 表;迁移 4 处(cross_combination YY+3位 / tree 组合-序号 / selection_result clone_code 扩位 / seedling batch_no YP-…),行为格式保持。
- **超期预警定时任务**:每日 job 按 `selection_rule` 扫描——树 N 年未决策(selection_result 无记录且定植超 N 年)/ pollen 批次过期(采集日+有效期)/ seed_lot 超期 → 写 `bre_alert`alert_type/entity_type/entity_id/message/status/created_id+ `GET /bre/alert/list` + 前端「预警中心」页。
- **备份容灾**`backend/scripts/pg_backup.sh`pg_dump 自定义格式到 `Temp/backup/` 按日期 + N 天轮转)+ `pg_restore.sh`;系统 job 每日 02:00ap_scheduler 3 系统 joboperation 清理 Sun 03:00 / alert 扫描 08:37 / 备份 02:17)。
- **BrAPI + MIAPPE**`module_bre/brapi/controller.py`app 根注册 prefix `/brapi/v2`,只读不建表):germplasm/observationvariables/studies/observations/miappe 五端点,BrAPI 2.x `metadata{pagination,status,datafiles}+result{data}` 包裹、0 基分页;bre_germplasm → germplasmDbId/germplasmName/PUI/accessionNumber/commonCropName=Peach/genus=Prunus/species=persica/subtaxabre_trait → observationVariableDbId/trait/method/scalescale.dataType 映射 + validValues);observations 合并 bre_trait_observation + bre_observationtree→germplasm join)。
### 17.4 版本与验证
- `_DATA_VERSION` v2.14ENGINE_VERSIONgwas 1.2.0ssGWAS/ mtblup 1.1.0solve_multi/ blup 1.4.0aniso/ genomic 1.2.0。
- **批1** `Temp/claude/e2e_gaps_engines_20260804.py` 3 组 PASSssgwas 复现已知 QTL(与 EMMAX 同数据集显著标记一致)+ solve_multi 3 性状 G0 半正定、r_g 与逐对 bivariate 同号量级 + aniso 双参 ρ 合理、aniso=False 与 v1 逐字节一致。
- **批2** `Temp/claude/e2e_gaps_modules_20260805.py` 15 组断言 PASS:四模块 CRUD + report generate 聚合 + 菜单翻转 + 文案清理。
- **批3** `Temp/claude/e2e_gaps_base_20260804.py` 19 ok / 0 fail:审计三操作(CREATE 记录级 / UPDATE 字段级 diff / DELETE 记录级)+ 导入抑制仅汇总 + 8-session 并发取号 seq 1-8 唯一 + 三类预警命中(树超期/花粉过期/种子超期)、无负例误报、幂等去重、resolve→不再重复 + 备份脚本执行成功 + pg_restore --list 含 bre_alert/bre_sequence/bre_audit_log/bre_analysis_dataset + BrAPI 分页数学/germplasm/variable/study/observation 映射。
- **回归**e2e_spatial_sparse3 段)/e2e_gwas7 段)/e2e_molrigor5 段)/e2e_advanced_gblup4 段)/e2e_gblup_cv3 段)/e2e_refine8 段)/e2e_gxr4 段)/e2e_corr_spatial3 段)全复跑零回归;其间修复 1 处回归——`statistics.service._allelic_columns` 的 B2 SSR 兜底对 **SNP 标记**误把多等位调用(如 "1/2")当有效剂量 → 树 4 被误判基因型、破坏「非基因型株 GBLUP EBV=0」语义;修复:仅 `marker_type` 为空时走 SSR 每等位展开,SNP 标记 "1/2" 视为缺失(显式 SSR 分支不受影响,e2e_molrigor 全绿兜底)。
- **openapi**:重启后端后核验 **631 路径**5 brapi + `/bre/breeding_report/report/generate` + `/bre/audit/list|detail|options` + `/bre/alert/list|detail|options|resolve` 全在);HTTP smokegermplasm 37 / variables 71 / studies 3 / observations 107 / miappe 3 模板);前端 vue-tsc --noEmit EXIT=0。
## 十八、桃育种业务流全面完善:业务数据链 + 统计算法 + 前端体验(2026-08-05
> 用户要求「对现有功能,结合桃育种实际业务流程与需求,进行全面测试分析,并完善」。三路审计(双代理并行 + 数据层性状字典探测 + 独立 grep/read 验证)收敛真实缺口 **10 项**(业务数据链 1-6 / 统计算法 7 / 前端 8-10),拍板全部实施 + 两裁决:**导入按钮维持隐藏**(23+ 页显式隐藏,导入弹窗/处理器/后端端点完整保留)、**采收入口走农事操作**(op_type=harvest 结构化产量表单 + 同步统计引擎,非独立模块)。批A 业务数据链(A1-A6)/ 批B 统计算法(B1-B4)/ 批C 前端(C1-C4),分三批独立 e2e + 全量回归零回归,后端重启 + openapi 核验 + vue-tsc EXIT=0。完整台账见规格 §8.27。
### 18.1 批A 业务数据链(A1-A6
- **A1 果实采收结构化入口**`field_operation/{model,service,schema}.py`):`bre_field_operation``yield_kg`/`fruit_count`/`avg_fruit_weight`/`marketable_rate` 4 可空列(`backend/sql/weld_busflow.sql` `ADD COLUMN IF NOT EXISTS` 幂等,create_all 不建已有表新列);service create/update 当 `op_type=="harvest"` 且 tree_id 非空且有产量数据 → 按 trait_codesingle_tree_yield/fruit_number/avg_fruit_weight/marketable_rate)查 trait_id 同步写 `bre_trait_observation`evaluate_year=op_date.year、trial_study_id 由 plot 继承),trait_code 缺失跳过不 409**plot 级采收只留 field_operation,不进树级统计**。
- **A2 性状种子**`backend/sql/bre_yield_phenology_traits.sql``ON CONFLICT(trait_code) DO UPDATE` 幂等):产量构成 5(单株产量/果数/均果重/好果率/裂果率 low)+ 物候 3 date 型(盛花期/果实成熟期/落叶期)+ 品质 3(可溶性固形物/可滴定酸 low/固酸比)+ 生长量 3(主干周长/树高/冠幅)+ 描述性 categorical 5(果形/茸毛/离核/果皮底色/着色类型,into_ebv=0)。
- **A3 种质级观测**`bre_observation` 加可空 `germplasm_id`FK→bre_germplasmweld ALTER + index);observation service `assert_parents_exist` 扩展种质校验;前端表单种质选择器 + 搜索栏 germplasm 过滤。
- **A4 授粉→收种→种子处理补链**:`bre_seed_lot.pollination_id`FK→bre_pollination+ `bre_seed_treatment.seed_lot_id`FK→bre_seed_lotweld ALTER);前端 seed_lot 授粉选择器(按 combination 过滤)、seed_treatment 种子批次选择器。
- **A5 EAV 观测校验**observation + trait_observation create/update):obs_type=numeric→parse float、obs_type=date→parse 日期,否则 409trait 有 valid_min/valid_max 且 numeric → 越界 409**重复校验** 同 (tree_id|plot_id|germplasm_id, trait_id, obs_year, obs_date) 已存在 → 409(精确到日,同日不同 trait / 不同日多次观测放行)。
- **A6 阶段自动设置 + 成株门禁**tree.service create 当 stage 为空 → 按 breeding_generation 推断(F 代杂种→`juvenile`、亲本/嫁接成株→`evaluation`);trait_observation create 门禁 trait.stage=evaluation 而 tree.stage=juvenile → **409**「童期树不可录成株性状」;juvenile 性状录童期树仍允许;不影响 decision_preview 的 marker 辅助选入(非观测路径)。
### 18.2 批B 统计算法(B1-B4
- **B1 type-B 多环境遗传力**`statistics/service.py`):`_values_by_tree_env`(按 trait_id + trial_study_id/evaluate_year 分环境聚合树→值)+ `run_type_b_heredity` **复用 `mtblup.solve_bivariate` 把环境当"性状"**phenos={"E1":{tree:v},"E2":{tree:v}} 同一系谱)精确 REML 估 r_g;`method="calo"` 备选(分环境 EBV 相关/√rel);`env_dim="site"|"year"`;共有树 <2 → 409;落 `bre_type_b_result``statistics/model.py` 新表,镜像 GENCORR+ controller `POST /statistics/type-b-heredity` + `GET /type-b` + `GET /type-b/{id}`;前端 type-B tab。
- **B2 correlation genetic 模式**`correlation_matrix``mode="pheno"|"genetic"``g_method``year`**pheno 分支逐字节不动**genetic 走新私有 `_genetic_corr_matrix` 逐对 `mtblup.solve_bivariate` 组装 G0(对角 1、非对角钳[-1,1]),**不落库**(对齐 data_quality 计算端点模式);schema CorrelationIn 加 mode/g_method/year。
- **B3 selection_index 自动权重**`auto_weights: bool=False` → True 时权重=`_trait_meta_map`.default_h2(实测 h² 优先,兜底 0.1)、**强制 use_h2=False**(防双重相乘)、direction 由 `_weighted_z_index` asc 翻转处理;weights_json 记 `"__auto":true`into_ebv=0 剔除进 dropped。
- **B4 UPGMA 聚类**`run_cluster`trait_ids/entity_type(tree|clone)/mode(pheno|genetic)/distance(1-|r| 或 euclidean 标准化)/k)输入矩阵复用 `_genetic_corr_matrix`/correlation_matrix**UPGMA 纯 numpy**(距离矩阵迭代合并,无 scipy);输出 `{clusters, merges, order}`controller `POST /statistics/cluster`(不落库);前端 cluster 树状图 tab。
### 18.3 批C 前端(C1-C4,按用户裁决:不恢复导入按钮)
- **C1 观测录入增强**observation 页搜索栏加 plot/trial_study(站点)/germplasm 过滤(ObservationQueryParam 加 tree_id/plot_id/germplasm_id/trial_study_id+ germplasm 表单(A3);field_operation 页 op_type=harvest 动态显示产量结构化表单 + 表格 4 列。
- **C2 统计可视化 ECharts**`echarts.ts` 注册 HeatmapChart + VisualMapComponent`statistics/index.vue` correlation 热图(mode 切换)+ gblup 可靠性热图/EBV 趋势折线(per-batch 聚合)+ type-B tab(热图+明细)+ cluster 树状图;图表生命周期(activeTab→resize、window resize、onBeforeUnmount dispose)。
- **C3 combination-funnel 前端入口**statistics 工具栏「组合得失漏斗」按钮 + 1080px 对话框调 `GET /statistics/combination-funnel`(后端已有、前端此前缺失)。
- **C4 stage_phenotype 容器同步**`_shared/StageView.vue` compMap 注册 Observation/FieldOperation`stage_phenotype/index.vue` tabs 通用观测/农事操作翻真实页。
### 18.4 版本与验证
- `_DATA_VERSION` **v2.15**service.py:94);**引擎版本不变**mtblup/blup/gwas/genomic 本轮未改)。
- **批A** `Temp/claude/e2e_busflow_20260805.py` **11 组断言 PASS**(A1 采收同步 4 行观测/plot 级不写 + A2 性状种子齐全 + A3 种质观测回查 + A4 授粉→收种→处理全链路 + A5 非法/越界/重复 409 + A6 F1 自动 juvenile、童期录成株 409)。
- **批B** `Temp/claude/e2e_statsflow_20260805.py` **15 组断言 PASS**type-B 矩阵对角 1/对称/r_g 范围/site·year 环境集不同/n_common 共有树/GET 回查 + correlation pheno 逐字节回归/genetic 对称对角 1/calo 回退 + index auto==手工 default_h2 权重/asc 翻转/into_ebv=0 剔除 + cluster 3 已知类还原/k 边界/clone 聚合)。
- **批C** HTTP smoke `Temp/claude/smoke_busflow_c_20260805.py` **10 检查全过**observation 3 过滤对真实数据 n=1 全命中 + funnel n=21 + correlation pheno/genetic + type-b list + cluster POST + auto_weights);vue-tsc --noEmit EXIT=0。
- **回归**:**11 套件全复跑零回归**——e2e_spatial_sparse / e2e_gwas / e2e_molrigor / e2e_advanced_gblup / e2e_gblup_cv / e2e_refine / e2e_gxr / e2e_corr_spatial / e2e_gaps_engines / e2e_gaps_modules / e2e_gaps_base(其间同步 e2e_spatial_sparse 两处 `data_version` 断言 v2.14→v2.15,版本语义更新非回归)。
- **openapi**:后端重启核验 `/statistics/type-b-heredity``/type-b``/type-b/{id}``/statistics/cluster``correlation?mode/genetic``/selection-index auto_weights` 全在;observation list 四过滤(tree/plot/germplasm/trial_study)经真实 HTTP 命中。
### 18.5 世代闭环修复:单株晋级同步落系谱(2026-08-05 跟进)
> **用户报告闭环断裂**`selection_result/service._promote_tree_to_clone` 晋升单株到品系(line/regional_trial/released)时仅 `BreedingGermplasmCRUD.create(cultivar_name=clone_code)` 建种质,**未同步写 `bre_pedigree`** → 新种质在统计引擎 `_build_pedigree`statistics/service.py:299,按 `bre_pedigree.child_code`→`germplasm.cultivar_name` 匹配祖先)里查不到亲本,被当 **founder**,跨世代系谱链断裂:A-BLUP / 亲缘矩阵 / 选配近交规避跨代失效、遗传增益滚雪球效应归零。
**修复**`selection_result/service.py`):晋级到 `_GERMPLASM_STAGES` 且树未关联种质时,建 `bre_germplasm` **携带 generation/stage**,并自动落一条 `bre_pedigree``child_code=clone_code(品种名)``dam_id/sire_id=tree.dam_id/sire_id`(为空回退组合 `female_parent_id/male_parent_id`)、`combination_id``generation=tree.generation`、remark「单株晋级自动落系谱(世代闭环)」;**child_code 幂等查重**(已存在不重复落)。附 `combo=None` 顶部初始化,消除"树已有 clone(ap/sp 晋级过)再晋级品系"路径的 `UnboundLocalError` 隐患。
**引擎级验证**`Temp/claude/e2e_pedigree_closure_20260805.py`,11 组断言全过):① 晋升 line → 建种质携带 generation/stage + 自动落谱(dam/sire/combination/generation 齐);② `_build_pedigree` 对下一代树输出 `g{晋升种质}` 带 dam/sire(非 founder);③ **A 矩阵跨代恢复**——两棵仅经晋升种质共享祖先的下一代树,亲缘 `A[T2,T3]=0`(修复前,gT1 当 founder)→ `0.125`(修复后,血缘推导 `2·¼·f(gT1,gA)=2·¼·¼`);`A[gT1,gA]=0.5`(亲子)佐证链条接通;④ tree.dam/sire 为空 → 组合亲本回退落谱;⑤ child_code 预置行不重复;⑥ 已有 clone(sp 晋级过)再晋级品系 → else 分支回退组合亲本落谱(`combo=None` 初始化防 UnboundLocalError 的回归用例)。
**回归**e2e_batch_selection(晋级主线,含新建谱行被 combo CASCADE 清理无残留)/ e2e_gaps_base19 ok/ e2e_spatial_sparse / e2e_advanced_gblup / e2e_gaps_modules15 组)全过零回归。
### 18.6 近交惩罚「静默关闭」修复:亲缘矩阵多源解析 + 显式告警(2026-08-05 跟进)
> **用户报告最隐蔽的坑**`mating_recommend` 的亲缘矩阵靠 `_germplasm_pedigree`statistics/service.py)用 `bre_pedigree.child_code` 与种质 `cultivar_name/accession_no` **精确字符串匹配**来建。一旦名称不完全一致(大小写/空格/代号),pedigree 返回空 → `rmat={}` → 所有配对 `r=0` → `kin_pen=max(0,0thr)=0` → **近交规避整体失效,且无任何告警**——用户以为系统在避近交,实际没避。用户提出三点修复方向:① 匹配失败显式告警;② 优先用种质实体自带 dam/sire 或 clone/tree 聚合,而非名称反查;③ 绝不静默 no-op。核实确认,并额外发现:候选既是 child 又是祖先时 `g{id}` 被重复追加 → `blup.relationship_matrix` 抛『系谱个体重复』→ 端点崩溃。
**修复**`statistics/service.py`)——重写 `_germplasm_pedigree` 为**多源级联**(返回 `(pedigree, coverage)``coverage={total,resolved,resolved_ids,founder,matched_rows,orphan_rows,fk_sources}`):
1. **① 显式系谱(权威)**`bre_pedigree.child_code` 规范化(strip+casefold)命中 `cultivar_name/accession_no` 索引——保留手录系谱语义,并直接修复大小写/空格错配;
2. **② FK 兜底**`tree.germplasm_id == 该种质` 的树 → 其 `dam_id/sire_id` 全集去重后**唯一一致**才采纳(升种质=升谱树自带种质级亲本,消除名称反查对代号错配的脆弱性);多对歧义(trial 树挂冲突亲本)→ 视为无回退 founder,不武断选取;
3. **③ founder**。祖先以同级联 **BFS 展开 + 去重**(修复重复抛错崩溃 + 打通跨代系谱链)。
`mating_recommend` 新增显式告警:**`kinship_status=ok|partial|none`** + **`kinship_warning`**(none→「候选亲本均未解析到系谱…近交惩罚已禁用:所有配对 r 按 0 计」;partial→列未解析亲本名单;ok 但有孤儿行→「bre_pedigree 有 N 条 child_code 未匹配任何种质名称(孤儿记录),跨代亲缘可能低估」)+ 逐对 `flags` 加「亲缘未解析(r 按 0 计)」;返回体新增 `kinship`resolved/founder/matched_rows/orphan_rows/fk_sources)。**设计红线**:FK 只做兜底、绝不覆盖显式系谱(A6 回归保真:trial 树 FK 挂 FM/MM 与显式系谱 dam=G0 冲突 → r(G0,G4)=0.5 保持)。
**验证**`Temp/claude/e2e_mating_kinship_20260805.py`,**14 组断言全过**):① FK 兜底恢复(无 ped 行升种质树直连 → r(GX,GA)=0.5,修复前为 0);② 孤儿行告警(全解析 status=ok + orphan 警告);③ 规范化匹配(child_code 大小写变体仍命中显式系谱);④ 三代链不崩 + r(GX,GW)=0.5 / r(GA,GW)=0.25;⑤ 全 founder → status=none + 显式告警 + 逐对旗标;⑥ partial → 未解析亲本名单。**回归**e2e_data_mating_gainA6r=0.5 保真)/ e2e_batch_selection / e2e_gaps_base 全过零回归。**HTTP 核验**:后端重启后 `/bre/statistics/mating-recommend` 真实数据 32/33 → `kinship_status=none` + `kinship_warning` 含「近交惩罚已禁用」+ `kinship={resolved:0,founder:2,orphan_rows:2}` + 逐对旗标(顺带暴露 2 条真实孤儿系谱行——数据质量信号)。
### 18.7 选配「亲本 EBV」回退逻辑方法学修复:direct 优先 + 子代测验降权 + 双侧去重(2026-08-05 跟进)
> **用户报告方法学错误**`mating_recommend` 旧实现对无直接 EBV 行(ABLUP/GBLUP 按树写、`germplasm_id` 为空)的候选种质,用**「其子代树 EBV 均值」回退代表该亲本育种值**。三条质疑核实成立:① 这是 **progeny-test 值**(子代世代预测值 ≈½亲本BV+共亲本渗入+孟德尔抽样),不是亲本自身育种值;② 同一子代树若双亲都缺直接 EBV,被**等权计入 dam 与 sire 两侧**,稀释严重;③ 跨组合混合无区分。会误导选配排序。用户提出修复方向:**优先用亲本自身预测值;回退值必须显式标注「基于子代测验的近似」并降权参与打分**。
**修复**`statistics/service.py` `mating_recommend`):
1. **direct 优先**:种质级 EBV 行(`germplasm_id` 直连)=亲本自身预测值,无条件最优先;有 direct 的候选**绝不被其子代树值污染**(回退仅对 `missing` 集生效,杜绝树级 99.0 泄漏进亲本)。
2. **回退显式标注 + 降权**:新增 `_EBV_SOURCE_FACTOR = {direct:1.0, progeny:0.5, missing:0.0}`;打分改 `mid=(f_a·ebv_a+f_b·ebv_b)/2``score=w_ebv·midw_kin·pen`——progeny 近似按**半权**参与,绝不冒充亲本自身值、不掩盖 direct;missing 按 0 计(与旧行为一致,全缺失时排序不变)。
3. **双侧等权稀释修复**:子代树双亲均在 `missing` 集(如 FM×MM 双亲均无 direct)→ **剔除**(该树均值无法归属,防止同值计入两侧);仅单侧可归属的树才计入对应亲本。
4. **跨组合辨别**:回退亲本记 `n_progeny`(子代数)/`n_combos`(跨组合数),供调用方判断子代测验近似的稳健性。
5. **显式可查,绝不静默降级**:返回体新增 **`candidate_ebv`**(每候选 `germplasm_id/name/value/source/n_progeny/n_combos`missing 的 value=None+ **`ebv_source.coverage`**direct/progeny/missing 计数)+ 逐对 `flags` 加「亲本EBV为子代测验近似(降权0.5)」/「亲本无EBV(按0计)」。
**验证**`Temp/claude/e2e_mating_ebv_20260805.py`,**5 组断言全过**):① candidate_ebv 来源可查——P0=direct/10.0(子代树值 99.0 未泄漏)、P1=progeny/8.0n_progeny=3、n_combos=2)、P2/P3/P4=missing/None;② `ebv_source.coverage={direct:1,progeny:1,missing:3}`;③ 降权打分——P0×P1 `ebv_mid=7.0=(1.0·10+0.5·8)/2`(≠9.0 原始均值)+「子代测验近似」旗标、P0×P2 `ebv_mid=5.0`+「无EBV」旗标;④ 双侧去重——P3×P4 双亲均缺 → 子代树剔除 → source=missing、`ebv_mid=0.0`(旧代码会 progeny=7.0);⑤ score 降序、榜首 P0×P1(加权 EBV 互补最高)。**回归**e2e_data_mating_gainA6 无 Prediction 行 → 全 missing → 排序不变)/ e2e_mating_kinshipok=14/ e2e_batch_selection / e2e_gaps_base19 ok)全过零回归。**HTTP 核验**:后端重启后 `/bre/statistics/mating-recommend` 真实数据返回 `candidate_ebv`12 候选全 source=missing/value=None+ `ebv_source.coverage={direct:0,progeny:0,missing:12}` + 逐对旗标。
### 18.8 数据质量「离群值」方向语义错位修复:同向=极值候选(精英)/ 反向=疑似录入错误(2026-08-05 跟进)
> **用户报告语义错位**`data_quality_report`(§8.17①/§8.23① 的 A5 数据质量端点)旧实现用 IQR(Q11.5IQR/Q3+1.5IQR) 超界 + MAD 稳健 z-score(>3.5) 双通道把**任何偏离分布的值**都标为「离群株(疑似异常)」。但桃育种**按选育目标选极端表型**——果重/固酸比/可溶性固形物要高的、裂果率/病指要低的——**正向偏离恰恰是育种家要选的精英单株**(与高 EBV 高度相关),把精英候选标成「疑似录入错误」会诱导弃选、误导决策。用户提出修复方向:**仅当偏离方向与选育目标相反才提示疑似录入错误;同向偏离标为「极值候选(精英)」**。
**修复**`statistics/service.py` `data_quality_report`):
1. **方向感知**`trait_row = await self._numeric_trait(trait_id)` 后取 `direction = (trait_row.direction or "desc").lower()``desirable_high = direction != "asc"`desc/None → 高值优;asc → 低值优)。判定标准与 v2.3 性状方向标注链路一致,低优性状(裂果率/病指)反向侧为高值。
2. **双通道分流**:IQR/MAD 命中的株再按偏离侧分类——`is_high = v > med``is_elite = is_high == desirable_high`**同向偏离 → `extreme_candidates`**`class="extreme_candidate"`side=high/low,极值候选·精英);**反向偏离 → `outliers`**`class="outlier"`,疑似录入错误)。两表**互斥**,精英绝不进错误表。
3. **返回体**:新增 `direction``extreme_candidates`tree_id/value/z/side/class/reasons)、`summary.n_extreme_candidates``summary.has_warning/n_outliers/outlier_rate` 语义收紧为**疑似录入错误**计数(不再把精英株计入告警)。`is_high = v > med` 而非 >0,中位对称稳健。
4. **前端**`statistics/index.vue` 数据质量 tab):选育方向指示条(高值优 desc / 低值优 asc)+ 双表——「极值候选(精英)」success 标签表 + 「疑似录入错误」danger 标签表;hint 说明同向=精英/反向=错误;无错误时绿色 info alert「未发现疑似录入错误」而非黄色警告。
**验证**`Temp/claude/e2e_data_mating_gain_20260804.py` **[1] 17 株断言全过**):15 正常树 + 精英树(`{PREFIX}-HI`,值 16.0G3+ 错误树(`{PREFIX}-LO`,值 2.0G3),direction=desc——精英树进 `extreme_candidates``class=extreme_candidate`/`side=high`)且**不在** outliers;错误树进 `outliers``class=outlier`/`side=low`);`n_trees=17``n_extreme_candidates=1``n_outliers=1``missing_rate=0`。**回归**e2e_mating_kinshipok=14/ e2e_batch_selection / e2e_gaps_base19 ok)全过零回归。**HTTP 核验**:后端重启后 `POST /bre/statistics/data-quality` 对 asc 裂果率(bB_DIR5668)与 desc 果重(dA_DIR5668)两真实性状返回 `direction`/`extreme_candidates`/`outliers`/`summary.n_extreme_candidates` 全部正确——真实数据无极端偏离 → 双表空(**无误报**)。
### 18.9 ΔG 投影假设声明 + 工程健壮性打磨:note 假设 + spatial 缺坐标降级 + numpy 收敛(2026-08-05 跟进)
> **用户报告两点,均非功能 bug**(核实确认后拍板落地):① `genetic_gain`(§8.23① A3 遗传增益端点)的 `next_pheno_mean = pheno_mean ± dg` 隐含「环境均值恒定」假设——若年际气候漂移,投影会偏;属投影演示性质,应**显式标注假设**。② 工程健壮性细节——spatial 模型要求所有观测树都有 row/col,否则整批 ValueError(门禁合理但无「剔除缺坐标者继续」的优雅降级);`data_quality_report`/`genetic_gain` 函数体内重复 `import numpy`;多处 numpy 计算未利用托管 venv 向量化优势。
**修复**`statistics/service.py` + `statistics/index.vue`):
1. **① ΔG 投影假设显式声明**`genetic_gain` 返回体新增 `note` 静态常量——`投影假设环境均值恒定(未计入年际气候漂移与栽培措施变化);ΔG=k·r_g·σ_A 仅含遗传增益分量,next_pheno_mean 为投影演示值而非实测预测。`(同性状/同数据重跑不变,探针断言稳定)。前端 gain tab 在描述区后、轮次表前展示 `el-alert type="info"` 提示假设边界。
2. **② spatial 缺坐标优雅降级**:`run_ablup(spatial=True)` 坐标收集循环把 `row_no/col_no` 为空的观测树记入 `missing_coord_ids`**剔除其表型但保留系谱**——`blup.solve_spatial` 本就对所有个体(含无表型)输出 EBV,故缺坐标株 EBV 仍由系谱预测;剔除数显式写入批次 note「缺坐标剔除N株表型(EBV由系谱预测)」;**仅当全部观测树都缺坐标(coords 空)才整批 409**(提示先在单株录入填行号/列号)。`input_hash` 随剔除后的表型子集计算(同数据可复现)。**设计红线**:缺坐标仅剔除该株表型、绝不剔除系谱——系谱是空间 EBV 的预测基础。
3. **③ numpy 工程清理**`data_quality_report`/`genetic_gain` 及另 5 处(genetic_corr/selection_index/bivariate/genetic/type-B/UPGMA)函数体内重复 `import numpy` 全部收敛为**模块级单次** `import numpy as np`service.py:24);`data_quality_report` 逐株 flag 循环改 **numpy 布尔掩码向量化**——`z_robust_all = np.where(mad>1e-9, 0.6745·(amed)/mad, 0)``iqr_flag_all = (a<q11.5iqr)|(a>q3+1.5iqr)``z_flag_all = |z_robust|>3.5``flagged_idx = np.nonzero(iqr|z)[0]` 一次性定位命中株,输出逐字节不变(精英/错误分流逻辑不变)。
**验证**`Temp/claude/e2e_spatial_sparse_20260804.py` **降级场景断言全过**):5 株(前 4 株 2×2 网格带 row/col + 第 5 株 `row_no=None`)观测 [10.0,10.5,11.0,11.5,9.0] → `method=AR1×AR1``train_n=4`、note 含「缺坐标剔除1株」、**5 株全部有 EBV 行**(缺坐标株由系谱预测);全缺坐标场景仍整批 409 且报错含 row_no/col_no 数据需求。**A6 探针 [2]** 新增 note 断言:`note` 含「环境均值恒定」且两性状稳定一致。**回归**e2e_spatial_sparse / e2e_data_mating_gain / e2e_mating_kinshipok=14/ e2e_batch_selection / e2e_gaps_base19 ok)五套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/genetic-gain`(真实性状 dA_DIR5668)返回 `note`(含「环境均值恒定」);`POST /bre/statistics/data-quality` 返回 `direction: asc`、双表空无误报。
### 18.10 A–F 六项功能级缺口·批1 父本验证 + 近交衰退:一致性校验 + F→表型回归(2026-08-05 跟进)
> 用户全模块 grep 实证 A–F 六项**功能级缺口**(「有无/深度」问题,非正确性 bug),逐项复核确认 + 拍板「**全部六项分批落地**」。批1 = A 父本验证(pollination 花粉来源一致性 / tree 显式亲本警示 / cross_combination 自交门禁)+ C 近交衰退(`_DATA_VERSION` v2.22)。
**A 父本验证**consistency,不落库):
1. **A1 pollination 花粉来源父本一致性**`pollination/service.py` 新增 `_validate_pollen_parent`):批次 `pollen_lot.male_tree_id` 声明采集父本树时,授粉声明 `male_tree_id` 须一致,否则 409「花粉批次 {lot_code} 采集自父本树 {X},与授粉声明父本树 {Y} 不一致,请确认花粉来源」;**批次无采集父本(混合/外地采集)或授粉未声明父本 → 放行**。create/update 统一在 `_validate_pollen_window` 后调用(update 取 `existing` 回退)。
2. **A2 tree 显式亲本 vs 组合父母本警示**`tree/service.py` `_resolve_parents` 改返回 `(dam, sire, warning)`):显式 dam/sire 与组合 female/male_parent 不一致时聚合「显式母本与组合母本不一致;显式父本与组合父本不一致(以显式为准)」;**warning 不阻断**(tree 可独立建,武断 409 会误伤);`tree/schema.py` 加只读 `warning` 字段(仅返回体,不落库)。
3. **A3 cross_combination 同质自交门禁**`cross_combination/service.py` `_check_parent_roles` 角色解析后追加):`female_parent_id == male_parent_id` → 409「母本与父本同为「{名}」,自交组合请确认」;create/update 生效亲本统一触发(与既有 S-等位 409 语义一致不冲突)。
**C 近交衰退分析**`statistics/` 三件套 + 前端,计算端点不建表):
- **`POST /statistics/inbreeding-depression`**`InbreedingDepressionIn`trait_id/trait_code + year/trial_study_id 可选 + min_n=10)——`inbreeding_depression`tree 系谱(`t{tree_id}` 个体 + `g{germplasm_id}` founder)→ `blup.relationship_matrix` 取 F=A_ii1**关键洞见:`inbreeding` dict 仅含 F>0,非近交树须从 `individuals` 默认 F=0 兜底**,否则非近交株被排除出回归;trait 树级表型 `select(obs.tree_id, func.avg(value_numeric)).group_by(tree_id)` 聚合(按 year/trial_study_id 可选过滤)→ 交集树 → 纯 numpy `np.linalg.lstsq` 线性回归 phenotype ~ F。返回 `{sufficient, reason, n_obs, mean_F, max_F, direction, regression:{intercept, slope, r2, t_slope, depression_rate, has_depression, interpretation}, high_inbreeding:[{tree_id, tree_no, F, value}]}``has_depression = slope<0 且 t_slope≤−1.645`(单侧 95% 大样本近似);`high_inbreeding` 按 F 降序取前 10**n<min_n 优雅降级** `sufficient=False` + reason(不 409)。
- **前端**「亲缘/近交」tab 加「近交衰退(F → 表型)」区:trait select + year input + 运行;`el-alert`insufficient=warning / has_depression=error / 无衰退=success+ `el-descriptions` + `high_inbreeding` 表。**修 vue-tsc TS2322`el-alert :type` 无 danger 合法值,改 `'error'`**。
**验证**`Temp/claude/e2e_parent_validation_20260805.py` **10 断言全过**——A1 不一致 409(含「不一致」)/一致放行/混合批次放行/update 同门禁;A2 双侧警示(含「以显式为准」、dam/sire=显式)/单侧仅父本/一致无警示/update 警示;A3 create/update 同质 409(含「自交」)。`Temp/claude/e2e_inbreeding_depression_20260805.py` **4 断言全过**——12 树(6×F=0 + 6×F=0.5 自交)衰退性状 y=10060F+ε → slope≈−60/t 显著负/r²>0.9/has_depression=true/depression_rate<0/max_F≈0.5/mean_F≈0.25/high_inbreeding 前 6 全为 S-自交 F=0.5、后 4 F=0;无衰退 y≈100 → slope≈0/「未检出」;min_n=20 → insufficient 含「12 棵」「≥20」;trait_id=99999999 → 409。**回归**e2e_spatial_sparsev2.22 断言同步)/ e2e_statsflow / e2e_data_mating_gain / e2e_mating_kinship / e2e_batch_selection / e2e_gaps_base 六套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/inbreeding-depression`(真实稀疏数据)返回 code=0、sufficient=false、n_obs=2、reason「同时具备系谱近交系数 F 与表型的树仅 2 棵(需 ≥10)」、mean_F/max_F/regression=null、high_inbreeding=[]。
### 18.11 AF 六项功能级缺口·批2 GS 家系 CV + 试验设计深度:家系阻塞折 + RCBD 生成/区组 ANOVA2026-08-05 跟进)
> AF 六项缺口批2 = **B GS 家系 CV**(深度:随机分层 → 家系阻塞折)+ **F 试验设计深度**(RCBD 生成 + 设计基 ANOVA)。批1 已落地 §18.10v2.22);本批 `_DATA_VERSION` v2.23。
**B GS 家系 CV**`genomic.py` + `statistics/service.py` + 前端):
1. **引擎** `genomic.kfold_cv_genomic``split: str = "random"` + `family_of: dict[str, str] | None = None``split="random"` → 现有 round-robin `bin_of = {c: i % k}` **逐字节不变**(回归零变化);`split="family"` → 照 `blup.kfold_cv` 的 sire 家系留出模式——`fam_of = {ind: (family_of or {}).get(ind, ("self", ind))}`(无家系个体自成一族)→ `fams` 去重 → `rng.shuffle(fams)``fam_bin = {f: i % k}``bin_of = {c: fam_bin[fam_of[c]]}`,**同家系个体同折**(防亲缘泄漏高估准确度);**家系数 < 折数 k → 折叠为 n_families 折 + warning**「家系数 {n} < 请求折数,折叠为 {k} 折(family-blocked)」;**单家系(n_families<2)→ folds=[] + warning**「可验证个体仅构成 1 个家系,无法家系阻塞交叉验证(请改用随机分层)」。输出加 `n_families`(逐键对齐 blup.kfold_cv)。
2. **服务** `run_cv``split="random"|"family"` 透传(controller/schemajob params_json 记 split):GS 分支 `split=="family"` 时用既有 `ped_rows`select 顺序 id/dam_id/**sire_id**/trial_study_id/rootstock_id/female_parent_id/**male_parent_id**/combination_id/clone_id/germplasm_id)构建 `family_of = {f"t{tid}": f"s{s}"}``s = sire if sire is not None else cm`sire 缺失回退组合 male_parent);落库 `CvResultModel.note``split=family · n_families={N}`+ 引擎 warning 拼接)。
3. **前端**「交叉验证」tab runCv 参数区加 split 下拉(random=随机分层/family=家系阻塞)+ 结果表 n_families 列。
**F 试验设计深度**`trial_study_entry/model.py` + `weld_trial_study_entry.sql` + `statistics/` 三件 + `anova.py` + 前端):
1. **F1 RCBD 生成器**`bre_trial_study_entry` 加可空 `block_no integer`model 列 `block_no: Mapped[int | None]` + `sql/weld_trial_study_entry.sql` `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`create_all 只建新表故 weld 幂等兜底);新端点 `POST /statistics/trial-design``TrialDesignIn`trial_study_id + design_type="rcbd" + seed 可选)——`trial_design``db.get(TrialStudyModel)` 409、design_type≠rcbd 409、block_count=study.block_count or 1、按 entry_number 取参试条目(空 409「无参试条目」)→ `random.Random(seed)` 洗牌 + round-robin 分进区组(均分 + 组内随机 = 田间布局)→ `update(...).values(block_no=case(block_of, value=TrialStudyEntryModel.id, else_=None))` 批量落库 + flush;返回 `{trial_study_id, design_type, block_count, seed, n_entries, blocks:{str(b): [entry_number…]}}`
2. **F2 设计基 ANOVA**`anova.solve_rcbd(rows)`rows=`{"group","block","value"}`RCBD 双因素 **Type I 顺序**X1→Xg→Xgb dummy 矩阵:SS_group=rss(X1)rss(Xg)、SS_block=rss(Xg)rss(Xgb)、SS_error=rss(Xgb),纯 numpy + `fdist.f_pvalue`),输出含 f_block/p_block/groups/blocks/warning<2 组合或 <2 区组 ValueErrordf_error≤0 → warning「区组设计过饱和」);`anova.solve` 单因素**逐字节不变**。`run_anova``block: bool=False`block=False → 原单因素路径不变;block=True → 查 `bre_tree.block_no` 组 rows、过滤空 block、<2 区组 → 409「区组数据不足:需 ≥2 个区组(请先运行 /statistics/trial-design 生成设计并落库 block_no)」,method=ANOVA/H2/RCBD。
3. **前端** statistics ANOVA tab 重构:顶部「生成 RCBD 设计」工具条(trial_study select + seed input + warning button+ 设计区组表 + trait select + year + `el-checkbox anovaBlock`「RCBD 区组校正」+ 提交;结果加 n_blocks/f_block/p_block 条件 v-if + 区组均值表。`statistics.ts``trialDesign()` + `TrialDesignResult`
**验证**
- `Temp/claude/e2e_trial_design_20260805.py` **5 组断言全过**——[1] RCBD 生成(block_count=3/n_entries=9/3 区组×3 均分/9 条目齐全/seed·design_type 回显);[2] block_no 落库核验(紧随首次生成避免复现覆盖;落库区组集合==返回设计集合);[1b] seed=42 复现同一设计 / seed=43 异动;[3] block=False → method=ANOVA/H2、无 f_block/n_blocks/blocks 键(单因素逐字节不变);[4] block=True → method=ANOVA/H2/RCBD、n_blocks=3、ss_block>0、f_block>1、p_block 存在、区组均值随 +3/0/−3 递减;[5] 空研究点 409「无参试条目」。
- `Temp/claude/e2e_gs_family_cv_20260805.py` **5 组断言全过**——[1] 5 家系×3 全同胞 k=3 → method=KFCV/GBLUP、note「split=family · n_families=5」、家系阻塞折 n_test=[3,6,6][2] k=5 → 每折恰 1 家系 n_test 全 3[3] random k=3 → note 无 split=family、n_test=[5,5,5](随机分层回归零变化);[4] 引擎级 6 家系<请求 8 → 折叠 6 折 + warning[5] 单家系 → folds=[] + warning。注:探针树创建曾漏 `db.add_all([fm, mm])` 致 germplasm.id=None → 组合父母本全空 → sire 全空 → n_families=15,补 add 后修正为 5(服务侧代码位置核实无误)。
- **回归**e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_busflow / e2e_mating_kinship / e2e_gaps_base / e2e_molrigor 七套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/trial-design` + `POST /bre/statistics/anova/run`(block=true)经真实端点返回。
### 18.12 AF 六项功能级缺口·批3 OCS 最优贡献选择 + MABC 标记辅助回交:投影梯度求解器 + 前景/背景选择工作流(2026-08-05 跟进)
> A–F 六项缺口批3(收官)= **D OCS 最优贡献选择** + **E MABC 标记辅助回交**。批1 §18.10v2.22)、批2 §18.11v2.23);本批 `_DATA_VERSION` **v2.24**。两端点**纯计算不落库**(对齐 data_quality 惯例);前端同批交付(选配推荐 tab OCS 运行区 + 独立回交 MABC tabvue-tsc EXIT=0)。
**共享 helper 抽取 `_candidate_ebv_map`**`statistics/service.py:3429-3531`):
1. `mating_recommend` 内联 EBV 解析块**原样抽取**为 `_candidate_ebv_map(prediction, tree_ids)``{germplasm_id → ebv}`prediction batch ABLUP/GXEBLUP/GXRBLUP/GBLUP/ssGBLUP 全支持;direct germplasm_id 先取,缺失走 progeny 子代均值并 `_EBV_SOURCE_FACTOR={direct:1.0, progeny:0.5, missing:0.0}` 降权;返回 `ebv_map/source/status/warning/cover/n_progeny/n_combos/ebv_mid`
2. **「双亲均缺直接 EBV → 子代树剔除(双侧去重)」规则随抽取原样保留**——经 transcript 抽取前内联块 old_string 实证该规则已存在于抽取前代码(v2.19 方法论),非抽取回归;`e2e_mating_ebv` [4] P3×P4=0.0 权威验证、`e2e_audit_fix_20260804` ④ 已同步语义。
3. **OCS 端点复用** `_candidate_ebv_map`candidate germplasm 直接取)+ `mating_recommend` 保留原内联调用(行为不变)——**mating 回归 14/14 零变化**证明抽取无副作用。
**D OCS 最优贡献选择**`POST /statistics/ocs`):
1. **`_proj_simplex`**:欧氏投影到单纯形(numpy sort/arange 解析投影,无 scipy),`_solve_ocs` **投影梯度 + 回溯线搜索**max Σc_i·ebv_i λ·c'Acs.t. Σc=n_select、c≥0A 由 `_germplasm_pedigree` + `blup.relationship_matrix` rmat 组装(对角=1、非对角候选对 r,覆盖<100% → kinship_status="partial" + warning)。
2. **输出**`contributions`c 降序 + ebv/source/可选 n_progeny/n_combos)、`mean_ebv``avg_kinship`c'Ac)、`kinship_quad``vs_top_n`(同 n 贪心 top-n 对照:mean_ebv 相当 + kinship_reduction,量化 OCS 亲缘控制价值)、`ebv_source/kinship_status/kinship_warning`
3. **门禁**:空候选 / n_select>候选数 / λ<0 → 409。
**E MABC 标记辅助回交**`POST /statistics/mabc-progress`):
1. **前景选择**:复用 `_mas_hit_map`/`_mas_marker_hit`additive/dominance/recessive/allele/haplotype 五语义),`foreground_pass` = 命中 ≥ `foreground_min_hits`stage 无关、童期幼苗即可)。
2. **背景基因组恢复率**background 面板逐标记候选 vs 轮回亲本「纯合剂量一致」比例(`_pure_homologous`:候选纯合且等位∈轮回亲本等位集;杂合不计),标记均值 = 恢复率 %(round 2)。
3. **回交代建议**`_BC_LADDER=["F1","BC1","BC2","BC3","BC4","BC5"]` + `_MABC_GENERATIONS={"F1","BC1","BC2","BC3"}`;晋级 / 再回交 / 补测后判定 / 前景未通过 四分支 reason;`recommended` 前景通过按恢复率降序(None 排尾)。
4. **门禁**:空候选 / 空前景或背景面板 / generation∉`_MABC_GENERATIONS` / background_target∉(0,100] / 轮回亲本不存在 → 409。
**验证**
- `Temp/claude/e2e_ocs_20260805.py` **17 断言全过**——[1] Σc=3、c≥0、coverage=direct 5/5、c 降序、最高=A[2] mean_ebv 与 vs_top_n 相当 + kinship_reduction=0.0398 + kinship_quad≈4.641[3] λ↑(0→0.5→1→10)→ avg_kinship 单调非增(1.0→0.5157→0.3211→0.2685);[4] λ=0 退化=贪心 top-n(满额投最高 EBV 单亲);[5] A 缺失 → kinship_status=partial + warning[6] 三 409。清理干净。
- `Temp/claude/e2e_mabc_20260805.py` **23 断言全过**——[1] 前景 5 pass/1 fail[2] 恢复复算 100/75/75/0[3] reason 晋级 BC2/再回交/前景未通过;[4] recommended 恢复率降序 [100,100,100,75,0][5] 童期 C6 前景通过+晋级;[6] 轮回亲本缺背景基因型 → None + warning[7] 六 409。清理干净。
- **回归**e2e_molrigor / e2e_gwas / e2e_mating_kinship14/14/ e2e_mating_ebv / e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_busflow / e2e_gaps_base / e2e_b8_seed_lot / e2e_prediction_rigor / e2e_audit_fix 全套零回归(`_candidate_ebv_map` 抽取 + mating 语义双核对)。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/ocs`(最小正例)+ `POST /bre/statistics/mabc-progress`(成功 + 空面板 409 + 非法 generation 409)经真实端点返回。环境性 b34(G1 门禁)为探针脆弱非本批回归。
### 18.13 近交衰退两处正确性修复:方向感知检测 + 深层系谱近交系数(2026-08-05 跟进)
> 用户实证复查 `inbreeding_depression`v2.22,§18.10)两处缺陷,本会话核实成立后修复:① **方向盲目判据**——无条件 `slope<0 且 t≤−1.645` 判衰退,对「越低越好」的 asc 性状(如病指)F↑→指标↑=恶化却误报「未检出」;② **浅层近交系数**——系谱只取树级 dam/sire 把每个引用种质当 founder,未走深层系谱,多世代项目(半同胞共享祖亲)低估 F(OCS/mating 已用 `_germplasm_pedigree` 深层解析,故仅近交衰退受影响)。版本仍 v2.24(正确性修复不升版,避免批3 版本断言连锁)。
**① 方向感知检测**`statistics/service.py` `inbreeding_depression`):
1.`direction`(此前读取未用)得 `desirable_high = direction != "asc"`
2. 高优性状(desc/None)衰退 = `slope<0 且 t≤−1.645`;低优性状(asc)衰退 = `slope>0 且 t≥+1.645`
3. `interpretation` 方向化——asc 衰退「F 每升 0.1,{trait} 表型平均**上升(恶化)** …%」/ 未达显著「斜率**偏正**…」/ 未检出「F 对表型无**上升(恶化)**影响」。对齐 `data_quality_report` 既有 `desirable_high` 方向语义。
**② 深层系谱近交系数**
1. 系谱构建改复用 `_germplasm_pedigree`bre_pedigree 名称反查 + tree FK 兜底 + BFS 祖先展开,与 OCS/mating 同源)展开全部被引用种质祖先 + 树节点 + 未解析种质 founder 兜底(软删引用不悬空);`_germplasm_pedigree` 本体零改动。
2. 多世代半同胞共享祖亲 → F 正确 >0(旧浅层把 G7/G8 当 founder → F=0 低估)。
**验证**
- `Temp/claude/e2e_inbreeding_depression_20260805.py` **6 组断言全过**——原 [1] 衰退 / [2] 无衰退 / [3] 样本不足保持,新增 [4] **asc 病指**12 树同 F 结构 y=10+40F → slope=+40、t 显著正、has_depression=true、文案含「上升(恶化)」、高近交前 6 仍 F=0.5 自交株;旧判据误报未检出)+ [5] **深层系谱 F**P→G7/G8 tree FK 升谱、6 候选树 dam=G7 sire=G8 半同胞近交 + 6 对照 F=0y=10060F → max_F=0.125/mean_F=0.0625、slope≈−61、has_depression=true、高近交前 6 全为 H 半同胞株;旧浅层 F=0+ [x] trait 不存在 409 保持。**清理干净**(26 树 48 观测 + 4 性状全删)。
- **回归**e2e_ocs / e2e_mabc / e2e_mating_ebv / e2e_mating_kinship / e2e_statsflow / e2e_spatial_sparse / e2e_gs_family_cv / e2e_trial_design / e2e_parent_validation / e2e_batch_selection / e2e_gaps_base / e2e_gaps_engines / e2e_gaps_modules 全套零回归。**vue-tsc** EXIT=0(前端仅提示文案方向化一行)。HTTP 核验沿用批3(后端未重启)。
### 18.14 分子亲本验证(孟德尔一致性)+ 试验设计深度(增广 + α-格子)(2026-08-05v2.25
> 用户实证复查指出两处遗留缺口,本会话核实**全部成立**:① `genotype_call` 对 mendelian/parentage 零命中(仅有 `fingerprint_check` 无性系混杂/标签互换检测);② `trial_design` 仅 RCBD。α-格子范围用户拍板:**平方格子(v=k²,闭式构造,平衡可证)+ 一般 v 贪心回退(balance_warning 诚实标注)**。`_DATA_VERSION` v2.25,同步 3 处探针版本断言(e2e_prediction_rigor / e2e_spatial_sparse / e2e_statsflow)。
**批4-A 孟德尔/亲本一致性检验**`genotype_call/service.py` `mendelian_check(dataset_id, compat_threshold=0.98)` + `controller.py` `GET /bre/genotype_call/mendelian/check`,镜像 fingerprint/check 模式,纯计算不落库):
1. **数据解析(跨数据集)**:子代样本 = `GenotypeSampleModel.source_type=="tree"` 且 source_id∈dataset → tree 集合;声明亲本 = `tree.dam_id/sire_id`→germplasm(两亲皆空 → `no_declared_parents` + reason「未声明亲本」);亲本基因型 = `source_type=="germplasm"` 样本**跨数据集解析**(同数据集优先,否则其他数据集最低 id 兜底)——探针验证子代样本 D1、亲本样本 D2 跨数据集解析成功;亲本声明但无 germplasm 基因型 → `missing_parent_genotype`**不 409**,reason 标注「母本/父本」缺哪个)。
2. **孟德尔规则**:逐标记 `_allele_set`"/" 分割去空白/缺失)得子代/母本/父本等位集;子代等位集 ⊆ dam∪sire 并集即兼容(union 规则);任亲本空白/缺失 → 非信息位点不计分母。单株兼容率 = 兼容/信息位点,`flag = rate < compat_threshold`0.98 对齐 fingerprint)。
3. **输出**`{dataset_id, compat_threshold, trees_checked, trees_flagged, trees_no_parents, trees_missing_parent_genotype, summary{informative_markers/incompatible_markers}, trees:[{tree_id, tree_no, dam, sire, status, informative_markers, compatible, incompatible, compatibility_rate, flag, incompatible_markers:[{marker_id, allele, dam, sire}], reason?}]}`;数据集无样本 → 零值返回 summary=None(不 409)。
**批4-B 试验设计深度**`statistics/service.py` `trial_design` 分派 rcbd/augmented/alpha**rcbd 路径逐字节不变**`schema.py` `TrialDesignIn``check_germplasm_ids: list[int]=[]` / `block_size: int|None` / `reps: int|None`extra="ignore"):
1. **augmented(增广)**:对照 `check_germplasm_ids` 须为参试条目种质 id 子集(否则 409「对照种质不在参试条目中」)、至少 1 对照 + 1 新品系(否则 409「增广设计需至少 1 个对照种质」);对照每区组重复(anchors,`check_reps=block_count`)、新品系 `rng.shuffle` + round-robin 均分区组(不重复);对照条目 `block_no` **不落库**None)、新品系落 1..block_count。输出加 `checks:[{entry_number,germplasm_id}]`/`n_new_entries`/`n_checks`/`check_reps`
2. **alpha(α-格子)**`block_size=k`v%k==0 否则 409「α-格子条目数 {v} 须能被 block_size {k} 整除」;k 缺省 v 完全平方自动 k=√v,否则 409「α-格子需指定 block_size(当前 {v} 条目非完全平方)」);`reps=r`(缺省平方 k+1/一般 s;r<2 → 409「α-格子重复数需 ≥2」;平方 r>k+1 → 409「完全平方格子(v={v}=k²)重复数最多 {r_full}」)。**平方 v=k² → 闭式格子**:`rng.shuffle` 打标 (x,y)rep m∈{0..k} 直线 y≡m·x+(b1) mod km=k=竖列),完全格子 r=k+1 任一对至多同块一次 λ≤1;k 素数(`_is_prime`)完全平衡 balance_warning=False,非素数 → balance_warning=True(保守告警,可分解不保证平衡)。**非平方 v → 贪心可分解构造**:逐 rep 贪心填 s 块×k,`used_pairs` 集避免同块对重复,卡死则余下允许复用 + balance_warning=Truerng(seed) 确定性。**block_no 复合编码 rep\*100+block**rep 1..r、block 1..k)落库。
3. **探针抓出的真 bug**:平方分支初版 block_no 编码 `m*100+b`0-based m)致 rep1 落库 `b`1..3)与贪心分支/文档的 `rep*100+block` 不一致 → 修正 `(m+1)*100+b`401/402…)。探针 [2] 落库断言由 301/302 → 401/402 验证。
**验证**
- `Temp/claude/e2e_mendelian_check_20260805.py` **8 断言全过**——跨数据集解析(子代 D1/亲本 D2):T1 全 0/1 唯 M5=2/2(亲本均无该等位)→ informative=5/compatible=4/incompatible=1/rate=0.8/flag + incompatible_markers[0]={M5,2/2,dam=0/0,sire=1/1}T2 全兼容 rate=1.0/flag=falseT3 双亲空 → no_declared_parents + reasonT4 dam=G3 无基因型 → missing_parent_genotype + reason「母本」不 409summary informative=10/incompatible=1D3 空数据集零值 summary=None 不 409。清理干净(call→sample→marker→dataset→tree→germ→combo→target 全删)。
- `Temp/claude/e2e_trial_design_ext_20260805.py` **19 断言全过**——[1] augmented 12 条目 3 对照×3 区组:n_new=9/n_checks=3/check_reps=3、新品系 block_no∈{1,2,3} 不重复、对照 block_no=None、checks 结构;[2] v=9=k² k=3 素数 r=4 完全格子:4 rep×3 块×3 条、每 rep 覆盖 9、任一对至多同块一次(maxλ≤1 恰 36 对)、balance_warning=False、block_no 复合编码落库;[3] 部分 r=3 仍平衡;[4] v=16 k=4 非素数 r=5 + balance_warning=True[5] v=12 一般贪心 s=4/r 缺省=s + block_no 落库;[6] 四 409(对照非条目子集/增广无对照/v 不被 k 整除/非平方缺 block_size)。清理干净(entry→study→trial→germ→combo→target 全删)。
- **回归**rcbd 由 `e2e_trial_design_20260805.py` 回归零变化兜底;全量套件 e2e_molrigor / e2e_gwas / e2e_mating_kinship / e2e_mating_ebv / e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_gs_family_cv / e2e_batch_selection / e2e_ocs / e2e_mabc / e2e_gaps_base / e2e_gaps_engines / e2e_gaps_modules / e2e_prediction_rigor / e2e_inbreeding_depression / e2e_parent_validation 全套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启(PID 更换)后 `GET /bre/genotype_call/mendelian/check?dataset_id=999999` → 200 零值结构;`POST /bre/statistics/trial-design` augmented/alpha → 409「该研究点无参试条目」(分派+参数链路通)、design_type=latin → 409「暂不支持设计类型 latin(可用: rcbd=随机完全区组、augmented=增广、alpha=α-格子)」。
- **方法学保留**mendelian_check 与 `fingerprint_check` 互补(样本一致性 vs 子代-亲本孟德尔规则);augmented 对照 anchoring + alpha 平衡性显式告警与 RCBD 随机化并存;亲本基因型缺失/双亲空归状态不 409(数据现状透明化)。
### 18.15 批5 区组随机效应 ABLUP(N3)+ 孟德尔检验落库/隔离/进报告(N1)+ 统计引擎全量数值校验(N2)(2026-08-05v2.26
> 用户实证复查提出三项,本会话逐项核实**全部成立**,用户拍板范围:① **N3**(中-高,真实断点)——`trial_design` 已给增广/α-格子落库 `block_no` 不完全区组结构,但 `run_ablup` 只把 block_no 当空间竞争协变量网格 key,未作随机效应([service.py:651](backend/app/api/v1/module_bre/statistics/service.py#L651))→ 用户选「**显式 block 开关**」;② **N1**(中)——`mendelian_check` 只读不落库、不进数据质量报告、不自动隔离可疑树,错配亲本仍污染系谱 → 用户选「**断开错误亲本链**」;③ **N2**(中)——run_gblup/ssGBLUP、genetic_corr、type_b、run_cluster、stability 等大体量新模块只有结构性断言,缺逐文件数值真值校验 → 用户选「**全量统计引擎**」。`_DATA_VERSION` v2.25→**v2.26**(同步 3 处探针版本断言:e2e_prediction_rigor / e2e_spatial_sparse×2 / e2e_statsflow);`blup.ENGINE_VERSION` 1.4.0→**1.5.0**。
**批5-AN3):ABLUP 区组随机效应**
1. **引擎** `blup.py``solve``block: dict|None` 分派 `_solve_block(pedigree, phenotypes, *, fixed, covariate, block_of, record_map, tol)`(镜像 `_solve_gxe`[blup.py:1006-1205](backend/scripts/breeding_stats/blup.py#L1006-L1205))——Z₂ 按 `block_of: {记录id: 区组水平}` 分组(G×E 的 (g,e) 复合键退化为单区块水平),剖面 REML 坐标上升估 (σ²a/σ²e, σ²block/σ²e)、MME、PEV 可靠性;输出键 `sigma_block/block_ratio/block_effects/n_blocks`、factor_label=「区组」;区组方差收敛到 0 / 无系谱 / 未收敛三警告。`ENGINE_VERSION` → 1.5.0。
2. **服务** `run_ablup`:新参 `block: bool=False`。互斥并入 [L491-494](backend/app/api/v1/module_bre/statistics/service.py#L491-L494)`block``gxe/gxr`(共用 Z₂ 槽)409、`block``spatial`(残差结构与第二随机效应槽)409。新分支:读 `select(TreeModel.id, TreeModel.block_no)``block_of={f"t{tid}": int(blk)}`;无 block_no 的树**降级剔除表型保留系谱**(镜像 spatial 缺坐标降级,note 记剔除数);`len(set(block_of))<2` → 409「区组数据不足:需 ≥2 个区组(请先运行 /statistics/trial-design 生成设计并落库 block_no)」;`method="ABLUP-BLOCK"`、model_name 前缀 `ABLUP_BLOCK_`、note_payload 含 `sigma_block/block_ratio/n_blocks/warning`accuracy 按 block 树均值可靠性。
3. **Schema/控制器/前端**`RunAblupIn``block: bool=False`controller `/ablup/run` 透传;前端 statistics「多环境 GxE」tab 加 `blockEnabled` 复选框 + 互斥 watchblock↔gxe/gxr/spatial+ payload.block + 成功文案/说明三元。
4. **探针** `Temp/claude/e2e_ablup_block_20260805.py` **3 批次落库全过**——[1] 3 区组×5 株已知 σ²block>0 → method/n_blocks/σ²block/block_ratio + EBV 独立矩阵解一致;[2] 单区组 409[3] 无 block_no 409[4] block+gxe/block+spatial 409 互斥;[5] 部分缺 block_no 降级剔除 + note 含剔除数;[6] 全收敛数据无区组归零警告。
**批5-B(N1):孟德尔检验落库 + 自动隔离 + 进数据质量报告**
1. **新表**create_all 自动建):`MendelianCheckModel``bre_mendelian_check`dataset_id/compat_threshold/计数/summary_json/data_version/input_hash/engine_version/note+ 子表 `MendelianCheckTreeModel``bre_mendelian_check_tree`FK check_id CASCADEtree_id/dam_id/sire_id/status/信息位点/兼容/不兼容/rate/flag/reason/incompatible_markers_json);`TreePedigreeExclusionModel``bre_pedigree_exclusion`tree_id 唯一、reason/source_type="mendelian"/source_check_id/created_id)。
2. **服务**`mendelian_check` 纯计算核心抽共享 `_compute_mendelian(dataset_id, compat_threshold)`(GET 预览与 POST 逐字节同源);新 `run_mendelian_check` 计算→落库主表+每树子行→**自动隔离**flag=true 树 upsert `bre_pedigree_exclusion`,本次未 flag 但此前隔离(同 dataset 范围)删除隔离行(注册表=最新检验结论、**可逆**)。
3. **控制器**:新 `POST /bre/genotype_call/mendelian/check/run`Auth `module_bre:genotype_call:edit`,写操作),GET 只读预览保留。
4. **进数据质量报告**`data_quality_report` 加可选 `dataset_id`,提供时追加 `mendelian` 段(最新 `bre_mendelian_check` 计数 + flagged 树列表 + 当前隔离状态);`flagged>0 → summary.has_warning=True`;无检验记录 → `mendelian: None``DataQualityIn``dataset_id` 透传。
5. **系谱消费方断开亲本链**(共享 `_excluded_tree_ids()` 读注册表,树级 dam/sire 置 None + note):`_build_pedigree`genetic_corr/index/type_b/gblup/ssgblup/gwas)、`run_ablup` 内联系谱循环、`inbreeding_depression``kinship_matrix``run_cv``_germplasm_pedigree`(树→种质亲本链)。**GBLUP/ssGBLUP 基因型样本不过滤**(错配是亲本声明非基因型)。
6. **前端**genotype_call 孟德尔对话框主按钮改 POST `mendelianCheckRun`(展示 check_id + 隔离树数 + 新类型);statistics「数据质量」tab 加 dataset 选择器 + mendelian 段(flag 计数 alert + 隔离树表)。
7. **探针** `Temp/claude/e2e_mendelian_persist_20260805.py` **ok=19 fail=0**——[1] 落库(主表行/计数/子表行/check_id);[2] 隔离生效 + EBV 断开(隔离树与声明亲本亲缘=0);[3] 再跑未 flag → 隔离行清除(可逆);[4] data_quality_report(dataset_id) mendelian 段 + has_warning=True、无检验 None[5] run_ablup note 含隔离剔除数、genetic_corr 亲缘=0[6] GET 只读预览 8 断言零回归。
**批5-C(N2):统计引擎全量数值真值校验**`Temp/claude/e2e_stats_numerics_20260805.py`**ok=101 fail=0**):
- **14 个引擎段 + 4 服务端点段全过**:`blup.solve` 普通(独立 V⁻¹ BLUP≡MME + 网格 REML 表面一致)、`_solve_gxe`MME 恒等 + 方差分解)、`_solve_block`MME 恒等 + 区组效应恢复)、`solve_spatial(_aniso)`R 重构 + MME 恒等 + ρ_row/ρ_col 恢复)、`build_g_matrix`(手算 VanRaden method2)、`solve_gblup`MME 恒等 + 可靠性公式)、`_build_h`(教科书 H⁻¹ 含 Christensen 缩放 + 岭)、ssGBLUP MME 恒等 + 非基因型株 EBV≠0、`solve_bivariate`(完全正相关 r_g→1 / 独立 r_g≈0)、`solve_multi`(已知 G0 恢复 + PSD)、`finlay_wilkinson`(独立 OLS)、`ammi`(解析 2×2 SVD)、`solve_rcbd`(手算 SS/MS/F)、`_solve_diallel`(手算 GCA/SCA)、`_proj_simplex`/`_solve_ocs`/`_selection_intensity`、服务端 `run_cluster`UPGMA 首次合并=最小距离对)、`genetic_gain`(ΔG=k·r_g·σ_A 复算)、`data_quality_report`IQR/MAD 手算边界)、`kinship_matrix`3 节点 A 手算)。
- **探针自身两处 fixture 缺陷修复(引擎本体零缺陷)**:① A8.4 独立性状 r_g 假收敛 -0.99 / A9 G0 恢复不可靠——根因是 4 创始人+10 子代低 h²(h²≈0.43)小样本 REML 面平坦/近边界(单性状 ve 塌缩、EM 起点被毒化),**换高遗传力(va=[4,3,2.5]、ve=[0.5,0.4,0.35]h²≈0.87-0.9+ 高真相关(0.95/0.90/0.85+ 10 全同胞家系×3 株(n=54,24 创始人)良态设计** → r_g 恢复误差 ≤0.0611.1s 收敛);② B4.2 硬编码 `tree_id==4`fixture 树真实自增 id 5664 非 4)→ 改 `trees[3]`(值 9.0 精英株)。逐项核实 EM-REML/M-step/固定点/MME/剖面均教科书正确,非引擎 bug 不误报。
- **runtime 约束记录**`solve_multi` 3 性状 n≥100 时每次迭代 MME `solve+inv` 0.7sn=100)超 2 分钟,数值探针 fixture 保持 n≤54。
**验证**
- 三新探针(e2e_ablup_block / e2e_mendelian_persist / e2e_stats_numerics)全过;**27 套件全量回归零回归**(含 e2e_mendelian_check / e2e_trial_design / e2e_trial_design_ext / e2e_gxe / e2e_gxr / e2e_molrigor / e2e_gwas / e2e_mating_kinship / e2e_mating_ebv / e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_gs_family_cv / e2e_batch_selection / e2e_ocs / e2e_mabc / e2e_gaps_base / e2e_gaps_engines / e2e_gaps_modules / e2e_prediction_rigor / e2e_inbreeding_depression / e2e_parent_validation / e2e_advanced_gblup / e2e_corr_spatial)。
- **vue-tsc** EXIT=0(前端 statistics/statistics.ts/genotype_call/index.vue 类型检查通过)。
- **HTTP 核验**(后端重启):`POST /bre/genotype_call/mendelian/check/run``POST /bre/statistics/data-quality`dataset_idmendelian 段、`POST /bre/statistics/ablup/run`block=True / block+gxe 409)、`POST /bre/statistics/ocs`
- **备份镜像** `Temp/claude/backup_block_mendelian_numerics_20260805/`(18 文件按相对路径,收尾补 2 文件 → 20:更新版 `e2e_gaps_engines_20260804.py` + `http_v226.py`)。
- **方法学保留**block 与 gxe/gxr 共用 Z₂ 槽故互斥(同一数据既跨环境又跨区组时用户二选一);孟德尔隔离**可逆**(数据修正/阈值提高再 run 自动解除);N2 探针与既有结构性探针互补(真值段独立 numpy 实现对照,fixture 良态设计避开小样本 REML 退化区)。
**批5 跟进(2026-08-05,收尾)**
- **回归首轮抓 1 处探针陈旧断言(非引擎回归)**:`e2e_gaps_engines_20260804.py:141` 断言 `blup.ENGINE_VERSION == "1.4.0"`,批5 已升 1.5.0 → 改断言 `1.5.0` 复跑通过(与批5 三处 `_DATA_VERSION` 同步同类机械性版本断言更新)。**27 套件全量回归最终全部 exit=0**。
- **HTTP 核验完成**`Temp/claude/http_v226.py`,后端重启后真实端点,**ok=14 fail=0**):`POST /bre/genotype_call/mendelian/check/run` 200check_id + isolated=1);`GET /bre/genotype_call/mendelian/check` 只读预览零回归;`POST /bre/statistics/data-quality`trait+dataset_idmendelian 段 flagged=1 + `summary.has_warning=True``POST /bre/statistics/ablup/run`block=True200 → prediction `method=ABLUP-BLOCK`、model_name 前缀 `ABLUP_BLOCK_`、note 含 `sigma_block/n_blocks=2`block+gxe / block+spatial 均 409Z₂/残差互斥文案);`POST /bre/statistics/ocs` 200contributions 4 条和=2)。fixture 运行后自动清理(bre_mendelian_check/tree/pedigree_exclusion 0 残留)。
- **核验前需换新 token**`dpb_token.txt` 旧 token 过期(401「认证已失效」)→ 经 `POST /system/auth/login`super/123456)刷新(登录在 /system 前缀,不在 /bre)。
### 18.16 批6 规划↔目标↔试验 可追溯性闭环:plan/target/trial 三 FK + trace 端点 + 双删除守卫(2026-08-05v2.27
> 用户全代码库 grep 实证可追溯性缺口成立:`bre_plan` 是**彻底孤立的根表**(零传入外键,`bre_trial` 无 `plan_id`/`target_id`,无 project/program 表)。用户拍板「**加试验挂目标**」最小双链:`bre_target.plan_id` + `bre_trial.plan_id`(双链),另加 `bre_trial.target_id`(试验挂目标)。`_DATA_VERSION` v2.26→**v2.27**`statistics/service.py:97` + `genotype_call/service.py:45`5 处探针版本断言同步:e2e_prediction_rigor:102 / e2e_spatial_sparse:175+229 / e2e_statsflow:174 / e2e_mendelian_persist:207)。
1. **DB**:新 `backend/sql/weld_plan_trace.sql`(幂等 ALTER 三列 + FK,已应用验证):`bre_target.plan_id` FK→`bre_plan``bre_trial.plan_id` FK→`bre_plan``bre_trial.target_id` FK→`bre_target`,均**可空**(历史孤目标/独立试验不受影响,可追溯性渐进式)。
2. **target 三件套**`TargetModel.plan_id` + relationshipschema `plan_id` 透传;get_list outerjoin 解析 `plan_name`create 父校验(plan_id 不存在 → 409None 跳过);delete `assert_no_children`(有 combo 子 → 409)。
3. **trial 三件套**`TrialModel.plan_id`/`target_id` + 双 relationshipschema 双字段透传;get_list 解析 `plan_name`+`target_name`;create 双父校验(不存在 → 409None 跳过);delete `assert_no_children`(有 trial_study 子 → 409)。
4. **plan trace 端点**:新 `trace(plan_id)` 服务方法 + `GET /bre/plan/trace/{id}`——`{plan, targets:[{…,n_combinations,n_trees,combinations:[{…,trees}]}], trials:[{…,target_name,n_trial_studies,n_trees,trial_studies:[{…,trees}]}], totals}`;组合/试验点**软删过滤**;孤目标不入链;不存在计划 409plan.delete `assert_no_children`(有 target/trial 子 → 409)。
5. **前端**target/trial 表单「所属计划/目标」select(`res.data.data ?? []`)+ 表格/详情列;plan 页「追溯」行操作弹窗(ElCollapse 目标链/试验链 + ElTags)。
6. **探针** `Temp/claude/e2e_plan_trace_20260805.py` **17 断言全过**(目标链/试验链/totals/软删过滤/孤目标不入链/三父校验 409/双删除守卫 409/标签解析),自清理(含 bre_target 审计行)。
7. **审计探针根治(本批排查修复)**`e2e_audit_20260805.py` 残留检查原 `entity_id.in_(CREATED_TARGET_IDS)` 未限定 `entity_type`,而 `entity_id` 按实体表各自序列**非全局唯一**`breeding_target_id_seq` 推进到 691 后,target id 与既有 `bre_cross_combination`(669/685)/`bre_germplasm`(675) 审计行撞 id → 间歇误报「仍有残留 id=…」)→ 残留检查限定 `entity_type=='bre_target'`(与 clean() 删除范围一致),连续 5 轮 13/13 稳定。
**验证**:新探针 17/17 + **全量回归零回归**(60 套件,含批5 三探针零变化)+ **vue-tsc** EXIT=0。**HTTP 核验**(后端重启,`Temp/claude/http_v227.py`):`GET /bre/plan/trace/{id}`、target/trial create 带 plan_id/target_id、三父校验 409、双删除守卫 409。**备份镜像** `Temp/claude/backup_plan_trace_20260805/`(按相对路径)。
### 18.17 批7 统计引擎全量十模块 golden 复查·系谱键空间错位修复(2026-08-05v2.28
> 用户质疑「GBLUP/ssGBLUP、genetic_corr、type_b、cluster、stability、OCS、MABC、inbreeding_depression、trial_design、mendelian 这批新建模块还没逐一数值校验(golden-test 缺失)。历史上 G–L 的静默失效都是靠校验才暴露的」。拍板「**全量十项逐一复查**」。复查确认 **8/10 已 golden**GBLUP/ssGBLUP、cluster、stability、OCS、MABC、inbreeding_depression、trial_design、mendelian 既有探针已具严格数值断言),**type_b 与 genetic_corr 补齐 golden 缺口**——审计深处抓到**真 bug 就地修 + 探针加回归**。`_DATA_VERSION` v2.27→**v2.28**`statistics/service.py:97` + `genotype_call/service.py:45` 同步;4 处探针版本断言同步:e2e_spatial_sparse:175+229 / e2e_statsflow:174 / e2e_prediction_rigor:102 / e2e_mendelian_persist:207)。
**根因(THE BUG**:服务层把 **int `tree_id` 表型键** 传给 `mtblup.solve_bivariate`,而 `_build_pedigree` 系谱用 **str `"t{tree_id}"`**`blup.solve` 的鲁棒逻辑(L382-385)把系谱外个体自动并入 base(视作无关 founder)→ **系谱被静默丢弃**。平衡数据(同株跨环境提供协方差)掩盖;**分裂家系数据**(无同株跨环境、全同胞链跨站点桥接)暴露——int 键 → r_B/r_g **锁死 ±0.99**(平剖面端点假收敛、假阴性负相关)。`run_ablup` 正确(L1020 `phenos_keyed={f"t{tid}": v}`),四个 mtblup 消费路径受影响。
**修复**:新增共享 helper `_tree_individual_keys(d)`service.py:163`{tree_id:值}→{"t{tree_id}":值}`)收口四个调用点——`_genetic_corr_matrix`L2214/ `_smith_hazel_index` mtblup 分支(L2754/ `run_genetic_corr`L5122,喂 `solve_multi``solve_bivariate`,类型注解同步改 `dict[str, dict[str, float]]`/ `run_type_b_heredity`L5294)。
**探针** `Temp/claude/e2e_rg_golden_20260805.py` **ok=21 fail=0**——20 founder10 母×10 父)、10 全同胞家系×3 同胞=30 株、3 站点、高遗传力良态设计(VA=4.0/VE=0.5h²≈0.89,与批5-N2 良态设计经验一致);tY 分裂家系(站1=同胞0,1/站2=同胞2/站3=全株,真 r_B=0.8+ tA/tB/tC 平衡(真 r_g AB=0.95、AC=BC=0+ tS1/tS2 分裂家系(真 r_g=0.8):
- [P0 诊断] `solve_bivariate` 直接调用:str 键恢复 r_B=0.7+、**int 键锁死 0.99**RED 实证);
- [P1 type_b golden] 服务端点 r_B(1,2)>0.5 + **n_common=0**(三站无共有树、靠全同胞系谱桥接——系谱生效的直接证据)+ 全正 min>0.3
- [P2 correlation golden] r_g(A,B)>0.65、|r_g(AC/BC)|<0.4、判别间隙>0.3、h²∈(0,1)
- [P2b discriminator] r_g(S1,S2)>0.5(分裂家系无共有树,RED 下锁死 −0.99)。
探针自身缺陷修复:`_simulate` 初版 int 键 vs 观测循环 str 键 KeyError(统一 str 键)、种子扫描键错位(E0/E1/E2 vs E1/E2/E3 查键致 p2 空)、P2 间隙阈值过紧(r_g(B,C)=0.374 高抽样波动,阈值 0.4→0.3 重校准)、死 `_build_ainv` 占位行删除、**exit-code 通道 bug**`return ok==0 and fail==0` 恒假,改 `fail==0`,断言 21/21 本就全过)。
**验证**:新探针 21/21 + `e2e_statsflow`B1/B2,单家系 fixture 对键 bug 不敏感,15 断言零变化)+ `e2e_advanced_mtblup`r_g=0.99/n_common=4/smith-hazel mtblup)回归通过 + **全量回归零回归**batches 13 + final60 套件,含版本断言同步)+ **vue-tsc** EXIT=0。**HTTP 核验**(后端重启,`Temp/claude/http_v228.py`):`POST /statistics/type-b-heredity`(分裂家系 r_B(1,2)>0.5 + n_common=0 + data_version=v2.28)、`POST /statistics/genetic-corr/run`tS1,tS2 分裂家系 r_g>0.5 + 平衡 tA,tB r_g>0.65)。**备份镜像** `Temp/claude/backup_keyspace_20260805/`(按相对路径)。**方法学保留**:四个 mtblup 消费路径统一 str 键对齐系谱;探针 fixture 高遗传力 + 分裂家系结构保证判别力;`run_ablup` 正确路径不受影响。
### 18.18 回归基建:run_regression.py 统一回归 + 高风险模块正式 tc 套件(ssGBLUP/OCS/MABC/孟德尔)(2026-08-05,测试基建,不 bump 版本)
> 用户对批7 提出三点质疑,逐项核实**全部成立**,拍板「**两者都要**」——先建统一回归脚本把所有探针纳入(立即止血),再抽正式 tc 套件。纯测试基建,**无后端代码改动**,`_DATA_VERSION` 保持 v2.28
>
> 1. 全库 `test_bre_*_tc.py`08-03)只覆盖「数据建链/导入导出/多波次」,对 GBLUP/ssGBLUP、OCS、MABC、近交衰退、试验设计、孟德尔检验这些新建分析模块**零命中**full_tc 的 correlation 只是 GET 200 冒烟);
> 2. 19:55 改动(批7)未补 golden 测试——批7 探针建在 Temp/claude 一次性目录、无统一回归脚本;
> 3. 风险:新模块若算偏(ssGBLUP 的 H⁻¹ 拼接、OCS 投影梯度收敛)会当「正常结果」输出——正是当年 G/I 静默失效的同款隐患(int-key bug 即活证据)。
**统一回归脚本 `run_regression.py`**(仓库根):`glob Temp/claude/e2e_*.py`(排除 `e2e_probe*` 探查工具)+ `backend/scripts/test_bre_analysis_*_tc.py` = **63 测试**;**顺序串跑不并发**(历史 RC=124 机器争用超时前科);每测试独立子进程(`cwd=os.path.dirname(p)`、timeout=1800s)完整输出写 `Temp/claude/regression_logs/<name>.log`,控制台回显尾部 + EXIT`EXIT` 汇总任一失败整体 exit≠0(供交付流程判断);`DPB_PYTHON` 环境变量覆盖解释器(须 dpb env python,基础 miniconda 缺 PEP 695 generics SyntaxError);`sys.stdout.reconfigure(encoding="utf-8")` 防 GBK 崩溃;过滤器 `python run_regression.py gwas ocs``--keep-logs` 保留日志。**验证**:全量 58/59 通过,唯一失败 gaps_engines 批量卡死(10 分钟无输出)单跑 RC=0 确认通过——机器争用非探针问题。
**4 个正式 tc 套件**`backend/scripts/`TestClient 走真实 API + lifespanURL 带 `/api/v1/bre/...` 前缀,登录 super/123456 form)——高风险模块必测,fixture 自带清理:
- `test_bre_analysis_ssgblup_tc.py` **ok=14 fail=0**GBLUP vs ssGBLUP 同 fixture5 株表型 + 基因型数据集:树0/1/3 直连、树2 名称兜底、树4 全多等位无有效剂量)。**H⁻¹ 拼接判别核心**——非基因型株(树4GBLUP EBV=0 / ssGBLUP EBV≠0(若 H⁻¹=A⁻¹+[0;G⁻¹−A22⁻¹] 拼接错,非基因型亲属 EBV 为 0 或爆炸);h²∈(0,1)、5 条 EBV、全部有限。
- `test_bre_analysis_ocs_tc.py` **ok=23 fail=0**8 种质(F1/F2/F3/D/E + A/B 全同胞 + C 半同胞)EBV 全 direct。Σc=3/c≥0/coverage direct 5/最高贡献 A≈1.419、vs_top_n mean_ebv 9.7667/avg_kinship 0.5556/c'Ac≈4.641、λ↑→avg_kinship 单调非增 [1.0,0.5157,0.3211,0.2685]、λ=0 满额投 A、kinship_status=partial+告警 D/E、n_select>候选/空候选→**409**、λ<0→**422**schema 层 Pydantic ge=0 拦截)。
- `test_bre_analysis_mabc_tc.py` **ok=24 fail=0**:轮回亲本 + 6 候选(C6 童期)、前景 F1/F2 + 背景 M1-M4。前景命中/背景恢复率 100/75/0 复算、回交建议(晋级 BC2/再回交/维持)降序、童期 C6 晋级、轮回亲本无基因型 warning、target 越界→**422**le=100 schema 校验)、其余 409。
- `test_bre_analysis_mendelian_tc.py` **ok=9 fail=0**P1/P2 全 0/1→T1、P3/P4 全 0/0→T25 标记)。POST `/bre/genotype_call/mendelian/check/run`**下划线** `genotype_call`,非连字符)落库 + T2 flag 进隔离注册表 `bre_pedigree_exclusion`source=mendelian/source_check_id+ 阈值 0.0 重跑可逆(隔离行清除)+ GET 只读预览零回归;data_version=v2.28 落库。
**tc 套件关键教训**(写进探针防再犯):
- **HTTP 语义差异**schema 层 Pydantic 校验(ge/le 约束)拦截 → **422**;服务层 CustomException → **409**e2e 直调只见 409tc 走 HTTP 见 422)——断言错误码须按路径定;
- **Mapper 注册**`PlantingModel` 等 relationship 引用 `UserModel`tc 套件必须显式 `from app.api.v1.module_system.user.model import UserModel` 注册,否则 SQLAlchemy `InvalidRequestError: expression 'UserModel' failed to locate a name`
- **时序验证**:孟德尔 tc 的隔离注册表断言必须在 run1 落库后、run2(阈值 0.0 清除)**之前**验证,否则必然 n=0 假失败;
- **启动残留预清理**`_wipe()` 按前缀清残留(防上次进程被杀/建 fixture 中途失败留下 `uq_bre_trait_code` 等唯一键脏数据),套件可重复跑。
**验证**4 个 tc 套件 EXIT=014/23/24/9+ 全量回归 58/59gaps_engines 单跑确认)。**备份镜像** `Temp/claude/backup_test_rigor_20260805/`root/run_regression.py + backend/scripts 4 tc 套件)。**交付流程**:凡改动统计引擎/业务链后端代码,跑 `python run_regression.py`(dpb env 解释器)全量回归 EXIT=0 后方可交付;新 tc 套件命名 `test_bre_analysis_<模块>_tc.py` 由驱动自动纳入。
### 18.19 回归基建 2:分析模块 tc 补齐(5 套)+ pytest 接入 + 本机 CI stage2026-08-05,测试基建,不 bump 版本)
> 用户对 §18.18 的 4 套 tc 认可后,继续补齐 5 个静默失效风险较低但属相关性/回归/生成器类的分析模块(genetic_corr / type_b_heredity / inbreeding_depression / trial_design / run_stability),并把 v8 验收标准定为「**CI 跑通 pytest 全绿**」。两条硬约束:① **基于真实 PostgreSQL 16 + Redis**(工程无 SQLitetc 全部在真实 PG+Redis 实跑);② **不做 GitHub Actions / 不登录 GitHub**(全工程无 git 仓库,GitHub Actions 云端本机用不上)——CI stage 落地为本机驱动脚本 `run_ci.py`。纯测试基建,无后端代码改动,`_DATA_VERSION` 保持 v2.28。
**补齐 5 套 tc**`backend/scripts/`TestClient 真实 API + `-X utf8` + `_wipe()` 残留预清理 + 自带清理):
- `test_bre_analysis_genetic_corr_tc.py` **ok=19**:平衡 3 性状(VA=4/VE=0.5,真 r_g AB=0.95/AC=BC=0h²≈0.89)——matrix_json 对角 1/对称/r_g(AB)>0.65/|r_g(AC,BC)|<0.4/判别间隙>0.3/h²∈(0,1)**分裂家系判别** tS1(测同胞 0/1+tS2(测同胞 2):r_g(S1,S2)>0.5 且 **n_common=0**(无共有树,全同胞系谱桥接生效;**rng 消耗序敏感性**——S1/S2 用独立种子 `SEED_S=3`(扫描 0-39 验证 r≈0.99)解耦自探针 tY-first 顺序);409×3。
- `test_bre_analysis_type_b_tc.py` **ok=18**:3 站点分裂家系(站1=同胞0/1×20 株/站2=同胞2×10/站3=全株×30):3 环境 envs_json 20/10/30、r_B(1,2)/r_B(1,3)/r_B(2,3)>0.5、min>0.3、**n_common=0****复刻探针 tY-first rng 消耗序 → r=0.990**409×3(坏 trait/env_dim/method)。
- `test_bre_analysis_inbreeding_tc.py` **ok=44**12 树(6×F=0 + 6 自交 dam==sire F=0.5),y=10060F+ε → slope<40/t<3/r²>0.9/has_depression=true/高 F 前 6 自交株;无衰退 slope≈0 未检出;**方向感知** asc 病指 y=10+40F slope>30(上升=指数型);deep 系谱 GP→G7/G8→H 树 F=0.125mean_F≈0.0625);min_n=20 insufficient"12 棵"/"≥20")不 409409+422。
- `test_bre_analysis_trial_design_tc.py` **ok=25**:增广 12 条目(9 新品系+3 对照)——新品系 3 区组×3 条不重复、**对照 block_no=None 不落库**check_reps=3);α-格子平方 v=9 k=3 r=4(λ≤1、每 rep 可分解、warn=False/ 部分 r=3 仍平衡 / v=16 k=4 非素数 warn=True / 一般 v=12 贪心(r 缺省=s=4);**block_no=rep*100+block 复合编码 DB 读回**TestClient 退出后单一 asyncio.run 防嵌套 loop);409×4**教训**:α-格子 r=4 会 case() 整表覆写 block_no——部分 r=3 重跑须在 r=4 **之前**,否则 DB 读回是部分态。
- `test_bre_analysis_stability_tc.py` **ok=16**3 组合×3 站点 cell means C0=[0,6,12]/C1=[2,5,8]/C2=[4,4,4] → FW b≈2.0/1.0/0.0、flag_stable C1=True 其余 False|b1|≤2se)、r²≈1(常量响应基因型 r²=None 合法);AMMI n=9、rank 按 ASV 升序、IPC1 占比 1.0≥IPC2、ss_interaction=36>0engine_version 落库断言;year 维度 + 409×2(坏 methods/gxe_env)。
**pytest 包装层 `backend/tests/test_stat_analysis_tc.py`**9 套 tc 各一个 pytest 测试(`@pytest.mark.pg` + parametrize),subprocess 顺序串跑真实脚本(镜像 run_regression 契约:`DPB_PYTHON` 覆盖、`-X utf8`、timeout=1800)。**环境控制关键**——包装层不 import 任何 app 模块(防 conftest sqlite 污染);subprocess env 显式构建:剥掉 conftest 注入的 `DATABASE_TYPE/DATABASE_NAME/POOL_SIZE/MAX_OVERFLOW/CAPTCHA_ENABLE`,置 `ENVIRONMENT=dev`/`DATABASE_TYPE=postgres`/`PYTHONPATH=backend`/`PYTHONUTF8=1`,再并入从 `backend/env/.env.dev` 解析的真实连接值(`TC_CI_*` 可覆盖验证 skipif 路径)。**skipif 探测**asyncpg 连 PG + redis.asyncio ping**`protocol=2` 必须显式**——redis-py 7.x 默认 RESP3,本机 WSL redis-server 版本较老 `hello``ResponseError`,与 `app.core.database.redis_connect``Redis.from_url(...protocol=2)`)对齐即通;任一失败 `pytest.skip``pyproject.toml` 注册 `pg` marker(消 PytestUnknownMarkWarning);`conftest.py``collect_ignore_glob=["../scripts/test_*.py"]` 防收集 import 独立脚本污染 sqlite 环境。
**本机 CI stage `run_ci.py`**(仓库根):step 0 探测真实 PG16+Redisasyncpg + redis.asyncio protocol=2,失败给明确指引并 exit≠0);step 1 `pytest -m pg`dpb python + `-X utf8`cwd=backend)跑 9 套;step 2 汇总 EXIT=0 →「✅ CI 全绿」;日志写 `Temp/claude/ci_logs/`。与 run_regression 并存(run_regression=手动全量回归 / run_ci=验收门)。
**验证**5 套逐个 EXIT=019+18+44+25+16=**122 断言**);`pytest -m pg` **9 passed**(真实 PG+Redis146s,含既有 4 套零回归);skipif 路径(`TC_CI_DB_PORT=1` 指错端口)**9 skipped** 不红、无 unknown-marker 警告、scripts 未被收集(88 collected/79 deselected/9 pg);`run_ci.py` **EXIT=0「CI 全绿」**`run_regression.py test_bre_analysis` glob 自动纳入 9 套。**备份镜像** `Temp/claude/backup_analysis_tc2_20260805/`。**交付流程**v8 验收 = `python run_ci.py` EXIT=0(或 `cd backend && pytest -m pg` 全绿);改动统计引擎/业务链后端仍跑 `python run_regression.py` 全量。
### 18.20 O2–O4 统计方法学广度:幼年–成年遗传相关 + 非线性基因组预测 + 约束选择指数(2026-08-05v2.29
> 用户系统核对统计引擎能力后确认三项 **P2 方法学缺口**(均零命中、不影响当前业务正确性,属统计方法库广度),拍板「O2–O4 先落地」+ 两项决策:① O4 用经典 KempthorneNordskog **=0 闭式解**(纯 numpy 不迭代);② 前后端同步扩展。方法学扩展 → `_DATA_VERSION` v2.28 → **v2.29**、`genomic.ENGINE_VERSION` 1.3.0 → **1.4.0**。**无新表**O2 复用 `bre_type_b_result`env_dim 自由字段)、O3 复用 `bre_prediction`/`bre_prediction_value`method 标签扩展)、O4 复用 `bre_selection_index`result_json 已含 extra)。
**O2 幼年–成年遗传相关(env_dim="stage"**`_values_by_tree_env`service.py:324)加 stage 分支——`coalesce(obs.stage, TraitModel.stage)` 分组(观测缺省继承 `bre_trait.stage`)、group_by 含 coalesce 表达式、同树同阶段多次观测取均值;`run_type_b_heredity` env_dim 校验扩 `("site","year","stage")`。发育阶段当"环境"→ 逐对 `mtblup.solve_bivariate` REML 精确估幼-成遗传相关 r_g(>0.5 表示童期可借力成株、早期间接选择有效)。前端 Type-B 页签 env_dim 下拉加「stage=发育阶段(幼/成)」。
**O3 非线性基因组预测(genomic 1.4.0**
- `solve_rrblup`service 5774 分派):**岭回归逐标记** y=μ+Xu+eu=(Xc'Xc+λI)⁻¹Xc'yc,λ 由剖面 REML σa²/σe² 定(σu²=σa²/c、c=2Σp(1-p)),EBV=Xc·u+μ —— **与 GBLUP 数学对偶**G=XcXc'/c 时闭式解 ĝ=G(G+λa·I)⁻¹yc+μ 逐位吻合,探针 1.42e-13);输出 marker effectsGBLUP 无的解释能力)+ PEV 可靠性近似。
- `solve_bayesb`**BayesB Gibbs 可变选择**——δ_j~Bernoulli(1−π)+方差尺度混合、σ²j~inv-χ²(df_s+1,(df_s·scale0+u_j²)/(df_s+1))、σe²~inv-χ²(df_e+m,...)**`numpy.random.default_rng(seed)` 确定性**MLOps 铁律:同 seed 两次 EBV 逐位一致);π 默认 0.95、稀疏 QTL 场景取 0.7 更贴合 30% QTL 真值。
- `kfold_cv_genomic` 加 dosage/markers 分派:rrblup/bayesb 折内走对应求解器(**实证 CV**);`run_cv` GS 分支透传 seed + genotypes + markersmethod_name=KFCV/RRBLUP·KFCV/BayesB。
- `run_gblup` method 扩 `("gblup","ssgblup","rrblup","bayesb")` + seed 透传,rrblup/bayesb 从 `_gather_gblup_inputs` dosage 构 X → `asyncio.to_thread` 引擎,落 `PredictionModel(method=RRBLUP/BayesB)` + `PredictionValueModel`EBV/rel/pa/rank)、engine_version=1.4.0。前端 GBLUP/CV 页签 method radio 加 RRBLUP/BayesB + seed 输入。
**O4 约束选择指数(restricted 闭式解 + economic weights**
- `_smith_hazel_index``restricted_traits`/`economic_weights`。受限时 **Kempthorne-Nordskog Lagrange 闭式投影**:C(第 j 行=第 j 个受限性状单位向量)、**M = C'(C·G·P⁻¹·G·C')⁻¹·C·G·P⁻¹·G**、b = P⁻¹·G·(IM)·a → 约束 C·G·b=0 ⇔ **受限性状 ΔG=0**(纯 numpy pinv,不迭代)。**对照旧公式 M=C'(C·P⁻¹·C')⁻¹·C·P⁻¹ 实测 ΔG=4.46 不满足 → 修正必要**e2e O4-1c 断言锁定)。
- economic_weights 直接作 a(绝对尺度、**不归一化**统计权重、未列性状按 0 不进聚合基因型),可与 restricted 叠加;`direction=asc` 仍翻转 a[i](b=P⁻¹Ga 线性于 a → 保证该性状 b 相对下降,(P⁻¹G)₀₀>0 保号,非必 sign flip——tc 断言用严格下降)。
- extra 落 `restricted`/`constraint_mode=ΔG=0`/`economic` + warningsmethod 校验扩 `("zsum","smith_hazel","restricted")`、缺 restricted_traits 409、restricted_traits ⊆ cols(越界 409)、economic_weights 性状 ⊆ tmap。落库 method=SI_RES。前端指数页 method radio 加 restricted + restricted_traits 多选 + 每性状经济权重输入。
**顺手修复(tc 暴露的既有缺口)**`cv_detail` 折明细 dict 缺 `cv_result_id`(CvFoldOut 必填字段)→ 任意 GET /cv/{id} **400**(既有 tc 均未触达该端点,静默失效风险同款);补 `"cv_result_id": cv_id` 后 rrblup/bayesb CV 详情可查。
**验证**`e2e_o234_20260805.py` 探针 19 断言(O3 对偶逐位 1.42e-13 + marker effects + BayesB 可复现 + kfold 5 折;O4 受限 ΔG=0 机器精度 + 旧公式失败 + economic asc 翻转;O2 真实 PG 16 树 r_g=0.6145);正式 tc `test_bre_analysis_o234_tc.py` **ok=41 fail=0**TestClient 真实 API + goldenO2 env_dim=stage r_g=0.8995/n_common=12/双阶段 12 株/data_version=v2.29O3 落库 method+engine_version 1.4.0/bayesb 同 seed 两次逐位一致/rrblup·GBLUP EBV 相关 1.000/CV 折数=5/非法 method 409O4 restricted b_受限=0.0/economic desc>0·asc<0/缺 restricted_traits 409+ TC_SCRIPTS 注册第 10 套 + **全量回归零回归**61 e2e + 10 tc+ `run_ci.py` EXIT=0「CI 全绿」。备份镜像 `Temp/claude/backup_o234_20260805/`
## 十、文件清单与备份
### 新增/修改文件(2026-08-03
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | G×E 引擎 + 异步任务 + 门禁(含 `blup.solve` 传参) |
| `backend/app/api/v1/module_bre/statistics/model.py` | `StatisticsJobModel`job_type/status/error_msg/result_ref |
| `Temp/claude/e2e_gxe_20260803.py` | G×E e2e 探针(5 场景) |
### 新增/修改文件(2026-08-04
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_trait_direction.sql` | 幂等 ALTER 三列 |
| `backend/sql/bre_trait_seed.sql` | 种子数据含三新列(43 行) |
| `backend/app/api/v1/module_bre/trait/model.py` / `schema.py` / `service.py` | 三字段透传 + 批量导入导出兼容 |
| `backend/app/api/v1/module_bre/statistics/service.py` | 方向翻转 + into_ebv 剔除 + default_h2 兜底 + 排行/对比方向修复 |
| `backend/app/api/v1/module_bre/statistics/controller.py` | `selection_only` query 参数 |
| `frontend/web/src/api/module_bre/statistics.ts` | `listTraits` 带 selection_only |
| `frontend/web/src/views/module_bre/statistics/index.vue` | selTraits 解耦 + asc 角标 |
| `frontend/web/src/views/module_bre/trait/index.vue` | 三字段表单/表格/详情/搜索 |
| `frontend/web/src/views/module_bre/selection_rule/index.vue` | 规则 JSON 说明 |
| `Temp/claude/e2e_direction_20260804.py` | 方向标注 e2e 探针(7 组) |
### 新增/修改文件(2026-08-04 无性系级指数)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/schema.py` | `SelectionIndexIn.aggregate`clone 默认 / tree+ 文件头补 UTF-8 编码声明 |
| `backend/app/api/v1/module_bre/statistics/controller.py` | selection_index 透传 `data.aggregate` |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_clone_units` 可靠加权聚合 + 自株退化;zsum/Smith-Hazel 改单元 key 排名;`apply_selection` 按遗传实体写(clone_id + 溯源株 + 系内N株)+ 幂等晋升建 clone |
| `frontend/web/src/api/module_bre/statistics.ts` | `selectionIndex` data 加 `aggregate` |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 聚合粒度 radio + clone 结果列 |
| `Temp/claude/e2e_clone_index_20260804.py` | 无性系级指数 e2e 探针(6 组) |
### 新增/修改文件(2026-08-04 配合力交配设计)
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_combining_design.sql` | 幂等 ALTER`bre_cross_combination` / `bre_combining_ability``design_type` |
| `backend/app/api/v1/module_bre/cross_combination/model.py` / `schema.py` / `service.py` | `design_type` 字段 + create/update 校验归一化 + 导出/导入/模板兼容 |
| `backend/scripts/breeding_stats/combining.py` | `solve(rows, design_type)` 按设计分支:双列 model A / line_tester+NCIII model B(双因素、顺序 ANOVA、角色重叠/NCIII 门禁、gca_se |
| `backend/app/api/v1/module_bre/statistics/controller.py` / `schema.py` / `service.py` | `run_combining` 透传 design_type + 按设计过滤 + 落库 + `anova.gca_se` |
| `frontend/web/src/api/module_bre/statistics.ts` / `cross_combination.ts` | design_type 类型透传 |
| `frontend/web/src/views/module_bre/statistics/index.vue` / `cross_combination/index.vue` | 运行对话框设计选择 + 结果分显示 + CRUD 四处支持 |
| `Temp/claude/e2e_combining_design_20260804.py` | 配合力交配设计 e2e 探针(5 组) |
### 新增/修改文件(2026-08-04 统计严谨·预测完整性与 MLOps 复现性)
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_prediction_rigor.sql` | 幂等 ALTER`bre_prediction_value.pa` + `bre_prediction.data_version/input_hash/engine_version` |
| `backend/sql/weld_rootstock.sql` | 幂等 ALTER`bre_rootstock.dwarf_class/compatibility` |
| `backend/app/api/v1/module_bre/statistics/model.py` / `schema.py` | `pa`/`data_version`/`input_hash`/`engine_version` 字段 + OutSchema 透出 |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_DATA_VERSION="v2.7"`;PA 落库 + 批次真 PA;输入哈希(确定性序列化);germplasm_id 回填;Calo 相关校正(`rel_by_trait` + `g_corr`/`g_note`);`covariate="competition"`Chebyshev 邻域 + G×E 泛化 + 无坐标报错) |
| `backend/scripts/breeding_stats/blup.py` | `ENGINE_VERSION="1.0.0"` |
| `backend/app/api/v1/module_bre/rootstock/model.py` / `schema.py` / `service.py` | `dwarf_class`/`compatibility` 字段 + 导入导出/模板下拉 |
| `frontend/web/src/api/module_bre/statistics.ts` | 指数批次表/EBV 行类型加 `germplasm_id`/`pa` |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 批次表新列 + 协变量 radio(无/crop_load/competition |
| `frontend/web/src/api/module_bre/rootstock.ts` | Rootstock 类型加两字段 |
| `frontend/web/src/views/module_bre/rootstock/index.vue` | 两字段全量(常量/搜索/表格/详情/表单) |
| `Temp/claude/e2e_prediction_rigor_20260804.py` | ②③④ e2e 探针(4 组) |
| `Temp/claude/e2e_rootstock_20260804.py` | ⑤ e2e 探针 |
| `Temp/claude/e2e_corr_spatial_20260804.py` | ①⑥ e2e 探针(3 组) |
| `backend/sql/weld_combination_funnel.sql` | 幂等建 `v_combination_funnel`(六级聚合普通 VIEW |
| `backend/app/api/v1/module_bre/statistics/service.py` / `controller.py` | `combination_funnel()` 查视图 + `GET /statistics/combination-funnel` |
| `Temp/claude/e2e_combination_funnel_20260804.py` | 组合得失漏斗 e2e 探针(3 组) |
### 新增/修改文件(2026-08-04 分子育种建数据能力)
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_molecular.sql` | 幂等补 `bre_genotype_sample.sample_name` + (dataset_id, sample_name) 索引 |
| `backend/sql/bre_menu.sql` | 900210-900213 切真实页面 + F 段按钮 900700-900799 + 角色关联 |
| `backend/app/api/v1/module_bre/marker/` | 五件套(marker_name UNIQUE 校验、CRUD/导入导出/模板) |
| `backend/app/api/v1/module_bre/genotype_dataset/` | 五件套(v1.4 规划表首次建服务) |
| `backend/app/api/v1/module_bre/genotype_sample/` | 五件套(dataset FK 校验 + dataset_name 透出) |
| `backend/app/api/v1/module_bre/genotype_call/` | 五件套 + `import_vcf` + `fingerprint_check` 两个专属端点 |
| `backend/app/api/v1/module_bre/__init__.py` | 注册 4 组路由 |
| `frontend/web/src/api/module_bre/marker.ts` | MarkerAPI |
| `frontend/web/src/api/module_bre/genotype_dataset.ts` | GenotypingDatasetAPI |
| `frontend/web/src/api/module_bre/genotype_sample.ts` | GenotypeSampleAPI |
| `frontend/web/src/api/module_bre/genotype_call.ts` | GenotypeCallAPI + VCF/指纹接口与结果类型 |
| `frontend/web/src/views/module_bre/marker/index.vue` | 标记 CRUD 页 |
| `frontend/web/src/views/module_bre/genotype_dataset/index.vue` | 数据集 CRUD 页 |
| `frontend/web/src/views/module_bre/genotype_sample/index.vue` | 样本 CRUD 页(dataset 下拉) |
| `frontend/web/src/views/module_bre/genotype_call/index.vue` | 分型 CRUD 页 + 导入 VCF / 指纹检测对话框 |
| `Temp/claude/e2e_molecular_20260804.py` | 分子育种 e2e 探针(CRUD/唯一键/父级/指纹/VCF/幂等) |
### 新增/修改文件(2026-08-04 精修项四连发:DUS 数据能力 + stage 感知 + k-fold CV + 公平性报告)
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_refine.sql` | 幂等 ALTER`bre_prediction.stage varchar(16)` + COMMENT |
| `backend/sql/bre_dus_seed.sql` | UPOV TG/53 桃描述符 15 条种子(trait_code LEFT JOIN 解析 trait_idON CONFLICT DO NOTHING |
| `backend/sql/bre_menu_refine.sql` | 900230 切真实页 + G 段按钮 900800-900808 + 角色关联 |
| `backend/app/api/v1/module_bre/dus/` | 五件套 ×3 资源(descriptor 9 端点含导入导出模板 / test 9 / observation 6),注册 `/bre/dus_test/*` |
| `backend/app/api/v1/module_bre/statistics/model.py` | `PredictionModel.stage` + `CvResultModel` + `CvFoldModel`create_all 建表) |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `PredictionOut.stage` + `CvRunIn/CvResultOut/CvFoldOut` + `SelectionIndexIn/DecisionPreviewIn.stage` |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_trait_meta_map` 取 stage`run_ablup` 落 stage`run_cv/list_cv/cv_detail``fairness_report``selection_index/decision_preview` stage 过滤 + `stage_warning`/`skipped_stage` |
| `backend/app/api/v1/module_bre/statistics/controller.py` | `/statistics/cv/run` `/statistics/cv` `/statistics/cv/{id}` `/statistics/fairness` + 指数/决策 stage 透传 |
| `backend/scripts/breeding_stats/blup.py` | `kfold_cv`:sire 家系分层留出 + 逐折 try/except + 留出 EBV 系谱预测 |
| `frontend/web/src/api/module_bre/dus.ts` | 三组 API + 类型 |
| `frontend/web/src/api/module_bre/statistics.ts` | `runCv/listCv/cvDetail/fairnessReport` + `listTraits` 补 stage |
| `frontend/web/src/views/module_bre/dus/index.vue` | 单页三 tab(描述符模板/DUS 测试/观测录入) |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 「交叉验证」「公平性报告」双 tab + 指数/决策 stage 三态 + `stage_warning` ElAlert |
| `Temp/claude/e2e_refine_20260804.py` | 精修项四连发 e2e 探针(4 组,ABLUP/GXE CV + 2 site 公平性) |
### 新增/修改文件(2026-08-04 六项能力完善:MT-BLUP + GBLUP/ssGBLUP + DUS 特异性 + AMMI/FW 稳定性 + MLOps 重训 + stage 拆分)
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_advanced.sql` | 幂等 ALTER`bre_prediction.is_active` + `bre_trait_observation.stage` + `bre_dus_test.analysis_json`jsonb+ COMMENT |
| `backend/app/api/v1/module_bre/statistics/model.py` | `PredictionModel.is_active` + `GeneticCorrResultModel` + `StabilityResultModel`create_all 建 2 新表) |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `GeneticCorrIn/GeneticCorrResultOut/StabilityRunIn/StabilityResultOut/GblupRunIn` + `SelectionIndexIn.g_method` + `RunStatsIn.stage` + `PredictionOut.is_active/stage` |
| `backend/app/api/v1/module_bre/statistics/service.py` | `run_genetic_corr/list/detail``run_stability/list/detail``run_gblup/list_genotyping_datasets``model_drift/retrain/activate``run_ablup(stage)``_gather_digest_inputs``_smith_hazel_index(g_method)`;修复未定义 `tid`、retrain 不激活新批次 |
| `backend/app/api/v1/module_bre/statistics/controller.py` | 6 组新端点(genetic-corr×3 / stability×3 / gblup×2 / model drift·retrain·activate×3+ 透传 g_method/stage |
| `backend/app/api/v1/module_bre/dus/service.py` | `distinctness` 求解器 + `test_distinctness`/`distinctness_report`(落 analysis_json + conclusion 自动建议) |
| `backend/app/api/v1/module_bre/dus/controller.py` / `schema.py` | `POST/GET /bre/dus_test/distinctness/{test_id}` + `DusTestOutSchema.analysis_json` |
| `backend/app/api/v1/module_bre/trait_observation/model.py` / `schema.py` / `service.py` | `stage` 字段(model 列 + create/update/out schema 透传 + 导入/导出映射,schema 暴露为收尾补丁) |
| `backend/scripts/breeding_stats/mtblup.py` | `solve_bivariate`(成对双性状 REMLENGINE_VERSION=1.0.0 |
| `backend/scripts/breeding_stats/genomic.py` | `build_g_matrix`/`solve_gblup`/`solve_ssgblup`ENGINE_VERSION=1.0.0;修复 V 块用 H 协方差) |
| `backend/scripts/breeding_stats/stability.py` | `finlay_wilkinson`/`ammi`ENGINE_VERSION=1.0.0;修复完美拟合 flag_stable |
| `backend/scripts/breeding_stats/fdist.py` | `f_icdf`(二分反解)+ `t_crit` |
| `backend/scripts/breeding_stats/blup.py` | `ENGINE_VERSION="1.1.0"` |
| `frontend/web/src/api/module_bre/statistics.ts` | 三 tab 组 API + modelDrift/Retrain/Activate + g_method/stage 类型 |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 「遗传相关 MT-BLUP」「稳定性 AMMI/FW」「基因组选择 GBLUP」三 tab + stage 三态 + g 矩阵来源 radio + 当前版本标签/漂移/重训/回滚按钮 |
| `frontend/web/src/views/module_bre/dus/index.vue` | 测试行「特异性判定」对话框 |
| `frontend/web/src/api/module_bre/tree_evaluation.ts` / `views/module_bre/tree_evaluation/index.vue` | 观测表单「观测阶段」下拉(juvenile/evaluation,写入每条观测 stage |
| `Temp/claude/e2e_advanced_stability.py` / `stage.py` / `mtblup.py` / `gblup.py` / `dus.py` / `mlops.py` | 6 组 e2e 探针(运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.10 版本行 + §8.18 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.10.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十一 六项能力完善 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑨ + EBV/分子行更新 |
### 新增/修改文件(2026-08-04 田间试验精度补强:砧木×接穗随机互作 G×R)
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/blup.py` | `_solve_gxe``factor_label/factor_name` 参数(仅喂警告文案,默认保 G×E 不变)+ 公开 `solve()` 透传 + ENGINE_VERSION 1.2.0 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `RunStatsIn.gxr` |
| `backend/app/api/v1/module_bre/statistics/controller.py` | run_ablup 透传 gxr |
| `backend/app/api/v1/module_bre/statistics/service.py` | `run_ablup(gxr)`:互斥门禁 + job_type=GXR + `elif gxr:` 分支(rootstock 剥离/门禁三件套/GXRBLUP/note σ²gxr+ 克隆坍缩系谱上移共享 + `_DATA_VERSION` v2.10 |
| `frontend/web/src/api/module_bre/statistics.ts` | `RunStatsPayload.gxr` |
| `frontend/web/src/views/module_bre/statistics/index.vue` | G×R 复选框 + 互斥 watcher + fmtGxeNote σ²gxr 分支 + 批次表 v-if |
| `Temp/claude/e2e_gxr_20260804.py` | e2e 探针(4 组断言,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.11 版本行 + §8.19 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.11.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十二 G×R 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑩ + EBV/田间试验精度行补 G×R |
### 新增/修改文件(2026-08-04 基因组选择实证严谨性:GS 专用 k-fold CV
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/genomic.py` | 抽取 `_build_h`(缺失基因型补 base+ 新增 `kfold_cv_genomic`(掩蔽留出 pearson/RMSE,输出对齐 blup.kfold_cv+ ENGINE_VERSION 1.1.0 |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_gather_gblup_inputs` 提取(run_gblup↔GS CV 复用);`run_cv``dataset_id/method/maf_min` + GS 分支(与 gxe/ABLUP 互斥)+ engine_version 按分支 + `_DATA_VERSION` v2.11 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `CvRunIn.dataset_id/method/maf_min` |
| `backend/app/api/v1/module_bre/statistics/controller.py` | run_cv 透传三参 |
| `frontend/web/src/api/module_bre/statistics.ts` | `CvRunPayload.dataset_id/method/maf_min` |
| `frontend/web/src/views/module_bre/statistics/index.vue` | CV tab mode radioABLUP/GS+ dataset/method/MAF + 隐藏 G×E + submitCv 按 mode |
| `Temp/claude/e2e_gblup_cv_20260804.py` | GS CV e2e 探针(3 组:GBLUP/ssGBLUP 正例 + 门禁,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.12 版本行 + §8.20 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.12.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十三 GS k-fold 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑪ + EBV/GS 行补「GS k-fold 实证验证」 |
### 新增/修改文件(2026-08-04 现代桃育种领域覆盖:S-allele + 抗病/需冷量性状)
| 文件 | 说明 |
|---|---|
| `backend/sql/bre_disease_chilling_traits.sql` | 5 条 numeric trait 种子(3 抗病 0-5 级病情指数 + 需冷量 h + 需热量 GDDinto_ebv=1、direction=asc,幂等 ON CONFLICT |
| `backend/app/api/v1/module_bre/germplasm/model.py` | `s_alleles` 列(String(32)Sf=自交亲和型) |
| `backend/app/api/v1/module_bre/germplasm/schema.py` | Create/Update 加 `s_alleles`Out 继承 Create |
| `backend/app/api/v1/module_bre/cross_combination/schema.py` | `CrossCombinationOutSchema.s_compat`(可选派生字段) |
| `backend/app/api/v1/module_bre/cross_combination/service.py` | `_parse_s_alleles`/`_s_compat_check`/`_check_s_compat` + create/update 校验(Sf 放行、共享 2→409、共享 1→半兼容警示) |
| `frontend/web/src/api/module_bre/germplasm.ts` | `GermplasmForm/GermplasmTable.s_alleles?` |
| `frontend/web/src/views/module_bre/germplasm/index.vue` | 表单加 S-等位基因输入 + 导出列 |
| `frontend/web/src/views/module_bre/cross_combination/index.vue` | 包装 createApi/updateApi 展示 `s_compat` 警示 |
| `Temp/claude/e2e_s_allele_20260804.py` | S-allele 兼容校验探针(纯函数 8 例 + service 层 5 组,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.13 版本行 + §8.21 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.13.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十四 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑫ + 相关行补「S-allele 兼容 + 抗病/需冷量性状字典」 |
### 新增/修改文件(2026-08-04 GWAS/QTL/MAS 标记辅助选择闭环)
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/gwas.py` | GWAS 求解器(GLM+PCSVD 群体结构 + `fdist.f_pvalue` p 值 + Bonferroni/BH-FDR + QTL 合并 + 岭回归共线兜底,ENGINE_VERSION=1.0.0,纯 numpy |
| `backend/sql/weld_gwas.sql` | 幂等 `CREATE TABLE IF NOT EXISTS`bre_gwas_result/bre_gwas_snp/bre_qtl/bre_mas_panel/bre_mas_panel_marker5 新表兜底) |
| `backend/sql/bre_menu.sql` | §6d`sys_menu 900214` component_path 翻转为 `module_bre/gwas/index` |
| `backend/app/api/v1/module_bre/statistics/model.py` | `GwasResultModel`/`GwasSnpModel`/`QtlModel`/`MasPanelModel`/`MasPanelMarkerModel` |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `GwasRunIn/GwasResultOut/GwasSnpOut/QtlIn/QtlOut/MasPanelIn/MasPanelOut/MasPanelMarkerIn/MasPanelSetMarkersIn` |
| `backend/app/api/v1/module_bre/statistics/controller.py` | gwas×3 + qtl×5 + mas-panel×4 端点(复用 `module_bre:statistics:*` 权限) |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_gather_gwas_inputs` + `run_gwas/list_gwas/gwas_detail` + qtl/mas_panel CRUD + `mas_panel_set_markers` + `_mas_hit_map` + decision_preview marker 条件 + `_DATA_VERSION` v2.12 |
| `frontend/web/src/api/module_bre/gwas.ts` | runGwas/listGwas/gwasDetail + Qtl/MasPanel/MasPanelMarker API |
| `frontend/web/src/views/module_bre/gwas/index.vue` | 三 tabGWAS 结果 Manhattan/QQ 裸 echarts + QTL 定位 + MAS 面板)+ 运行对话框 |
| `Temp/claude/e2e_gwas_20260804.py` | GWAS/QTL/MAS 闭环探针(7 段断言,运行后自动清理;含数据设计要点避免 PC 吞噬 QTL) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.14 版本行 + §8.22 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.14.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十五 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑬ + 900214 行「GWAS/QTL 已落地」 |
### 新增/修改文件(2026-08-04 九缺口补齐:经典侧计算端点 + 分子侧严谨性 + 求解器核心)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/controller.py` | `POST /data-quality` + `POST /genetic-gain` + `POST /mating-recommend` + `POST /gwas-qtl-x-e` |
| `backend/app/api/v1/module_bre/statistics/service.py` | `data_quality_report`/`genetic_gain`/`mating_recommend`/`qtl_x_e` + `_allelic_from_gt`/装配 marker_type 分支 + `_DATA_VERSION` v2.13 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | 4 新端点入参出参 + `RunStatsIn.spatial` 等 |
| `backend/scripts/breeding_stats/blup.py` | `solve_spatial`AR1×AR1ENGINE_VERSION 1.3.0+ `_build_ainv_sparse`/`_cg_solve`/HutchinsonN_SPARSE=1000 阈值分派稀疏-CG 路径,稠密路径逐字节不变) |
| `backend/scripts/breeding_stats/gwas.py` | `_emmax` + 后处理抽共享 `_bh_qvalues`/`_finalize`/`_cluster`GLM 逐字节不变,ENGINE_VERSION 1.1.0 |
| `backend/scripts/breeding_stats/genomic.py` | `build_g_matrix` 多等位 VanRaden 推广(ENGINE_VERSION 1.2.0 |
| `backend/app/api/v1/module_bre/genotype_call/service.py` | VCF 导入按 ALT 数定 `marker_type`ssr/snp |
| `backend/sql/weld_mas_semantics.sql` | 幂等 ADD COLUMNbre_mas_panel_marker.mode / favorable_allele / haplotype_group |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 数据质量/遗传增益/选配 3 入口 + spatial 复选框 |
| `frontend/web/src/api/module_bre/statistics.ts` | 3 新端点 + spatial 参数 |
| `frontend/web/src/views/module_bre/gwas/index.vue` | method 下拉(gwas/emmax+ QTL×E tab + 面板标记编辑器三控件(xeForm 类型断言修复 vue-tsc |
| `frontend/web/src/api/module_bre/gwas.ts` | `GwasQtlXEIn` + method 枚举 |
| `Temp/claude/e2e_data_mating_gain_20260804.py` | 批1 探针(数据质量/遗传增益/选配,运行后自动清理) |
| `Temp/claude/e2e_molrigor_20260804.py` | 批2 探针(EMMAX/SSR/QTL×E/MAS 语义,运行后自动清理) |
| `Temp/claude/e2e_spatial_sparse_20260804.py` | 批3 探针(AR1×AR1/稀疏-CG/Hutchinson,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.15 版本行 + §8.23 台账(+ 补 v2.13 缺失版本行) |
| `doc/桃育种系统模块扩展需求规格.v2.15.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十六 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑭ + EBV/ABLUP 行、GWAS/QTL/MAS 行补注 |
### 新增/修改文件(2026-08-05 十二项真缺口补齐:引擎三件 + 模块四件 + 底座五件)
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/blup.py` | `solve_spatial``aniso`(ρ_row/ρ_col 双参,ENGINE_VERSION 1.4.0 |
| `backend/scripts/breeding_stats/mtblup.py` | `solve_multi` 全多变量 EM-REMLENGINE_VERSION 1.1.0 |
| `backend/scripts/breeding_stats/gwas.py` | `_ssgwas` 单步 GWAS MEM 对角近似(ENGINE_VERSION 1.2.0 |
| `backend/app/api/v1/module_bre/statistics/service.py` | `full_mtblup=True` 模式 + `_DATA_VERSION` v2.14 + `_allelic_columns` SSR 兜底限定空 marker_type(回归修复) |
| `backend/app/api/v1/module_bre/field_operation/{model,crud,service,controller,schema}.py` | 农事操作 900051 五件套 |
| `backend/app/api/v1/module_bre/observation/{model,crud,service,controller,schema}.py` | 通用观测 900050 五件套 |
| `backend/app/api/v1/module_bre/breeding_report/{model,crud,service,controller,schema}.py` | 育种报告 900075 五件套 + `POST /report/generate` |
| `backend/app/api/v1/module_bre/analysis_dataset/{model,crud,service,controller,schema}.py` | 分析数据集 900070 五件套 + 新表 bre_analysis_dataset |
| `backend/app/api/v1/module_bre/audit/{model,crud,service,controller,schema}.py` | 审计切面 + `GET /bre/audit/list|detail` |
| `backend/app/api/v1/module_bre/alert/{model,crud,service,controller,schema,job}.py` | 超期预警 + `GET /bre/alert/list|resolve` |
| `backend/app/api/v1/module_bre/brapi/controller.py` | BrAPI 2.x /brapi/v2 五只读端点 + MIAPPE |
| `backend/app/utils/number_gen.py` | NumberGenService + pg_advisory_xact_lock 原子取号 |
| `backend/app/api/v1/module_bre/sequence/model.py` | bre_sequence 表 |
| `backend/app/api/v1/module_bre/{cross_combination,tree,selection_result,seedling}/service.py` | 4 处编号迁移(YY+3位/组合-序号/clone_code 扩位/batch_no YP-…) |
| `backend/app/core/ap_scheduler.py` | 3 系统 jobcleanup Sun 03:00 / alert 08:37 / backup 02:17 |
| `backend/app/utils/backup_job.py` | 每日备份 job 包装 pg_backup.shGit Bash + MSYS 路径) |
| `backend/scripts/pg_backup.sh` / `pg_restore.sh` | pg_dump 自定义格式 + N 天轮转 / 恢复脚本 |
| `backend/app/init_app.py` | brapi_router 根注册(/brapi/v2 非 /bre 前缀) |
| `backend/sql/weld_*.sql`(op_type 字典/菜单翻转/文案清理/bre_alert/bre_sequence/bre_analysis_dataset | 幂等 weld 兜底 |
| `frontend/web/src/views/module_bre/{field_operation,observation,breeding_report,analysis_dataset,alert}/index.vue` | 4 新模块页 + 预警中心 |
| `frontend/web/src/api/module_bre/{field_operation,observation,breeding_report,analysis_dataset,alert}.ts` | 5 新 API |
| `frontend/web/src/views/module_bre/statistics/index.vue` | spatial aniso 复选框 + gwas method=ssgwas 下拉 |
| `Temp/claude/e2e_gaps_engines_20260804.py` | 批1 探针(ssgwas/solve_multi/aniso,运行后自动清理) |
| `Temp/claude/e2e_gaps_modules_20260805.py` | 批2 探针(四模块 CRUD + report generate + 菜单翻转,运行后自动清理) |
| `Temp/claude/e2e_gaps_base_20260804.py` | 批3 探针(审计/编号并发/预警/备份/BrAPI,运行后自动清理) |
| `Temp/claude/regress_logs/` | 全量回归日志(8 旧探针 + 3 批探针) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.16 版本行 + §8.24/8.25/8.26 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.16.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十七 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑮ + 相关行补注 + 过时「待建」标记修正 |
### 新增/修改文件(2026-08-05 桃育种业务流全面完善:批A 业务数据链 + 批B 统计算法 + 批C 前端)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/field_operation/model.py` | 4 采收列 yield_kg/fruit_count/avg_fruit_weight/marketable_rate |
| `backend/app/api/v1/module_bre/field_operation/{service,schema}.py` | harvest 结构化产量同步 `bre_trait_observation`A1+ 表单 4 字段 |
| `backend/app/api/v1/module_bre/observation/model.py` | germplasm_id 可空 FKA3 |
| `backend/app/api/v1/module_bre/observation/{service,schema}.py` | 种质校验 + EAV 校验(A5+ 4 查询过滤 tree/plot/germplasm/trial_study + germplasm 表单字段 |
| `backend/app/api/v1/module_bre/seed_lot/{model,schema}.py` | pollination_id FKA4 |
| `backend/app/api/v1/module_bre/seed_treatment/{model,schema}.py` | seed_lot_id FKA4 |
| `backend/app/api/v1/module_bre/tree/service.py` | create 阶段自动设置(A6breeding_generation→juvenile/evaluation |
| `backend/app/api/v1/module_bre/trait_observation/service.py` | EAV 校验(numeric/date parse + valid_min/max + 重复)+ 成株性状门禁(A5/A6) |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_values_by_tree_env` + `run_type_b_heredity`B1+ `_genetic_corr_matrix`B2+ `auto_weights`B3+ `run_cluster`B4+ `_DATA_VERSION` v2.15 |
| `backend/app/api/v1/module_bre/statistics/controller.py` | POST /type-b-heredity + GET /type-b + GET /type-b/{id} + POST /cluster + correlation mode/g_method/year 透传 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | TypeBIn/Out + CorrelationIn mode/g_method/year + SelectionIndexIn auto_weights + ClusterIn |
| `backend/app/api/v1/module_bre/statistics/model.py` | `bre_type_b_result` 新表(TypeBResultModel |
| `backend/sql/weld_busflow.sql` | A1/A3/A4 四处 ALTER ADD COLUMN IF NOT EXISTS + index(幂等) |
| `backend/sql/bre_yield_phenology_traits.sql` | A2 产量/物候/品质/生长量/描述性状种子 19 条(ON CONFLICT 幂等) |
| `frontend/web/src/plugins/echarts.ts` | 注册 HeatmapChart + VisualMapComponent |
| `frontend/web/src/api/module_bre/statistics.ts` | type-b/cluster/correlation mode/funnel/auto_weights 类型 |
| `frontend/web/src/api/module_bre/observation.ts` | ObservationPageQuery 四过滤 + ObservationForm germplasm_id |
| `frontend/web/src/api/module_bre/field_operation.ts` | FieldOperationTable/Form 四采收字段 |
| `frontend/web/src/views/module_bre/observation/index.vue` | plot/站点/germplasm 过滤 + germplasm 表单(C1 |
| `frontend/web/src/views/module_bre/field_operation/index.vue` | harvest 结构化表单/表格 4 列(C1) |
| `frontend/web/src/views/module_bre/statistics/index.vue` | correlation/gblup 热图折线 + type-B tab + cluster 树状图 + funnel 对话框(C2/C3 |
| `frontend/web/src/views/module_bre/stage_phenotype/index.vue` | tabs 通用观测/农事操作翻真实页(C4) |
| `frontend/web/src/views/module_bre/_shared/StageView.vue` | compMap 注册 Observation/FieldOperationC4 |
| `Temp/claude/e2e_busflow_20260805.py` | 批A 探针(A1-A6,11 组断言,运行后自动清理) |
| `Temp/claude/e2e_statsflow_20260805.py` | 批B 探针(B1-B4,15 组断言,运行后自动清理) |
| `Temp/claude/smoke_busflow_c_20260805.py` | 批C HTTP smoke10 检查,不建数据) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.17 版本行 + §8.27 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.17.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §十八 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑯ + 相关行补注 |
### 新增/修改文件(2026-08-05 世代闭环:单株晋级落系谱)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/selection_result/service.py` | `_promote_tree_to_clone` 建种质时同步落 `bre_pedigree`child_code=品种名、dam/sire=tree.dam/sire 回退组合 female/male_parent_id、combination_id、generationchild_code 幂等)+ 种质携带 generation/stage + `combo=None` 初始化防 UnboundLocalError |
| `Temp/claude/e2e_pedigree_closure_20260805.py` | 世代闭环探针(11 组断言,运行后自动清理) |
| `Temp/claude/cleanup_pedigree_test.py` | 前缀清理脚本(幂等,探针残留兜底) |
### 新增/修改文件(2026-08-05 近交惩罚静默关闭修复:亲缘矩阵多源解析)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | 重写 `_germplasm_pedigree` 多源级联(① 规范化名称反查显式系谱 → ② tree FK 兜底唯一一致 → ③ founder;BFS 祖先展开去重;返回 (pedigree, coverage));`mating_recommend` 加 kinship_status/kinship_warning/kinship + 逐对「亲缘未解析(r 按 0 计)」旗标 |
| `Temp/claude/e2e_mating_kinship_20260805.py` | 近交惩罚静默关闭修复探针(14 组断言,运行后自动清理) |
### 新增/修改文件(2026-08-05 EBV 回退方法学修复:direct 优先 + 子代测验降权)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | `mating_recommend` EBV 回退重写——direct 优先(有 direct 绝不被树级值污染);回退显式标注 progeny + `_EBV_SOURCE_FACTOR` 降权 0.5 参与打分(`mid=(f_a·ebv_a+f_b·ebv_b)/2`);双亲均缺直接值的子代树剔除(防双侧等权重复计);记 n_progeny/n_combos;返回体加 `candidate_ebv` + `ebv_source.coverage` + 逐对旗标 |
| `Temp/claude/e2e_mating_ebv_20260805.py` | EBV 回退方法学修复探针(5 组断言,运行后自动清理) |
### 新增/修改文件(2026-08-05 数据质量离群值方向语义错位修复:同向=精英 / 反向=疑似错误)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | `data_quality_report` 方向感知分流——取 `trait_row.direction`desc/None→`desirable_high=True` 高值优;asc→False);IQR/MAD 命中的株按偏离侧双通道分类(`is_high=v>med``is_elite=is_high==desirable_high`):同向→`extreme_candidates`class=extreme_candidate/ 反向→`outliers`class=outlier);返回体加 `direction` + `extreme_candidates` + `summary.n_extreme_candidates``has_warning/n_outliers/outlier_rate` 语义收紧为疑似录入错误计数 |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 数据质量 tab 改双表——「极值候选(精英)」success 标签表 + 「疑似录入错误」danger 标签表 + 选育方向指示条 + 无错误绿色 info alert(提示文案改方向语义) |
| `Temp/claude/e2e_data_mating_gain_20260804.py` | A6 探针 [1] 扩展——17 株(15 正常 + 精英高值 16.0 + 错误低值 2.0):精英进 extreme_candidates/class=extreme_candidate/side=high 且不在 outliers;错误进 outliers/class=outlier/side=lown_extreme_candidates=1 |
### 新增/修改文件(2026-08-05 ΔG 投影假设声明 + 工程健壮性打磨:note 假设 + spatial 缺坐标降级 + numpy 收敛)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | ① `genetic_gain` 返回体加 `note` 投影假设声明(环境均值恒定/演示值);② `run_ablup(spatial=True)` 缺坐标株记 `missing_coord_ids` → 剔除表型保留系谱(EBV 由系谱预测)、剔除数写批次 note「缺坐标剔除N株表型(EBV由系谱预测)」、全缺才整批 409、`input_hash` 用剔除后子集;③ 模块级 `import numpy as np`:24+ 移除 7 处局部 import`data_quality_report` 逐株 flag 循环改 numpy 布尔掩码向量化(输出逐字节不变) |
| `frontend/web/src/views/module_bre/statistics/index.vue` | gain tab 描述区后、轮次表前加 `el-alert type="info"` 展示 `gainData.note`(投影假设边界) |
| `Temp/claude/e2e_spatial_sparse_20260804.py` | spatial 探针新增强健降级场景——5 株(4 株 2×2 网格 + 1 株无坐标):method=AR1×AR1/train_n=4/note 含剔除标注/5 株均有 EBV 行;全缺坐标仍整批 409trait 清理含 tD_{P} |
| `Temp/claude/e2e_data_mating_gain_20260804.py` | A6 探针 [2] 加 note 断言——含「环境均值恒定」且两性状稳定一致 |
### 新增/修改文件(2026-08-05 A–F 六项功能级缺口·批1 父本验证 + 近交衰退)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/pollination/service.py` | A1 `_validate_pollen_parent`create/update 统一:批次采集父本≠授粉父本 409,混合/未声明放行) |
| `backend/app/api/v1/module_bre/tree/service.py` | A2 `_resolve_parents` 改返回 `(dam, sire, warning)` + create/update 返回体 warning(以显式为准,不阻断) |
| `backend/app/api/v1/module_bre/tree/schema.py` | `warning: str | None` 只读字段(仅返回体不落库) |
| `backend/app/api/v1/module_bre/cross_combination/service.py` | A3 `_check_parent_roles` 同质自交 409create/update 生效亲本统一) |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `InbreedingDepressionIn`trait_id/trait_code + year/trial_study_id + min_n |
| `backend/app/api/v1/module_bre/statistics/controller.py` | `POST /bre/statistics/inbreeding-depression` |
| `backend/app/api/v1/module_bre/statistics/service.py` | `inbreeding_depression`(F=A_ii1 + 树级表型均值 → numpy lstsq 回归,F=0 兜底)+ `_DATA_VERSION` v2.22 |
| `frontend/web/src/api/module_bre/statistics.ts` | `inbreedingDepression` API |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 亲缘/近交 tab 近交衰退区(trait/year + el-alert + el-descriptions + 高 F 株表;el-alert `'error'` 修复 TS2322 |
| `Temp/claude/e2e_parent_validation_20260805.py` | 批1-A 父本验证探针(10 断言,运行后自动清理) |
| `Temp/claude/e2e_inbreeding_depression_20260805.py` | 批1-C 近交衰退探针(4 断言,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.22 版本行 + §8.32 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.22.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.10 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ⑳ + 相关行补注 |
### 新增/修改文件(2026-08-05 A–F 六项功能级缺口·批2 GS 家系 CV + 试验设计深度)
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/genomic.py` | B `kfold_cv_genomic``split="random"|"family"` + `family_of`(家系阻塞折、无家系个体自成一族、家系数<k 折叠 warning、单家系边界、输出 n_familiesrandom 逐字节不变) |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `AnovaIn.block`RCBD 区组校正开关)+ `TrialDesignIn`trial_study_id/design_type/seed |
| `backend/app/api/v1/module_bre/statistics/controller.py` | `POST /bre/statistics/trial-design` + run_anova 透传 block |
| `backend/app/api/v1/module_bre/statistics/service.py` | `run_cv` 加 split 透传 + GS family_of 构建 + note 记 n_families`trial_design` RCBD 生成器(random.Random(seed) 洗牌 + case() 批量落库);`run_anova` 加 block 分支(solve_rcbd);`_DATA_VERSION` v2.23 |
| `backend/scripts/breeding_stats/anova.py` | F2 `solve_rcbd`RCBD 双因素 Type I 顺序,SS_group/SS_block/SS_error + f_block/p_block + 区组均值;solve 单因素逐字节不变) |
| `backend/app/api/v1/module_bre/trial_study_entry/model.py` | F1 `block_no` 列(可空 integer |
| `backend/sql/weld_trial_study_entry.sql` | F1 `ALTER TABLE bre_trial_study_entry ADD COLUMN IF NOT EXISTS block_no integer`(幂等) |
| `frontend/web/src/api/module_bre/statistics.ts` | `runAnova` 加 block + `trialDesign()` + `TrialDesignResult` |
| `frontend/web/src/views/module_bre/statistics/index.vue` | ANOVA tab 重构(生成 RCBD 设计工具条 + 设计区组表 + anovaBlock checkbox + 区组均值/block 结果 v-if |
| `Temp/claude/e2e_trial_design_20260805.py` | 批2-F 探针(5 组断言,运行后自动清理) |
| `Temp/claude/e2e_gs_family_cv_20260805.py` | 批2-B 探针(5 组断言,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.23 版本行 + §8.33 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.23.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.11 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ㉒ + 相关行补注 |
### 新增/修改文件(2026-08-05 A–F 六项功能级缺口·批3 OCS 最优贡献选择 + MABC 标记辅助回交)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | D `_proj_simplex`/`_solve_ocs` + `ocs`(投影梯度,A=pedigree+rmat 组装,vs_top_n 对比);共享 helper `_candidate_ebv_map` 抽取(mating_recommend 内联原样提取,direct/progeny 降权 0.5/双侧去重保留);E `_pure_homologous` + `mabc_progress`(前景 `_mas_hit_map` + 背景恢复率 + `_BC_LADDER` 晋级建议);`_DATA_VERSION` v2.24 |
| `backend/app/api/v1/module_bre/statistics/controller.py` | `POST /bre/statistics/ocs` + `POST /bre/statistics/mabc-progress` |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `OcsIn`candidate_germplasm_ids/n_select/lam/prediction_id+ `MabcIn`candidate_tree_ids/foreground_panel_ids/background_panel_ids/recurrent_parent_tree_id/foreground_min_hits/generation/background_target)均 extra="ignore" |
| `frontend/web/src/api/module_bre/statistics.ts` | `ocs()` + `mabcProgress()` API |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 「选配推荐」tab OCS 运行区(n_select + λ 滑杆 + contribution 表 + vs_top_n 对比)+ 独立「回交 MABC」tab(面板/轮回亲本/候选树 + 参数 + 逐株结果 + recommended 降序表) |
| `Temp/claude/e2e_ocs_20260805.py` | 批3-D OCS 探针(17 断言,运行后自动清理;λ 梯度/退化/partial 告警/三 409 |
| `Temp/claude/e2e_mabc_20260805.py` | 批3-E MABC 探针(23 断言,运行后自动清理;前景/背景复算/reason/童期/六 409 |
| `doc/桃育种系统模块扩展需求规格.md` | v2.24 版本行 + §8.34 台账 |
| `doc/桃育种系统模块扩展需求规格.v2.24.md` | 冻结快照 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.12 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | header ㉓ + 相关行补注 |
### 新增/修改文件(2026-08-05 近交衰退两处正确性修复:方向感知 + 深层系谱)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | `inbreeding_depression` 方向感知检测(`desirable_high=direction!="asc"`asc 衰退=slope>0 且 t≥+1.645interpretation 方向化)+ 深层系谱 F(复用 `_germplasm_pedigree` BFS + 树节点 + 未解析 founder 兜底;`_germplasm_pedigree` 本体零改动) |
| `frontend/web/src/views/module_bre/statistics/index.vue` | 近交衰退提示文案方向化(「高优性状显著负斜率 / 低优性状(如病指)显著正斜率 = 近交衰退」) |
| `Temp/claude/e2e_inbreeding_depression_20260805.py` | 批1-C 近交衰退探针扩展 4→6 组断言(新增 [4] asc 病指方向感知 + [5] 深层系谱 F 多世代;原 [1][2][3][x] 保持) |
| `doc/桃育种系统模块扩展需求规格.md` | §8.35 跟进台账 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.13 跟进 + 文件清单/备份/复跑 |
### 新增/修改文件(2026-08-05 分子亲本验证 + 试验设计深度·批4)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/genotype_call/service.py` | `mendelian_check`(子代 vs 声明亲本 union 规则、跨数据集亲本基因型解析、no_declared_parents/missing_parent_genotype 状态、incompatible_markers 明细)+ `_allele_set` 复用 + import TreeModel |
| `backend/app/api/v1/module_bre/genotype_call/controller.py` | `GET /bre/genotype_call/mendelian/check`Auth `module_bre:genotype_call:query`Query dataset_id + compat_threshold=0.98,镜像 fingerprint/check |
| `backend/app/api/v1/module_bre/statistics/service.py` | `trial_design` 分派 rcbd/augmented/alpharcbd 逐字节不变)+ `_trial_design_augmented`(对照 anchoring/新品系 round-robin/对照 block_no 不落库)+ `_trial_design_alpha`(平方闭式格子 + 一般贪心可分解 + `_is_prime` + balance_warning + block_no 复合编码)+ `_DATA_VERSION` v2.25 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `TrialDesignIn``check_germplasm_ids: list[int]=[]` / `block_size: int\|None` / `reps: int\|None`extra="ignore"+ design_type 描述改 rcbd/augmented/alpha |
| `backend/app/api/v1/module_bre/statistics/controller.py` | trial_design 透传三新参 + summary 更新「RCBD/增广/α-格子(落库 block_no)」 |
| `frontend/web/src/api/module_bre/genotype_call.ts` | `mendelianCheck()` + `GenotypeCallMendelianParams/Result/Tree/IncompatMarker` 类型 |
| `frontend/web/src/views/module_bre/genotype_call/index.vue` | 工具栏「孟德尔/亲本一致性」按钮 + FaDialogdataset select + compat_threshold + summary 计数 + trees 表 tree_no/dam/sire/informative/rate/flag/incompatible_markers 展开) |
| `frontend/web/src/api/module_bre/statistics.ts` | `trialDesign` design_type 枚举扩 augmented/alpha + check_germplasm_ids/block_size/reps + `TrialDesignResult` 加 checks/n_new_entries/n_checks/check_reps/block_size/reps/balance_warning + blocks 联合类型 |
| `frontend/web/src/views/module_bre/statistics/index.vue` | DESIGN_TYPE_LABELS 补 增广/α-格子 + 条件参数(augmented 对照多选 / alpha block_size+reps+ α-格子平衡性 el-alert + alpha 块渲染「重复{rep}·块{blk}」 |
| `Temp/claude/e2e_mendelian_check_20260805.py` | 批4-A 探针(8 断言:跨数据集解析/alien 等位/rate/状态/空数据集零值,运行后自动清理) |
| `Temp/claude/e2e_trial_design_ext_20260805.py` | 批4-B 探针(19 断言:增广/平方格子/部分 r/非素数告警/一般贪心/四 409,运行后自动清理) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.25 版本行 + §8.36 台账 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.14 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | 相关行补注(分子育种 mendelian + 试验设计行增广/α-格子) |
### 新增/修改文件(2026-08-05 批5 区组随机效应 + 孟德尔落库隔离 + 统计引擎数值校验)
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/blup.py` | `solve``block` 参数分派新 `_solve_block`(区组第二随机效应,镜像 `_solve_gxe`+ `ENGINE_VERSION` 1.5.0 |
| `backend/app/api/v1/module_bre/statistics/service.py` | `run_ablup` block 开关 + block 分支(block_no 读取/降级剔除/≥2 区组 409+ 互斥(block×gxe/gxr/spatial+ `data_quality_report` dataset_id 可选 + mendelian 段 + `_excluded_tree_ids` 系谱消费方断链(_build_pedigree/run_ablup/inbreeding/kinship/cv/_germplasm_pedigree+ `_DATA_VERSION` v2.26 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | `RunAblupIn.block` + `DataQualityIn.dataset_id` |
| `backend/app/api/v1/module_bre/statistics/controller.py` | run_ablup block 透传 + data-quality dataset_id 透传 |
| `backend/app/api/v1/module_bre/genotype_call/model.py` | `MendelianCheckModel``bre_mendelian_check` + `MendelianCheckTreeModel``bre_mendelian_check_tree`FK CASCADE |
| `backend/app/api/v1/module_bre/genotype_call/service.py` | 纯计算核心抽共享 `_compute_mendelian` + 新 `run_mendelian_check`(落库 + flag upsert 隔离/未 flag 清除,可逆) |
| `backend/app/api/v1/module_bre/genotype_call/controller.py` | 新 `POST /bre/genotype_call/mendelian/check/run`Auth editGET 只读预览保留) |
| `backend/app/api/v1/module_bre/tree/model.py` | `TreePedigreeExclusionModel``bre_pedigree_exclusion`tree_id 唯一) |
| `frontend/web/src/api/module_bre/statistics.ts` | `RunAblupPayload.block` + `DataQualityPayload.dataset_id` |
| `frontend/web/src/api/module_bre/genotype_call.ts` | `mendelianCheckRun` + `GenotypeCallMendelianRunResult`check_id/isolated/cleared |
| `frontend/web/src/views/module_bre/statistics/index.vue` | GxE tab block 开关 + 互斥 + 数据质量 tab dataset 选择器 + mendelian 段(flag alert + 隔离树表) |
| `frontend/web/src/views/module_bre/genotype_call/index.vue` | 孟德尔对话框主按钮改 POST run + check_id/隔离树数展示 |
| `Temp/claude/e2e_ablup_block_20260805.py` | 批5-A 探针(6 场景:已知 σ²block 恢复/409 门禁/互斥/降级/无归零警告) |
| `Temp/claude/e2e_mendelian_persist_20260805.py` | 批5-B 探针(ok=19 fail=0:落库/隔离断开 EBV/可逆清除/data-quality 段/只读零回归) |
| `Temp/claude/e2e_stats_numerics_20260805.py` | 批5-C 探针(ok=101 fail=0:全量统计引擎逐段 ground-truth 真值) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.26 版本行 + §8.37 台账 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.15 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | 相关行补注(孟德尔落库隔离 + block 随机效应 + 统计引擎数值校验) |
### 新增/修改文件(2026-08-05 批6 规划↔目标↔试验 可追溯性闭环)
| 文件 | 说明 |
|---|---|
| `backend/sql/weld_plan_trace.sql` | 幂等 ALTER 三列 + FKbre_target.plan_id、bre_trial.plan_id、bre_trial.target_id(均可空) |
| `backend/app/api/v1/module_bre/target/model.py` | `TargetModel.plan_id` + relationship |
| `backend/app/api/v1/module_bre/target/schema.py` | `TargetCreateSchema/TargetUpdateSchema.plan_id` 透传 |
| `backend/app/api/v1/module_bre/target/service.py` | get_list outerjoin 解析 `plan_name` + create 父校验(坏 plan_id 409+ delete assert_no_children |
| `backend/app/api/v1/module_bre/trial/model.py` | `TrialModel.plan_id`/`target_id` + 双 relationship |
| `backend/app/api/v1/module_bre/trial/schema.py` | 双字段透传 |
| `backend/app/api/v1/module_bre/trial/service.py` | get_list 解析 `plan_name`+`target_name` + create 双父校验 + delete assert_no_children |
| `backend/app/api/v1/module_bre/plan/service.py` | 新 `trace(plan_id)`(目标链/试验链/软删过滤/totals+ delete assert_no_children |
| `backend/app/api/v1/module_bre/plan/controller.py` | 新 `GET /bre/plan/trace/{id}` |
| `frontend/web/src/api/module_bre/plan.ts` | `PlanTrace` 类型 + `getPlanTrace` |
| `frontend/web/src/api/module_bre/target.ts` | `getTargetOptions` |
| `frontend/web/src/views/module_bre/target/index.vue` | 「所属计划」select + 表格/详情列 |
| `frontend/web/src/views/module_bre/trial/index.vue` | 「所属计划/目标」select + 表格/详情列 |
| `frontend/web/src/views/module_bre/plan/index.vue` | 「追溯」行操作弹窗(ElCollapse 目标链/试验链) |
| `Temp/claude/e2e_plan_trace_20260805.py` | 批6 探针(17 断言:目标链/试验链/totals/软删/孤目标/父校验/删除守卫/标签解析) |
| `Temp/claude/e2e_audit_20260805.py` | 残留检查限定 `entity_type=='bre_target'`(跨表撞 id 误报根治) |
| `doc/桃育种系统模块扩展需求规格.md` | v2.27 版本行 + §8.38 台账 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.16 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | ㉖ 批6 可追溯性闭环补注 |
### 新增/修改文件(2026-08-05 批7 统计引擎全量十模块 golden 复查·系谱键空间错位修复)
| 文件 | 说明 |
|---|---|
| `backend/app/api/v1/module_bre/statistics/service.py` | 新增共享 helper `_tree_individual_keys`int→`"t{id}"` 对齐系谱键空间)+ 四个调用点收口(`_genetic_corr_matrix`/`_smith_hazel_index` mtblup 分支/`run_genetic_corr`/`run_type_b_heredity`+ `_DATA_VERSION` v2.28 |
| `backend/app/api/v1/module_bre/genotype_call/service.py` | `GENOTYPE_DATA_VERSION` v2.28 |
| `Temp/claude/e2e_rg_golden_20260805.py` | 批7 探针(ok=21 fail=0type_b 分裂家系 golden + correlation 平衡 golden + 分裂家系 discriminator + str/int 键诊断;含 exit-code 通道修复 `fail==0` |
| `Temp/claude/e2e_spatial_sparse_20260804.py` | 版本断言 v2.27→v2.28(×2 |
| `Temp/claude/e2e_statsflow_20260805.py` | 版本断言 v2.27→v2.28 |
| `Temp/claude/e2e_prediction_rigor_20260804.py` | 版本断言 v2.27→v2.28 |
| `Temp/claude/e2e_mendelian_persist_20260805.py` | 版本断言 v2.27→v2.28 |
| `Temp/claude/http_v228.py` | 批7 HTTP 核验(type-b-heredity 分裂家系 r_B>0.5/n_common=0 + genetic-corr/run 分裂家系 r_g>0.5 + 平衡 r_g>0.65 |
| `doc/桃育种系统模块扩展需求规格.md` | v2.28 版本行 + §8.39 台账 |
| `doc/桃育种系统统计引擎实施记录.md` | §18.17 落地 + 文件清单/备份/复跑 |
| `doc/桃育种系统规划对照总表.md` | ㉗ 批7 系谱键空间错位修复补注 |
### 新增/修改文件(2026-08-05 回归基建:统一回归 + 高风险模块 tc 套件,无后端代码改动)
| 文件 | 说明 |
|---|---|
| `run_regression.py` | 统一回归驱动:顺序串跑 Temp/claude/e2e_*.py(排除 e2e_probe*+ backend/scripts/test_bre_analysis_*_tc.py = 63 测试,每测试独立子进程 log 到 regression_logs/EXIT 汇总;DPB_PYTHON 覆盖解释器;utf-8 reconfigure 防 GBK;过滤器 + --keep-logs |
| `backend/scripts/test_bre_analysis_ssgblup_tc.py` | 正式 tc 套件(ok=14):GBLUP/ssGBLUP H⁻¹ 拼接判别——非基因型株 GBLUP EBV=0 / ssGBLUP EBV≠0(算偏当正常输出的同款隐患判别) |
| `backend/scripts/test_bre_analysis_ocs_tc.py` | 正式 tc 套件(ok=23):OCS 投影梯度 golden(Σc/c≥0/λ 单调/c'Ac/λ=0 退化/409+422 |
| `backend/scripts/test_bre_analysis_mabc_tc.py` | 正式 tc 套件(ok=24):MABC 前景/背景恢复率/晋级/童期 C6/422+409 |
| `backend/scripts/test_bre_analysis_mendelian_tc.py` | 正式 tc 套件(ok=9):孟德尔 POST run 落库/隔离注册表/阈值 0.0 可逆/GET 零回归(URL 下划线 genotype_call + 启动残留预清理 _wipe + 隔离验证时序) |
| `Temp/claude/backup_test_rigor_20260805/` | 备份镜像(root/run_regression.py + backend/scripts 4 tc 套件最新修复版) |
### 新增/修改文件(2026-08-05 回归基建 2:分析模块 tc 补齐 + pytest 接入 + run_ci,无后端代码改动)
| 文件 | 说明 |
|---|---|
| `backend/scripts/test_bre_analysis_genetic_corr_tc.py` | 正式 tc 套件(ok=19):平衡 3 性状 r_g 判别 + 分裂家系 r_g(S1,S2)>0.5 且 n_common=0(独立种子 SEED_S=3 |
| `backend/scripts/test_bre_analysis_type_b_tc.py` | 正式 tc 套件(ok=18):Type-B 3 站点分裂家系 r_B>0.5 且 n_common=0(复刻 tY-first rng 序 → 0.990+ 三 409 |
| `backend/scripts/test_bre_analysis_inbreeding_tc.py` | 正式 tc 套件(ok=44):近交衰退方向感知(衰退/无/上升)+ deep 系谱 F=0.125 + min_n insufficient + 422/409 |
| `backend/scripts/test_bre_analysis_trial_design_tc.py` | 正式 tc 套件(ok=25):增广(对照 block_no=None 不落库)+ α-格子(平方 λ≤1/非素数告警/一般贪心)+ block_no=rep*100+block DB 读回 + 四 409 |
| `backend/scripts/test_bre_analysis_stability_tc.py` | 正式 tc 套件(ok=16):AMMI/FW b 斜坡 + flag_stable + ASV rank + engine_version 落库 + year 维度 + 二 409 |
| `backend/tests/test_stat_analysis_tc.py` | pytest 包装层:9 套 tc @pytest.mark.pg + subprocess 串跑 + skipif 探测真实 PG16+Redisprotocol=2+ env 显式构建(剥 conftest 污染、解析 .env.dev、TC_CI_* 覆盖) |
| `backend/pyproject.toml` | `[tool.pytest.ini_options]` 注册 `pg` marker(消 PytestUnknownMarkWarning |
| `backend/tests/conftest.py` | 加 `collect_ignore_glob=["../scripts/test_*.py"]` 防 pytest 收集独立脚本污染 sqlite 环境 |
| `run_ci.py` | 本机 CI stagestep 0 探测 PG16+Redis(失败指引+exit≠0)→ step 1 `pytest -m pg` → step 2 EXIT=0「CI 全绿」,日志 Temp/claude/ci_logs/ |
| `Temp/claude/backup_analysis_tc2_20260805/` | 备份镜像(root/run_ci.py + backend/scripts 9 tc 套件 + backend/tests/test_stat_analysis_tc.py + pyproject/conftest diff |
### 新增/修改文件(2026-08-05 O2O4 统计方法学广度,v2.29)
| 文件 | 说明 |
|---|---|
| `backend/scripts/breeding_stats/genomic.py` | ENGINE_VERSION 1.4.0`solve_rrblup`(岭回归逐标记 + marker effects + 对偶)+ `solve_bayesb`BayesB Gibbs,确定性 seed 可复现)+ `kfold_cv_genomic` dosage/markers 分派 rrblup/bayesb |
| `backend/app/api/v1/module_bre/statistics/service.py` | `_values_by_tree_env` env_dim=stage 分支(`coalesce(obs.stage, TraitModel.stage)` 分组)+ `run_type_b_heredity` env_dim 校验扩 stage + `run_gblup` method 扩 rrblup/bayesb + seed 透传 + `run_cv` GS 分支 dosage/seed 透传 + `_smith_hazel_index` restricted 投影(Kempthorne-Nordskog 闭式解)/economic_weights + `selection_index` 透传 + `cv_detail``cv_result_id`(顺手修复)+ `_DATA_VERSION` v2.29 |
| `backend/app/api/v1/module_bre/statistics/schema.py` | TypeBIn.env_dim 描述扩 stage + GblupRunIn/CvRunIn method 描述扩 rrblup/bayesb + seed + SelectionIndexIn.method 描述扩 restricted + `restricted_traits`/`economic_weights` |
| `backend/app/api/v1/module_bre/statistics/controller.py` | run_gblup 透传 seed + selection_index 透传 restricted_traits/economic_weights |
| `backend/app/api/v1/module_bre/genotype_call/service.py` | `GENOTYPE_DATA_VERSION` v2.29 |
| `frontend/web/src/views/module_bre/statistics/index.vue` | Type-B env_dim 下拉加 stage + GBLUP/CV method radio 加 RRBLUP/BayesB + seed 输入 + 指数页 restricted 单选/restricted_traits 多选/每性状经济权重输入 + SI_RES 结果表与警示 |
| `frontend/web/src/api/module_bre/statistics.ts` | selectionIndex/runGblup/runCv method 类型扩 + restricted_traits/economic_weights/seed |
| `backend/scripts/test_bre_analysis_o234_tc.py` | 正式 tc 套件第 10 套(ok=41):O2 stage 幼成相关 / O3 rrblup+bayesb 落库与对偶可复现 / O4 restricted+economic |
| `backend/tests/test_stat_analysis_tc.py` | TC_SCRIPTS 注册 `("o234", "test_bre_analysis_o234_tc.py")`9 → 10 套) |
| `Temp/claude/e2e_o234_20260805.py` | O2–O4 e2e 探针(19 断言,纯计算 golden + 真实 PG |
| `Temp/claude/backup_o234_20260805/` | 备份镜像(后端 service/schema/controller/genomic + 前端 vue/ts + tc + e2e |
### 备份(无 git,批量编辑前手动镜像)
- 2026-08-03 引擎改动 → `Temp/claude/backup_gxe_20260803/`
- 2026-08-04 方向改动(13 文件,按相对路径镜像)→ `Temp/claude/backup_direction_20260804/`
- 2026-08-04 规范文档 → `Temp/claude/backup_docs_20260804/` + `doc/桃育种系统模块扩展需求规格.v2.2.md`(旧版本快照)
- 2026-08-04 无性系级指数改动(controller/schema/service/statistics.ts/index.vue/e2e)→ `Temp/claude/backup_clone_index_20260804/`
- 2026-08-04 配合力交配设计改动(13 文件,按模块相对路径镜像)→ `Temp/claude/backup_combining_design_20260804/`
- 2026-08-04 统计严谨·MLOps 复现性改动(weld SQL×2 + statistics 三件套 + blup.py + rootstock 三件套 + 前端四文件 + 三探针)→ `Temp/claude/backup_rigor_20260804/`
- 2026-08-04 组合得失漏斗改动(`weld_combination_funnel.sql` + statistics service/controller + e2e)→ `Temp/claude/backup_combination_funnel_20260804/`
- 2026-08-04 分子育种改动(weld SQL + bre_menu.sql + module_bre 四模块五件套 + __init__.py + 前端四 api 四页面 + e2e)→ `Temp/claude/backup_molecular_20260804/`
- 2026-08-04 精修项四连发改动(DUS 模块六件套 + statistics 四件套 + blup.py + weld/种子/菜单 SQL×3 + 前端 dus/statistics 两页两 api + e2e_refine)→ `Temp/claude/backup_refine_20260804/`
- 2026-08-04 六项能力完善改动(weld_advanced.sql + statistics 四件套 + dus 六件套 + trait_observation 三件套 + mtblup/genomic/stability/fdist/blup 求解器 + 前端 statistics/dus/tree_evaluation 三页四 api(含 trait_observation.ts+ 六探针 + 文档四件,37 文件)→ `Temp/claude/backup_advanced_20260804/`
- 2026-08-04 砧木×接穗随机互作改动(blup.py + statistics 三件套 + 前端 statistics.ts/index.vue + e2e_gxr)→ `Temp/claude/backup_gxr_20260804/`
- 2026-08-04 基因组选择实证严谨性改动(genomic.py + statistics 三件套 + 前端 statistics.ts/index.vue + e2e_gblup_cv + 文档三件)→ `Temp/claude/backup_gblup_cv_20260804/`
- 2026-08-04 现代桃育种领域覆盖改动(germplasm 三件套 + cross_combination 二件套 + bre_disease_chilling_traits.sql + 前端 germplasm/cross_combination 两页 + germplasm.ts + e2e_s_allele + 文档三件 + 规格快照 v2.13)→ `Temp/claude/backup_s_allele_traits_20260804/`
- 2026-08-04 GWAS/QTL/MAS 闭环改动(gwas.py + weld_gwas.sql + statistics 四件套 + bre_menu.sql + 前端 gwas.ts/index.vue + e2e_gwas + 文档三件 + 规格快照 v2.14)→ `Temp/claude/backup_gwas_20260804/`
- 2026-08-04 九缺口补齐改动(blup/gwas/genomic + statistics 四件套 + genotype_call + weld_mas_semantics.sql + 前端 statistics/gwas 两页两 ts + e2e×3 + 文档三件 + 规格快照 v2.15)→ `Temp/claude/backup_complete_20260804/`
- 2026-08-05 十二项真缺口补齐改动(批1 blup/mtblup/gwas 引擎 + statistics;批2 field_operation/observation/breeding_report/analysis_dataset 四模块五件套 + 前端四页四 ts;批3 audit/alert/brapi/sequence 模块 + number_gen + ap_scheduler + backup_job + pg_backup/pg_restore.sh + init_app + weld SQL 多枚 + 前端 alert 页/statisticse2e×3 + 文档三件 + 规格快照 v2.16)→ `Temp/claude/backup_gaps3_20260804/`
- 2026-08-05 桃育种业务流全面完善改动(批A field_operation/observation/seed_lot/seed_treatment/tree/trait_observation + weld_busflow.sql + bre_yield_phenology_traits.sql;批B statistics service/controller/schema/model + bre_type_b_result;批C echarts.ts + statistics/observation/field_operation 三 ts + statistics/observation/field_operation/stage_phenotype/StageView 五 vuee2e×2 + smoke + 文档三件 + 规格快照 v2.17)→ `Temp/claude/backup_busflow3_20260805/`
- 2026-08-05 世代闭环改动(selection_result/service.py 晋级落谱 + 探针)→ `Temp/claude/backup_pedigree_closure_20260805/`
- 2026-08-05 近交惩罚静默关闭修复改动(statistics/service.py 亲缘多源解析 + 探针)→ `Temp/claude/backup_kinship_20260805/`
- 2026-08-05 EBV 回退方法学修复改动(statistics/service.py 打分降权 + 探针)→ `Temp/claude/backup_ebv_20260805/`
- 2026-08-05 数据质量离群值方向语义修复改动(statistics/service.py 方向分流 + 前端 statistics/index.vue 双表 + A6 探针 + 文档三件 + 规格快照 v2.20)→ `Temp/claude/backup_dq_semantics_20260805/`
- 2026-08-05 ΔG 投影假设 + 工程健壮性打磨改动(statistics/service.py note 假设 + spatial 降级 + numpy 收敛向量化 + 前端 statistics/index.vue gain alert + spatial/A6 探针 + 文档三件 + 规格快照 v2.21)→ `Temp/claude/backup_dq_robust_20260805/`
- 2026-08-05 回归基建改动(run_regression.py + backend/scripts 4 tc 套件,无后端代码改动)→ `Temp/claude/backup_test_rigor_20260805/`
- 2026-08-05 AF 六项缺口·批1 父本验证 + 近交衰退改动(pollination/tree/cross_combination service + tree schema + statistics 三件套 + 前端 statistics.ts/index.vue + e2e×2 + 文档三件 + 规格快照 v2.22)→ `Temp/claude/backup_parent_validation_20260805/`
- 2026-08-05 AF 六项缺口·批2 GS 家系 CV + 试验设计深度改动(genomic.py + anova.py + statistics 三件套 + trial_study_entry model + weld_trial_study_entry.sql + 前端 statistics.ts/index.vue + e2e×2 + 文档三件 + 规格快照 v2.23)→ `Temp/claude/backup_gs_family_trial_design_20260805/`
- 2026-08-05 AF 六项缺口·批3 OCS + MABC 改动(statistics service/controller/schema 三件套 `_candidate_ebv_map` 抽取 + ocs + mabc_progress + 前端 statistics.ts/index.vue OCS 运行区 + MABC tab + e2e×2 + 文档三件 + 规格快照 v2.24)→ `Temp/claude/backup_ocs_mabc_20260805/`
- 2026-08-05 近交衰退正确性修复改动(statistics/service.py 方向感知 + 深层系谱 + 前端 statistics/index.vue 提示文案 + e2e_inbreeding_depression 扩展 + 文档二件 规格/实施记录)→ `Temp/claude/backup_inbreeding_fix_20260805/`
- 2026-08-05 分子亲本验证 + 试验设计深度·批4 改动(genotype_call 二件套 `mendelian_check` + statistics 三件套 `trial_design` augmented/alpha 分派 + 前端 genotype_call/statistics 两页两 ts + e2e×2 + 文档三件 规格/实施记录/对照总表,14 文件按相对路径镜像)→ `Temp/claude/backup_mendelian_design_20260805/`
- 2026-08-05 批5 区组随机效应 + 孟德尔落库隔离 + 统计引擎数值校验改动(blup.py + statistics 四件套 + genotype_call 三件套 + tree/model.py + 前端 statistics/genotype_call 两页两 ts + 三探针 + 文档三件,18 文件按相对路径镜像)→ `Temp/claude/backup_block_mendelian_numerics_20260805/`
- 2026-08-05 批6 规划↔目标↔试验 可追溯性闭环改动(weld_plan_trace.sql + target 三件套 + trial 三件套 + plan 二件套 + 前端 plan/target/trial 三页三 ts + 新探针 e2e_plan_trace + 文档三件,按相对路径镜像)→ `Temp/claude/backup_plan_trace_20260805/`
- 2026-08-05 批7 系谱键空间错位修复改动(statistics/service.py `_tree_individual_keys` + 四调用点 + genotype_call/service.py 版本 + 新探针 e2e_rg_golden + http_v228 + 版本断言探针×4 + 文档三件,按相对路径镜像)→ `Temp/claude/backup_keyspace_20260805/`
### 复跑验证
```bash
# 后端(GBK 控制台需 UTF-8worship() ASCII 画报会崩)
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python main.py run --env=dev
# 探针(真引擎 + spy 捕获 kwargs / 真引擎直跑)
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gxe_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_direction_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_clone_index_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_combining_design_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_prediction_rigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_rootstock_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_corr_spatial_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_combination_funnel_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_refine_20260804.py
# 砧木×接穗随机互作(G×R)探针(真引擎直跑,运行后自动清理):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gxr_20260804.py
# 基因组选择(GS)专用 k-fold CV 探针(真引擎直跑,运行后自动清理)+ GBLUP 回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_gblup.py
# GWAS/QTL/MAS 闭环探针(真引擎直跑 7 段断言,运行后自动清理)+ GBLUP/ssGBLUP 回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gwas_20260804.py
# 九缺口补齐三探针(真引擎直跑,运行后自动清理):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_data_mating_gain_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
# 九缺口补齐:MAS 面板语义三列(幂等,可重跑):
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_mas_semantics.sql
# 组合得失漏斗视图(幂等,可重跑):
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_combination_funnel.sql
# 精修项三 SQL(幂等,可重跑;bre_dus_seed 依赖 bre_dus_descriptor 已由 create_all 建出):
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_refine.sql
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/bre_dus_seed.sql
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/bre_menu_refine.sql
# 六项能力完善:weld_advanced(幂等,2 表 + 2 列 + 1 jsonb;新表 bre_genetic_corr_result/bre_stability_result 由 create_all 建出):
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_advanced.sql
# GWAS/QTL/MASweld_gwas(幂等,5 新表 bre_gwas_result/bre_gwas_snp/bre_qtl/bre_mas_panel/bre_mas_panel_marker 兜底;正常已由 create_all 建出)+ 900214 菜单翻转:
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_gwas.sql
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/bre_menu.sql
# 六探针(真引擎直跑,运行后自动清理):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_stability.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_stage.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_mtblup.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_gblup.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_dus.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_mlops.py
# 十二项真缺口:批1/批2/批3 探针(真引擎直跑,运行后自动清理)+ 全量回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_engines_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_modules_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gwas_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_gblup.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_refine_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gxr_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_corr_spatial_20260804.py
# 桃育种业务流全面完善:批A/批B 探针(真引擎直跑,运行后自动清理)+ 批C HTTP smoke + 全量回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_busflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/smoke_busflow_c_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_engines_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_modules_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gwas_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_gblup.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_refine_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gxr_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_corr_spatial_20260804.py
# 世代闭环:晋级落谱探针(真引擎直跑 11 组断言,运行后自动清理)+ 晋级主线回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_pedigree_closure_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
# 近交惩罚静默关闭修复:亲缘多源解析探针(真引擎直跑 14 组断言,运行后自动清理)+ A6 亲缘回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_data_mating_gain_20260804.py
# EBV 回退方法学修复:direct 优先/子代测验降权/双侧去重探针(真引擎直跑 5 组断言,运行后自动清理)+ 亲缘/批次回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_ebv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
# 数据质量离群值方向语义修复:A6 探针(真引擎直跑,运行后自动清理)+ 回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_data_mating_gain_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
# ΔG 投影假设 + 工程健壮性打磨:spatial 降级场景探针(真引擎直跑,运行后自动清理)+ A6 note 断言 + 回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_data_mating_gain_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
# A–F 六项缺口·批1 父本验证 + 近交衰退:双探针(真引擎直跑,运行后自动清理)+ 全量回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_parent_validation_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_inbreeding_depression_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_data_mating_gain_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
# A–F 六项缺口·批2 GS 家系 CV + 试验设计深度:双探针(真引擎直跑,运行后自动清理)+ 全量回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_trial_design_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gs_family_cv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_busflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
# AF 六项缺口·批3 OCS + MABC:双探针(真引擎直跑,运行后自动清理)+ 全量回归(含 _candidate_ebv_map 抽取后 mating/audit 双核对):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_ocs_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mabc_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gwas_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_ebv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_busflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_b8_seed_lot.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_prediction_rigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_audit_fix_20260805.py
# 近交衰退正确性修复(6 组断言:方向感知 asc 病指 + 深层系谱多世代 F)+ 全量回归(13 套):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_inbreeding_depression_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_ocs_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mabc_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_ebv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gs_family_cv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_trial_design_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_parent_validation_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_engines_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_modules_20260805.py
# A–F 六项缺口·批4 分子亲本验证 + 试验设计深度:双探针(真引擎直跑,运行后自动清理)+ 全量回归(rcbd 路径零变化 + 13 套):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mendelian_check_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_trial_design_ext_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_trial_design_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gwas_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_ebv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gs_family_cv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_ocs_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mabc_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_engines_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_modules_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_prediction_rigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_inbreeding_depression_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_parent_validation_20260805.py
```
# 批5 区组随机效应 + 孟德尔落库隔离 + 统计引擎数值校验:三探针(真引擎直跑,运行后自动清理)+ 27 套全量回归(含 gxe/gxr/mendelian_check/trial_design 零变化):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_ablup_block_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mendelian_persist_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_stats_numerics_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mendelian_check_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_trial_design_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_trial_design_ext_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gxe_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gxr_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_molrigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gwas_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_kinship_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mating_ebv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gblup_cv_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gs_family_cv_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_batch_selection_20260803.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_ocs_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mabc_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_base_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_engines_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_gaps_modules_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_prediction_rigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_inbreeding_depression_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_parent_validation_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_gblup.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_corr_spatial_20260804.py
```
# 批6 规划↔目标↔试验 可追溯性闭环:新探针(真引擎直跑 17 断言,运行后自动清理)+ weld SQL(幂等,可重跑)+ 全量回归:
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_plan_trace_20260805.py
PGPASSWORD=dpb psql -h localhost -p 5432 -U dpb -d dpb -w -f backend/sql/weld_plan_trace.sql
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_plan_trace_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_audit_20260805.py
# 批7 统计引擎十模块 golden 复查·系谱键空间错位修复:新探针(真引擎直跑 21 断言,运行后自动清理)+ 回归(版本断言已同步 v2.28):
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_rg_golden_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_advanced_mtblup.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_prediction_rigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mendelian_persist_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_statsflow_20260805.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_spatial_sparse_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_prediction_rigor_20260804.py
PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e_mendelian_persist_20260805.py
```
> **科学正确性收口**:方向标注后,低优性状(裂果率/病害级别/酸度等 asc)在指数、EBV 排行、决策预览、轮次对比中一律按"越小越优"参与,与育种目标语义一致;Smith-Hazel 的 b 符号、加权 Z 的贡献方向均按 direction 归一,不再存在"高 EBV=优"的隐含假设。**可追溯性收口**bre_plan 不再孤立——plan→target→cross_combination→tree(目标链)与 plan→trial→trial_study→tree(试验链)双链闭合,`GET /bre/plan/trace/{id}` 一查到底;三 FK 均可空,存量孤目标/独立试验不受影响,新数据挂链即可查(渐进式,不强制回填)。
# 18.21 前端 TAB 陈旧数据修复:KeepAlive 切回自动重拉真实数据(2026-08-05,前端框架级,无版本变更)
> 用户反馈:授粉管理、花粉档案等「第2、3个 TAB」页面,切换过来后列表仍是旧数据,点刷新才变真实数据。根因:`fa-page-content` 默认 KeepAlive 缓存页面,切换 workbar 标签时组件不重新 mounted → `onMounted` 不重跑 → 列表停留旧快照。框架级修复(覆盖全部 useTable 页面,而非逐页打补丁)。
**根因链(两层)**:① `hooks/core/useTable.ts``onActivated` 只置 `tableViewActive=true`fetch 内 guard 防失活期拉数据),从不主动重拉;`onDeactivated``cancelRequest()`。KeepAlive 切回 → `data.value` 仍是旧快照。约 30 个 module_bre CRUD 页共用 useTable,仅 3 页有手动 onActivatedtree 的 `refreshData()`、pollination/pollen 的下拉重载),故框架层修一处全覆盖。② **跨实例去重键不含 API 身份**`globalListNetworkInflight` 的 dedupeKey 仅由 `stableDedupeKeyFromParams(requestParams)` 生成(跳过 undefined 字段),而所有 module_bre 列表页默认参数形状相同(`{page_no:1, page_size:10}`)→ 硬刷新后多个 tab 并发挂载,各页 `onMounted` 并发发请求,**页面 A 复用页面 B 的 in-flight 响应**(字段与 prop 不匹配 → 列表只剩序号列有值,其它列空;这正是用户硬刷新后看到的"只有序号列")。点刷新(`refreshData`)时该 key 已无 in-flight,走自己的 HTTP → 正常。此 bug 既存,但激活重拉后并发概率骤增而被暴露。
**改动**
1. **`frontend/web/src/hooks/core/useTable.ts`**:新增 `tableActivatedOnce` 标志;`onActivated` 首次(与 mounted 重合)跳过,之后每次恢复激活 → `debouncedGetDataByPage.cancel()` + `clearCache(CLEAR_CURRENT, "恢复激活刷新")` + `getData()`(强制 HTTP 重拉,in-flight 去重仍生效)。守卫 `(immediate || data.value.length > 0)` 保持 `immediate:false` 页面(cronjob 定时页)"不自动加载"语义不变。**另修去重键**:新增 `apiIdentity = apiFn.toString()``dedupeKey = \`${apiIdentity}::${stableDedupeKeyFromParams(requestParams)}\``——跨实例去重仅在**同一接口**间合并,不同页面的同形参数不再错配(`globalListNetworkInflight` Map 全局共享,两处 in-flight key 均带上接口身份)。
2. **`frontend/web/src/views/module_bre/statistics/index.vue`**:抽取 `refreshPageLists()`onMounted 全部 15 个 load 调用),`onActivated``pageActivatedOnce` 守卫后续激活重载(统计页多数据区整体刷新)。
3. **`frontend/web/src/views/module_bre/pollination/index.vue`**`onActivated` 重载 5 个下拉(cross_combination/plot/personnel/tree/pollen 选项),表格由框架处理。
4. **`frontend/web/src/views/module_bre/pollen/index.vue`**`onActivated` 重载采集父本树下拉。
5. **`frontend/web/src/views/module_bre/tree/index.vue`**:移除冗余手动 `onActivated(() => refreshData())`(由 useTable 框架覆盖,避免双重重拉)。
**验证**`vue-tsc` EXIT=0(无类型回归);vite dev:5666base /web)热更新模块均 200 + 关键字符串存在;后端 `/bre/pollination/list` 实测返回字段完整(combination_name/pollination_date 等有值,确认非后端问题);浏览器行为需硬刷新(Ctrl+Shift+R,重建 KeepAlive 缓存与 HMR 旧实例)后实跑确认。备份镜像 `Temp/claude/backup_tab_stale_20260805/`
# 18.22 O1 花期数据消费补强:结构化花期区间 + 配对花期软警示 + 授粉窗口规划(2026-08-06v2.30
> 用户反馈 O1 花期字段(flowering_period 5 档字典)零消费属真实数据盲点,但定性为 **P1 数据消费补强 + 辅助信息**(非与 S-等位同量级的正确性硬防呆)。拍板三个落地档位:① 花期数据建模升级(结构化区间,前置);② `mating_recommend` 返回体加花期重叠软警示(重叠/错开/需采粉贮藏,**不硬阻断**);③ 授粉窗口规划消费 `bre_pollen`(新端点 `GET /bre/pollen/window-plan`)。花期建模新增列 → `_DATA_VERSION` v2.29 → **v2.30**。
**① 花期建模升级(germplasm 双 Date 列)**`bre_germplasm` 新增 `bloom_start_date`/`bloom_end_date`(Date 可空,年际重复物候——比较/投影时取月日、忽略年份;`flowering_period` 5 档字典保留作粗粒度 fallback)。weld 幂等 SQL`backend/sql/weld_flowering.sql`)+ 双处版本 bump。连锁全链:model.py / schemaCreate+Update/ serviceexport mapping_dict + import header_dict + fields 解析 + 模板 header_list/ 前端 germplasm 表单两个 date-picker、表格列、详情项。**前端设计取舍**:useCrudForm 无提交前 transform hook → 弃 daterange(需 bloomStartRange↔两字段双向映射),改用**两个独立 date 字段**直绑 `bloom_start_date`/`bloom_end_date`(与 acquisition_date 同模式,零转换)。
**② mating_recommend 花期软警示**:新模块级 helper `_bloom_overlap(female, male)`statistics/service.py`_md()` 月日→年序日 1..366)——优先结构化区间(月日年际比较),缺区间 fallback 到 `_BLOOM_TIER_ORDER` 5 档字典序号(相邻/同档视为重叠)。四态返回 (status, msg)`overlap`「花期重叠,可同期授粉」/ `store`「父本先开花,需采粉贮藏至母本花期授粉」(me_d < fs_d/ `offset`「母本先开花,父本花期在后,注意母本柱头可授期」(fe_d < ms_d/ `unknown`「花期未知(缺结构化区间与档位)」。pairs 循环(female=gs[i], male=gs[j] 语义)在 `s_compat` 旁加 `bloom_status`/`bloom_msg`;非重叠三态追加进 flags[](前端红色 tag 自动渲染),overlap 不进 flags——**软警示不硬阻断**。前端 pairs 表加「花期」列(重叠=success tag / 需采粉贮藏·错开=warning tag / 未知=info tag)。
**③ 授粉窗口规划(window-plan)**:新端点 `GET /bre/pollen/window-plan?window_start=&window_end=`controller + service.window_plan,纯计算不落库)。`_project_bloom(g, ref_year)` 把花期投影到窗口起始年:结构化区间按年际月日(桃花期 3-4 月单年窗口假设),缺区间 fallback `_BLOOM_TIER_SPAN`(5 档 → 代表区间,粗粒度标注)。花期种质给花粉覆盖三态 `covered`(整段有批次 `collect<=bs and expiry>=be`/`partial`/`none`(无覆盖 → n_need_pollen + 提示需采粉贮藏或同期授粉);库存侧给批次窗口状态 `full`(全程覆盖)/`expiring`(窗口内到期)/`entering`(窗口内采集、有效期出窗)/`expired`(窗口前失效)/`not_started`(窗口后采集)。窗口反向 409。前端 pollen 页顶部「授粉窗口规划」卡片:daterange 默认本年度/次年花期(3-4 月在当年、否则次年 03-01~04-30+ 生成按钮 + 缺粉 alert + 花期覆盖表 + 库存状态表;pollen.ts 加 `getWindowPlan` + `PollenWindowPlan`/`PollenBloomItem`/`PollenInventoryItem`/`PollenLotRef` 类型。
**验证**`e2e_o1_bloom_20260805.py` 探针全过——① CreateSchema→CRUD 双 Date 列落库;② 6 种质 15 对(重叠/错开/需采粉贮藏三类 + 档位 fallback mid×very_early→store + 区间×档位混合对→unknown,flags 仅非重叠进警示);③ 窗口 A(03-05~04-08)花期覆盖三态 covered/partial/none + 档位投影种质、窗口 B03-10~03-30)库存五态 full/expiring/entering/expired/not_started + 窗口反向 409。`vue-tsc` EXIT=0。全量回归 + `run_ci.py` EXIT=0 零回归。版本连锁:4 e2e 探针(statsflow/spatial_sparse×2/prediction_rigor/mendelian_persist+ o234 tc 断言 v2.29→v2.30。备份镜像 `Temp/claude/backup_o1_bloom_20260805/`