# Theme Editorial Workflow Guide **Version**: 1.0.0 **Last Updated**: March 18, 2026 **Audience**: Contributors, maintainers, theme curators ## Overview This guide documents the theme editorial quality system introduced in Roadmap 12 (M1-M4). It explains how theme quality is measured, how to curate high-quality themes, and how to use the linter to maintain catalog standards. ## Quality Scoring System ### Scoring Components Theme editorial quality is measured using an **Enhanced Quality Score** (0.0-1.0 scale) with four weighted components: | Component | Weight | Description | |-----------|--------|-------------| | **Card Count** | 30 points | Number of example cards (target: 8+) | | **Uniqueness** | 40 points | Ratio of cards appearing in <25% of themes | | **Description** | 20 points | Manual (20) > Rule-based (10) > Generic (0) | | **Curation** | 10 points | Presence of curated synergies | **Total**: 100 points → normalized to 0.0-1.0 scale ### Quality Tiers Themes are classified into four quality tiers based on their score: | Tier | Score Range | Description | Priority | |------|-------------|-------------|----------| | **Excellent** | ≥0.75 | 8+ unique cards, manual description, well-curated | ✅ Maintain | | **Good** | 0.60-0.74 | Strong card selection, rule-based description | ✅ Monitor | | **Fair** | 0.40-0.59 | Adequate cards, may have some generic cards or description | ⚠️ Improve | | **Poor** | <0.40 | Few cards, generic description, high duplication | 🔴 Urgent | ### Uniqueness vs Duplication - **Uniqueness Ratio**: Fraction of example cards appearing in <25% of themes (higher is better) - **Duplication Ratio**: Fraction of example cards appearing in >40% of themes (lower is better) **Example**: - A theme with `["Sol Ring", "Command Tower", "Unique Card A", "Unique Card B"]` might have: - Uniqueness: 0.50 (2/4 cards are unique) - Duplication: 0.50 (2/4 cards are generic staples) ## Curating High-Quality Themes ### Best Practices for Example Cards #### DO ✅ - **Use 8+ example cards** - Maximizes card count score (30 points) - **Select unique, theme-specific cards** - Boosts uniqueness score (40 points) - **Avoid generic staples** - Focus on cards that actually exemplify the theme - **Include archetype-specific cards** - Not just "good cards in these colors" - **Prioritize cards that demonstrate the strategy** - Help players understand the theme #### DON'T ❌ - **Include generic ramp** - `Sol Ring`, `Arcane Signet`, `Commander's Sphere` - **Include generic card draw** - `Rhystic Study`, `Esper Sentinel` (unless theme-relevant) - **Include generic removal** - `Swords to Plowshares`, `Cyclonic Rift` (unless theme-relevant) - **Use <5 example cards** - Severely impacts card count score - **Copy example cards from similar themes** - Reduces uniqueness, increases duplication #### Example Comparison **Poor Quality** (Score: 0.35, Tier: Poor): ```yaml display_name: Voltron Auras example_cards: - Sol Ring - Lightning Greaves - Swiftfoot Boots - Sword of Feast and Famine description_source: generic ``` *Issues*: Generic cards, only 4 cards, generic description **Excellent Quality** (Score: 0.82, Tier: Excellent): ```yaml display_name: Voltron Auras example_cards: - All That Glitters - Ethereal Armor - Ancestral Mask - Bess, Soul Nourisher - Sigil of the Empty Throne - Mesa Enchantress - Three Dreams - Spirit Mantle description_source: manual description: "Enchants a single creature with multiple Auras to create a powerful, evasive threat while drawing cards and generating value from enchantress effects." popularity_pinned: false ``` *Strengths*: 8 unique aura-specific cards, manual description, clear strategy ### Description Quality #### Description Sources - **`manual`**: Hand-written by a curator (20 points) - Clear, concise, strategic explanation - Explains *how* the theme wins, not just what it does - Example: "Reanimates high-cost creatures from the graveyard early via discard/mill effects, bypassing mana costs to establish board dominance." - **`rule`**: Generated from external heuristics (10 points) - Template-based with theme-specific keywords - Example: "Leverages the graveyard for recursion and value." - **`generic`**: Fallback template (0 points) - Minimal information, no strategic insight - Example: "A theme focused on [theme name] strategies." - ⚠️ **Should be upgraded to rule or manual** #### Writing Manual Descriptions Good manual descriptions answer: 1. **What** does the theme do? (mechanics) 2. **How** does it win? (strategy) 3. **Why** is it effective? (synergies/payoffs) **Template**: `[Action] [Key Cards/Mechanics] to [Strategic Goal] via [Synergies/Payoffs].` **Example**: - Theme: Aristocrats - Description: "Sacrifices creatures for value via death triggers, then recurs them to repeat the process while generating tokens, card advantage, and direct damage." ### Popularity Pinning Use `popularity_pinned: true` to prevent automatic popularity_bucket updates when you've manually curated the bucket: ```yaml popularity_bucket: Common popularity_pinned: true # Prevents overwriting during rebuilds ``` **When to pin**: - Manual research shows different bucket than analytics - Theme popularity has shifted but analytics lag - Theme is intentionally promoted/demoted for editorial reasons **When NOT to pin**: - Default/initial backfill state - No strong reason to override analytics ## Using the Linter ### Running the Linter The linter is integrated into `validate_theme_catalog.py`: ```bash # Basic quality checks (M1) python code/scripts/validate_theme_catalog.py --check-quality # Full linter with M4 rules python code/scripts/validate_theme_catalog.py --check-quality --lint # Customize thresholds python code/scripts/validate_theme_catalog.py --lint \ --lint-duplication-threshold 0.4 \ --lint-quality-threshold 0.5 ``` ### Linter Rules | Rule | Severity | Threshold | Description | |------|----------|-----------|-------------| | **Missing description_source** | ERROR | N/A | Theme has description but no source metadata | | **Generic description** | WARNING | N/A | Description_source is "generic" | | **Missing popularity_pinned** | ERROR | N/A | popularity_pinned=True but no bucket set | | **High duplication** | WARNING | >0.5 | >50% of example cards are generic staples | | **Low quality score** | WARNING | <0.5 | Quality score below threshold | ### Interpreting Linter Output #### Example Output ``` VALIDATION FAILED: - [QUALITY] voltron-auras.yml has generic description_source - consider upgrading to rule-based or manual - [LINT-WARNING] voltron-auras.yml has high duplication ratio (0.62 > 0.5). Generic cards: Sol Ring, Lightning Greaves, Swiftfoot Boots - [LINT-WARNING] voltron-auras.yml has low quality score (0.38 < 0.5, tier=Poor). Suggestions: Add more example cards (target: 8+); Upgrade to manual or rule-based description; Replace generic staples with unique cards ``` #### Recommended Actions 1. **High Duplication**: - Review listed generic cards - Replace with theme-specific alternatives - Example: Replace `Sol Ring` with `All That Glitters` for Voltron Auras 2. **Low Quality Score**: - Follow suggestions in order: cards first, then description, then deduplicate - **Add more cards** (fastest improvement) - **Upgrade description** (if you understand the theme) - **Replace generic cards** (if cards are already adequate) 3. **Generic Description**: - Write a manual description following the template - Or wait for rule-based generation improvements ## Workflow Examples ### Example 1: Improving a Fair-Quality Theme **Starting Point**: ```yaml display_name: Graveyard Value example_cards: - Command Tower - Sol Ring - Eternal Witness - Greenwarden of Murasa - Reanimate description_source: generic description: "A theme focused on graveyard strategies." ``` **Score**: 0.45 (Fair) **Step 1: Add Example Cards** (target: 8+) ```yaml example_cards: - Command Tower # Keep for now - Sol Ring # Keep for now - Eternal Witness - Greenwarden of Murasa - Reanimate - Living Death # Added - Victimize # Added - Animate Dead # Added - Muldrotha, the Gravetide # Added ``` **Score**: 0.53 (Fair → Good threshold) **Step 2: Upgrade Description** ```yaml description_source: manual description: "Fills the graveyard via self-mill and discard, then recurs high-value creatures and spells for repeated use, generating card advantage and overwhelming opponents with recursive threats." ``` **Score**: 0.63 (Good) **Step 3: Replace Generic Cards** ```yaml example_cards: - World Shaper # Replace Command Tower - Crucible of Worlds # Replace Sol Ring - Eternal Witness - Greenwarden of Murasa - Reanimate - Living Death - Victimize - Animate Dead - Muldrotha, the Gravetide ``` **Score**: 0.78 (Excellent!) ### Example 2: Maintaining Excellent Quality **Theme**: Aristocrats **Score**: 0.82 (Excellent) **Maintenance Checklist**: - ✅ 10 unique example cards - ✅ Manual description matches current strategy - ✅ Popularity bucket accurate (review quarterly) - ✅ No generic staples in example list - ✅ Synergies reflect current meta cards **Action**: Pin popularity if manually verified: ```yaml popularity_bucket: Very Common popularity_pinned: true ``` ## Common Pitfalls ### ❌ Pitfall 1: "Good Cards" Aren't Always Theme Cards **Bad**: ```yaml display_name: Enchantress example_cards: - Rhystic Study # Good card, but not enchantress-specific - Sol Ring # Generic ramp - Swords to Plowshares # Generic removal ``` **Good**: ```yaml display_name: Enchantress example_cards: - Enchantress's Presence - Setessan Champion - Mesa Enchantress - Argothian Enchantress ``` ### ❌ Pitfall 2: Copying Example Cards Themes with high overlap hurt the catalog's uniqueness metrics: **Bad** (Voltron + Equipment themes share 6/8 cards): ```yaml # voltron-equipment.yml example_cards: [Sword of Fire and Ice, Batterskull, Colossus Hammer, Lightning Greaves, ...] # voltron-auras.yml example_cards: [Sword of Fire and Ice, Batterskull, Colossus Hammer, Lightning Greaves, ...] ``` **Good** (Distinct card pools): ```yaml # voltron-equipment.yml example_cards: [Sword of Fire and Ice, Batterskull, Colossus Hammer, Sigarda's Aid, ...] # voltron-auras.yml example_cards: [All That Glitters, Ethereal Armor, Ancestral Mask, Estrid, the Masked, ...] ``` ### ❌ Pitfall 3: Ignoring Linter Warnings Linter warnings accumulate over time. Address them during regular maintenance: **Quarterly Workflow**: 1. Run `--lint --lint-quality-threshold 0.4` 2. Identify Poor/Fair themes (<0.5 score) 3. Improve 5-10 themes per session 4. Commit improvements incrementally ## Quality Metrics Dashboard Track catalog health with these statistics: ```bash # Generate quality report (future tool) python code/scripts/generate_quality_report.py # Expected Output: # Total Themes: 740 # Excellent: 220 (30%) # Good: 300 (40%) # Fair: 180 (24%) # Poor: 40 ( 6%) # Average Uniqueness: 0.62 # Average Duplication: 0.28 ``` **Health Benchmarks**: - **Excellent + Good**: >60% - **Poor**: <10% - **Average Uniqueness**: >0.50 - **Average Duplication**: <0.35 ## Resources - **Heuristics Config**: `config/themes/editorial_heuristics.yml` - **Validation Script**: `code/scripts/validate_theme_catalog.py` - **Backfill Script**: `code/scripts/backfill_editorial_fields.py` - **Service Implementation**: `code/web/services/theme_editorial_service.py` - **Tests**: `code/tests/test_theme_editorial_service.py`, `code/tests/test_theme_linter.py` ## FAQ ### Q: What's the minimum acceptable quality score? **A**: Fair (0.40) is acceptable for niche themes. Aim for Good (0.60+) for common themes. ### Q: Should I remove all generic staples? **A**: Not necessarily. If a card like `Sol Ring` is *genuinely* theme-relevant (e.g., "Colorless Matters"), include it. But avoid generic ramp/removal that appears in 50%+ of decks. ### Q: How do I handle themes with few unique cards? **A**: Focus on description quality (manual) and curate the best available examples. Some themes (e.g., "Mulligan Matters") inherently have limited card pools. ### Q: Can I batch-fix themes? **A**: Yes, but commit incrementally and test after each batch to avoid introducing errors. Use `--lint` to validate before committing. ### Q: What if the linter disagrees with my curation? **A**: Linter warnings are suggestions, not hard requirements. Use judgment for niche/experimental themes, but document reasoning in the theme's `notes` field. --- **Maintained by**: MTG Python Deckbuilder Contributors **Feedback**: Open an issue on GitHub with `[editorial]` prefix