Files
PlantAI-dev/docs/superpowers/specs/2026-07-20-string-tree-reference-resolution-design.md
2026-08-03 18:42:47 +08:00

15 KiB
Raw Permalink Blame History

STRING Tree Reference Resolution Design

日期:2026-07-20

状态:范围已确认,实施计划审查通过

目标

为 PPI 增加基于固定 STRING v12.0 物种注册表和 species tree 的通用物种解析:目标物种受 STRING 支持时直接查询;否则按 STRING tree 拓扑距离返回候选参考物种;有效缓存中仍无法得到候选时,推荐拟南芥作为明确标注的模型兜底,并在用户确认后才执行 Ortholog→PPI。本轮只闭合 STRING→Ortholog→PPI,不修订 KaKs 功能。

已确认决策

  • 运行期只使用项目内固定快照,不联网刷新。
  • 同时缓存 species.v12.0.txt 和约 97 MB 的 species.tree.v12.0.txt。
  • PPI 的候选发现和排序只依赖 STRING 自身数据,不引入 NCBI taxonomy。
  • 项目阶段身份继续使用 Species_Code;STRING 外部身份使用 TaxID。
  • 返回稳定排序的 Top 3 STRING tree 候选。
  • STRING tree 没有分类等级和分子枝长,因此只报告 LCA 节点与拓扑边数,不声称“同目”“最相似”或“进化距离最近”。
  • 找不到候选时推荐 Arabidopsis thaliana(TaxID 3702)作为 model_fallback,必须由用户确认一次,不能静默执行。
  • PPI 与 KaKs 保持独立 owner;KaKs 缺少 CDS 不得阻断可直接执行的 PPI。
  • PPI-only fallback 只准备参考 PEP;只有调用方明确请求 KaKs 时才准备 CDS。

非目标

  • 不修改 PlanningAgentV2 的 PPI 静态依赖。
  • 不恢复 PPI→Ortholog 静态绑定。
  • 不修改 TFBS 的 NCBI taxonomy 路径。
  • 不让 KaKs 强制使用 STRING 物种。
  • 不修改 KaKs 的算法、参数、参考物种选择、输入契约、Manifest 或结果展示。
  • 不为 KaKs 新增 resolver,也不把 PPI 选中的 STRING 参考物种传给 KaKs。
  • 不建设通用 taxonomy 服务或数据库。
  • 不使用 LLM、模糊匹配或联网搜索猜测物种身份。
  • 不删除、重命名或覆盖既有分析结果。

当前问题

当前 gfa_core/ppi_string_policy.py 仅维护少量 STRING code/TaxID 和 Ft→Spinacia 静态推荐。recommended_string_reference_species() 只是字典查询;resolve_ppi_species_resolution() 将空结果直接暴露为“无可用近源推荐”。因此前端虽然是数据驱动的,后端并没有通用候选发现能力。

另一个必须同时修复的边界是执行身份:当前 PPI 执行仍依赖少量三字母 code。新 resolver 即使找到 registry-only 物种,如果 TaxID 不能传到 STRING client,仍会出现“预检支持、执行不支持”的假通用化。

固定数据布局

data/string/v12.0/
  species.v12.0.txt
  species.tree.v12.0.txt
  source_manifest.json

source_manifest.json 必须记录:

  • STRING 版本;
  • 官方下载 URL;
  • 下载时间;
  • 文件大小;
  • 每个文件的 SHA256;
  • parser schema version;
  • Viridiplantae 根节点和 Arabidopsis TaxID 校验结果。

缓存发布前必须验证:

  • 每个 parent TaxID 都能在 tree 中解析,根节点除外;
  • 官方根节点 1 -> 1 自环被识别为终止条件,且除此之外不存在任何环;
  • is_STRING_species 只接受 t/f 并严格解析为布尔值,禁止使用 bool("f");
  • is_STRING_species 节点与 species registry 一致;
  • Viridiplantae 根节点 TaxID 33090 存在;
  • Arabidopsis TaxID 3702 存在且标记为 STRING species;
  • 文件 SHA256 与 Manifest 一致。

运行期缓存缺失、损坏或校验失败属于系统资源错误,返回 string_registry_unavailable 或 string_registry_integrity_failed,不得伪装成“没有近源物种”,也不得因此自动回退 At。

