refactor(server): decompose observer pipeline and fix interaction boundary

Extract visibility geometry into a separate system behind a
PerceptionQuery trait, enabling D-017 perception mode swapping.
Two-stage pipeline: compute_visibility_geometry writes to
VisibilityGeometry resource, compute_observer_snapshot reads it.

Remove KnowledgeGraph from compute_nearby_interactions (simulation
phase boundary violation). Verb availability stays in simulation;
POI-based priority adjustment moves to observer via
apply_poi_verb_priority helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 23:32:41 +01:00
co-authored by Claude Opus 4.6
parent e6bd577a5a
commit 18d8253bfe
9 changed files with 380 additions and 262 deletions
+19 -4
View File
@@ -90,7 +90,8 @@ mod tests {
use super::*;
use crate::knowledge::{EntityRegistry, KnowledgeGraph};
use crate::npc::Npc;
use crate::perception::observer::compute_observer_snapshot;
use crate::perception::observer::{compute_observer_snapshot, compute_visibility_geometry};
use crate::perception::query::{ActivePerceptionMode, VisibilityGeometry};
use crate::perception::vision_cone::Facing;
use crate::simulation::movement::WalkabilityMap;
@@ -101,6 +102,8 @@ mod tests {
world.init_resource::<SnapshotBuffer>();
world.init_resource::<KnowledgeEventQueue>();
world.init_resource::<EntityRegistry>();
world.init_resource::<VisibilityGeometry>();
world.init_resource::<ActivePerceptionMode>();
world
}
@@ -129,7 +132,11 @@ mod tests {
// First: compute snapshot so NPC is visible
let mut schedule = bevy_ecs::schedule::Schedule::default();
schedule.add_systems((compute_observer_snapshot, emit_observation_events).chain());
schedule.add_systems((
compute_visibility_geometry,
compute_observer_snapshot.after(compute_visibility_geometry),
emit_observation_events.after(compute_observer_snapshot),
));
schedule.run(&mut world);
let queue = world.resource::<KnowledgeEventQueue>();
@@ -171,7 +178,11 @@ mod tests {
walkability.set_walkable(&TilePosition::new(16, 15, 0), false);
let mut schedule = bevy_ecs::schedule::Schedule::default();
schedule.add_systems((compute_observer_snapshot, emit_observation_events).chain());
schedule.add_systems((
compute_visibility_geometry,
compute_observer_snapshot.after(compute_visibility_geometry),
emit_observation_events.after(compute_observer_snapshot),
));
schedule.run(&mut world);
let queue = world.resource::<KnowledgeEventQueue>();
@@ -203,7 +214,11 @@ mod tests {
world.insert_resource(registry);
let mut schedule = bevy_ecs::schedule::Schedule::default();
schedule.add_systems((compute_observer_snapshot, emit_observation_events).chain());
schedule.add_systems((
compute_visibility_geometry,
compute_observer_snapshot.after(compute_visibility_geometry),
emit_observation_events.after(compute_observer_snapshot),
));
schedule.run(&mut world);
let queue = world.resource::<KnowledgeEventQueue>();