docs(规约): 第二刀按真实范本密度压缩——CLAUDE.md 67行祈使句体+流程纪律独立成文(2026-10-15 用户令)

- 对照实测范本(anthropics/claude-code 40 行、openai/codex ≈250 行纯祈使句等七份)逐类清除叙事层:
- CLAUDE.md 140→67:三段开发流程/批次清单/分支纪律/两入口与MC细则/像素纪律全部降级出主文件;红线压成一行一条祈使句+指路;呈报六问压缩为单条索引行
- 新增 process-conventions.md(86 行):三段流程表格化+批次清单 14 条+两入口/MC 触发/分级周期/MC 档位/闸机轮次细则+像素结构件纪律——批次开工时加载
- 新增 code-conventions-cases.md(55 行):全部反面案例+缺陷对照表迁入(不常驻加载);code-conventions 148→92 行纯规则
- doc-conventions 149→120:总纲收一行、论证段压括注、骨架与生命周期条款表格全保
- 规则名全保(两入口铁规/文档同步闸/MC 触发细则等外部按名引用零断链,已全仓扫描核实)
- 机械闸:七文件≤150 ✓ IMPORTANT=0 ✓ 日期残留=0 ✓ 主文件叙事残留=0 ✓ 熵增闸 PASS ✓ doc 两闸零波及 ✓
- 行为验证:全新上下文子代理六问导航 6/6 正确(新增流程/像素面全命中)
This commit is contained in:
DKChan committed 2026-10-15 15:38:16 +08:00
1 parent 18e22f1b44
commit 5858629719
5 files changed
+251 -268

No files matched your search

