Componentes
60. Escolha segmentada e múltipla
seed-componentes.md v1.43 · §60seção 66 de 9860-escolha-segmentada-e-multipla-estavel-sg1-sg14.md · MD5 2d07c038Título completo no canon: Escolha segmentada e múltipla — estável, SG1–SG14 e SG6-b (F7.5, 2026-08-16) · validado pelo Rafael em 2026-08-16 na v0.3 · RE-GATE OBSERVADO em 2026-08-17 na v0.4: a BT-P1 FECHA — insumo nomeado, ver §64.10.1 · fecha C3 e C12 · bancada banco-escolha.html v0.4 · quatro camadas verdes: suite-escolha 238 · 0 · 29 [n/a] em cinco alvos · suite-painel 146 · 0 · contraste-painel 78 · 0 · suite-container 66 · 0 · SEM PENDÊNCIA ABERTA — dez fechadas em 2026-08-16
Rodada zero. Os dois itens TÊM leitura visual, e ela é recente: C114 (§14) — segmentação por estado como par de pílulas com contagem,
1 On-line · 7 Off-line, adjacentes, a ativa com fundo, não é filtro em barra, é recorte binário do mesmo conjunto · C63 — escopo como filtro na sidebar, com contagem · C74 — cada widget tem toolbar própria, com chips de filtro removíveis. Não é preciso navegar.E esta seção tem uma particularidade: ela chega DEPOIS dos consumidores. O §48 já usa segmentação para trocar de lente, o §56 usa um interruptor "só comentários", o §53 usa chips de filtro. Os três funcionam — e nenhum tinha spec. É o inverso do §54, que existiu como artefato sem seção; aqui a seção chega para nomear o que três artefatos já fazem, e a primeira coisa que ela faz é medir se eles fazem a mesma coisa.
Base (3 rodadas, 2026-08-16). E o achado da R1 é uma DIVERGÊNCIA DE CANON. Cinco fontes de peso dão quatro semânticas diferentes para o mesmo componente: (a) o Primer diz explicitamente para não tratar como
radiogroup— radiogroup requer um botão de salvar —, usa botões com Tab entre eles e setas que não movem foco; (b) o useUI mandarole="radiogroup"+role="radio"+aria-checked, com um único tab stop e setas movendo dentro — "o grupo é um radiogroup, não um tablist: não há painéis aqui, e prometer painéis enganaria a tecnologia assistiva"; (c) o Workday usa toggle button com estado pressionado; (d) o eBay usa botões comuns no tab order comaria-current, avisando que segmented buttons não são substitutos de abas e não operam como abas. O React Aria confirma a fronteira útil: se a escolha troca a vista do mesmo conteúdo, use grupo de alternância ou radiogroup; se troca o conteúdo, use abas.R3 normas: o estado selecionado precisa se distinguir por mais que cor — diferença de valor claro/escuro é o que sobrevive à deficiência de visão de cores.
60.1 A decisão que a divergência obriga: TRÊS SAÍDAS, com régua#
Não há "o jeito certo" no canon. Há três problemas diferentes que a mesma forma visual serve, e a semântica tem de seguir o problema, não a aparência.
| Se o controle… | Então é… | Semântica |
|---|---|---|
| troca a VISTA do mesmo conteúdo, com 2 a 5 opções mutuamente exclusivas, aplicando na hora | segmentado (SG1) | role="radiogroup" + role="radio" + aria-checked, um tab stop e setas dentro |
| liga e desliga um recorte do mesmo conjunto (binário) | interruptor de recorte (SG2) | um <button> com aria-pressed |
| troca o CONTEÚDO e tem painel associado | abas (§34) | tablist/tab/tabpanel — e não é este componente |
A régua em uma frase: pergunte o que muda. Muda a forma de ver o mesmo dado → segmentado. Muda quanto do mesmo dado aparece → interruptor. Muda o dado → abas.
Por que descartamos a saída do Primer (botões com Tab entre eles): num quadro com quatro lentes, quatro tab stops custam quatro pressionamentos para atravessar um controle só — e o próprio canon avisa que um controle de quatro opções não deve custar quatro pressionamentos para ser ultrapassado. Por que descartamos
aria-current(eBay): ele diz "este é o atual" sem dizer que os outros são escolhas;aria-checkednum radiogroup diz as duas coisas.O alerta do Primer, porém, entra como contrato (SG4): radiogroup em formulário sugere que a escolha só vale ao salvar. Aqui a escolha aplica na hora, e isso precisa estar dito no nome do grupo — não implícito.
60.2 Os contratos#
| # | Contrato | O que ele descarta, e por quê |
|---|---|---|
| SG1 | Segmentado é radiogroup com um único tab stop e setas movendo dentro (roving). <input type="radio"> nativo satisfaz o contrato e é a forma PREFERIDA quando cabe — o roving, as setas e o checked vêm de graça do HTML; role="radio" + aria-checked + roving em JS é a forma para quando o nativo não cabe |
Um tab stop por segmento. Quatro opções custariam quatro pressionamentos para atravessar |
| SG2 | Recorte binário é um <button> com aria-pressed, não um segmentado de duas opções |
Segmentar "com/sem". Ligar e desligar é um controle, não uma escolha entre dois |
| SG3 | Nunca tablist sem painel. Se não há painel, o papel promete o que não existe |
role="tablist" por parecer aba |
| SG4 | O nome do grupo diz o que a escolha faz ("Ver como", "Filtrar por") e que ela aplica na hora | Grupo sem nome. Sem ele, o leitor de tela anuncia as opções sem contexto — e o alerta do Primer sobre "salvar" fica de pé |
| SG5 | REVISTO 2026-08-16 · o teto é de APERTO MEDIDO, não de contagem. O segmentado cabe enquanto a fileira, em toda largura de uso, não vazar, não cortar e não reduzir nenhum alvo abaixo de 44px — quebrar em mais de uma linha é permitido quando as opções são de mesma natureza. Passado esse ponto, select. O grupo precisa oferecer Home e End, que é o que impede a fileira longa de custar N setas |
DESCARTADO: o teto fixo de 5. Ele foi violado pelo primeiro consumidor — as oito lentes do §48, estável e aprovadas em gate três dias antes de o contrato existir —, e mantê-lo exigiria converter pixel aprovado em select por uma regra que nasceu depois dele. Medido: 8 opções em 390/768/1180/1440px = 4/2/1/1 linhas, alvo mínimo 62×44px, sem vazar nem cortar |
| SG6 | REVISTO 2026-08-16 · o selecionado se distingue por diferença de VALOR MEDIDA ≥ 3,00 entre os dois fundos, não por matiz. O peso é reforço opcional | DESCARTADO: exigir mudança de font-weight. Ela altera a largura do texto e faz a fileira refluir a cada seleção — custo de layout real. Medido: 4,60 (lentes) e 4,57 (operador), ambos acima do piso 3,00 do SC 1.4.11 |
| SG6-b | NOVO 2026-08-16 · e ele é a razão de o SG6 não ter sido simplesmente relaxado. A separação tem de sobreviver a forced-colors: active, onde o agente de usuário SUBSTITUI background-color e border-color. O meio é cor de sistema — Highlight / HighlightText para o selecionado, ButtonFace / ButtonText para o repouso, com forced-color-adjust: none |
DESCARTADO: confiar no fundo da marca. Medido antes do conserto: a separação cai de 4,60 para 1,00 e o selecionado fica indistinguível do repouso. Depois: 19,04. O SG6 original estava certo pelo motivo errado — dizia "não só cor" pensando em daltonismo, e quem cobra a fatura é o alto contraste |
| SG7 | Contagem por segmento é opcional e, quando existe, conta o CONJUNTO — não muda com o filtro aplicado | Contador que acompanha o próprio recorte. Herda o CM11: número que muda ao filtrar deixa de ser referência |
| SG8 | Segmento com ícone e rótulo visível usa SÓ o rótulo no nome acessível; ícone sozinho exige nome próprio | Concatenar ícone e texto no nome |
| SG9 | Multi-select produz CHIPS REMOVÍVEIS, cada um com nome que diz o que remove | Lista de marcados escondida atrás do gatilho. O chip é o que torna o filtro visível — e removível de um clique |
| SG10 | O chip de filtro é do §22, com o X interno em alvo de 44px | Reinventar o chip |
| SG11 | Acima de um teto declarado, os chips colapsam em "+N", e o "+N" abre a lista completa | Vazar a linha. Herda o comportamento de excedente do §32 |
| SG12 | Remover um chip anuncia o que saiu e quantos restam em live region | Remoção silenciosa |
| SG13 | "Limpar tudo" existe quando há dois ou mais chips, e é a última ação da fileira | Limpar com um chip só: aí o próprio X já é o limpar |
| SG14 | Multi-select não fecha a lista ao escolher; escolha única fecha | Fechar a cada marcação. Quem escolhe vários teria de reabrir a cada item |
60.3 Os consumidores — AUDITADOS (SG-P1, fechada em 2026-08-16)#
Esta subseção nasceu, na v0.81, como uma lista de três consumidores a verificar. O que segue a
substitui: é o resultado medido. Instrumento: validacao/suite-escolha.mjs (nova nesta edição),
Chromium headless a 1440×900, sobre os quatro arquétipos que hoje têm controle de escolha.
Placar: 52 PASS · 22 FAIL · 21 [n/a]. Decomposição por arquivo em §60.5.
A auditoria achou seis controles em quatro arquivos — não três em três. E a tabela original
errava em dois pontos, corrigidos aqui: apontava o §53 para tela-tabela.html quando o
construtor FC1–FC6 vive em tela-lista.html, e não listava os dois controles do
tela-painel.html que não têm marcação de "atual" visível ao instrumento antigo.
| # | Controle | Arquivo | Seção · estado | Forma medida hoje | Veredito |
|---|---|---|---|---|---|
| 1 | Lentes (8) | tela-painel.html |
§48 · estável, gate 2026-08-13 |
role="group" + 8 <button> + aria-current="page" · 8 tab stops · 44,00px · raio 9999px |
DIVERGE do SG1 |
| 2 | Escala de tempo (4) | tela-painel.html |
§48 PN41 · estável |
role="group" + 4 <button aria-pressed>, exclusivos |
DIVERGE — 3ª forma |
| 3 | Gesto no vazio (2) | tela-painel.html |
§48 · estável |
2 <button aria-pressed>, exclusivos |
DIVERGE do SG2 |
| 4 | Operador do grupo / do subgrupo (2 cada) | tela-lista.html |
§53 FC3 · estável |
role="radiogroup" + <input type="radio"> nativos · 32,00px · raio 0px |
CONFORME ao SG1 |
| 5 | Chips de filtro (3) | tela-tabela.html |
§42/§53 · estável |
<span class="chip"> + <button class="x"> de 24×24px |
6 FAIL |
| 6 | "Só comentários" | tela-detalhe.html |
§56 · estável |
<button aria-pressed> |
CONFORME ao SG2 ✅ |
O achado central: o acervo já resolvia a mesma pergunta de TRÊS jeitos#
A divergência de canon que a R1 achou fora da casa — Primer × useUI × Workday × eBay, quatro semânticas para o mesmo componente — já estava reproduzida dentro da casa, e ninguém tinha medido. Para a mesma pergunta "escolha exclusiva que aplica na hora", o acervo responde:
tela-painel.html, lentes — fileira de<button>comaria-current="page". É a saída do eBay, e é exatamente a que o §60.1 descarta por escrito. Pior: o tokenpageé de navegação entre páginas; nem dentro do padrão eBay ele caberia aqui, onde nada navega. Custo medido: 8 tab stops para atravessar um controle só.tela-lista.html, operador —radiogroupcom rádios nativos. É a saída do useUI, e é a que o §60.1 escolheu. Um tab stop, setas movendo dentro, tudo de graça pelo HTML.tela-painel.html, escala de tempo e gesto no vazio — fileira dearia-pressedmutuamente exclusivos. Não é nenhuma das quatro saídas do canon: a exclusividade existe só no script. A tecnologia assistiva anuncia quatro interruptores independentes, não uma escolha entre quatro. É a forma mais silenciosa das três, porque cada botão isolado passa em qualquer guarda de ARIA.
É por isso que a SG-P1 vinha antes da SG-P2. A bancada
banco-escolha.htmlproduzida antes desta medição teria nascido como a quarta variação do mesmo controle, e o §60 teria documentado uma convergência que não existe. Spec que chega depois do uso começa por auditar o uso — a regra estava escrita; esta é a primeira vez que ela paga.
E a exclusividade precisa ser PROVADA, não inferida#
A guarda que acha o item 2 nasceu com falso positivo: "fileira de aria-pressed com exatamente
um ligado" também descreve uma barra de interruptores independentes em que só um está ligado por
acaso — foi o que a barra de controles do preview de tela-chat.html e tela-shell.html fez. Uma
guarda que acusa o inocente é pior que guarda nenhuma. A versão final prova por clique: liga
outra opção e mede se a primeira desligou sozinha. Com a prova, os dois falsos positivos caem e os
dois achados reais ficam de pé. Regra: exclusividade é comportamento, e comportamento se mede
agindo — nunca se lê da marcação.
60.4 Números — o que a SG-P1 já mediu, e o que segue a medir#
Método do §55: a spec nasceu só com relações; a auditoria trouxe os primeiros números. Estes são medidos, não escolhidos — são o retrato do acervo hoje, e a bancada da SG-P2 é que decide quais viram canon.
| Medida | tela-painel.html (lentes) |
tela-lista.html (operador) |
|---|---|---|
| Altura do segmento | 44,00px | 32,00px |
| Raio | 9999px (pílula) | 0px (reto) |
| Peso, repouso → selecionado | 600 → 600 (não muda) | 700 → 700 (não muda) |
| Fundo, repouso → selecionado | #ffffff → #098475 |
transparente → #098475 |
| Separação de VALOR entre os dois fundos | 4,60 | 4,57 |
| Texto sobre o selecionado | 4,60 (piso 4,50) | — |
Duas geometrias para a mesma família: pílula de 44px e retângulo de 32px. Nenhuma das duas é errada isoladamente; as duas juntas são a prova de que não havia canon. A escolha é da SG-P2.
Alvo do X, medido: 24×24px no chip (tela-tabela.html) e 32×32px na condição
(tela-lista.html). Piso do SG10: 44px. Detalhe do defeito em §60.6.
Seguem a medir na bancada: espessura e cor da fronteira do grupo · hover e foco · teto de chips
antes do "+N" · e todos os pares nos dois temas — nada acima foi medido no tema escuro.
60.5 Placar da SG-P1, por suíte#
Placar agregado sem decomposição não é auditável (regra da v8.7).
| Arquivo | PASS | FAIL | [n/a] |
O que os [n/a] querem dizer |
|---|---|---|---|---|
tela-painel.html |
16 | 9 | 5 | não tem chip removível — contrato declarado inaplicável, não pulado |
tela-lista.html |
20 | 7 | 3 | não tem fileira de chips |
tela-tabela.html |
8 | 6 | 4 | não tem controle segmentado |
tela-detalhe.html |
8 | 0 | 9 | só tem interruptor; único arquivo limpo |
| Agregado | 52 | 22 | 21 | + 15 medidas |
Rodam também, com zero achado, tela-quadro.html · tela-gantt.html · tela-chat.html ·
tela-shell.html · banco-dominio.html: achado negativo é achado — nenhum destes tem controle
de escolha, e isso agora está medido em vez de suposto.
60.6 Supersede formal — o que a auditoria muda, e o que ela cobra do gate#
(a) CORRIGIDO sem gate — fato, não decisão#
SUPERSEDE §60.3 (v0.81) → §60.3 (v0.82). A tabela de consumidores da v0.81 dizia
"Chips de filtro (§53, filtro composto) — tela-tabela.html". Está errado: o construtor
FC1–FC6 do §53 vive em tela-lista.html (fieldset + legend + radiogroup, FC3), e os chips
de tela-tabela.html são da toolbar do §42. A v0.81 também listava três consumidores; são
seis. Motivo do erro: a tabela foi escrita a partir da memória da seção, não de uma busca no
acervo. É a lição da v7.0 outra vez — reconstrução de memória é inferior ao arquivo real.
(b) DEFEITO MEDIDO, conserto pendente de autorização#
SG10 · o alvo de 44px do X do chip existe no código e não cobre o botão. tela-tabela.html
declara .chip .x::before { position:absolute; width:44px; height:44px } — a intenção certa. Mas
.chip .x é position:static: o absoluto ancora no primeiro ancestral posicionado, que é <html>.
O alvo de 44px está no canto da página. Alvo real do botão: 24×24px, contra piso 44px.
Conserto: uma declaração — .chip .x { position: relative }. O X da condição em tela-lista.html
mede 32×32px e não tem nem a tentativa.
Esta é a família de defeito mais cara do projeto: o que PARECE resolvido. Uma leitura do CSS vê "44px" e passa. Só a medição do retângulo real acusa. Regra nova: alvo estendido por pseudo-elemento absoluto só conta se o instrumento provar que o elemento-dono é posicionado. A guarda
SG10dasuite-escolha.mjsjá nomeia a âncora do::beforena mensagem de FAIL.
SG12 · a remoção anuncia o que saiu e não quantos restam. Medido:
"Filtro removido: Frente: Subestação MT." — sem o número. E a própria suíte tropeçou aqui:
a primeira versão lia a primeira live region do DOM e pegava o contador "Mostrando 12 de 148",
que é outro dispositivo (TD1). Veredito sobre o texto errado. A versão final lê a região que
mudou. Guarda que depende de qual elemento vem primeiro no DOM não é guarda, é sorte.
SG13 · "Limpar filtros" persiste com um chip só — medido descendo a fileira até 1.
SG11 · não há teto nem "+N" em nenhum dos dois arquivos: a fileira vaza.
(c) A PRÓPRIA SPEC ERRA — dois contratos que a medição derruba#
SG5 (teto de 5 opções) contra o §48 (oito lentes). O §48 é estável e passou pelo gate do
Rafael em 2026-08-13 com oito lentes. O SG5 foi escrito em 2026-08-16 sem olhar para ele. Não
é o artefato que está fora do contrato: é o contrato que nasceu sem consultar o consumidor.
O motivo do SG5 é "não espremer sete opções numa fileira apertada" — e o painel não espreme:
.lentes é flex-wrap: wrap, e o PN4 esconde a lente que o conjunto de dados não sustenta, de
modo que o número visível é menor que oito na maioria dos casos. A régua útil não é a contagem,
é o aperto. Proposta à decisão do gate, com a alternativa descartada nomeada:
SG5 revisto (proposta): o teto não é de contagem, é de aperto medido. Segmentado cabe enquanto a fileira couber em uma linha sem reduzir o alvo abaixo de 44px; passado isso,
select— ou quebra em duas linhas quando as opções são de mesma natureza e a quebra não muda o significado. Descartado: manter o teto fixo em 5, que exigiria converter as oito lentes emselecte desfazer pixel aprovado em gate por uma regra que nasceu depois dele.
SG6 ("fundo E peso") contra 2 de 2 dos segmentados. Nenhum dos dois muda o peso ao selecionar (600→600 e 700→700). O motivo do SG6 é "diferença de valor é o que sobrevive à deficiência de visão de cores e à escala de cinza" — e a medição diz que o fundo sozinho já entrega: 4,60 e 4,57 de separação de luminância, contra piso 3,00 do SC 1.4.11. Contrato violado por 100% dos seus consumidores é contrato mais estrito que o problema que ele resolve.
SG6 revisto (proposta): o selecionado se distingue por diferença de VALOR medida ≥ 3,00 entre os dois fundos — não por matiz. O peso é reforço opcional. Descartado: exigir a mudança de peso, porque
font-weightaltera a largura do texto e a fileira reflui a cada seleção — os segmentos mudariam de tamanho ao serem escolhidos, o que é custo de layout real em troca de um sinal que a medição mostra já existir.
(d) A DECISÃO DO GATE — tomada em 2026-08-16#
Os controles divergentes estão em seções estável, e convertê-los muda comportamento de teclado
aprovado (de 8 tab stops para 1) e marcação anunciada — a mesma forma do CP-P5, que só
andou com o "conserta" explícito. O Rafael autorizou: converter os três controles do §48
(SG-P4/SG-P5) e consertar os cinco defeitos dos removíveis (SG-P7). O SG-P6 ele delegou
("analise e tome a melhor decisão"), e o que segue registra a decisão tomada e por que ela é o
oposto da que eu tinha proposto.
(e) SG-P6 · A MEDIÇÃO DERRUBOU A PROPOSTA — e essa é a lição da edição#
Em §60.6(c) eu propus relaxar o SG6: o fundo sozinho media 4,60 e 4,57 de separação de
valor contra piso 3,00, logo o e PESO seria mais estrito que o problema. O argumento estava
correto dentro do modo que eu tinha medido. Antes de aplicar, medi os outros:
| Modo | Fundo, repouso → selecionado | Separação | Veredito |
|---|---|---|---|
| normal | #ffffff → #098475 |
4,60 | passa |
| escuro | #ffffff → #098475 |
4,60 | passa |
forced-colors: active |
#ffffff → #ffffff |
1,00 | o selecionado SOME |
Sob alto contraste do sistema o agente de usuário substitui background-color e
border-color. A distinção inteira do selecionado evaporava — nos três controles do painel e nos
dois operadores da lista. O SG6 estava certo pelo motivo errado: o texto dizia "não só cor"
pensando em deficiência de visão de cores e escala de cinza, e quem cobrava a fatura era um modo
que ninguém tinha medido.
Mas o remédio também não era o que o contrato dizia. font-weight sobreviveria ao modo, sim — só
que ao custo de a fileira refluir a cada seleção. O meio certo são as cores de sistema, que
são as únicas preservadas: Highlight / HighlightText é exatamente o par que o sistema reserva
para "isto está selecionado". Depois do conserto a separação mede 19,04.
Regra nova, e ela corrige uma que eu tinha acabado de escrever. Em §60.6(c) escrevi: "contrato violado por 100% dos seus consumidores é suspeito de ser mais estrito que o problema". Continua verdade — mas a suspeita não é veredito. Antes de relaxar, meça o modo em que o contrato ganha a vida. Um contrato pode estar certo pelo motivo errado, e relaxá-lo pelo motivo declarado destrói a proteção real. Irmã direta da regra da v9.8 — antes de declarar uma fronteira decorativa, meça se existe outro sinal — aplicada na direção oposta.
O SG5, esse sim, cedeu — e com número: as oito lentes cabem em 390, 768, 1180 e 1440px, em 4/2/1/1 linhas, alvo mínimo 62×44px, sem vazar e sem cortar. E a SG5 revista achou defeito que a antiga não alcançava: o segmento do operador do §53 media 62×32px, abaixo do piso de 44. A guarda SG10 não o via porque só cobria o X de chip e de condição. Contrato reescrito para medir o problema certo acha o que o contrato anterior não alcançava.
(f) DUAS GUARDAS APONTAVAM PARA O LADO ERRADO#
PN6-01 (suite-painel.mjs) AFIRMAVA o defeito. Ela dizia, e passava:
"a lente ativa usa aria-current". É por isso que cinco camadas de validação atravessaram o caso:
a guarda não estava cega — estava apontada para o lado errado. Superseded por seis guardas
(PN6-01a…PN6-01f) que testam o problema (radiogroup · role=radio · um tab stop · nenhum
aria-current sobrando · nome que diz "aplica na hora" · nenhuma LEITURA órfã de aria-current
no script) em vez da forma. Nasce também a PN6-03, do SG6-b.
E o instrumento novo errou duas vezes, das duas em família conhecida. A suite-escolha.mjs
casava as passadas extra (aperto por largura · forced-colors) com os grupos da passada principal
por posição no array — e consultas diferentes produzem ordens diferentes: o operador nativo do
§53 nem aparecia na segunda consulta, e o índice escorregou, atribuindo a um grupo a medida de
outro. E o detector do "+N" procurava [class*=mais-n], um nome que a guarda inventou e que não
batia com o chips-mais do artefato — guarda que procura um seletor que ninguém combinou
reprova o conserto correto. Consertos: casar por chave estável, e procurar o contrato
(aria-expanded na fileira) em vez do nome.
Regra nova: guarda que casa dois conjuntos por índice não é guarda, é coincidência. Irmã da regra da v9.4 (guarda que depende da ordem de execução das outras não é guarda, é sequência) e da v8.9 (o gate abriu o arquivo errado): as três são a mesma doença — veredito correto sobre o objeto errado.
(g) O QUE FOI EXECUTADO — e onde#
Tudo no molde e no gerador, nunca no HTML gerado: artefato editado à mão volta atrás no
próximo gen-*.
| Arquivo | O que mudou |
|---|---|
validacao/painel-template.html |
Os QUATRO grupos viram radiogroup; um helper de roving (marcar + rovingTeclado) substitui três mecanismos; @media (forced-colors: active); anel de foco do [role=radio]; lenteAtual() passa a ler aria-checked |
validacao/gen-painel.py |
Selo do preview v0.10 → v0.11 |
validacao/suite-painel.mjs |
PN6-01 superseded por 6 guardas · PN6-02/AC-01 com o seletor novo · PN6-03 (forced-colors) |
validacao/tela-tabela-template.html |
.chip .x{position:relative} + ::before centrado · "+N" com TETO_CHIPS declarado · anúncio com contagem · "Limpar" com piso de 2 |
validacao/tela-lista-template.html |
X da condição a 44px com dono posicionado · segmento do operador a 44px · @media (forced-colors) · anúncio com contagem |
validacao/gen-tela-lista.py |
Nome do radiogroup ganha "— aplica na hora" (SG4) · selo 0.1 → 0.2 |
validacao/gen-tela-tabela.py |
Selo 0.1 → 0.2 |
validacao/suite-escolha.mjs |
Guarda SG2/SG1 prova exclusividade por clique · SG5 e SG6 revistos · SG6-b · passadas extra por chave |
Cinco camadas, depois do conserto: suite-escolha 88 · 0 · 21 [n/a] (4 arquétipos) ·
suite-painel 146 · 0 · contraste-painel 78 · 0 · suite-container 66 · 0 (2 telas).
Falta o gate visual do Rafael — a única camada que mede se o controle é OPERÁVEL, e não só
conforme.
60.7 A promoção, e os TRÊS níveis de prova#
O gate visual do Rafael saiu em 2026-08-16 sobre os três previews: "verificado, tudo ok". Antes
de escrever estável, uma pergunta que o projeto ainda não tinha feito a si mesmo: quais destes
contratos têm PROVA, e quais têm só texto?
A resposta obrigou a distinguir três níveis de evidência, e a distinção fica registrada porque eles não valem o mesmo:
| Nível | O que significa | Contratos |
|---|---|---|
| 1 · Consumidor em produção | O contrato é exercido por artefato que já estava em uso, e a medição o confirmou. É o nível mais forte: ninguém construiu o caso para o contrato passar | SG1 · SG2 · SG4 · SG5 · SG6 · SG6-b · SG8 · SG9 · SG10 · SG11 · SG12 · SG13 |
| 2 · Bancada | O contrato é exercido por artefato que nós construímos para prová-lo. Vale — mas é mais fraco, porque quem escreve o teste e quem escreve o caso são o mesmo | SG7 · SG14 |
| 3 · Ausência de violação | O contrato é uma proibição, e a guarda informa que ninguém a viola | SG3 (zero tablist no acervo) |
Proibição sem instrumento é só uma frase. O SG3 existia desde a v0.81 e nada o media. Agora há guarda, e ela mede a cada rodada em vez de supor. Passar por ausência é veredito mais fraco que passar por instância, e a diferença fica dita.
O SG8 nunca tinha sido testado — e estava violado#
"Segmento com ícone e rótulo visível usa SÓ o rótulo no nome acessível." O contrato existia desde a
v0.81; nenhum consumidor parecia exercê-lo, então nenhuma guarda foi escrita. Ao escrever a guarda
para poder promover, ela achou o caso: o botão ✋ Mover do "Gesto no vazio" levava o glifo
num nó de texto, e o nome acessível saía "✋ Mover" — o leitor de tela anunciava "mão levantada
Mover". Conserto: <span aria-hidden="true">✋</span>.
Regra: contrato sem guarda é contrato sem prova — mesmo quando existe consumidor. A SG-P1 mediu se os consumidores concordavam entre si; não mediu se cada contrato tinha instrumento. São perguntas diferentes, e a segunda só foi feita na hora de promover. Auditoria de concordância não substitui auditoria de cobertura.
60.8 A bancada — e por que o escopo dela é estreito#
A banco-escolha.html nasce por último, e isso é decisão, não atraso. Quando o §60 foi escrito
(v0.81), quatro artefatos já usavam controles de escolha sem spec; a SG-P1 mandou auditar antes de
produzir, e a auditoria achou o acervo resolvendo a mesma pergunta de três jeitos
incompatíveis. Produzir a bancada primeiro teria criado a quarta variação, e o §60 teria
documentado uma convergência que não existia.
Com onze contratos já provados por consumidor real, o que sobrava para a bancada era estreito:
- Provar o SG7 e o SG14, os dois sem instância no acervo.
- Fechar a última divergência de geometria — o raio.
- Servir de referência única do mecanismo de roving (antes eram três mecanismos).
Placar: 137 PASS · 0 FAIL · 0 [n/a]. É o único artefato do acervo em que nenhum contrato sai
[n/a] — o que é o próprio critério de uma bancada estar completa.
SG-P9 · o raio, e por que ele vai a gate em vez de eu decidir#
A SG-P1 mediu duas geometrias para a mesma família. A altura convergiu em 44px (o §53 media 32 e subiu na SG-P7). O raio não: 9999px (pílula, §48) contra 6px no item e 8px no grupo (reto, §53).
A bancada põe os dois lado a lado, com o mesmo conteúdo, e acrescenta uma terceira fileira estreita de propósito — porque o SG5 revisto permite o segmentado quebrar em linhas, e é na quebra que os dois se comportam diferente: o arredondamento total do grupo tem de envolver duas linhas; o reto não tem esse problema.
Isto está na bancada para ser OLHADO, não afirmado. Eu poderia escrever "a pílula fica estranha quebrando" — seria opinião com cara de medição. Pôr as duas quebrando lado a lado é medição que o olho faz, e o olho é do Rafael. É o formato que ele mesmo pediu no §49: "me mostre visualmente a diferença, é mais fácil para eu decidir".
60.9 SG-P9 fechada — e o que a decisão descobriu#
Decisão do gate, 2026-08-16: "pilula contra reto, escolho reto". O segmento passa a 6px, o valor que já vinha do §53. A família de escolha do SEED fica com uma geometria: altura 44px (convergida na SG-P7) e raio 6px.
A regra escrita é específica — .lentes [role="radio"], .escala-ctrl [role="radio"],
.mapa-modos [role="radio"] —, e não uma troca no button genérico do preview.
O gate decidiu sobre o SEGMENTADO, não sobre todos os botões do painel. Trocar o raio genérico teria sido mais limpo de escrever e teria mudado dezenas de controles que ninguém avaliou. Alargar a decisão para além do que foi decidido é a forma silenciosa de decidir sozinho.
SG-P10 · aplicar o raio revelou o que o raio escondia#
Com o raio igualado, ficou visível que os dois não desenham a mesma coisa:
tela-painel.html (hoje) |
banco-escolha.html (bancada) |
|
|---|---|---|
| Fronteira | uma por segmento — oito bordas | uma por grupo — segmentos sem borda |
| Fundo do grupo | nenhum (fileira nua) | surface-subtle, com 3px de respiro |
| Espaçamento | gap: 6px entre botões soltos |
gap: 4px dentro de um contêiner |
| Leitura | oito botões que por acaso estão juntos | um controle com oito posições |
Altura igual, raio igual, anatomia diferente. É a mesma família de divergência que a SG-P1 achou e que esta seção inteira passou fechando — só que uma camada acima: não no valor, na estrutura.
Regra nova: divergência de VALOR esconde divergência de ESTRUTURA. Igualar o número não iguala a coisa. Quando dois artefatos convergem em todas as medidas e ainda parecem diferentes, o que resta é anatomia — e anatomia não aparece em placar de contraste, alvo ou raio, porque nenhuma guarda mede "isto lê como um controle ou como oito?".
A leitura de conjunto importa: um controle com oito posições e oito botões que por acaso estão
juntos dizem coisas diferentes ao olho, mesmo com a semântica de radiogroup correta nos dois.
Mas mudar a anatomia do §48 altera pixel aprovado em gate, e a decisão é dele.
60.10 SG-P10 fechada — a anatomia converge, e três defeitos aparecem no caminho#
Decisão do gate, 2026-08-16: B. O grupo carrega uma fronteira; os segmentos perdem a própria. O painel, a lista e a bancada passam a desenhar a mesma coisa:
| Antes | Agora (canon) | |
|---|---|---|
| Fronteira | uma por segmento (painel) · overflow:hidden com rótulos colados (lista) |
uma por grupo, nos três |
| Fundo do grupo | nenhum · nenhum | surface-subtle, 3px de respiro |
| Segmento | borda e fundo próprios | borda transparente, fundo transparente |
| Largura do grupo | flex — esticava até o fim da linha |
inline-flex — encolhe para o conteúdo |
O operador do §53 tinha uma TERCEIRA anatomia — contêiner com
overflow:hidden,gap:0e rótulos colados de borda a borda. Ele já tinha um contêiner, e por isso quase passou. Ter algum contêiner não é convergir; convergir é adotar A MESMA anatomia.
Por que inline-flex: com a fronteira do grupo visível, display:flex (nível de bloco) esticava
o contêiner até o fim da linha e deixava fundo vazio à direita do último segmento — a fronteira
passava a delimitar a linha, não o controle. Com flex-wrap, a largura disponível segue
sendo o limite, e a quebra medida na SG5 não muda.
Os três defeitos que apareceram ao aplicar — e todos foram pegos por guarda#
(1) AC-08 · token em vez de px. Eu digitei 8px e 6px, e existem
--seed-radius-md e --seed-radius-3 com esses valores. A guarda de higiene é de classe: não
interessa que o número esteja certo, interessa que o componente consuma a camada de token — senão a
escala muda e o segmentado não acompanha. Mesma família do GI2.
(2) Regressão de ESPECIFICIDADE, e ela é silenciosa. A regra nova
.lentes [role="radio"] { background: transparent } tem peso 0,2,0 — o mesmo de
[role="radio"][aria-checked="true"] { background: action-primary }. Empate resolve por ordem, e a
nova era posterior: o selecionado perdeu o fundo e ficou idêntico ao repouso. O placar acusou
separação de 1,00 contra piso 3,00.
Regra nova: regra escrita DEPOIS, com o MESMO peso, desfaz a anterior em silêncio. Não há erro de sintaxe, não há aviso, e a cor certa continua escrita no arquivo — só não vence. Só a medição do valor EFETIVO mostra; ler o CSS mostraria as duas regras, ambas corretas.
(3) Sexto defeito do instrumento: transparent lido como PRETO. Com o segmento em
background: transparent, o getComputedStyle().backgroundColor devolve rgba(0,0,0,0) — e a
leitura ingênua disso é preto. A guarda do SG6 passou a comparar #000000 com #000000 e reprovou
um artefato correto.
Regra nova: quando o contrato é sobre o valor PERCEBIDO, a guarda mede o valor EFETIVO. O que o usuário vê não é o fundo declarado: é o fundo composto com o que aparece por baixo. A guarda agora sobe pelos ancestrais compondo o alfa, que é o que o olho faz. Mesma família do
textContenttratado como nome acessível (v10.2) — ler o valor declarado quando o contrato é sobre o percebido é medir outra coisa com o nome certo.
60.11 Pendências#
Nenhuma. As dez pendências do §60 fecharam em 2026-08-16.
| # | Pendência | Como fechou |
|---|---|---|
| SG-P1 | Auditar os consumidores existentes | 6 controles em 4 arquivos; instrumento permanente |
| SG-P2 | Bancada banco-escolha.html |
137 · 0 · 0 — SG7 e SG14 provados |
| SG-P3 | Excedente em tela estreita | Respondida por medição: não há excedente |
| SG-P4 | Converter as lentes do §48 | 8 tab stops → 1 |
| SG-P5 | Escala, gesto e modo do mapa | um helper de roving para os quatro |
| SG-P6 | Revisar SG5 e SG6 | SG5 cede com número; SG6 não cede — vira SG6-b |
| SG-P7 | Alvos, anúncios, teto e piso | 24→44px · 32→44px · "+N" · contagem · piso de 2 |
| SG-P8 | Gate visual dos três previews | "verificado, tudo ok" |
| SG-P9 | Raio do segmentado | "escolho reto" — 6px |
| SG-P10 | Anatomia do grupo | "B com certeza" — fronteira por grupo |
Gate pendente: os previews mudaram depois do gate da SG-P8 —
tela-painelv0.14,tela-listav0.3,banco-escolhav0.2. As mudanças foram autorizadas (SG-P9 e SG-P10), mas autorização não é verificação: o olho ainda não viu o resultado montado. Fica como conferência de abertura da próxima sessão, não como pendência do §60.Atualização 2026-08-16: a
banco-escolhaestá hoje na v0.4 — barra de controles fixa (BT1), seletor de largura (BT2) e conserto da contagem no tema escuro, que media 1,00 e passou a medir 4,60 / 7,39. O re-gate destas versões é a BT-P1, no §64.6, para não haver duas listas disputando a mesma pendência.
| # | Pendência | Estado | Nota |
|---|---|---|---|
| SG-P1 | Auditar os consumidores existentes | ✅ FECHADA | 6 controles em 4 arquivos |
| SG-P2 | Bancada banco-escolha.html |
✅ FECHADA | 137 · 0 · 0 — SG7 e SG14 provados |
| SG-P3 | Excedente em tela estreita | ✅ RESPONDIDA por medição | Não há excedente: quebra em linhas mantendo 62×44px |
| SG-P4 | Converter as lentes do §48 | ✅ FECHADA | 8 tab stops → 1 |
| SG-P5 | Converter escala, gesto e modo do mapa | ✅ FECHADA | um helper de roving para os quatro |
| SG-P6 | Revisar SG5 e SG6 | ✅ FECHADA | SG5 cede com número; SG6 não cede — vira SG6-b |
| SG-P7 | Alvos, anúncios, teto e piso dos removíveis | ✅ FECHADA | 24→44px · 32→44px · "+N" · contagem · piso de 2 |
| SG-P8 | Gate visual dos três previews | ✅ FECHADA | "verificado, tudo ok" |
Gate pendente: os previews mudaram depois do gate da SG-P8 —
tela-painelv0.14,tela-listav0.3,banco-escolhav0.2. As mudanças foram autorizadas (SG-P9 e SG-P10), mas autorização não é verificação: o olho ainda não viu o resultado montado. Fica como conferência de abertura da próxima sessão, não como pendência do §60.Atualização 2026-08-16: a
banco-escolhaestá hoje na v0.4 — barra de controles fixa (BT1), seletor de largura (BT2) e conserto da contagem no tema escuro, que media 1,00 e passou a medir 4,60 / 7,39. O re-gate destas versões é a BT-P1, no §64.6, para não haver duas listas disputando a mesma pendência.
| # | Pendência | Estado | Nota |
|---|---|---|---|
| SG-P1 | Auditar os consumidores existentes | ✅ FECHADA | 6 controles em 4 arquivos |
| SG-P2 | Bancada banco-escolha.html |
✅ FECHADA | 137 · 0 · 0 — SG7 e SG14 provados |
| SG-P3 | Excedente em tela estreita | ✅ RESPONDIDA por medição | Não há excedente: quebra em linhas mantendo 62×44px |
| SG-P4 | Converter as lentes do §48 | ✅ FECHADA | 8 tab stops → 1 |
| SG-P5 | Converter escala, gesto e modo do mapa | ✅ FECHADA | um helper de roving para os quatro |
| SG-P6 | Revisar SG5 e SG6 | ✅ FECHADA | SG5 cede com número; SG6 não cede — vira SG6-b |
| SG-P7 | Alvos, anúncios, teto e piso dos removíveis | ✅ FECHADA | 24→44px · 32→44px · "+N" · contagem · piso de 2 |
| SG-P8 | Gate visual dos três previews | ✅ FECHADA | "verificado, tudo ok" |
| SG-P9 | RAIO do segmentado | ✅ FECHADA | "escolho reto" — 6px. A pílula fica na bancada marcada como superseded, porque decisão sem a evidência ao lado vira folclore em três meses |
| SG-P10 | ANATOMIA do grupo: fronteira por segmento ou fronteira por grupo | ABERTA — única do §60 | Descoberta ao aplicar a SG-P9: raio e altura iguais, estrutura diferente. O painel desenha oito botões com borda própria; a bancada desenha um contêiner com segmentos sem borda. Decisão de gate — altera pixel aprovado, e nenhuma guarda existente mede "isto lê como um controle ou como oito?" |
Também cita o §60: banco-edicao-linha, banco-identidade, banco-prioridade.