---
fonte: 01-canonicos/seed-componentes.md
versao_da_fonte: v1.43
secao: 66
titulo: "Credenciais — senha e código de uso único — **`estável`** (F7.5, 2026-08-16 · **promovido em 2026-08-17 pelo gate visual do Rafael — verbatim: 'aprovado'**) · CD1–CD16 · fecha **C13** e **C14** · bancada `banco-credencial.html` **v0.2** · `suite-credencial.mjs` **30 · 0 · 0**"
sequencia: 72 de 98
bytes_do_corpo: 19935
md5_do_corpo: e3789c03b2c36abd8c42915b25e20620
gerado_por: 06-validacao/geradores/gen-camada-ia.py
nota: fatia GERADA — o corpo abaixo é byte a byte o trecho do canônico; edite o canônico, nunca esta fatia. Canônico inteiro em https://ds.seed.eng.br/01-canonicos/seed-componentes.md
---
## 66. Credenciais — senha e código de uso único — **`estável`** (F7.5, 2026-08-16 · **promovido em 2026-08-17 pelo gate visual do Rafael — verbatim: "aprovado"**) · CD1–CD16 · fecha **C13** e **C14** · bancada `banco-credencial.html` **v0.2** · `suite-credencial.mjs` **30 · 0 · 0**

> **Por que os dois campos moram na MESMA seção — e o que foi descartado.** C13 (senha com
> revelar) e C14 (campo de código/OTP) chegaram na fila como duas lacunas. Viraram **uma** seção
> porque são governados pela **mesma norma** e falham pelo **mesmo mecanismo**: o **SC 3.3.8
> Accessible Authentication (Minimum)** da WCAG 2.2 proíbe *teste de função cognitiva* em qualquer
> etapa da autenticação — memorizar, transcrever, soletrar, calcular. Bloquear o colar, atrapalhar o
> gerenciador de senha e exigir transcrição são o mesmo defeito nos dois campos, e o conserto é o
> mesmo.
> **Descartado:** duas seções (§66 e §67). Separá-las duplicaria os contratos idênticos — colar,
> `autocomplete`, mensagem de erro — e cópia de contrato é a classe de problema que o
> `tokens_bloco.py` existe para impedir. *Se um dia um dos dois ganhar contrato que o outro não pode
> ter, a separação nasce por supersede formal, não por conveniência.*

### 66.0 Rodada zero — NÃO VISITADO, com o motivo dito

| O quê | Veredito | Motivo |
|---|---|---|
| Tela de autenticação do produto de referência (arquétipo **A19**) | **NÃO VISITADO** | Toda a leitura do `estudo-clickup-completo.md` foi feita **dentro de uma sessão logada**. Ver a tela de login exigiria **sair da sessão** da conta corporativa — risco operacional real, e a autorização de navegação é de **leitura**, não de mexer em estado de conta |
| Fluxo de recuperação com código | **NÃO VISITADO — e bloqueado** | Ele só existe depois de **disparar um e-mail de verdade**. Disparar é escrita, e escrita não está autorizada (mesma barreira nomeada da **PS-P2**) |

**E aqui a ausência de leitura visual custa pouco**, e é preciso dizer por quê para não parecer
conveniência: campo de credencial é o arquétipo do sistema em que a **norma é mais densa e mais
específica** — o SC 3.3.8 chega ao ponto de dizer que colar tem de funcionar. Onde a norma decide,
copiar o desenho do vizinho não acrescenta; **mede-se contra a norma**. É o oposto do §57 (quadro),
em que a norma diz pouco e a leitura visual decidiu quase tudo.

### 66.1 RITO — três rodadas encadeadas

