Files

129 lines
10 KiB
GDScript

extends "res://tests/s3/test_runtime_actor_hardening.gd"
var _observations: Array[Dictionary] = []
var _receipts: Array[Dictionary] = []
var _first_receipts: Array[Dictionary] = []
var _receipt_hook: Callable
var _evidence_dir := ""
var _facility_id: StringName = &""
var _service_id: StringName = &""
var _request_id: StringName = &"p04.order.shift.request"
var _guest_id: StringName = &"p04.order.shift.guest"
var _staff_ids: Array[StringName] = [&"p04.order.server.a", &"p04.order.server.b"]
var _serial := 0
var _observation_pass := "first"
func _run() -> void:
_evidence_dir = OS.get_environment("THE_TREE_ORDER_EVIDENCE")
if _evidence_dir.is_empty(): quit(2); return
_expect(DirAccess.make_dir_recursive_absolute(_evidence_dir) == OK, "fresh external evidence directory")
_reset_runtime(420410)
var facility := _build_cafeteria(true)
if facility == null: _finish_order(); return
_facility_id = facility.instance_id
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(facility.definition_id)
for id: StringName in _staff_ids:
_expect(_cmd(&"register_staff", {&"staff_id": id, &"role_id": &"server", &"options": {&"state": StaffRuntime.State.OFF_DUTY, &"current_cell": Vector3i.ZERO}}).is_success(), "register real Staff actor " + String(id))
_expect(_cmd(&"set_staff_work_assignment", {&"staff_id": id, &"template_id": &"DAY", &"facility_id": _facility_id}).is_success(), "original DAY 06:00-18:00 shift " + String(id))
# Publicly registered Staff actors walk normally. The inherited fixture's
# kitchen cook is explicitly placed at the kitchen and uses its existing FLEX
# shift; this is not natural hiring/unlock or a proof of the whole labor flow.
var boundary := ShiftInstance.DAY_END
var queue_at := boundary - definition.base_service_minutes - 1
_expect(queue_at > _clock.absolute_minute, "real ticks can reach exact admission minute")
_clock.advance_minutes(queue_at - _clock.absolute_minute)
_expect(facility.active_staff_ids == _staff_ids, "both daytime actors are physically projected before service")
for id: StringName in _staff_ids:
var worker: StaffRuntime = _runtime.staff_service.get_staff(id)
_expect(_runtime.staff_service.requires_attendance(id) and StaffCommuteService.is_at_facility(worker, facility) and worker.current_cell != Vector3i.ZERO, "actual workplace arrival and attendance plan " + String(id))
_expect(_stock(facility.local_inventory_id, &"ingredient/basic_meal", 1, &"p04.order.shift.stock"), "one actual meal to reserve")
_expect(_cmd(&"spawn_guest", {&"guest_id": _guest_id, &"guest_type_id": &"traveler", &"gold": definition.base_price * 2, &"options": {&"state": GuestRuntime.State.DECIDING, &"current_cell": Vector3i.ZERO, &"planned_exit_at": boundary + definition.base_service_minutes}}).is_success(), "real public Guest actor and wallet")
_expect(_cmd(&"create_service_request", {&"facility_id": _facility_id, &"request_id": _request_id, &"guest_ids": [_guest_id]}).is_success(), "original price and duration service request")
_clock.advance_one_minute()
var active: Array = _runtime.facility_service.get_active_services(_facility_id)
_expect(active.size() == 1, "exactly one actual service starts")
if active.size() != 1: _finish_order(); return
var service: ServiceInstance = active[0]; _service_id = service.service_id
_expect(service.duration_minutes == definition.base_service_minutes and service.price_snapshot == definition.base_price, "no price or duration override")
_expect(service.started_at + service.duration_minutes == boundary, "normal start plus original duration reaches 18:00 exactly")
_clock.advance_minutes(boundary - 1 - _clock.absolute_minute)
_expect(service.elapsed_minutes == service.duration_minutes - 1, "one real service minute remains at 17:59")
_observe("before-17-59")
var before: Dictionary = _runtime.create_snapshot()
var wallet_before: int = _runtime.economy_service.get_balance(StringName("GUEST_WALLET:" + String(_guest_id)))
_connect_receipts()
_clock.register_tick_handler(_clock.TickPhase.FACILITY_COMPLETION, &"aa.p04.order.observe", func(minute: int):
if minute == boundary: _observe("18-00-before-facility")
)
_clock.register_tick_handler(_clock.TickPhase.FACILITY_COMPLETION, &"zz.p04.order.observe", func(minute: int):
if minute == boundary: _observe("18-00-after-facility")
)
_clock.register_tick_handler(_clock.TickPhase.AI_DECISIONS, &"zz.p04.order.observe", func(minute: int):
if minute == boundary: _observe("18-00-after-staff")
)
_clock.advance_one_minute()
_observe("18-00-tick-complete")
var after: Dictionary = _runtime.create_snapshot()
var wallet_after: int = _runtime.economy_service.get_balance(StringName("GUEST_WALLET:" + String(_guest_id)))
_expect(_clock.absolute_minute == boundary and facility.active_staff_ids.is_empty(), "clock reaches original shift end and removes daytime attendance")
_expect(wallet_after == wallet_before - definition.base_price and _receipts.size() == 1, "approved last DAY interval completes and charges once before handover")
var all_consumed := not service.inventory_reservations.is_empty()
for reservation_id: StringName in service.inventory_reservations:
var reservation: InventoryReservation = _runtime.inventory_service.get_reservation(reservation_id)
if reservation == null or reservation.state != InventoryReservation.State.CONSUMED:
all_consumed = false
_expect(service.state == ServiceInstance.State.COMPLETED and all_consumed and _runtime.inventory_service.available_quantity(facility.local_inventory_id, &"ingredient/basic_meal") == 0, "completed paid service consumed its own real reserved meal exactly once")
_clock.advance_one_minute(); _observe("18-01-tick-complete")
var final: Dictionary = _runtime.create_snapshot()
_first_receipts.assign(_receipts.duplicate(true))
_expect(_runtime.restore_snapshot(before), "restore actual boundary-before whole state")
_observation_pass = "replay"
_receipts.clear(); _connect_receipts(); _clock.advance_one_minute()
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(after), "same boundary replay reproduces all typed state including history")
_clock.advance_one_minute()
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(final), "next minute replay reproduces all typed state")
_expect(_first_receipts.size() == 1 and _receipts.size() == 1, "first pass and snapshot replay each observe exactly one completion payment")
_write_var("before", before); _write_var("after", after); _write_var("next", final)
_finish_order()
func _connect_receipts() -> void:
if _receipt_hook.is_valid() and _runtime.economy_service.transaction_posted.is_connected(_receipt_hook):
_runtime.economy_service.transaction_posted.disconnect(_receipt_hook)
_receipt_hook = func(id: StringName, entries: Array):
var rows: Array = []
for row: LedgerEntry in entries: rows.append(row.to_dictionary())
_receipts.append({&"id": id, &"minute": _clock.absolute_minute, &"rows": rows, &"staff_at_receipt": _runtime.facility_service.get_instance(_facility_id).active_staff_ids.duplicate()})
_runtime.economy_service.transaction_posted.connect(_receipt_hook)
func _cmd(kind: StringName, payload: Dictionary) -> CommandResult:
_serial += 1
return _runtime.submit_command(kind, payload, &"player", &"", 10, -1, StringName("p04.order.shift.command.%d" % _serial))
func _observe(label: String) -> void:
label = _observation_pass + "-" + label
var facility: FacilityInstance = _runtime.facility_service.get_instance(_facility_id)
var service: ServiceInstance = _runtime.facility_service.get_service(_service_id)
var guest: GuestRuntime = _runtime.guest_service.get_guest(_guest_id)
var workers: Array = []
for id: StringName in _staff_ids:
var worker: StaffRuntime = _runtime.staff_service.get_staff(id)
var shift: ShiftInstance = _runtime.staff_service.get_shift(worker.shift_id)
workers.append({&"staff": worker.create_snapshot(), &"shift": shift.create_snapshot() if shift != null else {}, &"is_present": _runtime.staff_commute.is_present(worker, facility), &"requires_attendance": _runtime.staff_service.requires_attendance(id), &"at_facility": StaffCommuteService.is_at_facility(worker, facility), &"within_shift": shift.contains_minute(_clock.absolute_minute) if shift != null else false})
_observations.append({&"label": label, &"minute": _clock.absolute_minute, &"workers": workers, &"facility_state": facility.state, &"active_staff": facility.active_staff_ids.duplicate(), &"service": service.create_snapshot() if service != null else {}, &"request_present": _runtime.facility_service.get_request(_request_id) != null, &"wallet": _runtime.economy_service.get_balance(StringName("GUEST_WALLET:" + String(_guest_id))), &"available_meals": _runtime.inventory_service.available_quantity(facility.local_inventory_id, &"ingredient/basic_meal"), &"reservations": _runtime.inventory_service.create_snapshot(), &"guest": guest.create_snapshot() if guest != null else {}, &"receipts": _receipts.duplicate(true)})
_write_var(label, _runtime.create_snapshot())
func _write_var(label: String, value: Variant) -> void:
var file := FileAccess.open(_evidence_dir.path_join(label + ".var"), FileAccess.WRITE)
_expect(file != null, "write whole typed evidence " + label)
if file != null: file.store_buffer(var_to_bytes(value)); file.flush(); file.close()
var json_file := FileAccess.open(_evidence_dir.path_join(label + ".json"), FileAccess.WRITE)
_expect(json_file != null, "write engine JSON projection alongside authoritative typed evidence " + label)
if json_file != null: json_file.store_string(JSON.stringify(value, "\t")); json_file.flush(); json_file.close()
func _finish_order() -> void:
var file := FileAccess.open(_evidence_dir.path_join("observations.json"), FileAccess.WRITE)
if file != null:
file.store_string(JSON.stringify({&"classification": "P04-01 owner-approved DAY-end last interval completion diagnostic; public registered Staff and Guest; inherited physically placed kitchen fixture; snapshot replay only; no formal save/device/whole-unit acceptance", &"observations": _observations, &"first_receipts": _first_receipts, &"replay_receipts": _receipts, &"checks": _checks, &"failures": _failures}, "\t")); file.flush(); file.close()
_cleanup()
print("Order boundary diagnostic: %d checks, %d failures" % [_checks, _failures])
quit(1 if _failures else 0)