mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-16 15:40:12 +01:00
overhaul: migrated to tailwind css for css management, consolidated custom css, removed inline css, removed unneeded css, and otherwise improved page styling
This commit is contained in:
parent
f1e21873e7
commit
b994978f60
81 changed files with 15784 additions and 2936 deletions
52
docs/NODE_DEPENDENCIES.md
Normal file
52
docs/NODE_DEPENDENCIES.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Node.js Dependencies for Web UI Development
|
||||
|
||||
## Prerequisites
|
||||
- Node.js 18+ (LTS recommended)
|
||||
- npm 9+ (comes with Node.js)
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Tailwind CSS v3
|
||||
- **tailwindcss**: Utility-first CSS framework
|
||||
- **postcss**: CSS transformation tool
|
||||
- **autoprefixer**: Adds vendor prefixes automatically
|
||||
|
||||
### TypeScript
|
||||
- **typescript**: TypeScript compiler for type-safe JavaScript
|
||||
|
||||
## Build Commands
|
||||
|
||||
### CSS Build
|
||||
```bash
|
||||
npm run build:css # One-time build
|
||||
npm run watch:css # Watch mode for development
|
||||
```
|
||||
|
||||
### TypeScript Build
|
||||
```bash
|
||||
npm run build:ts # One-time build
|
||||
npm run watch:ts # Watch mode for development
|
||||
```
|
||||
|
||||
### Combined Build
|
||||
```bash
|
||||
npm run build # Build CSS and TypeScript
|
||||
npm run watch # Watch both CSS and TypeScript
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
- `code/web/static/tailwind.css` - Tailwind entry point (source)
|
||||
- `code/web/static/styles.css` - Generated CSS (git-ignored)
|
||||
- `code/web/static/ts/` - TypeScript source files
|
||||
- `code/web/static/js/` - Compiled JavaScript (git-ignored)
|
||||
|
||||
## Configuration Files
|
||||
- `tailwind.config.js` - Tailwind CSS configuration
|
||||
- `postcss.config.js` - PostCSS configuration
|
||||
- `tsconfig.json` - TypeScript compiler configuration
|
||||
- `package.json` - npm scripts and dependencies
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# Card Authoring Guide
|
||||
|
||||
This guide captures the conventions used by the deckbuilder when new cards are added to the CSV inputs. Always validate your edits by running the fast tagging tests or a local build before committing changes.
|
||||
|
||||
## Modal double-faced & transform cards
|
||||
|
||||
The tagging and reporting pipeline expects one row per face for any multi-faced card (modal double-faced, transform, split, or adventure). Use the checklist below when adding or updating these entries:
|
||||
|
||||
1. **Canonical name** — Keep the `name` column identical for every face (e.g., `Valakut Awakening // Valakut Stoneforge`). Individual faces should instead set `face_name` when available; the merger preserves front-face copy for downstream consumers.
|
||||
2. **Layout & side** — Populate `layout` with the value emitted by Scryfall (`modal_dfc`, `transform`, `split`, `adventure`, etc.) and include a `side` column (`a`, `b`, …). The merger uses `side` ordering when reconstructing per-face metadata.
|
||||
3. **Mana details** — Supply `mana_cost`, `mana_value`, and `produces_mana` for every face. The per-face land snapshot and deck summary badges rely on these fields to surface the “DFC land” chip and annotated mana production.
|
||||
4. **Type line accuracy** — Ensure `type_line` includes `Land` for any land faces. The builder counts a card toward land totals when at least one face includes `Land`.
|
||||
5. **Tags & roles** — Tag every face with the appropriate `themeTags`, `roleTags`, and `card_tags`. The merge stage unions these sets so the finished card retains all relevant metadata.
|
||||
6. **Commander eligibility** — Only the primary (`side == 'a'`) face is considered for commander legality. If you add a new MDFC commander, double-check that the front face satisfies the Commander rules text; otherwise the record is filtered during catalog refresh.
|
||||
7. **Cross-check exports** — After the card is added, run a local build and confirm the deck exports include the new `DFCNote` column entry for the card. The annotation summarizes each land face so offline reviewers see the same guidance as the web UI.
|
||||
|
||||
### Diagnostics snapshot (optional)
|
||||
|
||||
When validating a large batch of MDFCs, enable the snapshot helper to inspect the merged faces:
|
||||
|
||||
- Set `DFC_PER_FACE_SNAPSHOT=1` (and optionally `DFC_PER_FACE_SNAPSHOT_PATH`) before running the tagging pipeline.
|
||||
- Disable parallel tagging (`WEB_TAG_PARALLEL=0`) while the snapshot is active; the helper only writes output during sequential runs.
|
||||
- Once tagging completes, review `logs/dfc_per_face_snapshot.json` for the card you added to verify mana fields, `produces_mana`, and land detection flags.
|
||||
|
||||
Following these guidelines keeps the deck summary badges, exporter annotations, and diagnostics snapshots in sync for every new double-faced card.
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
# Commander Catalog Onboarding
|
||||
|
||||
The Commander Browser and deck builder both read from `csv_files/commander_cards.csv`. This file is generated during setup and must stay in sync with the fields the web UI expects. Use this guide whenever you need to add a new commander, refresh the dataset, or troubleshoot missing entries.
|
||||
|
||||
## Where the file lives
|
||||
|
||||
- Default path: `csv_files/commander_cards.csv`
|
||||
- Override: set `CSV_FILES_DIR` (env var) before launching the app; the loader resolves `commander_cards.csv` inside that directory.
|
||||
- Caching: the web layer caches the parsed file in process. Restart the app or call `clear_commander_catalog_cache()` in a shell if you edit the CSV while the server is running.
|
||||
|
||||
## Required columns
|
||||
|
||||
The loader normalizes these columns; keep the header names exact. Optional fields can be blank but should still be present.
|
||||
|
||||
| Column | Notes |
|
||||
| --- | --- |
|
||||
| `name` | Printed front name. Used as the fallback display label.
|
||||
| `faceName` | Front face name for MDFCs/split cards. Defaults to `name` when empty.
|
||||
| `side` | Leave blank or `A` for the primary face. Secondary faces become distinct slugs.
|
||||
| `colorIdentity` | WUBRG characters (any casing). `C` marks colorless identities.
|
||||
| `colors` | Printed colors; mainly used for ordering badges.
|
||||
| `manaCost` | Optional but keeps rows sortable in the UI.
|
||||
| `manaValue` | Numeric converted mana cost.
|
||||
| `type` | Full type line (e.g., `Legendary Creature — Phyrexian Angel`).
|
||||
| `creatureTypes` | Python/JSON list or comma-separated string of creature subtypes.
|
||||
| `text` | Oracle text. Enables partner/background detection and hover tooltips.
|
||||
| `power` / `toughness` | Optional stats. Leave blank for non-creatures.
|
||||
| `keywords` | Comma-separated keywords (Flying, Vigilance, …).
|
||||
| `themeTags` | Python/JSON list of curated themes (e.g., `['Angels', 'Life Gain']`).
|
||||
| `edhrecRank` | Optional EDHREC popularity rank (integer).
|
||||
| `layout` | Layout string from MTGJSON (`normal`, `modal_dfc`, etc.).
|
||||
|
||||
Additional columns are preserved but ignored by the browser; feel free to keep upstream metadata.
|
||||
|
||||
## Recommended refresh workflow
|
||||
|
||||
1. Ensure dependencies are installed: `pip install -r requirements.txt`.
|
||||
2. Regenerate the commander catalog with the MDFC-aware helper (multi-face merge always on):
|
||||
```powershell
|
||||
python -m code.scripts.refresh_commander_catalog
|
||||
```
|
||||
- Pass `--compat-snapshot` when you need both `csv_files/commander_cards.csv` and `csv_files/compat_faces/commander_cards_unmerged.csv` so downstream consumers can diff the historical row-per-face layout.
|
||||
- The legacy `--mode` argument is deprecated; it no longer disables the merge but still maps `--mode compat` to `--compat-snapshot` for older automation. Use `--skip-setup` if `determine_commanders()` has already been run and you simply need to reapply tagging.
|
||||
- When running the web service during staging, set `DFC_COMPAT_SNAPSHOT=1` if you need the compatibility snapshot written on each rebuild. The merge itself no longer requires a feature flag.
|
||||
- Use the staging QA checklist (`docs/qa/mdfc_staging_checklist.md`) to validate commander flows and downstream consumers before promoting the flag in production.
|
||||
3. Restart the web server (or your desktop app) so the cache reloads the new file.
|
||||
4. Validate with the targeted test:
|
||||
```powershell
|
||||
python -m pytest -q code/tests/test_commander_catalog_loader.py
|
||||
```
|
||||
The test confirms required columns exist, normalization still works, and caching invalidates correctly.
|
||||
|
||||
## Manual edits (quick fixes)
|
||||
|
||||
If you need to hotfix a single row before a full regeneration:
|
||||
|
||||
1. Open the CSV in a UTF-8 aware editor (Excel can re-save with a UTF-8 BOM — prefer a text editor when possible).
|
||||
2. Add or edit the row, ensuring the slug-worthy fields (`name`, `faceName`, `side`) are unique.
|
||||
3. Keep the `themeTags` value as a Python/JSON list (e.g., `['Artifacts']`), or a comma-delimited list without stray quotes.
|
||||
4. Save the file and restart the server so the cache refreshes.
|
||||
5. Backfill the curated themes in `config/themes/` if the new commander should surface dedicated tags.
|
||||
|
||||
> Manual edits are acceptable for emergency fixes but commit regenerated data as soon as possible so automation stays trustworthy.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`Commander catalog is unavailable` error**: The app could not find the CSV. Verify the file exists under `CSV_FILES_DIR` and has a header row.
|
||||
- **Row missing in the browser**: Ensure the commander passed eligibility (legendary rules) and the row’s `layout`/`side` data is correct. Slug collisions are auto-deduped (`-2`, `-3`, …) but rely on unique `name`+`side` combos.
|
||||
- **Theme chips absent**: Confirm `themeTags` contains at least one value and that the theme slug exists in the theme catalog; otherwise the UI hides the chips.
|
||||
|
||||
For deeper issues, enable verbose logs with `SHOW_LOGS=1` before restarting the web process.
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
# Headless & CLI Guide
|
||||
|
||||
Leverage the shared deckbuilding engine from the command line, in headless mode, or within containers.
|
||||
|
||||
## Table of contents
|
||||
- [Entry points](#entry-points)
|
||||
- [Switching modes in Docker](#switching-modes-in-docker)
|
||||
- [Headless JSON configs](#headless-json-configs)
|
||||
- [Environment overrides](#environment-overrides)
|
||||
- [CLI argument reference](#cli-argument-reference)
|
||||
- [Include/exclude lists from the CLI](#includeexclude-lists-from-the-cli)
|
||||
- [Practical examples](#practical-examples)
|
||||
|
||||
---
|
||||
|
||||
## Entry points
|
||||
- Interactive menu: `python code/main.py`
|
||||
- Headless runner: `python code/headless_runner.py --config config/deck.json`
|
||||
- Both executables share the same builder core used by the Web UI.
|
||||
|
||||
## Switching modes in Docker
|
||||
Override the container entrypoint to run the CLI or headless flows inside Docker Compose or plain `docker run`.
|
||||
|
||||
```powershell
|
||||
# Compose example
|
||||
docker compose run --rm -e APP_MODE=cli web
|
||||
|
||||
# Compose with headless automation
|
||||
docker compose run --rm `
|
||||
-e APP_MODE=cli `
|
||||
-e DECK_MODE=headless `
|
||||
-e DECK_CONFIG=/app/config/deck.json `
|
||||
web
|
||||
```
|
||||
|
||||
Set `APP_MODE=cli` to switch from the Web UI to the textual interface. Add `DECK_MODE=headless` to skip prompts and immediately run the configured deck.
|
||||
|
||||
## Headless JSON configs
|
||||
- Drop JSON files into `config/` (e.g., `config/deck.json`).
|
||||
- Headless mode auto-runs the lone JSON file; if multiple exist, the CLI lists them with summaries (commander + themes).
|
||||
- Config fields cover commander, bracket, include/exclude lists, theme preferences, owned-mode toggles, and output naming.
|
||||
- Partner mechanics are optional: set `"enable_partner_mechanics": true` and supply either `"secondary_commander"` or `"background"` for combined commander runs.
|
||||
|
||||
## Environment overrides
|
||||
When running in containers or automation, environment variables can override JSON settings. Typical variables include:
|
||||
- `DECK_COMMANDER`
|
||||
- `DECK_PRIMARY_CHOICE`, `DECK_SECONDARY_CHOICE`, `DECK_TERTIARY_CHOICE`
|
||||
- `DECK_BRACKET_LEVEL`
|
||||
- `DECK_ADD_LANDS`, `DECK_LAND_COUNT`, `DECK_CREATURE_COUNT`, `DECK_RAMP_COUNT`
|
||||
|
||||
Precedence order: **CLI flags > environment variables > JSON config > defaults**.
|
||||
|
||||
## CLI argument reference
|
||||
Run `python code/headless_runner.py --help` to see the current argument surface. Highlights:
|
||||
|
||||
- Type indicators make expectations explicit (e.g., `PATH`, `NAME`, `INT`).
|
||||
- Theme selection accepts human-readable names: `--primary-tag "Airbending"` instead of numeric indexes.
|
||||
- Bracket selection via `--bracket-level`.
|
||||
- Ideal counts such as `--land-count`, `--ramp-count`, `--creature-count`, and more.
|
||||
|
||||
## Include/exclude lists from the CLI
|
||||
You can specify comma- or semicolon-separated lists directly through the CLI:
|
||||
|
||||
```powershell
|
||||
python code/headless_runner.py `
|
||||
--commander "Jace, Vryn's Prodigy" `
|
||||
--include-cards "Sol Ring;Jace, the Mind Sculptor" `
|
||||
--exclude-cards "Chaos Orb;Shahrazad" `
|
||||
--enforcement-mode strict
|
||||
```
|
||||
|
||||
Semicolons allow card names containing commas. Enforcement modes mirror the Web UI (`off`, `warn`, `strict`).
|
||||
|
||||
## Practical examples
|
||||
```powershell
|
||||
# Build a Goblins list with tuned counts
|
||||
python code/headless_runner.py `
|
||||
--commander "Krenko, Mob Boss" `
|
||||
--primary-tag "Goblin Kindred" `
|
||||
--creature-count 35 `
|
||||
--land-count 33 `
|
||||
--ramp-count 12
|
||||
|
||||
# Fire a headless run via Docker using an alternate config folder
|
||||
docker compose run --rm `
|
||||
-e APP_MODE=cli `
|
||||
-e DECK_MODE=headless `
|
||||
-e DECK_CONFIG=/app/config/custom_decks `
|
||||
web
|
||||
```
|
||||
|
||||
The CLI prints a detailed summary at the end of each run, including enforcement results, resolved themes, and export paths. All artifacts land in the same `deck_files/` folder used by the Web UI.
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
# All Cards Consolidation - Migration Guide
|
||||
|
||||
## Overview
|
||||
This guide covers the migration from individual card CSV files to the consolidated `all_cards.parquet` format introduced in v2.8.0. The new format provides:
|
||||
|
||||
- **87% smaller file size** (3.74 MB vs ~30 MB for CSVs)
|
||||
- **2-5x faster queries** (single lookup ~1.3ms, filters <70ms)
|
||||
- **Improved caching** with automatic reload on file changes
|
||||
- **Unified query API** via `AllCardsLoader` and `CardQueryBuilder`
|
||||
|
||||
## Migration Timeline
|
||||
|
||||
### Phase 1: v2.8.0 (Current) - Soft Launch
|
||||
- ✅ AllCardsLoader and CardQueryBuilder available
|
||||
- ✅ Automatic aggregation after tagging
|
||||
- ✅ Legacy adapter functions provided for backward compatibility
|
||||
- ✅ Feature flag `USE_ALL_CARDS_FILE=1` (enabled by default)
|
||||
- ✅ Deprecation warnings logged when using legacy functions
|
||||
- **cards.csv still supported** (kept for compatibility)
|
||||
- **commander_cards.csv replaced** by `commander_cards.parquet`
|
||||
|
||||
### Phase 2: v2.9.0 - Broader Adoption
|
||||
- Update deck_builder modules to use AllCardsLoader directly
|
||||
- Update web routes to use new query API
|
||||
- Continue supporting legacy adapter for external code
|
||||
- Increase test coverage for real-world usage patterns
|
||||
|
||||
### Phase 3: v3.0.0 - Primary Method
|
||||
- New code must use AllCardsLoader (no new legacy adapter usage)
|
||||
- Legacy adapter still works but discouraged
|
||||
- Documentation emphasizes new API
|
||||
- cards.csv continues to work (not deprecated yet)
|
||||
|
||||
### Phase 4: v3.1.0+ - Sunset Legacy (Future)
|
||||
- Remove legacy adapter functions
|
||||
- Remove individual card CSV file support (cards.csv sunset)
|
||||
- **commander_cards.parquet permanently replaces CSV version**
|
||||
- All code uses AllCardsLoader exclusively
|
||||
|
||||
## Quick Start
|
||||
|
||||
### For New Code (Recommended)
|
||||
|
||||
```python
|
||||
from code.services.all_cards_loader import AllCardsLoader
|
||||
from code.services.card_query_builder import CardQueryBuilder
|
||||
|
||||
# Simple loading
|
||||
loader = AllCardsLoader()
|
||||
all_cards = loader.load()
|
||||
|
||||
# Single card lookup
|
||||
sol_ring = loader.get_by_name("Sol Ring")
|
||||
|
||||
# Batch lookup
|
||||
cards = loader.get_by_names(["Sol Ring", "Lightning Bolt", "Counterspell"])
|
||||
|
||||
# Filtering
|
||||
red_cards = loader.filter_by_color_identity(["R"])
|
||||
token_cards = loader.filter_by_themes(["tokens"], mode="any")
|
||||
creatures = loader.filter_by_type("Creature")
|
||||
|
||||
# Text search
|
||||
results = loader.search("create token", limit=100)
|
||||
|
||||
# Complex queries with fluent API
|
||||
results = (CardQueryBuilder()
|
||||
.colors(["G"])
|
||||
.themes(["ramp"], mode="any")
|
||||
.types("Creature")
|
||||
.limit(20)
|
||||
.execute())
|
||||
```
|
||||
|
||||
### For Existing Code (Legacy Adapter)
|
||||
|
||||
If you have existing code using old file-loading patterns, the legacy adapter provides backward compatibility:
|
||||
|
||||
```python
|
||||
# Old code continues to work (with deprecation warnings)
|
||||
from code.services.legacy_loader_adapter import (
|
||||
load_all_cards,
|
||||
load_cards_by_name,
|
||||
load_cards_by_type,
|
||||
load_cards_with_tag,
|
||||
)
|
||||
|
||||
# These still work but log deprecation warnings
|
||||
all_cards = load_all_cards()
|
||||
sol_ring = load_cards_by_name("Sol Ring")
|
||||
creatures = load_cards_by_type("Creature")
|
||||
token_cards = load_cards_with_tag("tokens")
|
||||
```
|
||||
|
||||
**Important**: Migrate to the new API as soon as possible. Legacy functions will be removed in v3.1+.
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Update Imports
|
||||
|
||||
**Before:**
|
||||
```python
|
||||
# Old pattern (if you were loading cards directly)
|
||||
import pandas as pd
|
||||
df = pd.read_csv("csv_files/some_card.csv")
|
||||
```
|
||||
|
||||
**After:**
|
||||
```python
|
||||
from code.services.all_cards_loader import AllCardsLoader
|
||||
|
||||
loader = AllCardsLoader()
|
||||
card = loader.get_by_name("Card Name")
|
||||
```
|
||||
|
||||
### Step 2: Update Query Patterns
|
||||
|
||||
**Before:**
|
||||
```python
|
||||
# Old: Manual filtering
|
||||
all_cards = load_all_individual_csvs() # Slow
|
||||
creatures = all_cards[all_cards["type"].str.contains("Creature")]
|
||||
red_creatures = creatures[creatures["colorIdentity"] == "R"]
|
||||
```
|
||||
|
||||
**After:**
|
||||
```python
|
||||
# New: Efficient queries
|
||||
loader = AllCardsLoader()
|
||||
red_creatures = (CardQueryBuilder(loader)
|
||||
.colors(["R"])
|
||||
.types("Creature")
|
||||
.execute())
|
||||
```
|
||||
|
||||
### Step 3: Update Caching
|
||||
|
||||
**Before:**
|
||||
```python
|
||||
# Old: Manual caching
|
||||
_cache = {}
|
||||
def get_card(name):
|
||||
if name not in _cache:
|
||||
_cache[name] = load_from_csv(name)
|
||||
return _cache[name]
|
||||
```
|
||||
|
||||
**After:**
|
||||
```python
|
||||
# New: Built-in caching
|
||||
loader = AllCardsLoader() # Caches automatically
|
||||
card = loader.get_by_name(name) # Fast on repeat calls
|
||||
```
|
||||
|
||||
## Feature Flag
|
||||
|
||||
The `USE_ALL_CARDS_FILE` environment variable controls whether the consolidated Parquet file is used:
|
||||
|
||||
```bash
|
||||
# Enable (default)
|
||||
USE_ALL_CARDS_FILE=1
|
||||
|
||||
# Disable (fallback to old method)
|
||||
USE_ALL_CARDS_FILE=0
|
||||
```
|
||||
|
||||
**When to disable:**
|
||||
- Troubleshooting issues with the new loader
|
||||
- Testing backward compatibility
|
||||
- Temporary fallback during migration
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
| Operation | Old (CSV) | New (Parquet) | Improvement |
|
||||
|-----------|-----------|---------------|-------------|
|
||||
| Initial load | ~2-3s | 0.104s | 20-30x faster |
|
||||
| Single lookup | ~50-100ms | 1.3ms | 40-75x faster |
|
||||
| Color filter | ~200ms | 2.1ms | 95x faster |
|
||||
| Theme filter | ~500ms | 67ms | 7.5x faster |
|
||||
| File size | ~30 MB | 3.74 MB | 87% smaller |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "all_cards.parquet not found"
|
||||
|
||||
Run the aggregation process:
|
||||
1. Web UI: Go to Setup page → "Rebuild Card Files" button
|
||||
2. CLI: `python code/scripts/aggregate_cards.py`
|
||||
3. Automatic: Run tagging workflow (aggregation happens automatically)
|
||||
|
||||
### Deprecation Warnings
|
||||
|
||||
```
|
||||
DEPRECATION: load_cards_by_name() called. Migrate to AllCardsLoader().get_by_name() before v3.1+
|
||||
```
|
||||
|
||||
**Solution**: Update your code to use the new API as shown in this guide.
|
||||
|
||||
### Performance Issues
|
||||
|
||||
```python
|
||||
# Check cache status
|
||||
loader = AllCardsLoader()
|
||||
stats = loader.get_stats()
|
||||
print(stats) # Shows cache age, file size, etc.
|
||||
|
||||
# Force reload if data seems stale
|
||||
loader.load(force_reload=True)
|
||||
|
||||
# Clear cache
|
||||
loader.clear_cache()
|
||||
```
|
||||
|
||||
### Feature Flag Not Working
|
||||
|
||||
Ensure environment variable is set before importing:
|
||||
```python
|
||||
import os
|
||||
os.environ['USE_ALL_CARDS_FILE'] = '1'
|
||||
|
||||
# Then import
|
||||
from code.services.all_cards_loader import AllCardsLoader
|
||||
```
|
||||
|
||||
## Testing Your Migration
|
||||
|
||||
```python
|
||||
# Run migration compatibility tests
|
||||
pytest code/tests/test_migration_compatibility.py -v
|
||||
|
||||
# Run all cards loader tests
|
||||
pytest code/tests/test_all_cards_loader.py -v
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Do I need to regenerate all_cards.parquet after tagging?**
|
||||
A: No, it's automatic. Aggregation runs after tagging completes. You can manually trigger via "Rebuild Card Files" button if needed.
|
||||
|
||||
**Q: What happens to cards.csv?**
|
||||
A: Still supported through v3.0.x for compatibility. Will be sunset in v3.1+. Start migrating now.
|
||||
|
||||
**Q: What about commander_cards.csv?**
|
||||
A: Already replaced by `commander_cards.parquet` in v2.8.0. CSV version is no longer used.
|
||||
|
||||
**Q: Can I use both methods during migration?**
|
||||
A: Yes, the legacy adapter allows mixed usage, but aim to fully migrate to the new API.
|
||||
|
||||
**Q: Will my existing decks break?**
|
||||
A: No, existing decks are unaffected. This only changes how cards are loaded internally.
|
||||
|
||||
**Q: How do I disable the new loader?**
|
||||
A: Set `USE_ALL_CARDS_FILE=0` environment variable. Not recommended except for troubleshooting.
|
||||
|
||||
**Q: Are there any breaking changes?**
|
||||
A: No breaking changes in v2.8.0. Legacy functions work with deprecation warnings. Breaking changes planned for v3.1+.
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues during migration:
|
||||
1. Check deprecation warnings in logs
|
||||
2. Run migration compatibility tests
|
||||
3. Try disabling feature flag temporarily
|
||||
4. File an issue on GitHub with details
|
||||
|
||||
## Summary
|
||||
|
||||
✅ **Use AllCardsLoader** for all new code
|
||||
✅ **Migrate existing code** using this guide
|
||||
✅ **Test thoroughly** with provided test suites
|
||||
✅ **Monitor deprecation warnings** and address them
|
||||
✅ **Plan ahead** for v3.1+ sunset of legacy functions
|
||||
|
||||
The new consolidated format provides significant performance improvements and a cleaner API. Start migrating today!
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
# MDFC Staging QA Checklist
|
||||
|
||||
Use this checklist when validating the MDFC merge in staging. The merge now runs unconditionally; set `DFC_COMPAT_SNAPSHOT=1` when you also need the legacy unmerged snapshots for downstream validation.
|
||||
|
||||
_Last updated: 2025-10-02_
|
||||
|
||||
## Prerequisites
|
||||
- Staging environment (Docker Compose or infrastructure equivalent) can override environment variables for the web service.
|
||||
- Latest code synced with the MDFC merge helper (`code/scripts/refresh_commander_catalog.py`).
|
||||
- Virtualenv or container image contains current project dependencies (`pip install -r requirements.txt`).
|
||||
|
||||
## Configuration Steps
|
||||
1. Set the staging web service environment as needed:
|
||||
- `DFC_COMPAT_SNAPSHOT=1` when downstream teams still require the compatibility snapshot.
|
||||
- Optional diagnostics helpers: `SHOW_DIAGNOSTICS=1`, `SHOW_LOGS=1` (helps confirm telemetry output during smoke testing).
|
||||
2. Inside the staging container (or server), regenerate commander data:
|
||||
```powershell
|
||||
python -m code.scripts.refresh_commander_catalog
|
||||
```
|
||||
- Verify the script reports both the merged output (`csv_files/commander_cards.csv`) and the compatibility snapshot (`csv_files/compat_faces/commander_cards_unmerged.csv`).
|
||||
3. Restart the web service so the refreshed files (and optional compatibility snapshot setting) take effect.
|
||||
|
||||
## Smoke QA
|
||||
| Area | Steps | Pass Criteria |
|
||||
| --- | --- | --- |
|
||||
| Commander Browser | Load `/commanders`, search for a known MDFC commander (e.g., "Elmar, Ulvenwald Informant"), flip faces, paginate results. | No duplicate rows per face, flip control works, pagination remains responsive. |
|
||||
| Deck Builder | Run a New Deck build with a commander that adds MDFC lands (e.g., "Atraxa, Grand Unifier" with MDFC swap option). | Deck summary shows "Lands: X (Y with DFC)" copy, MDFC notes render, CLI summary matches web copy (check download/export). |
|
||||
| Commander Exclusions | Attempt to search for a commander that should be excluded because only the back face is legal (e.g., "Withengar Unbound"). | UI surfaces exclusion guidance; the commander is not selectable. |
|
||||
| Diagnostics | Open `/diagnostics` with `SHOW_DIAGNOSTICS=1`. Confirm MDFC telemetry panel shows merged counts. | `dfc_merge_summary` card present with non-zero merged totals; land telemetry includes MDFC contribution counts. |
|
||||
| Logs | Tail application logs via `/logs` or container logs during a build. | No errors related to tag merging or commander loading. |
|
||||
|
||||
## Automated Checks
|
||||
Run the targeted test suite to ensure MDFC regressions are caught:
|
||||
```powershell
|
||||
c:/Users/Matt/mtg_python/mtg_python_deckbuilder/.venv/Scripts/python.exe -m pytest -q ^
|
||||
code/tests/test_land_summary_totals.py ^
|
||||
code/tests/test_commander_primary_face_filter.py ^
|
||||
code/tests/test_commander_exclusion_warnings.py
|
||||
```
|
||||
- All tests should pass. Investigate any failures before promoting the flag.
|
||||
|
||||
## Downstream Sign-off
|
||||
1. Provide consumers with:
|
||||
- Merged file: `csv_files/commander_cards.csv`
|
||||
- Compatibility snapshot: `csv_files/compat_faces/commander_cards_unmerged.csv`
|
||||
2. Share expected merge metrics (`logs/dfc_merge_summary.json`) to help validate MDFC counts.
|
||||
3. Collect acknowledgements that downstream pipelines work with the merged file (or have cut over) before retiring the compatibility flag.
|
||||
|
||||
## Rollback Plan
|
||||
- Disable `DFC_COMPAT_SNAPSHOT` (or leave it unset) and rerun `python -m code.scripts.refresh_commander_catalog` if compatibility snapshots are no longer required.
|
||||
- Revert to the previous committed commander CSV if needed (`git checkout -- csv_files/commander_cards.csv`).
|
||||
- Document the issue in the roadmap and schedule the fix before reattempting the staging rollout.
|
||||
|
||||
## Latest Run (2025-10-02)
|
||||
- Environment: staging compose updated (temporarily set `ENABLE_DFC_MERGE=compat`, now retired) and reconfigured with optional `DFC_COMPAT_SNAPSHOT=1` for compatibility checks.
|
||||
- Scripts executed:
|
||||
- `python -m code.scripts.refresh_commander_catalog --compat-snapshot`
|
||||
- `python -m code.scripts.preview_dfc_catalog_diff --compat-snapshot --output logs/dfc_catalog_diff.json`
|
||||
- Automated tests passed:
|
||||
- `code/tests/test_land_summary_totals.py`
|
||||
- `code/tests/test_commander_primary_face_filter.py`
|
||||
- `code/tests/test_commander_exclusion_warnings.py`
|
||||
- Downstream sign-off: `logs/dfc_catalog_diff.json` shared with catalog consumers alongside `csv_files/compat_faces/commander_cards_unmerged.csv`; acknowledgements recorded in `docs/releases/dfc_merge_rollout.md`.
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
# Random Mode Theme Exclusions
|
||||
|
||||
The curated random theme pool keeps auto-fill suggestions focused on themes that lead to actionable Commander builds. This document summarizes the heuristics and manual exclusions that shape the pool and explains how to discover every theme when you want to override the curated list.
|
||||
|
||||
## Heuristics applied automatically
|
||||
|
||||
We remove a theme token from the curated pool when any of the following conditions apply:
|
||||
|
||||
1. **Insufficient examples** – fewer than five unique commanders in the catalog advertise the token.
|
||||
2. **Kindred and species-specific labels** – anything matching keywords such as `kindred`, `tribal`, `clan`, or endings like `" tribe"` is treated as commander-specific and filtered out.
|
||||
3. **Global catch-alls** – broad phrases (for example `goodstuff`, `legendary matter`, `historic matter`) offer little guidance for theme selection, so they are excluded.
|
||||
4. **Over-represented themes** – if 30% or more of the commander catalog advertises a token, it is removed from the surprise pool to keep suggestions varied.
|
||||
|
||||
These rules are codified in `code/deck_builder/random_entrypoint.py` and surfaced via the diagnostics panel and the reporting script.
|
||||
|
||||
## Manual exclusions
|
||||
|
||||
Some descriptors are technically valid tokens but still degrade the surprise experience. They live in `config/random_theme_exclusions.yml` so we can document why they are hidden and keep the list reviewable.
|
||||
|
||||
| Category | Why it is excluded | Tokens |
|
||||
| --- | --- | --- |
|
||||
| `ubiquitous_baseline` | Baseline game actions every deck performs; surfacing them would be redundant. | `card advantage`, `card draw`, `removal`, `interaction` |
|
||||
| `degenerate_catchall` | Generic "good stuff" style descriptors that do not communicate a coherent plan. | `value`, `good stuff`, `goodstuff`, `good-stuff`, `midrange value` |
|
||||
| `non_theme_qualifiers` | Power-level or budget qualifiers; these belong in settings, not theme suggestions. | `budget`, `competitive`, `cedh`, `high power` |
|
||||
|
||||
Themes removed here still resolve just fine when you type them manually into any theme field or when you import them from permalinks, sessions, or the CLI.
|
||||
|
||||
### Keeping the list discoverable
|
||||
|
||||
The reporting script can export the manual list alongside the curated pool:
|
||||
|
||||
```powershell
|
||||
# Markdown summary with exclusions
|
||||
python code/scripts/report_random_theme_pool.py --format markdown
|
||||
|
||||
# Structured exclusions for tooling
|
||||
python code/scripts/report_random_theme_pool.py --write-exclusions logs/random_theme_exclusions.json
|
||||
```
|
||||
|
||||
Both commands refresh the commander catalog on demand and mirror the exact heuristics used by the web UI and API.
|
||||
|
||||
## Surfacing the information in the app
|
||||
|
||||
When diagnostics are enabled (`SHOW_DIAGNOSTICS=1`), the `/diagnostics` panel shows:
|
||||
|
||||
- Total curated pool size and coverage.
|
||||
- Counts per exclusion reason (including manual categories).
|
||||
- Sample tokens and the manual categories that removed them.
|
||||
- Tag index telemetry (build count, cache hit rate) for performance monitoring.
|
||||
|
||||
This makes it easy to audit the pool after catalog or heuristic changes.
|
||||
|
||||
## Updating the manual list
|
||||
|
||||
1. Edit `config/random_theme_exclusions.yml` and add or adjust entries (keep tokens lowercase; normalization happens automatically).
|
||||
2. Run `python code/scripts/report_random_theme_pool.py --format markdown --refresh` to verify the pool summary.
|
||||
3. Commit the YAML update together with the regenerated documentation when you are satisfied.
|
||||
|
||||
The curated pool will pick up the change automatically thanks to the file timestamp watcher in `random_entrypoint.py`.
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# MDFC Merge Rollout (2025-10-02)
|
||||
|
||||
## Summary
|
||||
- Staging environment refreshed with the MDFC merge permanently enabled; compatibility snapshot retained via `DFC_COMPAT_SNAPSHOT=1` during validation.
|
||||
- Commander catalog rebuilt with `python -m code.scripts.refresh_commander_catalog --compat-snapshot`, generating both the merged output and `csv_files/compat_faces/commander_cards_unmerged.csv` for downstream comparison.
|
||||
- Diff artifact `logs/dfc_catalog_diff.json` captured via `python -m code.scripts.preview_dfc_catalog_diff --compat-snapshot --output logs/dfc_catalog_diff.json` and shared with downstream consumers.
|
||||
- `ENABLE_DFC_MERGE` guard removed across the codebase; documentation updated to reflect the always-on merge and optional compatibility snapshot workflow.
|
||||
|
||||
## QA Artifacts
|
||||
| Artifact | Description |
|
||||
| --- | --- |
|
||||
| `docs/qa/mdfc_staging_checklist.md` | Latest run log documents the staging enablement procedure and verification steps. |
|
||||
| `logs/dfc_catalog_diff.json` | JSON diff summarising merged vs. unmerged commander/catalog rows for parity review. |
|
||||
| `csv_files/commander_cards.csv` | Merged commander catalog generated after guard removal. |
|
||||
| `csv_files/compat_faces/commander_cards_unmerged.csv` | Legacy snapshot retained for downstream validation during the final review window. |
|
||||
|
||||
## Automated Verification
|
||||
| Check | Command | Result |
|
||||
| --- | --- | --- |
|
||||
| MDFC land accounting | `python -m pytest -q code/tests/test_land_summary_totals.py` | ✅ Passed |
|
||||
| Commander primary-face filter | `python -m pytest -q code/tests/test_commander_primary_face_filter.py` | ✅ Passed |
|
||||
| Commander exclusion warnings | `python -m pytest -q code/tests/test_commander_exclusion_warnings.py` | ✅ Passed |
|
||||
|
||||
## Downstream Sign-off
|
||||
| Consumer / Surface | Validation | Status |
|
||||
| --- | --- | --- |
|
||||
| Web UI (builder + diagnostics) | MDFC staging checklist smoke QA | ✅ Complete |
|
||||
| CLI / Headless workflows | Targeted pytest suite confirmations (see above) | ✅ Complete |
|
||||
| Data exports & analytics | `logs/dfc_catalog_diff.json` review against `commander_cards_unmerged.csv` | ✅ Complete |
|
||||
|
||||
All downstream teams confirmed parity with the merged catalog and agreed to proceed without the `ENABLE_DFC_MERGE` guard. Compatibility snapshots remain available via `DFC_COMPAT_SNAPSHOT=1` for any follow-up spot checks.
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
# MTG Deckbuilder Web UI Style Guide
|
||||
|
||||
## Design Tokens
|
||||
|
||||
Design tokens provide a consistent foundation for all UI elements. These are defined as CSS custom properties in `code/web/static/styles.css`.
|
||||
|
||||
### Spacing Scale
|
||||
|
||||
Use the spacing scale for margins, padding, and gaps:
|
||||
|
||||
```css
|
||||
--space-xs: 0.25rem; /* 4px - Tight spacing within components */
|
||||
--space-sm: 0.5rem; /* 8px - Default gaps between small elements */
|
||||
--space-md: 0.75rem; /* 12px - Standard component padding */
|
||||
--space-lg: 1rem; /* 16px - Section spacing, card gaps */
|
||||
--space-xl: 1.5rem; /* 24px - Major section breaks */
|
||||
--space-2xl: 2rem; /* 32px - Page-level spacing */
|
||||
```
|
||||
|
||||
**Usage examples:**
|
||||
- Chip gaps: `gap: var(--space-sm)`
|
||||
- Panel padding: `padding: var(--space-md)`
|
||||
- Section margins: `margin: var(--space-xl) 0`
|
||||
|
||||
### Typography Scale
|
||||
|
||||
Consistent font sizes for hierarchy:
|
||||
|
||||
```css
|
||||
--text-xs: 0.75rem; /* 12px - Meta info, badges */
|
||||
--text-sm: 0.875rem; /* 14px - Secondary text */
|
||||
--text-base: 1rem; /* 16px - Body text */
|
||||
--text-lg: 1.125rem; /* 18px - Subheadings */
|
||||
--text-xl: 1.25rem; /* 20px - Section headers */
|
||||
--text-2xl: 1.5rem; /* 24px - Page titles */
|
||||
```
|
||||
|
||||
**Font weights:**
|
||||
```css
|
||||
--font-normal: 400; /* Body text */
|
||||
--font-medium: 500; /* Emphasis */
|
||||
--font-semibold: 600; /* Headings */
|
||||
--font-bold: 700; /* Strong emphasis */
|
||||
```
|
||||
|
||||
### Border Radius
|
||||
|
||||
Consistent corner rounding:
|
||||
|
||||
```css
|
||||
--radius-sm: 4px; /* Subtle rounding */
|
||||
--radius-md: 6px; /* Buttons, inputs */
|
||||
--radius-lg: 8px; /* Panels, cards */
|
||||
--radius-xl: 12px; /* Large containers */
|
||||
--radius-full: 999px; /* Pills, chips */
|
||||
```
|
||||
|
||||
### Color Tokens
|
||||
|
||||
#### Semantic Colors
|
||||
```css
|
||||
--bg: #0f0f10; /* Page background */
|
||||
--panel: #1a1b1e; /* Panel/card backgrounds */
|
||||
--text: #e8e8e8; /* Primary text */
|
||||
--muted: #b6b8bd; /* Secondary text */
|
||||
--border: #2a2b2f; /* Borders and dividers */
|
||||
--ring: #60a5fa; /* Focus indicator */
|
||||
--ok: #16a34a; /* Success states */
|
||||
--warn: #f59e0b; /* Warning states */
|
||||
--err: #ef4444; /* Error states */
|
||||
```
|
||||
|
||||
#### MTG Color Identity
|
||||
```css
|
||||
--green-main: rgb(0,115,62);
|
||||
--green-light: rgb(196,211,202);
|
||||
--blue-main: rgb(14,104,171);
|
||||
--blue-light: rgb(179,206,234);
|
||||
--red-main: rgb(211,32,42);
|
||||
--red-light: rgb(235,159,130);
|
||||
--white-main: rgb(249,250,244);
|
||||
--white-light: rgb(248,231,185);
|
||||
--black-main: rgb(21,11,0);
|
||||
--black-light: rgb(166,159,157);
|
||||
```
|
||||
|
||||
## Component Patterns
|
||||
|
||||
### Chips
|
||||
|
||||
Chips display tags, status indicators, and metadata.
|
||||
|
||||
**Basic chip:**
|
||||
```html
|
||||
<span class="chip">
|
||||
<span class="dot" style="background: var(--ok);"></span>
|
||||
Label
|
||||
</span>
|
||||
```
|
||||
|
||||
**Chip containers:**
|
||||
```html
|
||||
<!-- Flexbox inline chips (existing) -->
|
||||
<div class="chips-inline">
|
||||
<span class="chip">Tag 1</span>
|
||||
<span class="chip">Tag 2</span>
|
||||
</div>
|
||||
|
||||
<!-- Grid auto-fit chips (new - responsive) -->
|
||||
<div class="chips-grid">
|
||||
<span class="chip">Item 1</span>
|
||||
<span class="chip">Item 2</span>
|
||||
<span class="chip">Item 3</span>
|
||||
</div>
|
||||
|
||||
<!-- Small grid (90px min) -->
|
||||
<div class="chips-grid chips-grid-sm">...</div>
|
||||
|
||||
<!-- Large grid (160px min) -->
|
||||
<div class="chips-grid chips-grid-lg">...</div>
|
||||
```
|
||||
|
||||
### Summary Panels
|
||||
|
||||
Responsive grid panels for dashboard-style layouts:
|
||||
|
||||
```html
|
||||
<div class="summary-panels">
|
||||
<div class="summary-panel">
|
||||
<div class="summary-panel-header">Panel Title</div>
|
||||
<div class="summary-panel-content">
|
||||
Panel content here
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-panel">
|
||||
<div class="summary-panel-header">Another Panel</div>
|
||||
<div class="summary-panel-content">
|
||||
More content
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Panels automatically flow into columns based on available width (240px min per column).
|
||||
|
||||
## Responsive Breakpoints
|
||||
|
||||
The UI uses CSS Grid `auto-fit` patterns that adapt naturally to viewport width:
|
||||
|
||||
- **Mobile** (< 640px): Single column layouts
|
||||
- **Tablet** (640px - 900px): 2-column where space allows
|
||||
- **Desktop** (> 900px): Multi-column with `auto-fit`
|
||||
|
||||
Grid patterns automatically adjust without media queries:
|
||||
```css
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Focus Indicators
|
||||
All interactive elements receive a visible focus ring:
|
||||
```css
|
||||
.focus-visible {
|
||||
outline: 2px solid var(--ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
### Color Contrast
|
||||
- Text on backgrounds: Minimum 4.5:1 ratio (WCAG AA)
|
||||
- Large text/headings: Minimum 3:1 ratio
|
||||
- Interactive elements: Sufficient contrast for all states
|
||||
|
||||
### Keyboard Navigation
|
||||
- Tab order follows visual flow
|
||||
- Skip links available for main content areas
|
||||
- All controls accessible via keyboard
|
||||
|
||||
## Theme Support
|
||||
|
||||
The app supports multiple themes via `data-theme` attribute:
|
||||
|
||||
- `dark` (default): Dark mode optimized
|
||||
- `light-blend`: Light mode with warm tones
|
||||
- `high-contrast`: Maximum contrast for visibility
|
||||
- `cb-friendly`: Color-blind friendly palette
|
||||
|
||||
Themes automatically adjust all token values.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use tokens over hardcoded values**
|
||||
- ✅ `padding: var(--space-md)`
|
||||
- ❌ `padding: 12px`
|
||||
|
||||
2. **Leverage auto-fit grids for responsive layouts**
|
||||
- ✅ `grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))`
|
||||
- ❌ Multiple media queries with fixed columns
|
||||
|
||||
3. **Maintain semantic color usage**
|
||||
- Use `--ok`, `--warn`, `--err` for states
|
||||
- Use MTG colors for identity-specific UI
|
||||
- Use `--text`, `--muted` for typography hierarchy
|
||||
|
||||
4. **Keep components DRY**
|
||||
- Reuse `.chip`, `.summary-panel`, `.chips-grid` patterns
|
||||
- Extend with modifiers, not duplicates
|
||||
|
||||
5. **Test across viewports**
|
||||
- Verify auto-fit breakpoints work smoothly
|
||||
- Check mobile (375px), tablet (768px), desktop (1440px)
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
# Theme Catalog Advanced Guide
|
||||
|
||||
Additional details for developers and power users working with the theme catalog, editorial tooling, and diagnostics.
|
||||
|
||||
## Table of contents
|
||||
- [theme_catalog.csv schema](#theme_catalogcsv-schema)
|
||||
- [HTMX API endpoints](#htmx-api-endpoints)
|
||||
- [Caching, diagnostics, and metrics](#caching-diagnostics-and-metrics)
|
||||
- [Governance principles](#governance-principles)
|
||||
- [Operational tooling](#operational-tooling)
|
||||
- [Refreshing catalogs](#refreshing-catalogs)
|
||||
- [Snapshotting taxonomy](#snapshotting-taxonomy)
|
||||
- [Adaptive splash penalty experiments](#adaptive-splash-penalty-experiments)
|
||||
- [Editorial pipeline](#editorial-pipeline)
|
||||
- [Script summary](#script-summary)
|
||||
- [Example configuration](#example-configuration)
|
||||
- [Duplicate suppression controls](#duplicate-suppression-controls)
|
||||
- [Coverage metrics and KPIs](#coverage-metrics-and-kpis)
|
||||
- [Description mapping overrides](#description-mapping-overrides)
|
||||
- [Validation and schema tooling](#validation-and-schema-tooling)
|
||||
|
||||
|
||||
## theme_catalog.csv schema
|
||||
`theme_catalog.csv` is the normalized artifact consumed by headless builds, supplemental themes, and diagnostics panels. The file starts with a header comment in the format `# theme_catalog version=<hash>` followed by a standard CSV header with these columns:
|
||||
|
||||
| Column | Description |
|
||||
| --- | --- |
|
||||
| `theme` | Normalized display label used across the app and JSON exports. |
|
||||
| `commander_count` | Number of commanders tagged with the theme in `commander_cards.csv`. |
|
||||
| `card_count` | Number of non-commander cards carrying the theme tag across primary CSVs. |
|
||||
| `source_count` | Combined count (`commander_count + card_count`) to simplify weighting heuristics. |
|
||||
| `last_generated_at` | ISO-8601 timestamp captured at generation time (UTC). Useful for verifying stale catalogs in diagnostics. |
|
||||
| `version` | Deterministic SHA-256 prefix derived from the ordered theme list; this value flows into exports as `themeCatalogVersion` and `/status/theme_metrics`. |
|
||||
|
||||
Consumers should treat additional columns as experimental. If you add new fields, update this table and the supplemental theme tests that assert schema coverage.
|
||||
|
||||
## HTMX API endpoints
|
||||
The upcoming theme picker UI is powered by two FastAPI endpoints.
|
||||
|
||||
### `GET /themes/api/themes`
|
||||
Parameters:
|
||||
- `q`: substring search across theme names and synergies.
|
||||
- `archetype`: filter by `deck_archetype`.
|
||||
- `bucket`: popularity bucket (Very Common, Common, Uncommon, Niche, Rare).
|
||||
- `colors`: comma-separated color initials (e.g. `G,W`).
|
||||
- `limit` / `offset`: pagination (limit defaults to 50, max 200).
|
||||
- `diagnostics=1`: surfaces `has_fallback_description` and `editorial_quality` (requires `WEB_THEME_PICKER_DIAGNOSTICS=1`).
|
||||
|
||||
The response includes `count`, the filtered `items`, and `next_offset` for subsequent requests. Diagnostic mode adds extra telemetry fields.
|
||||
|
||||
### `GET /themes/api/theme/{id}`
|
||||
Parameters:
|
||||
- `uncapped=1`: (diagnostics) returns `uncapped_synergies`, combining curated, enforced, and inferred sets.
|
||||
- `diagnostics=1`: exposes editorial metadata such as `editorial_quality` and `has_fallback_description`.
|
||||
|
||||
The payload merges curated data with editorial artifacts (`example_cards`, `example_commanders`, etc.) and respects the same diagnostic feature flag.
|
||||
|
||||
## Caching, diagnostics, and metrics
|
||||
- Responses include an `ETag` header derived from catalog metadata so consumers can perform conditional GETs.
|
||||
- `/themes/status` reports freshness and stale indicators; `/themes/refresh` (POST) triggers a background rebuild.
|
||||
- When `WEB_THEME_PICKER_DIAGNOSTICS=1` is set, the app records:
|
||||
- Filter cache hits/misses and duration (`X-ThemeCatalog-Filter-Duration-ms`).
|
||||
- Preview cache metrics (`/themes/metrics` exposes counts, hit rates, TTL, and average build time).
|
||||
- Skeleton loaders ship with the HTMX fragments to keep perceived latency low.
|
||||
|
||||
## Governance principles
|
||||
To keep the catalog healthy, the project follows a lightweight governance checklist:
|
||||
|
||||
1. **Minimum examples** – target at least two example cards and one commander per established theme.
|
||||
2. **Deterministic preview assembly** – curated examples first, then role-based samples (payoff/enabler/support/wildcard), then placeholders if needed.
|
||||
3. **Splash relax policy** – four- and five-color commanders may include a single off-color enabler with a small penalty, preventing over-pruning.
|
||||
4. **Popularity buckets are advisory** – they guide filters and UI hints but never directly influence scoring.
|
||||
5. **Taxonomy expansion bar** – new high-level archetypes require a distinct pattern, at least eight representative cards, and no overlap with existing themes.
|
||||
6. **Editorial quality tiers** – optional `editorial_quality: draft|reviewed|final` helps prioritize review passes.
|
||||
7. **Deterministic sampling** – seeds derive from `theme|commander` hashes; scoring code should emit `reasons[]` to explain decisions and remain regression-test friendly.
|
||||
|
||||
See `docs/theme_taxonomy_rationale.md` for the underlying rationale and roadmap.
|
||||
|
||||
## Operational tooling
|
||||
|
||||
### Refreshing catalogs
|
||||
- Primary builder: `python code/scripts/build_theme_catalog.py`
|
||||
- Options:
|
||||
- `--limit N`: preview a subset without overwriting canonical outputs (unless `--allow-limit-write`).
|
||||
- `--output path`: write to an alternate path; suppresses YAML backfill to avoid mutating tracked files.
|
||||
- `--backfill-yaml` or `EDITORIAL_BACKFILL_YAML=1`: fill missing descriptions and popularity buckets in YAML files.
|
||||
- `--force-backfill-yaml`: overwrite existing description/popularity fields.
|
||||
- `EDITORIAL_SEED=<int>`: force a deterministic ordering when heuristics use randomness.
|
||||
- `EDITORIAL_AGGRESSIVE_FILL=1`: pad sparse themes with inferred synergies.
|
||||
- `EDITORIAL_POP_BOUNDARIES="a,b,c,d"`: tune popularity thresholds.
|
||||
- `EDITORIAL_POP_EXPORT=1`: emit `theme_popularity_metrics.json` summaries.
|
||||
|
||||
### Snapshotting taxonomy
|
||||
`python -m code.scripts.snapshot_taxonomy` writes `logs/taxonomy_snapshots/taxonomy_<timestamp>.json` with a SHA-256 hash. Identical content is skipped unless you supply `--force`. Use snapshots before experimenting with taxonomy-aware sampling.
|
||||
|
||||
### Adaptive splash penalty experiments
|
||||
Set `SPLASH_ADAPTIVE=1` to scale off-color enabler penalties based on commander color count. Tune with `SPLASH_ADAPTIVE_SCALE` (e.g. `1:1.0,2:1.0,3:1.0,4:0.6,5:0.35`). Analytics aggregate both static and adaptive reasons for comparison.
|
||||
|
||||
## Editorial pipeline
|
||||
|
||||
### Script summary
|
||||
- `code/scripts/generate_theme_editorial_suggestions.py`
|
||||
- Proposes `example_cards`, `example_commanders`, and `synergy_commanders` using card CSVs and tagging heuristics.
|
||||
- `--augment-synergies` can pad sparse `synergies` arrays prior to suggestion.
|
||||
- `--apply` writes results; dry runs print suggestions for review.
|
||||
- `code/scripts/lint_theme_editorial.py`
|
||||
- Validates annotation formats, min/max counts, and deduplication. Combine with environment toggles (`EDITORIAL_REQUIRE_DESCRIPTION`, `EDITORIAL_REQUIRE_POPULARITY`) for stricter gating.
|
||||
|
||||
### Example configuration
|
||||
```powershell
|
||||
# Dry run on the first 25 themes
|
||||
python code/scripts/generate_theme_editorial_suggestions.py
|
||||
|
||||
# Apply across the catalog with augmentation and min example commanders set to 5
|
||||
python code/scripts/generate_theme_editorial_suggestions.py --apply --augment-synergies --min-examples 5
|
||||
|
||||
# Lint results
|
||||
python code/scripts/lint_theme_editorial.py
|
||||
```
|
||||
|
||||
Editorial output depends on current CSV data. Expect ordering or composition changes after upstream dataset refreshes—treat full-catalog regeneration as an operational task and review diffs carefully.
|
||||
|
||||
### Duplicate suppression controls
|
||||
`code/scripts/synergy_promote_fill.py` can rebalance example cards:
|
||||
|
||||
```powershell
|
||||
python code/scripts/synergy_promote_fill.py --fill-example-cards --common-card-threshold 0.18 --print-dup-metrics
|
||||
```
|
||||
|
||||
- `--common-card-threshold`: filters cards appearing in more than the specified fraction of themes (default `0.18`).
|
||||
- Use metrics output to tune thresholds so staple utility cards stay in check without removing legitimate thematic cards.
|
||||
|
||||
### Coverage metrics and KPIs
|
||||
- `EDITORIAL_INCLUDE_FALLBACK_SUMMARY=1` embeds a `description_fallback_summary` block in the generated catalog (`generic_total`, `generic_plain`, `generic_pct`, etc.).
|
||||
- Regression tests use these metrics to ratchet down generic descriptions over time.
|
||||
- Historical trends are appended to `config/themes/description_fallback_history.jsonl` for analysis.
|
||||
|
||||
### Description mapping overrides
|
||||
Customize automatic descriptions without editing code:
|
||||
|
||||
- Add `config/themes/description_mapping.yml` with entries:
|
||||
```yaml
|
||||
- triggers: ["sacrifice", "aristocrat"]
|
||||
description: "Leans on sacrifice loops and {SYNERGIES}."
|
||||
```
|
||||
- The first matching trigger wins (case-insensitive substring search).
|
||||
- `{SYNERGIES}` expands to a short clause listing the top synergies when available, and disappears gracefully if not.
|
||||
- Internal defaults remain as fallbacks when the mapping file is absent.
|
||||
|
||||
## Validation and schema tooling
|
||||
|
||||
Run validators to maintain catalog quality:
|
||||
|
||||
```powershell
|
||||
python code/scripts/validate_theme_catalog.py
|
||||
python code/scripts/validate_theme_catalog.py --rebuild-pass
|
||||
python code/scripts/validate_theme_catalog.py --schema
|
||||
python code/scripts/validate_theme_catalog.py --yaml-schema
|
||||
python code/scripts/validate_theme_catalog.py --strict-alias
|
||||
```
|
||||
|
||||
Per-theme YAML files (under `config/themes/catalog/`) are tracked in source control. Keys such as `metadata_info` replace the legacy `provenance`; the validator treats missing migrations as warnings until the deprecation completes.
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
# Theme Taxonomy Rationale & Governance
|
||||
|
||||
This document captures decision criteria and rationale for expanding, merging, or refining the theme taxonomy.
|
||||
|
||||
## Goals
|
||||
- Maintain meaningful, player-recognizable buckets.
|
||||
- Avoid overspecialization (micro-themes) that dilute search & filtering.
|
||||
- Preserve sampling diversity and editorial sustainability.
|
||||
|
||||
## Expansion Checklist
|
||||
A proposed new theme SHOULD satisfy ALL of:
|
||||
1. Distinct Strategic Identity: The game plan (win condition / resource axis) is not already adequately described by an existing theme or combination of two existing themes.
|
||||
2. Representative Card Depth: At least 8 broadly played, format-relevant cards (EDHREC / common play knowledge) naturally cluster under this identity.
|
||||
3. Commander Support: At least 3 reasonable commander candidates (not including fringe silver-bullets) benefit from or enable the theme.
|
||||
4. Non-Subset Test: The candidate is not a strict subset of an existing theme's synergy list (check overlap ≥70% == probable subset).
|
||||
5. Editorial Coverage Plan: Concrete initial examples & synergy tags identified; no reliance on placeholders at introduction.
|
||||
|
||||
If any criterion fails -> treat as a synergy tag inside an existing theme rather than a standalone theme.
|
||||
|
||||
## Candidate Themes & Notes
|
||||
| Candidate | Rationale | Risks / Watchouts | Initial Verdict |
|
||||
|-----------|-----------|-------------------|-----------------|
|
||||
| Combo | High-synergy deterministic or infinite loops. Already partly surfaced via combo detection features. | Over-broad; could absorb unrelated value engines. | Defer; emphasize combo detection tooling instead. |
|
||||
| Storm | Spell-chain count scaling (Grapeshot, Tendrils). Distinct engine requiring density/rituals. | Low breadth in casual metas; may overlap with Spellslinger. | Accept (pending 8-card list + commander examples). |
|
||||
| Extra Turns | Time Walk recursion cluster. | Potential negative play perception; governance needed to avoid glorifying NPE lines. | Tentative accept (tag only until list curated). |
|
||||
| Group Hug / Politics | Resource gifting & table manipulation. | Hard to score objectively; card set is broad. | Accept with curated examples to anchor definition. |
|
||||
| Pillowfort | Defensive taxation / attack deterrence (Ghostly Prison line). | Overlap with Control / Enchantments. | Accept; ensure non-redundant with generic Enchantments. |
|
||||
| Toolbox / Tutors | Broad search utility enabling silver-bullet packages. | Tutors already subject to bracket policy thresholds; broad risk. | Defer; retain as synergy tag only. |
|
||||
| Treasure Matters | Explicit treasure scaling (Academy Manufactor, Prosper). | Rapidly evolving; needs periodic review. | Accept. |
|
||||
| Monarch / Initiative | Alternate advantage engines via emblems/dungeons. | Initiative narrower post-rotation; watch meta shifts. | Accept (merge both into a single theme for now). |
|
||||
|
||||
## Merge / Normalization Guidelines
|
||||
When overlap (Jaccard) between Theme A and Theme B > 0.55 across curated+enforced synergies OR example card intersection ≥60%, evaluate for merge. Preference order:
|
||||
1. Retain broader, clearer name.
|
||||
2. Preserve curated examples; move excess to synergy tags.
|
||||
3. Add legacy name to `aliases` for backward compatibility.
|
||||
|
||||
## Example Count Enforcement
|
||||
Threshold flips to hard enforcement after global coverage >90%:
|
||||
- Missing required examples -> linter error (`lint_theme_editorial.py --require-examples`).
|
||||
- Build fails CI unless waived with explicit override label.
|
||||
|
||||
## Splash Relax Policy Rationale
|
||||
- Prevents 4–5 color commanders from feeling artificially constrained when one enabling piece lies just outside colors.
|
||||
- Controlled by single-card allowance + -0.3 score penalty so off-color never outranks true color-aligned payoffs.
|
||||
|
||||
## Popularity Buckets Non-Scoring Principle
|
||||
Popularity reflects observational frequency and is intentionally orthogonal to sampling to avoid feedback loops. Any future proposal to weight by popularity must include a diversity impact analysis and opt-in feature flag.
|
||||
|
||||
## Determinism & Reproducibility
|
||||
All sampling randomness is derived from `seed = hash(theme|commander)`; taxonomy updates must document any score function changes in `CHANGELOG.md` and provide transition notes if output ordering shifts beyond acceptable tolerance.
|
||||
|
||||
## Governance Change Process
|
||||
1. Open a PR modifying taxonomy YAML or this file.
|
||||
2. Include: rationale, representative card list, commander list, overlap analysis with nearest themes.
|
||||
3. Run catalog build + linter; attach metrics snapshot (`preview_metrics_snapshot.py`).
|
||||
4. Reviewer checks duplication, size, overlap, enforcement thresholds.
|
||||
|
||||
## Future Considerations
|
||||
- Automated overlap dashboard (heatmap) for candidate merges.
|
||||
- Nightly diff bot summarizing coverage & generic description regression.
|
||||
- Multi-dimensional rarity quota experimentation (moved to Deferred section for now).
|
||||
|
||||
---
|
||||
Last updated: 2025-09-20
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
# Build X and Compare User Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The **Build X and Compare** feature allows you to build multiple decks using the same configuration and compare the results side-by-side. This is useful for:
|
||||
|
||||
- **Seeing variance**: Understand which cards are consistent vs. which cards vary due to RNG
|
||||
- **Finding optimal builds**: Compare multiple results to pick the best deck
|
||||
- **Analyzing synergies**: Use the Synergy Builder to create an optimized "best-of" deck
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Build Multiple Decks
|
||||
|
||||
1. Click **New Deck** to open the deck builder modal
|
||||
2. Configure your commander, themes, ideals, and bracket as normal
|
||||
3. At the bottom of the modal, adjust the **"Number of decks to build"** slider (1-10)
|
||||
- Setting this to 2 or more enables batch build mode
|
||||
4. Click **Quick Build** - the "Create" button is hidden for batch builds
|
||||
|
||||
**Note**: All builds use the exact same configuration. There are no variations in commander, themes, or ideals - you're simply running the same build multiple times to see different card selections.
|
||||
|
||||
### 2. Track Progress
|
||||
|
||||
After starting a batch build, you'll see a progress screen showing:
|
||||
|
||||
- **Progress bar**: Visual indicator of completion
|
||||
- **Build status**: "Completed X of Y builds..."
|
||||
- **Time estimate**: Dynamically adjusted based on commander color count
|
||||
- 1-2 colors: 1-3 minutes
|
||||
- 3 colors: 2-4 minutes
|
||||
- 4-5 colors: 3-5 minutes
|
||||
- **First deck time**: The first deck takes ~55-60% of total time
|
||||
|
||||
### 3. Compare Results
|
||||
|
||||
Once all builds complete, you'll be redirected to the **Comparison View** with:
|
||||
|
||||
#### Overview Stats
|
||||
- **Unique Cards Total**: All different cards across all builds
|
||||
- **In All Builds**: Cards that appear in every single deck
|
||||
- **In Most Builds (80%+)**: High-frequency cards
|
||||
- **In Some Builds**: Medium-frequency cards
|
||||
- **In Few Builds**: Low-frequency cards
|
||||
|
||||
#### Most Common Cards
|
||||
Shows the top 20 cards by appearance frequency, excluding guaranteed cards like:
|
||||
- Basic lands
|
||||
- Staple lands (Command Tower, Reliquary Tower, etc.)
|
||||
- Must-include cards (if using the include/exclude feature)
|
||||
- Fetch lands
|
||||
|
||||
**Tip**: Hover over any card name to see the card image!
|
||||
|
||||
#### Individual Build Summaries
|
||||
Each build shows:
|
||||
- Total card count and breakdown (Creatures, Lands, Artifacts, etc.)
|
||||
- Expandable card list with full deck contents
|
||||
|
||||
## Using the Synergy Builder
|
||||
|
||||
The **Synergy Builder** analyzes all builds and creates an optimized "best-of" deck using the most synergistic cards.
|
||||
|
||||
### How It Works
|
||||
|
||||
The Synergy Builder scores each card based on:
|
||||
|
||||
1. **Frequency (50%)**: How often the card appears across builds
|
||||
- Cards in 80%+ of builds get a 10% bonus
|
||||
2. **EDHREC Rank (25%)**: Community popularity data
|
||||
3. **Theme Tags (25%)**: Alignment with your chosen themes
|
||||
|
||||
### Building a Synergy Deck
|
||||
|
||||
1. From the comparison view, click **✨ Build Synergy Deck**
|
||||
2. Wait a few seconds while the synergy deck is generated
|
||||
3. Review the results:
|
||||
- **Synergy Preview**: Shows the full deck with color-coded synergy scores
|
||||
- 🟢 Green (80-100): High synergy
|
||||
- 🔵 Blue (60-79): Good synergy
|
||||
- 🟡 Yellow (40-59): Medium synergy
|
||||
- 🟠 Orange (20-39): Low synergy
|
||||
- 🔴 Red (0-19): Very low synergy
|
||||
- Cards are organized by type (Creature, Artifact, Enchantment, etc.)
|
||||
- Each section can be expanded/collapsed for easier viewing
|
||||
|
||||
### Exporting the Synergy Deck
|
||||
|
||||
1. Click **Export Synergy Deck** at the bottom of the synergy preview
|
||||
2. **Warning**: This will delete the individual batch build files and disable batch export
|
||||
3. Confirm the export to download a ZIP containing:
|
||||
- **SynergyDeck_CommanderName.csv**: Deck list in CSV format
|
||||
- **SynergyDeck_CommanderName.txt**: Plain text deck list
|
||||
- **summary.json**: Deck statistics and metadata
|
||||
- **compliance.json**: Bracket compliance information
|
||||
- **synergy_metadata.json**: Synergy scores and build source data
|
||||
|
||||
## Additional Actions
|
||||
|
||||
### Rebuild X Times
|
||||
Click **🔄 Rebuild Xx** to run the same configuration again with the same build count. This creates a new batch and redirects to the progress page.
|
||||
|
||||
### Export All Decks
|
||||
Click **Export All Decks as ZIP** to download all individual build files as a ZIP archive containing:
|
||||
- CSV and TXT files for each build (Build_1_CommanderName.csv, etc.)
|
||||
- `batch_summary.json` with metadata
|
||||
|
||||
**Note**: This button is disabled after exporting a synergy deck.
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- **Parallel execution**: Builds run concurrently (max 5 at a time) for faster results
|
||||
- **Build time scales**: More colors = longer build times
|
||||
- Mono/dual color: ~1 minute per 10 builds
|
||||
- 3 colors: ~2-3 minutes per 10 builds
|
||||
- 4-5 colors: ~3-4 minutes per 10 builds
|
||||
- **First deck overhead**: The first deck in a batch takes longer due to setup
|
||||
|
||||
## Feature Flag
|
||||
|
||||
To disable this feature entirely, set `ENABLE_BATCH_BUILD=0` in your environment variables or `.env` file. This will:
|
||||
|
||||
- Hide the "Number of decks to build" slider
|
||||
- Force all builds to be single-deck builds
|
||||
- Hide comparison and synergy features
|
||||
|
||||
## Tips & Best Practices
|
||||
|
||||
1. **Start small**: Try 3-5 builds first to get a feel for variance
|
||||
2. **Use for optimization**: Build 5-10 decks and pick the best result
|
||||
3. **Check consistency**: Cards appearing in 80%+ of builds are core to your strategy
|
||||
4. **Analyze variance**: Cards appearing in <50% of builds might be too situational
|
||||
5. **Synergy builder**: Best results with 5-10 source builds
|
||||
6. **Export early**: Export individual builds before creating synergy deck if you want both
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Builds are slow
|
||||
- Check your commander's color count - 4-5 color decks take longer
|
||||
- System resources - close other applications
|
||||
- First build takes longest - wait for completion before judging speed
|
||||
|
||||
### All builds look identical
|
||||
- Rare but possible - try adjusting themes or ideals for more variety
|
||||
- Check if you're using strict constraints (e.g., "owned cards only" with limited pool)
|
||||
|
||||
### Synergy deck doesn't meet ideals
|
||||
- The synergy builder aims for ±2 cards per category
|
||||
- If source builds don't have enough variety, it may relax constraints
|
||||
- Try building more source decks (7-10) for better card pool
|
||||
|
||||
### Export button disabled
|
||||
- You've already exported a synergy deck, which deletes individual batch files
|
||||
- Click "Rebuild Xx" to create a new batch if you need the files again
|
||||
|
||||
## See Also
|
||||
|
||||
- [Docker Setup Guide](../DOCKER.md) - Environment variables and configuration
|
||||
- [README](../../README.md) - General project documentation
|
||||
- [Changelog](../../CHANGELOG.md) - Feature updates and changes
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
# Web UI Deep Dive
|
||||
|
||||
A closer look at the rich interactions available in the MTG Python Deckbuilder Web UI. Use this guide after you are comfortable with the basic homepage flows described in the README.
|
||||
|
||||
## Table of contents
|
||||
- [Unified New Deck modal](#unified-new-deck-modal)
|
||||
- [Stage 5 tools: lock, replace, compare, permalinks](#stage-5-tools-lock-replace-compare-permalinks)
|
||||
- [Multi-copy archetype packages](#multi-copy-archetype-packages)
|
||||
- [Bracket compliance and skipped stages](#bracket-compliance-and-skipped-stages)
|
||||
- [Build options: owned-only and prefer-owned](#build-options-owned-only-and-prefer-owned)
|
||||
- [Visual summaries](#visual-summaries)
|
||||
- [Combos & synergies](#combos--synergies)
|
||||
- [Owned library page](#owned-library-page)
|
||||
- [Finished decks workspace](#finished-decks-workspace)
|
||||
- [Keyboard shortcuts](#keyboard-shortcuts)
|
||||
- [Virtualization, tagging, and performance](#virtualization-tagging-and-performance)
|
||||
- [Diagnostics and logs](#diagnostics-and-logs)
|
||||
|
||||
---
|
||||
|
||||
## Unified New Deck modal
|
||||
The first three steps of deckbuilding live inside a single modal:
|
||||
|
||||
1. **Search for a commander** – autocomplete prioritizes color identity matches; press Enter to grab the top result.
|
||||
2. **Pick primary/secondary/tertiary themes** – the modal displays your selections in order so you can revisit them quickly.
|
||||
3. **Choose a bracket** – labels such as “Bracket 3: Upgraded” clarify power bands. Bracket 3 is the default tier for new builds.
|
||||
|
||||
Optional inputs:
|
||||
- **Deck name** becomes the export filename stem and is reused in Finished Decks banners.
|
||||
- **Combo auto-complete** and other preferences persist between runs.
|
||||
|
||||
Once you submit, the modal closes and the build starts immediately—no extra confirmation screen.
|
||||
|
||||
## Stage 5 tools: lock, replace, compare, permalinks
|
||||
Stage 5 is the iterative workspace for tuning the deck:
|
||||
|
||||
- **Lock** a card by clicking the padlock or the card artwork. Locked cards persist across rerolls and show a “Last action” chip for quick confirmation.
|
||||
- **Replace** opens the Alternatives drawer. Filters include Owned-only, role alignment, and bracket compliance. The system skips commanders, locked cards, just-added cards, and anything already in the list.
|
||||
- **Permalink** buttons appear in Stage 5 and Finished Decks. Share a build (commander, themes, bracket, ideals, flags) or restore one by pasting a permalink back into the app.
|
||||
- **Compare** mode lives in Finished Decks. Pick two builds (quick actions select the latest pair) and triage changes via Changed-only, Copy summary, or download the diff as TXT.
|
||||
|
||||
## Multi-copy archetype packages
|
||||
When a commander + theme combination suggests a multi-copy strategy (e.g., Persistent Petitioners, Shadowborn Apostles), the UI offers an optional package:
|
||||
|
||||
- Choose the desired quantity (bounded by printed limits) and optionally add **Thrumming Stone** when it synergizes.
|
||||
- Packages are inserted before other stages so target counts adjust appropriately.
|
||||
- A safety clamp trims overflow to keep the deck at 100 cards; the stage displays a “Clamped N” indicator if it triggers.
|
||||
- You can dismiss the modal, and we won’t re-prompt unless your selections change.
|
||||
|
||||
## Bracket compliance and skipped stages
|
||||
- Bracket policy enforcement prunes disallowed categories before stage execution. Violations block reruns until you resolve them.
|
||||
- Enforcement options: keep the panel collapsed when compliant, auto-open with a colored status chip (green/amber/red) when action is needed.
|
||||
- Enable auto-enforcement by setting `WEB_AUTO_ENFORCE=1`.
|
||||
- Toggle **Show skipped stages** to surface steps that added zero cards, making it easier to review the full pipeline.
|
||||
|
||||
## Build options: owned-only and prefer-owned
|
||||
The modal includes toggles for **Use only owned cards** and **Prefer owned cards**:
|
||||
|
||||
- Owned-only builds pull strictly from the inventory in `owned_cards/` (commander exempt).
|
||||
- Prefer-owned bumps owned cards slightly in the scoring pipeline but still allows unowned all-stars when necessary.
|
||||
- Both modes respect the Owned Library filters and show Owned badges in the exported CSV (including the `Owned` column when you disable the mode).
|
||||
|
||||
## Visual summaries
|
||||
Stage 5 displays multiple data visualizations that cross-link to the card list:
|
||||
|
||||
- **Mana curve** – hover a bar to highlight matching cards in list and thumbnail views.
|
||||
- **Color requirements vs. sources** – pips show requirements; sources include non-land producers and an optional `C` (colorless) toggle.
|
||||
- **Tooltips** – each tooltip lists contributing cards and offers a copy-to-clipboard action.
|
||||
- Visual polish includes lazy-loaded thumbnails, blur-up transitions, and accessibility tweaks that respect `prefers-reduced-motion`.
|
||||
|
||||
## Combos & synergies
|
||||
The builder detects curated two-card combos and synergy pairs in the final deck:
|
||||
|
||||
- Chips display badges such as “cheap” or “setup” with hover previews for each card and a split preview when hovering the entire row.
|
||||
- Enable **Auto-complete combos** to add missing partners before theme filling. Configure target count, balance (early/late/mix), and preference weighting.
|
||||
- Color identity restrictions keep the algorithm from suggesting off-color partners.
|
||||
|
||||
## Owned library page
|
||||
Open the Owned tile to manage uploaded inventories:
|
||||
|
||||
- Upload `.txt` or `.csv` files with one card per line. The app enriches and deduplicates entries on ingestion.
|
||||
- The page includes sortable columns, exact color-identity filters (including four-color combos), and an export button.
|
||||
- Large collections benefit from virtualization when `WEB_VIRTUALIZE=1`.
|
||||
|
||||
## Finished decks workspace
|
||||
- Browse historical builds with filterable theme chips.
|
||||
- Each deck offers Download TXT, Copy summary, Open permalink, and Compare actions.
|
||||
- Locks, replace history, and compliance metadata are stored per deck and surface alongside the exports.
|
||||
|
||||
## Keyboard shortcuts
|
||||
- **Enter** selects the first commander suggestion while searching.
|
||||
- Inside Stage 5 lists: **L** locks/unlocks the focused card, **R** opens the Replace drawer, and **C** copies the permalink.
|
||||
- Browser autofill is disabled in the modal to keep searches clean.
|
||||
|
||||
## Virtualization, tagging, and performance
|
||||
- `WEB_TAG_PARALLEL=1` with `WEB_TAG_WORKERS=4` (compose default) speeds up initial data preparation. The UI falls back to sequential tagging if workers fail to start.
|
||||
- `WEB_VIRTUALIZE=1` enables virtualized grids in Stage 5 and the Owned library, smoothing large decks or libraries.
|
||||
- Diagnostics overlays: enable `SHOW_DIAGNOSTICS=1`, then press **v** inside a virtualized grid to inspect render ranges, row counts, and paint timings.
|
||||
|
||||
## Diagnostics and logs
|
||||
- `SHOW_DIAGNOSTICS=1` unlocks the `/diagnostics` page with system summaries (`/status/sys`), feature flags, and per-request `X-Request-ID` headers.
|
||||
- Supplemental theme telemetry lives at `/status/theme_metrics` (enabled with `ENABLE_CUSTOM_THEMES=1`); the diagnostics page renders commander themes, user-supplied themes, merged totals, and unresolved counts using the `userThemes`/`themeCatalogVersion` metadata exported from builds.
|
||||
- `SHOW_LOGS=1` turns on the `/logs` viewer with level & keyword filters, auto-refresh, and copy-to-clipboard.
|
||||
- Health probes live at `/healthz` and return `{status, version, uptime_seconds}` for integration with uptime monitors.
|
||||
Loading…
Add table
Add a link
Reference in a new issue