extends SceneTree ## Fixed-demand MOVE-06 acceptance. Guests use public spawning plus a fixed ## MOVING destination, as in test_runtime_path_traffic. Production Runtime owns ## every path choice, walking credit, congestion delay and elevator transition. ## This isolates equipment capacity; it does not exercise natural Guest demand, ## service purchasing or economic return on investment. const SEED := 806042 const POPULATION := 48 const WINDOW_MINUTES := 480 const START := Vector3i(2, 0, 0) const GOAL := Vector3i(2, 1, 0) const DEMAND_HASH := "5bafa62275370c2a6ce5b4d4f283c3d7679c679a2b3fc6b054b681f2647456cf" const REPORT_PATH := "res://artifacts/transport/runtime-comparison.json" var _checks := 0 var _failures := 0 var _runtime: Variant var _clock: Variant var _state: Variant var _start_minute := 0 var _records: Dictionary = {} var _trace: Array[Dictionary] = [] var _errors: Array[String] = [] var _demand_rows: Array[Dictionary] = [] func _initialize() -> void: call_deferred("_run") func _run() -> void: var global_clock := root.get_node_or_null("GameClock") if global_clock != null: global_clock.set_paused(true) _demand_rows = _demand() _expect(SimulationDigest.compute(_demand_rows) == DEMAND_HASH, "Runtime and pure-service fixtures share the exact seeded 48-person demand manifest") var before := _observe(1, true) var after := _observe(2, true) if before.is_empty() or after.is_empty(): _finish() return _expect(before[&"demand_hash"] == after[&"demand_hash"] and before[&"start_minute"] == after[&"start_minute"] and before[&"window_minutes"] == after[&"window_minutes"], "same seed, arrivals, endpoints and absolute observation window in both layouts") _expect(before[&"arrived_count"] == POPULATION and after[&"arrived_count"] == POPULATION, "both layouts receive all 48 real GuestRuntime actors") _expect(before[&"completed_count"] == POPULATION and after[&"completed_count"] == POPULATION, "both layouts physically complete all 48 journeys inside the fixed window") _expect(before[&"unfinished_count"] == 0 and after[&"unfinished_count"] == 0, "no incomplete passenger is omitted from the comparison") _expect(before[&"shortest_walking_steps"] == 4 and after[&"shortest_walking_steps"] == 4, "both physical layouts have equal four-step shortest walking distance to each cabin") _expect(before[&"walking_steps_min"] >= 4 and after[&"walking_steps_min"] >= 4, "actual Runtime guests never shorten the common four-step geometry by a hidden route or teleport") _expect(before[&"walking_steps"][&"samples"] == POPULATION and after[&"walking_steps"][&"samples"] == POPULATION, "actual walking and detour statistics retain all completed guests") _expect(after[&"shaft_usage"].size() == 2, "normal Runtime path choice sends passengers to both installed cabins") _expect(before[&"queue_wait_minutes"][&"samples"] == POPULATION and after[&"queue_wait_minutes"][&"samples"] == POPULATION, "wait statistics include the entire boarded cohort") _expect(_is_improved(before, after), "additional identical cabin improves wait and journey P95 with equal fully completed demand") var replay := _observe(2, false) _expect(after == replay, "fresh same-seed Runtime replay reproduces all outcomes and the full movement event trace hash") var incomplete := after.duplicate(true) incomplete[&"completed_count"] = 0 incomplete[&"unfinished_count"] = POPULATION incomplete[&"queue_wait_minutes"] = _stats([]) incomplete[&"journey_minutes"] = _stats([]) _expect(not _is_improved(before, incomplete), "an unfinished zero-completion result cannot be accepted as faster") var report := { &"scope": "Fixed-demand public-spawn GuestRuntime harness. Actual Runtime routing, movement credit, congestion and paid construction; not natural economic Guest AI or complete P2/S14 acceptance.", &"route_policy": "Production Runtime find_path re-evaluates each walking minute; global explicit vertical connectors; no benchmark blockers or debug simulation jumps. Congestion-driven route reconsideration may add walking; actual detours are reported, never frozen or discarded.", &"completion_policy": "Record actual common-destination arrival, then normal begin_leaving/despawn_guest so completed actors no longer obstruct later arrivals.", &"percentile_policy": "Nearest-rank P95 over observed boarding waits/completed journeys, with unfinished arrivals separately censored. Improvement requires both layouts to finish the entire equal cohort.", &"seed": SEED, &"demand_hash": DEMAND_HASH, &"demand": _demand_rows, &"before": before, &"after": after, &"equipment_cost_difference": {&"gold": after[&"costs"][&"gold"] - before[&"costs"][&"gold"], &"materials": after[&"costs"][&"materials"] - before[&"costs"][&"materials"], &"maintenance_mana_demand": after[&"costs"][&"maintenance_mana_demand"] - before[&"costs"][&"maintenance_mana_demand"]}, &"improvement_accepted": _is_improved(before, after), &"checks": _checks, &"failures": _failures} DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("res://artifacts/transport")) var output := FileAccess.open(REPORT_PATH, FileAccess.WRITE) if output != null: output.store_string(JSON.stringify(report, "\t") + "\n") print("RUNTIME_TRANSPORT_COMPARISON ", JSON.stringify({&"before": _summary(before), &"after": _summary(after), &"improved": report[&"improvement_accepted"]})) _finish() func _demand() -> Array[Dictionary]: var rng := RandomNumberGenerator.new() rng.seed = SEED var result: Array[Dictionary] = [] for index: int in range(POPULATION): result.append({&"actor_id": StringName("comparison/%03d" % index), &"arrived_at": (index / 4) * 15 + rng.randi_range(0, 2), &"from": [START.x, START.y, START.z], &"to": [GOAL.x, GOAL.y, GOAL.z]}) result.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: if a[&"arrived_at"] != b[&"arrived_at"]: return a[&"arrived_at"] < b[&"arrived_at"] return str(a[&"actor_id"]) < str(b[&"actor_id"])) return result func _prepare(cabins: int) -> Dictionary: _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() _expect(_runtime.initialize(_clock, _state, SEED)[&"valid"], "%d-cabin Runtime initializes at normal starting resources" % cabins) _runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false}) _clock.set_paused(true) var builds: Array = [[&"guest_elevator", Vector3i.ZERO], [&"guest_corridor", Vector3i(2, 1, 0)], [ &"guest_corridor", Vector3i(3, 1, 0)]] if cabins == 2: builds.append([&"guest_elevator", Vector3i(4, 0, 0)]) var success := true for index: int in range(builds.size()): var result: CommandResult = _runtime.submit_command(&"build_facility", { &"definition_id": builds[index][0], &"origin": builds[index][1]}, &"player", &"", 0, _clock.absolute_minute, StringName("comparison.build.%d" % index)) success = success and result.is_success() _expect(success, "%d-cabin layout is purchased through normal public construction" % cabins) _clock.advance_minutes(310) var report: Dictionary = _runtime.elevators.get_report() var maintenance := 0 var equal_walking := true for shaft: Dictionary in report[&"shafts"]: success = success and shaft[&"operational"] and shaft[&"capacity"] == 4 and shaft[&"travel_minutes_per_floor"] == 10 var lower: Vector3i = shaft[&"stops"][0] var upper: Vector3i = shaft[&"stops"][1] var approach: Array[Vector3i] = _runtime.path_service.find_path(START, lower) var departure: Array[Vector3i] = _runtime.path_service.find_path(upper, GOAL) equal_walking = equal_walking and approach.size() == 3 and departure.size() == 3 for cell: Vector3i in approach: equal_walking = equal_walking and cell.y == START.y for cell: Vector3i in departure: equal_walking = equal_walking and cell.y == GOAL.y for module: StringName in shaft[&"module_ids"]: var facility: Dictionary = _runtime.construction_service.get_facility(module) var definition: FacilityDefinition = _runtime.definition_registry.get_facility(facility[&"definition_id"]) maintenance += definition.maintenance_mana _expect(success and report[&"shafts"].size() == cabins, "%d identical four-person cabins complete normally and receive real network power" % cabins) _expect(equal_walking, "%d-cabin layout has two real approach and two departure walking steps at every boarding position" % cabins) _expect(_runtime.path_service.get_vertical_walk_requires_connector(), "fixture uses production explicit vertical connector policy") _start_minute = _clock.absolute_minute _records = {} _trace = [] _errors = [] _subscribe() return {&"gold": 5000 - _state.get_resource(&"gold"), &"materials": 50 - _state.get_resource(&"materials"), &"maintenance_mana_demand": maintenance} if success else {} func _observe(cabins: int, check_midride: bool) -> Dictionary: var costs := _prepare(cabins) if costs.is_empty(): _dispose() return {} _spawn_arrivals(0) var checked_phases: Dictionary = {} for offset: int in range(1, WINDOW_MINUTES + 1): _tick(offset) if check_midride: for shaft: Dictionary in _runtime.elevators.get_report()[&"shafts"]: var phase: StringName = shaft[&"phase"] var kind: StringName = &"QUEUED" if shaft[&"waiting_count"] > 0 else phase if kind in [&"QUEUED", &"BOARDING"] and not checked_phases.has(kind): checked_phases[kind] = true _check_replay(offset, kind) if check_midride: _expect(checked_phases.has(&"QUEUED") and checked_phases.has(&"BOARDING"), "%d-cabin comparison exercises both queued and boarding snapshot checkpoints" % cabins) _expect(_errors.is_empty(), "%d-cabin actors retain valid lifecycle, projection, event timing and physical floor transitions: %s" % [cabins, _errors]) var result := _report(cabins, costs) DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("res://artifacts/transport")) var trace_output := FileAccess.open("res://artifacts/transport/runtime-comparison-%d-trace.json" % cabins, FileAccess.WRITE) if trace_output != null: trace_output.store_string(JSON.stringify(_trace, "\t") + "\n") _expect(_runtime.guest_service.get_guests().size() == result[&"unfinished_count"], "only genuinely unfinished guests remain in live Runtime after the observation window") _expect(_runtime.path_service.get_transit_actor_ids().size() == result[&"aboard_count"], "Path transit occupancy equals actual unfinished boarded passengers") _dispose() return result func _tick(offset: int) -> void: _clock.advance_minutes(1) for guest_id: StringName in _records: var record: Dictionary = _records[guest_id] if record[&"completed_at"] >= 0: continue var guest: GuestRuntime = _runtime.guest_service.get_guest(guest_id) if guest == null: _errors.append("Guest vanished before reaching destination: %s" % guest_id) continue if guest.current_cell != GOAL: continue record[&"completed_at"] = offset _trace.append({&"kind": &"COMPLETED", &"guest_id": guest_id, &"minute": offset}) var leaving: Dictionary = _runtime.guest_service.begin_leaving(guest_id, _clock.absolute_minute, &"COMPARISON_DESTINATION_REACHED") var despawned: Dictionary = _runtime.guest_service.despawn_guest(guest_id, _clock.absolute_minute) if not leaving.get(&"ok", false) or not despawned.get(&"ok", false): _errors.append("Normal destination despawn failed: %s" % guest_id) if _runtime.path_service.has_actor_projection(StringName("guest:" + String(guest_id))): _errors.append("Completed actor retained Path projection: %s" % guest_id) _spawn_arrivals(offset) func _spawn_arrivals(offset: int) -> void: for row: Dictionary in _demand_rows: if row[&"arrived_at"] != offset: continue var guest_id: StringName = row[&"actor_id"] _records[guest_id] = {&"guest_id": guest_id, &"arrived_at": offset, &"requested_at": -1, &"boarded_at": -1, &"alighted_at": -1, &"completed_at": -1, &"walking_steps": 0, &"shaft_id": &""} var result: CommandResult = _runtime.submit_command(&"spawn_guest", { &"guest_id": guest_id, &"guest_type_id": &"traveler", &"gold": 100, &"options": {&"current_cell": START, &"state": GuestRuntime.State.MOVING, &"state_entered_at": _clock.absolute_minute - 1, &"planned_exit_at": _clock.absolute_minute + 2000, &"path_handle": {&"target_cell": GOAL}}}, &"world", guest_id, 10, -1, StringName("comparison.spawn.%s" % guest_id)) if not result.is_success(): _errors.append("Public spawn rejected: %s" % guest_id) _trace.append({&"kind": &"SPAWNED", &"guest_id": guest_id, &"minute": offset}) func _subscribe() -> void: _runtime.domain_events.subscribe(&"*", &"transport.comparison", Callable(self, "_on_event")) func _on_event(event: SimulationDomainEvent) -> void: if event.event_type not in [&"GUEST_MOVED", &"ELEVATOR_TRIP_REQUESTED", &"ELEVATOR_BOARDED", &"ELEVATOR_ARRIVED"]: return var guest_id := StringName(String(event.entity_ids[0]).trim_prefix("guest:")) if not _records.has(guest_id): return var record: Dictionary = _records[guest_id] var offset := event.absolute_minute - _start_minute _trace.append({&"kind": event.event_type, &"guest_id": guest_id, &"minute": offset, &"payload": event.payload.duplicate(true)}) match event.event_type: &"GUEST_MOVED": var from: Vector3i = event.payload[&"from_cell"] var to: Vector3i = event.payload[&"cell"] if from.y != to.y: _errors.append("Guest walked vertically without a cabin: %s" % guest_id) record[&"walking_steps"] += 1 &"ELEVATOR_TRIP_REQUESTED": if record[&"requested_at"] >= 0: _errors.append("Journey requested more than one ride: %s" % guest_id) record[&"requested_at"] = offset record[&"shaft_id"] = event.payload[&"shaft_id"] &"ELEVATOR_BOARDED": record[&"boarded_at"] = offset if int(event.payload.get(&"wait_minutes", -1)) != offset - record[&"requested_at"]: _errors.append("Boarding event wait disagrees with observed request: %s" % guest_id) &"ELEVATOR_ARRIVED": record[&"alighted_at"] = offset if event.payload.get(&"emergency", false) or event.payload.get(&"cancelled", false): _errors.append("Healthy comparison ride unexpectedly cancelled: %s" % guest_id) func _check_replay(offset: int, label: StringName) -> void: var saved: Dictionary = _runtime.create_snapshot() var records := _records.duplicate(true) var trace := _trace.duplicate(true) var errors := _errors.duplicate() for step: int in range(offset + 1, offset + 13): _tick(step) var expected: Dictionary = _runtime.create_snapshot() var expected_records := _records.duplicate(true) var expected_trace := _trace.duplicate(true) var expected_errors := _errors.duplicate() var restored: bool = _runtime.restore_snapshot(saved) _expect(restored, "%s mid-journey aggregate Runtime snapshot restores" % label) if not restored: return _records = records.duplicate(true) _trace.assign(trace.duplicate(true)) _errors.assign(errors) _subscribe() for step: int in range(offset + 1, offset + 13): _tick(step) _expect(_runtime.create_snapshot() == expected and _records == expected_records and _trace == expected_trace and _errors == expected_errors, "%s restore replays the next 12 minutes including scheduled spawns with exact state and event trace" % label) _expect(_runtime.restore_snapshot(saved), "%s checkpoint restores again before continuing the original observation window" % label) _records = records _trace.assign(trace) _errors.assign(errors) _subscribe() func _report(cabins: int, costs: Dictionary) -> Dictionary: var waits: Array[int] = [] var journeys: Array[int] = [] var rides: Array[int] = [] var walks: Array[int] = [] var completed: Array[Dictionary] = [] var unfinished: Array[Dictionary] = [] var usage: Dictionary = {} var waiting := 0 var aboard := 0 var detours := 0 for guest_id: StringName in _records: var record: Dictionary = _records[guest_id] if record[&"boarded_at"] >= 0: waits.append(record[&"boarded_at"] - record[&"requested_at"]) if record[&"alighted_at"] >= 0: rides.append(record[&"alighted_at"] - record[&"boarded_at"]) if not String(record[&"shaft_id"]).is_empty(): usage[record[&"shaft_id"]] = int(usage.get(record[&"shaft_id"], 0)) + 1 if record[&"completed_at"] >= 0: journeys.append(record[&"completed_at"] - record[&"arrived_at"]) walks.append(record[&"walking_steps"]) if record[&"walking_steps"] > 4: detours += 1 completed.append(record.duplicate(true)) else: var trip: Dictionary = _runtime.elevators.get_actor_trip(StringName("guest:" + String(guest_id))) var phase: StringName = trip.get(&"state", &"WALKING") if phase == PathService.ELEVATOR_REQUEST_QUEUED: waiting += 1 if phase == PathService.ELEVATOR_REQUEST_BOARDED: aboard += 1 unfinished.append({&"guest_id": guest_id, &"state": phase, &"age_minutes": WINDOW_MINUTES - record[&"arrived_at"], &"observed_wait_minutes": WINDOW_MINUTES - record[&"requested_at"] if phase == PathService.ELEVATOR_REQUEST_QUEUED else 0}) walks.sort() return {&"shaft_count": cabins, &"costs": costs, &"seed": SEED, &"start_minute": _start_minute, &"window_minutes": WINDOW_MINUTES, &"demand_count": POPULATION, &"demand_hash": SimulationDigest.compute(_demand_rows), &"arrived_count": _records.size(), &"not_arrived_count": POPULATION - _records.size(), &"completed_count": completed.size(), &"unfinished_count": unfinished.size(), &"failed_count": _errors.size(), &"waiting_count": waiting, &"aboard_count": aboard, &"walking_count": unfinished.size() - waiting - aboard, &"queue_wait_minutes": _stats(waits), &"journey_minutes": _stats(journeys), &"ride_minutes": _stats(rides), &"shortest_walking_steps": 4, &"walking_steps": _stats(walks), &"detour_guest_count": detours, &"walking_steps_min": walks[0] if not walks.is_empty() else -1, &"walking_steps_max": walks[-1] if not walks.is_empty() else -1, &"shaft_usage": usage, &"completed_guests": completed, &"unfinished_guests": unfinished, &"event_trace_hash": SimulationDigest.compute(_trace), &"event_count": _trace.size()} func _stats(values: Array[int]) -> Dictionary: if values.is_empty(): return {&"samples": 0, &"mean": null, &"p95": null, &"max": null} var sorted := values.duplicate() sorted.sort() var total := 0 for value: int in sorted: total += value return {&"samples": sorted.size(), &"mean": float(total) / sorted.size(), &"p95": sorted[ceili(sorted.size() * 0.95) - 1], &"max": sorted[-1]} func _is_improved(before: Dictionary, after: Dictionary) -> bool: return before[&"demand_hash"] == after[&"demand_hash"] and before[&"window_minutes"] == after[&"window_minutes"] \ and before[&"completed_count"] == POPULATION and after[&"completed_count"] == POPULATION \ and before[&"failed_count"] == 0 and after[&"failed_count"] == 0 \ and before[&"queue_wait_minutes"][&"samples"] == POPULATION and after[&"queue_wait_minutes"][&"samples"] == POPULATION \ and after[&"queue_wait_minutes"][&"p95"] < before[&"queue_wait_minutes"][&"p95"] \ and after[&"journey_minutes"][&"p95"] < before[&"journey_minutes"][&"p95"] func _summary(report: Dictionary) -> Dictionary: return {&"cabins": report[&"shaft_count"], &"completed": report[&"completed_count"], &"unfinished": report[&"unfinished_count"], &"wait": report[&"queue_wait_minutes"], &"journey": report[&"journey_minutes"], &"walking_steps_min": report[&"walking_steps_min"], &"walking_steps_max": report[&"walking_steps_max"], &"walking_steps": report[&"walking_steps"], &"detour_guest_count": report[&"detour_guest_count"], &"shaft_usage": report[&"shaft_usage"], &"trace_hash": report[&"event_trace_hash"]} func _dispose() -> void: _runtime.free() _clock.free() _state.free() func _expect(condition: bool, label: String) -> void: _checks += 1 if not condition: _failures += 1 print("%s: %s" % ["PASS" if condition else "FAIL", label]) func _finish() -> void: print("Runtime transport comparison: %d checks, %d failures" % [_checks, _failures]) quit(0 if _failures == 0 else 1)