Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-合批工作稿修订版独立复核-2026-09-29.md
Liubing\LB 6813da149a feat(upserver): 保存M2客户端KV迁移至本人统计写检查点
保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。
保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。

验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。
包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。
2026-09-30 19:19:05 +08:00

43 lines
6.4 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.
# M2 合批工作稿(修订版)独立复核
日期:2026-09-29。审查人:原 ZCode(独立侧)。对象:[合批工作稿修订版](M2-合批实施方案工作稿-2026-09-29.md)(17:47,21140 字节)及[预审主会话裁决](M2-合批预审主会话裁决-2026-09-29.md)。性质同前:只读事实/问题吸收,不是 hash 门控正式前审,不触发编码许可。未改生产/测试/服务器代码,未调用正式 101/102,未打包。
## 总裁决:承接完整,事实声明抽验全部属实;余 3 项 P3 修正,无 P1/P2
## 1. 裁决承接核对(预审七项 → 修订版落点)
| 预审输入 | 修订版落点 | 核对 |
|---|---|---|
| ① IUserService 成员三分表按新 PlayerId 重写 | "IUserService 成员责任与身份时序"全表(18 行成员逐项)+ 固定发布顺序段落 | ✓ 完整 |
| ② 中立面机制定死 | "生命周期窄契约含 KVHandoffReady/KVLastError/CloseKVAsync/ObserveKVQuitAsync,消费者只有 PFLoginAct/QuitAct";模式判断只读冻结 RuntimeSelection | ✓(成员命名见 §3-P3b) |
| ③ 测试迁移与签名耦合核验 | "候选修改文件"表 formal 合成宿主行(Program/Stubs/csproj)+ "不改但必须回归"行(KVGameplayLoop/AggUserService/EditorValidationHost 三文件签名兼容) | ✓ 完整 |
| ④ 身份发布硬断言 + 两个 IsLogin 消费者 | "身份发布顺序固定为…→同步发布→发布一次 EvtAPISvrLoginSuccess→Login 返回 Done→场景切换前再次确认";"FishingStage KV 入口需硬检查…不得依赖 5 秒软等待";OnApplicationResumedAsync/AutoRestart 分别限定 | ✓ 完整 |
| ⑤ 首场景最短链逐项边界 | "首场景请求与直接 KV 调用边界"表(Mail/AntiCheat/Friend/Club/Survey/等级榜/AIHelp/AutoRestart 逐行失败边界) | ✓ 完整 |
| ⑥ 等级榜 | 个人分按原算法推导、地区码未知不混入全局、聚合入口交服务端、活动榜沿用 event 请求 | ✓ 完整 |
| ⑦ SaveBackend 再读取 | "正式 KV 登录只信启动冻结选择,不再从 config 重读"(选消除路线) | ✓ 已定死 |
## 2. 新增源码事实声明抽验(全部属实)
| 声明 | 源码证据 |
|---|---|
| BattlePass 链:UpdateTaskData→SaveBattleTask→SaveBattlePassRecordTask→组合值单键 | `BattlePassData.cs:256,734`(订阅 ConditionTypeEvent);`:113-122`(SaveBattleTask→SaveBattlePassRecordTask);`:117`(`UpdateUserDataValue("BattlePassRecordTask", battlePass+"#"+battleTask)` 单组合键) |
| Achievement 只改内存、直接写已注释、经 PlayerData 合档 | `AchievementDataManager.cs:127,150`(订阅+UpdateData);`:200`(`//PlayFabMgr...UpdateUserDataValue("AchievementData"...)` 注释);`DataCenter.PlayerData.cs:35`(NewPlayerDataDic 合档事实源) |
| MiniBP:provider.SetMiniBattlePassRecord→`MiniBPKeyNew` | `MiniBattlePassDataProvider.cs:58,168,990` |
| LuckyTask:`ILuckyTaskGetData.SaveTaskData()` 接口多模型 | `LuckyTaskData.cs:18-31,320`;`EventLuckyGameModel.cs:12`、`EventLuckMagicData.cs:13` 均实现("不把接口名当已穷尽写入点"的表述与多实现一致) |
| TimeRefreshManager 已有 nullable 读取入口、缺失走首次登录分支 | `TimeRefreshManager.cs:106-108`(`DateTime? GetLastLoginTime()`);`:73-75`(`!lastLoginTime.HasValue` 分支) |
| Survey `TailNumberList` 存在,%10 尾数可映射 | `SurveyService.cs:69`(`surveyDataTable[i].TailNumberList.Contains(tailNumber)`) |
| `IUserService.entityKey` 直接使用 PlayFab DTO,与"新类零 PF 类型引用"不可同时成立 | `UserService.cs:6,66`(`using PlayFab.ClientModels` + `EntityKey entityKey { get; }`)——裁决"把 PF 专属身份移出共用契约"是必要而非可选,Duel 三处访问(`EventFishingDuelPanel.cs:634-635,748`)须同批迁移 |
| CreateTimeUtc/ServerTimeUtc 进入 AccountDescriptor | `PlayerKVLoginContext.cs:198,319-330` |
**补充事实(支持修订版发布顺序的正确性)**:`EvtAPISvrLoginSuccess` 现有订阅者恰三处——`ChatService.cs:189`、`InGameMailHandler.cs:165`(触发 FetchMail)、`RTService.cs:52`(触发连接)。三者分别依赖会话 Cookie、普通请求租约与登录态,修订版"绑定提示服务和同租约普通请求→…→发布事件"的先后顺序与这三个消费者吻合;正式 KV 现状从不发布该事件,修订版补上单次发布是开首场景的必要条件。
## 3. 待修正(均 P3,不阻塞方案完善)
- **P3a「CustomId 增加 setter」表述失准**:`IUserService.CustomId` 已声明 `get; set;`(`UserService.cs:70`),`PlayFabUserService` 亦已实现(:131)。无需任何接口变更——`PFLoginAct.cs:88,167-170` 的修复就是直接改用 `userService.CustomId` 去掉下转。按 AGENTS.md 不应记录一个并不需要的接口修改;该句应改为"直接使用既有 setter"。
- **P3b 生命周期契约出现第三个关闭名**:既有 `CloseKVForValidationAsync`(旧类,`UserService.KVLoad.cs:193`)与 `StopKVGameplayLoopAsync`(kv-loop),契约又引入 `CloseKVAsync`。最终方案须定死契约成员与既有方法的关系(复用改名或明确映射),避免同一关闭动作出现平行 API 面。
- **P3c 跨账号公开资料读取未入集中问题单**:成员表把"他人 GetPlayInfo/GetPlayLv 的其余跨账号公开资料读取"记为实现依赖,但[集中问题单](M2-客户端致服务端线上合同集中问题单-2026-09-29.md)只含新 ID 兼容确认与等级榜聚合两项。PF 模式的他人资料来自 PlayFab 公开档案(`UserService.cs:881-899` GetPlayerProfile),KV 模式无此通道;首场景链内 Club 自身响应已含成员资料、不受影响,但后续社交/成员列表 UI 依赖它。应在问题单补第三项(服务端是否提供按新 ID 的跨账号公开资料读取入口),或在最终方案明确这些 UI 的延期产品边界——二选一,不能只留在成员表脚注。
## 4. 结论
修订版把预审七项、主会话逐项裁决(含 EntityKey DTO 泄漏的处理方向、GetDefaultName/Survey 算法、地区码不拼全局名、身份时序)全部落入正文,且新增声明经抽验无失实。工作稿自认的剩余缺口(奖励写入边界、首场景动态存档链按可达动作展开、跨账号资料消费者)与实际相符。P3 三项修正后,下一步即可编制受审 hash 基线与一次性提示词进入正式前审;本复核不改变"未送审、未获白名单"状态。