首页
/ ECC PR 队列治理实战:以 continuous-learning-v2 五层自循环守卫的合并审查为例解析 triage 决策链路

ECC PR 队列治理实战:以 continuous-learning-v2 五层自循环守卫的合并审查为例解析 triage 决策链路

2026-09-07 10:00:43作者:谭伦延

本指南以 ECC 仓库在 2026-03-13 记录的一份实时 PR 队列治理快照(docs/PR-QUEUE-TRIAGE-2026-03-13.md)为主体,完整还原"紧急 hotfix 追溯审查 → 开放队列逐项评估 → 归并性分桶 → 排序放行"的标准流程,并对照当前仓库源码逐层拆解被审查的 5 层自动会话守卫实现。读完你既能掌握一套可复用的 gh 驱动的 PR triage 方法论,也能理解 ECC observe 钩子如何避免自我观察(self-loop)这一典型自动化陷阱。

快照信息与 triage 数据来源

该文档是 everything-claude-code 拉取请求队列在 2026-03-13T08:33:31Z 的一份实时治理快照(Snapshot),其作用是把散落在各 PR 页面的状态收敛成一份"此刻队列健康度"报告。它使用四条数据来源,全部基于 GitHub CLI 的只读查询:

  • gh pr view:获取 PR 的 draft 状态、可合并性与基础描述;
  • gh pr checks:读取可见的 CI / Bot 检查结果;
  • gh pr diff --name-only:只看变更文件清单,快速评估影响面;
  • 针对合并头(merged head)的本地定向验证:#399 合并后,作者对 merge commit 指向的代码做本地核对。

本次扫描使用的"陈旧(stale)"判定阈值是:last updated before 2026-02-11,即截至 2026-03-13 超过 30 天未更新的 PR 视为陈旧。这份阈值定义是队列治理中关键的量化规则——没有它,"该先看哪个 PR"就会退化成主观偏好。

PR #399 追溯审查:一次紧急 loop-stop 修复的完整复盘

队列治理往往从"已合并 PR 的追认审查"开始,因为最近一次合并决定的质量直接决定后续队列评估的置信度。

基本信息与变更范围

问题背景:为什么需要"自动会话守卫"

ECC 的连续学习(continuous-learning-v2)机制中,observe.sh 作为 Claude Code 的 PreToolUse/PostToolUse 钩子在每一次工具调用时被触发,把调用记录写入 observations.jsonl;而 observer-loop.sh 是一个后台常驻循环,它会在观测数据累积到阈值后,再以 claude --print 非交互模式启动一个"分析会话"来归纳 instinct 文件。

问题由此产生:分析会话本身也是"工具调用",也会触发 observe 钩子;若钩子不区分调用方是人类还是自动化代理,就会形成 ECC 观察自己 Haiku observer 会话的自我观察死循环(self-loop),并污染其他工具的自动化会话元数据。这正是 #399 要消灭的核心缺陷。

五层守卫在源码中的逐层落位

对照当前仓库 observe.sh,可以确认这套守卫矩阵按顺序真实存在,且被刻意放置于项目检测逻辑之前——文件内注释明确警告:"keep these guards above detect-project.sh,因为 source detect-project.sh 会创建项目作用域目录并更新 projects.json,自动化会话必须在此之前返回"。五层依次为:

触发变量 / 载荷 语义 源码位置
Layer 1 CLAUDE_CODE_ENTRYPOINT 仅允许 clisdk-tsclaude-desktopclaude-vscode 四种交互式入口继续;其余入口一律 exit 0 observe.sh
Layer 2 ECC_HOOK_PROFILE=minimal minimal 钩子配置档案抑制非必要钩子 observe.sh
Layer 3 ECC_SKIP_OBSERVE=1 自动化会话主动"合作式跳过"环境变量 observe.sh
Layer 4 stdin JSON 中的 agent_id 子代理(subagent)会话天然属于自动化,只要载荷携带 agent_id 即退出 observe.sh
Layer 5 ECC_OBSERVE_SKIP_PATHS 已知 observer 会话路径排除,默认排除 observer-sessions,.claude-mem,对 STDIN_CWD 做子串匹配 observe.sh

