Agent Skillszts212653/clowder-ai › merge-gate

merge-gate

GitHub

定义合入 main 分支的标准化门禁流程,涵盖 Co-Creation Docs 特殊路径及基于五轴风险(行为/数据/安全等)的分级 Gate 策略。核心在于验证独立 Review Source、确保 Review Continuity 并防止 SHA 自噬环,确保代码合并的安全性与合规性。

cat-cafe-skills/merge-gate/SKILL.md zts212653/clowder-ai

Trigger Scenarios

执行 PR 合并操作前 需要验证代码变更的风险等级与审查状态

Install

npx skills add zts212653/clowder-ai --skill merge-gate -g -y
More Options

Non-standard path

npx skills add https://github.com/zts212653/clowder-ai/tree/main/cat-cafe-skills/merge-gate -g -y

Use without installing

npx skills use zts212653/clowder-ai@merge-gate

指定 Agent (Claude Code)

npx skills add zts212653/clowder-ai --skill merge-gate -a claude-code -g -y

安装 repo 全部 skill

npx skills add zts212653/clowder-ai --all -g -y

预览 repo 内 skill

npx skills add zts212653/clowder-ai --list

SKILL.md

Frontmatter
{
    "name": "merge-gate",
    "triggers": [
        "合入 main",
        "merge",
        "准备合入",
        "开 PR",
        "cloud review",
        "gh pr create"
    ],
    "description": "合入 main:按行为 \/ 数据 \/ 安全 \/ 契约 \/ 不可逆风险选择 targeted 或 full gate,并消费一个或多个有客观触发理由的独立 review source。",
    "tips_exempt": "harness\/SOP workflow change (merge-gate Step 7.5 dev-process gate); no end-user capability"
}

Merge Gate

SOP definition: sop-definitions/development.yaml stage merge

合入 main 的流程:先锁定风险档、验证命令与独立 review source,再执行对应门禁。PR 是载体,不是自动触发 local + cloud + guardian 三连的理由。

Lane 0:Co-Creation Docs PR

先检查是否已有成功的 pnpm classify:co-creation-docs 证据,且输出同时满足:

  • lane=co_creation_docs
  • delivery=pull_request
  • changed files 与 PR diff 完全一致

满足时,直接消费 classifier 的 validation / cloudReview / fullGate 结论:

  1. 跑 classifier 返回的全部 validation 命令 + git diff --check
  2. 新实质内容需要非作者内容 review;已有内容 verdict 或可证明机械合并用 continuityProof 复用,不为 SHA 字符串变化重开 reviewer。
  3. cloudReview=required 才触发 cloud;skip 时在 PR 留 classifier 原因。家规 / SOP / skill 纯文字通常由有状态 local reviewer 覆盖治理语义,不把“免 cloud”当需要申请的特权。
  4. fullGate=required 才跑 pnpm gateskip 时 evidence manifest 记录 docs validation 命令。
  5. evidence 闭合后由在场 merge owner 执行 gh pr merge --squash;不再额外召唤一只猫只为按 merge 按钮。无 F 号时跳过 Feature Doc Truth post-merge sync。

任一 changed file 不匹配、classifier 缺失/失败或输出 lane=regular_development → 退出本节,走下方风险路由。行数不能作为 Lane 0 证据。

核心知识

Risk-Routed Merge 门禁 5 条(全部满足才能合入)

  1. PR body 写清五轴风险判断:行为面 / 数据 / 安全 / 契约 / 不可逆;默认最小安全动作,升档理由可查。
  2. 至少一个非作者独立 review source(local 或 cloud)有明确 verdict;仅在不同高风险面需要不同视角时叠加,愿景守护另按 feature-close 触发。
  3. 所有 P1/P2 已修复,并由提出 finding 的活跃 source 覆盖当前 HEAD(含 Harness Diet Rebase Continuity 的 continuityProof 桥接)。
  4. 适用的 feature / BACKLOG 真相源没有过度声称,PR 载体与 changed files 匹配。
  5. 与风险匹配的 gate 全绿:低 / 中风险用 targeted commands;安全、鉴权、生产数据、迁移、外部契约或不可逆风险用 pnpm gate 全量。

默认只选一个合适的独立 source:家里语境与治理语义优先 local;context-blind 安全 / 契约代码扫描优先 cloud。动作类型(“开了 PR”“改了代码”)不是叠加理由。

Review Continuity Guard(review 是否真的覆盖当前 HEAD)

pnpm gate、rebase、fixup、biome 格式化刷新等都可能让 HEAD 变化。HEAD 变化只触发 provenance 判定,不自动等于 re-review:先分清 review 后是否真的改了本 PR 的内容、base 前进是否与本 PR 有逻辑关联;两者都没有,或只有可机械证明的派生物重建 / 规范化,旧 review 用 continuityProof 桥接。只有真实的作者 delta 或相关 base delta 回 active source,而且只看那一小块。

Report 载体铁则(斩断 SHA 自噬环,operator 2026-07-15 投诉②修复)review verdict 之后、merge 之前,不得再向被审分支 commit 任何 review report / handoff 信 / evidence 说明类文档——这类内容的合法载体只有 PR comment、thread 消息、tracking 系统。被审分支的 HEAD 只应因代码内容(含 rebase)变化。病灶机制:report 进分支 → SHA 变 → 旧 APPROVE 失效 → re-review → 新 report → SHA 又变(round-10 自噬环)。review 请求信(mailbox,reviewer 开审前已在 HEAD 内)不受此限。

但 continuity 不是一个布尔 reviewer。进入 merge-gate 后必须维护 Review Provenance Matrix,先判当前 HEAD 变化由谁产生,再决定下一步 gate owner,避免把 cloud / CI / PR check 的外部 gate 投射成本地旧 reviewer。

Intake admission guard:inbound intake 已携带有效、覆盖当前 HEAD 的独立 verdict 时,它就是 already-consumed exact-HEAD review;merge-gate 直接消费证据,nextGateOwner=author|merge_owner,不能把原 reviewer 当每个 callback 的固定下一棒。已完成 review generation 只有 behavioral_deltastale_or_blockingexplicit_matrix_route 三类理由可用 reviewReentry + durable evidenceRef 重开。纯 ACK、状态复述、cloud finding 或其他 no new information 的消息必须 clean-stop。

字段 记录内容
localPeerReviewSha Stage ③ local peer reviewer 放行覆盖的 SHA
cloudReviewSha 最新 cloud Codex review 明确覆盖的 SHA
currentHead PR 当前 headRefOid
headChangeCause local-gate / cloud-finding / ci-fix / rebase / pr-meta
nextGateOwner local-peer / cloud / ci / author / guardian

判定规则

  • headChangeCause = cloud-finding(cloud P1/P2/COMMENTED 修复后 push 新 SHA)→ nextGateOwner = cloud:只重新触发 cloud review + 等 PR tracking;禁止为了 cloud P1/P2 修复 @ 本地旧 reviewer
  • headChangeCause = ci-fix / local-gate 且声称只是非行为性 delta(import order、formatter)→ 先按 C1 证明 reviewed patch 的语义内容没变;证明成立则 author 留痕桥接,不请求 approval。仅凭“formatter / import order”标签或“命令 exit 0”不算证明;证明不了才把实际 delta 交 local peer。
  • headChangeCause = ci-fix / local-gate 且是非 cloud 的行为性 delta(代码、测试、配置、接口变化)→ local peer delta review;若超出原 review scope,按完整 local review 处理。
  • headChangeCause = pr-meta(只改 PR body/comment,不改 commit SHA)→ 不影响 local/cloud review coverage。
  • owned feature branch 在 pnpm gate / latest-main rebase 后 HEAD 变化时,发布 PR head 用 git push --force-with-lease origin {branch}。这是受 lease 保护的正常 rebase 发布动作,不是禁止项;禁止的是无证据 rewrite 共享/非 owned 分支或 main 历史。发布后按 Matrix rebase 行检查“作者 delta + base 关联 + gate”:满足则 continuity 默认有效,author 自决 + 留痕 skip=rebase-rereview;否则只让 active review source 覆盖真实变化部分。
  • cloud 额度/权限不可用时,才降级为另一只合格本地猫做完整 PR review;这不是把旧 reviewer 拉回来续签。

