fix(simulation): Clippy cleanup and CI enforcement (#635)

Fix all Clippy warnings across the server codebase (2411 insertions, 1341
deletions). Raise type-complexity-threshold to 750 and too-many-arguments
to 12 in .clippy.toml for idiomatic Bevy ECS system signatures. The server
now passes `cargo clippy -- --deny warnings` cleanly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-17 10:33:15 +01:00
co-authored by Claude Opus 4.6
parent 7f7706442a
commit aa79dd97e7
84 changed files with 2409 additions and 1339 deletions
+53 -30
View File
@@ -39,22 +39,22 @@ use bevy_ecs::entity::Entity;
use bevy_ecs::world::World;
use serde::{Deserialize, Serialize};
use crate::simulation::triangle::{TemplateOwnership, TemplateReferenceMap, TriangleState};
use crate::knowledge::graph::KnowledgeGraph;
use crate::knowledge::registry::StableEntityId;
use crate::knowledge::types::StableId;
use crate::simulation::modification::Modification;
use crate::npc::awareness::PlayerAwareness;
use crate::npc::mood::MoodState;
use crate::npc::relationships::RelationshipGraph;
use crate::npc::vision::{NpcMemory, NpcVisionState};
use crate::npc::{
CombatCapability, Contentment, DailyRoutine, InformationInventory, JobPerformance, Npc,
PersonalityTraits, Relationships, Secret, SecretSeverity, SkillSet, TellSystem,
ToleranceThreshold, Want, WantKind,
};
use crate::npc::awareness::PlayerAwareness;
use crate::npc::mood::MoodState;
use crate::npc::relationships::RelationshipGraph;
use crate::npc::vision::{NpcMemory, NpcVisionState};
use crate::simulation::modification::Modification;
use crate::simulation::movement::TilePosition;
use crate::simulation::time::TickRate;
use crate::simulation::triangle::{TemplateOwnership, TemplateReferenceMap, TriangleState};
use crate::storyteller::EngagementRecord;
/// Current format version. Bump on any breaking schema change.
@@ -181,7 +181,6 @@ pub struct NpcSaveState {
// --- Full reconstruction fields (added #96, for tier eviction freeze) ---
// All fields below use serde(default) for backward compatibility with saves
// created before #96 shipped.
/// Axis 1: Want (primary drive, intensity, and description).
#[serde(default)]
pub want: Option<Want>,
@@ -350,10 +349,7 @@ pub fn deserialize_npc_from_frozen(state: &NpcSaveState, world: &mut World) -> E
level: state.contentment,
};
let kg = state
.knowledge_graph
.clone()
.unwrap_or_else(KnowledgeGraph::new);
let kg = state.knowledge_graph.clone().unwrap_or_default();
// Spawn the entity with all required components. Tier marker (ActiveSim /
// BackgroundSim) is NOT added here — the caller assigns it after registration.
@@ -579,17 +575,14 @@ mod tests {
// Roundtrip the recovered state again — bytes must still match
let bytes2 = recovered.to_bytes().expect("re-serialize");
assert_eq!(
bytes, bytes2,
"KnowledgeGraph roundtrip must be idempotent"
);
assert_eq!(bytes, bytes2, "KnowledgeGraph roundtrip must be idempotent");
}
#[test]
fn relationship_graph_roundtrips() {
use crate::knowledge::types::StableId;
use crate::npc::relationships::RelationshipEdge;
use crate::npc::RelationshipKind;
use crate::knowledge::types::StableId;
let mut state = minimal_save_state();
let mut rg = RelationshipGraph::new();
@@ -608,7 +601,10 @@ mod tests {
let bytes = state.to_bytes().expect("serialize");
let recovered = SaveStateV1::from_bytes(&bytes).expect("deserialize");
let bytes2 = recovered.to_bytes().expect("re-serialize");
assert_eq!(bytes, bytes2, "RelationshipGraph roundtrip must be lossless");
assert_eq!(
bytes, bytes2,
"RelationshipGraph roundtrip must be lossless"
);
}
#[test]
@@ -660,12 +656,12 @@ mod tests {
// -----------------------------------------------------------------------
fn spawn_minimal_npc(world: &mut World, stable_id: StableId) -> Entity {
use crate::npc::awareness::PlayerAwareness;
use crate::npc::mood::MoodState;
use crate::npc::vision::{NpcMemory, NpcVisionState};
use crate::npc::{
Contentment, Relationships, Secret, SecretSeverity, ToleranceThreshold, Want, WantKind,
};
use crate::npc::mood::MoodState;
use crate::npc::vision::{NpcMemory, NpcVisionState};
use crate::npc::awareness::PlayerAwareness;
world
.spawn((
@@ -763,13 +759,22 @@ mod tests {
// Want
let orig_want = world.get::<Want>(original).cloned().unwrap();
let rest_want = world.get::<Want>(restored).cloned().unwrap();
assert_eq!(orig_want.primary, rest_want.primary, "want.primary must match");
assert_eq!(orig_want.intensity, rest_want.intensity, "want.intensity must match");
assert_eq!(
orig_want.primary, rest_want.primary,
"want.primary must match"
);
assert_eq!(
orig_want.intensity, rest_want.intensity,
"want.intensity must match"
);
// Secret severity
let orig_secret = world.get::<Secret>(original).cloned().unwrap();
let rest_secret = world.get::<Secret>(restored).cloned().unwrap();
assert_eq!(orig_secret.severity, rest_secret.severity, "secret severity must match");
assert_eq!(
orig_secret.severity, rest_secret.severity,
"secret severity must match"
);
}
#[test]
@@ -806,15 +811,24 @@ mod tests {
assert!(world.get::<StableEntityId>(entity).is_some());
assert!(world.get::<ToleranceThreshold>(entity).is_some());
assert!(world.get::<Contentment>(entity).is_some());
assert!(world.get::<Want>(entity).is_some(), "Want defaults to Safety");
assert!(world.get::<Secret>(entity).is_some(), "Secret built from secret_severity");
assert!(
world.get::<Want>(entity).is_some(),
"Want defaults to Safety"
);
assert!(
world.get::<Secret>(entity).is_some(),
"Secret built from secret_severity"
);
// Secret severity must be preserved from the legacy field
let secret = world.get::<Secret>(entity).unwrap();
assert_eq!(secret.severity, SecretSeverity::Moderate);
// Optional axes absent in frozen state → not inserted or use defaults
assert!(world.get::<DailyRoutine>(entity).is_none(), "routine absent when not frozen");
assert!(
world.get::<DailyRoutine>(entity).is_none(),
"routine absent when not frozen"
);
}
#[test]
@@ -845,7 +859,10 @@ mod tests {
let bytes = save.to_bytes().expect("serialize");
let recovered = SaveStateV1::from_bytes(&bytes).expect("deserialize");
let bytes2 = recovered.to_bytes().expect("re-serialize");
assert_eq!(bytes, bytes2, "frozen NPC state must roundtrip via MessagePack");
assert_eq!(
bytes, bytes2,
"frozen NPC state must roundtrip via MessagePack"
);
}
#[test]
@@ -885,7 +902,7 @@ mod tests {
#[test]
fn populated_modifications_roundtrips_in_save_state() {
// Acceptance (#567): non-empty modifications field survives save/load.
use crate::simulation::modification::{ModificationType, Modification};
use crate::simulation::modification::{Modification, ModificationType};
let mut state = minimal_save_state();
state.modifications = vec![
@@ -908,9 +925,15 @@ mod tests {
2,
"two modifications must survive roundtrip"
);
assert_eq!(recovered.modifications[0].position, TilePosition::new(10, 20, 0));
assert_eq!(
recovered.modifications[0].position,
TilePosition::new(10, 20, 0)
);
assert_eq!(recovered.modifications[0].placed_at_tick, 500);
assert_eq!(recovered.modifications[1].position, TilePosition::new(3, 7, -1));
assert_eq!(
recovered.modifications[1].position,
TilePosition::new(3, 7, -1)
);
assert_eq!(recovered.modifications[1].placed_at_tick, 1200);
let bytes2 = recovered.to_bytes().expect("re-serialize");