Files
ft/CodexOutput/upserver/阶段4B分期与4B1方案独立审查-2026-09-23.md

6.7 KiB
Raw Blame History

阶段4B分期与4B1方案独立审查

日期:2026-09-23。审查者:用户指定外部AI(ZCode会话)。性质:方案设计审查,非实施。本轮只读:未修改生产代码/测试/csproj/共享文档/原报告,未使用子Agent,未访问正式服,未运行Unity(设计审查无需)。

受审版本核对

阶段4B1方案受审基线-2026-09-23.json共18项(方案、提示词、4A裁决/复核、阶段4分期、8份生产源码、UserService/PlayFabMgr/AggUserService/DataCenter.PlayerData/QuitAct、4A测试Program/csproj),本审查逐项重算SHA256——全部一致,无受审版本漂移。

实际读取范围:上述文档全文;源码抽查§1观察表(UserService InitData/LoginApiServer/401订阅/Logout Dispose apiSession、AggUserService OnInitData订阅窗口、QuitAct StartAsync次序、PlayFabMgr既有4A期核对);4A Bridge/Handle/Owner/Result实现(本轮及前轮已深读)。

双裁决

  • 4B分期:PASS。 4B1准备内核/4B2游戏加载/4B3普通读写路由的三分各有明确"编码前所需审查"与"启用范围";4B1白名单之外无任何放行;4C消费、身份专项、tickets有界历史、正式场景数据边界仍被门控;"4B1通过≠4B通过≠G4通过"的层级明确。
  • 4B1方案:PASS(附3条P3建议,均不阻塞)。 职责边界(拥有session、认证→Open→Read→快照、Close后才Dispose session)正确复用4A而非复制调度器;生命周期合同完整可实现;矩阵充分。

逐项审查

1. 分期合理性与白名单(§2/§6):通过

一次性4B的否决理由成立(缺完整逐调用点清单,§2表);按key混用维持原否决。§6白名单仅两份新生产文件+meta+独立测试目录+文档;明令禁改S101AccountSession/4A/3A/3B/KV Client/旧测试/UserService/PlayFabMgr/DataCenter/Stages/服务器/包;"发现接口不足先记差异再补审"与既有流程一致。无4B2/4B3偷渡路径。

2. 4B1新增价值与4A复用(§3):通过

与4A分工清晰:4A"外部已认证、不拥有session";4B1"建立session、按序取档、Close后才销毁"。复用4A的串行/票据/读接口(Bridge.OpenAsync/Handle.ReadLocalSnapshot/Bridge.CloseAsync均为4A公开面),不复制调度器。session所有权单一(context建、context在Bridge Close后Dispose),符合4A"桥接不拥有session"的反向合同。

3. 生命周期与并发(§4):通过,附P3

  • 单次Prepare:同实例返回同一任务、首token定义生命期(B1-06)✓。
  • workSettled与对外结果分离(§4.3):Close不等待对外Prepare任务、失败路径先完成workSettled再走统一Close——互等环被显式排除;即使workSettled完成仍await Bridge.CloseAsync ✓。
  • Close-before-Prepare:永久关闭+后续Prepare零请求Cancelled(B1-11)✓。
  • 资源次序(§4.4):撤销准入→取消CTS→await workSettled→await Bridge.Close→Dispose session→释放CTS——与4A Slot的Cancel/Dispose串行化兼容;Bridge Close失败保留session/bridge/故障任务并永久阻塞实例,不允许new绕过(§4.2)✓。
  • 取消回调只同步撤销+非阻塞收尾,后台收尾任务可被Close观察(§4.3)✓。
  • 外部委托约束(§4.5)逐条落实4A裁决P3-3(只读、无I/O、不等待、异常即失效、同号重登以epoch区分)✓。

4. Prepared语义与空快照(§3.1/§5):通过

Prepared≠可玩/有效业务档/建档批准;成功空快照显式IsEmpty=true且"来源于成功Get";失败Data=null;§5把空档阻塞、业务校验、初始化副作用、回调隔离、PF暂留边界全部明确推给4B2/4B3并给出默认策略方向——不存在被误解为初始化放行的措辞漏洞。

5. 可实现性(§6/现有API):通过

  • session注入:S101AccountSession(Uri, Func<CookieContainer,HttpMessageHandler>)构造已存在(3B/3C测试同模式)。
  • bridge注入:PlayerKVGameSessionBridge的internal handlerFactory构造已存在(4A测试同模式)。
  • 其余全部走4A公开面。无需扩大任何既有文件边界或公共接口;PlayerKVLoginContext自带internal工厂钩子供测试故障注入,符合"不新增公共任意传输入口"。

6. 矩阵B1-01~B1-16(§7):充分

覆盖正常链、输入校验/0传输、认证失败清理、Open/Read各失败态、空快照newCreate两态、重复Prepare、忽略取消(认证/Get)下Close、换号排水、epoch失效、Prepare/Close并发、幂等/重入、清理异常保留、委托/工厂异常、既有缓存pending/Unknown只读呈现、脱敏、回归与编译。TCS闸门+整体超时+采纳P3-1(保留完整stdout/stderr与真实退出码、失败证据不被后续成功覆盖)✓。真实游戏接线、消费、身份、tickets、正式数据边界均仍受门控(§5/§2)✓。

发现清单(全部P3,不阻塞)

P3-A|建议矩阵补一条显式断言:Close后IsCurrent=false且已返回快照"仍可读但不再授权"。 §3.1把IsCurrent定为业务侧合同,但B1-02/09/11只隐含覆盖。建议并入B1-11或B1-09:断言Close后IsCurrent=false、旧快照对象仍可枚举(不被销毁)、再Prepare被拒。位置:§7矩阵。

P3-B|"失败结果在清理完成前不完成"意味着Prepare可能无界等待——建议接口文档显式声明。 §3.2 Cancelled行规则正确(与4A/3C忽略取消的保守收尾一致),但调用方易假设PrepareAsync必有界返回。建议在PlayerKVLoginPrepareResult/PrepareAsync的文档注释中写明:"取消/失败结果在底层传输与Close真正收尾前不完成;忽略取消的传输可使本任务长期挂起,收尾状态以CloseAsync为准"。位置:§3.1/§3.2。

P3-C|重复Prepare"首token定义生命期"是易误用点。 B1-06已定义并有测试,建议生产代码以XML文档+Debug.Assert级防护(重复调用token不同不静默接受)双保险,避免4B2接线时误传新token以为能延长生命期。位置:§3.1。

源码观察核对(方案§1)

抽查确认:UserService 501–503行InitData在登录链内调用、151–155行401事件触发后台_ = LoginApiServer()、Logout多处apiSession?.Dispose();AggUserService 93/97行OnInitData订阅仅限base.Login等待期(try/finally退订);QuitAct.StartAsync先撤销销毁再await;PlayFabMgr 40秒任务/void写/全局Instance与4A期核对一致。方案§1观察表无失实。

结论

  • 4B分期:PASS。
  • 4B1方案:PASS(P3-A/B/C三条建议,建议随裁决采纳为实施说明)。
  • 本报告仅为方案审查:不构成实施批准、不等于4B任何单元验收;P3-1(KVSyncTests偶发失败)按4A关闭裁决口径保留为待查项,本方案§7的采纳表述准确。