# S1-CART — Cartographie et classification des chemins Sandbox - **Date :** 2026-10-06 - **Fiche :** S1-T3 | **Agent :** A-CART | **Rôle :** Cartographie & Audit de conformité S1 - **Modèle prévu :** `gemini-3.8-flash-high` | **Modèle utilisé :** `gemini-3.8-flash-high` - **Référence spécification :** `Docs/Migration/etat/sandbox/S1/S1-SPEC.md` - **Référence implémentation :** `Docs/Migration/etat/sandbox/S1/S1-IMPL.md` --- ## 1. Périmètre et méthode ### Fichiers audités - `Source/LifePlay/LPPairSandbox.cpp` - `Source/LifePlay/LPAnimRedirect.cpp` - `Source/LifePlay/LPSandboxConfig.h` - `Source/LifePlay/LPSandboxConfig.cpp` - *(En-têtes associés pour traçabilité : `LPPairSandbox.h`, `LPAnimRedirect.h`)* ### Motifs recherchés 1. `/Game/Heavy` 2. `/Game/BPs/Person` 3. `vin_Base` 4. `Quaternius` ### Grille de classification - **OK default** : Hit localisé dans `LPSandboxConfig.*` (valeur par défaut conforme au contrat `S1-SPEC.md` ou lecture de clé ini), ou appel dynamique via `FLPSandboxConfig::Get().` dans le code exécutable. - **DETTE (hors contrat volontaire)** : Identifiant C++ interne (méthode, membre, classe), chaîne de log, texte informatif UI Slate ou commentaire explicitement exclu du contrat d'externalisation ini par `S1-SPEC.md`. - **OUBLI** : Littéral de chemin restant en dur dans le code d'exécution qui aurait dû passer par la configuration `FLPSandboxConfig`. --- ## 2. Inventaire et classification des hits ### 2.1. Motif `/Game/Heavy` | Fichier | Ligne | Extrait / Contexte | Classification | Justification | |---|---:|---|---|---| | `LPSandboxConfig.h` | 16 | `FString BridgetMesh = TEXT("/Game/Heavy/Daz/Bridget/bridget_gp.bridget_gp");` | **OK default** | Default contractuel clé `BridgetMesh` (`[Sandbox.Assets]`) | | `LPSandboxConfig.h` | 17 | `FString MichaelMesh = TEXT("/Game/Heavy/Daz/Michael/michael.michael");` | **OK default** | Default contractuel clé `MichaelMesh` (`[Sandbox.Assets]`) | | `LPSandboxConfig.h` | 19 | `FString DazIdleFemale = TEXT("/Game/Heavy/Daz/Anims/Idle_F_Daz.Idle_F_Daz");` | **OK default** | Default contractuel clé `DazIdleFemale` (`[Sandbox.Assets]`) | | `LPSandboxConfig.h` | 20 | `FString DazIdleMale = TEXT("/Game/Heavy/Daz/Anims/idle_Daz.idle_Daz");` | **OK default** | Default contractuel clé `DazIdleMale` (`[Sandbox.Assets]`) | | `LPSandboxConfig.h` | 21 | `FString FurnitureWallMaterial = TEXT("/Game/Heavy/New2/Furniture/Materials/FntWall.FntWall");` | **OK default** | Default contractuel clé `FurnitureWallMaterial` (`[Sandbox.Assets]`) | | `LPSandboxConfig.h` | 24 | `FString FurnitureRoot = TEXT("/Game/Heavy/New2/Furniture");` | **OK default** | Default contractuel clé `FurnitureRoot` (`[Sandbox.Roots]`) | | `LPSandboxConfig.h` | 25 | `FString DazAnimRoot = TEXT("/Game/Heavy/Daz/Anims");` | **OK default** | Default contractuel clé `DazAnimRoot` (`[Sandbox.Roots]`) | | `LPSandboxConfig.h` | 36 | `FString SkyCubemap = TEXT("/Game/Heavy/New2/Buildings/Mats/urban_street_03_1k.urban_street_03_1k");` | **OK default** | Default contractuel clé `SkyCubemap` (`[Sandbox.Sky]`) | | `LPSandboxConfig.cpp` | - | *Aucun littéral brut* (lecture des clés ini par nom de clé) | **OK default** | Respecte le contrat | | `LPPairSandbox.cpp` | 858 | `*FLPSandboxConfig::Get().FurnitureRoot` | **OK default** | Consommateur config (ancien l.857 `/Game/Heavy/New2/Furniture`) | | `LPPairSandbox.cpp` | 878 | `*FLPSandboxConfig::Get().FurnitureWallMaterial` | **OK default** | Consommateur config (ancien l.877 `.../FntWall.FntWall`) | | `LPPairSandbox.cpp` | 1002 | `*FLPSandboxConfig::Get().SkyCubemap` | **OK default** | Consommateur config (ancien l.1001 `urban_street_03_1k`) | | `LPPairSandbox.cpp` | 1079 | `FLPSandboxConfig::Get().DazIdleFemale` | **OK default** | Consommateur config (ancien l.1078 `Idle_F_Daz`) | | `LPPairSandbox.cpp` | 1080 | `FLPSandboxConfig::Get().DazIdleMale` | **OK default** | Consommateur config (ancien l.1079 `idle_Daz`) | | `LPPairSandbox.cpp` | 1530 | `*FLPSandboxConfig::Get().BridgetMesh` | **OK default** | Consommateur config (ancien l.1529 `bridget_gp`) | | `LPPairSandbox.cpp` | 2611 | `*FLPSandboxConfig::Get().DazAnimRoot` | **OK default** | Consommateur config (ancien l.2610 `/Game/Heavy/Daz/Anims`) | | `LPPairSandbox.cpp` | 3028 | `FLPSandboxConfig::Get().BridgetMesh` | **OK default** | Consommateur config (ancien l.3026 `bridget_gp`) | | `LPPairSandbox.cpp` | 3031 | `FLPSandboxConfig::Get().MichaelMesh` | **OK default** | Consommateur config (ancien l.3030 `michael`) | | `LPPairSandbox.cpp` | 3108 | `*FLPSandboxConfig::Get().DazAnimRoot` | **OK default** | Consommateur config (ancien l.3106 `/Game/Heavy/Daz/Anims`) | | `LPAnimRedirect.cpp` | - | *Aucun hit* | - | Conforme | **Bilan `/Game/Heavy` :** 8 `OK default` (définitions `LPSandboxConfig.h`), 10 `OK default` (consommations `LPPairSandbox.cpp`), 0 DETTE, 0 OUBLI. --- ### 2.2. Motif `/Game/BPs/Person` | Fichier | Ligne | Extrait / Contexte | Classification | Justification | |---|---:|---|---|---| | `LPSandboxConfig.h` | 15 | `FString PersonBP = TEXT("/Game/BPs/Person.Person_C");` | **OK default** | Default contractuel clé `PersonBP` (`[Sandbox.Assets]`) | | `LPSandboxConfig.cpp` | 46 | `SandboxCfgReadString(File, TEXT("Sandbox.Assets"), TEXT("PersonBP"), PersonBP);` | **OK default** | Lecture ini de la clé `PersonBP` | | `LPPairSandbox.cpp` | 845 | `LoadObject(nullptr, *FLPSandboxConfig::Get().PersonBP);` | **OK default** | Consommateur config dans `Build` (ancien l.844) | | `LPPairSandbox.cpp` | 1090 | `LoadObject(nullptr, *FLPSandboxConfig::Get().PersonBP);` | **OK default** | Consommateur config dans `ConfigureCapsule` (ancien l.1089) | | `LPAnimRedirect.cpp` | - | *Aucun hit* | - | Conforme | *(Note : les occurrences de `PersonClass`, `PersonCap`, `struct FPerson` dans `LPPairSandbox.cpp` sont des symboles C++ / AST interne de script, sans aucun littéral de chemin).* **Bilan `/Game/BPs/Person` :** 2 `OK default` (`LPSandboxConfig.*`), 2 `OK default` (`LPPairSandbox.cpp`), 0 DETTE, 0 OUBLI. --- ### 2.3. Motif `vin_Base` | Fichier | Ligne | Extrait / Contexte | Classification | Justification | |---|---:|---|---|---| | `LPSandboxConfig.h` | 30 | `FString ModuleRoot = TEXT("Modules/vin_Base");` | **OK default** | Default contractuel clé `ModuleRoot` (`[Sandbox.Content]`) | | `LPSandboxConfig.h` | 31 | `FString WorldFile = TEXT("Modules/vin_Base/World/work___vin01.lpworld");` | **OK default** | Default contractuel clé `WorldFile` (`[Sandbox.Content]`) | | `LPSandboxConfig.h` | 32 | `FString ChatAction = TEXT("Modules/vin_Base/Interactions/chat.lpaction");` | **OK default** | Default contractuel clé `ChatAction` (`[Sandbox.Content]`) | | `LPSandboxConfig.cpp` | 59-61 | *Lectures `ModuleRoot`, `WorldFile`, `ChatAction`* | **OK default** | Lectures ini des clés | | `LPPairSandbox.cpp` | 623 | `FPaths::Combine(..., FLPSandboxConfig::Get().ModuleRoot)` | **OK default** | Consommateur config dans `LoadActions` (ancien l.622) | | `LPPairSandbox.cpp` | 833 | `FPaths::Combine(..., FLPSandboxConfig::Get().WorldFile)` | **OK default** | Consommateur config dans `Build` (ancien l.832) | | `LPPairSandbox.cpp` | 1046 | `FPaths::Combine(..., FLPSandboxConfig::Get().ChatAction)` | **OK default** | Consommateur config dans `LoadChat` (ancien l.1045) | | `LPAnimRedirect.cpp` | - | *Aucun hit* | - | Conforme | **Bilan `vin_Base` :** 3 `OK default` (`LPSandboxConfig.h`), 3 `OK default` (`LPPairSandbox.cpp`), 0 DETTE, 0 OUBLI. --- ### 2.4. Motif `Quaternius` | Fichier | Ligne | Extrait / Contexte | Classification | Justification | |---|---:|---|---|---| | `LPSandboxConfig.h` | 18 | `FString QuaterniusMannequinMesh = TEXT("/Game/Quaternius/UAL/UAL1_Standard.UAL1_Standard");` | **OK default** | Default contractuel clé `QuaterniusMannequinMesh` | | `LPSandboxConfig.h` | 26 | `FString QuaterniusRoot = TEXT("/Game/Quaternius");` | **OK default** | Default contractuel clé `QuaterniusRoot` | | `LPSandboxConfig.h` | 27 | `FString QuaterniusUALRoot = TEXT("/Game/Quaternius/UAL");` | **OK default** | Default contractuel clé `QuaterniusUALRoot` | | `LPSandboxConfig.h` | 33 | `FString QuaterniusUALDisk = TEXT("Quaternius/UAL");` | **OK default** | Default contractuel clé `QuaterniusUALDisk` | | `LPSandboxConfig.cpp` | 49 | `SandboxCfgReadString(..., TEXT("QuaterniusMannequinMesh"), ...);` | **OK default** | Lecture ini clé `QuaterniusMannequinMesh` | | `LPSandboxConfig.cpp` | 56 | `SandboxCfgReadString(..., TEXT("QuaterniusRoot"), ...);` | **OK default** | Lecture ini clé `QuaterniusRoot` | | `LPSandboxConfig.cpp` | 57 | `SandboxCfgReadString(..., TEXT("QuaterniusUALRoot"), ...);` | **OK default** | Lecture ini clé `QuaterniusUALRoot` | | `LPSandboxConfig.cpp` | 62 | `SandboxCfgReadString(..., TEXT("QuaterniusUALDisk"), ...);` | **OK default** | Lecture ini clé `QuaterniusUALDisk` | | `LPAnimRedirect.cpp` | 23 | `*FLPSandboxConfig::Get().QuaterniusUALRoot` | **OK default** | Formatage dynamique `ClipPath` via config | | `LPAnimRedirect.h` | 4 | `// Les fichiers restent dans /Game/Quaternius/UAL.` | **DETTE** | Commentaire d'en-tête informatif (aucun impact runtime) | | `LPPairSandbox.h` | 240 | `void LoadQuaternius();` | **DETTE** | Déclaration méthode C++ interne | | `LPPairSandbox.h` | 261 | `FString QuaterniusMesh;` | **DETTE** | Déclaration membre C++ interne de cache | | `LPPairSandbox.h` | 262 | `TMap QuaterniusClips;` | **DETTE** | Déclaration membre C++ interne de cache | | `LPPairSandbox.cpp` | 1529 | `*FLPSandboxConfig::Get().QuaterniusMannequinMesh` | **OK default** | Consommateur config dans `BeginMeasure` | | `LPPairSandbox.cpp` | 1890 | `// Clips du mannequin ... les 43 clips Quaternius.` | **DETTE** | Commentaire de documentation interne | | `LPPairSandbox.cpp` | 1895 | `FLPSandboxConfig::Get().QuaterniusUALDisk` | **OK default** | Consommateur config dans `GetMeasureClips` | | `LPPairSandbox.cpp` | 2773 | `LoadQuaternius();` | **DETTE** | Appel méthode C++ interne | | `LPPairSandbox.cpp` | 2958 | `void ALPPairSandboxCharacter::LoadQuaternius()` | **DETTE** | Définition méthode C++ interne | | `LPPairSandbox.cpp` | 2960 | `QuaterniusMesh.Reset();` | **DETTE** | Utilisation membre C++ interne | | `LPPairSandbox.cpp` | 2961 | `QuaterniusClips.Reset();` | **DETTE** | Utilisation membre C++ interne | | `LPPairSandbox.cpp` | 2963 | `FLPSandboxConfig::Get().QuaterniusRoot` | **OK default** | Scan synchronous via clé config | | `LPPairSandbox.cpp` | 2965 | `*FLPSandboxConfig::Get().QuaterniusUALRoot` | **OK default** | Recherche assets via clé config | | `LPPairSandbox.cpp` | 2977 | `QuaterniusMesh = Data.GetSoftObjectPath().ToString();` | **DETTE** | Assignation membre C++ interne | | `LPPairSandbox.cpp` | 2986 | `QuaterniusClips.Add(Name, Data.GetSoftObjectPath().ToString());` | **DETTE** | Assignation membre C++ interne | | `LPPairSandbox.cpp` | 2990 | `if (!QuaterniusClips.Contains(TEXT("Walk_Loop")))` | **DETTE** | Consultation membre C++ interne | | `LPPairSandbox.cpp` | 2994 | `UE_LOG(LogLifePlay, Warning, TEXT("Sandbox Quaternius : ..."), ...);` | **DETTE** | Tag de log console informatif | | `LPPairSandbox.cpp` | 3024 | `FString Path = QuaterniusMesh;` | **DETTE** | Lecture membre C++ interne | | `LPPairSandbox.cpp` | 3035 | `LoadQuaternius();` | **DETTE** | Appel méthode C++ interne | | `LPPairSandbox.cpp` | 3036 | `Path = QuaterniusMesh;` | **DETTE** | Lecture membre C++ interne | | `LPPairSandbox.cpp` | 3479 | `LoadQuaternius();` | **DETTE** | Appel méthode C++ interne | | `LPPairSandbox.cpp` | 3482 | `QuaterniusClips.GetKeys(ClipNames);` | **DETTE** | Lecture membre C++ interne | | `LPPairSandbox.cpp` | 3883 | `TEXT("MC et PNJ jouent le meme clip Quaternius...")` | **DETTE** | Texte UI Slate explicatif (hors contrat ini) | **Bilan `Quaternius` :** 13 `OK default` (4 en `.h`, 4 en `.cpp`, 5 consommateurs), 19 `DETTE` (identifiants C++, logs, Slate UI, commentaires), 0 OUBLI. --- ## 3. Matrice de couverture contractuelle `S1-SPEC.md` Vérification des 19 clés définies dans `Docs/Migration/etat/sandbox/S1/S1-SPEC.md` : | Clé | Section | Valeur Default contractuelle | Statut Implémentation | Statut Littéral Résiduel | |---|---|---|---|---| | `PersonBP` | `Sandbox.Assets` | `/Game/BPs/Person.Person_C` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `BridgetMesh` | `Sandbox.Assets` | `/Game/Heavy/Daz/Bridget/bridget_gp.bridget_gp` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `MichaelMesh` | `Sandbox.Assets` | `/Game/Heavy/Daz/Michael/michael.michael` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `QuaterniusMannequinMesh` | `Sandbox.Assets` | `/Game/Quaternius/UAL/UAL1_Standard.UAL1_Standard` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `DazIdleFemale` | `Sandbox.Assets` | `/Game/Heavy/Daz/Anims/Idle_F_Daz.Idle_F_Daz` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `DazIdleMale` | `Sandbox.Assets` | `/Game/Heavy/Daz/Anims/idle_Daz.idle_Daz` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `FurnitureWallMaterial` | `Sandbox.Assets` | `/Game/Heavy/New2/Furniture/Materials/FntWall.FntWall` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `FurnitureRoot` | `Sandbox.Roots` | `/Game/Heavy/New2/Furniture` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `DazAnimRoot` | `Sandbox.Roots` | `/Game/Heavy/Daz/Anims` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `QuaterniusRoot` | `Sandbox.Roots` | `/Game/Quaternius` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `QuaterniusUALRoot` | `Sandbox.Roots` | `/Game/Quaternius/UAL` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `ModuleRoot` | `Sandbox.Content` | `Modules/vin_Base` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `WorldFile` | `Sandbox.Content` | `Modules/vin_Base/World/work___vin01.lpworld` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `ChatAction` | `Sandbox.Content` | `Modules/vin_Base/Interactions/chat.lpaction` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `QuaterniusUALDisk` | `Sandbox.Content` | `Quaternius/UAL` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `SkyCubemap` | `Sandbox.Sky` | `/Game/Heavy/New2/Buildings/Mats/urban_street_03_1k.urban_street_03_1k` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `SkyIntensity` | `Sandbox.Sky` | `0.6` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `MeasureOutputRoot` | `Sandbox.Output` | `Measurement` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | | `Mode` | `Sandbox.Mode` | `Pair` | Implémenté (`FLPSandboxConfig`) | Aucun littéral durci restant | --- ## 4. Analyse des DETTES et éléments hors contrat Conformément à la section 1 de `S1-SPEC.md`, les éléments suivants ont été laissés hors contrat de façon volontaire et justifiée : 1. **Symboles C++ internes :** Les identifiants `LoadQuaternius()`, `QuaterniusMesh`, `QuaterniusClips` sont des noms de symboles internes au monolithe `ALPPairSandboxCharacter`. Leur renommage relève du refactoring / renommage de pipeline et non de la configuration de chemins. 2. **Textes d'interface utilisateur (UI Slate) :** La ligne 3883 de `LPPairSandbox.cpp` contient une aide contextuelle pour les développeurs (`MC et PNJ jouent le meme clip Quaternius...`). Elle ne référence aucun asset UE et n'impacte pas le pipeline d'import/redirection. 3. **Logs d'information console :** Les chaînes de logging (`UE_LOG(LogLifePlay, Warning, TEXT("Sandbox Quaternius : corps %s..."))`) servent au diagnostic développeur. 4. **Littéraux Engine & Poses conventionnelles :** Les chemins `/Engine/BasicShapes/Cube.Cube` (l.877), `/Engine/EngineSky/BP_Sky_Sphere.BP_Sky_Sphere_C` (l.1025) ainsi que les noms de poses conventionnels (`Idle_Loop`, `Walk_Loop`, `A_TPose`, préfixes `B_`/`M_`) restent en dur comme stipulé au contrat. 5. **Observation périphérique hors périmètre :** `Source/LifePlay/LPInteractionSandbox.cpp` contient encore des chemins en dur (`/Game/Heavy/...`, `Modules/vin_Base/...`). Ce fichier correspond à l'ancienne sandbox d'interaction legacy (marquée comme obsolète dans `S0-CART.md`) et ne fait pas partie du périmètre S1 défini par `S1-SPEC.md` (qui se concentre sur `LPPairSandbox` et `LPAnimRedirect`). --- ## 5. Synthèse et critère Done ### Synthèse quantitative - **Hits totaux audités sur les 4 motifs :** 47 - **OK default :** 28 (initialiseurs dans `LPSandboxConfig.h`, parsers dans `LPSandboxConfig.cpp`, consommations via `FLPSandboxConfig::Get()` dans `LPPairSandbox.cpp` et `LPAnimRedirect.cpp`) - **DETTE (hors contrat volontaire) :** 19 (symboles C++, logs, aide Slate UI, commentaires) - **OUBLI :** 0 ### Critère Done > **Critère Done : aucun OUBLI bloquant non justifié.** - **Résultat :** **ATTEINT (100% CONFORME)**. - Aucun littéral de chemin d'asset ou de fichier disque correspondant aux motifs recherchés n'est resté en dur dans `Source/LifePlay/LPPairSandbox.cpp` ou `Source/LifePlay/LPAnimRedirect.cpp`. - Tous les chemins passent sans exception par la configuration centralisée `FLPSandboxConfig::Get()`.