OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      26ea907a7b6b
DATE      2025-08-29
SUBJECT   web: improve team identification algo
FILES     2 CHANGED
HASH      26ea907a7b6b
DATE      2025-08-29
SUBJECT   web: improve team identification algo
FILES     2 CHANGED
 

diff --git a/nix/apps/team-leaderboard-generator.nix b/nix/apps/team-leaderboard-g
enerator.nix
index 5de1d01..e508ef3 100644
--- a/nix/apps/team-leaderboard-generator.nix
+++ b/nix/apps/team-leaderboard-generator.nix
@@ -231,7 +231,35 @@
                       "all_runs": sorted(all_runs, key=lambda x: x["duration"])
                   }
 
-                  deduplicated.append(merged_team)
+                  # Validate that merged core players appear in most of their bes
t runs
+                  core_participation_count = 0
+                  total_best_runs = len(best_team_runs)
+                  failed_runs = []
+                  
+                  for dungeon_slug, run_data in best_team_runs.items():
+                      # Find actual run to check core participation
+                      run_found = False
+                      for team in similar_teams:
+                          for run in team["all_runs"]:
+                              if run["duration"] == run_data["duration"] and run[
"completed_timestamp"] == run_data["completed_timestamp"]:
+                                  # Count how many core members participated in t
his run
+                                  core_in_run = sum(1 for core_id in merged_core_
ids if core_id in run["member_ids"])
+                                  if core_in_run >= 2:  # At least 2 of 3 core me
mbers
+                                      core_participation_count += 1
+                                  else:
+                                      failed_runs.append(f"{dungeon_slug}: {core_
in_run}/3 core members")
+                                  run_found = True
+                                  break
+                          if run_found:
+                              break
+                  
+                  core_participation_rate = core_participation_count / total_best
_runs if total_best_runs > 0 else 0
+                  if core_participation_rate >= 0.85 and len(failed_runs) <= 1:  
# Allow max 1 failed run
+                      deduplicated.append(merged_team)
+                  else:
+                      print(f"Warning: Rejecting merged team {merged_sig} - core 
players only appear in {core_participation_rate:.1%} of best runs. Failed runs: {f
ailed_runs}")
+                      # Add individual teams instead of the problematic merged te
am
+                      deduplicated.extend(similar_teams)
 
           return deduplicated
 
@@ -320,15 +348,18 @@
                   }
 
                   # Track extended rosters - players who run together consistentl
y
-                  # Group runs by overlapping player combinations to identify ext
ended teams
+                  # Use stricter criteria to prevent artificial team merging
                   found_roster = None
                   current_players = set(member_ids)
 
                   # Check if this run matches any existing extended roster
                   for roster_sig, roster_players in extended_rosters.items():
-                      # If 3+ players overlap, consider this part of the same ext
ended roster
                       overlap = len(current_players.intersection(roster_players))
-                      if overlap >= 3:
+                      overlap_percentage = overlap / len(current_players.union(ro
ster_players))
+                      
+                      # More balanced criteria: Allow extended rosters but preven
t mega-merging
+                      # Require 3+ overlap but with minimum 35% similarity to pre
vent distant connections
+                      if overlap >= 3 and overlap_percentage >= 0.35:
                           found_roster = roster_sig
                           # Add new players to the extended roster
                           extended_rosters[roster_sig].update(current_players)

diff --git a/nix/apps/team-leaderboard-gener
ator.nix b/nix/apps/team-leaderboard-generat
or.nix
index 5de1d01..e508ef3 100644
--- a/nix/apps/team-leaderboard-generator.ni
x
+++ b/nix/apps/team-leaderboard-generator.ni
x
@@ -231,7 +231,35 @@
                       "all_runs": sorted(al
l_runs, key=lambda x: x["duration"])
                   }
 
