runtime-verification · git:20261015.2c8093f · 2026-10-15 · sha256 27ef8058f6f2cb9a

runtime-verification git:20261015.2c8093fA

Immutable. This exact content never changes and is served at /api/v1/blob/27ef8058f6f2cb9a.

---
name: runtime-verification
description: 在提交或交付非平凡代码改动前,需要确认改动在真实运行面上按预期工作时使用;通过 CLI、接口、界面、公开包入口或代理行为驱动改动路径并留存证据。只改测试、文档或无运行面的类型声明时不触发;定位缺陷使用 systematic-debugging,审查代码使用 requesting-code-review。
---

# 运行面验证

目标是让改动的代码在真实入口上执行,并用捕获到的输出证明它做了声明的事。

测试、类型检查和构建是 CI 的证据,不是本技能的验证步骤;需要它们时单独执行并单独报告。在脚本里直接 import 内部函数再打印返回值,等于自己写了一个单元测试,应用并没有运行。

## 确定范围

- 在 Git 仓库中先确定完整范围:已提交的分支差异(相对上游或基线分支)和未提交的工作区改动都要看,不只看 `HEAD~1`。报告提交数。
- diff 是事实,PR 描述、提交信息和用户说法是对 diff 的声明。两者都读,不一致本身就是发现。
- 找不到任何改动时说明并停止;不在仓库中时,范围以用户指定为准,未指定就询问。

## 找到运行面

运行面是用户(人或程序)接触改动的地方:

| 改动到达 | 运行面 | 做法 |
|---|---|---|
| CLI / TUI | 终端 | 执行命令,捕获 stdout、stderr 和退出码 |
| 服务 / API | 网络端口 | 发请求,捕获状态码、响应头和响应体 |
| 界面 | 渲染结果 | 用浏览器自动化或真实应用操作,截图 |
| 库 | 公开导出 | 通过包名导入公开接口写示例,不从 `src/` 内部路径导入 |
| 提示词 / 代理配置 | 代理行为 | 运行代理,记录它实际做了什么 |
| CI 工作流 | CI 运行 | 触发或读取对应运行结果 |

内部函数不是运行面:沿调用方追到上表中的某一行,在那里观察。

只改文档、测试、无产物的类型声明或不改变行为的构建配置时,报告 `SKIP`,写一句原因,不用跑测试填补。测试与源码混合时只验证源码部分;可以读测试了解预期,但随后要去运行应用。

## 获取启动方式

1. 先找项目已有的启动或验证入口:仓库根目录和改动所在子目录的技能、`Makefile`、`Taskfile`、`package.json` 脚本、README 和 CI 配置。monorepo 中优先找改动所在包自己的入口。
2. 没有现成入口时,从 README 和构建配置冷启动,限时约 15 分钟。卡住时报告 `BLOCKED`,写明停在哪一步、缺什么。
3. 冷启动成功且用户要求或项目约定沉淀时,把有效的构建、启动和驱动命令补进项目已有文档;已有文档只在它给出的命令失效或缺步骤时修改。

## 驱动改动

- 用最短路径让改动代码执行:改了参数就带参数运行,改了处理函数就请求那个路由,改了错误处理就触发那个错误。
- 执行前回读计划:如果每一步都是构建、类型检查或跑测试文件,那是在重跑 CI,不是验证;找到能到达运行面的步骤,或报告 `BLOCKED`。
- 端到端走真实入口:用户点按钮,就点按钮,而不是只调用底层接口。各部分单独正常不代表连起来正常。
- 涉及删除、发布、发送或写到工作区外,且没有 dry-run 或安全目标时,不在真实目标上执行;验证周边能验证的部分,并写明哪条路径没跑及原因。
- 隔离共享状态:用 `mktemp -d`、独立端口、独立 tmux socket 等,不与用户或其他会话的进程、端口和锁冲突。
- 工作区里有无关未提交改动时,它们可能掩盖或制造问题;必要时在只应用本次改动的临时 worktree 中验证。

## 主动试探

声明成立只是一半。在同一运行面上,围绕改动试探作者可能没测的情况,选与改动相关的:

- 新参数:空值、重复传入、与冲突参数同用、拼错时错误信息是否指出问题。
- 新接口:错误方法、畸形请求体、缺必填字段、超大负载。
- 改动的错误路径:相邻未改的错误路径是否同样被处理。
- 交互界面:中途中断、调整窗口、粘贴异常输入、快速重复操作。
- 状态与持久化:执行两次、在旧状态上执行、两个会话同时执行。

至少做一次试探。没发现问题的试探也要记录,例如“传入空 `--from`,得到明确错误,退出码 2”。

## 防止假绿

以下情况不能算通过:

- 检查被跳过但仍输出成功;
- 代码提前返回导致输出为空,而断言对空结果为真;
- 只看了源码或构建日志,没有打开生成物、页面或产物;
- 改动路径根本没被触发,例如期望 429 却一直收到 200。

通过必须至少有一个非跳过、非空的用例实际经过改动路径。

## 报告

```markdown
## 运行面验证:<一句话说明改了什么>

**结论:** PASS | FAIL | BLOCKED | SKIP

**声明:** <改动应实现什么;diff 与描述不一致时写出>
**方式:** <使用的启动入口或冷启动过程,启动了什么>

### 步骤

1. ✅/❌/⚠️/🔍 <对运行中的应用做了什么> → <观察到什么>
   <证据:命令输出、响应体、截图或面板捕获>

### 发现

- <运行时注意到的问题、摩擦、意外、diff 与声明的差异、环境问题;每个试探即使通过也列一行>
```

- 构建、安装和检出是准备工作,不列为步骤;测试和类型检查结果不放进步骤。
- 🔍 表示试探;全是 ✅ 没有 🔍 说明只重放了正常路径。
- 证据要能被读者看到:读者无法访问本机文件时,把关键输出内联,截图用可发送文件的工具发出,不只给本地路径。
- 发现栏的门槛放低:运行中让你停顿、绕路或意外的都写;PR 页面上别人已经能看到的 CI 结果或评论不算你的观察。

## 结论定义

- **PASS**:运行了应用,改动在运行面上按预期工作。测试通过、构建干净、代码看起来正确都不算。
- **FAIL**:运行后不符合预期、破坏了其他功能,或 diff 与声明实质不一致。
- **BLOCKED**:无法到达能观察改动的状态,如构建失败、缺依赖、服务起不来。这不是对改动的判定;报告前先查完改动目录下可能提供运行环境的技能和脚本。
- **SKIP**:没有运行面。

没有部分通过:4 项中 3 项通过就是 FAIL,直到第 4 项通过或有充分解释。输出含糊时判 FAIL 并附原始输出,不自行解读。