BMAD 方法中的证据驱动回顾(bmad-retrospective):以证据而非记忆判定已完成 Epic 的验收结果 BMAD 方法中的证据驱动回顾bmad-retrospective以证据而非记忆判定已完成 Epic 的验收结果【免费下载链接】BMAD-METHODBreakthrough Method for Agile Ai Driven Development项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHODBMADBreakthrough Method for Agile AI Driven Development在每个 Epic 完成后提供专用的bmad-retrospective技能通过阅读 Epic 留下的规格、故事记录、完整 diff、提交记录与冲刺追踪产物对成果做出基于证据的回顾与验收判定而非依赖人的记忆。读完本文你将掌握该技能的两类输入冲刺追踪型与规格型、四阶段证据工作流、三种验收判定accepted/accepted-with-open-items/rejected的裁决规则以及sprint_status.py、git_evidence.py等底层脚本的调用方式与实现要点可直接在真实仓库中运行和解读回顾报告。为什么在 Epic 结束后立即运行回顾bmad-retrospective的核心定位是Epic 由多个各自独立实现、独立评审的 Story 累积而成单个 Story 的评审通过并不等于整个 Epic 达标。回顾把这些 Story 放在一起审视专门寻找只看单个 Story 永远发现不了的问题。依据 skills/bmad-retrospective/SKILL.md 的技能描述该技能在用户说出 run a retrospective 或 lets retro the epic [epic] 时触发并支持-H/--headless无头模式。关联文档 docs/ko-kr/explanation/retrospective.md 明确指出回顾要抓的四类问题累积缺陷一点点偏移的架构、重复编写的辅助函数、多次每次数百行增长最终膨胀过大的类diff 范围审查把 Epic 的 diff 交给bmad-review按代码视角lens审查重点看单个会话中从未同时见过两边的 Story 之间边界规格对照实现代码与 Epic 和 PRD 描述不一致之处验收判定按 Epic 自身的验收条件评估结果。回顾的黄金时间点是 Epic 结束时此时 diff 仍然新鲜、会话日志尚未被清理正是九个会话各自往同一文件加代码却没有任何一个会话从整体上看过合并后膨胀的类这一空档期的最佳补救时机。一个关键约束贯穿始终所有发现都必须附带可定位的证据文件、行、提交、日志无法指出证据的主张不会被写入报告。这一点在 skills/bmad-retrospective/workflow.md 中有硬性表述Every finding you report carries a source reference (file, line, commit, or log). A claim you cannot point at — an invented root cause, a pattern the diff does not actually show — is not a finding. Drop it.两种 Epic 输入冲刺追踪型与规格型回顾任务首先需要确定回顾哪个 Epic。关联文档给出的执行表如下期望的操作执行方法标准审查/bmad-retrospective审查特定 Epic/bmad-retrospective 3审查规格型 Epic/bmad-retrospective _bmad-output/specs/spec-slug/团队讨论请求团队一起讨论运行 派对模式默认关闭为自动化执行无人值守-H epic— 仅凭证据判定的非交互模式Epic 以两种对等的形态进入工作流详见 workflow.md 的 Inputs 一节Epic 输入列表与完成状态回顾结果冲刺追踪型 Epicsprint-status.yaml中选定的 Epic 与 Story 产物在实现产物目录生成带日期的回顾文档并更新冲刺状态规格型 EpicSPEC.md、有序的stories.yaml、stories/id-*.md记录在规格目录生成RETROSPECTIVE.md不创建也不修改冲刺状态文件两种形态的判定规则冲刺追踪型sprint mode通过 sprint_status.py 的detect-epic子命令读取sprint-status.yaml确定 Epic 及其未完成 Story 列表未指定 Epic 时自动检测拥有任一 done Story 的最高编号 Epic并需与用户确认。规格型stories mode直接传入规格文件夹路径。stories.yaml的列表顺序是权威的 Story 列表文件名排序不作数每个 Story 的stories/id-*.md前置元数据frontmatter中的status表示完成状态。无论记录由 Build 还是 Build Auto 技能产生规则一致。规格型模式下pending_stories是状态不为done的 Story id 列表对整个流程而言一旦进入规格型路径后续不再读写冲刺状态文件最终在规格文件夹内生成固定名称的{spec-folder}/RETROSPECTIVE.md固定名称便于断点续跑时找到文档且不触碰SPEC.md、stories.yaml或任何 Story 产物。判断顺序要点workflow.md 原文显式传入文件夹即为规格型无论是否存在冲刺状态显式传入 Epic 编号即为冲刺型两者都没传时存在sprint-status.yaml就用冲刺型否则在{{ config.output_folder }}/specs、规划产物、实现产物目录下寻找规格文件夹。存在多个候选时必须询问用户绝不静默选择无头模式下则停止并要求显式传入文件夹。五阶段工作流从收集证据到落盘判定workflow.md 将回顾组织为按序执行的五个阶段默认在写出证据报告与判定后停止Phase 3 的团队讨论默认跳过。运行期间回顾文档本身是工作产物——确定 Epic 后先按 retro-document.md 规定的章节创建骨架每完成一个阶段就把结果写入续跑时重新读取该文件即可已有回顾文档时先与当前证据核对状态以当前证据为准从第一个未完成阶段继续。Phase 1 — 收集Gather依据 evidence-gathering.md盘点 Epic 实际产出物并记录缺失项输出一份有什么、缺什么、diff 范围是什么的清单Epic 规格规划产物目录下的 Epic 文件包括声明的验收标准若未声明则注明判定将从 diff 推导profiledStory 文件实现产物目录下各 Story 的规格标记编码会话之间的边界diff 范围与提交Epic 引入的全部变更。范围必须包含第一个 Story 的提交——A..B会排除A因此左端点必须用第一个提交的父提交即first-commit^..last-commit否则第一个 Story 会整体消失于 diff、提交归属和判定证据中冲刺状态sprint-status.yaml用于确认哪些 Story 为done及回顾键的当前状态上一次回顾前一 Epic 的回顾文档若存在供 Phase 4 核对上次的行动项是否落地会话日志各 Story 的会话记录若可得是会话为何偏离预期的唯一记录也是最容易被删除/过期的证据需即时抓取引用。在冲刺型模式下范围确立后运行uv run --no-cache {skill-root}/scripts/git_evidence.py --repo {project-root} --range range --stories story-ids输出 JSON包含按 Story 的提交归属和按文件的变更量added / deleted / net。规格型模式的 diff 范围不同每个 Story 在其产物前置元数据中记录自己的基线baseline_revision已废弃或baseline_commit因此没有全 Epic 统一范围——范围终点是列表顺序中下一个 Story 的基线共享同一范围的 Story 分组后每个不同范围运行一次git_evidence.py该组 id 以逗号分隔作为--stories值。缺失证据规则证据可用性各不相同绝不允许掩盖缺口。每一项后续分析都声明自己需要什么输入缺失时记录收窄后的范围而非猜测。最终回顾的读者必须能区分已检查且干净checked and clean与从未检查never checked——缺少会话日志则跳过过程教训分析并写明无声明验收标准则判定标记为 profiled子代理不可用则相关分析在收窄范围内内联执行并记录收窄事实。Phase 2 — 分析Analyze从三个角度产出发现每个发现带源码引用聚合视图Aggregate views单个 diff hunk 显示不出的缺陷。依据 aggregate-views.md 的目录架构增量跨 Epic 依赖结构如何变化优先用语言原生依赖工具dependency-cruiser、madge、pydeps 等对范围前后分别构图再 diff寻找跨层依赖、分层违规与新增环重复地图同一问题被多种方式解决——两个会话各自写了近乎相同的逻辑或第二个会话不知道第一个已存在而重复实现辅助函数God-class / 体积增长在 Epic 过程中超过健康体积的文件按files排名后打开排名前列文件确认真实大小与结构再下结论——高净变更量只是值得检查的候选不是最终判定模式发散与周边代码库既有约定命名、错误处理、测试结构、模块边界的分歧规格到实现的对账实现与 Epic 规格、PRD/架构描述的分歧每条分歧要么是缺陷修复、要么是已接受偏差记录以免后续回顾重复标记、要么是需要对账回现实的规格在 Phase 4 提议。diff 范围审查不重复实现评审而是把 Epic 的 diff 交给bmad-review的代码视角adversarial、edge-case、verification-gap加权关注各 Story 之间的边界——没有任何单个会话同时见过两边。若bmad-review不可用则在收窄范围内内联运行这些视角并记录收窄。行为检查当 Epic 改变了运行时行为端到端实际运行变更后的流程并记录观察。通过测试不能替代运行系统。最后合并、去重、串联来源任何无法关联到证据来源的发现一律丢弃。Phase 3 — 团队讨论可选默认关闭仅当用户明确要求discuss it as a team、run party mode等才运行且永远不在无头模式运行。依据 team-discussion.md调用bmad-party-mode技能并注入 Phase 2 的发现带来源引用、按聚合视图或视角分组让已安装的 Agent 以真实子代理身份独立思考而不是照本宣科。注入内容还包括证据确认的改进点真实收益、Epic 验收标准或 profiled 替代物、上一次回顾的行动项及是否落地。唯一规则团队只讨论证据不讨论发明——没有来源引用的发现不能成为讨论对象若bmad-party-mode不可用讨论必须内联进行并记录内联运行这一收窄事实单一模型扮演所有角色会丢失独立分歧。讨论产出汇入 Phase 4 的行动项与判定但不替代Phase 4。Phase 4 — 裁决Decide依据 acceptance-verdict.md路由每条发现每条发现有两个独立处置维度——本例怎么办fix now/defer/accept as-is其中 fix-now 变成行动项defer 保留足够上下文供日后行动accept 记录以便后续回顾停止重复标记与如何预防下一个上游教训规格措辞、Story 粒度、缺失的约定或门禁。来自子代理或团队讨论的发现是未验证报告而非既定事实行动项依赖它之前必须回到一手来源复核来源经不起复核的发现被丢弃而非路由。行动项把 fix-now 发现与过程教训编译为具体、有归属owner的行动项。本版本中两类行动项是提议而非应用修复Remediation代码修复写成行动项或 Story 形态工作交给常规开发循环稍后执行回顾本身不运行开发循环规格对账Spec reconciliation实现偏离规格时把对账提议为附带证据的行动项由人来应用到项目契约不确定的解释绝不自动写入规格。上一次回顾的跟进follow-through存在上一回顾时读取sprint-status.yaml中的action_items对每个属于更早 Epic 且未done的条目在回顾文档的 Previous-retro follow-through 节记录如何定位该条目id遗留条目用epic加逐字符精确的action文本、是否落地必须有提交/文件行/测试作为证据无法指证的记为 no evidence found 而非 not done、以及它论证的状态done/in-progress或什么都不写——是提议不是写入。验收判定The verdict依据 Epic 声明的验收标准评判最终状态未声明时从 diff 和 Story 推导并标记为profiled而非 declared。三种判定accepted— 证据表明标准被确实满足、无阻塞性未决发现、且该 Epic无未完成 Storyaccepted-with-open-items— 标准满足但命名的发现仍被推迟并跟踪——且仍要求该 Epic 所有 Story 为donerejected— 标准未满足、存在未解决的阻塞性发现、或该 Epic 任一 Story 仍未done。三条硬规则原文人的决定永远覆盖机器判定未达标准且无人决定的 Epic 记录为not accepted——绝不允许静默通过非空的pending_stories列表使机器判定为rejected无头模式也不例外——未完成的交付不是已完成 Epic 上的开放发现Epic 本身就是不完整的不得软化为 accepted-with-open-items。若完整性检查未运行无sprint-status.yaml可读不得从数据缺失渲染出 rejected 或 accepted 判定——应说明检查不可用仅依据已有标准与发现权衡。Phase 5 — 定稿Finalize依据 retro-document.md 完成两处写入规格型模式只写第一处。回顾文档位于{{ config.implementation_artifacts }}/epic-{N}-retro-{date}.md规格型为{spec-folder}/RETROSPECTIVE.md带机器可读的 YAML 前置元数据--- epic: {epic_number} date: {date} verdict: accepted | accepted-with-open-items | rejected criteria: declared | profiled headless: true | false ---文档章节Epic summary哪个 Epic、diff 范围、完成的 Story、用户同意跨过的未完成 Story、证据清单、Findings按聚合视图与视角分组每条带来源引用与处置、Behavior verification端到端验证内容与观察或明确注明未验证、Previous-retro follow-through、Action items带 owner注明哪些是待人工应用的修复/规格对账提议、Acceptance verdict判定、declared/profiled、证据、Open questions、Assumptions仅无头运行所有未经用户做出的选择。文档内不写任何时间估算。关键实现约束verdict保持在回顾文档的前置元数据中绝不编码进 sprint-status 的回顾键——该键值保持donedone表示回顾运行过不表示Epic 通过了使既有生命周期消费者冲刺规划的optional ↔ done转换、状态 TUI无需改动继续工作。脚本不向sprint-status.yaml写入任何判定无retro_verdict键因此读取冲刺状态无法区分被拒绝与被接受的 Epic门禁或编排器必须读回顾文档的前置元数据。冲刺状态更新绝不手改sprint-status.yaml其注释块与引号格式正是最常损坏文件的写入点使用随附脚本通过保留注释的 YAML 解析器往返、强制加引号、并验证结果——验证失败则原样恢复文件uv run --no-cache {skill-root}/scripts/sprint_status.py update \ --file {{ config.implementation_artifacts }}/sprint-status.yaml \ --epic {epic_number} --set-retro-done \ --add-action [{action:...,owner:...}, ...] \ --ref {{ config.implementation_artifacts }}/epic-{epic_number}-retro-{date}.md \ --verdict accepted | accepted-with-open-items | rejected \ --date {date}注意每个值都要加引号--date只接受MM-DD-YYYY HH:MM格式未补零的写法如1-2-2026 9:05会被解析并规范化为补零形式无法解析的值会在触碰文件前以ok: false, restored: true与退出码 1 拒绝整个更新为 no-op格式带空格因此--date必须加引号否则 argparse 会把14:23当作独立参数报错argument error: unrecognized arguments: 14:23退出码 2--file与--ref同理。脚本把development_status[epic-{N}-retrospective]置为done、为每个提议项追加一条action_items条目并更新last_updated。每个追加条目携带status: open、稳定idepic-N-retro-item-n-slug由 action 文本派生或使用 JSON 中提供的id与指回回顾文档的ref——使编排器能在重跑时去重、并把每项分派到其完整带源的发现。--verdict不写入文件只在结果 JSON 中原样回显供消费者使用只接受前置元数据词汇表accepted、accepted-with-open-items、rejected其他拼写一律在触碰文件前拒绝。读取返回的 JSONok: true→ 报告回顾键转换、action_items_added、action_items_updated与回显的verdictok: false→ 文件保持原样restored: true呈现错误不得手改restored: false表示回滚写入也失败、文件可能不完整必须显式警告用户retro_key_found: false→ 回顾键缺失未标记 done文档仍保存但需告知用户冲刺状态需手动补一条回顾条目retro_key_found: null→ 未传--set-retro-done键从未被查找——与false的真实缺失含义不同。移动上一 Epic 行动项的状态--set-action-status同样只能通过脚本按id选择或遗留条目按epic加逐字符精确的action文本状态只有open、in-progress、donebmad-sprint-planning的状态视图把 open 与 in-progress 都算作开放行动项只有done才使条目从列表隐退。每个选择器必须恰好解析到文件中的一个条目——无匹配、多匹配或数组内冲突都会中止整个调用ok: false, restored: true文件逐字节不变任何部分都不生效整个调用包括同次传入的--set-retro-done与--add-action一个打错的选择器会丢弃全部更新修正后必须重跑完整命令。同一运行中由--add-action追加的条目在该次运行中不可寻址一律写为open。只应用用户确认过的状态证据只论证提议转换只有用户确认才论证写入无头运行完全不传该标志只在文档的 Previous-retro follow-through 节记录本会提议的转换。两种 Epic 输入的判定规则与验收门禁合并 Inputs 与 Phase 4 的规则得到可操作的验收门禁逻辑workflow.md 与 acceptance-verdict.md冲刺型sprint_status.py detect-epic成功返回时携带pending_stories——所选 Epic 中状态非done的 Story 键按文件顺序、仅限该 Epic其他 Epic 的未完成 Story 超出本回顾范围。列表非空时交互模式列出这些 Story 并询问是否回顾未完成 Epic用户拒绝则停止并报告、不进入 Phase 1接受则把用户同意跨过的 Story 记录进文档的 Epic summary。无头模式继续并把这些记录进 Assumptions 节不得虚构确认。规格型stories.yaml列表顺序中状态非done的 id 构成pending_stories应用同样的完整性门禁后跳过读取/写入冲刺状态直接进入 Phase 1。两种模式殊途同归pending_stories非空 → 机器判定rejected交互模式人类可覆盖无头模式不可。机器判定的story_count: 0陷阱detect-epic对不存在的 Epic 与已完成的 Epic 返回相同的空pending_stories。因此story_count: 0应视为Epic 编号很可能打错需与用户确认无头模式下停止并报告而不是继续。底层脚本实现剖析sprint_status.pyJSON 契约与文件安全写入sprint_status.py依赖ruamel.yaml0.18、要求 Python 3.11是回顾技能的状态中枢两个子命令detect-epic只读检测与update外科手术式更新。JSON-only 契约脚本 stdout 只输出 JSON错误也以 JSON 形式输出到 stdout 并带非零退出码。为此自定义了JsonArgumentParser——error()被覆写为输出{ok: false, error: ...}退出码 2且所有解析器以add_helpFalse构造把-h也路由到普通无法识别的参数错误路径避免把使用文本打到 stdout 破坏机器消费者sprint_status.py。保留注释与格式的往返update通过YAML(typrt)往返固定缩进mapping2, sequence4, offset2与 utf-8 编码使既有action_items块不被 ruamel 的默认偏移重新缩进sprint_status.py。写入为原子操作临时文件 os.replace先 fsync 文件再 fsync 目录任何验证失败都恢复原始文件字节_atomic_write。写入后的验证包括重新解析、development_status结构检查、回顾键状态检查、action_items长度校验、逐条状态校验、以及注释行多重集检查——任何注释行消失都判定为失败并恢复_comment_counts对比。稳定的行动项 id追加的条目默认生成epic-N-retro-item-n-slugslug 由 action 文本 Unicode 感知地派生_slugify非拉丁字符保留自身字符而非塌缩为占位符无 slug 可用时退化为 SHA-256 前 8 位内容哈希保证确定性与唯一性sprint_status.py。选择器解析的精确性_match_action_items中id优先遗留的 epicaction 形式是回退且匹配为精确相等无修剪、无大小写折叠、epic 必须是 JSON 整数同时排除boolPython 中True 1杜绝静默写入错误条目sprint_status.py。git_evidence.py只测量、不评判git_evidence.py 在修订范围上测量提交与文件变更证据只测量——从不评判加速或违规数字由模型解读脚本 docstring 原文。两个 git 遍历第一遍列出范围内每个提交含 merge并对非 merge 提交求和每文件 churn即files第二遍仅当范围含 merge 时运行单独测量这些 merge 并报告为merge_files——绝不并入files因为 merge 相对其第一父提交的 diff 会复述其合入提交的 churn第一遍已计入并入会双重计数但merge_files并非冗余因为 merge 第一父 diff 还携带冲突解决本身新增的代码这些代码不存在于任何非 merge 提交中。关键输出键的精确语义evidence-gathering.md 为权威解释每个提交携带is_merge与stories——subject 命名的每一个Story id跨两个 Story 的提交对两者都计数files只累计非 merge 提交且始终为整数不可测量的修订被排除而非置零binary_revisions计数该路径 churn 无法测量的修订——其真实体积至少是报告之和merges_measured计数范围头部第一父主干上的 mergemerge_count计数范围内所有 merge——两者有差距即表示有些 merge 未被测量实现细节core.quotePathfalse保证非 ASCII 路径为真实 UTF-8 而非八进制转义--no-renames使重命名成为诚实的删除新增而非不可解析的伪路径log.diffMergesseparate在命令行固定防止仓库配置把它设为off导致第二遍无文件行输出git_evidence.py解码用surrogateescape而非replace防止两个不同的非 UTF-8 路径塌缩为同一键并静默求和。范围校验--range只接受显式REV..REVgit_evidence.py前导-会被 git 当作选项消费、单个 rev 会记录其之前全部历史、裸 pathspec 会按路径记录、空端点..、a..、..b会让 git 把该侧默认为 HEAD、三点A...B是对称差——都是不同的提交集。partition在第一个..处分割因此任何多余点号的形态都会使右侧为空或点号前缀而被拒绝退出码 2。测试如何守护这些行为测试是理解技能行为边界的最快途径。test_sprint_status.py依赖pytest8.0与ruamel.yaml0.18通过uv run以子进程方式运行脚本针对临时夹具副本再重新读取文件断言注释与格式存活、标点密集的行动值完整往返覆盖detect_epic的 Epic 检测、对键入的回顾状态的 JSON 错误拒绝、pending_stories只列出所选 Epic 的未完成键、完整 Epic 得到空列表、忽略其他 Epic、无 Epic 检测时仍返回pending_stories形状以及update的注释/格式保持、行动项追加与状态转换的选择器精确性、JSON-only 契约含-h与 argparse 错误都输出 JSON 而非使用文本。test_git_evidence.py 则覆盖无范围返回空形状、按 Story 的提交归属、Story 归属的词边界1-2不匹配11-2、畸形范围单个 rev、pathspec、选项样范围、退化形态以 JSON 拒绝、重命名产生两个可打开路径、非 ASCII 路径在非 UTF-8 locale 下存活、merge churn 被测量与计数且files排除 merge、脊柱外 merge 被计数但不测量、敌对的log.diffMerges配置下第二遍仍工作、不同非 UTF-8 路径保持区分、重复 merge 头只计一次、线性历史报告无 merge、第二遍仅当范围含 merge 时运行、多 Story subject 归因到每个匹配、二进制备份不再抹除已测文本 churn、成功形状携带每个文档化键、显式--repo忽略环境中的 git 目录等。这些测试共同把上文提到的每一条边界条件固化为可回归的行为契约。回顾结果如何进入开发循环依据 docs/ko-kr/explanation/retrospective.md 的结果利用一节技能只做提议执行由人决定不自动修改代码或规格行动项进入常规开发循环——要么立即修复要么作为新 Story回顾只编写行动项不执行规格对账结果附带证据提供给用户由用户把对账直接反映到项目契约解释不确定的内容不自动写入规格判定作为门禁——rejected或accepted-with-open-items判定提示需要移交到下一规划阶段的内容。关联文档特别强调有问题的 Epic 不会被当作无事发生过而进入 approved 状态。验收条件未满足或 Epic 有任一 Story 未完成时除非人改变判定否则以未批准状态结束——这正是读证据而非记忆这一方法论的收尾保障。回顾的产出带日期的回顾文档、sprint-status 的done键与追加的行动项、前置元数据中的verdict为后续规划提供了可编程依据冲刺规划、状态 TUI 与编排器均可据此决定是否放行下一个 Epic。适用前提与限制本技能属于 BMAD 方法体系需先完成 BMAD 安装运行方式为通过render_skill.py渲染技能后按 stdout 输出的workflow.md绝对路径执行见 SKILL.md并要求uv可用、Python 3.11。冲刺型模式依赖存在可读的sprint-status.yaml规格型模式依赖SPEC.md、stories.yaml与stories/id-*.md的结构完整。文件缺失或无法解析时脚本以 JSON 错误呈现回顾按缺失证据规则记录收窄范围后继续或停止。无头模式-H epic是面向编排器的稳定接口跳过所有确认、凭证据渲染判定、把每个未经用户做出的假设选了哪个 Epic、机器判定、每个提议项记入回顾文档的 Assumptions 节以保证审计线索完整Phase 4 的验收保险fail-safe在无头运行中依然生效。判定词汇accepted/accepted-with-open-items/rejected与状态词汇open/in-progress/done是权威枚举任何其他拼写都会被脚本在触碰文件前拒绝——这是机器可读契约的一部分也是保证门禁与仪表盘一致性的前提。【免费下载链接】BMAD-METHODBreakthrough Method for Agile Ai Driven Development项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHOD创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考