ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用 to-tickets 把 Spec 拆成可独立交付的追踪弹 Ticket:skills 仓库的垂直切片与阻塞边工程实践

用 to-tickets 把 Spec 拆成可独立交付的追踪弹 Ticket:skills 仓库的垂直切片与阻塞边工程实践 用 to-tickets 把 Spec 拆成可独立交付的追踪弹 Ticketskills 仓库的垂直切片与阻塞边工程实践【免费下载链接】skillsSkills for Real Engineers. Straight from my .agents directory.项目地址: https://gitcode.com/GitHub_Trending/skills13/skillsto-tickets是本仓库 skills/engineering 系列中的一项用户显式调用的技能在 Claude Code 中通过/to-tickets触发它的职责是把一份计划、一份 spec 或当前对话中的内容拆解为一组带有**阻塞边blocking edges**的 ticket并发布到已配置的问题跟踪器上。本文围绕 docs/engineering/to-tickets.md 展开结合 skills/engineering/to-tickets/SKILL.md 的完整流程、模板与周边技能源码讲清追踪弹tracer bullet拆票原则、阻塞边在本地 markdown 与真实跟踪器上的不同形态、expand–contract 宽重构例外以及发布前后的 quiz 与手动调度环节让读者既能在实际项目中照章操作也能理解每一条规则背后的设计动机。它做什么从计划到一组追踪弹 Ticketto-tickets的输入可以是三类来源之一一份已写好的spec例如to-spec发布到跟踪器上的 spec issue仅存在于当前对话中的计划无需先成文直接读取线程即可当前正在进行的对话上下文本身。输出则是一组 ticket发布到你配置好的问题跟踪器GitHub、Linear 等真实跟踪器或.scratch/下的本地 markdown 文件。每个 ticket 必须声明自己的阻塞边哪些其他 ticket 必须先行完成它才能开工没有阻塞边的 ticket 可以立即开始。其中最关键的定义是每个 ticket 都是一颗追踪弹——一条狭窄但完整的、贯穿改动每一层schema、API、UI、测试的路径落地当天就能独立演示。这个约束让它与按层切分、最后集成的常规拆法截然不同同时它还把每个 ticket 的体量约束在**单个全新上下文窗口context window**内因为真正接手这个 ticket 的是一段从未见过你的 spec 的全新会话session。这两点可独立演示 单窗口可完成是整个技能区别于拍脑袋切票的核心判据。何时使用它一张决策表该技能只能由用户显式调用——SKILL.md 的 frontmatter 中写明了disable-model-invocation: true模型不会自主去拿它。原文档给出的决策表如下你的处境该做什么已有一个 spec issue且构建横跨多个会话/to-tickets或/to-tickets #spec_issue计划只存在于对话中从未成文/to-tickets直接读取线程无需 spec整个改动塞得进一个上下文窗口直接走 implement跳过 ticket什么都还没定先 grill-with-docs再 to-specwayfinder 的地图已清空先 to-spec 收拢地图再/to-tickets两处容易被忽略的边界原文档都给了明确指令不要对to-tickets产出的 ticket 再跑triage。这些 ticket 按构造即具备 agent-ready 属性triage是为从别人那里来的工作准备的见 skills/engineering/triage/SKILL.md 的五个状态角色needs-triage、needs-info、ready-for-agent、ready-for-human、wontfix。单窗口能装下的改动不需要这个技能直接进 implement拆票反而是在制造不必要的协调成本。前置条件先配置跟踪器与 triage 标签to-tickets要把结果发布到跟踪器上因此依赖 setup-matt-pocock-skills 为当前仓库完成一次性配置问题跟踪器GitHub默认走ghCLI、GitLab走glabCLI、本地 markdown.scratch/开箱即用、或其他由用户描述的自由格式工作流triage 标签词表五个规范角色名对应的实际标签字符串默认标签即角色名本身needs-triage、needs-info、ready-for-agent、ready-for-human、wontfix见 triage-labels.md。本地 markdown 模式无需任何额外配置仓库原样支持一个 feature 一个目录见 issue-tracker-local.md 的约定——.scratch/feature-slug/下放 specspec.mdissues/下放实现 ticketNN-slug.md从01起编号绝不使用单一合并文件Status:行记录 triage 状态。追踪弹而不是切片垂直切 vs 水平切**水平切片horizontal slice**每次只交付改动的一层先是所有 schema、再是所有 API、最后是所有 UI。结果是直到每一层都落地之前没有任何东西可用而且每个 ticket 的验收标准不得不伸进另一个 ticket 拥有的工作里验收边界相互纠缠。**垂直切片vertical slice即追踪弹**则一次交付一条贯穿所有层的窄路径可独立验证且它评估grades的一切都属于它自己。SKILL.md 里把这条规则固化为可复用的垂直切片准则每个切片都切出一条狭窄但完整的路径穿过每一层schema、API、UI、tests——是垂直的不是某一层的水平切片完成的切片可以独立演示或验证每个切片都能装进单个全新上下文窗口任何 prefactoring 都应当先行完成。原文档记录了一个值得警惕的真实案例某团队跑过一个按层切分的 26-ticket 栈corpus、producer、aggregator、selector 四层结果平均每个关闭的 ticket 消耗约二十次 agent 运行其中约四分之三是返工。他们自己的复盘把每一类失败都追溯到了水平切片本身而非实现质量——这是人们最常违反的一条规则最直白的代价说明。发布前必经的两件事在发布任何内容之前to-tickets会先做两件事寻找 prefactoring 机会——即先让改动变容易再做容易的改动make the change easy, then make the easy change原则SKILL.md 的第 2 步要求 agent 在探索代码库时主动寻找可以先行完成的重构并把这类工作排在 ticket 顺序的最前面以编号列表的形式呈现拆解结果并向你提问quiz粒度是否合适阻塞边是否真实哪些该合并、哪些该再拆分在获得你的批准之前任何内容都不会进入跟踪器这个 quiz 环节就是你讨价还价的地方。阻塞边工件的意义所在阻塞边是这份工件的核心价值。它们在不同的跟踪器上以两种形态呈现、以两种方式被使用跟踪器边存放在哪如何推进本地 markdown每个 ticket 一个文件位于.scratch/feature/issues/NN-slug.md阻塞者编号在前从上到下手动推进真实跟踪器GitHub、Linear原生阻塞链接或跟踪器支持时的 sub-issue所有阻塞者都完成的 ticket 处于前沿frontier可以随时被拿走无论哪种形态边都存在于 ticket 本身媒介只决定能否对它们并行行动。需要强调to-tickets只生产工件运行这些 ticket一次一个会话或一整个 agent 舰队是你自己的工作不是技能的责任。SKILL.md 的第 5 步对此有精确表述——推进前沿frontier任何阻塞者全部完成的 ticket 都可被领取纯线性链就是从上到下逐个开工。宽重构例外用 expand–contract 而非垂直切片有一种形态会打破追踪弹规则必须例外处理宽重构wide refactor。它指单一机械式改动重命名一列、重打一个共享符号的类型其**爆炸半径blast radius**扇面覆盖整个代码库一次编辑就破坏上千个调用点任何垂直切片都无法以绿色状态落地。此时to-tickets改用expand–contract先扩展后收缩序列来排序SKILL.md 与文档描述一致Expand扩展在旧形式旁边加入新形式保证什么都不破坏Migrate迁移按爆炸半径分批量迁移调用点按包、按目录每批一个 ticket每个都由 expand 阻塞因为旧形式仍然存在CI 每批都能保持绿色Contract收缩确认没有调用者残留后删除旧形式这个 ticket 被每一个迁移批次阻塞。如果连单批都无法独立保持绿色则让各批共享一个集成分支并共同阻塞一个最终的 integrate-and-verify ticket——绿色只在该处被承诺。发布两种跟踪器、两套模板、同样的 ticketSKILL.md 第 5 步明确发布方式取决于setup-matt-pocock-skills配置了哪种跟踪器ticket 本身两种方式完全相同只有阻塞边的形态不同本地文件在.scratch/feature-slug/issues/下按依赖顺序从01编号每个 ticket 一个文件阻塞者在前。每个文件的 Blocked by 列出它依赖的编号/标题。一个 ticket 一个文件绝不使用单一合并文件——原文档的 FAQ 指出v1.1 时代的根级tickets.md单文件方案在并行 agent 写入时会竞态这是一个已修复的 bug。NN前缀是真实的 ticket ID因此/implement 03可以直接引用而不必重敲一长串标题。本地 ticket 模板SKILL.md 内嵌# NN: Ticket title **What to build:** the end-to-end behaviour this ticket makes work, from the users perspective, not a layer-by-layer implementation list. **Blocked by:** the numbers/titles of the tickets that gate this one, or None (can start immediately). **Status:** ready-for-agent - [ ] Acceptance criterion 1 - [ ] Acceptance criterion 2真实跟踪器GitHub、Linear 等按依赖顺序阻塞者在前一个 ticket 一条 issue使每个 ticket 的阻塞边可以引用真实标识符优先使用平台原生的阻塞 / sub-issue 关系否则在 Blocked by 中列出阻塞 issue 编号默认打上ready-for-agent标签除非另有指示——这些 ticket 按构造即可被 agent 抓取。issue 模板## Parent A reference to the parent issue on the tracker (if the source was an existing issue, otherwise omit this section). ## What to build The end-to-end behaviour this ticket makes work, from the users perspective, not layer-by-layer implementation. ## Acceptance criteria - [ ] Criterion 1 - [ ] Criterion 2 ## Blocked by - A reference to each blocking ticket, or None (can start immediately).两种形态下共同遵守的规则避免在 ticket 里写具体文件路径或代码片段它们会迅速过时唯一的例外是原型prototype产出的、比文字更能精确编码决策的片段状态机、reducer、schema、类型形状可以内联并注明来自原型只保留决策密集的部分而不是一整个可运行的 demo。发布到真实跟踪器时的操作细节可对照 issue-tracker-github.mdgh issue create --title ... --body ...多行 body 用 heredoc、gh issue view number --comments、gh issue edit number --add-label ...、gh issue close number --comment ...GitHub 的 issue 与 PR 共用一套编号空间裸#42可能是其一需要gh pr view 42回退到gh issue view 42来分辨。常见问题来自实践场的第一手反馈一个三行改动产出了十二个 ticket。**过度分解over-decomposition**是这个技能被报告最多的摩擦点且在各实践者之间高度一致模型默认倾向产出原子单元却丢失了让这些单元有意义的归组。quiz 环节正是为此存在——让模型合并它会照做。更根本的答案是ticket 存在下限——如果整个改动塞得进一个上下文窗口你根本不需要这个技能直接走 implement。ticket 变成了一层一个schema 全在一个里API 全在另一个里。这正是垂直切片规则所要反对的失败形态而技能偶尔仍会产出它。在 quiz 环节对每个 ticket 追问一个问题即可拦截这个完成时我能演示什么答不上来的 ticket 就是水平切片。有人因此给每个 ticket 加一行 demo path并报告这能有效把模型推向垂直分解。在 GitHub 上ticket 没有作为 spec issue 的 sub-issue 创建。这是已知且尚未修复的问题在十几次运行、多个模型上都有报告在上游 issue 中有最完整的记录在 Codex 上比在 Claude 上更严重。gh自 v2.94 起已原生支持gh issue create --parent n创建子 issue事后用gh issue edit parent --add-sub-issue n补挂。在跟踪器模板优先使用这些命令之前运行后自行接好 parent 链接是可靠的做法。Blocked by 被写进了 issue 正文而不是真实的阻塞链接。同类问题上游 issue 有报告最极端的案例是 agent 直接断言 GitHub 根本没有原生阻塞关系。实际是有的gh issue create --blocked-by 12,15。因为阻塞者总是先发布所以创建时它们的编号一定可用。正文文本是给没有原生边的跟踪器准备的兜底方案而不是默认做法。本地的 ticket 放哪v1.1 的说明提到根级tickets.md。确有其事但那是个 bug单个共享文件在并行 agent 写入时会发生竞态。本地模式现在改为每个 ticket 一个文件位于.scratch/feature-slug/issues/NN-slug.md按依赖顺序排列与本地跟踪器模板早已描述的布局一致。NN前缀是真实 ticket ID所以/implement 03可用不必重打一长串标题。它读我的 spec 时总是截断。超大的 spec 可能超出跟踪器 issue 能干净返回的体量又没有本地副本兜底agent 于是反复重取片段烧掉工具调用永远读不到结尾。不要在/to-spec与/to-tickets之间做 clear 或 compact——在同一个上下文窗口内连续运行它们spec 就根本不需要被重新取回。验收标准什么都没评估有些在工作开始之前就通过了。模板要求写验收标准却没有要求标准必须能失败于是出现三种反复出现的形态标准在基线提交base commit上就已为真标准只能由另一个 ticket 拥有的工作来满足标准只是在复述需求而非从工件推导。垂直切片能预防大部分问题——一个交付了此前不存在行为的切片按构造在基线提交上就是红的。但这个检查仍值得手工过一遍对每条标准说出能证明它为假的观察并确认它在实现者起步的那个提交上确实失败。ticket 已经发布了。我到底怎么运行它们技能止步于工件没有自动分发模式。分发是手动的看板、数出没有未关闭阻塞者的 ticket 数量、开对应数量的 agent 会话。一个 ticket 一个全新上下文之间清空。需要注意implement 在完成时并不可靠地关闭或勾选 ticketGitHub 和本地 markdown 皆如此所以 ticket 的状态由你来更新。怎么算工作得对Its working if原文档给出了可操作的自检清单每个 ticket 都能回答这个完成时我能演示什么且答案是行为不是某一层在发布任何内容之前列表以编号形式回到你手里每个都带一行 Blocked by列表顶部的 ticket没有阻塞者可以立即开工ticket 正文里没有任何文件路径或行号除非是原型产出的片段每个 ticket 读起来像一个全新会话能在没有你在场的情况下独立完成的东西prefactoring如果发现了排在顺序最前面而不是混进功能 ticket 里。它在构建链中的位置to-tickets是主构建链中的一个环节grill-with-docs → to-spec → to-tickets → implement → code-review上游是 to-spec后者把对话沉淀为一份已定稿的 spec含 Problem Statement、Solution、User Stories、Implementation Decisions、Testing Decisions、Out of Scope、Further Notes 七个部分交给它作为切片对象两者应保持在同一个未断裂的上下文窗口内运行。下游是 implement每个 ticket 一个全新会话去构建用 tdd 驱动测试收尾时用 code-review 评审后再提交。当你拿不准该用哪个技能或哪条流程时ask-matt 负责为你路由。整套链路说明了一个贯穿性的设计哲学把拆to-spec/to-tickets与做implement放在不同的上下文窗口用带阻塞边的追踪弹 ticket 作为唯一交接物——每一份工件都必须让一个从未参与过前文的会话可以独立接手、独立演示、独立验收。理解了这条主线to-tickets的全部规则垂直切片、quiz、阻塞边、expand–contract、手动调度就都是同一原则的自然推论了。【免费下载链接】skillsSkills for Real Engineers. Straight from my .agents directory.项目地址: https://gitcode.com/GitHub_Trending/skills13/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表