Reuse the existing CS2/LoL divider roles as participant tags: sync_team_role
now also adds the divider role for the member's team's game, and strips any
other configured divider role (switched game / dropped out). Matched by ID
against config.TEAM_DIVIDERS, so only the divider roles are ever touched.
- TeamSyncResult gains divider_added / divider_removed; summary tallies both
- /teamsync report and log line surface divider_assigned / divider_removed
- tests: grants the game divider, swaps it on a game switch
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPRsW4tazVtYi2jNzVQkre
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>
The economy had many coin faucets but almost no sinks: the /shop is
one-time ownership, and gambling/rob fines route to the house (which
players drain back via jackpots and heists), so they recirculate rather
than destroy coins. Result: steady inflation.
Add a consumables shop as a true recurring sink - buying destroys the
coins and grants a temporary boost, so there's always something to spend
on after gear is maxed:
- Energiajook XL (500) - 1h of 2x earnings on /work, /beg, /crime
- XP jook (500) - 1h of 2x EXP
- Kohv (300) - instantly clears all cooldowns
Timed buffs live in a new active_buffs field ({kind: expiry_iso}), pruned
on read; rebuying extends the timer. Effects hook where they belong:
earn_mult in income.do_work/do_beg/do_crime, exp_buff_mult in
levels.award_exp; kohv is self-contained. New /consumables command browses
the menu (with active buffs) or buys a boost. Covered by 9 tests.
Note: active_buffs is a new PocketBase field - run
scripts/sync_pb_schema.py before deploying or buffs won't persist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>