---
title: "Discord Bot Release — 2026.3.12"
description: "Major catch-up release: trade deadline enforcement, performance parallelization, security fixes, CI/CD migration to CalVer, and 148 commits of accumulated improvements."
type: reference
domain: major-domo
tags: [release-notes, deployment, discord, major-domo]
---

# Discord Bot Release — 2026.3.12

**Date:** 2026-03-31
**Tag:** `2026.3.12`
**Image:** `manticorum67/major-domo-discordapp:2026.3.12` / `:production`
**Server:** akamai (`~/container-data/major-domo`)
**Deploy method:** `.scripts/deploy.sh -y` (docker compose pull + up)
**Previous tag:** `v2.29.4` (148 commits behind)

## Release Summary

Large catch-up release covering months of accumulated work since the last tag. The headline feature is trade deadline enforcement — `/trade` commands are now blocked after the configured deadline week, with fail-closed behavior when API data is unavailable. Also includes significant performance improvements (parallelized API calls, cached signatures, Redis SCAN), security hardening, dependency pinning, and a full CI/CD migration from version-file bumps to CalVer tag-triggered builds.

## Changes

### New Features
- **Trade deadline enforcement** — `is_past_trade_deadline` property on Current model; guards on `/trade initiate`, submit button, and `_finalize_trade`. Fail-closed when API returns no data. 4 new tests. (PR #121)
- `is_admin()` helper in `utils/permissions.py` (#55)
- Team ownership verification on `/injury set-new` and `/injury clear` (#18)
- Current week number included in weekly-info channel posts
- Local deploy script for production deploys

### Performance
- Parallelize independent API calls with `asyncio.gather()` (#90)
- Cache `inspect.signature()` at decoration time (#97)
- Replace `json.dumps` serialization test with `isinstance` fast path (#96)
- Use `channel.purge()` instead of per-message delete loops (#93)
- Parallelize schedule_service week fetches (#88)
- Replace Redis `KEYS` with `SCAN` in `clear_prefix` (#98)
- Reuse persistent `aiohttp.ClientSession` in GiphyService (#26)
- Cache user team lookup in player_autocomplete, reduce limit to 25

### Bug Fixes
- Fix chart_service path from `data/` to `storage/`
- Make ScorecardTracker methods async to match await callers
- Prevent partial DB writes and show detailed errors on scorecard submission failure
- Add trailing slashes to API URLs to prevent 307 redirects dropping POST bodies
- Trade validation: check against next week's projected roster, include pending trades and org affiliate transactions
- Prefix trade validation errors with team abbreviation
- Auto-detect player roster type in trade commands instead of assuming ML
- Fix key plays score text ("tied at X" instead of "Team up X-X") (#48)
- Fix scorebug stale data, win probability parsing, and read-failure tolerance (#39, #40)
- Batch quick-wins: 4 issues resolved (#37, #27, #25, #38)
- Fix ContextualLogger crash when callers pass `exc_info=True`
- Fix thaw report posting to use channel ID instead of channel names
- Use explicit America/Chicago timezone for freeze/thaw scheduling
- Replace broken `@self.tree.interaction_check` with MaintenanceAwareTree subclass
- Implement actual maintenance mode flag in `/admin-maintenance` (#28)
- Validate and sanitize pitching decision data from Google Sheets
- Fix `/player` autocomplete timeout by using current season only
- Split read-only data volume to allow state file writes (#85)
- Update roster labels to use Minor League and Injured List (#59)

### Security
- Address 7 security issues across the codebase
- Remove 226 unused imports (#33)
- Pin all Python dependency versions in `requirements.txt` (#76)

### Refactoring & Cleanup
- Extract duplicate command hash logic into `_compute_command_hash` (#31)
- Move 42 unnecessary lazy imports to top-level
- Remove dead maintenance mode artifacts in bot.py (#104)
- Remove unused `weeks_ahead` parameter from `get_upcoming_games`
- Invalidate roster cache after submission instead of force-refreshing

## Infrastructure Changes
- **CI/CD migration**: Switched from version-file bumps to CalVer tag-triggered Docker builds
- Added `.scripts/release.sh` for creating CalVer tags
- Updated `.scripts/deploy.sh` for tag-triggered releases
- Docker build cache switched from `type=gha` to `type=registry`
- Used `docker-tags` composite action for multi-channel release support
- Fixed act_runner auth with short-form local actions + full GitHub URLs
- Use Gitea API for tag creation to avoid branch protection failures

## Deployment Notes
- No migrations required
- No config changes needed
- Rollback: `ssh akamai "cd ~/container-data/major-domo && docker pull manticorum67/major-domo-discordapp@<previous-digest> && docker tag <digest> manticorum67/major-domo-discordapp:production && docker compose up -d discord-app"`
