This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Argumentum is an educational card game about logical fallacies (sophisms). The repository contains:
- A .NET pipeline (
Argumentum.AssetConverter) that transforms CSV data into print-ready PDFs, mind maps, and OWL ontologies - A customized fork of CardPen (HTML card renderer using Mustache/Handlebars templates)
- Source data (CSV files) for fallacies taxonomy, game scenarios, rules, and virtues
- A DNN web platform export (partial, keys excluded)
# Run the full generation pipeline
dotnet run --project "Generation/Converters/Argumentum.AssetConverter/Argumentum.AssetConverter.csproj"
# Run tests (xUnit)
dotnet test "Generation/Converters/Argumentum.AssetConverter.Tests/Argumentum.AssetConverter.Tests.csproj"
# Run visual tests
dotnet test "Generation/Converters/Argumentum.AssetConverter.VisualTests/Argumentum.AssetConverter.VisualTests.csproj"
# Build all projects
dotnet build "Argumentum Converters.sln"The pipeline uses a hierarchical configuration with C# default values:
AssetConverterConfig.cscontains the "factory default" configuration as property initializers- On first run, if
AssetConverterConfig.jsonis missing, it's auto-generated from C# defaults - The JSON file can be edited to override defaults
- Set
SkipConfigFile = trueto always use compiled defaults (ignore JSON)
Key config sections:
Mode: Flags enum controlling which pipeline stages run (WebBasedImageGeneration,QuestPdfGeneration,Mindmapper,PdfAuditor, etc.)DataSets: CSV source definitions with paths and C# entity typesWebBasedGeneratorConfig.CardSets: Card template configurationsCardSetDocuments: PDF assembly definitions
CSV Data → [Harvesting] → PNG Images → [PDF Assembly] → Print-ready PDFs
↓
[MindMapper] → SVG Mind Maps
↓
[OWL Generator] → Ontologies
-
Harvesting (
HarvestManager.cs)- Uses Playwright to automate Chromium
- Loads CardPen, injects data, captures card images
- Outputs
.harvest.jsonfiles (cached)
-
PDF Assembly (
PdfManager.cs,PrintAndPlayDocument.cs)- Uses QuestPDF library
- IMPORTANT: QuestPDF is NOT thread-safe - a global lock serializes PDF generation
- Complex manual layout logic for recto-verso printing
-
Mind Maps (
MindMapCreator)- Generates
.mmfiles (Freemind format) - Converts to SVG via Freeplane external process
- WARNING: SVG post-processing uses fragile heuristics ("disambiguation") dependent on Freeplane's output structure
- Generates
Located in Generation/CardPen/. Key customizations:
- Custom Handlebars helpers:
ifCond,each,markdown - Support for both Mustache and Handlebars modes (
useMustacheflag) - Markdown rendering via marked.js
- Template files are JSON with embedded
mustachekey containing HTML/CSS
Cards/ # Source data (CSV files)
├── Fallacies/ # Fallacy taxonomy + card assets
├── Scenarii/ # Game scenarios
├── Rules/ # Game rules (CSV + Markdown)
└── Memo/ # Memo cards
Generation/
├── CardPen/ # Customized HTML card renderer
│ └── js/main.js # Main CardPen logic
├── Converters/
│ ├── Argumentum.AssetConverter/ # Main pipeline
│ │ ├── Entities/ # CSV entity classes (Fallacy, Scenario, Rule, etc.)
│ │ ├── WebBasedGenerator/ # Harvesting & PDF generation
│ │ │ ├── HarvestManager.cs # Playwright orchestration
│ │ │ ├── PdfManager.cs # PDF assembly
│ │ │ └── Cardpen/ # CardSet configurations
│ │ ├── Mindmapper/ # Mind map generation
│ │ ├── Ontology/ # OWL generation
│ │ └── Tests/ # Validation modules
│ └── Argumentum.AssetConverter.Tests/ # Unit tests (xUnit)
docs/
├── sddd/ # SDDD methodology documentation
└── investigations/ # Debug/archaeology reports
CSV parsing uses CsvHelper. Entity classes in Entities/ have inner ClassMap classes. Common issues:
- Missing
.Optional()on nullable columns causes silent failures - Column name mismatches result in 0 records loaded
- QuestPDF PDF generation has a global
lock- cannot parallelize - Playwright harvesting uses a page pool (
ConcurrentStack<IPage>) Loggeris thread-safe (uses locks)
- SVG disambiguation in mind map generation
- Manual PDF layout calculations in
PrintAndPlayDocument.cs - CardPen Handlebars/Markdown rendering when data contains special characters
Languages: French (default), English, Russian, Portuguese
Localization is handled via LocalizationConfig in the main config:
CardSetLocalizations: Field mappings per languageMindMapLocalization: Mind map field translations
CSV fields use language suffixes: Title, Title_en, Title_ru, Title_pt
Generated files go to:
Generation/Converters/Argumentum.AssetConverter/bin/Debug/net9.0/Target/
├── {lang}/
│ ├── Documents/ # Final PDFs
│ └── Harvest/ # Cached .harvest.json files
└── Images/ # Generated card PNGs
The pipeline worked correctly before May 2025. A series of "vibecodés" commits introduced regressions.
The #1 cause of pipeline failures: If SkipConfigFile = true in AssetConverterConfig.cs (line 31), the JSON config is completely ignored, causing the pipeline to use an incomplete default config.
ALWAYS verify: SkipConfigFile = false
| Package | Version | Notes |
|---|---|---|
| QuestPDF | 2022.12.12 | MIT free license, thread-safe issues above this |
| Magick.NET | 13.5.0 | SVG conversion stability |
| SkiaSharp.NativeAssets.Win32 | 2.88.6 | Required for QuestPDF |
| Microsoft.Playwright | 1.43.0 | Browser automation |
- HarvestManager.cs - Timeout: Restored from 60s to 120s (CardPen needs 90-120s)
- HarvestManager.cs - frame.js: Removed manual injection (CardPen loads it)
- HarvestManager.cs - generateImages(): Added explicit call (no UI click in automation)
- PdfManager.cs - Lock: Global lock on QuestPDF (NOT thread-safe)
- WebBasedGeneratorConfig.cs - CardSet Memo: Reintegrated (critical for Print&Play Tarot)
- PdfManager.cs - Issue #119: Rules cards positioning (lines 43-72) - preserves CardSet order so Rules appear first in TarotCards PDFs
| File | Original Issue | Resolution |
|---|---|---|
Rule.cs |
GetId() returned string.Empty |
Now returns Rules_01, Rules_02 etc. via RowIndex |
RuleClassMap.cs |
print_and_play not mapped |
Mapped with .Optional() to PrintAndPlay property |
ArgumentVirtueClassMap.cs |
Id not mapped |
Uses Pk property mapped to CSV pk column |
CsvBase.cs |
MissingFieldFound = null |
Now logs warnings via Logger.Log() instead of silent |
In WebBasedGeneratorConfig.cs:
UseLocalCardpen = true(use local IIS, not GitHub Pages)LocalCardpenUrl = "http://argumentum.myia.io"(local IIS site)- FallaciesWeb DPI = 400 (not 72)
- Virtues
Enabled = true - Format A0:
NbColumns = 12
Located in docs/investigations/:
2025-10-15-investigation-historique-pipeline-pdf.md- Complete regression history2025-10-21-rapport-archeologie-git-final.md- Git archaeology (conclusion: C# code is intact)2025-12-13-rapport-cloture-mission.md- Final mission report with validation metrics
Located in docs/investigations/scripts/:
2025-10-16-XX-test-*.ps1- Pipeline validation tests2025-10-21-XX-*.ps1- Git archaeology scripts2025-10-23-01-validation-memo-restaure.ps1- Memo CardSet validation
Located in docs/investigations/archeologie-git/:
WebBasedGeneratorConfig_REFERENCE_FUNCTIONAL_*.cs- Known working config (20KB)- 15 historical versions for comparison
- NEVER edit JSON directly - Always modify C# source (single source of truth)
- Regenerate JSON from correct C# code to ensure consistency
AssetConverterConfig.jsonis in.gitignore(generated, not tracked)
| Parameter | Description | Example |
|---|---|---|
rscount |
Nombre de lignes CSV groupées par carte | Memo=200 (1 carte avec toutes les données) |
rsstyle |
Mode de groupement | "bunch", "cycle", "random" |
{{cardIndex}} |
Variable auto-injectée (1-based) | Utilisable pour numérotation de page |
Règle critique: Ne JAMAIS forcer rscount=0 dans le code C# - préserver la valeur du template JSON.
Avec rsstyle="bunch" et rscount >= N:
expectedImageCount = ceil(cardIds.Count / rscount)
Exemple: Memo avec 200 lignes CSV et rscount=200 → génère 1 seule image.
/* TOUJOURS inclure pour éviter problèmes d'affichage des caractères */
-webkit-font-variant-ligatures: no-common-ligatures;
font-variant-ligatures: no-common-ligatures;À éviter: flex-flow: column wrap - cause des débordements de texte. Préférer column nowrap avec gestion overflow.
Configuration Golden Master restaurée:
const options = {
height: height,
width: width,
scale: dpi / 96, // Important pour résolution correcte
cachedFonts: true, // Utilise polices préchargées
imagePlaceholder: "..." // Fallback pour images manquantes
};
// Appeler AVANT génération:
domtoimage.getFontsBefore();Les chemins ../../Cards/... ne fonctionnent pas avec CardPen local (IIS).
Solutions:
- Réécrire en URLs absolues GitHub:
https://raw.githubusercontent.com/ArgumentumGames/Argumentum/master/Cards/... - Ou configurer IIS pour servir
/Cards/depuis le répertoire local
| Symptôme | Cause probable | Solution |
|---|---|---|
Harvest vide (Images: {}) |
Erreur JS dans CardPen | Vérifier console Playwright |
| Harvest vide + Dpi=0 | CsvType manquant dans DataSet | Ajouter CsvType = typeof(Entity) |
| Images blanches/vides | Chemins assets relatifs | Réécrire en URLs absolues |
data:, (empty dataUrl) |
Timeout ou erreur fonts | Augmenter timeout à 120s |
| Mismatch image count | rscount mal calculé | Vérifier formule expectedImageCount |
CRITIQUE: Chaque DataSet doit avoir un CsvType défini dans AssetConverterConfig.cs pour que le harvesting fonctionne.
// ✅ CORRECT - CsvType défini
new DataSetInfo() {
Name = KnownDataSets.Scenarii,
CsvType = typeof(Scenario), // ← OBLIGATOIRE
DebugFilePath = @"..\..\Cards\Scenarii\..."
}
// ❌ INCORRECT - génère harvest vide
new DataSetInfo() {
Name = KnownDataSets.Scenarii,
// CsvType manquant → early return dans HarvestManager ligne ~494
DebugFilePath = @"..\..\Cards\Scenarii\..."
}Pour tenir sur 1 page A0 (841×1189mm):
- HeightMM = 69mm (pas 72mm)
- WidthMM = 69mm
- NbColumns = 12
- Padding = 2mm
Règle: Si le template JSON attend 1 ligne CSV par carte (variables simples comme {{titre}}), ne PAS définir RowsetNb dans la config C#.
// ✅ CORRECT - template avec rscount=1 utilise 1 ligne par carte
FaceCardSetInfo = new CardSetInfo()
{
DataSet = KnownDataSets.Scenarii,
JsonFilePathDebug = @"...\Argumentum_Scenarii_Face_fr.json",
// RowsetNb non défini → utilise rscount du template JSON
}
// ❌ INCORRECT - force 14 lignes par carte mais template attend 1 ligne
FaceCardSetInfo = new CardSetInfo()
{
...
RowsetNb = 14 // Casse le template !
}Symptôme si RowsetNb incorrect: Cartes générées avec contenu vide (seuls éléments statiques visibles).
Règle absolue: NE JAMAIS modifier le contenu CSV avant injection dans CardPen.
// ✅ CORRECT - Golden Master (avril 2024)
cardSetDocumentWrapper.CardSetDocument.csv = csvContent;
// ❌ INCORRECT - Casse le parsing PapaParse
cardSetDocumentWrapper.CardSetDocument.csv = csvContent.Replace("\n", "\\n");Pourquoi: PapaParse gère correctement les newlines dans les cellules CSV entre guillemets. L'échappement transforme les vrais newlines en chaînes littérales "\n", cassant le parsing.
Symptôme: Cartes générées avec contenu vide (seules les icônes statiques visibles).
Chaque famille doit avoir sa classe CSS définie dans le template JSON. Liste complète pour Virtues:
| Classe CSS | Famille | Couleur |
|---|---|---|
argumentsVertueux |
Arguments vertueux (racine) | Gris #555555 |
argumentPertinent |
Argument pertinent | Violet #811da3 |
présentationIntègre |
Présentation intègre | Rose #ff66eb |
exactitudeMathématique |
Exactitude mathématique | Turquoise #08af93 |
raisonnementValide |
Raisonnement valide | Vert #8dc801 |
langageRigoureux |
Langage rigoureux | Bleu #0054a4 |
honnêtetéIntellectuelle |
Honnêteté intellectuelle | Jaune #ffc307 |
débatRespectueux |
Débat respectueux | Rouge #dc0f0a |
Symptôme si classe manquante: Carte avec fond blanc au lieu de la couleur de famille.
P1 - Pipeline multilingue validé en DIMENSIONS uniquement : 79 PDFs générés, 4209 images, dimensions correctes.
| Langue | PDFs | Images | Status |
|---|---|---|---|
| FR (Français) | 18 | 620 | ✅ Golden Master |
| EN (English) | 22 | 1781 | ⚠ Structure OK, contenu FR (voir #216) |
| RU (Русский) | 17 | 1270 | ⚠ Structure OK, contenu FR (voir #216) |
| PT (Português) | 22 | 538 | ⚠ Structure OK, contenu FR (voir #216) |
Issue #119 validée : Rules cards apparaissent en premier dans tous les TarotCards multilingues.
Bug #216 découvert 2026-04-22 + corrigé 2026-04-23 : LocalizationConfig.FrontFieldConversions pour Fallacies référençait des noms de champs (Titre, Definition, Exemple, Contre-Exemple) qui n'existaient PAS dans les templates Mustache (qui utilisent {{text_fr}}, {{desc_fr}}, {{example_fr}}, {{Famille}}, {{Sous-Famille}}, {{Soussousfamille}}). Résultat : template.Replace() ne trouvait rien à remplacer → tous les PDFs EN/RU/PT contenaient du contenu français. Corrigé en restaurant le mapping Golden Master (avril 2024) + ajout de Rules (absent) + tests de régression FallaciesLocalizationTests. Regénération pipeline complète requise pour produire les PDFs réellement multilingues.
| CardSet | Images | PDFs | Status |
|---|---|---|---|
| Fallacies Tarot FR | 177 | ✅ | TarotCards_fr-1/2.pdf |
| FallaciesWeb FR | 176 | ✅ | A0 (99MB), A4 (98MB), Thumbnails |
| Virtues Tarot FR | 113 | ✅ | TarotCards_Virtues_fr-FacesOnly.pdf |
| Scenarii Poker FR | 97 | ✅ | PokerCards_fr-1.pdf (12MB) |
| Rules Tarot FR | 24 | ✅ | Dans TarotCards |
| Memo Tarot FR | 1 | ✅ | Dans TarotCards |
| Print&Play A4 | 34 | ✅ | Poker + Tarot Print&Play |
- 20 FreeMind Batik SVGs generated and committed (4 languages × 5 types)
- FreeMind GUI automation via
SendKeys.SendWait— VALIDATED (commit46d6cd9b) - Issues #127, #128, #129 closed
- OWL ontology with SKOS — committed (PR #161), issue #130 closed
- SDK: Official OpenAI .NET SDK v2.10.0 (PR #210 merged)
- Models:
gpt-4.1,gpt-4.1-mini(all deprecated model constants replaced) - Config:
DatasetUpdater/DatasetUpdaterRootConfig.cs— 7 task configs (allEnabled = false) - Prompts: 29 files in
DatasetUpdater/Resources/ - Function calling: Manual
FunctionToolDef+ JSON schema +BinaryData.FromString() - Virtues CSV has NO multilingual columns — only
_frfields, translation entirely absent - Issue #183 DONE — merged via PR #210
- Module:
GSheetSync/(9 files: CsvDiffEngine, DiffReport, SyncSafetyChecker, Auth, Service, Runner, configs) - Mode flag:
ConverterMode.GSheetSync = 1 << 14(16384) - Safety: 6-layer upload protection (dry-run, diff, thresholds, confirmation, backup, verify)
- 4 spreadsheet configs: Fallacies, Scenarii, Virtues, Rules (all
Enabled = false) - Pending: OAuth credentials for end-to-end testing
- Tests: 77 pass / 0 fail / 1 skip (includes CsvDiffEngine, SyncSafetyChecker, DiffReport, CsvToGrid tests)
- 77 tests pass, 1 skip (Freeplane GUI — requires interactive session)
- Coverage includes: CsvDiffEngine, SyncSafetyChecker, DiffReport, CsvToGrid, MindMapHtmlWrapper, Playwright visual tests
- Issue #204 tracks expansion (target >= 70, now exceeded)
- Issue #212 tracks Playwright visual regression tests for generated PDFs
Valider génération images après corrections CSV/CSSFAITTester génération PDFs (QuestPDF)FAITActiver et tester génération multilingueFAIT (17 Mars 2026)Valider formats: Tarot, Poker, A0, Print&PlayFAITMind Maps + SVGs (Batik)FAIT (6 Avril 2026)#183 — Upgrade SDK traductionFAIT (PR #210 merged, avril 2026)#193 — GSheet ↔ CSV syncFAIT (PR #200 merged, avril 2026)#202 Phase 1 — CSV text micro-fixesFAIT (PR #203 + #213 merged)- Valider DatasetUpdater round-trip avec OpenAI API (3-5 records, Enabled=true)
- #211 — Retraduction complète PT Rules via pipeline (débloqué par #183)
- #212 — Playwright visual regression tests pour PDFs générés
- Virtues i18n — ajouter colonnes _en/_ru/_pt au CSV + traduire
- Scenarii — 77 scénarios manquants EN/RU/PT à traduire
- #134 — GitHub Release
- #133 — Publication OWL
- #131/#132 — DNN site + déploiement
| Commit | Description |
|---|---|
37600e4a |
fix(harvest): restore Golden Master CSV injection |
f0b1cd35 |
fix(templates): add argumentsVertueux CSS class |
09b427ef |
fix(templates): Scenarii asset paths to GitHub URLs |
30483257 |
fix(templates): Virtues CSS and Rules naming |
9b19d5e8 |
fix(config): remove RowsetNb=14 for Scenarii CardSet |
75a049d3 |
fix(mindmap): restore validated FreeMind SendKeys automation |
55c6774e |
feat(assets): replace XSLT SVGs with FreeMind Batik SVGs |
fd2aef10 |
feat(dataset-updater): migrate to official OpenAI SDK v2.10.0 (#183) |
e24cbd17 |
fix(prompt): enable #nullable context and guard null param.Name |
092d4639 |
Merge PR #200 — bidirectional GSheet ↔ CSV sync (#193) |
| Issue | Description | Status |
|---|---|---|
| Fallacies duplicate PKs 520, 1000 | Warning surfaces during GSheet sync | Needs upstream fix |
| Scenarii 53% translated | 77/167 scenarios missing EN/RU/PT | Blocked by #211 → then pipeline run |
| Virtues 0% translated | No _en/_ru/_pt columns | Unblocked by #183, needs CSV columns added |
| PT Rules MT errors (#211) | Catastrophic MT translations | Needs full retranslation via pipeline |
- ARCHITECTURE_PIPELINE.md - Detailed pipeline architecture
- docs/sddd/ - SDDD methodology and investigation reports
- docs/investigations/ - Debug/archaeology reports (37 reports + scripts)