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 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:?}");
}
#[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("as = \"mypfx\""),
"emitted entry must carry as = \"mypfx\": {}",
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_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("as = \"sp\""),
"dump must emit as = \"sp\" from the source's own [source].prefix: {}",
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_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
);
}