Record original-alignment implementation and traceability checkpoint
Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
extends SceneTree
|
||||
var checks:=0
|
||||
var failures:=0
|
||||
var runtime: Variant
|
||||
var clock: Variant
|
||||
var state: Variant
|
||||
func expect(ok: bool, message: String) -> void:
|
||||
checks+=1
|
||||
if not ok: failures+=1;push_error(message)
|
||||
func _initialize() -> void: call_deferred("run")
|
||||
func build(id: StringName, origin: Vector3i) -> bool:
|
||||
var result: CommandResult=runtime.submit_command(&"build_facility",{&"definition_id":id,&"origin":origin})
|
||||
expect(result.is_success(),"legacy batch build %s" % id)
|
||||
if not result.is_success(): return false
|
||||
clock.advance_minutes(runtime.definition_registry.get_facility(id).build_minutes)
|
||||
return true
|
||||
func run() -> void:
|
||||
runtime=load("res://autoload/simulation_runtime.gd").new();clock=load("res://autoload/game_clock.gd").new();state=load("res://autoload/game_state.gd").new()
|
||||
clock.reset(1,6,0);state.reset();runtime.initialize(clock,state,42506);clock.set_paused(true)
|
||||
var paths: Array[String]=FacilityCatalog.FACILITY_PATHS+FacilityCatalog.INFRASTRUCTURE_FACILITY_PATHS+FacilityCatalog.RESCUE_FACILITY_PATHS
|
||||
paths.append_array(["res://tests/fixtures/legacy_premium_room.tres","res://tests/fixtures/legacy_staff_dormitory.tres"])
|
||||
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"],"load both legacy definitions")
|
||||
if not build(&"reception",Vector3i(-6,0,0)) or not build(&"premium_room",Vector3i(-6,2,0)) or not build(&"warehouse",Vector3i(-6,0,1)) or not build(&"staff_dormitory",Vector3i(-6,2,1)): finish();return
|
||||
if not build(&"service_stairs",Vector3i(-7,1,1)) or not build(&"service_stairs",Vector3i(-7,2,1)) or not build(&"service_stairs",Vector3i(-7,3,1)): finish();return
|
||||
paths.erase("res://tests/fixtures/legacy_premium_room.tres");paths.erase("res://tests/fixtures/legacy_staff_dormitory.tres");paths.append_array(FacilityCatalog.ORIGINAL_FACILITY_PATHS)
|
||||
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"],"switch batch to current definitions")
|
||||
var before: Dictionary=runtime.create_snapshot()
|
||||
var path: String="user://saves/dimension_batch_%d" % Time.get_ticks_usec()
|
||||
expect(SaveService.save_snapshot(path,before)[&"ok"],"persist original two-facility source")
|
||||
var migrated: Dictionary=runtime.migrate_facility_dimensions_at_path(path)
|
||||
expect(migrated[&"ok"],"batch disk migration accepts both facilities")
|
||||
var backup:=SaveService.load_snapshot(path+SaveService.MIGRATION_BACKUP_SUFFIX)
|
||||
expect(backup[&"ok"] and backup[&"snapshot"]==before,"one backup contains both original footprints")
|
||||
expect(runtime.create_snapshot()==before,"batch disk migration preserves live world")
|
||||
var loaded:=SaveService.load_snapshot(path)
|
||||
expect(loaded[&"ok"] and runtime.restore_snapshot(loaded[&"snapshot"]),"batch result restores all crosslinks")
|
||||
for room: FacilityInstance in runtime.facility_service.get_instances():
|
||||
if room.definition_id==&"premium_room": expect(room.occupied_cells.size()==4,"batch premium footprint is four cells")
|
||||
if room.definition_id==&"staff_dormitory": expect(room.occupied_cells.size()==2,"batch dormitory footprint is two cells")
|
||||
var repeated: Dictionary=runtime.migrate_facility_dimensions_at_path(path)
|
||||
expect(repeated[&"ok"] and not repeated.get(&"backup_created",true) and SaveService.load_snapshot(path+SaveService.MIGRATION_BACKUP_SUFFIX)[&"snapshot"]==before,"repeat batch preserves first backup")
|
||||
expect(runtime.restore_snapshot(before),"restore source to test late batch failure")
|
||||
var dorm_id: StringName=&""
|
||||
for room: FacilityInstance in runtime.facility_service.get_instances():
|
||||
if room.definition_id==&"staff_dormitory": dorm_id=room.instance_id
|
||||
expect(runtime.staff_service.create_task(&"maintenance",10,clock.absolute_minute,{&"target_entity_id":dorm_id,&"target_cell":Vector3i(-7,3,1)},&"batch_blocker").is_success(),"create valid task at disappearing second-facility entrance")
|
||||
var rejected_source: Dictionary=runtime.create_snapshot()
|
||||
expect(runtime.restore_snapshot(rejected_source) and SaveService.save_snapshot(path,rejected_source)[&"ok"],"late-failure source is valid and saved")
|
||||
var rejected: Dictionary=runtime.migrate_facility_dimensions_at_path(path)
|
||||
expect(not rejected[&"ok"] and rejected.get(&"details",{}).get(&"facility_id",&"")==dorm_id and rejected[&"details"].get(&"rolled_back",false),"second facility failure rolls back isolated first-facility conversion")
|
||||
expect(SaveService.load_snapshot(path)[&"snapshot"]==rejected_source and runtime.create_snapshot()==rejected_source,"late rejection preserves entire disk source and live state")
|
||||
expect(SaveService.load_snapshot(path+SaveService.MIGRATION_BACKUP_SUFFIX)[&"snapshot"]==before,"late rejected batch leaves prior backup intact")
|
||||
SaveService.delete_save(path);SaveService.delete_save(path+SaveService.MIGRATION_BACKUP_SUFFIX)
|
||||
finish()
|
||||
func finish() -> void:
|
||||
runtime.free();clock.free();state.free();print("Dimension batch save: %d checks, %d failures" % [checks,failures]);quit(failures)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cr2qkdh3c3d2s
|
||||
@@ -99,6 +99,7 @@ func _run() -> void:
|
||||
_test_callback_reentry_tamper_and_quarantine_recovery()
|
||||
_test_strict_snapshot_round_trip_and_atomic_rejection()
|
||||
_test_configuration_and_stale_dependency_boundaries()
|
||||
_test_validation_cache_detects_changes()
|
||||
if _failures == 0:
|
||||
print("PASS: %d checks" % _checks)
|
||||
else:
|
||||
@@ -459,6 +460,39 @@ func _test_configuration_and_stale_dependency_boundaries() -> void:
|
||||
_expect(not collision_projector.configure(collision_adapter, collision_source, collision_path), "configuration rejects an untracked managed-ID namespace collision")
|
||||
|
||||
|
||||
func _test_validation_cache_detects_changes() -> void:
|
||||
var start := Vector3i(0, 0, PathType.FRONT)
|
||||
var middle := Vector3i(1, 0, PathType.FRONT)
|
||||
var goal := Vector3i(2, 0, PathType.FRONT)
|
||||
var context := _context([start, goal])
|
||||
var instance := _instance(GUEST_CORRIDOR, &"facility_cache", middle, 10, &"construction_cache")
|
||||
_expect(context.projector.project_facility(&"project_cache", GUEST_CORRIDOR, instance).is_success(), "cache fixture projects corridor")
|
||||
_expect(context.projector.validate_invariants()[&"ok"], "initial complete validation succeeds")
|
||||
_expect(context.projector.validate_invariants()[&"ok"], "unchanged validation succeeds")
|
||||
var before: Dictionary = context.projector.create_snapshot()
|
||||
var exported: Dictionary = context.projector.create_snapshot()
|
||||
exported[&"projections"][0][&"cells"].clear()
|
||||
_expect(context.projector.validate_invariants()[&"ok"] and context.projector.create_snapshot() == before, "exported containers cannot alter validation cache or live state")
|
||||
var records: Dictionary = context.projector.get("_projections")
|
||||
var fingerprint: String = records[&"facility_cache"][&"record_fingerprint"]
|
||||
records[&"facility_cache"][&"record_fingerprint"] = "invalid"
|
||||
_expect(not context.projector.validate_invariants()[&"ok"], "warm cache detects changed projection content at unchanged revision")
|
||||
records[&"facility_cache"][&"record_fingerprint"] = fingerprint
|
||||
_expect(context.projector.validate_invariants()[&"ok"], "repaired owned state validates")
|
||||
var requests: Dictionary = context.projector.get("_processed_requests")
|
||||
var request_fingerprint: String = requests[&"project_cache"][&"fingerprint"]
|
||||
requests[&"project_cache"][&"fingerprint"] = "invalid"
|
||||
_expect(not context.projector.validate_invariants()[&"ok"], "warm cache detects changed request history")
|
||||
requests[&"project_cache"][&"fingerprint"] = request_fingerprint
|
||||
var path_snapshot: Dictionary = context.path.create_snapshot()
|
||||
_expect(context.path.rebuild_graph([start, goal]), "inject live path change without projector mutation")
|
||||
_expect(not context.projector.validate_invariants()[&"ok"], "unchanged owned snapshot still validates live dependencies")
|
||||
_expect(context.path.rebuild_graph([start, middle, goal]) and context.path.restore_snapshot(path_snapshot), "restore valid live graph and traffic snapshot")
|
||||
_expect(context.projector.validate_invariants()[&"ok"], "repaired dependencies validate against warm cache")
|
||||
_expect(context.projector.unproject_facility(&"unproject_cache", &"facility_cache").is_success(), "new history after cache warm can unproject")
|
||||
_expect(context.projector.validate_invariants()[&"ok"], "new history receives full validation")
|
||||
|
||||
|
||||
func _context(base_cells: Array, custom_path: Variant = null) -> Dictionary:
|
||||
var source := SpatialType.new()
|
||||
var path: PathService = custom_path if custom_path != null else PathType.new()
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
extends SceneTree
|
||||
const Preview = preload("res://scripts/construction/facility_resize_preview.gd")
|
||||
var checks := 0
|
||||
var failures := 0
|
||||
func expect(ok: bool, message: String) -> void:
|
||||
checks += 1
|
||||
if not ok: failures += 1; push_error(message)
|
||||
func _initialize() -> void:
|
||||
var world := WorldService.new()
|
||||
world.reset({&"min_x":-10,&"max_x":10,&"min_y":-5,&"max_y":10})
|
||||
var origin := Vector3i(0,0,0)
|
||||
var cells := world.cells_for_footprint(origin,Vector2i(3,2))
|
||||
world.occupy(&"room",cells)
|
||||
world.set_support(origin,0,true)
|
||||
var item := {&"instance_id":&"room",&"definition_id":&"premium_room",&"origin":origin,&"rotation":0,&"occupied_cells":cells}
|
||||
var before := world.create_snapshot()
|
||||
var report := Preview.inspect(world,item,2)
|
||||
expect(report[&"geometry_ok"] and report[&"target_cells"].size()==4 and report[&"added"].size()==1 and report[&"removed"].size()==3, "premium room preview changes 3x2 into 4x1")
|
||||
expect(not report[&"ready_to_apply"] and not report[&"remaining_gates"].is_empty(), "geometry success never bypasses route save or job migration")
|
||||
expect(world.create_snapshot()==before, "successful preview does not mutate live world")
|
||||
world.occupy(&"neighbor",[Vector3i(3,0,0)])
|
||||
before=world.create_snapshot();report=Preview.inspect(world,item,2)
|
||||
expect(not report[&"geometry_ok"] and report[&"errors"][0][&"code"]==&"OVERLAP", "expansion detects an occupied new cell")
|
||||
expect(world.create_snapshot()==before, "rejected preview preserves ownership and revisions")
|
||||
world.release(&"neighbor")
|
||||
world.occupy(&"upper",[Vector3i(2,2,0)])
|
||||
report=Preview.inspect(world,item,2)
|
||||
expect(not report[&"geometry_ok"] and &"upper" in report[&"affected_entities"], "shrink detects loss of support for upper facility")
|
||||
var bad:=item.duplicate(true);bad[&"occupied_cells"][0]=Vector3i(9,9,0)
|
||||
expect(not Preview.inspect(world,bad,2)[&"geometry_ok"], "source ownership cannot be guessed from current definition")
|
||||
bad=item.duplicate(true);bad[&"occupied_cells"][1]=bad[&"occupied_cells"][0]
|
||||
expect(not Preview.inspect(world,bad,2)[&"geometry_ok"], "duplicate saved cells reject")
|
||||
bad=item.duplicate(true);bad[&"instance_id"]=42
|
||||
expect(not Preview.inspect(world,bad,2)[&"geometry_ok"], "malformed saved identifiers reject without conversion errors")
|
||||
bad=item.duplicate(true);bad[&"rotation"]=45
|
||||
expect(not Preview.inspect(world,bad,2)[&"geometry_ok"], "invalid rotation rejects")
|
||||
world.release(&"upper");world.release(&"room")
|
||||
origin=Vector3i(0,0,1);cells=world.cells_for_footprint(origin,Vector2i(2,4))
|
||||
world.occupy(&"dorm",cells);world.set_support(origin,0,true)
|
||||
item={&"instance_id":&"dorm",&"definition_id":&"staff_dormitory",&"origin":origin,&"rotation":90,&"occupied_cells":cells}
|
||||
report=Preview.inspect(world,item,1)
|
||||
expect(report[&"geometry_ok"] and report[&"target_cells"]==[Vector3i(0,0,1),Vector3i(0,1,1)], "rotated dorm shrinks on correct layer and axis")
|
||||
world.release(&"dorm")
|
||||
origin=Vector3i(7,-3,0);cells=world.cells_for_footprint(origin,Vector2i(3,2))
|
||||
world.occupy(&"market",cells);world.set_support(origin,0,true)
|
||||
for cell: Vector3i in cells: world.set_excavated(cell,true)
|
||||
item={&"instance_id":&"market",&"definition_id":&"black_market",&"origin":origin,&"rotation":0,&"occupied_cells":cells}
|
||||
before=world.create_snapshot();report=Preview.inspect(world,item,2)
|
||||
expect(not report[&"geometry_ok"] and world.create_snapshot()==before, "market cannot expand into unexcavated underground space")
|
||||
world.set_excavated(Vector3i(10,-3,0),true);world.set_excavated(Vector3i(10,-2,0),true)
|
||||
report=Preview.inspect(world,item,2)
|
||||
expect(report[&"geometry_ok"] and report[&"target_cells"].size()==8 and report[&"added"].size()==2, "excavated market expands to original four-by-two footprint")
|
||||
world.release(&"market")
|
||||
origin=Vector3i(8,-3,0);cells=world.cells_for_footprint(origin,Vector2i(3,2))
|
||||
world.occupy(&"edge",cells);world.set_support(origin,0,true)
|
||||
item={&"instance_id":&"edge",&"definition_id":&"black_market",&"origin":origin,&"rotation":0,&"occupied_cells":cells}
|
||||
expect(not Preview.inspect(world,item,2)[&"geometry_ok"], "market expansion cannot leave map bounds")
|
||||
print("Facility resize preview: %d checks, %d failures" % [checks,failures]);quit(failures)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cja1om6ylyvfa
|
||||
@@ -0,0 +1,46 @@
|
||||
extends SceneTree
|
||||
var checks := 0
|
||||
var failures := 0
|
||||
class Budget:
|
||||
extends RefCounted
|
||||
var resources := {&"gold":100000, &"materials":100000}
|
||||
func get_resource(id: StringName) -> int: return resources.get(id, 0)
|
||||
func can_afford(cost: Dictionary) -> bool:
|
||||
for id: Variant in cost:
|
||||
if resources.get(id, 0) < cost[id]: return false
|
||||
return true
|
||||
func spend(cost: Dictionary) -> bool:
|
||||
if not can_afford(cost): return false
|
||||
for id: Variant in cost: resources[id] -= cost[id]
|
||||
return true
|
||||
func expect(ok: bool, message: String) -> void:
|
||||
checks += 1
|
||||
if not ok: failures += 1; push_error(message)
|
||||
func _initialize() -> void:
|
||||
for entry: Array in [["premium_room",Vector2i(4,1),0,2],["staff_dormitory",Vector2i(2,1),1,2],["black_market",Vector2i(4,2),0,-5]]:
|
||||
var definition: FacilityDefinition = load("res://data/facilities/expansion/%s.tres" % entry[0])
|
||||
expect(definition.footprint == entry[1] and definition.layer == entry[2], "canonical dimensions and layer: " + entry[0])
|
||||
for rotation: int in [0,90,180,270]:
|
||||
var world := WorldService.new()
|
||||
world.reset({&"min_x":-10,&"max_x":10,&"min_y":-10,&"max_y":10})
|
||||
var origin := Vector3i(0,entry[3],entry[2])
|
||||
var size: Vector2i = entry[1]
|
||||
if rotation in [90,270]: size = Vector2i(size.y,size.x)
|
||||
var expected := world.cells_for_footprint(origin,size)
|
||||
world.set_support(origin,0,true)
|
||||
for cell: Vector3i in expected:
|
||||
if cell.y < 0: world.set_excavated(cell,true)
|
||||
var budget := Budget.new()
|
||||
var construction := ConstructionService.new(world,budget)
|
||||
var started := construction.start_construction(definition,origin,rotation)
|
||||
expect(started.is_success(), "canonical construction accepted: %s rotation %d" % [entry[0],rotation])
|
||||
if not started.is_success(): continue
|
||||
var job := construction.get_jobs()[0]
|
||||
expect(job.reserved_cells == expected, "reservation has exact rotated original footprint")
|
||||
for minute in range(1,definition.build_minutes+1): construction.advance_one_minute(minute)
|
||||
var completed := construction.get_facility(job.facility_instance_id)
|
||||
expect(job.state == ConstructionJob.State.COMPLETED and completed.get(&"occupied_cells",[]) == expected and world.get_entity_cells(job.facility_instance_id).size() == expected.size(), "completion keeps original footprint")
|
||||
expect(budget.get_resource(&"gold") == 100000-int(definition.construction_cost[&"gold"]), "dimension correction does not multiply construction payment")
|
||||
var restored := ConstructionService.new(world,budget)
|
||||
expect(restored.restore_snapshot(construction.create_snapshot()), "completed original-size construction restores")
|
||||
print("Original facility dimensions: %d checks, %d failures" % [checks,failures]);quit(failures)
|
||||
@@ -0,0 +1 @@
|
||||
uid://crwpol62ko88p
|
||||
@@ -59,7 +59,7 @@ func _test_cell_traffic_and_dynamic_route() -> void:
|
||||
_expect(int(traffic[&"current_density"]) == 4, "cell reports projected current density")
|
||||
_expect(int(traffic[&"dynamic_cost"]) == 25, "cell reports configured dynamic cost")
|
||||
_expect(service.get_congestion_cost(top_middle) == 225, "density excess costs 75 units per actor")
|
||||
_expect(is_equal_approx(service.get_speed_multiplier(top_middle), 0.25), "soft collision speed clamps at 0.25")
|
||||
_expect(is_equal_approx(service.get_speed_multiplier(top_middle), 0.5), "overlapping units move at half speed")
|
||||
var diverted: Array[Vector3i] = service.find_path(start, goal, service.FRONT)
|
||||
_expect(diverted.has(bottom_middle), "A* avoids the dynamically congested route")
|
||||
_expect(not diverted.has(top_middle), "locally invalidated cache never returns the stale congested route")
|
||||
@@ -118,7 +118,7 @@ func _test_two_hundred_actor_chokepoint() -> void:
|
||||
_expect(all_entered, "all 200 actors can share the chokepoint without a hard-cap deadlock")
|
||||
_expect(service.get_current_density(choke) == 200, "chokepoint density reaches 200 exactly")
|
||||
_expect(service.get_congestion_cost(choke) == 14_700, "200-actor chokepoint congestion cost is exact")
|
||||
_expect(is_equal_approx(service.get_speed_multiplier(choke), 0.25), "extreme density remains bounded by minimum speed")
|
||||
_expect(is_equal_approx(service.get_speed_multiplier(choke), 0.5), "extreme density preserves the specified half speed")
|
||||
var all_exited := true
|
||||
for index: int in range(200):
|
||||
var actor_id := StringName("guest_%03d" % index)
|
||||
|
||||
@@ -63,6 +63,7 @@ func _run() -> void:
|
||||
_test_uncertain_rollback_quarantines_and_recovers()
|
||||
_test_strict_snapshot_round_trip_and_atomic_rejection()
|
||||
_test_strict_input_and_route_only_boundary()
|
||||
_test_validation_cache_checks_history_and_live_graph()
|
||||
if _failures == 0:
|
||||
print("PASS: %d checks" % _checks)
|
||||
else:
|
||||
@@ -450,6 +451,35 @@ func _test_strict_input_and_route_only_boundary() -> void:
|
||||
_expect(not adapter.configure(source, path, [Vector3i.ZERO]), "configured adapter rejects reconfiguration")
|
||||
|
||||
|
||||
func _test_validation_cache_checks_history_and_live_graph() -> void:
|
||||
var source := SpatialType.new()
|
||||
var path := PathType.new()
|
||||
var adapter := AdapterType.new()
|
||||
var start := Vector3i(0, 0, 0)
|
||||
var middle := Vector3i(1, 0, 0)
|
||||
var goal := Vector3i(2, 0, 0)
|
||||
_expect(adapter.configure(source, path, [start, goal]), "cache fixture configures")
|
||||
_expect(adapter.place_route(&"cache_place", &"cache_route", [middle]).is_success(), "cache fixture places route")
|
||||
_expect(adapter.validate_invariants()[&"ok"] and adapter.validate_invariants()[&"ok"], "fresh and unchanged validations succeed")
|
||||
var exported := adapter.create_snapshot()
|
||||
exported[&"projected_walkable_cells"].clear()
|
||||
exported[&"processed_requests"][0][&"input_cells"].clear()
|
||||
_expect(adapter.validate_invariants()[&"ok"], "snapshot mutation cannot change live state or cached input")
|
||||
var requests: Dictionary = adapter.get("_processed_requests")
|
||||
var fingerprint: String = requests[&"cache_place"][&"fingerprint"]
|
||||
requests[&"cache_place"][&"fingerprint"] = "invalid"
|
||||
_expect(not adapter.validate_invariants()[&"ok"], "warm cache detects history corruption without revision change")
|
||||
requests[&"cache_place"][&"fingerprint"] = fingerprint
|
||||
_expect(adapter.validate_invariants()[&"ok"], "restored history validates")
|
||||
var before := path.create_snapshot()
|
||||
_expect(path.rebuild_graph([start, goal]), "remove live bridge independently")
|
||||
_expect(not adapter.validate_invariants()[&"ok"], "warm cache still detects live graph divergence")
|
||||
_expect(path.rebuild_graph([start, middle, goal]) and path.restore_snapshot(before), "restore live path")
|
||||
_expect(adapter.validate_invariants()[&"ok"], "repaired graph validates")
|
||||
_expect(adapter.remove_route(&"cache_remove", &"cache_route").is_success(), "route removal updates cached history input")
|
||||
_expect(adapter.validate_invariants()[&"ok"], "updated history validates fully")
|
||||
|
||||
|
||||
func _assert_exact_rollback(
|
||||
adapter: RouteSubslotPathAdapter,
|
||||
source: SpatialSubslotService,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extends SceneTree
|
||||
|
||||
const RUNTIME_SNAPSHOT_VERSION := 9
|
||||
const RUNTIME_SNAPSHOT_VERSION := 13
|
||||
const INFRASTRUCTURE_SNAPSHOT_KEYS: Array[StringName] = [
|
||||
&"excavation",
|
||||
&"spatial_subslots",
|
||||
@@ -39,6 +39,22 @@ class SnapshotCountingDomainEventStream:
|
||||
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
|
||||
|
||||
@@ -51,8 +67,10 @@ 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()
|
||||
@@ -75,6 +93,61 @@ func _finish() -> void:
|
||||
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()
|
||||
@@ -113,7 +186,7 @@ func _test_runtime_surface(fixture: Dictionary) -> bool:
|
||||
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 v9 with infrastructure state")
|
||||
_expect(current_version, "Runtime emits schema v13 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
|
||||
@@ -827,6 +900,7 @@ func _test_v5_proxy_migration_determinism() -> void:
|
||||
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)
|
||||
@@ -849,7 +923,7 @@ func _test_v5_proxy_migration_determinism() -> void:
|
||||
_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"]) == 9,
|
||||
int(first_migrated[&"systems"][&"runtime"][&"runtime_schema_version"]) == 13,
|
||||
"v5 migration is immediately re-emitted as v9"
|
||||
)
|
||||
_expect(
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
extends SceneTree
|
||||
const Preview = preload("res://scripts/construction/facility_resize_preview.gd")
|
||||
var checks := 0
|
||||
var failures := 0
|
||||
func expect(ok: bool, message: String) -> void:
|
||||
checks += 1
|
||||
if not ok: failures += 1; push_error(message)
|
||||
func _initialize() -> void: call_deferred("run")
|
||||
func run() -> void:
|
||||
var world := WorldService.new()
|
||||
world.reset({&"min_x":-10,&"max_x":10,&"min_y":-5,&"max_y":10})
|
||||
var origin := Vector3i(0,-3,0)
|
||||
var cells := world.cells_for_footprint(origin,Vector2i(3,2))
|
||||
world.occupy(&"market",cells);world.occupy(&"heavy",[Vector3i(0,-4,0)])
|
||||
world.set_support(origin,10)
|
||||
for cell: Vector3i in world.cells_for_footprint(origin,Vector2i(4,2)): world.set_excavated(cell,true)
|
||||
var item := {&"instance_id":&"market",&"definition_id":&"black_market",&"origin":origin,&"rotation":0,&"occupied_cells":cells}
|
||||
var weights := {&"market":1,&"heavy":3}
|
||||
expect(world.validate_support(cells,1,weights)[&"ok"], "original occupied structure fits exact capacity")
|
||||
expect(Preview.inspect(world,item,1)[&"geometry_ok"], "generic occupant weights alone miss the overload")
|
||||
var before := world.create_snapshot()
|
||||
var preview := Preview.inspect(world,item,1,weights)
|
||||
expect(not preview[&"geometry_ok"] and &"TARGET_UNSUPPORTED" in preview[&"errors"], "exact neighboring definition weight rejects overloaded expansion")
|
||||
expect(world.create_snapshot()==before, "weighted validation does not mutate world")
|
||||
expect(not world.validate_support(cells,1,{&"missing":2})[&"ok"] and not world.validate_support(cells,1,{&"heavy":-1})[&"ok"], "unknown and negative weight overrides reject")
|
||||
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
|
||||
var clock: Variant = load("res://autoload/game_clock.gd").new()
|
||||
var state: Variant = load("res://autoload/game_state.gd").new()
|
||||
clock.reset(1,6,0);state.reset();runtime.initialize(clock,state,424242);clock.set_paused(true)
|
||||
var paths: Array[String] = FacilityCatalog.FACILITY_PATHS + FacilityCatalog.INFRASTRUCTURE_FACILITY_PATHS + FacilityCatalog.RESCUE_FACILITY_PATHS
|
||||
paths.append("res://tests/fixtures/legacy_premium_room.tres")
|
||||
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"], "fixture explicitly registers archived legacy-size definition")
|
||||
expect(runtime.submit_command(&"build_facility",{&"definition_id":&"reception",&"origin":Vector3i(-6,0,0)}).is_success(), "build supporting reception at ground level")
|
||||
clock.advance_minutes(120)
|
||||
var built: CommandResult = runtime.submit_command(&"build_facility",{&"definition_id":&"premium_room",&"origin":Vector3i(-6,2,0)})
|
||||
expect(built.is_success(), "build above-ground old-size room: " + built.message)
|
||||
if not built.is_success():
|
||||
runtime.free();clock.free();state.free();quit(failures);return
|
||||
var active_id: StringName = &""
|
||||
for job: ConstructionJob in runtime.construction_service.get_jobs():
|
||||
if job.definition_id == &"premium_room" and not job.is_terminal(): active_id = job.job_id
|
||||
paths.erase("res://tests/fixtures/legacy_premium_room.tres")
|
||||
paths.append("res://data/facilities/expansion/premium_room.tres")
|
||||
expect(runtime.definition_registry.rebuild_from_paths(paths)[&"valid"], "current original-size registry replaces legacy fixture after reservation")
|
||||
clock.advance_minutes(7)
|
||||
var active_before: Dictionary = runtime.create_snapshot()
|
||||
var original_job: Dictionary = runtime.construction_service.get_job(active_id).create_snapshot()
|
||||
var active_path := "user://saves/active_resize_%d" % Time.get_ticks_usec()
|
||||
expect(SaveService.save_snapshot(active_path,active_before)[&"ok"], "save partially built legacy job")
|
||||
var active_migration: Dictionary=runtime.migrate_facility_dimensions_at_path(active_path)
|
||||
expect(active_migration[&"ok"] and active_migration.get(&"backup_created",false), "batch migrates partial job with verified backup")
|
||||
var migrated_job_save := SaveService.load_snapshot(active_path)
|
||||
expect(migrated_job_save[&"ok"] and runtime.restore_snapshot(migrated_job_save[&"snapshot"]), "full Runtime restores migrated construction reservation")
|
||||
var current_job: ConstructionJob=runtime.construction_service.get_job(active_id)
|
||||
expect(current_job.reserved_cells.size()==4 and current_job.progress==original_job[&"progress"] and current_job.construction_cost==original_job[&"construction_cost"], "full Runtime migration preserves job progress and paid cost")
|
||||
clock.advance_minutes(150)
|
||||
var finished_job: ConstructionJob=runtime.construction_service.get_job(active_id)
|
||||
expect(finished_job.state==ConstructionJob.State.COMPLETED and runtime.facility_service.get_instance(finished_job.facility_instance_id).occupied_cells.size()==4, "migrated partial job completes as original-size operational room")
|
||||
expect(runtime.restore_snapshot(runtime.create_snapshot()), "completion after full job migration remains saveable")
|
||||
expect(SaveService.load_snapshot(active_path+SaveService.MIGRATION_BACKUP_SUFFIX)[&"snapshot"]==active_before and runtime.restore_snapshot(active_before), "original job backup remains intact and legacy fixture can resume")
|
||||
SaveService.delete_save(active_path);SaveService.delete_save(active_path+SaveService.MIGRATION_BACKUP_SUFFIX)
|
||||
var candidate := Preview.prepare_construction_candidate(runtime.world_service, runtime.construction_service, active_id, 2)
|
||||
expect(candidate[&"ok"] and not candidate[&"ready_to_apply"], "active construction has a validated candidate, not a Runtime commit")
|
||||
if candidate[&"ok"]:
|
||||
var active_row: Dictionary = {}
|
||||
for row: Dictionary in candidate[&"construction"][&"jobs"]:
|
||||
if StringName(row[&"job_id"]) == active_id: active_row = row
|
||||
expect(active_row[&"reserved_cells"].size() == 4 and active_row[&"progress"] == original_job[&"progress"] and active_row[&"progress"] > 0, "partially built job converts without advancing paid work")
|
||||
var resumed_world := WorldService.new()
|
||||
expect(resumed_world.restore_snapshot(candidate[&"world"]), "candidate world restores for partial-job continuation")
|
||||
var resumed := ConstructionService.new(resumed_world)
|
||||
expect(resumed.restore_snapshot(candidate[&"construction"]), "partial job restores through production validator")
|
||||
var job_before := resumed.get_job(active_id).create_snapshot()
|
||||
var replay := resumed.progress_job(active_id, ConstructionJob.NORMAL_WORK_RATE, resumed.current_minute)
|
||||
expect(replay.is_success() and replay.is_replay and resumed.get_job(active_id).create_snapshot() == job_before, "last saved construction minute is not charged as work twice")
|
||||
var completion_count := [0]
|
||||
resumed.facility_completed.connect(func(_facility: Dictionary): completion_count[0] += 1)
|
||||
for minute in range(resumed.current_minute + 1, resumed.current_minute + 201): resumed.advance_one_minute(minute)
|
||||
var finished := resumed.get_job(active_id)
|
||||
expect(finished.state == ConstructionJob.State.COMPLETED and completion_count[0] == 1, "resized partial job completes exactly once")
|
||||
var finished_room := resumed.get_facility(finished.facility_instance_id)
|
||||
expect(finished_room[&"occupied_cells"].size() == 4 and resumed_world.get_entity_cells(finished.facility_instance_id) == finished_room[&"occupied_cells"], "completion occupies original-spec footprint with new facility ownership")
|
||||
expect(finished.construction_cost == original_job[&"construction_cost"] and finished.build_minutes == original_job[&"build_minutes"] and finished.started_at == original_job[&"started_at"], "migration and completion retain paid cost, duration and start time")
|
||||
var completed_restore := ConstructionService.new(resumed_world)
|
||||
expect(completed_restore.restore_snapshot(resumed.create_snapshot()), "completed migrated source job and facility remain save-compatible")
|
||||
expect(runtime.create_snapshot() == active_before, "active candidate leaves source world, jobs and money unchanged")
|
||||
clock.advance_minutes(150)
|
||||
var id: StringName = &""
|
||||
for facility: Dictionary in runtime.construction_service.get_facilities():
|
||||
if facility[&"definition_id"] == &"premium_room": id = facility[&"instance_id"]
|
||||
expect(not id.is_empty(), "above-ground expansion completes")
|
||||
if id.is_empty():
|
||||
runtime.free();clock.free();state.free();quit(failures);return
|
||||
var full_before: Dictionary = runtime.create_snapshot()
|
||||
var disk_path := "user://saves/resize_disk_%d" % Time.get_ticks_usec()
|
||||
expect(SaveService.save_snapshot(disk_path, full_before)[&"ok"], "write isolated legacy-size disk fixture")
|
||||
var disk_migration: Dictionary = runtime.migrate_facility_dimensions_at_path(disk_path, id)
|
||||
expect(disk_migration[&"ok"] and disk_migration.get(&"backup_created",false), "disk migration verifies candidate and creates backup before promotion")
|
||||
var disk_loaded := SaveService.load_snapshot(disk_path)
|
||||
var disk_backup := SaveService.load_snapshot(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX)
|
||||
expect(disk_backup[&"ok"] and disk_backup[&"snapshot"] == full_before, "pre-migration disk backup retains original full snapshot")
|
||||
var backup_bytes := FileAccess.get_file_as_bytes(ProjectSettings.globalize_path(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX + "/world.bin"))
|
||||
expect(runtime.migrate_facility_dimensions_at_path(disk_path,id)[&"ok"] and FileAccess.get_file_as_bytes(ProjectSettings.globalize_path(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX + "/world.bin")) == backup_bytes, "repeated migration preserves original backup")
|
||||
var alternate: Dictionary = full_before.duplicate(true)
|
||||
alternate[&"clock"][&"absolute_minute"] += 1
|
||||
var stale := SaveService.replace_snapshot_with_backup(disk_path, full_before, alternate)
|
||||
expect(not stale[&"ok"] and stale[&"code"] == &"MIGRATION_SOURCE_CHANGED" and SaveService.load_snapshot(disk_path)[&"snapshot"] == disk_loaded[&"snapshot"], "stale source rejects before overwriting migrated save")
|
||||
var rejected_invalid := SaveService.replace_snapshot_with_backup(disk_path, disk_loaded[&"snapshot"], {&"invalid":true})
|
||||
expect(not rejected_invalid[&"ok"] and rejected_invalid[&"code"] == &"MIGRATION_INVALID_SNAPSHOT" and SaveService.load_snapshot(disk_path)[&"snapshot"] == disk_loaded[&"snapshot"], "invalid candidate preserves formal package")
|
||||
expect(FileAccess.get_file_as_bytes(ProjectSettings.globalize_path(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX + "/world.bin")) == backup_bytes, "failed migration preserves original backup bytes")
|
||||
expect(runtime.create_snapshot() == full_before, "disk migration does not alter live Runtime")
|
||||
var full_candidate: Dictionary = runtime.prepare_facility_dimension_snapshot(id)
|
||||
expect(full_candidate[&"ok"] and runtime.create_snapshot() == full_before, "full snapshot candidate preserves live Runtime")
|
||||
var isolated: Variant = load("res://autoload/simulation_runtime.gd").new()
|
||||
var isolated_clock: Variant = load("res://autoload/game_clock.gd").new()
|
||||
var isolated_state: Variant = load("res://autoload/game_state.gd").new()
|
||||
isolated_clock.reset(1,6,0);isolated_state.reset();isolated.initialize(isolated_clock,isolated_state,424242)
|
||||
isolated.definition_registry.rebuild_from_paths(paths)
|
||||
expect(isolated.restore_snapshot(full_candidate[&"snapshot"]), "full migrated snapshot passes Runtime crosslinks in isolated instance")
|
||||
expect(isolated.restore_snapshot(disk_loaded[&"snapshot"]) and isolated.facility_service.get_instance(id).occupied_cells.size() == 4, "migrated disk package restores original footprint in separate Runtime")
|
||||
SaveService.delete_save(disk_path)
|
||||
SaveService.delete_save(disk_path + SaveService.MIGRATION_BACKUP_SUFFIX)
|
||||
expect(isolated.facility_service.get_instance(id).occupied_cells.size() == 4, "operating facility restores original-spec footprint")
|
||||
var route_report := preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
|
||||
expect(route_report[&"ok"] and route_report[&"checked_routes"] == 1, "isolated Runtime route comparison preserves existing entrance reachability")
|
||||
# Controlled topology fixture for the route comparator, separate from the
|
||||
# valid full-snapshot acceptance above. Upper-floor-only access is lost.
|
||||
var old_graph: Array[Vector3i] = [Vector3i(-9,3,0), Vector3i(-8,3,0), Vector3i(-7,3,0)]
|
||||
runtime.path_service.rebuild_graph(old_graph); isolated.path_service.rebuild_graph(old_graph)
|
||||
var guest_type: StringName = runtime.get_mvp_guest_definition_ids()[0]
|
||||
var observer := GuestRuntime.new().configure(&"route_observer", guest_type, {&"current_cell":old_graph[0], &"state":GuestRuntime.State.MOVING, &"target_facility_id":id, &"path_handle":{&"target_cell":old_graph[-1]}})
|
||||
expect(runtime.guest_service.register_guest(observer, false) and isolated.guest_service.register_guest(GuestRuntime.from_snapshot(observer.create_snapshot()), false), "route fixture registers matching moving guests")
|
||||
route_report = preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
|
||||
expect(not route_report[&"ok"] and route_report[&"errors"].any(func(error: Variant): return error is Dictionary and error[&"code"] == &"GUEST_ACCESS_LOST"), "shrinking upper row detects loss of guest access even with unchanged path graph")
|
||||
# A replacement lower access remains reachable, but saved target needs update.
|
||||
old_graph.append_array([Vector3i(-9,2,0),Vector3i(-8,2,0),Vector3i(-7,2,0)])
|
||||
runtime.path_service.rebuild_graph(old_graph);isolated.path_service.rebuild_graph(old_graph)
|
||||
expect(runtime.path_service.add_connector(&"resize_stair",Vector3i(-9,3,0),Vector3i(-9,2,0)) and isolated.path_service.add_connector(&"resize_stair",Vector3i(-9,3,0),Vector3i(-9,2,0)), "fixture explicitly connects floors through a vertical connector")
|
||||
route_report = preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
|
||||
expect(route_report[&"errors"].is_empty() and route_report[&"guest_replans"].size() == 1 and not route_report[&"ok"], "reachable replacement still requires explicit moving-guest retargeting")
|
||||
var source_guest: Dictionary = runtime.guest_service.get_guest(&"route_observer").create_snapshot()
|
||||
var candidate_guest: Dictionary = isolated.guest_service.get_guest(&"route_observer").create_snapshot()
|
||||
var invalid_batch: Dictionary = route_report.duplicate(true)
|
||||
invalid_batch[&"guest_replans"].append({&"id":&"missing", &"old_target":Vector3i.ZERO, &"target":Vector3i.ZERO})
|
||||
var rejected := preload("res://scripts/construction/facility_resize_routes.gd").retarget_guests(isolated, invalid_batch)
|
||||
expect(not rejected[&"ok"] and isolated.guest_service.get_guest(&"route_observer").create_snapshot() == candidate_guest, "invalid later replan leaves earlier guest unchanged")
|
||||
var applied := preload("res://scripts/construction/facility_resize_routes.gd").retarget_guests(isolated, route_report)
|
||||
expect(applied[&"ok"] and applied[&"changed"] == [&"route_observer"], "retarget batch applies reachable entrance to isolated guest")
|
||||
var after_guest: Dictionary = isolated.guest_service.get_guest(&"route_observer").create_snapshot()
|
||||
after_guest[&"path_handle"] = candidate_guest[&"path_handle"]
|
||||
expect(after_guest == candidate_guest and runtime.guest_service.get_guest(&"route_observer").create_snapshot() == source_guest, "retarget preserves position, wallet, service state and source guest")
|
||||
expect(not preload("res://scripts/construction/facility_resize_routes.gd").retarget_guests(isolated, route_report)[&"ok"], "stale original destination cannot overwrite an already updated route")
|
||||
route_report = preload("res://scripts/construction/facility_resize_routes.gd").inspect(runtime, isolated, id)
|
||||
expect(route_report[&"ok"], "corrected moving target passes route comparison")
|
||||
var moving: GuestRuntime = isolated.guest_service.get_guest(&"route_observer")
|
||||
var actor_id: StringName = isolated._guest_path_actor_id(moving.guest_id)
|
||||
expect(isolated.path_service.project_actor_position(actor_id, moving.current_cell, isolated_clock.absolute_minute), "project candidate guest for actual movement")
|
||||
for offset in range(1, 21):
|
||||
isolated._advance_guest_path_travel(moving, actor_id, isolated_clock.absolute_minute + offset)
|
||||
if moving.current_cell.y == 2: break
|
||||
expect(moving.current_cell == Vector3i(-9,2,0), "production movement follows retargeted lower entrance instead of old upper entrance")
|
||||
expect(runtime.restore_snapshot(full_before), "restore valid source after controlled topology fixture")
|
||||
isolated.free();isolated_clock.free();isolated_state.free()
|
||||
expect(runtime.submit_command(&"register_staff",{&"staff_id":&"resize_observer",&"role_id":&"clerk",&"options":{&"current_cell":Vector3i.ZERO}}).is_success(), "register diagnostic worker on an existing corridor")
|
||||
# Diagnostic legacy-position input only; no claim of normal navigation to an
|
||||
# upper decorative cell. Preview must report it, never relocate it silently.
|
||||
runtime.staff_service.get_staff(&"resize_observer").current_cell = Vector3i(-6,3,0)
|
||||
expect(not runtime.prepare_facility_dimension_snapshot(id)[&"ok"], "removed-cell actor requires explicit relocation before preparing full snapshot")
|
||||
var completed_before: Dictionary = runtime.create_snapshot()
|
||||
candidate = Preview.prepare_construction_candidate(runtime.world_service, runtime.construction_service, id, 2)
|
||||
expect(candidate[&"ok"], "completed facility and source job migrate together")
|
||||
if candidate[&"ok"]:
|
||||
var migrated_world := WorldService.new()
|
||||
migrated_world.restore_snapshot(candidate[&"world"])
|
||||
var migrated := ConstructionService.new(migrated_world)
|
||||
expect(migrated.restore_snapshot(candidate[&"construction"]) and migrated.get_facility(id)[&"occupied_cells"].size() == 4, "candidate restores under production construction crosslink validation")
|
||||
var retry := Preview.prepare_construction_candidate(migrated_world, migrated, id, 2)
|
||||
expect(retry[&"ok"] and retry[&"construction"] == candidate[&"construction"] and retry[&"world"] == candidate[&"world"], "already migrated candidate is idempotent")
|
||||
expect(runtime.create_snapshot() == completed_before, "completed candidate leaves source state untouched")
|
||||
var snapshot: Dictionary = runtime.create_snapshot()
|
||||
preview=runtime.preview_facility_dimension_migration(id)
|
||||
expect(preview[&"construction_candidate"][&"ok"], "Runtime preview exposes validated construction candidate")
|
||||
expect(preview[&"target_cells"].size()==4 and preview[&"definition_weights"][id]==2, "Runtime preview uses original dimension and live definition weight")
|
||||
expect(preview[&"actors_on_removed_cells"].size()==1 and preview[&"actors_on_removed_cells"][0][&"id"]==&"resize_observer", "Runtime preview identifies actual worker requiring relocation")
|
||||
expect(not preview[&"ready_to_apply"] and runtime.create_snapshot()==snapshot, "Runtime preview preserves all authoritative simulation state")
|
||||
expect(not runtime.preview_facility_dimension_migration(&"missing")[&"ready_to_apply"], "unknown completed facility rejected")
|
||||
runtime.free();clock.free();state.free()
|
||||
print("Weighted resize Runtime: %d checks, %d failures" % [checks,failures]);quit(failures)
|
||||
@@ -0,0 +1 @@
|
||||
uid://buaihdar1qamn
|
||||
Reference in New Issue
Block a user