docs: ADR 体系废除 + architecture.md 确立为架构唯一事实源(2026-10-15 用户令:决策记录归 git commit log,不另存决策文档)

- 删除 design/dev/architecture/adr-0001~0007 共 7 份文件(内容留 git 历史可查)
- architecture.md:删「ADR 审计」「ADR 立项清单」两节;清除全文 ADR-000X 注记、QQ 表/S 表 ADR 引用;未决表关闭已落定项(QQ-01/02/03),立项清单在途事项转登记 QQ-11~14;补 A1 生成姿态事实、autoload 四件清单、board_generator 性能姿态;文档状态立「事实源地位」条
- CLAUDE.md:恢复 RNG 单点硬性红线(去 ADR-0007 引用);新增「架构事实唯一源」红线;规范导航架构行标注唯一事实源
- doc-conventions:§5 增「架构事实唯一源」行;§11 活文档清单补架构文档
- registry:architecture.yaml 删 18 处 adr 字段、autoload_set 补 SaveManager/MetaProgression、board_rending 更新为 Node2D 已落地事实;entities.yaml 12 处引用清除
- game/ 代码注释约 60 处清 ADR-000X 引用(事实与日期保留);豁免标记 ADR-0007-exempt → rng-seed-exempt(main.gd/static_scan.sh/architecture.md/06/iter27 五处同步)
- GDD/qa 实现报告/research 卡片/roadmap/tests README 引用全清;死链校验 1206 链接 0 死链、gdd_lint 0 不通过
- 代码中 adr/adr5 等为 adventure_runner 既有局部变量名(非 ADR 引用),未动
This commit is contained in:
DKChan committed 2026-10-15 23:52:30 +08:00
1 parent f22adb5564
commit 6c2dbc37c1
73 files changed
+193 -1118

No files matched your search

