mtg_python_deckbuilder/docs/theme_editorial_guide.md
mwisnowski 1ebc2fcb3c
Some checks are pending
CI / build (push) Waiting to run
Editorial Lint / lint-editorial (push) Waiting to run
feat: add theme editorial quality system with scoring, linting, and comprehensive documentation (#54)
2026-03-19 10:06:29 -07:00

13 KiB

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):

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):

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:

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:

# 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
  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:

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+)

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

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

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:

popularity_bucket: Very Common
popularity_pinned: true

Common Pitfalls

Pitfall 1: "Good Cards" Aren't Always Theme Cards

Bad:

display_name: Enchantress
example_cards:
  - Rhystic Study  # Good card, but not enchantress-specific
  - Sol Ring       # Generic ramp
  - Swords to Plowshares  # Generic removal

Good:

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):

# 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):

# 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:

# 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