@luanpdd/kit-mcp 1.34.0 → 1.36.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.
- package/README.md +1 -1
- package/bin/cli.js +2 -2
- package/bin/mcp.js +6 -6
- package/bin/ui.js +74 -74
- package/gates/ai-prompt-stability.md +120 -120
- package/gates/budget-description.md +68 -68
- package/gates/confidence.md +29 -29
- package/gates/dependency-check.md +33 -33
- package/gates/dept-cycle-prevention.md +179 -179
- package/gates/golden-signals-coverage.md +133 -133
- package/gates/legacy-refactor-safety.md +178 -178
- package/gates/multi-tenant-rls-coverage.md +102 -102
- package/gates/no-personal-uuid.md +72 -72
- package/gates/obs-agents-mcp-supabase.md +86 -86
- package/gates/obs-skills-frontmatter.md +76 -76
- package/gates/observability-coverage.md +151 -151
- package/gates/omm-no-regression.md +83 -83
- package/gates/postmortem-template-required.md +127 -127
- package/gates/prr-checklist-coverage.md +128 -128
- package/gates/regression.md +32 -32
- package/gates/release-pipeline-policy.md +132 -132
- package/gates/secrets-scan.md +33 -33
- package/gates/service-role-not-in-user-facing.md +113 -113
- package/gates/skill-must-include.md +71 -71
- package/gates/sync-idempotent.md +62 -62
- package/gates/verify-phase-goal.md +34 -34
- package/kit/agents/designer-ui.md +216 -216
- package/kit/agents/workflow-generator.md +537 -0
- package/kit/commands/adicionar-backlog.md +1 -1
- package/kit/commands/adicionar-fase.md +1 -1
- package/kit/commands/adicionar-tarefa.md +1 -1
- package/kit/commands/auditar-observabilidade.md +103 -103
- package/kit/commands/auditar-toil.md +129 -129
- package/kit/commands/caracterizar-prompt.md +195 -195
- package/kit/commands/criar-workflow.md +158 -0
- package/kit/commands/definir-perfil.md +1 -1
- package/kit/commands/definir-slo.md +108 -108
- package/kit/commands/fio.md +1 -1
- package/kit/commands/golden-signals.md +142 -142
- package/kit/commands/instrumentar-fase.md +200 -200
- package/kit/commands/investigar-producao.md +162 -162
- package/kit/commands/observabilidade.md +118 -118
- package/kit/commands/postmortem.md +179 -179
- package/kit/commands/prr.md +205 -205
- package/kit/commands/publicar-rapido.md +207 -207
- package/kit/commands/risk-budget.md +220 -220
- package/kit/commands/sre.md +230 -230
- package/kit/file-manifest.json +5 -2
- package/kit/framework/references/output-style.md +22 -22
- package/kit/hooks/post-apply-migration.js +199 -199
- package/kit/hooks/sidecar-tool-publisher.js +210 -210
- package/kit/skills/_shared-dados-distribuidos/glossary.md +224 -224
- package/kit/skills/_shared-legacy/glossary.md +389 -389
- package/kit/skills/_shared-multi-tenant/glossary.md +186 -186
- package/kit/skills/_shared-observability/glossary.md +396 -396
- package/kit/skills/_shared-sre/glossary.md +712 -712
- package/kit/skills/_shared-supabase/glossary.md +234 -234
- package/kit/skills/blameless-postmortems/SKILL.md +340 -340
- package/kit/skills/burn-rate-alerting/SKILL.md +258 -258
- package/kit/skills/cascading-failures/SKILL.md +311 -311
- package/kit/skills/core-analysis-loop/SKILL.md +352 -352
- package/kit/skills/distributed-tracing/SKILL.md +362 -362
- package/kit/skills/dynamic-workflow-authoring/SKILL.md +327 -0
- package/kit/skills/eliminating-toil/SKILL.md +243 -243
- package/kit/skills/event-based-slos/SKILL.md +296 -296
- package/kit/skills/four-golden-signals/SKILL.md +314 -314
- package/kit/skills/hermetic-builds/SKILL.md +323 -323
- package/kit/skills/legacy-monster-methods/SKILL.md +444 -444
- package/kit/skills/llm-as-dependency/SKILL.md +436 -436
- package/kit/skills/load-shedding-graceful-degradation/SKILL.md +396 -396
- package/kit/skills/observability-driven-development/SKILL.md +315 -315
- package/kit/skills/observability-maturity-model/SKILL.md +222 -222
- package/kit/skills/opentelemetry-standard/SKILL.md +351 -351
- package/kit/skills/production-readiness-review/SKILL.md +305 -305
- package/kit/skills/release-engineering/SKILL.md +367 -367
- package/kit/skills/retry-strategies/SKILL.md +372 -372
- package/kit/skills/sre-risk-management/SKILL.md +221 -221
- package/kit/skills/structured-events/SKILL.md +265 -265
- package/kit/skills/supabase-cron-queues/SKILL.md +275 -275
- package/kit/skills/supabase-database-functions/SKILL.md +332 -332
- package/kit/skills/supabase-declarative-schema/SKILL.md +183 -183
- package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -253
- package/kit/skills/supabase-postgres-style/SKILL.md +138 -138
- package/kit/skills/supabase-storage/SKILL.md +234 -234
- package/kit/skills/telemetry-pipelines/SKILL.md +259 -259
- package/kit/skills/telemetry-sampling/SKILL.md +256 -256
- package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
- package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
- package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
- package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
- package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
- package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
- package/kit/skills/ui-tipografia/SKILL.md +211 -211
- package/package.json +1 -1
- package/src/cli/index.js +1114 -1114
- package/src/cli/render.js +194 -194
- package/src/cli/upgrade-check.js +135 -135
- package/src/core/error-redaction.js +76 -76
- package/src/core/failures.js +153 -153
- package/src/core/gate-runner.js +205 -205
- package/src/core/gates.js +82 -82
- package/src/core/logger.js +170 -170
- package/src/core/manifest-verify.js +174 -174
- package/src/core/metrics.js +268 -268
- package/src/core/notify.js +60 -60
- package/src/core/path-safety.js +141 -141
- package/src/core/replays.js +120 -120
- package/src/core/ui.js +185 -185
- package/src/mcp-server/install.js +149 -149
- package/src/mcp-server/roots.js +124 -124
- package/src/ui/auto-spawn.js +113 -113
- package/src/ui/browser.js +78 -78
- package/src/ui/client.js +130 -130
- package/src/ui/events.js +65 -65
- package/src/ui/lockfile.js +191 -191
- package/src/ui/port.js +67 -67
- package/src/ui/server.js +547 -547
- package/src/ui/wrapper.js +129 -129
|
@@ -1,315 +1,315 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: observability-driven-development
|
|
3
|
-
description: Use ao bundlear telemetria com nova feature — 4 perguntas pré-PR, instrumentação shift-left, auto-page do autor por 30-60min após merge. Análogo TDD para produção.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Observabilidade — Observability-Driven Development (ODD)
|
|
7
|
-
|
|
8
|
-
## Quando usar
|
|
9
|
-
|
|
10
|
-
LLM carrega esta skill ao escrever nova feature, planejar fase, ou code review. Trigger phrases:
|
|
11
|
-
|
|
12
|
-
- "ODD", "observability-driven development"
|
|
13
|
-
- "como sei que essa feature funciona em prod?"
|
|
14
|
-
- "instrumentar antes do PR"
|
|
15
|
-
- "shift-left observability"
|
|
16
|
-
- "auto-page do autor"
|
|
17
|
-
- "bundle telemetry com feature"
|
|
18
|
-
|
|
19
|
-
## As 4 perguntas pré-PR (canônicas)
|
|
20
|
-
|
|
21
|
-
Antes de submeter PR, todo autor responde EM CÓDIGO:
|
|
22
|
-
|
|
23
|
-
| # | Pergunta | Como instrumentar |
|
|
24
|
-
|---|----------|-------------------|
|
|
25
|
-
| **1** | **Faz o que esperei?** | `result.success` boolean por evento + atributos do happy path (`order.id`, `user.id`) |
|
|
26
|
-
| **2** | **Compara à versão anterior?** | `build_id` em todo evento — permite `WHERE build_id = X vs build_id = Y` |
|
|
27
|
-
| **3** | **Usuários estão usando?** | Atributo de identidade (`user.id`, `tenant_id`, `customer.tier`) e do path do request (`endpoint`, `feature_flag.<name>`) |
|
|
28
|
-
| **4** | **Anomalias emergem?** | `error.type` enumerado + `duration_ms` + capturar todos os branches de código (try/catch + early returns) |
|
|
29
|
-
|
|
30
|
-
**Sem isso, o PR não é mergeável.** Não é regra burocrática — é a diferença entre "funciona em testes" e "funciona em produção".
|
|
31
|
-
|
|
32
|
-
## Regras absolutas
|
|
33
|
-
|
|
34
|
-
- **Bundle telemetria com a feature** — instrumentação não é fase separada. Mesmo PR adiciona feature + spans + atributos.
|
|
35
|
-
- **Auto-page o autor por 30-60min após merge** — feedback loop curto. "Fui eu, eu sei o que era e eu posso reverter." NUNCA pular essa janela.
|
|
36
|
-
- **Decouple deploy de release** — feature flag por default. Deploy = código em prod desligado; release = liga aos poucos.
|
|
37
|
-
- **Test em prod com subset** — 1% de tráfego com flag ativada > 100% rollout em horário de baixa.
|
|
38
|
-
- **Rollback < rollforward em duvida** — observabilidade rica mostra o que está errado em segundos, mas só se você não rolou-back o evidência primeiro. Pause primeiro, investigue, então decida.
|
|
39
|
-
- **Toda code branch = atributo** — `if (x) { ... } else { ... }` precisa emitir atributo de qual branch foi tomada (`branch_taken: 'fast_path'` vs `'slow_path'`).
|
|
40
|
-
- **Tighten do feedback loop é o objetivo** — minutos do commit ao prod, não dias. Cada hora de delay multiplica custo de debug.
|
|
41
|
-
|
|
42
|
-
## Patterns canônicos
|
|
43
|
-
|
|
44
|
-
### Pattern: feature instrumentada nasce ODD-compliant
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
// PT-BR: feature nova "novo método de pagamento" — instrumentação BUNDLED
|
|
48
|
-
import { trace, SpanStatusCode } from '@opentelemetry/api'
|
|
49
|
-
|
|
50
|
-
const tracer = trace.getTracer('payments')
|
|
51
|
-
|
|
52
|
-
export async function processPaymentV2(req: PaymentRequest) {
|
|
53
|
-
return tracer.startActiveSpan('process_payment_v2', async (span) => {
|
|
54
|
-
// PT-BR: Pergunta 3 — quem está usando?
|
|
55
|
-
span.setAttribute('user.id', req.user.id)
|
|
56
|
-
span.setAttribute('customer.tier', req.user.tier)
|
|
57
|
-
span.setAttribute('tenant_id', req.user.tenant)
|
|
58
|
-
span.setAttribute('endpoint', '/api/v2/payments')
|
|
59
|
-
|
|
60
|
-
// PT-BR: Pergunta 2 — qual versão?
|
|
61
|
-
span.setAttribute('build_id', process.env.BUILD_ID ?? 'dev')
|
|
62
|
-
span.setAttribute('feature_flag.payments_v2', true) // PT-BR: assumed via flag
|
|
63
|
-
span.setAttribute('payment.method', req.method) // novo: 'pix' | 'crypto' | 'card'
|
|
64
|
-
|
|
65
|
-
// PT-BR: Pergunta 4 — atributo por branch
|
|
66
|
-
if (req.amount > 1_000_00) {
|
|
67
|
-
span.setAttribute('branch_taken', 'high_value')
|
|
68
|
-
span.setAttribute('requires_3ds', true)
|
|
69
|
-
} else {
|
|
70
|
-
span.setAttribute('branch_taken', 'standard')
|
|
71
|
-
span.setAttribute('requires_3ds', false)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const result = await chargeProvider(req)
|
|
76
|
-
|
|
77
|
-
// PT-BR: Pergunta 1 — fez o que esperei?
|
|
78
|
-
span.setAttribute('result.success', true)
|
|
79
|
-
span.setAttribute('payment.id', result.id)
|
|
80
|
-
span.setAttribute('payment.processor_response', result.processorCode)
|
|
81
|
-
span.setStatus({ code: SpanStatusCode.OK })
|
|
82
|
-
return result
|
|
83
|
-
} catch (e) {
|
|
84
|
-
// PT-BR: Pergunta 4 — anomalia identificada com type enum
|
|
85
|
-
span.setAttribute('result.success', false)
|
|
86
|
-
span.setAttribute('error.type', classify(e)) // 'provider_down' | 'declined' | 'fraud_block'
|
|
87
|
-
span.setAttribute('error.processor_code', e.code)
|
|
88
|
-
span.setStatus({ code: SpanStatusCode.ERROR })
|
|
89
|
-
throw e
|
|
90
|
-
} finally {
|
|
91
|
-
span.end()
|
|
92
|
-
}
|
|
93
|
-
})
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Pattern: auto-page autor (config CI/CD)
|
|
98
|
-
|
|
99
|
-
```yaml
|
|
100
|
-
# PT-BR: GitHub Actions ou equivalente — paginar autor após merge
|
|
101
|
-
# .github/workflows/post-merge-watch.yml
|
|
102
|
-
name: post-merge-watch
|
|
103
|
-
on:
|
|
104
|
-
push:
|
|
105
|
-
branches: [main]
|
|
106
|
-
jobs:
|
|
107
|
-
page-author:
|
|
108
|
-
runs-on: ubuntu-latest
|
|
109
|
-
steps:
|
|
110
|
-
- name: Page commit author for 30-60min
|
|
111
|
-
run: |
|
|
112
|
-
AUTHOR_EMAIL="${{ github.event.head_commit.author.email }}"
|
|
113
|
-
PAGER_TOKEN="${{ secrets.PAGERDUTY_TOKEN }}"
|
|
114
|
-
# PT-BR: criar policy temporária — alertas SLO route para AUTHOR_EMAIL
|
|
115
|
-
# por 45 minutos. Após, retorna ao on-call normal.
|
|
116
|
-
curl -X POST https://api.pagerduty.com/oncall_overrides \
|
|
117
|
-
-H "Authorization: Token token=$PAGER_TOKEN" \
|
|
118
|
-
-d "{
|
|
119
|
-
\"override\": {
|
|
120
|
-
\"start\": \"$(date -u +%FT%TZ)\",
|
|
121
|
-
\"end\": \"$(date -u -d '+45 minutes' +%FT%TZ)\",
|
|
122
|
-
\"user\": {\"email\": \"$AUTHOR_EMAIL\"}
|
|
123
|
-
}
|
|
124
|
-
}"
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Pattern: deploy ≠ release (feature flag)
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
// PT-BR: deploy do código com flag DESLIGADA
|
|
131
|
-
const isV2Enabled = (req: Request): boolean => {
|
|
132
|
-
// PT-BR: 0% inicialmente — deploy = código em prod, mas dormente
|
|
133
|
-
if (!flags.isEnabled('payments_v2', { user_id: req.user.id })) {
|
|
134
|
-
return false
|
|
135
|
-
}
|
|
136
|
-
return true
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export async function processPayment(req: PaymentRequest) {
|
|
140
|
-
if (isV2Enabled(req)) {
|
|
141
|
-
return processPaymentV2(req)
|
|
142
|
-
}
|
|
143
|
-
return processPaymentV1(req)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// PT-BR: depois do deploy, release gradual:
|
|
147
|
-
// 1. flag.set('payments_v2', { user_id: 'me' }) — só dev
|
|
148
|
-
// 2. flag.set('payments_v2', { customer.tier: 'free' }, 1%) — 1% free users
|
|
149
|
-
// 3. observe SLO + error rate; se OK, sobe para 10%, 50%, 100%
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Pattern: comparar versão antes/depois (Pergunta 2)
|
|
153
|
-
|
|
154
|
-
```sql
|
|
155
|
-
-- PT-BR: SLI antes vs depois do deploy do build_id `abc123`
|
|
156
|
-
-- Mostra error_rate per build, agrupado por versão
|
|
157
|
-
select
|
|
158
|
-
build_id,
|
|
159
|
-
count(*) as total,
|
|
160
|
-
sum(case when result_success = false then 1 else 0 end) as errors,
|
|
161
|
-
100.0 * sum(case when result_success = false then 1 else 0 end) / count(*) as error_pct,
|
|
162
|
-
percentile_cont(0.99) within group (order by duration_ms) as p99_ms
|
|
163
|
-
from observability.spans
|
|
164
|
-
where
|
|
165
|
-
service_name = 'payments'
|
|
166
|
-
and timestamp > '2026-05-06 10:00'
|
|
167
|
-
and build_id in ('v1.5.2', 'v1.5.3') -- versão anterior + atual
|
|
168
|
-
group by build_id;
|
|
169
|
-
|
|
170
|
-
-- PT-BR: se v1.5.3 tem error_pct ou p99_ms > v1.5.2 → regressão. Rollback ou fix.
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Pattern: instrumentação shift-left no PLAN.md de fase
|
|
174
|
-
|
|
175
|
-
```markdown
|
|
176
|
-
# PLAN: Fase 42 — Novo método de pagamento
|
|
177
|
-
|
|
178
|
-
## Tarefas
|
|
179
|
-
|
|
180
|
-
| # | Task | Output |
|
|
181
|
-
|---|------|--------|
|
|
182
|
-
| 1 | Implementar `processPaymentV2` em `src/payments/v2.ts` | função |
|
|
183
|
-
| 2 | **Instrumentação OTel — bundled** | spans + atributos |
|
|
184
|
-
| 3 | Adicionar feature flag `payments_v2` | flag config |
|
|
185
|
-
| 4 | Tests unitários | tests/v2.spec.ts |
|
|
186
|
-
| 5 | **ODD — 4 perguntas validadas** | comments no PR |
|
|
187
|
-
|
|
188
|
-
## ODD — Validação das 4 perguntas
|
|
189
|
-
|
|
190
|
-
1. **Faz o que esperei?**
|
|
191
|
-
- Span `process_payment_v2` com atributo `result.success`
|
|
192
|
-
- Query: `SELECT count(*) WHERE result_success=true / count(*)` deve ser ≥ 99% após release
|
|
193
|
-
|
|
194
|
-
2. **Compara à versão anterior?**
|
|
195
|
-
- `build_id` em todo span permite cross-version
|
|
196
|
-
- Query: ver "Pattern: comparar versão" acima
|
|
197
|
-
|
|
198
|
-
3. **Usuários estão usando?**
|
|
199
|
-
- `customer.tier`, `payment.method` permitem slice & dice
|
|
200
|
-
- Query: `SELECT customer.tier, payment.method, count(*) FROM ... WHERE feature_flag.payments_v2=true GROUP BY 1,2`
|
|
201
|
-
|
|
202
|
-
4. **Anomalias emergem?**
|
|
203
|
-
- `error.type` enum: `'provider_down'`, `'declined'`, `'fraud_block'`
|
|
204
|
-
- `branch_taken` para code paths
|
|
205
|
-
- Alert: SLO burn rate > 2 sobre `WHERE feature_flag.payments_v2=true`
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## Anti-patterns
|
|
209
|
-
|
|
210
|
-
### ANTI: instrumentação como fase separada
|
|
211
|
-
|
|
212
|
-
```text
|
|
213
|
-
ANTI: "Vamos shipá-la primeiro, instrumentar na próxima sprint."
|
|
214
|
-
|
|
215
|
-
PROBLEMA: você está em prod cego. Quando algo quebrar, você não tem dados para
|
|
216
|
-
investigar. Adicionar instrumentação depois requer redeploy, que é
|
|
217
|
-
arriscado durante incident.
|
|
218
|
-
|
|
219
|
-
CERTO: instrumentação NO MESMO PR da feature. Não-negociável.
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### ANTI: glass castle (medo de mexer em prod)
|
|
223
|
-
|
|
224
|
-
```text
|
|
225
|
-
ANTI: "Não deploy hoje, é véspera de feriado."
|
|
226
|
-
"Não deploy depois das 17h."
|
|
227
|
-
"Vamos esperar a próxima janela de manutenção."
|
|
228
|
-
(Equipe deploya 1× por semana, em batches grandes)
|
|
229
|
-
|
|
230
|
-
PROBLEMA: deploys raros = deploys grandes = mais código mudando = mais risco.
|
|
231
|
-
Cada deploy fica mais perigoso por sua raridade. Cycle vicioso.
|
|
232
|
-
|
|
233
|
-
CERTO: deploy frequente (várias vezes ao dia) com features pequenas atrás de flags.
|
|
234
|
-
Cada deploy quase nada. Reverter quase nada se quebra. Confiança aumenta.
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### ANTI: rollback antes de investigar
|
|
238
|
-
|
|
239
|
-
```text
|
|
240
|
-
ANTI: alerta dispara → rollback automático → "voltou ao normal" → ninguém
|
|
241
|
-
investiga porque "tá funcionando agora"
|
|
242
|
-
|
|
243
|
-
PROBLEMA: você perdeu a evidência. Próximo incident similar começa do zero.
|
|
244
|
-
Padrão de regressão acumula tech debt invisível.
|
|
245
|
-
|
|
246
|
-
CERTO: pause feature flag (não rollback do deploy) → investigue com observability →
|
|
247
|
-
fix root cause → re-release. Rollback só se investigation tomar > 30min.
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### ANTI: testar com 100% rollout em horário de baixa
|
|
251
|
-
|
|
252
|
-
```text
|
|
253
|
-
ANTI: "Faz deploy 4h da manhã quando ninguém usa."
|
|
254
|
-
|
|
255
|
-
PROBLEMA: você está rodando com 100% de risk em condições não-realistas.
|
|
256
|
-
0 tráfego = 0 sinal. Quando bug aparecer no horário de pico, você
|
|
257
|
-
não terá dados.
|
|
258
|
-
|
|
259
|
-
CERTO: deploy a qualquer hora atrás de feature flag em 1% → observe → 10% → 100%.
|
|
260
|
-
Bugs aparecem no progressive rollout, não no horário de pico.
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### ANTI: paginar on-call em vez do autor
|
|
264
|
-
|
|
265
|
-
```text
|
|
266
|
-
ANTI: alerta dispara 2h após merge → on-call (que não escreveu o código) é paginado
|
|
267
|
-
|
|
268
|
-
PROBLEMA: on-call não tem contexto. Vai procurar "que mudou ultimamente" — toma 30min.
|
|
269
|
-
Autor está dormindo / fora do contexto. Feedback loop quebrado.
|
|
270
|
-
|
|
271
|
-
CERTO: por 30-60min após merge, alertas vão para o AUTOR. Ele tem o contexto fresco,
|
|
272
|
-
sabe o que mudou, pode reverter ou fix em 5min. Após janela, volta para on-call.
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### ANTI: instrumentação só em happy path
|
|
276
|
-
|
|
277
|
-
```text
|
|
278
|
-
ANTI: span com atributos só no `try` block; catch sem instrumentação
|
|
279
|
-
|
|
280
|
-
PROBLEMA: você não sabe nada sobre falhas. Pergunta 4 (anomalias) impossível de responder.
|
|
281
|
-
|
|
282
|
-
CERTO: cada `catch` adiciona `error.type` enum + `error.message` + `result.success=false`.
|
|
283
|
-
Cada early return adiciona `branch_taken: 'short_circuit_validation'` etc.
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
## Verificação
|
|
287
|
-
|
|
288
|
-
Antes de mergear PR, verificar as 4 perguntas:
|
|
289
|
-
|
|
290
|
-
| # | Pergunta | Validação |
|
|
291
|
-
|---|----------|-----------|
|
|
292
|
-
| 1 | **Faz o que esperei?** | Existe atributo `result.success` em algum span do código tocado? |
|
|
293
|
-
| 2 | **Compara à versão anterior?** | `build_id` é setado no span? (geralmente em SDK setup, validar uma vez) |
|
|
294
|
-
| 3 | **Usuários estão usando?** | Existe `user.id` ou `tenant_id` ou `customer.tier` no span? |
|
|
295
|
-
| 4 | **Anomalias emergem?** | `catch` blocks emitem `error.type` enum? branches if/else emitem `branch_taken`? |
|
|
296
|
-
|
|
297
|
-
Se qualquer pergunta = NÃO → PR não mergeable. Adicione instrumentação.
|
|
298
|
-
|
|
299
|
-
Após merge:
|
|
300
|
-
- ✅ Feature flag desligada por default? (deploy ≠ release)
|
|
301
|
-
- ✅ Auto-page do autor configurado por 30-60min?
|
|
302
|
-
- ✅ SLI/SLO baseline sabido para comparação pré/pós release?
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
## Ver também
|
|
307
|
-
|
|
308
|
-
- `kit/skills/_shared-observability/glossary.md` — termos canônicos, ODD, glass castle
|
|
309
|
-
- `kit/skills/structured-events/SKILL.md` — campos canônicos
|
|
310
|
-
- `kit/skills/distributed-tracing/SKILL.md` — instrumentação cross-service
|
|
311
|
-
- `kit/skills/event-based-slos/SKILL.md` *(Phase 32)* — SLI para baseline pré/pós release
|
|
312
|
-
- `kit/agents/observability-instrumenter.md` — agente que gera instrumentação
|
|
313
|
-
- `kit/commands/instrumentar-fase.md` — comando que aplica ODD em fases
|
|
314
|
-
|
|
315
|
-
*Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 11: "Observability-Driven Development".*
|
|
1
|
+
---
|
|
2
|
+
name: observability-driven-development
|
|
3
|
+
description: Use ao bundlear telemetria com nova feature — 4 perguntas pré-PR, instrumentação shift-left, auto-page do autor por 30-60min após merge. Análogo TDD para produção.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Observabilidade — Observability-Driven Development (ODD)
|
|
7
|
+
|
|
8
|
+
## Quando usar
|
|
9
|
+
|
|
10
|
+
LLM carrega esta skill ao escrever nova feature, planejar fase, ou code review. Trigger phrases:
|
|
11
|
+
|
|
12
|
+
- "ODD", "observability-driven development"
|
|
13
|
+
- "como sei que essa feature funciona em prod?"
|
|
14
|
+
- "instrumentar antes do PR"
|
|
15
|
+
- "shift-left observability"
|
|
16
|
+
- "auto-page do autor"
|
|
17
|
+
- "bundle telemetry com feature"
|
|
18
|
+
|
|
19
|
+
## As 4 perguntas pré-PR (canônicas)
|
|
20
|
+
|
|
21
|
+
Antes de submeter PR, todo autor responde EM CÓDIGO:
|
|
22
|
+
|
|
23
|
+
| # | Pergunta | Como instrumentar |
|
|
24
|
+
|---|----------|-------------------|
|
|
25
|
+
| **1** | **Faz o que esperei?** | `result.success` boolean por evento + atributos do happy path (`order.id`, `user.id`) |
|
|
26
|
+
| **2** | **Compara à versão anterior?** | `build_id` em todo evento — permite `WHERE build_id = X vs build_id = Y` |
|
|
27
|
+
| **3** | **Usuários estão usando?** | Atributo de identidade (`user.id`, `tenant_id`, `customer.tier`) e do path do request (`endpoint`, `feature_flag.<name>`) |
|
|
28
|
+
| **4** | **Anomalias emergem?** | `error.type` enumerado + `duration_ms` + capturar todos os branches de código (try/catch + early returns) |
|
|
29
|
+
|
|
30
|
+
**Sem isso, o PR não é mergeável.** Não é regra burocrática — é a diferença entre "funciona em testes" e "funciona em produção".
|
|
31
|
+
|
|
32
|
+
## Regras absolutas
|
|
33
|
+
|
|
34
|
+
- **Bundle telemetria com a feature** — instrumentação não é fase separada. Mesmo PR adiciona feature + spans + atributos.
|
|
35
|
+
- **Auto-page o autor por 30-60min após merge** — feedback loop curto. "Fui eu, eu sei o que era e eu posso reverter." NUNCA pular essa janela.
|
|
36
|
+
- **Decouple deploy de release** — feature flag por default. Deploy = código em prod desligado; release = liga aos poucos.
|
|
37
|
+
- **Test em prod com subset** — 1% de tráfego com flag ativada > 100% rollout em horário de baixa.
|
|
38
|
+
- **Rollback < rollforward em duvida** — observabilidade rica mostra o que está errado em segundos, mas só se você não rolou-back o evidência primeiro. Pause primeiro, investigue, então decida.
|
|
39
|
+
- **Toda code branch = atributo** — `if (x) { ... } else { ... }` precisa emitir atributo de qual branch foi tomada (`branch_taken: 'fast_path'` vs `'slow_path'`).
|
|
40
|
+
- **Tighten do feedback loop é o objetivo** — minutos do commit ao prod, não dias. Cada hora de delay multiplica custo de debug.
|
|
41
|
+
|
|
42
|
+
## Patterns canônicos
|
|
43
|
+
|
|
44
|
+
### Pattern: feature instrumentada nasce ODD-compliant
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// PT-BR: feature nova "novo método de pagamento" — instrumentação BUNDLED
|
|
48
|
+
import { trace, SpanStatusCode } from '@opentelemetry/api'
|
|
49
|
+
|
|
50
|
+
const tracer = trace.getTracer('payments')
|
|
51
|
+
|
|
52
|
+
export async function processPaymentV2(req: PaymentRequest) {
|
|
53
|
+
return tracer.startActiveSpan('process_payment_v2', async (span) => {
|
|
54
|
+
// PT-BR: Pergunta 3 — quem está usando?
|
|
55
|
+
span.setAttribute('user.id', req.user.id)
|
|
56
|
+
span.setAttribute('customer.tier', req.user.tier)
|
|
57
|
+
span.setAttribute('tenant_id', req.user.tenant)
|
|
58
|
+
span.setAttribute('endpoint', '/api/v2/payments')
|
|
59
|
+
|
|
60
|
+
// PT-BR: Pergunta 2 — qual versão?
|
|
61
|
+
span.setAttribute('build_id', process.env.BUILD_ID ?? 'dev')
|
|
62
|
+
span.setAttribute('feature_flag.payments_v2', true) // PT-BR: assumed via flag
|
|
63
|
+
span.setAttribute('payment.method', req.method) // novo: 'pix' | 'crypto' | 'card'
|
|
64
|
+
|
|
65
|
+
// PT-BR: Pergunta 4 — atributo por branch
|
|
66
|
+
if (req.amount > 1_000_00) {
|
|
67
|
+
span.setAttribute('branch_taken', 'high_value')
|
|
68
|
+
span.setAttribute('requires_3ds', true)
|
|
69
|
+
} else {
|
|
70
|
+
span.setAttribute('branch_taken', 'standard')
|
|
71
|
+
span.setAttribute('requires_3ds', false)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const result = await chargeProvider(req)
|
|
76
|
+
|
|
77
|
+
// PT-BR: Pergunta 1 — fez o que esperei?
|
|
78
|
+
span.setAttribute('result.success', true)
|
|
79
|
+
span.setAttribute('payment.id', result.id)
|
|
80
|
+
span.setAttribute('payment.processor_response', result.processorCode)
|
|
81
|
+
span.setStatus({ code: SpanStatusCode.OK })
|
|
82
|
+
return result
|
|
83
|
+
} catch (e) {
|
|
84
|
+
// PT-BR: Pergunta 4 — anomalia identificada com type enum
|
|
85
|
+
span.setAttribute('result.success', false)
|
|
86
|
+
span.setAttribute('error.type', classify(e)) // 'provider_down' | 'declined' | 'fraud_block'
|
|
87
|
+
span.setAttribute('error.processor_code', e.code)
|
|
88
|
+
span.setStatus({ code: SpanStatusCode.ERROR })
|
|
89
|
+
throw e
|
|
90
|
+
} finally {
|
|
91
|
+
span.end()
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Pattern: auto-page autor (config CI/CD)
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
# PT-BR: GitHub Actions ou equivalente — paginar autor após merge
|
|
101
|
+
# .github/workflows/post-merge-watch.yml
|
|
102
|
+
name: post-merge-watch
|
|
103
|
+
on:
|
|
104
|
+
push:
|
|
105
|
+
branches: [main]
|
|
106
|
+
jobs:
|
|
107
|
+
page-author:
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
steps:
|
|
110
|
+
- name: Page commit author for 30-60min
|
|
111
|
+
run: |
|
|
112
|
+
AUTHOR_EMAIL="${{ github.event.head_commit.author.email }}"
|
|
113
|
+
PAGER_TOKEN="${{ secrets.PAGERDUTY_TOKEN }}"
|
|
114
|
+
# PT-BR: criar policy temporária — alertas SLO route para AUTHOR_EMAIL
|
|
115
|
+
# por 45 minutos. Após, retorna ao on-call normal.
|
|
116
|
+
curl -X POST https://api.pagerduty.com/oncall_overrides \
|
|
117
|
+
-H "Authorization: Token token=$PAGER_TOKEN" \
|
|
118
|
+
-d "{
|
|
119
|
+
\"override\": {
|
|
120
|
+
\"start\": \"$(date -u +%FT%TZ)\",
|
|
121
|
+
\"end\": \"$(date -u -d '+45 minutes' +%FT%TZ)\",
|
|
122
|
+
\"user\": {\"email\": \"$AUTHOR_EMAIL\"}
|
|
123
|
+
}
|
|
124
|
+
}"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Pattern: deploy ≠ release (feature flag)
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
// PT-BR: deploy do código com flag DESLIGADA
|
|
131
|
+
const isV2Enabled = (req: Request): boolean => {
|
|
132
|
+
// PT-BR: 0% inicialmente — deploy = código em prod, mas dormente
|
|
133
|
+
if (!flags.isEnabled('payments_v2', { user_id: req.user.id })) {
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
136
|
+
return true
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function processPayment(req: PaymentRequest) {
|
|
140
|
+
if (isV2Enabled(req)) {
|
|
141
|
+
return processPaymentV2(req)
|
|
142
|
+
}
|
|
143
|
+
return processPaymentV1(req)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// PT-BR: depois do deploy, release gradual:
|
|
147
|
+
// 1. flag.set('payments_v2', { user_id: 'me' }) — só dev
|
|
148
|
+
// 2. flag.set('payments_v2', { customer.tier: 'free' }, 1%) — 1% free users
|
|
149
|
+
// 3. observe SLO + error rate; se OK, sobe para 10%, 50%, 100%
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Pattern: comparar versão antes/depois (Pergunta 2)
|
|
153
|
+
|
|
154
|
+
```sql
|
|
155
|
+
-- PT-BR: SLI antes vs depois do deploy do build_id `abc123`
|
|
156
|
+
-- Mostra error_rate per build, agrupado por versão
|
|
157
|
+
select
|
|
158
|
+
build_id,
|
|
159
|
+
count(*) as total,
|
|
160
|
+
sum(case when result_success = false then 1 else 0 end) as errors,
|
|
161
|
+
100.0 * sum(case when result_success = false then 1 else 0 end) / count(*) as error_pct,
|
|
162
|
+
percentile_cont(0.99) within group (order by duration_ms) as p99_ms
|
|
163
|
+
from observability.spans
|
|
164
|
+
where
|
|
165
|
+
service_name = 'payments'
|
|
166
|
+
and timestamp > '2026-05-06 10:00'
|
|
167
|
+
and build_id in ('v1.5.2', 'v1.5.3') -- versão anterior + atual
|
|
168
|
+
group by build_id;
|
|
169
|
+
|
|
170
|
+
-- PT-BR: se v1.5.3 tem error_pct ou p99_ms > v1.5.2 → regressão. Rollback ou fix.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Pattern: instrumentação shift-left no PLAN.md de fase
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
# PLAN: Fase 42 — Novo método de pagamento
|
|
177
|
+
|
|
178
|
+
## Tarefas
|
|
179
|
+
|
|
180
|
+
| # | Task | Output |
|
|
181
|
+
|---|------|--------|
|
|
182
|
+
| 1 | Implementar `processPaymentV2` em `src/payments/v2.ts` | função |
|
|
183
|
+
| 2 | **Instrumentação OTel — bundled** | spans + atributos |
|
|
184
|
+
| 3 | Adicionar feature flag `payments_v2` | flag config |
|
|
185
|
+
| 4 | Tests unitários | tests/v2.spec.ts |
|
|
186
|
+
| 5 | **ODD — 4 perguntas validadas** | comments no PR |
|
|
187
|
+
|
|
188
|
+
## ODD — Validação das 4 perguntas
|
|
189
|
+
|
|
190
|
+
1. **Faz o que esperei?**
|
|
191
|
+
- Span `process_payment_v2` com atributo `result.success`
|
|
192
|
+
- Query: `SELECT count(*) WHERE result_success=true / count(*)` deve ser ≥ 99% após release
|
|
193
|
+
|
|
194
|
+
2. **Compara à versão anterior?**
|
|
195
|
+
- `build_id` em todo span permite cross-version
|
|
196
|
+
- Query: ver "Pattern: comparar versão" acima
|
|
197
|
+
|
|
198
|
+
3. **Usuários estão usando?**
|
|
199
|
+
- `customer.tier`, `payment.method` permitem slice & dice
|
|
200
|
+
- Query: `SELECT customer.tier, payment.method, count(*) FROM ... WHERE feature_flag.payments_v2=true GROUP BY 1,2`
|
|
201
|
+
|
|
202
|
+
4. **Anomalias emergem?**
|
|
203
|
+
- `error.type` enum: `'provider_down'`, `'declined'`, `'fraud_block'`
|
|
204
|
+
- `branch_taken` para code paths
|
|
205
|
+
- Alert: SLO burn rate > 2 sobre `WHERE feature_flag.payments_v2=true`
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Anti-patterns
|
|
209
|
+
|
|
210
|
+
### ANTI: instrumentação como fase separada
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
ANTI: "Vamos shipá-la primeiro, instrumentar na próxima sprint."
|
|
214
|
+
|
|
215
|
+
PROBLEMA: você está em prod cego. Quando algo quebrar, você não tem dados para
|
|
216
|
+
investigar. Adicionar instrumentação depois requer redeploy, que é
|
|
217
|
+
arriscado durante incident.
|
|
218
|
+
|
|
219
|
+
CERTO: instrumentação NO MESMO PR da feature. Não-negociável.
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### ANTI: glass castle (medo de mexer em prod)
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
ANTI: "Não deploy hoje, é véspera de feriado."
|
|
226
|
+
"Não deploy depois das 17h."
|
|
227
|
+
"Vamos esperar a próxima janela de manutenção."
|
|
228
|
+
(Equipe deploya 1× por semana, em batches grandes)
|
|
229
|
+
|
|
230
|
+
PROBLEMA: deploys raros = deploys grandes = mais código mudando = mais risco.
|
|
231
|
+
Cada deploy fica mais perigoso por sua raridade. Cycle vicioso.
|
|
232
|
+
|
|
233
|
+
CERTO: deploy frequente (várias vezes ao dia) com features pequenas atrás de flags.
|
|
234
|
+
Cada deploy quase nada. Reverter quase nada se quebra. Confiança aumenta.
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### ANTI: rollback antes de investigar
|
|
238
|
+
|
|
239
|
+
```text
|
|
240
|
+
ANTI: alerta dispara → rollback automático → "voltou ao normal" → ninguém
|
|
241
|
+
investiga porque "tá funcionando agora"
|
|
242
|
+
|
|
243
|
+
PROBLEMA: você perdeu a evidência. Próximo incident similar começa do zero.
|
|
244
|
+
Padrão de regressão acumula tech debt invisível.
|
|
245
|
+
|
|
246
|
+
CERTO: pause feature flag (não rollback do deploy) → investigue com observability →
|
|
247
|
+
fix root cause → re-release. Rollback só se investigation tomar > 30min.
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### ANTI: testar com 100% rollout em horário de baixa
|
|
251
|
+
|
|
252
|
+
```text
|
|
253
|
+
ANTI: "Faz deploy 4h da manhã quando ninguém usa."
|
|
254
|
+
|
|
255
|
+
PROBLEMA: você está rodando com 100% de risk em condições não-realistas.
|
|
256
|
+
0 tráfego = 0 sinal. Quando bug aparecer no horário de pico, você
|
|
257
|
+
não terá dados.
|
|
258
|
+
|
|
259
|
+
CERTO: deploy a qualquer hora atrás de feature flag em 1% → observe → 10% → 100%.
|
|
260
|
+
Bugs aparecem no progressive rollout, não no horário de pico.
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### ANTI: paginar on-call em vez do autor
|
|
264
|
+
|
|
265
|
+
```text
|
|
266
|
+
ANTI: alerta dispara 2h após merge → on-call (que não escreveu o código) é paginado
|
|
267
|
+
|
|
268
|
+
PROBLEMA: on-call não tem contexto. Vai procurar "que mudou ultimamente" — toma 30min.
|
|
269
|
+
Autor está dormindo / fora do contexto. Feedback loop quebrado.
|
|
270
|
+
|
|
271
|
+
CERTO: por 30-60min após merge, alertas vão para o AUTOR. Ele tem o contexto fresco,
|
|
272
|
+
sabe o que mudou, pode reverter ou fix em 5min. Após janela, volta para on-call.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### ANTI: instrumentação só em happy path
|
|
276
|
+
|
|
277
|
+
```text
|
|
278
|
+
ANTI: span com atributos só no `try` block; catch sem instrumentação
|
|
279
|
+
|
|
280
|
+
PROBLEMA: você não sabe nada sobre falhas. Pergunta 4 (anomalias) impossível de responder.
|
|
281
|
+
|
|
282
|
+
CERTO: cada `catch` adiciona `error.type` enum + `error.message` + `result.success=false`.
|
|
283
|
+
Cada early return adiciona `branch_taken: 'short_circuit_validation'` etc.
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Verificação
|
|
287
|
+
|
|
288
|
+
Antes de mergear PR, verificar as 4 perguntas:
|
|
289
|
+
|
|
290
|
+
| # | Pergunta | Validação |
|
|
291
|
+
|---|----------|-----------|
|
|
292
|
+
| 1 | **Faz o que esperei?** | Existe atributo `result.success` em algum span do código tocado? |
|
|
293
|
+
| 2 | **Compara à versão anterior?** | `build_id` é setado no span? (geralmente em SDK setup, validar uma vez) |
|
|
294
|
+
| 3 | **Usuários estão usando?** | Existe `user.id` ou `tenant_id` ou `customer.tier` no span? |
|
|
295
|
+
| 4 | **Anomalias emergem?** | `catch` blocks emitem `error.type` enum? branches if/else emitem `branch_taken`? |
|
|
296
|
+
|
|
297
|
+
Se qualquer pergunta = NÃO → PR não mergeable. Adicione instrumentação.
|
|
298
|
+
|
|
299
|
+
Após merge:
|
|
300
|
+
- ✅ Feature flag desligada por default? (deploy ≠ release)
|
|
301
|
+
- ✅ Auto-page do autor configurado por 30-60min?
|
|
302
|
+
- ✅ SLI/SLO baseline sabido para comparação pré/pós release?
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Ver também
|
|
307
|
+
|
|
308
|
+
- `kit/skills/_shared-observability/glossary.md` — termos canônicos, ODD, glass castle
|
|
309
|
+
- `kit/skills/structured-events/SKILL.md` — campos canônicos
|
|
310
|
+
- `kit/skills/distributed-tracing/SKILL.md` — instrumentação cross-service
|
|
311
|
+
- `kit/skills/event-based-slos/SKILL.md` *(Phase 32)* — SLI para baseline pré/pós release
|
|
312
|
+
- `kit/agents/observability-instrumenter.md` — agente que gera instrumentação
|
|
313
|
+
- `kit/commands/instrumentar-fase.md` — comando que aplica ODD em fases
|
|
314
|
+
|
|
315
|
+
*Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 11: "Observability-Driven Development".*
|