diff --git a/crates/mind-body/src/control.rs b/crates/mind-body/src/control.rs index c12d91d..161899d 100644 --- a/crates/mind-body/src/control.rs +++ b/crates/mind-body/src/control.rs @@ -36,7 +36,7 @@ use std::path::{Path, PathBuf}; -use anyhow::{Context, Result}; +use anyhow::{Context, Result, bail}; use chrono::{DateTime, Utc}; use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry, SingleFileMessagePackBackingStore}; use eureka_pipeline::Slug; @@ -414,6 +414,10 @@ impl ControlWriter { let mut cache = registered_cache()?; cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path))?; cache.pull_all_backing_stores()?; + // A pull carries a record no registered type claims instead of refusing it; the writer still must not write beside one. + if !cache.foreign_records().is_empty() { + bail!("{} holds a record this control store does not read: archive it, nothing migrates it", path.display()); + } Ok(Self { cache, path }) } diff --git a/crates/mind-body/src/control/tests.rs b/crates/mind-body/src/control/tests.rs index 845ccd5..0db9742 100644 --- a/crates/mind-body/src/control/tests.rs +++ b/crates/mind-body/src/control/tests.rs @@ -255,3 +255,19 @@ fn release(root: &Path, name: &str) { ControlWriter::open(root.join(name).join("control.cc")).unwrap().set_brake(true, at(0), "op").unwrap(); release_swarm(root); } + +#[test] +fn a_writer_refuses_to_open_over_a_store_holding_a_record_it_does_not_read() { + let dir = tempfile::tempdir().unwrap(); + let path = store_path(dir.path()); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + let mut cache = CultCache::new(); + cache.register_entry_type::().unwrap(); + cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap(); + cache.pull_all_backing_stores().unwrap(); + cache.put("dial", &OldDial { heat: "1".into() }).unwrap(); + let before = std::fs::read(&path).unwrap(); + let refusal = ControlWriter::open(&path).err().expect("a foreign record refuses the open").to_string(); + assert!(refusal.contains("does not read"), "{refusal}"); + assert_eq!(std::fs::read(&path).unwrap(), before, "the refused open leaves the store bytes alone"); +}