Selaa lähdekoodia

native/dgpp: emit paths.resident_cache in cluster JSON; exempt Native deploy from multi-node-tp1

DGPP cluster JSON now always carries paths.resident_cache (from [dgpp], empty =
DGPP default) to match the engine's example contract. validate's multi-node-tp1
heuristic (required_nodes>1 with TP=1) is a false positive for head-coordinated
native engines (DGPP shards by its own world_size, not launcher TP/PP) — skip it
for deploy=native. Test asserts paths present. make check green.
Alexander Korolev 1 viikko sitten
vanhempi
sitoutus
5194805e77
3 muutettua tiedostoa jossa 22 lisäystä ja 2 poistoa
  1. 4 0
      src/config/recipe.rs
  2. 9 0
      src/native/mod.rs
  3. 9 2
      src/validate.rs

+ 4 - 0
src/config/recipe.rs

@@ -238,6 +238,10 @@ pub struct DgppConfig {
     /// written here. Default `~/dgpp`.
     #[serde(default)]
     pub dir: Option<String>,
+    /// DGPP `paths.resident_cache` (node-local resident weight cache dir);
+    /// empty = DGPP default. Emitted as `paths.resident_cache` in the JSON.
+    #[serde(default)]
+    pub resident_cache: Option<String>,
     /// The DGPP `engine` block, serialized verbatim into the cluster JSON.
     #[serde(default)]
     pub engine: HashMap<String, serde_json::Value>,

+ 9 - 0
src/native/mod.rs

@@ -79,6 +79,14 @@ pub fn generate_cluster_json(recipe: &Recipe, world_size: usize) -> Result<Strin
         serde_json::Value::from(http_port(recipe) as i64),
     );
     root.insert("http".into(), serde_json::Value::Object(http));
+    // `paths` always present (DGPP examples carry it); resident_cache empty =
+    // DGPP default.
+    let mut paths = serde_json::Map::new();
+    paths.insert(
+        "resident_cache".into(),
+        serde_json::Value::String(d.resident_cache.clone().unwrap_or_default()),
+    );
+    root.insert("paths".into(), serde_json::Value::Object(paths));
     Ok(serde_json::to_string_pretty(&serde_json::Value::Object(
         root,
     ))?)
@@ -288,6 +296,7 @@ mod tests {
         assert_eq!(json["engine"]["dflash_model"], "z-lab/Qwen3.8-27B-DFlash2");
         assert_eq!(json["http"]["port"], 18080);
         assert_eq!(json["http"]["bind_host"], "0.0.0.0");
+        assert_eq!(json["paths"]["resident_cache"], "");
     }
 
     #[test]

+ 9 - 2
src/validate.rs

@@ -21,7 +21,7 @@
 
 use std::path::{Path, PathBuf};
 
-use crate::config::{Config, Recipe, recipe_dirs};
+use crate::config::{Config, DeployTarget, Recipe, recipe_dirs};
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum Level {
@@ -108,7 +108,14 @@ fn check_recipe(name: &str, r: &Recipe, images_dirs: &[&Path], out: &mut Vec<Vio
         });
     }
     let multi = r.required_nodes.is_some_and(|n| n > 1);
-    if multi && r.tensor_parallel_size == 1 && r.pipeline_parallel_size.unwrap_or(1) == 1 {
+    // Native (head-coordinated, config-driven) engines like DGPP shard by their
+    // own `world_size`, not launcher TP/PP flags — the TP=1 heuristic is a
+    // false positive there.
+    if multi
+        && r.deploy != DeployTarget::Native
+        && r.tensor_parallel_size == 1
+        && r.pipeline_parallel_size.unwrap_or(1) == 1
+    {
         out.push(Violation {
             recipe: name.to_string(),
             level: Level::Warning,