封板协议(LL-072,cloud re-review 循环的硬上限)

"cloud-finding 修复 → 重新触发 cloud review" 没有自然终点——cloud reviewer 是无状态抽样信号源(每轮重放全部历史 inline comments、不能分辨 stale/fresh、不读 pushback),在多 commit 累积 diff 上"0 P1/P2"这个条件没有不动点,等它说零等于无限循环(F168 PR #2214 实测 21 轮,R19 单轮 22 findings 中 21 个假阳性)。因此:

  1. 循环检测阈值(机械判定,无弹性):同一 PR cloud review 达到 5 轮,或单轮假阳性(stale 重放/已修重报)比例 >50% → 当轮处理完强制进入封板,不是继续修-触发循环。
  2. 封板动作:处理完当前轮全部 finding(真 P1/P2 修复 + 红绿测试;假阳性在 PR comment 有据 pushback)→ 不再 re-trigger cloud review,无论结果。终局确权交给本地有状态 reviewer 对最终 SHA 做 final review(核 pushback 成立性 + 全 diff continuity),放行即 merge。cloud 的角色定位:有贡献预算的辅助信号源,不是终局确权者。
  3. 介入循环时必须改写驱动循环的持久化指令:tracking instructions / hold 文案里若写有 "0 P1/P2 → merge" 类无不动点条件,拉闸者第一动作是改写它——只改修法不拆循环指令,执行猫会被旧指令拖回循环(F168 R16→R17 复活实证)。
  4. 同类 finding ≥3 轮(同一 stateful 对象/同一 fallback 族)→ 停手回 plan 层补状态契约(转移表+不变量),不是补第 4 个锅(LL/F229)。

进入 Step 7 之前,author 必须核对:

CURRENT_HEAD="$(gh pr view {PR_NUMBER} --json headRefOid --jq '.headRefOid')"
echo "$CURRENT_HEAD"
  • local/cloud 对应 source 的 review SHA = CURRENT_HEAD → 通过
  • local/cloud 对应 source 的 review SHA ≠ CURRENT_HEAD停止 merge-gate,先按 Review Provenance Matrix 判定 nextGateOwner
    • 纯 rebase / 可证明的机械 delta(Matrix rebase 行 C1–C3 满足)old review APPROVE + continuityProof(C1,C2,C3) ⇒ provenance 合法桥接 reviewedHead → CURRENT_HEAD = 通过,author 自决 + 留痕,无需 reviewer 任何表态。
    • 其他声称非行为性的 delta(biome 格式化刷新、import order):先做 C1 的 reviewed-patch 对照;可证明没有作者语义 delta 就桥接,证明不了才做 scoped delta review。
    • 行为性 delta(代码、测试、配置、接口变化): 按 source 重新 review;cloud finding 修复走 cloud re-review,非 cloud 行为 delta 走 local peer re-review
  • 只改 PR body / comment 不改 commit SHA → 不影响 review 覆盖范围

作者交接格式(ping reviewer / 汇报 merge-gate 时必须带):

  • 当前 HEAD:{short_sha}
  • localPeerReviewSha:{short_sha|none}
  • cloudReviewSha:{short_sha|none}
  • headChangeCause:{local-gate|cloud-finding|ci-fix|rebase|pr-meta}
  • nextGateOwner:{local-peer|cloud|ci|author|guardian}

Evidence Manifest(F253 Phase A — Review Provenance Matrix 超集)

merge-gate 执行时,在 Step 7(squash merge)之前,猫必须组装并验证 evidence manifest。evidence manifest 是 Review Provenance Matrix 的超集,从 PR metadata + gate 输出实时组装——不是独立存储的文件

字段定义

字段 来源 说明
head git rev-parse HEAD(当前 worktree) 当前 HEAD SHA
localPeerReviewSha Review Provenance Matrix 已有 本地跨猫 review 覆盖的 SHA
cloudReviewSha Review Provenance Matrix 已有 remote review 覆盖的 SHA
headChangeCause Review Provenance Matrix 已有 HEAD 变化原因
nextGateOwner Review Provenance Matrix 已有 下一步门禁所有者
gate_passed 适用 gate 的退出码 选定的 targeted 或 full gate 是否通过;不是由“regular PR”自动决定
gate_commands 实际执行的命令 逐条记录真实命令;高风险通常为 ["pnpm gate"],其他风险记录受影响检查 + git diff --check
trigger_reason 猫判断 五轴风险快照 + 为什么选择这些 gate / review source;动作类型不能单独充当理由
stale head vs headChangeCause 决定的活跃 review 源 headChangeCause(不是 nextGateOwner)判定哪个 review 源必须覆盖 headcloud-finding → 只看 cloudReviewShalocal-gate / ci-fix → 实际作者 delta 默认回 local,除非 C1 证明只是机械规范化;rebaseC1–C3 全满足时 continuity 默认有效,author 自决合入 + 留痕 skip=rebase-rereview,无需 reviewer pre-approval条款归因:operator directive([thread-id] msg 0001783847510596-000126-50011546)的原意是“diff 不涉及我们自己改的代码、没有相关联的逻辑关系 → 别 re-review”;C1 的证明方法与 C3 gate 是猫方实现,不得反过来静默加严原意。C1(作者 delta):比较 review 时的 authored patch 与 current authored patch;逐 commit stable patch-id 全部相同只是零 delta 的快路。不相同时必须显式列 postReviewDeltaPaths,不能把它送进 C2 冒充 base 相关性:①仅 canonical 派生物路径可在运行生成器后、再次运行得到零工作树 diff 时桥接;②仅 canonical formatter / normalizer 造成的变化,必须证明“对 reviewed 内容运行该命令得到的输出 == current blob”,且 current tree 幂等重跑零 diff;③机械三方合并可在逐冲突路径证明 current blob 只是 reviewed authored 内容与新 base 内容的无损并集、没有改写观点或行为时桥接(记录 reviewed/base/current 三方 diff 或等价证据);重叠处需要语义取舍就只审那个 hunk;④其余代码、测试、配置、接口或无法证明的 delta,只让 active source review 这些真实变化。C2(base 相关性)git diff --name-only <oldBase>..<newBase>(base 前进)与本 PR 的非派生物路径无交集,并留痕 baseDeltaDomains=<...> relation=none:<理由>;共享契约 / schema / export / 构建配置等跨文件耦合拿不准就只审关联部分。C3:rebase 后风险匹配的 gate / targeted tests 绿。continuityProof 在 rebase 前固定 reviewedHead/oldBase/newBase,rebase 后记录 currentHead;任一项不满足只使对应真实 delta stale,不让无关 commit 重审。pr-meta 不改 SHA;local-only / cloud-only 分别消费自己选择的 source。
continuityProof reviewedHead/oldBase/newBase/currentHead + C1 authored-patch 对照(快路 patch-id,或 postReviewDeltaPaths 与 canonical-output 等价证明)+ C2 base 交集与 relation= + C3 gate 结果 review provenance 桥接凭证;证明“review 后没有相关作者变化”,不是要求 SHA / range-diff 字面全等
verdict 猫判断 passed(review APPROVE on final HEAD 或经 continuityProof 桥接的 APPROVE)/ blocked(未 APPROVE)/ pending

组装时机:Step 6.9(Evidence Validation Checker)中组装,紧接在 Step 6.8 之后、Step 7 merge 之前。

与 Review Provenance Matrix 的关系:Evidence Manifest ⊇ Review Provenance Matrix。前 5 个字段 = Matrix 原有字段(改名 currentHeadhead),其余为 F253 新增的 gate/evidence 字段与 continuityProof 桥接凭证(准确计数随字段演进,以表为准——不再硬编码数字)。猫不需要维护两份——执行 merge-gate 时按 Evidence Manifest 全量检查即可,Matrix 是其子集。

Evidence Validation Checker(F253 Phase A — Step 6.9)🔴

位置:在 Step 6.8(Hotfix Cross-Cat Review Gate)之后、Step 7.5a(Feature Doc Truth 核对)之前执行。

5 项硬条件——任一不满足 → BLOCKED,不执行 merge

# 检查项 验证方式 失败动作
E1 head === PR current HEAD git rev-parse HEAD vs gh pr view {PR_NUMBER} --json headRefOid --jq '.headRefOid' BLOCKED — HEAD 不一致,可能有 unpushed commit
E2 stale === false headChangeCause 判定的活跃 review 源覆盖当前 head(见上方 stale 字段定义的完整映射表)。nextGateOwner=author 时(merge-ready 态),沿用最后一次 headChangeCause 确定的活跃源;nextGateOwner=ci/guardian 时,review 覆盖规则不变(CI/guardian 是额外 gate,不改变 review 覆盖链) BLOCKED — 补 continuityProof;只有真实新内容才 re-review
E3 reviewer provenance 闭合 至少一个按风险选定的 review 源(local 或 cloud)非空且覆盖 head;仅校验本 PR 实际选择的 source。「覆盖」三种合法形态:① review SHA == head 直接覆盖;② old review APPROVE + continuityProof(C1,C2,C3) 桥接 reviewedHead → head(Matrix rebase 行,桥凭证在 Evidence Manifest);③ 对话内容审 + author 机械转录(2026-07-16,operator 席位纠偏):reviewer 已在 thread 对同一内容给出明确 verdict(含 message 锚点),PR diff 与已审内容一致由 author 出机械证据git diff <已审 ref>..HEAD 为空 / patch-id 相同 / diff hash 对照)→ author 将 verdict 转录为 PR comment(带 thread 锚点 + 机械证据),reviewer 零二次出场席位原则:机械动作(对账/转录/落点确认)归 author 或机器,判断动作才归 reviewer——召唤 reviewer 的唯一合法理由是"存在需要判断力的新内容",两个字符串的相等判断不配烧一只 reviewer invocation BLOCKED — 缺 review provenance
E4 verdict !== "blocked" review 结果为 APPROVE(非 BLOCK / CHANGES_REQUESTED) BLOCKED — reviewer 未放行
E5 gate_passed === true 风险匹配的 targeted / full gate 已运行并通过,命令记录在 gate_commands BLOCKED — gate 未通过、未跑或与风险不匹配

