Auto-created team roles now land directly under the CS2 / LoL "divider" role
in the community guild's role list, keeping it grouped by game.
- config: CS2_DIVIDER_ROLE_ID / LOL_DIVIDER_ROLE_ID (season-specific, env
overridable) exposed as TEAM_DIVIDER_ROLE_IDS keyed by game code.
- core/sheets: tag each team with its game (CS2/LoL) from the section title it
sits under; shared _scan_sections generator feeds both parse_team_rosters and
the new parse_team_games; get_game_for_team accessor + _team_game cache.
- core/member_sync: on creating a team role, position it at its game divider's
slot (best-effort; left in place if game/divider unknown or move refused).
- .env.example + tests for game tagging and role placement.
Each participant is in exactly one game, so one role per team is unambiguous.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R6JZkyszyDFuFtk25WBbcR
The team-role feature was aimed at the wrong bot. Tournament participants
live in the economy/community guild, but team-role sync had been bolted onto
the dev bot's roster sync (sync_member), which bails out for anyone missing
from the internal member sheet - so it could never reach its actual audience.
Decouple it: keep the (roster-independent) team-sheet parsing, pull the team
wiring off the dev/member-sync path, and re-home it on the economy bot.
- core/member_sync: revert sync_member to add-only (drop team block +
SyncResult.roles_removed); add roster-independent sync_team_role and a
whole-guild sync_all_team_roles returning a reporting summary. Still only
ever touches role NAMES present in the team sheet.
- commands/economy_team_commands: new admin-only /teamsync command.
- bot.py: hourly team_sync_hourly task (economy-only, no-op unless
TEAM_SHEET_ID is set; first tick at boot covers startup load); register
/teamsync under the economy profile; drop the dev-side startup load.
- commands/dev_member_commands: /check no longer refreshes teams or reports
removed roles.
- strings + .env.example: TEAMSYNC_UI, CMD[teamsync], document TEAM_SHEET_ID.
- tests: retarget sync tests to sync_team_role; add sync_all_team_roles case.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R6JZkyszyDFuFtk25WBbcR
Match members by Discord username against the lineup nicknames in the
separate registration spreadsheet (TEAM_SHEET_ID) and give each their
team's role. One team per person: switching teams removes the old team
role, and a team with no Discord role yet is auto-created. Only role
names present in the sheet are ever touched, so organisation/field/base
roles are never at risk; the feature is a no-op when TEAM_SHEET_ID is
unset.
The sheet is not a single table (merged rows, stacked CS2/LoL sections
with different layouts), so it is parsed via raw-row scanning rather than
get_all_records. Citizenship markers like "(EST)" are used only as
player delimiters and discarded.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>