Pular para conteúdo

workflow scout-log — monitoração de produção

Todo dia, um sistema de agentes olha produção sozinho e entrega uma mensagem: o que está quebrado, o que subiu e está de pé, se os parceiros respondem e se os agentes de IA estão atendendo. Esta página é a documentação do workflow — as seis fases, o que cada uma entrega e o que sai no fim. Quem o dispara está em rotinas.

O desenho abaixo é a fonte visual; o resto da página explica cada peça dele.

Diagrama do sistema de monitoração de produção: a rotina scout-log dispara o workflow de
varredura, que grava a leitura do dia; quatro leituras dessa leitura rodam em paralelo — três
lentes e a triagem, que cria a issue no In-box — e o attention-gate fecha com uma mensagem
única

Clique no diagrama para a versão interativa (scout-log.html): tema claro/escuro, pan/zoom, busca, três views guiadas e export PNG/SVG.

A fonte é o JSON, não o desenho. Os dois arquivos acima são derivados de docs/agents/monitoring-flow.architecture.json. Mudou o sistema? Edite o JSON e rode archify deliver + o extrator do SVG — nunca edite o .svg nem o .html à mão, porque a próxima geração sobrescreve.

O grafo de agentes

O desenho acima é o sistema (quem é rotina, quem é skill, quem é status). Este é o grafo de agentes: quem o workflow realmente spawna, em que padrão, e com qual modelo.

Grafo de agentes do scout-log: coleta em pipeline com um agente por fonte de log, caracterização
em paralelo por cluster, a leitura do dia no mem0, as quatro leituras num parallel() só, e um único
juiz Opus no fim, seguido da faxina

O padrão é fanout-and-synthesize: coleta em pipeline, uma barreira, um juiz no fim.

Fase Agentes Modelo
Varrer varre:<fonte> — 1 por fonte, em pipeline haiku / low
Caracterizar caracteriza:<cluster> — parallel dentro do pipeline sonnet / high
Leitura grava a leitura do dia no mem0 haiku / medium
Lentes as 4 no mesmo parallel() haiku, 2× sonnet
Digest gate:digest-unico — o juiz opus / medium
Faxina faxina:backlog haiku / medium

Duas leituras que o desenho deixa óbvias:

  • O único Opus é o juiz — uma chamada, não N. É a régua modelo-effort aplicada: em fan-out a inteligência se paga em quem consolida, não em quem coleta.
  • Caracterizar é sonnet mesmo sendo etapa de volume, porque é onde um cluster errado contamina as quatro leituras seguintes.

Cada agent() carrega model/effort explícitos no código do workflow. Num pipeline() de 40 itens, omitir roda 40 chamadas no degrau da sessão — que hoje é o Opus.

As seis fases

# Fase Entrega Modelo
1 Varrer um subagente por fonte (Railway · Sentry · PostHog · telemetria) + a cobertura haiku/low
2 Caracterizar tipo, volume, P sugerido, deploy correlacionado — sem diagnóstico sonnet/high
3 Leitura a leitura do dia (log_sweep) no mem0, organizada por domínio haiku/medium
4 Lentes quatro leituras da mesma leitura, em paralelo: entregas · parceiros · agentes de IA · triagem (as issues no In-box) haiku×2 + sonnet×2
5 Digest UMA mensagem: Slack + e-mail pela urgência opus/medium
6 Faxina issue de bug cujo erro morreu há ≥14 dias → Canceled haiku/medium

A ordem é a cadeia de dependência real: ler → organizar → (interpretar ‖ registrar) → comunicar. Cada fase existe porque a anterior entregou algo que ela não produziria sozinha — e onde não existe dependência, também não existe fase separada: é o caso da fase 4.

Um workflow, não dois. Já foram dois (scout-log chamando monitoring), e custava caro: workflow() não aninha dois níveis, então as lentes ficavam impedidas de ter fan-out interno (um agente por provider, um por card em quarentena). Num workflow só isso volta a ser possível — e some a classe de bug em que o encadeamento falha e metade da rotina não roda sem ninguém notar.

