# 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 :` 确认是否有残留监听进程。 ## 代码注释规范 - 本仓库所有源码(Python、JavaScript、HTML、CSS、TOML 等支持注释的文件) 必须配有详细中文注释,说明模块/文件职责、核心类与函数的作用以及关键逻辑, 确保后续维护人员无需通读全部实现即可快速理解工作原理。 - 新增或修改代码时,必须同步补充或更新对应注释;不得删除已有注释。 - 测试代码同样必须配有中文注释,说明每条测试验证的行为与覆盖的路径。 - 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 <<$` 或引号时默认用单引号。 - 外部程序路径可能有空格时,用 `& '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), 专题文档只保留结论并链接过去,避免同一内容多处维护。