| Rodada | Fonte | O que trouxe |
|---|---|---|
| **R1 — canon** | W3C, *Understanding SC 3.3.8 Accessible Authentication (Minimum)* | Define teste de função cognitiva como *"memorização, transcrição, uso de ortografia correta, cálculos ou resolução de puzzles"*. **Verbatim que decide o C14:** *"um serviço que requer transcrição manual de código de verificação não é compatível. Como com usuários e senhas, deve ser possível ao usuário pelo menos COLAR o código."* E: bloquear paste **ou** exigir *"o 1º, 3º e 5º caractere"* **falha** o critério. Gerenciador de senha e copiar-colar são listados como **mecanismos conformantes** |
| **R2 — mercado/stack** | GOV.UK Design System — *Password input* · Cloud Four — *Simple One-Time Passcode Inputs* | GOV.UK: o revelar é `button` com `aria-label` “Show password”/“Hide password”, anúncio *“Your password is visible/hidden”*, **`type` volta a `password` no envio** (senão o navegador guarda o valor como texto e o oferece em autofill de campo comum), `spellcheck="false"` contra *spell-jacking*, **sem `maxlength`**, e o achado de pesquisa: *“ter um segundo campo não ajuda os usuários”* — o campo “confirme a senha” **sai**. Cloud Four: OTP é **um** `<input>` com `inputmode="numeric"`, `autocomplete="one-time-code"`, `pattern` e `maxlength`; a aparência de caixinhas se faz com **tipografia** (mono + `letter-spacing`), não com seis elementos |
| **R3 — normas** | WCAG 2.2: SC 1.3.5 *Identify Input Purpose* · SC 1.4.11 *Non-text Contrast* · SC 2.2.1 *Timing Adjustable* · SC 4.1.3 *Status Messages* | `autocomplete` correto é o que permite o preenchimento automático (1.3.5) e o que torna o gerenciador um mecanismo (3.3.8). A **borda do campo** é elemento não-textual e cobra 3:1 (1.4.11) — foi por aí que apareceu o achado do 66.4. O **prazo do código** cai na exceção *Essential* do 2.2.1: estender invalidaria a atividade; o contrato então não é estender, é **declarar** o prazo e oferecer **reenvio** |

### 66.2 Os contratos CD1–CD16

| # | Contrato | Por quê | Descartado |
|---|---|---|---|
| **CD1** | **Colar nunca é bloqueado** — senha e código | SC 3.3.8 literal. E é o contrato que a suíte prova **usando a área de transferência de verdade** (Ctrl+V), não lendo atributo | “Bloquear paste por segurança”: empurra a pessoa para senha memorizável, que é **menos** segura |
| **CD2** | `autocomplete` correto e obrigatório: `username` · `current-password` · `new-password` · `one-time-code` | É o que faz o gerenciador de senha funcionar — e gerenciador é **mecanismo conformante** do 3.3.8, além do SC 1.3.5 | `autocomplete="off"` em campo de senha (prática comum, hostil, e ignorada pelos navegadores modernos) |
| **CD3** | Senha com `spellcheck="false"` e `autocapitalize="none"` | *Spell-jacking*: o corretor pode enviar o conteúdo do campo a um serviço remoto. E capitalizar a primeira letra corrompe a senha em teclado móvel | Deixar o padrão do navegador (o padrão não conhece o contexto) |
| **CD4** | Senha **sem `maxlength`**; o limite vira mensagem de erro | Truncar em silêncio faz a pessoa **guardar uma senha que ela não digitou** — e descobrir no próximo login | `maxlength` “para proteger o banco” (o hash tem tamanho fixo; o limite é do formulário, não do dado) |
| **CD5** | **Sem campo “confirme a senha”** | Achado de pesquisa do GOV.UK: *“um segundo campo não ajuda”*. Com revelar disponível, ele é digitação dobrada sem ganho | Confirmação obrigatória (convenção herdada de quando não existia revelar) |
| **CD6** | O revelar é `button type="button"`, com `aria-controls` e **nome que diz o efeito** | Dentro de um `<form>`, botão **sem `type` é SUBMIT** — um “mostrar senha” que envia o formulário é defeito que só aparece no primeiro uso real. E “olho” mudo não é nome | `checkbox` “mostrar senha” (o estado do controle não é o estado do campo); ícone sem nome acessível |
| **CD7** | A visibilidade é **anunciada**, não só refletida no botão | Quem não vê a tela precisa saber que a senha está **exposta em texto** — é informação de segurança física (alguém atrás), não de UI | Só trocar o rótulo do botão (não é anúncio; a AT não relê o botão sozinha) |
| **CD8** | **Ao enviar, o campo volta a `type="password"`** | GOV.UK, verbatim: senão o navegador memoriza o valor como texto digitado e passa a oferecê-lo em autofill de **campos não-senha** | Deixar revelado (vazamento silencioso, e a pessoa não fez nada errado) |
| **CD9** | A senha começa **oculta**; revelar é ação deliberada | Padrão seguro. O estado inicial não pode depender de quem não escolheu nada | Começar revelada “porque é mais fácil” |
| **CD10** | O código é **UM campo** — nunca N caixinhas | Com `maxlength="1"`, colar o código deixa **um dígito**. Isso é transcrição manual obrigatória: falha do 3.3.8. Some-se seis paradas de tabulação para um dado só e o autofill do sistema sem alvo | **Seis caixinhas** — o desenho mais comum do mercado. Está **impresso na bancada, operante e na sua MELHOR forma**, e a suíte mede os dois (ver 66.4-b) |
| **CD11** | No código, `inputmode="numeric"`, `pattern` e `maxlength` **são legítimos** | Aqui o comprimento é **do sistema** (o código tem 6 dígitos por definição), não da pessoa. **É o oposto do CD4, e o porquê está dito** — a mesma propriedade é certa num campo e errada no outro | Tratar os dois campos com a mesma regra “sem maxlength” (regra sem motivo vira dogma) |
| **CD12** | O prazo do código é **declarado em texto**, e existe **reenvio** | SC 2.2.1, exceção *Essential*: estender o prazo invalidaria a atividade. O que se pode fazer é **não esconder** e dar caminho de saída | Contador regressivo animado (pressão, e vira ruído em leitor de tela); prazo só no e-mail |
| **CD13** | Erro de credencial **não diz qual metade errou**; erro de **formato** diz | “Essa senha está errada” confirma que o usuário existe — enumeração de contas. Mas “o código tem 6 dígitos” não revela nada e evita uma tentativa perdida. **A fronteira é: formato ajuda, existência não** | Mensagem específica sempre (vaza); mensagem genérica sempre (esconde erro de digitação do próprio usuário) |
| **CD14** | Força da senha com **texto e forma**, e ela **não bloqueia o envio** | Barra colorida sozinha é o mesmo defeito das quatro bandeiras em quatro cores do §63 (C131): em cinza viram a mesma barra. Aqui a **quantidade de blocos preenchidos** é a forma | Bloquear envio por “senha fraca” (regra de política do produto, não do DS — e empurra para senha decorável) |
| **CD15** | Caps Lock ligado é **aviso anunciado**, não erro | Com a senha oculta a pessoa vê pontinhos idênticos e **não tem como saber** por que falhou | Detectar só depois do erro (tarde); nada (o padrão, e é o motivo de metade dos “esqueci a senha”) |
| **CD16** | **Nenhuma transcrição parcial** (“digite o 1º, 3º e 5º caractere”) | Falha citada **nominalmente** no *Understanding* do SC 3.3.8, e incompatível com gerenciador de senha | O padrão bancário brasileiro de “letras da senha” (é exatamente o caso que a norma proíbe) |

