---
fonte: 01-canonicos/seed-dataviz.md
versao_da_fonte: v0.22
secao: 04b
titulo: "Sub-bloco DM — monitoramento (DM1–DM11, **`estável`** em 2026-08-11)"
sequencia: 7 de 12
bytes_do_corpo: 11670
md5_do_corpo: bc50e2c24f8bbc11682a80f2697c2d49
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-dataviz.md
---
## 4b. Sub-bloco DM — monitoramento (DM1–DM11, **`estável`** em 2026-08-11)

> **O que é o DM.** O sub-bloco dos objetos de MONITORAMENTO — os que respondem "como está
> AGORA?" em vez de "como se comparam?": o **medidor** (KPI contra meta e faixas), a
> **sparkline** (tendência em espaço mínimo, célula de tabela §40 do ERP) e o **gráfico do
> alerta de geração** (fecha o slot ET5 do `seed-email.md`). Consolidado aprovado pelo Rafael
> em 2026-08-10 após as 3 rodadas de pesquisa do método (R1 canon · R2 mercado/stack ·
> R3 normas — Stephen Few *Bullet Graph Design Specification*, Tufte *Beautiful Evidence*
> sobre sparklines, ARIA `meter` pattern, WAI-ARIA 1.2); preview iterado v0.1 → **v0.7** com
> gate visual completo (matriz cruzada) e fechamento "acredito que agora esteja tudo ok".
>
> **Artefatos:** `seed-dataviz-monitoramento-preview.html` **v0.7** (30.166 B, md5
> `f146c84a3d140a892d1de87ee37d334c`) — reanexado e conferido por MD5 em 2026-08-11, fechando a
> pendência P6; a **v0.8** corrige as erratas E1–E4 e E6 e **aguarda gate** · `validacao/gen-dm.py` (gerador dos fragmentos SVG do preview) ·
> `validacao/render-dm.mjs` (puppeteer, com a guarda de `getBBox`) ·
> `validacao/suite-dataviz-dm.mjs` **v2** — placar oficial contra o artefato do gate:
> **85 PASS · 0 FAIL · 6 FAIL DOCUMENTADO** (as erratas E1–E6 do §5).
>
> **Promovido a `estável` em 2026-08-11**, por "aprovo" explícito do Rafael sobre o lote de
> formalização. O que o "aprovo" cobre: a **spec** (DM1–DM11), os tokens v1.5 que ela consome e a
> suite. O que ele **não** cobre, e por isso permanece aberto no §5: as seis erratas medidas no
> artefato depois do gate. Nenhuma delas altera decisão — a spec é a fonte, o preview é a
> evidência dela, e onde os dois divergem quem manda é a spec.

**DM1 — o medidor canônico é o BULLET GRAPH; gauge circular é exceção declarada.** O medidor
SEED é horizontal, linear, compacto — o bullet graph de Stephen Few. O gauge circular
(velocímetro) só entra como exceção declarada: peça ÚNICA em tela de exibição (TV de sala de
monitoramento), nunca em lista ou comparação. *Racional:* comprimento sobre linha de base é a
codificação perceptual mais precisa (Cleveland–McGill); ângulo é das piores. E o caso real da
SEED é COMPARAR muitas usinas — bullets empilham em lista com rótulos alinhados; velocímetros
não. Um bullet ocupa ~1/8 da área do gauge circular equivalente. *Alternativa descartada:*
gauge circular como padrão (é o clichê de dashboard que o mercado abandonou; Few o desenhou
o bullet exatamente para substituí-lo).

**DM2 — anatomia do medidor: seis partes.** (a) rótulo da métrica; (b) unidade; (c) **barra
de valor** (a medida); (d) **marca de meta** — traço perpendicular de 1,5px (exceção
registrada da hierarquia de traço: precisa vencer visualmente a banda atrás); (e) **bandas de
faixa** ao fundo — máximo **3** (Few: mais de 3 faixas vira arco-íris); (f) eixo numérico com
os limiares rotulados. *Alternativa descartada:* bandas sem eixo numérico — a faixa sem
número obriga o leitor a adivinhar os limiares.

