Releases: AllanSantos-DV/token-guard
Releases · AllanSantos-DV/token-guard
Release list
v2.2.0 — economia de saída, contrato com evidência real, replay sobre sessões reais
Economia de SAÍDA, contrato com evidência real, replay sobre sessões reais e o
backlog de hardening zerado (16 itens → 13+4 fechados, só monitoramento restante
— mapa em docs/BACKLOG.md).
Adicionado (rodada 2 — fechar tudo antes de lançar)
- Replay de transcripts REAIS (
bench/replay-transcripts.cjs): percorre os
JSONL de sessões passadas do Claude Code e roda o decide() atual sobre cada
chamada histórica. Na máquina do autor: 65 sessões, 8.197 chamadas → 28 denies
legítimos, ~437k tokens líquidos estimados — e a auditoria dos suspeitos
expôs duas classes de falso positivo que nenhuma suíte pegava (abaixo). - bigResult substitui de verdade também no Claude Code: v2.1.121 estendeu
updatedToolOutputpara todas as ferramentas; o post-hook emite o stub como
substituição (versões antigas: orientação, nunca bloqueio). - Cursor ganha broadScan de volta: o Cursor passou a expor
preToolUse
genérico com matcher por tipo de ferramenta — adapter traduz o evento e o
instalador registra; todas as 4 regras disparam nas versões recentes.
Adicionado (rodada 1)
- Regra
bigResult(pós-execução) —lib/postresult.cjs+ adapter
PostToolUse: resultado de ferramenta acima de ~25k caracteres vira stub com
preview (cabeça+cauda), versão integral gravada em.token-guard/results/
e a alternativa barata da família pronta para reexecutar. No modo plugin do
Copilot a substituição é REAL (modifiedResultdo SDK); no Claude Code o
hook de comando orienta (additionalContext) — diferença documentada em
docs/IDES.md. Fail-open absoluto (objeto circular, root impossível → passa
intacto). - Injeção automática do contrato — adapter UserPromptSubmit fecha o
circuito que estava aberto; e agora com evidência real: o PostToolUse
acumula os arquivos tocados da sessão (dedupe, teto 50) e as seções
quando:codigo/teste/docsentram conforme o tipo de trabalho. No modo
plugin do Copilot,onUserPromptSubmittedinjeta pelo mesmo estado. - mcp-cost acionável — seção RECOMENDAÇÕES: servidores >1,5k tok de schema
recebem sugestão de corte/slim; ferramentas >500 tok, de encurtar descrição.
Recomendação condicional ao uso real; servidor que falhou nunca recebe
recomendação inventada. E--extra-files a.json,b.jsontraz configs fora dos
locais conhecidos (Zed, JetBrains, frotas próprias) para o inventário. - Skill token-economy v2 — levers externos validados por pesquisa:
compaction, model routing, cache-friendly habits, CLI>MCP, slimming de MCP,
sub-agentes — com fontes. docs/BACKLOG.md: melhorias óbvias fora de escopo ficam anotadas (origem +
esforço) e são atacadas quando o escopo corrente fecha — política do dono,
espelhada no Brain.- Teste EPIPE (
test/epipe.test.cjs): stdout destruído com o filho vivo —
exit 0, zero stack trace. CI ganhou Node 16 na matriz (engines >=16 passou a
ser testada de fato);npm testroda as dez suítes.
Corrigido
- Re-gate da rodada de features (reviewer + tester independentes), 7 achados:
- knobs novos fora de
DEFAULTS.limitsburlavam osanitize(): config lixo
("resultCharsWithoutTrim": "abc"→ NaN) truncava TODA saída de ferramenta.
Chaves registradas nos defaults + validação local emlib/postresult.cjs; cfgsemlimitsdesligava bigResult silenciosamente (TypeError engolido
pelo fail-open) — defaults locais resolvem, e o teste que passava pelo
motivo errado foi reescrito;- registro VIVO em layout antigo coexistia com o novo (dois guards por
evento para sempre) → substituído com aviso (layout antigo substituído); - matcher drift congelado para sempre em quem já tinha instalado → matcher
atualizado automaticamente quando difere do atual; - dedup de PostToolUse/UserPromptSubmit olhava só
hooks[0](duplicava
canônico escondido após hook forasteiro) →reconcile()único com flatMap; - flag de "obsoleto reparado" vazava entre eventos (mensagens mentirosas)
→ estado por evento; - EPIPE derrubava os hooks novos via evento de stream; e prompt-hook
persistia estado ANTES de emitir (entrega falha = contrato perdido na
sessão) → handler de erro + emitir antes de persistir; - colisão de session-id sanitizado (
sess/1≡sess:1) suprimia injeção
entre sessões distintas → sufixo sha1 do id original quando sanitizado.
- knobs novos fora de
- Backlog P1:
writeJsondo instalador atômico (temp + rename — crash não
trunca mais o settings.json do usuário); matcher drift também no alvorepo;
CFG.loadmemoizado (TTL 2s, env na chave) para o modo plugin deixar de
re-walk a árvore a cada evento. renderAdvice: recomendações além da 8ª aparecem como "+N restantes";
renderTexttoleracharsPerTokenausente/zero (via API programática).- Identidade de sessão sem id do harness deriva da raiz (hash), em vez de um
'sem-sessao'global que misturava estado entre repositórios. - Removido
debug.logesquecido na raiz.
Corrigido (rodada 2 — achados do replay real)
- noisePath barrava leituras legítimas FORA do workspace (scratchpads e
outputs de tarefa do próprio harness em%TEMP%\claude\…): o ancestral
Tempcasava com a lista de ruído quando o caminho escapava da raiz. Caminho
fora do workspace não é ruído — é contexto escolhido. No replay real isso
eram 69 denies injustos numa máquina só; agora são zero. git ls-files docs/plans/escopado era negado como dump inteiro; agora segue
a mesma regra da busca por conteúdo: caminho explícito = barato, sem caminho
= árvore inteira (barrado).