### 66.3 Os números medidos

| Medida | Claro | Escuro |
|---|---|---|
| Erro de credencial (texto sobre fundo de perigo) | **6,58** | 9,47 |
| Erro de formato | 6,58 | 9,47 |
| Aviso de Caps Lock | 9,05 | 9,27 |
| Confirmação do código | 5,89 | 9,35 |
| Dica do campo · rótulo da força | 7,75 | 8,11 |
| **Borda do campo** (não-textual, piso 3,00) | **3,38** | **4,50** |

**A prova do CD10, medida em casa e não citada:** colado **o mesmo** `482913` nos dois desenhos, com
clipboard real e `Ctrl+V` —

| Desenho | O que ficou |
|---|---|
| Campo único (canônico) | `482913` — **6 de 6 dígitos** |
| Seis caixinhas (contraexemplo) | `4` · vazio · vazio · vazio · vazio · vazio — **1 de 6** |

### 66.4 O achado da BORDA — e a decisão, tomada depois de ler o gêmeo inteiro

A guarda de contraste reprovou a borda do campo: `--seed-border-default` (`#C8D6DF`) sobre
`--seed-surface-raised` (`#FFFFFF`) mede **1,49** no claro e **2,32** no escuro. Quando o fundo do
campo é **igual** ao da superfície em volta — que é o caso —, a borda é o **único** indicador de onde
se pode clicar, e o SC 1.4.11 cobra 3:1.

**Medidos os quatro candidatos do gêmeo, nos dois temas, contra a superfície elevada:**

| Token | Claro | Escuro |
|---|---|---|
| `--seed-border-default` | 1,49 ✗ | 2,32 ✗ |
| `--seed-border-strong` | 2,53 ✗ | 4,50 ✓ |
| `--seed-border-focus` | 3,22 ✓ | 8,31 ✓ |
| **`--seed-border-interactive`** | **3,38 ✓** | **4,50 ✓** |

**E aí a leitura do gêmeo mudou a decisão que eu ia tomar.** A primeira conclusão desta rodada foi
*"o §13 declara `--seed-field-border` (`cinza-600`, 4,74:1) e esse token não existe no
`seed-tokens.css`; logo, promova-o ao gêmeo"*. Errado — e o próprio gêmeo diz por quê. O comentário
da **v1.12** do `seed-tokens.css`, escrito ao criar o `--seed-border-interactive`:

