59 lines
6.5 KiB
Markdown
59 lines
6.5 KiB
Markdown
# 阶段4B2检查点2配置隔离与鱼数据派生独立审查(D4/D5)
|
||
|
||
日期:2026-09-23。审查者:ZCode会话。
|
||
|
||
**身份披露**:未参与本补审方案编写(由主会话编制)。延续性说明:D4/D5暴露的合同缺口(静态配置隔离、鱼数据派生规则未明确)属修订2附件M03/M18行粒度不足的延续——本审查按源码逐项复核方案断言。
|
||
|
||
本轮只读+仅新增本文件;未改代码/方案/基线/入口/TODO/日志;无子Agent、无正式服、无PlayMode、无Unity执行(纯静态审查,未运行任何用例)。
|
||
|
||
## 基线核对
|
||
|
||
`阶段4B2检查点2配置与派生差异受审基线-2026-09-23.json`共23项,逐项重算SHA256——**全部一致**。
|
||
|
||
## D4(PartnerInfoManager配置隔离):有条件通过
|
||
|
||
**源码事实核实(全部属实)**:
|
||
- `PartnerInfoManager.cs:27`:`private static Tables _tables { get; set; } = GContext.container.Resolve<Tables>()`——静态表缓存自GContext,类型初始化即冻结 ✓
|
||
- `:44`:`public static readonly int BuilderCapacity = _tables.TbEventPartnerConfig.InvitationCount[1]`——静态readonly,冷初始化时计算 ✓
|
||
- `:46`:实例`BuildPartners`数组长度绑定静态容量 ✓
|
||
- 外部`BuilderCapacity`数值读取恰为三处(EventPartnerGatherManager.cs:287/1182/1212);RobotInvitationSystem两处(:38/:135);Mining面板仅注释 ✓(308行`Init()`/309行`EventId`赋值不受字段→属性影响,盘点口径准确)
|
||
|
||
**评估**:冷/热类型初始化问题成立(首次构造临时实例会把临时表图永久留在静态`_tables`;已初始化则用旧表不服从不epoch快照)。推荐方案(`_tables`改实例只读+`BuilderCapacity`改计算属性+实例数组读实例表+`AddBuildPartner`改读`BuildPartners.Length`)能封住两种泄露路径;四条否决替代(反射改静态/假模块/只恢复GContext/正式Root预热)理由均成立。**批准PartnerInfoManager.cs新增白名单及公开字段→属性变化。**
|
||
|
||
**条件(均为实施时强制验收,方案已列,此处重申+补充)**:
|
||
1. 方案§2.2已列:全量Unity编译、全部引用盘点、预编译程序集依赖核查——不得仅凭编辑器可跑放行。
|
||
2. **P3-1(补充)**:`_tables`实例化后有**随动读取者**需在diff中显式列出——`:50`的`ActiveFriendCountThreshold`属性与`:242–244`的实例方法读`_tables`,实例化后自动转为实例读,行为正确但审查时须可见,避免"只改了两处"的误解。
|
||
3. **P3-2(补充)**:静态属性语义从"类型初始化冻结"变为"每次读当前容器"——固定配置下数值等价(D4-04覆盖),但**运行期配置热更场景**下两者可返回不同值:作为已知边界写入实施说明,不当作缺陷修复。
|
||
4. D4-02允许的"内存复制配置JSON改InvitationCount"仅限测试epoch内,最终B2-20用未改值表快照——边界正确,实施不得颠倒。
|
||
|
||
## D5(鱼数据派生):通过
|
||
|
||
**源码事实核实(全部属实)**:`DataCenter.PlayerFishData.cs:809–860`的`SetFishAllData`确实为"过滤+变换+三索引同步"复合链:
|
||
- 未知鱼`GetOrDefault`null→**静默跳过**;`AreaID != key`→`Debug.Log`+`continue`静默跳过(方案改UnsupportedSchema拒绝 ✓)
|
||
- 5字段复制→Quality≤5经`FishMaxG`修正MaxG(`FishMaxG`公式与方案§3.2逐项一致:`BaseWeight*PointExtraParam*(1+WeightRandom)`、Level>0乘`WeightMagList[level-1]`、`Mathf.Round(x*100)/100`、`min(原MaxG)` ✓)
|
||
- Level>0:`TbFishCard[FishCardID]`(缺卡**抛异常**而非拒绝)、`Level=min(Level,MaxLevel)`、`CardsRequiredList[Level-1]`阈值、`TotalCard=max` ✓
|
||
- `mapDataNew`/`fishData[ID]=同一实例`/`fishCardData[FishCardID]=TotalCard`三索引同步——**同卡ID跨鱼/跨地图覆盖使结果依赖字典遍历顺序**(方案"同一卡ID不同TotalCard→UnsupportedSchema"正确消除该不确定性)✓
|
||
|
||
**逐项裁决(提示词要求)**:
|
||
- **旧变换抽到纯Decode:同意**——变换是加载语义的一部分,不抽出则Replace后的运行态与PF路径不一致;快照字段清单(鱼ID/AreaID/Quality/BaseWeight/PointExtraParam/WeightRandom/FishCardID+卡MaxLevel/CardsRequiredList/WeightMagList)与变换链读表集合吻合,无遗漏。
|
||
- **原值比较先于变换:同意**——"先截断修正后比较"会把真实冲突掩盖为一致,顺序约束正确。
|
||
- **严格拒绝规则(未知鱼/错归属/缺表/下标/同卡冲突→UnsupportedSchema):全部同意**——取代旧静默跳过/抛异常,与"KV严于PF"既定政策一致;须计入P2-α迁移盘点(方案§3.1已列)✓。
|
||
- **三套索引一致性+同实例规则:同意**——模块内部`fishData`指向同Map同`FishWeightData`实例保持旧语义;跨输入/账号不共享。
|
||
- **9槽兼容槽保留不参与派生:同意**(与附件§3.2一致)。
|
||
- **float舍入:同意**——单精度保序+`Mathf.Round`中点行为对照(0/正负中点/相邻float/大值),不以双精度重排,正确。
|
||
- **InitLuck三标量保持0:同意**——源码中`InitFishLuck/InitBotLuck/BotCount`由玩法`Init→InitLuck`建立而非Load链;4B2只做Load、不运行Init,保持Reset的0是准确边界,不得套用表默认值。
|
||
|
||
**P3-3(补充)**:D5-02的"最大重量上下界"用例建议明确包含"原MaxG小于计算值时不抬高"(`min`语义的反向用例),防止实现误写成clamp双向。
|
||
|
||
## 遗漏检查
|
||
|
||
- M03当前消费键与可变集合:方案覆盖6整数字典、RodGSA六字段(GloveID/RodToSkin/GloveIds/SkinIds/GloveNewIds/SkinNewIds)、Luck三表示、Map动态键——与附件正式版2 M03行一致,未发现遗漏。
|
||
- M18/PartnerInfoManager状态:替换空新实例、GatherData=null、标志清空、不Init——与附件一致。
|
||
- 验证项D4-01~04/D5-01~05/D45-06能证明两项修订且明确"完整B2-20仍需31模块+guard零副作用"——不把局部通过冒充整体 ✓。
|
||
|
||
## 结论
|
||
|
||
- **D4:有条件通过**——条件为方案§2.2/§4已列强制项+本报告P3-1/P3-2随动说明;无需方案重报。
|
||
- **D5:通过**——含上述全部逐项裁决;P3-3为用例补充。
|
||
- 建议:批准PartnerInfoManager白名单扩展;两项均计入下一正式合同版本(沿用D1–D3合并先例);P2-α盘点追加"未知鱼/错归属/同卡冲突的旧静默跳过条目"。本轮仅静态审查;28模块局部实现与4B2整体的独立实施复核不在本次范围。
|