需要特别说明的是 Layer 1 的处理策略:文档审查结论称之为 fail-closed(失败即关闭)形状——即无法确认是人类会话时默认不放行。注意与实现细节的一致性:sdk-ts 之所以在白名单中,是因为 Agent SDK 会话仍可能由人类经 Happy 等界面交互驱动,非交互的 SDK 自动化则交由 Layer 2–5 继续过滤(见 observe.sh 的注释)。

而作为呼应,observer-loop.sh 在启动分析子进程时显式设置 ECC_SKIP_OBSERVE=1 ECC_HOOK_PROFILE=minimal,即自动化分析端主动配合 Layer 2 与 Layer 3 完成闭环。

验证手段与测试矩阵

文档记录了对合并头 546628182200c16cc222b97673ddd79e942eacce 的四类验证:

  1. 语法检查:对两个变更后的 Shell 脚本执行 bash -n
  2. 全量钩子测试:运行 node tests/hooks/hooks.test.js,结果为 204 passed、0 failed;
  3. 定向钩子调用(targeted hook invocations),覆盖六类场景:
    • 交互式 CLI 会话(默认放行路径);
    • CLAUDE_CODE_ENTRYPOINT=mcp(应被 Layer 1 拦截);
    • ECC_HOOK_PROFILE=minimal(应被 Layer 2 拦截);
    • ECC_SKIP_OBSERVE=1(应被 Layer 3 拦截);
    • 携带 agent_id 载荷(应被 Layer 4 拦截);
    • 裁剪后的 ECC_OBSERVE_SKIP_PATHS(验证 Layer 5 匹配逻辑)。

