use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::sync::atomic::{AtomicU32, Ordering};
static COUNTER: AtomicU32 = AtomicU32::new(0);
struct Sandbox {
base: PathBuf,
source: PathBuf,
mind_home: PathBuf,
claude_home: PathBuf,
}
struct Run {
stdout: String,
stderr: String,
success: bool,
}
impl Sandbox {
fn new(name: &str) -> Sandbox {
Sandbox::build(name, true)
}
fn bare(name: &str) -> Sandbox {
Sandbox::build(name, false)
}
fn build(name: &str, with_items: bool) -> Sandbox {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let base = std::env::temp_dir().join(format!("mind-dump-{}-{n}", std::process::id()));
let _ = std::fs::remove_dir_all(&base);
let source = base.join(name);
let sb = Sandbox {
base: base.clone(),
source: source.clone(),
mind_home: base.join("mind"),
claude_home: base.join("claude"),
};
if with_items {
write_file(
&source.join("skills/review/SKILL.md"),
"---\nname: review\ndescription: Review skill\n---\n# review\n",
);
write_file(
&source.join("agents/dev.md"),
"---\nname: dev\ndescription: Dev agent\n---\n# dev\n",
);
write_file(
&source.join("rules/style.md"),
"---\ndescription: Style rule\n---\n# style\n",
);
} else {
write_file(&source.join("README.md"), "# registry\n");
}
git_init(&source);
sb
}
fn source_spec(&self) -> String {
self.source.to_string_lossy().into_owned()
}
fn link(&self, tail: &str) -> String {
format!("file://{}/{tail}", self.source.to_string_lossy())
}
fn mind(&self, args: &[&str]) -> Run {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_mind"));
cmd.args(args)
.env("MIND_HOME", &self.mind_home)
.env("CLAUDE_HOME", &self.claude_home)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null());
let out = cmd.output().expect("run mind");
Run {
stdout: String::from_utf8_lossy(&out.stdout).into_owned(),
stderr: String::from_utf8_lossy(&out.stderr).into_owned(),
success: out.status.success(),
}
}
fn write_and_commit(&self, rel: &str, contents: &str) {
write_file(&self.source.join(rel), contents);
git_commit(&self.source);
}
}
impl Drop for Sandbox {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.base);
}
}
fn write_file(path: &Path, contents: &str) {
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, contents).unwrap();
}
fn git_init(dir: &Path) {
for args in [
vec!["-c", "init.defaultBranch=main", "init", "-q"],
vec!["config", "user.email", "t@t"],
vec!["config", "user.name", "t"],
vec!["add", "-A"],
vec!["commit", "-qm", "initial"],
] {
let status = Command::new("git")
.args(&args)
.current_dir(dir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.expect("run git");
assert!(status.success(), "git {args:?} in {dir:?}");
}
}
fn git_commit(dir: &Path) {
for args in [vec!["add", "-A"], vec!["commit", "-qm", "fixture"]] {
let _ = Command::new("git")
.args(&args)
.current_dir(dir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
}
}
fn git_tag(dir: &Path, tag: &str) {
let status = Command::new("git")
.args(["tag", tag])
.current_dir(dir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.expect("run git tag");
assert!(status.success(), "git tag {tag} in {dir:?}");
}
fn git_move_tag(dir: &Path, tag: &str) {
let status = Command::new("git")
.args(["tag", "-f", tag])
.current_dir(dir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.expect("run git tag -f");
assert!(status.success(), "git tag -f {tag} in {dir:?}");
}
fn git_head(dir: &Path) -> String {
let out = Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(dir)
.output()
.expect("git rev-parse");
String::from_utf8_lossy(&out.stdout).trim().to_string()
}
#[test]
fn dump_empty_registry_produces_valid_super_source() {
let sb = Sandbox::bare("empty");
let r = sb.mind(&["dump"]);
assert!(
r.success,
"dump with no melded sources must exit 0: {} {}",
r.stdout, r.stderr
);
let toml_text = &r.stdout;
assert!(
toml_text.contains("discover"),
"must contain discover section: {toml_text}"
);
assert!(
toml_text.contains("description"),
"must carry [source].description: {toml_text}"
);
assert!(
!toml_text.contains("[[discover.sources]]"),
"no source entries should appear when registry is empty: {toml_text}"
);
}
#[test]
fn dump_writes_to_stdout_by_default() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump must succeed: {} {}", r.stdout, r.stderr);
assert!(!r.stdout.is_empty(), "dump must write to stdout by default");
assert!(
r.stdout.contains("discover"),
"stdout must contain discover section: {}",
r.stdout
);
}
#[test]
fn dump_output_flag_writes_to_file() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let out_path = sb.base.join("dump.toml");
let out_str = out_path.to_string_lossy().into_owned();
let r = sb.mind(&["dump", "--output", &out_str]);
assert!(
r.success,
"dump --output must succeed: {} {}",
r.stdout, r.stderr
);
assert!(
r.stdout.is_empty(),
"stdout must be empty when --output is given: {}",
r.stdout
);
let content = std::fs::read_to_string(&out_path).expect("output file must exist");
assert!(
content.contains("discover"),
"output file must contain discover section: {content}"
);
assert!(
content.contains("description"),
"output file must carry [source].description: {content}"
);
}
#[test]
fn dump_all_installed_yields_install_true() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--yes"]);
assert!(meld.success, "meld failed: {} {}", meld.stdout, meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("install = true"),
"all items installed must emit install = true: {}",
r.stdout
);
assert!(
!r.stdout.contains("install-items"),
"must NOT emit install-items when all installed: {}",
r.stdout
);
}
#[test]
fn dump_none_installed_yields_install_false() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("install = false"),
"no items installed must emit install = false: {}",
r.stdout
);
assert!(
!r.stdout.contains("install-items"),
"must NOT emit install-items when none installed: {}",
r.stdout
);
assert!(
!r.stdout.contains("install-items = []"),
"empty install-items must never be emitted: {}",
r.stdout
);
}
#[test]
fn dump_proper_subset_yields_install_items() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let learn = sb.mind(&["learn", "skill:review"]);
assert!(
learn.success,
"learn skill:review failed: {} {}",
learn.stdout, learn.stderr
);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("install-items"),
"proper subset must emit install-items: {}",
r.stdout
);
assert!(
r.stdout.contains("skill:review"),
"install-items must contain skill:review: {}",
r.stdout
);
assert!(
!r.stdout.contains("agent:dev"),
"agent:dev (not installed) must not appear in install-items: {}",
r.stdout
);
assert!(
!r.stdout.contains("rule:style"),
"rule:style (not installed) must not appear in install-items: {}",
r.stdout
);
assert!(
!r.stdout.contains("install = true"),
"install = true must not be emitted with install-items: {}",
r.stdout
);
}
#[test]
fn dump_whole_sources_always_emits_install_true() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let learn = sb.mind(&["learn", "skill:review"]);
assert!(
learn.success,
"learn failed: {} {}",
learn.stdout, learn.stderr
);
let r = sb.mind(&["dump", "--whole-sources"]);
assert!(
r.success,
"dump --whole-sources failed: {} {}",
r.stdout, r.stderr
);
assert!(
r.stdout.contains("install = true"),
"--whole-sources must emit install = true: {}",
r.stdout
);
assert!(
!r.stdout.contains("install-items"),
"--whole-sources must NOT emit install-items: {}",
r.stdout
);
}
#[test]
fn dump_emits_alias_when_melded_with_as() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--as", "mypfx", "--link-only"]);
assert!(meld.success, "meld --as failed: {}", meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("namespace = \"mypfx\""),
"emitted entry must carry namespace = \"mypfx\" (DSC-78 canonical key): {}",
r.stdout
);
}
#[test]
fn dump_emits_roots_when_set() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--root", ".", "--link-only"]);
assert!(
meld.success,
"meld --root failed: {} {}",
meld.stdout, meld.stderr
);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("roots"),
"emitted entry must carry roots when set: {}",
r.stdout
);
}
#[test]
fn dump_install_items_are_bare_kind_name() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--as", "pfx", "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let learn = sb.mind(&["learn", "skill:pfx:review"]);
assert!(
learn.success,
"learn skill:pfx:review failed: {} {}",
learn.stdout, learn.stderr
);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("skill:review"),
"install_items must use bare kind:name (skill:review, not pfx:review): {}",
r.stdout
);
assert!(
!r.stdout.contains("skill:pfx:review"),
"prefixed name must NOT appear in install_items: {}",
r.stdout
);
}
#[test]
fn dump_dependency_item_is_in_install_items() {
let sb = Sandbox::bare("dep-src");
sb.write_and_commit(
"agents/dep.md",
"---\nname: dep\ndescription: Dependency agent\n---\n# dep\n",
);
sb.write_and_commit(
"skills/main/SKILL.md",
"---\nname: main\ndescription: Main skill\nrequires: agent:dep\n---\n# main\n",
);
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let learn = sb.mind(&["learn", "skill:main", "--yes"]);
assert!(
learn.success,
"learn skill:main failed: {} {}",
learn.stdout, learn.stderr
);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
let has_both_main_and_dep = r.stdout.contains("skill:main") && r.stdout.contains("agent:dep");
let has_install_true = r.stdout.contains("install = true");
assert!(
has_both_main_and_dep || has_install_true,
"dump must account for the dependency item (agent:dep): {}",
r.stdout
);
}
#[test]
fn dump_output_is_valid_super_source() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--yes"]);
assert!(meld.success, "meld failed: {} {}", meld.stdout, meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
let dump_path = sb.base.join("dumped.toml");
std::fs::write(&dump_path, &r.stdout).expect("write dump output");
let text = &r.stdout;
assert!(
text.contains("description"),
"must have [source].description: {text}"
);
assert!(
text.contains("discover"),
"must have discover section: {text}"
);
assert!(
!text.contains("[[items]]"),
"must NOT have [[items]] of its own: {text}"
);
}
#[test]
fn dump_roundtrip_remeld_reproduces_install_set() {
let src = Sandbox::new("original-src");
let meld = src.mind(&["meld", &src.source_spec(), "--link-only"]);
assert!(meld.success, "initial meld failed: {}", meld.stderr);
let learn = src.mind(&["learn", "skill:review"]);
assert!(
learn.success,
"learn failed: {} {}",
learn.stdout, learn.stderr
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = src.base.join(format!("super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super-source dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dump_r = src.mind(&["dump", "--output", &dump_path_str]);
assert!(
dump_r.success,
"dump --output failed: {} {}",
dump_r.stdout, dump_r.stderr
);
assert!(dump_path.exists(), "dump output file must exist");
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = src.base.join(format!("fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("create fresh base");
let fresh_mind_home = fresh_base.join("mind");
let fresh_claude_home = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind_home)
.env("CLAUDE_HOME", &fresh_claude_home)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run mind meld on dumped super-source");
let remeld_out = String::from_utf8_lossy(&remeld.stdout).into_owned();
let remeld_err = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(
remeld.status.success(),
"re-meld of dumped super-source failed: {remeld_out} {remeld_err}"
);
assert!(
fresh_claude_home.join("skills/review").exists(),
"skill:review must be installed in the reproduced environment: {:?}",
fresh_claude_home
);
assert!(
!fresh_claude_home.join("agents/dev.md").exists(),
"agent:dev (not in the subset) must NOT be installed in the reproduced environment"
);
assert!(
!fresh_claude_home.join("rules/style.md").exists(),
"rule:style (not in the subset) must NOT be installed in the reproduced environment"
);
}
#[test]
fn dump_of_a_curator_with_a_relative_nested_source_reproduces_it_absolutely() {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let curator = Sandbox::bare("dsc92-curator");
let nested = curator.base.join("nested-lib");
write_file(
&nested.join("skills/greet/SKILL.md"),
"---\nname: greet\ndescription: Greet skill\n---\n# greet\n",
);
git_init(&nested);
curator.write_and_commit(
"mind.toml",
"[[discover.sources]]\nsource = \"../nested-lib\"\ninstall = true\n",
);
let meld = curator.mind(&["meld", &curator.source_spec(), "--yes"]);
assert!(
meld.success,
"melding the curator must succeed: {} {}",
meld.stdout, meld.stderr
);
assert!(
curator.claude_home.join("skills/greet").exists(),
"the relative nested source's item must be installed: {:?}",
curator.claude_home
);
let super_dir = curator.base.join(format!("dsc92-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = curator.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
let text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
text.contains(&nested.to_string_lossy().into_owned()),
"the nested source must be dumped by its absolute path: {text}"
);
assert!(
!text.contains("\"../nested-lib\""),
"a cwd-relative nested spec must never be emitted: {text}"
);
let _ = n;
}
#[test]
fn dump_of_a_curator_with_a_relative_nested_source_remelds_in_a_fresh_home() {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let curator = Sandbox::bare("dsc92-remeld-curator");
let nested = curator.base.join("nested-lib");
write_file(
&nested.join("skills/greet/SKILL.md"),
"---\nname: greet\ndescription: Greet skill\n---\n# greet\n",
);
git_init(&nested);
curator.write_and_commit(
"mind.toml",
"[[discover.sources]]\nsource = \"../nested-lib\"\ninstall = true\n",
);
assert!(
curator
.mind(&["meld", &curator.source_spec(), "--yes"])
.success
);
let super_dir = curator.base.join(format!("dsc92-remeld-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
assert!(curator.mind(&["dump", "--output", &dump_path_str]).success);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = curator.base.join(format!("dsc92-remeld-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
assert!(
remeld.status.success(),
"re-meld of the dump must succeed: {} {}",
String::from_utf8_lossy(&remeld.stdout),
String::from_utf8_lossy(&remeld.stderr)
);
assert!(
fresh_claude.join("skills/greet").exists(),
"the nested source's item must be reproduced: {fresh_claude:?}"
);
assert!(
String::from_utf8_lossy(&remeld.stderr).contains("sources tree"),
"the skipped relative entry must be named on stderr: {}",
String::from_utf8_lossy(&remeld.stderr)
);
}
#[test]
fn dsc93_skip_is_reported_in_the_meld_json_skipped_array() {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let curator = Sandbox::bare("dsc93-json-curator");
let nested = curator.base.join("nested-lib");
write_file(
&nested.join("skills/greet/SKILL.md"),
"---\nname: greet\ndescription: Greet skill\n---\n# greet\n",
);
git_init(&nested);
curator.write_and_commit(
"mind.toml",
"[[discover.sources]]\nsource = \"../nested-lib\"\ninstall = true\n",
);
assert!(
curator
.mind(&["meld", &curator.source_spec(), "--yes"])
.success
);
let super_dir = curator.base.join(format!("dsc93-json-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
assert!(curator.mind(&["dump", "--output", &dump_path_str]).success);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = curator.base.join(format!("dsc93-json-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes", "--json"])
.env("MIND_HOME", fresh_base.join("mind"))
.env("CLAUDE_HOME", fresh_base.join("claude"))
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld --json");
let stdout = String::from_utf8_lossy(&remeld.stdout).into_owned();
let stderr = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(
remeld.status.success(),
"re-meld of the dump must succeed under --json too: {stdout} {stderr}"
);
let doc: serde_json::Value = serde_json::from_str(stdout.trim())
.unwrap_or_else(|e| panic!("stdout must be one JSON document ({e}): {stdout:?}"));
assert!(
stderr.contains("sources tree"),
"the DSC-93 warning must still be emitted, on stderr: {stderr}"
);
assert!(
!stdout.contains("sources tree"),
"the DSC-93 warning must not reach stdout under --json: {stdout}"
);
let skipped = doc["skipped"]
.as_array()
.unwrap_or_else(|| panic!("the meld result must carry a `skipped` array: {doc:#}"));
let entry = skipped
.iter()
.find(|e| e["reason"] == "unresolvable_local_path")
.unwrap_or_else(|| panic!("DSC-93 must record reason=unresolvable_local_path: {doc:#}"));
let named = entry["source"].as_str().unwrap_or_default();
assert!(
named.contains("nested-lib"),
"the skipped entry must name the entry that was dropped, so a consumer \
can tell WHICH nested source went missing: {doc:#}"
);
assert!(
fresh_base.join("claude/skills/greet").exists(),
"the nested source's item must still be reproduced: {doc:#} {stderr}"
);
}
#[test]
fn dump_pin_ref_pins_to_exact_commit_not_new_head() {
let src = Sandbox::new("evolving-src");
let meld = src.mind(&["meld", &src.source_spec(), "--yes"]);
assert!(meld.success, "initial meld failed: {}", meld.stderr);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = src.base.join(format!("pinref-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super-source dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dump_r = src.mind(&["dump", "--output", &dump_path_str]);
assert!(
dump_r.success,
"dump --output failed: {} {}",
dump_r.stdout, dump_r.stderr
);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump output");
assert!(
dump_text.contains("pin-ref"),
"dump output must contain pin-ref: {dump_text}"
);
src.write_and_commit(
"skills/new-skill/SKILL.md",
"---\nname: new-skill\ndescription: New skill added after dump\n---\n# new\n",
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = src.base.join(format!("pinref-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("create fresh base");
let fresh_mind_home = fresh_base.join("mind");
let fresh_claude_home = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind_home)
.env("CLAUDE_HOME", &fresh_claude_home)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run mind meld on dumped super-source");
let remeld_out = String::from_utf8_lossy(&remeld.stdout).into_owned();
let remeld_err = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(
remeld.status.success(),
"re-meld of dumped super-source failed: {remeld_out} {remeld_err}"
);
assert!(
!fresh_claude_home.join("skills/new-skill").exists(),
"skill added after dump must NOT appear in the reproduced environment \
(pin-ref must pin to the pre-advance commit): {:?}",
fresh_claude_home
);
assert!(
fresh_claude_home.join("skills/review").exists(),
"original skill:review must be installed in the reproduced environment"
);
assert!(
dump_text.contains(&src.source_spec()),
"dump must reference the source by its path: {dump_text}"
);
assert!(
!dump_text.contains("github.com"),
"dump must use local path (no github URL in this test): {dump_text}"
);
}
#[test]
fn dump_two_of_three_installed_yields_subset_not_install_true() {
let sb = Sandbox::new("src"); let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let l1 = sb.mind(&["learn", "skill:review"]);
assert!(
l1.success,
"learn skill:review: {} {}",
l1.stdout, l1.stderr
);
let l2 = sb.mind(&["learn", "agent:dev"]);
assert!(l2.success, "learn agent:dev: {} {}", l2.stdout, l2.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("install-items"),
"two-of-three installed must emit install-items (not install = true): {}",
r.stdout
);
assert!(
!r.stdout.contains("install = true"),
"must NOT emit install = true when only a subset is installed: {}",
r.stdout
);
assert!(
r.stdout.contains("skill:review") && r.stdout.contains("agent:dev"),
"install-items must list exactly the two installed items: {}",
r.stdout
);
assert!(
!r.stdout.contains("rule:style"),
"the un-installed rule:style must not appear in install-items: {}",
r.stdout
);
}
#[test]
fn dump_all_of_a_two_item_source_yields_install_true() {
let sb = Sandbox::bare("two-item");
sb.write_and_commit(
"skills/alpha/SKILL.md",
"---\nname: alpha\ndescription: Alpha skill\n---\n# alpha\n",
);
sb.write_and_commit(
"agents/beta.md",
"---\nname: beta\ndescription: Beta agent\n---\n# beta\n",
);
let meld = sb.mind(&["meld", &sb.source_spec(), "--yes"]);
assert!(meld.success, "meld failed: {} {}", meld.stdout, meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("install = true"),
"all offered items installed must emit install = true: {}",
r.stdout
);
assert!(
!r.stdout.contains("install-items"),
"must NOT emit install-items when the offered set is fully installed: {}",
r.stdout
);
}
#[test]
fn dump_install_true_when_all_currently_offered_installed_despite_stale_manifest_item() {
let sb = Sandbox::new("stale-src"); let meld = sb.mind(&["meld", &sb.source_spec(), "--yes"]);
assert!(meld.success, "meld failed: {} {}", meld.stdout, meld.stderr);
std::fs::remove_file(sb.source.join("rules/style.md")).expect("remove rule file");
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("install = true"),
"all currently-offered items installed must yield install = true even with a stale manifest item: {}",
r.stdout
);
assert!(
!r.stdout.contains("install-items"),
"a stale (no-longer-offered) manifest item must not force an install-items list: {}",
r.stdout
);
assert!(
!r.stdout.contains("rule:style"),
"the no-longer-offered item must not appear in the dump: {}",
r.stdout
);
}
#[test]
fn dump_multiple_sources_each_with_distinct_directive() {
let full = Sandbox::bare("full-src");
full.write_and_commit(
"skills/only/SKILL.md",
"---\nname: only\ndescription: Only skill\n---\n# only\n",
);
let subset = Sandbox::bare("subset-src");
subset.write_and_commit(
"skills/keep/SKILL.md",
"---\nname: keep\ndescription: Keep skill\n---\n# keep\n",
);
subset.write_and_commit(
"agents/drop.md",
"---\nname: drop\ndescription: Drop agent\n---\n# drop\n",
);
let none = Sandbox::bare("none-src");
none.write_and_commit(
"rules/unused.md",
"---\ndescription: Unused rule\n---\n# unused\n",
);
let m1 = full.mind(&["meld", &full.source_spec(), "--yes"]);
assert!(m1.success, "meld full failed: {} {}", m1.stdout, m1.stderr);
let m2 = full.mind(&["meld", &subset.source_spec(), "--link-only"]);
assert!(
m2.success,
"meld subset failed: {} {}",
m2.stdout, m2.stderr
);
let m3 = full.mind(&["meld", &none.source_spec(), "--link-only"]);
assert!(m3.success, "meld none failed: {} {}", m3.stdout, m3.stderr);
let l = full.mind(&["learn", "skill:keep"]);
assert!(
l.success,
"learn skill:keep failed: {} {}",
l.stdout, l.stderr
);
let r = full.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains(&full.source_spec())
&& r.stdout.contains(&subset.source_spec())
&& r.stdout.contains(&none.source_spec()),
"all three source specs must appear in the dump: {}",
r.stdout
);
assert!(
r.stdout.contains("install = true"),
"the fully-installed source must emit install = true: {}",
r.stdout
);
assert!(
r.stdout.contains("install = false"),
"the un-installed source must emit install = false: {}",
r.stdout
);
assert!(
r.stdout.contains("skill:keep"),
"the subset source must list skill:keep in install-items: {}",
r.stdout
);
assert!(
!r.stdout.contains("agent:drop"),
"the un-installed agent:drop must not appear in install-items: {}",
r.stdout
);
}
#[test]
fn dump_emits_alias_from_source_own_prefix_when_no_consumer_alias() {
let sb = Sandbox::bare("prefixed-src");
sb.write_and_commit("mind.toml", "[source]\nprefix = \"sp\"\n");
sb.write_and_commit(
"skills/widget/SKILL.md",
"---\nname: widget\ndescription: Widget skill\n---\n# widget\n",
);
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {} {}", meld.stdout, meld.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
r.stdout.contains("namespace = \"sp\""),
"dump must emit namespace = \"sp\" from the source's own [source].prefix (DSC-78): {}",
r.stdout
);
}
#[test]
fn dump_tag_pinned_source_dumps_exact_commit_pin_ref() {
let sb = Sandbox::new("tagged-src");
git_tag(&sb.source, "v1");
let meld = sb.mind(&["meld", &sb.source_spec(), "--pin-tag", "v1", "--yes"]);
assert!(
meld.success,
"meld --pin-tag failed: {} {}",
meld.stdout, meld.stderr
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("tag-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("pin-ref"),
"tag-pinned source must dump as pin-ref (exact commit): {dump_text}"
);
assert!(
!dump_text.contains("pin-tag"),
"dump must NOT carry the original pin-tag kind: {dump_text}"
);
sb.write_and_commit(
"skills/added-after/SKILL.md",
"---\nname: added-after\ndescription: Added after dump\n---\n# a\n",
);
git_move_tag(&sb.source, "v1");
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("tag-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
assert!(
!fresh_claude.join("skills/added-after").exists(),
"an item added after the dump must NOT appear (pin-ref must pin exactly): {fresh_claude:?}"
);
assert!(
fresh_claude.join("skills/review").exists(),
"the original skill:review must be present in the reproduced env"
);
}
#[test]
fn dump_branch_followed_source_dumps_exact_commit_pin_ref() {
let sb = Sandbox::new("branch-src");
let meld = sb.mind(&[
"meld",
&sb.source_spec(),
"--follow-branch",
"main",
"--yes",
]);
assert!(
meld.success,
"meld --follow-branch failed: {} {}",
meld.stdout, meld.stderr
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("branch-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("pin-ref"),
"branch-followed source must dump as pin-ref (exact commit): {dump_text}"
);
assert!(
!dump_text.contains("follow-branch"),
"dump must NOT carry the original follow-branch kind: {dump_text}"
);
sb.write_and_commit(
"skills/late/SKILL.md",
"---\nname: late\ndescription: Late skill\n---\n# late\n",
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("branch-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
assert!(
!fresh_claude.join("skills/late").exists(),
"a skill added after the dump must NOT appear (pin-ref pins exactly): {fresh_claude:?}"
);
assert!(
fresh_claude.join("skills/review").exists(),
"the original skill:review must be present in the reproduced env"
);
}
#[test]
fn dump_stdout_and_output_file_are_byte_identical() {
let sb = Sandbox::new("src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {}", meld.stderr);
let learn = sb.mind(&["learn", "skill:review"]);
assert!(
learn.success,
"learn failed: {} {}",
learn.stdout, learn.stderr
);
let stdout_run = sb.mind(&["dump"]);
assert!(
stdout_run.success,
"dump stdout failed: {}",
stdout_run.stderr
);
let out_path = sb.base.join("parity.toml");
let out_str = out_path.to_string_lossy().into_owned();
let file_run = sb.mind(&["dump", "--output", &out_str]);
assert!(
file_run.success,
"dump --output failed: {}",
file_run.stderr
);
let file_content = std::fs::read_to_string(&out_path).expect("read output file");
assert_eq!(
stdout_run.stdout, file_content,
"stdout and --output must be byte-identical:\n--- stdout ---\n{}\n--- file ---\n{}",
stdout_run.stdout, file_content
);
assert!(
!file_content.is_empty(),
"the parity content must not be empty"
);
}
#[test]
fn dump_linked_local_source_without_commit_emits_no_pin_ref() {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let base = std::env::temp_dir().join(format!("mind-dump-nogit-{}-{n}", std::process::id()));
let _ = std::fs::remove_dir_all(&base);
let nongit_src = base.join("nongit");
write_file(
&nongit_src.join("skills/plain/SKILL.md"),
"---\nname: plain\ndescription: Plain skill\n---\n# plain\n",
);
let mind_home = base.join("mind");
let claude_home = base.join("claude");
let run = |args: &[&str]| -> Run {
let out = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(args)
.env("MIND_HOME", &mind_home)
.env("CLAUDE_HOME", &claude_home)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run mind");
Run {
stdout: String::from_utf8_lossy(&out.stdout).into_owned(),
stderr: String::from_utf8_lossy(&out.stderr).into_owned(),
success: out.status.success(),
}
};
let nongit_spec = nongit_src.to_string_lossy().into_owned();
let meld = run(&["meld", &nongit_spec, "--link-only"]);
assert!(
meld.success,
"meld of a non-git local dir must succeed: {} {}",
meld.stdout, meld.stderr
);
let dump = run(&["dump"]);
assert!(dump.success, "dump failed: {} {}", dump.stdout, dump.stderr);
assert!(
!dump.stdout.contains("pin-ref"),
"a source with no recorded commit must emit no pin-ref: {}",
dump.stdout
);
assert!(
!dump.stdout.contains("pin-ref = \"\""),
"must never emit an empty pin-ref: {}",
dump.stdout
);
assert!(
dump.stdout.contains(&nongit_spec),
"the source must still be referenced in the dump: {}",
dump.stdout
);
let _ = std::fs::remove_dir_all(&base);
}
#[test]
fn dump_token_dependency_item_is_in_install_items() {
let sb = Sandbox::bare("tok-dep");
sb.write_and_commit(
"agents/helper.md",
"---\nname: helper\ndescription: Helper agent\n---\n# helper\n",
);
sb.write_and_commit(
"rules/extra.md",
"---\ndescription: Extra rule\n---\n# extra\n",
);
sb.write_and_commit(
"skills/caller/SKILL.md",
"---\nname: caller\ndescription: Caller skill\n---\n# caller\n\nSee {{ns:helper}}.\n",
);
let meld = sb.mind(&["meld", &sb.source_spec(), "--link-only"]);
assert!(meld.success, "meld failed: {} {}", meld.stdout, meld.stderr);
let learn = sb.mind(&["learn", "skill:caller", "--yes"]);
assert!(
learn.success,
"learn skill:caller failed: {} {}",
learn.stdout, learn.stderr
);
let r = sb.mind(&["dump"]);
assert!(r.success, "dump failed: {} {}", r.stdout, r.stderr);
assert!(
sb.claude_home.join("agents/helper.md").exists(),
"the {{{{ns:helper}}}} token must pull agent:helper in as a dependency"
);
assert!(
r.stdout.contains("agent:helper") && r.stdout.contains("skill:caller"),
"a token-pulled dependency must appear in install-items alongside its referrer: {}",
r.stdout
);
assert!(
!r.stdout.contains("rule:extra"),
"the un-installed rule:extra must not appear in install-items: {}",
r.stdout
);
}
#[test]
fn dump_roundtrips_add_root_items() {
let sb = Sandbox::bare("addroot-src");
sb.write_and_commit(
"skills/base/SKILL.md",
"---\nname: base\ndescription: Base skill\n---\n# base\n",
);
sb.write_and_commit(
"contrib/skills/addon/SKILL.md",
"---\nname: addon\ndescription: Add-root contributed skill\n---\n# addon\n",
);
let meld = sb.mind(&["meld", &sb.source_spec(), "--add-root", "contrib", "--yes"]);
assert!(
meld.success,
"meld --add-root failed: {} {}",
meld.stdout, meld.stderr
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("addroot-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("add-roots"),
"dump must emit add-roots for an --add-root source: {dump_text}"
);
assert!(
dump_text.contains("contrib"),
"dump must record the `contrib` add-root: {dump_text}"
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("addroot-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
assert!(
fresh_claude.join("skills/base").exists(),
"the base skill must install in the reproduced env: {fresh_claude:?}"
);
assert!(
fresh_claude.join("skills/addon").exists(),
"the add-root contributed skill must install in the reproduced env \
(proves dump round-tripped --add-root): {fresh_claude:?}"
);
}
#[test]
fn dump_add_root_over_authoritative_mindtoml_emits_but_is_gated_on_reroundtrip() {
let sb = Sandbox::bare("addroot-auth-src");
sb.write_and_commit(
"mind.toml",
"[[items]]\nkind = \"skill\"\nname = \"core\"\npath = \"skills/core\"\n",
);
sb.write_and_commit(
"skills/core/SKILL.md",
"---\nname: core\ndescription: Authoritative core skill\n---\n# core\n",
);
sb.write_and_commit(
"contrib/skills/addon/SKILL.md",
"---\nname: addon\ndescription: Add-root contributed skill\n---\n# addon\n",
);
let meld = sb.mind(&["meld", &sb.source_spec(), "--add-root", "contrib", "--yes"]);
assert!(
meld.success,
"meld --add-root over an authoritative mind.toml failed: {} {}",
meld.stdout, meld.stderr
);
assert!(
sb.claude_home.join("skills/core").exists(),
"the authoritative item must install: {:?}",
sb.claude_home
);
assert!(
sb.claude_home.join("skills/addon").exists(),
"the add-root item must install alongside the authoritative item \
(DSC-84): {:?}",
sb.claude_home
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("addroot-auth-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("add-roots") && dump_text.contains("contrib"),
"dump must still emit the recorded add-roots even when the source also \
has an authoritative mind.toml (DUMP-11 provenance): {dump_text}"
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("addroot-auth-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
assert!(
re.contains("mind.toml") && re.contains("ignored"),
"re-melding the dumped super-source must warn that the nested entry's \
curator-supplied add-roots is ignored (DSC-60/DSC-88): {re}"
);
assert!(
fresh_claude.join("skills/core").exists(),
"the authoritative item must install in the reproduced env: {fresh_claude:?}"
);
assert!(
!fresh_claude.join("skills/addon").exists(),
"the add-root item must NOT install in the reproduced env: once \
re-melded as a nested super-source entry, its add-roots is a curator \
value gated by DSC-60/DSC-88 because the nested source ships its own \
mind.toml -- it must not bypass that source's authoritative export \
list: {fresh_claude:?}"
);
}
#[test]
fn dump_emits_no_add_roots_key_when_source_has_none() {
let sb = Sandbox::new("no-add-root-src");
let meld = sb.mind(&["meld", &sb.source_spec(), "--yes"]);
assert!(
meld.success,
"plain meld (no --add-root) failed: {} {}",
meld.stdout, meld.stderr
);
let dr = sb.mind(&["dump"]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
assert!(
!dr.stdout.contains("add-roots"),
"dump must emit no add-roots key for a source with none recorded: {}",
dr.stdout
);
}
#[test]
fn dump_sync_rewalk_threads_add_roots_into_newly_registered_nested_source() {
let nested = Sandbox::bare("rewalk-nested");
nested.write_and_commit(
"skills/base/SKILL.md",
"---\nname: base\ndescription: Base skill\n---\n# base\n",
);
nested.write_and_commit(
"extra-contrib/skills/addon/SKILL.md",
"---\nname: addon\ndescription: Add-root contributed skill\n---\n# addon\n",
);
let nested_spec = nested.source_spec();
let t = Sandbox::bare("rewalk-super");
let initial = t.mind(&["meld", &t.source_spec(), "--yes"]);
assert!(
initial.success,
"initial meld of the super-source failed: {} {}",
initial.stdout, initial.stderr
);
let sources_after_meld = t.mind(&["recall", "--sources"]).stdout;
assert!(
!sources_after_meld.contains("rewalk-nested"),
"the nested source must not be registered before it is declared: {sources_after_meld}"
);
let toml = format!(
"[[discover.sources]]\nsource = \"{nested_spec}\"\nadd-roots = [\"extra-contrib\"]\n"
);
t.write_and_commit("mind.toml", &toml);
let sync = t.mind(&["sync"]);
assert!(
sync.success,
"sync re-walk failed: {} {}",
sync.stdout, sync.stderr
);
let sources_after_sync = t.mind(&["recall", "--sources"]).stdout;
assert!(
sources_after_sync.contains("rewalk-nested"),
"sync's re-walk must register the newly-declared nested source: {sources_after_sync}"
);
let dr = t.mind(&["dump"]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
assert!(
dr.stdout.contains("add-roots") && dr.stdout.contains("extra-contrib"),
"dump must show add-roots on the nested source sync's re-walk \
registered, proving the re-walk threaded the entry's add-roots into \
the nested meld: {}",
dr.stdout
);
}
#[test]
fn dump_is_classified_as_shared_lock() {
let sb = Sandbox::bare("lock-test");
let help = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["dump", "--help"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("run mind dump --help");
assert!(
help.status.success(),
"`mind dump --help` must exit 0: {}",
String::from_utf8_lossy(&help.stderr)
);
let help_out = String::from_utf8_lossy(&help.stdout).into_owned();
assert!(
help_out.contains("--output") || help_out.contains("--whole-sources"),
"help text must mention dump flags: {help_out}"
);
let r = sb.mind(&["dump"]);
assert!(
r.success,
"`mind dump` with empty home must exit 0: {} {}",
r.stdout, r.stderr
);
drop(sb);
}
#[test]
fn dump_json_flag_prints_stderr_note() {
let sb = Sandbox::new("json-note");
let spec = sb.source_spec();
sb.mind(&["meld", &spec, "--yes"]);
let r = sb.mind(&["--json", "dump"]);
assert!(
r.success,
"`dump --json` must exit 0: stdout={} stderr={}",
r.stdout, r.stderr
);
assert!(
!r.stdout.trim_start().starts_with('{'),
"dump --json stdout must be TOML, not a JSON object: '{}'",
r.stdout
);
assert!(
r.stdout.contains("[discover]") || r.stdout.contains("[source]"),
"dump --json stdout must contain TOML structure: '{}'",
r.stdout
);
assert!(
r.stderr.contains("--json")
&& (r.stderr.contains("does not apply") || r.stderr.contains("TOML")),
"dump --json must print a note to stderr: '{}'",
r.stderr
);
}
#[test]
fn dump_roundtrips_bare_link_instance() {
let sb = Sandbox::new("link-src");
let learn = sb.mind(&["learn", &sb.link("tree/main/skills/review")]);
assert!(
learn.success,
"learn <url> failed: {} {}",
learn.stdout, learn.stderr
);
let dumped_commit = git_head(&sb.source);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("link-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
assert!(
!dr.stderr.contains("skipping item link"),
"dump must no longer skip an item-link instance: {}",
dr.stderr
);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("/tree/"),
"dump must emit a reconstructed tree/<ref>/<path> link URL: {dump_text}"
);
assert!(
dump_text.contains("skills/review"),
"dump must reconstruct the recorded item path: {dump_text}"
);
assert!(
dump_text.contains("pin-ref"),
"dump must pin the link entry with pin-ref like every other entry: {dump_text}"
);
assert!(
dump_text.contains(&dumped_commit),
"dump must pin the reconstructed link to the recorded commit: {dump_text}"
);
sb.write_and_commit(
"skills/review/SKILL.md",
"---\nname: review\ndescription: Review skill CHANGED AFTER DUMP\n---\n# review v2\n",
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("link-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
let installed = fresh_claude.join("skills/review/SKILL.md");
assert!(
installed.exists(),
"the linked skill must be installed in the reproduced env: {fresh_claude:?}"
);
let content = std::fs::read_to_string(&installed).expect("read reinstalled SKILL.md");
assert!(
!content.contains("CHANGED AFTER DUMP"),
"reproduced install must pin to the dumped commit, not a later revision: {content}"
);
assert!(
content.contains("Review skill"),
"reproduced install must carry the pre-dump content: {content}"
);
let sources = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["recall", "--sources"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run recall --sources");
let sources_out = String::from_utf8_lossy(&sources.stdout).into_owned();
assert!(
sources_out.contains("#skills/review"),
"the reproduced instance must carry the same link identity: {sources_out}"
);
}
#[test]
fn dump_roundtrips_aliased_link_instance() {
let sb = Sandbox::new("link-alias-src");
let meld = sb.mind(&[
"meld",
&sb.link("tree/main/skills/review"),
"--namespace",
"fork",
"--yes",
]);
assert!(
meld.success,
"aliased link meld failed: {} {}",
meld.stdout, meld.stderr
);
assert!(
sb.claude_home.join("skills/fork:review").exists(),
"the aliased link's skill must install under the prefix"
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("link-alias-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("namespace = \"fork\""),
"dump must emit the identity alias as namespace on the link entry: {dump_text}"
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("link-alias-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
assert!(
fresh_claude.join("skills/fork:review").exists(),
"the reproduced env must install the skill under the SAME alias prefix: {fresh_claude:?}"
);
let sources = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["recall", "--sources"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run recall --sources");
let sources_out = String::from_utf8_lossy(&sources.stdout).into_owned();
assert!(
sources_out.contains("#skills/review@fork"),
"the reproduced instance must carry the SAME aliased identity: {sources_out}"
);
}
#[test]
fn dump_roundtrips_link_instance_with_ssh_config_set() {
let sb = Sandbox::new("link-ssh-src");
write_file(&sb.mind_home.join("config.toml"), "ssh = true\n");
let learn = sb.mind(&["learn", &sb.link("tree/main/skills/review")]);
assert!(
learn.success,
"learn <url> failed under ssh=true config: {} {}",
learn.stdout, learn.stderr
);
let dumped_commit = git_head(&sb.source);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("link-ssh-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
assert!(
!dr.stderr.contains("skipping item link"),
"dump must not skip the item-link instance under ssh=true: {}",
dr.stderr
);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
!dump_text.contains("git@"),
"the reconstructed link URL must never be the SSH form (not re-meldable as a link): \
{dump_text}"
);
assert!(
dump_text.contains("/tree/") && dump_text.contains("skills/review"),
"dump must emit a reconstructed tree/<ref>/<path> link URL: {dump_text}"
);
assert!(
dump_text.contains(&dumped_commit),
"dump must pin the reconstructed link to the recorded commit: {dump_text}"
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("link-ssh-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(
remeld.status.success(),
"remeld of the ssh=true dump must succeed: {ro} {re}"
);
let installed = fresh_claude.join("skills/review/SKILL.md");
assert!(
installed.exists(),
"the linked skill must be installed in the reproduced env: {fresh_claude:?}"
);
let sources = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["recall", "--sources"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run recall --sources");
let sources_out = String::from_utf8_lossy(&sources.stdout).into_owned();
assert!(
sources_out.contains("#skills/review"),
"the reproduced instance must carry the same link identity: {sources_out}"
);
}
#[test]
fn dump_link_and_ordinary_source_together_roundtrip() {
let sb = Sandbox::new("link-mixed-src");
let learn = sb.mind(&["learn", &sb.link("tree/main/skills/review")]);
assert!(
learn.success,
"learn <url> failed: {} {}",
learn.stdout, learn.stderr
);
let other_source = sb.base.join("other-src");
write_file(
&other_source.join("skills/helper/SKILL.md"),
"---\nname: helper\ndescription: Helper skill\n---\n# helper\n",
);
git_init(&other_source);
let other_spec = other_source.to_string_lossy().into_owned();
let meld_other = sb.mind(&["meld", &other_spec, "--yes"]);
assert!(
meld_other.success,
"ordinary meld failed: {} {}",
meld_other.stdout, meld_other.stderr
);
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("link-mixed-super-{n}"));
std::fs::create_dir_all(&super_dir).expect("create super dir");
let dump_path = super_dir.join("mind.toml");
let dump_path_str = dump_path.to_string_lossy().into_owned();
let dr = sb.mind(&["dump", "--output", &dump_path_str]);
assert!(dr.success, "dump failed: {} {}", dr.stdout, dr.stderr);
assert!(
!dr.stderr.contains("skipping item link"),
"dump must not skip the item-link instance: {}",
dr.stderr
);
let dump_text = std::fs::read_to_string(&dump_path).expect("read dump");
assert!(
dump_text.contains("/tree/") && dump_text.contains("skills/review"),
"dump must emit the reconstructed link entry: {dump_text}"
);
assert!(
dump_text.contains(&other_spec),
"dump must also emit the ordinary source entry: {dump_text}"
);
git_init(&super_dir);
let super_spec = super_dir.to_string_lossy().into_owned();
let fresh_base = sb.base.join(format!("link-mixed-fresh-{n}"));
std::fs::create_dir_all(&fresh_base).expect("fresh base");
let fresh_mind = fresh_base.join("mind");
let fresh_claude = fresh_base.join("claude");
let remeld = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_spec, "--yes"])
.env("MIND_HOME", &fresh_mind)
.env("CLAUDE_HOME", &fresh_claude)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
let ro = String::from_utf8_lossy(&remeld.stdout).into_owned();
let re = String::from_utf8_lossy(&remeld.stderr).into_owned();
assert!(remeld.status.success(), "remeld failed: {ro} {re}");
assert!(
fresh_claude.join("skills/review").exists(),
"the link instance's skill must install in the reproduced env: {fresh_claude:?}"
);
assert!(
fresh_claude.join("skills/helper").exists(),
"the ordinary source's skill must also install in the reproduced env: {fresh_claude:?}"
);
}
const PROF_TOML: &str = "[profiles]\n\
default = [\"rule:style\"]\n\
full = [\"skill:review\", \"agent:*\"]\n";
fn profiled(name: &str) -> Sandbox {
let sb = Sandbox::new(name);
sb.write_and_commit(
"skills/extra/SKILL.md",
"---\nname: extra\ndescription: Extra skill\n---\n# extra\n",
);
sb.write_and_commit("mind.toml", PROF_TOML);
sb
}
fn dump_entries(text: &str) -> Vec<toml::value::Table> {
let v: toml::Value =
toml::from_str(text).unwrap_or_else(|e| panic!("dump is TOML: {e}\n{text}"));
v.get("discover")
.and_then(|d| d.get("sources"))
.and_then(|s| s.as_array())
.map(|a| a.iter().filter_map(|e| e.as_table().cloned()).collect())
.unwrap_or_default()
}
fn str_list(t: &toml::value::Table, key: &str) -> Option<Vec<String>> {
t.get(key).map(|v| {
v.as_array()
.unwrap_or_else(|| panic!("{key} is an array"))
.iter()
.map(|s| s.as_str().unwrap().to_string())
.collect()
})
}
fn recorded(mind_home: &Path) -> (Vec<String>, Vec<String>) {
let src: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(mind_home.join("sources.json")).unwrap())
.unwrap();
let list = src
.get("sources")
.and_then(|s| s.as_array())
.cloned()
.or_else(|| src.as_array().cloned())
.unwrap_or_default();
let profs: Vec<String> = list
.iter()
.find_map(|s| s["profiles"].as_array())
.map(|a| a.iter().map(|p| p.as_str().unwrap().to_string()).collect())
.unwrap_or_default();
let man: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(mind_home.join("manifest.json")).unwrap())
.unwrap();
let mut keys: Vec<String> = man["items"]
.as_object()
.map(|o| o.keys().cloned().collect())
.unwrap_or_default();
keys.sort();
(profs, keys)
}
#[test]
fn dump_of_a_profile_tracked_source_emits_profiles_not_install() {
let sb = profiled("psrc");
let m = sb.mind(&["meld", &sb.source_spec(), "--profile", "full", "--yes"]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "{} {}", r.stdout, r.stderr);
let entries = dump_entries(&r.stdout);
assert_eq!(entries.len(), 1, "{}", r.stdout);
let e = &entries[0];
assert_eq!(str_list(e, "profiles"), Some(vec!["full".to_string()]));
assert!(!e.contains_key("default-profile"), "{}", r.stdout);
assert!(!e.contains_key("install"), "{}", r.stdout);
assert!(!e.contains_key("install-items"), "{}", r.stdout);
}
#[test]
fn dump_of_a_default_only_tracked_source_emits_empty_profiles() {
let sb = profiled("psrc");
let m = sb.mind(&["meld", &sb.source_spec(), "--yes"]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "{} {}", r.stdout, r.stderr);
let entries = dump_entries(&r.stdout);
assert_eq!(entries.len(), 1, "{}", r.stdout);
assert_eq!(str_list(&entries[0], "profiles"), Some(vec![]));
assert!(!entries[0].contains_key("install"), "{}", r.stdout);
assert!(!entries[0].contains_key("default-profile"), "{}", r.stdout);
}
#[test]
fn dump_emits_default_profile_false_when_default_is_disabled() {
let sb = profiled("psrc");
let m = sb.mind(&[
"meld",
&sb.source_spec(),
"--no-default-profile",
"--profile",
"full",
"--yes",
]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
let r = sb.mind(&["dump"]);
let entries = dump_entries(&r.stdout);
assert_eq!(entries.len(), 1, "{}", r.stdout);
assert_eq!(
str_list(&entries[0], "profiles"),
Some(vec!["full".to_string()])
);
assert_eq!(
entries[0].get("default-profile").and_then(|v| v.as_bool()),
Some(false),
"{}",
r.stdout
);
}
#[test]
fn dump_lists_only_explicit_items_outside_the_expansion_as_install_items() {
let sb = profiled("psrc");
let m = sb.mind(&["meld", &sb.source_spec(), "--profile", "full", "--yes"]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
let l = sb.mind(&["learn", "skill:extra"]);
assert!(l.success, "{} {}", l.stdout, l.stderr);
let l = sb.mind(&["learn", "skill:review"]);
assert!(l.success, "{} {}", l.stdout, l.stderr);
let r = sb.mind(&["dump"]);
assert!(r.success, "{} {}", r.stdout, r.stderr);
let entries = dump_entries(&r.stdout);
assert_eq!(entries.len(), 1, "{}", r.stdout);
assert_eq!(
str_list(&entries[0], "install-items"),
Some(vec!["skill:extra".to_string()]),
"{}",
r.stdout
);
assert!(!entries[0].contains_key("install"), "{}", r.stdout);
}
#[test]
fn dump_whole_sources_emits_no_profile_keys_for_a_tracked_source() {
let sb = profiled("psrc");
let m = sb.mind(&[
"meld",
&sb.source_spec(),
"--no-default-profile",
"--profile",
"full",
"--yes",
]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
sb.mind(&["learn", "skill:extra"]);
let r = sb.mind(&["dump", "--whole-sources"]);
assert!(r.success, "{} {}", r.stdout, r.stderr);
let entries = dump_entries(&r.stdout);
assert_eq!(entries.len(), 1, "{}", r.stdout);
let e = &entries[0];
assert_eq!(e.get("install").and_then(|v| v.as_bool()), Some(true));
for k in ["profiles", "default-profile", "install-items"] {
assert!(!e.contains_key(k), "{k} leaked: {}", r.stdout);
}
}
fn remeld_dump(sb: &Sandbox, tag: &str) -> PathBuf {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let super_dir = sb.base.join(format!("prof-super-{tag}-{n}"));
std::fs::create_dir_all(&super_dir).unwrap();
let dump_path = super_dir.join("mind.toml");
let dr = sb.mind(&["dump", "--output", &dump_path.to_string_lossy()]);
assert!(dr.success, "{} {}", dr.stdout, dr.stderr);
git_init(&super_dir);
let fresh = sb.base.join(format!("prof-fresh-{tag}-{n}"));
std::fs::create_dir_all(&fresh).unwrap();
let out = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(["meld", &super_dir.to_string_lossy(), "--yes"])
.env("MIND_HOME", fresh.join("mind"))
.env("CLAUDE_HOME", fresh.join("claude"))
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run remeld");
assert!(
out.status.success(),
"remeld failed: {} {}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
fresh.join("mind")
}
#[test]
fn dump_of_a_profile_tracked_source_roundtrips_enabled_profiles_and_items() {
let sb = profiled("psrc");
let m = sb.mind(&["meld", &sb.source_spec(), "--profile", "full", "--yes"]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
let l = sb.mind(&["learn", "skill:extra"]);
assert!(l.success, "{} {}", l.stdout, l.stderr);
let original = recorded(&sb.mind_home);
let fresh = remeld_dump(&sb, "a");
assert_eq!(recorded(&fresh), original);
}
#[test]
fn dump_roundtrips_a_disabled_default_profile() {
let sb = profiled("psrc");
let m = sb.mind(&[
"meld",
&sb.source_spec(),
"--no-default-profile",
"--profile",
"full",
"--yes",
]);
assert!(m.success, "{} {}", m.stdout, m.stderr);
let original = recorded(&sb.mind_home);
assert_eq!(original.0, vec!["full".to_string()]);
assert!(!original.1.contains(&"rule:style".to_string()));
let fresh = remeld_dump(&sb, "b");
assert_eq!(recorded(&fresh), original);
}