6.5 KiB
阶段4A独立实施复核
日期:2026-09-23。复核者:用户指定外部AI(ZCode会话)。范围:4A实施(Owner只读接口、PlayerKVLocalReadResult、PlayerKVGameSessionBridge、KVGameBridgeTests、三个csproj单行差异)的只读代码审查+证据核验+独立复跑。本轮未修改任何代码/csproj/共享文档,未访问正式服,未使用子Agent。
受审版本(SHA256,本复核逐项重算与交付一致)
| 文件 | SHA256(前16) |
|---|---|
| PlayerKVSessionOwner.cs | BFB5AC0DF38BCACC…(完整值与复核提示词一致) |
| PlayerKVLocalReadResult.cs | 9A00AA0ECEA286FC… |
| PlayerKVGameSessionBridge.cs | DD888351BFA4BBA0… |
| 三个旧csproj | 与project-diff-check.json一致;本复核用KVGameBridgeTests/*.csproj.baseline逐文件diff,各恰好只有已审一行Compile新增 |
边界证明核验:owner-diff-check.json——移除新增读取接口后Owner还原为3B终版F2F0430B…(Owner其余部分字节级未动,票据/关闭/保守语义未改的强证据);scope-hash-check.json——其余基线生产文件、3C测试Program、3B/Review Program未变。
复核结论
接受本轮4A实施。无P1/P2。 建议主会话逐条裁决后关闭4A;4B仍需独立方案与评审,本报告不自动授权。
代码审查(静态推导+实测结合)
ReadLocalSnapshot(Owner行141–167):通过。 操作租约内执行state.ReadLocal()(3A原子合并读);读后在admission锁内复查IsCapturedOwnerCurrent/closing/closed,失效优先返回StaleOrClosing(B-S3优先级落实);InvalidOperationException(非Ready)同样先判失效再归NotReady;失败结果Data=null,无伪空档(A1/A3实测)。租约计入Close drain(A8的read-close-reentry用例证实)。
PlayerKVLocalReadResult:通过。 成功路径深拷贝为ReadOnlyDictionary(不可变、与内部字典脱钩——A1断言旧快照不随后续写变化);失败路径不携带数据。
PlayerKVGameSessionBridge:通过。 逐项:
- 尾链串行(tail任务链):Open/Close全部串行化,锁内只做短临界区,任何await不持桥monitor。
- Close屏障:
CloseAsync锁内closeGeneration+++撤销活动槽,锁外Cancel()(取消回调不持monitor);CloseCoreAsync等待前驱后关闭Owner,完成后才放行后续Open——旧传输/Owner真正收尾前新Open不发布句柄(A4实测:忽略取消闸门下Close与102 Open均未提前完成,释放后MaxActive=1)。 - 排队Open取消:登记回调仅在
!Entered时置Cancelled;进入后在临界区检查token/generation——无窗口(A7实测:取消立即返回,原Close与后续合法Open正常完成)。 - 重复Open:后者经尾链先
CloseSlotAsync(previous)再建新槽,至多一个活动Owner,旧句柄因Revoke全部拒绝(A5/A6实测:旧句柄Update/Delete/Flush/Read/Wait拒绝且102请求数不变)。 - 初始Get失败(B-S1):
opened.Success==false→清活动位+Revoke+DisposeLifetime→OwnerRejected,后续Open可用(A3实测initial-read-failure-releases-slot)。 - 清理失败:catch路径
closeFailed=true且保留Creation/Closing/Owner,后续Open一律CloseFailed(A3实测close/create-cleanup-failure-blocks-reopen);Close失败同置closeFailed,重复Close返回同一lastClose任务。 - 取消与CTS.Dispose并发:
Slot.Cancel/DisposeLifetime经cancellationGate串行,Cancel异常被记录并上抛为清理失败(保守)。 - 固定句柄不重绑定:Handle只持创建时Slot;不Dispose登录session(仅ReferenceEquals归属检查)——session提前Dispose或重登换Cookie后读写/等待拒绝、桥接仍能完成Close且零变更外发(A9实测)。
- 不隐式Flush、不重试Unknown:Close路径只调Owner.CloseAsync(3B语义),A10实测关闭0写、重开读到pending、显式Flush确认;A3-write-unknown-retains-ticket-semantics实测Unknown票据语义保留。
非阻塞观察(P3)
- P3-1|KVSyncTests偶发一次失败(预存在,非4A引入)。 本复核首轮批量复跑出现"Passed 85; Failed 1"(当时输出管道未捕获失败用例名);随后连续3次完整复跑86/86、退出码0。该套件编译的5个生产文件hash未变(scope-hash-check+本复核重算),判定为偶发时序敏感(该套件含子进程文件锁用例)。建议:后续证据记录保留失败用例名;若复发,单独立项排查偶发源。不阻塞4A。
- P3-2|Handle各操作的失效判定粒度略异。 Update/Delete/Read用
slot.Revoked,WaitForTicket用完整slot.IsCurrent(Epoch)(含session/Cookie/外部epoch检查)——后者更严,方向保守,无安全影响;仅备忘统一时机(可留4B接线前评估)。 - P3-3|
isCurrent回调需轻量。Slot.IsCurrent同步调用外部回调;限定自审已记录"不可同步等待自己的Close",与设计一致,向4B接线方转述该约束即可。
独立复跑证据(本会话自有)
| 命令 | 结果 | 真实退出码 |
|---|---|---|
dotnet run --no-restore --project KVGameBridgeTests |
18组通过,断言226,失败0(新run 20260923081335_85da5c67…) |
0 |
| KVContractTests | 42/42 | 0 |
| KVSyncTests | 86/86(见P3-1:另有一次偶发85/86) | 0 |
| KVSyncCoordinatorTests | 29/29 | 0 |
| KVSyncCoordinatorReviewTests | 通过 | 0 |
| KVStage3CTests --offline | 8/8 | 0 |
dotnet build KVLiveTests(仅构建未运行) |
0错误 | 0 |
uloop compile --force-recompile true+get-logs |
错误0条(证据:KVGameBridgeTests/unity-compile-review.json、unity-errors-review.json) |
0 |
脱敏核验:artifact-and-transport-check.json——result.json中fixture key/value、Cookie/Token字段、用户路径0命中,accessedFormalServer=false;传输边界依据为synthetic.invalid替身注入+默认handler仅反射检查(交付已如实声明该字段非抓包结果)。
A1–A12逐行核对
交付矩阵§4的18个用例与本复核复跑输出、源码路径逐项对应属实(A1合并快照/A2校验取消与Get中Close/A3失败释放槽位与清理失败阻塞/A4-A7关闭排水与排队取消/A8读竞争与优先级/A9会话失效/A10不隐式Flush/A11默认传输/A12回归与边界);未发现矩阵与证据不符项。
结论
接受本轮4A实施;无P1/P2;P3三条仅记录。 建议主会话逐条裁决P3后关闭4A;4B启动需独立方案与评审(含新档策略、游戏回调隔离、消费流程),不因4A通过自动放行。