AGENTS.md 的注释规范新增三节可执行约束:
- 只写代码真实逻辑:注释只回答"做什么"与"为什么必须这么做",禁止写决策/
修改时间、历史版本对比、实测数据与实验结论、事故与缺陷编号(run_xxxx /
batch_xxxx / R01 等)——这些属 docs/decisions.md 与审查跟踪文件;当前生效
的约束可以写,但不附带它何时因何变成这样。
- 精简可读:单段连续注释不超过 3 行;docstring 一句话概括职责,不重复函数名
已表达的信息;不写逐行翻译代码的废话注释,只在非显然处(业务规则、边界、
易错点、外部约束)加注。
- 覆盖范围:测试注释只说明验证什么行为,回归用例可保留一句溯源;并明确
参数说明应写在**参数读取处**附近,而不是把多个参数的解释堆在离使用位置
很远的注释块里。
按此清理生产代码(注释净减 70 行,18 个文件),典型处理:
- nodes/whisper.py:删掉堆在一起、含"用户 2026-08 决定 / 实测 savr-1054"
等叙事的参数块,把各参数说明移到各自的读取处与 model.transcribe 调用处;
- nodes/llm_filter.py、nodes/subtitle_cleanup.py:模块 docstring 去掉英文
背景叙事与条数统计,保留"默认只跑规则层""整条删除而非 '-' 占位"等当前
行为;
- src/wov_app/{batch,db,scheduler}.py 与 routers:去掉 batch_xxx/run_xxx 事故
编号与"修复前……"对比,改为一句"否则会出现什么问题";
- nodes/ass.py、frame_extract.py:去掉废弃值对比与日期,保留判据本身。
安全验证:用 AST 对比(剥离 docstring 后比较语法树)确认 18 个文件**零逻辑
变更**;`nodes/proper_nouns.py` 的规则表 reason 字段会注入 LLM 提示词,属于
数据而非注释,已恢复原值。全量测试 476 passed。
209 lines
14 KiB
Markdown
209 lines
14 KiB
Markdown
# AGENTS.md — VRSub 协作规则
|
||
|
||
本文件只写**对 AI 编码代理的要求**(行为规则、流程约束、执行环境)。
|
||
项目信息(架构是什么、有哪些节点、怎么配置)不写在这里,按需阅读:
|
||
|
||
| 想了解 | 阅读 |
|
||
| --- | --- |
|
||
| 项目定位、快速开始、目录结构、文档导航 | [README.md](./README.md) |
|
||
| 架构、核心机制、北极星不变式、单体化说明 | [docs/architecture.md](./docs/architecture.md) |
|
||
| 节点输入输出协议、模型权重解析、长音频、OCR 并发 | [docs/node-protocol.md](./docs/node-protocol.md) |
|
||
| 内置工作流、参数标注约定、切换模型、产物命名 | [docs/workflows.md](./docs/workflows.md) |
|
||
| 环境变量全表、启动方式、uv 依赖管理 | [docs/configuration.md](./docs/configuration.md) |
|
||
| 批量处理、暂停/继续、孤儿清理、进度日志 | [docs/operations.md](./docs/operations.md) |
|
||
| 测试资产清单、真实模型集成测试 | [docs/testing.md](./docs/testing.md) |
|
||
| 设计决策与踩坑记录(含实验结论) | [docs/decisions.md](./docs/decisions.md) |
|
||
| 代码缺陷跟踪与修复验收标准 | [docs/代码审查问题跟踪.md](./docs/代码审查问题跟踪.md) |
|
||
|
||
**开工前先做两件事**:读 [README.md](./README.md) 建立项目认知,
|
||
再读 [docs/architecture.md](./docs/architecture.md#关键设计约束北极星不变式)
|
||
确认不能破坏的硬约束。
|
||
|
||
## 提交规则(强制,2026-08)
|
||
|
||
- **未经用户明确许可,禁止执行 `git commit` / `git push`**,包括"小步提交"。
|
||
- 完成改动后只汇报改动内容与验证结果,等待用户指示;用户明确说出
|
||
"提交 / push / 推上去" 等指令时才可执行提交。
|
||
- 需要用户确认的场景:新增功能、修复、文档改动、工作流/清单数据改动等
|
||
一切涉及 git 写操作的行为。
|
||
|
||
## 等待规则(强制,2026-09)
|
||
|
||
- **单次等待时间不得超过 10 秒**。需要长时间运行时,把它放到后台
|
||
(`setsid ... &` / `nohup ... &`)写日志,然后**每 10 秒轮询一次结果**
|
||
(`for i in $(seq 1 6); do sleep 10; ...; done`),而不是用一个长 `sleep`
|
||
或长 `timeout` 把用户的对话阻塞住。
|
||
- 反例(禁止):`sleep 600`、`timeout 1800 uv run pytest`——即使命令本身
|
||
很快,把 timeout 设成 30 分钟也是错的:它无法预判耗时,只会在出问题时
|
||
让用户白等半小时。应当先用 10 秒轮询确认它是否结束。
|
||
- 正例:把任务丢后台 → `for i in $(seq 1 N); do sleep 10; <检查是否完成 && break>; done`;
|
||
耗时任务写日志到 `data/experiments/...`,事后读日志汇报。
|
||
- 测试与构建也遵循此规则:已知 `uv run pytest` 全量约 70 秒,用后台+轮询,
|
||
不要写 `timeout 1800`。
|
||
|
||
## 开发流程:TDD(红-绿-重构)
|
||
|
||
- 任何新功能/修复必须先写失败测试(红),再实现最小代码让其通过(绿),
|
||
最后重构保持整洁;不允许先写实现后补测试。
|
||
- 小改动只跑相关测试,避免每次都完整跑全量测试;改动影响面大时才跑全量。
|
||
- 测试运行方式与资产说明见 [docs/testing.md](./docs/testing.md)。
|
||
|
||
## 测试规则
|
||
|
||
### 模块的边界
|
||
|
||
「模块」指**由独立功能、在程序运行时会真实被使用到的代码块构成的代码上下文**:
|
||
它可独立运行,也可和其他代码上下文组合运行。
|
||
例如 `nodes/whisper.py`、`nodes/llm_filter.py`、`src/wov_app/batch.py`、
|
||
`src/wov_sdk/models.py` 各是一个模块;`nodes/subtitle_ocr.py` 与其
|
||
`nodes/adaptive_pool.py` 是两个模块(后者可独立使用)。
|
||
|
||
### 按模块组织测试代码
|
||
|
||
- **测试代码必须按模块编写**:一个模块对应测试目录下的**一个模块目录**,
|
||
不得把同一模块的测试拆成多个互不相干的平铺文件。
|
||
- **单文件过长时**,在同一模块目录内拆成多个文件(按行为分组,如
|
||
`test_rules.py` / `test_llm_layer.py`),而**不是**拆到模块目录之外。
|
||
- 目录布局固定为 `tests/<层级>/<模块>/`,`<层级>` 对应被测代码位置
|
||
(`nodes/` → `tests/nodes/`,`src/wov_app/` → `tests/app/`,
|
||
`src/wov_sdk/` → `tests/sdk/`),模块目录名即模块名。
|
||
- 每个模块目录必须有 `__init__.py`,保证不同模块目录下的同名测试文件可共存。
|
||
- 具体目录示例见 [docs/testing.md](./docs/testing.md#目录结构与模块对应)。
|
||
|
||
### 数据 / 测试过程 / 验证结果
|
||
|
||
- 每个测试必须写成**数据 → 测试过程 → 验证结果**三段结构:先准备输入数据,
|
||
再调用真实生产代码,最后断言输出结果;顺序清晰、一读即懂。
|
||
- **测试必须可独立运行**:单个测试文件或单个模块目录被单独执行时结果不变。
|
||
**不依赖全局 `conftest.py`(不保留全局 conftest)**,不依赖仓库其他测试的
|
||
配置、执行顺序或共享状态。
|
||
- **数据与产物目录就是测试代码所在目录**:模块专用数据(JSON/期望输出等)
|
||
写在测试代码内的常量或模块目录下;视频、音频等无法写进代码的大体积素材,
|
||
放**同一个模块目录内**(如 `data/`)与其他测试区分,不使用仓库根级中央数据目录。
|
||
- 测试过程**必须调用真实的生产代码**(导入 `nodes/`、`wov_app`、`wov_sdk`
|
||
的真实实现),我们只构建测试数据、验证输出结果;
|
||
不得在测试里重写业务逻辑来模拟被测功能,也不得用伪造结构冒充被测数据。
|
||
- 需要磁盘或环境隔离时,由**模块自己的 fixture**(模块目录下的 `conftest.py`
|
||
或测试文件内部)创建临时目录并设置变量,不依赖外部预先存在的配置。
|
||
|
||
### 功能覆盖优先,不追求代码覆盖率
|
||
|
||
- **不追求测试的代码覆盖率 100%,追求功能性代码覆盖率 100%**。
|
||
- 一个大模块的功能正常,就无须对这个大模块中的辅助函数单独测试:
|
||
私有工具函数、内部转换、仅供主流程调用的分支,由主功能用例顺带覆盖即可,
|
||
**不为了凑行覆盖率给辅助函数补无意义用例**。
|
||
- 但**每个独立功能模块必须被测试覆盖**(即上文“模块的边界”中定义的模块),
|
||
不得出现“完全无测试的模块”。模块清单与当前覆盖状态见
|
||
[docs/testing.md](./docs/testing.md#功能模块覆盖清单)。
|
||
- 新增独立功能模块时,必须同时补上覆盖其功能的测试,并同步更新上述清单;
|
||
只写生产代码不补测试的改动视为未完成。
|
||
|
||
### 测试质量与运行
|
||
|
||
- 测试以保证功能可用为目标,**不强制 100% 行覆盖率**(pytest 已移除
|
||
`--cov-fail-under=100` 门槛);需要查看覆盖率时可手动追加
|
||
`uv run pytest --cov=src --cov=nodes`。
|
||
- **测试必须使用真实数据**:真实音频(合法 WAV/PCM)、真实 JSON/数据库/文件;
|
||
禁止用占位字节(如 `b"x"`)或伪造结构冒充被测数据——假数据测试只能凑覆盖率,
|
||
无法验证真实行为,视为无意义测试。
|
||
- 只允许在 I/O 边界使用 mock/stub:文件系统、网络、子进程、环境变量、时间、
|
||
**模型推理**(重模型不进入单元测试;注入的假模型必须返回结构真实的分段)。
|
||
- **真实模型集成测试**必须配套:真实 faster-whisper 模型 + 真实音频素材验证
|
||
端到端转写,本地缺模型/素材时跳过,有则必须执行(清单见
|
||
[docs/testing.md](./docs/testing.md#真实模型集成测试))。
|
||
- 测试素材必须**一次性准备后随模块目录入库**(放模块目录内),禁止在测试执行时
|
||
现场生成;缺失时跳过而非生成。
|
||
- **外部环境状态缺失时应跳过而不是判失败**:未配置的密钥、账户余额/配额、
|
||
限流、模型/服务不可达、缺失的真实素材都属于环境状态,不是被测代码的行为;
|
||
这类用例用 `pytest.skip()` 并说明原因(如 `pytest.mark.integration` 用例)。
|
||
但代码抛异常、返回结构错误、断言不成立仍必须失败,不得用跳过掩盖回归。
|
||
- 测试只保证代码路径被执行,不覆盖端口占用、防火墙、权限等外部环境状态;
|
||
端口问题用启动检查、端口检查与 uvicorn 冒烟测试补充。
|
||
- 本地出现 `WinError 10013` / `WinError 10048` 时,先用
|
||
`netstat -ano | findstr :<port>` 确认是否有残留监听进程。
|
||
|
||
## 代码注释规范
|
||
|
||
### 只写代码真实逻辑
|
||
|
||
- 注释只回答两个问题:**这段代码做什么**、**为什么必须这么做**(不这样写会出
|
||
什么错)。读代码的人需要的是当前逻辑,不是它的来历。
|
||
- **禁止写进代码注释**(这些属于 [docs/decisions.md](./docs/decisions.md) 与
|
||
[docs/代码审查问题跟踪.md](./docs/代码审查问题跟踪.md)):
|
||
- 修改/决策时间(“用户 2026-08 决定”、“2026-09 起”);
|
||
- 历史版本对比(“旧版是 X,现在改为 Y”、“修复前……”);
|
||
- 实测数据与实验结论(具体条数、耗时、模型名、实验目录);
|
||
- 事故与缺陷编号(`run_xxxx`、`batch_xxxx`、R01/R02 等):改用一句
|
||
“否则会出现什么问题” 描述后果即可;
|
||
- 变更原因的长篇叙述、将来计划、TODO 式背景;需要时在 docs 记录并链接。
|
||
- 例外:**当前生效的约束**可以写(如“默认 60 秒一块,切块失败回退整段”),
|
||
但不能附带它何时、因何改为如此。
|
||
|
||
### 精简可读
|
||
|
||
- **单段连续注释不超过 3 行**(含行)。超过说明它很可能在讲历史或设计辩论,
|
||
应压缩为 1~3 行;确实需要展开的写进 docs/ 并在此链接一句。
|
||
- 函数/类 docstring 用一句话概括职责,必要时补 1~2 句关键行为或参数语义;
|
||
不重复函数名已表达的信息(`def parse_srt` 不必再写“解析 SRT”)。
|
||
- 不写“废话注释”:逐行翻译代码、`# 返回结果`、`# 循环处理` 这类无信息量的
|
||
句子;只在**非显然处**加注释(业务规则、边界、易错点、外部约束)。
|
||
- 中文说明,术语与代码标识符保持英文;保持注释与代码同步,改代码必须
|
||
同步改注释(不留过期注释),但**不要为了“补充说明”把注释越写越长**。
|
||
|
||
### 覆盖范围
|
||
|
||
- 模块/文件职责、公开类与函数的职责与非显然行为必须有注释;私有工具函数
|
||
仅在逻辑非显然时加简注。
|
||
- 测试代码同样配中文注释,但只说明**验证什么行为**(一句话),不重复测试
|
||
步骤的机械描述。例外:回归用例可保留**简要的溯源**(如"曾因 XX 导致
|
||
时间轴错位"一句),因为它解释了"为什么必须有这条用例";但仍不写长叙事、
|
||
不贴大段实测数据,详细经过放 [docs/decisions.md](./docs/decisions.md)。
|
||
- JSON 数据文件(如 `manifests/*.json`、`workflows/*.json`)按 JSON 规范不支持
|
||
注释,字段语义以 `src/wov_sdk/models.py` 的模型注释和 [docs/](./docs/) 文档为准;
|
||
修改 JSON 字段时须同步更新文档。
|
||
|
||
## 目标运行环境
|
||
|
||
- 本服务的最终部署目标是 Linux,通常以 Docker/Kubernetes 容器运行。
|
||
- 当前 Windows 只作为本地开发环境,不允许在业务代码中写死 Windows 路径、
|
||
盘符或 Windows 专用命令。
|
||
- 路径处理统一使用 `pathlib`。
|
||
- ffmpeg 在 Linux 上可使用系统包,也允许通过 `imageio-ffmpeg` 使用内置
|
||
二进制,节点代码不能假设 ffmpeg 一定在 PATH。
|
||
- 测试必须可以在 Windows 和 Linux 上运行;涉及平台分支的代码应同时覆盖
|
||
两种路径解析。
|
||
|
||
## Windows / PowerShell 执行规则
|
||
|
||
- 默认 shell 视为 Windows PowerShell 5.1;不要假设 Bash、zsh 或 PowerShell 7。
|
||
必要时先查 `$PSVersionTable.PSVersion`。
|
||
- 禁止把 Bash 语法交给 PowerShell:`python - <<'PY'`、`cat <<EOF`、`export`、
|
||
`source`、`rm -rf`、Bash 后台 `&` 等。
|
||
- PowerShell 中 `&` 是调用运算符;URL 或参数含 `&` 时整体单引号引用。
|
||
- 避免 PowerShell 5.1 下使用 Bash 风格 `&&` / `||`;顺序步骤用多行 PowerShell。
|
||
- 参数含空格、括号、中文、`&|;><$` 或引号时默认用单引号。
|
||
- 外部程序路径可能有空格时,用 `& 'C:\path with spaces\tool.exe' arg1`。
|
||
- 文件操作优先 PowerShell 原生命令和 `-LiteralPath`。
|
||
- 复杂 Python 不用 `python -c`;涉及 SQL、JSON、中文、反斜杠、换行或
|
||
多层引号时,用仓库脚本或临时 `.py` 文件。
|
||
- 禁止在 PowerShell 用 Bash here-doc。临时传 Python 源码只允许 PowerShell
|
||
here-string,且尽量保持 ASCII。
|
||
- Python 源码含中文常量时,不通过 PowerShell 管道传给 `python -`;用 UTF-8
|
||
脚本文件、仓库脚本或 `\uXXXX`。
|
||
- 搜索文本/文件优先 `rg` / `rg --files`。
|
||
- 数据库或生产内容写操作前先查询当前数据;写入必须有明确筛选条件,禁止
|
||
无条件 `DELETE` / `UPDATE`。
|
||
- 同一 PowerShell 命令连续失败两次后,停止微调长命令;改短命令、脚本文件、
|
||
数组 splatting 或分步验证。
|
||
|
||
## 文档维护规则
|
||
|
||
- 本文件**只放对代理的要求**。新增项目知识(架构、协议、参数默认值、运维语义、
|
||
实验结果)写进 [README.md](./README.md) 或 [docs/](./docs/) ,
|
||
不得写进本文件。
|
||
- 新增/移动文档时同步更新 README 的文档导航表与本文件顶部的索引表,
|
||
保证链接可达;文档中的相对链接指向真实文件。
|
||
- 决策与踩坑("为什么这样做")写 [docs/decisions.md](./docs/decisions.md),
|
||
缺陷跟踪写 [docs/代码审查问题跟踪.md](./docs/代码审查问题跟踪.md),
|
||
专题文档只保留结论并链接过去,避免同一内容多处维护。
|