test(simulation): cross-room transition scenarios T1-T8 + test suite expansion (#506)

Cross-room transition tests (server/tests/cross_room_transitions.rs):
- T1: sprint suppresses interaction buffer, restores on Walk (D-055)
- T2: CarriedBy survives room transition — no TilePosition leak (D-065)
- T3: pause mid-corridor discards movement, Unpause resumes (D-031)
- T4: KnowledgeGraph persists across player position change (D-041)
- T5: entity knowledge downgrades Direct→KnowsDetails on LOS exit (D-060)
- T6: eavesdrop cut immediately on first movement out of corner (D-071)
- T7: confrontation verb disappears on retreat beyond MID_RANGE=5 (D-057/D-070)
- T8: Sprint blocks eavesdrop accumulation, Careful enables it (D-055+D-071)

All 8 tests pass. Test suite grows from 545 → 563 (18 tests added across sprint).
Tests use direct ECS World + Schedule pattern; T3 uses full App + SimulationPlugin.

Test suite expansion:
- content_scaling.rs: max_npc_pack_behavioral_regression + stress tests (#513)
- golden/proof_room_tick_10.json: updated golden file for gauntlet world changes
- golden_suite.rs, serialization.rs, bridge_ipc.rs, bridge_tcp.rs: adapted to
  new world entity count and wire types
- gen_fixtures.rs, perf_bench.rs, content_runtime.rs: minor test adaptations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 12:04:29 +01:00
co-authored by Claude Sonnet 4.6
parent d103e445e7
commit bee93963d9
11 changed files with 925 additions and 34 deletions
+8 -10
View File
@@ -25,6 +25,7 @@ fn test_snapshot(tick: u64, entities: Vec<VisibleEntity>) -> ObserverSnapshot {
pending_recognitions: vec![],
dialogue_response: None,
blocked_entities: vec![],
scan_events: vec![],
}
}
@@ -252,6 +253,7 @@ fn snapshot_v2_fields_roundtrip() {
pending_recognitions: vec![],
dialogue_response: None,
blocked_entities: vec![],
scan_events: vec![],
};
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
@@ -345,6 +347,7 @@ fn all_facing_direction_variants_roundtrip() {
pending_recognitions: vec![],
dialogue_response: None,
blocked_entities: vec![],
scan_events: vec![],
};
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
@@ -1040,18 +1043,16 @@ fn gdscript_generated_fixtures_deserialize() {
let bytes = fs::read(&path).unwrap_or_else(|_| panic!("read fixture {}", name));
if name.starts_with("input_batch") {
let inputs: Vec<PlayerInput> = rmp_serde::from_slice(&bytes).unwrap_or_else(|e| {
panic!("deserialize GDScript batch fixture {}: {}", name, e)
});
let inputs: Vec<PlayerInput> = rmp_serde::from_slice(&bytes)
.unwrap_or_else(|e| panic!("deserialize GDScript batch fixture {}: {}", name, e));
assert!(
!inputs.is_empty(),
"batch fixture {} should not be empty",
name
);
} else if name.starts_with("input_") || name.starts_with("boundary_tick_") {
let input: PlayerInput = rmp_serde::from_slice(&bytes).unwrap_or_else(|e| {
panic!("deserialize GDScript input fixture {}: {}", name, e)
});
let input: PlayerInput = rmp_serde::from_slice(&bytes)
.unwrap_or_else(|e| panic!("deserialize GDScript input fixture {}: {}", name, e));
// Verify specific fixtures for extra confidence
match name.as_str() {
"input_move_north" => {
@@ -1078,10 +1079,7 @@ fn gdscript_generated_fixtures_deserialize() {
assert_eq!(input.tick, 65536, "int_32 asymmetry: tick=65536");
}
"boundary_tick_2147483647" => {
assert_eq!(
input.tick, 2147483647,
"int_32 asymmetry: tick=2^31-1"
);
assert_eq!(input.tick, 2147483647, "int_32 asymmetry: tick=2^31-1");
}
_ => {} // Other fixtures: deserialization success is sufficient
}