Commit Graph

345 Commits

Author SHA1 Message Date
Cal Corum
9379ba587a fix: add trailing slashes to API URLs to prevent 307 redirects dropping POST bodies
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m13s
The FastAPI server returns 307 redirects for URLs without trailing slashes.
aiohttp follows these redirects but converts POST to GET, silently dropping
the request body. This caused play-by-play and decision data from
/submit-scorecard to never be persisted to the database despite the API
returning success.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:25:08 -05:00
cal
4314b67537 Merge pull request 'feat: add is_admin() helper to utils/permissions.py (#55)' (#64) from ai/major-domo-v2#55 into next-release
All checks were successful
Build Docker Image / build (push) Successful in 1m11s
Reviewed-on: #64
2026-03-09 14:38:07 +00:00
Cal Corum
c41166d53c feat: add is_admin() helper to utils/permissions.py (#55)
Add centralized `is_admin(interaction)` helper that includes the
`isinstance(interaction.user, discord.Member)` guard, preventing
AttributeError in DM contexts.

Use it in `can_edit_player_image()` which previously accessed
`guild_permissions.administrator` directly without the isinstance
guard. Update the corresponding test to mock the user with
`spec=discord.Member` so the isinstance check passes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 09:37:22 -05:00
Cal Corum
556a30c397 fix: re-fetch existing transactions on each validation
The TransactionBuilder cached pre-existing transactions on first load
and never refreshed them. This meant transactions submitted by other
sessions (or newly visible after API fixes) were invisible for the
lifetime of the builder session, causing incorrect roster projections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:10:22 -05:00
Cal Corum
db08d0eaa4 fix: auto-fetch next_week for trade validation against projected roster
Trade validation now automatically fetches the current week from
league_service and validates against next week's projected roster
(including pending transactions), matching /dropadd behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:48:15 -05:00
Cal Corum
8ee35e564c fix: prefix trade validation errors with team abbreviation
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m5s
Roster-level errors, warnings, and suggestions now display as
"[BSG] Too many ML players" so users know which team each issue
applies to.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:37:39 -05:00
cal
b3b8cd9683 Merge pull request 'fix: show validation errors in trade embed Quick Status' (#70) from fix/trade-embed-errors-and-cleanup into main
All checks were successful
Build Docker Image / build (push) Successful in 50s
Reviewed-on: #70
2026-03-08 16:29:06 +00:00
Cal Corum
58fe9f22de fix: trade validation now checks against next week's projected roster
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m5s
validate_trade() was passing next_week=None to each team's
validate_transaction(), which skipped load_existing_transactions()
entirely. Trades were validated against the current roster only,
ignoring pending /dropadd transactions for next week.

Now auto-fetches current week from league_service and passes
next_week=current_week+1, matching /dropadd validation behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:27:03 +00:00
Cal Corum
e98a658fde fix: show actual validation errors in trade embed Quick Status
Quick Status previously only showed "X errors found" with no details.
Now lists each error and suggestion inline. Also stripped all emoji
from embed titles, field names, values, buttons, and messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:27:03 +00:00
cal
ee324693b1 Merge pull request 'ci: Use docker-tags composite action for multi-channel release support' (#68) from ci/docker-tags-multi-channel into next-release
All checks were successful
Build Docker Image / build (push) Successful in 1m6s
Reviewed-on: #68
2026-03-07 03:33:26 +00:00
cal
1a6300854e Merge pull request 'test: implement test_validate_transaction_exception_handling (#35)' (#67) from ai/major-domo-v2#35 into next-release
Reviewed-on: #67
2026-03-07 03:32:22 +00:00
cal
b6b997c15e Merge pull request 'fix: reuse persistent aiohttp.ClientSession in GiphyService (#26)' (#66) from ai/major-domo-v2-26 into next-release
Reviewed-on: #66
2026-03-07 03:31:02 +00:00
cal
26a22aae4f Merge pull request 'refactor: extract duplicate command hash logic into _compute_command_hash (#31)' (#65) from ai/major-domo-v2-31 into next-release
Reviewed-on: #65
2026-03-07 03:28:28 +00:00
cal
f048a3c04b Merge pull request 'fix: update roster labels to use Minor League and Injured List (#59)' (#63) from ai/major-domo-v2-59 into next-release
Reviewed-on: #63
2026-03-07 03:26:15 +00:00
cal
111a6cf338 Merge pull request 'fix: replace create_item_in_table placeholder with direct endpoint call (#30)' (#69) from ai/major-domo-v2#30 into main
All checks were successful
Build Docker Image / build (push) Successful in 57s
Reviewed-on: #69
2026-03-07 03:25:08 +00:00
Cal Corum
18ae65a8e2 fix: replace create_item_in_table placeholder with direct endpoint call (#30)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m10s
Remove the generic placeholder method from BaseService and replace the
single call site in CustomCommandsService.get_or_create_creator with a
direct client.post("custom_commands/creators", ...) call, consistent
with how _update_creator_stats and _update_creator_info already work.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 14:04:05 -06:00
Cal Corum
72df98936b ci: Use docker-tags composite action for multi-channel release support
Adds next-release branch trigger and replaces separate dev/production
build steps with the shared docker-tags action for tag resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:41:05 -06:00
Cal Corum
ebec9a720b test: implement test_validate_transaction_exception_handling (#35)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m6s
Removes the @pytest.mark.skip and implements the test using a
patched RosterValidation that raises on the first call, triggering
the except clause in validate_transaction. Verifies the method
returns is_legal=False with a descriptive error message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 02:04:34 -06:00
Cal Corum
e9dd318e5a perf: reuse persistent aiohttp.ClientSession in GiphyService (#26)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m5s
Both get_disappointment_gif and get_gif previously created a new
ClientSession per call. Replace with a lazily-initialised shared
session stored on the instance, eliminating per-call TCP handshake
and DNS overhead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 01:32:52 -06:00
Cal Corum
2242140dcd refactor: extract duplicate command hash logic into _compute_command_hash (#31)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m6s
Both _should_sync_commands and _save_command_hash contained an identical
~35-line block building the command data list and computing the SHA-256 hash.
Extracted into a new synchronous helper method _compute_command_hash() that
both callers now delegate to.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 00:32:03 -06:00
Cal Corum
346e36bfc6 fix: update roster labels to use Minor League and Injured List (#59)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m10s
- Add section headers (Active Roster, Minor League, Injured List) to the
  main summary embed in _create_roster_embeds so each roster section is
  clearly labeled for users
- Fix incorrect docstring in team_service.get_team_roster that had the
  shortil/longil mapping backwards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:04:57 -06:00
cal
88ad58fa12 Merge pull request 'fix: implement actual maintenance mode flag in /admin-maintenance (#28)' (#62) from ai/major-domo-v2-28 into next-release
Reviewed-on: #62
2026-03-03 22:08:19 +00:00
Cal Corum
e3610e84ea fix: implement actual maintenance mode flag in /admin-maintenance (#28)
- Add `maintenance_mode: bool = False` flag to `SBABot.__init__`
- Register a global `@tree.interaction_check` that blocks non-admin users
  from all commands when maintenance mode is active
- Update `admin_maintenance` command to set `self.bot.maintenance_mode`
  and log the state change, replacing the no-op placeholder comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 22:08:02 +00:00
cal
bc8a256b14 Merge pull request 'fix: refresh roster data before validation to prevent stale cache' (#60) from hotfix/stale-roster-cache into next-release
Reviewed-on: #60
2026-03-02 21:06:59 +00:00
Cal Corum
ffa0366441 refactor: invalidate roster cache after submission instead of force-refreshing
Simplify review found that force_refresh=True on every validate_transaction()
call caused redundant API fetches on every embed render and button press.

Instead, invalidate the roster cache after successful submit_transaction() so
the next operation fetches fresh data. This preserves the cache for normal
interaction flows while still preventing stale data after submissions.

Also adds type annotation for roster_svc DI parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:06:00 +00:00
Cal Corum
c70669d474 fix: refresh roster data before validation to prevent stale cache
TransactionBuilder cached roster data indefinitely via _roster_loaded flag,
causing validation to use stale counts when builders persisted across multiple
/ilmove invocations. Now validate_transaction() always fetches fresh roster
data. Also adds dependency injection for roster_service to improve testability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:06:00 +00:00
cal
6e4191f677 Merge pull request 'refactor: move 42 unnecessary lazy imports to top-level' (#58) from refactor/remove-unnecessary-lazy-imports into next-release
Reviewed-on: #58
2026-03-02 20:48:26 +00:00
Cal Corum
c961ea0dea docs: clarify git branching workflow in CLAUDE.md
Branch from next-release for normal work, main only for hotfixes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:42:18 -06:00
Cal Corum
858663cd27 refactor: move 42 unnecessary lazy imports to top-level across codebase
Codebase audit identified ~50 lazy imports. Moved 42 unnecessary ones to
top-level imports — only keeping those justified by circular imports,
init-order dependencies, or optional dependency guards. Updated test mock
patch targets where needed. See #57 for remaining DI candidates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:35:23 -06:00
cal
677dd3b773 Merge pull request 'fix: auto-detect player roster type in trade commands' (#56) from fix/trade-from-roster-detection into next-release 2026-03-02 19:14:42 +00:00
cal
ced67a5eef Merge pull request 'feat: add team ownership verification to /injury commands (closes #18)' (#53) from fix/injury-team-ownership-check into next-release 2026-03-02 19:14:40 +00:00
Cal Corum
58043c996d fix: auto-detect player roster type in trade commands instead of assuming ML
/trade add-player hardcoded from_roster=MAJOR_LEAGUE for all players,
causing incorrect transaction records when trading MiL/IL players. This
cascaded into false roster validation errors for other teams' /dropadd
commands because pre-existing transaction processing misidentified which
roster a player was leaving from.

Now looks up the player's actual team and calls roster_type() to determine
the correct source roster. Same fix applied to /trade supplementary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:29:01 -06:00
Cal Corum
99489a3c42 feat: add team ownership verification to /injury set-new and /injury clear (closes #18)
Prevents users from managing injuries for players not on their team.
Admins bypass the check; org affiliates (MiL/IL) are recognized.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:59:58 -06:00
cal
98d47a1262 Merge pull request 'fix: key plays score text shows "tied at X" correctly (closes #48)' (#52) from fix/key-plays-tied-score into next-release
Reviewed-on: #52
2026-03-01 21:38:33 +00:00
Cal Corum
0daa6f4491 fix: key plays score text shows "tied at X" instead of "Team up X-X" (closes #48)
The else branch in descriptive_text() caught both "away leading" and
"tied" cases, always overwriting the tied text. Changed to if/elif/else
so tied scores display correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:36:38 -06:00
cal
f7a65706a1 Merge pull request 'next-release' (#51) from next-release into main
All checks were successful
Build Docker Image / build (push) Successful in 1m0s
Reviewed-on: #51
2026-03-01 20:56:38 +00:00
cal
46afbf25e0 Merge pull request 'fix: roster validation includes org affiliate transactions' (#50) from fix/roster-validation-org-affiliates into next-release
All checks were successful
Build Docker Image / build (pull_request) Successful in 4m10s
Reviewed-on: #50
2026-03-01 20:50:21 +00:00
Cal Corum
aa27769ed6 fix: roster validation now includes org affiliate transactions (closes #49)
load_existing_transactions only queried for the base team abbreviation
(e.g. "POR"), missing trades involving MiL/IL affiliates ("PORMIL",
"PORIL"). This caused false "too many players" errors when a pending
trade would have cleared a roster spot.

- get_team_transactions now accepts Union[str, List[str]] for team_abbrev
- load_existing_transactions queries all org affiliates [BASE, BASEMiL, BASEIL]
- Added 5 tests covering the fix and backwards compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:45:21 -06:00
cal
a80addc742 Merge pull request 'next-release' (#47) from next-release into main
All checks were successful
Build Docker Image / build (push) Successful in 46s
Reviewed-on: #47
2026-02-22 22:33:35 +00:00
cal
22c7f841e8 Merge branch 'main' into next-release
All checks were successful
Build Docker Image / build (pull_request) Successful in 48s
2026-02-22 22:31:07 +00:00
cal
e280928b4d Merge pull request 'feat: include current week number in weekly-info channel post' (#46) from feat/weekly-info-current-week into next-release
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m10s
Reviewed-on: #46
2026-02-22 22:22:00 +00:00
Cal Corum
b7a88844b6 feat: include current week number in weekly-info channel post
The #weekly-info message already shows season and game times but not
which week it is, making managers check elsewhere for that context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:20:08 -06:00
cal
1df9527697 Merge pull request 'fix: use explicit America/Chicago timezone for freeze/thaw scheduling' (#45) from fix/utc-timezone-scheduling into next-release
Reviewed-on: #45
2026-02-22 22:16:54 +00:00
Cal Corum
8a1a957c2a fix: use explicit America/Chicago timezone for freeze/thaw scheduling
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m16s
The production container has ambiguous timezone config — /etc/localtime
points to Etc/UTC but date reports CST. The transaction freeze/thaw task
used datetime.now() (naive, relying on OS timezone), causing scheduling
to fire at unpredictable wall-clock times.

- Add utils/timezone.py with centralized Chicago timezone helpers
- Fix tasks/transaction_freeze.py to use now_chicago() for scheduling
- Fix utils/logging.py timestamp to use proper UTC-aware datetime
- Add 14 timezone utility tests
- Update freeze task tests to mock now_chicago instead of datetime

Closes #43

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:00:22 -06:00
Cal Corum
a668a3505c docs: add release workflow section to CLAUDE.md
Documents the next-release staging branch pattern used for
batching changes before merging to main.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 15:59:07 -06:00
cal
12fe600e83 Merge pull request 'next-release' (#42) from next-release into main
All checks were successful
Build Docker Image / build (push) Successful in 50s
Reviewed-on: #42
2026-02-20 20:28:15 +00:00
Cal Corum
d1a6b57ccd fix: scorebug stale data, win probability parsing, and read-failure tolerance (closes #39, #40)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m14s
#40: ScorecardTracker cached data in memory at startup — background task never
saw newly published scorecards. Fixed by reloading from disk on every read.

#39: Win percentage defaulted to 50% when unavailable, showing a misleading
50/50 bar. Now defaults to None with "unavailable" message in embed. Parsing
handles decimal (0.75), percentage string, and empty values. Also fixed
orientation bug where win% was always shown as home team's even when the
sheet reports the away team as the leader.

Additionally: live scorebug tracker now distinguishes between "all games
confirmed final" and "sheet read failures" — transient Google Sheets errors
no longer hide the live scores channel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 14:14:23 -06:00
Cal Corum
67f9c734b0 Merge branch 'fix/quick-wins-batch' into next-release 2026-02-20 13:14:49 -06:00
Cal Corum
9cd577cba1 fix: batch quick-wins — 4 issues resolved (closes #37, #27, #25, #38)
- #37: Fix stale comment in transaction_freeze.py referencing wrong moveid format
- #27: Change config.testing default from True to False (was masking prod behavior)
- #25: Replace deprecated asyncio.get_event_loop() with get_running_loop()
- #38: Replace naive datetime.now() with timezone-aware datetime.now(UTC) across
  7 source files and 4 test files to prevent subtle timezone bugs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 11:48:16 -06:00
Cal Corum
f64fee8d2e fix: remove 226 unused imports across the codebase (closes #33)
Ran `ruff check --select F401 --fix` to auto-remove 221 unused imports,
manually removed 4 unused `import discord` from package __init__.py files,
and fixed test import for DISAPPOINTMENT_TIERS to reference canonical location.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 11:35:04 -06:00