Skip to content

Expose predicted-time as an API: GET /me and /players/{id} routes - #186

Open
puzzlerushse wants to merge 1 commit into
MySpeedPuzzling:mainfrom
puzzlerushse:feat/predicted-time-api
Open

Expose predicted-time as an API: GET /me and /players/{id} routes#186
puzzlerushse wants to merge 1 commit into
MySpeedPuzzling:mainfrom
puzzlerushse:feat/predicted-time-api

Conversation

@puzzlerushse

Copy link
Copy Markdown

Summary

Wraps GetPlayerPrediction (already live, already used on the website's puzzle detail page) behind two new read endpoints:

  • GET /v1/me/puzzles/{id}/predicted-time
  • GET /v1/players/{id}/puzzles/{id}/predicted-time

Both share PredictedTimeResponseFactory, which applies the same two gates the website does:

  • the requesting token must belong to an active member
  • the target player's own time_predictions_opted_out flag is always respected, regardless of who is asking

For the /players/{id} variant, a private target's prediction is only returned to the player themselves, matching every other /players/{id}/* endpoint's privacy rule (zeroed data, not 403).

The response also includes difficulty_score/difficulty_level/difficulty_confidence for the puzzle inline, fetched independently of the prediction (GetPlayerPrediction's personalized branch doesn't compute a real difficulty value, so it can't be read off the prediction result). There's no separate GET /v1/puzzles/{id} in this PR — a consumer wanting to show the difficulty a prediction was derived from doesn't need a second round-trip.

Adds two rows to the public for-developers API docs page and to docs/features/api/README.md.

Test plan

  • PredictedTimeEndpointTest covers: no active membership → null prediction, active membership + history → personalized prediction (with presence-only assertions on the new difficulty fields, since there's no puzzle_difficulty fixture yet for any test puzzle), non-existent puzzle → 404, missing scope → 403, privacy respected for /players/{id}, non-existent player → 404
  • Confirm difficulty_score/difficulty_level/difficulty_confidence populate correctly against real data (no fixture exists to assert exact values in CI yet)

Wraps GetPlayerPrediction (already live, already used on the website's
puzzle detail page) behind two new read endpoints:
  GET /v1/me/puzzles/{id}/predicted-time
  GET /v1/players/{id}/puzzles/{id}/predicted-time

Both share PredictedTimeResponseFactory, which applies the same two
gates the website does - the requesting token must belong to an active
member, and the target player's time_predictions_opted_out flag is
always respected regardless of who's asking. For the /players/{id}
variant, a private target's prediction is only returned to the player
themselves, matching every other /players/{id}/* endpoint's privacy
rule (zeroed data, not 403).

The response also includes difficulty_score/difficulty_level/
difficulty_confidence for the puzzle inline, fetched independently of
the prediction (GetPlayerPrediction's personalized branch doesn't
compute a real difficulty value, so it can't be read off the
prediction result) - there's no separate GET /v1/puzzles/{id}, so a
consumer wanting to show the difficulty a prediction was derived from
doesn't need a second round-trip.

Adds two rows to the public for-developers API docs page and to
docs/features/api/README.md.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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