可以印证的是,仓库测试目录中确实沉淀了针对这套守卫的回归测试,例如 tests/hooks/observe-entrypoint-allowlist.test.js 专门钉住 Layer 1 的 entrypoint 白名单(其头部注释还记录了更早的 #2102 修复:当时白名单缺 claude-vscode,导致 VS Code 扩展用户观察记录静默丢失)。

行为结果(Behavioral result) 三条:核心 self-loop 修复生效;自动化会话守卫分支按预期抑制了观察写入;最终的 non-cli => exit 入口逻辑是正确的 fail-closed 形态。

遗留发现与 verdict

审查没有止步于"能跑",而是给出了两条分层级的遗留发现:

  1. Medium 级:被跳过的自动化会话在守卫退出前仍会创建 homunculus 项目状态。原因在于 observe.sh 在到达守卫块之前就已经解析 cwd 并准备项目检测(从 stdin JSON 提取 cwd 并尝试 git rev-parse --show-toplevel),而真正 source 的 detect-project.sh 会在 L104/L142L232-L256mkdir -p 创建 projects/<id>/... 目录并更新 projects.json 注册表——即使该会话随后因守卫而提前 exit 0。换言之,守卫拦截了写入,却拦不住先行的项目注册副作用
  2. Low 级:新守卫矩阵没有随 PR 携带直接回归覆盖。钩子测试套件验证了相邻行为,但未直接断言 CLAUDE_CODE_ENTRYPOINTECC_HOOK_PROFILEECC_SKIP_OBSERVEagent_id、裁剪 skip-path 这些新分支。

最终结论(Verdict):就首要目标(紧急 loop-stop 修复)而言 #399 技术上正确、可安全合并;但仍需一个 follow-up issue 或补丁,把自动化会话守卫前移到项目注册副作用之前,并为守卫路径补充显式测试。

这一"合并通过 + 遗留项跟进"的双轨结论,正是把一次紧急修复从"堵住症状"推向"根因收敛"的关键动作。

开放队列盘点:4 个待办 PR 的实时快照

快照时刻开放队列共有 4 个 PR,无任何 PR 触发 >30 days 陈旧规则。原始队列表完整如下:

PR Title Draft Mergeable Merge State Updated Stale Current Verdict
#292 chore(config): governance and config foundation (PR #272 split 1/6) false MERGEABLE UNSTABLE 2026-03-13T07:26:55Z No Best current merge candidate
#298 feat(agents,skills,rules): add Rust, Java, mobile, DevOps, and performance content false CONFLICTING DIRTY 2026-03-11T04:29:07Z No Needs changes before review can finish
#336 Customisation for Codex CLI - Features from Claude Code and OpenCode true MERGEABLE UNSTABLE 2026-03-13T07:26:12Z No Needs manual review and draft exit
#420 feat: add laravel skills true MERGEABLE UNSTABLE 2026-03-12T22:57:36Z No Low-risk draft, review after draft exit

值得先读懂表中三个 GitHub 状态字段的判别价值,这是后续分桶判断的事实基础:

  • Mergeable(分支级可合并性)区分 MERGEABLE / CONFLICTING:冲突的 PR 连进入 review 的资格都没有,必须先行 rebase;
  • Merge State 区分 UNSTABLE / DIRTYUNSTABLE 表示分支本身可合并但 CI 尚未通过或被变更,DIRTY 则意味着存在冲突或未提交变更;
  • Draft 标志表达"作者认为尚未就绪"的意图信号,draft PR 不应被当作合并候选严肃对待。

逐 PR 评估:决策依据怎么摆

#292 — Governance / Config 基础(非 draft,MERGEABLE / UNSTABLE)

变更范围覆盖仓库根目录的治理与配置地基:.env.example.github/ISSUE_TEMPLATE/copilot-task.md.github/PULL_REQUEST_TEMPLATE.md.gitignore.markdownlint.json.tool-versionsVERSION(其中 .env.example.markdownlint.json.tool-versionsVERSION 在仓库根目录当前均真实存在)。

可见检查:CodeRabbitGitGuardian Security Checks 均通过。评估要点:

  • 当前队列中最干净的合并候选;分支已刷新到最新 main
  • 可见的机器人反馈属于 minor/nit 级别,不构成明显的合并阻塞;
  • 主要保留意见:当前只能看到外部 Bot 检查,gh pr checks 输出里没有出现 GitHub Actions matrix 运行

结论:Mergeable after one final owner pass——保守路径是先由人工快速过一遍 .env.example、PR 模板与 .tool-versions 的 nit 项再合并。

#298 — 大规模跨域内容扩展(非 draft,CONFLICTING / DIRTY)

范围:35 个文件,横跨 Java、Rust、移动端、DevOps、性能、数据与 MLOps 的文档及 skill/rule 扩充(当前仓库中的 rules/javarules/rustrules/react-native 等目录即属于这类领域内容的地基)。

可见检查:CodeRabbitGitGuardian Security Checkscubic · AI code reviewer 均通过。但评估结论依然是否定的,原因有三层:

  1. 与当前 main 冲突,分支层面已不可合并;
  2. cubic35 个文件中识别出 34 个问题,且这些 findings 是实质性与技术性的(覆盖多个新 skill 中破损或误导的示例),不是纯风格清理;
  3. 即便解决冲突,体量也决定了需要一次审慎的内容修正 pass,而不是快速合并决策。

结论:Needs changes。先 rebase 或重新叠层(restack),再解决示例质量缺陷;如果节奏重要,按领域拆分而不是扛一个超大型 PR。

#336 — Codex CLI 定制(draft,MERGEABLE / UNSTABLE)

提议修改的文件集中在 Codex 集成与全局 git 钩子路径,其文件路径在当前仓库中可一一对应:scripts/codex-git-hooks/pre-commitscripts/codex-git-hooks/pre-pushscripts/codex/check-codex-global-state.shscripts/codex/install-global-git-hooks.shscripts/sync-ecc-to-codex.sh(见 scripts/codex-git-hooksscripts/sync-ecc-to-codex.sh)。

评估要点:

  • 已不再冲突,但仍是 draft 且没有经过有意义的 first-party review;
  • 它改动的是用户全局 Codex 设置与 git-hook 安装行为,运行影响半径远超纯文档 PR;
  • 可见检查只有外部 Bot,缺少完整 GitHub Actions run;
  • 分支来自 contributor fork main,在变更状态前应额外做一次内容 sanity pass。

结论:Needs changes before merge readiness——所需的不是已被证明的代码缺陷修复,而是流程/审查向要求:完成人工审查、运行或确认 global-state 脚本验证、审查完成后再退出 draft。

#420 — Laravel Skills(draft,MERGEABLE / UNSTABLE)

提议范围与当前仓库中 rules/php(patterns / security / testing)、skills/laravel-patterns/SKILL.mdskills/laravel-security/SKILL.mdskills/laravel-tdd/SKILL.mdskills/laravel-verification/SKILL.mdskills/configure-ecc/SKILL.mdexamples/laravel-api-CLAUDE.md 这一组 Laravel 内容型资产对应。

评估要点:内容密集、运行风险低于 #336;但仍是 draft 且没有实质人工审查 pass;实时状态中没有任何指向合并阻塞器的信号——仅因仍是 draft 且审查不足,就不应合并

结论:Review next after the highest-priority non-draft work——作者准备好退出 draft 后即可成为优质审查对象。

归并性分桶:把状态翻译成动作

文档用四个分桶把上述判断收敛为可执行动作,这是一种值得借鉴的输出形态——桶的粒度比单条结论更适合驱动下一步:

  • 可立即合并或在 owner 最终审查后合并#292
  • 合并前需要变更#298#336
  • Draft / 在任何合并决策前需要审查#420
  • 陈旧(>30 天):无

推荐处理顺序与底线结论

推荐顺序(含理由):

  1. #292:当前最干净的实时合并候选;
  2. #420:运行风险低,但需等待 draft 退出并完成真正 review pass;
  3. #336:谨慎审查,因为它改动全局 Codex 同步与钩子行为;
  4. #298:先 rebase 并修复实质内容问题,再投入更多 review 时间。

Bottom Line(每条一句话,方便回归):

  • #399:安全的 bugfix 合并,仍值得一次清理类 follow-up;
  • #292:当前开放队列中最高优先级的合并候选;
  • #298:不可合并——冲突加实质内容缺陷;
  • #336:不再冲突,但 draft 且验证薄弱,未就绪;
  • #420:draft、低风险内容通道,待非 draft 队列处理后再审查。

实时刷新(Live Refresh)与三小时后的队列漂移

快照在 2026-03-13T22:11:40Z 做了一次刷新(距首版约 13.5 小时),这是队列治理中"快照不设最终版"思想的体现:合并状态会漂移,结论需跟随更新。

主分支origin/main 目前全绿(含 Windows 测试矩阵),主线 CI 修复不是当前瓶颈。

刷新后的队列读数

  • #292 仍是最可行动的 PR(Next actionable PR),最高信号剩余工作是合并前对 .env.example 与 PR 模板对齐的小范围正确性 pass,而非 CI 修复;
  • #420 的可见检查发生变化:CodeRabbit 因 PR 是 draft 而 skippedGitGuardian Security Checks 通过——注意观察这个细节:bot 检查本身也会随 draft 状态调整执行策略;
  • #336 明确被划入 manual-review lane, not immediate merge lane,因其触碰全局 Codex sync 与 git-hook 安装行为;
  • #298 仍是"最难的遗留 PR"(Last priority),必须先 rebase。

刷新后的最终顺序#292#420#336#298(与首版推荐顺序一致,但理由随检查状态漂移被强化)。

方法论沉淀:如何复刻这套 triage 决策链路

复盘整份文档,可以提炼出四条不依赖具体 PR 的可迁移规则:

  1. 量化陈旧规则:为"何时该被优先处理"设置显式时间阈值(本仓库为 >30 天),避免队列管理退化为直觉;
  2. 分层判断状态字段:先看分支级 CONFLICTING/MERGEABLE,再看 merge state DIRTY/UNSTABLE,再看 draft 意图信号,最后才进入内容评估——顺序错乱会导致把时间花在根本无法合并的 PR 上;
  3. 审查必须分离"功能正确"与"回归覆盖"#399 的 verdict 同时包含"技术上正确可合并"与"缺守卫路径直测",二者不冲突,但后者必须显式记入 follow-up 而非随合并消解;
  4. Bot 检查是信号不是结论CodeRabbitGitGuardiancubic 的通过/跳过状态需要与"是否有人类 review pass、是否有 GitHub Actions matrix run"交叉验证——本快照中多个 PR 都只有外部 Bot 可见,这本身就是需要保留意见的信号。

如果要在本地复现这套只读核验流程,#399 一节已给出可直接照搬的命令序列:gh pr viewgh pr checksgh pr diff --name-only 确认状态与影响面,再用 bash -nnode tests/hooks/hooks.test.js 完成本地验证,必要时配合 tests/hooks 目录下的定向回归测试(如 observe-entrypoint-allowlist.test.js)深入单条守卫路径。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388