- Shell 100%
Um teto sobre zero mutantes aprova sem medir. Foi o que aconteceu no battleship-client: as exclusões do .cargo/mutants.toml cobriam o crate inteiro, o cargo-mutants dizia "Found 0 mutants" e a checagem imprimia `sobreviventes=0 teto=0` -- que se lê como perfeição e significa silêncio. O hook levava 2 segundos e não verificava nada. Agora, se a soma de caught, missed, unviable e timeout for zero, a etapa falha e diz o que fazer: encolher as exclusões ou remover o .mutants-teto. Um portão que aprova sem medir é pior do que portão nenhum, porque dá a impressão de cobertura que não existe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PhdPjHUuVhXaitwT4mG53t |
||
|---|---|---|
| .cargo | ||
| .githooks | ||
| .woodpecker | ||
| client@26c2afcbb6 | ||
| server@de9208abb3 | ||
| tatic_lib@70e68e3544 | ||
| .gitignore | ||
| .gitmodules | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
RPG ASCII Tático
Jogo de tática por turnos num tabuleiro 8x8, com servidor HTTP/WebSocket e cliente gráfico. Escrito como protótipo de curso de Rust.
Dois jogadores movem unidades pelo tabuleiro; vence quem alcançar a base inimiga ou eliminar as unidades do adversário. Há uma IA que joga sozinha, em duas versões — uma gulosa e outra guiada por busca de caminho.
Estrutura
Este é um workspace com três crates, cada um em seu próprio submódulo git:
| crate | o que é | repositório |
|---|---|---|
tatic_lib |
as regras do jogo: tabuleiro, ações, vitória, pathfinding e IA | tactic_lib |
server |
API HTTP + WebSocket em axum, guarda as partidas em memória | tactic_server |
client |
interface gráfica em iced | tactic_client |
Cada um tem o seu próprio pipeline, que responde a uma pergunta que esta
build integrada não responde: o crate se sustenta sozinho? Por isso o
servidor e o cliente declaram tatic_lib pelo repositório dela, e não
por caminho — sem isso um clone isolado nem compila. Dentro deste
workspace o [patch] do Cargo.toml da raiz redireciona essa
dependência de volta para o diretório ao lado, então a build integrada
usa o código do submódulo, no SHA fixado aqui, e não a ponta de main.
tatic_lib é a fonte única da verdade: servidor e cliente dependem dela
para concordar sobre o que aconteceu no tabuleiro. Nenhum dos dois
reimplementa regra nenhuma.
cargo run -p server # sobe o servidor em :3000
cargo run -p client # abre o cliente
Como os crates são submódulos, depois de clonar:
git submodule update --init --recursive
Testes
cargo test --workspace # 322 testes
cargo test -p tatic_lib --test spider # propriedades (proptest)
cargo mutants -p tatic_lib # índice de mutação: 0 sobreviventes
Cada crate tem duas suítes documentadas em tests/:
spidervarre o espaço de entradas comproptestem vez de fixar casos. É onde moram as leis do domínio: ir e voltar é a identidade, a distância de Manhattan é uma métrica, todo caminho do BFS é contíguo e mínimo, e nenhuma sequência de ações faz unidade aparecer do nada.mutantesexiste porquecargo mutantsmostrou defeitos que a suíte não percebia. Notatic_liberam os limites deCoord::orthogonal_neighbors, a função que sustenta pathfinding, IA e validação de movimento — chamada por todo lado, mas com os vizinhos nas bordas nunca conferidos. No servidor, era todo o caminho do WebSocket, que nenhum teste abria; agora a suíte sobe o servidor de verdade numa porta efêmera e conecta um cliente real.
Os sobreviventes que restam estão listados no fim de cada suíte com o
motivo. Vale notar que 176 dos 216 mutantes do servidor são "unviable":
o cargo mutants não consegue gerar uma mutação que compile para a
maioria dos handlers async do axum.
Verificações antes do commit
O .githooks/pre-commit roda aqui o que o Woodpecker roda no servidor. Ele
é gerado a partir do .woodpecker/pipelines.yml deste repositório, então os
comandos não podem divergir do CI. Ative uma vez por clone -- o hook é
versionado, a configuração que aponta para ele não é:
git config core.hooksPath .githooks
Roda tudo a cada git commit, do mais barato ao mais caro, e para no
primeiro que falhar: lint do pipeline, cargo fmt --check, clippy com -D warnings, build, testes, cobertura (piso 95%), auditoria de dependências e
a perna MSRV 1.90.
O teste de mutação só existe aqui. Ele saiu do pipeline: mutação
recompila o crate uma vez por mutante, e no runner isso eram dezenas de
minutos por push, num passo que ninguém acompanha enquanto espera. O teto
continua em .mutants-teto, versionado -- a regra não afrouxou, mudou de
lugar. É de longe a etapa mais lenta; para pular só ela:
PRE_COMMIT_SEM_MUTACAO=1 git commit ...
Para pular tudo, git commit --no-verify. Um hook que não se pode pular é
um hook que todo mundo desativa.
Licença
GPL-3.0-or-later. Veja LICENSE.