rivals-api 2.0.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rivals_api-2.0.0 → rivals_api-3.0.0}/PKG-INFO +103 -5
- {rivals_api-2.0.0 → rivals_api-3.0.0}/README.md +102 -4
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/CHANGELOG.md +52 -0
- rivals_api-3.0.0/docs/GAME_REFERENCES.md +91 -0
- rivals_api-3.0.0/docs/PLAYER_SEARCH_AUDIT.md +131 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/PROJECT_CONTEXT.md +30 -1
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/PROVIDER_INTEGRATION.md +80 -5
- {rivals_api-2.0.0 → rivals_api-3.0.0}/pyproject.toml +1 -1
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/__init__.py +15 -1
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/client.py +5 -0
- rivals_api-3.0.0/src/rivals_api/game_catalog.json +815 -0
- rivals_api-3.0.0/src/rivals_api/game_ids.py +47 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/history.py +27 -12
- rivals_api-3.0.0/src/rivals_api/match_details.py +96 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/mcp_server.py +87 -15
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/models.py +291 -9
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/normalize.py +139 -40
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/providers.py +2 -2
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/resources.py +413 -49
- rivals_api-3.0.0/tests/test_game_references.py +209 -0
- rivals_api-3.0.0/tests/test_match_details.py +253 -0
- rivals_api-3.0.0/tests/test_mcp_player_search.py +83 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/tests/test_providers.py +15 -12
- {rivals_api-2.0.0 → rivals_api-3.0.0}/.github/workflows/publish-pypi.yml +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/.gitignore +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/CONTRIBUTING.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/LICENSE +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/API.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/PROVIDER_FEATURE_GAPS.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/RIVALSTRACKER_API.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/RIVALSTRACKER_API_AUDIT.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/SITE_COMPARISON_GS4.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/SITE_COMPARISON_GS_MULTI_SEASON.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/TRACKER_NETWORK_API.md +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/docs/provider-feature-gaps.json +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/exceptions.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/extensions.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/hero_catalog.json +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/hero_ids.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivals_api/selection.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/__init__.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/client.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/exceptions.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/extensions.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/hero_ids.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/history.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/mcp_server.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/models.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/normalize.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/providers.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/resources.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/src/rivalsdata/selection.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/tests/fixtures/providers.json +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/tests/test_class_stats.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/tests/test_hero_names.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/tests/test_selection.py +0 -0
- {rivals_api-2.0.0 → rivals_api-3.0.0}/tests/test_typed_responses.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rivals-api
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Multi-source Python client and MCP server for Marvel Rivals player stats
|
|
5
5
|
Project-URL: Homepage, https://github.com/GS-Rionnag/rivals-api
|
|
6
6
|
Project-URL: Repository, https://github.com/GS-Rionnag/rivals-api
|
|
@@ -71,7 +71,15 @@ with RivalsClient() as rd:
|
|
|
71
71
|
hero_season = player.heroes.fetch(season=20)
|
|
72
72
|
all_hero_seasons = player.heroes.fetch(season="all")
|
|
73
73
|
map_stats = player.stats.maps(season=20)
|
|
74
|
-
match_page = player.matches.fetch(season=20)
|
|
74
|
+
match_page = player.matches.fetch(limit=20, season=20)
|
|
75
|
+
all_matches = player.matches.fetch(limit="all")
|
|
76
|
+
combined_rate = player.matches.fetch_win_rate(season=20)
|
|
77
|
+
print(combined_rate.win_rate_pct, combined_rate.provider_rates)
|
|
78
|
+
fast_rate = player.matches.fetch_win_rate()
|
|
79
|
+
exact_rate = player.matches.fetch_win_rate(method="exact")
|
|
80
|
+
cached_rate = player.matches.fetch_win_rate(method="cached") # after fetch(limit="all")
|
|
81
|
+
hero_rates = player.matches.fetch_hero_win_rates(method="exact")
|
|
82
|
+
class_rates = player.matches.fetch_class_win_rates(method="cached")
|
|
75
83
|
|
|
76
84
|
# Current match when its provider exposes it; Custom discovery is unsupported.
|
|
77
85
|
live_game = player.live_game.fetch()
|
|
@@ -249,8 +257,88 @@ with annotations for fields observed in the API inventory. This includes
|
|
|
249
257
|
`ProficiencyResponse`, `LeaderboardResponse`, `PunishmentsPage`, `XPPage`,
|
|
250
258
|
`Top500Response`, and typed teammate, crosshair, stats, faction, and insight
|
|
251
259
|
records. For example, `rd.matches.get(match_id)` returns a `Match`,
|
|
252
|
-
`player.matches.fetch()` returns a `MatchHistory
|
|
253
|
-
|
|
260
|
+
`player.matches.fetch(limit=...)` returns a `MatchHistory`. The required limit
|
|
261
|
+
is either a positive number (bounded fetch with a resumable cursor) or
|
|
262
|
+
`"all"` (fetch every available page); both combine and deduplicate providers.
|
|
263
|
+
Each history row is a client-bound `Match`. Call `get_details()` while its
|
|
264
|
+
client is open to lazily fetch combined RivalsData, RivalsTracker, and Tracker.gg
|
|
265
|
+
details, including typed teams, players, and hero segments:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
with RivalsClient(use_browser_fallback=True) as client:
|
|
269
|
+
player = client.get_player(1970288503)
|
|
270
|
+
history = player.matches.fetch(limit=20)
|
|
271
|
+
if history.matches:
|
|
272
|
+
match = history.matches[0]
|
|
273
|
+
details = match.get_details() # Match; the history row stays unchanged
|
|
274
|
+
for team in details.teams:
|
|
275
|
+
for participant in team.players:
|
|
276
|
+
print(participant.name, participant.get("accuracy_percent"))
|
|
277
|
+
print(details.provider_metadata.errors)
|
|
278
|
+
# match.get_details(refresh=True) bypasses detail/provider caches.
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`client.matches.get(match_id, refresh=False)` uses the same fetcher. Provider
|
|
282
|
+
outages return available details with errors; conflicts and field selections
|
|
283
|
+
remain in `provider_metadata`. `accuracy_percent` uses percent units for players
|
|
284
|
+
and heroes. The legacy RD `accuracy` field remains a player percentage or a
|
|
285
|
+
hero ratio; `session_hit_rate` is separate and is never substituted for accuracy.
|
|
286
|
+
Unknown/NaN accuracy is unavailable. See the
|
|
287
|
+
[match detail guide](docs/PROVIDER_INTEGRATION.md#combined-match-details).
|
|
288
|
+
|
|
289
|
+
History and detail matches also expose readable typed references. They format
|
|
290
|
+
as names in bot messages; use `.name` for a plain string and `.id` for the
|
|
291
|
+
original identifier. For a match with map ID `1288`, mode `3`, and platform `1`:
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
print(match.map) # Hell's Heaven
|
|
295
|
+
print(match.map.name) # Hell's Heaven (str)
|
|
296
|
+
print(match.map.id) # 1288
|
|
297
|
+
print(match.map.location) # Hydra Charteris Base
|
|
298
|
+
print(match.game_mode) # Custom
|
|
299
|
+
print(match.gameplay_mode) # Domination
|
|
300
|
+
print(match.platform) # PC
|
|
301
|
+
print(match.hero) # Named Character, when history includes a hero
|
|
302
|
+
print(match.rank) # Named Rank, when a rank level is available
|
|
303
|
+
print(match.season_info) # Named Season, when a season is available
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
These are objects with `__str__`, so `f"Played on {match.map}"` prints the map
|
|
307
|
+
name while `match.map.id` remains available. `game_play_mode` aliases
|
|
308
|
+
`gameplay_mode`. Participants expose `hero`, `top_hero`, `rank_info`, and
|
|
309
|
+
`platform_info`; draft entries expose `hero` and `team`. Existing Character
|
|
310
|
+
records now have `.id`, `.name`, and name-based string formatting.
|
|
311
|
+
|
|
312
|
+
**Migration:** `match.platform` is now a `Platform` object. Use
|
|
313
|
+
`match.platform_id` or `match.platform.id` for its previous numeric value.
|
|
314
|
+
`to_dict()` serializes references as `{id, name, is_known, source, ...}` objects;
|
|
315
|
+
the original `map_id`, `game_mode_id`, and other numeric fields remain present.
|
|
316
|
+
`.raw` preserves the input payload. The packaged catalogs resolve names
|
|
317
|
+
without additional network requests. Unmapped codes produce an explicit
|
|
318
|
+
`Unknown ...` reference with `is_known=False`; absent fields return `None`.
|
|
319
|
+
See [readable match references](docs/GAME_REFERENCES.md) for mapping sources
|
|
320
|
+
and gameplay-code limits.
|
|
321
|
+
|
|
322
|
+
The overall, hero, and class win-rate methods accept `method="estimate"` (the
|
|
323
|
+
default), `"exact"`, or `"cached"`. Overall estimates average available
|
|
324
|
+
RivalsData/RivalsTracker competitive rates; hero estimates average each
|
|
325
|
+
provider's per-hero rates; class estimates aggregate provider hero-participation
|
|
326
|
+
counts within each class before averaging provider rates. These estimates are
|
|
327
|
+
fast and approximate, and include provider sample counts. Exact calculations
|
|
328
|
+
traverse all available history pages and deduplicate by match ID. Hero/class
|
|
329
|
+
exact calculations also inspect match details and assign each match to the
|
|
330
|
+
player's longest-played hero, which can require one detail lookup per match.
|
|
331
|
+
Cached calculations make no requests and reuse a prior
|
|
332
|
+
`matches.fetch(limit="all")` in the same Python process, including across client
|
|
333
|
+
instances. If the cached history fetch had provider errors, the calculation
|
|
334
|
+
does not retry missing data; inspect its coverage/errors. Cached hero/class
|
|
335
|
+
rates use cached playtime details when available and otherwise fall back to
|
|
336
|
+
the history row's hero. The returned metadata reports sources, unknown results,
|
|
337
|
+
provider errors, and hero-attribution fallback counts. See the
|
|
338
|
+
[win-rate method guide](docs/PROVIDER_INTEGRATION.md#win-rate-calculation-choices)
|
|
339
|
+
for the assumptions and costs of each method.
|
|
340
|
+
MCP tools expose the same three methods. `player.proficiency.fetch()` returns a
|
|
341
|
+
`ProficiencyResponse`. Nested match
|
|
254
342
|
teams and participants are converted to `MatchTeam` and `MatchPlayer`; embedded
|
|
255
343
|
character records use `Character`. Models support mapping access
|
|
256
344
|
(`player["level"]`) and attribute access (`player.level`). Unknown upstream
|
|
@@ -271,6 +359,16 @@ with RivalsClient() as rd:
|
|
|
271
359
|
|
|
272
360
|
## Public resources
|
|
273
361
|
|
|
362
|
+
For a player selection list, use `rd.search_players("silo")`, or the MCP tool
|
|
363
|
+
`search_players(name="silo")`. Each candidate includes a name and numeric UID;
|
|
364
|
+
pass the selected UID to `get_player_profile(uid=283622404)` for their profile
|
|
365
|
+
overview. `search_player_candidates` remains an alias, and `get_player` still
|
|
366
|
+
accepts a UID or exact name. MCP `search_players` now returns a list instead
|
|
367
|
+
of one resolved account. Live checks on 2026-10-02 confirmed that the
|
|
368
|
+
candidate search includes `siloء` (UID `283622404`) when searching `silo`.
|
|
369
|
+
See [the player-search audit](docs/PLAYER_SEARCH_AUDIT.md) for provider comparisons
|
|
370
|
+
and exact-name versus suggestion behavior.
|
|
371
|
+
|
|
274
372
|
- `rd.leaderboards.fetch(...)` — global player ranking.
|
|
275
373
|
- `rd.heroes.tier_list(...)`, `.get(hero_id)`, `.meta(hero_id, range=90)`,
|
|
276
374
|
`.leaderboard(hero_id, **filters)` — hero metrics and ranking.
|
|
@@ -317,7 +415,7 @@ Existing functions combine public RivalsData, RivalsTracker, and Tracker.gg data
|
|
|
317
415
|
|
|
318
416
|
## Documentation
|
|
319
417
|
|
|
320
|
-
- [
|
|
418
|
+
- [Release notes and migration guide](docs/CHANGELOG.md)
|
|
321
419
|
- [Provider integration and data-selection rules](docs/PROVIDER_INTEGRATION.md)
|
|
322
420
|
- [Research findings and unsupported features](docs/PROVIDER_FEATURE_GAPS.md)
|
|
323
421
|
- [RivalsTracker API audit](docs/RIVALSTRACKER_API_AUDIT.md)
|
|
@@ -35,7 +35,15 @@ with RivalsClient() as rd:
|
|
|
35
35
|
hero_season = player.heroes.fetch(season=20)
|
|
36
36
|
all_hero_seasons = player.heroes.fetch(season="all")
|
|
37
37
|
map_stats = player.stats.maps(season=20)
|
|
38
|
-
match_page = player.matches.fetch(season=20)
|
|
38
|
+
match_page = player.matches.fetch(limit=20, season=20)
|
|
39
|
+
all_matches = player.matches.fetch(limit="all")
|
|
40
|
+
combined_rate = player.matches.fetch_win_rate(season=20)
|
|
41
|
+
print(combined_rate.win_rate_pct, combined_rate.provider_rates)
|
|
42
|
+
fast_rate = player.matches.fetch_win_rate()
|
|
43
|
+
exact_rate = player.matches.fetch_win_rate(method="exact")
|
|
44
|
+
cached_rate = player.matches.fetch_win_rate(method="cached") # after fetch(limit="all")
|
|
45
|
+
hero_rates = player.matches.fetch_hero_win_rates(method="exact")
|
|
46
|
+
class_rates = player.matches.fetch_class_win_rates(method="cached")
|
|
39
47
|
|
|
40
48
|
# Current match when its provider exposes it; Custom discovery is unsupported.
|
|
41
49
|
live_game = player.live_game.fetch()
|
|
@@ -213,8 +221,88 @@ with annotations for fields observed in the API inventory. This includes
|
|
|
213
221
|
`ProficiencyResponse`, `LeaderboardResponse`, `PunishmentsPage`, `XPPage`,
|
|
214
222
|
`Top500Response`, and typed teammate, crosshair, stats, faction, and insight
|
|
215
223
|
records. For example, `rd.matches.get(match_id)` returns a `Match`,
|
|
216
|
-
`player.matches.fetch()` returns a `MatchHistory
|
|
217
|
-
|
|
224
|
+
`player.matches.fetch(limit=...)` returns a `MatchHistory`. The required limit
|
|
225
|
+
is either a positive number (bounded fetch with a resumable cursor) or
|
|
226
|
+
`"all"` (fetch every available page); both combine and deduplicate providers.
|
|
227
|
+
Each history row is a client-bound `Match`. Call `get_details()` while its
|
|
228
|
+
client is open to lazily fetch combined RivalsData, RivalsTracker, and Tracker.gg
|
|
229
|
+
details, including typed teams, players, and hero segments:
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
with RivalsClient(use_browser_fallback=True) as client:
|
|
233
|
+
player = client.get_player(1970288503)
|
|
234
|
+
history = player.matches.fetch(limit=20)
|
|
235
|
+
if history.matches:
|
|
236
|
+
match = history.matches[0]
|
|
237
|
+
details = match.get_details() # Match; the history row stays unchanged
|
|
238
|
+
for team in details.teams:
|
|
239
|
+
for participant in team.players:
|
|
240
|
+
print(participant.name, participant.get("accuracy_percent"))
|
|
241
|
+
print(details.provider_metadata.errors)
|
|
242
|
+
# match.get_details(refresh=True) bypasses detail/provider caches.
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`client.matches.get(match_id, refresh=False)` uses the same fetcher. Provider
|
|
246
|
+
outages return available details with errors; conflicts and field selections
|
|
247
|
+
remain in `provider_metadata`. `accuracy_percent` uses percent units for players
|
|
248
|
+
and heroes. The legacy RD `accuracy` field remains a player percentage or a
|
|
249
|
+
hero ratio; `session_hit_rate` is separate and is never substituted for accuracy.
|
|
250
|
+
Unknown/NaN accuracy is unavailable. See the
|
|
251
|
+
[match detail guide](docs/PROVIDER_INTEGRATION.md#combined-match-details).
|
|
252
|
+
|
|
253
|
+
History and detail matches also expose readable typed references. They format
|
|
254
|
+
as names in bot messages; use `.name` for a plain string and `.id` for the
|
|
255
|
+
original identifier. For a match with map ID `1288`, mode `3`, and platform `1`:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
print(match.map) # Hell's Heaven
|
|
259
|
+
print(match.map.name) # Hell's Heaven (str)
|
|
260
|
+
print(match.map.id) # 1288
|
|
261
|
+
print(match.map.location) # Hydra Charteris Base
|
|
262
|
+
print(match.game_mode) # Custom
|
|
263
|
+
print(match.gameplay_mode) # Domination
|
|
264
|
+
print(match.platform) # PC
|
|
265
|
+
print(match.hero) # Named Character, when history includes a hero
|
|
266
|
+
print(match.rank) # Named Rank, when a rank level is available
|
|
267
|
+
print(match.season_info) # Named Season, when a season is available
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
These are objects with `__str__`, so `f"Played on {match.map}"` prints the map
|
|
271
|
+
name while `match.map.id` remains available. `game_play_mode` aliases
|
|
272
|
+
`gameplay_mode`. Participants expose `hero`, `top_hero`, `rank_info`, and
|
|
273
|
+
`platform_info`; draft entries expose `hero` and `team`. Existing Character
|
|
274
|
+
records now have `.id`, `.name`, and name-based string formatting.
|
|
275
|
+
|
|
276
|
+
**Migration:** `match.platform` is now a `Platform` object. Use
|
|
277
|
+
`match.platform_id` or `match.platform.id` for its previous numeric value.
|
|
278
|
+
`to_dict()` serializes references as `{id, name, is_known, source, ...}` objects;
|
|
279
|
+
the original `map_id`, `game_mode_id`, and other numeric fields remain present.
|
|
280
|
+
`.raw` preserves the input payload. The packaged catalogs resolve names
|
|
281
|
+
without additional network requests. Unmapped codes produce an explicit
|
|
282
|
+
`Unknown ...` reference with `is_known=False`; absent fields return `None`.
|
|
283
|
+
See [readable match references](docs/GAME_REFERENCES.md) for mapping sources
|
|
284
|
+
and gameplay-code limits.
|
|
285
|
+
|
|
286
|
+
The overall, hero, and class win-rate methods accept `method="estimate"` (the
|
|
287
|
+
default), `"exact"`, or `"cached"`. Overall estimates average available
|
|
288
|
+
RivalsData/RivalsTracker competitive rates; hero estimates average each
|
|
289
|
+
provider's per-hero rates; class estimates aggregate provider hero-participation
|
|
290
|
+
counts within each class before averaging provider rates. These estimates are
|
|
291
|
+
fast and approximate, and include provider sample counts. Exact calculations
|
|
292
|
+
traverse all available history pages and deduplicate by match ID. Hero/class
|
|
293
|
+
exact calculations also inspect match details and assign each match to the
|
|
294
|
+
player's longest-played hero, which can require one detail lookup per match.
|
|
295
|
+
Cached calculations make no requests and reuse a prior
|
|
296
|
+
`matches.fetch(limit="all")` in the same Python process, including across client
|
|
297
|
+
instances. If the cached history fetch had provider errors, the calculation
|
|
298
|
+
does not retry missing data; inspect its coverage/errors. Cached hero/class
|
|
299
|
+
rates use cached playtime details when available and otherwise fall back to
|
|
300
|
+
the history row's hero. The returned metadata reports sources, unknown results,
|
|
301
|
+
provider errors, and hero-attribution fallback counts. See the
|
|
302
|
+
[win-rate method guide](docs/PROVIDER_INTEGRATION.md#win-rate-calculation-choices)
|
|
303
|
+
for the assumptions and costs of each method.
|
|
304
|
+
MCP tools expose the same three methods. `player.proficiency.fetch()` returns a
|
|
305
|
+
`ProficiencyResponse`. Nested match
|
|
218
306
|
teams and participants are converted to `MatchTeam` and `MatchPlayer`; embedded
|
|
219
307
|
character records use `Character`. Models support mapping access
|
|
220
308
|
(`player["level"]`) and attribute access (`player.level`). Unknown upstream
|
|
@@ -235,6 +323,16 @@ with RivalsClient() as rd:
|
|
|
235
323
|
|
|
236
324
|
## Public resources
|
|
237
325
|
|
|
326
|
+
For a player selection list, use `rd.search_players("silo")`, or the MCP tool
|
|
327
|
+
`search_players(name="silo")`. Each candidate includes a name and numeric UID;
|
|
328
|
+
pass the selected UID to `get_player_profile(uid=283622404)` for their profile
|
|
329
|
+
overview. `search_player_candidates` remains an alias, and `get_player` still
|
|
330
|
+
accepts a UID or exact name. MCP `search_players` now returns a list instead
|
|
331
|
+
of one resolved account. Live checks on 2026-10-02 confirmed that the
|
|
332
|
+
candidate search includes `siloء` (UID `283622404`) when searching `silo`.
|
|
333
|
+
See [the player-search audit](docs/PLAYER_SEARCH_AUDIT.md) for provider comparisons
|
|
334
|
+
and exact-name versus suggestion behavior.
|
|
335
|
+
|
|
238
336
|
- `rd.leaderboards.fetch(...)` — global player ranking.
|
|
239
337
|
- `rd.heroes.tier_list(...)`, `.get(hero_id)`, `.meta(hero_id, range=90)`,
|
|
240
338
|
`.leaderboard(hero_id, **filters)` — hero metrics and ranking.
|
|
@@ -281,7 +379,7 @@ Existing functions combine public RivalsData, RivalsTracker, and Tracker.gg data
|
|
|
281
379
|
|
|
282
380
|
## Documentation
|
|
283
381
|
|
|
284
|
-
- [
|
|
382
|
+
- [Release notes and migration guide](docs/CHANGELOG.md)
|
|
285
383
|
- [Provider integration and data-selection rules](docs/PROVIDER_INTEGRATION.md)
|
|
286
384
|
- [Research findings and unsupported features](docs/PROVIDER_FEATURE_GAPS.md)
|
|
287
385
|
- [RivalsTracker API audit](docs/RIVALSTRACKER_API_AUDIT.md)
|
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.0.0 — 2026-10-02
|
|
4
|
+
|
|
5
|
+
This release changes `match.platform` from a scalar to a typed `Platform`.
|
|
6
|
+
Use `match.platform.id` or `match.platform_id` for the previous numeric value.
|
|
7
|
+
Serialized matches now contain a structured `platform` and readable reference
|
|
8
|
+
objects alongside legacy numeric fields. See `docs/GAME_REFERENCES.md` for
|
|
9
|
+
migration details.
|
|
10
|
+
|
|
11
|
+
- Added readable typed map, queue, gameplay, platform, rank, season, and hero
|
|
12
|
+
references to match/history models, including nested participants and draft
|
|
13
|
+
entries. Names resolve offline; unknown IDs remain explicit. Map 1288 now
|
|
14
|
+
formats as Hell's Heaven, with its Hydra Charteris Base location accessible.
|
|
15
|
+
`match.platform` is now a Platform object; use `.platform_id` for its scalar.
|
|
16
|
+
Serialized responses include structured reference objects alongside legacy IDs.
|
|
17
|
+
- Lazy details retain missing same-match context from their originating history
|
|
18
|
+
row, with sources recorded in `provider_metadata.history_context`.
|
|
19
|
+
- Added lazy `Match.get_details(refresh=False)` to typed history rows from both
|
|
20
|
+
providers, bounded/all fetches, and iteration. It returns a new typed full
|
|
21
|
+
match through the same combined fetcher as `client.matches.get(...)`.
|
|
22
|
+
- Match details preserve raw provider responses, failures, completeness,
|
|
23
|
+
per-field provenance, and unresolved conflicts. They add provider-only roster
|
|
24
|
+
entries and hero segments while retaining ambiguous identities separately;
|
|
25
|
+
responses for a different match are rejected.
|
|
26
|
+
- Separated `session_hit_rate` from accuracy. Added `accuracy_percent` for
|
|
27
|
+
player/hero percentage access, preserving RD's legacy player-percentage and
|
|
28
|
+
hero-ratio `accuracy` fields. Unusable accuracy is missing.
|
|
29
|
+
- Scoped shared detail caches by enrichment mode and isolated returned objects.
|
|
30
|
+
Partial details retry on lookup; `refresh=True` bypasses both detail and
|
|
31
|
+
provider response caches. MCP `get_match` also accepts `refresh`.
|
|
32
|
+
|
|
33
|
+
## 2.1.0 — 2026-10-02
|
|
34
|
+
|
|
35
|
+
- `player.matches.fetch` now requires `limit`: pass a positive integer for a
|
|
36
|
+
bounded, resumable page of combined history, or `"all"` to traverse all
|
|
37
|
+
available pages. Results are merged and deduplicated across providers.
|
|
38
|
+
- Added overall, hero, and class win-rate methods to Python and MCP. Each
|
|
39
|
+
defaults to a quick provider-summary estimate and also supports exact
|
|
40
|
+
calculations over match history or request-free calculations from full
|
|
41
|
+
history already cached in the current Python process. Hero/class exact rates
|
|
42
|
+
attribute matches using the player's longest-played hero from match details,
|
|
43
|
+
with a summary-hero fallback when detail evidence is unavailable.
|
|
44
|
+
- Match history is shared in a bounded process-level calculation cache so
|
|
45
|
+
separate client instances can reuse previously fetched full history. Results
|
|
46
|
+
expose provider coverage, unknown outcomes, and hero attribution fallbacks;
|
|
47
|
+
exact hero/class calls may require a detail lookup for each match.
|
|
48
|
+
- MCP `search_players(name)` now returns a list of matching players with names
|
|
49
|
+
and numeric game UIDs instead of automatically resolving one account. Callers
|
|
50
|
+
must handle list results, including an empty list for no matches.
|
|
51
|
+
- Added MCP `get_player_profile(uid)` to fetch the selected player's overview by
|
|
52
|
+
numeric UID. `get_player(uid_or_name)` remains available, and
|
|
53
|
+
`search_player_candidates` is an alias for the list search.
|
|
54
|
+
|
|
3
55
|
## 2.0.0 — 2026-10-02
|
|
4
56
|
|
|
5
57
|
This release changes the project from a RivalsData-only wrapper into **rivals-api**,
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Readable game references
|
|
2
|
+
|
|
3
|
+
`Match` exposes `map: Map`, `game_mode: GameMode`,
|
|
4
|
+
`gameplay_mode: GameplayMode` (`game_play_mode` is an alias),
|
|
5
|
+
`platform: Platform`, `rank: Rank`, `season_info: Season`, and `hero: Character`.
|
|
6
|
+
Unavailable references are `None`. Printing or formatting a reference uses its
|
|
7
|
+
name; `.name` returns a string, `.id` retains its upstream identifier.
|
|
8
|
+
`Map.location` gives the broader location. `match.winner` references the winning
|
|
9
|
+
`MatchTeam` when known; `match.result` gives Victory, Defeat, or Draw when the
|
|
10
|
+
response establishes it. Team names are neutral Team 1/Team 2 labels; they do
|
|
11
|
+
not claim which side attacked or defended. Match and participant `.id` aliases
|
|
12
|
+
their respective match/game-player identifiers.
|
|
13
|
+
|
|
14
|
+
`MatchPlayer.hero` uses an explicitly reported hero or top hero, retaining the
|
|
15
|
+
corresponding Character's segment statistics when available. `top_hero`,
|
|
16
|
+
`rank_info`, and `platform_info` resolve their corresponding fields. Draft
|
|
17
|
+
entries have typed `hero` and `team` references. Stats records with `rank_level`,
|
|
18
|
+
`season`, `os`, or `login_os` expose `rank_info`, `season_info`, or
|
|
19
|
+
`platform_info`; player profiles also expose `platform_info`. Numeric fields
|
|
20
|
+
remain available. Account IDs, replay identifiers, party IDs, cosmetic IDs and
|
|
21
|
+
other opaque identifiers are preserved as reported: no established name
|
|
22
|
+
catalog was found for them, and party identifiers are not treated as match
|
|
23
|
+
team camps.
|
|
24
|
+
|
|
25
|
+
## Serialization and compatibility
|
|
26
|
+
|
|
27
|
+
References are mapping-compatible models. `match["map"].name` and
|
|
28
|
+
`match.map.name` are equivalent. `to_dict()` recursively serializes references
|
|
29
|
+
into ordinary JSON objects with `id`, `name`, `is_known`, `source`, and any
|
|
30
|
+
type-specific fields. It retains legacy `map_id`, `game_mode_id`,
|
|
31
|
+
`game_play_mode_id`, `season`, `hero_id`, and `rank_level` fields.
|
|
32
|
+
|
|
33
|
+
`match.platform` now holds a `Platform`; use `.platform_id` or `.platform.id`
|
|
34
|
+
for the original scalar. Serialized matches include both `platform_id` and the
|
|
35
|
+
structured `platform`. `.raw` remains the original input, including numeric
|
|
36
|
+
platform values on responses fetched from providers. Models round-trip through
|
|
37
|
+
`Match(match.to_dict())` without losing labels or nested Character types.
|
|
38
|
+
|
|
39
|
+
Unknown codes retain their IDs, display `Unknown map`, `Unknown platform`,
|
|
40
|
+
etc., and report `is_known=False`. No label is inferred by truncating a number,
|
|
41
|
+
guessing a future season, or treating every console as PlayStation. Known
|
|
42
|
+
provider labels can resolve a new map even before the packaged catalog changes.
|
|
43
|
+
Names are resolved locally; constructing history references makes no detail or
|
|
44
|
+
metadata requests. `get_details()` also fills missing map/queue/platform/season
|
|
45
|
+
context from the same history match, recording those fields and their sources
|
|
46
|
+
under `provider_metadata.history_context`. Detail values take precedence.
|
|
47
|
+
|
|
48
|
+
## Catalog evidence (checked 2026-10-02)
|
|
49
|
+
|
|
50
|
+
The packaged `src/rivals_api/game_catalog.json` contains 118 map variants and
|
|
51
|
+
20 verified season identifiers. It prefers the specific map names from
|
|
52
|
+
[RivalsData's current public match catalog](https://rivalsdata.com/assets/matches-BtVAubcc.js)
|
|
53
|
+
and fills additional variants and location labels from
|
|
54
|
+
[RivalsTracker's public map catalog](https://rivalstracker.com/_nuxt/CUE0zxkU.js).
|
|
55
|
+
For example, `1288` is **Hell's Heaven**, location **Hydra Charteris Base**,
|
|
56
|
+
objective **Domination**; `1245` is **Spider-Islands**, objective **Convoy**.
|
|
57
|
+
Provider-supplied `map_name` / `map_mode_name` values take precedence when usable.
|
|
58
|
+
The catalogs contain provider-maintained labels; resolving a label is not a
|
|
59
|
+
claim that every provider label has been independently verified in-game.
|
|
60
|
+
|
|
61
|
+
Queue codes `1/2/3/4` mean Quick Match / Competitive / Custom / Arcade. Code 5
|
|
62
|
+
is Tutorial in RivalsTracker; 7 is Practice vs AI; 9/10 are Tournament. Sources
|
|
63
|
+
disagree about code 6: RivalsData labels it **Duel**, RivalsTracker **Practice**.
|
|
64
|
+
The model follows the selected field's provider when available, exposes both
|
|
65
|
+
under `.alternatives`, and reports an unknown name if its source is unestablished.
|
|
66
|
+
See the [RivalsData catalog](https://rivalsdata.com/assets/matches-BtVAubcc.js)
|
|
67
|
+
and [RivalsTracker match UI](https://rivalstracker.com/_nuxt/DDKdWPNg.js).
|
|
68
|
+
|
|
69
|
+
The raw `game_play_mode_id` has no verified universal objective-name mapping.
|
|
70
|
+
The same code `200` can be returned for different map objectives. Accordingly,
|
|
71
|
+
`GameplayMode.name` comes from the match's `map_mode_name` or its map variant's
|
|
72
|
+
catalog entry. Its `.id` retains the raw gameplay code and `.map_id` records the
|
|
73
|
+
context. Without a known map/objective it stays unknown. It must not be used as
|
|
74
|
+
a global `200 = Convoy` lookup.
|
|
75
|
+
|
|
76
|
+
Platform codes **1 = PC, 2 = PlayStation, 4 = Xbox** are established by both
|
|
77
|
+
[RivalsData's leaderboard platform options](https://rivalsdata.com/assets/index-B7e1fRs3.js)
|
|
78
|
+
and [RivalsTracker's leaderboard](https://rivalstracker.com/_nuxt/C7pX95rV.js).
|
|
79
|
+
Code 3 is unestablished, so it remains unknown. Platform strings such as `pc`,
|
|
80
|
+
`psn`, and `xbl` retain their original string ID while resolving their name.
|
|
81
|
+
Rank levels and divisions follow the
|
|
82
|
+
[provider rank catalog](https://rivalsdata.com/assets/ranks-D6blxaOO.js), with
|
|
83
|
+
RivalsTracker's observed levels 23–25 labeled One Above All. These are rank
|
|
84
|
+
levels, not hero-stat tier filter IDs, which use a different numbering scheme.
|
|
85
|
+
Season labels follow that same RivalsData catalog and the recorded Tracker
|
|
86
|
+
profile season metadata: internal ID 20 is Season 10, 19 is Season 9.5, and
|
|
87
|
+
1 is Season 0. No future season label is extrapolated.
|
|
88
|
+
|
|
89
|
+
Catalog updates should verify the current public assets and retain map variant
|
|
90
|
+
keys; several RivalsTracker entries have an inner `ModeID` that differs from
|
|
91
|
+
their dictionary key. The variant dictionary key is the lookup identifier.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Player search: `silo` and `siloء`
|
|
2
|
+
|
|
3
|
+
Live checks on 2026-10-02. The requested behavior is a list of accounts for
|
|
4
|
+
`silo` that includes `siloء`, whose final character is U+0621 (Arabic hamza).
|
|
5
|
+
The exact-name result identifies that account as game UID **283622404**.
|
|
6
|
+
|
|
7
|
+
## Results
|
|
8
|
+
|
|
9
|
+
| Source | Search for `silo` | Search for `siloء` | Meets the requested suggestion behavior now? |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| RivalsData | One result: `Silo`, UID 1254981449 | One result: `siloء`, UID 283622404 | No |
|
|
12
|
+
| RivalsTracker | 10 results; `siloء` is fifth, UID 283622404 | One result: `siloء`, UID 283622404 | Yes |
|
|
13
|
+
| RivalsMeta | 10 results; `siloء` is fifth, UID 283622404 | One result: `siloء`, UID 283622404 | Yes |
|
|
14
|
+
| Tracker.gg autocomplete | 20 results, excluding `siloء` | One result: `siloء` | No for the shorter query |
|
|
15
|
+
| Tracker.gg submitted search | One result: `Silo` | One result: `siloء` | No for the shorter query |
|
|
16
|
+
| OP.GG website | Five displayed results after loading; `siloء` is fifth | Navigates to the `siloء` profile | Yes at the website level; a reusable search API contract was not established |
|
|
17
|
+
|
|
18
|
+
RivalsTracker and RivalsMeta returned identical search arrays in these checks.
|
|
19
|
+
This does not establish that they have independent databases or search coverage.
|
|
20
|
+
Tracker.gg's exact-name profile route also returned a public overview response
|
|
21
|
+
for `siloء`. These observations show that the character can be represented and
|
|
22
|
+
the account can be found. They do not establish why the short-query suggestions
|
|
23
|
+
omit it, nor that special characters in general are filtered out.
|
|
24
|
+
|
|
25
|
+
RivalsTracker's observed list, in order:
|
|
26
|
+
|
|
27
|
+
1. `-SILO_`
|
|
28
|
+
2. `Silo`
|
|
29
|
+
3. `Silo_`
|
|
30
|
+
4. `Silo_RAE`
|
|
31
|
+
5. `siloء`
|
|
32
|
+
6. `Silo_Koios`
|
|
33
|
+
7. `Silo af`
|
|
34
|
+
8. `Silo.is.bot`
|
|
35
|
+
9. `silo_greedy`
|
|
36
|
+
10. `Silo_92`
|
|
37
|
+
|
|
38
|
+
## Exact requests and evidence
|
|
39
|
+
|
|
40
|
+
- RivalsData: `POST https://api.rivalsdata.com/players/search`, JSON
|
|
41
|
+
`{"name":"silo"}` or `{"name":"siloء"}`. Both returned HTTP 200.
|
|
42
|
+
The friend's record contains `aid: "11001_283622404"`.
|
|
43
|
+
- RivalsTracker: `POST https://api.rivalstracker.com/api/find-player`, same JSON
|
|
44
|
+
bodies. Both returned HTTP 200. The friend's row was
|
|
45
|
+
`{"aid":"283622404","name":"siloء","cur_head_icon_id":"31048204"}`.
|
|
46
|
+
- RivalsMeta: `POST https://rivalsmeta.com/api/find-player`, same JSON bodies.
|
|
47
|
+
Both returned HTTP 200 and the same search rows as RivalsTracker. This route
|
|
48
|
+
and body were found in the site's current search component and runtime config.
|
|
49
|
+
- Tracker.gg: `GET https://api.tracker.gg/api/v2/marvel-rivals/standard/search`
|
|
50
|
+
with `platform=ign`, `query=silo` or `query=siloء`, and `autocomplete=true`
|
|
51
|
+
for suggestions. Submitted search omits `autocomplete`. Direct HTTP was
|
|
52
|
+
challenged with 403; the existing Camoufox provider fallback succeeded for
|
|
53
|
+
all four searches. Exact profile:
|
|
54
|
+
`/api/v2/marvel-rivals/standard/profile/ign/silo%D8%A1`.
|
|
55
|
+
- OP.GG: [short-name search](https://op.gg/marvel-rivals/search/silo) and
|
|
56
|
+
[full-name search](https://op.gg/marvel-rivals/search/silo%D8%A1), checked in
|
|
57
|
+
Camoufox. The short-name page initially showed four rows; after a longer load
|
|
58
|
+
it showed `Silofael`, `Silonace`, `silosue`, `Siloger`, and `siloء`. The exact
|
|
59
|
+
search opened the profile, which showed privacy and update notices. Those
|
|
60
|
+
notices were respected; no update button was clicked and no private stats
|
|
61
|
+
were requested. The list itself is the relevant evidence here.
|
|
62
|
+
|
|
63
|
+
All these are observed website behaviors, not permanent API guarantees.
|
|
64
|
+
Local raw responses and browser observations are saved in the ignored
|
|
65
|
+
`dist/search-audit/` directory. No cookies, authorization headers, or API keys
|
|
66
|
+
were saved in the research artifacts.
|
|
67
|
+
|
|
68
|
+
## Existing wrapper behavior
|
|
69
|
+
|
|
70
|
+
The Python method `RivalsClient.search_players()` already uses RivalsTracker's
|
|
71
|
+
multi-result `/find-player` endpoint. A live call to `search_players("silo")`
|
|
72
|
+
returned all 10 candidates, preserving `siloء` and adding numeric UID 283622404.
|
|
73
|
+
It currently queries RivalsTracker alone; it does not merge all three providers.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from rivals_api import RivalsClient
|
|
77
|
+
|
|
78
|
+
with RivalsClient() as client:
|
|
79
|
+
candidates = client.search_players("silo")
|
|
80
|
+
# Includes a row with name == "siloء" and uid == 283622404.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Following this audit, the MCP search/profile flow was updated:
|
|
84
|
+
|
|
85
|
+
| MCP tool | What it calls | Live result for `silo` |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `search_players(name="silo")` | `client.search_players("silo")` | 10 candidates, including `siloء`, UID 283622404 |
|
|
88
|
+
| `search_player_candidates(name="silo")` | `client.search_players("silo")` | 10 candidates, including `siloء`, UID 283622404 |
|
|
89
|
+
| `get_player_profile(uid=283622404)` | `get_player("283622404")` | Profile overview for the selected numeric UID; not a candidate search |
|
|
90
|
+
|
|
91
|
+
The original MCP `search_players` resolved one account through RivalsData and
|
|
92
|
+
returned `Silo`, UID 1254981449. It now returns the same list as the candidate
|
|
93
|
+
tool. For a selection list, use **`search_players`**, then **`get_player_profile`**
|
|
94
|
+
with the chosen UID. The candidate tool remains a compatibility alias.
|
|
95
|
+
Entering `silo` into a single-account resolver should not be treated as a
|
|
96
|
+
selection of `siloء`.
|
|
97
|
+
|
|
98
|
+
## Other trackers and APIs checked
|
|
99
|
+
|
|
100
|
+
- [RivalCounter](https://www.rivalcounter.com/) routes player searches to
|
|
101
|
+
filtering its top-500 leaderboard snapshot. Its frontend labels this as
|
|
102
|
+
matching leaderboard entries. The current PC snapshot did not contain this
|
|
103
|
+
UID; this is not a general player-discovery replacement.
|
|
104
|
+
- [MarvelRivalsAPI's documented search](https://docs.marvelrivalsapi.com/search-player-19312750e0)
|
|
105
|
+
is `GET /api/v1/find-player/{username}` and documents one name/UID result and
|
|
106
|
+
an `x-api-key` header. The anonymous `silo` probe returned a gateway error
|
|
107
|
+
(502), so live account coverage was not established.
|
|
108
|
+
- [RivalsIsland](https://api.rivalsisland.com/) documents
|
|
109
|
+
`GET /players/search?name=...` in `/docs/openapi.json`, with a singular
|
|
110
|
+
`player` response. Both anonymous queries returned 401, missing API key.
|
|
111
|
+
Its UI describes exact-name lookup; suggestion coverage is unverified.
|
|
112
|
+
- `mrapi.org` did not resolve in this environment. No current search behavior
|
|
113
|
+
could be verified.
|
|
114
|
+
|
|
115
|
+
## Recommendation
|
|
116
|
+
|
|
117
|
+
Use the RivalsTracker candidate path for this task. RivalsMeta is a
|
|
118
|
+
confirmed alternative endpoint, and OP.GG also finds the account on its website.
|
|
119
|
+
An additional provider is not needed to produce the requested list today.
|
|
120
|
+
|
|
121
|
+
If “always included” is a product requirement, third-party suggestions alone
|
|
122
|
+
cannot guarantee it. Persist the user's verified association between the alias
|
|
123
|
+
`silo` and UID 283622404, then merge that known account with live suggestions,
|
|
124
|
+
deduplicating by UID and preserving the displayed name `siloء`. Keep aliases
|
|
125
|
+
scoped to the user or application that chose them; do not globally equate `Silo`
|
|
126
|
+
with `siloء`. Resolve future names through the stored UID when available, and
|
|
127
|
+
retain a clearly labeled saved candidate during upstream outages.
|
|
128
|
+
|
|
129
|
+
The follow-up MCP change routes `search_players` to the existing candidate
|
|
130
|
+
search and adds the UID-only profile tool. A persistent alias index is not
|
|
131
|
+
implemented.
|
|
@@ -17,7 +17,7 @@ implemented feature. Provider APIs are unofficial/undocumented and may change.
|
|
|
17
17
|
|
|
18
18
|
- Distribution: `rivals-api`; preferred import: `rivals_api`.
|
|
19
19
|
- Compatibility: `rivalsdata` and `RivalsDataClient` remain aliases.
|
|
20
|
-
- Version: `
|
|
20
|
+
- Version: `3.0.0`.
|
|
21
21
|
- Python `>=3.10`, Hatchling build, `src/` layout.
|
|
22
22
|
- Runtime HTTP dependency: `curl-cffi`; optional browser fallback: Camoufox.
|
|
23
23
|
- Public entry point: `RivalsClient`.
|
|
@@ -67,11 +67,40 @@ details, leaderboards, heroes, team-ups, insights, factions, profiles and
|
|
|
67
67
|
favorites. New analytics and public community resources are documented in
|
|
68
68
|
`docs/PROVIDER_INTEGRATION.md` and the feature-gap inventory.
|
|
69
69
|
|
|
70
|
+
History rows carry their originating client and expose `match.get_details()`.
|
|
71
|
+
Both bounded/all fetches and iteration return these bound `Match` objects. The
|
|
72
|
+
method returns a new typed full `Match` through `client.matches.get(...)`, with
|
|
73
|
+
`refresh=True` available to bypass detail/provider caches. The client reference
|
|
74
|
+
is excluded from model serialization. Keep it open while fetching details.
|
|
75
|
+
The shared fetcher in `match_details.py` validates provider match IDs, preserves
|
|
76
|
+
raw responses and errors, merges roster/hero records by identity, and exposes
|
|
77
|
+
per-field source decisions and completeness. Ambiguous player bridges remain
|
|
78
|
+
unmatched. Accuracy percent is distinct from session hit rate; raw RD hero
|
|
79
|
+
accuracy retains ratio units. Detail caches are scoped to the enrichment setting;
|
|
80
|
+
partial cached evidence remains usable for request-free calculations but is
|
|
81
|
+
retried by detail lookups.
|
|
82
|
+
|
|
83
|
+
Match models resolve map, queue, gameplay, platform, rank, season, and hero
|
|
84
|
+
references offline from packaged provider catalogs. References format as names
|
|
85
|
+
and expose `.id`; the original numeric fields remain except `match.platform`,
|
|
86
|
+
which is a typed Platform with `.platform_id` providing the previous scalar.
|
|
87
|
+
Gameplay labels come from the map/objective context rather than guessing a
|
|
88
|
+
global interpretation of `game_play_mode_id`. Unknown codes stay explicit.
|
|
89
|
+
The catalog covers 118 map variants and 20 observed seasons; source evidence
|
|
90
|
+
and serialization/migration details are in `docs/GAME_REFERENCES.md`.
|
|
91
|
+
|
|
70
92
|
The MCP server exposes read-only tools over stdio or Streamable HTTP. It does
|
|
71
93
|
not implement authentication; remote deployments must supply an authenticated
|
|
72
94
|
gateway. The dashboard shows a snapshot and performs provider requests when a
|
|
73
95
|
tool runs.
|
|
74
96
|
|
|
97
|
+
MCP `search_players(name)` returns a list of RivalsTracker candidates with names
|
|
98
|
+
and numeric game UIDs. `get_player_profile(uid)` retrieves the chosen profile
|
|
99
|
+
by positive integer UID, including its current-season competitive win rate.
|
|
100
|
+
`search_player_candidates` is an alias for the list search; the existing
|
|
101
|
+
`get_player(uid_or_name)` tool remains available. The search tool previously
|
|
102
|
+
resolved one account, so callers must migrate to handling list results.
|
|
103
|
+
|
|
75
104
|
## Development and release
|
|
76
105
|
|
|
77
106
|
Create an isolated virtual environment and install `.[dev]`. Install
|