10 KiB
10 KiB
3C补修复交付与逐项证据
最新终审:用户指定外部AI复核接受,无新P1/P2;主会话核对版本并裁决R1–R5/F2关闭,3C/G3通过。见终审裁决。下方“待外部复核”等表述为当时状态,最新结论以本注为准。
日期:2026-09-23。实施者:主会话。R1–R5已修复并完成本轮技术验证,等待用户指定外部AI实施复核;不宣布3C/G3最终通过,4A未启动。
1. 代码与边界
- 仅修改 Program.cs,SHA256:66C41B8B0A8E0CD4FF13A3BED8212B3F61BF95E4707F5C6373B235E21B20492A。
- csproj未改,SHA256:27CC1AF41AC658EA9B8DE1ACB35E37058C294A93D30E232D42B9AFCBDD95A1E6。
- 八份链接生产源码与修复前记录一致;七份KV文件有3B历史基线,账号类仅按本次修复前基线核对。完整hash见 repair-final-source-hashes.json。
- 没有修改服务器、生产KV/登录、游戏入口、SDK或Unity配置;没有打包。故障均使用simulation,没有在正式服制造故障。
2. 修复效果
| 发现 | 最终实现 |
|---|---|
| R1 超时和清理重叠 | linked CTS贯穿登录/Owner/直接请求;超时禁止新写、先保存失败/不确定状态,取消后等待body及Close真正结束;原运行超时/Unknown不自动cleanup;独占run.lock排除并发执行。 |
| R2 manifest边界 | schema2严格字段/类型/重复属性解析;固定API、账号、runId、prefix及精确三个key;同run绑定、相对cache和路径/重解析点校验;登录前拒绝无效manifest;合法cleanup只输出key哈希。 |
| R3 失败结果被升级 | manifest保存原断言及执行状态;原result/log使用CreateNew不可覆盖;显式补cleanup产生独立JSON,只更新清理事实,原失败保持失败;Completed要求原断言通过且无未知/超时及两账号清理。 |
| R4 正式读回不足 | Delete前种值并确认存在;精确核对两账号不同值;新Cookie/Owner打开同缓存并经Get观察Ready;102后再次读取101;关闭后核对真实快照。 |
| R5 组合和证据缺项 | C子进程真实Get/Ready/精确值;Unknown重开后主动Flush且所有handler共享计数;损坏主档有效备份、缺主档bak/tmp、有效主档坏bak;失败编排、跨进程锁、Cookie/票据/环境隔离;诊断区分关闭前Ready和重开未Get的NotLoaded。 |
交付前自审补强:失败批次可能留下尚未结束的后续票据,不等待它们阻塞Close;失败只记录实际Flush汇总,成功才等待Confirmed票据。新增第二批Set未知、Delete尚未发送反例。参见 限定自审。
3. 实际执行与产物
所有命令在C:/projects/ft执行。使用现有依赖,避免默认restore读取受限的用户NuGet配置。
| 命令 | 退出码/结果 | 证据 |
|---|---|---|
| dotnet run --no-restore --project CodexOutput/upserver/KVStage3CTests -- --offline | 0,8组通过 | O目录result/log/diagnostic及child日志 |
| dotnet run --no-build --project CodexOutput/upserver/KVStage3CTests -- --live-s101 | 0,3条业务场景及双账号清理通过 | L目录result/log/manifest/diagnostic |
| dotnet run --no-restore --project CodexOutput/upserver/KVContractTests | 0,42/42 | repair-stage2.log |
| dotnet run --no-restore --project CodexOutput/upserver/KVSyncTests | 0,86/86 | repair-stage3a.log |
| dotnet run --no-restore --project CodexOutput/upserver/KVSyncCoordinatorTests | 0,29/29 | repair-stage3b.log |
| uloop compile --project-path C:/projects/ft/Client --wait-for-domain-reload true | 0,错误0/警告0 | repair-unity-compile.json |
最终证据目录缩写(下面每行使用):
- O:最终离线run,runId为20260923073652_de06350b988e4d1db4fc89937259a024。
- L:最终正式run,runId为20260923073720_199d4e8a22204ae5882057b1503092c6。
- E:补修复证据根目录。
- 目录内manifest/result/diagnostic/log文件名均为runId加相应后缀。
- 正式API固定http://s101.local:18080/;101/102;prefix和三个fixture key在L的manifest登记,报告不回显key或值。最终8张写票据Confirmed;每账号2次独立新会话清理读回为空;HadUnknownWrite=false、TimedOut=false、InFlight=false、Completed=true。
- 首次正式run 20260923073436_93b968171816414d8d0bec769a1acbad也已清理。因最后一次失败路径补强后源码hash变化,重跑得到L;两次证据都保留。
- 42/86/29与Unity在最后测试宿主失败分支补强之前执行;对应生产源码、Unity配置、既有回归源码没有后续修改,故未无意义重复。
- 原始历史run和外部审查原文未覆盖;simulation失败manifest是离线反例,不是正式服遗留待清理项。
4. 逐行验收映射
“本轮通过”是实施证据结论;独立验收门F2仍待完成,不能把分组数当作所有门自动通过。
| 矩阵项 | 具体测试/断言 | 产物位置 | 本轮结论 |
|---|---|---|---|
| S0 | 无参数、非法参数、非法child参数退出2;不创建run;Main分派在任何登录前退出 | E/repair-cli-guards.json、Main源码 | 通过 |
| S1 | 固定API/账号;错误API/账号/mode/字段类型等在登录前拒绝,计数0 | O/diagnostic guard条目;ManifestNegativeCases | 通过 |
| S2 | CreateManifest先保存;BeginWrite在转发前写InFlight;preflight两账号完成才授权写/cleanup | L/manifest;ExecuteOriginal、BeginWrite源码;离线碰撞反例 | 通过 |
| S3 | 同run精确绑定、cache固定相对路径;穿越、跨run、junction拒绝 | O/diagnostic;ManifestNegativeCases/CheckPath | 通过 |
| O1 | Set/Delete/localOnly/Flush真实Owner;关闭重开pending0、localOnly1 | O/state与ticketCounts;OwnerCombination | 通过 |
| O2 | A落盘pending、B恢复Flush、C新Owner Get后Ready且精确值/无pending | O/child-a/b/c.log、child-c-observation.json | 通过 |
| O3 | 独立Cookie身份、102缓存无101意图、跨Owner票据Blocked;正式值隔离 | O/diagnostic isolation条目;IdentityAndLock;L | 通过 |
| O4 | 不同API命名空间没有原baseline/pending/localOnly | O/diagnostic isolation条目;IdentityAndLock | 通过 |
| O5 | 未Close同进程/子进程Busy,Close后可重开 | O/child-lock.log;IdentityAndLock | 通过 |
| O6 | 远端观察基线/目标均Unknown;新旧handler合计仅一次写,重开后Flush不重发 | O/log O6;ConservativeUnknown | 通过 |
| O7 | 坏主档+有效备份、缺主档bak/tmp均RecoveryRequired | O/log O7-O8;CorruptionPolicy | 通过 |
| O8 | 有效主档+坏bak仍可打开 | O/log O7-O8;CorruptionPolicy | 通过 |
| D1 | 从真实Flush/票据累计,Owner关闭前状态/epoch/实例ID,重开快照NotLoaded及序号/数量;错误类别 | L/diagnostic、O/diagnostic;Confirm/VerifyOwner | 通过 |
| D2 | DTO仅手工选取状态元数据;扫描Cookie/Token字段、值、正文、用户名路径 | E/repair-artifact-scan.json;WriteArtifacts | 通过 |
| D3 | 完整fixture key不出现在diagnostic/result/log;只保留哈希 | E/repair-artifact-scan.json;WriteArtifacts | 通过 |
| H1 | 空Get改写为manifest三个key,返回越界key拒绝 | O/diagnostic handler-guards;HandlerGuards | 通过 |
| H2 | 越界Set/Delete不转发;Owner越界本地接受后Flush零写请求且Unknown | O/diagnostic outOfScopeMutationRequests=0;HandlerGuards | 通过 |
| H3 | handler绑定捕获Cookie、UseCookies=true、AllowAutoRedirect=false;错误响应一次无重试 | O/diagnostic responseAttempts=1;RealHandler/LiveAccount | 通过 |
| L0 | LiveLogin检查成功、输入身份匹配、非新建;不单靠PlayerId推断服务端身份 | L结果;LiveLogin;另结合L3的服务端值隔离 | 通过 |
| L1 | 两账号限定key碰撞预检为空才授权 | L/manifest CollisionPreflight=true;离线collision反例 | 通过 |
| L2 | 101种值、写/删、票据Confirmed、新Owner Ready | L/diagnostic playerId101、result | 通过 |
| L3 | 102不同值;写完再重开101并精确比较 | L/log reread-101-after-102、diagnostic | 通过 |
| L4 | 每次登录独立Cookie,重开不同Owner;同缓存Get和无pending/unknown快照 | L/diagnostic三个post-close-reopen;EnvironmentIO.Jars检查 | 通过 |
| L5 | CleanupCore精确m.Keys;RestrictedHandler再次约束 | L/manifest/result;CleanupCore源码 | 通过 |
| L6 | 101/102分别两次新会话Get为空 | L/manifest CleanupReads均2;log双清理行 | 通过 |
| L7 | 超时忽略取消闸门;Unknown;后续批次未知;失败清理;原失败补清理不得升级 | O/diagnostic case条目及所列simulation run,LifecycleGuards | 通过(synthetic) |
| R1 | 阶段2回归42 | E/repair-stage2.log | 通过 |
| R2 | 3A回归86 | E/repair-stage3a.log | 通过 |
| R3 | 3B回归29 | E/repair-stage3b.log | 通过 |
| U1 | Unity CLI Loop编译错误0/警告0 | E/repair-unity-compile.json | 通过 |
| F1 | 八份生产文件与修复前hash一致,csproj一致 | E/repair-final-source-hashes.json | 通过 |
| F2 | 设计独立审查及主会话裁决已完成;实施者自审已完成 | 设计审查/裁决、限定自审 | 外部实施复核待完成 |
5. 限制与交接
- 原运行超时/Unknown不自动清理;只有后续显式cleanup可补救。忽略取消并永久不返回时保持等待,不宣称已收尾。
- 崩溃遗留Running/InFlight的manifest被拒绝补cleanup;需人工核查,无自动恢复/解锁。schema1历史manifest不自动升级。
- 本轮真实正式run均清理完毕,无需再次cleanup;模拟Unknown遗留仅为离线证据。
- 磁盘永久不可写时无法保证最终结果文件写成,但manifest会尽可能保留失败/在途状态,不能按无文件推断通过。
- 不包含游戏存档接线、PlayFab移除、真机和打包;这些仍在后续阶段。
- 下一步把 外部AI复核提示词 交给用户独立AI。无P1/P2且逐条裁决后,才可恢复3C/G3并批准4A编码。