并master(迭代56收尾区): 解待办清单头部登记区冲突——保留master侧架构文档收敛第二批条目+本区两条过程发现登记(QQ-12写卡批与架构收敛批先后并入); 融合后核验: 反哺落文九处完好+README:184回表在位+版本行v2.0在位; 凭据: --docs【验收通过】无新增红
This commit is contained in:
commit
8a5c71eb8f
30 files changed
+292
-176
No files matched your search
@@ -48,7 +48,7 @@
|
||||
| 定文档方案 / 写文档 / 改文档前 | `design/engineering/doc-conventions.md`——白话写作 / 载体分工 / 用语 / 结构骨架 / 会话记录与生命周期 |
|
||||
| 概念切分与互链 | `design/engineering/concept-conventions.md`——概念封装 / 跨文档引用 / 归档与事实源 |
|
||||
| 系统设计 / 增删文档 | `design/gdd/02-系统清单.md`——根索引 + 中文规范名↔英文代号对照 |
|
||||
| 架构(唯一事实源) | `design/engineering/architecture/architecture.md`(只写约束面:分层/模块归属/数据流/API 边界;实现现状归代码与头注,闸清单归 `game/tests/README.md`)——历史决策沿革查 git commit log,不另设决策文档;修订须用户发令 |
|
||||
| 架构(唯一事实源) | `design/engineering/architecture/architecture.md`(只写依赖规则面:分层/目录归属/数据流/架构原则;模块级归属归代码头注,闸清单归 `game/tests/README.md`)——历史决策沿革查 git commit log,不另设决策文档;修订须用户发令 |
|
||||
| 术语与已锁数值 | 规范名与定义 = `design/gdd/术语表.md`(全库唯一对照表,仅 owner 文档可修订);现行数值 = `game/data/tables/*.tres`;规则(概念面)= 各系统 owner 文档;取值域与字段契约 = `game/data/schemas/*.gd`。冲突须显式提出,禁默默改值 |
|
||||
| 现在做什么 / 待办与待裁 | 根 `roadmap.md` 顶部「当前位」节+迭代总表六列 · 待办唯一登记处 `待办清单.md` · 批次过程与结论查 git 提交信息与 `reports/` |
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
- 文件头 = `##` 文档注释,介绍本模块是什么;禁写变更叙事(改动史查 git log);禁文档反向链接(code-conventions §1.4.1)
|
||||
- 数值单一事实源——玩法数值只存 `data/tables/`(.tres)经 ConfigDB 单点读取;禁数值字面量与自建 `load()` 表路径
|
||||
- RNG 单点——禁 `randomize()`/自建 RandomNumberGenerator,随机只经 `RngService` 统一流
|
||||
- 架构事实唯一源——架构事实只认 `design/engineering/architecture/architecture.md`(只写约束面:分层/模块归属/数据流/API 边界;实现现状归代码与头注);禁立第二架构文档或决策文档体系,历史决策记录只进 git commit log;架构文档写权限=用户专属,agent 与技能只读(2026-11-07 用户裁)
|
||||
- 架构事实唯一源——架构事实只认 `design/engineering/architecture/architecture.md`(只写依赖规则面:分层/目录归属/数据流/架构原则;模块级归属归代码头注);禁立第二架构文档或决策文档体系,历史决策记录只进 git commit log;架构文档写权限=用户专属,agent 与技能只读(2026-11-07 用户裁)
|
||||
- Core 层零 UI 依赖——完整战斗必须可 `--headless --script` 跑通;fail-fast——数据校验错误一律致命中止,无软回退
|
||||
- spec-AC 一致性——规约与验收标准禁止在同一输入上给出不同答案;评审隔离——`/design-review` 必须独立会话跑(与 `/design-system` 隔离)
|
||||
- 像素结构件——先抄后造、验收写成像素级判据、±1px 坐标推导(process-conventions 第 7 节)
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
## 文档状态
|
||||
|
||||
- 版本:2.0(收窄为约束面形态——分层/模块归属/数据流/API 边界;实现现状归代码与代码头注,实现历史归 git commit log,闸清单与判定口径归 `game/tests/README.md`,见 doc-conventions「架构事实唯一源」行)
|
||||
- 版本:3.0(依赖规则形态——分层/目录归属/数据流/原则;模块级归属登记与模块对接口契约均不进本文:前者归代码文件头注,后者规范源单点=各系统 GDD、执法=静态扫描域与契约测试)
|
||||
- 引擎:Godot 4.7.2-stable(GDScript 单语言;2026-09-07 锁定)
|
||||
- 评审模式:solo(`review-mode.txt`——门禁按 solo 跳过)
|
||||
- 覆盖 GDD:现行全集(根索引=`design/gdd/02-系统清单.md`,文档树构成以根索引为准)
|
||||
- 事实源地位:本文是架构约束的唯一权威(分层/模块归属/数据流/API 边界);写权限=用户专属(agent 与技能只读)
|
||||
- 事实源地位:本文是架构约束的唯一权威(分层/目录归属/数据流/架构原则);写权限=用户专属(agent 与技能只读)
|
||||
- 实现实证:`game/`(完整游戏开发版本;本文分层与所有权经实现验证)。测试层级=冒烟/单元/系统三级+UI 探针与渲染 golden,识别三元组权威=`design/engineering/test-conventions.md`「测试层三元组」节
|
||||
|
||||
---
|
||||
@@ -74,66 +74,19 @@
|
||||
|
||||
---
|
||||
|
||||
## 模块归属
|
||||
## 目录归属
|
||||
|
||||
> 命名遵循 `design/engineering/code-conventions.md`:领域命名、禁 ID 前缀。本表只写约束:模块的职责语句、对外封闭面概述与消费依赖——各件的完整公开方法面、成员与接线明细归代码文件头注(`##` 文档注释)与代码自身承载;文件路径是导航索引。
|
||||
> 目录=层级的物理承载:同一目录内的文件同层级、同受该层约束属性管辖,职责各自独立、归各文件头注(`##` 文档注释)承载;领域不做目录切分,仅当领域大到内部再需要一层时才立子目录。命名遵循 `design/engineering/code-conventions.md`:领域命名、禁 ID 前缀。逻辑依赖层级(基础/核心/功能/呈现)见「系统分层图」——`game/core/` 一目录内按依赖层级再分三段,层级约束由分层图与架构原则承载,目录不再切分。
|
||||
|
||||
### 基础层
|
||||
|
||||
| 模块 | 文件 | 独占职责 | 对外封闭面 | 消费依赖 |
|
||||
|---|---|---|---|---|
|
||||
| **ConfigDB**(autoload,D2) | `game/core/config_db.gd` | 全部玩法数值表唯一加载与持有单点(`.tres` 经校验后入容器);行族访问器归各 schema 表类(表管自己的行查询),本类只留加载/校验/override/诊断门面,表持有按域收进域容器 Resource | 类型化域容器属性+load_tables / reload / set_reload_gate / diagnostics 族 | 无(基础层顶点) |
|
||||
| **RngService**(autoload,D2) | `game/core/rng_service.gd` | master_seed 与各封闭流 scope 计数器单点(封闭流词表现值以 `RngServiceCore.PURPOSE_TAGS` 为准,增流走 P1 评审) | set_master_seed(唯一调用方 C2)/ open_stream 有状态门面 / derive_at 纯函数 / 只读计数器 | 无 |
|
||||
| **save_system**(SaveManager,autoload,D3) | `game/core/save_manager.gd` | 存档格式与版本比较、序列化接线单点;槽位文件域归 SlotStore、元进度数据归 MetaStateStore | 写盘/读回/槽位管理/断点快照公开面(契约规范源:`../../gdd/systems/表现与支撑/存档序列化.md`——契约锚:SAVE_FORMAT_VERSION + master_seed + 各流 scope 计数器快照) | ConfigDB、RngService 只读计数器 |
|
||||
| **SlotStore**(D3) | `game/core/slot_store.gd` | 存档三槽位文件域唯一所有者:槽位挂载与模板、激活与建删、摘要窥视 | 槽位读写原语族+摘要投影 | save_manager(注入路径与模板配置) |
|
||||
| **MetaStateStore**(D3) | `game/core/meta_state_store.gd` | 存档内元进度数据的读写唯一层(数据读写原语,不含业务规则) | 写口原语族+只读投影(消费方经 `save.meta_state.` 直连) | save_manager(序列化接线) |
|
||||
| **MetaProgression**(autoload,C4) | `game/core/meta_progression.gd` | 元进度账本服务:钥石收束入账、营地消费定价与解锁判定的纯被动服务,零信号零外发;业务层(数据读写全经 MetaStateStore) | 写口族(天赋树/锻造/同调)+解锁判定与读投影;四个 Autoload 中唯一有跨 Autoload 依赖(ConfigDB/SaveManager) | ConfigDB、SaveManager |
|
||||
| **action_economy**(A3) | `game/core/action_economy.gd` | AP/RAP 账本、轮次相位机 {Idle, Active, Waiting}、结束仲裁 | 意图与通知布尔面(request_dig / request_stop / request_refresh / notify_* 族)+预授权通道;ap/rap/phase 只读 | ConfigDB、EffectPort、B1 回发 |
|
||||
| **variation**(A4) | `game/core/variation*.gd` | VariationTable schema 与 F1 候选池门控谓词 | variant_pool(门控三维)/ global_variant_row 访问器 | ConfigDB |
|
||||
| **status_container**(B3) | `game/core/status_container.gd` | 状态实例容器(战斗域生命周期、跨轮跨图延续) | 五 API:notify_battle_start / apply_effect / query_active / decay_round / notify_battle_end | ConfigDB |
|
||||
| **effect_engine** | `game/core/effect_engine.gd` | 零运行时可变状态的全同步解释器(架构原则 8):事件由宿主在明确代码点位显式 dispatch 进件,命中序=装载声明序,不是事件总线/事件循环 | rebuild / dispatch / validate_trigger_row +静态计数口;事件/事实/效果类型/算子四词表封闭+树规则合成订阅六键 | ConfigDB 行集、EffectContext 引用束(四桶由宿主持有) |
|
||||
| **settings/localization**(D6,愿景) | — | 设置项、翻译数据 | (契约规范源:`../../gdd/systems/表现与支撑/设置与本地化.md`) | ConfigDB |
|
||||
|
||||
### 核心层
|
||||
|
||||
| 模块 | 文件 | 独占职责 | 对外封闭面 | 消费依赖 |
|
||||
|---|---|---|---|---|
|
||||
| **board_generator**(A1) | `game/core/board_generator.gd` | 生成算法(五阶段管线)、合法性谓词(clearable / R₀≠S / min_safe)、可推理率度量;生成姿态=MVP 同步生成+加载幕(WorkerThread 留扩展) | `generate(L, D, rng) -> Board`;度量独立入口 | ConfigDB;board_gen 封闭流(一次 open_stream=一张图) |
|
||||
| **minesweeper_rules**(A2) | `game/core/minesweeper_rules.gd` | 棋盘状态(已开集/封印集/小人位)、批次仲裁、install 四不变式 | `install_board` / `settle_batch`(唯一提交入口)/ 查询只读面 / preview_reveal 只读预览口 / retire_board;三事件封闭(cell_revealed / flag_judged / round_end,payload 字段封闭) | A1 Board 契约(class_name 数据契约);A3 try_spend |
|
||||
| **unit_container**(B2) | `game/core/unit_container.gd` | hero/enemy 单位实例(hp/atk/实例池) | spawn / query_alive / 动作与伤害面 | ConfigDB |
|
||||
| **reward_economy**(B4) | `game/core/reward_economy.gd` | 格面资源身份映射(install 期预分配、换图映射消亡)、极性路由字典面、受理账面(装配期摇号归掷格件 RewardRoller) | 封闭 API:roll_board / query_identity / grant / grant_clear / retire_mapping / polarity_row / phase | ConfigDB;BattleFxHost 偏运合计查询(注入 Callable) |
|
||||
| **helper_items**(A5) | `game/core/helper_items*.gd` | HelperItemTable、探测显影语义 | (契约规范源:`../../gdd/systems/跨局循环/秘宝.md`——桥接位:A2 查询接口+A4 counter_item_ids) | A2 / A4 / B4 |
|
||||
| **CurioDeck**(A5) | `game/core/curio_deck.gd` | 三选一/商店共享令牌池、抽签、cap 库存与专长凭证判定唯一所有者(停点编排与兑付推进留 CurioStop) | draw_candidates 抽签 / consume 族池消耗 / cap_ok / 凭证判定 / stock 只读投影 | ConfigDB;注入 RngServiceCore(reward_pick 封闭流) |
|
||||
| **ShopSession** | `game/core/shop_session.gd` | 关卡商店双模式(legacy 固定三件/pool 共享令牌池)的货架、定价、购买与刷新唯一宿主;账本/钱包经宿主 LevelRunner 注入共享引用 | 货架与定价只读面+写入口;调用方经宿主公开成员 `shop` 直连 | ConfigDB;注入 RngServiceCore;pool 模式经注入 Callable 转 CurioDeck |
|
||||
| **HeroStats** | `game/core/hero_stats.gd` | 冒险生命周期主角数值域唯一所有者:生命账与特性持有集、生效公式单点 | 构造注入;单写原语族+只读投影 | ConfigDB;注入 GainJournal(只读);AdventureRunner 创建 |
|
||||
| **GainJournal** | `game/core/gain_journal.gd` | 统一冒险加算区与获得记录唯一所有者(三层结构:记录→明细→四轴汇总) | gain_bonus 单写原语;记录与汇总只读投影 | AdventureRunner 创建,注入各消费方 |
|
||||
| **GpWallet** | `game/core/gp_wallet.gd` | 冒险局内货币唯一所有者(不入存档不入摘要) | gain / spend / clear 单写原语 | AdventureRunner 创建,宿主与商店注入读写 |
|
||||
| **RefreshBank** | `game/core/refresh_bank.gd` | 三选一刷新三源账唯一所有者+GP 付费刷报价公式(零停点态依赖,编排归 CurioStop) | 支出与余量原语+报价公式;断点自交片段(refresh_stock / attune_refresh_y) | ConfigDB;注入 CurioStop 支出路径 |
|
||||
| **AttuneLoadout** | `game/core/attune_loadout.gd` | 装备中的秘宝件对象集与同调充能唯一所有者(种行/补行改写时同步) | 构造注入;充能查询/消耗/按周期重置原语 | ConfigDB;TreasureItems 投放面;注入使用路径 |
|
||||
| **CurioStop** | `game/core/curio_stop.gd` | 三选一停点编排唯一所有者(架构原则 9 本域承载):停点三态、刷新编排、兑付方法族、零自动推进语义 | 开停点/刷新/兑付/放行谓词/交断点片段五组入口+信号面(curio_choice_presented / curio_resolved) | ConfigDB;注入 CurioDeck、HeroStats、GainJournal、RefreshBank |
|
||||
| **breakpoint_store** | `game/core/breakpoint_store.gd` | 存档断点组装与回放唯一承载:断点快照拼盘、回放回填、读侧策略分发 | `BREAKPOINT_FIELDS` 键登记单源(键名/策略标签/键序冻结) | 注入引用束 |
|
||||
|
||||
### 功能层
|
||||
|
||||
| 模块 | 文件 | 独占职责 | 对外封闭面 | 消费依赖 |
|
||||
|---|---|---|---|---|
|
||||
| **battle_orchestrator**(B1,域文件集=编排器+`settlement/` 五段段类+其拆件:BattleFxHost / RewardGrant / DamageController / BattleRefreshFlow / BoardInstaller / RoundCycle / BattleFacts / EffectPort / RewardRoller) | `game/core/battle_orchestrator.gd` 等 | 战斗域编排唯一宿主:战斗状态机与生命周期、A2 三事件订阅、结算五段驱动(授予/增益减益/战斗/衰减/判定,段序冻结于 SettlementTable.segment_order)、行发射基建、呈现投影;**战斗域全部跨系统调用权集中本域**(静态扫描域 S7 执法,文件集清单单点=`game/tests/static_scan.sh`) | `begin_battle(encounter)`;窗口/刷新意图提交面;`level_clear()`;步骤流(输出契约);[明细行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋) | B2/B3/B4 全调用面;A2 订阅;A1 generate;A3 代理+回发;D2 SettlementTable |
|
||||
| **level_runner**(C1) | `game/core/level_runner.gd` | 关卡域生命周期:节点链推进、共享 B4、HP 携带、关卡末 level_clear;依赖构造注入一次给齐 | 节点推进接口;LevelTable(ConfigDB 跨表校验) | B1(直构接线战斗)、ConfigDB |
|
||||
| **run_structure**(C2) | — | 冒险/关卡序列、失败重开、**master_seed 唯一接线方** | (契约规范源:`../../gdd/systems/冒险循环/冒险结构.md`) | RngService.set_master_seed、C3/D2 |
|
||||
| **difficulty**(C3) | — | DifficultyTable 回填、全部曲线数值调参所有权、战斗期望表 | 调参输出(经 D2 解析传递,禁反向调用生成) | ConfigDB、B1 对账输出、A1 报告 |
|
||||
| **meta_progression**(C4,业务层) | `game/core/meta_progression.gd` | MetaTable、钥石账本、天赋树域、同调位槽位判定(业务规则与写口编排;数据原语归 MetaStateStore) | tree_* / forge_* / attune_* / settle_adventure / hero_override 族 | MetaStateStore、ConfigDB |
|
||||
|
||||
### 呈现层
|
||||
|
||||
| 模块 | 文件 | 独占职责 | 对外封闭面 | 消费依赖 |
|
||||
|---|---|---|---|---|
|
||||
| **D1 HUD** | `game/presentation/main.gd`(组合根)+三屏壳+`views/` 视图单元族+`ui_registry.gd` | 全部 Control/CanvasLayer;输入→意图翻译(**唯一提交路径=settle_batch,不直调 A3**);组合根=信号接线与核心写调用唯一出口;views/ 各域呈现拆件的职责与接口归各件头注 | 组合根公开服务面与注册面句柄寻址合同(`main.ui.<域容器>.<句柄>`)归 main.gd / ui_registry.gd 头注承载 | A2 compute_move_path;A3 只读;B1 步骤流;ConfigDB display_name;**MEDIUM**:Control/CanvasLayer/draw_*/InputEvent/RichTextLabel |
|
||||
| **组合根拆件** | `game/presentation/*_controller.gd` / `camp_shop_presenter.gd` | 代组合根执行核心写调用(冒险节点推进/营地购买与刷新/道具使用) | 各拆件写入口(仅组合根装配面可达;视图零直连) | 构造注入的核心写引用 |
|
||||
| **HudPresenter** | `game/presentation/hud_presenter.gd` | 战斗屏数据投影+文案拼装静态族(核心状态→呈现文案的全部翻译集中于此) | refresh 全量重查装配+只读静态投影族 | 只走 `settlement.presentation_snapshot()` 成文快照面(禁链式穿透) |
|
||||
| **board_resolvers** | `game/presentation/board_resolvers.gd` | 棋盘每格渲染数据只读解析回调四函数(与无态静态投影族职责互斥) | 构造注入产出绑定 Callable 供组合根接线 | ConfigDB / 结算活态取值 Callable |
|
||||
| **battle_presentation**(B5,垂直切片后) | — | 结算动画 / 伤害数字 / 战斗舞台 | (契约规范源:`../../gdd/systems/战斗循环/战斗表现.md`——前置「战斗表现美术测试」锁双舞台陷阱) | B1 步骤流、D1;**MEDIUM**:AnimationPlayer/Tween |
|
||||
| **audio**(D4,Alpha) | — | 音频挂点 | 挂点=B1 明细行类型流(负反馈聚合——单结算至多一次) | B1 流水 |
|
||||
| **tutorial**(D5,Alpha) | — | 教学条目 | 口径来源=A2/A3/B3/B1 各教学条目 | 各上游 |
|
||||
| 目录 | 层级作用 | 该层约束属性 |
|
||||
|---|---|---|
|
||||
| `game/core/` | 全部玩法逻辑的承载(配置、RNG、存档域件、棋盘生成、排雷规则、经济与账本、效果引擎、战斗编排、关卡与冒险域件)——依赖逻辑层级内分基础/核心/功能三段,见分层图 | 纯逻辑:零 Control/场景引用、构造注入、fail-fast、`--headless --script` 完整可跑、玩法数值零字面量(读 `game/data/tables`)、随机只经封闭流 |
|
||||
| `game/core/settlement/` | 领域子目录——战斗结算五段段件(领域大到内部再需要一层时切分的在案先例) | 同 core;段类可直接 new() 单测、段类对编排器零引用 |
|
||||
| `game/presentation/` | 呈现层——全部 Control/CanvasLayer、输入→意图翻译、组合根装配 | 视图零核心写调用(信号外发为主)、组合根=核心写调用唯一出口、呈现数据只走成文快照面;引擎风险域对照 breaking-changes |
|
||||
| `game/data/` | 数据承载——玩法数值表(tables/*.tres)与字段契约(schemas/*.gd),对应基础层 D2 数据配置 | 数值单一事实源;表值直接改变游戏运行结果 |
|
||||
| `game/tests/` | 测试域——冒烟/单元/系统三闸承载 | 依赖只经 autoload 边界与场景契约两类入口;禁反向依赖呈现层实现内部 |
|
||||
| `game/probe/` | 探针域——场景级探针与取证探针 | 同测试域边界;在闸件与手动测量件两分 |
|
||||
| `game/sim/` | 测量域——MC/调参/数值验证驱动件 | 不入 CI、用户手动发起、随机显式定种 |
|
||||
|
||||
**依赖单向性**:上层可消费下层,禁止反向(C3 禁调用 A1 生成、D1 不直调 A3、A2/B3/B4 零相互直调)。全项目唯一回边=A2 事件订阅面。
|
||||
|
||||
@@ -190,7 +143,7 @@
|
||||
1. **autoload 边界**——ConfigDB / RngService 的公开面(--script 模式不加载 autoload 且不注册全局标识符,测试文件自带显式实例化夹具);
|
||||
2. **场景契约**——探针场景的信号外发面与视图单元接口(信号外发、setter 只读注入),禁直引呈现层实现内部。
|
||||
|
||||
测试域是所有层的消费方,进入方式限于上述两类边界;除此之外的依赖方向一律与「模块归属」节依赖单向性同规。
|
||||
测试域是所有层的消费方,进入方式限于上述两类边界;除此之外的依赖方向一律与「目录归属」节依赖单向性同规。
|
||||
|
||||
---
|
||||
|
||||
@@ -253,28 +206,6 @@ CJK 字体随包发行并设为 theme 默认字体——运行时默认字体无
|
||||
4. 续玩钮可见态恒等于断点在档态(双向)。
|
||||
5. 闲时会话已在树(`run_scope` 永非 null 契约的启动侧证明)。
|
||||
6. 调试浮窗 boot 不自动开(菜单优先)+调试入口全局浮层角标 boot 可见。
|
||||
|
||||
---
|
||||
|
||||
## API 边界
|
||||
|
||||
> 完整 API 面(含封闭枚举负空间、布尔受理口径、输入×相位矩阵)以各 GDD AC 前言为**规范源**——本节列边界契约与不变式,实现须与 GDD 逐字一致;冲突时以 GDD 为准并走接口漂移修订。
|
||||
|
||||
| 边界 | 契约要点 | 调用方必须遵守的不变式 | 模块保证 |
|
||||
|---|---|---|---|
|
||||
| D1 → A2 | 意图经 `settle_batch(intents)` 提交;不直调 A3 | 单意图帧收集;stop 经批次委托 | 语义序仲裁 + voided 零副作用 |
|
||||
| A2 → A3 | 挖/插/拔=先棋盘面判定后 `try_spend`;A2 不可自行扣减 | 相位判定两侧一致(同一矩阵) | 原子事务(余量+扣减+仲裁一体) |
|
||||
| A2 → 下游 | 只外发三事件,payload 字段封闭(digit 恒真透传 / reward_eligible / variant_ids) | 增删事件=接口漂移 | 发射面封闭 + 规范序 |
|
||||
| B1 → B2/B3/B4 | 全调用面集中 B1;调用序钉死(按摇定技能行兑现→apply_damage→commit_action;先兑付后衰减;段内伤害序=主角先手→逐敌还手→地图账殿后) | 禁第二调用方(静态扫描域 S7:API 符号命中文件 ⊆ B1 文件集) | 恰一次编排纪律(roll_board/decay/清理全序) |
|
||||
| B1 ↔ A3 | 编排期代理 `request_refresh`(玩家意图,禁 RAP 满自动刷);回发 next_round_mode/battle_over | stopped/ap_exhausted 未刷新回发 new_board=违约 fail-fast | 刷新受理契约(同 Waiting 多次合法) |
|
||||
| 各系统 → D2 | ConfigDB 类型化属性单点读取 | 禁绕过 ConfigDB load 表、禁缓存副本、禁玩法数值字面量、禁 randomize()/自建 RNG | 校验双通道 + fail-fast 致命 |
|
||||
| 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#明细流水每一行都能指回你刚才的哪一步棋)(基础行型+扩展行两层封闭 + 公共字段 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 域增量已在 breaking-changes.md 登记,D1 采纳前对照核实。
|
||||
|
||||
---
|
||||
|
||||
## 架构原则
|
||||
|
||||
@@ -5160,7 +5160,7 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
<rect data-graph-role="structural-frame" data-composition-frame-kind="region" data-composition-frame-id="1" data-composition-frame-label="浮层与对话框(组合根挂载)" x="90" y="390" width="1060" height="106" rx="12" class="c-region" stroke-width="1"/>
|
||||
|
||||
<rect data-graph-role="structural-frame" data-composition-frame-kind="region" data-composition-frame-id="2" data-composition-frame-label="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" x="66" y="524" width="1226" height="222" rx="12" class="c-region" stroke-width="1"/>
|
||||
<rect data-graph-role="structural-frame" data-composition-frame-kind="region" data-composition-frame-id="2" data-composition-frame-label="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" x="66" y="524" width="1226" height="222" rx="12" class="c-region" stroke-width="1"/>
|
||||
|
||||
<!-- Connection paths (before components for correct z-order) -->
|
||||
<path data-edge-from="main" data-edge-to="stage" data-edge-key="0" data-edge-id="main-stage" data-composition-points="566,132;566,196;125,196;125,260" d="M 566 132 L 566 188 Q 566 196 558 196 L 133 196 Q 125 196 125 204 L 125 260" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
|
||||
@@ -5390,8 +5390,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="fine" x="1044" y="468" class="t-frontend" font-size="7" text-anchor="middle">debug_overlay.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-save" data-node-id="save" data-node-label="存档管理" tabindex="0" role="button" aria-label="聚焦存档管理,save_manager.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="save_manager.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>存档管理 · save_manager.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-save" data-node-id="save" data-node-label="存档管理" tabindex="0" role="button" aria-label="聚焦存档管理,save_manager.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="save_manager.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>存档管理 · save_manager.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="96" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="96" y="554" width="130" height="48" rx="6" class="c-database" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="database" class="semantic-sigil s-database" transform="translate(102 560) scale(0.6875)">
|
||||
@@ -5402,8 +5402,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="161" y="592" class="t-muted" font-size="9" text-anchor="middle">save_manager.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-meta" data-node-id="meta" data-node-label="元进度" tabindex="0" role="button" aria-label="聚焦元进度,meta_progression.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="meta_progression.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>元进度 · meta_progression.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-meta" data-node-id="meta" data-node-label="元进度" tabindex="0" role="button" aria-label="聚焦元进度,meta_progression.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="meta_progression.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>元进度 · meta_progression.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="244" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="244" y="554" width="130" height="48" rx="6" class="c-database" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="database" class="semantic-sigil s-database" transform="translate(250 560) scale(0.6875)">
|
||||
@@ -5414,8 +5414,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="309" y="592" class="t-muted" font-size="9" text-anchor="middle">meta_progression.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-orch" data-node-id="orch" data-node-label="战斗编排器" tabindex="0" role="button" aria-label="聚焦战斗编排器,battle_orchestrator.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="battle_orchestrator.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>战斗编排器 · battle_orchestrator.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-orch" data-node-id="orch" data-node-label="战斗编排器" tabindex="0" role="button" aria-label="聚焦战斗编排器,battle_orchestrator.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="battle_orchestrator.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>战斗编排器 · battle_orchestrator.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="383" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="383" y="554" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(389 560) scale(0.6875)">
|
||||
@@ -5425,8 +5425,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="448" y="592" class="t-muted" font-size="9" text-anchor="middle">battle_orchestrator.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-rules" data-node-id="rules" data-node-label="扫雷规则" tabindex="0" role="button" aria-label="聚焦扫雷规则,minesweeper_rules.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="minesweeper_rules.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>扫雷规则 · minesweeper_rules.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-rules" data-node-id="rules" data-node-label="扫雷规则" tabindex="0" role="button" aria-label="聚焦扫雷规则,minesweeper_rules.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="minesweeper_rules.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>扫雷规则 · minesweeper_rules.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="540" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="540" y="554" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(546 560) scale(0.6875)">
|
||||
@@ -5436,8 +5436,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="605" y="592" class="t-muted" font-size="9" text-anchor="middle">minesweeper_rules.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-boardgen" data-node-id="boardgen" data-node-label="棋盘生成" tabindex="0" role="button" aria-label="聚焦棋盘生成,board_generator.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="board_generator.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>棋盘生成 · board_generator.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-boardgen" data-node-id="boardgen" data-node-label="棋盘生成" tabindex="0" role="button" aria-label="聚焦棋盘生成,board_generator.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="board_generator.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>棋盘生成 · board_generator.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="688" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="688" y="554" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(694 560) scale(0.6875)">
|
||||
@@ -5447,8 +5447,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="753" y="592" class="t-muted" font-size="9" text-anchor="middle">board_generator.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-boarddata" data-node-id="boarddata" data-node-label="棋盘数据" tabindex="0" role="button" aria-label="聚焦棋盘数据,board_data.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="board_data.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>棋盘数据 · board_data.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-boarddata" data-node-id="boarddata" data-node-label="棋盘数据" tabindex="0" role="button" aria-label="聚焦棋盘数据,board_data.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="board_data.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>棋盘数据 · board_data.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="836" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="836" y="554" width="130" height="48" rx="6" class="c-database" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="database" class="semantic-sigil s-database" transform="translate(842 560) scale(0.6875)">
|
||||
@@ -5459,8 +5459,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="901" y="592" class="t-muted" font-size="9" text-anchor="middle">board_data.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-effects" data-node-id="effects" data-node-label="效果引擎" tabindex="0" role="button" aria-label="聚焦效果引擎,effect_engine.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="effect_engine.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>效果引擎 · effect_engine.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-effects" data-node-id="effects" data-node-label="效果引擎" tabindex="0" role="button" aria-label="聚焦效果引擎,effect_engine.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="effect_engine.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>效果引擎 · effect_engine.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="984" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="984" y="554" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(990 560) scale(0.6875)">
|
||||
@@ -5470,8 +5470,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="1049" y="592" class="t-muted" font-size="9" text-anchor="middle">effect_engine.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-adventure" data-node-id="adventure" data-node-label="冒险运行器" tabindex="0" role="button" aria-label="聚焦冒险运行器,adventure_runner.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="adventure_runner.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>冒险运行器 · adventure_runner.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-adventure" data-node-id="adventure" data-node-label="冒险运行器" tabindex="0" role="button" aria-label="聚焦冒险运行器,adventure_runner.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="adventure_runner.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>冒险运行器 · adventure_runner.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="1132" y="554" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="1132" y="554" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(1138 560) scale(0.6875)">
|
||||
@@ -5481,8 +5481,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="1197" y="592" class="t-muted" font-size="9" text-anchor="middle">adventure_runner.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-levelrun" data-node-id="levelrun" data-node-label="关卡运行器" tabindex="0" role="button" aria-label="聚焦关卡运行器,level_runner.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="level_runner.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>关卡运行器 · level_runner.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-levelrun" data-node-id="levelrun" data-node-label="关卡运行器" tabindex="0" role="button" aria-label="聚焦关卡运行器,level_runner.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="level_runner.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>关卡运行器 · level_runner.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="96" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="96" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(102 622) scale(0.6875)">
|
||||
@@ -5492,8 +5492,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="161" y="654" class="t-muted" font-size="9" text-anchor="middle">level_runner.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-dmgctl" data-node-id="dmgctl" data-node-label="伤害控制" tabindex="0" role="button" aria-label="聚焦伤害控制,damage_controller.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="damage_controller.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>伤害控制 · damage_controller.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-dmgctl" data-node-id="dmgctl" data-node-label="伤害控制" tabindex="0" role="button" aria-label="聚焦伤害控制,damage_controller.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="damage_controller.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>伤害控制 · damage_controller.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="244" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="244" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(250 622) scale(0.6875)">
|
||||
@@ -5503,8 +5503,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="309" y="654" class="t-muted" font-size="9" text-anchor="middle">damage_controller.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-dgmath" data-node-id="dgmath" data-node-label="伤害公式" tabindex="0" role="button" aria-label="聚焦伤害公式,damage_math.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="damage_math.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>伤害公式 · damage_math.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-dgmath" data-node-id="dgmath" data-node-label="伤害公式" tabindex="0" role="button" aria-label="聚焦伤害公式,damage_math.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="damage_math.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>伤害公式 · damage_math.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="392" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="392" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(398 622) scale(0.6875)">
|
||||
@@ -5514,8 +5514,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="457" y="654" class="t-muted" font-size="9" text-anchor="middle">damage_math.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-reward" data-node-id="reward" data-node-label="奖励经济" tabindex="0" role="button" aria-label="聚焦奖励经济,reward_economy.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="reward_economy.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>奖励经济 · reward_economy.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-reward" data-node-id="reward" data-node-label="奖励经济" tabindex="0" role="button" aria-label="聚焦奖励经济,reward_economy.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="reward_economy.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>奖励经济 · reward_economy.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="540" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="540" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(546 622) scale(0.6875)">
|
||||
@@ -5525,8 +5525,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="605" y="654" class="t-muted" font-size="9" text-anchor="middle">reward_economy.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-lottery" data-node-id="lottery" data-node-label="技能抽奖" tabindex="0" role="button" aria-label="聚焦技能抽奖,skill_lottery.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="skill_lottery.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>技能抽奖 · skill_lottery.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-lottery" data-node-id="lottery" data-node-label="技能抽奖" tabindex="0" role="button" aria-label="聚焦技能抽奖,skill_lottery.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="skill_lottery.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>技能抽奖 · skill_lottery.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="688" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="688" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(694 622) scale(0.6875)">
|
||||
@@ -5536,8 +5536,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="753" y="654" class="t-muted" font-size="9" text-anchor="middle">skill_lottery.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-attune" data-node-id="attune" data-node-label="同调" tabindex="0" role="button" aria-label="聚焦同调,attunement.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="attunement.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>同调 · attunement.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-attune" data-node-id="attune" data-node-label="同调" tabindex="0" role="button" aria-label="聚焦同调,attunement.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="attunement.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>同调 · attunement.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="836" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="836" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(842 622) scale(0.6875)">
|
||||
@@ -5547,8 +5547,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="901" y="654" class="t-muted" font-size="9" text-anchor="middle">attunement.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-action" data-node-id="action" data-node-label="行动经济" tabindex="0" role="button" aria-label="聚焦行动经济,action_economy.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="action_economy.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>行动经济 · action_economy.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-action" data-node-id="action" data-node-label="行动经济" tabindex="0" role="button" aria-label="聚焦行动经济,action_economy.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="action_economy.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>行动经济 · action_economy.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="984" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="984" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(990 622) scale(0.6875)">
|
||||
@@ -5558,8 +5558,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="1049" y="654" class="t-muted" font-size="9" text-anchor="middle">action_economy.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-feats" data-node-id="feats" data-node-label="特长引擎" tabindex="0" role="button" aria-label="聚焦特长引擎,feats_engine.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="feats_engine.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>特长引擎 · feats_engine.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-feats" data-node-id="feats" data-node-label="特长引擎" tabindex="0" role="button" aria-label="聚焦特长引擎,feats_engine.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="feats_engine.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>特长引擎 · feats_engine.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="1132" y="616" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="1132" y="616" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(1138 622) scale(0.6875)">
|
||||
@@ -5569,8 +5569,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="1197" y="654" class="t-muted" font-size="9" text-anchor="middle">feats_engine.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-status" data-node-id="status" data-node-label="状态容器" tabindex="0" role="button" aria-label="聚焦状态容器,status_container.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="status_container.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>状态容器 · status_container.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-status" data-node-id="status" data-node-label="状态容器" tabindex="0" role="button" aria-label="聚焦状态容器,status_container.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="status_container.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>状态容器 · status_container.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="96" y="678" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="96" y="678" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(102 684) scale(0.6875)">
|
||||
@@ -5580,8 +5580,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="161" y="716" class="t-muted" font-size="9" text-anchor="middle">status_container.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-units" data-node-id="units" data-node-label="单位容器" tabindex="0" role="button" aria-label="聚焦单位容器,unit_container.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="unit_container.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>单位容器 · unit_container.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-units" data-node-id="units" data-node-label="单位容器" tabindex="0" role="button" aria-label="聚焦单位容器,unit_container.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="unit_container.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>单位容器 · unit_container.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="244" y="678" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="244" y="678" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(250 684) scale(0.6875)">
|
||||
@@ -5591,8 +5591,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="309" y="716" class="t-muted" font-size="9" text-anchor="middle">unit_container.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-treasure" data-node-id="treasure" data-node-label="秘宝数据" tabindex="0" role="button" aria-label="聚焦秘宝数据,treasure_items.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="treasure_items.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>秘宝数据 · treasure_items.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-treasure" data-node-id="treasure" data-node-label="秘宝数据" tabindex="0" role="button" aria-label="聚焦秘宝数据,treasure_items.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="database" data-node-sublabel="treasure_items.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>秘宝数据 · treasure_items.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="392" y="678" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="392" y="678" width="130" height="48" rx="6" class="c-database" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="database" class="semantic-sigil s-database" transform="translate(398 684) scale(0.6875)">
|
||||
@@ -5603,8 +5603,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="457" y="716" class="t-muted" font-size="9" text-anchor="middle">treasure_items.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-resolver" data-node-id="resolver" data-node-label="配置解析" tabindex="0" role="button" aria-label="聚焦配置解析,config_db_resolver.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="config_db_resolver.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>配置解析 · config_db_resolver.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-resolver" data-node-id="resolver" data-node-label="配置解析" tabindex="0" role="button" aria-label="聚焦配置解析,config_db_resolver.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="config_db_resolver.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>配置解析 · config_db_resolver.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="540" y="678" width="130" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="540" y="678" width="130" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(546 684) scale(0.6875)">
|
||||
@@ -5614,8 +5614,8 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-detail="context" x="605" y="716" class="t-muted" font-size="9" text-anchor="middle">config_db_resolver.gd</text>
|
||||
</g>
|
||||
|
||||
<g id="node-xvalid" data-node-id="xvalid" data-node-label="配置交叉校验" tabindex="0" role="button" aria-label="聚焦配置交叉校验,config_db_cross_validator.gd, 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="config_db_cross_validator.gd" data-node-context="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<title>配置交叉校验 · config_db_cross_validator.gd · 逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</title>
|
||||
<g id="node-xvalid" data-node-id="xvalid" data-node-label="配置交叉校验" tabindex="0" role="button" aria-label="聚焦配置交叉校验,config_db_cross_validator.gd, 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)" aria-pressed="false" data-node-kind="backend" data-node-sublabel="config_db_cross_validator.gd" data-node-context="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<title>配置交叉校验 · config_db_cross_validator.gd · 逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</title>
|
||||
<rect x="688" y="678" width="170" height="48" rx="6" class="c-mask"/>
|
||||
<rect x="688" y="678" width="170" height="48" rx="6" class="c-backend" stroke-width="1.5"/>
|
||||
<g aria-hidden="true" data-semantic-sigil="backend" class="semantic-sigil s-backend" transform="translate(694 684) scale(0.6875)">
|
||||
@@ -5660,9 +5660,9 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<text data-boundary-label="" x="98" y="413" class="t-cloud" font-size="9" font-weight="600">浮层与对话框(组合根挂载)</text>
|
||||
</g>
|
||||
|
||||
<g data-graph-role="structural-frame-label" data-composition-frame-id="2" data-composition-frame-kind="region" data-composition-frame-label="逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)">
|
||||
<rect data-graph-role="structural-frame-label-mask" x="70" y="534" width="339.4" height="16" rx="3" class="c-mask"/>
|
||||
<text data-boundary-label="" x="74" y="547" class="t-cloud" font-size="9" font-weight="600">逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)</text>
|
||||
<g data-graph-role="structural-frame-label" data-composition-frame-id="2" data-composition-frame-kind="region" data-composition-frame-label="逻辑层 core/(目录层级约束=architecture.md「目录归属」表)">
|
||||
<rect data-graph-role="structural-frame-label-mask" x="70" y="534" width="328.59999999999997" height="16" rx="3" class="c-mask"/>
|
||||
<text data-boundary-label="" x="74" y="547" class="t-cloud" font-size="9" font-weight="600">逻辑层 core/(目录层级约束=architecture.md「目录归属」表)</text>
|
||||
</g>
|
||||
|
||||
<!-- Legend -->
|
||||
@@ -5883,7 +5883,7 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
<h3>逻辑层与边界</h3>
|
||||
</div>
|
||||
<ul>
|
||||
<li>• core/ 模块与拆件全量清单以 architecture.md「模块归属」表为准,本图只画顶层导航件</li>
|
||||
<li>• core/ 全量清单以 architecture.md「目录归属」表与各文件头注为准,本图只画顶层导航件</li>
|
||||
<li>• ConfigDB/RngService 两单例经 project.godot autoload 全局供给</li>
|
||||
<li>• smoke/ 下 13 个测试探针场景属测试基建,不入架构主干</li>
|
||||
</ul>
|
||||
|
||||
@@ -556,7 +556,7 @@
|
||||
},
|
||||
{
|
||||
"kind": "region",
|
||||
"label": "逻辑层 core/(模块与拆件清单=architecture.md「模块归属」表)",
|
||||
"label": "逻辑层 core/(目录层级约束=architecture.md「目录归属」表)",
|
||||
"wraps": [
|
||||
"save",
|
||||
"meta",
|
||||
@@ -689,7 +689,7 @@
|
||||
"dot": "rose",
|
||||
"title": "逻辑层与边界",
|
||||
"items": [
|
||||
"core/ 模块与拆件全量清单以 architecture.md「模块归属」表为准,本图只画顶层导航件",
|
||||
"core/ 全量清单以 architecture.md「目录归属」表与各文件头注为准,本图只画顶层导航件",
|
||||
"ConfigDB/RngService 两单例经 project.godot autoload 全局供给",
|
||||
"smoke/ 下 13 个测试探针场景属测试基建,不入架构主干"
|
||||
]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。
|
||||
|
||||
### 1.3 依赖单向,核心写调用完成
|
||||
依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);核心写接口(settle_batch / player_request_refresh / runner 推进)只允许在组合根出现——组合根=main.gd+其构造注入的组合根拆件(成员与边界见架构文档「模块归属·呈现层」),视图不得直连拆件。
|
||||
依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);核心写接口(settle_batch / player_request_refresh / runner 推进)只允许在组合根出现——组合根=main.gd+其构造注入的组合根拆件(成员与边界见各件文件头注),视图不得直连拆件。
|
||||
|
||||
### 1.4 命名 = 领域命名,禁止系统 ID 前缀
|
||||
文件名与类名禁止 `a1_`/`b1_`/`c1_` 等系统 ID 前缀(`a1_board_generator.gd` → `board_generator.gd`)。设计追溯不靠前缀:代码↔设计的追溯由 GDD 文档承担,系统 ID 只作为文档的追溯锚;文件头注不承担追溯职责,不写任何文档链接(§1.4.1)。豁免:D2 schema 类与 autoload;文档/夹具登记名(如 b4_golden)属文档层。
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
| 规则 | 内容 |
|
||||
|---|---|
|
||||
| 树形文档体系 | 全部设计文档构成一棵树;文档增删必须同步根索引 `design/gdd/02-系统清单.md` |
|
||||
| 架构事实唯一源 | `design/engineering/architecture/architecture.md` 是架构事实的唯一权威(分层/模块归属/数据流/API 边界——只写约束面:难以改变的分层、依赖规则、边界契约与关键决策;实现现状归代码与代码头注,实现历史归 git commit log);禁建第二份架构文档;**架构文档写权限=用户专属**(2026-11-07 用户裁:agent 与技能只读,修订须用户发起) |
|
||||
| 架构事实唯一源 | `design/engineering/architecture/architecture.md` 是架构事实的唯一权威(分层/目录归属/数据流/架构原则——只写依赖规则面:难以改变的分层、目录层级约束、依赖方向与数据流;模块级归属归代码头注,接口契约规范源=各系统 GDD,实现历史归 git commit log);禁建第二份架构文档;**架构文档写权限=用户专属**(2026-11-07 用户裁:agent 与技能只读,修订须用户发起) |
|
||||
| 一页纸节点 | 一节、一条规则 ≤一页纸(约 ≤80 行);装不下就拆节 |
|
||||
| 一系统一文档 | 不建 analysis 推演件;两三句能说清的"为什么"直接写进设计目的或规则正文 |
|
||||
| 正文只写现行规则 | 禁删除线、"(作废)"、"(日期+拍板)"式注记;审计信息入对应文档附录 |
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
|
||||
**判据出处行锚(2026-11-05 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改,被编入迭代开工前由写卡段按本粒度补挂)**:对照表「需求点」列每行必须带**判据出处行锚**——该行验收判据所依据的现行文档句子,格式「`<文档相对路径>:<行号>`」。现行文档=`design/` 全域现行文档(含 `ux/` 交互规格与 art-bible 的判据行);已退役的需求卡片不是现行文档,不得充当判据出处。作用=断言预期值从规格句抄出,不从实现反推:实现行为与规格句冲突时断言红;规格缺席的行写不出锚,即停卡退回写卡段(那是需求澄清缺口,不是测试缺口)。机检=`tools/pipeline_gate.py` 判据 C5(锚格式与指向存在性,按卡文件名日期分流)+`tools/capability_audit.py` 链式锚检查(断言→套件→能力行→系统文档,见 §8.9)。
|
||||
|
||||
**测试函数的判据出处注记(2026-11-06 立)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# 判据出处: <design/相对路径>:<行号> <判据一句>`」——指针在前、判据摘要句在后;锚形态两档:行号锚(默认)与节锚(`<design/相对路径>「节名」<行关键词>`)——所指文档整节重排时同批把行号锚重锚为节锚,免行号漂移(2026-11-07 架构收窄批立),断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;被指规格句改行号时随批维护指针——死指针即红。局限如实声明:注记是被动文本,句内容改而行数不变时机检抓不到(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+指针存在性;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。
|
||||
**测试函数的判据出处注记(2026-11-06 立)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# 判据出处: <design/相对路径>:<行号> <判据一句>`」——指针在前、判据摘要句在后;锚形态两档:行号锚(默认)与节锚(`<design/相对路径>「节名」<行关键词>`)——所指文档整节重排时同批把行号锚重锚为节锚,免行号漂移(2026-11-07 架构收窄批立),断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行;测量面驱动契约锚 `game/sim/` 实现件文件头注——规范句在哪锚哪,2026-11-09 架构收敛批立);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;被指规格句改行号时随批维护指针——死指针即红。局限如实声明:注记是被动文本,句内容改而行数不变时机检抓不到(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+指针存在性;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。
|
||||
|
||||
**验收档申报(2026-11-04 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改)**:每张需求卡片在头部信息区(与设计事实源声明同区)申报一个验收档,三档:高/中/低。判据=失败代价单维——这条改动做错了,后果随存档或结算传播的(存档写读与迁移、RNG 流、战斗结算公式与乘区、经济入账、数值表结构校验)=高;后果玩家可见但不损持久状态的(常规玩法逻辑、门控、交互逻辑、呈现数据面)=中;后果即看即知且无状态残留的(文案、纯呈现样式、布局微调)=低。一张卡触多档按最高档申报;申报由写卡段落笔,用户批卡(U0)时确认或改判。档位只调节 §8.7 审计深度——闸机与 CI 的域划分、选闸算法、全量强制档一概不因档位变化,真实入口、判据绑定面、禁削弱等验收闭合判据全部照旧。未申报档位的卡一律按高档全量审计。机检=`tools/pipeline_gate.py` 判据 C4:卡内须含「验收档:高/中/低」申报行。
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
|
||||
|
||||
主动放弃按与失败同型结算:已兑付的三选一件与回血不追回、已到手的保留,摘要标记未打穿。放弃请求只在非战斗期受理,战斗进行中一律拒绝(战斗域单事务执行期间)。放弃的界面入口挂在[关卡节点地图](关卡节点地图.md)的选路覆盖层上——选路停点天然是非战斗期,按钮只在冒险模式开放(选路覆盖层只在冒险模式出现);战斗进行中没有选路停点,入口因此天然不可达,拒绝分支仅作防御兜底。
|
||||
|
||||
主种子(本文含义:冒险开始时注入的一个随机种子,本局全部随机性都派生自它)在冒险开始时注入恰一次。冒险内的雷图生成、奖励抽取、遭遇掷骰与 GP 掉落掷定(消费 gp_drop 封闭流)全部派生自它,冒险内不重置、不逐关播种。冒险的可复现域 = 主种子 + 全局取数计数器(统一随机流口径,语义权威归[数据配置](../表现与支撑/数据配置.md)),供复盘与快照(见[存档序列化](../表现与支撑/存档序列化.md))。重开抽到的种子与上一局相同是允许的(随机源范围小,撞种子不算错误),但生成新种子禁止复用玩法里的随机数。
|
||||
主种子(本文含义:冒险开始时注入的一个随机种子,本局全部随机性都派生自它)在冒险开始时注入恰一次。冒险内的雷图生成、奖励抽取、遭遇掷骰与 GP 掉落掷定(消费 gp_drop 封闭流)全部派生自它,冒险内不重置、不逐关播种。冒险的可复现域 = 主种子 + 全局取数计数器(统一随机流口径,语义权威归[数据配置](../表现与支撑/数据配置.md)),供复盘与快照(见[存档序列化](../表现与支撑/存档序列化.md))。重开抽到的种子与上一局相同是允许的(随机源范围小,撞种子不算错误),但生成新种子禁止复用玩法里的随机数。调试种子入口的三分判定:显式输入的合法整数优先;首局(无存档在档)空框恒用固定教学种子;非首局空框用引擎熵随机生成(不进玩法封闭流)。
|
||||
|
||||
### 冒险断点:中断可续玩的停点快照
|
||||
|
||||
@@ -193,7 +193,7 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
|
||||
- **停点粒度**:快照只挂选路停点(入口呈现/战斗胜利后/兑付确认后的选路态)——这是唯一可恢复停点形态。战斗进行中不写快照:中断恢复后**当场战斗从头打**,棋盘中局不入档。
|
||||
- **七字段拍板面**:关卡序号 / 节点位 / 生命 / 本关加成区 / GP 钱包 / 商店已购档 / 已抽模板。附随件(续玩正确性必需):主种子 + 取数计数器(rng 快照契约回填——续玩从断点号位精确续接原随机时间线,已抽模板零重抽)、钥石累计(Boss 掉落逐杀入账的中途值,终局摘要不失真)、已到节点序(关卡画面图条重建)、秘宝库存(奖励节点已选件防静默丢失)、**奖励选择态**(三选一停点中断:已选件 / 同调位替换在途——续玩已选不丢失;候选一致性=快照现状非强求 feature,2026-10-01 用户裁决)、**件获取次数计数**(kind 维度派生账本——断点附随件与读数承载)、**令牌池余库**(bonus_deck 逐枚还原——TP0 扩列,池消耗即上限的续玩正确性承载;旧版断点缺键=满库重建防御口径,单版本周期)、**商店货架态**(当前货架三件 + 本次进店已购次数;离开店=空架合法态,货架续玩由确定性重放承载:重进店同种子同货架逐位)、**Y 刷新池余量**(attune_refresh_y——冒险周期池消耗余量随断点:续玩优先读断点、不自参数面整额重注入,堵「用完 Y 退菜单再续玩满血复活」可利用漏洞;旧断点缺键回退参数面=旧档行为零变化)。
|
||||
- **中断与退出两口径分离**(2026-09-29 用户裁决):中断(关游戏)= 留断点可续;**退出冒险**(放弃流程)= 失败同型结算 + **清除断点**——退出后「继续上局」不再出现。
|
||||
- **获得日记键**(gain_journal,断点 28 键):获得记录明细(三层结构归架构文档「模块归属·核心层」GainJournal 行——本域只登记断点面口径)随断点保存,回退策略 plain;旧档回退两态——旧断点缺日记键=汇总键直载并跳过比对(零迁移损失),日记在档=由日记推导汇总值与留存值比对,不符即报错中止(迁移正确性自检)。
|
||||
- **获得日记键**(gain_journal,断点 28 键):获得记录明细(三层结构归实现类头注——本域只登记断点面口径)随断点保存,回退策略 plain;旧档回退两态——旧断点缺日记键=汇总键直载并跳过比对(零迁移损失),日记在档=由日记推导汇总值与留存值比对,不符即报错中止(迁移正确性自检)。
|
||||
- **续玩**:自断点重建到最近停点(逐字段回填 + 随机流回填),停点处玩家重新选路。三结局(冒险成功/失败/放弃)一律清断点——断点只活在一个进行中的冒险上。
|
||||
- 与测量面的关系:断点面只在注入存档承载的正式冒险路径生效;模拟/冒烟不注入 = 整面静默,MC 逐项比对零扰动。
|
||||
|
||||
|
||||
@@ -100,7 +100,9 @@
|
||||
|
||||
基础 9 类写的是裸机制的账:玩家没有任何专长时,结算流水的每一行都出得了这九类。有了专长之后,效果引擎会在段内挂点插入额外的结算效果,这类效果写**扩展行**。扩展行是**一个**行型,不是每种专长效果各占一个行型——具体插的是哪种效果,由行携带的效果身份(effect_id 载荷)说明,呈现层按身份取各自的行文案。专长会不断增加、效果种类不可穷举,行型词表因此对扩展类封口:新增专长效果只新增载荷身份,不再新增行型。
|
||||
|
||||
扩展行与基础行共用同一套行协议:公共字段、来源归因、两层豁免、无来源即炸,全部照常生效。发射时点由段序骨架的挂点决定(时序与挂点施加面、效果身份清单与各发射点归代码文件头注承载——模块归属见架构文档「模块归属·功能层」battle_orchestrator 行),本节只管这行是什么、带什么字段。扩展行携带效果身份(effect_id 载荷)。
|
||||
扩展行与基础行共用同一套行协议:公共字段、来源归因、两层豁免、无来源即炸,全部照常生效。发射时点由段序骨架的挂点决定(时序与挂点施加面、效果身份清单与各发射点归代码文件头注承载),本节只管这行是什么、带什么字段。扩展行携带效果身份(effect_id 载荷)。
|
||||
|
||||
效果引擎的装载与订阅面(表装载、rebuild、树规则挂接)与端口装配明细归实现件文件头注承载。两业务类(伤害管线/行动经济)持同一个效果端口件实例,命中批经端口路由全处理。伤害域传给效果引擎的事实面为封闭集合:载荷携带的事实键可达、宿主链事实不外溢——事实面增删走实现件修订,禁静默扩面。
|
||||
|
||||
举证:本节为行协议约定,无计算。
|
||||
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
- 清图口径:清图 = 全部安全格完成——挖开或封印都算完成;封到安全格计入清图进度,封印可以完成清图。
|
||||
- 已引爆危险格可通行:挖雷后轮次不结束,小人可站、可经已开区穿行续挖;危险格不计清图、不可再挖再封印。
|
||||
- 移动合法且预览同源:目标未开或无已开区连通路径时拒绝;路径预览与实际执行逐格相同;移动免费、零事件。
|
||||
- 揭示预览口:预览口按实挖同口径返回揭示闭包——零状态写入、零事件外发、封印格不外扩(只读查询面,供测量与呈现旁路取数)。
|
||||
- 批次仲裁与到达序无关:同一批意图按任意顺序提交,结束路径与结算结果一致;赢家定出后其余意图丢弃——零棋盘效果、零扣费、零事件,且丢弃区别于拒绝。
|
||||
- 收轮事件序:先报完全部封印判定,再报轮次结束;轮次结束每轮恰一条,停手路径由行动经济直发、本系统不双发。
|
||||
- 拒绝三源可辨:棋盘面非法、资源不足、相位不对三类原因互异可判定;任何拒绝零副作用。
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
第二条边界是反面清单:局内资源不入存档。行动点、储备行动点、道具库存、生命、GP 全部单局清零——各归各的系统管,没有局内数值需要持久化。若未来某局内资源要开放跨局携带(如储备行动点跨战斗携带),须修订其池规则并向本系统登记持久化归属,禁止静默超域。
|
||||
|
||||
**唯一豁免 = `breakpoint` 断点域**:断点是冒险进行中的瞬态快照,不是跨局携带——里面的生命/GP/道具库存只在「续玩上局」时还原进局内,冒险收束(冒险成功/失败/放弃)即整域清除,永远不会渗进永久进度。反面清单的管辖对象因此收窄为 `meta` 永久进度域(冒烟域界扫描收窄到 meta 域);断点域自身的字段口径归[冒险结构](../冒险循环/冒险结构.md)登记。断点顶层键(28 键)的登记单源=冒险应用层的断点键表(键→回退策略;现行契约见架构文档「模块归属·核心层」breakpoint_store 行);写读已换代为各件自交片段——主角账/停点件/关卡件各自写读自己的键(缺键回退策略随领域知识归各件),冒险应用层是唯一拼盘落盘口(收齐各件片段拼成顶层快照后写盘,写触发点不变)。**关卡完成停点的同调未用行留存**:`aux_items` 键在此停点形态含同调未用行(「同调行始终留在 treasure_inventory」与「键值形态逐位不变」在关卡完成停点互斥,采行留存;玩家可见 C 区投影零变化,24 停点充能读数逐位一致)。
|
||||
**唯一豁免 = `breakpoint` 断点域**:断点是冒险进行中的瞬态快照,不是跨局携带——里面的生命/GP/道具库存只在「续玩上局」时还原进局内,冒险收束(冒险成功/失败/放弃)即整域清除,永远不会渗进永久进度。反面清单的管辖对象因此收窄为 `meta` 永久进度域(冒烟域界扫描收窄到 meta 域);断点域自身的字段口径归[冒险结构](../冒险循环/冒险结构.md)登记。断点顶层键(28 键)的登记单源=冒险应用层的断点键表(键→回退策略,键表本体=承载件的常量登记);写读已换代为各件自交片段——主角账/停点件/关卡件各自写读自己的键(缺键回退策略随领域知识归各件),冒险应用层是唯一拼盘落盘口(收齐各件片段拼成顶层快照后写盘,写触发点不变)。**关卡完成停点的同调未用行留存**:`aux_items` 键在此停点形态含同调未用行(「同调行始终留在 treasure_inventory」与「键值形态逐位不变」在关卡完成停点互斥,采行留存;玩家可见 C 区投影零变化,24 停点充能读数逐位一致)。
|
||||
|
||||
**三存档位**:存档是 3 个独立的 JSON 文件(三个独立存档文件,槽文件名只经存档系统单点派生,槽 1 禁复用旧单档名),字典键一律字符串。写盘目标=当前激活槽的文件;启动(boot)不读任何槽文件——启动态=无激活态,不读写;激活态由选档界面的「新档」或「进档」建立。数据模型(现行 = v7;示例值全为零值默认态):
|
||||
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@
|
||||
|
||||
| 术语 | 定义 |
|
||||
|---|---|
|
||||
| 效果端口件 | 战斗业务类(伤害管线/行动经济)唯一的效果发射出口:收事件与载荷、交效果引擎结算、取回命中批——业务类零引擎直连(机制归属见架构文档「模块归属·功能层」battle_orchestrator 行;实现类 EffectPort) |
|
||||
| 效果端口件 | 战斗业务类(伤害管线/行动经济)唯一的效果发射出口:收事件与载荷、交效果引擎结算、取回命中批——业务类零引擎直连(机制归属见实现类 EffectPort 文件头注) |
|
||||
| 掷格件 | 装配期格面资源摇号的承载件:池行装配、区间行 roll、权重合成(订阅加权/board_skew 两路投影);受理账面留守地图战斗资源件(机制归属同上;实现类 RewardRoller) |
|
||||
| `seal_missed` | 封印落空事件(旧名已换代):封印动作落在安全格上时发出,订阅面据此做限次与豁免判定 |
|
||||
| `forgive_seal_miss` | 本场首次封印落空豁免——专长「完美保险」的效果类型,`domain=battle` 首例;有效误标=误标总数 − 豁免数,豁免不改写误标账 |
|
||||
|
||||
@@ -743,7 +743,7 @@ func _in_scroll(c: Control) -> bool:
|
||||
|
||||
|
||||
func _audit(screen: String, roots: Array) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·呈现层」D1 行(组合根交接面) 组合根交接面与呈现装配——屏结构审计宿主面(结构审计组)
|
||||
# 判据出处: design/engineering/architecture/architecture.md「三屏壳与组合根」(组合根交接面) 组合根交接面与呈现装配——屏结构审计宿主面(结构审计组)
|
||||
for r in roots:
|
||||
if r != null and is_instance_valid(r):
|
||||
_force_layout(r)
|
||||
|
||||
@@ -199,7 +199,7 @@ func _ready() -> void:
|
||||
_overlay_zero_motion_contract(main, problems)
|
||||
# ⑩ 种子三分单点断言(18卡⑦ C1——判定只落 _seed_value() 单点;对局态不影响本判定面):
|
||||
# 显式合法整数全场景优先(含首局)→ 首局(存档布尔 false)恒 42 → 非首局空框引擎熵连抽不全等 42
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·呈现层」D1 行(组合根交接面) seed_value=组合根公开服务面(⑩种子三分判定单点组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「主种子」(组合根交接面) seed_value=组合根公开服务面(⑩种子三分判定单点组)
|
||||
main.ui.modals.menu.debug_overlay.seed_edit.text = "777"
|
||||
if main.seed_value() != 777:
|
||||
problems.append("显式种子输入未优先(_seed_value != 777——C1 ①失守)")
|
||||
|
||||
@@ -46,7 +46,7 @@ tests/
|
||||
>
|
||||
> **维护规则(写卡段维护,实现批禁写本表)**:写需求卡片时当场入表——本批新增能力当场增行(真实入口取自设计文档已定的入口;代表用例=卡内定死的计划测试 `文件:函数`,实现照单落名,名实不符=卡片没写清=停卡退回);受影响存量行(入口/用例名变更)同批更新;能力退役删行。批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段(test-conventions §8.3/§8.9)。
|
||||
>
|
||||
> **旅程补录方法**:新旅程=加一行,「系统」列写涉及边界;源=architecture「API 边界」表+「数据流」存档/读档路径+各 GDD 登记的 deferral 跨系统用例。
|
||||
> **旅程补录方法**:新旅程=加一行,「系统」列写涉及边界;源=各系统 GDD「依赖与输出」节+「数据流」存档/读档路径+各 GDD 登记的 deferral 跨系统用例。
|
||||
|
||||
**旅程段一:开机与存档**
|
||||
|
||||
@@ -204,6 +204,7 @@ tests/
|
||||
| 状态实例按个体归属:个体隔离/全体授予逐体发/死亡即清/同体合并照旧 | 增益状态 | `StatusContainer.apply_effect()`(个体键)/`purge_owner()` | `system_contracts_test.gd:_test_status_individual_isolation`;`system_contracts_test.gd:_test_status_grant_all_per_unit`;`system_contracts_test.gd:_test_status_death_clears`;`system_contracts_test.gd:_test_status_merge_per_unit` |
|
||||
| 敌方增益自体落点与乘区池按个体 | 敌人系统×战斗结算×增益状态 | 技能兑付编排链/`DamageController.clamped_pool()` | `round_flow_skill_pool_test.gd:_smoke_enemy_buff_targets_self`;`damage_controller_test.gd:_test_pool_consumption_per_unit`;`damage_controller_test.gd:_test_defender_ac_per_unit`;`battle_narrator_test.gd:_test_snapshot_effects_per_unit` |
|
||||
| 敌人技能池跨表链接校验 | 数据配置×敌人系统 | `ConfigDbCrossValidator.validate_skill_pool_links()` | `config_db_cross_validator_test.gd:_test_all_links_valid`;`config_db_cross_validator_test.gd:_test_dangling_skill_id`;`config_db_cross_validator_test.gd:_test_cast_side_mismatch` |
|
||||
| 跨表量级校验 | 数据配置×敌人系统×难度曲线与Boss | `ConfigDbCrossValidator.cross_validate()`/`ConfigDB.load_tables()` | `config_db_cross_validator_test.gd:_test_magnitude_over_limit`(计划——需求卡片「跨表量级护栏批」2026-11-09 锚定);`cross_magnitude_fatal_test.gd:_init`(计划——同卡锚定) |
|
||||
| 精英行:池继承合并、加载期校验与暂不接线 | 敌人系统×数据配置 | `ConfigDB.load_tables()`/`EnemyTable.validate()`/`EnemyTable.effective_pool()`/`ConfigDbCrossValidator.validate_skill_pool_links()`/`EnemyTable.resolve_rowset()` | `elite_row_test.gd:_test_elite_validation_rejects`;`elite_row_test.gd:_test_effective_pool_merge`;`elite_row_test.gd:_test_base_pool_change_propagates`;`elite_row_test.gd:_test_merged_pool_composition`;`elite_row_test.gd:_test_elite_unreachable_by_encounter`;`elite_row_test.gd:_test_production_goblin_elite` |
|
||||
|
||||
**覆盖域表**(`design/gdd/systems/` 逐篇对照——状态三档:已覆盖/部分覆盖/未覆盖;部分与未覆盖行的缺口指待办清单条目,覆盖面提升时同批改本表):
|
||||
|
||||
@@ -19,7 +19,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (效果端口宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (效果端口宿主——装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
var load_ok: bool = _db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:表加载零 error", load_ok and _db.diagnostics_count("error") == 0)
|
||||
@@ -54,7 +54,7 @@ func _hero_attack_value(rows: Array) -> int:
|
||||
# ---- V1 端口单实例与真实发射路由 ----
|
||||
|
||||
func _smoke_effect_port_wiring() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (端口单实例与六 Callable 路由组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (端口单实例与六 Callable 路由组)
|
||||
print("--- 效果端口:装配链单实例+真实发射路由 ---")
|
||||
# 充能跑(蓄力周转 charge_rotation 在册——attack_commit 订阅行 attack_bonus per 蓄力周转计数器)
|
||||
var orch_c = _orch(TEST_SEED)
|
||||
@@ -88,7 +88,7 @@ func _smoke_effect_port_wiring() -> void:
|
||||
# ---- V2 业务类零引擎直连(源码契约锚——theme_projection_test 源码锚惯例)----
|
||||
|
||||
func _test_business_classes_engine_free() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (业务类零引擎直连组)
|
||||
# 判据出处: design/gdd/术语表.md「效果端口件」 (业务类零引擎直连组)
|
||||
print("--- 效果端口:业务类零引擎直连源码锚 ---")
|
||||
for path in ["res://core/damage_controller.gd", "res://core/action_economy.gd"]:
|
||||
var src := FileAccess.get_file_as_string(path)
|
||||
@@ -100,7 +100,7 @@ func _test_business_classes_engine_free() -> void:
|
||||
# ---- V3 伤害域事实面闭集(合成行两对照——damage_taken 真实单据流)----
|
||||
|
||||
func _test_biz_fact_face_closed() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (闭面四键 biz_fact 组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (闭面四键 biz_fact 组)
|
||||
print("--- 效果端口:业务发射事实面闭集 ---")
|
||||
var orch = _orch(TEST_SEED)
|
||||
Kit.check("V3 begin_battle 受理", orch.begin_battle(_enc([])))
|
||||
|
||||
@@ -41,8 +41,8 @@ func _init() -> void:
|
||||
# ---- B1 兑付配方词表:五配方/三目标规则/双结账政策——常量非空且互异(封闭枚举负空间) ----
|
||||
|
||||
func _test_damage_controller_vocabularies() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」effect_engine 行 (事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」effect_engine 行 (事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器」 (事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器」 (事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
var kinds: Array = [
|
||||
DamageControllerScript.KIND_HERO_ATTACK, DamageControllerScript.KIND_ENEMY_SKILL,
|
||||
DamageControllerScript.KIND_BOARD_TYPED, DamageControllerScript.KIND_BOARD_BLAST,
|
||||
@@ -72,8 +72,8 @@ func _test_damage_controller_vocabularies() -> void:
|
||||
# ---- D2↔B1:掷点用途标签 ∈ RngService 封闭词表(EC12——跨系统字面量契约的成员性断言) ----
|
||||
|
||||
func _test_rng_tag_closure(db) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」RngService 行 (流 scope 封闭词表组)
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」RngService 行 (流 scope 封闭词表组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (流 scope 封闭词表组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (流 scope 封闭词表组)
|
||||
var stream_label: String = String(db.combat.settlement.damage_roll.armor_roll_stream)
|
||||
Kit.check("settlement.armor_roll_stream ∈ RngService 封闭标签词表(EC12)",
|
||||
RngServiceScript.PURPOSE_TAGS.has(stream_label))
|
||||
|
||||
@@ -55,7 +55,7 @@ func _init() -> void:
|
||||
|
||||
# ① 缺省两参(真编排器):同种子两跑整轮驱动逐位(确定性自证——动作序列快照经 cell_revealed 事件流)
|
||||
func _smoke_drive_round_contract() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (效果端口件:收事件交结算取回命中批——驱动循环契约组)
|
||||
# 判据出处: design/gdd/术语表.md「效果端口件」 (效果端口件:收事件交结算取回命中批——驱动循环契约组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
|
||||
Kit.check("前置:表加载零 error", load_ok)
|
||||
@@ -81,7 +81,7 @@ func _smoke_drive_round_contract() -> void:
|
||||
|
||||
# ② provider 形态:策略回调产出 dig/seal_place/refresh 各一——提交与日志回调四元组在案
|
||||
func _provider_shapes() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (端口应答束形状组)
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (端口应答束形状组)
|
||||
var st := _StubSettlement.new()
|
||||
var script := [ {"kind": "dig", "cell": Vector2i(1, 1)}, {"kind": "seal", "cell": Vector2i(2, 2)}, {"kind": "refresh"}, {"kind": "stop"} ]
|
||||
var logs: Array = []
|
||||
@@ -102,7 +102,7 @@ func _provider_shapes() -> void:
|
||||
|
||||
# ③ max_rejects:策略恒返被拒动作——第 3 拒后停手出环(循环次数=3)
|
||||
func _max_rejects() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (拒绝通道组)
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (拒绝通道组)
|
||||
var st := _StubSettlement.new()
|
||||
st.minesweeper.accept = false
|
||||
st.minesweeper.reject_cells = {Vector2i(9, 9): true}
|
||||
@@ -122,7 +122,7 @@ func _max_rejects() -> void:
|
||||
|
||||
# ④ 合步 next:move 后相位变更即断弃 dig(桩 on_submit 钩子把 phase 推离 Active)
|
||||
func _combined_step_next() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·功能层」battle_orchestrator 行(域文件集含 EffectPort) (合并步进组)
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (合并步进组)
|
||||
var st := _StubSettlement.new()
|
||||
st.minesweeper.on_submit = func(action: String) -> void:
|
||||
if action == "move":
|
||||
|
||||
@@ -8,7 +8,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (CurioDeck:三选一/商店共享池、抽签、cap 库存——刷新付费组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「定位与形态」 (CurioDeck:三选一/商店共享池、抽签、cap 库存——刷新付费组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[curio_refresh_paid_test] FAIL — 数值表加载失败")
|
||||
|
||||
@@ -11,7 +11,7 @@ const EffectEngineScript = preload("res://core/effect_engine.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」effect_engine 行 (效果词表封闭——扩签封闭性组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「扩签登记」 (效果词表封闭——扩签封闭性组)
|
||||
# ① 词表在册断言(扩签面:2 事件+8 事实+7 效果类型+1 算子)
|
||||
Kit.check_quiet(EffectEngineScript.EVENTS.has("dig_stop") and EffectEngineScript.EVENTS.has("battle_won"),
|
||||
"新事件在册:dig_stop/battle_won〔专长批 V1〕")
|
||||
|
||||
@@ -1254,7 +1254,7 @@ func _paths_all_one_shop(nodes: Array) -> bool:
|
||||
# ---- ⑤ 商店共享池(三选一同构/乘法价/跨渠道共账/切边/断点扩键)----
|
||||
|
||||
func _smoke_shop_pool() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (商店共享池组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「共享池账本」 (商店共享池组)
|
||||
print("--- 商店共享池(抽3买1全重抽 · 乘法定价 ceil · 池空硬闸 · 切边零入店)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
var shelf_kinds: Array = []
|
||||
|
||||
@@ -126,7 +126,7 @@ func _test_reject_out_of_catalog() -> void:
|
||||
# ---- V14 棋盘揭示预览只读口(架构整改——preview_reveal 与实挖揭示集同口径、零状态写入零事件)----
|
||||
|
||||
func _test_preview_reveal_readonly() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」minesweeper_rules 行 (preview_reveal 只读预览口——零写入零事件组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「核心规则」 (preview_reveal 只读预览口——零写入零事件组)
|
||||
var events := 0
|
||||
_rules.cell_revealed.connect(func(_evt): events += 1) # 零发射哨兵(preview 全程不触发揭示事件)
|
||||
# 形态 A:封印在场——preview(未开格) 不越封印且零状态写入
|
||||
|
||||
@@ -9,7 +9,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (池结构案 D:候选抽取与池纪律组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池结构案 D:候选抽取与池纪律组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[pool_case_d_test] FAIL — 数值表加载失败")
|
||||
@@ -66,7 +66,7 @@ func _tiers_of(cands: Array) -> Array:
|
||||
|
||||
|
||||
func check_v7(a, db) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (池案 D V7 组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V7 组)
|
||||
if not a.start_adventure(201):
|
||||
Kit.check_quiet(false, "V7 前置:冒险启动")
|
||||
return
|
||||
@@ -112,7 +112,7 @@ func check_v7(a, db) -> void:
|
||||
|
||||
|
||||
func check_v6(b, db) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (池案 D V6 组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V6 组)
|
||||
if not b.start_adventure(202):
|
||||
Kit.check_quiet(false, "V6 前置:冒险启动")
|
||||
return
|
||||
@@ -142,7 +142,7 @@ func check_v6(b, db) -> void:
|
||||
|
||||
|
||||
func check_v12(m, db) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (池案 D V12 组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V12 组)
|
||||
if not m.start_adventure(401):
|
||||
Kit.check_quiet(false, "V12 前置:冒险启动")
|
||||
return
|
||||
@@ -161,7 +161,7 @@ func check_v12(m, db) -> void:
|
||||
|
||||
|
||||
func check_v8(c, db) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·核心层」CurioDeck 行 (池案 D V8 组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V8 组)
|
||||
if not c.start_adventure(203):
|
||||
Kit.check_quiet(false, "V8 前置:冒险启动")
|
||||
return
|
||||
|
||||
@@ -47,7 +47,7 @@ func _fresh_rng(seed_val: int):
|
||||
# ---- ① RNG 事件日志会话落盘(源 `_initialize` :70,主会话裁决一改判跨系统闭环承载——
|
||||
# 驱动沿源 :60–70 取号序列自持:master 种子 42 → 前置取号 → new_adventure 开日志会话 → 会话内取号)----
|
||||
func _rng_event_log_session() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」RngService 行 (事件日志落盘会话组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (事件日志落盘会话组)
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(42)
|
||||
rng.open_stream("board_gen")
|
||||
|
||||
@@ -218,7 +218,7 @@ func _test_negative_cases() -> void:
|
||||
# 现行 30;本套件零扩签,钉现行数(将来任何加词即转红提示复核)。
|
||||
|
||||
func _test_effect_kinds_closed() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」effect_engine 行 事件/事实/效果类型/算子四词表封闭(特效闭集组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「满级特效扩展位」 事件/事实/效果类型/算子四词表封闭(特效闭集组)
|
||||
Kit.check("效果引擎效果类型闭集 30 种〔锻造工坊批 V11〕",
|
||||
EffectEngineScript.EFFECT_KINDS.size() == 30)
|
||||
Kit.check("效果引擎事件词表在册 21 种(charge_full 位摘名——蓄力层删键批)〔锻造工坊批 V11〕",
|
||||
|
||||
@@ -77,7 +77,7 @@ func _test_stream_draw_determinism() -> void:
|
||||
|
||||
# 负输入 abs 归一化(警告通道)——|−s| 与 s 同派生
|
||||
func _test_negative_seed_normalization() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」RngService 行 RngService:master_seed 与各流 scope 计数器单点(种子规约组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 RngService:master_seed 与各流 scope 计数器单点(种子规约组)
|
||||
var pos = _fresh_service()
|
||||
var neg = RngServiceScript.new()
|
||||
neg.set_master_seed(-TEST_SEED)
|
||||
|
||||
@@ -22,7 +22,7 @@ func _init() -> void:
|
||||
# 单元宿主改由 `_init` 显式调用,断言逐字未动;源 :70 事件日志落盘条经主会话裁决一
|
||||
# 改判跨系统闭环套件——不随本宿主,见迁移账本转办清单)----
|
||||
func _smoke_initialize() -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「模块归属·基础层」RngService 行 RngService autoload:open_stream 有状态门面与启动初始化(启动流组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 RngService autoload:open_stream 有状态门面与启动初始化(启动流组)
|
||||
print("=== Dungeon Sweeper 垂直切片冒烟 ===")
|
||||
var db = ConfigDBScript.new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true)
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
# 需求卡片——跨表量级护栏批
|
||||
|
||||
> 来源:待办清单「未决问题迁移——零伤害死局跨字段跨表护栏落点」条目(唯一事实源:design/gdd/systems/表现与支撑/数据配置.md v1.4 §核心规则「跨表量级校验」节,:122-134)
|
||||
> 验收档:高(数值表结构校验——失败代价随加载期放行传播进全部战斗)
|
||||
> 估时:0.5–1 个工作日(中值 0.75);超 1 日软盒预挂=T1 夹具注入锚点失效时停机呈报,不扩面自救
|
||||
|
||||
## 1. 目标与完成定义
|
||||
|
||||
在加载期跨表校验通道新增一条量级检查:敌人表每行攻击上界 × 难度表全行攻击乘数最大值,不得超过主角表生命上限字段的取值域上界;越界=加载期校验错误,致命中止。只查取值域之间的量级相容性,不查玩法平衡。
|
||||
|
||||
完成定义:
|
||||
- V1–V6 验收行全部在真实跑批中执行并通过(单元经 cross_validate 真实通道,致命经 ConfigDB.load_tables 正式通道独立进程退出码 1)。
|
||||
- 生产表零误报:现行敌人表 battle/boss 行 atk∈{1,3}(atk_max≤4)、elite 行 atk=2(atk_max=3)、难度表空表,加载诊断零新增 error。
|
||||
- 代码域闸全绿;独立验收审计(高档)通过;reports/ 两份产出物落齐。
|
||||
|
||||
## 2. 设计事实源
|
||||
|
||||
design/gdd/systems/表现与支撑/数据配置.md v1.4:
|
||||
- :122-134 「跨表量级校验:组合数值的上界不得突破目标字段的取值域」节(组合式、上界、越界处置、空表跳过、Boss 不另查、域值归 schemas)。
|
||||
- :104 fail-fast 错误类别表(跨表量级越界在列,加载期收集后致命中止)。
|
||||
- :213-215 验收标准(夹具类别全覆盖+专条判据+致命真的会死)。
|
||||
|
||||
会话裁决沿革查 git 提交 6bfd8009(案A域级判据,用户裁「最底层防护不防玩法内容」)。
|
||||
|
||||
## 3. 现状事实(开工自行复核)
|
||||
|
||||
- F1 跨表校验器七项检查全是引用完整性/池构成类,无量级检查:game/core/config_db_cross_validator.gd:17-24(①–⑦调用链);cross_validate 入口 :8,开头 :12-13 对 status_effects/reward/settlement 缺表早退(单表校验已报错不连锁)。
|
||||
- F2 装载通道:game/core/config_db.gd:102-128 load_tables——逐表 validate 后经 :120 _cross_validate(loaded),:121-124 error 计数 >0 且非 collect_only 即返回 false(游戏通道致命);_cross_validate 门面 :164-165 委托 _validator.cross_validate(loaded, push_diag)。
|
||||
- F3 英雄表域:game/data/schemas/hero_table.gd:16 max_hp 域 [1,999] 以字面量写在 validate 内,无域上界常量。
|
||||
- F4 敌人表攻击字段:game/data/schemas/enemy_table.gd:114-116 atk 基值域 [0,999];:122-135 atk_min/atk_max 可省略配对、区间中点恒等锚。行类字段 row_kind(battle/boss/elite,生产表 game/data/tables/enemy.tres:9/:157/:211 实证)。
|
||||
- F5 难度表:game/data/schemas/difficulty_table.gd:9-10 MULT_MIN=0.1/MULT_MAX=10.0 常量;:26-29 乘数越域产 mult_oor_warning 类别条目;config_db.gd:117-118 将 validate() 条目一律按 error 级外发,故经正式通道越域乘数已拒载,「告警」仅类别名口径;生产表 game/data/tables/difficulty.tres rows=[] 空表。头注 :3「组合事故不作配置事故拒载」——本批把量级组合这一种升格为拒载,头注随批改写(行为载体注释,非 design/ 文档)。
|
||||
- F6 生产表安全余量:enemy.tres battle/boss 行 atk∈{1,3}(atk_max≤4,:16/:309 等)、elite 行 atk=2/atk_max=3(:217-219)、hero.tres:7 max_hp=26——新检查对生产表恒过(空难度表跳过)。
|
||||
- F7 单测先例:game/tests/unit/core/config_db_cross_validator_test.gd:49-87——夹具直构表对象、ValidatorScript.new() 直调、Kit.check 断言、每函数带「判据出处」注记;套件登记 game/tests/run_all.gd:259 expect=0。
|
||||
- F8 致命类先例:game/tests/unit/data_config/reward_dangling_treasure_test.gd:39-56——Kit.copy_tables 复制生产表到 user:// 夹具目录、文本注入违规、ConfigDBScript.new().load_tables(BAD_DIR,false) 正式通道、退出码协议 1=正确拒绝/2=放行回归;登记形态 run_all.gd:178 expect=1 negative=true。
|
||||
- F9 能力清单:game/tests/README.md:206 有「敌人技能池跨表链接校验」行(本批 :207 新增「跨表量级校验」行);:231 数据配置覆盖矩阵行不含跨表量级校验。
|
||||
- F10 gdstyle 基线:tools/gdstyle_baseline.txt 无 config_db_cross_validator.gd 与 hero_table.gd 键(均在默认阈值内);校验器现行 func 总数 14(公开 2:cross_validate/validate_skill_pool_links)。
|
||||
|
||||
## 4. 设计契约(违反即返工,🔴 触碰=L3 停机呈报)
|
||||
|
||||
- 🔴 C1 检查只挂 ConfigDbCrossValidator 跨表通道(经 config_db.gd:120 既有调用链生效);禁另设校验入口、禁在 schema 单表 validate 内做跨表读取。
|
||||
- 🔴 C2 上界取值单点:生命上限域上界常量落 hero_table.gd(schema 是域的唯一声明处),校验器引用该常量;禁在校验器或测试内第二处定义 999 这一域值(测试断言引用同一常量)。
|
||||
- 🔴 C3 只查域相容不查玩法平衡:判据不得引用 max_hp 现行值(26)、不得含任何平衡系数;不得在运行期新增任何行为。
|
||||
- 🔴 C4 Core 零 UI 依赖、无新增随机源、无数值字面量入玩法代码(域常量属 schema 声明面,不属玩法数值)。
|
||||
- 🔴 C5 禁删既有断言、禁放宽阈值;本卡测试削弱申报=无。
|
||||
|
||||
## 5. 范围边界
|
||||
|
||||
做:校验器第⑧项+域上界常量+单元五函数+致命入口测试一件+套件登记+能力表增行。
|
||||
不做(明示去向):
|
||||
- 运行期战斗轮数异常遥测——旧体系备选案,未裁启用,不属本卡;如日后要做另行登记。
|
||||
- 玩法级红线(案B,对比基线现行值×K)——用户已裁淘汰(2026-11-09 会话:最底层防护不防玩法内容)。
|
||||
- difficulty_table.gd 的 mult_oor_warning 行为不动(单乘数越域经装载通道已拒载、类别名不变、使用时 clamp;本批只升格「组合量级」这一种)。
|
||||
- 文档面改动一律走反哺点(见第 6 节),实现批禁写 design/ 与根规则文件。
|
||||
|
||||
## 6. 关联文档同步面
|
||||
|
||||
| 文档 | 关联点 | 同步义务 |
|
||||
|---|---|---|
|
||||
| design/gdd/systems/表现与支撑/数据配置.md v1.4 | 本卡实现其 :122-134 条款,条文无需改动 | 无同步义务(实现核对条文一致即可) |
|
||||
| game/tests/README.md 能力表 | 新增能力行「跨表量级校验」(写卡段同批已增 :207,见本批提交);:231 数据配置覆盖矩阵行补「跨表量级校验」面 | 覆盖矩阵行更新列反哺点,由文档批落 |
|
||||
| design/gdd/systems/冒险循环/难度曲线与Boss.md | 无条文冲突(乘数表空表零行为句与本检查空表跳过一致) | 无关联文档改动 |
|
||||
|
||||
## 7. 文件结构图(卡前定分解)
|
||||
|
||||
| 文件 | 职责 |新增/复用| 行为改动→验收行 |
|
||||
|---|---|---|---|
|
||||
| game/data/schemas/hero_table.gd | 生命上限域上界常量 MAX_HP_DOMAIN_MAX=999+validate 引用 | 复用既有(扩常量) | 是→V1/V2(域值单点) |
|
||||
| game/core/config_db_cross_validator.gd | 第⑧项 validate_attack_magnitude+接线 cross_validate | 复用既有(扩展) | 是→V1–V5 |
|
||||
| game/core/config_db.gd | 零改动(:120 调用链已覆盖新检查) | 复用既有 | 否 |
|
||||
| game/data/schemas/difficulty_table.gd | 头注 :3 改写(量级组合升格拒载);MULT_MIN/MAX 常量被引用,零逻辑改动 | 复用既有 | 否(注释面) |
|
||||
| game/tests/unit/core/config_db_cross_validator_test.gd | 新增五测试函数(V1–V5 单元面) | 复用既有(扩展) | 测试件 |
|
||||
| game/tests/unit/data_config/cross_magnitude_fatal_test.gd | 致命入口测试(V6) | 新增(先例=F8,为什么新增见预检节) | 测试件 |
|
||||
| game/tests/run_all.gd | 登记新致命套件 expect=1 negative=true | 复用既有(增行) | 否 |
|
||||
| game/tests/README.md | 能力表增行(写卡段落,非实现批) | 复用既有 | 否 |
|
||||
|
||||
## 8. 任务卡 T0..Tn
|
||||
|
||||
### T0 域常量与校验器第⑧项(估时 0.25–0.5 日)
|
||||
|
||||
取用:无(首卡)。产出:`HeroTable.MAX_HP_DOMAIN_MAX: int`、`ConfigDbCrossValidator.validate_attack_magnitude(loaded: Dictionary, push_diag: Callable) -> void`(T1/T2 引用逐字一致)。
|
||||
|
||||
- [ ] S13 读数:直跑 gdstyle 对 config_db_cross_validator.gd 与 hero_table.gd 记改前读数(两文件基线无键=默认阈值内;预期改后公开方法 2→3、func 14→≤17,仍阈值内,基线零增键)。
|
||||
- [ ] hero_table.gd 增常量 `const MAX_HP_DOMAIN_MAX := 999`,:16 域检查上界改引常量(语义不变);跑 hero 相关单测最窄确认(config_db_test.gd 全套件直跑,命令见验证闸节)。
|
||||
- [ ] 校验器新增 `func validate_attack_magnitude(loaded: Dictionary, push_diag: Callable) -> void`:取 enemy/difficulty/hero 三表,任一 null 早退(单表已报错不连锁,同 :12-13 先例);难度表 rows 为空早退(数据配置.md:132);乘数上界=全行 atk_mult(缺省 1.0)逐个钳制到 DifficultyTable.MULT_MIN/MULT_MAX 后取最大;逐敌行——row_kind="boss" 跳过(:132),攻击上界=有 atk_max 取 atk_max 否则 atk(:130);乘积 > HeroTable.MAX_HP_DOMAIN_MAX 即 push_diag.call("error", "cross_magnitude", 消息含 enemy_id/行键、乘积值、域上界)。
|
||||
- [ ] cross_validate 在 ⑦(:24)后接线 `_cv_attack_magnitude` 私有包装(缺表早退语义与 ⑤⑥⑦ 同款),第⑧项注释编号沿用既有圈码形态。
|
||||
- [ ] 单测五函数落地(签名与断言见验证闸 V1–V5),经 cross_validate 真实通道驱动(夹具 loaded 字典含三被测表+status_effects/reward 用 new() 空行+settlement 夹具=SettlementTable.new() 且 core=SettlementCoreTable.new(),source_label_map 填齐七必需键 safe_cell/seal_hit/mine_hit/clear_reward/hero_attack/enemy_action/seal_miss(值任意)、effect_pool_map 留空——否则②读 null core 脚本错误、③报 7 条 segorder_violation 污染零错断言,config_db_cross_validator.gd:68/:74-78;此三表过 :12-13 早退门);难度夹具行键=level_index/node_depth/hp_mult/atk_mult(difficulty_table.gd:7 声明面),英雄夹具=HeroTable.new()(检查只读域常量不读现行值);每函数带「判据出处」注记指向数据配置.md 行锚。
|
||||
- [ ] 直跑该单测套件绿(命令见验证闸节),读数写进本步提交。
|
||||
- [ ] difficulty_table.gd 头注 :3 改写:单乘数越域经装载通道按错误拒载(mult_oor_warning 类别)、使用时 clamp;敌攻击×乘数量级组合经跨表校验拒载(指向数据配置 GDD 节名,不写代码路径)。
|
||||
|
||||
### T1 致命入口测试与套件登记(估时 0.25–0.5 日)
|
||||
|
||||
取用:T0 的 `validate_attack_magnitude`(经 load_tables 间接消费,无直调)。产出:`cross_magnitude_fatal_test.gd`(run_all.gd 登记行)。
|
||||
|
||||
- [ ] 新建 game/tests/unit/data_config/cross_magnitude_fatal_test.gd,形态照 F8 先例:Kit.copy_tables("res://data/tables", "user://cross_magnitude_fixture") → 双表注入:enemy.tres 首行三改 `"atk": 1`→`"atk": 500`、`"atk_min": 0`→`"atk_min": 500`、`"atk_max": 2`→`"atk_max": 500`(首个 goblin battle 行锚 :16-18;该行带攻击区间,中点恒等锚 enemy_table.gd:134 要求 atk=(min+max)/2——只改 atk 则单表中点锚报错且跨表检查读上界=atk_max=2 不触发,三改保单表自洽+跨表上界 500)。注入取首现位置:find 定位+substr 拼接(照 F8 先例 substr 形态,reward_dangling_treasure_test.gd:27-30);禁 String.replace 全量替换——同值串遍布全表,且 :334-336/:362-364 行 atk_min=1 会被打破中点锚。difficulty.tres `rows = []` 改 `rows = [{ "level_index": 1, "node_depth": 0, "hp_mult": 1.0, "atk_mult": 3.0 }]`(500×3=1500>999 必触发)。
|
||||
- [ ] 断言协议:ConfigDBScript.new().load_tables(BAD_DIR,false) 返回 false 且 diagnostics 含 category="cross_magnitude" → quit(1);放行或无该诊断 → quit(2);夹具准备失败 → quit(2)。_init 函数体内首行写 `# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:215 …` 注记(照 F8 :40 形态;G 道按函数扫,文件头注不计,capability_audit.py:347-410);文件头注另写明退出码协议。
|
||||
- [ ] run_all.gd 致命类区(:178 邻域)增登记行 `{"path": "res://tests/unit/data_config/cross_magnitude_fatal_test.gd", "expect": 1, "negative": true}`。
|
||||
- [ ] 孤立直跑新套件确认退出码 1,再跑单元测试全套件确认登记生效且既有套件零回归,读数写进本步提交。
|
||||
|
||||
### T2 产出物落位卡(估时含于上两卡,批末执行)
|
||||
|
||||
- [ ] 代码域闸全绿(按 tools/run_all_gates.sh 本批改动域选档)+改前改后 S13 读数对拍(只降不升)。
|
||||
- [ ] reports/iter<N>-实现报告-<日期>.md 写齐:各卡状态+实机目检总清单(本批无玩家可见面,写明「无目检项」)+遗留读数义务+实现决定记录。
|
||||
- [ ] reports/iter<N>-反哺点-<日期>.md:第 6 节覆盖矩阵行更新一条落点写明。
|
||||
- [ ] 独立验收审计(高档,test-conventions §8.7 梯度):没参与实现的会话或子代理执行,报告 reports/iter<N>-验收审计-<日期>.md;未过不得合并。
|
||||
|
||||
## 9. 验证闸(改动—验收对照表)
|
||||
|
||||
| # | 需求点(判据出处行锚) | 改动 | 验收测试(名称+落点+尾缀) | 层级 | 真实入口 | 判据绑定面 | 能力行 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| V1 | 越界组合加载期报错(design/gdd/systems/表现与支撑/数据配置.md:130) | 校验器第⑧项 | _test_magnitude_over_limit报cross_magnitude(夹具敌行 atk=500×难度行 atk_mult=3.0→1500>999;config_db_cross_validator_test.gd,_test_ 尾缀) | 单元 | ConfigDbCrossValidator.cross_validate(loaded,push_diag) | push_diag 收到 severity=error ∧ category="cross_magnitude" ∧ 消息含越界敌行键 | 新增:跨表量级校验 |
|
||||
| V2 | 合法组合与边界等值零误报(design/gdd/systems/表现与支撑/数据配置.md:214) | 同上 | _test_magnitude_legal_and_boundary_zero_error(三组:999×1.0 边界等值/100×2.0 域下/boss 行 atk=999×mult 3.0 豁免) | 单元 | 同 V1 | 三组各零 error;boss 组难度行 atk_mult=3.0 非空(若不跳过 boss 则 2997>999 必报——防空表跳过使豁免断言空转) | 新增:跨表量级校验 |
|
||||
| V3 | 空难度表跳过(design/gdd/systems/表现与支撑/数据配置.md:132) | 同上 | _test_magnitude_empty_difficulty_skipped | 单元 | 同 V1 | 敌 atk=999+难度 rows=[] 零 error | 新增:跨表量级校验 |
|
||||
| V4 | 区间取上限(design/gdd/systems/表现与支撑/数据配置.md:130) | 同上 | _test_magnitude_range_uses_atk_max | 单元 | 同 V1 | atk=350/atk_min=100/atk_max=600+乘数 2.0 → 报(600×2=1200>999);atk=250/atk_min=100/atk_max=400 → 零错(400×2=800);两组 atk 均满足区间中点恒等锚(enemy_table.gd:134) | 新增:跨表量级校验 |
|
||||
| V5 | 越域乘数按域边界值计(design/gdd/systems/表现与支撑/数据配置.md:130) | 同上 | _test_magnitude_mult_clamped_to_domain | 单元 | 同 V1 | atk=100+atk_mult=50.0(钳制 10.0)→ 报(100×10=1000>999);atk=99+同乘数 → 零错(990) | 新增:跨表量级校验 |
|
||||
| V6 | 致命真的会死(design/gdd/systems/表现与支撑/数据配置.md:215+:104) | 第⑧项经装载通道 | cross_magnitude_fatal_test.gd:_init(独立进程,expect=1 negative=true) | 单元(致命协议) | ConfigDB.load_tables(BAD_DIR,false) 正式通道 | 进程退出码 1 ∧ load_tables 返回 false ∧ diagnostics 含 cross_magnitude | 新增:跨表量级校验 |
|
||||
|
||||
- 验证命令:单元套件直跑 `D:\code\godot\Godot_v4.7.2-stable_win64_console.exe --headless --path game --script res://tests/unit/core/config_db_cross_validator_test.gd`;致命套件同形换路径;全套件 `--script res://tests/run_all.gd`。
|
||||
- 测试方式两分法:V1–V6 全归调试夹具直构/夹具注入(能力验证);本批无玩家可见面,用户目检项=无。
|
||||
- 回归措辞:T 段出口跑一次覆盖改动面的套件;修复只做出红最小单元的最窄确认;新增测试先行孤立验证再并入全套。
|
||||
- 测试削弱申报:无(不删不改既有断言)。
|
||||
- 独立验收审计:入口=T2 第三步;报告 reports/iter<N>-验收审计-<日期>.md;高档梯度(test-conventions §8.7)。
|
||||
|
||||
## 10. 异常分级
|
||||
|
||||
- L1 自救:夹具注入锚点失配一次重试(换次处 battle 行块,三改随该行实际区间值对齐中点锚)。
|
||||
- L2 记录继续:导入缓存类在册环境坑按坑册处置。
|
||||
- L3 停机写报告等用户:🔴 契约触碰;机检预算互斥=上游缺陷停卡退回写卡段;夹具双注入仍无法触发(生产表面貌漂移)停卡呈报。
|
||||
|
||||
## 11. 代拍板白名单
|
||||
|
||||
- 错误消息文案措辞(须含行键/乘积/域上界三要素)。
|
||||
- 夹具 user:// 目录名与私有包装函数名(_cv_attack_magnitude 形态)。
|
||||
- 超清单事项记实现报告「实现决定记录」节。
|
||||
|
||||
## 12. 待裁点
|
||||
|
||||
零待裁点,开工门=U0。(落点/判据/处置三裁已在 2026-11-09 会话闭合,git 6bfd8009 可考。)
|
||||
|
||||
## 13. 落位与可复用性预检
|
||||
|
||||
| 新增件 | 复用面核查 | 唯一面 | 分层与交互 |
|
||||
|---|---|---|---|
|
||||
| validate_attack_magnitude(校验器新公开方法) | grep 全库无量级组合检查(跨表校验器七项全引用/池类,F1);量级检查职责归跨表校验器唯一宿主,不在 schema 单表层做跨表读取 | 检查逻辑只此一处;域上界常量只在 hero_table.gd | ConfigDB.load_tables→_cross_validate→cross_validate→第⑧项;push_diag 外发诊断,Core 零 UI |
|
||||
| MAX_HP_DOMAIN_MAX(hero_table.gd 常量) | 现行域上界 999 只存在于 validate 字面量(F3),提常量即收编单点,非第二处定义 | validate 与校验器同引一常量 | schema 声明面,供校验器只读 |
|
||||
| cross_magnitude_fatal_test.gd(新文件) | 既有致命套件各钉一类违规(reward_dangling_treasure/counter_prefix 等,F8/F9),无「量级组合」套件可扩展;致命协议要求独立进程独立文件(run_all.gd:15 协议注) | 退出码协议与 Kit.copy_tables 复用 test_kit,不复制其实现 | 经 ConfigDB.load_tables 正式通道,与生产加载同路径 |
|
||||
| 单测五函数 | 扩展既有 config_db_cross_validator_test.gd(F7),不另立新文件 | 夹具直构形态沿用该件 _skill/_enemy 先例,新增 _difficulty/_hero 夹具协函数同文件内 | 经 cross_validate 真实通道 |
|
||||
|
||||
## 14. 实现规范预算
|
||||
|
||||
- config_db_cross_validator.gd:无新文件;公开方法 2→3(≤20);类变量 0 新增(≤15);新函数 validate_attack_magnitude 分支预算 ≤8(缺表早退/空表早退/boss 跳过/区间取值/越界判定,实装超 8 即拆私有协函数)、返回 ≤6;func 总数 14→≤17。基线无键(F10),改后仍阈值内=零增键。
|
||||
- hero_table.gd:增一常量,validate 逻辑分支不变;基线无键,零增键。
|
||||
- 新文件 cross_magnitude_fatal_test.gd:公开方法 ≤1(_init)、类变量 ≤6(常量preload与目录名)、分支 ≤8(照 F8 先例四出口)——全在默认阈值内,无指标例外申报。
|
||||
- 存量触面一查:T0 S1 步骤记改前读数,S13 键较登记值只降不升(本批无基线键变动预期)。
|
||||
|
||||
## 15. 拆分边界纪律
|
||||
|
||||
本批非拆分/重构类(扩展既有件+一新测试件),无拆出单元;第 13/14 节条款照列备查:禁为机检文本保留无效成员;机检键与卡片契约互斥=停卡呈报。
|
||||
|
||||
## 16. 复核记录
|
||||
|
||||
复核形态:第 1 轮=未参与本卡撰写的只读子代理对抗复核(2026-11-09,审点按 req-card 技能 grilling 门全清单:三问/对照表两端/真实入口/绑定面、夹具钉值与空转、落位预检×结构图互指、预算实数、判据出处行锚逐行实读、引擎技术面三查〔godot-master hub NEVER/Gotchas/预算表已加载,领域 reference 未加载——Resource 面为 F8 先例同形〕、T 卡粒度/接口逐字/禁行句式、范围边界与两道机检相容)。复核前作者已跑自审七查,就地修复已并入卡正文:V1/V2/V4 夹具取值钉死、V2 boss 组难度非空防豁免空转、V4 夹具满足中点恒等锚、T1 首行三改(只改 atk 则上界读 atk_max=2 不触发)、V6/T1 判据锚 :214→:215、F6 生产表 atk 枚举修正。复核者总结论:无待裁类、无退回上游类;七条补写全部回填后可进入提交流程。复核凭据=本节自身,不另设报告文件(2026-11-06 用户裁)。
|
||||
|
||||
| 轮次 | 复核者身份 | 发现 | 去向 | 处置结果 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 只读子代理(未参与本卡撰写) | T0 S5 settlement「空表对象」按字面直构:core=null 致②null 访问脚本错误;core 补齐后③缺七必需键报 7 条 segorder_violation 污染零错断言 | 补写 | T0 S5 已改写:settlement 夹具 core=SettlementCoreTable.new()、source_label_map 填齐七键、effect_pool_map 留空(依据 config_db_cross_validator.gd:68/:74-78、settlement_table.gd:10、settlement_core_table.gd:8) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | F5/§5/T0 S7「乘数越域仅告警」表述失准——装载通道把 validate() 条目一律按 error 级外发,越域乘数已拒载 | 补写 | 三处已改写为「经装载通道按错误拒载、类别名 mult_oor_warning 不变、使用时 clamp」(依据 config_db.gd:117-118/:121-124);V5 走 cross_validate 直调不受影响 |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | T1 注入机制未钉死:String.replace 全量替换会打破他行中点锚(:334-336/:362-364 行 atk_min=1) | 补写 | T1 S1 已增「首现位置 find+substr 拼接、禁 String.replace 全量替换」(依据 enemy.tres:334-336/:362-364 实读;F8 先例 reward_dangling_treasure_test.gd:27-30 substr 形态) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | F9/§6 覆盖矩阵行锚 :230 失位——本批 :207 插入新能力行后数据配置行实为 :231 | 补写 | 两处已改 :231(README 实读核位) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | §1/F6「battle/boss 行 atk=1」枚举不全——后段行 atk=3/atk_max=4 | 补写 | 两处已改 atk∈{1,3}(atk_max≤4)(依据 enemy.tres:309/:445/:505 等实读);零误报结论不变(空难度表跳过) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | T1 S2 判据出处只写文件头注不计——G 道按函数体扫描,_init 含 push_error 属验证函数 | 补写 | 已改「_init 函数体内首行写判据出处注记、文件头注另写退出码协议」(依据 capability_audit.py:347-410;F8 :40 先例形态) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | §16 占位句「节末申报复核报告落盘路径」为过期指令(2026-11-06 已裁不另设报告文件) | 补写 | 回填本节时已删该句;凭据=本节自身(req-card 必备结构第 17 节;pipeline_gate.py check_review :650-687 不查报告文件) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | V3 零错判据不能区分「空表跳过」与「缺省乘数 1.0」两种实现 | 自判 | 不改:敌 atk 域 [0,999]×1.0 恒 ≤999,两实现可观测面等价;V3 绑可观测契约仍抓空最大值崩溃与错误缺省 >1(依据 enemy_table.gd:115;req-card 判据绑定面口径只要求绑可观测提交面) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | F1 锚 :17-24 含一行 helper 调用(①–⑦链实在 :18-24) | 自判 | 不改::17 为 _effect_ids_of 调用,范围覆盖调用链、内容匹配,一行偏差不影响核对(config_db_cross_validator.gd:17-24 实读) |
|
||||
| 1 | 只读子代理(未参与本卡撰写) | 既有单测件判据注记锚指 数据配置.md:195 已漂移(历史遗留,非本批改动面) | 自判 | 不改:本批只增函数不触既有注记;G 道只查行号越界不查内容(capability_audit.py:401-403);日后触及该件另登记 |
|
||||
@@ -339,7 +339,7 @@ def check_coverage(cov_tables, names):
|
||||
red(README.relative_to(REPO), 1, "覆盖域表", "%s 未在覆盖域表登记" % doc)
|
||||
|
||||
|
||||
CRITERION_RE = re.compile(r"^#\s*判据出处:\s*(\S+?\.md)(?::(\d+)|「([^」]+)」)\s*\S")
|
||||
CRITERION_RE = re.compile(r"^#\s*判据出处:\s*(\S+?\.(?:md|gd))(?::(\d+)|「([^」]+)」)\s*\S")
|
||||
VERDICT_RE = re.compile(r"(?<![_\w])check(?:_quiet)?\(|_problems\.append\(|push_error\(")
|
||||
CRITERION_FUNC_RE = re.compile(r"^(?:static\s+)?func\s+([A-Za-z_]\w*)")
|
||||
|
||||
@@ -391,8 +391,9 @@ def check_criterion_markers():
|
||||
marked += 1
|
||||
for m in oks:
|
||||
relp, no, sec = m.group(1), m.group(2), m.group(3)
|
||||
if not relp.replace("\\", "/").startswith("design/"):
|
||||
red(rel, s0 + 1, "判据出处注记", "%s 指针越出 design/ 全域:%s" % (name, relp))
|
||||
_rp = relp.replace("\\", "/")
|
||||
if not (_rp.startswith("design/") or _rp.startswith("game/sim/")):
|
||||
red(rel, s0 + 1, "判据出处注记", "%s 指针越出 design/ 与测量面全域:%s" % (name, relp))
|
||||
continue
|
||||
tp = REPO / relp
|
||||
if not tp.is_file():
|
||||
@@ -403,7 +404,7 @@ def check_criterion_markers():
|
||||
red(rel, s0 + 1, "判据出处注记", "%s 指针不可核:%s:%d(行号越界)" % (name, relp, int(no)))
|
||||
elif sec is not None:
|
||||
# 节锚(2026-11-07 架构收窄批立,test-conventions §8.3):核验节名首段(「·」前)
|
||||
# 在所指文档中出现——「模块归属·基础层」核「模块归属」节标题在档;关键词不核(随文档措辞漂移由人审兜)
|
||||
# 在所指文档中出现——节名首段为「·」前的标题词(如「统一随机流」),标题在档即过;关键词不核(随文档措辞漂移由人审兜)
|
||||
head = sec.split("·")[0]
|
||||
if head not in read(tp):
|
||||
red(rel, s0 + 1, "判据出处注记", "%s 节锚不可核:%s「%s」(文档内无该节名首段)" % (name, relp, head))
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
本清单是流水线的唯一登记处:以后才做的事在此登记一条,随流水线段推进改状态,做完整条删除(条目记进度,不是各段的开工前置);各系统文档的「待办」节只留一行指路存根,不再自建条目。条目格式(标题=登记元数据含可选优先级,正文=实况/缺口/改动面/状态四属性)与状态机以 [doc-conventions §12.1](design/engineering/doc-conventions.md) 为权威。
|
||||
|
||||
#### 架构文档收敛第二批——依赖规则形态(2026-11-09 登记,来源=会话提及)
|
||||
|
||||
**实况**:方案经用户批准(模块归属表目录化+API 边界表删除+29 处判据锚迁 GDD/规约规范源+四文档引用改指+架构图同步);分层依据=依赖方向、目录=层级承载、同目录同层级同约束。证据=design/engineering/doc-conventions.md 架构事实唯一源行(只写约束面条款)+用户 2026-11-09 会话裁决。
|
||||
**改动面**:文档+游戏代码+工具代码
|
||||
**状态**:待执行
|
||||
|
||||
#### 写卡段判据锚钉防漂——易漂移文档改用节锚(2026-11-09 登记,来源=批次移交)
|
||||
|
||||
**实况**:迭代 56 卡1 复核轮钉死的 ux/battle.md 行锚(:199/:272/:347)被同日「顶栏搬两侧」文档批修订冲漂(真锚 :200/:364/:439)——行锚钉死后同日文档批仍会冲漂;test-conventions §8.3 已有节锚两档机制(2026-11-07 架构收窄批立的防漂移机制)。
|
||||
@@ -39,9 +45,9 @@
|
||||
|
||||
#### 未决问题迁移——零伤害死局跨字段跨表护栏落点(2026-11-07 登记,来源=批次移交)
|
||||
|
||||
**实况**:原 architecture.md「未决问题」QQ-12(git 历史可考,架构收窄批迁出)。设计定稿:design/gdd/systems/表现与支撑/数据配置.md v1.4(2026-11-09,跨表量级校验节——域级判据,加载期致命)。
|
||||
**实况**:原 architecture.md「未决问题」QQ-12(git 历史可考,架构收窄批迁出)。设计定稿:design/gdd/systems/表现与支撑/数据配置.md v1.4(2026-11-09,跨表量级校验节——域级判据,加载期致命)。需求卡片:reports/需求卡片-跨表量级护栏批-2026-11-09.md(复核记录节在卡,对抗复核一轮 10 发现全处置:7 补写回填+3 自判不改)。
|
||||
**改动面**:文档+游戏代码
|
||||
**状态**:文档设计已闭合
|
||||
**状态**:文档设计已闭合+已写卡
|
||||
|
||||
#### 未决问题迁移——A1 EC5 运行期熔断(2026-11-07 登记,来源=批次移交)
|
||||
|
||||
|
||||
Reference in new issue
Block a user