MÓDULO 4.6

Prompt 05 — Safety Pass e Produção

📚

Tópicos

6

⏱️

Minutos

50

🎯

Nível

Avançado

🔒

Tipo

Safety

1

O que o Prompt 05 Entrega

Auditoria das 6 primitivas + integração GitHub + configuração por repo

O Prompt 05 é o safety pass — o prompt que transforma um plugin que funciona em condições ideais em um plugin que funciona em produção. Toda edge case não coberta aqui vai manifestar no pior momento possível.

💡 Deliverables do Prompt 05
1.Auditoria de todos os scripts contra as 6 primitivas de segurança
2.Integração gh pr comment para postar relatório no PR
3.Arquivo .claude/review-config.yaml com configuração por repo
4.Teste E2E completo: PR real → 3 rodadas → relatório → comment
2

O Prompt 05 Completo

Cole este texto no Claude Code com o SPEC.md em contexto

Prompt 05 — Cole no Claude Code

05_safety_pass_and_production.md
Read SPEC.md — the safety invariants section is your audit checklist.

You are building Prompt 05: the safety pass.
Audit every script against the 6 primitives, then add GitHub
integration and repo configuration.

**Part A — Safety Audit (audit each file, fix what's missing):**

For every .sh file in the plugin, verify and fix:

1. ERR trap:
   - Present as FIRST active line?
   - Does it print to stderr and exit 0 (not exit 1)?
   - Fix any script where it's missing or exits non-zero.

2. Atomic writes:
   - Every write to state/review.yaml goes through write_state_atomic?
   - No direct `echo > state/review.yaml` anywhere?
   - Fix any direct writes found.

3. CAS on state transitions:
   - Every status change in stop-hook.sh uses cas_state?
   - Fix any status write that bypasses CAS.

4. Lockfile:
   - stop-hook.sh acquires lock at entry?
   - EXIT trap releases it?
   - Stale lock: add check — if lock exists but PID in it is dead, remove.
   - Implement: `if [ -f state/review.lock ]; then
     lock_pid=$(cat state/review.lock 2>/dev/null || echo "")
     if [ -n "$lock_pid" ] && ! kill -0 "$lock_pid" 2>/dev/null; then
       rm -f state/review.lock  # stale lock — safe to remove
     fi; fi`

5. Path validation:
   - All scripts that receive a path argument validate it starts
     with /tmp/pr-review- before using it.
   - Implement: `[[ "$WORKTREE_PATH" == /tmp/pr-review-* ]] ||
     { echo "Invalid path: $WORKTREE_PATH" >&2; exit 0; }`

6. Subprocess timeouts:
   - runner scripts use `timeout 120 claude --print` not bare `claude`.
   - Fix any runner that calls claude without timeout.

**Part B — GitHub Integration:**

In scripts/generate-report.sh, after saving the report file:

Read .claude/review-config.yaml (use `yq` or manual grep fallback).
If `post_to_github: true` (default true):
  `gh pr comment $PR_NUMBER --body-file .claudex/reviews/PR-$PR_NUMBER-*.md`

Handle gh failure gracefully (log error, don't abort).

**Part C — repo configuration:**

Create `.claude/review-config.yaml` with defaults:
max_rounds: 3
min_severity: MEDIUM    # CRITICAL|HIGH|MEDIUM|LOW — filter for gh comment
ignore_paths:           # paths to skip in diff
  - "*.lock"
  - "*.sum"
  - "vendor/"
timeout_seconds: 120    # per runner invocation
post_to_github: true

**Part D — E2E test script:**

Create `tests/e2e-test.sh <pr_number>`:
1. Assert: state is clean (no active review)
2. Invoke: `/pr-reviewer $pr_number` (simulate: set state=SETUP, run hook)
3. Assert: state transitions SETUP → REVIEWING (round 1)
4. Simulate 3 runner completions (inject mock findings)
5. Assert: state transitions to SUMMARIZING
6. Assert: report file created at .claudex/reviews/PR-$pr_number-*.md
7. Assert: gh pr comment was called (check with mock or --dry-run)
8. Assert: state is DONE, worktree removed

**Report after delivery:**
- List of fixes applied in Part A (by primitive)
- Confirm all 6 primitives now covered
- E2E test result: all 7 assertions PASS
3

O Safety Pass

As 6 primitivas que todo plugin de produção deve ter

Cada primitiva cobre uma classe de falha diferente. Ausência de uma única primitiva é suficiente para transformar um edge case comum em uma corrupção de estado irrecuperável.

1

ERR trap em todo script

Qualquer erro não tratado é capturado. O hook não lança exceção para o Claude Code. Exit 0 sempre.

Falha coberta: erro de bash inesperado em qualquer linha

2

Escrita atômica universal

Todo write de estado usa tmp + rename. Nunca escrita direta.

Falha coberta: interrupção durante escrita → arquivo corrompido

3

CAS em toda transição de estado

Toda mudança de status verifica version antes de escrever.

Falha coberta: duas instâncias modificando estado simultaneamente

4

Lockfile com varredor de stale

flock não-bloqueante + verificação de stale locks de processos mortos.

Falha coberta: crash deixa lock órfão, bloqueando execuções futuras

5

Validação de paths

worktree_path deve começar com /tmp/pr-review- antes de qualquer uso.

Falha coberta: path traversal acidental ou malformado apaga dados

6

Timeout em subprocessos

Todo `claude --print` envolto em `timeout 120`. Runner não bloqueia indefinidamente.

Falha coberta: API travada deixa o loop preso para sempre

4

Integração GitHub

gh pr comment com o relatório gerado automaticamente

Postar o relatório diretamente no PR elimina o passo manual. A revisão aparece no contexto onde o time já está discutindo — sem precisar abrir outro arquivo.

🤖 Postando o Relatório
# Pegar o relatório mais recente para este PR
REPORT_FILE=$(ls -t .claudex/reviews/PR-${PR_NUMBER}-*.md 2>/dev/null | head -1)

if [ -z "$REPORT_FILE" ]; then
  echo "[pr-reviewer] No report file found, skipping comment" >&2
  exit 0
fi

# Postar no PR (fail gracefully se gh não está disponível)
if command -v gh >/dev/null 2>&1; then
  gh pr comment "$PR_NUMBER" \
    --body-file "$REPORT_FILE" \
    2>/dev/null || echo "[pr-reviewer] gh comment failed (ignored)" >&2
fi

min_severity filter

Se min_severity=HIGH, apenas findings CRITICAL e HIGH vão para o comment. MEDIUM e LOW ficam no relatório local mas não são postados — reduz ruído no PR.

post_to_github: false

Para repos onde você não quer comentários automáticos (ex: OSS público), desabilitar no review-config.yaml. O relatório ainda é salvo localmente.

5

Configuração por Repositório

.claude/review-config.yaml — defaults que o time pode ajustar

Hardcoded defaults funcionam para um repo mas não para todos. Configuração por repo permite que cada time ajuste o revisor ao seu contexto sem modificar o código do plugin.

Exemplo de review-config.yaml

# .claude/review-config.yaml
# PR Reviewer Configuration — customize for this repo

# Number of review rounds (1 = Author only, 2 = +Reviewer, 3 = +Security)
max_rounds: 3

# Minimum severity to include in the GitHub PR comment
# CRITICAL|HIGH|MEDIUM|LOW — lower severity findings still appear in local report
min_severity: MEDIUM

# Paths to skip in the diff (supports glob patterns)
ignore_paths:
  - "*.lock"
  - "*.sum"
  - "vendor/"
  - "*.generated.go"
  - "testdata/"

# Timeout per runner invocation (seconds)
timeout_seconds: 120

# Whether to post the report as a PR comment via gh
# Set false for OSS repos or when you prefer manual review of the report
post_to_github: true

# Override max diff size (lines) — diffs larger than this are split
max_diff_lines: 3000
6

E2E Sintético

Rodando o revisor completo num PR de teste — validação ponta a ponta

O teste E2E é o único que valida a integração ponta a ponta. Cada ponto de integração — Claude Code → hook → worktree → runner → relatório → GitHub — pode falhar silenciosamente. Este teste confirma que todos funcionam juntos.

1

Criar PR de teste no GitHub

Um PR real com pelo menos um arquivo modificado. Não precisa ter bugs — é para validar o fluxo, não a qualidade da revisão.

2

Rodar o plugin completo

Invocar `/pr-reviewer NNN` no Claude Code. Observar as 3 rodadas completarem. Não interferir — deixar o loop rodar até DONE.

3

Verificar todos os artefatos

State DONE? Worktree removido? Relatório em .claudex/reviews/? Lock liberado? Runners limpos?

4

Verificar integração GitHub

Abrir o PR no GitHub. O comentário do revisor deve estar lá. Se não está, verificar: gh autenticado? post_to_github: true? gh pr comment rodou sem erro?

5

Testar falha e recovery

Matar o Claude Code durante uma rodada (Ctrl+C). Rodar novamente. O revisor deve detectar o stale lock, limpar e continuar de onde parou.

🎉 Plugin Completo

Se o E2E passa — incluindo o teste de falha e recovery — o plugin pr-reviewer está pronto para produção. Você construiu um segundo plugin seguindo os mesmos 5 prompts incrementais da Trilha 2, aplicados a um sistema mais complexo com integração externa.

🚀 O que você pode fazer agora
Instalar em repos reais da sua equipe
Adicionar personas específicas do domínio (ex: compliance, GDPR)
Criar um 6° prompt para CI/CD integration (GitHub Actions trigger)
Aplicar o mesmo padrão para construir outros plugins

🏁 Trilha 4 Completa

Módulo 4.1 — SPEC.md completo antes do primeiro prompt
Prompt 01 — Scaffold + worktree com idempotência e fail-open
Prompt 02 — Estado YAML atômico, CAS e lockfile não-bloqueante
Prompt 03 — Stop Hook engine com máquina de estados SETUP→DONE
Prompt 04 — 3 personas (Author, Reviewer, Security) + relatório estruturado
Prompt 05 — Safety pass com 6 primitivas + gh integration + E2E test

O padrão que você aprendeu:

SPEC.md → Scaffold → Estado → Loop → Conteúdo → Safety. Cinco prompts incrementais, cada um verificado antes do próximo. Este é o método para construir qualquer plugin Claude Code complexo.