# Roadmap

> Versão atual: **3.24.0**. Estado atual e evolução planejada do **Izanagi AI: Adaptive Agent & Skill Runtime**.
> Legenda: ✅ Done · 🔧 In progress · 📋 Planned · 💡 Future idea
> Histórico linha-a-linha de cada release em `CHANGELOG.md`: este arquivo resume por fase, não duplica o changelog.

---

## Fase 1: Foundation (v1.x) ✅

- [x] SYSTEM.md / RULES.md / README / AGENTS.md: identidade e operação
- [x] Decision Engine: classificação e roteamento de tarefas
- [x] Context Engine + Compression Engine: contexto enxuto e compactação
- [x] Token Manager: orçamento e monitoramento
- [x] Reflection Engine + Evolution Engine: autoavaliação pós-tarefa
- [x] Quality Gates: portões de validação de output
- [x] Planning Engine: decomposição e estimativa
- [x] Memory Manager: memória persistente 3 níveis + knowledge graph

## Fase 2: Engine Layer (v2.0 → v2.8) ✅

- [x] 15 → 18 agentes especializados, cada um com chains compostas
- [x] Biblioteca de skills modulares (103) + Skill Composer
- [x] CLI executável publicado no npm (`izanagi-ai`) com `izanagi init/run/compile/chat/doctor`
- [x] Packs selecionáveis + export multi-CLI (claude, codex, cursor, copilot, kimi)
- [x] Multi-Agent Swarm Mode (execução paralela concorrente)
- [x] Memória persistente `.agents/memoria/` (contexto, decisões, erros, aprendizados)
- [x] Referências curadas por domínio (`references/`)
- [x] Blueprint Engine: gate de manifest de arquivos, zero stubs
- [x] Anti-AI-Slop, design-directions (Style Selector) e ui-ux-pro-max (BM25 offline)

## Fase 3: Adaptive Runtime (v2.9 → v2.10) ✅

- [x] **Evaluation Engine** (`core/evaluation/` → `src/runtime/evaluation/`): vereditos PASS / PASS_WITH_WARNINGS / FAIL / BLOCKED / UNKNOWN, métricas ponderadas (correctness, security, architecture, performance, maintainability, artifact validity), confiança e regressões
- [x] **Execution Graph** (`src/runtime/orchestration/`): grafo por tarefa com nós, dependências, condições, retry policy, timeout, token budget e validador; batches paralelos detectados; templates por categoria sem grafo gigante universal
- [x] **Adaptive Routing / Scoring** (`src/runtime/routing/`): ranking de agentes e skills por relevância semântica + histórico + compatibilidade + custo + risco
- [x] **Agent Genome**: 13 campos formais nos 22 agentes (purpose, capabilities, requiredSkills, optionalSkills, inputs, outputs, constraints, permissions, handoffs, memory, evaluation, tokenBudget, compatibility)
- [x] **Skill Manifest**: frontmatter padronizado nas skills (name, version, triggers, dependencies, risk, tokenBudget...) + `izanagi skill inspect/search`
- [x] **Agent Factory & Skill Factory** (`src/runtime/factories/`): geração de agentes e skills por lacuna real, com validação antes do registro
- [x] **Failure Memory** (`src/runtime/memory/`): 7 categorias (episodic, semantic, procedural, decision, failure, skill, project); padrões de falha reutilizáveis buscados antes da execução
- [x] **Self-Healing** (`src/runtime/recovery/`): classificação de falha (recoverable/non-recoverable/planning/tool/agent/validation/dependency) → local repair | replan | handoff | skill replacement | abort; limites maxAttempts/maxTokens/maxTime
- [x] **Contracts & Artifacts** (`src/runtime/contracts/`): schemas programáticos (requirements, architecture, database-schema, api-contract, security-report, test-plan, implementation-plan, evaluation) com validação INVALID → REPAIR → RE-EVALUATE
- [x] **Adversarial Critic**: 18º/19º agente: caça bugs, segurança, architecture flaws, AI slop
- [x] **Model Router** (`src/runtime/model/`): ModelProvider / ModelAdapter / ModelRouter por complexidade, risco, custo, latência e contexto
- [x] **Tracing / Observability** (`src/runtime/observability/`): spans por decisão/agente/skill/tool/model + `izanagi trace` e `izanagi trace <run-id>`
- [x] **Tools Registry (MCP-ready)** (`src/runtime/tools/`): discover → permission → compatibility → select → execute → validate, least privilege, path traversal bloqueado
- [x] **Skill Security Scanner** (`src/runtime/security/`): prompt injection, instruções perigosas, scripts, permissões, requisitos de rede/fs; LOW/MEDIUM/HIGH/CRITICAL
- [x] **Benchmarks** (`benchmarks/` + `src/runtime/benchmarks/`): 10 domínios, validators, expectativas de artefatos, `izanagi benchmark run/list/compare` com relatório comparável entre versões
- [x] **CLI runtime**: `izanagi agent list|inspect`, `skill list|search|inspect|create`, `workflow list|inspect`, `run`, `trace`, `eval`, `benchmark`, `memory inspect|search`, `doctor --deep`, `diagnose`
- [x] **Doctor expandido**: valida system/agents/skills/resolver/memória/providers/tools/contratos/avaliação/benchmarks
- [x] Testes node:test cobrindo resolver, scoring, contracts, evaluation, graph, parallel, retry, healing, memory, handoff, factories, model routing, CLI, tracer, scanner, tools, benchmarks, orchestrator

## Fase 4: Evolução v2.11 (🔧 / 📋)

- [x] **Evidence System** (`src/runtime/research/`): claims FACT / ASSUMPTION / INFERENCE / UNKNOWN com source, confidence, sourceType hierarquizado (official docs > source code > tests > package metadata > reliable tech > community) e relatório de claims críticas
- [x] **Token Budget 2.0** (`src/runtime/token/`): orçamento por fase (planning / execution / evaluation / recovery) com tetos e abort de fase; distribuído automaticamente por complexidade e tier de modelo
- [x] **Product Reasoner**: Understanding: intenção vaga → requisitos com evidências e critérios BDD (entrada do ciclo)
- [x] **Agent Architect**: projeto de novos agentes (Genome + guardrails + avaliação) por lacuna real
- [x] **Skill Architect**: curadoria de skills com security scan e anti-duplicação por lacuna comprovada
- [x] **Benchmarks externos**: `benchmarks/*.json` carregados pelo registry sem duplicar IDs embutidos
- [x] **Plugin System (base)**: trust tiers (builtin/generated/community) no Skill Scanner com bloqueio escalonado + Policy Engine para permissão contextual; ainda falta sandbox de execução isolada para skills de terceiros 🔧
- [ ] **Skill Marketplace**: compartilhar e instalar skills 📋
- [ ] **Izanagi API**: interface REST para interrogção do framework 💡
- [ ] **Web UI**: editor visual de skills e monitor de execuções 📋
- [ ] **Analytics Dashboard**: token usage, custo e evolução por execução 📋
- [ ] **Histórico persistente entre sessões/dispositivos + login por conta** (pedido do usuário, ainda não escopado 💡): hoje `izanagi dashboard` é local, single-user, lê `TraceStore`/`MemoryStore` do disco (`.agents/memoria/`) — sobrevive a fechar o terminal, mas não a trocar de computador. Login multi-dispositivo real exige backend hospedado + banco + auth, o que contradiz o design zero-infra/local-first atual do framework (roda 100% offline, sem servidor próprio). Antes de implementar: decidir explicitamente entre (a) continuar local-first e oferecer só *export/import* do estado (`.agents/memoria/` sincronizado via Git/Dropbox/etc, zero conta), ou (b) aceitar a mudança de filosofia e construir um serviço hospedado (conta, banco, sync) como produto separado do CLI. Não implementar às pressas sem essa decisão.

