卡②(结构小件批p1-p7+V15): 七点定点修落地+运行期违约通道负面套件+wr10 偏运缝拆验收——①p1 状态角标判据去重(main_overlay_flow._sync_status_entry 一组重复赋值语句删除,battle_live 局部量随之退役=wr1 载体);②p2 确认窗开合归模态栈单口(main 两处 _on_confirm_* 改 _close_modal;存档删除入口改 root._open_modal(root.confirm_dialog) 后再 open,遮挡记账/挂起兜底/开侧同步同口);③p3 棋盘动作与 stop 两入口显式 settlement 空防护(锁谓词异常时不崩于空引用);④p4 会话更替即清队:_begin_session 首行 _row_pacer.flush()(待播行不住局态=机制保证非时序约定);⑤p5 缝拆:RewardEconomy 删跨域直持(_fx/_ctx/set_fx)改注入 luck_bias_query: Callable,reward_roll 发射与 bias_rewards 求和收回 BattleFxHost.luck_bias_for(cell_count)(三参形 dispatch,不带 facts——禁复用 fx_emit 的第四实参会打开 when 事实条件面),组装点 set_fx 一行换赋值一行 1 换 1;类变量 15−2+2 净 15,gdstyle 无第 16 枚;⑥p6/p7 RngService 未知用途标签与未播种取数两分支加 violation_handler 记录位+release 下 return null 空引用即刻崩(fail-fast 传导,合法路径不可达)——debug 下 assert 先中断函数本体两态不可判别,故记录位是唯一可观测面;⑦board_generator/reward_economy 各加 fatal_handler 注入位并由组装点接 orchestrator._fatal(release 剥 assert 后仍经 battle_result 封印真中止)。新件 tests/unit/core/run_time_fatal_test.gd(manifest 登记 expect=1 negative=true):wr5 协作件 _fatal 经组装点传导 p5 封印+缺省形态不外溢/wr6 未知标签通道/wr7 未播种通道(各用新建 RngService 实例,播种断言 _counter==0)。wr10 三条入 variant_placement_test=判定面夹具白盒装载(现网数据无 bias_rewards 行,沿 tree_rules_v11_test 先例)+接线同源+权重生效 77+4*2。验收:variant_placement 49 checks 全绿(wr10 ①②③ PASS:空订阅 0/命中 1 行/装载后 2;查询口有效且与宿主同源;偏运池实测 85);run_time_fatal_test 退出码 1 三点绿;pacing_queue 绿(wr4 前置夹具真入队 2 行→更替后清零);ui_click_probe 问题 0(wr2 遮挡账开/关两侧断言);round_flow_skill_pool 130 checks 绿;wr11 dump_battle 六组(L{1,2}×S{42,779401,779501})与改前 before_* 逐字节 cmp 全等;gdstyle 基线外新违规 0、恶化 1(level_map_screen 类变量 22>21=iter38 存量非本批触碰面)、基线文件零改动〔结构小件批 V15〕

This commit is contained in:
DKChan committed 2026-10-27 18:39:53 +08:00
1 parent 3a20a40891
commit ea322599f7
14 files changed
+211 -27

No files matched your search

