Compare commits

...
25 Commits
Author SHA1 Message Date
TakeshiandClaude Opus 5.5 e8b3dbe7a4 P14-03: Record review PASS awaiting Runner gate; sync current status
- P14-03 on 83b170a: formal 192/192 (22,198 checks), Root pairs 5/5,
  representative perf r02 (collection/functional comparison established;
  x1 ~827 ms exceeds the 4 ms budget in both versions), independent Opus
  whole-unit review PASS. Per the skill contract it stays uncounted (21/88)
  until Runner's own validate/review/integration/final; the registration
  proposal and evidence-binding verifier are under artifacts/.../p14-03-runner-gate-r01.
- Correction notes on P06-01/P06-03/P14-02/P06-02: their regressions missed 46
  roster-only suites; the defects found there are fixed in 83b170a and the
  formal 192-suite run covers them. Completions and approvals are preserved.
- IMPLEMENTATION_PLAN header and progress_snapshot next pointers now show 21
  units, P14-03 at the Runner gate and P28-01 next; history kept.
- Evidence matrix: 50% slowdown attributed to test_runtime_path_traffic,
  injected trips and budget/scope wording per the review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:18:54 +09:00
TakeshiandClaude Opus 5.5 83b170a4c7 Fix regressions in roster-only suites from A06/A07/P14-03
The formal collector's roster includes 46 suites the Makefile never ran;
the first formal attempt stopped on test_required_kitchen and a sweep found:
- v15 MIMI purchase saves could not be written once Runtime saves carried
  mana_reserve (P06-01): the format detector now validates that section and
  excludes it before the unchanged v15 allowlist, like special_peeping_rooms.
- test_required_kitchen's legacy14 exact-load comparison now maps the two
  approved migrations (fresh A06 reserve at the restored boundary, elevator
  snapshot v1->v2) after checking each against its contract, in Runtime key
  order; every other byte must still match.
- test_runtime_defense_autonomy allowed Mana to change only by the A06 flow.
- test_p08_normal_placement_ops expects 25 palette slots (two warps); its
  suite-policy pin is updated with flags unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:08:40 +09:00
TakeshiandClaude Opus 5.5 40364345ab P14-03: Prove new-PID pairs inside the roster; declare UIDs and policy pins
- tests/s2/test_new_pid_pairs.gd runs each writer/reader save-restart pair as
  two real child processes and keeps their complete output in the private
  profile, since the script-level roster runs suites without arguments.
- Commit the Godot UIDs of scripts added this session (and the pre-existing
  peeping-room scripts that lacked tracked UIDs) plus the legacy fixture's
  thumbnail import, so a private import generates nothing undeclared.
- Repin suite-policy source SHAs for test_main_dashboard (A06 HUD, palette 25)
  and test_runtime_transport (sustained outage helper); flags unchanged.
- Register the pair suite's completion marker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:54:45 +09:00
TakeshiandClaude Opus 5.5 a8edd3c3a1 P14-03: Versioned shaft-wait saves, keep riders aboard, real-actor proof
- ElevatorService snapshot v2 carries the shaft-wide wait; v1 saves (written
  with every elevator dynamic_cost 0) migrate by deriving it on load, and any
  v2 mismatch, including all zeros, is rejected atomically. A genuine save
  from 50ceca0 is kept as tests/fixtures/p14-03/legacy_rush_v1.
- A guest aboard a cabin no longer decides, leaves or despawns until the
  elevator sets it down at a real landing; previously a rider told to leave
  vanished from a moving cabin.
- test_route_wait_choice now proves the rush detour and route loss with a
  worker who actually walks, every shared rider's arrival cell, service
  elevator and stair congestion, legacy migration and a new-PID restart.
- Register completion markers for the seven suites added this session and
  bring the P14 ledger in line with P14-02's completion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:51:41 +09:00
TakeshiandClaude Opus 5.5 62d1dcecad P14-03: Add evidence matrix (regression and review pending)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:10:56 +09:00
TakeshiandClaude Opus 5.5 0754f412a8 P14-03: Price whole-shaft elevator waits in A* route choice
Riders queued for any floor pair in a shaft now delay every pair: the
elevator service publishes the rest of the shaft queue as each connector's
dynamic cost, refreshed on trip changes and each cabin minute, and restore
rejects saves whose wait disagrees with their trips. A two-shaft fixture with
real guests shows rush diversion, shared cabins within capacity, recovery,
route loss and warp-exit congestion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:57:28 +09:00
TakeshiandClaude Opus 5.5 50ceca0b7d P06-02: Record completion under delegated approval; P06 package complete, units 21/88
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:48:47 +09:00
TakeshiandClaude Opus 5.5 d743bd67b6 P06-02: Assert no SERVICE_SALE events during the natural outage
Review r1 noted the facility revenue balance is swept immediately; the event
check proves no sale directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:48:08 +09:00
TakeshiandClaude Opus 5.5 f6f9c9c0d4 P06-02: Prove whole-tower stop under natural A06 depletion across PIDs
An ordinary operating tower whose upkeep exceeds the world tree's supply runs
dry on its own; for an hour every facility is stopped with no sales, income,
production, admissions, warp travel or elevator boarding, and no guest is lost
except through ordinary departure. A mid-outage save continues identically in
a new process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:18:38 +09:00
TakeshiandClaude Opus 5.5 0f23d34e9f Path: Apply "!id" access to layer-crossing and no-route diagnostics
A stopped guest warp now reports CONNECTOR_UNAVAILABLE instead of
GOAL_UNREACHABLE (P14-02 review r2 follow-up).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:12:47 +09:00
TakeshiandClaude Opus 5.5 28e3ffe146 P14-02: Record completion under delegated approval; original units 20/88
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:11:52 +09:00
TakeshiandClaude Opus 5.5 ad2ea79c7d P14-02: Record second independent review PASS on 8917c19
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 14:11:10 +09:00
TakeshiandClaude Opus 5.5 8917c190cf P14-02: Split warps into guest FRONT and staff BACK service warp (A08)
The FRONT Mana warp is guest-only: its connectors carry the "!staff" access,
which path access checks treat as open to everyone except staff. A new 2x2
BACK service warp links only to other service warps for staff, with A07
values. Registry and palette now hold 25 definitions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:48:14 +09:00
TakeshiandClaude Opus 5.5 619b5e07ed P14-02: Record independent review PASS on 728e5e6 and acceptance evidence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:30:34 +09:00
TakeshiandClaude Opus 5.5 728e5e612f P14-02: Record warp performance measurements
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:24:51 +09:00
TakeshiandClaude Opus 5.5 cca5457454 P14-02: Keep warp in its own catalog list
Stair infrastructure stays exactly the two stairs; the Runtime registry now
loads 24 definitions including the A07 warp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:05:29 +09:00
TakeshiandClaude Opus 5.5 0cfaec1626 P14-02: Add buildable Mana warp (A07)
2x2 FRONT warp at 3000G/30 materials/360 min, 15G/day and 1 Mana upkeep.
Every completed warp pair is linked by one path connector, so crossing is a
single step; a 3-Mana fare per rider is charged once in the step's tick.
Warps close while either end is unpowered, the reserve is empty or below one
fare, and blocked arrivals offer no step. Saves validate the derived links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:45:28 +09:00
TakeshiandClaude Opus 5.5 7e6e540837 P06-03: Record owner approval; original units 19/88
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:03:53 +09:00
TakeshiandClaude Opus 5.5 29782a3f0a P06-03: Record independent review PASS on 826ef60 and acceptance evidence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:22:26 +09:00
TakeshiandClaude Opus 5.5 826ef606df P06-03: Show Mana supply, consumption and storage; prove new-PID recovery
HUD tooltip reports world tree supply, upkeep consumption, net, stored amount
and the last boundary's shortage/overflow. A writer/reader pair saves mid-outage,
recovers in a new process and matches the writer exactly while DESTROYED and
RAIDED suspensions stay in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:59:59 +09:00
TakeshiandClaude Opus 5.5 db5ca62e42 P06-01: Record owner approval; original units 18/88
Owner approved P06-01 formal completion on candidate f247d19 (2026-10-20).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:57:41 +09:00
TakeshiandClaude Opus 5.5 a1538a8633 P06-01: Record independent review PASS on f247d19 and acceptance evidence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:01:19 +09:00
TakeshiandClaude Opus 5.5 f247d19325 P06-01: Fix review r01 findings for A06 reserve
Settle Mana raised above capacity between boundaries as recorded overflow
instead of rejecting saves or latching a fault, exclude destroyed facilities
from upkeep demand, and keep the depletion drill's outage sustained.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:56:57 +09:00
TakeshiandClaude Opus 5.5 65534cfd15 P06-01: Show A06 reserve capacity in HUD, add new-PID and perf evidence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:29:04 +09:00
TakeshiandClaude Opus 5.5 ae0f998ff4 P06-01: Implement approved A06 finite Mana reserve (MP-01-r02 recommended)
Initial 100, capacity 300, world tree +20 per 10 game minutes. Each boundary
pays registered upkeep demand before storing surplus; overflow is discarded
and recorded, 0 stops the whole tower. Furnace offers are judged after
generation and demand payment. New saves carry mana_reserve and Operations
rollback includes it; legacy saves keep a 0..300 amount and reject others.