## Fase 5: Runtime de Produção v2.11 ✅

Auditoria completa do framework + consolidação arquitetural (unificação de caminhos de execução, eliminação de duplicações) + as primitives que faltavam para o runtime ser "production-grade" pelos critérios de mercado 2026 (checkpoint/resume, observabilidade de decisão, rastreabilidade de artefato, human-in-the-loop real).

- [x] **`izanagi run` unificado**: Adaptive Runtime (graph + routing + evaluation + trace + healing + memória) é o único caminho de execução, por padrão; eliminado o modo estático paralelo que só imprimia um plano sem executar. `--prompt-only` preserva a geração de prompt para colar em outra ferramenta.
- [x] **Safe Expression Evaluator** (`src/runtime/orchestration/safe-eval.ts`): substitui `new Function()`/eval sobre `GraphNode.condition` e `BenchmarkValidator.check`, que podiam vir de dados de terceiros (benchmarks externos).
- [x] **Model Router com histórico e extensibilidade real**: `historicalPerformance` (antes um campo morto) agora é preenchido via `MemoryStore.recordModelRun`; `IZANAGI_MODEL` (override manual) e `.izanagi/izanagi.config.json → models` (catálogo por projeto) implementados.
- [x] **Policy Engine** (`src/runtime/security/policy.ts`): permissão CONTEXTUAL (ambiente dev/ci/produção, trust tier), distinta do Security Scanner (detecção de conteúdo perigoso). Wired em `ToolRegistry`.
- [x] **Trust tiers no Skill Scanner**: builtin/generated/community com bloqueio escalonado por origem.
- [x] **Checkpoint/Resume real** (`src/runtime/recovery/checkpoint.ts`): progresso salvo a cada rodada de batches; `izanagi resume <run-id>` continua sem replanejar nem reexecutar nós concluídos, restaurando budget/artefatos/modelo.
- [x] **Decision Journal** (`src/runtime/memory/decisions.ts`): decisão + alternativas realmente consideradas + razão + confiança, para model-routing e agent-routing.
- [x] **Artifact Registry** (`src/runtime/artifacts/registry.ts`): artefatos rastreáveis (produtor, hash, dependências, versão em retry/replan).
- [x] **Human-in-the-loop real**: `GraphNode.kind: 'approval'` pausa a execução (não é falha) até `izanagi approve`/`izanagi reject`, retomando via checkpoint.
- [x] **CLI**: `izanagi resume`, `izanagi approve`, `izanagi reject`, `izanagi explain`.
- [x] **Skill Lifecycle**: `discovered → draft → validated → active → deprecated → archived`; skills geradas pela Factory nascem `draft` (nunca "Generate → Automatically trust").
- [x] **`doctor`/`diagnose` sem duplicação**: checks compartilhados (`src/cli/checks.ts`) computados uma vez, cada comando decide o que exibir.
- [x] **Confirmado**: as 102 skills em `skills/*/SKILL.md` são 100% compliant com o padrão aberto agentskills.io (frontmatter `name`+`description`): portáveis para ~40 ferramentas de mercado (Cursor, Copilot, Codex, VS Code...) sem modificação.
- [ ] **Consolidação dos packs de skills legados** (`architecture/`, `coding/`, `security/`... vs. `skills/`): depreciação com apontamento para o equivalente novo, em andamento 🔧

## Fase 6: Hardening & Correção Real de Produção (v3.0 → v3.4) ✅

Cada item veio de um bug real encontrado por dogfooding, não de suposição. Detalhe completo em `CHANGELOG.md`.

- [x] **v3.0.0 (CRÍTICO)**: todo comando runtime lia/escrevia dentro do próprio pacote instalado em vez do projeto do usuário; `resolveFrameworkRoot(cwd)` corrigido para resolver a partir do `.agents/` do projeto real.
- [x] **v3.1.0 (CRÍTICO)**: `izanagi init` não gerava adapter Claude Code em modo não-interativo; `exportToClaude()` só exportava 10 de 103 skills; os 22 agentes tinham `model` fixado num snapshot datado; `.manifest` contava skills em dobro ("212 skills" corrigido para 103 reais); agente `/ai-engineer` adicionado (21 → 22 core).
- [x] **v3.2.0**: `checkNestedDuplicate()` detecta o padrão `<repo>/<repo>/`, causa raiz real de "skills/agentes não aparecem".
- [x] **v3.3.0: Izanagi Evolution**: auditoria contra roadmap de 7 fases; fechou lacunas reais (`FailureCategory`, `ArtifactRegistry.detectRegression()`, Event System, adapters Ollama/LM Studio/OpenRouter, ciclo de vida de failure-pattern, `benchmark report`/`arena`, `izanagi dashboard` local).
- [x] **v3.4.0 (CRÍTICO)**: os 3 commits pós-3.3.0 (persistência crash-safe, dashboard live via SSE, polish visual) tinham sido enviados ao GitHub mas nunca publicados no npm; republicado.

## Fase 7: Higiene de Texto & Consistência de Documentação (v3.5 → v3.6) ✅