**DM3 — papéis invertidos: banda é intensidade de cinza; a BARRA carrega a severidade.**
Formalizado como supersede na §3c do `seed-tokens.md` v1.5 (os hex não mudam; muda quem os
consome). Bandas: `cinza-100/200/300` no light, **invertendo** para `cinza-800/700/600` no
dark (distâncias de claridade 9/10/19 e 9/8/17 pontos, medidas). Barra de valor: assume
`gauge-range-ok/warning/critical` conforme a faixa em que o valor cai. *Racional medido:* as
três faixas coloridas originais distavam **1 ponto** de claridade no light e **0** no dark —
diferiam quase só por matiz, ilegível para daltônico e em grayscale; Few manda codificar
faixa em INTENSIDADE. *Alternativas descartadas:* texturizar as 3 bandas coloridas (ruído em
objeto pequeno) · mudar os hex (supersede caro sem necessidade). *Geometria:* barra de valor
com **12px de altura sobre banda de 18px** — engrossada no gate (era 8px) para dominar
sobre a banda mesmo com textura DM11 ativa.

**DM4 — acesso do medidor: `role="meter"` com nome e valor em português.** O elemento do
medidor leva `role="meter"` + `aria-valuenow/min/max` + **`aria-valuetext`** com a leitura
humana ("PR 83,1% — dentro do esperado"). Rótulo e valor visíveis ficam **FORA** do elemento
com o role — descendentes de `meter` são apresentacionais para leitores de tela, texto dentro
dele desaparece. No produto React, via **`useMeter` do React Aria**. *Alternativas
descartadas:* `<meter>` nativo (VoiceOver o anuncia como barra de progresso — semântica
errada) · `role="progressbar"` (progresso implica conclusão; medidor mede estado).

**DM5 — sparkline: tendência, nunca valor.** Sem eixo, sem grade, sem legenda, sem rótulo
interno; **série única**; traço 2px (`cat-N-stroke`, hierarquia de traço); **marcador só no
ponto final** (o valor "agora"). A sparkline responde "subiu ou desceu?" — quem responde
"quanto?" é o número na célula vizinha. *Racional:* é a definição de Tufte (word-like
graphic); qualquer adorno a transforma num gráfico de linha ruim.

**DM6 — sparkline em tabela é decorativa POR CONTRATO.** Na célula de tendência da tabela
§40 do ERP: `aria-hidden="true"` na sparkline, e a célula vizinha **obrigatoriamente** carrega
valor atual + variação em texto. **Sem par numérico, a sparkline não entra.** *Racional:*
uma micro-linha por linha de tabela é inaudível por construção; fingir que ela é acessível
(title, aria-label por ponto) é pior que declará-la decorativa e garantir o dado em texto —
o mesmo raciocínio do fallback do DG1, aplicado ao micro-formato.

**DM7 — rótulo textual de estado SEMPRE visível.** Todo medidor exibe a palavra do estado
("dentro do esperado" · "atenção" · "crítico") na coluna à direita, na cor
`gauge-range-*` correspondente + texto. Cor nunca é o único portador (1.4.1); em grayscale
e no impresso, a palavra é o que sobrevive. Nasceu como defeito no gate (v0.4 do preview o
omitia) e virou regra com teste.

