UX Polish Loop
App Factory's structured quality assurance system for React UIs. Combines a 20-pass iterative polish methodology with Playwright E2E testing.
Overview
The UX Polish Loop combines three components to ensure every UI is production-ready:
Ralph
A 20-pass iterative polish methodology that reviews, scores, and fixes until quality meets the threshold.
Playwright
E2E browser testing that verifies real user interactions work correctly across browsers.
Completion Promise
A verifiable definition of done that confirms all acceptance criteria are met.
The 20-Pass System
Each pass follows a systematic sequence until the UI reaches production quality.
Run Checks
Execute lint, typecheck, and E2E tests to identify any issues.
Evaluate Results
If failures exist, fix the highest-impact issue. If passing, make one high-leverage polish improvement.
Document Progress
Record what was done in ralph/PROGRESS.md
Check Completion
Verify if all acceptance criteria in ralph/ACCEPTANCE.md are met.
Continue or Complete
Write the completion promise if done, or proceed to the next pass. Loop stops when completed or after 20 passes.
The Completion Promise
The loop stops early only when this exact string is written to ralph/PROGRESS.md:
COMPLETION_PROMISE: All acceptance criteria met. UI is production-ready.This promise requires:
- All E2E tests passing
- All lint/typecheck passing
- All acceptance criteria verified
- No CRITICAL or HIGH issues remaining
Which Builders Use This?
Default Smoke Tests
Every UI project gets these baseline tests automatically.
Polish Priority Order
When all tests pass, improvements are prioritized in this order:
Directory Structure
Generated UI projects include these files for the polish loop.
<project>/
├── ralph/
│ ├── PRD.md # Product requirements
│ ├── ACCEPTANCE.md # Acceptance criteria
│ ├── LOOP.md # Loop execution instructions
│ ├── PROGRESS.md # Pass-by-pass progress log
│ └── QA_NOTES.md # Manual QA observations
├── tests/
│ └── e2e/
│ ├── smoke.spec.ts # Core smoke tests
│ └── [feature].spec.ts
├── playwright.config.ts # Playwright configuration
└── scripts/
└── ralph_loop_runner.sh # Human-in-the-loop runnerRunning the Loop
Option 1: Script Runner (Recommended)
cd <project>
npm install
npm run polish:uxOption 2: With Claude Code
cd <project>
claude
# Say: "Run the UX polish loop following ralph/LOOP.md"FAQ
Why 20 passes?
20 passes is enough to fix most issues and reach completion, but bounded to prevent infinite loops. If 20 passes aren't enough, manual intervention is needed.
Can I skip the loop?
For production UI: No. The completion promise is required. For prototypes: You can skip, but document why in QA_NOTES.md.
What if E2E tests are flaky?
Use stable selectors (data-testid), add explicit waits (waitForLoadState), and retry on CI only.