#94 — Active tier simulation (complete): - Add ActiveSim marker to all 9 test world room NPC spawns - Fix test entities in routine.rs and path_follow.rs to include ActiveSim so With<ActiveSim> queries match correctly in unit tests #99 — Tier transition logic (complete): - Implement update_tier_markers system in tier.rs - Promotes/demotes tier markers by manhattan distance from PlayerCharacter: ≤40 tiles → ActiveSim, ≤120 → BackgroundSim, beyond → StateSaved - Handles cross-z-level as u32::MAX (effectively unreachable) - No-op when no PlayerCharacter entity present (headless tests safe) - 11 new unit tests covering all distance bands and boundary cases - TierPlugin now registers the system after movement::validate_movement Also picks up extended test coverage added by hoshe: - observer/tests.rs — 230 lines of perception observer tests - sound.rs — additional sound event integration tests All 548 tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,8 @@ use bevy_ecs::prelude::*;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use crate::bridge::types::*;
|
||||
use crate::knowledge::types::KnowledgeState;
|
||||
use crate::knowledge::graph::filter_by_access;
|
||||
use crate::knowledge::types::{AccessRule, KnowledgeState};
|
||||
use crate::knowledge::{EntityRegistry, KnowledgeGraph, StableId};
|
||||
use crate::perception::cognitive_delay::CognitiveDelay;
|
||||
use crate::perception::query::{ActivePerceptionMode, VisibilityGeometry};
|
||||
@@ -80,6 +81,7 @@ pub fn compute_observer_snapshot(
|
||||
&TilePosition,
|
||||
Option<&PlayerCharacter>,
|
||||
Option<&crate::npc::Npc>,
|
||||
Option<&AccessRule>,
|
||||
)>,
|
||||
inventory_items: Query<(Entity, &CarriedBy, &ItemName, &InventorySlot)>,
|
||||
mut buffer: ResMut<SnapshotBuffer>,
|
||||
@@ -121,8 +123,13 @@ pub fn compute_observer_snapshot(
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
// Resolve observer's StableId for component-level access control (#139, D-010)
|
||||
let observer_stable_id = registry
|
||||
.to_stable(observer_entity)
|
||||
.unwrap_or(StableId(0));
|
||||
|
||||
let (mut entities, visible_ids, blocked_entities) =
|
||||
filter_visible_entities(&geometry, ®istry, observer_kg, &all_entities);
|
||||
filter_visible_entities(&geometry, ®istry, observer_kg, observer_stable_id, &all_entities);
|
||||
|
||||
collect_remembered_entities(
|
||||
observer_kg,
|
||||
@@ -237,18 +244,20 @@ fn filter_visible_entities(
|
||||
geometry: &VisibilityGeometry,
|
||||
registry: &EntityRegistry,
|
||||
observer_kg: &KnowledgeGraph,
|
||||
observer_stable_id: StableId,
|
||||
all_entities: &Query<(
|
||||
Entity,
|
||||
&TilePosition,
|
||||
Option<&PlayerCharacter>,
|
||||
Option<&crate::npc::Npc>,
|
||||
Option<&AccessRule>,
|
||||
)>,
|
||||
) -> (Vec<VisibleEntity>, BTreeSet<u64>, Vec<u64>) {
|
||||
let mut entities = Vec::new();
|
||||
let mut visible_ids: BTreeSet<u64> = BTreeSet::new();
|
||||
let mut blocked_ids: BTreeSet<u64> = BTreeSet::new();
|
||||
|
||||
for (entity, pos, is_player, is_npc) in all_entities.iter() {
|
||||
for (entity, pos, is_player, is_npc, access_rule) in all_entities.iter() {
|
||||
if pos.z != geometry.observer_z {
|
||||
continue;
|
||||
}
|
||||
@@ -289,7 +298,16 @@ fn filter_visible_entities(
|
||||
let relationship = if is_player.is_some() {
|
||||
RelationshipState::Known // Self
|
||||
} else if let Some(stable_id) = registry.to_stable(entity) {
|
||||
observer_kg.relationship_with(&stable_id)
|
||||
// D-010 principle 2: check access control before exposing relationship (#139)
|
||||
let access_granted = match access_rule {
|
||||
Some(rule) => filter_by_access(observer_stable_id, stable_id, &rule.0, observer_kg),
|
||||
None => true, // No AccessRule → Public (default)
|
||||
};
|
||||
if access_granted {
|
||||
observer_kg.relationship_with(&stable_id)
|
||||
} else {
|
||||
RelationshipState::Unknown // Access denied — redact relationship data
|
||||
}
|
||||
} else {
|
||||
RelationshipState::Unknown
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user