@luanpdd/kit-mcp 1.8.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +97 -1
  3. package/gates/golden-signals-coverage.md +133 -0
  4. package/gates/obs-agents-mcp-supabase.md +86 -0
  5. package/gates/obs-skills-frontmatter.md +76 -0
  6. package/gates/omm-no-regression.md +83 -0
  7. package/gates/postmortem-template-required.md +127 -0
  8. package/gates/prr-checklist-coverage.md +128 -0
  9. package/gates/skill-must-include.md +21 -19
  10. package/kit/agents/burn-rate-forecaster.md +160 -0
  11. package/kit/agents/golden-signals-instrumenter.md +241 -0
  12. package/kit/agents/incident-investigator.md +245 -0
  13. package/kit/agents/observability-instrumenter.md +200 -0
  14. package/kit/agents/omm-auditor.md +251 -0
  15. package/kit/agents/postmortem-writer.md +282 -0
  16. package/kit/agents/prr-conductor.md +288 -0
  17. package/kit/agents/slo-engineer.md +224 -0
  18. package/kit/agents/supabase-architect.md +62 -0
  19. package/kit/agents/supabase-auth-bootstrapper.md +17 -0
  20. package/kit/agents/supabase-edge-fn-writer.md +124 -0
  21. package/kit/agents/supabase-migration-writer.md +98 -0
  22. package/kit/agents/supabase-realtime-implementer.md +23 -0
  23. package/kit/agents/supabase-rls-writer.md +17 -0
  24. package/kit/agents/supabase-storage-implementer.md +174 -0
  25. package/kit/agents/toil-auditor.md +277 -0
  26. package/kit/commands/auditar-marco.md +102 -1
  27. package/kit/commands/auditar-observabilidade.md +103 -0
  28. package/kit/commands/auditar-toil.md +129 -0
  29. package/kit/commands/burn-rate-status.md +140 -0
  30. package/kit/commands/concluir-marco.md +73 -1
  31. package/kit/commands/definir-slo.md +108 -0
  32. package/kit/commands/discutir-fase.md +26 -0
  33. package/kit/commands/forense.md +83 -1
  34. package/kit/commands/golden-signals.md +142 -0
  35. package/kit/commands/instrumentar-fase.md +200 -0
  36. package/kit/commands/investigar-producao.md +162 -0
  37. package/kit/commands/observabilidade.md +116 -0
  38. package/kit/commands/planejar-fase.md +20 -0
  39. package/kit/commands/postmortem.md +179 -0
  40. package/kit/commands/prr.md +205 -0
  41. package/kit/commands/risk-budget.md +220 -0
  42. package/kit/commands/sre.md +227 -0
  43. package/kit/commands/verificar-trabalho.md +26 -0
  44. package/kit/skills/_shared-observability/glossary.md +396 -0
  45. package/kit/skills/_shared-sre/glossary.md +573 -0
  46. package/kit/skills/blameless-postmortems/SKILL.md +340 -0
  47. package/kit/skills/burn-rate-alerting/SKILL.md +258 -0
  48. package/kit/skills/core-analysis-loop/SKILL.md +352 -0
  49. package/kit/skills/distributed-tracing/SKILL.md +362 -0
  50. package/kit/skills/eliminating-toil/SKILL.md +243 -0
  51. package/kit/skills/event-based-slos/SKILL.md +296 -0
  52. package/kit/skills/four-golden-signals/SKILL.md +297 -0
  53. package/kit/skills/observability-driven-development/SKILL.md +315 -0
  54. package/kit/skills/observability-maturity-model/SKILL.md +222 -0
  55. package/kit/skills/opentelemetry-standard/SKILL.md +351 -0
  56. package/kit/skills/production-readiness-review/SKILL.md +305 -0
  57. package/kit/skills/sre-risk-management/SKILL.md +221 -0
  58. package/kit/skills/structured-events/SKILL.md +265 -0
  59. package/kit/skills/telemetry-pipelines/SKILL.md +259 -0
  60. package/kit/skills/telemetry-sampling/SKILL.md +256 -0
  61. package/package.json +1 -1
