265 lines
21 KiB
GDScript
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))
|