A.1 seed Minchiate Fiorentine 1860-1890 deck (97 cards) — TDD. Sprint A.1 follow-up to [[project-image-based-deck-face-rendering]]. Creates the actual Minchiate Fiorentine DeckVariant (separate from the renamed-from-fiorentine-minchiate RWS Tarot now living at tarot-rider-waite-smith per A.0). Slug minchiate-fiorentine-1860-1890 matches the asset dir committed in 0add163 (98 PNGs at src/apps/epic/static/apps/epic/images/cards-faces/minchiate-fiorentine-1860-1890/); Sprint A.2's image_filename property will use deck.slug to point at those images. Schema fields set: family='italian' (drives display + filename slug mapping per [[reference-card-image-naming-convention]] — BRANDS→batons, CROWNS→coins, GRAILS→cups, BLADES→swords), has_card_images=True (first deck w. images shipped), is_polarized=False (Earthman remains the only polarized deck), is_default=False (Earthman is default), card_count=97. 97 TarotCard rows seeded: 41 trumps (Il Matto at rank 0 per the unnumbered-Fool-gets-sortable-position convention from [[reference-card-image-naming-convention]]; then 40 numbered 1-40) + 56 minors (4 suits × 14 cards = pip 1-10 + page=11 + knight=12 + queen=13 + king=14 per the v2 convention's number-prefixed-courts decision). Trump names are Italian (Papa Uno / Papa Due / La Temperanza / La Forza / La Giustizia / La Ruota della Fortuna / Il Carro / Il Gobbo / L'Impiccato / La Morte / Il Diavolo / La Casa del Diavolo / La Speranza / La Prudenza / La Fede / La Carita / Il Fuoco / L'Acqua / La Terra / L'Aria + 12 zodiac signs + La Stella / La Luna / Il Sole / Il Mondo / Le Trombe). Card-suit canonical enum stays BRANDS/CROWNS/GRAILS/BLADES per A.0's lock; minor card NAMES use Italian-family display vocab ("Page of Batons" not "Page of Brands") since names are the user-facing label whereas suit is the structural identity. 16 trumps carry a correspondence field pointing to their RWS Tarot equivalent (Il Matto→The Fool, Il Carro→The Chariot, Il Gobbo→The Hermit, L'Impiccato→The Hanged Man, La Morte→Death, Il Diavolo→The Devil, La Casa del Diavolo→The Tower, La Temperanza→Temperance, La Forza→Strength, La Giustizia→Justice, La Ruota della Fortuna→Wheel of Fortune, La Stella→The Star, La Luna→The Moon, Il Sole→The Sun, Il Mondo→The World, Le Trombe→Judgement); the 25 Minchiate-only trumps (5 popes + 4 theological/cardinal virtues + 4 elements + 12 zodiac) have no RWS parallel → empty correspondence. keywords_upright / keywords_reversed intentionally left empty []: those are interpretive content the user owns; admin form (Sprint B) will enrich via UI rather than have them committed as code in a migration. Five trumps in the v2 filename convention have elided-apostrophe slugs restored (l-impiccato, l-acqua, l-aria, l-ariete, l-acquario); DB slug field matches (no apostrophe, but with the leading l- prefix). 17 new ITs in MinchiateFiorentine1860SeedTest cover the deck attributes (name + family + has_card_images + is_polarized + card_count) + total row count (97) + arcana breakdown (41 trumps + 56 minors + 0 middle) + specific cards (Il Matto at rank 0 + Il Gobbo at rank 11 w. correspondence "The Hermit" + Le Trombe at rank 40 + 5 popes are MAJOR ranks 1-5 + Page of Batons + King of Coins) + canonical-suit-only check (no WANDS/CUPS/SWORDS/PENTACLES in DB) + court rank range (11-14 per suit). Tests: 17 new green; 1272/1272 IT+UT total green (64s; +17 from A.0's 1255). Out of scope: A.2 adds the TarotCard.image_filename + display_suit_name properties consuming deck.family for per-family translation; A.3 wires my_sign.html's first render branch

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-24 23:32:19 -04:00
parent f107522b20
commit a4ac25605d
2 changed files with 249 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
"""Sprint A.1 — seed the Minchiate Fiorentine (1860-1890) deck.
97 cards: 40 numbered trumps + Il Matto (rank 0, unnumbered Fool) + 56 minors
(4 suits × 14 cards: pip 1-10, page 11, knight 12, queen 13, king 14).
Names are stored in Italian-display form (Italian for trumps; English-rank +
Italian-suit hybrid for minors — "Page of Batons", "King of Coins"). The
canonical SUIT enum stays Earthman vocab (BRANDS/GRAILS/BLADES/CROWNS) per the
2026-05-25 lock; Sprint A.2's `display_suit_name` property handles the
canonical→display translation.
Correspondences cite the RWS Tarot equivalent where one exists (16 trumps map
cleanly; the 5 popes, 4 theological+cardinal virtues, 4 elements, and 12
zodiac trumps don't have RWS parallels — left blank).
Keywords intentionally left empty for now; admin form (Sprint B) will enrich.
"""
from django.db import migrations
TRUMPS = [
# (number, name, slug, correspondence)
(0, "Il Matto", "il-matto", "The Fool"),
(1, "Papa Uno", "papa-uno", ""),
(2, "Papa Due", "papa-due", ""),
(3, "Papa Tre", "papa-tre", ""),
(4, "Papa Quattro", "papa-quattro", ""),
(5, "Papa Cinque", "papa-cinque", ""),
(6, "La Temperanza", "la-temperanza", "Temperance"),
(7, "La Forza", "la-forza", "Strength"),
(8, "La Giustizia", "la-giustizia", "Justice"),
(9, "La Ruota della Fortuna", "la-ruota-della-fortuna", "Wheel of Fortune"),
(10, "Il Carro", "il-carro", "The Chariot"),
(11, "Il Gobbo", "il-gobbo", "The Hermit"),
(12, "L'Impiccato", "l-impiccato", "The Hanged Man"),
(13, "La Morte", "la-morte", "Death"),
(14, "Il Diavolo", "il-diavolo", "The Devil"),
(15, "La Casa del Diavolo", "la-casa-del-diavolo", "The Tower"),
(16, "La Speranza", "la-speranza", ""), # Hope — theological virtue
(17, "La Prudenza", "la-prudenza", ""), # Prudence — cardinal virtue
(18, "La Fede", "la-fede", ""), # Faith
(19, "La Carita", "la-carita", ""), # Charity
(20, "Il Fuoco", "il-fuoco", ""), # Fire — element
(21, "L'Acqua", "l-acqua", ""), # Water
(22, "La Terra", "la-terra", ""), # Earth
(23, "L'Aria", "l-aria", ""), # Air
(24, "La Bilancia", "la-bilancia", ""), # Libra — zodiac
(25, "La Vergine", "la-vergine", ""), # Virgo
(26, "Il Scorpione", "il-scorpione", ""), # Scorpio
(27, "L'Ariete", "l-ariete", ""), # Aries
(28, "Il Capricorno", "il-capricorno", ""), # Capricorn
(29, "Il Sagittario", "il-sagittario", ""), # Sagittarius
(30, "Il Cancro", "il-cancro", ""), # Cancer
(31, "I Pesci", "i-pesci", ""), # Pisces
(32, "L'Acquario", "l-acquario", ""), # Aquarius
(33, "Il Leone", "il-leone", ""), # Leo
(34, "Il Toro", "il-toro", ""), # Taurus
(35, "I Gemelli", "i-gemelli", ""), # Gemini
(36, "La Stella", "la-stella", "The Star"),
(37, "La Luna", "la-luna", "The Moon"),
(38, "Il Sole", "il-sole", "The Sun"),
(39, "Il Mondo", "il-mondo", "The World"),
(40, "Le Trombe", "le-trombe", "Judgement"),
]
# Canonical Earthman suit enum → Italian-family display name (also used as slug stem).
SUIT_DISPLAY = {
"BRANDS": "Batons",
"GRAILS": "Cups",
"BLADES": "Swords",
"CROWNS": "Coins",
}
PIP_NAMES = {1: "Ace", 2: "Two", 3: "Three", 4: "Four", 5: "Five",
6: "Six", 7: "Seven", 8: "Eight", 9: "Nine", 10: "Ten"}
COURT_NAMES = {11: "Page", 12: "Knight", 13: "Queen", 14: "King"}
def forward(apps, schema_editor):
DeckVariant = apps.get_model("epic", "DeckVariant")
TarotCard = apps.get_model("epic", "TarotCard")
deck = DeckVariant.objects.create(
name="Minchiate Fiorentine (18601890)",
slug="minchiate-fiorentine-1860-1890",
card_count=97,
is_default=False,
family="italian",
has_card_images=True,
is_polarized=False,
description=(
"97-card Minchiate Fiorentine deck from the Baragioli-era 1860-1890 "
"Florence lithograph series. Five popes, four theological/cardinal "
"virtues, four elements, twelve zodiac signs, plus the standard "
"trump iconography and Il Matto."
),
)
# 41 trumps (incl. Il Matto at rank 0).
for number, name, slug, correspondence in TRUMPS:
TarotCard.objects.create(
deck_variant=deck,
arcana="MAJOR",
suit=None,
number=number,
name=name,
slug=slug,
correspondence=correspondence,
)
# 56 minors: 4 suits × 14 cards.
for canonical_suit, display in SUIT_DISPLAY.items():
for n in range(1, 15):
rank_word = PIP_NAMES.get(n) or COURT_NAMES[n]
TarotCard.objects.create(
deck_variant=deck,
arcana="MINOR",
suit=canonical_suit,
number=n,
name=f"{rank_word} of {display}",
slug=f"{rank_word.lower()}-of-{display.lower()}",
)
def backward(apps, schema_editor):
DeckVariant = apps.get_model("epic", "DeckVariant")
TarotCard = apps.get_model("epic", "TarotCard")
deck = DeckVariant.objects.filter(slug="minchiate-fiorentine-1860-1890").first()
if deck:
TarotCard.objects.filter(deck_variant=deck).delete()
deck.delete()
class Migration(migrations.Migration):
dependencies = [
("epic", "0012_rws_rename_and_suit_revocab"),
]
operations = [migrations.RunPython(forward, backward)]