Files
ft/CodexOutput/upserver/P2AlphaAudit/A3-空态语义与未消费键裁定.md

8.1 KiB
Raw Blame History

A3:空态语义与未消费键裁定

2026-09-28,主会话只读盘点。以下是源码观察及后续候选,不是生产兼容修订批准。

M15:不是随机坏档,但也不能宣称任意入口都可安全读取null

101保存的FishingChallengeData原字符串为null。旧代码有明确生产路径:FishingChallengeManager.ClearFishingChallengeData(184~189)清对象后DoSave;OnSettleFinished(false)(869~875)同样清对象后DoSave;DoSave(1082~1084)直接JsonConvert.SerializeObject。因此这不是只能靠手工造出的值。旧PlayerData.InitData在792~794遇到键才调用InitChallengeData(string),后者218反序列化得到null。

null和缺键的等价性必须限定前态:新对象默认null,受控Reset也清null;这两种前态下,缺键不装载与显式null的最终对象均为null。但旧对象已经有挑战数据时,“缺键不调用Init”与“显式null清对象”并不等价,不能推广为热换号安全,也不能通过删键替代兼容。

全部直接引用清单与分类

M15-all-references.txt和A3-M15-read-ledger.json/md覆盖当前Scripts全部142处标识符文本出现:94处需活动上下文、20处空判断/条件读取、6处赋值、1处别名、1处可保存null、1处声明、8处验证、11处注释。逐行保留路径、当前行号、原语句及上下文,注释/验证没有冒充运行读取。M15-type-and-key-references.txt扩大到Assets/LocalPackages的类型及key引用。该枚举不声称覆盖反射、资源持久化事件或任意动态加载代码的全部调用图。

入口/组 null与fresh缺键行为 结论
ShouldOpen:139;ChallengeState:1028 显式null分别false/state0 两种空态观察一致
Init:244、ProcessLastChallenge:278 无当前事件且null则返回;有当前事件才new并InitBaseData;历史结束处理先判非null 空态与活动初始化分开,不应在Decode中激活挑战
UpdateLocalData:569、AddScoreByQuality:601、OnSettle:840、UpdateTimeData:946、GetTimeSpan:1072、GetOpenEventKey:1087 有null分支/前置检查,具体见当前源码 同一空对象前态下分支一致;不扩大为所有异步续体安全
IsFirstOpen:110、IsTimeAllow:169、IsFinishCurLevel:200、IsClearAllLevel:205、各比分/结算/机器人/奖励方法 多处直接解引用,需要已初始化活动 null与fresh缺键均不满足活动前置;不能为让这类入口继续而造默认挑战
CheckAutoOpenPanel:495、IsSettleState:1062 状态0路径不进入需要时间的分支 对空态有保护
InChallenge:510 状态0仍可发起资源加载;后续依赖eventChallengeMain/config,未独立证明无效入口无法触发 保留为活动入口生命周期限制,本次不修,不批准101真实挑战运行
HomeBtnChallenge.OnEnable:64~119 CheckInit→ShouldOpen;false时禁用并return,其后才直接读EventId/uiStep 正常首页入口按此门工作;后续动画/事件读取仍依赖活动上下文
Challenge UI/Scene/Road/Players 全部直接读取位置见台账;例如SceneRoad.Awake:81取别名,82读_thisEventData.step 依赖挑战场景合法进入;直接null解引用在两种空态下都不安全,未运行这些场景
KV捕鱼奖励准入UserService.KVFishingReward:127 非null才判断挑战状态 不将缺挑战自动当作已启动挑战
Clear/OnSettleFinished(false)/DoSave 明确可写回JSON null 保留原样本和原key,不授权自动删键

最小候选:后续独立兼容方案只讨论“存在且为JSON null”的挑战输入如何保持未激活空态,原对象结构的严格检查保持。不得改变活动入口/场景/计分/奖励算法;需要测试fresh、Reset后、旧状态到空态、非对象错误输入及保存语义。此处没有修改Schema或Apply。

M22:null列表是原构造默认值,不能用清空礼包消除诊断

