fix(simulation): address PR #10 review — plugin wiring, stale reset, warnings

- Register KnowledgePlugin in main.rs and game_loop test (Tyre critical)
- Add KnowledgeGraph component to player spawn (Tyre critical)
- Reset Stale -> Active on fresh direct observation (Hoshe warning)
- Make registry/queue non-optional in emit_observation_events (Tyre/Hoshe)
- Add tracing::warn for missing EntityRegistry entries (Hoshe warning)
- Replace HashSet with Vec for small entity ID lookups (Hoshe suggestion)
- Add const static assertion for KnowledgeConfidence ordering (Hoshe)
- Add is_empty() and known_facts_iter() to KnowledgeGraph (Tyre)
- Add decay_skips_non_minute_ticks and observe_resets_stale tests (Hoshe)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 01:06:33 +01:00
co-authored by Claude Opus 4.6
parent a68a3ef429
commit 3115c7a84c
6 changed files with 113 additions and 15 deletions
+31 -2
View File
@@ -95,6 +95,16 @@ impl KnowledgeGraph {
self.facts.len()
}
/// Whether the knowledge graph has no entries at all.
pub fn is_empty(&self) -> bool {
self.entities.is_empty() && self.facts.is_empty()
}
/// Iterate all known facts (deterministic order via BTreeMap).
pub fn known_facts_iter(&self) -> impl Iterator<Item = (&FactId, &FactKnowledge)> {
self.facts.iter()
}
// --- Write Operations ---
/// Record a direct observation of another entity (entity is in LOS).
@@ -119,8 +129,12 @@ impl KnowledgeGraph {
entry.last_updated_tick = tick;
entry.confidence = KnowledgeConfidence::Direct;
entry.source = KnowledgeSource::DirectObservation { tick };
// Do NOT reset state here -- a Contradicted entry stays Contradicted
// even if you're looking at the entity right now.
// Stale entries become Active again on fresh observation.
// Contradicted entries stay Contradicted even if you're looking
// at the entity right now — the contradiction is still unresolved.
if entry.state == KnowledgeState::Stale {
entry.state = KnowledgeState::Active;
}
}
/// Entity has left the observer's LOS. Downgrade from Direct.
@@ -355,6 +369,21 @@ mod tests {
assert_eq!(entry.last_known_position, Some(make_position(6, 10)));
}
#[test]
fn observe_resets_stale_to_active() {
let mut g = KnowledgeGraph::new();
let target = StableId(1);
g.observe_entity(target, make_position(5, 10), 100);
// Mark as stale (would be done by decay system)
g.entities.get_mut(&target).unwrap().state = KnowledgeState::Stale;
// Re-observe — stale should reset to Active
g.observe_entity(target, make_position(6, 10), 200);
let entry = g.entity_knowledge(&target).unwrap();
assert_eq!(entry.state, KnowledgeState::Active);
assert_eq!(entry.confidence, KnowledgeConfidence::Direct);
}
#[test]
fn with_background_creates_facts() {
let facts = vec![