Bläddra i källkod

flare: mirror blob-store packages with hardlinks; adopt an already-downloaded package (0.2.6)

The gb10 package moved to the format-2 blob store (blobs/<sha> + hardlinked
models/<version>). mirror_cmd copied dirname(package) with rsync -a, which
expanded every hardlink: a 488 GB package became a second full 488 GB copy.
Mirror the store root with -aH instead, never --delete a store root, and probe
companions inside the package directory in both layouts.

Also adopt a store filled by a plain `flare download` (no mirror marker) via
`flare models list --json`, accepting only a single <revision>-tp<N> match.
Alexander Korolev 1 dag sedan
förälder
incheckning
017fa761f2
7 ändrade filer med 515 tillägg och 51 borttagningar
  1. 22 0
      CHANGELOG.md
  2. 1 1
      Cargo.lock
  3. 1 1
      Cargo.toml
  4. 116 0
      specs/tech-architecture/flare-bringup.md
  5. 44 32
      src/native/flare.rs
  6. 195 17
      src/native/flare_package.rs
  7. 136 0
      src/native/flare_tests.rs

+ 22 - 0
CHANGELOG.md

@@ -3,6 +3,28 @@
 Semantic versioning for the launcher CLI (`sm121`). The add-on image has its
 own version and its own `sm121/CHANGELOG.md`; do not mix them.
 
+## 0.2.6 — 2026-11-02
+
+- **FLARE package mirroring survives the new package format.** Current
+  (`format 2`) packages are blob stores: `blobs/<sha>` holds the data once and
+  `models/<version>/{model.safetensors,weights/,deployments/}` are hardlinks
+  into it. The mirror copied `dirname(package)` with `rsync -a`, so it expanded
+  every link — a 488 GB package produced a **second full copy** instead of a
+  mirror. It now mirrors the store root with `rsync -aH` and only prunes a flat
+  package's dedicated directory (`--delete` on a store root would drop every
+  other prepared model). A `$HOME`-relative `local_dir` also stays expandable
+  (the shell quoting used to leave a literal `$HOME`).
+- **An already-downloaded package is adopted, not re-verified.** A store filled
+  by a plain `flare download` carries no mirror marker, so every serve repeated
+  the 500 GB verification pass; the package is now resolved from
+  `flare models list --json`, and only when exactly one prepared version matches
+  `<revision>-tp<N>` (two candidates mean download — never guess, a wrong pick
+  serves the wrong model silently).
+- Companion probing is done inside the package's own directory in both layouts
+  (a blob store has no `weights/` at the mirror root).
+- Detail + measurements: `specs/tech-architecture/flare-bringup.md`
+  ("Package distribution: CLI store vs agent cache").
+
 ## 0.2.5 — 2026-10-29
 
 - **Image sync now waits for the unpack.** Every DGX Spark node uses the

+ 1 - 1
Cargo.lock

@@ -2941,7 +2941,7 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
 
 [[package]]
 name = "sm121"
-version = "0.2.5"
+version = "0.2.6"
 dependencies = [
  "anyhow",
  "axum",

+ 1 - 1
Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "sm121"
-version = "0.2.5"
+version = "0.2.6"
 edition = "2024"
 license = "MIT"
 

+ 116 - 0
specs/tech-architecture/flare-bringup.md

@@ -143,3 +143,119 @@ commits in 14 hours):
 - The DeepSeek side keeps moving too: `Preset DeepSeek V4.1 packed GPU
   speculation`, `Add a serving option for adaptive verification scoring alpha`,
   `Resume preparation checkpoints and share compiled forwards across ranks`.
