# 阶段4C2收线取消缺陷最小修复方案(待完整评审) 2026-09-24。依据:《阶段4C2第二次真实尝试与收线取消记录-2026-09-24.md》及用户提供的完整错误堆栈。仅修复已实证缺陷,不放宽任何准入/技能检查/票据保护;未编码。 ## 缺陷与证据 用户真实收线完成时(FishEnd 已触发)报错堆栈: ``` PlayerKVGameplayLoop:Fault ← CancelReward ← FishingUpdateSys:OnDisable(FishingUpdateSys.cs:3203) ← UnityEngine.Object:Destroy ← UIManager:DestroyUI(UIManager.cs:938) ← FishingUpdateSys:FishEndCore(:1312) ← FishEnd(:1255) ← Update(:1227) ``` 正常完成链为 `FishEnd → BeginRewardEnding(置a.Ending=true) → using BeginRewardSegment("ending") FishEndCore() → ShowKVRewardPanelAsync(等待票据确认后展示)`。`FishEndCore` 内 `UIManager.Instance.DestroyUI(UITypes.FishingPanel)`(:1311)会销毁承载 FishingUpdateSys 的战斗面板,同步触发 `OnDisable/OnDestroy` → `CancelReward(this,...)`。`CancelReward`(UserService.KVFishingReward.cs:281-288)只校验 actor 身份,不区分该拆除是否属于完成路径自身:`a.Cancelled=true` 且此刻 `Ready && !a.Confirmed` → Fault("Fishing reward cancelled: controller disabled"),奖励在确认前被自己的收尾拆除取消。第二次真实尝试(run 62216)即此:门通过、扣费票据确认、战斗约18秒正常结束,随后被误取消退出,无奖励。 ## 拟改动1(生产,唯一行为变化):UserService.KVFishingReward.cs CancelReward 增加一行守卫 在现有 actor 身份守卫之后、`a.Cancelled=true` 之前增加: ```csharp if(a.Ending && !a.Confirmed && ReferenceEquals(actor,a.Controller)) return; ``` 语义:**已进入完成流程(Ending=true)且尚未票据确认(!Confirmed)时,控制器(Controller)自身的 disable/destroy 属于 FishEndCore 的正常拆除窗口,不构成放弃。** - 战斗中(Ending=false)控制器被禁用/销毁:仍按原逻辑取消并 Fault(真实放弃保护保留)。 - 票据确认之后控制器 disable:守卫不适用(Confirmed=true),保持原语义——置 Cancelled、不 Fault(既有固定验证用例"confirmed-normal-cancel-no-second-exit"期望不变)。 - Panel 与 Consumption.Actor 两个 actor 路径完全不变;合法放弃主通道 `CancelFishing→CancelReward(action.Actor)`(KVGameplayLoop.cs:195)不受影响。 - 若该窗口内票据确认本身失败,仍由 ConfirmRewardAsync 的既有 Stop/Fault 报错,不产生悬空奖励。 不新增字段、事件、日志框架、await;不动 CheckRewardContext、技能检查、准入、票据等待、Fault 通道。 ## 拟改动2(既有固定验证维护):UserService.KVFishingRewardValidation.cs 增加一组用例 新增组(命名如 `ending-teardown-pre-confirm-not-cancel`):构造 rewardAction → `BeginRewardEnding` 成功后、`ConfirmRewardAsync` 完成前,模拟控制器 disable(调用 `CancelReward(rewardAction.Controller,"controller disabled")`)→ 断言 `!rewardAction.Cancelled && Ready`(红:现状会 Cancelled+Fault);随后正常完成确认与展示,断言流程可走完。既有"confirmed-normal-cancel-no-second-exit"用例保持原样(验证确认后语义未变)。 ## 验收 1. 固定验证全量重跑:既有43组168断言+新增组全部通过(Unity空闲Editor执行 `KVGameplayLoopSetup.RunValidationAsync("fishing-reward")`)。 2. Editor编译0错误、SERVICE_HOST编译exit0。 3. 静态diff判据:生产源码仅 UserService.KVFishingReward.cs 一行守卫+Validation文件新增用例段;FishingUpdateSys.cs、FishingRewardPanel.cs、KVGameplayLoop.cs 等其余文件字节不变。 4. 修复后真实收鱼闭环仍需用户另行授权新进程运行;本修复不构成4C2关闭。 ## 请独立评审裁决 1. 守卫条件 `Ending && !Confirmed && actor==Controller` 是否精确覆盖且仅覆盖误取消窗口?有无遗漏的取消场景(如FishEnd开始后用户真实退出应如何表现——应经CancelFishing/退出排水路径)? 2. 确认后语义不变的论证是否成立(对照既有验证用例)? 3. 新增验证用例设计是否充分(红绿边界)? 4. 是否批准这两处限定修改? 请输出问题等级(P1/P2/P3)、可执行修订与明确允许/不允许实施结论。