No description
Find a file
Jonatas Oliveira 22c93e0d6e fix(hooks): consertar onde o teste de mutação grava e onde ele compila
Duas correções no `mutacao()`, ambas descobertas rodando o hook nos quinze
repositórios.

`--output .`: o cargo-mutants grava o `mutants.out` na raiz do WORKSPACE,
não no diretório de onde foi chamado. Nos repositórios que também são
membros de um workspace maior o relatório ia parar um nível acima, fora do
repositório, e a checagem do teto não achava o arquivo -- reprovando um
crate que não tinha deixado nenhum mutante escapar (o battleship-common
foi reprovado assim, com 65 mutantes e 0 sobreviventes).

TMPDIR no disco: o cargo-mutants copia a árvore e compila a cópia no
TMPDIR, que aqui é /tmp em tmpfs -- memória. Uma árvore de build do `iced`
dentro dele esgotou a RAM da máquina. O scratch passa a ficar em
~/.cache/cargo-mutants, com CARGO_MUTANTS_TMPDIR para quem quiser outro
lugar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhdPjHUuVhXaitwT4mG53t
2026-09-05 13:31:07 +02:00
.cargo ci: run cargo-mutants from the workspace root 2026-09-02 11:29:50 +02:00
.githooks fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:31:07 +02:00
.woodpecker ci: tirar a mutação do pipeline e rodar o CI inteiro no pre-commit 2026-09-05 12:17:37 +02:00
client@667c034e99 fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:31:07 +02:00
server@51d2e052e2 fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:31:07 +02:00
tatic_lib@4d4d77f95b fix(hooks): consertar onde o teste de mutação grava e onde ele compila 2026-09-05 13:31:07 +02:00
.gitignore build: turn the three submodules into a workspace 2026-09-01 22:21:00 +02:00
.gitmodules fix(ci): give the workspace submodules a mapping and a recursive clone 2026-09-03 08:43:44 +02:00
Cargo.lock build: turn the three submodules into a workspace 2026-09-01 22:21:00 +02:00
Cargo.toml ci: give each submodule its own pipeline, and a manifest that stands alone 2026-09-03 13:28:26 +02:00
LICENSE build: turn the three submodules into a workspace 2026-09-01 22:21:00 +02:00
README.md ci: tirar a mutação do pipeline e rodar o CI inteiro no pre-commit 2026-09-05 12:17:37 +02:00

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/:

  • spider varre o espaço de entradas com proptest em 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.
  • mutantes existe porque cargo mutants mostrou defeitos que a suíte não percebia. No tatic_lib eram os limites de Coord::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.