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>
This commit is contained in:
Takeshi
2026-10-19 17:20:04 +09:00
co-authored by Claude Opus 5.5
parent c366012446
commit ae0f998ff4
18 changed files with 424 additions and 17 deletions
+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")