feat(all): 数据库模块化拆分与版本化迁移、任务引擎命名体系收敛、物理输出校验加固与用户配置接通

- server/db: 拆 4929 行 db.rs 单体为 db/ 目录,migrations.rs 引入 PRAGMA user_version
    版本化迁移运行器(M1~M13)
  - 任务引擎 Phase 6/7b/7c 改名收敛:EngineStageConfig→PhaseConfig、StagePolicy→ResumePolicy、
    Converged→Completed、删除 task_type 列、success_method 拆 tlusty_/synspec_ 双列、
    新增 tlusty_status/synspec_status 半失败阶段守卫
  - 科学正确性加固:conv_check 任意行 NaN/Inf/溢出判无效(0 行容忍)、新增 spec_is_valid
    校验 SYNSPEC 脏谱、itek_history 逐次迭代全量保真、fmt_abn powf 溢出饱和
  - 用户配置真正接通:tlusty_chain/tlusty_input 由死字段经 调度器→TaskSpec→executor→runner
    透传生效;config 加载期 validate + deny_unknown_fields + 解析失败记 warn
  - 调度修复:H1 活锁(pending_strategies 跳过已失败策略)、种子查找错误不再静默降级冷启动
  - dashboard: 阶段配置面板 tlusty_stage/synspec_stage、"已完成"标签、迭代诊断展示
  - docs: 新增 database_refactor_design.md,同步 database/api/PIPELINE/workflow_detail
