Files
bmad-method-template/.claude/skills/d8d-dev/modes/validation-mode.md
zyh 39156e160f sync: d8d-dev 结构重构为 modes/phases/rules 子目录 + journey 子模式拆分
- d8d-dev: 扁平文件 → modes/(journey, validation, visual-diff), phases/, rules/ 子目录
- d8d-dev: journey-mode.md 拆分为 journey-index/definition/execution/validation 四文件
- d8d-skills-sync: 新增技能同步工具
- d8d-iterate: 新增需求迭代编排技能
2026-04-19 10:31:31 +00:00

28 KiB
Raw Blame History

验证模式

参见 ../rules/e2e-testing.md 了解 Playwright MCP 测试序列详情。 参见 ../rules/iron-laws.md 了解四维验证检查清单。 参见 ../rules/auto-fix-engine.md 了解统一修复引擎FAIL分类标准 + 修复流程 + GATE-CHECK

续跑逻辑

恢复执行时:

  1. 读取 pipeline-state.yaml
  2. 定位 current_epiccurrent_story
  3. 根据 story_results[story_key].status 判断恢复点:
    • spec-created → 从 IMPLEMENT 恢复
    • implemented → 从 TEST 恢复
    • tested-fail → 从 AUTO-FIX 恢复
  4. 跳过 sprint-status 中已标记 done 的 Story
  5. 步骤级恢复 增强 — 优先于 Story 级恢复):
    • 读取 verification-checklist.yaml → 找到当前 Story 中第一个 status: pending 的 step
    • 读取 pipeline-state.yamlstep_results → 确认最后一个已完成步骤
    • 从下一个步骤继续执行(跳过已完成的步骤,不重复截图/分析)
    • 如无 pending step → 该 Story 验证已完成,继续下一个 Story

验证模式续跑

适用场景:验证模式被中断(上下文压缩、会话断开、用户暂停),需要恢复执行。

恢复流程

  1. 用户重新调用 /d8d-dev 并选择验证模式
  2. 按顺序读取恢复信息
    pipeline-context.md → 凭据/端口/路由/进度
        ↓
    pipeline-state.yaml → 每个 Story 的 verified 状态和 verification_detail
        ↓
    sprint-status.yaml → Story 标题和 execution_order
        ↓
    TaskList → 已有 Task 状态(无 Task 则执行 Phase 0V 批量创建)
        ↓
    pm2 list → 确认服务运行
    
  3. 定位恢复点
    • 找到 pipeline-state.yaml 中第一个 verified: false 或无 verified 字段的 Story
    • 或找到 TaskList 中第一个 status: pending 的 Task
    • 从该 Story 继续验证
  4. 输出恢复信息
    🔄 恢复验证模式:已完成 M/K Story从 Story X-Y 继续
    
  5. 服务预检pm2 list 确认三个服务 online否则启动

