核心引擎 · 难度:进阶

ce-debug 流水线

独立的诊断-修复循环。五个阶段,不能跳过,测试先行的修复纪律,为调用方准备结构化返回。

ce-debug 是什么——以及不是什么
>

ce-debug 是唯一拥有"诊断 → 修复"契约的技能。它可以独立运行(交互式),也可以作为叶子被 ce-babysit-pr(CI 失败)或 lfg(缺陷路由)调用。它在没有显式授权时绝不打开 PR 或推送,也绝不为了 CI 变绿而削弱一条断言。

五个阶段

阶段发生什么参考
0分流:对输入分类——问题引用 / 堆栈跟踪 / 测试路径 / 描述references/investigate.md
1调查:拉取问题、复现、环境健全性检查、脏树暂存实验、回溯、跟踪器 / PR 历史搜索、假设锚定references/investigate.md + references/investigation-techniques.md(384 行)
2根因:完整的因果链 trigger→step→symptom;因果链门;发出 findings 段 + 修复方案选择问题references/investigate.md + references/anti-patterns.md
3修复:先开分支;记录修复前范围;编写回归测试;实施修复;pipeline 模式下仅限收敛修复references/fix.md
4交接:结构化返回 + 可选的 simplify / review / commit / PR 路由references/post-fix-handoff.md

不存在跳级——一个硬 bug 在每个阶段都会花更长时间;它不会进入更少的阶段。

阶段 2 的因果链门

在能完整陈述整条链(从触发到每一步再到观察到的症状)且无缺口之前,不能进入阶段 3。"不知怎么 X 导致 Y" 就是缺口。findings 段必须写到聊天里,打开"修复方案选择"阻塞问题;仅在"根因已确认"上发出问题,会让用户在看不到因果链的情况下做选择。

修复方案选择门

用户在循环中时(交互模式)有三个选项:

  1. 现在修 → 阶段 3。
  2. 只要诊断——剩下的我来 → 跳到阶段 4 的总结,结束本技能。
  3. 重新思考设计ce-brainstorm)——仅当 bug 无法在当前设计内修复时。根因是责任/接口/需求的错误,而不只是大小问题。

收敛 vs 发散 修复

这是无人值守运行的承载边界:

类型定义pipeline 模式下的动作
收敛 修复真实缺陷,使代码符合其既定/被测试过的意图(空解引用、差一、坏调用、对"编码了预期行为"的测试的回归) 应用 + 提交 + 推送
发散 会改变既定契约、API 形态、默认值或产品/UX 决策,而非修复一个 bug。或者:一个"失败"是断言一个故意行为的测试,而修复将把它反转。或者:让 CI 变绿需要一次产品/设计决策 延后——以带类型化决策上下文的 needs-human 返回;绝不应用
Trajectory 处理(震荡 vs 进展)

当编排器传入 trajectory(复现的 check、heads_since_progress 等)时,先就它做推理再修:

  • 渐进式失败迁移(A 已修、B 出现一次、B 已修、结束)→ 继续修。
  • 震荡(同一项 check 在针对它的修复之后又出现;修复用一个失败换另一个)→ 延后。A 与 B 无法在不做出更大变更的前提下同时成立。更大的变更是一次产品/设计决策。以 needs-human 返回,并指明两项失败的张力。
  • 移动目标守护:若复现源自 base-branch 合并 / 依赖 bump / flaky infra,继续修;那不是震荡。

Pipeline 模式

当以 mode:pipeline 调用(由 ce-babysit-prlfg)时:

结构化返回(mode:pipeline)

{
  "status": "fixed-and-pushed" | "fixed-not-pushed" | "diagnosed-no-fix" | "flaky-infra" | "needs-human",
  "summary": "<one line: what happened>",
  "root_cause": "<causal chain, brief>",
  "changed_files": ["..."],
  "head_sha": "<sha of the fix commit, when fixed-and-pushed or fixed-not-pushed>",
  "residuals": [{
  {
    "type": "needs-human",
    "sources": [
      { "id": "<failing-check-key>", "kind": "check" },
      { "id": "<owned-open-thread-id>", "kind": "thread" }
    ],
    "decision_context": {
      "quoted_feedback": "<the failure or constraint in in tension>",
      "investigation": "<what was inspected and found>",
      "decision_reason": "<why no bounded convergent fix is safe>",
      "options": [ { "option": "<choice>", "tradeoff": "<gain and loss>" } ],
      "recommendation": "<lean and why, or null>"
    },
    "thread_urls": ["<URL for every owned open thread, or empty when none>"]
  }]
}

状态定义

状态含义
fixed-and-pushed已应用收敛修复,测试通过,已提交,推送成功。
fixed-not-pushed同一修复已应用并在本地提交,但未发生推送。head_sha 是本地 commit。第一条残余说明原因。
flaky-infra基础设施失败,非代码缺陷(调用方可重试)。
diagnosed-no-fix已找到根因,但本次运行内没有可用的安全收敛修复。residuals[] 开放。
needs-human需要发散 / 产品决策;未应用任何东西。residuals[]

Return-to-caller 模式

当以 mode:return-to-caller 调用(由 lfg 在缺陷路由上)时:

交互式交接(两个问题)

阶段 3 之后(或诊断模式下跳过),编排器在任何提交发生前问两个问题:

  1. 什么可以进这次提交?仅 fix-owned 文件。若 fix-owned 文件已带有用户的编辑,三个选项:连同用户编辑一起提交 / 留 fix 不提交 / 停止。阶段 3 此前的确认只覆盖编辑,不覆盖把用户编辑与 fix 一起提交。
  2. 谁提交 + 是否发布?
    • 发布 通过 ce-commit-push-pr——仅当三条全部成立:修复前的树干净;分支上没有任何用户尚未主动提供的工作;origin 是能开 PR 的(gh 真能开 PR 的地方)。先预览,再调用。
    • 保持本地——其他情况下,调用 ce-commit,不推送任何东西。
    • 非 git 仓库——不提交任何东西;总结后停止。

尊重上下文覆盖:如果用户说过"不要让技能开 PR"、"只提交"或"修完就停",照做。模糊的语气信号不算覆盖。

选择回归测试

已确认缺陷的回归测试,落在已经存在覆盖该行为的归属处:从既有测试出发,不是新建文件。归属与命名规则在 references/fix.md——读它要在写阶段 2 的推荐之前,不是写到阶段 3 的编辑前才读。

一个测试因为变更故意反转了它所断言的行为而失败,它的预期没有错——那是发散情形,延后而非更新。

问题记录

若用户给了一个工单或问题,那里就是这个 bug 所在之处。把它的标识与 URL 一路带到阶段 4。若输入仅有堆栈跟踪、测试路径或描述,则本次运行没有问题记录。这是常态——无需 issue 记录就发版修复,永远不要为了凑记录而开一个工单。

升级而非蛮干

2–3 个假设已用尽而未确认,或3 次修复尝试失败:诊断为什么,而不是再试一次。这是 references/investigate.md 描述的明智升级。一个假设,一次变更;同时改几处看哪个管用,那是霰弹式调试。

参考