feat(all): seed_step_stab 稳定化种子链与同族种子轮换、ladder/自适应 Teff/丰度轴延拓三级回退与梯级种子入库复用、热启动首末比豁免、workflow 完成翻转回退链阻塞修复、大气收敛权威统计与 M14 回填
收敛攻坚(81/400 失败点根因与实测,见 docs/failed81_cno_seed_popzer_dpsilg_2026_08_18.md): - runner: 新增 seed_step_stab 策略链——同物理族(同 Teff/logg/logHe)CNO 邻居种子 + DPSILG=3.0 λ 算子欠松弛 + POPZER=1E-10 微布居置零(联动 POPZR2/RADZER 同值 + NITZER=1),针对 20kK He 富大气 He I/II 电离前沿布居极限环 - runner: 三级链内延拓回退(主链与 nl_direct 全败后自动触发): · 固定 ladder 步进——plan_ladder_steps 按归一化间隔选轴,Δlogg≤0.25/ΔTeff≤2.5kK,≤4 步 · 自适应 Teff 延拓——步长 1250K 起、成功 ×1.5 恢复、失败二分至 25K 折叠墙,≤48 步 · C/N 丰度轴延拓——高温域(Teff>30kK)专用,严格同族种子沿 C(优先)/N 轴 0.2 dex 起步 延拓阶段 NITER 下限提至 300(慢收敛 waypoint 迭代饥饿误判修复) - runner: 稳定化多档回退(DPSILG/POPZER 三档互补,联合回收 41/65); 域门控 Teff≤30kK——高温高金属域实测旋钮致散(17 拍爆至 4e16),域外跳过 - 梯级种子持久化: 收敛中间模型登记 ladder_seeds 随上报落 server seeds 表 (任务失败也上传,合成名 _ladder 与真实网格点零冲突),簇内相邻失败点自动复用 调度与执行: - scheduler: 策略解析新增 seed_step_stab 臂——find_exact_family_seed_from_db 严格 同物理族判定(不做 global 退化,防 ladder 中间种子 ΔTeff≤5000K 误命中), 排除本点历史已用种子实现重试轮换;链在 stab 耗尽时轮换未试过同族邻居重派 - executor: seed_step_stab 补种子下载(漏列曾致 78 任务假失败,seed_nc 无 fort.8 崩溃); Teff>30kK 域外自动降级普通种子链 收敛判据: - conv_check: 热启动豁免——首拍 max_relc<1(种子已近解)时首末比 1e3 判据数学上 不可达,豁免后交五重物理硬门槛裁决(修复 nl_ladder 0.038→6e-4 物理全过被误杀); 冷启动仍受判据门控 workflow 生命周期: - workflows/tasks: 完成 flip 增加「未消费回退链」阻塞子句——failed 点策略链未耗尽 或链尾 seed_step_stab 尚有未试过同族种子时不得置 completed(修复最后活跃点 cold 失败上报抢先 flip、still_running 守卫拦截后续策略永不派发);按 failed_stage 归因 (synspec 失败行只看 synspec 链,防 stale 审计副本永久卡死)+ json_valid 脏行防护 统计与前端: - 统计新增权威口径 tlusty_converged(不按策略拆)与 seed_step_stab_converged 分项, 前端详情页色带/概览卡消费权威总数并新增稳定化青色段(修复 stab 收敛点漏计, 生产 9137/9216 差额);M14 迁移回填历史 completed 点的 tlusty_status 文档: - 新增 failed81 POPZER/DPSILG 制胜配方根因分析、Windows 节点经跳板 RDP 运维手册; failed400 增补 ladder 生产化实现与第二轮 121 残点实测矩阵
This commit is contained in:
@@ -360,6 +360,7 @@ impl GridScheduler {
|
||||
/// 「弹出再压回」保持原序而陷入死循环。
|
||||
async fn resolve_dispatchable_chain(
|
||||
db: &Database,
|
||||
workflow_name: &str,
|
||||
params: &GridPointParams,
|
||||
mut chain: Vec<String>,
|
||||
) -> Result<(Vec<String>, Option<String>)> {
|
||||
@@ -394,6 +395,36 @@ impl GridScheduler {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 稳定化种子步进(2026-08-18,docs/failed81_cno_seed_popzer_dpsilg_2026_08_18.md):
|
||||
// 仅在 exact_family(同 Teff/logg/logHe、仅 CNO 不同)内找种子——稳定化配方
|
||||
// (POPZER+DPSILG)的验证前提是种子与目标仅差丰度微扰,跨 Teff/logg 种子
|
||||
// 不在适用域。排除目标点自身名(防止把自己旧产物当种子)。
|
||||
// 2026-08-20 种子轮换:配方对种子逐点敏感(同距离换 N/换 O 邻居收敛性不同),
|
||||
// 排除本点历史任务已用过的种子,重试时轮换到下一个未试过的同族邻居。
|
||||
Some("seed_step_stab") => {
|
||||
let mut exclude = vec![params.model_name()];
|
||||
exclude.extend(db.list_used_seed_names(¶ms.model_name(), workflow_name).await?);
|
||||
let found_seed = db
|
||||
.find_exact_family_seed_from_db(params, &exclude)
|
||||
.await?;
|
||||
match found_seed {
|
||||
Some(seed) => {
|
||||
if !skipped.is_empty() {
|
||||
chain.extend(skipped);
|
||||
}
|
||||
return Ok((chain, Some(seed.name.clone())));
|
||||
}
|
||||
None if chain.len() > 1 => {
|
||||
let head = chain.remove(0);
|
||||
skipped.push(head);
|
||||
info!("策略解析:seed_step_stab 无同物理族 CNO 邻居种子,暂存顺位");
|
||||
}
|
||||
None => {
|
||||
chain.clear();
|
||||
return Ok((chain, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 空链或非 seed_step 顺位:可直接派发。先前跳过的 seed_step 追加到链尾,
|
||||
// 保留为后续回退顺位(空链由调用方判空处理)。
|
||||
_ => {
|
||||
@@ -561,7 +592,7 @@ impl GridScheduler {
|
||||
};
|
||||
let (dispatch_chain, seed_point_name) = if tlusty_cfg.enabled {
|
||||
let (chain, seed) =
|
||||
Self::resolve_dispatchable_chain(&self.db, ¶ms, base_chain).await?;
|
||||
Self::resolve_dispatchable_chain(&self.db, workflow_name, ¶ms, base_chain).await?;
|
||||
if chain.is_empty() {
|
||||
// enabled 阶段无可派发顺位(基础链全为无种子的 seed_step)→ 打回 pending,
|
||||
// 待近邻种子出现后由下轮调度自愈派发(不是终态,不能被卡死在 queued)。
|
||||
@@ -896,13 +927,6 @@ impl GridScheduler {
|
||||
popped,
|
||||
policy: row_policy,
|
||||
} = snap;
|
||||
if rest_strategies.is_empty() {
|
||||
info!(
|
||||
"策略回退:网格点 {} 的 {} 策略链已耗尽(弹出最后项 {}),保持 failed 终态",
|
||||
name, stage_label, popped
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 2026-08-04 语义修正:策略链回退**只由策略链驱动**(弹出失败首项、派发下一顺位,
|
||||
// 链耗尽保持 failed),不再受执行策略门控——策略只决定启动工作流时对历史终态点的
|
||||
@@ -929,6 +953,83 @@ impl GridScheduler {
|
||||
.await
|
||||
.unwrap_or((None, None, None, None, None, None, None, None));
|
||||
|
||||
// 2026-08-20 种子轮换:seed_step_stab 常为链上最后一项,失败弹出后链空。
|
||||
// 稳定化配方对种子逐点敏感(同 CNO 距离、换不同元素方向的邻居收敛性不同,
|
||||
// 见 docs/failed81_cno_seed_popzer_dpsilg_2026_08_18.md §九)——首个选中
|
||||
// 的邻居失败不代表配方无效。排除本点历史已用种子后若还有未试过的同族
|
||||
// 邻居,则以 seed_step_stab 单顺位重链重派。轮换次数天然受同族邻居数约束:
|
||||
// 全部试过后此处不再命中,落入下方 failed 终态,无死循环。
|
||||
if rest_strategies.is_empty() && failed_stage != "synspec" && popped == "seed_step_stab" {
|
||||
let mut exclude = vec![params.model_name()];
|
||||
exclude.extend(self.db.list_used_seed_names(name, workflow_name).await?);
|
||||
if let Some(fresh_seed) = self
|
||||
.db
|
||||
.find_exact_family_seed_from_db(params, &exclude)
|
||||
.await?
|
||||
{
|
||||
info!(
|
||||
"策略回退:工作流 {} 网格点 {} seed_step_stab 失败但存在未试过的同族邻居种子 {},轮换种子重派(已试过 {:?})",
|
||||
workflow_name, name, fresh_seed.name, &exclude[1..]
|
||||
);
|
||||
// 轮换任务显式注入新种子(绕过 resolve 的种子查找,避免其再次
|
||||
// 命中同一邻居)。
|
||||
let mut stab_cfg = tlusty_cfg.clone();
|
||||
stab_cfg.strategies = vec!["seed_step_stab".to_string()];
|
||||
stab_cfg.policy = row_policy.clone();
|
||||
let task_spec = TaskSpec {
|
||||
task_id: Uuid::new_v4(),
|
||||
point_name: name.to_string(),
|
||||
params: params.clone(),
|
||||
seed_point_name: Some(fresh_seed.name),
|
||||
timeout_sec,
|
||||
workflow_name: Some(workflow_name.to_string()),
|
||||
wave: 0,
|
||||
tlusty_config: stab_cfg,
|
||||
synspec_config: synspec_cfg.clone(),
|
||||
synspec_params,
|
||||
tlusty_chain_params: tlusty_chain.clone(),
|
||||
seed_chain_params: seed_chain.clone(),
|
||||
tlusty_input_params: tlusty_input.clone(),
|
||||
atmosphere_ref: None,
|
||||
energy_tolerance,
|
||||
temp_max_factor,
|
||||
temp_floor,
|
||||
temp_ceiling,
|
||||
emflux_tolerance,
|
||||
convergence_min_ratio,
|
||||
bfac_max,
|
||||
bfac_min,
|
||||
linelist: linelist.clone(),
|
||||
};
|
||||
self.db.insert_task(&task_spec).await?;
|
||||
self.db
|
||||
.update_grid_status(name, common::models::GridPointStatus::Queued, workflow_name)
|
||||
.await?;
|
||||
if let Err(e) = self.queue.push_task(&task_spec).await {
|
||||
let _ = self
|
||||
.db
|
||||
.update_grid_status(
|
||||
name,
|
||||
common::models::GridPointStatus::Pending,
|
||||
workflow_name,
|
||||
)
|
||||
.await;
|
||||
let _ = self.queue.remove_task(&task_spec.task_id.to_string()).await;
|
||||
let _ = self.db.delete_task(&task_spec.task_id).await;
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
if rest_strategies.is_empty() {
|
||||
info!(
|
||||
"策略回退:网格点 {} 的 {} 策略链已耗尽(弹出最后项 {}),保持 failed 终态",
|
||||
name, stage_label, popped
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// SYNSPEC 链回退:重试光谱合成。无邻居种子门控(大气来自目标点自身既有产物,
|
||||
// 见 docs/task_engine_decoupling_design.md §5)——旧实现把 synspec 失败误归因到
|
||||
// TLUSTY 链并做无意义的种子搜索(修复审查 #2)。
|
||||
@@ -1011,7 +1112,7 @@ impl GridScheduler {
|
||||
// pending_rest:resolve 前的基础剩余链(含全部 seed_step 顺位),H1 空链分支据此记录标记。
|
||||
let pending_rest = rest_strategies.clone();
|
||||
let (rest_strategies, seed_point_name) =
|
||||
Self::resolve_dispatchable_chain(&self.db, params, rest_strategies).await?;
|
||||
Self::resolve_dispatchable_chain(&self.db, workflow_name, params, rest_strategies).await?;
|
||||
if rest_strategies.is_empty() {
|
||||
// H1 修复:resolve_dispatchable_chain 仅在「剩余顺位全为无近邻种子的 seed_step」
|
||||
// 时返回空(调用方已在上方 line 790 排除了真耗尽)。此时**不能**保持 failed 终态:
|
||||
@@ -2909,6 +3010,7 @@ tlusty_stage:\n enabled: true\n policy: skip_converged\n strategies: [seed_st
|
||||
// 无种子 → 重复 seed_step 链应判空(不派发、不死循环)。
|
||||
let (chain, seed) = GridScheduler::resolve_dispatchable_chain(
|
||||
&db,
|
||||
"wf",
|
||||
¶ms,
|
||||
vec!["seed_step".to_string(), "seed_step".to_string()],
|
||||
)
|
||||
@@ -2921,6 +3023,7 @@ tlusty_stage:\n enabled: true\n policy: skip_converged\n strategies: [seed_st
|
||||
// 两个无种子 seed_step 保留为回退顺位且链首可派发。
|
||||
let (chain2, seed2) = GridScheduler::resolve_dispatchable_chain(
|
||||
&db,
|
||||
"wf",
|
||||
¶ms,
|
||||
vec![
|
||||
"seed_step".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user