- [x] **v3.5.0**: higiene Unicode default-on em todo `fs.write` gerado (`sanitizeText()`): remove caracteres invisíveis (zero-width space, bidi overrides, BOM...) e normaliza espaços homóglifos (nbsp, espaços largos), sem custo de rede/LLM.
- [x] **v3.6.0**: banners de versão de `AGENTS.md`/`SYSTEM.md`/`RULES.md` estavam presos em `2.11.0`/`1.0.0` desde antes da 3.0.0, apesar de terem recebido edições reais nesse período; unificados em `3.6.0`. Contagens obsoletas corrigidas (testes, skills, aliases, composições, "vs. 21 core"). `AGENTS.md` tinha referência a um agente dinâmico de exemplo já removido em 2.13.0. `izanagi export`/`init` não listavam `opencode` como CLI válido apesar de ser o adapter default. Os templates dos 6 adapters CLI e o campo `role` de 4 agentes violavam a própria Regra 13 do framework (zero travessão "—"): purgado. `senior-engineer-agent.json` tinha `optionalSkills` com nomes de arquivo de agente em vez de alias de skill (mesma classe de bug que a 2.13.0 corrigiu em outros 3 agentes, mas não neste): corrigido. `resolveFrameworkRoot()` tratava qualquer `.agents/` como projeto inicializado, mesmo quando só continha `.agents/memoria/` criado pelo próprio runtime sem `izanagi init` nunca ter rodado: `doctor`/`run`/`agent list` falhavam silenciosamente nesse caso, inclusive dentro do próprio checkout do framework; corrigido para exigir `.agents/core`. Adicionado orquestrador `/agents` nativo para Claude Code (`.claude/commands/agents.md`), espelhando o protocolo do opencode via Agent tool. Nova skill `payments-billing` (Stripe/Paddle/Mercado Pago), cabeada em `senior-engineer` e na composição `fullstack_crud`.

---

## Fase 8: Runtime de Execução de Trabalho (v3.13.0) ✅

De "framework de agentes" para runtime que transforma objetivo em plano executável, delega ao modelo certo, verifica o resultado e controla o custo.

- [x] **Commander (LEVEL 0)**: classificação de complexidade e domínios, escolha do modo, geração de Task Contracts com critérios de aceite derivados do schema real do artefato, estimativa de custo e degradação de modo sob teto. Determinístico: planejar não gasta token.
- [x] **Execution Modes**: `direct` / `assisted` / `orchestrated` / `autonomous`. Antes, "converta 10 dólares para reais" montava um grafo de 3 a 9 nós com avaliação e crítica.
- [x] **Task Contract**: objetivo, papel, insumos por referência, restrições, saída esperada, dependências, orçamento e política de verificação por tarefa.
- [x] **Model Router por papel**: tier por papel (commander/specialist/worker), pin por config/env, escalada worker→specialist→commander na retentativa, custo real em USD.
- [x] **Context Resolver**: contexto mínimo por tarefa. Corrigiu a lacuna de nós dependentes que nunca recebiam a saída dos predecessores.
- [x] **Agent Capability Registry**: "quem sabe fazer isso?" lido do disco, no lugar da lista fixa dentro do orchestrator.
- [x] **Agent-to-Agent Protocol**: mensagens tipadas por referência de artefato + crítica estruturada + correção mínima.
- [x] **Verification Engine 2.0**: determinística, evidência e semântica. Critério semântico sem juiz fica UNVERIFIED e nunca vira aprovação.
- [x] **Budget Controller**: custo em USD, tetos de tool/agente/retry, tempo, escada de degradação.
- [x] **Early stopping**: tarefa opcional não roda quando as dependências já estão VERIFIED.
- [x] **Response Cache** opt-in e **telemetria de economia** persistida no trace.
- [x] **SDK programático**: `izanagi.run()` / `izanagi.plan()` com eventos do run.
- [x] **CLI**: `--mode`, `--budget`, `--max-cost`, `--model`, `--local`, `--cache`, `--no-commander`; `izanagi models`; `izanagi budget`.
- [x] **Token Benchmark**: legado vs Commander em chamadas, tokens e custo, determinístico e com ressalva explícita do que não mede.

### Limitações desta fase: todas fechadas na Fase 9

As onze limitações registradas aqui na v3.13.0 foram resolvidas nas versões
3.13.x/3.14.0. O detalhamento de cada fechamento está na tabela *Fechados* de
[`docs/RUNTIME-PENDING.md`](docs/RUNTIME-PENDING.md).

## Fase 9: Fechamento do runtime (v3.14.0) ✅

De "as peças existem e são testadas" para "as peças estão ligadas e mudam a execução".

- [x] **Degradação de orçamento aplicada de fato**: cada degrau muda a execução (contexto pela metade, teto de saída a 60%, papel rebaixado, concorrência dividida, opcionais cortadas, pausa por aprovação humana), com limiar próprio por degrau e pressão calculada pela maior razão **por fase**.
- [x] **Content store de artefato**: conteúdo persistido em `.izanagi/state/artifacts/<runId>/` com `contentRef`, teto de 512KB e truncamento declarado. `izanagi explain --artifacts` mostra o que foi produzido depois que o processo morreu.
- [x] **Teto de concorrência**: pool com ordem preservada e falha isolada por índice (`orchestration/concurrency.ts`), default 3, configurável e reduzido pela degradação.
- [x] **Critique loop ligado**: crítica bloqueante reprova o nó CRITICADO e devolve correção mínima; a retentativa recebe a própria entrega anterior + a lista de correções, não o histórico. Teto de uma rodada por nó. `critique` virou ArtifactKind com formato obrigatório.
- [x] **Protocolo A2A com caller**: `ConversationLog` registra task/result/critique/correction do run, sempre por referência de artefato. Persiste no trace; `izanagi explain [--conversation]` mostra quem falou com quem.
- [x] **Juiz semântico ligado por default**: papel `worker`, artefato resumido, um critério por vez. Saída ilegível/erro de rede vira `inconclusive`, nunca reprovação. Tokens do julgamento cobrados da fase `evaluation`. `--no-judge` desliga.
- [x] **Replanejamento pelo Commander**: `Commander.replan` troca o agente, sobe o papel ou quebra a tarefa em rascunho + fechamento. Recebe só o delta da falha e declara quando não há alternativa estrutural.
- [x] **Memória no planejamento**: padrão de falha conhecido sobe o modo um degrau; agente com histórico ruim sai da disputa (com salvaguarda contra excluir todo mundo); a consulta entra no Decision Journal.
- [x] **Skills por tarefa**: cada nó carrega as skills do próprio objetivo (teto de 3) em vez da chain do run, com memoização de manifesto para o ranking por tarefa não multiplicar I/O.

### Limitações desta fase: todas fechadas na Fase 10

As sete limitações registradas aqui na v3.14.0 foram resolvidas na v3.15.0. O
detalhamento está na tabela *Fechados* de
[`docs/RUNTIME-PENDING.md`](docs/RUNTIME-PENDING.md).

## Fase 10: Segurança no caminho de execução e medição real (v3.15.0) ✅

O que sobrava depois da Fase 9 era, quase tudo, "existe mas não está no caminho".

