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

6.4 KiB
Raw Blame History

M2 合批工作稿(修订版)独立复核

日期:2026-09-29。审查人:原 ZCode(独立侧)。对象:合批工作稿修订版(17:47,21140 字节)及预审主会话裁决。性质同前:只读事实/问题吸收,不是 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 的其余跨账号公开资料读取"记为实现依赖,但集中问题单只含新 ID 兼容确认与等级榜聚合两项。PF 模式的他人资料来自 PlayFab 公开档案(UserService.cs:881-899 GetPlayerProfile),KV 模式无此通道;首场景链内 Club 自身响应已含成员资料、不受影响,但后续社交/成员列表 UI 依赖它。应在问题单补第三项(服务端是否提供按新 ID 的跨账号公开资料读取入口),或在最终方案明确这些 UI 的延期产品边界——二选一,不能只留在成员表脚注。

4. 结论

修订版把预审七项、主会话逐项裁决(含 EntityKey DTO 泄漏的处理方向、GetDefaultName/Survey 算法、地区码不拼全局名、身份时序)全部落入正文,且新增声明经抽验无失实。工作稿自认的剩余缺口(奖励写入边界、首场景动态存档链按可达动作展开、跨账号资料消费者)与实际相符。P3 三项修正后,下一步即可编制受审 hash 基线与一次性提示词进入正式前审;本复核不改变"未送审、未获白名单"状态。