sync: d8d-dev 增加 Pencil MCP 直接对比模式 + 旅程验证动态状态对比 #18

Merged
d8dfun merged 1 commits from sync/d8d-skills-20260410-121027 into master 2026-04-10 20:17:54 +08:00
4 changed files with 366 additions and 4 deletions

View File

@@ -378,7 +378,111 @@ Story 验证全部通过 ≠ 用户能正常使用系统。旅程模式弥补这
- 修复后重测:重新 browser_take_screenshot + analyze_image 确认问题已修复
- 修复失败 → 标记 journey-step-fail → 继续下一步骤
- 步骤 4修复阶段仅处理功能断言 FAIL不处理视觉验证 FAIL
f. 如涉及数据变化 → browser_evaluate 或 curl 验证数据(✅ 允许 curl 补充)
6. ⛔ **旅程步骤原型/Pencil 视觉对比验证**(⛔ 强制 — 针对操作时产生的动态状态)
目的: 捕获并验证操作时才会出现的视觉状态hover、选中、弹窗、展开、加载中、错误提示等这些状态在静态原型对比中无法覆盖
触发条件(满足任一即执行):
- 当前步骤操作后出现了弹窗/Modal/对话框
- 下拉菜单/Select/日期选择器展开
- 按钮/卡片/列表项处于 Hover/Active 状态
- 表单字段获得 Focus/有验证错误提示
- 页面显示 Loading/Skeleton/进度条
- 列表项被选中/高亮/勾选
- 页面切换/跳转后的首屏渲染完成
- 出现了错误提示/Toast/Notification
- 折叠面板展开/收起状态变化
执行流程:
a. 等待状态稳定(动画/过渡完成):
- browser_wait_for → time=1-2s等待动画完成
b. 捕获实际状态截图:
- browser_take_screenshot → 保存为 journey-epic{N}-{M}-step{S}-state.png
c. 搜索匹配的设计帧(双模式支持):
**Pencil MCP 模式(优先)**:
- 读取 pipeline-context.md 获取设计文件路径(如 VividSpark1.2.pen
- mcp__pencil__batch_get → 搜索与当前状态匹配的帧
- 搜索关键词: "{Page}-{State}" 如 "Dashboard-Modal", "Login-Error", "Upload-Loading"
- 或按 frame 类型和名称模式匹配
- 如找到匹配帧 → mcp__pencil__export_nodes 导出设计截图
**HTML 原型模式(回退)**:
- 检查 prototype/pages/{group}/{page}-{state}.html 是否存在
- 如存在 → 启动原型服务 → Playwright 截图
设计帧未找到处理:
- 标记 prototype_found: false
- 记录 actual_screenshot 路径
- 不阻断旅程,但记录到 pipeline-report.md 建议补充设计帧
d. 执行视觉对比(如找到设计帧):
- ui_diff_check:
- expected_image_source: 设计帧截图(或原型截图)
- actual_image_source: 当前状态截图 (journey-epic{N}-{M}-step{S}-state.png)
- prompt: "对比设计原型和实际实现。这是用户操作后出现的动态交互状态如弹窗、hover、选中、加载中、错误提示等
重点关注:
1) 组件布局和结构是否一致(弹窗位置、按钮排列等)
2) 颜色/样式是否匹配(背景色、边框、阴影等)
3) 文字内容是否正确(标题、提示信息、按钮文字等)
4) 交互状态是否准确hover 效果、选中状态、focus 样式等)
5) 图标和装饰元素是否一致
注意:忽略动态数据(如用户名、时间戳等),只关注 UI 结构和样式。
按严重程度列出所有视觉差异:"
e. 差异分级与处理:
记录到 pipeline-state.yaml:
```yaml
journey_state_visual_diff:
epic_6:
journey_1:
step_3:
state_type: "modal_open" # 状态类型: modal_open/hover/select_focus/loading/error/etc
prototype_found: true # 是否找到对应设计帧
prototype_source: "VividSpark1.2.pen:frame-456" # 设计来源
prototype_frame_id: "frame-456"
diff_check_executed: true
severity: "moderate" # critical/moderate/minor/none
differences:
- type: "color"
severity: "minor"
description: "弹窗背景色不一致:设计 #1A1A1A实际 #222222"
location: "弹窗背景"
- type: "spacing"
severity: "moderate"
description: "按钮间距偏差 8px设计 16px实际 24px"
location: "底部按钮组"
- type: "text"
severity: "critical"
description: "按钮文字错误:设计'确认',实际'提交'"
location: "主按钮"
screenshot_expected: "tests/e2e/screenshots/journey-epic6-1-step3-design.png" # 设计帧截图
screenshot_actual: "tests/e2e/screenshots/journey-epic6-1-step3-state.png" # 实际状态截图
auto_fix_triggered: true # 是否触发自动修复
auto_fix_type: "AUTO-FIX" # 修复类型
auto_fix_result: "PASS" # 修复结果
```
差异处理规则:
- 🔴 严重差异(布局错误、关键组件缺失、文字错误)→ 立即触发 AUTO-FIX
- 🟡 中等差异(颜色、间距偏差)→ 记录到 pipeline-report.md建议修复
- 🟢 轻微差异(微小像素偏移)→ 记录但不阻断旅程
- ✅ 无差异 → 标记状态正常
f. 自动修复与重测(如触发):
- AUTO-FIX 触发后:
1. 定位相关源码文件(根据差异类型确定)
2. 执行修复(如调整 CSS、修改组件样式等
3. 重新截图: browser_take_screenshot
4. 重新对比: ui_diff_check
5. 修复成功 → 标记 auto_fix_result: "PASS"
6. 修复失败 → 标记 auto_fix_result: "FAIL",记录原因
6. ⛔ **源码 SVG data URI 扫描**(视觉验证关卡内 — 每次 snapshot 后强制执行):
g. ⛔ **约束一致性检查**(每个用户步骤首次执行时 — R7 执行时强制检测):
触发条件(操作被拦截 + 声明方说"可选":
- 操作后 Toast 出现且含"请上传/请填写/请选择/不能为空/不能为空"

View File

@@ -0,0 +1,234 @@
# 原型对比验证模式 - Pencil MCP 直接对比版
> **定位**:使用 Pencil MCP 工具直接从 `.pen` 设计文件提取截图,与实际页面实现做逐页视觉对比。
>
> **与 HTML 原型版对比**
> | 维度 | Pencil MCP 直接版 | HTML 原型版 |
> |------|------------------|-------------|
> | 来源 | `.pen` 设计源文件 | `prototype/pages/*.html` |
> | 保真度 | 100% 设计稿像素级 | 可能有 HTML/CSS 转换损耗 |
> | 依赖 | Pencil MCP Server | Node.js + Express |
> | 启动 | 无需额外服务 | 需启动 `prototype/server.js` |
---
## 前置条件
```
检查清单(任一不满足 → 报错并终止):
├── .pen 设计文件存在(如 VividSpark1.2.pen
├── Pencil MCP Server 可用(`pencil` 工具集)
├── pipeline-context.md 存在(含实际应用 URL 和凭据)
├── pm2 服务运行中(实际应用可访问)
└── 至少有一个 Epic 的 Story 已 verified
```
---
## 核心流程
```
Phase PVD-0: 准备
├── 读取 .pen 文件 → 使用 Pencil MCP 发现设计页面
├── 读取 pipeline-context.md → 获取实际应用 URL
├── 构建页面映射表(设计帧 ↔ 实际路由)
└── 创建截图输出目录
Phase PVD-1: 逐页对比循环
对每个映射页面:
├── A. Pencil MCP 导出设计帧截图
├── B. Playwright 截取实际页面
├── C. UI 差异对比ui_diff_check
└── D. 差异分级 + 记录
Phase PVD-2: 汇总报告
├── 生成 visual-diff-pencil-report.md
└── 输出差异统计和修复建议
```
---
## Phase PVD-0: 准备
### 0.1 使用 Pencil MCP 发现设计页面
```
工具: mcp__pencil__batch_get
参数:
- filePath: "VividSpark1.2.pen"
- patterns: [{"type": "frame"}] # 查找所有帧/页面
- searchDepth: 2
```
从返回结果中提取所有设计帧:
- 帧名称(如 "Login", "Dashboard"
- 帧 ID如 "node-123", "frame-456"
- 帧尺寸width, height
分类为 frontend 和 admin 组:
- 帧名称含 "admin"、"Admin" → admin 组
- 其他 → frontend 组
### 0.2 读取实际应用信息
同 HTML 原型版,读取 `_bmad-output/implementation-artifacts/pipeline-context.md` 获取:
- 实际应用 URLAPI_URL, ADMIN_URL
- 认证凭据
- 已实现的路由
### 0.3 构建页面映射表
**自动映射规则**
```
对每个设计帧(从 Pencil MCP 获取):
1. 提取帧名称(如 "Login", "Dashboard"
2. 在实际路由中查找匹配:
- 帧名=Login → /login 或 /admin/login
- 帧名=Dashboard → / 或 /dashboard
- 帧名=Register → /register
- 其他 → /{帧名小写} 或 /admin/{帧名小写}
3. 验证实际路由可访问curl 检查非 404
4. 不可访问的页面标记为 skipped
```
**映射输出格式**(记录到 pipeline-state.yaml
```yaml
visual_diff_pencil_mapping:
- design_frame: "Login"
design_frame_id: "node-123"
actual_route: "/login"
group: "frontend"
status: "active" # active / skipped / error
- design_frame: "Dashboard"
design_frame_id: "node-456"
actual_route: "/"
group: "frontend"
status: "active"
```
### 0.4 创建截图输出目录
```bash
mkdir -p tests/e2e/screenshots/visual-diff-pencil
```
---
## Phase PVD-1: 逐页对比循环
对映射表中每个 `status: active` 的页面执行以下流程。
### 1.A Pencil MCP 导出设计帧截图
```
工具: mcp__pencil__export_nodes
参数:
- filePath: "VividSpark1.2.pen"
- nodeIds: ["{design_frame_id}"] # 从映射表获取
- outputDir: "tests/e2e/screenshots/visual-diff-pencil"
- format: "png"
- scale: 2 # 2x 高清
```
导出后的文件路径:
- `tests/e2e/screenshots/visual-diff-pencil/{design_frame_id}.png`
重命名为可读名称:
- `tests/e2e/screenshots/visual-diff-pencil/{name}-design.png`
### 1.B 截取实际页面截图
同 HTML 原型版,使用 Playwright
```
1. browser_navigate → {实际 URL}{route}
2. browser_resize → 1440x900与设计帧尺寸匹配
3. 处理认证(如需要)
4. browser_wait_for → time=3
5. browser_take_screenshot(fullPage=false)
→ tests/e2e/screenshots/visual-diff-pencil/{name}-actual.png
```
### 1.C UI 差异对比
```
工具: ui_diff_check
参数:
- expected_image_source: "tests/e2e/screenshots/visual-diff-pencil/{name}-design.png"
- actual_image_source: "tests/e2e/screenshots/visual-diff-pencil/{name}-actual.png"
- prompt: "对比这两张截图:第一张是 Pencil 设计稿,第二张是实际实现。列出所有视觉差异,包括布局结构、组件排列、颜色、间距、字体、图标等。按严重程度排序。"
```
### 1.D 差异分级
同 HTML 原型版:
| 级别 | 标准 | 示例 |
|------|------|------|
| 🔴 严重 | 布局结构不同、关键组件缺失 | 原型有两列布局实际一列 |
| 🟡 中等 | 颜色/间距偏差、图标不一致 | 卡片圆角不一致 |
| 🟢 轻微 | 微小像素差异 | 1-2px 偏移 |
---
## Phase PVD-2: 汇总报告
### 2.1 生成报告
生成 `tests/e2e/screenshots/visual-diff-pencil/visual-diff-pencil-report.md`
```markdown
# Visual Diff Report (Pencil MCP Direct)
生成时间: {timestamp}
对比页面数: {total_pages}
数据来源: VividSpark1.2.pen (Pencil MCP 直接导出)
## Summary
| 级别 | 数量 |
|------|------|
| 🔴 严重 | {critical_count} |
| 🟡 中等 | {moderate_count} |
| 🟢 轻微 | {minor_count} |
| ✅ 匹配 | {match_count} |
## 详细对比结果
### 🔴 {page_name}
- 设计截图: `visual-diff-pencil/{name}-design.png`
- 实际截图: `visual-diff-pencil/{name}-actual.png`
- 差异描述...
...
```
### 2.2 更新 pipeline-state.yaml
```yaml
visual_diff_pencil:
status: completed
total_pages: 11
compared_pages: 11
critical_count: 0
moderate_count: 3
minor_count: 5
match_count: 3
report_path: "tests/e2e/screenshots/visual-diff-pencil/visual-diff-pencil-report.md"
timestamp: "2026-04-08T12:00:00Z"
```
---
## 附录:与 HTML 原型版对比速查
| 步骤 | Pencil MCP 直接版 | HTML 原型版 |
|------|------------------|-------------|
| 原型来源 | `.pen` 文件 | `prototype/pages/*.html` |
| 截图工具 | `mcp__pencil__export_nodes` | Playwright 访问 `localhost:8080` |
| 保真度 | 100% 设计稿 | 可能有转换损耗 |
| 启动依赖 | 无 | 需启动 `prototype/server.js` |
| 推荐场景 | 有 `.pen` 文件时首选 | 无 `.pen` 或需 HTML 交互时 |

View File

@@ -1,6 +1,14 @@
# 原型对比验证模式Visual Diff Mode
> **定位**:在回归验证和旅程验证之后,将实际页面实现与原型 HTML 页面做逐页视觉对比,发现布局偏差、组件遗漏、交互方式差异等视觉问题。
> **定位**:在回归验证和旅程验证之后,将实际页面实现与原型做逐页视觉对比,发现布局偏差、组件遗漏、交互方式差异等视觉问题。
>
> **两种对比方式**(任选其一):
> | 方式 | 来源 | 适用场景 |
> |------|------|---------|
> | **Pencil MCP 直接版**(推荐) | `.pen` 设计源文件 | 有 `.pen` 文件时首选100% 设计稿保真度 |
> | **HTML 原型版** | `prototype/pages/*.html` | 无 `.pen` 文件或需要 HTML 交互时 |
>
> Pencil MCP 直接版文档:**[visual-diff-mode-pencil.md](./visual-diff-mode-pencil.md)**
>
> **与其他模式的关系**
> - 回归验证模式 → 检查功能点存在且正确(类比单元测试)

View File

@@ -87,7 +87,14 @@
| **单 Epic 模式** | 执行指定 Epic 的所有 Story | 按模块开发 |
| **回归验证模式** | 不做实现,逐 Story 验证功能点存在且正确 | 代码已实现需回归验证(类比:单元测试) |
| **旅程验证模式** | 专用用户旅程定义+验证(跨页面完整流程) | 跨 Story/Epic 的用户体验验证类比E2E 测试) |
| **原型对比验证模式** | 截取原型和实际页面截图,使用 ui_diff_check + analyze_image 对比差异 | Epic 完成后的视觉还原度检查(类比:视觉回归测试) |
| **原型对比验证模式** | 截取原型和实际页面截图,使用 ui_diff_check 对比差异 | Epic 完成后的视觉还原度检查(类比:视觉回归测试) |
### 原型对比验证子模式
| 子模式 | 原型来源 | 推荐场景 |
|--------|---------|---------|
| **Pencil MCP 直接版**(优先) | `.pen` 设计文件(如 VividSpark1.2.pen | 有 .pen 文件时首选100% 设计稿保真度 |
| **HTML 原型版** | `prototype/pages/*.html` | 无 .pen 文件或需要 HTML 交互时 |
## 模式选择与流转
@@ -183,9 +190,18 @@ Read fully and follow: ./journey-mode.md
### 原型对比验证模式
```
Read fully and follow: ./visual-diff-mode.md
自动检测并选择:
├── 存在 .pen 设计文件(如 VividSpark1.2.pen
│ └── Read fully and follow: ./visual-diff-mode-pencil.md # Pencil MCP 直接版
└── 不存在 .pen 文件,但存在 prototype/pages/*.html
└── Read fully and follow: ./visual-diff-mode.md # HTML 原型版
```
**手动指定子模式**
- `/d8d-dev visual-diff --pencil` → 强制使用 Pencil MCP 直接版
- `/d8d-dev visual-diff --html` → 强制使用 HTML 原型版
### 仅测试模式 / 仅审查模式
直接读取对应 Story 的 phase-04-test.md 或 phase-05-review.md 中的相关部分。