chore(deps): rand 0.9.4 + compatible sweep + serde_yaml→serde_norway (#966)

Focused Rust dependency-maintenance pass from the 2026-05-23 security/freshness
review. No CVEs; one advisory cleared and one deprecated crate replaced.

- rand 0.9.2 → 0.9.4 (lockfile): clears RUSTSEC-2026-0097 (unsound with a
  custom logger using rand::rng()). Semver-compatible; rand 0.10 is a separate
  major.
- Compatible-update sweep: ~90 lockfile-only patch/minor bumps (bevy 0.18.0→
  0.18.1, clap 4.5→4.6, rayon 1.11→1.12, pathfinding 4.14→4.15, uuid 1.20→1.23,
  zerocopy, serde_json, tracing-subscriber, etc.). cargo test green.
- serde_yaml 0.9 (deprecated/archived upstream) → serde_norway 0.9, an actively
  maintained drop-in fork. In the server it is test-only (poi.rs round-trip,
  trait_modifiers.rs fixture, tests/news_ticker.rs) so it moves to
  dev-dependencies; line-previewer parses dialogue/monologue pool YAML at
  runtime, so it keeps it as a normal dependency. API is identical (from_str/
  to_string).

news_ticker.rs also picks up its share of the #967 clippy sweep (HashSet/HashMap
→ BTree, doc-list indent) since it is the same file as the serde rename.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 11:02:57 +02:00
co-authored by Claude Opus 4.7
parent 88712ba54f
commit 9a10c6ffd6
9 changed files with 419 additions and 218 deletions
+389 -191
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -14,7 +14,6 @@ bevy_tasks = { version = "0.18", features = ["multi_threaded"] }
# systems marked with TODO comments. Active use begins when profiling shows bottlenecks.
rayon = "1"
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
ron = "0.8"
rmp-serde = "1"
rand = "0.9"
@@ -40,6 +39,9 @@ default = ["gauntlet"]
gauntlet = []
[dev-dependencies]
# Maintained drop-in fork of the deprecated serde_yaml 0.9 (#966). Test-only:
# the YAML round-trip in poi.rs and the trait-config fixture in trait_modifiers.rs.
serde_norway = "0.9"
# ---------------------------------------------------------------------------
# Explicit test target for the Layer 3 integration module (D-030, ticket #200).
+1 -1
View File
@@ -259,7 +259,7 @@ modifiers:
stage2:
delivery_tags: ["casual_delivery", "gossip_delivery"]
"#;
serde_yaml::from_str(yaml).expect("valid trait config YAML")
serde_norway::from_str(yaml).expect("valid trait config YAML")
}
#[test]
+3 -2
View File
@@ -205,8 +205,9 @@ mod tests {
#[test]
fn poi_serialization_roundtrip() {
let poi = make_poi("med_bay", PoiCategory::Service, PoiVisibility::LineOfSight);
let serialized = serde_yaml::to_string(&poi).expect("serialize");
let deserialized: PointOfInterest = serde_yaml::from_str(&serialized).expect("deserialize");
let serialized = serde_norway::to_string(&poi).expect("serialize");
let deserialized: PointOfInterest =
serde_norway::from_str(&serialized).expect("deserialize");
assert_eq!(deserialized.poi_id, "med_bay");
assert_eq!(deserialized.category, PoiCategory::Service);
}
+10 -10
View File
@@ -4,7 +4,7 @@
//! - D-036: Sova Transit District — The Last Shift bar shows news ticker
//! - D-010 principle 4: ticker rotation must use SimRng (deterministic)
//! - #591: TickerPool loads ticker/the-last-shift.yaml, rotates every 200 ticks,
//! populates current_ticker in ObserverSnapshot when player is in "bar" zone
//! populates current_ticker in ObserverSnapshot when player is in "bar" zone
//!
//! Test structure:
//! - Layer 1 (pure): validate the ticker YAML content (30 headlines, required fields)
@@ -54,7 +54,7 @@ fn ticker_yaml_exists_and_parses() {
let content = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("Failed to read ticker YAML: {}", e));
let _: TickerFile = serde_yaml::from_str(&content)
let _: TickerFile = serde_norway::from_str(&content)
.unwrap_or_else(|e| panic!("Ticker YAML failed to parse: {}\nFile: {:?}", e, path));
}
@@ -69,7 +69,7 @@ fn ticker_yaml_has_30_headlines() {
}
let content = std::fs::read_to_string(&path).expect("read ticker YAML");
let file: TickerFile = serde_yaml::from_str(&content).expect("parse ticker YAML");
let file: TickerFile = serde_norway::from_str(&content).expect("parse ticker YAML");
assert_eq!(
file.headlines.len(),
@@ -88,7 +88,7 @@ fn ticker_yaml_location_is_the_last_shift() {
}
let content = std::fs::read_to_string(&path).expect("read ticker YAML");
let file: TickerFile = serde_yaml::from_str(&content).expect("parse ticker YAML");
let file: TickerFile = serde_norway::from_str(&content).expect("parse ticker YAML");
assert_eq!(
file.location, "the-last-shift",
@@ -108,7 +108,7 @@ fn ticker_yaml_all_headlines_have_required_fields() {
}
let content = std::fs::read_to_string(&path).expect("read ticker YAML");
let file: TickerFile = serde_yaml::from_str(&content).expect("parse ticker YAML");
let file: TickerFile = serde_norway::from_str(&content).expect("parse ticker YAML");
for (i, headline) in file.headlines.iter().enumerate() {
assert!(!headline.id.is_empty(), "Headline[{}] missing id field", i);
@@ -135,9 +135,9 @@ fn ticker_yaml_ids_are_unique() {
}
let content = std::fs::read_to_string(&path).expect("read ticker YAML");
let file: TickerFile = serde_yaml::from_str(&content).expect("parse ticker YAML");
let file: TickerFile = serde_norway::from_str(&content).expect("parse ticker YAML");
let mut seen = std::collections::HashSet::new();
let mut seen = std::collections::BTreeSet::new();
for headline in &file.headlines {
assert!(
seen.insert(headline.id.clone()),
@@ -165,7 +165,7 @@ fn ticker_yaml_categories_are_valid() {
}
let content = std::fs::read_to_string(&path).expect("read ticker YAML");
let file: TickerFile = serde_yaml::from_str(&content).expect("parse ticker YAML");
let file: TickerFile = serde_norway::from_str(&content).expect("parse ticker YAML");
for headline in &file.headlines {
assert!(
@@ -188,9 +188,9 @@ fn ticker_yaml_category_distribution_is_sane() {
}
let content = std::fs::read_to_string(&path).expect("read ticker YAML");
let file: TickerFile = serde_yaml::from_str(&content).expect("parse ticker YAML");
let file: TickerFile = serde_norway::from_str(&content).expect("parse ticker YAML");
let mut counts: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
let mut counts: std::collections::BTreeMap<String, usize> = std::collections::BTreeMap::new();
for headline in &file.headlines {
*counts.entry(headline.category.clone()).or_insert(0) += 1;
}
+8 -8
View File
@@ -170,7 +170,7 @@ dependencies = [
"rand",
"rand_chacha",
"serde",
"serde_yaml",
"serde_norway",
]
[[package]]
@@ -278,16 +278,16 @@ dependencies = [
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
name = "serde_norway"
version = "0.9.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
checksum = "e408f29489b5fd500fab51ff1484fc859bb655f32c671f307dcd733b72e8168c"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
"unsafe-libyaml-norway",
]
[[package]]
@@ -314,10 +314,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
name = "unsafe-libyaml-norway"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
checksum = "b39abd59bf32521c7f2301b52d05a6a2c975b6003521cbd0c6dc1582f0a22104"
[[package]]
name = "utf8parse"
+1 -1
View File
@@ -10,7 +10,7 @@ path = "src/main.rs"
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
serde_norway = "0.9"
clap = { version = "4", features = ["derive"] }
rand = "0.9"
rand_chacha = "0.9"
+2 -2
View File
@@ -216,7 +216,7 @@ fn load_dialogue(path: &PathBuf) -> DialoguePool {
eprintln!("Error reading {}: {e}", path.display());
std::process::exit(1);
});
serde_yaml::from_str(&yaml_str).unwrap_or_else(|e| {
serde_norway::from_str(&yaml_str).unwrap_or_else(|e| {
eprintln!("Error parsing dialogue YAML: {e}");
std::process::exit(1);
})
@@ -227,7 +227,7 @@ fn load_monologue(path: &PathBuf) -> MonologuePool {
eprintln!("Error reading {}: {e}", path.display());
std::process::exit(1);
});
serde_yaml::from_str(&yaml_str).unwrap_or_else(|e| {
serde_norway::from_str(&yaml_str).unwrap_or_else(|e| {
eprintln!("Error parsing monologue YAML: {e}");
std::process::exit(1);
})
+2 -2
View File
@@ -431,9 +431,9 @@ pub fn print_monologue_results(results: &[MonologueResult], verbose: bool, _seed
pub fn print_coverage_report(yaml_str: &str, path: &Path) {
// Try dialogue first, then monologue
if let Ok(pool) = serde_yaml::from_str::<DialoguePool>(yaml_str) {
if let Ok(pool) = serde_norway::from_str::<DialoguePool>(yaml_str) {
print_dialogue_coverage(&pool, path);
} else if let Ok(pool) = serde_yaml::from_str::<MonologuePool>(yaml_str) {
} else if let Ok(pool) = serde_norway::from_str::<MonologuePool>(yaml_str) {
print_monologue_coverage(&pool, path);
} else {
eprintln!("Error: file is neither dialogue nor monologue YAML");