feat: add provenance-aware npc communication
This commit is contained in:
@@ -16,6 +16,7 @@ func _run() -> void:
|
||||
_test_previous_world_event_migration()
|
||||
_test_previous_world_relationship_migration()
|
||||
_test_previous_world_knowledge_migration()
|
||||
_test_previous_world_provenance_migration()
|
||||
_test_relationship_schema_rejection()
|
||||
_test_schema_rejection()
|
||||
|
||||
@@ -266,7 +267,7 @@ func _test_previous_world_relationship_migration() -> void:
|
||||
func _test_previous_world_knowledge_migration() -> void:
|
||||
var manager := _create_manager(59)
|
||||
var previous_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
previous_data["schema_version"] = SimulationStateRecord.PREVIOUS_SCHEMA_VERSION
|
||||
previous_data["schema_version"] = SimulationStateRecord.KNOWLEDGE_LEGACY_SCHEMA_VERSION
|
||||
previous_data.erase("event_knowledge")
|
||||
var deposit_event := EconomicEventRecord.create(
|
||||
0,
|
||||
@@ -291,12 +292,72 @@ func _test_previous_world_knowledge_migration() -> void:
|
||||
migrated.event_knowledge.size() == 1
|
||||
and migrated.event_knowledge[0].get_knower_id() == 0
|
||||
and migrated.event_knowledge[0].get_event_id() == 0
|
||||
and (
|
||||
migrated.event_knowledge[0].get_acquisition_method()
|
||||
== SimulationIds.KNOWLEDGE_ACQUISITION_LEGACY
|
||||
)
|
||||
),
|
||||
"World v4 migration should preserve the fact implied by a relationship cause"
|
||||
)
|
||||
manager.free()
|
||||
|
||||
|
||||
func _test_previous_world_provenance_migration() -> void:
|
||||
var manager := _create_manager(60)
|
||||
var previous_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
previous_data["schema_version"] = SimulationStateRecord.PREVIOUS_SCHEMA_VERSION
|
||||
var deposit_event := EconomicEventRecord.create(
|
||||
0,
|
||||
SimulationIds.EVENT_STORAGE_DEPOSITED,
|
||||
12,
|
||||
1,
|
||||
SimulationIds.npc_inventory_id(1),
|
||||
SimulationIds.STORAGE_VILLAGE_PANTRY,
|
||||
SimulationIds.RESOURCE_FOOD,
|
||||
2.0
|
||||
)
|
||||
previous_data["economic_events"] = [deposit_event.to_dictionary()]
|
||||
previous_data["simulation"]["next_event_id"] = 1
|
||||
previous_data["event_knowledge"] = [
|
||||
{"schema_version": 1, "knower_id": 0, "event_id": 0},
|
||||
{"schema_version": 1, "knower_id": 1, "event_id": 0},
|
||||
]
|
||||
previous_data["relationships"] = [
|
||||
RelationshipStateRecord.create(0, 1, 0.5, 0.65, 0).to_dictionary()
|
||||
]
|
||||
var migrated := SimulationStateRecord.from_dictionary(previous_data)
|
||||
_check(migrated != null, "World schema v5 should add honest acquisition provenance")
|
||||
if migrated != null:
|
||||
var observer_record: KnownEventStateRecord
|
||||
var actor_record: KnownEventStateRecord
|
||||
for known_event in migrated.event_knowledge:
|
||||
if known_event.get_knower_id() == 0:
|
||||
observer_record = known_event
|
||||
elif known_event.get_knower_id() == 1:
|
||||
actor_record = known_event
|
||||
_check(
|
||||
(
|
||||
actor_record != null
|
||||
and (
|
||||
actor_record.get_acquisition_method()
|
||||
== SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED
|
||||
)
|
||||
),
|
||||
"World v5 migration can safely identify an actor's own completed fact"
|
||||
)
|
||||
_check(
|
||||
(
|
||||
observer_record != null
|
||||
and (
|
||||
observer_record.get_acquisition_method()
|
||||
== SimulationIds.KNOWLEDGE_ACQUISITION_LEGACY
|
||||
)
|
||||
),
|
||||
"World v5 migration must not invent witness or speaker provenance"
|
||||
)
|
||||
manager.free()
|
||||
|
||||
|
||||
func _test_relationship_schema_rejection() -> void:
|
||||
var manager := _create_manager(58)
|
||||
var missing_cause_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
@@ -391,6 +452,96 @@ func _test_relationship_schema_rejection() -> void:
|
||||
SimulationStateRecord.from_dictionary(nonpositive_cause_data) == null,
|
||||
"A trust cause must describe a successful positive food deposit"
|
||||
)
|
||||
|
||||
var provenance_event := EconomicEventRecord.create(
|
||||
0,
|
||||
SimulationIds.EVENT_STORAGE_DEPOSITED,
|
||||
1,
|
||||
0,
|
||||
SimulationIds.npc_inventory_id(0),
|
||||
SimulationIds.STORAGE_VILLAGE_PANTRY,
|
||||
SimulationIds.RESOURCE_FOOD,
|
||||
1.0
|
||||
)
|
||||
var missing_source_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
missing_source_data["economic_events"] = [provenance_event.to_dictionary()]
|
||||
missing_source_data["simulation"]["next_event_id"] = 1
|
||||
missing_source_data["event_knowledge"] = [
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(1, 0, SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED, 2)
|
||||
. to_dictionary()
|
||||
)
|
||||
]
|
||||
_check(
|
||||
SimulationStateRecord.from_dictionary(missing_source_data) == null,
|
||||
"Communicated knowledge must reference a source who knows the same event"
|
||||
)
|
||||
|
||||
var wrong_actor_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
wrong_actor_data["economic_events"] = [provenance_event.to_dictionary()]
|
||||
wrong_actor_data["simulation"]["next_event_id"] = 1
|
||||
wrong_actor_data["event_knowledge"] = [
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(1, 0, SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED)
|
||||
. to_dictionary()
|
||||
)
|
||||
]
|
||||
_check(
|
||||
SimulationStateRecord.from_dictionary(wrong_actor_data) == null,
|
||||
"Performed provenance must belong to the event actor"
|
||||
)
|
||||
|
||||
var relayed_source_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
relayed_source_data["economic_events"] = [provenance_event.to_dictionary()]
|
||||
relayed_source_data["simulation"]["next_event_id"] = 1
|
||||
relayed_source_data["event_knowledge"] = [
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(1, 0, SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED, 2)
|
||||
. to_dictionary()
|
||||
),
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(2, 0, SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED, 0)
|
||||
. to_dictionary()
|
||||
),
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(0, 0, SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED)
|
||||
. to_dictionary()
|
||||
),
|
||||
]
|
||||
_check(
|
||||
SimulationStateRecord.from_dictionary(relayed_source_data) == null,
|
||||
"Communicated facts must not form a second relay hop in this phase"
|
||||
)
|
||||
|
||||
var order_independent_data: Dictionary = manager.create_state_record().to_dictionary()
|
||||
order_independent_data["economic_events"] = [provenance_event.to_dictionary()]
|
||||
order_independent_data["simulation"]["next_event_id"] = 1
|
||||
order_independent_data["event_knowledge"] = [
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(1, 0, SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED, 2)
|
||||
. to_dictionary()
|
||||
),
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(0, 0, SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED)
|
||||
. to_dictionary()
|
||||
),
|
||||
(
|
||||
KnownEventStateRecord
|
||||
. create(2, 0, SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED)
|
||||
. to_dictionary()
|
||||
),
|
||||
]
|
||||
_check(
|
||||
SimulationStateRecord.from_dictionary(order_independent_data) != null,
|
||||
"Provenance validation should not depend on knowledge array ordering"
|
||||
)
|
||||
manager.free()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user