- [x] **Policy Engine no caminho de `izanagi run`**: nó `kind: 'tool'` roteado por `ToolRegistry` + `PolicyEngine`. `TaskContract.permissions` declara o que a tarefa pode fazer (menor privilégio: contrato sem permissões executa tool nenhuma); trust tier vem da ORIGEM do arquivo do agente, não do que ele declara. Negativa de permissão é `non-recoverable`: retry não abre porta fechada.
- [x] **Simulação headless derivada do schema real**: `izanagi run` sem API key deixou de terminar `FAIL` por um motivo alheio ao runtime. Um teste valida a simulação de TODO kind registrado contra o validador de verdade, então schema e simulação não divergem em silêncio.
- [x] **Estatística de agente por domínio**: `AgentStats.byDomain`. Um agente bom em backend não é mais descartado de um trabalho de backend por ir mal em frontend. Ausência de histórico no domínio é tratada como ausência de sinal, não como sinal ruim.
- [x] **Cache de validação determinística**: `validateArtifact` memoizado por `(kind, hash)`. Economiza CPU, não token — e isso está dito no código e no relatório.
- [x] **Dashboard mostra o runtime novo**: modo, verificação por tarefa, economia e conversa A2A no Run Explorer.
- [x] **Izanagi Arena**: `izanagi benchmark run --execute` roda cada caso pelo runtime real e mede verificação, recuperação, retries, healing, tokens e custo. Métrica ausente aparece como ausente.

Três bugs reais corrigidos no caminho: `toText` podia devolver `undefined` (validar retorno vazio de tool estourava em vez de reprovar); caminho relativo de tool escapava da sandbox resolvendo contra o cwd do processo; e a tabela de economia do dashboard referenciava campos que não existem em `TokenTelemetry`.

### Limitações desta fase: todas fechadas na Fase 11

## Fase 11: Autonomia contida (v3.16.0) ✅

Os três itens que restavam eram os de maior risco da lista: cada um destrava
autonomia, e cada um erra caro se destravar demais.

- [x] **Sub-orquestração**: uma tarefa pode descobrir, executando, que é maior do que o plano previu, e abrir um subgrafo próprio. Os limites são o ponto: orçamento do pai **dividido** (decompor não libera gasto), profundidade com teto do RUNTIME e não do agente, largura máxima de 5, sub-tarefa que não decompõe de novo, pedido malformado recusado inteiro, e falha de filho sendo falha de quem pediu.
- [x] **`execute_code` com isolamento imposto pelo runtime**: processo Node separado com Permission Model. Filesystem restrito ao diretório de trabalho, subprocessos/workers/addons/WASI bloqueados, ambiente montado do zero (nenhuma chave de API atravessa), timeout com kill, teto de saída. Sem isolamento disponível, a execução é RECUSADA.
- [x] **Síntese de skill por trajetória recorrente**: o simétrico de converter falha em padrão. A barra é recorrência (3 execuções verificadas), a assinatura é o caminho e não o objetivo, e a skill gerada declara o próprio limite.
- [x] **A medição que destravava FTS5 e compressão neural**: `izanagi benchmark memory`. Busca p95 2.0ms sobre 296KB e compressão a 8.3% do original — as duas trocas não se pagam neste volume, e o comando dirá sozinho quando isso mudar.

Dois bugs reais corrigidos: a busca de memória tinha **recall truncado em silêncio** (buscava só nos primeiros 4000 chars de cada arquivo, então tudo que o projeto aprendeu depois era invisível), e a sandbox concedia leitura de `os.tmpdir()` inteiro, onde o próprio diretório de trabalho vive.

### A decisão que faltava, tomada na Fase 12.

## Fase 12: Local-first, decidido (v3.17.0) ✅

A escolha entre CLI local-first e serviço hospedado estava pendente desde a
Fase 4, e destravava três coisas ao mesmo tempo (daemon, cron, canais).
**Decisão: local-first.** O Izanagi não fica de pé — sem daemon, sem porta
escutando, sem credencial em repouso. É o pressuposto sobre o qual sandbox,
trust tier e Policy Engine foram desenhados, e mantê-lo evita revisitar todas
essas decisões de segurança.

Quem agenda passa a ser o cron ou o Task Scheduler do sistema, e o que faltava
era o Izanagi ser consumível por eles:

- [x] **`--json`**: um único objeto no stdout, saída humana silenciada,
      `console.error` preservado — erro real precisa chegar ao stderr do
      agendador sem contaminar o stdout que ele parseia.
- [x] **Código de saída com significado**: `0` concluiu · `1` falhou ·
      `2` aguarda decisão humana. Aguardar aprovação não é falha e não deve
      alertar como falha: alguém precisa aprovar, não consertar.
- [x] **`--notify-webhook=<url>`**: POST de fim de run com uma retentativa.
      `4xx` não é repetido (configuração errada não melhora repetindo), `5xx` é.
      Falha de notificação nunca derruba o run.

**A regra do payload**: o webhook leva metadado (status, score, tokens, custo,
verificação por tarefa, nomes de artefato), nunca o conteúdo produzido. Um
endpoint de notificação costuma ser um canal de equipe ou um serviço que
ninguém auditou; mandar o artefato para lá é exfiltração com aparência de
conveniência.

**O que isto explicitamente NÃO dá**: receber comando de fora. Para isso seria
preciso autenticação, isolamento entre execuções e credenciais em repouso.

Com isso o handoff [`docs/RUNTIME-PENDING.md`](docs/RUNTIME-PENDING.md) fica
sem itens abertos: o que resta são oito escolhas com motivo registrado (rede
não isolada na sandbox, templates sem nós de tool, Token Benchmark medindo
plano, entre outras), não dívida.

## Fase 13: O trabalho sai do runtime (v3.18.0) ✅

Duas coisas que o runtime fazia e ninguém via, e uma que ele não fazia.

O caminho seguro de tool (permissão declarada no contrato, trust tier pela
origem do arquivo, Policy Engine antes de executar, sandbox) existia desde a
Fase 10, era testado, e **nenhum `izanagi run` passava por ele**. Ao mesmo
tempo, o trabalho de um run terminava em `.izanagi/state/artifacts/` — visível
por `izanagi explain --artifacts`, invisível para o projeto. E cada agente
escrevia sobre um repositório que nunca tinha visto.

- [x] **Nó `deliver` (`--output <dir>`)**: primeiro nó `kind: 'tool'` gerado
      pelo planejamento em produção. Grava o que o run produziu num documento
      único, e a verificação do nó confere o arquivo escrito. Isso muda o que o
      critério significa: `file-exists` sobre arquivo que ninguém escreveu passa
      quando o arquivo já existia por outro motivo; aqui ele passa a significar
      "o runtime gravou isto".
- [x] **Nó `survey` (`project.survey`, `--no-survey` desliga)**: levantamento
      determinístico do projeto na cabeça do grafo — stack, manifestos, árvore
      por extensão, entrypoints, começo do README. Não custa token, tem teto de
      profundidade e de entradas, e **declara o próprio corte**. Só as raízes
      dependem dele: repetir o levantamento em sete prompts seria a duplicação
      de contexto que a arquitetura proíbe.
- [x] **Marcadores de input de tool** (`{ $artifact: '<nó>' }`,
      `{ $deliverable: true }`): um nó de tool é declarado no plano, antes de
      existir o que ele vai gravar. A resolução é determinística, na hora da
      chamada. Referência a nó inexistente é **erro**, nunca string vazia.
      `code.execute` recusa marcador em qualquer campo: levar saída de modelo
      para dentro de código executado é injeção com outro nome.
- [x] **Menor privilégio verificado nó a nó**: `survey` recebe `fs:read`,
      `deliver` recebe `fs:write`, e nenhum nó de agente recebe permissão
      nenhuma. Há teste que percorre o plano inteiro conferindo isso.

- [x] **Nó `materialize` (`project.materialize`)**: o código que o agente
      escreve vira arquivo. O Blueprint Engine já definia o contrato de
      materialização, mas só em `--prompt-only` — um texto para a pessoa colar
      em outra ferramenta. Agora o contrato da tarefa PEDE o formato e um
      parser determinístico o materializa. A fronteira que torna isto
      defensável: os arquivos vão para um subdiretório da SAÍDA, nunca por cima
      do código do projeto. Escrita é tudo ou nada — a validação roda sobre o
      manifesto inteiro antes de qualquer arquivo tocar o disco.
- [x] **Outcome `not-applicable` na verificação**: distinto de `unknown`. O
      primeiro é "a pergunta não existe para este artefato", o segundo é
      "havia pergunta e não houve resposta". Sem a distinção, groundedness
      derrubava toda ADR para `UNVERIFIED` — um critério que reprova por não se
      aplicar é um critério que ninguém mantém ligado.
- [x] **Check `references-exist` (groundedness)**: a verificação passou a
      perguntar se o artefato corresponde a alguma realidade, e não só se ele
      tem os campos do schema. A fronteira que dá valor à checagem: reprovar
      quem inventou o layout, sem reprovar quem propôs arquivo novo num
      diretório real — a pergunta é sobre o diretório-pai, não sobre o arquivo.
      Cobrado só quando o survey rodou.

- [x] **Suíte de cenários ponta a ponta**: os dez cenários exigidos —
      trivial, médio, complexo, paralelo, falha, retentativa, escalada,
      estouro de orçamento, parada antecipada e aprovação humana — cada um
      pelo Commander e pelo Orchestrator reais, com só o producer injetado.

### Catorze bugs que a implementação revelou

- **`baseDir` não é a raiz do projeto.** É a raiz do FRAMEWORK
  (`<projeto>/.agents`, ou a própria instalação do pacote). A sandbox de tool e
  o check `file-exists` resolviam contra ela: um nó `fs.read` lia dentro de
  `.agents/`, não do projeto. Rodando de dentro do checkout do framework as duas
  coincidem, que é por que passava despercebido. Novo `workspaceDir`, com
  default = `baseDir` para que nenhum caller existente mude de comportamento.
- **Nó falho sem artefato era invisível para a avaliação.** `correctness` é a
  média das verificações registradas e `artifactValidity` a razão dos artefatos
  existentes: as duas ignoram quem não chegou a produzir nada. Um nó abortado
  por permissão negada deixava o run terminar `PASS`. Agora vira regressão — nó
  `optional` fica de fora, porque reforço que falha não invalida evidência que
  passou. Dois testes existentes caíram com isso e estavam medindo a coisa
  errada: as fixtures não cobriam o schema de `critique`/`test-plan`, o nó
  falhava, e o run saía verde.
- **A telemetria de custo subestimava o gasto real.** `spend()` é chamado
  depois da resposta do modelo, mas recusava sem registrar quando o gasto
  passava do teto — então a chamada que estourava sumia da conta justamente por
  ter estourado. Medido: `$0.001` reportados de `$0.051` gastos. Registra
  sempre, decide depois.
- **O gasto do juiz semântico não era checado.** Fase `evaluation` esgotada e o
  juiz continuava sendo chamado a cada nó: o teto era decorativo.
- **O cache guardava resposta reprovada na validação**, então o run seguinte
  com o mesmo objetivo recomeçava do que já se sabia ruim.
- **O cache de resposta e o `runtime-state` do `diagnose`** ficaram para trás na
  separação de raízes de estado.
- **A telemetria afirmava paralelismo no momento em que ele era cortado.** O
  tamanho do batch era contado antes do teto de concorrência: pool de 1
  reportava "paralelo 5", e justamente sob a degradação que reduz paralelismo.
- **Decompor podia aumentar o orçamento do pai.** O piso de 512 tokens por
  sub-tarefa, sem teto de largura, fazia 5 sub-tarefas de um pai com 2000
  somarem 2560. A largura passou a ser limitada pelo que o pai paga no piso.
- **Sub-tarefa herdava as permissões do pai** — inertes hoje, e é assim que
  privilégio indevido começa.
- **A memória contava retentativa como recorrência.** Um incidente com três
  retries virava três ocorrências do padrão, e recorrência é justamente o que
  decide se um padrão vira conhecimento reutilizável.
- **`budgetLimits.maxTokens` era descartado em silêncio** enquanto os outros
  cinco tetos do mesmo objeto eram honrados.
- **Estado de projeto vazava para a instalação do framework.** Sem
  `izanagi init`, `.izanagi/state` (trace, artefato com conteúdo, memória,
  checkpoint) era gravado dentro de `node_modules/izanagi-ai/` e compartilhado
  entre todos esses projetos: `izanagi trace` listava execução alheia, e
  `npm update` apagava o histórico. A causa é a mesma da anterior — uma raiz só
  respondendo duas perguntas diferentes. `resolveStateRoot` separa; projeto
  inicializado não muda de lugar, porque mover apagaria o histórico de quem já
  usa. Encontrado procurando o trace de um run de teste e achando 300 traces de
  outros projetos.
- **Groundedness reprovava documento correto.** A primeira versão do check
  resolvia referência só contra a raiz do repositório, e o `docs/HANDOFF.md`
  deste projeto saiu com **0 de 17** caminhos fundamentados: ele cita
  `runtime/protocol/conversation.ts`, que existe em `src/runtime/...`. Gente e
  modelo escrevem caminho relativo à raiz de FONTE, não à do repositório, e
  reprovar isso encheria a verificação de falso positivo contra exatamente o
  trabalho legítimo. A correção resolve contra a raiz e contra cada diretório
  de PRIMEIRO nível — só o primeiro, porque descer mais faria qualquer caminho
  casar em algum lugar e a checagem pararia de medir alguma coisa. Depois:
  17 de 17 no documento real, 0 de 4 no layout inventado. Encontrado rodando a
  checagem contra um documento de verdade em vez de só contra fixture.

### Limitações desta fase

- **A materialização não toca o código do projeto, e isso é a decisão, não a
  limitação.** Os arquivos vão para `<output>/<slug>/`; aplicar por cima da
  fonte exigiria uma garantia que nenhuma verificação determinística consegue
  dar hoje. Quem quer aplicar revisa e copia — e é aí que uma pessoa olha o
  diff, que é exatamente o passo que não se deve automatizar antes de tempo.
- **O manifesto só é reconhecido no formato combinado.** `### FILE: <caminho>`
  seguido de bloco de código. Inferir caminho do texto ao redor ou do nome da
  linguagem na cerca seria adivinhar o destino de um arquivo que vai ser
  gravado, e esse erro só aparece depois de gravado.
- **O survey conta, não julga.** Ele devolve stack, contagem por extensão e
  manifestos. Não devolve "o projeto usa arquitetura X": quem interpreta é o
  agente a jusante, e essa separação é deliberada.
- **Grounding não foi medido contra ausência de grounding.** A comparação
  honesta (mesmo objetivo, mesmo provider, com e sem survey) exige provider
  real e um gabarito de acerto. Está registrado como próximo passo, não como
  resultado.
- **`references-exist` mede lugar, não semântica.** Ele confere que o diretório
  citado existe; não confere que a função citada exista dentro do arquivo. Isso
  exigiria análise sintática por linguagem — o `python-engine/ast_analyzer` já
  faz parte disso, e ligá-lo à verificação é trabalho de outra fase.

## Fase 14: Os tetos que não limitavam nada (2026-09-04) ✅

Auditoria dos 49 itens de Definition of Done da especificação de evolução do
runtime contra o código real, item por item. O `RUNTIME-PENDING.md` afirmava
**nenhum item aberto**. A auditoria encontrou **doze tetos, campos e caminhos
que existiam no código, eram plumbados de ponta a ponta e não tinham caller
nenhum**, mais um bug de formato entre produtor e consumidor do mesmo
repositório.

Nenhum item desta fase é feature nova. Todos são peças que o runtime já
declarava ter. O padrão é sempre o mesmo, e é o que o `HANDOFF.md` diz
combater: **um limite declarado que nada aplica**.

- [x] **Cancelamento cooperativo do run.** Era o item aberto 1 das pendências, e
      foi fechado na mesma sessão: sem ele o prazo por nó era metade de uma
      garantia. O sinal é conferido no topo de cada batch, desce até a
      requisição (combinado com o timeout HTTP) e recusa a chamada antes de
      gastá-la quando já está abortado. **Ctrl-C na CLI cancela em vez de matar
      o processo**, e a combinação com o checkpoint por batch é o que dá valor:
      o progresso pago fica em disco e `izanagi resume` retoma dali. Dois bugs
      apareceram escrevendo o teste: o checkpoint de um run cancelado era
      APAGADO (o que anula o resume), e falha `non-recoverable` era retentada
      quando casava com um padrão da memória (o passo de padrão conhecido vinha
      antes da classificação decidir, e valia desde antes para permissão
      negada).
- [x] **`maxRetries` e `maxAgents` passaram a limitar.** `recordRetry()`
      existia desde a Fase 9 sem caller de produção, então `telemetry.retries`,
      `RunTrace.retries` e o teto do `budgetLimits` eram estruturalmente
      mortos: `izanagi budget`, `izanagi trace` e o dashboard mostravam 0
      retries num run que retentou três vezes, enquanto a Arena, contando por
      `node.attempts`, relatava o número certo. Duas contas do mesmo fato e só
      uma verdadeira. Contado antes de gastar a chamada, pelo mesmo motivo do
      teto de tool calls. `recordAgent` tinha o retorno booleano descartado.
- [x] **Teto de run estourado deixou de ser retentado.** A mensagem do teto de
      tool calls contém a palavra "tool" e casava com a regra
      `/tool|mcp|exec|command failed|exit code/` do `Healer`, virando
      recuperável: o runtime retentava um limite que não se move entre
      tentativas.
- [x] **Prazo por nó aplicado** (`orchestration/deadline.ts`). `node.timeoutMs`
      é escrito por todo o caminho de planejamento e vira
      `TaskContract.budget.maxTimeMs`; nada lia nenhum dos dois. **Metade de
      uma garantia, e está dito que é metade:** o prazo interrompe a espera,
      não o trabalho em voo. Cancelamento cooperativo é o item 1 das
      pendências.
- [x] **O Plano B do Commander ficou alcançável.** `replan` só era acionado por
      falha de PLANEJAMENTO. Reprovação da Verification Engine classifica como
      `validation` e ia direto para "troca a skill e tenta de novo", com o mesmo
      agente, mesmo papel e mesma decomposição: o caminho de falha mais comum do
      runtime era exatamente o "repetir" que o replanejamento existe para
      evitar. 1ª falha troca skill, 2ª replaneja.
- [x] **Roteamento por tarefa, não por run.** O `RoutingContext` era montado
      uma vez e reusado em todo nó com `risk: 0.2`, raciocínio `medium`, o teto
      de tokens do run inteiro e nenhum histórico. O `scoreModel` lê todos esses
      campos: metade dos critérios de roteamento estava implementada no scorer e
      nunca era alimentada.
- [x] **`--local` serializa o pool; `--max-concurrency` expõe o teto.**
      `LOCAL_MAX_CONCURRENCY` existia desde a Fase 8 com o motivo escrito no
      arquivo e zero referências no repositório.
- [x] **`allowedTools`: allowlist de tool do run inteiro.** Camada distinta da
      permissão do contrato, conferida antes dela e da política: a permissão diz
      o que a TAREFA pode fazer, a allowlist diz o que este RUN pode usar. Lista
      vazia proíbe toda tool, ausência é "sem allowlist".
- [x] **`BenchmarkCase.budget` / `.mode` / `.allowedTools`.** A base oficial não
      tinha como declarar o teto sob o qual um caso deve ser resolvido: custo era
      observado no relatório e nunca imposto na execução.
- [x] **Verificação por tarefa emite evento** (`task.verification.passed` /
      `.failed`). `quality_gate.*` é do veredito final: um nó que reprovava não
      emitia evento nenhum, e o dado só aparecia depois do await.
