extends SceneTree var failures: Array[String] = [] func _init() -> void: var event_bus: Node = load("res://autoload/event_bus.gd").new() _expect(not event_bus.has_signal("action_judged"), "EventBus should not expose legacy action_judged") event_bus.free() var rhythm: Node = load("res://autoload/rhythm_manager.gd").new() _expect(not rhythm.has_signal("action_judged"), "RhythmManager should not expose legacy action_judged") rhythm.free() for runtime_path: String in [ "res://autoload/rhythm_manager.gd", "res://autoload/event_bus.gd", "res://scenes/components/action_controller.gd", "res://scenes/ui/rhythm_track.gd", ]: if not FileAccess.file_exists(runtime_path): continue _expect(not _read_text(runtime_path).contains("action_judged"), "%s should not reference action_judged" % runtime_path) for rule_path: String in [ "res://scenes/combat/action_resolver.gd", "res://scenes/components/action_controller.gd", ]: _expect(not _read_text(rule_path).contains("get_current_state_name"), "%s should not use legacy state API for rule context" % rule_path) var state_machine_source := _read_text("res://scenes/components/state_machine.gd") _expect(not state_machine_source.contains("state_names"), "StateMachine should not keep legacy state_names") _expect(not state_machine_source.contains("get_current_state_name"), "StateMachine should not expose legacy get_current_state_name") _expect(not state_machine_source.contains("\"state\""), "StateMachine.build_context should not emit legacy state") _expect(not state_machine_source.contains("func can_start_action"), "StateMachine should not own action permission rules") _expect(not state_machine_source.contains("func can_move_freely"), "StateMachine should not own movement permission rules") var action_rule_source := _read_text("res://scripts/resolvers/action_rule_resolver.gd") _expect(not action_rule_source.contains("legacy_state"), "ActionRuleResolver should not fallback to legacy state context") for marker_path: String in [ "res://scenes/ui/rhythm_track.gd", "res://tests/test_chart_layer.gd", "res://tests/test_ui_animation_regression.gd", ]: if not FileAccess.file_exists(marker_path): continue var marker_source := _read_text(marker_path) _expect(not marker_source.contains("enemy_prepare_attack"), "%s should not keep legacy enemy_prepare_attack marker" % marker_path) _expect(not marker_source.contains("enemy_attack_active"), "%s should not keep legacy enemy_attack_active marker" % marker_path) _expect(not marker_source.contains("enemy_recovery"), "%s should not keep legacy enemy_recovery marker" % marker_path) var action_controller_source := _read_text("res://scenes/components/action_controller.gd") _expect(not action_controller_source.contains("action_executor.execute(current_action, StringName(str(current_intent.judgement.get(\"label\", \"perfect\"))), burst_component)"), "ActionController should not pass BurstComponent as a stat provider") _expect(not action_controller_source.contains("resolve_cost\", action, burst_component"), "ActionController cost resolution should use EffectContainer, not BurstComponent provider") var burst_source := _read_text("res://scenes/components/burst_component.gd") _expect(not burst_source.contains("judgement_scale"), "BurstComponent should not directly mutate RhythmManager.judgement_scale") for presentation_path: String in [ "res://scenes/characters/character.gd", "res://scenes/characters/player.gd", "res://scenes/components/movement_motor.gd", ]: var presentation_source := _read_text(presentation_path) _expect(not presentation_source.contains("Character.State"), "%s should not reference legacy Character.State" % presentation_path) _expect(not presentation_source.contains("enum State"), "%s should use explicit presentation constants, not legacy Character.State enum" % presentation_path) _expect(not FileAccess.file_exists("res://scenes/rhythm/rhythm_conductor.gd"), "Legacy rhythm_conductor.gd should be removed") _expect(not FileAccess.file_exists("res://tests/test_rhythm_conductor.gd"), "Legacy rhythm conductor test should be removed") var charge_source := _read_text("res://scenes/components/charge_component.gd") for charge_needle: String in ["release_requested", "begin_hold", "finish_hold", "skill_a_charge_release", "skill_d_charge_release"]: _expect(not charge_source.contains(charge_needle), "ChargeComponent should not keep legacy charge API: %s" % charge_needle) var player_source := _read_text("res://scenes/characters/player.gd") for player_needle: String in ["_held_symbols", "_is_symbol_held"]: _expect(not player_source.contains(player_needle), "Player should not keep legacy held-symbol cache: %s" % player_needle) var action_script: Script = load("res://resources/action_data.gd") if action_script == null: failures.append("ActionData script should load for required_state cleanup") else: var action: Resource = action_script.new() as Resource _expect(not _has_property(action, "required_state"), "ActionData should not expose legacy required_state") for property_name: String in ["energy_cost", "energy_reward", "spawns_projectile", "projectile_scene", "damage", "cancel_window", "has_super_armor", "displacement"]: _expect(not _has_property(action, property_name), "ActionData should not expose legacy field %s" % property_name) for doc_path: String in [ "res://AGENTS.md", "res://docs/当前项目评估文档.md", ]: if not FileAccess.file_exists(doc_path): continue _expect(not _read_text(doc_path).contains("required_state"), "%s should not describe required_state as an active compatibility field" % doc_path) for artifact_path: String in [ "res://assets/art/characters/jump.png", "res://assets/art/characters/jump.png.import", "res://assets/art/characters/katana_attack_sheathe.png", "res://assets/art/characters/katana_attack_sheathe.png.import", "res://assets/art/characters/player_idle.png", "res://assets/art/characters/player_idle.png.import", "res://assets/art/characters/player_punch.png", "res://assets/art/characters/player_punch.png.import", "res://addons/limboai/bin/limboai.gdextension", ]: _expect(not FileAccess.file_exists(artifact_path), "Unused legacy artifact should be removed: %s" % artifact_path) _expect(DirAccess.open("res://something") == null, "Placeholder something/ directory should be removed") _finish() func _read_text(path: String) -> String: var file := FileAccess.open(path, FileAccess.READ) if file == null: failures.append("Could not read %s" % path) return "" return file.get_as_text() func _has_property(object: Object, property_name: String) -> bool: for property: Dictionary in object.get_property_list(): if property.get("name") == property_name: return true return false func _expect(condition: bool, label: String) -> void: if not condition: failures.append(label) func _finish() -> void: if failures.is_empty(): print("PASS v2 terms cleanup") quit(0) else: for failure: String in failures: push_error(failure) quit(1)