Error Taxonomy (classes, severity, retryability)
errors specs/errors/taxonomy.kmd
Vocabulário canônico de erros da Koder Stack: o enum fechado de CLASSES (categorias funcionais — `DL`, `UP`, `AU`, `NW`, `DB`, `UI`, `IO`, `PM`, `VL`, `XX`), a definição semântica + regra de desempate de cada classe, a escala de SEVERIDADE (`fatal`/`error`/`warning`/`info`) e a classificação de RETRYABILITY. É a fonte de verdade dos campos `error_category` e `severity` que `specs/errors/reporting.kmd` (Group D) captura e que o Error ID de `specs/errors/user-facing-messages.kmd §4` encurta. Não define texto exibido (user-facing-messages), captura/telemetria (reporting), padrões de código (code/error-handling) nem o envelope de wire (model).
When this pattern applies
Primary triggers
- Classificar um erro (classe + severidade + retryability) em qualquer surface Koder
All triggers
- Atribuir uma classe/categoria a um erro novo (Error ID, Group D, envelope)
- Decidir a severidade de um erro ou se ele é retryable
- Adicionar uma nova condição de erro a um registry de produto
- Code review verificando se a classe/severidade do erro está correta
Specification body
Spec — Error Taxonomy
Define o vocabulário dos erros (classes, severidade, retryability). O shape máquina-legível é
specs/errors/model.kmd; o texto humano éspecs/errors/user-facing-messages.kmd; a captura/telemetria éspecs/errors/reporting.kmd; os padrões de código sãospecs/code/error-handling.kmd. Esta spec é a fonte única dos camposerror_categoryeseverityque aqueles documentos consomem.
Applicability
Toda superfície Koder que produz, classifica, transmite, exibe ou registra um erro — apps mobile/desktop/TV/web, CLIs, landing pages, serviços backend, e qualquer binding SDK. A classe e a severidade de um erro são as mesmas em todas as camadas: o backend que origina, o envelope que transporta, a telemetria que captura e a UI que exibe usam o mesmo valor.
R1 — Classe de erro (enum fechado)
Todo erro pertence a exatamente uma classe. O enum é fechado: um
produto nunca inventa uma categoria nova — ele cria novos CODE dentro
de uma categoria existente (ver user-facing-messages.kmd §4). Se nenhuma
classe encaixa, é XX (e provavelmente um gap desta spec — abrir ticket).
| Classe | Nome | Domínio (o que falhou) |
|---|---|---|
DL | Download | Obtenção de bytes de um recurso remoto para o dispositivo |
UP | Upload | Envio de bytes do dispositivo para um recurso remoto |
AU | Authentication | Identidade do chamador não pôde ser estabelecida/provada |
NW | Network | Transporte/conectividade (DNS, TLS, timeout, sem rota) |
DB | Database / storage | Camada de persistência remota (query, constraint, indisponível) |
UI | UI render | Renderização/layout/binding na camada de apresentação |
IO | Filesystem / local I/O | Sistema de arquivos local, dispositivo, periférico |
PM | Permission | Identidade conhecida mas não autorizada para a ação |
VL | Validation | Input não satisfaz uma regra (ver specs/data/validation.kmd) |
XX | Unknown | Não classificável; fallback exclusivo |
Os 2 caracteres são o componente CATEGORY do Error ID
(<PRODUCT>-<CATEGORY>-<CODE>-<SEQ>) e o valor de error_category no
envelope (model.kmd) e na telemetria (reporting.kmd Group D).
R2 — Definição semântica + regra de desempate
Pares de classes confundem-se na prática. A tabela abaixo é normativa para o desempate; havendo ambiguidade, vale a coluna "Decisão".
| Confusão | Classe A | Classe B | Decisão |
|---|---|---|---|
| Não logado vs sem permissão | AU (quem é você?) | PM (você não pode) | 401-equivalente → AU; 403-equivalente → PM. Identidade ausente/expirada = AU; identidade válida mas escopo insuficiente = PM |
| Falha de rede vs storage remoto | NW (transporte) | DB (a query/recurso) | Não chegou ao servidor (timeout, DNS, TLS, connection refused) = NW. Chegou e o backend de persistência falhou (5xx de query, constraint, lock) = DB |
| Download vs network | DL (semântica: obter recurso) | NW (mecânica: transporte) | Se o propósito da operação é baixar um recurso identificável, DL mesmo que a causa raiz seja de rede — a classe descreve a operação do usuário, a causa raiz vai em cause/http_status do envelope. NW é para falha de conectividade sem semântica de recurso (ex.: health-check, handshake) |
| Filesystem local vs storage remoto | IO (local) | DB (remoto) | Disco/arquivo/dispositivo na máquina = IO. Persistência atrás de uma API/rede = DB |
| Input inválido vs erro de UI | VL (dado não passa regra) | UI (render quebrou) | Valor que viola uma regra de campo = VL. Falha ao desenhar/compor a tela = UI |
Princípio: a classe descreve a operação que o usuário tentava
(intent), não necessariamente a camada técnica da causa raiz. A causa raiz
vive em cause/http_status/upstream_dependency do envelope (model.kmd).
R3 — Severidade (escala fechada)
Todo erro carrega uma severidade. Enum fechado, ordenado:
| Severity | Significado | is_fatal | Ação típica |
|---|---|---|---|
fatal | Estado irrecuperável; o fluxo (ou o processo) não pode continuar com segurança | true | Abortar boundary, crash report, exit code ≠ 0 |
error | A operação falhou mas o app/serviço segue vivo; o usuário pode tentar de novo ou outra ação | false | Exibir mensagem humanizada (user-facing-messages), permitir retry/abandono |
warning | A operação prosseguiu de forma degradada; resultado parcial ou fallback usado | false | Sinalizar de forma não-bloqueante; logar |
info | Evento notável que não é falha (ex.: cancelado pelo usuário, no-op esperado) | false | Geralmente não exibir como erro |
- O campo booleano
is_fataldereporting.kmdGroup D é derivado:is_fatal == (severity == "fatal"). Não há fonte independente. fatalmapeia aopanic/abortdecode/error-handling.kmd §R2(invariante violada / estado impossível). Erro recuperável de input, IO ou rede nunca éfatal— éerror(ouwarningse houve fallback).info/cancelamento:user-facing-messages.kmd §2já manda não exibir erro em cancelamento do usuário — esse caso éseverity: info.
R4 — Retryability
Ortogonal à severidade. Todo erro é classificável em retryability, e o valor
deve alinhar com a política operacional de code/error-handling.kmd §R9.
| Retryability | Quando | Exemplos de classe/código |
|---|---|---|
retryable | Repetir a mesma operação pode ter sucesso sem mudança de input | NW timeout, DB/DL/UP 5xx (idempotentes), 429 (respeitar Retry-After) |
not-retryable | Repetir sem mudança falha de novo | VL (input não-corrigível por retry), AU/PM (credencial/escopo não melhoram), 4xx exceto 408/429 |
conditional | Retry só após uma correção/ação (re-login, liberar espaço, corrigir campo) | AU expirado (após re-auth), IO sem espaço (após liberar), VL (após corrigir) |
O envelope (model.kmd) expõe retryable: bool (com conditional mapeado
a false + um recovery hint). Esta tabela é a regra de classificação;
o mecanismo de backoff/circuit-breaker é de error-handling.kmd §R9–R10.
R5 — Fingerprint (agrupamento)
O campo fingerprint de reporting.kmd Group D agrupa ocorrências do
"mesmo" erro para deduplicação e contagem agregada. Regra de composição
canônica:
fingerprint = hash(error_category + ":" + code + ":" + normalized_call_site)
normalized_call_site=file:symbol(sem número de linha — linha muda a cada edição e fragmentaria o agrupamento).- Não incluir valores variáveis (IDs, paths, timestamps) no fingerprint
— isso explodiria a cardinalidade (anti-padrão de
policies/observability-first.kmd). - Dois call sites com a mesma
category+codetêm fingerprints distintos (é o que oSEQdo Error ID também desambigua).
R6 — Extensão por produto
- Produtos adicionam
CODEs, nunca classes. OCODEé HTTP status (503,404) para erros HTTP, ou um numérico curto definido pelo produto (user-facing-messages.kmd §4). - Cada produto registra seus pares
(category, code) → condição, mensagem, call-site, severity, retryabilityem<product>/docs/technical/errors.md(o registry queuser-facing-messages.kmd §4e oerrors-catalog.mdgerado já consomem). - Severidade e retryability de um
(category, code)são propriedade do registry do produto, classificadas segundo R3/R4 desta spec.
R7 — Audit determinístico
errors-taxonomy-audit.sh (advisory), rodável por /k-housekeep:
- Todo
error_categoryemitido em código/registry pertence ao enum de R1 (qualquer outro valor → error). - Todo
severityemitido pertence ao enum de R3 (→ error). is_fatalsemseverity == "fatal"correspondente → warning (campo derivado fora de sincronia).- Registry de produto (
docs/technical/errors.md) com entrada semseverity/retryabilityclassificados → warning. fingerprintcontendo dígitos de linha ou IDs variáveis → warning (cardinalidade/fragmentação).
Cross-link
specs/errors/model.kmd— envelope máquina-legível que carregaerror_category/severity/retryabledefinidos aqui.specs/errors/user-facing-messages.kmd— Error ID (§4referencia o enum desta spec) + texto humano.specs/errors/reporting.kmd— Group D capturaerror_category,severity,is_fatal,fingerprint(definidos aqui).specs/code/error-handling.kmd—§R2(fatal↔panic),§R9(retry),§R10(circuit breaker).specs/data/validation.kmd— origem dos erros de classeVL.policies/observability-first.kmd— budget de cardinalidade (fingerprint, labels).
References
specs/errors/user-facing-messages.kmdspecs/errors/model.kmdspecs/errors/reporting.kmdspecs/code/error-handling.kmdspecs/errors/README.kmd