 function buildRows(historyKey: TGKey): ResultRow[] {
  const { slot, date } = TGKey.parse(historyKey);
  let players: UserKey[] = Attendance.players(historyKey);

  if (players.length === 0) {
    const history = Store.read<{ scores: TGScore[] }>(TGKey.toHistoryPath(historyKey));
    if (history?.scores) {
      players = [...new Set(history.scores.map((s: TGScore) => s.playedBy ?? s.userKey))];
    }
  }

  const weekKey = WRank.weekKey(new Date(date));
  const history = Store.read<{ scores: TGScore[] }>(TGKey.toHistoryPath(historyKey));
  const rows: ResultRow[] = [];

  // Match each ATTENDEE (player) directly against the scores where
  // (playedBy ?? userKey) === that player — this is the authoritative
  // link, not "does this player own/share a character with a score".
  for (const playerKey of players) {
    const score = history?.scores.find((s: TGScore) => (s.playedBy ?? s.userKey) === playerKey);
    if (!score) continue; // attendee hasn't submitted yet — handled elsewhere (placeholder row)

    const foundChar = CharacterRegistry.find(score.characterName);
    const classKey   = (typeof score.class === "object" ? (score.class as any)?.key : score.class) as ClassKey;
    const char: Character = foundChar ?? {
      name:     score.characterName,
      class:    CLASSES[classKey] ?? { key: classKey, name: classKey, shortName: classKey },
      level:    0,
      nation:   score.nation,
      ownerKey: score.userKey,
    };

    const wrEntry  = WRank.entry(char.name, char.nation, weekKey);
    const position = score.wRankAtSubmission
      ? {
          currentRank:  score.wRankAtSubmission.rank,
          previousRank: score.wRankAtSubmission.rank - score.wRankAtSubmission.delta,
        }
      : wrEntry
        ? { currentRank: wrEntry.currentRank, previousRank: wrEntry.previousRank }
        : undefined;

    rows.push({
      character:   char,
      score,
      position,
      leavesCount: Leaves.countForChar({ characterName: char.name }),
    });
  }

  return rows;
}