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。
14 KiB
14 KiB
AGENTS.md — VRSub 协作规则
本文件只写对 AI 编码代理的要求(行为规则、流程约束、执行环境)。 项目信息(架构是什么、有哪些节点、怎么配置)不写在这里,按需阅读:
| 想了解 | 阅读 |
|---|---|
| 项目定位、快速开始、目录结构、文档导航 | README.md |
| 架构、核心机制、北极星不变式、单体化说明 | docs/architecture.md |
| 节点输入输出协议、模型权重解析、长音频、OCR 并发 | docs/node-protocol.md |
| 内置工作流、参数标注约定、切换模型、产物命名 | docs/workflows.md |
| 环境变量全表、启动方式、uv 依赖管理 | docs/configuration.md |
| 批量处理、暂停/继续、孤儿清理、进度日志 | docs/operations.md |
| 测试资产清单、真实模型集成测试 | docs/testing.md |
| 设计决策与踩坑记录(含实验结论) | docs/decisions.md |
| 代码缺陷跟踪与修复验收标准 | docs/代码审查问题跟踪.md |
开工前先做两件事:读 README.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。
测试规则
模块的边界
「模块」指由独立功能、在程序运行时会真实被使用到的代码块构成的代码上下文:
它可独立运行,也可和其他代码上下文组合运行。
例如 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。
数据 / 测试过程 / 验证结果
- 每个测试必须写成数据 → 测试过程 → 验证结果三段结构:先准备输入数据, 再调用真实生产代码,最后断言输出结果;顺序清晰、一读即懂。
- 测试必须可独立运行:单个测试文件或单个模块目录被单独执行时结果不变。
不依赖全局
conftest.py(不保留全局 conftest),不依赖仓库其他测试的 配置、执行顺序或共享状态。 - 数据与产物目录就是测试代码所在目录:模块专用数据(JSON/期望输出等)
写在测试代码内的常量或模块目录下;视频、音频等无法写进代码的大体积素材,
放同一个模块目录内(如
data/)与其他测试区分,不使用仓库根级中央数据目录。 - 测试过程必须调用真实的生产代码(导入
nodes/、wov_app、wov_sdk的真实实现),我们只构建测试数据、验证输出结果; 不得在测试里重写业务逻辑来模拟被测功能,也不得用伪造结构冒充被测数据。 - 需要磁盘或环境隔离时,由模块自己的 fixture(模块目录下的
conftest.py或测试文件内部)创建临时目录并设置变量,不依赖外部预先存在的配置。
功能覆盖优先,不追求代码覆盖率
- 不追求测试的代码覆盖率 100%,追求功能性代码覆盖率 100%。
- 一个大模块的功能正常,就无须对这个大模块中的辅助函数单独测试: 私有工具函数、内部转换、仅供主流程调用的分支,由主功能用例顺带覆盖即可, 不为了凑行覆盖率给辅助函数补无意义用例。
- 但每个独立功能模块必须被测试覆盖(即上文“模块的边界”中定义的模块), 不得出现“完全无测试的模块”。模块清单与当前覆盖状态见 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)。
- 测试素材必须一次性准备后随模块目录入库(放模块目录内),禁止在测试执行时 现场生成;缺失时跳过而非生成。
- 外部环境状态缺失时应跳过而不是判失败:未配置的密钥、账户余额/配额、
限流、模型/服务不可达、缺失的真实素材都属于环境状态,不是被测代码的行为;
这类用例用
pytest.skip()并说明原因(如pytest.mark.integration用例)。 但代码抛异常、返回结构错误、断言不成立仍必须失败,不得用跳过掩盖回归。 - 测试只保证代码路径被执行,不覆盖端口占用、防火墙、权限等外部环境状态; 端口问题用启动检查、端口检查与 uvicorn 冒烟测试补充。
- 本地出现
WinError 10013/WinError 10048时,先用netstat -ano | findstr :<port>确认是否有残留监听进程。
代码注释规范
只写代码真实逻辑
- 注释只回答两个问题:这段代码做什么、为什么必须这么做(不这样写会出 什么错)。读代码的人需要的是当前逻辑,不是它的来历。
- 禁止写进代码注释(这些属于 docs/decisions.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。
- JSON 数据文件(如
manifests/*.json、workflows/*.json)按 JSON 规范不支持 注释,字段语义以src/wov_sdk/models.py的模型注释和 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 或 docs/ , 不得写进本文件。
- 新增/移动文档时同步更新 README 的文档导航表与本文件顶部的索引表, 保证链接可达;文档中的相对链接指向真实文件。
- 决策与踩坑("为什么这样做")写 docs/decisions.md, 缺陷跟踪写 docs/代码审查问题跟踪.md, 专题文档只保留结论并链接过去,避免同一内容多处维护。