8.5 KiB
阶段 3A 独立代码审查
日期:2026-09-22。审查身份:主实现会话之外的独立审查 agent。
1. 最终裁决
限定阶段 3A 通过。 发现的 1 项 P2 路径校验问题已经由主会话修复并经独立回归确认;当前三文件没有剩余已证实阻塞问题。可按已批准方案继续阶段 3B,不能据此宣称整个阶段 3 或生产游戏 KV 切换完成。
本次只审查同步状态、快照格式和本地文件持久化,不修改生产代码,不调用正式服,不操作 Unity。独立证据写入 KVSyncReviewTests/;主会话测试和编译证据只读核对。
2. 对照依据及代码范围
方案:《阶段3缓存同步方案与评审-2026-09-22.md》,重点第 4–7 节与 G3A;此前方案独立审查的问题已闭环。用户本轮确认继续后,两项保守策略已经批准:未知写不得仅凭 Get 自动解锁;损坏主档不得自动恢复旧备份并继续写。
本次生产文件均在 Client/Assets/Scripts/Services/PlayerData/:
| 文件 | 实际审查范围 | 最终 SHA256 |
|---|---|---|
| PlayerKVSyncModels.cs | 身份规范化、不可变对外模型、快照编解码、序号及批次关联 | 49143F3A6DAD9A570C522288B471D5C4CE5812F73E0EB7B8E6081453C97990D4 |
| PlayerKVCacheStore.cs | 独占锁、加载失败分类、临时文件/flush/原子替换、失败与释放 | A08DAB00F51A28CB5AA9A26D66CB3EB9349216535E92F4DC4E77EE8DDEBA28B1 |
| PlayerKVSyncState.cs | 状态转换、基线/待写/本地覆盖、多版本确认、未知恢复、同步 gate/Dispose | B0BF9EBAA24C8ACB4761B7C09331B81A414E62CDBBF143B106B7F466E334A198 |
未将 owner、HTTP 串行调度、异步票据、Close 准入门判定为“缺失实现”:这些明确属于 3B。未扩大到 UserService、PlayFabMgr 或游戏存档接线。
3. 发现项及闭环
R1 — [P2,已修复] Windows 半绝对路径通过缓存根目录校验
- 位置:
PlayerKVSyncModels.cs:101,KVIdentity的根路径检查。 - 初审实现使用
Path.IsPathRooted。Windows 上C:relative与\relative均可返回 true,但并非完整绝对路径;随后GetFullPath根据当前目录或当前盘符解析。同一参数可能指向不同命名空间,不符合 G3A1 的非法路径拒绝约定。 - 最小复现:向身份构造/Open 传上述根路径。正常完整绝对路径是对照。问题仅在调用方提供这种非法根目录时触发,没有证据表明现有正常 persistentDataPath 已因此丢数据。
- 主会话修复:改为
Path.IsPathFullyQualified,不改变存储格式或同步算法。独立宿主断言两类路径均拒绝;主测试增加对应两项;Unity 编译证据确认该 API 在当前项目可用。 - 证据边界:修复发生在独立宿主首次执行之前,因此未伪造“旧源码执行失败”记录。旧实现由初审源码及明确的 Windows 路径语义确认;本报告保存的是修复后实际执行结果。
另有初审文档状态提醒:方案末尾一度残留“待用户确认/尚未实现”的旧总结,已反馈主会话同步。此项不属于生产代码缺陷。
4. 关键正确性核对
| 风险 | 核对结果 |
|---|---|
| 丢失已接纳编辑 | 每次编辑先克隆快照,保存成功才发布新内存和 Success。失败进入 StorageError,后续编辑/同步启动被拒绝;无失败后静默清队列路径。 |
| 本地提交不确定 | Save 在替换前设置不确定标记;替换后故障返回失败并保留原内存,同时报告目标 revision/attemptSequence 和不确定性。重开按实际主文件恢复,不强行认定本次编辑未保存。 |
| 损坏加载或错误身份 | 必填类型、未来版本、身份、重复 JSON 属性、完整根、序号界限、待写唯一序号及批次关联均有检查。损坏返回 RecoveryRequired 并释放独占句柄;不把损坏读成空字典。 |
| 备份退回旧数据 | 有效主文件优先;损坏/缺失主文件且有遗留材料时阻止打开,不自动接受备份。有效主文件不因损坏备份而冻结。 |
| active 与 v2 混淆 | 批次是不可变快照。v1 发出后可保存 v2;确认仅移除同 sequence,否则保留 v2 的目标并推进 base 至 v1。合法同 key 同 sequence 的引用可加载。 |
| unknown 在重开时丢失 | 重开遗留 active 在内存转换为 unknown;原磁盘 active 本身仍是再次重开的冻结证据。下一次保存才写成 unknown 不形成放行窗口。R=B/R=L 均不能清未知批次。 |
| 普通冲突误判损坏 | 最新 baseline 可是远端冲突观察值,而 pending.BaseValue 仍是编辑时基线;二者不要求始终相等。独立用例覆盖这个合法状态重开及重复冲突,不建议加入错误的无条件相等校验。 |
| remoteStore=false | 只形成 localOnly;不取消既有远端 pending,不被旧批次确认覆盖。显式远端 Update 或 Delete 同次提交清除对应覆盖。 |
| 锁/Dispose 竞态 | 状态操作和保存受同一同步 gate 保护,Dispose 也使用该 gate,重复 Dispose 不释放新实例的锁。3B 必须在释放此同步状态前排空已准入网络工作;本层不冒充已实现该异步生命周期。 |
5. 独立执行证据
独立宿主:CodexOutput/upserver/KVSyncReviewTests/KVSyncReviewTests.csproj。它直接编译上面三个生产 .cs 文件,引用项目现有 Newtonsoft,未用复制/镜像状态机代替实现,也没有 HTTP 代码或 Unity 自动化。
最终执行:13 组场景、127 个断言全部通过。组数与断言数不同,不能描述成 127 个独立完整业务场景。
证据目录:CodexOutput/upserver/KVSyncReviewTests/Evidence/20260922-072831-309/,汇总 Latest-review.log 含断言与源码 hash;入口控制台结果为 KVSyncReviewTests/Latest-console.log。首次执行证据另存于 Evidence/20260922-072648-825/,未覆盖。
覆盖重点:
- 完整绝对路径对照及 Windows 两类非法根路径拒绝。
- active v1 + pending v2 重启,R=B/R=L 不解锁,v1 确认推进 v2 base。
- localOnly 叠加、确认不覆盖及 Delete 清覆盖。
- 五个磁盘故障点:BeforeWrite、AfterWrite、AfterFlush、BeforeReplace、AfterReplace;内存不发布、冻结、实际磁盘重开与不确定标记。
- 数字溢出、字段类型、重复字段和尾随根拒绝;每次拒绝后修复测试材料并重新打开,验证句柄未泄漏。
- 12 种批次关联损坏(包含双 active/unknown、无对应 pending、目标/base 不符、非法批次 ID/结构等),以及合法同序号/更新序号的对照。
- 普通冲突 B 与最新远端观察不同的合法快照重开。
- 有效主档/损坏备份、缺失主档/遗留备份、独占锁和重复 Dispose。
上述磁盘数据均为合成测试字符串,根目录均在审查目录,没有读取或写入真实游戏缓存。URI 只作为身份字符串使用,没有网络请求。
6. 主会话证据的只读复核
- 已阅读
KVSyncTests/Program.cs和KVSyncTests/Latest.log:86 通过、0 失败。其中另含真实子进程独占锁、写步骤进程退出、101 个 key 分批、24 个并发编辑、超限文件以及更多输入/恢复用例。本 agent 没有重跑或改动主测试。 - 已读取
kv3a-unity-compile.json:Success=true,ErrorCount=0,WarningCount=274。本 agent 没有启动或控制 Unity;这是主会话执行并落盘的编译证据。
7. 后续门与限制
- 3B 验证真实 PlayerKVClient 配可控传输、固定会话、票据精确确认/Superseded、水位、取消和 Close 原子准入;不能用本次同步 gate 用例替代异步关闭验收。
- 3C 再做组合和限定联调;本次没有进行正式服 KV 写入或 Unity 业务存档运行验收。
- Windows/.NET 文件故障和进程退出测试不证明移动设备文件替换、文件锁错误分类及断电耐久性。当前 Unity 编译成功也不等于最终平台文件系统验收;真机/最终包按既定计划单列,当前不打包。
- Json.NET 扩展语法继续按阶段 2/方案约定兼容;结构校验不是防篡改签名,也不能识别所有仍满足格式的外部内容改写。本轮不新增手写 JSON 解析器或密码学完整性机制。
- 本地 Ordinal 字典不保证服务端数据库 collation 区分大小写;服务器仍无 CAS。不得扩展为跨设备强一致保证,实际生产 key 和桥接安全门留阶段 4。
收尾结论:R1 闭环,3A 限定代码审查通过;下一步是已批准范围内的 3B 开发与独立验收。