> *"fronteira de COMPONENTE INTERATIVO (SC 1.4.11, piso 3:1) — nenhum outro semântico de borda
> passava no claro (default 1.49, strong 2.53) … medido contra as seis superfícies
> 3.38/3.38/3.11/4.50/5.51/5.05, todos ≥3."*

**O sistema já tinha resolvido esta pergunta, com os mesmos números que eu remedi.** Promover o
`--seed-field-border` ao gêmeo criaria um **segundo semântico para a mesma coisa** — exatamente o
drift que o `tokens_bloco.py` existe para impedir.

**Decisão, com supersede formal:** o **`--seed-border-interactive` é o semântico canônico de
fronteira de controle** em todo o sistema. O `--seed-field-border` do §13 — declarado **localmente**
dentro da `banco-formfield.html`, nunca no gêmeo — fica **SUPERSEDIDO** por ele.

**E a decisão não é só de consistência: é melhor NOS DOIS TEMAS somados.**

| | Claro | Escuro |
|---|---|---|
| `--seed-field-border` (local, `cinza-600`) | 4,74 | **3,21** |
| `--seed-border-interactive` (gêmeo, `cinza-500`) | 3,38 | **4,50** |

O token local é melhor no claro e **pior no escuro**; o do gêmeo é **equilibrado e passa nos dois**.
*Um par que se degrada na inversão é o defeito BT3 do §64 — e o token local se degrada.*

**Nada muda no gêmeo `seed-tokens.css` nesta rodada.** §65, §66, §67 e §68 já consomem o
`--seed-border-interactive`. O que sobra é **migrar a `banco-formfield.html`** do token local para o
semântico do gêmeo — artefato `estável`, então entra por auditoria e não por edição solta
(**CD-P2**).

### 66.4-b O contraexemplo estava fraco — o gate consertou, e o argumento ficou mais forte

**Apontamento do Rafael, verbatim:** *"eu tentei colar e não consegui, quando digito o cursor pula
pro próximo campo, mas quando clico no backspace não consigo apagar cada campo, era pra ir voltando e
apagando."*

Ele está certo, e o erro era meu: a primeira versão das seis caixinhas **só avançava o foco**.
Qualquer implementação séria de OTP em caixinhas escreve pelo menos três remendos — avançar ao
digitar, **voltar apagando no Backspace** e navegar por setas. Comparar o campo único com uma versão
**capenga** das caixinhas é **espantalho**, e argumento apoiado em espantalho cai na primeira vez que
alguém implementa direito.

**Corrigido: o contraexemplo agora tem os três remendos.** E é aqui que o conserto **fortalece** a
tese em vez de enfraquecê-la — porque o argumento verdadeiro nunca foi *"caixinhas não funcionam"*, e
sim **quanto custa fazê-las funcionar**:

| | Campo único | Seis caixinhas |
|---|---|---|
| Avançar ao digitar | — (não se aplica) | remendo 1 |
| Voltar apagando | nativo | **remendo 2** |
| Navegar por setas | nativo | **remendo 3** |
| **Colar o código** | **nativo — 6 de 6 dígitos** | **remendo 4, que ninguém escreveu — 1 de 6** |
| Paradas de tabulação | 1 | 6 |
| Alvo do `autocomplete="one-time-code"` | 1 campo | nenhum |

> **Regra de método que sai daqui: contraexemplo tem de estar na MELHOR forma que o desenho
> concorrente consegue ter.** Contraexemplo enfraquecido mede a nossa implementação dele, não a
> decisão que ele representa — e o placar verde vira autoengano.

A guarda **`CD10-c`** passa a medir isso: ela exercita os três remendos no contraexemplo e reprova se
algum faltar. *E foi provada capaz de reprovar antes de ser aceita:* removidos os remendos, o placar
vai a **26 · 1**.

### 66.5 Dois defeitos de instrumento na mesma rodada

**Décimo sexto — o parser de cor não entendia HEXADECIMAL** (nasceu no §65 e vale para toda guarda
do projeto; o registro completo está em 65.4). Resumo: `getComputedStyle` devolve `rgb()`, mas o
**valor de um token** lido por `getPropertyValue` volta como está escrito no gêmeo (`#242E34`). O
regex de dígitos casava só o final e a razão saiu **232,67** — **fisicamente impossível** — com a
guarda emitindo **PASS**. Regra nova: **número fora da faixa [1,00 … 21,00] é MEDIDOR QUEBRADO, não
veredito.**

