From ac5772b0645662869fceae1912a5990ed3f58d87 Mon Sep 17 00:00:00 2001 From: matt Date: Mon, 23 Mar 2026 16:45:26 -0700 Subject: [PATCH] chore: prepare release 4.2.0 --- .env.example | 2 +- CHANGELOG.md | 22 +++++++++++--- RELEASE_NOTES_TEMPLATE.md | 58 +++++++++++++----------------------- docker-compose.yml | 2 +- dockerhub-docker-compose.yml | 2 +- docs/releases/v4.2.0.md | 53 ++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 7 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 docs/releases/v4.2.0.md diff --git a/.env.example b/.env.example index 01e035b..86c94ed 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=v4.1.0 # Matches dockerhub compose. +APP_VERSION=v4.2.0 # Matches dockerhub compose. ############################ # Theming diff --git a/CHANGELOG.md b/CHANGELOG.md index ca726e8..b1696ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning ## [Unreleased] ### Added +_No unreleased changes yet_ + +### Changed +_No unreleased changes yet_ + +### Fixed +_No unreleased changes yet_ + +### Removed +_No unreleased changes yet_ + +## [4.2.0] - 2026-03-23 +### Added - **RandomService**: New `code/web/services/random_service.py` service class wrapping seeded RNG operations with input validation and the R9 `BaseService` pattern - **InvalidSeedError**: New `InvalidSeedError` exception in `code/exceptions.py` for seed validation failures - **Random diagnostics endpoint**: `GET /api/random/diagnostics` behind `WEB_RANDOM_DIAGNOSTICS=1` flag, returning seed derivation test vectors for cross-platform consistency checks @@ -23,7 +36,7 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning - Basic lands excluded from all budget calculations - Budget summary bar in the deck summary view with under/over color coding - Budget badge and over-budget panel on the saved deck view - - Pickups list page (`/decks/{name}/pickups`) sorted by priority tier + - Pickups list page (`/decks/pickups?name=`) sorted by priority tier - Pool budget filter: cards exceeding the per-card ceiling by more than the pool tolerance (default 15%, configurable per build in the New Deck modal) are excluded from the candidate pool before building begins - Card price shown in the hover and tap popup for all card tiles with a cached price - Price shown inline on each alternative card suggestion in the alternatives panel @@ -41,19 +54,20 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning - "Card Price Cache Status" section on the Setup page with last-updated date and Refresh button - Footer now shows the price data date alongside the Scryfall attribution - **Price charts**: Visual cost breakdown added to the deck summary and build complete screens - - Donut/bar chart showing total deck spend by card role category (commander, ramp, card draw, lands, etc.) + - Donut/bar chart showing total deck spend by card role category (9 categories: Land, Ramp, Creature, Card Draw, Removal, Wipe, Protection, Synergy, Other) - Price histogram showing card count distribution across cost buckets - Basic lands excluded from all chart calculations - **Stale price warnings**: Cards with price data older than 24 hours are flagged with a subtle clock indicator (⏱) on card tiles, the hover popup, the budget review panel, and the Pickups page; if more than half the deck's prices are stale a single banner is shown instead of per-card indicators; controlled by `PRICE_STALE_WARNING_HOURS` (default: 24; set to 0 to disable) ### Changed -- **Create Button in New Dock Panel**: Button has been renamed to "Build Deck" for consistency with phrasing on the "Quick Build" button +- **Create Button in New Deck Modal**: Button has been renamed to "Build Deck" for consistency with phrasing on the "Quick Build" button ### Fixed - **Multi-copy include count**: Typing an archetype card in Must Include no longer adds only 1 copy — the archetype count is now respected when the dialog is confirmed +- **Stale price banner after refresh**: Refreshing the price cache on the Setup page now correctly clears the stale price warning ### Removed -_No unreleased changes yet_ +_No changes_ ## [4.1.0] - 2026-03-20 ### Added diff --git a/RELEASE_NOTES_TEMPLATE.md b/RELEASE_NOTES_TEMPLATE.md index 5ec5bb7..6eae8a4 100644 --- a/RELEASE_NOTES_TEMPLATE.md +++ b/RELEASE_NOTES_TEMPLATE.md @@ -2,48 +2,30 @@ ## [Unreleased] ### Added -- **RandomService**: New `code/web/services/random_service.py` service class wrapping seeded RNG operations with input validation and the R9 `BaseService` pattern -- **InvalidSeedError**: New `InvalidSeedError` exception in `code/exceptions.py` for seed validation failures -- **Random diagnostics endpoint**: `GET /api/random/diagnostics` behind `WEB_RANDOM_DIAGNOSTICS=1` flag, returning seed derivation test vectors for cross-platform consistency checks -- **Random Mode documentation**: New `docs/random_mode/` directory with `seed_infrastructure.md`, `developer_guide.md`, and `diagnostics.md` -- **Multi-copy / Include conflict dialog**: When a known multi-copy archetype card (e.g., Hare Apparent) is typed in the Must Include field of the New Deck modal, a popup now appears asking how many copies to include, with an optional Thrumming Stone checkbox -- **Multi-copy / Exclude conflict dialog**: When a multi-copy archetype is selected via the Multi-Copy Package selector and the same card also appears in the Must Exclude field, a conflict popup lets you choose to keep the multi-copy (removing it from excludes) or keep the exclude (disabling the archetype selection) -- **Budget Mode**: Full budget-aware deck building with price integration - - Budget configuration on the New Deck modal: set a total budget cap, optional per-card ceiling, and soft/hard enforcement mode - - Price display during building: card prices shown next to card names in list and thumbnail views throughout the build pipeline - - Running budget counter chip updates as each build stage completes - - Over-budget card highlight: cards exceeding the per-card ceiling are marked with a yellow/gold border - - Basic lands excluded from all budget calculations - - Budget summary bar in the deck summary view with under/over color coding - - Budget badge and over-budget panel on the saved deck view - - Pickups list page (`/decks/{name}/pickups`) sorted by priority tier - - Pool budget filter: cards exceeding the per-card ceiling by more than the pool tolerance (default 15%, configurable per build in the New Deck modal) are excluded from the candidate pool before building begins - - Card price shown in the hover and tap popup for all card tiles with a cached price - - Price shown inline on each alternative card suggestion in the alternatives panel - - Post-build budget review panel appears when the final deck total exceeds the budget cap by more than 10%; lists over-budget cards sorted by overage with up to 3 cheaper alternatives each - - Alternatives in the review panel are matched by card type (lands suggest land alternatives, creatures suggest creature alternatives) and sorted by role similarity using shared strategy tags - - Each alternative has a Swap button that replaces the card in the finalized deck and re-evaluates the budget live; the panel auto-dismisses when the total drops within tolerance - - "Accept deck as-is" button in soft mode lets you bypass the review and proceed to export - - Build complete screen shows a minimal action bar (Restart build / New build / Back) instead of the full stage ribbon - - Controlled by `ENABLE_BUDGET_MODE` environment variable (default: enabled) -- **Price Cache Infrastructure**: Improved price data lifecycle - - `price` and `price_updated` columns added to parquet card database via `refresh_prices_parquet()` - - `PRICE_AUTO_REFRESH=1`: optional daily 1 AM UTC scheduled price cache rebuild - - `PRICE_LAZY_REFRESH=1`: background per-card price refresh for cards not updated in 7 days (default: enabled) - - `POST /api/price/refresh`: manual price cache rebuild trigger - - "Card Price Cache Status" section on the Setup page with last-updated date and Refresh button - - Footer now shows the price data date alongside the Scryfall attribution -- **Price charts**: Visual cost breakdown added to the deck summary and build complete screens - - Donut/bar chart showing total deck spend by card role category (commander, ramp, card draw, lands, etc.) - - Price histogram showing card count distribution across cost buckets - - Basic lands excluded from all chart calculations -- **Stale price warnings**: Cards with price data older than 24 hours are flagged with a subtle clock indicator (⏱) on card tiles, the hover popup, the budget review panel, and the Pickups page; if more than half the deck's prices are stale a single banner is shown instead of per-card indicators; controlled by `PRICE_STALE_WARNING_HOURS` (default: 24; set to 0 to disable) +_No unreleased changes yet_ ### Changed -- **Create Button in New Dock Panel**: Button has been renamed to "Build Deck" for consistency with phrasing on the "Quick Build" button +_No unreleased changes yet_ ### Fixed -- **Multi-copy include count**: Typing an archetype card in Must Include no longer adds only 1 copy — the archetype count is now respected when the dialog is confirmed +_No unreleased changes yet_ ### Removed _No unreleased changes yet_ + +## [4.2.0] - 2026-03-23 +### Highlights +- **Budget Mode**: Set a budget cap and per-card ceiling when building a deck. Prices are shown throughout the build flow, over-budget cards are highlighted, and a post-build review panel lets you swap in cheaper alternatives live. +- **Pickups List**: New page (`/decks/pickups?name=`) listing affordable cards you don't own yet, sorted by theme-match priority. +- **Price Charts**: Donut chart and histogram showing deck spend by card role (9 categories) and cost distribution. +- **Stale Price Warnings**: Cards with price data older than 24 hours are flagged with a clock indicator; a banner appears when more than half the deck's prices are stale. +- **Price Cache Refresh**: Setup page Refresh button now downloads fresh Scryfall bulk data before rebuilding the cache. +- **Multi-copy Dialogs**: Conflict dialogs for Must Include and Must Exclude when using multi-copy archetypes (e.g., Hare Apparent). +- **RandomService & Diagnostics**: Seeded RNG service with optional diagnostics endpoint (`WEB_RANDOM_DIAGNOSTICS=1`). + +### Changed +- **Build Deck button**: "Create" renamed to "Build Deck" in the New Deck modal. + +### Fixed +- **Stale price banner after refresh**: Refreshing prices on the Setup page now correctly clears the stale warning. +- **Multi-copy include count**: Archetype card count is now correctly applied when confirmed from the conflict dialog. diff --git a/docker-compose.yml b/docker-compose.yml index faf1569..121fd32 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -140,7 +140,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: "v4.1.0" # Displayed version label (set per release/tag) + APP_VERSION: "v4.2.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 dd5ed81..c228859 100644 --- a/dockerhub-docker-compose.yml +++ b/dockerhub-docker-compose.yml @@ -142,7 +142,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: "v4.1.0" # Displayed version label (set per release/tag) + APP_VERSION: "v4.2.0" # Displayed version label (set per release/tag) # ------------------------------------------------------------------ # Misc / Land Selection (Step 7) Environment Tuning diff --git a/docs/releases/v4.2.0.md b/docs/releases/v4.2.0.md new file mode 100644 index 0000000..5fe1e81 --- /dev/null +++ b/docs/releases/v4.2.0.md @@ -0,0 +1,53 @@ +# MTG Python Deckbuilder v4.2.0 + +## Summary +Budget Mode: full price-aware deck building with live budget tracking, post-build review, pickup suggestions, and price charts. Also includes multi-copy conflict dialogs, RandomService infrastructure, and stale price warnings. + +## Added + +### Budget Mode +- Budget configuration in the New Deck modal: total cap, optional per-card ceiling, soft/hard enforcement mode, and pool tolerance +- Card prices shown throughout the build pipeline (list and thumbnail views) with a running budget counter chip +- Over-budget cards highlighted with a yellow/gold border; basic lands excluded from all calculations +- Budget summary bar in deck summary view; budget badge and over-budget panel on saved deck view +- Post-build budget review panel (triggered when total exceeds cap by >10%): lists over-budget cards with up to 3 cheaper alternatives, each with a live Swap button +- "Accept deck as-is" button in soft mode to bypass the review +- Pickups list page (`/decks/pickups?name=`) — affordable cards you don't own yet, sorted by priority tier +- Pool budget filter: cards over the per-card ceiling by more than the pool tolerance are excluded before building; configurable per build (default 15%) +- Controlled by `ENABLE_BUDGET_MODE` environment variable (default: enabled) + +### Price Cache Infrastructure +- `price` and `price_updated` columns added to parquet card database via `refresh_prices_parquet()` +- Setup page Refresh button downloads fresh Scryfall bulk data before rebuilding the cache +- Optional auto-refresh (`PRICE_AUTO_REFRESH=1`) and lazy per-card refresh (`PRICE_LAZY_REFRESH=1`, default enabled) +- `POST /api/price/refresh` manual rebuild endpoint +- "Card Price Cache Status" section on the Setup page with last-updated date and Refresh button +- Footer shows price data date alongside Scryfall attribution +- `build-similarity-cache` CI workflow now commits `prices_cache.json` and `prices_cache.json.ts` alongside the parquet + +### Price Charts +- Donut/bar chart showing deck spend by card role (9 categories: Land, Ramp, Creature, Card Draw, Removal, Wipe, Protection, Synergy, Other) +- Price histogram showing card count distribution across cost buckets +- Basic lands excluded from all chart calculations + +### Stale Price Warnings +- Cards with price data older than 24 hours flagged with a clock indicator (⏱) on card tiles, hover popup, budget review panel, and Pickups page +- If >50% of deck prices are stale, a single banner replaces per-card indicators +- Controlled by `PRICE_STALE_WARNING_HOURS` (default: 24; set to 0 to disable) + +### Multi-copy Dialogs +- Include conflict dialog: typing a multi-copy archetype card (e.g., Hare Apparent) in Must Include now prompts for copy count with optional Thrumming Stone checkbox +- Exclude conflict dialog: conflict popup when the same card appears in both the Multi-Copy Package selector and Must Exclude + +### RandomService & Diagnostics +- `RandomService` wrapping seeded RNG operations with input validation +- `InvalidSeedError` exception for seed validation failures +- `GET /api/random/diagnostics` endpoint behind `WEB_RANDOM_DIAGNOSTICS=1` flag +- Random Mode documentation in `docs/random_mode/` + +## Changed +- **Build Deck button**: "Create" renamed to "Build Deck" in the New Deck modal for consistency with "Quick Build" + +## Fixed +- **Stale price banner after refresh**: Refreshing the price cache on the Setup page now correctly clears the stale warning +- **Multi-copy include count**: Archetype card count is now correctly applied when confirmed from the conflict dialog diff --git a/pyproject.toml b/pyproject.toml index 78de78f..3fd62f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "mtg-deckbuilder" -version = "4.1.0" +version = "4.2.0" description = "A command-line tool for building and analyzing Magic: The Gathering decks" readme = "README.md" license = {file = "LICENSE"}