-
Notifications
You must be signed in to change notification settings - Fork 7
Evolve Loop and Quality Gate
The v3.0 polish loop. Runs lint → polish → re-lint on a generated artifact until it crosses a target score, plateaus, or hits the round cap. Below the quality gate (65), output is refused unless --force.
Round 1: evaluate input → score X1
if X1 >= 90: stop (target_hit)
apply polish passes → new artifact
Round 2: evaluate → score X2
if |X2 - X1| < 5: stop (plateau)
if X2 >= 90: stop (target_hit)
apply polish passes
Round 3..5: same logic
Round 5: if no stop yet → stop (max_rounds)
| Condition | Trigger | Result |
|---|---|---|
target_hit |
composite ≥ 90 | Ships clean. Great result. |
plateau |
` | delta_round_n - round_n-1 |
max_rounds |
5 rounds elapsed | Safety cap. |
gate_failed |
final < 65 + no --force
|
Refused. Suggests regenerate. |
| Pass | What it does | Idempotency |
|---|---|---|
strip_inline_styles |
Drops color: / font-weight: / text-align: inline attrs |
Yes (no inline → no change) |
replace_generic_ctas |
"Click here" → "View details", etc. | Yes (table-driven) |
swap_placeholder_urls |
via.placeholder.com / picsum.photos → inert data: URI |
Yes |
normalize_spacing |
Snap px values to nearest scale step (4/8/12/16/24/32/48/64/96/128). Only snaps if within 35% | Yes (already-snapped → no change) |
strip_lorem_ipsum |
Replaces Lorem ipsum with [editorial copy — replace before ship]
|
Yes |
fontweight_numeric |
font-weight: bold → font-weight: 700
|
Yes |
Each pass returns (new_artifact, changed_bool). The loop tracks which passes applied per round and surfaces them in the report.
The gate is non-negotiable unless --force. Below 65:
- The original artifact is NOT replaced
- The evolved
.evolved.html/.evolved.cssfiles are NOT written - The CLI exits with code 1
- The report includes a
gate_failedreason
The user can override with --force, which:
- Marks the result as
forced: true - Replaces files anyway
- Exit code 0
- Diagnostic notes still surface what was wrong
This gate exists because below 65, the output has multiple high-severity AI-slop fingerprints. Shipping it would dilute the brand.
# Basic usage
uxskill evolve docs/dashboard.html
# With separate CSS file
uxskill evolve docs/dashboard.html --css docs/dashboard.css
# Force-ship below gate
uxskill evolve <file> --force
# Custom round cap
uxskill evolve <file> --max-rounds 3| File | Content |
|---|---|
<input>.evolved.html |
The polished HTML (only if above gate or forced) |
<css_input>.evolved.css |
The polished CSS (only if above gate or forced) |
.ux/last-evolve.json |
Full EvolveResult with rounds + scores + polish trace |
.ux/decisions.jsonl |
+1 line — the learning signal |
from engine import evolve
result = evolve(
html=html_str,
css=css_str,
synth_system=synth_system, # Optional, used for tone_match
brief_axes=axes_dict, # Optional, for axis consistency
linter_score=92, # From a prior lint() call
force=False,
max_rounds=5,
)
print(result.initial_score, "→", result.final_score)
for r in result.rounds:
print(r.round, r.composite, r.polishes_applied)/ux-evolve is meant to be FAST and PREDICTABLE. It runs in under a second on average. Same input → same output. No API costs. No rate limits. No "the model returned slightly different output today."
If you want LLM-driven cosmetic polish, that's /ux-polish — a separate command.
- Wrong information architecture (sections in wrong order)
- Missing real content (no real copy, no real imagery)
- Stack mismatch (you want Next.js, generated Blade)
- Brand axis target wildly off (tone_match < 30 means axes are wrong, not polish)
These are flagged in the report instead of pushed through more rounds.
$ uxskill evolve docs/hero.html --css docs/hero.css
EVOLVING: docs/hero.html (initial score: 72)
Round 1: composite=72
applied: strip_inline_styles, normalize_spacing
Round 2: composite=84 (delta +12)
applied: replace_generic_ctas, fontweight_numeric
Round 3: composite=89 (delta +5)
applied: swap_placeholder_urls
Round 4: composite=91 → target_hit. Stop.
EVOLVE COMPLETE: 72 → 91 (target_hit, 4 rounds)
artifact: docs/hero.evolved.html
evaluation: .ux/last-evolve.json
ledger entry: .ux/decisions.jsonl (+1)- v3-The-Brain
- Synthesizer-7-axes
- Decisions-Ledger-and-Learning
- All-22-Commands — every command, including /ux-evolve