**DM8 — gráfico do alerta de geração (fecha o slot ET5 da F4).** Barra **agrupada**
esperado × medido (herda DG10 inteiro), renderizada a **PNG @2x, largura fixa 560px**,
hospedada no R2 (`/email/v1/`), com `alt` que declara o desvio em texto ("geração 18% abaixo
do esperado nos últimos 7 dias"). E-mail não roda SVG nem JS (leis do `seed-email.md`); o
PNG estático com alt textual é o único formato que sobrevive aos clientes. A emenda de
referência no `seed-email.md` dispara quando o PNG existir no R2.

> **SUPERSEDE do DM8 na v0.13 (2026-08-11) — o e-mail de alerta NÃO leva gráfico.** Decisão do
> Rafael no gate de produção do asset, e o racional dele derruba o desenho original: **um alerta
> não pode carregar dado que não é do destinatário.** O PNG hospedado no R2 é um arquivo único,
> servido a todos os disparos — logo, os números nele são ilustrativos. O cliente cujo desvio é
> de 6% receberia um e-mail com uma imagem mostrando 18%, contradizendo o texto ao lado. Quem vê
> isso não conclui "a imagem é genérica"; conclui que **o sistema erra** — e um alerta existe
> justamente para ser confiável.
>
> **Regra vigente:** o e-mail de alerta leva **símbolo de alerta**, não gráfico. O dado real vive
> no sistema, onde o cliente entra para ver o que está acontecendo. *O e-mail avisa; o sistema
> mostra.*
>
> **O slot ET5 sai do escopo da dataviz e volta para o `seed-email.md`, sem regra nova:** o
> **EC5** já determina que ícones raster são produzidos **sob demanda**, como par glifo×cor
> rasterizado do SVG normalizado quando um template o pede, em `/email/v1/icones/`. Um template
> de alerta pedindo glifo de alerta é exatamente o caso previsto. O DM8 tinha contornado essa
> lei ao especificar um PNG de conteúdo; a correção reconduz o slot à regra que já existia.
>
> *Alternativa descartada:* gráfico gerado por usina no envio, com renderização server-side. Não
> é rejeitada por mérito — é **fora do Design System**. O DM10 já pôs comportamento dependente de
> dado vivo no domínio do produto (Lovable/Supabase). Se um dia se decidir mandar gráfico real ou
> outra informação no e-mail, isso é programação de sistema, não spec de DS.
>
> *Consequência material:* o PNG `seed-email-et5-grafico@2x.png` (1120×520, 28.441 B) chegou a
> ser produzido e **foi descartado sem subir ao R2**. Fica registrado que existiu, para que
> ninguém o encontre num diretório de trabalho e o suba supondo que faltava propagar. O
> **DI19** — que decidiu o caminho `/email/v1/` para o asset do ET5 — **permanece válido quanto
> ao caminho** e muda de objeto: quando o glifo de alerta for rasterizado pelo EC5, vai para
> `/email/v1/icones/`.

**DM9 — estados herdam o DG6 com uma adição.** Skeleton/vazio/erro do medidor e da sparkline
seguem o DG6 (moldura real, Z1/Z2, alerta §15). Adição própria: **medidor sem leitura usa
`chart-no-data` hachurado na barra de valor** — "sem medição" NÃO desenha barra em zero, que
mentiria (zero é um valor legítimo de geração).

**DM10 — fronteiras do DM.** Atualização em tempo real/websocket = comportamento de
**produto** (Lovable/Supabase), não do DS · composição de painel/grid de medidores = **F6** ·
comportamento no impresso = **DI**. O DM entrega o objeto; quem orquestra é outro bloco.

**DM11 — textura nas bandas do medidor, no MESMO gatilho do DG13 (escuro + grayscale).**
Vocabulário próprio, por banda: **esperado = sólido · atenção = pontilhado · crítico =
quadriculado**; a diagonal 45° permanece exclusiva do no-data (lei da §3c). A legenda do
medidor repete a textura sob o mesmo gatilho. *Origem — gate visual de 2026-08-10:* com o
DM3 aplicado, as bandas cinza mediam 9/8/17 pontos de espalhamento — ACIMA do piso de 6 do
`contraste-dg.py` — e o Rafael ainda assim não as distinguia no escuro+grayscale. É o caso
que provou que **o piso não transfere de contexto** (emenda registrada no DG13): faixa fina
empilhada exige mais que barra alta adjacente. A textura entra como remédio no mesmo
gatilho conservador do DG13; no claro, o espalhamento medido basta.

### Registro de produção do DM (defeitos que viraram guarda)

Quatro defeitos de produção foram encontrados e corrigidos ANTES do gate final — três pela
suíte, um só pelo render real:

1. **Variáveis CSS órfãs** — o preview consumia `var(--seed-gauge-range-*)` sem declará-las
   no bloco de tokens embutido (herança silenciosa de um preview anterior). Guarda: teste de
   variáveis órfãs (toda `var()` consumida existe declarada) — permanente na suíte.
2. **DM7 não implementado** — a spec exigia o rótulo de estado e o preview v0.4 não o
   desenhava. Guarda: teste de presença do rótulo por medidor.
3. **Overflow silencioso de viewBox** — o rótulo "83,1%" estourava o viewBox em 9px e era
   CORTADO no render; **jsdom não detecta** (não faz layout), só `getBBox()` em navegador
   real vê. Guarda: o `render-dm.mjs` mede `getBBox()` de todo texto contra o viewBox —
   requisito permanente da camada de render do DM (mesma família do aprendizado
   puppeteer-vs-CLI do §5).
4. **Acentos perdidos** no HTML gerado pelo `gen-dm.py` (encoding). Guarda: verificação de
   round-trip UTF-8 no gerador.

**Exceção ao DG12 usada pelo DM:** registrada na emenda do próprio DG12 (§4.4) — a tinta da
marca de meta acompanha a superfície porque as bandas invertem com o tema (7,07 / 3,93
medidos).

