Fail-closed startup, view cache, and 503-until-refreshed serving path (FIX-14)#26
Merged
ChelseaKR merged 2 commits intoJul 12, 2026
Merged
Conversation
… (FIX-14) app/server.py::_load_view re-resolved config, opened the store, and could run a full first-run ingest inside a request; every request rebuilt stats/wrapped/diversity/recommendations with no caching, and pyproject.toml still omitted app/server.py from the coverage gate despite existing TestClient tests. - Add a FastAPI lifespan (_lifespan) that resolves config and probes the store once at startup, failing closed like app.auth.AuthNotConfigured: raises ConfigInvalid on bad config, StoreUnavailable on an unreachable store. A never-refreshed store only logs a warning — it does not block startup. - Cache the built DashboardView on app.state, keyed by (store_path, refreshed_at stamp, hash of view-relevant config fields) via a new Config.view_cache_fields() helper; a request only rebuilds the view when the store was actually refreshed or the config actually changed. - Remove the inline first-run ingest from _load_view; data routes (/, /browse, /share, /share/card.svg) now return 503 until an explicit `stacks refresh` populates the store. No route runs ingest inline. - Remove app/server.py from pyproject.toml's coverage omit list (the >=85% --cov-fail-under gate is unchanged); app/server.py now measures at 98% coverage. - Add tests/test_server_lifecycle.py covering populated-store routes, the 503 path, cache reuse/invalidation across a refreshed_at bump, and lifespan failing closed on bad config/store. Update test_auth.py, test_goals_time.py, and test_observability.py (via a new tests/conftest.py::seed_store_from_env helper) to seed the store explicitly before hitting data routes, since ingest no longer happens inside a request. - Mark FIX-14 done in docs/ideation/02-large-scale-fixes.md. Full suite: 206 passed, 96.6% total coverage. make lint/typecheck/test all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # app/server.py # docs/audits/coverage.xml # docs/ideation/02-large-scale-fixes.md # docs/ideation/03-expansions.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
app/server.py::_load_view re-resolved config, opened the store, and could run
a full first-run ingest inside a request; every request rebuilt
stats/wrapped/diversity/recommendations with no caching, and pyproject.toml
still omitted app/server.py from the coverage gate despite existing
TestClient tests.
store once at startup, failing closed like app.auth.AuthNotConfigured:
raises ConfigInvalid on bad config, StoreUnavailable on an unreachable
store. A never-refreshed store only logs a warning — it does not block
startup.
(store_path, refreshed_at stamp, hash of view-relevant config fields) via
a new Config.view_cache_fields() helper; a request only rebuilds the view
when the store was actually refreshed or the config actually changed.
/browse, /share, /share/card.svg) now return 503 until an explicit
stacks refreshpopulates the store. No route runs ingest inline.503 path, cache reuse/invalidation across a refreshed_at bump, and
lifespan failing closed on bad config/store. Update test_auth.py,
test_goals_time.py, and test_observability.py (via a new
tests/conftest.py::seed_store_from_env helper) to seed the store
explicitly before hitting data routes, since ingest no longer happens
inside a request.
Full suite: 206 passed, 96.6% total coverage. make lint/typecheck/test all
green.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Backfill PR for a completed roadmap item (
roadmap/fix-14-serving-path-lifecycle-startup-ch, 1 commit(s) overmain). Part of the portfolio roadmap batch.