diff --git a/Assets/Tests/EditMode/Enemies/BossPhaseAbilityGateTests.cs b/Assets/Tests/EditMode/Enemies/BossPhaseAbilityGateTests.cs
new file mode 100644
index 00000000..c474feb5
--- /dev/null
+++ b/Assets/Tests/EditMode/Enemies/BossPhaseAbilityGateTests.cs
@@ -0,0 +1,58 @@
+using System.Collections;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+using BaseGames.Enemies;
+using BaseGames.Enemies.Abilities;
+
+namespace BaseGames.Tests.EditMode.Enemies
+{
+ public class BossPhaseAbilityGateTests
+ {
+ /// 最小可实例化能力:不播动画、不碰 HitBox,只为验证启停与 CanUse。
+ private sealed class StubAbility : EnemyAbilityBase
+ {
+ ///
+ /// 编辑模式下 Unity 不会在 AddComponent 时调用 Awake,_enemy 会留空导致 CanUse 恒假。
+ /// 这里手动跑一次真实的 Awake(而非反射直写字段),让依赖解析走生产代码路径。
+ ///
+ public void RunAwake() => Awake();
+
+ protected override IEnumerator ExecuteCoroutine() { yield break; }
+ }
+
+ /// 测试期建出的宿主对象;在 TearDown 统一销毁,断言失败也不会残留到编辑器场景。
+ private GameObject _host;
+
+ // RunAwake 时 EnemyAbilityBase 找不到 AnimancerComponent 会告警,与本测试无关。
+ [SetUp]
+ public void SetUp() => LogAssert.ignoreFailingMessages = true;
+
+ [TearDown]
+ public void TearDown()
+ {
+ // 项目关闭了 Domain/Scene Reload:断言失败会跳过用例后续语句,
+ // 清理必须放在 TearDown,否则失败一次就往编辑器场景里漏一个对象。
+ if (_host != null) Object.DestroyImmediate(_host);
+ _host = null;
+ LogAssert.ignoreFailingMessages = false;
+ }
+
+ [Test]
+ public void DisabledAbility_IsNotUsable()
+ {
+ // 必须先挂 EnemyBase:否则 _enemy==null 会让 CanUse 恒假,
+ // 这条断言在修复前也会"通过",成为一个永远不会失败的测试。
+ _host = new GameObject("ability-host");
+ _host.AddComponent(); // 裸 EnemyBase 的 _currentState=Controlled → IsAlive 为真
+ var ab = _host.AddComponent();
+ ab.RunAwake(); // 编辑模式不自动跑 Awake,手动解析 _enemy
+
+ Assert.IsTrue(ab.CanUse,
+ "前提:启用且宿主存活时应可用——否则下一条断言分不清是 enabled 还是别的门在起作用");
+
+ ab.enabled = false;
+ Assert.IsFalse(ab.CanUse, "禁用的能力组件不可用——否则选招器会选中一个启不动招的招");
+ }
+ }
+}
diff --git a/Assets/Tests/EditMode/Enemies/BossPhaseAbilityGateTests.cs.meta b/Assets/Tests/EditMode/Enemies/BossPhaseAbilityGateTests.cs.meta
new file mode 100644
index 00000000..f3c91fef
--- /dev/null
+++ b/Assets/Tests/EditMode/Enemies/BossPhaseAbilityGateTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cc78469b00f228648844d2e34c13f80c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs b/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs
index 42d1a474..9961fe2b 100644
--- a/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs
+++ b/Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs
@@ -37,11 +37,16 @@ namespace BaseGames.Enemies.Abilities
public float CooldownRemaining => Mathf.Max(0f, _cooldownEndTime - Time.time);
public bool IsOnCooldown => CooldownRemaining > 0f;
- /// 能力被外部中断时触发(BD Task / 状态机订阅用)。
+ /// 能力被外部中断时触发(AI 决策层 / 状态机订阅用)。
public event System.Action Interrupted;
- /// BD 任务统一查询入口:当前是否可用(冷却完毕且未执行中)。
- public virtual bool CanUse => !_isRunning && !IsOnCooldown && _enemy != null && _enemy.IsAlive;
+ ///
+ /// 统一可用性查询:组件启用 + 冷却完毕 + 未执行中 + 宿主存活。
+ /// enabled 这一维供阶段门使用——被阶段禁用的能力不得进入选招候选,
+ /// 否则选招器会选中它然后 StartCoroutine 在禁用组件上必然失败。
+ ///
+ public virtual bool CanUse => enabled && !_isRunning && !IsOnCooldown
+ && _enemy != null && _enemy.IsAlive;
// ── IAttackCandidate(供 EnemyAttackSelector 选招)──────────────────
public bool RequiresLineOfSight => _config != null && _config.requiresLineOfSight;