История: изменение рейтинга на карточках партий профиля

GET /users/{id}/matches отдаёт у каждой партии rating_delta — изменение
общего рейтинга владельца истории за неё (один знак после запятой), в обоих
режимах, включая «лучшую партию»; история и рейтинг считаются одним
проигрыванием. В списке партий группы поле пустое: там непонятно, чья это
дельта.

Фронт: компактная карточка истории — второй строкой «Рейтинг: +12.3»,
подробная (MatchListView) — последней строкой, только когда дельта есть.
Рост — зелёным, падение — красным, минус типографский (formatRatingDelta).
schema.d.ts перегенерирован.

Тест: дуэль новичков ±32 в обеих историях, реванш с обратными знаками,
сумма изменений сходится с рейтингом, в списке группы дельты нет, режим
«лучшая» её отдаёт. #77

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
This commit is contained in:
2026-09-14 23:51:37 +03:00
co-authored by Claude Opus 5
parent 171aebb6f8
commit 6f54e0f9df
9 changed files with 102 additions and 29 deletions
+27
View File
@@ -138,3 +138,30 @@ def test_best_match_is_biggest_rating_gain(client: TestClient, engine):
data = client.get(f"/api/users/{me['id']}/matches").json()
assert data["total"] == 1
assert data["items"][0]["id"] == first["id"]
def test_history_shows_rating_delta_of_its_owner(client: TestClient, engine):
"""История игрока несёт изменение его общего рейтинга за каждую партию (#77)."""
me = login(client, "Историк")
gid, fids = _group(client)
b = add_group_member(engine, gid, "Оппонент")
_duel(client, gid, fids, me["id"], b) # новички на 1500: ±32
_duel(client, gid, fids, b, me["id"]) # реванш: 1468 обыгрывает 1532
mine = client.get(f"/api/users/{me['id']}/matches").json()["items"]
theirs = client.get(f"/api/users/{b}/matches").json()["items"]
# Свежие сверху: реванш первым.
assert (mine[1]["rating_delta"], theirs[1]["rating_delta"]) == (32.0, -32.0)
assert mine[0]["rating_delta"] == -theirs[0]["rating_delta"] < 0
# Изменения складываются в рейтинг (с точностью округления до десятых).
score = _board(client)[me["id"]]["score"]
assert abs(1500 + sum(i["rating_delta"] for i in mine) - score) <= 0.6
# В списке партий группы дельты нет — непонятно, чья она была бы.
group_items = client.get(f"/api/groups/{gid}/matches").json()["items"]
assert [i["rating_delta"] for i in group_items] == [None, None]
# Режим «лучшая партия» тоже её отдаёт.
client.patch("/api/users/me/profile", json={"history_mode": "best"}, headers=csrf_headers(client))
best = client.get(f"/api/users/{me['id']}/matches").json()["items"]
assert best[0]["rating_delta"] == 32.0