From ccd31de9ce7a5280b8bbb8bfc8859d5fa83265e4 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sun, 25 Oct 2026 17:56:36 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=B7=A5=E7=A8=8B(S9=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=97=B8=E6=AD=A3=E5=88=99=E4=BF=AE=E5=A4=8D):=20FUNC=5FDECL?= =?UTF-8?q?=20=E8=AE=A4=E8=A1=8C=E5=B0=BE=E5=86=92=E5=8F=B7=E4=B8=8E=20sta?= =?UTF-8?q?tic=20=E5=89=8D=E7=BC=80=E4=B8=A4=E6=B4=9E=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=EF=BC=8C=E5=AD=98=E9=87=8F=2029=20=E5=A4=84=E8=A1=A5=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=B3=A8=E8=A7=A3=E9=9B=B6=E8=A1=8C=E4=B8=BA=E5=8F=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C--code=20=E5=9F=9F=E9=97=B8=E5=85=A8=E7=BB=BF?= =?UTF-8?q?=EF=BC=88=E5=9B=9E=E6=89=A7=20domain=3Dcode=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/core/attunement.gd | 2 +- game/core/battle_orchestrator.gd | 4 ++-- game/core/damage_controller.gd | 4 ++-- game/core/effect_engine.gd | 2 +- game/core/level_runner.gd | 2 +- game/core/reward_economy.gd | 8 ++++---- game/core/unit_container.gd | 2 +- game/presentation/battle_narrator.gd | 6 +++--- game/presentation/hud_presenter.gd | 6 +++--- game/presentation/main.gd | 4 ++-- game/presentation/tune_sim_controller.gd | 2 +- game/presentation/ui_assembler.gd | 6 +++--- game/presentation/views/battle_stage_view.gd | 2 +- game/presentation/views/board_view.gd | 2 +- tools/audit_type_hints.py | 2 +- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/game/core/attunement.gd b/game/core/attunement.gd index b282c727..f426f60c 100644 --- a/game/core/attunement.gd +++ b/game/core/attunement.gd @@ -7,7 +7,7 @@ extends RefCounted # 同调位实时求值(营地进冒险前求值一次 + 装配覆盖层实时呈现共用同一口径): # 槽位数量 = att_socket1..3 树点亮数(tree_level>=1),未点亮=0。 # db 参数保留(调用面两处签名不变——当前判定源零表依赖,参数弃置)。 -static func slots(db, save) -> int: +static func slots(db: ConfigDb, save: Variant) -> int: if save == null: return 0 var n := 0 diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index 3cdf75d9..89e30d56 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -163,7 +163,7 @@ func _flush_pending_reveals(ri: int) -> void: # 补充事实面(fact 取值第二优先源——payload 未携带的运行态读数) -func _fx_fact(fact: String): +func _fx_fact(fact: String) -> Variant: match fact: "charge_layers": return action_economy.charge_layers @@ -1225,7 +1225,7 @@ func is_battle_live() -> bool: # 奖励身份解析(组合根注入 BoardView 徽章回调的只读代理——Ready 相位守卫归 地图战斗资源) -func query_reward_identity(cell: Vector2i): +func query_reward_identity(cell: Vector2i) -> Variant: return _reward_economy.query_identity(cell) diff --git a/game/core/damage_controller.gd b/game/core/damage_controller.gd index 18c0303d..07b370cb 100644 --- a/game/core/damage_controller.gd +++ b/game/core/damage_controller.gd @@ -84,7 +84,7 @@ func _fx_hits(event: String, payload: Dictionary) -> Array: # 补充事实面(fact 取值第二优先源——payload 未携带的运行态读数:charge_layers 编排器每轮注入。 # hp_ratio 补入〔背水 when 面,敌技 damage_taken 载荷不带血比例时回落〕; # fx_reveal_request=揭示效果回调〔斩首学者 kill 订阅面——编排器注入,入队授予段末兑付〕) -func _fx_fact(fact: String): +func _fx_fact(fact: String) -> Variant: match fact: "charge_layers": return charge_layers @@ -611,7 +611,7 @@ func _attack_label(base: String, crit: bool, discount: int) -> String: # ---- 内部 ---- # 目标解析(结账时刻照规则看现场;句柄即 Dictionary 引用) -func _target_for(rule: String): +func _target_for(rule: String) -> Variant: match rule: TARGET_FRONT_ALIVE: return units.default_target() diff --git a/game/core/effect_engine.gd b/game/core/effect_engine.gd index 0883c8f4..e425518e 100644 --- a/game/core/effect_engine.gd +++ b/game/core/effect_engine.gd @@ -309,7 +309,7 @@ func _cond_ok(ctx: EffectContext, c: Dictionary, payload: Dictionary, facts: Cal return false -func _fact_value(ctx: EffectContext, fact: String, c: Dictionary, payload: Dictionary, facts: Callable): +func _fact_value(ctx: EffectContext, fact: String, c: Dictionary, payload: Dictionary, facts: Callable) -> Variant: match fact: "counter": return counter(ctx, String(c.get("id", ""))) diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index 300534b3..35dfc7b5 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -616,7 +616,7 @@ func pick_next_node(node_id: int) -> bool: # ---- 只读出口(E1/E3 封装收口:呈现层/工具经此读当前战斗,禁直读协作对象)---- -func current_battle(): +func current_battle() -> Variant: return _settlement # aux 解锁门控集注入(AdventureRunner 自 params 传递) diff --git a/game/core/reward_economy.gd b/game/core/reward_economy.gd index a74842af..3f820360 100644 --- a/game/core/reward_economy.gd +++ b/game/core/reward_economy.gd @@ -101,7 +101,7 @@ func is_mapped(cell: Vector2i) -> bool: return _phase == "ready" and _mapping.has(cell) -func query_identity(cell: Vector2i): +func query_identity(cell: Vector2i) -> Variant: if _phase != "ready": _diag("query_identity 非 Ready 相位") return null @@ -116,7 +116,7 @@ func query_identity(cell: Vector2i): # 身份完整快照(轮内刷新批次隔离用——facts 缓冲期捕获,授予期 mapping 可能已换批): # 返回与 grant 相同结构的快照(cell_type/display_name/power/effect_id/stacks 齐备), # 供 战斗结算 冻结授予直通 -func query_full_snapshot(cell: Vector2i): +func query_full_snapshot(cell: Vector2i) -> Variant: if _phase != "ready": _diag("query_full_snapshot 非 Ready 相位") return null @@ -128,7 +128,7 @@ func query_full_snapshot(cell: Vector2i): # ---- 受理面(战斗结算 编排期调用;E6 收口:失败统一返回 null)---- -func grant(cell: Vector2i): +func grant(cell: Vector2i) -> Variant: if _phase != "ready": _diag("grant 非 Ready 相位(E4/E7)") return null @@ -143,7 +143,7 @@ func grant(cell: Vector2i): return snap -func grant_clear(): +func grant_clear() -> Variant: if _phase != "ready": _diag("grant_clear 非 Ready 相位") return null diff --git a/game/core/unit_container.gd b/game/core/unit_container.gd index 2a3416c6..f1716edb 100644 --- a/game/core/unit_container.gd +++ b/game/core/unit_container.gd @@ -272,7 +272,7 @@ func heal(u: Dictionary, n: int) -> int: # 固定顺位:行主序生成序最前存活敌;死亡后顺延;空 → null -func default_target(): +func default_target() -> Variant: for u in _enemies: if u.alive: return u diff --git a/game/presentation/battle_narrator.gd b/game/presentation/battle_narrator.gd index c765c3ea..d66cf267 100644 --- a/game/presentation/battle_narrator.gd +++ b/game/presentation/battle_narrator.gd @@ -5,7 +5,7 @@ extends RefCounted # 节点进入横幅(棋盘日志——battle/boss 用;节点编号 = 行进器编号空间读面;行色 = UiKit.HEX_* 语义档单点) -static func node_banner(runner, node: Dictionary, t: String) -> String: +static func node_banner(runner: LevelRunner, node: Dictionary, t: String) -> String: return "[color=#%s]── 节点 %d/%d · %s(编号 %d)──[/color]" % [UiKit.HEX_LOG_GAIN, runner.node_index + 1, runner.nodes().size(), "Boss 房" if t == "boss" else "战斗", runner.node_id_of(node)] @@ -25,7 +25,7 @@ static func shop_line(gp: int) -> String: # 选路口行(零自动推进停点——战斗胜利/兑付确认后出现) -static func route_line(candidates: Array, runner) -> String: +static func route_line(candidates: Array, runner: LevelRunner) -> String: var names: Array[String] = [] for cand in candidates: names.append("节点 %d" % runner.node_id_of(cand)) @@ -69,7 +69,7 @@ static func phase_text(round_index: int, battle_result: String, waiting: bool, b # 行集多行时取**首行** display_name(行序即契约的呈现面后果, # Boss 行集混编护卫时 Boss 名显示可能为护卫名,知情代价登记 敌人系统 v0.15 / 出口报告; # 每坐标恰一行时无此歧义) -static func boss_name(runner, db) -> String: +static func boss_name(runner: Variant, db: ConfigDb) -> String: if runner != null: var node: Dictionary[Variant, Variant] = runner.current_node() if String(node.get("type", "")) == "boss": diff --git a/game/presentation/hud_presenter.gd b/game/presentation/hud_presenter.gd index 2ce1214f..f86a7541 100644 --- a/game/presentation/hud_presenter.gd +++ b/game/presentation/hud_presenter.gd @@ -76,7 +76,7 @@ static func _refresh_hero(stage: BattleStageView, info: HeroInfoPanelView, s: Di # ---- 行动经济(AP 点阵 / RAP / 弃图刷新按钮态——RAP 读数在本条) ---- -static func _refresh_economy(ap_bar: ApBarView, s: Dictionary, db, refresh_remaining: int) -> void: +static func _refresh_economy(ap_bar: ApBarView, s: Dictionary, db: ConfigDb, refresh_remaining: int) -> void: ap_bar.set_ap(int(s.ap), int(db.action_economy.ap_per_round)) ap_bar.set_rap(int(s.rap)) var digging := String(s.phase) == ActionEconomy.PHASE_ACTIVE @@ -88,7 +88,7 @@ static func _refresh_economy(ap_bar: ApBarView, s: Dictionary, db, refresh_remai # 特性持有文案(战斗 C 区与关卡选择页两处共用;空持有=空数组。 # 行形态=逐件「件名 ×N」(非逐流派聚合)——表行 # 无 archetype 字段,聚合形态会空键兜底实显「流派 ×N · 档一」僵尸文案;流派档位非现行机制) -static func feat_holdings_lines(db, held: Array) -> Array[String]: +static func feat_holdings_lines(db: ConfigDb, held: Array) -> Array[String]: var rlines: Array[String] = [] if db == null or db.feats == null or (db.feats.rows as Array).is_empty() or held.is_empty(): return rlines @@ -105,7 +105,7 @@ static func feat_holdings_lines(db, held: Array) -> Array[String]: # 地形变异常驻角标文案(整图变异 id → 文案行; # 空集 = 空数组=空态隐藏。三行制:变异名+两行效果说明(C 区 240px 宽防裁切)。 # 文案用常规表述,不用俚语 -static func board_variant_lines(db, ids: Array) -> Array[String]: +static func board_variant_lines(db: ConfigDb, ids: Array) -> Array[String]: var lines: Array[String] = [] if db == null or db.variation == null: return lines diff --git a/game/presentation/main.gd b/game/presentation/main.gd index 11eb50ed..357b51f4 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -562,7 +562,7 @@ func _wire_adventure() -> void: # 取值=meta.hero_attack_type/hero_armor_type=存档选中路线类型轴,未解锁/异常选中态回退锻造配置默认值)。 # 注:runner 侧 resume_adventure 受理面收 attunement/attune_refresh_y/tree_rules 三键 # (传参/受理两侧对齐)。 -static func build_adventure_params(save_manager_ref, meta_ref, extra: Dictionary = {}) -> Dictionary: +static func build_adventure_params(save_manager_ref: SaveManagerCore, meta_ref: MetaProgressionCore, extra: Dictionary = {}) -> Dictionary: var params: Dictionary[Variant, Variant] = { "hero_override": meta_ref.hero_override() if meta_ref != null else {}, "attack_type": meta_ref.hero_attack_type() if meta_ref != null else "", @@ -757,7 +757,7 @@ func _debug_hero_override() -> Dictionary: # 奖励徽章身份解析(组合根守卫:仅挖掘期 Active 相位内查询——地图战斗资源 Ready 域外零读、零诊断噪音; # 相位取数经 presentation_snapshot 成文面——禁 settlement.action_economy 链式穿透) -func _identity_lookup(c: Vector2i): +func _identity_lookup(c: Vector2i) -> Variant: if run_scope.settlement == null or run_scope.settlement.minesweeper.current_board() == null: return null if String(run_scope.settlement.presentation_snapshot().get("phase", "")) != ActionEconomy.PHASE_ACTIVE: diff --git a/game/presentation/tune_sim_controller.gd b/game/presentation/tune_sim_controller.gd index ccb3b0d8..07867c87 100644 --- a/game/presentation/tune_sim_controller.gd +++ b/game/presentation/tune_sim_controller.gd @@ -21,7 +21,7 @@ func _init(db_ref, panel_ref, base_hp: int, driver = null) -> void: # 驱动解析:注入优先;缺省回退运行时 load(旧行为——编译期反向依赖已解除,运行时口径与拆分前逐位一致) -func _autoplay(): +func _autoplay() -> Variant: if _driver != null: return _driver return load("res://sim/level_autoplay.gd") # 与 headless 扫描同口径的自动策略(P3 兜底路径) diff --git a/game/presentation/ui_assembler.gd b/game/presentation/ui_assembler.gd index 95366d4c..d1b2706e 100644 --- a/game/presentation/ui_assembler.gd +++ b/game/presentation/ui_assembler.gd @@ -11,7 +11,7 @@ extends RefCounted # + 结算演出覆盖层(A–D 之上、模态之下——跨区弹道/光带载体)。 # 返回句柄字典:{stage, log_view, info_panel, board_zone, board_view, ap_bar, settlement_fx} # (返回句柄不含 gp_label/keystone_label——GP/钥石不在战斗屏呈现) -static func build_battle_ui(root: Control, db) -> Dictionary: +static func build_battle_ui(root: Control, db: ConfigDb) -> Dictionary: # set_anchors_and_offsets_preset(非 set_anchors_preset):后者会把控件重置回最小内容尺寸 # (实测 927×613——缩顶、棋盘 45px 格 ×10 行超出 D 区 333px 高被裁) root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) @@ -64,7 +64,7 @@ static func build_battle_ui(root: Control, db) -> Dictionary: # (本组不含调试浮窗——由组合根直构挂树序最末,见 main._build_ui; # 本组不含明细回看 overlay——冒险中回看归「生涯」页; # 本组不含营地覆盖层——在 camp_screen 屏壳构建) -static func build_overlays(host: Control, db) -> Dictionary: +static func build_overlays(host: Control, db: ConfigDb) -> Dictionary: var legend_overlay := LegendOverlay.new(int(db.action_economy.rap_refresh_cost)) # RAP 行表值注入 host.add_child(legend_overlay) @@ -94,7 +94,7 @@ static func build_overlays(host: Control, db) -> Dictionary: #(教学内容归 Beta 帮助手册〔教学引导定稿 P4 丙〕)**;本层无玩法速览牌; # tooltip 主题归全局主题单点(禁在 root 挂程序化 tooltip 主题)。 # 返回键集如首行所列,接线归组合根) -static func build_start_overlay(host: Control, db = null) -> Dictionary: +static func build_start_overlay(host: Control, db: ConfigDb = null) -> Dictionary: var overlay := overlay_bg(host, UiKit.BG_BRIGHT) # 石纹弱质感+斜光带+暗角(demo .tilebg 0.14/.beams/.vignette 三层; # 石纹层用半透明贴图,非满铺不透。缺位不挂即回退平色) diff --git a/game/presentation/views/battle_stage_view.gd b/game/presentation/views/battle_stage_view.gd index fb23bc05..29b6db38 100644 --- a/game/presentation/views/battle_stage_view.gd +++ b/game/presentation/views/battle_stage_view.gd @@ -339,7 +339,7 @@ func _card_by_name(display_name: String) -> Node2D: # 跨区弹道目标坐标(结算演出链批——组合根传给 SettlementFxView 的全局锚点;壳层口径 C4) -func enemy_standee_center(display_name: String): +func enemy_standee_center(display_name: String) -> Variant: var card := _card_by_name(display_name) if card == null or not is_instance_valid(card): return null diff --git a/game/presentation/views/board_view.gd b/game/presentation/views/board_view.gd index 976a2006..ba9208a3 100644 --- a/game/presentation/views/board_view.gd +++ b/game/presentation/views/board_view.gd @@ -995,7 +995,7 @@ static func _flip_tex(tex: Texture2D) -> Texture2D: # 地板瓦片明度归一(方向稿 _v3_darken_floors 同式移植):8×8 双线性重采样均值测光 # (sRGB→线性域,Rec.709 系数),增益 k=(目标/实测)^(1/2.2) 钳 [0.6,1.8],逐通道 sRGB 域线性拉伸。 # 输入恒为 freshly-loaded 原图(load_tex 每次盘读)——幂等可重入;32×32 五变体开销可忽略 -static func _normalize_floor_luma(tex: Texture2D, target_l: float = 0.10, lumas_out = null) -> Texture2D: +static func _normalize_floor_luma(tex: Texture2D, target_l: float = 0.10, lumas_out: Variant = null) -> Texture2D: var img: Image = tex.get_image() if img.is_compressed(): img.decompress() diff --git a/tools/audit_type_hints.py b/tools/audit_type_hints.py index 09407b20..968c1d4b 100644 --- a/tools/audit_type_hints.py +++ b/tools/audit_type_hints.py @@ -22,7 +22,7 @@ SCAN_DIRS = ["game/core", "game/data", "game/presentation"] R1A_UNPARAM = re.compile(r"\bvar\s+\w+\s*:\s*(Dictionary|Array)\b(?!\[)") R1B_LITERAL = re.compile(r"^\s*var\s+\w+\s*(:?=)\s*[\{\[]") R1B_TYPED = re.compile(r"^\s*var\s+\w+\s*:\s*[\w\[\]]+") -FUNC_DECL = re.compile(r"^(\s*)func\s+(_?\w+)\s*\((.*)\)\s*(->\s*.+)?\s*(#.*)?$") +FUNC_DECL = re.compile(r"^(\s*)(?:static\s+)?func\s+(_?\w+)\s*\((.*)\)\s*(?:->\s*([^:#]+?))?\s*:\s*(#.*)?$") PARAM_SPLIT = re.compile(r",(?![^(\[]*[)\]])") RETURN_VALUE = re.compile(r"^\s*return\s+\S") From 5dcbbd48dcae3a55810a92de39cdc039d4492a9b Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sun, 25 Oct 2026 18:24:16 +0800 Subject: [PATCH 2/3] =?UTF-8?q?docs(S9/S13=E6=94=B6=E5=B0=BE):=20=E4=B8=A4?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E6=94=B9=E5=8A=A8=E6=89=B9=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=8D=B3=E5=88=A0=E6=9D=A1=E7=9B=AE=E2=80=94=E2=80=94S9?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E9=97=B8=E6=AD=A3=E5=88=99=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=8ES13=E5=9F=BA=E7=BA=BF=E9=94=AE=E6=B2=BB=E6=9C=AC?= =?UTF-8?q?=E5=9D=87=E5=B7=B2=E5=90=88=E5=9B=9Emaster(37625317/b95879de),?= =?UTF-8?q?=E6=9D=A1=E7=9B=AE=E6=8C=89=E5=AE=8C=E6=88=90=E5=87=BA=E8=B4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 待办清单.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/待办清单.md b/待办清单.md index 7fbee2cf..624e736b 100644 --- a/待办清单.md +++ b/待办清单.md @@ -28,24 +28,6 @@ **状态**:待写卡+已写卡+已编迭代 37 -#### S9 类型闸正则失灵修复——R2 恒零命中+static 函数漏网(2026-10-24 登记,来源=审计发现) - -**实况**:工程债证据=reports/审计-game代码结构审查-2026-10-24.md §二 C1(已独立复现):tools/audit_type_hints.py:29 的 FUNC_DECL 正则两洞——①无返回类型声明按 GDScript 语法必然以 `:` 结尾,正则要求 `)` 后只跟 `->`/注释/行尾,R2 目标形态 100% 失配(R2 从上线起恒零命中恒绿);②`^(\s*)func` 不认 `static ` 前缀,static 函数对 R2/R3 整体漏网。实证存量(闸当前退出码 0):core/level_runner.gd:632、core/attunement.gd:10、presentation/main.gd:565、presentation/views/hud_presenter.gd:10-11、core/reward_economy.gd:104/119/131/146、core/unit_container.gd:275(写卡会话路径订正:hud_presenter 实址 game/presentation/hud_presenter.gd,非 views/)。属架构文档测试域自警的「规则扫描面为空=恒绿」静默失效模式(零命中自检因 R1/R3 仍有命中能力未拦住)。2026-10-25 规则修订(改动四类):本件属工程改动(闸件修复,直改类)。执行口径=修 `tools/audit_type_hints.py:29` FUNC_DECL 正则两洞(①无返回类型声明的声明形态恒失配;②`^(\s*)func` 不认 `static ` 前缀),存量以开工时盘面清点(实证九址为已知下限),验收走撤销证明。原需求卡片按违形退役:结论已回写本条目,卡片删除,全稿查 git 历史(提交 546e5113)。 - -**改动面**:工具代码 - -**状态**:待执行 - -#### S13 gdstyle 免名单把数字当身份——存量债改小也报「基线外新违规」(2026-10-25 登记,来源=批次移交) - -**实况**:工程债证据=迭代 35 卡② 合回前后实测(master 合回笔 `5499eb9c`)。闸件 `tools/gdstyle_gate.py:82` 把每条违规登记成三元组「文件|规则|消息全文」,而 gdstyle 的消息文本里带具体数字(如 `function 'resume_adventure' is 104 lines long (max 50)`),基线 `tools/gdstyle_baseline.txt`(241 行)按整句逐字比对——**只要某函数的行数/分支数/变量数发生变化,老违规就匹配不上,被判「基线外新违规」并判红,改小也算新增**。卡② 一批即因此冒出 12 项假新增,逐条对基线旧值核实全是存量债的计数漂移:`config_db_cross_validator.cross_validate` 159→107 行/31→21 分支/39→24 局部/嵌套 6→5(本批按卡片删除跨表校验④整段所致,债变小)、`level_runner` 类变量 40→38 且其「文件 1013 行超长」违规已消失(债被还掉)、`start_level_external` 参数 8→7、`main.gd` 1509→1507、`adventure_runner` 类变量 43→42/文件 1050→1051/`resume_adventure` 104→108 行(本批加断点代差标记键拒绝检查多 4 行)。本批真正新写的超标仅 1 处(新函数 `validate_graph` 72 行/20 分支),已当场拆成四段修掉。**盘面后果**:卡② 按用户令零复跑合回,master 尖 5499eb9c 从未整套跑绿过代码域闸;下一次任何批跑代码域闸都会看到 S13 红这 12 项(不处理则每批重复一次「要么重生成基线、要么被红挡在合回前」)。卡片裁决留档(卡片已违形退役,git 历史可考):四待裁点已拍板——稳定身份键/恶化判据超登记值即红/本批治本+批内刷新基线/refresh 加对账自检与骤降守卫;验收按 2026-10-24 撤销证明口径执行。2026-10-25 规则修订(改动四类):本件属工程改动(闸件修复,直改类)——原卡片按违形退役,结论已回写本条目,卡片删除,全稿查 git 历史(提交 36b444eb);执行口径=治本档(四待裁点已拍板项照录上文),用户发令直改。 - -两档方案(第一条只治标):① 治标=人工跑一次 `python tools/gdstyle_gate.py --refresh` 重生成基线+一笔提交,约 5 分钟,但键形态未改,下一批再动这些文件还会重演;② 治本=改 `tools/gdstyle_gate.py` 的键构造段(:77-90,约 10–20 行)为「文件|规则|函数名」——函数名从消息里正则提取 `function 'x'`,无函数名的条目(类变量数/文件长度)退化为「文件|规则」,并**另加一条恶化判据**防新键吞掉真问题(同一函数当前指标较基线登记值恶化超阈值即判红,纯规范化数字会把 104→300 行的恶化也放过去,不可只靠数字抹平);随动=重生成 `tools/gdstyle_baseline.txt`(241 行按新键重排)、`tools/run_all_gates.sh` 头注与 `game/tests/README.md` 工具速查表的 S13 描述各一行、撤销证明四项(新增一处真超标必红/同函数改小改大的数字漂移禁止再冒新/恶化超阈值必红/禁闸内自动重生成清基线换绿的自检仍绿——各配撤销该判据见红+还原复绿)。合计约 **0.5 个工作日**,工程改动(tools/ 闸机面)直改类。 - -**改动面**:文档+工具代码 - -**状态**:待执行 - #### S6/S7/S8 静态规则落地——编排唯一性/禁 await/信号纪律三闸(2026-10-24 登记,来源=审计发现) **实况**:工程债证据=reports/审计-game代码结构审查-2026-10-24.md §二 C2:三规则 static_scan.sh TODO 在案(架构文档静态扫描表自认未落地)——S6 core↔core 信号禁 lambda 捕获 self、S7 B2/B3/B4 API 符号命中文件 ⊆ B1 文件集、S8 结算路径 await 零命中。2026-10-24 审查人工 grep 结论干净(core 零 await、A2/B3/B4 零相互直调),但防线缺位=回归无闸。S7 前置:须先在架构文档成文 B1 文件集边界(含 core/settlement/ 五段类与 damage_controller——现归属表零条目,见「架构与规范对齐批」条目①)。**2026-10-24 用户裁:条目整条冻结待④(「架构与规范对齐批」)裁决后再写卡**——写卡会话核对结论:S6(core 信号禁 lambda)与 S8(结算路径禁 await,文件集可按现行结算文件直接枚举)与④零依赖、技术上可先行,但按「先裁④再动③」整条冻结不先行。 From 82d0cf24a615a77963f21f4c8656f6d57fbb8020 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sun, 25 Oct 2026 18:47:14 +0800 Subject: [PATCH 3/3] =?UTF-8?q?docs(=E6=9E=B6=E6=9E=84=E4=B8=8E=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E5=AF=B9=E9=BD=90=E6=89=B9=C2=B7=E9=83=A8=E5=88=86?= =?UTF-8?q?=E8=90=BD=E6=96=87):=20=E2=91=A4=E6=98=8E=E7=BB=86=E8=A1=8C?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E4=B8=A4=E5=B1=82=E5=8C=96(=E5=9F=BA?= =?UTF-8?q?=E7=A1=809+=E6=89=A9=E5=B1=95=E8=A1=8C1,=E6=A6=82=E5=BF=B5+?= =?UTF-8?q?=E6=8C=87=E5=BC=95=E6=B3=95,=E6=95=88=E6=9E=9C=E8=BA=AB?= =?UTF-8?q?=E4=BB=BD=E6=8C=87=E5=90=91=E5=AE=9E=E7=8E=B0=E5=A4=B4=E6=B3=A8?= =?UTF-8?q?)+=E6=9D=A5=E6=BA=90=E8=B1=81=E5=85=8D=E5=B0=81=E9=97=AD?= =?UTF-8?q?=E6=B8=85=E5=8D=95=E4=BA=94=E7=B1=BB=E5=AF=B9=E9=BD=90;=20?= =?UTF-8?q?=E2=91=A0=E5=BD=92=E5=B1=9E=E8=A1=A8API=E5=AF=B9=E9=BD=90?= =?UTF-8?q?=E5=AE=9E=E5=86=B5(A2=E6=92=A4=E4=BE=BF=E6=8D=B7=E5=BD=A2/A3?= =?UTF-8?q?=E8=A1=A5=E9=A2=84=E6=8E=88=E6=9D=83=E9=80=9A=E9=81=93/B2?= =?UTF-8?q?=E6=8D=A2check=5Fskill=5Funlocks/B4=E6=92=A4equivalence=5Fsuppl?= =?UTF-8?q?y/level=5Frunner=E6=92=A4=E5=B9=BB=E5=BD=B1grant=5Fnode=5Factiv?= =?UTF-8?q?e)+damage=5Fcontroller=E4=B8=8Esettlement=E4=BA=94=E6=AE=B5?= =?UTF-8?q?=E6=AE=B5=E7=B1=BB=E5=85=A5=E8=A1=A8+B1=E5=9F=9F=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E9=9B=86=E6=88=90=E6=96=87(S7=E5=89=8D=E7=BD=AE?= =?UTF-8?q?=E5=A4=87=E9=BD=90);=20=E2=91=A3=E5=B1=82=E5=90=88=E5=90=8C?= =?UTF-8?q?=E8=AE=A1=E6=95=B018;=20=E2=91=A5=C2=A71.3=E4=BE=8B=E4=B8=BE?= =?UTF-8?q?=E6=8D=A2=E4=BB=A3player=5Frequest=5Frefresh;=20=E2=91=A1?= =?UTF-8?q?=E2=91=A2=E4=B8=A4=E8=A3=81=E5=86=B3=E7=82=B9=E4=BF=9D=E6=8C=81?= =?UTF-8?q?=E5=BC=80=E6=94=BE=E5=BE=85=E7=94=A8=E6=88=B7=E6=8B=8D=E6=9D=BF?= =?UTF-8?q?(2026-10-25=E7=94=A8=E6=88=B7=E4=BB=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=89=A7=E8=A1=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../engineering/architecture/architecture.md | 24 ++++++++++--------- design/engineering/code-conventions.md | 2 +- design/gdd/systems/战斗循环/战斗结算.md | 14 ++++++++--- 待办清单.md | 6 +++-- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/design/engineering/architecture/architecture.md b/design/engineering/architecture/architecture.md index 6eb4fbce..145f4d1b 100644 --- a/design/engineering/architecture/architecture.md +++ b/design/engineering/architecture/architecture.md @@ -2,8 +2,8 @@ ## 文档状态 -- 版本:1.9 -- 最近更新:2026-10-21(迭代 32 卡②反哺点写入——effect_engine 行与战斗域装配节改无状态化 ctx 形态、架构原则新增「系统无状态」条;2026-10-21 用户裁) +- 版本:1.10 +- 最近更新:2026-10-25(架构与规范对齐批部分落文——模块归属表 API 对齐实现实况+B1 域文件集成文+明细行协议两层化指针+层合同计数 18;2026-10-25 用户令) - 引擎:Godot 4.7.2-stable(GDScript 单语言;2026-09-07 锁定) - 评审模式:solo(`review-mode.txt`,2026-09-12 用户拍板——TD/LP 门禁按 solo 跳过,用户授权架构产出自主推进、迭代期回调) - 覆盖 GDD:现行全集——`design/gdd/` 顶层 00–08 共 9 件 + `systems/` 五域 25 件(排雷循环 4 / 战斗循环 5 / 冒险循环 5 / 跨局循环 5 / 表现与支撑 6)+ `ux/` 8 件;原英文命名 12 份系统 GDD 已全部迁入中文域目录,原「未设计」预留(A5 扫雷秘宝 / C1–C4 / B5 / D3–D6)均已立项成文 @@ -92,7 +92,7 @@ |---|---|---|---|---| | **ConfigDB**(autoload,D2) | 全部玩法数值表(`data/tables/*.tres` + `data/schemas/*.gd`);SCHEMA_VERSION;加载/校验/override/诊断状态机 | 类型化属性读取;`load_tables(root, collect_only)`;`resolve()`(R1 floor);debug override;`set_reload_gate()`;诊断收集器 | 无(基础层顶点) | Resource/.tres 加载、autoload 生命周期——LOW | | **RngService**(autoload,D2) | master_seed、各流 scope 计数器(封闭流:board_gen / reward_roll;增流走 P1 评审) | `set_master_seed()`(唯一调用方 C2);`open_stream(stream)` 有状态门面;`derive_at(stream, scope)` 纯函数;只读计数器 | ConfigDB(无) | 无——纯逻辑 | -| **action_economy**(A3) | AP/RAP 账本、last_round_end、轮次相位机 {Idle, Active, Waiting}、结束仲裁 | 8 API 全布尔面:notify_round_start / request_dig / request_flag_place / request_flag_pull / request_stop / request_refresh / notify_settlement_done / notify_combat_end;ap/rap/phase 只读 | ConfigDB(ActionEconomyTable);B1 回发 next_round_mode/battle_over | 无 | +| **action_economy**(A3) | AP/RAP 账本、last_round_end、轮次相位机 {Idle, Active, Waiting}、结束仲裁 | 意图与通知布尔面:notify_round_start / request_dig / request_stop / request_refresh / notify_settlement_done / notify_combat_end;预授权通道:grant_reserve_ap / finish_round_stop;ap/rap/phase 只读 | ConfigDB(ActionEconomyTable);B1 回发 next_round_mode/battle_over | 无 | | **variation 定义**(A4) | VariationTable schema(现行 6 行:六 region——贫矿脉 global 行 2026-10-16 用户令屏蔽删行,global 型机制代码保留)与 F1 候选池门控谓词 | `variant_pool(level_index, board_type, node_type="")`(门控三维:unlock+board_types+节点身份——global 行仅 boss/elite 入池,缺省跳过零扰动);`global_variant_row(level_index, board_type, node_type)`(全局型单行决议访问器) | ConfigDB(VariationTable) | 无 | | **status_container**(B3) | 状态实例容器(战斗域生命周期、跨轮跨图延续) | 5 API:notify_battle_start / apply_effect / query_active / decay_round / notify_battle_end | ConfigDB(StatusEffectTable) | 无(RefCounted) | | **save_system**(D3,Alpha;iter27 已升格 autoload「SaveManager」) | 存档格式与版本比较 | (契约规范源:`../../gdd/systems/表现与支撑/存档序列化.md`——契约锚:SCHEMA_VERSION + master_seed + 各流 scope 计数器快照,须在无正在执行中的 open_stream 实例时切出) | ConfigDB、RngService 只读计数器 | FileAccess——LOW | @@ -103,18 +103,20 @@ | 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API | |---|---|---|---|---| | **board_generator**(A1) | 生成算法(五阶段管线)、BoardGenTable 回填、生成期指标集、合法性谓词(clearable / R₀≠S / min_safe)、可推理率度量(metric_version);生成姿态 = MVP 同步生成 + 加载幕(切片实证 10×10/12×12 同步可接受,WorkerThread 留扩展) | `generate(L, D, rng) -> Board`;度量独立入口×3(推理器 / F3 度量 / 合法性谓词——独立纯函数、同一实现) | ConfigDB(BoardGenTable/VariationTable);board_gen 流(一次 open_stream = 一张图);dig_ap_cost 只读 | 无 | -| **minesweeper_rules**(A2) | 棋盘状态(已开集 O / 封印集 G / 小人位)、三事件面、批次仲裁、install 四不变式 | `install_board(board)`;`settle_batch(intents)`(唯一提交入口);try_dig / try_flag_place / try_flag_pull / try_move(便捷形);`compute_move_path(cell)` 只读;`retire_board()`;三源拒绝(board_face / resource_face / phase)+ sub_reason 封闭枚举 | A1 产物(Board class_name 数据契约);A3 try_spend / last_round_end / 相位 | 无(零表读取、零 UI——切片实证) | -| **unit_container**(B2) | hero/enemy 单位实例(hp/atk/实例池:池快照+冷却+摇定动作+保底计数)、行值快照 | spawn / query_alive / rollable_skills / special_skills / set_pending_action / pending_action / basic_streak / commit_action / tick_cooldowns / apply_damage / heal / default_target / ambush_grant_plan / despawn_all(2026-09-16 敌人技能池批:query_beat/query_attack/advance 随行为环退役) | ConfigDB(EnemyTable/SkillTable/HeroTable) | 无 | -| **reward_economy**(B4) | 格面资源身份映射(install 期预分配、Ready 只读、换图映射消亡)、极性路由字典面((类型, 极性)→ 字典行查询;路由执行归 B1 授予段)、F6 当量供给投影 | 封闭 API:roll_board / query_identity / query_full_snapshot / grant / grant_clear / retire_mapping / polarity_row / equivalence_supply / phase / weighted_pick;另有 is_mapped 静默布尔投影(批量工具用) | ConfigDB(RewardTable);reward_roll 流(scope = 每次 install 批) | 无 | +| **minesweeper_rules**(A2) | 棋盘状态(已开集 O / 封印集 G / 小人位)、三事件面、批次仲裁、install 四不变式 | `install_board(board)`;`settle_batch(intents)`(唯一提交入口);查询只读面(current_board / hero_pos / is_revealed / has_seal 等);`compute_move_path(cell)` 只读;`retire_board()`;三源拒绝(board_face / resource_face / phase)+ sub_reason 封闭枚举 | A1 产物(Board class_name 数据契约);A3 try_spend / last_round_end / 相位 | 无(零表读取、零 UI——切片实证) | +| **unit_container**(B2) | hero/enemy 单位实例(hp/atk/实例池:池快照+冷却+摇定动作+保底计数)、行值快照 | spawn / query_alive / rollable_skills / special_skills / set_pending_action / pending_action / basic_streak / commit_action / tick_cooldowns / apply_damage / heal / default_target / check_skill_unlocks / despawn_all(2026-09-16 敌人技能池批:query_beat/query_attack/advance 随行为环退役) | ConfigDB(EnemyTable/SkillTable/HeroTable) | 无 | +| **reward_economy**(B4) | 格面资源身份映射(install 期预分配、Ready 只读、换图映射消亡)、极性路由字典面((类型, 极性)→ 字典行查询;路由执行归 B1 授予段)、F6 当量供给投影 | 封闭 API:roll_board / query_identity / query_full_snapshot / grant / grant_clear / retire_mapping / polarity_row / phase / weighted_pick;另有 is_mapped 静默布尔投影(批量工具用) | ConfigDB(RewardTable);reward_roll 流(scope = 每次 install 批) | 无 | | **helper_items**(A5,切片已实装秘宝域) | HelperItemTable、探测显影语义 | (契约规范源:`../../gdd/systems/跨局循环/秘宝.md`——桥接位:A2 查询接口 + A4 counter_item_ids) | A2 / A4 / B4 | 无 | ### 功能层 | 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API | |---|---|---|---|---| -| **battle_orchestrator**(B1) | 段序骨架(七段结构冻结)、轮 facts 缓冲、可回放步骤流、[明细行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)(15 类行 + 字段分层)、条款③⑤闭合对账、**战斗域全部跨系统调用权**、效果引擎宿主(每战 rebuild;round/battle 桶为编排器自有字典、经 EffectContext 引用挂载)+ 树规则挂点施加面(posture 窗/sense 限次/守侧 seal_missed 发射/聚乘算入账前) | `begin_battle(encounter)`;窗口/刷新意图提交面(扮演 D1);`level_clear()`;步骤流(输出契约) | B2/B3/B4 全调用面(**唯一调用方**);A3 request_refresh 代理 + 回发;A2 install/retire + 三事件订阅;A1 generate(attempt 非 scope 事件);D2 SettlementTable + set_reload_gate | 无(零随机、禁 await——切片 88 冒烟实证可回放) | +| **battle_orchestrator**(B1) | 段序骨架(七段结构冻结)、轮 facts 缓冲、可回放步骤流、[明细行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)(基础行型+扩展行两层 + 字段分层,词表以 owner「明细流水」节为准)、条款③⑤闭合对账、**战斗域全部跨系统调用权**、效果引擎宿主(每战 rebuild;round/battle 桶为编排器自有字典、经 EffectContext 引用挂载)+ 树规则挂点施加面(posture 窗/sense 限次/守侧 seal_missed 发射/聚乘算入账前) | `begin_battle(encounter)`;窗口/刷新意图提交面(扮演 D1);`level_clear()`;步骤流(输出契约) | B2/B3/B4 全调用面(**唯一调用方=B1 域文件集:battle_orchestrator.gd + settlement/ 五段段类 + damage_controller**);A3 request_refresh 代理 + 回发;A2 install/retire + 三事件订阅;A1 generate(attempt 非 scope 事件);D2 SettlementTable + set_reload_gate | 无(零随机、禁 await——切片 88 冒烟实证可回放) | +| **damage_controller**(B1 域·伤害单据管线) | 伤害单据唯一兑现管线(单据九栏目声明→分量掷点/克制修正/伤害下限归一→明细行发射;双方同规) | 兑付入口(编排侧开单)+ fx 揭示回调注入位 | B2 单位实例(单据目标传入);B1 注入(EffectContext 引用束与编排回调) | 无 | +| **settlement/ 五段段类**(B1 域·结算段件) | B1 每轮结算序列的五段逻辑件(授予/增益减益/战斗/衰减/判定——细则见下「战斗域装配现状」节) | 段处理入口(B1 接线调用);可直接 `new()` 单测 | B2/B3/B4 兑付面与 B1 轮 facts 缓冲(各段按职责) | 无 | | **effect_engine**(核心层——内容数据驱动扩展批 iter17 建域) | 零运行时可变状态的系统(见「架构原则」条 8):事件/事实/效果类型/算子四词表封闭(迭代 21 T3 扩签:EVENTS 18→19 +seal_missed 标错判定、FACTS +battle_index 关卡域战斗序)+ 树规则合成订阅六键(posture 每关首轮窗/sense 两组限次 counter 闸·adv_ 前缀走冒险桶跨战斗持久) | rebuild(每战重建订阅表)/`dispatch(ctx, event, payload, facts)`/`validate_trigger_row` + 静态计数口 `counter`·`counter_add`·`counter_spend`·`bucket_of`·`counter_id_legal`(计数器读写只经 EffectContext 引用束,无导出/灌入接口) | ConfigDB(feats/treasure 行集)、EffectContext(四桶引用由宿主持有:round/battle 桶归编排器、level 桶归关卡域、adventure 桶归 RunLedger) | 无(零随机全确定) | -| **level_runner**(C1-lite,切片已建) | 关卡域生命周期(节点链推进、共享 B4 + HP 携带、关卡末 level_clear) | 节点推进接口;LevelTable(`level.tres`——节点 enum {battle,reward,rest,boss}、末节点必须 Boss、ConfigDB 跨表校验⑧) | B1 begin_battle、B4 grant_node_active、ConfigDB LevelTable | 无 | +| **level_runner**(C1-lite,切片已建) | 关卡域生命周期(节点链推进、共享 B4 + HP 携带、关卡末 level_clear) | 节点推进接口;LevelTable(`level.tres`——节点 enum {battle,reward,rest,boss}、末节点必须 Boss、ConfigDB 跨表校验⑧) | B1(直构 BattleOrchestrator 接线战斗)、ConfigDB LevelTable | 无 | | **run_structure**(C2) | 冒险/关卡序列、失败重开、**master_seed 唯一接线方** | (契约规范源:`../../gdd/systems/冒险循环/冒险结构.md`) | RngService.set_master_seed、C3/D2 | 无 | | **difficulty**(C3) | DifficultyTable 回填、全部曲线数值调参所有权、战斗期望表(切片 monte_carlo 为工具原型) | 调参输出(经 D2 R1 解析/编排器传递,禁反向调用生成) | ConfigDB、B1 对账输出(调参约束清单)、A1 报告 C | 无 | | **meta_progression**(C4,Alpha) | MetaTable、钥石账本、天赋树域(MetaTreeTable 12 节点 v0.8——Fork 一节点双态/row 字段退役/RULE_KEYS 六键/彩蛋特化觉醒,迭代 21 T1 换代)+ 同调位槽位判定(树点亮数单源——T4 槽位收编) | tree_can_buy/tree_buy/tree_buy_fork/tree_toggle_fork(写口唯一)、hero_override 注入(树淬炼 flat+锻造路线加值位预留 0)、tree_rule_keys | D3、C2、ConfigDB | 无 | @@ -146,9 +148,9 @@ ### 视觉层装配合同 -- **树序 = 登记序 = z 序**,同源派生;层序唯一事实源 = `main.gd` 的 `LAYER_CONTRACT` 常量表(现行 17 项,kind 五类:shell=屏壳〔成员随壳不占独立树位〕/modal=模态层〔入登记册,tags 随登记〕/state=全屏态/node=非视觉节点/float=不注册 ModalStack 的最顶浮层〔任何 UI 打开都不遮挡它〕)。 +- **树序 = 登记序 = z 序**,同源派生;层序唯一事实源 = `main.gd` 的 `LAYER_CONTRACT` 常量表(现行 18 项,kind 五类:shell=屏壳〔成员随壳不占独立树位〕/modal=模态层〔入登记册,tags 随登记〕/state=全屏态/node=非视觉节点/float=不注册 ModalStack 的最顶浮层〔任何 UI 打开都不遮挡它〕)。 - 全仓唯一落位口 = `_apply_layer_contract()`(装配尾统一排序+登记);散落 `move_child` 由冒烟 V1d 源码断言判红;**改层序只改合同表**。 -- 具体层清单不复制进本文(双写失同步禁令)——查现行 17 项直接读 `main.gd`。 +- 具体层清单不复制进本文(双写失同步禁令)——查现行 18 项直接读 `main.gd`。 ### 会话生命周期(RunScope) @@ -338,7 +340,7 @@ CJK 字体随包发行并设为 theme 默认字体——运行时默认字体无 | A1 → A2 | Board 产物 class_name 数据契约 | install 四不变式校验(violation = 拒绝 + 五类诊断枚举) | 生成期合法性闸(R₀≠S / clearable / min_safe) | | A1 ↔ B1 | attempt 边界非 scope 事件;actuals p10 为对账输入(非 target 参数) | 编排不把重试当取号 | 生成期指标集输出(实测可推理率 / 实际雷数与安全格数 / 重试次数 / 降级与非法产物标记) | | B4 → B3 | buff 类经 B1 调 apply_effect(B4 零跨系统读、零直接接口) | 满层拒绝 = 零兑付 + 明细行(无折算) | 授予时数值快照(抗热重载) | -| B1 → D1 | [步骤流行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)(15 类封闭枚举 + 公共字段 type/source_class/origin_cell/round_index/display_name/value/highlight? + 特有字段 target/effect_id/pool_value) | 无来源行 = 断言失败;呈现侧禁按行序重演 B2 状态机 | 可回放步骤流(同种子逐行相同) | +| B1 → D1 | [步骤流行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)(基础行型+扩展行两层封闭 + 公共字段 type/source_class/origin_cell/round_index/display_name/value/highlight? + 特有字段 target/effect_id/pool_value) | 无来源行 = 断言失败;呈现侧禁按行序重演 B2 状态机 | 可回放步骤流(同种子逐行相同) | **引擎类型核验注记**:接口使用的引擎类型 = Resource / .tres(D2 全表)、RefCounted(容器类)、Signal/Callable(事件载体)、Control/CanvasLayer/Drawing(D1)、SceneTree headless 协议(测试)——均属 4.x 基线稳定面;4.7 Control 域增量(offset_transform_* 等)已在 breaking-changes.md 登记,D1 采纳前对照核实。 diff --git a/design/engineering/code-conventions.md b/design/engineering/code-conventions.md index 2777509b..508b9cc1 100644 --- a/design/engineering/code-conventions.md +++ b/design/engineering/code-conventions.md @@ -16,7 +16,7 @@ 设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。 ### 1.3 依赖单向,核心写调用完成 -依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);核心写接口(settle_batch / submit_window_selection / runner 推进)只允许在组合根出现。 +依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);核心写接口(settle_batch / player_request_refresh / runner 推进)只允许在组合根出现。 ### 1.4 命名 = 领域命名,禁止系统 ID 前缀 文件名与类名禁止 `a1_`/`b1_`/`c1_` 等系统 ID 前缀(`a1_board_generator.gd` → `board_generator.gd`)。设计追溯不靠前缀:代码↔设计的追溯由 GDD 文档承担,系统 ID 只作为文档的追溯锚;文件头注不承担追溯职责,不写任何文档链接(§1.4.1)。豁免:D2 schema 类与 autoload;文档/夹具登记名(如 b4_golden)属文档层。 diff --git a/design/gdd/systems/战斗循环/战斗结算.md b/design/gdd/systems/战斗循环/战斗结算.md index feaaf80a..402d55bd 100644 --- a/design/gdd/systems/战斗循环/战斗结算.md +++ b/design/gdd/systems/战斗循环/战斗结算.md @@ -70,7 +70,7 @@ ### 明细流水:每一行都能指回你刚才的哪一步棋 -结算过程中每一件事都写一行明细,每行标注来源——哪个安全格、哪处封印、哪颗雷、清图奖励。这份流水是结算明细屏(玩家逐行查看决策兑现结果的界面)的数据源,也是回放对账与数据导出共读的唯一契约。行型封闭为 9 类(2026-09-20 伏击上限删除批下线溢出未生效行),不允许私自增加;新增或下线行型属于行协议变更,必须走本文修订,并同步呈现层的行格式化。 +结算过程中每一件事都写一行明细,每行标注来源——哪个安全格、哪处封印、哪颗雷、清图奖励。这份流水是结算明细屏(玩家逐行查看决策兑现结果的界面)的数据源,也是回放对账与数据导出共读的唯一契约。行型分两层:**基础行型**封闭 9 类(下表),**扩展行** 1 类(专长经效果引擎插入的结算效果,见下节)。行型词表不允许私自增加;新增或下线行型属于行协议变更,必须走本文修订,并同步呈现层的行格式化。 | 行型 | 什么时候写 | |---|---| @@ -90,12 +90,20 @@ 第一层按行型豁免两类:衰减行(到期移除本就是段级动作,不属于任何一格)、判定行(它是胜负出口的结论,不是棋盘事实)。这两类连来源类别都不必填。 -第二层按来源类别豁免三类:主角攻击行的来源是主角单位本身,敌方行动行的来源是当时动手的那个敌人单位,清图奖励行的来源是"这张板被清掉"这一整板事实——它们都不指向某个棋盘格,来源格校验因此跳过。 +第二层按来源类别豁免,封闭清单五类:主角攻击行(来源是主角单位本身)、敌方行动行(来源是当时动手的那个敌人单位)、清图奖励行(来源是"这张板被清掉"这一整板事实)、专长揭示掷格行(落空行没有真实棋盘格可指)、专长 GP 入账行(来源是钱包面而非棋盘面)——它们都不指向某个棋盘格,来源格校验因此跳过。 豁免不等于免检:按行型豁免的行仍要带齐公共字段、守住各自的语义约束(如衰减行的数值必须是本次移除的读数),按来源类别豁免的行仍必须写明来源类别,其余行必须指回一个真实存在的棋盘格。豁免只是免掉"来源格必须有效"这一条校验,不是免掉整份行协议。 举证:本节为行协议约定,无计算。 +### 扩展行:专长插入的结算效果 + +基础 9 类写的是裸机制的账:玩家没有任何专长时,结算流水的每一行都出得了这九类。有了专长之后,效果引擎会在段内挂点插入额外的结算效果,这类效果写**扩展行**。扩展行是**一个**行型,不是每种专长效果各占一个行型——具体插的是哪种效果,由行携带的效果身份(effect_id 载荷)说明,呈现层按身份取各自的行文案。专长会不断增加、效果种类不可穷举,行型词表因此对扩展类封口:新增专长效果只新增载荷身份,不再新增行型。 + +扩展行与基础行共用同一套行协议:公共字段、来源归因、两层豁免、无来源即炸,全部照常生效。发射时点由段序骨架的挂点决定(时序与挂点施加面归架构文档「模块归属·战斗域装配现状」节),本节只管这行是什么、带什么字段。现行实现的扩展行型值以专长实名串承载,效果身份清单与发射点以实现侧 `battle_orchestrator.gd` 文件头注为准;收敛为单一扩展行型+效果载荷的条目在 [待办清单](../../../../待办清单.md) 在册。 + +举证:本节为行协议约定,无计算。 + ### 收益对照表:所有收益共用同一把尺子 开安全格给正向、封印标中给正向、踩雷与标错给负向、清图给清图奖励对象——来源不同、形态不同,但玩家必须能回答"挖这一格值不值",所以全部收益用一张效果档位对照表归一换算。折算单位是当量:1 当量等于 1 点主角生命的期望净变化。这张表是[行动经济](../排雷循环/行动经济.md)五条经济契约第一条"单一当量"的载体;本系统是全部五条契约的唯一对账责任方(契约本体见该文档,对账现状登记 [待办清单](../../../../待办清单.md))。 @@ -350,7 +358,7 @@ EV 参考数不入正文(派生读数,需要时按判定式与现行表值 - 关卡收束:关卡结束清空秘宝背包(关卡域库存——现行恒空的机械惰性承载,见「轮次生命周期」节注)恰一次并返回清空前计数;战斗结束不清背包。 - 可回放(封闭随机流口径):同种子同输入两遍步骤流逐位复现;随机消费仅限七处封闭随机流——开战掷骰(初始化随机)、技能摇号 `behavior_roll`(回合内、开轮时点、步骤流之外)、护甲等级掷点 `armor_roll`(回合内、步骤流之内)、奖励格摇号 `reward_roll`(初始化、装板期)、变异布置 `variant_place`(初始化、装板与资源预分配之后)、换板棋盘生成 `board_gen`(初始化、清图轮换板时点)、战斗结束掉落掷定 `gp_drop`(出口随机、战斗结束分支),无未登记随机源、零界面等待;单敌出招轨迹可独立复放、互不穿插。 - 无来源即炸:每行明细都能指回一个来源事实(棋盘格、单位、清图或段级结论);找不到来源即断言失败,行型与来源类别两层豁免清单见明细流水一节,豁免行仍受其它契约约束。 -- 行型封闭:流水只出现本文登记的 9 类行型;新增或下线行型必须走本文修订并同步呈现层行格式化,未登记行型禁止落行。 +- 行型封闭:流水行型只出现本文登记的基础 9 类与扩展行;行型词表改动必须走本文修订并同步呈现层行格式化,未登记行型禁止落行。 - 伤害单据管线(2026-09-24):全部伤害(主角先手、敌方伤害技、棋盘克制直伤、群伤、反噬、地形变异)经伤害控制器单据管线兑现,兑付配方封闭五种;目标在结账时刻照规则解析;死亡事件由单位自行宣布——怪死其未结单据作废(零行、不进冷却不进保底计数)、主角死兑付终止;段界结账为现行口径、开单即结为回切结构位,两模式各自同种子同输入逐位复现。 - 条款3 对账(2026-10-05 判式换代批 T3——与行动经济 F1 条款3 重立同步):①聚合健康式 (1−ρ̂)·E_dig(u) − ρ̂·V_mine(u) ≥ 0 与 β 比值带 [1.2, 2.5] 判读逐 u 检算(常设重跑入口 `tools/clear_dominance_audit.py`,读数快照归 registry clause3 重立条);②封印溢价兑付正确:封印标中正向兑付 = 同型正向 ×(1+δ)(δ 读 `settlement.tres` flag_hit_premium,100=无溢价直通零扰动),三类形态全覆盖(flat power / percent 幅度 / gp 缓冲)、标空与挖格兑付不乘溢价、危险格与安全格同池结构零触碰。 diff --git a/待办清单.md b/待办清单.md index 624e736b..e1cdb0b3 100644 --- a/待办清单.md +++ b/待办清单.md @@ -30,7 +30,7 @@ #### S6/S7/S8 静态规则落地——编排唯一性/禁 await/信号纪律三闸(2026-10-24 登记,来源=审计发现) -**实况**:工程债证据=reports/审计-game代码结构审查-2026-10-24.md §二 C2:三规则 static_scan.sh TODO 在案(架构文档静态扫描表自认未落地)——S6 core↔core 信号禁 lambda 捕获 self、S7 B2/B3/B4 API 符号命中文件 ⊆ B1 文件集、S8 结算路径 await 零命中。2026-10-24 审查人工 grep 结论干净(core 零 await、A2/B3/B4 零相互直调),但防线缺位=回归无闸。S7 前置:须先在架构文档成文 B1 文件集边界(含 core/settlement/ 五段类与 damage_controller——现归属表零条目,见「架构与规范对齐批」条目①)。**2026-10-24 用户裁:条目整条冻结待④(「架构与规范对齐批」)裁决后再写卡**——写卡会话核对结论:S6(core 信号禁 lambda)与 S8(结算路径禁 await,文件集可按现行结算文件直接枚举)与④零依赖、技术上可先行,但按「先裁④再动③」整条冻结不先行。 +**实况**:工程债证据=reports/审计-game代码结构审查-2026-10-24.md §二 C2:三规则 static_scan.sh TODO 在案(架构文档静态扫描表自认未落地)——S6 core↔core 信号禁 lambda 捕获 self、S7 B2/B3/B4 API 符号命中文件 ⊆ B1 文件集、S8 结算路径 await 零命中。2026-10-24 审查人工 grep 结论干净(core 零 await、A2/B3/B4 零相互直调),但防线缺位=回归无闸。S7 前置:须先在架构文档成文 B1 文件集边界(含 core/settlement/ 五段类与 damage_controller——现归属表零条目,见「架构与规范对齐批」条目①;2026-10-25 该前置已落文备齐,冻结状态不变)。**2026-10-24 用户裁:条目整条冻结待④(「架构与规范对齐批」)裁决后再写卡**——写卡会话核对结论:S6(core 信号禁 lambda)与 S8(结算路径禁 await,文件集可按现行结算文件直接枚举)与④零依赖、技术上可先行,但按「先裁④再动③」整条冻结不先行。 **改动面**:工具代码 @@ -40,7 +40,9 @@ **实况**:审计报告=reports/审计-game代码结构审查-2026-10-24.md(§二 C3/C4/C5+§三 漂移清单)。漂移与待裁件七件:①架构文档「模块归属」多行 API 清单与实现不符(A2 try_* 便捷形/B2 ambush_grant_plan/B4 equivalence_supply 不存在;实有 grant_reserve_ap/finish_round_stop/check_skill_unlocks 未登记;damage_controller 与 settlement/ 五段类零条目——S7 落地的前置);②code-conventions §1.3 核心写调用位置——三拆件控制器(presentation/curio_interact_controller.gd、camp_shop_presenter.gd、treasure_interact_controller.gd)持写调用 vs 规范「只允许在组合根出现」的 spec-AC 冲突,须裁「改规范成文组合根家族」vs「调用收回 main」;③A3→EffectEngine 反向依赖(core/action_economy.gd:43-49)——真违约或事实源失真二选一(effect_engine 降层登记基础层 vs B1 代发 vs 仅补登记);④架构文档 :149/151 层合同计数写死 17 项 vs LAYER_CONTRACT 实 18 项;⑤明细行协议三处三个数(头注 9/实发 13/架构文档 15);⑥§1.3 例举 submit_window_selection 符号已退役;⑦core/effect_engine.gd:360 校验文案「9 项」实为 18 项。 -**缺口**:一次 doc-design 会话逐点裁决(②③有方案取舍须用户拍板,①④⑤⑥⑦为机械对齐);裁决后走文档设计改动直改写入 design/engineering/。 +**2026-10-25 部分落文(用户令执行已裁件)**:⑤明细行协议两层化(基础 9 类+扩展行 1 类;文档只写概念与指引,效果身份清单指向实现侧 battle_orchestrator.gd 头注,专长实名串永不入文档词表)落战斗结算.md 明细流水节+验收标准+来源类别豁免封闭清单五类对齐;①归属表 API 对齐实现实况(A2 撤 try_* 便捷形换查询只读面、A3 补 grant_reserve_ap/finish_round_stop、B2 换 check_skill_unlocks、B4 撤 equivalence_supply、level_runner 撤幻影 grant_node_active)+damage_controller 与 settlement/ 五段段类两行入表+B1 域文件集成文(S7 判据来源已备);④层合同计数 17→18(实数核对);⑥§1.3 例举换代 player_request_refresh。凭据=architecture.md v1.10+战斗结算.md/code-conventions.md(本批 git 提交)。 + +**缺口**:②核心写调用位置(案甲改规范成文「组合根家族=main+三拆件控制器」vs 案乙调用经回调收口回 main——乙涉游戏代码须转需求通道)与③A3→EffectEngine 反向依赖(案 a effect_engine 降登记基础层 vs 案 b B1 代发改码 vs 案 c 仅补登记消费依赖)两裁决点待用户拍板,裁后落文闭合条目;⑦校验文案改数属游戏代码字符串修订,归需求改动通道随卡顺带。 **改动面**:文档