feat(perception): add cognitive delay system for fog recognition (#423)

New CognitiveDelay component buffers perception events before emitting
KnowledgeEvents. Normal delay: 6 ticks (0.6s), urgent: 3 ticks (0.3s).
Drain system runs after emit_observation_events, before process_knowledge_events.

Adds pending_recognitions to ObserverSnapshot (protocol v7) for client
fog entity visualization. Includes cancellation when entity leaves LOS.

Monologue fires during delay (not after) per D-060 — cross-system
wiring deferred to follow-up ticket #451.

Ref: D-060 (cognitive delay), D-031 (10 tps), D-059 (fog layers)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 00:41:08 +01:00
co-authored by Claude Opus 4.6
parent 3a2cfc37e0
commit 4d8fe996fc
17 changed files with 933 additions and 105 deletions
+19 -4
View File
@@ -79,8 +79,15 @@ pub fn process_knowledge_events(
if let Some(stable_id) = registry.to_stable(target) {
observer_kg.observe_entity(stable_id, position, event.tick);
} else {
debug_assert!(false, "DirectObservation target {:?} not in EntityRegistry", target);
tracing::error!("DirectObservation target {:?} not in EntityRegistry", target);
debug_assert!(
false,
"DirectObservation target {:?} not in EntityRegistry",
target
);
tracing::error!(
"DirectObservation target {:?} not in EntityRegistry",
target
);
}
}
KnowledgeEventType::LeftLOS { target } => {
@@ -262,7 +269,11 @@ mod tests {
world.insert_resource(thresholds);
// Tick 7: not a multiple of 10, decay should NOT run
world.insert_resource({ let mut t = SimulationTime::default(); t.tick = 7; t });
world.insert_resource({
let mut t = SimulationTime::default();
t.tick = 7;
t
});
let mut schedule = bevy_ecs::schedule::Schedule::default();
schedule.add_systems(decay_knowledge);
schedule.run(&mut world);
@@ -275,7 +286,11 @@ mod tests {
);
// Tick 10: multiple of 10, decay SHOULD run (age = 10 > decay_after = 5)
world.insert_resource({ let mut t = SimulationTime::default(); t.tick = 10; t });
world.insert_resource({
let mut t = SimulationTime::default();
t.tick = 10;
t
});
let mut schedule2 = bevy_ecs::schedule::Schedule::default();
schedule2.add_systems(decay_knowledge);
schedule2.run(&mut world);