+19 -75
View File
@@ -1,7 +1,7 @@
# 代码规范(Dungeon Sweeper)
> 约束范围:`game/` 代码同尺度;与 CLAUDE.md「硬性红线」节硬约束(数值表单点 / RNG 封闭流 / Core 零 UI / fail-fast / spec-AC 一致性)并行生效,冲突以用户裁决为准。
> 分工:本文管结构 / 契约 / 语言 / 数值 / 流程五类;测试的编写与验收纪律见 `design/dev/test-conventions.md`。
> 分工:本文管结构 / 契约 / 语言 / 数值 / 流程五类;测试的编写与验收见 `design/dev/test-conventions.md`;真实反例库见同目录 `code-conventions-cases.md`(不常驻加载,对规则适用有疑义时查)。
**写任何代码前必须通读本文件。**
@@ -10,93 +10,46 @@
## 1. 结构纪律——高内聚、低耦合
### 1.1 禁止上帝对象
一个类只承载一个职责。场景主脚本(main)= **组合根**:模式流转、信号接线、核心写调用的唯一出口;
渲染、文案拼装、状态装配一律拆分为独立视图/装配器类。单文件超过 ~400 行即触发审视。
> 反例:main.gd 曾长到 ~1100 行——棋盘渲染、HUD、结算日志格式化、四种模态覆盖层、调整板、
> 模拟器、关卡流程全部内联;后拆分为 9 个单一职责单元(views/ + hud_presenter),main 回到 ~430 行组合根。
一个类只承载一个职责。场景主脚本(main)= **组合根**:模式流转、信号接线、核心写调用的唯一出口;渲染、文案拼装、状态装配一律拆分为独立视图/装配器类。单文件超过 ~400 行即触发审视。
### 1.2 一切功能以类封装,禁止裸函数堆
设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。
工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。
> 反例:供给控制器曾以裸函数伪代码呈现被否;正式实现按私有组合件 RewardSupplyController 封装。
设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。
### 1.3 依赖单向,核心写调用收口
依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。
视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);
核心写接口(settle_batch / submit_window_selection / runner 推进)只允许在组合根出现。
依赖方向唯一:`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:design/gdd/systems/<循环>/<系统文档>.md(系统 ID Xn)`;系统 ID 只作为文档与 registry 的追溯锚。
豁免:D2 schema 类与 autoload(本就领域命名);文档/夹具登记名(如 b4_golden)属文档层。
> 反例:ID 前缀是跟随 GDD 文档名的事实约定,从未成文;`config_db`/`rng_service` 无前缀与 A/B/C 系列
> 并存——两套命名并行即规范缺失。
文件名与类名禁止 `a1_`/`b1_`/`c1_` 等系统 ID 前缀(`a1_board_generator.gd` → `board_generator.gd`)。设计追溯不靠前缀:每个核心实现文件头注必须带一行 `# 实现 GDD:design/gdd/systems/<循环>/<系统文档>.md(系统 ID Xn)`;系统 ID 只作为文档与 registry 的追溯锚。豁免:D2 schema 类与 autoload;文档/夹具登记名(如 b4_golden)属文档层。
### 1.4.1 文件头 = `##` 文档注释,≤8 行,白名单制
文件头注释只用 `##` 文档注释(Godot 官方载体,进编辑器 F1 帮助),总行数 ≤8 行(不含空行,
从文件首个非空行到首个非注释代码行)。写法权威 = Google Python Style Guide §3.8 + PEP 257
(GDScript 官方风格指南对文件头零条款,GDScript 语法近 Python,沿用其规范——不自造标准)。
文件头注释只用 `##` 文档注释(Godot 官方载体,进编辑器 F1 帮助),总行数 ≤8 行(不含空行,从文件首个非空行到首个非注释代码行)。写法权威 = Google Python Style Guide §3.8 + PEP 257(GDScript 官方风格指南对文件头零条款,语法近 Python,沿用其规范——不自造标准)。
白名单(只许写这五类,超出一类即违规):
1. 一行职责摘要——这是什么;
2. 用途/验证问题一行——它为什么存在;
3. GDD 锚行(§1.4 格式);
4. 硬使用约束——使用本文件前必须知道的禁令,每条一行;
5. 指路行——架构文档/ADR/契约文档的位置。
白名单(只许五类,超出一类即违规):①一行职责摘要——这是什么;②用途/验证问题一行——它为什么存在;③GDD 锚行(§1.4 格式);④硬使用约束——使用本文件前必须知道的禁令,每条一行;⑤指路行——架构文档/ADR/契约文档的位置。
黑名单(出现即违规):
- 日期与变更叙事:任何日期、「XX批/T几/迭代N 做了什么」、迁移/改名/退役经过——
改动史查 `git log`/`git blame`,变更背景读对应迭代实现报告;
- 与 code-conventions、ADR、架构文档重复的段落——规范与架构各有唯一权威文档,文件头只指路不复制;
- 场景结构、生命周期等代码机制描述——"Never describe the code"(pyguide §3.8.5),读者读代码或架构文档。
黑名单(出现即违规):日期与变更叙事——改动史查 `git log`/`git blame`,变更背景读对应迭代实现报告;与 code-conventions、ADR、架构文档重复的段落——规范与架构各有唯一权威文档,文件头只指路不复制;场景结构、生命周期等代码机制描述——"Never describe the code"(pyguide §3.8.5)。
机器闸:`tools/audit_file_headers.py`(static_scan S10:行数上限 + 黑名单机械可判子集;
信号契约成文位置见 §2.1)。存量头注按白名单清偿后挂入收口闸序列;此间新增/改动的文件头必须即合规。
> 反例:main.gd 头注曾累积 42 行——历次提交各自追加「本批做了什么」而全部闸静默放行;删掉叙事后
> 仍剩 31 行,约 2/3 是对 code-conventions §1.3 与 ADR-0001 的整段复制、场景结构/生命周期机制描述
> (对规约与代码零新信息)。全仓头注按白名单重写,机制事实归 design/dev/architecture。
机器闸:`tools/audit_file_headers.py`(static_scan S10:行数上限+黑名单机械可判子集;信号契约成文位置见 §2.1)。存量头注按白名单清偿后挂入收口闸序列;此间新增/改动的文件头必须即合规。
### 1.5 禁止事实约定
任何"大家默认这么做"的惯例必须成文进本文件(或 CLAUDE.md)才算存在。
写代码时发现未成文但必须遵守的约定 → 当场补条文,不许靠惯性延续。
任何"大家默认这么做"的惯例必须成文进本文件(或 CLAUDE.md)才算存在。写代码时发现未成文但必须遵守的约定 → 当场补条文,不许靠惯性延续。
---
## 2. 契约纪律——跨层/跨类调用的语义
### 2.1 信号与事件契约成文
每个跨类信号:参数语义、发送时点、消费方依赖,必须在发送方 `##` 文档注释成文,每信号一行
(参照 A2 三事件面先例);计入 §1.4.1 的 8 行上限,塞不下时迁契约文档并在文件头留指路行。
状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
> 反例:旗动作花完末点 AP 后相位翻 Waiting 但不发 round_end,结算点依赖该事件 → 整局软锁;
> 自动玩家不用旗,冒烟路径覆盖不全没抓住。
每个跨类信号:参数语义、发送时点、消费方依赖,必须在发送方 `##` 文档注释成文,每信号一行;计入 §1.4.1 的 8 行上限,塞不下时迁契约文档并在文件头留指路行。状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
### 2.2 跨层标识符语义单一且成文
位置(index)/ 句柄(handle)/ 键(key)是三种不同的东西。跨类传递标识符时,
传递方的语义必须与接收方契约逐字一致,禁止凭"当前恰好相等"传值。
> 反例:窗口选择契约 = 窗口条目位置,UI 却传库存数组句柄——未消耗时二者巧合相等;
> 消耗一件后错位 → 选中件不消耗、邻件被误耗。
位置(index)/ 句柄(handle)/ 键(key)是三种不同的东西。跨类传递标识符时,传递方的语义必须与接收方契约逐字一致,禁止凭"当前恰好相等"传值。
### 2.3 模态覆盖层层级规则
覆盖层遮挡关系由场景树加入顺序决定。打开任何模态覆盖层时,必须显式隐藏会遮挡它的全屏层;
新增覆盖层必须登记其在 z 序中的位置,并提供"打开可见性"的场景断言。
> 反例:数值调整板已实现,但打开时被不透明的开始覆盖层完全遮住 = "点击无反应"。功能存在 ≠ 功能可达。
覆盖层遮挡关系由场景树加入顺序决定。打开任何模态覆盖层时,必须显式隐藏会遮挡它的全屏层;新增覆盖层必须登记其在 z 序中的位置,并提供"打开可见性"的场景断言。
### 2.4 状态字段语义显式
跨战斗/跨场景携带或恢复的状态字段,其语义来源必须显式(表值 / 明确入参),禁止用入参隐式定义。
> 反例:spawn 把 hero 的 max_hp 设为入参 hero_hp——跨战斗携带 HP 时上限被压扁,
> 恢复点/治疗包的满血守卫全部失效。
---
## 3. 测试纪律
@@ -107,37 +60,28 @@
## 4. 语言纪律——GDScript 4.x 实战坑(本项目踩实)
1. **多行 lambda 内禁止嵌套 match / 复杂控制流**(解析不可靠,报"Expected expression for match
pattern")——信号处理体一律抽成命名方法 + `bind` 传状态。
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 = 静默输出字面量)——工具输出错
等于没有输出。
5. **重命名脚本必须同步 `.uid` 文件**;新增 `class_name` 后必须跑一次编辑器扫描刷新全局类缓存,否则 `--headless --script` 模式解析失败。
6. **`print` 格式占位符与实参类型必须匹配**(`%d` 配 String = 静默输出字面量)。
---
## 5. 数值与汇报纪律
### 5.1 数值口径必须显式标注尺度
任何期望值/均值汇报必须写明口径:**每格 / 每板 / 每战 / 每关**。混用口径 = 误导
("可选类 3.32"不加"每板",会被读成每格期望 >1)。
任何期望值/均值汇报必须写明口径:**每格 / 每板 / 每战 / 每关**。混用口径 = 误导。
### 5.2 调参先测量,改后复测
改任何玩法数值前,先用扫描工具产出基线(通关率/难度类读数走 `balance_verifier.py` 冒险段,
机制类读数走 `reward_expectation.gd` 等);改完必须复测回填数据。禁止拍脑袋调参。
改任何玩法数值前,先用扫描工具产出基线(通关率/难度类读数走 `balance_verifier.py` 冒险段,机制类读数走 `reward_expectation.gd` 等);改完必须复测回填数据。禁止拍脑袋调参。
### 5.3 数值设计必须跨尺度推演
在单一尺度校准的数值,必须推演其在更大尺度的复合结果(每战合理 × 关内囤积 = 关卡灾难)。
> 反例:可选类 25% 格子配比在单战斗尺度校准(击杀需求 18/54),×"库存关内延续"× 5 张板复合后
> = 每关 24.8 件、刀总伤 180 > Boss 130 HP——单尺度合理的参数在关卡尺度坐实灾难。
在单一尺度校准的数值,必须推演其在更大尺度的复合结果(每战合理 × 关内囤积 = 关卡灾难;反例见 code-conventions-cases.md §5.3)。
### 5.4 用户拍板的实现零发挥
拍板范围外的细节一律不自行补全——以"待办问题"清单列出等裁决。
(反面案例:清图奖励被自行设计成入库刀,用户纠正为"一次性高额伤害不入库"。)
---