oettaM123 Claude Opus 4.8 commited on
Commit
b57b82b
·
1 Parent(s): d41587d

Power-series: bind history to account id, not name

Browse files

The live lookup only populates player_id when ranks are attached
(_sm_attach_level_ranks), which normal lookups skip — so recorded
points were key'd by name (or dropped), and the chart (which queries
by id) found nothing. Now the recorder resolves the account id from
the scanner-maintained leaderboard by name when the result lacks a
player_id, and stores strictly under id:<player_id> (no name fallback),
so history survives renames and never fragments by name. Harden the
name->id leaderboard scan against concurrent-mutation RuntimeErrors.

Verified end-to-end: a normal lookup (player_id=None) and a scanner
ingest push both now record an exact point under the account id;
sub-1-Qnt accounts are still skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +16 -5
app.py CHANGED
@@ -8320,8 +8320,12 @@ def _sm_power_series_record(result: dict):
8320
  level = int(result.get("level"))
8321
  except (TypeError, ValueError):
8322
  return
8323
- key = _sm_leaderboard_storage_key(result.get("username") or "", result.get("player_id") or "")
8324
- if not key:
 
 
 
 
8325
  return
8326
  gold = _sm_float_sort_value(result.get("gold_raw"))
8327
  sword = _sm_pseries_gear_type(result.get("sword_type"))
@@ -8372,9 +8376,16 @@ def _sm_pseries_resolve_key(username: str, player_id: str):
8372
  try:
8373
  with _SM_LEADERBOARD_LOCK:
8374
  players = _sm_leaderboard_load_unlocked().get("players") or {}
8375
- for k, r in players.items():
8376
- if str(k).startswith("id:") and _discord_lookup_key((r or {}).get("username")) == want:
8377
- return str(k)
 
 
 
 
 
 
 
8378
  except Exception: # noqa: BLE001
8379
  pass
8380
  return key
 
8320
  level = int(result.get("level"))
8321
  except (TypeError, ValueError):
8322
  return
8323
+ # Zeitreihe NUR an die Account-ID binden (kein name:-Fallback) -> überlebt Umbenennungen
8324
+ # und wird nie nach Namen fragmentiert. player_id direkt bevorzugt; fehlt sie (normaler
8325
+ # Lookup ohne Rang -> _sm_attach_level_ranks setzt sie nicht), wird sie über das
8326
+ # (scanner-gepflegte) Leaderboard per Name aufgelöst. Keine ID auflösbar -> nicht speichern.
8327
+ key = _sm_pseries_resolve_key(result.get("username") or "", result.get("player_id") or "")
8328
+ if not key.startswith("id:"):
8329
  return
8330
  gold = _sm_float_sort_value(result.get("gold_raw"))
8331
  sword = _sm_pseries_gear_type(result.get("sword_type"))
 
8376
  try:
8377
  with _SM_LEADERBOARD_LOCK:
8378
  players = _sm_leaderboard_load_unlocked().get("players") or {}
8379
+ # Lock-frei iterieren (kein langer Lock-Hold bei ~1,7 Mio Zeilen). Falls ein anderer
8380
+ # Thread die dict-Groesse waehrend der Iteration aendert -> kurz erneut versuchen.
8381
+ for _attempt in range(3):
8382
+ try:
8383
+ for k, r in players.items():
8384
+ if str(k).startswith("id:") and _discord_lookup_key((r or {}).get("username")) == want:
8385
+ return str(k)
8386
+ break
8387
+ except RuntimeError:
8388
+ continue
8389
  except Exception: # noqa: BLE001
8390
  pass
8391
  return key