---
fonte: 01-canonicos/seed-componentes.md
versao_da_fonte: v1.43
secao: 62
titulo: "Seletor de pessoa — **`estável`** (F7.5 · promovida em 2026-08-17 por gate **declarado**, verbatim *'aprovo. siga'* · **GATE OBSERVADO em 2026-08-17: a PS-P4 FECHA — insumo nomeado, ver §64.10.1**) · PS1–PS16 · fecha C4 · C5 e C8 com bloqueio nomeado (PS-P2, que segue ABERTA) · bancada `banco-pessoa.html` **v0.1** *(errata corrigida: este cabeçalho declarava v0.2, versão que nem o artefato, nem o gerador, nem o MANIFESTO, nem o mapa de cobertura têm — §64.10.3)* · `suite-pessoa.mjs` **44 · 0 · 1 [n/a]** · **BT7 consertado em 2026-08-17**"
sequencia: 68 de 98
bytes_do_corpo: 17278
md5_do_corpo: 25ea53b36977b357c644ed77bdd387de
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
---
## 62. Seletor de pessoa — **`estável`** (F7.5 · promovida em 2026-08-17 por gate **declarado**, verbatim *"aprovo. siga"* · **GATE OBSERVADO em 2026-08-17: a PS-P4 FECHA — insumo nomeado, ver §64.10.1**) · PS1–PS16 · fecha C4 · C5 e C8 com bloqueio nomeado (PS-P2, que segue ABERTA) · bancada `banco-pessoa.html` **v0.1** *(errata corrigida: este cabeçalho declarava v0.2, versão que nem o artefato, nem o gerador, nem o MANIFESTO, nem o mapa de cobertura têm — §64.10.3)* · `suite-pessoa.mjs` **44 · 0 · 1 [n/a]** · **BT7 consertado em 2026-08-17**

> **Rodada zero: NÃO VISITADO.** O §13 tinha lido o avatar *renderizado* (C85) e o cartão de pessoa
> (C115), mas **nenhum seletor** tinha sido aberto. Navegação autorizada, modo somente leitura:
> menus abertos, lidos e fechados; **nenhuma atribuição feita**. Seis dispositivos, **C125–C130**,
> no §16 do `estudo-clickup-completo.md`. **LGPD:** a lista traz nomes reais de colaboradores;
> nenhum foi transcrito.
>
> **E o achado principal é o mesmo da volta anterior, noutro componente.** Na árvore de
> acessibilidade, cada pessoa da lista é `generic` — **sem `role="listbox"`, sem `role="option"`,
> sem `aria-selected`** em quem já está escolhido —, e o campo de busca é um `textbox` simples,
> **sem `role="combobox"`, sem `aria-expanded`, sem `aria-controls`**. Na tela a lista é exemplar:
> agrupada, com avatares, com o escolhido destacado. Na árvore é um bloco de nomes soltos.
>
> **Dois de dois seletores auditados repetem o padrão** (C122 no calendário, C130 aqui). *A regra da
> quinta volta — onde o dispositivo é de ESCOLHA, leia a ÁRVORE junto com a TELA — deixou de ser
> precaução e virou expectativa.*
>
> **Base (3 rodadas, 2026-08-16).** **R1 · ARIA APG (combobox):** o campo é `role="combobox"` com
> `aria-controls` apontando o popup e `aria-expanded`; **o foco do DOM permanece no campo** e o foco
> da tecnologia assistiva anda por **`aria-activedescendant`**; a opção escolhida leva
> `aria-selected="true"`; teclado ↓/↑ para andar, `Esc` para fechar sem alterar, `Enter` para
> aceitar. Para grupos, o APG traz o exemplo de **listbox com opções agrupadas** —
> `role="group"` com nome próprio. **R2 · mercado:** o produto de referência agrupa em
> "Responsáveis" e "Pessoas", põe **"Eu"** no topo, e usa o mesmo campo para buscar **e convidar**.
> **R3 · normas:** SC 4.1.2 (nome, papel e valor) é o que o C130 viola; SC 2.4.3 (ordem de foco) é o
> que o `aria-activedescendant` preserva.

