docs(规约): 规则文件审计与目录划分批——150行上限+领域拆分+日期注记清零(2026-10-15 用户令)

- CLAUDE.md 137→140:日期注记全清;文件头红线收敛为指针(全表唯一权威=code-conventions §1.4.1);测试两入口/闸机轮次/MC 档位超长红线拆子条目(MC 精度数字收敛为 sim-data/README 档位表指针);规范导航补 test-conventions/concept-conventions 两行
- code-conventions 210→148:§3 测试纪律拆出独立成文;缺陷对照表与版本历史表退役(历史归 git);反面案例去日期化;与 §1.5 重复的流程条目合并
- doc-conventions 210→149:概念封装/引用纪律/归档三节拆出 concept-conventions.md(原 §7–9 合并桩节标注);§10/§11 保号——active.md 与 tools 脚本存量引用零断链;数值纪律强制收口条款移出表格单元格
- 新增 test-conventions.md(49 行):探针标配/回归断言/提交前全量验证/验收清单落码规范
- 新增 concept-conventions.md(54 行):概念封装建模/跨文档引用纪律/归档与事实源
- 机械闸:五文件行数≤150 ✓ IMPORTANT=0 ✓ 日期残留=0 ✓ 熵增闸 PASS ✓ doc 三闸(gdd_lint/doc_link_audit/doc_term_audit)对改动文件零波及(存量 GDD 基线失败与本批无关)
- 行为验证:全新上下文只读子代理五问导航 5/5 正确(含两份新文档命中与 §10/§11 交叉印证)
This commit is contained in:
DKChan committed 2026-10-15 08:07:09 +08:00
1 parent 39c6544783
commit 18e22f1b44
5 files changed
+196 -213

No files matched your search

