Files
gplan-2/design/dev/code-conventions.md
T
DKChan 27812167ef refactor(状态规矩): 废除根目录会话状态文件 active.md 与全套执法件(2026-10-18 用户裁)
判据(对 869 个 ZCode 会话与 16 个 Qoder 会话的读写统计):active.md 被整文件读 448 次、
单次中位数 14 KB、累计 6.09 MB 进上下文,311/320 个碰它的会话把它当第一个工具调用读;
但 7311 个提及它的思考片段的语境分布是——写入与编号簿记 327 个会话、并行冲突与避让 234 个、
退役与失真核对 162 个,而明确写「从它所载内容得知某事实」的只有 20 个会话。
逐条核 41 个条目:独特且现行 2 条(另 3 个子句)、别处已有权威源 14 条、陈旧或自相矛盾 7 条、
已完结批次的历史叙述 18 条;按字节约 95% 属后三类。失实样本:architecture 版本记 v1.6 实为 v1.8、
规则文件数记 7 份实为 6 份、迭代 27/28 记「位预留追加卡」而 roadmap 记已完成、三个已删 worktree
仍记「在盘待删」、同一条既宣称「文档禁列闸清单」又自行列出 01–11 全套闸。
执法件已建一轮仍拦不住:08b 体量闸只测条目数/行数/编号/死链,测不出语义失真;钩子不随仓库传播,
只有 ZCode 在跑;10-15 清到 8.6 KB、10-17 回到 40 KB,用户为「只写不删」连续三次发火。

改动面:
- 删 active.md 与 tools/audit_active_state.py;run_all_gates.sh 摘除 08b 闸件与头注、
  baseline.json 删 08b 记录(现存 12 闸)、repo_structure_audit.py 根文件白名单去 active.md
- doc-conventions §10 改写为「仓库根不设状态文件」并留裁决与判据(保持 §11/§12 编号不漂);
  §11 表两行去状态文件口径;§4 适用范围去 active.md
- process-conventions §1 第 2/3 条(合回前查尾号防撞号、豁免面)、§3 第 12 条(批次完成后的
  登记义务)、§6 分级周期口径(闸件清单不再在文档重列)四处换代
- code-conventions「实现批收尾双登记」改为单登记;CLAUDE.md 目录节、规范导航行、worktree 豁免
  行三处换代,红线新增「仓库根禁止设会话状态文件」一条
- roadmap.md 顶部新增「当前位」三行(阶段/迭代位/下一步)接替原快照职责,头注、执行纪律第 3 条、
  loop 规范第 8 条、维护纪律四处改指 06 与本文;reports/README.md 与 sim-data/README.md 两处
  现行指路改口;architecture.md 文档域闸表行去 active.md 体量闸与触发路径
- 06-待办清单迁入七条真残值(原仅载于该文件):卡片入库纪律悬空待办、req-card 两副本取齐、
  魔法道具与罕见残留(实数 23/17 处,旧记约 30/18)、通关口径统一(gdd 内 188 处,旧记 273)、
  黑话第二波待发令、数据整改批九条存疑待抽查(该批未提交面所载)、发布前删除 main.gd:196 调试
  入口写死行(工程直入·待写卡)

harness 侧另批处理(.zcode/ 与用户级技能不入 git):session-snapshot.sh 与 config.json 注册、
worktree-guard.sh 的 active.md 豁免白名单、active-closing 技能、doc-consistency-check 第 8/9 项、
iter 与 req-card 技能里的「唯一例外=active.md」与查尾号条款。
2026-10-18 07:28:48 +08:00

101 lines
9.1 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/` 代码同尺度;与 CLAUDE.md「硬性红线」节硬约束(数值表单点 / RNG 封闭流 / Core 零 UI / fail-fast / spec-AC 一致性)并行生效,冲突以用户裁决为准。
> 分工:本文管结构 / 契约 / 语言 / 数值 / 流程五类;测试的编写与验收见 `design/dev/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 文档与 registry 侧承担,系统 ID 只作为文档与 registry 的追溯锚;文件头注不承担追溯职责,不写任何文档链接(§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 文档与 registry 侧承担。
机器闸:`tools/audit_file_headers.py`(static_scan S10:行数上限+黑名单机械可判子集)。存量头注按白名单清偿(约 90 文件,清偿批进行中);清偿落地后闸增补「头注必须 `##` 开头」锁死载体;此间新增/改动的文件头必须即合规。
### 1.5 禁止事实约定
任何"大家默认这么做"的惯例必须成文进本文件(或 CLAUDE.md)才算存在。写代码时发现未成文但必须遵守的约定 → 当场补条文,不许靠惯性延续。
---
## 2. 契约纪律——跨层/跨类调用的语义
### 2.1 信号与事件契约成文
每个跨类信号:参数语义、发送时点、消费方依赖,必须在发送方 `##` 文档注释成文,每信号一行;计入 §1.4.1 的 8 行上限,装不下时迁契约文档。状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
### 2.2 跨层标识符语义单一且成文
位置(index)/ 句柄(handle)/ 键(key)是三种不同的东西。跨类传递标识符时,传递方的语义必须与接收方契约逐字一致,禁止凭"当前恰好相等"传值。
### 2.3 模态覆盖层层级规则
覆盖层遮挡关系由场景树加入顺序决定。打开任何模态覆盖层时,必须显式隐藏会遮挡它的全屏层;新增覆盖层必须登记其在 z 序中的位置,并提供"打开可见性"的场景断言。
### 2.4 状态字段语义显式
跨战斗/跨场景携带或恢复的状态字段,其语义来源必须显式(表值 / 明确入参),禁止用入参隐式定义。
---
## 3. 测试纪律
已独立成文:`design/dev/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. **大改动三段走**:设计稿/伪代码 → 用户审阅 → 实现;实现禁止先于审阅。修改记录落切片 README。
2. **实现批完成后的登记义务**:切片 README 写修改记录,06 条目按 doc-conventions §12.1 推进状态,批次过程与结论进 git 提交信息与 `reports/`(2026-10-18 用户裁:根目录会话状态文件已废除,禁止再在其中登记条目)。
3. **呈现层缺陷的教训回写 D1 GDD 设计输入**(信号载荷 schema / 场景级测试 / 时点状态可见性)。