转为工单
功能简介¶
to-tickets 接受一个计划、一个规格或你当前的对话,并将其分解为工单跟踪器上的一组工单。每个工单都声明其阻塞边:必须先完成的其他工单。
每个工单都是一颗曳光弹:一条狭窄但完整的路径,贯穿变更的每一层(schema、API、UI、测试),一旦落地便能独立演示。这正是该技能与显而易见的拆分方式(一次切割一层、最后再集成)的不同之处。它还会把每个工单的规模控制在一个全新的上下文窗口内,因为一个从未见过你规格的会话也能接手这个工单。
何时使用¶
你通过输入 /to-tickets 来调用它。智能体不会主动使用它。
| 你处于什么情况 | 运行什么 |
|---|---|
| 你有一个规格工单,且构建横跨多个会话 | /to-tickets,或 /to-tickets #<spec_issue> |
| 计划只在对话中,从未写下来 | /to-tickets 直接读取对话线程,无需规格 |
| 整个变更适配一个上下文窗口 | 使用 implement,跳过工单 |
| 尚未做出任何决定 | 先 grill-with-docs,再 to-spec |
| 一张 wayfinder 地图已经清晰 | 先 to-spec 把地图收敛,然后 /to-tickets |
to-tickets 生成的工单天然就是智能体就绪的。不要对它们运行 triage。triage 适用于来自其他人的工作。
前提条件¶
to-tickets 会发布到工单跟踪器中,因此 setup-matt-pocock-skills 必须已经为此仓库配置好一个跟踪器,以及 triage-label 词汇表。两种类型都可以:像 GitHub 或 Linear 这样的真实跟踪器,或者 .scratch/ 下的本地 markdown 文件,后者无需额外设置即可使用。
曳光弹,而非按层切分¶
水平切片只交付变更的一层。在每一层都落地之前,什么都不能工作;而且每个工单的验收标准都不得不伸入另一个工单所拥有的工作。垂直切片(曳光弹)一次交付一条贯穿所有层的细路径,因此它可以单独验证,并且它对自己所涉及的一切拥有所有权。
这是人们最常违反的规则。一个团队运行了一个按层切分的 26 工单堆栈(corpus、producer、aggregator、selector),结果每个关闭的工单大约对应二十次智能体运行,其中约四分之三是返工。他们自己的事后分析将每类失败都追溯到水平切分,而不是实现本身。
在发布任何内容之前,会发生两件事。to-tickets 会寻找预重构(即“让变更变容易,然后再做容易的变更”这一原则),并把这类工作排在最前。然后,它会以编号列表的形式呈现拆分结果,并就这些结果对你提问:粒度是否合适、阻塞边是否真实、是否有条目应当合并或拆分。在你批准之前,什么都不会进入跟踪器;而那次提问正是你提出异议的地方。
阻塞边¶
这些边正是这个产物的意义所在。它们有两种工作方式,取决于跟踪器:
| 跟踪器 | 边存放在哪里 | 如何使用它们 |
|---|---|---|
| 本地 markdown | 每个工单一个文件,位于 .scratch/<feature>/issues/<NN>-<slug>.md,按阻塞者优先编号 |
从上到下,手动处理 |
| 真实跟踪器(GitHub、Linear) | 原生阻塞链接,或跟踪器支持的子问题 | 任何阻塞者都完成的工单都在前沿上,可被领取 |
无论哪种方式,边都存在于工单中。跟踪器唯一决定的是是否有东西能并行处理这些边。to-tickets 产出这个产物;运行它(一次一个会话,或一支智能体舰队)是你的工作,而不是该技能的工作。
大规模重构的例外¶
有一种形态会打破曳光弹规则。大规模重构是一次机械式变更(重命名列、重定义共享符号的类型),其爆炸半径覆盖整个代码库。一次编辑会破坏数千个调用点,因此没有任何垂直切片能保持绿色落地。
to-tickets 会将这种情况按展开–收缩顺序处理:
- 展开(Expand):在旧形态旁边添加新形态,因此不会破坏任何东西。
- 迁移(Migrate):按爆炸半径分批移动调用点(按包、按目录),每批一个工单,每个工单都被展开工单阻塞。由于旧形态仍然存在,CI 保持绿色。
- 收缩(Contract):一旦没有任何调用者,就删除旧形态,并以一个被所有迁移批次阻塞的工单来完成。
即使批次本身无法单独保持绿色,它们也会共享一个集成分支,并共同阻塞最终的集成与验证工单。CI 只需要在该工单处保持绿色。
常见问题¶
它为三行变更生成了十二个工单。 过度拆分是该技能被报告最多的问题,许多用户都会遇到。模型 默认会生成原子化单元,却丢掉了能让它们有意义的组合。提问步骤就是你来修正这一点的地方。让它合并工单,它就会合并。此外还有一个下限:如果整个变更都适配一个上下文窗口,你根本不需要这个技能,直接 implement 即可。
工单按层一单一单地出来了:schema 全在一个工单里,API 全在另一个工单里。 这正是垂直切片规则所针对的失败,而该技能有时仍会产生这种结果。在提问步骤中,通过每个工单问一个问题来捕捉它:完成后我能演示什么?一个没有答案的工单就是水平切片。出于这个原因,有些人会在每个工单里添加一条“demo path”(演示路径),并报告说这会让模型倾向于生成垂直切片。
在 GitHub 上,工单并未作为 spec issue 的子 issue 创建。
这个问题在十多次运行和多个模型上都有报告,最完整的记录见 issue #554。已修复:to-tickets 现在会把每个工单建为源 issue 的子 issue,GitHub tracker 模板也给出了相应命令(gh issue create --parent <n>,gh 2.94+)。重新运行 setup-matt-pocock-skills 即可刷新旧的 docs/agents/issue-tracker.md。
“Blocked by” 被写进了 issue 正文,而不是真正的阻塞链接。
这是同类问题,报告见 issue #513;那个 agent 甚至声称 GitHub 根本没有原生的阻塞关系。但实际上它有:gh issue create --blocked-by 12,15。由于该 skill 会先发布阻塞项,所以创建时这些编号总是可用的。正文文本本应是那些没有原生边的 tracker 用的后备方案,而不该是默认做法。因此,当边是原生的时候,工单模板现在会省略 ## Blocked by。
本地的工单去哪里了?v1.1 的说明写的是根目录下的 tickets.md。
确实是这么写的,但那是 bug。单个共享文件还会在多个并行 agent 同时写入时引发竞态条件。本地模式现在会在 .scratch/<feature-slug>/issues/<NN>-<slug>.md 下按依赖顺序为每个工单各写一个文件,这与本地 tracker 模板原本描述的布局一致。NN 前缀是真实的工单 ID,所以 /implement 03 就能用,不必重新输入一长串标题。
它想读我的 spec 时总被截断。
非常大的 spec 可能会超出 tracker issue 能干净返回的规模。由于没有本地副本可供回退,agent 会反复花 tool calls 去抓取分块,始终读不到结尾。不要在 /to-spec 和 /to-tickets 之间执行 clear 或 compact。在同一个上下文窗口中运行它们,agent 就不必把 spec 重新抓回来。
验收标准没有评判作用:有些标准在动手之前就通过了。 模板要求写出标准,却没说明这些标准是否可能不成立,于是出现了这种情况。常见的形态有三种:某个标准在基准提交上已经成立;某个标准只有另一个工单中的工作才能满足;某个标准只是复述了请求,而不是从产物中推导出来的。垂直切片能消除其中大部分,因为按构造来说,一个交付新行为的切片在基准提交上就是不成立的。不过这个检查仍然值得手工做一遍。对每个标准,说出能证明它为假的观察项,并确认它在 implementer 开始所在的提交上确实不成立。
工单已经发布了。我到底怎么运行它们? 这个 skill 止步于产物,没有自动分发模式。分发是手动的:看板上数一数没有未解决阻塞项的工单有多少,然后开同样数量的 agent 会话。给每个工单一个全新的上下文,并在它们之间 clear。implement 完成时并不能可靠地关闭或勾选工单——无论 GitHub 还是本地 markdown 都是如此——所以你需要自己更新工单的状态。
工作正常的标志¶
- 每个工单都能回答“完成后我可以演示什么?”,而答案是一种行为,而不是某一个层。
- 在发布任何内容之前,列表会以编号形式交到你手上,每个工单都带有一行 “Blocked by”。
- 最顶上的工单没有阻塞项,可以立即开始。
- 工单正文中没有任何文件路径或行号,除非是原型产出的代码片段。
- 每个工单读起来都像是全新会话在你不在场的情况下也能独立完成的任务。
- 预重构(prefactoring)如果有发现,排在任务顺序的前端,而不是混进功能工单。
所处位置¶
to-tickets 是主构建链中的一步:
上游是 to-spec,后者会把一份已定稿的 spec 交给它来做切片。两者保持在同一个上下文窗口中,之间不要 clear。下游是 implement,每个全新会话构建一个工单,用 tdd 驱动测试,并以 code-review 收尾。implement-spec 是另一条下行路径。它把同样的阻塞边读作任务图,并在同一个集成分支上并行构建所有就绪的工单。当你不确定哪个 skill 或流程合适时,ask-matt 会为你指路。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 skills13/skills