feat(simulation): add YAML content loader with hot-reload (#326)
LinePool system parses dialogue.yaml and monologue.yaml into indexed BTreeMap structures. Supports 4-layer query filtering (access > situation > trust > topic+mood) per D-028. Hot-reload via timestamp polling every 20 ticks (dev-only). Graceful failure preserves previous content on reload error. 30+ tests covering enum parsing, index building, query filtering, monologue fallback, and content watching. Ref: D-028, D-032, D-035, D-041 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -291,15 +291,13 @@ fn load_yaml_dir<T: serde::de::DeserializeOwned>(dir: &Path) -> Vec<T> {
|
||||
/// Load all YAML files recursively under a directory, skipping stubs.
|
||||
fn load_yaml_recursive<T: serde::de::DeserializeOwned>(dir: &Path) -> Vec<T> {
|
||||
let mut results = Vec::new();
|
||||
walk_yaml_files(dir, &mut |path| {
|
||||
match load_yaml::<T>(path) {
|
||||
Ok(item) => results.push(item),
|
||||
Err(e) => {
|
||||
if is_comment_only_file(path) {
|
||||
tracing::debug!("Skipping stub: {:?}", path);
|
||||
} else {
|
||||
tracing::warn!("Failed to parse {:?}: {}", path, e);
|
||||
}
|
||||
walk_yaml_files(dir, &mut |path| match load_yaml::<T>(path) {
|
||||
Ok(item) => results.push(item),
|
||||
Err(e) => {
|
||||
if is_comment_only_file(path) {
|
||||
tracing::debug!("Skipping stub: {:?}", path);
|
||||
} else {
|
||||
tracing::warn!("Failed to parse {:?}: {}", path, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -525,7 +523,8 @@ motivation: "HANDLER"
|
||||
#[test]
|
||||
fn derive_district_id_from_path() {
|
||||
let root = Path::new("/content");
|
||||
let district = Path::new("/content/campaigns/main/systems/krenn/stations/sova/districts/transit");
|
||||
let district =
|
||||
Path::new("/content/campaigns/main/systems/krenn/stations/sova/districts/transit");
|
||||
let id = derive_district_id(root, district);
|
||||
assert_eq!(id, "krenn.sova.transit");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user