fix: stabilize the live recommendation path
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bfea9efb5e
commit
dbc5c2d93f
12 changed files with 113 additions and 31 deletions
|
|
@ -22,6 +22,7 @@ class ResolvedSession:
|
|||
|
||||
session_id: str
|
||||
session: SpotifySession
|
||||
can_logout: bool
|
||||
|
||||
|
||||
@router.get("/api/auth/login")
|
||||
|
|
@ -81,7 +82,12 @@ def current_session(request: Request) -> JSONResponse:
|
|||
resolved = resolve_session(request)
|
||||
if resolved is None:
|
||||
return JSONResponse({"detail": "Not authenticated"}, status_code=401)
|
||||
return JSONResponse({"display_name": resolved.session.display_name})
|
||||
return JSONResponse(
|
||||
{
|
||||
"display_name": resolved.session.display_name,
|
||||
"can_logout": resolved.can_logout,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/suggestions")
|
||||
|
|
@ -119,16 +125,16 @@ def resolve_session(request: Request) -> ResolvedSession | None:
|
|||
application_settings = cast(Settings, request.app.state.settings)
|
||||
if application_settings.app_mode is AppMode.DEMO:
|
||||
demo_session = cast(SpotifySession, request.app.state.demo_session)
|
||||
return ResolvedSession("demo", demo_session)
|
||||
return ResolvedSession("demo", demo_session, can_logout=False)
|
||||
session_store = cast(SessionStore, request.app.state.session_store)
|
||||
cookie_session_id = request.cookies.get(SESSION_COOKIE_NAME)
|
||||
if cookie_session_id is not None:
|
||||
cookie_session = session_store.get(cookie_session_id)
|
||||
if cookie_session is not None:
|
||||
return ResolvedSession(cookie_session_id, cookie_session)
|
||||
return ResolvedSession(cookie_session_id, cookie_session, can_logout=True)
|
||||
|
||||
seed_session_id = cast(str | None, getattr(request.app.state, "seed_session_id", None))
|
||||
seed_session = session_store.get(seed_session_id) if seed_session_id is not None else None
|
||||
if seed_session is None or seed_session_id is None:
|
||||
return None
|
||||
return ResolvedSession(seed_session_id, seed_session)
|
||||
return ResolvedSession(seed_session_id, seed_session, can_logout=False)
|
||||
|
|
|
|||
|
|
@ -64,8 +64,12 @@ Retain understandable bridges through genre, scene, production style, instrument
|
|||
energy, era, or songwriting. The profile is not exhaustive, so never claim that a
|
||||
candidate is definitely unknown. When familiarity is
|
||||
familiar, candidates may include supplied top or saved tracks, but remain responsive to the
|
||||
current request. When familiarity is mix, combine recognizable anchors with real,
|
||||
confidently identifiable adjacent discoveries rather than splitting into unrelated halves.
|
||||
current request. When familiarity is mix, the first 15 candidates must be suitable anchors
|
||||
copied from the supplied top or saved tracks: copy the title exactly and use one listed
|
||||
artist name exactly, preferring the first. Deduplicate those anchors, then fill the remaining
|
||||
candidates with confidently identifiable adjacent discoveries. If fewer than 15 supplied
|
||||
tracks fit, use every suitable one before adding discoveries. When familiarity is familiar,
|
||||
use supplied tracks for the majority of the list.
|
||||
|
||||
Use musical knowledge conservatively. Base selection on durable, commonly knowable
|
||||
attributes of recordings. Do not invent listening statistics, personal memories, release
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ def test_login_callback_cookie_and_current_user_flow() -> None:
|
|||
assert "discovery_session=" in callback_response.headers["set-cookie"]
|
||||
assert "HttpOnly" in callback_response.headers["set-cookie"]
|
||||
assert "SameSite=lax" in callback_response.headers["set-cookie"]
|
||||
assert client.get("/api/auth/me").json() == {"display_name": "Ada Listener"}
|
||||
assert client.get("/api/auth/me").json() == {
|
||||
"display_name": "Ada Listener",
|
||||
"can_logout": True,
|
||||
}
|
||||
|
||||
|
||||
def test_unknown_callback_state_redirects_to_login_error() -> None:
|
||||
|
|
@ -108,9 +111,16 @@ def test_seed_session_authenticates_requests_without_a_cookie() -> None:
|
|||
)
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/api/auth/me")
|
||||
logout_response = client.post("/api/auth/logout")
|
||||
after_logout_response = client.get("/api/auth/me")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"display_name": "Seed Listener"}
|
||||
assert response.json() == {"display_name": "Seed Listener", "can_logout": False}
|
||||
assert logout_response.status_code == 204
|
||||
assert after_logout_response.json() == {
|
||||
"display_name": "Seed Listener",
|
||||
"can_logout": False,
|
||||
}
|
||||
|
||||
|
||||
def test_seed_session_failure_keeps_application_serving() -> None:
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ def test_demo_auth_playlist_and_suggestions_are_explicitly_simulated() -> None:
|
|||
for scenario in load_scenarios()
|
||||
if not scenario.is_refinement
|
||||
]
|
||||
assert current_user.json() == {"display_name": "Demo Listener"}
|
||||
assert current_user.json() == {"display_name": "Demo Listener", "can_logout": False}
|
||||
assert login.headers["location"] == "/?login=demo"
|
||||
assert playlist.json()["url"].startswith("https://open.spotify.com/playlist/demo-")
|
||||
assert suggestions.json() == expected_suggestions
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue