Files
ft/CodexOutput/upserver/P2实施裁决-2026-09-22.md

33 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 独立复审P2实施裁决(生产修改前)
2026-09-22,依据独立报告《最小登录独立复审-2026-09-22.md》及 ReviewLifecycleTests/regression-failing.log,实际方法提取的4条退出安全断言失败,正常对照4条通过。非Unity竞态复现,不把历史快速换号0错误扩大为全时序安全。
## 完整方案与边界
仅修改三个生产文件:
1. FishingAct.cs:GetUI与同一首登分支NewEnterMap,在入口捕获原container及IUserService.LoginLifetime;每个await后先检查Unity对象销毁、令牌取消或container替换,失效立即返回。所有后续Resolve使用原container。已有正常UI流程和补单调用保持,不改奖励/玩法。新手分支同样保留正常行为,不扩大到其他玩法异步方法。
2. SoundService.cs:新增私有初始化版本号,InitAsync开始递增并捕获;Release首先递增使在途Init失效。两个Addressables句柄由局部变量持有,await后先检查版本;仅完整有效初始化时将局部句柄移交成员。try/finally在未移交时释放本次局部有效句柄;Release只释放成员,避免双释放/误释放后一次初始化资源。旧等待返回不再注册lowpass事件、建池;接口和调用方签名不变。
3. SoundMgr.cs:新增私有初始化版本号;Release先递增。Init捕获原container,每个等待返回检查版本和container。residentFish按地址去重加载(已有数组首项重复,否则opMap覆盖句柄造成漏释放);局部opMap由try/finally负责,仅有效完成时移交residentClip,未移交则释放每个有效句柄。保持成功后已有按clip释放机制,不改音量/音效/播放规则。旧完成不得注册全局订阅、写音量或解析新container。
## 资源/错误策略评审
- 采用局部句柄+移交标志,Release不会处理尚未移交的句柄;在途方法finally负责其本次句柄,释放恰好一次。SoundMgr取消轮询时可释放未完成句柄,之后不再读取结果;SoundService等待完成后释放,不制造取消异常。
- 同一实例后续Init通过新版本与旧任务隔离;不新增自动重试、吞正常加载异常或全局catch。原有效初始化仍传播资源失败。初始化/退出都沿Unity主线程,不引入并行修改容器。
- 正常完成的音频资源沿原Release路径,定向测试必须覆盖正常Init/Release与重复Release,不能仅证明旧回调被跳过。
- Config、身份、存档、KV、俱乐部、SDK、服务器及预编译框架不在边界。修改前已Stop C盘Play,D盘不动。
## 验证计划与裁决
重新提取上述真实方法,保留失败基线;验证GetUI各等待点退出/换容器,声音两级初始化等待中Release、重复释放、正常初始化与新实例初始化。然后Unity编译、Play实际101→102→101和实际Hub/错误日志复查,独立agent复审本次差异。无法确定性覆盖的Unity细粒度资源时序明确保留证据限制。
主会话完整方案评审结论:上述最小边界可实施;已复现问题满足用户“发现问题再编码修复”的条件,不需扩大范围。独立agent的详细方案作为补充审查,不替代本裁决;若发现资源归属反例,先更新裁决再改。
## 独立方案补充评审裁决(完善实现前)
已完整读取《独立复审P2修复方案-2026-09-22.md》,认可失败回滚与重复Init资源条件。补充允许FishingAct.OnCameraSpeedEvent这一NewEnterMap直接子方法:在其自身等待后检查同一对象/令牌/容器,避免外层检查过晚;不改相机时序。GetUI/NewEnterMap入口拒绝已销毁对象。
SoundService/SoundMgr成功Init后的再次Init先释放已移交成员;新一代失效旧等待。初始化订阅用局部变量持有,只有全部成功才移交成员;当前初始化失败由Release清理本实例已初始化部分,局部finally释放未移交资源/订阅,旧版本失败不触及新版本。正常资源失败继续抛出。此补充与独立评审条件一致,可实施并做资源引用逐个断言。
## Unity复现后的第四文件补充裁决(实施前)
快速101→102实际复跑在FishingStage.StartAsync:191发生AddTo空container,p2-progress-102-errors.json。Stop已将disposable置null,但Unity对象尚未销毁、QuitAct尚未注销,原this/token检查不能识别“已Stop但仍活”的阶段。不能通过新建订阅容器让旧阶段继续运行。
允许仅增加FishingStage.cs:私有stopping标识在Stop入口(任何清理前)设true,OnDestroy也设true;Start入口、现有每await/进度回调和旧初始化异常过滤加入该条件。disposable释放改可空以支持重复Stop清理。保持正常启动行为、错误传播和既有场景顺序,不改框架DLL。独立review/test补stopped-alive-uncancelled分支,真实快速流程重新跑;失败证据存档。本补充由主会话完整评审通过,生产边界更新为四文件。