Skip to content

fix(health): liveness must not fail on something a restart cannot fix - #153

Merged
github-actions[bot] merged 1 commit into
mainfrom
fix/health-liveness-vs-readiness
Aug 28, 2026
Merged

fix(health): liveness must not fail on something a restart cannot fix#153
github-actions[bot] merged 1 commit into
mainfrom
fix/health-liveness-vs-readiness

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

#151 made /api/health return 503 whenever the LLM chain was down. That's right for alerting and wrong for liveness: restarting botsmann doesn't repair an expired Groq key, so the only effect of failing there is to get a healthy process killed — and to fail deploy gates on a problem no deploy caused. That's precisely the failure class that teaches people to bypass the gate.

Two flavours

Endpoint Meaning Behaviour
GET /api/health liveness 200 while the process serves and the database answers. Body still carries status: healthy | degraded | down and the full llm block, so the outage stays visible.
GET /api/health?strict=1 readiness 503 once the chain is consistently failing. Point alerting here.

unknown — nothing has exercised the chain since this process started — is not evidence of a problem, so it reports healthy rather than degraded.

Was anything actually broken?

No. selfhost-deploy.yml curls the homepage, not this endpoint, so the deploy gate was never at risk. But the shape was wrong regardless, and the post-deploy guidance in CLAUDE.md does point a check at /api/health.

Guard

The test now asserts the 503-on-LLM path stays behind strict, so it can't quietly become unconditional again.

Verify

format:check, lint, typecheck, 269 tests, build — all green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HVwg8DKHQktxJuHeLM3xpG

#151 made /api/health return 503 whenever the LLM chain was down. That is
right for alerting and wrong for liveness: restarting botsmann does not
repair an expired Groq key, so the only effect of failing there is to get a
healthy process killed, and to fail deploy gates on a problem no deploy
caused. That is the failure class that teaches people to bypass the gate.

  GET /api/health            liveness -- 200 while the process serves and the
                             database answers. The body still carries
                             status: healthy | degraded | down and the full
                             llm block, so the outage stays visible.
  GET /api/health?strict=1   readiness -- 503 once the chain is consistently
                             failing. Point alerting here.

'unknown' (nothing has exercised the chain since this process started) is not
evidence of a problem, so it reports healthy rather than degraded.

The deploy gate was never at risk -- selfhost-deploy.yml curls the homepage,
not this endpoint -- but the shape was wrong regardless, and the guidance in
CLAUDE.md does point a post-deploy check at /api/health.

The guard now asserts the 503-on-LLM path stays behind `strict`, so this
cannot quietly become unconditional again.

verify: format, lint, typecheck, 269 tests, build -- all green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVwg8DKHQktxJuHeLM3xpG
@github-actions
github-actions Bot merged commit 1e1fd8d into main Aug 28, 2026
1 check passed
@github-actions
github-actions Bot deleted the fix/health-liveness-vs-readiness branch August 28, 2026 12:10
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