Resolver 输入与输出

输入

  • project_species_code:项目身份,例如 Ft、Os;
  • target_scientific_name:存在时优先用于匹配;
  • ppi_target_tree_taxon_id:明确属于 STRING tree 的 TaxID,不复用含义不同的 NCBI 通用 taxid 字段;
  • 固定 STRING snapshot 路径;
  • top_n=3。

常用简称 alias 只用于将项目输入映射到 STRING tree 节点,不作为候选知识库。服务器维护最小的 PPI 默认 alias,例如 Os -> 39947,避免在没有更明确信息时把通用 NCBI 物种 TaxID 4530 错当成 STRING 实际使用的 japonica TaxID 39947。解析顺序固定为:明确的 ppi_target_tree_taxon_id → 科学名精确唯一匹配 → PPI 项目 alias 默认值。用户显式指定的 STRING tree TaxID 不得被 alias 覆盖。无法唯一匹配返回 target_string_tree_unresolved,不做模糊猜测。

输出

{
  "selection_mode": "exact_string|tree_nearest|model_fallback|unresolved",
  "project_species_code": "Ft",
  "target_tree_taxon_id": "62330",
  "selected_string_taxon_id": "3562",
  "selected_string_name": "Spinacia oleracea",
  "lca_taxon_id": "...",
  "lca_name": "...",
  "target_edges_to_lca": 4,
  "candidate_edges_to_lca": 3,
  "tree_distance": 7,
  "string_version": "12.0",
  "snapshot_id": "...",
  "requires_user_confirmation": true
}

解析算法

  1. 加载并验证固定 snapshot。
  2. 用显式 TaxID、科学名或现有常用 alias 将目标解析为 STRING tree 节点。
  3. 若目标节点本身 is_STRING_species=true:
    • 返回 exact_string;
    • PPI 直接使用该 TaxID;
    • 不插入 Ortholog。
  4. 若目标节点存在但不受 STRING 支持:
    • 候选池限定为 Viridiplantae 子树内 is_STRING_species=true 的节点;
    • 计算目标与每个候选的 LCA 和双向拓扑边数;
    • 排序键固定为 (tree_distance, candidate_taxon_id, candidate_name);
    • 返回 Top 3,模式为 tree_nearest;
    • 用户确认候选后才准备参考 PEP、执行 Ortholog,再执行 PPI。
  5. 若目标名称/TaxID 有歧义:
    • 返回 unresolved,要求用户补充 STRING tree TaxID 或精确科学名;
    • 不推荐 At,避免把可修正的身份问题伪装成生物学兜底。
  6. 若目标完全无法解析且用户选择继续,或有效 tree 中没有植物 STRING 候选:
    • 返回 model_fallback;
    • 推荐 At/3702;
    • 显示“远缘模型兜底,不是近源物种”;
    • 用户确认一次后才进入 Ortholog→PPI。
  7. 若缓存无效:
    • 返回资源错误;
    • 不提供 At 兜底,避免掩盖部署故障。

身份与依赖边界

项目级身份不变:

  • targetSpecies、referenceSpecies、scope_id、memberSetId 和文件名继续使用 Species_Code。

新增 PPI 技术身份:

  • ppiSpecies:唯一 STRING selector,可为旧 alias 或数字 TaxID;
  • ppiReferenceSpeciesCode:可选旧项目 code,registry-only 候选允许为空;
  • ppiReferenceStorageKey;
  • ppiReferenceTaxonId;
  • ppiReferenceSelectionMode;
  • ppiReferenceUserConfirmed;
  • ppiReferencePolicyId。

snapshot_id = sha256(parser_schema_version + registry_sha256 + tree_sha256)。ppiReferencePolicyId 由项目目标 Species_Code、目标 tree TaxID、选择的 STRING TaxID、selection mode、STRING version 和 snapshot_id 计算。它记录 PPI 如何选择和确认参考物种,不作为 Ortholog mapping 的复用身份,也不进入全局 gene-family scope_id。

