Runbook operacional

Uma porta só, porque às 3h da manhã ninguém quer procurar em qual arquivo está o procedimento: a triagem é a primeira coisa, e cada linha leva direto a ele. Os procedimentos moram em runbook/*.md, cortados por tema. Comece pela triagem. O que prova cada procedimento, e o que roda essa prova, está na tabela do fim: Procedimentos e como cada um é verificado.

Triagem — do sintoma ao procedimento

o que você está vendo vá para
quero subir tudo do zero Deploy local
pods presos, ExternalSecret nunca Ready, HPA em <unknown> Diagnóstico do deploy
vou fazer rollout do engine Rollout do engine
sessão active sem processo, ou presa em closing Quando a sessão escapa
perdi dados / quero verificar o backup Restore
quero verificar ou restaurar um backup numa instalação sem cluster Restore — make test-restore-compose
um projeto do provider local perdeu o repositório, ou estou levando uma instalação para outra máquina Recuperando os bare repos
o grafo está vazio depois de um restore ou de uma migração Perda do grafo — grafo:reprojetar
a pasta docs/ de um projeto (os artefatos dos agentes) sumiu depois de um restore, de uma perda de volume ou de uma conversão de modo Perda da pasta de artefatos — artefatos:reprojetar
credencial de LLM ou de git parou de decifrar Rotação da chave mestra
todo mundo deslogado de uma vez, ou conta bloqueada no login Rotação das chaves do auth
o custo por hora disparou Incidente de custo
painel vazio, sem trace, sem log Observabilidade
não sei que versão está rodando Que versão está no ar
blocked by CORS policy no console do navegador Erro de CORS
ativar uma sessão não faz nada, ou transition devolve 500 com ECONNREFUSED A sessão não sai de created
a api sai no boot reclamando de GIT_OAUTH_STATE_SECRET A api recusa subir por segredo de OAuth
"Entrar com GitHub/GitLab" volta do provider com erro de redirect_uri O provider recusa o callback do login social
a api ou o engine saem no boot reclamando de AUTH_JWT_SECRET, BRABO_SERVICE_TOKEN, CREDENTIALS_MASTER_KEY, SECRET_KEY_BASE, ou NEO4J_URI/NEO4J_USER/NEO4J_PASSWORD Os quatro segredos irmãos também não sobem com o default
quero ligar SMTP real, ou a api sai no boot reclamando de SMTP_HOST/SMTP_USER/SMTP_PASSWORD/SMTP_FROM SMTP real no MailSender
agente respondendo vazio, truncado ou muito devagar Ambiente de inferência
agente parando com iteration limit reached sem entregar Ambiente de inferência
quero acrescentar um provider de LLM compatível com OpenAI Acrescentando um provider compatível
quero migrar meus workspaces do volume do Docker para uma pasta de verdade Migrar workspaces para pasta local
o assistente de projeto não oferece o modo Pasta montada, ou criar um projeto montado é recusado dizendo que o caminho tem de ficar dentro da base Projeto no modo Pasta montada: a base de projetos
aprovar container_start num projeto montado falha dizendo que a api não conseguiu criar ou alcançar a pasta Projeto no modo Pasta montada: a base de projetos
make dev recusa subir, dizendo que BRABO_PROJECTS_BASE se sobrepõe ao checkout do Brabo Projeto no modo Pasta montada: a base de projetos
brabo-runner sai com base de projetos recusada, ou imprime base de projetos: nenhuma configurada quando eu esperava uma base A base de projetos do runner
brabo-runner fica imprimindo nada a atender AINDA, ou a unit de máquina está de pé mas nenhum projeto é atendido O agente de máquina
systemctl --user status diz Loaded: bad-setting / WorkingDirectory= path is not absolute, e o serviço do agente nunca inicia A unit está bad-setting
preciso de uma chave de dispositivo para a máquina e não há navegador (uma instalação nova, uma máquina sem tela) Chave de dispositivo pelo terminal
o instalador terminou com um bloco "O que ficou pendente", ou uma instalação nova não tem conta, nem chave de máquina, nem serviço do agente Quando o instalador não fecha a instalação
a pasta do projeto nunca aparece na máquina do usuário, e o log do engine diz workspace_create: o projeto <id> não criou pasta A pasta do projeto nunca aparece
um dev agent num projeto runner fica bloqueado preparando o worktree, nomeando credencial-nao-atravessa-o-container, com origem politica Clone autenticado no modo Runner
apps/api/dist/node_modules, ou um arquivo que um agente escreveu numa pasta de projeto, pertence a root e não consigo editar sem sudo Os containers de dev escrevem como o seu usuário, não como root
quero subir o broker de containers, ou ele responde permission denied no socket do Docker O broker de containers
provisionar um repositório falha com permission denied: /data/git-repos/<slug>.git, ou o permissions.json não pode ser escrito Os containers de dev escrevem como o seu usuário, não como root
quero apagar o banco de dev e começar de novo, ou o reset-total.sh parou no meio Reset total do ambiente de dev
o web mostra 429 (rate limit) sem motivo aparente, ou um projeto em modo runner parece "sem agente local" enquanto o brabo-runner está rodando O runner inunda a api com um ticket morto

Duas coisas que vale saber antes de qualquer procedimento:

  • Silêncio não é saúde. As regras de alerta moram no Grafana, não no Prometheus (ADR 0026): Grafana fora do ar quer dizer nenhum aviso, não nenhum problema.
  • Matar o pod não fecha uma sessão. kubectl delete pod sem drenar cria um órfão. O caminho é sempre a transição normal.

Procedimentos e como cada um é verificado

Todo procedimento de operação desta página, com o arquivo que o prova e o que roda essa prova. Seções de diagnóstico (o que fazer quando algo parece errado) e as seções do ambiente de desenvolvimento não estão aqui: são jeitos de achar uma causa, não procedimentos que podem passar ou reprovar.

  • verification nomeia o spec, script, workflow ou alvo make que prova o procedimento, ou começa com None e diz isso. Uma prova parcial nomeia o que cobre e o que não cobre.
  • schedule diz o que o roda sem ninguém lembrar: um workflow agendado (weekly), todo pull request (every PR), toda tag final (every tag), ou manual — alguém tem de lembrar.

Os cabeçalhos da tabela e as palavras de classe da coluna schedule ficam em inglês de propósito: são vocabulário de máquina, que o pnpm docs:check lê. Ele lê esta tabela e reprova quando um arquivo em verification não está no repositório, um alvo make não está no Makefile, uma célula está vazia ou diz "ver abaixo", uma âncora não é cabeçalho desta página, ou um workflow em schedule não tem o gatilho que a célula afirma (schedule: para weekly, pull_request para every PR, push: tags para every tag). Como funciona está em Como a documentação continua viva.

procedure anchor verification schedule
Subir a stack num cluster local Deploy local make deploy-local termina com make smoke-k8s (deploy/k8s/smoke.sh); a execução agendada faz o mesmo deploy/k8s/bootstrap.sh e smoke weekly .github/workflows/propriedades.yml
Validar uma tag da esteira (TAG=) Validar uma tag da esteira None. Nenhum workflow passa TAG=; o checkout destacado da tag só roda à mão manual
Provar que o HPA do engine escala Deploy local make hpa-test (deploy/k8s/hpa-test.sh) weekly .github/workflows/propriedades.yml
Validar os overlays sem cluster Deploy local make k8s-validate (deploy/k8s/validate.sh) every PR .github/workflows/ci.yml
Fazer deploy das imagens de uma release Fazendo deploy das imagens de uma release scripts/ci/aplicar-imagens.spec.ts prova a leitura do manifesto da release, scripts/ci/images-manifest.spec.ts os digests entregues ao kustomize; rodá-lo no overlay e aplicar os digests de uma release real: nenhuma every PR .github/workflows/ci.yml (o spec); manual (a corrente)
Fazer rollout do engine Rollout do engine make rollout-test (deploy/k8s/rollout-test.sh); os coletores de evidência dele por scripts/ci/rollout-evidencia.spec.ts weekly .github/workflows/propriedades.yml; every PR .github/workflows/ci.yml (os coletores)
Aumentar a janela de drain Aumentar a janela de drain None própria. make rollout-test prova só o par do overlay local (drain de 20 s, grace de 90 s); rode-o de novo com os valores aumentados manual
Fallback para sealed-secrets Segredos: fallback para sealed-secrets None. Nada roda kubeseal; o cluster agendado usa External Secrets manual
Verificar um backup no Kubernetes O caminho automatizado make test-restore (deploy/k8s/test-restore.sh) e a quebra deliberada make test-restore-mutacao weekly .github/workflows/propriedades.yml
Verificar um backup numa instalação compose O caminho automatizado make test-restore-compose (docker/backup/test-restore-compose.sh); o repasse do .env dele por scripts/dev/prova-de-restauracao-env.spec.ts weekly .github/workflows/propriedades.yml, job restore-compose (a prova); every PR .github/workflows/ci.yml (o spec)
Restaurar de verdade durante um incidente Restaurando de verdade passos 1–2: make test-restore (o mesmo brabo-restore, as mesmas consultas do docker/backup/restore.sh); passo 3, promover DATABASE_URL: nenhuma, nunca exercitado weekly .github/workflows/propriedades.yml (passos 1–2); manual (passo 3)
Verificar e recuperar os bare repos Recuperando os bare repos scripts/ci/backup-lib.spec.ts (as funções); make test-restore-compose (o comando que verifica, na imagem); --restaurar na imagem: nenhuma every PR .github/workflows/ci.yml (o spec); weekly .github/workflows/propriedades.yml, job restore-compose (o comando que verifica); manual (--restaurar)
Reprojetar o grafo Perda do grafo make test-reprojecao (apps/api/test/scripts/reprojetar-grafo.spec.ts, pulado nos PRs, que não têm Neo4j) e make test-reprojecao-k8s (deploy/k8s/test-reprojecao.sh) weekly .github/workflows/propriedades.yml
Reprojetar a pasta de artefatos Perda da pasta de artefatos apps/api/test/scripts/reprojetar-artefatos.spec.ts e make test-reprojecao-artefatos-k8s (deploy/k8s/test-reprojecao-artefatos.sh, o comando dentro da imagem da api) every PR .github/workflows/ci.yml (o spec); weekly .github/workflows/propriedades.yml (o caminho da imagem)
Rotacionar AUTH_JWT_SECRET AUTH_JWT_SECRET apps/api/test/infrastructure/security/ed25519-access-token-issuer.spec.ts e apps/api/test/application/use-cases/auth/rotacao-dos-segredos.spec.ts every PR .github/workflows/ci.yml
Trocar AUTH_TOKEN_PEPPER AUTH_TOKEN_PEPPER apps/api/test/application/use-cases/auth/rotacao-dos-segredos.spec.ts every PR .github/workflows/ci.yml
Rotacionar BRABO_SERVICE_TOKEN BRABO_SERVICE_TOKEN apps/api/test/infrastructure/security/service-token.spec.ts, apps/api/test/interfaces/engine-service.guard.spec.ts, apps/engine/test/engine_web/plugs/verify_service_token_test.exs, apps/engine/test/engine/runtime_service_token_test.exs, apps/broker/src/config.spec.ts e scripts/ci/previous-nos-composes.spec.ts every PR .github/workflows/ci.yml
Pôr e aposentar um _PREVIOUS no Kubernetes Fazendo no Kubernetes scripts/ci/previous-nos-composes.spec.ts mantém o ExternalSecret em dataFrom.extract sem _PREVIOUS em data:; o sync por um External Secrets Operator de verdade: make test-rotacao-chave-mestra-k8s (deploy/k8s/test-rotacao-chave-mestra.sh) acrescenta e remove CREDENTIALS_MASTER_KEY_PREVIOUS por ele; as outras chaves _PREVIOUS: nenhuma automatizada every PR .github/workflows/ci.yml (o spec); weekly .github/workflows/propriedades.yml (o _PREVIOUS da chave mestra); manual (as outras chaves)
Destravar uma conta por SQL Conta travada por lockout None. As duas consultas foram conferidas contra o schema por leitura; apps/api/test/application/use-cases/auth/lockout.spec.ts cobre o lockout, não elas manual
Rotacionar a chave mestra Rotação da chave mestra apps/api/test/scripts/rewrap-deks.spec.ts e apps/api/test/infrastructure/security/envelope-encryption.service.spec.ts; os três passos no cluster: make test-rotacao-chave-mestra-k8s (deploy/k8s/test-rotacao-chave-mestra.sh) every PR .github/workflows/ci.yml (os specs); weekly .github/workflows/propriedades.yml (o ensaio)
Cortar o gasto num incidente de custo Incidente de custo apps/api/test/runbook/sql-do-incidente-de-custo.spec.ts roda o SQL da seção, nos dois idiomas, contra o schema migrado; passos (b) e (d), na tela: nenhuma every PR .github/workflows/ci.yml
Subir a observabilidade sem cluster Observabilidade local scripts/dev/observabilidade-pronta.mjs, uma autoverificação no fim do o overlay de observabilidade (comando em Observabilidade local), sem spec manual
Conferir o registro de gates na imagem Registro de gates docker/smoke.sh chama as duas rotas contra a imagem de produção; as funções de gate dele por scripts/ci/smoke-gates.spec.ts every PR .github/workflows/ci.yml
Instalar Instalando .github/workflows/install-e2e.yml (máquina limpa) e scripts/dev/install*.spec.ts; o caminho de migração de ponta a ponta: nenhuma every tag .github/workflows/install-e2e.yml; every PR .github/workflows/ci.yml (os specs)
Ligar ou desligar o broker da instalação O broker de containers numa instalação na instalação: scripts/dev/install-broker.spec.ts e .github/workflows/install-e2e.yml; ligá-lo depois à mão, e desligá-lo: nenhuma every tag .github/workflows/install-e2e.yml; every PR .github/workflows/ci.yml (o spec); manual (depois, e desligar)
Ligar os modelos locais da instalação Modelos locais numa instalação na instalação: scripts/dev/install-llm.spec.ts; ligá-los depois à mão: nenhuma every PR .github/workflows/ci.yml (o spec); manual (depois)
Reinstalar do zero sobre uma instalação anterior Reinstalando do zero scripts/dev/install-llm.spec.ts every PR .github/workflows/ci.yml
Verificar um artefato publicado Verificando um artefato publicado os workflows de publicação verificam o que assinaram, na mesma execução: .github/workflows/release.yml (cosign verify) e .github/workflows/build-runner-binaries.yml (cosign verify-blob) every tag .github/workflows/release.yml .github/workflows/build-runner-binaries.yml
Conferir a oferta escrita de fonte A oferta escrita de fonte scripts/ci/oferta-de-fonte-na-imagem.spec.ts mantém cada COPY e o asset da Release; as cinco imagens construídas a partir do PR, lidas de volta pelo .github/workflows/ci.yml; os artefatos publicados levando o arquivo: nenhuma every PR .github/workflows/ci.yml (o spec e as imagens construídas); manual (os artefatos publicados)
Subir uma imagem de terceiro Subindo uma imagem de terceiro scripts/ci/imagens-pinadas.ts, scripts/ci/imagens-pinadas.spec.ts e scripts/ci/imagens-do-compose.spec.ts every PR .github/workflows/ci.yml
Acrescentar um provider de LLM compatível Acrescentando um provider compatível passos 2–4: apps/api/test/contract/llm-provider.contract.ts, rodado pelo spec de contrato de cada provider; passo 6, com credencial real: nenhuma no CI — os specs de smoke pulam sem chave every PR .github/workflows/ci.yml (passos 2–4); manual (passo 6)

Âncoras antigas

Cada âncora que já existiu nesta página continua aqui e leva à parte que hoje guarda a seção. Os links antigos não quebram.

O broker de containers
Migrar workspaces para pasta local
Projeto no modo Pasta montada: a base de projetos
A base de projetos do runner
O agente de máquina: uma conexão por projeto
A unit está bad-setting e nunca inicia
Chave de dispositivo pelo terminal
Quando o instalador não fecha a instalação
A pasta do projeto nunca aparece na máquina do usuário
Clone autenticado no modo Runner é recusado enquanto o container está de pé
Os containers de dev escrevem como o seu usuário, não como root
Reset total do ambiente de dev
Levando um ambiente de dev para brabo-dev
Ligando o acesso rápido na instalação local (TP-01)
Deploy local
Pré-requisitos
Subir
Validar uma tag da esteira
Fazendo deploy das imagens de uma release
Que versão está no ar
O gate de SecOps está preso em "SAST não rodou"
O engine aborta com sys_sigaltstack(): Internal error
Erro de CORS
A sessão não sai de created
A aba Terminal fica presa em "Abrindo terminal..." para sempre
O runner inunda a api com um ticket morto
A api recusa subir por segredo de OAuth
O provider recusa o callback do login social
Os quatro segredos irmãos também não sobem com o default
SMTP real no MailSender
k3d é o padrão mesmo com kind instalado
O que o smoke test cobre
Diagnóstico do deploy
403 no /internal/*, ou 401 nas chamadas da api para o engine
Login devolvendo 401 para todo mundo depois de um deploy
O ExternalSecret nunca fica Ready
HPA do engine em
O Job de migração não reaplica
bin/engine rpc responde eaddrinuse
Conferindo que as réplicas do engine estão em cluster
Segredos: fallback para sealed-secrets
Limites conhecidos deste ambiente
Rollout do engine
O que acontece durante um rollout, em ordem
Fazendo o rollout
Provando que nada ficou órfão
Quando a sessão escapa
Aumentar a janela de drain
Restore
O que tem backup, e o que deliberadamente não tem
Onde o backup mora
O que o arquivo dos bare repos garante — e o que não garante
Antes de restaurar: o backup existe, e presta?
O caminho automatizado (o mesmo que o teste roda)
Restaurando de verdade, durante um incidente
Restaurando numa instalação compose (banco recém-criado)
O que o restore NÃO cobre
Recuperando os bare repos
Perda do grafo (Neo4j)
Rodando uma reprojeção completa: uma janela de manutenção, sem teto de tempo
Perda da pasta de artefatos (docs/)
Quando o restore falha
Provas de propriedade agendadas
Última execução verificada
O que esta execução achou (e que o teste agora impede)
Última execução verificada — compose, destino em disco
O que esta execução achou
Rotação das chaves do auth
AUTH_JWT_SECRET — rotação sem indisponibilidade
AUTH_TOKEN_PEPPER — logout global, sem meio-termo
BRABO_SERVICE_TOKEN — rotação sem indisponibilidade, dos dois lados
Fazendo no Kubernetes
Conta travada por lockout
Rotação da chave mestra
O que está em jogo
Antes: dimensione
1. Publique as duas chaves
2. Re-embrulhe o acervo
3. Descarte a chave antiga
Verificando sem esperar um incidente
Interação com o restore
Quando algo dá errado
Incidente de custo
Sinal
1. Qual projeto, qual agente
2. Confira o orçamento
3. Corte o gasto
4. Depois
O que esta seção não conserta
Observabilidade
Observabilidade local, sem cluster
Onde as coisas estão
Acompanhando uma sessão da raiz até uma chamada de ferramenta
Quando não há trace no Tempo
Quando um painel está vazio
Quando não há log no Loki
Alertas
Limites conhecidos
Registro de gates
Ambiente de inferência
Um gate semântico num modelo pequeno
Instalando
O broker de containers numa instalação
Modelos locais numa instalação
Reinstalando do zero
Verificando um artefato publicado
Uma imagem, por digest
Os binários do runner
Quando a verificação falha
A oferta escrita de fonte, dentro de todo artefato publicado
Subindo uma imagem de terceiro
Acrescentando um provider compatível
1. Leia a doc oficial antes de escrever a primeira linha
2. Escreva a config
3. Rode a suíte de contrato contra ele
4. Registre o provider e o tipo de credencial
5. Semeie os modelos com o preço da doc
6. Verifique com uma credencial real