Outage tests that relied on Mana 0 persisting now hold the outage with a
disabled demand sink, since the world tree recovers at the next boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:20:04 +09:00
88 changed files with 4096 additions and 93 deletions
+15
View File
@@ -63,6 +63,12 @@ test-s2:
$(GODOT) --headless --path . --script res://tests/s2/test_economy_service.gd
$(GODOT) --headless --path . --script res://tests/s2/test_ledger_backed_resources.gd
$(GODOT) --headless --path . --script res://tests/s2/test_mana_network_service.gd
$(GODOT) --headless --path . --script res://tests/s2/test_mana_reserve_cycle.gd
$(GODOT) --headless --path . --script res://tests/s2/test_runtime_mana_reserve.gd
$(GODOT) --headless --path . --script res://tests/s2/test_mana_reserve_new_pid.gd -- writer
$(GODOT) --headless --path . --script res://tests/s2/test_mana_reserve_new_pid.gd -- reader
$(GODOT) --headless --path . --script res://tests/s2/test_mana_recovery_new_pid.gd -- writer
$(GODOT) --headless --path . --script res://tests/s2/test_mana_recovery_new_pid.gd -- reader
$(GODOT) --headless --path . --script res://tests/s2/test_runtime_operations_cycle.gd
test-s3:
@@ -95,6 +101,9 @@ test-s6:
test-mvp:
$(GODOT) --headless --path . --script res://tests/mvp/test_premium_room_guest_flow.gd
$(GODOT) --headless --path . --script res://tests/mvp/test_runtime_mana_depletion.gd
$(GODOT) --headless --path . --script res://tests/mvp/test_whole_tower_outage.gd -- writer
$(GODOT) --headless --path . --script res://tests/mvp/test_whole_tower_outage.gd -- reader
$(GODOT) --headless --path . --script res://tests/mvp/test_premium_room.gd
$(GODOT) --headless --path . --script res://tests/mvp/test_original_room_zones.gd
$(GODOT) --headless --path . --script res://tests/mvp/test_upkeep_loss_streak.gd
@@ -231,6 +240,12 @@ test-transport:
$(GODOT) --headless --path . --script res://tests/transport/test_transport_density_migration.gd
$(GODOT) --headless --path . --script res://tests/transport/test_transport_boundaries.gd
$(GODOT) --headless --path . --script res://tests/transport/test_runtime_transport.gd
$(GODOT) --headless --path . --script res://tests/transport/test_runtime_warp.gd -- writer
$(GODOT) --headless --path . --script res://tests/transport/test_runtime_warp.gd -- reader
$(GODOT) --headless --path . --script res://tests/transport/test_route_wait_choice.gd
$(GODOT) --headless --path . --script res://tests/transport/test_route_wait_choice.gd -- writer
$(GODOT) --headless --path . --script res://tests/transport/test_route_wait_choice.gd -- reader
$(GODOT) --headless --path . --script res://tests/s2/test_new_pid_pairs.gd
capture-transport:
THE_TREE_TRANSPORT_CAPTURE=1 $(GODOT) --path . --script res://tests/transport/test_runtime_transport.gd
+136 -6
View File
@@ -29,6 +29,8 @@ const AutoPurchasePlansType := preload("res://scripts/supply/supply_auto_purchas
const CLEANING_RUNTIME_SNAPSHOT_VERSION := 12
const WEATHER_RUNTIME_SNAPSHOT_VERSION := 11
const FacilityCleanliness = preload("res://scripts/environment/facility_cleanliness_service.gd")
const ManaReserveCycle = preload("res://scripts/mana/mana_reserve_cycle.gd")
const WarpService = preload("res://scripts/transport/warp_service.gd")
const CleaningBridge = preload("res://scripts/environment/facility_cleaning_bridge.gd")
const CleaningPolicy = preload("res://scripts/environment/facility_cleaning_policy.gd")
const UPKEEP_RUNTIME_SNAPSHOT_VERSION := 10
@@ -108,6 +110,7 @@ var facility_cleanliness := FacilityCleanliness.new()
var cleaning_policy := CleaningPolicy.new()
var cleaning_bridge := CleaningBridge.new()
var facility_upkeep := FacilityUpkeepAccrual.new()
var mana_reserve := ManaReserveCycle.new()
var upkeep_settlement := FacilityUpkeepSettlement.new()
var economy_service: EconomyService
var construction_resource_state: LedgerBackedResourceState
@@ -441,7 +444,7 @@ func initialize(clock: SimulationKernel, state: Variant, seed := DEFAULT_WORLD_S
)
_initialized = true
var report := definition_registry.rebuild_from_paths(
FacilityCatalog.FACILITY_PATHS + FacilityCatalog.INFRASTRUCTURE_FACILITY_PATHS + FacilityCatalog.RESCUE_FACILITY_PATHS + FacilityCatalog.ORIGINAL_FACILITY_PATHS)
FacilityCatalog.FACILITY_PATHS + FacilityCatalog.INFRASTRUCTURE_FACILITY_PATHS + FacilityCatalog.RESCUE_FACILITY_PATHS + FacilityCatalog.ORIGINAL_FACILITY_PATHS + FacilityCatalog.TRANSPORT_FACILITY_PATHS)
var catalog_registration_ok := _catalog_definitions_are_registered(guest_service)
report[&"content_catalog"] = mvp_content_report.duplicate(true)
report[&"progression_initialized"] = initial_progression_ok
@@ -539,6 +542,7 @@ func create_snapshot() -> Dictionary:
&"path": path_service.create_snapshot(),
&"movement_credits": _serialize_movement_credits(),
&"mana": mana_network_service.create_snapshot(),
&"mana_reserve": mana_reserve.create_snapshot(),
&"economy": economy_service.create_snapshot(),
&"facility_upkeep": facility_upkeep.create_snapshot(),
&"upkeep_settlement": upkeep_settlement.create_snapshot(),
@@ -676,6 +680,8 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
runtime_current_keys.append(&"auto_purchase_plans")
if runtime_data.has(&"special_peeping_rooms"):
runtime_current_keys.append(&"special_peeping_rooms")
if runtime_data.has(&"mana_reserve"):
runtime_current_keys.append(&"mana_reserve")
if not _dictionary_has_exact_canonical_keys(runtime_data, runtime_current_keys) \
or typeof(runtime_data.get(&"runtime_schema_version", null)) != TYPE_INT \
or typeof(runtime_data.get(&"world_seed", null)) != TYPE_INT \
@@ -857,6 +863,23 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
var restored_mana := ManaNetworkService.new()
if not restored_mana.restore_snapshot(runtime_data[&"mana"]):
return false
# A06: saves without the finite reserve keep an explicit stored amount
# (0 stays stopped) only within capacity; nothing is silently truncated.
var restored_mana_reserve := ManaReserveCycle.new()
var saved_game_resources: Variant = snapshot[&"game_state"].get(&"resources", null)
if not saved_game_resources is Dictionary:
return false
var saved_mana: Variant = saved_game_resources.get(&"mana", saved_game_resources.get("mana", null))
if runtime_data.has(&"mana_reserve"):
# Between boundaries Mana may exceed capacity; the next boundary records
# and discards the excess, so only a valid integer amount is required.
if not ManaReserveCycle.stored_amount_is_valid(saved_mana) \
or not restored_mana_reserve.restore_snapshot(runtime_data[&"mana_reserve"]) \
or restored_mana_reserve.get_minute() > restored_minute:
return false
elif not ManaReserveCycle.amount_is_valid(saved_mana) \
or not restored_mana_reserve.start_at(restored_minute):
return false
var restored_economy := EconomyService.new()
if not restored_economy.restore_snapshot(runtime_data[&"economy"]):
return false
@@ -1235,6 +1258,8 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
if not _validate_elevator_crosslinks(restored_elevators, restored_path, restored_construction,
restored_guests, restored_staff, restored_runtime_domain_minute):
return false
if not WarpService.connectors_match(restored_path, restored_construction.get_facilities()):
return false
for facility: FacilityInstance in restored_facilities.get_instances():
for staff_id: StringName in facility.active_staff_ids:
if not restored_elevators.get_actor_trip(_staff_path_actor_id(staff_id)).is_empty() and not CleaningBridge.is_deployed(restored_staff.get_staff(staff_id), facility, restored_staff):
@@ -1325,6 +1350,7 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
_movement_credits = (restored_movement_credits as Dictionary).duplicate(true)
_connect_path_performance_signal()
mana_network_service = restored_mana
mana_reserve = restored_mana_reserve
weather = restored_weather
facility_cleanliness = restored_cleanliness
facility_upkeep = restored_upkeep
@@ -2054,6 +2080,7 @@ func _build_operations_external_state() -> Dictionary:
&"personal_action_points": _personal_action_points,
# The remaining aggregates are reachable through Event actions or signals.
&"mana": mana_network_service.create_snapshot(),
&"mana_reserve": mana_reserve.create_snapshot(),
&"logistics_dispatcher": logistics_dispatcher.create_snapshot(),
&"logistics_requests": _serialize_logistics_requests(),
&"defense": defense_service.create_snapshot(),
@@ -2091,7 +2118,7 @@ func _restore_operations_external_state(token: Variant) -> bool:
&"excavation", &"spatial_subslots", &"route_projection",
&"facility_infrastructure",
&"movement_credits", &"domain_events", &"id_generator", &"rng_streams",
&"progression", &"hired_staff_candidate_ids", &"mana",
&"progression", &"hired_staff_candidate_ids", &"mana", &"mana_reserve",
&"logistics_dispatcher", &"defense", &"construction",
]
for key: StringName in required_dictionary_keys:
@@ -2152,6 +2179,7 @@ func _restore_operations_external_state(token: Variant) -> bool:
var ids_ok := id_generator.restore_snapshot(saved[&"id_generator"])
var progression_ok := progression_service.restore_snapshot(saved[&"progression"])
var mana_ok := mana_network_service.restore_snapshot(saved[&"mana"])
mana_ok = mana_reserve.restore_snapshot(saved[&"mana_reserve"]) and mana_ok
var dispatcher_ok := logistics_dispatcher.restore_snapshot(saved[&"logistics_dispatcher"])
var defense_ok := defense_service.restore_snapshot(saved[&"defense"])
var construction_ok := construction_service.restore_snapshot(saved[&"construction"])
@@ -2258,6 +2286,7 @@ func _operations_external_state_matches(saved: Dictionary) -> bool:
or not _strict_variants_equal(id_generator.create_snapshot(), saved[&"id_generator"]) \
or not _strict_variants_equal(progression_service.create_snapshot(), saved[&"progression"]) \
or not _strict_variants_equal(mana_network_service.create_snapshot(), saved[&"mana"]) \
or not _strict_variants_equal(mana_reserve.create_snapshot(), saved[&"mana_reserve"]) \
or not _strict_variants_equal(logistics_dispatcher.create_snapshot(), saved[&"logistics_dispatcher"]) \
or not _strict_variants_equal(_serialize_logistics_requests(), saved[&"logistics_requests"]) \
or not _strict_variants_equal(defense_service.create_snapshot(), saved[&"defense"]) \
@@ -5226,6 +5255,8 @@ func _initialize_economy() -> void:
upkeep_settlement = FacilityUpkeepSettlement.new()
FacilityUpkeepSettlement.prepare_accounts(economy_service)
facility_upkeep.start_at(_clock.absolute_minute)
mana_reserve = ManaReserveCycle.new()
mana_reserve.start_at(_clock.absolute_minute)
construction_resource_state = _create_resource_adapter(
economy_service,
CONSTRUCTION_EXPENSE_ACCOUNT,
@@ -7816,7 +7847,8 @@ func _execute_demolish_facility(command: SimulationCommand) -> CommandResult:
demolished.command_id = command.command_id
var transport_ok := false
if demolished.is_success():
transport_ok = bool(_synchronize_elevators(_runtime_event_minute()).get(&"ok", false)) and _prune_legacy_stairs_and_movement()
transport_ok = bool(_synchronize_elevators(_runtime_event_minute()).get(&"ok", false)) \
and bool(_synchronize_warps().get(&"ok", false)) and _prune_legacy_stairs_and_movement()
if not transport_ok or not demolished.is_success() \
or not _validate_runtime_path_crosslinks(path_service, guest_service, staff_service, _movement_credits, _runtime_event_minute()) \
or facility_infrastructure_projector.has_projection(instance_id) \
@@ -8331,6 +8363,11 @@ func _apply_completed_facility_internal(instance: Dictionary, absolute_minute: i
var transport := _synchronize_elevators(absolute_minute)
if not bool(transport.get(&"ok", false)):
return {&"ok": false, &"code": &"ELEVATOR_SYNC_FAILED", &"reason": elevators.last_error, &"details": transport}
if definition.id in WarpService.DEFINITION_IDS:
_register_facility_mana_consumer(instance)
var warp_sync := _synchronize_warps()
if not bool(warp_sync.get(&"ok", false)):
return {&"ok": false, &"code": &"WARP_SYNC_FAILED", &"reason": String(warp_sync.get(&"reason", "")), &"details": warp_sync}
if not _prune_legacy_stairs_and_movement():
return {&"ok": false, &"code": &"LEGACY_STAIR_PRUNE_FAILED", &"reason": "Stair topology could not be updated."}
if not _publish_domain_event(SimulationDomainEvent.new(
@@ -8759,6 +8796,10 @@ func get_guest_decision_record(guest_id: StringName) -> Dictionary:
func _advance_guest_ai_decisions(absolute_minute: int) -> void:
for guest: GuestRuntime in guest_service.get_guests():
# A rider inside a cabin cannot decide, leave or despawn until the
# elevator sets it down at a real landing (P14-03: passengers never vanish).
if elevators.get_actor_trip(_guest_path_actor_id(guest.guest_id)).get(&"state", &"") == PathService.ELEVATOR_REQUEST_BOARDED:
continue
match guest.state:
GuestRuntime.State.SPAWNING:
guest_service.transition_guest(guest.guest_id, GuestRuntime.State.ENTERING, absolute_minute, &"ENTRY_STARTED")
@@ -8948,7 +8989,8 @@ func _advance_guest_path_travel(
actor_id, guest.current_cell, absolute_minute
)
accumulated = mini(accumulated, required_credit + MOVEMENT_CREDIT_SCALE - 1)
if accumulated < required_credit:
var guest_warp := _warp_step_connector(path[0], path[1], [])
if accumulated < required_credit or not _warp_fare_affordable(guest_warp, 1):
_record_blocked_actor_wait(
actor_id,
guest.guest_id,
@@ -8972,6 +9014,7 @@ func _advance_guest_path_travel(
guest.recovery_kind = previous_recovery_kind
_report_path_integration_failure(actor_id, guest.guest_id, &"guest", previous_cell)
return
_charge_warp_fare(guest_warp, [actor_id], previous_cell, guest.current_cell)
var remaining_credit := accumulated - required_credit
_movement_credits[actor_id] = {
&"credit": remaining_credit,
@@ -9074,7 +9117,9 @@ func _advance_staff_task_travel(
actor_id, staff.current_cell, absolute_minute
)
accumulated = mini(accumulated, required_credit + MOVEMENT_CREDIT_SCALE - 1)
if accumulated < required_credit:
var staff_warp := _warp_step_connector(path[0], path[1], [&"staff"])
var warp_riders := 2 if task.task_type == &"rescue_transport" else 1
if accumulated < required_credit or not _warp_fare_affordable(staff_warp, warp_riders):
_record_blocked_actor_wait(
actor_id,
staff.staff_id,
@@ -9098,6 +9143,9 @@ func _advance_staff_task_travel(
return
patient.current_cell = staff.current_cell
_record_expected_actor_wait(_staff_path_actor_id(patient.staff_id), patient.current_cell, absolute_minute)
_charge_warp_fare(staff_warp, [actor_id, _staff_path_actor_id(patient.staff_id)], previous_cell, staff.current_cell)
else:
_charge_warp_fare(staff_warp, [actor_id], previous_cell, staff.current_cell)
var remaining_credit := accumulated - required_credit
_movement_credits[actor_id] = {
&"credit": remaining_credit,
@@ -10713,6 +10761,30 @@ func _reservation_references_are_valid(
return false
return true
## HUD view of the A06 reserve: supply, consumption and storage per interval.
func get_mana_reserve_report() -> Dictionary:
var demand := _mana_reserve_demand()
return {
&"amount": int(_state.get_resource(&"mana")),
&"capacity": ManaReserveCycle.CAPACITY,
&"generation": ManaReserveCycle.WORLD_TREE_GENERATION,
&"interval_minutes": ManaReserveCycle.INTERVAL_MINUTES,
&"demand": demand,
&"net": ManaReserveCycle.WORLD_TREE_GENERATION - demand,
&"last_flow": mana_reserve.get_last_flow(),
}
## A06 upkeep demand: every owned consumer, open or not, except destroyed
## facilities. Removed facilities are already unregistered from the network.
func _mana_reserve_demand() -> int:
var destroyed: Array[StringName] = []
for facility: FacilityInstance in facility_service.get_instances():
if facility.suspension_reason == &"DESTROYED":
destroyed.append(facility.instance_id)
return mana_network_service.get_total_consumer_demand(destroyed)
func _advance_mana(absolute_minute: int) -> void:
if _operations_tick_blocked:
return
@@ -10729,12 +10801,32 @@ func _advance_mana(absolute_minute: int) -> void:
infrastructure_preflight.get(&"details", {})
)
return
# A06: generation and upkeep demand settle before local distribution and the
# whole-tower gate, so the network and projection see the committed reserve.
var reserve_flow := mana_reserve.advance_to(
absolute_minute, int(_state.get_resource(&"mana")), _mana_reserve_demand()
)
if not bool(reserve_flow.get(&"ok", false)):
_latch_infrastructure_failure(
StringName(reserve_flow.get(&"code", &"MANA_RESERVE_FAILED")),
absolute_minute,
"The finite Mana reserve could not settle this boundary.",
{&"mana": int(_state.get_resource(&"mana"))}
)
return
if bool(reserve_flow.get(&"processed", false)):
_state.set_resource(&"mana", int(reserve_flow[&"after"]))
var report := mana_network_service.advance_one_minute(absolute_minute)
# Finite reserve is an additional gate, even between network evaluations and
# for zero-demand facilities. The network remains the local supply authority.
preload("res://scripts/mana/mana_power_projection.gd").apply(
facility_service, mana_network_service, int(_state.get_resource(&"mana")), absolute_minute
)
var warp_sync := _synchronize_warps()
if not bool(warp_sync.get(&"ok", false)):
_latch_infrastructure_failure(&"WARP_SYNC_FAILED", absolute_minute,
"Warp connectors could not follow the current power state.", warp_sync)
return
for change: Dictionary in report.get(&"state_changes", []):
var consumer_id := StringName(change.get(&"consumer_id", ""))
_publish_domain_event(SimulationDomainEvent.new(
@@ -12754,7 +12846,8 @@ func advance_staff_commute(staff_id: StringName, target_cell: Vector3i, minute:
var required_credit := _step_movement_credit(path_service, path[0], path[1], [&"staff"])
var credit := _movement_credit_after_one_minute(actor_id, staff.current_cell, minute)
credit = mini(credit, required_credit + MOVEMENT_CREDIT_SCALE - 1)
if credit < required_credit:
var commute_warp := _warp_step_connector(path[0], path[1], [&"staff"])
if credit < required_credit or not _warp_fare_affordable(commute_warp, 1):
_record_expected_actor_wait(actor_id, staff.current_cell, minute)
_movement_credits[actor_id] = {&"credit": credit, &"updated_at": minute}
return {&"ok": true, &"moved": false}
@@ -12763,6 +12856,7 @@ func advance_staff_commute(staff_id: StringName, target_cell: Vector3i, minute:
_report_path_integration_failure(actor_id, staff_id, &"staff", previous)
return {&"ok": false}
staff.current_cell = path[1]
_charge_warp_fare(commute_warp, [actor_id], previous, staff.current_cell)
_movement_credits[actor_id] = {&"credit": credit - required_credit, &"updated_at": minute}
_publish_actor_event(&"STAFF_MOVED", &"staff_commute", [staff_id, actor_id], {
&"path_actor_id": actor_id, &"from_cell": previous, &"cell": staff.current_cell,
@@ -12846,6 +12940,42 @@ func _execute_set_elevator_operation(command: SimulationCommand) -> CommandResul
return CommandResult.succeeded(command.command_id, {&"shaft_id": shaft_id, &"operator_open": open_value})
## A07: warp connectors exist for every completed warp pair and are usable only
## while both warps are powered and the reserve can pay one fare.
func _synchronize_warps() -> Dictionary:
var available := {}
var reserve_ok := int(_state.get_resource(&"mana")) > 0
for warp: Dictionary in WarpService.warps_from_facilities(construction_service.get_facilities()):
var state := mana_network_service.get_consumer_state(warp[&"instance_id"])
available[warp[&"instance_id"]] = reserve_ok and state in [ManaNetworkService.ConsumerState.ACTIVE, ManaNetworkService.ConsumerState.DEGRADED]
return WarpService.synchronize(path_service, construction_service.get_facilities(), available,
int(_state.get_resource(&"mana")) >= WarpService.MANA_PER_TRIP)
func _warp_step_connector(from: Vector3i, to: Vector3i, access: Array[StringName]) -> StringName:
var connector_id := path_service.get_step_connector(from, to, access)
return connector_id if WarpService.is_warp_connector(connector_id) else &""
func _warp_fare_affordable(connector_id: StringName, riders: int) -> bool:
return connector_id.is_empty() or int(_state.get_resource(&"mana")) >= WarpService.MANA_PER_TRIP * riders
## Charged once, in the same tick as the committed step; affordability was
## checked before the step, so the deduction cannot fail here.
func _charge_warp_fare(connector_id: StringName, actor_ids: Array, from: Vector3i, to: Vector3i) -> void:
if connector_id.is_empty():
return
var fare := WarpService.MANA_PER_TRIP * actor_ids.size()
_state.apply_resource_deltas({&"mana": -fare})
var subjects: Array[StringName] = [connector_id]
for actor_id: Variant in actor_ids:
subjects.append(StringName(actor_id))
_publish_actor_event(&"WARP_TRAVELED", &"warp", subjects, {
&"connector_id": connector_id, &"from_cell": from, &"cell": to,
&"riders": actor_ids.size(), &"mana": fare})
func _synchronize_elevators(minute: int) -> Dictionary:
return elevators.synchronize(ElevatorService.configurations_from_facilities(
construction_service.get_facilities(), definition_registry), minute)
@@ -0,0 +1,27 @@
[gd_resource type="Resource" script_class="FacilityDefinition" load_steps=2 format=3]
[ext_resource type="Script" path="res://scripts/data/facility_definition.gd" id="1"]
[resource]
script = ExtResource("1")
id = &"mana_warp"
display_name = "マナワープ"
description = "建設済みの表層ワープ同士を瞬時につなぐ客用の転移陣。客が1回3マナで移動する。従業員は裏層の業務用ワープを使う。"
zone = 0
layer = 0
footprint = Vector2i(2, 2)
construction_cost = {&"gold": 3000, &"materials": 30}
build_minutes = 360
weight_per_cell = 3
pass_through = true
maintenance_gold = 15
maintenance_mana = 1
power_priority = 80
staff_min = 0
staff_max = 0
capacity = 4
queue_capacity = 0
base_service_minutes = 1
base_quality = 50
base_price = 0
tags = Array[StringName]([&"guest_access", &"movement", &"schema_facility_proxy", &"warp"])
@@ -0,0 +1,27 @@
[gd_resource type="Resource" script_class="FacilityDefinition" load_steps=2 format=3]
[ext_resource type="Script" path="res://scripts/data/facility_definition.gd" id="1"]
[resource]
script = ExtResource("1")
id = &"service_warp"
display_name = "業務用マナワープ"
description = "建設済みの業務用ワープ同士を瞬時につなぐ裏層の転移陣。従業員が1回3マナで移動する。"
zone = 0
layer = 1
footprint = Vector2i(2, 2)
construction_cost = {&"gold": 3000, &"materials": 30}
build_minutes = 360
weight_per_cell = 3
pass_through = true
maintenance_gold = 15
maintenance_mana = 1
power_priority = 80
staff_min = 0
staff_max = 0
capacity = 4
queue_capacity = 0
base_service_minutes = 1
base_quality = 50
base_price = 0
tags = Array[StringName]([&"movement", &"schema_facility_proxy", &"staff_only", &"warp"])
@@ -1,3 +1,27 @@
## 現在の対象(2026-10-20・正式21成果/P14-03はRunnerゲート待ち)
元30パッケージ・88成果単位で、部分点はありません。正式完了は21成果、完了パッケージは3(P00、P04、P06)です。
- 2026-10-19 以降に正式完了したもの: P06-01、P06-03、P14-02、P06-02。いずれも、ユーザーが承認判断を委任した体制で、独立Opusレビューの合格を受けて記録しました。
- 承認済みの決定: A06(有限マナ)、A07(客用マナワープ)、A08(裏層の業務用ワープ)。
**P14-03「混雑と経路選択」**
- 正確候補は `83b170a` です。次の証拠がそろっています。
- 正式全回帰: 192/192 suite、22,198 checks、失敗0
- Root の別PID pair: 5/5、10 PID
- 代表性能 r02: 収集と機能検証は合格し、版間の比較が成立
- 独立Opusの whole-unit レビュー: PASS
- ただし skill 契約では、完了を確定するのは Runner です(試験・独立レビュー・最新mainとの統合・最終試験)。そのため Runner の正式ゲートが終わるまで加算0です。登録案と、既存証拠を結合する検証器は `artifacts/original-completion-2026-10-02/p14-03-runner-gate-r01/` にあります。
**未達として明記している性能**
- 代表負荷での1分 tick は平均約827 ms で、x1 の予算 4 ms を両版とも大きく超えています。
- x3 frame、stall、描画、Windows は未測定です。
**過去の回帰の訂正**: P06-01・P06-03・P14-02・P06-02 当時の回帰は Makefile 経由で、roster にしか載っていない46 suite を含んでいませんでした。その46 suite で見つかった回帰(v15保存の拒否など)は `83b170a` で修正済みで、正式192 suite の実行で全件合格を確認しました。各単位の完了記録には訂正注記を付けています。
**次の候補**: P28-01「現HEADの性能基準」です。描画とx3はheadlessの結果で代用せず、新たに測定します。P05-02・P22-03(仕様が未承認)とP02-03(Windows実機待ち)は保留ですが、作業全体は止めません。
以下の「現在」は各記録時点の履歴です。上記と現在の台帳を優先してください。
## 現在の対象(2026-10-19・P04-01正式完了/開発体制更新)
P04-01「同時発生の更新規約」は通常候補 `b1810ff4b2809018fe7434be7bdcf6f6411c91f4` で全条件・独立Opusレビュー・統合・最終検証を完了。元30パッケージ/88成果、部分点なしで正式17成果、完了2パッケージ。詳細は[正式受入証拠](../../../artifacts/original-completion-2026-10-02/p04-01-formal-closure-b1810ff4/ACCEPTANCE.json)と `work_packages.json` / `progress_snapshot.json` を参照。
@@ -33,6 +33,29 @@
"decision": "2×1・裏層。建築350G、資材4、工期60分、清掃員最低1人/上限2人、顧客0人・利用料なし、維持費2G/日。清潔0〜100・初期100、75以下で予約、現地8分で25回復。定義済み汚れ量を使い未定義値を補完しない。",
"origin": "user_reply",
"reference": "../original-completion-2026-09-29/execution/CLEANING_APPROVED_FOUNDATION.md"
},
{
"id": "A06",
"title": "マナ有限残量契約(MP-01-r02推薦案)",
"decision": "初期100・容量300・世界樹生成20/ゲーム内10分。10分境界ごとにB+G+F−Dを計算し、需要を先に支払い、超過は明示破棄、0で全館停止。需要は保有施設のmaintenance_mana合計(閉店・停止中も計上、撤去・破壊済みは除外)。境界間に返却等で容量を超えた分は次の境界でoverflowとして記録・破棄。炉の投入は自然生成と需要支払後のbase_after=min(C,max(0,B+G−D))で空き100以上のとき受理。現Runtimeのphase順序を保持しMANA内で処理。受入契約なしの旧セーブの残量は0〜300のみ保持し、超過・不正値は拒否。炉の人物適格性・収率の実接続は別承認。",
"origin": "user_reply_in_conversation",
"approved_at_jst": "2026-10-19",
"reference": "execution/mana-proposal/PROPOSAL.md"
},
{
"id": "A07",
"title": "マナワープの初期値(推薦案)",
"decision": "2x2・表層。建設3000G・資材30、工期360分、維持費15G/日、維持マナ1/10分。建設済みワープは全て相互接続。利用者は客と接客中の従業員。1人1回3マナを出発時に一回だけ差し引く。残量不足・停電・到着先不可のときは経路から除外し、費用と移動を発生させない。途中保存・再開で費用と移動を二重反映しない。",
"origin": "user_reply_in_conversation",
"approved_at_jst": "2026-10-20"
},
{
"id": "A08",
"title": "ワープの客用・業務用分離",
"decision": "表層のマナワープは客用とし、従業員の経路からは使わない。従業員用に裏層の業務用マナワープ(2x2・裏層)を別に設け、業務用同士だけを相互接続し従業員のみ利用する。業務用の建設費・工期・維持費・維持マナ・1人3マナの運賃はA07と同値。",
"origin": "user_reply_in_conversation「従業員用を裏層に別で作って」",
"approved_at_jst": "2026-10-20",
"values_note": "業務用の数値はユーザー指定がなくA07と同値を適用。"
}
],
"pending": [
@@ -3723,8 +3723,8 @@
"path": "docs/spec/acceptance/P08-03.json",
"scope": "normal placement; native and OS pending"
}
}
,{
},
{
"test": "tests/ui/test_p23_life_observation.gd",
"template": "P23 life observation: <checks> checks, <failures> failures",
"required": true,
@@ -3789,6 +3789,142 @@
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"scope": "new backend suite marker; native execution pending"
}
},
{
"test": "tests/mvp/test_whole_tower_outage.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "dd786e8c7448eeb77d51d7effd9100059ae6febf638ca2c20f3a55683009c9ea",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 41,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if _failures == 0 else \"FAIL\", _checks])"
}
]
},
{
"test": "tests/s2/test_mana_recovery_new_pid.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "8ef67859db2a31213585fa49dfc687ea69bf215c41c8d1d8cbb3f84d00dd5d17",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 26,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if _failures == 0 else \"FAIL\", _checks])"
}
]
},
{
"test": "tests/s2/test_mana_reserve_cycle.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "048d79e067cc85eef1c5c5f3e412198e652a2acc08e6d910e0761c7148a34cb6",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 64,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if failures == 0 else \"FAIL\", checks])"
}
]
},
{
"test": "tests/s2/test_mana_reserve_new_pid.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "9f42e4f7f5aac403ee4a6091e54ebf3995e25d11a450000e5a8ce870094f7a6b",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 26,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if _failures == 0 else \"FAIL\", _checks])"
}
]
},
{
"test": "tests/s2/test_runtime_mana_reserve.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "323750a533f2bbdf95b96b1615996cd3c4155bdadc6dcfb0936eaaa19a04809b",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 25,
"text": "\t\tprint(\"PASS: %d checks\" % _checks)"
}
]
},
{
"test": "tests/transport/test_route_wait_choice.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "c4db1db2e60f1a24fbbcb6c2c3706a7ee1534c7191f612e1d8df40d0a39a97bc",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 49,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if _failures == 0 else \"FAIL\", _checks])"
}
]
},
{
"test": "tests/transport/test_runtime_warp.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "cfbb69e63aca12d9d198393fd853c76be63df95e8d1e777e7a14194dbd181234",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new suite added with P06/P14 work; exact label/schema only, check count is not an expected future value"
},
"source_marker_lines": [
{
"line": 40,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if _failures == 0 else \"FAIL\", _checks])"
}
]
},
{
"test": "tests/s2/test_new_pid_pairs.gd",
"template": "PASS: <checks> checks",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "9742f9ac253067e6ae69a53faed054d71925f316d038ff7c5e480c3a9be91b04",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-03-route-wait/EVIDENCE_MATRIX.md",
"scope": "Claude session 2026-10-20: new-PID pair suite; exact label/schema only"
},
"source_marker_lines": [
{
"line": 45,
"text": "\tprint(\"%s: %d checks\" % [\"PASS\" if _failures == 0 else \"FAIL\", _checks])"
}
]
}
],
"unknown_roster_suite_policy": "refuse, explicitly review its source/schema before accepting",
@@ -0,0 +1,85 @@
{
"unit": "P06-01",
"title": "供給と蓄積の契約",
"candidate": "f247d19",
"base": "c366012",
"decision": "A06",
"status": "independent_review_pass_awaiting_owner_approval",
"acceptance": "初期値や係数の根拠を区別し、旧版移行と残量境界で矛盾がない。",
"cross_cutting": {
"原本条件とUI操作が一致": "HUDに残量/容量と生成・容量・停止条件を表示(scenes/main/main.gd)。原本は全館停止のみ規定し数値は承認値A06。",
"Runtimeの実利用・会計・行動へ接続": "MANA phaseで境界精算→局所配電→全館ゲート。",
"途中保存・再起動で再現": "test_mana_reserve_new_pid writer/reader別PIDで残量・receipt・全状態digest一致、旧0セーブ移行。",
"異常/境界/中断を検証": "同境界再送、逆行、境界飛ばし、境界間の容量超過→overflow、改ざん・旧版容量超過の原子的拒否、破壊施設除外、Operations巻き戻し。",
"関連回帰PASS": "142本中118 PASS。失敗24本は基準c366012でも同一終了コード(UI/audio owner cleanup、resources still in use、保存パッケージ残骸1件)でマナ起因なし。",
"要件別ログとソースハッシュを保存": "本ファイルのsource_sha256、regression-f247d19.log。",
"既存代表負荷の性能回帰を計測": "perf-r01.json:1日tick 1008→1014ms(+0.6%)、snapshot +1.5%、save差は誤差内。描画・Windowsは対象外。"
},
"reviews": [
{
"round": 1,
"candidate": "65534cf",
"verdict": "FAIL",
"blocking": [
"境界間のマナ増加で読込拒否/INVALID_FLOW latch",
"test_runtime_mana_depletion回帰",
"破壊済み施設の需要計上"
]
},
{
"round": 2,
"candidate": "f247d19",
"verdict": "PASS",
"blocking": [],
"non_blocking": [
"change_resourcesで10億超にすると境界でlatch(通常プレイ外)",
"reserve分が古い現行セーブは読込後に境界を順に追いつく(方針どおり)",
"HUDが境界間に容量超過値を表示",
"test_runtime_transportはaudio cleanup 1件のみ失敗(基準線と同種)"
]
}
],
"regression_failures_baseline_identical": [
"res://tests/mvp/test_amelia_donations.gd",
"res://tests/mvp/test_fine_cleaning_effect.gd",
"res://tests/s1/test_path_snapshot_transit_guard.gd",
"res://tests/supply/test_normal_auto_purchase_chain.gd",
"res://tests/supply/test_normal_supply_chain.gd",
"res://tests/transport/test_runtime_transport.gd",
"res://tests/ui/test_anri_recruitment.gd",
"res://tests/ui/test_chapel_gameplay.gd",
"res://tests/ui/test_dashboard_coalescing.gd",
"res://tests/ui/test_dimension_migration_ui.gd",
"res://tests/ui/test_first_operating_day.gd",
"res://tests/ui/test_guest_decision_log.gd",
"res://tests/ui/test_guest_observation.gd",
"res://tests/ui/test_layer_skin.gd",
"res://tests/ui/test_original_build_pointer.gd",
"res://tests/ui/test_rank_pointer.gd",
"res://tests/ui/test_staff_management.gd",
"res://tests/ui/test_staff_rescue.gd",
"res://tests/ui/test_staff_rest.gd",
"res://tests/ui/test_stair_transport_details.gd",
"res://tests/ui/test_supply_auto_purchase_ui.gd",
"res://tests/ui/test_upkeep_inspector.gd",
"res://tests/ui/test_world_tree_rank.gd",
"tests/ui/test_cleaning_gameplay.gd"
],
"source_sha256": {
"scripts/mana/mana_reserve_cycle.gd": "7d372d6e944765de5799803a4f5f60babf129741e6de30fe2452f133a4524d9a",
"scripts/mana/mana_network_service.gd": "3f28a9b291cc00efd1495a9adf11a37988ce13e8c8ace01a950fd0075b6d7950",
"autoload/simulation_runtime.gd": "22dae2e188ce4e099aad5cfcdcd2103c5ec979858740a7dbba46444153e066fa",
"scenes/main/main.gd": "bf45d29b3ea49147651097b783e1d6422a024a22f5422bb38aa1517677ab66ba",
"tests/helpers/mana_outage.gd": "8df68f67fd023fb3fed4c465acf8227094d0e9403efc1f56ae009685629563e1",
"tests/s2/test_mana_reserve_cycle.gd": "048d79e067cc85eef1c5c5f3e412198e652a2acc08e6d910e0761c7148a34cb6",
"tests/s2/test_runtime_mana_reserve.gd": "323750a533f2bbdf95b96b1615996cd3c4155bdadc6dcfb0936eaaa19a04809b",
"tests/s2/test_mana_reserve_new_pid.gd": "9f42e4f7f5aac403ee4a6091e54ebf3995e25d11a450000e5a8ce870094f7a6b"
},
"not_claimed": [
"炉の人物投入の実接続",
"未定義13施設の需要",
"D05詳細",
"全館の実プレイ・Windows実機",
"P06全体の完了"
]
}
@@ -0,0 +1,34 @@
# P06-01:A06 マナ有限残量契約の実装(2026-10-19)
ユーザーが MP-01-r02 推薦案を採用しました(decisions.json A06)。内容は初期100、容量300、世界樹の生成20/ゲーム内10分です。炉は、自然生成と需要の支払いを済ませた後に判定します。
## 製品への反映
- `scripts/mana/mana_reserve_cycle.gd`:承認値と境界処理です。10分境界ごとに `available=B+G+F`、`consumed=min(available,D)`、`after=min(C,available−consumed)` を計算します。容量を超えた分は overflow として記録し、破棄します。イベント費用の返却などで境界の間に容量を超えた場合も、次の境界で同じく処理します。同じ境界は二度処理しません。境界を飛ばした場合は、各境界を順番に処理します。保存データは検証が通ってから反映し、不正なら何も変えません。炉の受理判定は `furnace_offer_accepted`(base_after 後の空きが100以上)です。
- `scripts/mana/mana_network_service.gd`:`get_total_consumer_demand(excluded_ids)` を追加しました。登録済みの consumer の需要を合計します。無効化・停止中の consumer も含みます。Runtime の `_mana_reserve_demand()` が、破壊済み(DESTROYED)施設を除外して呼び出します。撤去済みの施設はネットワークから登録解除されます。
- `autoload/simulation_runtime.gd`:MANA phase の最初で残量を確定してから、局所配電と全館ゲートを評価します。phase の順序は変えていません。新しいセーブは `mana_reserve` を持ちます。Operations の巻き戻し対象にも含めました。
- 現行セーブは整数の残量を受け付けます。境界の間に容量を超えた値も読み込めます。
- 旧セーブの移行:`mana_reserve` が無いセーブは、残量が0〜300の整数であれば、その値を保持して開始します。明示的な0は停止のまま保持します。300超・負値・非整数は拒否し、現在の状態を保持します。
## 試験
- 新規:`tests/s2/test_mana_reserve_cycle.gd`(提案書の比較表の推薦列の値、炉判定の3例、改ざん拒否)、`tests/s2/test_runtime_mana_reserve.gd`(Runtimeでの境界処理、保存往復、旧0の移行、容量超過の拒否、枯渇と復帰)。
- 既存の停電試験は「マナを0にすれば停電が続く」前提でした。A06では世界樹が次の境界で復帰させるため、停電を継続させる試験だけ `tests/helpers/mana_outage.gd` に置き換えました。これは配電を受けない無効 consumer で需要を足す方法です。
## 未了
- 炉の人物適格性・収率の実接続、未定義13施設の需要、D05 の詳細は別承認です。
- 全館の実プレイ、性能、Windows での受入は未実施です。原88の正式完了数は変わりません。
## 独立レビュー r01 の指摘と修正
候補 65534cf への判定は FAIL でした。修正した内容は次のとおりです。
1. 境界の間にマナが増えた場合の不整合を直しました。以前は、読込を拒否するか、毎分 INVALID_FLOW を起こして全館が停止していました。現在は、次の境界で overflow として記録・破棄します。
2. `test_runtime_mana_depletion` は停電が続く前提でした。`ManaOutage` に置き換え、旧セーブも `mana_reserve` を外して作るようにしました。また、Makefile の test-mvp に追加しました。
3. 需要に破壊済みの施設が含まれていました。提案書の「撤去・破壊済みは除外」に合わせて除外し、A06 の記録文も同じ内容に訂正しました。
## 未検証として残す点
- 世界樹の生成を0にする経路が無いため、提案書の比較表にある「生成0→0→通常」は適用外です。
- 炉の receipt と配電投影の保存は、炉の実接続が別承認なので対象外です。
@@ -0,0 +1,78 @@
{
"probe": "perf_probe.gd",
"baseline_source": "c366012 (autoload/simulation_runtime.gd, scripts/mana/mana_network_service.gd swapped in place)",
"candidate_source": "working tree after ae0f998 + HUD change",
"runs": [
{
"side": "BASE",
"minutes": 1440,
"save_ms_avg": 18.752,
"save_ms_max": 20.915,
"snapshot_ms_avg": 0.38877,
"tick_day_ms_avg": 1005.434,
"tick_day_ms_max": 1022.47,
"trials": 5
},
{
"side": "CAND",
"minutes": 1440,
"save_ms_avg": 19.2478,
"save_ms_max": 21.626,
"snapshot_ms_avg": 0.39343,
"tick_day_ms_avg": 1013.9146,
"tick_day_ms_max": 1037.407,
"trials": 5
},
{
"side": "BASE",
"minutes": 1440,
"save_ms_avg": 19.9272,
"save_ms_max": 22.122,
"snapshot_ms_avg": 0.39169,
"tick_day_ms_avg": 1010.7658,
"tick_day_ms_max": 1021.417,
"trials": 5
},
{
"side": "CAND",
"minutes": 1440,
"save_ms_avg": 16.6394,
"save_ms_max": 20.276,
"snapshot_ms_avg": 0.39521,
"tick_day_ms_avg": 1016.2724,
"tick_day_ms_max": 1036.077,
"trials": 5
},
{
"side": "BASE",
"minutes": 1440,
"save_ms_avg": 18.8624,
"save_ms_max": 21.534,
"snapshot_ms_avg": 0.38799,
"tick_day_ms_avg": 1007.718,
"tick_day_ms_max": 1034.979,
"trials": 5
},
{
"side": "CAND",
"minutes": 1440,
"save_ms_avg": 15.2772,
"save_ms_max": 17.564,
"snapshot_ms_avg": 0.40309,
"tick_day_ms_avg": 1012.192,
"tick_day_ms_max": 1053.282,
"trials": 5
}
],
"base_mean": {
"tick_day_ms_avg": 1007.973,
"snapshot_ms_avg": 0.389,
"save_ms_avg": 19.181
},
"cand_mean": {
"tick_day_ms_avg": 1014.126,
"snapshot_ms_avg": 0.397,
"save_ms_avg": 17.055
},
"scope": "Ordinary new-game Runtime only, 1440 minutes x5 trials x3 runs, snapshot x20, disk save. Not rendering, Operations-heavy fixtures, or Windows."
}
@@ -0,0 +1,55 @@
extends SceneTree
## P06-01 A06 performance regression probe. Same script runs on the baseline
## and candidate checkouts; prints one JSON line. Measures ordinary Runtime
## minute ticks, full snapshots and disk saves; not rendering or Windows.
const TRIALS := 5
const MINUTES := 1440
const SNAPSHOTS := 20
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var tick_ms: Array = []
var snapshot_ms: Array = []
var save_ms: Array = []
for trial: int in TRIALS:
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()
runtime.initialize(clock, state, 5505 + trial)
clock.set_paused(true)
var start := Time.get_ticks_usec()
clock.advance_minutes(MINUTES)
tick_ms.append((Time.get_ticks_usec() - start) / 1000.0)
start = Time.get_ticks_usec()
var snapshot: Dictionary
for i: int in SNAPSHOTS:
snapshot = runtime.create_snapshot()
snapshot_ms.append((Time.get_ticks_usec() - start) / 1000.0 / SNAPSHOTS)
var path := "user://saves/p06_01_perf_probe_%d" % trial
start = Time.get_ticks_usec()
var saved: Dictionary = SaveService.save_snapshot(path, snapshot)
save_ms.append((Time.get_ticks_usec() - start) / 1000.0)
SaveService.delete_save(path)
if not saved[&"ok"]:
push_error("save failed")
runtime.free(); clock.free(); state.free()
print("P06_01_PERF=" + JSON.stringify({
"trials": TRIALS, "minutes": MINUTES,
"tick_day_ms_avg": _avg(tick_ms), "tick_day_ms_max": tick_ms.max(),
"snapshot_ms_avg": _avg(snapshot_ms), "save_ms_avg": _avg(save_ms), "save_ms_max": save_ms.max(),
}))
quit(0)
func _avg(values: Array) -> float:
var total := 0.0
for value: float in values:
total += value
return total / values.size()
@@ -0,0 +1 @@
uid://fstsv5yarw5v
@@ -0,0 +1,170 @@
PASS res://tests/run_tests.gd
PASS res://tests/s0/test_definition_registry.gd
PASS res://tests/s0/test_command_transaction.gd
PASS res://tests/s0/test_determinism.gd
PASS res://tests/s0/test_stable_id_generator.gd
PASS res://tests/s0/test_domain_events.gd
PASS res://tests/s0/test_runtime_integration.gd
PASS res://tests/s1/test_dimension_batch_save.gd
PASS res://tests/s1/test_facility_resize_preview.gd
PASS res://tests/s1/test_weighted_resize_runtime.gd
PASS res://tests/s1/test_original_facility_dimensions.gd
PASS res://tests/s1/test_world_service.gd
PASS res://tests/s1/test_path_service.gd
FAIL(1) res://tests/s1/test_path_snapshot_transit_guard.gd
ERROR: refusal creates no new temporary or backup package
PASS res://tests/s1/test_path_congestion.gd
PASS res://tests/s1/test_construction_service.gd
PASS res://tests/s1/test_excavation_service.gd
PASS res://tests/s1/test_spatial_subslot_service.gd
PASS res://tests/s1/test_route_subslot_path_adapter.gd
PASS res://tests/s1/test_facility_infrastructure_projector.gd
PASS res://tests/s1/test_runtime_infrastructure_integration.gd
PASS res://tests/s1/test_runtime_world_construction.gd
PASS tests/environment/test_cleaning_access.gd
FAIL(97) tests/ui/test_cleaning_gameplay.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 64508, &"owner_instance_id": 131617261207, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131617261207] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS tests/environment/test_runtime_cleanliness.gd
PASS res://tests/environment/test_facility_cleanliness.gd
PASS res://tests/s2/test_facility_upkeep_accrual.gd
PASS res://tests/s2/test_facility_upkeep_settlement.gd
PASS res://tests/s2/test_facility_service.gd
PASS res://tests/s2/test_service_start_slots.gd
PASS res://tests/s2/test_inventory_logistics.gd
PASS res://tests/s2/test_economy_service.gd
PASS res://tests/s2/test_ledger_backed_resources.gd
PASS res://tests/s2/test_mana_network_service.gd
PASS res://tests/s2/test_mana_reserve_cycle.gd
PASS res://tests/s2/test_runtime_mana_reserve.gd
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- writer
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- reader
PASS res://tests/s2/test_runtime_operations_cycle.gd
PASS res://tests/s3/test_runtime_staff_assignment.gd
PASS res://tests/s3/test_guest_service.gd
PASS res://tests/s3/test_staff_service.gd
PASS res://tests/s3/test_staff_payroll_operations.gd
PASS res://tests/s3/test_runtime_actor_cycle.gd
PASS res://tests/s3/test_runtime_actor_hardening.gd
PASS res://tests/s3/test_runtime_path_traffic.gd
PASS res://tests/s2/test_kitchen_production.gd
PASS res://tests/supply/test_supply_save_migration.gd
PASS res://tests/supply/test_supply_logistics_bridge.gd
PASS res://tests/supply/test_supply_management_service.gd
PASS res://tests/supply/test_supply_auto_purchase.gd
FAIL(1) res://tests/supply/test_normal_auto_purchase_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/supply/test_supply_auto_purchase_boundaries.gd
PASS res://tests/supply/test_supply_auto_purchase_destruction.gd
FAIL(1) res://tests/supply/test_normal_supply_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/s2/test_facility_pricing.gd
PASS res://tests/business/test_business_operations.gd
PASS res://tests/business/test_business_closure.gd
PASS res://tests/s4/test_relationship_event_service.gd
PASS res://tests/s4/test_placement_risk_preview_service.gd
PASS res://tests/s4/test_runtime_relationship_events.gd
PASS res://tests/s5/test_authority_service.gd
PASS res://tests/s5/test_defense_service.gd
PASS res://tests/s5/test_runtime_authority_cycle.gd
PASS res://tests/s5/test_runtime_defense_cycle.gd
PASS res://tests/s6/test_save_operations.gd
PASS res://tests/s6/test_save_preflight.gd
PASS res://tests/s6/test_save_recovery_preservation.gd
PASS res://tests/s6/test_runtime_snapshot_serialization.gd
PASS res://tests/s6/test_performance_budget.gd
PASS res://tests/s6/test_runtime_save_lifecycle.gd
PASS res://tests/mvp/test_premium_room_guest_flow.gd
PASS res://tests/mvp/test_runtime_mana_depletion.gd
PASS res://tests/mvp/test_premium_room.gd
PASS res://tests/mvp/test_original_room_zones.gd
PASS res://tests/mvp/test_upkeep_loss_streak.gd
PASS res://tests/mvp/test_upkeep_legacy_midnight.gd
PASS res://tests/mvp/test_runtime_upkeep.gd
PASS res://tests/mvp/test_upkeep_construction_boundaries.gd
PASS res://tests/mvp/test_operations_coordinator.gd
PASS res://tests/mvp/test_mvp_content_catalog.gd
PASS res://tests/mvp/test_progression_service.gd
PASS res://tests/mvp/test_runtime_content_progression.gd
PASS res://tests/mvp/test_runtime_operations_integration.gd
PASS res://tests/mvp/test_runtime_operations_acceptance.gd
PASS res://tests/mvp/test_chapel_boundaries.gd
FAIL(96) res://tests/ui/test_chapel_gameplay.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 69163, &"owner_instance_id": 179667207680, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [179667207680] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_chapel_service.gd
FAIL(96) res://tests/ui/test_dashboard_coalescing.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69190, &"owner_instance_id": 131315271307, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131315271307] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_anri_floor_pricing.gd
FAIL(97) res://tests/mvp/test_fine_cleaning_effect.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 69231, &"owner_instance_id": 132087023256, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132087023256] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/mvp/test_amelia_donations.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 69255, &"owner_instance_id": 180036306434, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [180036306434] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_anri_recruitment.gd
ERROR: Anri recruitment ordinary owner cleanup failed: { &"owned_engine_pid": 69276, &"owner_instance_id": 134754600590, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134754600590] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_layer_skin.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 1 resources still in use at exit (run with --verbose for details).
FAIL(96) res://tests/ui/test_world_tree_rank.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69339, &"owner_instance_id": 134721046155, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134721046155] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_rank_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69359, &"owner_instance_id": 134771377803, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134771377803] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_layer_presentation.gd
FAIL(96) res://tests/ui/test_original_build_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69392, &"owner_instance_id": 134704268951, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134704268951] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_dimension_migration_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69456, &"owner_instance_id": 164450272915, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [164450272915] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_upkeep_inspector.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69483, &"owner_instance_id": 131399157387, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131399157387] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rest.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69491, &"owner_instance_id": 131399157387, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131399157387] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rescue.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69507, &"owner_instance_id": 131583706763, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131583706763] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_observation.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69534, &"owner_instance_id": 131533375116, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131533375116] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_decision_log.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69549, &"owner_instance_id": 277310605252, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [277310605252] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_room_presentation.gd
PASS res://tests/ui/test_pixel_tower.gd
PASS res://tests/ui/test_main_dashboard.gd
FAIL(96) res://tests/ui/test_staff_management.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 2 resources still in use at exit (run with --verbose for details).
PASS res://tests/ui/test_supply_management.gd
FAIL(96) res://tests/ui/test_supply_auto_purchase_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69672, &"owner_instance_id": 134989481613, &"before": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134989481613] }, &"after": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_business_management.gd
PASS res://tests/ui/test_elevator_management.gd
FAIL(96) res://tests/ui/test_first_operating_day.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 69732, &"owner_instance_id": 134687491727, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134687491727] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/staff/test_dormitory_dimension_migration.gd
PASS res://tests/staff/test_staff_dormitory.gd
PASS res://tests/staff/test_dormitory_shift_cycle.gd
PASS res://tests/staff/test_shift_rush.gd
PASS res://tests/staff/test_staff_rest.gd
PASS res://tests/staff/test_rescue_elevator.gd
PASS res://tests/staff/test_staff_rescue.gd
PASS res://tests/staff/test_task_work_clock.gd
PASS res://tests/world/test_path_vertical_policy.gd
PASS res://tests/world/test_path_transit_density.gd
PASS res://tests/world/test_stair_infrastructure.gd
PASS res://tests/world/test_legacy_stairs.gd
PASS res://tests/transport/test_runtime_stairs.gd
FAIL(96) res://tests/ui/test_stair_transport_details.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 70072, &"owner_instance_id": 132154132118, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132154132118] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/world/test_elevator_topology.gd
PASS res://tests/transport/test_elevator_service.gd
PASS res://tests/staff/test_staff_commute.gd
PASS res://tests/transport/test_transport_save.gd
PASS res://tests/transport/test_transport_density_migration.gd
PASS res://tests/transport/test_transport_boundaries.gd
FAIL(1) res://tests/transport/test_runtime_transport.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/performance/test_facility_reachability.gd
PASS res://tests/performance/test_snapshot_ownership.gd
PASS res://tests/performance/test_world_snapshot_cache.gd
PASS res://tests/performance/test_lazy_digest.gd
PASS res://tests/performance/test_path_membership.gd
PASS res://tests/performance/test_system_optimization.gd
PASS res://tests/performance/test_digest_performance.gd
PASS res://tests/performance/test_perf_mvp_001.gd
DONE
@@ -0,0 +1,72 @@
{
"unit": "P06-02",
"title": "全館停止の統合",
"candidate": "f6f9c9c",
"followup_commit_test_only": "SERVICE_SALEイベント0の検査を追加(writer 45/reader 7 PASS)",
"status": "completed_delegated_approval",
"acceptance": "停電中の無条件売上・生産がなく、乗客と搬送対象が消えない。",
"evidence": "DOMAIN_MATRIX.md(7領域の共通停止判定と制御試験)+test_whole_tower_outage(需要23>生成20の自然枯渇、60分停止、別PID一致)",
"cross_cutting": {
"原本条件とUI操作が一致": "原本9.1全館停止。HUDの停止表示はP06-01/P06-03で受入済み。",
"Runtimeの実利用・会計・行動へ接続": "通常建設・自然営業・実雇用の塔で自然枯渇。",
"途中保存・再起動で再現": "停電中保存→別PID60分継続で台帳・全状態digest一致。",
"異常/境界/中断を検証": "reviewer probeで利用中・乗車中の瞬間に自然枯渇させる8条件と120分観測、10分境界越えの持続を確認。",
"関連回帰PASS": "149本中124 PASS、失敗24本は基準と同一。test_cleaning_gameplay/test_runtime_transportは終了処理のcleanupのみ失敗でゲーム検査は全PASS。",
"要件別ログとソースハッシュを保存": "本ファイル・regression-f6f9c9c.log。",
"既存代表負荷の性能回帰を計測": "本単位の製品コード変更なし(試験と記録のみ)。直前のP14-02計測を継承。"
},
"reviews": [
{
"round": 1,
"candidate": "f6f9c9c",
"verdict": "PASS",
"blocking": [],
"non_blocking": [
"統合試験のrevenue検査は即時掃き出しで常に0、cash<=beforeは賃金で弱い、乗車trip検査は該当0件で空振り、meals/raw_food 0とワープ利用0(生産停止は厨房制御試験が担保)→SERVICE_SALE 0検査を追加",
"TIME_BOUNDARIESがMANAより先のため、残量0に精算される当該分の到着判定は精算前残量で行われ得る(probeで2名到着、売上なしで退館)。境界端として記録",
"停止籠の待ち客・緊急降車客は30分stuck後PATH_RECOVERY→LEAVINGで上階でdespawnする既存仕組み。停電が消すのではないが非主張として明記",
"清掃・運営サイクル試験は持続helper未使用(取消は終端状態で結論不変)",
"EV/ワープはFacilityInstanceでないため全施設停止の検査に含まれない(判定コードと制御試験で確認)"
]
}
],
"not_claimed": [
"清掃対象施設の電力判定、医務室のマナ消費者登録、直接spawn_guestの電力判定(監査で根拠未確定、追加しない)",
"上階で停止した客のstuck退館の挙動変更",
"Windows実機"
],
"regression_failures_baseline_identical": [
"res://tests/mvp/test_amelia_donations.gd",
"res://tests/mvp/test_fine_cleaning_effect.gd",
"res://tests/s1/test_path_snapshot_transit_guard.gd",
"res://tests/supply/test_normal_auto_purchase_chain.gd",
"res://tests/supply/test_normal_supply_chain.gd",
"res://tests/transport/test_runtime_transport.gd",
"res://tests/ui/test_anri_recruitment.gd",
"res://tests/ui/test_chapel_gameplay.gd",
"res://tests/ui/test_dashboard_coalescing.gd",
"res://tests/ui/test_dimension_migration_ui.gd",
"res://tests/ui/test_first_operating_day.gd",
"res://tests/ui/test_guest_decision_log.gd",
"res://tests/ui/test_guest_observation.gd",
"res://tests/ui/test_layer_skin.gd",
"res://tests/ui/test_original_build_pointer.gd",
"res://tests/ui/test_rank_pointer.gd",
"res://tests/ui/test_staff_management.gd",
"res://tests/ui/test_staff_rescue.gd",
"res://tests/ui/test_staff_rest.gd",
"res://tests/ui/test_stair_transport_details.gd",
"res://tests/ui/test_supply_auto_purchase_ui.gd",
"res://tests/ui/test_upkeep_inspector.gd",
"res://tests/ui/test_world_tree_rank.gd",
"tests/ui/test_cleaning_gameplay.gd"
],
"source_sha256": {
"tests/mvp/test_whole_tower_outage.gd": "dd786e8c7448eeb77d51d7effd9100059ae6febf638ca2c20f3a55683009c9ea",
"scripts/mana/mana_power_projection.gd": "2026467960e857349bcb18fb97b7753189be5f2de2be91a17e73e90146eba69e",
"scripts/mana/mana_reserve_cycle.gd": "7d372d6e944765de5799803a4f5f60babf129741e6de30fe2452f133a4524d9a",
"scripts/transport/warp_service.gd": "7602c6b8a9672a703bfa98a1424c2cf68cf50184f87f72349d564af6a5ca9d41",
"autoload/simulation_runtime.gd": "68d03872a591955740346a894fa4139cea75ed264428d61ade181532ea398b41",
"docs/plans/original-completion-2026-10-02/execution/p06-02-whole-stop/DOMAIN_MATRIX.md": "47e735f72ddef95b1aa15e09ed0c7ad608c49a00c79a5d5afea7bc5ab9f2f282"
}
}
@@ -0,0 +1,33 @@
# P06-02 全館停止の統合:領域別の証拠(候補 f6f9c9c)
受入条件は「停電中に無条件の売上・生産がなく、乗客と搬送対象が消えない」です。停止判定はどの領域も共通で、同じ連鎖を通ります。A06 の有限残量が0になる → `mana_power_projection`(`reserve > 0` かつ局所配電)→ 各施設の `power_available` → 各領域の停止。ワープ(A07/A08)は同じ残量と各ワープの給電状態を毎分 connector に反映します。
| 領域 | 停止の判定 | 証拠 |
|---|---|---|
| 利用中サービス | 施設が NO_POWER になると、実行中のサービスを PAUSED にする。時間を進めず、課金しない | `test_runtime_operations_cycle`(停電中は一時停止、復帰後に一回だけ課金)、`test_premium_room_guest_flow`(宿泊、持続停電、ディスク保存)、`test_whole_tower_outage`(自然停電の60分間、収入・財布・売上が不変) |
| EV | 給電が無いと籠は非稼働。乗車中の客は有効な階で緊急降車させ、安全な階が無ければ保持する | `test_runtime_transport`(緊急降車、降車不能時の保持を持続停電で確認)、`test_whole_tower_outage`(停電中の新規乗車0、残るのは保持中の乗車だけ) |
| ワープ | 残量3未満、停電、片側の未給電、到着先の封鎖のいずれかで経路から除外。費用も移動も発生しない | `test_runtime_warp`(各条件と、別PIDでの二重反映なし)、`test_whole_tower_outage`(停電中のワープ移動0) |
| 物流 | 両端の施設が非稼働なら引渡しを止める。荷は保持する | `test_supply_logistics_bridge::_test_reserve_outage`(持続停電30分、荷を保持、復旧後に一回だけ配達) |
| 生産(厨房) | NO_POWER の間は批(batch)を保持し、投入も生成もしない | `test_supply_logistics_bridge::_test_kitchen_reserve_outage`(持続停電、批の同一性と予約を保持、生成0) |
| 救護 | 医務室が OPERATING でなければ治療しない。救助の2人組は一緒に降ろす | `test_rescue_elevator`(全館停止で2人とも有効な階へ、停止中は治療されない、保存の完全一致、持続停電) |
| 清掃 | 清掃員室が非稼働なら作業を取り消す。回復はさせない | `test_cleaning_gameplay`(停電で清掃を止め、回復させない。保存も復元される) |
| 入館 | 残量0の間、到着の受入数を0にする | `test_runtime_mana_depletion`(停電中は受入数0)、`test_whole_tower_outage`(自然停電の60分間、新規到着0) |
## 自然停電の統合試験
`test_whole_tower_outage` は通常の操作だけで塔を作ります。客用EV・受付・客室・食堂+厨房・ワープ2基・按摩室2室・倉庫・警備員詰所で、自然営業を有効にしています。維持需要は23で、世界樹の生成20を上回るため、残量が自然に0へ落ちます。
停電中の60分間、次を確認しました。
- 全施設が停止する
- 売上・収入・残っている客の財布が動かない
- 食事と食材が増えも減りもしない
- 新規の到着、ワープ移動、EV への乗車がいずれも0
- 客は塔に残るか、通常の退店で出ていくだけ
さらに、停電中に保存し、別PIDで60分続けた結果が writer と完全に一致しました。
## 適用範囲と既知の制約
- 統合試験の塔には在庫・物流・救護・清掃の作業がありません。これらの領域は、上の表の制御試験(持続停電の helper を使用)で確認しています。
- 清掃と救護には別の論点が残っています。清掃は対象施設の電力を停止判定に含めるか、医務室は電力消費者として登録すべきか、という点です。どちらも P06-02 監査で「根拠未確定」とされたままで、新しい判定は追加していません。
- 直接 `spawn_guest` コマンドで客を出す経路には、電力の判定がありません。通常の到着は残量で止まります。監査の方針(判定を追加しない)に従っています。
@@ -0,0 +1,176 @@
PASS res://tests/run_tests.gd
PASS res://tests/s0/test_definition_registry.gd
PASS res://tests/s0/test_command_transaction.gd
PASS res://tests/s0/test_determinism.gd
PASS res://tests/s0/test_stable_id_generator.gd
PASS res://tests/s0/test_domain_events.gd
PASS res://tests/s0/test_runtime_integration.gd
PASS res://tests/s1/test_dimension_batch_save.gd
PASS res://tests/s1/test_facility_resize_preview.gd
PASS res://tests/s1/test_weighted_resize_runtime.gd
PASS res://tests/s1/test_original_facility_dimensions.gd
PASS res://tests/s1/test_world_service.gd
PASS res://tests/s1/test_path_service.gd
FAIL(1) res://tests/s1/test_path_snapshot_transit_guard.gd
ERROR: refusal creates no new temporary or backup package
PASS res://tests/s1/test_path_congestion.gd
PASS res://tests/s1/test_construction_service.gd
PASS res://tests/s1/test_excavation_service.gd
PASS res://tests/s1/test_spatial_subslot_service.gd
PASS res://tests/s1/test_route_subslot_path_adapter.gd
PASS res://tests/s1/test_facility_infrastructure_projector.gd
PASS res://tests/s1/test_runtime_infrastructure_integration.gd
PASS res://tests/s1/test_runtime_world_construction.gd
PASS tests/environment/test_cleaning_access.gd
FAIL(97) tests/ui/test_cleaning_gameplay.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 45540, &"owner_instance_id": 132691003032, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132691003032] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS tests/environment/test_runtime_cleanliness.gd
PASS res://tests/environment/test_facility_cleanliness.gd
PASS res://tests/s2/test_facility_upkeep_accrual.gd
PASS res://tests/s2/test_facility_upkeep_settlement.gd
PASS res://tests/s2/test_facility_service.gd
PASS res://tests/s2/test_service_start_slots.gd
PASS res://tests/s2/test_inventory_logistics.gd
PASS res://tests/s2/test_economy_service.gd
PASS res://tests/s2/test_ledger_backed_resources.gd
PASS res://tests/s2/test_mana_network_service.gd
PASS res://tests/s2/test_mana_reserve_cycle.gd
PASS res://tests/s2/test_runtime_mana_reserve.gd
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- writer
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- reader
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- writer
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- reader
PASS res://tests/s2/test_runtime_operations_cycle.gd
PASS res://tests/s3/test_runtime_staff_assignment.gd
PASS res://tests/s3/test_guest_service.gd
PASS res://tests/s3/test_staff_service.gd
PASS res://tests/s3/test_staff_payroll_operations.gd
PASS res://tests/s3/test_runtime_actor_cycle.gd
PASS res://tests/s3/test_runtime_actor_hardening.gd
PASS res://tests/s3/test_runtime_path_traffic.gd
PASS res://tests/s2/test_kitchen_production.gd
PASS res://tests/supply/test_supply_save_migration.gd
PASS res://tests/supply/test_supply_logistics_bridge.gd
PASS res://tests/supply/test_supply_management_service.gd
PASS res://tests/supply/test_supply_auto_purchase.gd
FAIL(1) res://tests/supply/test_normal_auto_purchase_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/supply/test_supply_auto_purchase_boundaries.gd
PASS res://tests/supply/test_supply_auto_purchase_destruction.gd
FAIL(1) res://tests/supply/test_normal_supply_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/s2/test_facility_pricing.gd
PASS res://tests/business/test_business_operations.gd
PASS res://tests/business/test_business_closure.gd
PASS res://tests/s4/test_relationship_event_service.gd
PASS res://tests/s4/test_placement_risk_preview_service.gd
PASS res://tests/s4/test_runtime_relationship_events.gd
PASS res://tests/s5/test_authority_service.gd
PASS res://tests/s5/test_defense_service.gd
PASS res://tests/s5/test_runtime_authority_cycle.gd
PASS res://tests/s5/test_runtime_defense_cycle.gd
PASS res://tests/s6/test_save_operations.gd
PASS res://tests/s6/test_save_preflight.gd
PASS res://tests/s6/test_save_recovery_preservation.gd
PASS res://tests/s6/test_runtime_snapshot_serialization.gd
PASS res://tests/s6/test_performance_budget.gd
PASS res://tests/s6/test_runtime_save_lifecycle.gd
PASS res://tests/mvp/test_premium_room_guest_flow.gd
PASS res://tests/mvp/test_runtime_mana_depletion.gd
PASS res://tests/mvp/test_whole_tower_outage.gd -- writer
PASS res://tests/mvp/test_whole_tower_outage.gd -- reader
PASS res://tests/mvp/test_premium_room.gd
PASS res://tests/mvp/test_original_room_zones.gd
PASS res://tests/mvp/test_upkeep_loss_streak.gd
PASS res://tests/mvp/test_upkeep_legacy_midnight.gd
PASS res://tests/mvp/test_runtime_upkeep.gd
PASS res://tests/mvp/test_upkeep_construction_boundaries.gd
PASS res://tests/mvp/test_operations_coordinator.gd
PASS res://tests/mvp/test_mvp_content_catalog.gd
PASS res://tests/mvp/test_progression_service.gd
PASS res://tests/mvp/test_runtime_content_progression.gd
PASS res://tests/mvp/test_runtime_operations_integration.gd
PASS res://tests/mvp/test_runtime_operations_acceptance.gd
PASS res://tests/mvp/test_chapel_boundaries.gd
FAIL(96) res://tests/ui/test_chapel_gameplay.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 50424, &"owner_instance_id": 180740949505, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [180740949505] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_chapel_service.gd
FAIL(96) res://tests/ui/test_dashboard_coalescing.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50457, &"owner_instance_id": 132389013132, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132389013132] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_anri_floor_pricing.gd
FAIL(97) res://tests/mvp/test_fine_cleaning_effect.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 50497, &"owner_instance_id": 133160765081, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [133160765081] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/mvp/test_amelia_donations.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 50522, &"owner_instance_id": 181110048259, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [181110048259] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_anri_recruitment.gd
ERROR: Anri recruitment ordinary owner cleanup failed: { &"owned_engine_pid": 50550, &"owner_instance_id": 135828342415, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135828342415] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_layer_skin.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 1 resources still in use at exit (run with --verbose for details).
FAIL(96) res://tests/ui/test_world_tree_rank.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50598, &"owner_instance_id": 135794787980, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135794787980] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_rank_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50614, &"owner_instance_id": 135845119628, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135845119628] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_layer_presentation.gd
FAIL(96) res://tests/ui/test_original_build_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50654, &"owner_instance_id": 135778010776, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135778010776] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_dimension_migration_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50712, &"owner_instance_id": 165524014740, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [165524014740] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_upkeep_inspector.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50737, &"owner_instance_id": 132472899212, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132472899212] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rest.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50751, &"owner_instance_id": 132472899212, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132472899212] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rescue.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50777, &"owner_instance_id": 132657448588, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132657448588] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_observation.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50798, &"owner_instance_id": 132607116941, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132607116941] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_decision_log.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50807, &"owner_instance_id": 278384347081, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [278384347081] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_room_presentation.gd
PASS res://tests/ui/test_pixel_tower.gd
PASS res://tests/ui/test_main_dashboard.gd
FAIL(96) res://tests/ui/test_staff_management.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 2 resources still in use at exit (run with --verbose for details).
PASS res://tests/ui/test_supply_management.gd
FAIL(96) res://tests/ui/test_supply_auto_purchase_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50934, &"owner_instance_id": 136063223438, &"before": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [136063223438] }, &"after": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_business_management.gd
PASS res://tests/ui/test_elevator_management.gd
FAIL(96) res://tests/ui/test_first_operating_day.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 50998, &"owner_instance_id": 135761233552, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135761233552] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/staff/test_dormitory_dimension_migration.gd
PASS res://tests/staff/test_staff_dormitory.gd
PASS res://tests/staff/test_dormitory_shift_cycle.gd
PASS res://tests/staff/test_shift_rush.gd
PASS res://tests/staff/test_staff_rest.gd
PASS res://tests/staff/test_rescue_elevator.gd
PASS res://tests/staff/test_staff_rescue.gd
PASS res://tests/staff/test_task_work_clock.gd
PASS res://tests/world/test_path_vertical_policy.gd
PASS res://tests/world/test_path_transit_density.gd
PASS res://tests/world/test_stair_infrastructure.gd
PASS res://tests/world/test_legacy_stairs.gd
PASS res://tests/transport/test_runtime_stairs.gd
FAIL(96) res://tests/ui/test_stair_transport_details.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 51379, &"owner_instance_id": 133227873943, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [133227873943] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/world/test_elevator_topology.gd
PASS res://tests/transport/test_elevator_service.gd
PASS res://tests/staff/test_staff_commute.gd
PASS res://tests/transport/test_transport_save.gd
PASS res://tests/transport/test_transport_density_migration.gd
PASS res://tests/transport/test_transport_boundaries.gd
FAIL(1) res://tests/transport/test_runtime_transport.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/transport/test_runtime_warp.gd -- writer
PASS res://tests/transport/test_runtime_warp.gd -- reader
PASS res://tests/performance/test_facility_reachability.gd
PASS res://tests/performance/test_snapshot_ownership.gd
PASS res://tests/performance/test_world_snapshot_cache.gd
PASS res://tests/performance/test_lazy_digest.gd
PASS res://tests/performance/test_path_membership.gd
PASS res://tests/performance/test_system_optimization.gd
PASS res://tests/performance/test_digest_performance.gd
PASS res://tests/performance/test_perf_mvp_001.gd
DONE
@@ -0,0 +1,74 @@
{
"unit": "P06-03",
"title": "復帰と表示",
"candidate": "826ef60",
"depends_on": "P06-01 f247d19 (A06)",
"status": "independent_review_pass_awaiting_owner_approval",
"acceptance": "破壊・摘発の休止を停電復旧で解除しない。途中保存後も復帰結果が一致する。",
"cross_cutting": {
"原本条件とUI操作が一致": "原本9.1の枯渇時全館停止。HUDにマナ残量/容量・停止表示、ツールチップに供給+20/10分・消費・収支・蓄積・直近の不足/破棄、休止は解除されない旨を表示。",
"Runtimeの実利用・会計・行動へ接続": "get_mana_reserve_report()はA06の実Runtime値(_mana_reserve_demand、last_flow)を返す。復帰後の搬送・調理・EV・救護・接客の再開と一回請求は既存試験(supply_logistics_bridge、rescue_elevator、runtime_transport、runtime_operations_cycle、premium_room_guest_flow)で、持続停電中に検証。",
"途中保存・再起動で再現": "test_mana_recovery_new_pid:停電中の保存を別PIDで読み、同じ復帰後に全状態digestと施設状態が一致。",
"異常/境界/中断を検証": "DESTROYED/RAIDEDが復帰後も保持。reviewerが600分停電+4320分経過でも保持を確認。digestは1分差・未復帰で不一致となり比較が自明でないことを確認。runtime無しでもHUDは固定文言で動作。",
"関連回帰PASS": "144本中120 PASS。失敗24本はc366012基準と同一の既知失敗(UI/audio cleanup等)。",
"要件別ログとソースハッシュを保存": "本ファイルのsource_sha256、regression-826ef60.log。",
"既存代表負荷の性能回帰を計測": "Runtime tickの変更なし。追加はsnapshot公開ごとのHUD報告1回:2.84µs/回(1分tick 794µsの0.36%、施設1件)。施設数に比例。描画・Windowsは対象外。"
},
"reviews": [
{
"round": 1,
"candidate": "826ef60",
"verdict": "PASS",
"blocking": [],
"non_blocking": [
"HUD供給に炉受入量(未接続)を含まない",
"収支の負号がASCII「-」、消費は全角「−」",
"新PID試験はreceptionがINACTIVEに留まる理由を検証しない(運行再開は既存試験に依存)",
"dashboard試験は部分一致のみ",
"ログ・ハッシュ・性能証跡は受入記録で別途用意(本ファイル)"
]
}
],
"regression_failures_baseline_identical": [
"res://tests/mvp/test_amelia_donations.gd",
"res://tests/mvp/test_fine_cleaning_effect.gd",
"res://tests/s1/test_path_snapshot_transit_guard.gd",
"res://tests/supply/test_normal_auto_purchase_chain.gd",
"res://tests/supply/test_normal_supply_chain.gd",
"res://tests/transport/test_runtime_transport.gd",
"res://tests/ui/test_anri_recruitment.gd",
"res://tests/ui/test_chapel_gameplay.gd",
"res://tests/ui/test_dashboard_coalescing.gd",
"res://tests/ui/test_dimension_migration_ui.gd",
"res://tests/ui/test_first_operating_day.gd",
"res://tests/ui/test_guest_decision_log.gd",
"res://tests/ui/test_guest_observation.gd",
"res://tests/ui/test_layer_skin.gd",
"res://tests/ui/test_original_build_pointer.gd",
"res://tests/ui/test_rank_pointer.gd",
"res://tests/ui/test_staff_management.gd",
"res://tests/ui/test_staff_rescue.gd",
"res://tests/ui/test_staff_rest.gd",
"res://tests/ui/test_stair_transport_details.gd",
"res://tests/ui/test_supply_auto_purchase_ui.gd",
"res://tests/ui/test_upkeep_inspector.gd",
"res://tests/ui/test_world_tree_rank.gd",
"tests/ui/test_cleaning_gameplay.gd"
],
"source_sha256": {
"autoload/simulation_runtime.gd": "5a23418002cad5bde1f1db847b49b8c953c7b9d16a61c749415e2a41162902c1",
"scenes/main/main.gd": "64142faf89ced6a8aedfedbf5642d830628d3ce003a3670507ba8b82bead2fa2",
"scripts/mana/mana_power_projection.gd": "2026467960e857349bcb18fb97b7753189be5f2de2be91a17e73e90146eba69e",
"scripts/facility/facility_instance.gd": "0c6aa493f3299611e05dd26aa429dda8cf7b5c479e4d09632036fb862f79a324",
"scripts/facility/facility_service.gd": "ceb4a3e9224587423f273cdb2b56e6843ab176ac1fc4fe79dd498b5ed5c33b77",
"tests/s2/test_mana_recovery_new_pid.gd": "8ef67859db2a31213585fa49dfc687ea69bf215c41c8d1d8cbb3f84d00dd5d17",
"tests/ui/test_main_dashboard.gd": "793e23077fc7e2d9c6112c8847c4ee0fd92d5c00037bf753bd05d9888b3ffcfe",
"tests/helpers/mana_outage.gd": "8df68f67fd023fb3fed4c465acf8227094d0e9403efc1f56ae009685629563e1"
},
"not_claimed": [
"P06-02(ワープ未実装)",
"P06全体",
"炉の実接続",
"Windows実機・全館実プレイ"
]
}
@@ -0,0 +1,172 @@
PASS res://tests/run_tests.gd
PASS res://tests/s0/test_definition_registry.gd
PASS res://tests/s0/test_command_transaction.gd
PASS res://tests/s0/test_determinism.gd
PASS res://tests/s0/test_stable_id_generator.gd
PASS res://tests/s0/test_domain_events.gd
PASS res://tests/s0/test_runtime_integration.gd
PASS res://tests/s1/test_dimension_batch_save.gd
PASS res://tests/s1/test_facility_resize_preview.gd
PASS res://tests/s1/test_weighted_resize_runtime.gd
PASS res://tests/s1/test_original_facility_dimensions.gd
PASS res://tests/s1/test_world_service.gd
PASS res://tests/s1/test_path_service.gd
FAIL(1) res://tests/s1/test_path_snapshot_transit_guard.gd
ERROR: refusal creates no new temporary or backup package
PASS res://tests/s1/test_path_congestion.gd
PASS res://tests/s1/test_construction_service.gd
PASS res://tests/s1/test_excavation_service.gd
PASS res://tests/s1/test_spatial_subslot_service.gd
PASS res://tests/s1/test_route_subslot_path_adapter.gd
PASS res://tests/s1/test_facility_infrastructure_projector.gd
PASS res://tests/s1/test_runtime_infrastructure_integration.gd
PASS res://tests/s1/test_runtime_world_construction.gd
PASS tests/environment/test_cleaning_access.gd
FAIL(97) tests/ui/test_cleaning_gameplay.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 16049, &"owner_instance_id": 131617261207, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131617261207] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS tests/environment/test_runtime_cleanliness.gd
PASS res://tests/environment/test_facility_cleanliness.gd
PASS res://tests/s2/test_facility_upkeep_accrual.gd
PASS res://tests/s2/test_facility_upkeep_settlement.gd
PASS res://tests/s2/test_facility_service.gd
PASS res://tests/s2/test_service_start_slots.gd
PASS res://tests/s2/test_inventory_logistics.gd
PASS res://tests/s2/test_economy_service.gd
PASS res://tests/s2/test_ledger_backed_resources.gd
PASS res://tests/s2/test_mana_network_service.gd
PASS res://tests/s2/test_mana_reserve_cycle.gd
PASS res://tests/s2/test_runtime_mana_reserve.gd
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- writer
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- reader
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- writer
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- reader
PASS res://tests/s2/test_runtime_operations_cycle.gd
PASS res://tests/s3/test_runtime_staff_assignment.gd
PASS res://tests/s3/test_guest_service.gd
PASS res://tests/s3/test_staff_service.gd
PASS res://tests/s3/test_staff_payroll_operations.gd
PASS res://tests/s3/test_runtime_actor_cycle.gd
PASS res://tests/s3/test_runtime_actor_hardening.gd
PASS res://tests/s3/test_runtime_path_traffic.gd
PASS res://tests/s2/test_kitchen_production.gd
PASS res://tests/supply/test_supply_save_migration.gd
PASS res://tests/supply/test_supply_logistics_bridge.gd
PASS res://tests/supply/test_supply_management_service.gd
PASS res://tests/supply/test_supply_auto_purchase.gd
FAIL(1) res://tests/supply/test_normal_auto_purchase_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/supply/test_supply_auto_purchase_boundaries.gd
PASS res://tests/supply/test_supply_auto_purchase_destruction.gd
FAIL(1) res://tests/supply/test_normal_supply_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/s2/test_facility_pricing.gd
PASS res://tests/business/test_business_operations.gd
PASS res://tests/business/test_business_closure.gd
PASS res://tests/s4/test_relationship_event_service.gd
PASS res://tests/s4/test_placement_risk_preview_service.gd
PASS res://tests/s4/test_runtime_relationship_events.gd
PASS res://tests/s5/test_authority_service.gd
PASS res://tests/s5/test_defense_service.gd
PASS res://tests/s5/test_runtime_authority_cycle.gd
PASS res://tests/s5/test_runtime_defense_cycle.gd
PASS res://tests/s6/test_save_operations.gd
PASS res://tests/s6/test_save_preflight.gd
PASS res://tests/s6/test_save_recovery_preservation.gd
PASS res://tests/s6/test_runtime_snapshot_serialization.gd
PASS res://tests/s6/test_performance_budget.gd
PASS res://tests/s6/test_runtime_save_lifecycle.gd
PASS res://tests/mvp/test_premium_room_guest_flow.gd
PASS res://tests/mvp/test_runtime_mana_depletion.gd
PASS res://tests/mvp/test_premium_room.gd
PASS res://tests/mvp/test_original_room_zones.gd
PASS res://tests/mvp/test_upkeep_loss_streak.gd
PASS res://tests/mvp/test_upkeep_legacy_midnight.gd
PASS res://tests/mvp/test_runtime_upkeep.gd
PASS res://tests/mvp/test_upkeep_construction_boundaries.gd
PASS res://tests/mvp/test_operations_coordinator.gd
PASS res://tests/mvp/test_mvp_content_catalog.gd
PASS res://tests/mvp/test_progression_service.gd
PASS res://tests/mvp/test_runtime_content_progression.gd
PASS res://tests/mvp/test_runtime_operations_integration.gd
PASS res://tests/mvp/test_runtime_operations_acceptance.gd
PASS res://tests/mvp/test_chapel_boundaries.gd
FAIL(96) res://tests/ui/test_chapel_gameplay.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 20818, &"owner_instance_id": 179667207680, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [179667207680] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_chapel_service.gd
FAIL(96) res://tests/ui/test_dashboard_coalescing.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20847, &"owner_instance_id": 131315271307, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131315271307] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_anri_floor_pricing.gd
FAIL(97) res://tests/mvp/test_fine_cleaning_effect.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 20887, &"owner_instance_id": 132087023256, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132087023256] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/mvp/test_amelia_donations.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 20914, &"owner_instance_id": 180036306434, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [180036306434] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_anri_recruitment.gd
ERROR: Anri recruitment ordinary owner cleanup failed: { &"owned_engine_pid": 20933, &"owner_instance_id": 134754600590, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134754600590] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_layer_skin.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 1 resources still in use at exit (run with --verbose for details).
FAIL(96) res://tests/ui/test_world_tree_rank.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20985, &"owner_instance_id": 134721046155, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134721046155] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_rank_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21004, &"owner_instance_id": 134771377803, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134771377803] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_layer_presentation.gd
FAIL(96) res://tests/ui/test_original_build_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21034, &"owner_instance_id": 134704268951, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134704268951] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_dimension_migration_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21103, &"owner_instance_id": 164450272915, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [164450272915] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_upkeep_inspector.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21110, &"owner_instance_id": 131399157387, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131399157387] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rest.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21137, &"owner_instance_id": 131399157387, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131399157387] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rescue.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21154, &"owner_instance_id": 131583706763, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131583706763] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_observation.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21181, &"owner_instance_id": 131533375116, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [131533375116] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_decision_log.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21189, &"owner_instance_id": 277310605252, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [277310605252] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_room_presentation.gd
PASS res://tests/ui/test_pixel_tower.gd
PASS res://tests/ui/test_main_dashboard.gd
FAIL(96) res://tests/ui/test_staff_management.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 2 resources still in use at exit (run with --verbose for details).
PASS res://tests/ui/test_supply_management.gd
FAIL(96) res://tests/ui/test_supply_auto_purchase_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21314, &"owner_instance_id": 134989481613, &"before": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134989481613] }, &"after": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_business_management.gd
PASS res://tests/ui/test_elevator_management.gd
FAIL(96) res://tests/ui/test_first_operating_day.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21381, &"owner_instance_id": 134687491727, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [134687491727] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/staff/test_dormitory_dimension_migration.gd
PASS res://tests/staff/test_staff_dormitory.gd
PASS res://tests/staff/test_dormitory_shift_cycle.gd
PASS res://tests/staff/test_shift_rush.gd
PASS res://tests/staff/test_staff_rest.gd
PASS res://tests/staff/test_rescue_elevator.gd
PASS res://tests/staff/test_staff_rescue.gd
PASS res://tests/staff/test_task_work_clock.gd
PASS res://tests/world/test_path_vertical_policy.gd
PASS res://tests/world/test_path_transit_density.gd
PASS res://tests/world/test_stair_infrastructure.gd
PASS res://tests/world/test_legacy_stairs.gd
PASS res://tests/transport/test_runtime_stairs.gd
FAIL(96) res://tests/ui/test_stair_transport_details.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 21756, &"owner_instance_id": 132154132118, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132154132118] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/world/test_elevator_topology.gd
PASS res://tests/transport/test_elevator_service.gd
PASS res://tests/staff/test_staff_commute.gd
PASS res://tests/transport/test_transport_save.gd
PASS res://tests/transport/test_transport_density_migration.gd
PASS res://tests/transport/test_transport_boundaries.gd
FAIL(1) res://tests/transport/test_runtime_transport.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/performance/test_facility_reachability.gd
PASS res://tests/performance/test_snapshot_ownership.gd
PASS res://tests/performance/test_world_snapshot_cache.gd
PASS res://tests/performance/test_lazy_digest.gd
PASS res://tests/performance/test_path_membership.gd
PASS res://tests/performance/test_system_optimization.gd
PASS res://tests/performance/test_digest_performance.gd
PASS res://tests/performance/test_perf_mvp_001.gd
DONE
@@ -0,0 +1,19 @@
extends SceneTree
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
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(); runtime.initialize(clock, state, 7707); clock.set_paused(true)
runtime.submit_command(&"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(-6, 0, 0)})
clock.advance_minutes(180)
var n := 2000
var start := Time.get_ticks_usec()
for i in n: runtime.get_mana_reserve_report()
var per := (Time.get_ticks_usec() - start) / float(n)
start = Time.get_ticks_usec()
for i in 200: clock.advance_minutes(1)
var tick := (Time.get_ticks_usec() - start) / 200.0
print("P06_03_REPORT_COST=" + JSON.stringify({"report_us_avg": per, "tick_us_avg": tick, "ratio_percent": per / tick * 100.0, "facilities": runtime.facility_service.get_instances().size()}))
runtime.free(); clock.free(); state.free(); quit(0)
@@ -0,0 +1,95 @@
{
"unit": "P14-02",
"title": "ワープの通常接続",
"candidate": "8917c19",
"decision": "A07+A08",
"status": "independent_review_pass_awaiting_owner_approval",
"acceptance": "途中保存、マナ不足、到着不能時に移動や費用が二重反映されない。",
"closed_gaps": {
"通常建設できる2x2 FRONTのワープ定義": "mana_warp.tres(3000G・資材30・360分・15G/日・維持マナ1)、通常ビルドパレットに追加。",
"通常経路選択から対象・出口・実位置へ接続": "建設済みワープ全組を経路connectorで連結し、客・従業員の通常経路探索が1歩で移動。自然営業の客が実際にワープで移動(test_runtime_warp)。",
"費用確定規約と二重計上拒否": "移動確定と同じtickで1人3マナを1回だけ差し引き、WARP_TRAVELEDを記録。投影失敗時は課金なし。救助ペアは2人分。",
"マナ不足/機能停止/到着不能の原状保持": "残量3未満・停電・片側未評価/無電力・到着セル封鎖で経路から除外し、費用・移動なし。",
"途中保存・別PID再開で二重反映なし": "課金直後の保存を別PIDで読み、120分継続のマナ・移動履歴・全状態digestが一致。",
"通常UI・影響回帰・性能・独立レビュー": "パレット(25件)・コード描画、147本中122 PASS(失敗24本は基準と同一)、性能計測、独立レビュー2回PASS。",
"A08 客用/業務用の分離": "表層mana_warpは客専用(access \"!staff\")、裏層service_warpは従業員専用で同種同士のみ接続。値はA07と同じ。"
},
"reviews": [
{
"round": 1,
"candidate": "728e5e6",
"verdict": "PASS",
"blocking": [],
"non_blocking": [
"access_id=\"\"のため通勤・休憩・作業中の従業員もワープを使う(A07文言「客と接客中の従業員」より広い。既存の客用昇降機と同じ扱い)。owner確認事項。",
"同一分内で残量が3未満に落ちると後続はその分だけブロック待ち(課金・移動なし)",
"connectors_matchはoperational_stateを検証しない(次分に自己修復)",
"到着先ワープの収容数4は未反映",
"UIは接続状態・運賃・停止理由を表示しない/パレットからの実建設UI操作試験なし/描画未目視",
"4基(6リンク)で1日tickが約74%増。ただし同配置の客用昇降機4基はさらに重く、ワープ固有ではない。リンク数はN(N-1)/2",
"15G/日維持費・救助2人課金・通勤ワープ・同一分複数乗客の専用試験なし(コード確認のみ)"
],
"note": "r1で従業員も表層ワープを使う点を指摘→owner判断A08で分離"
},
{
"round": 2,
"candidate": "8917c19",
"verdict": "PASS",
"blocking": [],
"non_blocking": [
"path_service.gd:2260-2261 _route_exists_with_overridesが\"!staff\"を旧比較で読み、停電中の客ワープ経路の理由コードがCONNECTOR_UNAVAILABLEでなくGOAL_UNREACHABLEになる(移動・費用に影響なし)",
"path_service.gd:2193-2194 _has_permitted_layer_crossingも同様(現ワープは層をまたがないため無害)",
"A08以前のaccess \"\"ワープ接続を含むセーブは原子的に読込拒否(配布済みセーブにワープなし)",
"描画未目視"
]
}
],
"regression_failures_baseline_identical": [
"res://tests/mvp/test_amelia_donations.gd",
"res://tests/mvp/test_fine_cleaning_effect.gd",
"res://tests/s1/test_path_snapshot_transit_guard.gd",
"res://tests/supply/test_normal_auto_purchase_chain.gd",
"res://tests/supply/test_normal_supply_chain.gd",
"res://tests/transport/test_runtime_transport.gd",
"res://tests/ui/test_anri_recruitment.gd",
"res://tests/ui/test_chapel_gameplay.gd",
"res://tests/ui/test_dashboard_coalescing.gd",
"res://tests/ui/test_dimension_migration_ui.gd",
"res://tests/ui/test_first_operating_day.gd",
"res://tests/ui/test_guest_decision_log.gd",
"res://tests/ui/test_guest_observation.gd",
"res://tests/ui/test_layer_skin.gd",
"res://tests/ui/test_original_build_pointer.gd",
"res://tests/ui/test_rank_pointer.gd",
"res://tests/ui/test_staff_management.gd",
"res://tests/ui/test_staff_rescue.gd",
"res://tests/ui/test_staff_rest.gd",
"res://tests/ui/test_stair_transport_details.gd",
"res://tests/ui/test_supply_auto_purchase_ui.gd",
"res://tests/ui/test_upkeep_inspector.gd",
"res://tests/ui/test_world_tree_rank.gd",
"tests/ui/test_cleaning_gameplay.gd"
],
"source_sha256": {
"data/facilities/infrastructure/mana_warp.tres": "42f1156e04a4454d8525bf3dd77b214a39e11bb7c5e749af1413fe77cdb1e456",
"scripts/transport/warp_service.gd": "7602c6b8a9672a703bfa98a1424c2cf68cf50184f87f72349d564af6a5ca9d41",
"scripts/world/facility_infrastructure_projector.gd": "7903b7aa6a46b50150beeb13dd8675ce34168c044b1b818f0dc6e2f7e1872d51",
"scripts/world/path_service.gd": "fd0f4b202291eda6ab06442d14373f9c2457627550958fa79008d2f828b21521",
"scripts/data/facility_catalog.gd": "08a09405a4f07a6b5fd21ba41eff347692f376c50306ccf6ae18e74ed95adacf",
"autoload/simulation_runtime.gd": "68d03872a591955740346a894fa4139cea75ed264428d61ade181532ea398b41",
"scenes/main/main.gd": "e09c361603da85b7a8b1e299a62b0f9b27f2b20b373b511e6450fe281e16614e",
"scripts/ui/pixel_tower_art.gd": "f766b47167db8bd5906b1467fd6f8587af8e9268304c7ba209a9eb157847165e",
"tests/transport/test_runtime_warp.gd": "ce263dd680dfa753f7435b85a733e3909740e98ec75e9e3b72750ed11b664f85",
"tests/ui/test_main_dashboard.gd": "305227c1077a92ef3ee522b561a68b0685767740b46b51ff789c800931647ef1",
"data/facilities/infrastructure/service_warp.tres": "712ae26bf2d9d18c9da6344ee18ef716250e051693bcace586b85f35a794dba2"
},
"not_claimed": [
"Windows実機",
"完成素材・描画の目視",
"P06-02全体(別単位)",
"P14全体"
],
"followups": [
"\"!\"接頭辞accessを_route_exists_with_overridesと_has_permitted_layer_crossingにも適用する"
]
}
@@ -0,0 +1,174 @@
PASS res://tests/run_tests.gd
PASS res://tests/s0/test_definition_registry.gd
PASS res://tests/s0/test_command_transaction.gd
PASS res://tests/s0/test_determinism.gd
PASS res://tests/s0/test_stable_id_generator.gd
PASS res://tests/s0/test_domain_events.gd
PASS res://tests/s0/test_runtime_integration.gd
PASS res://tests/s1/test_dimension_batch_save.gd
PASS res://tests/s1/test_facility_resize_preview.gd
PASS res://tests/s1/test_weighted_resize_runtime.gd
PASS res://tests/s1/test_original_facility_dimensions.gd
PASS res://tests/s1/test_world_service.gd
PASS res://tests/s1/test_path_service.gd
FAIL(1) res://tests/s1/test_path_snapshot_transit_guard.gd
ERROR: refusal creates no new temporary or backup package
PASS res://tests/s1/test_path_congestion.gd
PASS res://tests/s1/test_construction_service.gd
PASS res://tests/s1/test_excavation_service.gd
PASS res://tests/s1/test_spatial_subslot_service.gd
PASS res://tests/s1/test_route_subslot_path_adapter.gd
PASS res://tests/s1/test_facility_infrastructure_projector.gd
PASS res://tests/s1/test_runtime_infrastructure_integration.gd
PASS res://tests/s1/test_runtime_world_construction.gd
PASS tests/environment/test_cleaning_access.gd
FAIL(97) tests/ui/test_cleaning_gameplay.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 15221, &"owner_instance_id": 132691003032, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132691003032] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS tests/environment/test_runtime_cleanliness.gd
PASS res://tests/environment/test_facility_cleanliness.gd
PASS res://tests/s2/test_facility_upkeep_accrual.gd
PASS res://tests/s2/test_facility_upkeep_settlement.gd
PASS res://tests/s2/test_facility_service.gd
PASS res://tests/s2/test_service_start_slots.gd
PASS res://tests/s2/test_inventory_logistics.gd
PASS res://tests/s2/test_economy_service.gd
PASS res://tests/s2/test_ledger_backed_resources.gd
PASS res://tests/s2/test_mana_network_service.gd
PASS res://tests/s2/test_mana_reserve_cycle.gd
PASS res://tests/s2/test_runtime_mana_reserve.gd
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- writer
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- reader
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- writer
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- reader
PASS res://tests/s2/test_runtime_operations_cycle.gd
PASS res://tests/s3/test_runtime_staff_assignment.gd
PASS res://tests/s3/test_guest_service.gd
PASS res://tests/s3/test_staff_service.gd
PASS res://tests/s3/test_staff_payroll_operations.gd
PASS res://tests/s3/test_runtime_actor_cycle.gd
PASS res://tests/s3/test_runtime_actor_hardening.gd
PASS res://tests/s3/test_runtime_path_traffic.gd
PASS res://tests/s2/test_kitchen_production.gd
PASS res://tests/supply/test_supply_save_migration.gd
PASS res://tests/supply/test_supply_logistics_bridge.gd
PASS res://tests/supply/test_supply_management_service.gd
PASS res://tests/supply/test_supply_auto_purchase.gd
FAIL(1) res://tests/supply/test_normal_auto_purchase_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/supply/test_supply_auto_purchase_boundaries.gd
PASS res://tests/supply/test_supply_auto_purchase_destruction.gd
FAIL(1) res://tests/supply/test_normal_supply_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/s2/test_facility_pricing.gd
PASS res://tests/business/test_business_operations.gd
PASS res://tests/business/test_business_closure.gd
PASS res://tests/s4/test_relationship_event_service.gd
PASS res://tests/s4/test_placement_risk_preview_service.gd
PASS res://tests/s4/test_runtime_relationship_events.gd
PASS res://tests/s5/test_authority_service.gd
PASS res://tests/s5/test_defense_service.gd
PASS res://tests/s5/test_runtime_authority_cycle.gd
PASS res://tests/s5/test_runtime_defense_cycle.gd
PASS res://tests/s6/test_save_operations.gd
PASS res://tests/s6/test_save_preflight.gd
PASS res://tests/s6/test_save_recovery_preservation.gd
PASS res://tests/s6/test_runtime_snapshot_serialization.gd
PASS res://tests/s6/test_performance_budget.gd
PASS res://tests/s6/test_runtime_save_lifecycle.gd
PASS res://tests/mvp/test_premium_room_guest_flow.gd
PASS res://tests/mvp/test_runtime_mana_depletion.gd
PASS res://tests/mvp/test_premium_room.gd
PASS res://tests/mvp/test_original_room_zones.gd
PASS res://tests/mvp/test_upkeep_loss_streak.gd
PASS res://tests/mvp/test_upkeep_legacy_midnight.gd
PASS res://tests/mvp/test_runtime_upkeep.gd
PASS res://tests/mvp/test_upkeep_construction_boundaries.gd
PASS res://tests/mvp/test_operations_coordinator.gd
PASS res://tests/mvp/test_mvp_content_catalog.gd
PASS res://tests/mvp/test_progression_service.gd
PASS res://tests/mvp/test_runtime_content_progression.gd
PASS res://tests/mvp/test_runtime_operations_integration.gd
PASS res://tests/mvp/test_runtime_operations_acceptance.gd
PASS res://tests/mvp/test_chapel_boundaries.gd
FAIL(96) res://tests/ui/test_chapel_gameplay.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 20026, &"owner_instance_id": 180740949505, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [180740949505] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_chapel_service.gd
FAIL(96) res://tests/ui/test_dashboard_coalescing.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20063, &"owner_instance_id": 132389013132, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132389013132] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_anri_floor_pricing.gd
FAIL(97) res://tests/mvp/test_fine_cleaning_effect.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 20101, &"owner_instance_id": 133160765081, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [133160765081] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/mvp/test_amelia_donations.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 20128, &"owner_instance_id": 181110048259, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [181110048259] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_anri_recruitment.gd
ERROR: Anri recruitment ordinary owner cleanup failed: { &"owned_engine_pid": 20148, &"owner_instance_id": 135828342415, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135828342415] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_layer_skin.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 1 resources still in use at exit (run with --verbose for details).
FAIL(96) res://tests/ui/test_world_tree_rank.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20200, &"owner_instance_id": 135794787980, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135794787980] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_rank_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20209, &"owner_instance_id": 135845119628, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135845119628] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_layer_presentation.gd
FAIL(96) res://tests/ui/test_original_build_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20255, &"owner_instance_id": 135778010776, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135778010776] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_dimension_migration_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20315, &"owner_instance_id": 165524014740, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [165524014740] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_upkeep_inspector.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20330, &"owner_instance_id": 132472899212, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132472899212] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rest.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20361, &"owner_instance_id": 132472899212, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132472899212] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rescue.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20377, &"owner_instance_id": 132657448588, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132657448588] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_observation.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20402, &"owner_instance_id": 132607116941, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132607116941] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_decision_log.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20410, &"owner_instance_id": 278384347081, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [278384347081] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_room_presentation.gd
PASS res://tests/ui/test_pixel_tower.gd
PASS res://tests/ui/test_main_dashboard.gd
FAIL(96) res://tests/ui/test_staff_management.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 2 resources still in use at exit (run with --verbose for details).
PASS res://tests/ui/test_supply_management.gd
FAIL(96) res://tests/ui/test_supply_auto_purchase_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20534, &"owner_instance_id": 136063223438, &"before": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [136063223438] }, &"after": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_business_management.gd
PASS res://tests/ui/test_elevator_management.gd
FAIL(96) res://tests/ui/test_first_operating_day.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20599, &"owner_instance_id": 135761233552, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135761233552] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/staff/test_dormitory_dimension_migration.gd
PASS res://tests/staff/test_staff_dormitory.gd
PASS res://tests/staff/test_dormitory_shift_cycle.gd
PASS res://tests/staff/test_shift_rush.gd
PASS res://tests/staff/test_staff_rest.gd
PASS res://tests/staff/test_rescue_elevator.gd
PASS res://tests/staff/test_staff_rescue.gd
PASS res://tests/staff/test_task_work_clock.gd
PASS res://tests/world/test_path_vertical_policy.gd
PASS res://tests/world/test_path_transit_density.gd
PASS res://tests/world/test_stair_infrastructure.gd
PASS res://tests/world/test_legacy_stairs.gd
PASS res://tests/transport/test_runtime_stairs.gd
FAIL(96) res://tests/ui/test_stair_transport_details.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 20968, &"owner_instance_id": 133227873943, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [133227873943] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/world/test_elevator_topology.gd
PASS res://tests/transport/test_elevator_service.gd
PASS res://tests/staff/test_staff_commute.gd
PASS res://tests/transport/test_transport_save.gd
PASS res://tests/transport/test_transport_density_migration.gd
PASS res://tests/transport/test_transport_boundaries.gd
FAIL(1) res://tests/transport/test_runtime_transport.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/transport/test_runtime_warp.gd -- writer
PASS res://tests/transport/test_runtime_warp.gd -- reader
PASS res://tests/performance/test_facility_reachability.gd
PASS res://tests/performance/test_snapshot_ownership.gd
PASS res://tests/performance/test_world_snapshot_cache.gd
PASS res://tests/performance/test_lazy_digest.gd
PASS res://tests/performance/test_path_membership.gd
PASS res://tests/performance/test_system_optimization.gd
PASS res://tests/performance/test_digest_performance.gd
PASS res://tests/performance/test_perf_mvp_001.gd
DONE
@@ -0,0 +1,174 @@
PASS res://tests/run_tests.gd
PASS res://tests/s0/test_definition_registry.gd
PASS res://tests/s0/test_command_transaction.gd
PASS res://tests/s0/test_determinism.gd
PASS res://tests/s0/test_stable_id_generator.gd
PASS res://tests/s0/test_domain_events.gd
PASS res://tests/s0/test_runtime_integration.gd
PASS res://tests/s1/test_dimension_batch_save.gd
PASS res://tests/s1/test_facility_resize_preview.gd
PASS res://tests/s1/test_weighted_resize_runtime.gd
PASS res://tests/s1/test_original_facility_dimensions.gd
PASS res://tests/s1/test_world_service.gd
PASS res://tests/s1/test_path_service.gd
FAIL(1) res://tests/s1/test_path_snapshot_transit_guard.gd
ERROR: refusal creates no new temporary or backup package
PASS res://tests/s1/test_path_congestion.gd
PASS res://tests/s1/test_construction_service.gd
PASS res://tests/s1/test_excavation_service.gd
PASS res://tests/s1/test_spatial_subslot_service.gd
PASS res://tests/s1/test_route_subslot_path_adapter.gd
PASS res://tests/s1/test_facility_infrastructure_projector.gd
PASS res://tests/s1/test_runtime_infrastructure_integration.gd
PASS res://tests/s1/test_runtime_world_construction.gd
PASS tests/environment/test_cleaning_access.gd
FAIL(97) tests/ui/test_cleaning_gameplay.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 60299, &"owner_instance_id": 132355458712, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132355458712] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS tests/environment/test_runtime_cleanliness.gd
PASS res://tests/environment/test_facility_cleanliness.gd
PASS res://tests/s2/test_facility_upkeep_accrual.gd
PASS res://tests/s2/test_facility_upkeep_settlement.gd
PASS res://tests/s2/test_facility_service.gd
PASS res://tests/s2/test_service_start_slots.gd
PASS res://tests/s2/test_inventory_logistics.gd
PASS res://tests/s2/test_economy_service.gd
PASS res://tests/s2/test_ledger_backed_resources.gd
PASS res://tests/s2/test_mana_network_service.gd
PASS res://tests/s2/test_mana_reserve_cycle.gd
PASS res://tests/s2/test_runtime_mana_reserve.gd
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- writer
PASS res://tests/s2/test_mana_reserve_new_pid.gd -- reader
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- writer
PASS res://tests/s2/test_mana_recovery_new_pid.gd -- reader
PASS res://tests/s2/test_runtime_operations_cycle.gd
PASS res://tests/s3/test_runtime_staff_assignment.gd
PASS res://tests/s3/test_guest_service.gd
PASS res://tests/s3/test_staff_service.gd
PASS res://tests/s3/test_staff_payroll_operations.gd
PASS res://tests/s3/test_runtime_actor_cycle.gd
PASS res://tests/s3/test_runtime_actor_hardening.gd
PASS res://tests/s3/test_runtime_path_traffic.gd
PASS res://tests/s2/test_kitchen_production.gd
PASS res://tests/supply/test_supply_save_migration.gd
PASS res://tests/supply/test_supply_logistics_bridge.gd
PASS res://tests/supply/test_supply_management_service.gd
PASS res://tests/supply/test_supply_auto_purchase.gd
FAIL(1) res://tests/supply/test_normal_auto_purchase_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/supply/test_supply_auto_purchase_boundaries.gd
PASS res://tests/supply/test_supply_auto_purchase_destruction.gd
FAIL(1) res://tests/supply/test_normal_supply_chain.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/s2/test_facility_pricing.gd
PASS res://tests/business/test_business_operations.gd
PASS res://tests/business/test_business_closure.gd
PASS res://tests/s4/test_relationship_event_service.gd
PASS res://tests/s4/test_placement_risk_preview_service.gd
PASS res://tests/s4/test_runtime_relationship_events.gd
PASS res://tests/s5/test_authority_service.gd
PASS res://tests/s5/test_defense_service.gd
PASS res://tests/s5/test_runtime_authority_cycle.gd
PASS res://tests/s5/test_runtime_defense_cycle.gd
PASS res://tests/s6/test_save_operations.gd
PASS res://tests/s6/test_save_preflight.gd
PASS res://tests/s6/test_save_recovery_preservation.gd
PASS res://tests/s6/test_runtime_snapshot_serialization.gd
PASS res://tests/s6/test_performance_budget.gd
PASS res://tests/s6/test_runtime_save_lifecycle.gd
PASS res://tests/mvp/test_premium_room_guest_flow.gd
PASS res://tests/mvp/test_runtime_mana_depletion.gd
PASS res://tests/mvp/test_premium_room.gd
PASS res://tests/mvp/test_original_room_zones.gd
PASS res://tests/mvp/test_upkeep_loss_streak.gd
PASS res://tests/mvp/test_upkeep_legacy_midnight.gd
PASS res://tests/mvp/test_runtime_upkeep.gd
PASS res://tests/mvp/test_upkeep_construction_boundaries.gd
PASS res://tests/mvp/test_operations_coordinator.gd
PASS res://tests/mvp/test_mvp_content_catalog.gd
PASS res://tests/mvp/test_progression_service.gd
PASS res://tests/mvp/test_runtime_content_progression.gd
PASS res://tests/mvp/test_runtime_operations_integration.gd
PASS res://tests/mvp/test_runtime_operations_acceptance.gd
PASS res://tests/mvp/test_chapel_boundaries.gd
FAIL(96) res://tests/ui/test_chapel_gameplay.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 65058, &"owner_instance_id": 180405405185, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [180405405185] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_chapel_service.gd
FAIL(96) res://tests/ui/test_dashboard_coalescing.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65080, &"owner_instance_id": 132053468812, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132053468812] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/mvp/test_anri_floor_pricing.gd
FAIL(97) res://tests/mvp/test_fine_cleaning_effect.gd
ERROR: Cleaning ordinary owner cleanup failed: { &"owned_engine_pid": 65129, &"owner_instance_id": 132825220761, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132825220761] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/mvp/test_amelia_donations.gd
ERROR: Chapel ordinary owner cleanup failed: { &"owned_engine_pid": 65145, &"owner_instance_id": 180774503939, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [180774503939] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_anri_recruitment.gd
ERROR: Anri recruitment ordinary owner cleanup failed: { &"owned_engine_pid": 65173, &"owner_instance_id": 135492798095, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135492798095] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_layer_skin.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 1 resources still in use at exit (run with --verbose for details).
FAIL(96) res://tests/ui/test_world_tree_rank.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65217, &"owner_instance_id": 135459243660, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135459243660] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_rank_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65233, &"owner_instance_id": 135509575308, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135509575308] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_layer_presentation.gd
FAIL(96) res://tests/ui/test_original_build_pointer.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65263, &"owner_instance_id": 135442466456, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135442466456] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_dimension_migration_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65325, &"owner_instance_id": 165188470420, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [165188470420] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_upkeep_inspector.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65351, &"owner_instance_id": 132137354892, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132137354892] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rest.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65367, &"owner_instance_id": 132137354892, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132137354892] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_staff_rescue.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65397, &"owner_instance_id": 132321904268, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132321904268] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_observation.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65414, &"owner_instance_id": 132271572621, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132271572621] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
FAIL(96) res://tests/ui/test_guest_decision_log.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65432, &"owner_instance_id": 278048802760, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [278048802760] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_room_presentation.gd
PASS res://tests/ui/test_pixel_tower.gd
PASS res://tests/ui/test_main_dashboard.gd
FAIL(96) res://tests/ui/test_staff_management.gd
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: Ordinary fixture audio cleanup failed: { &"passed": false, &"reason": "fresh absolute owned control proof required" }
ERROR: 2 resources still in use at exit (run with --verbose for details).
PASS res://tests/ui/test_supply_management.gd
FAIL(96) res://tests/ui/test_supply_auto_purchase_ui.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65547, &"owner_instance_id": 135727679118, &"before": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135727679118] }, &"after": { &"clock_process": false, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/ui/test_business_management.gd
PASS res://tests/ui/test_elevator_management.gd
FAIL(96) res://tests/ui/test_first_operating_day.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65610, &"owner_instance_id": 135425689232, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [135425689232] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/staff/test_dormitory_dimension_migration.gd
PASS res://tests/staff/test_staff_dormitory.gd
PASS res://tests/staff/test_dormitory_shift_cycle.gd
PASS res://tests/staff/test_shift_rush.gd
PASS res://tests/staff/test_staff_rest.gd
PASS res://tests/staff/test_rescue_elevator.gd
PASS res://tests/staff/test_staff_rescue.gd
PASS res://tests/staff/test_task_work_clock.gd
PASS res://tests/world/test_path_vertical_policy.gd
PASS res://tests/world/test_path_transit_density.gd
PASS res://tests/world/test_stair_infrastructure.gd
PASS res://tests/world/test_legacy_stairs.gd
PASS res://tests/transport/test_runtime_stairs.gd
FAIL(96) res://tests/ui/test_stair_transport_details.gd
ERROR: Ordinary fixture audio cleanup failed: { &"owned_engine_pid": 65968, &"owner_instance_id": 132892329623, &"before": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": false, &"owner_meta_present": true, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [132892329623] }, &"after": { &"clock_process": true, &"clock_physics_process": false, &"clock_process_mode": 0, &"root_gui_disable_input": false, &"auto_accept_quit": true, &"owner_meta_present": false, &"original_auto_accept_quit": true, &"closing": false, &"owner_ids": [] }, &"expected_remaining_owner_ids": [], &"ordinary_owner_release_verified": true, &"clock_process_flags_unchanged": true, &"root_gui_input_flag_unchanged": true, &"audio_teardown_passed": true, &"maximum_wait_us": 500000, &"whole_Runtime_field_deletions": 0, &"gameplay_expectations_changed": false, &"clock_flags_intentionally_modified": false, &"application_close_called": false, &"SceneTree_quit_overridden": false, &"WindowQuit_verified": false, &"formal_acceptance": false, &"passed": false }
PASS res://tests/world/test_elevator_topology.gd
PASS res://tests/transport/test_elevator_service.gd
PASS res://tests/staff/test_staff_commute.gd
PASS res://tests/transport/test_transport_save.gd
PASS res://tests/transport/test_transport_density_migration.gd
PASS res://tests/transport/test_transport_boundaries.gd
FAIL(1) res://tests/transport/test_runtime_transport.gd
ERROR: ordinary Main final audio cleanup failed
PASS res://tests/transport/test_runtime_warp.gd -- writer
PASS res://tests/transport/test_runtime_warp.gd -- reader
PASS res://tests/performance/test_facility_reachability.gd
PASS res://tests/performance/test_snapshot_ownership.gd
PASS res://tests/performance/test_world_snapshot_cache.gd
PASS res://tests/performance/test_lazy_digest.gd
PASS res://tests/performance/test_path_membership.gd
PASS res://tests/performance/test_system_optimization.gd
PASS res://tests/performance/test_digest_performance.gd
PASS res://tests/performance/test_perf_mvp_001.gd
DONE
@@ -0,0 +1,4 @@
P14_02_WARP_PERF={"links_0":0,"links_4":6,"tick_day_ms_avg_warps_0":1015.712,"tick_day_ms_avg_warps_4":1810.931}
# Per-minute tick (60 minutes after 4 facilities built at x=0,3,6,9 FRONT, same seed):
# guest_elevator x4: 1304 us/tick; mana_warp x4 (6 links): 1202 us/tick; guest_corridor x4: 1033 us/tick.
# _synchronize_warps alone: 43 us/call with 4 warps. No-warp day: 1015.7 ms (P06-01 candidate 1014, base 1008).
@@ -0,0 +1,33 @@
extends SceneTree
## P14-02 A07 warp tick cost: the same 1440-minute run with 0 or 4 warps
## (6 linked pairs) built on ground-supported columns. Not rendering/Windows.
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var out := {}
for warps: int in [0, 4]:
var samples: Array = []
for trial: int in 3:
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
var rt: Variant = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0); state.reset(); rt.initialize(clock, state, 9909 + trial); clock.set_paused(true)
rt.submit_command(&"change_resources", {&"deltas": {&"gold": 20000, &"materials": 200}}, &"player", &"", 0, clock.absolute_minute, &"perf.fund")
for i: int in warps:
var built: CommandResult = rt.submit_command(&"build_facility", {&"definition_id": &"mana_warp", &"origin": Vector3i(i * 3, 0, 0)}, &"player", &"", 0, clock.absolute_minute, StringName("perf.w%d" % i))
if not built.is_success():
push_error("warp build failed: " + built.message)
clock.advance_minutes(370)
var start := Time.get_ticks_usec()
clock.advance_minutes(1440)
samples.append((Time.get_ticks_usec() - start) / 1000.0)
out["links_%d" % warps] = rt.path_service.get_connector_ids_with_prefix("warp.connector:").size()
rt.free(); clock.free(); state.free()
var total := 0.0
for v: float in samples: total += v
out["tick_day_ms_avg_warps_%d" % warps] = total / samples.size()
print("P14_02_WARP_PERF=" + JSON.stringify(out))
quit(0)
@@ -0,0 +1 @@
uid://clvwcbbt34gwr
@@ -0,0 +1,59 @@
# P14-03 混雑と経路選択:証拠
作業内容は「客用・業務用EV、階段、ワープの待ち時間をA*費用へ反映する」です。受入条件は「ラッシュ、相乗り、50%減速、救護同伴、経路喪失を、実際の位置と人数で検証する」です。
候補は、実装 `0754f41` に次の修正を加えた正確版です。正確な commit は ACCEPTANCE.json に記録します。
- 保存契約 v2
- 乗車中の客の退館修正
- 試験の強化
## 製品の変更
1. **EVの待ち時間を shaft 全体で数える。** 同じ籠で別の階の組を待っている人も、1人あたり1分(ORTHOGONAL_MOVE_COST)として各接続の `dynamic_cost` に公開します。更新するのは、乗車の要求・取消の時と、籠の毎分処理の時です。同じ階の組の行列、満員の籠1回あたり2分、移動階数×階あたり時間は、これまでどおり `estimate_elevator_wait_cost` が数えます。
2. **保存契約を v2 にする。** ElevatorService の snapshot version を 1 から 2 に上げます。
- v1 は旧版の保存で、昇降機の `dynamic_cost` は常に0でした。v1 は0のときだけ受理し、読込後に待ち時間を導出します。
- v2 は、行列から導いた値との完全一致を必須にします。全0を含めて、一致しなければ原子的に拒否します。
- 旧版 `50ceca0` が書き出した本物の保存(`tests/fixtures/p14-03/legacy_rush_v1`)で移行を確認しました。
3. **乗車中の客は籠の中で判断・退館しない。** 乗車中(BOARDED)の客は、籠が有効な階に降ろすまで判断も退館もしません。試験で再現した欠陥は、乗車中に退館を決めた客が乗車中のまま消えるものでした(1094分)。修正後は1115分に1階で降車し、そのあと退館します。
## A*費用
| 移動手段 | 内訳 |
|---|---|
| EV(客用・業務用) | 基本費用+移動階数×階あたり時間+同じ組の待ち行列+shaft の他の組の待ち人数×1分 |
| 階段 | 費用150(移動は半速の2分)+セルの混雑費用 |
| ワープ | 費用400+到着先セルの混雑費用。停止中・残量不足のときは除外 |
| 通路 | 定員を超えた1人ごとに75。2人以上が重なると移動速度は50% |
## 証拠(`tests/transport/test_route_wait_choice.gd`。full は119 checks、`-- writer` は39、`-- reader` は7)
| 観点 | 確認したこと |
|---|---|
| ラッシュ | 実際の客12人が籠Aで3階行きを待つと、0→1階の経路は籠Bへ迂回します。籠Aの0→1階の接続は12人分の待ちを費用に含みます。登録した従業員が実際に歩き、籠Bに乗り、籠Aには乗らずに目的地へ着きます。取消後は、待ち費用がちょうど消えます。 |
| 保存・再開 | v2 の保存は完全に往復します。v2 の待ち費用を0や300に改ざんした保存は、原子的に拒否されます。旧版 v1 の本物の保存は移行し、v2 として往復します。v1 に非0値を入れた改ざんは拒否されます。別PIDで再開すると、同じ従業員が同じ物理経路を歩き、全状態の digest が一致します。 |
| 相乗り | 実際の客6人が目的地を持ち、Runtime 自身が乗車を要求します。同時に乗るのは定員4人以内です。全員の乗車が終わり、乗車中に退館を指示された1人を除く5人は、存在したまま1階の乗り場 (4,1,0) にいます。退館を指示された1人も、1階で降車してから退館します。 |
| 経路喪失 | 籠Bを撤去すると、経路は籠Aに切り替わります。実際に歩く従業員も籠Aで目的地へ着きます。撤去後の状態も保存・往復します。 |
| 業務用EV | 裏層の業務用 shaft は従業員専用です。実際の従業員4人が並ぶと、A*費用が上がります。 |
| 階段 | 階段で2階をつなぎ、上の乗り場に客6人がいると、階段経路の費用が上がります。 |
| ワープ | 出口に客6人がいると、ワープ経路の費用が上がります。 |
| 50%減速 | 実際の客5人での確認は `tests/s3/test_runtime_path_traffic.gd:146-158`(定員を超えると半速になり、2分目までに必ず進む)です。`test_path_congestion` は PathService 単体での混雑費用と経路回避の試験です。 |
| 救護同伴 | `test_rescue_elevator` で、2人組が同じ籠を予約し、乗車中の保存・読込が完全に一致し、停止時は2人一緒に降りることを確認します。ワープの2人分課金は P14-02 のレビュー(コード確認)です。 |
## 主張しないこと
- 階段(150、2分)とEV(階あたり10分)の費用の釣り合いは変えていません。近くに階段があればEVより優先されます。
- ワープ到着先の定員4は、混雑費用以外では扱いません。
- 退館中の客は位置に関係なく次の分に消えます(既存の仕組み。P06-02 の非主張)。今回の修正は、乗車中だけに限ったものです。
- Windows 実機は、適用ありの未検証として残します。
## レビュー後の確定(2026-10-20)
- **代表性能 r02**(`artifacts/original-completion-2026-10-02/p14-03-representative-perf-r01/run-r02`)
- 収集と機能検証は合格し、版間の比較も成立しました(両版とも checks>0、failures 0)。
- **絶対予算との合格判定は、これとは別にします。** x1 の1分 tick は平均約 827 ms(両版)で、4 ms の予算を超えています。経路、save、load は予算内です。
- 版間の差分は42ファイルで、P14 だけではありません。そのため「P14 単独の影響はない」とは断定しません。
- **r01 の失敗**: save と load の20件は、probe が保存先を artifacts 配下の絶対パスにしたことによる `UNSAFE_PATH` 拒否でした(save-diag-r01)。製品の欠陥ではなく、計測側の誤りです。
- **試験への注入**: ラッシュの12人と業務用EVの4人は、試験から `request_trip` で直接並ばせています。実際に歩くのは迂回する従業員だけです。進行中に経路を失った actor の再計画は、この suite では試験していません。
- **新PID pair suite**(`test_new_pid_pairs`): 子プロセスは正式全回帰の外側捕捉の対象外です。正式な別PIDの証拠は Root の pair(10 PID)です。
- **レビュー依頼書の表記**: `REVIEW_REQUEST.md` は提出時のまま保全しています。71行の「r02実行中・結果欄は空欄」は提出前の古い記載で、実値は同じ文書の74〜79行にあります。性能の「両版が合格しなければ比較不成立」は収集と機能検証の成立を指すもので、絶対予算の合格を意味しません。
- **独立Opus レビュー**: PASS(`p14-03-whole-unit-review-r01/review-output.md`)。正式完了は Runner の final を待ちます。
@@ -84,7 +84,7 @@
"passed": true
},
{
"name": "all5_confirmed_decisions",
"name": "all8_confirmed_decisions",
"passed": true
},
{
@@ -204,8 +204,8 @@
"packages": 30,
"remaining_delivery_units": 88,
"current_package_state_counts": {
"completed": 2,
"in_progress": 28
"completed": 3,
"in_progress": 27
},
"initial_snapshot_checked": false,
"historical_source_bytes_compared": false,
@@ -222,7 +222,7 @@
"ASSETS_PLATFORM_AUDIT.md": "a3a4b8ca0fb39a9abf88692285d26aa879815e092352ba304ef2758e71da50bd",
"ATOMIC_REGISTER.md": "6070143b85b7c3b9b73d7c9768d88d2dae4d20407ad54a563cb6ffd74f2373ae",
"ATOMIC_SEMANTIC_REVIEW.md": "c156b1fb57c2b4a900f27a19049510f3e9616e723d5edb3417f50d733de5be48",
"IMPLEMENTATION_PLAN.md": "317b0cbe5948a3783ef7c167f4ea32f412c71854119b4ad504feedf0420ea3dd",
"IMPLEMENTATION_PLAN.md": "823d559e35d5c1aac9385c5bba1ccc56e41e3c2e436e13fda1168e89c56943fb",
"IMPORT_UNICODE_AUDIT.md": "88b2382bfbb3411fece8be7e6004ba21d8bf6a47e9d1f3cf573ea6638f79c12f",
"P09_VALUE_CONTRACTS.md": "c5abdc4543e54033b1fcfd0943cba266f664d8c10968965fd36ade40da488a25",
"PERFORMANCE_AUDIT.md": "c75e806acf825fc4a61f773a2cce7e71be335a1e25dbb15d98091097e8dc47c1",
@@ -238,12 +238,12 @@
"build_atomic_requirements.py": "6d6ea9e4216372dbd0f9fed3f885a4481b21a3f539a26f64cf98a6830af984c5",
"build_facility_value_contracts.py": "35027b23ce75ce9e4e0cdfc5132fd2eb771ba9f598d97750d7ecf9ecb257f769",
"current_evidence_links.json": "db1837bcc8497201134297e312f4b266a297102285307ec3075d4e23632e26c2",
"decisions.json": "ad0673051b0fa601e525f05128e0b11e2dddd9d4bae6a3e0170bbf47da35efe9",
"decisions.json": "8b7dba984d5b1cc0091e8faf8fddb2ab357dd79f1bd093eba46c23c2f62a068c",
"facility_value_contracts.json": "447388ba03a29bfac25f2bcd068665aedbb07ba7641ce86f2db93d44f4c9f326",
"facility_value_contracts_validation.json": "bf490a9ca585c48fc318e76c4a069ef244827d828d46e6415399f7710590dd16",
"performance_audit.json": "0b630b15a392c3e0366f1362bfe4ddacb968f915f54549f82e4d6fa315384762",
"progress_contract.json": "ccbdfce8c8365d5c13f59531955708834cce45acd0e136561c95295dfdb5df77",
"progress_snapshot.json": "6906588e1199657bfb58df86b8bd205cffb795410b6df56759a4a2a14fbc953b",
"progress_snapshot.json": "111faeb32f4772fedd5ab35b723d5b975b59ab8bd913547f38fe849fc71afd8d",
"progress_validator_guard_checks.json": "72ee513fcf1cad85c24bfd0a4b472f425f6acf117928ece0f6b41e29018da627",
"progress_validator_guard_checks.r01.json": "14c26adffa5a1938241db4912e50ea54b660641ee6fee2e412d467dce14d0519",
"requirement_coverage.json": "03b10e4da367579db502d0671a6e0dda36fd385111c6f1c0084acaff7605f593",
@@ -251,8 +251,8 @@
"source_atomic_coverage.json": "2ab7b9e6a2536ef248d4f7ccd695bf75a082b47018aca7a5a1b6b706fe1907bc",
"validate_atomic_requirements.py": "5b2d0b7d72cb124830fbb0a12d1434e6db698148cc5263d33fd5bd7c2953a1e0",
"validate_facility_value_contracts.py": "91640e2a76cd6cc9186f7b85c0bf379b24b6cac0d48962815235ee628e7ae43e",
"validate_plan.py": "23678227d9b3c556f1bd903f4b5b3147c4a82ce5085e10055481026803451b80",
"validate_plan.py": "4973d3c2797289d266f5c6e7c36f3d2c31931b23a1022eab3d94328267bcc1b4",
"validator_update_checks.json": "f997d0f3de2cea29550840b1d5cb23647d64f81329de46758551e2b6c8fecc27",
"work_packages.json": "1913634b33ca25bec6d5a0a6a4d3d9258b7fd4c9c79c9ab426f21ac2b11c6e81"
"work_packages.json": "e1cd56f1fff8a4787d0e378e8b271a59f45b261baff93227f0832d9854996413"
}
}
@@ -151,13 +151,13 @@
"scope": "Base defect reproduction and isolated candidate checks; normal source adoption and merged regression require their own evidence."
},
"current_package_state_counts": {
"completed": 2,
"in_progress": 28
"completed": 3,
"in_progress": 27
},
"current_delivery_state_counts": {
"completed": 17,
"in_progress": 23,
"planned": 48
"completed": 21,
"in_progress": 20,
"planned": 47
},
"completed_current_deliveries": [
"P00-01",
@@ -167,10 +167,14 @@
"P04-02",
"P04-03",
"P05-01",
"P06-01",
"P06-02",
"P06-03",
"P08-02",
"P08-03",
"P13-03",
"P14-01",
"P14-02",
"P19-03",
"P22-01",
"P23-01",
@@ -179,7 +183,8 @@
"P26-01"
],
"whole_packages_newly_completed": [
"P04"
"P04",
"P06"
],
"remaining_acceptance": [
"原子条件の8観点と適用外/独立判定者",
@@ -4542,7 +4547,7 @@
}
},
"known_original_principal_profit_difference_unresolved": 0,
"next_priority_original_principal_profit": "P04 existingD05 answers pending; current independent nextwholeunit P26-01 actualOpus selected. PriorP06 evidence retained, no activeworker.",
"next_priority_original_principal_profit": "Current: P14-03 Runner gate on 83b170a (no rerun; evidence binding). Next unit: P28-01 current-HEAD performance baseline.",
"historical_before_original_profit_fix_original_principal_profit_reproduction_checkpoint": {
"issued_by": "/root",
"linked_at_jst": "2026-10-09T07:29:13.140774+09:00",
@@ -5233,23 +5238,23 @@
"whole_P06_accepted": false,
"whole_goal_accepted": false
},
"next_priority_p06": "Deferred existingP06 original conditions; no duplicate run. CurrentfocusP26-01.",
"next_priority_p06": "P06 package completed 2026-10-20 (P06-01/02/03).",
"current_P02_01_formal_completion": {
"path": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p02-01-completion-acceptance-r01.json",
"bytes": 8539,
"sha256": "45845238d8a73b84fd346f2d834ee4aaa12d32b45367ea0952b523db9b2523d9"
},
"next_single_delivery_unit": {
"id": "P04-01",
"title": "同時発生の更新規約",
"id": "P14-03",
"title": "混雑と経路選択",
"state": "in_progress",
"completed": false,
"existing_project": "the-tree-p04-01",
"source": "2dde7596a87c43f7bf0bf704b7479f2fa06a5b1c",
"actual_runner_state": "repair_pending; verify live before next run",
"actual_worker": null,
"approval_record": "docs/plans/original-completion-2026-10-02/execution/p04-01-owner-approval-20261018/D05_ACTUAL_HUMAN_APPROVAL.json",
"remaining": "Adopt actual approved rules/authority refs/registry/pins; qualified minimal real-boundary probes; exact final full roster and whole-unit independent review; normalcandidate/final. No duplicateP26."
"candidate_commit": "83b170a4c7176761b0b18d8e9292017d990e80a9",
"current_gate_status": "independent Opus review PASS; awaiting Runner registration/validate/review/integration/final",
"runner_gate_proposal": "artifacts/original-completion-2026-10-02/p14-03-runner-gate-r01/REGISTRATION_PROPOSAL.json",
"original_completed": 21,
"original_total": 88,
"next_after": "P28-01"
},
"current_P14_01_contract_audit": {
"audit": "artifacts/original-completion-2026-10-02/p14-01-current-contract-audit-r01/audit.json",
@@ -9716,7 +9721,7 @@
"execution": "the-tree-p06-01 Runner; recorded Claude decision, one Codex implementer",
"current_gate_status": "not implemented or executed; formal completion not accepted"
},
"next_closure_plan_id": "P06-02",
"next_closure_plan_id": "P14-03",
"p24_03_formal_closure": "docs/plans/original-completion-2026-10-02/execution/p24-03-formal-closure-r01/closure.json",
"new_engine_run_scope": "Supplemental positive metadata diagnostic r01 failed cleanup preparation/log isolation; r02 passed17checks unchanged source and entire default profile. No duplicated full game regression.",
"current_closure_targets": {
@@ -10781,5 +10786,64 @@
"support_review": "No verdict: Antigravity actual429; native Claude resets05:00JST",
"resume_at_jst": "2026-10-19T05:01:00+09:00",
"production_runner_modified": false
},
"current_p06_01_a06_completion": {
"unit": "P06-01",
"candidate": "f247d19",
"acceptance": "docs/plans/original-completion-2026-10-02/execution/p06-01-a06/ACCEPTANCE.json",
"acceptance_sha256": "6f471e3f32460758b8a617051a507f780d70b33f254a7910dfada87a8c5c3484",
"owner_approved_at_jst": "2026-10-20T00:00:00+09:00",
"original_completed": 18,
"original_total": 88,
"whole_package_completed": false
},
"current_p06_03_recovery_completion": {
"unit": "P06-03",
"candidate": "826ef60",
"acceptance": "docs/plans/original-completion-2026-10-02/execution/p06-03-recovery/ACCEPTANCE.json",
"acceptance_sha256": "4e3da801cec700ba5b4c87e881de931bc4e2e971d4ab44d38af6e964baabc9a7",
"owner_approved_at_jst": "2026-10-20T00:00:00+09:00",
"original_completed": 19,
"original_total": 88,
"whole_package_completed": false
},
"current_p14_02_warp_completion": {
"unit": "P14-02",
"candidate": "8917c19",
"acceptance": "docs/plans/original-completion-2026-10-02/execution/p14-02-warp/ACCEPTANCE.json",
"acceptance_sha256": "ac7bfd6fb88cb8ac8c195c8051ebe22ba95a6a6393342de089aae88fdcc73307",
"approved_at_jst": "2026-10-20T00:00:00+09:00",
"approval": "delegated_by_user",
"original_completed": 20,
"original_total": 88,
"whole_package_completed": false
},
"current_p06_02_whole_stop_completion": {
"unit": "P06-02",
"candidate": "f6f9c9c",
"acceptance": "docs/plans/original-completion-2026-10-02/execution/p06-02-whole-stop/ACCEPTANCE.json",
"acceptance_sha256": "d5592fa8f6e3646f7d8a81952cf34f894ca4d1048ab0b2a10d87927cd176b9a2",
"approved_at_jst": "2026-10-20T00:00:00+09:00",
"approval": "delegated_by_user",
"original_completed": 21,
"original_total": 88,
"whole_package_completed": false
},
"historical_next_before_20261020_sync": {
"next_single_delivery_unit": {
"id": "P04-01",
"title": "同時発生の更新規約",
"state": "in_progress",
"completed": false,
"existing_project": "the-tree-p04-01",
"source": "2dde7596a87c43f7bf0bf704b7479f2fa06a5b1c",
"actual_runner_state": "repair_pending; verify live before next run",
"actual_worker": null,
"approval_record": "docs/plans/original-completion-2026-10-02/execution/p04-01-owner-approval-20261018/D05_ACTUAL_HUMAN_APPROVAL.json",
"remaining": "Adopt actual approved rules/authority refs/registry/pins; qualified minimal real-boundary probes; exact final full roster and whole-unit independent review; normalcandidate/final. No duplicateP26."
},
"next_closure_plan_id": "P06-02",
"next_priority_original_principal_profit": "P04 existingD05 answers pending; current independent nextwholeunit P26-01 actualOpus selected. PriorP06 evidence retained, no activeworker.",
"next_priority_p06": "Deferred existingP06 original conditions; no duplicate run. CurrentfocusP26-01."
}
}
@@ -172,7 +172,7 @@ def main():
pending = {d["id"] for d in decisions["pending"]}
check("all10_pending_decision_groups", pending == {f"D{i:02d}" for i in range(1, 11)})
check("known_decision_references", all(set(p["decisions"]) <= pending for p in packages))
check("all5_confirmed_decisions", {d["id"] for d in decisions["confirmed"]} == {f"A{i:02d}" for i in range(1, 6)})
check("all8_confirmed_decisions", {d["id"] for d in decisions["confirmed"]} == {f"A{i:02d}" for i in range(1, 9)})
check("confirmed_decision_references_exist", all((PLAN / d["reference"]).is_file() for d in decisions["confirmed"] if "reference" in d))
state_counts = dict(collections.Counter(p["state"] for p in packages))
check("valid_package_states", all(p["state"] in states for p in packages))
@@ -6260,7 +6260,7 @@
"D04",
"D05"
],
"state": "in_progress",
"state": "completed",
"supplement_ids": [],
"owner_roles": {
"implementation": "実装担当(担当者未割当)",
@@ -6269,14 +6269,14 @@
},
"legacy_state": "in_progress",
"state_scope": "package-level; completed means whole package accepted; partial implementation is not completion",
"current_summary": "停電、厨房、救護の停止復帰は部分実装。有限マナ供給の契約が残る。 制御したEV乗車中救護の停電保存/再開691/0・10全状態pair・無制限journal各9件を限定照合。安全階での緊急降車・自然停電・全館停止・通常UIは未受入。 最新現1299参照で通常建設からの物流/厨房の制御停電・復旧、2正式保存/別PID全状態一致を460/0で限定受入。利用中サービス0件なので途中販売/中断は未受入。全P06未完。 現版の自然入館客の食事/宿泊の制御停電・復旧・一回請求、既存RAIDED休止時の安全終了と正式保存別PID全状態一致を1906/0で限定受入。再開の不具合仮説は反証、ゲーム変更0。全P06未完。 2026-10-12: 旧限定停電証拠から現Runtime等13sourceが変化しており現受入へ自動適用しない。P06-01の原契約監査をRunner経由で開始。正式完了なし。 MP-01-r02承認用資料は追加許可後に同じSol担当で修正し、提出6b78f8fd・正式検証・別Opus5.5独立review PASS・最新main統合/最終検証65a4fe2bを完了。修正使用済み2を保持、現在の個別上限は撤廃済み。全37需要・53source pin・21候補比較・炉の容量判定・旧0/再送/D05を整理。数値/人物分類/更新順序/保存移行は未承認、製品未反映。P06-01はin_progress、原88正式完了増加0。 2026-10-14: MP-01-r02のcompletedと検証/review/統合/最終証拠をRunnerで再確認。推薦契約の採用選択をユーザーへ提示。採用回答は未受領、製品値は未反映。P08-03進行を止める依存ではない。",
"current_summary": "全3成果P06-01/02/03を正式受入済み(A06有限残量、自然枯渇の全館停止、復帰と表示)。P06の完了を全ゲーム/Windows/炉の人物投入/根拠未確定の清掃・医務室・直接spawn判定へ転用しない。",
"remaining_deliverables": [
{
"id": "P06-01",
"title": "供給と蓄積の契約",
"work": "世界樹、マナ炉、消費施設の生成・蓄積・消費と旧ゼロ値保存の意味を整理する。",
"acceptance": "初期値や係数の根拠を区別し、旧版移行と残量境界で矛盾がない。",
"state": "in_progress",
"state": "completed",
"evidence": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/multi-agent-dev-handoff/runner-start-r01.json",
@@ -6304,22 +6304,35 @@
"sha256_at_integration": "21eb3136124ed76f7cc9f063e78eea74a773412dd22976535bc54a02fd23db66",
"scope": "Completed owner-requested unapproved proposal artifact; validation, independent review, integration and final all pinned. Not P06-01 game acceptance.",
"current_game_acceptance_inferred": false
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-01-a06/ACCEPTANCE.json",
"sha256_at_integration": "6f471e3f32460758b8a617051a507f780d70b33f254a7910dfada87a8c5c3484",
"scope": "A06実装の候補f247d19:独立レビュー2回目PASS、別PID保存再開、境界/移行試験、142本回帰(失敗24本は基準と同一)、性能計測。owner承認2026-10-20。P06-01のみ。",
"linked_at_jst": "2026-10-20T00:00:00+09:00"
}
],
"progress_summary": "停電、厨房、救護の停止復帰は部分実装。有限マナ供給の契約が残る。 制御したEV乗車中救護の停電保存/再開691/0・10全状態pair・無制限journal各9件を限定照合。安全階での緊急降車・自然停電・全館停止・通常UIは未受入。 最新現1299参照で通常建設からの物流/厨房の制御停電・復旧、2正式保存/別PID全状態一致を460/0で限定受入。利用中サービス0件なので途中販売/中断は未受入。全P06未完。 現版の自然入館客の食事/宿泊の制御停電・復旧・一回請求、既存RAIDED休止時の安全終了と正式保存別PID全状態一致を1906/0で限定受入。再開の不具合仮説は反証、ゲーム変更0。全P06未完。 2026-10-12: 旧限定停電証拠から現Runtime等13sourceが変化しており現受入へ自動適用しない。P06-01の原契約監査をRunner経由で開始。正式完了なし。 MP-01-r02承認用資料は追加許可後に同じSol担当で修正し、提出6b78f8fd・正式検証・別Opus5.5独立review PASS・最新main統合/最終検証65a4fe2bを完了。修正2/2保持。全37需要・53source pin・21候補比較・炉の容量判定・旧0/再送/D05を整理。数値/人物分類/更新順序/保存移行は未承認、製品未反映。P06-01はin_progress、原88正式完了増加0。",
"progress_summary": "A06(MP-01-r02推薦案:初期100・容量300・世界樹20/10分、需要先払い、overflow記録破棄、0で全館停止、炉は需要支払後判定)を製品へ実装。旧版移行は受入契約なしの0〜300のみ保持し他は原子的に拒否、境界間の容量超過は次境界でoverflow。別PID保存再開・Operations巻き戻し・破壊施設除外を試験。独立レビューr01 FAIL→修正→r02 PASS(f247d19)、owner承認で正式完了。炉の人物投入接続・未定義13施設需要・D05詳細・Windows・全P06は対象外。",
"remaining_gaps": [
"承認用数値・炉対象分類・需要換算・D05更新順序・保存domain/移行元適用条件のオーナー判断。",
"承認後の生成・蓄積・消費接続、旧ゼロ保存の実移行・残量境界・原条件全体の現版証拠。",
"原P06-01の必要検証・独立レビュー・統合/最終を含む全条件完了。候補資料の完了を代用しない。"
],
"updated_at_jst": "2026-10-13T17:09:33.500243+09:00"
"updated_at_jst": "2026-10-20T00:00:00+09:00",
"completion_acceptance": {
"path": "docs/plans/original-completion-2026-10-02/execution/p06-01-a06/ACCEPTANCE.json",
"sha256": "6f471e3f32460758b8a617051a507f780d70b33f254a7910dfada87a8c5c3484",
"candidate": "f247d19",
"owner_approval": "user_reply_in_conversation 2026-10-20「承認する」"
},
"regression_scope_correction_20261020": "2026-10-20訂正:当時の回帰はMakefile経由で、collector rosterのみの46 suiteを含まなかった。その範囲で見つかった回帰(v15 mana_reserve保存拒否、test_required_kitchen旧14比較、defense autonomyのマナ前提、P08 palette数)は83b170aで修正し、正式192/192・22198 checks・失敗0(artifacts/original-completion-2026-10-02/p14-03-formal-regression-83b170a-r01)で全roster合格を確認。当該単位の完了・承認・独立証拠はそのまま保全。"
},
{
"id": "P06-02",
"title": "全館停止の統合",
"work": "利用中、EV、ワープ、物流、救護、清掃、入館へ同じ停止判定を接続する。",
"acceptance": "停電中の無条件売上・生産がなく、乗客と搬送対象が消えない。",
"state": "in_progress",
"state": "completed",
"evidence": [
{
"path": "artifacts/original-completion-2026-10-02/p06-rescue-power-final-root-review-r01.json",
@@ -6341,17 +6354,30 @@
"scope": "Current1299 naturally admitted active meal/lodging services with controlled reserve;1906/0,28 whole typed,14 exact cross-PID pairs,2 formal8 members;existing RAIDED safe failure verified. Natural depletion,whole P06 and OS pending",
"linked_at_jst": "2026-10-09T10:46:38.784861+09:00",
"current_game_acceptance_inferred": false
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-02-whole-stop/ACCEPTANCE.json",
"sha256_at_integration": "d5592fa8f6e3646f7d8a81952cf34f894ca4d1048ab0b2a10d87927cd176b9a2",
"scope": "候補f6f9c9c:7領域共通停止、自然枯渇の統合試験と別PID一致、独立レビューPASS、委任承認。P06-02のみ。",
"linked_at_jst": "2026-10-20T00:00:00+09:00"
}
],
"progress_summary": " 制御したEV乗車中救護の停電保存/再開691/0・10全状態pair・無制限journal各9件を限定照合。安全階での緊急降車・自然停電・全館停止・通常UIは未受入。 現版物流/厨房の制御枯渇と復旧の別PID正式保存を460/0で限定照合。 現版食事/宿泊2種の制御枯渇と復旧、一回請求、既存摘発休止の境界を別PID正式保存で1906/0照合。",
"updated_at_jst": "2026-10-09T10:46:38.784861+09:00"
"progress_summary": "A06自然枯渇の下で利用中・EV・ワープ・物流・救護・清掃・入館の停止を共通判定で確認。需要23の通常塔が自然に0へ落ち、60分間売上・生産・入館・ワープ・乗車0、客は通常退店以外で消えない。停電中保存の別PID継続が一致。独立レビューPASS。根拠未確定3項目は非主張。",
"updated_at_jst": "2026-10-20T00:00:00+09:00",
"completion_acceptance": {
"path": "docs/plans/original-completion-2026-10-02/execution/p06-02-whole-stop/ACCEPTANCE.json",
"sha256": "d5592fa8f6e3646f7d8a81952cf34f894ca4d1048ab0b2a10d87927cd176b9a2",
"candidate": "f6f9c9c",
"owner_approval": "delegated_by_user 2026-10-20"
},
"regression_scope_correction_20261020": "2026-10-20訂正:当時の回帰はMakefile経由で、collector rosterのみの46 suiteを含まなかった。その範囲で見つかった回帰(v15 mana_reserve保存拒否、test_required_kitchen旧14比較、defense autonomyのマナ前提、P08 palette数)は83b170aで修正し、正式192/192・22198 checks・失敗0(artifacts/original-completion-2026-10-02/p14-03-formal-regression-83b170a-r01)で全roster合格を確認。当該単位の完了・承認・独立証拠はそのまま保全。"
},
{
"id": "P06-03",
"title": "復帰と表示",
"work": "供給復帰時の予約・在庫・運行を再開し、HUDへ供給、消費、蓄積を表示する。",
"acceptance": "破壊・摘発の休止を停電復旧で解除しない。途中保存後も復帰結果が一致する。",
"state": "in_progress",
"state": "completed",
"evidence": [
{
"path": "artifacts/original-completion-2026-10-02/p06-rescue-power-final-root-review-r01.json",
@@ -6373,10 +6399,23 @@
"scope": "Current1299 naturally admitted active meal/lodging services with controlled reserve;1906/0,28 whole typed,14 exact cross-PID pairs,2 formal8 members;existing RAIDED safe failure verified. Natural depletion,whole P06 and OS pending",
"linked_at_jst": "2026-10-09T10:46:38.784861+09:00",
"current_game_acceptance_inferred": false
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p06-03-recovery/ACCEPTANCE.json",
"sha256_at_integration": "4e3da801cec700ba5b4c87e881de931bc4e2e971d4ab44d38af6e964baabc9a7",
"scope": "候補826ef60:独立レビューPASS、停電中保存の別PID復帰一致、DESTROYED/RAIDED保持、HUD供給/消費/蓄積表示、144本回帰(失敗24本は基準と同一)、HUD報告コスト計測。owner承認2026-10-20。P06-03のみ。",
"linked_at_jst": "2026-10-20T00:00:00+09:00"
}
],
"progress_summary": " 制御したEV乗車中救護の停電保存/再開691/0・10全状態pair・無制限journal各9件を限定照合。安全階での緊急降車・自然停電・全館停止・通常UIは未受入。 現版物流/厨房の制御枯渇と復旧の別PID正式保存を460/0で限定照合。 現版食事/宿泊2種の制御枯渇と復旧、一回請求、既存摘発休止の境界を別PID正式保存で1906/0照合。",
"updated_at_jst": "2026-10-09T10:46:38.784861+09:00"
"progress_summary": "A06有限残量の下で停電復帰を実装・検証。HUDに供給+20/10分・消費・収支・蓄積・直近不足/破棄を表示。停電中保存を別PIDで復帰させ全状態digest一致、破壊・摘発の休止は復帰で解除されない。予約・在庫・運行・接客の再開は既存試験で持続停電下に確認。独立レビューPASS(826ef60)、owner承認で正式完了。P06-02(ワープ)・P06全体・Windowsは対象外。",
"updated_at_jst": "2026-10-20T00:00:00+09:00",
"completion_acceptance": {
"path": "docs/plans/original-completion-2026-10-02/execution/p06-03-recovery/ACCEPTANCE.json",
"sha256": "4e3da801cec700ba5b4c87e881de931bc4e2e971d4ab44d38af6e964baabc9a7",
"candidate": "826ef60",
"owner_approval": "user_reply_in_conversation 2026-10-20「承認する」"
},
"regression_scope_correction_20261020": "2026-10-20訂正:当時の回帰はMakefile経由で、collector rosterのみの46 suiteを含まなかった。その範囲で見つかった回帰(v15 mana_reserve保存拒否、test_required_kitchen旧14比較、defense autonomyのマナ前提、P08 palette数)は83b170aで修正し、正式192/192・22198 checks・失敗0(artifacts/original-completion-2026-10-02/p14-03-formal-regression-83b170a-r01)で全roster合格を確認。当該単位の完了・承認・独立証拠はそのまま保全。"
}
],
"estimate_person_days_historical_2026_09_29": [
@@ -6408,7 +6447,7 @@
],
"cross_cutting_acceptance_scope": "Completion requirements only, not achieved results. Apply each to relevant slices; non-applicable views require a recorded reason.",
"initial_revision_state": "in_progress",
"updated_at_jst": "2026-10-13T17:09:33.500243+09:00",
"updated_at_jst": "2026-10-20T00:00:00+09:00",
"current_controlled_supply_outage_checkpoint": {
"issued_by": "/root",
"linked_at_jst": "2026-10-09T10:37:43.610273+09:00",
@@ -6710,7 +6749,27 @@
"all_schema_feature_acceptance": false,
"whole_P06_accepted": false,
"whole_goal_accepted": false
}
},
"completion_evidence": [
{
"delivery_id": "P06-01",
"state": "completed",
"evidence_reference": "work_packages.json:P06.remaining_deliverables.P06-01.evidence",
"evidence_count": 6
},
{
"delivery_id": "P06-02",
"state": "completed",
"evidence_reference": "work_packages.json:P06.remaining_deliverables.P06-02.evidence",
"evidence_count": 4
},
{
"delivery_id": "P06-03",
"state": "completed",
"evidence_reference": "work_packages.json:P06.remaining_deliverables.P06-03.evidence",
"evidence_count": 4
}
]
},
{
"id": "P07",
@@ -8202,7 +8261,7 @@
},
"legacy_state": "planned",
"state_scope": "package-level; completed means whole package accepted; partial implementation is not completion",
"current_summary": "採用済み1299参照は初回独立レビューと同一。初回に確認した失敗時保存保護、正常順序・型・所有権・保存復元・経路、1200Kernel ticksの全状態・イベント一致、同版172回帰14636checks/0を維持する。追加証拠で20,000セル・200客・50職員・150施設、既存施設要求200・物流要求200・イベント50の同一Operations OFF状態を採用前後で復元し、snapshot/manual/autosaveを各5試行、各64checks/0として確認。平均snapshotは75.985→74.624ms、manualは425.955→445.803ms、autosaveは280.757→297.499ms。手動保存平均19.848ms、自動保存平均16.741msの実測増加を保持し、ゼロ回帰とは扱わない。採用後保存最大515.903msは既存5秒予算内。P14-01の性能回帰測定不足B01を解消し、この成果単位のみ正式完了可と判定する。5試行の保存・snapshot測定に限定し、simulation、Operations ON、描画、全P28・全P14・全原子・完成素材・全体完成へ拡張しない。Windowsは適用ありの未検証を保持し、通常OS全受入も未完のままとする。 P14-02/03・全P14・Windows全体受入は未完。",
"current_summary": "採用済み1299参照は初回独立レビューと同一。初回に確認した失敗時保存保護、正常順序・型・所有権・保存復元・経路、1200Kernel ticksの全状態・イベント一致、同版172回帰14636checks/0を維持する。追加証拠で20,000セル・200客・50職員・150施設、既存施設要求200・物流要求200・イベント50の同一Operations OFF状態を採用前後で復元し、snapshot/manual/autosaveを各5試行、各64checks/0として確認。平均snapshotは75.985→74.624ms、manualは425.955→445.803ms、autosaveは280.757→297.499ms。手動保存平均19.848ms、自動保存平均16.741msの実測増加を保持し、ゼロ回帰とは扱わない。採用後保存最大515.903msは既存5秒予算内。P14-01の性能回帰測定不足B01を解消し、この成果単位のみ正式完了可と判定する。5試行の保存・snapshot測定に限定し、simulation、Operations ON、描画、全P28・全P14・全原子・完成素材・全体完成へ拡張しない。Windowsは適用ありの未検証を保持し、通常OS全受入も未完のままとする。 P14-02は2026-10-20に正式完了(8917c19、A07/A08)。P14-03は独立レビューPASS・Runnerゲート待ち(加算0)、全P14・Windows全体受入は未完。",
"remaining_deliverables": [
{
"id": "P14-01",
@@ -8263,7 +8322,7 @@
"title": "ワープの通常接続",
"work": "マナワープの建設、対象、待ち時間、消費、停止、実移動を接続する。",
"acceptance": "途中保存、マナ不足、到着不能時に移動や費用が二重反映されない。",
"state": "in_progress",
"state": "completed",
"evidence": [
{
"path": "artifacts/original-completion-2026-10-02/p14-02-current-warp-gap-audit-r01/audit.json",
@@ -8271,27 +8330,49 @@
"scope": "Authoritative requirement/current-catalog gap audit only; no implementation or acceptance",
"linked_at_jst": "2026-10-10T00:39:35.742448+09:00",
"current_game_acceptance_inferred": false
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p14-02-warp/ACCEPTANCE.json",
"sha256_at_integration": "ac7bfd6fb88cb8ac8c195c8051ebe22ba95a6a6393342de089aae88fdcc73307",
"scope": "候補8917c19:A07/A08ワープ、自然営業の客のワープ移動と1回課金、停電/残量不足/到着封鎖の除外、別PID再開で二重反映なし、147本回帰(失敗24本は基準と同一)、性能計測、独立レビュー2回PASS。完了判断はユーザー委任により実施(2026-10-20)。",
"linked_at_jst": "2026-10-20T00:00:00+09:00"
}
],
"progress_summary": "原本86/176/211と現1299の通常施設カタログ37定義を再監査。ワープ定義0、通常建設/移動/費用/停止/途中保存の接続証拠は不足。イベント復旧teleportとマウスwarpは通常マナワープへ転用しない。原本の2x2 FRONT・瞬間移動・高コストを保持し、D04必須値/D05費用時点等は未確定のまま。独立レビュー待ちのP14-01を次の正式完了対象として維持。",
"progress_summary": "A07表層マナワープ(客用)とA08裏層業務用ワープ(従業員用)を通常建設・経路・課金・停止・保存へ接続。建設済み同種ワープを全組接続し1歩移動、出発確定時に1人3マナを一回課金。残量不足・停電・到着封鎖で経路除外し費用・移動なし。別PID再開で費用・移動の二重反映なし。独立レビューr1/r2 PASS(8917c19)。Windows・完成素材・描画目視は対象外。",
"remaining_gaps": [
"通常建設できる2x2 FRONTのワープ施設と原本/承認値の費用・工期等の定義",
"通常経路選択から対象と出口の所有/予約/実位置へ接続する処理",
"承認済み費用確定規約と二重計上拒否",
"マナ不足/機能停止/到着不能の原状保持",
"途中保存・別PID再開で費用と移動が二重反映されない証拠",
"通常UI、影響回帰、性能、完成素材の適用範囲と独立レビュー",
"適用する同一配布版のWindows実機条件"
"完成素材と描画の目視確認(非主張)",
"同一配布版のWindows実機条件(非主張)"
],
"updated_at_jst": "2026-10-10T00:39:35.742448+09:00"
"updated_at_jst": "2026-10-20T00:00:00+09:00",
"completion_acceptance": {
"path": "docs/plans/original-completion-2026-10-02/execution/p14-02-warp/ACCEPTANCE.json",
"sha256": "ac7bfd6fb88cb8ac8c195c8051ebe22ba95a6a6393342de089aae88fdcc73307",
"candidate": "8917c19",
"owner_approval": "delegated_by_user 2026-10-20「承認するかどうかの判断はそちらでやって」"
},
"remaining_gaps_at_completion": "2026-10-20に解消済み(execution/p14-02-warp/ACCEPTANCE.json)。完成素材・描画目視・Windows実機は非主張として残す。",
"regression_scope_correction_20261020": "2026-10-20訂正:当時の回帰はMakefile経由で、collector rosterのみの46 suiteを含まなかった。その範囲で見つかった回帰(v15 mana_reserve保存拒否、test_required_kitchen旧14比較、defense autonomyのマナ前提、P08 palette数)は83b170aで修正し、正式192/192・22198 checks・失敗0(artifacts/original-completion-2026-10-02/p14-03-formal-regression-83b170a-r01)で全roster合格を確認。当該単位の完了・承認・独立証拠はそのまま保全。"
},
{
"id": "P14-03",
"title": "混雑と経路選択",
"work": "客用・業務用EV、階段、ワープの待ち時間をA*費用へ反映する。",
"acceptance": "ラッシュ、相乗り、50%減速、救護同伴、経路喪失を実位置と人数で検証する。",
"state": "planned",
"evidence": []
"state": "in_progress",
"evidence": [
{
"path": "artifacts/original-completion-2026-10-02/p14-03-whole-unit-review-r01/review-output.md",
"scope": "独立Opus whole-unit review PASS(入力SHA 0e53d1c1…)。Runner final ではない。",
"linked_at_jst": "2026-10-20T00:00:00+09:00"
}
],
"progress_summary": "正確候補83b170a:shaft全体の待ちをA*費用へ、保存契約v2(v1は導出して移行、v2は導出値不一致を改ざん0含め原子拒否、正常v2は往復)、乗車中の客を籠内で退館させない修正。正式全回帰192/192・22198 checks・失敗0、Root別PID pair 5/5・10PID、代表性能r02(収集と機能検証は合格・比較成立、x1は両版約827msで4ms予算超過)、独立Opus whole-unit review PASS。skill契約によりRunnerの正式ゲート(登録・validate・review・統合final)待ちで加算0。",
"remaining_gaps": [
"Runner登録とvalidate/review/integration/final(登録案と検証器: artifacts/original-completion-2026-10-02/p14-03-runner-gate-r01/)",
"代表負荷で実職員が業務用shaftを使う場面は未実施",
"x3 frame / stall / 描画 / Windows は未測定(x1は両版とも予算超過、P28で扱う)"
],
"updated_at_jst": "2026-10-20T00:00:00+09:00"
}
],
"estimate_person_days_historical_2026_09_29": [
+27 -1
View File
@@ -47,6 +47,8 @@ const MVP_FACILITY_IDS: Array[StringName] = [
&"service_elevator",
&"guest_stairs",
&"service_stairs",
&"mana_warp",
&"service_warp",
&"staff_door",
&"guest_corridor",
&"service_corridor",
@@ -2583,6 +2585,7 @@ func _on_snapshot_published(_snapshot: Dictionary = {}, _digest: String = "") ->
_synchronize_elevator_pending()
_queue_dashboard_refresh()
_update_pause_and_speed()
_refresh_mana_tooltip()
var operation: Dictionary = _snapshot.get(&"systems", {}).get(&"runtime", {}).get(&"operations", {}).get(&"coordinator", {})
var summaries: Array = operation.get(&"day_summaries", [])
if summaries.is_empty():
@@ -2793,6 +2796,7 @@ func _phase_name(phase: GameClock.Phase) -> String:
return "夜"
const MANA_RESERVE := preload("res://scripts/mana/mana_reserve_cycle.gd")
const RESOURCE_TITLES := {&"gold": "所持金", &"mana": "マナ", &"materials": "資材", &"faith": "信仰"}
func _resource_title(resource_name: StringName) -> String:
@@ -2805,8 +2809,9 @@ func _on_resource_changed(resource_name: StringName, value: int) -> void:
var label := resource_labels[resource_name] as Label
label.text = "%s %d" % [_resource_title(resource_name), value]
if resource_name == &"mana":
label.text += "/%d" % MANA_RESERVE.CAPACITY
label.mouse_filter = Control.MOUSE_FILTER_STOP
label.tooltip_text = "残量0で全館停止。接客・調理・搬入・エレベーターと新規入館が停止します。\n残量と配電が回復すると再開します。破壊・摘発による休止は解除されません。"
_refresh_mana_tooltip(label)
if value <= 0:
label.text += "・停止"
label.add_theme_color_override("font_color", Color("ffb095"))
@@ -2814,6 +2819,27 @@ func _on_resource_changed(resource_name: StringName, value: int) -> void:
label.add_theme_color_override("font_color", _visual_color(&"text_light", Color("fff2d0")))
func _refresh_mana_tooltip(label: Label = null) -> void:
if label == null:
label = resource_labels.get(&"mana") as Label
if label == null:
return
var lines: Array[String] = []
if _runtime != null and _runtime.has_method(&"get_mana_reserve_report"):
var report: Dictionary = _runtime.call(&"get_mana_reserve_report")
lines.append("供給 +%d/%d分 消費 −%d/%d分 収支 %+d" % [int(report[&"generation"]), int(report[&"interval_minutes"]), int(report[&"demand"]), int(report[&"interval_minutes"]), int(report[&"net"])])
var flow: Dictionary = report[&"last_flow"]
var stored := "蓄積 %d/%d" % [int(report[&"amount"]), int(report[&"capacity"])]
if not flow.is_empty():
stored += "(直近:不足 %d・上限超過で破棄 %d)" % [int(flow[&"shortage"]), int(flow[&"overflow"])]
lines.append(stored)
else:
lines.append("世界樹が%d分ごとに%dマナを生成し、施設の維持マナを先に支払って残りを最大%dまで蓄えます。" % [MANA_RESERVE.INTERVAL_MINUTES, MANA_RESERVE.WORLD_TREE_GENERATION, MANA_RESERVE.CAPACITY])
lines.append("残量0で全館停止。接客・調理・搬入・エレベーターと新規入館が停止します。")
lines.append("残量と配電が回復すると再開します。破壊・摘発による休止は解除されません。")
label.tooltip_text = "\n".join(lines)
func _button(text_value: String, callback: Callable, minimum_width := 82) -> Button:
var button := Button.new()
button.text = text_value
+6
View File
@@ -1055,6 +1055,12 @@ static func _snapshot_package_format(snapshot: Dictionary) -> int:
# Keep PurchaseQuotePlansV2's exact original allowlist and all format rules.
runtime_data = runtime_data.duplicate()
runtime_data.erase(&"special_peeping_rooms")
if runtime_data.has(&"mana_reserve"):
# A06 finite reserve: validate the section, then keep the exact original
# v15 purchase allowlist unchanged, as for the peeping-room extension.
if not preload("res://scripts/mana/mana_reserve_cycle.gd").new().restore_snapshot(runtime_data[&"mana_reserve"]): return -1
runtime_data = runtime_data.duplicate()
runtime_data.erase(&"mana_reserve")
if version >= 1 and version <= 14:
return -1 if PurchaseQuoteV2.has_history(runtime_data) else FORMAT_VERSION
if version != 15: return -1
+7
View File
@@ -66,6 +66,13 @@ const INFRASTRUCTURE_FACILITY_PATHS: Array[String] = [
"res://data/facilities/infrastructure/service_stairs.tres",
]
## A07 Mana warp: original 10.7 transport, kept apart from the stair list.
const TRANSPORT_FACILITY_IDS: Array[StringName] = [&"mana_warp", &"service_warp"]
const TRANSPORT_FACILITY_PATHS: Array[String] = [
"res://data/facilities/infrastructure/mana_warp.tres",
"res://data/facilities/infrastructure/service_warp.tres",
]
## Optional post-MVP expansion definitions. They live below a subdirectory so
## DefinitionRegistry's baseline directory scan remains exactly compatible with
## existing saves and the sixteen-facility acceptance fixture.
+10
View File
@@ -231,6 +231,16 @@ func get_storage_current(node_id: StringName) -> int:
return int(_nodes[node_id][&"current"])
## Upkeep demand of every registered consumer, including disabled ones,
## except the given consumer ids (for example destroyed facilities).
func get_total_consumer_demand(excluded_ids: Array = []) -> int:
var total := 0
for node_id: StringName in _nodes:
if int(_nodes[node_id][&"kind"]) == NodeKind.CONSUMER and not node_id in excluded_ids:
total += int(_nodes[node_id][&"demand"])
return total
func get_last_report() -> Dictionary:
return _last_report.duplicate(true)
+139
View File
@@ -0,0 +1,139 @@
extends RefCounted
## Approved finite Mana reserve contract A06 (MP-01-r02 recommended plan).
## GameState keeps the stored amount so existing spending stays authoritative;
## this owns the processed 10-minute boundary and the last flow, so a boundary
## is consumed exactly once and replays after rollback reproduce the same flow.
const VERSION := 1
const POLICY_ID := &"MP-01-r02"
const INITIAL_MANA := 100
const CAPACITY := 300
const WORLD_TREE_GENERATION := 20
const INTERVAL_MINUTES := 10
const FURNACE_YIELD := 100
const LIMIT := 1000000000
const FLOW_KEYS: Array[String] = [
"from_minute", "to_minute", "before", "generation", "furnace", "demand",
"consumed", "shortage", "overflow", "after",
]
var _minute := -1
var _last_flow: Dictionary = {}
func start_at(minute: Variant) -> bool:
if _minute >= 0 or typeof(minute) != TYPE_INT or minute < 0:
return false
_minute = minute - minute % INTERVAL_MINUTES
return true
func get_minute() -> int:
return _minute
func get_last_flow() -> Dictionary:
return _last_flow.duplicate(true)
## Processes every boundary in (last boundary, minute]. Boundaries already
## processed are no-ops, so per-minute callers and same-minute retries are safe.
## Mana may rise between boundaries (event refunds, commands); anything above
## capacity is discarded and recorded as overflow at the next boundary.
func advance_to(minute: Variant, before: Variant, demand: Variant) -> Dictionary:
if _minute < 0:
return _failure(&"NOT_STARTED")
if typeof(minute) != TYPE_INT or not _amount(before) \
or typeof(demand) != TYPE_INT or demand < 0 or demand > LIMIT or minute < _minute:
return _failure(&"INVALID_FLOW")
var boundary: int = minute - minute % INTERVAL_MINUTES
if boundary <= _minute:
return {&"ok": true, &"processed": false, &"after": before}
var amount: int = before
var flow := {}
var count := 0
for to_minute: int in range(_minute + INTERVAL_MINUTES, boundary + 1, INTERVAL_MINUTES):
flow = plan(amount, demand, 0, to_minute - INTERVAL_MINUTES, to_minute)
amount = flow[&"after"]
count += 1
_minute = boundary
_last_flow = flow
return {&"ok": true, &"processed": true, &"boundaries": count, &"after": amount, &"flow": flow.duplicate(true)}
## Furnace offers are judged after natural generation and upkeep demand are
## paid: base_after = min(C, max(0, B + G - D)); accept only with 100 free.
static func furnace_offer_accepted(before: int, demand: int) -> bool:
var base_after := mini(CAPACITY, maxi(0, before + WORLD_TREE_GENERATION - demand))
return CAPACITY - base_after >= FURNACE_YIELD
static func plan(before: int, demand: int, furnace: int, start: int, end: int) -> Dictionary:
var available := before + WORLD_TREE_GENERATION + furnace
var consumed := mini(available, demand)
var remaining := available - consumed
return {&"from_minute": start, &"to_minute": end, &"before": before,
&"generation": WORLD_TREE_GENERATION, &"furnace": furnace, &"demand": demand,
&"consumed": consumed, &"shortage": demand - consumed,
&"overflow": maxi(remaining - CAPACITY, 0), &"after": mini(remaining, CAPACITY)}
## Legacy saves without a reserve receipt must already fit the approved capacity.
static func amount_is_valid(value: Variant) -> bool:
return _amount(value) and value <= CAPACITY
## A current save may hold more than capacity until the next boundary settles it.
static func stored_amount_is_valid(value: Variant) -> bool:
return _amount(value)
func create_snapshot() -> Dictionary:
return {&"version": VERSION, &"policy_id": POLICY_ID, &"capacity": CAPACITY,
&"generation": WORLD_TREE_GENERATION, &"interval_minutes": INTERVAL_MINUTES,
&"minute": _minute, &"last_flow": _last_flow.duplicate(true)}
## Validates fully before committing; a rejected snapshot leaves state intact.
func restore_snapshot(source: Variant) -> bool:
if not source is Dictionary or not _keys(source, ["version", "policy_id", "capacity", "generation", "interval_minutes", "minute", "last_flow"]):
return false
if typeof(source["version"]) != TYPE_INT or source["version"] != VERSION \
or typeof(source["policy_id"]) not in [TYPE_STRING, TYPE_STRING_NAME] \
or StringName(source["policy_id"]) != POLICY_ID \
or typeof(source["capacity"]) != TYPE_INT or source["capacity"] != CAPACITY \
or typeof(source["generation"]) != TYPE_INT or source["generation"] != WORLD_TREE_GENERATION \
or typeof(source["interval_minutes"]) != TYPE_INT or source["interval_minutes"] != INTERVAL_MINUTES \
or not _amount(source["minute"]) or source["minute"] % INTERVAL_MINUTES != 0 \
or not source["last_flow"] is Dictionary:
return false
var flow: Dictionary = source["last_flow"]
if not flow.is_empty():
if not _keys(flow, FLOW_KEYS):
return false
for key: Variant in flow:
if not _amount(flow[key]):
return false
if flow["to_minute"] != source["minute"] \
or flow["generation"] != WORLD_TREE_GENERATION \
or flow["from_minute"] + INTERVAL_MINUTES != flow["to_minute"]:
return false
var expected := plan(flow["before"], flow["demand"], flow["furnace"], flow["from_minute"], flow["to_minute"])
if not _same_flow(expected, flow):
return false
_minute = source["minute"]
var normalized := {}
for key: Variant in flow:
normalized[StringName(key)] = flow[key]
_last_flow = normalized
return true
static func _same_flow(expected: Dictionary, actual: Dictionary) -> bool:
for key: String in FLOW_KEYS:
if expected[StringName(key)] != actual[key]:
return false
return true
static func _amount(value: Variant) -> bool:
return typeof(value) == TYPE_INT and value >= 0 and value <= LIMIT
static func _keys(source: Dictionary, expected: Array) -> bool:
if source.size() != expected.size():
return false
for key: Variant in source:
if typeof(key) not in [TYPE_STRING, TYPE_STRING_NAME] or String(key) not in expected:
return false
return true
static func _failure(code: StringName) -> Dictionary:
return {&"ok": false, &"code": code}
+1
View File
@@ -0,0 +1 @@
uid://dhi1bipyd67tx
@@ -0,0 +1 @@
uid://bi36fvp1jiiiv
+42 -2
View File
@@ -4,7 +4,10 @@ extends RefCounted
## One physical cabin per contiguous shaft. Path connectors expose reachability;
## boarding and arrival here remain authoritative for actual movement.
## Dispatch is oldest request first, batching one origin/destination at a time.
const SNAPSHOT_VERSION := 1
## 2: connectors publish the shaft-wide wait as dynamic_cost (P14-03).
## 1: legacy saves, where every elevator connector's dynamic_cost was 0.
const SNAPSHOT_VERSION := 2
const LEGACY_SNAPSHOT_VERSION := 1
const PREFIX := "transport."
const REQUEST_PREFIX := "transport.trip."
const DOOR_MINUTES := 2
@@ -170,6 +173,7 @@ func request_trip(actor_id: StringName, from: Vector3i, to: Vector3i, minute: in
&"connector_id": connector_id, &"from": from, &"to": to,
&"enqueued_at": minute, &"state": PathService.ELEVATOR_REQUEST_QUEUED}
_trips[actor_id] = trip
_refresh_shaft_wait(config[&"shaft_id"])
last_error = ""
return {&"ok": true, &"replay": false, &"trip": trip.duplicate(true)}
@@ -264,6 +268,7 @@ func _cancel_single(actor_id: StringName) -> bool:
last_error = _path.last_error
return false
_trips.erase(actor_id)
_refresh_shaft_wait(trip[&"shaft_id"])
last_error = ""
return true
@@ -369,7 +374,8 @@ func create_snapshot() -> Dictionary:
func restore_snapshot(snapshot: Dictionary) -> bool:
if _path == null or not _exact_keys(snapshot, [&"version", &"current_minute", &"request_sequence", &"shafts", &"trips"]):
return _invalid("Elevator snapshot shape is invalid.")
if snapshot[&"version"] != SNAPSHOT_VERSION or not snapshot[&"current_minute"] is int or snapshot[&"current_minute"] < 0 \
if not snapshot[&"version"] is int or snapshot[&"version"] not in [LEGACY_SNAPSHOT_VERSION, SNAPSHOT_VERSION] \
or not snapshot[&"current_minute"] is int or snapshot[&"current_minute"] < 0 \
or not snapshot[&"request_sequence"] is int or snapshot[&"request_sequence"] < 0 \
or not snapshot[&"shafts"] is Array or not snapshot[&"trips"] is Array:
return _invalid("Elevator snapshot header is invalid.")
@@ -400,6 +406,8 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
var connector_id: StringName = expected[&"id"]
var live := _path.get_connector(connector_id)
for key: StringName in expected:
# The shaft-wide wait is derived from trips and checked below.
if key == &"dynamic_cost": continue
if not live.has(key) or live[key] != expected[key]: return _invalid("Path elevator configuration disagrees with cabin.")
if live[&"cabin_state"] != _path_cabin_state(car) \
or live[&"operational_state"] != (PathService.CONNECTOR_OPERATIONAL if car[&"operational"] else PathService.CONNECTOR_STOPPED):
@@ -455,6 +463,18 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
if trip[key] != other[key]: return _invalid("Companion trip was split.")
for actor_id: StringName in boarded_owners:
if not next_trips.has(actor_id): return _invalid("Cabin seat has no matching trip.")
for shaft_id: StringName in next_shafts:
var queued := 0
for trip: Dictionary in next_trips.values():
if trip[&"shaft_id"] == shaft_id and trip[&"state"] == PathService.ELEVATOR_REQUEST_QUEUED:
queued += 1
for connector: Dictionary in _connector_configs(next_shafts[shaft_id][&"config"]):
var expected_wait := maxi(queued - _path.elevator_queue_size(connector[&"id"]), 0) * PathService.ORTHOGONAL_MOVE_COST
# Legacy saves never priced the shaft queue; v2 must match exactly.
if snapshot[&"version"] == LEGACY_SNAPSHOT_VERSION:
expected_wait = 0
if int(_path.get_connector(connector[&"id"]).get(&"dynamic_cost", -1)) != expected_wait:
return _invalid("Path shaft wait disagrees with queued trips.")
var path_snapshot := _path.create_snapshot()
for connector: Dictionary in path_snapshot[&"connectors"]:
if str(connector[&"id"]).begins_with(PREFIX) and not expected_connectors.has(connector[&"id"]):
@@ -475,6 +495,10 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
_trips = next_trips
_minute = snapshot[&"current_minute"]
_sequence = snapshot[&"request_sequence"]
if snapshot[&"version"] == LEGACY_SNAPSHOT_VERSION:
# Validated legacy queue: derive the shaft-wide wait once on load.
for shaft_id: StringName in _names(_shafts):
_refresh_shaft_wait(shaft_id)
last_error = ""
return true
@@ -605,6 +629,22 @@ func _publish_cabin(car: Dictionary) -> void:
for connector: Dictionary in _connector_configs(car[&"config"]):
_path.set_connector_operational_state(connector[&"id"], PathService.CONNECTOR_OPERATIONAL if car[&"operational"] else PathService.CONNECTOR_STOPPED)
_path.set_elevator_cabin_state(connector[&"id"], _path_cabin_state(car))
_refresh_shaft_wait(car[&"config"][&"shaft_id"])
## The cabin serves the whole shaft, so riders queued for any other floor pair
## delay this pair too. PathService already prices the connector's own queue;
## the rest of the shaft queue is published as the connector's dynamic cost.
func _refresh_shaft_wait(shaft_id: StringName) -> void:
if not _shafts.has(shaft_id):
return
var queued := 0
for trip: Dictionary in _trips.values():
if trip[&"shaft_id"] == shaft_id and trip[&"state"] == PathService.ELEVATOR_REQUEST_QUEUED:
queued += 1
for connector: Dictionary in _connector_configs(_shafts[shaft_id][&"config"]):
var own := _path.elevator_queue_size(connector[&"id"])
_path.set_connector_dynamic_cost(connector[&"id"], maxi(queued - own, 0) * PathService.ORTHOGONAL_MOVE_COST)
func _shaft_busy(shaft_id: StringName) -> bool:
+113
View File
@@ -0,0 +1,113 @@
extends RefCounted
## A07/A08 Mana warp: every completed warp is linked to every other warp of the
## same kind by one path connector, so crossing is a single instant step. The
## FRONT guest warp excludes staff routes; the BACK service warp is staff-only.
## Connectors are derived from construction state; their operational state
## follows the reserve and the warps' own power. The Runtime charges fares.
const PathType := preload("res://scripts/world/path_service.gd")
const DEFINITION_ID := &"mana_warp"
const SERVICE_DEFINITION_ID := &"service_warp"
const DEFINITION_IDS: Array[StringName] = [DEFINITION_ID, SERVICE_DEFINITION_ID]
const ACCESS_BY_DEFINITION := {&"mana_warp": &"!staff", &"service_warp": &"staff"}
const PREFIX := "warp.connector:"
const MANA_PER_TRIP := 3
const PATH_COST := 400
static func is_warp_connector(connector_id: StringName) -> bool:
return String(connector_id).begins_with(PREFIX)
## Completed warps sorted by instance id: [{instance_id, origin}].
static func warps_from_facilities(facilities: Array) -> Array[Dictionary]:
var warps: Array[Dictionary] = []
for value: Variant in facilities:
if not value is Dictionary:
continue
var facility: Dictionary = value
var definition_id := StringName(str(facility.get(&"definition_id", "")))
if definition_id not in DEFINITION_IDS:
continue
var origin: Variant = facility.get(&"origin")
if not origin is Vector3i:
continue
warps.append({&"instance_id": StringName(str(facility.get(&"instance_id", ""))), &"origin": origin,
&"definition_id": definition_id})
warps.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
return String(a[&"instance_id"]) < String(b[&"instance_id"]))
return warps
static func expected_connectors(facilities: Array) -> Array[Dictionary]:
var warps := warps_from_facilities(facilities)
var result: Array[Dictionary] = []
for i: int in warps.size():
for j: int in range(i + 1, warps.size()):
if warps[i][&"definition_id"] != warps[j][&"definition_id"]:
continue
result.append({
&"access_id": ACCESS_BY_DEFINITION[warps[i][&"definition_id"]],
&"id": StringName("%s%s|%s" % [PREFIX, warps[i][&"instance_id"], warps[j][&"instance_id"]]),
&"from": warps[i][&"origin"],
&"to": warps[j][&"origin"],
&"endpoints": [warps[i][&"instance_id"], warps[j][&"instance_id"]],
})
return result
## Rebuilds warp connectors from construction state and applies availability.
## available: instance_id -> bool. Atomic: on failure the path is restored. The
## rollback snapshot is taken only when a change is actually needed.
static func synchronize(path: PathService, facilities: Array, available: Dictionary, fare_affordable: bool) -> Dictionary:
var expected := expected_connectors(facilities)
var expected_ids: Dictionary = {}
for connector: Dictionary in expected:
expected_ids[connector[&"id"]] = true
var before: Variant = null
for connector_id: StringName in path.get_connector_ids_with_prefix(PREFIX):
if expected_ids.has(connector_id):
continue
if before == null:
before = path.create_snapshot()
if not path.remove_connector(connector_id):
path.restore_snapshot(before)
return {&"ok": false, &"code": &"WARP_CONNECTOR_REMOVE_FAILED", &"reason": path.last_error}
for connector: Dictionary in expected:
var connector_id: StringName = connector[&"id"]
var existing := path.get_connector(connector_id)
var endpoints: Array = connector[&"endpoints"]
var usable := fare_affordable and bool(available.get(endpoints[0], false)) and bool(available.get(endpoints[1], false))
var state := PathType.CONNECTOR_OPERATIONAL if usable else PathType.CONNECTOR_OUTAGE
if not existing.is_empty() and existing[&"from"] == connector[&"from"] and existing[&"to"] == connector[&"to"] \
and existing[&"access_id"] == connector[&"access_id"] and existing[&"operational_state"] == state:
continue
if before == null:
before = path.create_snapshot()
if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"] \
or existing[&"access_id"] != connector[&"access_id"]:
if not existing.is_empty():
path.remove_connector(connector_id)
if not path.configure_connector(connector_id, connector[&"from"], connector[&"to"], PATH_COST, true, connector[&"access_id"], true,
{&"movement_type": PathType.MOVEMENT_CONNECTOR}):
path.restore_snapshot(before)
return {&"ok": false, &"code": &"WARP_CONNECTOR_CONFIGURE_FAILED", &"reason": path.last_error}
if not path.set_connector_operational_state(connector_id, state):
path.restore_snapshot(before)
return {&"ok": false, &"code": &"WARP_CONNECTOR_STATE_FAILED", &"reason": path.last_error}
return {&"ok": true, &"connector_count": expected.size()}
## Saved paths must hold exactly the derived warp connectors.
static func connectors_match(path: PathService, facilities: Array) -> bool:
var expected := expected_connectors(facilities)
var ids := path.get_connector_ids_with_prefix(PREFIX)
if ids.size() != expected.size():
return false
for connector: Dictionary in expected:
var existing := path.get_connector(connector[&"id"])
if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"] \
or int(existing[&"cost"]) != PATH_COST or StringName(existing[&"access_id"]) != connector[&"access_id"] \
or existing[&"movement_type"] != PathType.MOVEMENT_CONNECTOR:
return false
return true
+1
View File
@@ -0,0 +1 @@
uid://5mjcum1r1poa
+10
View File
@@ -89,6 +89,16 @@ static func room(canvas: CanvasItem, rect: Rect2, id: StringName, pixel: float,
table(canvas, at + Vector2(-2, -7)*p, p)
&"chapel":
chapel_furnishings(canvas, rect, p)
&"mana_warp", &"service_warp":
# Original code-drawn transfer circle and rising motes; existing palette.
var ring := Vector2(mid, floor_y - 3.0 * p)
canvas.draw_circle(ring, 9.0 * p, INK)
canvas.draw_circle(ring, 8.0 * p, TEAL)
canvas.draw_circle(ring, 6.0 * p, Color("c1e0d4"))
canvas.draw_circle(ring, 4.0 * p, TEAL)
for i in 5:
var x := mid + (i - 2) * 4.0 * p
canvas.draw_rect(Rect2(x, floor_y - (9 + (i % 3) * 5) * p, p, 2.0 * p), CREAM)
&"public_bath":
canvas.draw_rect(Rect2(rect.position.x+4*p, floor_y-7*p, w-8*p, 7*p), CREAM)
canvas.draw_rect(Rect2(rect.position.x+6*p, floor_y-6*p, w-12*p, 4*p), Color("72b6b8"))
@@ -35,6 +35,8 @@ const KIND_GUEST_ELEVATOR: StringName = &"guest_elevator"
const KIND_SERVICE_ELEVATOR: StringName = &"service_elevator"
const KIND_GUEST_STAIRS: StringName = &"guest_stairs"
const KIND_SERVICE_STAIRS: StringName = &"service_stairs"
const KIND_MANA_WARP: StringName = &"mana_warp"
const KIND_SERVICE_WARP: StringName = &"service_warp"
const SUPPORTED_KINDS: Array[StringName] = [
KIND_GUEST_CORRIDOR,
KIND_SERVICE_CORRIDOR,
@@ -43,6 +45,8 @@ const SUPPORTED_KINDS: Array[StringName] = [
KIND_SERVICE_ELEVATOR,
KIND_GUEST_STAIRS,
KIND_SERVICE_STAIRS,
KIND_MANA_WARP,
KIND_SERVICE_WARP,
]
const KNOWN_KINDS: Array[StringName] = [
KIND_GUEST_CORRIDOR,
@@ -52,6 +56,8 @@ const KNOWN_KINDS: Array[StringName] = [
KIND_SERVICE_ELEVATOR,
KIND_GUEST_STAIRS,
KIND_SERVICE_STAIRS,
KIND_MANA_WARP,
KIND_SERVICE_WARP,
]
const UNSUPPORTED_VERTICAL_KINDS: Array[StringName] = []
@@ -692,6 +698,27 @@ static func _kind_schema(kind: StringName) -> Dictionary:
&"guest_access", &"movement", &"schema_facility_proxy", &"vertical_connector",
]),
}
KIND_MANA_WARP:
# Walkable FRONT cells; WarpService links every warp pair (A07).
return {
&"layer": PathType.FRONT,
&"footprint": Vector2i(2, 2),
&"pass_through": true,
&"staff_only": false,
&"tags": _sorted_name_array([
&"guest_access", &"movement", &"schema_facility_proxy", &"warp",
]),
}
KIND_SERVICE_WARP:
return {
&"layer": PathType.BACK,
&"footprint": Vector2i(2, 2),
&"pass_through": true,
&"staff_only": true,
&"tags": _sorted_name_array([
&"movement", &"schema_facility_proxy", &"staff_only", &"warp",
]),
}
KIND_SERVICE_ELEVATOR:
return {
&"layer": PathType.BACK,
+41 -6
View File
@@ -395,6 +395,27 @@ func set_connector_enabled(connector_id: StringName, enabled: bool) -> bool:
return true
## Cost-only update (no topology change), e.g. waiting riders elsewhere in the
## same elevator shaft. Any change may make routes cheaper, so all caches drop.
func set_connector_dynamic_cost(connector_id: StringName, dynamic_cost: int) -> bool:
if not _connectors.has(connector_id):
last_error = "Unknown connector id: %s" % connector_id
return false
if dynamic_cost < 0:
last_error = "Connector dynamic cost must be non-negative."
return false
var connector: Dictionary = _connectors[connector_id]
if int(connector[&"dynamic_cost"]) == dynamic_cost:
last_error = ""
return true
connector[&"dynamic_cost"] = dynamic_cost
_connectors[connector_id] = connector
traffic_revision += 1
invalidate_all_cache()
last_error = ""
return true
func set_connector_operational_state(connector_id: StringName, state: StringName) -> bool:
if not _connectors.has(connector_id):
last_error = "Unknown connector id: %s" % connector_id
@@ -1420,6 +1441,15 @@ func has_connector(connector_id: StringName) -> bool:
return _connectors.has(connector_id)
func get_connector_ids_with_prefix(prefix: String) -> Array[StringName]:
var ids: Array[StringName] = []
for connector_id: Variant in _connectors:
if String(connector_id).begins_with(prefix):
ids.append(StringName(connector_id))
ids.sort_custom(func(a: StringName, b: StringName) -> bool: return String(a) < String(b))
return ids
func get_connector(connector_id: StringName) -> Dictionary:
if not _connectors.has(connector_id):
return {}
@@ -2088,9 +2118,16 @@ func _edge_meets_vertical_policy(from_cell: Vector3i, edge: Dictionary) -> bool:
or not StringName(edge[&"connector_id"]).is_empty() or edge[&"movement_type"] != MOVEMENT_WALK
## "" is public, "id" needs id, and "!id" is open to everyone except actors
## that carry id (guest-only warp).
static func _access_id_permits(required_access: StringName, allowed_access_ids: Array[StringName]) -> bool:
if String(required_access).begins_with("!"):
return StringName(String(required_access).substr(1)) not in allowed_access_ids
return required_access.is_empty() or required_access in allowed_access_ids
func _edge_is_accessible(edge: Dictionary, allowed_access_ids: Array[StringName]) -> bool:
var required_access: StringName = edge[&"access_id"]
if not required_access.is_empty() and required_access not in allowed_access_ids:
if not _access_id_permits(edge[&"access_id"], allowed_access_ids):
return false
var connector_id: StringName = edge[&"connector_id"]
if connector_id.is_empty():
@@ -2177,8 +2214,7 @@ func _cell_is_temporarily_blocked(cell: Vector3i) -> bool:
## Only the absence of any permitted directed crossing proves unreachable.
func _has_permitted_layer_crossing(from_layer: int, to_layer: int, allowed_access_ids: Array[StringName]) -> bool:
for connector: Dictionary in _connectors.values():
var access_id: StringName = connector[&"access_id"]
if not access_id.is_empty() and access_id not in allowed_access_ids:
if not _access_id_permits(connector[&"access_id"], allowed_access_ids):
continue
var from_cell: Vector3i = connector[&"from"]
var to_cell: Vector3i = connector[&"to"]
@@ -2244,8 +2280,7 @@ func _route_exists_with_overrides(
neighbor_set[neighbor] = true
for connector_id: StringName in connector_ids:
var connector: Dictionary = _connectors[connector_id]
var required_access: StringName = connector[&"access_id"]
if not required_access.is_empty() and required_access not in allowed_access_ids:
if not _access_id_permits(connector[&"access_id"], allowed_access_ids):
continue
if not allow_unavailable_connectors and not _connector_is_operational(connector):
continue
+40
View File
@@ -274,6 +274,42 @@ func _legacy_controls(writer: Dictionary, reader: Dictionary) -> void:
_legacy_control(writer, reader, "byte-identical deep copy", "copy")
_proof("legacy14-migration-controls", {"attempts": 17, "writer_sha256": _typed_sha(writer), "reader_sha256": _typed_sha(reader), "failures": failures})
## Approved later save migrations applied when an older save is loaded, each
## checked against its own contract and then mapped into `expected` in place:
## A06 starts a fresh finite Mana reserve at the restored boundary, and P14-03
## raises the elevator snapshot from v1 to v2 with every other field unchanged.
func _approved_runtime_migrations(expected: Dictionary, reader: Dictionary) -> Dictionary:
var old: Dictionary = expected[&"systems"][&"runtime"]
var now: Dictionary = reader[&"systems"][&"runtime"]
var fields: Array = []
var proof := {}
var ok := true
if not old.has(&"mana_reserve") and now.has(&"mana_reserve"):
var minute := int(expected[&"clock"][&"absolute_minute"])
var fresh := {&"version": 1, &"policy_id": &"MP-01-r02", &"capacity": 300, &"generation": 20,
&"interval_minutes": 10, &"minute": minute - minute % 10, &"last_flow": {}}
ok = ok and now[&"mana_reserve"] == fresh
old[&"mana_reserve"] = now[&"mana_reserve"].duplicate(true)
fields.append("mana_reserve_absent_to_A06_fresh_start")
proof["mana_reserve"] = {"fresh_start_minute": minute - minute % 10, "matches_contract": ok}
if old.get(&"elevators", {}).get(&"version") == 1 and now.get(&"elevators", {}).get(&"version") == 2:
var raised: Dictionary = old[&"elevators"].duplicate(true)
raised[&"version"] = 2
var same_otherwise: bool = raised == now[&"elevators"]
ok = ok and same_otherwise
old[&"elevators"] = raised
fields.append("elevators_v1_to_v2")
proof["elevators"] = {"only_version_changed": same_otherwise}
if not fields.is_empty():
# Saves keep the Runtime's own key order, so the mapped tree follows it.
ok = ok and old.size() == now.size()
var ordered := {}
for key: Variant in now:
ok = ok and old.has(key)
ordered[key] = old.get(key)
expected[&"systems"][&"runtime"] = ordered
return {"ok": ok, "fields": fields, "proof": proof}
func _compare_loaded(writer: Dictionary, write_path: String, read_path: String, label: String, migrate_relationships_v1: bool = false) -> void:
var reader: Dictionary = runtime.create_snapshot()
var old: Dictionary = writer[&"systems"][&"runtime"][&"domain_events"]["recent_events"].back().duplicate(true)
@@ -286,6 +322,8 @@ func _compare_loaded(writer: Dictionary, write_path: String, read_path: String,
valid = valid and var_to_bytes(event) == var_to_bytes(old)
event["event_type"] = actual["event_type"]; event["payload"] = actual["payload"].duplicate(true); replaced += 1
var migration_proof := {}
var runtime_migrations := _approved_runtime_migrations(expected, reader)
valid = valid and runtime_migrations["ok"]
if migrate_relationships_v1:
_legacy_controls(expected, reader)
var migration := _legacy_checkpoint(expected, reader)
@@ -300,6 +338,8 @@ func _compare_loaded(writer: Dictionary, write_path: String, read_path: String,
if migrate_relationships_v1:
binding["mapped_fields"].append("relationships_v1_to_v2")
binding["relationships_v1_to_v2"] = migration_proof
binding["mapped_fields"].append_array(runtime_migrations["fields"])
binding["approved_runtime_migrations"] = runtime_migrations["proof"]
_proof(label + "-io1-binding", binding)
expect(valid, "whole typed loaded state unchanged except complete identity/saveID-bound IO1: " + label)
+30
View File
@@ -0,0 +1,30 @@
# P14-03 旧形式セーブの fixture
`legacy_rush_v1/` は、P14-03 より前の本物のセーブパッケージです。待ち時間を shaft 全体で数えるようにする前の版で書き出しています(ElevatorService snapshot v1、Runtime schema 14)。
- 籠Aの1階で12人の客が3階行きを待っています。
- 昇降機の接続はすべて `dynamic_cost` が0です。
## 生成方法(2026-10-20)
1. 作業ツリーの次の2ファイルを、一時的に `50ceca0` 時点の版へ差し替えました。
- `scripts/transport/elevator_service.gd`
- `scripts/world/path_service.gd`
2. `legacy_rush_writer.gd.txt` を `LEGACY_OUT=user://tests/p14_03_legacy_rush` として実行しました(headless)。出力は次のとおりです。
- `LEGACY dynamic costs [0, 0, 0, 0, 0, 0, 0]`
- `SAVE true`
3. 2ファイルを元に戻しました。git の blob が HEAD と一致することを確認済みです。
- elevator: 574ba4f3…
- path: 5cc9516f…
## SHA256
```
978fd98f250ae5a9d3249f22adc3dcf032007dde92ddd10d556e050dd87616d8 journal.log
80c251341bd3f2a6c4a659f30e477dd856c9fec7961d5b2dfd98d7e9eb5006ab manifest.json
0ef55674eca98b6748ae5ccca85a14b042c1545a143810c9c47b487119895c32 thumbnail.png
26171ed8994982ed13fe038d225522044f1049070be53d76a4ed5572a227257d world.bin
```
`tests/transport/test_route_wait_choice.gd` が確認する内容は次のとおりです。
- この保存は読み込みに成功し、待ち時間が再計算されて v2 として保存されます。
- v1 には現れ得ない非0の待ち費用を含む保存は、原子的に拒否されます。
+1
View File
@@ -0,0 +1 @@
save_completed 2026-10-20T07:38:59
+15
View File
@@ -0,0 +1,15 @@
{
"absolute_minute": 1091,
"checksum_world": "baa5cb8d4eb3ed651934cca0bc1f26f22fd345dc9886a72ca383c3722438ffb9",
"content_pack_ids": [],
"created_at_real": "2026-10-20T07:38:59",
"day": 1,
"display_name": "p14_03_legacy_rush",
"enabled_filter_profile": "default",
"format_version": 1,
"game_version": "0.1.0",
"save_id": "p14_03_legacy_rush",
"seed": 1403,
"uncompressed_size": 197716,
"updated_at_real": "2026-10-20T07:38:59"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cnde4l2e1lib7"
path="res://.godot/imported/thumbnail.png-307ea4ea2aa92de395157267241a407e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://tests/fixtures/p14-03/legacy_rush_v1/thumbnail.png"
dest_files=["res://.godot/imported/thumbnail.png-307ea4ea2aa92de395157267241a407e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.
+34
View File
@@ -0,0 +1,34 @@
extends SceneTree
var n := 0
func c(rt, clock, k, p):
n += 1
var r: CommandResult = rt.submit_command(k, p, &"player", &"", 0, clock.absolute_minute, StringName("p1403.%d" % n))
if not r.is_success(): print("FAIL ", k, " ", r.message)
return r
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
var rt: Variant = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0); state.reset(); rt.initialize(clock, state, 1403); clock.set_paused(true)
c(rt, clock, &"change_resources", {&"deltas": {&"gold": 30000, &"materials": 300}})
c(rt, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(0,0,0)})
c(rt, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(4,0,0)})
clock.advance_minutes(360)
c(rt, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(0,2,0)})
for x in [2, 3]: c(rt, clock, &"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(x,1,0)})
clock.advance_minutes(360)
clock.advance_minutes(10 - int(clock.absolute_minute) % 10 + 1)
for i in 12:
var gid := StringName("rush_%02d" % i)
c(rt, clock, &"spawn_guest", {&"guest_id": gid, &"guest_type_id": &"traveler", &"options": {&"current_cell": Vector3i(0,0,0)}})
var t = rt.elevators.request_trip(StringName("guest:%s" % gid), Vector3i(0,0,0), Vector3i(0,3,0), clock.absolute_minute)
if not t.ok: print("TRIPFAIL ", t)
var dyn := []
for row in rt.path_service.create_snapshot()[&"connectors"]:
if String(row[&"id"]).begins_with("transport."): dyn.append(int(row[&"dynamic_cost"]))
print("LEGACY dynamic costs ", dyn)
var out := OS.get_environment("LEGACY_OUT")
print("SAVE ", SaveService.save_snapshot(out, rt.create_snapshot())[&"ok"], " ", out)
rt.free(); clock.free(); state.free(); quit(0)
+18
View File
@@ -0,0 +1,18 @@
extends RefCounted
## Test-only sustained reserve outage under the A06 finite Mana contract.
## Zeroing the reserve alone recovers at the next 10-minute boundary because the
## world tree keeps generating. A disabled consumer adds upkeep demand that the
## reserve must pay but takes no local network allocation, so the tower stays
## at 0 until release() without changing any other consumer's supply.
const SINK_ID := &"test.mana_outage_sink"
const SINK_DEMAND := 1000
static func hold(runtime: Variant, state: Variant) -> void:
if runtime.mana_network_service.get_node(SINK_ID).is_empty():
runtime.mana_network_service.register_consumer(SINK_ID, SINK_DEMAND, ManaNetworkService.ConsumerPriority.NORMAL, false)
state.set_resource(&"mana", 0)
static func release(runtime: Variant, state: Variant, amount := 100) -> void:
runtime.mana_network_service.unregister_node(SINK_ID)
state.set_resource(&"mana", amount)
+1
View File
@@ -0,0 +1 @@
uid://3h45paa0oqnn
+3 -2
View File
@@ -1,4 +1,5 @@
extends SceneTree
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
var checks := 0
var failures := 0
var runtime: Variant
@@ -59,7 +60,7 @@ func run() -> void:
var mid: Dictionary=runtime.create_snapshot()
expect(runtime.restore_snapshot(mid), "real guest and in-progress premium service restore together")
var elapsed: int=runtime.facility_service.get_service(service_id).elapsed_minutes
state.set_resource(&"mana",0)
ManaOutage.hold(runtime, state)
clock.advance_minutes(15)
var paused: ServiceInstance=runtime.facility_service.get_service(service_id)
expect(paused.state==ServiceInstance.State.PAUSED and paused.elapsed_minutes==elapsed, "zero mana pauses actual guest lodging without consuming service time")
@@ -70,7 +71,7 @@ func run() -> void:
var saved := SaveService.load_snapshot(disk_path)
expect(saved[&"ok"] and runtime.restore_snapshot(saved[&"snapshot"]), "restore real guest, paused service and empty mana from disk")
SaveService.delete_save(disk_path)
state.set_resource(&"mana",100)
ManaOutage.release(runtime, state)
for minute in 370:
clock.advance_one_minute()
+4 -2
View File
@@ -1,4 +1,5 @@
extends SceneTree
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
var checks := 0
var failures := 0
func _initialize() -> void:
@@ -31,11 +32,12 @@ func _run() -> void:
runtime.free(); clock.free(); state.free(); quit(failures); return
# Only reserve depletion is a diagnostic input; no numeric generation policy
# is asserted by this test. Everything else advances through Runtime ticks.
state.set_resource(&"mana", 0)
ManaOutage.hold(runtime, state)
# Pre-fix saves legitimately contain zero reserve with old powered flags.
var legacy: Dictionary = runtime.create_snapshot()
var legacy_data: Dictionary = legacy[&"systems"][&"runtime"]
legacy_data[&"runtime_schema_version"] = 9
legacy_data.erase(&"mana_reserve")
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(legacy_data)
var source_copy := legacy.duplicate(true)
var old_reception_id := reception.instance_id
@@ -65,7 +67,7 @@ func _run() -> void:
var room_id := room.instance_id
var reception_id := reception.instance_id
runtime.facility_service.set_operational_status(room_id, {&"suspension_reason": &"DESTROYED"}, clock.absolute_minute)
state.set_resource(&"mana", 1)
ManaOutage.release(runtime, state, 1)
clock.advance_minutes(1)
room = runtime.facility_service.get_instance(room_id)
reception = runtime.facility_service.get_instance(reception_id)
+194
View File
@@ -0,0 +1,194 @@
extends SceneTree
## P06-02 whole-tower stop under the A06 finite reserve, reached naturally: the
## tower's own upkeep demand exceeds the world tree's 20 Mana per 10 minutes.
## "-- writer" (default) builds an ordinary operating tower, waits for natural
## depletion, checks every domain during the outage and saves mid-outage;
## "-- reader" restores that save in a new process and must match exactly.
const SAVE_PATH := "user://saves/p06_02_whole_outage"
const EXPECTED_PATH := "user://saves/p06_02_whole_outage_expected.json"
const OUTAGE_OBSERVE_MINUTES := 60
const CONTINUE_MINUTES := 60
var _checks := 0
var _failures := 0
var _serial := 0
var _clock: Variant
var _state: Variant
var _runtime: Variant
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var mode := "reader" if "reader" in OS.get_cmdline_user_args() else "writer"
print("Whole tower outage %s (pid %d)" % [mode, OS.get_process_id()])
_clock = load("res://autoload/game_clock.gd").new()
_state = load("res://autoload/game_state.gd").new()
_runtime = load("res://autoload/simulation_runtime.gd").new()
_clock.reset(1, 6, 0)
_state.reset()
_runtime.initialize(_clock, _state, 6602)
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
_clock.set_paused(true)
_expect(bool(_runtime.enable_production_operations().get(&"ok", false)), "natural operations start at Day 1 06:00")
if mode == "writer":
_write()
else:
_read()
_runtime.free(); _clock.free(); _state.free()
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
func _cmd(kind: StringName, payload: Dictionary) -> CommandResult:
_serial += 1
return _runtime.submit_command(kind, payload, &"player", &"", 0, _clock.absolute_minute, StringName("p0602.%d" % _serial))
func _build(id: StringName, origin: Vector3i) -> bool:
var result := _cmd(&"build_facility", {&"definition_id": id, &"origin": origin})
_expect(result.is_success(), "build %s at %s %s" % [id, origin, result.message])
return result.is_success()
func _facility(id: StringName) -> FacilityInstance:
for facility: FacilityInstance in _runtime.facility_service.get_instances():
if facility.definition_id == id:
return facility
return null
## Everything an outage must not create, consume or lose.
func _ledger() -> Dictionary:
var revenue := 0
var wallets := {}
for guest: GuestRuntime in _runtime.guest_service.get_guests():
wallets[String(guest.guest_id)] = _runtime.economy_service.get_balance(StringName("GUEST_WALLET:%s" % guest.guest_id))
for facility: FacilityInstance in _runtime.facility_service.get_instances():
revenue += _runtime.economy_service.get_balance(StringName("FACILITY_REVENUE:%s" % facility.instance_id))
var meals := 0
var stock := 0
for facility: FacilityInstance in _runtime.facility_service.get_instances():
meals += _runtime.inventory_service.total_quantity(facility.local_inventory_id, SupplyCatalog.BASIC_MEAL)
stock += _runtime.inventory_service.total_quantity(facility.local_inventory_id, SupplyCatalog.RAW_FOOD)
var guest_ids: Array[String] = []
for guest: GuestRuntime in _runtime.guest_service.get_guests():
guest_ids.append(String(guest.guest_id))
guest_ids.sort()
return {"revenue": revenue, "wallets": wallets, "meals": meals, "raw_food": stock,
"guests": guest_ids, "cash": _runtime.economy_service.get_balance(&"PLAYER_CASH"), "staff": _runtime.staff_service.get_staff_members().size()}
func _events_since(minute: int, types: Array) -> int:
var count := 0
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if event.absolute_minute > minute and event.event_type in types:
count += 1
return count
func _write() -> void:
_expect(_cmd(&"change_resources", {&"deltas": {&"gold": 30000, &"materials": 300}}).is_success(), "fund the mixed tower fixture")
# FRONT: warps x-6..-5, massage x-4..-1, elevator stack x0-1, reception/rooms x2-5, cafeteria x6-7.
_build(&"guest_elevator", Vector3i(0, 0, 0))
_build(&"reception", Vector3i(2, 0, 0))
_build(&"cafeteria", Vector3i(6, 0, 0))
_build(&"mana_warp", Vector3i(-6, 0, 0))
_build(&"massage_room", Vector3i(-4, 0, 0))
_build(&"massage_room", Vector3i(-2, 0, 0))
_build(&"warehouse", Vector3i(2, 0, 1))
_build(&"security_station", Vector3i(-2, 0, 1))
_clock.advance_minutes(360)
_build(&"guest_elevator", Vector3i(0, 2, 0))
_build(&"standard_room", Vector3i(2, 2, 0))
_build(&"mana_warp", Vector3i(-6, 2, 0))
_clock.advance_minutes(360)
var cafe := _facility(&"cafeteria")
if cafe != null:
var kitchen: Dictionary = load("res://tests/fixtures/required_kitchen_setup.gd").ensure(_runtime, _clock, cafe.instance_id, false)
_expect(bool(kitchen.get(&"ok", false)), "kitchen linked to cafeteria")
var reception := _facility(&"reception")
_expect(reception != null and _cmd(&"hire_staff_candidate", {&"candidate_id": &"staff_akane"}).is_success(), "hire receptionist")
if reception != null:
_expect(_cmd(&"set_staff_work_assignment", {&"staff_id": &"staff_akane", &"facility_id": reception.instance_id, &"template_id": &"DAY"}).is_success(), "assign receptionist")
var demand: int = _runtime.call(&"_mana_reserve_demand")
print("FIXTURE demand=%d mana=%d minute=%d" % [demand, _state.get_resource(&"mana"), _clock.absolute_minute])
_expect(demand > 20, "ordinary tower upkeep exceeds world tree generation (natural depletion)")
# Run normally until the reserve reaches 0 through upkeep alone.
var depleted_at := -1
for minute: int in range(3000):
_clock.advance_minutes(1)
if _state.get_resource(&"mana") == 0:
depleted_at = _clock.absolute_minute
break
_expect(depleted_at > 0, "reserve reaches 0 naturally")
if depleted_at < 0:
return
var flow: Dictionary = _runtime.mana_reserve.get_last_flow()
_expect(int(flow[&"after"]) == 0 and int(flow[&"demand"]) > int(flow[&"generation"]) and int(flow[&"generation"]) == 20, "depletion comes from upkeep exceeding generation, not a test input")
_clock.advance_minutes(1)
var before := _ledger()
var started: int = _clock.absolute_minute
_clock.advance_minutes(OUTAGE_OBSERVE_MINUTES)
var after := _ledger()
_expect(_state.get_resource(&"mana") == 0, "outage persists while upkeep exceeds generation")
for facility: FacilityInstance in _runtime.facility_service.get_instances():
_expect(not facility.power_available, "%s is stopped" % facility.definition_id)
var wallets_kept := true
for guest_id: String in after["wallets"]:
if before["wallets"].has(guest_id) and before["wallets"][guest_id] != after["wallets"][guest_id]:
wallets_kept = false
_expect(after["revenue"] == before["revenue"] and wallets_kept, "no unconditional sales during the outage (revenue and every remaining wallet unchanged)")
_expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") <= int(before["cash"]), "no income reaches the tower during the outage")
_expect(after["meals"] == before["meals"] and after["raw_food"] == before["raw_food"], "no production and no lost stock during the outage")
_expect(_events_since(started, [&"GUEST_SPAWNED", &"GUEST_AUTO_ARRIVED"]) == 0, "no admissions during the outage")
_expect(_events_since(started, [&"SERVICE_SALE", &"CASH_SWEEP"]) == 0, "no service sale or revenue sweep event during the outage")
_expect(_events_since(started, [&"WARP_TRAVELED"]) == 0, "no warp travel during the outage")
_expect(_events_since(started, [&"ELEVATOR_BOARDED"]) == 0, "no elevator boarding during the outage")
var departed := {}
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if event.absolute_minute > started and event.event_type in [&"GUEST_LEFT", &"GUEST_DESPAWNED"]:
departed[String(event.entity_ids[0])] = true
for guest_id: String in before["guests"]:
_expect(_runtime.guest_service.get_guest(StringName(guest_id)) != null or departed.has(guest_id), "guest %s stays or leaves through an ordinary departure" % guest_id)
for trip: Dictionary in _runtime.elevators.get_report()[&"trips"]:
_expect(trip[&"state"] == PathService.ELEVATOR_REQUEST_BOARDED, "only held boarded riders remain on a stopped cabin")
var snapshot: Dictionary = _runtime.create_snapshot()
_expect(SaveService.save_snapshot(SAVE_PATH, snapshot)[&"ok"], "save mid-outage")
_clock.advance_minutes(CONTINUE_MINUTES)
var file := FileAccess.open(EXPECTED_PATH, FileAccess.WRITE)
file.store_string(JSON.stringify({
"writer_pid": OS.get_process_id(),
"ledger": JSON.stringify(_ledger()),
"digest": SimulationDigest.compute(_runtime.create_snapshot()),
}))
file.close()
func _read() -> void:
var expected: Variant = JSON.parse_string(FileAccess.get_file_as_string(EXPECTED_PATH))
_expect(expected is Dictionary, "reader finds writer record")
if not expected is Dictionary:
return
_expect(int(expected["writer_pid"]) != OS.get_process_id(), "reader runs in a different process")
var loaded := SaveService.load_snapshot(SAVE_PATH)
_expect(loaded[&"ok"] and _runtime.restore_snapshot(loaded[&"snapshot"]), "reader restores mid-outage save")
_expect(_state.get_resource(&"mana") == 0, "restored tower is still stopped")
_clock.advance_minutes(CONTINUE_MINUTES)
_expect(JSON.stringify(_ledger()) == String(expected["ledger"]), "continued outage ledger matches the writer")
_expect(SimulationDigest.compute(_runtime.create_snapshot()) == String(expected["digest"]), "whole continued state digest matches")
SaveService.delete_save(SAVE_PATH)
DirAccess.remove_absolute(ProjectSettings.globalize_path(EXPECTED_PATH))
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)
+1
View File
@@ -0,0 +1 @@
uid://jetoym5gu2ts
+1 -1
View File
@@ -66,7 +66,7 @@ func _test_tick_command_execution() -> void:
func _test_starter_world_layers() -> void:
_reset_runtime()
_expect(_runtime.definition_registry.facility_count() == 23, "Runtime loads baseline sixteen plus stairs, the infirmary and premium room/dormitory and chapel")
_expect(_runtime.definition_registry.facility_count() == 25, "Runtime loads baseline sixteen plus stairs, the infirmary, premium room/dormitory, chapel and A07/A08 warps")
_expect(_runtime.definition_registry.has_facility(&"chapel"), "Runtime exposes the original chapel definition")
var front_start := Vector3i(-2, 0, WorldService.LAYER_FRONT)
var back_goal := Vector3i(2, 0, WorldService.LAYER_BACK)
+146
View File
@@ -0,0 +1,146 @@
extends SceneTree
## P06-03 outage recovery across a real process boundary. "-- writer" saves
## mid-outage and records its own recovery; "-- reader" restores that save in a
## new Godot process, recovers the same way and must match exactly. Recovery
## must never clear DESTROYED or RAIDED suspension.
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
const OUTAGE_SAVE := "user://saves/p06_03_recovery_new_pid"
const EXPECTED_PATH := "user://saves/p06_03_recovery_new_pid_expected.json"
const RECOVERY_MINUTES := 30
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var mode := "reader" if "reader" in OS.get_cmdline_user_args() else "writer"
print("S2: P06-03 Mana recovery new-PID %s (pid %d)" % [mode, OS.get_process_id()])
if mode == "writer":
_write()
else:
_read()
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
func _new_runtime() -> Array:
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()
runtime.initialize(clock, state, 6606)
clock.set_paused(true)
return [clock, state, runtime]
func _facility(runtime: Variant, definition_id: StringName) -> FacilityInstance:
for facility: FacilityInstance in runtime.facility_service.get_instances():
if facility.definition_id == definition_id:
return facility
return null
func _summary(runtime: Variant, state: Variant) -> Dictionary:
var rows := {}
for facility: FacilityInstance in runtime.facility_service.get_instances():
rows[String(facility.definition_id)] = {
"power": facility.power_available,
"suspension": String(facility.suspension_reason),
"operation": facility.operation_state,
}
return {"mana": state.get_resource(&"mana"), "facilities": rows}
func _recover(clock: Variant, state: Variant, runtime: Variant) -> void:
ManaOutage.release(runtime, state, 0)
clock.advance_minutes(RECOVERY_MINUTES)
func _write() -> void:
var nodes := _new_runtime()
var clock: Variant = nodes[0]
var state: Variant = nodes[1]
var runtime: Variant = nodes[2]
_expect(runtime.submit_command(&"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(-6, 0, 0)}).is_success(), "build reception")
clock.advance_minutes(120)
_expect(runtime.submit_command(&"build_facility", {&"definition_id": &"standard_room", &"origin": Vector3i(-6, 2, 0)}).is_success(), "build room on supported floor")
var cafeteria_built := false
for x: int in [-2, 2, -8, -10]:
if runtime.submit_command(&"build_facility", {&"definition_id": &"cafeteria", &"origin": Vector3i(x, 0, 0)}).is_success():
cafeteria_built = true
break
_expect(cafeteria_built, "build cafeteria on ground floor")
clock.advance_minutes(180)
var reception := _facility(runtime, &"reception")
var cafeteria := _facility(runtime, &"cafeteria")
var room := _facility(runtime, &"standard_room")
_expect(reception != null and cafeteria != null and room != null, "facilities complete normally")
if reception == null or cafeteria == null or room == null:
return
runtime.facility_service.set_operational_status(cafeteria.instance_id, {&"suspension_reason": &"DESTROYED"}, clock.absolute_minute)
runtime.facility_service.set_operational_status(room.instance_id, {&"suspension_reason": &"RAIDED"}, clock.absolute_minute)
ManaOutage.hold(runtime, state)
clock.advance_minutes(15)
_expect(not _facility(runtime, &"reception").power_available, "outage stops the tower")
var outage: Dictionary = runtime.create_snapshot()
_expect(SaveService.save_snapshot(OUTAGE_SAVE, outage)[&"ok"], "writer saves mid-outage")
_recover(clock, state, runtime)
var summary := _summary(runtime, state)
_check_recovered(summary)
var file := FileAccess.open(EXPECTED_PATH, FileAccess.WRITE)
_expect(file != null, "writer records recovery")
if file != null:
file.store_string(JSON.stringify({
"writer_pid": OS.get_process_id(),
"summary": summary,
"digest": SimulationDigest.compute(runtime.create_snapshot()),
}))
file.close()
for node: Variant in nodes:
node.free()
func _read() -> void:
var expected: Variant = JSON.parse_string(FileAccess.get_file_as_string(EXPECTED_PATH))
_expect(expected is Dictionary, "reader finds writer record")
if not expected is Dictionary:
return
_expect(int(expected["writer_pid"]) != OS.get_process_id(), "reader runs in a different process")
var nodes := _new_runtime()
var clock: Variant = nodes[0]
var state: Variant = nodes[1]
var runtime: Variant = nodes[2]
var loaded := SaveService.load_snapshot(OUTAGE_SAVE)
_expect(loaded[&"ok"] and runtime.restore_snapshot(loaded[&"snapshot"]), "reader restores mid-outage save")
_expect(state.get_resource(&"mana") == 0 and not _facility(runtime, &"reception").power_available, "restored tower is still stopped")
_recover(clock, state, runtime)
var summary := _summary(runtime, state)
_check_recovered(summary)
_expect(JSON.stringify(JSON.parse_string(JSON.stringify(summary))) == JSON.stringify(expected["summary"]), "recovered facility states match the writer")
_expect(SimulationDigest.compute(runtime.create_snapshot()) == String(expected["digest"]), "whole recovered state digest matches the writer")
SaveService.delete_save(OUTAGE_SAVE)
DirAccess.remove_absolute(ProjectSettings.globalize_path(EXPECTED_PATH))
for node: Variant in nodes:
node.free()
func _check_recovered(summary: Dictionary) -> void:
var rows: Dictionary = summary["facilities"]
_expect(int(summary["mana"]) > 0, "world tree refills the reserve after the outage")
_expect(bool(rows["reception"]["power"]) and String(rows["reception"]["suspension"]) == "", "ordinary facility power returns")
_expect(bool(rows["cafeteria"]["power"]) and String(rows["cafeteria"]["suspension"]) == "DESTROYED" and int(rows["cafeteria"]["operation"]) == FacilityInstance.OperationState.SUSPENDED, "recovery does not clear destruction")
_expect(bool(rows["standard_room"]["power"]) and String(rows["standard_room"]["suspension"]) == "RAIDED" and int(rows["standard_room"]["operation"]) == FacilityInstance.OperationState.SUSPENDED, "recovery does not clear raid suspension")
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)
@@ -0,0 +1 @@
uid://bdhjn1ujekdi3
+65
View File
@@ -0,0 +1,65 @@
extends SceneTree
const Cycle = preload("res://scripts/mana/mana_reserve_cycle.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 run(before: int, demand: int, minutes: int) -> int:
var cycle = Cycle.new()
cycle.start_at(360)
var amount := before
for minute: int in range(361, 360 + minutes + 1):
var result: Dictionary = cycle.advance_to(minute, amount, demand)
amount = int(result[&"after"])
return amount
func _initialize() -> void:
expect(Cycle.INITIAL_MANA == 100 and Cycle.CAPACITY == 300 and Cycle.WORLD_TREE_GENERATION == 20, "approved A06 values")
# Proposal comparison table (recommended column), F=0, start 360.
expect(run(100, 2, 120) == 300, "low load fills to capacity")
expect(run(100, 16, 120) == 148, "normal load 100+12*(20-16)")
expect(run(100, 63, 120) == 0, "overload depletes")
expect(run(0, 16, 10) == 4, "zero reserve recovers on next boundary")
expect(run(300, 2, 10) == 300, "full reserve keeps capacity")
var cycle = Cycle.new()
expect(not cycle.advance_to(370, 100, 16)[&"ok"], "unstarted cycle rejected")
expect(cycle.start_at(365) and cycle.get_minute() == 360, "start floors to boundary")
expect(not cycle.advance_to(369, 100, 16)[&"processed"], "non-boundary minute is a no-op")
var flow: Dictionary = cycle.advance_to(370, 100, 63)[&"flow"]
expect(flow[&"after"] == 57 and flow[&"consumed"] == 63 and flow[&"overflow"] == 0, "demand paid from generation and reserve")
var saved: Dictionary = cycle.create_snapshot()
expect(not cycle.advance_to(370, 57, 63)[&"processed"] and cycle.create_snapshot() == saved, "same boundary never consumed twice")
expect(not cycle.advance_to(360, 57, 63)[&"ok"], "time reversal rejected")
expect(not cycle.advance_to(380, -1, 0)[&"ok"] and cycle.create_snapshot() == saved, "negative reserve rejected without change")
var high = Cycle.new()
high.start_at(360)
flow = high.advance_to(370, 525, 16)[&"flow"]
expect(flow[&"after"] == 300 and flow[&"overflow"] == 229, "amount raised above capacity between boundaries settles with recorded overflow")
var high_restored = Cycle.new()
expect(high_restored.restore_snapshot(high.create_snapshot()), "over-capacity before survives snapshot validation")
var skipped: Dictionary = cycle.advance_to(400, 57, 63)
expect(skipped[&"boundaries"] == 3 and skipped[&"after"] == 0 and skipped[&"flow"][&"shortage"] == 43, "skipped boundaries settle in order")
var restored = Cycle.new()
expect(restored.restore_snapshot(cycle.create_snapshot()) and restored.create_snapshot() == cycle.create_snapshot(), "snapshot round trip")
var corrupt: Dictionary = cycle.create_snapshot()
corrupt[&"last_flow"][&"after"] += 1
var untouched = Cycle.new()
expect(not untouched.restore_snapshot(corrupt) and untouched.get_minute() == -1, "tampered flow rejected atomically")
corrupt = cycle.create_snapshot()
corrupt[&"capacity"] = 600
expect(not untouched.restore_snapshot(corrupt), "foreign policy capacity rejected")
corrupt = cycle.create_snapshot()
corrupt[&"minute"] = 405
expect(not untouched.restore_snapshot(corrupt), "off-boundary minute rejected")
# Furnace is judged after natural generation and demand payment.
expect(not Cycle.furnace_offer_accepted(200, 16), "B=200 base_after 204 free 96 rejected")
expect(Cycle.furnace_offer_accepted(196, 16), "B=196 base_after 200 free 100 accepted")
expect(not Cycle.furnace_offer_accepted(300, 16), "B=300 full rejected")
expect(Cycle.plan(196, 16, 100, 360, 370)[&"after"] == 300, "accepted furnace offer fills exactly")
expect(Cycle.amount_is_valid(0) and Cycle.amount_is_valid(300) and not Cycle.amount_is_valid(301) and not Cycle.amount_is_valid(-1) and not Cycle.amount_is_valid(1.5), "legacy amount bounds")
print("%s: %d checks" % ["PASS" if failures == 0 else "FAIL", checks])
quit(failures)
+1
View File
@@ -0,0 +1 @@
uid://de3w8hfsk83nt
+111
View File
@@ -0,0 +1,111 @@
extends SceneTree
## A06 reserve across a real process boundary. Run "-- writer" first, then
## "-- reader" in a new Godot process; the reader must reproduce the writer's
## continuation exactly from the disk save, and migrate a legacy save.
const Cycle = preload("res://scripts/mana/mana_reserve_cycle.gd")
const CURRENT_SAVE := "user://saves/a06_mana_new_pid_current"
const LEGACY_SAVE := "user://saves/a06_mana_new_pid_legacy"
const EXPECTED_PATH := "user://saves/a06_mana_new_pid_expected.json"
const CONTINUE_MINUTES := 75
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var mode := "writer" if not "reader" in OS.get_cmdline_user_args() else "reader"
print("S2: A06 Mana reserve new-PID %s (pid %d)" % [mode, OS.get_process_id()])
if mode == "writer":
_write()
else:
_read()
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
func _new_runtime() -> Array:
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()
runtime.initialize(clock, state, 4404)
clock.set_paused(true)
return [clock, state, runtime]
func _free(nodes: Array) -> void:
for node: Variant in nodes:
node.free()
func _write() -> void:
var nodes := _new_runtime()
var clock: Variant = nodes[0]
var state: Variant = nodes[1]
var runtime: Variant = nodes[2]
# Stop mid-interval so the reader must not settle the pending boundary early.
clock.advance_minutes(43)
var snapshot: Dictionary = runtime.create_snapshot()
_expect(SaveService.save_snapshot(CURRENT_SAVE, snapshot)[&"ok"], "writer saves current A06 reserve")
var legacy: Dictionary = snapshot.duplicate(true)
legacy[&"systems"][&"runtime"].erase(&"mana_reserve")
legacy[&"game_state"][&"resources"][&"mana"] = 0
_expect(SaveService.save_snapshot(LEGACY_SAVE, legacy)[&"ok"], "writer saves legacy zero-reserve save")
var saved_mana: int = state.get_resource(&"mana")
clock.advance_minutes(CONTINUE_MINUTES)
var expected := {
"writer_pid": OS.get_process_id(),
"saved_minute": int(snapshot[&"clock"][&"absolute_minute"]),
"saved_mana": saved_mana,
"mana": state.get_resource(&"mana"),
"reserve": var_to_str(runtime.mana_reserve.create_snapshot()),
"digest": SimulationDigest.compute(runtime.create_snapshot()),
}
var file := FileAccess.open(EXPECTED_PATH, FileAccess.WRITE)
_expect(file != null, "writer records continuation")
if file != null:
file.store_string(JSON.stringify(expected))
file.close()
_free(nodes)
func _read() -> void:
var expected: Variant = JSON.parse_string(FileAccess.get_file_as_string(EXPECTED_PATH))
_expect(expected is Dictionary, "reader finds writer record")
if not expected is Dictionary:
return
_expect(int(expected["writer_pid"]) != OS.get_process_id(), "reader runs in a different process")
var nodes := _new_runtime()
var clock: Variant = nodes[0]
var state: Variant = nodes[1]
var runtime: Variant = nodes[2]
var loaded := SaveService.load_snapshot(CURRENT_SAVE)
_expect(loaded[&"ok"] and runtime.restore_snapshot(loaded[&"snapshot"]), "reader restores current save from disk")
_expect(clock.absolute_minute == int(expected["saved_minute"]) and state.get_resource(&"mana") == int(expected["saved_mana"]), "restored minute and reserve match the save")
clock.advance_minutes(CONTINUE_MINUTES)
_expect(state.get_resource(&"mana") == int(expected["mana"]), "continued reserve matches the writer")
_expect(var_to_str(runtime.mana_reserve.create_snapshot()) == String(expected["reserve"]), "continued reserve receipt matches the writer")
_expect(SimulationDigest.compute(runtime.create_snapshot()) == String(expected["digest"]), "whole continued state digest matches the writer")
var legacy := SaveService.load_snapshot(LEGACY_SAVE)
_expect(legacy[&"ok"] and runtime.restore_snapshot(legacy[&"snapshot"]), "reader migrates legacy save from disk")
_expect(state.get_resource(&"mana") == 0 and runtime.mana_reserve.get_last_flow().is_empty(), "legacy explicit 0 stays stopped")
_expect(runtime.create_snapshot()[&"systems"][&"runtime"].has(&"mana_reserve"), "migrated state saves with the A06 reserve")
for path: String in [CURRENT_SAVE, LEGACY_SAVE]:
SaveService.delete_save(path)
DirAccess.remove_absolute(ProjectSettings.globalize_path(EXPECTED_PATH))
_free(nodes)
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)
@@ -0,0 +1 @@
uid://c340fnfuwchcs
+68
View File
@@ -0,0 +1,68 @@
extends SceneTree
## Runs every writer/reader save-restart pair as two real child Godot processes
## (distinct PIDs) from this one suite, so a script-level regression roster also
## proves the new-PID halves. Each child's complete stdout+stderr and exit code
## are kept under user://pair-evidence/ (inside the run's private profile);
## summaries printed here avoid completion-marker wording on purpose.
const PAIRS: Array[String] = [
"res://tests/s2/test_mana_reserve_new_pid.gd",
"res://tests/s2/test_mana_recovery_new_pid.gd",
"res://tests/transport/test_runtime_warp.gd",
"res://tests/mvp/test_whole_tower_outage.gd",
"res://tests/transport/test_route_wait_choice.gd",
]
const EVIDENCE_DIR := "user://pair-evidence"
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var engine := OS.get_executable_path()
var project := ProjectSettings.globalize_path("res://")
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(EVIDENCE_DIR))
print("New-PID pairs: parent pid %d engine %s" % [OS.get_process_id(), engine])
for script: String in PAIRS:
var pids := {}
for mode: String in ["writer", "reader"]:
var output: Array = []
var code := OS.execute(engine, ["--headless", "--path", project, "--script", script, "--", mode], output, true)
var text := "".join(output)
var name := "%s.%s" % [script.get_file().get_basename(), mode]
var file := FileAccess.open(EVIDENCE_DIR.path_join(name + ".log"), FileAccess.WRITE)
file.store_string(text)
file.close()
var pid := _child_pid(text)
pids[mode] = pid
var passed := code == 0 and _child_marker_passed(text)
print(" pair %s %s exit=%d child_pid=%d bytes=%d sha256=%s" % [script.get_file(), mode, code, pid, text.to_utf8_buffer().size(), text.sha256_text()])
_expect(passed, "%s %s child completes with zero failures" % [script.get_file(), mode])
_expect(int(pids["writer"]) > 0 and int(pids["reader"]) > 0 and pids["writer"] != pids["reader"] and pids["reader"] != OS.get_process_id(), "%s writer and reader ran in distinct processes" % script.get_file())
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
## Each pair script prints its own pid on its first line ("... pid N" or "(pid N)").
static func _child_pid(text: String) -> int:
var regex := RegEx.new()
regex.compile("pid (\\d+)")
var found := regex.search(text)
return int(found.get_string(1)) if found != null else -1
static func _child_marker_passed(text: String) -> bool:
var regex := RegEx.new()
regex.compile("(?m)^PASS: (\\d+) checks$")
var found := regex.search(text)
return found != null and int(found.get_string(1)) > 0 and not text.contains("FAIL:") and not text.contains("SCRIPT ERROR")
func _expect(condition: bool, label: String) -> void:
_checks += 1
if not condition:
_failures += 1
push_error(" ✗ %s" % label)
+1
View File
@@ -0,0 +1 @@
uid://bykhpoojytbrd
+151
View File
@@ -0,0 +1,151 @@
extends SceneTree
const Cycle = preload("res://scripts/mana/mana_reserve_cycle.gd")
var _checks := 0
var _failures := 0
var _clock: Variant
var _state: Variant
var _runtime: Variant
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
print("S2: runtime finite Mana reserve (A06)")
_reset_runtime()
_test_generation_and_demand()
_test_save_round_trip_and_migration()
_test_depletion_stops_tower()
_test_between_boundary_increase()
_test_destroyed_facility_demand()
_cleanup()
if _failures == 0:
print("PASS: %d checks" % _checks)
else:
push_error("FAIL: %d of %d checks failed" % [_failures, _checks])
quit(_failures)
func _reset_runtime() -> void:
_cleanup()
_clock = load("res://autoload/game_clock.gd").new()
_state = load("res://autoload/game_state.gd").new()
_runtime = load("res://autoload/simulation_runtime.gd").new()
_clock.reset(1, 6, 0)
_state.reset()
var report: Dictionary = _runtime.initialize(_clock, _state, 3303)
_clock.set_paused(true)
_expect(report[&"valid"], "runtime initializes")
_expect(_state.get_resource(&"mana") == Cycle.INITIAL_MANA, "new game starts with approved 100 Mana")
_expect(_runtime.mana_reserve.get_minute() == _clock.absolute_minute, "reserve starts on the opening boundary")
func _cleanup() -> void:
for node: Variant in [_runtime, _clock, _state]:
if node != null:
node.free()
_runtime = null
_clock = null
_state = null
func _test_generation_and_demand() -> void:
_clock.advance_minutes(10)
var demand: int = _runtime.mana_network_service.get_total_consumer_demand()
var flow: Dictionary = _runtime.mana_reserve.get_last_flow()
_expect(flow[&"generation"] == 20 and flow[&"demand"] == demand, "boundary uses world tree 20 and registered demand")
_expect(_state.get_resource(&"mana") == mini(Cycle.CAPACITY, 100 + 20 - demand), "one boundary settles exactly once")
_clock.advance_minutes(9)
var mid: int = _state.get_resource(&"mana")
_expect(mid == int(flow[&"after"]), "no settlement between boundaries")
_clock.advance_minutes(200)
_expect(_state.get_resource(&"mana") <= Cycle.CAPACITY, "reserve never exceeds capacity")
func _test_save_round_trip_and_migration() -> void:
var snapshot: Dictionary = _runtime.create_snapshot()
var runtime_data: Dictionary = snapshot[&"systems"][&"runtime"]
_expect(runtime_data.has(&"mana_reserve"), "new saves carry the reserve contract")
_expect(_runtime.restore_snapshot(snapshot.duplicate(true)), "current save restores")
_expect(_runtime.create_snapshot() == snapshot, "restored reserve state is identical")
var legacy: Dictionary = snapshot.duplicate(true)
legacy[&"systems"][&"runtime"].erase(&"mana_reserve")
legacy[&"game_state"][&"resources"][&"mana"] = 0
_expect(_runtime.restore_snapshot(legacy), "legacy save with explicit 0 migrates")
_expect(_state.get_resource(&"mana") == 0 and _runtime.mana_reserve.get_last_flow().is_empty(), "explicit 0 stays 0 with fresh reserve")
var over: Dictionary = snapshot.duplicate(true)
over[&"systems"][&"runtime"].erase(&"mana_reserve")
over[&"game_state"][&"resources"][&"mana"] = Cycle.CAPACITY + 1
var before: Dictionary = _runtime.create_snapshot()
_expect(not _runtime.restore_snapshot(over), "legacy amount over capacity is rejected")
_expect(_runtime.create_snapshot() == before, "rejected migration keeps live state")
var tampered: Dictionary = snapshot.duplicate(true)
tampered[&"systems"][&"runtime"][&"mana_reserve"][&"last_flow"][&"after"] += 1
_expect(not _runtime.restore_snapshot(tampered), "tampered reserve flow is rejected")
_expect(_runtime.restore_snapshot(snapshot.duplicate(true)), "original save still restores")
func _test_depletion_stops_tower() -> void:
_state.set_resource(&"mana", 0)
var demand: int = _runtime.mana_network_service.get_total_consumer_demand()
_runtime.mana_network_service.register_consumer(&"test.mana_sink", 40)
_clock.advance_minutes(10 - (_clock.absolute_minute % 10))
_expect(_state.get_resource(&"mana") == 0, "demand above generation keeps the reserve at 0")
_expect(int(_runtime.mana_reserve.get_last_flow()[&"shortage"]) == demand + 40 - 20, "shortage is recorded")
_runtime.mana_network_service.unregister_node(&"test.mana_sink")
_clock.advance_minutes(10)
_expect(_state.get_resource(&"mana") == maxi(0, 20 - demand), "world tree recovers the reserve at the next boundary")
func _test_between_boundary_increase() -> void:
_clock.advance_minutes(10 - (_clock.absolute_minute % 10) + 3)
_state.add_resource(&"mana", 400)
var high: int = _state.get_resource(&"mana")
_expect(high > Cycle.CAPACITY, "mana can rise above capacity between boundaries (event refund / command)")
var saved: Dictionary = _runtime.create_snapshot()
_expect(_runtime.restore_snapshot(saved.duplicate(true)) and _state.get_resource(&"mana") == high, "over-capacity mid-interval save restores")
_clock.advance_minutes(1)
_expect(not _runtime.get_operations_report()[&"runtime_failure_latched"], "over-capacity amount does not latch a runtime fault")
_clock.advance_minutes(10 - (_clock.absolute_minute % 10))
var flow: Dictionary = _runtime.mana_reserve.get_last_flow()
_expect(_state.get_resource(&"mana") == Cycle.CAPACITY and flow[&"before"] == high, "next boundary settles to capacity")
_expect(flow[&"overflow"] == high + 20 - int(flow[&"consumed"]) - Cycle.CAPACITY, "excess is recorded as overflow")
func _test_destroyed_facility_demand() -> void:
var build = _runtime.submit_command(
&"build_facility",
{&"definition_id": &"cafeteria", &"origin": Vector3i(-5, 0, WorldService.LAYER_FRONT), &"rotation": 0},
&"player", &"", 50, -1, &"a06.build.cafeteria"
)
_expect(build.is_success(), "cafeteria construction starts")
_clock.advance_minutes(180)
var cafeteria: FacilityInstance = null
for facility: FacilityInstance in _runtime.facility_service.get_instances():
if facility.definition_id == &"cafeteria":
cafeteria = facility
_expect(cafeteria != null, "cafeteria completes")
if cafeteria == null:
return
var with_cafeteria: int = _runtime.call("_mana_reserve_demand")
_expect(with_cafeteria == _runtime.mana_network_service.get_total_consumer_demand(), "owned facility demand counts")
_runtime.facility_service.set_operational_status(cafeteria.instance_id, {&"business_open": false}, _clock.absolute_minute)
_expect(_runtime.call("_mana_reserve_demand") == with_cafeteria, "closed facility still pays upkeep demand")
_runtime.facility_service.set_operational_status(cafeteria.instance_id, {&"suspension_reason": &"DESTROYED"}, _clock.absolute_minute)
_expect(_runtime.call("_mana_reserve_demand") == with_cafeteria - 2, "destroyed facility demand is excluded")
_clock.advance_minutes(10 - (_clock.absolute_minute % 10))
_expect(int(_runtime.mana_reserve.get_last_flow()[&"demand"]) == with_cafeteria - 2, "boundary uses demand without destroyed facility")
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)
@@ -0,0 +1 @@
uid://cewrt8dc6d4hi
+8 -1
View File
@@ -328,10 +328,17 @@ func _test_exhausted_generated_ids_fail_atomically() -> void:
_expect(_runtime.id_generator.restore_snapshot(allocator), "valid near-exhausted allocator is a disclosed saved-state boundary")
var before: Dictionary = _runtime.defense_service.create_snapshot()
var rng_before: Dictionary = _runtime.get_rng_stream(&"defense").snapshot()
var mana_before: int = _state.get_resource(&"mana")
var reserve_minute_before: int = _runtime.mana_reserve.get_minute()
_advance(5)
# A06: crossing a 10-minute boundary settles the finite reserve; that flow is
# the only Mana change allowed here.
var reserve_mana := mana_before
if _runtime.mana_reserve.get_minute() != reserve_minute_before:
reserve_mana = int(_runtime.mana_reserve.get_last_flow()[&"after"])
before[&"current_minute"] = _clock.absolute_minute
_expect(before == _runtime.defense_service.create_snapshot() and rng_before == _runtime.get_rng_stream(&"defense").snapshot() and _clock.paused, "exhausted automatic allocator fails without advancing combat or RNG")
_expect(_state.get_resource(&"gold") == 5_000 and _state.get_resource(&"mana") == 100, "allocation failure charges no skill or outcome resources")
_expect(_state.get_resource(&"gold") == 5_000 and _state.get_resource(&"mana") == reserve_mana, "allocation failure charges no skill or outcome resources (Mana moves only by the A06 reserve flow)")
_expect(_count_domain_events(&"DEFENSE_AUTOMATIC_ROUND_FAILED", &"raid.id.exhausted") == 1 and _runtime.id_generator.get_counter(&"defense_round_resolution") == StableIdGenerator.MAX_COUNTER - 1, "exhaustion records one diagnostic and rolls skipped-ID allocation back")
@@ -0,0 +1 @@
uid://b0c3ouuq42ycg
@@ -0,0 +1 @@
uid://dftsky13pe0uj
@@ -0,0 +1 @@
uid://4r40f1kpjmvj
@@ -0,0 +1 @@
uid://cnnon5woufurp
@@ -0,0 +1 @@
uid://4n5welqfhdqg
@@ -0,0 +1 @@
uid://8uytmpjup8q4
+3 -2
View File
@@ -1,4 +1,5 @@
extends SceneTree
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
var checks := 0
var failures := 0
var runtime: Variant
@@ -50,7 +51,7 @@ func run() -> void:
expect(patient.current_cell == medic.current_cell and patient.health == 0 and runtime.elevators.get_report()[&"trips"].is_empty(), "emergency unloads both at the same floor without healing")
expect(runtime.restore_snapshot(runtime.create_snapshot()), "emergency pair release remains saveable")
expect(runtime.restore_snapshot(checkpoint), "restore boarded rescue pair for tower-wide depletion")
state.set_resource(&"mana", 0)
ManaOutage.hold(runtime, state)
clock.advance_minutes(1)
patient = runtime.staff_service.get_staff(&"patient"); medic = runtime.staff_service.get_staff(&"medic")
expect(patient.current_cell == medic.current_cell and patient.health == 0 and runtime.elevators.get_report()[&"trips"].is_empty(), "reserve depletion lands both rescue passengers together without healing")
@@ -60,7 +61,7 @@ func run() -> void:
expect(runtime.staff_service.get_staff(&"patient").health == 0 and runtime.staff_service.get_staff(&"patient").current_cell == landing, "stopped clinic cannot heal or teleport the landed patient")
var outage: Dictionary = runtime.create_snapshot()
expect(runtime.staff_service.validate_invariants()[&"ok"] and runtime.restore_snapshot(outage) and runtime.create_snapshot() == outage, "depleted rescue ownership survives exact complete save restoration")
state.set_resource(&"mana", 100)
ManaOutage.release(runtime, state)
clock.advance_minutes(100)
expect(runtime.staff_service.get_staff(&"patient").health == 100, "restored power resumes rescue and treatment for the same patient")
expect(runtime.staff_service.validate_invariants()[&"ok"] and runtime.restore_snapshot(runtime.create_snapshot()), "recovered rescue has no orphan ownership and remains saveable")
+3 -2
View File
@@ -1,4 +1,5 @@
extends SceneTree
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
var checks := 0
var failures := 0
var runtime: Variant
@@ -40,11 +41,11 @@ func run() -> void:
expect(runtime.create_snapshot()==arrived,"staff movement and recovery replay exactly")
worker=runtime.staff_service.get_staff(&"dorm_sleeper")
var health:=worker.health
state.set_resource(&"mana",0);clock.advance_minutes(30)
ManaOutage.hold(runtime, state);clock.advance_minutes(30)
expect(worker.health==health and not runtime.get_staff_rest_report(worker.staff_id).get(&"resting",false),"unpowered dormitory stops recovery")
expect(runtime.restore_snapshot(runtime.create_snapshot()),"stopped dormitory and staff position restore")
worker=runtime.staff_service.get_staff(&"dorm_sleeper")
state.set_resource(&"mana",100);clock.advance_minutes(40)
ManaOutage.release(runtime, state);clock.advance_minutes(40)
expect(worker.health>health,"power recovery resumes rest")
runtime.facility_service.set_operational_status(room_id,{&"operator_open":false},clock.absolute_minute)
health=worker.health;clock.advance_minutes(30)
+5 -4
View File
@@ -1,4 +1,5 @@
extends SceneTree
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
## Real construction, hired porter and purchased stock; failure injection is
## limited to route closures, capacity pressure and expired cargo.
@@ -363,12 +364,12 @@ func _finish() -> void:
func _test_reserve_outage() -> void:
_expect(_runtime.restore_snapshot(_loaded), "restore physically loaded cargo for reserve outage")
_state.set_resource(&"mana", 0)
ManaOutage.hold(_runtime, _state)
_clock.advance_minutes(30)
_expect(_request().state == LogisticsRequest.State.DELIVERING and _quantity(_cargo()) == 8 and _quantity(_inventory(_destination)) == 0, "outage retains loaded cargo without delivering into stopped facility")
_expect(_crosslinks(), "outage preserves Request Task inventory ownership")
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "cargo waiting through outage restores")
_state.set_resource(&"mana", 100)
ManaOutage.release(_runtime, _state)
_wait_for(LogisticsRequest.State.COMPLETED, 60)
_expect(_request().state == LogisticsRequest.State.COMPLETED and _quantity(_cargo()) == 0 and _quantity(_inventory(_destination)) == 8, "recovered power delivers cargo exactly once")
_expect(_crosslinks(), "recovered delivery ownership reconciles")
@@ -389,7 +390,7 @@ func _test_kitchen_reserve_outage() -> void:
if before[&"active_batch"].is_empty():
_runtime.restore_snapshot(_loaded)
return
_state.set_resource(&"mana", 0)
ManaOutage.hold(_runtime, _state)
_clock.advance_minutes(30)
var stopped: Dictionary = _runtime.kitchen_production.get_report(_destination)
_expect(stopped[&"state"] == &"NO_POWER" and stopped[&"active_batch"] == before[&"active_batch"], "thirty stopped minutes preserve batch identity reservations and progress")
@@ -397,7 +398,7 @@ func _test_kitchen_reserve_outage() -> void:
_expect(_runtime.kitchen_production.validate_crosslinks(), "stopped kitchen reservations remain owned")
var saved: Dictionary = _runtime.create_snapshot()
_expect(_runtime.restore_snapshot(saved) and _runtime.create_snapshot() == saved, "active cooking outage round trips through complete Runtime save")
_state.set_resource(&"mana", 100)
ManaOutage.release(_runtime, _state)
_clock.advance_minutes(30)
_expect(_quantity(_inventory(_destination)) == 4 and _runtime.inventory_service.total_quantity(_inventory(_destination), SupplyCatalog.BASIC_MEAL) == 4, "recovery consumes exactly four raw food and produces exactly four meals")
_expect(_runtime.kitchen_production.get_report(_destination)[&"state"] == &"TARGET_REACHED" and _runtime.kitchen_production.validate_crosslinks(), "recovered batch releases reservations and stops at target")
+406
View File
@@ -0,0 +1,406 @@
extends SceneTree
## P14-03 route choice with real waiting. Two guest shafts with real guests at
## real cells; a registered worker physically walks the chosen route. Covers a
## whole-shaft rush detour, shared cabins within capacity with every rider's
## arrival cell, cancellation, route loss on demolition, service-elevator and
## stair congestion pricing, warp-exit congestion, legacy v1 save migration and
## v2 tamper rejection. "-- writer"/"-- reader" add a new-PID rush save check.
const START := Vector3i(1, 0, 0)
const GOAL := Vector3i(2, 1, 0)
const LEGACY_FIXTURE := "res://tests/fixtures/p14-03/legacy_rush_v1"
const LEGACY_COPY := "user://tests/p14_03_legacy_rush_copy"
const PID_SAVE := "user://saves/p14_03_route_new_pid"
const PID_EXPECTED := "user://saves/p14_03_route_new_pid_expected.json"
const PID_CONTINUE := 60
var _checks := 0
var _failures := 0
var _serial := 0
var _clock: Variant
var _state: Variant
var _runtime: Variant
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var args := OS.get_cmdline_user_args()
var mode := "reader" if "reader" in args else ("writer" if "writer" in args else "full")
print("Route wait choice (P14-03) %s pid %d" % [mode, OS.get_process_id()])
_new_runtime()
if mode == "reader":
_read_new_pid()
else:
_layout()
if mode == "writer":
_write_new_pid()
else:
_test_shaft_rush()
_test_worker_walks_detour()
_test_shared_cabin()
_test_route_loss()
_test_service_elevator_wait()
_test_stair_congestion()
_test_warp_exit_congestion()
_test_legacy_v1_migration()
_free_runtime()
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
func _new_runtime() -> void:
_clock = load("res://autoload/game_clock.gd").new()
_state = load("res://autoload/game_state.gd").new()
_runtime = load("res://autoload/simulation_runtime.gd").new()
_clock.reset(1, 6, 0)
_state.reset()
_runtime.initialize(_clock, _state, 1403)
_clock.set_paused(true)
func _free_runtime() -> void:
_runtime.free(); _clock.free(); _state.free()
func _cmd(kind: StringName, payload: Dictionary) -> CommandResult:
_serial += 1
return _runtime.submit_command(kind, payload, &"player", &"", 0, _clock.absolute_minute, StringName("p1403.%d" % _serial))
func _build(id: StringName, origin: Vector3i) -> void:
var result := _cmd(&"build_facility", {&"definition_id": id, &"origin": origin})
_expect(result.is_success(), "build %s at %s %s" % [id, origin, result.message])
func _next_evaluation() -> void:
_clock.advance_minutes(10 - int(_clock.absolute_minute) % 10 + 1)
func _layout() -> void:
_expect(_cmd(&"change_resources", {&"deltas": {&"gold": 40000, &"materials": 400}}).is_success(), "fund the fixture")
# FRONT: warps x-4, shaft A x0 (floors 0-3), shaft B x4 (floors 0-1), floor-1 link x2-3.
# BACK: service shaft x6, security station x-2 for the worker's shift.
_build(&"guest_elevator", Vector3i(0, 0, 0))
_build(&"guest_elevator", Vector3i(4, 0, 0))
_build(&"mana_warp", Vector3i(-4, 0, 0))
_build(&"service_elevator", Vector3i(6, 0, 1))
_build(&"security_station", Vector3i(-2, 0, 1))
_clock.advance_minutes(360)
_build(&"guest_elevator", Vector3i(0, 2, 0))
_build(&"mana_warp", Vector3i(-4, 2, 0))
for x: int in [2, 3]:
_build(&"guest_corridor", Vector3i(x, 1, 0))
_clock.advance_minutes(360)
_next_evaluation()
_expect(_runtime.elevators.get_report()[&"shafts"].size() == 3, "two guest shafts and one service shaft")
func _spawn(guest_id: StringName, cell: Vector3i) -> bool:
var result := _cmd(&"spawn_guest", {&"guest_id": guest_id, &"guest_type_id": &"traveler", &"options": {&"current_cell": cell}})
_expect(result.is_success(), "spawn real guest %s at %s %s" % [guest_id, cell, result.message])
return result.is_success()
func _route() -> Array:
return _runtime.path_service.find_path(START, GOAL)
func _uses_shaft_a(path: Array) -> bool:
return path.size() > 1 and path[1] == Vector3i(0, 0, 0)
func _queue_rush(count: int) -> Array[StringName]:
var riders: Array[StringName] = []
for i: int in count:
var guest_id := StringName("rush_%02d" % i)
if _spawn(guest_id, Vector3i(0, 0, 0)):
var actor_id := StringName("guest:%s" % guest_id)
var trip: Dictionary = _runtime.elevators.request_trip(actor_id, Vector3i(0, 0, 0), Vector3i(0, 3, 0), _clock.absolute_minute)
_expect(bool(trip.get(&"ok", false)), "real guest %s queues for floor 3" % guest_id)
riders.append(actor_id)
return riders
func _shaft_a_link() -> StringName:
return _runtime.path_service.get_step_connector(Vector3i(0, 0, 0), Vector3i(0, 1, 0), [])
func _test_shaft_rush() -> void:
var idle := _route()
var idle_cost: int = _runtime.path_service.last_path_cost
_expect(_uses_shaft_a(idle), "idle tower routes through the nearer shaft A")
var riders := _queue_rush(12)
var rush := _route()
_expect(not _uses_shaft_a(rush) and rush.has(Vector3i(4, 0, 0)), "whole-shaft rush diverts the 0->1 trip to idle shaft B")
_expect(_runtime.path_service.last_path_cost > idle_cost, "diverted route is dearer than the idle one")
_expect(int(_runtime.path_service.get_connector(_shaft_a_link())[&"dynamic_cost"]) == 12 * PathService.ORTHOGONAL_MOVE_COST, "shaft A 0->1 prices all 12 riders waiting elsewhere in the shaft")
var saved: Dictionary = _runtime.create_snapshot()
_expect(int(saved[&"systems"][&"runtime"][&"elevators"][&"version"]) == ElevatorService.SNAPSHOT_VERSION, "new saves carry elevator snapshot v2")
_expect(_runtime.restore_snapshot(saved.duplicate(true)) and _runtime.create_snapshot() == saved, "rush wait costs and queues survive save restore exactly")
for bad: int in [0, 300]:
var tampered: Dictionary = saved.duplicate(true)
for row: Dictionary in tampered[&"systems"][&"runtime"][&"path"][&"connectors"]:
if row[&"id"] == _shaft_a_link(): row[&"dynamic_cost"] = bad
var live: Dictionary = _runtime.create_snapshot()
_expect(not _runtime.restore_snapshot(tampered) and _runtime.create_snapshot() == live, "v2 save with shaft wait %d (disagreeing with its queue) is rejected atomically" % bad)
var a_route_during_rush: int = _runtime.path_service.calculate_path_cost(idle)
for actor_id: StringName in riders:
_runtime.elevators.cancel_actor(actor_id)
_expect(int(_runtime.path_service.get_connector(_shaft_a_link())[&"dynamic_cost"]) == 0, "cancelled rush clears the shaft wait")
_expect(_runtime.path_service.calculate_path_cost(idle) == a_route_during_rush - 12 * PathService.ORTHOGONAL_MOVE_COST, "cleared shaft wait removes exactly the queued riders' cost from shaft A's route")
_expect(_runtime.restore_snapshot(saved), "rewind to the rush state")
func _register_walker(staff_id: StringName, cell: Vector3i) -> bool:
var registered := _cmd(&"register_staff", {&"staff_id": staff_id, &"role_id": &"porter", &"options": {
&"current_cell": cell, &"state": StaffRuntime.State.OFF_DUTY, &"role_tags": [&"porter"],
&"permitted_task_tags": [&"work"], &"skills": {&"operation": 50}}})
var station: FacilityInstance = null
for facility: FacilityInstance in _runtime.facility_service.get_instances():
if facility.definition_id == &"security_station": station = facility
var minute: int = posmod(_clock.absolute_minute, 1440)
var shift := _cmd(&"create_staff_shift", {&"staff_id": staff_id, &"template_id": &"FLEX", &"start_day": _clock.absolute_minute / 1440,
&"start_minute_of_day": minute, &"end_minute_of_day": mini(minute + 600, 1439), &"facility_id": station.instance_id})
_expect(registered.is_success() and shift.is_success(), "register real walker %s at %s %s %s" % [staff_id, cell, registered.message, shift.message])
return registered.is_success() and shift.is_success()
## Sends the walker to GOAL through an ordinary Staff task; returns visited cells.
func _walk(staff_id: StringName, task_id: StringName) -> Array:
var created := _cmd(&"create_staff_task", {&"task_id": task_id, &"task_type": &"inspect", &"priority": 90, &"options": {
&"target_cell": GOAL, &"required_role_tags": [&"porter"], &"task_tags": [&"work"], &"estimated_minutes": 1}})
_expect(created.is_success(), "walk task %s created %s" % [task_id, created.message])
var visited: Array = []
for minute: int in 180:
_clock.advance_minutes(1)
var worker: StaffRuntime = _runtime.staff_service.get_staff(staff_id)
if worker == null:
break
if visited.is_empty() or visited.back() != worker.current_cell:
visited.append(worker.current_cell)
if worker.current_cell == GOAL:
break
return visited
func _test_worker_walks_detour() -> void:
# Still in the rush state saved above: shaft A has 12 riders queued.
var before: Dictionary = _runtime.create_snapshot()
if not _register_walker(&"walker_rush", START):
return
var visited := _walk(&"walker_rush", &"walk_rush")
_expect(not visited.is_empty() and visited.back() == GOAL, "real walker reaches the goal during the rush")
_expect(visited.has(Vector3i(4, 0, 0)) and visited.has(Vector3i(4, 1, 0)), "walker physically rides shaft B (%s)" % [visited])
_expect(not visited.has(Vector3i(0, 1, 0)), "walker never rides the congested shaft A")
_expect(_runtime.restore_snapshot(before), "rewind walker drill")
func _shaft_id_at(x: int, layer: int) -> StringName:
for shaft: Dictionary in _runtime.elevators.get_report()[&"shafts"]:
var bottom: Vector3i = (shaft[&"stops"] as Array).front()
if bottom.x == x and bottom.z == layer:
return shaft[&"shaft_id"]
return &""
func _test_shared_cabin() -> void:
var before: Dictionary = _runtime.create_snapshot()
for trip: Dictionary in _runtime.elevators.get_report()[&"trips"]:
_runtime.elevators.cancel_actor(StringName(trip[&"actor_id"]))
var riders: Array[StringName] = []
for i: int in 6:
var guest_id := StringName("share_%02d" % i)
if not _spawn(guest_id, Vector3i(4, 0, 0)):
continue
# Real guest with a floor-1 destination; the Runtime's own path travel
# requests the elevator ride (no test-side trip injection).
var guest: GuestRuntime = _runtime.guest_service.get_guest(guest_id)
guest.path_handle = {&"target_cell": Vector3i(4, 1, 0)}
_expect(bool(_runtime.guest_service.transition_guest(guest_id, GuestRuntime.State.ENTERING, _clock.absolute_minute, &"TEST_ENTRY").get(&"ok", false))
and bool(_runtime.guest_service.transition_guest(guest_id, GuestRuntime.State.MOVING, _clock.absolute_minute, &"TEST_DESTINATION").get(&"ok", false)), "rider %s heads for floor 1" % guest_id)
riders.append(StringName("guest:%s" % guest_id))
var requested := {}
var leaver: StringName = &""
var shaft_b := _shaft_id_at(4, 0)
var max_boarded := 0
var arrival_cell := {}
for minute: int in 60:
_clock.advance_minutes(1)
var boarded := 0
for trip: Dictionary in _runtime.elevators.get_report()[&"trips"]:
if trip[&"shaft_id"] == shaft_b and trip[&"state"] == PathService.ELEVATOR_REQUEST_BOARDED:
boarded += 1
if leaver.is_empty():
# A boarded guest told to leave (patience/closing) must ride on.
leaver = StringName(trip[&"actor_id"])
_expect(bool(_runtime.guest_service.begin_leaving(StringName(String(leaver).trim_prefix("guest:")), _clock.absolute_minute, &"TEST_LEAVE_WHILE_ABOARD").get(&"ok", false)), "boarded rider %s starts leaving mid-ride" % leaver)
max_boarded = maxi(max_boarded, boarded)
for actor_id: StringName in riders:
if not _runtime.elevators.get_actor_trip(actor_id).is_empty():
requested[actor_id] = true
continue
if arrival_cell.has(actor_id) or not requested.has(actor_id):
continue
var guest: GuestRuntime = _runtime.guest_service.get_guest(StringName(String(actor_id).trim_prefix("guest:")))
arrival_cell[actor_id] = guest.current_cell if guest != null else null
_expect(max_boarded > 1 and max_boarded <= 4, "riders share the cabin up to its capacity of 4 (max %d)" % max_boarded)
_expect(requested.size() == riders.size(), "the Runtime requested a ride for every rider")
var arrived_at := -1
var despawned_at := -1
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if not (leaver in event.entity_ids or StringName(String(leaver).trim_prefix("guest:")) in event.entity_ids):
continue
if event.event_type == &"ELEVATOR_ARRIVED" and event.payload.get(&"cell") == Vector3i(4, 1, 0):
arrived_at = event.absolute_minute
if event.event_type == &"GUEST_DESPAWNED":
despawned_at = event.absolute_minute
_expect(not leaver.is_empty() and arrived_at >= 0 and (despawned_at < 0 or despawned_at >= arrived_at), "a rider leaving mid-ride rides on and alights at the floor-1 landing before it can leave (arrived %d, left %d)" % [arrived_at, despawned_at])
_expect(arrival_cell.size() == riders.size(), "every rider's trip ends")
for actor_id: StringName in riders:
if actor_id == leaver:
continue
_expect(arrival_cell.get(actor_id) == Vector3i(4, 1, 0), "%s exists and stands on the floor-1 landing when the ride ends (%s)" % [actor_id, arrival_cell.get(actor_id)])
_expect(_runtime.restore_snapshot(before), "rewind shared-cabin drill")
func _test_route_loss() -> void:
var before: Dictionary = _runtime.create_snapshot()
for trip: Dictionary in _runtime.elevators.get_report()[&"trips"]:
_runtime.elevators.cancel_actor(StringName(trip[&"actor_id"]))
var shaft_b_facility: StringName = &""
for facility: Dictionary in _runtime.construction_service.get_facilities():
if facility[&"definition_id"] == &"guest_elevator" and facility[&"origin"] == Vector3i(4, 0, 0):
shaft_b_facility = facility[&"instance_id"]
_expect(_cmd(&"demolish_facility", {&"instance_id": shaft_b_facility}).is_success(), "demolish shaft B")
_expect(_uses_shaft_a(_route()), "route loss falls back to the remaining shaft")
if _register_walker(&"walker_loss", START):
var visited := _walk(&"walker_loss", &"walk_loss")
_expect(not visited.is_empty() and visited.back() == GOAL and visited.has(Vector3i(0, 1, 0)), "real walker reaches the goal through shaft A after the loss (%s)" % [visited])
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "post-loss state restores")
_expect(_runtime.restore_snapshot(before), "rewind route-loss drill")
func _test_service_elevator_wait() -> void:
var ps: PathService = _runtime.path_service
var lower := Vector3i(6, 0, 1)
var upper := Vector3i(6, 1, 1)
var staff_only: Array[StringName] = [&"staff"]
var layers: Array[int] = [WorldService.LAYER_FRONT, WorldService.LAYER_BACK]
_expect(ps.find_path(lower, upper).is_empty() and not ps.find_path(lower, upper, layers, staff_only).is_empty(), "service shaft is staff-only")
var idle_cost: int = ps.last_path_cost
var before: Dictionary = _runtime.create_snapshot()
for i: int in 4:
var staff_id := StringName("svc_rider_%d" % i)
_expect(_cmd(&"register_staff", {&"staff_id": staff_id, &"role_id": &"porter", &"options": {&"current_cell": lower, &"state": StaffRuntime.State.OFF_DUTY, &"role_tags": [&"porter"]}}).is_success(), "register real worker %s on the service landing" % staff_id)
_expect(bool(_runtime.elevators.request_trip(StringName("staff:%s" % staff_id), lower, upper, _clock.absolute_minute, staff_only).get(&"ok", false)), "real worker %s queues on the service shaft" % staff_id)
ps.find_path(lower, upper, layers, staff_only)
_expect(ps.last_path_cost > idle_cost, "queued workers raise the service elevator's A* cost")
_expect(_runtime.restore_snapshot(before), "rewind service drill")
func _test_stair_congestion() -> void:
var ps: PathService = _runtime.path_service
var before: Dictionary = _runtime.create_snapshot()
_expect(_cmd(&"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(-1, 1, 0)}).is_success(), "build a floor-1 corridor beside shaft A")
_expect(_cmd(&"build_facility", {&"definition_id": &"guest_stairs", &"origin": Vector3i(-2, 1, 0)}).is_success(), "build stairs to floor 1")
_clock.advance_minutes(20)
var landing := Vector3i(-2, 1, 0)
var foot := Vector3i(-2, 0, 0)
var quiet: Array = ps.find_path(foot, landing)
var quiet_cost: int = ps.last_path_cost
_expect(quiet == [foot, landing], "stairs connect the two floors")
for i: int in 6:
_spawn(StringName("stair_crowd_%d" % i), landing)
ps.find_path(foot, landing)
_expect(ps.last_path_cost > quiet_cost, "a crowded stair landing raises the stair route's A* cost")
_expect(_runtime.restore_snapshot(before), "rewind stair drill")
func _test_warp_exit_congestion() -> void:
var ps: PathService = _runtime.path_service
var lower := Vector3i(-4, 0, 0)
var upper := Vector3i(-4, 2, 0)
var quiet: Array = ps.find_path(lower, upper)
var quiet_cost: int = ps.last_path_cost
_expect(quiet == [lower, upper], "idle warp is the cheapest way up")
var crowd := 0
for i: int in 6:
if _spawn(StringName("crowd_%02d" % i), upper):
crowd += 1
ps.find_path(lower, upper)
_expect(crowd > 0 and ps.last_path_cost > quiet_cost, "a crowded warp exit raises the warp route's A* cost")
## A genuine save written by 50ceca0 (pre-P14-03, elevator snapshot v1) with 12
## riders queued for floor 3 and every elevator dynamic_cost 0.
func _test_legacy_v1_migration() -> void:
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(LEGACY_COPY))
for member: String in ["world.bin", "manifest.json", "thumbnail.png", "journal.log"]:
var bytes := FileAccess.get_file_as_bytes(LEGACY_FIXTURE.path_join(member))
var file := FileAccess.open(LEGACY_COPY.path_join(member), FileAccess.WRITE)
file.store_buffer(bytes)
file.close()
var loaded := SaveService.load_snapshot(LEGACY_COPY)
_expect(loaded[&"ok"], "legacy v1 package loads from disk")
if not loaded[&"ok"]:
return
var legacy: Dictionary = loaded[&"snapshot"]
_expect(int(legacy[&"systems"][&"runtime"][&"elevators"][&"version"]) == 1, "fixture really is elevator snapshot v1")
var live: Dictionary = _runtime.create_snapshot()
var bad: Dictionary = legacy.duplicate(true)
for row: Dictionary in bad[&"systems"][&"runtime"][&"path"][&"connectors"]:
if String(row[&"id"]).begins_with("transport.") and int(row[&"dynamic_cost"]) == 0:
row[&"dynamic_cost"] = 500
break
_expect(not _runtime.restore_snapshot(bad) and _runtime.create_snapshot() == live, "v1 save with a nonzero wait (never written by v1) is rejected atomically")
_expect(_runtime.restore_snapshot(legacy.duplicate(true)), "legacy v1 rush save migrates")
_expect(int(_runtime.path_service.get_connector(_shaft_a_link())[&"dynamic_cost"]) == 12 * PathService.ORTHOGONAL_MOVE_COST, "migration derives the shaft-wide wait from the legacy queue")
_expect(not _uses_shaft_a(_route()), "migrated rush diverts like a fresh one")
var migrated: Dictionary = _runtime.create_snapshot()
_expect(int(migrated[&"systems"][&"runtime"][&"elevators"][&"version"]) == ElevatorService.SNAPSHOT_VERSION and _runtime.restore_snapshot(migrated) and _runtime.create_snapshot() == migrated, "migrated state saves as v2 and round-trips exactly")
SaveService.delete_save(LEGACY_COPY)
func _write_new_pid() -> void:
_queue_rush(12)
_register_walker(&"walker_pid", START)
var snapshot: Dictionary = _runtime.create_snapshot()
var serial_at_save := _serial
_expect(SaveService.save_snapshot(PID_SAVE, snapshot)[&"ok"], "writer saves the rush state")
var visited := _walk(&"walker_pid", &"walk_pid")
_clock.advance_minutes(maxi(PID_CONTINUE - visited.size(), 0))
var file := FileAccess.open(PID_EXPECTED, FileAccess.WRITE)
file.store_string(JSON.stringify({"writer_pid": OS.get_process_id(), "serial_at_save": serial_at_save, "visited": var_to_str(visited),
"minute": _clock.absolute_minute, "digest": SimulationDigest.compute(_runtime.create_snapshot())}))
file.close()
_expect(not visited.is_empty() and visited.back() == GOAL and visited.has(Vector3i(4, 1, 0)), "writer walker reaches the goal through shaft B")
func _read_new_pid() -> void:
var expected: Variant = JSON.parse_string(FileAccess.get_file_as_string(PID_EXPECTED))
_expect(expected is Dictionary, "reader finds writer record")
if not expected is Dictionary:
return
_expect(int(expected["writer_pid"]) != OS.get_process_id(), "reader runs in a different process")
var loaded := SaveService.load_snapshot(PID_SAVE)
_expect(loaded[&"ok"] and _runtime.restore_snapshot(loaded[&"snapshot"]), "reader restores the rush save")
_expect(int(_runtime.path_service.get_connector(_shaft_a_link())[&"dynamic_cost"]) == 12 * PathService.ORTHOGONAL_MOVE_COST, "restored shaft wait matches the queue")
# Same player command sequence as the writer after its save.
_serial = int(expected["serial_at_save"])
var visited := _walk(&"walker_pid", &"walk_pid")
_clock.advance_minutes(maxi(PID_CONTINUE - visited.size(), 0))
_expect(var_to_str(visited) == String(expected["visited"]), "walker takes the same physical route after restart")
_expect(_clock.absolute_minute == int(expected["minute"]) and SimulationDigest.compute(_runtime.create_snapshot()) == String(expected["digest"]), "whole continued state digest matches the writer")
SaveService.delete_save(PID_SAVE)
DirAccess.remove_absolute(ProjectSettings.globalize_path(PID_EXPECTED))
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)
@@ -0,0 +1 @@
uid://btfqo5k3jf8p2
+1 -1
View File
@@ -16,7 +16,7 @@ func _run() -> void:
_state = load("res://autoload/game_state.gd").new()
_reset()
_expect(_runtime.path_service.get_vertical_walk_requires_connector(), "new Runtime requires explicit vertical transport")
_expect(_runtime.definition_registry.facility_count() == 23, "Runtime registers baseline16, stairs, infirmary and premium room/dormitory and chapel")
_expect(_runtime.definition_registry.facility_count() == 25, "Runtime registers baseline16, stairs, infirmary, premium room/dormitory, chapel and A07/A08 warps")
var before: Dictionary = _runtime.create_snapshot()
var invalid := _command(&"build_facility", {&"definition_id": &"guest_stairs", &"origin": Vector3i(4, 3, 0)})
_expect(not invalid.is_success() and invalid.details.get(&"reason") == &"STAIR_LANDING_MISSING", "stairs without a lower landing reject before any construction")
+3 -2
View File
@@ -1,4 +1,5 @@
extends SceneTree
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd")
var _finishing := false
@@ -128,7 +129,7 @@ func _verify_mid_ride() -> bool:
_expect(_runtime.restore_snapshot(snapshot), "rewind depletion drill to original passenger state")
for cell: Vector3i in shaft[&"stops"]:
_runtime.path_service.configure_cell_traffic(cell, 4, 0, true)
_state.set_resource(&"mana", 0)
ManaOutage.hold(_runtime, _state)
_clock.advance_minutes(1)
for actor_id: StringName in riders:
_expect(_runtime.elevators.get_actor_trip(actor_id).get(&"state") == PathService.ELEVATOR_REQUEST_BOARDED, "no safe landing retains boarded passenger instead of teleporting")
@@ -140,7 +141,7 @@ func _verify_mid_ride() -> bool:
_expect(_runtime.restore_snapshot(held_snapshot) and _runtime.create_snapshot() == held_snapshot, "no-landing outage preserves full Runtime save and passenger ownership")
for cell: Vector3i in shaft[&"stops"]:
_runtime.path_service.configure_cell_traffic(cell)
_state.set_resource(&"mana", 100)
ManaOutage.release(_runtime, _state)
_clock.advance_minutes(45)
for actor_id: StringName in riders:
_expect(_runtime.elevators.get_actor_trip(actor_id).is_empty() and _runtime.path_service.get_active_elevator_request(actor_id).is_empty(), "landing repair and power restoration release held trip ownership")
+199
View File
@@ -0,0 +1,199 @@
extends SceneTree
## A07 Mana warp through ordinary construction, natural guests and the reserve.
## "-- writer" (default) runs the mechanics and saves mid-operation; "-- reader"
## restores that save in a new process and must reproduce the writer exactly.
const Warp = preload("res://scripts/transport/warp_service.gd")
const ManaOutage = preload("res://tests/helpers/mana_outage.gd")
const SAVE_PATH := "user://saves/p14_02_warp_new_pid"
const EXPECTED_PATH := "user://saves/p14_02_warp_new_pid_expected.json"
const CONTINUE_MINUTES := 120
var _checks := 0
var _failures := 0
var _serial := 0
var _clock: Variant
var _state: Variant
var _runtime: Variant
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var mode := "reader" if "reader" in OS.get_cmdline_user_args() else "writer"
print("Warp runtime %s (pid %d)" % [mode, OS.get_process_id()])
_clock = load("res://autoload/game_clock.gd").new()
_state = load("res://autoload/game_state.gd").new()
_runtime = load("res://autoload/simulation_runtime.gd").new()
_clock.reset(1, 6, 0)
_state.reset()
_runtime.initialize(_clock, _state, 8808)
_runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
_clock.set_paused(true)
_expect(bool(_runtime.enable_production_operations().get(&"ok", false)), "natural operations start at Day 1 06:00")
if mode == "writer":
_write()
else:
_read()
_runtime.free(); _clock.free(); _state.free()
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
func _cmd(kind: StringName, payload: Dictionary) -> CommandResult:
_serial += 1
return _runtime.submit_command(kind, payload, &"player", &"", 0, _clock.absolute_minute, StringName("warp.test.%d" % _serial))
func _build(id: StringName, origin: Vector3i) -> bool:
var result := _cmd(&"build_facility", {&"definition_id": id, &"origin": origin})
_expect(result.is_success(), "build %s at %s %s" % [id, origin, result.message])
return result.is_success()
func _warp_connectors() -> Array[StringName]:
return _runtime.path_service.get_connector_ids_with_prefix(Warp.PREFIX)
func _warp_events() -> Array[Dictionary]:
var rows: Array[Dictionary] = []
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if event.event_type == &"WARP_TRAVELED":
rows.append({&"minute": event.absolute_minute, &"mana": int(event.payload[&"mana"])})
return rows
func _write() -> void:
_expect(_cmd(&"change_resources", {&"deltas": {&"gold": 12000, &"materials": 100}}).is_success(), "fund four warps for the fixture")
var gold_before: int = _state.get_resource(&"gold")
if not _build(&"mana_warp", Vector3i(0, 0, 0)) or not _build(&"reception", Vector3i(2, 0, 0)):
return
_expect(gold_before - int(_state.get_resource(&"gold")) >= 3000, "warp construction charges its approved 3000G")
_clock.advance_minutes(359)
_expect(_warp_connectors().is_empty(), "a single warp has no destination")
_clock.advance_minutes(1)
if not _build(&"mana_warp", Vector3i(0, 2, 0)) or not _build(&"standard_room", Vector3i(2, 2, 0)):
return
_clock.advance_minutes(360)
_expect(_runtime.path_service.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0)).is_empty(), "new warp waits for its first power evaluation")
_clock.advance_minutes(10 - int(_clock.absolute_minute) % 10)
var ids := _warp_connectors()
_expect(ids.size() == 1, "two completed warps are linked by one connector")
if ids.size() != 1:
return
var connector: Dictionary = _runtime.path_service.get_connector(ids[0])
_expect(connector[&"from"] == Vector3i(0, 0, 0) and connector[&"to"] == Vector3i(0, 2, 0) and connector[&"operational_state"] == PathService.CONNECTOR_OPERATIONAL, "connector joins both warp origins and is operational")
_expect(_runtime.path_service.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0)) == [Vector3i(0, 0, 0), Vector3i(0, 2, 0)], "path crosses floors in one instant step")
_expect(_runtime.mana_network_service.get_total_consumer_demand() >= 2, "each warp registers 1 Mana upkeep")
_expect(_runtime.path_service.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0), [WorldService.LAYER_FRONT, WorldService.LAYER_BACK], [&"staff"]).is_empty(), "staff routes never use the guest warp (A08)")
_expect(_build(&"service_warp", Vector3i(0, 0, 1)), "build lower BACK service warp")
_clock.advance_minutes(360)
_expect(_build(&"service_warp", Vector3i(0, 2, 1)), "build upper BACK service warp on the completed one")
_clock.advance_minutes(360)
_clock.advance_minutes(10 - int(_clock.absolute_minute) % 10)
_expect(_warp_connectors().size() == 2, "service warps link only to each other, never to guest warps")
var staff_route: Array = _runtime.path_service.find_path(Vector3i(0, 0, 1), Vector3i(0, 2, 1), [WorldService.LAYER_FRONT, WorldService.LAYER_BACK], [&"staff"])
_expect(staff_route == [Vector3i(0, 0, 1), Vector3i(0, 2, 1)], "staff cross floors through the BACK service warp")
_expect(_runtime.path_service.find_path(Vector3i(0, 0, 1), Vector3i(0, 2, 1)).is_empty(), "guests cannot use the service warp")
_expect(_runtime.call(&"_warp_step_connector", Vector3i(0, 0, 1), Vector3i(0, 2, 1), [&"staff"] as Array[StringName]) != &"", "a staff step through the service warp is fare-bearing")
# Outage and an unaffordable fare both remove the warp from routing.
var before_outage: Dictionary = _runtime.create_snapshot()
ManaOutage.hold(_runtime, _state)
_clock.advance_minutes(1)
_expect(_runtime.path_service.get_connector(ids[0])[&"operational_state"] == PathService.CONNECTOR_OUTAGE, "reserve outage stops the warp")
_expect(_runtime.path_service.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0)).is_empty(), "stopped warp offers no route")
_expect(_runtime.path_service.find_path_report(Vector3i(0, 0, 0), Vector3i(0, 2, 0))[&"reason"] == PathService.ROUTE_CONNECTOR_UNAVAILABLE, "guest sees the stopped warp as an unavailable connector")
ManaOutage.release(_runtime, _state, Warp.MANA_PER_TRIP - 1)
_clock.advance_minutes(1)
_expect(_runtime.path_service.get_connector(ids[0])[&"operational_state"] == PathService.CONNECTOR_OUTAGE, "reserve below one fare keeps the warp closed")
_expect(_runtime.restore_snapshot(before_outage), "rewind outage drill")
_clock.advance_minutes(1)
var mana_blocked: int = _state.get_resource(&"mana")
_runtime.path_service.set_cell_temporary_block(Vector3i(0, 2, 0), true)
_expect(_runtime.path_service.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0)).is_empty()
and _runtime.call(&"_warp_step_connector", Vector3i(0, 0, 0), Vector3i(0, 2, 0), [] as Array[StringName]) == &"", "blocked arrival offers no warp step and no fare")
_expect(_state.get_resource(&"mana") == mana_blocked, "blocked arrival charges nothing")
_expect(_runtime.restore_snapshot(before_outage), "rewind arrival drill")
# Natural guests use the warp; each crossing charges exactly 3 Mana once.
_expect(_cmd(&"hire_staff_candidate", {&"candidate_id": &"staff_akane"}).is_success(), "hire receptionist")
var reception: FacilityInstance = null
for facility: FacilityInstance in _runtime.facility_service.get_instances():
if facility.definition_id == &"reception": reception = facility
_expect(_cmd(&"set_staff_work_assignment", {&"staff_id": &"staff_akane", &"facility_id": reception.instance_id, &"template_id": &"DAY"}).is_success(), "assign receptionist")
var saved := false
var crossings := 0
for minute: int in range(1200):
var mana_before: int = _state.get_resource(&"mana")
var events_before := _warp_events().size()
_clock.advance_minutes(1)
var new_events := _warp_events().size() - events_before
if new_events > 0:
crossings += new_events
var boundary: bool = int(_clock.absolute_minute) % 10 == 0
if not boundary:
_expect(mana_before - int(_state.get_resource(&"mana")) == Warp.MANA_PER_TRIP * new_events, "warp crossing charges 3 Mana per rider")
if not saved:
saved = true
var snapshot: Dictionary = _runtime.create_snapshot()
_expect(SaveService.save_snapshot(SAVE_PATH, snapshot)[&"ok"], "save right after a paid crossing")
_clock.advance_minutes(CONTINUE_MINUTES)
var file := FileAccess.open(EXPECTED_PATH, FileAccess.WRITE)
file.store_string(JSON.stringify({
"writer_pid": OS.get_process_id(),
"saved_events": events_before + new_events,
"mana": _state.get_resource(&"mana"),
"digest": SimulationDigest.compute(_runtime.create_snapshot()),
"events": JSON.stringify(_warp_events()),
}))
file.close()
break
if crossings == 0:
for guest: GuestRuntime in _runtime.guest_service.get_guests():
print("GUEST ", guest.guest_id, " ", guest.state, " ", guest.current_cell)
for facility: FacilityInstance in _runtime.facility_service.get_instances():
print("FAC ", facility.definition_id, " ", facility.state, " ", facility.active_staff_ids)
_expect(crossings > 0, "a natural guest crosses by warp")
_expect(saved, "mid-operation save written")
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "warp state round trips")
# Demolishing one end removes the link.
var upper: StringName = &""
for facility: Dictionary in _runtime.construction_service.get_facilities():
if facility[&"definition_id"] == &"mana_warp" and facility[&"origin"] == Vector3i(0, 2, 0):
upper = facility[&"instance_id"]
var occupied := false
for guest: GuestRuntime in _runtime.guest_service.get_guests():
if guest.current_cell.x <= 1 and guest.current_cell.y >= 2: occupied = true
if not occupied:
_expect(_cmd(&"demolish_facility", {&"instance_id": upper}).is_success(), "demolish upper warp")
_expect(_warp_connectors().is_empty(), "demolition removes the warp link")
_expect(_runtime.restore_snapshot(_runtime.create_snapshot()), "post-demolition state restores")
func _read() -> void:
var expected: Variant = JSON.parse_string(FileAccess.get_file_as_string(EXPECTED_PATH))
_expect(expected is Dictionary, "reader finds writer record")
if not expected is Dictionary:
return
_expect(int(expected["writer_pid"]) != OS.get_process_id(), "reader runs in a different process")
var loaded := SaveService.load_snapshot(SAVE_PATH)
_expect(loaded[&"ok"] and _runtime.restore_snapshot(loaded[&"snapshot"]), "reader restores mid-operation save")
_expect(_warp_events().size() == int(expected["saved_events"]), "restored crossing history is not replayed")
_clock.advance_minutes(CONTINUE_MINUTES)
_expect(_state.get_resource(&"mana") == int(expected["mana"]), "continued Mana matches: no double fare")
_expect(JSON.stringify(_warp_events()) == String(expected["events"]), "continued crossings match the writer")
_expect(SimulationDigest.compute(_runtime.create_snapshot()) == String(expected["digest"]), "whole continued state digest matches")
SaveService.delete_save(SAVE_PATH)
DirAccess.remove_absolute(ProjectSettings.globalize_path(EXPECTED_PATH))
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)
+1
View File
@@ -0,0 +1 @@
uid://73ewrfw84byc
+4 -1
View File
@@ -64,6 +64,8 @@ func _run() -> void:
_state.set_resource(&"mana", 0)
_expect("停止" in mana_label.text and "0" in mana_label.text, "resource signal visibly identifies zero-reserve outage")
_expect("残量と配電" in mana_label.tooltip_text and "休止は解除されません" in mana_label.tooltip_text, "mana HUD explains recovery without promising suspension reset")
_expect("供給 +20" in mana_label.tooltip_text and "消費 −" in mana_label.tooltip_text and "蓄積 0/300" in mana_label.tooltip_text, "mana HUD shows A06 supply, consumption and storage")
_expect(mana_label.text.ends_with("/300・停止"), "mana HUD shows capacity with outage")
if OS.get_environment("THE_TREE_MANA_CAPTURE") == "1":
await process_frame
await RenderingServer.frame_post_draw
@@ -129,7 +131,8 @@ func _run() -> void:
)
await _test_defense_notice()
var palette := _main.find_child("BuildPalette", true, false) as GridContainer
_expect(palette.get_child_count() == 23, "all23 facilities including the cleaning room appear in the build palette")
_expect(palette.get_child_count() == 25, "all25 facilities including the cleaning room and both A07/A08 warps appear in the build palette")
_expect((_main.get("build_buttons") as Dictionary).has(&"mana_warp") and (_main.get("build_buttons") as Dictionary).has(&"service_warp"), "guest and service Mana warps are buildable from the ordinary palette")
var iconized_build_buttons := 0
for build_button_value: Variant in (_main.get("build_buttons") as Dictionary).values():
if (build_button_value as Button).icon != null:
+3 -3
View File
@@ -8,9 +8,9 @@ class PalettePlacement extends Placement:
expect(palette != null, "production facility palette exists")
if palette == null:
return
expect(palette.get_child_count() == 23 and palette.columns == 23,
"palette has exactly 23 facility slots")
expect(main.build_buttons.size() == 23, "all 23 registered facility buttons exist")
expect(palette.get_child_count() == 25 and palette.columns == 25,
"palette has exactly 25 facility slots (A07/A08 warps added)")
expect(main.build_buttons.size() == 25, "all 25 registered facility buttons exist")
for child: Node in palette.get_children():
expect(child is Button and main.build_buttons.values().has(child),
"every palette child is a registered facility button")
+3 -3
View File
@@ -191,7 +191,7 @@
"new_audio_QA": false
},
"tests/ui/test_main_dashboard.gd": {
"source_sha256": "fa9ee0c4b9aee00a2be6d05a9dab7c0c3e8b0beb2b944257de1dc308bfc3cc20",
"source_sha256": "305227c1077a92ef3ee522b561a68b0685767740b46b51ff789c800931647ef1",
"ordinary_cleanup_prepared": false,
"ordinary_control_labels": [],
"old_bounded_teardown": true,
@@ -379,7 +379,7 @@
"source_only_ownership_review": true
},
"tests/transport/test_runtime_transport.gd": {
"source_sha256": "ec6f8fa8e8f2a76a6f6214b4ee84861aba1bb13845a342c5126905b01f428a15",
"source_sha256": "78a5563ff2421ae65a0988cf0d26669f54bcc0f44250b00e5334cadf1228da94",
"ordinary_cleanup_prepared": true,
"ordinary_control_labels": [
"single"
@@ -407,7 +407,7 @@
"new_audio_QA": false
},
"tests/ui/test_p08_normal_placement_ops.gd": {
"source_sha256": "d3c246d34f8fd66f6ed237e42a86df89ebaf481bc9dee143b4de8d654ce0eb2e",
"source_sha256": "a5c5abdc1348e7dadafd70f73072ac98afcc4c918211c3389e88da5e903af803",
"ordinary_cleanup_prepared": true,
"ordinary_control_labels": [
"single"