As três camadas (e por que o nome se repete)

scout-log nomeia três coisas diferentes, e confundi-las é a fonte de erro mais comum aqui:

Camada O que é Onde vive
rotina o agendamento — dispara todo dia às 21h rotina de nuvem do Claude, a única ativa do comitê
workflow a orquestração — fan-out por fonte, diagnóstico, gravação, encadeamento .claude/workflows/scout-log.js
skill a lógica — o que varrer, como atribuir, o que gravar .claude/skills/scout-log/SKILL.md

A rotina é a casca mais fina: só manda executar. Quem sabe como é a skill; quem sabe em que ordem e com quantos agentes é o workflow. No desenho, a rotina aparece fora dos dois boundaries justamente por isso.

Fase 1–3 — varrer, caracterizar, organizar

Uma rotina só, e ela começa lendo log no escuro: sem saber o que procurar. É a única peça do sistema com essa pergunta aberta — tem algo quebrado que ninguém viu ainda?

Fontes que ele cobre:

  • Sentry — 3 projetos (crm, api, agents), sempre environment:production, janela 24h
  • PostHog — console log do front que não virou exceção, saúde de telemetria e o ledger de lançamentos (as annotations que dizem quando cada PR subiu)
  • Railway — deployments por serviço (o que está SERVINDO é o último SUCCESS), logs de runtime, o app do cliente e o Redis de produção
  • git do checkout — pra cruzar erro ↔ arquivo ↔ commit culpado

O app do cliente e o Redis entram por um motivo específico: fila crescendo sem worker, chave estourando memória e conexão recusada não viram exceção no Sentry. Existem só no estado, e quebra no app do cliente é sentida por quem está do outro lado, não pelo time.

O produto dele não é o achado — é a organização do achado. Cada cluster de erro sai etiquetado com um domínio:

Domínio Como é atribuído Confiança
agent:ju · agent:abel · agent:infra tag agent do Sentry (o app taggeia) alta
provider:<nome> culprit / módulo / mensagem média — os adapters não taggeiam provider
nosso:<app>/<área> culprit + git log do arquivo média
nao_atribuido não deu

Confiança baixa não delega. Erro entregue ao dono errado é pior que erro sem dono: o dono errado não reconhece e o certo nunca vê.

Isso vira a leitura do dia (log_sweep, no mem0) — com os clusters, a atribuição e a cobertura (o que deu pra ler de verdade). A cobertura existe pra ninguém confundir checou e não achou nada com não conseguiu checar: dia verde também gera leitura, com clusters: [] e a cobertura preenchida.

Fase 4 — as quatro leituras da mesma leitura

Com a leitura gravada, quatro agentes partem dela em paralelo. Estão no mesmo nível e nenhum consome o produto do outro — o que muda entre eles é a pergunta:

Quem Pergunta Evidência exclusiva Escreve em
ci-monitoring as entregas que subiram estão de pé? a coluna Monitoring do Linear (a lista de quarentena) Monitoring (é dona)
providers-monitoring os parceiros estão de pé? select no Supabase de prod: mandato criado, parcela processada nada — só digest
monitoring-agents a Ju e o Abel estão atendendo? funil, messages por role, link de Open Finance enviado nada — só digest
triagem o que aqui merece issue? o board (dedup, incluindo Canceled/Done) In-box — é a única porta

A ci-monitoring é a única com dois movimentos, e a ordem importa: do board sai o que olhar; da leitura, o que aconteceu. Ela puxa a lista de quarentena e só então volta à leitura pra julgar a saúde dos últimos commits daquelas entregas.

Por que a triagem está aqui e não numa fase depois

Porque ela não consome o parecer das lentes. O insumo dela é o cluster de erro, que já existe quando a fase começa — numa fase própria ela ficaria esperando a lente mais lenta pra ler exatamente o mesmo dado. E o que ela precisa pra dedupar não está no parecer de ninguém: está no board.