通过时输出(cloud-finding 流程示例):

✅ Evidence validation passed
  head: abc1234
  headChangeCause: cloud-finding → active review source: cloud
  review coverage: cloud=abc1234 ✓ (local=def5678, not active for this headChangeCause — ok)
  gate: passed (pnpm gate)
  stale: false
  verdict: passed

通过时输出(local-only SKILL.md PR 示例):

✅ Evidence validation passed
  head: ghi9012
  headChangeCause: local-gate → active review source: local (risk-selected; no cloud)
  review coverage: local=ghi9012 ✓
  gate: passed (light path: biome + check:features + git diff --check)
  stale: false
  verdict: passed

失败时输出示例

❌ Evidence validation BLOCKED
  E2 FAIL: headChangeCause=cloud-finding → active source=cloud
           cloudReviewSha=def5678 ≠ head=abc1234
  → 需要重新触发 cloud review 覆盖当前 HEAD

不是脚本——是猫执行的 checklist。Phase A 的 evidence validation 是猫在 merge-gate 流程中人工检查 + 报告的步骤。如果需要自动化,可在后续 Phase 写 scripts/check-qc-evidence.mjs,但 Phase A 不做。

与已有 Review Continuity Guard 的关系:Review Continuity Guard 定义了"HEAD 变了怎么判 nextGateOwner"的规则;Evidence Validation Checker 在 merge 前执行这些规则的最终验证。前者是政策,后者是门禁。

Gate 选择 — targeted 默认,高风险 full

默认运行受影响检查 + git diff --check;现有精确检查已经红时,它就是 RED。确定性生成物刷新不为仪式感另造测试。

命中安全 / 鉴权 / 生产数据 / 数据迁移 / 外部契约 / 不可逆面,或 targeted 检查无法覆盖跨包合流风险时,运行 Latest Main 全量门禁:

pnpm gate
# 等价于 bash scripts/pre-merge-check.sh
# 自动执行:fetch origin/main → rebase → build → test → lint → check
# 高风险全绿才能继续开 PR。任一步骤失败 → 修复后重跑

为什么高风险需要这一步:quality-gate 和 request-review 跑的测试可能基于旧 base SHA。 并行开发中,其他猫的 PR 合入 main 后可能改变共享契约(类型/接口/store 结构), 导致你的代码在新 main 上 break。pnpm gate 在最终合流点做一次全量验证, 堵住"每只猫都说绿,合流后一堆红"的系统性漏洞。

full gate 三件套证据pnpm gate 通过后自动打印):

  1. 命令:pnpm gate(全量,不是 --filter
  2. SHA:基于最新 origin/main rebase 后的 HEAD SHA
  3. 状态:已 rebase 到最新 origin/main

Root Artifact Guard(Step 0.5,开 PR 前必跑)

ROOT_ARTIFACTS="$(git diff --name-only origin/main...HEAD | \
  rg '^[^/]+\.(png|jpe?g|webp|gif|webm|mp4|mov|wav|pdf|pen)$' || true)"

if [ -n "$ROOT_ARTIFACTS" ]; then
  echo "❌ 根目录存在媒体/设计工件(已提交差异),停止 merge-gate"
  printf '%s\n' "$ROOT_ARTIFACTS"
  echo "请先归档到 project-evidence/、docs/features/assets/F{NNN}/ 或其他正式目录。"
  exit 1
fi

这个检查和 Step 8 的脏工作树 fail-closed 互补:

  • Step 0.5 拦“已经进分支历史但放错位置”的文件
  • Step 8 拦“还在工作树里没处理的脏改动”

合入方式(唯一正确做法)

# 1. Push feature branch
git push origin {branch}

# 2. 开 PR(读 refs/pr-template.md 获取 body 模板,用 HEREDOC 填写)
gh pr create --title "feat(xxx): ..." --body "$(cat <<'EOF'
... 按 refs/pr-template.md 模板填写 ...
EOF
)"

# 3. 只注册当前真正阻塞你的显式等待(F280;不是订阅所有 PR 事件)
# → 调用 MCP: cat_cafe_register_pr_tracking(
#      repoFullName, prNumber,
#      when=[1–4 个 typed predicate],
#      nextStep="条件满足后的具体动作",
#      expiresAt=<future unix ms>
#    )
# 例:当前下一步是“CI 到终态后继续 merge-gate”:
#    when=[{kind:'pr_ci_terminal'}, {kind:'pr_became_conflicting'}]
# 若注册时 CI 已经终态,live baseline 会吸收历史,不补发;立即 `gh pr checks {PR}` 并继续。
# 等待目标变化时显式 re-register;新 generation 原子替换旧 generation,不叠加 tracker/hold。
# predicate catalog、compact wake 与 terminal 语义见 refs/pr-signals.md。
#
# 收到冲突通知时(F140 Phase B):
# - 暂停当前工作,处理冲突优先(冲突是 merge blocker)
# - 在对应 worktree 执行 rebase(参见 refs/pr-signals.md Phase B)
# - rebase 成功后继续原工作流
# - 复杂冲突 → 通知operator,等指示后再继续

