Pular para o conteúdo

UI Quality Score (UQS)

design specs/design/ui-quality-score.kmd

Índice composto 0–100 da qualidade de UI de uma surface (tela/form/ícone/ layout/landing): 5 pilares (Efetividade/Eficiência/Satisfação/Visual/A11y) com pesos por profile, sinais AUTO determinísticos, gate duro de contraste e bandas Sauro–Lewis. Implementado no core puro `engines/sdk/koder_ui_score` + harness `tools/ui-score` (CLI `ui-score`, runner `run-headless.py`); rodável por `/k-ui-score <url>`. Este spec é a fonte normativa da lógica. Funda: stack-RFC-030.

Quando esta spec se aplica

Todos os triggers

Corpo da especificação

Regra: Cálculo do UI Quality Score (UQS) de uma surface Koder

Usar este spec sempre que for necessário medir, pontuar ou auditar a qualidade de UI de uma surface Koder (tela, formulário, ícone, layout, landing). O modelo é o implementado no core puro engines/sdk/koder_ui_score + harness tools/ui-score — este arquivo é a fonte normativa da lógica. É o irmão de medição do /k-arch (arquitetura) e do brand-score.kmd (nomes).

Visão geral

O UQS é um número 0–100 (maior = melhor) que compõe 5 pilares, cada um também 0–100 no mesmo sentido. Os três primeiros são os eixos de usabilidade da ISO 9241-11; os dois últimos são as dimensões AUTO-mensuráveis a partir de um render estático:

PilarMedeFonte
Efetividadeconclusão da tarefa, ausência de errotask-flow (JUDGE / não-estático)
Eficiênciaesforço/tempo (Fitts/Hick/KLM)task-flow (JUDGE / não-estático)
Satisfaçãopercepção, estética percebidasurvey (SURVEY / não-estático)
Visualestética computável (forma + disciplina + cor + clutter)AUTO (geometria + pixels)
A11yacessibilidade WCAG AUTOAUTO (DOM + pixels)

R1 — Composição. O UQS é a média ponderada dos pilares fornecidos sob os pesos do profile, renormalizada sobre os pilares presentes (scoring parcial): pilares não medidos numa surface estática — Efetividade/Eficiência/Satisfação — são simplesmente omitidos, não pontuam 0.

R2 — Cap de gate duro. Qualquer falha de gate duro (ver R6) capa o UQS em ≤ 59 (GateCap = 59.0), mesmo que a média ponderada seja maior. O gate nunca é "diluído" na média.

Pesos por profile (seed v1)

R3 — Pesos. Cada profile reponta os pilares; cada linha soma 1.0 (RFC-030 §5 / síntese §4):

profileEfet.Efic.Satisf.VisualA11y
screen0.250.220.180.170.18
form0.220.200.180.100.30
icon0.050.050.050.750.10
layout0.200.180.100.370.15
landing0.150.120.200.380.15

São seed v1 (síntese 07); calibração PCA contra surfaces reais é meta#387 slice 1 (baseline reprodutível já coletado em tools/ui-score/calibration/).

Pilar Visual — blend dos sinais (síntese §3.3)

R4 — Visual. O pilar Visual é o blend dos sinais computados, com os pesos renormalizados sobre os sinais medidos:

Visual = 100 · ( 0.45·NgoOM + 0.25·discipline + 0.15·(1−clutter) + 0.15·colorfulnessFit ) / Σ(pesos presentes)
  • NgoOM — roll-up Ngo, Teo & Byrne 2003 (12 das 13 medidas-componente; rhythm pendente). As medidas Ngo (balance/symmetry/proportion) operam sobre o canvas da composição = o bounding box do conteúdo, NÃO o viewport: surface rolável tem conteúdo além da dobra (o cockpit: linhas até y≈6900 num viewport de 757px), e medir peso contra o frame do viewport dá resultado sem sentido (CoM offset 763%, ngo deprimido). O harness usa max(viewport, bbox).
  • discipline — média de aderência grid-8pt / type-scale / vertical-rhythm.
  • clutter — edge-density (Sobel; Mack–Oliva). Entra como 1−clutter.
  • colorfulnessFit — Hasler–Süsstrunk M3 mapeado a um ótimo moderado (drab E caótico pontuam baixo).

Contraste NUNCA entra aqui — é gate de A11y, jamais média.

Pilar A11y — checagens AUTO + gate (compêndio ch.06 §7)

