Files
aetherbound-guild/runtime/tests/p9_10/continuation_authority_test.gd
T

108 lines
6.5 KiB
GDScript

extends SceneTree
const Content = preload("res://content/p9_10_content.gd")
const State = preload("res://p9_10/contract_state.gd")
const Service = preload("res://p9_10/contract_service.gd")
const BattleService = preload("res://p9_10/battle_service.gd")
const Fixture = preload("res://tests/p9_10/runtime_fixture.gd")
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
verify_content()
verify_exact_carry_in()
verify_full_continuation()
if failures.is_empty():
print("ABG_P9_10_CONTINUATION_AUTHORITY_OK routes=27 markets=9 recruits=10 equipment=6 carry=p99_market4 capacity=5,6,6,7,7,8,8,9,9,10 hires=5 slots=1 final_order=true boss_muster=stable stale=true duplicate=true invalid_mutations=0")
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func verify_content() -> void:
var catalog: Dictionary = Content.snapshot("CH-RG01-CATALOG-01")
var threat: Dictionary = Content.snapshot("CH-RG01-THREAT-01")
expect(Content.validate(catalog).ok and Content.validate(threat).ok, "both Charter content projections validate")
expect(catalog.routes.size() == 27 and catalog.boards.size() == 9 and catalog.recruit_offers.size() == 10 and catalog.equipment_offers.size() == 6, "declared content counts are exact")
expect(String(catalog.equipment_offers["P910-M8-E2"].catalog_id) == "EQ-041", "catalog Charter exposes Neighborwall at Market 8")
expect(String(threat.equipment_offers["P910-M8-E2"].catalog_id) == "EQ-023", "threat Charter preserves base equipment row")
var tampered := catalog.duplicate(true)
tampered.routes["P910-R4-Q0"].risk = 2
expect(not Content.validate(tampered).ok, "route identity drift rejects")
func verify_exact_carry_in() -> void:
var p99 := Fixture.p99_market_four()
var state = State.new()
expect(state.initialize_from_p99(p99), "exact P9.9 Market 4 initializes")
expect(state.current_market == 4 and state.cleared_rounds == 3 and state.line_capacity == 5 and state.company.size() == 4, "carry-in preserves Market, clears, capacity and Company")
var wrong := p99.duplicate(true)
wrong.current_market = 3
var rejected = State.new()
expect(not rejected.initialize_from_p99(wrong), "non-Market-4 P9.9 state rejects")
func verify_full_continuation() -> void:
var service = Service.new(Fixture.p99_market_four("CH-RG01-CATALOG-01"))
var stale_before: Dictionary = service.state.snapshot()
expect(service.hire("stale-hire", "P910-M4-H1", service.state.revision + 1).code == "stale_revision" and service.state.snapshot() == stale_before, "stale hire is inert")
var first_hire: Dictionary = service.hire("hire-m4", "P910-M4-H1")
expect(first_hire.ok and service.state.company.size() == 5 and service.state.deployed_recruit_ids == service.auto_order_candidate(), "Market 4 hire fills capacity and reorders automatically")
var after_hire: Dictionary = service.state.snapshot()
expect(service.hire("hire-m4", "P910-M4-H1").duplicate and service.state.snapshot() == after_hire, "hire retry returns original receipt")
expect(service.hire("hire-m4-over", "P910-M4-H2").code == "line_capacity_reached" and service.state.snapshot() == after_hire, "capacity blocks a second Market-4 hire")
for round_index in range(4, 13):
if round_index in [5, 7, 9, 11] and service.state.company.size() < service.state.line_capacity:
var offer_id := "P910-M%d-H1" % round_index
expect(service.hire("hire-m%d" % round_index, offer_id).ok, "Market %d optional hire commits" % round_index)
if round_index in [5, 8, 11]:
var equipment_id := "P910-M%d-E1" % round_index
var target: String = service.state.deployed_recruit_ids[-1]
var preview: Dictionary = service.equipment_preview(equipment_id, target)
expect(preview.ok and preview.current_catalog_id == String(service.state.inventory.get(service.state.equipped_by_recruit[target], {}).get("catalog_id", "")), "Market %d equipment preview shows current slot" % round_index)
expect(service.buy_and_equip("equip-m%d" % round_index, equipment_id, target).ok, "Market %d equipment commits" % round_index)
if round_index == 12:
var proposed: Array[String] = service.state.deployed_recruit_ids.duplicate()
proposed.reverse()
expect(service.propose_final_order("order-propose", proposed).ok, "final order proposal is reversible state")
expect(service.confirm_final_order("order-confirm").ok and service.state.deployed_recruit_ids == proposed, "final order confirmation commits exact members")
var route_id := "P910-R%d-Q0" % round_index
var preview: Dictionary = service.route_preview(route_id)
expect(preview.ok and String(preview.mechanic_id) == String(Content.ROUND_BLUEPRINTS[round_index].mechanic_id), "Round %d preview exposes its mechanic" % round_index)
var result := play(service, route_id, "round-%d" % round_index)
expect(result.outcome == "victory", "Round %d low-risk path wins" % round_index)
expect(service.state.phase == State.Phase.BOSS_MUSTER and service.state.current_market == 13 and service.state.cleared_rounds == 12, "nine victories reach Boss Muster")
expect(service.state.line_capacity == 10 and service.state.company.size() == 9, "capacity reaches ten while optional hires grow Company to nine")
expect(String(service.state.boss_muster.boss_id) == Content.BOSS_ID and String(service.state.boss_muster.muster_hash).length() == 64, "Gale Loom Muster has stable identity and hash")
var restored = Service.new()
expect(restored.restore_snapshot(service.state.snapshot()) and restored.state.boss_muster == service.state.boss_muster, "Boss Muster survives reconstruction byte-for-byte")
expect(service.state.equipped_by_recruit.values().filter(func(value): return not String(value).is_empty()).size() <= service.state.company.size(), "each Recruit retains at most one equipped instance")
func play(service, route_id: String, prefix: String) -> Dictionary:
expect(service.commit_route("%s-route" % prefix, route_id).ok, "%s route commits" % prefix)
var battle = BattleService.new(service.state.selected_charter_claim_id)
expect(battle.start_from_market(service.state).ok, "%s battle starts" % prefix)
var guard := 0
while not battle.state.terminal and guard < 2000:
battle.advance_ticks(1)
guard += 1
expect(guard < 2000, "%s battle terminates" % prefix)
var settled: Dictionary = service.settle_battle("%s-settle" % prefix, battle.state.snapshot())
expect(settled.ok, "%s battle settles" % prefix)
return {"outcome": battle.state.outcome, "ticks": guard, "snapshot": battle.state.snapshot()}
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("P9.10 continuation: %s" % message)