Files
TheTree_mock/tests/s1/test_runtime_infrastructure_integration.gd
T

1310 lines
50 KiB
GDScript

extends SceneTree
const RUNTIME_SNAPSHOT_VERSION := 14
const INFRASTRUCTURE_SNAPSHOT_KEYS: Array[StringName] = [
&"excavation",
&"spatial_subslots",
&"route_projection",
&"facility_infrastructure",
]
const INFRASTRUCTURE_MEMBER_NAMES: Array[StringName] = [
&"excavation_service",
&"spatial_subslot_service",
&"route_subslot_path_adapter",
&"facility_infrastructure_projector",
]
const PathType = preload("res://scripts/world/path_service.gd")
class DenyingOperationsCoordinator:
extends OperationsCoordinator
func can_start_construction_or_investment() -> Dictionary:
return {
&"allowed": false,
&"reason": &"ARREARS_REMAIN",
&"arrears_total": 1,
&"consecutive_insolvency_count": 1,
}
class SnapshotCountingDomainEventStream:
extends DomainEventStream
var snapshot_calls := 0
func create_snapshot() -> Dictionary:
snapshot_calls += 1
return super.create_snapshot()
class CountingSpatialValidation:
extends SpatialSubslotService
var validation_calls := 0
func validate_invariants() -> Dictionary:
validation_calls += 1
return super.validate_invariants()
class CountingAdapterValidation:
extends RouteSubslotPathAdapter
var validation_calls := 0
func validate_invariants() -> Dictionary:
validation_calls += 1
return super.validate_invariants()
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
print("S1: Runtime infrastructure integration")
var probe := _new_fixture(81_001)
var surface_ready := _test_runtime_surface(probe)
_test_exact_cell_sets(probe[&"runtime"])
_free_fixture(probe)
if surface_ready:
_test_composed_infrastructure_validation()
_test_completion_capture_fast_path()
_test_rank_and_operations_gates()
_test_excavation_tick_pause_resume_and_completion()
_test_completed_proxy_projection()
_test_proxy_completion_raw_signal_commit_order()
_test_proxy_completion_projection_failure_is_atomic()
_test_completed_elevator_topology()
_test_demolition_projection_atomicity()
_test_current_snapshot_strictness()
_test_v5_proxy_migration_determinism()
_test_rank_expansion_preserves_route_union()
_finish()
func _finish() -> void:
if _failures == 0:
print("PASS: %d checks" % _checks)
else:
push_error("FAIL: %d of %d checks failed" % [_failures, _checks])
quit(_failures)
func _test_composed_infrastructure_validation() -> void:
var fixture := _new_fixture(81_099)
var runtime: Variant = fixture[&"runtime"]
var spatial := CountingSpatialValidation.new()
var adapter := CountingAdapterValidation.new()
var path := PathService.new()
var projector := FacilityInfrastructureProjector.new()
_expect(adapter.configure(spatial, path, runtime.world_service.get_walkable_cells()), "counted route dependencies configure")
_expect(projector.configure(adapter, spatial, path), "counted projector binds authoritative dependencies")
var validate := func() -> bool:
return runtime.call("_validate_infrastructure_crosslinks", runtime.world_service, path,
runtime.construction_service, runtime.construction_resource_state, runtime.excavation_service,
spatial, adapter, projector)
spatial.validation_calls = 0
adapter.validation_calls = 0
_expect(validate.call(), "composed infrastructure validation accepts healthy graph")
_expect(spatial.validation_calls == 1 and adapter.validation_calls == 1, "one graph audit validates each dependency exactly once")
_expect(projector.is_bound_to(adapter, spatial, path) and not projector.is_bound_to(adapter, SpatialSubslotService.new(), path), "binding test requires identical dependency objects")
spatial.revision = -1
_expect(not validate.call(), "active composed check still catches raw source corruption")
spatial.revision = 0
var prior_revision := adapter.projection_revision
adapter.projection_revision = -1
_expect(not validate.call(), "active composed check still catches raw adapter corruption")
adapter.projection_revision = prior_revision
projector.set("_quarantined", true)
projector.set("_quarantine_reason", FacilityInfrastructureProjector.QUARANTINE_REASONS[0])
spatial.validation_calls = 0
adapter.validation_calls = 0
_expect(validate.call(), "canonical quarantined projector retains previous graph-validation semantics")
_expect(spatial.validation_calls == 1 and adapter.validation_calls == 1, "quarantine retains independent dependency checks")
spatial.revision = -1
_expect(not validate.call(), "quarantine never conceals malformed supplied source")
spatial.revision = 0
projector.set("_quarantined", false)
projector.set("_quarantine_reason", &"")
var original_projector: FacilityInfrastructureProjector = runtime.facility_infrastructure_projector
spatial.revision = -1
_expect(not runtime.call("_validate_infrastructure_crosslinks", runtime.world_service, path,
runtime.construction_service, runtime.construction_resource_state, runtime.excavation_service,
spatial, adapter, original_projector), "different projector binding does not bypass supplied-source validation")
_free_fixture(fixture)
func _test_exact_cell_sets(runtime: Variant) -> void:
var first := Vector3i(0, 0, 0)
var second := Vector3i(1, 0, 0)
_expect(runtime.call("_same_vector3i_set", [first, second], [second, first]), "cell equality ignores order")
_expect(not runtime.call("_same_vector3i_set", [first, second], [first, first]), "duplicate actual cell cannot conceal a missing cell")
_expect(not runtime.call("_same_vector3i_set", [first, first], [first, second]), "duplicate expected cell is rejected")
_expect(runtime.call("_same_vector3i_set", [], []), "empty cell sets match")
_expect(not runtime.call("_same_vector3i_set", [first], [Vector3i(0, 0, 1)]), "same coordinate in another layer does not match")
_expect(not runtime.call("_same_vector3i_set", [first], [Vector2i.ZERO]), "wrong cell type is rejected")
func _new_fixture(seed: int) -> Dictionary:
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0)
state.reset()
var initialized: Dictionary = runtime.initialize(clock, state, seed)
clock.set_paused(true)
_expect(bool(initialized.get(&"valid", false)), "fixture Runtime initializes")
return {&"clock": clock, &"state": state, &"runtime": runtime}
func _free_fixture(fixture: Dictionary) -> void:
var runtime: Variant = fixture.get(&"runtime")
var clock: Variant = fixture.get(&"clock")
var state: Variant = fixture.get(&"state")
if runtime != null:
runtime.free()
if clock != null:
clock.free()
if state != null:
state.free()
func _test_runtime_surface(fixture: Dictionary) -> bool:
var runtime: Variant = fixture[&"runtime"]
var ready := true
for member_name: StringName in INFRASTRUCTURE_MEMBER_NAMES:
var present := _object_has_property(runtime, member_name)
_expect(present, "Runtime publishes %s" % member_name)
ready = ready and present
if present:
var service: Variant = runtime.get(member_name)
_expect(service != null, "%s is initialized" % member_name)
ready = ready and service != null
var snapshot: Dictionary = runtime.create_snapshot()
var runtime_data: Dictionary = snapshot[&"systems"][&"runtime"]
var current_version := int(runtime_data.get(&"runtime_schema_version", -1)) == RUNTIME_SNAPSHOT_VERSION
_expect(current_version, "Runtime emits schema v14 with infrastructure and weather state")
ready = ready and current_version
for key: StringName in INFRASTRUCTURE_SNAPSHOT_KEYS:
var valid_dictionary := runtime_data.get(key, null) is Dictionary
_expect(valid_dictionary, "current Runtime stores strict %s state" % key)
ready = ready and valid_dictionary
if not ready:
print(" PENDING: Runtime v9 infrastructure surface is not connected yet; behavioral cases skipped.")
return ready
func _test_completion_capture_fast_path() -> void:
var fixture := _new_fixture(81_005)
var runtime: Variant = fixture[&"runtime"]
var clock: Variant = fixture[&"clock"]
var counting_events := SnapshotCountingDomainEventStream.new()
_expect(
counting_events.restore_snapshot(runtime.domain_events.create_snapshot()),
"fast-path probe preserves the authoritative DomainEvent stream"
)
runtime.domain_events = counting_events
counting_events.snapshot_calls = 0
clock.advance_minutes(1)
_expect(
counting_events.snapshot_calls == 1,
"idle Construction tick performs only the normal publish snapshot capture"
)
_expect(
runtime.construction_service.current_minute == clock.absolute_minute
and runtime.excavation_service.current_minute == clock.absolute_minute,
"idle fast path keeps Construction and Excavation on the exact Runtime minute"
)
var started = _submit(
runtime,
&"build_facility",
{
&"definition_id": &"guest_corridor",
&"origin": Vector3i(0, 1, PathType.FRONT),
&"rotation": 0,
},
&"infra.fast_path.progress"
)
_expect(started.is_success(), "fast-path probe starts a non-completing Construction job")
if not started.is_success():
_free_fixture(fixture)
return
var job_id := StringName(started.details.get(&"job_id", &""))
var raw_job_changed_count := [0]
runtime.construction_service.job_changed.connect(
func(changed_job: ConstructionJob) -> void:
if changed_job != null and changed_job.job_id == job_id:
raw_job_changed_count[0] += 1
)
counting_events.snapshot_calls = 0
clock.advance_minutes(1)
var job: ConstructionJob = runtime.construction_service.get_job(job_id)
_expect(
job != null and job.state == ConstructionJob.State.BUILDING
and job.progress > 0 and job.progress < ConstructionJob.MAX_PROGRESS,
"ordinary Construction progress remains on the non-completion fast path"
)
_expect(
counting_events.snapshot_calls == 1,
"non-completing Construction progress avoids the full completion token"
)
_expect(
raw_job_changed_count[0] == 1,
"non-completion fast path preserves the raw job_changed notification"
)
_expect(
runtime.construction_service.current_minute == clock.absolute_minute
and runtime.excavation_service.current_minute == clock.absolute_minute,
"progress fast path keeps both minute-driven infrastructure services synchronized"
)
_free_fixture(fixture)
func _test_rank_and_operations_gates() -> void:
var fixture := _new_fixture(81_010)
var runtime: Variant = fixture[&"runtime"]
var target := Vector3i(0, -1, PathType.FRONT)
var before_rank_gate := _infrastructure_state(fixture)
var rank_rejected = _submit(
runtime, &"start_excavation", {&"cell": target}, &"infra.rank.reject"
)
_expect(not rank_rejected.is_success(), "Rank 1 cannot start excavation")
_expect(
_infrastructure_state(fixture) == before_rank_gate,
"Rank rejection changes no infrastructure or resource state"
)
_expect(_promote_rank_two(fixture, &"infra.rank"), "fixture reaches Rank 2 through public commands")
_free_fixture(fixture)
fixture = _new_fixture(81_011)
runtime = fixture[&"runtime"]
_expect(_promote_rank_two(fixture, &"infra.operations.rank"), "Operations-gate fixture reaches Rank 2")
var enabled: Dictionary = runtime.enable_production_operations()
_expect(bool(enabled.get(&"ok", false)), "Operations enable before gate probe")
# A deterministic coordinator test double exercises the public gate result
# without advancing a full payroll day or mutating Runtime private helpers.
runtime.operations_coordinator = DenyingOperationsCoordinator.new()
var before_operations_gate := _infrastructure_state(fixture)
var gate_rejected = _submit(
runtime, &"start_excavation", {&"cell": target}, &"infra.operations.reject"
)
_expect(
not gate_rejected.is_success()
and gate_rejected.details.get(&"reason", &"") == &"ARREARS_REMAIN",
"excavation uses the Operations construction/investment gate"
)
_expect(
_infrastructure_state(fixture) == before_operations_gate,
"Operations gate rejection is infrastructure-atomic"
)
_free_fixture(fixture)
func _test_excavation_tick_pause_resume_and_completion() -> void:
var fixture := _new_fixture(81_020)
var runtime: Variant = fixture[&"runtime"]
var clock: Variant = fixture[&"clock"]
_expect(_promote_rank_two(fixture, &"infra.excavation.rank"), "excavation fixture reaches Rank 2")
var target := Vector3i(0, -1, PathType.FRONT)
var started = _submit(
runtime, &"start_excavation", {&"cell": target}, &"infra.excavation.start"
)
_expect(started.is_success(), "start_excavation accepts a cell payload")
if not started.is_success():
_free_fixture(fixture)
return
var excavation_job_id := StringName(started.details.get(&"job_id", &""))
var excavation_events_before := _domain_event_count(runtime, &"EXCAVATION_COMPLETED")
var build = _submit(
runtime,
&"build_facility",
{
&"definition_id": &"guest_corridor",
&"origin": Vector3i(-4, 1, PathType.FRONT),
&"rotation": 0,
},
&"infra.excavation.tick.build"
)
_expect(build.is_success(), "construction comparison job starts in the same Runtime minute")
var construction_job_id := StringName(build.details.get(&"job_id", &""))
clock.advance_minutes(5)
var excavation_job: Dictionary = runtime.excavation_service.get_job(excavation_job_id)
var construction_job := _construction_job_snapshot(runtime, construction_job_id)
_expect(
int(excavation_job.get(&"progress", 0)) > 0
and int(construction_job.get(&"progress", 0)) > 0,
"excavation and construction both progress through Runtime ticks"
)
_expect(
int(excavation_job.get(&"last_progress_at", -1)) == clock.absolute_minute
and int(construction_job.get(&"last_progress_at", -2)) == clock.absolute_minute
and runtime.excavation_service.current_minute == runtime.construction_service.current_minute,
"excavation advances in the exact Construction phase minute"
)
var pause = _submit(
runtime,
&"pause_excavation",
{&"job_id": excavation_job_id},
&"infra.excavation.pause"
)
var paused_progress := int(runtime.excavation_service.get_job(excavation_job_id)[&"progress"])
_expect(pause.is_success(), "pause_excavation accepts a job_id payload")
clock.advance_minutes(4)
_expect(
int(runtime.excavation_service.get_job(excavation_job_id)[&"progress"]) == paused_progress,
"paused Runtime ticks retain excavation progress exactly"
)
var paused_snapshot: Dictionary = runtime.create_snapshot()
_expect(
runtime.restore_snapshot(paused_snapshot)
and runtime.create_snapshot() == paused_snapshot,
"paused excavation survives an exact current Runtime save/restore"
)
_expect(
runtime.excavation_service.get_job(excavation_job_id).get(&"state", &"")
== runtime.excavation_service.STATE_PAUSED
and int(runtime.excavation_service.get_job(excavation_job_id).get(&"progress", -1))
== paused_progress,
"restored excavation retains its paused state and accumulated work"
)
var resume = _submit(
runtime,
&"resume_excavation",
{&"job_id": excavation_job_id},
&"infra.excavation.resume"
)
_expect(resume.is_success(), "resume_excavation accepts the same job_id")
clock.advance_minutes(24)
excavation_job = runtime.excavation_service.get_job(excavation_job_id)
_expect(
excavation_job.get(&"state", &"") == runtime.excavation_service.STATE_ACTIVE
and int(excavation_job.get(&"work_units_done", -1))
== 29 * runtime.excavation_service.NORMAL_WORK_RATE
and int(excavation_job.get(&"progress", -1)) < runtime.excavation_service.MAX_PROGRESS
and not runtime.world_service.is_excavated(target)
and _domain_event_count(runtime, &"EXCAVATION_COMPLETED") == excavation_events_before,
"hardness-0 excavation remains incomplete at the exact 29-minute boundary"
)
clock.advance_minutes(1)
excavation_job = runtime.excavation_service.get_job(excavation_job_id)
_expect(
excavation_job.get(&"state", &"") == runtime.excavation_service.STATE_COMPLETED
and runtime.world_service.is_excavated(target)
and runtime.world_service.is_excavated(Vector3i(target.x, target.y, PathType.BACK)),
"the 30th minute completes FRONT and BACK excavation together"
)
_expect(
_domain_event_count(runtime, &"EXCAVATION_COMPLETED") == excavation_events_before + 1
and _saw_domain_event(runtime, &"EXCAVATION_COMPLETED", excavation_job_id),
"the 30-minute boundary publishes exactly one excavation completion event"
)
clock.advance_minutes(3)
_expect(
_domain_event_count(runtime, &"EXCAVATION_COMPLETED") == excavation_events_before + 1,
"later Runtime ticks cannot duplicate excavation completion"
)
_free_fixture(fixture)
func _test_completed_proxy_projection() -> void:
var fixture := _new_fixture(81_030)
var runtime: Variant = fixture[&"runtime"]
_expect(_promote_rank_two(fixture, &"infra.proxy.rank"), "proxy fixture reaches Rank 2")
var front_a := Vector3i(0, -1, PathType.FRONT)
var front_b := Vector3i(1, -1, PathType.FRONT)
_expect(not _complete_excavation(fixture, front_a, &"infra.proxy.dig.a").is_empty(), "first proxy cell is excavated")
_expect(not _complete_excavation(fixture, front_b, &"infra.proxy.dig.b").is_empty(), "adjacent proxy cell is excavated")
runtime.world_service.set_support(front_a, 10, true)
runtime.world_service.set_support(front_b, 10, true)
runtime.world_service.set_support(Vector3i(0, -1, PathType.BACK), 10, true)
runtime.world_service.set_support(Vector3i(1, -1, PathType.BACK), 10, true)
var guest := _complete_proxy(
fixture, &"guest_corridor", front_a, &"infra.proxy.guest"
)
var adjacent_guest := _complete_proxy(
fixture, &"guest_corridor", front_b, &"infra.proxy.guest.adjacent"
)
_expect(adjacent_guest[&"ok"], "same-floor guest corridor completes beside the proxy")
var service := _complete_proxy(
fixture,
&"service_corridor",
Vector3i(1, -1, PathType.BACK),
&"infra.proxy.service"
)
var door := _complete_proxy(
fixture,
&"staff_door",
Vector3i(0, -1, PathType.BACK),
&"infra.proxy.door"
)
_expect(guest[&"ok"] and service[&"ok"] and door[&"ok"], "all three supported proxy kinds complete")
if not guest[&"ok"] or not service[&"ok"] or not door[&"ok"]:
_free_fixture(fixture)
return
var guest_id: StringName = guest[&"instance_id"]
var service_id: StringName = service[&"instance_id"]
var door_id: StringName = door[&"instance_id"]
_expect(
runtime.facility_infrastructure_projector.has_projection(guest_id)
and runtime.facility_infrastructure_projector.has_projection(service_id)
and runtime.facility_infrastructure_projector.has_projection(door_id),
"completed proxy facilities project immediately"
)
_expect(
not runtime.facility_service.has_instance(guest_id)
and not runtime.facility_service.has_instance(service_id)
and not runtime.facility_service.has_instance(door_id),
"schema proxy facilities never enter operational FacilityService"
)
var guest_projection: Dictionary = runtime.facility_infrastructure_projector.get_projection(guest_id)
var service_projection: Dictionary = runtime.facility_infrastructure_projector.get_projection(service_id)
var door_projection: Dictionary = runtime.facility_infrastructure_projector.get_projection(door_id)
_expect(
guest_projection[&"route_entity_id"] == StringName("infra.route:%s" % guest_id)
and service_projection[&"route_entity_id"] == StringName("infra.route:%s" % service_id)
and door_projection[&"connector_id"] == StringName("infra.connector:%s" % door_id),
"Runtime projection retains stable managed IDs"
)
var entrance := Vector3i(0, 0, PathType.FRONT)
var door_back := Vector3i(0, -1, PathType.BACK)
var service_back := Vector3i(1, -1, PathType.BACK)
_expect(
runtime.path_service.find_path(front_b, front_a) == [front_b, front_a],
"guest corridors form a real same-floor FRONT Path edge"
)
_expect(
runtime.path_service.find_path(entrance, front_a).is_empty(),
"corridor projection does not create an implicit staircase from ground level"
)
_expect(
runtime.path_service.find_path(
front_a,
service_back,
[PathType.FRONT, PathType.BACK],
[&"staff"]
) == [front_a, door_back, service_back],
"staff door and service corridor form a real staff-only Path"
)
_expect(
runtime.path_service.find_path(
front_a,
service_back,
[PathType.FRONT, PathType.BACK],
[]
).is_empty(),
"guest access cannot traverse the staff-only projection"
)
_expect(
runtime.world_service.get_occupant(front_a) == guest_id
and runtime.world_service.get_occupant(service_back) == service_id
and runtime.world_service.get_occupant(door_back) == door_id,
"proxy ROUTEs coexist with authoritative primary World occupancy"
)
_expect(
runtime.spatial_subslot_service.validate_invariants()[&"ok"]
and runtime.route_subslot_path_adapter.validate_invariants()[&"ok"]
and runtime.facility_infrastructure_projector.validate_invariants()[&"ok"],
"completed proxy projection satisfies every infrastructure invariant"
)
_free_fixture(fixture)
func _test_proxy_completion_raw_signal_commit_order() -> void:
var fixture := _new_fixture(81_034)
var runtime: Variant = fixture[&"runtime"]
var clock: Variant = fixture[&"clock"]
var started = _submit(
runtime,
&"build_facility",
{
&"definition_id": &"guest_corridor",
&"origin": Vector3i(0, 1, PathType.FRONT),
&"rotation": 0,
},
&"infra.proxy.signals.start"
)
_expect(started.is_success(), "signal-order fixture starts a proxy job")
if not started.is_success():
_free_fixture(fixture)
return
var job_id := StringName(started.details.get(&"job_id", &""))
var job: ConstructionJob = runtime.construction_service.get_job(job_id)
if job == null:
_expect(false, "signal-order fixture exposes its Construction job")
_free_fixture(fixture)
return
clock.advance_minutes(maxi(job.build_minutes - 1, 0))
var raw_signal_order: Array[StringName] = []
runtime.construction_service.job_changed.connect(
func(changed_job: ConstructionJob) -> void:
if changed_job != null and changed_job.job_id == job_id:
raw_signal_order.append(&"job_changed")
)
runtime.construction_service.facility_completed.connect(
func(instance: Dictionary) -> void:
if StringName(instance.get(&"source_job_id", &"")) == job_id:
raw_signal_order.append(&"facility_completed")
)
var completed_events_before := _domain_event_count(runtime, &"FACILITY_COMPLETED")
var projected_events_before := _domain_event_count(runtime, &"FACILITY_INFRASTRUCTURE_PROJECTED")
clock.advance_minutes(1)
job = runtime.construction_service.get_job(job_id)
_expect(
job != null
and job.state == ConstructionJob.State.COMPLETED
and runtime.facility_infrastructure_projector.has_projection(job.facility_instance_id),
"successful proxy completion commits Construction and projection together"
)
_expect(
raw_signal_order == [&"job_changed", &"facility_completed"],
"successful completion publishes raw job_changed then facility_completed exactly once each"
)
_expect(
_domain_event_count(runtime, &"FACILITY_COMPLETED") == completed_events_before + 1
and _domain_event_count(runtime, &"FACILITY_INFRASTRUCTURE_PROJECTED")
== projected_events_before + 1,
"successful proxy completion publishes each committed DomainEvent exactly once"
)
_free_fixture(fixture)
func _test_proxy_completion_projection_failure_is_atomic() -> void:
var fixture := _new_fixture(81_035)
var runtime: Variant = fixture[&"runtime"]
var clock: Variant = fixture[&"clock"]
var started = _submit(
runtime,
&"build_facility",
{
&"definition_id": &"guest_corridor",
&"origin": Vector3i(0, 1, PathType.FRONT),
&"rotation": 0,
},
&"infra.proxy.failure.start"
)
_expect(started.is_success(), "projection-failure fixture starts a proxy job")
if not started.is_success():
_free_fixture(fixture)
return
var job_id := StringName(started.details.get(&"job_id", &""))
var job: Variant = runtime.construction_service.get_job(job_id)
if job == null:
_expect(false, "projection-failure fixture exposes its Construction job")
_free_fixture(fixture)
return
clock.advance_minutes(maxi(int(job.build_minutes) - 1, 0))
job = runtime.construction_service.get_job(job_id)
_expect(
job != null
and job.state != ConstructionJob.State.COMPLETED
and job.progress > 0
and job.progress < ConstructionJob.MAX_PROGRESS,
"proxy job reaches the exact minute before completion"
)
var external_route_id := &"external_route_before_proxy_completion"
var made_stale = runtime.spatial_subslot_service.place(
external_route_id,
runtime.spatial_subslot_service.CATEGORY_ROUTE,
[Vector3i(5, 2, PathType.FRONT)]
)
_expect(
made_stale.is_success()
and runtime.route_subslot_path_adapter.is_projection_stale(),
"public Spatial mutation makes the completion projector dependency stale"
)
var before_failure := _completion_boundary_state(fixture)
var completed_events_before := _domain_event_count(runtime, &"FACILITY_COMPLETED")
var projected_events_before := _domain_event_count(runtime, &"FACILITY_INFRASTRUCTURE_PROJECTED")
var raw_completion_signals: Array[StringName] = []
runtime.construction_service.job_changed.connect(
func(changed_job: ConstructionJob) -> void:
if changed_job != null and changed_job.job_id == job_id:
raw_completion_signals.append(&"job_changed")
)
runtime.construction_service.facility_completed.connect(
func(instance: Dictionary) -> void:
if StringName(instance.get(&"source_job_id", &"")) == job_id:
raw_completion_signals.append(&"facility_completed")
)
# A newly raised runtime failure must stop an initially-running batch. The
# test otherwise uses paused manual stepping so no wall-clock frame can race it.
clock.set_paused(false)
clock.advance_minutes(1)
var after_job: Variant = runtime.construction_service.get_job(job_id)
_expect(
_completion_boundary_state(fixture) == before_failure,
"failed completion restores Construction, World, Path, infrastructure, and resources exactly"
)
_expect(
after_job != null
and after_job.state != ConstructionJob.State.COMPLETED
and after_job.progress < ConstructionJob.MAX_PROGRESS
and runtime.construction_service.get_facilities().is_empty()
and runtime.facility_infrastructure_projector.get_projection_ids().is_empty(),
"projection rejection leaves no completed facility or one-sided projection"
)
_expect(
runtime.spatial_subslot_service.get_entity_ids(
runtime.spatial_subslot_service.CATEGORY_ROUTE
) == [external_route_id]
and runtime.route_subslot_path_adapter.get_projected_route_cells().is_empty(),
"projection rejection retains only the pre-existing stale mutation and no managed ROUTE"
)
_expect(
_domain_event_count(runtime, &"FACILITY_COMPLETED") == completed_events_before
and _domain_event_count(runtime, &"FACILITY_INFRASTRUCTURE_PROJECTED") == projected_events_before,
"projection rejection publishes no ghost completion or projection DomainEvent"
)
_expect(
raw_completion_signals.is_empty(),
"projection rejection exposes no raw job_changed or facility_completed signal"
)
var diagnostic := _runtime_failure_diagnostic(runtime)
_expect(
clock.paused
and bool(diagnostic.get(&"latched", false))
and not String(diagnostic.get(&"reason", "")).is_empty(),
"projection rejection pauses Runtime with a public reason-bearing failure latch"
)
_free_fixture(fixture)
func _test_completed_elevator_topology() -> void:
var fixture := _new_fixture(81_040)
var runtime: Variant = fixture[&"runtime"]
_expect(_promote_rank_two(fixture, &"infra.vertical.rank"), "vertical fixture reaches Rank 2")
var cash_before: int = runtime.economy_service.get_balance(&"PLAYER_CASH")
for request: Array in [[&"guest_elevator", Vector3i(-6, 0, PathType.FRONT)], [&"service_elevator", Vector3i(5, 0, PathType.BACK)]]:
var result = _submit(runtime, &"build_facility", {&"definition_id": request[0], &"origin": request[1], &"rotation": 0}, StringName("infra.vertical." + String(request[0])))
_expect(result.is_success(), "%s is accepted through paid build-command preflight" % request[0])
_expect(runtime.economy_service.get_balance(&"PLAYER_CASH") == cash_before - 3700, "accepted lift construction spends actual definition costs")
_expect(runtime.facility_infrastructure_projector.get_projection_ids().is_empty(), "unfinished lift construction does not create usable shaft topology")
fixture[&"clock"].advance_minutes(360)
_expect(runtime.facility_infrastructure_projector.get_projection_ids().size() == 2 and runtime.elevators.get_report()[&"shafts"].size() == 2, "completed guest and service modules project separate cabins")
for shaft: Dictionary in runtime.elevators.get_report()[&"shafts"]:
var result = _submit(runtime, &"set_elevator_operation", {&"shaft_id": shaft[&"shaft_id"], &"operator_open": false}, StringName("infra.vertical.stop." + String(shaft[&"shaft_id"])))
_expect(result.is_success(), "completed lift can be stopped through Runtime command")
_expect(runtime.path_service.find_path(shaft[&"stops"][0], shaft[&"stops"][1]).is_empty(), "stopped lift shaft never permits an ordinary vertical walk bypass")
_expect(runtime.facility_infrastructure_projector.validate_invariants()[&"ok"], "completed elevator ROUTE and owned shaft restrictions crosslink exactly")
_free_fixture(fixture)
func _test_demolition_projection_atomicity() -> void:
var fixture := _new_fixture(81_050)
var runtime: Variant = fixture[&"runtime"]
_expect(_promote_rank_two(fixture, &"infra.demolish.rank"), "demolition fixture reaches Rank 2")
var built := _complete_proxy(
fixture,
&"guest_corridor",
Vector3i(0, 1, PathType.FRONT),
&"infra.demolish.proxy"
)
_expect(built[&"ok"], "demolition target proxy completes")
if not built[&"ok"]:
_free_fixture(fixture)
return
var instance_id: StringName = built[&"instance_id"]
var projection: Dictionary = runtime.facility_infrastructure_projector.get_projection(instance_id)
_expect(
projection.get(&"route_entity_id", null) is StringName,
"demolition fixture exposes the completed proxy projection"
)
if not projection.get(&"route_entity_id", null) is StringName:
_free_fixture(fixture)
return
var managed_route: StringName = projection[&"route_entity_id"]
_expect(
runtime.spatial_subslot_service.place(
&"external_route",
runtime.spatial_subslot_service.CATEGORY_ROUTE,
[Vector3i(5, 2, PathType.FRONT)]
).is_success(),
"public Spatial mutation creates a deterministic stale-dependency failure"
)
var before_failure := _infrastructure_state(fixture)
var refunds_before := _ledger_category_count(runtime, &"CONSTRUCTION_REFUND")
var raw_demolished_ids: Array[StringName] = []
runtime.construction_service.facility_demolished.connect(
func(demolished_id: StringName, _refund: Dictionary) -> void:
if demolished_id == instance_id:
raw_demolished_ids.append(demolished_id)
)
var rejected = _submit(
runtime,
&"demolish_facility",
{&"instance_id": instance_id},
&"infra.demolish.stale"
)
_expect(
not rejected.is_success()
and not String(rejected.details.get(&"reason", "")).is_empty(),
"demolition rejects stale projection with a stable public reason"
)
_expect(
_infrastructure_state(fixture) == before_failure,
"failed unprojection preserves projection, construction, World, and resources exactly"
)
_expect(
raw_demolished_ids.is_empty()
and _ledger_category_count(runtime, &"CONSTRUCTION_REFUND") == refunds_before
and runtime.spatial_subslot_service.get_entity_cells(&"external_route")
== [Vector3i(5, 2, PathType.FRONT)],
"failed demolition emits no raw signal or refund and retains the external ROUTE"
)
_expect(
runtime.route_subslot_path_adapter.synchronize_projection(&"infra.demolish.sync").is_success(),
"fixture repairs the stale route through the public adapter"
)
var removed = _submit(
runtime,
&"demolish_facility",
{&"instance_id": instance_id},
&"infra.demolish.commit"
)
_expect(removed.is_success(), "proxy demolition commits after dependencies are fresh")
_expect(
not runtime.facility_infrastructure_projector.has_projection(instance_id)
and not runtime.spatial_subslot_service.has_entity(managed_route),
"demolition removes projector and Spatial projection together"
)
_expect(
runtime.spatial_subslot_service.get_entity_cells(&"external_route")
== [Vector3i(5, 2, PathType.FRONT)]
and runtime.path_service.has_cell(Vector3i(5, 2, PathType.FRONT)),
"committed demolition preserves the unrelated external ROUTE projection"
)
_expect(
runtime.construction_service.get_facility(instance_id).is_empty()
and runtime.world_service.get_entity_cells(instance_id).is_empty(),
"demolition removes Construction and primary World state together"
)
_expect(
_saw_domain_event(runtime, &"FACILITY_DEMOLISHED", instance_id),
"committed proxy demolition publishes its domain event"
)
_free_fixture(fixture)
func _test_current_snapshot_strictness() -> void:
var fixture := _new_fixture(81_060)
var runtime: Variant = fixture[&"runtime"]
_expect(_promote_rank_two(fixture, &"infra.snapshot.rank"), "snapshot fixture reaches Rank 2")
var target := Vector3i(0, -1, PathType.FRONT)
var excavation_job_id := _complete_excavation(fixture, target, &"infra.snapshot.dig")
_expect(not excavation_job_id.is_empty(), "snapshot fixture stores completed excavation evidence")
if excavation_job_id.is_empty():
_free_fixture(fixture)
return
var built := _complete_proxy(
fixture,
&"guest_corridor",
Vector3i(0, 1, PathType.FRONT),
&"infra.snapshot.proxy"
)
_expect(built[&"ok"], "snapshot fixture stores one completed projection")
var snapshot: Dictionary = runtime.create_snapshot()
var expected_digest := SimulationDigest.compute(snapshot)
_expect(runtime.restore_snapshot(snapshot), "valid Runtime v9 snapshot restores")
_expect(
runtime.create_snapshot() == snapshot and runtime.latest_digest == expected_digest,
"Runtime v9 round trip is exact"
)
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][&"unknown_infrastructure"] = {},
"unknown v9 Runtime field"
)
for key: StringName in INFRASTRUCTURE_SNAPSHOT_KEYS:
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"].erase(key),
"missing %s field" % key
)
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][key] = [],
"non-Dictionary %s field" % key
)
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][key][&"unknown"] = true,
"unknown nested %s field" % key
)
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][&"route_projection"][&"projected_route_cells"].clear(),
"Spatial-to-adapter route crosslink tamper"
)
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][&"facility_infrastructure"][&"projections"].clear(),
"projector-to-managed-route crosslink tamper"
)
_assert_runtime_restore_rejected(
runtime,
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][&"excavation"][&"jobs"][0][&"position"] = [2, -2],
"excavation-to-World completion crosslink tamper"
)
_free_fixture(fixture)
func _test_v5_proxy_migration_determinism() -> void:
var source := _new_fixture(81_070)
var runtime: Variant = source[&"runtime"]
var built := _complete_proxy(
source,
&"guest_corridor",
Vector3i(0, 1, PathType.FRONT),
&"infra.legacy.proxy"
)
_expect(built[&"ok"], "legacy fixture creates a completed proxy")
if not built[&"ok"]:
_free_fixture(source)
return
var instance_id: StringName = built[&"instance_id"]
var construction_instance: Dictionary = runtime.construction_service.get_facility(instance_id)
var legacy_registered := _register_legacy_operational_proxy(runtime, construction_instance)
_expect(
legacy_registered,
"legacy fixture reproduces the v5 operational-proxy shape"
)
if not legacy_registered:
_free_fixture(source)
return
var baseline := _new_fixture(81_070)
var legacy: Dictionary = runtime.create_snapshot()
var legacy_runtime: Dictionary = legacy[&"systems"][&"runtime"]
var stripped_v6_events := _strip_v6_infrastructure_domain_history(legacy_runtime)
legacy_runtime[&"runtime_schema_version"] = 5
legacy_runtime.erase(&"kitchen_production")
legacy_runtime.erase(&"elevators")
legacy_runtime.erase(&"legacy_stairs")
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(legacy_runtime)
legacy_runtime.erase(&"staff_commute")
for key: StringName in INFRASTRUCTURE_SNAPSHOT_KEYS:
legacy_runtime.erase(key)
legacy_runtime[&"path"] = baseline[&"runtime"].path_service.create_snapshot()
legacy_runtime[&"path"][&"schema_version"] = 3
legacy_runtime[&"path"].erase(&"vertical_walk_blockers")
legacy_runtime[&"path"].erase(&"vertical_walk_requires_connector")
legacy_runtime[&"path"].erase(&"transit_actor_ids")
_free_fixture(baseline)
_expect(
stripped_v6_events > 0 and _legacy_v5_infrastructure_shape_is_clean(legacy_runtime),
"v5 fixture removes v6-only aggregate and DomainEvent history instead of relabelling v6"
)
if not _legacy_v5_infrastructure_shape_is_clean(legacy_runtime):
_free_fixture(source)
return
var first_target := _new_fixture(81_071)
var first_runtime: Variant = first_target[&"runtime"]
_expect(first_runtime.restore_snapshot(legacy), "v5 proxy snapshot migrates through Runtime restore")
var first_migrated: Dictionary = first_runtime.create_snapshot()
_expect(
int(first_migrated[&"systems"][&"runtime"][&"runtime_schema_version"]) == 14,
"v5 migration is immediately re-emitted as v9"
)
_expect(
first_runtime.facility_infrastructure_projector.has_projection(instance_id)
and first_runtime.path_service.has_cell(Vector3i(0, 1, PathType.FRONT)),
"v5 construction proxy is deterministically reprojected into real Path"
)
_expect(
not first_runtime.facility_service.has_instance(instance_id),
"v5 operational proxy is removed from FacilityService during migration"
)
var second_target := _new_fixture(81_072)
var second_runtime: Variant = second_target[&"runtime"]
_expect(second_runtime.restore_snapshot(legacy), "the same v5 proxy snapshot migrates a second time")
_expect(
second_runtime.create_snapshot() == first_migrated,
"v5 proxy reprojection is deterministic across Runtime instances"
)
_free_fixture(second_target)
_free_fixture(first_target)
_free_fixture(source)
func _test_rank_expansion_preserves_route_union() -> void:
var fixture := _new_fixture(81_080)
var runtime: Variant = fixture[&"runtime"]
var route_cell := Vector3i(0, 1, PathType.FRONT)
var built := _complete_proxy(
fixture,
&"guest_corridor",
route_cell,
&"infra.expansion.proxy"
)
_expect(built[&"ok"] and runtime.path_service.has_cell(route_cell), "Rank 1 fixture has a projected route outside base walkability")
if not built[&"ok"] or not runtime.path_service.has_cell(route_cell):
_free_fixture(fixture)
return
var adjacent_cell := Vector3i(1, 1, PathType.FRONT)
var adjacent := _complete_proxy(fixture, &"guest_corridor", adjacent_cell, &"infra.expansion.adjacent")
_expect(adjacent[&"ok"], "rank expansion fixture has a same-floor corridor connection")
_expect(_promote_rank_two(fixture, &"infra.expansion.rank"), "rank expansion commits with an existing route")
_expect(
runtime.route_subslot_path_adapter.get_projected_route_cells().has(route_cell)
and runtime.path_service.has_cell(route_cell),
"rank expansion preserves projected ROUTE cells"
)
_expect(
_same_cells(
runtime.route_subslot_path_adapter.get_base_walkable_cells(),
runtime.world_service.get_walkable_cells()
),
"rank expansion replaces the adapter base with all expanded World walkability"
)
_expect(
runtime.path_service.find_path(adjacent_cell, route_cell) == [adjacent_cell, route_cell],
"expanded base preserves the pre-existing same-floor route"
)
_expect(
runtime.path_service.find_path(Vector3i(0, 0, PathType.FRONT), route_cell).is_empty(),
"rank expansion does not add implicit vertical walking"
)
_free_fixture(fixture)
func _promote_rank_two(fixture: Dictionary, prefix: StringName) -> bool:
var runtime: Variant = fixture[&"runtime"]
var reputation = _submit(
runtime,
&"update_progression_metrics",
{&"metrics": {&"reputation": 25}},
StringName("%s.reputation" % prefix)
)
var capital = _submit(
runtime,
&"change_resources",
{
&"deltas": {
&"gold": maxi(
10_000 - runtime.economy_service.get_balance(&"PLAYER_CASH"),
0
),
},
},
StringName("%s.capital" % prefix)
)
var promoted = _submit(
runtime,
&"set_world_tree_rank",
{&"rank": 2},
StringName("%s.promote" % prefix)
)
return reputation.is_success() and capital.is_success() and promoted.is_success() \
and fixture[&"state"].world_tree_rank == 2
func _complete_excavation(
fixture: Dictionary,
cell: Vector3i,
key: StringName
) -> StringName:
var runtime: Variant = fixture[&"runtime"]
var result = _submit(runtime, &"start_excavation", {&"cell": cell}, key)
if not result.is_success():
return &""
var job_id := StringName(result.details.get(&"job_id", &""))
var job: Dictionary = runtime.excavation_service.get_job(job_id)
fixture[&"clock"].advance_minutes(int(job.get(&"build_minutes", 0)))
return job_id if runtime.excavation_service.get_job(job_id).get(&"state", &"") \
== runtime.excavation_service.STATE_COMPLETED else &""
func _complete_proxy(
fixture: Dictionary,
definition_id: StringName,
origin: Vector3i,
key: StringName
) -> Dictionary:
var runtime: Variant = fixture[&"runtime"]
var result = _submit(
runtime,
&"build_facility",
{&"definition_id": definition_id, &"origin": origin, &"rotation": 0},
key
)
if not result.is_success():
return {&"ok": false, &"result": result}
var job_id := StringName(result.details.get(&"job_id", &""))
var job: Variant = runtime.construction_service.get_job(job_id)
if job == null:
return {&"ok": false, &"result": result}
fixture[&"clock"].advance_minutes(int(job.build_minutes))
return {
&"ok": job.state == ConstructionJob.State.COMPLETED,
&"job_id": job_id,
&"instance_id": job.facility_instance_id,
&"result": result,
}
func _register_legacy_operational_proxy(runtime: Variant, instance: Dictionary) -> bool:
var definition: Variant = runtime.definition_registry.get_facility(
StringName(instance.get(&"definition_id", &""))
)
if definition == null:
return false
var instance_id := StringName(instance.get(&"instance_id", &""))
# While this acceptance test straddles the v5/v6 boundary, an older Runtime
# may already have registered the proxy through its completion callback. A
# completed v6 Runtime deliberately will not, so construct the same legacy
# aggregate only when it is absent.
if runtime.facility_service.has_instance(instance_id):
return true
runtime.economy_service.register_account(StringName("FACILITY_REVENUE:%s" % instance_id))
var result = runtime.facility_service.create_instance({
&"instance_id": instance_id,
&"definition_id": definition.id,
&"origin": instance.get(&"origin", Vector3i.ZERO),
&"rotation": instance.get(&"rotation", 0),
&"occupied_cells": instance.get(&"occupied_cells", []),
&"local_inventory_id": StringName("facility.inventory:%s" % instance_id),
&"capacity": maxi(definition.capacity, 1),
&"queue_capacity": definition.queue_capacity,
&"base_service_minutes": definition.base_service_minutes,
&"base_quality": definition.base_quality,
&"base_price": definition.base_price,
&"staff_min": definition.staff_min,
&"staff_max": definition.staff_max,
&"created_at": int(instance.get(&"completed_at", 0)),
})
return result.is_success()
func _strip_v6_infrastructure_domain_history(runtime_data: Dictionary) -> int:
var stream_value: Variant = runtime_data.get(&"domain_events", null)
if not stream_value is Dictionary:
return 0
var stream: Dictionary = stream_value
var recent_value: Variant = stream.get("recent_events", null)
var published_value: Variant = stream.get("published_ids", null)
if not recent_value is Array or not published_value is Array:
return 0
var removed_ids: Dictionary = {}
var retained_recent: Array[Dictionary] = []
for raw_event: Variant in recent_value:
if not raw_event is Dictionary:
return 0
var event: Dictionary = raw_event
if StringName(event.get("event_type", "")) in [
&"FACILITY_INFRASTRUCTURE_PROJECTED",
&"EXCAVATION_COMPLETED",
]:
removed_ids[StringName(event.get("event_id", ""))] = true
else:
retained_recent.append(event.duplicate(true))
var retained_published: Array[String] = []
for raw_event_id: Variant in published_value:
var event_id := StringName(raw_event_id)
if not removed_ids.has(event_id):
retained_published.append(String(event_id))
stream["recent_events"] = retained_recent
stream["published_ids"] = retained_published
return removed_ids.size()
func _legacy_v5_infrastructure_shape_is_clean(runtime_data: Dictionary) -> bool:
if runtime_data.has(&"kitchen_production") or runtime_data.has(&"elevators") or runtime_data.has(&"legacy_stairs") or runtime_data.has(&"staff_commute"):
return false
for key: StringName in INFRASTRUCTURE_SNAPSHOT_KEYS:
if runtime_data.has(key) or runtime_data.has(String(key)):
return false
var stream_value: Variant = runtime_data.get(&"domain_events", null)
if not stream_value is Dictionary:
return false
for raw_event: Variant in stream_value.get("recent_events", []):
if not raw_event is Dictionary:
return false
if StringName(raw_event.get("event_type", "")) in [
&"FACILITY_INFRASTRUCTURE_PROJECTED",
&"EXCAVATION_COMPLETED",
]:
return false
var queue_value: Variant = runtime_data.get(&"command_queue", null)
if not queue_value is Dictionary:
return false
for queue_key: String in ["pending", "in_flight"]:
for raw_command: Variant in queue_value.get(queue_key, []):
if not raw_command is Dictionary:
return false
if StringName(raw_command.get("command_type", "")) in [
&"start_excavation", &"pause_excavation", &"resume_excavation",
]:
return false
return true
func _construction_job_snapshot(runtime: Variant, job_id: StringName) -> Dictionary:
for row: Variant in runtime.construction_service.create_snapshot().get(&"jobs", []):
if row is Dictionary and StringName(row.get(&"job_id", &"")) == job_id:
return row.duplicate(true)
return {}
func _infrastructure_state(fixture: Dictionary) -> Dictionary:
var runtime: Variant = fixture[&"runtime"]
return {
&"game_state": fixture[&"state"].create_snapshot(),
&"economy": runtime.economy_service.create_snapshot(),
&"world": runtime.world_service.create_snapshot(),
&"path": runtime.path_service.create_snapshot(),
&"construction": runtime.construction_service.create_snapshot(),
&"excavation": runtime.excavation_service.create_snapshot(),
&"spatial_subslots": runtime.spatial_subslot_service.create_snapshot(),
&"route_projection": runtime.route_subslot_path_adapter.create_snapshot(),
&"facility_infrastructure": runtime.facility_infrastructure_projector.create_snapshot(),
&"facilities": runtime.facility_service.create_snapshot(),
&"mana": runtime.mana_network_service.create_snapshot(),
}
func _completion_boundary_state(fixture: Dictionary) -> Dictionary:
# MANA is an earlier Clock phase and has legitimately committed the new
# minute before Construction discovers a projection failure. The atomic
# completion boundary starts at Construction and owns the state below.
var state := _infrastructure_state(fixture)
state.erase(&"mana")
return state
func _assert_runtime_restore_rejected(
runtime: Variant,
source: Dictionary,
mutator: Callable,
label: String
) -> void:
var before: Dictionary = runtime.create_snapshot()
var candidate: Dictionary = source.duplicate(true)
mutator.call(candidate)
_expect(not runtime.restore_snapshot(candidate), "%s is rejected" % label)
_expect(runtime.create_snapshot() == before, "%s rejection is Runtime-atomic" % label)
func _saw_domain_event(runtime: Variant, event_type: StringName, entity_id: StringName) -> bool:
for event: SimulationDomainEvent in runtime.domain_events.recent_events():
if event.event_type == event_type and entity_id in event.entity_ids:
return true
return false
func _domain_event_count(runtime: Variant, event_type: StringName) -> int:
var count := 0
for event: SimulationDomainEvent in runtime.domain_events.recent_events():
if event.event_type == event_type:
count += 1
return count
func _ledger_category_count(runtime: Variant, category: StringName) -> int:
var count := 0
for entry: LedgerEntry in runtime.economy_service.get_entries():
if entry.category == category:
count += 1
return count
func _runtime_failure_diagnostic(runtime: Variant) -> Dictionary:
var report_methods: Array[StringName] = [
&"get_infrastructure_report",
&"get_operations_report",
]
for method_name: StringName in report_methods:
if not runtime.has_method(method_name):
continue
var raw_report: Variant = runtime.call(method_name)
if not raw_report is Dictionary:
continue
var report: Dictionary = raw_report
var latched_value: Variant = report.get(
&"failure_latched",
report.get(&"runtime_failure_latched", null)
)
var raw_failure: Variant = report.get(
&"failure_report",
report.get(&"runtime_failure_report", null)
)
if typeof(latched_value) != TYPE_BOOL or not raw_failure is Dictionary:
continue
var failure: Dictionary = raw_failure
var reason := String(failure.get(
&"reason",
failure.get(&"code", failure.get(&"message", ""))
))
return {
&"latched": bool(latched_value),
&"reason": reason,
&"failure": failure.duplicate(true),
}
return {}
func _submit(
runtime: Variant,
command_type: StringName,
payload: Dictionary,
idempotency_key: StringName
) -> Variant:
return runtime.submit_command(
command_type,
payload,
&"player",
&"",
100,
-1,
idempotency_key
)
func _object_has_property(value: Object, property_name: StringName) -> bool:
for property: Dictionary in value.get_property_list():
if StringName(property.get(&"name", property.get("name", ""))) == property_name:
return true
return false
func _same_cells(first: Array, second: Array) -> bool:
if first.size() != second.size():
return false
var first_set: Dictionary = {}
for cell: Variant in first:
first_set[cell] = true
for cell: Variant in second:
if not first_set.has(cell):
return false
return true
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
return
_failures += 1
push_error(" ✗ %s" % label)