Mode deckbuilding
Mode deckbuilding
Dernière mise à jour : 2026-05-10
Depuis 2026-04-24 (Axe 2 Phase 1), un 4e intent 'deckbuilding' s'ajoute à 'rules' | 'synergy' | 'meta'. Il déclenche un pipeline dédié pour produire des decklists structurées exécutables (60 cartes MTG, 40+12+3 Riftbound, 60+sideboard FAB) là où le RAG classique produisait de la prose d'analyse.
Flux (src/services/rag/deckbuilding/)
1. Classification (classify.ts)
Haiku retourne 'deckbuilding' quand la question exige une liste exhaustive avec un nombre de cartes précis ("decklist complète", "40 + 12 runes", "avec sideboard").
À distinguer de synergy qui reste une discussion d'archétype en prose.
Ordre de priorité : deckbuilding > meta > synergy > rules.
2. Dispatch (answer.ts)
Early-return vers askDeckbuilding() juste après résolution de l'intent. Le retrieval standard est jeté, askDeckbuilding relance son propre retrieval avec intent='synergy' forcé.
3. Spec Haiku (deckbuilding/spec.ts)
Un appel Haiku produit un DeckSpec (Zod) structuré :
- format
- tailles (mainboard, sideboard, runes, battlefields, equipment)
- max copies (généralement 4 MTG, 3 Riftbound, etc.)
- rôles cibles (
creatures,spells,lands,equipment…) - anchor cards (cartes obligatoires)
Fallback defaults par jeu si Haiku renvoie un JSON invalide :
- MTG Standard :
60 + 15, max 4 - Riftbound :
40 + 0 + 3 + 12r + 3bf - FAB CC :
60 + 0, max 3
4. Anchor cards
Les fresh + sticky mentions (@-cartes de l'Axe 1) deviennent obligatoires dans la decklist. Le prompt Opus a une règle stricte « tu DOIS inclure ces cartes ». Log warning serveur si une anchor est absente de la réponse finale.
5. Retrieval synergy
retrieveChunks() est appelé avec intent='synergy' → déclenche l'expansion mécanique (retrieve/synergy-expansion.ts). retrieveChunks accepte 'deckbuilding' mais le mappe vers 'synergy' en interne (fallback safe).
6. Prompt Opus spécialisé (prompt-deckbuilding.ts)
DECKBUILDING_SYSTEM_PROMPT impose :
- total exact par section
- max copies non-basiques (basic lands FR/EN whitelistés)
- anchor cards obligatoires
- pool strict (uniquement cartes du contexte)
- format markdown par rôles :
### Créatures (24)+4× [[card:Nom]]
7. userPrompt assemblage
Ordre des blocs :
SPEC DU DECK(JSON Haiku)CARTES OBLIGATOIRES (ANCHORS)(anchors fresh + sticky)CARTES CITÉES PAR LE JOUEUR (ce tour)(full)CARTES ÉVOQUÉES DANS LA CONVERSATION(sticky abrégées)DECKLISTS DE TOURNOI(mainboard + sideboard complets, jusqu'à 5)POOL DE CARTES ÉLIGIBLES(organisé par rôle, cap 30 par rôle)CARTES CANDIDATES(chunks[CARD]+[META], pas[BASE]/[EXT])
8. Génération Opus
promptStream(DECKBUILDING_SYSTEM_PROMPT, userPrompt, 'opus') streamé. Post-processing : autoWrapCardMentions + buildWrapAliases + enrichissement extraCards.
9. Pool exhaustif + decklists d'inspiration (Phase 2, 2026-04-24)
fetchEligibleCards()(deckbuilding/pool.ts) scroll Qdrant avec filtre structurel :- MTG :
card_mtg_legal_formats+ post-filtrecard_mtg_color_identity ⊆ spec.colors - FAB :
card_legal_heroes - Riftbound : sans filtre Qdrant (collection mono-format) + post-filtre
card_domains ⊆ spec.domains
- MTG :
fetchInspirationDecklists(): hybrid search (dense+sparse) surmeta_type='tournament_deck'filtré parmeta_format— jusqu'à 5 decklists similaires (infra : MTGTop8 pour MTG, RiftboundStats pour Riftbound, fabtcg.com pour FAB)selectRoleCandidates(): pré-filtre chaque rôle de la spec à cap 30 par rôle, priorité aux cartes déjà vues dans les decklists d'inspiration- TM / Ark Nova : pas de champs structurels → retombent silencieusement sur Phase 1 (retrieval synergy seul)
scrollAllPoints()accepteopts.filteretopts.withVector(défaut true — Phase 2 passefalsepour économiser ~120 MB sur MTG 30k cartes)
10. Validation structurelle + retry auto (Phase 3, 2026-04-24)
parseDeckResponse(): extrait les cartes par section (main / sideboard / runes / battlefields) via regex stricte avec×/x/Xobligatoire — les lignes de prose ne matchent pasvalidateDeck():- Total exact par section
- Max copies non-basiques (basic lands whitelist FR/EN : Plains/Island/Swamp/Mountain/Forest/Wastes + Plaine/Île/Marais/Montagne/Forêt)
- Anchor cards présentes (≥1 copie)
- Cartes inconnues du catalogue → warning non bloquant
- Si validation échoue :
formatRetryPrompt()construit nouveau userPrompt listant les issues + contraintes strictes - Opus relancé jusqu'à 2 retries (3 tentatives max)
- Pendant retry : token séparateur visible streamé pour transparence —
done.fullAnswerécrase le content côté frontend, l'utilisateur final voit uniquement la version corrigée - Si après 3 tentatives la decklist reste invalide : on garde la dernière + warning log serveur (pas d'échec total)
11. Frontend
Aucun changement. Le rendu markdown gère titres + listes + Nx [[card:X]] (texte standard). CardZoomModal fonctionne automatiquement.
Hors scope Phases 1/2/3
- Pas de composant
<DeckListView> - Pas d'export
.decni bouton Copier - Pas de badge de validation côté frontend (verdict logué serveur, pas exposé via
done) - Pas de support TM / Ark Nova (pas d'équivalent format/archétype dans leurs données)
Helpers exportés
autoWrapCardMentions, buildWrapAliases, renderFullCard, renderShortCard sont exportés depuis answer.ts pour réutilisation par deckbuilding/ask.ts.
No comments to display
No comments to display