Auditoria Fable 05/09: síntese
Três executores Grok 4.6 (Cursor, via herdr) auditaram duas horas do orquestrador Fable no chat Bancal (worktree sl-bancada-all-in-one, épico FER-827). Esta página condensa os três relatórios, agrupa os problemas em clusters e lista os acionáveis por camada do stack de orquestração do Mac.
Janela: 2026-09-05 11:47:42Z–13:47:42Z (08:47–10:47 BRT). Veredito dos três lanes: ISSUES Fontes: timing.md, tools.md, policy.md, candidates.jsonl, verified.md, clusters.md.
1. O que foi feito
O coordenador recortou 2524 registros com carimbo de tempo de cinco arquivos jsonl do projeto (prepare.cjs, manifest.json) e despachou três workers com lanes disjuntas e 10 min de orçamento cada. Nenhum worker conseguiu autenticar o Linear MCP; a auditoria ficou só em arquivos locais até este card.
| Worker | Lane | Saída | Veredito |
|---|---|---|---|
| 1 | Cronologia, throughput, loops de espera, trabalho duplicado, caminho crítico | timing.md | ISSUES |
| 2 | Escolha de ferramenta: comandos falhos, saída grande, GUI vs API, polling, dispatch | tools.md | ISSUES |
| 3 | Arquitetura de instruções: conflitos de mandato, cerimônia, perda de memória entre handoffs | policy.md | ISSUES |
A cadeia auditada
Não são duas horas de um contexto só. São cinco sessões do mesmo chat, encadeadas por auto-clear e handoff, com menos de 4 s entre uma e outra. A vida de cada contexto encolhe: ~50 min, depois ~14, ~15 e a âncora ainda rodava quando a janela fechou.
- 65dd9aeb · 11:49–12:21Z · já rodava desde 11:43Z; termina em handoff
w5N_p1-…092014.md - 1ddd0620 · 12:21–13:11Z · 50 min; dono repete a meta da prova ao vivo duas vezes (12:26Z) e pede para não perder o pedido entre handoffs (13:08Z)
- 78d3b533 · 13:11–13:25Z · 14 min; interrupção do dono no fim
- 8aecd549 · 13:25–13:41Z · 15 min; dono reporta o watcher de auto-clear em loop (13:28Z)
- 502e904c (âncora) · 13:41Z– · cortada pela janela aos 6,5 min
2. Os números
Contagens sobre o log do orquestrador. Os panes dos executores não estão no corpus: nada aqui mede o trabalho do Grok dentro dos fer-*. Nenhum total de tokens foi calculado. Verificação independente das contagens: seção 6.
3. O stack de orquestração (as camadas que os acionáveis tocam)
orchestrate-with-linear, herdr-executors, orchestrator-contract, stay-available, handofffer-*, open-swarm-tab.sh, watch-blocked.sh, executor-hard-cut.shauto-clear-watch.sh, arquivos w5N_p1-*.md, kickoff4. Problemas em clusters
Seis clusters. Cada acionável aponta a camada do stack e o estado hoje, no arquivo em disco (checado pelo executor B em 05/09): aplicado parcial pendente. Os hooks citados nos relatórios em ~/.claude/hooks/ não existem lá; as cópias vivas estão em ~/agents-config/shared/hooks/.
C1 A cerimônia de skills depois do /clear enche a próxima janela de 200k
Achados: timing#1, policy#1, policy#3. O maior alavancador e o mais barato.
Causa raiz. Três camadas exigem "primeira resposta": os cats do SessionStart, orchestrate-with-linear tratando /clear como tópico novo, e o checklist do handoff (Ordem 1 com oito skills). grill-with-docs ainda força mais duas via PostToolUse. O sidecar que poderia pular a recarga é chaveado por session_id, e o clear gera outro. Resultado: 8 skills × 4 clears, primeira escrita no Linear só 27–39 s depois da primeira Skill, e a vida do contexto cai de 50 min para 14–16.
| Acionável | Camada / arquivo | Estado | Evidência |
|---|---|---|---|
Depois do /clear, carregar no máximo 1 skill; sem burst de 8. "Continuação não é tópico novo": mesmo label, pula o loading step, só takeover + list_issues | Skills: orchestrator-mandate.md, orchestrate-with-linear | pendente | mandate L5 ainda manda Skills-only; skill L39 "continuation is a new topic" |
Persistir skills-loaded por pane id, não por session id | Hooks: post-tool-use-skill.sh + lib.sh sidecar_dir | pendente | lib.sh L21–23: sidecar em $HOOK_SESSION_ID |
| SessionStart exclusivo por papel: sem poteto-mode quando há orchestrator-mandate | Hooks: settings.json SessionStart | pendente | L187–200 faz cat dos dois mandatos |
| Lembrete do UserPromptSubmit só no primeiro prompt da sessão (foram 96 iguais) | Hooks: settings.json UserPromptSubmit | pendente | L246–252: echo em todo submit |
| Tirar grill/gap-waves do checklist de continuação; hook de deps só quando o Next steps grila | Skills: grill-with-docs frontmatter + PostToolUse | pendente | requires: [grilling, domain-modeling] ainda dispara |
| Kickoff não pode codificar procedimento de 8 skills | Auto-clear: auto-clear-watch.sh default_kickoff, /handoff | parcial | kickoff padrão = ler handoff (L428); /handoff ainda pede "Suggested skills" (L501) |
| Watcher não reenvia o mesmo kickoff | Auto-clear: step_kickoff | aplicado | L552–556, FER-1033 |
| Handoff é snapshot, não procedimento | Skills: handoff/SKILL.md | aplicado (texto) | L37; contradito pelos handoffs vivos com Ordem 1 |
Métrica de aceite. No próximo SessionStart:clear deste chat: Skill calls até o primeiro herdr agent ou list_issues = 0 ou 1; tempo até o primeiro herdr ≤ 15 s; intervalo entre auto-clears não cai abaixo de 30 min só por cerimônia.
C2 O wait não espera; a leitura do terminal vira o sinal de status
Achados: timing#2, tools#1, mais as propostas contraintuitivas dos workers 1 e 2.
Causa raiz. O Bash manda herdr agent wait para background em menos de 5 s (34 de 36). O orquestrador nunca bloqueia no fim do executor. Nas duas primeiras sessões ele sai (away_summary, silêncio de 4–7 min); nas três seguintes ele polla: read + wait + read a 45 registros/min, o que consome a janela em 14 min. --until idle não é predicado de conclusão. O fer-81 sozinho rendeu 23–30 passos de status.
| Acionável | Camada / arquivo | Estado | Evidência |
|---|---|---|---|
Um wait --until done que bloqueia, ou notify-on-done; nunca em background | Herdr + Skills: herdr-executors | pendente | L15 manda start, prompt e wait "detached" |
No timeout: herdr agent get e decidir por agent_status; read só em done/blocked | Skills: tabela de falhas de herdr-executors | pendente | L61: read de 40 linhas a cada wait |
Tirar --until idle das receitas | Skills: receitas N=1 e N≥2 | pendente | L60 e L80 |
Teto de ciclos wait+read por agente; ler todos os vivos num único comando (for n in fer-… já existe) | Skills + scripts | pendente | sem cap; receita é por nome |
| 120 s de rearme + corte de 10/12 min | Skills + executor-hard-cut.sh | aplicado | CUT_S=600, KILL_S=720; correção do dono nesta janela |
| Prova de produto: MCP/HTTP/CLI primeiro; browser só para print por URL | Skills: seção "Prova de produto" | aplicado | L92–93 |
Worker não carrega browser-control sem o card dizer que a API não basta | Hooks: SessionStart + prompt do executor | parcial | prompt proíbe skills de orquestração; SessionStart ainda faz cat de browser-control-mandate.md |
Métrica de aceite. Por executor vivo: wait+read ≤ 3 a cada 10 min até done; read/start ≤ 2; nenhum wait que volta "running in background" seguido de read em 15 s. Agentes paralelos lidos num só turno.
Tensão a resolver. Os workers 1 e 2 querem wait quieto e bloqueante. A regra atual de herdr-executors (L61, correção do dono) manda ler o pane a cada 120 s. As duas não podem ser a regra ao mesmo tempo. Sugestão: manter o rearme de 120 s, trocar a leitura de pane por agent get, e ler o pane só quando o status é blocked, unknown ou done sem VERDICT.
C3 O caminho quente do orquestrador é cerimônia serial e I/O gordo
Achados: timing#3, tools#3.
Causa raiz. O único escritor do jsonl do orquestrador é obrigado a recarregar skills, escriturar o Linear e esperar agente por agente. Dispatch usa três CLIs (open-tab, start, prompt). ToolSearch do Linear repetiu 4 vezes; curl na porta :3100 do Linear 6 vezes; get_issue FER-964 com includeRelations devolveu 17–22 kB mais de uma vez; dois dumps de Bash acima de 30 kB; gh 21 vezes e gh-axi zero, embora o SessionStart o injete.
| Acionável | Camada / arquivo | Estado | Evidência |
|---|---|---|---|
| Escrever no Linear só na conclusão do executor, não a cada poll | Linear + Skills: "When executor reports arrive" | pendente | L163–169 ok; loading step e self-improvement ainda escrevem no meio |
| Pular ToolSearch do Linear depois da primeira escrita MCP que deu certo | Skills: Tool reference | pendente | L199 manda ToolSearch em todo load |
Heartbeat com get_issue sem includeRelations; nunca curl :3100 | Skills | pendente | sem proibição escrita |
gh-axi para GitHub; um comando simples por chamada, sem $( ) | Hooks: SessionStart gh-axi | parcial | L157–163 roda o binário; nenhuma skill proíbe gh + jq |
| Arquivos do repo via Read/Grep; dumps de Bash limitados antes de voltar | não codificado | pendente | |
open-swarm-tab uma vez, depois start com prompt no mesmo argv (se a CLI aceitar) | Herdr: receita N=1 | pendente | L43–60; capacidade da CLI não verificada |
Latch por sessão para check-compat.sh e helpers relidos (16 cats de open-swarm-tab, 10 do watcher) | Herdr scripts | pendente | L19–22 sem latch |
Não fechar tab que herdr agent list não devolve | Herdr: N=1 L65 | parcial | fecha só a tab da receita; sem guarda para ids velhos |
Não ler handoffs de ontem quando o w5N_p1 de hoje existe | Auto-clear / handoff | pendente | não codificado |
Métrica de aceite. Bash por executor, do start ao done, ≤ 8. Linear MCP por vida de contexto ≤ 10 sem pedido do dono. gh-axi ≥ gh. Curl em :3100 = 0. ToolSearch do Linear ≤ 1 por sessão. Nenhum resultado de Bash acima de 8 kB.
C4 Recusa de isolamento vira loop de reescrita
Achado: tools#2.
Causa raiz. Bash é o padrão para git, HTTP, MCP e GitHub. Depois de um "Refusing to run" (9) ou de um bloqueio do classifier (5), a ação seguinte é um Bash mais ofuscado ($VAR como nome de comando, python3 -c, git -C, curl JSON-RPC em /api/mcp) em vez de Read, MCP ou caminho literal. Cadeia de 15–25 chamadas por intenção travada (sonda MCP 13:12–13:18Z; edição do watcher 13:28–13:31Z). O guarda está certo; a repetição, não.
| Acionável | Camada / arquivo | Estado | Evidência |
|---|---|---|---|
Depois de uma recusa: caminhos literais, sem $VAR em nome de comando, sem git -C fora do cwd; script salvo e rodado por caminho | Hooks: PreToolUse de isolamento + regra de conduta | pendente | deny existe; nenhuma skill diz "pare após 1 recusa" |
Arquivo fora do worktree (auto-clear-watch.sh): parar e relatar | Hooks: classifier + isolamento | aplicado (guarda) / pendente (obedecer) | Edit bloqueado em 8aecd549:393 |
MCP do produto pelas tools do ToolSearch, não por curl/python; nunca extrair token de ~/.claude.json por Bash | não codificado | pendente | ToolSearch achou as tools em 78d3b533:229 antes do loop de curl |
Métrica de aceite. Recusas de isolamento ≤ 1 por janela; zero curl/python JSON-RPC em /api/mcp depois de um ToolSearch bem-sucedido para o mesmo servidor.
C5 Loop de auto-melhoria e unidades atômicas roubam a meta do dono
Achado: policy#2.
Causa raiz. O Linear é a memória, mas a sucessora age pelo Meta comprimido do handoff, que tinha perdido o card da prova ao vivo. O dono repetiu a meta duas vezes (12:26Z) e pediu às 13:08Z para não perder o pedido entre handoffs. O loop de auto-melhoria transforma cada erro em um novo pai de Harness despachado no mesmo segmento, no mesmo orçamento de 10 min da prova. Um único ISSUES virou três pais. Título duplicado (MCP-host) criado duas vezes em 2,3 min: idempotência é frase, não hook. "Escrita de issue via herdr" é um MUST que o orquestrador precisa violar para manter o board verdadeiro (49 save_issue inline).
| Acionável | Camada / arquivo | Estado | Evidência |
|---|---|---|---|
Bloco "meta do dono" congelado na descrição do épico; a primeira leitura da sucessora é get_issue nesse épico, antes de qualquer spawn de Harness | Linear + Skills: orchestrate-with-linear L157–158, handoff Meta | parcial | entendimento gravado no pai; loading step ainda é Skill → list_issues |
| Auto-melhoria: linha no FER-996 no segmento; pai de Harness entra como Todo; despacha só sem prova ao vivo In Progress (cap 1) | Skills: seção Self-improvement loop | pendente | L191–195: "in the same segment" e "dispatch that parent" |
| ISSUES de executor de prova viram sub-issues do pai da prova, salvo tema novo | Skills: Board visibility L65 + Dogfood L189 | pendente (conflito) | "todo tópico é pai" briga com sub-issue do pai da prova |
Hook nega save_issue com create sem list_issues prévio do mesmo título | Hooks: post-tool-use-linear.sh → novo PreToolUse | pendente | L10–15 só grava o sidecar linear-written |
| "Escrita via herdr" vira should, ou existe um executor escriturário de verdade | Skills: Board integrity L183 | pendente | ainda MUST |
Métrica de aceite. Depois do próximo /clear, a primeira resposta ao dono nomeia o pai da prova ao vivo sem o dono repetir a meta. Nenhum pai de Harness despachado enquanto um filho da prova está In Progress. Zero títulos iguais em 10 min.
C6 A pilha de mandatos é "ou" no papel e "e" no SessionStart
Achado: policy#3 (parte que C1 não cobre).
Causa raiz. O SessionStart injeta poteto-mode, orchestrator, browser-control e gh-axi juntos, a cada clear (16 anexos). Regras demais de "primeira resposta": ler handoff, Skills-only, comentário no Linear, poteto-mode, decompor e despachar, ficar disponível. O modelo cumpre o checklist mais recente e pula o resto: 8 skills carregadas, e o comentário de obrigações que elas exigem apareceu 1 vez em 32. Fila: 85 enqueue / 27 dequeue / 56 remove, prompts do dono empilhando sobre um orquestrador em cerimônia.
| Acionável | Camada / arquivo | Estado | Evidência |
|---|---|---|---|
| Parágrafos de isenção de worker ficam como estão | Hooks: os três mandatos | aplicado | poteto L5; orchestrator L7; browser-control L3 |
pre-tool-use-herdr.sh exige FER-n e sidecar linear-written no start/prompt | Hooks: agents-config | aplicado | L66–72 |
Fundir stay-available com o wait do herdr | Skills | não fazer | stay-available é do Task/PSTACK do Cursor; herdr é CLI. Fundir mistura dois harnesses |
Métrica de aceite. No próximo SessionStart:clear de pane de orquestrador, a primeira mensagem tem zero ou uma Skill (orchestrate-with-linear) e contém takeover no épico ou rearme do herdr.
Ordem sugerida de execução (benefício estimado ÷ custo)
- C1 SessionStart exclusivo por papel + "continuação não é tópico novo". Uma edição em
settings.jsone uma emorchestrate-with-linear. Estimativa: segmentos pós-clear voltam para ~50 min. - C1
skills-loadedpor pane id emlib.sh. - C1 UserPromptSubmit só no primeiro prompt.
- C2 tirar
--until idle;wait --until done+agent get; read só em blocked/unknown. - C5 auto-melhoria vira fila (Todo) enquanto há prova ao vivo In Progress.
- C3 proibir curl
:3100; ToolSearch do Linear uma vez; semincludeRelationsem heartbeat. - C3/C4
gh-axie "pare após 1 recusa de isolamento". - C2 wait bloqueante ou notify-on-done no herdr. Maior ganho de parede, maior custo.
- C5 hook de idempotência para
save_issue. - C3 start + prompt num argv só se a CLI aceitar.
Todos são propostas nascidas de lacuna, não de ordem direta. Pela regra do board, cada um entra como pai em Harness & agentes e vai para Aprovação Pendente com o antes/depois exato. Exceção: itens que o dono já ordenou (120 s, corte de 10 min, kickoff sem reenvio) já estão aplicados.
5. O que preservar e as propostas contraintuitivas
Preservar
- Panes sobrevivem ao clear.
fer-81,fer-83,fer-87… foram lidos pela sessão seguinte sem novo start. É o único motivo de o corte de 4 s não ser uma parada total. Manter nomes e pane ids no handoff. - Takeover no épico. Um comentário em FER-827 por sessão nomeando o handoff lido e a tabela de executores vivos. Foi assim que os cinco arquivos puderam ser encadeados.
- Linear MCP para escritas.
save_issue/save_comment, nunca GraphQL por curl. - Leituras de pane com teto de bytes (
tail -c 1800–4000) quando uma leitura é mesmo necessária. - Guardas que recusam
git -Cfora do worktree e edição em~/.local/share/auto-clear/. A recusa é o guarda funcionando. - 120 s de wait + corte de 10 min como estão hoje em
herdr-executors. Foram correções do dono durante a janela.
Contraintuitivo
- Worker 1: os buracos de 3–7 min parecem desperdício e as sessões a 45 registros/min parecem progresso. É o contrário: o frenesi é o que queima 200k em 14 min. Prefira um wait que bloqueia e um orquestrador quieto.
- Worker 2: pare de ler o terminal do filho para decidir se espera. Um
wait --until donemaisherdr agent getparece menos informado e termina com menos tokens do pai. Se o worker travou em GUI, o erro é dele. - Worker 3: pare de carregar skills depois de
/clear. A política não é cara por não ser lida; é cara por ser relida num contexto que encolhe até a releitura causar o próximo handoff. Persista um bit "política já aplicada" por pane.
6. Verificação independente das contagens
O executor A (FER-1040) recomputou as contagens contra candidates.jsonl com verify_counts.py. O censo central bate. Quatro números divergem; nenhum inverte um achado.
| Contagem | Relatório | Reportado | Recomputado | Status |
|---|---|---|---|---|
| Registros total e por sessão (268 / 625 / 645 / 701 / 285) | timing, manifest | 2524 | 2524 | confirmado |
| Bash / Skill / Write / Edit / Read / ToolSearch | timing, tools | 297 / 35 / 10 / 3 / 3 / 5 | iguais | confirmado |
| Linear MCP (save_issue / save_comment / list_comments / get_issue / list_issues) | timing, tools | 116 = 49/32/19/12/4 | iguais | confirmado |
| herdr wait / start / prompt | timing, tools | 36 / 15 / 21 | iguais | confirmado |
| herdr read | timing 35; tools 29 (classificado) | 35 / 29 | 35 | confirmado vs timing; divergente vs tools |
| herdr get | tools | 1 | 2 | divergente (piora a razão, não inverte) |
| Skills: 8 nomes, poteto-mode 0, por sessão 0+8+11+8+8 | policy, timing | 35 | 35 | confirmado |
| "Refusing to run" / classifier | tools | 9 / 5 | 9 / 5 | confirmado |
| gh / gh-axi | tools | 21 / 0 | 21 / 0 | confirmado |
curl em :3100 | tools | 5 | 6 | divergente (extra em 65dd9aeb:611) |
| save_issue com título (creates) | policy | 16 | 15 | divergente |
| Título duplicado (MCP-host) | policy | 2× | 2× (8aecd549:245, :365) | confirmado |
| away_summary | timing | 5 | 5 | confirmado |
| Silêncio >60 s: 65dd / 1ddd / 3 últimas / soma | timing | 25,3 / 22,9 / 0 / 48,2 min | 25,31 / 32,21 / 0 / 57,52 min | divergente em 1ddd e na soma |
| Bash em background | timing | 74 | 74 | confirmado |
Leitura das divergências: o silêncio do orquestrador nas duas primeiras sessões é ~9 min maior do que o worker 1 disse (57,5 min, não 48,2); as três sessões seguintes continuam sem nenhum buraco. O número de creates é 15, não 16. A razão wait+read contra get fica pior para o achado do worker 2, não melhor. Nenhuma das quatro muda a direção de um top-3.
7. Lacunas declaradas
- Panes dos executores fora do corpus: não dá para medir produtividade do Grok dentro dos
fer-*. - Faltam 2,25 min no início da janela; a sessão âncora continua depois de 13:47Z (160 registros pós-janela).
- 175–213 registros por arquivo sem timestamp foram excluídos das contas de tempo.
- Nenhum total de tokens ou custo; só contagens de anexos.
- Os workers não abriram o Linear nem o estado vivo do herdr. O Linear MCP deles não autenticou (Cursor precisa de auth interativa).
- Chats paralelos em outros diretórios de projeto: fora do conjunto de candidatos, desconhecidos.
8. Board
| Card | O quê | Executor |
|---|---|---|
| FER-1039 | Pai: síntese em HTML da auditoria (este documento) | Fable (orquestrador, ordem do dono) |
| FER-1040 | A: recomputar as contagens contra candidates.jsonl → verified.md | herdr fer-1, cursor-grok-4.6-high |
| FER-1041 | B: clusterizar e checar cada acionável contra os arquivos atuais do stack → clusters.md | herdr fer-2, cursor-grok-4.6-high |
Os três workers da auditoria original não criaram card (board.md). FER-1039 é o registro que faltava.