# 4. PR body 防呆检查(禁止任何 @句柄出现在 body)
PR_BODY="$(gh pr view {PR_NUMBER} --json body --jq '.body')" || \
  { echo "❌ 无法读取 PR body,停止流程"; exit 1; }
printf '%s\n' "$PR_BODY" | rg -q '@[A-Za-z0-9_-]+ review' && \
  { echo "❌ 不合规:remote review 触发句柄只能写在 comment,不能写在 body"; exit 1; }
printf '%s\n' "$PR_BODY" | rg -q '@(codex|chatgpt-codex-connector|gpt52|opus|sonnet|gemini)\b' && \
  { echo "❌ 不合规:PR body 禁止出现任何 @句柄(含 HTML 注释中的签名)"; exit 1; }

# 5. 仅当风险路由选中 cloud 时触发remote review;local-only / guardian-only lane 跳过 5–6
#    (极简格式,在 PR comment 中,不是 body!)
# ⚠️ 只发 “@codex review” 一行,不带 SHA、不带规则描述、不带审查标准!
# 详细格式会让 Codex connector 误解为代码修改请求(2026-04-20 PR #1300 确认)
# 详见 refs/pr-template.md「云端 Review 触发 Comment 模板」

# 5.1 去重防呆
LAST_TRIGGER=”$(gh pr view {PR_NUMBER} --json comments | jq -r '
  [.comments[] | select(.body | test(“^@codex\\s+review\\s*$”; “m”))] | last | .url // empty
')”
# 有已触发 → 检查是否需要重发(新 commit / create-environment 回复 / 无 👀)

gh pr comment {PR_NUMBER} --body '@codex review'

# 6. 已选 cloud 时等remote review(事件驱动,不轮询)
#
# 6.1 👀 接单检测(触发后 5 分钟查一次)
TRIGGER_COMMENT_ID=”$(gh api repos/{OWNER}/{REPO}/issues/{PR_NUMBER}/comments \
  --jq '[.[] | select(.body | test(“^@codex\\s+review”; “m”))] | last | .id')”
EYES=”$(gh api repos/{OWNER}/{REPO}/issues/comments/${TRIGGER_COMMENT_ID}/reactions \
  --jq '[.[] | select(.content == “eyes” and .user.login == “chatgpt-codex-connector[bot]” and .user.type == “Bot”)] | length')”
#   - Codex connector EYES > 0 → 云端已接单 → 停止监控,注册 exact trigger 的 typed wait。
#     ⚠️ KD-27:此时必须释放 hold_ball,禁止续约轮询。typed wait 回调是唯一通知渠道。
#     如果你之前 hold_ball 轮询等接单,现在 connector EYES > 0 = 切换到事件驱动模式,不再 hold。
#     为让 routing guard 机械证明本 invocation 的 clean stop,必须用同 PR + exact trigger comment id
#     注册一次 server-bound wait(server 会独立验证 comment subject/body/reaction actor):
#       cat_cafe_register_pr_tracking(
#         repoFullName={OWNER}/{REPO}, prNumber={PR_NUMBER},
#         when=[{
#           kind:'pr_review_result_available',
#           triggerCommentId:Number(TRIGGER_COMMENT_ID)
#         }],
#         nextStep='Consume the exact-HEAD cloud review verdict.',
#         expiresAt=<future unix ms>
#       )
#     只有注册成功才可纯事件驱动停止;验证失败 / 503 均 fail closed,禁止把任意 active tracker
#     或一句“PR tracking 会叫我”当合法出口。
#   - connector EYES == 0 → 云端没接到 → 允许 re-trigger(进 6.2),可以 hold_ball 轮询等 EYES
#
# 6.2 允许再次触发的条件(满足任一即可):
#     a. HEAD SHA 变化(有新 commit)
#     b. 触发 comment 存在但 5 分钟后仍无 👀 reaction
#     c. 首次触发收到 “create an environment” 回复(= Codex 没接单)
#     其它情况一律禁止二次触发

# 6.5 Guardian Sign-Off Gate (F168 Phase D — community intake PRs only)
#
# Trigger condition: PR branch links to a community issue (check PR body or branch name).
# Skip this step for non-community PRs.
#
# Prerequisites: cat agent env vars $CAT_CAFE_INVOCATION_ID and $CAT_CAFE_CALLBACK_TOKEN
# are set by invoke-single-cat.ts at launch. All guardian endpoints require callback auth.
AUTH_HEADERS=(-H "X-Invocation-Id: $CAT_CAFE_INVOCATION_ID" \
              -H "X-Callback-Token: $CAT_CAFE_CALLBACK_TOKEN")
#
# 6.5.1 Request guardian assignment (if not already assigned):
ISSUE_ID="{COMMUNITY_ISSUE_ID}"  # from PR body or branch metadata
GUARDIAN_STATUS="$(curl -sf "${AUTH_HEADERS[@]}" \
  http://localhost:3004/api/community-issues/${ISSUE_ID}/guardian-status)"
HAS_GUARDIAN="$(echo "$GUARDIAN_STATUS" | jq -r '.hasGuardian')"
if [ "$HAS_GUARDIAN" != "true" ]; then
  # request-guardian returns guardianAssignment + signoffToken (for later guardian-signoff)
  ASSIGN_RESULT="$(curl -sf -X POST "${AUTH_HEADERS[@]}" \
    -H 'Content-Type: application/json' \
    -d "{\"author\": \"{AUTHOR_CAT_ID}\", \"reviewer\": \"{REVIEWER_CAT_ID}\"}" \
    http://localhost:3004/api/community-issues/${ISSUE_ID}/request-guardian)"
  SIGNOFF_TOKEN="$(echo "$ASSIGN_RESULT" | jq -r '.signoffToken')"
  # Refresh status after assignment
  GUARDIAN_STATUS="$(curl -sf "${AUTH_HEADERS[@]}" \
    http://localhost:3004/api/community-issues/${ISSUE_ID}/guardian-status)"
fi
#
# 6.5.2 Notify guardian via MCP (auto @ — AC-D1):
GUARDIAN_CAT="$(echo "$ASSIGN_RESULT" | jq -r '.guardianAssignment.guardianCatId')"
# Use cat_cafe_multi_mention to @ the guardian cat with intake checklist instructions.
# Pass SIGNOFF_TOKEN to the guardian so they can call guardian-signoff with it.
# The guardian cat receives the mention, reviews the checklist, and calls guardian-signoff.
#
# 6.5.3 Check sign-off status (blocking):
SIGNED_OFF="$(echo "$GUARDIAN_STATUS" | jq -r '.signedOff')"
if [ "$SIGNED_OFF" != "true" ]; then
  echo "❌ Guardian sign-off missing. Cannot merge until guardian completes intake checklist."
  echo "$GUARDIAN_STATUS" | jq .
  exit 1
fi

# 6.8 Hotfix Cross-Cat Review Gate(F177 Phase E)🔴
# 运行检测脚本(不纯依赖 label — 脚本扫 commit messages + PR title)
HOTFIX_OUTPUT="$(PR_NUMBER={PR_NUMBER} node scripts/check-hotfix-pattern.mjs --apply-label {PR_NUMBER} 2>&1 || true)"
HOTFIX_JSON="$(echo "$HOTFIX_OUTPUT" | tail -1)"
if ! echo "$HOTFIX_JSON" | jq empty 2>/dev/null; then
  echo "❌ Hotfix 检测脚本输出无效 JSON,停止 merge-gate(fail-closed)"
  echo "Output: $HOTFIX_OUTPUT"
  exit 1
fi
IS_HOTFIX="$(echo "$HOTFIX_JSON" | jq -r '.hotfix // false')"
LABEL_ERROR="$(echo "$HOTFIX_JSON" | jq -r '.labelError // empty')"
if [ -n "$LABEL_ERROR" ]; then
  echo "⚠️ Hotfix label 添加失败: $LABEL_ERROR — 请手动: gh pr edit {PR_NUMBER} --add-label hotfix"
fi
if [ "$IS_HOTFIX" = "true" ]; then
  PR_AUTHOR="$(gh pr view {PR_NUMBER} --json author --jq '.author.login')"
  REVIEWERS="$(gh pr view {PR_NUMBER} --json reviews --jq '[.reviews[] | select(.state == "APPROVED") | .author.login] | unique | join(",")')"
  if [ -z "$REVIEWERS" ] || echo "$REVIEWERS" | grep -q "^${PR_AUTHOR}$"; then
    echo "❌ Hotfix PR 必须有跨猫 review 放行(禁止 self-merge)"
    echo "   Author: $PR_AUTHOR | Approved by: ${REVIEWERS:-none}"
    exit 1
  fi
  echo "✅ Hotfix cross-cat review: Author=$PR_AUTHOR, Approved by=$REVIEWERS"
fi

# 6.9 Evidence Validation Checker(F253 Phase A)🔴
#   组装 evidence manifest → 验证 5 项硬条件(E1-E5)→ 通过才继续
#   → 详见上方「Evidence Validation Checker(Step 6.9)」
#   E1: head === PR current HEAD
#   E2: stale === false (review SHA covers head)
#   E3: reviewer provenance 闭合
#   E4: verdict !== "blocked"
#   E5: gate_passed === true
# 7.5a Pre-merge: Feature Doc Truth 核对(在 merge 之前!)🔴
#   拿这个 PR 的代码现实对账 feature doc 当前的声称,确认 doc 没对 main 撒谎。
#   机械兜底(已含在 Step 0 `pnpm gate`)——硬拦明显 status↔timeline drift:
node scripts/check-feature-truth.mjs
# → 详见下方「Feature Doc Truth 核对(Step 7.5)」§ 7.5a(含人工核对项)

# 7. Squash merge(GitHub 处理,禁止本地 squash!)
# ⚠️ merge 退出码双向不可信 → cleanup 只由 PR truth(state=MERGED) 授权,退出码不能单独定性:
#    ① worktree false-fail(#2567 opus48 / #2837 Sol):gh 删远端 branch 后切回 main 被主仓 worktree
#       占用而拒绝("main is already used by <path>")→ 远端已 merged 但【非零退出】。非零 ≠ 失败。
#    ② merge queue / auto-merge(cloud P2-2):`gh pr merge --help` 明确 exit 0 可能只是入队 / 启用
#       auto-merge,PR 仍 OPEN 未 merged → 【exit 0 ≠ 已 merged】。盲信 exit 0 会 cleanup 未合的 PR。
#    ❌ 禁止凭退出码判 merge 成败或重跑 gh pr merge。
MERGE_RC=0
gh pr merge {PR_NUMBER} --squash --delete-branch || MERGE_RC=$?
# 定性:脚本查 gh pr view state,仅 state=MERGED 才授权 cleanup(回归测试 classify-merge-outcome.test.mjs)。
# 退出码三态——pending 不是失败,必须与真失败分开出口(cloud P2-4):
#   0 = PR truth 确认 MERGED(clean / worktree false-fail)→ 进入 7.5b/8 cleanup
#   3 = merge_pending(merge queue / auto-merge 已入队,PR 仍 OPEN)→ 不是失败,等 PR truth=MERGED 再 cleanup
#   1 = 真失败 / indeterminate(PR truth 不可得)→ 停下诊断,禁止盲目 retry 或 cleanup
node scripts/classify-merge-outcome.mjs --pr {PR_NUMBER} --merge-exit-code "$MERGE_RC"
CLASSIFY_RC=$?
case "$CLASSIFY_RC" in
  0) : ;;  # confirmed MERGED → 继续 7.5b/8 cleanup
  3)  # merge_pending:PR 入队 / auto-merge,未 merged。不是失败——不 cleanup、不 retry、不 abort。
      echo "⏳ PR 在 merge queue / auto-merge pending(未 merged)——不是失败,暂不 cleanup。"
      echo "   等它合完再 cleanup:轮询 gh pr view {PR_NUMBER} --json state 到 MERGED,"
      echo "   或 cat_cafe_hold_ball 等 PR state=MERGED(wakeWhen 跑 gh pr view ... 命令),MERGED 后再进 Step 7.5b/8。"
      exit 3 ;;
  *)  # 1(及其它非 0/3,如 2 bad-invocation)= 真失败 / indeterminate
      echo "❌ merge 未确认成功(真失败 / PR truth 不可得)——停止 merge-gate;人工核 PR 状态"
      echo "   gh pr view {PR_NUMBER} --json state,mergeable,mergeStateStatus  (不要盲目重跑 gh pr merge 或 cleanup)"
      exit 1 ;;
