Pular para conteúdo

AUR-439 — Bloquear o merge quando o review reprova

Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.

O que este card entrega

Uma nova flag no caminho de pull request de aurumcode review:

aurumcode review --pr <numero> --repo <dono>/<projeto> --publicar --check

Depois de publicar cada achado como comentario no pull request (o comportamento que o AUR-438 ja entrega, inalterado), publica um commit status no commit de topo do pull request atraves do cliente GitHub restaurado (AUR-437, internal/git/githubclient.SetStatus): "failure" quando pelo menos um achado e grave (severidade error, o mesmo patamar que --fail-on high|error ja nomeia), "success" caso contrario. Uma regra de branch protection que exige esse check bloqueia o merge do pull request ate a correcao.

Este card e fiacao, nao reescrita: SetStatus ja existe, ja esta provado (internal/git/githubclient/client_test.go) e ja e fail-closed em permissao de escrita (requireWritePermission, a mesma garantia que PostReviewComment/PostIssueComment ja usam). O que falta, e o que este card adiciona, e inteiramente em cmd/aurumcode/pr.go: a flag --check, a classificacao "grave" (reaproveitando severityRank/countAtOrAbove de cmd/aurumcode/main.go -- nenhuma segunda escala de severidade), e a funcao publishCheckStatus que monta e publica o githubclient.CommitStatus.

Flags

  • --check: opcional (booleano). Publica o commit status descrito acima. Com --pr, satisfaz sozinha a exigencia que --na-linha normalmente impoe -- o comando declarado por este card (review --pr N --repo o/r --publicar --check) nao leva --na-linha, e --check nomeia seu proprio comportamento com a mesma clareza que --na-linha nomeia o dela. Sem --check e sem --na-linha, o caminho de PR continua recusando exatamente como antes (aurumcode review: --na-linha is required with --pr, exit 2) -- nada nesse contrato pre-existente muda.
  • --repo e --publicar continuam obrigatorios com --pr, com ou sem --check, exatamente como o AUR-438 ja exige. --check nao substitui nem suprime a publicacao de comentarios que --publicar ja exige: os dois convivem na mesma execucao -- cada achado ainda vira comentario inline ou geral no pull request (AUR-438, inalterado), e o commit status e publicado depois, como um efeito adicional, nunca no lugar dos comentarios.

O que conta como "grave"

Um achado e grave quando sua severidade e error -- o rank mais alto que o motor de review ja usa (internal/prompt's vocabulary: error, warning, info), o mesmo rank que --fail-on high|error ja nomeia no caminho --base. publishCheckStatus conta os achados grave com countAtOrAbove(issues, rankError), a mesma funcao que --fail-on ja usa em cmd/aurumcode/main.go -- nao existe uma segunda nocao de "grave" só para o --check.

O commit status publicado

githubclient.CommitStatus{
    Context:     "aurumcode/review",
    State:       "failure" | "success",
    Description: "<N> achado(s) grave(s) no pull request #<numero>" |
                  "nenhum achado grave no pull request #<numero>",
}

Context e contrato publico: uma regra de branch protection identifica qual check e obrigatorio pelo context exato, entao renomea-lo em uma versao futura des-bloquearia silenciosamente todo merge que dependia dele em vez de continuar bloqueando. "aurumcode/review" e o valor fixo que este card publica e testa (tests/unit/AUR-439.go, tests/integration/AUR-439.go).

Zero achados ainda publica "success": um commit que corrigiu todo achado grave de uma execucao anterior precisa que o check anterior seja limpo, ou o merge continua bloqueado para sempre por um status que nunca mais e atualizado. "No issues found." continua imprimindo exatamente como antes; o commit status e adicional, nao um substituto.

O SHA do commit: a mesma recusa fail-closed, agora tambem por --check

SetStatus publica em /repos/{owner}/{repo}/statuses/{sha} -- nao ha forma dessa chamada sem um SHA de commit, exatamente como uma chamada PostReviewComment inline nao existe sem um commit_id (AUR-438). Este card nao abre um segundo guardiao paralelo para essa exigencia: a mesma variavel needsCommitID que o AUR-438 ja usa para achados elegiveis a comentario inline agora tambem comeca em true quando --check foi dado. O efeito pratico: um review --pr ... --publicar --check sem GITHUB_SHA recusa antes de qualquer POST -- mesmo quando nenhum achado e elegivel a comentario inline, mesmo quando nao ha achado nenhum -- com a mesma mensagem de recusa que o AUR-438 ja publica em stderr (refusing to publish: an inline comment requires a commit SHA...). A mensagem e reaproveitada tal como esta, sem alteracao: o contrato pre-existente sem --check e byte a byte pinado, e mudar o texto so para --check exigiria dois textos condicionais em vez de um guardiao unico.

tests/integration/AUR-439.go prova especificamente o caso mais estreito: um achado so-geral (nenhum elegivel a inline) com --check e sem GITHUB_SHA ainda recusa -- a prova de que --check contribui sua propria exigencia ao guardiao em vez de depender de carona em um achado inline que por acaso esteja presente.

Permissao de escrita: herdada, nao contornada

A checagem explicita de HasWritePermission que o AUR-438 ja faz antes de qualquer trabalho (busca de diff, chamada ao modelo) cobre --check sem nenhuma mudanca: --check nunca chega a publishCheckStatus quando o token e so-leitura, porque a funcao inteira ja retornou. E mesmo que chegasse, SetStatus em si tambem chama requireWritePermission internamente (o mesmo guardiao fail-closed que PostReviewComment/ PostIssueComment ja usam) -- nao existe um caminho que contorne essa garantia so porque a chamada e para o endpoint de status em vez de comentario.

Exit codes

  • 0: os achados foram publicados (ou "No issues found."), sem erro; com --check, o commit status publicado foi "success" (nenhum achado grave).
  • 1: falha em tempo de execucao -- inclui agora a falha ao publicar o proprio commit status (uma falha de transporte/API do SetStatus, nao um achado grave).
  • 2: erro de uso -- --repo/--publicar ausentes com --pr, --na-linha ausente quando --check tambem esta ausente, --pr nao positivo, ou --repo fora do formato dono/projeto.
  • 3 (exitFindings, o mesmo codigo que --fail-on ja usa): com --check, pelo menos um achado grave foi encontrado e o commit status publicado foi "failure". Este codigo nunca pode ser confundido com sucesso -- é exatamente o que MUT-001 prova: uma versao que reportasse sucesso (codigo 0, ou um status "success") com um achado grave presente e o defeito que a mutacao introduz e que o aceite precisa pegar.

Uma falha ao publicar um comentario individual e a falha ao publicar o commit status sao independentes: se um achado falha ao publicar mas o commit status ainda publica com sucesso (ou vice-versa), o exit code permanece 1 (a falha de publicacao de comentario tem precedencia sobre o 3 do --check, porque 1 ja significa "algo na publicacao falhou" -- nenhuma das duas causas de falha e silenciada, ambas aparecem em stderr).

Nenhum destes codigos e novo: e o mesmo vocabulario que --base e --pr ... --na-linha ja usam (docs/specs/AUR-430.md, docs/specs/AUR-431.md, docs/specs/AUR-438.md).

Exemplo executavel sem segredo

bash tests/e2e/AUR-439.sh E2EAUR439

Compila o binario real, sobe um fake GitHub em loopback a partir de tests/fixtures/scm/github/ (o diff do PR 42, as permissoes de leitura-escrita e so-leitura, a resposta de comentario criado) estendido com o endpoint de status (/repos/dono/projeto/statuses/<sha>, que responde 422 a um state ausente ou invalido, nunca um mock que concorda com qualquer corpo), escreve quatro respostas de modelo deterministicas -- uma com um achado grave (error) mais um achado geral, uma so com um achado nao-grave (warning), uma sem achado nenhum, e uma so-geral (para a prova mais estreita do SHA acima) -- e roda aurumcode review --pr 42 --repo dono/projeto --publicar --check contra cada uma. Prova: achado grave publica state=failure e um exit code que nunca e 0; achado so warning publica state=success e exit 0; zero achados ainda publica state=success; sem GITHUB_SHA o comando recusa antes de qualquer POST mesmo quando nada e elegivel a inline; um token so-leitura e recusado antes de qualquer POST; repetir a execucao produz a mesma saida e o mesmo status publicado; e o contrato pre-existente (--na-linha no lugar de --check) nunca contata o endpoint de status. Tokens sao strings sinteticas montadas em tempo de execucao; nenhum shape de credencial existe em arquivo rastreado.

Selectors e exit codes do aceite

  • Aceite: tests/acceptance/AUR-439.sh -- selectors AC-001 (tudo), TestAUR439, IntegrationAUR439, E2EAUR439, AC-001-MUT-001.
  • Exit codes (convencao do board, tests/acceptance/EXIT_CODE_CONVENTION.md): 0 comportamento provado; 1 RED comportamental; 64 selector desconhecido; 79 infraestrutura / inconclusivo (nunca evidencia de RED).

Diagnostico de falha

  • AUR-439/AC-001/behavior-missing: o caminho --check nao entrega o fluxo prometido (ver stderr do harness em tests/e2e/AUR-439.sh).
  • grave_wrong_exit: um achado grave nao produziu o exit code 3 esperado (ou produziu 0, o defeito exato que MUT-001 injeta).
  • wrong_state_reported_success: o state publicado no commit status foi "success" com um achado grave presente -- o outro rosto do mesmo defeito, visivel no corpo do POST em vez de so no exit code (a licao dos cards irmaos: o discriminador tem que ser o state publicado, nao so "nao deu erro").
  • clean_wrong_state / empty_missing_check_line: o caminho sem achado grave nao publicou "success".
  • nosha_not_refused / nosha_post_leaked: --check nao herdou a recusa fail-closed por SHA ausente.
  • readonly_not_refused / readonly_post_leaked: --check nao herdou a recusa fail-closed por falta de permissao de escrita.
  • nocheck_status_leaked / nocheck_check_line_leaked: o contrato pre-existente (--na-linha, sem --check) regrediu -- contatou o endpoint de status ou imprimiu a linha de check quando nao deveria.
  • non_deterministic / non_deterministic_status_count: duas execucoes identicas divergiram na saida ou no status publicado.
  • infrastructure/missing_go, infrastructure/mktemp, infrastructure/fakegithub_did_not_start (exit 79): ambiente, nunca RED.

Compatibility, migration, rollback

  • Compatibility: --base e review --pr ... --publicar (sem --check) mantem o contrato publicado byte a byte -- toda a logica nova de --check fica atras de if check { ... }, e o unico ramo pre-existente que muda de posicao (o calculo de commitID/needsCommitID, movido para antes do retorno antecipado de "No issues found.") e um no-op quando check e false: needsCommitID so passa a true ali pela mesma condicao que ja usava antes (um achado elegivel a inline), entao nenhuma saida observavel muda para quem nunca passa --check.
  • Migration: not-applicable.
  • Rollback: reverter somente os paths deste card; nenhum estado externo (alem do commit status publicado durante um teste real, nunca durante o aceite offline) e afetado.