Warp 发布审计报告的落盘规则解析:destination-rules 如何让同一份审计结果幂等更新到 Gist 或本地文件
【免费下载链接】warpA Python framework for GPU-accelerated simulation, robotics, and machine learning.项目地址: https://gitcode.com/GitHub_Trending/warp/warp
本文围绕 Warp 仓库中发布审计技能(warp-release-audit)的参考文档 destination-rules.md 展开,讲清楚"一份发布审计报告最终应该写到哪里"这一看似简单、实则决定整条审计流水线安全性的机制:如何通过稳定命名实现同一版本多次审计的幂等更新、如何用显式确认协议防止未经授权的产出落盘、以及本地文件与私密 Gist 两条落盘路径各自的命令细节与约束。读完后你将掌握该技能的完整"目的地"决策流程,并能将其迁移到任何需要"同一产出反复修订而非反复新建"的自动化报告场景中。
1. destination-rules 在审计技能中的定位
Warp 仓库内嵌了一个面向 Claude/Agent 的发布审计技能,入口是 SKILL.md。该技能用于生成某次 Warp 预发布(pre-release)或候选版本(release candidate, RC)的 Markdown 审计报告,供发布负责人做 keep/defer 决策。它被拆成六个阶段,其中多个阶段"按需加载"参考文档,而 destination-rules 明确规定为Phase 1 结束前必须加载的那一个:
Read
references/destination-rules.md, probegh, and look up matching gists as specified there.(SKILL.md Phase 1 第 5 步)
之所以放在最前面,是因为审计报告的内容生成(Towncrier 草稿渲染、公共 API 签名 diff、语义破坏性验证等,见 SKILL.md Phase 2–5)开销很大,必须在确认"结果写到哪里、用户是否认可该位置"之后才允许开始。destination-rules 同时是 Phase 6c("Write output to chosen destination")的执行依据,整个技能里报告只落盘一次,且必须落在 Phase 1 确认过的那个目的地 token 上。
2. 两种目的地与"稳定命名"设计
文档规定了两种报告目的地,二者的命名规则都刻意排除了日期(除本地文件外),这是整份规则的核心设计:
| 目的地 | 文件命名 | 说明 |
|---|---|---|
| 本地 Markdown 文件 | warp-<version-string>-<prerelease\|rc>-report-<today>.md(仓库根目录) | 文件名含当天日期,不自动提交,用户自行移动、分享或删除 |
| 私密 Gist | warp-<version-string>-<prerelease\|rc>-report.md | 文件名与描述均不含日期 |
| Gist 描述 | Warp <version-string> <Pre-Release\|Release Candidate> Report | 作为后续运行的匹配键 |
原文给出的理由是:文件名与描述里不带日期,使得后续针对同一版本的审计会修订同一个 Gist,而它的 git 历史会保留之前的版本。换言之,Gist 路径上"同一报告身份 = 同一版本字符串 + 同一报告类型",而不是"同一天"。这与本地文件路径不同:本地文件名带<today>(SKILL.md 中进一步写明完整路径为$(git rev-parse --show-toplevel)/warp-<version-string>-<prerelease\|rc>-report-<YYYY-MM-DD>.md),每天生成一份新的带日期快照,二者互为补充——Gist 负责"单一事实来源 + 修订历史",本地文件负责"离线快照 + 手动分发"。
<prerelease|rc>取值与报告模式一一对应,而模式由版本号决定:当前仓库的 VERSION.md 内容为1.18.0.dev3,与 warp/config.py(version: str = "1.18.0.dev3",第 86 行)声明一致。按 SKILL.md Phase 1 的规则,版本号含dev即 Pre-release 模式,因此当前仓库状态下审计报告会走prerelease命名分支,head 为 main 而非 release 分支。
3. 发现既有 Gist:先探测 gh,再做精确描述匹配
落盘流程的第一步是判定ghCLI 是否可用且已认证:
gh --version && gh auth status- 任一步失败 → 只能使用本地 Markdown 文件(此时还需要请用户额外确认 base/head refs)。
- 两步都成功 → 计算上面第 2 节定义的稳定描述字符串,然后运行
gh gist list --limit 1000,收集描述精确等于该字符串的行。
这里有两个细节值得注意。第一,--limit 1000是一个偏保守的扫描窗口:它假设同一版本字符串的历史 Gist 不会超过 1000 个(配合稳定命名,正常情况下同一版本只会有一个匹配项)。第二,匹配用的是"描述精确相等"而非文件名或模糊搜索——因为 SKILL.md 明确gh未认证时要"跳过 gist 匹配与 gist 提问",匹配键必须做到零歧义,而描述是唯一每次运行都不变的字段。这也解释了为什么后文修订 Gist 时禁止再传--desc:描述就是匹配键,一旦被改,下一次运行就找不到这个 Gist,幂等性立刻失效。
4. 确认协议:先给选项、后记录目的地 token
destination-rules 规定,审计 Agent 必须先用一句话"亮明"本次运行,再附上与gh状态相关的选项,并在用户显式确认 refs 与目的地之前不得进入 Phase 2。
开场白有两种固定句式(加粗为原文强调的占位渲染):
- 预发布:
Generating **pre-release report** for Warp **<version>**. Base **<base-ref>** → Head **<head-ref>**. **<N>** commits in range. - 候选版本:
Generating **release-candidate report** for Warp **<version>**. Base **<base-ref>** → Head **<head-ref>** (release branch cut). **<N>** commits in range.
随后按四种情况追加选项:
| 情况 | 提供的选项 |
|---|---|
gh不可用 | 本地 Markdown 文件;请用户确认 refs |
| 无匹配 Gist | 新建私密 Gist(默认)或本地文件 |
| 恰好一个匹配 | 修订该 Gist(默认)、新建私密 Gist、本地文件 |
| 多个匹配 | 逐个列出 URL 与更新时间,然后提供"按列表编号修订"、新建私密 Gist、本地文件 |
确认之后,Agent 必须只记录一个目的地 token,三选一:
localnew-gistrevise-gist:<id>
文档还特别约束:"字母回复(如用户答 A/B/C)只对当前这条 prompt 里展示的选项有效,没有全局含义"——即不能假设 A 永远是"本地文件"。这个 token 一路传递到 Phase 6c 执行落盘,保证"用户选了哪、就写到哪",且不存在一个运行里混用两个目的地的分支。
5. 落盘的三种执行路径与硬性约束
5.1local:写到仓库根目录
直接以稳定命名把报告写到仓库根目录(SKILL.md 补充了带日期的完整路径规则)。文档同时说明本地文件"不自动提交",由用户自行决定移动、分享或删除——审计产物不会污染 git 历史。
5.2new-gist:临时文件 +gh gist create
先把报告写入临时文件,再执行:
gh gist create --desc "<stable-desc>" /tmp/<gist-filename>其中<stable-desc>就是第 2 节的描述字符串,<gist-filename>为warp-<version-string>-<prerelease|rc>-report.md。
5.3revise-gist:<id>:临时文件 +gh gist edit
gh gist edit <id> --filename <gist-filename> /tmp/<gist-filename>两个关键约束:
--filename指定的是 Gist 内部要替换的文件。一个 Gist 可以有多个文件,省略它会误建新文件;显式指定才能做到"原地替换同一文件",从而让修订历史挂在同一个文件名下。- 不要传
--desc。稳定描述是后续运行查找该 Gist 的匹配键,改了描述等于销毁了幂等匹配键。
5.4 通用禁令
- 两种 Gist 操作完成后都要删除临时文件,不在系统里残留报告副本。
- 永远不传
--public:审计内容可能包含未发布 API 与破坏性变更分析,只能落在私密 Gist。 - 永远不落到用户没有选择过的目的地:落盘目标与 Phase 1 记录的 token 严格绑定。
6. 收尾:返回位置 + 头条计数 + 修订说明
文档最后规定了运行结束时的回包格式:
- 返回本地路径或 Gist URL;
- 附带 headline counts(报告模板中的头条计数块);
- 若本次是修订已有 Gist,还要明确说明"本次为原地编辑,历史版本仍保留在 gist history 中"。
"头条计数"对应 report-template.md 中的**Headline counts**块:新公共 API 数(区分 Python 作用域与 kernel 作用域)、破坏性变更数、现有 API 变更数、行为/支持变更数、修复数,以及按主分支"烘焙"天数分档的分布表。也就是说,落盘回包把"报告在哪"与"报告结论摘要"一次给出,发布负责人无需打开报告就能拿到 keep/defer 决策所需的最少信息。
7. 与技能其余部分的衔接(源码级佐证)
把 destination-rules 放回整个技能目录.claude/skills/warp-release-audit/可以看到它并非孤立规则,而是一套"证据链"的一环:
- 报告内容来自可复现的机械步骤。Phase 2 用 list_commits.py(stdlib-only、确定性输出 JSON)枚举
<base>..<head>提交并计算主分支烘焙天数;用 changelog/README.md 中同一套 Towncrier 约定(版本固定为towncrier==25.8.0的build --draft命令)渲染待发布条目;用 diff_public_api.py 对比 base 与 head 的公共 API 签名。 - 分类与渲染另有文档负责。
classification-rules.md管破坏性/实验性/计划移除的判定,render-rules.md管输出的硬性风格约束(如每条 GH 引用必须渲染为超链接、签名与 docstring 必须合并在一个 Python 风格代码块内)。destination-rules 只管"写到哪",三者边界清晰,这正是它能只读加载、独立演进的原因。 - 模式与版本的判定决定了命名分支。如前所述,当前仓库
1.18.0.dev3(dev后缀)对应 pre-release 命名;若将来切出 release 分支且版本号变为1.18.0rc1(rc后缀),同一套规则会自动切换到rc命名与"release branch cut"开场白,无需修改规则文档本身。
8. 适用前提与限制
- 该规则面向在 Warp 仓库内运行审计技能的 Agent 会话,不是给 CI 的脚本规范;其"确认"语义依赖一个交互式用户。
- Gist 路径依赖
ghCLI 的安装与认证;两者任一缺失时,规则退化为本地文件路径并强制额外确认 refs。 - 本地报告文件带日期且不自动提交,因此"历史版本"只在 Gist 路径下由 gist history 保证;本地路径下的多日修订是多个独立文件。
- 仓库为只读使用时,上述流程只涉及查看与生成产物(写临时文件、创建/编辑 Gist),不涉及修改仓库内容本身。
9. 小结:可复用的"幂等报告"模式
destination-rules 的价值超出了 Warp 发布流程本身。它演示了一个通用的自动化报告设计模式:身份不含时间戳(文件名/描述只由版本与报告类型决定)+精确键匹配(描述精确相等)+单 token 落盘决策(local/new-gist/revise-gist:<id>)+修订而非新建(--filename原地替换,历史交给 git)。把这四条搬用到任何"同一产出需要反复修订且要保留修订历史"的 Agent 工作流里,都能避免报告碎片化和未经授权的产出扩散。
【免费下载链接】warpA Python framework for GPU-accelerated simulation, robotics, and machine learning.项目地址: https://gitcode.com/GitHub_Trending/warp/warp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考