A consequência, dita por inteiro: o achado que só a lente vê — funil travado sem exceção no log, provider mudo, soak inconclusivo — não passa pela triagem e não vira card automaticamente. Ele tem dois destinos honestos:

  1. a ci-monitoring comenta no card de quarentena (é dona da coluna);
  2. o resto vira o bloco "sem card — decidir" no digest, onde o humano escolhe.

O alternativo seria a triagem abrir card a partir de parecer que ela não pode conferir — e é aí que nasce issue que ninguém consegue fechar. Corolário prático: quem julga o que exige baseline são as lentes, então a triagem não transforma em issue volume que só é anômalo contra um baseline (empty_response, blip de fallback do Vertex). Cluster agent:* vira issue quando é exceção dura — ai_fallback_total_failure, vertex_conta_billing.

Duas regras que separam parecer honesto de relatório inútil:

  • Mudo nunca vira ✅. Sem evidência positiva de uso, o status é ⚪ "não sei". Provider e agente que caem por completo também produzem zero erro.
  • Um agente de IA pode estar de pé e inútil. Respondendo tudo, Sentry limpo, e nenhum lead chegando no fim do funil — daí o status 🟠 respondendo mal, que só existe porque o monitoring-agents olha dois eixos (está de pé × faz o trabalho). Varredura de log nunca acha isso, porque não há exceção pra achar.

A triagem: constata, e quem abre a issue é ela

Dois recortes deliberados definem o escopo desta rotina:

Ninguém aqui investiga. Nenhuma das quatro skills roda diagnosing-bugs nem persegue causa raiz. O que elas entregam é evidência: qual erro, qual volume, desde quando, de qual domínio, e o que subiu junto (correlação com deploy — correlação, não causa). Investigar exige ler código, reproduzir e às vezes inspecionar estado ao vivo; num run diário isso estoura o orçamento ou entrega diagnóstico raso, que é pior que nenhum porque parece pronto.

A skill triagem é a única porta de issue, e sempre em In-box com tag Bug. Ela decide o que entra, consolida clusters de mesma causa numa issue só, e carimba tag, prioridade (priorize) e esforço (estimate). As lentes também marcam tipo (bug / melhoria / saude) e sugerem o P — mas isso alimenta o digest, não a triagem. Achado saude (verde, mudo, tendência) não vira issue de jeito nenhum.

O attention-gate não cria mais issue: ele organiza e comunica. A separação é por natureza do trabalho — classificar e registrar (triagem) é diferente de decidir interromper (gate), e juntar os dois fazia a régua de board contaminar a régua de atenção.

Vai pra In-box e não pra To scout/Reach por coerência: aquelas colunas pressupõem alguém investigando ou causa raiz fechada, e aqui ninguém investigou. O efeito colateral é útil — o In-box passa a mostrar o tamanho real da fila de bug de produção.

Duas exceções:

  • A ci-monitoring comenta e move card dentro da coluna Monitoring — é dona dela, e isso é acompanhar soak, não abrir bug novo.
  • A providers-monitoring nunca gera issue, em nenhuma hipótese: todo achado dela é tipo: saude, porque ela é notificação diária de estado. Provider de terceiro quebrado não tem fix nosso, e issue que ninguém pode fechar envelhece no board. Quando o problema é no nosso adapter, ele aparece como exceção no log e chega pelo scout-log como cluster provider:* — é por ali que vira issue. São dois sinais diferentes: o estado da integração e a exceção no nosso código.

O dedup é da triagem, e é a única rede que existe: sendo porta única, é a busca dela antes de criar que impede duplicata — incluindo Canceled/Done, porque erro cancelado que voltou reabre o card antigo em vez de gerar outro.

Os status do Linear são parte do sistema

O board não é onde o resultado é anotado depois — é estado, e cada status tem um dono. É por isso que eles aparecem como caixas próprias no desenho, com o tipo status Linear:

