Skip to content

Lote 3: os sete defeitos de comando do milestone 3 - #32

Merged
CRangelP merged 12 commits into
mainfrom
fix/rodada-2-lote-3
Aug 9, 2026
Merged

Lote 3: os sete defeitos de comando do milestone 3#32
CRangelP merged 12 commits into
mainfrom
fix/rodada-2-lote-3

Conversation

@CRangelP

@CRangelP CRangelP commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Fecha as sete issues do milestone "Rodada 2 - lote 3". São defeitos de comando: coisas que o agente executa e que falham, ou que passam quando deveriam falhar.

Fecha #17, #18, #19, #20, #21, #22, #23.

Duas mudanças de comportamento

Estas atingem repo real e não são refactor. Leia antes de mergear.

Repo poliglota não recebe mais GREEN se algum stack ficou sem suíte contável. Módulo Go sem *_test.go ao lado de um app JS testado é o caso típico: antes lia GREEN, agora capa em YELLOW. O veredito diz qual cap disparou. Isso fecha boa parte da #25, mas sem granularidade por stack no checks= — comentei lá o que ficou de fora.

Baseline vermelho virou RED, era YELLOW. Com a suíte já quebrada o gate nunca fica verde, e como todo commit exige gate verde, a skill anunciava YELLOW, gastava rodadas de knip e deleções, e entregava zero commits com tudo marcado como falha. O script de teste que o npm init escreve cai nesse caminho, e nenhuma doc avisa — está na #29.

O que cada issue era

#17 — o pipeline de churn usava --format=%H --name-only, então o hash do commit e a linha separadora entravam no mesmo fluxo dos nomes de arquivo. Num repo de 4000 commits a linha em branco liderava o ranking e os 4000 SHAs empatavam com os arquivos raros.

#18 — o exemplo de git mv não criava o diretório de destino, e a fase 3 existe para aplicar uma estrutura que ainda não existe. Exit 128, que o agente rodando sozinho lê como passo que falhou.

#19 — as três categorias da fase 1 liam um knip-report.json congelado. Elas se alimentam: apagar órfão mata export que o relatório via vivo. Agora o relatório é regenerado depois do commit de cada categoria.

#20 — tirar a dependência do package.json não a tira do node_modules, e o gate nunca instalava. Typecheck e teste passavam com a dep removida por engano, e a quebra aparecia na CI. O protocolo passa a rodar o install simples antes do gate, com o lockfile no commit da categoria.

#21 — o redirecionamento truncava o knip-report.json antes de o knip começar, então uma falha apagava o relatório anterior e deixava um arquivo vazio que o passo 1.3 lia como "nada a deletar".

#22 — a linha YELLOW da tabela prometia commits que o gate nunca deixaria acontecer.

#23 — o gate só reconhecia scripts com nome exato typecheck e test. Projeto com type-check ou test:unit caía em exit 3 e exigia gate manual mesmo tendo rede completa. Agora aceita type-check, check-types e uma fatia test:* quando ela é a única.

tsc ficou de fora da lista de propósito: como nome de script normalmente é compilação com emissão, e o gate escreveria .js/.d.ts na árvore que está julgando, que o git add -A do 1.3 levaria ao commit — e o rollback documentado não remove arquivo untracked. O custo disso está na #27.

Revisão

Quatro passadas de /code-review max --fix, 60 achados. As rodadas 2, 3 e 4 auditaram quase só o código que o --fix da rodada anterior tinha escrito, o que valeu a pena: a rodada 4 pegou uma regressão contra usuário existente que a 3 havia introduzido — repo JS verde com um requirements.txt do build da doc ficava capado em YELLOW para sempre.

O que não foi consertado virou issue: #24, #25, #26, #27, #28, #29, #30, #31.

Verificação

bash scripts/test.sh em bash 5 e no /bin/bash 3.2 do macOS:

gate_test.sh        86/86 cases passed
rollback_test.sh    5/5 properties held
coherence_test.sh   77/77 invariants held

shellcheck scripts/*.sh sem achado novo, bash -n limpo.

Os dois invariantes novos foram provados por mutação, e os autotestes deles também: dois eram vazios na primeira escrita e passavam verde com a regra apagada. A seção 7 nasceu vazia para a própria regressão da #22 — reverter a linha RED para YELLOW passava 61/61 — e isso só apareceu na primeira revisão.

CRangelP added 12 commits August 8, 2026 19:30
O pipeline prescrito usava --format=%H --name-only, que joga o hash do
commit e a linha separadora no mesmo fluxo dos nomes de arquivo. O uniq -c
contava os tres como se fossem arquivos: a linha em branco liderava o
ranking e cada SHA empatava em 1 com os arquivos raros.

audit.md pedia os '20 mais modificados' sem dar receita nenhuma, entao
recebeu o mesmo one-liner corrigido em vez do convite a rederivar o
quebrado.

Closes #17
O redirecionamento direto abria e truncava knip-report.json antes de o
knip comecar, entao qualquer falha (config quebrada, plugin, OOM) apagava
o relatorio anterior e deixava um arquivo vazio, que o passo 1.3 le como
'nada a deletar'. Falha silenciosa em vez de erro visivel.

Passa a escrever em .tmp e mover so em caso de sucesso. --no-exit-code e
o que torna o && utilizavel: knip sai 1 sempre que encontra algo, que e o
caso normal aqui, e 2 so quando de fato falhou. Comando byte a byte igual
nos dois arquivos.

Closes #21
…r deps

As tres categorias liam um knip-report congelado. Elas se alimentam: apagar
arquivo orfao mata export que o relatorio ainda via vivo e libera dep que
via usada, e export listado como morto pode estar em arquivo ja removido
pela categoria anterior. O ciclo passa a regenerar o relatorio depois do
commit de cada categoria, e a contagem final vira estado medido.

Tirar a entrada do package.json nao tira o pacote do node_modules e o gate
nunca instala, entao typecheck e teste passavam com a dep removida por
engano e a quebra so aparecia na CI. O protocolo passa a rodar o install
simples do package manager antes do gate, com o lockfile entrando no commit
da categoria. Forma congelada fica de fora: --frozen-lockfile e --immutable
recusam manifesto podado, e npm ci deixa o lockfile obsoleto (medido em npm
11 e 12: sai 0, mas nao reescreve o lock). gate.sh nao muda.

Inclui o mkdir -p no exemplo de git mv da fase 3 (parte de #18), para casar
com references/phase-3-structure.md.

Closes #19, closes #20
O exemplo canonico de movimentacao nao criava o diretorio de destino, e a
fase 3 existe justamente para aplicar uma estrutura que ainda nao existe:
git mv para diretorio inexistente morre com exit 128, e o agente rodando
sem supervisao le isso como passo que falhou, ou parte para mv + git rm,
que a propria doc proibe por atrapalhar a deteccao de rename.

Secao 6 do coherence_test amarra as duas coisas: todo arquivo de protocolo
com linha de comando git mv precisa do mkdir -p na linha imediatamente
acima. Mencao em prosa nao conta (ancora em ^git mv). Piso derivado no
mesmo estilo da secao 4.

O item nao entrou na lista 'Do not forget': aquela lista e sobre o que
aponta para caminho antigo e quebra em silencio; diretorio faltando aborta
alto, antes de mover, e e lido depois do fato. Ficou junto do comando.

Closes #18
O gate so reconhecia scripts com nome exato typecheck e test, entao
projeto com type-check ou test:unit caia em exit 3 e exigia gate manual
mesmo tendo rede de seguranca completa. Falhava fechado, nunca dava verde
falso, mas custava a autonomia que a skill promete.

Passa a aceitar typecheck/type-check/tsc/check-types e test/test:unit, com
o primeiro nome definido pelo projeto vencendo e os demais ignorados. O que
chega em run() e o KIND, nunca o apelido: run() classifica por kind, e
nome cru ali faria o check rodar, passar e nao contar, caindo em exit 3 do
mesmo jeito. checks= mantem o vocabulario canonico; o apelido aparece so na
linha humana. bash 3.2, sem arrays.

6 casos novos no gate_test (57 -> 63), incluindo o ramo yarn com lockfile,
que ate agora nao tinha teste nenhum.

Closes #23
…contecer

A tabela admitia 'tests exist but fail' em YELLOW e prometia rodar a fase 1
em deps e orfaos. Mas o gate sai 1 em qualquer check vermelho e o passo 1.3
exige gate verde antes de cada commit: com suite vermelha preexistente todo
gate falha, o protocolo manda reverter e seguir, e nenhuma categoria
commita. A skill anunciava YELLOW, gastava rodadas de knip e delecoes, e
entregava zero commits com tudo marcado como falha.

YELLOW passa a ser rede parcial, igual ao que os READMEs ja diziam, e
baseline vermelho vira RED com diagnostico: sem verde inicial nao da para
separar o que a faxina quebrou do que ja estava quebrado. Os READMEs
tambem paravam de mencionar que a fase 2 trava no checkpoint no nivel
GREEN - corrigido nos dois.

Secao 7 do coherence_test amarra as tres tabelas: mesma sequencia de niveis
nos tres arquivos e condicao canonica de YELLOW na linha da tabela, com o
PT casando a versao em portugues. O grep orfao do Step 0 e a redacao antiga
de YELLOW entraram na lista de strings mortas da secao 3.

Tambem remove o grep de package.json do Step 0 (resto de #23): nenhum dos
tres paragrafos seguintes o consumia, o papel passou para o gate.sh, e ele
casaria o nome de uma dependencia chamada 'test'.

Closes #22
Os numeros gravados (57/57, 5/5, 49/49) estavam corretos na base desta
branch e foram invalidados por ela: os casos do gate foram a 63 com os
apelidos de script, e os invariantes a 61 com as secoes 6 e 7.
O mais grave: a secao 7 do coherence_test era vazia para a propria
regressao que motivou a #22. O colapso de repeticoes consecutivas fazia
GREEN,YELLOW,YELLOW,RED ler como 'GREEN YELLOW RED', entao trocar a linha
RED por YELLOW passava 61/61 verde. Agora ancora na tabela de niveis e
checa a condicao canonica de YELLOW e de RED.

Secao 6 estava rigida e frouxa ao mesmo tempo: exigia mkdir -p na linha
imediatamente acima (reprovava um mkdir servindo dois moves, que e a forma
natural) e ancorava em coluna 0 (comando indentado dentro de lista passava
invisivel). Vira cobertura por bloco, sem ancora de coluna, com IFS preso
em newline para nao quebrar em caminho com espaco.

gate.sh: a string com dois-pontos vira run_first <kind> <nomes>, sem split
sem aspas e sem o comentario que dizia 'sem arrays' num arquivo que ja usa
array indexado. Comportamento identico.

SKILL.md: exit 1 nao emite linha checks=, entao classificar por ela nao
funcionava no vermelho; a validacao do relatorio passa a checar a ausencia
do .tmp, que e o unico sinal que distingue relatorio fresco de relatorio
velho; knip-report entra no .git/info/exclude para o git add -A nao
commitar artefato da ferramenta no repo do usuario; o install entra na
linha da sequencia de 1.3, nao so no paragrafo 20 linhas abaixo.

audit.md e phase-2-consolidation.md: --since restaurado no ranking de
churn, que tinha perdido a janela de 6 meses da propria frase.

Suite 61 -> 66 invariantes, com os dois extratores novos ganhando
autoteste na secao 0.
Dois defeitos na lista de apelidos introduzida em 5f35d14.

tsc como nome de script normalmente e compilacao com emissao, nao check.
O gate escreveria .js/.d.ts/.tsbuildinfo ao lado dos fontes da arvore que
esta julgando, o git add -A do passo 1.3 levaria isso para o commit da
faxina, e o rollback documentado (git restore --staged --worktree .) nao
remove arquivo untracked. Ficam typecheck, type-check e check-types, que
nao sao ambiguos.

test:unit contava como suite canonica sem olhar o resto do manifesto,
entao projeto com test:unit e test:e2e e sem test ia a GREEN tendo rodado
so a fatia unitaria - e GREEN e o que libera delecao de export e as fases
2 e 3. Agora test simples sempre vence; na ausencia dele, um test:* so
conta se for o unico. Com duas ou mais fatias o gate nomeia as que achou,
nao conta nenhuma, e o projeto cai no teto YELLOW, que e o veredito
honesto para uma suite que ele nao consegue rodar inteira.

Regra generalizada para qualquer test:*, nao so test:unit: projeto cujo
unico ponto de entrada e test:integration continua funcionando, que era o
ganho de autonomia da #23.

5 casos novos (63 -> 68), incluindo check-types, que nao tinha fixture
nenhuma e podia ser removido da lista sem nenhum teste reclamar. O caso
js-alias-tsc virou fixture anti-regressao do comportamento oposto.
Defeito introduzido pela regra do test:* unico: script de watch era
promovido a suite inteira. Com {typecheck, test:watch} o gate rodava
npm run test:watch, que nunca termina, e saia 4 depois de 900s - que a
SKILL.md define como 'rede nao pode ser medida, nao rode sozinho'.
Reproduzido com GATE_TIMEOUT=3. test:watch, test:ui e test:debug ficam
de fora da promocao.

O ramo de multiplas fatias imprimia linha propria em vez de passar pelo
no_tests(), entao nunca emitia o marcador 'test' not counted que a
SKILL.md manda usar para classificar - o agente nao distinguia essa
YELLOW de um stack genuinamente sem suite, e o conselho de promover a
mao estava exatamente invertido. E js_test_script descartava o exit do
node: qualquer falha depois da sonda de parse virava string vazia, sem
diagnostico, o unico caminho mudo do script inteiro. Agora imprime e
seta incomplete.

coherence_test: o invariante do mkdir so exigia que ALGUM mkdir -p
precedesse o move, nao que ele criasse o destino daquele move - plano
com duas pastas passava verde com o segundo git mv morrendo em 128.
Dois autotestes eram vazios (provado por mutacao: apagar cada regra
mantinha a contagem) e level_row casava o nivel em qualquer lugar da
linha, entao prosa citando outro nivel sequestrava a assercao.

Secoes 8 e 9 novas: comandos canonicos de knip e churn, e a contagem de
casos dos READMEs derivada do gate_test - que e a classe de drift que
produziu o numero errado no commit 8403489 (63 gravado, 68 real).

Docs: vocabulario de apelidos e fatias documentado (so existia em
comentario do gate.sh), bullet RED dos limites conhecidos nos dois
READMEs ainda trazia a definicao antiga, .git/info/exclude nao cobre
arquivo ja rastreado, node_modules reinstalado antes do git add -A em
repo que depende de gitignore global, e o .tmp que faltava no passo 6
do knip-config.

Suite 68 -> 70 casos e 66 -> 77 invariantes.
O cap de suite fatiada era derrotado em repo poliglota: outro stack
fornecia test, checks= lia typecheck,test e o gate anunciava GREEN com a
suite JS inteira sem ter rodado. Mesma classe para go, rust, .NET e o
pytest-5, porque no_tests nao setava nada que o veredito lesse.

uncounted_suite() passa a marcar todo cap de stack inteiro, e o veredito
recusa GREEN quando a marca esta ligada, dizendo por que. O cap por
projeto do .NET fica no no_tests simples: projeto sem teste ao lado de
outro com teste e normal.

MUDANCA DE COMPORTAMENTO: repo poliglota que antes lia GREEN passa a
capar em YELLOW quando qualquer stack ficou descoberto. Modulo Go sem
*_test.go ao lado de app JS testado e o caso tipico.

Outros achados do proprio codigo novo: a exclusao de watch era ancorada
no fim, entao test:watch:all voltava a ser promovido e o gate travava
ate o timeout; fatia com comando vazio era filtrada por truthiness e
duas metades viravam uma so, devolvendo GREEN; run_first tratava
qualquer exit nao-zero do node como 'script nao definido' e derrubava o
typecheck em silencio - a mesma assimetria que a rodada anterior tinha
corrigido do lado do teste, um bloco abaixo. Manifesto sem nenhum script
de teste tambem nao emitia marcador nenhum, entao a frase da SKILL.md
sobre classificar por 'test' not counted era falsa.

coherence_test: gitmv_orphans lia o destino como , entao git mv -f,
caminho com aspas ou move de varias fontes eram checados contra o token
errado; level_rows ancorava na primeira linha com | citando um nivel, e
tabela vizinha sequestrava o extrator. Secao 9 contava 70 call sites dos
quais 10 vivem atras do guard de perl - a premissa agora esta escrita.

audit.md: a justificativa do --no-merges estava factualmente errada
sobre o git (log --stat nao imprime arquivo de merge por padrao); vale
o aviso contra -m no lugar dela.

Suite 70 -> 75 casos.
A quarta passada auditou o que a terceira escreveu, e o uncounted_suite
tinha cinco veredictos falsos.

Regressao contra usuario existente, a mais grave: os caps novos de Python
e Ruby disparavam nos marcadores mais frouxos do script - requirements.txt
ou Gemfile soltos. Repo JS verde com um requirements.txt do build da doc
passava a capar em YELLOW para sempre, sem resposta possivel, quando antes
lia GREEN. Os caps agora exigem fonte .py de verdade, ou .rb com gemspec.

.NET por projeto chamava no_tests puro, entao stack .NET onde NENHUM
projeto tem teste nunca marcava uncounted e ainda anunciava GREEN - o
buraco exato que a marca existia para fechar. Vira acumulador
dotnet_counted; cap por projeto ao lado de projeto com teste continua
sendo no_tests simples, que e o caso normal.

JVM usava run both, que conta test incondicionalmente: pom.xml sem
src/test dava GREEN, e mvn -q test sai 0 em modulo sem classe de teste.
Ganhou varredura de evidencia de fonte de teste.

ui estava no mesmo denylist de watch e debug, mas denylist tira a fatia
da CONTAGEM, nao so da execucao: {test:unit, test:ui} virava fatia unica e
subia a GREEN com a metade de UI sem rodar. watch e debug sao modo da
mesma suite; ui e escopo proprio. Agora ui nao roda mas conta.

E o veredito com elif descartava metade da mensagem quando os dois caps
batiam junto - os testes so grepavam a substring YELLOW, presente nas
duas, entao nada reclamava.

Docs: npm ci nao 'aceita a remocao', ele falha com EUSAGE em manifesto
dessincronizado (a rodada 1 tinha medido npm 12 e escrito o contrario);
.git/info/exclude vira git rev-parse --git-path, que e o unico que
funciona em worktree e submodule; o find -type d -empty -delete da fase 3
era varredura cega em src/ e virou rmdir por nome.

11 casos novos (75 -> 86), um por defeito. A fixture jvm-hybrid ganhou
src/test/java: ela passava pegando carona no bug.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@CRangelP
CRangelP merged commit 8712f88 into main Aug 9, 2026
2 checks passed
@CRangelP
CRangelP deleted the fix/rodada-2-lote-3 branch August 9, 2026 04:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant