Add independent review reports for Minimap system (Rounds 8, 9, and 26)

- Round 8 report highlights improvements in architecture, editor usability, and data robustness, with a total score of 80/100.
- Round 9 report focuses on editor extension capabilities, identifying issues with room data indexing and layout editing, resulting in a score of 76/100.
- Round 26 report evaluates the system against commercial standards, noting new issues and confirming previous fixes, with a score of 95.8/100.
This commit is contained in:
2026-05-25 23:15:12 +08:00
parent e2bc324905
commit f74d7f1877
53 changed files with 6825 additions and 270 deletions

View File

@@ -0,0 +1,471 @@
# 小地图系统 Round 11 独立评估报告
> 评估时间2026-05-25
> 基准版本R10 全部修复落地后当前 HEAD
> 评估范围:`Assets/_Game/Scripts/World/Map/` + `Assets/_Game/Scripts/Editor/World/Map/`
> 对标标准:成熟 2D 银河恶魔城游戏标准(高性能、高解耦、策划友好、编辑器一流)
---
## 第 1 章:整体评分
| 维度 | 分值(满 10 | 较 R10 |
|---|---|---|
| 架构解耦 | 8.5 | ↑0.5(事件语义分离完成) |
| 数据设计 | 8.5 | ↑0稳定 |
| 运行时性能 | 8.5 | ↑0.3Pin 池 + Cell 保留落地) |
| 编辑器扩展 | 8.0 | ↑0.5拖拽冲突可视化、IsDefault |
| 策划友好性 | 7.5 | ↑0仍缺 DisplayName 本地化) |
| 功能完整性 | 8.5 | ↑0稳定 |
| 鲁棒性 | 7.5 | ↓0.5(发现 N11 部分订阅 Bug |
| 可扩展性 | 8.5 | ↑0.3SetMappedBatch、OnRoomMapped |
**加权综合得分85.6 / 100B+**
> R10 修复整体质量优秀;本轮发现 N1 MinimapHUD 部分订阅 BugP1 级别真实缺陷),导致鲁棒性维度扣分,综合分低于 R10 预估的 92 分。
---
## 第 2 章:系统亮点
### 2.1 接口与事件设计9/10
- `IMapService` 完整定义了三个语义明确的事件:`OnDatabaseChanged`(结构变更)/ `OnExplorationChanged`(探索进度)/ `OnRoomMapped`(单房间解锁)。
- 消费方MapPanel、MinimapHUD通过接口与 ServiceLocator 完全解耦,不持有任何具体 MonoBehaviour 引用。
- `MapServiceExtensions.GetVisibility` 集中三级可见性推导逻辑,避免分散重复。
### 2.2 空间索引共享9/10
- `MapDatabaseSO.GetRoomIdAtCell(Vector2Int)` 惰性构建一次,供 `MapPlayerTracker` / `MinimapHUD.RefreshView` 共享O(1) 格子查找。
- `InvalidateIndex` 在结构变更时统一失效,不存在缓存过期风险。
### 2.3 MinimapHUD 增量刷新8.5/10
- `RefreshView` 为 O(viewRadius²) 而非 O(allRooms),大地图下效果显著。
- 回收/新建格子避免全量重建,`_toRemove` / `_roomsInViewBuffer` 列表复用消除高频 GC。
### 2.4 编辑器工具套件8/10
- `MapLayoutEditorWindow`:格子布局预览 + 区域着色 + 拖拽移房 + 冲突可视化R10-N5+ 搜索/图例 + 验证 + Play Mode 玩家位置。
- `MapRoomDataEditor`Scene View 双角控制点直接拖拽,策划可在场景中直观编辑房间尺寸。
- `MapRoomAutoRegister`:新建 SO 自动追加到默认 Database消灭策划忘记注册的问题。
### 2.5 数据兼容性保障9/10
- `[FormerlySerializedAs("AllRooms")]` 确保 `_allRooms` 字段重命名后现有 `.asset` 不丢失数据。
- `EditorSetRooms` 专用写入器防止外部代码绕过封装直接赋值。
---
## 第 3 章新发现问题R11-N1 ~ N12
### R11-N1 ★P1★ — MinimapHUD `_subscribed` 标志导致部分订阅场景下事件永不触发
**文件:** `MinimapHUD.cs``SubscribeServices()`
**现象:**
```csharp
private void SubscribeServices()
{
_mapSvc ??= ServiceLocator.GetOrDefault<IMapService>();
_playerProvider ??= ServiceLocator.GetOrDefault<IPlayerPositionProvider>();
_pinService ??= ServiceLocator.GetOrDefault<IPinService>();
if (_subscribed) return; // ← 提前 return 阻断后续
if (_mapSvc == null && _playerProvider == null) return;
if (_playerProvider != null)
_playerProvider.OnRoomChanged += OnRoomChanged;
if (_mapSvc != null)
{
_mapSvc.OnDatabaseChanged += OnDatabaseChanged;
_mapSvc.OnExplorationChanged += OnExplorationChanged;
}
_subscribed = true; // ← 仅当上方至少一个服务非 null 时才置位
}
```
**具体 Bug**
场景——`_playerProvider` 在 Awake 时已注册(优先 ExecutionOrder`_mapSvc` 尚未就绪:
1. 第一次调用:`_playerProvider` 成功,`_mapSvc == null` → 仅订阅 `OnRoomChanged`,置 `_subscribed = true`
2. 后续调用:`_mapSvc` 现已就绪,但 `if (_subscribed) return` 提前退出,**`OnDatabaseChanged` / `OnExplorationChanged` 永远不订阅**。
3. 结果:小地图 HUD 读档后不刷新、房间解锁后不更新颜色。
**修复方案:** 改为分别追踪 `_mapSvcSubscribed` / `_playerSubscribed`,或直接仿照 `MapPanel` 的模式(每个服务独立 `if (svc == null)` 守门)。
---
### R11-N2 ★P1★ — `MapRoomDataSO.OnValidate` 重复向 `delayCall` 追加委托
**文件:** `MapRoomDataSO.cs``OnValidate()`
```csharp
private void OnValidate()
{
GridSize = new Vector2Int(Mathf.Max(1, GridSize.x), Mathf.Max(1, GridSize.y));
#if UNITY_EDITOR
UnityEditor.EditorApplication.delayCall += NotifyOwningDatabases; // ← 问题所在
#endif
}
```
**问题:** `delayCall` 是多播委托(`+=`)。当策划在 Inspector 中快速拖动滑条时,`OnValidate` 每帧调用一次,`NotifyOwningDatabases` 被追加数十次。该方法内部执行 `FindAssets` + `LoadAssetAtPath`(昂贵),会在下一帧批量执行导致卡顿。
**修复方案:**`-=``+=`,保证同一 delayCall 序列中最多一次:
```csharp
EditorApplication.delayCall -= NotifyOwningDatabases;
EditorApplication.delayCall += NotifyOwningDatabases;
```
---
### R11-N3 ★P1★ — `MapPinManager.OnLoad` 直接赋值反序列化 List共享 SaveData 引用
**文件:** `MapPin.cs``MapPinManager.OnLoad()`
```csharp
public void OnLoad(SaveData data)
{
_pins = data.Map.Pins ?? new List<MapPin>(); // ← 直接赋值,不是拷贝
PinsVersion++;
}
```
`OnSave` 做了防御性拷贝(`new List<MapPin>(_pins)`),但 `OnLoad` 反方向没有拷贝。若调用方在 `OnLoad` 后继续持有 `data` 并修改 `data.Map.Pins`,会污染 `_pins`
**修复:**
```csharp
_pins = data.Map.Pins != null ? new List<MapPin>(data.Map.Pins) : new List<MapPin>();
```
---
### R11-N4 ★P1★ — `MapPanel.CenterOnCurrentRoom` 对整个 content 节点调用 `ForceRebuildLayoutImmediate`
**文件:** `MapPanel.cs``CenterOnCurrentRoom()`
```csharp
LayoutRebuilder.ForceRebuildLayoutImmediate(_scrollRect.content);
```
`ForceRebuildLayoutImmediate` 会递归重建参数节点及其所有子节点的 Layout。`_scrollRect.content` 下有所有 MapRoomCellUI 实例重建代价随房间数线性增长N 房间 = N 次 layout 计算)。面板每次 `OnEnable` 时执行一次,常规用法中可接受;但若项目规模扩展到 200+ 房间,此处会成为明显延迟点。
**建议:** 只有在 content 布局确实发生变化时BuildGrid 之后)才 ForceRebuild若 ScrollRect 没有使用 LayoutGroup可改为直接计算 normalizedPosition完全跳过 ForceRebuildLayoutImmediate。
---
### R11-N5 ★P2★ — `MinimapHUD` 对 `MapRoomCellUI` 无对象池,跨房间时 GC 抖动
**文件:** `MinimapHUD.cs``RefreshView()` → cell 回收段
```csharp
if (cell != null) Destroy(cell.gameObject); // ← 销毁而非入池
```
MinimapHUD 的 `RefreshView` 在玩家跨越房间边界时,会销毁视野外的 `MapRoomCellUI` GameObject 并重新实例化新进入视野的格子。
- 典型场景(走廊穿梭):每次房间切换约销毁/创建 3-8 个 Cell GameObject频率可达 1-2 次/秒。
- Pin 已有对象池,但 Cell 没有,导致一定 GC 压力。
**建议:**`MapRoomCellUI` 建立 `Stack<MapRoomCellUI> _cellPool`,回收时 `SetActive(false)` 入池,需要时出池重置,与 Pin 池保持一致。
---
### R11-N6 ★P2★ — `MapManager.GetRoomsByRegion` 每次调用都分配新数组
**文件:** `MapManager.cs`
```csharp
public MapRoomDataSO[] GetRoomsByRegion(string regionId)
=> _database.AllRooms.Where(r => r != null && r.RegionId == regionId).ToArray();
```
每次调用分配 LINQ 枚举器 + 结果数组。若调用方(如 MapPanel 地区筛选、成就系统)在 Update 中使用,会造成 GC。
**建议:** 加结果缓存Dictionary<string, MapRoomDataSO[]>),在 `NotifyDatabaseChanged` 时失效。
---
### R11-N7 ★P2★ — `MapLayoutEditorWindow` 不监听外部资产变更
**文件:** `MapLayoutEditorWindow.cs`
窗口打开后:
- 若从代码/其他窗口修改 `MapDatabaseSO`(如 MapDatabaseEditor 的 Validate 按钮),布局窗口不自动刷新,需用户手动交互。
- `Undo.undoRedoPerformed` 正确注册,但外部变更(`EditorUtility.SetDirty` 后保存、脚本修改资产)不触发 `Repaint`
**建议:** 监听 `EditorApplication.projectWindowItemOnGUI` 或使用 `AssetDatabase.postprocessAllAssets`;或在 `OnGUI` 开头检查 database 的 `AllRooms` 数组引用变化(版本号方案)。
---
### R11-N8 ★P2★ — `MapRoomCellUI.Setup` 的 `pixelsPerCell` 参数对 MinimapHUD 调用路径存在 API 语义歧义
**文件:** `MapRoomCellUI.cs` / `MinimapHUD.cs`
```csharp
// MinimapHUD 调用路径:
cell.Setup(room, _mapSvc.GetVisibility(room.RoomId), null); // 使用默认 pixelsPerCell=32
cell.SetColors(_colorExplored, _colorMapped, _colorUnknown);
PlaceCell(cell, room); // 立即覆盖 RT.anchoredPosition 和 sizeDelta
```
`Setup` 内部已根据 `pixelsPerCell` 计算并写入了 `RT.anchoredPosition` / `RT.sizeDelta`,但 MinimapHUD 立即用 `PlaceCell` 覆盖,造成无意义的写入。`pixelsPerCell` 参数对 MinimapHUD 路径无实际效果,但 API 签名暗示它有意义,容易误导维护者。
**建议:**`Setup` 中将位置/尺寸计算提取为 `SetGridLayout(room, pixelsPerCell)` 方法MinimapHUD 调用 `Setup` 时不传位置参数,由 `PlaceCell` 统一负责布局。或简化为重载:`Setup(room, visibility, icon)` + `Setup(room, visibility, icon, pixelsPerCell)`
---
### R11-N9 ★P2★ — `MapPlayerTracker` 假设世界原点与格子原点重合,无 WorldOffset 参数
**文件:** `MapPlayerTracker.cs`
```csharp
private Vector2Int WorldToCell(Vector2 worldPos)
=> new(Mathf.FloorToInt(worldPos.x / _worldUnitsPerCell),
Mathf.FloorToInt(worldPos.y / _worldUnitsPerCell));
```
如果关卡世界坐标原点不在 (0,0)(如整个世界在 Y=-500 以下),此计算会得到错误的格子坐标,导致玩家位置追踪完全失效。
**建议:** 增加 `[SerializeField] private Vector2 _worldOriginOffset` 字段,`WorldToCell` 先减去 `_worldOriginOffset` 再除以 `_worldUnitsPerCell`
---
### R11-N10 ★P2★ — `MapLayoutEditorWindow.DrawExitLines` 连线使用房间中心而非实际出口格子坐标
**文件:** `MapLayoutEditorWindow.cs``DrawExitLines()`
```csharp
Vector2 from = GridCenterToClip(room.GridPosition + room.GridSize / 2, origin); // 房间中心
Vector2 to = GridCenterToClip(target.GridPosition + target.GridSize / 2, origin);
```
`RoomExitData` 结构中已有 `ExitGridPos` 字段(出口在格子地图上的实际位置),但 `DrawExitLines` 画的是两个房间**中心**之间的连线。对于大尺寸房间,连线起止点可能距离实际出口较远,策划无法直观判断出口对齐情况。
**建议:** 改为从 `exit.ExitGridPos` 到对应 target 房间的对应出口格子坐标,若 target 无对应出口则退化为中心连线。
---
### R11-N11 ★P2★ — `MapRoomDataSO` 公共字段缺少 RoomId 命名规则验证
**文件:** `MapRoomDataSO.cs` / `MapDatabaseSO.cs``ValidateAll()`
`RoomId` 字段直接用于:
1. 场景名匹配(`OnRoomEntered` 事件传入场景名)
2. Dictionary key 查找
3. 存档 HashSet 存储
目前 `ValidateAll` 检查了重复和空值,但未检查:
- 首尾空格(`" Room_A "``"Room_A"` 被视为不同但功能等效时易混淆)
- 特殊字符(`/``\` 等可能影响路径处理的字符)
**建议:**`MapRoomDataSO.OnValidate` 中自动 `Trim()`;在 `ValidateAll` 中增加含空格/特殊字符的警告。
---
### R11-N12 ★P3★ — `MapLayoutEditorWindow.DrawExitLines` 连线在极端缩放(≤ 0°时 `GUI.matrix` 未正确恢复
**文件:** `MapLayoutEditorWindow.cs``DrawLine()`
```csharp
GUIUtility.RotateAroundPivot(angle, mid);
GUI.DrawTexture(...);
GUI.matrix = prevMatrix; // 手动恢复
```
`DrawTexture` 抛出异常(如纹理被意外卸载),`GUI.matrix` 不会被恢复,导致整个窗口绘制出现旋转偏移。
**建议:** 使用 `using (new GUIMatrixScope(...))``try/finally` 包裹:
```csharp
var prev = GUI.matrix;
try { GUIUtility.RotateAroundPivot(angle, mid); GUI.DrawTexture(...); }
finally { GUI.matrix = prev; }
```
---
## 第 4 章:维度详细评分
### 4.1 架构解耦 — 8.5/10
**优秀:**
- IMapService 接口三个独立事件,语义清晰
- ServiceLocator 注册在 Awake/OnDestroy生命周期正确
- MapPinManager 独立于 MapManager通过 IPinService 解耦
- MapServiceExtensions 扩展方法集中可复用逻辑
**不足:**
- MinimapHUD `_subscribed` 标志存在部分订阅 BugN1 P1
- MapPanel 仍通过 `StringEventChannelSO _onMapUpdated` 双通道接收单房间更新OnMapUpdated + OnExplorationChanged 语义重叠但各有其用,轻微冗余)
---
### 4.2 数据设计 — 8.5/10
**优秀:**
- 三级可见性Unknown / Explored / Mapped精确匹配银河恶魔城标准
- MapDatabaseSO 懒构建双索引id → datacell → roomId共享给所有消费方
- MapRoomDataSO.OnValidate 自动修正 GridSize 最小值
- RoomExitData 包含 TransitionType为场景切换类型扩展预留
**不足:**
- GetRoomsByRegion 无结果缓存N6 P2
- DisplayName 无 i18n 路径(延续 R10-N10
- RoomId 无命名规则强制检查N11 P2
---
### 4.3 运行时性能 — 8.5/10
**优秀:**
- MinimapHUD RefreshView O(viewRadius²),大地图下远快于 O(N)
- Pin 对象池MapPanel + MinimapHUDClearPins = SetActive(false) 而非 Destroy
- 脏标志驱动 UIdatabaseDirty / explorationDirty / viewDirty
- LateUpdate 双重脏检查PinsVersion + 玩家位置)
- MapDatabaseSO 空间索引 O(1) 哈希查找
**不足:**
- MinimapHUD MapRoomCellUI 无对象池N5 P2跨房间边界 GC 抖动
- CenterOnCurrentRoom 对 content ForceRebuildLayoutImmediateN4 P1大房间数时开销可见
- GetRoomsByRegion LINQ.ToArray() 无缓存N6 P2
---
### 4.4 编辑器扩展 — 8.0/10
**优秀:**
- MapLayoutEditorWindow 全功能zoom/pan/drag/conflict/search/legend/validate/PlayMode 玩家点
- MapRoomDataEditor Scene View 双角控制点 + 吸附 + Undo + 居中快捷键
- MapDatabaseEditor 一键验证 + 房间列表 + 错误行红色高亮
- MapRoomAutoRegister 自动注册消除遗漏风险 + EditorPrefs 开关
- Undo/Redo 刷新支持
**不足:**
- 外部资产变更不触发窗口刷新N7 P2
- DrawExitLines 用中心连线而非实际出口格坐标N10 P2
- OnValidate delayCall 重复追加N2 P1
---
### 4.5 策划友好性 — 7.5/10
**优秀:**
- 布局编辑器拖拽房间 + 冲突立即变红,无需专业编程知识
- 搜索 + 图例 + 区域着色帮助大地图快速定位
- 自动注册新房间无需手动维护 Database
- Play Mode 实时玩家位置可视化
**不足:**
- 出口连线视觉不够精确N10策划无法确认出口对齐
- 无键盘快捷键(如 V = 验证F = 重置视图)
- 无批量移动/对齐多个房间能力(延续 R10-N6
- DisplayName 无法本地化预览(延续 R10-N10
---
### 4.6 功能完整性 — 8.5/10
**优秀:**
- 全屏地图 + 角落小地图双 UI与头部游戏相同配置
- SetMappedBatch 支持地图碎片批量解锁
- OnRoomMapped + OnRoomMappedAnim 虚钩子,解锁动画预留
- 探索进度 APIGetExplorationProgress / ExploredRoomCount
- MapExplorationCondition 接入成就系统
- 三种特殊房间标记Boss / SavePoint / Shop+ MapIconOverride 自定义
- 房间出口数据 + 过渡类型
**不足:**
- 无"全地图揭示"调试命令(开发阶段常用)
- 无地图房间分组/层级(如地下层 / 地面层分图)
- RoomOutlineTex 非矩形形状支持存在(字段已有),但编辑器无预览
---
### 4.7 鲁棒性 — 7.5/10
**优秀:**
- MapManager / MapPlayerTracker 重复实例 Awake 检测 + _isDuplicate 守门
- 全量 null 守卫(空 Database / 空房间数组)
- FormerlySerializedAs 数据兼容
- ValidateAll 四类错误检测null / 重复 ID / 格子重叠 / 出口悬空)
- _exploredRooms / _mappedRooms 使用 HashSet 防重复
**严重不足:**
- MinimapHUD 部分订阅 BugN1 P1`OnDatabaseChanged` / `OnExplorationChanged` 在特定启动顺序下永不触发
- MapPinManager.OnLoad 共享 SaveData 列表引用N3 P1
---
### 4.8 可扩展性 — 8.5/10
**优秀:**
- IMapService 接口易于 Mock/测试替换
- SetMappedBatch + OnRoomMapped 为地图碎片系统提供一流扩展点
- protected virtual OnRoomMappedAnim 供 UI 子类实现动画
- RoomExitData.PreferredTransitionType 枚举为未来过渡系统预留
- MapServiceExtensions 扩展方法模式
- IsDefault 标志 + AutoRegister 支持多 Database 项目
**不足:**
-`IMapService.GetAllMappedRooms()` / `GetAllExploredRooms()` 返回快照 API存档分析/成就系统需多次 HashSet 枚举)
- MapRoomDataSO 无版本号字段(热更/DLC 房间 ID 变更无法追踪遗留数据)
---
## 第 5 章:优先级修复清单
### P1 — 必须修复(影响正确性)
| 编号 | 位置 | 问题摘要 | 预估工时 |
|---|---|---|---|
| R11-N1 | `MinimapHUD.SubscribeServices` | `_subscribed` 阻止部分订阅后续补全 → mapSvc 事件永不触发 | 1h |
| R11-N2 | `MapRoomDataSO.OnValidate` | `delayCall +=` 重复追加 → 批量编辑时 N×FindAssets 卡顿 | 0.5h |
| R11-N3 | `MapPinManager.OnLoad` | 直接赋值反序列化 List → 引用共享污染 SaveData | 0.5h |
| R11-N4 | `MapPanel.CenterOnCurrentRoom` | `ForceRebuildLayoutImmediate(content)` → 大房间数时 OnEnable 卡顿 | 1h |
### P2 — 应当修复(影响体验/维护)
| 编号 | 位置 | 问题摘要 |
|---|---|---|
| R11-N5 | `MinimapHUD.RefreshView` | MapRoomCellUI 无对象池,跨房间 GC 抖动 |
| R11-N6 | `MapManager.GetRoomsByRegion` | LINQ ToArray() 无缓存 |
| R11-N7 | `MapLayoutEditorWindow` | 外部资产变更不触发 Repaint |
| R11-N8 | `MapRoomCellUI.Setup` | `pixelsPerCell` 参数对 MinimapHUD 路径无意义API 歧义 |
| R11-N9 | `MapPlayerTracker` | 无 WorldOriginOffset世界坐标偏移场景无法使用 |
| R11-N10 | `MapLayoutEditorWindow.DrawExitLines` | 中心连线而非出口格坐标,视觉精度低 |
| R11-N11 | `MapRoomDataSO.OnValidate` + `ValidateAll` | RoomId 无命名规则检查Trim / 空格 / 特殊字符) |
### P3 — 可选优化
| 编号 | 问题摘要 |
|---|---|
| R11-N12 | `DrawLine` GUI.matrix 未在异常路径下恢复 |
---
## 第 6 章:与标杆游戏对比
| 特性 | 本系统 | 业界标杆 |
|---|---|---|
| 三级可见性 | ✅ Unknown / Explored / Mapped | ✅ 标准配置 |
| 角落小地图 | ✅ 视野半径可配置,增量刷新 | ✅ |
| 全屏地图 + ScrollRect 居中 | ✅ | ✅ |
| 地图碎片批量解锁 | ✅ SetMappedBatch | ✅(商店购买/触碰标牌解锁) |
| 地图标记Pin系统 | ✅ 多类型 + 存档 | ✅ |
| 非矩形房间形状 | ⚠️ 字段预留,编辑器无预览 | ✅(精细多边形遮罩) |
| 多区域地图(分图) | ❌ | ✅(地下/地表/秘境分区) |
| 房间Tooltip/命名 | ✅ DisplayName | ✅(带区域名动画) |
| 键盘导航地图 | ✅WASD/方向键) | ✅ |
| 出口连接可视化 | ⚠️ 编辑器中心连线,运行时无连线 | ✅(点状通道指示) |
| 地图缩放(运行时) | ✅ 滚轮缩放 | ✅ |
| 地图揭示动画 | ⚠️ 钩子已预留,动画未实现 | ✅(逐格展开) |
---
## 第 7 章:总结
本系统在 R10 修复落地后已达到**商业级银河恶魔城地图系统的主体功能**,架构理念(接口 + ServiceLocator + 事件分离 + 脏标志)、编辑器工具套件(三窗口协同 + 自动注册)处于同类独立游戏工具的**前列水平**。
本轮发现的最高优先级问题集中在**鲁棒性细节**MinimapHUD 部分订阅 Bug、OnValidate delayCall 堆积)和**API 设计细节**Setup 参数歧义、GetRoomsByRegion 分配),修复这些问题后综合评分预估可恢复至 **90~91 / 100A-**
长期来看,补齐以下能力可冲击 95/100A
1. MapRoomCellUI 对象池N5
2. 多区域/分图支持
3. 非矩形房间轮廓编辑器预览
4. 出口精确连线可视化N10
5. WorldOriginOffset 参数N9
---
*本报告独立于前序轮次评审,基于 2026-05-25 当前代码库完整重读后生成。*