diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 8b146062..319e1d2a 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -1331,53 +1331,6 @@ func _ms_digest(ms, ae) -> Array: return [[int(ms.hero_pos().x), int(ms.hero_pos().y)], rev, seals, ae.ap, ae.phase, ms.seal_count()] -# ---- 地图战斗资源·身份面单元冒烟(格面资源:roll 恰一次 / 雷安同池 / 幂等 / 清图批尾)---- - -func _smoke_reward_identity_unit() -> void: - print("--- 地图战斗资源·格面资源身份面 ---") - var rng = load("res://core/rng_service.gd").new() - rng.set_master_seed(20260911) - var reward_economy_factory = load("res://core/reward_economy.gd") - var reward_economy = reward_economy_factory.new(_db, rng) - var eligible: Array = [] - for i in range(6): - eligible.append({"cell": Vector2i(i, 0)}) - check(reward_economy.roll_board(eligible), "roll_board 受理") - check(not reward_economy.roll_board(eligible), "重复 roll_board 被拒(恰一次——double-roll 守卫)") - # 身份查询投影 = {reward_id, cell_type, tier};五型封闭 - var types_ok := true - var types_seen := {} - for e in eligible: - var ident: Dictionary = reward_economy.query_identity(e.cell) - if not (ident.has("reward_id") and ident.has("cell_type") and ident.has("tier")): - types_ok = false - if not RewardTable.CELL_TYPES.has(String(ident.cell_type)): - types_ok = false - types_seen[String(ident.cell_type)] = true - check(types_ok, "query_identity 投影 = {reward_id, cell_type, tier} 且五型封闭(样本 %s)" % str(types_seen.keys())) - # 清单外坐标 = null(E19——封锁格不入清单的同款出口) - check(reward_economy.query_identity(Vector2i(99, 99)) == null, "清单外坐标查询 = null(封锁格无身份同口径)") - # 同格重复受理幂等:同一快照逐字段相同 - var snap1: Dictionary = reward_economy.grant(eligible[0].cell) - var snap2: Dictionary = reward_economy.grant(eligible[0].cell) - check(JSON.stringify(snap1) == JSON.stringify(snap2), "同格重复 grant 幂等(同一快照——受理恰一次)") - check(reward_economy.grant(Vector2i(99, 99)) == null, "清单外 grant 拒绝") - # 清图批尾身份:clear_default 唯一活行 clear_blast(blast 型正向);重调幂等 - var cs1: Dictionary = reward_economy.grant_clear() - var cs2: Dictionary = reward_economy.grant_clear() - check(String(cs1.cell_type) == "blast" and String(cs1.reward_id) == "clear_blast", "清图批尾身份 = clear_blast(clear_default 唯一活行)") - var cb_range := [-1, -1] - for row in _db.reward.rows: - if String(row.reward_id) == "clear_blast": - cb_range = [int(row.get("power_min", row.power)), int(row.get("power_max", row.power))] - check(int(cs1.power) >= int(cb_range[0]) and int(cs1.power) <= int(cb_range[1]), - "清图奖励 power ∈ 表区间 [%d, %d](roll 值 %d——配置推导)" % [cb_range[0], cb_range[1], int(cs1.power)]) - check(JSON.stringify(cs1) == JSON.stringify(cs2), "grant_clear 同批次重调幂等") - # 退役后受理拒绝 - reward_economy.retire_mapping() - check(reward_economy.grant(eligible[0].cell) == null, "映射退役后 grant 拒绝(生命周期闭合)") - - # ---- 地图战斗资源·伤害量值区间冒烟(roll 域内 + 中点锚 + 变异实际流动 + 定值行不受扰)---- diff --git a/game/tests/unit/core/board_gen_reward_test.gd b/game/tests/unit/core/board_gen_reward_test.gd index 5fd3d340..f1a8a35f 100644 --- a/game/tests/unit/core/board_gen_reward_test.gd +++ b/game/tests/unit/core/board_gen_reward_test.gd @@ -31,6 +31,7 @@ func _init() -> void: _rng.set_master_seed(42) # 套执行序沿源编排序 _smoke_layout_cell_formula() + _smoke_reward_identity_unit() quit(Kit.finish("board_gen_reward_test")) @@ -64,3 +65,50 @@ func _smoke_layout_cell_formula() -> void: Kit.check("L%d 格边在 26–46 档内(%dpx)" % [L, int(cell)], cell >= 26.0 and cell <= 46.0) board_view.free() + + +# ---- 地图战斗资源·身份面单元冒烟(格面资源:roll 恰一次 / 雷安同池 / 幂等 / 清图批尾)---- + +func _smoke_reward_identity_unit() -> void: + print("--- 地图战斗资源·格面资源身份面 ---") + var rng = load("res://core/rng_service.gd").new() + rng.set_master_seed(20260911) + var reward_economy_factory = load("res://core/reward_economy.gd") + var reward_economy = reward_economy_factory.new(_db, rng) + var eligible: Array = [] + for i in range(6): + eligible.append({"cell": Vector2i(i, 0)}) + Kit.check("roll_board 受理", reward_economy.roll_board(eligible)) + Kit.check("重复 roll_board 被拒(恰一次——double-roll 守卫)", not reward_economy.roll_board(eligible)) + # 身份查询投影 = {reward_id, cell_type, tier};五型封闭 + var types_ok := true + var types_seen := {} + for e in eligible: + var ident: Dictionary = reward_economy.query_identity(e.cell) + if not (ident.has("reward_id") and ident.has("cell_type") and ident.has("tier")): + types_ok = false + if not RewardTable.CELL_TYPES.has(String(ident.cell_type)): + types_ok = false + types_seen[String(ident.cell_type)] = true + Kit.check("query_identity 投影 = {reward_id, cell_type, tier} 且五型封闭(样本 %s)" % str(types_seen.keys()), types_ok) + # 清单外坐标 = null(E19——封锁格不入清单的同款出口) + Kit.check("清单外坐标查询 = null(封锁格无身份同口径)", reward_economy.query_identity(Vector2i(99, 99)) == null) + # 同格重复受理幂等:同一快照逐字段相同 + var snap1: Dictionary = reward_economy.grant(eligible[0].cell) + var snap2: Dictionary = reward_economy.grant(eligible[0].cell) + Kit.check("同格重复 grant 幂等(同一快照——受理恰一次)", JSON.stringify(snap1) == JSON.stringify(snap2)) + Kit.check("清单外 grant 拒绝", reward_economy.grant(Vector2i(99, 99)) == null) + # 清图批尾身份:clear_default 唯一活行 clear_blast(blast 型正向);重调幂等 + var cs1: Dictionary = reward_economy.grant_clear() + var cs2: Dictionary = reward_economy.grant_clear() + Kit.check("清图批尾身份 = clear_blast(clear_default 唯一活行)", String(cs1.cell_type) == "blast" and String(cs1.reward_id) == "clear_blast") + var cb_range := [-1, -1] + for row in _db.reward.rows: + if String(row.reward_id) == "clear_blast": + cb_range = [int(row.get("power_min", row.power)), int(row.get("power_max", row.power))] + Kit.check("清图奖励 power ∈ 表区间 [%d, %d](roll 值 %d——配置推导)" % [cb_range[0], cb_range[1], int(cs1.power)], + int(cs1.power) >= int(cb_range[0]) and int(cs1.power) <= int(cb_range[1])) + Kit.check("grant_clear 同批次重调幂等", JSON.stringify(cs1) == JSON.stringify(cs2)) + # 退役后受理拒绝 + reward_economy.retire_mapping() + Kit.check("映射退役后 grant 拒绝(生命周期闭合)", reward_economy.grant(eligible[0].cell) == null) diff --git a/reports/批B-断言迁移账本-2026-10-22.md b/reports/批B-断言迁移账本-2026-10-22.md index 212fbf80..3a606349 100644 --- a/reports/批B-断言迁移账本-2026-10-22.md +++ b/reports/批B-断言迁移账本-2026-10-22.md @@ -268,6 +268,7 @@ 逐套变异记账(每条独立一轮:改坏→跑新宿主→红→`git checkout` 还原→`git status` 清洁确认): - `_smoke_layout_cell_formula`(2 条):2/2 验红。变异点——board_view.gd:233 删 `- float((n - 1) * sep)` 格间距项(bug⑥ 原缺陷形态;红唯一两条迭代齐红 L1 438/L2 442 > 436,档内条保持绿);board_view.gd:234 clamp 上界 46→25(该条守面=钳制带本体——夹具板实测格边 41/33 为带内值,带内改界不红,改界出带方验红;红唯一两条迭代齐红 25px < 26,网格高条保持绿)。 +- `_smoke_reward_identity_unit`(10 条):10/10 验红(全部红唯一 1/14)。变异点——reward_economy.gd:89 roll_board 尾 return true→false(红「roll_board 受理」);:39 相位守卫 `_phase == "ready"`→`"never"`(红「重复 roll_board 被拒」);:113 投影删 tier 键(红「query_identity 投影」);:111 清单外出口 return null→{}(红「清单外坐标查询」;null→{} 形态避免 `_mapping[cell]` 缺键 crash);:140 grant 幂等缓存出口改扰动副本 duplicate+stacks=99(红「同格重复 grant 幂等」——重算快照值相等,非扰动副本形态红不了);:137 grant 清单外出口 return null→{}(红「清单外 grant 拒绝」);:87 `_clear_identity = clear_rid`→`"gp_coin"`(红「清图批尾身份」,power 掷定仍循真 clear_rid 故 :1977 power 条保持绿——隔离成功);:85 `_clear_power` 区间掷点→`power_min - 1`(红「清图奖励 power ∈ 表区间」roll 23 < 24);:152 grant_clear 幂等缓存出口改扰动副本(红「grant_clear 同批次重调幂等」);:163–164 两点变异 `_phase = "retired"` 与 `_mapping.clear()` 双双 pass 化(红「映射退役后 grant 拒绝」——该条守面=相位门+映射 wipe 联合,单点均被另一机制代偿必须两点)。 ## 十、支援线 9 项待裁闭合(2026-10-22 主会话裁)