# 阶段4B2检查点2字段差异补审方案 日期:2026-09-23。状态:**待外部差异评审,尚未批准以下两项语义修订**。 修订2整包已经外部审查并由主会话逐条裁决、批准受控实施;该事实不撤回。检查点1的Lease/Registry和原4B1回归已完成。检查点2在把字段合同映射到实际codec时发现以下两处冲突。本文件是明确的局部修订提案,不覆盖原受审附件,不把实施中新发现写成已经通过。 本轮未修改M08/M23或其他业务模块,没有用错误合同先做Apply。检查点2尚未完成,检查点3/4不越序启动。 ## 1. D1:旧AD与顶层AchievementData并非相同JSON值类型 证据(路径相对项目根): - `Client/Assets/Scripts/DataCenter/DataCenter.PlayerData.cs:992`起,`NewPlayerDataDic.AD`调用`LoadAchievementDataToObject`;顶层`AchievementData`调用另一个`LoadAchievementData`。 - `Client/Assets/Scripts/DataCenter/AchievementDataManager.cs:35`起:`LoadAchievementData`读取`Dictionary`,而`LoadAchievementDataToObject`读取`Dictionary`,把每个字符串按`|`切分后调用`AchievementData.ToObject`。 - `AchievementData`的三个字段分别为`Id:Int32`、`Target:UInt64`、`day:Int32`。 - 受审附件§3.1将`LDD、AD`统一描述为分别同`LuckDataDic、AchievementData`的旧JSON格式。因此AD会被错误实现成对象值;合法旧字符串值会被拒绝,反而可能接受现有该入口不支持的对象值。单纯增加严格校验不能解决这个格式定义错误。 **建议修订:** 仅替换附件§3.1的AD格式定义,其余优先级不变: | 表示 | 严格读取合同 | 规范数据 | |---|---|---| | 顶层AchievementData | JSON对象;每个键为已定义ConditionType,值为AchievementData对象;Id/Target/day按声明整数类型检查 | ConditionType→(Id, Target, day) | | NewPlayerDataDic.AD | JSON对象;每个键为已定义ConditionType,值必须是字符串,恰好`Id|Target|day`三槽;分别按Int32/UInt64/Int32、InvariantCulture解析 | 同上 | | NewPlayerDataDic.ad | 已审`ConditionType:Id|Target|day`,以`;`连接 | 同上 | 空对象和空紧凑整体允许为空集合。JSON null、对象值冒充旧AD字符串、缺槽/多槽、空记录、溢出、重复JSON属性、枚举归一化后重复键和未定义枚举拒绝为Malformed。不把坏AD转换为对象格式重试,也不回落其他合法表示掩盖错误。所有现存表示先独立严格解码,再按已审“共有字段冲突则ConflictingRepresentations、一致选新”规则处理:`ad > AD > 顶层AchievementData`,选中表示整字典替换,不合并旧账号条目。 验收新增:三种表示各有合法/缺失/坏值;AD字符串正例及对象值反例;Target超过UInt64、重复枚举别名、三者共存一致/冲突;AD损坏而ad合法仍失败。只用合成枚举记录,不使用真实账号档。应用M08同对象A→B缺失后为空集合,且零保存/事件。 ## 2. D2:FootPrint的64位合同与32位实际承载矛盾 证据:`Client/Assets/Scripts/Services/FootPrintService.cs`中`LoadData`先`ulong.Parse`,再转`EFootPrint`;同文件声明`public enum EFootPrint : int`,私有字段及公开属性也是这个枚举。原附件§3要求UInt64并“保持原值位宽”,但§5只指定替换`_footPrint`。例如合成值`4294967296`仅第32位为1,直接转32位枚举会丢失该位;不能把解析器接受UInt64当成真实模块保留了64位。 **建议修订:** 不更改公开枚举基础类型或IFootPrintService/PF原方法。在同一白名单`FootPrintService.cs`增加仅受控KV适配使用的`ulong`完整位集字段及internal只读验证访问: 1. Decode使用UInt64纯值;不根据当前已声明8个枚举位拒绝未声明高位,不收紧既定64位输入域。 2. Reset同时清空完整位集和现有`_footPrint`。 3. Replace直接保存完整UInt64;同时把低32位按明确的unchecked转换投影到`_footPrint`,供现有32位枚举视图表示。完整位集才是受控KV加载的完整状态;公开枚举视图不能声称反映全部64位。 4. 不改变旧`LoadData`/`UpdateFootPrint`/`UploadData`,不新增公开接口,不允许受控加载后进入玩法。guard仍必须阻止受控范围内UploadData触发PF写入口。 5. 4B3未来读写路由须另审如何消费完整位集;本补审不批准通过旧UploadData保存64位KV状态,也不承诺受控范围退出后该对象可以用于玩法。 这一方案增加M23明确的KV加载字段及Reset断言,属于需要补审的状态合同变化。另两条路线均不建议:把公开enum改为ulong会扩大PF/调用方兼容面;拒绝高32位会缩窄已审UInt64合同并引入新的拒档政策。 验收新增:0、低位组合、2^31、2^32、UInt64.MaxValue完整值保持;低32位视图符合既有枚举位操作;负值、超UInt64拒绝;A高位→B缺失时完整字段与视图同时归零。真实对象在Unity宿主验证,离线算术/DTO测试不替代该项。PF原方法源码不变且既定默认PF行为回归仍执行。 ## 3. 范围、顺序和审批理由 只修正AD codec合同和M23完整位集承载;没有新增业务文件白名单、额外功能、联网或持久化授权。基线和原外部报告保持不变。本补审通过后由主会话逐项裁决,形成附件覆盖层,继续检查点2所有31组,再按原顺序3/4。检查点1成果无需重做,后续最终回归仍覆盖它。 暂停相关代码的依据是用户“方案完整评审后编码”要求,以及主方案§9:“如构建依赖、公开接口、白名单不够,先形成差异方案并补审”,附件§5关于新增状态/消费差异先补审的边界。这里不是重新索取修订2实施授权,而是对新发现的具体格式与状态合同冲突送审。 P2-α真实档兼容性与迁移/用户产品确认的启用门保持。4B1保持关闭;4B2实施中、未交付验收;4B3未启动、G4未通过。固定地址`http://s101.local:18080/`,只用Unity CLI Loop,不使用UnitySkills,暂不打包。 ## 4. 外部审查应逐项回答 - D1:源码证据、三种表示及规范化优先级是否正确,边界和测试是否足够。 - D2:完整64位保存+旧32位视图是否满足本阶段受控合同,是否存在必须修改公开面/旧PF路径的隐藏依赖。 - 两项修订是否仍在既有文件边界内;给出通过/退回及P1/P2/P3清单,不以“代码实现时决定”代替裁决。 - 本轮是设计差异补审,不代替未来4B2完整独立实施复核,不把检查点1局部证据解释为31组模块通过。