- d8d-dev: 扁平文件 → modes/(journey, validation, visual-diff), phases/, rules/ 子目录 - d8d-dev: journey-mode.md 拆分为 journey-index/definition/execution/validation 四文件 - d8d-skills-sync: 新增技能同步工具 - d8d-iterate: 新增需求迭代编排技能
28 KiB
验证模式
参见 ../rules/e2e-testing.md 了解 Playwright MCP 测试序列详情。 参见 ../rules/iron-laws.md 了解四维验证检查清单。 参见 ../rules/auto-fix-engine.md 了解统一修复引擎(FAIL分类标准 + 修复流程 + GATE-CHECK)。
续跑逻辑
恢复执行时:
- 读取
pipeline-state.yaml - 定位
current_epic和current_story - 根据
story_results[story_key].status判断恢复点:spec-created→ 从 IMPLEMENT 恢复implemented→ 从 TEST 恢复tested-fail→ 从 AUTO-FIX 恢复
- 跳过 sprint-status 中已标记
done的 Story - 步骤级恢复(⛔ 增强 — 优先于 Story 级恢复):
- 读取
verification-checklist.yaml→ 找到当前 Story 中第一个status: pending的 step - 读取
pipeline-state.yaml的step_results→ 确认最后一个已完成步骤 - 从下一个步骤继续执行(跳过已完成的步骤,不重复截图/分析)
- 如无 pending step → 该 Story 验证已完成,继续下一个 Story
- 读取
验证模式续跑
适用场景:验证模式被中断(上下文压缩、会话断开、用户暂停),需要恢复执行。
恢复流程
- 用户重新调用
/d8d-dev并选择验证模式 - 按顺序读取恢复信息:
pipeline-context.md → 凭据/端口/路由/进度 ↓ pipeline-state.yaml → 每个 Story 的 verified 状态和 verification_detail ↓ sprint-status.yaml → Story 标题和 execution_order ↓ TaskList → 已有 Task 状态(无 Task 则执行 Phase 0V 批量创建) ↓ pm2 list → 确认服务运行 - 定位恢复点:
- 找到
pipeline-state.yaml中第一个verified: false或无verified字段的 Story - 或找到
TaskList中第一个status: pending的 Task - 从该 Story 继续验证
- 找到
- 输出恢复信息:
🔄 恢复验证模式:已完成 M/K Story,从 Story X-Y 继续 - 服务预检:
pm2 list确认三个服务 online,否则启动
续跑时的注意事项
- 已
verified: true的 Story 跳过,不重复验证 - 如果
pipeline-context.md存在,从中读取凭据和路由,不需要重新发现 - 如果 TaskList 为空,执行 Phase 0V 批量创建(但已有 verified=true 的直接标记 completed)
- 恢复后的第一个 Story 仍然需要执行完整的 8 步验证序列
验证模式逻辑
适用场景:代码已实现(首次开发或之前的流水线已完成),需要逐 Story 回归验证。
Phase 0V: 批量任务创建(验证模式前置步骤)
在开始逐 Story 验证之前,一次性创建所有 Task,而非逐个创建。 这解决了上下文压缩后无法看到全局进度的问题。
-
读取 Story 规格文档
- 扫描
{implementation_artifacts}/下的 Story 规格文件(如2-1-create-event.md) - 从每个规格文件提取:
- Acceptance Criteria:验收标准
- Validation Tasks(V1/V2/V3):具体验证检查点
- Proto Reference:关联的原型页面
- 如果某个 Story 没有规格文件,从 sprint-status.yaml 获取标题和 assignee
- 扫描
-
批量 TaskCreate × N(N = Story 总数)
- 每个 Task 的 description 从对应规格文档提取:
subject: "Verify Story 2-1: 创建组局" description: | 验收标准(来自 2-1-create-event.md): V1 API: POST /api/events 201/400/401/403 测试 V2 前端: 表单字段/标签切换/人数计数器/价格输入/提交 V3 集成: DB 记录创建/organizerId 关联 Story 类型: API+前端 (assignee: frontend+backend)
- 每个 Task 的 description 从对应规格文档提取:
-
生成步骤级验证清单(⛔ 强制 — 写入 verification-checklist.yaml)
- 为每个待验证 Story 从 V1/V2/V3 检查点生成操作步骤条目
- 每个步骤包含:id、phase(api/e2e/source-check)、action、expected、screenshot_required、screenshot_path、analyze_image_required、status(初始 pending)
- 为每个 Story 生成 gate_check 条目(9 项检查,初始 pending)
- 写入
_bmad-output/implementation-artifacts/verification-checklist.yaml:generated_at: "{ISO timestamp}" mode: "validation" stories: "X-Y-title": title: "{Story 标题}" assignee: "{assignee}" steps: - id: "X-Y-s{N}" phase: "api|e2e|source-check" action: "{操作描述}" expected: "{预期结果}" screenshot_required: true/false screenshot_path: "tests/e2e/screenshots/story-X-Y-step{N}.png" analyze_image_required: true/false status: "pending" gate_check: - check: "{检查项名称}" status: "pending"
-
标记已完成的 Task
- 已
verified: true的 Story → 立即TaskUpdate: completed - 同步将 verification-checklist.yaml 中对应 Story 的所有 steps 标记为
skipped - 输出:
已创建 N 个验证 Task,其中 M 个已完成(跳过),K 个待验证
- 已
-
恢复时检查 TaskList 和清单文件
- 如果 TaskList 已有 Task(续跑场景)→ 跳过批量创建,直接找 pending Task 继续
- 如果 verification-checklist.yaml 已存在 → 跳过清单生成,从第一个 status=pending 的 step 继续执行
Phase 0V COMPLETE GATE
⛔ Phase 0V 以下条件全部满足后,才能进入 Story 验证循环:
- 所有 Task 已创建(每个未验证 Story 各有 1 个 Task)
- 三个服务 URL 已验证可用
- pipeline-context.md 已读取且凭据有效
任一未满足 → 停在 Phase 0V,修复后再继续。不得跳过此门进入 Story 验证。
验证模式状态机
Phase 0V: 批量创建 Task + 读取 Story 规格文档
↓
读取 pipeline-context.md + pipeline-state.yaml + sprint-status.yaml
↓
构建验证队列(所有 Story,按 execution_order)
↓
逐 Story 独立执行(一个完成才能开始下一个):
↓
┌───────────────────────────────────────────────────┐
│ PER-STORY VERIFICATION(每个 Story 独立执行) │
│ │
│ 0. 读取 pipeline-context.md 恢复上下文 │
│ 1. TaskUpdate → in_progress │
│ 2. 读取 Story 规格文档提取 Validation Tasks │
│ 3. VERIFY-API → curl 测试(按 V1 检查点) │
│ 4. VERIFY-E2E → Playwright MCP(按 V2 检查点) │
│ ├── browser_resize(设置正确视口) │
│ ├── browser_navigate + browser_snapshot │
│ ├── browser_type + browser_click(交互操作) │
│ ├── browser_wait_for + browser_snapshot(验证) │
│ ├── browser_take_screenshot(保存证据) │
│ └── analyze_image(AI 视觉验证项目设计系统) │
│ 4.5. GATE-CHECK(⛔ 必须全部通过才能继续) │
│ 检查项: │
│ - layout_check.horizontal_overflow === false │
│ - icons_check.broken_images === false │
│ - icons_check.emoji_as_icons === false │
│ - api_target_verified === true(外网模式下) │
│ 任一 FAIL → 走 AUTO-FIX 路径 │
│ 5. MARK-VERIFIED → pipeline-state + pipeline-context│
└──────┬────────────────────────────────────────────┘
│ 失败
↓
┌──────────────────┐ ┌───────────────────────────────────┐
│ AUTO-FIX │ │ AUTO-IMPLEMENT │
│ (Bug修复, max 3x)│ │ (未实现功能, max 2x) │
│ Edit 改几行代码 │ │ 读取 phase-03 方案 → 完整实现 │
│ → 重测 │ │ Bash+Write+Edit → 重启 → 重测 │
└──────────────────┘ └───────────────────────────────────┘
│
↓(所有 Story verified 后)
继续下一个 Epic
> 跨 Epic 的用户旅程验证已独立为「旅程验证模式」,不在此模式中执行。
> 回归验证模式只负责逐 Story 功能点验证。完成所有 Story 后建议进入旅程验证模式。
> AUTO-FIX/AUTO-IMPLEMENT/AUTO-DATA-FIX 的完整分类标准和修复流程见 ../rules/auto-fix-engine.md
与完整模式的区别
- 不执行 CREATE-SPEC、IMPLEMENT、REVIEW 阶段
- 只执行 TEST(单元测试 + E2E)+ AUTO-FIX
- 每个验证通过的 Story 标记
verified: true
验证模式的 Task 粒度规则
铁律三同样适用于验证模式。每个 Story 必须创建独立的验证 Task,独立执行完毕后才能开始下一个。
| 规则 | 说明 |
|---|---|
| 35 个 Story = 35 个 TaskCreate | 每个 Task 对应一个 Story,禁止合并 |
| 每个 Task 独立执行完毕后才能创建下一个 | 禁止批量 |
| 禁止一个 Bash 命令测试多个 Story 的 API | 每条 curl 只测一个端点 |
| 禁止一次 Playwright 会话验证多个 Story | 每个 Story 独立 session |
验证模式的执行模板(每个 Story)
每个 Story 的验证必须按以下模板逐步执行,不允许省略任何步骤:
步骤 1: 创建 Task
TaskCreate: subject: "Verify Story X-Y: {title}"
TaskUpdate: status: in_progress
步骤 1.1: 解析 URL(每个 Story 必须执行)
从 pipeline-context.md 的"## 当前使用的 URL"部分读取本次验证使用的 URL。
如果 pipeline-context.md 已有"当前使用的 URL"且三个 URL 都可用 → 直接使用,跳过重新探测。
如果 pipeline-context.md 没有此部分或某个 URL 不可用 → 执行 URL 解析三步法:
对每个服务(API / Admin / Mini-H5):
Step 1: curl -sf --max-time 5 https://{外网域名}
↳ 200 → 使用 HTTPS
↳ 失败 → Step 2
Step 2: curl -sf --max-time 5 http://{外网域名}
↳ 200 → 使用 HTTP
↳ 502 → Step 2.5(诊断修复,见 phase-00-setup.md 4.6)
↳ 失败 → Step 3
Step 3: curl -sf --max-time 5 http://localhost:{port}
↳ 200 → 使用 localhost(记录 fallback_reason)
↳ 失败 → 服务未启动
⛔ 关键规则:
- 禁止跳过 HTTP 直接 fallback 到 localhost
- 502 是可修复的配置问题(通常是 Vite 监听地址不对),必须先修复再继续
- 禁止在步骤 3/4 中硬编码 localhost,必须使用解析出的 URL
**三个基础 URL 解析后供后续步骤使用**:
- `API_URL`:用于步骤 3 的 curl 测试
- `ADMIN_URL`:用于步骤 4 管理后台的 browser_navigate
- `MINI_URL`:用于步骤 4 小程序的 browser_navigate
#### 步骤 1.5: API 路由发现(仅首次验证时)
**在验证第一个 Story 之前**执行一次路由发现,后续 Story 从 `pipeline-context.md` 查找端点:
```bash
find api/src/app/api -name "route.ts" | sort
将发现的完整路由列表写入 pipeline-context.md 的"已发现的关键路由"部分。后续每个 Story 验证时直接从 pipeline-context.md 查找对应端点,避免盲目测试导致 404。
步骤 2: 读取 Story 规格文档
- 读取
{implementation_artifacts}/{epic_num}-{story_num}-{title}.md(如果存在) - 从中提取 Validation Tasks 作为具体检查项:
- V1: API Route Validation → 作为步骤 3 API 验证的检查清单
- V2: Frontend Page Validation → 作为步骤 4 E2E 验证的检查清单
- V3: Integration Validation → 作为步骤 3/4 的补充检查
- 如果规格文件不存在,从 sprint-status.yaml 的 assignee 字段判断 Story 类型:
backend→ 纯后端frontend→ 纯前端frontend+backend→ API+前端admin→ 管理后台backend+admin→ API+管理后台
步骤 3: API 验证(Story 涉及 API 路由时)
- 一个 Bash 命令只测试当前 Story 的 API 端点
- 按 Story 规格文档的 V1 Validation Tasks 逐项验证
- 验证 HTTP status code + JSON 响应结构
- 纯前端 Story(无新 API)可跳过,但需在 Task description 中记录
api_skipped: true
步骤 3.5: 源码三重检查(Story 涉及任何前端代码时强制执行)
适用范围: app/ 下所有前端源码(admin、mini-program、web 等),排除 node_modules。 对任何涉及前端页面的 Story 强制执行,不仅限于 admin。
检查 1: API 声明 + localhost fallback(通用)
# 搜索所有前端代码中的 localhost fallback 值
LOCALHOST_FALLBACK=$(grep -rn "localhost:[0-9]" app/*/src/ --include="*.ts" --include="*.tsx" --include="*.vue" | grep -v node_modules)
LOCALHOST_COUNT=$(echo "$LOCALHOST_FALLBACK" | grep -c ":" || echo 0)
# 搜索非集中式的内联 API 声明(排除已集中化的模块文件)
INLINE_FILES=$(grep -rn "const.*API_BASE\s*=" app/*/src/ --include="*.ts" --include="*.tsx" --include="*.vue" | grep -v node_modules | grep -v "lib/api\|config/api\|lib/config")
INLINE_COUNT=$(echo "$INLINE_FILES" | grep -c ":" || echo 0)
echo "localhost_fallback=$LOCALHOST_COUNT inline_api=$INLINE_COUNT"
[ "$LOCALHOST_COUNT" -gt 0 ] && echo "LOCALHOST_FILES:" && echo "$LOCALHOST_FALLBACK"
[ "$INLINE_COUNT" -gt 0 ] && echo "INLINE_FILES:" && echo "$INLINE_FILES"
判定:
LOCALHOST_COUNT > 0→ FAIL (Bug) → AUTO-FIXINLINE_COUNT > 0→ FAIL → 集中模块存在则 AUTO-FIX,不存在则 AUTO-IMPLEMENT- 全部为 0 → PASS
检查 2: 图标方案合规(小程序/移动端 Story 强制)
完整检测命令和判定规则见 ../reference/platform-uni-app.md 第 6 节。
判定:
tabbar_iconpath_empty=true→ FAIL (未实现) → AUTO-IMPLEMENT- mini-program 缺 Tailwind/Iconify → WARN (未实现) → AUTO-IMPLEMENT
检查 3: Emoji 充当功能图标(所有前端强制)
完整检测命令和判定规则见 ../reference/platform-uni-app.md 第 6 节。
判定:
EMOJI_COUNT > 0→ FAIL (未实现) → AUTO-IMPLEMENTEMOJI_COUNT === 0→ PASS
AUTO-FIX 动作(Bug 类型):
- localhost fallback → 从 pipeline-context.md 读取正确域名,Edit 替换
- 内联 API 声明(集中模块已存在)→ Edit 替换为 import 引用
- 替换后重新执行对应检查
AUTO-IMPLEMENT 动作(未实现类型):
- 读取
phase-03-implement.md对应方案章节(如第 5 节图标方案) - 按方案逐步执行:安装依赖(Bash)→ 创建文件(Write)→ 修改引用(Edit)→ 重启服务(Bash)
- 重测验证
⛔ AUTO-FIX/IMPLEMENT 失败阻断:源码三重检查 AUTO-FIX/AUTO-IMPLEMENT 重试 3 次后仍 FAIL → Story 标记为 failed,记录到 error_log,继续下一个 Story。不得反复重试或跳过。
完整的 AUTO-FIX/IMPLEMENT/DATA-FIX 流程和重试上限见 ../rules/auto-fix-engine.md 第 4 节
检查 4: 未实现功能占位符(所有前端强制)
# 搜索前端代码中的"暂未开放"等占位符文本
PLACEHOLDER=$(grep -rn "暂未开放\|功能.*开发中\|TODO.*实现\|not.*implemented\|暂未实现\|功能未开放" \
app/*/src/ --include="*.vue" --include="*.tsx" --include="*.ts" | grep -v node_modules)
PLACEHOLDER_COUNT=$(echo "$PLACEHOLDER" | grep -c ":" || echo 0)
echo "placeholder_functions=$PLACEHOLDER_COUNT"
[ "$PLACEHOLDER_COUNT" -gt 0 ] && echo "PLACEHOLDER_FILES:" && echo "$PLACEHOLDER"
判定:
PLACEHOLDER_COUNT > 0→ FAIL (未实现) → AUTO-IMPLEMENT: 实现该功能PLACEHOLDER_COUNT === 0→ PASS
检查 5: 零交互元素检测(Story 涉及前端页面时浏览器端检查)
在 E2E 验证步骤(步骤 4)中,browser_navigate 到目标页面后,browser_snapshot 如显示有内容但无交互元素(button/input/a/form),执行:
// browser_evaluate 检查
() => {
const interactive = document.querySelectorAll('button, input, a, form, [role="button"], [role="link"]');
const hasContent = document.body.innerText.trim().length > 0;
const hasNextRoot = !!document.getElementById('__next');
const hasReactRoot = !!document.querySelector('[data-reactroot]');
const hasVueApp = !!document.querySelector('[data-v-app]');
return { interactiveCount: interactive.length, hasContent, frameworkMounted: hasNextRoot || hasReactRoot || hasVueApp };
}
判定:
interactiveCount === 0且hasContent === true→ FAIL → 触发 FAIL #5 诊断子步骤(见 auto-fix-engine.md)interactiveCount > 0→ PASS → 继续正常 E2E 流程
检查 6: UI 硬编码英文枚举值(所有前端 Story 强制)
在 E2E 验证步骤(步骤 4)中,browser_navigate 到任何前端页面后,执行:
// browser_evaluate 检查页面可见文本是否包含英文枚举值
() => {
const text = document.body.innerText;
const enumPatterns = /\b(APPROVED|REJECTED|PENDING|PAID|CANCELLED|REFUNDED|DRAFT|ONGOING|COMPLETED|AVAILABLE|FROZEN|WITHDRAWN)\b/g;
const matches = text.match(enumPatterns);
return { hasEnglishEnum: matches !== null, matches: matches || [] };
}
判定:
hasEnglishEnum === true→ FAIL (#15) → AUTO-FIX(添加中文映射函数)hasEnglishEnum === false→ PASS
步骤 4: E2E 交互验证(Story 涉及前端页面时)
- 必须使用完整 8 步 Playwright 测试序列(见下方"Playwright MCP 测试序列模式")
- 按 Story 规格文档的 V2 Validation Tasks 逐项验证
- 禁止只执行 navigate + snapshot 就跳过 —— 这是验证模式最常见的失败模式
- 管理后台:必须填写表单、点击按钮、验证提交结果
- 小程序:必须模拟用户交互流程(登录/浏览/报名等)
- 切换前端目标时必须
browser_resize到正确视口
⛔ 交互后 UI 验证规则(不可省略):
每个交互操作(click/type/upload)完成后,必须按以下顺序验证:
- browser_snapshot → 确认 DOM 状态变化(checked/selected/disabled/value 变化)
- browser_take_screenshot → 保存视觉证据
- 与操作前 snapshot 对比 → 确认 UI 有可观察的变化
- 如无变化 → 标记 FAIL + 进入诊断流程
禁止:
- ❌ 只调用 API 验证(curl POST → 200 → PASS),不检查 UI 是否更新
- ❌ 点击按钮后不检查按钮状态(disabled→enabled? loading? error?)
- ❌ 勾选框点击后不确认 checked 属性变化
- ❌ 弹窗关闭后不确认主界面是否更新
- ⛔ 视觉验证关卡(⛔ 强制 — Read fully and follow: ../rules/visual-verification.md):
- 每个关键操作后必须通过视觉验证关卡(独立步骤,不可跳过)
- 关卡 = browser_take_screenshot + analyze_image(使用 visual-verification.md 标准提示词)
- 关卡未通过 → 按分流规则处理,不得进入下一个操作
⛔ 步骤级跟踪(每个 E2E 操作步骤完成后强制执行):
每个操作步骤完成后,必须执行以下 5 项操作(与视觉验证关卡配合执行):
步骤级跟踪流程(每个 E2E 操作后):
1. 截图保存 → browser_take_screenshot
2. 视觉分析 → analyze_image(如 analyze_image_required=true)
3. 更新清单 → Edit verification-checklist.yaml 对应 step 的 status
4. 记录结果 → 追加 step_results 到 pipeline-state.yaml:
```yaml
- step_id: "X-Y-s{N}"
phase: "e2e"
action: "{操作描述}"
status: "pass|fail|fixed|skipped"
screenshot_path: "tests/e2e/screenshots/story-X-Y-step{N}.png"
analyze_image_result: { ... } # 如有
issues_detected: [ ... ] # 检测到的问题(如有)
auto_fixes: [ ... ] # 自动修复记录(如有)
step_gate: "pass|fail|blocked" # 步骤级门禁结果
gate_checks: # 5 项检查结果
- check: "screenshot_consistency"
result: "pass|fail"
- check: "analyze_image_executed"
result: "pass|fail"
- check: "checklist_synced"
result: "pass|fail"
- check: "state_persisted"
result: "pass|fail"
- check: "all_issues_resolved"
result: "pass|fail"
executed_at: "{ISO timestamp}"
note: "{备注}"
```
5. 步骤级 GATE → 检查 5 项条件:
├── G1: screenshot_consistency — 如步骤要求截图,screenshot_path 文件存在
├── G2: analyze_image_executed — 如步骤要求分析,analyze_image_result 非空
├── G3: checklist_synced — verification-checklist.yaml 中 step status 已更新
├── G4: state_persisted — pipeline-state.yaml step_results 已追加
└── G5: all_issues_resolved — issues_detected 中所有问题有对应 auto_fix 且 result=pass
任一 FAIL → 阻断,不得继续下一步骤
检测到问题时的记录格式(issues_detected):
issues_detected:
- issue_id: "ISSUE-{NNN}"
type: "{问题类型}" # layout_overflow | english_enum | emoji_icons | broken_images | svg_data_uri | dual_nav | placeholder | api_target | constraint_mismatch
severity: "{严重程度}" # bug | unimplemented | data_issue | env_limit
description: "{问题描述}"
detected_by: "{检测方式}" # browser_evaluate | analyze_image | source_scan | curl
detected_at: "{ISO timestamp}"
自动修复记录格式(auto_fixes):
auto_fixes:
- fix_id: "FIX-{NNN}"
issue_id: "ISSUE-{NNN}" # 关联的问题
fix_type: "AUTO-FIX|AUTO-IMPLEMENT|AUTO-DATA-FIX"
description: "{修复描述}"
files_changed: [ "{文件路径}" ]
retry_count: {N} # 重试次数
result: "pass|fail" # 修复结果
fixed_at: "{ISO timestamp}"
screenshot_after_fix: "{修复后截图路径}" # 修复后重测截图
步骤 5: 最终截图保存(Story 涉及前端页面时)
- browser_take_screenshot → filename: "tests/e2e/screenshots/story-{x}-{y}.png", type: "png"
- 管理后台和小程序分别截图时使用不同后缀:
story-x-y-admin.png(管理后台页面)story-x-y-mini.png(小程序页面)
- 此步骤保留作为最终证据归档(中间步骤截图已在步骤 4 中完成)
步骤 6: AI 视觉验证(Story 涉及前端页面时)
- ⛔ 详细规则和标准提示词见 ../rules/visual-verification.md
- 对最终截图强制调用
analyze_image - 不调用 analyze_image 等于未完成该 Story 的验证(GATE-CHECK 会验证
analyze_image_called: true) - 注:中间步骤的视觉验证已在步骤 4 逐步完成(视觉验证关卡),此步骤是最终确认
步骤 6.5: GATE-CHECK(⛔ 所有前端 Story 必须通过才能继续)
在步骤 6(analyze_image)之后、步骤 7(标记完成)之前执行。
检查以下条件,任一 FAIL → 不得执行步骤 7,必须进入 AUTO-FIX:
GATE-CHECK 检查项:
├── layout_check.horizontal_overflow === false ← 步骤 8.5 的溢出检测结果
├── icons_check.broken_images === false ← 步骤 8 的视觉验证结果
├── icons_check.emoji_as_icons === false ← 步骤 8 的视觉验证结果
├── api_target_verified === true ← 步骤 9 的 API 目标检测结果(外网模式下)
├── code_architecture_pass === true ← 步骤 3.5 的源码三重检查(所有前端 Story)
├── source_code_no_localhost === true ← 步骤 3.5 检查 1(localhost fallback)
├── icon_solution_compliant === true ← 步骤 3.5 检查 2(图标方案合规,小程序/移动端)
├── source_code_no_emoji_icons === true ← 步骤 3.5 检查 3(Emoji 充当图标)
├── no_placeholder_functions === true ← 步骤 3.5 检查 4("暂未开放"等未实现占位符)
├── SG1: all_steps_gated === true ← 所有 step_results 的 step_gate 均为 "pass"
├── SG2: no_unresolved_issues === true ← 所有 steps 的 issues_detected 都有对应 resolved 的 auto_fix
└── SG3: checklist_complete === true ← verification-checklist.yaml 中所有 steps 的 status 均非 "pending"
任一 FAIL → 分类分流:
Bug(代码有但值错误)→ AUTO-FIX
未实现(功能根本不存在)→ AUTO-IMPLEMENT
全部 PASS → 继续步骤 7
⛔ 跳过此步骤直接执行步骤 7 是严重违规行为。
SG1-SG3 详细判定:
SG1 (all_steps_gated):
读取 step_results → 所有条目的 step_gate === "pass"
任一 step_gate === "fail" 或 "blocked" → SG1 FAIL
SG2 (no_unresolved_issues):
遍历所有 step_results 的 issues_detected:
对每个 issue → 在 auto_fixes 中找到 issue_id 匹配的修复记录 → result === "pass"
无匹配修复或 result !== "pass" → SG2 FAIL
SG3 (checklist_complete):
读取 verification-checklist.yaml 当前 Story 的 steps:
所有条目的 status !== "pending"
任一 status === "pending" → SG3 FAIL
步骤 7: 标记完成(三个写入操作,缺一不可)
7a. TaskUpdate:
TaskUpdate: status: completed
7b. 更新 pipeline-state.yaml:
story_results:
"X-Y-title":
status: done
verified: true
verification_detail:
api_tested: true/false/skipped
api_endpoints_tested: ["POST /api/xxx", "GET /api/xxx"]
e2e_tested: true/false/skipped
screenshot_saved: true/false
screenshot_path: "tests/e2e/screenshots/story-x-y.png"
analyze_image_called: true/false
url_used: "外网域名" / "localhost(fallback)"
api_centralized: true/false
layout_check:
horizontal_overflow: true/false
tabbar_visible: true/false/null
document_width: 375
viewport_width: 375
icons_check:
tabbar_icons_visible: true/false
broken_images: true/false
emoji_as_icons: true/false
dual_write_verified: true
# ===== 新增: 步骤级结果 =====
step_results: [] # 已在步骤 3/4 执行过程中逐步追加
# ===== 新增: Story 级问题汇总 =====
total_issues_detected: 0 # 所有步骤检测到的问题总数
total_auto_fixes: 0 # 所有步骤的自动修复总数
all_issues_resolved: true # 所有问题是否全部修复
note: "简短验证摘要"
7c. 更新 pipeline-context.md 进度追踪表:
Edit pipeline-context.md 的"## 进度追踪"部分:
- 找到当前 Story 的行
- 将状态改为 ✅ done
- 填写验证摘要
⛔ 步骤 7c 是强制操作,跳过等于上下文压缩后无法恢复进度。
7d. 三写一致性验证:
# 验证 pipeline-state 和 pipeline-context 中的完成数一致
STATE_COUNT=$(grep -c "status: done" _bmad-output/implementation-artifacts/pipeline-state.yaml)
CONTEXT_COUNT=$(grep -c "✅ done" _bmad-output/implementation-artifacts/pipeline-context.md)
echo "pipeline-state: $STATE_COUNT done, pipeline-context: $CONTEXT_COUNT done"
# 如果不一致 → 说明漏写了某个文件,必须修复
⛔ 步骤 7a/7b/7c/7d 四个操作缺一不可,缺少任何一个,Story 不得标记为完成。
⛔ 三写一致性阻断:STATE_COUNT ≠ CONTEXT_COUNT 时,不得标记 Story 为完成。必须定位漏写的文件并修复后再继续。