Skip to main content

aesthetic-loop

Loop agênico keep-or-revert para estética/UX — melhora a aparência de uma página por tempo limitado com juiz pairwise cego (screenshots apenas, ordem AB+BA), painel de 2–3 modelos de famílias distintas, gates determinísticos antes do juiz caro e revert automático de regressões. Use quando o usuário pedir para "deixar a UI mais bonita", "rodar o aesthetic loop" ou iterar estética sem score absoluto.

Source facts

Repository
Wesley-Source/aesthetic-loop
Last source activity
October 5, 2026 at 21:25
Detected SKILL.md language
Portuguese
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
aesthetic-loop
description
Loop agênico keep-or-revert para estética/UX — melhora a aparência de uma página por tempo limitado com juiz pairwise cego (screenshots apenas, ordem AB+BA), painel de 2–3 modelos de famílias distintas, gates determinísticos antes do juiz caro e revert automático de regressões. Use quando o usuário pedir para "deixar a UI mais bonita", "rodar o aesthetic loop" ou iterar estética sem score absoluto.
# Aesthetic Loop Melhora a estética/UX de uma página-alvo por tempo limitado. Dois papéis: - **Juiz PERSISTENTE**: orquestra, roda os gates, comuta o painel de juízes, decide keep/revert, guarda estado (champion, swap-rate, κ, contadores). NUNCA edita código e NUNCA vê a tela "por conta própria" — julga só pelos protocolos abaixo. - **Builder DESCARTÁVEL** (subagente novo a cada rodada): faz UMA mudança visual pequena. Não roda gates, não julga, não commita. **REGRA DE OURO: o builder nunca vê o veredito — só o screenshot do champion.** O veredito (racional do painel, scores, viés detectado) fica no log do juiz. O builder recebe apenas o screenshot atual, o brief de melhora e a direção estética ainda-não-tentada do deck (`directions/deck.yaml`); assim ele não mimetiza o gosto do juiz nem racionaliza regressões. ## ⚠️ Modo single-family — not recommended as sole configuration O protocolo completo (painel multi-família com firewall builder/juiz) exige **2+ famílias de modelo** em `judge/panel.yaml`. Com **1 família apenas** (ex.: só GLM/Z.ai), o loop RODA MAS EM MODO DEGRADADO: - O firewall por família é impossível: juiz e builder compartilham o mesmo prior estético de RLHF. Cegueira a código/diff NÃO remove family-bias — modelos preferem a própria impressão estilística mesmo sem saber a autoria (Panickssery et al. 2024). Ao longo de 20 rodadas o efeito líquido é convergência ao gosto-médio-da-família com reforço positivo (AI-AI bias, Risco #3 do design). - Nesse modo: gates determinísticos decidem quase tudo; o pairwise GLM-only serve só como DESEMPATE entre candidatos que passaram nos gates; rode a meta-juiz com frequência dobrada (a cada 3 rodadas, não 5) e exija voto humano no FIM antes de qualquer merge. - O README diz isso explicitamente e a validação WiserUI-Bench multi-família (benchmark/PROTOCOL.md) é o que dá licença para confiar no painel. Não publique resultados de run single-family como evidência da tese. ## Temperatura do juiz: 0.2 Fixa em `judge/panel.yaml` (`judge_temperature: 0.2`), não 0 nem 1.0: - temp 0 remove apenas ruído de amostragem, não viés (viés está nos pesos); - com temp 0, inconsistência entre ordens AB/BA vira sistemática (sempre a mesma), e o swap deixa de filtrar ruído para descartar direções inteiras; - 0.2 mantém o swap como filtro de ruído. Os limiares do meta-juiz (`swap_rate_min`, em `meta_judge.py`) DEVEM ser recalibrados medindo o baseline real do painel antes de fixar qualquer número — não use o 50% do design original sem medir. ## Entrada - `alvo` — URL ou rota da página. - `direção` — critério estético livre ("mais premium", "menos cara de IA"); OBRIGATÓRIO perguntar se faltar. Vira o brief do builder + as personas. - `duração_do_loop`, `iterações máx.` (cap 20), `objetivo` (opcional). ## Pré-flight (ordem fixa) 1. `git rev-parse --show-toplevel`; branch dedicada `aesthetic/<slug>` + commit baseline (`BASELINE_SHA`). `ORIGINAL_BRANCH`/`ORIGINAL_SHA` gravados. 2. **Censo de estados (não lista manual)**: `python3 tools/state_census.py` faz crawl dirigido (clica tudo clicável, força estado vazio, viewport estreito) e fotografa o conjunto de estados → congela em `states/` por run. Acima de 6 estados, use os pesos por estado de `judge/panel.yaml`. 3. **Invariância de fixture**: hash do HTML renderizado do champion (`python3 tools/fixture_hash.py`) capturado no pré-flight e re-checado toda rodada; mudou → run inválida, não "continua e torce". 4. Servir o preview (dev server do projeto; senão `npx serve`). 5. Smoke test de screenshots **e de comparabilidade**: mesmo viewport, `prefers-reduced-motion: reduce`, `Date.now` congelado, scroll 0, animações desativadas. **Canário**: renderize o champion 2× sob essas condições — hash diferente → a página não é elegível para modo automático. 6. Verificar fontes do ambiente de render: `tools/doctor.sh` roda `fc-list`; fonte do projeto ausente → ABORTO (fonte faltando muda a tipografia que o juiz julga). 7. `aesthetic-results.md` (APPEND-only) + `aesthetic-calibration.md` criados. ## Gates determinísticos (o chão — imutáveis durante o loop) `bash gates/run_gates.sh <champion_url> <challenger_url>` — ordem do mais barato ao mais caro, short-circuit na primeira falha: | Ordem | Gate | Ferramenta | Falha se | |---|---|---|---| | 1 | Build/compile | toolchain do projeto | exit ≠ 0 | | 2 | Acessibilidade | axe-core via Playwright (`gates/gate_axe.mjs`) | violação serious/critical nova vs. champion | | 3 | Contraste | WCAG AA via axe color-contrast (`gates/gate_contrast.sh`) | novo par texto/fundo < 4.5:1 | | — | Invariância DOM | `tools/dom_invariance.py` | conjunto de elementos interativos/overflow mudou sem justificativa | **O slop-score NÃO é gate.** É SINAL: `python3 tools/slop_signal.py` imprime um número (0–100) que entra no log e na rubrica do prompt do juiz. Motivo (patch B2): um detector de tells hardcodado é trivialmente gameable pelo builder (aprende a evitar `#F4F1EA` mantendo a estética idêntica) e pune escolhas humanas legítimas; promovê-lo a filtro principal é Goodhart embutido — e "ninguém vigia os gates". Os tells anti-slop vivem como **rubrica negativa** em `judge/prompt_pairwise.md` (custo zero, não-gameable por gate). Se um dia o slop virar gate: meça antes o ruído (mesmo champion renderizado 5×) e fixe δ = 2–3× o ruído observado — nunca um número escolhido. Falhou qualquer gate → revert imediato (sem LLM), `PLATÔ++`, log. Falha de INFRA (Chromium OOM, timeout de render, rate limit da API) → retry com backoff, até 3×, e NÃO conta para `FALHAS→FIM`; só falha de produto conta. ## Rodada (repita) 1. `elapsed ≥ duração_do_loop` → FIM. 2. Integridade dos gates (dupla checagem): `git diff --quiet $BASELINE_SHA -- gates/ tools/ judge/` E `git status --porcelain` desses dirs limpos. Violação → ABORTO. 3. **Direção ainda não tentada**: pegue do deck (`directions/deck.yaml`) a próxima direção estética não queimada; logue a queima. Dedup: hash normalizado do diff — variação repetida nem chega ao juiz (custa só builder). Deck esgotado → PLATÔ. 4. Builder novo (subagente descartável): screenshot do champion + brief de UMA mudança (1 arquivo / ~30 linhas) + a direção do deck. Ele NÃO vê vereditos anteriores. 5. Screenshot do challenger — mesmos breakpoints, viewport, seed e condições do champion (senão o pairwise é inválido). 6. Hash do fixture/champion re-checado (`tools/fixture_hash.py`); mudou → run inválida. 7. Gates determinísticos; falha → revert imediato, `PLATÔ++`, log. 8. **Painel pairwise cego AB+BA** (`judge/run_pair.py`): screenshots apenas, sem código, sem diff, sem nome de modelo, ordem aleatorizada por seed logada. Cada juiz × persona julga nas duas ordens; veredito só vale se sobreviver ao swap. Família do builder REMOVIDA do painel da rodada (firewall — impossível em single-family, ver modo degradado acima). Empate ("sem diferença perceptível" é opção explícita) → revert: o challenger precisa vencer, não empatar (maioria ≥ 2/3 do painel). Com painel mínimo de 2 famílias: 2 "indecisos" seguidos na mesma direção → pausa + voto humano (desempate N2, não espera o swap-rate janelado). 9. Keep: commit só dos paths tocados, champion avança (`aesthetic/<slug>`). Revert: fiel e auditado (`git restore --source=HEAD --staged --worktree`, `git status` limpo após cada revert). 10. Meta-juiz a cada 5 rodadas (3 em single-family) — `judge/meta_judge.py`: swap-rate da janela e κ do painel; fora da faixa calibrada → PAUSE_HUMAN (1 voto humano exigido) ou DEMOTE:<juiz> (peso zerado na maioria). 11. Contadores: PLATÔ (5 → FIM), FALHAS de produto (3 → FIM; falha de infra com retry NÃO conta). ## FIM 1. Checkout da branch original (fiel ao karpathy-loop; stash/backup reportados). 2. Relatório: rodadas executadas + motivo do FIM; keeps com hashes; **keeps/rodada** (métrica obrigatória — abaixo de 0.1 em validação interna, o posicionamento público muda); par de screenshots antes/depois do champion final; swap-rate/κ finais; custo em tokens e US$ da run. 3. Em single-family: recomendar explicitamente voto humano em lote sobre o diff acumulado antes de merge. 4. Opção: merge manual ou `git branch -D aesthetic/<slug>` — só com aprovação explícita do usuário. ## Validação (B3) — leia ANTES de confiar no painel `benchmark/PROTOCOL.md` é PRÉ-REGISTRADO: prompt, modelos com pin exato, temperatura, personas, split 70/30, orçamento de 2 iterações de protocolo, regra de pivô e fórmula de IC foram fixados antes do primeiro run. Não há dados de resultado neste repo ainda — o critério de vida do projeto (≥65% multi-família no WiserUI-Bench, IC distinguishable de acaso) está definido lá, junto com o pivô honesto ("aesthetic-loop assistido") caso fique abaixo. ## Doctor `bash tools/doctor.sh` valida, nesta ordem: git disponível + repo limpo, Playwright/Chromium instalado, fontes via `fc-list`, invariância de hash (render 2× do mesmo estado), e throughput real da API do painel (1 chamada por família configurada). Falhou um passo → o README documenta qual custo de setup por projeto aquele passo representa (seção "quanto setup o SEU projeto precisa").
View on GitHub