Skip to content

fix(server): stats endpoint 500s in sync-only mode (AI disabled) - #88

Merged
vitofico merged 1 commit into
mainfrom
fix/issue-87-stats-sync-only
Jul 13, 2026
Merged

fix(server): stats endpoint 500s in sync-only mode (AI disabled)#88
vitofico merged 1 commit into
mainfrom
fix/issue-87-stats-sync-only

Conversation

@vitofico

Copy link
Copy Markdown
Owner

Summary

Fixes #87. A sync-only server (QUIRE_SERVER_AI_ENABLED=false) started from a fresh database returns HTTP 500 on GET /library/v1/stats (and the endpoint stays broken) because the query joins tables that only exist when AI is enabled.

Root cause

  • The library router mounts on progress_enabled (default true), not on ai_enabled — so /library/v1/stats is live in sync-only mode.
  • get_stats unconditionally computes top_themes, which joins book_insights (pick-one CTE) and book_themes.
  • Both tables live on the ai alembic branch, which the deploy migrator applies only when QUIRE_SERVER_AI_ENABLED=true.
  • Result: relation "book_themes" does not exist → blanket 500. Booting once with AI enabled applies the migration and "fixes" it permanently — exactly the workaround the reporter found.

Fix

Gate the entire top_themes block on settings.ai_enabled and return top_themes=[] when AI is off (reporter's option B). Gating only the final BookTheme join is insufficient — the pick-one CTE still references the absent book_insights. Themes are an AI-only feature, so an empty list is the correct sync-only answer; all other stats (counts, top authors) are unchanged. When AI is enabled, behavior is identical to before (only indentation moved).

Test

New tests/integration/test_stats_sync_only.py provisions a fresh Postgres migrated with ai_enabled=False (so book_insights/book_themes genuinely don't exist), builds a sync-only app, and asserts /library/v1/stats returns 200 with top_themes=[] while the non-AI stats still compute. The test also asserts the AI tables are absent so it can't silently degrade.

The existing suite never caught this because conftest.py always migrates with ai_enabled=True.

Verification

  • Full server suite: 563 passed; ruff check + ruff format --check clean.
  • Regression test proven: it fails with HTTP 500 when the fix is stashed, and passes with the fix applied.

…I is disabled

A sync-only deployment (`QUIRE_SERVER_AI_ENABLED=false`) never applies the
`ai` alembic branch, so `book_insights` / `book_themes` do not exist. The
library router mounts on `progress_enabled`, so `GET /library/v1/stats` is
still reachable — and it unconditionally joined those AI-only tables,
producing `relation "book_themes" does not exist` and a blanket HTTP 500.
Operators had to boot once with AI enabled (to apply the migration) before
sync-only mode would work.

Gate the whole `top_themes` computation on `settings.ai_enabled`. Skipping
only the final `BookTheme` join is not enough — the pick-one CTE still
references the absent `book_insights` — so the entire block is guarded.
Themes are an AI-only feature, so `top_themes=[]` is the correct sync-only
answer; the other stats (counts, top authors) are unaffected.

Adds a regression test that provisions a fresh Postgres migrated with
`ai_enabled=False` and asserts the endpoint returns 200 with `top_themes=[]`.
The existing suite never caught this because conftest always migrates with
`ai_enabled=True`.

Closes #87
@vitofico vitofico self-assigned this Jul 13, 2026
@vitofico
vitofico merged commit ec7d521 into main Jul 13, 2026
8 checks passed
@vitofico
vitofico deleted the fix/issue-87-stats-sync-only branch July 13, 2026 07:50
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.

server: Requires at least one start in AI/full mode even for sync-only

1 participant