[BUG] Overall weighted acc calculation returning wrong values
Since some time we've been experiencing weird issues with weighted acc calculation, we've had some users that were aiming for profile acc of 100%. But after some time acc went down even though they had only SS ranks.
Here's one of our users, his scores and output of acc calculation
https://pastebin.com/yYEG1H1Y

I used bancho.py's acc calculation method and fetched scores where status=2 in mode=4
diff --git a/app/api/domains/osu.py b/app/api/domains/osu.py
index 2a13667..81ade2a 100644
--- a/app/api/domains/osu.py
+++ b/app/api/domains/osu.py
@@ -1036,20 +1036,19 @@ async def osuSubmitModularSelector(
                 {"user_id": score.player.id, "mode": score.mode},
             )
 
-            total_scores = len(best_scores)
-            top_100_pp = best_scores[:100]
-
             # calculate new total weighted accuracy
             weighted_acc = sum(
-                row["acc"] * 0.95**i for i, row in enumerate(top_100_pp)
+                row["acc"] * 0.95**i for i, row in enumerate(best_scores)
             )
-            bonus_acc = 100.0 / (20 * (1 - 0.95**total_scores))
+            bonus_acc = 100.0 / (20 * (1 - 0.95 ** len(best_scores)))
             stats.acc = (weighted_acc * bonus_acc) / 100
             stats_updates["acc"] = stats.acc
 
             # calculate new total weighted pp
-            weighted_pp = sum(row["pp"] * 0.95**i for i, row in enumerate(top_100_pp))
-            bonus_pp = 416.6667 * (1 - 0.9994**total_scores)
+            weighted_pp = sum(
+                row["pp"] * 0.95**i for i, row in enumerate(best_scores)
+            )
+            bonus_pp = 416.6667 * (1 - 0.9994 ** len(best_scores))
             stats.pp = round(weighted_pp + bonus_pp)
             stats_updates["pp"] = stats.pp
 
diff --git a/tools/recalc.py b/tools/recalc.py
index fae5483..25a2e17 100644
--- a/tools/recalc.py
+++ b/tools/recalc.py
@@ -212,9 +212,23 @@ async def main(argv: Optional[Sequence[str]] = None) -> int:
     if len(argv) == 0:
         argv = ["--help"]
 
-    parser = argparse.ArgumentParser(description="Recalculate performance for scores")
+    parser = argparse.ArgumentParser(
+        description="Recalculate performance for scores and/or stats",
+    )
 
     parser.add_argument("-d", "--debug", action="store_true")
+    parser.add_argument(
+        "--scores",
+        description="Recalculate scores",
+        action="store_true",
+        default=True,
+    )
+    parser.add_argument(
+        "--stats",
+        description="Recalculate stats",
+        action="store_true",
+        default=True,
+    )
 
     parser.add_argument(
         "-m",
@@ -241,8 +255,11 @@ async def main(argv: Optional[Sequence[str]] = None) -> int:
     for mode in args.mode:
         mode = GameMode(int(mode))
 
-        await recalculate_mode_scores(mode, ctx)
-        await recalculate_mode_users(mode, ctx)
+        if args.scores:
+            await recalculate_mode_scores(mode, ctx)
+
+        if args.stats:
+            await recalculate_mode_users(mode, ctx)
 
     await app.state.services.http_client.close()
     await db.disconnect()
['app/api/domains/osu.py', 'tools/recalc.py']