Files
gplan-2/design/engineering/code-conventions.md
T
DKChan c25daa30cd docs(迭代37结项): 批后收尾——反哺落文六处+账面换代+迭代37产出物九件退役(四卡批2026-10-25合回8faf1763)
反哺落文(reports/iter37-反哺点 逐条出账,清单随批退役):
- architecture.md v1.12→v1.13:模块归属表登记迭代37拆件新模块(CurioDeck/ShopSession/board_resolvers/main_ui_build/main_adventure_flow/main_overlay_flow/main_debug_flow/TilePalette/HeroSprite/BoardWorld 在册补行+HudPresenter 数据投影+文案拼装静态族加注;表内原无 HudPresenter 行,按新增落表)。
- 存档序列化.md:断点域豁免段注记 27 顶层键登记单源=core/adventure_runner.gd const BREAKPOINT_FIELDS(写侧 _bp_parts()、读侧 _bp_read/_bp_read_int)。
- 冒险结构.md 共享池账本节:载体注记 AdventureRunner._bonus_deck→CurioDeck(池与判定)+ShopSession(货架/定价/购买/刷新),规则文字零改动。
- code-conventions.md §1.1:新立拆分判据硬纪律——重构卡禁为迎合机检计数保留无效成员/别名,机检键与卡片契约互斥时实现段停卡呈报(反哺条7+条9口径同落;行访问器直读=db即ConfigDB,口径由该条与既有数值单点纪律覆盖)。.zcode/.qoder 两份 req-card 技能同步第13项。
- game/tests/验证集清单.md:extract_checks.py --extract --force 重生成(64源1583调用点);〔wr2〕三条走 check_quiet 通道不在提取器现行口径(旧清单同口径零条),属工具覆盖面既成事实,未扩口径。
- 反哺条4/10 批内已执行、条8 无义务、条5/6 分别由本批重生成/转待办新条出账。

代拍板:B-1~B-8 由用户 2026-10-25 结项发令整单追认(E-1/E-2 补救已入账于 P0 待办条)。

账面换代:roadmap 迭代37行=已完成(2026-10-25)+卡列/报告列退役保留字+当前位三行换代;待办清单删「game代码结构审查批」条(未决六小件迁「结构审查未立项小件候审」、gdstyle基线陈旧键迁新条)、P0「AdventureRunner职责真拆分」吸收拆分卡缺口件(撤装置计数读数/五件收编范围/验收面预案);体验验证清单录迭代37实机目检七条。

退役九件(判据逐份核对,引用面改写后 git rm):iter37 产出物五份(代拍板/反哺点/实现报告/拆分卡缺口/验收审计)+四张需求卡片(迭代已完成,roadmap 已填退役保留字)。
2026-10-25 23:46:01 +08:00

99 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 代码规范(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 / player_request_refresh / runner 推进)只允许在组合根出现——组合根=main.gd+其构造注入的组合根拆件(成员与边界见架构文档「模块归属·呈现层」),视图不得直连拆件。
### 1.4 命名 = 领域命名,禁止系统 ID 前缀
文件名与类名禁止 `a1_`/`b1_`/`c1_` 等系统 ID 前缀(`a1_board_generator.gd` → `board_generator.gd`)。设计追溯不靠前缀:代码↔设计的追溯由 GDD 文档承担,系统 ID 只作为文档的追溯锚;文件头注不承担追溯职责,不写任何文档链接(§1.4.1)。豁免:D2 schema 类与 autoload;文档/夹具登记名(如 b4_golden)属文档层。
### 1.4.1 文件头 = `##` 文档注释,介绍本模块
头注以 Python 规范为权威(GDScript 语法近 Python,官方风格指南对文件头零条款,不自造标准):Google Python Style Guide §3.8.2——文件应以描述模块内容与用法的 docstring 开头;PEP 257——模块一般都应有 docstring,摘要压一行。载体只用 `##` 文档注释(Godot 官方载体,进编辑器 F1 帮助),头注以说清模块为度,长度不设硬限。
黑名单(出现即违规):日期与变更叙事——改动史查 `git log`/`git blame`,变更背景读迭代实现报告;与其他文档或其他文件头重复的内容——零新信息不写;一切文档反向链接——「实现 GDD:xxx」「指路:架构见 xxx」一类全部废止,代码↔设计追溯由 GDD 文档承担。
机器闸:`tools/audit_file_headers.py`(static_scan S10:变更叙事黑名单机械可判子集)。行数上限与类别白名单已停用。
### 1.5 禁止事实约定
任何"大家默认这么做"的惯例必须成文进本文件(或 AGENTS.md)才算存在。写代码时发现未成文但必须遵守的约定 → 当场补条文,不许靠惯性延续。
---
## 2. 契约纪律——跨层/跨类调用的语义
### 2.1 信号与事件契约成文
每个跨类信号:参数语义、发送时点、消费方依赖,必须在发送方 `##` 文档注释成文,每信号一行;装不下时迁契约文档。状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
### 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 类型闸**——`tools/audit_type_hints.py`,执行载体=静态扫描域 S9(`game/tests/static_scan.sh`),退出码 0=归零。扫描面=产品码(`game/core`+`game/data`+`game/presentation`;probe/sim/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. **实现批完成后的登记义务**:待办清单条目按 doc-conventions §12.1 推进状态,批次过程与结论进 git 提交信息与 `reports/`(根目录会话状态文件已废除,禁止再在其中登记条目)。
3. **呈现层缺陷的教训回写 D1 GDD 设计输入**(信号载荷 schema / 场景级测试 / 时点状态可见性)。