fix(client): align tests and data with server v4 protocol changes

Server team shipped strict PROTOCOL_VERSION enforcement (c05ff7b),
1-indexed verb priorities, and "Observe" label for ExamineNpc.
Updates all test snapshots to include version: 4, fixes sim_bridge
test mode priorities (0-indexed → 1-indexed) and labels, replaces
v1 backward-compat tests with strict version rejection tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 00:04:58 +01:00
co-authored by Claude Opus 4.6
parent 7af8de0117
commit 52972e6f21
5 changed files with 41 additions and 26 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ var visible_tiles: Array = []
var visible_positions: Dictionary = {} # Vector2i -> true, for fast fog lookups
# v2 fields (D-015, D-031)
var game_time: Dictionary = {} # {day, time_of_day, day_phase, paused} or empty
var game_time: Dictionary = {} # {day, time_of_day, day_phase, tick_rate} or empty
var player_facing: String = "North" # 8-directional facing direction
var visibility_sectors: Dictionary = {} # Vector2i -> "Forward"/"Peripheral"
+2 -2
View File
@@ -302,8 +302,8 @@ func _test_snapshot() -> Dictionary:
"entity_type": "Npc",
"distance": npc_dist,
"verbs": [
{"kind": "Talk", "label": "Talk", "priority": 0, "available": true},
{"kind": "ExamineNpc", "label": "Examine", "priority": 1, "available": true},
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{"kind": "ExamineNpc", "label": "Observe", "priority": 2, "available": true},
],
})
+22 -9
View File
@@ -21,8 +21,8 @@ func test_protocol_decode_v4_with_nearby_interactions() -> void:
"entity_type": "Npc",
"distance": 1,
"verbs": [
{"kind": "Talk", "label": "Talk", "priority": 0, "available": true},
{"kind": "ExamineNpc", "label": "Examine", "priority": 1, "available": true},
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{"kind": "ExamineNpc", "label": "Observe", "priority": 2, "available": true},
],
}],
}
@@ -39,14 +39,14 @@ func test_protocol_decode_v4_with_nearby_interactions() -> void:
assert_that(ni.verbs.size()).is_equal(2)
assert_that(ni.verbs[0].kind).is_equal("Talk")
assert_that(ni.verbs[0].label).is_equal("Talk")
assert_that(ni.verbs[0].priority).is_equal(0)
assert_that(ni.verbs[0].priority).is_equal(1)
assert_that(ni.verbs[0].available).is_true()
assert_that(ni.verbs[1].kind).is_equal("ExamineNpc")
func test_protocol_decode_v2_no_nearby_interactions() -> void:
func test_protocol_decode_v4_no_nearby_interactions() -> void:
var raw := {
"tick": 5,
"version": 2,
"version": 4,
"entities": [],
}
var encoded = Messagepack.encode(raw)
@@ -57,6 +57,7 @@ func test_protocol_decode_v2_no_nearby_interactions() -> void:
func test_protocol_decode_empty_nearby_interactions() -> void:
var raw := {
"tick": 1,
"version": 4,
"entities": [],
"nearby_interactions": [],
}
@@ -67,6 +68,7 @@ func test_protocol_decode_empty_nearby_interactions() -> void:
func test_protocol_decode_interaction_missing_verbs() -> void:
var raw := {
"tick": 1,
"version": 4,
"entities": [],
"nearby_interactions": [{"entity_id": 2}],
}
@@ -77,6 +79,7 @@ func test_protocol_decode_interaction_missing_verbs() -> void:
func test_protocol_decode_interaction_empty_verbs() -> void:
var raw := {
"tick": 1,
"version": 4,
"entities": [],
"nearby_interactions": [{"entity_id": 2, "entity_type": "Npc", "distance": 1, "verbs": []}],
}
@@ -97,12 +100,22 @@ func test_protocol_decode_v4_entity_relationship() -> void:
var snapshot = Protocol.decode_snapshot(encoded.value)
assert_that(snapshot.entities[0].relationship).is_equal("Friendly")
func test_protocol_rejects_version_mismatch() -> void:
var raw := {
"tick": 5,
"version": 2,
"entities": [],
}
var encoded = Messagepack.encode(raw)
var snapshot = Protocol.decode_snapshot(encoded.value)
assert_that(snapshot).is_null()
# -- GameState: nearby_interactions storage --
func test_game_state_stores_nearby_interactions() -> void:
var ni := [{"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 0, "available": true}]}]
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}]}]
GameState.apply_snapshot({"tick": 1, "entities": [], "nearby_interactions": ni})
assert_that(GameState.nearby_interactions.size()).is_equal(1)
assert_that(GameState.nearby_interactions[0].entity_id).is_equal(2)
@@ -110,7 +123,7 @@ func test_game_state_stores_nearby_interactions() -> void:
func test_game_state_clears_nearby_interactions_when_absent() -> void:
var ni := [{"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 0, "available": true}]}]
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}]}]
GameState.apply_snapshot({"tick": 1, "entities": [], "nearby_interactions": ni})
assert_that(GameState.nearby_interactions.size()).is_equal(1)
GameState.apply_snapshot({"tick": 2, "entities": []})
@@ -152,8 +165,8 @@ func test_prompt_get_selected_verb_returns_first_kind() -> void:
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [
{"kind": "Talk", "label": "Talk", "priority": 0, "available": true},
{"kind": "ExamineNpc", "label": "Examine", "priority": 1, "available": true},
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{"kind": "ExamineNpc", "label": "Observe", "priority": 2, "available": true},
],
}]
var prompt = _make_prompt()
+1 -1
View File
@@ -95,7 +95,7 @@ func test_frame_encode_large_payload_length() -> void:
func test_framed_protocol_snapshot_roundtrip() -> void:
# Encode a snapshot with Protocol, frame it, decode the frame, decode the snapshot
var snapshot_data := {"tick": 42, "entities": []}
var snapshot_data := {"tick": 42, "version": Protocol.PROTOCOL_VERSION, "entities": []}
var encoded: Variant = Messagepack.encode(snapshot_data)
assert_that(encoded.status).is_null()
+15 -13
View File
@@ -188,6 +188,7 @@ func test_decode_snapshot_malformed_entities_counted() -> void:
# Snapshot with one valid and one malformed entity — decode_errors should count the bad one
var raw := {
"tick": 7,
"version": Protocol.PROTOCOL_VERSION,
"entities": [
{"entity_id": 1, "x": 5.0, "y": 10.0, "z": 0, "kind": "Npc"},
{"entity_id": 2, "broken": true}, # Missing required fields
@@ -321,10 +322,10 @@ func test_multi_entity_visibility_sectors() -> void:
assert_that(snapshot.entities[3].visibility).is_equal("Forward")
# -- v1 backward compatibility (no v2 fields → graceful null defaults) --------
# -- Version enforcement (strict PROTOCOL_VERSION check) --------------------
func test_decode_v1_snapshot_graceful_defaults() -> void:
# Minimal v1 snapshot — only tick + entities, no v2 fields
func test_decode_snapshot_rejects_missing_version() -> void:
# Snapshot without version field → rejected by strict version check
var v1_raw := {"tick": 10, "entities": [
{"entity_id": 1, "x": 5.0, "y": 5.0, "z": 0, "kind": "Player"},
]}
@@ -332,16 +333,17 @@ func test_decode_v1_snapshot_graceful_defaults() -> void:
assert_that(encoded.status).is_null()
var snapshot: Variant = Protocol.decode_snapshot(encoded.value)
assert_that(snapshot).is_not_null()
assert_that(snapshot.tick).is_equal(10)
assert_that(snapshot.entities.size()).is_equal(1)
# v2 fields should be null/empty, not crash
assert_that(snapshot.version).is_null()
assert_that(snapshot.game_time).is_null()
assert_that(snapshot.player_facing).is_null()
assert_that(snapshot.visible_tiles.size()).is_equal(0)
# Entity should have null visibility
assert_that(snapshot.entities[0].visibility).is_null()
assert_that(snapshot).is_null()
func test_decode_snapshot_rejects_old_version() -> void:
# Snapshot with version 2 → rejected by strict version check
var old_raw := {"tick": 10, "version": 2, "entities": []}
var encoded: Variant = Messagepack.encode(old_raw)
assert_that(encoded.status).is_null()
var snapshot: Variant = Protocol.decode_snapshot(encoded.value)
assert_that(snapshot).is_null()
# -- Batch input fixture (D-030 Layer 1 bidirectional symmetry) ----------------