LifePlay-Revival/Docs/Migration/etat/REL/FIX1/FIX1-F6-VAL.md
2026-10-21 09:36:04 +02:00

9.5 KiB

Fiche FIX1-F6-VAL — Niveau N1 — Modèle prévu sonnet | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate

FIX1-F6-VAL : validation statique de la redirection Saves/… (2026-10-20)

Verdict : PASS-STATIC avec réserves (équivalent de « PASS avec réserves » de la fiche : statique complet et rejoué, aucun essai en jeu). Rien n'a été modifié hors ce livrable. Seule écriture par commande : deux résumés FIX1-VAL_BuildLog_20261020-191429.txt et -191430.txt produits par Build.ps1 -FromLog dans etat\REL\FIX1\ (ignorés par git, .gitignore:75).

1. Fiches amont relues

  • etat\REL\FIX1\FIX1-F6-SPEC.md (lue en entier, § 2.1 a-g et § 7.1).
  • etat\REL\FIX1\FIX1-F6-IMPL.md (lue en entier, § 5 points à confirmer).
  • etat\REL\FIX1\FIX1-F6-PRE.md : existe, non relue (la SPEC la cite, elle n'est pas un critère).
  • Journaux Saved\Logs\portage\FIX1_Build_20261020-190716.log et -190831.log.
  • Instantané D:\Game\LifePlay_Backup_5.5\FIX1\ (manifeste et copie du fichier).

2. Points à confirmer des IMPL

Id Verdict Preuve
V1 PASS git diff --stat -- Plugins/ModdingExtra : 1 file changed, 120 insertions(+), 2 deletions(-) ; recompté par git diff --no-index --numstat <instantané> <fichier> : 120 2. Le « ≈ 100 » de la SPEC est bien une estimation basse (IMPL écart 3), le texte est celui de la SPEC.
V2 PASS ResolvePath, branche !Match : return FPaths::ProjectContentDir() + ContentRelativePath; (diff, bloc b). Identique à l'ancienne expression.
V3 PASS Diff complet : seules LoadTxt (:308) et SaveTxt (:354) changent. :313 (relecture ProjectContentDir() + FileNameA), :307 TryGet(FileNameA…), :309 Record(FileNameA…), :357 OnWritten(FileNameB…) hors hunks, donc inchangées.
V4 PASS _session : Slot.Equals("_session", IgnoreCase) renvoie NewPath sans test de dossier. Écriture : bForWrite renvoie NewPath. L'ancien chemin n'est rendu que hors Saves/ ou avec -LPNoSavesRedirect, ou pour une lecture de slot de repli.
V5 PASS git ls-files --eol : i/lf w/lf attr/-text ; CR comptés par tr -cd '\r' | wc -c : 0.
V6 PASS § 3.
B1 PASS (constat) LPKeyboardSubsystem.cpp : MD5 611c21489d80374a4817f70e408cf4db (attendu 611c2148), i/crlf w/crlf, lot KEY2, non touché par F6. Les binaires contiennent donc F6 + KEY2 ; à retenir pour le build de référence.
B2 reporté Paquet Development non produit (IMPL § 5 B2) : hors périmètre VAL statique, étape suivante de l'ordonnateur.
B3 reporté Shipping non compilé.
B4 non rejoué Recherche UTF-16 de chaînes dans les binaires : non refaite (preuve de liaison seulement, sans valeur de comportement). Les unités compilées (§ 3) suffisent pour la liaison.
C1 PASS (lu) Fichier posé directement dans Saves/ : Slot vide, journal Saves slot '' : nouvelle racine, cosmétique. Voir § 5 réserve 3.
C2 PASS-STATIC static const bool dans IsDisabled() : initialisation thread-safe C++11, lue au premier appel après l'initialisation de la ligne de commande (premier LoadTxt BP). E6 le tranchera en jeu.
E1-E9 reporté Essais en jeu non faits (aucun jeu lancé).

3. Critères rejoués

Contrôle Commande Résultat
MD5 du fichier md5sum Plugins/ModdingExtra/…/ModdingExtraBPLibrary.cpp 1f93601c71d126f173fe30636aec0660 (attendu 1f93601c : conforme)
MD5 instantané md5sum D:/Game/LifePlay_Backup_5.5/FIX1/Plugins/…/ModdingExtraBPLibrary.cpp 7628837e7b77c68c3921acfad3d92ec0 (conforme)
Autres fichiers de plugin/source git status --porcelain -- Plugins Source M …ModdingExtraBPLibrary.cpp et M Source/LifePlay/LPKeyboardSubsystem.cpp (KEY2, MD5 ci-dessus). LPDataCache.*, Build.cs, .uplugin non modifiés. LifePlay.uproject est modifié (date 2026-10-19 23:32, antérieur au lot, 15+/7-) : hors F6.
Build 1 (LifePlayEditor) pwsh -NoProfile -File Tools/Build.ps1 -Lot FIX1-VAL -FromLog …190716.log -EtatDir <abs> erreurs=0 avertissements=1 autres=20 unites=3 ; Result: Succeeded (log l. 61) ; Total execution time: 57.83 seconds ; l. 51 Compile [x64] ModdingExtraBPLibrary.cpp, l. 52 Module.ModdingExtra.cpp, l. 42 Module.LifePlay.cpp. Le code -1 du résumé est celui de -FromLog (code de sortie non dans le journal), pas un échec.
Build 2 (LifePlay Development) idem, …190831.log erreurs=0 avertissements=1 autres=0 unites=3 ; Result: Succeeded (l. 33) ; 60.91 s ; mêmes 3 unités [NoUba].
Avertissement Grep warning C dans les deux journaux seul LPCameraModeSubsystem.cpp(2378) : warning C4701 (Aim), connu ; aucun dans ModdingExtraBPLibrary.cpp.
Toolchain ligne Using Visual Studio des deux résumés 14.50.35739 toolchain (…\MSVC\14.50.35717) : conforme à la copie 5.8.
PubCheck pwsh -NoProfile -File Tools/PubCheck.ps1 -Fichiers Plugins/ModdingExtra/Source/ModdingExtra/Private/ModdingExtraBPLibrary.cpp -Depot "D:/Game/LifePlay-master 5.8" (stdin /dev/null) PubCheck : 0 constat(s), code 0.

Non rejoué : LPTestStringCompat (la fiche ne le demande pas ; le test ne couvre pas ce code), compilation (la fiche demande de recompter seulement).

4. Diff lu en entier

git diff -U3 -- Plugins/ModdingExtra lu en entier : 1 fichier, 120 insertions, 2 suppressions, hunks a, b, c, d, e, f, g de la SPEC § 2.1 et rien d'autre. Les deux lignes retirées sont exactement celles de la SPEC (f, g). L'IMPL signale que la ligne vide du bloc b est en fin de bloc plutôt qu'en tête : présentation uniquement, constatée dans le diff (l. 29-31 et 140-142 du fichier). Texte des blocs a-g relu ligne à ligne contre la SPEC : conforme, aucun ajout. Fichier non modifié par script d'après l'IMPL (outil Edit).

Revue de logique (établi par lecture du code) :

Exigence Constat
Seul le préfixe exact Saves/ est redirigé \ remplacé par /, / de tête retirés, StartsWith("Saves/", IgnoreCase). saves\x, /Saves/x redirigés ; Modules/… et tout autre : ProjectContentDir() + chemin d'origine. Chemin absolu (C:/…) : non redirigé, comme avant.
Repli par slot Si <SavedDir>/Saves/<Slot> absent ET <Content>/Saves/<Slot> présent : lecture dans l'ancien. Sinon nouvelle racine.
_session jamais de repli confirmé (V4).
Écriture toujours vers la nouvelle racine confirmé, hors -LPNoSavesRedirect.
-LPNoSavesRedirect rétablit ProjectContentDir() + chemin pour Saves/… ; ligne de journal unique ; bilan (redirection desactivee).
Témoin sans débordement une ligne racine, puis une par couple (racine, slot en minuscules) via TSet, plus 3 compteurs. Borné par le nombre de slots.
LPDataCache TryGet et OnWritten reçoivent FileNameA/FileNameB relatifs d'origine ; TryGet ne sert que modules/ ; ResolvePath n'est appelée que si le cache n'a pas servi (court-circuit `bFromCache
Accès concurrent non sûr s'il y a plusieurs threads : voir réserve 1.

5. Verdict et réserves numérotées

Verdict : PASS-STATIC avec réserves. V1-V6 conformes ; build 2/2 Succeeded, seul C4701 connu ; essais en jeu non faits.

Réserves :

  1. Concurrence : NewReads/OldReads/Writes (static int32 non atomiques), Seen et Warned (TSet statiques) et les static bool (bFirst, bLogged) ne sont pas protégés. Sûr seulement sur le thread de jeu (le commentaire du code le dit). C'est cohérent avec le code existant (ReportedFailures, commentaire l. 326 « Appele uniquement depuis les Blueprints »), et la SPEC prescrit ce code ; mais si un appel arrive d'un autre thread, courses possibles (compteurs faux, corruption du TSet). Aucun appel hors thread de jeu n'a été mesuré ici (incertain).
  2. Traversée .. (R7 de la SPEC, accepté) : Saves/../Modules/x est redirigé sous <SavedDir>/Modules/x ; Saves/../../x écrirait au-dessus de <SavedDir> (aucune normalisation). Cas inverse : Modules/../Saves/x n'est pas détecté et reste dans l'ancien Content/Saves. Aucun littéral connu de ces formes ; un mod pourrait les produire.
  3. Cas limites non couverts par un traitement dédié : (a) Saves seul (sans /) : non redirigé, ancien chemin ; (b) Saves/ final ou Saves//x : redirigé, Slot vide, traité comme fichier direct sans repli, journal Saves slot '' … ; (c) nom de slot vide : même cas ; (d) ./Saves/x non détecté. Aucun usage connu (SPEC § 1.1).
  4. Binaires : contiennent aussi KEY2 non commité (B1) ; la référence E8 « même build sans F6 » est à choisir en tenant compte de cela.
  5. Écart de format : l'IMPL n'a pas de section ordonnée exactement « Constats » avant « Fichiers à commiter » : la section « Constats » est après Tours :, conforme au gabarit (section libre à la fin). Aucun écart.

6. Points à confirmer par l'utilisateur

  • Accepter les réserves 1 à 3 (SPEC R7 déjà acceptée) pour la build 1.
  • Faire produire le paquet Development (IMPL B2) puis jouer E1-E8 (SPEC § 7.2) ; les cas E1-E9 restent à passer.
  • Choisir le journal de référence de E8 en tenant compte de KEY2.

Témoin en jeu : COMMUN- à créer (le cas de la fiche de tests commune pour F6 n'est pas identifié ici ; demande à l'ordonnateur : E1-E8 de la SPEC § 7.2).

Fichiers à commiter : A Docs/Migration/etat/REL/FIX1/FIX1-F6-VAL.md (les deux FIX1-VAL_BuildLog_*.txt sont ignorés par git).

Tours : 9 / 40