### 62.1 A régua: quem escolhe pessoa está escolhendo RESPONSABILIDADE

Um seletor de pessoa num ERP de engenharia não é um `select` bonito: **atribuir é transferir
responsabilidade técnica.** Isso muda três coisas em relação a um seletor genérico — quem pode
aparecer na lista, o que acontece quando a pessoa sai da empresa, e o fato de que a escolha
**precisa ser desfazível** e visível a quem audita.

### 62.2 Os contratos

| # | Contrato | O que ele descarta, e por quê |
|---|---|---|
| **PS1** | **O campo é `role="combobox"`** com `aria-expanded` e `aria-controls` apontando a lista | `textbox` solto ao lado de uma lista sem vínculo. É o **C130** medido: sem o vínculo, quem não vê não sabe que existe lista |
| **PS2** | **A lista é `listbox`; cada item é `option` com `aria-selected`** | Itens `generic`. Sem papel, o leitor de tela anuncia nomes soltos em vez de "lista de 8, 1 selecionada" |
| **PS3** | **O foco do DOM fica no campo; a AT anda por `aria-activedescendant`** | Mover o foco real para dentro da lista. Isso quebra a digitação contínua, que é o modo natural de filtrar |
| **PS4** | **Grupos são `role="group"` com nome próprio** ("Já atribuídos", "Equipe") | Cabeçalho só visual. O agrupamento é informação; sem papel ele é decoração |
| **PS5** | **Multi-select produz CHIPS removíveis** — herda SG9–SG13 do §60, inclusive o teto e o `"+N"` | Reinventar. A família de chips já é canon |
| **PS6** | **Teclado: ↓/↑ anda · `Enter` escolhe · `Esc` fecha SEM alterar · `Backspace` no campo vazio remove o último chip** | Fechar aplicando. `Esc` que confirma é a armadilha clássica de picker |
| **PS7** | **O avatar é `aria-hidden`; quem informa é o NOME** | Concatenar. Herda o **SG8** e o defeito real do `✋ Mover` |
| **PS8** | **Avatar sem foto cai para INICIAIS sobre fundo derivado do nome** — determinístico, nunca aleatório | Cor sorteada. A mesma pessoa mudaria de cor entre telas |
| **PS9** | **O indicador de presença, quando existe, tem rótulo textual** | Bolinha muda. Cor sozinha não diz "disponível" |
| **PS10** | **"Eu" aparece primeiro, e é rotulado como tal** | Só o nome próprio. **C127**: o atalho para si mesmo é o caso mais frequente |
| **PS11** | **Buscar e CONVIDAR são ações distintas**, ainda que no mesmo campo: convidar exige confirmação explícita | Convidar por Enter. **C126** mostra os dois no mesmo campo; num ERP, convidar cria acesso — não pode ser efeito colateral de digitar |
| **PS12** | **Pessoa INATIVA continua exibível onde já foi atribuída, marcada como inativa; e não é oferecida para novas atribuições** | Sumir com quem saiu. O histórico de quem assinou o quê é registro técnico — herda o VD16: ausência e vazio não são a mesma coisa |
| **PS13** | **A lista carrega em página, com estado de carregando declarado**; nunca corta em silêncio | Cortar em N sem dizer. Herda a regra do teto declarado (SG11) |
| **PS14** | **Vazio de busca diz o que fazer** ("Ninguém com esse nome. Digite um e-mail para convidar.") | "Nenhum resultado" |
| **PS15** | **Remover uma pessoa anuncia quem saiu e quantos restam** | Remoção silenciosa. Herda o **SG12** |
| **PS16** | **Alvo de 44px por linha da lista**, e a linha inteira é clicável | Alvo só no nome |

### 62.3 A fronteira, e os dois bloqueios nomeados

* **C5 · seletor de entidade colorida** (espaço/lista com glifo) — o seletor vive atrás da ação
  **mover**, que é escrita. A entidade *renderizada* foi vista; o **seletor** não. **Bloqueio
  nomeado: só se alcança escrevendo.**
