Files
dpb/doc/桃育种系统模块扩展需求规格.v2.20.md
T
34047007@qq.com b95053c52c init: 初始化 dpb 桃育种系统代码库
前后端 + 后端 FastAPI 全量源码、部署脚本与文档。
2026-08-06 00:17:49 +08:00

1324 lines
213 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.
# 桃育种系统 · 模块扩展需求规格(V2 草案)
> 编制日期:2026-07-28
> 依据:通用育种软件功能清单(用户提供) + 国际成熟方案(BrAPI / BMS·Breedbase / RosBREED / MIAPPE / Crop Ontology / FAO-MCPD / Genesys + `doc\果树所\育种\yz.sql` 真实桃性状 + 现有 14 个 breeding 域
> 状态:**草案,待评审**。字段取值/枚举以「待确认」标注处需与业务方对齐后再落地(遵循"不确定不擅自动手"准则)。
## 版本历史
| 版本 | 日期 | 说明 |
|---|---|---|
| v1.0 | 2026-07-28 | 初稿+复审:14 域对标、新增 7 模块、§8 复审(9 遗漏)、EAV 定稿为混合固定列。BrAPI/MIAPPE/team/库存 待定 |
| v1.1 | 2026-07-28 | 决策落地:① 采纳**直接对齐 BrAPI API**(新增 BrAPI 只读适配层)② 采纳 **MIAPPE 合规****不建 team 模块**(仅数据隔离,不需要,留 RBAC+created_id)④ **库存延后**(暂用报表) |
| v1.2 | 2026-07-28 | 取值决策(用户授权"你来定"):敲定 stage/generation/group_type/design_type 四枚举(§9+ propagation 纳入一期(§3.8);trait 种子建议 yz.sql;字段表补 generation/germplasm_id |
| v1.3 | 2026-07-28 | §8 二次复审落地:① **MET 链路彻底修补**trial_study.block_count + planting.trial_study_id + tree.trial_study_id/block_no + plot.block_no),与库存 `seed_lot` 一并建模,形成 seed_lot→seedling→planting→tree→trial_study 选择强度链(§3.13/§4/§5)② §0 原则1 与混合模型对齐(修订措辞)③ observation/field_operation 改显式 FK(弃多态)④ 补 environment_condition / audit_log / selection_rule / prediction 字段规格(§3.9–§3.12)⑤ tree_evaluation 明确"按 pa_four 扩列"+ 统一性状值视图 ⑥ 补「选择阈值规则」+「批量表型导入」规划 ⑦ 文档计数/枚举对齐修正 |
| v1.4 | 2026-07-28 | 国际基准三轮复审(BrAPI/Breedbase/RosBREED/MIAPPE/Crop Ontology/FAO-MCPD/Genesys)落地:① 新增 `trial_study_entry`entry 清单+entry_numberMET 设计矩阵)② site 补 lat/long/elevation(空间 BLUP/MIAPPE)③ observation 加 `status` 校验态(数据质量)④ trait 加 `ontology_uri`Crop Ontology 对接)⑤ 明确 tree.trial_study_id/block_no 为**派生**(单写点=planting,防双真相漂移)⑥ germplasm 补护照描述符块(FAO-MCPD)⑦ 新增 `genotyping_dataset`+marker.panelGS 训练群体分组)⑧ selection_result 加 `rule_id`(决策闭环)⑨ 补 crossing block 父/母本树(pollination 挂 female/male_tree_id)⑩ experiment_factor / breeding_report / breeding_program 标记延后。详见 §8.6 |
| v1.6 | 2026-07-28 | 第五轮复审(v1.5 自洽+国际盲点)全部采纳:① tree_evaluation 加 trial_study_idA1 核心性状环境键)② planting 粒度=block 级 + entry 跨 block 多 plantingA2)③ 新增 planting_treatment 关联表(A3)④ seed_lot.used_count 明确粒数(A4)⑤ §4 补 tree_photo 行(A5)⑥ tree→germplasm 重复测量聚合 EBVA6)⑦ 国际补强:marker.assembly_version、genotype_call VCF/GP、trial_study.season、observation.validated_by/date/unit、trait.method_uri/scale_uri、planting.propagation_id、observationUnit level、kinship A 矩阵、selection_rule EBV 阈值、breeding_program 自由文本说明 ⑧ selection_result.trial_study_id、新表数据权限约束(并补齐 v1.5 因替换异常遗漏的 §3.14/treatment 行/used_count)。详见 §8.8 |
| v1.7 | 2026-07-28 | V2.11 方案书《统计分析决策支持》逐条对照评估落地(用户确认报告一期必须):① **`breeding_report` 确认进一期**(P2,年度 Word/PDF 报告实体+生成服务,不再仅只读端点,原 v1.4 延后项移除)② **`breeding_prediction_value` 值表前移 V1.1**(与 V1.1 统计引擎同期持久化 EBV,支撑年遗传趋势图/双轨选择/亲本单株决策;仅 GS 模型训练留 V2.0)③ `tree_evaluation``crop_load`(坐果量评级 1/2/3 协变量,降果实性状环境误差,专册 1.3)④ `breeding_trait``valid_min/valid_max`(自定义生物学合理阈值,数据质量校验/异常标记)⑤ 超期预警/通知列为工程项(cron + selection_rule,不阻塞数据模型)。详见 §8.9 |
| v1.8 | 2026-07-29 | 团队/课题组隔离收口(讨论定稿):**不建 team 模块,改用系统已有 `sys_dept` 承载"课题组"**,启用框架"本部门及子部门"数据范围实现**课题组间隔离**;breeding 业务表**不加 `owner_team` 字段**(隔离靠创建者 `dept_id` 推断,由 `Permission._permission_condition()` 自动注入)。边界:性状字典/选择规则/种质/基地地块/人员等**公共基础数据跨组共享**;育种流程(杂交→评价)与统计分析(育种值/指数/报告)**按课题组隔离**。落地为配置级(建 dept 节点+配角色 data_scope+用户归属),非代码,需确认真实课题组清单后执行。 |
| v1.9 | 2026-07-29 | **枚举归属决策(方案A 已定)**:性状的**量表选项/范围**单一真相内联在 `breeding_trait.scale_json`categorical 存 `options`、numeric 存 `min/max/step`),**不进 `sys_dict`**`sys_dict` 仅承载"实体状态/分类枚举"(§9 的 `breeding_stage`/`breeding_generation``tree.status``germplasm_type` 等,非被测变量)。与"生成器机制 A/B/C"是两回事,勿混。详见 §3.1 / §0 原则1。 |
| v2.0 | 2026-07-30 | **遗传评估数据模型架构决策锁定**:① 新增 **`breeding_clone` 独立系谱表**(§3.0clone_id/combination_id/母父本/planting_year/status**无砧木**),与 `germplasm`(亲本/种质档案)**分离**,聚合路径由 `tree.germplasm_id`→germplasm 级 EBV 改为 `tree.clone_id``breeding_clone` 级 EBV(§3.0/§4/§5 同步修订)② `breeding_trait``stage`juvenile/evaluation,与 `category` 正交)③ 新增 **`breeding_rootstock` 砧木字典**(§3.17,只挂 observation 层)④ 新增 **数据质量门禁**(§3.16:缺失标记/异常值/单位强校验/按(clone_id,地点,年份,性状名)去重)⑤ 显式锁定 **砧木建模铁律**(§5.x:记 observation 层 + BLUP 固定效应扣除 + 绝不进 A 矩阵)⑥ 新增 **间接早选**(§5.y)⑦ 实施路线最前插入 **第0阶段 数据治理**(占40%、前置)。均为决策锁定、方案态,待用户"做"后落地 |
| v2.1 | 2026-07-30 | **review 修订(R1R9**:① **R1** §4 tree 加 `clone_id`(FK→breeding_clone,定植必填,聚合锚点) ② **R2** 系谱升级为独立 `breeding_pedigree`(§3.18,个体覆盖 clone+germplasm,dam/sire 指回本表递归闭环)`breeding_clone.female/male_parent_id` 降冗余;`germplasm.pedigree` 自由文本移除 ③ **R3** `breeding_prediction_value``heritability`(h² 同批次落库)、个体锚点改 `clone_id`**R4** 新增模型健康监控(§5.z:h²连年突降/排名翻转告警) ⑤ **R5** 报告 §5.2 模块1 去掉种质内联表型/系谱 ⑥ **R6** 报告 R 引擎统一 subprocess 隔离(弃 rpy2) ⑦ **R7** 统一表名 `breeding_observation`**R8** GCA/SCA 定位为亲本选配辅助 ⑨ **R9** 混合模型加 `clone×year` 随机互作。仍方案态,待"做"落地 |
| v2.2 | 2026-07-30 | **深度复审 A–H 全量落地(用户逐条确认 + F1/F2 架构拍板)**,详见 §8.10:**A 组内部矛盾**——A1 `tree.clone_id` 改为「实生苗定植可空/参试无性系必填、入选晋升才建 clone」(删"定植必填/1树=1clone");A2 `produced_clone_id`=被扩繁原 clone(沿用不新建);A3 全文 `rootstock_id` 统一 FK→`breeding_rootstock`(删 FK→germplasm);A4 A 矩阵系谱以 `breeding_pedigree` 为唯一权威、combination 父母本仅作派生源。**B 组统计**——B1 `heritability` 由明细移主表 `breeding_prediction`;B2 术语正名**加性(狭义)遗传力**、落库取克隆均值 h²=V_clone/(V_clone+V_e/k̄)B3 补 sommer 基线公式;B4 双轨选择统一 clone 级判定。**C 组门禁**——C1 门禁作用于 `breeding_trait_observation` 长表;C2 加 `issue_status`;C3 门禁×状态机衔接。**D 组 clone 居中**——D1 `selection_result`+clone_idD2 `breeding_clone`+generationD3 `trial_study_entry`+clone_idD4 补 tree↔clone 状态流转矩阵。**F 组架构(本轮拍板)**——F1 **裁定走单一长表、废固定列、报表用视图 pivot**F2 保留两张长表职责正交(`breeding_trait_observation` 单株鉴定明细/喂 EBV`breeding_observation` 仅 plot/combination+物候/不喂 EBV),plot 级果实均值由**统计 VIEW 聚合、不双写**;统计管线用普通 **VIEW 保 fresh**、看板层才用 **MV**(MV 不得作 BLUP 输入);F3 门禁关键键实生苗阶段退化为 tree_id;F4 判重键含 tree_id(保 clonal replicates);F5 §5.2 公式补 rootstock 固定效应。**G/H**——G1 统一编号服务定义+clone_id 序号扩位;G2 鉴定类表禁物理删+UPDATE 强制 auditG3 method 文本+method_uri 受控合并;H1-H3 打磨。仍方案态,待"做"落地 |
| v2.3 | 2026-08-04 | **统计引擎两轮 P0 代码落地(自 v2.0 起首次从方案态推进到可运行,均 e2e 验证通过)**,详见 §8.11 / `桃育种系统统计引擎实施记录.md`:① **G×E 交互引擎**(§5.2 互作项落地)——`run_ablup``gxe=True` + `gxe_env=site/year`method=GXEBLUP),site→自动固定效应 `trial_study`、year→`year`,σ²gxe/gxe_ratio/n_cross_env 落 `breeding_prediction.note`,不可辨识门禁(无跨环境重复/单元内无重复)→409,同 clone 多株坍缩为基因型节点 `c{clone}`,异步 `StatisticsJobModel` job_type=GXE/ABLUP+SUCCESS/FAILED;② **性状方向标注**(§3.1/§5.9/§5.z 落地)——`breeding_trait``direction`(desc/asc)/`into_ebv`(1/0)/`default_h2`(先验),选择指数(zsum/smith_hazel/EBV 排行/决策预览/轮次对比按方向归一,低优性状(裂果率/病害级别/酸度)不再选反;`into_ebv='0'` 仅从选种候选剔除;`default_h2` 无实测 h² 时兜底;并修复两处结构性 bug(`ebv_ranking` 方向盲区→读时重排、`compare_predictions` 硬编码降序→方向感知) |
| v2.4 | 2026-08-04 | **桃田间刚需·花粉档案落地(§3.19 + §4 pollination 修订,e2e 验证通过)**:① 新增 **`breeding_pollen` 花粉档案表**(§3.19)——批次号/采集父本(树级 `male_tree_id`,混合/外地采集可空)/采集日期/采集方式/采集量/贮藏方式(4℃/-20℃/-80℃/液氮)/活力测定(方法+百分值+测定日期,TTC 染色率/离体萌发率)/有效期;**授粉窗口 = [采集日, 失效日] 派生**,不建独立计划表 ② §4 pollination 补 `pollen_lot_id`FK→bre_pollen,授粉所用花粉)+ **一期文档规划但遗漏的 `pollination_method`(授粉方式)**,窗口校验(授粉日期须落在批次 [采集日,失效日] 内,否则 409)落地在 pollination service`available_lots` 端点支撑"当前花期可用批次"下拉 ③ 菜单 900056(杂交配组)+按钮 E 段 900601-900608,前端花粉 CRUD 页 + 授粉表单集成批次选择 |
| v2.5 | 2026-08-04 | **决策正确性·选择指数无性系级聚合落地(§5.3 / §5.7,e2e 验证通过)**:桃无性繁殖,**选择指数单位由「树级」升为「无性系级」**——`selection_index` 新增 `aggregate` 参数(默认 `clone`),先按 `tree.clone_id` 把同系多株聚合成一个遗传实体(EBV 均值按**可靠性加权**:`Σ(ebv×rel)/Σ(rel)`,全 rel=0 回退简单均值),再在 clone 级算 zsum/Smith-Hazel 排名;**自株退化**(无 clone_id 的未晋升实生株 → 每株独立单元,不进聚合),保证实生苗阶段不塌缩;`apply_selection` 按**遗传实体**写决选——入选 clone 一条记录(`clone_id` 指向全系 + 溯源株 + reason「系内N株」),self 株逐株写,入选株命中选择规则晋级时晋升建 clone(幂等)。旧行为保留:`aggregate="tree"` 回退单株级。详见 §8.13 / `桃育种系统统计引擎实施记录.md` v1.2 |
| v2.6 | 2026-08-04 | **统计严谨·配合力交配设计落地(§5.3 / §5.5,e2e 验证通过)**:修复统计严谨缺陷——`combining.solve` 原只实现 Griffing 对称全双列,现按 `design_type` 分支(`full_diallel` 完全双列 / `partial_diallel` 部分双列 / `line_tester` line×tester NCII / `nciii` NCIII 测交);NCII/NCIII 走**双因素模型** `y=μ+l_i+t_j+(lt)_ij`line 母本 / tester 父本,各自 Σ=0 约束,SCA=互作=残差,自由度 df_line=n_l-1 / df_tester=n_t-1 / df_sca=残差),不再一律按全双列算错;`bre_cross_combination` / `bre_combining_ability``design_type``run_combining` 按设计过滤只纳入一致组合,GCA 标准误内嵌 `anova_json.gca_se`;角色重叠(同亲本既作 line 又作 tester)→ 409 拒绝,NCIII 门槛 tester 恰 2 个。详见 §8.14 / `桃育种系统统计引擎实施记录.md` v1.3 |
| v2.7 | 2026-08-04 | **统计严谨·预测完整性与 MLOps 复现性(七条复审逐条落地,e2e 验证通过)**,详见 §8.15 / `桃育种系统统计引擎实施记录.md` v1.4:① **Smith-Hazel 遗传相关改可靠性校正**Calo`r_g = r_EBV/√(rel_i·rel_j)` 钳制 [−1,1],替代裸 EBV 皮尔逊相关;真 MT-BLUP 记为引擎级后续项,§8.15 备注)② **PA 落库**——`bre_prediction_value``pa`=√reliability,预测准确度),批次 `bre_prediction.accuracy` 改填真 PA=√(均值可靠性),不再填误名的"均值" ③ **MLOps 溯源**——`bre_prediction``data_version`/`input_hash`(SHA256:表型+系谱确定性序列化)/`engine_version`,同数据重跑哈希一致、改观测必变(数据漂移可检测)④ **germplasm_id 填充**——`run_ablup` 写 EBV 行时填 `tree.germplasm_id`,亲本级 EBV 可查 ⑤ **砧木字典扩列**——`bre_rootstock``dwarf_class`(矮化/半矮化/乔化/柱状)/`compatibility`(砧穗亲和性强/中/弱)选配决策信息(BLUP 固定效应维持够用)⑥ **空间竞争协变量**——`run_ablup` 新增 `covariate="competition"`:同 (plot,block) 网格 Chebyshev 邻域株数作协变量(边缘株相邻少隐式捕捉边缘效应),缺 row/col 数据时显式报错;`bre_tree.row_no/col_no` 数据能力已在录入/导入/导出全链路就位 ⑧ **组合得失漏斗 v_combination_funnel**(同日追加,§8.16):按组合汇总 花→果→种→苗→定植→树→入选 六级派生指标(结实率/出苗率/选择强度),数据源全为既有表、普通 VIEW 保 fresh、只读端点可查,配合力第一手证据落地 |
| v2.8 | 2026-08-04 | **组合得失漏斗落地(§3.13 选择强度链的派生指标收口,e2e 验证通过)**:既有 `bre_pollination.flower_count/effective_count``bre_seed_lot.seed_count/germination_rate``bre_seedling.seedling_count``bre_planting.tree_count``bre_tree``bre_selection_result` 六级数据本已齐全,但**无任何按 `bre_cross_combination` 汇总的派生指标**——结实率/出苗率/选择强度未滚到组合层、配合力上下文吃不到(`run_combining` 只取组合表型均值)。本轮补普通视图 `v_combination_funnel`(花→果 结实率、种→苗 出苗率、树→入选 选择强度,缺环节组合比率列留 NULL)+ 只读端点 `GET /statistics/combination-funnel`。详见 §8.16 / `桃育种系统统计引擎实施记录.md` v1.4 |
| v2.18 | 2026-08-05 | **遗传链完整性两次修复(用户先后报告「建种质断链」与「近交惩罚静默关闭」,逐条核实确认 + 拍板落地,e2e 验证通过,§8.28 / `桃育种系统统计引擎实施记录.md` §18.5/§18.6**:① **世代闭环修复**——`selection_result._promote_tree_to_clone` 单株晋级到 line/regional_trial/released 建 `bre_germplasm` 时**同步落 `bre_pedigree`**child_code=品种名、dam/sire=tree.dam_id/sire_id 回退组合 female/male_parent_id、combination_id、generationchild_code 幂等查重)→ 晋升种质不再被统计引擎当 founder,跨世代系谱链闭合(A-BLUP/亲缘矩阵/近交规避/遗传增益滚雪球恢复);② **近交惩罚「静默关闭」修复**——`mating_recommend` 亲缘矩阵旧实现靠 `bre_pedigree.child_code` 与种质 cultivar_name/accession_no **精确字符串匹配**,大小写/空格/代号 任一错配即全空 → rmat={} → 每对 r=0 → kin_pen=max(0,0thr)=0 → 近交规避整体失效且**无任何告警**。重写 `_germplasm_pedigree` 为**多源级联**:① bre_pedigree 规范化(strip+casefold)名称反查(显式系谱为权威)→ ② `tree.germplasm_id` 直连 FK 兜底(升种质树自带亲本,多对去重后**唯一一致**才采纳、歧义回退 founder 不武断选)→ ③ founder;祖先同源 BFS 展开 + 去重(修复候选既是 child 又是祖先时 `g{id}` 重复追加 → `blup.relationship_matrix` 抛『系谱个体重复』崩溃);`mating_recommend` 新增 **kinship_status(ok/partial/none) + kinship_warning + 逐对『亲缘未解析(r 按 0 计)』旗标**——绝不静默 no-op。验证:探针 14 组断言全过 + A6 回归(显式系谱仍压过冲突 FK trial 亲本,r=0.5 保真)+ HTTP 核验新字段经真实端点 |
| v2.19 | 2026-08-05 | **选配「亲本 EBV」回退逻辑方法学修复(用户报告 §8.28② 近交修复同一区域的方法学缺陷,核实确认 + 拍板落地,e2e 验证通过,§8.29 / `桃育种系统统计引擎实施记录.md` §18.7)**`mating_recommend` 旧实现对无直接 EBV 行(ABLUP/GBLUP 按树写、germplasm_id 为空)的候选种质,用**「其子代树 EBV 均值」回退代表该亲本育种值**——三个方法学错误:① 子代测验(progeny-test)值是子代世代的预测值(≈½亲本BV+共亲本渗入+孟德尔抽样),**不是亲本自身育种值**,冒充会误导选配排序;② 同一子代树若双亲都缺直接 EBV,**等权计入 dam 与 sire 两侧**(如 FM×MM 双亲均无 → 该树均值重复计、稀释);③ 跨组合混合无区分。修复:**directgermplasm_id 直连的亲本自身预测值)优先**;回退仅当亲本无自身值时才用,**显式标注「子代测验近似」并打分降权 0.5**(`_EBV_SOURCE_FACTOR = {direct:1.0, progeny:0.5, missing:0.0}`score=w_ebv·((f_a·ebv_a+f_b·ebv_b)/2)w_kin·pen,回退近似绝不掩盖 direct);**双亲均缺直接值的子代树剔除**(无法归属,防双侧等权重复计);记 `n_progeny`/`n_combos` 供调用方辨别跨组合混合;返回体加 **`candidate_ebv`**(每候选 value/source/n_progeny/n_combos+ `ebv_source.coverage`direct/progeny/missing 计数)+ 逐对旗标「亲本EBV为子代测验近似(降权0.5)」/「亲本无EBV(按0计)」——EBV 来源显式可查,绝不静默降级。验证:探针 5 组断言全过(direct 优先不被树级值污染 / progeny mean=(6+8+10)/3=8 n_combos=2 / 双亲均缺树剔除 P3×P4=0 / P0×P1 加权 mid=7.0≠9.0 原始 / score 降序) + A6/亲缘/批次/底座四回归零回归 + HTTP 核验新字段经真实端点 |
| v2.20 | 2026-08-05 | **数据质量报告「离群值」语义错位修复(用户报告 §8.17①/§8.23① A5 数据质量端点的 IQR/MAD 异常标记把任何偏离分布的值都标「离群株」,与育种目标方向错位——正向偏离恰恰是要选的精英单株,核实确认 + 拍板落地,e2e 验证通过,§8.30 / `桃育种系统统计引擎实施记录.md` §18.8)**`data_quality_report` 旧实现用 IQR(Q11.5IQR/Q3+1.5IQR) 超界 + MAD 稳健 z(>3.5) 把一切偏离标为「疑似异常」,但桃育种中**正向偏离就是要选的精英单株**(果重/固酸比/可溶性固形物的高值、裂果率/病指的低值即选育对象,与高 EBV 高度相关),把精英候选标成「疑似录入错误」会误导决策。修复:**偏离方向与选育目标对齐**——按 `bre_trait.direction`desc/None=高值优、asc=低值优)判定 `desirable_high`,超界株按偏离侧**双通道分流**:**同向偏离 → `extreme_candidates` 极值候选(精英)**(选育目标内的极端表型),**反向偏离 → `outliers` 疑似录入错误**(高值优性状的异常低值 / 低值优性状的异常高值)。返回体新增 **`direction`** + **`extreme_candidates`**tree_id/value/z/side/class/reasons+ `summary.n_extreme_candidates``outliers` 只含反向株、`has_warning` 语义收紧为「疑似录入错误」。前端数据质量 tab 改**双表 + 选育方向指示**(精英=success 标签 / 错误=danger 标签 + 方向说明 + 误报归零后绿色 info alert)。验证:A6 探针 17 株(15 正常 + 精英高值 16.0 + 错误低值 2.0direction=desc)断言精英进 extreme_candidates/class=extreme_candidate/side=high、错误进 outliers/class=outlier/side=low、**互斥不串表** + summary.n_extreme_candidates=1;回归 A6/亲缘/批次/底座四套零回归;后端重启 + HTTP 核验 asc 裂果率 bB_DIR5668 与 desc 果重 dA_DIR5668 两性状 `direction`/`extreme_candidates`/`outliers`/`summary.n_extreme_candidates` 经真实端点正确返回(真实数据无极端值 → 双表空 = 无误报) |
| v2.9 | 2026-08-04 | **精修项四连发(用户核实四条缺口、拍板全部落地,e2e 验证通过)**,详见 §8.17 / `桃育种系统统计引擎实施记录.md`:① **DUS/品种保护「数据能力(三表)」**(§2 原 ⏳待建,按拍板档位落地)——`bre_dus_descriptor`UPOV TG/53 描述符模板)/`bre_dus_test`(测试记录)/`bre_dus_observation`(观测,UNIQUE(test,descriptor))三表五件套 + TG/53 桃描述符种子 15 条(trait_code→bre_trait LEFT JOIN 关联 8 条)+ Excel 导入导出/模板 + 菜单 900230 真实页与 G 段按钮 900800-900808;② **stage 感知**v2.0 ① `trait.stage` 终被消费)——`PredictionModel.stage` 落库,选择指数/决策预览按 juvenile/evaluation 过滤、跨阶段混用返回 `stage_warning`/`skipped_stage`;③ **模型外部验证**(可靠性原仅 PEV 法)——`blup.kfold_cv`(sire 家系分层留出避免乐观、逐折容错、留出 EBV 系谱预测)+ `bre_cv_result/fold` 落库 + 端点,**ABLUP/GXEBLUP 双支持**;④ **AI 伦理·分组偏差**——按 site EBV 公平性报告(site_summary deviation/flagged + rank_consistency Spearman + gxe_pattern),只读不建表 |
| v2.17 | 2026-08-05 | **桃育种业务流全面完善(用户要求「对现有功能,结合桃育种实际业务流程与需求,进行全面测试分析,并完善」;三路审计收敛 10 项真缺口,拍板全部实施 + 两裁决:不恢复导入按钮 / 采收入口走农事操作 op_type=harvest;批A 业务数据链/批B 统计算法/批C 前端,分三批独立 e2e + 全量回归零回归,§8.27 / `桃育种系统统计引擎实施记录.md` §十八)****批A 业务数据链(A1-A6)**——① 果实采收结构化入口(`bre_field_operation` 加 yield_kg/fruit_count/avg_fruit_weight/marketable_rate 四列,op_type=harvest 树级采收同步写 `bre_trait_observation` 4 行按 trait_code,plot 级只留操作记录)② 产量构成/物候/品质/生长量/描述性状种子(`bre_yield_phenology_traits.sql`:单株产量/果数/均果重/好果率/裂果率 + 盛花期/果实成熟期/落叶期 + 可溶性固形物/可滴定酸/固酸比 + 主干周长/树高/冠幅 + 果形/茸毛/离核/果皮底色/着色类型)③ 种质级观测(`bre_observation` 加 germplasm_id,描述性数据入口)④ 授粉→收种→种子处理补链(`bre_seed_lot.pollination_id` + `bre_seed_treatment.seed_lot_id`)⑤ EAV 观测校验(numeric/date parse + valid_min/max 越界 409 + 同(tree/plot/germplasm,trait,year,date)重复 409)⑥ 育种阶段自动设置 + 成株性状门禁(tree stage 按 breeding_generation 推断 F→juvenile/亲本嫁接→evaluation,童期树录成株性状 409);**批B 统计算法(B1-B4**——① type-B 多环境遗传力(`run_type_b_heredity` 复用 `mtblup.solve_bivariate` 把环境当"性状"精确 REML、env_dim=site/year、落 `bre_type_b_result` + POST /statistics/type-b-heredity + GET /type-b + /type-b/{id})② correlation_matrix 增 genetic 模式(`_genetic_corr_matrix` 逐对 bivariate 组装 G0、pheno 分支逐字节不变、不落库)③ selection_index 自动权重(auto_weights=True → 权重=default_h2 兜底 0.1、强制 use_h2=False 防双重相乘、direction 翻转、weights_json 记 __auto)④ UPGMA 层次聚类(`run_cluster` 纯 numpy 无 scipy、POST /statistics/cluster 不落库、输出 {clusters,merges,order});**批C 前端(C1-C4**——观测录入增强(observation 页 plot/站点/germplasm 过滤 + germplasm 表单、field_operation harvest 结构化表单)、统计可视化 EChartscorrelation 热图 mode 切换 + gblup 可靠性热图/EBV 趋势折线 + type-B 新 tab + cluster 树状图)、combination-funnel 前端入口对话框、stage_phenotype 容器同步(通用观测/农事操作翻真实页);`_DATA_VERSION` v2.15 |
| v2.16 | 2026-08-05 | **十二项真缺口补齐(用户全量现状盘点收敛 12 件真缺口,拍板只补这 12 件,分三批独立 e2e + 全量回归零回归,§8.24–8.26 / `桃育种系统统计引擎实施记录.md` §十七)**:**批1 引擎三件(solver 扩展独立路径)**——① ssGWAS(`gwas.py` 1.2.0 `_ssgwas``genomic.build_g_matrix` 岭保正定构 G → `solve_gblup` 全样本 GEBV û,**Wang et al. 单步 GWAS MEM 对角近似**反推标记效应 ê_j=(M_j'Z'G⁻¹û)/(2Σp_j(1p_j))、Var(ê)=σ²u/(2Σp_j(1p_j))Wald t=ê/SE → `fdist.f_pvalue`;共享 `_finalize`/`_bh_qvalues`/`_cluster` 后处理、G⁻¹ 岭兜底、无基因型样本报错、method=ssgwas 透传 + 前端下拉)② 全 MT-BLUP 多变量 REML`mtblup.py` 1.1.0 `solve_multi`:m 性状 y 堆叠 X/Z 块对角、Var(u)=G0⊗AG0 m×m 半正定)、EM-REML 迭代 G0+ve(单性状 REML 初始 + 特征值截断/Higham 投影保正定、max_iter 兜底不收敛→converged=False+warning),输出 G0 全元素 + r_g 矩阵 + n_iter/converged/warning`run_genetic_corr``full_mtblup=True` 一次 m 性状给完整 G0,逐对 bivariate 路径保活零回归)③ AR1×AR1 双参 ρ(`blup.py` 1.4.0 `solve_spatial``aniso`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 逐字节一致**;门禁/互斥/缺坐标逻辑不变);**批2 模块四件(标准 CRUD 9 端点五件套 + 前端页 + 菜单翻转)**——field_operation 农事操作 900051`bre_field_operation`op_type 字典施肥/喷药/修剪/灌溉/疏果/套袋/采收 bre_dict 灌入)+ observation 通用观测 900050`bre_observation` EAV 通用录入可挂 plot 级、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 + statusCRUD +「查看性状值」跳 statistics trait-values 复用既有视图);**批3 底座五件**——④ 审计切面(`bre_audit_log` + `base_crud` 三写方法事务内注入 CREATE/UPDATE/DELETE、UPDATE 字段级 diff 每变更字段一行、批量导入会话标志抑制逐行仅汇总 IMPORT 一条、`settings.AUDIT_BRE_ENABLED`+模型 `__bre_audit__` opt-in、`GET /bre/audit/list|detail`)⑤ 统一编号服务(`app/utils/number_gen.py` `NumberGenService` 规则配置前缀/日期/序列/回绕 + **`pg_advisory_xact_lock` 原子取号** + `bre_sequence` 表;迁移 4 处:cross_combination._gen_combination_codeYY+3位)/tree._gen_tree_no(组合-序号)/selection_result clone_code(组合-{:04d} 扩位)/seedling batch_noYP-…))⑥ 超期预警定时任务(每日 job 按 selection_rule 扫描——树 N 年未决策 / 花粉批次过期(采集日+有效期)/ seed_lot 超期 → 写 `bre_alert`alert_type/entity_type/entity_id/message/status+ `GET /bre/alert/list` + 前端「预警中心」页)⑦ 备份容灾(`backend/scripts/pg_backup.sh` pg_dump 自定义格式到 `Temp/backup/` 按日期 + N 天轮转、`pg_restore.sh` 恢复脚本、系统 job 每日 02:00)⑧ BrAPI + MIAPPE 互操作(`module_bre/brapi/controller.py` prefix `/brapi/v2` 只读五端点:germplasm/observationvariables/studies/observations/miappeBrAPI 2.x `metadata{pagination,status,datafiles}+result{data}` 包裹、0 基分页、bre_germplasm→germplasmDbId/germplasmName/genus/species/subtaxa 映射);`_DATA_VERSION` v2.14、gwas 1.2.0 / mtblup 1.1.0 / blup 1.4.0 |
| v2.15 | 2026-08-04 | **九缺口补齐(用户重扫 12 项缺口、剔除同日已落地的 A1 S-等位/A4 G×R 余 9 项,拍板「全部补齐」,分三批独立 e2e + 回归全过,§8.23 / `桃育种系统统计引擎实施记录.md` §十六)**:**批1 经典侧计算端点(纯计算不建表)**——A5 数据质量 `POST /statistics/data-quality`(缺失率/变异系数 + IQR 箱线 + MAD 稳健 z-score 双法异常标记);A3 遗传增益 `POST /statistics/genetic-gain`(ΔG=k·r_g·σ_Ak 经 Acklam 有理近似 Φ⁻¹ 纯 numpy、r_g=批次 PA、σ_A=√h²·σ_P,逐轮投影);A6 主动选配 `POST /statistics/mating-recommend`(S-等位硬过滤 + 亲缘 A 惩罚 score=w_ebv·mid_parent_EBVw_kin·max(0,rthreshold),不落库);**批2 分子侧严谨性**——B1 EMMAX 混合模型 GWAS`gwas._emmax`:零模型方差分量复用 `genomic._profile_solve`、eigh 对角化 K→V⁻¹、逐标记 GLS t²→`fdist.f_pvalue`;run_gwas 后处理抽共享函数、GLM 路径逐字节不变);B2 SSR 多等位虚拟编码(VCF 按 ALT 数定 marker_type、`_allelic_from_gt` 每等位 0/1/2、3 处装配按 marker_type 分支、`build_g_matrix` 多等位 VanRaden 推广);B3 QTL×E `POST /statistics/gwas-qtl-x-e`(分环境 GWAS 合并 stable/env-specific/异号 G×QTL 警示);B4 MAS 面板语义(mode/favorable_allele/haplotype_group 三列 + `_mas_hit_map` additive/dominance/recessive/allele/haplotype 五语义命中);**批3 求解器核心**——A2 AR1×AR1 空间协方差(`blup.solve_spatial`e~N(0,σ²e·R)、R=AR1(ρ)⊗AR1(ρ) 纯 numpy eigh 求 R⁻¹、REML 对 (h²,ρ) 坐标上升黄金搜索、`run_ablup(spatial=True)`→method=AR1×AR1、与 G×E/G×R 互斥、缺坐标 409);A7 稀疏 A⁻¹+共轭梯度(`_build_ainv_sparse` COO + `_cg_solve`、n>N_SPARSE(1000) 阈值分派 solver=sparse-cg、Hutchinson k=100 估 PEV 对角 reliability 近似、稠密路径逐字节不变);`_DATA_VERSION` v2.13、blup 1.3.0 / genomic 1.2.0 / gwas 1.1.0 |
| v2.14 | 2026-08-04 | **现代桃育种四方向收口·GWAS/QTL/MAS 闭环落地(§8.22e2e 验证通过)****④ GWAS/QTL/MAS 闭环由「留待」落地为完整发现层**——GWAS 引擎 `gwas.py`(GLM+PC 单标记回归:群体结构 SVD 前 n_pc 个主成分得分作协变量、p 值复用 `fdist.f_pvalue(t²,1,df)` 纯 numpy 零 scipy、微小岭回归兜底共线标记(标记与 PC 共线时效应被吸收 p≈1,不误吸正交 QTL 效应)、Bonferroni 阈值 + BH-FDR q、显著标记同染色体相邻间距合并 QTL 定位);**5 张新表**(`bre_gwas_result`/`bre_gwas_snp`/`bre_qtl`/`bre_mas_panel`/`bre_mas_panel_marker`create_all + `weld_gwas.sql` 幂等兜底);**服务端** `POST/GET /bre/statistics/gwas/run|list|{id}`job_type=GWAS`_gather_gwas_inputs` 独立装配不复用 run_gblup 零回归,input_hash/engine_version 落库)+ `bre_qtl` CRUD(已知 QTL 录入 source=known / GWAS 自动定位 source=gwas+ `bre_mas_panel` CRUD + `set_markers` + **decision_preview 加 marker 条件**(MAS 决策 hook,童期幼苗无表型/无 EBV 也能被标记辅助选中);**前端** `gwas.ts` + `gwas/index.vue`GWAS 批次 + Manhattan/QQ 裸 echarts + QTL 定位 + MAS 面板三 tab+ sys_menu 900214 占位页翻转真实页(复用统计模块权限,无需新按钮);`_DATA_VERSION` v2.12、`gwas.ENGINE_VERSION` 1.0.0 |
| v2.13 | 2026-08-04 | **现代桃育种领域覆盖·S-等位基因交配兼容性 + 抗病/需冷量性状字典落地(§8.21,e2e 验证通过)**:① `bre_germplasm.s_alleles`String32Sf=自交亲和型)+ `cross_combination` create/update 兼容校验(任亲本含 Sf→放行、共享 2 个→409「配了不结」硬门禁、共享 1 个→s_compat 半兼容警示);②③ `bre_trait` 种子 5 条 numeric(细菌性穿孔病/褐腐病/白粉病 0-5 级病情指数 + 需冷量 h + 需热量 GDD,category 抗病性/生态适应性,into_ebv=1、direction=asc、default_h2 兜底,统计引擎仅消费 numeric);④ MAS/QTL/GWAS 闭环单独立项(§8.22 / v2.14 |
| v2.12 | 2026-08-04 | **基因组选择(GS)实证严谨性·GBLUP/ssGBLUP 专用 k-fold 交叉验证(§8.20e2e 验证通过)**`genomic.kfold_cv_genomic`(G/H/Hinv 只建一次、逐折掩蔽留出表型,个体保留在关系矩阵、留出 GEBV 由 G⁻¹/H⁻¹ 交叉关系预测)——`run_cv``dataset_id`/`method`/`maf_min` 入参(method=KFCV/GBLUP·KFCV/ssGBLUP),候选=genotyped∩phenos**固定种子随机分层**(GS 同世代样本无家系树,区别于 ABLUP 的 sire 家系留出),单折失败容错不中断,mean/pooled pearson + RMSE + cv_accuracy 落 `bre_cv_result``_gather_gblup_inputs` 提取(run_gblup↔GS CV 复用取数,行为不变);`_build_h` 缺失基因型个体按 base 补入系谱(不再 raise);ENGINE_VERSION 1.1.0、_DATA_VERSION v2.11。SSR 多等位 dummy 编码(§8.20 ②)留待后续 |
| v2.11 | 2026-08-04 | **田间试验精度补强·砧木×接穗随机互作(G×R,rootstock 由固定哑变量升级为第三随机效应槽,e2e 验证通过)**,详见 §8.19 / `桃育种系统统计引擎实施记录.md` §十二:`run_ablup(gxr=True)` 走 G×R 分支(method=GXRBLUP、job_type=GXR),按 `(基因型,砧木)` 分组建 Z₂ 随机互作(克隆坍缩系谱与 G×E 共享),`rootstock` 强制从 fixed_effects 剥离防共线,不可辨识门禁(同基因型无跨砧木/单元内无重复/残差 df<1)→409,σ²gxr/gxr_ratio/n_cross_rootstock 落 note;求解器 `_solve_gxe``factor_label/factor_name` 参数(G×E 警告文案逐字节不变、G×R 显「砧木」),ENGINE_VERSION 1.2.0**Z₂ 单槽位 → G×E/G×R 必须互斥**(双开 409 + 前端互斥 watcher);前端 G×E tab 加 G×R 复选框、批次表互作方差列同显 σ²gxr |
| v2.10 | 2026-08-04 | **六项能力完善(用户核实六条缺口、逐项拍板「全部落地」,e2e 验证通过)**,详见 §8.18 / `桃育种系统统计引擎实施记录.md` §十一:① **MT-BLUP**——`mtblup.solve_bivariate` 成对双性状 REML(共享系谱 A/A⁻¹、y 堆叠 X/Z 块对角、Var(u)=G0⊗A、固定单性状方差仅对 ρ 黄金分割求极大精确 REML),`run_genetic_corr` 逐对 bivariate 组装 G0 + Higham 半正定投影,落 `bre_genetic_corr_result`job_type=GENCORR),`_smith_hazel_index``g_method="mtblup"`(单对不收敛回退 Calo + warning,G 非正定特征值截断)② **GBLUP/ssGBLUP**——`genomic.py`VanRaden G method1/2 + MAF 过滤 + blend 岭;`solve_gblup` 仅基因型株入模型;`solve_ssgblup` 单步法 H⁻¹=A⁻¹+[[0,0],[0,G⁻¹−A22⁻¹]]**V 块用 H 协方差、H⁻¹ 仅进 MME**),`run_gblup`(样本 source_type=tree 直连 / sample_name↔tree_no·品种名兜底,未映射跳过+warning,多等位标记跳过;`genotyped=sorted(dosage)` 对齐 G 行序)③ **DUS 特异性统计检验**——QN 单因素 ANOVA→LSDt_crit 由 `fdist.f_icdf` 二分反解 F(1,df) 开方)、PQ/QL 状态众数比较、**必测描述符**驱动建议,`POST/GET /bre/dus_test/distinctness/{test_id}``analysis_json`,参照默认同 trial_study 自动 + `reference_test_ids` 显式覆盖,conclusion 为 pending 时自动建议 ④ **AMMI/Finlay-Wilkinson 稳定性**——`stability.py`FW 环境指数回归 b/R²/se_b/flag_stable,完美拟合 se_b=0 时 b≈1 判稳;AMMI 残差 SVD→IPC/ASV/ecovalence),`run_stability(gxe_env=site/year)``bre_stability_result`,格子 <2×2 → 409 ⑤ **MLOps 重训+回滚**——`bre_prediction.is_active`(版本链:无 active 时首批 active),`GET /statistics/model/drift`(轻量 `_gather_digest_inputs` 重算输入哈希)+ `POST /statistics/model/retrain`(漂移才重训,新批次 `model_activate` 转移 active+ `POST /statistics/model/activate/{id}`(回滚原语),list 加 is_active ⑥ **BLUP stage 拆分**——`bre_trait_observation.stage`(观测级发育阶段,缺省继承 trait.stage),`run_ablup(stage)` 取数按 coalesce(obs.stage,trait.stage) 过滤 + model_name `_{stage}` 后缀 + PredictionModel.stage 落库,未指定但数据有分歧→note 警示 |
---
## 0. 设计原则(本规格的宪法)
1. **性状字典与测量值分离 + 统一长表存储(对标 BrAPI `ObservationVariable` + `Observation`**`trait` 是唯一的性状字典(代码/类型/单位/量表),**新增桃性状只加字典、不动核心表结构**;测量值一律走**长表 EAV**,分两张职责正交的表——① **单株鉴定明细**`breeding_trait_observation`(挂 `evaluation_id`tree 级,clone 级 EBV 取数主路径)② **物候时序 + plot/combination 级观测**`breeding_observation`。统计层经"统一性状值视图"(DB 普通 `VIEW`,按 `trait_code` pivot)归一供 BLUP 消费(§8.4)。**v2.2/F1 裁定:废弃初稿"核心性状固定列 + EAV 双轨"口径——`tree_evaluation` 已删固定列、全迁 `breeding_trait_observation` 长表;当初上固定列的收益=报表/SQL 聚合快,改由 DB 视图/物化视图 pivot 顶上,不回退固定列)**。这是与初稿最大的修正:字典一处定义、值全部长表、报表用视图。
2. **Program/Trial/Study 三层(对标 BrAPI**:把"多年多点试验"从 site/plot 里抽象出来,支持同一品系跨生态点、跨年同步试验(MET, Multi-Environment Trial)。
3. **桃语义而非大田语义**:清单里的「P/F1/F2 世代、拔节期/抽穗期、播种季节、随机区组/间比」是按一年生大田作物(玉米/小麦)写的,**对桃(多年生无性繁殖果树)必须语义替换**(见 §1)。
4. **砧木–接穗建模**:桃特有的「嫁接繁殖」维度,现有系统完全缺失,必须补齐。
5. **预留分子层**`marker`/`genotype_sample`/`genotype_call` 对齐 BrAPI `Sample`+`Calls`,未来接 GBS / PeachSNP170K 做基因组选择(GS)不改骨架。
6. **统计与决策是地基不是补丁**:上面的数据模型必须能让 V1.1 统计引擎(R `sommer`/`lme4` 做 ABLUP/EBV、选择指数)与 V3.0 AI 决策直接消费,不做"先堆数据再补分析"的短视设计。
7. **API 直接对齐 BrAPI(已采纳)**:保留现有 `/breeding/*`UI 业务接口)的同时,新增 **BrAPI 兼容只读适配层**`/brapi/v2/...`)。数据模型已按 BrAPI 实体设计,适配成本低,可无缝对接 Breedbase / Flapjack / 国际数据交换,避免未来重复造导入导出。
8. **MIAPPE 合规(已采纳)**:试验元数据按 MIAPPE 的 **Investigation(=target/Program) / Study(=trial_study) / ObservationUnit(=tree/plot) / ObservationVariable(=trait)** 对齐,作为数据共享/投稿的一致性基线。
---
## 1. 桃育种语义替换表(清单 → 桃)
| 清单原文(大田作物语境) | 桃系统应改为 | 落点 |
|---|---|---|
| P / F1 / F2 世代(选择阶段) | **选择阶段 `stage`**:实生苗 → 初选株 → 复选株 → 品系 → 区试品系 → 新品种(枚举见 §9 | germplasm/tree/cross/selection_result 的 `stage` |
| 遗传世代 | **遗传世代 `generation`**F1 / F2 / BC1 / BC2 / BC3(与 `cross_type` 联动;引入种质留空) | 权威 `cross_combination.generation``tree`/`germplasm` 冗余拷贝便于筛选 |
| 拔节期 / 抽穗期 | 桃物候:萌芽 / 开花(初花·盛花) / 坐果 / 果实发育 / 成熟 / 落叶 | `observation`(物候类变量) |
| 播种季节 | 桃用**嫁接 / 定植**(砧木 + 接穗),非播种 | planting.rootstock_id → **breeding_rootstock**A3 |
| 自交系 | 桃为**克隆(无性繁殖)**,入选株 = 待审定克隆,需砧木关联 | germplasm.is_rootstock(仅"可作砧木"标记)/ tree.rootstock_id → **breeding_rootstock**(A3,全文砧木 FK 统一指字典,不指 germplasm |
| 随机区组 / 间比试验 | 桃果园株数少,简化为 **区组 + 重复 + 对照**轻量设计 | trial.design_type |
| 材料编号 | accession_no(唯一 accession 编号) | germplasm.accession_no |
**stage / generation 枚举(v1.2 已定,详 §9**:依 RosBREED 桃无性选育流水线与现有 14 域敲定,作为 `sys_dict` 新增字典类型(`breeding_stage` / `breeding_generation`),落库英码、前端显中文。
---
## 2. 目标模块总览(现有 14 + 新增 13,部分为规划)
**A. 现有 14 域(保留 + 字段调整)**
germplasm / site / plot / target / cross_combination / pollination / seed_treatment / seedling / planting / tree / tree_evaluation / tree_photo / selection_result / personnel
**B. 新增模块(P0P2,含 v1.3 复审补入)**
| 模块 | 表名 | BrAPI 映射 | 优先级 |
|---|---|---|---|
| trait(性状字典) | breeding_trait | ObservationVariable | P0 地基 |
| observationplot/物候观测) | breeding_observation | Observation | P0 地基 |
| trait_observation(单株鉴定明细,**v2.2/F2 补登记** | breeding_trait_observation | Observation | P0 地基 |
| field_operation(农事操作) | breeding_field_operation | Observation(op_type) | P0 |
| trial(多年多点试验) | breeding_trial + breeding_trial_study + **breeding_trial_study_entry**(v1.4) | Trial / Study / Entry | P1 |
| group(分组/标签) | breeding_group + breeding_group_member | List | P1 |
| statistics(统计报表) | breeding_report(配置)+ 聚合端点 | — | P2 |
| propagation(克隆扩繁) | breeding_propagation | — | P1(§3.8 |
| seed_lot(种子批·库存) | breeding_seed_lot | — | P1(§3.13,与 MET 一并建模) |
| environment_condition(环境因子) | breeding_environment_condition | — | P1(§3.9G×E 地基) |
| audit_log(审计日志) | breeding_audit_log | — | P1(§3.10 |
| selection_rule(选择阈值规则) | breeding_selection_rule | — | P1(§3.11,决策地基) |
| treatment(试验因子/处理) | breeding_treatment | Treatment(BrAPI) | P1(§3.14,支撑 split_plot 等设计的因子主效应/互作估计) |
| planting_treatment(定植-处理关联) | breeding_planting_treatment | — | P1(§3.15treatment 多对多落地) |
| 分子基因型层 | breeding_marker(含 panel) / breeding_genotype_sample / breeding_genotype_call + **breeding_genotyping_dataset**(v1.4) | Sample / Calls / Marker / Dataset | V2.0(地基先建) |
| prediction(育种值) | breeding_prediction / breeding_prediction_value | — | **值表 V1.1EBV 持久化)/ GS 模型训练 V2.0(§3.12** |
> 注:原稿数"21"已过期,此处以清单为准;其中 seed_lot / environment_condition / audit_log / selection_rule 为 v1.3 复审补入一期,`prediction` 留 V2.0。
**重要简化(避免模块膨胀)**
- **物候期不单列模块** → 只是 `observation` 中「物候类变量」的观测。
- **系谱树不单列模块** → 靠 `cross_combination.parent_combination_id` 自链 + `germplasm.pedigree` 字符串 + 前端 D3 树图 + `/pedigree/{id}` 聚合端点。
---
## 3. 新模块字段规格
### 3.0 breeding_clone(入选克隆系谱表,P0 数据治理地基)
> 桃为无性繁殖,入选株 = 待审定克隆。本表是**遗传身份(clone)层**,与亲本/种质档案 `germplasm`(父母本来源)**分离**(v2.0 决策:亲本资源 vs 入选克隆分离)。砧木只挂在 observation 层,**本表无砧木字段**(建模铁律,§5.x)。嫁接扩繁株沿用原 clone_id,不新建。
> **v2.2/A1 修订)** clone ≠ 每株实生苗。杂种实生苗定植时**不建 clone**`tree.clone_id` 可空),仅当该单株**入选晋升**时由流程创建一条 `breeding_clone` 并回填 `tree.clone_id`;参试无性系(来自 `entry`)定植即有 clone。故本表行数 = 入选克隆数(数百级),而非定植实生苗数(数千级),避免 EBV 全收缩到单株均值。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK | 自增主键 |
| clone_id | varchar(32) | UNIQUE NOT NULL | 组合码 + **单株序(≥4 位,容纳单组合数千株,G1)**,如 `JY-DJB-001-0007`;全局唯一可追溯。**由统一编号服务在入选晋升时生成(§8.9),非定植时**(A1) |
| combination_id | int | FK→breeding_cross_combination NOT NULL | 所属杂交组合 |
| female_parent_id | int | FK→breeding_germplasm | 母本(**冗余直查列**;权威系谱见 §3.18 `breeding_pedigree`,避免 A 矩阵递归断裂) |
| male_parent_id | int | FK→breeding_germplasm | 父本(**冗余直查列**;同上) |
| planting_year | int | NOT NULL | 定植年份 |
| generation | varchar(16) | | **v2.2/D2**:世代 F1/BC1/F2…;脚注:可由 `combination_id`→组合父母本派生,与 `tree.generation` 保持一致,冗余存此便于 clone 级筛选与系谱世代统计 |
| status | varchar(1) | NOT NULL DEFAULT '1' | clone 级决选状态:1入选/2初选/3重点/4保存/5淘汰(淘汰=状态变更非删除) |
| uuid / is_deleted / created_time / updated_time / deleted_time | — | 同框架契约 | 审计与软删 |
**聚合语义**:同一 clone 经嫁接扩繁产生多株 `tree`,其表型是同一基因型的重复观测;统计前按 `tree.clone_id` 聚合为该 clone 的重复测量,EBV 随机效应估在 `breeding_clone` 级(`clone_id`),`tree` 仅作重复测量单元。此点取代原 `tree.germplasm_id → germplasm 级 EBV` 的聚合口径(§4/§5 同步修订)。**(v2.2/A1** 实生苗入选前无 clone_id,其童期观测按 `tree_id` 聚合(门禁键此阶段退化为 tree_id,见 §3.16/F3);入选建 clone 后再切换到 clone 级聚合。
### 3.1 breeding_trait(性状字典,P0
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| trait_code | varchar(64) | UNIQUE, NOT NULL | 如 `brix``fruit_weight``bloom_date` |
| trait_name | varchar(128) | NOT NULL | 中文名:可溶性固形物、单果重… |
| category | varchar(32) | NOT NULL | fruit/flower/plant/disease/phenology/yield/quality/rootstock(业务类别) |
| stage | varchar(16) | NOT NULL | **v2.0**:性状分段 `juvenile`(童期)/ `evaluation`(评价段),与 `category` **正交并存、不混用**;童期采集→间接早选,评价段采集→clone 级 EBV |
| data_type | varchar(16) | NOT NULL | numeric / categorical / date / boolean |
| unit | varchar(32) | NOT NULL | g、%、°Brix、mm、date**v2.0**:导入/观测时**强校验**,值单位须匹配,不符**整行拒收**(数据质量门禁,§3.17) |
| method | varchar(256) | | 测定方法自由文本(如折射仪、游标卡尺) |
| method_uri | varchar(256) | | **v2.2/G3**:受控词表方法 URICrop Ontology / MIAPPE Method),与 `method` 自由文本并存互补——`method` 供人读、`method_uri` 供 BrAPI/国际仓储对接;可空(合并 §6 路线图曾提的 method_uri,消除双字段漂移) |
| scale_json | jsonb | | 量表/选项(categorical 时存选项数组;numeric 时存 min/max/step |
| ontology_uri | varchar(256) | | **v1.4**Crop Ontology / Trait Ontology / MIAPPE 受控词表 term URI(如 `CO_356:0000041`),供 BrAPI 适配层与国际合作仓储对接;可空 |
| valid_min | numeric(12,4) | | **v1.7**:生物学合理下限(自定义阈值),数据质量校验/异常值自动标记用;可空(专册 3.3.2 数据质量监控) |
| valid_max | numeric(12,4) | | **v1.7**:生物学合理上限,同上;可空 |
| direction | varchar(16) | NOT NULL DEFAULT 'desc' | **v2.3 已落地**:性状方向 `desc`=越大越好(默认)/ `asc`=越小越好(**低优性状**:裂果率、病害级别、酸度——若目标是低酸)。选择指数(zsum/smith_hazel)、EBV 排行、决策预览、轮次对比均按此翻转贡献符号/排序方向,杜绝"高 EBV=优"隐含假设把低优性状选反 |
| into_ebv | varchar(1) | NOT NULL DEFAULT '1' | **v2.3 已落地**:是否选种目标 `1`=进 EBV/指数/决策候选(默认)/ `0`=仅记录(**仅从选种相关候选剔除**——指数候选/EBV 排行/决策预览/ABLUP 下拉;describe/correlation/trait_values 不受影响) |
| default_h2 | double precision | | **v2.3 已落地**:先验遗传力 h²(桃经典先验,可在性状字典修改);指数无实测 h² 时兜底(zsum/smith_hazel 均兜底,两者皆无才 409 拒绝) |
> **valid_min/max 局限说明(v2.2/H1**:本字段为**全局单值**,但果重/糖度等的生物学合理区间随**成熟期/年份/砧木**变化,全局阈值可能误标或漏标。一期口径:**接受全局阈值 + 人工复核**(门禁本就对异常值走人工复核,见 §3.16),不强制按 stage 分档;后续如需精细化,可在 `scale_json` 内按 stage 追加分档区间,不改表结构。
| is_preset | bool | default false | 是否系统内置(种子数据) |
| remark | varchar(512) | | |
| created_time / updated_time / is_deleted | 标准 | | 来自 ModelMixin |
> **BrAPI 映射简化说明(v1.4**BrAPI `ObservationVariable = Trait + Method + Scale` 三元组,本系统将 method/scale **内联合并**进 `trait`(桃单作物、方法稳定,避免三表 join 复杂度)。适配层导出 BrAPI 时需按此三元组拆分;`ontology_uri` 提供受控词表引用,满足 MIAPPE/Crop Ontology 可引用性。
**种子数据来源**`doc\果树所\育种\yz.sql``pa_four`(~40 字段:单果重/果形/果核/可溶性固形物/成熟期/离粘核/风味…)与物候类变量,导入为 `is_preset=true` 的桃专用性状字典。
> **枚举归属决策(v1.92026-07-29,方案A 已定)**:性状的**量表选项/范围**是性状定义的一部分,单一真相内联在 `scale_json`categorical 存 `options` 数组、numeric 存 `min/max/step`),**不进 `sys_dict`**`sys_dict` 仅承载"实体状态/分类枚举"(如 §9 的 `breeding_stage`/`breeding_generation`、`tree.status`、`germplasm_type` 等,非被测变量)。二者语义不同——性状=ObservationVariable(有 method/unit/obs_year/重复测量);分类枚举=实体一次设定属性,无测定方法/单位——**不得混用**。BrAPI 导出时 `scale_json`→Scale 三元组,无需 join `sys_dict`。这一定位与"方便统计分析"无关:统计引擎只读 `data_type`+实测值,选项清单存哪不影响计算;A 的真正收益是元数据自包含、防双源漂移、BrAPI 干净导出。
### 3.2 breeding_observation(通用观测,P0
> 采用**显式可空外键**`tree_id` / `plot_id` / `combination_id`),**不采用** `(unit_type, unit_id)` 多态——多态会破坏引用完整性、无法真正联表、且令现有 `_build_conditions` 数据权限注入(依赖已知 FK 列)失效。三者至多一个非空。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| tree_id | int FK→breeding_tree | 可空 | 观测单元=单株 |
| plot_id | int FK→breeding_plot | 可空 | 观测单元=小区 |
| combination_id | int FK→breeding_cross_combination | 可空 | 观测单元=杂交组合(如组合级表型) |
| trait_id | int FK→breeding_trait | NOT NULL | 测了哪个性状 |
| value_numeric | numeric(12,4) | | data_type=numeric 时 |
| value_text | varchar(512) | | categorical / boolean 存此 |
| value_date | date | | data_type=date 时 |
| obs_year | int | | 观测年份(MET 聚合键) |
| obs_date | date | | 具体日期 |
| site_id | int FK→breeding_site | | 观测地点(冗余便于聚合;亦可由 tree→plot→site 推导) |
| person_id | int FK→breeding_personnel | | 观测人 |
| trial_study_id | int FK→breeding_trial_study | 可空 | 区分「试验观测」vs「果园日常观测」;试验观测可参与 BLUP |
| status | varchar(16) | default "draft" | **v1.4**:数据质量态 `draft`(草稿)/`validated`(已校验);批量导入/多人观测下隔离脏数据,统计前按 validated 筛选 |
| issue_status | varchar(16) | default "normal" | **v2.2/C2**:门禁质量标记 `normal`(正常)/`pending`(待补录)/`rejected`(拒收);与 `status` 配合驱动状态机(§3.16/C3),不新建 issue 表 |
| validated_by | int FK→breeding_personnel | | **v1.6**:校验人(status=validated 时记录) |
| validated_date | date | | **v1.6**:校验日期 |
| unit | varchar(32) | | **v1.6**:本次观测值单位(冗余自 trait.unit,便于核对与单位换算);批量导入时按 trait.unit 校验/换算 |
| remark | varchar(512) | | |
**索引**`(trait_id, obs_year)``(tree_id)``(plot_id)``(combination_id)``(trial_study_id)`
**语义(v2.2/F1+F2 重定职责)**:本表**仅承载 plot/combination 级观测 + 物候时序观测**(如花期/果实发育期时序、小区级/组合级群体表型),**不再承载 tree 级果实鉴定性状**——后者一律走 §3.2b `breeding_trait_observation`(挂 evaluation)。两表职责按"**是否喂 EBV**"正交切分:`breeding_trait_observation` 喂 EBV(clone 级取数主路径),`breeding_observation` **不喂 EBV**。**plot 级果实均值不在本表落值**,由统计 VIEW 从 `breeding_trait_observation` 聚合派生(§8.4),杜绝双写与重复计数。原"核心性状走 `tree_evaluation` 固定列"表述作废(F1,见 §4/§8.4)。**v1.6B8**:本系统 tree/plot/block 对应 BrAPI `observationLevels`plant/plot/block),观测单元层级即观测的 FK 类型(tree_id/plot_id/combination_id)。
### 3.2b breeding_trait_observation(单株鉴定明细长表,P0,v2.2 正式登记)
> **命名说明(v2.2/F2)**:本表已在代码落地(模块/URL/权限名 `trait_observation`,模型 `TraitObservationModel`**物理表名 `breeding_trait_observation`** 与全项目 `breeding_*` 前缀一致),此前文档漏登记("代码有、文档无"缺口)。此处补记**既有表**,非新建。
> **职责(F1+F2**:承载**单株(tree 级)每次鉴定的性状明细**——童期性状 + 评价段果实性状,是 clone 级 EBV 的**取数主路径**。与 §3.2 `breeding_observation`plot/combination + 物候)按"是否喂 EBV"正交:本表**喂 EBV**。取代初稿 `tree_evaluation` 固定列(F1)。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK | |
| evaluation_id | int | FK→breeding_tree_evaluation NOT NULL | 所属鉴定主记录(一次鉴定=一主记录+N 明细) |
| tree_id | int | FK→breeding_tree NOT NULL | 观测单元=单株(可经 evaluation 推导,冗余便于按株聚合/判重,F4) |
| trait_id | int | FK→breeding_trait NOT NULL | 测了哪个性状(`breeding_trait` 驱动长表) |
| value_numeric | numeric(12,4) | | data_type=numeric 时(统计 pivot 取此列) |
| value_text | varchar(512) | | categorical / boolean |
| value_date | date | | data_type=date 时 |
| category | varchar(32) | | 归属标签页(基本鉴定/果实外观/果皮/果实大小/果肉/果核/其它),驱动前端分组录入 |
| issue_status | varchar(16) | default "normal" | **v2.2/C2**:门禁标记 normal/pending/rejected(同 §3.2 |
| unit | varchar(32) | | 本次观测值单位(冗余自 trait.unit,导入校验用) |
| remark | varchar(512) | | |
| uuid / is_deleted / created_time / updated_time / deleted_time | — | 同框架契约 | **鉴定类表:禁物理删、UPDATE 强制 audit(§3.10/G2** |
**索引**`(evaluation_id)``(tree_id, trait_id)``(trait_id)`
**统一性状值视图**:统计管线由 DB **普通 VIEW**`trait_code` pivot 本表(+ 必要时 union `breeding_observation`)生成宽表供 BLUP,保证 fresh;看板/报表可另建 **物化视图 MV**(定时刷新),但 **MV 不得作为 BLUP 输入**(§8.4)。
### 3.3 breeding_field_operation(农事操作,P0
> 同样改显式 FK`tree_id` / `plot_id`),弃 `(unit_type, unit_id)` 多态,理由同 §3.2。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| op_type | varchar(32) | NOT NULL | 施肥/灌溉/植保/除草/修剪/病害防治/其他 |
| tree_id | int FK→breeding_tree | 可空 | 作用对象=单株 |
| plot_id | int FK→breeding_plot | 可空 | 作用对象=小区 |
| op_date | date | NOT NULL | 操作日期 |
| material | varchar(128) | | 药剂/肥料名 |
| dosage | varchar(64) | | 用量 |
| method | varchar(128) | | 方式(叶面/根施…) |
| operator_id | int FK→breeding_personnel | | 操作人 |
| site_id | int FK→breeding_site | | 定位 |
| remark | varchar(512) | | |
**索引**`(tree_id)``(plot_id)``(op_date)`
**BrAPI 映射修正**field_operation **不映射为 `/events`**BrAPI 无顶层 Event);改为映射到 `/observations`(带 `op_type`),或自定义只读端点(见 §8.2-C)。
### 3.4 breeding_trial + breeding_trial_study(多年多点试验,P1
**breeding_trial**
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| trial_code | varchar(64) UNIQUE | 试验编号 |
| trial_name | varchar(128) NOT NULL | |
| target_id | int FK→breeding_breeding_target | 关联育种目标 |
| design_type | varchar(32) | 取值见 §9rcbd/augmented/contrast/split_plot/unreplicated|
| description | varchar(512) | |
| years | varchar(64) | 跨年计划,如 2026-2028 |
| remark | varchar(512) | |
**breeding_trial_study**Trial×Location×Year
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| trial_id | int FK→breeding_trial | |
| site_id | int FK→breeding_site | 试验点 |
| year | int | 年份 |
| replicate_count | int | 重复次数(原 `replicate` |
| block_count | int | **区组数(v1.3 补)**;与 `tree.block_no` 对应,是 BLUP 的 block 随机效应来源 |
| design_type | varchar(32) | 取值见 §9.4(便于 study 级覆盖 trial 默认设计) |
| control_germplasm_id | int FK→breeding_germplasm | 对照品种 |
| layout_json | jsonb | 田间种植图(小区排布坐标) |
| season | varchar(32) | | **v1.6**:季节/播期分组(如 `2026_dry` 旱季),MIAPPE/BrAPI season 概念,关联 year 的细粒度环境聚合 |
| remark | varchar(512) | |
> **试验隶属链路(v1.3 彻底补全,原稿断裂)**:观测单元(tree)经两条显式 FK 挂到试验——
> - `breeding_planting.trial_study_id`(定植时把这批树挂到某 trial_study,运营钩子)
> - `breeding_tree.trial_study_id`(从 planting 同步,BLUP 直接消费)+ `breeding_tree.block_no`(该树所属区组/重复)
> - `breeding_plot.block_no`(小区级试验时;tree 未填 block_no 则继承 plot
>
> 这样任意 `tree_evaluation`/`observation` 记录 → tree → `trial_study`(environment=site×year) + `block_no` → 混合模型 `y = genotype + block + environment + G×E` 的 block 项不再缺失。布局图由前端可视化 + 轻量排布算法生成。
**breeding_trial_study_entry**(试验 entry 清单,v1.4 补,对标 BrAPI Study 的 entry / ObservationUnit
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| trial_study_id | int FK→breeding_trial_study | 所属试验 |
| germplasm_id | int FK→breeding_germplasm | 参试无性系/品系的**种质溯源**(保留,v2.2/D3 |
| clone_id | int FK→breeding_clone | **v2.2/D3**:参试落 **clone 级**(entry 直指遗传身份,与 BLUP/EBV 聚合层一致);germplasm_id 仅作种质溯源 |
| entry_number | int | **entry 编号**(该 study 内唯一;BrAPI `entryNumber`BLUP 设计矩阵聚合键) |
| planned_reps | int | 计划重复/区组数 |
| n_plants | int | 计划株数 |
| is_control | bool | 是否对照 entry |
| remark | varchar(512) | |
> **为何需要 entry 抽象(v1.4**v1.3 让 `tree` 直接带 `germplasm_id + trial_study_id + block_no`,假设一株=一个观测单元。但一个无性系在某 study 内常**重复多株/多区组**,且需"entry 编号"聚合设计效应。BrAPI 的 `ObservationUnit = germplasm × entryNumber × replicate × blockNumber × position`,本表即此 entry 层;`tree` 通过 `entry_id`(或冗余 `germplasm_id`)挂回,统计层按 `entry_number` 聚合后再估 genotype 效应。
>
> **⚠ 单写点纪律(v1.5 强化)**`tree.trial_study_id` / `tree.block_no` / `tree.entry_id` **均派生自 `planting`**(定植时 planting 一次性写入 `trial_study_id` / `block_no` / `entry_id`tree 创建时由 service 从所属 planting 复制并锁定;后续修改只能改 `planting` 并级联同步 tree)。严禁两处各自手填,否则 BLUP 输入静默错配。
> - **`tree.trial_study_id` 仅记「定植所属 study」**(来自 planting 的单次定植),多年生树跨年/跨点观测**不**改 tree 自身,而是落到 `observation.trial_study_id` + `obs_year`(观测级表达),统计按 observation 的 study 聚合,tree 只是观测单元。
> - **两类 tree 区分(v1.5**`planting.entry_id` 非空 ⇒ 这是**参试无性系**批次,定植时 `germplasm_id` 必须等于 `trial_study_entry.germplasm_id`(入试即定,禁待晋升);`planting.entry_id` 为空 ⇒ **杂种实生苗**批次,`germplasm_id` 待晋升流程写入(晋级纪律管)。单写点 + entry 有无即可区分两类 tree,无需新增类型字段。
> - 写树校验:`tree.trial_study_id = planting.trial_study_id`、`tree.entry_id = planting.entry_id`、`tree.germplasm_id` 与 entry 一致性按上述规则。
### 3.5 breeding_group + breeding_group_member(分组/标签,P1
**breeding_group**
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| group_name | varchar(128) NOT NULL | |
| group_type | varchar(32) | 取值见 §9project/family/category/temporary_set/custom|
| target_id | int FK | 关联育种目标(可选) |
| description | varchar(512) | |
**breeding_group_member**
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| group_id | int FK→breeding_group | |
| germplasm_id | int FK→breeding_germplasm | 或成员种质 |
| clone_id | int FK→breeding_clone | **v2.2/H3**:或成员克隆(入选群体/决选批以 clone 为成员,呼应 D 组 clone 居中);三者(germplasm/clone/tree)按分组用途择一 |
| tree_id | int FK→breeding_tree | 或成员单株 |
| note | varchar(256) | |
> group_type 取值已定(§9):project(育种项目) / family(家系·杂交组合群) / category(种质类别群) / temporary_set(临时选系集) / custom(自定义)。为避免与 `target`(育种目标) 语义重叠,不设 objective 维度。
> **family / category 冗余消减(v1.3**`group_type=family` 本质是"某 `cross_combination` 的后代集合",可由 `tree.combination_id` **动态推导**,不必存静态成员 → 建议 family 做成**虚拟分组(查询)**,不在 `group_member` 落成员;`group_type=category`(油桃/蟠桃/观赏桃)与 `germplasm.variety_type` 字典**重叠**,直接复用 `variety_type`,不在 group 里另起炉灶。故 `group_member` 主要服务于 project/temporary_set/custom 三类。
### 3.6 breeding_report(统计报表配置,P2
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| report_name | varchar(128) NOT NULL | 报表名 |
| report_type | varchar(32) | 育种进度/世代汇总/杂交组合统计/材料库存/MET分析 |
| query_json | jsonb | 报表查询参数(保存配置,便于复用) |
| created_by | varchar(64) | |
| output_format | varchar(16) | | **v1.7**:报告输出格式 `docx` / `pdf` / `view`(看板实时聚合);默认 `docx` |
> **v1.7 确认进一期(原 v1.4 标记延后)**:V2.11 方案书 3.3.1 要求「年度育种进展 Word/PDF 报告」。故一期提供**报告生成服务**(基于 `report_type` 模板 + `query_json` 渲染),支持 docx/pdf 导出,不再仅限于只读聚合端点;看板类走 `view` 实时聚合,归档类走 docx/pdf 落盘。
**配套**
- 报告生成服务:`POST /breeding/statistics/report/generate`(按配置渲染 docx/pdf,可由 cron 触发年度归档)
- 只读聚合端点:
- `GET /breeding/statistics/progress` 育种进度
- `GET /breeding/statistics/generation-summary` 世代汇总
- `GET /breeding/statistics/cross-stats` 杂交组合统计
- `GET /breeding/statistics/inventory` 材料库存
- `GET /breeding/statistics/met` 多年多点分析(钩子,V1.1 R 引擎)
### 3.7 分子基因型层(V2.0,地基先建)
**breeding_marker**(标记/位点)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| marker_name | varchar(64) UNIQUE | 如 SNP_Chr01_123456 |
| chromosome | varchar(16) | 染色体 |
| position | int | 物理位置 |
| marker_type | varchar(16) | SSR / SNP / InDel |
| panel | varchar(32) | **v1.4**:所属标记面板/芯片版本(如 `PeachSNP170K` / `GBSv1`),用于区分不同基因组集、GS 时需一致 |
| assembly_version | varchar(32) | | **v1.6**:参考基因组版本(如 `Peach_v2.0`/`Peach_v2.1`),GS 拼接须同版本坐标,不同版本不可混;对齐 BrAPI marker.referenceGenome |
| remark | varchar(512) | |
**breeding_genotyping_dataset**(基因分型数据集,v1.4 补,GS 训练/预测群体分组)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| dataset_name | varchar(128) NOT NULL | 如 "2026_Brix_GS_train" |
| platform | varchar(32) | GBS / PeachSNP170K / 测序 |
| panel | varchar(32) | 与 marker.panel 对应 |
| purpose | varchar(16) | train(训练群体)/ predict(预测群体)/ reference |
| run_date | date | 分型日期 |
| lab | varchar(128) | 检测单位 |
| remark | varchar(512) | |
> 关联:`genotype_sample.dataset_id` FK→genotyping_dataset(标记某样品属于哪个分型集)。GS 训练时按 dataset(purpose=train) 取 sample→call 矩阵,避免每次手工挑样品。
**breeding_genotype_sample**(基因型样品)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| dataset_id | int FK→breeding_genotyping_dataset | **v1.4**:所属分型数据集 |
| source_type | varchar(16) | germplasm / tree |
| source_id | int | 来源 id |
| sample_type | varchar(16) | DNA / leaf |
| sample_date | date | |
| method | varchar(64) | 测序/芯片(GBS / PeachSNP170K |
| lab | varchar(128) | 检测单位 |
| remark | varchar(512) | |
**breeding_genotype_call**(基因型调用)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| sample_id | int FK→breeding_genotype_sample | |
| marker_id | int FK→breeding_marker | |
| allele | varchar(32) | 基因型编码(AA/AT/TT 或 0/1/2);**v1.6**:遵循 VCF/GP 编码约定(Breedbase 走 VCF 导入),0/1/2 = 纯合ref/杂合/纯合alt |
| remark | varchar(256) | |
**索引**`(sample_id, marker_id)` 复合唯一。
### 3.8 breeding_propagation(克隆扩繁/苗圃,P1,已定纳入一期)
> 桃主繁殖方式为嫁接/芽接扩繁(非种子实生)。打通 **入选株(tree) → 克隆种质(germplasm) → 扩繁批次(propagation) → 新定植树(tree)** 闭环;现有 `seedling`/`seed_treatment` 仍管种子实生苗,二者互补。
**breeding_propagation**(扩繁批次)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| batch_code | varchar(64) UNIQUE | 扩繁批次号 |
| scion_source_type | varchar(16) | germplasm / tree(被扩繁的克隆来源) |
| scion_source_id | int | 来源 id(入选株或其对应种质) |
| produced_clone_id | int FK→breeding_clone | **v2.2/A2 澄清**:本次扩繁**所繁殖的原克隆**(嫁接扩繁沿用同一 clone,**不新建 clone**);产出的新 tree 直接 `tree.clone_id = produced_clone_id`。原"产出的克隆"措辞易误读为新建,特此澄清。取代原 `produced_germplasm_id`→germplasm |
| rootstock_id | int FK→breeding_rootstock | **v2.2/A3**:砧木字典(§3.17);不再 FK→germplasm。`germplasm.is_rootstock` 仅作"可作砧木"标记 |
| method | varchar(16) | 嫁接/芽接/扦插 |
| graft_date | date | 嫁接日期 |
| nursery_site_id | int FK→breeding_site | 苗圃地点 |
| operator_id | int FK→breeding_personnel | 操作人 |
| scion_count | int | 接穗/芽数 |
| grafted_count | int | 嫁接株数 |
| survival_count | int | 成活株数(后续登记) |
| destination | varchar(32) | 出圃/定植/入库 |
| remark | varchar(512) | |
> `survival_count` 与 `grafted_count` 可派生成活率;产出苗木经 `planting`(带 `rootstock_id`→breeding_rootstock)成为新 `tree`,新 tree 的 `clone_id` = `produced_clone_id`**沿用原 clone,不新建**A2),完成闭环(**v2.0clone 级晋升,取代原 germplasm 级**)。
### 3.9 breeding_environment_condition(环境因子,P1G×E 地基)
> 多年多点分析的核心是 G×E 互作。无 site×year 的环境协变量(需冷量/积温/降水),BLUP 只能粗估。本表提供每个试验点每年的环境背景。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| site_id | int FK→breeding_site | NOT NULL | 试验点 |
| year | int | NOT NULL | 年份 |
| chilling_hours | numeric(8,1) | | 需冷量(小时) |
| growing_degree_days | numeric(8,1) | | 积温(GDD |
| rainfall_mm | numeric(8,1) | | 降水量 |
| temp_avg | numeric(6,1) | | 年均温 |
| soil_moisture | numeric(6,1) | | 土壤墒情(可选) |
| source | varchar(32) | | 气象站/人工记录/遥感 |
| remark | varchar(512) | | |
**索引/唯一**`(site_id, year)` 唯一,确保每点每年一条。可复用 `yz.sql` 的"天气"字段做种子。
### 3.10 breeding_audit_log(审计日志,P1
> 晋级审批、全程可追溯需"谁/何时/改了什么"轨迹,现有仅 `updated_time` 粒度不足。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| entity_type | varchar(32) | 实体(tree/selection_result/cross_combination…) |
| entity_id | int | 实体 id |
| action | varchar(32) | create/update/delete/select/approve |
| field_name | varchar(64) | 变更字段(可空,批量时为 null) |
| old_value | varchar(512) | 旧值 |
| new_value | varchar(512) | 新值 |
| operator_id | int FK→breeding_personnel | 操作人 |
| created_time | 标准 | 时间戳 |
**索引**`(entity_type, entity_id)``(created_time)`。建议作为现有 14 域的**通用切面**(在 Service 写操作时统一落审计),而非逐表加列。
> **审计覆盖范围(v2.2/G2,落实操作手册"记录不可删只能改、改要留痕"铁律)**:
> - **鉴定类表**`breeding_tree_evaluation` / `breeding_trait_observation` / `breeding_observation`):**禁止物理删除**,且**禁用软删**`is_deleted` 不对外开放);淘汰/作废走**状态变更**`status`/`issue_status`)而非删除。
> - 上述表的**每次 UPDATE 必须写 `breeding_audit_log`**field_name/old_value/new_value 逐字段),由 Service 切面强制,不可绕过。
> - 其余业务表沿用框架软删;`selection_result`/`cross_combination`/`tree` 等关键决策表的 update/select/approve 一并纳入审计切面。
### 3.11 breeding_selection_rule(选择阈值规则,P1,决策地基)
> RosBREED 的 DNA-informed 选择靠**指数阈值**(如 Brix≥12 且单果重≥200g)自动 flagged。`selection_result` 只记晋级/淘汰,缺"标准"实体,决策支撑会退化为纯人工勾选。本表把"选择标准"显式建模。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| rule_name | varchar(128) | NOT NULL | 规则名(如"鲜食品系晋级线" |
| target_id | int FK→breeding_breeding_target | | 适用育种目标(可选) |
| stage | varchar(32) | | 适用选择阶段(§9.1,如 ap 复选) |
| conditions_json | jsonb | NOT NULL | 阈值条件数组,如 `[{"trait_code":"brix","op":">=","value":12},{"trait_code":"fruit_weight","op":">=","value":200}]` |
| logic | varchar(8) | default "and" | 多条件组合 and/or |
| action | varchar(16) | | flag(标记)/select(自动晋级)/eliminate(自动淘汰) |
| priority | int | | 规则优先级 |
| enabled | bool | default true | |
| remark | varchar(512) | | |
> 决策支撑(§5.4):前端按规则对 `tree_evaluation`/观测值求布尔,自动 flag/晋级;规则与 `trait` 字典通过 `trait_code` 关联,新增性状自动可被规则引用。
>
> **v2.3 已落地)方向感知**`conditions_json` 的 `op` 缺省按性状 `direction`desc→`>=`asc→`<=`);`rank_top_n` 按方向取**最优前 N**asc 取 EBV 最小前 Ndesc 取最大前 N);`into_ebv='0'` 性状不参与决策候选。**兼容性提醒**:既有规则对 asc 性状**显式写了** `>=` 的仍字面执行(可能选反),上线后人工复核。
### 3.12 breeding_prediction(育种值:值表 V1.1 持久化 / GS 模型训练 V2.0
> **v1.7 时序拆分(关键)**v1.6 曾把整张 `breeding_prediction` 标 V2.0,与分子层同期。但 V1.1 统计引擎(R `sommer`/`lme4` 做 ABLUP/EBLUP)会产出育种值(EBV),而「年遗传趋势图(专册 2.6.3)」「EBV 双轨选择(§5 B10)」「亲本/单株决策(专册 3.1/3.2)」都依赖 **EBV 持久化读取**——若不建值表,V1.1 一接入即断链。**v1.7 拆分**:
> - **值存储表 `breeding_prediction_value` 前移 V1.1**:与 V1.1 引擎同期建表并写入,持久化 EBV/预测值,供趋势图与决策读(**硬缺口①闭环**)。
> - **GS 模型训练(基因型→育种值)留 V2.0**:依赖分子层(§3.7 `genotype_call`);其产出的 GBLUP/EBV 同样写入同一 `breeding_prediction_value` 表。
**主表** `breeding_prediction`(模型/批次元数据):
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int PK | |
| model_name | varchar(128) | 模型名(如"2026_Brix_ABLUP" / "2027_Brix_GS" |
| trait_id | int FK→breeding_trait | 预测的性状 |
| method | varchar(32) | ABLUP(系谱) / gBLUP / rrBLUP / GBLUP / BayesV1.1 先填 ABLUPGS 类 V2.0 |
| accuracy | numeric(5,3) | 模型精度(交叉验证) |
| heritability | numeric(5,3) | **v2.2/B1+B2**:本次 BLUP × 该性状的**加性(狭义)遗传力 h²**(一次预测=一个 h²,故落**主表**而非明细)。落库口径取**克隆均值遗传力** h² = V_clone /V_clone + V_e/k̄),k̄=各 clone 平均重复株数;PA 上限 PA≤√h² 用此值。**注**:术语正名——ABLUP 产出的是加性/狭义 h²,非"广义遗传力"(后者含显性/上位,clonal 数据虽可估广义,但本系统选择决策用加性 h²) |
| train_n | int | 训练样本数 |
| predict_date | date | 预测日期 |
| note | varchar(512) | |
**明细** `breeding_prediction_value`(个体预测值,**V1.1 建表**):`prediction_id` / **`clone_id`(FK→breeding_clone,个体锚点,v2.1/R1 与 EBV 聚合层一致)** / `tree_id`(可选重复测量)/ `predicted_value` / `reliability` / `rank`EBV 排名)。**v2.2/B1** `heritability` 已上移主表 `breeding_prediction`(一次 BLUP × 一性状 = 一个 h²,不应在每条明细重复),明细仅存个体级 clone/value/reliability/rank。V1.1 引擎每次跑 BLUP 在主表落 h²、明细落各 clone 的 EBV,同批次持久化。
> **v2.3 已落地)rank 语义 + h² 兜底**`breeding_prediction_value.rank` 是**写时快照**——读时(EBV 排行/轮次对比)按性状当前 `direction` 重新推导优度序(`ebv_ranking` 读时重排、`compare_predictions` 方向感知),性状事后改方向**不需重跑批次**。主表 `heritability` 实测缺失时,指数/排行可用 `breeding_trait.default_h2` 先验兜底(两者皆无才拒绝)。
### 3.13 breeding_seed_lot(种子批·库存,P1,与 MET 一并建模)
> v1.1/§8.3 曾把库存"延后"。v1.3 复审:MET 与**选择强度**都依赖 "种子→播种→定植→入选" 链,故把 `seed_lot` 作为**批记录**提前进一期(仍非完整事务性出入库台账,后者延后)。与 §3.4 的 trial_study 链路共同拼出完整育种流程。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| combination_id | int FK→breeding_cross_combination | NOT NULL | 所属杂交组合 |
| lot_code | varchar(64) | UNIQUE, NOT NULL | 种子批号 |
| harvest_year | int | | 收获年份 |
| seed_count | int | | 收获粒数(选择强度源头) |
| used_count | int | default 0 | **v1.5/v1.6**:已从该批**取用的粒数**(在 seedling/播种环节按粒累加,非定植株数),由 planting/seedling 写操作维护;`remaining = seed_count - used_count` 派生「剩余可播种量」,选强链前段(获种→已用)可量化,不再依赖手工孤值 |
| germination_rate | numeric(5,2) | | 发芽率 %(活力) |
| storage_type | varchar(16) | | 种子库/离体/DNA |
| storage_location | varchar(128) | | 存放位置 |
| test_date | date | | 活力检测日期 |
| remark | varchar(512) | | |
**链接(选择强度链)**
- `breeding_seedling.seed_lot_id` FK→seed_lot(追溯幼苗来源批)
- `breeding_planting.seed_lot_id` FK→seed_lot(可选;种子来源定植)
- **`used_count` 维护(v1.5/v1.6**:每次从某 `seed_lot` 取种(建 seedling / planting 引用该 lot)时由 service 按**粒**累加 `used_count``remaining = seed_count - used_count` 实时可查,避免手工维护 `seed_count` 与实际消耗脱节(注意粒度:粒≠株,used_count 记粒数)。
> **选择强度贯通(v1.5/v1.6**`seed_lot.seed_count`(获种数)→ `seed_lot.used_count`(已用/播种粒数,派生 remaining)→ `COUNT(seedling WHERE seed_lot_id)`(成苗)→ `COUNT(tree WHERE planting.seed_lot_id)`(定植数)→ `COUNT(selection_result 入选)`(入选数)→ 各级**选择强度/选择率**可算,且 "每组合在某试验点种了多少" 与 MET 的 `trial_study` 直接挂钩。前段「获种→已用」因 `used_count` 派生而不再失真。
---
### 3.14 breeding_treatment(试验因子/处理,P1v1.5 提进一期)
> **背景**:§9.4 `design_type` 含 `split_plot`(砧木×接穗两因子)。若只记 design_type 而不结构化 factor/level,BLUP 无法估因子主效应与互作,设计等于白支持。BrAPI 有 `Treatment`(factor + level) 实体;MIAPPE 要求 `ExperimentalFactor`。本表把"试验处理"显式建模,使裂区/析因设计的统计效应可估。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| trial_study_id | int FK→breeding_trial_study | NOT NULL | 所属试验 |
| factor | varchar(32) | NOT NULL | 因子名(如 `rootstock` 砧木 / `scion` 接穗 / `fertilizer` 肥料) |
| level | varchar(32) | NOT NULL | 因子水平(如 `GF677` / `Maotao` / `N0` |
| description | varchar(256) | | 处理说明 |
| remark | varchar(512) | | |
**索引/唯一**`(trial_study_id, factor, level)` 唯一。统计层按 `treatment.factor×level` 估主效应与互作,与 `block` / `environment` 一并进入混合模型 `y = genotype + block + treatment + genotype×env(+空间)`
### 3.15 breeding_planting_treatment(定植-处理关联,P1v1.6 落地 A3)
> **背景(A3v1.6**:§3.14 的 `treatment` 需落到具体定植批次才能进统计。一个 block 级 `planting` 批次常同时接受一组处理(如 rootstock=GF677 + scion=Maotao),故建多对多关联表。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int PK | | |
| planting_id | int FK→breeding_planting | NOT NULL | 定植批次(block 级) |
| treatment_id | int FK→breeding_treatment | NOT NULL | 接受的处理(factor×level |
| remark | varchar(512) | | |
**索引/唯一**`(planting_id, treatment_id)` 唯一。统计层按 `planting→treatment` 把 factor×level 挂到该批次全部 tree,与 `block`/`environment` 一并进入混合模型。
---
### 3.16 数据质量门禁(quality gateP0,作用在 breeding_trait_observation / breeding_observation 入库前)
> **v2.2/C1** 门禁作用于长表 `breeding_trait_observation`(单株鉴定明细)与 `breeding_observation`plot/物候),**不再作用于已废弃的 `tree_evaluation` 固定列**F1);单位/阈值一律从 `breeding_trait` 对齐(valid_min/valid_max/unit)。
| 门禁项 | 规则 | 处置 |
|---|---|---|
| 缺失值标记 | 关键**单元键**缺失(**入选前实生苗=`tree_id`**;入选后=`clone_id`,F3)+ 年份 + 性状值 | 标记 `issue_status=pending`(待补录),**不进分析池** |
| 异常值 | 数值性状按 `trait.valid_min/valid_max` 越界 | 标记 `issue_status=pending`,人工复核(H1:全局阈值 + 人工) |
| 单位混用 | 值单位 ≠ `trait.unit` | **整行拒收** `issue_status=rejected`(§3.1 unit 强校验) |
| 重复记录 | 按 **`(tree_id, 年份, 性状, obs_date)`** 判重(**含 tree_idF4**) | 去重(保留最新 / 人工选择) |
> **(v2.2/F4)判重与重复测量的命门区分**:同一 clone 经扩繁的**多株 tree** 在同点同年的观测是**合法重复测量(clonal replicates**,正是 reliability 的来源,**绝不可当"重复记录"删**。故判重键必须**含 `tree_id`/株号**——只有"同一株、同年、同性状、同日期"多条才是真重复;clone 级多株是"重复测量"而非"重复记录"。原 v2.1 按 `(clone_id,地点,年份,性状)` 判重(会把 clonal replicates 删到只剩一条 → reliability 崩、自由度虚低)**作废**。
> **(v2.2/F3)实生苗阶段单元键退化**:入选晋升前实生苗无 clone_id,门禁单元键退化为 `tree_id`(童期观测按株入库),入选建 clone 后切换 clone_id;否则童期采集会被全部判"缺失键"打回。
> **(v2.2/C3)门禁 × 状态机衔接**:门禁拒收 → `issue_status=rejected` 且记录停留 `status=draft`;门禁标记异常/缺失 → `issue_status=pending`,须人工修正后方可置 `status=validated`**仅 `issue_status=normal` 且 `status=validated` 的记录进 BLUP 分析池**。
### 3.17 breeding_rootstock(砧木字典,P0 数据治理地基)
> 阶段0 建砧木字典(砧木名称/类型/来源),**只挂 observation 层**tree/planting 的 `rootstock_id`),与 `germplasm.is_rootstock`(亲本种质属性)**区分用途**`germplasm.is_rootstock` 标记"该种质可作砧木"`breeding_rootstock` 才是观测层实际使用的砧木清单。砧木**绝不进 A 矩阵**(建模铁律,§5.x)。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK | 自增主键 |
| code | varchar(32) | UNIQUE NOT NULL | 砧木编码 |
| name | varchar(64) | NOT NULL | 砧木名称(如毛桃/山桃/GF677…) |
| type | varchar(32) | | 砧木类型(乔化/矮化/本砧…) |
| source | varchar(128) | | 来源(自繁/引进) |
| remark | varchar(512) | | |
### 3.18 breeding_pedigree(独立系谱表,P0 数据治理地基,v2.1)
> **v2.1 修订(R2**:系谱从"clone 内联 female/male_parent_id + germplasm.pedigree 自由文本"升级为**独立系谱表**。原因:① clone 父本指向 germplasm,而 germplasm 父级是自由文本 → A 矩阵递归到父本级断裂;② 自选系作亲本时递归立刻崩。独立表让 `dam`/`sire` 也指向本表,递归闭环。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK | 自增主键 |
| individual_type | varchar(16) | NOT NULL | `clone` / `germplasm`(个体类型,两类共用本表) |
| individual_id | int | NOT NULL | 指向 breeding_clone.id 或 breeding_germplasm.id(由 individual_type 决定) |
| dam_id | int | FK→breeding_pedigree.id | 母本(指向本表,递归闭环;引进种可为 NULL) |
| sire_id | int | FK→breeding_pedigree.id | 父本(指向本表;引进种可为 NULL) |
| rel_type | varchar(16) | | 关系类型(biological / 可选) |
| combination_id | int | FK→breeding_cross_combination 可空 | 来源杂交组合(clone 型时有意义) |
| remark | varchar(512) | | |
> `breeding_clone.female_parent_id/male_parent_id` 降为**冗余直查列**(§3.0),权威系谱以本表为准;`germplasm.pedigree`(自由文本)**移除**,改由本表承载(§4 germplasm 行同步修订)。
> **v2.2/A4)A 矩阵系谱唯一权威**:构造遗传关系 A 矩阵的系谱**以本表 `breeding_pedigree`dam_id/sire_id 递归闭环)为唯一权威**`cross_combination` 的父/母本仅作 clone 系谱行的**自动派生源**(新建 clone 时据组合父母本自动生成本表一行),**不作为 A 矩阵的独立系谱来源**,避免"combination 父母本"与"pedigree dam/sire"双源不一致。§5.8 同步修订。
### 3.19 breeding_pollen(花粉档案,P0 田间刚需,v2.4 落地)
> **(v2.4 落地)** 用户田间刚需:桃花期仅 3–7 天,父本花粉是杂交季命脉;原 `breeding_pollination` 有花朵数/坐果数/去雄/套袋,但**无花粉采集/贮藏/活力/授粉窗口**——明年复盘"这批坐果为什么低"毫无抓手。V2.11 方案书(document.xml:3682-3718)要求父本间花粉效力比较(同一母本×不同父本坐果率对比 + 花粉活力不足诊断),结构化活力数据是统计引擎依赖,不只是文档字段。
>
> **架构决策(v2.4 用户确认)**:① **父本锚点=树级 `male_tree_id`**FK→breeding_tree,与 pollination.male_tree_id 一致;混合/外地采集时为空 + `source_type` 区分)② **活力=单值+方法**`viability_method`[ttc/germination] + `viability_pct` + `viability_test_date`,不建子表)③ **窗口=派生有效期+校验**`collect_date` + `expiry_date`,窗口=[采集日,失效日] 由 pollination service 校验,不建独立授粉计划表)。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK | 自增主键 |
| lot_code | varchar(64) | NOT NULL UNIQUE | 花粉批次号(如 PL-2026-0001 |
| male_tree_id | int | FK→breeding_tree 可空 | 采集父本树(**树级锚点**;混合/外地采集可空) |
| source_type | varchar(16) | NOT NULL default 'tree' | 来源类型 `tree`父本树 / `mixed`混合花粉 / `external`外地采集 |
| source_desc | varchar(128) | 可空 | 来源说明(混合配比/外地品种) |
| collect_date | date | 可空 | 花粉采集日期 |
| collect_method | varchar(32) | 可空 | 采集方式(采花取粉/振动收集/网袋挂置…) |
| quantity | varchar(32) | 可空 | 采集量(如 50g / 花药数) |
| storage_method | varchar(16) | NOT NULL default 'fridge' | 贮藏方式 `fridge`4℃ / `minus20` / `minus80` / `liquid_n2`液氮 |
| viability_method | varchar(16) | 可空 | 活力测定方法 `ttc`(TTC染色率) / `germination`(离体萌发率%) |
| viability_pct | double precision | 可空 | 花粉活力 % |
| viability_test_date | date | 可空 | 活力测定日期 |
| expiry_date | date | 可空 | 有效期/失效日期(授粉窗口上界) |
| remark | text | | |
> **授粉窗口(派生,不建独立计划表)**:窗口 = `[collect_date, expiry_date]`。`breeding_pollination` 保存/更新时若选定了 `pollen_lot_id` 且批次两日齐备,校验**授粉日期须落在窗口内**,否则 409(错误信息含批次号与窗口区间)。`/bre/pollen/available_lots?date_on=` 端点返回指定日期(缺省今天)窗口内可用批次,供授粉表单下拉("当前花期能用的花粉")与父本效力复盘取数。
> **统计链路**:父本效力分析 = 同一 `female_tree_id` 下按 `pollen_lot_id`/`male_tree_id` 分组的坐果率(`effective_count`/`flower_count`)对比;花粉活力不足诊断 = `viability_pct` 阈值筛查。结构化活力字段(非仅文档)保证该分析可落 SQL。
## 4. 现有模块字段调整(非新增模块)
| 模块 | 新增字段 | 说明 |
|---|---|---|
| germplasm | accession_no(varchar UNIQUE)、stage(varchar 选择阶段)、generation(varchar 遗传世代,可空)、storage_type(varchar 田间/离体/种子/DNA)、is_rootstock(bool)、rootstock_id(int FK 自关联)、**护照块(v1.4,FAO-MCPD): institute_code(varchar 保存单位)、country_origin(varchar 起源国)、collection_site(varchar 采集地)、acquisition_date(date 引种日期)、biological_status(varchar 生物状态:wild/landrace/breeding_line)、breeding_program(varchar 所属育种计划,v1.6 暂自由文本,后续可升级 FK breeding_program 顶层)** | 种质档案补全 + 桃特有维度 + **国际种质资源护照(Genesys/FAO 对齐)**;**系谱不再内联**(v2.1:移除 `pedigree` 自由文本,改由 §3.18 `breeding_pedigree` 独立表承载,避免 A 矩阵递归断裂) |
| cross_combination | cross_type(varchar 杂交/自交/开放)、parent_combination_id(int 自链 FK)、reason(varchar 选配理由)、stage | 系谱链 + 选配理由 |
| pollination | bagging_date(date 套袋)、emasculation_date(date 去雄)、**female_tree_id(int FK→breeding_tree,可空)、male_tree_id(int FK→breeding_tree,可空)(v1.4,杂交圃父/母本树指定)**、**pollination_method(varchar(32) 授粉方式:人工点授/喷粉/涂抹…,v2.4 补一期文档规划但遗漏)、pollen_lot_id(int FK→breeding_pollen,可空,v2.4 授粉所用花粉批次,窗口校验见 §3.19)** | 田间杂交登记补全 + **控制杂交父/母本树追溯(crossing block** + **花粉批次溯源(父本效力分析:同母本×不同父本坐果率对比 + 花粉活力不足诊断)** |
| seedling | seed_lot_id(int FK→breeding_seed_lot) | 追溯幼苗来源批(选择强度链,§3.13) |
| planting | rootstock_id(int FK→breeding_rootstockv2.2/A3)、**entry_id(int FK→breeding_trial_study_entry,可空,v1.5 单写点补 entry)**、**trial_study_id(int FK→breeding_trial_study,可空,单写点)**、**block_no(int,该批树所属区组,单写点)**、**seed_lot_id(int FK→breeding_seed_lot,可空)**、**propagation_id(int FK→breeding_propagation,可空,v1.6 来源双路径)** | **粒度=block 级批次(v1.6 明确:同一 entry 跨多 block 须建多个 planting**;砧木–接穗建模 + **试验隶属(MET 链路唯一写入口;entry_id 非空=参试无性系批次,germplasm_id 入试即定;为空=杂种实生苗批次,germplasm_id 待晋升)** + 库存链接(seed_lot.used_count 派生剩余)+ 来源双路径(种子批/扩繁批二选一) |
| tree | **clone_id(int FK→breeding_clone**可空**;杂种实生苗定植可空、入选晋升时建 clone 回填,参试无性系定植必填,v2.2/A1 取代原"定植必填/1树=1clone";扩繁后 1 clone↔N tree,§3.0 聚合锚点)**、stage(varchar 选择阶段)、generation(varchar 遗传世代,冗余自 combination)、rootstock_id(int FK→breeding_rootstockv2.2/A3)、**germplasm_id(int FK→breeding_germplasm,晋升时回填、定植时留空,禁手填;v2.0:定植即定 clonegermplasm 仅当 clone 晋升为种质时写入)**、**entry_id(int FK→breeding_trial_study_entry,可空,v1.5 派生自 planting,区分两类 tree)**、**trial_study_id(int FK→breeding_trial_study,可空,v1.5 仅记「定植所属 study」,派生自 planting;跨年/跨点观测走 observation.trial_study_id+obs_year)**、**block_no(int,派生自 plantingBLUP block 效应来源)** | **clone 聚合锚点(R1 修正:tree 必带 clone_idEBV 经 tree.clone_id 聚合到 breeding_clone,否则链路断)** + 阶段/世代标记 + 克隆晋升链路(4.x 全流程 + GS 拼接依赖)+ **MET 观测单元归属(派生,单写点=planting;两类 tree 以 entry_id 有无区分)** |
| site | soil_type(varchar 土壤类型)、**latitude(numeric 坐标)、longitude(numeric)、elevation(int 海拔)(v1.4,空间 BLUP/MIAPPE 环境描述)** | 试验地块补全 + **地理定位** |
| selection_result | **clone_id(int FK→breeding_clonev2.2/D1,决选落 clone 级)**、对齐 stage 晋级流转(建议加 from_stage/to_stage + approved_by)、**rule_id(int FK→breeding_selection_rule,可空,v1.4,记录触发晋级的规则,决策闭环)**、tree_id(保留作溯源) | 晋级审批流 + **选择决策溯源(决选粒度=clone,tree_id 溯源到具体单株)** |
| tree_evaluation | **(v2.2/F1:已删果实性状固定列,改为"一次鉴定主记录",性状明细全落 §3.2b `breeding_trait_observation`** trial_study_id(int FK→breeding_trial_study,可空,环境键)、evaluate_date(调查时间)、breeding_personnel_id(评价人)、overall_score(总评)、**crop_load(varchar 坐果量评级 1/2/3,可空,作果实性状协变量降环境误差——**作鉴定主记录字段,每次鉴定一值**)** | 鉴定主记录 + 环境键 + **负载量协变量(专册 1.3:坐果量评级吸收单株负载造成的生理/环境误差,提升 EBV 与选择指数精度)** |
**tree_evaluation 定位(v2.2/F1 裁定:单一长表,废弃固定列)**`tree_evaluation` **已删除所有果实性状固定列**,降为**一次鉴定的主记录**tree_id + evaluate_date + 评价人 + overall_score + crop_load 等每次鉴定级字段),性状明细**全部迁往 §3.2b `breeding_trait_observation` 长表**`breeding_trait` 字典驱动)。原 v1.3「按 `pa_four` 扩 ~30–40 固定列」口径**作废**——已落地代码(2026-07-29)删固定列、统计 service 改从 `breeding_trait_observation` pivot 取数。**报表/SQL 聚合的补偿**:由 DB 视图(统计用普通 VIEW / 看板用 MV)按 `trait_code` pivot 顶上(§8.4),不回退固定列。*原则回归:§0「性状与观测分离」恢复为「字典定义 + 值全部长表」,不再是「固定列 + EAV 双轨」。*
> **v1.6 补(A1/ v2.2 修订**`tree_evaluation`(鉴定主记录)加 `trial_study_id`(可空,按该年 `observation.trial_study_id` 推导或直填),使该次鉴定的所有性状明细(经 evaluation_id 关联的 `breeding_trait_observation`)都继承环境键,纳入 MET 环境效应估计(原"固定列层漏环境键"的裂痕在长表下由主记录统一承载)。
**统一性状值视图(v1.3 补 / v2.2 F1 重定义,统计层关键)**:性状值一律经 `trait_id``trait` 字典关联(长表天然带键,无固定列漂移问题)。在统计/GS 层定义**统一性状值视图 `v_trait_value`**DB **普通 VIEW**),把 `breeding_trait_observation`(单株鉴定明细,喂 EBV)+ 必要时 union `breeding_observation`plot/物候)按 `(unit_key, trait_code, obs_year)` pivot 归一为宽/长表,供 V1.1 BLUP 与 V3.0 决策消费——**普通 VIEW 保证 fresh,不会有过期数据污染 EBV**。看板/报表另建**物化视图 MV**(定时刷新换性能),**MV 不得作为 BLUP 输入**。种子初始化只需把 `pa_four` 写入 `trait` 字典(`is_core=true`),不再向任何固定列写值;新增核心性状只加字典行,不改表结构。
> **v1.6 补(A6/ v2.0 修订**:视图/引擎须把 `tree_evaluation`/`observation` 的观测按 `tree.clone_id`**v2.0:由 `tree.germplasm_id` 改为 `tree.clone_id`→`breeding_clone`**,详见 §3.0)聚合为 clone 的**重复测量**(同一 clone 经扩繁多株 tree 是重复而非独立个体),EBV 随机效应估在 `breeding_clone` 级(`clone_id`),tree 作重复;否则 V1.1 会误把每株当独立个体高估自由度。
---
## 5. 统计分析与决策地基(关键要求)
用户明确要求"统计分析与决策,需要基础能够支持"。数据模型须满足:
1. **任意性状可聚合**:统一性状值视图(§4 末尾,v2.2/F1 由 `breeding_trait_observation` + `breeding_observation` 长表 pivot)使「按性状×年份×地点×阶段」切片聚合无需改表——这是 ABLUP/EBV 与选择指数的输入。
2. **MET 结构就绪(v1.3v1.5 补全)**`tree.trial_study_id`**v1.5 仅记「定植所属 study」**,派生自 planting+ `tree.block_no`(区组随机效应)+ `trial_study.block_count` + **`trial_study_entry`entry_number 设计矩阵聚合键)** + **`treatment`factor×levelv1.5 提进一期,支撑 split_plot 等因子效应)** 提供完整试验设计维度;跨年/跨点观测经 `observation.trial_study_id + obs_year` 表达(树自身不跨 study)。`site` 经纬度/海拔支持 **空间 BLUPsommer 空间项)**。V1.1 混合模型 `y = rootstock + site + year + block + treatment + environment + genotype(clone) + clone×year(随机互作) + G×E(+空间)` 各效应项齐备(**v2.2/F5`rootstock` 作固定效应显式入模,与 §5.x 铁律一致,否则 EBV 被砧木注水**;**v2.1/R9:桃多年生、同 clone 跨年观测是重复测量,须含 `clone×year` 随机互作,否则单年运气被当遗传进展**),可输出 clone 级 EBV。
> **sommer 基线公式(v2.2/B3,供 R 脚本落地)**`mmer(y ~ rootstock + site + year + block, random = ~ vsr(clone, Gu=Amat) + vsr(clone:year), rcov = ~ units, data=...)`,其中 `clone` 走 A 矩阵(`Amat` 由 §3.18 `breeding_pedigree` 构造),`rootstock/site/year/block` 为固定效应扣除系统偏差。lme4 退化版:`lmer(y ~ rootstock + site + year + block + (1|clone) + (1|clone:year))`(无 A 矩阵时)。
>
> > **v2.3 已落地)G×E 交互引擎**`run_ablup` 已支持 `gxe=True` + `gxe_env=site/year``method=GXEBLUP`);site→自动固定效应 `trial_study`、year→自动固定效应 `year`;σ²gxe/gxe_ratio/n_cross_env 落 `breeding_prediction.note` JSON**不可辨识门禁**(无跨环境重复 / 单元内无重复)→409「G×E 不可辨识」;同 clone 多株**坍缩为基因型节点 `c{clone}`**(EBV 一致,重复测量聚合);异步 `StatisticsJobModel` job_type=GXE/ABLUP + SUCCESS/FAILED。落地台账见 §8.11 与 `桃育种系统统计引擎实施记录.md`。
3. **选择指数可计算**:统一性状值视图(表型) + `genotype_call`(基因型) → 多维选择指数(RosBREED DNA-informed 思路),按 `stage` 分层筛选;`selection_rule`(§3.11)把阈值显式化,支持自动 flag/晋级。**(v2.5 落地:指数单位=无性系级)**——桃无性繁殖、一个 clone 多株遗传同质,先按 §5.7 的 `clone_id` 聚合成遗传实体再排名(EBV 均值**按可靠性加权**,同一优系不会因"只中 1 株"被拆散漏选),未晋升 clone 的实生株退化单株参与;`selection_result` 按遗传实体写(clone 级决选 + 溯源株)。
4. **选择强度可算(v1.3 补)**`seed_lot.seed_count`→成苗→定植→入选 四级计数贯通(§3.13),育种效率/选择压力可量化,且与 MET 的"每组合在某点种了多少"挂钩。
5. **决策支撑**`selection_result`(晋级/淘汰) + `stage` 流转 + EBV 排名 + `selection_rule` 自动标记 → 前端决策视图(哪些株晋级/淘汰、依据 EBV 与哪条规则)。
6. **溯源闭环**`tree→combination→父/母本 germplasm` + `observation/field_operation/pollination` 全 FK → 任意品系反向追溯(需求 7.1)。
7. **重复测量聚合(v1.6A6 / v2.0 修订)**:同一 clone 经扩繁产生多株 tree,其表型是同一基因型的重复观测;统计前按 `tree.clone_id``breeding_clone` 聚合为 clone 重复(**v2.0:取代原 `tree.germplasm_id`→germplasm 级聚合**),EBV 随机效应估在 `breeding_clone` 级(`clone_id`),避免自由度虚高。
8. **系谱 A 矩阵(v1.6B9 / v2.0 明确 / v2.2 A4 修订)**:除基因组 G 矩阵(来自 `genotype_call`)外,BLUP 可并入系谱 A 矩阵;A 矩阵系谱**以 §3.18 `breeding_pedigree`dam_id/sire_id 递归闭环)为唯一权威**v2.2/A4),供 `sommer` 递归构造;`cross_combination` 的父/母本仅作 clone 系谱行的**自动派生源**(建 clone 时据组合父母本自动生成 pedigree 行),不作独立系谱来源,避免双源不一致。`breeding_clone.female/male_parent_id` 仅为冗余直查列。**砧木(`breeding_rootstock`)绝不进 A 矩阵**(建模铁律,§5.x)——砧木改表型不改遗传身份。
9. **EBV 驱动选择(v1.6B10 / v2.2 B4 修订)**`selection_rule`(§3.11)的 `conditions_json` 除引用 `trait_code`(表型阈值)外,应允许引用 `prediction_value`(EBV 排名阈值),实现 RosBREED「表型 + EBV」双轨选择。**v2.2/B4)双轨统一在 clone 级判定**:表型侧先按 `tree.clone_id` 聚合到 clone 均值,再与 clone 级 EBV 按同一规则比较,避免"表型按株、EBV 按 clone"粒度错配。
10. **负载量协变量(v1.7,硬缺口②)**`tree_evaluation.crop_load`(坐果量评级 1/2/3)作为果实性状混合模型协变量,吸收单株负载造成的环境/生理误差(专册 1.3),提升 EBV/选择指数精度;V1.1 引擎须支持该协变量项。
11. **超期预警/通知(v1.7,软缺口⑤,工程项)**:专册 3.3.2「树 N 年未决策预警」由定时任务(cron)扫描 `selection_result`/`tree.stage` 实现,结合 `selection_rule` 触发通知;不阻塞一期数据模型,属前端/调度工程项。
### 5.x 砧木建模铁律(遗传评估不可动摇规则,v2.0 2026-07-30 锁定)
> 适用于所有落地:数据字典、R 脚本(sommer/lme4fixed 公式、observation 层字段、质量门禁。
1. **记录层**:砧木只记在 observation 层(`tree`/`planting``rootstock_id``breeding_rootstock` 字典,§3.17);`breeding_clone` 系谱层**无砧木**。
2. **A 矩阵(遗传随机关系)**:**绝不进**——砧木改表型不改遗传身份,进 A 矩阵会污染 clone 的 EBV。
3. **BLUP 固定效应**:砧木**必须进**,与 `地点 / 年份 / 定植批次` 并列扣除系统偏差;否则残差被污染、clone 的 EBV 被砧木注水。
> 关键澄清:"不进 A 矩阵" ≠ "不进模型"——砧木不进随机遗传关系,但**必须进固定效应**。这一字之差直接决定 EBV 是否被砧木注水,是建模正确性的命门。
### 5.y 间接早选(indirect early selectionv2.0
| 分期 | 内容 | 阶段 |
|---|---|---|
| 童期采集 | `trait.stage=juvenile` 性状采集(tree 视角,2–3 年) | **一期必做** |
| r_G 早选模型 | 基于遗传相关 r_G 的早选(童期性状预测评价段性状) | 排**二期** |
| 一期过渡 | 用历史"晋级/淘汰"标签训练**监督分类器(过渡)** | 一期 |
### 5.z 模型健康监控(v2.1R4
> "模型还准不准"的命门。每次 BLUP 重跑后扫描并与上一轮对比:
> - **h² 连年突降**:某性状 h² 较上一轮跌幅超阈值 → 告警(疑似数据质量/环境突变)。
> - **clone EBV 排名大幅翻转**:排名 delta / 排序相关性骤降 → 告警(疑似录入错误或模型设定漂移)。
> - 输出进现有告警/定时任务通道(§5 第11点),与"树 N 年未决策"并列。
>
> **(v2.3 已落地)方向感知**:轮次对比 `compare_predictions` 已按性状当前 `direction` 排序(asc 时 rank 1 = 最低 EBV 优);h²/相关/翻转位移量对反转不变量不变,仅展示 rank 列不再把最差株显示为第 1。
---
## 6. 实施路线(建议)
| 阶段 | 内容 |
|---|---|
| **第0阶段 数据治理(占40%、前置,v2.0/v2.1/v2.2** | 盘点5年历史数据 + **breeding_clone 系谱表(§3.0** + **breeding_pedigree 独立系谱表(§3.18,A 矩阵唯一权威)** + **breeding_rootstock 砧木字典(§3.17** + **trait_observation 单株鉴定明细长表(§3.2b,v2.2 补登记既有表)** + `trait``stage`(§3.1+ 字段规范 + **数据质量门禁(§3.16**garbage in garbage out,决定后续 EBV 可信度 |
| 地基(先做) | trait(含 ontology_uri) + observation(含 status) + **trait_observation 单株鉴定明细长表(§3.2b,v2.2 补登记既有表)** + 现有模块 stage/rootstock/accession_no/pedigree 字段;数据权限/options 沿用现有生成器 |
| P0 | field_operation |
| P1 | trial(+study+**study_entry**,§3.4)、**treatment(试验因子/处理,§3.14,v1.5 提进一期)**、**planting_treatment(§3.15,v1.6)**、group(+member,§3.5)、propagation(克隆扩繁,§3.8)、seed_lot(种子批,§3.13,**v1.5/v1.6 used_count 派生剩余**)、environment_condition(环境因子,§3.9)、audit_log(审计,§3.10)、selection_rule(选择阈值,§3.11,**v1.6 支持 EBV 阈值**)、**site 坐标 + germplasm 护照块 + pollination 父/母本树 + selection_result.rule_id(v1.4)+trial_study_id(v1.6) + planting.entry_id(v1.5)+propagation_id(v1.6)+block级粒度 + tree 两类区分 + tree_evaluation.trial_study_id(v1.6) + tree_evaluation.crop_load(v1.7) + tree_photo.observation_id(v1.6)(§4 字段调整)** + trial_study.season(v1.6) + marker.assembly_version(v1.6) + trait.method_uri/scale_uri(v1.6) + observation.validated_by/date/unit(v1.6) + kinship A矩阵(v1.6) |
| P2 | statistics 聚合端点(含 selection_rule 驱动的自动 flag/晋级预览) |
| **延后(v1.4 标记,v1.7 调整)** | **experiment_factorMIAPPE 受控试验因子,先用 field_operation 近似)、breeding_program 顶层(BrAPI Programtarget 暂代)** |
| **批量表型导入(v1.3 补,规划)** | `observation` 是 EAV(性状×单元×值),主数据入口是**成千上万条观测的批量进表**(设备/ sheet 导出),与现有"一行一实体"行式导入机制不同,需单列导入通道(含 trait_code 校验、单位换算、单元解析 tree_id/plot_id |
| 字典类型扩展 | breeding_dict.sql 增 breeding_stage/breeding_generation/breeding_group_type/breeding_design_type 四类(英码+中文),接入下拉与 Excel 导入翻译(DictLabelResolver) |
| V2.0 | marker + genotype_sample + genotype_call(地基先建表,分析后置)+ **GS 模型训练**(§3.12,值表已 V1.1 前移) |
| V1.1 | R 统计引擎接入统一性状值视图 + trial 做 BLUP/EBV |
| V3.0 | AI 决策(Agno + DeepSeek)消费 EBV/选择指数 |
| BrAPI 适配层 | 只读 `/brapi/v2/*` 端点(germplasm/crosses/trials/studies/observations/observationvariables/lists/samples/markers/calls/programs**field_operation 映射为 `/observations`(带 op_type) 而非 `/events`**),对接 Breedbase/Flapjack/国际交换(§0 原则 7 |
**工程约定(生成器机制待拍板)**:新模块用**系统内置代码生成器**`module_generator/gencode`DB-first,产物落 `app/plugin/`,自动建菜单)还是**续用自定义 `_gen_*.py`**(落 `app/api/v1/module_breeding/`,与现有 14 域一致)仍待用户定 A/B/C(见记忆「建表/生成器坑」)。无论哪条,改字段后跑 `deploy.bat migrate``fix_breeding_columns.py`)再重启后端。
---
## 7. 待确认项(收口)
v1.7–v1.8 已闭环统计/决策地基与团队隔离;**v1.9 已收口"枚举归属 A/B"(性状量表选项→`scale_json`、不进 `sys_dict`,详见 §3.1 / §0 原则1)**。剩余**唯一未拍板项 = 生成器机制 A/B/C**(注意:此 A/B/C 与"枚举归属 A/B"是两回事,勿混):
1. **生成器机制 A/B/C(唯一未拍板)**:新模块落 `app/plugin/`(内置 gencode 式)/ 续用自定义 `_gen_*.py`(与老 14 一致)/ 全迁 plugin 式。其余规格(含 v1.7 全部字段、v1.9 枚举归属)均已锁定,实施时据此生成即可。
> 文档进入"v1.9 枚举归属定稿版"。除生成器 A/B/C 外,待用户明确"做/搞吧"后实施,不先行编码。
---
## 8. 复审补充:遗漏与替代思路(2026-07-28 复审)
> 本节为第一稿(§0–§7)的批判性复审结论,针对"还有哪些遗漏 / 不同思路"自省。改变范围的项标注「待拍板」。
### 8.1 原稿遗漏的关键项
1. **`generation`(遗传世代)与 `selection_stage`(选择阶段)混为一谈**:桃虽以无性选择为主,但回交转育(BC1/BC2)、自交分离(F2)仍是真实遗传世代,与"选到第几轮"是两回事。建议拆字段:`generation`F1/BC1/BC2…,跟 `cross_type` 联动)+ `selection_stage`(实生苗/初选株/复选株/品系/区试/新品种)。
2. **缺"树→种质"晋升链路(克隆生命周期)**:入选株应晋升为 clone/accessiongermplasm)被命名扩繁。需 `tree.germplasm_id`,否则基因型(测在 germplasm)与表型(测在 tree)无法在 GS 中拼接。
3. **原清单 1.4「按团队权限隔离」→ 改用 `sys_dept` 承载课题组隔离(v1.8 定稿)**:经讨论,team 仍**不建独立模块、不加 `owner_team` 字段**;但启用 FastApiAdmin 框架**已有**的"部门(dept)数据范围"能力承载课题组隔离——把"课题组"建模为 `sys_dept` 节点,给角色配"本部门及子部门"数据范围,`Permission._permission_condition()` 即按创建者所在部门自动隔离,breeding 表零改动。
**隔离边界(关键业务决策)**
| 数据域 | 隔离策略 | 理由 |
|---|---|---|
| 性状字典、选择规则 | **跨组共享** | 全所统一观测标准与选择阈值 |
| 种质资源、系谱 | **跨组共享** | 所级资源库,亲本须被各课题组选配 |
| 试验基地、地块、育种人员 | **按课题组隔离** | 各组自有基地/地块与人员花名册 |
| 育种流程(杂交→评价) | **按课题组隔离** | 各组私有作业数据 |
| 统计分析(数据集/计算/育种值/指数/报告) | **按课题组隔离** | 各组独立遗传评估与决策 |
**局限**:隔离靠"创建者部门"推断(谁建的归哪组);若要"跨组协作同一条数据"需升级显式 `owner_team` + 多对多协作,留待单独立项。
**范围说明(2026-07-29 澄清)**:当前实际仅「桃育种课题组」在用,多课题组为**未来扩展**预留。隔离机制**先就位**——建 `sys_dept` 课题组节点 + 给角色配"本部门及子部门"数据范围即可,无需改任何 breeding 代码;无多组时所有用户同属一组,效果等同无隔离,不影响现有使用。未来新增课题组只需加 dept 节点并迁移用户 `dept_id`,即可自然隔离。
**落地(配置级、非代码,需先确认真实课题组清单)**:① `sys_dept` 建课题组节点 ② 用户 `dept_id` 归属 ③ 育种员等角色配数据范围"本部门及子部门"ADMIN/SUPER_ADMIN 看全部)④ 验证普通用户仅见本组数据。
4. **"材料库存"被弱化成纯报表**:库存是事务性的(种子批/ lot、在圃株数、离体/DNA 管数、活力)。应加 `germplasm_stock`/`seed_lot` 表(数量、批次、位置、活力、出入库),报表只是视图。【待拍板】
5. **缺环境/气象数据(G×E 统计地基)**:多年多点分析核心是基因型×环境互作,无环境协变量(site×year 的需冷量/积温/降雨)BLUP 只能粗估。建议加 `environment_condition`site×year),可复用 `yz.sql` 的"天气"字段。
6. **分子层缺"预测模型"表(GS 反馈环断裂)**:RosBREED 是闭环(表型+基因型→训练模型→输出 EBV→指导下轮选配)。需 `breeding_prediction`(模型/性状/精度 accuracy/预测日期/被预测个体)。
7. **克隆繁殖/苗圃 → 已定纳入一期(§3.8)**:现有 `seedling`/`seed_treatment` 仅种子实生苗;桃入选后主要靠嫁接/芽接扩繁,补 `breeding_propagation`(接穗来源→成活→出圃),打通 入选株→克隆种质→扩繁→新定植树 闭环。
8. **统一修改日志/审计缺失**:晋级审批、全程可追溯需"谁/何时/改了什么"轨迹,现有仅 `updated_time`。建议轻量 `breeding_audit_log`(或接系统操作日志)。
9. **小遗漏**`tree_photo` 应可关联 `observation`(某次测量的果实照片,为 CV/AI 预留);`observation` 应可挂 `trial_study_id`(区分试验观测 vs 果园日常观测);编号生成策略未定义(`accession_no`/`combination_code`/`tree_no`/`trial_code` 需统一自动编号服务)。
### 8.2 替代思路与推荐
- **A. EAV 纯通用 vs 混合固定列 → ~~推荐混合固定列~~(v2.2/F1 已推翻,改为单一长表,详 §8.4)**。~~理由:桃果实质性状稳定且高频、报表是核心需求、现有 tree_evaluation 已在工作。~~ **v2.2 更新**:代码 2026-07-29 已删 `tree_evaluation` 固定列、全迁 `breeding_trait_observation` 长表,故最终裁定走单一长表;原"报表性能"顾虑改由 DB 视图 pivot(统计 VIEW / 看板 MV)解决,不再保留固定列。
- **B. 分组 vs 标签 → 建议并行**:`group`(正式项目组/品系群)+ 自由 `tag`(多对多,如"抗褐腐""高Brix""区试备选")。
- **C. 直接对齐 BrAPI API → 已采纳(见 §0 原则 7)**:不仅"铺路",而是正式承诺实现 BrAPI 兼容只读适配层。建议首批暴露端点(映射我们的模块):
- `/brapi/v2/germplasm``/brapi/v2/germplasm/{id}/pedigree` ← germplasm + cross_combination 系谱链
- `/brapi/v2/programs` ← target`/brapi/v2/crosses` ← cross_combination
- `/brapi/v2/trials``/brapi/v2/studies` ← trial / trial_study
- `/brapi/v2/observationvariables` ← trait`/brapi/v2/observations` ← observation
- `/brapi/v2/lists` ← group`/brapi/v2/observations`(带 op_type) ← field_operation(注:BrAPI 无顶层 Event,不映射 `/events`
- `/brapi/v2/samples``/brapi/v2/markers``/brapi/v2/calls` ← 分子层
- 适配层为**只读适配器**(读我们现有表,映射成 BrAPI JSON),不重复实现写操作;UI 仍走 `/breeding/*`
- **D. MIAPPE 合规 → 已采纳(见 §0 原则 8**Investigation=target、Study=trial_study、ObservationUnit=tree/plot、Variable=trait 对齐;作为数据导出/共享到国际仓储时的一致性检查基线。
### 8.3 复审后模块清单(原 21 模块基础上)
- 新增(一期):`environment_condition`site×year 环境因子,G×E 统计地基,§3.9)、`propagation`(克隆扩繁/苗圃,§3.8)、`breeding_audit_log`(审计,§3.10)、`breeding_selection_rule`(选择阈值,§3.11)、`breeding_seed_lot`(种子批/库存链,§3.13,v1.3 从延后**提前进一期**与 MET 一并建模);`breeding_prediction`(GS 模型/育种值,V2.0 与分子层同期,§3.12);`breeding_trial_study_entry`(试验 entry 清单,v1.4,MET 设计矩阵);`breeding_genotyping_dataset`(分型数据集,v1.4,GS 训练群体)。
- **字段强化(v1.4**`trait.ontology_uri`Crop Ontology 对接);`observation.status`(数据质量);`site` 经纬度/海拔(空间 BLUP);`germplasm` 护照块(FAO-MCPD);`pollination` 父/母本树(crossing block);`selection_result.rule_id`(决策闭环);`tree.entry_id`entry 聚合);`marker.panel`(芯片版本);`genotype_sample.dataset_id`
- **不建 `team` 模块**(v1.8 定稿):团队隔离由 `sys_dept` + 角色数据范围实现,breeding 表不加 `owner_team` 字段;公共基础数据跨组共享、育种流程与统计按组隔离(见 §8.1 第 3 点)。
- **仍延后(v1.4 标记)**:完整事务性出入库台账(`germplasm_stock` 等,`seed_lot` 已精简进一期);`experiment_factor`(MIAPPE 受控试验因子,先用 field_operation 近似);`breeding_report` 配置表(先用只读端点);`breeding_program` 顶层(BrAPI Programtarget 暂代)。
- 字段细化:`tree.germplasm_id` + `generation``tree.trial_study_id` + `block_no`**派生自 planting,单写点纪律**v1.4);`planting.trial_study_id` + `block_no` + `seed_lot_id``observation.trial_study_id` + 显式 FKv1.3);`tree_photo.observation_id`;统一编号生成服务。
- 物候期仍走 `observation`(时序,非固定列);系谱树仍靠 `cross_combination.parent_combination_id` 自链 + 前端树图。
### 8.4 长表决策详述(对应 §4 tree_evaluationv2.2/F1 改写)
**结论:单一长表(废弃"混合固定列")。** v1.0v2.1 曾定"混合固定列(Hybrid",但代码 2026-07-29 已删 `tree_evaluation` 固定列、全迁长表,统计 service 改从长表 pivot 取数;文档据此裁定改为单一长表:
- **单株鉴定明细层 = `breeding_trait_observation`**(挂 `evaluation_id`,tree 级):承载童期 + 评价段的所有单株性状(含原 `pa_four` 的 ~40 个核心果实/农艺性状),是 clone 级 EBV 的取数主路径,**喂 EBV**。
- **plot/物候层 = `breeding_observation`**:仅承载 plot/combination 级观测 + 物候期时序,**不喂 EBV**。
- **两表按"是否喂 EBV"正交切分**plot 级果实均值**不落表**,由统计视图从 `breeding_trait_observation` 聚合派生(§3.2/§3.2b),杜绝双写。
- **报表/SQL 聚合补偿(原固定列的唯一收益)**:由 DB 视图 pivot 顶上——**统计管线用普通 `VIEW`(实时 pivot、保 fresh、喂 BLUP****看板/报表用物化视图 `MV`(定时刷新换性能),但 MV 不得作 BLUP 输入**,避免过期数据污染 EBV/reliability。
- **防双源规则**:同一性状值只存一处(tree 级果实性状→`breeding_trait_observation`;物候/plot→`breeding_observation`),禁两表重复记录;`trait.is_core` 仅作"是否纳入统计核心指标"标志,**不再决定"存固定列还是 EAV"**。
- **代价**:报表需经视图 pivot(一次性建视图,非每次改表);换来"新增性状零表结构变更"与代码/文档一致。原"新增核心性状需 migrate 改表"的代价消除。
### 8.5 二次复审(v1.32026-07-28)— §8 遗留项处置
针对 §8.1–§8.3 的遗留与本人深度复盘,本轮一次性落档,要点:
| # | 议题(源自 §8 / 复盘) | v1.3 处置 |
|---|---|---|
| 1 | **MET 链路断裂(最致命)** | 彻底补全:`trial_study.block_count` + `planting.trial_study_id` + `tree.trial_study_id`/`block_no` + `plot.block_no`(§3.4/§4)。block 随机效应不再缺失,混合模型可估 |
| 2 | **库存与选择强度** | `seed_lot` 从"延后"提前进一期(§3.13),与 MET 拼出 seed_lot→seedling→planting→tree→trial_study 选择强度链;完整 ledger 仍延后 |
| 3 | **§0 原则1 与混合模型自相矛盾** | 已修订 §0 原则1 措辞,与 §4/§8.4 一致(字典一处定义、值可固定可扩展) |
| 4 | **observation/field_operation 多态反模式** | 改显式可空 FKtree_id/plot_id/combination_id),保引用完整 + 数据权限 `_build_conditions` 可用(§3.2/§3.3 |
| 5 | **三模块只有名字无规格** | 已补 `environment_condition`(§3.9)、`audit_log`(§3.10)、`prediction`(§3.12);并额外补 `selection_rule`(§3.11) |
| 6 | **tree_evaluation "保留"误述** | 改为"按 pa_four 扩 ~40 列",并补**统一性状值视图**消除 trait↔固定列双源漂移(§4) |
| 7 | **选择阈值规则缺失** | 新增 `breeding_selection_rule`(§3.11),决策支撑可自动化 |
| 8 | **批量表型导入未规划** | 已单列规划(§6),EAV 主数据入口区别于行式导入 |
| 9 | **tree_photo.observation_id 未落地** | 已纳入 §4 字段调整(todo 与正文对齐) |
| 10 | **group family/category 冗余** | family 改虚拟分组(由 combination_id 推导)、category 复用 `variety_type`(§3.5 |
| 11 | **BrAPI `/events` 不标准** | field_operation 改映射 `/observations`(op_type)(§3.3/§8.2-C |
| 12 | **文档计数过期** | §2 改为显式清单,不再钉"21" |
| 13 | **生成器机制** | 标注为待拍板 A/B/C(§6 工程约定),不再默认续用 `_gen_*.py` |
> 本轮为**纯文档定稿**,未触碰任何代码。待用户就 §7 minor 项(尤其生成器 A/B/C)确认后即可实施。
### 8.6 三轮复审(v1.42026-07-28)— 国际基准(BrAPI/Breedbase/RosBREED/MIAPPE/Crop Ontology/FAO-MCPD/Genesys
对照国际先进做法再扫一遍,把"正经育种程序该有、v1.3 仍缺"的落档:
| # | 议题(国际基准) | v1.4 处置 |
|---|---|---|
| 1 | **缺试验 entry 清单 / entry_number**BrAPI ObservationUnit = germplasm×entryNumber×rep×block | 新增 `breeding_trial_study_entry`(§3.4),`tree.entry_id` 挂回,BLUP 设计矩阵按 entry 聚合 |
| 2 | **缺 site 地理坐标**(空间 BLUP / MIAPPE 环境 / 积温插值) | `site``latitude/longitude/elevation`(§4 |
| 3 | **缺观测校验态**Breedbase 数据质量) | `observation.status`draft/validated)(§3.2),统计前按 validated 筛 |
| 4 | **trait 缺本体引用**Crop Ontology / MIAPPE 受控词表) | `trait.ontology_uri`(§3.1);注明 method/scale 内联简化、BrAPI 适配层拆分三元组 |
| 5 | **tree↔planting 双写漂移风险**(v1.3 隐患) | 明确**单写点=planting**`tree.trial_study_id/block_no` 为**派生**service 写树校验一致(§3.4 注) |
| 6 | **germplasm 缺护照描述符**FAO-MCPD / Genesys | germplasm 补 `institute_code/country_origin/collection_site/acquisition_date/biological_status/breeding_program`(§4 |
| 7 | **缺 genotyping_dataset**GS 训练群体分组) | 新增 `breeding_genotyping_dataset`(§3.7),`genotype_sample.dataset_id``marker.panel`(芯片版本) |
| 8 | **selection_result 未关联规则**RosBREED 决策闭环) | `selection_result.rule_id`(§4 |
| 9 | **缺 crossing block 父/母本树**(桃控制杂交) | `pollination.female_tree_id/male_tree_id`(§4 |
| 10 | **受控试验因子未结构化**MIAPPE ExperimentalFactor | 标记延后,先用 `field_operation` 近似(§6 |
| 11 | **breeding_report 配置表过早** | 标记延后,先用只读端点(§6) |
| 12 | **target 映射 BrAPI Program 略偏** | 标记延后,target 暂代 Program,后续可加 `breeding_program` 顶层(§6 |
| 13 | **tree.germplasm_id 多路径派生漂移** | 明确 `germplasm_id` 非空且由晋升流程写入、禁手填(§4) |
> 本轮为**纯文档定稿(v1.4)**,未触碰任何代码。文档进入"国际基准对齐版",待 §7 minor(尤其生成器 A/B/C)确认后实施。
### 8.7 四轮复审(v1.52026-07-28)— 用户拍板的 v1.4 自洽修复
用户就第四轮复审(§8 末尾 16 点)拍板:只要合理全部采纳以下 5 点,并生成新版:
| # | 议题(v1.4 自洽/国际盲点) | v1.5 处置 |
|---|---|---|
| 1 | `planting` 单写点却无 entry`tree.entry_id` 无法派生 | `planting``entry_id`(§3.4/§4);`tree.entry_id`/`block_no`/`trial_study_id` 全派生自 planting |
| 2 | 多年生 `tree` 与单值 `trial_study_id` 冲突(跨年观测归属丢失) | `tree.trial_study_id` **仅记「定植所属 study」**;跨年/跨点观测改由 `observation.trial_study_id + obs_year` 表达,不引入中间表,保单写点纪律 |
| 3 | 试验树 `germplasm_id` 时序张力(入试即需已知 vs 晋升才写) | 区分两类 tree:`planting.entry_id` 非空 ⇒ 参试无性系(`germplasm_id` 入试即定 = `entry.germplasm_id`);为空 ⇒ 杂种实生苗(待晋升)。以 entry 有无区分,无需新类型字段 |
| 4 | `split_plot` 设计已支持但 `experiment_factor/treatment` 延后 | `breeding_treatment`(factor+level) **提进一期(§3.14**,混合模型增 `treatment` 项,可估因子主效应与互作 |
| 5 | `seed_lot` 非事务致「获种数」源头不可靠 | `seed_lot``used_count`,派生 `remaining = seed_count - used_count`,选强链前段(获种→已用)可量化 |
> 本轮为**纯文档定稿(v1.5)**,未触碰任何代码。文档进入「v1.5 自洽修复版」,待 §7 minor(尤其生成器 A/B/C)确认后实施。
### 8.8 五轮复审(v1.62026-07-28)— 用户拍板"全部采纳"第五轮复审
用户就第五轮复审拍板"全部采纳",落档 v1.6(同时补齐 v1.5 因替换异常遗漏的 §3.14/treatment 行/used_count):
| # | 议题 | v1.6 处置 |
|---|---|---|
| A1 | 核心性状固定列(tree_evaluation)缺 trial_study_id 环境键 | tree_evaluation 加 `trial_study_id`(按年 observation 推导/直填),使核心性状纳入 MET 环境效应(修复 v1.5 裂痕) |
| A2 | planting 粒度未定义 | 明确 planting=block 级批次;同 entry 跨多 block 建多 planting |
| A3 | treatment 关联字段未落地 | 新增 `breeding_planting_treatment`(§3.15planting×treatment 多对多) |
| A4 | seed_lot.used_count 单位未定义 | 明确=已从该批取用**粒数**(播种环节按粒累加,非定植株数) |
| A5 | tree_photo.observation_id 文档自述已改但 §4 无行 | §4 补 `tree_photo` 行(observation_id |
| A6 | EBV 估 germplasm 级但 tree↔germplasm 重复测量未建模 | 明确 tree_evaluation/observation 按 `tree.germplasm_id` 聚合为 clone 重复,EBV 随机效应在 germplasm |
| B1 | marker 缺 assembly_version | marker 加 `assembly_version` |
| B2 | 基因型编码标准 | genotype_call.allele 声明 VCF/GP 编码(0/1/2=纯合ref/杂合/纯合alt |
| B3 | season 概念 | trial_study 加 `season` |
| B4 | observation 缺审核人/时间 | observation 加 `validated_by`/`validated_date` |
| B5 | 单位校验+批量换算 | observation 加 `unit`(冗余自 trait),导入服务做换算 |
| B6 | method/scale 受控词表 URI | trait 加 `method_uri`/`scale_uri` |
| B7 | planting 来源双路径 | planting 加 `propagation_id`(种子批/扩繁批二选一) |
| B8 | observationUnit level | 文档标注 tree/plot/block 对应 BrAPI observationLevels |
| B9 | kinship/A 矩阵 | §5 补系谱 A 矩阵(pedigree 解析) |
| B10 | selection_rule 支持 EBV | conditions_json 允许引用 prediction_valueEBV 阈值) |
| B11 | breeding_program 自由文本说明 | 文档标注 germplasm.breeding_program 暂自由文本、后续可升级 FK |
| C1 | selection_result 跨年晋级关联 | selection_result 加 `trial_study_id`(可空) |
| C2 | 新表数据权限接入 | 文档约束新模块须用 CRUDBase 自动注入数据权限 |
> 本轮为**纯文档(v1.6)**,未触碰任何代码。此后 v1.7(统计决策闭环)、v1.8(团队隔离收口)均为纯文档演进,未触碰任何 breeding 业务表/接口/代码。文档进入「v1.8 团队隔离定稿版」,待生成器 A/B/C 拍板后实施。
### 8.9 V2.11 方案书统计/决策支撑对照(v1.72026-07-28
用户要求评估《桃育种数字化项目方案书_V2.11》中「统计分析与决策支持」(专册 2.1–2.8 方法 / 3.13.4 决策)能否被 v1.6 支撑。结论:**方法面全部可支撑**(数据地基 / MET 维度 / 统计引擎接口齐备);发现 3 硬 + 2 软缺口,v1.7 全部闭环:
| # | 缺口 | v1.7 处置 | 类型 |
|---|---|---|---|
| ① | EBV 持久化时序冲突(值表标 V2.0,但趋势图 / 双轨选择 / 亲本单株决策需读持久化 EBV) | `breeding_prediction_value` 值表前移 V1.1,与统计引擎同期写入;GS 模型训练留 V2.0 | 硬 |
| ② | 负载量协变量未建模(专册 1.3 要求坐果量评级降果实性状环境误差) | `tree_evaluation.crop_load`(评级 1/2/3)作混合模型协变量 | 硬 |
| ③ | `breeding_report` 延后(专册 3.3.1 年度 Word/PDF 报告) | 用户确认一期必须:进 P2,补 `output_format` + 报告生成服务(docx/pdf 导出) | 硬/软(用户拍板"必须" |
| ④ | 数据质量自定义生物学阈值无落点 | `breeding_trait.valid_min/valid_max` 承载合理范围,供异常标记 | 软 |
| ⑤ | 超期预警/通知机制(专册 3.3.2 树 N 年未决策预警) | 列为工程项:cron + `selection_rule`/`selection_result` 触发通知,不阻塞数据模型 | 软 |
> 本次为**纯文档(v1.7)**,未触碰任何代码。文档进入「v1.7 统计/决策闭环版」,仅余生成器 A/B/C 待拍板。
---
### 8.10 深度复审 AH 全量落地(v2.2,2026-07-30,用户逐条确认 + F1/F2 拍板)
**变更索引**(每项均已在正文对应 § 落字):
| 编号 | 问题 | 裁决 | 落点 |
|---|---|---|---|
| A1 | `tree.clone_id` 定植必填与"clone=入选克隆"矛盾 | 实生苗定植可空、入选晋升才建 clone 回填;参试无性系必填 | §3.0/§4 tree |
| A2 | `produced_clone_id` 命名易读作"新建克隆" | 澄清=被扩繁原 clone、沿用不新建 | §3.8 |
| A3 | `rootstock_id` FK 三处打架 | 全文统一 FK→`breeding_rootstock`germplasm.is_rootstock 仅标记 | §1/§3.8/§4/§5.x |
| A4 | A 矩阵系谱来源双源 | 以 `breeding_pedigree` 为唯一权威,combination 仅派生源 | §3.18/§5.8 |
| B1 | h² 落在明细每行 | 上移主表 `breeding_prediction`(一次 BLUP×一性状=一 h²) | §3.12 |
| B2 | "广义遗传力"误称 | 正名加性(狭义) h²,落库取克隆均值 h²=V_clone/(V_clone+V_e/k̄) | §3.12 |
| B3 | 缺 sommer 基线公式 | 补 `mmer(y~rootstock+site+year+block, random=~vsr(clone,Gu=A)+vsr(clone:year))` | §5.2 |
| B4 | 双轨选择粒度错配 | 统一 clone 级判定(表型先聚合到 clone 均值) | §5.9 |
| C1 | 门禁作用于固定列 | 改作用于 `breeding_trait_observation` 长表 | §3.16 |
| C2 | 缺质量标记字段 | 加 `issue_status`normal/pending/rejected),不新建表 | §3.2/§3.2b |
| C3 | 门禁与状态机脱节 | 拒收→rejected+draft;异常→pendingnormal+validated 才进池 | §3.16 |
| D1 | selection_result 无 clone 级 | 加 `clone_id`tree_id 留溯源) | §4 |
| D2 | clone 无世代 | 加 `generation`(可由 combination 派生) | §3.0 |
| D3 | entry 未落 clone | `trial_study_entry``clone_id` | §3.4 |
| D4 | tree↔clone 状态流转缺矩阵 | 补状态流转矩阵(下) | §8.10 |
| F1 | 固定列 vs 长表三方打架 | **裁定单一长表、废固定列、报表用视图** | §0/§3.2/§4/§8.4 |
| F2 | 两长表命名/职责重叠 | 保留两张、按"是否喂 EBV"正交;补登记 `breeding_trait_observation` | §2/§3.2/§3.2b |
| F3 | 门禁键含 clone_id 拒收实生苗 | 实生苗阶段单元键退化为 tree_id | §3.16 |
| F4 | 判重键删合法 clonal replicates | 判重键含 tree_id | §3.16 |
| F5 | §5.2 公式漏 rootstock | 公式补 rootstock 固定效应 | §5.2 |
| G1 | 编号服务未定义 + 序号位宽不足 | 定义统一编号服务(下)、clone 序号≥4 位 | §3.0/§8.10 |
| G2 | 手册"不可删只留痕"落点缺 | 鉴定类表禁物理删+UPDATE 强制 audit | §3.10 |
| G3 | method 文本 vs method_uri 受控 | 合并声明两字段并存 | §3.1 |
| H1 | valid_min/max 全局单值 | 接受全局+人工复核,可 scale_json 分档 | §3.1 |
| H2 | environment 与 site/year 共线 | environment=具体气象协变量,非再建 site×year 层 | §5.2/§3.9 |
| H3 | group_member 挂 tree/clone 未定 | 加 clone_id 成员 | §3.5 |
**G1 · 统一编号生成服务(定义)**:集中式编号服务按前缀 + 顺序号生成,全局唯一、可追溯,并发下加行锁/序列保证不重号:
- `accession_no`(种质):`GP-{组来源}-{6位序}``combination_no`(组合):`CC-{年}-{4位序}``tree_no`(单株):`{combination_no}-{4位株序}`(定植时生成);`clone_id`(克隆):`{combination_no}-{≥4位单株序}`(**入选晋升时**由服务生成,非定植时,A1);`trial_code``TR-{年}-{3位序}`
- clone 序号扩至 **≥4 位**(容纳单组合数千株,解决原 3 位=999 上限,G1)。
**D4 · tree ↔ clone 状态流转矩阵**
| 阶段 | tree.status | 是否建 clone | breeding_clone.status | selection_result | 说明 |
|---|---|---|---|---|---|
| 定植(杂种实生苗) | 入选(默认) | 否(clone_id 空) | — | — | 童期观测按 tree_id 聚合 |
| 初选晋升 | 初选 | **是(建 clone、回填 clone_id** | 入选/初选 | 写一行(clone_id+tree_id | 门禁键切 clone_id、启用 A 矩阵 |
| 复选/重点 | 重点 | 沿用 | 重点 | 追加流转 | clone 级 EBV 多年重复 |
| 保存 | 保存 | 沿用 | 保存 | 追加 | 资源保留 |
| 淘汰 | 淘汰 | 沿用(状态变更非删除) | 淘汰 | 追加淘汰记录 | **禁物理删/软删,G2** |
| 参试无性系(entry 批) | 入选 | 定植即有 clone | 入选 | — | 定植即 clone 级 |
**F2 · 命名对照(消除"代码有、文档无"**:模块/URL/权限 = `trait_observation`;模型类 = `TraitObservationModel`**物理表 = `breeding_trait_observation`**(与全项目 `breeding_*` 前缀一致)。文档指物理表用后者,指模块用前者。
---
### 8.11 统计引擎两轮 P0 代码落地台账(v2.32026-08-03/04,代码级)
> 本规格自 v2.0 起为**方案态**(待"做"落地)。2026-08-03/04 将其中两条统计地基从方案推进到**代码落地 + e2e 验证**。本节为落地台账摘要,完整明细(含文件清单/备份/复跑命令)见 `桃育种系统统计引擎实施记录.md`。
**① G×E 交互引擎(2026-08-03**——对应 §5.2「G×E」互作项落地:
| 规格点 | 落地 |
|---|---|
| G×E 随机互作 | `run_ablup(gxe=True, gxe_env=site/year)``method=GXEBLUP``gxe=False` 回归纯 ABLUP |
| 环境维度 | `site`→自动固定效应 `trial_study``year`→自动固定效应 `year`(调用方可显式追加 `fixed_effects` |
| 交互量 | σ²gxe / gxe_ratio / n_cross_env 落 `breeding_prediction.note` JSON |
| 可辨识性门禁 | 无跨环境重复 / 单元内无重复 → 409「G×E 不可辨识:…」 |
| 克隆坍缩 | 同 clone 多株坍缩为基因型节点 `c{clone}`record_map 全映射),同 clone EBV 一致 |
| 异步任务 | `StatisticsJobModel` job_type=GXE/ABLUPSUCCESS/FAILED + error_msg(门禁失败亦落) |
| 验证 | `e2e_gxe_20260803.py` 5 场景全过(spy 捕获 fixed/record_map kwargs |
**② 性状方向标注(2026-08-04**——对应 §3.1 / §5.9 / §5.z 落地:
| 规格点 | 落地 |
|---|---|
| 三字段 | `breeding_trait.direction/into_ebv/default_h2`(幂等 ALTER `weld_trait_direction.sql` + 种子 43 行 ON CONFLICT 含新列) |
| 指数翻转 | zsum 对 asc 性状 z 取负、smith_hazel 对 asc 元素 a 取负 → 统一"越大越优",低优性状不选反 |
| into_ebv | `'0'` 从指数候选/EBV 排行/决策预览/ABLUP 下拉剔除(`extra.dropped` 提示);describe/correlation/trait_values 不受影响 |
| default_h2 兜底 | 指数无实测 h² 用先验兜底(zsum/smith_hazel 均兜底,两者皆无才 409 |
| 排行方向 | `run_ablup` 写时按方向排序;`ebv_ranking` **读时重排**(结构性 bug 修复);`clone_ranking` 方向感知 |
| 轮次对比 | `compare_predictions` 方向感知(结构性 bug 修复) |
| 前端 | statistics `selTraits` 解耦(与 describe/correlation 共享列表分离)+ trait 表单三字段 + selection_rule 说明 |
| 验证 | `e2e_direction_20260804.py` 7 组全过(4 性状 × 4 批次 × 12 株 EBV 基线) |
---
### 8.12 花粉档案落地台账(v2.42026-08-04,代码级)
> 用户田间刚需:桃花期仅 3–7 天,父本花粉是杂交季命脉,原授粉表无花粉采集/贮藏/活力/窗口,复盘坐果率无抓手。本轮新增 `breeding_pollen`(§3.19+ 授粉表 `pollen_lot_id`/`pollination_method`e2e 验证通过。完整明细见 `桃育种系统统计引擎实施记录.md`。
| 规格点 | 落地 |
|---|---|
| 新表 `breeding_pollen` | `weld_pollen.sql` 幂等 DDLCREATE TABLE IF NOT EXISTS + 索引 + COMMENT+ 模型注册(create_all 经 import 链拾取) |
| 父本锚点 | 树级 `male_tree_id` FK→bre_tree SET NULL(可空;`source_type`=tree/mixed/external 区分来源) |
| 活力建模 | 单值+方法:`viability_method`(ttc/germination)+`viability_pct`+`viability_test_date`,不建子表 |
| 授粉窗口 | 派生有效期:窗口=[collect_date,expiry_date]pollination create/update 校验授粉日期在窗口内否则 409;`/bre/pollen/available_lots` 返回当前窗口内批次 |
| 授粉表补字段 | `pollen_lot_id` FK→bre_pollen SET NULL + `pollination_method`(一期文档规划但遗漏,授粉方式) |
| 去重/FK | 批次号唯一预检(409「已存在」);父本树不存在→409(`assert_parents_exist` 自动跳过空值) |
| 菜单/权限 | 900056 花粉档案(杂交配组 900030 下)+ 按钮 E 段 900601-900608;角色关联含新段 |
| 前端 | `pollen` CRUD 页(贮藏/活力下拉、采集/测定/有效期日期)+ 授粉表单集成批次选择(窗口提示)+ stage_cross 第三标签 |
| 验证 | `e2e_pollen_20260804.py`create/去重/FK/list/detail/options/available_lots/窗口内授粉/窗口外 409/update/delete 全过;`vue-tsc` 通过 |
---
### 8.13 选择指数·无性系级聚合落地台账(v2.5,2026-08-04,代码级)
> **决策正确性 P0.3**:桃无性繁殖,选择指数按"树级"算指数会把**同一优系多株拆成独立条目**——可能只选中其中 1 株而漏掉该系其他株,也不利"系级决选"。本轮把指数单位升为**无性系级**(§5.3/§5.7 落地),e2e 验证通过。完整明细见 `桃育种系统统计引擎实施记录.md` v1.2。
| 规格点 | 落地 |
|---|---|
| `aggregate` 参数 | `selection_index` 新增 `aggregate`(默认 `clone``tree`=旧单株级行为保留) |
| clone 聚合单元 | `_clone_units`:按 `tree.clone_id` 分桶成遗传实体;EBV 均值**可靠性加权** `Σ(ebv×rel)/Σ(rel)`,全 rel=0 回退简单均值;表型均值走简单均值 |
| 自株退化 | 无 clone_id 的未晋升实生株 → 单元 key=`-tree_id`(每株独立,不进聚合),实生苗阶段不塌缩 |
| 排名单位 | zsum / Smith-Hazel 均在 clone 单元上算(方向感知沿用 v2.3:统一越大越优) |
| `apply_selection` 粒度 | 按遗传实体写决选:入选 clone 一条 `selection_result``clone_id` 指向全系 + `tree_id` 溯源一株 + reason「系内N株」);self 株逐株写 |
| 晋升建 clone | 入选 self 株命中规则 stage → `_promote_tree_to_clone` 幂等晋升建 clone`tree.clone_id` 回填) |
| 前端 | statistics 工具栏「聚合:无性系级/单株级」radio + 结果表 clone 列(clone_code/n_trees/涉及单株);API 类型补 `aggregate` |
| 验证 | `e2e_clone_index_20260804.py` 6 组全过(聚合单元/可靠加权排名翻转/tree 兼容/方向翻转/smith_hazel clone/apply 写入粒度+晋升) |
### 8.14 配合力交配设计落地台账(v2.6,2026-08-04,代码级)
> **统计严谨 P0.4**`combining.solve` 原只实现 Griffing 对称全双列(model A),但 `run_combining` / `bre_combining_ability` 无 `design_type`——用 line×testerNCII)设计时 GCA/SCA 算法与 ANOVA 自由度都与全双列不同,此前一律按全双列算**会算错**。本轮加 `design_type` 并按设计分支。完整明细见 `桃育种系统统计引擎实施记录.md` v1.3。
| 规格点 | 落地 |
|---|---|
| `design_type` 取值 | `bre_cross_combination` + `bre_combining_ability``design_type``full_diallel`(默认)/`partial_diallel`/`line_tester`/`nciii`;硬编码校验(同 `selection_index.method`,非 sys_dict),create/update 接受 code 或中文标签并归一化,非法值 409 |
| 求解器分支 | `combining.solve(rows, design_type)``full_diallel`/`partial_diallel` → Griffing 对称全双列 `y=μ+g_i+g_j+s_ij`(Σg=0,最小二乘 BLUE);`line_tester`/`nciii`**NCII 双因素模型** `y=μ+l_i+t_j+(lt)_ij`parent1=line 母本、parent2=tester 父本,分别 Σl=0/Σt=0SCA=line×tester 互作=残差);NCIII 同模型但门槛 tester 恰 2 个 |
| 可辨识性 | tester 列从索引 `1+n_l` 起 → **显式列选择**(非连续切片);基线列切出后吸收剩余列 |
| 顺序 ANOVA | SS_lineintercept→line)→ SS_tester(→tester)→ SS_sca(残差);df_line=n_l-1、df_tester=n_t-1、df_sca=n-1-两 df;输出 `design`/`roles`/`df_line`/`df_tester`/`df_sca` |
| 门禁 | 同亲本既作 line 又作 tester(角色重叠)→ 任务 FAILED + CustomException「角色重叠」;NCIII tester≠2 → 拒绝 |
| `gca_se` 持久化 | GCA 标准误内嵌 `anova_json["gca_se"]`(避免 DB 迁移,gca_json/sca_json 形状稳定);前端 GCA 表加 SE 列 |
| 运行过滤 | `run_combining` 按设计过滤:只纳入 `design_type` 一致(或未标注按 `full_diallel`)的组合,杜绝全双列组合混入 line×tester 运行 |
| 前端 | statistics 运行对话框加交配设计 radio;配合力批次表加「设计」列;详情 ANOVA 按设计分支显示(NCII/NCIII → line/tester/互作 F 与 p;双列 → GCA F);cross_combination 表单/表格/详情/搜索全量支持 `design_type` |
| 验证 | `e2e_combining_design_20260804.py` 5 组全过(NCII 2×2 精确解 gca{l:-2,+2,t:-1,+1} + df 1/1/1 + gca_se 内嵌 + full_diallel 组合被过滤;NCIII 分支;角色重叠 gatecreate/update 校验含中文标签归一化;commit 后跨会话持久化)+ `vue-tsc` |
### 8.15 统计严谨·预测完整性与 MLOps 复现性落地台账(v2.72026-08-04,代码级)
> **七条复审逐条核实为真缺陷后全部落地**(用户逐条确认"逐条来",优先级:便宜且值得马上补 ②④ → 中期 ③⑤ → 需新能力 ①⑥)。完整明细见 `桃育种系统统计引擎实施记录.md` v1.4。
>
> **遗留(已记账,不动引擎)**:真 **MT-BLUP** 多性状 G 需全新多变量 REML 求解器(Kronecker 积 G/R + 方差分量迭代,数值收敛风险大),本轮用 **Calo 可靠性校正**(业界回退的严格改进版)先顶上——`r_g = r_EBV/√(rel_i·rel_j)`,直接消费 ② 落库的 reliability,无新求解器;`extra.g_corr`/`g_note` 落 `bre_selection_index.result_json` 可审计。
| 规格点 | 落地 |
|---|---|
| ② PA 落库 | `bre_prediction_value``pa double precision`=√reliability,预测准确度);批次 `bre_prediction.accuracy` 改填**真 PA = √(均值可靠性)**(原误填"均值的平方根量纲不符",注释正名),`numeric(5,3)` 3 位小数 |
| ③ MLOps 溯源 | `bre_prediction``data_version varchar(32)``_DATA_VERSION="v2.7"`/ `input_hash varchar(64)`SHA256`{tree_id}:{均值表型}` + `{个体}\|dam\|sire` 确定性序列化)/ `engine_version varchar(32)``blup.ENGINE_VERSION="1.0.0"`);**同数据重跑哈希一致、改 1 条观测哈希必变**(数据漂移可检测),e2e 断言 |
| ④ germplasm_id 填充 | `run_ablup` 写 EBV 行填 `tree.germplasm_id`(晋升回填的种质,非手填);亲本级 EBV 查询可用(e2e:按 gA 查得 2 条);无种质株保持 NULL(合规) |
| ⑤ 砧木字典扩列 | `bre_rootstock``dwarf_class varchar(32)`(矮化/半矮化/乔化/柱状/其他)+ `compatibility varchar(16)`(砧穗亲和性强/中/弱)——选配决策信息;`weld_rootstock.sql` 幂等 ALTER;模型/schema/service(导出/导入/模板下拉)全链路 + 前端 表单/表格/详情/搜索 |
| ① Smith-Hazel 遗传相关 | `_smith_hazel_index` G 矩阵非对角改 **Calo 校正**`r_g = r_EBV/√(rel_i·rel_j)`(rel 取配对树该性状均值),钳制 [−1,1],可靠性缺失/近零 → 0(保守);`extra["g_corr"]`(性状对)+ `extra["g_note"]` 落结果 JSON |
| ⑥ 空间竞争协变量 | `run_ablup` 新增 `covariate="competition"`:同 **(plot_id, block_no)** 网格内 Chebyshev 距离 1(8 邻域,不含自身)株数作协变量——相邻越多竞争越强、边缘株相邻少隐式捕捉边缘效应;G×E 分支同步支持;**全无 row/col → 显式 CustomException**(数据需求判定);`bre_tree.row_no/col_no` 数据能力已全链路就位(模型/前端录入/表格/详情/导入导出) |
| 前端 | 指数批次表加 `germplasm_id`/`pa` 列;ABLUP 运行对话框协变量改**单选**(无 / crop_load / competition);rootstock 页面全量扩列 |
| 验证 | `e2e_prediction_rigor_20260804.py`(②③④:PA=√rel 逐条 + 批次真 PA + 溯源三字段 + 哈希复现/漂移 + germplasm 级查询 + ebv_ranking 透出 + 跨会话持久化)`e2e_rootstock_20260804.py`(⑤ CRUD/搜索/导出/模板/DB 直查)`e2e_corr_spatial_20260804.py`(① Calo 值独立重算一致 + ⑥ EBV 差分消费验证 + 无坐标报错)+ `vue-tsc` 全过 |
### 8.16 组合得失漏斗 v_combination_funnel 落地台账(v2.82026-08-04,代码级)
> **用户主张**(逐条复审第 8 条,最贴业务):数据其实捕获齐全了——`bre_pollination.flower_count/effective_count`(花→果)、`bre_seed_lot.seed_count/germination_rate`(种→苗)、`bre_seedling.seedling_count`(出苗)——但**没有任何按 `bre_cross_combination` 汇总的派生指标**:结实率、出苗率、选择强度没有滚到组合层,配合力第一手证据(组合得失链路)字段在但没合成进配合力上下文。**核实属实**:全库 grep 结实率/出苗率/选择强度/funnel 无实现;唯一"选择强度链"是 `seed_lot.used_count` 机械累加(seedling/planting 按出苗/定植回写,账本非派生指标);`run_combining` 的 rows 只取 `func.avg(value_numeric)` 组合均值(`service.py:708-748`)、`combining.solve` 只认 `combo/parent1/parent2/value`。**用户拍板范围:补一个 combination_funnel 视图/派生表即可,数据已齐、风险极低。**
| 规格点 | 落地 |
|---|---|
| 六级链路 | 花 `bre_pollination`(Σflower_count/Σeffective_count)→ 果 → 种 `bre_seed_lot`(Σseed_count/AVG germination_rate)→ 苗 `bre_seedling`(Σseedling_count/strong_seedling_count)→ 定植 `bre_planting`(Σtree_count)→ 树 `bre_tree`(非软删 COUNT)→ 入选 `bre_selection_result`(非软删 COUNT |
| 派生指标 | **结实率** `fruit_set_rate` = Σeff/Σflower×100**出苗率** `emergence_rate` = Σseedling/Σseed×100**选择强度** `selection_rate` = 入选数/树数×100(逐级各留原始计数可复查);缺环节组合比率列留 NULL(LEFT JOIN 正确性) |
| 视图 | `v_combination_funnel``weld_combination_funnel.sql` 幂等 DROP IF EXISTS + CREATE OR REPLACE,普通 VIEW 保 freshF2 决策:统计管线用普通 VIEW,不用 MV),`bre_cross_combination` 主表 LEFT JOIN 六源、按组合一行;create_all 只建 ORM 表,视图经 psql 应用 |
| 端点 | `GET /statistics/combination-funnel``module_bre:statistics:query` 权限)→ `StatisticsService.combination_funnel()` 查视图返回 `{rows, n}`Numeric→int/float 归一);视图未就绪时 CustomException 提示先应用 SQL |
| 消费 | 配合力上下文第一手证据落地:查某一组合可得 花→果→种→苗→定植→树→入选 全程漏斗,解释 GCA/SCA 差异时按组合得失对照(如低 GCA 组合是否因出苗率低样本崩缩) |
| 验证 | `e2e_combination_funnel_20260804.py`:全六级组合 150 花/50 果→结实率 33.33%、100 种/80 苗→出苗率 80%、55 定植/3 树/2 入选→选择强度 66.67%,精确断言;仅授粉组合 fruit_set=50%、其余全 NULLcommit 后跨会话读同值。**注**:首跑清理阶段 FK 崩(helper flush 前取 `.id` 拿到 None),修 flush 顺序后全过 |
### 8.17 精修项四连发落地台账:DUS 数据能力 + stage 感知 + k-fold CV + 公平性报告(v2.92026-08-04,代码级)
> 用户核实四条精修缺口、全部拍板「落地」(并保留版本):① **DUS/品种保护**——无模块、无 UPOV TG/53 描述符模板(§2 总表 ⏳待建),按拍板档位**数据能力(三表)**;② **stage 感知**——`trait.stage`v2.0 ①定义)未被 BLUP/选择指数/决策消费,童期/成株混用无警示;③ **模型外部验证**——可靠性仅 PEV 法,补 k-fold CV**ABLUP + GXEBLUP 双支持**);④ **AI 伦理·分组偏差**——G×E 引擎已覆盖互作,补按 site 的系统性 EBV 偏差/公平性报告。完整明细见 `桃育种系统统计引擎实施记录.md` §九。
| 规格点 | 落地 |
|---|---|
| ① DUS 三表 | `bre_dus_descriptor`(描述符模板:descriptor_no 唯一 UPOV TG/53 特性号、trait_id→bre_trait **可空**=自由描述符、trait_code 快照、expression_type QN/PQ/QL、method、example_varieties 标准品种、test_stage、required/ `bre_dus_test`(测试记录:test_name 唯一、germplasm_id→申请品种、trial_study_id→测试点、tester/test_date/status(planning/testing/completed/report)/conclusion(pending/distinct/not_distinct)/report_path/ `bre_dus_observation`(观测:dus_test_id/dus_descriptor_id 双 FK、value_numeric/value_text/expression_note、UNIQUE(test,descriptor));create_all 建新表(非既有 DDL);五件套模块 `module_bre/dus/` 注册 `/bre/dus_test/*`descriptor 9 端点含 Excel 导入导出+模板下载,test 9observation 6 |
| ① TG/53 种子 | `sql/bre_dus_seed.sql`UPOV TG/53 桃描述符 15 条(树性/树势/叶形/花型/花期/果形/果皮底色/着色程度/茸毛/果肉色/离核性/成熟期/风味/平均单果重/可溶性固形物),`trait_code → bre_trait LEFT JOIN` 解析 trait_id**8 条关联**),`ON CONFLICT(descriptor_no) DO NOTHING` 幂等;descriptor 导入导出/模板中文头(关联性状编码 → trait_id) |
| ① 菜单 | `sql/bre_menu_refine.sql`900230 component 切真实页 `module_bre/dus/index`**G 段按钮 900800-900808**perm `module_bre:dus_test:*`,含导入/下载模板)+ SUPER_ADMIN/ADMIN 角色关联 |
| ② stage 感知 | `_trait_meta_map` 读入 `trait.stage`(缺省 evaluation);`PredictionModel.stage` 落库(`sql/weld_refine.sql` 补列)+ 预测批次表展示;`selection_index``stage` 入参——传 juvenile/evaluation 只纳入该阶段性状(异阶段写入 `skipped_stage`,同阶段无性状→409 带剔除清单)、不传且横跨两阶段返回 `stage_warning`(童期/成株清单 + 复核提示);`decision_preview` 同样——传 stage 时异阶段规则条件跳过(matched=None)、不传且规则引用性状横跨两阶段返回 `stage_warning` |
| ③ k-fold CV | 求解器 `blup.kfold_cv`:按 **sire 家系分层留出**(同家系不进训练/测试双折避免乐观,无父本个体自成一系),每折训练子集重估方差组分 → 留出个体 EBV 由系谱预测(个体保留在 A 矩阵、仅掩蔽表型)→ pearson+RMSE;单折失败(train<2 / G×E 结构不可辨识)记 None+warning 不中断;返回 mean/pooled pearson/RMSE、cv_accuracy(=mean_pearson)、h2。端点 `POST /bre/statistics/cv/run`trait_id/code/year/fixed/covariate/**gxe/gxe_env**/k 2~10ABLUP 与 GXEBLUP 同入口)→ 落 `bre_cv_result`method=KFCV/ABLUP|KFCV/GXE,溯源 data_version/input_hash/engine_version 复用)+ `bre_cv_fold` 明细;`GET /bre/statistics/cv`(批次)+ `GET /bre/statistics/cv/{id}`(含折明细) |
| ④ 公平性报告 | `GET /bre/statistics/fairness?prediction_id=&group_by=site&threshold_sd=`(只读不建表):`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 排名翻转 |
| 前端 | `dus.ts` 3 组 API + `dus/index.vue` 三 tab(描述符模板/DUS 测试/观测录入)CRUD 页;`statistics.ts` 加 runCv/listCv/cvDetail/fairnessReport + 类型;`statistics/index.vue` 加「交叉验证」tab(性状+k+gxe 开关+批次+折明细)与「公平性报告」tabprediction+threshold_sd+site 偏差表+一致性表)、指数/决策对话框加 stage 三态下拉 + `stage_warning` ElAlert`vue-tsc` 通过 |
| 验证 | `e2e_refine_20260804.py` 4 组全过:DUS 三表 CRUD + TG/53 种子命中 + FK/唯一键/子表阻断/软删 409 全路径;stageselection_index 无过滤警示 + 过滤只含该阶段 + decision_preview 异阶段跳过 + ABLUP stage 落库);CVABLUP k=3 sire 家系留出折 pearson=0 为设计预期 + GXE k=2 跨 site + 幂等重跑新批次 + 溯源/任务状态);fairness2 site 9 株 site_summary 2 行 deviation 异号 + rank_consistency spearman + gxe_pattern);后端 openapi 确认 DUS/CV/fairness 路由注册,清理自动执行 |
---
### 8.18 六项能力完善落地台账:MT-BLUP + GBLUP/ssGBLUP + DUS 特异性检验 + AMMI/FW 稳定性 + MLOps 重训回滚 + BLUP stage 拆分(v2.102026-08-04,代码级)
> 用户两轮复核核实六条能力缺口、逐项拍板「全部落地」:① **MT-BLUP**——Smith-Hazel 的 G 非对角仍用 Calo 校正 EBV 相关近似,拍板**成对双性状 BLUP**(非全多变量 REML);② **GBLUP/ssGBLUP**——分子层只有数据能力(四模块 CRUD + VCF + 指纹),无 VanRaden G / 基因组选择引擎,item 明确两者都做;③ **DUS 特异性统计检验**——`conclusion` 纯人工、无判定端点,拍板**参照=同 trial_study 自动 + 可显式指定**;④ **AMMI/Finlay-Wilkinson 稳定性**——G×E 已估 σ²gxe,无跨环境稳定性排名;⑤ **MLOps 自动重训 + 版本回滚**——拍板**漂移检测端点 + 手动触发**,不注册 cron;⑥ **BLUP stage 拆分**——run_ablup 只打标签不按 stage 取数。完整明细见 `桃育种系统统计引擎实施记录.md` §十一。
| 规格点 | 落地 |
|---|---|
| ① MT-BLUP | 求解器 `mtblup.solve_bivariate`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**降维策略**Va/Ve 取自各性状单性状 REML,仅对 ρ∈[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。Service `run_genetic_corr(trait_ids,year)`:两两 bivariate,对角=单性状 h²·P_ii、非对角=r_g·√(G_ii·G_jj) 组装 G0Higham 特征值截断投影半正定;落 `bre_genetic_corr_result`matrix/sigma_a/heritability/pairs_json/n_common + 溯源三字段)+ job_type=GENCORR`_smith_hazel_index``g_method="calo"\|"mtblup"`selection_index 透传)——mtblup 逐对跑 bivariate,单对不收敛回退 Calo+warning,≥3 性状三角不等式违反时特征值截断,`extra["g_source"]` 落库可审计 |
| ② GBLUP/ssGBLUP | 求解器 `genomic.py`ENGINE_VERSION=1.0.0):`build_g_matrix`dosage 0/1/2 样本×标记,缺格按列均值 2p 填充,MAF 过滤,VanRaden **method1** G=ZZ'/2Σp(1-p)diag≈1/ **method2** G=ZDZ'D=1/[2p(1-p)]),blend 岭 G_w=(1−ω)G+ω·mean(diag)G·I 保证可逆);`solve_gblup`(仅基因型个体入模型,MME 用 G⁻¹ 替代 A⁻¹,σ²a 用 `_golden_max` profile 仿 blup.solve);`solve_ssgblup`**单步法** H⁻¹=A⁻¹+[[0,0],[0,G⁻¹−A22⁻¹]]Aguilar et al. 2010),A22=A[genotyped,genotyped] 稠密子阵 np.linalg.inv(病态加 ridge),**V 块必须用 H 协方差**——Aguilar 块公式构造完整 HH=A+[[A12·A22⁻¹·D·A22⁻¹·A21, A12·A22⁻¹·D],[D·A22⁻¹·A21, D]]D=GA22),MME 系数矩阵用 H⁻¹、REML 似然 V=ZH[z,z]Z'+R;修复前 V 块误用 H⁻¹ 致似然失构),基因型+非基因型个体都出 EBV。Service `run_gblup(dataset_id,trait_id,trait_code,year,method,maf_min)`:取数 sample×marker pivot 剂量("0/0"→0/"0/1"→1/"1/1"→2,多等位跳过),样本→个体映射 source_type='tree' 直连 + sample_name↔tree_no/品种名名称兜底,未映射→跳过+warning 清单(note 落库);`genotyped=sorted(dosage)` 对齐 build_g_matrix 内部行序(修复前映射树零有效调用会错位 EBV);落 PredictionModelmethod=GBLUP/ssGBLUP,含溯源三字段)+ EBV 行 + job_type=GBLUP |
| ③ DUS 特异性 | 求解器 `dus.distinctness`(复用 fdist):QN `LSD = t_crit(α,df)·√(MSE·(1/n_cand+1/n_ref))`(df=总观测−参照组数;t_crit 由新增 `fdist.f_icdf` 二分反解 F(1,df) 再开方);PQ/QL 表达状态众数比较(候选众数 ∉ 参照众数集 → distinct);逐描述符 {statistic,critical,distinct},总体建议=≥1 个 **required** 描述符 distinct → distinct,否则 not_distinct,数据不足→pending(不判)。端点 `POST /bre/dus_test/distinctness/{test_id}`body {reference_test_ids?**默认同 trial_study 其他非软删 test 自动参照**,可显式覆盖;alpha=0.01})——取候选+参照观测+描述符,跑判定**落 `analysis_json`**(逐描述符表+建议+参照集+alpha),`conclusion` 为 pending 时自动填建议(人工可改);`GET /bre/dus_test/distinctness/{test_id}` 读已存分析;DusTestOutSchema 加 analysis_json |
| ④ 稳定性 | 求解器 `stability.py`ENGINE_VERSION=1.0.0):`finlay_wilkinson` 每基因型对**环境指数**(该环境全基因型均值)回归 b/截距/R²/se_b/dev_ms`flag_stable=\|b1\|≤2·se_b`(**完美拟合残差≈0 时 se_b 无信息量 → b≈1(≤1e-6)判稳**,修复前浮点 b 永不精确=1 误判不稳);`ammi` 两因素 μ+g+e 分解→残差 SVDnp.linalg.svd)→IPC 得分/ASVPurchase 2000IPC1 按 SS 比例缩放合成)/Wricke ecovalence/ipc_variancerank 按 ASV 升序。Service `run_stability(trait_id,trait_code,gxe_env=site/year,year,methods)`:两向表 genotype=clone(缺则 combination,再退 tree)× env=site(trial_study_id)/year(evaluate_year),每格多株均值;格子 <2×2 → 409;落 `bre_stability_result`detail_json+溯源三字段)+ job_type=STABILITY |
| ⑤ MLOps | weld `bre_prediction.is_active boolean default false`run_ablup/GXE/GBLUP 落库:同 trait 无 active → 本批 active,否则 false**版本链语义**)。`GET /statistics/model/drift?prediction_id=`——从批次 job params_json 取 (trait_id,year,gxe,gxe_env) → 轻量 `_gather_digest_inputs`(仅组装进 `_input_digest` 的 phenos+pedigree,规避全量抽取)重算当前哈希 → {changed,current_hash,stored_hash,data_version}`POST /statistics/model/retrain?prediction_id=`——**漂移才重训**run_ablup(同 params) 建新批次并 `model_activate(new_id)` 转移 active(修复前新批次默认 inactive 卡在旧批次下)→ {retrained,old_id,new_id,new_hash},无漂移 → {retrained:false,reason}`POST /statistics/model/activate/{id}`——trait 内标 active(回滚原语);list_predictions/PredictionOut 加 is_active |
| ⑥ stage 拆分 | weld `bre_trait_observation.stage varchar(16)`(观测级发育阶段,缺省继承 trait.stage);TraitObservationModel+schemacreate/update/out+ 前端观测表单 stage 下拉(juvenile/evaluation);`run_ablup(stage)` + RunStatsIn.stage:给定 → 取数 `where(coalesce(obs.stage,trait.stage)==stage)`model_name 加 `_{stage}` 后缀 + PredictionModel.stage=生效 stage;未给定但数据 obs.stage 与 trait.stage 出现分歧 → note 警示(不阻断);GXE 分支同步应用 |
| 端点汇总 | `POST/GET /bre/statistics/genetic-corr(/run/{cid})``POST /bre/statistics/gblup/run` + `GET /bre/statistics/gblup/datasets`(批次/EBV 复用 list_predictions 按 method 过滤 + ebv_ranking)、`POST/GET /bre/statistics/stability(/run/{sid})``GET /bre/statistics/model/drift` + `POST /bre/statistics/model/retrain` + `POST /bre/statistics/model/activate/{prediction_id}``POST/GET /bre/dus_test/distinctness/{test_id}`、selection_index 请求体加 `g_method` |
| 前端 | `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` 通过 |
| 验证 | `e2e_advanced_{stability,stage,mtblup,gblup,dus,mlops}.py` 6 组全过:stabilityFW b=2.0/1.0/0.0 flag=F/T/F、AMMI 9 格 IPC1≥IPC2 rank 升序、year 维度、非法 methods 409、list/detail);stagejuvenile/evaluation 各只含对应观测树、不传含全部+note 警示、非法 stage 409);mtblupr_g>0.3 对称、σa 对角>0、h²∈(0,1)、n_common=4、Smith-Hazel g_method=mtblup g_source 落库);gblupGBLUP 5 EBV 非基因型株=0 + ssGBLUP 非零 + solve_ssgblup V 块用 H、G method1 diag_mean≈1、样本 4 直连+1 名称兜底+1 多等位+1 未映射 warning、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→幂等 false→activate 回滚);后端重启后 openapi 确认 6 组新端点 + 2 新表(bre_genetic_corr_result/bre_stability_resultcreate_allweld_advanced.sql 幂等;清理自动执行 |
---
### 8.19 田间试验精度补强·砧木×接穗随机互作落地台账(v2.11,2026-08-04,代码级)
> 用户核实两条田间试验设计精度缺口——无 R 侧空间协方差(行-列 AR1×AR1)、无 scion×rootstockG×R)随机互作(rootstock 当前仅固定哑变量);拍板**先做 G×R 随机互作**(空间协方差留待补 row/column 字段后再议)。核心洞察:G×E 分支 `_solve_gxe` 的 Z₂ 已按 `(基因型,因子水平)` 分组配 `I·σ²` 交互、**因子无关**,G×R 直接复用;但 Z₂ **单槽位 → G×E/G×R 必须互斥**。完整明细见 `桃育种系统统计引擎实施记录.md` §十二。
| 规格点 | 落地 |
|---|---|
| 求解器 | `blup._solve_gxe``factor_label="G×E"/factor_name="环境"` 可选参数(仅喂警告文案:未收敛「{factor_label} 似然面可能极平/边界最优」、方差归零「{factor_label} 方差分量收敛到 0(数据不支持基因型×{factor_name}互作)」),默认值保 G×E 文案逐字节不变;公开 `solve()` 透传两参;MME/REML/输出键全不变;ENGINE_VERSION 1.1.0→**1.2.0** |
| 服务端 G×R | `RunStatsIn`+`run_ablup``gxr: bool`;互斥门禁 `gxe and gxr` → 409(共用 Z₂ 槽,文案「G×E 与 G×R 互作共用同一随机效应槽(Z₂)」);job_type=`GXR`、params 落 gxr;克隆坍缩系谱 `gxe_pedigree` 上移为 G×E/G×R 共享(纯构建、ABLUP 不执行);`elif gxr:` 镜像 G×E site 分支——按 `phenotypes.items()``rootstock_map[f"t{tid}"]`**字符串键**)构建 `rec_gxr[rid]=(grp,rs)``rec_map`/`rec_fixed`/`rec_cov``rootstock` 强制从 `fixed_effects` 剥离防共线;门禁三件套镜像(`n_cross_rootstock`=同基因型跨砧木数==0 / max cell_counts<2 / residual_df<1 →「G×R 不可辨识」409p_est 不再计入 rootstock);求解传 `gxe=rec_gxr, 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/n_cross_rootstock/n_genotypes/warning/skipped/stage_note`;EBV 写入共用段个体集按 gxr 选 `gxr_tree_ids``_DATA_VERSION` v2.9→**v2.10** |
| 前端 | `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``vue-tsc` 通过 |
| 验证 | `e2e_gxr_20260804.py` 4 组全过:① 2 基因型×2 砧木×2 株强交叉互作(clone1×R1 高/R2 低、clone2 相反)→ method=GXRBLUP、job_type=GXR、σ²gxr=74.8>0、n_cross_rootstock=2、n_genotypes=2、8 EBV 行;② 同基因型仅跨单砧木 →「G×R 不可辨识」409;③ `gxe=True,gxr=True` →「Z₂」互斥 409;④ `fixed_effects=["rootstock"]` 同开 → rootstock 被剥离、不共线、正常出 σ²gxr;后端重启后 openapi 确认 `gxr` 入参;清理自动执行 |
### 8.20 基因组选择(GS)实证严谨性·GBLUP/ssGBLUP 专用 k-fold 交叉验证落地台账(v2.122026-08-04,代码级)
> 用户核实 GS 两条实证缺口:① **GS 缺自身交叉验证**——`run_cv`/`kfold_cv`blup.py)是 A 矩阵系谱预测(ABLUP/GXE),GBLUP 落库的 `accuracy=√mean(reliability)` 是**理论准确度**(PEV 推导),模型误设(G 算错/标记编码错/遗传力先验偏)时 PEV 可靠性依然漂亮、真实预测能力却崩了,只有掩蔽留出「GEBV vs 表型 r」能测出来;② **SSR panel 难构 VanRaden G**——`_dosage_from_gt` 只吃 0/1/2SSR 片段编码(`168/174`)/多等位被丢弃。用户拍板**先做 GS k-fold(①)**SSR dummy 编码(②)留待后续。核心洞察:`_profile_solve` 已支持「仅观测子集进模型、**全部个体**出 EBV」——非观测个体 Z 行全 0、经 G⁻¹/H⁻¹ 交叉关系预测,所以掩蔽留出 = 传训练子集 phenos → 全个体 GEBV → 取留出个体与观测表型相关。完整明细见 `桃育种系统统计引擎实施记录.md` §十三。
| 规格点 | 落地 |
|---|---|
| 求解器 | `genomic.py`:① 抽取 **`_build_h(pedigree, genotyped, G, ridge, extra_base)`**solve_ssgblup 的 base/non_base→`_order_pedigree`→A/Ainv→Hinv→H 构建,Aguilar 2010)——**缺失基因型个体按 base 补入系谱**(原 raise ValueError 改补入,无表型基因型树不再崩,与 phenos 兜底一致);② 新增 **`kfold_cv_genomic(phenos, G, genotyped, k, seed, method, pedigree)`**——`method=gblup`individuals=genotypedG 行序)、relmat_inv=G⁻¹(奇异回退 pinv)、zmat_full=G`method=ssgblup``_build_h` → individuals=order、relmat_inv=H⁻¹、zmat_full=Hcand=genotyped∩phenos`len(cand)<2` → 空 folds + warning**折划分固定种子随机分层**round-robin,GS 同世代样本无系谱家系树,区别于 ABLUP 的 sire 家系留出,文档明示);逐折掩蔽留出:train_phenos=phenostest_set → `_profile_solve(ZGZ_train, X, y_train, relmat_inv, n, z_train)` → 全 EBV → 留出个体 GEBV vs 表型 `blup._pearson`+RMSE,单折失败 error 记 warning 不中断;输出 dict 与 blup.kfold_cv **逐键对齐**k/n_total/n_individuals/folds/mean/pooled_pearson/pooled_rmse/cv_accuracy/h2/warning);**G/H/Hinv 只建一次、逐折只换 z_train 子阵**ENGINE_VERSION 1.0.0→**1.1.0** |
| 服务端 | ① **`_gather_gblup_inputs(dataset_id, maf_min)` 提取**run_gblup 的 dataset→samples→call_rows→markers→sample→tree 映射→dosage→`build_g_matrix`→genotyped 装配提成 helper,返回 `(dosage, marker_order, genotyped, G, g_meta, unmapped)`,run_gblup 改调、行为逐字节不变);② **`run_cv``dataset_id/method/maf_min` 入参**params_json 同步落库)——公共表型/系谱装配后 `if dataset_id:` GS 分支(与 `elif gxe:`/`else:` 互斥,G×E 与 GS 双开 GS 优先):`kfold_cv_genomic` + method 名 **`KFCV/GBLUP`**/**`KFCV/ssGBLUP`**method varchar(16) 放得下);input_hash=sha256(`_input_digest(pedigree, phenos)`+`\n`+geno_str)(镜像 run_gblup 3360-3366);engine_version 按分支(GS 用 `genomic.ENGINE_VERSION`ABLUP/GXE 用 blup);③ schema `CvRunIn` + controller 透传 `dataset_id/method/maf_min``_DATA_VERSION` v2.10→**v2.11** |
| 前端 | CV tab 加 **mode radioABLUP/GS**:GS 模式显示基因型数据集下拉(复用已加载 `gbDatasets`+ method radioGBLUP/ssGBLUP+ MAF≥ 输入,**隐藏 G×E 控件**、辅助文案分支「掩蔽留出 GEBV vs 表型 pearson(实证预测能力,固定种子随机分层)」;`submitCv` 按 mode 组装 payloadGS 传 dataset_id/method/maf_min);`CvRunPayload` 加三个可选字段;`vue-tsc` 通过 |
| 验证 | `e2e_gblup_cv_20260804.py` 3 组全过:① 5 家系×3 全同胞=15 株、10 标记(MK0/MK1 为 QTL 效应 2.0,表型=12+2·dose(MK0)+2·dose(MK1)+低噪)→ `run_cv(dataset_id, method=gblup, k=5)`method=`KFCV/GBLUP`、cv_accuracy=0.794>0.3、==mean_pearson、n_total/n_individuals=15/15、input_hash 64hex、engine=1.1.0、5 折 n_train/n_test≥1、CvFoldModel 5 行;② `method=ssgblup``KFCV/ssGBLUP`、cv_accuracy=0.794>0.3;③ 门禁:无映射样本数据集 → `CustomException`「基因型样本均无法映射到单株」;回归 `e2e_advanced_gblup.py` 复跑全过(`_gather_gblup_inputs` 提取无行为变化);后端重启 openapi 确认 `CvRunIn.dataset_id/method/maf_min`;清理自动执行 |
### 8.21 现代桃育种领域覆盖·S-等位基因交配兼容性 + 抗病/需冷量性状字典落地台账(v2.13,2026-08-04,代码级)
> 用户核实现代桃育种四方向覆盖缺口,拍板开始做(按建议次序先落地 ②③ 小活、① 中活;④ GWAS/QTL/MAS 最大留待单独立项):
> - **① S-等位基因(自交不亲和)交配兼容性**——桃是配子体型自交不亲和(S-RNase),配组合时 S 基因型决定能否坐果;`bre_pollination` 有花粉批但无 S-allele 追踪与兼容性校验——"配了不结"的硬需求。
> - **② 需冷量/需热量**——低需冷量桃适应暖区是核心育种目标;`bre_germplasm.chilling_requirement`(属性)+ `bre_environment_condition.chilling_hours/GDD`(环境侧)已有,**选种性状侧(bre_trait)缺失**。
> - **③ 抗病性状**——细菌性穿孔病/褐腐病/白粉病减药育种关键;`bre_germplasm.disease_resistance` 仅自由文本,**bre_trait 字典一条都没有**。
> - **④ MAS/QTL/GWAS 闭环**——已有 GS 预测层,但缺发现层(GWAS/QTL 定位→MAS);900214 仍 `_coming_soon`,留待单独立项。
> 完整明细见 `桃育种系统统计引擎实施记录.md` §十四。
| 规格点 | 落地 |
|---|---|
| ②③ 性状字典 | `backend/sql/bre_disease_chilling_traits.sql`(幂等 ON CONFLICT)种子 **5 条**`disease_shot_hole` 细菌性穿孔病 / `disease_brown_rot` 褐腐病 / `disease_powdery_mildew` 白粉病(category「抗病性」,0-5 级病情指数 0=免疫…5=高感,`valid_min=0/valid_max=5`+ `chilling_requirement` 需冷量(h0-3000+ `heat_requirement` 需热量(GDD0-10000)(category「生态适应性」)。全部 `data_type='numeric'` + `into_ebv='1'` + `direction='asc'`(低值优:低需冷/低需热/低病情指数抗病)+ `default_h2`(需冷 0.5/需热 0.4/抗病 0.3+ `stage='evaluation'` + `method` 测定说明——**统计引擎 `_trait_meta_map` 仅消费 numeric,故不用 categorical 分级**;前端 trait 页 category 自由文本自动显示、0 改动 |
| ① S-allele 建模 | `bre_germplasm.s_alleles``String(32)`model+schema Create/Update/Out+ALTER TABLE+COMMENT,如 `S1/S3``Sf`=自交亲和型)——`bre_germplasm.sql` 补列;germplasm 前端表单/导出列加 S-等位基因输入 |
| ① 兼容校验 | `cross_combination/service.py``_parse_s_alleles`(分隔符 `/ , ;` 归一化小写集合)+ `_s_compat_check`**任一亲本含 `sf`→full 放行**;共享 2 个→`none`;共享 1 个→`half`;无 S 数据→`unknown` 跳过)+ `_check_s_compat`(读亲本 s_alleles`none``CustomException` 409「S-等位基因完全不相容(共享 …),该组合无法坐果」,`half`→返回警示文案);`create`/`update` 在亲本断言后调用,`CrossCombinationOutSchema.s_compat`(可选派生字段)落警示;**自交(同亲本共享 2 等位)自然被 409 拦截** |
| 前端 | germplasm 表单加 S-等位基因输入(type inputplaceholder 提示 Sf);cross_combination 组合提交包装 createApi/updateApi——响应含 `s_compat``msg.warning` 展示(409 由统一错误处理自动提示);`germplasm.ts` `GermplasmForm/GermplasmTable``s_alleles?``vue-tsc` EXIT=0 |
| 验证 | `Temp/claude/e2e_s_allele_20260804.py` 6 组全过:纯函数 8 例(S1/S3×S1/S3→none、×S2/S4→full、×S1/S2→half、含 Sf→full、大小写/混合分隔→none、缺数据→unknown+ service 层 create(共享 S1/S3→409「不相容」;共享 S1→`s_compat` 半兼容;0 共享→无警示;Sf 放行;缺 S 跳过);DB 核验 bre_trait 5 条 numeric+asc+into_ebv=1 落库;openapi 核验 `BreedingGermplasm{Create/Update/Out}.s_alleles` + `CrossCombinationOut.s_compat`;清理自动执行 |
### 8.22 GWAS/QTL/MAS 闭环落地台账(v2.142026-08-04,代码级)
> v2.13 标记「④ GWAS/QTL/MAS 闭环留待单独立项」——本轮单独立项落地:补齐**发现层**(GWAS/QTL 定位→显著标记→MAS 面板),900214 占位页翻真实页。桃在成熟期/果重等位点已有已知 QTL,MAS 让童期幼苗在无表型/无 EBV 时也能被标记辅助选择。
| 规格点 | 落地 |
|---|---|
| GWAS 引擎 | `backend/scripts/breeding_stats/gwas.py`(纯 numpy 零 scipy`ENGINE_VERSION=1.0.0`):逐标记单标记回归 `y ~ μ + PC1..PCk + marker`,加性效应=标记系数;**群体结构**=标记剂量矩阵中心化 SVD 前 n_pc 个主成分得分(缺失按列均值填);**p 值复用 `fdist.f_pvalue(t²,1,df)`**df=nn_pc2,正则不完全 beta);**多重检验**=Bonferroni 阈值 + BH-FDR qnumpy argsort);**QTL 定位**=显著(Bonf)标记同染色体相邻间距 < qtl_window 合并簇、簇内最小 p 为峰标记(单显著标记也落 QTL);**共线兜底**:标记与 PC 共线时 XtX 奇异,微小岭回归(reg=1e-8·max(diag))令 SE 大而有限→p≈1(效应被 PC 吸收正确非显著),**不误吸与群轴正交的 QTL 标记**method 参数预留 ssgwasMLM 留待) |
| 数据装配 | `_gather_gwas_inputs`(独立 helper,仿 `_gather_gblup_inputs` 但 marker 查询**补 chromosome/position**)——**不改 run_gblup 零回归**;样本 source_type=tree 直连/sample_name↔tree_no·品种名兜底、未映射跳过;表型 tree 级均值(同 run_gblup |
| 5 张新表 | `bre_gwas_result`(批次:n/m_after_maf/n_pc/threshold_bonf/n_sig_bonf/n_sig_fdr/n_qtl/data_version/input_hash/engine_version)· `bre_gwas_snp`(逐标记:chromosome/position/maf/effect/se/t/p/neg_log10p/q/sig_bonf/sig_fdr)· `bre_qtl`(已知 QTL 人工 CRUD source=known + GWAS 自动定位 source=gwas)· `bre_mas_panel` + `bre_mas_panel_marker`favorable_dose/direction/effectUNIQUE(panel,marker))——`statistics/model.py` ORM + `backend/sql/weld_gwas.sql` 幂等 CREATE IF NOT EXISTS 双保险 |
| 服务端端点 | `POST /statistics/gwas/run`job_type=GWASinput_hash 镜像 run_gblup+ `GET /statistics/gwas/list` + `GET /statistics/gwas/{id}`result+snps+qtls);`bre_qtl` CRUD 五件套;`bre_mas_panel` CRUD + `POST /mas-panel/{id}/markers`(全量替换);权限复用 `module_bre:statistics:*`(已授 ADMIN);`_DATA_VERSION` v2.12 |
| MAS 决策 hook | `decision_preview` 条件循环 `("pheno","ebv")``("pheno","ebv","marker")``conds["marker"]={panel_id:{min_hits:N}}``_mas_hit_map` 按候选树批量查 call→`_dosage_from_gt`→有利剂量(direction=high: dose≥favorable_dose / low: ≤)命中计数——**童期幼苗无表型/无 EBV 也能被 MAS 选入** |
| 前端 | `gwas.ts`runGwas/listGwas/gwasDetail + Qtl/MasPanel API+ `gwas/index.vue` 三 tab:GWAS 结果(批次表 + **Manhattan 图**(裸 `echarts.init`,x=染色体累加位置、逐染色体分组着色、显著点红色、Bonf 阈值 markLine、dataZoom+ **QQ 图**(期望 log10((i+.5)/m) vs 观测)+ SNP 表 + QTL 表)/ QTL 定位(已知 QTL 录入 CRUD/ MAS 面板(面板 CRUD + 标记选择对话框);运行参数 dataset/trait/maf_min/n_pc/sig_level/qtl_windowsys_menu 900214 `component_path='module_bre/gwas/index'` 翻转(G 段按钮已由统计模块 900071 授予,无需新增);`vue-tsc` EXIT=0 |
| 验证 | `Temp/claude/e2e_gwas_20260804.py` 7 段全过:① run_gwas→job GWAS/SUCCESS、bre_gwas_result 字段(n_pc/threshold_bonf=input_hash 64 位/engine_version)② snp 全字段 + MK0/MK1 Bonf 显著且为所在染色体最小 p ③ QTL 定位 2 区间峰标记=MK0/MK1source=gwas 落库)④ 已知 QTL CRUDsource=known)⑤ MAS 面板+set_markers+decision_preview marker 条件(16 株 + 无表型童期幼苗命中、低剂量株不命中)⑥ 门禁:dataset 无映射样本→CustomException ⑦ 数据清理自动执行;**回归**:`e2e_advanced_gblup.py` + `e2e_gblup_cv_20260804.py` 复跑零回归(`_gather_gwas_inputs` 独立);openapi 核验 10 条 gwas/qtl/mas-panel 路径 |
### 8.23 九缺口补齐落地台账(v2.152026-08-04,代码级)
> 用户自 GWAS/QTL/MAS 闭环后重扫 12 项缺口,A1(S-等位)与 A4(G×R)已同日落地剔除,余 **9 项拍板「全部补齐」**,分三批(批1 经典侧计算端点 → 批2 分子侧严谨性 → 批3 求解器核心),每批独立 e2e + 回归全部通过。完整明细见 `桃育种系统统计引擎实施记录.md` §十六。
**批1 经典侧计算端点(纯计算不建表,零回归)**
| 缺口 | 落地 |
|---|---|
| A5 数据质量 | `POST /statistics/data-quality`——`data_quality_report(trait_id, site_id?, tree_ids?)`tree 级观测装配(同 run_ablup 模式)+ 缺失率复用 `_readiness_report` 逻辑 + 变异系数 + **IQRQ11.5IQR / Q3+1.5IQR****MAD 稳健 z-score** 双法异常标记,输出 `{trait, n_trees, missing_rate, cv, outliers:[{tree_id, tree_no, value, z, reason}], summary}`;前端 statistics 页「数据质量」对话框 |
| A3 遗传增益 | `POST /statistics/genetic-gain`——**ΔG = k·r_g·σ_A**:选择强度 k 由入选比例 top_p 查正态,**Acklam 有理近似 Φ⁻¹**(纯 numpy 零 scipy);r_g=批次 PA(√mean reliability,聚合 `bre_prediction_value.pa`);σ_A=√h²·σ_Ph²=`bre_prediction.heritability`、σ_P=trait 观测 SD);入参 top_p/top_n + 世代间隔 L 可选,逐轮(predict_date/round)输出 `{round, current_mean, ΔG_units, ΔG_pct_mean, next_mean, cumulative}` |
| A6 主动选配 | `POST /statistics/mating-recommend`——入参候选 tree_ids + EBV 批次/trait 集 + 亲缘阈值(默认 0.25+ 权重 w_ebv/w_kin + max_pairs:① EBV map(决策块复用)② 亲缘 A(`blup.relationship_matrix`,系谱仿 kinship_matrix)③ **S-等位硬过滤**(复用 `cross_combination.service._s_compat_check`none→剔除、half→flag)④ 打分 `score=w_ebv·mid_parent_EBV w_kin·max(0,rthreshold)` 排序 top N;输出 `{pairs:[{female, male, ebv_mean, r, s_compat, score, flags}]}`;**计算端点不落库**(用户拍板) |
**批2 分子侧严谨性(solver 扩展,独立路径)**
| 缺口 | 落地 |
|---|---|
| B1 EMMAX | `gwas.py` 新增 `_emmax`**零模型** y=Xβ+u+eu~N(0,σ²g·K)K 由 dose 矩阵 GRM(复用 `genomic.build_g_matrix`),方差分量复用 `genomic._profile_solve`Z=I、G=K);**纯 numpy eigh** 对角化 K=QΛQ' → 固定 V=σ²g·K+σ²e·I、V⁻¹=Q(σ²Λ+σ²e·I)⁻¹Q';逐标记 GLS y~[1,PC,marker]t²→`fdist.f_pvalue`**run_gwas 后处理(显著判定/Bonferroni/BH-q/QTL 聚类)抽共享函数**,GLM 路径输出逐字节不变(e2e_gwas 回归兜底),EMMAX 兄弟路径;`method="emmax"` 服务端透传 + 前端运行对话框 method 下拉 |
| B2 SSR 多等位虚拟编码 | VCF 导入按 REF/ALT 数定 `marker_type`ALT≥2→"ssr",否则 "snp");新增 `_allelic_from_gt`"0/2"→{0:1,2:1} 每等位 0/1/2 存在)与 `_dosage_from_gt` 并列;**3 处装配(gather L3502/3636/3993)按 marker_type 分支**——SNP 走剂量、SSR 标记列展开为每等位一列(key `name:A{j}`);`genomic.build_g_matrix` 多等位分支:p_a=mean/2 逐等位列、Z=M2p_a、scale 分母 2Σ_all p_a(1p_a)VanRaden 多等位推广);全列 MAF 过滤照常;GS/GWAS 双消费,前端无需改(marker_type 下拉已存在) |
| B3 QTL×E | `POST /statistics/gwas-qtl-x-e`——按环境(site/year)分层:tree 观测按环境分桶(TraitObservationModel.site),每环境跑 `run_gwas`(同 marker/参数),合并 QTL`{qtl, peak_marker, chromosome, n_env_sig, envs:{site:{p,effect,sig}}, stable}`——≥2 环境显著且效应同号→**stable**、仅 1 环境→**env-specific**、异号→**G×QTL 警示****计算端点不建表**;前端 gwas 页 QTL×E tab |
| B4 MAS 语义 | `bre_mas_panel_marker` 扩列(`weld_mas_semantics.sql` 幂等 ADD COLUMN IF NOT EXISTS):`mode` String(16)additive/dominance/recessive/allele/haplotype,默认 additive/`favorable_allele` String(16)/`haplotype_group` String(32)`_mas_hit_map` gather 保留原始基因型(a,b)按语义分支——**additive**=现规则(dose≥fav/方向)、**dominance**=dose≥1(high)/≤1(low)、**recessive**=dose==2(high)/0(low)、**allele**=有利等位存在、**haplotype**=同组内全部命中才计 1decision_preview marker 条件沿用 n≥min_hits 语义自动透传;前端面板标记编辑器加三控件 |
**批3 求解器核心(高风险,独立新路径)**
| 缺口 | 落地 |
|---|---|
| A2 AR1×AR1 空间协方差 | `blup.solve_spatial``ENGINE_VERSION` 1.3.0):y=Xb+Zg+ee~N(0,σ²e·R)R_ij=ρ^(|Δrow|+|Δcol|)AR1(ρ)⊗AR1(ρ)v1 取 ρ_row=ρ_col 降维);**R⁻¹ 纯 numpy eigh**R_row=PΛP' → R⁻¹=(P⊗P)(Λ⊗Λ+…)⁻¹(P⊗P)');REML 对 (λ,ρ) 双重黄金搜索(复用 `_golden_max`);`run_ablup(spatial=True)` 装配补 row_no/col_no → method=AR1×AR1 / model_name=SPATIAL_*,ρ/σ²a/σ²e/h² 落批次 noteNA 安全 `_fmt`);**与 G×E/G×R 互斥**(Z₂ 单槽位,双开 409「互斥」);缺 row/col 坐标 → 409「需行/列坐标」;默认 `spatial=False` 路径逐字节不变 |
| A7 稀疏 A⁻¹+共轭梯度 | 阈值分派 `use_sparse = n_with_parents>0 and n>N_SPARSE(1000)``_build_ainv_sparse`Henderson 规则 COO 三元组 ainv_ii/jj/vv,纯 numpy)→ `_cg_solve`C·v=稠密 XtX/XtZ/ZtZ 子块 + `np.add.at` 稀疏 Ainv·vmax_iter=800/tol=1e-9);返回 `"solver":"sparse-cg"` + `cg_iter`**Hutchinson 随机探测**k=100、固定种子 20260804、`np.random.RandomState`):diag(C22⁻¹)≈mean(P∘(C⁻¹P))、P 随机 ±1 → PEV 对角 → reliability=1PEV/σa²,`"reliability_approx":True`;收敛失败→回退稠密/warning;稠密路径(n≤1000 或无线谱)逐字节不变,EBV/h²/σ² 为精确 CG 解(e2e 差 3.49e-12)、mean reliability 为 k=100 MC 近似(n=20 最坏 ~0.054,大群体收紧,文档标注「稀疏路径可靠性为近似」) |
**验证**:批1 `e2e_data_mating_gain_20260804.py`data-quality 命中人为离群株 / ΔG 公式自洽 / mating-recommend S-等位剔除+亲缘惩罚 / 无观测 409 门禁);批2 `e2e_molrigor_20260804.py` 五段(EMMAX 复现 QTL + SSR 混合 GBLUP 全标记进入 + QTL×E stable/env-specific 判定 + dominance/haplotype 语义命中 + 门禁);批3 `e2e_spatial_sparse_20260804.py` 三段(AR1×AR1 ρ=0.9796/h² 合理/method 标签 + 稀疏路径 EBV 3.49e-12/h² 0.00/CG 7 折/Hutchinson mean-rel Δ0.054 文档化 + 默认稠密路径引擎级 0 差、落库 4.92e-05 为 numeric(12,4) 量化);**回归**e2e_gwas7 段)/e2e_advanced_gblup/e2e_gblup_cv/e2e_gxr/e2e_refine/e2e_corr_spatial/e2e_molrigor 全绿;openapi 核验 4 新端点 + RunStatsIn.spatial/gxe/gxr + GwasRunIn/GwasQtlXEIn.method=emmax + MasPanelMarkerIn 三字段;前端 vue-tsc EXIT=0。
---
### 8.24 十二项真缺口·批1 引擎三件落地台账(v2.16,2026-08-05,代码级)
> 用户「全部补齐」后做全量现状盘点(2 个 Explore 代理 + 关键文件精读),发现总表大量「待建」标记过时——35 个 module_bre 后端模块 CRUD 全部齐全(9 端点 + 前端页 + API ts + 菜单)、数据字典四类已灌、描述统计/ANOVA 引擎已落地。真实缺口收敛为 **12 件**,用户拍板范围=只补这 12 件;移动端(V1.2)/品种登记 PVP(V3.0)/AI 三件套(V4.0)留波次不建。分三批独立 e2e + 回归,每批验收。本批批1=引擎三件(solver 扩展,独立新路径)。
| 缺口 | 落地 |
|---|---|
| ① ssGWAS | `gwas.py` 1.2.0 新增 `_ssgwas`run_gwas L161 `if method=="emmax"` 后加 elif):`genomic.build_g_matrix`blend 岭保证正定)构 G → `genomic.solve_gblup` 拟合全样本 GEBV û;**标记效应反推(Wang et al. 单步 GWAS)对角近似** `ê_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` 透传 ssgwasschema 已留)+ 前端 gwas 运行对话框 method 下拉加 ssgwas |
| ② 全 MT-BLUP | `mtblup.py` 1.1.0 新增 `solve_multi`(现状 `solve_bivariate` 单对双性状、Va/Ve 取单性状 REML 仅 ρ 一维):m 性状 y 堆叠、X/Z 块对角、Var(u)=G0⊗AG0 m×m 半正定)、Var(e)=diag(ve_i·I)**EM-REML 迭代**:初始 Va/Ve 取各性状 `blup.solve` REML、G0 非对角取 0,迭代更新 G0/ve(特征值截断 + Higham 投影保正定,mtblup 已有投影先例),max_iter 兜底不收敛→`converged=False`+warning;输出 G0 全元素 + r_g 矩阵 + n_iter/converged/warning`run_genetic_corr``full_mtblup=True` 模式(一次 m 性状给完整 G0 替代逐对);逐对 bivariate 路径保持(回归零风险) |
| ③ AR1×AR1 双参 ρ | `blup.py` 1.4.0 `solve_spatial``aniso: bool=False`v1 单参 ρ_row=ρ_col 坐标上升 h²↔ρ):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 逐字节一致**(回归断言);门禁/互斥/缺坐标逻辑不变 |
### 8.25 十二项真缺口·批2 模块四件落地台账(v2.16,2026-08-05,代码级)
> 批2=模块四件:参照 propagation/seed_lot 现成五件套(model + service/controller/schema + `module_bre/__init__.py` 注册 + 前端 `views/module_bre/<name>/index.vue` + `api/module_bre/<name>.ts` + 菜单 component 翻转 + Excel 导入导出)。表均已存在(analysis_dataset 新表 create_all 建),业务增强见下。
| 模块 | 落地 |
|---|---|
| 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`report_name/report_type/year/target_id/doc_path/gen_byCRUD + `POST /report/generate`(按 report_type 聚合 bre_prediction/bre_stability_result/bre_cv_result 成结构化报告 + doc_path);前端列表 + 生成对话框 |
| analysis_dataset 分析数据集 900070 | 新表 `bre_analysis_dataset`name/description/trait_codes jsonb/sample_ids jsonb/config jsonb/statuscreate_all + 幂等 weld 兜底);CRUD +「查看性状值」跳 statistics trait-values(复用既有视图,不重复造轮子) |
| 菜单翻转 + 文案清理 | 幂等 UPDATE component_path→`module_bre/<name>/index`、加 E 段按钮 900xxx;菜单 description 残留「待建」的 900014/900015/900021/900061/900063/900065 → UPDATE 去「待建」;前端 statistics/index.vue spatial 复选框加 aniso、gwas 运行对话框 method 下拉加 ssgwas |
### 8.26 十二项真缺口·批3 底座五件落地台账(v2.16,2026-08-05,代码级)
> 批3=底座五件:审计切面 / 统一编号服务 / 超期预警定时任务 / 备份容灾 / BrAPI+MIAPPE 互操作。
| 缺口 | 落地 |
|---|---|
| ④ 审计切面 | `bre_audit_log` 表(16 列已建,零实现)→ `module_bre/audit/`AuditLogModel + `GET /bre/audit/list` 过滤 entity_type/action/operator_id + 详情);`base_crud.py` 三个写方法事务内 flush 后追加:**create→CREATE 记录级**、**update→UPDATE 字段级 diff(每变更字段一行)**、**delete→DELETE 记录级**;开关 `settings.AUDIT_BRE_ENABLED`(默认 True+ 模型 `__bre_audit__=True` opt-in;**批量导入路径会话标志抑制逐行审计、仅汇总记一条**;uuid=str(uuid4())、created_time/updated_time=now()、is_deleted=falseoperator_id 仅 personnel.name==user.username 命中填(默认只填 created_id |
| ⑤ 统一编号服务 | 现状 4 处分散扫描式生成 → `app/utils/number_gen.py` `NumberGenService`(规则配置前缀/日期/序列/回绕)+ **原子取号 `pg_advisory_xact_lock` + bre_sequence 表**(新表 name/current_seq);迁移 4 处(行为格式保持):cross_combination._gen_combination_codeYY+3位)、tree._gen_tree_no(组合-序号)、selection_result clone_code(组合-{:04d} 扩位)、seedling batch_noYP-…);e2e:并发取号不重复(advisory lock)、4 种格式回归 |
| ⑥ 超期预警定时任务 | 调度框架已就绪(`app/core/ap_scheduler.py` + `module_task/cronjob` 持久化),任务本体缺 → 每日 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` + 前端「预警中心」页;e2e:造超期数据 → 触发 job → alert 落库 → 查询/幂等去重/resolve 后不再重复预警 |
| ⑦ 备份容灾 | `backend/scripts/pg_backup.sh`pg_dump 自定义格式到 `Temp/backup/`(按日期)+ N 天轮转;`pg_restore.sh` 恢复脚本;系统 job 每日 02:00 备份;e2e:跑脚本 → 备份文件存在 + `pg_restore --list` 校验(bre_alert/bre_sequence/bre_audit_log/bre_analysis_dataset 均在内,不实还原) |
| ⑧ BrAPI + MIAPPE | `module_bre/brapi/controller.py`prefix `/brapi/v2`,只读不建表,app 根注册非 /bre 前缀):`GET /germplasm`bre_germplasm → germplasmDbId/germplasmName/germplasmPUI/accessionNumber/commonCropName=Peach/genus=Prunus/species=persica/subtaxa=variety_type + additionalInfo 育种字段)、`GET /observationvariables`bre_trait → trait/method/scalescale.dataType 按 numeric/date/text 映射 + validValues 自 valid_min/max 与 scale_json categories)、`GET /studies`bre_trial_study + site 名)、`GET /observations`bre_trait_observation + bre_observation 合并、tree→germplasm join)、`GET /miappe`MIAPPE v1.1 元数据模板导出);BrAPI 2.x 包裹 `metadata{pagination,status,datafiles}+result{data}`、0 基分页 |
| 验证 | 批1 `Temp/claude/e2e_gaps_engines_20260804.py` 3 组 PASSssgwas 复现已知 QTL + solve_multi 3 性状 G0 半正定 r_g 与逐对同号量级 + aniso 与 v1 兼容、aniso=False 逐字节一致);批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 + IMPORT 抑制汇总 + 8-session 并发取号 1-8 唯一 + 三类预警命中/无负例误报/去重/resolve + 备份 pg_restore --list 四表 + BrAPI 结构分页映射);**回归**e2e_spatial_sparse / e2e_gwas / e2e_molrigor / e2e_advanced_gblup / e2e_gblup_cv / e2e_refine / e2e_gxr / e2e_corr_spatial 全复跑零回归(其间修复 `_allelic_columns` SSR 兜底误伤——SNP 标记"1/2"多等位调用应视为缺失,恢复 GBLUP「非基因型株 EBV=0」语义,B2 SSR 分支显式 marker_type="SSR" 不受影响);后端重启 + openapi 核验 631 路径(5 brapi + /report/generate + /audit/list + /alert/list+ HTTP smoke;前端 vue-tsc --noEmit EXIT=0 |
### 8.27 桃育种业务流全面完善·批A 业务数据链 + 批B 统计算法 + 批C 前端落地台账(v2.172026-08-05,代码级)
> 用户要求「对现有功能,结合桃育种实际业务流程与需求,进行全面测试分析,并完善」。三路审计(双代理并行 + 数据层性状字典探测 + 独立 grep/read 验证)收敛真实缺口 **10 项**(业务数据链 1-6 / 统计算法 7 / 前端 8-10),拍板全部实施并裁决两点:**导入按钮维持隐藏**(23+ 页显式隐藏,导入弹窗/处理器/后端端点完整保留)、**果实采收入口走农事操作**(op_type=harvest 结构化产量表单 + 同步统计引擎,非独立模块)。分三批独立 e2e + 全量回归,每批验收。
**批A 业务数据链(A1-A6**
| 缺口 | 落地 |
|---|---|
| A1 果实采收结构化入口 | `bre_field_operation` 加 4 可空列 `yield_kg`(单株产量kg)/`fruit_count`(果数)/`avg_fruit_weight`(均果重g)/`marketable_rate`(好果率%)`backend/sql/weld_busflow.sql` `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`create_all 不建已有表新列);service create/update 当 `op_type=="harvest"` 且 tree_id 非空且有产量数据 → 按 A2 种子 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``INSERT ... ON CONFLICT(trait_code) DO UPDATE`,幂等):产量构成 5single_tree_yield 单株产量 kg / fruit_number 果实个数 / avg_fruit_weight 平均单果重 g / marketable_rate 好果率 % / fruit_crack_rate 裂果率 % low+ 物候 3 date 型(full_bloom_date 盛花期 / fruit_maturity_date 果实成熟期 / leaf_fall_date 落叶期)+ 品质 3ss_content 可溶性固形物 % / titratable_acid 可滴定酸 % low / ss_acid_ratio 固酸比)+ 生长量 3trunk_circumference 主干周长 cm / tree_height 树高 m / crown_width 冠幅 m+ 描述性 categorical 5fruit_shape 果形 / pubescence 茸毛 / freestone 离核 / ground_color 果皮底色 / coloring_type 着色类型,into_ebv=0);category 产量构成/物候/果实品质/生长量/果实外观 + default_h2/direction |
| A3 种质级观测 | `bre_observation` 加可空 `germplasm_id`FK→bre_germplasmweld SQL ALTER + index);observation service `assert_parents_exist` 扩展种质校验;前端 observation 表单加种质选择器 + 搜索栏 germplasm 过滤 |
| A4 授粉→收种→种子处理补链 | `bre_seed_lot` 加可空 `pollination_id`FK→bre_pollination+ `bre_seed_treatment` 加可空 `seed_lot_id`FK→bre_seed_lotweld SQL ALTER);前端 seed_lot 授粉选择器(按 combination 过滤)、seed_treatment 种子批次选择器 |
| A5 EAV 观测校验 | observation + trait_observation create/updateobs_type=numeric → obs_value 可 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 育种阶段自动设置 + 成株性状门禁 | tree.service create 当 stage 为空 → 按 breeding_generation 推断(F 代杂种→`juvenile`、亲本/嫁接成株→`evaluation`);trait_observation create 门禁:trait.stage=evaluation 而 tree.stage=juvenile → **409**「童期树不可录成株性状」;juvenile 性状录童期树仍允许;不影响 decision_preview 的 marker 辅助选入(非观测路径) |
**批B 统计算法(B1-B4**
| 缺口 | 落地 |
|---|---|
| B1 type-B 多环境遗传力 | service 新 helper `_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`trait_id/trait_code/env_dim/envs_json/matrix_json/pairs_json/n_common/input_hash/engine_version/note+ controller `POST /statistics/type-b-heredity` + `GET /type-b` + `GET /type-b/{id}` |
| B2 correlation_matrix genetic 模式 | `correlation_matrix``mode="pheno"|"genetic"``g_method``year`**mode=pheno 分支逐字节不动**genetic 分支调新私有 `_genetic_corr_matrix`:1991)逐对 `mtblup.solve_bivariate` 组装矩阵(对角 1、非对角钳[-1,1]),**不落库**(对齐 data_quality 计算端点模式);schema CorrelationIn 加 mode/g_method/year;前端 correlation tab 加热图 + mode 切换 |
| B3 selection_index 自动权重 | `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:[{label,members,n}], merges:[{a,b,dist}], order:[...]}`controller `POST /statistics/cluster`(不落库) |
**批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 | `statistics/index.vue`correlation tab 相关性热图(mode 切换 pheno/genetic + 数值表);gblup tab 可靠性热图 + EBV 随年份趋势折线(per-batch 聚合);新增 type-B tab(热图 + 明细表 + 分环境对表);新增 cluster tab(树状图 + 聚类表);`echarts.ts` 注册 HeatmapChart + VisualMapComponent |
| C3 combination-funnel 前端入口 | statistics 工具栏「组合得失漏斗」按钮 + 对话框(1080px)调 `GET /statistics/combination-funnel` 六级派生指标表(后端 :351 已有、前端此前缺失) |
| C4 stage_phenotype 容器同步 | `stage_phenotype/index.vue` tabs 通用观测→observation、农事操作→field_operation`_shared/StageView.vue` compMap 注册,替换 ComingSoon |
**验证**:批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 2 环境矩阵对角 1/对称/r_g∈[-1,1]/site 与 year 环境集不同/n_common=共有树/GET 回查 + correlation pheno 逐字节回归/genetic 对称对角 1/g_method=calo + index auto==手工 default_h2 权重排名/asc 符号翻转/into_ebv=0 剔除 + cluster 3 已知类 UPGMA 还原/k=1·k=n 边界/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);**回归**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 核验新路径(/type-b-heredity、/type-b、/type-b/{id}、/cluster、correlation?mode/genetic、/selection-index auto_weights);前端 vue-tsc --noEmit EXIT=0。
---
### 8.28 遗传链完整性两次修复:世代闭环 + 近交惩罚静默关闭落地台账(v2.18,2026-08-05,代码级)
> 两次修复同根同源——**统计引擎的系谱解析若拿不到亲本,一切遗传分析(A-BLUP/亲缘/近交规避/遗传增益)都会在用户无感知时静默退化**。用户先后以具体现象报告:① 建种质断链(晋升种质被当 founder);② 近交惩罚可能「静默关闭」(亲缘矩阵全 0 且无告警)。逐条核实后确认,并发现额外崩溃隐患(候选既是 child 又是祖先 → 系谱重复 → 引擎抛错),一并修复。
**修复 ① 世代闭环**`selection_result/service.py`):`_promote_tree_to_clone` 晋级到 `line/regional_trial/released` 建种质时,**同步落 `bre_pedigree`**——child_code=品种名、dam/sire=tree.dam_id/sire_id(为空回退组合 female/male_parent_id)、combination_id、generation=tree.generationchild_code 幂等查重;种质携带 generation/stage`combo=None` 顶部初始化防"已有 clone 再晋级品系"路径 UnboundLocalError。**判别点**:两棵仅经晋升种质共享祖先的下一代树 `A[T2,T3]=0(修复前)→0.125(修复后)`,血缘推导 `2·¼·f(gT1,gA)=2·¼·¼``A[gT1,gA]=0.5`(亲子)佐证。
**修复 ② 近交惩罚静默关闭**`statistics/service.py`):
- **根因**`mating_recommend` 亲缘矩阵靠 `_germplasm_pedigree``bre_pedigree.child_code``cultivar_name/accession_no` **精确等值匹配**建系谱。名称不完全一致(大小写/空格/代号)→ 行全部跳过 → pedigree 空 → rmat={} → 所有配对 r=0 → `kin_pen=max(0,0thr)=0` → 近交规避整体失效且返回体无任何告警。
- **重写 `_germplasm_pedigree` 多源级联**(返回 `(pedigree, coverage)`):① `bre_pedigree.child_code` 规范化(strip+casefold)命中名称(**显式系谱为权威**,且直接修复大小写/空格错配)→ ② **FK 兜底**`tree.germplasm_id == 该种质` 的树 → 其 dam_id/sire_id 全集去重后**唯一一致**才采纳(升种质=升谱树自带种质级亲本;多对歧义如 trial 树挂冲突亲本 → 视为无回退 founder,不武断选取)→ ③ founder。祖先以同级联 **BFS 展开 + 去重**——消除候选既是 child 又是祖先时的 `g{id}` 重复追加 → `relationship_matrix`『系谱个体重复』崩溃。coverage 含 total/resolved/resolved_ids/founder/matched_rows/orphan_rows/fk_sources。
- **`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)。**绝不静默 no-op**。
- **设计红线**e2e_data_mating_gain 回归保真):A6 探针的 trial 树 `germplasm_id=G4` 但 dam/sire=FM/MM(与 bre_pedigree 显式 dam=G0 冲突)→ 显式系谱必须压过冲突 FK,`r(G0,G4)=0.5` 保持——**FK 只做兜底,绝不覆盖显式系谱**。
**验证**`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` 返回 `kinship_status/kinship_warning/kinship` 与逐对旗标(真实数据 32/33 → status=none 正确触发,且暴露 2 条真实孤儿系谱行——数据质量信号)。
### 8.29 选配「亲本 EBV」回退逻辑方法学修复落地台账(v2.19,2026-08-05,代码级)
> 与 §8.28② 同区域(`mating_recommend`)的**方法学缺陷**——不是"拿不到数据",而是"拿到后用错了":旧实现对缺直接 EBV 行的候选种质,用其**子代树 EBV 均值**代表该亲本育种值,且**不区分来源、不降权**。用户三条质疑逐条核实成立:① 子代测验值是**子代世代**的预测值(≈½亲本BV + 共亲本渗入 + 孟德尔抽样),不是亲本自身育种值;② 同一子代树若双亲都缺直接 EBV,被**等权计入 dam 与 sire 两侧**(每棵树的均值重复计,稀释);③ 跨组合混合无区分。会误导选配排序。
**修复**`statistics/service.py` `mating_recommend`):
- **direct 优先**:种质级 EBV 行(`germplasm_id` 直连)=亲本自身预测值,无条件最优先;有 direct 的候选**绝不被其子代树值污染**(回退仅对 `missing` 集生效)。
- **回退显式标注 + 降权**:新增 `_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 计(与旧行为一致,全缺失时排序不变,A6 回归安全)。
- **双侧等权稀释修复**:子代树双亲均在 `missing` 集(如 FM×MM 双亲均无 direct)→ **剔除**(该树均值无法归属,防止同值计入两侧);仅单侧可归属的树才计入对应亲本。
- **跨组合辨别**:回退亲本记 `n_progeny`(子代数)/`n_combos`(跨组合数),供调用方判断子代测验近似的稳健性。
- **显式可查,绝不静默降级**:返回体新增 **`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;② 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 核验真实端点返回 `candidate_ebv``ebv_source.coverage`(真实数据 coverage={direct:0,progeny:0,missing:12} 正确)。
---
### 8.30 数据质量「离群值」方向语义错位修复落地台账(v2.20,2026-08-05,代码级)
> 与 §8.17①/§8.23① 的 A5 数据质量端点同区域(`data_quality_report`)的**语义错位**——旧实现把 IQR/MAD 检出的任何偏离株一律标为「离群株(疑似异常)」,但**偏离的方向才是关键**:桃育种按选育目标选极端表型(果重/固酸比/可溶性固形物要高的、裂果率/病指要低的),**正向偏离恰恰是育种家要找的精英单株**,把精英候选标成「疑似录入错误」会诱导弃选、误导决策。
**修复**`statistics/service.py` `data_quality_report`):
- **方向感知**:取 `bre_trait.direction`desc/None → `desirable_high=True` 高值优;asc → `False` 低值优)。判定标准与既有遗传评估链路(v2.3 性状方向标注)完全一致。
- **双通道分流**IQR 超界 / MAD 稳健 z>3.5 命中的株再按偏离侧分类——`is_high = v > med``is_elite = is_high == desirable_high`**同向偏离 → `extreme_candidates`**class=`extreme_candidate`side=high/low,极值候选·精英);**反向偏离 → `outliers`**class=`outlier`,疑似录入错误)。两表**互斥**,精英绝不进错误表。
- **返回体**:新增 `direction``extreme_candidates`tree_id/value/z/side/class/reasons)、`summary.n_extreme_candidates``summary.has_warning/n_outliers/outlier_rate` 语义收紧为**疑似录入错误**计数(不再把精英株计入告警)。
- **前端**`statistics/index.vue` 数据质量 tab):选育方向指示条(高值优 desc / 低值优 asc)+ 双表(「极值候选(精英)」success 标签表 + 「疑似录入错误」danger 标签表);hint 说明同向=精英/反向=错误;无错误时绿色 info alert「未发现疑似录入错误」而非黄色警告。
**验证**`Temp/claude/e2e_data_mating_gain_20260804.py` **[1] 17 株断言全过**——15 正常 + 精英树(16.0+ 错误树(2.0),direction=desc:精英树进 `extreme_candidates`class=extreme_candidate/side=high)且**不在** outliers;错误树进 `outliers`class=outlier/side=low);`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` 全部正确——真实数据无极端偏离 → 双表空(**无误报**)。
---
## 9. 已决策取值汇总(v1.2,本人敲定)
> 下列枚举由本人依据 RosBREED 桃无性选育流水线 + 现有 14 域敲定(用户授权"你来定")。全部作为 `sys_dict` 新增字典类型,落库英码、前端显中文,并接入 Excel 导入翻译(DictLabelResolver)。
### 9.1 breeding_stage(选择阶段)
| code | 中文 | 主要适用实体 | 说明 |
|---|---|---|---|
| germplasm | 种质资源 | germplasm | 基础材料/引入种 |
| parent | 亲本 | germplasm | 用于杂交的亲本 |
| seedling | 实生苗/群体植株 | tree | 杂交实生群体、未入选 |
| sp | 初选株 | tree | Single Plant,田间初选 |
| ap | 复选株 | tree | Advanced,跨年跨点复选 |
| line | 品系 | germplasm | 克隆扩繁、系统观察 |
| regional_trial | 区试品系 | germplasm | 区域试验 |
| released | 新品种/审定 | germplasm | 命名/登记/审定 |
> tree 用 seedling/sp/apgermplasm 用 germplasm/parent/line/regional_trial/released`selection_result` 记录 from_stage→to_stage 晋级流转。
### 9.2 breeding_generation(遗传世代)
| code | 中文 | 说明 |
|---|---|---|
| F1 | 杂交集 | 首次杂交产生的分离群体(桃主要选种群体) |
| F2 | 自交/互交分离世代 | F1 自交或 F1×F1 |
| BC1 | 回交 1 代 | 导入性状(如抗病)回交 |
| BC2 | 回交 2 代 | |
| BC3 | 回交 3 代 | |
> 引入种质/地方品种 `generation` 留空。权威存 `cross_combination.generation`(与 `cross_type` 联动:回交→BCn,自交→F2),`tree`/`germplasm` 冗余拷贝便于筛选。
### 9.3 breeding_group_type(分组维度)
| code | 中文 | 说明 |
|---|---|---|
| project | 育种项目 | 正式项目集合 |
| family | 家系/杂交组合群 | 同 cross_combination 的后代集合 |
| category | 种质类别群 | 油桃/蟠桃/观赏桃等类别 |
| temporary_set | 临时选系集 | 临时任务选系集 |
| custom | 自定义 | 用户自由定义 |
> 不设 objective 维度(与 `target` 育种目标语义重叠)。
### 9.4 breeding_design_type(试验设计)
| code | 中文 | 说明 |
|---|---|---|
| rcbd | 随机区组 | 高级 trial 常用,区组+重复+对照 |
| augmented | 增广设计 | 多品系少重复+对照重复,**早期选种最适用** |
| contrast | 对比试验 | 少量材料与对照比较 |
| split_plot | 裂区设计 | 砧木×接穗等两因子 |
| unreplicated | 观察圃/简约 | 无重复,初步观察 |
### 9.5 propagation 纳入一期(§3.8
打通 入选株(tree) → 克隆种质(germplasm) → 扩繁批次(propagation) → 新定植树(tree) 闭环。
### 9.6 字典落地
`breeding_dict.sql` 增补 `breeding_stage`/`breeding_generation`/`breeding_group_type`/`breeding_design_type` 四类(英码+中文),并接入对应 service 的 Excel 导入翻译(DictLabelResolver)与前端下拉。
---
**定稿状态(v2.22026-07-30**:历经 v1.0→…→v1.9 + **v2.0 架构决策锁定** + **v2.1 review 修订(R1R9** + **v2.2 深度复审 A–H 全量落地(含 F1/F2 架构拍板:单一长表 + 两长表职责正交 + 统计 VIEW/看板 MVA1 clone 建于入选 / A3 砧木 FK 统一字典 / A4 pedigree 唯一权威 / B1-B4 统计口径 / C1-C3 门禁重构 / D1-D4 clone 居中 / F3-F5 门禁与公式修正 / G1-G3 编号·审计·method / H1-H3 打磨,详见 §8.10**。所有模块、字段、枚举、建模铁律、互操作映射均已规格化。**仍为决策锁定、方案态**:除生成器 A/B/C 外,待用户明确"做/搞吧"后据此实施,不先行编码。