fix(server): address PR #23 review — 4 critical bugs, 3 warnings, 11 suggestions
Critical fixes: - Add PendingRecognitionWire serialization roundtrip test - Check Option return from delay.cancel() before logging - InputQueue capacity limit (1000) with drop-oldest and warning - TODO in observation.rs references ticket #450 Warning fixes: - Hot-reload guards against invalid/empty content root - Location header mismatch warning in line pool indexing - walk_yaml() depth limit (100) against symlink loops - Consecutive reload failure counter (warns after 5+) Test additions: - Negative prerequisite filtering test for monologue lines - Integration test for pending_recognitions in observer snapshot - Eavesdrop threshold ordering assertion (Careful < default) Documentation: - Playtesting expectation comments on delay constants - is_pending() scalability note for future NPC cognitive delay - ID format regex validation in line pool spec - BTreeMap vs sort() ordering clarification in loader - Multiplayer TODO in relationships.rs references D-010 - ContentSlug ticket #452 filed for entity slug resolution 394 tests, 0 failures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1817,3 +1817,101 @@ fn sprint_anomaly_multiple_contradicted_npcs_only_first_queued() {
|
||||
let queue = query.single(&world).unwrap();
|
||||
assert!(queue.has_pending(), "one anomaly should be queued");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Pending recognitions in observer snapshot (#423, D-060)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn pending_recognitions_appear_in_snapshot() {
|
||||
// H11: When a player entity has a CognitiveDelay component with pending
|
||||
// recognitions, compute_observer_snapshot should include them in
|
||||
// pending_recognitions for the client to render as grey blobs.
|
||||
use crate::perception::cognitive_delay::{
|
||||
CognitiveDelay, PendingRecognition, RecognitionTrigger,
|
||||
};
|
||||
|
||||
let mut world = setup_world(32, 32);
|
||||
let mut registry = EntityRegistry::new(0);
|
||||
|
||||
// Target entity that is being "recognized"
|
||||
let target = world.spawn_empty().id();
|
||||
let target_sid = registry.register(target);
|
||||
|
||||
// Player with CognitiveDelay containing a pending recognition
|
||||
let mut cd = CognitiveDelay::default();
|
||||
cd.push(PendingRecognition {
|
||||
target,
|
||||
stable_id: target_sid,
|
||||
position: TilePosition::new(16, 14, 0),
|
||||
delay_until_tick: 110, // will complete at tick 110
|
||||
trigger: RecognitionTrigger::Normal,
|
||||
});
|
||||
|
||||
let player = world
|
||||
.spawn((
|
||||
PlayerCharacter,
|
||||
TilePosition::new(16, 16, 0),
|
||||
Facing::default(),
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
cd,
|
||||
))
|
||||
.id();
|
||||
registry.register(player);
|
||||
world.insert_resource(registry);
|
||||
world.insert_resource({
|
||||
let mut t = SimulationTime::default();
|
||||
t.tick = 106; // 4 ticks remaining until recognition
|
||||
t
|
||||
});
|
||||
|
||||
run_observer_pipeline(&mut world);
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().expect("snapshot should exist");
|
||||
|
||||
assert_eq!(
|
||||
snapshot.pending_recognitions.len(),
|
||||
1,
|
||||
"should have one pending recognition in snapshot"
|
||||
);
|
||||
let pending = &snapshot.pending_recognitions[0];
|
||||
assert_eq!(pending.entity_id, target_sid.0);
|
||||
assert_eq!(pending.remaining_ticks, 4, "110 - 106 = 4 remaining");
|
||||
assert_eq!(
|
||||
pending.total_delay_ticks,
|
||||
crate::perception::cognitive_delay::NORMAL_DELAY_TICKS,
|
||||
"total delay should match Normal trigger"
|
||||
);
|
||||
// Position should be render coords of (16, 14, 0)
|
||||
let (expected_x, expected_y, expected_z) = TilePosition::new(16, 14, 0).to_render_coords();
|
||||
assert_eq!(pending.x, expected_x);
|
||||
assert_eq!(pending.y, expected_y);
|
||||
assert_eq!(pending.z, expected_z);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_cognitive_delay_component_means_empty_pending_recognitions() {
|
||||
// H11 complement: player WITHOUT CognitiveDelay should produce
|
||||
// an empty pending_recognitions vec (backward compatibility).
|
||||
let mut world = setup_world(32, 32);
|
||||
world.spawn((
|
||||
PlayerCharacter,
|
||||
TilePosition::new(16, 16, 0),
|
||||
Facing::default(),
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
));
|
||||
|
||||
run_observer_pipeline(&mut world);
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().unwrap();
|
||||
assert!(
|
||||
snapshot.pending_recognitions.is_empty(),
|
||||
"no CognitiveDelay component should produce empty pending_recognitions"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user