+26 -88
View File
@@ -1,9 +1,7 @@
# 代码规范(Dungeon Sweeper)
> 生效:2026-09-11 · 来源:用户在垂直切片评审中逐一指出的真实陋习与缺陷,全部成文。
> 每条规则附本项目真实反面案例(标注缺陷编号/日期)——规则不是抽象美德,是踩过的坑。
> 约束范围:`game/`(原 prototypes/ 垂直切片,2026-09-24 转正)代码同尺度;与 CLAUDE.md「硬性红线」节既有硬约束
> (数值表单点 / RNG 封闭流 / Core 零 UI / fail-fast / spec-AC 一致性)并行生效,冲突以用户裁决为准。
> 约束范围:`game/` 代码同尺度;与 CLAUDE.md「硬性红线」节硬约束(数值表单点 / RNG 封闭流 / Core 零 UI / fail-fast / spec-AC 一致性)并行生效,冲突以用户裁决为准。
> 分工:本文管结构 / 契约 / 语言 / 数值 / 流程五类;测试的编写与验收纪律见 `design/dev/test-conventions.md`。
**写任何代码前必须通读本文件。**
@@ -15,16 +13,14 @@
一个类只承载一个职责。场景主脚本(main)= **组合根**:模式流转、信号接线、核心写调用的唯一出口;
渲染、文案拼装、状态装配一律拆分为独立视图/装配器类。单文件超过 ~400 行即触发审视。
> **反面案例(2026-09-11,用户:"一个工程师看了想吐")**:main.gd 随功能追加长到 ~1100 行——棋盘渲染、
> HUD、结算日志格式化、四种模态覆盖层、调整板、蒙特卡洛模拟器、关卡流程全部糊在一个类里。
> 已拆分为 9 个单一职责单元(views/ + hud_presenter),main 降到 433 行组合根。
> 反例:main.gd 曾长到 ~1100 行——棋盘渲染、HUD、结算日志格式化、四种模态覆盖层、调整板、
> 模拟器、关卡流程全部内联;后拆分为 9 个单一职责单元(views/ + hud_presenter),main 回到 ~430 行组合根。
### 1.2 一切功能以类封装,禁止裸函数堆
设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。
工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。
> **反面案例(2026-09-11,用户:"我看你都是函数的方式……没有对象封装吧")**:供给控制器的伪代码
> 以裸函数呈现被否;正式实现按"B4 私有组合件 RewardSupplyController"封装。
> 反例:供给控制器曾以裸函数伪代码呈现被否;正式实现按私有组合件 RewardSupplyController 封装。
### 1.3 依赖单向,核心写调用收口
依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。
@@ -37,10 +33,10 @@
`# 实现 GDD:design/gdd/systems/<循环>/<系统文档>.md(系统 ID Xn)`;系统 ID 只作为文档与 registry 的追溯锚。
豁免:D2 schema 类与 autoload(本就领域命名);文档/夹具登记名(如 b4_golden)属文档层。
> **反面案例(2026-09-11,用户:"是没有代码规范吗")**:ID 前缀是跟随 GDD 文档名的事实约定,
> 从未成文;同目录 `config_db`/`rng_service` 无前缀与 A/B/C 系列并存——两套命名即规范缺失的铁证。
> 反例:ID 前缀是跟随 GDD 文档名的事实约定,从未成文;`config_db`/`rng_service` 无前缀与 A/B/C 系列
> 并存——两套命名并行即规范缺失。
### 1.4.1 文件头 = `##` 文档注释,≤8 行,白名单制(2026-10-15 第二轮立规)
### 1.4.1 文件头 = `##` 文档注释,≤8 行,白名单制
文件头注释只用 `##` 文档注释(Godot 官方载体,进编辑器 F1 帮助),总行数 ≤8 行(不含空行,
从文件首个非空行到首个非注释代码行)。写法权威 = Google Python Style Guide §3.8 + PEP 257
@@ -62,10 +58,9 @@
机器闸:`tools/audit_file_headers.py`(static_scan S10:行数上限 + 黑名单机械可判子集;
信号契约成文位置见 §2.1)。存量头注按白名单清偿后挂入收口闸序列;此间新增/改动的文件头必须即合规。
> **反面案例(main.gd,两轮,2026-10-15)**:第一轮头注累积 42 行——11+ 笔提交各自追加「本批做了什么」,
> 全部闸静默放行;清偿删叙事后仍剩 31 行——约 2/3 是对 code-conventions §1.3 与 ADR-0001 的整段复制、
> 场景结构/生命周期机制描述(对规约与代码零新信息),且第 4 行残留带日期批次叙事。第二轮立规后
> 全仓头注按白名单重写,机制事实归 design/dev/architecture。
> 反例:main.gd 头注曾累积 42 行——历次提交各自追加「本批做了什么」而全部闸静默放行;删掉叙事后
> 仍剩 31 行,约 2/3 是对 code-conventions §1.3 与 ADR-0001 的整段复制、场景结构/生命周期机制描述
> (对规约与代码零新信息)。全仓头注按白名单重写,机制事实归 design/dev/architecture。
### 1.5 禁止事实约定
任何"大家默认这么做"的惯例必须成文进本文件(或 CLAUDE.md)才算存在。
@@ -80,67 +75,33 @@
(参照 A2 三事件面先例);计入 §1.4.1 的 8 行上限,塞不下时迁契约文档并在文件头留指路行。
状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
> **反面案例(playtest 缺陷②)**:A2 旗动作花完末点 AP 后相位翻 Waiting 但不发 round_end,
> B1 结算点依赖该事件 → 整局软锁。v1 冒烟没抓到是因为自动玩家不用旗——路径覆盖不全的代价。
> 反例:旗动作花完末点 AP 后相位翻 Waiting 但不发 round_end,结算点依赖该事件 → 整局软锁;
> 自动玩家不用旗,冒烟路径覆盖不全没抓住。
### 2.2 跨层标识符语义单一且成文
位置(index)/ 句柄(handle)/ 键(key)是三种不同的东西。跨类传递标识符时,
传递方的语义必须与接收方契约逐字一致,禁止凭"当前恰好相等"传值。
> **反面案例(playtest 缺陷④)**:窗口选择契约 = 窗口条目位置,UI 却传库存数组句柄——
> 未消耗时二者巧合相等;消耗一件后错位 → 选中件不消耗、邻件被误耗。
> 反例:窗口选择契约 = 窗口条目位置,UI 却传库存数组句柄——未消耗时二者巧合相等;
> 消耗一件后错位 → 选中件不消耗、邻件被误耗。
### 2.3 模态覆盖层层级规则
覆盖层遮挡关系由场景树加入顺序决定。打开任何模态覆盖层时,必须显式隐藏会遮挡它的全屏层;
新增覆盖层必须登记其在 z 序中的位置,并提供"打开可见性"的场景断言。
> **反面案例(playtest 缺陷⑤)**:数值调整板已实现,但打开时被不透明的开始覆盖层完全遮住
> = "点击无反应"。功能存在 ≠ 功能可达。
> 反例:数值调整板已实现,但打开时被不透明的开始覆盖层完全遮住 = "点击无反应"。功能存在 ≠ 功能可达。
### 2.4 状态字段语义显式
跨战斗/跨场景携带或恢复的状态字段,其语义来源必须显式(表值 / 明确入参),禁止用入参隐式定义。
> **反面案例**:B2 spawn 把 hero 的 max_hp 设为入参 hero_hp——跨战斗携带 HP 时上限被压扁,
> 反例:spawn 把 hero 的 max_hp 设为入参 hero_hp——跨战斗携带 HP 时上限被压扁,
> 恢复点/治疗包的满血守卫全部失效。
---
## 3. 测试纪律——"存在"必须证明"可达且正确"
## 3. 测试纪律
### 3.1 场景级探针标配
每新增一个可交互 UI 区域(视图/覆盖层/面板),必须配套场景级 headless 探针:
真实实例化场景 → 驱动真实输入路径 → 断言可见性与状态。**只有 core 层 AC 通过不算有测试**
(GDScript 编译不查字典字段与时序,呈现层错误只在运行时暴露)。
### 3.2 覆盖层/面板必测"打开后可见"
凡模态覆盖层,探针必须断言:打开后自身 visible 且遮挡物已隐藏(缺陷⑤回归断言)。
### 3.3 缺陷修复必须沉淀回归断言
每个缺陷修复必须在探针或冒烟中留下能抓住该缺陷的断言(旗动作耗尽 AP → 必须进入第 2 轮;
选用道具 → 库存态必须变 Used)。没有回归断言的修复视为未完成。
### 3.4 提交前全量验证
交付前必须全绿:`smoke_all.gd` + 全部场景探针(ui_probe / ui_click_probe / ui_tune_probe)。
行为探针使用随机化玩家行为(旗/停手/刷新/无效点击)——自动玩家不做的动作就是测试盲区。
### 3.5 测试函数怎么写——验收清单条目的落码规范(2026-10-11 用户立规)
需求卡片 §7「逐需求点验收清单」每一条都要落成可执行的验证;本节定统一写法,卡里定每批的具体内容(测什么/注入哪里)。写卡期查不出执行载体的条目=不可测,当场呈报,禁拖到实现期。
1. **执行载体五选一,逐条声明**:单元测试(`tests/run_all`)/冒烟断言(`smoke_all.gd` 对应场景段)/场景探针(`smoke/` 下 `*_probe`)/MC 同种子对拍/人工核对(仅限无法自动化的纪律类需求点,如命名锁定、数值占位)。行为类条目以自动化载体为主。
2. **粒度与对应关系**:每条清单条目至少一个自动断言;多条条目可合用一个测试函数。断言失败消息末尾带编号尾缀〔卡短名 Vn〕(如〔秘宝批 V3〕)——断言与卡片清单可互相 grep 查找。
3. **断言词汇按验证对象五选一**:
| 词汇 | 适用场景 |
|---|---|
| 逐位相等 | 同种子下确定性公式与结算的精确对拍 |
| 区间/差值带 | 概率与平衡读数(MC 同种子配对比较,出带即红) |
| 快照比对 | 存档域结构、配置表行结构 |
| 重放 | 同种子断点回放、改前改后配对 |
| 状态/计数器断言 | 条件解锁、限次、充能——置数据→走路径→断计数值 |
4. **调试注入两层(测试方式两分法的落码面)**:自动化测试=测试代码直调核心层写口构造状态(直改数据表行/计数器/存档域,不经 UI、不走正常资源积累流程——冒烟现役做法);人工体验=DebugOverlay/DS_DEBUG 调试面,服务用户目检。清单条目的「怎么测」必须写到数据面粒度:改哪张表哪行、置哪个计数、调哪个核心写口。
5. **换代批旧验证约束同生死**:删除旧数据行/旧实现代码的批次,必须同批摘除只验证旧实现的断言与护栏校验,由新断言替代——旧件断言残留=冒烟假绿来源;合并后冒烟全绿且全仓无旧件残留引用为证。
已独立成文:`design/dev/test-conventions.md`(探针标配 / 回归断言 / 提交前全量验证 / 验收清单落码规范)。
---
@@ -165,14 +126,14 @@
("可选类 3.32"不加"每板",会被读成每格期望 >1)。
### 5.2 调参先测量,改后复测
改任何玩法数值前,先用扫描工具产出基线(通关率/难度类读数走 `balance_verifier.py` 冒险段——单关直入口口径已退役,机制类读数走 `reward_expectation.gd` 等);
改完必须复测回填数据。禁止拍脑袋调参。
改任何玩法数值前,先用扫描工具产出基线(通关率/难度类读数走 `balance_verifier.py` 冒险段,
机制类读数走 `reward_expectation.gd` 等);改完必须复测回填数据。禁止拍脑袋调参。
### 5.3 数值设计必须跨尺度推演
在单一尺度校准的数值,必须推演其在更大尺度的复合结果(每战合理 × 关内囤积 = 关卡灾难)。
> **反面案例(2026-09-11)**:可选类 25% 格子配比在单战斗尺度校准(击杀需求 18/54),
> ×"库存关内延续"× 5 张板复合后 = 每关 24.8 件、刀总伤 180 > Boss 130 HP——预警⑥在关卡尺度坐实。
> 反例:可选类 25% 格子配比在单战斗尺度校准(击杀需求 18/54),×"库存关内延续"× 5 张板复合后
> = 每关 24.8 件、刀总伤 180 > Boss 130 HP——单尺度合理的参数在关卡尺度坐实灾难。
### 5.4 用户拍板的实现零发挥
拍板范围外的细节一律不自行补全——以"待办问题"清单列出等裁决。
@@ -182,29 +143,6 @@
## 6. 流程纪律
1. **大改动三段走**:设计稿/伪代码 → 用户审阅 → 实现 → 修改记录(README + session-state)。实现不得先于审阅。
2. **实现批收尾双登记**:切片 README 修改记录 + 根目录 `active.md` 条目(会话状态唯一状态源——2026-10-09 定性,路径自 production/session-state/ 迁根目录),缺一不可。
3. **规范变更必须成文进本文件**——发现未成文约定、或用户裁决产生新规则,当场补条文。
4. **呈现层缺陷的教训回写 D1 GDD 设计输入**(信号载荷 schema / 场景级测试 / 时点状态可见性)。
---
## 附:缺陷-规范对照表(本项目真实案例,2026-09-11)
| 缺陷 | 现象 | 根因 | 对应规则 |
|---|---|---|---|
| ① UI 抖动/"第3轮"消失 | 悬停文案换行推挤侧栏,末行被挤出视口 | 动态内容参与布局回流 | 1.1 拆分 + 视图定长槽(HUDView) |
| ② Boss 战 AP 用完不结算(软锁) | 插旗耗尽末点 AP 后整局冻结 | 旗动作路径缺轮末事件 | 2.1 事件发射完整性 |
| ④ 道具使用后不消失 | 选用件留存、邻件被误耗 | 窗口位置 vs 库存句柄错位 | 2.2 标识符语义单一 |
| ⑤ 调整板点击无反应 | 面板已实现但被开始层遮挡 | 模态打开未隐藏遮挡物 | 2.3 层级规则 + 3.2 |
| 上帝对象 | main.gd ~1100 行 | 职责无边界持续堆积 | 1.1–1.3 |
| ID 前缀命名 | a1_/b1_ 与领域命名并存 | 事实约定未成文 | 1.4–1.5 |
| 可选类每关 24.8 件 | 速杀退化、囤刀秒 Boss | 单尺度校准未做跨尺度推演 | 5.3 |
## 版本历史
| 版本 | 日期 | 说明 |
|---|---|---|
| v1 | 2026-09-11 | 首版成文(垂直切片评审用户逐一指出,全部附真实反面案例) |
| v2 | 2026-10-09 | 文档正确性审查批·独立复核(worktree docaudit-2026-10-09):§6 流程纪律第 2 条「production/session-state/active.md」过期路径改「根目录 active.md」(会话状态唯一状态源,2026-10-09 用户定性为状态文件并迁根目录);本表系本批补建 |
| v3 | 2026-10-11 | 新增 §3.5「测试函数怎么写——验收清单条目的落码规范」(2026-10-11 用户立规,需求卡片逻辑验收方法论批):执行载体五选一逐条声明/断言消息带〔卡短名 Vn〕编号尾缀/断言词汇五选一表/调试注入两层/换代批旧验证约束同生死 |
1. **大改动三段走**:设计稿/伪代码 → 用户审阅 → 实现;实现不得先于审阅。修改记录落切片 README。
2. **实现批收尾双登记**:切片 README 修改记录 + 根目录 `active.md` 条目(会话状态唯一状态源),缺一不可。
3. **呈现层缺陷的教训回写 D1 GDD 设计输入**(信号载荷 schema / 场景级测试 / 时点状态可见性)。