1585 lines
297 KiB
Markdown
1585 lines
297 KiB
Markdown
# 桃育种系统 · 模块扩展需求规格(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_number,MET 设计矩阵)② 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.panel(GS 训练群体分组)⑧ 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_id(A1 核心性状环境键)② planting 粒度=block 级 + entry 跨 block 多 planting(A2)③ 新增 planting_treatment 关联表(A3)④ seed_lot.used_count 明确粒数(A4)⑤ §4 补 tree_photo 行(A5)⑥ tree→germplasm 重复测量聚合 EBV(A6)⑦ 国际补强: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.0,clone_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 修订(R1–R9)**:① **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_id;D2 `breeding_clone`+generation;D3 `trial_study_entry`+clone_id;D4 补 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 强制 audit;G3 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、generation,child_code 幂等查重)→ 晋升种质不再被统计引擎当 founder,跨世代系谱链闭合(A-BLUP/亲缘矩阵/近交规避/遗传增益滚雪球恢复);② **近交惩罚「静默关闭」修复**——`mating_recommend` 亲缘矩阵旧实现靠 `bre_pedigree.child_code` 与种质 cultivar_name/accession_no **精确字符串匹配**,大小写/空格/代号 任一错配即全空 → rmat={} → 每对 r=0 → kin_pen=max(0,0−thr)=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 双亲均无 → 该树均值重复计、稀释);③ 跨组合混合无区分。修复:**direct(germplasm_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(Q1−1.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.0,direction=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.22 | 2026-08-05 | **A–F 六项功能级缺口补齐·批1 父本验证 + 近交衰退(用户全模块 grep 实证 A–F 六项缺口均为「有无/深度」问题、非正确性 bug,逐项复核确认 + 拍板「全部六项分批落地」;批1 独立 e2e + 全量回归零回归,§8.32 / `桃育种系统统计引擎实施记录.md` §18.10)**:**A 父本验证(consistency,不落库)**——① A1 pollination 花粉来源一致性(`_validate_pollen_parent`,create/update 统一)——花粉批次声明采集父本树(`pollen.male_tree_id`)时,授粉声明父本树须与之相同否则 409(「花粉批次 {lot} 采集自父本树 {X},与授粉声明父本树 {Y} 不一致」);批次无采集父本(混合/外地采集)或授粉未声明父本 → 放行不武断 ② A2 tree 显式亲本 vs 组合父母本警示——`_resolve_parents` 显式 dam/sire 与组合 female/male_parent 不一致时返回体 `warning`「显式母本/父本与组合母本/父本不一致(以显式为准)」(双侧/单侧分别聚合),**warning 不阻断**(tree 可独立建,武断 409 会误伤),schema 加只读 `warning` 字段不落库 ③ A3 cross_combination 同质自交门禁——`_check_parent_roles` 中 `female_parent_id==male_parent_id` → 409「母本与父本同为「{名}」,自交组合请确认」(create/update 生效亲本统一);**C 近交衰退分析(计算端点,不建表)**——`POST /statistics/inbreeding-depression`(入参 trait_id/trait_code + year/trial_study_id 可选 + min_n):取 `blup.relationship_matrix` 的 F=A_ii−1(按树,**非近交树从 individuals 默认 F=0 兜底**,避免被排除)+ 该 trait 树级表型(group_by(tree_id) 均值聚合)→ **纯 numpy lstsq 线性回归 phenotype ~ F**——`sufficient`/`reason`/`n_obs`/`mean_F`/`max_F`/`direction`/`regression{intercept,slope,r2,t_slope,depression_rate,has_depression,interpretation}` + `high_inbreeding`(F 排名前列含 tree_no/value,现场核查);`has_depression = slope<0 且 t_slope≤−1.645`(单侧 95% 大样本近似);n<min_n 优雅降级 `sufficient=False` + reason(不 409);前端「亲缘/近交」tab 加衰退区(trait 选择 + year + 回归摘要 el-descriptions + 高 F 株表,el-alert 用 error/success/warning 合法类型)。验证:`e2e_parent_validation_20260805.py` 10 断言全过(A1 不一致 409/一致放行/混合批次放行/update 同门禁 + A2 双侧警示/单侧仅父本/一致无警示/update 警示 + A3 create/update 同质 409);`e2e_inbreeding_depression_20260805.py` 4 断言全过(12 树 6×F=0+6×F=0.5:衰退性状 y=100−60F+ε → slope≈−60/has_depression=true/前 6 高 F=自交株、无衰退 y≈100 → slope≈0/未检出、min_n=20 → insufficient 含「12 棵」「≥20」、性状不存在 409);回归 spatial/sparse、statsflow、A6、亲缘、批次、底座六套零回归;vue-tsc EXIT=0;后端重启 + HTTP 核验 inbreeding-depression 真实稀疏数据返回 code=0/sufficient=false/n_obs=2/reason;`_DATA_VERSION` v2.22 |
|
||
| v2.23 | 2026-08-05 | **A–F 六项功能级缺口补齐·批2 GS 家系 CV + 试验设计深度(批1 已落地 §8.32/v2.22;批2 = B+F,独立 e2e 探针 + 全量回归零回归,§8.33 / `桃育种系统统计引擎实施记录.md` §18.11)**:**B GS 家系 CV(深度:随机分层 → 家系阻塞折)**——`genomic.kfold_cv_genomic` 加 `split="random"|"family"` + `family_of`:`split="random"` 现有 round-robin **逐字节不变**(回归零变化);`split="family"` 照 `blup.kfold_cv` 的 sire 家系留出模式——`fam_of = {ind: family_of.get(ind, ("self", ind))}`(无家系个体自成一族)→ 家系 shuffle + 分折,**同家系个体同折**(防亲缘泄漏高估准确度),**家系数<折数 k → 折叠为 n_families 折 + warning**、单家系 → folds=[] + warning,输出加 `n_families`;`run_cv` 加 `split` 透传——GS 分支用既有 `ped_rows`(已取 `TreeModel.sire_id` + `CrossCombinationModel.male_parent_id`)构建 `family_of={f"t{tid}": f"s{sire}"}`(sire 缺失回退组合 male_parent),落库 note 记 `split=family · n_families=N`;前端 runCv 对话框加 split 下拉(随机分层/家系阻塞)+ 结果 n_families;**F 试验设计深度(RCBD 生成 + 设计基 ANOVA)**——F1 `bre_trial_study_entry.block_no`(model 列 + `weld_trial_study_entry.sql` 幂等)+ 新端点 `POST /statistics/trial-design`(`TrialDesignIn`:trial_study_id + design_type="rcbd" + seed 可选)——按 `trial_study.block_count` 把 entry **均分到区组 + `random.Random(seed)` 组内随机**(seed 可复现、异 seed 异设计)、`case()` 批量落库 block_no、输出 `{blocks:{block_no:[entry_number…]}, block_count, seed}`、无参试条目 409;F2 `anova.solve_rcbd` RCBD 双因素 **Type I 顺序**(grand mean→group→block,SS_block=rss(Xg)−rss(Xgb),纯 numpy + fdist)析出 SS_block/F_block/p_block + 校正后遗传差异 + `run_anova(block=True)`(method=ANOVA/H2/RCBD、<2 区组 409 提示先运行 trial-design;**block=False 单因素路径逐字节不变**);前端 ANOVA tab 加「生成 RCBD 设计」工具条 + 设计区组表 + block 校正 checkbox + 区组均值表。验证:`e2e_trial_design_20260805.py` 5 组断言全过(生成/复现/落库/block=True 区组效应析出/门禁)+ `e2e_gs_family_cv_20260805.py` 5 组断言全过(家系阻塞折 [3,6,6]/每折1家系/random 回归零变化/家系数折叠/单家系边界)+ 回归 gblup_cv/statsflow/spatial/busflow/kinship/gaps_base/molrigor 七套零回归 + vue-tsc EXIT=0 + HTTP 核验;`_DATA_VERSION` v2.23、`genomic.ENGINE_VERSION` 1.3.0 |
|
||
| v2.25 | 2026-08-05 | **分子亲本验证 + 试验设计深度·批4(前批1-3 已落地 §8.32-§8.34、v2.22-v2.24;批4 独立 e2e 探针 + 全量回归零回归,§8.36 / `桃育种系统统计引擎实施记录.md` §18.14)**:**A 孟德尔/亲本一致性检验(genotype_call 补齐 parentage 零命中缺口,只读纯计算不落库)**——`GET /bre/genotype_call/mendelian/check`(镜像 fingerprint/check 的 GET+Query 模式):子代树样本(`source_type="tree"`)基因型 vs 声明亲本(`tree.dam_id/sire_id`→germplasm)基因型,亲本基因型取 `source_type="germplasm"` 样本**跨数据集解析**(同数据集优先、否则全库最低 id 兜底);按标记 `_allele_set`("/" 分割去空白/缺失)**union 规则**——子代等位集 ⊆ dam∪sire 并集即兼容,任亲本空白/缺失 → 非信息位点不计分母;单株兼容率=兼容/信息位点,`rate < compat_threshold`(默认 0.98 对齐 fingerprint)判 flag;双亲皆空 → `no_declared_parents`、亲本声明但无 germplasm 基因型 → `missing_parent_genotype`(不 409,数据现状);输出 `{trees_checked/trees_flagged/trees_no_parents/trees_missing_parent_genotype, summary{informative/incompatible}, trees:[{tree_no,dam,sire,status,informative_markers,compatible,incompatible,compatibility_rate,flag,incompatible_markers:[{marker_id,allele,dam,sire}]}]}`;**B 试验设计深度(trial_design 仅 RCBD → augmented 增广 + alpha α-格子,rcbd 路径逐字节不变)**——**augmented** `check_germplasm_ids` 显式对照(须为参试条目种质子集否则 409、至少 1 对照 + 1 新品系):对照每区组重复(anchors)、新品系 `rng.shuffle` round-robin 均分区组,对照 `block_no` 不落库(None)、新品系落 1..block_count;输出加 `checks/n_new_entries/n_checks/check_reps=block_count`;**alpha** `block_size=k` + `reps=r` 可选:平方条目数 v=k² → **闭式格子**(标签 (x,y)、rep m 直线 y≡m·x+(b−1) mod k、m=k=竖列;k 素数完全平衡 λ≤1,非素数 `balance_warning=True` 保守告警)、完全格子 r=k+1;非平方 v → **贪心可分解构造**(`used_pairs` 避免同块对重复、卡死允许复用 + balance_warning);`block_no` 复合编码 **rep*100+block**(1-based,修复探针抓出的 0-based off-by-one:平方分支原 `m*100+b` 致 rep1 落库 1..3 与 greedy 分支/文档不一致 → 改 `(m+1)*100+b`);校验 v%k≠0/非平方缺 k/重复数 r<2 或超完全格子上限 409;输出 `{block_count=s, block_size, reps, balance_warning, blocks:{rep:{block:[entry_number…]}}}`。验证:`e2e_mendelian_check_20260805.py` **8 断言全过**(子代样本 D1/亲本样本 D2 跨数据集解析:T1 alien 等位 2/2 → rate=0.8/flag/incompatible_markers 含 M5+双亲等位、T2 全兼容 rate=1.0、T3 双亲空 no_declared_parents、T4 亲本缺基因型 missing_parent_genotype、summary informative=10/incompatible=1、空数据集零值不 409)+ `e2e_trial_design_ext_20260805.py` **19 断言全过**([1] augmented 9 新+3 对照×3 区组、新条 block_no∈{1,2,3} 对照 None、checks 结构;[2] v=9=k² k=3 素数完全格子 r=4 每 rep 覆盖 9 + 任一对 λ≤1 + balance_warning=False + block_no 编码落库;[3] 部分 r=3 仍平衡;[4] v=16 k=4 非素数 balance_warning=True 可分解;[5] v=12 一般贪心 s=4 可分解 + 编码落库;[6] 四 409)+ 回归 trial_design(rcbd)/ocs/mabc/mating_ebv/mating_kinship/parent_validation/statsflow/spatial_sparse/gs_family_cv/batch_selection/gaps_base/gaps_engines/gaps_modules/prediction_rigor/inbreeding_depression 全套零回归 + vue-tsc EXIT=0 + 后端重启 HTTP 核验(mendelian/check 200 零值结构、trial-design augmented/alpha 经真实端点分派到无条目 409、latin 等非法类型 409「暂不支持设计类型」);`_DATA_VERSION` v2.25 |
|
||
| v2.28 | 2026-08-05 | **统计引擎全量十模块 golden 复查·系谱键空间错位修复(用户质疑 GBLUP/ssGBLUP、genetic_corr、type_b、cluster、stability、OCS、MABC、inbreeding_depression、trial_design、mendelian 十新建模块缺逐模块数值校验,拍板「全量十项逐一复查」;审计抓到真 bug 就地修 + 探针加回归,独立 e2e 探针 21 断言 + 全量回归零回归,§8.39 / `桃育种系统统计引擎实施记录.md` §18.17)**:复查确认 **8/10 模块已 golden**(GBLUP/ssGBLUP、cluster、stability、OCS、MABC、inbreeding_depression、trial_design、mendelian 既有探针已具严格数值断言),**type_b 与 genetic_corr 补齐 golden 缺口**——审计深处暴露**系谱键空间错位真 bug**:`run_type_b_heredity`/`correlation_matrix`(mtblup)/`run_genetic_corr` 四个服务路径把 **int `tree_id` 表型键**传给 `mtblup.solve_bivariate`,而 `_build_pedigree` 系谱用 **str `"t{id}"`**,`blup.solve` 把系谱外个体自动并入 base(无关 founder)→ **系谱被静默丢弃**。平衡数据(同株跨环境)掩盖;**分裂家系数据**(无同株跨环境、靠全同胞链桥接)暴露——int 键 → r_B/r_g 锁死 ±0.99(平剖面端点假收敛、假阴性负相关)。修复:共享 helper `_tree_individual_keys`(int→`"t{id}"` 对齐系谱键空间)收口**四个调用点**(`_genetic_corr_matrix`/`_smith_hazel_index` mtblup 分支/`run_genetic_corr`/`run_type_b_heredity`);`run_ablup` 早已正确不受影响。新探针 `e2e_rg_golden_20260805.py` **ok=21 fail=0**(20 founder×10 全同胞家系×3 同胞=30 株、3 站点:P0 诊断 str 键恢复 r_B=0.7+ / int 键锁死 −0.99;P1 type_b 分裂家系 r_B(1,2)>0.5 + **n_common=0**(无共有树、系谱桥接生效的直接证据);P2 correlation 平衡 r_g(A,B)>0.65/AC,BC<0.4/判别间隙>0.3/h²∈(0,1);P2b 分裂家系 discriminator r_g(S1,S2)>0.5)。验证:`e2e_statsflow`(单家系 fixture 对键 bug 不敏感,15 断言零变化)+ `e2e_advanced_mtblup` 回归通过 + **全量回归零回归**(batches 1–3 + final,60 套件,含版本断言同步)+ vue-tsc EXIT=0 + 后端重启 HTTP 核验(type-b-heredity / genetic-corr/run 分裂家系判别经真实端点)+ 备份镜像 `Temp/claude/backup_keyspace_20260805/`;`_DATA_VERSION` v2.28 |
|
||
| v2.27 | 2026-08-05 | **规划↔目标↔试验 可追溯性闭环(用户全代码库 grep 实证 `bre_plan` 彻底孤立根表——plan_id/bre_plan/ForeignKey…plan 只命中 plan/ 模块自身,零传入外键,`bre_trial` 无 plan_id/target_id,无 project/program 表;核实确认 + 拍板「加试验挂目标」最小双链,独立 e2e 探针 17 断言 + 全量回归零回归,§8.38 / `桃育种系统统计引擎实施记录.md` §18.16)**:**bre_target.plan_id + bre_trial.plan_id + bre_trial.target_id 三可空 FK**(weld SQL 幂等 + model/schema/service/controller 透传),关闭两条可追溯链——**plan→target→cross_combination→tree**(目标链)与 **plan→trial→trial_study→tree**(试验链);target/trial 列表返回 `plan_name`(挂计划目标/试验)与 `target_name` 解析标签;**父校验**:target create 不存在 plan_id → 409、trial create 不存在 plan_id/target_id → 409(`assert_parents_exist` 跳过 None,孤目标/独立试验仍可建);**删除守卫**:plan.delete 有 target/trial 子 → 409、target.delete 有 combo/trial 子 → 409(`assert_no_children`);**计划可追溯端点** `GET /bre/plan/trace/{id}`——`plan` 基础信息 + `targets[]`(n_combinations/n_trees/combinations[] 含每组合株数)+ `trials[]`(target_id/target_name/n_trial_studies/n_trees/trial_studies[])+ `totals`(targets/trials/combinations/trial_studies/trees),**软删过滤**(is_deleted 组合/试验点不进入 trace),trace 不存在计划 → 409;前端:target/trial 表单加「所属计划/目标」select + 表格/详情列 + plan 页「追溯」行操作弹窗(ElCollapse 目标链/试验链,组合与试验点 ElTags)。验证:`e2e_plan_trace_20260805.py` **17 断言全过**([1] 目标链 n_combinations=2/4 树 + 软删 C2 排除;[2] 试验链 n_trial_studies=1/2 树 + target_name 解析 + 软删 S2 排除;[3] totals=2 组合/6 树;[4] 孤目标不入 trace + 不存在计划 409;[5] target/trial page 标签解析 + 孤目标 plan_name=None;[6] 三父校验 409;[7] 双删除守卫 409)+ 全量回归零回归(含审计切面探针排查修复:`entity_id` 按实体表各自序列非全局唯一 → 残留检查限定 `entity_type=='bre_target'`,跨表撞 id 误报根治)+ vue-tsc EXIT=0 + 后端重启 HTTP 核验;`_DATA_VERSION` v2.27 |
|
||
| v2.26 | 2026-08-05 | **批5 区组随机效应 ABLUP(N3)+ 孟德尔检验落库/隔离/进报告(N1)+ 统计引擎全量数值校验(N2)**(用户实证复查三项全部成立,拍板落地,§8.37 / `桃育种系统统计引擎实施记录.md` §18.15):**N3** `blup.solve` 加 `block` 第二随机效应(`_solve_block` 镜像 `_solve_gxe`,σ²block 剖面 REML,ENGINE_VERSION 1.5.0);`run_ablup(block=True)` → method=ABLUP-BLOCK,block_no 缺树降级剔表型留系谱、<2 区组 409、与 gxe/gxr/spatial 互斥 409,前端 GxE tab block 开关;**N1** 孟德尔检验落库(`bre_mendelian_check` + 每树子表 + `bre_pedigree_exclusion` 隔离注册表,`POST /bre/genotype_call/mendelian/check/run`,GET 只读预览零回归)+ 自动隔离可逆(flag→upsert 隔离、未 flag→清除)+ `data_quality_report(dataset_id)` mendelian 段(flagged>0 → has_warning)+ 系谱消费方断开隔离树亲本链(退化为 founder 表型保留:_build_pedigree/run_ablup/inbreeding/kinship/cv/_germplasm_pedigree,GBLUP 基因型样本不受影响);**N2** 新探针 `e2e_stats_numerics_20260805.py` **ok=101 fail=0** 全量统计引擎逐段独立 ground-truth 真值(blup/gxe/block/spatial-aniso/gblup/ssgblup/bivariate/multi/FW/ammi/rcbd/diallel/ocs/UPGMA/ΔG/data-quality/kinship 全对照;探针自身两处 fixture 缺陷修复——低 h² 小样本 r_g 假收敛换高遗传力良态设计、B4.2 硬编码 tree_id——**引擎本体零缺陷**);验证 27 套件全量回归零回归 + vue-tsc EXIT=0 + HTTP 核验四端点 + 备份镜像 `Temp/claude/backup_block_mendelian_numerics_20260805/`;`_DATA_VERSION` v2.26、`blup.ENGINE_VERSION` 1.5.0 |
|
||
| v2.24 | 2026-08-05 | **A–F 六项功能级缺口补齐·批3 OCS 最优贡献选择 + MABC 标记辅助回交(批1/批2 已落地 §8.32/§8.33、v2.22/v2.23;批3 = D+E,独立 e2e 探针 + 全量回归零回归,§8.34 / `桃育种系统统计引擎实施记录.md` §18.12)**:**D OCS 最优贡献选择(群体配种贡献优化,纯计算不落库)**——`POST /statistics/ocs`(`OcsIn`:candidate_germplasm_ids + n_select=5 + lam=0.1 + prediction_id 可选):**max Σc_i·ebv_i − λ·c'Ac,s.t. Σc=n_select、c≥0**(纯 numpy **欧氏投影梯度** `_proj_simplex` + `_solve_ocs`,候选数<50 足够;A 由 `_germplasm_pedigree` + `blup.relationship_matrix` rmat 组装、对角=1 非对角按候选对取 r);EBV 复用**抽出的共享 helper `_candidate_ebv_map`**(mating_recommend 内联块原样提取,direct 优先/progeny 降权 0.5/双亲均缺剔除/n_progeny·n_combos/coverage,**mating 回归 14/14 零变化**);输出 `contributions`(每候选 c 降序含 germplasm_id/name/c/ebv/source + 可选 n_progeny/n_combos)、`mean_ebv`、`avg_kinship`(c'Ac)、`kinship_quad`、`vs_top_n{n,mean_ebv,avg_kinship,ebv_loss,kinship_reduction}`(对照贪心 top-n 展示 OCS 亲缘控制价值)、ebv_source/kinship_status/kinship_warning;门禁 n_select>候选/空候选/λ<0 409;**E MABC 标记辅助回交(前景+背景选择工作流,纯计算不落库)**——`POST /statistics/mabc-progress`(`MabcIn`:candidate_tree_ids + foreground_panel_ids + background_panel_ids + recurrent_parent_tree_id + foreground_min_hits=1 + generation=BC1 + background_target=90):**前景**复用 `_mas_hit_map`/`_mas_marker_hit`(additive/dominance/recessive/allele/haplotype 五语义,stage 无关、童期幼苗即可筛选),`foreground_pass`=命中≥阈值;**背景恢复率**对 background 面板每标记取候选 vs 轮回亲本「**纯合剂量一致**」比例(`_pure_homologous`:候选纯合且等位∈轮回亲本等位集;杂合不算),均值=基因组恢复率估计 %;**回交代建议**按 `_BC_LADDER` 晋级(pass+恢复≥target → 下一代 F1→BC1→…→BC5→自交固定;pass+不足 → 再回交一代;pass+恢复无法评估 → 补测后判定;fail → 维持+前景未通过);输出 per_tree{foreground_hits/by_panel/pass,background_recovery,n_background_compared,n_background_recovered,bc_generation,reason} + `recommended`(前景通过按恢复率降序)+ summary{n_pass,n_with_recovery,mean_background_recovery} + warning(轮回亲本无背景基因型/背景面板无标记);门禁空候选/空面板/generation 非法/background_target∉(0,100]/轮回亲本不存在 409。验证:`e2e_ocs_20260805.py` 17 断言全过(Σc=3/c≥0/coverage direct 5/c 降序/最高=A、vs_top_n EBV 相当+kinship_reduction 0.0398+kinship_quad≈4.641、λ↑→avg_kinship 单调非增 [1.0→0.5157→0.3211→0.2685]、λ=0 满额投最高 EBV 单亲、kinship_status=partial+告警 D/E、三 409)+ `e2e_mabc_20260805.py` 23 断言全过(前景 5 pass/1 fail、背景恢复 100/75/75/0 复算、晋级 BC2/再回交 BC1/前景未通过 reason、recommended 恢复率降序 [100,100,100,75,0]、童期 C6 被前景选中、轮回亲本无基因型 warning+None、六 409)+ 回归 molrigor/gwas/mating_kinship/mating_ebv/gblup_cv/statsflow/spatial/busflow/批次/底座 全套零回归 + vue-tsc EXIT=0 + 后端重启 HTTP 核验 ocs/mabc-progress(200 结构 + 409 门禁);`_DATA_VERSION` v2.24 |
|
||
| v2.21 | 2026-08-05 | **ΔG 投影假设声明 + 工程健壮性打磨(用户报告两点均非功能 bug,核实确认 + 拍板落地,e2e 验证通过,§8.31 / `桃育种系统统计引擎实施记录.md` §18.9)**:① **ΔG 投影假设显式声明**——`genetic_gain` 旧实现 `next_pheno_mean = pheno_mean ± dg` 隐含「环境均值恒定」,若年际气候漂移投影会偏;属投影演示性质,返回体新增 **`note` 假设声明**(投影假设环境均值恒定、未计入年际气候漂移与栽培措施变化;ΔG=k·r_g·σ_A 仅含遗传增益分量,next_pheno_mean 为投影演示值而非实测预测),前端 gain tab 展示 info alert;② **空间模型缺坐标优雅降级**——`run_ablup(spatial=True)` 旧实现任一观测树缺 row/col 即整批 ValueError 409,现改为**剔除缺坐标株的表型(保留系谱 → EBV 仍由系谱预测),仅当全部观测树都缺坐标才整批 409**,剔除数显式写入批次 note「缺坐标剔除N株表型(EBV由系谱预测)」;③ **numpy 工程清理**——`data_quality_report`/`genetic_gain` 及另 5 处函数体内重复 `import numpy` 收敛为模块级单次导入;`data_quality_report` 逐株 flag 循环改 numpy 布尔掩码向量化(输出逐字节不变)。验证:spatial 探针新增强健降级场景(5 株含 1 株缺坐标 → method=AR1×AR1/train_n=4/note 含剔除标注/5 株均有 EBV 行)+ 全缺坐标整批 409 门禁 + A6 探针 [2] note 断言(含「环境均值恒定」)+ 回归 spatial/A6/亲缘/批次/底座五套零回归 + vue-tsc EXIT=0 + HTTP 核验 genetic-gain 返回 note、data-quality 返回 direction 经真实端点 |
|
||
| 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 结构化表单)、统计可视化 ECharts(correlation 热图 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(1−p_j))、Var(ê)=σ²u/(2Σp_j(1−p_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⊗A(G0 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 + status,CRUD +「查看性状值」跳 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_code(YY+3位)/tree._gen_tree_no(组合-序号)/selection_result clone_code(组合-{:04d} 扩位)/seedling batch_no(YP-…))⑥ 超期预警定时任务(每日 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/miappe,BrAPI 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·σ_A,k 经 Acklam 有理近似 Φ⁻¹ 纯 numpy、r_g=批次 PA、σ_A=√h²·σ_P,逐轮投影);A6 主动选配 `POST /statistics/mating-recommend`(S-等位硬过滤 + 亲缘 A 惩罚 score=w_ebv·mid_parent_EBV−w_kin·max(0,r−threshold),不落库);**批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.22,e2e 验证通过)**:**④ 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`(String32,Sf=自交亲和型)+ `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.20,e2e 验证通过)**:`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→LSD(t_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. 新增模块(P0–P2,含 v1.3 复审补入)**
|
||
| 模块 | 表名 | BrAPI 映射 | 优先级 |
|
||
|---|---|---|---|
|
||
| trait(性状字典) | breeding_trait | ObservationVariable | P0 地基 |
|
||
| observation(plot/物候观测) | 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.9,G×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.15,treatment 多对多落地) |
|
||
| 分子基因型层 | 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.1(EBV 持久化)/ 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**:受控词表方法 URI(Crop 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.9,2026-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.6(B8)**:本系统 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) | 取值见 §9(rcbd/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) | 取值见 §9(project/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.0:clone 级晋升,取代原 germplasm 级**)。
|
||
|
||
### 3.9 breeding_environment_condition(环境因子,P1,G×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 最小前 N,desc 取最大前 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 / Bayes(V1.1 先填 ABLUP,GS 类 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(试验因子/处理,P1,v1.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(定植-处理关联,P1,v1.6 落地 A3)
|
||
> **背景(A3,v1.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 gate,P0,作用在 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_id,F4**) | 去重(保留最新 / 人工选择) |
|
||
|
||
> **(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_rootstock,v2.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_rootstock,v2.2/A3)、**germplasm_id(int FK→breeding_germplasm,晋升时回填、定植时留空,禁手填;v2.0:定植即定 clone,germplasm 仅当 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,派生自 planting,BLUP block 效应来源)** | **clone 聚合锚点(R1 修正:tree 必带 clone_id,EBV 经 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_clone,v2.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.3–v1.5 补全)**:`tree.trial_study_id`(**v1.5 仅记「定植所属 study」**,派生自 planting)+ `tree.block_no`(区组随机效应)+ `trial_study.block_count` + **`trial_study_entry`(entry_number 设计矩阵聚合键)** + **`treatment`(factor×level,v1.5 提进一期,支撑 split_plot 等因子效应)** 提供完整试验设计维度;跨年/跨点观测经 `observation.trial_study_id + obs_year` 表达(树自身不跨 study)。`site` 经纬度/海拔支持 **空间 BLUP(sommer 空间项)**。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.6,A6 / v2.0 修订)**:同一 clone 经扩繁产生多株 tree,其表型是同一基因型的重复观测;统计前按 `tree.clone_id`→`breeding_clone` 聚合为 clone 重复(**v2.0:取代原 `tree.germplasm_id`→germplasm 级聚合**),EBV 随机效应估在 `breeding_clone` 级(`clone_id`),避免自由度虚高。
|
||
8. **系谱 A 矩阵(v1.6,B9 / 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.6,B10 / 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/lme4)fixed 公式、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 selection,v2.0)
|
||
| 分期 | 内容 | 阶段 |
|
||
|---|---|---|
|
||
| 童期采集 | `trait.stage=juvenile` 性状采集(tree 视角,2–3 年) | **一期必做** |
|
||
| r_G 早选模型 | 基于遗传相关 r_G 的早选(童期性状预测评价段性状) | 排**二期** |
|
||
| 一期过渡 | 用历史"晋级/淘汰"标签训练**监督分类器(过渡)** | 一期 |
|
||
|
||
### 5.z 模型健康监控(v2.1,R4)
|
||
> "模型还准不准"的命门。每次 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_factor(MIAPPE 受控试验因子,先用 field_operation 近似)、breeding_program 顶层(BrAPI Program,target 暂代)** |
|
||
| **批量表型导入(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/accession(germplasm)被命名扩繁。需 `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 Program,target 暂代)。
|
||
- 字段细化:`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` + 显式 FK(v1.3);`tree_photo.observation_id`;统一编号生成服务。
|
||
- 物候期仍走 `observation`(时序,非固定列);系谱树仍靠 `cross_combination.parent_combination_id` 自链 + 前端树图。
|
||
|
||
### 8.4 长表决策详述(对应 §4 tree_evaluation,v2.2/F1 改写)
|
||
**结论:单一长表(废弃"混合固定列")。** v1.0–v2.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.3,2026-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 多态反模式** | 改显式可空 FK(tree_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.4,2026-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.5,2026-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.6,2026-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.15,planting×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_value(EBV 阈值) |
|
||
| 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.7,2026-07-28)
|
||
|
||
用户要求评估《桃育种数字化项目方案书_V2.11》中「统计分析与决策支持」(专册 2.1–2.8 方法 / 3.1–3.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 深度复审 A–H 全量落地(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;异常→pending;normal+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.3,2026-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/ABLUP,SUCCESS/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.4,2026-08-04,代码级)
|
||
|
||
> 用户田间刚需:桃花期仅 3–7 天,父本花粉是杂交季命脉,原授粉表无花粉采集/贮藏/活力/窗口,复盘坐果率无抓手。本轮新增 `breeding_pollen`(§3.19)+ 授粉表 `pollen_lot_id`/`pollination_method`,e2e 验证通过。完整明细见 `桃育种系统统计引擎实施记录.md`。
|
||
|
||
| 规格点 | 落地 |
|
||
|---|---|
|
||
| 新表 `breeding_pollen` | `weld_pollen.sql` 幂等 DDL(CREATE 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×tester(NCII)设计时 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=0,SCA=line×tester 互作=残差);NCIII 同模型但门槛 tester 恰 2 个 |
|
||
| 可辨识性 | tester 列从索引 `1+n_l` 起 → **显式列选择**(非连续切片);基线列切出后吸收剩余列 |
|
||
| 顺序 ANOVA | SS_line(intercept→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 分支;角色重叠 gate;create/update 校验含中文标签归一化;commit 后跨会话持久化)+ `vue-tsc` |
|
||
|
||
### 8.15 统计严谨·预测完整性与 MLOps 复现性落地台账(v2.7,2026-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.8,2026-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 保 fresh(F2 决策:统计管线用普通 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%、其余全 NULL;commit 后跨会话读同值。**注**:首跑清理阶段 FK 崩(helper flush 前取 `.id` 拿到 None),修 flush 顺序后全过 |
|
||
|
||
### 8.17 精修项四连发落地台账:DUS 数据能力 + stage 感知 + k-fold CV + 公平性报告(v2.9,2026-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 9,observation 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~10,ABLUP 与 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_mean−grand_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 开关+批次+折明细)与「公平性报告」tab(prediction+threshold_sd+site 偏差表+一致性表)、指数/决策对话框加 stage 三态下拉 + `stage_warning` ElAlert;`vue-tsc` 通过 |
|
||
| 验证 | `e2e_refine_20260804.py` 4 组全过:DUS 三表 CRUD + TG/53 种子命中 + FK/唯一键/子表阻断/软删 409 全路径;stage(selection_index 无过滤警示 + 过滤只含该阶段 + decision_preview 异阶段跳过 + ABLUP stage 落库);CV(ABLUP k=3 sire 家系留出折 pearson=0 为设计预期 + GXE k=2 跨 site + 幂等重跑新批次 + 溯源/任务状态);fairness(2 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.10,2026-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⊗A(G0=[[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) 组装 G0,Higham 特征值截断投影半正定;落 `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 块公式构造完整 H(H=A+[[A12·A22⁻¹·D·A22⁻¹·A21, A12·A22⁻¹·D],[D·A22⁻¹·A21, D]],D=G−A22),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);落 PredictionModel(method=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=\|b−1\|≤2·se_b`(**完美拟合残差≈0 时 se_b 无信息量 → b≈1(≤1e-6)判稳**,修复前浮点 b 永不精确=1 误判不稳);`ammi` 两因素 μ+g+e 分解→残差 SVD(np.linalg.svd)→IPC 得分/ASV(Purchase 2000,IPC1 按 SS 比例缩放合成)/Wricke ecovalence/ipc_variance,rank 按 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+schema(create/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 表)三 tab,ABLUP 运行对话框加 stage 三态(全部/童期/成株),Smith-Hazel 对话框加 g 矩阵来源 radio(Calo/MT-BLUP),预测批次表加「当前版本」标签+漂移检测/自动重训/设为当前版本按钮;`dus/index.vue` DUS 测试行加「特异性判定」按钮→对话框(alpha+参照默认同点+逐描述符结果表+建议)→「应用判定」写 conclusion;`vue-tsc` 通过 |
|
||
| 验证 | `e2e_advanced_{stability,stage,mtblup,gblup,dus,mlops}.py` 6 组全过:stability(FW b=2.0/1.0/−0.0 flag=F/T/F、AMMI 9 格 IPC1≥IPC2 rank 升序、year 维度、非法 methods 409、list/detail);stage(juvenile/evaluation 各只含对应观测树、不传含全部+note 警示、非法 stage 409);mtblup(r_g>0.3 对称、σa 对角>0、h²∈(0,1)、n_common=4、Smith-Hazel g_method=mtblup g_source 落库);gblup(GBLUP 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_result)create_all,weld_advanced.sql 幂等;清理自动执行 |
|
||
|
||
---
|
||
|
||
### 8.19 田间试验精度补强·砧木×接穗随机互作落地台账(v2.11,2026-08-04,代码级)
|
||
|
||
> 用户核实两条田间试验设计精度缺口——无 R 侧空间协方差(行-列 AR1×AR1)、无 scion×rootstock(G×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 不可辨识」409,p_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.12,2026-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/2,SSR 片段编码(`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=genotyped(G 行序)、relmat_inv=G⁻¹(奇异回退 pinv)、zmat_full=G;`method=ssgblup`:`_build_h` → individuals=order、relmat_inv=H⁻¹、zmat_full=H;cand=genotyped∩phenos,`len(cand)<2` → 空 folds + warning;**折划分固定种子随机分层**(round-robin,GS 同世代样本无系谱家系树,区别于 ABLUP 的 sire 家系留出,文档明示);逐折掩蔽留出:train_phenos=phenos−test_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 radio(ABLUP/GS)**:GS 模式显示基因型数据集下拉(复用已加载 `gbDatasets`)+ method radio(GBLUP/ssGBLUP)+ MAF≥ 输入,**隐藏 G×E 控件**、辅助文案分支「掩蔽留出 GEBV vs 表型 pearson(实证预测能力,固定种子随机分层)」;`submitCv` 按 mode 组装 payload(GS 传 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` 需冷量(h,0-3000)+ `heat_requirement` 需热量(GDD,0-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 input,placeholder 提示 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.14,2026-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=n−n_pc−2,正则不完全 beta);**多重检验**=Bonferroni 阈值 + BH-FDR q(numpy argsort);**QTL 定位**=显著(Bonf)标记同染色体相邻间距 < qtl_window 合并簇、簇内最小 p 为峰标记(单显著标记也落 QTL);**共线兜底**:标记与 PC 共线时 XtX 奇异,微小岭回归(reg=1e-8·max(diag))令 SE 大而有限→p≈1(效应被 PC 吸收正确非显著),**不误吸与群轴正交的 QTL 标记**;method 参数预留 ssgwas(MLM 留待) |
|
||
| 数据装配 | `_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/effect,UNIQUE(panel,marker))——`statistics/model.py` ORM + `backend/sql/weld_gwas.sql` 幂等 CREATE IF NOT EXISTS 双保险 |
|
||
| 服务端端点 | `POST /statistics/gwas/run`(job_type=GWAS,input_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_window;sys_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/MK1(source=gwas 落库)④ 已知 QTL CRUD(source=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.15,2026-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` 逻辑 + 变异系数 + **IQR(Q1−1.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²·σ_P(h²=`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,r−threshold)` 排序 top N;输出 `{pairs:[{female, male, ebv_mean, r, s_compat, score, flags}]}`;**计算端点不落库**(用户拍板) |
|
||
|
||
**批2 分子侧严谨性(solver 扩展,独立路径)**
|
||
|
||
| 缺口 | 落地 |
|
||
|---|---|
|
||
| B1 EMMAX | `gwas.py` 新增 `_emmax`:**零模型** y=Xβ+u+e,u~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=M−2p_a、scale 分母 2Σ_all p_a(1−p_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**=同组内全部命中才计 1;decision_preview marker 条件沿用 n≥min_hits 语义自动透传;前端面板标记编辑器加三控件 |
|
||
|
||
**批3 求解器核心(高风险,独立新路径)**
|
||
|
||
| 缺口 | 落地 |
|
||
|---|---|
|
||
| A2 AR1×AR1 空间协方差 | `blup.solve_spatial`(`ENGINE_VERSION` 1.3.0):y=Xb+Zg+e,e~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² 落批次 note(NA 安全 `_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·v,max_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=1−PEV/σ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_gwas(7 段)/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(1−p_j))`、`Var(ê_j)=σ²u/(2Σp_j(1−p_j))`;Wald `t=ê/SE`、df=n−2 → `fdist.f_pvalue`;**共享 `_finalize`/`_bh_qvalues`/`_cluster` 后处理**(GLM/EMMAX 逐字节不变);门禁:无基因型样本→报错、G⁻¹ 岭兜底;服务端 `method` 透传 ssgwas(schema 已留)+ 前端 gwas 运行对话框 method 下拉加 ssgwas |
|
||
| ② 全 MT-BLUP | `mtblup.py` 1.1.0 新增 `solve_multi`(现状 `solve_bivariate` 单对双性状、Va/Ve 取单性状 REML 仅 ρ 一维):m 性状 y 堆叠、X/Z 块对角、Var(u)=G0⊗A(G0 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_by)CRUD + `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/status,create_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=false;operator_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_code(YY+3位)、tree._gen_tree_no(组合-序号)、selection_result clone_code(组合-{:04d} 扩位)、seedling batch_no(YP-…);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/scale,scale.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 组 PASS(ssgwas 复现已知 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.17,2026-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_code(single_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`,幂等):产量构成 5(single_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 落叶期)+ 品质 3(ss_content 可溶性固形物 % / titratable_acid 可滴定酸 % low / ss_acid_ratio 固酸比)+ 生长量 3(trunk_circumference 主干周长 cm / tree_height 树高 m / crown_width 冠幅 m)+ 描述性 categorical 5(fruit_shape 果形 / pubescence 茸毛 / freestone 离核 / ground_color 果皮底色 / coloring_type 着色类型,into_ebv=0);category 产量构成/物候/果实品质/生长量/果实外观 + default_h2/direction |
|
||
| A3 种质级观测 | `bre_observation` 加可空 `germplasm_id`(FK→bre_germplasm,weld 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_lot,weld SQL ALTER);前端 seed_lot 授粉选择器(按 combination 过滤)、seed_treatment 种子批次选择器 |
|
||
| A5 EAV 观测校验 | observation + trait_observation create/update:obs_type=numeric → obs_value 可 parse float、obs_type=date → 可 parse 日期,否则 409;trait 有 `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.generation;child_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,0−thr)=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_gain(A6,r=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·mid−w_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.0(n_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_gain(A6 无 Prediction 行 → 全 missing → 排序不变)/ e2e_mating_kinship(ok=14)/ e2e_batch_selection / e2e_gaps_base(19 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_kinship(ok=14)/ e2e_batch_selection / e2e_gaps_base(19 ok)全过零回归。**HTTP 核验**:后端重启后 `POST /bre/statistics/data-quality` 对 asc 裂果率(bB_DIR5668)与 desc 果重(dA_DIR5668)两真实性状返回 `direction`/`extreme_candidates`/`outliers`/`summary.n_extreme_candidates` 全部正确——真实数据无极端偏离 → 双表空(**无误报**)。
|
||
|
||
### 8.31 ΔG 投影假设声明 + 工程健壮性打磨落地台账(v2.21,2026-08-05,代码级)
|
||
|
||
> 用户报告两点,均**非功能 bug**、核实确认后拍板落地:① `genetic_gain` 的 `next_pheno_mean = pheno_mean ± dg` 隐含「环境均值恒定」假设,年际气候漂移会使投影偏;② 工程健壮性细节(spatial 缺坐标整批失败无优雅降级、numpy 重复导入/未向量化)。
|
||
|
||
**修复**(`statistics/service.py` + `statistics/index.vue`):
|
||
|
||
- **① ΔG 投影假设显式声明**:`genetic_gain` 返回体新增 **`note`**——`投影假设环境均值恒定(未计入年际气候漂移与栽培措施变化);ΔG=k·r_g·σ_A 仅含遗传增益分量,next_pheno_mean 为投影演示值而非实测预测。`note` 为静态常量(同性状/同数据不变,探针断言稳定)。前端 gain tab 在描述区后、轮次表前展示 `el-alert type="info"` 提示假设边界。
|
||
- **② spatial 缺坐标优雅降级**:`run_ablup(spatial=True)` 坐标收集循环把 `row_no/col_no` 为空的观测树记入 `missing_coord_ids`,**剔除其表型但保留系谱**(EBV 仍由系谱预测,`blup.solve_spatial` 本就对所有个体输出 EBV);剔除数显式写入批次 note「缺坐标剔除N株表型(EBV由系谱预测)」;**仅当全部观测树都缺坐标(coords 空)才整批 409**(提示先在单株录入填行号/列号)。`input_hash` 随剔除后的表型子集计算(同数据可复现)。
|
||
- **③ numpy 工程清理**:`data_quality_report`/`genetic_gain` 及另 5 处函数体内重复 `import numpy` 全部收敛为**模块级单次** `import numpy as np`(service.py:24);`data_quality_report` 逐株 flag 循环改 **numpy 布尔掩码**(`np.where(mad>1e-9, 0.6745·(a−med)/mad, 0)` / `(a<q1−1.5iqr)|(a>q3+1.5iqr)` / `|z|>3.5`)一次性定位命中株,输出逐字节不变。
|
||
|
||
**验证**:`Temp/claude/e2e_spatial_sparse_20260804.py` **降级场景断言全过**——5 株(前 4 株 2×2 网格带坐标 + 第 5 株 `row_no=None`)观测 [10.0,10.5,11.0,11.5,9.0]:method=AR1×AR1、`train_n=4`、note 含「缺坐标剔除1株」、**5 株全部有 EBV 行**(缺坐标株系谱预测);全缺坐标场景仍整批 409 且报错说明 row_no/col_no 需求。**A6 探针 [2]** 新增 note 断言:`note` 含「环境均值恒定」且两性状稳定不变。**回归**:e2e_spatial_sparse / e2e_data_mating_gain / e2e_mating_kinship(ok=14)/ e2e_batch_selection / e2e_gaps_base(19 ok)五套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/genetic-gain`(真实性状 dA_DIR5668)返回 `note`(含「环境均值恒定」);`POST /bre/statistics/data-quality` 返回 `direction: asc` 且双表空无误报。
|
||
|
||
### 8.32 A–F 六项功能级缺口·批1 父本验证 + 近交衰退落地台账(v2.22,2026-08-05,代码级)
|
||
|
||
> 用户全模块 grep 实证 A–F 六项**功能级缺口**(均有/深度问题,非正确性 bug),本会话逐项 grep 复核全部成立后拍板「**全部六项分批落地**」。批1 = A 父本验证 + C 近交衰退(小快,纯校验 + 数据侧既有);批2 = B GS 家系 CV + F 试验设计深度;批3 = D OCS + E MABC。
|
||
|
||
**A 父本验证**(consistency,不落库,`pollination`/`tree`/`cross_combination` service):
|
||
|
||
- **A1 pollination 花粉来源父本一致性**(`pollination/service.py` 新增 `_validate_pollen_parent`,create/update 统一在 `_validate_pollen_window` 后调用):取 `pollen_lot.male_tree_id`——批次声明采集父本树时,授粉声明 `male_tree_id` 须与之相同,否则 409「花粉批次 {lot_code} 采集自父本树 {X},与授粉声明父本树 {Y} 不一致,请确认花粉来源」(父本树名取 `tree_no` 兜底 `#id`);**批次无采集父本(混合/外地采集)或授粉未声明父本 → 放行**,不武断拒绝。
|
||
- **A2 tree 显式亲本 vs 组合父母本警示**(`tree/service.py` `_resolve_parents` 签名改返回 `(dam, sire, warning)`):显式 dam/sire 与组合 female/male_parent 不一致时聚合 warning「显式母本与组合母本不一致;显式父本与组合父本不一致(以显式为准)」(单侧仅报该侧);**warning 不阻断**(tree 可独立建,武断 409 会误伤);`tree/schema.py` 加只读 `warning: str | None` 字段(仅返回体,不落库),create/update 返回体均带。
|
||
- **A3 cross_combination 同质自交门禁**(`cross_combination/service.py` `_check_parent_roles` 中,角色解析后追加):`female_parent_id == male_parent_id` → 409「母本与父本同为「{名}」,自交组合请确认」;create 经 `_check_parent_roles(data.female_parent_id, data.male_parent_id)`、update 经生效亲本 `eff_female/eff_male` 统一触发(同亲本必共享全部 S-等位,与既有 `_check_s_compat` 409 语义一致不冲突)。
|
||
|
||
**C 近交衰退分析**(计算端点不建表,`statistics/service.py` + `statistics/schema.py` + `statistics/controller.py`):
|
||
|
||
- **`POST /statistics/inbreeding-depression`**(`InbreedingDepressionIn`:trait_id/trait_code 必填 + year/trial_study_id 可选 + min_n=10)——`inbreeding_depression` 方法:构造 tree 系谱(`t{tree_id}` 个体 + `g{germplasm_id}` founder)→ `blup.relationship_matrix` 取 F=A_ii−1;**关键:`inbreeding` dict 仅含 F>0,非近交树必须从 `individuals` 默认 F=0 兜底**,否则非近交株被排除出回归;trait 树级表型 `select(obs.tree_id, func.avg(value_numeric)).group_by(tree_id)` 聚合(可选按 year/trial_study_id 过滤)→ 取交集树 → **纯 numpy `np.linalg.lstsq` 线性回归 phenotype ~ F**。返回 `{sufficient, reason, n_obs, mean_F, max_F, direction, regression:{intercept, slope, r2, t_slope, depression_rate, has_depression, interpretation}, high_inbreeding:[{tree_id, tree_no, F, value}]}`;`has_depression = slope<0 且 t_slope≤−1.645`(单侧 95% 大样本近似,负=近交使表型下降);`high_inbreeding` 按 F 降序取前 10(并列取 value 降序),现场核查;**n<min_n 优雅降级** `sufficient=False` + reason「同时具备系谱近交系数 F 与表型的树仅 {n} 棵(需 ≥{min_n})」+ regression/high_inbreeding 为 null/[](不 409)。
|
||
- **前端**「亲缘/近交」tab 加「近交衰退(F → 表型)」区:trait select + year input + 运行按钮;`el-alert`(insufficient=warning / has_depression=error / 无衰退=success)+ `el-descriptions`(n_obs/slope/r2/t_slope/depression_rate/mean_F/max_F/direction)+ `high_inbreeding` 表(tree_no/F/value)。**注意 el-alert `:type` 合法值 primary/success/warning/info/error,无 danger**(index.vue 667 曾因 `'danger'` 致 vue-tsc TS2322,改 `'error'`)。
|
||
|
||
**验证**:
|
||
|
||
- `Temp/claude/e2e_parent_validation_20260805.py` **10 断言全过**——A1:批次采集父本(male_tree)≠授粉父本(other_tree) → 409 含「不一致」;一致 → 放行;混合批次(无 male_tree_id)→ 放行;update 把一致授粉改不一致 → 409。A2:双侧显式 fm2/mm2 vs 组合 fm/mm → warning 含双侧「不一致」+「以显式为准」、dam/sire=显式;单侧 sire 偏离 → 仅「显式父本…」;显式一致 → warning=None;update 显式偏离 → warning。A3:create female==male → 409 含「自交」;update 生效亲本同质 → 409。
|
||
- `Temp/claude/e2e_inbreeding_depression_20260805.py` **4 断言全过**——12 树(6×F=0 dam≠sire + 6×F=0.5 自交 dam==sire):衰退性状 y=100−60F+ε → sufficient/n_obs=12/slope≈−60/t 显著负/r²>0.9/has_depression=true/depression_rate<0/max_F≈0.5/mean_F≈0.25/high_inbreeding 前 6 全为 S-自交 F=0.5、后 4 F=0;无衰退性状 y≈100 → slope≈0/has_depression=false/「未检出」;min_n=20 → sufficient=false + reason 含「12 棵」「≥20」;trait_id=99999999 不存在 → 409。
|
||
- **回归**:e2e_spatial_sparse(v2.22 断言同步)/ e2e_statsflow / e2e_data_mating_gain / e2e_mating_kinship / e2e_batch_selection / e2e_gaps_base 六套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/inbreeding-depression`(真实稀疏数据)返回 code=0、sufficient=false、n_obs=2、reason「同时具备系谱近交系数 F 与表型的树仅 2 棵(需 ≥10)」、mean_F/max_F/regression=null、high_inbreeding=[]。
|
||
|
||
`_DATA_VERSION` v2.22(`statistics/service.py:95`)。
|
||
|
||
### 8.33 A–F 六项功能级缺口·批2 GS 家系 CV + 试验设计深度落地台账(v2.23,2026-08-05,代码级)
|
||
|
||
> A–F 六项缺口批2 = **B GS 家系 CV**(深度:随机分层 → 家系阻塞折)+ **F 试验设计深度**(RCBD 生成 + 设计基 ANOVA)。沿用工程模式:独立 e2e 探针(真引擎直跑)+ 全量回归零回归 + vue-tsc EXIT=0 + 后端重启 HTTP 核验。
|
||
|
||
**B GS 家系 CV**(`scripts/breeding_stats/genomic.py` + `statistics/service.py` + 前端):
|
||
|
||
- **引擎** `genomic.kfold_cv_genomic` 加 `split: str = "random"` + `family_of: dict[str, str] | None = None`:`split="random"` → 现有 round-robin 随机分层**逐字节不变**(回归零变化);`split="family"` → 照 `blup.kfold_cv` 的 sire 家系留出模式——`fam_of = {ind: (family_of or {}).get(ind, ("self", ind))}`(无家系个体自成一族)→ 家系去重 `fams` → `rng.shuffle(fams)` → `fam_bin = {f: i % k}` → `bin_of = {c: fam_bin[fam_of[c]]}`,**同家系个体同折**(防亲缘泄漏高估准确度);**家系数 < 折数 k → 折叠为 n_families 折 + warning**「家系数 {n} < 请求折数,折叠为 {k} 折(family-blocked)」;**单家系(n_families<2)→ folds=[] + warning**「可验证个体仅构成 1 个家系,无法家系阻塞交叉验证(请改用随机分层)」。输出加 `n_families`(与 blup.kfold_cv 逐键对齐)。
|
||
- **服务** `run_cv` 加 `split="random"|"family"`(controller/schema 透传,job params_json 记 split):GS 分支 `split=="family"` 时用既有 `ped_rows`(select 顺序 id/dam_id/**sire_id**/trial_study_id/rootstock_id/female_parent_id/**male_parent_id**/combination_id/clone_id/germplasm_id)构建 `family_of = {f"t{tid}": f"s{s}"}`(`s = sire if sire is not None else cm`,sire 缺失回退组合 male_parent,两者皆空则缺省自成一族)传入引擎;落库 `CvResultModel.note` 记 `split=family · n_families={N}`(+ 引擎 warning 拼接)。
|
||
- **前端**「交叉验证」tab runCv 参数区加 split 下拉(random=随机分层/family=家系阻塞)+ 结果表显示 n_families。
|
||
|
||
**F 试验设计深度**(`trial_study_entry/model.py` + `sql/weld_trial_study_entry.sql` + `statistics/` 三件 + `anova.py` + 前端):
|
||
|
||
- **F1 RCBD 生成器**:`bre_trial_study_entry` 加可空 `block_no integer`(`model.py` 列 `block_no: Mapped[int | None]` + `weld_trial_study_entry.sql` `ALTER TABLE ... ADD COLUMN IF NOT EXISTS block_no integer`,SQLAlchemy create_all 只建新表故 weld 幂等兜底,psql 应用后 `\d` 确认);新端点 `POST /statistics/trial-design`(`TrialDesignIn`:trial_study_id + design_type="rcbd" + seed 可选;`StatisticsRouter.post("/trial-design")` 权限 module_bre:statistics:create)——`trial_design` 方法:`db.get(TrialStudyModel)` 409 缺、design_type≠"rcbd" 409、block_count=study.block_count or 1、按 entry_number 有序取参试条目(空 → 409「无参试条目」)、`random.Random(seed)` 洗牌 + round-robin 分进 block_count 区组(均分 + 组内随机顺序 = 田间布局)、`update(TrialStudyEntryModel).values(block_no=case(block_of, value=TrialStudyEntryModel.id, else_=None))` 批量落库 + flush;返回 `{trial_study_id, design_type, block_count, seed, n_entries, blocks:{str(b): [entry_number…]}}`。
|
||
- **F2 设计基 ANOVA**:`anova.solve_rcbd(rows)`(rows=`{"group","block","value"}`)RCBD 双因素 **Type I 顺序**(X1→Xg→Xgb dummy 设计矩阵:SS_group=rss(X1)−rss(Xg)、SS_block=rss(Xg)−rss(Xgb)、SS_error=rss(Xgb),纯 numpy 零 scipy + `fdist.f_pvalue`),输出 n_groups/n_blocks/n/overall_mean/ss_total/ss_between(=ss_group)/ss_block/ss_within(=ss_error)/ms_between/ms_block/ms_within/sigma_g/sigma_e/h2_broad/f/p_value/f_block/p_block/groups/blocks/warning(<2 组合或 <2 区组 ValueError;df_error≤0 → warning「区组设计过饱和」);`anova.solve` 单因素**逐字节不变**。`run_anova` 加 `block: bool = False`:block=False → 原单因素路径不变(rows `{"group","value"}`);block=True → 查 `bre_tree.block_no` 组 rows(`{"group","block","value"}`)、过滤 block_no 为空株、<2 区组 → 409「区组数据不足:需 ≥2 个区组(请先运行 /statistics/trial-design 生成设计并落库 block_no)」,`solve_rcbd` 后 method=ANOVA/H2/RCBD。
|
||
- **前端** statistics ANOVA tab 重构:顶部「生成 RCBD 设计」工具条(trial_study el-select + seed el-input-number + warning el-button @click=submitDesign)+ 设计区组表(designBlocks:block/参试编号列)+ trait select + year + `el-checkbox anovaBlock`「RCBD 区组校正(bre_tree.block_no)」+ 提交;结果 el-descriptions 加 n_blocks/f_block/p_block 条件 v-if + 区组均值表(家系均值下)。`statistics.ts` 加 `trialDesign()` + `TrialDesignResult` 类型。
|
||
|
||
**验证**:
|
||
|
||
- `Temp/claude/e2e_trial_design_20260805.py` **5 组断言全过**——[1] RCBD 生成(block_count=3/n_entries=9/3 区组×3 条目均分/全部 9 条目齐全/seed·design_type 回显);[2] block_no 落库核验(紧随首次生成执行避免复现覆盖,落库区组集合 == 返回设计集合);[1b] seed=42 复现同一设计 / seed=43 得不同设计(random.Random(seed) 可复现);[3] block=False → method=ANOVA/H2、无 f_block/n_blocks/blocks 键、n_groups=3/n=9(单因素逐字节不变);[4] block=True → method=ANOVA/H2/RCBD、n_blocks=3、ss_block>0、f_block>1、p_block 存在、3 区组均值随 +3/0/−3 递减;[5] 无参试条目研究点 → 409「无参试条目」。
|
||
- `Temp/claude/e2e_gs_family_cv_20260805.py` **5 组断言全过**——[1] 5 家系×3 全同胞 k=3 → method=KFCV/GBLUP、note「split=family · n_families=5」、家系阻塞折 n_test=[3,6,6](2+2+1 家系同折);[2] k=5 → 每折恰 1 家系 n_test 全 3、无折叠 warning;[3] random k=3 → note 无 split=family、n_test=[5,5,5](随机分层回归零变化);[4] 引擎级 6 家系<请求 8 折 → 折叠为 6 折 + warning「折叠为 6 折(family-blocked)」;[5] 单家系 → folds=[] + warning「1 个家系」。注:探针树创建曾漏 `db.add_all([fm, mm])` 致 germplasm.id=None → 组合 female/male_parent_id 全空 → sire 全空 → n_families=15,补 add 后修正为 5。
|
||
- **回归**:e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_busflow / e2e_mating_kinship / e2e_gaps_base / e2e_molrigor 七套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启后 `POST /bre/statistics/trial-design` + `POST /bre/statistics/anova/run`(block=true)经真实端点返回。
|
||
|
||
`_DATA_VERSION` v2.23(`statistics/service.py:97`)。`genomic.ENGINE_VERSION` 1.3.0(批2-B,函数扩展不升主版本;aniso 空间双参此前已 1.4.0,与 run_cv 无耦合)。
|
||
|
||
### 8.34 A–F 六项功能级缺口·批3 OCS 最优贡献选择 + MABC 标记辅助回交落地台账(v2.24,2026-08-05,代码级)
|
||
|
||
> A–F 六项缺口批3 = **D OCS 最优贡献选择**(群体配种贡献联合优化)+ **E MABC 标记辅助回交**(前景+背景选择工作流)。批1(A 父本验证 + C 近交衰退,v2.22 §8.32)与批2(B GS 家系 CV + F 试验设计深度,v2.23 §8.33)已落地;本批为 A–F **六项闭环收官**。沿用工程模式:独立 e2e 探针(真引擎直跑)+ 全量回归零回归 + vue-tsc EXIT=0 + 后端重启 HTTP 核验。两端点均**纯计算不落库**(对齐 data_quality 惯例)。
|
||
|
||
**D OCS 最优贡献选择**(`statistics/service.py` + controller/schema 三件):
|
||
|
||
- **共享 helper 抽取 `_candidate_ebv_map`**(`service.py:3429-3531`):`mating_recommend` 内联 EBV 解析块**原样抽取**为 `(prediction, tree_ids) → {germplasm_id → ebv}`(prediction batch ABLUP/GXEBLUP/GXRBLUP/GBLUP/ssGBLUP;direct germplasm_id 先取,缺失走 progeny 子代均值并 `_EBV_SOURCE_FACTOR={direct:1.0, progeny:0.5, missing:0.0}` 降权;返回 `ebv_map/source/status/warning/cover/n_progeny/n_combos/ebv_mid`)。**「双亲均缺直接 EBV → 子代树剔除(双侧去重)」规则随抽取原样保留**——已在抽取前内联块存在,属 v2.19 方法论延续,非抽取回归(`e2e_mating_ebv` [4] P3×P4=0.0 权威验证;`e2e_audit_fix_20260804` ④ 已同步该语义)。
|
||
- **端点 `POST /statistics/ocs`**(`OcsIn`:candidate_germplasm_ids + n_select=5 + lam=0.1 + prediction_id 可选;`_proj_simplex` + `_solve_ocs`):**max Σc_i·ebv_i − λ·c'Ac,s.t. Σc=n_select、c≥0**(纯 numpy 欧氏投影梯度 + 拉格朗日投影,无 scipy;候选数 <50 足够收敛)。A 由 `_germplasm_pedigree` 取系谱、`blup.relationship_matrix` 计算 rmat 组装(对角=1,非对角按候选对取 r)。输出:`contributions`(每候选 c 降序:germplasm_id/name/c/ebv/source + 可选 n_progeny/n_combos)、`mean_ebv`、`avg_kinship`(c'Ac)、`kinship_quad`、`vs_top_n{n,mean_ebv,avg_kinship,ebv_loss,kinship_reduction}`(同 n_select 贪心 top-n 对照,量化 OCS 亲缘控制价值)、`ebv_source/kinship_status/kinship_warning`(A 覆盖 <100% → kinship_status="partial" + warning「部分候选对缺少亲缘系数」)。门禁:空候选 / n_select>候选数 / λ<0 → 409。
|
||
- **前端**「选配推荐」tab OCS 运行区(候选种质多选 + n_select + λ 滑杆 + contribution 表 + vs_top_n 对比 + kinship_warning alert + 亲缘状态 tag)。
|
||
|
||
**E MABC 标记辅助回交**(`statistics/service.py` + controller/schema 三件):
|
||
|
||
- **端点 `POST /statistics/mabc-progress`**(`MabcIn`:candidate_tree_ids + foreground_panel_ids + background_panel_ids + recurrent_parent_tree_id + foreground_min_hits=1 + generation=BC1 + background_target=90):**前景选择**复用 `_mas_hit_map`/`_mas_marker_hit`(additive/dominance/recessive/allele/haplotype 五语义,stage 无关、童期幼苗即可筛选),`foreground_pass` = 有利剂量命中 ≥ `foreground_min_hits`;**背景基因组恢复率**对 background_panel 每标记取候选 vs 轮回亲本「**纯合剂量一致**」比例(`_pure_homologous`:候选纯合且有利等位 ∈ 轮回亲本等位集;杂合不计),标记均值 = 基因组恢复率估计 %(round 2);**回交代建议**按 `_BC_LADDER=["F1","BC1","BC2","BC3","BC4","BC5"]` + `_MABC_GENERATIONS={"F1","BC1","BC2","BC3"}`:前景通过+恢复≥target → 晋级下一代(F1→BC1→…→BC5→自交固定);前景通过+恢复不足 → 再回交一代;前景通过+恢复无法评估(轮回亲本缺背景基因型)→ 补测后判定;前景未通过 → 维持 + 前景未通过提示。输出 per_tree{foreground_hits/by_panel/foreground_pass/background_recovery/n_background_compared/n_background_recovered/bc_generation/reason} + `recommended`(前景通过按恢复率降序,恢复率 None 排尾)+ summary{n_pass/n_with_recovery/mean_background_recovery} + warning(轮回亲本无背景基因型 / 背景面板无标记)。门禁:空候选 / 空前景或背景面板 / generation∉`_MABC_GENERATIONS` / background_target∉(0,100] / 轮回亲本树不存在 → 409。
|
||
- **前端**独立「回交 MABC」tab(前景/背景 MAS 面板多选 + 轮回亲本树单选 + 候选回交单株多选 + 前景阈值/当前世代/背景目标参数 + 逐株结果表 + recommended 恢复率降序表 + warning alert)。
|
||
|
||
**验证**:
|
||
|
||
- `Temp/claude/e2e_ocs_20260805.py` **17 断言全过**——[1] Σc=3(n_select)、c≥0、coverage=direct 5/5、c 降序排列、贡献最高=A;[2] mean_ebv 与 vs_top_n 相当、kinship_reduction=0.0398、kinship_quad≈4.641(OCS 以极小 EBV 损失换亲缘大幅下降);[3] λ 梯度 ↑(0→0.5→1→10)→ avg_kinship 单调非增(1.0→0.5157→0.3211→0.2685)且贡献越摊越匀;[4] λ=0 满额投最高 EBV 单亲(OCS 退化 = 贪心 top-n);[5] A 缺失 → kinship_status=partial + warning「部分候选对缺少亲缘系数」(D/E 均可触发);[6] 三 409(空候选 / n_select>候选 / λ<0)。**清理干净**(按 PREFIX 删 genos/samples/markers/datasets/panels/组合/亲本,e2e 前预清残留)。
|
||
- `Temp/claude/e2e_mabc_20260805.py` **23 断言全过**——[1] 前景 5 pass(C1/C2/C4/C5/C6)+ 1 fail(C3 前景 M1 0/0);[2] 背景恢复复算 100%(C1/C4/C6)/75%(C2)/0%(C5)n_background_compared=4;[3] reason(C1/C4 晋级 BC2 / C2/C5 再回交 BC1 / C3 前景未通过);[4] recommended 恰为前景通过子集、恢复率降序 [100,100,100,75,0];[5] 童期 C6 前景通过+晋级(stage 无关);[6] 轮回亲本无背景基因型 → 恢复 None + warning + 不阻断;[7] 六 409(空候选 / 空前景面板 / 空背景面板 / generation=BC2 非法 / background_target=0 / 轮回亲本不存在)。**清理干净**。
|
||
- **回归**:e2e_molrigor(复练 `_mas_hit_map`)/ e2e_gwas / e2e_mating_kinship / e2e_mating_ebv / e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_busflow / e2e_gaps_base / e2e_b8_seed_lot / e2e_prediction_rigor / e2e_audit_fix 全套零回归(`_candidate_ebv_map` 抽取后 mating_kinship 14/14、mating_ebv 与 audit_fix ④ 语义双核对)。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启(PID 更换)后 `POST /bre/statistics/ocs`(n_select=1 最小正例 200 结构)+ `POST /bre/statistics/mabc-progress`(空面板 409 / 非法 generation 409 / 成功路径 200 + 轮回亲本缺背景基因型 warning)经真实端点返回。环境性 b34(G1 门禁 sample 量)为探针脆弱非本批回归,e2e_g1_gate 独立通过。
|
||
- **方法学保留**:OCS 与 `mating_recommend` 逐对 kin-penalty 启发式**并存不冲突**(OCS 管群体层面「配多少」,mating_recommend 管配对层面「配哪对」);MABC 前景语义与 `decision_preview` marker 条件同源(童期幼苗可标记辅助选入)。
|
||
|
||
`_DATA_VERSION` v2.24(`statistics/service.py:97`)。`genomic.ENGINE_VERSION` 1.3.0(批3 复用 `_mas_hit_map`/`_candidate_ebv_map`,引擎函数零改动)。
|
||
|
||
### 8.35 近交衰退两处正确性修复落地台账(2026-08-05 跟进,代码级)
|
||
|
||
> 用户实证复查 `inbreeding_depression`(v2.22,§8.32)两处缺陷,本会话核实成立后修复:
|
||
> ① **方向盲目的衰退判据**——`has_depression = slope<0 且 t≤−1.645` 无条件取负斜率,对「越低越好」的 asc 性状(如病指)F↑→指标↑=恶化却误报「未检出」;
|
||
> ② **浅层近交系数**——系谱只取树级 dam/sire 把每个引用种质当 founder,未走深层系谱,多世代项目(半同胞共享祖亲)低估 F(OCS/mating 已用 `_germplasm_pedigree` 深层解析,故仅近交衰退分析受影响)。
|
||
|
||
**修复**(`statistics/service.py` `inbreeding_depression`):
|
||
|
||
- **① 方向感知检测**:读 `direction`(此前读了未用)得 `desirable_high = direction != "asc"`;高优性状(desc/None)衰退 = `slope<0 且 t≤−1.645`,低优性状(asc)衰退 = `slope>0 且 t≥+1.645`;`interpretation` 方向化——asc 衰退「F 每升 0.1,{trait} 表型平均**上升(恶化)** …%」/ 未达显著「斜率偏正…」/ 未检出「F 对表型无**上升(恶化)**影响」。对齐既有 `data_quality_report` 的 `desirable_high` 方向语义。
|
||
- **② 深层近交系数**:系谱构建改复用 `_germplasm_pedigree`(bre_pedigree 名称反查 + tree FK 兜底 + BFS 祖先展开,与 OCS/mating 同源)展开所有被引用种质的祖先,再补树节点 + 未解析种质 founder 兜底(软删引用不悬空)。多世代半同胞共享祖亲 → F 正确 >0,不再低估。
|
||
|
||
**验证**:
|
||
|
||
- `Temp/claude/e2e_inbreeding_depression_20260805.py` **6 组断言全过**(原 [1] 衰退/[2] 无衰退/[3] 样本不足 + 新增)——[4] **asc 病指**:12 树同 F 结构 y=10+40F → slope=+40、t 显著正、has_depression=true、文案含「上升(恶化)」、高近交前 6 仍为 F=0.5 自交株(旧判据误报未检出,修复后正确检出);[5] **深层系谱 F**:P→G7/G8(tree FK 升谱),6 候选树 dam=G7 sire=G8 半同胞近交 + 6 对照 F=0,desc 性状 y=100−60F → max_F=0.125、mean_F=0.0625(旧浅层=0 低估)、slope≈−61、has_depression=true、高近交前 6 全为 H 半同胞株;[x] trait 不存在 409 保持。
|
||
- **回归**:e2e_ocs / e2e_mabc / e2e_mating_ebv / e2e_mating_kinship / e2e_statsflow / e2e_spatial_sparse / e2e_gs_family_cv / e2e_trial_design / e2e_parent_validation / e2e_batch_selection / e2e_gaps_base / e2e_gaps_engines / e2e_gaps_modules 全套零回归(`_germplasm_pedigree` 本体零改动,仅消费方 inbreeding_depression 引用)。**vue-tsc** EXIT=0(前端仅提示文案方向化一行)。版本仍 v2.24(正确性修复不升版,避免批3 版本断言连锁)。
|
||
|
||
### 8.36 分子亲本验证(孟德尔一致性)+ 试验设计深度(增广 + α-格子)落地台账(v2.25,2026-08-05,代码级)
|
||
|
||
> 用户实证复查指出两处遗留缺口,本会话核实**全部成立**:① `genotype_call` 仅 `fingerprint_check`(无性系混杂/标签互换检测),对 **mendelian/parentage 零命中**——零孟德尔分离一致性检验、零亲本亲缘验证;② `trial_design` 仅 RCBD,增广/α-格子仍 TODO(docstring 明言留待后续)。α-格子范围用户已拍板:**平方格子(v=k²,闭式构造,平衡可证)+ 一般 v 贪心回退(balance_warning 诚实标注)**。
|
||
|
||
**批4-A:孟德尔/亲本一致性检验**(`genotype_call` 模块,`GET /bre/genotype_call/mendelian/check`,镜像 fingerprint/check 的 GET+Query 模式,纯计算不落库):
|
||
|
||
- **规则**:子代树样本基因型 vs 声明亲本(`tree.dam_id/sire_id`→germplasm)基因型——按标记解析等位(`_allele_set`,"/" 分割去空白/缺失),**子代等位集 ⊆ dam∪sire 等位集并集**即孟德尔兼容(union 规则);任一亲本该标记等位空白/缺失 → 非信息位点(不计分母);单株兼容率 = 兼容位点 / 信息位点数,`flag = rate < compat_threshold`(默认 0.98,对齐 fingerprint)。
|
||
- **数据解析(跨数据集)**:子代样本 `source_type=="tree"`(source_id→tree 集合);声明亲本两亲皆空 → `no_declared_parents`;亲本基因型取 `source_type=="germplasm"` 样本**跨数据集解析**(同数据集优先、否则其他数据集最低 id 兜底);亲本声明但无 germplasm 基因型样本 → `missing_parent_genotype`(**不 409**,数据现状,reason 标注缺哪个亲本);数据集无样本 → 零值返回。
|
||
- **输出**:`{trees_checked/trees_flagged/trees_no_parents/trees_missing_parent_genotype, summary{informative_markers/incompatible_markers}, trees:[{tree_no,dam,sire,status,informative_markers,compatible,incompatible,compatibility_rate,flag,incompatible_markers:[{marker_id,allele,dam,sire}]}]}`。
|
||
|
||
**批4-B:试验设计深度**(`trial_design` 按 `design_type ∈ {rcbd, augmented, alpha}` 分派;**rcbd 路径逐字节不变**,回归零变化):
|
||
|
||
- **augmented(增广)**:入参 `check_germplasm_ids` 显式对照(须为参试条目种质 id 子集,否则 409「对照种质不在参试条目中」;至少 1 对照 + 1 新品系否则 409)。对照每区组重复(anchors,`check_reps=block_count`)、新品系 `rng.shuffle` + round-robin 均分区组(同 RCBD 随机化、不重复);对照条目 `block_no` **不落库**(None)、新品系落 1..block_count。输出加 `checks:[{entry_number,germplasm_id}]`、`n_new_entries/n_checks/check_reps`。
|
||
- **alpha(α-格子)**:入参 `block_size=k` + `reps=r` 可选。v=条目数需 `v%k==0`(s=v/k=每重复块数)否则 409;k 缺省时 v 为完全平方自动取 k=√v,否则 409「α-格子需指定 block_size(当前 {v} 条目非完全平方)」;reps 缺省=平方时 k+1(完全格子)/ 一般时 s;r<2 → 409「重复数需 ≥2」。**平方 v=k² → 闭式格子**:`rng.shuffle` 打标 (x,y),rep m∈{0..k} 直线 y≡m·x+(b−1) mod k(m=k=竖列),完全格子 r=k+1 任一对至多同块一次 λ≤1;k 素数完全平衡(`_is_prime`),非素数 → `balance_warning=True` 保守告警(可分解不保证平衡);r>k+1 → 409「完全平方格子重复数最多 {r_full}」。**非平方 v → 贪心可分解构造**:逐 rep 贪心填 s 块×k,`used_pairs` 集避免同块对重复,卡死则余下允许复用 + `balance_warning=True`。`block_no` 写复合编码 **rep\*100+block**(rep 1..r、block 1..k)。输出 `{reps, block_size, balance_warning, blocks:{rep:{block:[entry_number…]}}}`。
|
||
- **探针抓出的真 bug**:平方分支 block_no 初版 `m*100+b`(0-based m)致 rep1 落库 1..3 与贪心分支/文档的 `rep*100+block` 不一致 → 修正为 `(m+1)*100+b`。
|
||
|
||
**验证**:
|
||
|
||
- `Temp/claude/e2e_mendelian_check_20260805.py` **8 断言全过**——数据设计验证**跨数据集解析**(子代样本 D1、亲本样本 D2、D3 空):G1/G2 亲本基因型各 5 标记、T1 全 0/1 唯 M5=2/2(亲本均无该等位)→ 5 信息位点 4 兼容 1 冲突 rate=0.8 flag + incompatible_markers 含 M5/2/2 + dam=0/0/sire=1/1;T2 全兼容 rate=1.0 flag=false;T3 双亲空 → no_declared_parents + reason「未声明亲本」;T4 dam=G3(声明但无 germplasm 基因型)→ missing_parent_genotype + reason「母本」不 409;summary informative=10/incompatible=1;D3 空数据集 → 零值返回 summary=None 不 409。**清理干净**。
|
||
- `Temp/claude/e2e_trial_design_ext_20260805.py` **19 断言全过**——[1] augmented:12 条目(G01-G12)3 对照(G01-G03)× block_count=3 → n_new=9/n_checks=3/check_reps=3、新品系 block_no∈{1,2,3} 且不重复、对照 block_no=None、checks 结构;[2] alpha 平方 v=9=k²(k=3 素数)r=4 → 自动 k=3/s=3/r=4、4 rep×3 块×3 条、每 rep 覆盖 9、任一对至多同块一次(maxλ≤1 且恰 36 对)、balance_warning=False、block_no 复合编码落库(修复后 401/402…);[3] 部分 r=3 仍可分解平衡;[4] v=16 k=4(非素数)r=5 完全格子 + balance_warning=True(保守告警可分解);[5] v=12 一般(k=3 显式)s=4/r 缺省=s=4 贪心可分解 + block_no 落库;[6] 四 409(对照非条目子集 / 增广无对照 / v 不被 k 整除 / 非平方缺 block_size)。**清理干净**。
|
||
- **回归**:rcbd 路径由 `e2e_trial_design_20260805.py` 回归零变化兜底;全量套件 e2e_molrigor / e2e_gwas / e2e_mating_kinship / e2e_mating_ebv / e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_gs_family_cv / e2e_batch_selection / e2e_ocs / e2e_mabc / e2e_gaps_base / e2e_gaps_engines / e2e_gaps_modules / e2e_prediction_rigor / e2e_inbreeding_depression / e2e_parent_validation 全套零回归。**vue-tsc** EXIT=0。**HTTP 核验**:后端重启(PID 更换)后 `GET /bre/genotype_call/mendelian/check?dataset_id=999999` → 200 零值结构;`POST /bre/statistics/trial-design` design_type=augmented/alpha → 409「该研究点无参试条目」(分派+参数链路通)、design_type=latin → 409「暂不支持设计类型 latin(可用: rcbd=随机完全区组、augmented=增广、alpha=α-格子)」。
|
||
- **方法学保留**:mendelian_check 与 `fingerprint_check` 互补不冲突(fingerprint 管样本间一致性/混杂,mendelian 管子代-亲本孟德尔规则);augmented 对照 anchoring + α-格子平衡性显式告警与既有 RCBD 随机化并存。
|
||
|
||
`_DATA_VERSION` v2.25(`statistics/service.py:97`)。同步 3 处探针版本断言(e2e_prediction_rigor / e2e_spatial_sparse / e2e_statsflow)。
|
||
|
||
### 8.37 区组随机效应 ABLUP(N3)+ 孟德尔检验落库/隔离/进报告(N1)+ 统计引擎全量数值校验(N2)落地台账(v2.26,2026-08-05,代码级)
|
||
|
||
> 用户实证复查提出三项,本会话逐项核实**全部成立**,分三子批落地:**N3** trial_design 已落库 `block_no` 不完全区组结构但 `run_ablup` 未把 block 当随机效应(只当空间竞争协变量网格 key)——用户拍板「显式 block 开关」;**N1** `mendelian_check` 只读纯计算、不落库不隔离错配亲本——用户拍板「断开错误亲本链」(可疑树退化为 founder、自身表型保留,可逆);**N2** run_gblup/ssGBLUP、genetic_corr、type_b、run_cluster、stability 等大体量新模块只有结构性断言,缺逐文件数值真值校验——用户拍板「全量统计引擎」新增强立 ground-truth 数值探针。`_DATA_VERSION` v2.26(`statistics/service.py:97`),`blup.ENGINE_VERSION` 1.4.0→**1.5.0**。
|
||
|
||
**批5-A(N3):ABLUP 区组随机效应**(`blup.py` `solve` 加 `block: dict|None` 分派新 `_solve_block`,镜像 `_solve_gxe`,`blup.ENGINE_VERSION` 1.5.0):
|
||
|
||
- **引擎**:`_solve_block(pedigree, phenotypes, *, fixed, covariate, block_of, record_map, tol)`——Z₂ 按 `block_of: {记录id: 区组水平}` 分组(G×E 的 (g,e) 复合键退化为单区块水平),其余逐字节复用 `_solve_gxe`:剖面 REML 坐标上升估 (σ²a/σ²e, σ²block/σ²e)、MME、PEV 可靠性。输出键 `sigma_block`/`block_ratio`/`block_effects`/`n_blocks`,factor_label=「区组」;区组方差收敛到 0 / 无系谱 / 未收敛三警告文案。
|
||
- **服务**:`run_ablup` 加 `block: bool=False`。互斥:`block` 与 `gxe/gxr`(共用 Z₂ 第二随机效应槽)**409**、`block` 与 `spatial`(残差结构与第二随机效应槽互斥)**409**。新分支读 `bre_tree.block_no` 构 `block_of={f"t{tid}": int(blk)}`;无 block_no 的树**降级剔除表型保留系谱**(镜像 spatial 缺坐标降级,note 记剔除数);`len(set(block_of))<2` → 409「区组数据不足:需 ≥2 个区组(请先运行 /statistics/trial-design 生成设计并落库 block_no)」。`method="ABLUP-BLOCK"`、model_name 前缀 `ABLUP_BLOCK_`、note_payload 含 `sigma_block/block_ratio/n_blocks/warning`;accuracy 按 block 树均值可靠性。
|
||
- **前端**:「多环境 GxE」tab 加 `blockEnabled` 复选框 + 互斥 watch(block↔gxe/gxr/spatial)+ payload.block + 成功文案三元。
|
||
- **探针** `e2e_ablup_block_20260805.py` **6 场景全过**——[1] 3 区组×每区组 5 株已知 σ²block>0 → method=ABLUP-BLOCK/n_blocks=3/σ²block>0/block_ratio>0/EBV 与探针内独立矩阵解一致;[2] 单区组 → 409 区组数据不足;[3] 无 block_no → 409;[4] block+gxe → 409、block+spatial → 409;[5] 部分树缺 block_no → 降级剔除 + note 含剔除数;[6] 全收敛数据 → 无区组归零警告。
|
||
|
||
**批5-B(N1):孟德尔检验落库 + 自动隔离 + 进数据质量报告**(`genotype_call` 新表 + 写端点 + `statistics` 消费方断链,`bre_mendelian_check`/`bre_mendelian_check_tree`/`bre_pedigree_exclusion` 三新表 create_all 自动建):
|
||
|
||
- **落库**:纯计算核心抽共享 `_compute_mendelian(dataset_id, compat_threshold)`(GET 预览与 POST 逐字节同源)。新 `run_mendelian_check` → 落 `bre_mendelian_check`(计数/summary_json/data_version/input_hash/engine_version)+ 每树子行 `bre_mendelian_check_tree`(FK check_id CASCADE;status/兼容计数/rate/flag/reason/incompatible_markers_json);`POST /bre/genotype_call/mendelian/check/run`(Auth `module_bre:genotype_call:edit`),**GET 只读预览保留零回归**。
|
||
- **自动隔离(可逆)**:对 flag=true 树 upsert `bre_pedigree_exclusion`(唯一 tree_id、source_type="mendelian"、source_check_id);本次未 flag 但此前隔离过的树(同 dataset 范围)删除隔离行——注册表=最新检验结论,数据修正/阈值提高后自动解除。
|
||
- **进数据质量报告**:`data_quality_report` 加可选 `dataset_id`,提供时追加 `mendelian` 段(最新一次检验计数 + flagged 树列表 + 当前隔离状态);`flagged>0 → summary.has_warning=True`;无检验记录 → `mendelian: None`。
|
||
- **系谱消费方断开亲本链**(「断开错误亲本链」语义):共享 `_excluded_tree_ids()` 读隔离注册表,树级 dam/sire 读取处把隔离树 parent 置 None + note——覆盖 `_build_pedigree`(genetic_corr/index/type_b/gblup/ssgblup/gwas)、`run_ablup` 内联系谱循环、`inbreeding_depression`、`kinship_matrix`、`run_cv`、`_germplasm_pedigree`(树→种质亲本链)。**GBLUP/ssGBLUP 基因型样本不受影响**(错配的是亲本声明,非基因型本身)。
|
||
- **前端**:genotype_call 孟德尔对话框主按钮改 POST run(展示 check_id + 隔离树数);statistics「数据质量」tab 加 dataset 选择器 + mendelian 段(flag 计数 alert + 隔离树表)。
|
||
- **探针** `e2e_mendelian_persist_20260805.py` **ok=19 fail=0**——[1] POST run 落库(bre_mendelian_check 行/计数/子表行/check_id);[2] 隔离生效 + EBV 断开验证(隔离树与声明亲本亲缘=0、EBV 符合 founder 语义);[3] 再跑未 flag → 隔离行清除(可逆);[4] data_quality_report(dataset_id) mendelian 段 + has_warning=True、无检验 → None;[5] run_ablup note 含隔离剔除数、genetic_corr 亲缘=0;[6] GET 只读预览 8 断言零回归。
|
||
|
||
**批5-C(N2):统计引擎全量数值真值校验**(新探针 `e2e_stats_numerics_20260805.py` **ok=101 fail=0**,直接调引擎 + 关键服务端点,逐段独立 ground-truth 对照):
|
||
|
||
- **已覆盖真值段**:`blup.solve` 普通(独立 V⁻¹ BLUP ≡ MME、网格 REML 表面一致);`_solve_gxe`/`_solve_block`(MME 正规方程恒等 + 方差分解一致性 + 区组效应恢复);`solve_spatial(_aniso)`(R 重构 + MME 恒等 + aniso ρ_row/ρ_col 恢复);`genomic.build_g_matrix`(手算 VanRaden method2)+ `solve_gblup`(MME 恒等 + 可靠性公式);`_build_h`(教科书 H⁻¹=A⁻¹+[0,0;0,G⁻¹−A22⁻¹] 含 Christensen 缩放 + 岭)+ ssGBLUP MME 恒等 + 非基因型株 EBV≠0;`solve_bivariate`(完全正相关 r_g→1 / 独立 r_g≈0);`solve_multi`(已知 G0 对角 1 相关 0.5 恢复 + PSD);`finlay_wilkinson`(独立 OLS 对照);`ammi`(解析 2×2 SVD);`anova.solve_rcbd`(手算 SS/MS/F);`combining._solve_diallel`(手算 GCA/SCA);`_proj_simplex`/`_solve_ocs`/`_selection_intensity`;服务端点 `run_cluster`(UPGMA 首次合并=最小距离对)/`genetic_gain`(ΔG=k·r_g·σ_A 公式复算)/`data_quality_report`(IQR/MAD 手算边界)/`kinship_matrix`(3 节点 A 手算)。
|
||
- **探针抓出的两处探针自身 fixture 缺陷(非引擎 bug,全部修复)**:① A8/A9 双变量/多变量小样本低 h² 设计(4 创始人+10 子代)REML 面平坦/近边界 → 单性状 ve 塌缩 → ρ 剖面假收敛(独立性状 r_g=-0.99)、G0 恢复不可靠——**高遗传力(va≫ve,h²≈0.87-0.9)+ 高真相关(0.95/0.90/0.85)+ 10 全同胞家系×3 株良态设计**替换后 r_g 恢复误差 ≤0.06(11s);② B4.2 硬编码 `tree_id==4`(fixture 树真实自增 id 非 4)→ 改引用 fixture 树列表 `trees[3]`。**引擎本体零缺陷**(EM-REML/M-step/固定点/MME/剖面逐项验证教科书正确)。
|
||
- **runtime 约束记录**:`solve_multi` 3 性状 n≥100 时本机 numpy LAPACK 每次迭代 0.7s(n=100),超 2 分钟——数值探针 fixture 保持小样本(n≤54)规避。
|
||
|
||
**验证**:三新探针全过 + **27 套件全量回归零回归**(含 e2e_mendelian_check / e2e_trial_design / e2e_trial_design_ext / e2e_gxe / e2e_gxr / e2e_molrigor / e2e_gwas / e2e_mating_kinship / e2e_mating_ebv / e2e_gblup_cv / e2e_statsflow / e2e_spatial_sparse / e2e_gs_family_cv / e2e_batch_selection / e2e_ocs / e2e_mabc / e2e_gaps_base / e2e_gaps_engines / e2e_gaps_modules / e2e_prediction_rigor / e2e_inbreeding_depression / e2e_parent_validation / e2e_advanced_gblup / e2e_corr_spatial)**vue-tsc** EXIT=0。**HTTP 核验**(后端重启):`POST /bre/genotype_call/mendelian/check/run`、`POST /bre/statistics/data-quality`(dataset_id)mendelian 段、`POST /bre/statistics/ablup/run`(block=True / block+gxe 409)、`POST /bre/statistics/ocs`。**备份镜像** `Temp/claude/backup_block_mendelian_numerics_20260805/`(18 文件按相对路径)。
|
||
|
||
---
|
||
|
||
### 8.38 规划↔目标↔试验 可追溯性闭环落地台账(v2.27,2026-08-05,代码级)
|
||
|
||
> 用户全代码库 grep 实证**可追溯性缺口成立**:`plan_id`/`bre_plan`/`ForeignKey…plan` 只命中 `plan/` 模块自身字段,**零传入外键**;`bre_trial` 无 `plan_id`/`target_id`;无 project/program 表——`bre_plan` 是**彻底孤立的根表**(规划定了目标、挂了试验,却无任何指针从目标/试验指回规划)。用户拍板「**加试验挂目标**」:最小双链方案——`bre_target.plan_id` + `bre_trial.plan_id`,另加 `bre_trial.target_id`(试验挂目标),不新建 project/program 表。`_DATA_VERSION` v2.26→**v2.27**(`statistics/service.py:97` + `genotype_call/service.py:45` 同步,5 处探针版本断言同步:e2e_prediction_rigor / e2e_spatial_sparse×2 / e2e_statsflow / e2e_mendelian_persist)。
|
||
|
||
**DB(weld SQL 幂等)**:`weld_plan_trace.sql` 三列 ALTER——`bre_target.plan_id`(FK→bre_plan,可空)、`bre_trial.plan_id`(FK→bre_plan,可空)、`bre_trial.target_id`(FK→bre_target,可空)。已应用并验证 `\d bre_target` / `\d bre_trial` 三 FK 就位。
|
||
|
||
**模型/模式/服务**:
|
||
|
||
- **target**:`TargetModel.plan_id` + `PlanModel` relationship;`TargetCreateSchema/TargetUpdateSchema.plan_id` 透传;get_list 加 outerjoin 解析 `plan_name`;create 前 `_assert_parents_exist`(plan_id 不存在 → 409,None 跳过——孤目标仍可建);delete `assert_no_children`(有 combo 子 → 409)。
|
||
- **trial**:`TrialModel.plan_id`/`target_id` + 双 relationship;schema 双字段透传;get_list 解析 `plan_name` + `target_name`;create 前双父校验(不存在 plan_id/target_id → 409,None 跳过——独立试验仍可建);delete `assert_no_children`(有 trial_study 子 → 409)。
|
||
- **plan**:新 `trace(plan_id)` 服务方法 + `GET /bre/plan/trace/{id}` 控制器——返回 `{plan, targets:[{id,target_name,plan_id,n_combinations,n_trees,combinations:[{id,combination_code,bre_target_id,trees}]}], trials:[{id,trial_name,plan_id,target_id,target_name,n_trial_studies,n_trees,trial_studies:[{id,study_name,year,trees}]}], totals:{targets,trials,combinations,trial_studies,trees}}`;组合/试验点**软删过滤**(is_deleted=true 不进入);挂计划的 target 才入目标链(孤目标不入);不存在计划 → 409「计划不存在」;plan.delete `assert_no_children`(有 target/trial 子 → 409,防孤挂链)。
|
||
- **前端**:target/trial 表单「所属计划/目标」select(PlanAPI.getPlanOptions / TargetAPI.getTargetOptions,`res.data.data ?? []`)+ 表格/详情列(plan_name/target_name);plan 页「追溯」行操作(`PlanAPI.getPlanTrace`)弹窗——ElCollapse 目标链/试验链,组合与试验点 ElTags(`组合码(N株)`/`试验点名(N株)`)。
|
||
|
||
**探针** `Temp/claude/e2e_plan_trace_20260805.py` **17 断言全过**——[1] 目标链(挂计划目标 T1 含未软删 C1+C4、软删 C2 排除,n_combinations=2/n_trees=4,组合明细 C1=2 树/C4=2 树);[2] 试验链(挂计划+目标试验 R1,软删 S2 排除,n_trial_studies=1/n_trees=2,target_name 解析到 T1);[3] totals(targets=1/trials=1/combinations=2/trial_studies=1/trees=6);[4] 孤目标 T2 不入 trace + 不存在计划 409;[5] target page 返回 plan_name、trial page 返回 plan_name+target_name、孤目标 plan_id/plan_name=None;[6] 三父校验(target 坏 plan_id / trial 坏 plan_id / trial 坏 target_id 均 409);[7] 双删除守卫(plan.delete 有子 409、target.delete 有子 409)。探针自清理(含 bre_target 审计行,防孤儿)。
|
||
|
||
**验证**:新探针 17/17 + **全量回归零回归**(60 套件——含批5 三探针零变化 + 审计切面 e2e_audit 排查修复:探针残留检查原 `entity_id.in_(CREATED_TARGET_IDS)` **未限定 entity_type**,而 `entity_id` 按实体表各自序列非全局唯一(如 `bre_seed_lot` id 72 可与 `bre_target` id 72 撞车),目标序列被推进到 691 后与既有 `bre_cross_combination`/`bre_germplasm` 审计行撞 id 间歇误报 → 残留检查限定 `entity_type=='bre_target'` 与 clean() 删除范围一致,连续 5 轮 13/13 稳定)**vue-tsc** EXIT=0。**HTTP 核验**(后端重启):`GET /bre/plan/trace/{id}`、target/trial create 带 plan_id/target_id、三父校验 409、双删除守卫 409。**备份镜像** `Temp/claude/backup_plan_trace_20260805/`(按相对路径)。**方法学保留**:三 FK 全可空(历史孤目标/独立试验不受影响),可追溯性是**渐进式**——新数据挂链即可查,存量数据不强制回填。
|
||
|
||
---
|
||
|
||
### 8.39 系谱键空间错位修复——type_b / genetic_corr 静默丢系谱(v2.28,2026-08-05,代码级)
|
||
|
||
> 用户质疑「GBLUP/ssGBLUP、genetic_corr、type_b、cluster、stability、OCS、MABC、inbreeding_depression、trial_design、mendelian 这批新建模块还没逐一数值校验(golden-test 缺失)」,拍板**全量十项逐一复查**。审计发现**真 bug**:`type_b`(`run_type_b_heredity`)与 `genetic_corr`(`correlation_matrix` mtblup / `run_genetic_corr`)服务层把 **int `tree_id` 表型键** 传给 `mtblup.solve_bivariate`,而系谱(`_build_pedigree`)用 **str `"t{id}"`** —— `blup.solve` 把系谱外个体自动并入 base(视作无关 founder,[blup.py](backend/scripts/breeding_stats/blup.py) `solve` 系谱外 id 合并进 base 的鲁棒逻辑)→ **系谱被静默丢弃**。平衡数据(同株跨环境)掩盖了它;**分裂家系**(无同株跨环境、靠全同胞链桥接)会暴露:int 键 → r_B/r_g **锁死在 ±0.99(平剖面端点假收敛)**。`_DATA_VERSION` v2.27→**v2.28**(`statistics/service.py:97` + `genotype_call/service.py:45` 同步,4 处探针版本断言同步:e2e_spatial_sparse×2 / e2e_statsflow / e2e_prediction_rigor / e2e_mendelian_persist)。
|
||
|
||
**修复**:新增共享 helper `_tree_individual_keys(d)`(`{tree_id:值}→{"t{tree_id}":值}`,对齐 `_build_pedigree` 个体键空间),**四个调用点**统一收口——`_genetic_corr_matrix`(L2214)/ `_smith_hazel_index` 的 mtblup 分支(L2754)/ `run_genetic_corr`(L5122,喂 `solve_multi` 与 `solve_bivariate`)/ `run_type_b_heredity`(L5294)。`run_ablup` 早已正确(`phenos_keyed={f"t{tid}":v}`),不受影响。
|
||
|
||
**探针** `Temp/claude/e2e_rg_golden_20260805.py` —— 20 founder(10 母×10 父)、10 全同胞家系×3 同胞=30 株、3 站点;tY 分裂家系(站1=同胞0,1 / 站2=同胞2 / 站3=全株,真 r_B=0.8,站1-站2 无共有树)+ tA/tB/tC 平衡(真 r_g AB=0.95、AC=BC=0)+ tS1/tS2 分裂家系(真 r_g=0.8 无共有树)。**ok=21 fail=0**:
|
||
|
||
- [P0 诊断] `solve_bivariate` 直接调用:str 键恢复 r_B=0.7+、**int 键锁死 −0.99**(RED 实证);
|
||
- [P1 type_b golden] 服务端点 r_B(1,2)>0.5 + **n_common=0**(三站无共有树、靠系谱桥接,系谱生效的直接证据)+ 全正 min>0.3;
|
||
- [P2 correlation golden] r_g(A,B)>0.65、|r_g(AC/BC)|<0.4、判别间隙>0.3、h²∈(0,1);
|
||
- [P2b discriminator] r_g(S1,S2)>0.5(分裂家系无共有树,RED 下锁死 −0.99)。
|
||
|
||
**验证**:新探针 21/21 + `e2e_statsflow`(B1/B2,单家系 fixture 对键 bug 不敏感,15 断言零变化)+ `e2e_advanced_mtblup`(r_g=0.99/n_common=4/smith-hazel mtblup)回归通过 + **全量回归零回归**(batches 1–3 + final,60 套件,含版本断言同步的 spatial/prediction_rigor/statsflow/mendelian_persist)+ **vue-tsc** EXIT=0。**HTTP 核验**(后端重启):`POST /statistics/type-b-heredity`(分裂家系 r_B(1,2)>0.5 + n_common=0 + data_version=v2.28)、`POST /statistics/genetic-corr/run`(tS1,tS2 分裂家系 r_g>0.5 + 平衡 tA,tB r_g>0.65)。**备份镜像** `Temp/claude/backup_keyspace_20260805/`(按相对路径)。**方法学保留**:四个 mtblup 消费路径统一 str 键对齐系谱,`run_ablup` 正确路径不受影响;探针 fixture 高遗传力(h²≈0.89)+ 分裂家系结构保证判别力。
|
||
|
||
### 8.40 回归基建:统一回归 + 高风险模块正式 tc 套件(测试基建,不 bump 版本,2026-08-05)
|
||
|
||
> 用户三点质疑(① 全库 `test_bre_*_tc.py` 只覆盖「数据建链/导入导出/多波次」,对 GBLUP/ssGBLUP、OCS、MABC、近交衰退、试验设计、孟德尔检验零命中;② 批7 改动未补 golden;③ 新模块算偏会当「正常结果」输出——正是当年 G/I 静默失效同款隐患)核实**全部成立**,拍板「**两者都要**」:先统一回归脚本(立即止血),再抽正式 tc 套件。纯测试基建,**无后端代码改动**,`_DATA_VERSION` 保持 v2.28。
|
||
|
||
**统一回归 `run_regression.py`**(仓库根):`glob Temp/claude/e2e_*.py`(排除 `e2e_probe*`)+ `backend/scripts/test_bre_analysis_*_tc.py` = **63 测试**;**顺序串跑不并发**(RC=124 机器争用超时前科);每测试独立子进程、完整输出写 `Temp/claude/regression_logs/<name>.log`、控制台回显尾部 + EXIT;任一失败整体 exit≠0 供交付流程判断;`DPB_PYTHON` 覆盖解释器(须 dpb env python);utf-8 reconfigure 防 GBK 崩溃;过滤器 + `--keep-logs`。验证:全量 58/59,唯一失败 gaps_engines 批量卡死、单跑 RC=0 确认(机器争用非探针问题)。
|
||
|
||
**4 个正式 tc 套件**(TestClient 走真实 API + lifespan,URL 带 `/api/v1/bre/...` 前缀,高风险模块必测,fixture 自带清理):
|
||
|
||
| 套件 | 断言数 | golden 判别核心 |
|
||
|---|---|---|
|
||
| `test_bre_analysis_ssgblup_tc.py` | ok=14 | **H⁻¹ 拼接判别**——非基因型株 GBLUP EBV=0 / ssGBLUP EBV≠0(拼接错则非基因型亲属 EBV=0 或爆炸) |
|
||
| `test_bre_analysis_ocs_tc.py` | ok=23 | 投影梯度收敛——Σc=3/c≥0/coverage direct 5/A≈1.419、λ↑→avg_kinship 单调非增、c'Ac≈4.641、λ=0 满额投 A、409+422 |
|
||
| `test_bre_analysis_mabc_tc.py` | ok=24 | 前景命中/背景恢复率 100/75/0 复算、晋级 BC2/再回交/维持、童期 C6 晋级、422+409 |
|
||
| `test_bre_analysis_mendelian_tc.py` | ok=9 | POST `/bre/genotype_call/mendelian/check/run`(**下划线** `genotype_call`)落库 + flag 进 `bre_pedigree_exclusion` 隔离注册表 + 阈值 0.0 重跑可逆 + GET 零回归 |
|
||
|
||
**tc 套件关键教训**:① **HTTP 语义差异**——schema 层 Pydantic 校验(ge/le)拦截 → **422**,服务层 CustomException → **409**(e2e 直调只见 409,tc 走 HTTP 见 422);② **Mapper 注册**——tc 必须显式 `import UserModel`,否则 `InvalidRequestError: UserModel failed to locate a name`;③ **时序验证**——孟德尔隔离断言须在 run1 后、run2(清除)前验证;④ **启动残留预清理** `_wipe()`——防上次进程被杀留唯一键脏数据,套件可重复跑。**交付流程**:改动统计引擎/业务链后端代码后跑 `python run_regression.py` 全量 EXIT=0 方可交付;新 tc 命名 `test_bre_analysis_<模块>_tc.py` 由驱动自动纳入。
|
||
|
||
### 8.41 回归基建 2:分析模块 tc 补齐(5 套)+ pytest 接入 + 本机 CI stage(测试基建,不 bump 版本,2026-08-05)
|
||
|
||
> 用户认可 §8.40 的 4 套 tc(ssGBLUP/OCS/MABC/孟德尔),并拍板「**两者都要**」后继续补齐 5 个静默失效风险「显著低于」但属相关性/回归/生成器类的分析模块(genetic_corr / type_b_heredity / inbreeding_depression / trial_design / run_stability),以达成 v8 验收标准「**CI 跑通 pytest 全绿**」。两条用户硬约束:① 全部基于**真实 PostgreSQL 16 + Redis**(工程无 SQLite,tc 全部在真实 PG+Redis 实跑);② 不做 GitHub Actions / 不登录 GitHub(全工程无 git 仓库,GitHub Actions 是云端服务本机用不上),CI stage 落地为**本机驱动脚本 `run_ci.py`**。纯测试基建,`_DATA_VERSION` 保持 v2.28。
|
||
|
||
**补齐 5 套正式 tc**(沿用 §8.40 骨架:TestClient 真实 API、`-X utf8` 防 GBK、`_wipe()` 启动残留预清理、自带清理、`sys.exit(1 if fail else 0)`):
|
||
|
||
| 套件 | 断言数 | golden 判别核心 |
|
||
|---|---|---|
|
||
| `test_bre_analysis_genetic_corr_tc.py` | ok=19 | 平衡 3 性状真 r_g(AB)=0.95 / AC=BC=0 判别(r_g(AB)>0.65、间隙>0.3、h²∈(0,1))+ **分裂家系判别** r_g(S1,S2)>0.5 且 **n_common=0**(S1 测同胞 0/1、S2 测同胞 2,无共有树靠全同胞系谱桥接;S1/S2 独立种子 SEED_S=3 扫描保 r≈0.99) |
|
||
| `test_bre_analysis_type_b_tc.py` | ok=18 | Type-B 多环境遗传力 3 站点分裂家系(站1=同胞0/1、站2=同胞2、站3=全株):3 环境、r_B(1,2)>0.5 且 **n_common=0**(复刻 tY-first rng 消耗序 → r=0.990)+ 三 409 |
|
||
| `test_bre_analysis_inbreeding_tc.py` | ok=44 | 近交衰退方向感知:y=100−60F 衰退 slope<−40 / t<−3 / 高 F 前 6 自交株;无衰退 slope≈0 未检出;**上升** y=10+40F slope>30(方向正确);deep 系谱 F=0.125;min_n=20 insufficient 优雅降级 + 422/409 |
|
||
| `test_bre_analysis_trial_design_tc.py` | ok=25 | 增广(9 新品系+3 对照×3 区组,**对照 block_no=None 不落库**、新品系落 1..3)+ α-格子平方 v=9 k=3 r=4(λ≤1、每 rep 可分解、warn=False)/ v=16 k=4 非素数(warn=True)/ 一般 v=12 贪心(r 缺省=s=4)+ **block_no=rep*100+block 复合编码落库读回** + 四 409;**教训**:α-格子 r=4 会整表覆写 block_no,部分 r=3 重跑须放在 r=4 之前否则读回的是部分态 |
|
||
| `test_bre_analysis_stability_tc.py` | ok=16 | AMMI/FW:3 组合×3 站点 cell means C0=[0,6,12]/C1=[2,5,8]/C2=[4,4,4] → FW b≈2.0/1.0/0.0 + flag_stable C1=True 其余 False(|b−1|≤2se)、r²≈1(常量响应基因型 None 合法);AMMI n=9、rank 按 ASV 升序、IPC1 占比≥IPC2、互作 SS>0;engine_version 落库;year 维度 + 二 409 |
|
||
|
||
**pytest 包装层 `backend/tests/test_stat_analysis_tc.py`**:9 套 tc 各一个 pytest 测试(`@pytest.mark.pg` + parametrize),以 **subprocess** 顺序串跑真实脚本(镜像 run_regression 契约,`DPB_PYTHON` 覆盖、`-X utf8`)。**环境控制关键**——包装层不 import 任何 app 模块(防 conftest 污染),subprocess env 显式构建:剥掉 conftest 注入的 `DATABASE_TYPE/DATABASE_NAME/POOL_SIZE/MAX_OVERFLOW/CAPTCHA_ENABLE`,置 `ENVIRONMENT=dev`/`DATABASE_TYPE=postgres`/`PYTHONPATH=backend`/`PYTHONUTF8=1`,再并入从 `backend/env/.env.dev` 解析的真实连接值(可被 `TC_CI_*` 覆盖验证 skipif 路径)。**skipif 探测**:asyncpg 连 PG + redis.asyncio ping(**须 `protocol=2`**——redis-py 7.x 默认 RESP3,本机 WSL redis-server 版本较老 `hello` 失败报 ResponseError,与 `app.core.database.redis_connect` 对齐);任一失败 `pytest.skip`。`pyproject.toml` 注册 `pg` marker(消 PytestUnknownMarkWarning);`conftest.py` 加 `collect_ignore_glob=["../scripts/test_*.py"]` 防 pytest 收集 import 独立脚本污染 sqlite 环境。
|
||
|
||
**本机 CI stage `run_ci.py`**(仓库根,镜像 run_regression 风格):step 0 探测本机真实 PG16+Redis(失败给出明确指引:起服务/核对 .env.dev/TC_CI_* 覆盖,exit 非 0);step 1 `pytest -m pg`(dpb python + `-X utf8`)跑 9 套;step 2 汇总 EXIT=0 → 「✅ CI 全绿」;日志写 `Temp/claude/ci_logs/`。与 run_regression 并存:run_regression = 手动全量回归,run_ci = 验收门。
|
||
|
||
**验证**:5 套逐个 EXIT=0(19+18+44+25+16=**122 断言**);`pytest -m pg` 9 passed(真实 PG+Redis,146s,含既有 4 套零回归);skipif 路径(`TC_CI_DB_PORT=1` 指错端口)9 skipped 不红、无 unknown-marker 警告、scripts 未被收集;`run_ci.py` EXIT=0「CI 全绿」;`run_regression.py test_bre_analysis` glob 自动纳入 9 套。**交付流程**:v8 验收 = `python run_ci.py` EXIT=0(或 `cd backend && pytest -m pg` 全绿);改动统计引擎/业务链后仍跑 `python run_regression.py` 全量。备份镜像 `Temp/claude/backup_analysis_tc2_20260805/`。
|
||
|
||
### 8.42 O2–O4 统计方法学广度落地:幼年–成年遗传相关 + 非线性基因组预测 + 约束选择指数(v2.29,2026-08-05,代码级)
|
||
|
||
> 用户系统核对统计引擎能力后确认三项 **P2 方法学缺口**(均零命中、不影响当前业务正确性,属统计方法库广度),拍板「O2–O4 先落地」+ 两项决策:① **O4 用经典 Kempthorne–Nordskog =0 闭式解**(b = P⁻¹G(I−M)a,纯 numpy 不迭代);② **前后端同步扩展**。统计引擎方法学扩展 → `_DATA_VERSION` v2.28 → **v2.29**(`genomic.ENGINE_VERSION` 1.3.0 → **1.4.0**;blup/mtblup 版本不动)。**无新表**——O2 复用 `bre_type_b_result`(env_dim 已是自由字段)、O3 复用 `bre_prediction`/`bre_prediction_value`(method 标签扩展)、O4 复用 `bre_selection_index`(result_json 已含 extra)。
|
||
|
||
**O2 幼年–成年遗传相关(env_dim="stage")**:`_values_by_tree_env`(service.py:324)加 stage 分支——按 `coalesce(obs.stage, TraitModel.stage)` 分组(观测缺省继承 `bre_trait.stage`、两者皆空不参与分组)、group_by 含 coalesce 表达式、同树同阶段多次观测取均值;`run_type_b_heredity` env_dim 校验扩 `("site","year","stage")`。发育阶段当"环境"→ 逐对 `mtblup.solve_bivariate` REML 精确估 **幼年–成年遗传相关 r_g**(>0.5 表示童期可借力成株、早期间接选择有效)。前端 Type-B 页签 env_dim 下拉加「stage=发育阶段(幼/成)」。
|
||
|
||
**O3 非线性基因组预测(genomic 1.4.0)**:`solve_rrblup`(岭回归逐标记:y=μ+Xu+e,u=(Xc'Xc+λI)⁻¹Xc'yc,λ 由剖面 REML 的 σa²/σe² 定 → σu²=σa²/c、EBV=Xc·u+μ,**与 GBLUP 数学对偶**)+ `solve_bayesb`(BayesB Gibbs:δ_j~Bernoulli(1−π) + 方差尺度混合 + inv-χ² 更新,**确定性 seed 可复现**——MLOps 铁律);`kfold_cv_genomic` 加 dosage/markers 分派 rrblup/bayesb 折内走对应求解器;`run_gblup` method 扩 `("gblup","ssgblup","rrblup","bayesb")` + seed 透传,落 `PredictionModel(method=RRBLUP/BayesB)` + `PredictionValueModel`(EBV/rel/pa/rank)+ **marker effects**(GBLUP 无的解释能力);`run_cv` GS 分支 rrblup/bayesb 传 dosage,method_name=KFCV/RRBLUP·KFCV/BayesB。前端 GBLUP/CV 页签 method radio 加 RRBLUP/BayesB + seed 输入。
|
||
|
||
**O4 约束选择指数(restricted 闭式解 + economic weights)**:`_smith_hazel_index` 加 `restricted_traits`/`economic_weights`——受限时 **Kempthorne-Nordskog Lagrange 闭式投影** b = P⁻¹·G·(I−M)·a,M = C'(C·G·P⁻¹·G·C')⁻¹·C·G·P⁻¹·G(约束 C·G·b=0 ⇔ **受限性状 ΔG=0**,纯 numpy pinv 不迭代;**对照旧公式 M=C'(C·P⁻¹·C')⁻¹·C·P⁻¹ 不满足 ΔG=0(实测 ΔG=4.46)**,证明修正必要);economic_weights 直接作 a(绝对尺度**不归一化**统计权重、未列性状按 0 不进聚合基因型),可与 restricted 叠加;extra 落 `restricted`/`constraint_mode=ΔG=0`/`economic` 标记 + warnings(受限性状数/eco_missing/P 样本量);门禁 restricted_traits ⊆ cols(越界 409)、economic_weights 性状须在 tmap。method 校验扩 `("zsum","smith_hazel","restricted")`,落库 method=SI_RES。前端指数页 method radio 加 restricted + restricted_traits 多选 + 每性状经济权重输入。
|
||
|
||
**顺手修复(tc 暴露的既有缺口)**:`cv_detail` 折明细 dict 缺 `cv_result_id`(CvFoldOut 必填)→ 任意 GET /cv/{id} 400——补上后 rrblup/bayesb CV 详情可查(既有 tc 均未触达该端点,静默失效风险同款)。
|
||
|
||
**验证**:`e2e_o234_20260805.py` 探针 19 断言(O3 rrBLUP/GBLUP 闭式对偶 EBV 逐位吻合 1.42e-13 + marker effects 恢复 + BayesB 固定 seed 两次逐位一致 + kfold rrblup/bayesb 5 折完整;O4 受限性状 ΔG=0 机器精度 −8.88e-16/−3.66e-16 + 旧公式不满足(修正必要)+ economic asc 翻转严格下降((P⁻¹G)₀₀>0 保号);O2 真实 PG 16 树幼/成双阶段 r_g=0.6145>0.5 + n_common=16);正式 tc `test_bre_analysis_o234_tc.py` **ok=41 fail=0**(TestClient 真实 API + golden:O2 env_dim=stage 落库 r_g=0.8995>0.5 / n_common=12 / 双阶段各 12 株 / data_version=v2.29;O3 rrblup·bayesb·gblup 落库 method + engine_version=1.4.0、bayesb 同 seed 两次 EBV 逐位一致(可复现)、rrblup/GBLUP EBV 相关 1.000(对偶)、CV KFCV/RRBLUP·KFCV/BayesB 折数=5、非法 method 409;O4 restricted b_受限=0.0(ΔG=0 投影生效)+ 非受限自由响应 + smith_hazel economic desc 性状 b>0 / asc 翻转 b<0 + 缺 restricted_traits 409);TC_SCRIPTS 注册第 10 套;全量回归零回归(含既有 9 套 + 61 e2e)+ `run_ci.py` EXIT=0「CI 全绿」。备份镜像 `Temp/claude/backup_o234_20260805/`。
|
||
|
||
---
|
||
|
||
### 8.43 O1 花期数据消费补强:结构化花期区间 + 配对花期软警示 + 授粉窗口规划(v2.30,2026-08-06,代码级)
|
||
|
||
> 用户反馈 O1 花期字段零消费属真实数据盲点,但定性为 **P1 数据消费补强 + 辅助信息**(非与 S-等位同量级的正确性硬防呆)。拍板三个落地档位:① 花期数据建模升级(结构化区间,前置);② `mating_recommend` 返回体加花期重叠软警示(重叠/错开/需采粉贮藏,**不硬阻断**);③ 授粉窗口规划消费 `bre_pollen`(新端点 `GET /bre/pollen/window-plan`)。花期建模新增列 → `_DATA_VERSION` v2.29 → **v2.30**。
|
||
|
||
**① 花期建模升级**:`bre_germplasm` 新增双 Date 列 `bloom_start_date`/`bloom_end_date`(可空,年际重复物候——比较/投影时取月日、忽略年份),`flowering_period` 5 档字典保留作粗粒度 fallback。连锁:model/schema(Create+Update)/export 映射/import header/Excel 模板 + 前端 germplasm 表单双 date-picker、列、详情。
|
||
|
||
**② mating_recommend 花期软警示**:新 helper `_bloom_overlap(female, male)`(statistics/service.py)——优先结构化区间(月日年际比较),缺区间 fallback 到 5 档字典(相邻/同档视为重叠)。四态:`overlap`(重叠,可同期授粉)/ `store`(父本先开,需采粉贮藏至母本花期授粉)/ `offset`(母本先开,父本花期在后)/ `unknown`(缺区间与档位,提示补充)。pairs[] 每项加 `bloom_status`/`bloom_msg`;非重叠(store/offset/unknown)追加进 flags[](前端红色 tag 已渲染),overlap 不进 flags——**软警示不硬阻断**。
|
||
|
||
**③ 授粉窗口规划**:新端点 `GET /bre/pollen/window-plan?window_start=&window_end=`(pollen/service.window_plan)——把花期数据 × bre_pollen 库存映射到 [W1,W2] 窗口。花期按年际月日投影到窗口起始年(桃花期 3-4 月单年窗口假设),每株窗口内花期种质给花粉覆盖三态 `covered`(整段有批次覆盖)/`partial`(部分覆盖)/`none`(需采粉贮藏或同期授粉);库存侧给批次窗口状态 `full`/`expiring`/`entering`/`expired`/`not_started`。纯计算不落库;窗口反向 409。前端 pollen 页顶部加「授粉窗口规划」卡片(日期范围默认本年度/次年花期 03-01~04-30,花期覆盖表 + 库存状态表)。
|
||
|
||
**验证**:`e2e_o1_bloom_20260805.py` 探针全过(① CreateSchema→CRUD 双 Date 列落库;② 6 种质 15 对——重叠/错开/需采粉贮藏三类 + 档位 fallback mid×very_early→store + 区间×档位混合对→unknown,flags 仅非重叠进警示;③ 窗口 A 花期覆盖三态 covered/partial/none + 档位投影种质、窗口 B 库存五态 full/expiring/entering/expired/not_started + 窗口反向 409);`vue-tsc` EXIT=0;全量回归(run_regression.py)+ `run_ci.py` EXIT=0 零回归。版本连锁:4 e2e 探针 + o234 tc 断言 v2.29→v2.30。备份镜像 `Temp/claude/backup_o1_bloom_20260805/`。
|
||
|
||
---
|
||
|
||
## 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/ap;germplasm 用 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.2,2026-07-30)**:历经 v1.0→…→v1.9 + **v2.0 架构决策锁定** + **v2.1 review 修订(R1–R9)** + **v2.2 深度复审 A–H 全量落地(含 F1/F2 架构拍板:单一长表 + 两长表职责正交 + 统计 VIEW/看板 MV;A1 clone 建于入选 / A3 砧木 FK 统一字典 / A4 pedigree 唯一权威 / B1-B4 统计口径 / C1-C3 门禁重构 / D1-D4 clone 居中 / F3-F5 门禁与公式修正 / G1-G3 编号·审计·method / H1-H3 打磨,详见 §8.10)**。所有模块、字段、枚举、建模铁律、互操作映射均已规格化。**仍为决策锁定、方案态**:除生成器 A/B/C 外,待用户明确"做/搞吧"后据此实施,不先行编码。
|