Connect physical elevators and staff commutes to construction, saves, and cutaway UI

This commit is contained in:
Takeshi
2026-09-09 12:58:40 +09:00
parent 4d72de8973
commit 0f12c748e9
46 changed files with 3267 additions and 165 deletions
@@ -93,7 +93,7 @@ func _run() -> void:
_test_corridors_and_primary_world_coexistence()
_test_staff_door_access_and_stable_ids()
_test_project_unproject_replay_and_defensive_queries()
_test_vertical_topology_rejects_unchanged()
_test_vertical_topology_projects_without_walk_bypass()
_test_definition_and_instance_crosslink_validation()
_test_project_and_unproject_failures_roll_back_exactly()
_test_callback_reentry_tamper_and_quarantine_recovery()
@@ -202,21 +202,17 @@ func _test_project_unproject_replay_and_defensive_queries() -> void:
_expect(context.projector.projection_revision == 2, "project and unproject each advance exactly once")
func _test_vertical_topology_rejects_unchanged() -> void:
func _test_vertical_topology_projects_without_walk_bypass() -> void:
var context := _context([Vector3i(0, 0, PathType.FRONT)])
var before_projector: Dictionary = context.projector.create_snapshot()
var before_source: Dictionary = context.source.create_snapshot()
var before_adapter: Dictionary = context.adapter.create_snapshot()
var before_path: Dictionary = context.path.create_snapshot()
var guest_instance := _instance(GUEST_ELEVATOR, &"facility_00000005", Vector3i(4, 4, PathType.FRONT), 40, &"construction_00000005")
var guest = context.projector.project_facility(&"guest_elevator", GUEST_ELEVATOR, guest_instance)
_expect(guest.code == CommandResultType.Code.VALIDATION_FAILED and guest.details[&"reason"] == context.projector.REASON_UNSUPPORTED_VERTICAL_TOPOLOGY, "guest elevator explicitly reports unsupported vertical topology")
_expect(guest.is_success(), "guest elevator projects completed shaft topology")
var service_instance := _instance(SERVICE_ELEVATOR, &"facility_00000006", Vector3i(8, 4, PathType.BACK), 41, &"construction_00000006")
var service = context.projector.project_facility(&"service_elevator", SERVICE_ELEVATOR, service_instance)
_expect(service.code == CommandResultType.Code.VALIDATION_FAILED and service.details[&"reason"] == context.projector.REASON_UNSUPPORTED_VERTICAL_TOPOLOGY, "service elevator explicitly reports unsupported vertical topology")
_expect(context.projector.create_snapshot() == before_projector, "unsupported vertical facilities leave projector state unchanged")
_expect(context.source.create_snapshot() == before_source and context.adapter.create_snapshot() == before_adapter and context.path.create_snapshot() == before_path, "unsupported vertical facilities leave all authoritative dependencies unchanged")
_expect(context.projector.get_processed_request_ids().is_empty(), "unsupported vertical rejection does not consume request IDs")
_expect(service.is_success(), "service elevator projects completed shaft topology")
_expect(context.path.find_path(Vector3i(4, 4, 0), Vector3i(4, 5, 0)).is_empty(), "guest shaft cannot be climbed without its separately owned cabin connector")
_expect(context.path.find_path(Vector3i(8, 4, 1), Vector3i(8, 5, 1)).is_empty(), "service shaft cannot be climbed by ordinary walk edges")
_expect(context.path.get_vertical_walk_blockers().size() == 2 and context.projector.validate_invariants()[&"ok"], "both completed elevator footprints retain authoritative owned shaft restrictions")
func _test_definition_and_instance_crosslink_validation() -> void:
+4 -3
View File
@@ -384,13 +384,13 @@ func _test_snapshot_roundtrip_and_atomic_rejection() -> void:
)
original.record_actor_progress(&"off_graph_actor", Vector3i(4, 4, 0), 12)
var snapshot := original.create_snapshot()
_expect(int(snapshot[&"schema_version"]) == 3, "request-safe traffic snapshot uses schema version 3")
_expect(int(snapshot[&"schema_version"]) == 4, "shaft-safe traffic snapshot uses schema version 4")
_expect(snapshot.has(&"cell_traffic") and snapshot.has(&"actor_cells"), "snapshot persists traffic and occupancy projection")
_expect(not snapshot.has(&"graph") and not snapshot.has(&"cache"), "snapshot still excludes derived graph and cache")
var restored = PathServiceScript.new()
_expect(restored.restore_snapshot(snapshot), "v3 snapshot restores before authoritative world graph")
_expect(restored.restore_snapshot(snapshot), "v4 snapshot restores before authoritative world graph")
_expect(restored.rebuild_graph([from_cell, to_cell]), "restored traffic validates against authoritative cells")
_expect(restored.create_snapshot() == snapshot, "v3 snapshot roundtrip is exact")
_expect(restored.create_snapshot() == snapshot, "v4 snapshot roundtrip is exact")
_expect(restored.get_current_density(from_cell) == 1, "restored density is derived consistently from actors")
_expect(restored.elevator_queue_size(&"lift_save") == 1, "restored elevator retains its request queue")
@@ -407,6 +407,7 @@ func _test_snapshot_roundtrip_and_atomic_rejection() -> void:
v2_snapshot[&"schema_version"] = 2
v2_snapshot.erase(&"known_elevator_request_ids")
v2_snapshot.erase(&"active_elevator_units")
v2_snapshot.erase(&"vertical_walk_blockers")
var v2_restored = PathServiceScript.new()
_expect(v2_restored.restore_snapshot(v2_snapshot), "schema v2 snapshot remains readable")
_expect(v2_restored.rebuild_graph([from_cell, to_cell]), "schema v2 traffic validates against authoritative cells")
@@ -1,6 +1,6 @@
extends SceneTree
const RUNTIME_SNAPSHOT_VERSION := 7
const RUNTIME_SNAPSHOT_VERSION := 8
const INFRASTRUCTURE_SNAPSHOT_KEYS: Array[StringName] = [
&"excavation",
&"spatial_subslots",
@@ -59,7 +59,7 @@ func _run() -> void:
_test_completed_proxy_projection()
_test_proxy_completion_raw_signal_commit_order()
_test_proxy_completion_projection_failure_is_atomic()
_test_vertical_preflight_rejection()
_test_completed_elevator_topology()
_test_demolition_projection_atomicity()
_test_current_snapshot_strictness()
_test_v5_proxy_migration_determinism()
@@ -113,14 +113,14 @@ 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 v7 with infrastructure state")
_expect(current_version, "Runtime emits schema v8 with infrastructure 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 v6 infrastructure surface is not connected yet; behavioral cases skipped.")
print(" PENDING: Runtime v8 infrastructure surface is not connected yet; behavioral cases skipped.")
return ready
@@ -593,45 +593,23 @@ func _test_proxy_completion_projection_failure_is_atomic() -> void:
_free_fixture(fixture)
func _test_vertical_preflight_rejection() -> void:
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 before := _infrastructure_state(fixture)
var guest = _submit(
runtime,
&"build_facility",
{
&"definition_id": &"guest_elevator",
&"origin": Vector3i(-6, 1, PathType.FRONT),
&"rotation": 0,
},
&"infra.vertical.guest"
)
var service = _submit(
runtime,
&"build_facility",
{
&"definition_id": &"service_elevator",
&"origin": Vector3i(5, 1, PathType.BACK),
&"rotation": 0,
},
&"infra.vertical.service"
)
_expect(
not guest.is_success()
and guest.details.get(&"reason", &"") == &"UNSUPPORTED_VERTICAL_TOPOLOGY",
"guest elevator is rejected at build-command preflight"
)
_expect(
not service.is_success()
and service.details.get(&"reason", &"") == &"UNSUPPORTED_VERTICAL_TOPOLOGY",
"service elevator is rejected with the same stable reason"
)
_expect(
_infrastructure_state(fixture) == before,
"unsupported vertical preflight spends nothing and mutates no service"
)
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)
@@ -750,10 +728,10 @@ func _test_current_snapshot_strictness() -> void:
_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 v7 snapshot restores")
_expect(runtime.restore_snapshot(snapshot), "valid Runtime v8 snapshot restores")
_expect(
runtime.create_snapshot() == snapshot and runtime.latest_digest == expected_digest,
"Runtime v7 round trip is exact"
"Runtime v8 round trip is exact"
)
_assert_runtime_restore_rejected(
@@ -761,7 +739,7 @@ func _test_current_snapshot_strictness() -> void:
snapshot,
func(candidate: Dictionary) -> void:
candidate[&"systems"][&"runtime"][&"unknown_infrastructure"] = {},
"unknown v7 Runtime field"
"unknown v8 Runtime field"
)
for key: StringName in INFRASTRUCTURE_SNAPSHOT_KEYS:
_assert_runtime_restore_rejected(
@@ -838,9 +816,13 @@ func _test_v5_proxy_migration_determinism() -> void:
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(&"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")
_free_fixture(baseline)
_expect(
stripped_v6_events > 0 and _legacy_v5_infrastructure_shape_is_clean(legacy_runtime),
@@ -855,8 +837,8 @@ 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"]) == 7,
"v5 migration is immediately re-emitted as v7"
int(first_migrated[&"systems"][&"runtime"][&"runtime_schema_version"]) == 8,
"v5 migration is immediately re-emitted as v8"
)
_expect(
first_runtime.facility_infrastructure_projector.has_projection(instance_id)
@@ -1057,7 +1039,7 @@ func _strip_v6_infrastructure_domain_history(runtime_data: Dictionary) -> int:
func _legacy_v5_infrastructure_shape_is_clean(runtime_data: Dictionary) -> bool:
if runtime_data.has(&"kitchen_production"):
if runtime_data.has(&"kitchen_production") or runtime_data.has(&"elevators") 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)):