@@ -0,0 +1,221 @@
1
+ ---
2
+ name: sre-risk-management
3
+ description: Use ao escolher SLO target — risk continuum, error budget como balanço explícito risk × innovation, "as reliable as needs to be, no more", sabedoria 99.99%.
4
+ ---
5
+
6
+ # SRE — Risk Management
7
+
8
+ ## Quando usar
9
+
10
+ LLM carrega esta skill ao definir SLO target, debater "qual disponibilidade precisamos?", ou justificar trade-off entre velocidade de release e estabilidade. Trigger phrases:
11
+
12
+ - "SLO target", "qual disponibilidade?"
13
+ - "99.9% vs 99.99%", "quantos noves?"
14
+ - "error budget", "risk budget"
15
+ - "risk continuum"
16
+ - "as reliable as needs to be"
17
+ - "sabedoria 99.99%", "smartphone dilui SLO"
18
+ - "embracing risk", "Google SRE cap 3"
19
+
20
+ ## Regras absolutas
21
+
22
+ - **100% disponibilidade NÃO é o objetivo** — custo cresce não-linearmente acima de 99.95%; benefício marginal cai a zero porque outros componentes (ISP do usuário, smartphone, ar do ambiente) já têm < 99.99% de disponibilidade. Esforço além disso é desperdício.
23
+ - **"As reliable as needs to be, no more"** — disponibilidade é decisão de produto, não de engenharia. Pergunta: "qual nível o usuário percebe como aceitável e está disposto a pagar?" — não "qual o máximo que conseguimos?".
24
+ - **Sabedoria 99.99%** — smartphone tem ~99% de disponibilidade (sinal cai, bateria acaba, app trava). Usuário em 99% smartphone NÃO distingue serviço 99.99% vs 99.999% — ambos parecem "sempre funcionando" no contexto dele.
25
+ - **Error budget é balanço explícito risk × innovation** — `(1 - SLO_target) × total_events` é orçamento de "bad" que pode ser gasto em deploys arriscados, experimentos, refactors. Se budget esgota, freeze releases até regenerar.
26
+ - **Target ≤ 99.95% para SLO real** — 99.99% = 4.3 min de tolerância em 30d; sem tempo de reagir antes do budget esgotar; alerts viram zero-level. Para 99.99%+, use métricas/dashboards informativos, NÃO SLO acionável.
27
+ - **SLI deve refletir customer perception** — meça o que o usuário sente ("checkout completou em < 800ms"), não estado interno ("threads ativas"). Risk é sobre consequência do customer, não engenharia.
28
+ - **Diferentes tiers, diferentes targets** — `customer.tier='enterprise'` pode ter SLO 99.95%; `tier='free'` pode ter 99.5%. Risk é gradual; tratar todos clientes como tier-1 desperdiça budget.
29
+
30
+ ## Patterns canônicos
31
+
32
+ ### Pattern: risk continuum como decisão explícita
33
+
34
+ | Target | Tolerância 30d | User-perceptible? | Recomendação | Custo relativo |
35
+ |---|---|---|---|---|
36
+ | 99% | 7.2 h | Sim (notável) | Tier free, beta features, internal tools | 1× |
37
+ | 99.5% | 3.6 h | Notável em paths críticos | Tier free de produção | 2× |
38
+ | 99.9% | 43.2 min | Aceitável para maior parte de UX | Tier paid default | 5× |
39
+ | 99.95% | 21.6 min | Quase imperceptível | Tier enterprise / mission-critical | 10× |
40
+ | 99.99% | 4.3 min | Imperceptível em smartphone | Apenas se justificado por user perception (raro) | 50×+ |
41
+ | 99.999% | 26 s | NÃO perceptível | NUNCA para serviço user-facing | 100×+ |
42
+
43
+ Cada nove adicional **multiplica custo** mas **divide benefício marginal**. Cliente final (humano em smartphone com ISP residencial ~99%) tem disponibilidade no canal de comunicação inferior à do seu serviço 99.99%. Essa é a sabedoria 99.99%.
44
+
45
+ ### Pattern: error budget como decisão de release
46
+
47
+ ```yaml
48
+ # PT-BR: SLO documenta target + política de budget
49
+ slo:
50
+ name: checkout_success
51
+ target: 0.999 # 99.9% — escolha explícita no risk continuum
52
+ window: 30d_sliding
53
+
54
+ # PT-BR: política de budget — o que fazer quando queima
55
+ budget_policy:
56
+ green: # > 50% restante
57
+ action: "Releases livres; experimentos OK"
58
+ yellow: # 10-50% restante
59
+ action: "Aumentar canary % menor; review extra de PRs riscados"
60
+ red: # < 10% restante
61
+ action: "Freeze de features; foco em stability; postmortems revisitados"
62
+ exhausted: # 0%
63
+ action: "Freeze total; rollback de releases recentes; SEV1 incident review"
64
+ ```
65
+
66
+ Budget esgotado **não é punição** — é sinal de que o time gastou risk em demais releases arriscadas e precisa pausar para investir em stability. Restaurar budget = entregar trabalho que reduz erro, não pular o reset.
67
+
68
+ ### Pattern: target diferenciado por customer.tier
69
+
70
+ ```sql
71
+ -- PT-BR: SLO compliance por tier — diferentes targets, diferentes alarmes
72
+ select
73
+ customer_tier,
74
+ count(*) as total,
75
+ count(*) filter (where result_success = true and duration_ms < 800) as good,
76
+ count(*) filter (where result_success = true and duration_ms < 800)::float / count(*) as compliance,
77
+ case customer_tier
78
+ when 'enterprise' then 0.9995 -- PT-BR: 99.95% — paga por SLO rigoroso
79
+ when 'pro' then 0.999 -- PT-BR: 99.9%
80
+ when 'free' then 0.995 -- PT-BR: 99.5% — best effort
81
+ end as target,
82
+ case
83
+ when count(*) filter (where result_success = true and duration_ms < 800)::float / count(*) >= (
84
+ case customer_tier
85
+ when 'enterprise' then 0.9995
86
+ when 'pro' then 0.999
87
+ when 'free' then 0.995
88
+ end
89
+ ) then 'IN_BUDGET'
90
+ else 'OUT_OF_BUDGET'
91
+ end as status
92
+ from observability.events
93
+ where service = 'orders-api' and timestamp > now() - interval '30 days'
94
+ group by customer_tier;
95
+ ```
96
+
97
+ ### Pattern: justificar 99.99%+ excepcional
98
+
99
+ ```text
100
+ Para SLO ≥ 99.99%, o time DEVE responder afirmativamente a TODAS as perguntas:
101
+
102
+ 1. User percebe diretamente a falha? (não apenas erro 500 — UX colapsa, dados perdidos)
103
+ Ex: trading platform de high-frequency, controle de fluxo industrial, healthcare critical
104
+
105
+ 2. Custo de outage > 10× custo de engineering p/ atingir target?
106
+ (calcular: 4.3 min outage por mês × revenue/min impactado)
107
+
108
+ 3. Sistema componentes downstream também são ≥ 99.99%?
109
+ (cliente em ISP 99% — investir aqui é desperdício; trocar de ISP/CDN primeiro)
110
+
111
+ 4. Time tem cultura para sustentar (canary obrigatório, rollback < 60s, on-call < 30s page)?
112
+ (sem isso, 99.99% é aspiracional — real será 99.5%)
113
+
114
+ Se QUALQUER resposta = NÃO → use 99.95% ou menos. Justificar em SLO.md comentário inline.
115
+ ```
116
+
117
+ ## Anti-patterns
118
+
119
+ ### ANTI: pursuit of 100% availability
120
+
121
+ ```text
122
+ ANTI: perseguir 100% como meta de disponibilidade — rejeitar qualquer outage como
123
+ falha de engenharia; medir sucesso por "zero downtime"
124
+
125
+ PROBLEMA: custo cresce assintoticamente perto de 100%; benefício marginal cai a zero
126
+ porque downstream (ISP do usuário, smartphone, ar do ambiente) já tem
127
+ < 99.99%; time burns out perseguindo target inalcançável; budget de
128
+ inovação some — toda capacidade vai para reliability sem ganho real.
129
+
130
+ CERTO: aceitar imperfeição como design — error budget existe PARA SER GASTO em
131
+ deploys arriscados, experimentos, refactors. Reliability é trade-off
132
+ contra velocity, não absoluto.
133
+ ```
134
+
135
+ ### ANTI: SLO 99.99% sem justificativa
136
+
137
+ ```text
138
+ ANTI: definir 99.99% como target por default — "queremos o melhor possível";
139
+ copiar número do AWS SLA; impor 99.99% sem checklist de justificação
140
+
141
+ PROBLEMA: 4.3 min de tolerância em 30d é zero margem de manobra; alerts disparam
142
+ após budget esgotar (zero-level — tarde demais para ação preventiva);
143
+ comportamentos perversos (esconder outages para preservar number);
144
+ time-pressure compulsiva; aspiração ≠ realidade — real será 99.5%
145
+ por falta de cultura para sustentar.
146
+
147
+ CERTO: ≤ 99.95% por default; 99.99%+ exige passar checklist de 4 perguntas
148
+ (ver Pattern: justificar 99.99%+ excepcional). Documentar racional em
149
+ SLO.md como comentário inline auditável.
150
+ ```
151
+
152
+ ### ANTI: SLO global "site availability"
153
+
154
+ ```text
155
+ ANTI: 1 SLO genérico "site availability 99.9%" cobrindo tudo — /admin, /api,
156
+ /checkout, /search, /docs com mesmo target
157
+
158
+ PROBLEMA: falha em /admin (uso 1×/dia por staff) não importa para customer;
159
+ falha em /checkout (uso 100×/min com revenue impact) é catastrófico;
160
+ mistura tudo no mesmo budget — alerts confusos, ações vagas; quando
161
+ burn dispara, time não sabe o que priorizar.
162
+
163
+ CERTO: 1 SLO por jornada crítica do user (`checkout_success: 99.9%`,
164
+ `login_success: 99.95%`, `search_p95: 99% < 200ms`); cada um com target
165
+ apropriado ao seu risk; admin/docs SEM SLO formal (só metric informativo).
166
+ ```
167
+
168
+ ### ANTI: budget como score de "performance"
169
+
170
+ ```text
171
+ ANTI: celebrar "atingimos SLO 99.99% este mês!" como vitória; KPIs comparam
172
+ times por % budget intacto; pressão de leadership para subir target
173
+
174
+ PROBLEMA: budget vira métrica de vaidade; budget intacto significa SUBUTILIZAÇÃO
175
+ (não shippamos suficientes deploys arriscados/experimentos); leadership
176
+ pressiona por mais features sem reconhecer trade-off; quando budget
177
+ esgota uma vez, vira "fracasso" — time esconde problemas no próximo mês.
178
+
179
+ CERTO: budget é orçamento — gastá-lo é OK e esperado. KPI é "shippamos N deploys
180
+ de valor sem queimar budget", não "budget alto". Budget esgotado = sinal
181
+ de aprender (quais releases custaram caro?), não punição.
182
+ ```
183
+
184
+ ### ANTI: SLA == SLO
185
+
186
+ ```text
187
+ ANTI: usar SLA do contrato (99.9%) como SLO interno — "se prometemos 99.9% no
188
+ contrato, basta atingir 99.9% internamente"
189
+
190
+ PROBLEMA: 0 margem de segurança entre compromisso comercial e meta interna;
191
+ primeira anomalia operacional quebra contrato; sem buffer para reagir;
192
+ SEV1 vira liability legal; cliente perde confiança no primeiro burn.
193
+
194
+ CERTO: SLO interno mais rígido que SLA externo — fator de margem 5×.
195
+ SLA externo: 99.9% (compromisso ao cliente);
196
+ SLO interno: 99.95% (meta de engenharia com folga para reagir).
197
+ ```
198
+
199
+ ## Verificação
200
+
201
+ Antes de marcar SLO target como decidido:
202
+
203
+ 1. **Target justificado por customer perception** — não "queremos 99.99%" mas "usuário em smartphone percebe falha acima de X%"
204
+ 2. **Target ≤ 99.95%** OU passou checklist de 99.99%+ (ver Pattern: justificar 99.99%+ excepcional)
205
+ 3. **Tier-aware** — diferentes targets para `customer.tier` quando aplicável (enterprise/pro/free)
206
+ 4. **Budget policy documentada** — 4 estados (green/yellow/red/exhausted) com ações claras
207
+ 5. **Owner nomeado** — SLO sem dono = sem ação = sem valor
208
+ 6. **SLI customer-facing** — mede o que cliente sente, não estado interno
209
+ 7. **SLA externo > SLO interno** — margem entre compromisso comercial e meta interna
210
+
211
+ ## Ver também
212
+
213
+ - [`_shared-sre/glossary.md`](../_shared-sre/glossary.md) — termos canônicos risk continuum, error budget, MTTR/MTBF
214
+ - [`event-based-slos`](../event-based-slos/SKILL.md) (v1.9) — definir SLO event-based com sliding window
215
+ - [`burn-rate-alerting`](../burn-rate-alerting/SKILL.md) (v1.9) — alertas predictive sobre error budget
216
+ - [`production-readiness-review`](../production-readiness-review/SKILL.md) — PRR axis "Performance" usa risk continuum
217
+ - [`blameless-postmortems`](../blameless-postmortems/SKILL.md) — postmortem documenta budget consumido
218
+
219
+ ---
220
+
221
+ *Material-fonte: Site Reliability Engineering — Beyer, Jones, Petoff, Murphy (Google/O'Reilly, 2016) — Cap 3: "Embracing Risk".*
@@ -0,0 +1,265 @@
1
+ ---
2
+ name: structured-events
3
+ description: Use ao instrumentar — wide events de alta cardinalidade (1/request), campos canônicos com dot notation, evite logs unstructured e métricas pre-aggregated.
4
+ ---
5
+
6
+ # Observabilidade — Structured Events (Wide Events)
7
+
8
+ ## Quando usar
9
+
10
+ LLM carrega esta skill quando instrumentar código para emitir telemetria. Trigger phrases:
11
+
12
+ - "structured logging", "wide events", "observability events"
13
+ - "instrumentar handler", "emitir telemetria", "log estruturado"
14
+ - "como salvar evento de request"
15
+ - "campos canônicos", "atributos de span"
16
+ - "alta cardinalidade", "debug por user_id"
17
+
18
+ ## Regras absolutas
19
+
20
+ - **1 evento por request** — não múltiplos. Acumule contexto durante o request, emita 1 wide event no final (ou em erros).
21
+ - **Wide é melhor que narrow** — adicione campos liberalmente. Custo de 100 campos/evento ≈ 10 campos. Disco é barato; falta de campo no incidente é caro.
22
+ - **Alta cardinalidade é OBRIGATÓRIA** — `user.id`, `tenant_id`, `request.id`, `customer.email`. Sem isso, observabilidade não funciona (Cap 1).
23
+ - **Dot notation OTel** — `user.id` (não `userId` nem `user_id`). `error.type`, `http.status_code`, `db.query`. Snake_case apenas em colunas de DB.
24
+ - **NUNCA pre-aggregate** — não emita "p99 latency = 247ms"; emita o `duration_ms` cru de cada request. Aggregation no read time.
25
+ - **Estruturado, não texto livre** — JSON, OTel attributes, ou colunas tipadas. **Nunca** `console.log("user 123 did X at 12:34")`.
26
+ - **Errors são especiais** — sample 100% de eventos com `result.success = false`. Sucesso pode ser samplado (skill `telemetry-sampling`).
27
+ - **Capture context, não code** — emita atributos de business logic (`customer.tier`, `feature_flag.x`), não estado interno de código (`var_x_value_at_line_42`).
28
+
29
+ ## Patterns canônicos
30
+
31
+ ### Pattern: handler instrumentado (Node/TypeScript)
32
+
33
+ ```ts
34
+ // PT-BR: 1 evento por request, alta cardinalidade, atributos canônicos
35
+ import { trace, SpanStatusCode } from '@opentelemetry/api'
36
+
37
+ const tracer = trace.getTracer('orders-service')
38
+
39
+ export async function handlePlaceOrder(req: Request) {
40
+ return tracer.startActiveSpan('place_order', async (span) => {
41
+ // PT-BR: campos canônicos sempre — alta cardinalidade
42
+ span.setAttribute('user.id', req.user.id)
43
+ span.setAttribute('tenant_id', req.user.tenant)
44
+ span.setAttribute('customer.tier', req.user.tier)
45
+ span.setAttribute('request.id', req.headers['x-request-id'])
46
+ span.setAttribute('endpoint', '/api/v1/orders')
47
+ span.setAttribute('http.method', 'POST')
48
+ span.setAttribute('build_id', process.env.BUILD_ID ?? 'dev')
49
+
50
+ // PT-BR: feature flags como dimensões
51
+ span.setAttribute('feature_flag.new_pricing', req.flags.newPricing)
52
+
53
+ try {
54
+ const order = await createOrder(req.body)
55
+
56
+ // PT-BR: result e atributos de domínio
57
+ span.setAttribute('result.success', true)
58
+ span.setAttribute('order.id', order.id)
59
+ span.setAttribute('order.amount_cents', order.amount)
60
+ span.setAttribute('order.items_count', order.items.length)
61
+ span.setAttribute('http.status_code', 200)
62
+ span.setStatus({ code: SpanStatusCode.OK })
63
+ return order
64
+ } catch (e) {
65
+ // PT-BR: erros — sample 100%, classificar por tipo
66
+ span.setAttribute('result.success', false)
67
+ span.setAttribute('error.type', classifyError(e))
68
+ span.setAttribute('error.message', e.message)
69
+ span.setAttribute('http.status_code', e.statusCode ?? 500)
70
+ span.setStatus({ code: SpanStatusCode.ERROR, message: e.message })
71
+ throw e
72
+ } finally {
73
+ span.end() // PT-BR: SEMPRE — duration_ms é calculado aqui
74
+ }
75
+ })
76
+ }
77
+
78
+ function classifyError(e: any): string {
79
+ if (e.code === 'P2002') return 'db_conflict'
80
+ if (e.statusCode === 401) return 'auth'
81
+ if (e.statusCode === 403) return 'authz'
82
+ if (e.statusCode === 422) return 'validation'
83
+ if (e.statusCode === 429) return 'rate_limit'
84
+ if (e.code === 'ETIMEDOUT') return 'timeout'
85
+ return 'unknown'
86
+ }
87
+ ```
88
+
89
+ ### Pattern: Edge Function (Deno) com structured event
90
+
91
+ ```ts
92
+ // PT-BR: Supabase Edge Function — 1 evento estruturado por invocação
93
+ import { trace } from 'npm:@opentelemetry/api@1.9.0'
94
+
95
+ const tracer = trace.getTracer('edge-process-emails')
96
+
97
+ Deno.serve(async (req) => {
98
+ return tracer.startActiveSpan('process_emails', async (span) => {
99
+ const requestId = crypto.randomUUID()
100
+ span.setAttribute('request.id', requestId)
101
+ span.setAttribute('build_id', Deno.env.get('SUPABASE_GIT_SHA') ?? 'local')
102
+
103
+ try {
104
+ const body = await req.json()
105
+ span.setAttribute('user.id', body.user_id)
106
+ span.setAttribute('tenant_id', body.tenant_id)
107
+ span.setAttribute('email.batch_size', body.emails?.length ?? 0)
108
+
109
+ const result = await processBatch(body.emails)
110
+
111
+ span.setAttribute('result.success', true)
112
+ span.setAttribute('email.sent_count', result.sent)
113
+ span.setAttribute('email.failed_count', result.failed)
114
+ span.setAttribute('duration_ms', result.duration)
115
+
116
+ return new Response(JSON.stringify(result), { status: 200 })
117
+ } catch (e) {
118
+ span.setAttribute('result.success', false)
119
+ span.setAttribute('error.type', classify(e))
120
+ span.setAttribute('error.message', String(e))
121
+ return new Response(JSON.stringify({ error: 'failed' }), { status: 500 })
122
+ } finally {
123
+ span.end()
124
+ }
125
+ })
126
+ })
127
+ ```
128
+
129
+ ### Pattern: campos canônicos por categoria
130
+
131
+ | Categoria | Campos | Exemplo |
132
+ |---|---|---|
133
+ | **Identidade** | `user.id`, `tenant_id`, `session.id` | `"550e8400-e29b-41d4-..."` |
134
+ | **Request** | `request.id`, `endpoint`, `http.method`, `http.status_code` | `"req_abc123"`, `"/api/v1/orders"`, `"POST"`, `200` |
135
+ | **Resultado** | `result.success`, `error.type`, `error.message` | `true`, `"validation"`, `"email already exists"` |
136
+ | **Performance** | `duration_ms`, `db.query_count`, `cache.hit` | `127`, `3`, `true` |
137
+ | **Build/Deploy** | `build_id`, `service.version`, `region` | `"abc123f"`, `"v1.9.0"`, `"us-east-1"` |
138
+ | **Business** | `customer.tier`, `order.amount_cents`, `feature_flag.<name>` | `"pro"`, `4990`, `true` |
139
+ | **Tracing** | `trace.id`, `span.id`, `span.parent_id` | (auto via OTel) |
140
+
141
+ ### Pattern: query observability — encontrar pattern em wide events
142
+
143
+ ```sql
144
+ -- PT-BR: alta cardinalidade permite group by ad hoc — sem schema rigido
145
+ -- Exemplo: qual tenant + endpoint + error_type domina os erros da última hora?
146
+ select
147
+ tenant_id,
148
+ endpoint,
149
+ error_type,
150
+ count(*) as error_count,
151
+ avg(duration_ms) as avg_duration
152
+ from observability.events
153
+ where
154
+ result_success = false
155
+ and timestamp > now() - interval '1 hour'
156
+ group by tenant_id, endpoint, error_type
157
+ order by error_count desc
158
+ limit 20;
159
+ ```
160
+
161
+ ## Anti-patterns
162
+
163
+ ### ANTI: log unstructured
164
+
165
+ ```ts
166
+ // PT-BR: BAD — não estruturado, não queryable, sem alta cardinalidade
167
+ console.log(`User ${userId} placed order ${orderId} for $${amount}`)
168
+
169
+ // PT-BR: GOOD — structured wide event
170
+ span.setAttribute('user.id', userId)
171
+ span.setAttribute('order.id', orderId)
172
+ span.setAttribute('order.amount_cents', amount * 100)
173
+ ```
174
+
175
+ ### ANTI: pre-aggregate em métricas
176
+
177
+ ```ts
178
+ // PT-BR: BAD — pre-aggregation perde alta cardinalidade
179
+ metrics.histogram('order_latency_ms').record(duration, { service: 'orders' })
180
+
181
+ // PT-BR: GOOD — emit raw event, agregue no read
182
+ span.setAttribute('duration_ms', duration)
183
+ // PT-BR: ao queryar: SELECT percentile_cont(0.99) WITHIN GROUP (ORDER BY duration_ms)
184
+ // FROM events GROUP BY tenant_id, endpoint -- alta cardinalidade preservada!
185
+ ```
186
+
187
+ ### ANTI: múltiplos eventos por request
188
+
189
+ ```ts
190
+ // PT-BR: BAD — 5 eventos para 1 request, sem trace context
191
+ log('user_action_started', { user_id })
192
+ log('user_action_db_query', { user_id, query })
193
+ log('user_action_email_sent', { user_id, to })
194
+ log('user_action_completed', { user_id })
195
+ log('user_action_response_sent', { user_id, status })
196
+
197
+ // PT-BR: GOOD — 1 wide event acumulando contexto
198
+ const span = tracer.startSpan('user_action')
199
+ span.setAttribute('user.id', user_id)
200
+ // ... ao longo do handler, span.setAttribute('email.recipient', ...) etc.
201
+ span.end() // 1 evento emitido com todos os atributos
202
+ ```
203
+
204
+ ### ANTI: cardinalidade baixa
205
+
206
+ ```ts
207
+ // PT-BR: BAD — apenas service e endpoint, sem identidade
208
+ span.setAttribute('service', 'orders')
209
+ span.setAttribute('endpoint', '/place')
210
+ // PT-BR: durante incident você não consegue responder "afeta quem?"
211
+
212
+ // PT-BR: GOOD — adicione identidades de alta cardinalidade
213
+ span.setAttribute('user.id', '550e8400-...')
214
+ span.setAttribute('tenant_id', 'acme-corp')
215
+ span.setAttribute('customer.tier', 'pro')
216
+ // PT-BR: durante incident: "afeta quem?" → group by customer.tier, tenant_id
217
+ ```
218
+
219
+ ### ANTI: capturar valores internos de código
220
+
221
+ ```ts
222
+ // PT-BR: BAD — atributos sobre estado de variáveis, não sobre business
223
+ span.setAttribute('var_temp_array_length', tempArr.length)
224
+ span.setAttribute('loop_iteration', i)
225
+
226
+ // PT-BR: GOOD — atributos sobre business + identidade
227
+ span.setAttribute('order.items_count', items.length)
228
+ span.setAttribute('user.id', userId)
229
+ ```
230
+
231
+ ### ANTI: nomes inconsistentes de atributos
232
+
233
+ ```ts
234
+ // PT-BR: BAD — mesmo conceito com nomes diferentes em handlers diferentes
235
+ span.setAttribute('userId', user.id) // handler A
236
+ span.setAttribute('user_id', user.id) // handler B
237
+ span.setAttribute('user', user.id) // handler C
238
+ // PT-BR: query `WHERE user_id = X` falha em handler A; agg cross-handler quebra
239
+
240
+ // PT-BR: GOOD — convenção única em todo o projeto
241
+ span.setAttribute('user.id', user.id) // sempre dot notation OTel
242
+ ```
243
+
244
+ ## Verificação
245
+
246
+ Antes de marcar instrumentação completa:
247
+
248
+ 1. **1 evento por request** — em request de exemplo, contar eventos emitidos. Deve ser 1 (ou 2 se houver retry interno).
249
+ 2. **Atributos canônicos presentes** — checar `user.id`, `tenant_id`, `request.id`, `result.success`, `endpoint`, `duration_ms` no evento emitido.
250
+ 3. **Alta cardinalidade verificada** — `select count(distinct user_id)` deve crescer com tráfego real (não estagnar em N pequeno).
251
+ 4. **`result.success` define SLI** — boolean confiável para alimentar SLO downstream (ver skill `event-based-slos`).
252
+ 5. **Erros têm `error.type` enum** — não `error.message` cru. Permite group by por categoria.
253
+ 6. **Build_id presente** — permite comparar versão antes vs depois de deploy.
254
+ 7. **Smoke local** — emitir 100 eventos sintéticos, queryar via `select * from events where user_id = X` deve retornar todos.
255
+
256
+ ---
257
+
258
+ ## Ver também
259
+
260
+ - `kit/skills/_shared-observability/glossary.md` — termos canônicos, campos canônicos, anti-patterns
261
+ - `kit/skills/distributed-tracing/SKILL.md` — como spans se conectam em traces
262
+ - `kit/skills/opentelemetry-standard/SKILL.md` — SDK e exporters
263
+ - `kit/skills/core-analysis-loop/SKILL.md` — como queryar wide events para debug
264
+
265
+ *Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 5: "Structured Events Are the Building Blocks of Observability".*