关于 audit-ticket
audit-ticket 用于将 GitHub 旧 Issue 的要求与当前已提交代码快照逐项核对。它提供带代码证据的审计报告,并在用户选择后再更新、关闭、拆分或保留 Issue。
主要功能
- 01获取 Issue 正文和评论
- 02将附件图片纳入证据
- 03基于固定 Git 快照审计
- 04提供带代码引用的判定
- 05支持更新、关闭或拆分 Issue
适用场景
- 01规划前重新评估旧 Issue
- 02核实哪些要求已经实现
- 03识别过时或部分完成的请求
- 04准备有证据的 Issue 更新
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bhagyamudgal/ skills --skill audit-ticket安装后在 Claude Code 中输入/audit-ticket确认已加载。
附带文件references/execute.mdreferences/ticket-evidence.md
详细介绍
/audit-ticket:根据当前代码审查过时 issue
我会拿一条发布了数周或数月的 GitHub issue,逐项对照当前代码库检查其中的每项要求。旧工单会逐渐失效:一半的事项可能已在无关的 PR 中交付;有些会在重构后变得过时;其余事项则会悄无声息地阻碍规划,因为没人再相信这条工单。我会为每项给出判定和证据,然后由用户决定如何处理工单。我宁愿把这次审查一次做好,也不想再为这条工单争论一个季度。
用法
/audit-ticket 123
/audit-ticket https://github.com/owner/repo/issues/123
/audit-ticket # no arg → ask for the issue number or URL
如果没有提供 issue,我会询问其编号或 URL。我绝不会根据当前分支、近期提交或未关闭的 issue 来推断。审查错工单会白白浪费一次完整的子 Agent 并行调用。
如果 URL 指向的仓库与 cwd 不同,我会在每次 gh 调用中传入 --repo <owner>/<repo>。如果 issue 所属仓库与要审查的代码不一致,我会先停下来确认要以哪个工作树为准。
阶段 1:接收信息(主流程)
在提取要求之前,我会完整阅读 ${CLAUDE_SKILL_DIR}/references/ticket-evidence.md。我会同时整理其中的来源映射和要求清单,以便后续重写或拆分时保留原始证据。
获取完整工单
gh issue view <n> --comments --json number,title,body,state,author,createdAt,updatedAt,labels,assignees,comments,url
我会获取所有评论,而不只是正文。后续评论经常会修改、缩小范围或删除正文中的要求。如果评论与正文矛盾,以评论为准,因为评论更新。
下载附加图片
我会从正文和每条评论中提取附件 URL。
https://github.com/user-attachments/assets/<id>https://user-images.githubusercontent.com/...
对每个 URL,我都会使用身份验证下载,因为私有仓库的附件未经身份验证会返回 404;然后用 Read 读取文件,实际查看图片。
curl -fsSL -H "Authorization: token $(gh auth token)" -o /tmp/audit-ticket-<n>-img<i>.png "<url>"
-f 至关重要。没有它时,404 会以状态码 0 退出,并将错误正文写入 .png 文件;我可能会把非图片文件当作规格说明来 Read。我会在 Read 之前检查退出代码。
截图和模型图往往就是规格说明。正文中的 UI 模型图可能包含文字中未提及的要求。我会将图片所示内容纳入下方的要求清单。如果下载以非零状态码退出,我会在报告中注明 image <i> unavailable,而不是假装它不存在。
提取要求清单
我会按时间顺序浏览正文和评论,将每项独立的要求或主张编号为 R1..Rn。
- 任务列表项,即
- [ ]和- [x]。我会保留其勾选状态,作为工单的“已有”主张,以供核实,而不是直接采信。 - “添加 X”“修复 Y”“应当 Z”或“迁移到 W”之类的祈使表述。
- 隐藏在评论中的验收标准和后续要求。
- 附加模型图和截图中暗示的要求。
对每项,我都会记录 id、作为简短引文的 text、来源映射中的支持证据 E<n> ID,以及在后续评论修改了该要求时记录 superseded_by。重复项会合并。同一要求即使在三条评论中重述,仍只算一个 Rn,但我会在各自的证据 ID 下保留每条相关来源。
如果无法提取出任何要求,例如工单只有一句含糊的话,我会先询问用户具体要核实什么,再启动任何任务。
锚定审查对象
我会运行 git rev-parse HEAD 和 git rev-parse HEAD^{tree},并记录完整的提交 ID 和树 ID。我审查的是已提交的树。所有代码搜索、文件读取和行号引用都必须使用能指定快照的 Git 命令,例如 git grep <pattern> <tree-id> 和 git show <tree-id>:<path>,或对该确切树进行隔离检出。我不会触碰用户已暂存、未暂存或未跟踪的内容,也不会将其纳入审查。我会将这些内容标记为未检查,而不是将它们哈希进仓库对象数据库。
报告中的每项判定都会写明“截至 <full HEAD SHA>,已提交树为 <tree ID>”,以免后续提交和无关的本地工作悄然改变其证据。
第 2 阶段:调查(并行子 Agent)
我会为每项要求分配一个 general-purpose 子 Agent,并以每批 3-4 个的方式并行执行。主上下文充当协调者,不会自行 grep 来判断结果,这也能让各项判断保持独立。只有当两项要求涉及对同一文件进行相同修改时,我才会让它们共用一个子 Agent,例如“添加列”和“在 API 响应中公开该列”。
子 Agent 提示词
You are verifying ONE requirement from a stale GitHub issue against one
frozen code snapshot. The ticket is old. Code may have shipped, changed,
or made the requirement meaningless since it was written. Your job is a
verdict grounded in file:line evidence, not a guess.
## Ticket context
Issue: #<n>, <title> (opened <createdAt>)
Goal (1 sentence): <from body>
HEAD: <full Phase 1 SHA>
Content snapshot: <verified_content_snapshot tree hash>
## Requirement to verify
<Rn>: <requirement text>
Source: <body | comment | image>
<superseded_by note, if any>
## Your task
1. Search only the recorded content snapshot with snapshot-aware Git
commands (`git grep <pattern> <tree>` and `git ls-tree -r <tree>`).
Search by behavior keywords, not just the exact names the ticket uses.
2. Read matches with `git show <tree>:<path>` and derive line numbers from
those bytes. Decide whether the requirement is implemented,
partially implemented, absent, or no longer applicable, meaning the code it
targeted was removed or rewritten, or a different approach shipped.
## Output format (exactly this)
verdict: done | partially-done | not-done | obsolete
confidence: high | medium | low
evidence:
- <file:line>: <what this line shows, one clause>
- ...
gaps: <REQUIRED for partially-done/not-done. What's still missing, specific>
obsolete_reason: <REQUIRED for obsolete. What changed and where (file:line)>
## Rules
- Every done/partially-done verdict MUST cite at least one file:line.
- "obsolete" needs evidence of the superseding change, not a hunch.
- If you genuinely cannot determine it, say verdict: not-done with
confidence: low and explain what you'd need.
降级模式规则
子 Agent 失败或返回空结果不会中止审计。我会在报告中将该要求标记为 unverified 并继续。只有当所有子 Agent 都失败时,我才会中止。
第 3 阶段:报告(主流程)
打印前,我会通过读取 git show <verified_content_snapshot>:<path> 中所引用的范围,确认返回的每个 file:line 都存在于记录的内容快照中。我会删除伪造的引用,并将对应判断的置信度降为 low。
表格中会且只会出现一次第 1 阶段的每个 Rn。N 等于 d + p + nd + o + u。没有返回判断结果的要求标记为 unverified,不会省略。我只在表格单元格中放置证据 ID,然后在块格式的来源映射中列出每条完整的 Rn → E<n> 关联。代码引用仍作为独立的判断证据。
接手此工单的人会阅读这份审计报告,第 5 阶段也可能会将其原样发布到 GitHub。报告中不使用 em dash 或 en dash。如果已安装 unslop,其余规则由它负责。
然后我会打印以下内容。
# Ticket audit: <title> (#<n>)
**State**: <open|closed> · opened <date> · last activity <date>
**Audited against**: <full HEAD SHA> at content snapshot <tree hash> on <today>
**Requirements**: <N> total, <d> done / <p> partial / <nd> not done / <o> obsolete / <u> unverified
**Recommendation**: <one sentence, grounded in the verdict mix>
| # | Requirement | Source evidence | Verdict | Code evidence |
|---|-------------|-----------------|---------|---------------|
| R1 | <short text> | E1 | ✅ done | `<file:line>` |
| R2 | <short text> | E2, E4 | 🟡 partial | `<file:line>`: <gap, short> |
| R3 | <short text> | E3 | ❌ not done | none |
| R4 | <short text> | E5 | 🪦 obsolete | <reason, short> |
## Source evidence map
### R1 → E1
**Source**: <author> · <date> · <direct URL>
<complete exact excerpt; indent every original line so multiline text and pipes remain intact>
<repeat one block for every Rn → E<n> edge>
## Details
<per-item: full gaps, obsolete reasons, low-confidence notes, unavailable images>
我的建议逻辑如下。
- 全部已完成或已过时 → 我建议结束处理;大部分已完成时标记为
completed,大部分已过时时标记为not planned。 - 有些事项已完成,有些仍未处理 → 我建议原地更新,即发表评论并编辑正文。
- 尚无事项完成,且仍然有效 → 我建议原地更新,并添加“仍全部待处理,已于 重新分诊”的备注;如果工单正文已经准确,则保持不变。
第 4 阶段:决定(AskUserQuestion)
header: "Ticket fate"
text: "Audit of #<n>: <d> done, <p> partial, <nd> not done, <o> obsolete. What should happen to it?"
options:
- "Update in place (Recommended)": Post the audit as a status comment and edit the body into an accurate current checklist
- "Sunset (close)": Post the audit reasoning as a comment and close as <completed | not planned>
- "Split remainder": File a follow-up issue with only the open items (assigned to you), link it, close this one
- "Leave unchanged": Keep the report local; ticket untouched
当每项要求都已完成或已过时时,我会调整选项顺序。“结束处理(关闭)”会排在第一位,并标记为“(推荐)”。更新一份已无待办事项的正文只会造成无谓改动。
第 5 阶段:执行(gh)
第 5 阶段根据第 4 阶段选择的处理方式执行,且只依据该选择执行。报告始终可以安全打印,但每项 gh 写入操作都必须等待用户明确选择。我会读取 ${CLAUDE_SKILL_DIR}/references/execute.md 中所选处理方式对应的操作方案。
对于任何重写或拆分,在撰写工单正文前,以及再次执行其渲染后的关闭检查关卡时,我都会重新读取 ${CLAUDE_SKILL_DIR}/references/ticket-evidence.md。缺少必需来源证据时,所选处理方式不能关闭工单。
在撰写或冻结第 5 阶段的载荷之前,我会立即重新运行 git rev-parse HEAD 和 git rev-parse HEAD^{tree},然后将两个确切值与第 1 阶段的提交 ID 和树 ID 进行比较。我不会触碰用户的暂存索引和工作树。如果任一值发生变化,我会找出所有代码证据或判断可能受到新提交字节影响的要求,针对新树通过第 2 阶段重新处理这些要求,使用两个新标识符重建第 3 阶段报告,然后返回第 4 阶段重新征求批准。如果无法界定受影响的范围,我会重新处理所有要求。
随后,我会重新获取完整的工单正文和评论,并重新下载所有保留的附件。我会将 updatedAt、正文、评论 ID 和内容、附件 URL 以及附件摘要与第 1 阶段的内容进行比较。如果任何来源发生变化,或无法确认其时效性,我会重建来源映射,保留匹配的证据 ID,为新证据追加 ID,并通过第 2 和第 3 阶段重新处理所有受影响的要求。如果无法获取必需证据,我会停止。在拆分流程创建后渲染之前,我会再次执行代码和来源时效性检查关卡。若审计提交或树、要求、判断、建议、后续工单范围或处理方式发生变化,则返回第 4 阶段重新征求批准。
每个已冻结的正文或评论都包含其提及的每项要求的 Rn → E<n> 映射和块形式的保留摘录。前置任务状态、推理、编辑后的正文和拆分评论载荷包含完整映射。后续任务包含其迁移要求对应的映射。
对于原位更新或结束,我会在预检前渲染所有最终正文和评论。我会提供其确切的冻结字节和 SHA-256 摘要、当前目标保护信息,以及供用户明确批准的有序操作。我会将批准绑定到这些值,以及源证据、范围、判定、建议和处置方式。任何变更都会使批准失效。
对于拆分,我会将不可重复的创建状态绑定到一个现有且持久的账本,并且用户已授权写入该账本。在创建前,我会写入一条尝试记录,其中包含操作 ID、冻结的后续任务载荷路径和摘要、前置任务保护信息、预期标题、指派对象,以及 --label ai-created;协调状态为 planned,并预留稳定的后续任务 ID、URL 和保护信息字段。如果不存在已授权且可写的账本,我会将拟议记录保留在行内,并在创建前停止。我不会启动多卡片拆分。
首先,我会协调每条 attempting、reconcile-required 或 landed 记录。只有当记录为 planned 且此前没有进行过不可重复的尝试时,我才会渲染并预检创建操作;并且必须先完成 file-issue 的双词汇重复项搜索和 ai-created 标签初始化。我会在执行 gh issue create 前立即持久化 attempting 状态。结果不明确时,状态会变为 reconcile-required,绝不会重试。一旦权威回读确认后续任务已带有 ai-created 标签,我会填写其稳定 ID、URL、冻结载荷摘要和保护信息,然后将记录标记为不可重复的 landed 部分状态。每次重新进入流程时,我都会重新获取并复用该后续任务,绝不会再次调用创建操作。
对于每张变更卡片,我会记录每个载荷路径和 SHA-256 摘要、确切标题、标签和命令选项、最新目标保护信息,以及每一步预期的保护信息转换。在该卡片首次写入前,我会立即将确切目标、审计提交和树 ID、有序操作、第 4 阶段批准及拆分元数据传给 preflight-mutations。后续每次写入前,我只会根据上一次写入的权威回读更新保护信息。
后续任务创建完成后,我会执行源信息时效性检查,然后使用真实的后续任务 URL 渲染并冻结前置任务评论。我会就该评论的确切字节和摘要、当前前置任务与后续任务的保护信息,以及预期评论保护信息转换的有序评论和关闭操作,重新获取明确批准。权威回读确认确切评论已发布后,我会将状态更新为返回的预期保护信息,并允许关闭,无需重新审批。任何意外的状态转换,或外部保护信息、源证据、载荷字节、范围、判定、建议或处置方式发生变化,都会使批准失效。我会通过明确的保留、编辑或关闭计划协调已创建的后续任务;语义发生变化时,我会返回第 4 阶段。我绝不会重新创建后续任务。
错误处理
- 未安装
gh。我会立即停止,并提示Install gh CLI: https://cli.github.com。 - 已安装
gh,但未通过身份验证。我会立即停止,并提示Run 'gh auth login' and retry. - 找不到问题或无权访问。我会报告
Couldn't access issue #<n>. Check the number and repo access. - 问题已关闭。我仍会执行审计,因为用户可能想验证关闭状态或重新打开问题,并会在报告中醒目注明
State: closed。对于“原位更新”,我会询问是否也要重新打开问题。