pr-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PR Review

PR代码审查

Review a PR/MR diff by dispatching independent role-based subagents in parallel, then publish findings as one sticky summary comment + per-finding inline comments. The main session never reviews — it ingests, dispatches, merges, emits, publishes.
<HARD-GATE> You MUST dispatch independent subagents — NEVER review the diff yourself in the main session. The main session accumulates context bias from prior conversation. Only an isolated subagent can deliver an unbiased finding.
Dispatch in PARALLEL using a single message with multiple Agent tool calls. If one subagent fails, proceed with the rest BUT surface the failure in the sticky comment header (never silent). If ALL fail, report failure — do NOT fall back to self-review.
Publishing happens in the main session (post-merge) — not in subagents.
mode: local
does NOT relax this gate. Local mode changes the output target (JSON to stdout instead of GitHub sticky/inline), not the reviewer. The 4-subagent parallel dispatch is exactly the property that makes local mode worth invoking from a supervisor session — without it the caller could just self-review. </HARD-GATE>
通过并行调度独立的角色化subagent来审查PR/MR代码差异,然后将审查结果发布为一条固定总结评论 + 每个问题对应的行内评论。主会话从不直接参与审查——仅负责接收信息、调度subagent、合并结果、输出内容、发布评论。
<HARD-GATE> 你必须调度独立的subagent——绝对不能在主会话中自行审查代码差异。主会话会从之前的对话中积累上下文偏见,只有独立的subagent才能提供无偏见的审查结果。
通过单条消息调用多个Agent工具来并行调度subagent。如果某个subagent执行失败,继续使用其他subagent的结果,但必须在固定总结评论的头部说明失败情况(绝对不能隐瞒)。如果所有subagent都失败,报告失败——绝对不能 fallback 到自行审查。
发布操作在主会话中完成(合并结果后)——而非在subagent中。
mode: local
模式不会放宽此限制。Local模式仅改变输出目标(将JSON输出到标准输出而非GitHub的固定/行内评论),不改变审查主体。4个subagent并行调度正是Local模式值得从主管会话调用的核心特性——没有这一特性,调用方完全可以自行审查。 </HARD-GATE>

Rationalization Prevention

防止合理化借口

ThoughtReality
"The diff is small, I can review it myself"Self-review is biased by what you saw in the conversation. Small ≠ unbiased.
"I already saw this code earlier"That's exactly why you can't review it. Familiarity hides issues.
"Dispatching 3-4 subagents is overkill"Each persona uses a different mental model. A single agent dilutes all of them.
"Sequential is fine, I'll save tokens"Parallel is faster wall-clock and prevents one report from biasing the next.
"spec-auditor isn't needed, the spec is short"If has_spec is true, dispatch. The check is whether spec exists, not whether it's verbose.
"I'll just check the obvious bug myself"Even one self-checked finding contaminates the report — readers can't tell which findings are biased.
"1 subagent failed, just hide it"Hiding partial review = pretending coverage existed. Surface it in sticky header.
"Prior finding line moved, mark fixed"Line moving ≠ behaviour fixed. Require subagent verification, then hedge as
Likely fixed
.
想法实际情况
"代码差异很小,我可以自己审查"自行审查会受到对话中已见内容的偏见影响。代码量小≠无偏见。
"我之前已经看过这段代码了"这正是你不能自行审查的原因。熟悉感会掩盖问题。
"调度3-4个subagent太夸张了"每个角色使用不同的思维模型。单个Agent会稀释所有模型的作用。
"顺序调度就可以,能节省token"并行调度耗时更短,还能避免一份报告影响下一份报告的结果。
"不需要spec-auditor,规范很短"如果has_spec为true,就必须调度。判断标准是规范是否存在,而非是否冗长。
"我自己检查明显的bug就行"哪怕只有一个自行检查的问题,也会污染整个报告——读者无法区分哪些结果带有偏见。
"有1个subagent失败了,隐瞒就行"隐瞒部分审查结果=假装完成了全面审查。必须在固定总结评论头部说明。
"之前的问题行被移动了,标记为已修复"代码行移动≠行为修复。需要subagent验证,然后标记为
Likely fixed
(可能已修复)。

Red Flags — STOP if you catch yourself:

危险信号——如果发现自己有以下行为,请立即停止:

  • Reviewing any category yourself instead of dispatching
  • Dispatching subagents sequentially instead of in parallel
  • Skipping a subagent because "the diff doesn't look like it has X"
  • Claiming review passed without reading subagent findings
  • Editing code during review (review reads, doesn't write)
  • Falling back to self-review because a subagent failed
  • Hiding subagent failures in output (must surface in sticky header)
  • Marking prior findings as
    ✅ Fixed
    without a verification note from subagent
  • Publishing inline comments before merging findings (dispatch → merge → publish)
<decision_boundary>
Use for:
  • Reviewing a PR/MR diff and producing structured findings
  • Security / logic / performance scans on code changes
  • Spec compliance verification when spec exists
  • Organizing findings with severity + blast radius + confidence
  • Posting findings to GitHub PR as sticky summary + inline comments
NOT for:
  • Writing or improving PR descriptions
  • Design review requiring business judgment about scope or direction
  • Writing the actual code/diff
  • Deep CVE / supply-chain / OWASP sweep
  • Writing release notes / CHANGELOG
  • End-user / UX review (use /qa or /design-review)
  • Auto-approving or auto-merging (produce findings only; humans merge)
</decision_boundary>
  • 自行审查任何类别内容,而非调度subagent
  • 顺序调度subagent而非并行调度
  • 因为“代码差异看起来没有X问题”而跳过某个subagent
  • 未阅读subagent结果就声称审查通过
  • 审查过程中修改代码(审查仅负责读取,不负责编写)
  • 因subagent失败而fallback到自行审查
  • 在输出中隐瞒subagent失败情况(必须在固定总结评论头部说明)
  • 未获得subagent的验证说明就将之前的问题标记为
    ✅ Fixed
    (已修复)
  • 合并结果前就发布行内评论(流程应为:调度→合并→发布)
<decision_boundary>
适用场景:
  • 审查PR/MR代码差异并生成结构化问题
  • 对代码变更进行安全/逻辑/性能扫描
  • 当存在规范时,验证代码是否符合规范
  • 按严重性、影响范围、置信度整理审查结果
  • 将审查结果发布到GitHub PR,形式为固定总结评论+行内评论
不适用场景:
  • 撰写或优化PR描述
  • 需要业务判断范围或方向的设计审查
  • 编写实际代码/差异
  • 深度CVE/供应链/OWASP扫描
  • 撰写发布说明/CHANGELOG
  • 终端用户/UX审查(使用/qa或/design-review)
  • 自动批准或自动合并(仅生成审查结果;合并由人工完成)
</decision_boundary>

Flow

流程

dot
digraph pr_review {
    "Receive inputs" [shape=doublecircle];
    "Resolve mode" [shape=box];
    "Compute capability flags" [shape=box];
    "Parallel dispatch" [shape=box, style=bold];
    "security-reviewer" [shape=box];
    "staff-engineer" [shape=box];
    "sdet" [shape=box];
    "has_spec?" [shape=diamond];
    "spec-auditor" [shape=box];
    "Skip spec-auditor" [shape=box];
    "Collect + Dedup" [shape=box];
    "Apply severity merge rule" [shape=box];
    "Build sticky + inline" [shape=box];
    "dry-run?" [shape=diamond];
    "Print to console" [shape=box];
    "Publish to PR" [shape=box];
    "Done" [shape=doublecircle];

    "Receive inputs" -> "Resolve mode";
    "Resolve mode" -> "Compute capability flags";
    "Compute capability flags" -> "Parallel dispatch";
    "Parallel dispatch" -> "security-reviewer";
    "Parallel dispatch" -> "staff-engineer";
    "Parallel dispatch" -> "sdet";
    "Parallel dispatch" -> "has_spec?";
    "has_spec?" -> "spec-auditor" [label="yes"];
    "has_spec?" -> "Skip spec-auditor" [label="no"];
    "security-reviewer" -> "Collect + Dedup";
    "staff-engineer" -> "Collect + Dedup";
    "sdet" -> "Collect + Dedup";
    "spec-auditor" -> "Collect + Dedup";
    "Skip spec-auditor" -> "Collect + Dedup";
    "Collect + Dedup" -> "Apply severity merge rule";
    "Apply severity merge rule" -> "Build sticky + inline";
    "Build sticky + inline" -> "dry-run?";
    "dry-run?" -> "Print to console" [label="yes"];
    "dry-run?" -> "Publish to PR" [label="no"];

    "Apply severity merge rule" -> "Emit findings JSON" [label="mode=local"];
    "Emit findings JSON" [shape=box];
    "Emit findings JSON" -> "Done";
}
dot
digraph pr_review {
    "Receive inputs" [shape=doublecircle];
    "Resolve mode" [shape=box];
    "Compute capability flags" [shape=box];
    "Parallel dispatch" [shape=box, style=bold];
    "security-reviewer" [shape=box];
    "staff-engineer" [shape=box];
    "sdet" [shape=box];
    "has_spec?" [shape=diamond];
    "spec-auditor" [shape=box];
    "Skip spec-auditor" [shape=box];
    "Collect + Dedup" [shape=box];
    "Apply severity merge rule" [shape=box];
    "Build sticky + inline" [shape=box];
    "dry-run?" [shape=diamond];
    "Print to console" [shape=box];
    "Publish to PR" [shape=box];
    "Done" [shape=doublecircle];

    "Receive inputs" -> "Resolve mode";
    "Resolve mode" -> "Compute capability flags";
    "Compute capability flags" -> "Parallel dispatch";
    "Parallel dispatch" -> "security-reviewer";
    "Parallel dispatch" -> "staff-engineer";
    "Parallel dispatch" -> "sdet";
    "Parallel dispatch" -> "has_spec?";
    "has_spec?" -> "spec-auditor" [label="yes"];
    "has_spec?" -> "Skip spec-auditor" [label="no"];
    "security-reviewer" -> "Collect + Dedup";
    "staff-engineer" -> "Collect + Dedup";
    "sdet" -> "Collect + Dedup";
    "spec-auditor" -> "Collect + Dedup";
    "Skip spec-auditor" -> "Collect + Dedup";
    "Collect + Dedup" -> "Apply severity merge rule";
    "Apply severity merge rule" -> "Build sticky + inline";
    "Build sticky + inline" -> "dry-run?";
    "dry-run?" -> "Print to console" [label="yes"];
    "dry-run?" -> "Publish to PR" [label="no"];

    "Apply severity merge rule" -> "Emit findings JSON" [label="mode=local"];
    "Emit findings JSON" [shape=box];
    "Emit findings JSON" -> "Done";
}

Inputs

输入参数

Required

必填参数

pr
<owner>/<repo>#<N>
or full PR URL. Used for sticky lookup and publishing. No implicit branch-based detection (too brittle).
Exception:
mode: local
does not require
pr
(no GitHub side effects). See Local Mode.
pr
<owner>/<repo>#<N>
或完整PR URL。用于查找固定评论和发布内容。不支持隐式基于分支的检测(过于脆弱)。
例外情况
mode: local
模式不需要
pr
参数(无GitHub相关操作)。详见Local模式

Optional

可选参数

mode
auto
(default) /
full
/
incremental
/
local
. See Mode Detection and Local Mode.
dry-run
true
/
false
(default
false
). When true, builds sticky + inline payloads and prints to console; no GitHub API writes.
base
— base git ref for diff scope (e.g.
origin/main
). Used by local mode only — replaces the sticky/PR-based base lookup. Ignored for other modes (they derive base from the PR or repo state).
last_sha
— prior reviewed HEAD commit. Used by local mode only for incremental review. In non-local modes the last_sha lives in the sticky body; local mode has no sticky, so the caller (e.g. supervisor) must pass it explicitly.
spec
— source of the spec / design doc. Sets
has_spec
flag.
  • Path:
    spec: docs/specs/payment-v2.md
  • URL:
    spec: https://confluence.example.com/payment-v2
  • Inline:
    spec: this PR implements PCI DSS v4.0 logical isolation
  • Multiple:
    spec: design doc at X, acceptance criteria in Jira ABC-123
If absent → spec-auditor not dispatched. Other subagents do not reference spec.
test direction
— tells sdet how to evaluate test coverage. All sub-fields optional:
  • Approach:
    unit only
    /
    integration required
    /
    e2e required
    /
    no test needed
  • Location: expected test file path
  • Focus: scenario or case the test should cover
Missing → sdet uses heuristic from diff nature.
context
— free-form supplementary signals:
  • Business risk: "this endpoint is internal-admin only"
  • Domain rules: "tenant_id is required"
  • Known trade-offs: "we're aware of the N+1, will fix next sprint"
  • Environment constraints: "CDE service, security findings cannot be downgraded"
  • Hotfix narrowing: "hotfix — only check critical security"
  • Cross-PR coupling: "ships together with PR #1234"
Context can adjust severity at merge time (see Severity Merge Rule).
mode
auto
(默认)/
full
/
incremental
/
local
。详见模式检测Local模式
dry-run
true
/
false
(默认
false
)。设为true时,生成固定+行内评论内容并打印到控制台;不调用GitHub API写入内容。
base
— 代码差异范围的基准git引用(例如
origin/main
)。仅Local模式使用——替代基于固定评论/PR的基准查找。其他模式忽略此参数(它们从PR或仓库状态推导基准)。
last_sha
— 上次审查的HEAD提交。仅Local模式用于增量审查。非Local模式下,last_sha存储在固定评论内容中;Local模式没有固定评论,因此调用方(如主管会话)必须显式传入。
spec
— 规范/设计文档的来源。用于设置
has_spec
标志。
  • 路径:
    spec: docs/specs/payment-v2.md
  • URL:
    spec: https://confluence.example.com/payment-v2
  • 内联:
    spec: this PR implements PCI DSS v4.0 logical isolation
  • 多个来源:
    spec: design doc at X, acceptance criteria in Jira ABC-123
如果未提供→不调度spec-auditor。其他subagent不会引用规范。
test direction
— 告知sdet如何评估测试覆盖。所有子字段均为可选:
  • Approach
    unit only
    /
    integration required
    /
    e2e required
    /
    no test needed
  • Location:预期的测试文件路径
  • Focus:测试应覆盖的场景或用例
如果未提供→sdet根据代码差异的性质使用启发式规则判断。
context
— 自由格式的补充信息:
  • 业务风险:"this endpoint is internal-admin only"
  • 领域规则:"tenant_id is required"
  • 已知权衡:"we're aware of the N+1, will fix next sprint"
  • 环境约束:"CDE service, security findings cannot be downgraded"
  • 热修复范围:"hotfix — only check critical security"
  • 跨PR关联:"ships together with PR #1234"
上下文信息可在合并阶段调整问题严重性(详见严重性合并规则)。

Mode Detection

模式检测

Resolve before dispatch. The mode controls diff scope and output sections.
mode: local
short-circuits this whole section — no sticky lookup, no SHA reachability check, no noop case. Diff scope comes from the
base
(and optional
last_sha
) inputs; see Local Mode.
dot
digraph mode {
  "mode input" [shape=box];
  "Has sticky?" [shape=diamond];
  "last_sha reachable?" [shape=diamond];
  "Same as HEAD?" [shape=diamond];
  "incremental" [shape=box, style=bold];
  "full" [shape=box, style=bold];
  "local" [shape=box, style=bold];
  "noop (report no-change)" [shape=box, style=bold];

  "mode input" -> "Has sticky?" [label="auto"];
  "mode input" -> "incremental" [label="incremental (forced)"];
  "mode input" -> "full" [label="full (forced)"];
  "mode input" -> "local" [label="local (forced)"];
  "Has sticky?" -> "last_sha reachable?" [label="yes"];
  "Has sticky?" -> "full" [label="no"];
  "last_sha reachable?" -> "Same as HEAD?" [label="yes"];
  "last_sha reachable?" -> "full" [label="no\n(force-push?)"];
  "Same as HEAD?" -> "noop (report no-change)" [label="yes"];
  "Same as HEAD?" -> "incremental" [label="no"];
}
Sticky discovery:
bash
gh api repos/<owner>/<repo>/issues/<N>/comments \
  --jq '.[] | select(.body | contains("<!-- pr-review:sticky -->")) | {id, body}'
Markers embedded in sticky body:
  • <!-- pr-review:sticky -->
    — locator
  • <!-- pr-review:sha=<commit> -->
    — last reviewed HEAD
SHA reachability:
bash
git cat-file -e <last_sha> 2>/dev/null && echo reachable || echo unreachable
If unreachable (force-push / squash-merge of older PR / branch rebased): fall back to
full
AND prepend to sticky body:
markdown
> ⚠️ Prior review base `<last_sha>` is not reachable (force-push?). This iteration is a full re-review.
调度前先确定模式。模式控制代码差异范围和输出内容。
mode: local
模式会跳过本节所有内容——无需查找固定评论、无需检查SHA可达性、无需处理noop情况。代码差异范围由
base
(可选
last_sha
)输入决定;详见Local模式
dot
digraph mode {
  "mode input" [shape=box];
  "Has sticky?" [shape=diamond];
  "last_sha reachable?" [shape=diamond];
  "Same as HEAD?" [shape=diamond];
  "incremental" [shape=box, style=bold];
  "full" [shape=box, style=bold];
  "local" [shape=box, style=bold];
  "noop (report no-change)" [shape=box, style=bold];

  "mode input" -> "Has sticky?" [label="auto"];
  "mode input" -> "incremental" [label="incremental (forced)"];
  "mode input" -> "full" [label="full (forced)"];
  "mode input" -> "local" [label="local (forced)"];
  "Has sticky?" -> "last_sha reachable?" [label="yes"];
  "Has sticky?" -> "full" [label="no"];
  "last_sha reachable?" -> "Same as HEAD?" [label="yes"];
  "last_sha reachable?" -> "full" [label="no\n(force-push?)"];
  "Same as HEAD?" -> "noop (report no-change)" [label="yes"];
  "Same as HEAD?" -> "incremental" [label="no"];
}
固定评论查找:
bash
gh api repos/<owner>/<repo>/issues/<N>/comments \
  --jq '.[] | select(.body | contains("<!-- pr-review:sticky -->")) | {id, body}'
固定评论内容中嵌入的标记:
  • <!-- pr-review:sticky -->
    — 定位标记
  • <!-- pr-review:sha=<commit> -->
    — 上次审查的HEAD
SHA可达性检查:
bash
git cat-file -e <last_sha> 2>/dev/null && echo reachable || echo unreachable
如果不可达(强制推送/旧PR squash合并/分支变基):fallback到
full
模式,并在固定评论内容开头添加:
markdown
> ⚠️ 上次审查基准 `<last_sha>` 不可达(可能是强制推送?)。本次为全面重新审查。

Noop case (
last_sha == HEAD
)

Noop情况(
last_sha == HEAD

When the sticky exists AND
last_sha == HEAD
: skip dispatch + publish. Print to console:
pr-review: nothing new since <last_sha>. Skipping. Use mode=full to force a re-review.
The sticky is already current; do not touch it.
当固定评论存在且
last_sha == HEAD
时:跳过调度+发布。打印到控制台:
pr-review: 自 <last_sha> 以来无新内容。已跳过。使用mode=full可强制重新审查。
固定评论已为最新状态;请勿修改。

Local Mode

Local模式

Use when the caller is another skill or supervisor session that needs unbiased multi-role review of a diff but has no PR open yet (e.g. a supervisor session's verify phase doing pre-PR critique). The HARD-GATE still applies — local mode is about output target, not about who reviews.
Caveat — calling from the same dev session that wrote the code (author-as-reviewer bias): pr-review's 4-subagent dispatch is isolated by design — finding generation is robust even when called from the author's session. But the downstream
modify / wontfix / defer
verdict on each finding is NOT covered by this isolation.
If the same session that wrote the code also reasons about which findings to wontfix, author-narrative bias compounds — framing a diff as "bug-free" produces the strongest detection drop among framing conditions tested across 6 LLMs (Mitropoulos et al., Measuring and Exploiting Contextual Bias in LLM-Assisted Security Code Review, arXiv:2603.18740). Treat local-mode findings as advisory in dev sessions; do NOT auto-execute verdicts in main session. A proper dev-stage verdict loop needs a separate Deriver-pattern verdict-subagent (not built yet — see
pr-babysit/SKILL.md
§ 4.6 "When NOT to use" for the equivalent caveat on Wontfix Template).
适用于调用方为其他技能或主管会话,需要对代码差异进行无偏见的多角色审查,但尚未创建PR的场景(例如主管会话的验证阶段,在PR创建前进行评审)。HARD-GATE仍然适用——Local模式仅改变输出目标,不改变审查主体。
注意——从编写代码的同一开发会话调用(作者兼审查者偏见):pr-review的4-subagent调度设计为完全隔离——即使从作者的会话调用,问题生成也能保持稳健。但对每个问题的下游
modify / wontfix / defer
判定不受此隔离保护
。如果编写代码的同一会话同时判定哪些问题标记为wontfix,作者叙事偏见会加剧——将代码差异描述为“无bug”会导致6种LLM的检测率大幅下降(Mitropoulos等人,Measuring and Exploiting Contextual Bias in LLM-Assisted Security Code ReviewarXiv:2603.18740)。在开发会话中,Local模式的结果仅作为参考建议;绝对不要在主会话中自动执行判定。完善的开发阶段判定流程需要独立的Deriver模式判定subagent(尚未构建——详见
pr-babysit/SKILL.md
§4.6 "不适用场景"中关于Wontfix模板的类似注意事项)。

Inputs

输入参数

  • mode: local
    (required to enter this mode)
  • base: <ref>
    (required — e.g.
    origin/main
    )
  • last_sha: <sha>
    (optional — if provided, runs incremental on
    <last_sha>..HEAD
    and still reads
    <base>...HEAD
    for cumulative context that subagents need for prior-finding verification)
  • spec
    ,
    test direction
    ,
    context
    — same semantics as default mode
pr
is NOT required and ignored if provided.
  • mode: local
    (必填,用于进入此模式)
  • base: <ref>
    (必填——例如
    origin/main
  • last_sha: <sha>
    (可选——如果提供,对
    <last_sha>..HEAD
    进行增量审查,同时读取
    <base>...HEAD
    以获取累积上下文,供subagent验证之前的问题)
  • spec
    ,
    test direction
    ,
    context
    — 语义与默认模式相同
pr
参数非必填,若提供会被忽略。

Diff scope

代码差异范围

  • No
    last_sha
    → full diff:
    git diff <base>...HEAD
    (three-dot — topic-only changes)
  • With
    last_sha
    → incremental: subagents see both
    <base>...HEAD
    and
    <last_sha>..HEAD
    ; they report findings only inside the incremental window plus verification status for prior findings (caller must pass prior findings too — see below)
  • 未提供
    last_sha
    → 完整差异:
    git diff <base>...HEAD
    (三点语法——仅主题分支变更)
  • 提供
    last_sha
    → 增量差异:subagent同时查看
    <base>...HEAD
    <last_sha>..HEAD
    ;仅报告增量范围内的问题,以及之前问题的验证状态(调用方还必须传入之前的问题——详见下文)

Caller responsibilities (incremental local mode)

调用方职责(增量Local模式)

The sticky normally carries prior findings between iterations. In local mode the caller owns that state and must pass to pr-review on each invocation:
  • prior_findings
    : array of objects with
    {id, slug, file, line, category, severity, justification, summary}
    — same shape as findings JSON output (see below)
  • prior_fix_range
    :
    <first-fix-sha>^..<last-fix-sha>
    — the commits that addressed iter (N-1) findings, used by the threshold's drop signal (B)
If
last_sha
is set but
prior_findings
is missing → ESCALATE to caller; do not fabricate.
固定评论通常在迭代之间保存之前的问题。Local模式下,调用方负责维护该状态,每次调用pr-review时必须传入:
  • prior_findings
    :对象数组,格式为
    {id, slug, file, line, category, severity, justification, summary}
    ——与输出的findings JSON格式相同(详见下文)
  • prior_fix_range
    <first-fix-sha>^..<last-fix-sha>
    ——解决第(N-1)次迭代问题的提交范围,用于阈值的drop signal (B)自引入检查。如果每次迭代仅提交一个commit,此范围简化为
    <last_sha>..HEAD
    。如果调度方无法确定范围(例如强制推送、第N-1次迭代的提交被squash合并)→ fallback到
    full
    模式并在固定评论中说明;绝对不要在没有
    prior_fix_range
    的情况下调用增量模式
如果设置了
last_sha
但未提供
prior_findings
→向调用方报错;请勿自行生成。

Output

输出

Skip Publishing. Skip sticky/inline markdown construction. Emit one JSON document to stdout:
json
{
  "mode": "local",
  "base": "origin/main",
  "head": "<HEAD sha>",
  "last_sha": "<sha or null>",
  "status": "blocking | review-before-merge | approved-with-notes | approved | noop | partial-failure",
  "subagent_failures": [],
  "summary_line": "<same wording as sticky summary line>",
  "findings": [
    {
      "id": "#1",
      "p_code": "P0 | P1 | P2 | Q",
      "severity_emoji": "🚨 | ⚠️ | 💡 | ❓",
      "slug": "kebab-case-slug",
      "category": "Original [code name] from subagent",
      "file": "path/to/file",
      "line_start": 42,
      "line_end": 42,
      "confidence": "high | medium | low",
      "blast": "Local | Module | Cross-service | Data layer",
      "justification": "Reachable | Precedent | Asymmetric | Historical",
      "failure_mode": "one-line",
      "mitigation": "one-line",
      "evidence": "verbatim diff line(s)",
      "details": "optional multi-line",
      "severity_adjustment": null | { "from": "💡 P2", "to": "⚠️ P1", "reason": "..." }
    }
  ],
  "spec_gaps": [
    {
      "id": "#7",
      "section": "spec section or decision id",
      "title": "one-line",
      "spec_quote": "verbatim",
      "code_quote": "verbatim",
      "questions": ["..."]
    }
  ],
  "prior_verifications": [
    {
      "prior_id": "#1",
      "verification": "yes | unclear | no",
      "note": "what evidence"
    }
  ],
  "checked_and_clean": [
    { "slug": "...", "evidence": "one-line" }
  ]
}
severity_adjustment: null
when no adjustment; the merged severity is already reflected in
p_code
/
severity_emoji
. The adjustment field exists so callers can audit downgrades (same role as the sticky's
## ⚖️ Severity adjustments
section).
prior_verifications
is empty
[]
when
last_sha
is absent.
跳过发布步骤。跳过固定/行内评论的markdown构建。向标准输出输出一个JSON文档:
json
{
  "mode": "local",
  "base": "origin/main",
  "head": "<HEAD sha>",
  "last_sha": "<sha or null>",
  "status": "blocking | review-before-merge | approved-with-notes | approved | noop | partial-failure",
  "subagent_failures": [],
  "summary_line": "<与固定评论摘要行相同的措辞>",
  "findings": [
    {
      "id": "#1",
      "p_code": "P0 | P1 | P2 | Q",
      "severity_emoji": "🚨 | ⚠️ | 💡 | ❓",
      "slug": "kebab-case-slug",
      "category": "来自subagent的原始[代码名称]",
      "file": "path/to/file",
      "line_start": 42,
      "line_end": 42,
      "confidence": "high | medium | low",
      "blast": "Local | Module | Cross-service | Data layer",
      "justification": "Reachable | Precedent | Asymmetric | Historical",
      "failure_mode": "单行描述",
      "mitigation": "单行描述",
      "evidence": "逐字差异行",
      "details": "可选多行",
      "severity_adjustment": null | { "from": "💡 P2", "to": "⚠️ P1", "reason": "..." }
    }
  ],
  "spec_gaps": [
    {
      "id": "#7",
      "section": "规范章节或决策ID",
      "title": "单行描述",
      "spec_quote": "逐字引用",
      "code_quote": "逐字引用",
      "questions": ["..."]
    }
  ],
  "prior_verifications": [
    {
      "prior_id": "#1",
      "verification": "yes | unclear | no",
      "note": "验证依据"
    }
  ],
  "checked_and_clean": [
    { "slug": "...", "evidence": "单行描述" }
  ]
}
severity_adjustment: null
表示未调整;合并后的严重性已反映在
p_code
/
severity_emoji
中。调整字段用于调用方审计降级操作(与固定评论的
## ⚖️ Severity adjustments
部分作用相同)。
未提供
last_sha
时,
prior_verifications
为空数组
[]

What local mode keeps from default mode

Local模式保留默认模式的特性

  • HARD-GATE: still dispatch 4 parallel subagents; main session never reviews
  • Capability flags (has_spec, has_repo, is_trivial)
  • Finding Inclusion Threshold (Reachable / Precedent / Asymmetric / Historical + drop signals A/B/C/D)
  • Severity Merge Rule (4 steps + P-code mapping)
  • Dedup between subagent findings
  • Subagent failure → if all 4 fail, report failure to caller; never self-review
  • HARD-GATE:仍并行调度4个subagent;主会话从不审查
  • 能力标志(has_spec, has_repo, is_trivial)
  • 问题纳入阈值(Reachable / Precedent / Asymmetric / Historical + drop signals A/B/C/D)
  • 严重性合并规则(4步+P-code映射)
  • subagent结果去重
  • subagent失败→如果全部4个失败,向调用方报告失败;绝不自行审查

What local mode drops

Local模式移除的特性

  • Sticky comment build / markdown rendering
  • Inline comment markdown / GitHub Review API call
  • Sticky discovery via
    gh api
  • last_sha derivation from sticky body (caller passes it)
  • Noop case (caller decides whether to re-invoke; if
    last_sha == HEAD
    and caller still invokes, return
    findings: []
    + a
    status: "noop"
    )
  • 固定评论构建/markdown渲染
  • 行内评论markdown/GitHub Review API调用
  • 通过
    gh api
    查找固定评论
  • 从固定评论内容推导last_sha(由调用方传入)
  • Noop情况(调用方决定是否重新调用;如果
    last_sha == HEAD
    且调用方仍调用,返回
    findings: []
    +
    status: "noop"

Capability Flags

能力标志

Compute before dispatch:
FlagDefaultSet whenEffect
has_spec
falsespec input present OR PR description has goal/requirement sectiondispatch spec-auditor
has_repo
truerepo access available (grep / index / LSP)enable cross-file checks
is_trivial
false<50 LOC AND (docs-only OR pure rename OR pure type-only)skip staff-engineer
调度前计算:
标志默认值设置条件效果
has_spec
false提供了spec输入 或 PR描述包含目标/需求章节调度spec-auditor
has_repo
true可访问仓库(支持grep / 索引 / LSP)启用跨文件检查
is_trivial
false代码行数<50 且(仅文档变更 或 纯重命名 或 仅类型变更)跳过staff-engineer

Dispatch

调度

Default dispatch (4 subagents in parallel via a single message):
SubagentPrompt fileWhen dispatched
security-reviewer
security-reviewer-prompt.md
always
staff-engineer
staff-engineer-prompt.md
always (skip if is_trivial)
sdet
sdet-prompt.md
always
spec-auditor
spec-auditor-prompt.md
only if has_spec
Each subagent receives:
  • Diff (full in
    full
    mode;
    <last_sha>..HEAD
    in
    incremental
    mode)
  • Capability flags (has_spec, has_repo, is_trivial)
  • Mode (
    full
    /
    incremental
    )
  • Their relevant inputs only (spec content for spec-auditor, test direction for sdet)
  • In
    incremental
    mode (dispatcher MUST provide all three):
    • Prior findings JSON (subagent's own category scope only)
    • Prior
      Checked & clean
      slugs for drift spot-check
    • prior_fix_range
      :
      <first-fix-sha>^..<last-fix-sha>
      — git range covering the commits that addressed iter (N-1) findings. Subagent uses this to apply drop signal (B) self-introduced surface. In single-commit-per-iter cases this collapses to
      <last_sha>..HEAD
      . If the dispatcher cannot determine the range (e.g. force-push, squash-merge of iter N-1 commits) → fall back to
      full
      mode and announce in sticky; do NOT invoke incremental mode without
      prior_fix_range
  • NO conversation history, NO session context, NO prior subagent findings from this run
Threshold inlining: the Finding Inclusion Threshold is inlined directly in each subagent prompt (
security-reviewer-prompt.md
/
staff-engineer-prompt.md
/
sdet-prompt.md
/
spec-auditor-prompt.md
). Dispatcher does NOT need to prepend threshold text — subagents apply it from their baked-in section. This avoids relying on dispatcher's "good behavior" to inject the gate on every invocation.
默认调度(通过单条消息并行调度4个subagent):
Subagent提示文件调度条件
security-reviewer
security-reviewer-prompt.md
始终调度
staff-engineer
staff-engineer-prompt.md
始终调度(如果is_trivial为true则跳过)
sdet
sdet-prompt.md
始终调度
spec-auditor
spec-auditor-prompt.md
仅当has_spec为true时调度
每个subagent会收到:
  • 代码差异(
    full
    模式下为完整差异;
    incremental
    模式下为
    <last_sha>..HEAD
  • 能力标志(has_spec, has_repo, is_trivial)
  • 模式(
    full
    /
    incremental
  • 仅与自身相关的输入(spec-auditor收到规范内容,sdet收到test direction)
  • incremental
    模式下(调度方必须提供全部三项):
    • 之前的问题JSON(仅subagent自身负责的类别范围)
    • 之前的
      Checked & clean
      标识,用于检查漂移
    • prior_fix_range
      :
      <first-fix-sha>^..<last-fix-sha>
      ——解决第(N-1)次迭代问题的提交范围。subagent使用此范围应用drop signal (B)自引入检查。如果每次迭代仅提交一个commit,此范围简化为
      <last_sha>..HEAD
      。如果调度方无法确定范围(例如强制推送、第N-1次迭代的提交被squash合并)→ fallback到
      full
      模式并在固定评论中说明;绝对不要在没有
      prior_fix_range
      的情况下调用增量模式
  • 无对话历史、无会话上下文、无本次运行中其他subagent的结果
阈值内联问题纳入阈值直接内联到每个subagent的提示中(
security-reviewer-prompt.md
/
staff-engineer-prompt.md
/
sdet-prompt.md
/
spec-auditor-prompt.md
)。调度方无需预先添加阈值文本——subagent从自身提示中的内置部分应用阈值。这避免依赖调度方在每次调用时都正确注入阈值。

Incremental-mode subagent additions

增量模式下subagent的额外输出

In incremental mode, each subagent ALSO emits for every prior finding within its scope:
Prior finding status: <id>
verification: yes | unclear | no
note: <one-line — what evidence supports the verification>
Mapping to display status (in
## 🔄 Changes since last review
table):
verification
Display
yes
✅ Likely fixed
<sha>
<verification note>
unclear
⏸️ Untouched — <note: "file segment not in diff">
no
🔄 Still present — <note: "evidence still observable at <file>:<line>">
Never emit
✅ Fixed
without
verification: yes
. Default hedge is
Likely fixed
always — finality belongs to the human reviewer.
增量模式下,每个subagent还会针对自身范围内的每个之前的问题输出:
Prior finding status: <id>
verification: yes | unclear | no
note: <单行描述——验证依据>
映射到显示状态(在
## 🔄 Changes since last review
表格中):
verification
显示内容
yes
✅ Likely fixed
<sha>
— <验证说明>
unclear
⏸️ Untouched — <说明:"文件片段未在差异中">
no
🔄 Still present — <说明:"在<file>:<line>仍能看到相关证据">
绝对不要在没有
verification: yes
的情况下输出
✅ Fixed
。默认使用
Likely fixed
(可能已修复)——最终判定由人工审查者完成。

Fallback rules

fallback规则

  • 1 subagent fails → continue with rest; sticky header shows
    ⚠️ Partial — <subagent> failed
  • 2+ fail → continue with surviving findings; sticky header shows
    ⚠️ Partial — N/4 subagents failed: <names>
  • ALL fail → report failure to user, do not publish, never self-review
  • 1个subagent失败→继续使用其他结果;固定评论头部显示
    ⚠️ Partial — <subagent> failed
  • 2个及以上失败→继续使用可用结果;固定评论头部显示
    ⚠️ Partial — N/4 subagents failed: <名称>
  • 全部失败→向用户报告失败,不发布内容,绝不自行审查

Subagent Finding Contract

Subagent问题输出约定

Each subagent emits findings in this shape:
[<category-id> <category-name>] <file>:<line_start>-<line_end>
Severity: 🚨 | ⚠️ | 💡 | ❓
Confidence: high | medium | low
Blast: Local | Module | Cross-service | Data layer
Justification: Reachable | Precedent | Asymmetric | Historical

Evidence: <verbatim diff line(s) — cite-or-drop rule>
Failure mode: <one-line — what breaks if shipped as-is>
Mitigation: <one-line — fix action; cite test path when test coverage is part of the fix>
Details: <optional — multi-line narrative, repro steps, code patch. Use only when Failure mode genuinely needs more than one line>
Notes: <optional — only if severity differs from default>
Field semantics:
  • Failure mode
    — concrete bug / breach / drift consequence. Forces severity calibration: if you cannot describe what goes wrong in one line, you do not have a finding.
  • Mitigation
    — actionable fix. When the finding's resolution involves test coverage, name the test file and case (e.g.
    add assert in foo_test.py:42 'rejects empty input' case
    ).
  • Details
    — escape hatch for findings whose explanation cannot fit one line (e.g. multi-step race, cross-file impact chain). Keep
    Failure mode
    and
    Mitigation
    as one-liners regardless; put narrative here.
  • Justification
    — required class declaring why the finding is worth emitting. See Finding Inclusion Threshold below. Findings that cannot commit to one of the four classes MUST NOT be emitted as standalone findings; batch into a Q-class hygiene followup instead.
After findings, each subagent emits
N/A categories: [<list>]
declaring which of its owned categories were reviewed and clean. This distinguishes "checked, found nothing" from "skipped".
spec-auditor uses
Spec quote:
+
Code quote:
instead of single
Evidence:
— both must be verbatim quotes.
Failure mode
for spec findings = "what spec contract gets violated if shipped".
Drop rule: any finding without
Evidence:
(or both quotes for spec-auditor) is fabrication — discard before merge.
每个subagent输出的问题格式如下:
[<category-id> <category-name>] <file>:<line_start>-<line_end>
Severity: 🚨 | ⚠️ | 💡 | ❓
Confidence: high | medium | low
Blast: Local | Module | Cross-service | Data layer
Justification: Reachable | Precedent | Asymmetric | Historical

Evidence: <逐字差异行——引用或丢弃规则>
Failure mode: <单行描述——如果按当前状态发布会出现什么问题>
Mitigation: <单行描述——修复操作;如果修复涉及测试覆盖,需指明测试路径>
Details: <可选——多行叙述、复现步骤、代码补丁。仅当Failure mode确实需要超过一行描述时使用>
Notes: <可选——仅当严重性与默认值不同时使用>
字段语义:
  • Failure mode
    — 具体的bug/漏洞/偏离后果。用于校准严重性:如果无法用一行描述清楚问题,说明这不是一个有效问题。
  • Mitigation
    — 可执行的修复方案。如果问题的解决涉及测试覆盖,需指明测试文件和用例(例如
    add assert in foo_test.py:42 'rejects empty input' case
    )。
  • Details
    — 针对无法用一行解释的问题的逃生舱(例如多步骤竞态、跨文件影响链)。无论如何,
    Failure mode
    Mitigation
    必须保持为单行描述;将叙述内容放在此处。
  • Justification
    — 必填类别,说明问题值得输出的原因。详见下文问题纳入阈值。无法归入四个类别之一的问题不得作为独立问题输出;应归类为Q类卫生跟进问题。
输出问题后,每个subagent会输出
N/A categories: [<列表>]
,声明自身负责的哪些类别已审查且无问题。这用于区分“已检查,未发现问题”和“已跳过”。
spec-auditor使用
Spec quote:
+
Code quote:
替代单个
Evidence:
——两者必须为逐字引用。spec问题的
Failure mode
= "如果按当前状态发布,会违反哪些规范约定"。
丢弃规则:任何没有
Evidence:
(spec-auditor没有两个引用)的问题均为伪造内容——合并前需丢弃。

Finding Inclusion Threshold

问题纳入阈值

This gate is applied by each subagent inline before emitting a finding. Canonical definition lives in the subagent prompts, not here — see any of:
  • security-reviewer-prompt.md
    § Finding Inclusion Threshold
  • staff-engineer-prompt.md
    § Finding Inclusion Threshold
  • sdet-prompt.md
    § Finding Inclusion Threshold
  • spec-auditor-prompt.md
    § Finding Inclusion Threshold
All four contain the same Justification classes (Reachable / Precedent / Asymmetric / Historical), the same drop signals (A / B / C / D), and the same Asymmetric escape hatch. Per-prompt variations only add category-specific guidance (e.g. "most S1–S5 are Asymmetric" for security, "rare for T-class" for SDET).
Why duplicated across four prompts rather than referenced from one source: see Design note: prompt inlining.
Full vs incremental mode: full mode applies the threshold but drop signal (B) self-introduced surface never fires (no
prior_fix_range
on iter 1). Incremental mode applies all four signals.
Spec ambiguity rule (applies only to spec-auditor's C-class findings, kept in this SKILL.md as cross-cutting): if a candidate finding's mitigation offers "add a code comment" / "document the limitation in a comment" as an equal-weight resolution (phrasing "either X or document Y"), the finding is a Q-class spec gap addressed to the spec author, not P-class actionable. A comment-as-last-resort fallback ("do X; if impractical, document Y") keeps the finding actionable — the primary mitigation is what gets judged.
每个subagent在输出问题前会内联应用此阈值。标准定义位于subagent提示中,而非此处——可查看以下任意文件:
  • security-reviewer-prompt.md
    § Finding Inclusion Threshold
  • staff-engineer-prompt.md
    § Finding Inclusion Threshold
  • sdet-prompt.md
    § Finding Inclusion Threshold
  • spec-auditor-prompt.md
    § Finding Inclusion Threshold
四个文件包含相同的Justification类别(Reachable / Precedent / Asymmetric / Historical)、相同的drop signals(A / B / C / D)和相同的Asymmetric逃生舱。每个提示的差异仅为类别特定指导(例如安全类提示中“大多数S1–S5属于Asymmetric”,SDET提示中“T类很少属于Asymmetric”)。
为何在四个提示中重复而非引用单一来源:详见设计说明:提示内联优于引用间接
完整模式vs增量模式:完整模式应用阈值,但drop signal (B)自引入检查永远不会触发(第一次迭代没有
prior_fix_range
)。增量模式应用全部四个信号。
规范歧义规则(仅适用于spec-auditor的C类问题,作为跨领域规则保留在此SKILL.md中):如果候选问题的修复方案将“添加代码注释”/“在注释中记录限制”作为同等权重的解决方案(措辞为“either X or document Y”),则该问题为针对规范作者的Q类规范缺口,而非可执行的P类问题。如果注释是最后手段的 fallback(“do X; if impractical, document Y”),则问题仍为可执行问题——以主要修复方案为准。

Severity Merge Rule (deterministic precedence)

严重性合并规则(确定性优先级)

Apply in fixed order to each finding. Lower number wins on conflict.
  1. Base severity — assigned by subagent at finding emission (emoji form)
  2. Confidence demote
    confidence: low
    → demote to ❓ Question (terminal, no further escalation)
  3. Blast escalate
    blast: cross-service
    or
    blast: data-layer
    → escalate one level (max 🚨 Blocker). Skipped if step 2 already demoted.
  4. Context adjust — overrides from context input (e.g. "CDE service: security cannot downgrade") applied last
  5. Final severity — result after all four steps
  6. Map to P-code for output (dispatcher does this; subagents emit emoji severity only):
EmojiP-codeLabel
🚨 BlockerP0must fix; blocks merge
⚠️ FactualP1should fix
💡 SuggestionP2consider
❓ QuestionQclarify; not a priority tier
Severity ordering (for sort): P0 > P1 > P2. Q is orthogonal.
Downgrades (step 4 lowering a tier) MUST appear in the
Severity adjustments
section. Never silent. Never collapsed behind
<details>
— render as plain section when any adjustment exists.
按固定顺序应用于每个问题。冲突时,数字越小优先级越高。
  1. 基准严重性 — subagent输出问题时指定(表情符号形式)
  2. 置信度降级
    confidence: low
    → 降级为❓ Question(终止,不再进一步升级)
  3. 影响范围升级
    blast: cross-service
    blast: data-layer
    → 升级一级(最高为🚨 Blocker)。如果步骤2已降级,则跳过此步骤。
  4. 上下文调整 — 最后应用context输入中的覆盖规则(例如“CDE服务:安全问题不得降级”)
  5. 最终严重性 — 经过以上四步后的结果
  6. 映射到P-code 用于输出(由调度方完成;subagent仅输出表情符号严重性):
表情符号P-code标签
🚨 BlockerP0必须修复;阻止合并
⚠️ FactualP1应该修复
💡 SuggestionP2建议考虑
❓ QuestionQ需要澄清;非优先级问题
严重性排序(用于排序):P0 > P1 > P2。Q类与其他类别正交。
降级操作(步骤4降低级别)必须显示在
Severity adjustments
部分。绝对不能隐瞒。绝对不能放在
<details>
中——只要存在调整,就以普通章节形式显示。

Dedup (between subagent findings)

去重(subagent结果之间)

  • Same
    file:line
    + same category → keep highest base severity, attribute to all reporting subagents
  • Same issue described differently across subagents → merge into one finding with combined notes
  • Cross-cutting (e.g. staff-eng AND sdet both flag missing test for SQL injection) → keep both, dispatcher cross-references
  • 相同
    file:line
    + 相同类别 → 保留基准严重性最高的问题,注明所有报告该问题的subagent
  • 不同subagent以不同方式描述同一问题 → 合并为一个问题,合并相关说明
  • 跨领域问题(例如staff-eng和sdet均标记SQL注入缺少测试)→ 保留两个问题,调度方添加交叉引用

Output Language

输出语言

PR-published prose (sticky shape narrative,
Failure mode
/
Mitigation
/
Details
content, spec gap question body, verification notes, framing text around code refs) renders in the PR description's primary language. Everything else — markers, section titles, field labels, kebab-case slugs, P-codes, severity / justification / status tokens, the race meta tag — stays English.
Fallback when the PR description lacks substantive prose: linked issue body, then English.
Terminal / JSON output (
mode=local
JSON, dry-run console, noop message) stays English regardless of PR language — those go to callers, not the PR.
PR中发布的文本(固定评论叙述内容、
Failure mode
/
Mitigation
/
Details
内容、规范缺口问题正文、验证说明、代码引用周围的框架文本)使用PR描述的主要语言。其他内容——标记、章节标题、字段标签、短横线命名标识、P-code、严重性/理由/状态标记、竞态元标记——均保留英文。
如果PR描述缺乏实质性文本, fallback到关联的issue正文,再fallback到英文。
终端/JSON输出(
mode=local
JSON、dry-run控制台输出、noop消息)无论PR语言如何均保留英文——这些内容面向调用方,而非PR。

Output Format

输出格式

Two artifacts produced post-merge:
  1. Sticky comment — single issue comment on the PR; updated in place across iterations (PATCH same comment id)
  2. Inline review comments — one GitHub review submission (
    event=COMMENT
    ) containing one comment per P0 / P1 / P2 finding; Q findings stay in the sticky
Status tier (drives sticky header wording, NOT the actual GitHub review event):
ConditionWording
Any P0
🔴 Blocking issues found
No P0, any P1
⚠️ Review before merge
Only P2 / Q
✅ Approved with notes
Zero findings
✅ Approved
Any subagent failedprepend
⚠️ Partial — <details>
to the status
The skill does not submit
APPROVE
or
REQUEST_CHANGES
reviews. Status wording lives inside the sticky comment only. Auto-approve / auto-merge is forbidden.
合并结果后生成两个产物:
  1. 固定评论 — PR上的单个issue评论;迭代过程中就地更新(PATCH同一评论ID)
  2. 行内审查评论 — 一次GitHub审查提交(
    event=COMMENT
    ),包含每个P0/P1/P2问题对应的一条评论;Q类问题仅保留在固定评论中
状态层级(驱动固定评论头部措辞,而非实际GitHub审查事件):
条件措辞
存在任何P0问题
🔴 Blocking issues found
无P0问题,存在任何P1问题
⚠️ Review before merge
仅存在P2/Q问题
✅ Approved with notes
无任何问题
✅ Approved
存在任何subagent失败在状态前添加
⚠️ Partial — <details>
本技能不会提交
APPROVE
REQUEST_CHANGES
审查。状态措辞仅存在于固定评论中。禁止自动批准/自动合并。

Summary line (top of sticky)

摘要行(固定评论顶部)

Show only non-zero P-buckets + total + clean count. Zero suppression keeps the line scannable; incremental drift is communicated via the
Changes since last review
table, not by comparing zero counts.
**Review: <status>** · <total> finding(s) (<P0×N, P1×N, P2×N, Q×N — only non-zero>) · ✅ <N> clean
Examples:
**Review: ✅ Approved** · 0 findings · ✅ 11 clean
**Review: ✅ Approved with notes** · 1 finding (P2×1) · ✅ 11 clean
**Review: ⚠️ Review before merge** · 6 findings (P1×2, P2×3, Q×1) · ✅ 11 clean
**Review: 🔴 Blocking issues found** · 3 findings (P0×1, P1×2) · ✅ 11 clean
**Review: ⚠️ Partial — security-reviewer failed · ⚠️ Review before merge** · 2 findings (P1×2)
仅显示非零的P类问题数量 + 总问题数 + 已检查无问题的类别数量。隐藏零值使该行更易扫描;增量漂移通过
Changes since last review
表格传达,而非比较零值计数。
**Review: <status>** · <total> finding(s) (<P0×N, P1×N, P2×N, Q×N — 仅显示非零>) · ✅ <N> clean
示例:
**Review: ✅ Approved** · 0 findings · ✅ 11 clean
**Review: ✅ Approved with notes** · 1 finding (P2×1) · ✅ 11 clean
**Review: ⚠️ Review before merge** · 6 findings (P1×2, P2×3, Q×1) · ✅ 11 clean
**Review: 🔴 Blocking issues found** · 3 findings (P0×1, P1×2) · ✅ 11 clean
**Review: ⚠️ Partial — security-reviewer failed · ⚠️ Review before merge** · 2 findings (P1×2)

Category slugs

类别标识

Convert each subagent's
[<code> <name>]
to a kebab-case slug for output. Drop the subagent-owned code (S/E/T/C). Examples:
  • [E3 Conditional side effects]
    state-consistency
    (use semantic slug, not the literal name when one is more reviewer-meaningful)
  • [S3 Secret / credential]
    secrets-handling
  • [T1 Test coverage gaps]
    missing-coverage
  • [C4 Business rule alignment]
    decision-conflict
When semantic slug differs from the literal category name, prefer semantic. The slug is the navigation handle reviewers see; pick the term that conveys "what kind of problem" most directly.
将每个subagent的
[<code> <name>]
转换为短横线命名的标识用于输出。移除subagent专属代码(S/E/T/C)。示例:
  • [E3 Conditional side effects]
    state-consistency
    (使用语义标识,而非字面名称,选择对审查者更有意义的术语)
  • [S3 Secret / credential]
    secrets-handling
  • [T1 Test coverage gaps]
    missing-coverage
  • [C4 Business rule alignment]
    decision-conflict
当语义标识与字面类别名称不同时,优先使用语义标识。标识是审查者看到的导航句柄;选择最能直接传达“问题类型”的术语。

Sticky comment template

固定评论模板

markdown
<!-- pr-review:sticky -->
<!-- pr-review:sha=<HEAD> -->

> 🤖 Automated review by `pr-review` skill

**Review: <status>** · <total> finding(s) (<non-zero buckets>) · ✅ <N> clean

> <one-line shape narrative  what's the issue cluster; render in PR description language. English example: "observability + state-consistency form two P1 clusters; security clean">
markdown
<!-- pr-review:sticky -->
<!-- pr-review:sha=<HEAD> -->

> 🤖 由`pr-review`技能自动生成的审查

**Review: <status>** · <total> finding(s) (<非零分类>) · ✅ <N> clean

> <单行叙述——问题集群情况;使用PR描述语言渲染。英文示例:"observability + state-consistency form two P1 clusters; security clean">

📋 Currently open (<N>)

📋 当前未解决问题 (<N>)

  • <id> <P-code>
    <slug>
    <file>:<line>
  • ...
📍 Inline comments: <N> findings pinned to source lines (see the Files changed tab) — render this locator line in PR description language
  • <id> <P-code>
    <slug>
    <file>:<line>
  • ...
📍 Inline comments: <N> findings pinned to source lines (see the Files changed tab) — 此定位行使用PR描述语言渲染

⚖️ Severity adjustments

⚖️ Severity adjustments

<rendered only when ≥1 adjustment exists; NOT inside <details>; see template below>
<仅当存在≥1次调整时渲染;不要放在<details>中;详见下方模板>

🔄 Last iteration changes (
<last_sha>..<HEAD>
)

🔄 上次迭代变更 (
<last_sha>..<HEAD>
)

<rendered only in incremental mode; ONLY this iter's verifications, not cumulative; see template below>
<details><summary>📊 Overview by category</summary>
CategoryP0P1P2QFiles
<slug>
NNNN<file paths, comma-separated>
</details> <details><summary>❓ Spec gap questions (<N>)</summary> <rendered only when spec-auditor emitted gap items> </details> <details><summary>✅ Checked & clean (<N>)</summary>
  • <slug>
    : <one-line evidence — what specific patterns were verified clean, or which grep / file-read confirmed>
  • ...
</details>
🤖
pr-review
skill · reviewed
<base>..<HEAD>
<· last reviewed
<last_sha>
— incremental only>

Rules:

- Shape narrative mandatory when ≥2 findings; optional for 0-1
- `📋 Currently open` rendered **flat** (no `<details>`) when ≥1 finding is not yet `Likely fixed`; one bullet per finding, sorted P0→P1→P2→Q then by file path. Omit the section entirely when all findings are closed (avoid empty heading)
- `📊 Overview by category` always in `<details>` (collapsed); rows omitted where P0/P1/P2/Q are all zero. Collapsed by default — summary line already conveys totals; the table is for drill-down only
- `📍 Inline comments` line shown when ≥1 P0/P1/P2 finding posted inline; omit otherwise
- `Severity adjustments` rendered **flat** (no `<details>`) when any adjustment exists — discipline requirement, never silent
- `🔄 Last iteration changes` rendered **flat** in incremental mode; shows ONLY this iter's verifications (`<last_sha>..<HEAD>`), never cumulative across older iterations. Audit trail for older iters lives in git history (commits + prior inline comment threads), not in the sticky
- `Spec gap questions` always in `<details>` (collapsed) — verbose; secondary to actionable findings
- `Checked & clean` always in `<details>` (collapsed) — count is the load-bearing signal; expand for trust calibration
<仅在增量模式下渲染;仅显示本次迭代的验证结果,不显示累积结果;详见下方模板>
<details><summary>📊 按类别统计</summary>
CategoryP0P1P2QFiles
<slug>
NNNN<文件路径,逗号分隔>
</details> <details><summary>❓ 规范缺口问题 (<N>)</summary>
<仅当spec-auditor输出缺口项时渲染>
</details> <details><summary>✅ 已检查无问题 (<N>)</summary>
  • <slug>
    : <单行依据——验证了哪些特定模式无问题,或通过哪些grep/文件读取确认>
  • ...
</details>
🤖
pr-review
skill · reviewed
<base>..<HEAD>
<· last reviewed
<last_sha>
— 仅增量模式显示>

规则:

- 当存在≥2个问题时,必须添加叙述内容;0-1个问题时可选
- 当存在≥1个未标记为`Likely fixed`的问题时,`📋 当前未解决问题`部分**平铺显示**(不使用`<details>`);每个问题对应一个项目符号,按P0→P1→P2→Q排序,再按文件路径排序。当所有问题均已解决时,省略此部分(避免空标题)
- `📊 按类别统计`始终放在`<details>`中(折叠状态);P0/P1/P2/Q均为零的行省略。默认折叠——摘要行已传达总数;表格仅用于深入查看
- 当存在≥1个P0/P1/P2问题发布为行内评论时,显示`📍 Inline comments`行;否则省略
- 当存在任何调整时,`Severity adjustments`部分**平铺显示**(不使用`<details>`)——这是纪律要求,绝对不能隐瞒
- `🔄 上次迭代变更`在增量模式下**平铺显示**;仅显示本次迭代`<last_sha>..<HEAD>`中的验证结果,不显示跨旧迭代的累积结果。旧迭代的审计记录保存在git历史中(提交+之前的行内评论线程),而非固定评论中
- `规范缺口问题`始终放在`<details>`中(折叠状态)——内容冗长;优先级低于可执行问题
- `已检查无问题`始终放在`<details>`中(折叠状态)——数量是核心信号;展开用于信任校准

Severity adjustments section

Severity adjustments部分模板

markdown
undefined
markdown
undefined

⚖️ Severity adjustments

⚖️ Severity adjustments

#CategoryAdjustmentReason
#<n>
<slug>
<original-emoji + P-code> → <final-emoji + P-code><reason — one line>
undefined
#CategoryAdjustmentReason
#<n>
<slug>
<原始表情+P-code> → <最终表情+P-code><理由——单行描述>
undefined

Last iteration changes section (incremental only)

上次迭代变更部分(仅增量模式)

markdown
undefined
markdown
undefined

🔄 Last iteration changes (
<last_sha>..<HEAD>
)

🔄 上次迭代变更 (
<last_sha>..<HEAD>
)

PriorStatus
#<n> <P-code> <slug> (<file>:<line>)✅ Likely fixed
<sha>
<verification note>
#<n> <P-code> <slug> (<file>:<line>)🔄 Still present — <note>
#<n> <P-code> <slug> (<file>:<line>)⏸️ Untouched — <note>
#<n> Q <slug>⏸️ Awaiting spec author

Scope: **only findings whose status changed (or was re-confirmed) in this iteration's `<last_sha>..<HEAD>` diff**. Untouched findings carrying over from before `<last_sha>` belong in `📋 Currently open`, not here. The table is the delta, not the inventory.

Status legend (hedged on purpose — line-moved ≠ behaviour-fixed):

- `✅ Likely fixed <sha>` — subagent emitted `verification: yes` + note explaining what changed
- `🔄 Still present` — subagent emitted `verification: no` + note pointing to remaining evidence
- `⏸️ Untouched` — subagent emitted `verification: unclear` (file segment not in diff)
PriorStatus
#<n> <P-code> <slug> (<file>:<line>)✅ Likely fixed
<sha>
— <验证说明>
#<n> <P-code> <slug> (<file>:<line>)🔄 Still present — <说明>
#<n> <P-code> <slug> (<file>:<line>)⏸️ Untouched — <说明>
#<n> Q <slug>⏸️ Awaiting spec author

范围:**仅包含本次迭代`<last_sha>..<HEAD>`差异中状态变更(或重新确认)的问题**。`<last_sha>`之前未解决的问题属于`📋 当前未解决问题`,而非此部分。此表格显示的是增量变更,而非完整清单。

状态图例(故意使用模糊表述——代码行移动≠行为修复):

- `✅ Likely fixed <sha>` — subagent输出`verification: yes` + 说明变更内容的注释
- `🔄 Still present` — subagent输出`verification: no` + 指向剩余证据的注释
- `⏸️ Untouched` — subagent输出`verification: unclear`(文件片段未在差异中)

Inline comment body template

行内评论正文模板

One per P0 / P1 / P2 finding. Posted via GitHub Review API (single review,
event=COMMENT
).
markdown
**![<P-code>](https://img.shields.io/badge/<P-code>-<color>) <slug>**

**Failure mode**: <one-line>

**Mitigation**: <one-line; cite test path when applicable>

<details><summary>Evidence</summary>

```diff
<verbatim diff line(s)>
```

</details>

<sub>blast: <Local|Module|Cross-service|Data layer> · <reversible|not reversible> · confidence: <high|medium|low> · justification: <Reachable|Precedent|Asymmetric|Historical></sub>

<!-- pr-review:finding-id=#<n> -->
<!-- pr-review:justification=<Reachable|Precedent|Asymmetric|Historical|Hygiene> -->
The
justification
HTML marker is consumed by
pr-babysit
's diminishing-returns gate to decide whether to keep looping or hand back to the user.
Hygiene
value is reserved for batched Q-class hygiene followups; never emit
Hygiene
on a P0/P1/P2 finding.
Badge colors:
  • P0
    red
  • P1
    orange
  • P2
    yellow
reversible
derivation:
  • reversible
    — code-only change, additive feature, refactor without state migration
  • not reversible
    — destructive migration, breaking contract change, irreversible side effect (sent message, deleted data)
  • omit if ambiguous (don't guess)
每个P0/P1/P2问题对应一条行内评论。通过GitHub Review API提交(单次审查,
event=COMMENT
)。
markdown
**![<P-code>](https://img.shields.io/badge/<P-code>-<color>) <slug>**

**Failure mode**: <单行描述>

**Mitigation**: <单行描述;适用时指明测试路径>

<details><summary>Evidence</summary>

```diff
<逐字差异行>
```

</details>

<sub>blast: <Local|Module|Cross-service|Data layer> · <reversible|not reversible> · confidence: <high|medium|low> · justification: <Reachable|Precedent|Asymmetric|Historical></sub>

<!-- pr-review:finding-id=#<n> -->
<!-- pr-review:justification=<Reachable|Precedent|Asymmetric|Historical|Hygiene> -->
justification
HTML标记由
pr-babysit
的递减收益阈值使用,用于决定是否继续循环或交还给用户。
Hygiene
值保留给批量Q类卫生跟进问题;P0/P1/P2问题绝对不要输出
Hygiene
徽章颜色:
  • P0
    red
  • P1
    orange
  • P2
    yellow
reversible
推导:
  • reversible
    — 仅代码变更、新增功能、无状态迁移的重构
  • not reversible
    — 破坏性迁移、违反约定的变更、不可逆副作用(已发送消息、已删除数据)
  • 若不确定则省略(不要猜测)

Spec gap questions (in sticky
<details>
)

规范缺口问题(固定评论的
<details>
中)

markdown
undefined
markdown
undefined

❓ #<n> <spec-section-or-decision-id><one-line title>

❓ #<n> <spec-section-or-decision-id> — <单行标题>

<Blast>
· spec-author confirm
Spec quote: <verbatim>
Code quote: <verbatim>
Question for spec author:
  1. <numbered question>
  2. ...
<closing line, in PR description language — e.g. "not blocking the PR; want to clarify X">

Q findings do **not** become inline comments — they're often cross-file conceptual questions, pinning to a line misleads.
<Blast>
· spec-author confirm
Spec quote: <逐字引用>
Code quote: <逐字引用>
Question for spec author:
  1. <编号问题>
  2. ...
<结束语,使用PR描述语言——例如"不阻止PR;希望澄清X">

Q类问题**不会**成为行内评论——它们通常是跨文件的概念性问题,固定到某一行会产生误导。

What to drop from output

需要从输出中移除的内容

DropWhy
Capability: has_spec=Y · has_repo=Y · is_trivial=N
dispatch logic; reviewer doesn't care
Subagents: security ✅ · staff-eng ✅ · ...
which bots ran is process metadata — UNLESS one failed (then surface)
Source: <subagent>
per finding
reviewer wants "what kind of issue" (already in category), not "who found it"
<subagent>/
namespace prefix on slugs
leaks subagent identity; bare slug reads cleaner
Checked & clean
grouped under subagent headers
same — flat topic list
Empty
Severity adjustments
section heading
render section only when content exists
移除内容原因
Capability: has_spec=Y · has_repo=Y · is_trivial=N
调度逻辑;审查者无需关心
Subagents: security ✅ · staff-eng ✅ · ...
哪些bot运行属于流程元数据——除非某个bot失败(此时需说明)
每个问题的
Source: <subagent>
审查者想知道“问题类型”(已包含在类别中),而非“谁发现的”
标识中的
<subagent>/
命名空间前缀
暴露subagent身份;纯标识更简洁
按subagent分组的
Checked & clean
同理——平铺主题列表
空的
Severity adjustments
章节标题
仅当存在内容时才渲染章节

Publishing

发布

Runs after merge step. Skipped entirely when
dry-run: true
(print sticky + inline payloads to console instead) or when
mode: local
(emit findings JSON to stdout — see Local Mode).
dot
digraph publish {
  "Findings merged" [shape=doublecircle];
  "Build sticky body" [shape=box];
  "Build inline payload" [shape=box];
  "Find sticky comment" [shape=box];
  "Found?" [shape=diamond];
  "PATCH sticky body" [shape=box];
  "POST new sticky" [shape=box];
  "POST review with inline comments" [shape=box];
  "Done" [shape=doublecircle];

  "Findings merged" -> "Build sticky body";
  "Findings merged" -> "Build inline payload";
  "Build sticky body" -> "Find sticky comment";
  "Find sticky comment" -> "Found?";
  "Found?" -> "PATCH sticky body" [label="yes"];
  "Found?" -> "POST new sticky" [label="no"];
  "PATCH sticky body" -> "POST review with inline comments";
  "POST new sticky" -> "POST review with inline comments";
  "Build inline payload" -> "POST review with inline comments";
  "POST review with inline comments" -> "Done";
}
合并结果后执行。当
dry-run: true
时完全跳过(改为将固定+行内评论内容打印到控制台)
mode: local
时(向标准输出输出findings JSON——详见Local模式)。
dot
digraph publish {
  "Findings merged" [shape=doublecircle];
  "Build sticky body" [shape=box];
  "Build inline payload" [shape=box];
  "Find sticky comment" [shape=box];
  "Found?" [shape=diamond];
  "PATCH sticky body" [shape=box];
  "POST new sticky" [shape=box];
  "POST review with inline comments" [shape=box];
  "Done" [shape=doublecircle];

  "Findings merged" -> "Build sticky body";
  "Findings merged" -> "Build inline payload";
  "Build sticky body" -> "Find sticky comment";
  "Find sticky comment" -> "Found?";
  "Found?" -> "PATCH sticky body" [label="yes"];
  "Found?" -> "POST new sticky" [label="no"];
  "PATCH sticky body" -> "POST review with inline comments";
  "POST new sticky" -> "POST review with inline comments";
  "Build inline payload" -> "POST review with inline comments";
  "POST review with inline comments" -> "Done";
}

Commands

命令

bash
undefined
bash
undefined

1. find sticky id (may be empty)

1. 查找固定评论ID(可能为空)

STICKY_ID=$(gh api repos/$OWNER/$REPO/issues/$N/comments
--jq '.[] | select(.body | contains("<!-- pr-review:sticky -->")) | .id' | head -1)
STICKY_ID=$(gh api repos/$OWNER/$REPO/issues/$N/comments
--jq '.[] | select(.body | contains("<!-- pr-review:sticky -->")) | .id' | head -1)

2. write sticky body to a temp file (skill builds the markdown)

2. 将固定评论内容写入临时文件(技能构建markdown)

sticky.md should embed both markers: <!-- pr-review:sticky --> and <!-- pr-review:sha=$HEAD -->

sticky.md应嵌入两个标记:<!-- pr-review:sticky --><!-- pr-review:sha=$HEAD -->

3a. create new sticky

3a. 创建新的固定评论

[ -z "$STICKY_ID" ] && gh api -X POST repos/$OWNER/$REPO/issues/$N/comments
-F body=@sticky.md
[ -z "$STICKY_ID" ] && gh api -X POST repos/$OWNER/$REPO/issues/$N/comments
-F body=@sticky.md

3b. or patch existing sticky

3b. 或更新现有固定评论

[ -n "$STICKY_ID" ] && gh api -X PATCH repos/$OWNER/$REPO/issues/comments/$STICKY_ID
-F body=@sticky.md
[ -n "$STICKY_ID" ] && gh api -X PATCH repos/$OWNER/$REPO/issues/comments/$STICKY_ID
-F body=@sticky.md

4. post inline comments as one review (single API call)

4. 将行内评论作为一次审查提交(单次API调用)

inline-comments.json shape: [{"path": "...", "line": N, "side": "RIGHT", "body": "..."}, ...]

inline-comments.json格式: [{"path": "...", "line": N, "side": "RIGHT", "body": "..."}, ...]

gh api -X POST repos/$OWNER/$REPO/pulls/$N/reviews
-F event=COMMENT
-F body="See sticky summary above."
-F 'comments=@inline-comments.json'
undefined
gh api -X POST repos/$OWNER/$REPO/pulls/$N/reviews
-F event=COMMENT
-F body="See sticky summary above."
-F 'comments=@inline-comments.json'
undefined

Old inline comments

旧行内评论

Do not delete or resolve old inline review comments from prior iterations. GitHub auto-marks them
outdated
when the underlying line moves; the UI collapses outdated threads. This is the chosen trade-off (vs. graphql resolve) for operational simplicity.
请勿删除或解决之前迭代的旧行内审查评论。当底层代码行移动时,GitHub会自动将其标记为
outdated
;UI会折叠过时的线程。这是为了操作简便而选择的权衡(vs. graphql解决)。

Dry-run mode

Dry-run模式

When
dry-run: true
:
  • Print sticky body markdown to console (with markers)
  • Print inline payload as JSON
  • Skip all
    gh api
    writes
  • Useful for first-time use, debugging, or auditing output before publishing
dry-run: true
时:
  • 将固定评论markdown打印到控制台(包含标记)
  • 将行内评论内容打印为JSON
  • 跳过所有
    gh api
    写入操作
  • 适用于首次使用、调试或发布前审计输出内容

Design note: prompt inlining over reference indirection

设计说明:提示内联优于引用间接

Subagents (security-reviewer / staff-engineer / sdet / spec-auditor) operate as isolated
Agent
dispatches with no shared loader. They cannot follow a "see
references/X.md
" pointer at dispatch time — references load via the main session, not the subagent's. This inverts skill-creator's default duplication-avoidance principle: any policy a subagent MUST apply is inlined verbatim into each subagent prompt, not stored once in
references/
and pointed to.
Current inlined-duplicated content (intentional, not drift):
  • Finding Inclusion Threshold (Justification classes + drop signals A/B/C/D) — identical wording across all 4 subagent prompts; SKILL.md only points to them
  • Race-class Finding Metadata (
    [window=..., damage=..., recovery=...]
    meta tag spec) — identical across
    staff-engineer-prompt.md
    +
    security-reviewer-prompt.md
    ; pr-babysit's Gate B parser depends on identical syntax
Cross-prompt sync is maintained via
<!-- keep-in-sync: ... -->
HTML comments at each duplicated section header. When editing one, grep for the keep-in-sync marker to find paired sections.
Do NOT refactor inlined content into a shared
references/
file — the alternative regresses to the exact failure mode that motivated inlining. SKILL.md previously claimed "dispatcher prepends threshold at dispatch time" and that contract was never enforced (commit
328b73b8
fixed it by baking threshold into prompts; ⇒ this design note exists to prevent a future editor from re-introducing the same gap).
Subagent(security-reviewer / staff-engineer / sdet / spec-auditor)作为独立的
Agent
调度运行,无共享加载器。它们无法在调度时遵循“see
references/X.md
”的引用——引用内容通过主会话加载,而非subagent的会话。这颠覆了技能创建者默认的避免重复原则:subagent必须应用的任何策略都逐字内联到每个subagent的提示中,而非存储在
references/
中并通过引用指向。
当前内联重复的内容(故意设计,而非漂移):
  • 问题纳入阈值(Justification类别+drop signals A/B/C/D)——所有4个subagent提示中的措辞完全相同;SKILL.md仅指向它们
  • 竞态类问题元数据
    [window=..., damage=..., recovery=...]
    元标记规范)——
    staff-engineer-prompt.md
    +
    security-reviewer-prompt.md
    中的措辞完全相同;pr-babysit的Gate B解析器依赖于相同的语法
跨提示同步通过每个重复章节头部的
<!-- keep-in-sync: ... -->
HTML注释维护。编辑其中一个时,grep查找keep-in-sync标记以找到对应章节。
请勿将内联内容重构到共享的
references/
文件中——替代方案会回归到导致内联设计的完全相同的失败模式。SKILL.md之前声称“调度方在调度时预先添加阈值”,但该约定从未被强制执行(commit
328b73b8
通过将阈值嵌入提示修复了此问题;⇒ 本设计说明的存在是为了防止未来编辑者重新引入相同的漏洞)。

Notes

注意事项

  • Don't auto-approve or auto-merge — produce findings; merge belongs to humans
  • Lean conservative — low-confidence findings always demote to ❓ Question (Q)
  • Spec gaps don't block review — mark Q for spec author, proceed with code findings
  • Severity downgrades must be visible — flat section in sticky, never
    <details>
  • Don't auto-grep for spec location — use only what the user provides
  • Subagent reports are advisory — dispatcher applies merge rule and dedup, not subagents
  • Subagent failure must be surfaced — sticky header carries the partial-mode warning; never silent
  • Prior findings: hedge on "fixed" — always
    Likely fixed
    , never bare
    Fixed
    ; line-moved ≠ behaviour-fixed
  • Force-push aware — when last_sha is unreachable, fall back to full + announce in sticky
  • Output language is adaptive — PR-published prose follows the PR description's language; markers / titles / field labels / keywords / terms stay English. See Output Language
  • Local mode is JSON-only — no markdown, no sticky, no inline; caller (e.g. a supervisor session) consumes findings JSON and drives its own follow-up loop
  • 请勿自动批准或自动合并——仅生成审查结果;合并由人工完成
  • 保守原则——低置信度问题始终降级为❓ Question(Q类)
  • 规范缺口不阻止审查——标记为Q类供规范作者处理,继续进行代码问题审查
  • 严重性降级必须可见——在固定评论中以平铺章节显示,绝不放在
    <details>
  • 请勿自动查找规范位置——仅使用用户提供的内容
  • Subagent报告仅作为参考——调度方应用合并规则和去重,而非subagent
  • Subagent失败必须说明——固定评论头部显示部分模式警告;绝对不能隐瞒
  • 之前的问题:对“已修复”保持模糊——始终使用
    Likely fixed
    ,绝不使用单纯的
    Fixed
    ;代码行移动≠行为修复
  • 支持强制推送——当last_sha不可达时,fallback到完整模式并在固定评论中说明
  • 输出语言自适应——PR中发布的文本遵循PR描述的语言;标记/标题/字段标签/关键词/术语保留英文。详见输出语言
  • Local模式仅输出JSON——无markdown、无固定评论、无行内评论;调用方(如主管会话)消费findings JSON并驱动自身的后续流程