续跑时的注意事项

  • verified: true 的 Story 跳过,不重复验证
  • 如果 pipeline-context.md 存在,从中读取凭据和路由,不需要重新发现
  • 如果 TaskList 为空,执行 Phase 0V 批量创建(但已有 verified=true 的直接标记 completed
  • 恢复后的第一个 Story 仍然需要执行完整的 8 步验证序列

验证模式逻辑

适用场景:代码已实现(首次开发或之前的流水线已完成),需要逐 Story 回归验证。

Phase 0V: 批量任务创建(验证模式前置步骤)

在开始逐 Story 验证之前,一次性创建所有 Task而非逐个创建。 这解决了上下文压缩后无法看到全局进度的问题。

  1. 读取 Story 规格文档

    • 扫描 {implementation_artifacts}/ 下的 Story 规格文件(如 2-1-create-event.md
    • 从每个规格文件提取:
      • Acceptance Criteria:验收标准
      • Validation TasksV1/V2/V3具体验证检查点
      • Proto Reference:关联的原型页面
    • 如果某个 Story 没有规格文件,从 sprint-status.yaml 获取标题和 assignee
  2. 批量 TaskCreate × NN = 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)
      
  3. 生成步骤级验证清单 强制 — 写入 verification-checklist.yaml

    • 为每个待验证 Story 从 V1/V2/V3 检查点生成操作步骤条目
    • 每个步骤包含id、phaseapi/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"
      
  4. 标记已完成的 Task

    • verified: true 的 Story → 立即 TaskUpdate: completed
    • 同步将 verification-checklist.yaml 中对应 Story 的所有 steps 标记为 skipped
    • 输出: 已创建 N 个验证 Task其中 M 个已完成跳过K 个待验证
  5. 恢复时检查 TaskList 和清单文件

    • 如果 TaskList 已有 Task续跑场景→ 跳过批量创建,直接找 pending Task 继续
    • 如果 verification-checklist.yaml 已存在 → 跳过清单生成,从第一个 status=pending 的 step 继续执行

Phase 0V COMPLETE GATE

Phase 0V 以下条件全部满足后,才能进入 Story 验证循环:

  1. 所有 Task 已创建(每个未验证 Story 各有 1 个 Task
  2. 三个服务 URL 已验证可用
  3. 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_imageAI 视觉验证项目设计系统)      │
  │  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 > 0FAIL (Bug) → AUTO-FIX
  • INLINE_COUNT > 0FAIL → 集中模块存在则 AUTO-FIX不存在则 AUTO-IMPLEMENT
  • 全部为 0 → PASS

检查 2: 图标方案合规(小程序/移动端 Story 强制)

完整检测命令和判定规则见 ../reference/platform-uni-app.md 第 6 节

判定

  • tabbar_iconpath_empty=trueFAIL (未实现) → AUTO-IMPLEMENT
  • mini-program 缺 Tailwind/Iconify → WARN (未实现) → AUTO-IMPLEMENT

检查 3: Emoji 充当功能图标(所有前端强制)

完整检测命令和判定规则见 ../reference/platform-uni-app.md 第 6 节

判定

  • EMOJI_COUNT > 0FAIL (未实现) → AUTO-IMPLEMENT
  • EMOJI_COUNT === 0PASS

AUTO-FIX 动作Bug 类型)

  1. localhost fallback → 从 pipeline-context.md 读取正确域名Edit 替换
  2. 内联 API 声明(集中模块已存在)→ Edit 替换为 import 引用
  3. 替换后重新执行对应检查

AUTO-IMPLEMENT 动作(未实现类型)

  1. 读取 phase-03-implement.md 对应方案章节(如第 5 节图标方案)
  2. 按方案逐步执行安装依赖Bash→ 创建文件Write→ 修改引用Edit→ 重启服务Bash
  3. 重测验证

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 > 0FAIL (未实现) → AUTO-IMPLEMENT: 实现该功能
  • PLACEHOLDER_COUNT === 0PASS

检查 5: 零交互元素检测Story 涉及前端页面时浏览器端检查)

在 E2E 验证步骤(步骤 4browser_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 === 0hasContent === trueFAIL → 触发 FAIL #5 诊断子步骤(见 auto-fix-engine.md
  • interactiveCount > 0PASS → 继续正常 E2E 流程

检查 6: UI 硬编码英文枚举值(所有前端 Story 强制)

在 E2E 验证步骤(步骤 4browser_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 === trueFAIL (#15) → AUTO-FIX添加中文映射函数
  • hasEnglishEnum === falsePASS

步骤 4: E2E 交互验证Story 涉及前端页面时)

  • 必须使用完整 8 步 Playwright 测试序列(见下方"Playwright MCP 测试序列模式"
  • 按 Story 规格文档的 V2 Validation Tasks 逐项验证
  • 禁止只执行 navigate + snapshot 就跳过 —— 这是验证模式最常见的失败模式
  • 管理后台:必须填写表单、点击按钮、验证提交结果
  • 小程序:必须模拟用户交互流程(登录/浏览/报名等)
  • 切换前端目标时必须 browser_resize 到正确视口

交互后 UI 验证规则(不可省略)

每个交互操作click/type/upload完成后必须按以下顺序验证

  1. browser_snapshot → 确认 DOM 状态变化checked/selected/disabled/value 变化)
  2. browser_take_screenshot → 保存视觉证据
  3. 与操作前 snapshot 对比 → 确认 UI 有可观察的变化
  4. 如无变化 → 标记 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 必须通过才能继续)

在步骤 6analyze_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 检查 1localhost fallback
├── icon_solution_compliant === true               ← 步骤 3.5 检查 2图标方案合规小程序/移动端)
├── source_code_no_emoji_icons === true            ← 步骤 3.5 检查 3Emoji 充当图标)
├── 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 为完成。必须定位漏写的文件并修复后再继续。