This commit is contained in:
fmq
2026-08-06 20:51:21 +08:00
parent cd370d88e7
commit d16b3d3cdc
61 changed files with 10268 additions and 5881 deletions
+26 -11
View File
@@ -84,8 +84,8 @@ struct CandidateResult {
src_dir: PathBuf,
/// 权威新名(来自 workflow 配置的小数精度命名)。
canonical_name: String,
/// 该点当初的收敛途径("cold_run" / "seed_step"),据 stages 是否含 seed_nc 判定,
/// 透传给服务端写入 grid_points.success_method,让导入点融入冷启动/种子步进统计。
/// 该点当初的大气收敛途径("cold_run" / "seed_step"),据 stages 是否含 seed_nc 判定,
/// 透传给服务端写入 grid_points.tlusty_success_method,让导入点融入冷启动/种子步进统计。
success_method: String,
}
@@ -256,10 +256,10 @@ fn candidate_cno_sum(c: &CandidateResult) -> f64 {
/// 从 workflow 配置派生收敛链最后阶段标签。
///
/// 旧版 run_one.py 每阶段覆盖同名 .5/.6/.err/nst,只留最后阶段的版本。迁移时需把这些
/// 裸文件归到正确的阶段标签下。标签取自配置 chain 的末段;chain 为空则回退到默认收敛链
/// 裸文件归到正确的阶段标签下。标签取自配置 tlusty_chain 的末段;为空则回退到默认收敛链
/// 的末段(default_cold_chain 末段是 nl)。
fn derive_last_stage_label(cfg: &GridConfig) -> String {
if let Some(last) = cfg.chain.last() {
if let Some(last) = cfg.tlusty_chain.last() {
return last.label.clone();
}
// chain 为空(仅 grid,无 chain 配置):回退到默认收敛链末段。
@@ -330,7 +330,21 @@ async fn scan_dir_for_results(
continue;
}
};
if !(summary.converged && !summary.atmosphere_has_nan && !atmosphere_has_nan(&seed_file)) {
if !summary.result_valid {
info!("跳过 {}: conv.json 标记未收敛 (converged=false)", name);
continue;
}
if summary.atmosphere_has_nan {
info!("跳过 {}: conv.json 标记大气含 NaN/Inf", name);
continue;
}
// 收紧阈值后(0 行容忍),对种子 .7 文件做二次校验。旧 run_grid 产物若含单行
// NaN(此前 10% 阈值放过)会被这里拒绝——记日志便于排查"为何某历史种子被拒"。
if atmosphere_has_nan(&seed_file) {
info!(
"跳过 {}: 种子 .7 文件含 NaN/Inf/溢出行(0 行容忍阈值)",
name
);
continue;
}
@@ -361,7 +375,7 @@ async fn scan_dir_for_results(
continue;
};
// 判定该历史点的收敛途径(供服务端写入 success_method,让导入点融入冷启动/种子步进统计):
// 判定该历史点的大气收敛途径(供服务端写入 tlusty_success_method,让导入点融入冷启动/种子步进统计):
// 旧 run_grid.py 流程——冷启动失败才改用 seed_step 链重跑,种子链首段 label 为 "seed_nc"。
// 故 stages 含 seed_nc → seed_step(种子步进救活);否则 → cold_run(冷启动一次收敛)。
let has_seed_nc_stage = summary.stages.iter().any(|s| s.label == "seed_nc");
@@ -680,11 +694,11 @@ async fn upload_results_to_server(
.file_name(format!("{}.7", c.canonical_name))
.mime_str("application/octet-stream")?,
)
// 收敛途径(cold_run/seed_step):服务端据此写 grid_points.success_method
// 大气收敛途径(cold_run/seed_step):服务端据此写 grid_points.tlusty_success_method
// 让导入点融入冷启动/种子步进统计而非独立 imported 分类。
// Part::text 需 'static 生命周期,克隆一份脱离 candidates 借用。
.part(
"success_method",
"tlusty_success_method",
Part::text(c.success_method.clone()).mime_str("text/plain")?,
);
@@ -961,7 +975,8 @@ mod tests {
let v: serde_json::Value = serde_json::from_str(&rewritten).unwrap();
assert_eq!(v["name"].as_str().unwrap(), "t20000_g5.0_he-2_c-4_n-4_o-4");
assert_eq!(v["params"]["logg"].as_f64().unwrap(), 5.0);
assert!(v["converged"].as_bool().unwrap());
// 旧键 "converged" 经 alias 读入 result_valid,重写后按新键名写出。
assert!(v["result_valid"].as_bool().unwrap());
assert_eq!(v["final_max_relc"].as_f64().unwrap(), 0.001);
// 格式对齐本项目计算生成的 conv.jsonrunner.rs:597 to_string_pretty(&ModelSummary)):
// pretty 多行缩进 + 字段按 ModelSummary 声明顺序(name 为首字段,非字母序)。
@@ -1016,8 +1031,8 @@ mod tests {
#[test]
fn test_derive_last_stage_label_from_chain() {
// 配置显式指定 chain → 取末段标签
let yaml = "grid:\n teff: [20000]\n logg: [5.0]\n loghe: [-2]\n logc: [-4]\n logn: [-4]\n logo: [-4]\nchain:\n - {label: lte, lte: T, ltgray: T, ilvlin: 0, require_converged: false, niter: 0}\n - {label: nc, lte: F, ltgray: F, ilvlin: 0, require_converged: false, niter: 10}\n - {label: nl_final, lte: F, ltgray: F, ilvlin: 100, require_converged: true, niter: 100}\n";
// 配置显式指定 tlusty_chain → 取末段标签
let yaml = "grid:\n teff: [20000]\n logg: [5.0]\n loghe: [-2]\n logc: [-4]\n logn: [-4]\n logo: [-4]\ntlusty_chain:\n - {label: lte, lte: T, ltgray: T, ilvlin: 0, require_converged: false, niter: 0}\n - {label: nc, lte: F, ltgray: F, ilvlin: 0, require_converged: false, niter: 10}\n - {label: nl_final, lte: F, ltgray: F, ilvlin: 100, require_converged: true, niter: 100}\n";
let cfg = GridConfig::from_yaml_str(yaml).unwrap();
assert_eq!(derive_last_stage_label(&cfg), "nl_final");
}