+7 -2
View File
@@ -173,6 +173,7 @@ func _replay_locked_click() -> void:
# 会话生命周期:_ready 建闲时态(永非 null——全组合根零空判责),
# 开局/续玩/调试两层各建新会话,旧会话整节点 queue_free()(帧末回收;新节点先挂树无真空窗)。
func _begin_session(adventure_session: bool) -> void:
_row_pacer.flush() # 会话更替即清队(待播行不住局态——机制保证,不靠时序约定)
if run_scope != null:
run_scope.queue_free()
run_scope = RunScope.new()
@@ -308,7 +309,7 @@ func _start_adventure_from_menu() -> void:
#(确认才删、取消只关窗——裁决 3)。"new_adventure" 消费方已随卡② 主菜单确认链摘除退役
#(mn6/V5——主菜单零确认残留),分派机制保留(卡④ 到位接入第三消费方不返工)。
func _on_confirm_accepted() -> void:
confirm_dialog.close()
_close_modal(confirm_dialog) # 模态栈单口
match _confirm_consumer:
"delete_slot":
save_manager.delete_slot(_confirm_consumer_slot)
@@ -317,7 +318,7 @@ func _on_confirm_accepted() -> void:
func _on_confirm_declined() -> void:
confirm_dialog.close() # 只关窗(取消无状态变更——裁决 3:取消不删)
_close_modal(confirm_dialog) # 只关窗(取消无状态变更——裁决 3:取消不删);关侧恢复归 ModalFlow
_confirm_consumer = ""
@@ -718,6 +719,8 @@ func _on_board_action(cell: Vector2i, kind: String) -> void:
if treasure_sel != 0 and kind == "dig":
_treasure_ui.attempt_use(treasure_sel, cell)
return
if run_scope.settlement == null:
return # 入口显式空防护(双保险——锁谓词正常态已挡,防锁判据异常时崩于空引用)
var outcomes: Array[Variant] = run_scope.settlement.minesweeper.settle_batch([{"action": kind, "cell": cell}])
var accepted: bool = not outcomes.is_empty() and bool(outcomes[0].accepted)
logger.log_action(kind, cell, accepted)
@@ -745,6 +748,8 @@ func _on_stop_pressed() -> void:
if _input_locked():
return
# stop 经批次提交(排雷玩法 D1×6①——不直调 行动经济)
if run_scope.settlement == null:
return # 入口显式空防护(同棋盘动作入口——零成本双保险)
var outcomes: Array[Variant] = run_scope.settlement.minesweeper.settle_batch([{"action": "stop"}])
logger.log_action("stop", Vector2i(-1, -1), not outcomes.is_empty() and bool(outcomes[0].accepted))
if not outcomes.is_empty() and String(outcomes[0].get("outcome", "")) == "voided":
+1 -7
View File
@@ -85,6 +85,7 @@ static func _on_save_select_load(root: Variant, slot: int) -> void:
static func _on_save_select_delete(root: Variant, slot: int) -> void:
root._confirm_consumer = "delete_slot"
root._confirm_consumer_slot = slot
root._open_modal(root.confirm_dialog) # 模态栈单口(显示编排/挂起兜底/遮挡记账——与其余覆盖层同口)
root.confirm_dialog.open("删除存档位 %d?删除后该档不可恢复。" % slot, "删除", "取消")
@@ -108,18 +109,11 @@ static func _sync_status_entry(root: Variant) -> void:
if root.status_panel == null or root._modals == null or root.board_zone == null or root.level_screen == null:
return
var map_on: bool = root.level_screen.visible
var battle_live: bool = root.run_scope.level_active or root.run_scope.settlement != null # 调试两层无 level_active——settlement 判据补位
root.board_zone.status_badge.visible = root.run_scope.level_active and not map_on
root.level_screen.status_badge.visible = map_on
# 置灰判据为排除式(调试浮窗开态不计入:对局中浮窗开着时角标仍可点)
root.board_zone.status_badge.disabled = root._modal_flow.badge_greyed_battle() # 互斥域谓词
root.level_screen.status_badge.disabled = root._modal_flow.badge_greyed_map()
# 状态角标判据(同上——重复语句在案):
# 战斗屏=对局内(冒险或调试两层)且地图屏未激活;地图屏=随屏;开始菜单零角标
root.board_zone.status_badge.visible = root.run_scope.level_active and not map_on
root.level_screen.status_badge.visible = map_on
root.board_zone.status_badge.disabled = root._modal_flow.badge_greyed_battle() # 互斥域谓词
root.level_screen.status_badge.disabled = root._modal_flow.badge_greyed_map()
# 调试浮层角标(全局浮层任何 UI 不遮挡——可见性不随场景变,只抬 offset
# 避让:地图屏底栏 85px 常驻,角标抬至底栏上方 16px;其余场景右下角 16px 贴底)
root.debug_badge.offset_bottom = -101.0 if map_on else -16.0
+2 -2
View File
@@ -37,8 +37,8 @@ func open(text: String, confirm_label: String, cancel_label: String = "取消")
_text.text = text
_confirm_btn.text = confirm_label
_cancel_btn.text = cancel_label
# z 序纪律:树序由组合根构建序保证——本弹窗在 main._build_ui 尾部
# add_child(开始层/过场层之后 = 子级最末,登记序 = 树序 = 绘制序恒最上)
# z 序纪律:层序唯一事实源=main.LAYER_CONTRACT(树序与登记序同源派生);开合单口
# 归组合根 ModalFlow(挂起兜底/遮挡记账/开侧同步)——本类只管文案与显示,不自行抬层
visible = true