Add public_user_profile to Crypto API (resolve model_id by name)#128
Add public_user_profile to Crypto API (resolve model_id by name)#128lingster wants to merge 1 commit into
Conversation
CryptoAPI had no way to resolve a model name (the "username" shown on the crypto leaderboard) to a model_id, which is required by submission_scores, diagnostics, staking, etc. public_user_profile existed only on the Classic and Signals APIs. The v3UserProfile GraphQL field accepts a `tournament` argument that disambiguates a model name within a given tournament. The previous Classic and Signals implementations ignored it, so a name shared across tournaments could resolve to the wrong model's id (verified: "quixotic15" returns a different id with vs without tournament=12). This unifies all three into a single base_api.Api.public_user_profile that passes `tournament=self.tournament_id`, so: - CryptoAPI gains public_user_profile (tournament 12) - Signals/Classic resolve names within their own tournament (11 / 8) - the duplicated overrides in numerapi.py and signalsapi.py are removed (DRY) Verified end-to-end against the live API and the Numerai MCP: a fresh crypto leaderboard name resolves to its model_id and that id drives submission_scores. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25bca132e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| data = self.raw_query(query, arguments)["data"]["v3UserProfile"] | ||
| # convert strings to python objects | ||
| utils.replace(data, "startDate", utils.parse_datetime_string) | ||
| utils.replace(data, "nmrStaked", utils.parse_float_string) |
There was a problem hiding this comment.
Preserve Classic nmrStaked as a string
When this shared method is invoked through NumerAPI, it now converts nmrStaked to Decimal; the removed Classic implementation only converted startDate, so existing callers of NumerAPI.public_user_profile(...) that persist or compare the previously returned stake string will start seeing a different type. If the goal is only to add tournament-scoped lookup, keep this conversion limited to APIs that already returned Decimal or leave the Classic return type unchanged.
Useful? React with 👍 / 👎.
Problem
submission_scores(anddiagnostics, staking, etc.) require amodel_id,but the Crypto API had no way to resolve a model name → model_id.
public_user_profileexisted only onNumerAPI(Classic) andSignalsAPI,so there was no supported path to map the usernames shown on the crypto
leaderboard to the UUIDs the rest of the API expects.
Fix
The
v3UserProfileGraphQL field accepts atournamentargument thatdisambiguates a model name within a tournament. The old Classic/Signals
implementations ignored it — meaning a name shared across tournaments could
resolve to the wrong model's id (verified:
quixotic15returns adifferent id with vs. without
tournament=12).This unifies all three tournaments into a single
base_api.Api.public_user_profilethat passestournament=self.tournament_id:CryptoAPIgainspublic_user_profile(tournament 12) — the missing piecenumerapi.pyandsignalsapi.pyremoved (DRY)Return shape is unchanged (
id,username,startDate,bio,nmrStaked).Usage
Testing (red/green TDD)
test_cryptoapi.pyandtest_signalsapi.pyassert the modelis resolved within the API's own tournament and that string fields are
converted. Written failing first, then made to pass.
45 passed(live-API tests deselected).pyflakesclean.Verified against the live API + Numerai MCP
v3UserProfile(no tournament) for a crypto modelnull(reproduces the bug)v3UserProfile(tournament: 12)2d844064-...CryptoAPI().public_user_profile(...)['id']2d844064-...(matches)submission_scores(model_id)🤖 Generated with Claude Code