Status Significado Dono da escrita
In-box constatado, não investigado — a fila real de bug de produção triagem (cria) · Faxina (cancela)
Monitoring quarentena pós-merge, em soak de 14 dias ci-monitoring
To scout alguém decidiu que vale investigar o humano
Reach causa raiz fechada, aguardando plano investigate-bug
Canceled julgado morto uma vez — memória, não lixo Faxina

O In-box só diz a verdade sobre o tamanho da fila porque nada além da triagem escreve nele e porque a Faxina limpa o outro lado. Escrever na coluna de outro é o mesmo tipo de erro que sobrescrever memória de outro prefixo no mem0.

Fase 5 — uma mensagem (attention-gate)

Nenhuma das quatro manda Slack, e-mail ou push. Cada uma devolve o seu produto, e o attention-gate consolida tudo — varredura + três pareceres + as issues criadas + o bloco "sem card — decidir" — em um digest único, decidindo o canal por prioridade (P0 → push + Slack + e-mail · P1 → push + Slack · P2 → só o digest).

Isso é o ponto de existir um Gate. Quatro remetentes disparando no mesmo horário é pior que ruído solto: o mesmo incidente chega em duas mensagens com prioridades diferentes e quem lê precisa reconciliar na cabeça.

O encadeamento completo

rotina scout-log (nuvem, 21h)
   └─► workflow scout-log
         1. varrer        fan-out: um subagente Haiku por fonte
         2. caracterizar  tipo, volume, P sugerido, deploy correlacionado   (Sonnet)
         3. leitura       grava log_sweep + cobertura
         4. lentes        as QUATRO leituras da mesma leitura, em paralelo:
                            ci-monitoring · providers-monitoring · monitoring-agents
                            triagem  → cria as issues no In-box (a única porta)
         5. digest        attention-gate organiza e comunica → UMA mensagem
         6. faxina        cancela issue cujo erro morreu há ≥14 dias

Por que uma rotina e não quatro (o desenho anterior tinha quatro, às 8h/19h/20h/21h):

  • A leitura fresca deixou de ser aposta — era de 11h antes; agora tem minutos.
  • A ordem deixou de ser convenção — as fases garantem produtor → consumidores, em vez de depender de quem foi agendado mais cedo.
  • Uma falha, um lugar — se a varredura quebra, as lentes rodam em modo estreito e declaram que rodaram sem base; lente que não devolve parecer vira achado P2 no digest ("monitoração cega neste domínio"). Dia sem monitoração se parece com dia sem problema, e é o silêncio que engana.

O modelo de cada peça segue a matriz inteligência × volume da régua modelo-effort: varrer é volume mecânico (Haiku), o parecer dos agentes exige baseline e julgamento (Sonnet), e o digest decide o que interrompe uma pessoa (Opus). Em fan-out, a inteligência se paga no juiz, não nos coletores.

Memória — cada um no seu namespace

As quatro compartilham o mesmo escopo no mem0, então o que as separa é o metadata.type mais um prefixo de domínio na primeira linha:

Tipo Quem escreve Conteúdo
log_sweep scout-log a leitura do dia
provider_health providers-monitoring uma memória por provider: números + baseline
agent_health monitoring-agents uma por agente (ju, abel, infra) + baseline do funil

Só atualize memória cujo prefixo é do seu domínio — memória de outro prefixo é leitura, nunca update/delete. Baseline é uma memória por assunto, atualizada no lugar: duas memórias do mesmo baseline fazem a tendência de amanhã ser calculada contra o número errado.

Estado hoje

  • A rotina de nuvem scout-log — varredura geral de produção (todo dia 21h) é a única ativa. As demais rotinas do comitê estão pausadas durante a reconstrução do harness.
  • As rotinas de nuvem providers-monitoring (8h) e ci-monitoring (20h) ficaram redundantes com o encadeamento e seguem pausadas.
  • Checagem pendente: o prompt da rotina precisa invocar o workflow scout-log. Se invocar a skill direto, o encadeamento pro monitoring não acontece — a chamada workflow('monitoring') vive no .js, não na skill.

O contrato completo, que é autoridade sobre as quatro skills, está em docs/agents/monitoring-contract.md.