Files
TheTree_mock/tests/supply/test_supply_auto_purchase_boundaries.gd

265 lines
21 KiB
GDScript

extends SceneTree
## Supplemental P05 QA only. Actual paid construction/purchases and porter paths
## are used. Capacity pressure, cargo lot expiry, callback failures and a ledger
## refund are explicit boundary fixtures, not normal-business success evidence.
var runtime: Variant
var clock: Variant
var state: Variant
var warehouse: StringName
var second: StringName
var kitchen: StringName
var checks := 0
var failures := 0
var output := ""
var observations: Array[Dictionary] = []
const PORTER := &"staff_gina"
const RETURN_REQUEST := &"supply.boundary_return"
func _initialize() -> void:
call_deferred("_run")
func expect(ok: bool, label: String) -> void:
checks += 1
if ok:
print(" ✓ ", label)
else:
failures += 1
push_error(label)
func _run() -> void:
output = OS.get_environment("THE_TREE_AUTO_BOUNDARY_OUTPUT")
var user_dir := OS.get_environment("THE_TREE_AUTO_PURCHASE_EXPECTED_USER_DIR")
var res_dir := OS.get_environment("THE_TREE_AUTO_PURCHASE_EXPECTED_RES_DIR")
var profile := OS.get_environment("THE_TREE_AUTO_PURCHASE_EXPECTED_PROFILE")
var external_evidence: bool = not output.is_empty()
var valid := false
if external_evidence:
valid = output.is_absolute_path() and DirAccess.dir_exists_absolute(output) and not FileAccess.file_exists(output.path_join("boundaries.json")) and user_dir.is_absolute_path() and OS.get_user_data_dir() == user_dir and res_dir.is_absolute_path() and ProjectSettings.globalize_path("res://").simplify_path().trim_suffix("/") == res_dir.simplify_path().trim_suffix("/") and not profile.is_empty() and bool(ProjectSettings.get_setting("application/config/use_custom_user_dir", false)) and ProjectSettings.get_setting("application/config/custom_user_dir_name", "") == profile
else:
# Standard regression needs no external output/guards. Use only a new
# process-specific tests child, never a player slot or res:// source file.
var relative := "user://tests/supply_auto_boundaries_%d_%d" % [OS.get_process_id(), Time.get_ticks_usec()]
output = ProjectSettings.globalize_path(relative).simplify_path()
var allowed_parent := OS.get_user_data_dir().path_join("tests").simplify_path()
valid = user_dir.is_empty() and res_dir.is_empty() and profile.is_empty() and output.get_base_dir() == allowed_parent and not DirAccess.dir_exists_absolute(output)
if valid: valid = DirAccess.make_dir_recursive_absolute(output) == OK
profile = ProjectSettings.get_setting("application/config/custom_user_dir_name", "")
if not valid:
push_error("P05_AUTO_BOUNDARIES requires exact fresh actual profile/resource/output guards")
quit(91)
return
runtime = root.get_node("SimulationRuntime")
clock = root.get_node("GameClock")
state = root.get_node("GameState")
clock.set_process(false)
_storage_and_incoming()
_local_power_and_suspension()
_operations_deferred()
_operations_quarantine()
_unpaid_expenses()
_returned_cargo()
var file := FileAccess.open(output.path_join("boundaries.json"), FileAccess.WRITE)
expect(file != null, "fresh boundary summary opens")
if file != null:
file.store_string(JSON.stringify({"checks": checks, "failures": failures, "actual_user_data_dir": OS.get_user_data_dir(), "actual_resource_dir": ProjectSettings.globalize_path("res://"), "actual_profile": profile, "output": output, "external_evidence": external_evidence, "observations": observations, "normal_business_acceptance": false, "p05_full_acceptance": false}, "\t", true, true) + "\n")
file.close()
print("Supply auto purchase boundaries: %d checks, %d failures" % [checks, failures])
print("P05_AUTO_BOUNDARY_OUTPUT ", output)
quit(1 if failures > 0 else 0)
func fresh(rows: Array = [[&"warehouse", Vector3i(-8, 0, 1)]], operations := false) -> bool:
warehouse = &""
second = &""
kitchen = &""
clock.reset(1, 6, 0)
state.reset()
expect(runtime.initialize(clock, state, 420_505)[&"valid"], "canonical14 Runtime resets")
clock.set_paused(true)
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
if operations:
expect(runtime.enable_production_operations()[&"ok"], "actual Operations enable at original Day1 06:00 before construction")
for row: Array in rows:
expect(runtime.submit_command(&"build_facility", {&"definition_id": row[0], &"origin": row[1]}).is_success(), "ordinary paid build: %s" % row[0])
clock.advance_minutes(180)
for facility: FacilityInstance in runtime.facility_service.get_instances():
if facility.definition_id == &"warehouse":
if warehouse.is_empty(): warehouse = facility.instance_id
else: second = facility.instance_id
if facility.definition_id == &"kitchen": kitchen = facility.instance_id
expect(not warehouse.is_empty(), "real warehouse completed")
return not warehouse.is_empty()
func inv(id: StringName) -> StringName:
return runtime.facility_service.get_instance(id).local_inventory_id
func stock(id: StringName = &"") -> int:
if id.is_empty(): id = warehouse
return runtime.inventory_service.total_quantity(inv(id), SupplyCatalog.RAW_FOOD)
func plan(target: int, minute: int = -1) -> CommandResult:
return runtime.submit_command(&"set_supply_auto_purchase", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"enabled": true, &"target_stock": target}, &"player", warehouse, 75, minute)
func record(label: String, before: Dictionary, report: Dictionary) -> void:
var after: Dictionary = runtime.create_snapshot()
for row: Array in [["before", before], ["after", after]]:
var path: String = output.path_join(label + "-" + String(row[0]) + ".var")
expect(not FileAccess.file_exists(path), "fresh actual typed boundary snapshot: " + label + "/" + String(row[0]))
var file := FileAccess.open(path, FileAccess.WRITE)
expect(file != null, "typed boundary evidence opens")
if file != null:
file.store_buffer(var_to_bytes(row[1]))
file.close()
observations.append({"boundary": label, "report": report, "before_digest": SimulationDigest.compute(before), "after_digest": SimulationDigest.compute(after), "whole_bytes_equal": var_to_bytes(before) == var_to_bytes(after), "checks_so_far": checks, "failures_so_far": failures})
func _storage_and_incoming() -> void:
if not fresh([[&"warehouse", Vector3i(-8, 0, 1)], [&"warehouse", Vector3i(2, 0, 1)]]): return
expect(not second.is_empty(), "actual second warehouse is inbound source")
if second.is_empty(): return
# Disclosed capacity-pressure seam: actual supported other item, not invented
# commodity/capacity or ordinary free-stock success evidence.
expect(runtime.inventory_service.add_stack(inv(warehouse), SupplyCatalog.BASIC_MEAL, 95, 100, clock.absolute_minute + 720, clock.absolute_minute, 1)[&"ok"], "disclosed95 other-item pressure occupies canonical100 capacity")
expect(runtime.submit_command(&"purchase_supplies", {&"warehouse_id": second, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 6}).is_success(), "inbound6 are actually paid at the source")
expect(runtime.submit_command(&"create_logistics_request", {&"request_id": &"supply.boundary_inbound", &"source_inventory_id": inv(second), &"destination_inventory_id": inv(warehouse), &"item_requirements": {SupplyCatalog.RAW_FOOD: 6}}).is_success(), "actual reserved inbound6 request targets the receiver")
expect(plan(10).is_success(), "player arms10 actual enabled auto target")
var before: Dictionary = runtime.create_snapshot()
var report: Dictionary = runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD)
expect(report[&"enabled"] and report[&"incoming_quantity"] == 6 and report[&"deficit"] == 4 and report[&"reason"] == &"STORAGE_FULL", "other95 plus actual inbound6 blocks remaining auto4 with STORAGE_FULL")
expect(runtime.supply_management.advance_auto_purchases(runtime, clock.absolute_minute).is_empty() and var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "STORAGE_FULL enabled auto changes no whole typed state or payment")
record("storage-full-with-inbound", before, report)
var reserved: Dictionary = runtime.inventory_service.reserve(inv(warehouse), SupplyCatalog.BASIC_MEAL, 95, &"boundary.pressure.release", &"TEST", clock.absolute_minute)
expect(reserved.get(&"ok", false), "disclosed pressure release uses actual reservation API")
var ids: Array[StringName] = []
for id: Variant in reserved.get(&"reservation_ids", []): ids.append(StringName(id))
expect(runtime.inventory_service.consume_reservations(ids, &"boundary.pressure.consume", clock.absolute_minute).get(&"ok", false), "pressure releases only its disclosed95 cooked meals")
before = runtime.create_snapshot()
var cash: int = state.get_resource(&"gold")
clock.advance_minutes(1)
expect(stock() == 4 and state.get_resource(&"gold") == cash - 12, "released capacity buys actual deficit4 once, retaining inbound6 deduction")
expect(runtime.restore_snapshot(runtime.create_snapshot()), "enabled auto plus real reserved inbound14 saves strictly")
record("inbound-deducted-purchase", before, runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD))
func _local_power_and_suspension() -> void:
for kind: String in ["local-power", "suspension"]:
if not fresh(): return
expect(plan(6).is_success(), "arm enabled auto before " + kind)
var conditions: Dictionary = {&"power_available": false} if kind == "local-power" else {&"suspension_reason": &"RAIDED"}
expect(runtime.facility_service.set_operational_status(warehouse, conditions, clock.absolute_minute).is_success(), "disclosed public operational boundary: " + kind)
var facility: FacilityInstance = runtime.facility_service.get_instance(warehouse)
expect(state.get_resource(&"mana") > 0 and not facility.allows_logistics(), "global Mana remains available while warehouse local condition blocks " + kind)
var before: Dictionary = runtime.create_snapshot()
var report: Dictionary = runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD)
expect(report[&"enabled"] and report[&"state"] == &"BLOCKED" and report[&"reason"] == &"FACILITY_CLOSED", "owned auto report exposes local blocked receiver: " + kind)
expect(runtime.supply_management.advance_auto_purchases(runtime, clock.absolute_minute).is_empty() and var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "local stopped enabled auto spends/stocks/notifies nothing: " + kind)
record(kind, before, report)
func _operations_deferred() -> void:
if not fresh([[&"warehouse", Vector3i(-8, 0, 1)]], true): return
var due: int = clock.absolute_minute + 30
expect(plan(6, due).is_success(), "actual auto intent is queued for failing Operations boundary")
expect(runtime.set_operations_test_boundary_hook(&"ARRIVAL_PLAN", func(_payload: Dictionary, phase: StringName, _token: Variant) -> Dictionary: return {&"ok": false, &"reason": &"DISCLOSED_BOUNDARY_PREPARE_FAILURE", &"phase": phase}), "disclosed actual prepare fault seam registered")
clock.advance_minutes(30)
var operations: Dictionary = runtime.get_operations_report()
expect(operations[&"tick_blocked"] and operations[&"runtime_failure_latched"] and operations[&"deferred_runtime_minute"] == due and runtime.auto_purchase_plans.get_plan(warehouse, SupplyCatalog.RAW_FOOD)[&"enabled"], "actual deferred suffix is blocked with actual enabled auto intent")
var before: Dictionary = runtime.create_snapshot()
expect(stock() == 0 and runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD)[&"reason"] == &"OPERATIONS_BLOCKED", "deferred boundary never purchases before its skipped suffix")
expect(runtime.supply_management.advance_auto_purchases(runtime, due).is_empty() and var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "deferred enabled auto is whole typed no-op")
record("operations-deferred", before, operations)
expect(runtime.restore_snapshot(before), "actual deferred enabled-auto14 snapshot strictly restores")
var cash: int = state.get_resource(&"gold")
var acknowledged: Dictionary = runtime.acknowledge_operations_pause()
expect(acknowledged.get(&"ok", false) and acknowledged.get(&"suffix_replayed", false) and stock() == 6 and state.get_resource(&"gold") == cash - 18, "explicit actual retry runs deferred suffix and paid auto6 exactly once")
var completed: Dictionary = runtime.create_snapshot()
expect(runtime.supply_management.advance_auto_purchases(runtime, due).is_empty() and var_to_bytes(completed) == var_to_bytes(runtime.create_snapshot()), "retried actual suffix cannot purchase twice in the same minute")
func _quarantine_arrival(payload: Dictionary, phase: StringName, token: Variant) -> Dictionary:
if phase == OperationsCoordinator.PHASE_APPLY:
return {&"ok": false, &"reason": &"DISCLOSED_APPLY_FAILURE"}
if phase == OperationsCoordinator.PHASE_ROLLBACK:
return {&"ok": false, &"reason": &"DISCLOSED_ROLLBACK_UNAVAILABLE"}
return runtime.call("_operations_arrival_boundary", payload, phase, token)
func _operations_quarantine() -> void:
if not fresh([[&"warehouse", Vector3i(-8, 0, 1)]], true): return
var due: int = clock.absolute_minute + 30
expect(plan(6, due).is_success(), "actual auto intent is queued for quarantined boundary")
# Public callback contract, no manual tick_blocked/quarantine flag mutation.
runtime.operations_coordinator.configure_callbacks(Callable(runtime, "_operations_daily_boundary"), Callable(self, "_quarantine_arrival"), Callable(runtime, "_operations_morning_boundary"), Callable(runtime, "_operations_midnight_upkeep_boundary"))
clock.advance_minutes(30)
var operations: Dictionary = runtime.get_operations_report()
expect(runtime.operations_coordinator.is_external_quarantined() and operations[&"tick_blocked"] and runtime.auto_purchase_plans.get_plan(warehouse, SupplyCatalog.RAW_FOOD)[&"enabled"], "actual external rollback failure quarantines owning Coordinator with enabled auto")
var before: Dictionary = runtime.create_snapshot()
expect(stock() == 0 and runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD)[&"reason"] == &"OPERATIONS_BLOCKED", "actual quarantine exposes blocked enabled auto")
expect(runtime.supply_management.advance_auto_purchases(runtime, due).is_empty() and var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "quarantined enabled auto is whole typed no-op")
expect(not runtime.acknowledge_operations_pause().get(&"ok", true), "normal acknowledgement cannot clear external uncertainty")
record("operations-quarantine", before, {"operations": operations, "quarantine": runtime.operations_coordinator.get_quarantine_report()})
func _unpaid_expenses() -> void:
if not fresh([[&"warehouse", Vector3i(-8, 0, 1)]], true): return
clock.advance_minutes(1439 - clock.absolute_minute)
var cash: int = state.get_resource(&"gold")
expect(runtime.economy_service.transfer(&"PLAYER_CASH", &"CONSTRUCTION_EXPENSE", cash, clock.absolute_minute, &"CONSTRUCTION", warehouse, &"boundary.disclosed.budget").is_success(), "disclosed real ledger budget fixture spends cash before midnight")
clock.advance_minutes(1)
var debt: int = runtime.upkeep_settlement.get_arrears_total()
expect(debt > 0 and runtime.operations_coordinator.get_arrears_total() == debt and state.get_resource(&"gold") == 0, "actual midnight accrual creates unpaid upkeep, not crafted debt")
expect(runtime.economy_service.transfer(&"CONSTRUCTION_EXPENSE", &"PLAYER_CASH", 18, clock.absolute_minute, &"CONSTRUCTION_REFUND", warehouse, &"boundary.disclosed.refund").is_success(), "disclosed actual ledger refund funds a6-food order")
expect(plan(6).is_success(), "player arms auto while actual debt remains unpaid")
var before: Dictionary = runtime.create_snapshot()
var settlement: Dictionary = runtime.upkeep_settlement.create_snapshot()
clock.advance_minutes(1)
expect(stock() == 6 and state.get_resource(&"gold") == 0 and runtime.upkeep_settlement.get_arrears_total() == debt, "actual18G paid auto preserves unpaid expense instead of erasing or netting debt")
expect(var_to_bytes(settlement) == var_to_bytes(runtime.upkeep_settlement.create_snapshot()), "procurement leaves all unpaid settlement receipts/history/IDs exact")
expect(runtime.restore_snapshot(runtime.create_snapshot()), "actual paid auto plus unpaid expense14 strictly restores")
record("unpaid-expense-procurement", before, {"actual_arrears": debt, "settlement": settlement, "ordinary_sales_fixture": false})
func _returned_cargo() -> void:
if not fresh([[&"warehouse", Vector3i(-8, 0, 1)], [&"kitchen", Vector3i(2, 0, 1)], [&"staff_door", Vector3i(0, 0, 1)]]): return
expect(not kitchen.is_empty(), "real kitchen destination completes")
if kitchen.is_empty(): return
expect(runtime.submit_command(&"hire_staff_candidate", {&"candidate_id": PORTER}).is_success(), "ordinary paid hire provides real porter")
expect(runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": PORTER, &"facility_id": warehouse, &"template_id": &"DAY"}).is_success(), "real recurring shift assigns warehouse porter")
for minute: int in range(40):
if runtime.staff_service.get_staff(PORTER).state == StaffRuntime.State.AVAILABLE: break
clock.advance_minutes(1)
expect(runtime.staff_service.get_staff(PORTER).state == StaffRuntime.State.AVAILABLE, "porter physically checks in")
expect(runtime.submit_command(&"purchase_supplies", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 8}).is_success(), "all cargo8 originate in ordinary paid purchase")
expect(runtime.submit_command(&"create_logistics_request", {&"request_id": RETURN_REQUEST, &"source_inventory_id": inv(warehouse), &"destination_inventory_id": inv(kitchen), &"item_requirements": {SupplyCatalog.RAW_FOOD: 8}}).is_success(), "actual reserved request starts porter delivery")
for minute: int in range(40):
if runtime.logistics_requests[RETURN_REQUEST].state == LogisticsRequest.State.DELIVERING: break
clock.advance_minutes(1)
var request: LogisticsRequest = runtime.logistics_requests[RETURN_REQUEST]
var cargo: StringName = StringName("cargo:%s" % PORTER)
expect(request.state == LogisticsRequest.State.DELIVERING and stock() == 0 and runtime.inventory_service.total_quantity(cargo, SupplyCatalog.RAW_FOOD) == 8, "real employee picks up8 paid stock into owned cargo")
if request.state != LogisticsRequest.State.DELIVERING: return
clock.advance_minutes(2)
# Disclosed expiry-lot seam preserves the exact8 paid units. No extra or free
# stock is inserted; only half the existing lot expires at the next minute.
var inventory: Dictionary = runtime.inventory_service.create_snapshot()
for owner: Dictionary in inventory[&"inventories"]:
if owner[&"owner_inventory_id"] == String(cargo):
var lot: Dictionary = owner[&"stacks"][0]
lot[&"quantity"] = 4
var expiring: Dictionary = lot.duplicate(true)
expiring[&"stack_id"] = "boundary-expiring-paid-lot"
expiring[&"expires_at"] = clock.absolute_minute + 1
(owner[&"stacks"] as Array).append(expiring)
(inventory[&"known_stack_ids"] as Array).append("boundary-expiring-paid-lot")
expect(runtime.inventory_service.restore_snapshot(inventory), "disclosed expiry split preserves8 actual paid units")
clock.advance_minutes(1)
request = runtime.logistics_requests[RETURN_REQUEST]
expect(runtime.supply_logistics.is_returning(RETURN_REQUEST) and runtime.inventory_service.total_quantity(cargo, SupplyCatalog.RAW_FOOD) == 4, "actual bridge retargets unspoiled paid4 as return cargo")
expect(plan(4).is_success(), "player enables auto4 while actual4 cargo are returning")
var before: Dictionary = runtime.create_snapshot()
var report: Dictionary = runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD)
expect(report[&"enabled"] and report[&"physical_quantity"] == 0 and report[&"incoming_quantity"] == 4 and report[&"deficit"] == 0 and report[&"state"] == &"TARGET_REACHED", "actual return cargo4 satisfies target despite warehouse physical0")
expect(runtime.supply_management.advance_auto_purchases(runtime, clock.absolute_minute).is_empty() and var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "actual incoming return suppresses duplicate whole-state purchase")
record("return-cargo-pending", before, report)
var cash: int = state.get_resource(&"gold")
for minute: int in range(40):
if request.state == LogisticsRequest.State.CANCELLED: break
clock.advance_minutes(1)
expect(request.state == LogisticsRequest.State.CANCELLED and request.state_reason == "CARGO_EXPIRED_RETURNED" and stock() == 4 and state.get_resource(&"gold") == cash, "actual porter return unloads paid4 with no duplicate auto charge")
expect(runtime.inventory_service.total_quantity(cargo, SupplyCatalog.RAW_FOOD) == 0 and runtime.logistics_dispatcher.get_reserved_load(PORTER) == 0 and SupplyLogisticsBridge.validate_crosslinks(runtime.logistics_requests, runtime.staff_service, runtime.inventory_service, runtime.facility_service), "actual return clears cargo/task/reservations/carrier ownership")
expect(runtime.restore_snapshot(runtime.create_snapshot()), "actual completed return plus enabled intent strictly restores14")
record("return-cargo-completed", before, runtime.supply_management.auto_purchase_report(runtime, warehouse, SupplyCatalog.RAW_FOOD))