+12 -12
View File
@@ -101,7 +101,7 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/a
**同批其它改动(口径读法)**:明细行协议 **13 类 → 15 类**(新增窗口打开锚行 `window_open`、窗口跳过锚行 `window_skip`,服务"窗口段恒在案"验收;单点定义见[战斗结算](../../design/gdd/systems/战斗循环/战斗结算.md));状态表 **四行 → 六行**(暴走 / 失衡两行随标错反噬批收编);达标判定回归**单一判据**(可推理率 ≥ 及格线);求解器禁读雷位真值。本文正文的 v1/v2 范围登记与各历史批条目保留当时陈述,计数以现行文档与代码为准。
## 2026-09-11 关卡扩展批 · 切片级偏差登记(实现期决策,正式化时须回 GDD/ADR)
## 2026-09-11 关卡扩展批 · 切片级偏差登记(实现期决策,正式化时须回 GDD/架构文档)
1. **C1 线性推进器 provisional**:节点链来自 LevelTable(结构位 = 未来 C1 的数据承载面);路径分支/奖励点分布定稿权归 C1/C3。节点类型 closed enum {battle, reward, rest, boss};末节点必须 Boss(LevelTable schema 校验)。
2. **B4 新增 `grant_node_active()`**(接口漂移):关卡奖励点在可选类活行 {damage_item, heal_pack} 中 roll 一件直接入库;消耗 `reward_roll` 恰一 scope(与 board install 批同流异 scope,流集合封闭不变)。正式侧应走 B4 GDD 修订(节点奖励 = clear_reward 插槽族的新来源候选)。
@@ -266,19 +266,19 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/a
**全屏 States 与模态**:`legend_overlay.gd`(图例,状态槽空态说明)/ `settlement_review_overlay.gd`(明细回看)/ `battle_end_overlay.gd`(胜=金蜡封落于棋盘中央+判定行+回看入口;败=暮蓝 #5A6C8C+旗化光点收回)——统一模态登记序管理(`_open_modal` 打开时显式隐藏上方遮挡层,缺陷⑤纪律)。清图金粒喷泉+彩纸 / 完美排雷金光带+横幅 / 标中旗加重弹道 / Boss 紫赤影子爬棋盘 / 零合法板诚实 toast / chord·非相邻一次性提示(每 run 去重,`ux_hint_shown` 遥测)。**发现并修复历史 quirk**:TunePanel 默认 `visible=true` 靠被不透明开始层遮蔽的树序巧合——已显式初始化 false(缺陷⑤家族)。
**遥测**(playtest_logger 增 ux 行族,呈现层观测不改 core):`ux_round_input_ratio`(原始输入:AP 消耗,快照驱动)/ `ux_round_exit{path_tag}`(快照 round_facts.path——呈现层只订 B1 的 ADR 纪律下唯一合法源)/ `ux_refresh_attempt{result, round_refresh_index}` / `ux_window_choice` / `ux_reject{source, sub_reason}` / `ux_hint_shown{hint_id}`。
**遥测**(playtest_logger 增 ux 行族,呈现层观测不改 core):`ux_round_input_ratio`(原始输入:AP 消耗,快照驱动)/ `ux_round_exit{path_tag}`(快照 round_facts.path——呈现层只订 B1 的接线纪律下唯一合法源)/ `ux_refresh_attempt{result, round_refresh_index}` / `ux_window_choice` / `ux_reject{source, sub_reason}` / `ux_hint_shown{hint_id}`。
**探针**:ui_probe 增五区构建断言;ui_click_probe 增刷新确认链/图例开关/tooltip 触发/模态遮挡断言(图例/回看/窗口态/终局)/窗口期去饱和断言/首格可点计时(进入战斗屏口径 133–151ms ≤500ms AC;场景冷启动 ~700ms 为脚本首载编译域,观测项)——既有全部断言保留。** Waiting 刷新代理已按 OQ12 退役**:UI 刷新按钮仅挖掘期 Active 受理(presenter 门禁),原探针"窗口期点刷新"行为由 Active 确认链测试替代。
**回归**:smoke_all 149/149 · ui_probe PASS · ui_tune_probe PASS · ui_click_probe PASS(PROBE_SEED 7/11/23/99/42/77 六种子 done=true、选用失效=0、问题=0)。
**占位登记**:敌人意图视觉映射按 enemy_id 程序化占位(资产定稿归 B5);D区演出(喷泉/彩纸/弹道/影子)全部程序化占位;CJK 字体依赖系统回退(Windows 可用,随包字体归 D1 正式化硬性前置——ADR-0003);金蜡封/暮蓝氛围为色块占位级。
**占位登记**:敌人意图视觉映射按 enemy_id 程序化占位(资产定稿归 B5);D区演出(喷泉/彩纸/弹道/影子)全部程序化占位;CJK 字体依赖系统回退(Windows 可用,随包字体归 D1 正式化硬性前置——2026-09-12 定);金蜡封/暮蓝氛围为色块占位级。
**2026-09-15 补记(雾格移除)**:雾格机制已整体移除(见[不做清单](../../design/gdd/05-不做清单.md))——本节五区规格里的已开雾格 tint 残留、雾区全开一次性信号、图例「迷雾 = 无雷盲区」条目与雾首遇提示已随机制同批从实现与探针中删除(现行格态收窄为已开 / 未开两态,一次性提示只余 chord 与非相邻两项)。本文以上各历史批次条目保留当时陈述,现行实现与呈现义务以[战斗屏规格](../../design/ux/battle.md)与 [HUD框架](../../design/gdd/systems/表现与支撑/HUD框架.md)等现行文档为准。
## 2026-09-12 呈现层 code-review 修复批(/code-review CHANGES REQUIRED → 全项清偿)
**触发**:全切片 53 脚本 ~9400 行 /code-review(CLAUDE.md 代码规范 + ADR-0001/0003/0004 对照),裁决 CHANGES REQUIRED(7 项必改)。core/ 12 文件与 smoke 断言面整体健康;病灶集中于 tune_panel 封装破口、main.gd 结构回涨、三处呈现契约错位。
**触发**:全切片 53 脚本 ~9400 行 /code-review(CLAUDE.md 代码规范 + 架构文档对照),裁决 CHANGES REQUIRED(7 项必改)。core/ 12 文件与 smoke 断言面整体健康;病灶集中于 tune_panel 封装破口、main.gd 结构回涨、三处呈现契约错位。
**BLOCKING 修复**:
@@ -291,21 +291,21 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/a
**结构/封装修复**:
- **main.gd 761 → 667 行**(评审记录基线 433 行,400 行审视线):节点构建拆 `ui_assembler.gd`(只 new/add_child/布局,零接线零核心写);模态层级状态机拆 `modal_stack.gd`(缺陷⑤纪律载体);战斗流程叙事文案拆 `battle_narrator.gd`(兑现 main 头注"不拼呈现字符串");模拟编排拆 `tune_sim_controller.gd`。剩余行数 = ADR-0001 规定的接线 + 模式流转 + 核心写调用唯一出口(再压需移动 ADR 规定职责,登记为 D1 正式化批候审)。
- **level_runner core↔core 接线 lambda → 方法 Callable ×4**(ADR-0001 静态规则 S6——lambda 捕获 self 延长 RefCounted 生命周期/成环)。
- **main.gd 761 → 667 行**(评审记录基线 433 行,400 行审视线):节点构建拆 `ui_assembler.gd`(只 new/add_child/布局,零接线零核心写);模态层级状态机拆 `modal_stack.gd`(缺陷⑤纪律载体);战斗流程叙事文案拆 `battle_narrator.gd`(兑现 main 头注"不拼呈现字符串");模拟编排拆 `tune_sim_controller.gd`。剩余行数 = 组合根规定的接线 + 模式流转 + 核心写调用唯一出口(再压需移动组合根规定职责,登记为 D1 正式化批候审)。
- **level_runner core↔core 接线 lambda → 方法 Callable ×4**(静态规则 S6——lambda 捕获 self 延长 RefCounted 生命周期/成环)。
- **B1 新增 `diagnostic_snapshot()` 诊断观测面**:组合根诊断转储与 click_probe 停滞诊断全部改走成文 API,零下划线私有字段直读(此前直读 8 个)。
- **信号处理体去 lambda 化**:main 三处多行/单行 lambda(inter 层继续/单场入口/库存拒绝)改命名方法 + `bind`(规范 4.1)。
- 顺带:`can_request_refresh()` 断行格式修复(原单行内嵌 tab 不可读);`_build_inter_overlay` 死参 `parent_root` 删除;`_start_battle` 重复 `_start_overlay.visible = false` 去重;调试两层入口改由 `_start_battle` 统一取加成后满血(原传参在加成前取表值)。
**探针同步(缺陷回归断言随契约更新——3.3)**:ui_tune_probe 重写——应用/重置走真实按钮信号路径(`press_apply_for_probe` 接缝,ADR-0004"合成输入走真实翻译出口"口径);**新增两条回归断言**:⑦模拟后 hero 表保持基线(无残留)⑧应用加成 + 启动完整关卡后 runner 写表值 = 基线 × 单次加成(12/75;旧缺陷表现 24/112 在此被抓获);ui_click_probe 停滞状态与诊断转储改走 `diagnostic_snapshot()`。
**探针同步(缺陷回归断言随契约更新——3.3)**:ui_tune_probe 重写——应用/重置走真实按钮信号路径(`press_apply_for_probe` 接缝——合成输入走真实翻译出口口径);**新增两条回归断言**:⑦模拟后 hero 表保持基线(无残留)⑧应用加成 + 启动完整关卡后 runner 写表值 = 基线 × 单次加成(12/75;旧缺陷表现 24/112 在此被抓获);ui_click_probe 停滞状态与诊断转储改走 `diagnostic_snapshot()`。
**验证**:smoke_all **141/141** · ui_probe PASS · ui_tune_probe PASS(含新回归⑦⑧)· ui_click_probe 六种子(7/11/23/99/42/77)全 PASS(done=true、选用失效=0、问题=0)。新增 4 脚本 `.uid` 经 headless 编辑器扫描生成(语言纪律⑤)。
**登记待办(非本批范围)**:自动玩家策略四份复制收口(评审 W-3);schema 溯源行补齐(W-9);S1–S8 静态扫描脚本化后 S1 自建 RNG 豁免口径登记(W-1);views 转发层信号契约头注补齐(W-2)。
## 2026-09-13 封装收口批(代码架构审查 E1–E5/O1–O5/P3 修复——ADR-0009 候选项的切片侧预收口)
## 2026-09-13 封装收口批(代码架构审查 E1–E5/O1–O5/P3 修复——接口正式化候选项的切片侧预收口)
**触发**:/architecture-review 改编批——以 architecture.md + ADR-0001~0005 + code-conventions 为基线做代码组织/封装专项审查(报告:`代码架构评审(已退役,git 历史可查)`,Verdict: CONCERNS),用户拍板 P1+P2+P3 全修(P2 中涉接口漂移两项另出设计稿待审)。
**触发**:/architecture-review 改编批——以 architecture.md + code-conventions 为基线做代码组织/封装专项审查(报告:`代码架构评审(已退役,git 历史可查)`,Verdict: CONCERNS),用户拍板 P1+P2+P3 全修(P2 中涉接口漂移两项另出设计稿待审)。
**核心封装修复(P1)**:
@@ -318,7 +318,7 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/a
**组织修复(P1/P2/P3)**:
- **O1/O2 调试模式抽离**:main.gd 调试分支(单场/连续两层/HP 携带/共享 B4)拆 `presentation/debug_session.gd`——调试语义单一实现点(O2 双实现漂移收口);组合根保留接线(battle_created 先于 begin_battle 发出,ADR-0001 接线唯一归组合根 + 缺陷①时序义务)与终局 UI 决策。ui_probe 抓获初版时序缺陷(battle_ready 才接手 b1)——即缺陷①同款,battle_created 接手修复。
- **O1/O2 调试模式抽离**:main.gd 调试分支(单场/连续两层/HP 携带/共享 B4)拆 `presentation/debug_session.gd`——调试语义单一实现点(O2 双实现漂移收口);组合根保留接线(battle_created 先于 begin_battle 发出,接线唯一归组合根 + 缺陷①时序义务)与终局 UI 决策。ui_probe 抓获初版时序缺陷(battle_ready 才接手 b1)——即缺陷①同款,battle_created 接手修复。
- **O3 DamageMath 抽取**:B1 伤害公式族(F2 乘区/充能分量,零状态纯算术)拆 `core/damage_math.gd`(规范 1.2 工具函数挂宿主类);board_generator 同一合法板重复调用两次 measure_inferability 合并为一次(全库最贵求解器)。
- **P3 清债**:头注溯源补齐 ×4(board_data/config_db/rng_service/reward_supply_controller——规范 1.4);B4 grant/grant_clear/stock/use 失败返回统一 `false`→`null`(E6 消费方 `is Dictionary` 判定天然兼容);equivalence_supply 表行 duplicate 防配置源泄漏;load()→preload/类名直引 ×3(main logger/runner、tune_sim autoplay)。
@@ -336,7 +336,7 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/a
- `LevelRunner`:`start_level` 表写删除、生效值进 encounter、`restore_hero_base` 只清百分比(表值不可变后无基线可恢复)、`_base_*` 字段删除(直接读恒定的表);
- main:`_apply_hero_override/_scaled_override` 表写路径废除 → `_debug_hero_override()` 生效值供给 Callable(面板百分比现算经 encounter 入战斗);`_on_tune_apply/_on_tune_simulate` 去复位步骤;`_db_base_*` 字段删除。
- **收益**:双写叠加(6→18→54)与双基线同步整类隐患随表写移除;D2「单一事实源」原则机制化(表值运行期不可变)。
- **登记义务**:registry architecture.yaml 新增 `hero_override_parameter_passing` 条目(ADR-0009 候选;B2.spawn 签名 +2 / B1 encounter +2 = 接口漂移,正式侧 B1/B2 GDD 修订随 ADR-0009 批)。
- **登记义务**:registry architecture.yaml 新增 `hero_override_parameter_passing` 条目(接口漂移候选;B2.spawn 签名 +2 / B1 encounter +2 = 接口漂移,正式侧 B1/B2 GDD 修订随正式化批)。
- **探针语义升级**:ui_tune_probe ⑦「表值残留」→「hero 表运行期不可变」(reintroduce 表写即 FAIL);⑧ 双写叠加回归改为完整关卡路径 + 呈现快照单次生效断言(12/75;旧缺陷形态 24/112 仍被抓获)。ui_probe 的 `_start_single` 语义注记:调试单场恒基线(入口清零滑条——原行为,非缺陷)。
**O4(自动玩家策略四份复制 → 单一实现,合并既有待办 W-3)**:
@@ -412,7 +412,7 @@ Godot_v4.7.2-stable_win64_console.exe --headless --path . --script res://smoke/a
**落地变更**:
- **第一步·奖励侧五行**(reward.tres + reward_table.gd schema + reward_economy.gd):heal_minor [2,6] / knife_t1 [5,11] / heal_pack [6,18] / knife_adv [10,22] / clear_blast [25,55]——power_min/power_max 可选配对字段(缺省定值行向后兼容,armor_type 先例);schema 校验 = 成对/buff 禁止/中点锚;roll 在 roll_board 身份批内**追加取号**(既有取号序零扰动)+ grant_node_active 同路径;快照 power = roll 值,B1/呈现零改动,授予期零随机纪律不变;
- **第二步·敌方攻击侧**(enemy.tres 六行 + enemy_table.gd schema + unit_container.spawn + battle_orchestrator):atk [min,max] = 行值 ±3 provisional(d0 7[4,10] / d1 5[2,8] / d2 9[6,12] / d3 6[3,9] / Boss 9[6,12] / L2 7[4,10]);roll = 遭遇骰同流(encounter 恰一 scope,数量骰先、atk 骰后)spawn 期**整战持久**——每拍抖动否决(数字可读性锚),B2 零随机纪律保持(收 override 即确定值);spawn 签名 +1 参数(接口漂移登记,ADR-0009 同批);
- **第二步·敌方攻击侧**(enemy.tres 六行 + enemy_table.gd schema + unit_container.spawn + battle_orchestrator):atk [min,max] = 行值 ±3 provisional(d0 7[4,10] / d1 5[2,8] / d2 9[6,12] / d3 6[3,9] / Boss 9[6,12] / L2 7[4,10]);roll = 遭遇骰同流(encounter 恰一 scope,数量骰先、atk 骰后)spawn 期**整战持久**——每拍抖动否决(数字可读性锚),B2 零随机纪律保持(收 override 即确定值);spawn 签名 +1 参数(接口漂移登记,随正式化批);
- smoke_all 新增 `_smoke_power_interval`(4 断言:五行中点锚/roll 域内含清图槽/定值行零外溢/节点路径域内)。
**实测(N=30,种子 4200–4229)**:
+4 -4
View File
@@ -28,7 +28,7 @@
# pick 入口候选走同一 _enter_node(entry),呈现零 RNG 消耗;关卡切换(continue_to_next_level)后
# 新 LevelRunner 实例重新走 defer 流程;abandon 在入口停点天然非战斗期(current_battle 为空)
# ——受理语义与选路停点一致。
# 纪律:ADR-0001 S6——连 runner 信号一律 _forward_* 方法 Callable(禁 lambda 捕获 self 成环);
# 纪律:S6——连 runner 信号一律 _forward_* 方法 Callable(禁 lambda 捕获 self 成环);
# Core 层禁 UI 引用;数值零字面量——level_clear_hp_bonus / keystone_per_level 只读 db.adventure,
# 基础上限只读 db.hero。
# 断点续玩:save_manager 经 set_save_manager 注入(缺省 null = 不写断点——模拟/
@@ -42,7 +42,7 @@ signal level_started(level_index: int, display_name: String) # 每关开始(
signal curio_choice_presented(payload: Dictionary) # 专长三选一停点(非末关通关恰一次;迭代 20 T5 换代正名——旧「提升三选一」退役,通道白名单后候选恒专长+回血在载荷)——{level_index, candidates, heal_gained, hp_before, hp_after, keystone_gained, keystone_total, gp, aux_cleared}
signal curio_resolved(result: Dictionary) # 三选一兑付完成(pick_curio/替换受理后恰一次)——{picked, value, hp_before, hp_after, level_index}
signal adventure_finished(summary: Dictionary) # 冒险结算(completed/failed/abandoned)——summary 五件事:打穿没有/通关几关/止步第几关/钥石合计/主种子(+additive keystone_drops 迭代 10)
# ---- 转发族(签名与 LevelRunner 同款——呈现层对接透明;ADR-0001 S6 经 _forward_* 方法)----
# ---- 转发族(签名与 LevelRunner 同款——呈现层对接透明;S6 经 _forward_* 方法)----
signal node_entered(node: Dictionary, info: Dictionary)
signal choices_presented(candidates: Array)
signal step_row(row: Dictionary)
@@ -513,7 +513,7 @@ func pool_stock(kind: String) -> int:
return n
# 商店购买消费 handler(LevelRunner.buy_pool_item 经 Callable 调用——ADR-0001 S6 方法引用):
# 商店购买消费 handler(LevelRunner.buy_pool_item 经 Callable 调用——S6 方法引用):
# 消费在架令牌本体(kind+tier 精确——货架卡即令牌,TP0 令牌级货架)→ _apply_curio_pick 同口
# 写加算区+账本+摘牌(与奖励三选一真单点——买一件=奖励面少一件的库存语义由同库成立)。
# 未知 kind 拒绝(货架词表封闭的前置防御)。
@@ -913,7 +913,7 @@ func _reset_tree_limited_counters() -> void:
func _start_current_level() -> bool:
_runner = LevelRunner.new(db, rng)
_reset_tree_limited_counters() # 树限次计数按关重置(V10 生命周期四态闭合——断言面直呼本口)
# core↔core 接线只许方法 Callable(ADR-0001 S6——lambda 捕获 self 会延长 RefCounted 生命周期乃至成环)
# core↔core 接线只许方法 Callable(S6——lambda 捕获 self 会延长 RefCounted 生命周期乃至成环)
_runner.node_entered.connect(_forward_node_entered)
_runner.choices_presented.connect(_forward_choices_presented)
_runner.step_row.connect(_forward_step_row)
+3 -3
View File
@@ -18,7 +18,7 @@
# (保授予段事件序),战斗段「主角先手→逐敌还手」后补提交统一结账;主角死于敌方还手 → 暂存单
# 整体不兑,逐单留「未生效(主角已倒下)」行(forfeit=hero_down);
# 死亡事件 = 单位容器 unit_died(单位自行宣布)→ 控制器作废该敌未结单据〔死亡即不动手〕/ 主角死终止兑付。
# 切片登记:① 事件总线载体 = 直连信号(实现期 ADR 项,provisional)② Waiting 相位无刷新通道
# 切片登记:① 事件总线载体 = 直连信号(已定)② Waiting 相位无刷新通道
# (仅 Active 挖掘期受理)③ 效果行协议 = 授予段逐 grant 行 + 增益/减益段续存实例组合行。
# 实现 GDD:design/gdd/systems/战斗循环/战斗结算.md(registry 追溯锚)
class_name BattleOrchestrator
@@ -303,7 +303,7 @@ func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void:
minesweeper.flag_judged.connect(_on_flag_judged)
minesweeper.round_end_board.connect(_on_round_end)
action_economy.round_end_stopped.connect(_on_round_end)
# 结算五段接线(迭代 27 T2——段持宿主引用;信号连接纪律不涉段〔段零信号连接,ADR-0001 同构〕)
# 结算五段接线(迭代 27 T2——段持宿主引用;信号连接纪律不涉段〔段零信号连接〕)
_grant_seg = GrantSegment.new(self)
_aura_seg = AuraSegment.new(self)
_combat_seg = CombatSegment.new(self)
@@ -965,7 +965,7 @@ func _grant_clear_identity(snap: Dictionary, ri: int, suffix: String) -> bool:
# 每实例:保底判定(连续执行普攻 ≥ M → 必出特殊技、特殊技内按权重、不受冷却限制)→ 排除冷却中技能
# (中签率 = 权重 ÷ 可摇权重合计——份额归一)→ 按行序逐敌从统一流顺序取号摇定本拍动作。
# 随机消费只在换算层(本方法 + SkillLottery);单位容器收确定值(零随机纪律——armor_roll 先例同构)。
# 并流批(ADR-0007 裁丙 2026-09-27):behavior_roll 子流派生向量(spawn_index×STRIDE+序)退役——
# 并流批(2026-09-27 统一流裁决):behavior_roll 子流派生向量(spawn_index×STRIDE+序)退役——
# 「单敌轨迹独立复放」前提随之移除(位置交错,单点定位由事件日志承载)。摇定后、兑现前死亡 → 本拍技能作废。
func _roll_round_actions() -> void:
var pity_m: int = int(db.skill.pity_threshold)
+1 -1
View File
@@ -475,7 +475,7 @@ func _start_battle(node: Dictionary) -> bool:
_settlement.treasure_inventory = treasure_inventory # 迭代 7 T3——库存注入(授予路由+use_treasure 编排消费面)
if _settlement != null:
_settlement.set_treasure_unlocked(_treasure_unlocked) # 迭代 7 T5——解锁门控下传(装板摇号前)
# core↔core 接线只许方法 Callable(ADR-0001 静态规则 S6——lambda 捕获 self 会延长
# core↔core 接线只许方法 Callable(静态规则 S6——lambda 捕获 self 会延长
# RefCounted 生命周期乃至成环:settlement 的信号持捕获 runner 的 lambda,runner 又持 settlement)
_settlement.step_row.connect(_forward_step_row)
_settlement.round_started.connect(_forward_round_started)
+1 -1
View File
@@ -6,7 +6,7 @@
# 安全格与雷格一视同仁(同一类型池、同一权重分布——雷安同池);封锁格不入摇号清单。
# 极性不在资源内:「动作 × 格型」矩阵的字典定义归 GDD、路由执行归 战斗结算 授予段
# (本类只提供 polarity_row 的(类型, 极性)→ 字典行查询面)。
# 切片登记:取号约定 = randi_range(0, W-1)(实现期 ADR 事实,切片内恒定);
# 切片登记:取号约定 = randi_range(0, W-1)(切片内恒定);
# 区间行 power roll 取号语义:快照 power = roll 值,授予期零随机不变。
# 实现 GDD:design/gdd/systems/战斗循环/地图战斗资源.md(registry 追溯锚)
class_name RewardEconomy
+3 -3
View File
@@ -1,11 +1,11 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# Validation Question: 玩家能否无指导在一场完整战斗中经历「开战→挖掘规划→轮末结算逐行兑现→胜/负」并逐行归因(P2)
# Date: 2026-09-10
# RngService autoload(数据配置)——统一随机流单点(Rule 5;ADR-0007 裁丙:七流并一+全事件日志)。
# RngService autoload(数据配置)——统一随机流单点(Rule 5;2026-09-27 七流并一+全事件日志)。
# 玩法代码禁止 randomize()/自建 RandomNumberGenerator。
# 实现 GDD:design/gdd/systems/表现与支撑/数据配置.md(系统 ID D2·数据配置——registry 追溯锚,命名规范见 CLAUDE.md)
# 统一流口径:唯一主种子 + 唯一派生(单盐)+ 唯一全局取数计数器;open_stream 参数降格为「用途标签」——
# 不参与派生,只进事件日志(并流前七条流名全部保留为合法标签)。号位语义(ADR-0007 后果,用户裁决承接):
# 不参与派生,只进事件日志(并流前七条流名全部保留为合法标签)。号位语义(并流后果,用户裁决承接):
# 全局 scope 只回答「全局第 N 次取数」,不再回答「第 N 次某类事件」——路线依赖为已知代价,单点定位能力由事件日志承载。
# 派生公式(R3 + 统一流):derive = mix64(SINGLE_SALT XOR wrap64(master + scope×GOLDEN))——
# splitmix64 finalizer 变体终末混淆,见 _mix64 注记;scope 0-3 与旧 board_gen 向量逐位连续
@@ -72,7 +72,7 @@ func set_master_seed(seed_val: int) -> void:
# 切片登记:冒险开始重播种入口(正式侧调用权归 冒险结构;切片主菜单 = 冒险起点)——
# 并流批(ADR-0007 裁丙):重播种同时开本次冒险的事件日志会话。
# 并流批(2026-09-27 统一流裁决):重播种同时开本次冒险的事件日志会话。
func new_adventure(seed_val: int) -> void:
_counter = 0
set_master_seed(seed_val)
+1 -1
View File
@@ -113,7 +113,7 @@ func spawn(level_index: int, node_depth: int, hero_hp: int, unit_count_overrides
"atk": maxi(0, int(round(float(eff_row_atk) * atk_mult))),
"pool": pool_snap, # 实例池(模板快照 + 冷却状态——独立摇号互不干涉)
"pending_skill": "", # 本拍摇定动作(开轮摇号写入;兑现前死亡 = 作废不 commit)
"roll_seq": 0, # 单敌摇号拍序(诊断标签——并流后不参与派生,ADR-0007 裁丙 2026-09-27)
"roll_seq": 0, # 单敌摇号拍序(诊断标签——并流后不参与派生,2026-09-27 统一流裁决)
"basic_streak": 0, # 保底计数:连续执行普攻的拍数(执行上报驱动)
"armor_type": String(row.get("armor_type", "light")), # 护甲类型快照(克制矩阵消费面——战斗结算·战斗段;2026-09-15 命名统一批:light/ward/heavy)
"armor_class": int(row.get("armor_class", 0)), # 护甲等级快照(掷点判定阈值基数——战斗结算·战斗段;2026-09-16 护甲等级掷点批)
+1 -1
View File
@@ -34,7 +34,7 @@ extends Resource
@export var crit_roll: int = 20 # [1,roll_faces] knob——nat 最大面 = 暴击触发掷点(恒全额)
@export var crit_multiplier: int = 200 # [100,999] percent knob——暴击倍率(200 = ×2,只乘该次基础攻击分量)
@export var damage_floor: int = 1 # [1,999] knob——任何伤害落地全局下限·全来源("被减伤归零 v=0"行语义随批退役)
@export var armor_roll_stream: String = "armor_roll" # 掷点用途标签(rng_service PURPOSE_TAGS 成员——并流后不参与派生,仅作事件日志用途标记;ADR-0007 裁丙 2026-09-27)
@export var armor_roll_stream: String = "armor_roll" # 掷点用途标签(rng_service PURPOSE_TAGS 成员——并流后不参与派生,仅作事件日志用途标记;2026-09-27 统一流裁决)
const ARMOR_KEYS := ["light", "ward", "heavy"]
const ATTACK_TYPE_KEYS := ["normal", "pierce", "magic"]
+1 -1
View File
@@ -1,7 +1,7 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# 营地/商店投影控制器(规范 1.1 单一职责拆件):
# 营地面开合/快照投影/锻造·同调·天赋树·Fork 购买与切换 + 商店房购买/离开(pool 与 product 双面)。
# 装配纪律(ADR-0001,仿 treasure_interact_controller 先例):信号连接不在此发生——campbtn/
# 装配纪律(仿 treasure_interact_controller 先例):信号连接不在此发生——campbtn/
# camp_overlay 四信号/shop_overlay 两信号由组合根接至本类 on_* 入口;模态栈/呈现刷新/续玩按钮
# 刷新经组合根回调注入;runner 随局更替——现值回调注入;写调用唯一经 MetaProgression 购买原语
# 与 LevelRunner.buy_*(core 侧单口,本类零直写——拒绝可见 pattern 1 兜底 toast 保留原地)。
@@ -2,7 +2,7 @@
# 三选一交互控制器(规范 1.1 单一职责拆件):
# 三选一停点编排(presented→pick→confirm/refresh→resolved→continue)+ 同调位替换子态
#(presented→chosen)+ TP0 令牌池卡片文案装配("kind|tier|feat_id" 复合键)+ 工坊显示名投影。
# 装配纪律(ADR-0001,仿 treasure_interact_controller 先例):信号连接不在此发生——curio_overlay
# 装配纪律(仿 treasure_interact_controller 先例):信号连接不在此发生——curio_overlay
# 四信号与 adventure 两信号由组合根接至本类 on_* 入口;模态栈/演播后排窗/呈现刷新/终局面/
# 推进失败 fatal 经组合根回调注入;adventure/runner 随局更替——现值回调注入;兑付写调用唯一
# 经 adventure.pick_curio/apply_node_curio(core 侧单口,本类零直写;无替换子交互——装配不可变契约 1,冒险中零更换途径)。
+2 -2
View File
@@ -4,13 +4,13 @@
# 职责边界:层序/携带 HP + 战斗结算 生命周期编排(创建 / begin_battle)。
# 层间延续 = HP 关内延续(库存与共享 地图战斗资源 已下线)。
# 授权边界:与 tune_sim_controller 同款——控制器承接模式编排,
# 组合根仍持有全部信号接线(battle_created 先于 begin_battle 发出,ADR-0001 接线唯一归组合根)
# 组合根仍持有全部信号接线(battle_created 先于 begin_battle 发出,接线唯一归组合根)
# 与终局 UI 决策;玩家意图写调用(settle_batch / 刷新)不经本类。
# 加成生效值经注入 Callable 供给(组合根从面板百分比现算)→ encounter
# 显式传入战斗——零表写。
extends RefCounted
signal battle_created(settlement, level: int, carry_hp: int) # begin_battle 前——组合根完成信号接线(ADR-0001)
signal battle_created(settlement, level: int, carry_hp: int) # begin_battle 前——组合根完成信号接线
signal battle_ready(settlement, level: int, carry_hp: int) # begin_battle 完成后——组合根 rebuild 棋盘 + 刷新呈现
var db
+7 -7
View File
@@ -27,7 +27,7 @@
# 排除式开态查询+三例外(浮窗开态不计入锁);battle 收尾反馈与结算视觉 setter 走 hud_presenter 单通道
# (时序敏感演出触发留本类并注释);settlement 相位读取经 presentation_snapshot 成文面、变异表读取直读
# 本根 db(settlement.db 即同一实例)——禁 settlement.action_economy / settlement.db 链式穿透。
# ADR-0001 纪律:呈现层永不直接订阅 排雷玩法/行动经济——只订 战斗结算/runner 转发信号;相位读取仅用于
# 接线纪律:呈现层永不直接订阅 排雷玩法/行动经济——只订 战斗结算/runner 转发信号;相位读取仅用于
# 驱动视图状态;信号连接只在组合根(row_pacer/treasure_interact_controller 零连接,只收注入)。
extends Control
@@ -317,7 +317,7 @@ func _build_ui() -> void:
curio_overlay = CurioPickOverlay.new()
add_child(curio_overlay)
# 提升三选一与替换子交互(T4/D4 拆件批——迁 curio_interact_controller.gd;本类只接线与回调注入,
# ADR-0001——模态栈/演播后排窗/呈现刷新/fatal 经回调注入,adventure/runner 现值回调)
# 模态栈/演播后排窗/呈现刷新/fatal 经回调注入,adventure/runner 现值回调)
_bonus = CurioInteractController.new(CurioFlowContext.new(db, func() -> Variant: return meta, curio_overlay, _end_overlay, board_view,
board_zone.toast, func() -> Variant: return save_manager, func() -> Variant: return run_scope.adventure,
func() -> Variant: return run_scope.runner, func() -> Variant: return run_scope.is_adventure,
@@ -556,7 +556,7 @@ func _resume_from_menu() -> void:
return
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根,ADR-0001;断点注入同口)
# 冒险编排构建+接线(开新局/续玩共用——信号连接只在组合根;断点注入同口)
func _wire_adventure() -> void:
run_scope.adventure = AdventureRunner.new(db, get_node(AUTOLOAD_PATH_RNG))
run_scope.adventure.step_row.connect(_on_step_row)
@@ -595,7 +595,7 @@ static func build_adventure_params(save_manager_ref, meta_ref, extra: Dictionary
# 冒险模式(三关连探——AdventureRunner 编排;转发信号签名与 runner 一致,接线照原样对接;
# 信号连接只在组合根——ADR-0001)
# 信号连接只在组合根)
func _start_adventure() -> void:
_close_modal(debug_overlay) # 开冒险路径显式关浮窗(迭代 18 卡⑦ T2 防护——DS_DEBUG 默认开态下开局不带窗;对局中经角标再开)
_begin_session(true)
@@ -741,7 +741,7 @@ func _start_debug_levels() -> void:
func _on_debug_battle_created(settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void:
# begin_battle 前接手 + 接线(ADR-0001:signal.connect 唯一归组合根)。settlement 必须先于 begin_battle
# begin_battle 前接手 + 接线(signal.connect 唯一归组合根)。settlement 必须先于 begin_battle
# 就位——begin 期间发出的 board_changed 要用新板重建棋盘并触发一次性提示(缺陷①同款时序义务)
run_scope.settlement = settlement_ref
_wire_battle(settlement_ref)
@@ -1448,9 +1448,9 @@ func _seed_value() -> int:
# ②首局固定 42(P5 甲——存档现役布尔 is_first_adventure_done:新档显式 false=教学局恒 42〔教学
# 重放模板 0 即在此种子下标定〕;置位 true=教学局已收束的非首局走 ③ 随机);
# ③非首局空/非法框=引擎全局熵 randi()(Godot 4 启动自播种子,headless 同;不走 rng_service
# 封闭流、禁 randomize()/自建 RNG——组合根建种子属 ADR-0007 豁免面,不进玩法 RNG 消费)
# 封闭流、禁 randomize()/自建 RNG——组合根建种子属引擎熵豁免面,不进玩法 RNG 消费)
if _seed_edit.text.is_valid_int():
return int(_seed_edit.text)
if save_manager.is_first_adventure_done():
return randi() # ADR-0007-exempt(非首局空框引擎熵——组合根建种子不进玩法 RNG 消费,static_scan S1/S2 标记豁免)
return randi() # rng-seed-exempt(非首局空框引擎熵——组合根建种子不进玩法 RNG 消费,static_scan S1/S2 标记豁免)
return 42
+1 -1
View File
@@ -2,7 +2,7 @@ class_name ModalFlow
extends RefCounted
# 模态编排纯逻辑类(迭代 27 T4——审计 P1-5/P2-7:组合根可测化抽取 + 模态互斥域内聚)。
# 依赖仅 ModalStack + 查询 Callable(审计处方原话)——零节点构建、零信号连接、零核心触碰
#(ADR-0001 同构:连接归组合根,本类只收注入)。可直接 new() 单测(V6)。
#(同构:连接归组合根,本类只收注入)。可直接 new() 单测(V6)。
# 职责三件:
# ① 登记与开合编排(遮挡记账单口 / T17 演播后排窗挂起——原 main._open_modal 系逻辑随迁)
# ② 棋盘输入锁谓词(互斥域随层登记——原 main._input_locked 排除式拼装消亡)
+1 -1
View File
@@ -6,7 +6,7 @@
# level_finished/step_row);本组件负责订阅、缓冲与写文件——核心零日志感知(零 UI 依赖不变)。
# 文件 = user://logs/playtest_<seed>_<时间戳>.jsonl(每行一次结算/终局/节点的全量状态 JSON)。
# ux 行族(呈现层观测,不改 core):ux_round_input_ratio(原始输入动作数∶AP 消耗)、
# ux_round_exit{path_tag}(快照 round_facts.path——呈现层只订 战斗结算 的 ADR 纪律下唯一合法来源)、
# ux_round_exit{path_tag}(快照 round_facts.path——呈现层只订 战斗结算 的接线纪律下唯一合法来源)、
# ux_refresh_attempt / ux_reject / ux_hint_shown(组合根显式上报;无 ux_window_choice——道具窗口已下线)。
# 诊断转储 = 全量核心状态 + 最近结算/操作环形缓冲 → user://logs/diag_<时间戳>.json(卡死时点按钮)。
class_name PlaytestLogger
+1 -1
View File
@@ -4,7 +4,7 @@
# 硬契约:核心层零 await 不破——本队列只做信号的"后置消费",结算顺序/结果/时序逻辑零改动(§3 契约 1);
# 减动效开=延迟归零走同帧直落快路(行呈现不跳过——§3 契约 5);模态开启前强制排空(明细回看/停点
# 覆盖层所见明细带恒完整——排空入口在组合根 _open_modal)。
# 装配纪律:视图句柄与呈现刷新回调由组合根注入(ADR-0001——本类零信号连接,仅做信号后置消费)。
# 装配纪律:视图句柄与呈现刷新回调由组合根注入(本类零信号连接,仅做信号后置消费)。
extends Node
const PACE_SEGMENT_GAP := 0.3 # 段间阶梯延迟(代拍板:白名单 0.2–0.4s 内取值,追认清单呈报)
+1 -1
View File
@@ -5,7 +5,7 @@ extends Node
# 会话更替/终局整节点 queue_free()——旧手工复位清单(原 main._reset_run_scope 三项 +
# _on_battle_end_continue 置空四件)随节点释放机制消亡,此后新增跨局字段零新增泄漏点
#(泄漏=低频难复现脏状态的手工契约病灶,审计 P0-2)。
# 纪律:本节点零信号连接、零视图构建、零核心写调用(ADR-0001——信号连接只在组合根):
# 纪律:本节点零信号连接、零视图构建、零核心写调用(信号连接只在组合根):
# 纯状态承载,组合根经 run_scope.X 读写。
var adventure = null # 冒险结构编排器(调试两层恒 null)
var runner = null # 关卡推进器(冒险每关重取 adventure.runner();调试两层恒 null)
+1 -1
View File
@@ -2,7 +2,7 @@ class_name AdventureScreen
extends Control
# 冒险屏壳(迭代 27 T1 场景拆分——审计 P0-1 第一步;内含关卡地图屏与战斗屏两容器)。
# 两容器视图原样构建(build_battle_ui 归 ui_assembler 纪律不变、LevelMapScreen 类视图继续
# 代码构建、零 .tscn 化改造——契约 2);战斗信号接线归组合根 main.gd(ADR-0001——信号连接
# 代码构建、零 .tscn 化改造——契约 2);战斗信号接线归组合根 main.gd(信号连接
# 只在组合根)。树序语义:本屏壳挂 main 首子位(全模态之下)——屏内 level_screen 与
# battle_root 无同时可见态(屏级互斥+模态栈遮挡),层内先后序零视觉差;
# 模态登记序不变(level_screen 实例仍按节点层与三选一层之间登记)。
+1 -1
View File
@@ -2,7 +2,7 @@ class_name CampScreen
extends Control
# 营地屏壳(迭代 27 T1 场景拆分——审计 P0-1 第一步)。
# 营地覆盖层视图原样构建(CampOverlay 类视图继续代码构建、零 .tscn 化改造——契约 2);
# 购买/开合接线归组合根经 CampShopPresenter(ADR-0001——信号连接只在组合根)。
# 购买/开合接线归组合根经 CampShopPresenter(信号连接只在组合根)。
# 可独立实例化(F6/headless 挂载)——V2 探针断言载体。
var camp_overlay: CampOverlay # 营地覆盖层(原 build_overlays 营地段迁入——main 组合根句柄指向本屏成员)
+1 -1
View File
@@ -2,7 +2,7 @@ class_name MenuScreen
extends Control
# 开始菜单屏壳(迭代 27 T1 场景拆分——审计 P0-1「场景作为组合单元/生命周期单元」第一步)。
# 视图代码原样构建(节点构建归 ui_assembler.gd 纪律不变——本屏壳只持有与暴露句柄);
# 按钮接线归组合根 main.gd(ADR-0001——信号连接只在组合根)。
# 按钮接线归组合根 main.gd(信号连接只在组合根)。
# 可独立实例化(F6/headless 挂载)——V2「各新屏场景可独立实例化」探针断言载体。
# main 组合根保留 _start_overlay 等句柄指向本屏成员——可见性开关与探针挂载假设零迁移。
@@ -4,7 +4,7 @@
# 数据源 = runner 级库存只读面(query_inventory/query_overlays)+ 表行投影(display_name/target/effect_kinds);
# 写调用唯一经 战斗结算.use_treasure(core 侧四步编排——拒绝零消耗 toast 可辨认)。
# 装配纪律:settlement/runner 随关卡逐关更替——经组合根现值回调注入(仿 identity_resolver 只读回调
# 先例);呈现句柄(信息面板/toast/棋盘叠加层)由组合根注入;ADR-0001——信号连接不在此发生,
# 先例);呈现句柄(信息面板/toast/棋盘叠加层)由组合根注入;信号连接不在此发生,
# info_panel.treasure_slot_clicked 由组合根接至 on_slot_clicked。
# 无目标使用显式化:AP 类(target=none)无坐标可给——
# 调用面一律 attempt_use(handle)(cell 缺省=null=显式「无目标」),core 契约的
+1 -1
View File
@@ -2,7 +2,7 @@
# 实现 GDD:design/ux/battle.md(四区装配器——组合根的 UI 构建拆分载体)。
# Date: 2026-09-12(code-review 修复批:main.gd 回涨 761 行触规范 1.1 审视线——构建拆出)
# 高内聚边界(规范 1.1/1.3):视图构建装配器——只做 new / add_child / 布局,
# 零信号连接、零核心写调用;返回句柄供组合根接线(ADR-0001:接线拓扑唯一归组合根)。
# 零信号连接、零核心写调用;返回句柄供组合根接线(接线拓扑唯一归组合根)。
# 静态无状态。z 序契约:调用方必须按 build 返回序 addChild(登记序 = 模态遮挡序——缺陷⑤纪律)。
extends RefCounted
+1 -1
View File
@@ -181,7 +181,7 @@ func is_refresh_ready() -> bool:
return not _btn_refresh.disabled
# 探针接缝(ADR-0004"合成输入走真实翻译出口"口径):刷新按钮点击 → 确认 chips 全链路
# 探针接缝(合成输入走真实翻译出口口径):刷新按钮点击 → 确认 chips 全链路
func press_refresh_for_probe() -> void:
_on_refresh_pressed()
+2 -2
View File
@@ -4,7 +4,7 @@
# 底部结算明细带(布局决策 D1 常驻双舞台分屏))。
# Date: 2026-09-12(setter 面契约:set_enemies/clear_enemies/on_step_row_fx/gray_all_enemies
# 签名稳定——探针与组合根零改造面)
# 结构(ADR-0006 / board-node2d-migration-plan §3——B 区战斗舞台归 Node2D):根壳 Control(类名/
# 结构(Node2D 迁移批——B 区战斗舞台归 Node2D):根壳 Control(类名/
# 尺寸 252px/树内位置不变),内部两半区——「Node2D 舞台半区 = SubViewportContainer + SubViewport +
# StageWorld(站桩本体 StandeeBody 世界精灵)」+「Control 文本半区 = round_label / stage_center /
# log_view 三件」。SubViewport 逻辑分辨率 = 壳层像素 1:1(stretch,禁任何缩放系数——C2/C5);
@@ -60,7 +60,7 @@ func _init(db_ref) -> void:
beams.resized.connect(beams.queue_redraw)
add_child(beams)
# ── Node2D 舞台半区(ADR-0006 Phase B 同构;stretch 1:1 无缩放系数——C2/C5)──
# ── Node2D 舞台半区(战斗舞台迁移批 Phase B 同构;stretch 1:1 无缩放系数——C2/C5)──
_svp_container = SubViewportContainer.new()
_svp_container.stretch = true # 容器尺寸 = 视口逻辑分辨率,恒 1:1
_svp_container.mouse_filter = Control.MOUSE_FILTER_IGNORE # 世界零输入(tooltip 归壳层伴随件)
+1 -1
View File
@@ -1,6 +1,6 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# CellUnit——BoardView SubViewport 世界内逐格渲染件(Node2D)。
# 固定叠层序(ADR-0006 Decision 4):砖面底 < 变异纹带 < 数字/徽章 < 旗 < 焦点高亮——全部程序化
# 固定叠层序(Node2D 迁移批 Decision 4):砖面底 < 变异纹带 < 数字/徽章 < 旗 < 焦点高亮——全部程序化
# _draw 占位视觉;每层留 texture 槽位(art-bible §8.2 格面 32×32 暂定档——终稿 1:1 换入,
# 纹理加载未实现)。无 class_name(类名缓存面纪律——BoardView 经 preload 使用)。
# 字体:font 槽位缺省 = ThemeDB.fallback_font(与旧 Button 缺省主题字体同源);注入挂点归
+4 -4
View File
@@ -3,11 +3,11 @@
# BFS 路径预览/奖励徽章/结算期去饱和锁输入)。
# Date: 2026-09-12(battle.md 战斗屏改造批;基础 = 2026-09-11 HUD框架-lite 版)
# 棋盘渲染本体 = Control 壳 + SubViewportContainer + SubViewport + BoardWorld(Node2D) +
# CellUnit(Node2D)(ADR-0006 / docs/architecture/board-node2d-migration-plan.md §2)。对外契约:
# CellUnit(Node2D)(Node2D 迁移批)。对外契约:
# 类名/extends/三信号/click_cell/_cells 键面(Vector2i→格单元,值 Button→CellUnit)/
# board()/set_desaturated()/set_identity_resolver()/set_variant_mask_resolver()/set_cell_area()/
# rebuild()/refresh()/set_dig_glow_enabled()——探针与组合根零改造。
# 命中 = 壳层 _gui_input + 板级公式单点换算(ADR-0006 Decision 3,_cell_at 为唯一公式函数;
# 命中 = 壳层 _gui_input + 板级公式单点换算(Node2D 迁移批 Decision 3,_cell_at 为唯一公式函数;
# SubViewportContainer 逻辑分辨率恒等于板像素尺寸(stretch 1:1,无缩放比),换算只需减居中偏移)。
# 程序化占位视觉:数字三档/旗/徽章/危险红/变异遮蔽 "?"/呼吸微光/悬停/路径预览/R₀ 豁免;
# CellUnit 叠层 texture 槽位留好(纹理资产接 CellUnit)。只读属性 cell_size 为格尺寸契约出口。
@@ -480,7 +480,7 @@ func click_cell(cell: Vector2i, button: int) -> void:
_on_cell_input(cell, ev)
# 板级公式单点(ADR-0006 Decision 3):格坐标 = floor(板内局部坐标 / 格步长)
# 板级公式单点(Node2D 迁移批 Decision 3):格坐标 = floor(板内局部坐标 / 格步长)
#(格步长 = 格边长 + 间距;板外/负域返回 (-9,-9)。旧逐格 Button 命中被此函数取代;
# 2px 格间隙落入左/上邻格——旧间隙为零命中死区,等价性偏差已登记迁移方案汇报面)
func _cell_at(shell_pos: Vector2) -> Vector2i:
@@ -513,7 +513,7 @@ func _update_world_size() -> void:
_viewport.size = px
# 真实输入路径(ADR-0006 Decision 3):壳层 _gui_input → 板级公式换算 → 复用既有 hover/点选/chord 出口
# 真实输入路径(Node2D 迁移批 Decision 3):壳层 _gui_input → 板级公式换算 → 复用既有 hover/点选/chord 出口
func _gui_input(ev: InputEvent) -> void:
if _minesweeper == null:
return
+1 -1
View File
@@ -2,7 +2,7 @@
# BoardWorld——棋盘 Node2D 世界根(SubViewport 内
# CellUnit 容器)。职责单点:世界级材质挂点(set_desaturated 去饱和挂此处,CellUnit
# use_parent_material 链下随世界灰化)+ 主题/字体显式注入槽位(SubViewport 不自动继承主场景
# Control 主题——ADR-0006 Negative 项;两舞台共用骨架,ADR-0006 Decision 5)。
# Control 主题(Node2D 迁移批 Negative 项);两舞台共用骨架(Decision 5)。
# 无 class_name(类名缓存面纪律——BoardView 经 preload 使用)。
# 板块伪立体绘制(正俯视纸雕风):
# 顶面方格不变(数字可读性硬指标不受伤),厚度全部画在网格矩形外的正面/右侧悬崖带:
+1 -1
View File
@@ -44,7 +44,7 @@ func _init() -> void:
board_area.add_child(toast)
# 角标对(迭代 18 卡⑦ P2 甲——调试+状态两枚右下角常驻,HBox 并排锚角距 16px):
# 17卡③状态角标同形制:紧凑钮豁免宽度基准+字号降档。可见性/置灰归组合根 _sync_status_entry
#(DS_DEBUG 门控/其他模态开着=置灰不可点——排除式开态查询);信号连接归组合根(ADR-0001)。
#(DS_DEBUG 门控/其他模态开着=置灰不可点——排除式开态查询);信号连接归组合根。
# preset 在子件全部入列后调用——MINSIZE 锚按当时最小尺寸计偏移(空容器调用=零尺寸锚外溢屏边)
var corner := HBoxContainer.new()
corner.add_theme_constant_override("separation", 8)
+1 -1
View File
@@ -8,7 +8,7 @@
#(apply_requested / simulate_requested / debug_levels_requested / closed);
# 当局数据经 update_run_data setter 喂入(只读投影零回读);模拟进度与报告经 setter 注入——
# 零核心写、不拼报告文案(装配归 HudPresenter)。零动效(零 tween/AnimationPlayer)。
# 探针接缝(ADR-0004"合成输入走真实翻译出口"口径):press_apply_for_probe 等三键 = 按钮真实信号路径。
# 探针接缝(合成输入走真实翻译出口口径):press_apply_for_probe 等三键 = 按钮真实信号路径。
class_name DebugOverlay
extends Control
+2 -2
View File
@@ -112,7 +112,7 @@ func _init() -> void:
gp_row.add_child(_gp_value)
# 状态面板入口角标(迭代 17 卡③ P1 丁——顶栏常驻;debug 角标同形制:紧凑钮豁免宽度基准+字号降档。
# 置灰守卫归组合根 _sync_status_entry(其他模态开着=不可点;本屏自身的登记开态不计——has_open_excluding);
# 信号连接归组合根(ADR-0001——视图零连接))
# 信号连接归组合根(视图零连接))
status_badge = UiKit.button("状态", 0.0)
status_badge.add_theme_font_size_override("font_size", UiKit.FS_HINT)
status_badge.tooltip_text = "查看钥石与永久强化进度(只读)"
@@ -120,7 +120,7 @@ func _init() -> void:
top.add_child(status_badge)
# 调试浮窗入口角标(迭代 18 卡⑦ P2 甲——顶栏状态角标右侧;17卡③同形制:紧凑钮豁免宽度基准+
# 字号降档。可见性/置灰归组合根 _sync_status_entry(DS_DEBUG 门控/其他模态开着=置灰——排除式
# 开态查询,本屏自身开态不计);信号连接归组合根(ADR-0001——视图零连接))
# 开态查询,本屏自身开态不计);信号连接归组合根(视图零连接))
debug_badge = UiKit.button("调试", 0.0)
debug_badge.add_theme_font_size_override("font_size", UiKit.FS_HINT)
debug_badge.tooltip_text = "打开调试浮窗(当局数据/种子/数值调整)"
+3 -3
View File
@@ -1,8 +1,8 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# StageWorld——B 区战斗舞台 Node2D
# 世界根(SubViewport 内站桩本体容器)。ADR-0006 分工:Node2D = D 区棋盘 + B 区战斗舞台;
# 世界根(SubViewport 内站桩本体容器)。分工:Node2D = D 区棋盘 + B 区战斗舞台;
# 与 BoardWorld 同构。职责单点:主题/字体显式注入槽位(SubViewport 不自动继承主场景
# Control 主题——ADR-0003 Decision 4;set_world_font 同款挂点,null = ThemeDB.fallback_font 与
# Control 主题(2026-09-12 场景结构裁决);set_world_font 同款挂点,null = ThemeDB.fallback_font 与
# 旧 Label 缺省主题同源)+ 站桩本体装载面。无 class_name(类名缓存面纪律——
# BattleStageView 经 preload 使用)。
# 坐标空间钉死:世界内 = 局部排布坐标(SubViewport 逻辑分辨率 =
@@ -12,5 +12,5 @@ extends Node2D
var world_font: Font = null # 字体注入槽位(null = ThemeDB.fallback_font——BattleStageView.set_world_font 注入)
# C6 headless 可验判据(ADR-0003 Decision 4):注入字体非空 + 中文字形 has_char + 采样文本宽度 > 0。
# C6 headless 可验判据(2026-09-12 场景结构裁决):注入字体非空 + 中文字形 has_char + 采样文本宽度 > 0。
# 实际光栅观感归批末目检清单。
+1 -1
View File
@@ -1,7 +1,7 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# 实现 GDD:design/ux/battle.md(B 区全站桩形态——主角与敌人均为无框立绘+底座,
# 英雄卡/敌人卡卡片式整体退役禁再提)。
# 站桩本体 = Node2D 世界精灵(ADR-0006:B 区战斗舞台归 Node2D)。行为面契约逐项保持:
# 站桩本体 = Node2D 世界精灵(B 区战斗舞台归 Node2D)。行为面契约逐项保持:
# set_data/set_hero/_set_hp/set_idle/set_effects/set_effects_cleared_feedback/set_order/set_pending/
# _play_intent_motion/set_portrait_texture(tex,flip)/mark_dead/is_dead/flash_hit/_revive/
# _update_name_line/_refresh_portrait_glyph(调用点 hud_presenter/main/探针零改造目标——C3)。
+7 -7
View File
@@ -49,7 +49,7 @@ func _initialize() -> void:
print(" error: [%s] %s" % [d.category, d.message])
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(42)
# 统一流黄金向量(数据配置 AC-3——ADR-0007 裁丙 2026-09-27 单盐重登记:单盐沿用并流前 board_gen 盐,
# 统一流黄金向量(数据配置 AC-3——2026-09-27 统一流裁决单盐重登记:单盐沿用并流前 board_gen 盐,
# scope 0-3 与旧 R3 board_gen 向量逐位连续;Python 参考实现逐位交叉验证一致;并流前分盐向量随批作废)
check(rng.derive_at(0) == 8672514112661456564, "统一流向量 m=42 scope=0(=旧 board_gen scope0 连续性锚)")
check(rng.derive_at(1) == 8834291164406037215, "统一流向量 m=42 scope=1")
@@ -68,7 +68,7 @@ func _initialize() -> void:
rng.new_adventure(4242)
var s2 = rng.open_stream("gp_drop")
check(rng.counter() == 1 and s2.seed == rng.derive_at(0), "new_adventure 重置全局计数器")
check(FileAccess.file_exists("user://logs/rng_log_4242.jsonl"), "事件日志会话落盘(ADR-0007 丙案)")
check(FileAccess.file_exists("user://logs/rng_log_4242.jsonl"), "事件日志会话落盘(2026-09-27 统一流裁决)")
if load_ok:
_run_core_smoke(db, rng)
@@ -2011,7 +2011,7 @@ func _smoke_armor_roll() -> void:
for roll in range(1, 21):
ev_sum += DamageMath.roll_discount_percent(roll, 10, _db.settlement.roll_tier_bounds, _db.settlement.roll_tier_discounts)
check(ev_sum == 1575, "AC10 EV 锚:期望系数合计 %d/2000 = 期望减免 21.25%%(nat20 恒全额含内)" % ev_sum)
# ② nat20 暴击(行为面):并流批(ADR-0007 裁丙)后掷点位随全局序漂移——探针改为按行为面扫描
# ② nat20 暴击(行为面):并流批(2026-09-27 统一流裁决)后掷点位随全局序漂移——探针改为按行为面扫描
# 「主角先手首掷 = 20」的种子,不再假设 armor_roll scope0 位
var crit_seed := -1
var crit_rows := {}
@@ -2235,7 +2235,7 @@ func _smoke_board_generator() -> void:
func _mk_stream(stream_name: String, scope: int) -> RandomNumberGenerator:
# 并流批(ADR-0007 裁丙):stream_name 降格为调用点自述标签(不参与派生),保留参数零改调用方
# 并流批(2026-09-27 统一流裁决):stream_name 降格为调用点自述标签(不参与派生),保留参数零改调用方
var rg := RandomNumberGenerator.new()
rg.seed = _rng.derive_at(scope)
return rg
@@ -3358,7 +3358,7 @@ func _polarity_probe_accepts(probe: Dictionary) -> bool:
func _smoke_polarity_routing() -> void:
print("--- 极性路由(挖安全格正向 / 挖雷格负向 / 标中正向 / 标空负向)---")
# 并流批(ADR-0007 裁丙)后战斗随机值面漂移——构造种子改行为面扫描(谓词见 _polarity_probe_accepts)
# 并流批(2026-09-27 统一流裁决)后战斗随机值面漂移——构造种子改行为面扫描(谓词见 _polarity_probe_accepts)
var probe := {}
var polarity_seed := -1
for s in [20260918, 20260919, 20260920, 20260921, 42, 4242, 7, 100, 20260922, 123, 2024, 31337, 555, 1111, 2222, 20260923, 999, 777]:
@@ -4015,7 +4015,7 @@ func _smoke_skill_pool_data() -> void:
# ② 同种子回放逐位复现(D3 大地精——原熊地精双雄,多实例同种)
# ③「单敌轨迹独立复放」随并流批退役(ADR-0007 裁丙 2026-09-27):子流派生向量退役后单敌轨迹无法
# ③「单敌轨迹独立复放」随并流批退役(2026-09-27 统一流裁决):子流派生向量退役后单敌轨迹无法
# 脱离全序重建(位置与其它流取数交错);同种子全战斗逐位复现由 ② 全对拍承载,单点定位归事件日志。
func _smoke_skill_pool_replay_independence() -> void:
var seed_val := -1
@@ -4328,7 +4328,7 @@ func _smoke_level_graph() -> void:
var orphan_errs: Array = lt.validate()
check(_has_err_category(orphan_errs, "structural"), "图校验拒绝:孤儿节点(从入口不可达 / 双入口同体违例)")
# ④ L2 选路推进:min / max 双路径全通(确定性路径轴——零随机流自开)
# 并流批(ADR-0007 裁丙)后战斗随机值面漂移——max 路径种子改行为面扫描(路线形状/商店/选路口为断言本体)
# 并流批(2026-09-27 统一流裁决)后战斗随机值面漂移——max 路径种子改行为面扫描(路线形状/商店/选路口为断言本体)
var win_min = autoplay.run_level(_db, 42, 2, 200, 100, false, null, "normal", "min", 0)
check(win_min.result == "victory", "L2·满配 min 路径通关(实测:%s)" % win_min.result)
check(win_min.boss_depth == 9, "L2 Boss 以编号 9 解析(终点编号最大——商店房批重编号 8→9)")
+3 -3
View File
@@ -1,6 +1,6 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# push_input 端到端输入探针(ADR-0003 登记项转义务、
# ADR-0006 Risks 缓解面)。现役探针全走 BoardView.click_cell 直调(合成鼠标事件零命中已实证)——
# push_input 端到端输入探针(2026-09-12 场景结构批登记项转义务、
# Node2D 迁移批 Risks 缓解面)。现役探针全走 BoardView.click_cell 直调(合成鼠标事件零命中已实证)——
# 本探针是真实输入路径的唯一自动化覆盖:鼠标事件 → 壳层 _gui_input → 板级公式换算(_cell_at)→
# 悬停/点选/chord 既有出口 → 组合根信号。四 case:①悬停可挖域(金框+十字光标)②悬停禁入
# (hover_forbidden 信号+灰禁红框)③悬停已开格(路径预览点迹+移动光标)④右键插旗(flag_place
@@ -129,7 +129,7 @@ func _ready() -> void:
_pre_fail("先导移动未到达(actions=%s hero=%s→%s)" % [str(_actions), hero0, ms.hero_pos()])
return
# ---- 目标格实证选取(不写死坐标;两枚相邻可挖格 + 禁入格 + 已开格)----
# 并流批(ADR-0007 裁丙 2026-09-27)后首战板面种子随全局序漂移——_diggable(主角 8 邻未开域)
# 并流批(2026-09-27 统一流裁决)后首战板面种子随全局序漂移——_diggable(主角 8 邻未开域)
# 不足两枚时,沿已开区真点击移位到「≥2 未开邻」的前沿格再选;移位失败即收手交由选取失败分支报状态
for _expand in range(16):
if bv.diggable_probe().size() >= 2:
+1 -1
View File
@@ -13,7 +13,7 @@ extends Node
const ProbeUiUtil := preload("res://smoke/probe_ui_util.gd") # T6 收口:隔离样板单点
const SIM_GUARD_FRAMES := 1800 # ⑤ N=10 headless 模拟防挂死帧预算上限(ADR-0004:探针内停滞检测第一道——坏态不等满预算才报,超时即断言失败)
const SIM_GUARD_FRAMES := 1800 # ⑤ N=10 headless 模拟防挂死帧预算上限(探针内停滞检测第一道——坏态不等满预算才报,超时即断言失败)
# 只读巡检信号名清单(17卡③「白名单外零连接」形制沿用——玩家交互可携带写意图的通道全集
# +本层外发 closed;引擎内部布局生命线信号不计)
+6 -6
View File
@@ -1,7 +1,7 @@
# Test Infrastructure — Dungeon Sweeper
**Engine**: Godot 4.7.2-stable(GDScript 单语言)
**Test Framework**: 双载体(ADR-0004)——`--headless --script` 逻辑冒烟 + headless 场景探针;gdUnit4 **deferred**(D2 OQ1 关闭形态,正式 CI 期再议)
**Test Framework**: 双载体——`--headless --script` 逻辑冒烟 + headless 场景探针;gdUnit4 **deferred**(D2 OQ1 关闭形态,正式 CI 期再议)
**CI**: `.github/workflows/tests.yml`(首次 push 到 GitHub 后自动生效;仓库已初始化 git、尚未配置远端)
**Setup date**: 2026-09-12(2026-09-27 `7f24b640` 三层收敛:根 tests/ 并入 `game/tests/`、docs 并入 `design/dev/`、production 解散)
**参考实现**: `game/smoke/`(冒烟断言 + 场景探针族——正式工程的活样板;断言计数双口径见下节)
@@ -14,7 +14,7 @@ tests/
smoke/ # critical-paths.md——人工 gate 清单(/smoke-check 读取)
evidence/ # 截图与人工签核记录
run_all.gd # CI 冒烟统一入口(套件 manifest 协议,D2 AC-2b)
static_scan.sh # ADR-0004 静态扫描域 S1–S8 可执行子集
static_scan.sh # 静态扫描域 S1–S8 可执行子集
```
> integration/ 目录已删空壳(迭代 19 卡① T4/Q8 2026-10-08——彼时仅有章程 README 无实体)。章程句保留在此:将来跨系统测试(Core-Core 集成、回放确定性〔同种子步骤流逐行相同——B1 AC-33 形态〕、存档/RNG 快照往返、A1×A2 双包含端到端)落地时随批建 `tests/integration/` 迁入;各 GDD 登记的 deferral 集成用例以对侧登记为生效条件。
@@ -36,13 +36,13 @@ godot --headless --script tests/unit/example_test.gd
# 场景探针(双载体之二)——以探针场景为运行目标,走完整项目引导(autoload 在位)
godot --headless --path . res://smoke/<probe>.tscn
# CI 旁必须配外部 wall-clock 超时(ADR-0004:引擎无死锁探测)
# CI 旁必须配外部 wall-clock 超时(引擎无死锁探测)
timeout 120s godot --headless --script tests/run_all.gd
```
> 单元/契约套件状态(单元测试与契约层批 2026-09-28 立基,后随迭代 7/8 增补):`_suites()` manifest 已登记实跑 **18 套件**(第 18 套 = 迭代 19 卡④提灯载体批新增 `unit/core/fog_lantern_wiring_test` 提灯装配链〔行加载/schema/只读出口双态/enc 注入面〕——本分支基点早于卡④合并时实测 17 套全绿,合并后 18)——data_config(ConfigDB 加载/进度坐标 ceil 解析/fatal 退出码/统一随机流)、core(秘宝结构冻结/断点续玩/提灯装配链)、battle_settlement(DamageMath 纯函数/DamageController 伤害单据五配方)、contracts(系统间接口契约断言)、presentation(节奏队列/奖励浮层/字体资产/地形瓦片集);致命类独立进程 `expect=1`。期望值一律由表读值推导(零玩法数值字面量)、随机只经 RngService 统一流。
**协议要点**(D2 冒烟协议 + ADR-0004):
**协议要点**(D2 冒烟协议):
- 冒烟脚本 `extends SceneTree` 以获得 `quit(code)`;成功 `quit(0)`、失败 `quit(1)`
- `--script` 模式**不加载 autoload 且不注册全局标识符**(裸引用 `ConfigDB` = parse error)——ConfigDB/RngService 由脚本显式实例化,core 一律构造注入
- 致命类用例独立进程,runner manifest 登记"调用 → 期望退出码"
@@ -67,8 +67,8 @@ timeout 120s godot --headless --script tests/run_all.gd
## Static Scan(提交前双跑:本地 + CI)
`tests/static_scan.sh` 实现 ADR-0004 扫描域 S1–S8 的可执行子集;规则全集与动机见
`design/dev/architecture/adr-0004-test-carrier-and-ci.md`。新违规案例必须**先补扫描规则再修码**。
`tests/static_scan.sh` 实现静态扫描域 S1–S8 的可执行子集;规则全集与动机见
`design/dev/architecture/architecture.md`「测试与质量域」节。新违规案例必须**先补扫描规则再修码**。
## CI
+1 -1
View File
@@ -1,4 +1,4 @@
# tests/run_all.gd — 单元测试统一入口(ADR-0004 双载体的逻辑测试调用点,套件 manifest 协议 D2 AC-2b)
# tests/run_all.gd — 单元测试统一入口(双载体的逻辑测试调用点,套件 manifest 协议 D2 AC-2b)
# 用法:godot --headless --path game --script res://tests/run_all.gd (CI 侧包装外部超时:timeout 120s …)
# 协议:套件清单逐条"套件 → 期望退出码";致命类独立进程(expect=1)。
# 执行形态:逐套件起独立 Godot 子进程实跑
+3 -3
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# tests/static_scan.sh — ADR-0004 静态扫描域 S1–S8 可执行子集
# 规则全集与动机:design/dev/architecture/adr-0004-test-carrier-and-ci.md §Decision 3
# tests/static_scan.sh — 静态扫描域 S1–S8 可执行子集
# 规则全集与动机:design/dev/architecture/architecture.md「测试与质量域」节
# 正式工程(core/ 存在)时执行;否则优雅跳过(工程在 game/core——2026-09-24 转正结构批后仓库根布局)。
# 纪律:新违规案例必须先补本脚本规则再修码(design/dev/code-conventions.md 缺陷-规范对照表)。
set -u
@@ -34,7 +34,7 @@ fi
# 2026-09-24 首次实跑收敛(转正结构批):违规签名=裸 randomize/rand* 调用(实例方法 .randi() 排除)
# + RngService 之外的 RandomNumberGenerator.new();接收服务注入流的类型标注不属违规(core 五文件 15 处实证)
hits=$(grep -rnE '\brandomize[[:space:]]*\(|(^|[^.[:alnum:]_])randi[[:space:]]*\(|(^|[^.[:alnum:]_])randf[[:space:]]*\(|(^|[^.[:alnum:]_])randf_range[[:space:]]*\(' \
game/core game/presentation --include='*.gd' 2>/dev/null | grep -vE '^[^:]+:[0-9]+:[[:space:]]*#' | grep -v 'ADR-0007-exempt' | wc -l)
game/core game/presentation --include='*.gd' 2>/dev/null | grep -vE '^[^:]+:[0-9]+:[[:space:]]*#' | grep -v 'rng-seed-exempt' | wc -l)
hits2=$(grep -rn 'RandomNumberGenerator\.new()' game/core game/presentation --include='*.gd' 2>/dev/null | grep -vc rng_service)
if [ "$hits" -gt 0 ] || [ "$hits2" -gt 0 ]; then echo "[static_scan] S1/S2 FAIL: 全局随机/RNG 自建命中 $hits+$hits2 处"; grep -rnE '\brandomize[[:space:]]*\(|(^|[^.[:alnum:]_])randi[[:space:]]*\(|(^|[^.[:alnum:]_])randf[[:space:]]*\(|(^|[^.[:alnum:]_])randf_range[[:space:]]*\(' game/core game/presentation --include='*.gd' 2>/dev/null; grep -rn 'RandomNumberGenerator\.new()' game/core game/presentation --include='*.gd' 2>/dev/null | grep -v rng_service; fail=1; else echo "[static_scan] S1/S2 ok"; fi
@@ -1,6 +1,6 @@
# tests/unit/data_config/config_db_test.gd — 数据配置单元测试:表加载/进度坐标 ceil 解析/变异池门控/消费面访问器
# 运行:godot --headless --path game --script res://tests/unit/data_config/config_db_test.gd
# 协议(ADR-0004 + tests/README):extends SceneTree + quit(code);--script 模式无 autoload——显式实例化。
# 协议(tests/README):extends SceneTree + quit(code);--script 模式无 autoload——显式实例化。
# 红线:期望值由表读值推导,不写死玩法数值(tests/README 协议要点)。
extends SceneTree
@@ -2,7 +2,7 @@
# 覆盖:六路线 schema 零违例(id 唯一/类型轴枚举/值域——出域行逐类构造各一行全部被拒)
# + 满级特效留空(行字段闭集=无特效参数位 + 效果类型闭集 24 种零新增)+ 几何价格梯 20/30/45/67/101。
# 运行:godot --headless --path game --script res://tests/unit/data_config/forge_table_test.gd(expect 0)
# 协议(ADR-0004 + tests/README):extends SceneTree + quit(code);负向用例资源直构不碰生产表(enemy_table 先例)。
# 协议(tests/README):extends SceneTree + quit(code);负向用例资源直构不碰生产表(enemy_table 先例)。
extends SceneTree
const ConfigDBScript := preload("res://core/config_db.gd")
@@ -49,7 +49,7 @@ func _test_counter_ledger() -> void:
rng.open_stream("armor_roll")
var c2: int = rng.counter()
Kit.check("open_stream 逐次推进全局计数器(+1/次)", c1 == c0 + 1 and c2 == c0 + 2)
# 用途标签只进事件日志不参与派生——同 scope 同派生种子(ADR-0007 裁丙口径)
# 用途标签只进事件日志不参与派生——同 scope 同派生种子(2026-09-27 统一流裁决口径)
var rng_x = _fresh_service()
var rng_y = _fresh_service()
var s1: int = int(rng_x.open_stream("board_gen").seed)
+1 -1
View File
@@ -1,6 +1,6 @@
# tests/unit/example_test.gd — 示例测试:项目测试协议的活样板(gate-check 硬性要求 ≥1 示例测试)
# 运行:godot --headless --script tests/unit/example_test.gd
# 协议要点(ADR-0004 + D2 冒烟协议):
# 协议要点(D2 冒烟协议):
# extends SceneTree 以获得 quit(code);断言失败 → push_error + quit(1);全绿 → quit(0)
# --script 模式无 autoload 且无全局标识符(裸引用 ConfigDB = parse error)——
# 涉及表值的测试须显式实例化 ConfigDB,期望由表读值推导不写死