Ortholog 另行计算 orthologMappingIdentity,至少绑定 target/member set、参考 Species_Code/TaxID、query/reference PEP SHA256、BLAST 参数和工具版本。只有该身份一致时,才可复用 final mapping 或 ortholog/*_pairs.txt 中间结果;PPI policy 改变但序列和 Ortholog 参数未变时,不应无意义重跑 BLAST。

STRING registry 不保证提供项目三字母 Species_Code。科学身份始终以 ppiSpecies 中的数字 STRING TaxID 为准;job-local 参考 PEP、ID map 和 Ortholog subject label 使用 ppiReferenceStorageKey。已存在唯一旧 code 时可兼容读取旧目录;registry-only 候选的 ppiReferenceSpeciesCode 为空,存储键固定按 string_taxon_{taxid} 生成,不得写回全局物种表或冒充项目 Species_Code。

现有 NCBI Datasets 下载器只可作为“按已选 TaxID 获取参考 PEP”的文件传输层,不参与候选发现、树排序或物种身份推断;本轮不建设 NCBI taxonomy 映射。

Ortholog 仍只是 producer:只有 tree_nearest 或已确认的 model_fallback 缺少目标→参考映射时才动态插入。PPI 是选择策略 owner。KaKs 不读取 PPI 的 STRING 候选;若用户另行要求 KaKs,独立检查其 reference CDS/PEP。

PPI fallback 只写 PPI 专用参数,并给动态 Ortholog 标记 dependencyOwner="ppi"。KaKs 调度路径必须忽略 ppiReference*、ppiReferenceStorageKey 与 ppiReferencePolicyId。fallback PPI 与 KaKs 同批且需要不同参考物种时,不在本轮自动生成两套 Ortholog;本轮联合验收只覆盖 direct Os PPI 不被 KaKs 阻断。

现有参考包下载函数不得为 PPI-only 请求隐式追加 kaks。requested_stages=["ppi"] 只要求参考 PEP;requested_stages 明确包含 kaks 时,既有 CDS/PEP 行为保持不变。此处只解除 owner 泄漏,不改变 KaKs 逻辑。

前端行为

  • exact_string:不弹参考选择框,不显示 Ortholog。
  • tree_nearest:显示 Top 3、TaxID、LCA 名称、拓扑距离、STRING 版本,用户选择后继续。
  • model_fallback:单独警告“拟南芥是远缘模型兜底”,默认不勾选;用户确认后记录确认状态。
  • unresolved:允许补充 TaxID/科学名、显式选择参考物种或跳过 PPI。
  • 缓存错误:显示部署资源错误,不显示生物学 fallback。

同一 ppiReferencePolicyId 的确认在当前批次内只询问一次;参考物种或 snapshot 改变后必须重新确认。

STRING 候选的参考 PEP 可下载性初始标记为 unknown。NCBI Datasets 下载失败时保留当前候选和错误,允许用户选择第二候选或上传 PEP;不得自动换候选或静默回退 At。

单次 PPI 执行继续只解析一个目标物种。多目标请求不得把第一个目标的推荐偷用于其余目标,保持现有“需要显式参考/Ortholog mapping”的行为,不在本轮扩展为多目标自动推荐。

Manifest 与诊断

预检、等待确认和等待参考 PEP 使用独立的 decision record,不写成最终 failed PPI Manifest。只有真正提交 PPI 执行后发生成功或失败时,execution Manifest 才记录:

  • project Species_Code;
  • 原始目标输入和解析方式;
  • 目标 tree TaxID;
  • 选择模式;
  • 选中 STRING TaxID;
  • LCA 和拓扑距离证据;
  • snapshot 版本和 SHA256;
  • ppiReferencePolicyId;
  • 用户是否确认模型兜底;
  • Ortholog mapping 路径及其参考 TaxID。

诊断代码至少区分:

  • string_registry_unavailable;
  • string_registry_integrity_failed;
  • target_string_tree_unresolved;
  • no_string_tree_candidate;
  • ppi_model_fallback_confirmation_required;
  • ppi_requires_ortholog_mapping;
  • stale_ortholog_reference_conflict。

分任务与门禁

T0 基线冻结

  • 记录真实 9000 服务目录、测试结果和 Os/Ft/非 Ft 预检响应。
  • 通过条件:现有聚焦测试绿色,错误现状可重复。
  • 不通过:停止,不叠加新功能。

T1 STRING snapshot 落地

  • 下载两个官方文件,生成 Manifest,完成完整性和 tree 一致性校验。
  • 通过条件:断网可加载;篡改任一文件会被拒绝;At 和 Viridiplantae 根节点校验通过。
  • 不通过:不得进入 resolver 开发。

T2 只读 registry/tree loader

  • 建立内存索引并按文件 SHA256 缓存,避免每个请求重复解析 97 MB 文件。
  • 通过条件:第一次加载可测量;后续请求复用同一只读索引;结果不受字典遍历顺序影响。
  • 不通过:不得接 API。

T3 通用 resolver

  • 实现 exact、Top 3 tree-nearest、unresolved、At model fallback。
  • 通过条件:Os direct;Ft 不靠静态表得到合理候选;第二个非 Ft 目标返回候选;无解析目标进入 At 确认分支。
  • 不通过:不得修改生产预检。

T4 TaxID 执行链

  • 复用现有 ppiSpecies 作为唯一执行 transport,允许其承载数字 TaxID;backend、CLI、STRING client 和 Manifest 原样使用;旧 code 保持兼容,不新增平行 ppiStringTaxonId 字段。
  • 通过条件:一个不在旧 12 项 map、但 registry 支持的物种能真实调用 STRING;请求、CLI 日志、API TaxID、Manifest 完全一致。
  • 不通过:不得宣称通用支持。

T5 PPI preflight、PPI-only 参考包和动态 Ortholog

  • 用 resolver 替换 Ft 静态推荐;PPI-only 参考包只要求 PEP;保持 PPI/KaKs owner 隔离。
  • 通过条件:direct PPI 无 Ortholog;tree nearest/已确认 At 才插 Ortholog;PPI-only 下载不索要 CDS;明确请求 KaKs 时原有 CDS/PEP 检查不变;KaKs 缺 CDS 不阻断 direct PPI。
  • 不通过:不得进入 UI 完成验收。

T6 前端确认与错误显示

  • 复用现有动态弹窗,增加 Top 3 evidence 和 At model fallback 确认。
  • 通过条件:前端选择的 TaxID 原样进入下载、Ortholog 和 PPI;缓存错误不显示 At;At 不能静默执行。
  • 不通过:不得部署。

T7 PPI/Ortholog Contract、Manifest、status 与 diagnosis 闭环

  • 只同步 PPI/Ortholog 合同、Manifest provenance、旧映射冲突和状态复用;不修改 KaKs contract/Manifest/status。
  • 通过条件:/api/execute、CLI 日志、Manifest、/api/stage-status 使用一致的 Species_Code/STRING TaxID/policy ID。
  • 不通过:不得复用旧结果。

T8 真实 9000 验收

  • 重启真实服务和 worker,使用真实固定 snapshot 执行 direct 与 fallback 链路。
  • 通过条件:Os direct;Ft tree nearest;第二个非 Ft;registry-only 物种;At 确认 fallback;缓存损坏;PPI/KaKs 隔离全部通过。
  • 至少一个真实小家族完成“推荐→确认→参考 PEP→Ortholog→PPI→final artifacts→Manifest→status→前端展示”。
  • 不通过:不得报告线上完成。

反模式约束

  • 不继续扩充 STRING_REFERENCE_RECOMMENDATIONS 静态表。
  • 不用 species_code 是否在旧 map 判断 STRING 支持。
  • 不把 tree topology 描述成分子进化距离。
  • 不因缓存错误静默使用 At。
  • 不让前端重新计算或重新排序候选。
  • 不只验证预检;必须验证 registry-only TaxID 能进入真实 STRING 请求。
  • 不在错误工作副本测试后宣称真实 9000 已修复。

最终验收矩阵

  1. Os:exact_string,无需 Ortholog。
  2. Ft:由 tree 算法产生候选,无 Ft 特例读取。
  3. 第二个非 Ft、非直接 STRING 植物:返回 Top 3。
  4. 旧 12 项 map 外、registry 内物种:真实 PPI 成功。
  5. 未知目标:进入用户确认 At 的 model_fallback。
  6. cache missing/corrupt:资源错误,不回退 At。
  7. 旧 mapping 与新 TaxID 冲突:拒绝复用。
  8. Os PPI + 缺 CDS 的 KaKs:只作为隔离回归,证明 PPI 可继续;不改变 KaKs 的暂停原因或行为。