- [x] **Checkpoint por batch.** O docstring de `captureCheckpoint` já dizia "a
      cada rodada de batches" e não era verdade: um run interrompido no meio do
      grafo descartava todo o progresso da tentativa, e o `resume` pagava de
      novo chamadas já pagas.
- [x] **Nó aprovado sem prova carrega o fato.** `VerificationEngine.isDone` não
      tinha caller e o docstring dele contradizia o código. O nó segue como
      `succeeded` (derrubá-lo transformaria "não medi" em "está errado"), e
      passa a levar `metadata.unverified` mais uma mensagem A2A de tipo
      `evidence`.
- [x] **`parseFrontmatter` lê lista de bloco YAML.** A `SkillFactory` escreve
      exclusivamente lista de bloco e o parser só entendia inline: toda skill
      gerada pela Factory perdia em silêncio os `triggers` pelos quais
      `rankSkills` a encontraria.
- [x] **O registry para de descartar `model`, `permissions` e `evaluation`** dos
      22 agentes que os declaram em 22/22 arquivos. `declaredPermissions` tem
      esse nome porque é prosa do autor, **não** a concessão de permissão do
      runtime: um agente não se autoriza declarando o que quer.
- [x] **A lista literal de 19 agentes saiu do orquestrador.** Ela decidia se a
      Agent Factory geraria um agente novo, e esquecia 3 dos 22 core além de
      ignorar qualquer agente do projeto do usuário.
- [x] **Gate de banner de versão** (`scripts/doc-version.ts`). `bump` e
      `release` mexiam só no `package.json`: `ROADMAP`, `ARCHITECTURE`, `SYSTEM`
      e `RULES` diziam 3.10.0 e `AGENTS.md` 3.9.0 com o código em 3.18.0. Oito
      minors de drift, e a Fase 7 já tinha corrigido isso à mão uma vez. O
      banner **não** é estampado automaticamente: escrever uma versão num
      documento que ninguém leu é afirmar um número que não aconteceu.

### O que esta fase deliberadamente NÃO fechou

Catorze itens, cada um com critério de pronto, em
[`docs/RUNTIME-PENDING.md`](docs/RUNTIME-PENDING.md). Os de maior valor:
a camada determinística não executar teste do projeto
de verdade (a métrica `tests` vem de um artefato que um agente escreveu),
critérios de aceite falarem da forma do artefato e não do objetivo, o Decision
Journal ser write-only, e o cost-aware planning não comparar estratégias
alternativas nem ter piso de qualidade configurável.

Também está registrado ali que **três afirmações do próprio
`RUNTIME-PENDING.md` não se sustentavam no código** e foram corrigidas. Um
documento de pendências que afirma estar vazio é a pior versão da família de
defeitos que este runtime existe para combater.

Testes: **764, 763 passando** (69 novos). Cada teto novo tem teste que mede o
teto, não a contagem.

## Fase 15: A evidência que ninguém produzia (v3.20.0) ✅

Os catorze itens que a Fase 14 deixou abertos, fechados com implementação,
teste e medição. O padrão que eles compartilhavam é o irmão do da fase
anterior: lá era **um limite declarado que nada aplica**; aqui é **uma
evidência declarada que ninguém produz**.

Quatro exemplos do mesmo defeito, em lugares diferentes do runtime:

- a métrica `testResults` da avaliação vinha de um artefato `test-results` que
  um AGENTE escreveu — o runtime afirmava "testes passando" a partir de um
  texto produzido pelo mesmo processo que deveria estar sendo testado;
- todo critério de aceite era derivado do SCHEMA do artefato, então
  "adicionar paginação em GET /users" não produzia nenhum critério sobre
  paginação, e não havia por onde o usuário fornecer um;
- a camada semântica da memória era lida e nunca escrita pelo runtime, e o
  Decision Journal era escrito e nunca consultado: uma memória que não aprende
  e um registro que não lembra;
- das 106 skills, ZERO declaravam `triggers` ou `capabilities`, então o
  ranking escolhia entre 106 descrições soltas com dois arrays sempre vazios
  no haystack.

### O que entrou

| Capacidade | O que mudou na execução |
|---|---|
| `--verify-tests` | Nó `verify-tests` roda o comando de teste do PROJETO e o check `exit-zero` decide pelo exit code do processo. O comando vem do manifesto, o binário de uma allowlist fixa, `spawn` com `shell: false`, e nenhum campo de entrada carrega comando |
| `--acceptance` | O critério do usuário entra nos contratos das tarefas terminais. Prefixo conhecido vira determinístico; prosa vira semântico. Entrada malformada é recusada em voz alta |
| `--min-quality` | Os modos até o sugerido viram candidatos, cada um estimado pelo mesmo caminho de roteamento, e vence o mais barato que atinge o piso de VERIFICAÇÃO |
| `--reuse-artifacts` | Artefato de run anterior com a mesma pergunta entra no lugar da chamada e passa pela verificação inteira. A invalidação vem declarada antes do cache |
| `--allow-tool` | A allowlist que existia no Orchestrator, no SDK e no caso de benchmark ganhou flag |
| `HUMAN_REQUIRED` | Teto esgotado deixa de se confundir com falha por bug. A avaliação continua `FAIL`: ela mede a entrega, o status carrega o fato do processo |
| Decision Journal | Decisão leva o objetivo, o fim do run carimba o veredito, e o planejamento consulta por semelhança de objetivo. Agente queimado no mesmo objetivo sai da disputa |
| Memória semântica | `appendKnowledge` escreve conhecimento reutilizável com barra de recorrência, e `search()` passa a ser consultado por tarefa pelo Context Resolver |
| Linhagem e checksum | Travessia completa dos dois lados, comparação por conteúdo, `checksum` sha256 e `metadata` livre com teto |
| `EXTERNAL-TOOL-001` | Tool registrada em runtime exige aprovação humana, e `requiresApproval` virou pausa por `izanagi approve` em vez de campo que ninguém lia |
| Oito dimensões | `benchmark run --execute --compare` mede tokens, custo, latência, model calls, agent calls, retries, sucesso e verificação nos DOIS caminhos |
| Metadado de skill | As 22 mais acionadas pelas chains declaram `triggers` e `capabilities`, com gate que quebra se o campo esvaziar em massa |

### Compatibilidade

As quatro capacidades novas são **opt-in**. Sem elas, o plano, o grafo e o
veredito são byte a byte os de antes, e há teste que mede isso. A única adição
ao tipo do resultado é o valor `HUMAN_REQUIRED`; o exit code da CLI não mudou.

### O que esta fase deliberadamente NÃO fechou

Nada da lista de gaps ficou aberto. O que continua registrado como **escolha,
não dívida**, está em [`docs/RUNTIME-PENDING.md`](docs/RUNTIME-PENDING.md), e
três limitações dali só deixam de ser limitações contra um provider real:
grounding medido contra a ausência dele, a Arena com números de execução real,
e o critique loop exercitado por um modelo de verdade.

Duas limitações novas entraram na mesma lista, e as duas são de MEDIÇÃO, não de
implementação: o nó de teste mede a suíte do projeto e não o efeito da entrega
(quando o `--output` cai fora da árvore testada), e o piso de `--min-quality`
mede o quanto o plano se compromete a verificar, nunca a qualidade do que vai
ser entregue.

Testes: **838, 837 passando** (74 novos nesta fase; medido no Windows, onde o
único vermelho é `polyglot`, que passa no Linux). A fase foi publicada dizendo
"837, 837 passando" a partir de uma medição só no Linux: dois testes de
`project.test` falhavam no Windows, e o motivo virou linha na seção 3 do
[`docs/HANDOFF.md`](docs/HANDOFF.md).

## Fase 16: O executor que faltava (v3.22.0) ✅

O defeito não era de arquitetura: era de **alcance**. O runtime planejava,
roteava por papel, verificava por evidência, curava e replanejava — e, sem
API key configurada, executava os nós com `createHeadlessProducer`, que
SIMULA o artefato. Quem não quisesse colar uma chave nem subir um modelo
local tinha um planejador, não um runtime. É a diferença entre "o framework
está completo" e "o framework funciona na máquina de quem instalou".

### O que entrou

- **`claude-cli`: agente de codificação já autenticado como executor**
  (`runtime/llm/agent-cli.ts`). `AgentCLIAdapter` implementa `ModelAdapter`,
  entra no `LLMClient` como qualquer provider e atravessa run/SDK/`models`/
  juiz/arena sem que nenhum chamador mude. Não fala HTTP: spawna o `claude`
  em modo print, sem shell, prompt por stdin. **Zero configuração** — o
  binário é detectado no PATH.
- **As flags do CLI viraram os controles do runtime**: modelo do papel
  (`--model`), teto de custo restante (`--max-budget-usd`), política de tools
  (`--restricted`/`--tools`), escrita em opt-in (`--permission-mode
  acceptEdits`), sem estado residual (`--no-session-persistence`,
  `--strict-mcp-config`) e telemetria (`--output-format json`).
- **Custo MEDIDO substitui custo estimado.** `total_cost_usd` sobe pelo
  producer até o Budget Controller (`NodeProduction.costUsd`): `--max-cost`
  passa a ser cobrado sobre o gasto real, não sobre a tabela do catálogo.
- **`--agent-tools none|read|write`**: o executor roda sem tool alguma por
  padrão; `read` dá grounding real no repositório (`Read/Grep/Glob`), `write`
  autoriza alteração de arquivo. `Bash` não entra em nenhuma política. A
  política também entra na chave do cache de resposta (esquema v2).
- **Dois avisos que faltavam**: `izanagi doctor` passou a ter seção
  "Executor" dizendo quem vai rodar os nós AGORA, e `izanagi run` diz qual
  escolheu antes de começar — antes, "modo headless" era descoberto vendo o
  run simular.
- **Guarda de recursão e supressão em teste**: o filho recebe
  `IZANAGI_AGENT_CLI_DEPTH+1` e no teto o adapter degrada para headless;
  dentro de test runner o executor fica desligado, para que `npm test` nunca
  gaste cota real de quem rodou.
- **`izanagi export --cli claude --global`**: escopo pessoal em
  `~/.claude/{agents,commands,skills}`, para que os 22 agentes e a biblioteca
  de skills valem em todo projeto aberto (eram descobertos só por projeto, e
  quem abria a CLI em outro diretório concluía que o framework não funciona).
  Nunca escreve `~/CLAUDE.md`.
- **O agente do nó opina no modelo**: os 22 core declaravam `model` no JSON e
  o roteamento nunca lia o campo. Agora `agent-architect` sai em opus, um
  specialist em sonnet e a avaliação em haiku, no MESMO grafo, com o Commander
  determinístico decidindo isso sem gastar token.
- **Higiene de repositório e de disco, tudo achado executando de verdade**: a
  verificação de build escrevia ~700 arquivos na raiz do repo (sandbox que só
  era limpo no caminho de sucesso), o espelho de assets em `.agents/` era
  criado dentro do próprio repo do framework (~700 arquivos duplicando o que o
  repositório já é, e a razão das "duas pastas de agentes"), e 3.517
  diretórios temporários estavam acumulados no TEMP do usuário porque ~40
  suítes criam `mkdtempSync` e nenhuma remove. Novo `npm run clean:temp`,
  varrendo por prefixo conhecido e rodando dentro do `npm test`.
- **Dois bugs de artefato achados executando de verdade**: o survey do projeto reprovava
  como "stub/lazy-code" qualquer repositório que contivesse a palavra `TODO`
  (o run abortava no PRIMEIRO nó, culpando o runtime pelo vocabulário do
  projeto), e o teste de capacidades cobrava `model`/`evaluation` dos agentes
  de `agents/generated/`, que nascem sem eles.

Medições desta fase, no executor sem chave: um nó de specialist custou ~18.000
tokens com `tools=none` e ~68.000 com `tools=read`; o system prompt do próprio
CLI cai de 20.848 para 4.095 tokens de entrada com `--restricted --tools ""`
(US$ 0,042 → US$ 0,005 na mesma pergunta).

Limitação nova, e é de QUALIDADE, não de implementação: com `--agent-tools
read` o executor leu o repositório de verdade (acertou a versão exata do
`package.json`) e ainda assim reportou 5 providers onde havia 6, citando um
intervalo de linhas que terminava antes da entrada nova. Grounding real não é
grounding completo, e é por isso que a Verification Engine e os critérios de
aceite continuam sendo o que decide se um artefato passa.

Testes: **899, 895 passando, 0 falhando, 4 skipped** com motivo (49 novos nesta
fase). Primeira rodada verde no Windows: o `polyglot` era o único vermelho
havia várias versões, e a v3.22.1 mostrou que o motivo não era o Rust ausente,
eram dois caminhos de arquivo que só valiam em POSIX (`target/debug/<nome>` sem
`.exe`, e `.venv/bin/python` em vez de `.venv/Scripts/python.exe`). Três outras
falhas estavam escondidas atrás daquela: a asserção estourava depois do fim do
teste e chegava como `unhandledRejection`.

## Critérios de aceite das próximas fases

Toda mudança no framework deve provar impacto em pelo menos uma dimensão:

```
reliability · adaptability · correctness · observability
token waste reduction · recovery · extensibility · developer experience
```

E deve passar o quality bar completo: `build` → `test` → `doctor --deep` → `benchmark run` → documentação.