-                  deduplicated.append(merge
d_team)
+                  # Validate that merged co
re players appear in most of their best runs
+                  core_participation_count 
= 0
+                  total_best_runs = len(bes
t_team_runs)
+                  failed_runs = []
+                  
+                  for dungeon_slug, run_dat
a in best_team_runs.items():
+                      # Find actual run to 
check core participation
+                      run_found = False
+                      for team in similar_t
eams:
+                          for run in team["
all_runs"]:
+                              if run["durat
ion"] == run_data["duration"] and run["compl
eted_timestamp"] == run_data["completed_time
stamp"]:
+                                  # Count h
ow many core members participated in this ru
n
+                                  core_in_r
un = sum(1 for core_id in merged_core_ids if
 core_id in run["member_ids"])
+                                  if core_i
n_run >= 2:  # At least 2 of 3 core members
+                                      core_
participation_count += 1
+                                  else:
+                                      faile
d_runs.append(f"{dungeon_slug}: {core_in_run
}/3 core members")
+                                  run_found
 = True
+                                  break
+                          if run_found:
+                              break
+                  
+                  core_participation_rate =
 core_participation_count / total_best_runs 
if total_best_runs > 0 else 0
+                  if core_participation_rat
e >= 0.85 and len(failed_runs) <= 1:  # Allo
w max 1 failed run
+                      deduplicated.append(m
erged_team)
+                  else:
+                      print(f"Warning: Reje
cting merged team {merged_sig} - core player
s only appear in {core_participation_rate:.1
%} of best runs. Failed runs: {failed_runs}"
)
+                      # Add individual team
s instead of the problematic merged team
+                      deduplicated.extend(s
imilar_teams)
 
           return deduplicated
 
@@ -320,15 +348,18 @@
                   }
 
                   # Track extended rosters 
- players who run together consistently
-                  # Group runs by overlappi
ng player combinations to identify extended 
teams
+                  # Use stricter criteria t
o prevent artificial team merging
                   found_roster = None
                   current_players = set(mem
ber_ids)
 
                   # Check if this run match
es any existing extended roster
                   for roster_sig, roster_pl
ayers in extended_rosters.items():
-                      # If 3+ players overl
ap, consider this part of the same extended 
roster
                       overlap = len(current
_players.intersection(roster_players))
-                      if overlap >= 3:
+                      overlap_percentage = 
overlap / len(current_players.union(roster_p
layers))
+                      
+                      # More balanced crite
ria: Allow extended rosters but prevent mega
-merging
+                      # Require 3+ overlap 
but with minimum 35% similarity to prevent d
istant connections
+                      if overlap >= 3 and o
verlap_percentage >= 0.35:
                           found_roster = ro
ster_sig
                           # Add new players
 to the extended roster
                           extended_rosters[
roster_sig].update(current_players)
 

diff --git a/web/src/layouts/ChallengeModeLayout.astro b/web/src/layouts/Challenge
ModeLayout.astro
index 853b003..c95c045 100644
--- a/web/src/layouts/ChallengeModeLayout.astro
+++ b/web/src/layouts/ChallengeModeLayout.astro
@@ -375,77 +375,77 @@ const baseUrl = import.meta.env.BASE_URL;
       </p>
     </div>
   </div>
+</PageLayout>
 
-  <div id="loading" class="loading-overlay hidden">
-    <LoadingState message="Loading Challenge Mode leaderboard data..." />
-  </div>
+<div id="loading" class="loading-overlay hidden">
+  <LoadingState message="Loading Challenge Mode leaderboard data..." />
+</div>
 
-  <div id="error" class="error-overlay hidden">
-    <LoadingState type="error" />
-  </div>
+<div id="error" class="error-overlay hidden">
+  <LoadingState type="error" />
+</div>
 
-  <div id="no-data" class="no-data-message hidden">
-    <div class="card">
-      <div class="no-data-content">
-        <h3 class="section-title-large">No Times Found</h3>
-        <p>
-          No Challenge Mode times were found for this realm and dungeon
-          combination.
-        </p>
-      </div>
+<div id="no-data" class="no-data-message hidden">
+  <div class="card">
+    <div class="no-data-content">
+      <h3 class="section-title-large">No Times Found</h3>
+      <p>
+        No Challenge Mode times were found for this realm and dungeon
+        combination.
+      </p>
     </div>
   </div>
-
-  <div id="content" class="hidden">
-    <div class="card">
-      <div class="info-grid">
-        <div class="info-item">
-          <span class="info-label">Dungeon</span>
-          <span class="info-value" id="dungeon-name">Loading...</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Period</span>
-          <span class="info-value" id="period">-</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Realm</span>
-          <span class="info-value" id="realm-name">-</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Period Start</span>
-          <span class="info-value" id="period-start">-</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Period End</span>
-          <span class="info-value" id="period-end">-</span>
-        </div>
+</div>
+
+<div id="content" class="hidden">
+  <div class="card">
+    <div class="info-grid">
+      <div class="info-item">
+        <span class="info-label">Dungeon</span>
+        <span class="info-value" id="dungeon-name">Loading...</span>
       </div>
-
-      <div
-        id="cross-realm-note"
-        style="display: none; margin-top: 15px; padding: 10px; background-color: 
rgba(255, 107, 107, 0.1); border-left: 3px solid #ff6b6b; border-radius: 4px;"
-      >
-        <p style="margin: 0; font-size: 0.85em; color: var(--text-secondary);">
-          <span style="color: #ff6b6b; font-weight: bold;">*</span> indicates pla
yers
-          from other realms. Times with 3+ local players represent the true realm
-          record for Feat of Strength achievement.
-        </p>
+      <div class="info-item">
+        <span class="info-label">Period</span>
+        <span class="info-value" id="period">-</span>
+      </div>
+      <div class="info-item">
+        <span class="info-label">Realm</span>
+        <span class="info-value" id="realm-name">-</span>
+      </div>
+      <div class="info-item">
+        <span class="info-label">Period Start</span>
+        <span class="info-value" id="period-start">-</span>
+      </div>
+      <div class="info-item">
+        <span class="info-label">Period End</span>
+        <span class="info-value" id="period-end">-</span>
       </div>
-    </div>
-
-    <div class="leaderboard-container card-container" id="dungeon-leaderboard">
-      <div id="leaderboard-rows"></div>
     </div>
 
     <div
-      class="leaderboard-container card"
-      id="team-player-leaderboard"
-      style="display: none;"
+      id="cross-realm-note"
+      style="display: none; margin-top: 15px; padding: 10px; background-color: rg
ba(255, 107, 107, 0.1); border-left: 3px solid #ff6b6b; border-radius: 4px;"
     >
-      <div id="team-rows"></div>
+      <p style="margin: 0; font-size: 0.85em; color: var(--text-secondary);">
+        <span style="color: #ff6b6b; font-weight: bold;">*</span> indicates playe
rs
+        from other realms. Times with 3+ local players represent the true realm r
ecord
+        for Feat of Strength achievement.
+      </p>
     </div>
   </div>
-</PageLayout>
+
+  <div class="leaderboard-container card-container" id="dungeon-leaderboard">
+    <div id="leaderboard-rows"></div>
+  </div>
+
+  <div
+    class="leaderboard-container card"
+    id="team-player-leaderboard"
+    style="display: none;"
+  >
+    <div id="team-rows"></div>
+  </div>
+</div>
 
 <style is:global>
   /* Global styles for dynamically generated content */
@@ -1648,7 +1648,7 @@ const baseUrl = import.meta.env.BASE_URL;
 
     return `
       <div style="margin-bottom: 20px;">
-        <h4 style="color: var(--highlight-color); margin-bottom: 10px;">Core Team
 (3-player consistent core)</h4>
+        <h4 style="color: var(--highlight-color); margin-bottom: 10px;">Identifie
d Core Team </h4>
         <div style="display: flex; flex-wrap: wrap; align-items: center;">${coreM
embers}</div>
       </div>
       

diff --git a/web/src/layouts/ChallengeModeLa
yout.astro b/web/src/layouts/ChallengeModeLa
yout.astro
index 853b003..c95c045 100644
--- a/web/src/layouts/ChallengeModeLayout.as
tro
+++ b/web/src/layouts/ChallengeModeLayout.as
tro
@@ -375,77 +375,77 @@ const baseUrl = import
.meta.env.BASE_URL;
       </p>
     </div>
   </div>
+</PageLayout>
 
-  <div id="loading" class="loading-overlay 
hidden">
-    <LoadingState message="Loading Challeng
e Mode leaderboard data..." />
-  </div>
+<div id="loading" class="loading-overlay hi
dden">
+  <LoadingState message="Loading Challenge 
Mode leaderboard data..." />
+</div>
 
-  <div id="error" class="error-overlay hidd
en">
-    <LoadingState type="error" />
-  </div>
+<div id="error" class="error-overlay hidden
">
+  <LoadingState type="error" />
+</div>
 
-  <div id="no-data" class="no-data-message 
hidden">
-    <div class="card">
-      <div class="no-data-content">
-        <h3 class="section-title-large">No 
Times Found</h3>
-        <p>
-          No Challenge Mode times were foun
d for this realm and dungeon
-          combination.
-        </p>
-      </div>
+<div id="no-data" class="no-data-message hi
dden">
+  <div class="card">
+    <div class="no-data-content">
+      <h3 class="section-title-large">No Ti
mes Found</h3>
+      <p>
+        No Challenge Mode times were found 
for this realm and dungeon
+        combination.
+      </p>
     </div>
   </div>
-
-  <div id="content" class="hidden">
-    <div class="card">
-      <div class="info-grid">
-        <div class="info-item">
-          <span class="info-label">Dungeon<
/span>
-          <span class="info-value" id="dung
eon-name">Loading...</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Period</
span>
-          <span class="info-value" id="peri
od">-</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Realm</s
pan>
-          <span class="info-value" id="real
m-name">-</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Period S
tart</span>
-          <span class="info-value" id="peri
od-start">-</span>
-        </div>
-        <div class="info-item">
-          <span class="info-label">Period E
nd</span>
-          <span class="info-value" id="peri
od-end">-</span>
-        </div>
+</div>
+
+<div id="content" class="hidden">
+  <div class="card">
+    <div class="info-grid">
+      <div class="info-item">
+        <span class="info-label">Dungeon</s
pan>
+        <span class="info-value" id="dungeo
n-name">Loading...</span>
       </div>
-
-      <div
-        id="cross-realm-note"
-        style="display: none; margin-top: 1
5px; padding: 10px; background-color: rgba(2
55, 107, 107, 0.1); border-left: 3px solid #
ff6b6b; border-radius: 4px;"
-      >
-        <p style="margin: 0; font-size: 0.8
5em; color: var(--text-secondary);">
-          <span style="color: #ff6b6b; font
-weight: bold;">*</span> indicates players
-          from other realms. Times with 3+ 
local players represent the true realm
-          record for Feat of Strength achie
vement.
-        </p>
+      <div class="info-item">
+        <span class="info-label">Period</sp
an>
+        <span class="info-value" id="period
">-</span>
+      </div>
+      <div class="info-item">
+        <span class="info-label">Realm</spa
n>
+        <span class="info-value" id="realm-
name">-</span>
+      </div>
+      <div class="info-item">
+        <span class="info-label">Period Sta
rt</span>
+        <span class="info-value" id="period
-start">-</span>
+      </div>
+      <div class="info-item">
+        <span class="info-label">Period End
</span>
+        <span class="info-value" id="period
-end">-</span>
       </div>
-    </div>
-
-    <div class="leaderboard-container card-
container" id="dungeon-leaderboard">
-      <div id="leaderboard-rows"></div>
     </div>
 
     <div
-      class="leaderboard-container card"
-      id="team-player-leaderboard"
-      style="display: none;"
+      id="cross-realm-note"
+      style="display: none; margin-top: 15p
x; padding: 10px; background-color: rgba(255
, 107, 107, 0.1); border-left: 3px solid #ff
6b6b; border-radius: 4px;"
     >
-      <div id="team-rows"></div>
+      <p style="margin: 0; font-size: 0.85e
m; color: var(--text-secondary);">
+        <span style="color: #ff6b6b; font-w
eight: bold;">*</span> indicates players
+        from other realms. Times with 3+ lo
cal players represent the true realm record
+        for Feat of Strength achievement.
+      </p>
     </div>
   </div>
-</PageLayout>
+
+  <div class="leaderboard-container card-co
ntainer" id="dungeon-leaderboard">
+    <div id="leaderboard-rows"></div>
+  </div>
+
+  <div
+    class="leaderboard-container card"
+    id="team-player-leaderboard"
+    style="display: none;"
+  >
+    <div id="team-rows"></div>
+  </div>
+</div>
 
 <style is:global>
   /* Global styles for dynamically generate
d content */
@@ -1648,7 +1648,7 @@ const baseUrl = import
.meta.env.BASE_URL;
 
     return `
       <div style="margin-bottom: 20px;">
-        <h4 style="color: var(--highlight-c
olor); margin-bottom: 10px;">Core Team (3-pl
ayer consistent core)</h4>
+        <h4 style="color: var(--highlight-c
olor); margin-bottom: 10px;">Identified Core
 Team </h4>
         <div style="display: flex; flex-wra
p: wrap; align-items: center;">${coreMembers
}</div>
       </div>
       
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET