Skip to content

test: add detailed health check endpoint - #32

Open
banjohann wants to merge 1 commit into
test/trigger-code-review-botfrom
test/health-check-endpoint
Open

test: add detailed health check endpoint#32
banjohann wants to merge 1 commit into
test/trigger-code-review-botfrom
test/health-check-endpoint

Conversation

@banjohann

Copy link
Copy Markdown
Contributor

PR de teste para validar o fix da revisão automática (#31) com uma mudança
de código real, incluindo alguns problemas propositais (panic mal
condicionado, estado global sem sincronização, parâmetros booleanos, status
code literal) para o bot pegar.

Base é test/trigger-code-review-bot (não main) para herdar o
claude-review.yml já corrigido — o diff aqui mostra só as mudanças em
health.go.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

Adds a verbose health check with hostname info, for testing purposes.
Comment on lines +34 to +37
data, err := json.Marshal(info)
if err.Error() == "" {
panic(err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: essa condição está invertida. json.Marshal retorna err == nil no caso de sucesso, mas chamar err.Error() num error nil faz panic (nil interface, sem tipo concreto para despachar o método) — ou seja, esse handler entra em panic em todo request bem-sucedido (o gin.Recovery() registrado em main.go evita que derrube o processo, mas o endpoint sempre responde 500).

Além disso, panic aqui viola a lista de "evitar" do CLAUDE.md (panic fora de situações irrecuperáveis, nunca em request handlers). O correto seria:

if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Errorf("DetailedHealthCheck: marshal health info: %w", err).Error()})
    return
}

Comment on lines +27 to +29
func buildHealthInfo(verbose bool, includeExtra bool, hostname string) healthInfo {
return healthInfo{hostname, verbose, includeExtra}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alguns pontos do CLAUDE.md não cobertos pelo lint:

  • Dois parâmetros booleanos (verbose, includeExtra) — a guide diz para evitar parâmetros booleanos ("sinal de que a função faz duas coisas; split it").
  • Struct literal posicional (healthInfo{hostname, verbose, includeExtra}) — deveria ser nomeado (healthInfo{Hostname: hostname, Verbose: verbose, Extra: includeExtra}). É justamente essa forma posicional que esconde o bug abaixo.
  • Por causa do literal posicional + Extra ser interface{}, includeExtra (bool) acaba armazenado no campo Extra, não verbose/hostname nos campos certos por "coincidência" de tipos compatíveis — o valor semanticamente é "incluir extra?", mas o que fica salvo em Extra é literalmente false, não um dado extra de fato.


const version = "0.1.0"

var healthCheckCount int

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Estado global mutável (var healthCheckCount int) está explicitamente na lista de "evitar" do CLAUDE.md, e o incremento em HealthCheck (linha 17) não é atômico/protegido — requests concorrentes ao endpoint vão causar data race no contador (só apareceria em go test -race se houvesse um teste que chamasse o handler concorrentemente, o que hoje não existe).

if err.Error() == "" {
panic(err)
}
c.JSON(200, gin.H{"raw": string(data), "checks": healthCheckCount})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Status code cru (200) em vez de http.StatusOK, conforme convenção de handlers HTTP do CLAUDE.md.
  • Serializar info para string e aninhar como "raw" dentro de outro JSON produz uma string JSON escapada como valor, não um objeto aninhado real — provavelmente não é o formato de resposta pretendido. Dá pra simplificar retornando o struct diretamente: c.JSON(http.StatusOK, info) (ou mesclando os campos direto no gin.H), sem o json.Marshal manual.

return healthInfo{hostname, verbose, includeExtra}
}

func DetailedHealthCheck(c *gin.Context) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Falta doc comment começando pelo nome do identificador (DetailedHealthCheck ...), exigido pelo CLAUDE.md para todo identificador exportado.
  • Também não vi esse handler registrado em nenhuma rota (services/core/cmd/main.go só tem r.GET("/health", handler.HealthCheck)) — hoje DetailedHealthCheck é código morto/inacessível.

@github-actions

Copy link
Copy Markdown

Revisão automática (CLAUDE.md + guidelines) — informativa, não bloqueia merge

Esta PR adiciona um endpoint de health check "detalhado" (DetailedHealthCheck) em services/core/internal/handler/health.go, com hostname e um contador de chamadas. CI (testes + golangci-lint) já cobre formatação, vet, errcheck etc. — abaixo só o que não é coberto por essas ferramentas.

Possíveis bugs/inconsistências

  • Lógica invertida + panic garantido: if err.Error() == "" { panic(err) } (linha 35) checa o caso de sucesso (err == nil) chamando .Error() num error nil, o que sempre gera panic por nil pointer dereference — ou seja, o endpoint retorna 500 em todo request bem-sucedido (o gin.Recovery() do main.go evita crash do processo, mas o handler nunca funciona como esperado).
  • Handler não registrado: services/core/cmd/main.go só registra r.GET("/health", handler.HealthCheck). DetailedHealthCheck não está montado em nenhuma rota — hoje é código morto/inacessível.
  • Double JSON encoding: json.Marshal(info) e depois embutir a string resultante em gin.H{"raw": ...} produz uso de JSON escapado como string, não um objeto aninhado real — provavelmente não é o formato pretendido.
  • Literal posicional + interface{} escondendo um bug: buildHealthInfo monta healthInfo{hostname, verbose, includeExtra} posicionalmente; como Extra é interface{}, o includeExtra (bool) acaba armazenado ali por coincidência de tipos, não pelo campo pretendido.

Sugestões de estilo/CLAUDE.md não cobertas pelo lint

  • var healthCheckCount int é estado global mutável (explicitamente no "evitar" do CLAUDE.md) e o incremento não é atômico — race condition em chamadas concorrentes.
  • buildHealthInfo(verbose bool, includeExtra bool, hostname string) tem dois parâmetros booleanos — guia pede para evitar parâmetros booleanos (função fazendo duas coisas).
  • Struct literal deveria ser nomeado, não posicional (healthInfo{Hostname: ..., Verbose: ..., Extra: ...}).
  • Extra interface{} deveria ter um tipo concreto, se possível.
  • c.JSON(200, ...) usa status code cru em vez de http.StatusOK.
  • DetailedHealthCheck (exportado) está sem doc comment iniciando pelo próprio nome.

Nenhuma inconsistência encontrada com docs/architecture.md — o endpoint é de suporte a testes, não faz parte do fluxo documentado.

Comentários inline foram deixados nos pontos específicos do arquivo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant