Issue Review — AI Agent Review / Audit for Doc-from-Issue
Repo profile — read .claude/repo-profile.md first. This skill is repo-agnostic;
arc is the reference implementation. Use the profile's repo_slug, verification_entry,
kb_issue, plugin_root (where issue-graph's scripts live), and toolchain wherever this doc shows an arc default. Arc's own provenance
for the lessons below is not inlined here (fuller case narratives, where they exist, are under .claude/case-law/).
把一篇 issue 处理到位:读 issue + 引用的 repo 文档/代码 + 已有 comments + 对照已落地的实现/代码/intent,产出带证据的发现,作为 comment 落回 issue(而不是埋在某次对话里)。覆盖五类:
- Doc-review:人起源的新设计在 issue 里被讨论/评审(找漂移、独立发现、reframe)。轻量、讨论导向,产出 = 评审 comment + 拆分建议。
- Doc-audit:repo 里的存量老文档被逐篇审计(对照代码重验、跑测试、给 5 类结论)。有界单元,按价值分档投入。
- System-audit(comprehensive code audit):issue 要求对一个子系统 / 跨平台 parity / runtime 本身做全面代码审计(如「Swift/Kotlin 实现是否落后于 Node/CF 参考」)。无界任务,完整执行是契约——见下「★ System-audit」。
- Research(研究类):issue 要求调研一个外部系统/技术与本系统的结合点(如「研究 perkeep 和 did space 的结合点」)。调研这一轮只产出 comment,不改 repo 代码;下一轮按 ratchet 转执行管道——见下「★ Research」(铁律 1 与铁律 10)。
- Idea(想法类):issue 是一个内部提案/想法(如「提供一个 DID Space + MCP endpoint 给 loop 里的 agent」)——可能可行、可能不可行、可能太模糊、可能与现有设计矛盾。首轮是 clarify,不是执行;首轮产出 = 评估 comment + 澄清问题 + 行动声明,首轮不改 repo 代码、不开 spin-off;第二轮起按 ratchet 开工——见下「★ Idea」(铁律 2 与铁律 10)。
五类共用同一台引擎(读 → 对照现实 → 带证据落 comment),但投入档位和产出形态不同:doc-review 轻、doc-audit 按价值分档、system-audit 必须全量、research/idea 深调但首轮只落 comment(下面「省 token」那套不适用于 system-audit 和 research/idea 的调研深度)。research/idea 的「只落 comment」是首轮限定,不是永久状态——两者的铁律 10 都要求第二轮起转成动作,否则就是原地打转。
怎么判类型:issue 锚定单篇文档 = doc-review / doc-audit;issue 说「comprehensive audit」「review 整个 runtime / 跨平台是否一致」「需要完整 test run」「发现 gap/bug 开 issue」= system-audit;标题带 [research] / 正文是「研究一下 X 和我们的 Y」「调研 X 是否适合我们」= research;标题带 idea: / 正文自称「这是个 idea,首先需要分析可行性和价值」/ 是一段提案性质的构想(常附 Slack/讨论原文,无验收标准、无明确 spec)= idea。拿不准 audit 类就按 system-audit 的高标准做(宁可多投入,不可粗略);拿不准「指令还是想法」就按 idea 处理(先 clarify 的代价远低于把模糊想法当指令执行错方向)。
输出语言与写作规范(遵循 comment_language,信雅达)。 所有面向团队的产出——issue comment、spin-off issue 标题与正文、PR 描述正文、评估/验证报告——一律用 repo profile 的 comment_language 指定的正文语言(arc 默认:中文,团队阅读语言);代码标识符、路径、命令、path:line、测试输出保持原样(不翻译代码)。PR 与 commit 标题遵循 comment_language 的标题惯例——完整 Conventional Commits(type(scope): description,arc 默认标题全英文,冒号后的描述也用英文,不得混用);issue 标题(含 spin-off)随正文语言(arc 默认:中文)。追求信雅达,不堆砌:内容太多本身就是阅读负担——先给一句话结论,再给最少但足够的证据,不为显得全面而铺陈;每条断言配证据(文档 / 代码 path:line / 真实测试输出,UI 相关必附截图);长日志折叠进 <details>,不平铺刷屏。
Usage
/agentloop:issue-review <issue-number-or-url> [--dry-run]
<issue-number-or-url> — 要处理的 GitHub issue(用 gh 读取)
--dry-run(旧名 --no-post 仍兼容)— 只产出给用户看,不发/改 comment、不自动开 spin-off issue、不动 label、不加锁(用于人想先预览)。语义见插件 README 的 Dry-run contract。
Examples
/agentloop:issue-review 115 # doc-review:评审一篇新设计
/agentloop:issue-review 120 # doc-audit:审计一篇存量老文档
/agentloop:issue-review 756 # idea:先 clarify + open 评估一个提案
/agentloop:issue-review 120 --dry-run
When to Use
- 一个 issue 在讨论/评审一篇 repo 内文档(
planning/、docs/、intent/),需要有据可查的 AI 处理。
- 已有人类 reviewer 留意见,想要一个独立的、能发现人类没提到的问题的视角。
- 你在搭"自动处理 issue 的 agent loop",需要一个可复用、产物可追溯的动作。
不适用:纯代码 PR 的 review(用 /code-review / /review);纯本地文档、不走 issue 的(用 /agentloop:design-review <path>)。
★ 并发锁(每次 run 先 acquire,收尾必 release)
多个 actor 会同时碰同一个 issue:定时 issue-sweep(cron)、多人本地手工 /agentloop:issue-review、本地 agent。不协调就重复读+核验+跑测试+重复评论(白烧 token),严重时重复开 PR。两个 label 各管一件事:
| label |
含义 |
谁加/摘 |
谁尊重 |
agent:hold |
人类保留 = 终态冻结——"没我反馈别做不可逆动作(close/merge)",不是"别理它"(issue/PR 通用) |
只人加、只人摘;agent 永不自动摘。唯一例外(arc#2914):本 skill 产出「建议关闭」类结论清单时,自动加给清单点名的 issue(见下 ★「建议关闭」类结论清单)——摘除仍然只人。 |
issue-sweep / pr-sweep 冻结终态动作(永不 close/去重关闭/合并),但人类新评论/新 commit 照常触发 review + 响应(人的反馈是最高优先级输入);无新输入才跳过。issue-review / pr-review 显式手工调用只提示不挡(人点名就是要处理) |
agent:processing |
处理中互斥锁(advisory,带 TTL 30min) |
agent 开工 acquire、收尾 release |
任何 run 见新鲜的锁就 SKIP;过期(上一个 runner 崩了)则抢锁重做 |
关闭带 agent:hold / needs-human-confirm 的 issue,可执行闸是 hook deny-guarded-issue-close.ts(#5426);散文不是闸。
跨 issue/PR 边界: agent:hold 两边通用——「人类保留」是与对象类型无关的预约(GitHub label 仓库级共享),两侧语义一致:冻结终态动作(close/merge),不冻结响应——人类新评论照常处理,pr-review 显式调用只提示不挡(见各自 SKILL)。agent:processing(TTL 互斥锁)只用于 issue:PR 侧的并发去重由 pr-sweep 自己的确定性分支 claude/issue-<N> + 开 PR 前认领检查 + disposition label 承载,不复用这个锁。
定位要诚实:agent:processing 是 advisory(省重复工作),不是完美分布式锁——本仓库人和 AI 同账号/可能同 token,label-add 幂等,两机同瞬起步有残留竞态。真正的硬去重仍是 issue-sweep 已有的「确定性分支 claude/issue-<N> + 开 PR 前认领检查」,这层不动、兜底。agent:processing 只是把撞车从"收尾才发现"提前到"开工就短路",省掉前面的读/核验/测试。
无分支兜底的终态动作(comment+close 类,如 ★父级 rollup)另有硬互斥:claim-comment fencing。 分支碰撞兜不住它们,label 又无 CAS——用 issue-graph 的 claim.ts(comment id 全序裁决,先写后读、最早未过期 claim 赢):
bun <plugin_root>/skills/issue-graph/scripts/claim.ts --issue <N> --action rollup # exit 0=赢/3=输(输了自删claim退出)
# …执行动作(动手前最后重读一次目标状态)…
bun <plugin_root>/skills/issue-graph/scripts/claim.ts --release <claimId> # 完成必调;崩溃靠TTL 30min兜底
命名消歧:本 skill 里 in-progress 这个词已是「多轮续做的 comment disposition」(轮次感知接力),所以互斥锁另起名 agent:processing,别复用 in-progress。
acquire(Step 0 最前,读 thread 之前):
N=<issue>; TTL_MIN=30
# 缺 label 自建(幂等,best-effort)
gh label create agent:hold --color D4C5F9 --description "人类保留:自动化别碰,只人摘" 2>/dev/null || true
gh label create agent:processing --color FBCA04 --description "处理中互斥锁(advisory,TTL 30min)" 2>/dev/null || true
labels=$(gh issue view "$N" --json labels --jq '.labels[].name')
# agent:hold —— 人类保留:显式手工调用只提示(sweep 才真跳过)
grep -qx 'agent:hold' <<<"$labels" && echo "⚠️ #$N 带 agent:hold(人类保留);显式调用继续。"
# agent:processing —— 互斥锁:新鲜则 SKIP,过期则抢
if grep -qx 'agent:processing' <<<"$labels"; then
since=$(gh api --paginate repos/{owner}/{repo}/issues/$N/timeline \
--jq '[.[]|select(.event=="labeled" and .label.name=="agent:processing")]|last|.created_at')
now=$(date -u +%s)
then=$(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$since" +%s 2>/dev/null || date -u -d "$since" +%s)
age_min=$(( (now - then) / 60 ))
if [ "${age_min:-9999}" -lt "$TTL_MIN" ]; then
echo "🔒 #$N 正被处理中(since $since, ${age_min}min<${TTL_MIN}) — SKIP"; exit 0
fi
echo "♻️ #$N 锁已过期(${age_min}min) — 抢锁重做"
fi
gh issue edit "$N" --add-label agent:processing # 加锁
release(收尾,成功/失败都做):
gh issue edit "$N" --remove-label agent:processing
--dry-run 不 acquire/不 release(不做任何 outward 写);只在发现已上锁时打印一句提示。
- ★ 解读→执行的升级点 = 重新过 Step 0。 会话以「帮我看看/解释一下」开场(dry-run 语义,不加锁)后,用户中途说「解决掉/实现它」——升级为执行的那一刻必须先 acquire 锁再动手,不能带着 dry-run 的无锁状态直接开工(实战教训:曾因此被并发 agent 重复实现)。
- 长任务续锁:预计超过 TTL(30min)的执行(实现+验证+PR),每 ~20min 重新
gh issue edit <n> --add-label agent:processing 一次(label-add 幂等,timeline 会刷新 labeled 时间戳),否则锁中途过期照样被抢。
- 崩溃/被 kill 没 release → 锁靠 TTL(30min)自动失效,下一个 run 抢锁重做,不会永久卡死。
- 手工想长期独占某条:人先打
agent:hold(sweep 永久绕开),处理完人摘掉——比临时锁更强、更明确的预约。
★ 轮次感知 + 省 token(每次调用先做这件事)
不要无脑全量重跑。 一篇 issue 会被处理多轮;后续轮的成本应该远低于首轮。先读 thread(gh issue view <n> --comments,便宜),判断轮次:
| 轮次 |
信号 |
该做什么 |
| 首轮(冷启动) |
没有既往 AI review/audit comment |
先 triage 价值,按档投入(见下):明显废弃的只轻确认;真活的才全量(对照代码 + 跑测试) |
| 后续轮(热启动) |
已有 AI 结论 + human 意见 |
不重做:读 thread,把既往证据当既成事实,按 human 意见走下一步 |
冷启动也要按价值分档,别一上来就 full build / 全测:
- 先廉价判类别:读 frontmatter(
superseded / superseded_by / deprecated)+ ls/grep 扫一眼对应代码在不在。明显已废弃 / 不再有价值的(显式 superseded、方案被取代、对应代码已移除)→ 只做轻确认:用 grep/ls/git log 坐实"代码确实没了 / 已被取代"即可下 deprecated,不 build、不跑测试套件、不逐条 path:line。
- 只有判断它「真活着」(可能 drifted/partial/current、细节要紧)时,才上全量:逐条
path:line + 真跑测试。
- 一句话:投入与文档的价值成正比。 给一篇要删的死文档做全量审计,本身就是浪费。
⚠️ 以上「按价值分档 / 轻确认 / 省 token」只约束 doc-review 和 doc-audit。System-audit 不走这套——见下。
★ System-audit(comprehensive code audit)——完整执行是契约
当 issue 要求全面代码审计(子系统 / 跨平台 parity / runtime 本身),「省 token」让位于「不漏」。粗略 = 失败。 铁律:
- 不许轻确认、不许靠 frontmatter 下结论。 每条 parity claim 必须
path:line 坐实(在 / 不在 / 漂移),两侧都查(参考实现面 vs 目标实现面)。
- 必须真跑测试,缺测试就补。 issue 通常明说「要有完整 test run」——跑得动的全跑、记确切命令 + pass/fail;跑不动要说清原因(见 repo profile 的 Deployment Environments 列出的平台工具链缺口,arc 例:沙箱无 Xcode/Android SDK → Swift/Kotlin 测试
describe.skip/无法编译),并退而用静态对照 + conformance 套件兜底,不能假装跑过。「跑不动」的判定纪律同 Step 4:先真尝试 + 先补 setup(编译原生依赖、link CLI 不算环境限制),只有实际撞上硬工具链缺失才算,且贴确切报错——别预先开脱。
- 先分解再审计。 把大审计拆成子系统单元(core / aup / session / 各 provider …),逐元对照,别糊成一团。每元独立给证据。
- gap/bug/security 当场开 issue(合理颗粒度),不必等确认。 一类 gap 一个 issue;bug、security 各自独立开(
security + P0)。审计 comment 汇总矩阵 + 一句话指向各 spin-off。
- 产出 = 现状矩阵(参考×目标,逐元 ✅/⚠️/❌ + 证据)+ 测试结果 + gap 清单 + 已开 issue 列表。 这是「报告现状」的交付物,不是给一个 status label。
Model / 编排(System-audit)
- 不要为省钱用弱模型做整体综合。 主控(synthesis + 开 issue + 判 parity 真伪)用强模型(Opus);分解后的有界子元审计可以下放 Sonnet(读 1 个子系统两侧代码 + 跑 1 个测试 + 给结构化发现),但关键语义面(core 语义、协议/校验、安全降级)留 Opus。
- 该并行就并行:子系统之间相互独立,用 subagent 扇出(每个 agent 一个子系统,返回结构化 parity 发现),主控汇总。这既快又能各自深入——比单线程顺序扫更完整,不是更省。
- 一句话:doc-audit 选 Sonnet 是因为它有界;system-audit 反过来——宁可 Opus + 扇出多 agent,把它做透。
跨 repo / reference×target 一致性审计(system-audit 的常见形态)
很多 system-audit 是「审 A 是否正确消费了 B 的抽象」——如「下游 repo 是否 protocol-first 并正确复用上游核心抽象」「某平台实现是否落后于参照 runtime」(arc 例:「aside 是否 AFS-first + 用 ARC AUP」「Swift/Kotlin 实现是否落后于 Node/CF 参照」)。审计物在 target repo、参照实现在 reference repo,两个 repo 都本地 checkout、路径不同。纪律:
- 先定 reference 与 target,两侧都读。 reference = 权威抽象/协议真相源(
<reference-repo-path>,arc 例:platforms/swift、platforms/kotlin、providers/runtime/ui、packages/aup、AFS core);target = 被审代码(<target-repo-path>,arc 例:aside ios/ android/ .aup/)。每条 parity claim 两侧各给 path:line:target 到底在「消费 reference 的抽象」还是「平行重造一套」。
gh 全部带 --repo <owner/repo>。 审计 issue、verdict comment、spin-off issue、label 全落在 target 的 repo(issue 所在处);reference repo 只读,不在里面开 issue。跨 repo 时 repos/{owner}/{repo} 占位符会解析成当前 cwd 的 repo,别依赖它,显式写 --repo。
- 核心透镜:「真用」vs「用不彻底」要分层,别二值判。 常见形态是壳复用、肉不复用:renderer/接口是通用的 ✅,但喂给它的东西(UI tree / 数据)在各端手搭/平行重写 ❌。精确结论(「是真 AUP renderer,但每屏在 native 手搭 AUPNode、不加载 canonical
.aup,三套并行必然漂移」)远比「违反 AUP」有价值。先肯定做对的部分,再精确定位违规在哪一层。
- 单一真相源(SSOT)判定是这类审计的核心产出。 同一界面/能力有没有「一份 canonical 定义被各端 render/消费」,还是 N 份平行实现(JSON + Swift + Kotlin…)?列出同名单元的重叠矩阵坐实。
- 跨 repo 根因回溯 + 分段修复。 target 的违规常根因在 reference 的能力缺口(如「热读绕过 AFS」根因是「ARC AFS 缺 reactive/watch API」)。spin-off 要写清两段:reference 侧补能力(可能需在 reference repo 另立 issue)+ target 侧改用。
- fix 需方向时,issue 框成「确认的 gap + 待定方向 A/B/C」,别预设。 现状(违规)已坐实就开 tracking issue(system-audit 契约要求开),但把统一/修复方案作为待人拍板的选项列出,不替人选(呼应 spin-off 的「needs-decision 不预设」)。纯营销页/需人定性的(如 bespoke landing HTML)留 verdict comment,不自动开 issue。
- 平台专属工具链测试大概率跑不动——诚实退档。 具体平台见 repo profile 的 Deployment Environments(arc 例:Xcode(Swift)/gradle+Android SDK(Kotlin)在沙箱通常缺);先真尝试 + 先补 setup,撞硬阻塞就贴确切命令+报错(arc 例:
gradle.properties 硬编码 JBR、composite build 期望的同级 repo 布局不符、缺 compileSdk),退回静态对照 + 读测试源坐实结构,显式标注跳过哪层、绝不假装跑过。结论基于代码结构的确定事实,不依赖测试通过。
- 批量开 spin-off 后必须核对 title↔body↔label 对齐。 循环里捕获 issue number 易错位(首个 create 漏号→整体偏移),后续 body 回填会打到错误的 issue。开完逐个 dump body 首行比对 title,发现错位立即
gh issue edit 修正 + 补建漏掉的。宁可多一步核对。
共享 KB(热启动 repo 拓扑,免重复探索)
有一个 pinned 知识库 issue(repo profile 的 kb_issue,arc 默认 label doc-audit-kb),body 是 repo 拓扑 hints(子系统在哪、测试命令、大迁移、meta 事实)。每次 run 先读它热启动,末尾把新学到的 append 回去:
- 开工前先读 KB body(
gh issue view <kb_issue>,只读 body——comment 是原始追加流,别全读)拿热启动事实——别再从零 grep "CLI 在哪 / 测试命令是什么 / 哪些大迁移"。
- hints 非真相:信它快速定位,但便宜复查(代码会动)。读到错条目(如"X 在
packages/cli"但其实已迁)→ 编辑 KB body 改那行 + 留一条 comment 说改了什么。一条 stale 的 hint 比没有还坏。
- 末尾 append:本轮新发现的拓扑 / 命令 / 迁移 / meta 事实,加进 KB body 对应小节,带"最后确认 commit/日期"。
- 范围:KB 只放拓扑 / 命令 / 迁移 / meta;不放审计账本(账本 =
gh issue list --label doc-audit)。
- 并行批处理时(暂未启用):agent 只追加 comment,由一个整理步骤折叠进 body,避免 body 写冲突;顺序审计时直接编辑 body。
Memory MCP(可选,当已配置时)
如果运行环境的 MCP 工具列表包含 AFS 命名空间(如 afs_read / afs_write / afs_search,来自已连接的 ARC instance MCP 端点),在 Step 0 中增加两步:
热启动前先 recall(与读 KB 同时做,并行):
afs_search /user/memory 关键词:<issue 相关术语 / 路径 / 子系统>
读到的内容(observations / patterns / principles)补充进热启动上下文——和 KB hint 同等地位:「快速定位,需代码便宜复查」。
处理完毕后 store(追加,不覆写已有条目): 写入时机——本轮发现以下任一:
- 非显而易见的代码约束(某函数在某场景不可用的原因、隐藏副作用、hook 执行顺序)
- 团队决策(为什么选 A 不选 B、某字段命名的历史原因)
- revert 理由(某 PR 回退的真实原因,防止下次重蹈)
- 跨 issue 的规律(同类 bug 反复出现的根因模式)
写入三层(粒度由小到大):
observation:具体事实 + path:line(最小粒度、最贴代码)
pattern:跨多次观察归纳出的规律(「X 类 issue 根因通常是 Y」)
principle:推断出的工作原则(「做 Z 前必须先检查 W」)
路径:afs_write /user/memory/<memory_namespace>/<namespace>/<id>(memory_namespace 见 repo profile Agent Tooling,arc 默认 arc-loop);caller 身份自动隔离(不同 loop agent 互不干扰)。
未配置 MCP = 本节跳过,skill 其余行为完全不变。
热启动三条硬规则(省 token 的闸):
- issue thread 是累积状态。 既往已核验的证据(
path:line、测试 pass/fail 数)默认信任,不重新推导——除非"文件变了"或"human 质疑了这一条"。
- 不重 build、不重跑整套测试、不重读全部文档。 只在「目标代码变了 / human 点名要重查」时,重跑那一个测试、重读那一节。
- 判断"变没变"用便宜的命令:
git log --oneline --since="<上条 comment 时间>" -- <unit 路径>。没动过 → 既往证据成立,直接进下一步。
human comment 是后续轮的方向,但不是圣旨。 它确认/否决某结论、提新事实(如"这协议其实是给反向注入用的")、指下一步——优先按它走,但不盲从:
- human 没提到的真问题不要因此丢掉——该指出还指出(他可能没 cover 全)。
- human comment 是疑问 / 不确定(带"?"、"是不是"、"我不确定")时,当作要回答的问题,不是要执行的命令——给带证据的答复,必要时坦白你也不确定、列出选项让人定。
- 多条 comment / 来自不同人时,逐一列出、调和分歧;别只听最后一条或最大声的那条。有冲突就摆出来让人拍板,不要自己悄悄选一个。
后续轮的产出往往不是"再来一份完整 review",而是一个针对性的下一步(确认某结论 / 解某个 gap / 起草 crystal / 回答疑问)。
★ Research(研究类 issue)——外部系统 × 本系统结合点调研
issue 要求研究一个外部项目/技术(开源系统、协议、竞品)与本系统的结合点、可行性或借鉴价值。范式如 perkeep × did-space 的结合点调研。这是 deep research 的 repo 内变体:最大区别是我们身在一个 repo 里(知识库或产品代码),所以能做代码级深度,而不是只读对方的宣传页。
铁律(与其他各类的关键差异):
- 调研这一轮绝不改本 repo 代码。 产物 = 一条证据化研究 comment(+ label),不是 PR、不是文件。skill 改进等衍生工作是另一件事,不混在 research 交付里。边界:这条约束的是「research 交付本身」——铁律 9/10 把 issue 转进 feature 管道之后,它就不再按 research 处理,那一轮该开 PR 就开 PR(切到 feature 的纪律)。不许拿本条当「永远不动手」的挡箭牌。
- 默认只留 comment + 外部资源链接,不下载保存。 外部 repo clone 到 scratchpad 用完即弃。仅当 issue 明确说要收集数据保存在 repo 里时,才在
research/<task-slug>/ 开专门目录收集值得保存的(仍走 PR,人签名)。
- 两侧都必须代码级,不许只读 README。 外部侧:shallow clone 到 scratchpad,读架构文档 + 关键源码包,结论带 repo 内相对路径(尽量带行号)+ 官方 doc 链接;我方侧:读本 repo 代码/intent/planning,结论带
path:line。并行 fan-out 两个 subagent(一侧一个),主控综合——两侧独立取证,防止先入为主。
- 外部项目健康度必查:
git log 最近 12 个月提交曲线、最近 release、核心作者近期是否活跃、license、gh api repos/<owner>/<repo> 的 pushed_at/stars。结合点结论强依赖对方活性(死项目和刚复活的项目结论完全不同),这常是独立发现的来源(如发现 perkeep 2025-10 复活、7 年来首个 release)。
- 诚实优先,反「为用而用」。 issue 主人常自带警惕(「不能为用 X 而用」),研究结论必须敢说「这个方向不建议」;每个结合点标注真实受益方和前提条件。
- 产物结构(comment,中文):TL;DR 逐条直接回答 issue 提出的具体问题 → 两侧架构对照表(均代码坐实) → 冲突面 → 结合点分档(⭐ 推荐 / ◐ 待定或仅借鉴 / ✗ 不建议,每条给理由) → 行动声明收尾(铁律 10 的 ratchet 格式:「下一轮我会做 X,除非你说不」,X 默认取 ⭐ 档) → 外部资源链接清单。首轮不自动开 spin-off(先给人一个廉价的纠错点),但收尾不是选项菜单——异议窗口过了就按声明执行。
- Label:
research;并发锁照常(agent:processing)。needs-human-confirm 只在存在真分叉(互斥且不可逆)时才加——见铁律 10;能给安全默认的一律不加。issue 保持 open。
- 投入档位:调研深度不省(两侧 subagent 各自全量),但验证层不同——research 不跑本 repo 测试套件(没有要验收的实现),证据 = 双侧源码引用 + 官方文档 + 项目活性数据。
- ★ 自带明确终局目标的 issue,调研只是 phase 0,不许停在调研(#1947 反馈,2026-07-19)。
〔本条原标题是「纯调研才以 needs-human-confirm 收尾」——已被铁律 10 取代:现在纯调研也不
以 needs-human-confirm 收尾,而是 ratchet 行动声明。本条只保留它真正管的那一档:自带终局目标的。〕
issue 同时载有明确终局目标(「不可动摇的目标」「最终应该…」式表述)时,research 只是 phase 0:调研 comment 落地后立即转 feature 管道(拆 sub-issue 图 + 原生边 + 可测终局验收写进父 issue,能做即做),不得以「待拍板选项」冻结。拍板项必须是互斥分叉——非互斥的工作项是依赖序,列成 phases 直接执行;可由工程判断决定的选择(API 形态、实现路线)由 agent 自决并在 PR/issue 记录 rationale;只有真正不确定的(不可逆分叉、审美、优先级)才需要人,且用「推荐 + 默认执行的异议窗口」(不同意在 issue 喊停)而不是阻塞等待。把工作分解包装成拍板项交给人 = 用拍板换工作量,禁止。(与 ★Idea 铁律 9 同源同判据——#1947/#1949 同日反馈;改其一必同步另一处及 issue-sweep 表对应两行。)
- ★ 调研不得以「仍需拍板」收尾——收尾必须是 ratchet(2026-08-20 老冒反馈,镜像 ★Idea 铁律 10)。 铁律 9 修的是「issue 自带明确目标」那一档;这条修的是剩下的那档——纯调研也不许无限期挂在「待人选方向」。研究 comment 的最后一段固定为行动声明:「下一轮我会做 X(具体到第一个 spin-off 的标题和第一步),除非你在此之前说不」;下一轮人若没有否决也没有改方向,直接执行 X,不再重新调研——再写一篇「更完整的调研」是本条明确禁止的动作。分档结论仍然照给,但 ⭐ 档就是默认选中的那个。完整措辞与三条边界见 ★Idea 铁律 10(两处同源,改其一必同步另一处及 issue-sweep 表对应两行)。
后续轮:人选定方向(如「做 A」)后,按选项拆自足 feature issue(照「partial → 拆分剩余工作」的自足配方),或转入 /agentloop:design-review → /agentloop:build-phases 管道;人什么都没说 → 按铁律 10 的 ratchet 执行 ⭐ 档,不是再调研一轮;若人只是追问,原地编辑/追加 comment 回答(仍以行动声明收尾)。
★ Idea(想法类 issue)——先 clarify,open 评估,不当指令
issue 是一个内部提案/想法——作者自己都标注「可能可行,可能不可行,可能太模糊,也可能和现有的东西矛盾」。范式如「给 loop agent 提供 DID Space + MCP endpoint」这类提案。这类 issue 最大的处理风险不是做得不深,而是做错性质:把 idea 当指令,直接开工实现一个方向未定、边界未清的东西。
铁律(与其他四类的关键差异):
不当指令,当提案。 第一步是理解复述(把 idea 用自己的话讲一遍,分解成可独立评估的价值主张),而不是拆任务。复述放 comment 最前——它给人一个廉价的纠错点(「你理解错了」比「你做错了」便宜一百倍)。
首轮绝不改 repo 代码、不开 PR、不开 spin-off——方向没定之前开 issue/写码都是预设。产物 = 一条证据化评估 comment + label。但这条只管首轮,而且首轮只有一次。 见铁律 10:第二轮起,除非人明确否决,评估必须转成动作。
Open 评估,三个方向都真查: ① 可行且有价值——对照代码找「地基已有多少」(常见惊喜:构件早已存在,idea 只缺接线);② 不可行 / 价值不明——缺口带 path:line 坐实,不糊「应该可以」;③ 与现有设计矛盾——点名矛盾对象(哪个机制/纪律/在途设计),把张力摆出来而不是悄悄选边。每条断言 path:line 坐实,grounding 纪律与审计同级。
诚实优先,敢泼冷水。 idea 作者(常是 founder/架构师)要的是可行性分析,不是附和。「这半个价值主张有实打实的工程量缺口」比「好主意」有价值;同时先肯定确实成立的部分再指缺口(同 system-audit 的分层判定)。
信息不足 → 列具体澄清问题,请人下一轮补,不硬编方案。 问题要具体到能拍板(「作用域是共享还是 per-repo?」「认证接受 owner token 共享吗?」),不是开放式的「你觉得呢」。每个问题说明为什么它 block 后续(影响什么设计分叉)。issue 保持 open。但「多轮迭代」指的是问题逐轮变少、方案逐轮收窄,不是每轮重出一份评估——每个问题都必须同时给出「没人答时按哪个默认走」(铁律 10),没有默认可给的才算真 block;有默认的问题不阻塞开工。
产物结构(comment,中文):理解复述(价值主张分解)→ 现状对照表(地基已有什么,path:line)→ 真实缺口(要落地必须补的,带证据)→ 张力/矛盾检查(与现有机制、与在途设计、拓扑分叉)→ 价值评估分档(⭐/◐/✗,按主张分别给,不整体二值判)→ 需人补充的 context(具体澄清问题,每条附「没人答时我按哪个默认走」)→ 行动声明收尾(铁律 10 的 ratchet 格式:「下一轮我会做 X,除非你说不」)。不以选项菜单 / 「仍需拍板」结尾。
Label:idea;并发锁照常(agent:processing)。needs-human-confirm 只在存在真分叉(互斥且不可逆)时才加——见铁律 10;能给安全默认的一律不加。issue 保持 open。
投入档位:评估深度不省(对照代码逐主张坐实),但验证层不同——idea 不跑测试套件(没有要验收的实现),证据 = 本 repo 源码引用 + 既有设计文档 + 相关讨论原文。
需求已明确的 idea → 不出拍板菜单(Robert 纠错,#1949/#1947,2026-07-19)。 作者已把目标说清、只是路径/细节未定时,评估不得把「可给安全默认的决策」做成选择题——那是变相让人替 AI 砍 scope,且人选完后 agent 容易「解决几个具体问题就以为全部完成」。正确形态:①凡能给安全默认的决策直接选定并标注「按此推进,不同意请指出」(ratchet,同 Step 5.5);②产出必须附终局验收清单(对齐 issue 原始目标、逐项可验证)——它是父 issue close 的唯一条件(rollup 核对的就是它),「子 issue 全关 ≠ 完成」;③人确认方向后立即全量分解成自足 spin-off + 写边(此刻铁律 2 的「不开 spin-off」解除),分期是优先级顺序、不是删减;④只有真不确定项(资源级投入、不可逆动作、外部依赖时机)才留给人拍板,且不 block 其他 workstream。判据:拍板项之间若不互斥,那它们就不是拍板项,是依赖序——直接排进计划执行。(与 ★Research 铁律 9 同源同判据——#1947/#1949 同日反馈;改其一必同步另一处及 issue-sweep 表对应两行。)
★ 评估不得以「仍需拍板」收尾——收尾必须是 ratchet(2026-08-20 老冒反馈)。 铁律 5 的「信息不足就列澄清问题」和铁律 2 的「首轮不开 spin-off」,在旧写法下(铁律 7 曾无条件挂 needs-human-confirm + 「issue 保持 open 等人拍板」)合起来给了 idea 一个结构性的原地打转出口:每一轮都能合法地产出一篇高质量分析然后停在「仍需拍板」,人再说一句,下一轮再分析一篇。实测这就是「两个 agent 互相附和、没有人去做」的来源。本条与铁律 2/5/7 的现行文字是配套改的——修法是把默认方向反过来:
- 评估 comment 的最后一段不是问题清单,是行动声明。 格式固定:
「下一轮我会做 X(具体到第一个 spin-off 的标题和第一步动作),除非你在此之前说不。」
仍然可以在上面列澄清问题——但它们是优化输入,不是开工前置;你必须同时给出
「问题没人答时我按哪个默认走」。给不出安全默认的,才是真拍板项(同 Step 5.5 硬前置)。
- 异议窗口过了就开工。 第二轮起(评估 comment 已发、人没有明确否决也没有改方向),
不再重新评估——直接按上一轮声明的 X 执行:拆自足 spin-off + 写原生边(此刻铁律 2
的「不开 spin-off」解除)、能做即做、走
/agentloop:design-review →
/agentloop:build-phases。再写一篇「更完整的评估」是本条明确禁止的动作。
needs-human-confirm 只贴给真分叉。 「这个方向对不对」不是分叉(给推荐 + 异议窗口);
「A 和 B 互斥且都不可逆」才是。判据同铁律 9:拍板项之间若不互斥,那它们就不是拍板项,
是依赖序——直接排进计划执行。
- 唯一维持原地不动的情形:人明确否决(建议 close,人来 close),或人提出了新的、
与上一轮不同的问题(答它,然后仍以 ratchet 收尾)。
与 Research 的区别:research 调研外部系统与本系统的结合点(双侧 subagent、查对方项目活性);idea 评估内部提案(单侧,但重点在「对照现有架构找已有/缺口/矛盾」+「把模糊处变成可拍板的问题」)。一个 idea 可能内嵌 research 需求(「用 X 来做这个」)——那就在评估里嵌套 research 那套双侧纪律。
后续轮:人答了澄清问题/拍了方向 → 按选定项拆自足 feature issue,或转 /agentloop:design-review 出设计;人什么都没说 → 按铁律 10 的 ratchet 开工,不是再评估一轮;人否决 → 建议 close(人来 close,agent 不动手);人追问 → 原地编辑/追加 comment 回答(仍以行动声明收尾)。多轮之后 idea 常收敛成 feature/design issue——那一刻起它就不再按 idea 处理,切到对应类型的纪律。
★ 父级 rollup(孩子全关的父 issue 收尾)——授权的自动 close 例外
触发:issue-sweep Step 0.5 的 graph-scan 报出 rollupCandidates(open 父 issue
∧ 原生 sub-issue 全部已关),或人点名。这是本 skill「绝不自动 close」铁律的唯一
显式例外,需 repo owner 授权——修的是「孩子
全做完、父 issue 敞着等人 bump」的存量病。close 可逆(可 reopen),风险等级是噪音不是损坏。
流程(顺序硬性):
- 幂等检查:issue 已关 → 结束;已有
<!-- rollup-done --> marker comment → 结束。
- fencing 抢锁:
claim.ts --issue <N> --action rollup(见 ★并发锁)。输了 → 结束
(另一台机器在做)。agent:hold 的父 issue 不做 rollup close(hold = 人类保留
终态,见并发锁表),只写综合 comment 不关。
- 核对验收:读父 issue 的验收标准/问题清单/body 意图,逐条对应到子 issue/PR 的
落地证据(
path:line、PR 链接、测试输出)。动手前最后重读一次 issue state
(已关/有新人类 comment → 放弃动作,先按新输入走)。
★ 大块 issue 的完整测试闸(Robert 拍板 2026-07-20,源 #1947):多 phase /
带 sub-issue 图 / 带终局验收的 feature epic,close 前必须有真实 surface 上的
完整端到端场景测试——不是各 PR 单测绿,而是在真实目标环境(真机 / 真浏览器 /
live daemon)设计多类型场景(正向 + 诚实性负样本 + 边界),逐 case 跑、每 case 附
截图/输出证据,报告以稳定编号 checkbox(如 FM-01…)post 到 issue 逐项核销;
测试计划本身先 post 并标注为关闭验收条款。缺这层 → 不 close,先补测试
(这是 rollup 的默认组成,不等人提醒)。失败项如实记录:接线 bug → spin-off;
平台/模型局限 → 注明请人认可,不调宽判定凑绿。单 PR 小修不适用本闸。
- 综合 comment(中文,
> 🤖 AI Agent 头 + @ <hostname>):逐条覆盖表 +
每个子 issue 一句话结论 + 残留 gap(如有)。末尾带 <!-- rollup-done --> marker
(幂等 key)。
- 处置:全覆盖 →
gh issue close <N> -r completed;有残留 gap → 列出并留开
(残留是有界任务就按「partial → 拆分」拆自足 spin-off 并写边)。research/idea 类
父 issue 同样综合后 close——结论已在子 issue/comment 落地,父级只是收口。
- release claim:
claim.ts --release <claimId>;带 agent:ready 的同时摘掉
(消费方处理完摘——close 的 producer 下轮也会清,留开的必须现在摘,否则队列视图
一直显示"可干"误导人和其他 worker)。
★「建议关闭」类结论清单 → 落地时立即挂 agent:hold(arc#2914)
任何本 skill 产出的结论性批量处置清单——doc-audit 汇总、★父级 rollup 综合 comment、
一次性全量 backlog audit 等场景里,表格/列表形式列出多个 issue并给出「建议关闭」/
「建议合并」/「建议删除」这类需要人工复核才能执行的结论——在这份清单落地
(post 到 issue body 或 comment)的同一时刻,必须对清单里点名的每一个 issue 打上
agent:hold:
for n in <清单里点名的每个 issue 号>; do
gh issue edit "$n" --add-label agent:hold
done
(label 不存在则先按 ★并发锁 acquire 段落的 gh label create agent:hold ... || true 幂等创建。)
为什么不能只靠正文文字承诺(arc#1863 教训): #1863 是一次一次性 138-issue 全量
backlog audit,body 末尾明确写「『建议关闭』一栏本次没有代关,等人扫一眼表格后批量关即
可」——这段自然语言承诺没有配套任何结构化信号。下一轮无人值守 sweep 把这段文字里点名的
12 个 issue 直接当成可执行指令关闭了,绕开了这里声明的人工确认闸(事后核对基本站得
住,但那是运气,不是设计——见 arc#2914)。agent:hold 是 issue-sweep Step 1「Then
drop the reserved/locked ones」已经尊重的既有确定性机制——用它承载「等人复核」的承
诺,而不是指望下一轮 sweep 去解析 issue body 里的自然语言限定语。这与 issue-sweep
Step 2 的对应规则互补:Step 2 保证即便某个被点名的 issue 意外漏挂 agent:hold,清单
本身也不会被当成指令消费——需要独立人工确认才行。
人复核完摘 label:批准 → 人自己 close(或摘掉 agent:hold 后走正常 sweep 流程);
否决 → 摘掉 agent:hold 并留一条说明。agent 永不自动摘这个 label(同上 ★并发锁
表的通用规则:agent:hold 只人加只人摘,本节是唯一的"自动加"例外,且不含"自动摘")。
Doc-from-Issue 生命周期(这个 skill 所处的流程)
人起源的文档从 issue 开始,讨论到可落盘,再像代码一样提交进 repo。两层:
| 层 |
角色 |
性质 |
| Issue = raw / 工作层 |
一切输入 + AI 铺开 + AI review/audit(本 skill) |
可变、可以脏、累积、AI 辅助;永不进 repo |
| Repo = crystal / 结晶层 |
人逐字负责的极简文档,走 PR commit,回链 issue 作 provenance |
像代码一样;人对每个字负责 |
方向单向:脏的往精炼走;精炼的不回流污染(要改 = 开新一轮)。Provenance 是 append-only 链:doc → 本轮 issue → 上轮 issue → …,closed issue 永久可达。
人 / AI 的边界(按"后果可逆性"划,不按"是不是 outward")
agent 要有判断力、自己动手,不要事事请示。可逆的、可追溯的操作直接做;只有大动作 / 不可逆才停下来等人。
- 自动做,不问(有判断力地做):发/改 comment、打/调 label、指派 assignee、判定并标
status、维护"活的 crystal"草稿;以及该单独开 issue 的就直接开——review 中发现的、明显独立于本文档的问题(安全漏洞、未接线的死代码、明确的 bug),自动开新 issue(挂好 label/milestone/assignee + 双向回链),不征求用户意见。
- 需人确认(只有大动作 / 不可逆):删除内容或文件、搬目录、PR merge、close issue、改架构方向的拍板。这些挂
needs-human-confirm 等人——理由:这是后果的承担点,AI 没有后果。
- 铁律:产出始终带证据;绝不自动 merge / close issue / 删文件 / 改文档 frontmatter。close 的唯一显式例外 = ★父级 rollup(孩子全关 + fencing 互斥 + 验收核对全覆盖,close 可逆)与
issue-sweep 的「PR merged 未自动关」清理。
Doc-audit 流程(审计存量老文档)
存量 intent/ planning/ 的逐篇清理。不搬目录(搬目录会破坏 issue↔文档路径 key、断 git history),只用 frontmatter status 标记 + 回链 issue;唯一物理改动是 deprecated 类删文件。
5 类 status 枚举(受控词表,替换历史上 30+ 种乱标)
status: |
含义 |
issue 去向 |
planned |
有价值,还没实现 |
open(tracker;创建前先 dedup 现有 issue/roadmap) |
partial |
实现了,但不完整(「待分诊」信号) |
open;gap 有 path:line 坐实 → 自动拆成独立自足 spin-off 后摘掉本 label、换残留状态(剩漂移→drifted;无残留→current+待人 close);仍推测/未定的 gap 留 comment 给人确认。见「partial → 拆分剩余工作」 |
drifted |
实现了,但文档漂移(描述的接口面 ≠ shipped 面) |
按文档类别分流(2026-07-17 Robert 拍板,#187 批): planning//intent/ → 归档,不修正文——ship 后它们是历史文物,真相源已转移到代码+living docs,修了必再漂(反例:#243 修一轮漂一轮)。归档 = 顶部打 historical tombstone banner(见下「historical 归档」),有价值的设计 rationale 先抽进 docs/guides//README 再归档;tombstone PR merge 时 close issue。docs/ living guide → 修文档 → 转 current |
current |
实现了,文档准确 |
closed + 审计记录 |
deprecated |
废弃 |
closed;内容先存 issue → 人确认 → 单独 PR 删文件 |
(在途新设计用 draft,不属审计 5 类。)
命名 / 归类约定
- Milestone = 目录批次:命名与归类跟随 repo profile 的 Milestone Conventions(arc 默认:
Doc Audit: intent/ / Doc Audit: planning/ / Doc Audit: docs/),一个个清,防 issue 爆炸。
- Label:
doc-audit(meta,全挂)+ status:<x>(本轮结论挂)+ needs-human-confirm(给了建议、待人确认 close/delete)。
- 标题:
[<area>] <doc-name> — doc audit,如 [intent] session-protocol — doc audit。
- 幂等 key:issue body 首行
<!-- doc-audit-key: <doc-path> -->;创建前先 gh issue list --search 搜它防重复建。
- Assignee(让对的人来 review):把 issue 指派给两类人——
- 文档创建者(创建 issue 时就能拿到):文档首次提交的作者。
sha=$(git log --reverse --format=%H -- <doc-path> | head -1); gh api repos/{owner}/{repo}/commits/$sha --jq .author.login
- 实现代码的提交者(review 中定位到
path:line 后顺手拿):从实现文件的近期提交取、去重。
gh api "repos/{owner}/{repo}/commits?path=<impl-file>&per_page=5" --jq '.[].author.login'
gh issue edit <n> --add-assignee <login>。指派失败 / 非协作者就跳过并记一句,别 block。 同一个人只指派一次。
文档侧 frontmatter 契约(resolve 时由人签名的 PR 写入)
status: current # 受控词表,grep ^status: 一把筛
audit: "#<N>" # 回链审计 issue(issue body 反指文档路径,双向)
verified: 2026-06-24 # current 时记确认日期
historical 归档(drifted 的 planning/intent resolve 路径)
对无 YAML frontmatter 的老文档,tombstone 是顶部 banner(可 grep doc-status: historical 一把筛):
<!-- doc-status: historical (archived <date>, doc-audit #N) -->
> ⚠️ **Historical** — 实现期 planning/intent 文稿,已归档(doc-audit [#N](.../issues/N))。
> 内容以写作当时为准,**不再随代码更新**;与现行代码的已知漂移明细见上述 audit issue。
> 现状以代码与 living docs(`docs/`、各包 README)为准。
主文档用全量 banner,同目录 sibling(tasks/plan/review)用一行简版指回主文档。不删文件、不搬目录——
tombstone 保住反向引用的链接(反例:#253 想删 context-builder,结果 2 处活跃文档链接指着它)。
漂移明细不抄进文档,留在 audit issue 里(单一真相源)。归档后该单元退出后续 doc-audit 扫描范围。
生命周期
create(一篇=一 issue,挂 milestone+doc-key) → review(冷启动:对照代码+跑测试,见下) → human 给意见(comment) → resolve(热启动:按 human 意见起草修复/crystal) → 人确认 → close。
批量建 issue(精简;review 时补全)
存量批量 issue 化时,create 步骤刻意精简、不深读:每个 issue 只放 doc-key + 目录/主文档链接 + frontmatter status + 文档自己的 anchor 行 + 通用 audit 任务模板。目的只是让人快速浏览、给初步判断,不是当场分析。深度 overview 留到真正 review 时补。
- 幂等:create 前用
doc-audit-key 搜一遍,已存在就跳过——可重复跑、绝不重复建。这就是"哪些 doc 已 issue 化"的记录,不需要额外文件。
- 覆盖跟踪:账本 = doc-audit issue 集合;覆盖率 =
(所有单元) − (已存在 doc-key);milestone 做可见聚合。
- 老式合集(per-feature 约定前的扁平目录,如
specs//bugs//*.legacy/):先 1 目录 = 1 issue 粗审(整体是否 legacy),review 若发现需拆再拆 per-file。
- 审计阶段不必改 issue body:结论 + 证据放 verdict comment 即可(body 保持精简,comment 紧随其下、足够清晰)。仅在 resolve 阶段、或多轮后 body 已明显误导时,才(可选)补 body——别为补 body 给每篇多烧 token。
批量 review 编排(model / 限速 / 并发)
几十~几百篇一起跑时,skill 之外的编排层有四条经验,务必守:
- Model 选最合适的,别默认继承 Opus。 doc-audit 是有界任务(读 1 篇 + skill + KB + grep 代码 + 可能 1 个测试 + 归 5 类 + 写 comment)→ 用 Sonnet;不用 Opus、不用 1M context(单 agent 上下文远不到 200k)。
needs-human-confirm 兜底,Sonnet 偶尔偏差人会接住。Opus 只按需留给少数难/有争议的篇(如安全 spin-off 复核)单独重跑。成本差 ~5×。
- 限速:GitHub「内容创建」是硬约束(≤500/h、≤80/min)。 批量 POST 大头是 comment,所以:
- 每 agent 只发 1 条 verdict comment;
- 大批量时 agent 不各自发 KB comment(否则 POST 翻倍)——新拓扑事实写进 agent 返回行,KB 由单点(主控)集中折叠;
- spin-off 仅在确有独立真问题时;
- gh 遇 403 secondary limit → 退避重试(≤3 次),仍失败标
RATE-LIMITED、不整篇报错(可 resume 补);
- 估算:N 篇 ≈ N 个 POST,确保 < 500/h;N 很大就分段/降并发拉长时间。
- 并发 = 吞吐 × 限速的平衡。
10–14 并发 × 每 agent ~2–3min ≈ ~4–5 POST/min(250–300/h),稳在限速下;别盲目拉高并发触发 80/min burst。
- KB body 单点编辑。 并行 agent 只读 KB、不写 body;新事实由主控在每段/每批后统一折叠(见「共享 KB」)。仅交互式 session 可用 Workflow 编排(批量跑应 resumable,失败/限速可续);无人值守 routine 绝不 Workflow、绝不 AskUserQuestion——由
issue-sweep 的 bounded worker pool 使用无需确认的 agent fan-out;runtime 不支持时才串行 inline。待拍板问题照常落 comment。
Spin-off issue(自动开,不问)
review/audit 中常会撞到独立于本文档 status 的真问题(安全漏洞、未接线死代码该不该留、明确的 bug)。这些不要埋在审计 comment 里,也不要等用户点头——直接开一个独立 issue:贴切 label、assign 相关代码提交者、双向回链审计 issue,并在审计 comment 里一句话提"已 spin-off 到 #N"。开 issue 可逆可追溯,属"自动做"。
- 只为「清楚 / 已确认」的问题自动开:有坐实证据的 bug/漏洞、或 human 已批准要开的。仍悬而未决的疑问 / 方案 A-B-C 没定的,不要先开 issue——留在 comment 里给人拍板,定了再开。「定了」包含 ratchet 选定(★Idea/★Research 铁律 10:上一轮声明了默认方向、异议窗口已过而人未否决)——那已经是「已确认」,不是「没定」;本条禁的是方向从没被声明过就先开 issue,不是禁 ratchet。
- 开完必写原生边(写边纪律):body 首行
<!-- spinoff-of: #N --> 标记之外,同时
bun <plugin_root>/skills/issue-graph/scripts/link.ts --parent <N> --child <新号>(幂等)。
标记是 provenance,原生边才进确定性图计算(close-kick / rollup);不写边 = 这个
spin-off 关闭时永远不会 kick 回父 issue。
- 发现即修升级(对齐
pr-review ★ 发现即修):spin-off 里满足四门(证据坐实 · 修法无歧义且有界 · 非安全 · 无需方向拍板)的缺陷——尤其截图一眼可见的 UI 缺陷——开 issue 的同时当场修并开 fix PR(before/after 截图 + verification),issue 只作 tracking 回链,不留给「下一轮/其他 agent」。
- 优先级用受控词表(防 label 漂移,和 status 同理):
P0(紧急 / 安全)· P1 · P2 · P3(低优);安全类另加 security。缺这些 label 就建,但只用这套词,别再造 priority:high / urgent 等变体。
partial → 拆分剩余工作(status:partial 的主结论处理)
上面 Spin-off 讲的是 review 中附带撞到的独立问题。这一节讲不同的场景:当审计的主结论就是 partial(主体已落地、剩几个有界子任务没做),正确动作是把剩余工作分解成独立、无依赖、自足的实现 issue——别只在 comment 里列 gap 等人。
触发(证据坐实即自动拆,不问): gap 有 path:line 坐实确属未完成(如「grep this.emit providers/iot/frigate/ → 0 命中」),就自动拆。仍推测性 / 方案 A-B-C 没定的 gap 不拆,留 comment 给人拍板,定了再拆(和 Spin-off 同一条原则,「定了」同样包含 ratchet 选定)。
拆分纪律:
- 先分清「未完成的任务」 vs 「已完成但文档漂移」——只拆前者。
- 未完成的功能任务(代码确实没写)→ 拆成 feature spin-off。
- 已完成但文档没回头更新(测试计数过时、checkbox 没勾、decisions「待定」其实已决)→ 这是本审计自身的 resolve(由人签名 PR 修文档),不拆 issue,否则制造噪音。在审计 comment 里明说这几项留给 resolve。
- 颗粒度:独立可完成、无步骤依赖。 一个能被一个人独立做完、不依赖另一个的单元 = 一个 issue(如不同 provider / 不同 API 各一个)。绝不拆出「先做 A 才能做 B」的链式 issue。
- feature spin-off ≠ doc-audit:不挂
doc-audit label、不挂审计 milestone(这是实现任务不是文档审计);用 feature + 优先级(受控词表)。标题用实现口吻,如 [frigate] emit events into AFS EventBus。
- 每个 spin-off 必须自足(让只看 issue 的 agent 就能开工),固定配方:
- 目标:一句话 + 现状证据(
grep/path:line 证明缺什么)。
- 背景:一句话点明所属系统。
- 参考实现:已落地的同类范式
path:line(照抄即可),含关键签名 / 约定。
- 具体任务 + 命名/路径约定(对齐范式)。
- 验收标准(可勾选;含具体测试命令 + 要贴 pass/fail)。
- Optional research:回引原审计 issue #N + 相关 spec——标明是可选研究,不是必读前置。
- 双向回链 + 原生边:spin-off body 首行
<!-- spinoff-of: #N ... --> + Optional research 引 #N;原 issue 落一条 comment 列出拆出的 #X/#Y(表格:范围 + 独立性)+ 剩余 resolve 动作。每个拆出的 spin-off 同时 link.ts --parent <N> --child <#X> 写原生边(写边纪律,close-kick/rollup 依赖它)。
- 拆完立即摘掉
status:partial,换成残留真实状态(否则误导 human review)。 status:partial 是**「待分诊」信号**;path:line 坐实的 gap 一旦全部 routed 到 tracking issue,它就会让 human 误判本 issue 还有未处理的实现缺口。摘 label / 换 label 可逆 → 自动做:
- 本 issue 还有残留(典型:文档漂移——「已完成但文档没更新」)→ 换
status:drifted(open;resolve 按 status 表分流:planning/intent → historical 归档,docs/ → 修文档转 current;均由人签名 PR 落地 → close)。
- 完全无残留(gap 全 track + 无漂移)→ 换
status:current(或无 status)+ 保留 needs-human-confirm,作「审计完成,待人最终 close」信号。
- 拆分≠完成,但「本 issue 的 partial 工作已分诊完毕」= 完成——区别在于:剩余实现工作的家已搬到 spin-off,本 issue 只剩 doc resolve(或无)。
- 仍绝不自动 close / 改 frontmatter(那是人的不可逆动作);最终 resolve(写 frontmatter + 修 doc + close)由人签名 PR。label 归 AI(可逆)、frontmatter 归人(签名)。
How It Works(冷启动首轮)
┌────────────────────────────────────────────────────────────┐
│ 0. 读 thread,判轮次。后续轮 → 走上面"轮次感知",别全量重跑 │
│ │
│ 1. 读 issue 全貌(body + 全部 comments,含 human 意见) │
│ │
│ 2. 读被处理文档 + 引用的 spec/design / 对标范式 │
│ │
│ 3. ★ 对照已落地实现/代码/intent(最关键) │
│ 逐条声明 → grep/read 定位 `path:line`,或标 NOT FOUND │
│ │
│ 4. ★ 真跑测试(doc-audit 必做) │
│ 找到相关测试 → 跑 → 记录确切命令 + pass/fail │
│ │
│ 5. 出结论:逐条验证表 + 测试结果 + gap + 推荐 status,带证据 │
│ │
│ 5.5 能给安全默认就别升级(needs-human-confirm 硬前置) │
│ 5.7 沉默闸:agent 自发 + 无动作无新信息 → 本条不发,只记账 │
│ │
│ 6. 落 comment(中文),挂 status(+ 真分叉才挂 │
│ needs-human-confirm);不 close、不删文件、不改 frontmatter│
└────────────────────────────────────────────────────────────┘
Implementation Instructions
Step 0 — acquire 并发锁 + 判轮次 + 读 KB 热启动(先做,决定省不省)
最先 acquire 并发锁(见「★ 并发锁」):已被新鲜 agent:processing 持有 → SKIP 退出;否则加锁(--dry-run 不加)。并行 issue-sweep 的主控只分配 slot、不替 worker 预加锁;worker 到这里自行即时 acquire。再读共享 KB(gh issue view <kb_issue> 的 body)拿 repo 拓扑热启动,别从零探索。再 gh issue view <n> --comments:有既往 AI 结论 + human 意见 → 走「轮次感知」热启动路径,跳过下面会重复的全量步骤,只做 human 指定的下一步;否则走冷启动 Step 1–6(冷启动也按价值分档)。收尾:普通单 issue 调用把本轮新学到的拓扑事实 append/修正进 KB body;作为并行 issue-sweep worker 时不直接改 KB body,把结构化 KB delta 返回主控统一折叠。两种模式都由本 worker release 锁(Step 7)。
claim 后、任何实现/worktree 写入前必须检查开放 PR 路径重叠。 当本轮将进入实现时,
先从已核验的执行计划形成结构化 allowedPaths(repo-relative file/directory prefixes;不得从
issue 标题或自然语言猜),再运行:
bun <plugin_root>/scripts/check-pr-path-overlap.ts --run-args '{"allowedPaths":["<prefix>"]}'
目录 prefix 包含具体文件,所以 scripts/ 与 PR 的 scripts/foo.ts 是 overlap。overlap
必须在开工前报告 PR 号和具体文件,再由人/既有策略决定是否继续;clean 才表示确实查过且
无重叠;unavailable(paths 缺失/为空、gh/网络/auth/数据不可读)必须停止实现并显式回报,
不得当成 clean。comment-only 的 review 无 repo write,不伪造 allowedPaths,也不得声称已做
路径重叠检查。
Step 1 — 读 issue 全貌
gh issue view <n> --json title,body,author,labels,state,milestone + --comments。记下:文档路径、引用的 spec/范式、关键 commits、全部 human/AI 意见(human 意见优先级最高)。
Step 2 — 读文档 + 引用物
Read 被处理文档全文 + 它引用的 spec/design / 声称对齐的范式(如 docs/architecture/did-space.md)。
Step 3 — ★ 对照已落地实现/代码/intent
这是把"读起来对"和"其实已落地 / 方向反了 / 接口面漂了"区分开的关键。 不要只在文档间比对——查真实代码:
find . -path ./node_modules -prune -o -iname "*<topic>*" -print
grep -rniE "<关键路径或符号>" -l . | grep -vi node_modules
ls intent/<topic>/ ; sed -n '1,80p' intent/<topic>/INTENT.md
逐条声明 → 定位 path:line 或标 NOT FOUND。注意:历史文档常见 TASK.yaml 标 done 但 INTENT.md/plan.md 没回头更新 → status frontmatter 普遍不可信,必须对照代码重验,绝不信 status。
Step 4 — ★ 真跑测试(doc-audit / 验收点名的验证)
找到相关测试(pnpm --filter <pkg> test / bun test <path>),真的跑,把确切命令 + 真实 pass/fail 计数记进结论。
上面的 targeted bun test <path> 是为坐实某一条 doc-audit claim(只想要那一个测试的输出当证据)——保持轻量,别为一条 claim 跑全量门控。下面这套只在 issue 是 feature/task、验收标准或 human 点名了验证手段时适用。
当验收 / human 点名了验证——「本环境跑不动」是要被证明的结论,不是预设借口。 用仓库自己的 blessed skill,别自己手搓命令再手填数字:
- 结构性 PR 门控(build / lint / types / tests / architecture)走
/agentloop:verification。 跑 <verification_entry>,数字由脚本测出、不手填。不要自己 pnpm build / bun test 再手写「759 pass」——那正是手搓命令 + 手填计数的反模式,也是 /agentloop:verification 要消灭的非确定性。见 verification skill + CLAUDE.md「Self-Verification」。
- 验收点名的集成 e2e(blocklet render / mount / serve)走
/e2e-verify(该仓库的 companion,见 repo-profile 的 Companion Skills;没有就 stub 或跳过该步)——先尝试再下结论。 它自己 pnpm build + boot 两个 runtime(dev_server_node + dev_server_edge,见 repo profile)——边缘侧 = <dev_server_edge> 起本地环境,不需要云账号、不碰线上环境;所以 edge-parity / runtime 类验证本地就能做,绝不判成「需要云端环境」而 defer——那是错的。别把「别猛测线上环境」当成「本地验不了」;<cli_binary> 缺失/陈旧就先跑 <cli_setup_command>(e2e-verify 自身也这么要求)。/agentloop:verification、/e2e-verify、<cli_setup_command> 你完全可以调用——没真跑过就写「需要 daemon / 本环境无法执行」= 失败,也不能拿 unit test 顶替点名的 e2e。
- 缺依赖 = 多一步 setup,不是「跑不动」。 原生插件没编译(如 better-sqlite3 →
npx node-gyp rebuild)、CLI 没 link、没 build —— 先把 setup 做掉再跑,别当环境限制。
- 真正的硬限制才算「跑不动」:沙箱根本没那条工具链(repo profile Deployment Environments 列出的平台工具链,arc 例:无 Xcode → Swift、无 Android SDK → Kotlin、无 Playwright MCP → e2e-verify 的 Tier B 真浏览器),且已实际撞墙。
dev_server_edge 不在此列——它是本地环境,永远不算「跑不动」。这时贴确切命令 + 确切报错,退而用能跑的那部分兜底(/agentloop:verification 脚本 / 别的 tier / 静态对照),并显式标注跳过了哪一层(如 Tier B skipped/no-playwright)。
- 绝不假装跑过、不手填数字。 没跑就说没跑;跑了就贴 skill / 脚本的真实输出。
Step 5 — 出结论
- 逐条验证表:claim →
path:line 或 NOT FOUND。
- 测试结果:命令 + pass/fail。
- gap 列表 + phase 完成度(doc-audit)。
- 推荐 status(doc-audit 5 类之一)或 分级发现(doc-review:🔴 回归/方向错 · 🟡 真增量 · 🟢 已落地复述 · ⚪ 可删)。
- reframe(如适用):文档整体站错层/重开已结的题时,直接说"这一轮真正该产出什么"。
- 价值在独立发现,不在复述 human。
Step 5.5 — needs-human-confirm 硬前置(issue #1860)
打 needs-human-confirm 标之前先问一遍:我能不能说出一个安全默认动作? 能 → 禁止升级,当场按 ratchet(默认放行,出问题再收紧,同 pr-review Step 5.5)执行该动作并留 trace;不能,才是真判断题,才配打 needs-human-confirm 走 Step 6 的结构化拍板块。这条硬前置在打标动作之前过,不是打完标再补。
★ Step 5.7 — 沉默闸:没有状态变化就不要发言(硬前置,在 Step 6 之前过)
发 comment 之前先答一道判断题:这一轮我让世界发生了什么变化? 三选一,只有前两类配发 comment:
| 本轮产出 |
发不发 |
形态 |
| 动作——开了 PR / 关了 issue / 改了 label / 提了 spin-off / 推进了一个 phase |
发 |
说做了什么,附产物链接 |
| 新信息——上一条 agent comment 里没有的发现、结论翻转、新证据、新缺口、真需要人拍板的分叉 |
发 |
说新在哪 |
| 以上都不是——核验了一遍,结论与既有 thread 一致,没有新动作也没有新信息 |
不发(仅限 agent 自发路径,见下「适用面」) |
零 outward 写,只写进 run report |
第三类的典型措辞就是它自己的判据——你正准备写下这些句子中的任何一句,就说明该闭嘴:
复核确认:现状与描述一致 / 结论成立,无需改动
premise 复核:与当前 main 一致
状态跟踪:三个子 issue 现状如下(与上一轮相同)
本轮不新开动作 / 本轮无进展 / 继续等待
确认收到 / 已阅 / 同意上述判断
为什么这是硬闸,不是风格偏好: 一条「我看过了,没变」的 comment 对读它的人是净负担——它把 issue 顶到 timeline 最前面、发一次通知、占一屏,换来的信息量是零。更糟的是它有自激回路:sweep 的 round-awareness 判据是「最后一条是未回应的人类评论」,人一回话就触发下一轮 agent 回话;多台机器覆盖同一个 repo 时,就变成两个 agent 在同一条 issue 下轮流附和「这个想法对,我们应该这么做」而没有人动手。实测(arc,2026-08-13→20 一周):261 条 agent 评论 : 21 个 PR ≈ 12:1,其中约一半是本表第三类。
沉默 ≠ 没干活。 本轮的核验结果写进 $AGENTLOOP_RUN_REPORT({"noop":true,"summary":"…"})——它是给机器看的记账面,不是给人看的通知面。「查过了没问题」属于记账面。
适用面:只管 agent 自发的复核,绝不管对人的应答(这条是机制性的,不是礼貌)
沉默闸只适用于 agent 自己发起的处理路径:--autofix-green 扫描、Step 0.5 的 graph-scan / rollup 候选、状态跟踪、定期复核。
人类输入触发的路径必须回应,哪怕答案是「没变」。 理由不是礼貌,是它会造成每轮重复核验的死循环:
issue-sweep Step 2 的判据是「最后一条是未回应的人类评论」,而「已回应」的唯一证据就是那条带
sweep-trace 的 agent comment。
agent 对人类评论保持沉默 = thread 里永远没有那条 trace = 下一轮 sweep 认定它仍未处理 = 重新读、重新核验、重新判定沉默——每轮都花全额的钱,一条 comment 都不产出。 那比刷屏更糟:刷屏至少人看得见。
所以判据要两问连读,顺序不能反:
- 这一轮是谁触发的? 人类输入触发 → 必须发(内容按下面第 2 问约束),跳过沉默闸。
- (仅 agent 自发时)有动作或新信息吗? 没有 → 沉默。
边界(在适用面之内)
- 结论从上一轮翻转 → 必须发(哪怕方向是「上次说能做,这次发现不能」)。翻转就是新信息。
- 要更新既有结论 → 原地编辑那一条(
--edit-last),不是新发一条也不是不发。
- 人类触发时「必须发」约束的是发不发,不是发什么。 「复核确认,现状不变」依然不是合法内容——回应人类的正确形态是答他的具体问题 + 一条行动声明(★Idea/★Research 铁律 10 的 ratchet 格式),而不是复述现状。#4384 那类 1400 字分析停在「仍需拍板」,归铁律 10 管,不归本闸管;本闸管的是 agent 自己跑去把一条没人问的 issue 重新核验一遍然后宣布「没变」。 两条规则分工不重叠。
Step 6 — 落 comment(产物归宿)
用 comment_language 指定的正文语言写(arc 默认:中文),顶部标 AI 身份与读取/运行范围:
> 🤖 AI Agent Audit @ <hostname> · runner:<runner> · skills@<hash>[ · engine:<kind>[/<model>]]。读取:<文档+代码+测试>。运行:<测试命令>。每条发现附可复现证据。
整行 header 必须由单点脚本生成(<agent_identity_script>;环境/归属/skills/engine 四维溯源,不能用日期、占位符或手拼代替——尤其别再手写死 "Claude Code()",脚本按 ARC_AGENT_ENGINE/ARC_AGENT_MODEL 自动带出真实 engine,Codex 下跑手写死会错误自称 Claude),行尾追加读取/运行范围:
bash <agent_identity_script> --heade
…(truncated)
1---2name: issue-review3description: Process one GitHub issue end-to-end — read the issue + referenced repo docs/code + existing comments, verify against the landed implementation/intent, and post evidence-backed findings as a comment on the issue. Covers doc-review, doc-audit, system-audit, research, and idea issue types. Use when handling a single issue (issue-sweep calls this per issue).4---56# Issue Review — AI Agent Review / Audit for Doc-from-Issue78> **Repo profile — read `.claude/repo-profile.md` first.** This skill is repo-agnostic;9> **arc is the reference implementation.** Use the profile's `repo_slug`, `verification_entry`,10> `kb_issue`, `plugin_root` (where issue-graph's scripts live), and toolchain wherever this doc shows an arc default. Arc's own provenance11> for the lessons below is not inlined here (fuller case narratives, where they exist, are under `.claude/case-law/`).1213把一篇 issue 处理到位:读 issue + 引用的 repo 文档/代码 + 已有 comments + **对照已落地的实现/代码/intent**,产出**带证据**的发现,作为 comment 落回 issue(而不是埋在某次对话里)。覆盖五类:1415- **Doc-review**:人起源的**新设计**在 issue 里被讨论/评审(找漂移、独立发现、reframe)。轻量、讨论导向,产出 = 评审 comment + 拆分建议。16- **Doc-audit**:repo 里的**存量老文档**被逐篇审计(对照代码重验、跑测试、给 5 类结论)。**有界**单元,按价值分档投入。17- **System-audit(comprehensive code audit)**:issue 要求对一个**子系统 / 跨平台 parity / runtime 本身**做全面代码审计(如「Swift/Kotlin 实现是否落后于 Node/CF 参考」)。**无界**任务,**完整执行是契约**——见下「★ System-audit」。18- **Research(研究类)**:issue 要求**调研一个外部系统/技术与本系统的结合点**(如「研究 perkeep 和 did space 的结合点」)。**调研这一轮只产出 comment,不改 repo 代码**;下一轮按 ratchet 转执行管道——见下「★ Research」(铁律 1 与铁律 10)。19- **Idea(想法类)**:issue 是一个**内部提案/想法**(如「提供一个 DID Space + MCP endpoint 给 loop 里的 agent」)——可能可行、可能不可行、可能太模糊、可能与现有设计矛盾。**首轮是 clarify,不是执行**;首轮产出 = 评估 comment + 澄清问题 + 行动声明,**首轮不改 repo 代码、不开 spin-off**;**第二轮起按 ratchet 开工**——见下「★ Idea」(铁律 2 与铁律 10)。2021五类共用同一台引擎(读 → 对照现实 → 带证据落 comment),但**投入档位和产出形态不同**:doc-review 轻、doc-audit 按价值分档、**system-audit 必须全量**、research/idea 深调但**首轮**只落 comment(下面「省 token」那套**不适用于 system-audit 和 research/idea 的调研深度**)。**research/idea 的「只落 comment」是首轮限定,不是永久状态**——两者的铁律 10 都要求第二轮起转成动作,否则就是原地打转。2223> **怎么判类型**:issue 锚定**单篇文档** = doc-review / doc-audit;issue 说「comprehensive audit」「review 整个 runtime / 跨平台是否一致」「需要完整 test run」「发现 gap/bug 开 issue」= **system-audit**;标题带 `[research]` / 正文是「研究一下 X 和我们的 Y」「调研 X 是否适合我们」= **research**;标题带 `idea:` / 正文自称「这是个 idea,首先需要分析可行性和价值」/ 是一段**提案性质**的构想(常附 Slack/讨论原文,无验收标准、无明确 spec)= **idea**。拿不准 audit 类就按 system-audit 的高标准做(宁可多投入,不可粗略);**拿不准「指令还是想法」就按 idea 处理**(先 clarify 的代价远低于把模糊想法当指令执行错方向)。2425> **输出语言与写作规范(遵循 `comment_language`,信雅达)。** 所有面向团队的产出——issue comment、spin-off issue 标题与正文、**PR 描述正文**、评估/验证报告——一律用 repo profile 的 `comment_language` 指定的正文语言(arc 默认:中文,团队阅读语言);代码标识符、路径、命令、`path:line`、测试输出**保持原样**(不翻译代码)。**PR 与 commit 标题遵循 `comment_language` 的标题惯例**——完整 Conventional Commits(`type(scope): description`,arc 默认标题全英文,冒号后的描述也用英文,不得混用);issue 标题(含 spin-off)随正文语言(arc 默认:中文)。**追求信雅达,不堆砌**:内容太多本身就是阅读负担——先给一句话结论,再给最少但足够的证据,不为显得全面而铺陈;每条断言配证据(文档 / 代码 `path:line` / 真实测试输出,**UI 相关必附截图**);长日志折叠进 `<details>`,不平铺刷屏。2627## Usage2829```30/agentloop:issue-review <issue-number-or-url> [--dry-run]31```3233- `<issue-number-or-url>` — 要处理的 GitHub issue(用 `gh` 读取)34- `--dry-run`(旧名 `--no-post` 仍兼容)— 只产出给用户看,**不**发/改 comment、**不**自动开 spin-off issue、不动 label、**不加锁**(用于人想先预览)。语义见插件 README 的 **Dry-run contract**。3536### Examples3738```39/agentloop:issue-review 115 # doc-review:评审一篇新设计40/agentloop:issue-review 120 # doc-audit:审计一篇存量老文档41/agentloop:issue-review 756 # idea:先 clarify + open 评估一个提案42/agentloop:issue-review 120 --dry-run43```4445## When to Use4647- 一个 issue 在讨论/评审一篇 repo 内文档(`planning/`、`docs/`、`intent/`),需要**有据可查**的 AI 处理。48- 已有人类 reviewer 留意见,想要一个**独立的、能发现人类没提到的问题**的视角。49- 你在搭"自动处理 issue 的 agent loop",需要一个可复用、产物可追溯的动作。5051**不适用**:纯代码 PR 的 review(用 `/code-review` / `/review`);纯本地文档、不走 issue 的(用 `/agentloop:design-review <path>`)。5253## ★ 并发锁(每次 run 先 acquire,收尾必 release)5455多个 actor 会同时碰同一个 issue:定时 `issue-sweep`(cron)、多人本地手工 `/agentloop:issue-review`、本地 agent。不协调就**重复读+核验+跑测试+重复评论**(白烧 token),严重时重复开 PR。两个 label 各管一件事:5657| label | 含义 | 谁加/摘 | 谁尊重 |58|---|---|---|---|59| **`agent:hold`** | **人类保留 = 终态冻结**——"没我反馈别做不可逆动作(close/merge)",**不是"别理它"**(**issue/PR 通用**) | **只人加、只人摘**;agent 永不自动摘。**唯一例外(arc#2914)**:本 skill 产出「建议关闭」类结论清单时,**自动加**给清单点名的 issue(见下 ★「建议关闭」类结论清单)——**摘除仍然只人**。 | **`issue-sweep` / `pr-sweep` 冻结终态动作**(永不 close/去重关闭/合并),但**人类新评论/新 commit 照常触发 review + 响应**(人的反馈是最高优先级输入);无新输入才跳过。**`issue-review` / `pr-review` 显式手工调用只提示不挡**(人点名就是要处理) |60| **`agent:processing`** | **处理中互斥锁**(advisory,带 TTL 30min) | agent 开工 acquire、收尾 release | 任何 run 见**新鲜**的锁就 **SKIP**;**过期**(上一个 runner 崩了)则抢锁重做 |6162关闭带 `agent:hold` / `needs-human-confirm` 的 issue,可执行闸是 hook `deny-guarded-issue-close.ts`(#5426);散文不是闸。6364> **跨 issue/PR 边界:** `agent:hold` 两边通用——「人类保留」是与对象类型无关的预约(GitHub label 仓库级共享),两侧语义一致:**冻结终态动作(close/merge),不冻结响应**——人类新评论照常处理,`pr-review` 显式调用只提示不挡(见各自 SKILL)。`agent:processing`(TTL 互斥锁)**只用于 issue**:PR 侧的并发去重由 `pr-sweep` 自己的确定性分支 `claude/issue-<N>` + 开 PR 前认领检查 + disposition label 承载,不复用这个锁。6566**定位要诚实:`agent:processing` 是 advisory(省重复工作),不是完美分布式锁**——本仓库人和 AI 同账号/可能同 token,label-add 幂等,两机同瞬起步有残留竞态。**真正的硬去重仍是 `issue-sweep` 已有的「确定性分支 `claude/issue-<N>` + 开 PR 前认领检查」**,这层不动、兜底。`agent:processing` 只是把撞车从"收尾才发现"提前到"开工就短路",省掉前面的读/核验/测试。6768**无分支兜底的终态动作(comment+close 类,如 ★父级 rollup)另有硬互斥:claim-comment fencing。** 分支碰撞兜不住它们,label 又无 CAS——用 [`issue-graph`](../issue-graph/SKILL.md) 的 `claim.ts`(comment id 全序裁决,先写后读、最早未过期 claim 赢):6970```bash71bun <plugin_root>/skills/issue-graph/scripts/claim.ts --issue <N> --action rollup # exit 0=赢/3=输(输了自删claim退出)72# …执行动作(动手前最后重读一次目标状态)…73bun <plugin_root>/skills/issue-graph/scripts/claim.ts --release <claimId> # 完成必调;崩溃靠TTL 30min兜底74```7576> **命名消歧**:本 skill 里 `in-progress` 这个**词**已是「多轮续做的 comment disposition」(轮次感知接力),所以互斥锁**另起名 `agent:processing`**,别复用 `in-progress`。7778**acquire(Step 0 最前,读 thread 之前):**7980```bash81N=<issue>; TTL_MIN=3082# 缺 label 自建(幂等,best-effort)83gh label create agent:hold --color D4C5F9 --description "人类保留:自动化别碰,只人摘" 2>/dev/null || true84gh label create agent:processing --color FBCA04 --description "处理中互斥锁(advisory,TTL 30min)" 2>/dev/null || true8586labels=$(gh issue view "$N" --json labels --jq '.labels[].name')87# agent:hold —— 人类保留:显式手工调用只提示(sweep 才真跳过)88grep -qx 'agent:hold' <<<"$labels" && echo "⚠️ #$N 带 agent:hold(人类保留);显式调用继续。"89# agent:processing —— 互斥锁:新鲜则 SKIP,过期则抢90if grep -qx 'agent:processing' <<<"$labels"; then91 since=$(gh api --paginate repos/{owner}/{repo}/issues/$N/timeline \92 --jq '[.[]|select(.event=="labeled" and .label.name=="agent:processing")]|last|.created_at')93 now=$(date -u +%s)94 then=$(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$since" +%s 2>/dev/null || date -u -d "$since" +%s)95 age_min=$(( (now - then) / 60 ))96 if [ "${age_min:-9999}" -lt "$TTL_MIN" ]; then97 echo "🔒 #$N 正被处理中(since $since, ${age_min}min<${TTL_MIN}) — SKIP"; exit 098 fi99 echo "♻️ #$N 锁已过期(${age_min}min) — 抢锁重做"100fi101gh issue edit "$N" --add-label agent:processing # 加锁102```103104**release(收尾,成功/失败都做):**105106```bash107gh issue edit "$N" --remove-label agent:processing108```109110- **`--dry-run` 不 acquire/不 release**(不做任何 outward 写);只在发现已上锁时打印一句提示。111- **★ 解读→执行的升级点 = 重新过 Step 0。** 会话以「帮我看看/解释一下」开场(dry-run 语义,不加锁)后,用户中途说「解决掉/实现它」——**升级为执行的那一刻必须先 acquire 锁再动手**,不能带着 dry-run 的无锁状态直接开工(实战教训:曾因此被并发 agent 重复实现)。112- **长任务续锁**:预计超过 TTL(30min)的执行(实现+验证+PR),每 ~20min 重新 `gh issue edit <n> --add-label agent:processing` 一次(label-add 幂等,timeline 会刷新 labeled 时间戳),否则锁中途过期照样被抢。113- **崩溃/被 kill 没 release** → 锁靠 TTL(30min)自动失效,下一个 run 抢锁重做,不会永久卡死。114- **手工想长期独占**某条:人**先打 `agent:hold`**(sweep 永久绕开),处理完人摘掉——比临时锁更强、更明确的预约。115116## ★ 轮次感知 + 省 token(每次调用先做这件事)117118**不要无脑全量重跑。** 一篇 issue 会被处理多轮;后续轮的成本应该远低于首轮。先读 thread(`gh issue view <n> --comments`,便宜),判断轮次:119120| 轮次 | 信号 | 该做什么 |121|---|---|---|122| **首轮(冷启动)** | 没有既往 AI review/audit comment | **先 triage 价值,按档投入**(见下):明显废弃的只轻确认;真活的才全量(对照代码 + 跑测试) |123| **后续轮(热启动)** | 已有 AI 结论 + human 意见 | **不重做**:读 thread,把既往证据当既成事实,按 human 意见走下一步 |124125**冷启动也要按价值分档,别一上来就 full build / 全测:**126127- **先廉价判类别**:读 frontmatter(`superseded` / `superseded_by` / `deprecated`)+ `ls`/`grep` 扫一眼对应代码在不在。**明显已废弃 / 不再有价值**的(显式 superseded、方案被取代、对应代码已移除)→ 只做**轻确认**:用 `grep`/`ls`/`git log` 坐实"代码确实没了 / 已被取代"即可下 `deprecated`,**不 build、不跑测试套件、不逐条 `path:line`**。128- **只有判断它「真活着」**(可能 drifted/partial/current、细节要紧)时,才上全量:逐条 `path:line` + 真跑测试。129- 一句话:**投入与文档的价值成正比。** 给一篇要删的死文档做全量审计,本身就是浪费。130131> ⚠️ **以上「按价值分档 / 轻确认 / 省 token」只约束 doc-review 和 doc-audit。System-audit 不走这套**——见下。132133## ★ System-audit(comprehensive code audit)——完整执行是契约134135当 issue 要求**全面代码审计**(子系统 / 跨平台 parity / runtime 本身),「省 token」让位于「不漏」。**粗略 = 失败。** 铁律:1361371. **不许轻确认、不许靠 frontmatter 下结论。** 每条 parity claim 必须 `path:line` 坐实(在 / 不在 / 漂移),两侧都查(参考实现面 vs 目标实现面)。1382. **必须真跑测试,缺测试就补。** issue 通常明说「要有完整 test run」——跑得动的全跑、记确切命令 + pass/fail;**跑不动要说清原因**(见 repo profile 的 **Deployment Environments** 列出的平台工具链缺口,arc 例:沙箱无 Xcode/Android SDK → Swift/Kotlin 测试 `describe.skip`/无法编译),并退而用**静态对照 + conformance 套件**兜底,**不能假装跑过**。**「跑不动」的判定纪律同 Step 4**:先真尝试 + 先补 setup(编译原生依赖、link CLI 不算环境限制),只有实际撞上硬工具链缺失才算,且贴确切报错——别预先开脱。1393. **先分解再审计。** 把大审计拆成**子系统单元**(core / aup / session / 各 provider …),逐元对照,别糊成一团。每元独立给证据。1404. **gap/bug/security 当场开 issue(合理颗粒度),不必等确认。** 一类 gap 一个 issue;bug、security 各自独立开(`security` + `P0`)。审计 comment 汇总矩阵 + 一句话指向各 spin-off。1415. **产出 = 现状矩阵(参考×目标,逐元 ✅/⚠️/❌ + 证据)+ 测试结果 + gap 清单 + 已开 issue 列表。** 这是「报告现状」的交付物,不是给一个 status label。142143### Model / 编排(System-audit)144145- **不要为省钱用弱模型做整体综合。** 主控(synthesis + 开 issue + 判 parity 真伪)用**强模型(Opus)**;**分解后的有界子元审计可以下放 Sonnet**(读 1 个子系统两侧代码 + 跑 1 个测试 + 给结构化发现),但**关键语义面**(core 语义、协议/校验、安全降级)留 Opus。146- **该并行就并行**:子系统之间相互独立,用 subagent 扇出(每个 agent 一个子系统,返回结构化 parity 发现),主控汇总。这既快又能各自深入——**比单线程顺序扫更完整,不是更省**。147- 一句话:**doc-audit 选 Sonnet 是因为它有界;system-audit 反过来——宁可 Opus + 扇出多 agent,把它做透。**148149### 跨 repo / reference×target 一致性审计(system-audit 的常见形态)150151很多 system-audit 是「**审 A 是否正确消费了 B 的抽象**」——如「下游 repo 是否 protocol-first 并正确复用上游核心抽象」「某平台实现是否落后于参照 runtime」(arc 例:「aside 是否 AFS-first + 用 ARC AUP」「Swift/Kotlin 实现是否落后于 Node/CF 参照」)。审计物在 target repo、参照实现在 reference repo,**两个 repo 都本地 checkout、路径不同**。纪律:1521531. **先定 reference 与 target,两侧都读。** reference = 权威抽象/协议真相源(`<reference-repo-path>`,arc 例:`platforms/swift`、`platforms/kotlin`、`providers/runtime/ui`、`packages/aup`、AFS core);target = 被审代码(`<target-repo-path>`,arc 例:aside `ios/` `android/` `.aup/`)。**每条 parity claim 两侧各给 `path:line`**:target 到底在「消费 reference 的抽象」还是「平行重造一套」。1542. **`gh` 全部带 `--repo <owner/repo>`。** 审计 issue、verdict comment、spin-off issue、label 全落在 **target 的 repo**(issue 所在处);reference repo **只读**,不在里面开 issue。跨 repo 时 `repos/{owner}/{repo}` 占位符会解析成当前 cwd 的 repo,**别依赖它**,显式写 `--repo`。1553. **核心透镜:「真用」vs「用不彻底」要分层,别二值判。** 常见形态是**壳复用、肉不复用**:renderer/接口是通用的 ✅,但喂给它的东西(UI tree / 数据)在各端**手搭/平行重写** ❌。精确结论(「是真 AUP renderer,但每屏在 native 手搭 AUPNode、不加载 canonical `.aup`,三套并行必然漂移」)远比「违反 AUP」有价值。**先肯定做对的部分,再精确定位违规在哪一层。**1564. **单一真相源(SSOT)判定是这类审计的核心产出。** 同一界面/能力有没有「一份 canonical 定义被各端 render/消费」,还是 N 份平行实现(JSON + Swift + Kotlin…)?列出**同名单元的重叠矩阵**坐实。1575. **跨 repo 根因回溯 + 分段修复。** target 的违规常**根因在 reference 的能力缺口**(如「热读绕过 AFS」根因是「ARC AFS 缺 reactive/watch API」)。spin-off 要写清**两段**:reference 侧补能力(可能需在 **reference repo** 另立 issue)+ target 侧改用。1586. **fix 需方向时,issue 框成「确认的 gap + 待定方向 A/B/C」,别预设。** 现状(违规)已坐实就开 tracking issue(system-audit 契约要求开),但把统一/修复方案作为**待人拍板的选项列出**,不替人选(呼应 spin-off 的「needs-decision 不预设」)。纯营销页/需人定性的(如 bespoke landing HTML)留 verdict comment,不自动开 issue。1597. **平台专属工具链测试大概率跑不动——诚实退档。** 具体平台见 repo profile 的 **Deployment Environments**(arc 例:Xcode(Swift)/gradle+Android SDK(Kotlin)在沙箱通常缺);先真尝试 + 先补 setup,撞硬阻塞就**贴确切命令+报错**(arc 例:`gradle.properties` 硬编码 JBR、composite build 期望的同级 repo 布局不符、缺 `compileSdk`),退回**静态对照 + 读测试源**坐实结构,**显式标注跳过哪层、绝不假装跑过**。结论基于代码结构的确定事实,不依赖测试通过。1608. **批量开 spin-off 后必须核对 title↔body↔label 对齐。** 循环里捕获 issue number 易错位(首个 create 漏号→整体偏移),后续 body 回填会打到**错误的 issue**。开完**逐个 dump body 首行比对 title**,发现错位立即 `gh issue edit` 修正 + 补建漏掉的。宁可多一步核对。161162### 共享 KB(热启动 repo 拓扑,免重复探索)163164有一个 **pinned 知识库 issue**(repo profile 的 `kb_issue`,arc 默认 label `doc-audit-kb`),body 是 repo 拓扑 hints(子系统在哪、测试命令、大迁移、meta 事实)。**每次 run 先读它热启动,末尾把新学到的 append 回去:**1651661. **开工前先读 KB body**(`gh issue view <kb_issue>`,**只读 body**——comment 是原始追加流,别全读)拿热启动事实——别再从零 grep "CLI 在哪 / 测试命令是什么 / 哪些大迁移"。1672. **hints 非真相**:信它**快速定位**,但**便宜复查**(代码会动)。读到错条目(如"X 在 `packages/cli`"但其实已迁)→ **编辑 KB body 改那行** + 留一条 comment 说改了什么。一条 stale 的 hint 比没有还坏。1683. **末尾 append**:本轮新发现的拓扑 / 命令 / 迁移 / meta 事实,加进 KB body 对应小节,带"最后确认 commit/日期"。1694. **范围**:KB 只放拓扑 / 命令 / 迁移 / meta;**不放**审计账本(账本 = `gh issue list --label doc-audit`)。1705. **并行批处理时**(暂未启用):agent 只**追加 comment**,由一个整理步骤折叠进 body,避免 body 写冲突;顺序审计时直接编辑 body。171172### Memory MCP(可选,当已配置时)173174如果运行环境的 MCP 工具列表包含 AFS 命名空间(如 `afs_read` / `afs_write` / `afs_search`,来自已连接的 ARC instance MCP 端点),在 Step 0 中增加两步:175176**热启动前先 recall(与读 KB 同时做,并行):**177```178afs_search /user/memory 关键词:<issue 相关术语 / 路径 / 子系统>179```180读到的内容(observations / patterns / principles)补充进热启动上下文——和 KB hint 同等地位:「快速定位,需代码便宜复查」。181182**处理完毕后 store(追加,不覆写已有条目):** 写入时机——本轮发现以下任一:183- **非显而易见的代码约束**(某函数在某场景不可用的原因、隐藏副作用、hook 执行顺序)184- **团队决策**(为什么选 A 不选 B、某字段命名的历史原因)185- **revert 理由**(某 PR 回退的真实原因,防止下次重蹈)186- **跨 issue 的规律**(同类 bug 反复出现的根因模式)187188写入三层(粒度由小到大):189- `observation`:具体事实 + `path:line`(最小粒度、最贴代码)190- `pattern`:跨多次观察归纳出的规律(「X 类 issue 根因通常是 Y」)191- `principle`:推断出的工作原则(「做 Z 前必须先检查 W」)192193路径:`afs_write /user/memory/<memory_namespace>/<namespace>/<id>`(`memory_namespace` 见 repo profile Agent Tooling,arc 默认 `arc-loop`);caller 身份自动隔离(不同 loop agent 互不干扰)。194195**未配置 MCP = 本节跳过**,skill 其余行为完全不变。196197**热启动三条硬规则(省 token 的闸):**1981991. **issue thread 是累积状态。** 既往已核验的证据(`path:line`、测试 pass/fail 数)默认**信任**,不重新推导——除非"文件变了"或"human 质疑了这一条"。2002. **不重 build、不重跑整套测试、不重读全部文档。** 只在「目标代码变了 / human 点名要重查」时,重跑**那一个**测试、重读**那一节**。2013. **判断"变没变"用便宜的命令**:`git log --oneline --since="<上条 comment 时间>" -- <unit 路径>`。没动过 → 既往证据成立,直接进下一步。202203**human comment 是后续轮的方向,但不是圣旨。** 它确认/否决某结论、提新事实(如"这协议其实是给反向注入用的")、指下一步——优先按它走,但**不盲从**:204205- human 没提到的真问题**不要因此丢掉**——该指出还指出(他可能没 cover 全)。206- human comment 是**疑问 / 不确定**(带"?"、"是不是"、"我不确定")时,当作**要回答的问题**,不是要执行的命令——给带证据的答复,必要时坦白你也不确定、列出选项让人定。207- **多条 comment / 来自不同人**时,逐一列出、**调和分歧**;别只听最后一条或最大声的那条。有冲突就摆出来让人拍板,不要自己悄悄选一个。208209后续轮的产出往往不是"再来一份完整 review",而是一个**针对性的下一步**(确认某结论 / 解某个 gap / 起草 crystal / 回答疑问)。210211## ★ Research(研究类 issue)——外部系统 × 本系统结合点调研212213issue 要求研究一个**外部项目/技术**(开源系统、协议、竞品)与**本系统**的结合点、可行性或借鉴价值。范式如 perkeep × did-space 的结合点调研。这是 deep research 的 repo 内变体:**最大区别是我们身在一个 repo 里(知识库或产品代码),所以能做代码级深度,而不是只读对方的宣传页。**214215**铁律(与其他各类的关键差异):**2162171. **调研这一轮绝不改本 repo 代码。** 产物 = 一条证据化研究 comment(+ label),不是 PR、不是文件。skill 改进等衍生工作是另一件事,不混在 research 交付里。**边界:这条约束的是「research 交付本身」**——铁律 9/10 把 issue 转进 feature 管道之后,它就不再按 research 处理,那一轮该开 PR 就开 PR(切到 feature 的纪律)。**不许拿本条当「永远不动手」的挡箭牌。**2182. **默认只留 comment + 外部资源链接,不下载保存。** 外部 repo clone 到 scratchpad 用完即弃。**仅当 issue 明确说要收集数据保存在 repo 里**时,才在 `research/<task-slug>/` 开专门目录收集值得保存的(仍走 PR,人签名)。2193. **两侧都必须代码级,不许只读 README。** 外部侧:shallow clone 到 scratchpad,读架构文档 + 关键源码包,结论带 repo 内相对路径(尽量带行号)+ 官方 doc 链接;我方侧:读本 repo 代码/intent/planning,结论带 `path:line`。**并行 fan-out 两个 subagent(一侧一个)**,主控综合——两侧独立取证,防止先入为主。2204. **外部项目健康度必查**:`git log` 最近 12 个月提交曲线、最近 release、核心作者近期是否活跃、license、`gh api repos/<owner>/<repo>` 的 pushed_at/stars。结合点结论强依赖对方活性(死项目和刚复活的项目结论完全不同),这常是**独立发现**的来源(如发现 perkeep 2025-10 复活、7 年来首个 release)。2215. **诚实优先,反「为用而用」。** issue 主人常自带警惕(「不能为用 X 而用」),研究结论必须敢说「这个方向不建议」;每个结合点标注真实受益方和前提条件。2226. **产物结构**(comment,中文):TL;DR 逐条直接回答 issue 提出的具体问题 → 两侧架构对照表(均代码坐实) → 冲突面 → 结合点**分档**(⭐ 推荐 / ◐ 待定或仅借鉴 / ✗ 不建议,每条给理由) → **行动声明收尾**(铁律 10 的 ratchet 格式:「下一轮我会做 X,除非你说不」,X 默认取 ⭐ 档) → 外部资源链接清单。**首轮不自动开 spin-off**(先给人一个廉价的纠错点),但**收尾不是选项菜单**——异议窗口过了就按声明执行。2237. **Label**:`research`;并发锁照常(`agent:processing`)。**`needs-human-confirm` 只在存在真分叉(互斥且不可逆)时才加**——见铁律 10;能给安全默认的一律不加。issue 保持 open。2248. **投入档位**:调研深度不省(两侧 subagent 各自全量),但**验证层不同**——research 不跑本 repo 测试套件(没有要验收的实现),证据 = 双侧源码引用 + 官方文档 + 项目活性数据。2259. **★ 自带明确终局目标的 issue,调研只是 phase 0,不许停在调研(#1947 反馈,2026-07-19)。**226 〔本条原标题是「纯调研才以 needs-human-confirm 收尾」——**已被铁律 10 取代**:现在纯调研也不227 以 needs-human-confirm 收尾,而是 ratchet 行动声明。本条只保留它真正管的那一档:自带终局目标的。〕228 issue 同时载有**明确终局目标**(「不可动摇的目标」「最终应该…」式表述)时,research 只是 phase 0:调研 comment 落地后**立即转 feature 管道**(拆 sub-issue 图 + 原生边 + 可测终局验收写进父 issue,能做即做),不得以「待拍板选项」冻结。**拍板项必须是互斥分叉**——非互斥的工作项是依赖序,列成 phases 直接执行;可由工程判断决定的选择(API 形态、实现路线)由 agent 自决并在 PR/issue 记录 rationale;只有真正不确定的(不可逆分叉、审美、优先级)才需要人,且用「**推荐 + 默认执行的异议窗口**」(不同意在 issue 喊停)而不是阻塞等待。把工作分解包装成拍板项交给人 = 用拍板换工作量,禁止。(与 ★Idea 铁律 9 同源同判据——#1947/#1949 同日反馈;改其一必同步另一处及 issue-sweep 表对应两行。)22910. **★ 调研不得以「仍需拍板」收尾——收尾必须是 ratchet(2026-08-20 老冒反馈,镜像 ★Idea 铁律 10)。** 铁律 9 修的是「issue 自带明确目标」那一档;这条修的是**剩下的那档**——纯调研也不许无限期挂在「待人选方向」。研究 comment 的最后一段固定为行动声明:「**下一轮我会做 X**(具体到第一个 spin-off 的标题和第一步),**除非你在此之前说不**」;下一轮人若没有否决也没有改方向,**直接执行 X,不再重新调研**——再写一篇「更完整的调研」是本条明确禁止的动作。分档结论仍然照给,但 ⭐ 档就是默认选中的那个。完整措辞与三条边界见 ★Idea 铁律 10(两处同源,改其一必同步另一处及 issue-sweep 表对应两行)。230231**后续轮**:人选定方向(如「做 A」)后,按选项拆自足 feature issue(照「partial → 拆分剩余工作」的自足配方),或转入 `/agentloop:design-review` → `/agentloop:build-phases` 管道;**人什么都没说 → 按铁律 10 的 ratchet 执行 ⭐ 档,不是再调研一轮**;若人只是追问,原地编辑/追加 comment 回答(仍以行动声明收尾)。232233## ★ Idea(想法类 issue)——先 clarify,open 评估,不当指令234235issue 是一个**内部提案/想法**——作者自己都标注「可能可行,可能不可行,可能太模糊,也可能和现有的东西矛盾」。范式如「给 loop agent 提供 DID Space + MCP endpoint」这类提案。**这类 issue 最大的处理风险不是做得不深,而是做错性质:把 idea 当指令,直接开工实现一个方向未定、边界未清的东西。**236237**铁律(与其他四类的关键差异):**2382391. **不当指令,当提案。** 第一步是**理解复述**(把 idea 用自己的话讲一遍,分解成可独立评估的价值主张),而不是拆任务。复述放 comment 最前——它给人一个廉价的纠错点(「你理解错了」比「你做错了」便宜一百倍)。2402. **首轮**绝不改 repo 代码、不开 PR、不开 spin-off——方向没定之前开 issue/写码都是预设。产物 = 一条证据化评估 comment + label。**但这条只管首轮,而且首轮只有一次。** 见铁律 10:第二轮起,除非人明确否决,评估必须转成动作。2413. **Open 评估,三个方向都真查:** ① **可行且有价值**——对照代码找「地基已有多少」(常见惊喜:构件早已存在,idea 只缺接线);② **不可行 / 价值不明**——缺口带 `path:line` 坐实,不糊「应该可以」;③ **与现有设计矛盾**——点名矛盾对象(哪个机制/纪律/在途设计),把张力摆出来而不是悄悄选边。**每条断言 `path:line` 坐实**,grounding 纪律与审计同级。2424. **诚实优先,敢泼冷水。** idea 作者(常是 founder/架构师)要的是可行性分析,不是附和。「这半个价值主张有实打实的工程量缺口」比「好主意」有价值;同时**先肯定确实成立的部分**再指缺口(同 system-audit 的分层判定)。2435. **信息不足 → 列具体澄清问题,请人下一轮补,不硬编方案。** 问题要**具体到能拍板**(「作用域是共享还是 per-repo?」「认证接受 owner token 共享吗?」),不是开放式的「你觉得呢」。每个问题说明**为什么它 block 后续**(影响什么设计分叉)。issue 保持 open。**但「多轮迭代」指的是问题逐轮变少、方案逐轮收窄,不是每轮重出一份评估**——每个问题都必须同时给出「没人答时按哪个默认走」(铁律 10),**没有默认可给的才算真 block**;有默认的问题不阻塞开工。2446. **产物结构**(comment,中文):理解复述(价值主张分解)→ 现状对照表(地基已有什么,`path:line`)→ 真实缺口(要落地必须补的,带证据)→ 张力/矛盾检查(与现有机制、与在途设计、拓扑分叉)→ 价值评估分档(⭐/◐/✗,按主张分别给,不整体二值判)→ 需人补充的 context(具体澄清问题,**每条附「没人答时我按哪个默认走」**)→ **行动声明收尾**(铁律 10 的 ratchet 格式:「下一轮我会做 X,除非你说不」)。**不以选项菜单 / 「仍需拍板」结尾。**2457. **Label**:`idea`;并发锁照常(`agent:processing`)。**`needs-human-confirm` 只在存在真分叉(互斥且不可逆)时才加**——见铁律 10;能给安全默认的一律不加。issue 保持 open。2468. **投入档位**:评估深度不省(对照代码逐主张坐实),但**验证层不同**——idea 不跑测试套件(没有要验收的实现),证据 = 本 repo 源码引用 + 既有设计文档 + 相关讨论原文。2479. **需求已明确的 idea → 不出拍板菜单(Robert 纠错,#1949/#1947,2026-07-19)。** 作者已把目标说清、只是路径/细节未定时,评估不得把「可给安全默认的决策」做成选择题——那是变相让人替 AI 砍 scope,且人选完后 agent 容易「解决几个具体问题就以为全部完成」。正确形态:①凡能给**安全默认**的决策直接选定并标注「按此推进,不同意请指出」(ratchet,同 Step 5.5);②产出必须附**终局验收清单**(对齐 issue 原始目标、逐项可验证)——它是父 issue close 的唯一条件(rollup 核对的就是它),「子 issue 全关 ≠ 完成」;③人确认方向后**立即全量分解**成自足 spin-off + 写边(此刻铁律 2 的「不开 spin-off」解除),分期是优先级顺序、不是删减;④只有真不确定项(资源级投入、不可逆动作、外部依赖时机)才留给人拍板,且不 block 其他 workstream。判据:拍板项之间若**不互斥**,那它们就不是拍板项,是依赖序——直接排进计划执行。(与 ★Research 铁律 9 同源同判据——#1947/#1949 同日反馈;改其一必同步另一处及 issue-sweep 表对应两行。)24824910. **★ 评估不得以「仍需拍板」收尾——收尾必须是 ratchet(2026-08-20 老冒反馈)。** 铁律 5 的「信息不足就列澄清问题」和铁律 2 的「首轮不开 spin-off」,在旧写法下(铁律 7 曾无条件挂 `needs-human-confirm` + 「issue 保持 open 等人拍板」)合起来给了 idea 一个**结构性的原地打转出口**:每一轮都能合法地产出一篇高质量分析然后停在「仍需拍板」,人再说一句,下一轮再分析一篇。实测这就是「两个 agent 互相附和、没有人去做」的来源。**本条与铁律 2/5/7 的现行文字是配套改的**——修法是**把默认方向反过来**:250251 - **评估 comment 的最后一段不是问题清单,是行动声明。** 格式固定:252 「**下一轮我会做 X**(具体到第一个 spin-off 的标题和第一步动作),**除非你在此之前说不**。」253 仍然可以在上面列澄清问题——但它们是**优化输入**,不是**开工前置**;你必须同时给出254 「问题没人答时我按哪个默认走」。**给不出安全默认的,才是真拍板项**(同 Step 5.5 硬前置)。255 - **异议窗口过了就开工。** 第二轮起(评估 comment 已发、人没有明确否决也没有改方向),256 **不再重新评估**——直接按上一轮声明的 X 执行:拆自足 spin-off + 写原生边(此刻铁律 2257 的「不开 spin-off」解除)、能做即做、走 `/agentloop:design-review` →258 `/agentloop:build-phases`。**再写一篇「更完整的评估」是本条明确禁止的动作。**259 - **`needs-human-confirm` 只贴给真分叉。** 「这个方向对不对」不是分叉(给推荐 + 异议窗口);260 「A 和 B 互斥且都不可逆」才是。判据同铁律 9:**拍板项之间若不互斥,那它们就不是拍板项,261 是依赖序——直接排进计划执行。**262 - 唯一维持原地不动的情形:**人明确否决**(建议 close,人来 close),或**人提出了新的、263 与上一轮不同的问题**(答它,然后仍以 ratchet 收尾)。264265**与 Research 的区别**:research 调研**外部系统**与本系统的结合点(双侧 subagent、查对方项目活性);idea 评估**内部提案**(单侧,但重点在「对照现有架构找已有/缺口/矛盾」+「把模糊处变成可拍板的问题」)。一个 idea 可能内嵌 research 需求(「用 X 来做这个」)——那就在评估里嵌套 research 那套双侧纪律。266267**后续轮**:人答了澄清问题/拍了方向 → 按选定项拆自足 feature issue,或转 `/agentloop:design-review` 出设计;**人什么都没说 → 按铁律 10 的 ratchet 开工,不是再评估一轮**;人否决 → 建议 close(人来 close,agent 不动手);人追问 → 原地编辑/追加 comment 回答(仍以行动声明收尾)。**多轮之后 idea 常收敛成 feature/design issue——那一刻起它就不再按 idea 处理**,切到对应类型的纪律。268269## ★ 父级 rollup(孩子全关的父 issue 收尾)——授权的自动 close 例外270271触发:`issue-sweep` Step 0.5 的 `graph-scan` 报出 `rollupCandidates`(open 父 issue272∧ 原生 sub-issue 全部已关),或人点名。**这是本 skill「绝不自动 close」铁律的唯一273显式例外,需 repo owner 授权**——修的是「孩子274全做完、父 issue 敞着等人 bump」的存量病。close 可逆(可 reopen),风险等级是噪音不是损坏。275276**流程(顺序硬性):**2772781. **幂等检查**:issue 已关 → 结束;已有 `<!-- rollup-done -->` marker comment → 结束。2792. **fencing 抢锁**:`claim.ts --issue <N> --action rollup`(见 ★并发锁)。输了 → 结束280 (另一台机器在做)。`agent:hold` 的父 issue **不做 rollup close**(hold = 人类保留281 终态,见并发锁表),只写综合 comment 不关。2823. **核对验收**:读父 issue 的验收标准/问题清单/body 意图,逐条对应到子 issue/PR 的283 落地证据(`path:line`、PR 链接、测试输出)。**动手前最后重读一次 issue state**284 (已关/有新人类 comment → 放弃动作,先按新输入走)。285 **★ 大块 issue 的完整测试闸(Robert 拍板 2026-07-20,源 #1947)**:多 phase /286 带 sub-issue 图 / 带终局验收的 feature epic,**close 前必须有真实 surface 上的287 完整端到端场景测试**——不是各 PR 单测绿,而是在真实目标环境(真机 / 真浏览器 /288 live daemon)设计多类型场景(正向 + 诚实性负样本 + 边界),逐 case 跑、每 case 附289 截图/输出证据,报告以稳定编号 checkbox(如 FM-01…)post 到 issue 逐项核销;290 **测试计划本身先 post 并标注为关闭验收条款**。缺这层 → 不 close,先补测试291 (这是 rollup 的默认组成,不等人提醒)。失败项如实记录:接线 bug → spin-off;292 平台/模型局限 → 注明请人认可,不调宽判定凑绿。单 PR 小修不适用本闸。2934. **综合 comment**(中文,`> 🤖 AI Agent` 头 + `@ <hostname>`):逐条覆盖表 +294 每个子 issue 一句话结论 + 残留 gap(如有)。末尾带 `<!-- rollup-done -->` marker295 (幂等 key)。2965. **处置**:全覆盖 → `gh issue close <N> -r completed`;有残留 gap → 列出并**留开**297 (残留是有界任务就按「partial → 拆分」拆自足 spin-off 并写边)。research/idea 类298 父 issue 同样综合后 close——结论已在子 issue/comment 落地,父级只是收口。2996. **release claim**:`claim.ts --release <claimId>`;带 `agent:ready` 的同时摘掉300 (消费方处理完摘——close 的 producer 下轮也会清,留开的必须现在摘,否则队列视图301 一直显示"可干"误导人和其他 worker)。302303## ★「建议关闭」类结论清单 → 落地时立即挂 `agent:hold`(arc#2914)304305任何本 skill 产出的**结论性批量处置清单**——doc-audit 汇总、★父级 rollup 综合 comment、306一次性全量 backlog audit 等场景里,表格/列表形式列出**多个 issue**并给出「建议关闭」/307「建议合并」/「建议删除」这类**需要人工复核才能执行**的结论——**在这份清单落地308(post 到 issue body 或 comment)的同一时刻**,必须对清单里点名的**每一个** issue 打上309`agent:hold`:310311```bash312for n in <清单里点名的每个 issue 号>; do313 gh issue edit "$n" --add-label agent:hold314done315```316317(label 不存在则先按 ★并发锁 acquire 段落的 `gh label create agent:hold ... || true` 幂等创建。)318319**为什么不能只靠正文文字承诺(arc#1863 教训):** `#1863` 是一次一次性 138-issue 全量320backlog audit,body 末尾明确写「『建议关闭』一栏本次没有代关,等人扫一眼表格后批量关即321可」——这段自然语言承诺没有配套任何结构化信号。下一轮无人值守 sweep 把这段文字里点名的32212 个 issue 直接当成可执行指令关闭了,绕开了这里声明的人工确认闸(事后核对基本站得323住,但那是运气,不是设计——见 arc#2914)。`agent:hold` 是 `issue-sweep` Step 1「Then324drop the reserved/locked ones」已经尊重的既有确定性机制——**用它承载「等人复核」的承325诺,而不是指望下一轮 sweep 去解析 issue body 里的自然语言限定语**。这与 `issue-sweep`326Step 2 的对应规则互补:Step 2 保证即便某个被点名的 issue 意外漏挂 `agent:hold`,清单327本身也不会被当成指令消费——需要独立人工确认才行。328329**人复核完摘 label**:批准 → 人自己 close(或摘掉 `agent:hold` 后走正常 sweep 流程);330否决 → 摘掉 `agent:hold` 并留一条说明。**agent 永不自动摘这个 label**(同上 ★并发锁331表的通用规则:`agent:hold` 只人加只人摘,本节是唯一的"自动加"例外,且不含"自动摘")。332333## Doc-from-Issue 生命周期(这个 skill 所处的流程)334335人起源的文档**从 issue 开始**,讨论到可落盘,再像代码一样提交进 repo。两层:336337| 层 | 角色 | 性质 |338|---|---|---|339| **Issue = raw / 工作层** | 一切输入 + AI 铺开 + **AI review/audit(本 skill)** | 可变、可以脏、累积、AI 辅助;**永不进 repo** |340| **Repo = crystal / 结晶层** | 人逐字负责的极简文档,走 PR commit,回链 issue 作 provenance | 像代码一样;人对每个字负责 |341342**方向单向**:脏的往精炼走;精炼的不回流污染(要改 = 开新一轮)。**Provenance 是 append-only 链**:`doc → 本轮 issue → 上轮 issue → …`,closed issue 永久可达。343344### 人 / AI 的边界(按"后果可逆性"划,不按"是不是 outward")345346agent 要**有判断力、自己动手**,不要事事请示。可逆的、可追溯的操作直接做;只有大动作 / 不可逆才停下来等人。347348- **自动做,不问**(有判断力地做):发/改 comment、打/调 label、指派 assignee、判定并标 `status`、维护"活的 crystal"草稿;以及**该单独开 issue 的就直接开**——review 中发现的、明显独立于本文档的问题(安全漏洞、未接线的死代码、明确的 bug),**自动开新 issue**(挂好 label/milestone/assignee + 双向回链),**不征求用户意见**。349- **需人确认(只有大动作 / 不可逆)**:删除内容或文件、搬目录、PR merge、**close issue**、改架构方向的拍板。这些挂 `needs-human-confirm` 等人——理由:这是后果的承担点,AI 没有后果。350- **铁律**:产出始终带证据;**绝不**自动 merge / close issue / 删文件 / 改文档 frontmatter。**close 的唯一显式例外 = ★父级 rollup**(孩子全关 + fencing 互斥 + 验收核对全覆盖,close 可逆)与 `issue-sweep` 的「PR merged 未自动关」清理。351352## Doc-audit 流程(审计存量老文档)353354存量 `intent/` `planning/` 的逐篇清理。**不搬目录**(搬目录会破坏 issue↔文档路径 key、断 git history),只用 frontmatter `status` 标记 + 回链 issue;唯一物理改动是 `deprecated` 类删文件。355356### 5 类 status 枚举(受控词表,替换历史上 30+ 种乱标)357358| `status:` | 含义 | issue 去向 |359|---|---|---|360| `planned` | 有价值,还没实现 | **open**(tracker;创建前先 dedup 现有 issue/roadmap) |361| `partial` | 实现了,但不完整(**「待分诊」信号**) | **open**;gap 有 `path:line` 坐实 → **自动拆成独立自足 spin-off** 后**摘掉本 label**、换残留状态(剩漂移→`drifted`;无残留→`current`+待人 close);仍推测/未定的 gap 留 comment 给人确认。见「partial → 拆分剩余工作」 |362| `drifted` | 实现了,但文档漂移(描述的接口面 ≠ shipped 面) | **按文档类别分流**(2026-07-17 Robert 拍板,#187 批): **`planning/`/`intent/` → 归档**,不修正文——ship 后它们是历史文物,真相源已转移到代码+living docs,修了必再漂(反例:#243 修一轮漂一轮)。归档 = 顶部打 historical tombstone banner(见下「historical 归档」),有价值的设计 rationale 先抽进 `docs/guides/`/README 再归档;tombstone PR merge 时 close issue。**`docs/` living guide → 修文档** → 转 `current` |363| `current` | 实现了,文档准确 | **closed** + 审计记录 |364| `deprecated` | 废弃 | **closed**;内容先存 issue → 人确认 → 单独 PR 删文件 |365366(在途新设计用 `draft`,不属审计 5 类。)367368### 命名 / 归类约定369370- **Milestone = 目录批次**:命名与归类跟随 repo profile 的 **Milestone Conventions**(arc 默认:`Doc Audit: intent/` / `Doc Audit: planning/` / `Doc Audit: docs/`),一个个清,防 issue 爆炸。371- **Label**:`doc-audit`(meta,全挂)+ `status:<x>`(本轮结论挂)+ `needs-human-confirm`(给了建议、待人确认 close/delete)。372- **标题**:`[<area>] <doc-name> — doc audit`,如 `[intent] session-protocol — doc audit`。373- **幂等 key**:issue body 首行 `<!-- doc-audit-key: <doc-path> -->`;创建前先 `gh issue list --search` 搜它防重复建。374- **Assignee(让对的人来 review)**:把 issue 指派给两类人——375 - **文档创建者**(创建 issue 时就能拿到):文档首次提交的作者。376 `sha=$(git log --reverse --format=%H -- <doc-path> | head -1); gh api repos/{owner}/{repo}/commits/$sha --jq .author.login`377 - **实现代码的提交者**(review 中定位到 `path:line` 后顺手拿):从实现文件的近期提交取、去重。378 `gh api "repos/{owner}/{repo}/commits?path=<impl-file>&per_page=5" --jq '.[].author.login'`379 - `gh issue edit <n> --add-assignee <login>`。**指派失败 / 非协作者就跳过并记一句,别 block。** 同一个人只指派一次。380381### 文档侧 frontmatter 契约(resolve 时由人签名的 PR 写入)382383```yaml384status: current # 受控词表,grep ^status: 一把筛385audit: "#<N>" # 回链审计 issue(issue body 反指文档路径,双向)386verified: 2026-06-24 # current 时记确认日期387```388389### historical 归档(drifted 的 planning/intent resolve 路径)390391对无 YAML frontmatter 的老文档,tombstone 是顶部 banner(可 grep `doc-status: historical` 一把筛):392393```markdown394<!-- doc-status: historical (archived <date>, doc-audit #N) -->395396> ⚠️ **Historical** — 实现期 planning/intent 文稿,已归档(doc-audit [#N](.../issues/N))。397> 内容以写作当时为准,**不再随代码更新**;与现行代码的已知漂移明细见上述 audit issue。398> 现状以代码与 living docs(`docs/`、各包 README)为准。399```400401主文档用全量 banner,同目录 sibling(tasks/plan/review)用一行简版指回主文档。**不删文件、不搬目录**——402tombstone 保住反向引用的链接(反例:#253 想删 context-builder,结果 2 处活跃文档链接指着它)。403漂移明细**不抄进文档**,留在 audit issue 里(单一真相源)。归档后该单元退出后续 doc-audit 扫描范围。404405### 生命周期406407`create(一篇=一 issue,挂 milestone+doc-key)` → `review(冷启动:对照代码+跑测试,见下)` → `human 给意见(comment)` → `resolve(热启动:按 human 意见起草修复/crystal)` → `人确认 → close`。408409### 批量建 issue(精简;review 时补全)410411存量批量 issue 化时,**create 步骤刻意精简、不深读**:每个 issue 只放 doc-key + 目录/主文档链接 + frontmatter status + 文档自己的 anchor 行 + 通用 audit 任务模板。目的只是让人**快速浏览、给初步判断**,不是当场分析。**深度 overview 留到真正 review 时补。**412413- **幂等**:create 前用 `doc-audit-key` 搜一遍,已存在就跳过——可重复跑、绝不重复建。这就是"哪些 doc 已 issue 化"的记录,不需要额外文件。414- **覆盖跟踪**:账本 = doc-audit issue 集合;覆盖率 = `(所有单元) − (已存在 doc-key)`;milestone 做可见聚合。415- **老式合集**(per-feature 约定前的扁平目录,如 `specs/`/`bugs/`/`*.legacy/`):**先 1 目录 = 1 issue 粗审**(整体是否 legacy),review 若发现需拆再拆 per-file。416- **审计阶段不必改 issue body**:结论 + 证据放 **verdict comment** 即可(body 保持精简,comment 紧随其下、足够清晰)。**仅在 resolve 阶段、或多轮后 body 已明显误导时,才(可选)补 body**——别为补 body 给每篇多烧 token。417418### 批量 review 编排(model / 限速 / 并发)419420几十~几百篇一起跑时,**skill 之外的编排层**有四条经验,务必守:4214221. **Model 选最合适的,别默认继承 Opus。** doc-audit 是**有界任务**(读 1 篇 + skill + KB + grep 代码 + 可能 1 个测试 + 归 5 类 + 写 comment)→ **用 Sonnet**;**不用 Opus、不用 1M context**(单 agent 上下文远不到 200k)。`needs-human-confirm` 兜底,Sonnet 偶尔偏差人会接住。**Opus 只按需留给少数难/有争议的篇**(如安全 spin-off 复核)单独重跑。成本差 ~5×。4232. **限速:GitHub「内容创建」是硬约束(≤500/h、≤80/min)。** 批量 POST 大头是 comment,所以:424 - **每 agent 只发 1 条 verdict comment**;425 - **大批量时 agent 不各自发 KB comment**(否则 POST 翻倍)——新拓扑事实写进 agent 返回行,**KB 由单点(主控)集中折叠**;426 - spin-off 仅在确有独立真问题时;427 - gh 遇 403 secondary limit → 退避重试(≤3 次),仍失败标 `RATE-LIMITED`、不整篇报错(可 resume 补);428 - 估算:N 篇 ≈ N 个 POST,确保 < 500/h;N 很大就分段/降并发拉长时间。4293. **并发 = 吞吐 × 限速的平衡。** ~10–14 并发 × 每 agent ~2–3min ≈ ~4–5 POST/min(~250–300/h),稳在限速下;别盲目拉高并发触发 80/min burst。4304. **KB body 单点编辑。** 并行 agent **只读 KB、不写 body**;新事实由主控在每段/每批后统一折叠(见「共享 KB」)。**仅交互式 session** 可用 Workflow 编排(批量跑应 resumable,失败/限速可续);**无人值守 routine 绝不 Workflow、绝不 AskUserQuestion**——由 [`issue-sweep` 的 bounded worker pool](../issue-sweep/SKILL.md) 使用无需确认的 agent fan-out;runtime 不支持时才串行 inline。待拍板问题照常落 comment。431432### Spin-off issue(自动开,不问)433434review/audit 中常会撞到**独立于本文档 status 的真问题**(安全漏洞、未接线死代码该不该留、明确的 bug)。这些**不要埋在审计 comment 里**,也**不要等用户点头**——**直接开一个独立 issue**:贴切 label、assign 相关代码提交者、双向回链审计 issue,并在审计 comment 里一句话提"已 spin-off 到 #N"。开 issue 可逆可追溯,属"自动做"。435436- **只为「清楚 / 已确认」的问题自动开**:有坐实证据的 bug/漏洞、或 human 已批准要开的。**仍悬而未决的疑问 / 方案 A-B-C 没定的,不要先开 issue**——留在 comment 里给人拍板,定了再开。**「定了」包含 ratchet 选定**(★Idea/★Research 铁律 10:上一轮声明了默认方向、异议窗口已过而人未否决)——那已经是「已确认」,不是「没定」;本条禁的是**方向从没被声明过**就先开 issue,不是禁 ratchet。437- **开完必写原生边(写边纪律)**:body 首行 `<!-- spinoff-of: #N -->` 标记之外,同时438 `bun <plugin_root>/skills/issue-graph/scripts/link.ts --parent <N> --child <新号>`(幂等)。439 标记是 provenance,**原生边才进确定性图计算**(close-kick / rollup);不写边 = 这个440 spin-off 关闭时永远不会 kick 回父 issue。441- **发现即修升级**(对齐 [`pr-review` ★ 发现即修](../pr-review/SKILL.md)):spin-off 里满足四门(证据坐实 · 修法无歧义且有界 · 非安全 · 无需方向拍板)的缺陷——尤其截图一眼可见的 UI 缺陷——**开 issue 的同时当场修并开 fix PR**(before/after 截图 + verification),issue 只作 tracking 回链,不留给「下一轮/其他 agent」。442- **优先级用受控词表**(防 label 漂移,和 status 同理):`P0`(紧急 / 安全)· `P1` · `P2` · `P3`(低优);安全类另加 `security`。缺这些 label 就建,但**只用这套词**,别再造 `priority:high` / `urgent` 等变体。443444### partial → 拆分剩余工作(status:partial 的主结论处理)445446上面 Spin-off 讲的是 review 中**附带撞到**的独立问题。**这一节讲不同的场景**:当审计的**主结论就是 `partial`**(主体已落地、剩几个有界子任务没做),正确动作是把**剩余工作分解成独立、无依赖、自足的实现 issue**——别只在 comment 里列 gap 等人。447448**触发(证据坐实即自动拆,不问):** gap 有 `path:line` 坐实确属未完成(如「`grep this.emit providers/iot/frigate/` → 0 命中」),就自动拆。**仍推测性 / 方案 A-B-C 没定的 gap 不拆**,留 comment 给人拍板,定了再拆(和 Spin-off 同一条原则,「定了」同样包含 ratchet 选定)。449450**拆分纪律:**4514521. **先分清「未完成的任务」 vs 「已完成但文档漂移」——只拆前者。**453 - **未完成的功能任务**(代码确实没写)→ 拆成 feature spin-off。454 - **已完成但文档没回头更新**(测试计数过时、checkbox 没勾、decisions「待定」其实已决)→ 这是**本审计自身的 resolve**(由人签名 PR 修文档),**不拆 issue**,否则制造噪音。在审计 comment 里明说这几项留给 resolve。4552. **颗粒度:独立可完成、无步骤依赖。** 一个能被一个人独立做完、不依赖另一个的单元 = 一个 issue(如不同 provider / 不同 API 各一个)。**绝不**拆出「先做 A 才能做 B」的链式 issue。4563. **feature spin-off ≠ doc-audit**:**不挂** `doc-audit` label、**不挂**审计 milestone(这是实现任务不是文档审计);用 `feature` + 优先级(受控词表)。标题用实现口吻,如 `[frigate] emit events into AFS EventBus`。4574. **每个 spin-off 必须自足**(让只看 issue 的 agent 就能开工),固定配方:458 - **目标**:一句话 + 现状证据(`grep`/`path:line` 证明缺什么)。459 - **背景**:一句话点明所属系统。460 - **参考实现**:已落地的同类范式 `path:line`(照抄即可),含关键签名 / 约定。461 - **具体任务** + **命名/路径约定**(对齐范式)。462 - **验收标准**(可勾选;含具体测试命令 + 要贴 pass/fail)。463 - **Optional research**:回引原审计 issue #N + 相关 spec——标明是**可选**研究,不是必读前置。4645. **双向回链 + 原生边**:spin-off body 首行 `<!-- spinoff-of: #N ... -->` + Optional research 引 #N;原 issue 落一条 comment 列出拆出的 #X/#Y(表格:范围 + 独立性)+ 剩余 resolve 动作。**每个拆出的 spin-off 同时 `link.ts --parent <N> --child <#X>` 写原生边**(写边纪律,close-kick/rollup 依赖它)。4656. **拆完立即摘掉 `status:partial`,换成残留真实状态(否则误导 human review)。** `status:partial` 是**「待分诊」信号**;`path:line` 坐实的 gap 一旦全部 routed 到 tracking issue,它就会让 human 误判本 issue 还有未处理的实现缺口。摘 label / 换 label 可逆 → **自动做**:466 - **本 issue 还有残留**(典型:文档漂移——「已完成但文档没更新」)→ 换 `status:drifted`(open;resolve 按 status 表分流:`planning`/`intent` → historical 归档,`docs/` → 修文档转 `current`;均由人签名 PR 落地 → close)。467 - **完全无残留**(gap 全 track + 无漂移)→ 换 `status:current`(或无 status)+ 保留 `needs-human-confirm`,作「审计完成,待人最终 close」信号。468 - **拆分≠完成,但「本 issue 的 partial 工作已分诊完毕」= 完成**——区别在于:剩余实现工作的家已搬到 spin-off,本 issue 只剩 doc resolve(或无)。469 - **仍绝不自动 close / 改 frontmatter**(那是人的不可逆动作);最终 resolve(写 frontmatter + 修 doc + close)由人签名 PR。label 归 AI(可逆)、frontmatter 归人(签名)。470471## How It Works(冷启动首轮)472473```474┌────────────────────────────────────────────────────────────┐475│ 0. 读 thread,判轮次。后续轮 → 走上面"轮次感知",别全量重跑 │476│ │477│ 1. 读 issue 全貌(body + 全部 comments,含 human 意见) │478│ │479│ 2. 读被处理文档 + 引用的 spec/design / 对标范式 │480│ │481│ 3. ★ 对照已落地实现/代码/intent(最关键) │482│ 逐条声明 → grep/read 定位 `path:line`,或标 NOT FOUND │483│ │484│ 4. ★ 真跑测试(doc-audit 必做) │485│ 找到相关测试 → 跑 → 记录确切命令 + pass/fail │486│ │487│ 5. 出结论:逐条验证表 + 测试结果 + gap + 推荐 status,带证据 │488│ │489│ 5.5 能给安全默认就别升级(needs-human-confirm 硬前置) │490│ 5.7 沉默闸:agent 自发 + 无动作无新信息 → 本条不发,只记账 │491│ │492│ 6. 落 comment(中文),挂 status(+ 真分叉才挂 │493│ needs-human-confirm);不 close、不删文件、不改 frontmatter│494└────────────────────────────────────────────────────────────┘495```496497## Implementation Instructions498499### Step 0 — acquire 并发锁 + 判轮次 + 读 KB 热启动(先做,决定省不省)500**最先 acquire 并发锁**(见「★ 并发锁」):已被新鲜 `agent:processing` 持有 → SKIP 退出;否则加锁(`--dry-run` 不加)。并行 `issue-sweep` 的主控只分配 slot、**不替 worker 预加锁**;worker 到这里自行即时 acquire。再读共享 KB(`gh issue view <kb_issue>` 的 body)拿 repo 拓扑热启动,别从零探索。再 `gh issue view <n> --comments`:有既往 AI 结论 + human 意见 → 走「轮次感知」热启动路径,**跳过**下面会重复的全量步骤,只做 human 指定的下一步;否则走冷启动 Step 1–6(冷启动也按价值分档)。**收尾**:普通单 issue 调用把本轮新学到的拓扑事实 append/修正进 KB body;作为并行 `issue-sweep` worker 时不直接改 KB body,把结构化 KB delta 返回主控统一折叠。两种模式都由本 worker **release 锁(Step 7)**。501502**claim 后、任何实现/worktree 写入前必须检查开放 PR 路径重叠。** 当本轮将进入实现时,503先从已核验的执行计划形成结构化 `allowedPaths`(repo-relative file/directory prefixes;不得从504issue 标题或自然语言猜),再运行:505506```bash507bun <plugin_root>/scripts/check-pr-path-overlap.ts --run-args '{"allowedPaths":["<prefix>"]}'508```509510目录 prefix 包含具体文件,所以 `scripts/` 与 PR 的 `scripts/foo.ts` 是 overlap。`overlap`511必须在开工前报告 PR 号和具体文件,再由人/既有策略决定是否继续;`clean` 才表示确实查过且512无重叠;`unavailable`(paths 缺失/为空、`gh`/网络/auth/数据不可读)必须停止实现并显式回报,513不得当成 clean。comment-only 的 review 无 repo write,不伪造 `allowedPaths`,也不得声称已做514路径重叠检查。515516### Step 1 — 读 issue 全貌517`gh issue view <n> --json title,body,author,labels,state,milestone` + `--comments`。记下:文档路径、引用的 spec/范式、关键 commits、**全部 human/AI 意见**(human 意见优先级最高)。518519### Step 2 — 读文档 + 引用物520Read 被处理文档全文 + 它引用的 spec/design / 声称对齐的范式(如 `docs/architecture/did-space.md`)。521522### Step 3 — ★ 对照已落地实现/代码/intent523**这是把"读起来对"和"其实已落地 / 方向反了 / 接口面漂了"区分开的关键。** 不要只在文档间比对——查真实代码:524525```bash526find . -path ./node_modules -prune -o -iname "*<topic>*" -print527grep -rniE "<关键路径或符号>" -l . | grep -vi node_modules528ls intent/<topic>/ ; sed -n '1,80p' intent/<topic>/INTENT.md529```530531逐条声明 → 定位 `path:line` **或标 NOT FOUND**。注意:历史文档常见 `TASK.yaml` 标 done 但 `INTENT.md`/`plan.md` 没回头更新 → **status frontmatter 普遍不可信,必须对照代码重验,绝不信 status。**532533### Step 4 — ★ 真跑测试(doc-audit / 验收点名的验证)534找到相关测试(`pnpm --filter <pkg> test` / `bun test <path>`),**真的跑**,把**确切命令 + 真实 pass/fail 计数**记进结论。535536> 上面的 targeted `bun test <path>` 是为坐实**某一条 doc-audit claim**(只想要那一个测试的输出当证据)——保持轻量,别为一条 claim 跑全量门控。**下面这套只在 issue 是 feature/task、验收标准或 human 点名了验证手段时适用。**537538**当验收 / human 点名了验证——「本环境跑不动」是要被证明的结论,不是预设借口。** 用**仓库自己的 blessed skill**,别自己手搓命令再手填数字:5395401. **结构性 PR 门控(build / lint / types / tests / architecture)走 `/agentloop:verification`。** 跑 `<verification_entry>`,**数字由脚本测出、不手填**。**不要**自己 `pnpm build` / `bun test` 再手写「759 pass」——那正是手搓命令 + 手填计数的反模式,也是 `/agentloop:verification` 要消灭的非确定性。见 [`verification` skill](../verification/SKILL.md) + CLAUDE.md「Self-Verification」。5412. **验收点名的集成 e2e(blocklet render / mount / serve)走 `/e2e-verify`(该仓库的 companion,见 repo-profile 的 Companion Skills;没有就 stub 或跳过该步)——先尝试再下结论。** 它自己 `pnpm build` + boot **两个** runtime(`dev_server_node` + `dev_server_edge`,见 repo profile)——**边缘侧 = `<dev_server_edge>` 起本地环境,不需要云账号、不碰线上环境;所以 edge-parity / runtime 类验证本地就能做,绝不判成「需要云端环境」而 defer——那是错的。别把「别猛测线上环境」当成「本地验不了」**;**`<cli_binary>` 缺失/陈旧就先跑 `<cli_setup_command>`**(e2e-verify 自身也这么要求)。`/agentloop:verification`、`/e2e-verify`、`<cli_setup_command>` 你**完全可以调用**——没真跑过就写「需要 daemon / 本环境无法执行」= 失败,**也不能拿 unit test 顶替点名的 e2e**。5423. **缺依赖 = 多一步 setup,不是「跑不动」。** 原生插件没编译(如 better-sqlite3 → `npx node-gyp rebuild`)、CLI 没 link、没 build —— 先把 setup 做掉再跑,别当环境限制。5434. **真正的硬限制才算「跑不动」**:沙箱根本没那条工具链(repo profile **Deployment Environments** 列出的平台工具链,arc 例:无 Xcode → Swift、无 Android SDK → Kotlin、无 Playwright MCP → e2e-verify 的 Tier B 真浏览器),**且已实际撞墙**。**`dev_server_edge` 不在此列**——它是本地环境,永远不算「跑不动」。这时贴**确切命令 + 确切报错**,退而用能跑的那部分兜底(`/agentloop:verification` 脚本 / 别的 tier / 静态对照),并**显式标注跳过了哪一层**(如 `Tier B skipped/no-playwright`)。5445. **绝不假装跑过、不手填数字。** 没跑就说没跑;跑了就贴 skill / 脚本的真实输出。545546### Step 5 — 出结论547- **逐条验证表**:claim → `path:line` 或 NOT FOUND。548- **测试结果**:命令 + pass/fail。549- **gap 列表** + **phase 完成度**(doc-audit)。550- **推荐 status**(doc-audit 5 类之一)或 **分级发现**(doc-review:🔴 回归/方向错 · 🟡 真增量 · 🟢 已落地复述 · ⚪ 可删)。551- **reframe**(如适用):文档整体站错层/重开已结的题时,直接说"这一轮真正该产出什么"。552- 价值在**独立发现**,不在复述 human。553554### Step 5.5 — needs-human-confirm 硬前置(issue #1860)555556打 `needs-human-confirm` 标之前先问一遍:**我能不能说出一个安全默认动作?** 能 → 禁止升级,当场按 ratchet(默认放行,出问题再收紧,同 [`pr-review` Step 5.5](../pr-review/SKILL.md))执行该动作并留 trace;不能,才是真判断题,才配打 `needs-human-confirm` 走 Step 6 的结构化拍板块。这条硬前置在**打标动作之前**过,不是打完标再补。557558### ★ Step 5.7 — 沉默闸:没有状态变化就不要发言(硬前置,在 Step 6 之前过)559560**发 comment 之前先答一道判断题:这一轮我让世界发生了什么变化?** 三选一,只有前两类配发 comment:561562| 本轮产出 | 发不发 | 形态 |563|---|---|---|564| **动作**——开了 PR / 关了 issue / 改了 label / 提了 spin-off / 推进了一个 phase | **发** | 说做了什么,附产物链接 |565| **新信息**——上一条 agent comment 里没有的发现、结论翻转、新证据、新缺口、真需要人拍板的分叉 | **发** | 说新在哪 |566| **以上都不是**——核验了一遍,结论与既有 thread 一致,没有新动作也没有新信息 | **不发**(仅限 agent 自发路径,见下「适用面」) | **零 outward 写**,只写进 run report |567568第三类的典型措辞就是它自己的判据——**你正准备写下这些句子中的任何一句,就说明该闭嘴**:569570```571复核确认:现状与描述一致 / 结论成立,无需改动572premise 复核:与当前 main 一致573状态跟踪:三个子 issue 现状如下(与上一轮相同)574本轮不新开动作 / 本轮无进展 / 继续等待575确认收到 / 已阅 / 同意上述判断576```577578**为什么这是硬闸,不是风格偏好:** 一条「我看过了,没变」的 comment 对读它的人是**净负担**——它把 issue 顶到 timeline 最前面、发一次通知、占一屏,换来的信息量是零。更糟的是它有**自激回路**:sweep 的 round-awareness 判据是「最后一条是未回应的人类评论」,人一回话就触发下一轮 agent 回话;多台机器覆盖同一个 repo 时,就变成两个 agent 在同一条 issue 下轮流附和「这个想法对,我们应该这么做」而**没有人动手**。实测(arc,2026-08-13→20 一周):261 条 agent 评论 : 21 个 PR ≈ 12:1,其中约一半是本表第三类。579580**沉默 ≠ 没干活。** 本轮的核验结果写进 `$AGENTLOOP_RUN_REPORT`(`{"noop":true,"summary":"…"}`)——它是给机器看的记账面,不是给人看的通知面。**「查过了没问题」属于记账面。**581582#### 适用面:只管 agent 自发的复核,绝不管对人的应答(这条是机制性的,不是礼貌)583584**沉默闸只适用于 agent 自己发起的处理路径**:`--autofix-green` 扫描、Step 0.5 的 graph-scan / rollup 候选、状态跟踪、定期复核。585586**人类输入触发的路径必须回应,哪怕答案是「没变」。** 理由不是礼貌,是**它会造成每轮重复核验的死循环**:587[`issue-sweep` Step 2](../issue-sweep/SKILL.md) 的判据是「最后一条是**未回应的**人类评论」,而「已回应」的唯一证据就是那条带588[sweep-trace](#-sweep-trace-埋点round-awareness-判据--l2-可观测层) 的 agent comment。589**agent 对人类评论保持沉默 = thread 里永远没有那条 trace = 下一轮 sweep 认定它仍未处理 = 重新读、重新核验、重新判定沉默——每轮都花全额的钱,一条 comment 都不产出。** 那比刷屏更糟:刷屏至少人看得见。590591所以判据要**两问连读**,顺序不能反:5925931. **这一轮是谁触发的?** 人类输入触发 → **必须发**(内容按下面第 2 问约束),跳过沉默闸。5942. **(仅 agent 自发时)有动作或新信息吗?** 没有 → 沉默。595596#### 边界(在适用面之内)5975981. **结论从上一轮翻转 → 必须发**(哪怕方向是「上次说能做,这次发现不能」)。翻转就是新信息。5992. **要更新既有结论 → 原地编辑那一条**(`--edit-last`),不是新发一条也不是不发。6003. **人类触发时「必须发」约束的是发不发,不是发什么。** 「复核确认,现状不变」**依然不是合法内容**——回应人类的正确形态是**答他的具体问题 + 一条行动声明**(★Idea/★Research 铁律 10 的 ratchet 格式),而不是复述现状。**#4384 那类 1400 字分析停在「仍需拍板」,归铁律 10 管,不归本闸管;本闸管的是 agent 自己跑去把一条没人问的 issue 重新核验一遍然后宣布「没变」。** 两条规则分工不重叠。601602### Step 6 — 落 comment(产物归宿)603用 `comment_language` 指定的正文语言写(arc 默认:中文),顶部标 AI 身份与读取/运行范围:604605```606> 🤖 AI Agent Audit @ <hostname> · runner:<runner> · skills@<hash>[ · engine:<kind>[/<model>]]。读取:<文档+代码+测试>。运行:<测试命令>。每条发现附可复现证据。607```608609整行 header **必须由单点脚本生成**(`<agent_identity_script>`;环境/归属/skills/engine 四维溯源,不能用日期、占位符或手拼代替——尤其别再手写死 "Claude Code(<model>)",脚本按 `ARC_AGENT_ENGINE`/`ARC_AGENT_MODEL` 自动带出真实 engine,Codex 下跑手写死会错误自称 Claude),行尾追加读取/运行范围:610```bash611bash <agent_identity_script> --heade612613…(truncated)