PR 演示
审查者应在不到一分钟内理解变更内容,而无需打开差异文件:变更了什么、新功能如何工作、运行证明以及审查重点。仓库相关信息——字幕语言、如何录制变更流程、发布位置——存储在 .claude/profiles/delivery.md(Demo、Notify)中。
简短有力胜过完整全面。 30秒内包含五个场景,按此顺序,省略变更不包含的内容而非填充:
- 变更内容 —— 标题和最多三个要点。
- 新流程 —— 流程,标记变更的节点。
- 前后对比 —— 仅针对可见内容;后端变更则跳过。
- 修复运行 —— 录屏,裁剪到关键部分,不超过12秒。
- 证据 —— 审查要点的检查 和 测试结果合并在一个
key场景中。它们回答同一个问题,因此不需要各占一个场景。
1. 收集素材
放入 out/demo/<pr 或 issue>/(git忽略):
- 审查要点的证据:
out/review-key/<n>/result.json和key-reviewer的判定结果(review-key)。 - 用户可见变更的截图:同一视图在变更前(基础分支)和变更后,相同尺寸和数据。裁剪到变更的部分;1280像素的整页会使变更太小而难以看清。
- 变更流程的录屏(配置文件的 Demo 命令,或 Playwright 配合
browser.newContext({ recordVideo: { dir, size: { width: 1280, height: 800 } }, viewport: { width: 1280, height: 800 } })围绕涉及变更的 e2e 检查步骤;文件在上下文关闭时出现)。保持在20秒内:从关键屏幕开始,不要在镜头中显示登录过程。 - 变更流程图:使用 mermaid
flowchart LR(或TD),五到九个节点,表示用户或请求路径,使用:::changed标记变更部分,:::added标记新增部分,:::removed标记删除部分。描述行为,而非文件。 - 运行的测试,每个带一个数字(
476 个测试、12 个流程)。
2. 编写 demo.json
放置在素材旁边(路径相对于该文件)。使用配置文件中指定的字幕语言;文本应简短——场景在几秒内被阅读完毕。支持反引号和 **粗体**。
{
"lang": "zh-CN",
"brand": "**商店** · PR #352",
"ref": "关闭 #331",
"kicker": "Bug 修复",
"title": "结账界面适配 1280 px",
"subtitle": "支付按钮遮挡了购物篮,优惠券字段宽度仅为 49 像素。",
"chips": [{ "text": "审查要点:通过", "ok": true }, "3 个文件"],
"scenes": [
{ "type": "title", "seconds": 3 },
{ "type": "bullets", "items": ["…", "…", "…"], "seconds": 5 },
{ "type": "flow", "mermaid": "flowchart LR\n A[宽度] --> B{\"< 1440 px?\"}\n B -- 是 --> C[图标]:::changed", "seconds": 6 },
{ "type": "compare", "before": "before.png", "after": "after.png", "seconds": 5 },
{ "type": "clip", "heading": "在 1280 px 下录制", "src": "run.webm", "caption": "e2e: checkout-fit", "speed": 1.5, "maxSeconds": 12 },
{ "type": "key", "result": "../../review-key/331/result.json", "baseFails": true, "seconds": 7,
"rows": [{ "ok": true, "text": "`verify.sh` · 476 个测试" }] },
{ "type": "end", "title": "准备审查", "lines": ["PR: **github.com/…/pull/352**", "3 am:…"], "seconds": 3 }
]
}
场景类型:title、bullets(items,最多四个)、flow(mermaid,legend: false 隐藏图例)、compare(before、after 及标签;layout: "stack" 垂直排列,适用于宽条状元素如工具栏)、clip(src .webm/.mp4 文件,from/to 秒数,speed,maxSeconds 默认20,crop {x, y, w, h} 按录制像素裁剪以放大关键部分;时长来自文件)、key(result = keycheck 的 result.json 或对象;verdict、baseFails、claim、rows 和 count {value, total, label} 可覆盖——例如,一个检查运行八个案例,显示为 8/8 更清晰)、checks(items 包含 name、detail、ok)、end(title、lines)。每个场景接受 heading、kicker 和 seconds。省略变更不包含的内容——后端变更没有 compare 或 clip;纯重构只有包含对等性检查的 key 场景,几乎无其他内容。
key 场景的左侧面板最多容纳八行,并在检查结果之前接受自定义 rows,因此测试结果可以作为单独行(如 "verify.sh · 476 个测试")放在此处,而不是在 key 场景之后再添加一个 checks 场景。仅在无审查要点可展示时使用单独的 checks 场景。
文案措辞
字幕在屏幕上的几秒内被阅读,因此每个字都必须承载信息。根据过往惹恼读者的演示经验,总结出三条规则:
- 陈述结果,而非赞美结果。 判定结果印章和“由 key-reviewer 独立检查”已经说明了要点通过及检查者身份。额外添加“通过,无作弊”或“完全验证”会显得作者在自夸。切勿对判定结果添加主观评论。
- 计数标签使用普通名词:
检查通过、案例相同、测试。像失败这样的动词作为标签会把“5/5”变成一句反向解读的句子——“5 个中有 5 个失败”听起来像是变更出错了,而实际意思是基础分支有问题。如果你需要说明基础分支失败,使用baseFails行,它自身会正确表述。 - 无填充词。 删掉“成功”、“如预期”、“这确保”以及任何重复标题的要点。如果一个要点会让审查者说“是,很明显”,那它就不是一个要点。
3. 渲染
node <此技能目录>/scripts/render-demo.mjs out/demo/<n>/demo.json [--webm]
该工具在 Chromium 中逐帧绘制每个场景(文字清晰,无丢帧),并编码输出 demo.mp4(H.264,可在 Slack、GitHub 和浏览器中内联播放)、demo.png(海报图:流程图或关键场景),配合 --webm 参数还会生成 VP9 编码的 demo.webm。需要 ffmpeg,Playwright 从项目中获取,否则会安装到 ~/.cache/carnufex-showcase 中。渲染速度约为每秒钟视频需要一秒钟渲染时间。
发送前务必观看检查:从每个场景截取帧(ffmpeg -ss <t> -i demo.mp4 -frames:v 1 f.png)并查看。文字被截断、图表为空、录屏显示登录界面:修正后重新渲染。
4. 发布
发送到配置文件中 Notify 指定的频道,使用 bot 身份,这样相关人员会收到真实的通知(通过 Slack 连接器发送的消息会显示为发送者本人,而 Slack 不会通知用户自己的消息)。每个 PR 一个线程:演示视频作为 PR 线程的开头;之后的所有内容——CI、审查轮次、合并、部署、线上检查、回滚——都作为该线程的回复(ship 发布这些内容)。频道中每个 PR 只占一行,跨所有仓库。将消息写入文件;消息必须自成一体(Slack mrkdwn 格式),并以仓库名称开头:
*<仓库>* · PR #<n> · <标题> — 准备审查
<PR 网址>
• <变更内容,第一行>
• <第二行>
审查要点(<类型>):*通过*,独立检查:<判定结果一行>
3 am:<信号>
node <此技能目录>/scripts/post-slack.mjs --channel <频道ID> --pr <PR 网址> --file out/demo/<n>/demo.mp4 --title "<仓库> PR #<n>: <标题>(<秒数> 秒)" --comment-file out/demo/<n>/message.md
node <此技能目录>/scripts/post-slack.mjs --channel <频道ID> --pr <PR 网址> --text-file update.md [--broadcast]
--pr 参数通过 PR 网址在频道中查找对应的线程(不保存状态):如果找到,则消息发布到该线程中;未找到,则启动新线程。--text-file 发布纯文本消息而不附带文件;--broadcast 还会将线程回复显示在频道中(用于发布结果:上线或回滚)。命令会输出线程链接和固定链接。Bot token 来自 SLACK_BOT_TOKEN 或 slack-channel 插件的 ~/.claude/channels/slack/.env;bot 必须已在频道中(not_in_channel:使用 /invite @<bot>)。如果没有 bot,则回退到 Slack 连接器(slack_get_file_upload_url → POST 文件字节 → slack_complete_file_upload),并说明不会发送通知。
将同样的三行文字、mermaid 流程图和 Slack 链接放入 PR 描述中(GitHub 支持渲染 mermaid 图表;但无法通过 API 上传视频播放)。