+
+## Package distribution: CLI store vs agent cache (measured 2026-11-02)
+
+The gb10 package on the `local-inference-lab` HF repo was re-cut (`format 2`,
+blob store) and is now prepared **and distributed** differently from the 2026-10-22
+build. What follows is measured, not inferred — the numbers come from two live
+4-node lanes (`prod4` = dgx1–4 with dgx4 as controller+rank 0, `sparks` = dgx5–8
+with dgx4 as controller only).
+
+### Two stores, and only one of them is configurable
+
+```
+HF repo ──► `flare download` ──► CLI store   (paths.package_cache)
+                                     │  source for staging
+                                     ▼
+                              `orbit run` ──► agent cache, per node
+                                (~/.cache/flare/packages/<sha256>-<size>/)
+```
+
+- `paths.package_cache` (config) moves the **CLI** store. The **agent** store is
+  a separate location (`~/.cache/flare/packages`) that this key does not move;
+  the launched rank receives it as `--package-cache`. Budget both.
+- A `format 2` package is a blob store: `blobs/<sha>.safetensors` holds the data
+  once and `models/<version>/{model.safetensors,weights/,deployments/}` are
+  **hardlinks** into it (link count 2). Per-version data is not self-contained —
+  copying `models/<version>` alone with a hardlink-blind tool expands every link
+  and duplicates the whole package.
+- `orbit run` stages data **through the ranks**: the complete package goes to
+  rank 0 first, then rank 0 relays to its peers over the fabric (`fabric FETCH`,
+  "upstream hop"). The `gx10-dgx5: sending …` log lines name the hop's source,
+  not the receiver — a rank-0 line is not a node copying to itself.
+
+### Measured footprint per node (gb10, 488 GB package, TP4)
+
+| role | agent cache | contents |
+|---|---|---|
+| rank 0 (seed) | **488,241 MB** | the complete package |
+| rank 1–3 | **267,111 MB** each | 183 GB shared Engram tables + ~84 GB own rank slice |
+
+The Engram tables are duplicated on every rank **by design** (rows are read per
+request at token time), so ~183 GB/node is not reclaimable.
+
+### The duplicate on a controller that is also rank 0
+
+`prod4` runs on dgx4 (2 TB): CLI store 488 GB **plus** agent cache 488 GB =
+**976 GB**, because the same machine must both stage (CLI store) and serve
+(agent cache). `sparks` (dgx5–8, 916 GB disks) has no CLI store and therefore no
+duplication:
+
+| node | role | used | free |
+|---|---|---|---|
+| dgx5 | rank 0 | 615 GB | **255 GB** |
+| dgx6/7/8 | rank 1–3 | ~396 GB | ~473 GB |
+
+So a 916 GB Spark is a perfectly good FLARE rank — including rank 0 — as long as
+it is not also the controller's staging store.
+
+### Removing the duplicate: source the package from a node
+
+`orbit run` accepts `NODE:/absolute/path` as the package argument ("A Hugging
+Face repository, local package path, or NODE:/absolute/path"), and the agent
+cache directory (`<cache>/packages/<sha256>-<size>/`) has exactly the flat
+package layout, so rank 0's own copy can seed the launch:
+
+```bash
+flare orbit run gx10-dgx5:/home/kilork/.cache/flare/packages/<id>/model.safetensors \
+  --cluster sparks --name dsv41-flare-sparks --detach …
+```
+
+Verified: a real path passes package verification and fails only on GPU
+occupancy, while a bogus path fails earlier with `cannot stat package file`. With
+that form the controller needs no CLI store at all (dgx4's 488 GB becomes
+reclaimable once a node holds the package).
+
+### Launcher fixes this brought (0.2.6)
+
+- `mirror_cmd` is layout-aware: a blob store mirrors its **store root** with
+  `rsync -aH` (hardlinks preserved) and **without** `--delete` (that root holds
+  every other prepared package); a flat package keeps a dedicated destination
+  and prunes. Before this, mirroring expanded the links — a 488 GB package
+  produced a second full copy rather than a mirror.
+- `local_package` no longer requires the mirror marker: a store populated by a
+  plain `flare download` is adopted via `flare models list --json`, but only when
+  exactly **one** prepared version matches `<revision>-tp<N>` (two candidates
+  mean "download", never guess).
+- companion probing happens inside the package's own directory in both layouts
+  (it used to probe the mirror root, which a blob store does not have).
+
+## Re-pairing an orbit without the old controller (2026-11-02)
+
+An orbit node only accepts a controller listed in its
+`~/.config/flare/agent/controllers.toml`, and that record is **signed by the
+pairing controller** — a node that trusts `gx10-dgx5` refuses `gx10-dgx4` with
+`<key> is not an authorized controller of this node`, and `orbit controllers add`
+cannot be run by the un-authorized controller (it fails with "this controller is
+not in the controller set"). With dgx5 powered off (NAS failure) the only path
+was a clean re-pair, which is safe as long as no group is running on that orbit:
+
+```bash
+# on each node (keeps the key and the package cache)
+flare agent reset
+flare agent install --accept-first
+
+# on the new controller — the HOSTS are resolved by name, so pass real hostnames
+flare orbit pair dgx1.lan dgx2.lan dgx3.lan dgx4.lan
+```
+
+Two practical notes:
+
+- `orbit pair` resolves its `HOST` arguments through DNS **and** rewrites the
+  node's address in `orbit.toml`; a short name that only resolves on some nodes
+  (`gx10-dgx1` instead of `dgx1.lan`) fails with "Temporary failure in name
+  resolution". Use the FQDN form.
+- Rank order comes from `[cluster.<name>].nodes` in `orbit.toml`, and it decides
+  who is rank 0 — the node that receives the complete package and serves the
+  API. On a disk-constrained set put the roomiest node first.

+ 44 - 32
src/native/flare.rs

@@ -264,26 +264,49 @@ pub fn preflight_cmd(config: &Config, orbit_cluster: &str, controller: bool) ->
     }
 }
 
