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.
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 rodearchify deliver+ o extrator do SVG — nunca edite o.svgnem 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.
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() |
2× 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-effortaplicada: em fan-out a inteligência se paga em quem consolida, não em quem coleta. - Caracterizar é
sonnetmesmo sendo etapa de volume, porque é onde um cluster errado contamina as quatro leituras seguintes.
Cada
agent()carregamodel/effortexplícitos no código do workflow. Numpipeline()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), sempreenvironment: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 gitdo 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:
- a
ci-monitoringcomenta no card de quarentena (é dona da coluna); - 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-agentsolha 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-monitoringcomenta e move card dentro da colunaMonitoring— é dona dela, e isso é acompanhar soak, não abrir bug novo. - A
providers-monitoringnunca 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 peloscout-logcomo clusterprovider:*— é 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 |
só scout-log |
a leitura do dia |
provider_health |
só providers-monitoring |
uma memória por provider: números + baseline |
agent_health |
só 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) eci-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 promonitoringnão acontece — a chamadaworkflow('monitoring')vive no.js, não na skill.
O contrato completo, que é autoridade sobre as quatro skills, está em
docs/agents/monitoring-contract.md.