* **C8 · campo de menção `@`** — abrir a lista de menção exige **digitar no compositor de
  comentário**, e o produto persiste rascunho. **Mesmo bloqueio.**

> *Achado negativo é achado.* Os dois não são "não deu tempo": são **inalcançáveis no modo
> autorizado**, e ficam assim registrados. Quando a spec deles for escrita, ou o modo muda, ou a
> base é canon + norma sem leitura — declarado, como o DH12.

**Também fora:** permissão (quem pode ser atribuído é regra de produto) · notificação ao atribuir ·
carga de trabalho (A15, bloqueado por ambiente desde a quarta volta).

### 62.4 Números — a MEDIR na bancada

Altura da linha · diâmetro do avatar e sua escala de tipo para as iniciais · alvo do X do chip
(herda os 44px do SG10) · contraste das iniciais sobre os fundos derivados, **em todos os fundos que
a derivação puder gerar** · altura máxima da lista antes de rolar. **Nenhuma medida é afirmada
aqui.**

### 62.5 Pendências — a lista de origem (2026-08-16, manhã)

| # | Pendência | Por que nasceu |
|---|---|---|
| **PS-P1** | **Bancada `banco-pessoa.html`**, com gerador, molde e suíte | Nível de prova ao escrever a spec: **nenhum** — não havia consumidor no acervo |
| **PS-P2** | **C5 e C8 sem leitura** | Bloqueio nomeado: só se alcançam escrevendo |
| **PS-P3** | **A derivação de cor das iniciais** | O contraste tem de passar em **todas** as cores que a função puder gerar, não numa amostra. É medição de classe, não de caso |

*O estado ATUAL de cada uma está em §62.7, abaixo — esta tabela fica como registro de origem.*

### 62.6 A bancada `banco-pessoa.html` — e a decisão que torna a PS-P3 DEMONSTRÁVEL

A bancada nasceu em 2026-08-16 com **44 PASS · 0 FAIL · 1 [n/a]** em `suite-pessoa.mjs`, cobrindo
PS1–PS16 mais sete guardas de **operabilidade** (PS-OP1…PS-OP7), duas de `forced-colors` e a guarda
transversal GI2/BT3 do §64.

> **Por que sete guardas de operabilidade, e não só as de estrutura.** Em 2026-08-16 a
> `banco-data.html` **v0.1** passou em **25 PASS · 0 FAIL** com o calendário **inoperante** — nenhuma
> data clicável. Quem reprovou foi o olho do Rafael, não o placar. Desde então, guarda de componente
> de escolha **clica, digita e tecla** antes de aprovar: aqui, ↓ move o cursor, o clique na
> extremidade da linha escolhe, `Esc` fecha, `Backspace` remove, o filtro filtra, o `"+N"` abre e a
> carga em página carrega.

#### A paleta das iniciais é FECHADA — e é isso que fecha a PS-P3

O **PS8** manda que o avatar sem foto caia para iniciais sobre fundo **derivado do nome**,
determinístico. A **PS-P3** exigia mais: *o contraste tem de passar em **todas** as cores que a
função puder gerar, não numa amostra.*

**Alternativa descartada — e é a que a maioria dos produtos usa:** hash do nome → **matiz livre**
(HSL). Ela gera uma classe **infinita** de cores. Contraste de classe infinita **não se mede**: se
torce para dar certo, e no dia em que um nome cair num amarelo claro com tinta clara ninguém vai
saber por quê.

**Decisão (2026-08-16):** o hash indexa um conjunto **FECHADO de oito pares** (fundo, tinta), com os
dois lados na mesma família da rampa. Duas consequências que se ganham juntas:

1. **A PS-P3 vira demonstrável por ENUMERAÇÃO** — oito pares se medem; classe infinita, não.
2. **O par não se rompe na inversão de tema** (contrato **BT3** do §64), porque fundo e tinta são do
   mesmo par fixo. É o caso que o **BT4** tolera de propósito — primitiva em superfície de
   identidade —, com o número **impresso** no placar em vez de tolerado em silêncio.