-/// Mirror a package's files into the controller's local dir and return the
-/// local primary path.
+/// A path for a shell command: a leading `$HOME` stays expandable (double
+/// quotes) while everything else is single-quoted.
+pub(crate) fn shell_path(p: &str) -> String {
+    match p.strip_prefix("$HOME") {
+        Some(rest) => format!("\"$HOME{}\"", rest.replace('"', "\\\"")),
+        None => shq(p),
+    }
+}
+
+/// Mirror a package into the controller's local dir and return the local
+/// primary path.
+///
+/// The source is the package's **store root**, not `dirname(package)`: a
+/// current (`format 2`) package lives in a blob store, where `blobs/<sha>`
+/// holds the bytes once and `models/<version>/{model.safetensors,weights,…}`
+/// are hardlinks into it. Two consequences, both measured on the 488 GB gb10
+/// package:
 ///
-/// FLARE names every companion by its sha256, so "present and the same size"
-/// is a sound consistency check — a truncated or stale file re-copies, and an
-/// unchanged package costs a `stat` per file. The primary (metadata) is tiny
-/// and always refreshed.
+/// * the copy must keep hardlinks (`rsync -aH`) — a hardlink-blind copy
+///   expands every link and duplicates the whole package instead of mirroring
+///   it;
+/// * it must not `--delete` the destination root, which holds every other
+///   prepared package in the same store.
+///
+/// A flat (legacy) package is a self-contained directory, so the destination
+/// is dedicated to it and `--delete` still prunes stale companions.
 pub fn mirror_cmd(local_dir: &str, remote_pkg: &str) -> String {
-    let dir = shq(local_dir);
-    let pkg = shq(remote_pkg);
-    // New packages keep companion data in nested `weights/` and
-    // `deployments/` directories, so a flat file loop is wrong: copy the
-    // package directory recursively, and skip the copy when the cache root
-    // is already the package directory itself.
+    use crate::native::flare_package::{Layout, layout_of, mirror_destination, mirror_source};
+    let src = mirror_source(remote_pkg);
+    let dst = shell_path(local_dir);
+    let dest_pkg = shell_path(&mirror_destination(local_dir, remote_pkg));
+    let (flags, prune) = match layout_of(remote_pkg) {
+        Layout::BlobStore => ("-aH", ""),
+        Layout::Flat => ("-aH", " --delete"),
+    };
     format!(
-        "set -e; src=$(dirname {pkg}); dst={dir}; \
-         if [ \"$src\" = \"$dst\" ]; then echo {pkg}; exit 0; fi; \
+        "set -e; src={}; dst={}; \
+         if [ \"$src\" = \"$dst\" ]; then echo {dest_pkg}; exit 0; fi; \
          mkdir -p \"$dst\"; \
-         rsync -a --delete --exclude '.sm121-flare-package.json' \"$src\"/ \"$dst\"/; \
-         echo \"$dst/$(basename {pkg})\""
+         rsync {flags}{prune} --exclude '.sm121-flare-package.json' \"$src\"/ \"$dst\"/; \
+         echo {dest_pkg}",
+        shq(&src),
+        dst,
     )
 }
 
@@ -359,23 +382,12 @@ pub async fn serve(
             let out = crate::ssh::run_ssh_long_running(config, controller, dl, dry_run).await?;
             package = parse_package_path(&out).unwrap_or_default();
             // A cached download prints only "Resolved package: … / model.safetensors"
-            // and no final path; resolve the default prepared model from Flare's
-            // model cache instead of failing after a successful download.
+            // and no final path; resolve the prepared package from the Flare
+            // store instead of failing after a successful download.
             if package.is_empty() {
-                let cache_cmd = format!(
-                    "{} models list --json 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); m=d.get(\"models\") or []; vers=(m[0].get(\"versions\") or []) if m else []; v=vers[0] if vers else dict(); print(d.get(\"cache\",\"\") + \"/models/\" + m[0].get(\"model_key\",\"\") + \"/\" + v.get(\"version\",\"\"))'",
-                    binary(config)
-                );
-                let dir = crate::ssh::run_ssh(config, controller, cache_cmd, false).await?;
-                let dir = dir.trim();
-                if !dir.is_empty() {
-                    let find = format!(
-                        "find {} -maxdepth 1 -name '*.safetensors' -print -quit",
-                        shq(dir)
-                    );
-                    let primary = crate::ssh::run_ssh(config, controller, find, false).await?;
-                    package = primary.trim().to_string();
-                }
+                package = crate::native::flare_package::cached_package(config, recipe, controller)
+                    .await?
+                    .unwrap_or_default();
             }
             if package.is_empty() {
                 bail!(

+ 195 - 17
src/native/flare_package.rs

@@ -57,6 +57,76 @@ fn marker_path(dir: &str) -> String {
     format!("{}/.sm121-flare-package.json", dir.trim_end_matches('/'))
 }
 
+/// A prepared package has two on-disk layouts and both must be handled:
+///
+/// * **blob store** (current `flare download`, format 2):
+///   `<root>/blobs/<sha>.safetensors` holds the data once, and
+///   `<root>/models/<version>/model.safetensors` + `weights/` + `deployments/`
+///   are **hardlinks** into `blobs/`. Copying only `models/<version>` with a
+///   hardlink-blind tool expands the links and duplicates the whole package
+///   (measured: a 488 GB package becomes 488 GB again, not a subset).
+/// * **flat** (legacy self-contained package, and the agents' own cache):
+///   `<version>/model.safetensors` sits beside its `weights/` and
+///   `deployments/` directories.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Layout {
+    BlobStore,
+    Flat,
+}
+
+/// Segment that separates a blob store's model versions from its root.
+const MODELS: &str = "models";
+
+/// Which layout a package path lives in, judged by its `/models/` segment.
+pub fn layout_of(package: &str) -> Layout {
+    let mut parts = package.trim_end_matches('/').rsplit('/');
+    // …/<root>/models/<version>/model.safetensors — skip the file and version
+    let _file = parts.next();
+    let _version = parts.next();
+    match parts.next() {
+        Some(MODELS) => Layout::BlobStore,
+        _ => Layout::Flat,
+    }
+}
+
+/// Directory to copy when mirroring a package: the whole blob store (so the
+/// hardlinks stay links), or the package directory itself for a flat package.
+pub fn mirror_source(package: &str) -> String {
+    let trimmed = package.trim_end_matches('/');
+    match layout_of(trimmed) {
+        Layout::BlobStore => {
+            // strip `models/<version>/model.safetensors`
+            let mut parts = trimmed.rsplitn(4, '/');
+            let _ = (parts.next(), parts.next(), parts.next());
+            parts
+                .next()
+                .map(str::to_string)
+                .unwrap_or_else(|| "/".to_string())
+        }
+        Layout::Flat => trimmed
+            .rsplit_once('/')
+            .map(|(dir, _)| dir.to_string())
+            .unwrap_or_else(|| ".".to_string()),
+    }
+}
+
+/// The package path inside a mirror rooted at `dir`: the path relative to
+/// [`mirror_source`] keeps a blob store's `models/<version>/…` prefix.
+pub fn mirror_destination(dir: &str, package: &str) -> String {
+    let src = mirror_source(package);
+    let rel = package
+        .trim_end_matches('/')
+        .strip_prefix(&format!("{src}/"))
+        .unwrap_or_else(|| {
+            package
+                .trim_end_matches('/')
+                .rsplit_once('/')
+                .map(|(_, name)| name)
+                .unwrap_or(package)
+        });
+    format!("{}/{rel}", dir.trim_end_matches('/'))
+}
+
 /// Current prepared versions in Flare's cache (`flare models list --json`).
 /// The package version is a directory name; comparing it catches a re-cut
 /// package under the same revision (the stale-NFS class, but for a package).
@@ -84,25 +154,108 @@ async fn current_versions(config: &Config, controller: &Node) -> Result<Vec<Stri
 }
 
 /// Test that a local mirror is complete enough to launch: the primary
-/// `model.safetensors`, the `weights/` companion and every rank deployment.
-async fn local_files_present(
-    config: &Config,
-    controller: &Node,
-    dir: &str,
-    package: &str,
-) -> Result<bool> {
-    let cmd = format!(
+/// `model.safetensors`, the `weights/` companion and every rank deployment,
+/// plus the `blobs/` store when the package uses the blob layout.
+///
+/// The companions live beside the primary in **both** layouts, so the
+/// package's own directory is the one to probe — the mirror root is not.
+async fn local_files_present(config: &Config, controller: &Node, package: &str) -> Result<bool> {
+    let pkg = package.trim_end_matches('/');
+    let dir = pkg
+        .rsplit_once('/')
+        .map(|(d, _)| d.to_string())
+        .unwrap_or_default();
+    let mut cmd = format!(
         "test -f {} && test -d {}/weights && test -d {}/deployments",
-        shq(package),
-        shq(dir),
-        shq(dir)
+        shq(pkg),
+        shq(&dir),
+        shq(&dir)
     );
+    if layout_of(pkg) == Layout::BlobStore {
+        // The blobs hold the bytes the hardlinked companions point at.
+        cmd.push_str(&format!(" && test -d {}/blobs", shq(&mirror_source(pkg))));
+    }
     match crate::ssh::run_ssh(config, controller, cmd, false).await {
         Ok(_) => Ok(true),
         Err(_) => Ok(false),
     }
 }
 
+/// Resolve the prepared package an existing `flare download` left in the
+/// node's store: `<cache>/models/<model_key>/<version>/model.safetensors`.
+///
+/// `flare models list --json` names the cache root, the model key and the
+/// current version, so a store populated by an earlier serve (or by the
+/// operator by hand) is adopted without a second 500 GB verification pass —
+/// the same short-circuit the marker gives a mirror.
+///
+/// The model key is the checkpoint's own identity (`checkpoint-expanded-scales`
+/// for the gb10 package), not the recipe's repo name, so the match is made on
+/// the version: prepared versions are named `<hardware>-tp<N>-<stamp>`, and
+/// only a version carrying **our** revision and TP size may be adopted. Any
+/// other — or more than one — candidate means "download it".
+pub async fn cached_package(
+    config: &Config,
+    recipe: &Recipe,
+    node: &Node,
+) -> Result<Option<String>> {
+    let id = package_id(recipe)?;
+    let cmd = format!(
+        "{} models list --json 2>/dev/null",
+        crate::native::flare::binary(config)
+    );
+    let out = match crate::ssh::run_ssh(config, node, cmd, false).await {
+        Ok(o) => o,
+        Err(_) => return Ok(None),
+    };
+    let Ok(v) = serde_json::from_str::<serde_json::Value>(&out) else {
+        return Ok(None);
+    };
+    let cache = v.get("cache").and_then(|c| c.as_str()).unwrap_or_default();
+    if cache.is_empty() {
+        return Ok(None);
+    }
+    let prefix = format!("{}-tp{}", id.revision, id.tensor_parallel);
+    Ok(select_cached(cache, &v, &prefix))
+}
+
+/// Pick the single prepared version whose name starts with `prefix` (our
+/// hardware revision and TP size) out of a `flare models list --json` value.
+///
+/// One unambiguous candidate only: adopting a different package would serve
+/// the wrong model with no error at all, so two matches mean "download it".
+pub fn select_cached(cache: &str, listing: &serde_json::Value, prefix: &str) -> Option<String> {
+    let mut found: Vec<String> = Vec::new();
+    for model in listing
+        .get("models")
+        .and_then(|m| m.as_array())
+        .map(Vec::as_slice)
+        .unwrap_or_default()
+    {
+        let key = model
+            .get("model_key")
+            .and_then(|k| k.as_str())
+            .unwrap_or_default();
+        for ver in model
+            .get("versions")
+            .and_then(|x| x.as_array())
+            .map(Vec::as_slice)
+            .unwrap_or_default()
+        {
+            let Some(name) = ver.get("version").and_then(|x| x.as_str()) else {
+                continue;
+            };
+            if name.starts_with(prefix) {
+                found.push(format!("{cache}/models/{key}/{name}/model.safetensors"));
+            }
+        }
+    }
+    match found.len() {
+        1 => found.pop(),
+        _ => None,
+    }
+}
+
 /// The local package path if the marker matches the recipe identity and the
 /// current prepared version. `None` means a download/mirror pass is needed.
 pub async fn local_package(
@@ -111,12 +264,37 @@ pub async fn local_package(
     cluster: &str,
     controller: &Node,
 ) -> Result<Option<String>> {
-    let Some(dir) = crate::native::flare::local_dir_for(config, cluster) else {
-        return Ok(None);
-    };
-    let dir = dir.replace('~', "$HOME");
+    if let Some(dir) = crate::native::flare::local_dir_for(config, cluster) {
+        let dir = dir.replace('~', "$HOME");
+        if let Some(pkg) = marked_package(config, recipe, controller, &dir).await? {
+            return Ok(Some(pkg));
+        }
+    }
+    // No usable mirror marker — but the store may already hold the current
+    // version (a plain `flare download` into `paths.package_cache` leaves no
+    // marker). Adopt it instead of re-verifying 500 GB.
+    if let Some(pkg) = cached_package(config, recipe, controller).await?
+        && local_files_present(config, controller, &pkg).await?
+    {
+        tracing::info!(
+            "FLARE package already prepared on {}: {pkg}",
+            controller.name
+        );
+        return Ok(Some(pkg));
+    }
+    Ok(None)
+}
+
+/// The package path recorded by a previous mirror, when the marker still
+/// matches the recipe and the files are intact.
+async fn marked_package(
+    config: &Config,
+    recipe: &Recipe,
+    controller: &Node,
+    dir: &str,
+) -> Result<Option<String>> {
     let id = package_id(recipe)?;
-    let mp = marker_path(&dir);
+    let mp = marker_path(dir);
     let read = format!("test -f {} && cat {}", shq(&mp), shq(&mp));
     let out = match crate::ssh::run_ssh(config, controller, read, false).await {
         Ok(o) => o,
@@ -135,7 +313,7 @@ pub async fn local_package(
         // Same revision, but the lab re-cut the package: the mirror is stale.
         return Ok(None);
     }
-    if !local_files_present(config, controller, &dir, &marker.package).await? {
+    if !local_files_present(config, controller, &marker.package).await? {
         return Ok(None);
     }
     Ok(Some(marker.package))

+ 136 - 0
src/native/flare_tests.rs

@@ -184,3 +184,139 @@ fn missing_block_is_an_error() {
     r.flare = None;
     assert!(download_cmd(&cfg(), &r).is_err());
 }
+
+// ── package mirroring: blob store vs flat ────────────────────────────────────
+// A current (`format 2`) package stores its data once in `blobs/` and
+// hardlinks `models/<version>/…` into it. Mirroring `dirname(package)` with a
+// hardlink-blind rsync expanded every link and duplicated the whole package
+// (measured: 488 GB became 488 GB again), and `--delete` on that root would
+// drop every other prepared model in the same store.
+
+use crate::native::flare_package::{Layout, layout_of, mirror_destination, mirror_source};
+
+const BLOB_PKG: &str = "/home/u/flare-pkgs/gb10/models/gb10-tp4-202611021809/model.safetensors";
+const FLAT_PKG: &str = "/home/u/.cache/flare/packages/7cf40bec-35842073/model.safetensors";
+
+#[test]
+fn layout_is_read_from_the_models_segment() {
+    assert_eq!(layout_of(BLOB_PKG), Layout::BlobStore);
+    assert_eq!(layout_of(FLAT_PKG), Layout::Flat);
+    // the agents' own cache keeps the flat layout even with a long version dir
+    assert_eq!(
+        layout_of("/c/packages/abc-123/model.safetensors"),
+        Layout::Flat
+    );
+}
+
+#[test]
+fn mirror_source_is_the_store_root_for_a_blob_store() {
+    assert_eq!(mirror_source(BLOB_PKG), "/home/u/flare-pkgs/gb10");
+    // a flat package is self-contained: its own directory is the source
+    assert_eq!(
+        mirror_source(FLAT_PKG),
+        "/home/u/.cache/flare/packages/7cf40bec-35842073"
+    );
+}
+
+#[test]
+fn mirror_destination_keeps_the_version_prefix() {
+    // the mirrored package must stay at `<dst>/models/<version>/model.safetensors`
+    assert_eq!(
+        mirror_destination("/data/flare", BLOB_PKG),
+        "/data/flare/models/gb10-tp4-202611021809/model.safetensors"
+    );
+    assert_eq!(
+        mirror_destination("/data/flare", FLAT_PKG),
+        "/data/flare/model.safetensors"
+    );
+}
+
+#[test]
+fn blob_store_mirror_preserves_hardlinks_and_never_prunes() {
+    let cmd = mirror_cmd("/data/flare", BLOB_PKG);
+    assert!(cmd.contains("rsync -aH "), "{cmd}");
+    assert!(!cmd.contains("--delete"), "{cmd}");
+    assert!(cmd.contains("src='/home/u/flare-pkgs/gb10'"), "{cmd}");
+    assert!(
+        cmd.contains("echo '/data/flare/models/gb10-tp4-202611021809/model.safetensors'"),
+        "{cmd}"
+    );
+}
+
+#[test]
+fn flat_mirror_is_dedicated_so_it_prunes() {
+    let cmd = mirror_cmd("/data/flare", FLAT_PKG);
+    assert!(cmd.contains("rsync -aH --delete "), "{cmd}");
+    assert!(
+        cmd.contains("echo '/data/flare/model.safetensors'"),
+        "{cmd}"
+    );
+}
+
+#[test]
+fn mirror_skips_the_copy_when_the_package_already_is_the_destination() {
+    // config `local_dir` == `paths.package_cache`: source and destination are
+    // the same directory, so the 488 GB check must short-circuit
+    let cmd = mirror_cmd("/home/u/flare-pkgs/gb10", BLOB_PKG);
+    assert!(cmd.contains("if [ \"$src\" = \"$dst\" ]"), "{cmd}");
+}
+
+#[test]
+fn a_home_relative_mirror_root_stays_expandable() {
+    let cmd = mirror_cmd("$HOME/flare-pkgs/gb10", BLOB_PKG);
+    // double quotes so the remote shell expands $HOME; single quotes would
+    // leave a literal "$HOME" path behind
+    assert!(cmd.contains("dst=\"$HOME/flare-pkgs/gb10\""), "{cmd}");
+    assert!(
+        cmd.contains(
+            "echo \"$HOME/flare-pkgs/gb10/models/gb10-tp4-202611021809/model.safetensors\""
+        ),
+        "{cmd}"
+    );
+}
+
+// ── adopting an already-downloaded package ──────────────────────────────────
+
+use crate::native::flare_package::select_cached;
+
+fn listing(versions: &[(&str, &str)]) -> serde_json::Value {
+    let models: Vec<serde_json::Value> = versions
+        .iter()
+        .map(|(key, version)| {
+            serde_json::json!({
+                "model_key": key,
+                "versions": [{"version": version}],
+            })
+        })
+        .collect();
+    serde_json::json!({"cache": "/store", "models": models})
+}
+
+#[test]
+fn a_single_matching_version_is_adopted() {
+    let v = listing(&[("checkpoint-expanded-scales", "gb10-tp4-202611021809")]);
+    assert_eq!(
+        select_cached("/store", &v, "gb10-tp4").as_deref(),
+        Some("/store/models/checkpoint-expanded-scales/gb10-tp4-202611021809/model.safetensors")
+    );
+}
+
+#[test]
+fn another_hardware_or_tp_size_is_not_adopted() {
+    // gb202 package, and a TP8 cut of our own revision: neither is ours
+    let v = listing(&[
+        ("checkpoint", "gb202-tp4-202610010000"),
+        ("checkpoint", "gb10-tp8-202610010000"),
+    ]);
+    assert_eq!(select_cached("/store", &v, "gb10-tp4"), None);
+}
+
+#[test]
+fn two_candidates_are_refused() {
+    // a re-cut left both versions: guessing would serve the wrong one
+    let v = listing(&[
+        ("checkpoint", "gb10-tp4-202611021809"),
+        ("checkpoint", "gb10-tp4-202610312359"),
+    ]);
+    assert_eq!(select_cached("/store", &v, "gb10-tp4"), None);
+}