LifePlay-Revival/Docs/Migration/etat/REL/FIX1/FIX1-F6-PRE.md

179 lines
23 KiB
Markdown
Raw Normal View History

Fiche FIX1-F6-PRE — Niveau N2 — Modèle prévu non précisé par la fiche | utilisé claude-sonnet-5-5 — Agent lp-cart — Skills sk-protocol, ue-cpp-build, lp-commandlets, lp-paths
# FIX1-F6-PRE : étude préliminaire de dimensionnement de F6, ERR-042, personnages de partie dans `Content\Saves` (2026-10-20)
Hors gabarit : étude préliminaire (pas une CART complète). Les rubriques 1 à 6 du gabarit CART sont gardées ; la rubrique 3 suit les quatre questions de la fiche (existant, localisation, dimensionnement, recommandation). Lecture seule : ni copie UE, ni MCP, ni éditeur, ni commandlet. Seul ce fichier est écrit.
## Résumé (à lire en premier)
1. **Ce qui reste d'ERR-042** : les fichiers `.lpcharacter` d'une partie sont lus et écrits dans `<dossier du jeu>\Content\Saves\…`, hors du nouveau dossier `%LOCALAPPDATA%\LifePlay-Revival\Saved` (établi : `Docs/Registre_Erreurs.md:49`, `README.md:82-83`).
2. **Point d'étranglement unique en C++** : tous les accès Blueprint à ces fichiers passent par `UModdingExtraBPLibrary::LoadTxt` et `::SaveTxt`, qui préfixent `FPaths::ProjectContentDir()` (établi : `Plugins/ModdingExtra/Source/ModdingExtra/Private/ModdingExtraBPLibrary.cpp:190, 236`). Rediriger les chemins `Saves/…` à cet endroit demande 1 fichier C++ et **0 Blueprint** (estimé, à prouver en SPEC).
3. **GI n'est pas exigé** par cette voie (estimé). La voie Blueprint, elle, toucherait GI (29 littéraux `Saves/…`) et au moins 3 widgets UI : à écarter.
4. **La ligne du doc 37 est mal classée** : `37_Feuille_De_Route_Alpha2.md:171` range F6 dans « petits correctifs Blueprint par MCP, `lp-mcp-bp` ». L'existant dit autre chose : c'est un correctif C++ dans un plugin, sur le chemin de lecture de toutes les données du jeu.
5. **Recommandation** : lot **N3** ; SPEC par un modèle opus (effort medium) ; IMPL par `lp-impl` (Sonnet) sur une SPEC qui dicte les lignes, ou `lp-impl-max` si la SPEC laisse des choix ; BUILD `lp-builder` ; VAL `lp-validator` distinct ; essai en jeu sous le jeton de la copie UE. **Build 1 sous condition** (porte au J4), sinon build 2 et la limite connue reste documentée. Détail en § 3.4.
## 1. Objet et périmètre
Un domaine : l'emplacement des fichiers `.lpcharacter` d'une partie (ERR-042, reste). Question posée par Big Boss : quel agent et quel modèle pour F6 (doc 37 § 1.2, ligne 59), build 1 (gel 2026-10-24) ou build 2. Hors périmètre : le dossier `SaveGames` et les réglages `*.ini` (déjà traités par REL-SAV), le contenu des modules, toute correction.
## 2. Commandes et lectures (exactes) avec compte brut
| # | Commande ou lecture | Résultat brut |
|---|---|---|
| 1 | Grep `ERR-042` dans `Docs` | ligne `Registre_Erreurs.md:49` ; `37_Feuille_De_Route_Alpha2.md:59` ; `BOSS-JOURNAL.md:983` |
| 2 | Glob `**/SAV1*` sous `Docs/Migration/etat` | `No files found` (aucun dossier SAV1) |
| 3 | Glob `**/REL-SAV*` sous `Docs/Migration/etat` | 13 fichiers dans `REL/SAV/` (DIAG, SPEC, IMPL, VAL, ESSAIS, DOC, TACHES, RESULTATS-COMMUN8, `fiches/T1-T4`) et `REPO/tickets/REL-SAV-R1.md` |
| 4 | Read `REL-SAV-DIAG.md`, `REL-SAV-SPEC.md`, `REL-SAV-IMPL.md`, `Registre_Erreurs.md:49`, `37_…:30-100, 140-198` | cités en § 3 |
| 5 | Grep `lpcharacter` dans `Source` (insensible à la casse) | 1 résultat : `Source/LifePlay/LPStringCompat.h:9` (commentaire) |
| 6 | Grep `Content[\\/]+Saves\|"Saves\|/Saves/` dans `Source` | `No matches found` |
| 7 | Grep `"Saves\|/Saves/\|Content/Saves\|lpcharacter` dans `Plugins` (`*.cpp,*.h,*.cs,*.py,*.ini`) | `No files found` (Plugins/Marketplace et McpAutomationBridge, ignorés par git, non parcourus) |
| 8 | Grep `Saves` dans `Config` | `No matches found` |
| 9 | Glob `Content/Saves/*` | `No files found` (dossier absent de la copie 5.8 ; `.gitignore:84` : `/Content/Saves/`) |
| 10 | Grep `'Saves/` dans `Docs/Migration/etat/portage55/L6f/L6f_dump_GI.txt` (dump 5.5 de toutes les fonctions de GI, 2026-09-30) | 29 lignes (liste § 3.2) |
| 11 | Grep `= 'Saves/\|'Saves/` en `*.txt` sous `etat` | 38 fichiers, tous des dumps GI (ou 1 fichier CAM-T6) |
| 12 | Grep `appel ModdingExtraBPLibrary::(LoadTxt\|SaveTxt)` dans `L6f_dump_GI.txt` | 45 lignes (nœuds d'appel dans GI) |
| 13 | `rg -a -l -e "Saves/_session" -e "Saves/Characters" -e "\.lpcharacter" -g "*.uasset" -g "*.umap" Content` (Bash, depuis la racine) | 6 fichiers : `Content/UI/BodyShapeMenu`, `UI/CharGen`, `UI/ContactMenu`, `UI/Contact`, `UI/StatMenu`, `BPs/GI` (.uasset) ; code de sortie 0 |
| 14 | `rg -a -o -e 'Saves[A-Za-z_/]*' -e '[A-Za-z]*\.lpcharacter' <fichier>` puis `sort \| uniq -c` | tableau § 3.2 (comptes **bruts de correspondances dans le binaire**, pas de nœuds) |
| 15 | `git ls-files Plugins/ModdingExtra \| wc -l` ; `git check-ignore -v Content/Saves/x` | `8` ; `.gitignore:84:/Content/Saves/` |
Écart de méthode à signaler : les commandes 13 et 14 passent par `rg -a` en Bash. L'outil Grep ne lit pas un `.uasset` en mode texte quand il parcourt un dossier : le Grep sur le dossier `Content` (motif `Saves/_session`, `*.uasset`) a rendu `No files found`, alors que le Grep sur le seul fichier `Content/BPs/GI.uasset` rend 54 occurrences. **Un résultat vide d'un Grep de dossier sur des `.uasset` ne prouve donc rien** (à verser).
## 3. Constats `fichier:ligne`
### 3.1 État de l'existant (question 1)
| Constat | Source | Niveau |
|---|---|---|
| ERR-042 porte le lot « SAV1 » et dit : dossier de sauvegarde partagé avec le jeu d'origine ; REL-SAV a posé la garde `LPSaveRelaunch` ; E9 PASS sur le Shipping `2026.10.2.1a` ; **reste** : « les personnages d'une partie sauvegardée restent dans le dossier du jeu (`LifePlay\Content\Saves`), annoncé comme limite connue de l'alpha » ; E5 non fait (facultatif) ; Mod Manager à refaire avec un zip | `Docs/Registre_Erreurs.md:49` | établi |
| Le lot SAV1 n'a **aucun dossier** `etat/` propre ; son travail est le lot REL-SAV (`etat/REL/SAV/`). Le Cahier des charges le cite (§ 6) | Glob n° 2 et n° 3 ; `Registre_Erreurs.md:49` ; `Docs/21_Sandbox_Addon.md:213` | établi |
| **Option retenue : B+ seul** (garde dans le jeu qui relance l'exe avec `-UserDir`), **aucun lanceur livré** (option B écartée) | `REL-SAV-SPEC.md:7-16` (« Aucun lanceur n'est donc livré », l. 16) | établi |
| Aucune reprise des anciennes sauvegardes (décision R0) | `REL-SAV-TACHES.md:19` | établi |
| **Déjà fait** : dossier `%LOCALAPPDATA%\LifePlay-Revival\Saved` (Config, Logs, LPDataCache, SaveGames) créé et utilisé en Shipping ; code `LPSaveRelaunch.cpp` (396 l.), `LPSaveRelaunch.h`, `LifePlay.cpp` (+3 l.) | `Registre_Erreurs.md:49` ; `REL-SAV-IMPL.md:13-15` | établi |
| **Le dossier du jeu est hors du lot** : `Player.lpcharacter` est dans `Content\Saves`, « le renommage ne la touche pas ; le défaut existant (SAV1 / ERR-042) reste ouvert » | `REL-SAV-DIAG.md:58` | établi |
| Conséquence pour le joueur : « une sauvegarde est donc répartie entre les deux dossiers » | `REL/ALPHA/REL-ALPHA-T6b.md:24` | établi |
| Texte public actuel : limite connue (« keep the game folder when you update, or copy `LifePlay\Content\Saves` to the new one ») | `README.md:82-83` ; repris `MEN/MEN1/MEN1-B-PROPOSITION.md:24, 105-106` | établi |
| Statut de F6 : « ERR-042 : personnages de partie dans `Content\Saves` (reste) », rubrique Fix ; FIX1 = « F6, F7, F8 : petits correctifs Blueprint par MCP · `lp-mcp-bp` · 7e jeton » | `37_Feuille_De_Route_Alpha2.md:59, 171` | établi |
| ERR-042 avait été « non retenu » pour l'après-alpha (2026-10-14), puis F6 est entré dans la liste d'avant gel | `BOSS-ETAT.md:259` ; `37_…:59` | établi |
Cartographie des dossiers de sauvegarde d'une partie, aujourd'hui :
| Quoi | Où | Preuve |
|---|---|---|
| Emplacements `.sav` (UE `SaveGame`) et `GameSettings.sav` | `<…>\Saved\SaveGames` → nouveau dossier Revival | `Registre_Erreurs.md:49` |
| Réglages `LP*.ini` | `<…>\Saved\Config\Windows` → nouveau dossier | `LPKeyboardSubsystem.cpp:77`, `LPColorGradeSubsystem.cpp:27`, `LPVideoQualitySubsystem.cpp:71` |
| **Personnages de la partie en cours (copie de travail)** | `<jeu>\Content\Saves\_session\Characters\…` | dump GI `CAM-B1-PRE_LPDumpFunction_20261013-083048.txt:6469, 9655, 18018, 25060` |
| **Personnages d'une partie enregistrée** | `<jeu>\Content\Saves\<Slot>\Characters\<N>.lpcharacter`, `F<N>`, `C<N>`, `OldPlayer`, `Player` | même dump : événement `DuplicateCharacters` l. 8397-8431 ; copies N l. 8459-8489, `F` l. 15288-15320, `OldPlayer` l. 18924-18955, `C` l. 19003-19020, `Player` l. 8505-8534 |
| Sens de la copie | `Load = vrai` : `Saves/<Slot>/Characters/` → `_session` ; `Load = faux` : l'inverse | même dump l. 8400, 8402-8413 |
### 3.2 Où sont les accès (question 2)
**C++ (un seul fichier d'E/S, établi)**
| Point | Ligne | Rôle |
|---|---|---|
| `LoadTxt` : lecture `FFileHelper::LoadFileToString(…, ProjectContentDir() + FileNameA)` | `ModdingExtraBPLibrary.cpp:190` | **lecture** (1 point) |
| `LoadTxt` : relecture de contrôle si le cache est en mode vérification | `ModdingExtraBPLibrary.cpp:195` | lecture de contrôle (même chemin) |
| `SaveTxt` : `FFileHelper::SaveStringToFile(…, ProjectContentDir() + FileNameB)` | `ModdingExtraBPLibrary.cpp:236` | **écriture** (1 point) |
| `GetAllFilesFromFolder`, `GetAllSubfolders`, `ContentDirectory` : base `ProjectContentDir()` | `ModdingExtraBPLibrary.cpp:50, 120, 254` | listes et chemin absolu ; usage sur `Saves/` **non démontré** (inconnu) |
| Le cache de données ne couvre que `Modules` : « pour tout chemin hors Modules, la lecture se fait sur le disque » | `LPDataCache.h:10-11` ; `LPDataCache.cpp:25, 104, 110` | établi : `Saves/` n'est pas servi par le cache |
Aucun autre code C++ du jeu ne cite `Saves` ni `lpcharacter` : Grep n° 5 à 8 (Source : 1 commentaire ; Plugins et Config : rien). Le module d'outils de l'éditeur (`LPDumpSaveCommandlet.cpp`) ne lit que des `.sav`.
**Blueprint (chemins littéraux, base relative à `Content`)**
| Asset | Correspondances brutes `rg -a -o` | Lecture |
|---|---|---|
| `Content/BPs/GI.uasset` | `Saves/_session/Characters/` 41 ; `…/F` 10 ; `…/C` 4 ; `…/OldPlayer` 4 ; `Saves/` 7 ; `Saves` 5 ; `.lpcharacter` 80 ; `OldPlayer.lpcharacter` 5 ; `Player.lpcharacter` 4 ; presets de modèles `elf/orc/vampire/thirties/twenties` | GI porte **la quasi-totalité** des accès |
| `Content/UI/Contact.uasset` | `Saves/_session/Characters/` 4 ; `…/C` 2 ; `…/F` 2 ; `.lpcharacter` 4 | 3 familles de chemins ; ≈ 4 littéraux (estimé : chaque littéral apparaît 2 fois dans le binaire) |
| `Content/UI/ContactMenu.uasset` | `Saves/_session/Characters/` 2 ; `.lpcharacter` 2 | ≈ 1 littéral (estimé) |
| `Content/UI/BodyShapeMenu.uasset` | `F.lpcharacter` 2 ; appel `SaveTxt` | ≈ 1 chemin ; écrit un personnage |
| `Content/UI/CharGen.uasset`, `Content/UI/StatMenu.uasset` | `.lpcharacter` 2 chacun ; appels `LoadTxt`, `GetAllFilesFromFolder` (3 chacun) | pas de littéral `Saves` ; presets de `Modules` ; passent par `GI.SavePreset` / `LoadPreset` (`CG2-CART-01.md:44-45, 55, 74`) |
Littéraux `Saves/…` **dans les graphes de GI** (dump 5.5 `L6f_dump_GI.txt`, 29 lignes) : 22 dans 17 fonctions, 7 dans l'`EventGraph`. Lignes du dump, rattachées aux fonctions par l'ordre des en-têtes (déduit) : `GeneratePerson` (17478, 17709), `GetAllGeneratedCharacters` (23601, 23632, 23694), `getPerson` (24098), `GetSpecific` (26089, 26773), `getRelative` (29595), `isMarried` (29924), `GetNameFromSlot` (31346), `cloneFrom` (32249), `UpdateChildrenAges` (32922, 33014), `GetFratBros` (33397), `calculateStaffIntelligence` (34570), `calculateStaffInterpersonal` (34673), `GenerateCreature` (36231), `getCreature` (36531), `saveOldPlayer` (37959), `GenerateHomeAndWork` (43519), `populateGlassesAndVirgins` (44889). `EventGraph` : 55001, 56563, 56568, 56582, 57538, 64195, 69938, identiques aux 7 lignes du dump 5.8 `CAM-B1-PRE…txt:6469, 8405, 8410, 8428, 9655, 18018, 25060`.
Autres constats utiles :
- `GI.SavePreset` choisit le préfixe d'après le chemin : `StartsWith(File, "Saves")` sinon `"Modules/"` (`L6f_dump_GI.txt:2325-2336`). Un chemin d'une autre forme tomberait dans `Modules/` : une migration par Blueprint devrait garder ce test (et la redirection C++ le laisse intact).
- Appels `LoadTxt`/`SaveTxt` dans GI : 45 nœuds (grep n° 12). `SavePreset` en compte 2 écritures (l. 1134, 2288) et 2 lectures (l. 2188, 3045), `LoadPreset` 1 lecture (l. 3310) ; le sous-ensemble sur des chemins `Saves` n'a pas été isolé par flux de données (inconnu, estimé 20 à 25).
- Message à l'écran quand les fichiers manquent : « The save you just loaded is missing crucial *.lpcharacter files. Please copy your old LifePlay\Content\Saves folder into the directory of the current version of the game… » (`CAM-B1-PRE…txt:14822-14823`, `EventGraph` de GI) : devient faux si F6 aboutit.
- Les fichiers de presets de mods sont lus dans `Modules/<mod>/Presets/…` (`L6f_dump_GI.txt:17506, 35316-35326`) et non dans `Saves`.
### 3.3 Dimensionnement (question 3)
| Critère | Établi | Estimé | Inconnu |
|---|---|---|---|
| Écritures | 1 point C++ (`SaveTxt`, `.cpp:236`) | côté Blueprint : `DuplicateCharacters` (5 familles de fichiers), `SavePreset` (2 `SaveTxt`), `saveOldPlayer`, `BodyShapeMenu` ; toutes passent par `SaveTxt` | écritures hors `SaveTxt` (aucune trouvée dans Source, Plugins, ni dans les noms d'appel de GI) |
| Lectures | 1 point C++ (`LoadTxt`, `.cpp:190`) ; 45 nœuds d'appel dans GI | ≈ 20 à 25 sur des chemins `Saves` | lectures par `GetAllFilesFromFolder` ou `ContentDirectory` sur `Saves` |
| BP ou C++ | le chemin réel est construit en C++ (`ProjectContentDir() + chemin relatif`) | **C++ seul** si la redirection est faite dans `LoadTxt`/`SaveTxt` : ≈ 40 à 80 lignes dans 1 fichier (helper de résolution, repli de lecture, journal) | helper commun aux 3 fonctions de liste si elles servent `Saves` |
| Voie BP (non retenue) | 29 littéraux dans GI + ≈ 6 dans 3 widgets UI ; le test `StartsWith "Saves"` de `SavePreset` ; ≈ 35 modifications par MCP | — | — |
| GI touché ? | **non, par la voie C++** | le texte du message (`CAM-B1-PRE…txt:14823`) reste faux jusqu'à la build 2 | — |
| GI touché ? (voie BP) | **oui** : 17 fonctions + `EventGraph` | contraire à la règle « GI.uasset n'est révisé qu'une fois, en build 2 » | — |
| Migration des fichiers existants | R0 déjà décidé pour `SaveGames` (`REL-SAV-TACHES.md:19`) | **repli de lecture** vers l'ancien `Content\Saves` : aucune copie, aucune suppression ; l'écriture va dans le nouveau dossier | granularité du repli (par fichier ou par dossier de slot) : voir risque R2 |
| Saves déjà faites (alpha 2026.10.2.1a, V1.x) | les `.sav` sont dans `…\SaveGames`, les personnages dans `<jeu>\Content\Saves` (`REL-ALPHA-T6b.md:24`) | avec le repli, une partie chargée depuis l'ancien emplacement fonctionne ; au premier enregistrement, les personnages passent dans le nouveau dossier | cas d'un joueur qui supprime l'ancien dossier du jeu avant d'avoir réenregistré |
| Compatibilité des mods | le format `.lpcharacter` ne change pas ; les presets de mods sont dans `Modules` (`L6f_dump_GI.txt:17506`) ; le cache ne touche pas `Saves` (`LPDataCache.h:10-11`) | le contrat de données des mods n'est pas modifié | **les guides de modding décrivent l'emplacement** : `Docs/Modding/ShortGuides/explanation.lpcharacter:3`, `FullGuides/Creating_Presets.txt:7, 13, 15` (`Content/Saves`, `_session`, `Saves/Default`) : texte à corriger, décision de l'utilisateur car le contrat est « figé » (`REL-SAV-DIAG.md:48`) |
| Éditeur et Development | `ProjectSavedDir()` = `<copie>\Saved` hors paquet (`REL-SAV-DIAG.md:59`) | les parties de test se rangeraient dans `Saved` au lieu de `Content\Saves` | règle de copie d'une sauvegarde de test (`21_Sandbox_Addon.md:213` ; `REF/REF1/REF1-CART-02.csv:65`) et règle « `Content/Saves` doit exister mais rester vide » (`REF1-CART-01.csv:41`) à réécrire |
| Dossier cible et `-UserDir` | `ProjectSavedDir()` suit déjà `-UserDir` (`REL-SAV-DIAG.md:19-20`) | le nouveau chemin suit donc le dossier choisi par le joueur | création de dossiers : `SaveTxt` crée les sous-dossiers de slot aujourd'hui (le dossier `Content/Saves` est livré vide, `REF1-CART-01.csv:41`), donc `FFileHelper` crée l'arborescence (déduit) |
| `Saves/Default` | cité par `Creating_Presets.txt:13` | — | lu ou non par GI, livré ou non : non vérifié |
### 3.4 Recommandation (question 4)
**Agent et niveau (estimé)**
| Étape | Agent | Modèle | Niveau | Raison |
|---|---|---|---|---|
| SPEC | Big Boss, ou une fiche opus (effort medium) | opus | **N3** | décisions à prendre (racine, repli par slot, journal, interrupteur de retour arrière, texte des guides) ; chemin chaud |
| IMPL | `lp-impl` | Sonnet | N2 | ≈ 40 à 80 lignes dans 1 fichier, si la SPEC donne la signature et les cas ; passer à `lp-impl-max` (opus) si la SPEC laisse des choix |
| BUILD | `lp-builder` | — | N1 à N2 | compilation d'un plugin du jeu, sans l'addon |
| VAL | `lp-validator` distinct de l'IMPL | — | N2 | relecture du diff ; branche « hors `Saves/` » inchangée octet pour octet |
| Essai en jeu | Big Boss, sous le jeton de la copie UE | — | — | nouvelle partie, sauvegarde, Continuer, ancien dossier présent / absent |
| DOC | `lp-writer` | — | N1 | README, guides de modding, `lp-validate`, REF1, annonces, ERR-042 |
À ne **pas** confier : `lp-mcp-bp` (aucun Blueprint à modifier par cette voie ; GI est réservé à la build 2) ; un agent xhigh (pas d'analyse profonde nécessaire une fois la SPEC écrite). Le niveau « lot » à porter dans `FIX1-TACHES` : **N3** (le chemin touché est lu par toutes les données du jeu et l'essai exige la copie UE).
**Durée (estimée, non mesurée)** : SPEC 20 à 30 tours ; IMPL 15 à 25 tours, sans la copie UE ; compilation incrémentale du plugin (durée non mesurée) ; VAL 15 à 20 tours ; essai en jeu 30 à 60 minutes sous le jeton ; DOC 10 à 15 tours. Environ une journée de session répartie sur J2 à J4, dont **un seul créneau sur la copie UE** (compilation et essai).
**Risques**
- R1, chemin chaud : `LoadTxt` sert toutes les données du jeu. Le test `Saves/` doit précéder tout et laisser les autres chemins inchangés (VAL par relecture du diff et par le bilan `ModdingExtra.LoadTxtStats` au démarrage).
- R2, mélange de deux parties : un repli de lecture **par fichier** pourrait relire un personnage de l'ancienne partie du même numéro de slot. Préférer un repli **par dossier de slot** (si le dossier du slot existe dans le nouveau dossier, ne plus regarder l'ancien).
- R3, retour arrière : prévoir un interrupteur (argument de lancement ou variable de configuration) qui rétablit le chemin d'origine, pour tenir le gel du 24.
- R4, textes périmés : message de GI (`CAM-B1-PRE…txt:14823`), README (`:82-83`, et `:117` qui cite encore l'ancien dossier, non vérifié), annonces `REL/ALPHA/REL-ALPHA-ANNONCE-*.md`, guides de modding.
- R5, file de la copie UE déjà chargée (`37_…:171, 179-185`) : un créneau de plus.
**Build 1 ou build 2 (estimé, décision de l'utilisateur)**
- **Build 1 est tenable sous trois conditions** : (a) la voie C++ seule est confirmée par la SPEC (aucune modification de GI) ; (b) la SPEC est acceptée le J2 (2026-10-21) pour que l'IMPL se fasse hors copie UE ; (c) l'essai en jeu a lieu au J3 ou au J4 dans le créneau voisin de FIX1 (`37_…:183-184`). Porte : si l'essai n'est pas concluant au J4 soir, F6 passe en build 2 et la limite reste dans le README.
- **Build 2 est préférable** si CG2 ou CAM2 glissent : F6 change l'emplacement des données de **tous** les joueurs juste avant le gel, pour un gain limité (une limite déjà annoncée). Le message de GI pourrait alors être corrigé avec la révision unique de GI.
- Dans les deux cas, GI n'est pas touché en build 1.
## 4. Établi / estimé / incertain (synthèse)
**Établi (relu à la source)** : texte d'ERR-042 et ses mises à jour ; B+ seul retenu, aucun lanceur ; R0 ; `LPSaveRelaunch` livré et E9 PASS ; limite connue au README ; chemins de personnages `Saves/_session/Characters/…` et `Saves/<Slot>/Characters/…` ; point d'E/S unique `LoadTxt`/`SaveTxt` sur `ProjectContentDir()` ; aucun autre code C++ ne cite `Saves` ; 29 littéraux dans les graphes de GI (dump 5.5) dont 7 dans l'`EventGraph` (dump 5.8) ; 6 assets contiennent ces chaînes ; le cache de données ne couvre que `Modules` ; guides de modding qui citent `Content/Saves`.
**Estimé (déduit)** : la redirection en C++ suffit sans toucher GI ; le nombre de modifications Blueprint si on avait choisi cette voie (≈ 35) ; 20 à 25 nœuds `LoadTxt`/`SaveTxt` sur chemins `Saves` ; le repli de lecture couvre les parties existantes ; `FFileHelper` crée les dossiers ; durées et niveaux de § 3.4.
**Incertain, essai qui trancherait** :
- Les dumps de fonctions de GI (29 littéraux) datent du 2026-09-30 (5.5) : `LPDumpFunction -BP=GI -Fn=<chaque fonction> -Pins` sur la 5.8, éditeur fermé, rendrait le compte actuel (utilise la copie UE).
- Usage de `GetAllFilesFromFolder` / `GetAllSubfolders` / `ContentDirectory` sur `Saves` : suivi du flux de données dans ces dumps `-Pins`.
- `Saves/Default` : lu ou non, livré ou non.
- Comportement réel d'un Shipping avec un repli de lecture : essai en jeu seulement.
## 5. Points à confirmer (repris par la fiche suivante)
1. Rafraîchir par commandlet (copie UE) le relevé des littéraux `Saves` de GI en 5.8 et isoler, par flux de données, les nœuds `LoadTxt`/`SaveTxt` sur chemins `Saves`.
2. Chercher les usages de `GetAllFilesFromFolder`, `GetAllSubfolders` et `ContentDirectory` avec une base `Saves`.
3. Lire `LPDataCache::OnWritten` (`LPDataCache.cpp:269`) pour confirmer qu'elle ignore les chemins hors `Modules` (non lu ici).
4. Vérifier que `FFileHelper::SaveStringToFile` crée l'arborescence dans le moteur 5.8 installé (`Engine/Source/Runtime/Core/…/FileHelper.cpp`) : déduit ici d'un comportement observé, non relu dans le moteur.
5. Statuer sur `Saves/Default` (guides de modding `Creating_Presets.txt:13`).
6. Vérifier `README.md:117` (cite encore `%LOCALAPPDATA%\LifePlay\Saved`).
7. Corriger la classe de la ligne FIX1 du doc 37 (F6 n'est pas un correctif Blueprint) quand l'utilisateur aura tranché.
## 6. Questions pour la SPEC ou l'utilisateur
1. Racine du nouveau dossier : `ProjectSavedDir()/Saves/…` (même arbre que `SaveGames`) ou `ProjectSavedDir()/SaveGames/Characters/…` ?
2. Repli de lecture sur l'ancien `Content\Saves` : oui ou non ; par slot (recommandé) ou par fichier ; durée de vie (jusqu'à quelle version) ?
3. Copie des anciens personnages vers le nouveau dossier au premier chargement, ou aucune copie (cohérent avec R0) ?
4. Guides de modding (`explanation.lpcharacter:3`, `Creating_Presets.txt:7, 13, 15`) : corriger le texte, sachant que le contrat des mods est « figé » ?
5. Texte du message de GI (`CAM-B1-PRE…txt:14823`) : le laisser en build 1 et le corriger avec la révision unique de GI en build 2 ?
6. Interrupteur de retour arrière : sous quelle forme (argument de lancement, `.ini`) ?
7. F6 en build 1 sous la porte du J4, ou directement en build 2 ?
8. Où classer la ligne FIX1 : garder `lp-mcp-bp` pour F7 et F8, et sortir F6 de FIX1 vers un lot propre (ex. FIX1-F6) piloté en C++ ?
Tours : 26 / 20 (budget « environ 20 » dépassé de 6 : recherche des chaînes dans les assets binaires et rattachement des littéraux aux fonctions de GI ; `Tools/FicheStats.py` fait foi)