esac

# 7.5b Post-merge: 仅当本 PR 改变 feature truth 时同步状态 🔴
#   Phase / AC / Status 有真实 delta → 同步 + Timeline provenance → commit → 复跑 check-feature-truth
#   仅“发生了一次 merge”不是状态 delta;无 delta 则整段跳过,不制造 doc churn
# → 详见下方「Feature Doc Truth 核对(Step 7.5)」§ 7.5b

Step 7.5c: Runtime Activation Truth(按影响面触发)🔴

PR 触及 runtime 加载面(API / Web / MCP / L0 staging 等)时,merge 只证明代码落到 main,不证明 live runtime 已加载。合入后必须分别声明:

  • main=landed:<merge SHA>
  • live=dormant:<当前 runtime 未加载的证据>,或 live=activated:<授权与新实例验证证据>

默认终态是 live=dormant,不得自动同步或重启。只有operator显式授权后,才从持有 main 的 worktree 运行 ADR-039 唯一入口 pnpm start 完成 sync + build + restart;禁止进入 cat-cafe-runtime 手工 pull / build / restart。

激活后的验证必须来自新进程或新 invocation:至少证明 runtime HEAD 包含目标 merge SHA,并验证一个该 PR 改变的真实加载面。旧进程上的源码 diff、重复 delivery receipt、或 main 文件存在都不能冒充 live 生效。

尚未获授权时,带 Decision Packet 路由 @co-creator,把 durable 状态留为 live=dormant;等待人类回复不调用 hold_ball。只有完成授权后的启动与新实例 probe,才能改报 live=activated

Step 7.6: Hotfix 升级 Review Cron 注册(F177 Phase E)🔴

触发条件:Step 6.8 检测到 IS_HOTFIX = true 时执行;否则跳过直接进 Step 8。

时机:merge 完成后、清理前。delayMs: 1209600000(14 天)从注册时刻起算 ≈ 合入后 14 天。

操作:调用 MCP 工具 cat_cafe_register_scheduled_task

参数
templateId "reminder"
trigger {"type":"once","delayMs":1209600000} (14 天)
label "Hotfix 升级 review — PR #{PR_NUMBER}"
description "2 周升级 review:PR #{PR_NUMBER} 是 hotfix,需要三选一处置"
category "pr"
params {"message":"Hotfix PR #{PR_NUMBER} 合入已满 2 周。请三选一处置:1. 升级正式修复(开 feat)2. 接受永久方案(标记 permanent)3. 已不再相关(代码已重写/删除,标记 obsolete)"}

注册范围(2026-07-15 修订):仅对明确临时债务注册(修法自声明是权宜、欠正式方案);走了 hotfix 流程但修法本身已是终态的,留痕 reminder=not-needed:<理由> 免注册。注册失败不阻塞清理:记 telemetry / 留痕后继续 Step 8,事后补注册——调度器故障不该扣押 worktree(旧版 fail-closed 是自噬环)。

