merge: 同步 master e92a18e1(卡片落位 reports/+dev→engineering 改名批)——四处版本历史节冲突取本批删除侧,reports 卡片重放禁写变更记录清理,06b 闸扫描面扩 reports/
This commit is contained in:
commit
8a68c9ea11
116 files changed
+253
-2660
No files matched your search
@@ -0,0 +1,373 @@
|
||||
# Dungeon Sweeper — 总体架构文档
|
||||
|
||||
## 文档状态
|
||||
|
||||
- 版本:1.8
|
||||
- 最近更新:2026-10-17(迭代 27/28 GDD 反哺点写入——新增「呈现层装配与会话生命周期」节(视觉层装配合同/三屏壳/RunScope 生命周期与存活性矩阵/ModalFlow tags 协议)、战斗域现状补结算五段与 RunLedger 四账、初始化顺序补启动后置条件六条,均 2026-10-17 用户裁按推荐案写入;实现实证行读数换代)
|
||||
- 引擎: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)均已立项成文
|
||||
- 事实源地位:本文是架构事实的唯一来源——分层/所有权/数据流/API 边界/测试与质量域均以本文为准;历史决策沿革查 git commit log,不另设决策文档体系
|
||||
- 实现实证:`game/`(2026-09-10 起开发,**现为完整游戏开发版本,已非垂直切片**;迭代 29 已入库合并——冒烟 1127/0、单元 33 套(含 1 集成)、重闸按改动域分跑在役)——本文档的分层/所有权/数据流均经实现验证,非纯纸面设计
|
||||
- 技术总监签核:2026-09-12 — 有条件通过(原条件「决策记录须于正式工程骨架前定稿」已满足:骨架已成、沿革在 git 历史可查;`.claude/docs/director-gates.md` 缺失已登记技术债)
|
||||
- 主程序可行性:跳过 — solo 模式
|
||||
|
||||
---
|
||||
|
||||
## 引擎知识缺口摘要
|
||||
|
||||
- **风险等级:MEDIUM**(2026-09-12 `/setup-engine refresh` 后由 HIGH 降级)。4.5→4.7 官方迁移指南已逐条核实并入 `design/engineering/engine-reference/godot/breaking-changes.md` 与 `deprecated-apis.md`;**结论:无一条破坏 GDD 已锁架构契约**(autoload 体系 / .tres 单一事实源 / Callable 信号 / int64 二补数 / headless SceneTree 协议均不受影响)。
|
||||
- 写码纪律不变:不确定的 API 一律查 `docs.godotengine.org/en/4.7/` 核实后再用;4.8(dev 阶段)稳定版发布后跑 `/setup-engine refresh`。
|
||||
- 三类必须入编码纪律的引擎事实(详见 `design/engineering/engine-reference/godot/current-best-practices.md`):
|
||||
1. **GDScript 4.7 两条语义变化**:打包数组元素赋值不再触发属性 setter;类型化返回的方法覆盖必须显式 `return`。
|
||||
2. **新项目默认值已变**:stretch mode `canvas_items` / aspect `expand`(4.7);Windows 渲染驱动 D3D12(4.6,仅 Forward+ 线)——创建 project.godot 后逐项核对。
|
||||
3. `Resource.duplicate(true)` 深复制不再覆盖外部子资源——D2 表资源复制语义注意。
|
||||
- 残余风险敞口:modules/ 分域参考未建(按实现期需要建,非阻塞);UI/渲染域(D1/B5)为 MEDIUM 风险集中地——渲染器与窗口基座已定(gl_compatibility + 1280×800,2026-09-12),采纳引擎增量前对照文档核实。
|
||||
|
||||
---
|
||||
|
||||
## 系统分层图
|
||||
|
||||
20 系统按 `design/gdd/02-系统清单.md` 依赖分层表映射到标准五层。实现已验证该分层(core/ 纯逻辑零 UI 依赖 headless 可跑、presentation/ 组合根模式)。
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ 呈现层 │
|
||||
│ D1 HUD 与界面框架 (MVP) · B5 战斗表现 │
|
||||
│ D4 音频 (Beta) · D5 教学引导 (Beta) │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ 功能层 │
|
||||
│ B1 战斗结算编排 (MVP) · C1 关卡节点地图 (lite 已实装) │
|
||||
│ C2 冒险结构 · C3 难度曲线 · C4 元进度 (Alpha) │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ 核心层 │
|
||||
│ A1 扫雷棋盘生成 · A2 排雷玩法规则 · B2 敌人系统 │
|
||||
│ B4 地图战斗资源 · A5 扫雷秘宝 │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ 基础层 │
|
||||
│ D2 数据配置与数值表 · A3 行动经济 · A4 地形变异 │
|
||||
│ B3 增益/状态系统 · D3 存档序列化 (Alpha) · D6 设置/本地化│
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ 平台层 │
|
||||
│ Godot 4.7.2 引擎 API 面(GDScript / Resource / │
|
||||
│ SceneTree / Control / InputEvent)——无游戏系统 │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
> 层名对照:基础层=Foundation、核心层=Core、功能层=Feature、呈现层=Presentation、平台层=Platform——本文一律用中文名;跨文档与代码目录仍见英文名(`game/core/`、`game/presentation/` 等目录名不改)。
|
||||
|
||||
| 系统 | 层 | 里程碑 | headless 约束 | 引擎风险域 |
|
||||
|---|---|---|---|---|
|
||||
| D2 数据配置 | 基础层 | MVP | ✅ 完整可跑 | LOW(Resource/.tres 基线稳定) |
|
||||
| A3 行动经济 | 基础层 | MVP | ✅ 完整可跑 | LOW(纯逻辑) |
|
||||
| A4 地形变异 | 基础层 | MVP | ✅ 完整可跑 | LOW(纯逻辑) |
|
||||
| B3 状态系统 | 基础层 | MVP | ✅ 完整可跑 | LOW(RefCounted 纯逻辑) |
|
||||
| A1 棋盘生成 | 核心层 | MVP | ✅ 完整可跑 | LOW(纯逻辑) |
|
||||
| A2 排雷规则 | 核心层 | MVP | ✅ 完整可跑 | LOW(零表读取零 UI) |
|
||||
| B2 敌人系统 | 核心层 | MVP | ✅ 完整可跑 | LOW(纯逻辑) |
|
||||
| B4 地图战斗资源 | 核心层 | MVP | ✅ 完整可跑 | LOW(纯逻辑) |
|
||||
| B1 战斗结算编排 | 功能层 | MVP | ✅ 完整可跑(禁 await) | LOW(纯逻辑) |
|
||||
| C1 关卡节点地图 | 功能层 | MVP(切片期实装) | ✅(切片 level_runner 先例) | LOW |
|
||||
| C2 冒险结构 | 功能层 | MVP(切片期实装) | ✅ | LOW |
|
||||
| C3 难度曲线 | 功能层 | MVP(切片期实装) | ✅ | LOW |
|
||||
| C4 元进度 | 功能层 | Alpha | ✅ | LOW |
|
||||
| D1 HUD | 呈现层 | MVP | ❌(UI 层——场景级探针测试承载) | **MEDIUM**(Control/Input/文本域) |
|
||||
| B5 战斗表现 | 呈现层 | 切片后立项(未实装,前置战斗表现美术测试) | ❌ | **MEDIUM**(Animation/Tween/渲染) |
|
||||
| D4 音频 / D5 教学 | 呈现层 | Beta(2026-10-13 Alpha 版本标准裁:与游戏内容无关者一律排 Beta) | 部分 | LOW-MEDIUM |
|
||||
| D3 存档序列化 | 基础层 | Alpha | ✅ | LOW |
|
||||
| D6 设置/本地化 | 基础层 | 完整愿景 | ✅ | LOW |
|
||||
|
||||
**MVP 关键路径**(实现已验证):D2 → A3/A4/B3 → A1 → A2 → B2/B4 → B1 → D1-lite。
|
||||
**依赖分层与唯一回边**:A2 只外发三事件(cell_revealed / flag_judged / round_end),B4/B1 订阅后回调——A2 不依赖任何下游(TD-SYSTEM-BOUNDARY 裁决,全项目唯一允许回边)。
|
||||
|
||||
---
|
||||
|
||||
## 模块归属
|
||||
|
||||
> 命名遵循 `design/engineering/code-conventions.md`:领域命名、禁 ID 前缀(文件头注不写文档链接——「实现 GDD:xxx」一类已废止,代码↔设计追溯由 GDD 文档承担)。切片已按此规范完成领域命名批。
|
||||
|
||||
### 基础层
|
||||
|
||||
| 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API |
|
||||
|---|---|---|---|---|
|
||||
| **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 | 无 |
|
||||
| **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 |
|
||||
| **settings/localization**(D6,愿景) | 设置项、翻译数据 | (契约规范源:`../../gdd/systems/表现与支撑/设置与本地化.md`) | ConfigDB | 无 |
|
||||
|
||||
### 核心层
|
||||
|
||||
| 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 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 批) | 无 |
|
||||
| **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/战末 adventure 计数器导出回写)+ 树规则挂点施加面(posture 窗/sense 限次/守侧 flag_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 冒烟实证可回放) |
|
||||
| **effect_engine**(核心层——内容数据驱动扩展批 iter17 建域) | 事件/事实/效果类型/算子四词表封闭(迭代 21 T3 扩签:EVENTS 18→19 +flag_missed 标错判定、FACTS +battle_index 关卡域战斗序)+ 树规则合成订阅六键(posture 每关首轮窗/sense 两组限次 counter 闸·domain=adventure 跨战斗持久) | rebuild(每战重建)/dispatch/validate_trigger_row/counters_export·counters_seed | ConfigDB(feats/treasure 行集) | 无(零随机全确定) |
|
||||
| **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 | 无 |
|
||||
| **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 | 无 |
|
||||
|
||||
### 战斗域装配现状(迭代 27——2026-10-17 用户裁写入)
|
||||
|
||||
- **结算五段**:B1 编排器的每轮结算序列拆为 `game/core/settlement/` 五个段类——GrantSegment(①授予段,含封印判定与 counter/grant 助手单点)→ AuraSegment(②增益/减益段)→ CombatSegment(③战斗段)→ DecaySegment(④衰减段)→ VerdictSegment(⑤判定段,返回裁定,终局早退语义留 B1)。段序骨架冻结于 `SettlementTable.segment_order` 语义,B1 退为段序编排+接线;段类可直接 `new()` 单测(`settle_segments_test` 在役)。
|
||||
- **RunLedger 四账**:`game/core/run_ledger.gd` 单类持四本共享账——同调充能账/真视使用计数/冒险域计数器/统一冒险加算区。所有权:AdventureRunner 开局构造、全程唯一宿主;LevelRunner 经 `set_run_ledger` 下传装配 encounter;战斗侧(B1)经 `encounter["ledger"]` 拿引用、只走 read/append 原语族。审计 P1-4「共享可变字典跨三层三处可写」由「函数签名上不可见的共享引用」换成签名可见的显式类,时点语义(战末导出/开局回灌)逐字不变。
|
||||
|
||||
### 呈现层
|
||||
|
||||
| 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API |
|
||||
|---|---|---|---|---|
|
||||
| **D1 HUD**(呈现面拆分持续换代:组合根 main.gd + 三屏壳(MenuScreen/CampScreen/AdventureScreen)+ views/ 视图单元(现行承载面见「呈现层装配与会话生命周期」节;早期 9 单元清单与 LevelStripView 已随场景换代退役);营地覆盖层=四柜台并排〔树淬炼主界面/锻造工坊·秘宝匣钥匙门/图鉴常开——迭代 21 T6 程序占位重排〕) | 全部 Control/CanvasLayer(例外:BoardView 棋盘本体与 BattleStageView 站桩本体 = Control 壳 + SubViewportContainer + SubViewport + Node2D 世界〔BoardWorld/CellUnit;StageWorld/StandeeBody——B 区 slot_row 伴随件留壳层〕,探针契约面不变——棋盘 Node2D 迁移批 Phase A 2026-09-23 / 战斗舞台 Phase B 2026-09-26)、输入→意图翻译(**唯一提交路径 = settle_batch,不直调 A3**)、呈现义务状态记录(A2×6 / B2×4 / B3×4 / B4×5 / B1×3) | 视图单元接口(信号外发、setter 只读注入) | A2 compute_move_path / ActionOutcome;A3 ap/rap;B1 步骤流行协议(数据源);ConfigDB display_name | **MEDIUM**:Control / CanvasLayer / draw_* / InputEvent / RichTextLabel——对照 breaking-changes.md 4.5–4.7 条目(CanvasItem 线条无抗锯齿羽化、设备 ID 常量、RichTextLabel 图片参数两轮变化) |
|
||||
| **battle_presentation**(B5,垂直切片后) | 结算动画 / 伤害数字 / 战斗舞台 | (契约规范源:`../../gdd/systems/战斗循环/战斗表现.md`——前置「战斗表现美术测试」锁双舞台陷阱) | B1 步骤流(回放脚本源)、D1 | **MEDIUM**:AnimationPlayer(String→StringName 变更)/ Tween |
|
||||
| **audio**(D4,Alpha) | 音频挂点 | (挂点 = B1 明细行类型流;负反馈聚合——单结算至多一次) | B1 流水 | AudioStreamPlayer(4.7 area_mask 默认 1→0 注意) |
|
||||
| **tutorial**(D5,Alpha) | 教学条目 | (口径来源:A2/A3/B3/B1 各教学条目) | 各上游 | 无 |
|
||||
|
||||
**依赖单向性**:上层可消费下层,禁止反向(C3 禁调用 A1 生成、D1 不直调 A3、A2/B3/B4 零相互直调)。全项目唯一回边 = A2 事件订阅面。
|
||||
|
||||
---
|
||||
|
||||
## 呈现层装配与会话生命周期(迭代 27/28 完成反哺——2026-10-17 用户裁按推荐案写入)
|
||||
|
||||
### 三屏壳与组合根句柄面
|
||||
|
||||
- 呈现场景拆为三屏壳:MenuScreen(开始菜单屏)/CampScreen(营地屏)/AdventureScreen(冒险屏——内含关卡地图与战斗两容器)。
|
||||
- 屏成员经组合根 main.gd 一级句柄暴露(探针挂载假设 `main.X` 路径零迁移);局态一律住 RunScope 节点,禁在屏/视图侧持有局态引用。
|
||||
|
||||
### 视觉层装配合同
|
||||
|
||||
- **树序 = 登记序 = z 序**,同源派生;层序唯一事实源 = `main.gd` 的 `LAYER_CONTRACT` 常量表(现行 17 项,kind 五类:shell=屏壳〔成员随壳不占独立树位〕/modal=模态层〔入登记册,tags 随登记〕/state=全屏态/node=非视觉节点/float=不注册 ModalStack 的最顶浮层〔任何 UI 打开都不遮挡它〕)。
|
||||
- 全仓唯一落位口 = `_apply_layer_contract()`(装配尾统一排序+登记);散落 `move_child` 由冒烟 V1d 源码断言判红;**改层序只改合同表**。
|
||||
- 具体层清单不复制进本文(双写失同步禁令)——查现行 17 项直接读 `main.gd`。
|
||||
|
||||
### 会话生命周期(RunScope)
|
||||
|
||||
- `run_scope.gd` = 纯状态承载 Node:零信号连接、零视图构建、零核心写调用(连接只在组合根,组合根经 `run_scope.X` 读写)。
|
||||
- 会话更替机制:`_begin_session()` 新建会话节点挂树、旧会话节点**整节点 `queue_free()`**——无独立收束函数,跨局字段清理靠节点释放机制(原手工复位清单随其消亡,新增跨局字段零新增泄漏点);`_ready` 即建闲时会话,`run_scope` 永非 null。
|
||||
- **存活性矩阵**(九阶段 × 五引用面,2026-10-17 用户裁认账阶段划分;执行判据=冒烟 V3a–V3i。计划书原十阶段中「开局停点」与「地图选路」在现行流程同为关卡画面停点态、无可观测中间态,合并为一处断言):
|
||||
|
||||
| 阶段 | run_scope | adventure | runner | settlement |
|
||||
|---|---|---|---|---|
|
||||
| ① 闲时 | 在树(闲时会话) | null | null | null |
|
||||
| ② 开局停点 | 在树 | alive | alive | null |
|
||||
| ③ 战斗中 | 在树 | alive | alive | alive |
|
||||
| ④ 结算后(胜利停点)/⑤ 选路页 | 在树 | alive | alive | both |
|
||||
| ⑥ 终局面 | 在树 | alive | alive | null |
|
||||
| ⑦ 回菜单收束 | 新闲时会话即刻在树(旧会话已释放——无真空窗) | null | null | null |
|
||||
| ⑧ 各模态开合后(设置/生涯/营地/调试) | 闲时会话零扰动 | null | null | null |
|
||||
| ⑨ 两连局+续玩断点 | 换全新会话在树 | alive | both | both |
|
||||
|
||||
- 三态记号沿用冒烟参数:**alive**=应有实例、**null**=必须缺位(实测非空判红)、**both**=按分支可空可活(如胜停点后走向选路或直接终局)。对象有值但已失效一律判「悬挂」红。
|
||||
- 第五引用面=四持句柄件(`_treasure_ui`/`_bonus`/`_camp_pres`/`_modal_flow`,另有 `_row_pacer`):其会话取值 Callable 与 `run_scope` 成员**逐面同源比对**(回调悬挂=两值不等即红),会话更替零残留由矩阵每阶段顺带铁证。
|
||||
|
||||
### 模态编排(ModalFlow/ModalStack)
|
||||
|
||||
- `modal_flow.gd` = 模态编排纯逻辑类(依赖仅 ModalStack + 查询 Callable,可直接 `new()` 单测):开合编排(遮挡记账单口 + T17 演播后排窗挂起)/棋盘输入锁谓词/角标置灰谓词三职责。
|
||||
- 互斥排除语义随层登记(`register(node, tags)`):`debug_overlay=["non_locking"]`、`level_screen=["screen_state"]`,其余层零标签——原调用点排除式条件拼装已消亡。
|
||||
|
||||
---
|
||||
|
||||
## 测试与质量域
|
||||
|
||||
> 定位:本节为测试域(本地闸、探针、静态扫描等横切关注点)的**事实源**。仓库无远端、无 CI——本地闸是唯一验收门禁,判定严密性即全仓质量下限。
|
||||
|
||||
### 模块归属
|
||||
|
||||
| 模块 | 载体 | 独占职责 | 对外暴露 | 判定口径 |
|
||||
|---|---|---|---|---|
|
||||
| **run_smoke**(系统级断言面) | `tools/run_smoke.py` | 冒烟总入口与判定权:headless 跑 `res://smoke/smoke_all.gd` 全量(轻闸首项,迭代 28 后在册 1125 项检查)+ 三闸判定 | 进程退出码(0=PASS / 1=FAIL) | 三闸齐备、判定无洞:①退出码 = 0;②摘要行「冒烟完成:N 项检查,0 项失败」在案且失败数为 0;③输出扫 `SCRIPT ERROR` / `Parse Error` 标记行。外部 wall-clock 超时在位(超时 = FAIL) |
|
||||
| **run_all**(单元套件+L2 集成) | `game/tests/run_all.gd` | 33 套统一入口(32 单元/集成 + 见下):套件 manifest 逐条「套件 → 期望退出码」,致命类 expect=1 独立子进程实跑;`negative` 字段标负面套件(仅豁免错误扫描一闸) | 逐套件结果 + 汇总退出码(任一套件失败 quit(1)) | 套件级退出码协议在位;三硬闸齐备(入口内扫子套件输出 + 编排层扫 `unit.log`;`Kit.finish` 零断言返回专用码 2)。子进程输出须经系统命令解释器重定向落盘再读——`OS.execute` 的输出管道在本机恒空 |
|
||||
| **probe_gate**(场景探针) | `tools/probe_gate.sh` | headless 场景探针段编排:默认段 ui_input_probe / ui_struct_probe / layout_probe / ui_contrast_probe / **screen_flow_probe**(L3 屏壳切换),`--click` 加跑 ui_click_probe,`--full` 加跑 ui_probe / ui_tune_probe / t17_defer_probe / fx_probe;孤儿 Godot 预清 + 批末残留清点(必须 0) | 段级 FAIL 输出 + 汇总退出码 | 每段 timeout 守卫在位(挂死 124/137 = FAIL,不静默);判定统一走 `verdict` 函数——退出码为唯一权威判据,PASS 串降级为附加判据,逐段跑 `tools/error_scan.py` |
|
||||
| **render_gate**(视觉 golden) | `tools/render_gate.sh` | 窗口化渲染闸:①shot_probe 七屏截图 → shot_checker A-D 语义断言;②fx_shot_probe / board_shot_probe 取证(超时/零字节/文件缺失任一 = FAIL);③棋盘 golden 逐像素容差比对(差 ≤16 / changed ≤2%,provisional)+ 菜单 golden;④批末孤儿残留清零 | 段级 FAIL 输出 + 汇总退出码 | 查退出码在位(每段 timeout 守卫 + 退出码/取证文件双检);**SCRIPT ERROR 扫描缺失**;断言数下限不适用(判定主体 = golden 容差与取证文件存在性,非断言计数) |
|
||||
| **static_scan**(静态扫描域) | `game/tests/static_scan.sh` | 静态扫描域 S1–S10 可执行载体(grep 规则 + `tools/audit_type_hints.py`〔S9〕+ `tools/audit_file_headers.py`〔S10〕) | fail 聚合退出码(任一硬失败规则命中即 exit 1) | 查退出码在位;SCRIPT ERROR 扫描与断言数下限不适用(逐规则命中即红,无运行时错误面与断言计数);S3 现为 warning 级、不参与 fail 判定(见下表) |
|
||||
|
||||
### 改动域划分(2026-10-17 用户裁「代码批只跑代码闸、文档批只跑文档闸」)
|
||||
|
||||
| 域 | 闸 | 本批改动落在这些路径即属该域 |
|
||||
|---|---|---|
|
||||
| **代码域** | run_smoke、run_all、probe_gate `--click`、probe_gate `--full`、render_gate、static_scan、回放确定性对拍(条件件) | **唯一触发=`game/`**(游戏工程代码、测试、探针、场景、数据表)。2026-10-18 用户裁「跨领域执法禁绝」(提交 `7bdf53e3`)后,原 `tools/`、`artwork/` 两前缀不再把改动拉进代码域 |
|
||||
| **文档域** | gdd_lint、doc_link_audit、doc_term_audit、流水线闸 | 一切非 `game/` 的路径:`design/`、根规则文件(`AGENTS.md`/`roadmap.md`)、`tools/` 工具脚本、`.zcode/` 配置、`sim-data/`、`reports/` |
|
||||
| **两域都含** | repo_structure_audit(熵增闸:顶层目录/根文件/图像白名单/退役路径/design 子目录五查——文档批新增或挪动 `.md` 同样会绊它;纯文本扫描秒级) | — |
|
||||
|
||||
口径三条:**域划分的唯一出处是 `tools/run_all_gates.sh`**(`--code`/`--docs`/不带参数=全量),本表是它的现状登记、不是第二份清单;改闸件本身或一次改动跨两域 → 跑全量档(§6.2 共享件例外);合回闸按 merge diff 路径推出应验的域,再校验回执的 `domain` 字段与新增红。代码域跑前先过**素材齐盘预检**——`game/assets/art/**` 与一切 `*.import` 边车都不入 git(2026-09-29 裁定),worktree 冷检出必空盘,空盘态冒烟 V1 成片假红、渲染闸更是一段 golden 都不比。
|
||||
|
||||
### 三条判定硬闸现行状态
|
||||
|
||||
| 硬闸 | run_smoke | run_all | probe_gate | render_gate | static_scan |
|
||||
|---|---|---|---|---|---|
|
||||
| **退出码优先** | 已落实(闸①) | 已落实(套件 manifest expect 协议) | 已落实(`verdict` 函数逐段判退出码,PASS 串不作判据) | 已落实(段级退出码 + 取证双检) | 已落实(fail 聚合退出) |
|
||||
| **SCRIPT ERROR 扫描** | 已落实(闸③,外部扫描——GDScript 无脚本错误陷阱 API,闸设在外部包装) | 已落实(入口内扫子套件输出;子进程的 stdout/stderr 须先落盘——`OS.execute` 管道在本机恒空) | 已落实(逐探针段 `tools/error_scan.py`,标记与 run_smoke 同源) | **缺失**(本批未收——判定主体是 golden 容差与取证存在性;登记 06) | 不适用(静态域无运行时错误面) |
|
||||
| **断言数下限** | 无独立下限(闸②摘要行必须在案,防「跑一半仍 PASS」;脚本错误吞断言路径由闸③兜住) | 已落实(`Kit.finish` 零断言返回专用退出码 2——与「断言失败=1」区分,防致命类套件的 expect 协议放过) | 已落实(退出码 0 但无该探针签名标记亦判红——防静默退出) | 不适用(golden 容差 + 取证存在性判定) | 不适用(逐规则命中判定;另有扫描面为空即判红的零命中自检) |
|
||||
|
||||
背景事实(run_smoke 头注在案):GDScript 运行时脚本错误不改进程退出码、不计入冒烟失败数、且静默中断所在函数剩余断言——2026-09-19 状态记录 83 实证「309 项 0 失败」实为断言未跑全。这是 SCRIPT ERROR 扫描必须存在于判定层的原因。
|
||||
|
||||
### 静态扫描域 S1–S8 承接清单
|
||||
|
||||
静态扫描域规则(2026-09-12 立,沿革见 git commit log;下表为现行事实登记):
|
||||
|
||||
| # | 规则 | 状态 |
|
||||
|---|---|---|
|
||||
| S1 | 玩法代码禁 `randomize()`、自建 `RandomNumberGenerator`(D2 Rule 5) | **在位**(硬失败;扫描面 game/core + game/presentation) |
|
||||
| S2 | 禁全局随机函数 `randi()` / `randf()` / `randf_range()`——全局 RNG 绕开 RngService(specialist 补登) | **在位**(与 S1 同段硬失败;实例方法 `.randi()` 排除、`rng-seed-exempt` 豁免注记在案) |
|
||||
| S3 | core/ 禁 ConfigDB 外 data 表加载(`load(` / `preload(` / `ResourceLoader.load`;schema class_name 直引豁免)(D2 Rule 2) | **在位**(warning 级——class_name 直引误报需人工复核;路径已由裸 `core` 修正为 `game/core`,此前恒零命中静默空转;豁免 config_db.gd 自身=数值单一事实源的正主) |
|
||||
| S4 | core/ 禁 `extends Control/Node2D`、禁 `.tscn` preload(D2 Rule 7) | **在位**(硬失败) |
|
||||
| S5 | core/ 禁裸引用 autoload 全局标识符(`ConfigDB` / `RngService` 直接写 = --script 模式 parse error)——构造注入 only(specialist 升格) | **在位**(硬失败;形态=标识符后紧跟 `.` 的成员访问,排除注释行与字符串字面量) |
|
||||
| S6 | core↔core 信号连接只许方法 Callable(禁 lambda 捕获 self);发射者禁持有订阅者反向引用 | **未落地**(脚本 TODO 注记在案) |
|
||||
| S7 | B1 编排唯一性:B2/B3/B4 API 符号命中文件 ⊆ B1 文件集;A2/B3/B4 零相互直调(B1 AC-43) | **未落地**(脚本 TODO 注记在案) |
|
||||
| S8 | 结算路径 `await` 零命中(B1 结算/编排文件集);字面量扫描 = warning 级 + 人工三要素复核(D2 AC-14 口径) | **未落地**(脚本 TODO 注记在案) |
|
||||
|
||||
域外扩充两件(均硬失败在位):**S9** 类型闸(`tools/audit_type_hints.py`,迭代 27 T5——产品码无类型容器/有值返回缺类型/参数缺类型);**S10** 文件头闸(`tools/audit_file_headers.py`——头注 ≤8 行 + 日期/变更叙事黑名单)。
|
||||
|
||||
### 三层承载与判定原则
|
||||
|
||||
测试分三层,各有在册承载与入闸方式(细目见 `game/tests/README.md`):
|
||||
|
||||
| 层 | 判什么 | 承载 | 入闸 |
|
||||
|---|---|---|---|
|
||||
| L1 单元 | 最单元的逻辑代码对不对 | `game/tests/unit/` | `run_all.gd`(闸 02) |
|
||||
| L2 集成 | 跨系统闭环对不对 | `game/tests/integration/` | 同上(同一入口同一协议) |
|
||||
| L3 系统/场景 | 跑起来之后 UI 与场景切换对不对 | `game/smoke/*.tscn` 探针 | `probe_gate.sh`(闸 03/04) |
|
||||
|
||||
**判定原则**:验收不能只是「跑一遍没崩」。三硬闸(退出码/脚本错误扫描/断言数下限)是判定的底线,
|
||||
缺一即判定有洞;「日志里写着 PASS」不作判据。另有两类静默失效必须机制性防范——规则扫描面为空
|
||||
(路径写错即恒零命中恒绿)与子进程输出丢失(本机 `OS.execute` 管道恒空),两者都以显式自检拦住。
|
||||
|
||||
### 依赖约束
|
||||
|
||||
测试域禁止反向依赖呈现层具体实现。五闸及其调用的探针场景、审计脚本只允许依赖两类边界:
|
||||
|
||||
1. **autoload 边界**——ConfigDB / RngService 的公开面(--script 模式不加载 autoload 且不注册全局标识符,测试文件自带显式实例化夹具);
|
||||
2. **场景契约**——探针场景的信号外发面与视图单元接口(信号外发、setter 只读注入),禁直引呈现层实现内部(如 UiKit 工厂内部状态、BoardView 绘制细节)。
|
||||
|
||||
测试域是所有层的消费方,进入方式限于上述两类边界;除此之外的依赖方向一律与「模块归属」节依赖单向性同规。
|
||||
|
||||
### 事实源声明
|
||||
|
||||
本节为测试域(测试载体、判定口径、静态扫描域)的事实源。新增违规案例仍须先补 static_scan 规则再修码(code-conventions 缺陷-规范对照表纪律)。
|
||||
|
||||
---
|
||||
|
||||
## 数据流
|
||||
|
||||
### 1. 帧更新路径(2D 回合制:无逐帧玩法逻辑)
|
||||
|
||||
```
|
||||
Input(鼠标)→ D1 输入翻译 → 意图对象 → A2.settle_batch(唯一提交入口)
|
||||
→ A3.try_spend(原子扣减)→ A2 棋盘效果(挖/连锁/封印/移动)→ 三事件外发
|
||||
→ [棋盘渲染:D1 BoardView 按事件增量重绘;无事件帧 = 静态 + 动效]
|
||||
→ 轮次结束 → A3 Waiting → B1 结算编排(段序七段)→ 明细步骤流 → D1 结算屏逐行呈现
|
||||
```
|
||||
|
||||
- 回合制下每帧只做:输入采样、呈现刷新、动效推进——**玩法状态只在意图事务内变更**(单意图帧输入收集:stop 点击终结当帧)。
|
||||
- 无跨线程玩法数据流(Godot 主线程假设,D2 EC13);A1 生成若引入 WorkerThread,join 必须先于任何快照切出(既定约束)。
|
||||
|
||||
### 2. 事件/信号路径(系统间通信,无紧耦合)
|
||||
|
||||
```
|
||||
A2 ──cell_revealed / flag_judged / round_end(棋盘路径)──▶ B1(轮 facts 缓冲)
|
||||
A3 ──round_end(stopped 直发,payload 同构)──────────────▶ B1
|
||||
B1 ──notify_settlement_done(next_round_mode) / notify_combat_end──▶ A3
|
||||
B1 ──apply_effect / apply_damage / grant / 伤害单据 submit…──▶ B3/B2/B4(唯一调用方;段内伤害序=主角先手→逐敌还手→地图账殿后〔案C 2026-10-06〕)
|
||||
B1 ──install_board / retire_board──▶ A2 B1 ──generate(L,D)──▶ A1
|
||||
D1 ◀──呈现数据源:A2 事件流 / B1 步骤流 / A3 ap-rap / ConfigDB display_name
|
||||
```
|
||||
|
||||
- **事件载体(已定)**:组合根直连信号接线 + B1 Waiting 相位触发(不依赖事件到达序);autoload 全局事件总线已否决(2026-09-12,沿革见 git 历史)——单线程回合制沿用组合根直连(KISS)。
|
||||
- 事件规范序:A2 发射序 = 触发格 BFS、8 邻行主序;事件序契约 `flag_judged` < `round_end` 全路径统一。
|
||||
- **呈现层订阅禁令(切片缺陷②教训固化)**:呈现层永不直接订阅 排雷玩法/行动经济 的事件流,只订 战斗结算 步骤流与 `level_runner`——核心事件形态变化不得直接冲击界面。
|
||||
|
||||
### 3. 存档/读档路径(MVP 无存档;契约已锁)
|
||||
|
||||
- MVP 无元进度持久化(C4/D3 归 Alpha)。**已锁契约**:续玩/复盘快照 = master_seed + 各流 scope 计数器 + 意图序列 + 窗口选择序列;快照切出须发生在无正在执行中的 `open_stream` 实例时(scope 事件边界外——B1 编排保证:切点 = board install 边界)。
|
||||
- 可回放性已实证:切片冒烟同种子双跑步骤流逐行相同(B1 AC-33 前身)。
|
||||
- D3 Alpha 期按此契约设计格式;SCHEMA_VERSION 高版本拒读。
|
||||
|
||||
### 4. 打包与字体(CJK 随包发行)
|
||||
|
||||
CJK 字体随包发行并设为 theme 默认字体——运行时默认字体无中文字形。此项是 HUD框架 正式化的硬性前置,同时进导出 checklist 核对项。
|
||||
|
||||
### 4. 初始化顺序
|
||||
|
||||
```
|
||||
进程启动
|
||||
→ autoload 实例化:ConfigDB → RngService → SaveManager → MetaProgression(顺序固定;战斗编排器等核心类为普通类、由组合根按局实例化)
|
||||
→ ConfigDB._ready():load_tables 加载 + 校验(致命通道;失败 = 构建中止 + 错误清单)
|
||||
→ 主场景(D1 组合根)装配视图单元 + 信号接线
|
||||
→ C2 begin_run:RngService.set_master_seed()(唯一接线方;两流计数器全零前提)
|
||||
→ B1.begin_battle(encounter):set_reload_gate(true) → B3 开域 → B2 spawn → A2 install_board(A1.generate) + B4 roll_board(恰一次)→ A3 notify_round_start
|
||||
→ 挖掘循环 …… → battle_over 清理序列 → set_reload_gate(false)
|
||||
→ 关卡末:通关结算(钥石/GP/专长 level_clear 渠道——现行语义归 冒险结构 GDD;原 clear_inventory 随库存轴下线退役 2026-09-15)
|
||||
```
|
||||
|
||||
**启动后置条件**(2026-10-17 用户裁入册——迭代 28 以冒烟 V2a–V2f 共 11 条断言把「启动完成后玩家该看到什么」成文;执行判据事实源在 `game/smoke/smoke_all.gd`):
|
||||
|
||||
1. ConfigDB 就绪且表已载(`is_ready` + hero 表在座)。
|
||||
2. 系统设置已落引擎态——Master 音量 mute/volume_db = settings_store 现值;减动效开关 = `UiKit.motion_scale`。
|
||||
3. 启动态菜单可见(boot 后自树顶向下第一个可见内容层 = 开始层——菜单被冒险屏盖住即红)。
|
||||
4. 续玩钮可见态恒等于断点在档态(双向:无断点隐藏/有断点可见/清断点回隐;boot 路径与刷新单口同源)。
|
||||
5. 闲时会话已在树(`run_scope` 非空、非冒险会话、在树——永非 null 契约的启动侧证明)。
|
||||
6. 调试浮窗 boot 不自动开(菜单优先,2026-10-16 用户令)+ 调试入口全局浮层角标 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;先兑付后衰减;段内伤害序=主角先手→逐敌还手→地图账殿后〔案C 2026-10-06〕) | 禁第二调用方(静态扫描域: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#明细流水每一行都能指回你刚才的哪一步棋)(15 类封闭枚举 + 公共字段 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 采纳前对照核实。
|
||||
|
||||
---
|
||||
|
||||
## 架构原则
|
||||
|
||||
1. **核心层纯逻辑、headless 完整可跑**——核心层/功能层玩法逻辑零 Control/场景引用、零 UI 依赖;`--headless --script` 可跑完整战斗(D2 Rule 7 工程债;切片 88 冒烟实证)。输入是意图对象、输出是事件流/步骤流,D1 与输入设备皆可替换。
|
||||
2. **单一事实源与零字面量**——玩法数值只存在于 `data/tables/*.tres`,经 ConfigDB 类型化单点读取;代码零玩法数值字面量;参数禁止跨系统复制(D2 Rule 1/2)。
|
||||
3. **封闭 RNG 与可回放**——玩法代码零随机;一切随机经 RngService 具名封闭流(增流走 P1 评审);同种子 + 同输入序列 ⇒ 事件流/步骤流逐位相同(结算禁 await,B1 承重约束)。
|
||||
4. **编排唯一性与事件面封闭**——战斗域跨系统调用权集中 B1(静态扫描承载);A2 三事件面封闭即负空间;每格受理、每雷转化、每次推进、每次衰减各恰一次。
|
||||
5. **fail-fast + 零特判**——数据错误一律致命中止(错误数值上线比崩溃更伤);API 非法 = 拒绝 + 诊断不静默;变异零运行时分支(行为差异全部由生成端约束保证)。
|
||||
6. **依赖单向 + 组合根模式**——层间单向依赖、唯一回边 = A2 事件订阅面;核心写调用唯一发生在组合根;禁上帝对象(切片 1100 行 main.gd 反面案例 → 9 单元拆分)。
|
||||
7. **呈现层契约成文**——面向呈现的信号载荷必须有成文 schema;模态覆盖层必须有"打开时遮挡物隐藏"场景级断言;场景级 UI 探针测试为标配(切片缺陷 ①②④⑤ 教训沉淀)。
|
||||
|
||||
---
|
||||
|
||||
## 未决问题
|
||||
|
||||
| ID | Summary | Priority | Resolution Path |
|
||||
|----|---------|----------|-----------------|
|
||||
| QQ-01 | 渲染器选择(Forward+ vs gl_compatibility)与项目窗口基线 | High | **已落定**(2026-09-12):gl_compatibility + 1280×800 基座(canvas_items + expand);沿革见 git 历史 |
|
||||
| QQ-02 | 事件总线载体与 A2 事件捕获测试 API | High | **已落定**(2026-09-12):组合根直连 signal + Waiting 相位触发;autoload 全局总线否决 |
|
||||
| QQ-03 | gdUnit4 是否引入并迁移冒烟用例 | Medium | **已落定**:deferred(现行双载体承载;D2 OQ1 关闭) |
|
||||
| QQ-04 | 轮内刷新数值连锁(清图支配性条款⑤ / 真人刷图行为获取期望)重算 | Medium | playtest 实测 |
|
||||
| QQ-05 | 战斗末可选类"j==0 补发 1 件"兜底是否采纳(切片遗留待办) | Medium | playtest + B4 GDD 修订批 |
|
||||
| QQ-06 | 可选类退出格子池后 buff 频率被动上升(44%→59%)的难度对冲杠杆(敌 HP / 权重 / 幅度) | High | C3 调参 + 切片数据复测 |
|
||||
| QQ-07 | 标错惩罚(A2 OQ1:候选敌方伏击+1;hit=false 无去重的不对称裁决) | Medium | 原型小补丁实测会话(可与 v3 终验合并) |
|
||||
| QQ-08 | B5 双舞台陷阱(战斗发生在棋盘上还是独立场景) | Low(B5 前) | 战斗表现美术测试后裁决 |
|
||||
| QQ-09 | C3 消费 B1 对账输出的事实依赖回写 `design/gdd/02-系统清单.md` | Low | C3 GDD 定稿时 |
|
||||
| QQ-10 | `.claude/docs/director-gates.md` 缺失(TD-ARCHITECTURE/LP-FEASIBILITY 判据无载体) | Low | 补建 gate 定义文件或维持 solo/lean 模式约定 |
|
||||
| QQ-11 | A1 生成性能姿态(F2c 常数 C 定稿;切片实证 10×10/12×12 同步生成可接受,WorkerThread 留扩展) | Medium | A1 GDD 修订批 |
|
||||
| QQ-12 | 零伤害死局跨字段/跨表护栏落点(B2 OQ9;推荐 D2 跨表校验——切片 LevelTable 校验⑧先例) | Medium | D2 校验设计批 |
|
||||
| QQ-13 | A1 EC5 运行期熔断(连续降级确定性回退已知好种子) | Low | A1 GDD 修订批 |
|
||||
| QQ-14 | A5 探测显影接口 / D3 存档格式(RNG 快照契约已在案,格式归 Alpha) | Low | 秘宝域正式化 / D3 Alpha 设计批 |
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,698 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "游戏代码实现架构(Godot 场景·脚本·运行时树)",
|
||||
"output": "code-architecture.html",
|
||||
"quality_profile": "showcase",
|
||||
"locale": "zh-CN",
|
||||
"viewBox": [
|
||||
1320,
|
||||
760
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "config_db",
|
||||
"type": "database",
|
||||
"label": "ConfigDB 配置库",
|
||||
"sublabel": "core/config_db.gd",
|
||||
"pos": [
|
||||
1140,
|
||||
168
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
44
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rng_service",
|
||||
"type": "backend",
|
||||
"label": "RngService 随机流",
|
||||
"sublabel": "core/rng_service.gd",
|
||||
"pos": [
|
||||
1140,
|
||||
222
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
44
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "main",
|
||||
"type": "frontend",
|
||||
"label": "组合根 Main",
|
||||
"sublabel": "main.gd · 运行时建树",
|
||||
"tag": "main.tscn",
|
||||
"pos": [
|
||||
480,
|
||||
60
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
72
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "level_map",
|
||||
"type": "frontend",
|
||||
"label": "关卡地图屏",
|
||||
"sublabel": "三停点选路",
|
||||
"pos": [
|
||||
1060,
|
||||
60
|
||||
],
|
||||
"size": [
|
||||
180,
|
||||
70
|
||||
],
|
||||
"tag": "level_map_screen.gd"
|
||||
},
|
||||
{
|
||||
"id": "stage",
|
||||
"type": "frontend",
|
||||
"label": "战斗展示区",
|
||||
"sublabel": "站桩·回合·战斗日志",
|
||||
"pos": [
|
||||
40,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
170,
|
||||
88
|
||||
],
|
||||
"tag": "battle_stage_view.gd"
|
||||
},
|
||||
{
|
||||
"id": "hero",
|
||||
"type": "frontend",
|
||||
"label": "角色信息区",
|
||||
"sublabel": "攻防·秘宝槽·特性",
|
||||
"pos": [
|
||||
250,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
170,
|
||||
88
|
||||
],
|
||||
"tag": "hero_info_panel_view.gd"
|
||||
},
|
||||
{
|
||||
"id": "board",
|
||||
"type": "frontend",
|
||||
"label": "棋盘区",
|
||||
"sublabel": "棋盘·AP条·气泡·特效",
|
||||
"pos": [
|
||||
510,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
170,
|
||||
88
|
||||
],
|
||||
"tag": "board_zone_view.gd"
|
||||
},
|
||||
{
|
||||
"id": "shop_camp",
|
||||
"type": "frontend",
|
||||
"label": "商店·营地浮层",
|
||||
"sublabel": "商品卡·三柜台",
|
||||
"pos": [
|
||||
730,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
170,
|
||||
88
|
||||
],
|
||||
"tag": "ui_assembler.gd 拼装"
|
||||
},
|
||||
{
|
||||
"id": "settle",
|
||||
"type": "frontend",
|
||||
"label": "结算特效",
|
||||
"sublabel": "跨区飞行演出",
|
||||
"pos": [
|
||||
918,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
170,
|
||||
88
|
||||
],
|
||||
"tag": "settlement_fx_view.gd"
|
||||
},
|
||||
{
|
||||
"id": "pause",
|
||||
"type": "frontend",
|
||||
"label": "状态面板",
|
||||
"sublabel": "只读入口",
|
||||
"pos": [
|
||||
120,
|
||||
420
|
||||
],
|
||||
"size": [
|
||||
152,
|
||||
56
|
||||
],
|
||||
"tag": "status_panel.gd"
|
||||
},
|
||||
{
|
||||
"id": "settings",
|
||||
"type": "frontend",
|
||||
"label": "设置浮层",
|
||||
"sublabel": "音量·全屏·减动效",
|
||||
"pos": [
|
||||
288,
|
||||
420
|
||||
],
|
||||
"size": [
|
||||
152,
|
||||
56
|
||||
],
|
||||
"tag": "settings_overlay.gd"
|
||||
},
|
||||
{
|
||||
"id": "career",
|
||||
"type": "frontend",
|
||||
"label": "生涯浮层",
|
||||
"sublabel": "六类九项汇总",
|
||||
"pos": [
|
||||
464,
|
||||
420
|
||||
],
|
||||
"size": [
|
||||
152,
|
||||
56
|
||||
],
|
||||
"tag": "career_overlay.gd"
|
||||
},
|
||||
{
|
||||
"id": "curio",
|
||||
"type": "frontend",
|
||||
"label": "三选一浮层",
|
||||
"sublabel": "通关停点·三卡点选",
|
||||
"pos": [
|
||||
632,
|
||||
420
|
||||
],
|
||||
"size": [
|
||||
152,
|
||||
56
|
||||
],
|
||||
"tag": "curio_pick_overlay.gd"
|
||||
},
|
||||
{
|
||||
"id": "confirm",
|
||||
"type": "frontend",
|
||||
"label": "确认对话框",
|
||||
"sublabel": "通用确认弹窗",
|
||||
"pos": [
|
||||
800,
|
||||
420
|
||||
],
|
||||
"size": [
|
||||
152,
|
||||
56
|
||||
],
|
||||
"tag": "confirm_dialog.gd"
|
||||
},
|
||||
{
|
||||
"id": "debug",
|
||||
"type": "frontend",
|
||||
"label": "调试浮窗",
|
||||
"sublabel": "DS_DEBUG 门控",
|
||||
"pos": [
|
||||
968,
|
||||
420
|
||||
],
|
||||
"size": [
|
||||
152,
|
||||
56
|
||||
],
|
||||
"tag": "debug_overlay.gd"
|
||||
},
|
||||
{
|
||||
"id": "save",
|
||||
"type": "database",
|
||||
"label": "存档管理",
|
||||
"pos": [
|
||||
96,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "save_manager.gd"
|
||||
},
|
||||
{
|
||||
"id": "meta",
|
||||
"type": "database",
|
||||
"label": "元进度",
|
||||
"pos": [
|
||||
244,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "meta_progression.gd"
|
||||
},
|
||||
{
|
||||
"id": "orch",
|
||||
"type": "backend",
|
||||
"label": "战斗编排器",
|
||||
"pos": [
|
||||
383,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "battle_orchestrator.gd"
|
||||
},
|
||||
{
|
||||
"id": "rules",
|
||||
"type": "backend",
|
||||
"label": "扫雷规则",
|
||||
"pos": [
|
||||
540,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "minesweeper_rules.gd"
|
||||
},
|
||||
{
|
||||
"id": "boardgen",
|
||||
"type": "backend",
|
||||
"label": "棋盘生成",
|
||||
"pos": [
|
||||
688,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "board_generator.gd"
|
||||
},
|
||||
{
|
||||
"id": "boarddata",
|
||||
"type": "database",
|
||||
"label": "棋盘数据",
|
||||
"pos": [
|
||||
836,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "board_data.gd"
|
||||
},
|
||||
{
|
||||
"id": "effects",
|
||||
"type": "backend",
|
||||
"label": "效果引擎",
|
||||
"pos": [
|
||||
984,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "effect_engine.gd"
|
||||
},
|
||||
{
|
||||
"id": "adventure",
|
||||
"type": "backend",
|
||||
"label": "冒险运行器",
|
||||
"pos": [
|
||||
1132,
|
||||
554
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "adventure_runner.gd"
|
||||
},
|
||||
{
|
||||
"id": "levelrun",
|
||||
"type": "backend",
|
||||
"label": "关卡运行器",
|
||||
"pos": [
|
||||
96,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "level_runner.gd"
|
||||
},
|
||||
{
|
||||
"id": "dmgctl",
|
||||
"type": "backend",
|
||||
"label": "伤害控制",
|
||||
"pos": [
|
||||
244,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "damage_controller.gd"
|
||||
},
|
||||
{
|
||||
"id": "dgmath",
|
||||
"type": "backend",
|
||||
"label": "伤害公式",
|
||||
"pos": [
|
||||
392,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "damage_math.gd"
|
||||
},
|
||||
{
|
||||
"id": "reward",
|
||||
"type": "backend",
|
||||
"label": "奖励经济",
|
||||
"pos": [
|
||||
540,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "reward_economy.gd"
|
||||
},
|
||||
{
|
||||
"id": "lottery",
|
||||
"type": "backend",
|
||||
"label": "技能抽奖",
|
||||
"pos": [
|
||||
688,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "skill_lottery.gd"
|
||||
},
|
||||
{
|
||||
"id": "attune",
|
||||
"type": "backend",
|
||||
"label": "同调",
|
||||
"pos": [
|
||||
836,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "attunement.gd"
|
||||
},
|
||||
{
|
||||
"id": "action",
|
||||
"type": "backend",
|
||||
"label": "行动经济",
|
||||
"pos": [
|
||||
984,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "action_economy.gd"
|
||||
},
|
||||
{
|
||||
"id": "feats",
|
||||
"type": "backend",
|
||||
"label": "特长引擎",
|
||||
"pos": [
|
||||
1132,
|
||||
616
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "feats_engine.gd"
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "backend",
|
||||
"label": "状态容器",
|
||||
"pos": [
|
||||
96,
|
||||
678
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "status_container.gd"
|
||||
},
|
||||
{
|
||||
"id": "units",
|
||||
"type": "backend",
|
||||
"label": "单位容器",
|
||||
"pos": [
|
||||
244,
|
||||
678
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "unit_container.gd"
|
||||
},
|
||||
{
|
||||
"id": "treasure",
|
||||
"type": "database",
|
||||
"label": "秘宝数据",
|
||||
"pos": [
|
||||
392,
|
||||
678
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "treasure_items.gd"
|
||||
},
|
||||
{
|
||||
"id": "resolver",
|
||||
"type": "backend",
|
||||
"label": "配置解析",
|
||||
"pos": [
|
||||
540,
|
||||
678
|
||||
],
|
||||
"size": [
|
||||
130,
|
||||
48
|
||||
],
|
||||
"sublabel": "config_db_resolver.gd"
|
||||
},
|
||||
{
|
||||
"id": "xvalid",
|
||||
"type": "backend",
|
||||
"label": "配置交叉校验",
|
||||
"pos": [
|
||||
688,
|
||||
678
|
||||
],
|
||||
"size": [
|
||||
170,
|
||||
48
|
||||
],
|
||||
"sublabel": "config_db_cross_validator.gd"
|
||||
}
|
||||
],
|
||||
"boundaries": [
|
||||
{
|
||||
"kind": "region",
|
||||
"label": "战斗主界面(UiAssembler 拼装)",
|
||||
"wraps": [
|
||||
"stage",
|
||||
"hero",
|
||||
"board",
|
||||
"shop_camp",
|
||||
"settle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "region",
|
||||
"label": "浮层与对话框(组合根挂载)",
|
||||
"wraps": [
|
||||
"pause",
|
||||
"settings",
|
||||
"career",
|
||||
"curio",
|
||||
"confirm",
|
||||
"debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "region",
|
||||
"label": "逻辑层 core/(21 件·名称清单)",
|
||||
"wraps": [
|
||||
"save",
|
||||
"meta",
|
||||
"orch",
|
||||
"rules",
|
||||
"boardgen",
|
||||
"boarddata",
|
||||
"effects",
|
||||
"adventure",
|
||||
"levelrun",
|
||||
"dmgctl",
|
||||
"dgmath",
|
||||
"reward",
|
||||
"lottery",
|
||||
"attune",
|
||||
"action",
|
||||
"feats",
|
||||
"status",
|
||||
"units",
|
||||
"treasure",
|
||||
"resolver",
|
||||
"xvalid"
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "main-stage",
|
||||
"from": "main",
|
||||
"to": "stage",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "main-hero",
|
||||
"from": "main",
|
||||
"to": "hero",
|
||||
"fromSide": "bottom",
|
||||
"toSide": "top"
|
||||
},
|
||||
{
|
||||
"id": "board-main",
|
||||
"from": "board",
|
||||
"to": "main",
|
||||
"label": "翻开·封印·和弦",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom"
|
||||
},
|
||||
{
|
||||
"id": "hero-board",
|
||||
"from": "hero",
|
||||
"to": "board",
|
||||
"label": "秘宝两步交互",
|
||||
"fromSide": "right",
|
||||
"toSide": "left"
|
||||
},
|
||||
{
|
||||
"id": "main-save",
|
||||
"from": "main",
|
||||
"to": "save",
|
||||
"label": "存档读写",
|
||||
"variant": "dashed",
|
||||
"fromSide": "left",
|
||||
"toSide": "top",
|
||||
"via": [
|
||||
[
|
||||
28,
|
||||
96
|
||||
],
|
||||
[
|
||||
28,
|
||||
512
|
||||
],
|
||||
[
|
||||
161,
|
||||
512
|
||||
]
|
||||
],
|
||||
"labelSegment": 0
|
||||
},
|
||||
{
|
||||
"id": "orch-stage",
|
||||
"from": "orch",
|
||||
"to": "stage",
|
||||
"label": "结算回流",
|
||||
"variant": "emphasis",
|
||||
"fromSide": "top",
|
||||
"toSide": "bottom",
|
||||
"via": [
|
||||
[
|
||||
448,
|
||||
376
|
||||
],
|
||||
[
|
||||
125,
|
||||
376
|
||||
]
|
||||
],
|
||||
"labelSegment": 1
|
||||
},
|
||||
{
|
||||
"id": "main-levelmap",
|
||||
"from": "main",
|
||||
"to": "level_map",
|
||||
"label": "挂载",
|
||||
"fromSide": "right",
|
||||
"toSide": "left"
|
||||
}
|
||||
],
|
||||
"cards": [
|
||||
{
|
||||
"dot": "cyan",
|
||||
"title": "组合根与建树",
|
||||
"items": [
|
||||
"main.tscn 全场景仅 1 个节点,整棵界面树由 main.gd 运行时搭建(1392 行)",
|
||||
"战斗界面由 UiAssembler 拼装;商店/营地浮层即拼装于战斗根内",
|
||||
"元进度账本与存档同由组合根持有(main.gd preload)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "emerald",
|
||||
"title": "战斗动作链",
|
||||
"items": [
|
||||
"棋盘区 翻开/封印/和弦 → 组合根 → 战斗编排器规则判定",
|
||||
"结算回流:血量攻防→角色信息区 · 受击演出→展示区 · AP 扣减与提示→棋盘区",
|
||||
"秘宝槽点击走两步交互:角色信息区 → 棋盘区/即刻生效"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "rose",
|
||||
"title": "逻辑层与边界",
|
||||
"items": [
|
||||
"core/ 21 件仅列名称,源码出处见各节点 sources 指针",
|
||||
"ConfigDB/RngService 两单例经 project.godot autoload 全局供给",
|
||||
"smoke/ 下 13 个测试探针场景属测试基建,不入架构主干"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,262 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Dungeon Sweeper 系统架构总图",
|
||||
"output": "design/engineering/architecture/gdd-architecture.html",
|
||||
"quality_profile": "showcase",
|
||||
"locale": "zh-CN"
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"id": "ap",
|
||||
"type": "backend",
|
||||
"label": "行动经济",
|
||||
"sublabel": "每轮AP·停手刷新",
|
||||
"tag": "ACTION_ECONOMY",
|
||||
"pos": [
|
||||
24,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "minesweeper",
|
||||
"type": "frontend",
|
||||
"label": "排雷循环",
|
||||
"sublabel": "挖格·封印·连锁展开",
|
||||
"tag": "MINESWEEPER_CYCLE",
|
||||
"pos": [
|
||||
236,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
150,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "status",
|
||||
"type": "database",
|
||||
"label": "增益状态",
|
||||
"sublabel": "状态容器·叠层衰减",
|
||||
"tag": "STATUS_EFFECT",
|
||||
"pos": [
|
||||
458,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
150,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "combat",
|
||||
"type": "backend",
|
||||
"label": "战斗循环",
|
||||
"sublabel": "轮末自动结算",
|
||||
"tag": "COMBAT_CYCLE",
|
||||
"pos": [
|
||||
680,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
160,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "adventure",
|
||||
"type": "backend",
|
||||
"label": "冒险循环",
|
||||
"sublabel": "关卡节点链·一条命",
|
||||
"tag": "ADVENTURE_CYCLE",
|
||||
"pos": [
|
||||
912,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
160,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "meta",
|
||||
"type": "database",
|
||||
"label": "跨局循环·元进度",
|
||||
"sublabel": "钥石解锁永久提升",
|
||||
"tag": "META_PROGRESS",
|
||||
"pos": [
|
||||
1144,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
160,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "enemy",
|
||||
"type": "backend",
|
||||
"label": "敌人系统",
|
||||
"sublabel": "技能池·出招意图",
|
||||
"tag": "ENEMY_SYSTEM",
|
||||
"pos": [
|
||||
680,
|
||||
570
|
||||
],
|
||||
"size": [
|
||||
160,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "curio",
|
||||
"type": "frontend",
|
||||
"label": "奇物",
|
||||
"sublabel": "三分类×三渠道",
|
||||
"tag": "ADVENTURE_CURIO",
|
||||
"pos": [
|
||||
912,
|
||||
570
|
||||
],
|
||||
"size": [
|
||||
160,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "support",
|
||||
"type": "cloud",
|
||||
"label": "表现与支撑",
|
||||
"sublabel": "HUD·数据配置·存档",
|
||||
"tag": "PRESENTATION_SUPPORT",
|
||||
"pos": [
|
||||
1144,
|
||||
570
|
||||
],
|
||||
"size": [
|
||||
160,
|
||||
64
|
||||
]
|
||||
}
|
||||
],
|
||||
"boundaries": [
|
||||
{
|
||||
"kind": "region",
|
||||
"label": "局内 · 一条命的冒险",
|
||||
"wraps": [
|
||||
"ap",
|
||||
"minesweeper",
|
||||
"status",
|
||||
"combat",
|
||||
"adventure",
|
||||
"enemy",
|
||||
"curio"
|
||||
],
|
||||
"pad": 20
|
||||
},
|
||||
{
|
||||
"kind": "region",
|
||||
"label": "局外 · 存档层",
|
||||
"wraps": [
|
||||
"meta"
|
||||
],
|
||||
"pad": 20
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from": "ap",
|
||||
"to": "minesweeper",
|
||||
"label": "每轮AP"
|
||||
},
|
||||
{
|
||||
"from": "minesweeper",
|
||||
"to": "status",
|
||||
"label": "扫雷攒因"
|
||||
},
|
||||
{
|
||||
"from": "status",
|
||||
"to": "combat",
|
||||
"label": "轮末兑现",
|
||||
"variant": "emphasis"
|
||||
},
|
||||
{
|
||||
"from": "combat",
|
||||
"to": "adventure",
|
||||
"label": "胜利·GP"
|
||||
},
|
||||
{
|
||||
"from": "adventure",
|
||||
"to": "meta",
|
||||
"label": "掉钥石"
|
||||
},
|
||||
{
|
||||
"from": "meta",
|
||||
"to": "adventure",
|
||||
"label": "解锁永久提升·下一局",
|
||||
"variant": "emphasis",
|
||||
"fromSide": "top",
|
||||
"toSide": "top",
|
||||
"via": [
|
||||
[
|
||||
1224,
|
||||
180
|
||||
],
|
||||
[
|
||||
992,
|
||||
180
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"from": "enemy",
|
||||
"to": "combat",
|
||||
"label": "技能池出招"
|
||||
},
|
||||
{
|
||||
"from": "curio",
|
||||
"to": "adventure",
|
||||
"label": "三渠道注入"
|
||||
},
|
||||
{
|
||||
"from": "support",
|
||||
"to": "meta",
|
||||
"label": "存档承载",
|
||||
"variant": "dashed"
|
||||
}
|
||||
],
|
||||
"cards": [
|
||||
{
|
||||
"dot": "cyan",
|
||||
"title": "核心循环",
|
||||
"items": [
|
||||
"下洞 → 扫雷攒筹码 → 自动战斗兑现 → 变强再下洞;死了,从头再来",
|
||||
"扫雷的因=战斗的果:增益打出、控制的巢穴变虚弱、惊动的巢穴变先手",
|
||||
"关底 Boss 掉钥石入存档;冒险之间用钥石解锁永久提升,存档逐局变厚"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "emerald",
|
||||
"title": "循环 × 子系统(systems/)",
|
||||
"items": [
|
||||
"排雷循环:棋盘生成 · 排雷玩法 · 行动经济 · 地形变异 · 秘宝",
|
||||
"战斗循环:战斗结算 · 敌人系统 · 增益状态 · 地图战斗资源 · 战斗表现",
|
||||
"冒险循环:关卡节点地图 · 关卡节点图生成 · 冒险结构 · 难度曲线与Boss · 奇物",
|
||||
"跨局循环:元进度 | 表现与支撑:HUD框架 · 数据配置 · 存档序列化 · 音频 · 教学"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "amber",
|
||||
"title": "数值语言",
|
||||
"items": [
|
||||
"伤害与成长一律整数加减(+1/−1 点),全局向下取整",
|
||||
"百分比仅保留三处既有粗档修正,新增数值系统默认走整数"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
# 代码规范反面案例库(code-conventions 配套)
|
||||
|
||||
> 本文件是 `code-conventions.md` 各条规则对应的真实反例,说明每条规则针对什么缺陷;规则本体以规约为准,规约与本文冲突时以规约为准。不随规约常驻加载——写码前不必通读,对某条规则的适用有疑义时再查。
|
||||
|
||||
## 1.1 上帝对象
|
||||
|
||||
main.gd 曾长到 ~1100 行——棋盘渲染、HUD、结算日志格式化、四种模态覆盖层、调整板、模拟器、关卡流程全部内联;后拆分为 9 个单一职责单元(views/ + hud_presenter),main 回到 ~430 行组合根。
|
||||
|
||||
## 1.2 裸函数堆
|
||||
|
||||
供给控制器曾以裸函数伪代码呈现被否;正式实现按私有组合件 RewardSupplyController 封装。
|
||||
|
||||
## 1.4 ID 前缀命名
|
||||
|
||||
ID 前缀是跟随 GDD 文档名的事实约定,从未成文;`config_db`/`rng_service` 无前缀与 A/B/C 系列并存——两套命名并行即规范缺失。
|
||||
|
||||
## 1.4.1 文件头失守
|
||||
|
||||
main.gd 头注曾累积 42 行——历次提交各自追加「本批做了什么」而全部闸静默放行;删掉叙事后仍剩 31 行,约 2/3 是对 code-conventions §1.3 与架构文档的整段复制、场景结构/生命周期机制描述(对规约与代码零新信息)。
|
||||
|
||||
## 2.1 信号契约缺失(软锁)
|
||||
|
||||
封印动作花完末点 AP 后相位翻 Waiting 但不发 round_end,结算点依赖该事件 → 整局软锁;自动玩家不用封印,冒烟路径覆盖不全没抓住。
|
||||
|
||||
## 2.2 标识符语义错位
|
||||
|
||||
窗口选择契约 = 窗口条目位置,UI 却传库存数组句柄——未消耗时二者巧合相等;消耗一件后错位 → 选中件不消耗、邻件被误耗。
|
||||
|
||||
## 2.3 覆盖层不可达
|
||||
|
||||
数值调整板已实现,但打开时被不透明的开始覆盖层完全遮住 = "点击无反应"。功能存在 ≠ 功能可达。
|
||||
|
||||
## 2.4 状态字段语义隐式
|
||||
|
||||
spawn 把 hero 的 max_hp 设为入参 hero_hp——跨战斗携带 HP 时上限被压扁,恢复点/治疗包的满血守卫全部失效。
|
||||
|
||||
## 5.3 单尺度校准的关卡灾难
|
||||
|
||||
可选类 25% 格子配比在单战斗尺度校准(击杀需求 18/54),×"库存关内延续"× 5 张板复合后 = 每关 24.8 件、刀总伤 180 > Boss 130 HP——单尺度合理的参数在关卡尺度坐实灾难。
|
||||
|
||||
## 5.4 拍板范围外自行发挥
|
||||
|
||||
清图奖励被自行设计成入库刀,用户纠正为"一次性高额伤害不入库"。
|
||||
|
||||
## 缺陷-规范对照表
|
||||
|
||||
| 缺陷 | 现象 | 对应规则 |
|
||||
|---|---|---|
|
||||
| UI 抖动 / "第3轮"消失 | 悬停文案换行推挤侧栏,末行被挤出视口 | 1.1 拆分 + 视图定长槽 |
|
||||
| Boss 战 AP 用完不结算(软锁) | 封印耗尽末点 AP 后整局冻结 | 2.1 事件发射完整性 |
|
||||
| 道具使用后不消失 | 选用件留存、邻件被误耗 | 2.2 标识符语义单一 |
|
||||
| 调整板点击无反应 | 面板已实现但被开始层遮挡 | 2.3 层级规则 + test-conventions §2 |
|
||||
| 上帝对象 | main.gd ~1100 行 | 1.1–1.3 |
|
||||
| ID 前缀命名 | 两套命名并存 | 1.4–1.5 |
|
||||
| 可选类每关 24.8 件 | 速杀退化、囤刀秒 Boss | 5.3 跨尺度推演 |
|
||||
@@ -0,0 +1,100 @@
|
||||
# 代码规范(Dungeon Sweeper)
|
||||
|
||||
> 约束范围:`game/` 代码同尺度;与 AGENTS.md「硬性红线」节硬约束(数值表单点 / RNG 封闭流 / Core 零 UI / fail-fast / spec-AC 一致性)并行生效,冲突以用户裁决为准。
|
||||
> 分工:本文管结构 / 契约 / 语言 / 数值 / 流程五类;测试的编写与验收见 `design/engineering/test-conventions.md`;真实反例库见同目录 `code-conventions-cases.md`(不常驻加载,对规则适用有疑义时查)。
|
||||
|
||||
**写任何代码前必须通读本文件。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 结构纪律——高内聚、低耦合
|
||||
|
||||
### 1.1 禁止上帝对象
|
||||
一个类只承载一个职责。场景主脚本(main)= **组合根**:模式流转、信号接线、核心写调用的唯一出口;渲染、文案拼装、状态装配一律拆分为独立视图/装配器类。单文件超过 ~400 行即触发审视。
|
||||
|
||||
### 1.2 一切功能以类封装,禁止裸函数堆
|
||||
设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。
|
||||
|
||||
### 1.3 依赖单向,核心写调用完成
|
||||
依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);核心写接口(settle_batch / submit_window_selection / 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)属文档层。
|
||||
|
||||
### 1.4.1 文件头 = `##` 文档注释,介绍本模块,≤8 行,两类白名单制
|
||||
|
||||
头注的存在性与内容范围以 Python 规范为权威(GDScript 语法近 Python,官方风格指南对文件头零条款,不自造标准):Google Python Style Guide §3.8.2 明文要求——"Files should start with a docstring describing the contents and usage of the module"(文件应以描述模块内容与用法的 docstring 开头);PEP 257——模块一般都应有 docstring,摘要压一行。
|
||||
|
||||
载体与上限:只用 `##` 文档注释(Godot 官方载体,进编辑器 F1 帮助),总行数 ≤8(不含空行,从文件首个非空行到首个非注释代码行)。
|
||||
|
||||
白名单(只许两类):①职责摘要——这是什么,一句话;项目语境(垂直切片状态/验证目标)以括号并入本行。②使用约束——使用本文件前必须知道的禁令与边界,每条一行。
|
||||
|
||||
黑名单(出现即违规):日期与变更叙事——改动史查 `git log`/`git blame`,变更背景读迭代实现报告;与其他文档或其他文件头重复的内容——零新信息不写(pyguide §3.8.2.1);场景结构、生命周期等代码机制描述——"Never describe the code"(pyguide §3.8.5);一切文档反向链接——「实现 GDD:xxx」「指路:架构见 xxx」一类全部废止,代码↔设计追溯由 GDD 文档承担。
|
||||
|
||||
机器闸:`tools/audit_file_headers.py`(static_scan S10:行数上限+黑名单机械可判子集)。存量头注按白名单清偿(约 90 文件,清偿批进行中);清偿落地后闸增补「头注必须 `##` 开头」锁死载体;此间新增/改动的文件头必须即合规。
|
||||
|
||||
### 1.5 禁止事实约定
|
||||
任何"大家默认这么做"的惯例必须成文进本文件(或 AGENTS.md)才算存在。写代码时发现未成文但必须遵守的约定 → 当场补条文,不许靠惯性延续。
|
||||
|
||||
---
|
||||
|
||||
## 2. 契约纪律——跨层/跨类调用的语义
|
||||
|
||||
### 2.1 信号与事件契约成文
|
||||
每个跨类信号:参数语义、发送时点、消费方依赖,必须在发送方 `##` 文档注释成文,每信号一行;计入 §1.4.1 的 8 行上限,装不下时迁契约文档。状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
|
||||
|
||||
### 2.2 跨层标识符语义单一且成文
|
||||
位置(index)/ 句柄(handle)/ 键(key)是三种不同的东西。跨类传递标识符时,传递方的语义必须与接收方契约逐字一致,禁止凭"当前恰好相等"传值。
|
||||
|
||||
### 2.3 模态覆盖层层级规则
|
||||
覆盖层遮挡关系由场景树加入顺序决定。打开任何模态覆盖层时,必须显式隐藏会遮挡它的全屏层;新增覆盖层必须登记其在 z 序中的位置,并提供"打开可见性"的场景断言。
|
||||
|
||||
### 2.4 状态字段语义显式
|
||||
跨战斗/跨场景携带或恢复的状态字段,其语义来源必须显式(表值 / 明确入参),禁止用入参隐式定义。
|
||||
|
||||
---
|
||||
|
||||
## 3. 测试纪律
|
||||
|
||||
已独立成文:`design/engineering/test-conventions.md`(探针标配 / 回归断言 / 提交前全量验证 / 验收清单落码规范 / 变异验证)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 语言纪律——GDScript 4.x 实战坑(本项目踩实)
|
||||
|
||||
1. **多行 lambda 内禁止嵌套 match / 复杂控制流**(解析不可靠)——信号处理体一律抽成命名方法 + `bind` 传状态。
|
||||
2. **Dictionary 取值返回 Variant,无类型推断**——参与算术或传参前显式声明类型(`var x: float = ...`)。
|
||||
3. **RichTextLabel:`append_text()` 不回写 `text` 属性**——读可见文本用 `get_parsed_text()`。
|
||||
4. **lambda 捕获循环变量按创建时值**——循环内先落地局部变量再捕获,或用 `bind`。
|
||||
5. **重命名脚本必须同步 `.uid` 文件**;新增 `class_name` 后必须跑一次编辑器扫描刷新全局类缓存,否则 `--headless --script` 模式解析失败。
|
||||
6. **`print` 格式占位符与实参类型必须匹配**(`%d` 配 String = 静默输出字面量)。
|
||||
7. **语言纪律已机器化为 S9 类型闸**(迭代 27——2026-10-17 用户裁写入)——`tools/audit_type_hints.py`,执行载体=静态扫描域 S9(`game/tests/static_scan.sh`),退出码 0=归零。扫描面=产品码(`game/core`+`game/data`+`game/presentation`;smoke/tests 豁免——测量面容器直构是既有惯例)。三规则:R1 无类型容器(显式非参数化 `Dictionary`/`Array` 注解)/R2 有值返回缺返回类型(纯副作用缺 `-> void` 属写法面不入闸)/R3 参数缺类型(`_init` 豁免——构造注入面形态自由)。
|
||||
8. **`:= {}` 推断形态不算债**——`var x := {}` 类赋值推断属类型推断合法面,不入 R1 扫描;只有显式写的非参数化容器注解才算无类型容器。
|
||||
9. **行级白名单通道 `# type-hint: ignore`**——豁免该行不入 S9;豁免理由必须随行注明(现行例:`board_generator` 四函数的 db 参鸭子型——typed 参拒冒烟夹具 `_BoardRowStub` 注入)。
|
||||
10. **`# rng-seed-exempt` 标记豁免通道**——S1/S2 随机函数扫描对该行豁免;限定用途=非玩法 RNG 消费面的引擎熵(现行例:组合根种子编辑框空态取 `randi()`——建种子不进玩法封闭流)。
|
||||
11. **`--script` 模式禁裸 autoload 标识符**——`ConfigDB`/`RngService` 等 autoload 名在 `--headless --script` 模式编译器不解析(parse error);产品码与测试夹具一律经节点路径取用(`get_node("/root/…")`/`AUTOLOAD_PATH_*` 常量);静态扫描域 S5 硬失败承载在位。
|
||||
12. **Variant 参数化现行口径**——账本类字典/数组标注 `Dictionary[Variant, Variant]`/`Array[Variant]` 即合格(满足 R1);元素类型精化列后续事项、不入硬纪律,口径变更须用户裁决后续批次另行写入。
|
||||
|
||||
---
|
||||
|
||||
## 5. 数值与汇报纪律
|
||||
|
||||
### 5.1 数值口径必须显式标注尺度
|
||||
任何期望值/均值汇报必须写明口径:**每格 / 每板 / 每战 / 每关**。混用口径 = 误导。
|
||||
|
||||
### 5.2 调参先测量,改后复测
|
||||
改任何玩法数值前,先用扫描工具产出基线(通关率/难度类读数走 `balance_verifier.py` 冒险段,机制类读数走 `reward_expectation.gd` 等);改完必须复测回填数据。禁止拍脑袋调参。
|
||||
|
||||
### 5.3 数值设计必须跨尺度推演
|
||||
在单一尺度校准的数值,必须推演其在更大尺度的复合结果(每战合理 × 关内囤积 = 关卡灾难;反例见 code-conventions-cases.md §5.3)。
|
||||
|
||||
### 5.4 用户拍板的实现零发挥
|
||||
拍板范围外的细节一律不自行补全——以"待办问题"清单列出等裁决。
|
||||
|
||||
---
|
||||
|
||||
## 6. 流程纪律
|
||||
|
||||
1. **大改动三段走**:设计稿/伪代码 → 用户审阅 → 实现;实现禁止先于审阅。改动明细只进 git 提交信息,README 与代码内不写修改记录(doc-conventions 第 5 节「禁写变更记录」)。
|
||||
2. **实现批完成后的登记义务**:06 条目按 doc-conventions §12.1 推进状态,批次过程与结论进 git 提交信息与 `reports/`(2026-10-18 用户裁:根目录会话状态文件已废除,禁止再在其中登记条目)。
|
||||
3. **呈现层缺陷的教训回写 D1 GDD 设计输入**(信号载荷 schema / 场景级测试 / 时点状态可见性)。
|
||||
@@ -0,0 +1,53 @@
|
||||
# 概念与引用规范(Dungeon Sweeper)
|
||||
|
||||
> 约束范围:设计文档的概念建模与跨文档引用。写作层(句子、结构、骨架)归 `design/engineering/doc-conventions.md`;本文管概念怎么切、文档怎么互链。
|
||||
> 概念只在 owner 文档里定义一次;跨系统术语的规范名、定义与互斥关系登记在 `design/gdd/术语表.md`。某概念被谁引用,靠全仓搜索它的规范名得出,不设第二处登记表。
|
||||
|
||||
**写设计文档前必须通读本文。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 概念封装纪律(概念对象化建模)
|
||||
|
||||
动笔之前先做概念建模:像写代码划分对象那样,把设计切成分界清晰的概念——每个概念有自己的规范名、自己的属性、自己的规则,概念之间靠显式关系(包含、挂载、引用)连接,而不是把所有内容揉进一个概念里。概念没有边界,删除修改就得全仓翻找。
|
||||
|
||||
| 规则 | 内容 |
|
||||
|---|---|
|
||||
| 概念即对象 | 核心概念各自独立成体,有规范名、有属性、有规则边界;下笔前先能用一句"它是谁、它管什么"说清,说不清就是还没想完 |
|
||||
| 属性归属唯一 | 每个属性只归一个概念——离开 A 就没有意义的属性写在 A 名下,禁止上提给容器、也不下压给成员 |
|
||||
| 包含关系显式写 | 容器与成员的关系明文写出谁是容器、谁是成员、一对几(例:棋盘包含多个格);禁止让读者从散文里反推结构 |
|
||||
| 概念状态用枚举 | 概念的类型与状态写成封闭枚举并列全成员(例:格的类型 = 安全格 / 危险格,格的状态 = 未开 / 已开);禁止用散文形容词零散罗列状态 |
|
||||
| 附加物独立成对象 | 挂在概念上的附加内容若自己有一组属性或规则要写(例:格上的奖励/惩罚 = 格面资源),就是独立对象——父概念只保留挂载位(如"有无资源资格"),禁止把附加物摊平成父概念的一堆属性字段 |
|
||||
| 关系不吸内容 | 概念间关系只写"有没有关系、是什么关系";对方的属性与规则留在对方名下——与第 2 节"引用不转述"同源 |
|
||||
| 落位五要素 | 概念的权威文档必须写全五要素:**定义**(它是什么)/ **作用对象与范围**(作用在谁、什么范围内有效)/ **生命周期**(何时出现、何时变化、何时消失、怎么重置)/ **关联**(与谁衔接、边界归谁、哪些指路别处)/ **状态**(已定稿/待实施/已退役)。缺任何一项都是半成品概念,如同对象缺了构造函数 |
|
||||
|
||||
**切分正例**(现行排雷循环即按此切分):棋盘是地图级对象,包含多个格;格是成员对象,危险格/安全格是它的枚举属性;格上可能挂的奖励或惩罚(格面资源)是独立对象,本体与规则归地图战斗资源与战斗结算,格只保留"有无资源资格"一个挂载位。反面基准:把奖励的类型、数值、极性全摊开写成格子的属性字段——奖励规则一改,棋盘文档就得跟着改,这便是没封装。
|
||||
|
||||
**无权威文档,不下定义**:一个概念还没有权威文档时,任何其他文档都禁止替它下定义——只能引用概念名,并在 `design/gdd/06-待办清单.md` 登记「待落位」;谁先立权威文档,谁拿走全部定义权。(反例:某概念长期无权威文档,art-bible 复述、06 登记、需求卡片摘要三处各自给出口径,范围限定词在层层复述中丢失,最终放大成「全板常显」的错误事实。)
|
||||
|
||||
**与引用纪律的关系**:第 1 节管单个概念的边界与归属(概念级封装),第 2 节管概念之间、文档之间的引用(跨文档解耦)——先有封装,第 2 节的单点定义、反向边与删除 SOP 才有干净的作用对象。
|
||||
|
||||
## 2. 引用纪律(跨文档高内聚低耦合)
|
||||
|
||||
目标:修改或删除一个概念时,只改它的 owner 文档;引用方最多删掉一个链接。反例模式:同一概念多名并存、机制被织进多份文档的规则正文——删除时全仓几十处文字修改与大量事后一致性复查。
|
||||
|
||||
| 规则 | 内容 |
|
||||
|---|---|
|
||||
| 单点定义 | 每个概念只在 owner 文档里定义一次,其规范名与定义收进 `design/gdd/术语表.md` |
|
||||
| 规范名唯一 | 正文只准用规范名,禁止别名散开——否则删除时 grep 搜不全 |
|
||||
| 引用不转述 | 跨文档引用 = 规范名 + 链接,禁止复述对方的规则细节、公式、数值与口径;确需携带口径时,作用对象/范围/生命周期必须随句写全或显式指路——禁止只复述形容词,「常显」「恒亮」这类词不带范围就是半句话;若发现自己需要一条规则,那是自己的概念,先立权威文档再定义 |
|
||||
| 引用落到对外承诺 | 跨文档链接只锚到对方文档明示的对外内容(事件、接口、规则条目),不锚其内部细节 |
|
||||
| 依赖逐条列出 | 系统文档的「依赖与输出」节逐条列出本系统依赖的他人概念(规范名 + 链接)——这份清单就是删除概念时的影响面清单 |
|
||||
| 引用可查 | 需要某概念的影响面时,全仓搜索它的规范名即得;被引方在自己的「依赖与输出」节写明谁依赖它。人工维护的反向边清单已废止(2026-10-19 核出旧登记漏 7 份、多 1 份) |
|
||||
| 链接断了也好读 | 引用处的句子在链接失效后仍通顺完整(写"变异规则见《地形变异》",不把半截语义挂在链接里) |
|
||||
| 待办单点登记 | 全项目待办事项单点登记于 `design/gdd/06-待办清单.md`:系统文档的「待办」节只留指路存根,禁止自建条目表;新增待办条目直接登记清单,裁决后改「状态」列留痕、不删条目 |
|
||||
|
||||
**引用格式**:一律 Markdown 相对链接,指向文件、必要时带节锚点(例:`[地形变异 · 变异类型](systems/排雷循环/地形变异.md#变异类型)`)——机械可查,死链可被工具检出。
|
||||
|
||||
**删除概念 SOP**:① 全仓搜索该概念的规范名,得到影响面清单 → ② owner 文档删除概念 → ③ 纯引用方删链接即完事;机制被织入对方规则的,按清单逐处修订 → ④ 收尾跑一遍死链检查,全绿即干净。
|
||||
|
||||
**诚实边界**:机制耦合无法靠删链接消灭——别人的规则真的因你的概念而改变时,改内容不可避免。引用纪律保证的是:这类修改有一份现成清单(反向边 + 依赖节),不用事后全仓搜索。
|
||||
|
||||
## 3. 归档与事实源
|
||||
|
||||
- 旧文档里的概念写进现行文档时,必须翻译成现行术语与现行决策口径(例:已退役机制禁止作为现行机制引用)。
|
||||
@@ -0,0 +1,226 @@
|
||||
# 文档写作规范(写文档前必读)
|
||||
|
||||
> **地位**:本文是文档写作的规范权威,与 `design/engineering/code-conventions.md`(代码规范)对等;AGENTS.md 只留导航指针,细则以本文为准。
|
||||
> **适用范围**:`design/` 下一切现行文档与根目录 `roadmap.md`;概念建模与跨文档引用见 `design/engineering/concept-conventions.md`。
|
||||
|
||||
## 0. 总纲
|
||||
|
||||
默认读者没读过项目历史——可能是半年后的你自己。先让人读懂,再谈结构整齐。
|
||||
|
||||
## 1. 可读性第一(最高纪律)
|
||||
|
||||
**读者测试是每个小节的验收标准**:只读这一节,回答三个问题——这节管的是谁/什么?在什么情况下?会发生什么?答不出来,就重写这一节,而不是给看不懂的地方补注释。
|
||||
|
||||
旧体系 lean 格式六条硬规则已停用(其解读对象 `design/archive/` 旧档已删除,现无适用文档;原表格占比 30% 口径随之作废)。`tools/gdd_lint.py` 现为现行文档机检三闸之一(gdd_lint / doc_link_audit / doc_term_audit,分级周期口径见 AGENTS.md);可读性仍是第一内容质量门,lint 是格式机检面,两者并行。
|
||||
|
||||
## 2. 白话写作规则
|
||||
|
||||
写文档像向朋友当面解释你的游戏:
|
||||
|
||||
1. **完整句子优先**:一段只说一件事,长句拆短句。
|
||||
2. **禁止碎片笔记体**:不写压缩碎片,不把 `A→B→C` 箭头链当叙述(流程交给字符画,见第 3 节),不用只有作者自己懂的缩略语。
|
||||
3. **每节人话开头**:每小节第一段先用白话说清"这是什么、为什么需要它";只读各节第一段就能看懂全文故事线。
|
||||
4. **术语首现即解释**:专业术语或项目概念首次出现用一句话解释;玩家可见专属名词(如"显影尘")同样要说清。
|
||||
5. **叙述优先于引用**:AC-x、F-x 等编号引用不进正文叙述,只出现在验收标准与附录。
|
||||
6. **反面基准**:数据库条目、会议纪要、只有评审工具能"读懂"的表格堆。
|
||||
|
||||
## 3. 表达分工:散文、表格、字符画、公式
|
||||
|
||||
| 内容 | 载体 | 纪律 |
|
||||
|---|---|---|
|
||||
| 规则的来龙去脉、行为逻辑 | 散文段 | 每段 ≤240 字,一段一件事 |
|
||||
| 枚举、数值、边界、依赖 | 表格 | 表格只放可列举的事实;禁把需要解释的内容塞进单元格让读者自己拼 |
|
||||
| 流程、状态流转 | 字符画(代码块) | 禁用散文逐步描述流程 |
|
||||
| 公式 | 结论先行 | 先一行加粗结论,再放公式代码块、变量表与验算表 |
|
||||
| 体验锚点 | 关键词表 | 支柱/关键词/机制承诺 三列表,禁长篇情绪描述 |
|
||||
|
||||
节点内顺序:先人话,再表格枚举,再字符流程图,最后公式举证。**规则两段式**:先写"人话阶段"(作用于哪个系统、什么情况下、谁触发、触发后发生什么),再写"举证阶段"(逐效果给出计算方法;纯流程规则明写"无计算")。规则名禁止纯名词短语(反面例:"获取路由")。
|
||||
|
||||
## 4. 用语纪律(见名知意 · 所见即所得 · 禁自造黑话)
|
||||
|
||||
**正面总则**:见名知意——每个名字(概念名、术语、文档与目录名)本身就说清所指,起不出这样的名字多半是概念还没想清;所见即所得——字面意思就是规则的完整意思,有隐含前提就写进句子。两句管语义透明,不与第 8 节指路存根冲突。
|
||||
|
||||
文档、评审输出、日志与一切沟通中**禁止自造黑话**——比喻性生造词、只有作者自己懂的缩略语:
|
||||
|
||||
- 只能使用:(a)人人可懂的直白语言,或(b)游戏行业通用术语(如 flood fill、战争迷雾、连锁展开、结算、增益/减伤)。
|
||||
- 指代新概念用直白描述性短语(正例:"实测可推理率");确需命名时:首现处附一句白话定义,并登记进 `design/gdd/术语表.md`。
|
||||
- 唯一例外:玩家在游戏里也会看到的专属名词(道具名、界面用语)。文档内部的机制概念不得造词。
|
||||
|
||||
**自造词的三种固定形态(全部禁止)**:
|
||||
|
||||
| 形态 | 反例 | 正确写法 |
|
||||
|---|---|---|
|
||||
| 给工作包起代号 | "样张批""八型批" | 叙述名 = 日期 + 做什么 |
|
||||
| 给机制、检查、基线、区域造名词 | "形象锚""判读口径""变异纹带" | 用行业通用词;长期复用的概念走登记通道(正常名字+白话定义+登记进 术语表) |
|
||||
| 给流程步骤造动词 | "收口""落籍""在飞""随批""对拍""销账""正主""台账" | 用日常动词:完成 / 合并进 master / 执行中 / 顺带 / 与基线数据逐项比对 / 注销 / 定义所属的那份文档 / 状态记录 |
|
||||
|
||||
**通行检验标准**:读者是业内人但没读过项目历史——需要作者解释才懂的词不合格,必须展开成完整白话句(换新名词不算改,展开才算改)。**写后自查**:凡自己都要停顿才能想起意思的词,一律展开。
|
||||
|
||||
## 5. 结构纪律
|
||||
|
||||
| 规则 | 内容 |
|
||||
|---|---|
|
||||
| 树形文档体系 | 全部设计文档构成一棵树;文档增删必须同步根索引 `design/gdd/02-系统清单.md` |
|
||||
| 架构事实唯一源 | `design/engineering/architecture/architecture.md` 是架构事实的唯一权威(分层/模块归属/数据流/API 边界/测试与质量域);禁建第二份架构文档;历史决策记录只进 git commit log |
|
||||
| 一页纸节点 | 一节、一条规则 ≤一页纸(约 ≤80 行);装不下就拆节 |
|
||||
| 一系统一文档 | 不建 analysis 推演件;两三句能说清的"为什么"直接写进设计目的或规则正文 |
|
||||
| 正文只写现行规则 | 禁删除线、"(作废)"、"(日期+拍板)"式注记;审计信息入对应文档附录 |
|
||||
| 正文单点维护 | 一条规则句只写在定义它的那份文档(owner 文档);其他文档要引用时写指针或语义概括,禁复制色值、尺寸、路径等可核对的具体值——上一句管不住数值之外的双写,本句补上。豁免面 = 执行侧文件必须带字面值才能工作时(生图提示词里的十六进制色、脚本参数),转写不算双写,但该文件头部必须写明"冲突时以 owner 文档为准" |
|
||||
| 禁写变更记录 | 文档与代码文件内一律禁设「版本历史/修订记录/变更记录/修改记录/更新记录/更新日志」节或表格,禁逐版本叙述「改了哪些条款」;沿革与改动明细只进 git commit log。版本号可作为文档现行身份标记出现在文首状态行与正文引用中,但不得再挂变更表 || 后置 ≠ 删除 | P1/P2 后置内容逐条列出;复活后置项 = 修订文档,禁静默加回 |
|
||||
|
||||
**数值纪律**:正文定规则、取值域、单位;平衡值进 `data/tables/`,provisional 必须标注;已锁数值事实源 = `game/data/tables/*.tres`(现行值)与 owner 文档正文(规则、取值域、单位)。
|
||||
|
||||
**登记处唯一性(2026-10-19 用户裁)**:`design/registry/`(`entities.yaml`/`architecture.yaml`)已注销删除,禁再建第二处事实登记——术语进 术语表、数值进 `.tres`、架构进 架构文档、影响面靠全仓搜索概念规范名得出。强制收口条款:
|
||||
|
||||
1. **双写失同步禁止**——任何数值变更必须同时同步引用该数值的 GDD 表格正文、`data/tables/` 行值与 schema 校验域、相关待办清单现状——三类之一未更新即视为变更未完成。
|
||||
2. **调参表锁数后删现行值列**——仅留 schema 模板与取值域,只留 schema 模板与取值域,指针指向 `.tres` 对应行键。
|
||||
3. **覆盖范围** = 奖励/状态/敌人/技能/充能/护甲等级/区间掷点/难度曲线/D_ref 等所有数值字段。
|
||||
4. **维护通道** = 「设计批 → 同步批」两段式;数值表改完不等于修订完成。
|
||||
5. **压缩/换装批** = 「`.tres` 落批 + 切片 smoke 跑通 + GDD 表格改为只留取值域与 `.tres` 指针 + 待办清单刷新」四步全收才记版本号。
|
||||
|
||||
## 6. 文档类型与骨架
|
||||
|
||||
**顶层文档**:
|
||||
|
||||
| 文档 | 管什么 |
|
||||
|---|---|
|
||||
| `00-游戏概念.md` | 一句话概念、目标受众、世界观命名、术语层级 |
|
||||
| `01-核心循环.md` | 玩家醒来→做什么→得到什么→又想做什么,一条线讲清 |
|
||||
| `02-系统清单.md` | 根索引:循环 × 子系统总表 + 文档树导航 |
|
||||
| `03-内容规模.md` | 几个关卡、几种敌人、几种道具——做多少砍多少 |
|
||||
| `04-美术音频方向.md` | 参考图、参考游戏、风格关键词 |
|
||||
| `05-不做清单.md` | 明确写:这些我不要 |
|
||||
| `06-待办清单.md` | 流水线唯一登记处:条目=登记元数据标题+四属性正文,状态随流水线段推进(格式与状态机见第 12.1 节);各系统文档「待办」节只留指路存根 |
|
||||
| `roadmap.md`(根目录) | 里程碑表+迭代总表,一行一迭代,记录编排与实现进度(六列格式见第 12.2 节) |
|
||||
|
||||
**系统文档骨架**(`systems/` 下统一采用):文首引言(一句话定位+状态)/设计目的(2-4 句白话)/系统范围(负责/不负责两表)/在核心循环中的位置(字符画一行+两句白话)/核心规则(领域章节 ×2–6,每节一页纸)/依赖与输出(表格;引用纪律见 concept-conventions)/P0 最小闭环与 P1·P2 后置/调参表(取值域+provisional 标注)/验收标准(可验证判据)/待办(指路存根)。
|
||||
|
||||
**命名**:中文、见名知意;禁 a1_/b1_ 编号前缀;不留纯空目录。正文指代子系统一律用中文规范名;英文代号对照表见 `02-系统清单.md`,旧代号(a1–d6)仅限解读归档。
|
||||
|
||||
## 7–9. 概念封装 / 引用纪律 / 归档与事实源——已独立成文 `design/engineering/concept-conventions.md`
|
||||
|
||||
## 10. 会话状态——仓库根不设状态文件
|
||||
|
||||
**2026-10-18 用户裁:根目录 `active.md` 连同「会话状态唯一状态源」这条规矩一起废除。** 判据来自对 869 个历史会话的读写统计:整文件被读 448 次、平均每次 14 KB 进上下文,但会话里关于它的思考九成花在「追加条目前先查尾部编号防撞号」与「并行会话同时改它导致的合并冲突与丢弃」上,明确写「从它所载内容得知某事实」的只有 20 个会话;文件 45 KB 里约 95% 是别处已有权威源的重复说法、已失真陈述或已完结批次的历史叙述。体量闸只能测条目数与死链,测不出语义失真:10-15 清到 8.6 KB/3 条,10-17 已回到 40 KB,用户为「只写不删」连续三次发火,规矩照样失效。
|
||||
|
||||
废除后的分工:**现在做什么**看根目录 `roadmap.md` 顶部「当前位」节;**待办与待裁**看 [06-待办清单](../gdd/06-待办清单.md)(唯一登记处);**批次过程与结论**看 git 提交信息与 `reports/`;**跨会话教训**看记忆库。禁止在仓库根新建同类状态文件,也禁止在任何文档里另设「当前状态快照」节——两处记同一件事必然漂移,这正是本次统计查出七条失实陈述的成因。
|
||||
|
||||
## 11. 文档生命周期:吸收即死
|
||||
|
||||
**活文档**=唯一事实源长期维护:GDD 树、art-bible 等定稿规范、术语表、架构文档(`design/engineering/architecture/architecture.md`)、本规范、06-待办清单、roadmap。**中间文档**=脚手架,寿命=迭代寿命:批需求卡片、机检/验收过程报告、调研/审计报告、模拟读数、迭代计划书、目检清单。为什么:了解游戏看 GDD,了解变更看 git;增量中间文档让版本管理失去意义,原始数据 dump 是化石不是证据。
|
||||
|
||||
| 规则 | 内容 |
|
||||
|---|---|
|
||||
| 吸收即死 | 中间文档结论写进权威文档(GDD 对应节/art-bible/术语表)那一刻,文件即删 |
|
||||
| 未决先迁再死 | 未决内容先迁现行事实源(06/roadmap 卡/GDD 对应节),然后文档即死 |
|
||||
| 永不入库 | 迭代出口后中间产物一律删除且不许提交;迭代进行中可暂存工作区,出口批一并清 |
|
||||
| 引用面口径 | 活文档对中间文档的指路阻塞删除:先改写指路句为结论内联或 git 提交号再删 |
|
||||
| 删除不留死链 | 中间文档删除后,任何现行文档禁止再留指向它的文件路径;改指结论或提交号 |
|
||||
| sim-data 白名单 | 只留 README、日志、分析工具 .py、现行 MC 对拍锚、设计文档 md;可再生原始数据不入库 |
|
||||
| 出口清理项 | 每迭代出口检查单必含:本迭代中间产物逐份核对(结论已吸收、未决已迁移)后删除 |
|
||||
| 暂存地非档案库 | 中间文档有两处暂存地,入内文件默认到期即死:`reports/`(需求卡片+迭代产出物)、`design/research/`(调研/提案/评估/历史验收)。`design/` 各子目录不留验证截图——截图属一次性凭据,结论写进 06 或需求卡片后图像即弃(在途图放 `artwork/`,整目录不入 git);只有需要机器逐像素比对的基线图长期入库,落 `game/tests/golden/` |
|
||||
| 落档必写接收方 | 新报告落档时头部必须写明接收方——`06-待办清单.md` 第几条,或哪张需求卡片。写不出接收方的不落文件,内容在会话里交付即可 |
|
||||
| 迭代实现报告 | 实现批收口的迭代级报告(各卡状态/代拍板追认单/GDD 反哺点清单),属中间文档,**落 `reports/` 不落 `design/`**(2026-10-17 用户裁:实现批禁写 `design/`,`reports/` 是其唯一可写目录):反哺点裁决落文吸收后按「证据只留最新」退役 |
|
||||
| 证据只留最新 | 测试证据只保留最新一次迭代或最新一轮同类审计版本;新证据落位后同批删上一份;待人清单过人闸后同规退役 |
|
||||
|
||||
**删除方式**:按 `design/engineering/concept-conventions.md` 第 2 节删除概念 SOP 口径——先查引用面(grep 文件名于阻塞域),改写或删除指路句,再删文件,收尾跑死链检查全绿。执行入口=项目技能 batch-closure(批后收尾与中间文档退役)。
|
||||
|
||||
## 12. 流程文档格式
|
||||
|
||||
五段流水线(登记 → 文档设计/美术设计 → 写卡 → 迭代编排 → 实现,流程纪律见 `design/engineering/process-conventions.md` §2)靠流程文档运转:06-待办清单登记要做的事,roadmap 记录迭代编排结果,artwork 目录承载美术在途素材。本节是这些流程文档的格式与状态机权威,也是流水线闸(`tools/pipeline_gate.py`,自动检查 06 与 roadmap 两文件格式及互相引用的机检闸)的判据依据。
|
||||
|
||||
### 12.1 06-待办清单条目格式与状态机
|
||||
|
||||
06-待办清单是流水线的唯一登记处:要做的事先登记一条,随流水线段推进改状态,做完整条删除。一条条目分两层——**标题=登记元数据**(何时登记、从哪来、走哪条设计轨,登记后不再变),**正文=四个属性**(随进程演进)。
|
||||
|
||||
标题格式(尖括号处按实际填写):
|
||||
|
||||
```
|
||||
#### <条目名>(<YYYY-MM-DD>登记,来源=<playnote/会话提及/审计发现/批次移交>,设计面=<文档轨/美术轨/双轨/工程直入/反哺点>)
|
||||
```
|
||||
|
||||
正文四属性模板:
|
||||
|
||||
```
|
||||
**现状**:现在缺什么、为什么是问题(关键处带 file:line 或文档指针)。工程直入条目必须在现状里指认证据(bug 证据或工程债条目)。
|
||||
**缺口**:还差哪一次设计讨论/哪份设计产物才能写卡。尚有未闭合的设计轨时此属性必须存在;全部设计轨闭合后删除。
|
||||
**归属**:主责系统文档或线别。
|
||||
**状态**:按状态机取词。
|
||||
```
|
||||
|
||||
状态机按标题里的设计面分轨,状态一律取下例用词。状态行按**状态段累积制**书写:条目每推进一段,就把新状态段接在状态行末尾,段与段用+号连接,书写顺序=推进顺序;已过去的段一律保留、禁删——闭合凭据要留在行内,编排四查与开工核验拿它比对。每段各自按状态词白名单与凭据规则校验,+号只作状态段连接符。
|
||||
|
||||
```
|
||||
各轨推进序列(双轨条目设计阶段两段并列推进,一文档轨一美术轨):
|
||||
文档轨:待文档设计 → 文档设计中 → 文档设计已闭合(凭据=文档路径+版本号,
|
||||
例:文档设计已闭合(design/gdd/systems/xxx.md v1.2))
|
||||
美术轨:待美术设计 → 美术设计中 → 美术设计已闭合(凭据=样张过审、art-bible 条款版本,
|
||||
例:美术设计已闭合(样张过审、art-bible v3.x))
|
||||
双轨条目设计阶段示例:文档设计已闭合(design/gdd/systems/xxx.md v0.6)+美术设计中
|
||||
进入下游段(待写卡及之后)的前置条件——双轨:两个设计轨段都在场且都已闭合(带凭据);单轨:本轨闭合段(带凭据)在场
|
||||
下游共用序列:待写卡 → 已写卡(reports/ 下的需求卡片路径)→ 已编迭代 N → 完成即整条删除
|
||||
单轨累积示例(已编迭代):文档设计已闭合(design/gdd/systems/xxx.md v1.2)+已写卡(reports/需求卡片-xxx.md)+已编迭代 2
|
||||
```
|
||||
|
||||
凭据括号内禁用+号——+只作状态段连接符,凭据内需要并列多项时用顿号(如上例「样张过审、art-bible v3.x」),用+会被流水线闸误判为状态段。已编迭代 N 段的交叉核依据=同状态行内「已写卡」段括号里的卡片路径。
|
||||
|
||||
三条特殊通道:
|
||||
|
||||
| 设计面 | 通道规则 |
|
||||
|---|---|
|
||||
| 工程直入 | 缺陷修复/工程债/测试基建/重构四类工程条目:登记即「待写卡」,凭现状里指认的证据跳过设计轨 |
|
||||
| 反哺点专条 | 待裁决 → 已写入(落点=文档+版本)→ 删除 |
|
||||
| 备选库条目 | 暂不排期、留在备选库的条目:状态词后缀「(备选)」 |
|
||||
|
||||
「已闭合」不带凭据不算合法状态词。特批标记见 12.4。
|
||||
|
||||
### 12.2 roadmap 迭代行格式
|
||||
|
||||
roadmap 由顶部里程碑表+迭代总表组成,迭代总表一行一个迭代,回答一个问题:这个迭代编入了哪些卡、做到哪一步。迭代行六列:
|
||||
|
||||
```
|
||||
| 迭代号 | 状态 | 需求卡片 | 编入时间 | 预计周期 | 实现报告 |
|
||||
```
|
||||
|
||||
| 列 | 规则 |
|
||||
|---|---|
|
||||
| 迭代号 | 写「迭代 N」形态(N 为阿拉伯数字);这是流水线闸交叉核匹配的依据 |
|
||||
| 状态 | 待开工 / 进行中 / 已完成(YYYY-MM-DD)/ 已终止(YYYY-MM-DD) |
|
||||
| 需求卡片 | 只写文件路径;一格内一行一卡,格内排列顺序=执行顺序;已退役填保留字「已退役(git 历史可考)」;历史迭代不可考填「—」(早期无卡片制的迭代) |
|
||||
| 编入时间 | YYYY-MM-DD(该迭代最近一次编入卡片的日期);历史迭代不可考填「—」 |
|
||||
| 预计周期 | ≈N 周(0.5 步进,N ≤ 2);超过 2 周须随带日期的用户特批标记(格式见 12.4),流水线闸见标记放行、无标记判红;历史迭代不可考填「—」(不做 ≤2 周判) |
|
||||
| 实现报告 | `reports/iterN-实现报告-YYYY-MM-DD.md`;未完成=「—」;退役=「已退役(git 历史可考)」;已完成迭代只许存在路径或退役保留字、禁「—」 |
|
||||
|
||||
迭代行禁入内容:事项说明、卡序叙述、T 段明细、读数、闸数字、裁点记录、门依赖。卡间依赖写在卡片自身,行内只放上表六列的事实。特批标记同样可用于 roadmap 格(须带日期,见 12.4)。
|
||||
|
||||
### 12.3 美术工作区目录与命名
|
||||
|
||||
美术素材走两条目录线:在途工作在 `artwork/`(整目录不入 git),定稿进 `game/assets/art/`(入包被游戏加载)。图片永不进 `design/`。
|
||||
|
||||
| 位置 | 规则 |
|
||||
|---|---|
|
||||
| `artwork/<YYYY-MM-DD-主题>/` | 批次工作区,一次美术批一个目录,整目录不入 git |
|
||||
| `artwork/<批次工作区>/samples/` | 样张子目录 |
|
||||
| `artwork/archive/<主题>-<日期>/` | 批次完结归档 |
|
||||
| `game/assets/art/<用途子目录>/` | 终稿,入包被游戏加载 |
|
||||
|
||||
命名总则:全小写英文+下划线,禁中文/空格/大写。
|
||||
|
||||
| 对象 | 文件名规则 |
|
||||
|---|---|
|
||||
| 终稿 | 三段式 `<对象>_<部位或状态>_<规格>.png`;终稿文件名=代码消费名——先定 ui_kit/资源路径常量,素材名跟它走,防断链 |
|
||||
| 样张 | `sample_<屏名>_<版本>.png` |
|
||||
| 同名迭代 | 直接覆盖,不留 v2 副本 |
|
||||
|
||||
美术内容不做机检,只保留命名与目录检查。
|
||||
|
||||
### 12.4 特批标记
|
||||
|
||||
特批标记是流程格式例外的唯一放行凭证:`〔用户特批 YYYY-MM-DD 跳过××〕`。只有用户明示才能给,用于 06 条目状态与 roadmap 格(见 12.1、12.2)。
|
||||
|
||||
执行技能一律两段式:
|
||||
|
||||
1. 对象已有内容 → 直接写入标记。
|
||||
2. 对象没有任何内容 → 必须回呈实况,经用户再次确认后才写标记。
|
||||
|
||||
标记必须带日期,无日期=非法。流水线闸见合法特批标记放行对应判据。
|
||||
@@ -0,0 +1,46 @@
|
||||
# Godot — Version Reference
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Engine Version** | 4.7.2-stable(2026-08-18 发布) |
|
||||
| **Project Pinned** | 2026-09-07 |
|
||||
| **LLM Knowledge Cutoff** | May 2025(训练数据覆盖 ~4.3/4.4) |
|
||||
| **Risk Level** | **MEDIUM**(2026-09-12 降级)——4.5→4.7 API 级破坏性变更已逐条核实(源:官方迁移指南),无一条破坏本项目架构契约;残余风险 = 4.8(dev 阶段)未来升级 + 未覆盖的运行期边角行为,代理写码规则不变:不确定的 API 一律查 `docs.godotengine.org/en/4.7/` 或 WebSearch 核实后再用 |
|
||||
| **Last Docs Verified** | 2026-09-12(4.5/4.6/4.7 迁移指南逐条核实 + 版本检查:4.7.2 仍为最新稳定版,4.8 仅 dev 快照) |
|
||||
|
||||
## Post-Cutoff Version Timeline
|
||||
|
||||
| Version | 发布 | 与本项目相关要点 |
|
||||
|---|---|---|
|
||||
| 4.4 | 2025-03(训练覆盖边缘) | — |
|
||||
| 4.5-stable | 2025-09-15 | stencil 效果、无障碍改进;4.5.2(2026-03-19)为末版维护;**逐条变更已核实(2026-09-12)** |
|
||||
| 4.6-stable | 2026-02 起(4.6.1 2026-02) | Modern 主题、flexible docks、编辑器 QoL;4.6.3 维护;**逐条变更已核实(2026-09-12)** |
|
||||
| **4.7-stable** | 2026-06(**4.7.2 = 2026-08-18,本项目锁定**) | 见下;**逐条变更已核实(2026-09-12)** |
|
||||
| 4.8 | dev 快照 1–4(开发中) | 无稳定版发布日期;稳定版发布后跑 `/setup-engine refresh` |
|
||||
|
||||
## 4.7 与本项目相关的变更(已核实)
|
||||
|
||||
- `Tween.tween_await()`(信号等待)——**不影响** B1"结算逻辑禁 await"约束(那是设计约束,非引擎限制)
|
||||
- Control `offset_transform_*`(平移/旋转/缩放 Control 而不影响容器布局)——D1 HUD 可用
|
||||
- DrawableTexture2D、AreaLight3D、HDR 输出、新 Asset Store——本项目暂不依赖
|
||||
- 2D:CollisionShape2D 单向碰撞方向属性、conic gradient、AtlasTexture 进 TextureRect
|
||||
- **GDScript 两条语义变化**(打包数组元素赋值不触发属性 setter;类型化返回覆盖必须显式 return)——详见 `current-best-practices.md`
|
||||
- **新项目默认值已变**(stretch mode `canvas_items`、aspect `expand`;4.6 起 Windows 驱动 D3D12)——详见 `current-best-practices.md`
|
||||
- Android/iOS/XR 增强——本项目 PC 先行,无关
|
||||
|
||||
## Migration Guides(升级/写码前必读)
|
||||
|
||||
- 4.7: https://docs.godotengine.org/en/4.7/tutorials/migrating/upgrading_to_godot_4.7.html
|
||||
- 4.6 / 4.5 同路径模式:`.../tutorials/migrating/upgrading_to_godot_4.6.html`、`..._4.5.html`
|
||||
- 三份指南的逐条中文对照与项目相关性标注见 `breaking-changes.md`(2026-09-12 版)
|
||||
|
||||
## Note
|
||||
|
||||
**MEDIUM 风险处置(2026-09-12 更新)**:4.5→4.7 的 API 级破坏性变更清单已逐条核实并入 `breaking-changes.md`,deprecated → replacement 对照已并入 `deprecated-apis.md`;对本项目的结论 = **无一破坏 GDD 已锁架构契约**。残余风险两项:① 4.8 未来升级(dev 阶段,稳定版后 refresh);② 运行期边角行为(迁移指南未覆盖的引擎内部行为差异)——代理写码规则保持不变:**不确定的 API 一律查 `docs.godotengine.org/en/4.7/` 或 WebSearch 核实后再用**。
|
||||
|
||||
## Verification History
|
||||
|
||||
| 日期 | 动作 |
|
||||
|---|---|
|
||||
| 2026-09-07 | 初次锁定 4.7.2;核实版本时间线与 4.7 特性清单 |
|
||||
| 2026-09-12 | `/setup-engine refresh`:4.5/4.6/4.7 官方迁移指南逐条核实(breaking-changes.md 逐条清单 + deprecated-apis.md 对照表 + 新建 current-best-practices.md);版本检查确认 4.7.2 仍为最新稳定版(4.8 仅 dev);风险等级 HIGH → MEDIUM |
|
||||
@@ -0,0 +1,115 @@
|
||||
# Godot Breaking Changes(4.4 → 4.7)
|
||||
|
||||
> **Last verified: 2026-09-12**(官方迁移指南三份逐条核实——4.5/4.6/4.7 API 级清单已补全,原 2026-09-07"待 refresh"状态解除)
|
||||
> 训练数据覆盖至 ~4.4:4.4 及以前的变更视为"已知基线",4.5+ 为超出截止的增量。
|
||||
> 官方迁移指南(升级/写码前必读):
|
||||
> - 4.5:https://docs.godotengine.org/en/4.7/tutorials/migrating/upgrading_to_godot_4.5.html
|
||||
> - 4.6:https://docs.godotengine.org/en/4.7/tutorials/migrating/upgrading_to_godot_4.6.html
|
||||
> - 4.7:https://docs.godotengine.org/en/4.7/tutorials/migrating/upgrading_to_godot_4.7.html
|
||||
>
|
||||
> 项目相关性图例:🔵 需要留意(本项目域内)/ ⚪ 本项目不用(3D/XR/网络/移动/GLTF/编辑器插件)。
|
||||
> 本项目形态:2D 回合制、GDScript 单语言、Control 重 UI、autoload + .tres、无 3D/物理/网络。
|
||||
|
||||
## 4.5(2025-09-15)
|
||||
|
||||
### API 级变更
|
||||
|
||||
| 类/方法 | 变更 | GDScript 兼容 | 项目相关性 |
|
||||
|---|---|---|---|
|
||||
| `Resource.duplicate(true)` | 深复制**不再覆盖外部子资源**;旧行为需 `duplicate_deep(DEEP_DUPLICATE_ALL)` | 行为变更 | 🔵 D2 schema/表资源复制语义注意 |
|
||||
| `Node.set_name` | 参数 `String` → `StringName` | 兼容 | 🔵 |
|
||||
| `JSONRPC.set_scope` | 更名 `set_method` | ❌ | ⚪ |
|
||||
| `Node.get_rpc_config` | 更名 `get_node_rpc_config` | ❌ | ⚪(RPC 不用) |
|
||||
| `RenderingServer.instance_reset_physics_interpolation` | **移除** | ❌ | ⚪(3D 插值) |
|
||||
| `RenderingServer.instance_set_interpolated` | **移除** | ❌ | ⚪ |
|
||||
| TextServer/Font/CanvasItem/TextLine/TextParagraph 全部 draw 方法 | 新增可选 `oversampling` 参数 | 兼容 | 🔵 D1 自绘文字 |
|
||||
| `TextServerExtension` 四个 draw 虚方法 | 同上签名变化 | ❌(全不兼容) | ⚪(不实现 TextServer 扩展) |
|
||||
| `RichTextLabel.add_image`/`update_image` | `size_in_percent` → `width_in_percent` + `height_in_percent` | 兼容 | 🔵(低——富文本用图时) |
|
||||
| C# `RenderingDevice.Features.Address` | 更名 `BufferDeviceAddress` | 仅 C# | ⚪(C# 不用) |
|
||||
| GLTF Accessor/BufferView 十字段 | int32 → int64 / 枚举化 | 仅 C# | ⚪(GLTF 不用) |
|
||||
|
||||
### 行为变更
|
||||
|
||||
- **TileMapLayer 物理分块默认开启**;`get_coords_for_body_rid()` 返回值变化;需 4.4 精确行为设 `physics_quadrant_size=1` —— 🔵 若棋盘实现走 TileMapLayer(当前设计倾向自绘,未定)
|
||||
- 3D 模型导入 skeleton 行为修复(新文件新行为;旧文件需改 Import Naming Version)—— ⚪
|
||||
- Navigation 区域默认异步线程更新;navmesh 合并次序变化 —— ⚪(A2 用自研 BFS,不用 NavigationServer)
|
||||
- Jolt:`areas_detect_static_bodies` 设置移除 —— ⚪
|
||||
- `ProjectSettings.add_property_info()` 对缺失/非法键(含 `usage`)告警 —— 🔵(若程序化注册设置项)
|
||||
|
||||
## 4.6(2026-02)
|
||||
|
||||
### API 级变更
|
||||
|
||||
| 类/方法 | 变更 | GDScript 兼容 | 项目相关性 |
|
||||
|---|---|---|---|
|
||||
| `FileAccess.get_as_text` | `skip_cr` 参数**移除** | ❌ | 🔵 文本读取路径 |
|
||||
| `FileAccess.create_temp` | `mode_flags` int → `ModeFlags` 枚举 | 兼容性检查变化 | 🔵 |
|
||||
| AnimationPlayer `assigned_animation`/`autoplay`/`current_animation` | `String` → `StringName`(`get_queue()`、`current_animation_changed` 信号参数同步) | ❌(类型不兼容) | 🔵 B5 期 |
|
||||
| SpringBoneSimulator3D 三个枚举 | 移至 `SkeletonModifier3D` | ❌ | ⚪ |
|
||||
| StreamPeerTCP / TCPServer | `disconnect_from_host`/`get_status`/`poll`、`is_connection_available`/`is_listening`/`stop` 上移至 `StreamPeerSocket`/`SocketServer` 基类 | 兼容(继承) | ⚪(网络不用) |
|
||||
| `Control.grab_focus`/`has_focus`、`LineEdit.edit`、`SplitContainer.clamp_split_offset`、`FileDialog.add_filter` | 新增可选参数 | 兼容 | 🔵 D1 |
|
||||
| EditorFileDialog | `add_side_menu` **移除**;17 方法 / 8 属性 / 4 信号并入 `FileDialog` 基类 | 兼容(继承) | ⚪(编辑器) |
|
||||
| `Performance.add_custom_monitor` | 新增可选 `type` 参数 | 兼容 | 🔵(调试遥测可选) |
|
||||
|
||||
### 行为 / 格式变更
|
||||
|
||||
- **TSCN 格式**:`load_steps` 不再写入、节点唯一 ID 入文件——双向兼容,但 VCS diff 变大(可 Project > Tools > Upgrade Project Files 预升级)—— 🔵
|
||||
- **Glow 默认值大改**(blend mode Soft Light → Screen、intensity 0.8 → 0.3、各 level 重排);Mobile 渲染器 glow 重写 —— 🔵 D1/B5 用 2D Glow 时注意视觉基底已变
|
||||
- AStar2D/AStar3D/AStarGrid2D:`from_id` 被禁用/固体时返回空路径 —— ⚪(自研 BFS)
|
||||
- **新项目默认值**:Windows 渲染驱动 D3D12;3D 物理引擎 Jolt —— 🔵 创建 project.godot 时须知(本项目 2D、无 3D 物理;渲染驱动已定 = gl_compatibility,2026-09-12)
|
||||
|
||||
## 4.7(2026-06;4.7.2 = 本项目锁定版本)
|
||||
|
||||
### API 级变更
|
||||
|
||||
| 类/方法 | 变更 | GDScript 兼容 | 项目相关性 |
|
||||
|---|---|---|---|
|
||||
| **GDScript 语义 ①** | 打包数组元素赋值不再触发整属性 setter(GH-113228) | 语义变化 | 🔵 全部 .gd 代码 |
|
||||
| **GDScript 语义 ②** | 覆盖类型化返回方法:返回类型自动继承,必须显式 `return`(GH-115763) | 语义变化 | 🔵 全部 .gd 代码 |
|
||||
| `Object.is_class()` | 参数 `String` → `StringName` | 兼容 | 🔵 |
|
||||
| `PhysicsServer2D.body_set_shape_as_one_way_collision` | 新增可选 `direction`(= CollisionShape2D 单向碰撞方向属性的 server 层) | 兼容 | 🔵(已核实特性的 API 面) |
|
||||
| `PhysicsServer2DExtension._body_set_shape_as_one_way_collision` | 新增**必填** `direction` | ❌ | ⚪(不写 PhysicsServer 扩展) |
|
||||
| `CanvasItem` 线条绘制 | 不再自动加抗锯齿羽化;粗线需手动绘制(GH-105122) | 行为变更 | 🔵 D1 自绘 |
|
||||
| Input 设备 ID | 鼠标/键盘设备 ID `0` → `InputEvent.DEVICE_ID_MOUSE` / `DEVICE_ID_KEYBOARD` 常量 | 行为变更 | 🔵 D1 输入 |
|
||||
| `Control.accessibility_live` | 枚举类型 `DisplayServer.` → `AccessibilityServer.AccessibilityLiveMode` | 仅 C# 不兼容 | 🔵(低) |
|
||||
| RichTextLabel 图片参数 | `add_image`/`update_image` width/height int→float;`width_in_percent/height_in_percent` → `width_unit/height_unit`;常量 `UPDATE_WIDTH_IN_PERCENT` → `UPDATE_WIDTH_UNIT` | ❌(常量更名) | 🔵(低) |
|
||||
| `Animation.length` | 元数据 float → double | 仅 C# 不兼容 | 🔵(低,B5 期) |
|
||||
| AnimationNodeBlendSpace1D/2D | 布尔 `sync` 属性 → `SyncMode` 枚举(`sync_mode`) | 行为变更 | ⚪(3D 动画树) |
|
||||
| `Font.find_variation` / `TreeItem.select` / `ZIPPacker.start_file` / `Image.save_exr`×2 | 新增可选参数 | 兼容 | ⚪/🔵 |
|
||||
| `AudioEffectSpectrumAnalyzer.tap_back_pos` | **移除** | ❌ | ⚪(D4 Alpha 期若用频谱分析注意) |
|
||||
| `EditorSceneFormatImporter` 七常量 | 并入 `ImportFlags` 枚举 | 仅 C# 源不兼容 | ⚪ |
|
||||
| `EditorVCSInterface._commit` | 新增 `amend` 参数 | ❌ | ⚪ |
|
||||
| `OptimizedTranslation.generate` | 返回 void → bool | 仅 C# 二进制 | ⚪ |
|
||||
| `AudioStreamPlayer.area_mask` | 默认 1 → 0 | 行为变更 | ⚪(D4 Alpha 期注意) |
|
||||
|
||||
### 行为 / 默认值变更
|
||||
|
||||
- `LinearToSRGB` visual shader 不再 clamp 到 [0,1](Mobile/Forward+)—— 🔵(若写 shader)
|
||||
- **新项目默认值**:stretch mode `disabled` → `canvas_items`、stretch aspect `keep` → `expand` —— 🔵 **创建 project.godot 时须知(训练数据默认值已过时)**
|
||||
- macOS 最低版本 10.13 → 11 —— ⚪
|
||||
- `LookAtModifier3D.relative` 默认 true → false —— ⚪
|
||||
- `ResourceImporterDynamicFont.hinting` 默认 1 → 3 —— 🔵(字体导入)
|
||||
- `rendering/reflections/sky_reflections/roughness_layers` 默认 7 → 8 —— ⚪(3D)
|
||||
|
||||
## 已知基线(≤4.4,训练数据内,低风险)
|
||||
|
||||
- 4.x 系列:Tween 一律经 `create_tween()` 获取(Tween 节点已废);信号连接用 `Callable` 语法;`@onready`/`@export` 注解体系;int 恒 64 位(D2 R2 规约依赖此语义,4.x 内稳定)
|
||||
|
||||
## 本项目影响评估(2026-09-12 复核)
|
||||
|
||||
| 变更 | 影响 |
|
||||
|---|---|
|
||||
| 4.7 全部已核实特性 | 均为增量,无破坏 D2/A3 已批准规约的项 |
|
||||
| **4.5–4.7 逐条 API 变更** | **无一破坏 GDD 已锁架构契约**(autoload 体系 / .tres 单一事实源 / Callable 信号 / int64 二补数 / headless SceneTree 协议均不受影响) |
|
||||
| 需入编码规范的项 | GDScript 两条新语义(打包数组 setter / 显式 return)→ `current-best-practices.md` |
|
||||
| 需项目设置留意的项 | 新项目默认值已变(stretch mode / aspect / D3D12)→ `current-best-practices.md` |
|
||||
| `Resource.duplicate(true)` 语义收窄 | D2 表资源含外部子资源时的复制语义注意 |
|
||||
|
||||
## Pending
|
||||
|
||||
- [x] 4.4→4.5 breaking changes 逐条清单(2026-09-12 官方迁移指南)
|
||||
- [x] 4.5→4.6 breaking changes 逐条清单(2026-09-12 官方迁移指南)
|
||||
- [x] 4.6→4.7 breaking changes 逐条清单(2026-09-12 官方迁移指南)
|
||||
- [x] 各版本 deprecated → replacement 对照表(见 `deprecated-apis.md`,2026-09-12)
|
||||
- [ ] 4.8 逐条清单(当前仅 dev 快照;稳定版发布后跑 `/setup-engine refresh`)
|
||||
- [ ] modules/ 分域参考(按实现期需要建,非阻塞)
|
||||
@@ -0,0 +1,49 @@
|
||||
# Godot 当前最佳实践(4.7 视角,post-cutoff)
|
||||
|
||||
> **Last verified: 2026-09-12**(源:官方迁移指南 4.5/4.6/4.7 逐条核实 + 4.7 release 页)
|
||||
> 用途:训练数据(~4.4)之后的实践差异速查。写码代理在以下事项上**不要**按训练数据默认值行事。
|
||||
|
||||
## 1. 新建 project.godot 的默认值差异(最易踩坑)
|
||||
|
||||
| 设置 | 训练数据默认(≤4.4) | 4.7 实际新项目默认 | 生效版本 |
|
||||
|---|---|---|---|
|
||||
| `display/window/stretch/mode` | `disabled` | `canvas_items` | 4.7(新项目) |
|
||||
| `display/window/stretch/aspect` | `keep` | `expand` | 4.7(新项目) |
|
||||
| `rendering/rendering_device/driver.windows` | Vulkan(Forward+) | D3D12 | 4.6(新项目) |
|
||||
| `physics/3d/physics_engine` | GodotPhysics3D | Jolt | 4.6(新项目;本项目 2D、无 3D 物理,无关) |
|
||||
|
||||
本项目为 2D 棋盘 UI:stretch mode / aspect 已定(canvas_items + expand,2026-09-12),但须知道**引擎新项目默认值已不是训练数据里的那个**——新建工程后检查这三项。
|
||||
|
||||
## 2. GDScript 4.7 两条语义变化(建议入编码规范)
|
||||
|
||||
1. **打包数组元素赋值不再触发属性 setter**(4.7,GH-113228):`my_packed_array[i] = v` 不再调用所在对象的 property setter——依赖 setter 副作用的写法必须改为显式赋回 + 显式调用 setter。D2 schema 类若以 setter 做校验,注意此差异。
|
||||
2. **类型化返回的方法覆盖必须显式 `return`**(4.7,GH-115763):覆盖带返回类型的方法时返回类型自动继承,缺少 return 直接报错(旧版隐式返回 null)——虚方法覆盖一律显式写 return。
|
||||
|
||||
## 3. 资源与文件
|
||||
|
||||
- `Resource.duplicate(true)`(4.5 起):深复制**只覆盖内部子资源**,不再覆盖外部子资源;需旧行为用 `duplicate_deep(DEEP_DUPLICATE_ALL)`。D2 表资源含外部子资源时注意复制语义。
|
||||
- `FileAccess.get_as_text()` 的 `skip_cr` 参数已移除(4.6)——换行处理如需自定义须自行实现。
|
||||
- TSCN 格式(4.6):`load_steps` 不再写入、节点唯一 ID 入文件——双向兼容,但 VCS diff 会变大(可 Project > Tools > Upgrade Project Files 预升级,减少一次性大 diff)。
|
||||
- `ProjectSettings.add_property_info()`(4.5):对缺失/非法键(含 `usage`)告警;改用 `set_as_basic()` / `set_restart_if_changed()` / `set_as_internal()`。
|
||||
|
||||
## 4. 2D / UI / 文本
|
||||
|
||||
- `CanvasItem` 线条绘制**不再自动加抗锯齿羽化**(4.7)——粗线/描边需手动方案(D1 自绘棋盘格边框时注意)。
|
||||
- 输入设备 ID:比较输入来源时用 `InputEvent.DEVICE_ID_MOUSE` / `DEVICE_ID_KEYBOARD` 常量,**不要硬编码 0**(4.7)——D1 输入路由。
|
||||
- 字体导入 `hinting` 默认 1 → 3(4.7);TextServer/Font/CanvasItem 全部 draw 方法新增可选 `oversampling` 参数(4.5)——自绘文字(数字标签)可显式控制过采样。
|
||||
- RichTextLabel 图片参数两轮变化:4.5 `size_in_percent` → `width_in_percent`+`height_in_percent`;4.7 → `width_unit`/`height_unit`(bool → `ImageUnit`),常量 `UPDATE_WIDTH_IN_PERCENT` → `UPDATE_WIDTH_UNIT`。
|
||||
- **Glow 默认值大改**(4.6):blend mode Soft Light → Screen、intensity 0.8 → 0.3、各 level 重排——2D 后处理发光的视觉基底已变,调参以 4.7 默认为起点。
|
||||
- `Control.grab_focus` / `has_focus` 新增可选参数(4.6,`hide_focus` / `ignore_hidden_focus`)——焦点可视化管理更细。
|
||||
|
||||
## 5. 4.7 已核实新特性(本项目可用的增量)
|
||||
|
||||
- `Tween.tween_await()`:信号等待语法糖——**注意** B1 结算逻辑禁 await 是设计约束(可回放步骤流),该 API 不改变该约束
|
||||
- Control `offset_transform_*`:平移/旋转/缩放 Control 不影响容器布局——D1 HUD 局部动效可用
|
||||
- CollisionShape2D 单向碰撞方向属性(+ `PhysicsServer2D.body_set_shape_as_one_way_collision` 的 `direction` 参数)——本项目棋盘非物理驱动,暂不依赖
|
||||
- conic gradient、AtlasTexture 进 TextureRect——D1 贴图/着色可选
|
||||
- DrawableTexture2D、AreaLight3D、HDR 输出、内置 VirtualJoystick、新 Asset Store——本项目暂不依赖
|
||||
- `Font.find_variation` 扩展(palette_index / custom_colors)、`TreeItem.select` 扩展——低相关
|
||||
|
||||
## 6. 本项目不消费的域(相关变更可忽略)
|
||||
|
||||
3D 渲染与物理(Jolt 行为变化 / SoftBody / WorldBoundary / SpringBone / LookAtModifier)、XR/OpenXR、网络(StreamPeerTCP/TCPServer 方法上移、RPC 更名)、GLTF 导入(int64 字段)、移动端导出(Android 模板结构变化、.NET 9)、编辑器插件 API(ImportFlags / VCS / ExportPlatform)。
|
||||
@@ -0,0 +1,51 @@
|
||||
# Godot Deprecated APIs(Don't use X → Use Y)
|
||||
|
||||
> **Last verified: 2026-09-12**
|
||||
> 4.5–4.7 移除/更名/签名变化对照已补全(源 = 官方迁移指南,2026-09-12 逐条核实)。仍不含 4.8(dev 阶段)。**不要向本表添加未经验证的条目。**
|
||||
|
||||
## 4.7 release 页核实
|
||||
|
||||
- 4.7 release 页未列出新的 API 弃用;完整清单以其迁移指南为准(已逐条核实,见下节)
|
||||
|
||||
## 4.5–4.7 移除 / 更名 / 签名变化对照(源 = 官方迁移指南)
|
||||
|
||||
| Don't use | Use | Since | GDScript 影响 | 项目相关性 |
|
||||
|---|---|---|---|---|
|
||||
| `RenderingServer.instance_reset_physics_interpolation()` | (无替代——API 移除) | 4.5 | ❌ 移除 | ⚪ |
|
||||
| `RenderingServer.instance_set_interpolated()` | (无替代——API 移除) | 4.5 | ❌ 移除 | ⚪ |
|
||||
| `JSONRPC.set_scope()` | `set_method()` | 4.5 | ❌ 更名 | ⚪ |
|
||||
| `Node.get_rpc_config()` | `get_node_rpc_config()` | 4.5 | ❌ 更名 | ⚪ |
|
||||
| `Node.set_name(name: String)` | `set_name(name: StringName)` | 4.5 | 兼容(自动转换) | 🔵 |
|
||||
| `TextServerExtension` 四个 draw 虚方法 | 签名新增 `oversampling` | 4.5 | ❌(虚方法覆盖不兼容) | ⚪ |
|
||||
| RichTextLabel `size_in_percent` 参数 | `width_in_percent` + `height_in_percent` | 4.5 | 兼容(参数拆分) | 🔵(低) |
|
||||
| `FileAccess.get_as_text(skip_cr)` | `get_as_text()`(**skip_cr 参数移除**) | 4.6 | ❌ 参数移除 | 🔵 |
|
||||
| `EditorFileDialog.add_side_menu()` | (无替代;EditorFileDialog 17 方法/8 属性/4 信号并入 `FileDialog`) | 4.6 | ❌ 移除 | ⚪ |
|
||||
| AnimationPlayer `assigned_animation` / `autoplay` / `current_animation`(String) | `StringName`(含 `get_queue()`、`current_animation_changed` 参数) | 4.6 | ❌ 类型不兼容 | 🔵(B5 期) |
|
||||
| SpringBoneSimulator3D 三个枚举 | `SkeletonModifier3D.BoneDirection` / `.RotationAxis` | 4.6 | ❌ | ⚪ |
|
||||
| `AudioEffectSpectrumAnalyzer.tap_back_pos` | (无替代——属性移除) | 4.7 | ❌ 移除 | ⚪(D4 期注意) |
|
||||
| AnimationNodeBlendSpace1D/2D `sync: bool` 属性 | `sync_mode: SyncMode` 枚举 | 4.7 | ❌ 属性类型变化 | ⚪ |
|
||||
| RichTextLabel `ImageUpdateMask.UPDATE_WIDTH_IN_PERCENT` | `UPDATE_WIDTH_UNIT`;`width/height_in_percent` 参数 → `width/height_unit`(bool → `ImageUnit`) | 4.7 | ❌ 常量/参数更名 | 🔵(低) |
|
||||
| `Object.is_class("X")`(String 字面量) | `is_class(&"X")`(StringName) | 4.7 | 兼容 | 🔵 |
|
||||
| `EditorVCSInterface._commit()` | 签名新增 `amend` | 4.7 | ❌(虚方法覆盖不兼容) | ⚪ |
|
||||
| `PhysicsServer2DExtension._body_set_shape_as_one_way_collision()` | 签名新增必填 `direction` | 4.7 | ❌(虚方法覆盖不兼容) | ⚪ |
|
||||
| C# `RenderingDevice.Features.Address` | `BufferDeviceAddress` | 4.5 | 仅 C# | ⚪ |
|
||||
| GLTF Accessor/BufferView 十字段(int) | int64 / 强类型枚举 | 4.5 | 仅 C# | ⚪ |
|
||||
|
||||
## 训练数据内基线(≤4.4,高置信,本项目相关)
|
||||
|
||||
| Don't use | Use | Since | 备注 |
|
||||
|---|---|---|---|
|
||||
| `Tween` 节点 / `create_tween()` 以外的补间获取 | `create_tween()` / `tween_property()` | 4.0 | Tween 节点已移除 |
|
||||
| 旧式 `connect("sig", instance, "method")` | `signal.connect(callable)` | 4.0 | Callable 语法 |
|
||||
| `onready var` | `@onready var` | 4.0 | 注解体系 |
|
||||
| `export var` | `@export var` | 4.0 | |
|
||||
| `RandomNumberGenerator` 自建实例(玩法侧) | `RngService.open_stream(stream)` | 本项目 | D2 Rule 5(项目级禁令,非引擎弃用) |
|
||||
| `randomize()`(玩法代码) | 禁止——种子归 `RngService.set_master_seed()`(C2 调用) | 本项目 | D2 Rule 5 |
|
||||
| `yield` | `await` | 4.0 | 4.7 新增 `Tween.tween_await()`;但 B1 结算逻辑禁 await(设计约束) |
|
||||
|
||||
## Pending
|
||||
|
||||
- [x] 4.5 deprecated → replacement 对照(2026-09-12)
|
||||
- [x] 4.6 deprecated → replacement 对照(2026-09-12)
|
||||
- [x] 4.7 deprecated → replacement 对照(2026-09-12)
|
||||
- [ ] 4.8 对照(dev 阶段;稳定版发布后 `/setup-engine refresh`)
|
||||
@@ -0,0 +1,93 @@
|
||||
# 流程规范(Dungeon Sweeper)
|
||||
|
||||
> 约束范围:一切批次的流程纪律——分支与 worktree、五段流水线、批次工作流、测试执行细则、像素件工作纪律。
|
||||
> 分工:硬性红线的一句话索引在 AGENTS.md「硬性红线」;本文承载其操作细则;批次开工前通读本文。
|
||||
|
||||
**开工任何批次前必须通读本文。**
|
||||
|
||||
## 1. 分支纪律(worktree 铁律)
|
||||
|
||||
主工作区(master 检出)只作合并落点,一切开发/设计改动禁止直接发生在主工作区:
|
||||
|
||||
1. **开工**:每批次先建独立 worktree:`git worktree add ../g-plan2-<任务名> -b <任务分支>`;所有改动与验证都在 worktree 内进行(未跟踪文件不会出现在新 worktree,需手工搬运)
|
||||
2. **收尾**:迭代 loop 批次验证全绿(冒烟+场景探针)后在主工作区 `git merge --no-ff <任务分支>`,再 `git worktree remove`+删分支;合回前若 master 已被别的批次推进,先在分支里 `git merge master` 解冲突、重跑本域闸再合回。非 loop 批次默认完成不跑闸(两入口铁规),用户点名或当场问
|
||||
3. **豁免面**:仅 `.zcode/`(钩子与配置)与 `.qoder/`(本机 harness 配置)允许主工作区直改——两份实测均不入 git(走 worktree 反而带不进去,改动只对本机生效);其余一律走 worktree,主工作区 git commit 被钩子拦截
|
||||
4. 本铁律由 PreToolUse 钩子 `.zcode/hooks/worktree-guard.sh` 强制兜底;钩子只约束 agent,用户手工改动不受限
|
||||
|
||||
## 2. 五段流水线
|
||||
|
||||
一切要做的东西按五段流水线走:**登记 → 文档设计/美术设计(双轨)→ 写需求卡片 → 迭代编排 → 实现**。段间不自动流转,每段转进由用户发令;每段一个技能入口(五者均装于项目 `.zcode/skills/`:doc-design/asset-ingest/req-card/iter-plan/iter),登记不立技能(条目格式由流水线闸强制)。设计工作在会话内进行、用户主导、禁无监管自跑。
|
||||
|
||||
| 段 | 入口技能 | 产出 | 出入口铁律 |
|
||||
|---|---|---|---|
|
||||
| 一·登记 | 无(闸管格式) | 06-待办清单条目 | 条目=标题登记元数据+正文四属性(现状/缺口/归属/状态);标题登记后不再变,正文随进程演进。格式与状态机权威=doc-conventions 第 12 节 |
|
||||
| 二·文档设计/美术设计 | doc-design(文档轨,兼任反哺点写入)/asset-ingest(美术录入;样张素材由用户主导产出) | GDD 文档或 art-bible/过审样张素材 | 用户提起或从 06 取出;会话内进行、用户主导、禁无监管自跑;经用户点头确认心智一致才许写入文档;完成判据=待裁点清零,带未裁点的是讨论稿;轨闭合凭据记入 06 状态(文档轨=文档路径+版本号,美术轨=样张过审+art-bible 条款版本) |
|
||||
| 三·写需求卡片 | req-card | 需求卡片 | 轨闭合后用户发令;新玩法/新系统/新内容必须有设计定稿前置,例外=工程直入四类(缺陷修复/工程债/测试基建/重构)凭证据跳过设计轨;卡片必经 grilling 多轮复核、零待裁点才成立;写完在 06 状态记「已写卡」+卡片路径(防遗忘) |
|
||||
| 四·迭代编排 | iter-plan | roadmap 迭代行 | 编排四查:①每卡卡片文件存在 ②每卡设计闭合凭据齐(或工程直入证据)③总估时 ≤2 周 ④写完 roadmap 行后跑流水线闸确认绿;编入未完成迭代,新开迭代行经用户确认 |
|
||||
| 五·实现 | iter | 代码与配置,可运行的游戏 | 需求卡片永不单独施工,统一由用户指定迭代号触发(=U0 开工令),按 iter 技能与本文 §3 执行;**本段是代码实现批:禁写 `design/` 与根规则文件,产出物只落 `reports/`(见 §3 第 13 条)**;设计权威文档(GDD/art-bible)批内一律不更新;完成人闸=实机目检清单+代拍板追认单登记交用户即完成批内义务 |
|
||||
|
||||
**实现段零裁断**:实现段的输入在编排段出口已锁死(卡片零待裁点+设计闭合凭据齐+编排四查过)。实现中冒出卡片没写清的分歧=上游缺陷——停该卡、06 状态回退+缺口补记,退回上游;禁自答、禁内联提问求裁断;该卡停摆不阻塞同迭代其他卡。环境故障与测试红走异常分级(自救重试/记录继续/停机呈报)。代拍板白名单保留:授权发生在卡片审问阶段,实现只执行预授权;批后追认单=备案确认。
|
||||
|
||||
**流水线闸**:`tools/pipeline_gate.py` 机检 06-待办清单与 roadmap 两文件的格式与互相引用;将注册进 `run_all_gates.sh` 文档域(注册归第二批,本批不注册)。流程文档的条目格式、迭代行格式与状态机细则见 doc-conventions 第 12 节。
|
||||
|
||||
## 3. 批次工作流标准清单
|
||||
|
||||
每个批次按以下链路执行(本清单是总索引,细则散见各规约;冲突以细则为准,发现清单过时须同批修订):
|
||||
|
||||
**开工前**
|
||||
1. **先检索后提问**——先查在册记忆与权威文档,禁把已裁决事项当新问题重问或重踩在册坑
|
||||
2. **需求卡片全列备选案**——每个待拍板点列全部备选方案与代价交用户裁决,禁卡片内自行定夺
|
||||
3. **用户发开工令才动手**——需求卡片经用户批准(U0)后方开工
|
||||
|
||||
**环境与基线**
|
||||
4. **独立 worktree+拷导入缓存**——按 §1 建 worktree;先拷主区 `.godot/` 目录与字体 `.import` 边车再跑测试,否则全量重导入资源近似卡死
|
||||
5. **改码前定基线三查**——记录冒烟全绿数目、单元测试套数、现行模拟基线读数;改完同口径逐项比对,红绿才能归因到本批
|
||||
6. **涉数值改动先采改前读数**——与改后同随机种子配对比较并写明逐项比对口径;无数值改动禁跑模拟
|
||||
|
||||
**实施**
|
||||
7. **新功能必配新测试**——新增玩法/机制必须配套新测试套件进 `tests/run_all`;没有对应测试的变更不许合并
|
||||
8. **验收改动先行声明**——验收变化(基线换代/探针增改/旧断言改判)预先写进需求卡片,禁事后补
|
||||
9. **验收函数变异验证**——新增/改写的验收函数(冒烟断言/探针自检/闸机判据)必须配一次变异验证:故意把被测件改坏成该类缺陷形态 → 跑最窄那道闸确认变红 → `git checkout` 精确还原;变异点/跑的闸/红输出摘要/还原结论四件记入实现报告变异验证记录表;**无变异红记录的断言不写「已验收」,只写「已实现,拦截能力未证」**(细则见 test-conventions §6)
|
||||
|
||||
**完成**
|
||||
10. **批末按域验收才合并**——在任务 worktree 内跑 `tools/run_all_gates.sh`,**按本批改动域选档**:本批改动触及 `game/`(游戏工程代码、测试、探针、场景)→ `--code`;不触及 `game/` 的一切改动(`design/`、根规则文件、`tools/` 工具脚本、`.zcode/` 配置等)→ `--docs`;同批混触 `game/` 与文档面 → 全量档不带参数。所选域全绿才合回 master。该脚本是全部验证闸的**唯一入口、唯一清单与唯一域划分**,闸件增减、分域调整都只改它;**本文与其他文档禁另列闸件清单**(清单散落多处正是 iter27 漏跑 `probe_gate --full` 的成因)。跑完写回执 `game/tests/.gates/receipt.json`(含 `domain` 字段),合回时由 worktree-guard 按 diff 路径推域强制校验。闸件(`tools/` 下机检脚本与闸壳)自身的改动不占合回全量——其质量义务=落批时的变异验证(test-conventions §6),闸真崩溃时合回闸 fail-closed(跑不出回执即拦),不以合回全量为兜底
|
||||
11. **合并后主区按域复跑**——合并可能引入冲突或环境差异,落回 master 后按本批改动域复跑:触及 `game/` 的批=全量复跑(维持);纯文档域批=复跑文档域档(秒级),不再全量
|
||||
12. **批次完成后的登记义务**——合回 master 后按 doc-conventions §12.1 推进 06 条目状态(做完整条删除),涉及迭代编排的在 roadmap 迭代总表与顶部「当前位」节换代——执行入口=项目技能 batch-closure(批后收尾与中间文档退役),跨会话教训写记忆库。批次过程与结论由 git 提交信息承载,禁止再写会话状态文件(2026-10-18 用户裁,见 doc-conventions 第 10 节)。`design/` 与根规则文件(`AGENTS.md`/`roadmap.md`)实现批禁写,见 §13
|
||||
13. **文档同步闸(2026-10-17 改口径:实现批禁写文档)**——实现批**禁写 `design/` 整个目录与根规则文件**,要往外交代的东西一律落 `reports/`:实现报告 `reports/iter<N>-实现报告-<日期>.md`(各卡状态+实机目检总清单+遗留读数义务)、代拍板追认单 `reports/iter<N>-代拍板-<日期>.md`、GDD 反哺点清单 `reports/iter<N>-反哺点-<日期>.md`(每条写清哪个文件哪一节、改成什么、依据是什么)。设计权威文档(GDD/art-bible)**任何批都不直改**:用户在会话中逐点裁决后,由非迭代批(工具/规则/文档批)写入 `design/`(执行入口=doc-design 技能),并把反哺条目从 `reports/` 清掉(吸收即死;退役执行=batch-closure 技能)。机械面文档(roadmap 行/术语表/README 工具注)同样归非迭代批在合并前更新。反哺点未落地期间相关 GDD 节视为待反哺,读前先查 `reports/` 与 06;需求卡片必列「关联文档同步面」按两层标注
|
||||
14. **实机目检归用户,只登记不阻塞**——真人检测项登记进实现报告目检总清单与 07-体验验证清单即完成批内义务;禁把等目检当停工理由或完成前置
|
||||
15. **中间产物吸收即死**——细则见 AGENTS.md 硬性红线与 doc-conventions 第 11 节
|
||||
|
||||
## 4. 测试执行两入口铁规(细则)
|
||||
|
||||
测试类执行——冒烟、单元测试(tests/run_all)、模拟验证(MC/verifier/调参批量工具)、场景探针等一切跑游戏的验证——只有两个触发入口:①**迭代 loop 开发**(冒烟挂迭代出口/入库闸,loop 内过程性验证属开发工作本身);②**用户主动点名**。其余会话(问答/调研/文档/审查/零散小改)一律零测试;确需测试支撑结论时先请示,以静态阅读/推理作答并注明未跑测。
|
||||
|
||||
**MC/verifier 触发细则**:仅在数值验证场景触发(改数值前后取证);normal 档为主、perfect 按需;**无数值改动的会话禁跑 MC**;结构位移类「存档锚」须先向用户请示定性再跑;需求卡片预设步骤的前提消失时(如「带值裁定后重锚」实际未投值)停问勿照字面执行。
|
||||
|
||||
**分级周期口径**:全部验证闸收编在 `tools/run_all_gates.sh` 一个入口下(**脚本即清单,且即域划分的唯一出处**),分三档——`--code`/`--docs` 按本批改动域只跑该域闸(闸件清单与域划分只写在脚本头部注释,本文不重列);`--quick` 是全量档的中段自检形态(跳过渲染闸与静态扫描);**不带参数=两域全量**,用于一次改动同批混触 `game/` 与文档面。完成出库按所选域全绿,回执由合回闸按 diff 推域强制校验。真人实机目检归用户不进自动闸。
|
||||
|
||||
## 5. MC 采集档位细则
|
||||
|
||||
四档硬闸(全表与统计精度见 `sim-data/README.md`「MC 采集档位表」):
|
||||
|
||||
| 档 | 用途 | 上限 | 触发权 |
|
||||
|---|---|---|---|
|
||||
| 一档·调研 | 调研/数值分析 | 总量 >40 | **只能由用户发起**——需求卡片/计划书/agent 均无权授权 |
|
||||
| 二档·数值修改验证 | 改数值前后取证 | 总量 ≤40、每档 ≤20 | 数值验证场景 |
|
||||
| 三档·小调 | 只测不判 | 总量 ≤20、每档 ≤10 | 数值验证场景 |
|
||||
| 四档·微量 | sanity 门,零统计判读 | 总量 ≤5 | 数值验证场景 |
|
||||
|
||||
配套纪律:超档=停机呈报,窗口不足如实挂起,禁在二/三/四档下带值结论;改前/改后锚同 seed0 配对、改前锚留盘禁补跑;逐项比对断言零新跑(复验用锚内子集 ≤20);读数缺陷(零 gameplay/RNG 触碰)禁整套重跑、走事件流重构补算;≥60 局采集先 N=5 pilot 校验字段;二/三/四档会话累计 ≤20 分钟;零数值改动=零 MC;四档仅承接数值验证场景,两入口铁规不变。
|
||||
|
||||
## 6. 闸机轮次纪律
|
||||
|
||||
1. **孤立验证先行**——新代码/新工具/新断言进全套闸之前,先走通最小可运行路径的 standalone 验证(30 秒级:新断言=单独驱动函数直跑;新工具=最小参数全路径试车含产出落盘;新探针=单 .tscn 直跑);禁以全套闸首跑充当新码首验
|
||||
2. **调试期最窄确认**——出红→修复→确认只跑出红的最小单元(单探针/单套件/单函数);全套闸每个里程碑步(波/T 段)出口最多一次,红灯补跑只跑红件;修的是全部探针/套件共用的共享件(冒烟包装器、闸机脚本本身)时全套即最小充分单元,注记说明即可
|
||||
3. **长批试车**——≥2 分钟的跑批(逐位逐项比对冻结/MC 批/批量模拟)发起前,先用最小参数把工具完整路径(含解析/落盘/写锚全链)跑通一遍再放长批
|
||||
4. **开工坑册扫描**——每波/T 段开工前,按要触碰的面扫一遍在册坑(worktree 缓存三件套、--script 模式无 autoload、守卫文本匹配等)
|
||||
|
||||
## 7. 像素结构件工作纪律
|
||||
|
||||
1. **先抄后造**——画像素结构件前,先从参考素材裁同类结构放大逐像素描述,再实现同款;禁凭印象/第一性原理发明像素结构(art-bible §8.5 参考核验的执行口径)
|
||||
2. **验完成径写成像素级视觉判据**——开工前把合格标准写成"X 与 Y 同列收尾/无悬空/无突出"式句子;自检放大最差交界处逐行核像素,不只看整板观感
|
||||
3. **±1px 一律坐标推导**——单像素级结构先写坐标推导(哪条线在哪列、谁与谁齐平)留档再写码;禁蒙数试错
|
||||
4. **修复默认附前后对比图+像素审计**,不等用户索要
|
||||
@@ -0,0 +1,86 @@
|
||||
# 测试规范(Dungeon Sweeper)
|
||||
|
||||
> 约束范围:`game/smoke/`、`game/tests/` 与一切场景探针的编写与验收。
|
||||
> 分工:测试**执行许可**(什么时候允许跑测试)归 AGENTS.md「硬性红线·测试执行两入口铁规」;**跑什么闸、什么顺序**归 `tools/run_all_gates.sh`(脚本即清单,本文与 AGENTS.md 均不另列);本文管测试怎么写、怎么算合格。
|
||||
|
||||
**写任何测试前必须通读本文。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 测试总纲——"存在"必须证明"可达且正确"
|
||||
|
||||
核心层验收标准通过不算有测试:GDScript 编译不查字典字段与时序,呈现层错误只在运行时暴露。
|
||||
测试必须证明功能可达(用户真的能用到)且行为正确(结果符合验收标准)。
|
||||
|
||||
## 2. 场景级探针标配
|
||||
|
||||
每新增一个可交互 UI 区域(视图/覆盖层/面板),必须配套场景级 headless 探针:
|
||||
真实实例化场景 → 驱动真实输入路径 → 断言可见性与状态。
|
||||
|
||||
凡模态覆盖层,探针必须断言:打开后自身 visible 且遮挡物已隐藏(模态被遮挡 = 功能存在但不可达)。
|
||||
|
||||
## 3. 缺陷修复必须沉淀回归断言
|
||||
|
||||
每个缺陷修复必须在探针或冒烟中留下能抓住该缺陷的断言(例:封印动作耗尽 AP → 必须进入第 2 轮;
|
||||
选用道具 → 库存态必须变 Used)。没有回归断言的修复视为未完成。
|
||||
|
||||
## 4. 提交前全量验证
|
||||
|
||||
交付前跑 `tools/run_all_gates.sh`(不带 `--quick`)全绿——该脚本是全部验证闸的唯一入口与唯一清单,本文禁另列闸件清单。闸件增减只改脚本。
|
||||
行为探针使用随机化玩家行为(封印/停手/刷新/无效点击)——自动玩家不做的动作就是测试盲区。
|
||||
|
||||
## 5. 测试函数怎么写——验收清单条目的落码规范
|
||||
|
||||
需求卡片 §7「逐需求点验收清单」每一条都要落成可执行的验证;本文定统一写法,卡里定每批的具体内容(测什么/注入哪里)。写卡期查不出执行载体的条目=不可测,当场呈报,禁拖到实现期。
|
||||
|
||||
1. **执行载体五选一,逐条声明**:单元测试(`tests/run_all`)/冒烟断言(`smoke_all.gd` 对应场景段)/场景探针(`smoke/` 下 `*_probe`)/MC 同种子逐项比对/人工核对(仅限无法自动化的纪律类需求点,如命名锁定、数值占位)。行为类条目以自动化载体为主。
|
||||
2. **粒度与对应关系**:每条清单条目至少一个自动断言;多条条目可合用一个测试函数。断言失败消息末尾带编号尾缀〔卡短名 Vn〕(如〔秘宝批 V3〕)——断言与卡片清单可互相 grep 查找。
|
||||
3. **断言词汇按验证对象五选一**:
|
||||
|
||||
| 词汇 | 适用场景 |
|
||||
|---|---|
|
||||
| 逐位相等 | 同种子下确定性公式与结算的精确逐项比对 |
|
||||
| 区间/差值带 | 概率与平衡读数(MC 同种子配对比较,出带即红) |
|
||||
| 快照比对 | 存档域结构、配置表行结构 |
|
||||
| 重放 | 同种子断点回放、改前改后配对 |
|
||||
| 状态/计数器断言 | 条件解锁、限次、充能——置数据→走路径→断计数值 |
|
||||
|
||||
4. **调试注入两层(能力测试与流程体验两分法的落码面)**:自动化测试=测试代码直调核心层写口构造状态(直改数据表行/计数器/存档域,不经 UI、不走正常资源积累流程——冒烟现役做法);人工体验=DebugOverlay/DS_DEBUG 调试面,服务用户目检。清单条目的「怎么测」必须写到数据面粒度:改哪张表哪行、置哪个计数、调哪个核心写口。
|
||||
5. **换代批旧验证约束同生死**:删除旧数据行/旧实现代码的批次,必须同批摘除只验证旧实现的断言与护栏校验,由新断言替代——旧件断言残留=冒烟假绿来源;合并后冒烟全绿且全仓无旧件残留引用为证。
|
||||
|
||||
## 6. 变异验证——验收函数的拦截能力自证
|
||||
|
||||
测试绿只证明「当前代码没犯这个错」,不证明「犯了这个错会被抓住」。新增或改写的验收函数(冒烟断言/探针自检/闸机判据)必须配一次变异验证,把拦截能力自证一遍。**无变异红记录的断言不写「已验收」,只写「已实现,拦截能力未证」。**
|
||||
|
||||
**操作四步(逐条落实现报告变异验证记录表)**:
|
||||
|
||||
1. **注入**——把被测件改坏成该类缺陷的最小形态(翻装配序、注释一行 `add_child`、把状态源取反、把层 `visible` 置 false)。一次只注入一处;可直接改源码,不必留长期开关。
|
||||
2. **跑最窄的那一道闸**——只跑能覆盖该断言的最小单元(单冒烟脚本/单探针/单比对命令),禁跑全套闸(见 process-conventions §6 闸机轮次纪律)。判据:注入后该断言**必须变红**;红在别处而目标断言仍绿=判据没打在缺陷上,按第 4 条处理。
|
||||
3. **精确还原**——`git checkout -- <文件>`(不用 `git stash`、不手工回改,防残留)。还原后复跑同一道闸确认回绿,才算本轮闭环。
|
||||
4. **记录**——变异点(文件:行)、跑的闸、红输出摘要、还原结论,逐条进实现报告记录表。
|
||||
|
||||
**变异不红怎么办(二选一,不许含糊带过)**:
|
||||
|
||||
- **改判据**——把断言打到真正的缺陷面上(例:断言「菜单标题可见」只查截图墨色占比时,把菜单层藏起来仍不红——底层棋盘透过标题框照样给出高反差像素;改查 `is_visible_in_tree` 或加 golden 逐像素比对才红)。
|
||||
- **如实标注拦截边界**——判据本身只覆盖弱面的(如「只证伪整框空白/整框糊,不证明框里是何内容」),在断言注释与报告里写明边界,并说明强判据由哪一件承担。
|
||||
|
||||
**判据强弱分层**:同一缺陷面往往需要多件配合——**可见性/状态源类**缺陷由 `is_visible_in_tree`、树序、状态源取值的**运行期断言**抓;**内容/观感类**缺陷由 **golden 逐像素比对**抓;**占比/统计类**判据(墨色占比、纹理幅度)只能兜「整框空白/整框糊/压 busy 纹理」,是补充不是主力。写卡时按此分层配齐,别指望一条断言包打。
|
||||
|
||||
## 7. 判定三硬闸——闸承载的构造义务(迭代 29 三硬闸 2026-10-17 用户裁升格为纪律)
|
||||
|
||||
任何**新增或改写的闸承载**(闸脚本/批跑编排/探针入口)必须三闸齐备;现行各闸状态登记归架构文档「测试与质量域」节(本文不另列闸件清单):
|
||||
|
||||
1. **退出码为唯一权威判据**——输出里的 PASS 串只作附加判据不作判据主体;打印 PASS 后 `quit(1)` 必须判红。
|
||||
2. **SCRIPT ERROR / Parse Error 扫描面在位**——GDScript 脚本错误不改进程退出码、不计失败数(机制事实见 §8),错误标记必须扫输出,且判据必须覆盖「跑了但半途脚本错误」态——退出码 0 但输出缺预期签名同样判红(防静默退出)。
|
||||
3. **断言数下限**——零断言的正常返回与断言失败必须区分开(现行做法:`Kit.finish` 零断言返回专用退出码 2,不与「断言失败=1」混用,否则致命类套件的期望码协议会放过空跑)。
|
||||
- 负面套件(测试目标就是产生错误输出)仅可豁免第 2 闸,且须在 manifest 显式标记,其余两闸照判。
|
||||
- 子进程输出须经系统命令解释器重定向落盘再读——`OS.execute` 的输出管道在本机恒空。
|
||||
|
||||
**新写测试件全类型标注**(2026-10-17 用户裁写法纪律)——新写的测试件(冒烟断言/探针/单测)参数、返回值、容器一律带类型标注,与 S9 对产品码的要求同型;存量不强制清扫,被批次触碰时顺带换代。暂不机器闸(S9 扫描面=产品码,smoke/tests 豁免是测量面直构惯例的既有裁量)。
|
||||
|
||||
## 8. 判定可靠性优先于覆盖率(迭代 29 核心命题 2026-10-17 用户裁成节)
|
||||
|
||||
- 「跑一遍没崩=通过」无效:测试绿只证明**当前代码没犯这个错**,不证明**犯了这个错会被抓住**;断言存在不等于断言执行。
|
||||
- **脚本错误会静默中断所在函数的剩余断言,而套件仍报全绿**(机制事实):GDScript 无脚本错误陷阱 API,错误不改进程退出码、不计失败数。三处实证:①2026-09-19「309 项 0 失败」实为断言未跑全(状态记录 83);②敌人表行集纪律 10 条断言因定型数组赋值错误从未执行(迭代 29 修复后两条正向见红=夹具本缺锚行);③`Callable` 形参类型写错致解析函数返回 null、后续断言整段蒸发。
|
||||
- 由此产生两条义务:**写闸件**按 §7 配三硬闸;**写验收函数**必须自证断言全数执行——变异验证(§6)为主证,反例实证(构造缺陷态改前判绿/改后判红)与零命中自检(扫描面为空即判红)为辅证。
|
||||
- **覆盖率不是目标**:行覆盖率度量缺失(Godot 无内建,第三方属新基建,是否引入 06 在册待裁);现行补洞=零指名单测清单+人工判定,判定可靠性靠上列自证手段,不靠覆盖率数字。
|
||||
Reference in new issue
Block a user