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

60 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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已续进度。