# 8. 更新本地 + 清理(fail-closed)
# ⚠️ 发现脏工作树就停止,不要“即兴”用 git stash -u 清理。
# 原因:git stash -u/--include-untracked 会删除 untracked 文件(内部 git clean),
# 在多 session 共享工作目录时可能导致其他 session 的未 commit 产出丢失。
if [ -n "$(git status --porcelain)" ]; then
  echo "❌ 工作树不干净,停止 merge-gate(fail-closed)"
  echo "请先处理改动后再继续。禁止使用 git stash -u/--include-untracked。"
  git status --short
  exit 1
fi
# 本段从主仓(持有 main 的 worktree)执行;7.5b 已 cd 至此,git checkout main 幂等 no-op。
# 勿在 feature worktree 执行 git checkout main(main 被主仓占用会被拒绝,见 7.5b)。
git checkout main && git pull origin main
git worktree remove ../cat-cafe-{feature-name}
git branch -d {branch-name} && git worktree prune

# 8.5 回收 review 沙盒(review-target-id 与 request-review 约定一致)
REVIEW_TARGET_ID="{review-target-id}"  # e.g. f113 or fix-redis-keyprefix
REVIEW_BASE="/tmp/cat-cafe-review/${REVIEW_TARGET_ID}"
if [ -d "$REVIEW_BASE" ]; then
  for sandbox in "$REVIEW_BASE"/*/; do
    [ ! -d "$sandbox" ] && continue
    # no-force 铁律(LL-012):有未保存改动 → 报阻塞,不硬删
    if git worktree list 2>/dev/null | grep -q "$sandbox"; then
      STATUS=$(cd "$sandbox" && git status --porcelain 2>/dev/null)
      if [ -n "$STATUS" ]; then
        echo "⚠️ Review 沙盒 $sandbox 有未保存改动,跳过"
        continue
      fi
      git worktree remove "$sandbox"
    else
      rm -rf "$sandbox"
    fi
  done
  rmdir "$REVIEW_BASE" 2>/dev/null
  echo "✅ Review 沙盒已回收: $REVIEW_BASE"
fi
git worktree prune  # 清理 dangling worktree references

remote review 选择与处理规则

⚠️ LL-033 教训:必须检查 inline code comments!

remote review 的 P1/P2 可能在 inline code comments 里,不在 review body 里。 gh pr view--json reviews 只返回 review body(可能显示"no major issues"), 但 inline code comment 里可能有 P1。

什么时候选 cloud

云端 Codex 没有 Clowder AI MCP,看不到 thread / memory / 家里 SOP 演化历史;它的价值是 context-blind 代码扫描,不是所有 PR 的第二张门票。

优先 local、默认不选 cloud

  • cat-cafe-skills/**、家规、SOP、治理 / discussion 等依赖家里语境的改动;
  • 风险低、targeted checks 精确、local stateful reviewer 足以覆盖的实现;
  • co-creation docs classifier 返回 cloudReview=skip

优先 cloud

  • secret / auth / SSRF / DoS / 生产数据 / 外部契约等高风险代码面;
  • 跨包或陌生代码,需要独立 context-blind 扫描;
  • inbound community PR 的 source-intent / 外部边界验证。

普通 packages/** 或 test 改动不因文件类型自动触发 cloud;先看五轴风险与 targeted coverage。若 local 与 cloud 同时使用,PR body 必须分别写明两者覆盖的不同风险面。未选 cloud 时记录 cloudReview=not-selected reason=<...>,不是“豁免申请”。

事故来源:PR #1661 的纯 SOP 改动在 local review 后又无意识触发 cloud;第二刀把“默认触发 + 申请豁免”反转为“有风险理由才选择”。

层级 A:通知已包含 severity(自动)

ReviewRouter 现在会在投递通知时主动拉取 review body + inline comments, 提取 P0/P1/P2 findings 并写入通知消息。如果通知里已有 severity header (Review 检测到 P1),说明有 actionable findings,必须处理

层级 B:merge 前软守护(手动确认)

即使通知层漏报(GitHub API 暂时不可用、新 commit 后内容变化), merge 前仍需执行以下检查作为兜底:

gh api --paginate repos/{OWNER}/{REPO}/pulls/{PR_NUMBER}/comments \
  --jq '.[] | select(.body | test("\\bP[012]\\b"; "i")) | {body: .body[:200], path: .path}'
  • 有 P1/P2 输出 → WARNING,确认是否已处理后再决定是否继续
  • 无输出 → 通过,继续 Step 7
  • 命令执行失败 → 不默认通过,排查原因或手动检查 PR 页面
结果 处理
0 P1/P2(review body + inline comments 都无) 通过,执行 Step 7
P1/P2 有复现证据 在 feature branch 修 → push → re-trigger review → 等通过
P1/P2 无复现证据 降级 P3,留 comment,视为通过
误报 留 comment 解释,视为通过
架构/改法建议(非 P1/P2) 过 VERIFY 三道门再决定改不改(见 receive-review VERIFY)。云端没有运行环境,理论推理 < 本地实测。改坏能跑的功能 = P0

Feature Doc Truth 核对(Step 7.5)🔴

为什么在 merge-gate 而不是 feat-lifecycle close:一个 Feature 拆 N 个 Phase/PR,如果等 close 才核对/更新文档,中间所有 session 冷启动读到的都是过时甚至说谎的状态。每次 merge 都是一次"代码现实 ↔ feature doc"对账——merge 前核对 doc 没撒谎,merge 后记录已合入。这不是只在最后做的事,是每个 PR 的增量动作。

7.5a — Pre-merge:核对 feature doc 是否说真话(在 Step 7 merge 之前)

merge 是把状态写进 main 的不可逆点(其他 session 立即读到)。合之前,拿这个 PR 的代码现实对账 feature doc 当前的声称,确认没有对 main 撒谎:

  1. 识别 Feature:从 PR title/branch 提取 F{NNN}(无 Feature ID → 跳过,纯 TD/hotfix 不需要)。
  2. 声称 vs 代码现实(人工 — 语义层机器判不了):
    • feature doc 里标 ✅ 的 Phase / 打勾的 [x] AC,这个 PR(及历史)的代码真做了吗?严防"doc 声称完成但代码是 stub / 没做"——糖衣包装"未做"(参 self-evolution「下次一定」)。
    • Status 行和真实开发阶段一致吗?(写 spec/spike 但代码已在跑 = 撒谎)
    • 反向:代码已做的,doc 漏记了吗?
  3. 机械兜底 node scripts/check-feature-truth.mjs(已含在 Step 0 pnpm gate):硬拦明显矛盾 —— Status 仍是 pre-development(spec/design/idea/draft/spike/...)但 ## Timeline 已有 merged PR 且无 reopen 标记。机器只抓这一类零歧义 drift,不替你判 AC/Phase 语义
  4. 核对不过 → 先修 doc 再 merge:doc 撒谎(过度声称 / 漏记 / Status 虚高)当场修正、commit、重新核对。禁止带着说谎的 doc 合进 main。

7.5b — Post-merge:记录已合入状态(在 Step 7 merge 之后)

⚠️ 切到持有 main 的 worktree 再 commitgh pr merge --squash --delete-branch 之后你仍在 feature worktree 上。直接 commit 会落到已合并/已删的 feature branch(或留脏工作树让 Step 8 fail-closed abort)。而且 worktree 开发场景下 main 由主仓 worktree 持有——在 feature worktree git checkout main 会被 git 拒绝(ref 已被另一 worktree 占用)。所以切到持有 main 的 worktree(而非 checkout):

# 找到持有 main 的 worktree(通常是主仓 cat-cafe/),cd 过去做 doc-sync:
MAIN_WT="$(git worktree list --porcelain \
  | awk '/^worktree /{wt=substr($0,10)} /^branch refs\/heads\/main$/{print wt; exit}')"
cd "$MAIN_WT" && git pull origin main   # 取回刚 squash 的 commit,doc-sync 落点切到 main

然后先判断这个 PR 是否带来 feature truth delta:Phase 完成、AC 达成/删除/签字、Status 推进。“PR merged”这个事实本身不是 feature truth delta;若三者均无变化,整段 7.5b 留痕跳过,Timeline 也不追加。

仅在存在上述 truth delta 时,在 main 上把这个 PR 带来的增量写进 feature doc:

  1. 更新 feature doc docs/features/F{NNN}-*.md
    • Phase 状态:本 PR 对应的 Phase 标记从 📋/🚧 → ✅
    • AC 打勾:本 PR 实际完成的 AC 项 [ ][x](只勾代码真做了的 —— 7.5a 已核对)
    • Timeline:为这次 truth delta 加一行 provenance:| {YYYY-MM-DD} | Phase {X} merged (PR #{N}) |
    • Status 行:第一个 Phase 完成 specin-progress;最后一个 Phase 视情况推进(done 留给 completion 愿景守护)
    • 不做:不动 Dependencies/Risk/Links(kickoff/completion 的事)
  2. Commit + push:只有 Phase / AC / Status 至少一项真实变化才会进入本段;Timeline 是该变化的 provenance,不能反过来把自己当成触发 commit 的理由。本 PR 未改变 feature truth → 留痕跳过,不产出空 doc commit 刷 main(churn + index 竞态源,2026-07-15 修订)。派生 index 由生成器 / merge finalizer 机器独占维护,不随手工 doc commit 顺手刷。message docs(F{NNN}): sync phase progress after PR #{N} merge(文档同步不需走 review)。
  3. 复验:再跑一次 node scripts/check-feature-truth.mjs —— 确认 post-merge 写入没引入新 drift(例如加了 merged Timeline 却忘把 spec 推进成 in-progress,lint 会抓)。

落点说明:7.5b 切到持有 main 的 worktree(通常是主仓)做 doc-sync;后续 Step 8 清理本就从主仓发起(git worktree remove ../cat-cafe-{name}),此时已在 main worktree,其 git checkout main 幂等 no-op。单仓无独立 feature worktree 时 git worktree list 只返回主仓,cd 即原地。

检查清单

  • (pre) doc 标 ✅ 的 Phase / 打勾 AC 都有代码支撑(没撒谎)
  • (pre) check-feature-truth 绿(无 status↔timeline drift)
  • (post, 有 truth delta 时) Phase / AC / Status 与现实同步,Timeline 记录同一 delta
  • (post, 有 truth delta 时) 复验 check-feature-truth 仍绿
  • (post, 无 truth delta 时) 已留痕跳过,未仅为 Timeline 制造 doc commit

Quick Reference

条件 检查方式
Reviewer 放行? 搜索明确信号词
P1/P2 清零? 检查 review 记录
BACKLOG 更新? grep '\[x\]' docs/ROADMAP.md
选中 cloud 时通过? review body + inline comments + gh pr checks {PR};未选 cloud 记录理由
Evidence validation 通过?(Step 6.9) E1-E5 五项全绿(head 一致 + review 不 stale + provenance 闭合 + verdict passed + gate passed)
Feature doc 说真话?(pre-merge) doc 标 ✅/打勾 AC 有代码支撑 + node scripts/check-feature-truth.mjs 绿
已合入状态记录?(post-merge) 有 Phase/AC/Status truth delta → 同步并加 Timeline provenance;无 delta → 留痕跳过

Common Mistakes

错误 正确
因为“regular PR / packages 改动”默认叠 local + cloud 先做五轴风险判断,默认一个合适的独立 source;高风险才按不同风险面叠加
PR body 里写了remote review 触发句柄 在 PR comment 里写(body 里写会触发代码修改权限而非 review)
PR body 或 HTML 注释里写了 @句柄(例如签名) PR body 禁止任何 @句柄,签名改为纯文本(如 codex / gpt52
触发 comment 带了多行描述(SHA/规则/审查标准) 只发 @codex review 一行,详细内容让 Codex 误解为代码修改请求
同一个 commit 连续发多条触发 comment 先做 Step 5.1 去重检查;只有新 commit 才 re-trigger
触发后立刻轮询或手动重触发 5 分钟后查 👀(Step 6.1);有 👀 = PR tracking 自动通知,释放 hold_ball 不再轮询(KD-27);无 👀 = 允许 re-trigger
修了 P1 没让 active source 覆盖新 HEAD local finding 回 local;cloud finding 才 re-trigger cloud
cloud P1/P2 修完后又 @ 本地旧 reviewer 续签 headChangeCause=cloud-finding → re-trigger cloud review + 等 PR tracking;本地 peer 不是 Stage ④ 常驻 gate
pnpm gate rebase / fixup 后不做判定就沿用旧 review 直接 merge 先对齐 headRefOid只要 HEAD 变了,先按 Review Provenance Matrix 判定 nextGateOwner(pure rebase 三条件全满足 = 合法 continuity + 留痕,见 rebase 行;未判定未留痕就沿用 = 违规)
owned feature branch 被 pnpm gate rebase 到新 main 后不敢 push 先用 range-diff / gate 输出确认 patch-equivalent 或 delta scope;然后 git push --force-with-lease origin {branch} 发布 PR head,再做 continuity / evidence validation
本地 git rebase -i 手动 squash gh pr merge --squash(GitHub 处理)
本地 merge 后 gh pr close gh pr close = 放弃,gh pr merge = 合入
gh pr merge 非零退出就判 merge 失败 / 重跑 worktree 里远端 merge 成功但本地切回 main 被拒也会非零退出(#2567 opus48 / #2837 Sol);Step 7 用 classify-merge-outcome.mjs 查 PR truth 定性——state=MERGED 进 cleanup、禁止重跑;真失败才 block
把 merge queue / auto-merge pending 当 merge 失败 abort exit 0 + PR OPEN = 入队 / auto-merge pending(不是失败,cloud P2-4);classify 给独立 exit 3,Step 7 case 3 分支等 PR truth=MERGED 再 cleanup——pending 不 cleanup、不 retry、不 abort、不标成 failure
选了 cloud 却没等结果就合入 选中的 source 必须覆盖 final HEAD 且 P1/P2 已处置;未选 cloud 不等待它
把截图/录屏/.pen 直接 commit 到仓库根目录 Step 0.5 Root Artifact Guard 先拦截;先归档再开 PR
跳过 evidence validation 直接 merge Step 6.9 五项 E1-E5 全过才能进 Step 7;不组装 evidence = 不知道 review 是否 stale
Merge 不核对 feature doc 说真话 Step 7.5a:标 ✅/打勾 AC 必须有代码支撑,check-feature-truth 绿,再 merge
Merge 无条件追加 Timeline Step 7.5b:先判 Phase/AC/Status truth delta;有才同步并记 provenance,无则整段跳过
Merge 后不清理 review 沙盒 Step 8.5 按 review-target-id 回收 /tmp/cat-cafe-review/

⚠️⚠️ 反面案例(PR #160)— 必须记住

错误行为

  • PR description 里签名写了 (@句柄)(在 HTML 注释里)
  • 后续说明评论又写了 @句柄

后果

  • 触发了 chatgpt-codex-connector 的“Create an environment”自动回复
  • remote review 没有实际执行,流程被噪声污染

硬规则(加粗执行)

  • PR body(含 HTML 注释)禁止出现任何 @句柄
  • 只允许在专用触发 comment 里使用标准触发模板(见 refs/pr-template.md)

常见 QA(云端 Review 触发)

Q1: 出现 "Create an environment for this repo",是不是 review 没权限?

不是。

⚠️ THIS IS NOT A REVIEW-PERMISSION ERROR. THIS MESSAGE IS ABOUT CODE-WRITE ENVIRONMENT PERMISSION.

最常见原因:comment body 里带了多行内容(SHA、审查标准、规则描述等),Codex connector 把它解析成了代码修改请求而非 review。即使第一行是 @codex review,附加描述在当前解析规则下仍会触发 code-write intent。

动作只发 @codex review 一行重新触发(同 SHA 不需要新 commit)。

gh pr comment {PR_NUMBER} --body '@codex review'

教训演进:2026-04-18 曾以为是"后台 bug / 没接单",2026-04-20 PR #1300 确认根因是详细格式触发 code-write 解析。极简格式是唯一可靠触发方式(PR #1258 + PR #1300 两次实战验证)。

Q2: PR 里看到小眼睛(👀)是什么意思?

小眼睛 = remote reviewer 已接单/已看到触发。

⚠️ EYES ICON MEANS "REQUEST RECEIVED", NOT "FAILED".

它不是失败信号,也不等于环境错误。后续是否通过,以 review comment / findings 为准。

Q3: 触发后多久需要再操作?

默认 不操作

  • 5 分钟后查一次 👀(Step 6.1):有 👀 = 已接单,PR tracking 会自动通知,猫猫不用管
  • 无 👀 = 云端没接到 → 允许 re-trigger
  • 有 👀 的情况下严禁重复触发

Q4: remote reviewer 没猫粮了怎么办?

云端 Codex 的"代码审查"额度独立于总额度,可能单独耗尽。此时降级到其他猫做 完整 PR review(不是跳过 review!):

原 reviewer 降级到 说明
Maine Coon Codex Ragdoll Opus 家族(47/48) 跨 provider family(Codex 和 GPT-5.4 共享 OpenAI API 池,一个没猫粮 = 都没猫粮)
Maine Coon GPT-5.4 Ragdoll Opus 家族(47/48) 同上——OpenAI 共享池
Ragdoll某个体 Ragdoll其他个体 / Maine Coon 同族或跨族
禁止 Siamese 不做代码 review(Bengal Opus 除外,底层是 Opus)

铁律:降级后仍须校验"reviewer ≠ 作者"——降级表是建议顺序,不能覆盖 self-review 禁令。

⚠️ 共享 API 池陷阱(F238 教训):同一 provider 的不同 model(Codex/GPT-5.4/GPT-5.5)共享 API 额度。降级必须跨 provider family(OpenAI → Anthropic),不能在同 provider 内换个体。

操作:gh pr comment {PR} --body "..." 用标准触发模板 @ 降级 reviewer(句柄查 cat-config.json)。

和其他 skill 的区别

  • quality-gate: 自检(在 review 之前)
  • request-review / receive-review: review 循环(在 merge 之前)
  • 本 skill: review 通过后的合入全流程

下一步

合入后判断 feature 规模:

最后一个 Phase(或小 Feature)feat-lifecycle completion:

  1. 自己做愿景三问。
  2. 用户可见、产品方向或愿景发生变化 → @ 非 reviewer、非作者的猫做愿景守护;这是终态风险触发,不是每个 PR 固定第三审。
  3. 纯内部机械 change 且没有 feature-close 愿景面 → 记录 guardian=not-triggered reason=<...>,不为流程完整度召唤守护猫。
  4. 守护触发时:放行才 close;踢回则修改并跑与 delta 匹配的验证。

中间 Phase(大 Feature,3+ Phase) → Phase 文档同步(Step 7.5 已做)+ 主动碰头operator

  1. 成果展示(截图 / demo / 关键改动)
  2. 愿景进度(哪些 AC ✅ 了)
  3. 下个 Phase 方向 + 新发现
  4. "方向对吗?" → operator确认 → 继续下一个 Phase

CI Repair Loop (F253 Phase C)

When CI fails after push:

  1. Read CI output → classifyCiError(output) (from scripts/classify-ci-error.mjs) → get error class + deterministic flag
  2. If non-deterministic → escalate immediately (post to thread, @ author)
  3. If deterministic + round < 2 → run autoFixCommand, commit, push
  4. If deterministic + round ≥ 2 → escalate (same error class won't auto-fix after 2 tries)
  5. Track round count via PR label ci-repair-round:N

Allowlisted auto-fixes: biome format, biome lint (non-suspicious) Never auto-fix: test failures, type errors, lint/suspicious, unknown errors

Use shouldAutoFix(classification, sameClassRound) to check the protocol. State machine: idle → attempt_1 → attempt_2 → escalated (terminal).

Version History

  • 06263d9 Current 2026-08-06 20:20
  • f30e20c 2026-08-05 06:06

    新增 Lane 0 Co-Creation Docs PR 处理逻辑;细化风险路由与独立 review source 消费规则;明确 Report 载体铁则以阻断 SHA 自噬环;优化 Review Provenance Matrix 判定逻辑。

  • 4167cb0 2026-07-05 14:52

Same Skill Collection

cat-cafe-skills/anime-forge/SKILL.md
cat-cafe-skills/bootcamp-guide/SKILL.md
cat-cafe-skills/browser-automation/SKILL.md
cat-cafe-skills/browser-preview/SKILL.md
cat-cafe-skills/co-creation-docs/SKILL.md
cat-cafe-skills/code-as-harness/SKILL.md
cat-cafe-skills/collaborative-thinking/SKILL.md
cat-cafe-skills/concept-demo-design/SKILL.md
cat-cafe-skills/console-dev/SKILL.md
cat-cafe-skills/context-self-management/SKILL.md
cat-cafe-skills/convention-graph-discovery/SKILL.md
cat-cafe-skills/cross-cat-handoff/SKILL.md
cat-cafe-skills/cross-thread-sync/SKILL.md
cat-cafe-skills/debugging/SKILL.md
cat-cafe-skills/deep-research/SKILL.md
cat-cafe-skills/enterprise-workflow/SKILL.md
cat-cafe-skills/eval-design/SKILL.md
cat-cafe-skills/expert-panel/SKILL.md
cat-cafe-skills/feat-lifecycle/SKILL.md
cat-cafe-skills/fresh-context-review/SKILL.md
cat-cafe-skills/guide-authoring/SKILL.md
cat-cafe-skills/guide-interaction/SKILL.md
cat-cafe-skills/hyperfocus-brake/SKILL.md
cat-cafe-skills/image-generation/SKILL.md
cat-cafe-skills/incident-response/SKILL.md
cat-cafe-skills/knowledge-engineering/SKILL.md
cat-cafe-skills/memory-navigation/SKILL.md
cat-cafe-skills/open-source-teardown/SKILL.md
cat-cafe-skills/organize-threads/SKILL.md
cat-cafe-skills/pencil-design/SKILL.md
cat-cafe-skills/ppt-forge/SKILL.md
cat-cafe-skills/proactive-memory-judgment/SKILL.md
cat-cafe-skills/quality-gate/SKILL.md
cat-cafe-skills/receive-review/SKILL.md
cat-cafe-skills/request-review/SKILL.md
cat-cafe-skills/rich-messaging/SKILL.md
cat-cafe-skills/schedule-tasks/SKILL.md
cat-cafe-skills/self-evolution/SKILL.md
cat-cafe-skills/source-audit/SKILL.md
cat-cafe-skills/sprite-forge/SKILL.md
cat-cafe-skills/tdd/SKILL.md
cat-cafe-skills/tech-writing/SKILL.md
cat-cafe-skills/thread-orchestration/SKILL.md
cat-cafe-skills/ttfund-skills/SKILL.md
cat-cafe-skills/video-forge/SKILL.md
cat-cafe-skills/vision-rescue/SKILL.md
cat-cafe-skills/workspace-navigator/SKILL.md
cat-cafe-skills/worktree/SKILL.md
cat-cafe-skills/writing-plans/SKILL.md

Metadata

Files
0
Version
06263d9
Hash
89380e2a
Indexed
2026-07-05 14:52

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-07 12:05
浙ICP备14020137号-1 $Carte des visiteurs$