diff --git a/.env.example b/.env.example index 2fcc200..129e102 100644 --- a/.env.example +++ b/.env.example @@ -13,7 +13,7 @@ # HOST=0.0.0.0 # Uvicorn bind host (only when APP_MODE=web). # PORT=8080 # Uvicorn port. # WORKERS=1 # Uvicorn worker count. -APP_VERSION=v2.5.2 # Matches dockerhub compose. +APP_VERSION=v2.6.0 # Matches dockerhub compose. ############################ # Theming diff --git a/.github/workflows/dockerhub-publish.yml b/.github/workflows/dockerhub-publish.yml index 08d89f4..ec5eff6 100644 --- a/.github/workflows/dockerhub-publish.yml +++ b/.github/workflows/dockerhub-publish.yml @@ -112,7 +112,7 @@ jobs: build_arm64: name: Build (arm64) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: prepare permissions: contents: read diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fdb901..e526fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning ## [Unreleased] ### Summary +- _No unreleased changes yet._ + +### Added +- _No unreleased changes yet._ + +### Changed +- _No unreleased changes yet._ + +### Fixed +- _No unreleased changes yet._ + +## [2.6.0] - 2025-10-13 +### Summary - Card tagging system improvements split metadata from gameplay themes for cleaner deck building experience - Keyword normalization reduces specialty keyword noise by 96% while maintaining theme catalog quality - Protection tag now focuses on cards that grant shields to others, not just those with inherent protection diff --git a/RELEASE_NOTES_TEMPLATE.md b/RELEASE_NOTES_TEMPLATE.md index 0ad49b7..2bdb2d6 100644 --- a/RELEASE_NOTES_TEMPLATE.md +++ b/RELEASE_NOTES_TEMPLATE.md @@ -2,66 +2,13 @@ ## [Unreleased] ### Summary -- Card tagging system improvements split metadata from gameplay themes for cleaner deck building experience -- Keyword normalization reduces specialty keyword noise by 96% while maintaining theme catalog quality -- Protection tag now focuses on cards that grant shields to others, not just those with inherent protection -- Web UI improvements: faster polling, fixed progress display, and theme refresh stability -- Comprehensive enhancement to protection card detection, classification, and deck building - - Fine-grained scope metadata distinguishes self-protection from board-wide effects ("Your Permanents: Hexproof" vs "Self: Hexproof") - - Enhanced grant detection with Equipment/Aura patterns, phasing support, and complex trigger handling - - Intelligent deck builder filtering includes board-relevant protection while excluding self-only and type-specific cards - - Tiered pool limiting focuses on high-quality staples while maintaining variety across builds - - Improved scope tagging for cards with keyword-only protection effects (no grant text, just inherent keywords) -- Large-scale refactor to improve code quality and maintainability - - Centralized regex patterns, extracted reusable utilities, decomposed complex functions - - Improved code organization and readability while maintaining 100% tagging accuracy +- _No unreleased changes yet._ ### Added -- Metadata partition system separates diagnostic tags from gameplay themes in card data -- Keyword normalization system with smart filtering of one-off specialty mechanics -- Allowlist preserves important keywords like Flying, Myriad, and Transform -- Protection grant detection identifies cards that give Hexproof, Ward, or Indestructible to other permanents -- Automatic tagging for creature-type-specific protection (e.g., "Knights Gain Protection") -- New `metadataTags` column in card data for bracket annotations and internal diagnostics -- Static phasing keyword detection from keywords field (catches creatures like Breezekeeper) -- "Other X you control have Y" protection pattern for static ability grants -- "Enchanted creature has phasing" pattern detection -- Chosen type blanket phasing patterns -- Complex trigger phasing patterns (reactive, consequent, end-of-turn) -- Protection scope filtering in deck builder (feature flag: `TAG_PROTECTION_SCOPE`) intelligently selects board-relevant protection -- Phasing cards with "Your Permanents:" or "Targeted:" metadata now tagged as Protection and included in protection pool -- Metadata tags temporarily visible in card hover previews for debugging (shows scope like "Your Permanents: Hexproof") -- Web-slinging tagger function to identify cards with web-slinging mechanics +- _No unreleased changes yet._ ### Changed -- Card tags now split between themes (for deck building) and metadata (for diagnostics) -- Keywords now consolidate variants (e.g., "Commander ninjutsu" becomes "Ninjutsu") -- Setup progress polling reduced from 3s to 5-10s intervals for better performance -- Theme catalog streamlined from 753 to 736 themes (-2.3%) with improved quality -- Protection tag refined to focus on 329 cards that grant shields (down from 1,166 with inherent effects) -- Protection tag renamed to "Protective Effects" throughout web interface to avoid confusion with the Magic keyword "protection" -- Theme catalog automatically excludes metadata tags from theme suggestions -- Grant detection now strips reminder text before pattern matching to avoid false positives -- Deck builder protection phase now filters by scope metadata: includes "Your Permanents:", excludes "Self:" protection -- Protection card selection now randomized per build for variety (using seeded RNG when deterministic mode enabled) -- Protection pool now limited to ~40-50 high-quality cards (tiered selection: top 3x target + random 10-20 extras) -- Tagging module imports standardized with consistent organization and centralized constants +- _No unreleased changes yet._ ### Fixed -- Setup progress now shows 100% completion instead of getting stuck at 99% -- Theme catalog no longer continuously regenerates after setup completes -- Health indicator polling optimized to reduce server load -- Protection detection now correctly excludes creatures with only inherent keywords -- Dive Down, Glint no longer falsely identified as granting to opponents (reminder text fix) -- Drogskol Captain, Haytham Kenway now correctly get "Your Permanents" scope tags -- 7 cards with static Phasing keyword now properly detected (Breezekeeper, Teferi's Drake, etc.) -- Type-specific protection grants (e.g., "Knights Gain Indestructible") now correctly excluded from general protection pool -- Protection scope filter now properly prioritizes exclusions over inclusions (fixes Knight Exemplar in non-Knight decks) -- Inherent protection cards (Aysen Highway, Phantom Colossus, etc.) now correctly get "Self: Protection" metadata tags -- Scope tagging now applies to ALL cards with protection effects, not just grant cards -- Cloak of Invisibility, Teferi's Curse now get "Your Permanents: Phasing" tags -- Shimmer now gets "Blanket: Phasing" tag for chosen type effect -- King of the Oathbreakers now gets "Self: Phasing" tag for reactive trigger -- Cards with static keywords (Protection, Hexproof, Ward, Indestructible) in their keywords field now get proper scope metadata tags -- Cards with X in their mana cost now properly identified and tagged with "X Spells" theme for better deck building accuracy -- Card tagging system enhanced with smarter pattern detection and more consistent categorization +- _No unreleased changes yet._ diff --git a/docker-compose.yml b/docker-compose.yml index fe54379..420c069 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -113,7 +113,7 @@ services: # WEB_THEME_FILTER_PREWARM: "0" WEB_AUTO_ENFORCE: "0" # 1=auto-run compliance export after builds WEB_CUSTOM_EXPORT_BASE: "" # Optional: custom base dir for deck export artifacts - APP_VERSION: "2.5.2" # Displayed version label (set per release/tag) + APP_VERSION: "2.6.0" # Displayed version label (set per release/tag) # ------------------------------------------------------------------ # Misc / Land Selection (Step 7) Environment Tuning diff --git a/dockerhub-docker-compose.yml b/dockerhub-docker-compose.yml index b2b1731..6fdc85d 100644 --- a/dockerhub-docker-compose.yml +++ b/dockerhub-docker-compose.yml @@ -115,7 +115,7 @@ services: # WEB_THEME_FILTER_PREWARM: "0" WEB_AUTO_ENFORCE: "0" # 1=auto-run compliance export after builds WEB_CUSTOM_EXPORT_BASE: "" # Optional: custom base dir for deck export artifacts - APP_VERSION: "2.5.2" # Displayed version label (set per release/tag) + APP_VERSION: "2.6.0" # Displayed version label (set per release/tag) # ------------------------------------------------------------------ # Misc / Land Selection (Step 7) Environment Tuning diff --git a/docs/releases/v2.6.0.md b/docs/releases/v2.6.0.md new file mode 100644 index 0000000..a416f78 --- /dev/null +++ b/docs/releases/v2.6.0.md @@ -0,0 +1,66 @@ +# MTG Python Deckbuilder v2.6.0 + +## Summary +- Card tagging system improvements split metadata from gameplay themes for cleaner deck building experience +- Keyword normalization reduces specialty keyword noise by 96% while maintaining theme catalog quality +- Protection tag now focuses on cards that grant shields to others, not just those with inherent protection +- Web UI improvements: faster polling, fixed progress display, and theme refresh stability +- **Protection System Overhaul**: Comprehensive enhancement to protection card detection, classification, and deck building + - Fine-grained scope metadata distinguishes self-protection from board-wide effects ("Your Permanents: Hexproof" vs "Self: Hexproof") + - Enhanced grant detection with Equipment/Aura patterns, phasing support, and complex trigger handling + - Intelligent deck builder filtering includes board-relevant protection while excluding self-only and type-specific cards + - Tiered pool limiting focuses on high-quality staples while maintaining variety across builds + - Improved scope tagging for cards with keyword-only protection effects (no grant text, just inherent keywords) +- **Tagging Module Refactoring**: Large-scale refactor to improve code quality and maintainability + - Centralized regex patterns, extracted reusable utilities, decomposed complex functions + - Improved code organization and readability while maintaining 100% tagging accuracy + +## Added +- Metadata partition system separates diagnostic tags from gameplay themes in card data +- Keyword normalization system with smart filtering of one-off specialty mechanics +- Allowlist preserves important keywords like Flying, Myriad, and Transform +- Protection grant detection identifies cards that give Hexproof, Ward, or Indestructible to other permanents +- Automatic tagging for creature-type-specific protection (e.g., "Knights Gain Protection") +- New `metadataTags` column in card data for bracket annotations and internal diagnostics +- Static phasing keyword detection from keywords field (catches creatures like Breezekeeper) +- "Other X you control have Y" protection pattern for static ability grants +- "Enchanted creature has phasing" pattern detection +- Chosen type blanket phasing patterns +- Complex trigger phasing patterns (reactive, consequent, end-of-turn) +- Protection scope filtering in deck builder (feature flag: `TAG_PROTECTION_SCOPE`) intelligently selects board-relevant protection +- Phasing cards with "Your Permanents:" or "Targeted:" metadata now tagged as Protection and included in protection pool +- Metadata tags temporarily visible in card hover previews for debugging (shows scope like "Your Permanents: Hexproof") +- Web-slinging tagger function to identify cards with web-slinging mechanics + +## Changed +- Card tags now split between themes (for deck building) and metadata (for diagnostics) +- Keywords now consolidate variants (e.g., "Commander ninjutsu" becomes "Ninjutsu") +- Setup progress polling reduced from 3s to 5-10s intervals for better performance +- Theme catalog streamlined from 753 to 736 themes (-2.3%) with improved quality +- Protection tag refined to focus on 329 cards that grant shields (down from 1,166 with inherent effects) +- Protection tag renamed to "Protective Effects" throughout web interface to avoid confusion with the Magic keyword "protection" +- Theme catalog automatically excludes metadata tags from theme suggestions +- Grant detection now strips reminder text before pattern matching to avoid false positives +- Deck builder protection phase now filters by scope metadata: includes "Your Permanents:", excludes "Self:" protection +- Protection card selection now randomized per build for variety (using seeded RNG when deterministic mode enabled) +- Protection pool now limited to ~40-50 high-quality cards (tiered selection: top 3x target + random 10-20 extras) +- Tagging module imports standardized with consistent organization and centralized constants + +## Fixed +- Setup progress now shows 100% completion instead of getting stuck at 99% +- Theme catalog no longer continuously regenerates after setup completes +- Health indicator polling optimized to reduce server load +- Protection detection now correctly excludes creatures with only inherent keywords +- Dive Down, Glint no longer falsely identified as granting to opponents (reminder text fix) +- Drogskol Captain, Haytham Kenway now correctly get "Your Permanents" scope tags +- 7 cards with static Phasing keyword now properly detected (Breezekeeper, Teferi's Drake, etc.) +- Type-specific protection grants (e.g., "Knights Gain Indestructible") now correctly excluded from general protection pool +- Protection scope filter now properly prioritizes exclusions over inclusions (fixes Knight Exemplar in non-Knight decks) +- Inherent protection cards (Aysen Highway, Phantom Colossus, etc.) now correctly get "Self: Protection" metadata tags +- Scope tagging now applies to ALL cards with protection effects, not just grant cards +- Cloak of Invisibility, Teferi's Curse now get "Your Permanents: Phasing" tags +- Shimmer now gets "Blanket: Phasing" tag for chosen type effect +- King of the Oathbreakers now gets "Self: Phasing" tag for reactive trigger +- Cards with static keywords (Protection, Hexproof, Ward, Indestructible) in their keywords field now get proper scope metadata tags +- Cards with X in their mana cost now properly identified and tagged with "X Spells" theme for better deck building accuracy +- Card tagging system enhanced with smarter pattern detection and more consistent categorization diff --git a/entrypoint.sh b/entrypoint.sh index 1e61e3f..e09443b 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -12,6 +12,8 @@ seed_defaults() { [ -f /app/config/deck.json ] || cp "/.defaults/config/deck.json" "/app/config/deck.json" 2>/dev/null || true # brackets.yml (power brackets) if present [ -f /app/config/brackets.yml ] || { [ -f "/.defaults/config/brackets.yml" ] && cp "/.defaults/config/brackets.yml" "/app/config/brackets.yml"; } 2>/dev/null || true + # random_theme_exclusions.yml if present + [ -f /app/config/random_theme_exclusions.yml ] || { [ -f "/.defaults/config/random_theme_exclusions.yml" ] && cp "/.defaults/config/random_theme_exclusions.yml" "/app/config/random_theme_exclusions.yml"; } 2>/dev/null || true # Copy any default card list JSONs that are missing (generic loop) if [ -d "/.defaults/config/card_lists" ]; then for f in /.defaults/config/card_lists/*.json; do diff --git a/pyproject.toml b/pyproject.toml index 6c7d729..b4e09c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "mtg-deckbuilder" -version = "2.5.2" +version = "2.6.0" description = "A command-line tool for building and analyzing Magic: The Gathering decks" readme = "README.md" license = {file = "LICENSE"}