停滞工作诊断
Adapted from paperclipai/paperclip (.agents/skills/diagnose-why-work-stopped) by paperclipai (MIT)
针对一类反复出现的问题的可复用排查程序:管理者或用户指着一个停滞、空转或过度恢复的任务树/自动化流水线问——「为什么停了?」「为什么在死循环?」「怎么保证不再发生?」
本技能是诊断+规则设计,不是修复工程。产出是一份写明根因的取证报告和一份经确认的规则方案。诊断阶段不落地任何代码变更。
何时使用
触发条件——任务标题或描述命中任意一条:
- 「为什么这个任务停了」「为什么卡住了」「怎么突然不动了」
- 「死循环」「空转」「一直重试」「恢复逻辑跑过头了」
- 「帮我查一下这条流水线的活性」「这棵任务树不转了」
- 要求先做取证/根因分析/书面结论,再做任何变更
何时不使用
- 任务要求直接修代码走正常工程流程——用正常排查。
- 是某个具体功能的普通 bug 报告——用正常调查。
- 你就是当初的实现者、被要求修自己的 bug——用正常调试。
三条不变量(必须同时守住)
每一条诊断结论、每一条 proposed 规则,都必须同时满足以下三条。它们是承重墙,任何一条被破坏的规则直接丢弃或返工:
- 有产出的工作要继续跑。 有明确下一步动作的任务必须持续推进,不需要人手动唤醒。
- 只有真阻塞才能停工作。 停止只能发生在真正无法推进时(缺审批、缺依赖、缺人工负责人)。伪停止(状态显示「审核中」却没有任何人在审、已取消的叶子节点挂在阻塞链上、元数据损坏)必须被识别并路由,不能静默放着。
- 不允许无限循环。 恢复逻辑与续跑逻辑必须有界,且与真正的有效推进可区分。
在方案里显式写出:每条不变量分别是怎么被守住的。
排查程序
0. 先读现行执行契约
动手前先弄清系统当前的状态语义:哪些状态算终态、哪些算显式等待、哪些算显式活跃、恢复/续跑边界在哪。在能说出你的新规则与现行契约差异之前,不许发明新规则。
1. 对点名对象做取证——先于一切
在同一拍内完成,不给出具体停止点就不许提规则:
- 打开被点名的任务/流水线及其阻塞链、父任务、恢复兄弟节点、近期运行记录。
- 逐节点遍历,找到让全局停摆的那一个确切的(对象, 状态)组合。常见形态:
- 状态是「审核中」,但没有任何执行参与者、没有活跃运行、没有待处理交互、没有恢复任务。
- 运行已成功结束、状态「进行中」,但没有任何后续动作排队。
- 阻塞链的叶子是已取消/已损坏/无权访问的对象。
- 恢复逻辑在成功运行之后反复唤醒同一个任务(超过 N 次)。
- 恢复逻辑把自己的恢复任务又当作待恢复的源工作——这是教科书级死循环,识别后拒绝加深。
- 引用证据:运行 ID、日志时间戳、状态迁移记录。「推断」仅在证据边界确实挡住直读时可用——必须显式声明并把该结论标记为暂定。
2. 调研近期的相关工作
提新规则前,先看同一区域最近已经上线了什么。与 48 小时前刚合并的方案相矛盾的「新规则」是返工,不是改进。
快速盘点:近期合并的相关变更;近期完结的、标题涉及活性/恢复/续跑的任务;正在进行的上层方案文档——修法也许应该并进已有方案,而不是另起炉灶。
在取证结论里写明:「我复查了 X、Y、Z。真正的缺口是……」
3. 给每个非推进项分类
对受影响范围内每一个没有终态、也没有活跃运行的对象,三选一:
| 分类 | 判定 | 必须写出 |
|---|---|---|
| 真需要人/上级介入 | 确实无法自动推进 | 负责人是谁、要做什么动作 |
| 可自动推进但没被路由 | 缺一条本应存在的路由规则 | 该有的规则是什么、该唤醒谁 |
| 已被覆盖 | 有活跃运行/排队唤醒/恢复任务/待处理交互 | 指向那个覆盖物 |
没有这张表,方案就是空谈。这是需求方反复要的那张表。
4. 把修法表述为通用契约,而非补丁
要的不是对被点名对象的的一次性修补,而是规则本身。两个检查:
- 规则以契约形式陈述,不是 if/else 补丁。范例契约:「每个由执行方负责的非终态对象,在每次心跳结束时必须处于终态、显式等待路径或显式活跃路径之一。」
- 规则与现行执行契约核对过;优先引用并套用已有契约,只有现行文档确实不完备或与已接受行为矛盾时才提议改文档。
- 规则显式保住三条不变量——把推导写出来。
- 反向检验:如果这条规则会拦住最近某次成功运行,删掉或收窄它。
5. 只做方案,不写代码
把方案写进报告文档,覆盖:
- 取证摘要(根因 + 证据)。
- 通用规则(契约形式)。
- 现行契约是否已覆盖该情形;若需改文档,改哪一段。
- 分阶段子任务:典型地,Phase 0 处置被点名的活对象(谨慎、不毁证据),Phase 1 把契约写进文档,然后才是检测、恢复、界面呈现、评审等实现阶段。
- 每阶段指明负责角色,用显式依赖串起阻塞关系,标出可并行分支。
此刻不创建子任务、不推代码。
6. 请求确认,然后才分解
- 针对最新一版方案发起确认请求。若需求方后续留言取代了方案,旧确认作废,针对新版本重新发起(循环几轮是正常的)。
- 只有获得接受后:才创建分阶段子任务并接好依赖。
7. Phase 0 卫生处置
清理活的现场,但不抹掉证据:
- 把没有参与者的「审核中」叶子挪回待办,写明精确的下一步动作和负责人。
- 把已取消/已死的阻塞物从链上摘除;不许为了清账静默把任务标成完成。
- 在原任务上留言总结改了什么、为什么;恢复链历史必须保留。
8. 收尾
阶段链全部完成后,在父任务上发一条面向全局的总结:改了什么、新契约是什么、上线步骤是什么、被点名对象的当前状态。然后关闭父任务。
常见坑
- 审批前写代码。 每次诊断类需求里需求方都说了「先出方案」。取证阶段产出代码是浪费一个来回。
- 保了一条不变量丢了另一条。 续跑收得太紧会卡住有效工作;恢复放得太开死循环就回来。三条必须一起查。
- 跳过近期工作调研。 提一条与 24 小时前刚上线的契约相矛盾的规则,是被拒最快的路。
- 把「审核中」当成完成。 分给了别的执行方、却没有任何参与者或活跃运行的叶子,不是进展,是停止。
- 绕过权限边界。 无权访问的取证对象要么走批准的路径,要么基于可达证据推断并显式标注,绝不越权。
- 递归恢复。 恢复逻辑恢复自己的恢复任务,是最经典的死循环。识别它,拒绝加深。
- 藏链子。 不许静默删除或隐藏症状性恢复任务——运维方需要完整的审计轨迹。
交付前核查清单
- [ ] 被点名对象的确切停止点已定位,附运行 ID / 日志 ID。
- [ ] 同区域近期上线的工作已调研并在结论中引用。
- [ ] 每个非推进项都已按「人必需 / 可路由 / 已覆盖」三分类。
- [ ] 规则以契约形式陈述,不是补丁。
- [ ] 三条不变量均显式保住。
- [ ] 取证这一拍没有落地任何代码变更。
- [ ] 针对最新方案版本的确认已发起。
- [ ] Phase 0 处置了活的现场且未销毁证据。
- [ ] 实现阶段指明了合适角色的负责人和依赖关系。