R5 — A11y = cobertura. O pilar A11y é a fração de elementos aplicáveis que passam somando todas as checagens AUTO (coverage %): contrast (#1), target-size (#6, exceção 2.5.8 inline-text), accessible-name (#2), form-label (#5), focus-visible (#9), page-language (#14), landmark-main + heading-order (#15, condicionais). Checagem sem elementos aplicáveis é excluída.

R6 — Gate duro de contraste (G-AA). Qualquer texto abaixo de WCAG 2.x AA4.5:1 normal, 3.0:1 large (≥24px ou ≥18.66px bold) — dispara o gate → UQS capado em ≤59 (R2). O gate é a única checagem dura no v1; as demais são dedução suave de cobertura. Tap-target mínimo = 24×24px (2.5.8), exceto links de texto inline.

Bandas de rating (Sauro–Lewis; ch.03 + ch.07 §6)

R7 — Bandas. 68 = âncora neutra SUS.

UQSBanda
≥ 90A+/A
≥ 80A-/B+
≥ 68B/C+
≥ 51C/D
< 51F

Como medir

R8 — Rodar o harness. Medir via /k-ui-score <url> (ou direto: run-headless.pyui-score). O render headless é trabalho pesado → off-laptop (heavy-work-isolation.kmd). Read-only: medir não muta o repo.

R9 — Pontuar AMBOS os temas, pegar o pior. A nota é tema-específica (o contraste muda por claro/escuro). Surfaces com tema claro/escuro DEVEM ser pontuadas nos dois temas (run-headless.py --theme light|dark); a nota da surface = a do pior tema (ambos são user-facing). Evidência: na calibração 2026-06-29 o pior tema variou por surface (flow-login pior no claro, www.koder.dev pior no escuro).

R10 — Surface atrás de auth / canvas. Surface atrás de auth (Koder ID OAuth) precisa de token de sessão injetado (owner-decision). App canvas/Flutter/Kroma (GPU) tem DOM vazio → só o pilar Visual (pixels: clutter + colorfulness) é medível (Mode:"pixel-only"); A11y/comportamentais ficam não-medidos (precisam da introspecção da plataforma — kroma#088).

Tier JUDGE/SURVEY — os 3 pilares comportamentais (RFC-030 §9 slice 3)

Os pilares Efetividade, Eficiência e Satisfação (ISO 9241-11) não saem de um snapshot estático. Dois caminhos:

R11 — Eficiência é AUTO (preditiva). Computável sem juiz, via KLM/Fitts (compêndio ch.05): EfficiencyScore = T_KLM(caminho_ótimo) / T_KLM(caminho_real) ∈ [0,1] — a UI é eficiente na medida em que mantém o usuário perto do caminho de esforço mínimo do objetivo (engines/sdk/koder_ui_score::EfficiencyPillar). O harness deriva os fluxos do descriptor para o perfil form (tools/ui-score deriveEfficiency): tarefa canônica = completar o formulário — caminho real = point-and-click Fitts por cada controle na ordem de leitura (distância/largura reais); caminho ótimo = o mínimo por teclado (Home + 1 Tab por controle). Como o ótimo é constante para uma contagem fixa de controles, a razão isola a qualidade do layout (tamanho/ proximidade dos alvos). É AUTO (não marca Mode:"full", que é do tier JUDGE) e entra no composto sempre que derivável; um fluxo gravado explícito (--judge com efficiency) tem precedência. Outros perfis não têm tarefa canônica → Eficiência fica ausente e o composto re-normaliza (R1/R13).

R12 — Efetividade e Satisfação são JUDGE (juízo-IA). Pontuadas por um AI-judge (/k-meta-judge), 0–100, contra a rubrica abaixo — não por fórmula. O juiz resolve surface→spec via registries/spec-triggers.kmd e pontua com evidência citada:

PilarO que o juiz avalia (grounded)Fonte
Efetividadea UI permite concluir a tarefa sem erro? prevenção de erro, mensagens úteis, recuperação/undo, estados vazios/carregando clarosNielsen H5/H9 (ch.02), ISO 9241-110 §6 (use error robustness), specs/errors/*
Satisfaçãoa UI é agradável e confiável de usar? estética percebida (aesthetic-usability), consistência, voz/tom, ausência de atritoTractinsky aesthetic-usability (ch.04 §5), Nielsen H4/H8, specs/themes/verge.kmd

R13 — Composição dos 5 pilares. Os scores JUDGE/SURVEY entram no composto via os pesos por profile (R3); o UQS re-normaliza sobre os pilares presentes (R1). O harness ingere os scores comportamentais (ui-score --judge judge.json{effectiveness, efficiency, satisfaction} 0–100) e compõe Mode:"full"; sem eles, Mode:"dom" (só os 2 AUTO, re-normalizado). Reportar quais pilares foram medidos — uma nota de 2 pilares e uma de 5 não são a mesma coisa.

R14 — Protocolo de juízo (produtor/consumidor, model-agnóstico). O harness não embute cliente de IA (acoplaria a um endpoint + credenciais + não-determinismo). Em vez disso emite um pedido de juízo autocontido e ingere a resposta:

  • Produtor: ui-score --emit-judge-request <desc.json> [shot.png]judge-request.json (schema uqs-judge-request/v1) com a rubrica R12 verbatim + resumo da surface (profile, frame, contagens, outline de headings, nomes interativos) + o response_schema exato. O screenshot acompanha para o eixo estético da Satisfação.
  • Juiz: qualquer AI-judge preenche — /k-meta-judge, Kortex, um cron, ou humano — pontuando 0–100 com evidência citada, resolvendo surface→spec via spec-triggers.kmd.
  • Consumidor: ui-score --judge judge.json ingere {effectiveness, satisfaction[, efficiency]} (campos de evidência extras são ignorados) → Mode:"full".

Mantém o harness determinístico/testável e o tier de IA plugável (headless-first, reuse-first).

Aplicação

  • Achou falha no gate (R6): consertar na camada certa — texto em token accent/muted que falha AA → trocar pelo role token --on-* do Verge (specs/themes/verge.kmd), não a cor crua (classe TRIAGE-027). Re-pontuar: o gate deve limpar.
  • Antes/depois de polish: pontuar nos dois estados; a nota deve subir (RFC-030 §9 slice 6).
  • Informative-first → CI-gate: o UQS é informativo agora; vira gate de CI por surface após soak (RFC-030 §11). Conserto de artefato = /k-go; conserto da regra = /k-meta-tune.

Referências