**Décimo sétimo — a guarda leu a DOCUMENTAÇÃO do contrato como se fosse o contrato violado.** A
primeira forma do CD16 varria o `innerText` do `<body>` inteiro procurando “1º, 3º e 5º caractere”.
Ela achou — **dentro da própria tabela de contratos da bancada**, onde o CD16 cita a frase proibida
entre aspas para explicar o que proíbe. O artefato foi reprovado por explicar a si mesmo.

> **Regra nova: guarda mede o CONTROLE, nunca o texto que descreve o controle.** O escopo passou a
> ser rótulos, legendas, dicas e `placeholder` dos campos. *Mesma família dos defeitos de recorte (8º
> e 14º): escopo errado inventa achado ou esconde achado — aqui, inventou.*
>
> **E a guarda foi provada capaz de reprovar** antes de ser aceita: injetada a frase proibida num
> rótulo real, o placar vai a **25 · 1**. Guarda que nunca falha não é guarda.

### 66.6 A bancada e a suíte

`banco-credencial.html` **v0.1**, gerada por `validacao/gen-banco-credencial.py` sobre
`validacao/banco-credencial-template.html`. Barra fixa e seletor de largura desde a v0.1 (BT1/BT2).
**Nada nesta bancada envia nada a lugar nenhum**, e o selo diz isso.

**`suite-credencial.mjs` — 27 PASS · 0 FAIL · 1 medida.** É a **primeira suíte do projeto que usa a
área de transferência**: o contexto do navegador é aberto com permissão de clipboard, o código é
escrito nele e colado com `Ctrl+V`. *Colar não se prova lendo atributo.*

| Guarda | O que ela faz de fato |
|---|---|
| `CD1-senha` / `CD1-codigo` | escreve no clipboard e **cola** nos dois campos |
| `CD10-b` | cola o **mesmo** código nos dois desenhos e compara: 6/6 contra 1/6 |
| `CD7` | **clica** no revelar e confere tipo, nome do botão e anúncio |
| `CD8` | **envia** o formulário e confere que o tipo voltou a `password` |
| `CD15` | dispara `keyup` **com `modifierCapsLock`** — e a guarda **declara** que o modificador é sintético, em vez de fingir que ligou a tecla |
| `CD12-OP` | **clica** em reenviar e confere que o campo limpou e o prazo foi anunciado |
| `CD13-OP` | digita código incompleto, **clica** em confirmar e confere erro, `aria-invalid` e foco |

### 66.7 Pendências

| # | Pendência | Por que fica aberta |
|---|---|---|
| **CD-P1** | ✅ **FECHADA — gate visual APROVADO em 2026-08-17.** O olho achou que o contraexemplo das seis caixinhas era **espantalho** (não voltava apagando no Backspace); corrigido para a melhor forma de mercado, com guarda `CD10-c`. A seção é promovida a `estável` |
| **CD-P2** | Migrar a `banco-formfield.html` do `--seed-field-border` **local** para o `--seed-border-interactive` do gêmeo | **Decidido em 2026-08-16 (66.4), com supersede formal:** o gêmeo já tem o semântico canônico de fronteira de controle desde a v1.12, criado com os mesmos números. O token local é melhor no claro (4,74 × 3,38) e **pior no escuro** (3,21 × 4,50). A migração é de artefato `estável`: entra por auditoria, junto com a **CD-P3** |
| **CD-P3** | Auditoria de **todos** os campos do sistema contra o piso 3,00 de borda | Esta rodada mediu `banco-formfield` (passa, 4,74/3,60) e os dois artefatos novos. As telas (`tela-detalhe`, `tela-lista`, `tela-painel`) não foram medidas nesta régua |
| **CD-P4** | ✅ **FECHADA em 2026-08-16, no gate.** Dado real num artefato `estável` | A `banco-formfield.html` trazia **dois** endereços de e-mail reais — linha **333** (estado `success`, campo `s4`) e linha **756** (campo `g3`). Os dois viraram `operador@exemplo.com.br`. *Achado colateral do gate:* a varredura foi feita porque o Rafael perguntou **onde** verificar — e a resposta honesta exigiu procurar, o que revelou a segunda ocorrência que o registro original não mencionava |
| **CD-P5** | O fluxo completo de autenticação (**arquétipo A19**) segue **AUSENTE** | O §66 entrega os **campos**; a **tela** de entrar/recuperar/criar conta não existe como `tela-*.html`. O mapa de cobertura registra A19 como arquétipo, e ele continua sem gabarito |