GeneralEventPackData是struct,构造函数:30的selections默认null,:45原样保存。BargainPackData.UpdateData:204~216构造时未提供selections,随后SaveData:181序列化全部_data;原加载PlayerData:829~836按redirectID/PackType=3调用LoadData(:185原样赋值)。101的redirect4056001在冻结配置中PackType=3(A3-M22-pack-config.json),不是因为礼包类型错配而故意拒绝。

M22-all-selections-references.txt核查Assets/LocalPackages当前C#文本:旧构造与序列化可保留null;现有Bargain玩法中没有找到读取列表元素/Count的业务逻辑,元素访问出现在KV验证;新DecodeBargain:238 IntegerList要求数组,PlayerKVBargainState:318拒绝null,Apply:64复制新List。因此不是只改Schema一行即可保证整个物化链支持null。

候选优先讨论保留null的窄兼容:Schema、解码DTO、Apply/Snapshot各自应明确定义null、空数组和非空数组;其余11整数/2布尔/浮点等字段与_isPresent不能丢失。不以“当前没读元素”为由把整键删除、重建礼包或自动把null写成[]。真正改动白名单和测试须另完整评审。

26种模块外键(42个出现项)

100个样本出现项中,58个出现项关联31模块;42个出现项/26种键在该解码图之外。Schema的Valid仅覆盖31模块,不等于raw中所有key逐值通过。Raw保留这些键供其他消费者,并不承诺其生命周期隔离或迁移安全。

类别 键与旧消费定位 本次处置
泛型活动仓库 Event1v1BattleSlapData、EventBoostPackData、EventBossFightData等;具体类型引用见key台账,EventDataRepository:26/38/55按typeof(T).Name读写(原B3-C001/C002等) 保留;需具体活动解码/写入归属专项,未为它们造Schema
懒加载或独立模块 AquariumEventDataNewKey、DigCount/DigGridData、EventBingo、EventLuckGameRecord、EventLuckMagicPlayfabData、EventPartnerStatueData、MiniBPKeyNew、LuckyTaskADKey、OfferStoryChain、OfferSweepPackData、Pack1A1Data/Pack1A2Data、SoloDataKey、TransitionData、WelcomeBack、DeferredRewardStashService、LastPaymentTime 逐key旧引用与B3字面量/同文件候选位于A3-key-ledger.json;存档保存不等于已批准所有玩法使用;不清理
当前C#文本未定位 EventLuckyTowerData、EventOfferDevourFishData、EventTransitionTokenDic、Leadboard_LastContinent、SeasonStampData Assets/LocalPackages搜索exit1无命中,见搜索元数据;可能历史/外部/动态来源,无法判断废弃,原值保留

原审查引用的“234行”是早期文本初扫;本轮复用的B3DesignAudit/calls.json实际223个语法调用。按原B3-C编号/历史行号引用,并附当前源码引用;同文件候选不冒充精确语义绑定,也不因无字面量命中推断无读写。

其他严格项与样本覆盖限制

项 本轮观察 后续规则建议
AD坏槽/多表示 两样本M08未报诊断;Achievements/DecodeAchievements分别解析AchievementData、AD、ad并检查重叠值;当前样本没有覆盖所有旧坏槽 保留严格拒绝迁移候选;不得沿用旧静默跳过,也不得宣称坏槽已实测兼容
未知鱼/错归属/缺卡配置/同卡冲突 M03本轮未报诊断;DeriveFish显式检查鱼/地图/卡及下标;部分旧派生会限制重量/等级、补最低卡数量 原字节与运行派生值区分,原备份不改;没有新样本时仅记录合同,不能说全历史档支持
core布局/重复表示/时间/数值 新主档、别名与旧顶层存在优先级/冲突处理;此次无新diagnostic,不代表所有布局/时区组合 保留各表示与采样UTC/cfg指纹;不手工拼新core试图消诊断
未采到Present的模块 M18/M23/M24/M27/M28/M29等本批无相应直接键,M30仅加载壳 明确Absent覆盖,未来要拓展这些业务需相应样本和用例;不把31节点运行过当31类真实档齐全

结论:两类兼容冲突已得到具体来源及边界,不需要先修改整个活动框架;后续最小单位应为101两类空态的精确兼容方案。模块外键和样本代表性仍是正式启用前问题;本轮不修改101,也不覆盖102已续进度。