fix(bmm): remove stale validate-prd references (fixes #1030) (#1038)

- Remove validate-prd workflow references from all workflow path YAML files
- Update Excalidraw diagram: remove Validate PRD box and zombie JSON elements
- Re-export SVG at 1x scale
- Standardize implementation-readiness descriptions across all docs
- Add validation script (validate-svg-changes.sh) and README for SVG export process
- Correct Excalidraw timestamps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Brian <bmadcode@gmail.com>
This commit is contained in:
Alex Verkhovsky 2025-12-05 19:35:46 -08:00 committed by GitHub
parent c95b65f462
commit 5ee1551b5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 474 additions and 243 deletions

View File

@ -76,8 +76,7 @@ The BMad Method Module (BMM) provides a comprehensive team of specialized AI age
- `create-prd` - Create PRD for Level 2-4 projects (creates FRs/NFRs only)
- `tech-spec` - Quick spec for Level 0-1 projects
- `create-epics-and-stories` - Break PRD into implementable pieces (runs AFTER architecture)
- `validate-prd` - Validate PRD completeness
- `validate-tech-spec` - Validate Technical Specification
- `implementation-readiness` - Validate PRD + Architecture + Epics + UX (optional)
- `correct-course` - Handle mid-project changes
- `workflow-init` - Initialize workflow tracking
@ -146,7 +145,7 @@ The BMad Method Module (BMM) provides a comprehensive team of specialized AI age
- `workflow-status` - Check what to do next
- `create-architecture` - Produce a Scale Adaptive Architecture
- `validate-architecture` - Validate architecture document
- `implementation-readiness` - Validate readiness for Phase 4
- `implementation-readiness` - Validate PRD + Architecture + Epics + UX (optional)
**Communication Style:** Comprehensive yet pragmatic. Uses architectural metaphors. Balances technical depth with accessibility. Connects decisions to business value.
@ -642,13 +641,12 @@ Some workflows are available to multiple agents:
Many workflows have optional validation workflows that perform independent review:
| Validation | Agent | Validates |
| ----------------------- | ----------- | -------------------------------- |
| `validate-prd` | PM | PRD completeness (FRs/NFRs only) |
| `validate-tech-spec` | PM | Technical specification quality |
| `validate-architecture` | Architect | Architecture document |
| `validate-design` | UX Designer | UX specification and artifacts |
| `validate-create-story` | SM | Story draft |
| Validation | Agent | Validates |
| -------------------------- | ----------- | ------------------------------------------ |
| `implementation-readiness` | Architect | PRD + Architecture + Epics + UX (optional) |
| `validate-architecture` | Architect | Architecture document |
| `validate-design` | UX Designer | UX specification and artifacts |
| `validate-create-story` | SM | Story draft |
**When to use validation:**
@ -945,9 +943,8 @@ Agent analyzes project state → recommends next workflow
```
Each phase has validation gates:
- Phase 2 to 3: validate-prd, validate-tech-spec
- Phase 3 to 4: implementation-readiness
Run validation before advancing
- Phase 3 to 4: implementation-readiness (validates PRD + Architecture + Epics + UX (optional))
Run validation before advancing to implementation
```
**Course correction:**

View File

@ -147,7 +147,7 @@ If status file exists, use workflow-status. If not, use workflow-init.
### Q: How do I know when Phase 3 is complete and I can start Phase 4?
**A:** For Level 3-4, run the implementation-readiness workflow. It validates that PRD (FRs/NFRs), architecture, epics+stories, and UX (if applicable) are cohesive before implementation. Pass the gate check = ready for Phase 4.
**A:** For Level 3-4, run the implementation-readiness workflow. It validates PRD + Architecture + Epics + UX (optional) are aligned before implementation. Pass the gate check = ready for Phase 4.
### Q: Can I run workflows in parallel or do they have to be sequential?

View File

@ -246,7 +246,7 @@ Workflow that initializes Phase 4 implementation by creating sprint-status.yaml,
### Gate Check
Validation workflow (implementation-readiness) run before Phase 4 to ensure PRD, architecture, and UX documents are cohesive with no gaps or contradictions. Required for BMad Method and Enterprise Method tracks.
Validation workflow (implementation-readiness) run before Phase 4 to ensure PRD + Architecture + Epics + UX (optional) are aligned with no gaps or contradictions. Required for BMad Method and Enterprise Method tracks.
### DoD (Definition of Done)

View File

@ -0,0 +1,37 @@
# Workflow Diagram Maintenance
## Regenerating SVG from Excalidraw
When you edit `workflow-method-greenfield.excalidraw`, regenerate the SVG:
1. Open https://excalidraw.com/
2. Load the `.excalidraw` file
3. Click menu (☰) → Export image → SVG
4. **Set "Scale" to 1x** (default is 2x)
5. Click "Export"
6. Save as `workflow-method-greenfield.svg`
7. **Validate the changes** (see below)
8. Commit both files together
**Important:**
- Always use **1x scale** to maintain consistent dimensions
- Automated export tools (`excalidraw-to-svg`) are broken - use manual export only
## Visual Validation
After regenerating the SVG, validate that it renders correctly:
```bash
./tools/validate-svg-changes.sh src/modules/bmm/docs/images/workflow-method-greenfield.svg
```
This script:
- Checks for required dependencies (Playwright, ImageMagick)
- Installs Playwright locally if needed (no package.json pollution)
- Renders old vs new SVG using browser-accurate rendering
- Compares pixel-by-pixel and generates a diff image
- Outputs a prompt for AI visual analysis (paste into Gemini/Claude)
**Threshold**: <0.01% difference is acceptable (anti-aliasing variations)

View File

@ -1036,10 +1036,6 @@
"type": "arrow",
"id": "arrow-discovery-no"
},
{
"type": "arrow",
"id": "arrow-prd-validate"
},
{
"id": "arrow-phase1-to-phase2",
"type": "arrow"
@ -1055,17 +1051,21 @@
{
"id": "arrow-has-ui-no",
"type": "arrow"
},
{
"id": "arrow-prd-hasui",
"type": "arrow"
}
],
"locked": false,
"version": 107,
"versionNonce": 930129274,
"version": 108,
"versionNonce": 930129275,
"index": "aN",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"updated": 1764191563350,
"updated": 1764952855000,
"link": null
},
{
@ -1107,197 +1107,6 @@
"autoResize": true,
"lineHeight": 1.25
},
{
"id": "arrow-prd-validate",
"type": "arrow",
"x": 439.4640518625828,
"y": 331.0450590268819,
"width": 0.17283039375342923,
"height": 28.50332681186643,
"angle": 0,
"strokeColor": "#1976d2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 0,
"opacity": 100,
"groupIds": [],
"startBinding": {
"elementId": "proc-prd",
"focus": 0,
"gap": 1
},
"endBinding": {
"elementId": "proc-validate-prd",
"focus": 0,
"gap": 1
},
"points": [
[
0,
0
],
[
0.17283039375342923,
28.50332681186643
]
],
"lastCommittedPoint": null,
"version": 102,
"versionNonce": 1274591910,
"index": "aP",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"roundness": null,
"boundElements": [],
"updated": 1764191023838,
"link": null,
"locked": false,
"startArrowhead": null,
"endArrowhead": "arrow"
},
{
"id": "proc-validate-prd",
"type": "rectangle",
"x": 360,
"y": 360,
"width": 160,
"height": 80,
"angle": 0,
"strokeColor": "#43a047",
"backgroundColor": "#c8e6c9",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 0,
"opacity": 100,
"roundness": {
"type": 3,
"value": 8
},
"groupIds": [
"proc-validate-prd-group"
],
"boundElements": [
{
"type": "text",
"id": "proc-validate-prd-text"
},
{
"type": "arrow",
"id": "arrow-prd-validate"
},
{
"type": "arrow",
"id": "arrow-validate-prd-hasui"
},
{
"id": "jv0rnlK2D9JKIGTO7pUtT",
"type": "arrow"
}
],
"locked": false,
"version": 3,
"versionNonce": 894806650,
"index": "aQ",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"updated": 1764191341774,
"link": null
},
{
"id": "proc-validate-prd-text",
"type": "text",
"x": 370,
"y": 375,
"width": 140,
"height": 50,
"angle": 0,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 0,
"opacity": 100,
"groupIds": [
"proc-validate-prd-group"
],
"fontSize": 14,
"fontFamily": 1,
"text": "Validate PRD\n<<optional>>",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": "proc-validate-prd",
"locked": false,
"version": 2,
"versionNonce": 944332155,
"index": "aR",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"roundness": null,
"boundElements": [],
"updated": 1763522171080,
"link": null,
"originalText": "Validate PRD\n<<optional>>",
"autoResize": true,
"lineHeight": 1.7857142857142858
},
{
"id": "arrow-validate-prd-hasui",
"type": "arrow",
"x": 440,
"y": 440,
"width": 0,
"height": 30,
"angle": 0,
"strokeColor": "#1976d2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 0,
"opacity": 100,
"groupIds": [],
"startBinding": {
"elementId": "proc-validate-prd",
"focus": 0,
"gap": 1
},
"endBinding": {
"elementId": "decision-has-ui",
"focus": 0,
"gap": 1
},
"points": [
[
0,
0
],
[
0,
30
]
],
"lastCommittedPoint": null,
"version": 2,
"versionNonce": 1369541557,
"index": "aS",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"roundness": null,
"boundElements": [],
"updated": 1763522171080,
"link": null,
"locked": false,
"startArrowhead": null,
"endArrowhead": "arrow"
},
{
"id": "decision-has-ui",
"type": "diamond",
@ -1322,7 +1131,7 @@
},
{
"type": "arrow",
"id": "arrow-validate-prd-hasui"
"id": "arrow-prd-hasui"
},
{
"type": "arrow",
@ -1334,15 +1143,15 @@
}
],
"locked": false,
"version": 2,
"versionNonce": 1003877915,
"version": 3,
"versionNonce": 1003877916,
"index": "aT",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"roundness": null,
"updated": 1763522171080,
"updated": 1764952855000,
"link": null
},
{
@ -5162,6 +4971,57 @@
"startArrowhead": null,
"endArrowhead": "arrow",
"elbowed": false
},
{
"id": "arrow-prd-hasui",
"type": "arrow",
"x": 440,
"y": 330,
"width": 0,
"height": 140,
"angle": 0,
"strokeColor": "#1976d2",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 2,
"roughness": 0,
"opacity": 100,
"groupIds": [],
"startBinding": {
"elementId": "proc-prd",
"focus": 0,
"gap": 1
},
"endBinding": {
"elementId": "decision-has-ui",
"focus": 0,
"gap": 1
},
"points": [
[
0,
0
],
[
0,
140
]
],
"lastCommittedPoint": null,
"version": 1,
"versionNonce": 1,
"index": "b1J",
"isDeleted": false,
"strokeStyle": "solid",
"seed": 1,
"frameId": null,
"roundness": null,
"boundElements": [],
"updated": 1764952855000,
"link": null,
"locked": false,
"startArrowhead": null,
"endArrowhead": "arrow"
}
],
"appState": {

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -56,11 +56,6 @@ phases:
output: "Enterprise PRD with compliance requirements"
note: "Must address existing system constraints and migration strategy"
- id: "validate-prd"
recommended: true
agent: "pm"
command: "validate-prd"
- id: "create-ux-design"
recommended: true
agent: "ux-designer"
@ -114,7 +109,7 @@ phases:
required: true
agent: "architect"
command: "implementation-readiness"
note: "Critical gate - validates all planning + Epics before touching production system"
note: "Validates PRD + Architecture + Epics + UX (optional)"
- phase: 3
name: "Implementation"

View File

@ -44,11 +44,6 @@ phases:
output: "Comprehensive Product Requirements Document"
note: "Enterprise-level requirements with compliance considerations"
- id: "validate-prd"
recommended: true
agent: "pm"
command: "validate-prd"
- id: "create-ux-design"
recommended: true
agent: "ux-designer"
@ -102,7 +97,7 @@ phases:
required: true
agent: "architect"
command: "implementation-readiness"
note: "Validates all planning artifacts + Epics + testability align before implementation"
note: "Validates PRD + Architecture + Epics + UX (optional)"
- phase: 3
name: "Implementation"

View File

@ -55,11 +55,6 @@ phases:
output: "PRD focused on new features/changes"
note: "Must consider existing system constraints"
- id: "validate-prd"
optional: true
agent: "pm"
command: "validate-prd"
- id: "create-ux-design"
conditional: "if_has_ui"
agent: "ux-designer"
@ -98,7 +93,7 @@ phases:
required: true
agent: "architect"
command: "implementation-readiness"
note: "Validates PRD + UX + Architecture + Epics cohesion before implementation"
note: "Validates PRD + Architecture + Epics + UX (optional)"
- phase: 3
name: "Implementation"

View File

@ -43,12 +43,6 @@ phases:
command: "prd"
output: "Product Requirements Document with FRs and NFRs"
- id: "validate-prd"
optional: true
agent: "pm"
command: "validate-prd"
note: "Quality check for PRD completeness"
- id: "create-ux-design"
conditional: "if_has_ui"
agent: "ux-designer"
@ -89,7 +83,7 @@ phases:
required: true
agent: "architect"
command: "implementation-readiness"
note: "Validates PRD + UX + Architecture + Epics + Testability cohesion before implementation"
note: "Validates PRD + Architecture + Epics + UX (optional)"
- phase: 3
name: "Implementation"

356
tools/validate-svg-changes.sh Executable file
View File

@ -0,0 +1,356 @@
#!/bin/bash
#
# Visual SVG Validation Script
#
# Compares old vs new SVG files using browser-accurate rendering (Playwright)
# and pixel-level comparison (ImageMagick), then generates a prompt for AI analysis.
#
# Usage: ./tools/validate-svg-changes.sh <path-to-svg>
#
set -e
SVG_FILE="${1:-src/modules/bmm/docs/images/workflow-method-greenfield.svg}"
TMP_DIR="/tmp/svg-validation-$$"
echo "🎨 Visual SVG Validation"
echo ""
# Check if file exists
if [ ! -f "$SVG_FILE" ]; then
echo "❌ Error: SVG file not found: $SVG_FILE"
exit 1
fi
# Check for ImageMagick
if ! command -v magick &> /dev/null; then
echo "❌ ImageMagick not found"
echo ""
echo "Install with:"
echo " brew install imagemagick"
echo ""
exit 1
fi
echo "✓ ImageMagick found"
# Check for Node.js
if ! command -v node &> /dev/null; then
echo "❌ Node.js not found"
exit 1
fi
echo "✓ Node.js found ($(node -v))"
# Check for Playwright (local install)
if [ ! -d "node_modules/playwright" ]; then
echo ""
echo "📦 Playwright not found locally"
echo "Installing Playwright (local to this project, no package.json changes)..."
echo ""
npm install --no-save playwright
echo ""
echo "✓ Playwright installed"
else
echo "✓ Playwright found"
fi
echo ""
echo "🔄 Rendering SVGs to PNG..."
echo ""
# Create temp directory
mkdir -p "$TMP_DIR"
# Extract old SVG from git
git show HEAD:"$SVG_FILE" > "$TMP_DIR/old.svg" 2>/dev/null || {
echo "❌ Could not extract old SVG from git HEAD"
echo " Make sure you have uncommitted changes to compare"
exit 1
}
# Copy new SVG
cp "$SVG_FILE" "$TMP_DIR/new.svg"
# Create Node.js renderer script in project directory (so it can find node_modules)
cat > "tools/render-svg-temp.js" << 'EOJS'
const { chromium } = require('playwright');
const fs = require('fs');
async function renderSVG(svgPath, pngPath) {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
const svgContent = fs.readFileSync(svgPath, 'utf8');
const widthMatch = svgContent.match(/width="([^"]+)"/);
const heightMatch = svgContent.match(/height="([^"]+)"/);
const width = Math.ceil(parseFloat(widthMatch[1]));
const height = Math.ceil(parseFloat(heightMatch[1]));
const html = `
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; padding: 0; background: white; }
svg { display: block; }
</style>
</head>
<body>${svgContent}</body>
</html>
`;
await page.setContent(html);
await page.setViewportSize({ width, height });
await page.waitForTimeout(1000);
await page.screenshot({ path: pngPath, fullPage: true });
await browser.close();
console.log(`✓ Rendered ${pngPath}`);
}
(async () => {
await renderSVG(process.argv[2], process.argv[3]);
await renderSVG(process.argv[4], process.argv[5]);
})();
EOJS
# Render both SVGs (run from project dir so node_modules is accessible)
node tools/render-svg-temp.js \
"$TMP_DIR/old.svg" "$TMP_DIR/old.png" \
"$TMP_DIR/new.svg" "$TMP_DIR/new.png"
# Clean up temp script
rm tools/render-svg-temp.js
echo ""
echo "🔍 Comparing pixels..."
echo ""
# Compare using ImageMagick
DIFF_OUTPUT=$(magick compare -metric AE "$TMP_DIR/old.png" "$TMP_DIR/new.png" "$TMP_DIR/diff.png" 2>&1 || true)
DIFF_PIXELS=$(echo "$DIFF_OUTPUT" | awk '{print $1}')
# Get image dimensions
DIMENSIONS=$(magick identify -format "%wx%h" "$TMP_DIR/old.png")
WIDTH=$(echo "$DIMENSIONS" | cut -d'x' -f1)
HEIGHT=$(echo "$DIMENSIONS" | cut -d'x' -f2)
TOTAL_PIXELS=$((WIDTH * HEIGHT))
# Calculate percentage
DIFF_PERCENT=$(echo "scale=4; $DIFF_PIXELS / $TOTAL_PIXELS * 100" | bc)
echo "📊 Results:"
echo " Dimensions: ${WIDTH} × ${HEIGHT}"
echo " Total pixels: $(printf "%'d" $TOTAL_PIXELS)"
echo " Different pixels: $(printf "%'d" $DIFF_PIXELS)"
echo " Difference: ${DIFF_PERCENT}%"
echo ""
if (( $(echo "$DIFF_PERCENT < 0.01" | bc -l) )); then
echo "✅ ESSENTIALLY IDENTICAL (< 0.01% difference)"
VERDICT="essentially identical"
elif (( $(echo "$DIFF_PERCENT < 0.1" | bc -l) )); then
echo "⚠️ MINOR DIFFERENCES (< 0.1%)"
VERDICT="minor differences detected"
else
echo "❌ SIGNIFICANT DIFFERENCES (≥ 0.1%)"
VERDICT="significant differences detected"
fi
echo ""
echo "📁 Output files:"
echo " Old render: $TMP_DIR/old.png"
echo " New render: $TMP_DIR/new.png"
echo " Diff image: $TMP_DIR/diff.png"
echo ""
# Generate HTML comparison page
cat > "$TMP_DIR/comparison.html" << 'EOHTML'
<!DOCTYPE html>
<html>
<head>
<title>SVG Comparison</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #f5f5f5;
padding: 20px;
}
.header {
background: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 { margin-bottom: 10px; color: #333; }
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
margin-top: 15px;
}
.stat {
background: #f8f9fa;
padding: 10px;
border-radius: 4px;
}
.stat-label { font-size: 12px; color: #666; text-transform: uppercase; }
.stat-value { font-size: 18px; font-weight: 600; color: #333; margin-top: 4px; }
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.panel {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h2 {
margin: 0 0 15px 0;
color: #333;
font-size: 18px;
border-bottom: 2px solid #e0e0e0;
padding-bottom: 10px;
}
.image-container {
border: 1px solid #ddd;
background: white;
overflow: auto;
max-height: 600px;
}
img {
display: block;
max-width: 100%;
height: auto;
}
.verdict {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 14px;
font-weight: 600;
}
.verdict.good { background: #d4edda; color: #155724; }
.verdict.warning { background: #fff3cd; color: #856404; }
.verdict.bad { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<div class="header">
<h1>🎨 SVG Visual Comparison</h1>
<p><strong>File:</strong> FILENAME_PLACEHOLDER</p>
<div class="stats">
<div class="stat">
<div class="stat-label">Dimensions</div>
<div class="stat-value">DIMENSIONS_PLACEHOLDER</div>
</div>
<div class="stat">
<div class="stat-label">Different Pixels</div>
<div class="stat-value">DIFF_PIXELS_PLACEHOLDER</div>
</div>
<div class="stat">
<div class="stat-label">Difference</div>
<div class="stat-value">DIFF_PERCENT_PLACEHOLDER%</div>
</div>
<div class="stat">
<div class="stat-label">Verdict</div>
<div class="stat-value"><span class="verdict VERDICT_CLASS_PLACEHOLDER">VERDICT_PLACEHOLDER</span></div>
</div>
</div>
</div>
<div class="container">
<div class="panel">
<h2>📄 Old (HEAD)</h2>
<div class="image-container">
<img src="old.png" alt="Old SVG">
</div>
</div>
<div class="panel">
<h2>📝 New (Working)</h2>
<div class="image-container">
<img src="new.png" alt="New SVG">
</div>
</div>
<div class="panel">
<h2>🔍 Diff (Red = Changes)</h2>
<div class="image-container">
<img src="diff.png" alt="Diff">
</div>
</div>
</div>
</body>
</html>
EOHTML
# Determine verdict class for styling
if (( $(echo "$DIFF_PERCENT < 0.01" | bc -l) )); then
VERDICT_CLASS="good"
elif (( $(echo "$DIFF_PERCENT < 0.1" | bc -l) )); then
VERDICT_CLASS="warning"
else
VERDICT_CLASS="bad"
fi
# Replace placeholders in HTML
sed -i '' "s|FILENAME_PLACEHOLDER|$SVG_FILE|g" "$TMP_DIR/comparison.html"
sed -i '' "s|DIMENSIONS_PLACEHOLDER|${WIDTH} × ${HEIGHT}|g" "$TMP_DIR/comparison.html"
sed -i '' "s|DIFF_PIXELS_PLACEHOLDER|$(printf "%'d" $DIFF_PIXELS) / $(printf "%'d" $TOTAL_PIXELS)|g" "$TMP_DIR/comparison.html"
sed -i '' "s|DIFF_PERCENT_PLACEHOLDER|$DIFF_PERCENT|g" "$TMP_DIR/comparison.html"
sed -i '' "s|VERDICT_PLACEHOLDER|$VERDICT|g" "$TMP_DIR/comparison.html"
sed -i '' "s|VERDICT_CLASS_PLACEHOLDER|$VERDICT_CLASS|g" "$TMP_DIR/comparison.html"
echo "✓ Generated comparison page: $TMP_DIR/comparison.html"
echo ""
echo "🌐 Opening comparison in browser..."
open "$TMP_DIR/comparison.html"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "🤖 AI VISUAL ANALYSIS PROMPT"
echo ""
echo "Copy and paste this into Gemini/Claude with the diff image attached:"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
cat << PROMPT
I've made changes to an Excalidraw diagram SVG file. Please analyze the visual differences between the old and new versions.
**Automated Analysis:**
- Dimensions: ${WIDTH} × ${HEIGHT} pixels
- Different pixels: $(printf "%'d" $DIFF_PIXELS) out of $(printf "%'d" $TOTAL_PIXELS)
- Difference: ${DIFF_PERCENT}%
- Verdict: ${VERDICT}
**Attached Image:**
The attached image shows the pixel-level diff (red = differences).
**Questions:**
1. Are the differences purely anti-aliasing/rendering artifacts, or are there actual content changes?
2. If there are content changes, what specifically changed?
3. Do the changes align with the intent to remove zombie Excalidraw elements (elements marked as deleted but left in the JSON)?
4. Is this safe to commit?
**Context:**
- File: $SVG_FILE
- Changes: Removed 191 lines of zombie JSON from Excalidraw source
- Expected: Visual output should be identical (zombie elements were already marked as deleted)
PROMPT
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "📎 Attach this file to your AI prompt:"
echo " $TMP_DIR/diff.png"
echo ""
echo "💡 To open the diff image:"
echo " open $TMP_DIR/diff.png"
echo ""