steward · git:20260829.d5ee857 · 2026-08-29 · sha256 8b31081f8b003730

steward git:20260829.d5ee857A

Immutable. This exact content is served forever at /api/v1/blob/8b31081f8b003730.

---
name: steward
description: Guia específica do GarraRUST para dirigir um PR até o verde — quais falhas de CI são ambientais, quais são suas, e o que validar antes de empurrar. Lida ao reagir a eventos de CI ou de review num PR.
---

# Steward — dirigindo um PR do GarraRUST até o verde

Esta skill é lida **no momento em que um PR seu fica vermelho ou recebe
review**. Ela não repete o `CLAUDE.md` (convenções de código, regras absolutas,
estrutura de crates) — vá lá para isso. Aqui está só o que morde nesse momento
específico, e que já custou ciclos de CI reais.

Ela **não** autoriza aprovar nem mergear PR, e não sobrepõe nenhuma regra
"nunca" da política de PR do harness (pular/desabilitar teste, reescrever
histórico de branch alheia, commit vazio para chacoalhar CI).

---

## 1. Antes de qualquer push

O `Format Check` é **bloqueante** e é o erro mais barato e mais frequente:

```bash
cargo fmt --all && cargo fmt --all -- --check
```

Rode isso **sempre**, mesmo em mudança que "só mexe em comentário". `cargo
check`, `clippy` e `test` passando **não** implicam fmt limpo — o rustfmt
reflui `params!`, `assert!`, `match` longos e reordena blocos `use`, e nada
disso aparece nas outras ferramentas.

> Caso real: PR #861 foi para o CI com 21 de 22 checks verdes e o único
> vermelho era fmt — 19 blocos em 8 arquivos, todos cosméticos. Um ciclo
> inteiro de CI (~25 min) perdido.

Depois, o mais próximo possível do que o CI roda:

```bash
cargo clippy --workspace --exclude garraia-desktop --all-targets -- -D warnings
cargo test  --workspace --exclude garraia-desktop
```

`garraia-desktop` é excluído em **todos** os jobs (clippy, build, test, msrv) —
faltam libs GTK e o sidecar Windows nos runners. Não tente "consertar" isso.

---

## 2. Falhas que NÃO são suas

Antes de investigar como defeito, descarte estas. Todas aparecem como falha
legítima e não são.

### `migration_smoke` — "failed to initialize a docker client"

```
Error: failed to initialize a docker client: Socket not found: /var/run/docker.sock
```

Os testes de `garraia-workspace` (e os de integração de `garraia-auth` /
`garraia-gateway`) usam testcontainers. **O container de dev não tem Docker.**
Nos runners Linux do GitHub tem, e lá passam — inclusive aplicando todas as
migrations via `sqlx::migrate!` em Postgres real. Se falhar só localmente com
essa mensagem, é ambiente. Diga isso explicitamente em vez de alegar que
validou.

### `utoipa-swagger-ui` — build script falha localmente

O `build.rs` baixa um zip do GitHub, e o proxy de egresso desta sessão bloqueia
o domínio; o "zip" gravado é uma página de erro JSON de 378 bytes. O `ci.yml`
já contorna pré-baixando com curl.

Para destravar localmente, **não apague o cache cegamente** (`find target -name
'v5.17.14.zip' -delete` remove também cópias válidas de builds anteriores —
erro já cometido). Gere o arquivo a partir do clone da tag:

```bash
git clone --depth 1 --branch v5.17.14 https://github.com/swagger-api/swagger-ui /tmp/swui
git -C /tmp/swui archive --format=zip --prefix=swagger-ui-5.17.14/ HEAD -o /tmp/v5.17.14.zip
export SWAGGER_UI_DOWNLOAD_URL="file:///tmp/v5.17.14.zip"
```

### "No space left on device" disfarçado de erro de compilação

`target/` chega a ~26 GB e o disco da sessão é uma cota fixa — `df` engana
(mostra "Avail" baixo com "Used" baixo). Sintoma típico: vários `could not
compile X` sem erro de tipo algum, e no meio um `error 28`. Cure com
`target/debug/incremental` primeiro (metade do peso), `cargo clean` se
necessário. **Commite e empurre antes de limpar**, para que um estouro não leve
o trabalho junto.

### Quality Ratchet reclamando de arquivos grandes

O baseline está congelado em 2026-05-05 e a `main` andou muito desde então.
As regressões de `max_file_lines` / `files_over_*` quase sempre são **deriva do
baseline, não suas**. Confirme antes de agir:

```bash
git diff --name-only origin/main..HEAD          # o arquivo apontado está aqui?
git show origin/main:<arquivo> | wc -l          # já tinha esse tamanho na main?
```

O modo é `report-only` (exit 0) e o check fica verde. **Nunca** edite
`.quality/baseline.json` à mão — é fraude; use `freeze-baseline.py`.

### CodeQL agregado em `neutral`

O check-run agregado "CodeQL" às vezes fecha como `neutral` enquanto os três
`Analyze (rust|actions|javascript-typescript)` fecham `success`. `neutral` não
é falha e não bloqueia. Olhe os três individuais.

---

## 3. Bump do wasmtime: o piso de MSRV vem junto

Já aconteceu **quatro vezes** (1.92, 1.93, 1.94, 1.95). Um PR do Dependabot que
sobe `wasmtime` costuma trazer **dois** bloqueios independentes, e o segundo
não aparece se você ler só o erro de compilação:

1. quebra de API em `crates/garraia-plugins/src/runtime.rs`;
2. `MSRV check` falhando **antes de compilar**, porque a árvore
   `wasmtime`/`cranelift-*`/`pulley-*`/`wiggle-*` declara um `rust-version`
   novo.

Corrigir só o código deixa o job de MSRV vermelho. Subir o piso toca
`Cargo.toml` (`rust-version`) **e** o `ci.yml` (nome do job, `dtolnay/rust-
toolchain@X.YZ`, e as duas invocações `cargo +X.YZ`). Prove nos dois sentidos:
o novo piso passa `--locked`, o antigo ainda recusa.

Não confie na sugestão do compilador em migração de API do `wasmtime-wasi`: no
bump 47→48 ele mandava trocar só `FilePerms` por `FsPerms` e **manter**
`DirPerms`, o que não compilaria.

---

## 4. Auto-merge está armado neste repositório

Ele dispara assim que os checks **obrigatórios** passam — o que pode ser
**antes** de todos os checks terminarem, e antes de você chamar merge.

Consequências práticas:

- **Nunca afirme que você mergeou** sem conferir `merged_at` e `merged_by`.
  Uma chamada de merge sobre PR já mergeado retorna "successfully merged" de
  forma idempotente, e o `commit_title` que você passou é ignorado.
- Por isso, **arrume o título do PR antes de ele ficar verde**. O squash herda
  o título do PR, e o auto-merge usa o valor em cache. Um título autogerado
  (`Claude/foo-bar-abc123`) vira assunto de commit na `main`, fora de
  Conventional Commits — e corrigir depois exigiria reescrever a `main`, o que
  é proibido.

---

## 5. O CI não roda em branch solta

`ci.yml` dispara em `push` para `main`/`develop`/`master` e em `pull_request`
para esses alvos. Empurrar uma branch **não** roda nada: sem PR aberto, não há
validação de CI. Planeje isso — e não peça para o usuário "esperar o CI" de uma
branch que não tem PR.

---

## 6. Ao reagir a um review

Achado de bot é relatório de defeito: verifique e corrija se for pequeno e
local. Se os achados pararem de convergir (cada correção gera um novo), pare de
empurrar e levante o assunto uma vez, dizendo o que continua sinalizado.

Pedido grande de revisor humano em PR que não é seu → responda com a proposta,
não empurre nem resolva a thread.

Mudança que toca segurança, auth, storage, RLS, secrets ou CI crítico: o
`CLAUDE.md` manda acionar os agents `security-auditor` e `code-reviewer` antes
de seguir.