| Par | Fundo | Tinta | Contraste medido |
|---|---|---|---:|
| turquesa claro | `--seed-turquesa-100` | `--seed-turquesa-900` | **11,37** |
| turquesa médio | `--seed-turquesa-200` | `--seed-turquesa-900` | 9,35 |
| amarelo claro | `--seed-amarelo-100` | `--seed-amarelo-900` | **11,54** |
| amarelo médio | `--seed-amarelo-200` | `--seed-amarelo-900` | 9,73 |
| azul claro | `--seed-azul-100` | `--seed-azul-900` | 11,50 |
| azul médio | `--seed-azul-200` | `--seed-azul-900` | 9,38 |
| cinza claro | `--seed-cinza-100` | `--seed-cinza-900` | 11,49 |
| cinza médio | `--seed-cinza-200` | `--seed-cinza-900` | **9,33** (o pior) |

Piso do projeto para texto: **4,50**. Medido nos **dois temas** — os valores não mudam, e é essa
estabilidade que o BT4 exige que seja impressa.

> **Detalhe de implementação que é contrato, não gosto:** a derivação **não** pode usar o `hash()` do
> Python — ele é randomizado por processo (`PYTHONHASHSEED`), então a mesma pessoa mudaria de cor
> entre duas gerações do mesmo arquivo, que é exatamente o defeito que o PS8 proíbe. A derivação usa
> soma de códigos de ponto: estável, reproduzível em JS, e portanto igual no gerador e em produção.

#### O estado ABERTO é impresso EM FLUXO — e isso é decisão de bancada

A primeira versão da página imprimia os quatro seletores abertos com o popup em
`position:absolute` — que é o comportamento **real** do componente. Resultado observado no render:
cada popup cobriu o cartão vizinho e as duas seções seguintes, e a bancada ficou **ilegível
justamente nos estados que ela existe para mostrar**.

**Regra que fica:** bancada é catálogo de estados **lado a lado** (CP31); sobreposição é
comportamento de **tela**. Os estados impressos abertos vão em fluxo (`.sel--fluxo`), e a
sobreposição real continua exercida pelo **Estado 1**, que abre no clique.

#### Décimo quinto defeito de instrumento — coordenada de elemento recortado

A guarda **PS-OP2** (a linha inteira é clicável) pegava o retângulo da última opção e clicava em
`right − 6` **sem rolar antes**. A lista tem `max-height:264px; overflow:auto`, e a última opção
estava em `y=865`, fora da área visível do popup, que termina em `y=782`. **O clique caiu na página,
não no controle**, e a guarda reprovou um artefato correto com *"o alvo é só o texto"*.

> **Regra nova: coordenada de elemento recortado por contêiner rolável não é a coordenada do
> controle.** Rola-se primeiro, mede-se depois — e a guarda agora **verifica** que o ponto medido cai
> sobre a opção antes de emitir veredito.

### 62.7 Pendências — atualizadas em 2026-08-16

> **Aviso de supersede (2026-08-17):** a linha **PS-P4** desta tabela está **SUPERSEDIDA** pelo
> **§64.10.4** — ela FECHOU com o gate **observado** da `banco-pessoa` **v0.1**. A **PS-P2** segue
> ABERTA e não foi tocada. A tabela abaixo fica como histórico; o estado vigente é o do §64.10.4.

| # | Pendência | Estado |
|---|---|---|
| **PS-P1** | Bancada `banco-pessoa.html`, com gerador, molde e suíte | ✅ **FECHADA** — 44 · 0 · 1. Nível de prova: **2 (bancada)**. Continua sem consumidor em produção, e isso está dito: quem escreve o teste escreve o caso |
| **PS-P3** | A derivação de cor das iniciais | ✅ **FECHADA por DECISÃO + ENUMERAÇÃO** — paleta fechada de 8 pares, medida nos dois temas, pior par **9,33** contra piso 4,50 |
| **PS-P2** | **C5 e C8 sem leitura** | **ABERTA** — bloqueio nomeado: os dois só se alcançam **escrevendo** no produto de referência, e o modo autorizado é somente leitura |
| **PS-P4** | **Gate visual da `banco-pessoa.html` v0.1** | **NOVA, e ABERTA** — quatro camadas verdes não substituem o olho. Foi o gate que reprovou a `banco-data` v0.1 com 25 PASS |


---


### 62.8 PS-P5 — **REVOGADA PELA MEDIÇÃO**: o `.mini-avatar` não é avatar de pessoa

> **Escrito em 2026-08-19, ao executar a PS-P5.** Seção autossuficiente, e ela **supersede formalmente**
> a linha PS-P5 do §64.13.4 e do §69.6.

**O que a pendência mandava fazer.** A PS-P5 nasceu em 2026-08-17, da auditoria transversal do §69, com
este enunciado: *"o `.mini-avatar`, círculo de iniciais de PESSOA, pinta-se com a paleta de ENTIDADE,
quando o §62 fechou paleta própria de 8 pares"*. A decisão do Rafael foi migrá-lo para a paleta de
**PESSOA**, *"não a de entidade do CP23"*.

**O que a medição encontrou, em 2026-08-19, antes de tocar em qualquer coisa:**

| tela | quantos `.mini-avatar` | o que as iniciais são | o que a cor é | o que mais tem |
|---|---|---|---|---|
| `tela-lista` | **ZERO no DOM** | — | — | folha de estilo **sem consumidor**: `.pessoa`, `.mini-avatar` e cinco posições de cor, mantidas por cópia entre telas |
| `tela-tabela` | 6, na coluna **Cliente** | **MA** = Metalúrgica Andrade · **FB** = Fazenda Boa Vista · **HS** = Hospital Santa Rita | posição de **ENTIDADE** (1 a 5) | um **ponto de presença** (`disponivel` / `ocupado` / `ausente`) |
| `tela-referencia` | 5, na coluna **Cliente** | idem | idem | idem |

**Ou seja: ele NÃO é um avatar de pessoa.** Ele carrega o **CLIENTE**, que é uma ENTIDADE, com as
iniciais do cliente. A paleta que ele usa — a de entidade — é **a paleta certa** para o que ele
representa. *Migrar para a paleta de PESSOA seria pintar uma empresa com a cor de uma pessoa.*

> **A PS-P5, como escrita, está REVOGADA. Não se executa uma decisão cuja premissa a medição derrubou.**
> É o mesmo movimento de 2026-08-18, quando o RITO reprovou o conserto que a própria pendência CD-P9
> mandava aplicar. *O que a auditoria viu foi o NOME da classe — `pessoa`, `mini-avatar` —, e o nome
> mentia sobre o dado.*

**O que a medição achou de verdade, e vira pendência nova:**

| # | Pendência que nasce | O que está medido |
|---|---|---|
| **PS-P6** | **Um CLIENTE está desenhado com a anatomia de uma PESSOA.** Círculo de 26px com **INICIAIS** e **ponto de presença**, na coluna Cliente de duas telas `estáveis`. Três problemas, e os três são de **PRODUTO**: **(a)** o **SI1** do §65 descartou explicitamente *"inicial da palavra sobre cor"* como identidade de entidade — *"duas entidades com a mesma letra e cores próximas ficam idênticas, e a inicial não sobrevive a renome"* —, e é exatamente o que está em uso; **(b)** o **ponto de presença** é estado de PESSOA: uma empresa não fica "ocupada"; **(c)** o elemento inteiro é `aria-hidden`, então a presença é comunicada **só por cor** e **para ninguém** — ela não está escrita em lugar nenhum da linha. Vai a gate com recorte, **não se conserta por conta própria** |

**O que FOI feito, e é inerte:** o `tela-lista` teve o bloco `.pessoa` / `.mini-avatar` **removido** —
eram **zero** elementos no DOM, zero em `class="pessoa"` e zero menções em script. **Prova de inércia: 0
de 3.294.000 pixels em 4 comparações, duas execuções.**

> **Regra que fica: REGRA DE ESTILO SEM ELEMENTO É DRIFT ESPERANDO DATA.** Ela não pinta hoje e pintaria
> errado amanhã, e foi por cópia entre telas que ela chegou ali. *Foi essa mesma folha morta que fez a
> auditoria contar o `.mini-avatar` em três telas quando ele existe em duas.*

